[med-svn] [fis-gtm] 02/05: Imported Upstream version 6.0-003
Andreas Tille
tille at debian.org
Sun Nov 24 09:01:27 UTC 2013
This is an automated email from the git hooks/post-receive script.
tille pushed a commit to branch master
in repository fis-gtm.
commit d883233f4018839ce9f3da6faa57a5de8e2de98f
Author: Andreas Tille <tille at debian.org>
Date: Sun Nov 24 09:27:39 2013 +0100
Imported Upstream version 6.0-003
---
CMakeLists.txt | 17 +-
README.txt => LICENSE | 0
README | 65 +-
sr_alpha/axp.h | 133 +
sr_alpha/cacheflush.m64 | 27 +
sr_alpha/double2s.c | 158 +
sr_alpha/emit_code_sp.c | 278 +
sr_alpha/emit_code_sp.h | 206 +
sr_alpha/follow.m64 | 32 +
sr_alpha/gtm_dump.c | 17 +
sr_alpha/inst_flush.m64 | 24 +
sr_alpha/mint2mval.m64 | 51 +
sr_alpha/movq.m64 | 21 +
sr_alpha/mval2bool.m64 | 39 +
sr_alpha/mval2mint.m64 | 39 +
sr_alpha/objlangdefs.h | 457 +
sr_alpha/op_call.m64 | 51 +
sr_alpha/op_equnul.m64 | 61 +
sr_alpha/op_forlcldo.m64 | 51 +
sr_alpha/op_linestart.m64 | 24 +
sr_alpha/op_pattern.m64 | 51 +
sr_alpha/op_sorts_after.m64 | 41 +
sr_alpha/pseudo_ret.m64 | 37 +
sr_alpha/zbreaksp.h | 28 +
sr_avms/adawi.c | 22 +
sr_avms/aswp.m64 | 14 +
sr_avms/aswp_secshr.m64 | 14 +
sr_avms/aswp_src.h | 85 +
sr_avms/auto_zlink.c | 110 +
sr_avms/auto_zlink.h | 17 +
sr_avms/axp_gtm_registers.h | 44 +
sr_avms/axp_registers.h | 56 +
sr_avms/base_frame.max | 168 +
sr_avms/bci.mar | 9 +
sr_avms/bind_symbol.m64 | 32 +
sr_avms/bndsym.max | 70 +
sr_avms/bsi.mar | 11 +
sr_avms/call_dm.m64 | 33 +
sr_avms/caller_id.m64 | 18 +
sr_avms/callg.mar | 12 +
sr_avms/cmi_symbols.m64 | 13 +
sr_avms/cmilink.axp | 28 +
sr_avms/code_psect.max | 3 +
sr_avms/compswap.m64 | 14 +
sr_avms/compswap_secshr.m64 | 14 +
sr_avms/compswap_src.h | 104 +
sr_avms/create_base_frame.max | 51 +
sr_avms/data_psect_bound.m64 | 34 +
sr_avms/ddp_dal_dispatch.m64 | 113 +
sr_avms/ddpgvusr_symbols.m64 | 15 +
sr_avms/ddplink.axp | 38 +
sr_avms/error_return_vms.m64 | 32 +
sr_avms/fetch_args.max | 50 +
sr_avms/fgncal_dispatch.m64 | 1108 ++
sr_avms/fgncal_rtn.m64 | 136 +
sr_avms/find_line_call.c | 98 +
sr_avms/g_msf.max | 76 +
sr_avms/get_registers.m64 | 11 +
sr_avms/getframe.max | 33 +
sr_avms/gtm$defaults.m64 | 27 +
sr_avms/gtm$fgncall.m64 | 231 +
sr_avms/gtm_code_address.m64 | 17 +
sr_avms/gtm_dyn_ch.m64 | 80 +
sr_avms/gtm_main.m64 | 218 +
sr_avms/gtm_memmove.c | 57 +
sr_avms/gtm_ret_code.m64 | 48 +
sr_avms/gtm_zc.m64 | 19 +
sr_avms/gtmi$def.m64 | 14 +
sr_avms/gtmsecplv.m64 | 60 +
sr_avms/gtmshrlink.axp | 74 +
sr_avms/gtmstopzc.m64 | 22 +
sr_avms/gtmzcall.max | 483 +
sr_avms/i2s.mar | 37 +
sr_avms/incr_link.c | 555 +
sr_avms/mdefsp.h | 130 +
sr_avms/mem_access.c | 49 +
sr_avms/memcmp.mar | 27 +
sr_avms/mum_tstart.m64 | 96 +
sr_avms/mumps_binding.max | 96 +
sr_avms/mutex.mar | 952 ++
sr_avms/mutex_stoprel.mar | 140 +
sr_avms/mval$def.max | 149 +
sr_avms/mval2num.m64 | 39 +
sr_avms/obj_file.c | 1283 ++
sr_avms/obj_filesp.h | 28 +
sr_avms/op_bkpt.m64 | 427 +
sr_avms/op_call.m64 | 51 +
sr_avms/op_callsp.m64 | 54 +
sr_avms/op_contain.m64 | 243 +
sr_avms/op_currtn.m64 | 39 +
sr_avms/op_equ.m64 | 32 +
sr_avms/op_exfun.m64 | 85 +
sr_avms/op_extcall.m64 | 111 +
sr_avms/op_extexfun.m64 | 161 +
sr_avms/op_extjmp.m64 | 115 +
sr_avms/op_fetchintrrpt.m64 | 53 +
sr_avms/op_fnget.m64 | 52 +
sr_avms/op_fnzextract.m64 | 71 +
sr_avms/op_follow.m64 | 69 +
sr_avms/op_forcenum.m64 | 96 +
sr_avms/op_forchk1.m64 | 24 +
sr_avms/op_forinit.m64 | 74 +
sr_avms/op_forintrrpt.m64 | 49 +
sr_avms/op_forlcldo.m64 | 51 +
sr_avms/op_forloop.m64 | 260 +
sr_avms/op_gettruth.m64 | 42 +
sr_avms/op_iretmvad.m64 | 29 +
sr_avms/op_linefetch.m64 | 31 +
sr_avms/op_mprofcall.m64 | 51 +
sr_avms/op_mprofcallsp.m64 | 54 +
sr_avms/op_mprofexfun.m64 | 85 +
sr_avms/op_mprofextcall.m64 | 111 +
sr_avms/op_mprofextexfun.m64 | 161 +
sr_avms/op_mprofforchk1.m64 | 31 +
sr_avms/op_mprofforlcldo.m64 | 51 +
sr_avms/op_mproflinefetch.m64 | 34 +
sr_avms/op_mproflinestart.m64 | 24 +
sr_avms/op_neg.m64 | 98 +
sr_avms/op_numcmp.m64 | 22 +
sr_avms/op_restartpc.m64 | 31 +
sr_avms/op_retarg.m64 | 41 +
sr_avms/op_startintrrpt.m64 | 52 +
sr_avms/op_sto.m64 | 67 +
sr_avms/opp_break.m64 | 27 +
sr_avms/opp_commarg.m64 | 27 +
sr_avms/opp_dmode.m64 | 27 +
sr_avms/opp_hardret.m64 | 26 +
sr_avms/opp_inddevparms.m64 | 27 +
sr_avms/opp_indfnname.m64 | 27 +
sr_avms/opp_indfun.m64 | 27 +
sr_avms/opp_indglvn.m64 | 27 +
sr_avms/opp_indincr.m64 | 37 +
sr_avms/opp_indlvadr.m64 | 27 +
sr_avms/opp_indlvarg.m64 | 27 +
sr_avms/opp_indlvnamadr.m64 | 27 +
sr_avms/opp_indmerge.m64 | 27 +
sr_avms/opp_indpat.m64 | 27 +
sr_avms/opp_indrzshow.m64 | 27 +
sr_avms/opp_indsavglvn.m64 | 37 +
sr_avms/opp_indsavlvn.m64 | 37 +
sr_avms/opp_indset.m64 | 27 +
sr_avms/opp_indtext.m64 | 27 +
sr_avms/opp_iretmval.m64 | 26 +
sr_avms/opp_newintrinsic.m64 | 27 +
sr_avms/opp_newvar.m64 | 27 +
sr_avms/opp_ret.m64 | 112 +
sr_avms/opp_rterror.m64 | 27 +
sr_avms/opp_svput.m64 | 27 +
sr_avms/opp_tcommit.m64 | 27 +
sr_avms/opp_trestart.m64 | 26 +
sr_avms/opp_trollback.m64 | 24 +
sr_avms/opp_tstart.m64 | 97 +
sr_avms/opp_xnew.m64 | 66 +
sr_avms/opp_zcont.m64 | 26 +
sr_avms/opp_zg1.m64 | 34 +
sr_avms/opp_zgoto.m64 | 34 +
sr_avms/pdscdef.h | 99 +
sr_avms/prober.mar | 18 +
sr_avms/probew.mar | 19 +
sr_avms/proc_desc.h | 26 +
sr_avms/procdesc.max | 6 +
sr_avms/putframe.max | 15 +
sr_avms/release_name.h | 14 +
sr_avms/rundown_dispatch.m64 | 12 +
sr_avms/secshrlink.axp | 32 +
sr_avms/zc_call.m64 | 363 +
sr_avms/zc_makespace.m64 | 55 +
sr_cmi/cmi_close.c | 63 +
sr_cmi/cmi_init.c | 78 +
sr_cmi/cmi_open.c | 64 +
sr_cmi/cmi_read.c | 21 +
sr_cmi/cmi_write.c | 20 +
sr_cmi/cmi_write_int.c | 28 +
sr_cmi/cmierrors.msg | 20 +
sr_cmi/cmihdr.h | 30 +
sr_cmi/cmivector.mar | 23 +
sr_cmi/cmj_ast.c | 26 +
sr_cmi/cmj_disconn2.c | 28 +
sr_cmi/cmj_fini.c | 33 +
sr_cmi/cmj_iostart.c | 46 +
sr_cmi/cmj_mbx_ast.c | 231 +
sr_cmi/cmj_mbx_read_start.c | 25 +
sr_cmi/cmj_netinit.c | 62 +
sr_cmi/cmj_unit2clb.c | 27 +
sr_cmi/cmj_util.mar | 70 +
sr_cmi/cmu_getclb.c | 35 +
sr_cmi/cmu_makclb.c | 22 +
sr_cmi/cmu_ntdroot.c | 20 +
sr_i386/emit_code.c | 34 +-
sr_i386/merrors_ansi.h | 79 +-
sr_i386/merrors_ctl.c | 174 +-
sr_i386/ttt.c | 1350 +-
sr_linux/gtm_env_sp.csh | 2 +-
sr_linux/gtm_system.c | 27 -
sr_linux/release_name.h | 10 +-
sr_port/actuallist.c | 9 +-
sr_port/advancewindow.c | 6 +-
sr_port/alloc_reg.c | 91 +-
sr_port/anticipatory_freeze.h | 137 +-
sr_port/asc_hex2i.c | 55 +-
sr_port/bm_getfree.c | 31 +-
sr_port/bm_setmap.c | 20 +-
sr_port/bt_init.c | 19 +-
sr_port/bt_put.c | 9 +-
sr_port/bx_boolop.c | 78 +-
sr_port/cdb_sc_table.h | 3 +-
sr_port/cert_blk.c | 128 +-
sr_port/cmd_qlf.h | 13 +-
sr_port/comp_fini.c | 15 +-
sr_port/compiler.h | 14 +-
sr_port/compiler_startup.c | 11 +-
sr_port/compswap.h | 8 +-
sr_port/copy_stack_frame.c | 13 +-
sr_port/cre_jnl_file.c | 66 +-
sr_port/cre_jnl_file_intrpt_rename.c | 4 +-
sr_port/db_auto_upgrade.c | 9 +-
sr_port/db_csh_get.c | 43 +-
sr_port/db_csh_getn.c | 3 +-
sr_port/db_csh_ini.c | 11 +-
sr_port/db_csh_ref.c | 93 +-
sr_port/dbcertify_certify_phase.c | 4 +-
sr_port/dbcertify_funcs.c | 56 +-
sr_port/deviceparameters.c | 50 +-
sr_port/dse.h | 24 +-
sr_port/dse.hlp | 3552 +++--
sr_port/dse_adrec.c | 6 +-
sr_port/dse_adstar.c | 5 +-
sr_port/dse_all.c | 7 +-
sr_port/dse_cache.c | 13 +-
sr_port/dse_chng_bhead.c | 7 +-
sr_port/dse_chng_rhead.c | 5 +-
sr_port/dse_crit.c | 6 +-
sr_port/dse_dmp_fhead.c | 6 +-
sr_port/dse_maps.c | 16 +-
sr_port/dse_over.c | 5 +-
sr_port/dse_rest.c | 5 +-
sr_port/dse_rmrec.c | 7 +-
sr_port/dse_shift.c | 5 +-
sr_port/dsewrap.mpt | 16 +-
sr_port/eintr_wrappers.h | 335 +-
sr_port/emit_code.c | 10 +-
sr_port/eval_expr.c | 15 +-
sr_port/exfun_frame.c | 13 +-
sr_port/expritem.c | 14 +-
sr_port/f_get.c | 20 +-
sr_port/f_incr.c | 3 +-
sr_port/f_name.c | 9 +-
sr_port/f_order.c | 12 +-
sr_port/f_zpeek.c | 78 +
sr_port/fntext_ch.c | 3 +-
sr_port/gbldefs.c | 229 +-
sr_port/gde.hlp | 2004 ++-
sr_port/gdemap.m | 187 +-
sr_port/gdeshow.m | 24 +-
sr_port/gds_map_moved.c | 19 +-
sr_port/gds_map_moved.h | 4 +-
sr_port/gds_rundown.h | 28 +-
sr_port/gdsbgtr.h | 4 +-
sr_port/gdsbml.h | 48 +-
sr_port/gdsbt.h | 34 +-
sr_port/gdsdbver.h | 4 +-
sr_port/gdsfhead.h | 219 +-
sr_port/gdsfilext.h | 11 +-
sr_port/gdsroot.h | 8 +-
sr_port/get_cmd_qlf.c | 19 +-
sr_port/get_fs_block_size.c | 4 +-
sr_port/golevel.h | 22 +-
sr_port/gtm_common_defs.h | 80 +-
sr_port/gtm_env_init.c | 18 +-
sr_port/gtm_inet.h | 5 +-
sr_port/gtm_ipv6.h | 134 +
sr_port/gtm_malloc_src.h | 130 +-
sr_port/gtm_netdb.h | 28 +-
sr_port/gtm_putmsg_list.h | 4 +-
sr_port/gtm_rename.h | 14 +-
sr_port/gtm_socket.h | 32 +-
sr_port/gtm_stdlib.h | 8 +-
sr_port/gtm_string.h | 28 +-
sr_port/gtm_threadgbl_defs.h | 18 +-
sr_port/gtm_threadgbl_deftypes.c | 3 +-
sr_port/gtm_threadgbl_init.c | 3 +-
sr_port/gtm_time.h | 54 +-
sr_port/gtm_unistd.h | 8 +-
sr_port/gtmmsg.h | 5 +-
sr_port/gtmrecv_comm_init.c | 64 +-
sr_port/gtmrecv_helpers_init.c | 20 +-
sr_port/gtmrecv_upd_proc_init.c | 43 +-
sr_port/gtmsource_comm_init.c | 61 +-
sr_port/gtmsource_heartbeat.h | 11 +-
sr_port/gtmsource_poll_actions.c | 13 +-
sr_port/gv_bind_name.c | 8 +-
sr_port/gv_rundown.c | 10 +-
sr_port/gv_select.c | 18 +-
sr_port/gvcst_bmp_mark_free.c | 8 +-
sr_port/gvcst_expand_any_key.c | 6 +-
sr_port/gvcst_expand_free_subtree.c | 8 +-
sr_port/gvcst_init.c | 101 +-
sr_port/gvcst_kill.c | 23 +-
sr_port/gvcst_map_build.c | 32 +-
sr_port/gvcst_protos.h | 5 +-
sr_port/gvcst_put.c | 32 +-
sr_port/gvcst_search.c | 39 +-
sr_port/have_crit.c | 15 +-
sr_port/have_crit.h | 103 +-
sr_port/indirection.c | 23 +-
sr_port/insert_region.c | 5 +-
sr_port/io.h | 9 +-
sr_port/io_dev_dispatch.h | 6 +-
sr_port/iop.h | 8 +-
sr_port/iosocket_bind.c | 177 +-
sr_port/iosocket_close.c | 10 +-
sr_port/iosocket_connect.c | 227 +-
sr_port/iosocket_create.c | 234 +-
sr_port/iosocket_flush.c | 23 +-
sr_port/iosocket_iocontrol.c | 18 +-
sr_port/iosocket_listen.c | 71 +-
sr_port/iosocket_open.c | 106 +-
sr_port/iosocket_readfl.c | 55 +-
sr_port/iosocket_use.c | 79 +-
sr_port/iosocket_wait.c | 422 +-
sr_port/iosocket_write.c | 18 +-
sr_port/iosocket_wteol.c | 3 +-
sr_port/iosocketdef.h | 141 +-
sr_port/iotcp_close.c | 4 +-
sr_port/iotcp_fillroutine.c | 10 +-
sr_port/iotcp_flush.c | 4 +-
sr_port/iotcp_iocontrol.c | 18 +-
sr_port/iotcp_list.c | 38 +-
sr_port/iotcp_name2ip.c | 39 -
sr_port/iotcp_open.c | 353 +-
sr_port/iotcp_readfl.c | 35 +-
sr_port/iotcp_write.c | 16 +-
sr_port/iotcpdef.h | 98 +-
sr_port/iotcproutine.h | 54 +-
sr_port/jnl.h | 46 +-
sr_port/jnl_file_close.c | 14 +-
sr_port/jnl_file_lost.c | 13 +-
sr_port/jnl_file_open_common.c | 15 +-
sr_port/jnl_file_open_switch.c | 7 +-
sr_port/jnl_send_oper.c | 7 +-
sr_port/jnl_write_attempt.c | 106 +-
sr_port/jnl_write_logical.c | 4 +-
sr_port/job_addr.c | 7 +-
sr_port/job_addr.h | 4 +-
sr_port/jobexam_process.c | 6 +-
sr_port/jobinterrupt_event.c | 33 +-
sr_port/line.c | 109 +-
sr_port/lke.hlp | 685 +-
sr_port/lke_clear.c | 10 +-
sr_port/lke_getki.c | 92 +-
sr_port/m_zcompile.c | 4 +-
sr_port/mdb_condition_handler.c | 76 +-
sr_port/mdef.h | 155 +-
sr_port/merrors.msg | 115 +-
sr_port/mm_read.c | 4 +-
sr_port/mprof_funcs.c | 281 +-
sr_port/mprof_tree.c | 4 +-
sr_port/mtables.c | 16 +-
sr_port/mtables.h | 16 +
sr_port/mu_clsce.c | 65 +-
sr_port/mu_extr_gblout.c | 14 +-
sr_port/mu_int_fhead.c | 3 +-
sr_port/mu_int_reg.c | 11 +-
sr_port/mu_reorg.c | 19 +-
sr_port/mu_reorg.h | 153 +-
sr_port/mu_reorg_upgrd_dwngrd.c | 9 +-
sr_port/mu_split.c | 20 +-
sr_port/mu_swap_blk.c | 14 +-
sr_port/mucregini.c | 3 +-
sr_port/mupip.hlp | 8671 +++++++++---
sr_port/mupip_backup.c | 140 +-
sr_port/mupip_extend.c | 12 +-
sr_port/mupip_io_dev_dispatch.h | 4 +-
sr_port/mupip_reorg.c | 93 +-
sr_port/mupip_reorg.h | 5 +-
sr_port/mupip_set.c | 3 +-
sr_port/mupip_set_journal.c | 104 +-
sr_port/muprec.h | 27 +-
sr_port/mur_apply_pblk.c | 49 +-
sr_port/mur_back_process.c | 105 +-
sr_port/mur_block_count_correct.c | 4 +-
sr_port/mur_close_file_extfmt.c | 5 +-
sr_port/mur_close_files.c | 91 +-
sr_port/mur_forward.c | 3 +-
sr_port/mur_get_pini.c | 20 +-
sr_port/mur_init.c | 3 +-
sr_port/mur_insert_prev.c | 22 +-
sr_port/mur_open_files.c | 48 +-
sr_port/mur_output_show.c | 5 +-
sr_port/mur_process_intrpt_recov.c | 28 +-
sr_port/mur_process_timequal.c | 15 +-
sr_port/mur_put_aimg_rec.c | 6 +-
sr_port/mur_read_file.c | 169 +-
sr_port/mutex_deadlock_check.c | 84 +-
sr_port/mutex_deadlock_check.h | 6 +-
sr_port/mvalconv.c | 173 +-
sr_port/mvalconv.h | 11 +-
sr_port/objlabel.h | 4 +-
sr_port/one_job_param.c | 13 +-
sr_port/op.h | 15 +-
sr_port/op_bindparm.c | 11 +-
sr_port/op_fntext.c | 15 +-
sr_port/op_fnview.c | 65 +-
sr_port/op_halt.c | 4 +-
sr_port/op_hang.c | 71 +-
sr_port/op_indlvnamadr.c | 4 +-
sr_port/op_litc.c | 34 +
sr_port/op_lock2.c | 23 +-
sr_port/op_setfnretin2als.c | 8 +-
sr_port/op_setfnretin2alsct.c | 6 +-
sr_port/op_stolitc.c | 32 +
sr_port/op_svget.c | 42 +-
sr_port/op_tcommit.c | 144 +-
sr_port/op_view.c | 251 +-
sr_port/op_xkill.c | 4 +-
sr_port/op_zalloc2.c | 311 -
sr_port/op_zallocate.c | 7 +-
sr_port/op_zcompile.c | 25 +-
sr_port/op_zgoto.c | 14 +-
sr_port/op_zsystem.c | 8 +-
sr_port/opcode_def.h | 5 +-
sr_port/prepare_unique_name.c | 11 +-
sr_port/process_deferred_stale.c | 18 -
sr_port/region_freeze.c | 3 +-
sr_port/region_init.c | 7 +-
sr_port/rename_file_if_exists.c | 12 +-
sr_port/reorg_funcs.c | 184 +
sr_port/repl_comm.c | 470 +-
sr_port/repl_comm.h | 31 +-
sr_port/repl_ctl.h | 7 +-
sr_port/resolve_ref.c | 73 +-
sr_port/sec_shr_map_build.c | 46 +-
sr_port/secshr_db_clnup.c | 17 +-
sr_port/send_msg.h | 10 +-
sr_port/setzdir.c | 37 +-
sr_port/show_source_line.c | 18 +-
sr_port/show_source_line.h | 4 +-
sr_port/sleep_cnt.h | 7 +-
sr_port/stack_frame.h | 4 +-
sr_port/stp_gcol_src.h | 56 +-
sr_port/stx_error.c | 20 +-
sr_port/t_begin.c | 10 +-
sr_port/t_create.c | 23 +-
sr_port/t_end.c | 190 +-
sr_port/t_end_sysops.c | 494 +-
sr_port/t_qread.c | 96 +-
sr_port/t_retry.c | 19 +-
sr_port/tcp_open.c | 299 +-
sr_port/tp.h | 29 +-
sr_port/tp_clean_up.c | 13 +-
sr_port/tp_cw_list.c | 29 +-
sr_port/tp_grab_crit.h | 17 -
sr_port/tp_hist.c | 10 +-
sr_port/tp_restart.c | 9 +-
sr_port/tp_set_sgm.c | 7 +-
sr_port/tp_tend.c | 32 +-
sr_port/tp_timeout.c | 4 +-
sr_port/tp_unwind.c | 89 +-
sr_port/trans_code.c | 2 +-
sr_port/unw_mv_ent.c | 4 +-
sr_port/updhelper_reader.c | 12 +-
sr_port/updproc.c | 237 +-
sr_port/updproc_open_files.c | 4 +-
sr_port/viewtab.h | 8 +-
sr_port/wbox_test_init.h | 35 +-
sr_port/wcs_mm_recover.h | 4 +-
sr_port/wcs_recover.c | 116 +-
sr_port/wcs_verify.c | 444 +-
sr_port/xfer.h | 9 +-
sr_port/zlput_rname.c | 79 +-
sr_port/zshow_params.h | 6 +-
sr_port/zshow_stack.c | 8 +-
sr_unix/CMakeLists.txt | 17 +-
sr_unix/anticipatory_freeze.c | 140 +-
sr_unix/append_time_stamp.c | 31 +-
sr_unix/badd.txt | 7 +-
sr_unix/bdelete.txt | 4 +-
sr_unix/bin_load.c | 48 +-
sr_unix/build.sh | 4 +-
sr_unix/buildaux.csh | 13 +-
sr_unix/check_unicode_support.csh | 8 +-
sr_unix/clear_cache_array.c | 62 +-
sr_unix/cli_lex.c | 15 +-
sr_unix/cmidefsp.h | 50 +-
sr_unix/comlist.csh | 122 +-
sr_unix/configure.gtc | 189 +-
sr_unix/continue_handler.c | 8 +-
sr_unix/ctrlc_handler.c | 9 +-
sr_unix/db_ipcs_reset.c | 11 +-
sr_unix/dbcertify_deferred_signal_handler.c | 48 +-
sr_unix/dbcertify_signal_handler.c | 95 +-
sr_unix/dbinit_ch.c | 95 +-
sr_unix/deferred_signal_handler.c | 33 +-
sr_unix/dircompare.m.txt | 111 +-
sr_unix/disk_block_available.c | 3 +-
sr_unix/dollarh.c | 31 +-
sr_unix/dse_cmd.c | 5 +-
sr_unix/dse_help.c | 3 +-
sr_unix/dsk_read.c | 65 +-
sr_unix/err_init.c | 98 +-
sr_unix/errorsp.h | 90 +-
sr_unix/extract_signal_info.c | 51 +-
sr_unix/exttab_parse.c | 180 +-
sr_unix/fgncalsp.h | 12 +-
sr_unix/filestruct.h | 6 +-
sr_unix/fork_init.h | 14 +-
sr_unix/ftok.c | 4 +-
sr_unix/ftok_sems.c | 61 +-
sr_unix/gds_rundown.c | 320 +-
sr_unix/gds_rundown_ch.c | 39 +
sr_unix/gds_rundown_err_cleanup.c | 91 +
sr_unix/gds_rundown_err_cleanup.h | 16 +
sr_unix/gdsfilext.c | 325 +-
sr_unix/generic_signal_handler.c | 82 +-
sr_unix/get_full_path.c | 11 +-
sr_unix/go_load.c | 26 +-
sr_unix/golevel.c | 14 +-
sr_unix/grab_crit_immediate.c | 108 +
sr_unix/grab_lock.c | 94 +-
sr_unix/gt_as.csh | 58 +-
sr_unix/gt_cc.csh | 51 +-
sr_unix/gt_timer.h | 16 +-
sr_unix/gt_timers.c | 205 +-
sr_unix/gtm.gtc | 6 +-
sr_unix/gtm_asm_establish.c | 11 +-
sr_unix/gtm_bintim.c | 172 +-
sr_unix/gtm_c_stack_trace.c | 28 +-
sr_unix/gtm_compare_dir.csh | 15 +-
sr_unix/gtm_compile.c | 40 +-
sr_unix/gtm_dump_core.c | 4 +-
sr_unix/gtm_env_init_sp.c | 30 +-
sr_unix/gtm_fd_trace.c | 19 +-
sr_unix/gtm_fork_n_core.c | 34 +-
sr_unix/gtm_logicals.h | 6 +-
sr_unix/gtm_pipe.c | 23 +-
sr_unix/gtm_putmsg.c | 43 +-
sr_unix/gtm_putmsg_list.c | 16 +-
sr_unix/gtm_semutils.h | 11 +-
sr_unix/gtm_startup_chk.c | 28 +-
sr_unix/gtm_statvfs.h | 9 +-
sr_unix/gtm_stdio.h | 13 +-
sr_unix/gtm_syslog.h | 3 +-
sr_unix/gtm_system.c | 88 +
sr_unix/gtm_test_install.csh | 70 +-
sr_unix/gtm_text_alloc.c | 177 +-
sr_unix/gtm_trigger.c | 7 +-
sr_unix/gtm_unlink_all.c | 5 +-
sr_unix/gtmci.c | 473 +-
sr_unix/gtmci_ch.c | 3 +-
sr_unix/gtmcrypt.h | 19 +-
sr_unix/gtmdbgflags.h | 49 +
sr_unix/gtmio.h | 19 +-
sr_unix/gtmprofile.gtc | 7 +-
sr_unix/gtmrecv.c | 62 +-
sr_unix/gtmrecv.h | 14 +-
sr_unix/gtmrecv_fetchresync.c | 244 +-
sr_unix/gtmrecv_poll_actions.c | 40 +-
sr_unix/gtmrecv_process.c | 525 +-
sr_unix/gtmrecv_shutdown.c | 16 +-
sr_unix/gtmsecshr.c | 318 +-
sr_unix/gtmsecshr_wrapper.c | 128 +-
sr_unix/gtmshr_symbols.exp | 3 +
sr_unix/gtmsource.c | 64 +-
sr_unix/gtmsource.h | 50 +-
sr_unix/gtmsource_checkhealth.c | 24 +-
sr_unix/gtmsource_flush_fh.c | 4 +-
sr_unix/gtmsource_freeze.c | 4 +-
sr_unix/gtmsource_get_opt.c | 64 +-
sr_unix/gtmsource_heartbeat.c | 22 +-
sr_unix/gtmsource_losttncomplete.c | 4 +-
sr_unix/gtmsource_mode_change.c | 31 +-
sr_unix/gtmsource_needrestart.c | 4 +-
sr_unix/gtmsource_onln_rlbk_clnup.c | 4 +-
sr_unix/gtmsource_process.c | 267 +-
sr_unix/gtmsource_process_ops.c | 508 +-
sr_unix/gtmsource_readfiles.c | 43 +-
sr_unix/gtmsource_rootprimary_init.c | 4 +-
sr_unix/gtmsource_seqno_init.c | 8 +-
sr_unix/gtmsource_showbacklog.c | 11 +-
sr_unix/gtmsource_shutdown.c | 16 +-
sr_unix/gtmxc_types.h | 27 +-
sr_unix/gv_trigger.c | 105 +-
sr_unix/gv_trigger.h | 5 +-
sr_unix/gvcst_init_sysops.c | 320 +-
sr_unix/heartbeat_timer.c | 200 +-
sr_unix/heartbeat_timer.h | 8 +-
sr_unix/hpuxia64_badd.txt | 7 +-
sr_unix/hpuxparisc_badd.txt | 14 +-
sr_unix/incr_link.c | 30 +-
sr_unix/init_gtm.c | 21 +-
sr_unix/interlock.h | 9 +-
sr_unix/io_open_try.c | 38 +-
sr_unix/iopi_iocontrol.c | 16 +-
sr_unix/iopi_open.c | 71 +-
sr_unix/iorm_close.c | 20 +-
sr_unix/iorm_get.c | 316 +-
sr_unix/iorm_open.c | 44 +-
sr_unix/iorm_readfl.c | 428 +-
sr_unix/iorm_use.c | 47 +-
sr_unix/iorm_write.c | 36 +-
sr_unix/iorm_wteol.c | 22 +-
sr_unix/iormdef.h | 9 +-
sr_unix/iott_iocontrol.c | 54 +
sr_unix/iott_open.c | 39 +-
sr_unix/iott_rdone.c | 41 +-
sr_unix/iott_readfl.c | 64 +-
sr_unix/iott_use.c | 28 +-
sr_unix/iottdef.h | 3 +-
sr_unix/ipcrmid.c | 45 +-
sr_unix/jnl_file_extend.c | 44 +-
sr_unix/jnl_fsync.c | 65 +-
sr_unix/jnl_output_sp.c | 14 +-
sr_unix/jnlpool_init.c | 138 +-
sr_unix/jobchild_init.c | 32 +-
sr_unix/joberr.h | 35 +-
sr_unix/jobsp.h | 61 +-
sr_unix/kitstart.csh | 213 +-
sr_unix/libmupip.list | 2 +-
sr_unix/linuxi686_badd.txt | 7 +-
sr_unix/list_file.c | 5 +-
sr_unix/lke_cmd.c | 5 +-
sr_unix/lke_help.c | 4 +-
sr_unix/maskpass.c | 8 +-
sr_unix/mdefsa.h | 3 +-
sr_unix/mdefsp.h | 26 +-
sr_unix/mu_all_version_standalone.c | 20 +-
sr_unix/mu_extract.c | 21 +-
sr_unix/mu_replpool_grab_sem.c | 4 +-
sr_unix/mu_rndwn_all.c | 11 +-
sr_unix/mu_rndwn_file.c | 549 +-
sr_unix/mu_rndwn_repl_instance.c | 8 +-
sr_unix/mu_rndwn_replpool.c | 17 +-
sr_unix/mu_size_scan.c | 3 +-
sr_unix/mu_swap_root.c | 42 +-
sr_unix/mu_truncate.c | 36 +-
sr_unix/mu_truncate.h | 6 +-
sr_unix/mubfilcpy.c | 40 +-
sr_unix/mumps_clitab.c | 3 +-
sr_unix/mupip_cmd.c | 12 +-
sr_unix/mupip_exit.c | 4 +-
sr_unix/mupip_exit_handler.c | 7 +-
sr_unix/mupip_help.c | 7 +-
sr_unix/mupip_restore.c | 19 +-
sr_unix/mupip_set_file.c | 34 +-
sr_unix/mur_cre_file_extfmt.c | 5 +-
sr_unix/mutex.c | 9 +-
sr_unix/mutex_sock_init.c | 26 +-
sr_unix/obj_code.c | 26 +-
sr_unix/ojchildioset.c | 118 +-
sr_unix/ojparams.c | 34 +-
sr_unix/ojstartchild.c | 419 +-
sr_unix/op_fnfgncal.c | 506 +-
sr_unix/op_fnzpeek.c | 664 +
sr_unix/op_job.c | 131 +-
sr_unix/op_zedit.c | 19 +-
sr_unix/op_ztrigger.c | 6 +-
sr_unix/osf1alpha_badd.txt | 9 +-
sr_unix/parse_file.c | 105 +-
sr_unix/recvpool_init.c | 19 +-
sr_unix/repl_inst_create.c | 6 +-
sr_unix/repl_inst_dump.c | 36 +-
sr_unix/repl_instance.c | 4 +-
sr_unix/repl_log_init.c | 5 +-
sr_unix/repl_logfileinfo_get.c | 80 +
sr_unix/repl_msg.h | 31 +-
sr_unix/repl_sem.c | 11 +-
sr_unix/rtnhdr.h | 5 +-
sr_unix/rts_error.c | 56 +-
sr_unix/runall.csh | 38 +-
sr_unix/secshr_client.c | 103 +-
sr_unix/semstat2.c | 6 +-
sr_unix/send_msg.c | 46 +-
sr_unix/sig_init.c | 205 +-
sr_unix/sleep.h | 140 +-
sr_unix/source_file.c | 5 +-
sr_unix/ss_initiate.c | 16 +-
sr_unix/ss_write_block.c | 39 +-
sr_unix/timersp.h | 13 +-
sr_unix/tp_grab_crit.c | 107 -
sr_unix/trigger_compare.c | 10 +-
sr_unix/trigger_delete.c | 52 +-
sr_unix/trigger_gbl_fill_xecute_buffer.c | 10 +-
sr_unix/trigger_read_name_entry.c | 8 +-
sr_unix/trigger_select.c | 16 +-
sr_unix/trigger_source_read_andor_verify.c | 36 +-
sr_unix/trigger_update.c | 54 +-
sr_unix/ttt.txt | 14 +-
sr_unix/util_help.c | 63 +
sr_unix/util_help.h | 16 +
sr_unix/util_output.c | 24 +-
sr_unix/util_spawn.c | 9 +-
sr_unix/versions.csh | 4 +-
sr_unix/wait_for_disk_space.c | 68 +-
sr_unix/wcs_clean_dbsync.c | 29 +-
sr_unix/wcs_flu.c | 237 +-
sr_unix/wcs_get_space.c | 36 +-
sr_unix/wcs_wtstart.c | 97 +-
sr_unix/zlmov_lnames.c | 13 +-
sr_unix/zshow_devices.c | 23 +-
sr_unix_cm/gtcm.h | 4 +-
sr_unix_cm/gtcm_bgn_net.c | 77 +-
sr_unix_cm/gtcm_cn_acpt.c | 25 +-
sr_unix_cm/gtcm_cn_disc.c | 6 +-
sr_unix_cm/gtcm_dmpstat.c | 8 +-
sr_unix_cm/gtcm_hist.c | 15 +-
sr_unix_cm/gtcm_loop.c | 6 +-
sr_unix_cm/gtcm_ping.c | 63 +-
sr_unix_cm/gtcm_pktdmp.c | 54 +-
sr_unix_cm/gtcm_rep_err.c | 9 +-
sr_unix_cm/omi.h | 28 +-
sr_unix_cm/omi_prc_conn.c | 6 +-
sr_unix_cm/omi_srvc_xct.c | 14 +-
sr_unix_gnp/cmi_init.c | 30 +-
sr_unix_gnp/cmi_open.c | 33 +-
sr_unix_gnp/cmi_peer_info.c | 49 +-
sr_unix_gnp/cmj_get_port.c | 3 +-
sr_unix_gnp/cmj_getsockaddr.c | 147 +-
sr_unix_gnp/cmj_incoming_call.c | 17 +-
sr_unix_gnp/cmj_resolve_nod_tnd.c | 57 -
sr_unix_gnp/cmj_setupfd.c | 5 +-
sr_unix_gnp/cmu_getclb.c | 17 +-
sr_unix_gnp/gtcm_gnp_pktdmp.c | 4 +-
sr_unix_gnp/gtcm_gnp_server.c | 3 +-
sr_unix_gnp/libcmisockettcp.list | 1 -
sr_unix_nsb/opcode_def.h | 5 +-
sr_unix_nsb/rtnhdr.h | 5 +-
sr_unix_nsb/ttt.txt | 8 +-
sr_vms_cm/gtcm_ch.c | 381 +
sr_vms_cm/gtcm_exi_ch.c | 124 +
sr_vms_cm/gtcm_mbxread_ast.c | 74 +
sr_vms_cm/gtcm_server.c | 369 +
sr_vms_cm/gtcmd_ini_reg.c | 130 +
sr_vms_cm/gvcmz_errmsg.c | 131 +
sr_vvms/append_time_stamp.c | 79 +
sr_vvms/ast.h | 16 +
sr_vvms/ast_get_static.c | 38 +
sr_vvms/ast_init.c | 31 +
sr_vvms/ast_init.h | 17 +
sr_vvms/backup_buffer_flush.c | 170 +
sr_vvms/bin_load.c | 510 +
sr_vvms/bt_que_refresh.c | 47 +
sr_vvms/build_print_stage.com | 20 +
sr_vvms/buildaux.com | 425 +
sr_vvms/buildbta.com | 47 +
sr_vvms/buildcm.com | 20 +
sr_vvms/buildcmi.com | 18 +
sr_vvms/builddbcertify.com | 18 +
sr_vvms/builddbg.com | 32 +
sr_vvms/buildddp.com | 18 +
sr_vvms/builddse.com | 18 +
sr_vvms/buildgde.com | 18 +
sr_vvms/buildhlp.com | 43 +
sr_vvms/buildlke.com | 18 +
sr_vvms/buildmapdb.com | 78 +
sr_vvms/buildmupip.com | 18 +
sr_vvms/buildpro.com | 64 +
sr_vvms/buildsec.com | 130 +
sr_vvms/buildshr.com | 208 +
sr_vvms/buildtcx.com | 93 +
sr_vvms/cce.c | 88 +
sr_vvms/cce.hlp | 253 +
sr_vvms/cce_ccp.c | 118 +
sr_vvms/cce_ccp_ch.c | 15 +
sr_vvms/cce_ccpdmp.c | 106 +
sr_vvms/cce_cluster.c | 170 +
sr_vvms/cce_cmd.cld | 110 +
sr_vvms/cce_dbdump.c | 190 +
sr_vvms/cce_dump.c | 26 +
sr_vvms/cce_get_return_channel.c | 47 +
sr_vvms/cce_help.c | 35 +
sr_vvms/cce_output.c | 76 +
sr_vvms/cce_output.h | 20 +
sr_vvms/cce_read_return_channel.c | 59 +
sr_vvms/cce_sec_size.c | 61 +
sr_vvms/cce_sec_size.h | 17 +
sr_vvms/cce_show_file.c | 146 +
sr_vvms/cce_show_locks.c | 232 +
sr_vvms/cce_start.c | 75 +
sr_vvms/ccp.c | 60 +
sr_vvms/ccp_add_reg.c | 25 +
sr_vvms/ccp_bt_get.c | 40 +
sr_vvms/ccp_ch.c | 141 +
sr_vvms/ccp_close1.c | 237 +
sr_vvms/ccp_close_timeout.c | 39 +
sr_vvms/ccp_closejnl_ast.c | 44 +
sr_vvms/ccp_cluster_lock_wake.c | 27 +
sr_vvms/ccp_dump.c | 168 +
sr_vvms/ccp_enq.c | 42 +
sr_vvms/ccp_enqw.c | 44 +
sr_vvms/ccp_ewmwtbf_interrupt.c | 33 +
sr_vvms/ccp_exi_ch.c | 26 +
sr_vvms/ccp_exitwm1.c | 53 +
sr_vvms/ccp_exitwm1a.c | 29 +
sr_vvms/ccp_exitwm2.c | 35 +
sr_vvms/ccp_exitwm2a.c | 42 +
sr_vvms/ccp_exitwm3.c | 90 +
sr_vvms/ccp_exitwm_attempt.c | 177 +
sr_vvms/ccp_exitwm_blkast.c | 40 +
sr_vvms/ccp_extra_tick.c | 29 +
sr_vvms/ccp_format_querec.c | 166 +
sr_vvms/ccp_get_reg.c | 36 +
sr_vvms/ccp_get_reg_by_fab.c | 33 +
sr_vvms/ccp_gotdrt_tick.c | 23 +
sr_vvms/ccp_init.c | 178 +
sr_vvms/ccp_lkdowake_blkast.c | 25 +
sr_vvms/ccp_lkrqwake1.c | 45 +
sr_vvms/ccp_mbx_manager.c | 62 +
sr_vvms/ccp_opendb.c | 69 +
sr_vvms/ccp_opendb1.c | 35 +
sr_vvms/ccp_opendb1a.c | 28 +
sr_vvms/ccp_opendb1e.c | 28 +
sr_vvms/ccp_opendb2.c | 131 +
sr_vvms/ccp_opendb3.c | 35 +
sr_vvms/ccp_opendb3a.c | 34 +
sr_vvms/ccp_opendb3a.h | 16 +
sr_vvms/ccp_opendb3b.c | 43 +
sr_vvms/ccp_opendb3c.c | 101 +
sr_vvms/ccp_pndg_proc_add.c | 36 +
sr_vvms/ccp_pndg_proc_wake.c | 30 +
sr_vvms/ccp_quantum_interrupt.c | 39 +
sr_vvms/ccp_queue_manager.c | 250 +
sr_vvms/ccp_release_name.c | 20 +
sr_vvms/ccp_reqdrtbuf_interrupt.c | 59 +
sr_vvms/ccp_request_write_mode.c | 44 +
sr_vvms/ccp_reqwm_interrupt.c | 109 +
sr_vvms/ccp_retchan_manager.c | 168 +
sr_vvms/ccp_retchan_manager.h | 35 +
sr_vvms/ccp_rundown.c | 59 +
sr_vvms/ccp_sendmsg.c | 55 +
sr_vvms/ccp_signal_cont.c | 56 +
sr_vvms/ccp_staleness.c | 38 +
sr_vvms/ccp_tick_interrupt.c | 44 +
sr_vvms/ccp_tick_start.c | 42 +
sr_vvms/ccp_tr_checkdb.c | 60 +
sr_vvms/ccp_tr_close.c | 86 +
sr_vvms/ccp_tr_closejnl.c | 63 +
sr_vvms/ccp_tr_debug.c | 23 +
sr_vvms/ccp_tr_ewmwtbf.c | 79 +
sr_vvms/ccp_tr_exitwm.c | 147 +
sr_vvms/ccp_tr_exwmreq.c | 37 +
sr_vvms/ccp_tr_flushlk.c | 39 +
sr_vvms/ccp_tr_gotdrt.c | 54 +
sr_vvms/ccp_tr_lkrqwake.c | 54 +
sr_vvms/ccp_tr_null.c | 20 +
sr_vvms/ccp_tr_opendb1.c | 119 +
sr_vvms/ccp_tr_opendb1a.c | 42 +
sr_vvms/ccp_tr_opendb1b.c | 154 +
sr_vvms/ccp_tr_opendb1e.c | 60 +
sr_vvms/ccp_tr_opendb3.c | 103 +
sr_vvms/ccp_tr_opendb3a.c | 28 +
sr_vvms/ccp_tr_stop.c | 43 +
sr_vvms/ccp_tr_writedb.c | 53 +
sr_vvms/ccp_tr_writedb1.c | 151 +
sr_vvms/ccp_userwait.c | 89 +
sr_vvms/ccp_writedb2.c | 192 +
sr_vvms/ccp_writedb2.h | 16 +
sr_vvms/ccp_writedb3.c | 76 +
sr_vvms/ccp_writedb3.h | 16 +
sr_vvms/ccp_writedb4.c | 61 +
sr_vvms/ccp_writedb4a.c | 39 +
sr_vvms/ccp_writedb5.c | 26 +
sr_vvms/ce_init.c | 56 +
sr_vvms/ce_substitute.c | 86 +
sr_vvms/change_fhead_timer.c | 75 +
sr_vvms/cli.c | 370 +
sr_vvms/cli.h | 27 +
sr_vvms/cli_get_str_all_piece.c | 61 +
sr_vvms/cmicom.com | 73 +
sr_vvms/cmidefsp.h | 168 +
sr_vvms/cms_load.com | 105 +
sr_vvms/cms_load_verify_from_to_version.com | 99 +
sr_vvms/comall.m | 259 +
sr_vvms/comimage.com | 110 +
sr_vvms/comp_lits.c | 48 +
sr_vvms/comque.com | 53 +
sr_vvms/cre_comlist.com | 45 +
sr_vvms/cre_comlistxp.com | 32 +
sr_vvms/crit_wake.c | 32 +
sr_vvms/ctrap_set.c | 49 +
sr_vvms/ctrlc_set.c | 71 +
sr_vvms/ctrly_set.c | 56 +
sr_vvms/curr_dev_outbndset.c | 30 +
sr_vvms/curr_dev_outbndset.h | 17 +
sr_vvms/cvtprot.c | 51 +
sr_vvms/cvttime.c | 27 +
sr_vvms/dbcertify_cmd.cld | 20 +
sr_vvms/dbcertify_dbfilop.c | 222 +
sr_vvms/dbcertify_exit_handler.c | 124 +
sr_vvms/dbcertify_parse_and_dispatch.c | 62 +
sr_vvms/dbcx_ref.c | 54 +
sr_vvms/dbcx_ref.h | 17 +
sr_vvms/dbfilop.c | 241 +
sr_vvms/dbgflip.com | 38 +
sr_vvms/dbinit_ch.c | 240 +
sr_vvms/dcp_a2c.c | 198 +
sr_vvms/dcp_a2c.h | 24 +
sr_vvms/dcp_get_circuit.c | 44 +
sr_vvms/dcp_get_groups.c | 73 +
sr_vvms/dcp_get_maxrecsize.c | 50 +
sr_vvms/dcp_get_volsets.c | 163 +
sr_vvms/dcpsubs.c | 180 +
sr_vvms/dcpsubs.h | 17 +
sr_vvms/ddp_db_op.c | 348 +
sr_vvms/ddp_spkitbld.dat | 6 +
sr_vvms/ddp_trace_output.c | 52 +
sr_vvms/ddp_trace_output.h | 25 +
sr_vvms/ddpcom.h | 102 +
sr_vvms/ddpgvusr.c | 772 +
sr_vvms/ddpkithlp.com | 157 +
sr_vvms/ddpkitinstal.com | 557 +
sr_vvms/ddpserver.c | 466 +
sr_vvms/dec_err.c | 42 +
sr_vvms/decddp.c | 393 +
sr_vvms/decddp.h | 44 +
sr_vvms/decddp_log_error.c | 86 +
sr_vvms/define-old-library-logicals.com | 137 +
sr_vvms/del_sec.c | 37 +
sr_vvms/del_sec.h | 17 +
sr_vvms/desblk.h | 25 +
sr_vvms/desc2mval.c | 162 +
sr_vvms/desc2mval.h | 19 +
sr_vvms/dfntmpmbx.c | 39 +
sr_vvms/dfntmpmbx.h | 17 +
sr_vvms/disable_ctrl.c | 20 +
sr_vvms/disk_block_available.c | 55 +
sr_vvms/disk_block_available.h | 17 +
sr_vvms/dm_read.c | 263 +
sr_vvms/do_verify.c | 24 +
sr_vvms/do_xform.c | 80 +
sr_vvms/do_zcall.c | 567 +
sr_vvms/dpgbldir_sysops.c | 162 +
sr_vvms/dpgbldir_sysops.h | 22 +
sr_vvms/dse.c | 177 +
sr_vvms/dse.hlp | 1158 ++
sr_vvms/dse_cmd.cld | 353 +
sr_vvms/dse_ctrlc_setup.c | 65 +
sr_vvms/dse_help.c | 66 +
sr_vvms/dse_open.c | 184 +
sr_vvms/dse_puttime.c | 26 +
sr_vvms/dsk_read.c | 173 +
sr_vvms/dsk_write.c | 184 +
sr_vvms/dsk_write_nocache.c | 111 +
sr_vvms/dsm_api.c | 895 ++
sr_vvms/dtgbldir.c | 225 +
sr_vvms/edrelbta.m | 37 +
sr_vvms/edrelnam.m | 37 +
sr_vvms/efn.h | 39 +
sr_vvms/error_return.c | 97 +
sr_vvms/errorsp.h | 170 +
sr_vvms/ether_trace.c | 100 +
sr_vvms/exi_ch.c | 31 +
sr_vvms/exttime.c | 37 +
sr_vvms/f_piece.c | 88 +
sr_vvms/fetch_cms_version.com | 90 +
sr_vvms/fgn_parms.c | 50 +
sr_vvms/fgn_resolve_lab.c | 22 +
sr_vvms/fgncal_ch.c | 61 +
sr_vvms/fgncal_rundown.c | 60 +
sr_vvms/fgncal_zlinit.c | 23 +
sr_vvms/fgncalsp.h | 17 +
sr_vvms/fid_from_sec.c | 43 +
sr_vvms/fid_from_sec.h | 17 +
sr_vvms/file_head_read.c | 97 +
sr_vvms/file_head_write.c | 80 +
sr_vvms/filestruct.h | 54 +
sr_vvms/finish_active_jnl_qio.c | 57 +
sr_vvms/fix_pages.c | 66 +
sr_vvms/gbldirnam.h | 15 +
sr_vvms/gde.hlp | 887 ++
sr_vvms/gdeget.m | 334 +
sr_vvms/gdeoget.m | 436 +
sr_vvms/gdeput.m | 176 +
sr_vvms/gdeverif.m | 196 +
sr_vvms/gds_file_size.c | 59 +
sr_vvms/gds_rundown.c | 583 +
sr_vvms/gdsfheadsp.h | 22 +
sr_vvms/gdsfilext.c | 387 +
sr_vvms/gen_gtm_threadgbl_deftypes.com | 159 +
sr_vvms/generic_exit_handler.c | 218 +
sr_vvms/generic_exit_handler.h | 18 +
sr_vvms/get_command_line.c | 46 +
sr_vvms/get_full_path.c | 70 +
sr_vvms/get_page_size.c | 26 +
sr_vvms/get_proc_info.c | 60 +
sr_vvms/get_src_line.c | 217 +
sr_vvms/get_tpu_addr.c | 26 +
sr_vvms/get_tpu_addr.h | 17 +
sr_vvms/getjobnum.c | 34 +
sr_vvms/getline.com | 66 +
sr_vvms/getstorage.c | 24 +
sr_vvms/getzmode.c | 38 +
sr_vvms/getzprocess.c | 43 +
sr_vvms/global_name.c | 47 +
sr_vvms/go_load.c | 344 +
sr_vvms/golevel.c | 53 +
sr_vvms/goq_load.c | 193 +
sr_vvms/goq_m11_load.c | 437 +
sr_vvms/goq_mvx_load.c | 520 +
sr_vvms/grab_crit.c | 111 +
sr_vvms/grab_crit_immediate.c | 109 +
sr_vvms/grab_lock.c | 67 +
sr_vvms/gse.mpt | 77 +
sr_vvms/gt_timer.h | 72 +
sr_vvms/gt_timers.c | 155 +
sr_vvms/gtcm_spkitbld.dat | 6 +
sr_vvms/gtcmkithlp.com | 146 +
sr_vvms/gtcmkitinstal.com | 363 +
sr_vvms/gtcmstop.m | 58 +
sr_vvms/gtcx_spkitbld.dat | 6 +
sr_vvms/gtcxkithlp.com | 126 +
sr_vvms/gtcxkitinstal.com | 302 +
sr_vvms/gtm$ce.h | 28 +
sr_vvms/gtm$ce_establish.c | 58 +
sr_vvms/gtm$ce_getinfo.c | 136 +
sr_vvms/gtm$compile.c | 162 +
sr_vvms/gtm$dmod.m | 1 +
sr_vvms/gtm$interrupt.c | 42 +
sr_vvms/gtm$ivp.tlb | Bin 0 -> 11265 bytes
sr_vvms/gtm$startup.c | 452 +
sr_vvms/gtm_bintim.c | 65 +
sr_vvms/gtm_blkast.c | 41 +
sr_vvms/gtm_ce.h | 28 +
sr_vvms/gtm_conv.c | 38 +
sr_vvms/gtm_conv.h | 27 +
sr_vvms/gtm_deq.c | 67 +
sr_vvms/gtm_enq.c | 53 +
sr_vvms/gtm_enqw.c | 88 +
sr_vvms/gtm_env_init_sp.c | 54 +
sr_vvms/gtm_env_translate.c | 110 +
sr_vvms/gtm_event_log.c | 22 +
sr_vvms/gtm_file_remove.c | 55 +
sr_vvms/gtm_file_stat.c | 110 +
sr_vvms/gtm_getlkiw.c | 31 +
sr_vvms/gtm_getlkiw.h | 17 +
sr_vvms/gtm_getmsg.c | 36 +
sr_vvms/gtm_logicals.h | 86 +
sr_vvms/gtm_mtio.h | 15 +
sr_vvms/gtm_putmsg.c | 42 +
sr_vvms/gtm_rename.c | 64 +
sr_vvms/gtm_snprintf.c | 29 +
sr_vvms/gtm_spkitbld.dat | 11 +
sr_vvms/gtm_stdio.h | 50 +
sr_vvms/gtm_utf8.c | 28 +
sr_vvms/gtm_utf8.h | 46 +
sr_vvms/gtm_verify_symbols.com | 38 +
sr_vvms/gtm_wake.c | 19 +
sr_vvms/gtmcollect.opt | 41 +
sr_vvms/gtmcommands.cldx | 28 +
sr_vvms/gtmdc_spkitbld.dat | 6 +
sr_vvms/gtmdckithlp.com | 94 +
sr_vvms/gtmdckitinstal.com | 229 +
sr_vvms/gtmfi_spkitbld.dat | 6 +
sr_vvms/gtmfikithlp.com | 131 +
sr_vvms/gtmfikitinstal.com | 239 +
sr_vvms/gtmidef.h | 26 +
sr_vvms/gtmio.h | 104 +
sr_vvms/gtmkithlp.com | 172 +
sr_vvms/gtmkitinstal.com | 443 +
sr_vvms/gtmrecv.c | 334 +
sr_vvms/gtmrecv.h | 330 +
sr_vvms/gtmrecv_end.c | 167 +
sr_vvms/gtmrecv_fetchresync.c | 290 +
sr_vvms/gtmrecv_poll_actions.c | 446 +
sr_vvms/gtmrecv_process.c | 1113 ++
sr_vvms/gtmrecv_shutdown.c | 150 +
sr_vvms/gtmsecshr.h | 34 +
sr_vvms/gtmsource.c | 556 +
sr_vvms/gtmsource.h | 410 +
sr_vvms/gtmsource_changelog.c | 85 +
sr_vvms/gtmsource_checkhealth.c | 134 +
sr_vvms/gtmsource_end.c | 138 +
sr_vvms/gtmsource_flush_fh.c | 102 +
sr_vvms/gtmsource_get_opt.c | 349 +
sr_vvms/gtmsource_heartbeat.c | 248 +
sr_vvms/gtmsource_mode_change.c | 116 +
sr_vvms/gtmsource_process.c | 841 ++
sr_vvms/gtmsource_process_ops.c | 740 +
sr_vvms/gtmsource_readfiles.c | 1704 +++
sr_vvms/gtmsource_readpool.c | 201 +
sr_vvms/gtmsource_secnd_update.c | 61 +
sr_vvms/gtmsource_seqno_init.c | 82 +
sr_vvms/gtmsource_showbacklog.c | 65 +
sr_vvms/gtmsource_shutdown.c | 185 +
sr_vvms/gtmsource_statslog.c | 83 +
sr_vvms/gtmsource_stopfilter.c | 68 +
sr_vvms/gtmstop.m | 47 +
sr_vvms/gvcmy_open.h | 17 +
sr_vvms/gvcst_init_sysops.c | 902 ++
sr_vvms/gvusr_queryget.c | 47 +
sr_vvms/ident.h | 12 +
sr_vvms/incr_link.h | 17 +
sr_vvms/init_sec.c | 38 +
sr_vvms/init_sec.h | 17 +
sr_vvms/interlock.h | 58 +
sr_vvms/io_get_fgn_driver.c | 76 +
sr_vvms/io_init_name.c | 37 +
sr_vvms/io_is_rm.c | 23 +
sr_vvms/io_is_sn.c | 44 +
sr_vvms/io_open_try.c | 154 +
sr_vvms/io_type.c | 98 +
sr_vvms/ioff_open.c | 19 +
sr_vvms/iomb_cancel_read.c | 34 +
sr_vvms/iomb_close.c | 55 +
sr_vvms/iomb_dataread.c | 134 +
sr_vvms/iomb_dummy.c | 18 +
sr_vvms/iomb_flush.c | 18 +
sr_vvms/iomb_open.c | 188 +
sr_vvms/iomb_rdone.c | 55 +
sr_vvms/iomb_read.c | 57 +
sr_vvms/iomb_readfl.c | 59 +
sr_vvms/iomb_use.c | 104 +
sr_vvms/iomb_write.c | 82 +
sr_vvms/iomb_wteol.c | 35 +
sr_vvms/iomb_wtff.c | 29 +
sr_vvms/iomb_wtone.c | 25 +
sr_vvms/iombdef.h | 45 +
sr_vvms/iomt_closesp.c | 19 +
sr_vvms/iomt_open.c | 338 +
sr_vvms/iomt_opensp.c | 40 +
sr_vvms/iomt_qio.c | 44 +
sr_vvms/iomt_rdlblk.c | 36 +
sr_vvms/iomt_sense.c | 29 +
sr_vvms/iomt_tm.c | 30 +
sr_vvms/iomt_wtlblk.c | 22 +
sr_vvms/iomtdef.h | 106 +
sr_vvms/iorm_close.c | 128 +
sr_vvms/iorm_flush.c | 28 +
sr_vvms/iorm_get.c | 105 +
sr_vvms/iorm_jbc.c | 206 +
sr_vvms/iorm_open.c | 405 +
sr_vvms/iorm_put.c | 72 +
sr_vvms/iorm_rdone.c | 93 +
sr_vvms/iorm_read.c | 100 +
sr_vvms/iorm_readfl.c | 107 +
sr_vvms/iorm_use.c | 280 +
sr_vvms/iorm_write.c | 63 +
sr_vvms/iorm_wteol.c | 73 +
sr_vvms/iormdef.h | 55 +
sr_vvms/iosb_disk.h | 26 +
sr_vvms/iosize.h | 12 +
sr_vvms/iosp.h | 25 +
sr_vvms/iotcp_select.h | 49 +
sr_vvms/iotcp_string.c | 107 +
sr_vvms/iott_cancel_read.c | 39 +
sr_vvms/iott_clockfini.c | 21 +
sr_vvms/iott_close.c | 111 +
sr_vvms/iott_flush.c | 73 +
sr_vvms/iott_open.c | 254 +
sr_vvms/iott_rdone.c | 320 +
sr_vvms/iott_read.c | 30 +
sr_vvms/iott_readfl.c | 223 +
sr_vvms/iott_resetast.c | 58 +
sr_vvms/iott_use.c | 495 +
sr_vvms/iott_write.c | 96 +
sr_vvms/iott_wtclose.c | 57 +
sr_vvms/iott_wtctrlu.c | 63 +
sr_vvms/iott_wtfini.c | 29 +
sr_vvms/iott_wtstart.c | 76 +
sr_vvms/iottdef.h | 147 +
sr_vvms/iottdefsp.h | 34 +
sr_vvms/ious_iocontrol.c | 58 +
sr_vvms/ious_open.c | 49 +
sr_vvms/ious_rdone.c | 32 +
sr_vvms/ious_read.c | 34 +
sr_vvms/ious_readfl.c | 36 +
sr_vvms/ious_write.c | 28 +
sr_vvms/ious_wtone.c | 28 +
sr_vvms/is_file_identical.c | 140 +
sr_vvms/is_five_bit.c | 27 +
sr_vvms/is_five_bit.h | 17 +
sr_vvms/is_proc_alive.c | 31 +
sr_vvms/jnl_file_extend.c | 386 +
sr_vvms/jnl_file_open.c | 300 +
sr_vvms/jnl_output_sp.c | 298 +
sr_vvms/jnl_prc_vector.c | 99 +
sr_vvms/jnlext_write.c | 42 +
sr_vvms/jnlpool_init.c | 384 +
sr_vvms/jnlsp.h | 133 +
sr_vvms/jobchild_init.c | 298 +
sr_vvms/jobchild_init.h | 17 +
sr_vvms/jobsp.h | 86 +
sr_vvms/jpv_v10to12.c | 39 +
sr_vvms/jpv_v10to12.h | 37 +
sr_vvms/kitprepare.com | 73 +
sr_vvms/kitstart.com | 153 +
sr_vvms/la.hlp | 170 +
sr_vvms/la_cmnd.cld | 114 +
sr_vvms/la_convert.c | 42 +
sr_vvms/la_create.c | 103 +
sr_vvms/la_edit.c | 150 +
sr_vvms/la_encrypt.c | 51 +
sr_vvms/la_exit.c | 21 +
sr_vvms/la_fputmsgu.c | 48 +
sr_vvms/la_fputmsgu.h | 16 +
sr_vvms/la_getcli.c | 138 +
sr_vvms/la_getdat.c | 81 +
sr_vvms/la_getdb.c | 85 +
sr_vvms/la_getnum.c | 77 +
sr_vvms/la_getstr.c | 71 +
sr_vvms/la_help.c | 42 +
sr_vvms/la_initial.c | 111 +
sr_vvms/la_initpak.c | 45 +
sr_vvms/la_io.c | 201 +
sr_vvms/la_io.h | 61 +
sr_vvms/la_listpak.c | 132 +
sr_vvms/la_maint.c | 126 +
sr_vvms/la_match.c | 92 +
sr_vvms/la_mdl2nam.c | 75 +
sr_vvms/la_nam2mdl.c | 98 +
sr_vvms/la_putdb.c | 71 +
sr_vvms/la_putfldr.c | 38 +
sr_vvms/la_puthead.c | 41 +
sr_vvms/la_putline.c | 32 +
sr_vvms/la_putline.h | 16 +
sr_vvms/la_putmsgs.c | 27 +
sr_vvms/la_putmsgu.c | 48 +
sr_vvms/la_showpak.c | 55 +
sr_vvms/la_store.c | 61 +
sr_vvms/la_uniqlid.c | 48 +
sr_vvms/la_validate.c | 65 +
sr_vvms/la_writepak.c | 153 +
sr_vvms/la_writepak.h | 16 +
sr_vvms/ladef.h | 133 +
sr_vvms/laerrors.msg | 89 +
sr_vvms/lbrdef.h | 143 +
sr_vvms/license_adm.c | 45 +
sr_vvms/linkshr.com | 28 +
sr_vvms/list_file.c | 279 +
sr_vvms/lke.c | 132 +
sr_vvms/lke.hlp | 305 +
sr_vvms/lke_cmd.cld | 46 +
sr_vvms/lke_getansw.c | 53 +
sr_vvms/lke_help.c | 44 +
sr_vvms/lke_setgdr.c | 74 +
sr_vvms/lm_cmnd.cld | 82 +
sr_vvms/lm_convert.c | 36 +
sr_vvms/lm_edit.c | 115 +
sr_vvms/lm_getnid.c | 107 +
sr_vvms/lm_help.c | 42 +
sr_vvms/lm_listpak.c | 123 +
sr_vvms/lm_maint.c | 138 +
sr_vvms/lm_mdl_nid.c | 51 +
sr_vvms/lm_putmsgu.c | 41 +
sr_vvms/lm_register.c | 99 +
sr_vvms/lm_showcl.c | 92 +
sr_vvms/lmdef.h | 24 +
sr_vvms/lmu.c | 49 +
sr_vvms/lmu.hlp | 589 +
sr_vvms/load.h | 21 +
sr_vvms/lockdefs.h | 17 +
sr_vvms/locks.h | 35 +
sr_vvms/lp_acquire.c | 95 +
sr_vvms/lp_confirm.c | 64 +
sr_vvms/lp_id.c | 64 +
sr_vvms/lp_licensed.c | 118 +
sr_vvms/lperrors.msg | 22 +
sr_vvms/m_recall.c | 133 +
sr_vvms/m_recall.h | 17 +
sr_vvms/map_sym.c | 137 +
sr_vvms/mapdb.awk | 74 +
sr_vvms/mapoff.m | 115 +
sr_vvms/mapoffset.awk | 32 +
sr_vvms/mcompile.c | 18 +
sr_vvms/mdefsa.h | 82 +
sr_vvms/mem_access.c | 45 +
sr_vvms/mem_list.c | 328 +
sr_vvms/mem_list.h | 21 +
sr_vvms/movempt.com | 63 +
sr_vvms/msg.h | 45 +
sr_vvms/mu_cre_file.c | 308 +
sr_vvms/mu_cre_vms_structs.c | 60 +
sr_vvms/mu_cre_vms_structs.h | 17 +
sr_vvms/mu_extract.c | 392 +
sr_vvms/mu_getlst.c | 144 +
sr_vvms/mu_gvis.c | 45 +
sr_vvms/mu_load_stat.c | 50 +
sr_vvms/mu_load_stat.h | 18 +
sr_vvms/mu_outofband_setup.c | 61 +
sr_vvms/mu_rndwn_file.c | 607 +
sr_vvms/mu_rndwn_file.h | 17 +
sr_vvms/mu_rndwn_replpool.c | 148 +
sr_vvms/mu_rndwn_replpool.h | 18 +
sr_vvms/mu_signal_process.c | 118 +
sr_vvms/mu_upgrd_outofband.c | 58 +
sr_vvms/mubchkfs.c | 82 +
sr_vvms/mubexpfilnam.c | 76 +
sr_vvms/mubfilcpy.c | 492 +
sr_vvms/mubgetfil.c | 104 +
sr_vvms/mubinccpy.c | 747 +
sr_vvms/mucblkini.c | 75 +
sr_vvms/mumps.hlp | 19589 ++++++++++++++++++++++++++
sr_vvms/mumps_clitab.cld | 25 +
sr_vvms/mup_bak_sys.c | 56 +
sr_vvms/mupip.c | 145 +
sr_vvms/mupip.hlp | 2355 ++++
sr_vvms/mupip_cmd.cld | 482 +
sr_vvms/mupip_ctrl.c | 33 +
sr_vvms/mupip_ctrl.h | 17 +
sr_vvms/mupip_cvtgbl.c | 177 +
sr_vvms/mupip_cvtpgm.c | 215 +
sr_vvms/mupip_dispatch.c | 148 +
sr_vvms/mupip_exit.c | 23 +
sr_vvms/mupip_ftok.c | 52 +
sr_vvms/mupip_getcmd.c | 76 +
sr_vvms/mupip_getcmd.h | 17 +
sr_vvms/mupip_help.c | 36 +
sr_vvms/mupip_restore.c | 555 +
sr_vvms/mupip_rundown.c | 376 +
sr_vvms/mupip_set_file.c | 562 +
sr_vvms/mupip_set_jnlfile.c | 137 +
sr_vvms/muprecsp.h | 21 +
sr_vvms/mur_cre_file_extfmt.c | 136 +
sr_vvms/mur_read_file_sp.c | 171 +
sr_vvms/murgetlst.c | 48 +
sr_vvms/mutexsp.h | 51 +
sr_vvms/mval2desc.c | 255 +
sr_vvms/mval2desc.h | 19 +
sr_vvms/newincver.com | 224 +
sr_vvms/nmadef.h | 1128 ++
sr_vvms/ntd_root.c | 15 +
sr_vvms/obj_code.c | 213 +
sr_vvms/ojastread.c | 62 +
sr_vvms/ojch.c | 56 +
sr_vvms/ojchkbytcnt.c | 47 +
sr_vvms/ojchkfs.c | 47 +
sr_vvms/ojcleanup.c | 60 +
sr_vvms/ojcrembxs.c | 160 +
sr_vvms/ojdefbaspri.c | 40 +
sr_vvms/ojdefdeffs.c | 40 +
sr_vvms/ojdefimage.c | 50 +
sr_vvms/ojdefprcnam.c | 82 +
sr_vvms/ojerrcleanup.c | 50 +
sr_vvms/ojhex_to_str.c | 33 +
sr_vvms/ojmba_to_unit.c | 34 +
sr_vvms/ojmbxio.c | 39 +
sr_vvms/ojparams.c | 269 +
sr_vvms/ojsetattn.c | 44 +
sr_vvms/ojtmrinit.c | 54 +
sr_vvms/ojtmrrtn.c | 27 +
sr_vvms/ojunit_to_mba.c | 38 +
sr_vvms/op_fgnlookup.c | 65 +
sr_vvms/op_fgnlookup.h | 17 +
sr_vvms/op_fn.h | 31 +
sr_vvms/op_fnfgncal.c | 71 +
sr_vvms/op_fngetdvi.c | 297 +
sr_vvms/op_fngetjpi.c | 227 +
sr_vvms/op_fngetlki.c | 171 +
sr_vvms/op_fngetsyi.c | 181 +
sr_vvms/op_fnrandom.c | 40 +
sr_vvms/op_fnzcall.c | 86 +
sr_vvms/op_fnzfile.c | 496 +
sr_vvms/op_fnzlkid.c | 52 +
sr_vvms/op_fnzp1.c | 219 +
sr_vvms/op_fnzparse.c | 211 +
sr_vvms/op_fnzpid.c | 94 +
sr_vvms/op_fnzpiece.c | 97 +
sr_vvms/op_fnzpriv.c | 135 +
sr_vvms/op_fnzsearch.c | 145 +
sr_vvms/op_fnzsetprv.c | 182 +
sr_vvms/op_fnztrnlnm.c | 296 +
sr_vvms/op_horolog.c | 36 +
sr_vvms/op_job.c | 366 +
sr_vvms/op_setzp1.c | 292 +
sr_vvms/op_zattach.c | 82 +
sr_vvms/op_zedit.c | 128 +
sr_vvms/op_zhelp.c | 53 +
sr_vvms/op_zlink.c | 421 +
sr_vvms/op_zmess.c | 71 +
sr_vvms/pid.m | 64 +
sr_vvms/probe.c | 44 +
sr_vvms/prvdef.h | 87 +
sr_vvms/quad2asc.c | 96 +
sr_vvms/quad2asc.h | 18 +
sr_vvms/rc_cpt_ops.c | 37 +
sr_vvms/recvpool_init.c | 216 +
sr_vvms/reg_cmcheck.c | 51 +
sr_vvms/rel_crit.c | 85 +
sr_vvms/rel_lock.c | 63 +
sr_vvms/rel_quant.c | 51 +
sr_vvms/relqueopi.mar | 195 +
sr_vvms/remove_rms.c | 48 +
sr_vvms/repl_create_server.c | 301 +
sr_vvms/repl_fork_rcvr_server.c | 107 +
sr_vvms/repl_ipc_cleanup.c | 184 +
sr_vvms/repl_log.c | 98 +
sr_vvms/repl_log_init.c | 23 +
sr_vvms/repl_msg.h | 119 +
sr_vvms/repl_sem.c | 326 +
sr_vvms/repl_sem.h | 74 +
sr_vvms/repl_sem_sp.h | 40 +
sr_vvms/repl_shm.c | 224 +
sr_vvms/repl_shm.h | 49 +
sr_vvms/repl_sp.h | 90 +
sr_vvms/repl_utils.c | 99 +
sr_vvms/route_table.c | 208 +
sr_vvms/route_table.h | 24 +
sr_vvms/rtn_tbl_sort.c | 164 +
sr_vvms/rtnhdr.h | 152 +
sr_vvms/runall.com | 170 +
sr_vvms/same_device_check.c | 32 +
sr_vvms/send_msg.c | 116 +
sr_vvms/set_jnl_file_close.c | 135 +
sr_vvms/set_num_additional_processors.c | 50 +
sr_vvms/set_zstatus.c | 122 +
sr_vvms/setactive_silent.com | 24 +
sr_vvms/setfileprot.c | 52 +
sr_vvms/setfileprot.h | 17 +
sr_vvms/setterm.c | 54 +
sr_vvms/sgtm_putmsg.c | 108 +
sr_vvms/source_file.c | 207 +
sr_vvms/spawn_and_bgwait.c | 33 +
sr_vvms/spkitbld.m | 42 +
sr_vvms/spkitupdate.com | 28 +
sr_vvms/srm_check.com | 29 +
sr_vvms/st.mpt | 77 +
sr_vvms/std_dev_outbndset.c | 52 +
sr_vvms/stpimg.m | 22 +
sr_vvms/term_setup.c | 45 +
sr_vvms/timedef.h | 24 +
sr_vvms/timersp.h | 22 +
sr_vvms/trans_log_name.c | 134 +
sr_vvms/ttt.c | 695 +
sr_vvms/ttt.txt | 1008 ++
sr_vvms/upd_log_init.c | 74 +
sr_vvms/user_rundown.c | 76 +
sr_vvms/util_input.c | 76 +
sr_vvms/util_output.c | 330 +
sr_vvms/util_output_cm.c | 91 +
sr_vvms/util_spawn.c | 38 +
sr_vvms/v010_jnl_prc_vector.c | 100 +
sr_vvms/v010_jnlsp.h | 80 +
sr_vvms/v15_filestruct.h | 15 +
sr_vvms/vaxsym.h | 19 +
sr_vvms/vms_cms_load.com | 211 +
sr_vvms/vmsdtype.h | 29 +
sr_vvms/wait_for_block_flush.c | 42 +
sr_vvms/wcs_clean_dbsync_ast.c | 306 +
sr_vvms/wcs_clean_dbsync_timer_ast.c | 57 +
sr_vvms/wcs_flu.c | 296 +
sr_vvms/wcs_get_space.c | 162 +
sr_vvms/wcs_wtfini.c | 227 +
sr_vvms/wcs_wtstart.c | 229 +
sr_vvms/zcall.h | 66 +
sr_vvms/zcch.c | 46 +
sr_vvms/zcdef.h | 51 +
sr_vvms/zl_cmd_qlf.c | 47 +
sr_vvms/zl_olb.c | 53 +
sr_vvms/zl_olb.h | 17 +
sr_vvms/zro_gettok.c | 54 +
sr_vvms/zro_load.c | 272 +
sr_vvms/zro_search.c | 163 +
sr_vvms/zroutinessp.h | 39 +
sr_vvms/zshow_devices.c | 564 +
sr_vvms/zshow_zcalls.c | 93 +
sr_x86_64/compswap.s | 3 +-
sr_x86_64/merrors_ansi.h | 79 +-
sr_x86_64/merrors_ctl.c | 174 +-
sr_x86_64/op_exfun.s | 4 +-
sr_x86_64/op_mprofexfun.s | 4 +-
sr_x86_64/ttt.c | 1377 +-
1460 files changed, 153926 insertions(+), 17197 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b4fff87..b200284 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -26,7 +26,7 @@ foreach(lang ${languages})
endforeach()
# Defaults
-set(version V6.0-001)
+set(version V6.0-003)
if("${version}" STREQUAL "")
set(version V9.9-0)
endif()
@@ -37,7 +37,7 @@ if(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE)
endif()
# If it's a debug build make sure GT.M uses all of its debug options
-set(CMAKE_C_FLAGS_DEBUG -DDEBUG)
+set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DDEBUG")
set(install_permissions_script
OWNER_READ OWNER_EXECUTE OWNER_WRITE
@@ -56,6 +56,7 @@ set(gtm_osarch_libs "")
# Define these ahead of establishing platforms
set(gt_src_list)
set(sources_used "")
+set(extralibs "")
set(is_encryption_supported 1)
set(libmumpsrestoreregex "")
message("--> OS = ${CMAKE_SYSTEM_NAME} / ARCH = ${CMAKE_SYSTEM_PROCESSOR}")
@@ -374,6 +375,7 @@ foreach(lib
mupip
stub
mumps
+ ${extralibs}
)
add_library(lib${lib} STATIC ${lib${lib}_SOURCES})
set_property(TARGET lib${lib} PROPERTY OUTPUT_NAME ${lib})
@@ -441,7 +443,7 @@ target_link_libraries(ftok libmumps libstub)
if("${CMAKE_SYSTEM_NAME}" STREQUAL "SunOS")
add_executable(gtm_svc ${gtm_svc_SOURCES})
- target_link_libraries(gtm_svc libmumps libcmisockettcp libgnpclient libgtmrpc)
+ target_link_libraries(gtm_svc libmumps libgnpclient libcmisockettcp libgtmrpc)
endif()
foreach(t ${with_export})
set_target_properties(${t} PROPERTIES
@@ -465,9 +467,7 @@ if(is_encryption_supported)
# Iterate over the list of GPG related libraries
foreach(gpglib gpg-error gpgme gcrypt)
# For each library, we need a new CMake variable, hence GPGLIB_${gpglib}
- find_library(GPGLIB_${gpglib}
- NAME ${gpglib}
- PATHS ${CMAKE_LIBRARY_PATH} /usr/local/lib64 /usr/local/lib)
+ find_library(GPGLIB_${gpglib} NAME ${gpglib} PATHS ${CMAKE_LIBRARY_PATH})
# Append the found library to the list
set(GPG_LIBRARIES ${GPG_LIBRARIES} ${GPGLIB_${gpglib}})
endforeach()
@@ -717,7 +717,10 @@ endforeach()
#-----------------------------------------------------------------------------
set(gtm_hlp mumps.hlp)
set(gde_hlp gde.hlp)
-foreach(help gtm gde)
+set(mupip_hlp mupip.hlp)
+set(dse_hlp dse.hlp)
+set(lke_hlp lke.hlp)
+foreach(help gtm gde mupip dse lke)
set(CMAKE_CONFIGURABLE_FILE_CONTENT
"Change -segment DEFAULT -block=2048 -file=\$gtm_dist/${help}help.dat
Change -region DEFAULT -record=1020 -key=255
diff --git a/README.txt b/LICENSE
similarity index 100%
rename from README.txt
rename to LICENSE
diff --git a/README b/README
index 7eb8ac6..c7a9d51 100644
--- a/README
+++ b/README
@@ -1,6 +1,6 @@
-All software in this package is part of FIS GT.M (http://fis-gtm.com)
+All software in this package is part of FIS GT.M (http://fis-gtm.com)
which is Copyright 2013 Fidelity Information Services, Inc., and
-provided to you under the terms of a license. If there is a COPYING
+provided to you under the terms of a license. If there is a COPYING
file included in this package, it contains the terms of the license under
which the package is provided to you. If there is not a COPYING file in
the package, you must ensure that your use of FIS GT.M complies with the
@@ -22,49 +22,68 @@ To build GT.M for Linux, do the following steps:
Install developement libraries libelf, zlib, libicu, libgpgme, libgpg-error,
libgcrypt.
+ Ensure that your locale settings are correct, otherwise you will see
+ GTM-E-NONUTF8LOCALE messages. Refer the Messages and Recovery Procedures
+ Manual if you do encounter these messages.
+
[optional] The GT.M source tarball includes pre-generated files. To generate
these files requires a binary distribution of GT.M. You can download GT.M
from http://sourceforge.net/projects/fis-gtm/ Unpack the tar file and run
the configure script as root. Note: the tar file unpacks everything into
your current working directory, not a new subdirectory. The Linux Standard
- Base (LSB) install path for GT.M V60000 is /opt/lsb-gtm/V6.0-000_i686 or
- /opt/lsb-gtm/V6.0-000_x8664.
- $ tar xfz gtm_V60000_linux_i686_pro.tar.gz
- $ sudo sh ./configure
+ Base (LSB) install path for GT.M V6.0-003 is /opt/fis-gtm/V6.0-003_i686 or
+ /opt/fis-gtm/V6.0-003_x8664. These instrcutions are written using x8664, please
+ use i686 as necessary.
- # Provide the directory path to cmake using
- # -D GTM_DIST:PATH=$gtm_dist
+ $ tar xfz gtm_V60003_linux_x8664_pro.tar.gz
+
+ # Note down the installation path for use with cmake below
+
+ $ sudo sh ./configure
2. Unpack the GT.M sources
- Change directory in the directory that you will place the GT.M source,
- here after referred to as <gtm-directory>.
- $ mkdir <gtm-directory>
- $ cd <gtm-directory>
- $ tar xfz gtm_V60000_linux_i686_src.tar.gz
+ The GT.M source tarball extracts to a directory with the version number in
+ the name, fis-gtm-V6.0-003
+ $ tar xfz fis-gtm-V6.0-003.tar.gz
+ $ cd fis-gtm-V6.0-003
- You should find this README, COPYING and CMakeLitst.txt file and sr_* source
- directories.
+ You should find this README, LICENSE, COPYING and CMakeLists.txt file and
+ sr_* source directories.
3. Building GT.M -
- <gtm-builddir> can be a sub directory of the source directory <gtm-directory>
-
- $ mkdir <gtm-builddir>
- $ cd <gtm-builddir>
- $ cmake <gtm-directory>
+ <fis-gtm-build> can be a sub directory of the source directory,
+ fis-gtm-V6.0-003, or any other valid path.
+ $ mkdir <fis-gtm-build>
+ $ cd <fis-gtm-build>
+ # [optional] If you installed GT.M, provide the directory path to cmake
+ # -D GTM_DIST:PATH=$gtm_dist
+ #
# By default the build produces release versions of GT.M. To build a debug
# version of GT.M supply the following parameter to cmake
# -D CMAKE_BUILD_TYPE=DEBUG
#
- # Note that the default install location is driven by CMAKE_INSTALL_PREFIX.
- # You can change this when executing cmake
- # -D CMAKE_INSTALL_PREFIX:PATH=/opt/lsb-gtm
+ # Note that the cmake install does not create the final installed GT.M.
+ # Instead, it stages GT.M for distribution. Change the CMAKE_INSTALL_PREFIX
+ # to place the staged files in a local directory. To install GT.M, you must
+ # cd to that installed directory and execute the configure script.
#
+ # -D CMAKE_INSTALL_PREFIX:PATH=${PWD}/package
+ #
+ $ cmake <path to>/fis-gtm-V6.0-003 -D CMAKE_INSTALL_PREFIX:PATH=${PWD}/package
+
$ make
$ make install
+ $ cd package/lib/fis-gtm/V6.0-003_x86_64
+
+ # Now you are ready to install GT.M. Answer a few questions and install it.
+ # The recommended installation path is /opt/fis-gtm/V6.0-003_x86_64
+
+ $ sudo ./configure
+
$ make clean
4. Packaging GT.M -
diff --git a/sr_alpha/axp.h b/sr_alpha/axp.h
new file mode 100644
index 0000000..1f514ce
--- /dev/null
+++ b/sr_alpha/axp.h
@@ -0,0 +1,133 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2002 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* axp.h - AXP machine instruction information.
+ *
+ * Requires "axp_registers.h" and "axp_gtm_registers.h".
+ *
+ */
+
+
+/* Machine instruction templates. */
+
+#define ALPHA_INS_ADDL ((unsigned)0x10 << ALPHA_SHIFT_OP)
+#define ALPHA_INS_BEQ ((unsigned)0x39 << ALPHA_SHIFT_OP)
+#define ALPHA_INS_BGE ((unsigned)0x3e << ALPHA_SHIFT_OP)
+#define ALPHA_INS_BGT ((unsigned)0x3f << ALPHA_SHIFT_OP)
+#define ALPHA_INS_BIS ((unsigned)0x11 << ALPHA_SHIFT_OP | 0x20 << ALPHA_SHIFT_FUNC)
+#define ALPHA_INS_BLE ((unsigned)0x3b << ALPHA_SHIFT_OP)
+#define ALPHA_INS_BLT ((unsigned)0x3a << ALPHA_SHIFT_OP)
+#define ALPHA_INS_BLBC ((unsigned)0x38 << ALPHA_SHIFT_OP)
+#define ALPHA_INS_BLBS ((unsigned)0x3c << ALPHA_SHIFT_OP)
+#define ALPHA_INS_BNE ((unsigned)0x3d << ALPHA_SHIFT_OP)
+#define ALPHA_INS_BSR ((unsigned)0x34 << ALPHA_SHIFT_OP)
+#define ALPHA_INS_BR ((unsigned)0x30 << ALPHA_SHIFT_OP)
+#define ALPHA_INS_JMP ((unsigned)0x1a << ALPHA_SHIFT_OP)
+#define ALPHA_INS_JSR ((unsigned)0x1a << ALPHA_SHIFT_OP | 1 << ALPHA_SHIFT_BRANCH_FUNC)
+#define ALPHA_INS_LDA ((unsigned)0x08 << ALPHA_SHIFT_OP)
+#define ALPHA_INS_LDAH ((unsigned)0x09 << ALPHA_SHIFT_OP)
+#define ALPHA_INS_LDL ((unsigned)0x28 << ALPHA_SHIFT_OP)
+#define ALPHA_INS_LDQ ((unsigned)0x29 << ALPHA_SHIFT_OP)
+#define ALPHA_INS_RET ((unsigned)0x1a << ALPHA_SHIFT_OP | 2 << ALPHA_SHIFT_BRANCH_FUNC)
+#define ALPHA_INS_STL ((unsigned)0x2c << ALPHA_SHIFT_OP)
+#define ALPHA_INS_STQ ((unsigned)0x2d << ALPHA_SHIFT_OP)
+#define ALPHA_INS_SUBL ((unsigned)0x10 << ALPHA_SHIFT_OP | 0x9 << ALPHA_SHIFT_FUNC)
+#define ALPHA_INS_SUBQ ((unsigned)0x10 << ALPHA_SHIFT_OP | 0x29 << ALPHA_SHIFT_FUNC)
+
+
+/* Bit offsets to instruction fields. */
+
+#define ALPHA_SHIFT_OP 26
+#define ALPHA_SHIFT_BRANCH_FUNC 14
+#define ALPHA_SHIFT_FUNC 5
+#define ALPHA_SHIFT_LITERAL 13
+#define ALPHA_SHIFT_RA 21
+#define ALPHA_SHIFT_RB 16
+#define ALPHA_SHIFT_RC 0
+#define ALPHA_SHIFT_BRANCH_DISP 0
+#define ALPHA_SHIFT_DISP 0
+
+
+/* Bit masks for instruction fields. */
+
+#define ALPHA_BIT_LITERAL (1 << 12)
+#define ALPHA_MASK_BRANCH_DISP 0x1fffff
+#define ALPHA_MASK_BRANCH_FUNC 0xc00000
+#define ALPHA_MASK_DISP 0xffff
+#define ALPHA_MASK_FUNC 0x7f
+#define ALPHA_MASK_LITERAL 0xff
+#define ALPHA_MASK_OP 0x3f
+#define ALPHA_MASK_REG 0x1f
+
+
+/* Alternative assembler mnemonics for machine instruction. */
+
+#define ALPHA_INS_CLRQ (ALPHA_INS_BIS \
+ | (ALPHA_REG_ZERO << ALPHA_SHIFT_RA) \
+ | (ALPHA_REG_ZERO << ALPHA_SHIFT_RB))
+#define ALPHA_INS_LPC (ALPHA_INS_BR \
+ | (GTM_REG_CODEGEN_TEMP << ALPHA_SHIFT_RA))
+#define ALPHA_INS_MOVE (ALPHA_INS_BIS \
+ | ALPHA_REG_ZERO << ALPHA_SHIFT_RB)
+#define ALPHA_INS_NOP (ALPHA_INS_BIS \
+ | (ALPHA_REG_ZERO << ALPHA_SHIFT_RA) \
+ | (ALPHA_REG_ZERO << ALPHA_SHIFT_RB) \
+ | (ALPHA_REG_ZERO << ALPHA_SHIFT_RC))
+
+
+/* Construction forms. */
+
+#define ALPHA_BRA(op,ra,disp) ((op) | ((ra) << ALPHA_SHIFT_RA) | (disp)&ALPHA_MASK_BRANCH_DISP)
+#define ALPHA_JMP(op,ra,rb) ((op) | ((ra) << ALPHA_SHIFT_RA) | ((rb) << ALPHA_SHIFT_RB))
+#define ALPHA_LIT(op,ra,lit,rc) ((op) | ((ra) << ALPHA_SHIFT_RA) \
+ | (((lit)&ALPHA_MASK_LITERAL) << ALPHA_SHIFT_LITERAL) \
+ | ALPHA_BIT_LITERAL \
+ | ((rc) << ALPHA_SHIFT_RC))
+#define ALPHA_MEM(op,ra,rb,disp)((op) | ((ra) << ALPHA_SHIFT_RA) | ((rb) << ALPHA_SHIFT_RB) | (disp)&ALPHA_MASK_DISP)
+#define ALPHA_OPR(op,ra,rb,rc) ((op) | ((ra) << ALPHA_SHIFT_RA) | ((rb) << ALPHA_SHIFT_RB) | ((rc) << ALPHA_SHIFT_RC))
+
+#ifdef DEBUG
+#define GET_OPCODE(ains) ((ains >> ALPHA_SHIFT_OP) & ALPHA_MASK_OP)
+#define GET_RA(ains) ((ains >> ALPHA_SHIFT_RA) & ALPHA_MASK_REG)
+#define GET_RB(ains) ((ains >> ALPHA_SHIFT_RB) & ALPHA_MASK_REG)
+#define GET_RC(ains) ((ains >> ALPHA_SHIFT_RC) & ALPHA_MASK_REG)
+#define GET_MEMDISP(ains) ((ains >> ALPHA_SHIFT_DISP) & ALPHA_MASK_DISP)
+#define GET_BRDISP(ains) ((ains >> ALPHA_SHIFT_BRANCH_DISP) & ALPHA_MASK_BRANCH_DISP)
+#define GET_FUNC(ains) ((ains >> ALPHA_SHIFT_FUNC) & ALPHA_MASK_FUNC)
+
+#define ADDL_INST "addl"
+#define SUBL_INST "subl"
+#define SUBQ_INST "subq"
+#define BIS_INST "bis"
+#define JSR_INST "jsr"
+#define RET_INST "ret"
+#define JMP_INST "jmp"
+#define LDA_INST "lda"
+#define LDAH_INST "ldah"
+#define LDL_INST "ldl"
+#define LDQ_INST "ldq"
+#define STL_INST "stl"
+#define STQ_INST "stq"
+#define BR_INST "br"
+#define BSR_INST "bsr"
+#define BLBC_INST "blbc"
+#define BEQ_INST "beq"
+#define BLT_INST "blt"
+#define BLE_INST "ble"
+#define BLBS_INST "blbs"
+#define BNE_INST "bne"
+#define BGE_INST "bge"
+#define BGT_INST "bgt"
+#define CONSTANT "Constant 0x"
+
+/* Space for op_code to be in */
+#define OPSPC 7
+#endif
diff --git a/sr_alpha/cacheflush.m64 b/sr_alpha/cacheflush.m64
new file mode 100644
index 0000000..27a553d
--- /dev/null
+++ b/sr_alpha/cacheflush.m64
@@ -0,0 +1,27 @@
+; ################################################################
+; # #
+; # Copyright 2001, 2008 Fidelity Information Services, Inc #
+; # #
+; # This source code contains the intellectual property #
+; # of its copyright holder(s), and is made available #
+; # under a license. If you do not know the terms of #
+; # the license, please stop and do not read further. #
+; # #
+; ################################################################
+
+ .title cacheflush - flush data and instruction caches
+
+; cacheflush
+;
+; entry:
+; a0 (r16) address of start of region to flush
+; a1 (r17) length (in bytes) of region to flush
+; a2 (r18) flag indicating which region to flush (not used on AXP)
+
+ $routine name=cacheflush, entry=cacheflush_ca, kind=null
+
+ imb
+
+ ret r26
+
+ $end_routine name=cacheflush
diff --git a/sr_alpha/double2s.c b/sr_alpha/double2s.c
new file mode 100644
index 0000000..7b7efd8
--- /dev/null
+++ b/sr_alpha/double2s.c
@@ -0,0 +1,158 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "stringpool.h"
+
+#define MAX_NUM_SIZE 64
+
+GBLREF spdesc stringpool;
+
+static char pot_index [256] =
+ {
+ -78, 78, -77, 77, 77, 77, -76, 76, 76, -75, 75, 75, -74, 74, 74, 74,
+ -73, 73, 73, -72, 72, 72, -71, 71, 71, 71, -70, 70, 70, -69, 69, 69,
+ -68, 68, 68, -67, 67, 67, 67, -66, 66, 66, -65, 65, 65, -64, 64, 64,
+ 64, -63, 63, 63, -62, 62, 62, -61, 61, 61, 61, -60, 60, 60, -59, 59,
+ 59, -58, 58, 58, 58, -57, 57, 57, -56, 56, 56, -55, 55, 55, 55, -54,
+ 54, 54, -53, 53, 53, -52, 52, 52, 52, -51, 51, 51, -50, 50, 50, -49,
+ 49, 49, 49, -48, 48, 48, -47, 47, 47, -46, 46, 46, 46, -45, 45, 45,
+ -44, 44, 44, -43, 43, 43, 43, -42, 42, 42, -41, 41, 41, -40, 40, 40,
+ 40, -39, 39, 39, -38, 38, 38, -37, 37, 37, -36, 36, 36, 36, -35, 35,
+ 35, -34, 34, 34, -33, 33, 33, 33, -32, 32, 32, -31, 31, 31, -30, 30,
+ 30, 30, -29, 29, 29, -28, 28, 28, -27, 27, 27, 27, -26, 26, 26, -25,
+ 25, 25, -24, 24, 24, 24, -23, 23, 23, -22, 22, 22, -21, 21, 21, 21,
+ -20, 20, 20, -19, 19, 19, -18, 18, 18, 18, -17, 17, 17, -16, 16, 16,
+ -15, 15, 15, 15, -14, 14, 14, -13, 13, 13, -12, 12, 12, 12, -11, 11,
+ 11, -10, 10, 10, -9, 9, 9, -8, 8, 8, 8, -7, 7, 7, -6, 6,
+ 6, -5, 5, 5, 5, -4, 4, 4, -3, 3, 3, -2, 2, 2, 2, -1
+ };
+
+static double pot [79] =
+ {
+ 1.701411834604692e+38 + 2.83e+22,
+ 1e+38, 1e+37, 1e+36, 1e+35, 1e+34, 1e+33, 1e+32,
+ 1e+31, 1e+30, 1e+29, 1e+28, 1e+27, 1e+26, 1e+25, 1e+24,
+ 1e+23, 1e+22, 1e+21, 1e+20, 1e+19, 1e+18, 1e+17, 1e+16,
+ 1e+15, 1e+14, 1e+13, 1e+12, 1e+11, 1e+10, 1e+9, 1e+8,
+ 1e+7, 1e+6, 1e+5, 1e+4, 1e+3, 1e+2, 1e+1, 1.0,
+ 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7, 1e-8,
+ 1e-9, 1e-10, 1e-11, 1e-12, 1e-13, 1e-14, 1e-15, 1e-16,
+ 1e-17, 1e-18, 1e-19, 1e-20, 1e-21, 1e-22, 1e-23, 1e-24,
+ 1e-25, 1e-26, 1e-27, 1e-28, 1e-29, 1e-30, 1e-31, 1e-32,
+ 1e-33, 1e-34, 1e-35, 1e-36, 1e-37, 1e-38, 0
+ };
+
+#define POT_UNITY 39 /* Subscript of pot: pot[POT_UNITY] == 1.0 */
+
+
+struct D_float /* Format of D-floating point datum */
+{
+ unsigned int : 7; /* fraction, bits 0:6 */
+ unsigned int exp : 8; /* exponent, bits 7:14 */
+ unsigned int sign : 1; /* sign, bit 15 */
+ unsigned int : 16; /* fraction, bits 16:31 */
+ unsigned int : 32; /* fraction, bits 32:63 */
+};
+
+void double2s (double *dp, mval *v)
+{
+ double d = *dp;
+ char *p, *q;
+ int i, j, k;
+
+ ENSURE_STP_FREE_SPACE(MAX_NUM_SIZE);
+ assert (stringpool.free >= stringpool.base);
+ v->mvtype = MV_STR;
+ p = v->str.addr
+ = (char *)stringpool.free;
+
+ if (d == 0.0)
+ *p++ = '0';
+ else
+ {
+ if (d < 0.0)
+ {
+ *p++ = '-'; /* plug in a minus sign */
+ d = -d; /* but make d positive */
+ }
+
+ i = pot_index[((struct D_float *)dp)->exp];
+ if (i < 0)
+ {
+ i = -i;
+ if (d < pot[i])
+ ++i;
+ }
+ i = POT_UNITY + 1 - i;
+
+ /* "Normalize" the number; i.e. adjust it to be between 0.0 and 1.0 */
+ d *= pot[i + POT_UNITY];
+
+ if (d < 5e-16)
+ /* Call it zero */
+ *p++ = '0';
+ else
+ {
+ /* Round the sixteenth digit */
+ d += 5e-16;
+
+ if (d >= 1.0)
+ {
+ /* Readjust it to be between 0.0 and 1.0 */
+ d /= 10.0;
+ ++i;
+ }
+
+ q = p; /* q will point to the last non-zero byte */
+ j = i;
+
+ if (i <= 0)
+ {
+ *p++ = '.';
+ for (; i < 0; ++i)
+ *p++ = '0';
+ }
+
+ for (i = 15; i > 0; --i)
+ {
+ /* Multiply the value by ten, put the integer portion
+ of the result into k (0 <= k <= 9), and replace the
+ value with the fractional portion of the result */
+ k = d *= 10.0;
+ d -= k;
+
+ *p++ = '0' + k;
+
+ if (k > 0)
+ q = p;
+ if (--j == 0)
+ {
+ q = p;
+ *p++ = '.';
+ }
+ }
+
+ if (j > 0)
+ do
+ *p++ = '0';
+ while (--j > 0);
+ else
+ p = q;
+ }
+ }
+
+ v->str.len = p - (char *)stringpool.free;
+ stringpool.free = (unsigned char *)p;
+ assert(stringpool.free <= stringpool.top);
+
+ return;
+}
diff --git a/sr_alpha/emit_code_sp.c b/sr_alpha/emit_code_sp.c
new file mode 100644
index 0000000..6aaf4b7
--- /dev/null
+++ b/sr_alpha/emit_code_sp.c
@@ -0,0 +1,278 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include "cgp.h"
+#include "compiler.h"
+#include <rtnhdr.h>
+#include "list_file.h"
+#include <emit_code.h>
+
+GBLREF uint4 code_buf[]; /* Instruction buffer */
+GBLREF int code_idx; /* Index into code_buf */
+GBLREF char cg_phase; /* Current compiler phase */
+GBLREF int4 curr_addr;
+#ifdef DEBUG
+GBLREF unsigned char *obpt; /* output buffer index */
+GBLREF unsigned char outbuf[]; /* assembly language output buffer */
+static unsigned int ains; /* assembler instruction (binary) */
+#endif
+
+
+/* Used by emit_base_offset to extract offset parts */
+int alpha_adjusted_upper(int offset)
+{
+ int upper;
+
+ upper = (offset >> 16) & 0xFFFF;
+ if (offset & 0x8000)
+ upper = (upper + 1) & 0xFFFF;
+
+ return upper;
+}
+
+
+void emit_base_offset(int base, int offset)
+{
+ /* NOTE: emit_base_offset does not advance past its last
+ generated instruction because that instruction is
+ incomplete; it contains only a base and offset -- the
+ rt and opcode field are left empty for use by the caller. */
+ int upper, low, source;
+
+ switch (cg_phase)
+ {
+#ifdef DEBUG
+ case CGP_ASSEMBLY:
+#endif
+ case CGP_ADDR_OPT:
+ case CGP_APPROX_ADDR:
+ case CGP_MACHINE:
+ assert(base >= 0 && base <= 31);
+ source = base;
+ upper = alpha_adjusted_upper(offset);
+
+ if (0 != upper)
+ {
+ code_buf[code_idx++] = ALPHA_INS_LDAH
+ | (GTM_REG_CODEGEN_TEMP << ALPHA_SHIFT_RA)
+ | (source << ALPHA_SHIFT_RB)
+ | (upper & ALPHA_MASK_DISP) << ALPHA_SHIFT_DISP;
+ source = GTM_REG_CODEGEN_TEMP;
+ }
+ low = offset & 0xFFFF;
+ code_buf[code_idx] = source << ALPHA_SHIFT_RB
+ | (low & ALPHA_MASK_DISP) << ALPHA_SHIFT_DISP;
+ break;
+ default:
+ GTMASSERT;
+ }
+}
+
+
+#ifdef DEBUG
+void fmt_ra()
+{
+ *obpt++ = 'r';
+ obpt = i2asc(obpt, GET_RA(ains));
+}
+void fmt_ra_rb()
+{
+ fmt_ra();
+ *obpt++ = ',';
+ *obpt++;
+ *obpt++ = 'r';
+ obpt = i2asc(obpt, GET_RB(ains));
+}
+void fmt_ra_rb_rc()
+{
+ fmt_ra_rb();
+ *obpt++ = ',';
+ *obpt++;
+ *obpt++ = 'r';
+ obpt = i2asc(obpt, GET_RC(ains));
+}
+void fmt_ra_mem()
+{
+ fmt_ra();
+ *obpt++ = ',';
+ obpt++;
+ *obpt++ = '0';
+ *obpt++ = 'x';
+ obpt += i2hex_nofill(GET_MEMDISP(ains), obpt, 6);
+ *obpt++ = '(';
+ *obpt++ = 'r';
+ obpt = i2asc(obpt, GET_RB(ains));
+ *obpt++ = ')';
+}
+void fmt_ra_brdisp()
+{
+ fmt_ra();
+ *obpt++ = ',';
+ obpt++;
+ *obpt++ = '0';
+ *obpt++ = 'x';
+ obpt += i2hex_nofill(GET_BRDISP(ains) * 4, obpt, 6);
+}
+void format_machine_inst(void)
+{
+ int instindx;
+
+ for (instindx = 0; instindx < code_idx; instindx++)
+ {
+ list_chkpage();
+ obpt = &outbuf[0];
+ memset(obpt, SP, ASM_OUT_BUFF);
+ obpt += 10;
+ i2hex((curr_addr - SIZEOF(rhdtyp)), (uchar_ptr_t)obpt, 8);
+ curr_addr += 4;
+ obpt += 10;
+ i2hex(code_buf[instindx], (uchar_ptr_t)obpt, 8);
+ obpt += 10;
+ ains = code_buf[instindx];
+ switch(GET_OPCODE(ains))
+ {
+ case 0x8:
+ memcpy(obpt, LDA_INST, SIZEOF(LDA_INST) - 1);
+ obpt += OPSPC;
+ fmt_ra_mem();
+ break;
+ case 0x9:
+ memcpy(obpt, LDAH_INST, SIZEOF(LDAH_INST) - 1);
+ obpt += OPSPC;
+ fmt_ra_mem();
+ break;
+ case 0x10:
+ /* Note opcodes 0x10, 0x11, have overlapping functions but none that we generate
+ so we can combine their disassembly.
+ */
+ case 0x11:
+ switch(GET_FUNC(ains))
+ {
+ case 0x0: /* main opcode 0x10 */
+ memcpy(obpt, ADDL_INST, SIZEOF(ADDL_INST) - 1);
+ break;
+ case 0x9: /* main opcode 0x10 */
+ memcpy(obpt, SUBL_INST, SIZEOF(SUBL_INST) - 1);
+ break;
+ case 0x29: /* main opcode 0x10 */
+ memcpy(obpt, SUBQ_INST, SIZEOF(SUBQ_INST) - 1);
+ break;
+ case 0x20: /* main opcode 0x11 */
+ memcpy(obpt, BIS_INST, SIZEOF(BIS_INST) - 1);
+ break;
+ default:
+ GTMASSERT;
+ }
+ obpt += OPSPC;
+ fmt_ra_rb_rc();
+ break;
+ case 0x1a:
+ switch(GET_MEMDISP(ains) & 0x3)
+ {
+ case 0x0:
+ memcpy(obpt, JMP_INST, SIZEOF(JMP_INST) - 1);
+ break;
+ case 0x1:
+ memcpy(obpt, JSR_INST, SIZEOF(JSR_INST) - 1);
+ break;
+ case 0x2:
+ memcpy(obpt, RET_INST, SIZEOF(RET_INST) - 1);
+ break;
+ default:
+ GTMASSERT;
+ }
+ obpt += OPSPC;
+ fmt_ra_rb();
+ break;
+ case 0x28:
+ memcpy(obpt, LDL_INST, SIZEOF(LDL_INST) - 1);
+ obpt += OPSPC;
+ fmt_ra_mem();
+ break;
+ case 0x29:
+ memcpy(obpt, LDQ_INST, SIZEOF(LDQ_INST) - 1);
+ obpt += OPSPC;
+ fmt_ra_mem();
+ break;
+ case 0x2c:
+ memcpy(obpt, STL_INST, SIZEOF(STL_INST) - 1);
+ obpt += OPSPC;
+ fmt_ra_mem();
+ break;
+ case 0x2d:
+ memcpy(obpt, STQ_INST, SIZEOF(STQ_INST) - 1);
+ obpt += OPSPC;
+ fmt_ra_mem();
+ break;
+ case 0x30:
+ memcpy(obpt, BR_INST, SIZEOF(BR_INST) - 1);
+ obpt += OPSPC;
+ fmt_ra_brdisp();
+ break;
+ case 0x34:
+ memcpy(obpt, BSR_INST, SIZEOF(BSR_INST) - 1);
+ obpt += OPSPC;
+ fmt_ra_brdisp();
+ break;
+ case 0x38:
+ memcpy(obpt, BLBC_INST, SIZEOF(BLBC_INST) - 1);
+ obpt += OPSPC;
+ fmt_ra_brdisp();
+ break;
+ case 0x39:
+ memcpy(obpt, BEQ_INST, SIZEOF(BEQ_INST) - 1);
+ obpt += OPSPC;
+ fmt_ra_brdisp();
+ break;
+ case 0x3a:
+ memcpy(obpt, BLT_INST, SIZEOF(BLT_INST) - 1);
+ obpt += OPSPC;
+ fmt_ra_brdisp();
+ break;
+ case 0x3b:
+ memcpy(obpt, BLE_INST, SIZEOF(BLE_INST) - 1);
+ obpt += OPSPC;
+ fmt_ra_brdisp();
+ break;
+ case 0x3c:
+ memcpy(obpt, BLBS_INST, SIZEOF(BLBS_INST) - 1);
+ obpt += OPSPC;
+ fmt_ra_brdisp();
+ break;
+ case 0x3d:
+ memcpy(obpt, BNE_INST, SIZEOF(BNE_INST) - 1);
+ obpt += OPSPC;
+ fmt_ra_brdisp();
+ break;
+ case 0x3e:
+ memcpy(obpt, BGE_INST, SIZEOF(BGE_INST) - 1);
+ obpt += OPSPC;
+ fmt_ra_brdisp();
+ break;
+ case 0x3f:
+ memcpy(obpt, BGT_INST, SIZEOF(BGT_INST) - 1);
+ obpt += OPSPC;
+ fmt_ra_brdisp();
+ break;
+ default: /* Not an instruction but a constant */
+ memcpy(obpt, CONSTANT, SIZEOF(CONSTANT) - 1);
+ obpt += SIZEOF(CONSTANT) - 1;
+ i2hex(ains, obpt, 8);
+ obpt += 8;
+ }
+ emit_eoi();
+ }
+}
+#endif
diff --git a/sr_alpha/emit_code_sp.h b/sr_alpha/emit_code_sp.h
new file mode 100644
index 0000000..c7da71b
--- /dev/null
+++ b/sr_alpha/emit_code_sp.h
@@ -0,0 +1,206 @@
+/****************************************************************
+ * *
+ * Copyright 2003, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef EMIT_CODE_SP_INCLUDED
+#define EMIT_CODE_SP_INCLUDED
+
+#include "axp_registers.h"
+#include "axp_gtm_registers.h"
+#include "axp.h"
+
+void emit_base_offset(int base, int offset);
+int alpha_adjusted_upper(int offset);
+
+#ifdef DEBUG
+void format_machine_inst(void);
+void fmt_ra(void);
+void fmt_ra_rb(void);
+void fmt_ra_rb_rc(void);
+void fmt_ra_mem(void);
+void fmt_ra_brdisp(void);
+#endif
+
+#define INST_SIZE (int)SIZEOF(uint4)
+#define BRANCH_OFFSET_FROM_IDX(idx_start, idx_end) (idx_end - (idx_start + 1))
+#define LONG_JUMP_OFFSET (0x4ffffffc) /* should be large enough to force the long jump instruction sequence */
+#define MAX_BRANCH_CODEGEN_SIZE 32 /* The length in bytes, of the longest form of branch instruction sequence */
+
+#define MAX_OFFSET 0x3fff
+#define STACK_ARG_OFFSET(indx) (8 * (indx)) /* All arguments on Alpha platforms are 8 bytes wide on stack */
+#define MACHINE_FIRST_ARG_REG ALPHA_REG_A0
+
+/* Register usage in some of the code generation expansions */
+#define CALLS_TINT_TEMP_REG ALPHA_REG_R1
+#define CLRL_REG ALPHA_REG_ZERO
+#define CMPL_TEMP_REG ALPHA_REG_T1
+#define GET_ARG_REG(indx) (ALPHA_REG_A0 + (indx))
+#define MOVC3_SRC_REG ALPHA_REG_R0
+#define MOVC3_TRG_REG ALPHA_REG_R1
+#define MOVL_RETVAL_REG ALPHA_REG_V0
+#define MOVL_REG_R1 ALPHA_REG_R1
+
+/* Macros to define the opcodes for use in emit_jmp() and emit_tip() args */
+
+#define GENERIC_OPCODE_BEQ ((uint4)ALPHA_INS_BEQ)
+#define GENERIC_OPCODE_BGE ((uint4)ALPHA_INS_BGE)
+#define GENERIC_OPCODE_BGT ((uint4)ALPHA_INS_BGT)
+#define GENERIC_OPCODE_BLE ((uint4)ALPHA_INS_BLE)
+#define GENERIC_OPCODE_BLT ((uint4)ALPHA_INS_BLT)
+#define GENERIC_OPCODE_BNE ((uint4)ALPHA_INS_BNE)
+#define GENERIC_OPCODE_BLBC ((uint4)ALPHA_INS_BLBC)
+#define GENERIC_OPCODE_BLBS ((uint4)ALPHA_INS_BLBS)
+#define GENERIC_OPCODE_BR ((uint4)ALPHA_INS_BR)
+#define GENERIC_OPCODE_LDA ((uint4)ALPHA_INS_LDA)
+#define GENERIC_OPCODE_LOAD ((uint4)ALPHA_INS_LDL)
+#define GENERIC_OPCODE_STORE ((uint4)ALPHA_INS_STL)
+#define GENERIC_OPCODE_NOP ((uint4)ALPHA_INS_NOP)
+
+/* Macro to extract parts of generic opcodes */
+#define GENXCT_LOAD_SRCREG(inst) ((inst >> ALPHA_SHIFT_RB) & ALPHA_MASK_REG)
+
+/* Macros to create specific generated code sequences */
+
+/* Note that the GEN_CLEAR/SET_TRUTH macros are only used on VMS (TRUTH_IN_REG) */
+#define GEN_CLEAR_TRUTH code_buf[code_idx++] = (ALPHA_INS_STL | ALPHA_REG_ZERO << ALPHA_SHIFT_RA \
+ | GTM_REG_DOLLAR_TRUTH << ALPHA_SHIFT_RB \
+ | 0 << ALPHA_SHIFT_DISP)
+#define GEN_SET_TRUTH { \
+ code_buf[code_idx++] = (ALPHA_INS_BIS | ALPHA_REG_ZERO << ALPHA_SHIFT_RA \
+ | 1 << ALPHA_SHIFT_LITERAL | ALPHA_BIT_LITERAL \
+ | GTM_REG_CODEGEN_TEMP << ALPHA_SHIFT_RC); \
+ code_buf[code_idx++] = (ALPHA_INS_STL | GTM_REG_CODEGEN_TEMP << ALPHA_SHIFT_RA \
+ | GTM_REG_DOLLAR_TRUTH << ALPHA_SHIFT_RB \
+ | 0 << ALPHA_SHIFT_DISP); \
+ }
+#define GEN_LOAD_ADDR(reg, breg, disp) code_buf[code_idx++] = (ALPHA_INS_LDA | reg << ALPHA_SHIFT_RA \
+ | breg << ALPHA_SHIFT_RB \
+ | (disp & ALPHA_MASK_DISP) << ALPHA_SHIFT_DISP)
+#define GEN_LOAD_WORD(reg, breg, disp) code_buf[code_idx++] = (ALPHA_INS_LDL | reg << ALPHA_SHIFT_RA \
+ | breg << ALPHA_SHIFT_RB \
+ | (disp & ALPHA_MASK_DISP) << ALPHA_SHIFT_DISP)
+#define GEN_STORE_WORD(reg, breg, disp) code_buf[code_idx++] = (ALPHA_INS_STL | reg << ALPHA_SHIFT_RA \
+ | breg << ALPHA_SHIFT_RB \
+ | (disp & ALPHA_MASK_DISP) << ALPHA_SHIFT_DISP)
+#define GEN_LOAD_IMMED(reg, disp) GEN_LOAD_ADDR(reg, ALPHA_REG_ZERO, disp)
+#define GEN_CLEAR_WORD_EMIT(reg) emit_trip(*(fst_opr + *inst++), TRUE, ALPHA_INS_STL, reg)
+#define GEN_LOAD_WORD_EMIT(reg) emit_trip(*(fst_opr + *inst++), TRUE, ALPHA_INS_LDL, reg)
+#define GEN_SUBTRACT_REGS(src1, src2, trgt) \
+ code_buf[code_idx++] = (ALPHA_INS_SUBL \
+ | src1 << ALPHA_SHIFT_RA \
+ | src2 << ALPHA_SHIFT_RB \
+ | trgt << ALPHA_SHIFT_RC)
+#define GEN_ADD_IMMED(reg, imval) code_buf[code_idx++] = (ALPHA_INS_ADDL \
+ | reg << ALPHA_SHIFT_RA \
+ | imval << ALPHA_SHIFT_LITERAL | ALPHA_BIT_LITERAL \
+ | reg << ALPHA_SHIFT_RC)
+#define GEN_JUMP_REG(reg) code_buf[code_idx++] = (ALPHA_INS_JMP | ALPHA_REG_ZERO << ALPHA_SHIFT_RA \
+ | reg << ALPHA_SHIFT_RB)
+#define GEN_STORE_ARG(reg, offset) code_buf[code_idx++] = (ALPHA_INS_STQ | reg << ALPHA_SHIFT_RA \
+ | ALPHA_REG_SP << ALPHA_SHIFT_RB \
+ | (offset & ALPHA_MASK_DISP) << ALPHA_SHIFT_DISP)
+#define GEN_PCREL code_buf[code_idx++] = (ALPHA_INS_LPC)
+#define GEN_MOVE_REG(trg, src) code_buf[code_idx++] = (ALPHA_INS_MOVE | src << ALPHA_SHIFT_RA | trg << ALPHA_SHIFT_RC)
+
+#if defined(__vms)
+/* CALL_INST_SIZE is the byte length of the minimum-length instruction sequence to implement a transfer
+ * table call. In the case of OpenVMS AXP, this is the sequence:
+ *
+ * ldl r27, xfer(r11) ; get address of procedure descriptor from transfer table
+ * ldq r26, 8(r27) ; get code address of procedure from procedure descriptor
+ * jmp r26, (r26) ; call it
+ *
+ * This value is used to determine how to adjust the offset value for a relative call and may not
+ * be appropriate for the Alpha because VAX relative calls are emulated on the Alpha differently.
+*/
+# define CALL_INST_SIZE (3 * INST_SIZE)
+# define GEN_XFER_TBL_CALL(xfer) \
+ { \
+ emit_base_offset(GTM_REG_XFER_TABLE, xfer); \
+ code_buf[code_idx++] |= ALPHA_INS_LDL | ALPHA_REG_PV << ALPHA_SHIFT_RA; \
+ emit_base_offset(ALPHA_REG_PV, 8); \
+ code_buf[code_idx++] |= ALPHA_INS_LDQ | ALPHA_REG_RA << ALPHA_SHIFT_RA; \
+ code_buf[code_idx++] = ALPHA_INS_JSR | ALPHA_REG_RA << ALPHA_SHIFT_RA | ALPHA_REG_RA << ALPHA_SHIFT_RB; \
+ }
+#elif defined(__osf__)
+/* CALL_INST_SIZE is the byte length of the minimum-length instruction sequence to implement a transfer
+ * table call. In the case of OSF/1 (Digital Unix) AXP, this is the sequence:
+ *
+ * ldl r27, offset(r12) # get address of entry point from transfer table
+ * jmp r26, (r27) # call it
+ *
+ * This value is used to determine how to adjust the offset value for a relative call and may not
+ * be appropriate for the Alpha because VAX relative calls are emulated on the Alpha differently.
+*/
+# define CALL_INST_SIZE (2 * INST_SIZE)
+# define GEN_XFER_TBL_CALL(xfer) \
+ { \
+ emit_base_offset(GTM_REG_XFER_TABLE, xfer); \
+ code_buf[code_idx++] |= ALPHA_INS_LDL | ALPHA_REG_PV << ALPHA_SHIFT_RA; \
+ code_buf[code_idx++] = ALPHA_INS_JSR | ALPHA_REG_RA << ALPHA_SHIFT_RA | ALPHA_REG_PV << ALPHA_SHIFT_RB; \
+ }
+#else
+# error "Unsupported platform"
+#endif
+
+
+/* Macros to return an instruction value. This is typcically used to modify an instruction
+ that is already in the instruction buffer such as the last instruction that was created
+ by emit_pcrel().
+*/
+#define IGEN_COND_BRANCH_REG_OFFSET(opcode, reg, disp) (opcode | ((reg & ALPHA_MASK_REG) << ALPHA_SHIFT_RA) \
+ | ((disp & ALPHA_MASK_DISP) << ALPHA_SHIFT_BRANCH_DISP))
+#define IGEN_UCOND_BRANCH_REG_OFFSET(opcode, reg, disp) IGEN_COND_BRANCH_REG_OFFSET(opcode, reg, disp)
+#define IGEN_LOAD_ADDR_REG(reg) (ALPHA_INS_LDA | (reg & ALPHA_MASK_REG) << ALPHA_SHIFT_RA)
+#define IGEN_LOAD_WORD_REG(reg) (ALPHA_INS_LDL | (reg & ALPHA_MASK_REG) << ALPHA_SHIFT_RA)
+#define IGEN_LOAD_NATIVE_REG(reg) IGEN_LOAD_WORD_REG(reg)
+#define IGEN_COND_BRANCH_OFFSET(disp) ((disp & ALPHA_MASK_BRANCH_DISP) << ALPHA_SHIFT_BRANCH_DISP)
+#define IGEN_UCOND_BRANCH_OFFSET(disp) IGEN_COND_BRANCH_OFFSET(disp)
+#define IGEN_LOAD_LINKAGE(reg) (ALPHA_INS_LDQ | (reg & ALPHA_MASK_REG) << ALPHA_SHIFT_RA)
+#define IGEN_GENERIC_REG(opcode, reg) (opcode | ((reg & ALPHA_MASK_REG) << ALPHA_SHIFT_RA))
+
+/* Some macros that are used in certain routines in emit_code.c. The names of these
+ macros start with the routine name they are used in.
+*/
+
+/* Branch has origin of +1 instructions. However, if the branch was nullified in an earlier shrink_trips,
+ * the origin is the current instruction itself */
+#define EMIT_JMP_ADJUST_BRANCH_OFFSET branch_offset = ((branch_offset != 0) ? branch_offset - 1 : 0)
+/* Can jump be done within range of immediate operand */
+#define EMIT_JMP_SHORT_CODE_CHECK (branch_offset >= (-(ALPHA_MASK_BRANCH_DISP/2) - 1) \
+ && branch_offset <= (ALPHA_MASK_BRANCH_DISP/2))
+/* Emit the short jump */
+#define EMIT_JMP_SHORT_CODE_GEN \
+{ \
+ code_buf[code_idx++] = (branchop | (reg << ALPHA_SHIFT_RA) \
+ | ((branch_offset & ALPHA_MASK_BRANCH_DISP) << ALPHA_SHIFT_BRANCH_DISP)); \
+ branch_offset--; \
+}
+/* Is this a conditional branch? */
+#define EMIT_JMP_OPPOSITE_BR_CHECK (branchop != ALPHA_INS_BR && (branchop != ALPHA_INS_BEQ || reg != ALPHA_REG_ZERO))
+#define EMIT_JMP_GEN_COMPARE /* No compare necessary */
+#define EMIT_JMP_LONG_CODE_CHECK FALSE
+/* Is the offset field in this instruction zero? */
+#define EMIT_JMP_ZERO_DISP_COND (0 == ((code_buf[code_idx] >> ALPHA_SHIFT_DISP) & ALPHA_MASK_DISP))
+/* Emit code to load a given numeric literal */
+#define EMIT_TRIP_ILIT_GEN { /* Emit liternal number */ \
+ emit_base_offset(ALPHA_REG_ZERO, immediate); \
+ code_buf[code_idx++] |= (ALPHA_INS_LDA | \
+ (trg_reg & ALPHA_MASK_REG) << ALPHA_SHIFT_RA); \
+ }
+/*
+ * GT.M on AIX and SPARC is 64bit
+ * By default the loads/stores use ldd/std(load double),
+ * but if the value being dealt with is a word,the
+ * opcode in generic_inst is changed to ldw/stw
+ */
+#define REVERT_GENERICINST_TO_WORD(inst)
+
+#endif
diff --git a/sr_alpha/follow.m64 b/sr_alpha/follow.m64
new file mode 100644
index 0000000..7267a82
--- /dev/null
+++ b/sr_alpha/follow.m64
@@ -0,0 +1,32 @@
+; ################################################################
+; # #
+; # Copyright 2001, 2008 Fidelity Information Services, Inc #
+; # #
+; # This source code contains the intellectual property #
+; # of its copyright holder(s), and is made available #
+; # under a license. If you do not know the terms of #
+; # the license, please stop and do not read further. #
+; # #
+; ################################################################
+
+ .title FOLLOW "Allows run-time modules to call OP_FOLLOW"
+
+; FOLLOW simply passes its two arguments, which are pointers to
+; mval's, to OP_FOLLOW, which expects them in registers r0 and r1.
+; OP_FOLLOW returns 1, 0, or -1; FOLLOW returns a boolean result:
+; 1 (true) if OP_FOLLOW returned 1, otherwise 0 (false).
+
+ $routine FOLLOW, entry=FOLLOW_CA, kind=stack
+ .base r27, $ls
+
+ sextl r16, r0
+ sextl r17, r1
+ $call OP_FOLLOW, set_arg_info=false
+ sextl r0, r0
+ cmovlt r0, 0, r0
+
+ $return
+
+ $end_routine
+
+ .end
diff --git a/sr_alpha/gtm_dump.c b/sr_alpha/gtm_dump.c
new file mode 100644
index 0000000..422d9b7
--- /dev/null
+++ b/sr_alpha/gtm_dump.c
@@ -0,0 +1,17 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/*** STUB FILE ***/
+
+#include "mdef.h"
+#include "error.h"
+
+void gtm_dump(void) {};
diff --git a/sr_alpha/inst_flush.m64 b/sr_alpha/inst_flush.m64
new file mode 100644
index 0000000..8f63803
--- /dev/null
+++ b/sr_alpha/inst_flush.m64
@@ -0,0 +1,24 @@
+; ################################################################
+; # #
+; # Copyright 2001, 2008 Fidelity Information Services, Inc #
+; # #
+; # This source code contains the intellectual property #
+; # of its copyright holder(s), and is made available #
+; # under a license. If you do not know the terms of #
+; # the license, please stop and do not read further. #
+; # #
+; ################################################################
+
+ .title inst_flush flush instruction cache
+
+; inst_flush is a C-callable routine that makes the instruction cache coherent with memory.
+
+ $routine name=inst_flush,entry=inst_flush_ca,kind=null
+
+ imb
+
+ ret r26
+
+ $end_routine name=inst_flush
+
+ .end
diff --git a/sr_alpha/mint2mval.m64 b/sr_alpha/mint2mval.m64
new file mode 100644
index 0000000..262527d
--- /dev/null
+++ b/sr_alpha/mint2mval.m64
@@ -0,0 +1,51 @@
+ .title mint2mval "Convert integer to mval"
+
+; ###############################################################
+; # #
+; # Copyright 2001, 2004 Sanchez Computer Associates, Inc. #
+; # #
+; # This source code contains the intellectual property #
+; # of its copyright holder(s), and is made available #
+; # under a license. If you do not know the terms of #
+; # the license, please stop and do not read further. #
+; # #
+; ###############################################################
+
+; On input, r1 = integer value, r0 -> mval
+
+ mval$def
+
+ $linkage_section
+
+int_hi_val:
+ .quad INT_HI
+
+ $routine MINT2MVAL, entry=MINT2MVAL_CA, kind=null
+ lda sp, -24(sp)
+ stq r26, (sp)
+ stq r13, 8(sp)
+ mov r27, r13
+ .base r13, $ls
+
+ ldq r22, int_hi_val
+ cmplt r1, r22, r28
+ beq r28, 11$ ; int >= INT_HI
+ negq r22, r22
+ cmple r1, r22, r28
+ bne r28, 11$ ; int <= -INT_HI
+
+ mv_i2mval r1, r0
+
+12$: ldq r26, (sp)
+ ldq r13, 8(sp)
+ lda sp, 24(sp)
+ ret r26
+
+11$: mov r0, r16
+ mov r1, r17
+ $call I2MVAL, args=<r16, r17>, set_arg_info=false, nonstandard=true
+ br 12$
+
+ $end_routine
+
+ .end
diff --git a/sr_alpha/movq.m64 b/sr_alpha/movq.m64
new file mode 100644
index 0000000..ef9d980
--- /dev/null
+++ b/sr_alpha/movq.m64
@@ -0,0 +1,21 @@
+; ################################################################
+; # #
+; # Copyright 2001, 2008 Fidelity Information Services, Inc #
+; # #
+; # This source code contains the intellectual property #
+; # of its copyright holder(s), and is made available #
+; # under a license. If you do not know the terms of #
+; # the license, please stop and do not read further. #
+; # #
+; ################################################################
+
+ .title movq move quadword
+
+ $routine name=movq,entry=movq_ca,kind=null
+
+ ldq r28, (r16)
+ stq r28, (r17)
+
+ ret r26
+
+ $end_routine name=movq
diff --git a/sr_alpha/mval2bool.m64 b/sr_alpha/mval2bool.m64
new file mode 100644
index 0000000..d294d1f
--- /dev/null
+++ b/sr_alpha/mval2bool.m64
@@ -0,0 +1,39 @@
+; ################################################################
+; # #
+; # Copyright 2000, 2008 Fidelity Information Services, Inc #
+; # #
+; # This source code contains the intellectual property #
+; # of its copyright holder(s), and is made available #
+; # under a license. If you do not know the terms of #
+; # the license, please stop and do not read further. #
+; # #
+; ################################################################
+
+ .title mval2bool "Sets condition code from mval"
+
+; On entry, r1 -> mval.
+; On exit, r24 = numeric value of mval
+
+ mval$def
+
+ $routine MVAL2BOOL, entry=MVAL2BOOL_CA, kind=null
+ lda sp, -24(sp)
+ stq r26, (sp)
+ stq r13, 8(sp)
+ mov r27, r13
+ .base r13, $ls
+
+ mv_force_defined r1
+ stq r1, 16(sp)
+ mv_force_num (r1)
+ ldq r1, 16(sp)
+ ldl r24, mval$l_m1(r1)
+
+ ldq r26, (sp)
+ ldq r13, 8(sp)
+ lda sp, 24(sp)
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_alpha/mval2mint.m64 b/sr_alpha/mval2mint.m64
new file mode 100644
index 0000000..a27508c
--- /dev/null
+++ b/sr_alpha/mval2mint.m64
@@ -0,0 +1,39 @@
+; ################################################################
+; # #
+; # Copyright 2000, 2008 Fidelity Information Services, Inc #
+; # #
+; # This source code contains the intellectual property #
+; # of its copyright holder(s), and is made available #
+; # under a license. If you do not know the terms of #
+; # the license, please stop and do not read further. #
+; # #
+; ################################################################
+
+ .title mval2mint "Converts an mval to integer"
+
+; On entry, r1 -> mval
+; On exit, r0 = integer value
+
+ mval$def
+
+ $routine MVAL2MINT, entry=MVAL2MINT_CA, kind=null
+ lda sp, -24(sp)
+ stq r26, (sp)
+ stq r13, 8(sp)
+ mov r27, r13
+ .base r13, $ls
+
+ mv_force_defined r1
+ stq r1, 16(sp)
+ mv_force_num (r1)
+ ldq r16, 16(sp)
+ $call MVAL2I, args=<r16>, set_arg_info=false, nonstandard=true
+
+ ldq r26, (sp)
+ ldq r13, 8(sp)
+ lda sp, 24(sp)
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_alpha/objlangdefs.h b/sr_alpha/objlangdefs.h
new file mode 100644
index 0000000..1d5d6c0
--- /dev/null
+++ b/sr_alpha/objlangdefs.h
@@ -0,0 +1,457 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* Object record types: */
+#define EOBJ$C_EMH 8
+#define EOBJ$C_EEOM 9
+#define EOBJ$C_EGSD 10
+#define EOBJ$C_ETIR 11
+#define EOBJ$C_EDBG 12
+#define EOBJ$C_ETBT 13
+#define EOBJ$C_MAXRECTYP 13
+
+/* Byte offsets into object record and related constants: */
+#define EOBJ$K_SUBTYP 4
+#define EOBJ$C_SUBTYP 4
+#define EOBJ$C_MAXRECSIZ 8192
+#define EOBJ$C_STRLVL 2
+#define EOBJ$C_SYMSIZ 31
+#define EOBJ$C_STOREPLIM -1
+#define EOBJ$C_PSCALILIM 16
+#define EOBJ$S_EOBJRECDEF 10
+#define EOBJ$W_RECTYP 0
+#define EOBJ$W_SIZE 2
+#define EOBJ$W_SUBTYP 4
+#define EOBJ$B_MHD_STRLV 6
+#define EOBJ$B_MHD_HOLD 7
+#define EOBJ$W_MHD_RECSZ 8
+#define EOBJ$T_MHD_NAME 10
+
+/* Object header record (EOBJ$C_EMH) subtypes: */
+#define EMH$C_MHD 0
+#define EMH$C_LNM 1
+#define EMH$C_SRC 2
+#define EMH$C_TTL 3
+#define EMH$C_CPR 4
+#define EMH$C_MTC 5
+#define EMH$C_GTX 6
+#define EMH$C_MAXHDRTYP 6
+
+/* Byte offsets of fields in object header record (EOBJ$C_EMH): */
+#define EMH$S_EMHDEF 52
+#define EMH$W_RECTYP 0
+#define EMH$W_SIZE 2
+#define EMH$W_HDRTYP 4
+#define EMH$B_STRLVL 6
+#define EMH$B_TEMP 7
+#define EMH$L_ARCH1 8
+#define EMH$L_ARCH2 12
+#define EMH$L_RECSIZ 16
+#define EMH$B_NAMLNG 20
+#define EMH$S_NAME 31
+#define EMH$T_NAME 21
+
+#define EEOM$C_SUCCESS 0
+#define EEOM$C_WARNING 1
+#define EEOM$C_ERROR 2
+#define EEOM$C_ABORT 3
+#define EEOM$K_EOMMIN 10
+#define EEOM$C_EOMMIN 10
+#define EEOM$K_EOMMX1 10
+#define EEOM$C_EOMMX1 10
+#define EEOM$M_WKTFR 0X1
+#define EEOM$K_EOMMAX 24
+#define EEOM$C_EOMMAX 24
+#define EEOM$S_EEOMDEF 24
+#define EEOM$W_RECTYP 0
+#define EEOM$W_SIZE 2
+#define EEOM$L_TOTAL_LPS 4
+#define EEOM$W_COMCOD 8
+#define EEOM$B_TFRFLG 10
+#define EEOM$V_WKTFR 0
+#define EEOM$B_TEMP 11
+#define EEOM$L_PSINDX 12
+#define EEOM$S_TFRADR 8
+#define EEOM$Q_TFRADR 16
+#define EEOM$L_TFRADR 16
+
+
+#define EGSD$K_ENTRIES 2
+#define EGSD$C_ENTRIES 2
+
+#define EGSD$C_PSC 0
+#define EGSD$C_SYM 1
+#define EGSD$C_IDC 2
+#define EGSD$C_ENV 3
+#define EGSD$C_LSY 4
+#define EGSD$C_SPSC 5
+#define EGSD$C_SYMV 6
+#define EGSD$C_SYMM 7
+#define EGSD$C_SYMG 8
+#define EGSD$C_MAXRECTYP 8
+
+#define EGSD$S_EGSDEF 12
+#define EGSD$W_RECTYP 0
+#define EGSD$W_RECSIZ 2
+#define EGSD$L_ALIGNLW 4
+#define EGSD$W_GSDTYP 8
+#define EGSD$W_GSDSIZ 10
+
+#define EGPS$M_PIC 0X1
+#define EGPS$M_LIB 0X2
+#define EGPS$M_OVR 0X4
+#define EGPS$M_REL 0X8
+#define EGPS$M_GBL 0X10
+#define EGPS$M_SHR 0X20
+#define EGPS$M_EXE 0X40
+#define EGPS$M_RD 0X80
+#define EGPS$M_WRT 0X100
+#define EGPS$M_VEC 0X200
+#define EGPS$M_NOMOD 0X400
+#define EGPS$M_COM 0X800
+#define EGPS$K_NAME 12
+#define EGPS$C_NAME 12
+#define EGPS$S_EGPSDEF 44
+#define EGPS$W_GSDTYP 0
+#define EGPS$T_START 0
+#define EGPS$W_SIZE 2
+#define EGPS$B_ALIGN 4
+#define EGPS$B_TEMP 5
+#define EGPS$W_FLAGS 6
+#define EGPS$V_PIC 0
+#define EGPS$V_LIB 1
+#define EGPS$V_OVR 2
+#define EGPS$V_REL 3
+#define EGPS$V_GBL 4
+#define EGPS$V_SHR 5
+#define EGPS$V_EXE 6
+#define EGPS$V_RD 7
+#define EGPS$V_WRT 8
+#define EGPS$V_VEC 9
+#define EGPS$V_NOMOD 10
+#define EGPS$V_COM 11
+#define EGPS$L_ALLOC 8
+#define EGPS$B_NAMLNG 12
+#define EGPS$S_NAME 31
+#define EGPS$T_NAME 13
+
+#define ESGPS$M_PIC 0X1
+#define ESGPS$M_LIB 0X2
+#define ESGPS$M_OVR 0X4
+#define ESGPS$M_REL 0X8
+#define ESGPS$M_GBL 0X10
+#define ESGPS$M_SHR 0X20
+#define ESGPS$M_EXE 0X40
+#define ESGPS$M_RD 0X80
+#define ESGPS$M_WRT 0X100
+#define ESGPS$M_VEC 0X200
+#define ESGPS$M_NOMOD 0X400
+#define ESGPS$M_COM 0X800
+#define ESGPS$K_NAME 25
+#define ESGPS$C_NAME 25
+#define ESGPS$S_ESGPSDEF 56
+#define ESGPS$W_GSDTYP 0
+#define ESGPS$T_START 0
+#define ESGPS$W_SIZE 2
+#define ESGPS$B_ALIGN 4
+#define ESGPS$B_TEMP 5
+#define ESGPS$W_FLAGS 6
+#define ESGPS$V_PIC 0
+#define ESGPS$V_LIB 1
+#define ESGPS$V_OVR 2
+#define ESGPS$V_REL 3
+#define ESGPS$V_GBL 4
+#define ESGPS$V_SHR 5
+#define ESGPS$V_EXE 6
+#define ESGPS$V_RD 7
+#define ESGPS$V_WRT 8
+#define ESGPS$V_VEC 9
+#define ESGPS$V_NOMOD 10
+#define ESGPS$V_COM 11
+#define ESGPS$L_ALLOC 8
+#define ESGPS$L_BASE 12
+#define ESGPS$S_VALUE 8
+#define ESGPS$Q_VALUE 16
+#define ESGPS$L_VALUE 16
+#define ESGPS$B_NAMLNG 24
+#define ESGPS$S_NAME 31
+#define ESGPS$T_NAME 25
+
+#define EGSY$M_WEAK 0X1
+#define EGSY$M_DEF 0X2
+#define EGSY$M_UNI 0X4
+#define EGSY$M_REL 0X8
+#define EGSY$M_COMM 0X10
+#define EGSY$M_VECEP 0X20
+#define EGSY$M_NORM 0X40
+#define EGSY$S_EGSYDEF 8
+#define EGSY$W_GSDTYP 0
+#define EGSY$T_START 0
+#define EGSY$W_SIZE 2
+#define EGSY$B_DATYP 4
+#define EGSY$B_TEMP 5
+#define EGSY$W_FLAGS 6
+#define EGSY$V_WEAK 0
+#define EGSY$V_DEF 1
+#define EGSY$V_UNI 2
+#define EGSY$V_REL 3
+#define EGSY$V_COMM 4
+#define EGSY$V_VECEP 5
+#define EGSY$V_NORM 6
+
+#define EGST$K_NAME 37
+#define EGST$C_NAME 37
+#define EGST$S_EGSTDEF 68
+#define EGST$W_GSDTYP 0
+#define EGST$T_START 0
+#define EGST$W_SIZE 2
+#define EGST$B_DATYP 4
+#define EGST$B_TEMP 5
+#define EGST$W_FLAGS 6
+#define EGST$S_VALUE 8
+#define EGST$Q_VALUE 8
+#define EGST$L_VALUE 8
+#define EGST$S_LP_1 8
+#define EGST$Q_LP_1 16
+#define EGST$L_LP_1 16
+#define EGST$S_LP_2 8
+#define EGST$Q_LP_2 24
+#define EGST$L_LP_2 24
+#define EGST$L_PSINDX 32
+#define EGST$B_NAMLNG 36
+#define EGST$S_NAME 31
+#define EGST$T_NAME 37
+
+#define ESDF$K_NAME 33
+#define ESDF$C_NAME 33
+#define ESDF$S_ESDFDEF 64
+#define ESDF$W_GSDTYP 0
+#define ESDF$T_START 0
+#define ESDF$W_SIZE 2
+#define ESDF$B_DATYP 4
+#define ESDF$B_TEMP 5
+#define ESDF$W_FLAGS 6
+#define ESDF$S_VALUE 8
+#define ESDF$Q_VALUE 8
+#define ESDF$L_VALUE 8
+#define ESDF$S_CODE_ADDRESS 8
+#define ESDF$Q_CODE_ADDRESS 16
+#define ESDF$L_CODE_ADDRESS 16
+#define ESDF$L_CA_PSINDX 24
+#define ESDF$L_PSINDX 28
+#define ESDF$B_NAMLNG 32
+#define ESDF$S_NAME 31
+#define ESDF$T_NAME 33
+
+#define ESDFV$K_NAME 25
+#define ESDFV$C_NAME 25
+#define ESDFV$S_ESDFVDEF 56
+#define ESDFV$W_GSDTYP 0
+#define ESDFV$T_START 0
+#define ESDFV$W_SIZE 2
+#define ESDFV$B_DATYP 4
+#define ESDFV$B_TEMP 5
+#define ESDFV$W_FLAGS 6
+#define ESDFV$S_VALUE 8
+#define ESDFV$Q_VALUE 8
+#define ESDFV$L_VALUE 8
+#define ESDFV$L_PSINDX 16
+#define ESDFV$L_VECTOR 20
+#define ESDFV$B_NAMLNG 24
+#define ESDFV$S_NAME 31
+#define ESDFV$T_NAME 25
+#define ESDFM$K_NAME 25
+#define ESDFM$C_NAME 25
+#define ESDFM$S_ESDFMDEF 56
+#define ESDFM$W_GSDTYP 0
+#define ESDFM$T_START 0
+#define ESDFM$W_SIZE 2
+#define ESDFM$B_DATYP 4
+#define ESDFM$B_TEMP 5
+#define ESDFM$W_FLAGS 6
+#define ESDFM$S_VALUE 8
+#define ESDFM$Q_VALUE 8
+#define ESDFM$L_VALUE 8
+#define ESDFM$L_PSINDX 16
+#define ESDFM$L_VERSION_MASK 20
+#define ESDFM$B_NAMLNG 24
+#define ESDFM$S_NAME 31
+#define ESDFM$T_NAME 25
+#define ESRF$K_NAME 9
+#define ESRF$C_NAME 9
+#define ESRF$S_ESRFDEF 40
+#define ESRF$W_GSDTYP 0
+#define ESRF$T_START 0
+#define ESRF$W_SIZE 2
+#define ESRF$B_DATYP 4
+#define ESRF$B_TEMP 5
+#define ESRF$W_FLAGS 6
+#define ESRF$B_NAMLNG 8
+#define ESRF$S_NAME 31
+#define ESRF$T_NAME 9
+#define EIDC$C_LEQ 0
+#define EIDC$C_EQUAL 1
+#define EIDC$S_EIDCDEF 7
+#define EIDC$W_GSDTYP 0
+#define EIDC$W_SIZE 2
+#define EIDC$B_NAMLNG 4
+#define EIDC$T_NAME 5
+#define EIDC$W_FLAGS 5
+#define EIDC$V_BINIDENT 0
+#define EIDC$S_IDMATCH 2
+#define EIDC$V_IDMATCH 1
+#define EIDC$S_ERRSEV 3
+#define EIDC$V_ERRSEV 3
+
+#define EENV$M_DEF 0X1
+#define EENV$M_NESTED 0X2
+#define EENV$S_EENVDEF 40
+#define EENV$W_GSDTYP 0
+#define EENV$W_SIZE 2
+#define EENV$W_FLAGS 4
+#define EENV$V_DEF 0
+#define EENV$V_NESTED 1
+#define EENV$W_ENVINDX 6
+#define EENV$B_NAMLNG 8
+#define EENV$S_NAME 31
+#define EENV$T_NAME 9
+
+#define ELSY$M_WEAK 0X1
+#define ELSY$M_DEF 0X2
+#define ELSY$M_UNI 0X4
+#define ELSY$M_REL 0X8
+#define ELSY$S_ELSYDEF 14
+#define ELSY$W_GSDTYP 0
+#define ELSY$T_START 0
+#define ELSY$W_SIZE 2
+#define ELSY$B_DATYP 4
+#define ELSY$B_TEMP1 5
+#define ELSY$W_FLAGS 6
+#define ELSY$V_WEAK 0
+#define ELSY$V_DEF 1
+#define ELSY$V_UNI 2
+#define ELSY$V_REL 3
+#define ELSY$L_PSINDX 8
+#define ELSY$W_ENVINDX 12
+
+#define ELSRF$K_NAME 17
+#define ELSRF$C_NAME 17
+#define ELSRF$S_ELSRFDEF 48
+#define ELSRF$W_GSDTYP 0
+#define ELSRF$T_START 0
+#define ELSRF$W_SIZE 2
+#define ELSRF$B_DATYP 4
+#define ELSRF$B_TEMP1 5
+#define ELSRF$W_FLAGS 6
+#define ELSRF$L_PSINDX 8
+#define ELSRF$W_ENVINDX 12
+#define ELSRF$W_TEMP2 14
+#define ELSRF$B_NAMLNG 16
+#define ELSRF$S_NAME 31
+#define ELSRF$T_NAME 17
+
+#define ELSDF$K_NAME 25
+#define ELSDF$C_NAME 25
+#define ELSDF$S_ELSDFDEF 56
+#define ELSDF$W_GSDTYP 0
+#define ELSDF$T_START 0
+#define ELSDF$W_SIZE 2
+#define ELSDF$B_DATYP 4
+#define ELSDF$B_TEMP1 5
+#define ELSDF$W_FLAGS 6
+#define ELSDF$S_VALUE 8
+#define ELSDF$Q_VALUE 8
+#define ELSDF$L_VALUE 8
+#define ELSDF$L_PSINDX 16
+#define ELSDF$W_ENVINDX 20
+#define ELSDF$W_TEMP2 22
+#define ELSDF$B_NAMLNG 24
+#define ELSDF$S_NAME 31
+#define ELSDF$T_NAME 25
+
+/* ETIR command types: */
+/* ETIR stack commands: */
+#define ETIR$C_MINSTACOD 0
+#define ETIR$C_STA_GBL 0
+#define ETIR$C_STA_LW 1
+#define ETIR$C_STA_QW 2
+#define ETIR$C_STA_PQ 3
+#define ETIR$C_STA_LI 4
+#define ETIR$C_STA_MOD 5
+#define ETIR$C_STA_CKARG 6
+#define ETIR$C_MAXSTACOD 6
+
+#define ETIR$C_MINSTOCOD 50
+#define ETIR$C_STO_B 50
+#define ETIR$C_STO_W 51
+#define ETIR$C_STO_LW 52
+#define ETIR$C_STO_QW 53
+#define ETIR$C_STO_IMMR 54
+#define ETIR$C_STO_GBL 55
+#define ETIR$C_STO_CA 56
+#define ETIR$C_STO_RB 57
+#define ETIR$C_STO_AB 58
+#define ETIR$C_STO_OFF 59
+#define ETIR$C_STO_IMM 61
+#define ETIR$C_STO_GBL_LW 62
+#define ETIR$C_STO_HINT_GBL 64
+#define ETIR$C_STO_HINT_PS 65
+#define ETIR$C_MAXSTOCOD 65
+
+#define ETIR$C_MINOPRCOD 100
+#define ETIR$C_OPR_NOP 100
+#define ETIR$C_OPR_ADD 101
+#define ETIR$C_OPR_SUB 102
+#define ETIR$C_OPR_MUL 103
+#define ETIR$C_OPR_DIV 104
+#define ETIR$C_OPR_AND 105
+#define ETIR$C_OPR_IOR 106
+#define ETIR$C_OPR_EOR 107
+#define ETIR$C_OPR_NEG 108
+#define ETIR$C_OPR_COM 109
+#define ETIR$C_OPR_INSV 110
+#define ETIR$C_OPR_ASH 111
+#define ETIR$C_OPR_USH 112
+#define ETIR$C_OPR_ROT 113
+#define ETIR$C_OPR_SEL 114
+#define ETIR$C_OPR_REDEF 115
+#define ETIR$C_OPR_DFLIT 116
+#define ETIR$C_MAXOPRCOD 116
+
+#define ETIR$C_MINCTLCOD 150
+#define ETIR$C_CTL_SETRB 150
+#define ETIR$C_CTL_AUGRB 151
+#define ETIR$C_CTL_DFLOC 152
+#define ETIR$C_CTL_STLOC 153
+#define ETIR$C_CTL_STKDL 154
+#define ETIR$C_MAXCTLCOD 154
+
+#define ETIR$C_MINSTCCOD 200
+#define ETIR$C_STC_LP 200
+#define ETIR$C_STC_LP_PSB 201
+#define ETIR$C_STC_GBL 202
+#define ETIR$C_STC_GCA 203
+#define ETIR$C_STC_PS 204
+#define ETIR$C_STC_NOP_GBL 205
+#define ETIR$C_STC_NOP_PS 206
+#define ETIR$C_STC_BSR_GBL 207
+#define ETIR$C_STC_BSR_PS 208
+#define ETIR$C_STC_LDA_GBL 209
+#define ETIR$C_STC_LDA_PS 210
+#define ETIR$C_STC_BOH_GBL 211
+#define ETIR$C_STC_BOH_PS 212
+#define ETIR$C_STC_NBH_GBL 213
+#define ETIR$C_STC_NBH_PS 214
+#define ETIR$C_MAXSTCCOD 214
+
+#define ETIR$S_ETIRDEF 4
+#define ETIR$W_RECTYP 0
+#define ETIR$W_SIZE 2
diff --git a/sr_alpha/op_call.m64 b/sr_alpha/op_call.m64
new file mode 100644
index 0000000..d2e6d27
--- /dev/null
+++ b/sr_alpha/op_call.m64
@@ -0,0 +1,51 @@
+ .title OP_CALL
+; ###############################################################
+; # #
+; # Copyright 2001, 2003 Sanchez Computer Associates, Inc. #
+; # #
+; # This source code contains the intellectual property #
+; # of its copyright holder(s), and is made available #
+; # under a license. If you do not know the terms of #
+; # the license, please stop and do not read further. #
+; # #
+; ###############################################################
+
+ G_MSF
+
+
+ $linkage_section
+
+a_frame_pointer:
+ .address frame_pointer
+
+
+ $code_section
+
+ $routine OP_CALLB, entry=OP_CALL_CA, aliases=<OP_CALLW, OP_CALLL>, kind=null
+
+ lda sp, -16(sp)
+ stq r13, 8(sp)
+ stq r26, (sp)
+ mov r27, r13
+ .base r13, $ls
+
+ ldq r1, a_frame_pointer
+ ldl r1, (r1)
+
+; Bump the return PC past the branch sequence following the jsr that got us here:
+ addl r26, r16, r26 ; length of branch sequence
+ stl r26, msf$mpc_off(r1) ; and store it in the Mumps stack frame
+
+ $call COPY_STACK_FRAME, set_arg_info=false, nonstandard=true
+
+ ldq r12, a_frame_pointer
+ ldl r12, (r12)
+
+ ldq r26, (sp)
+ ldq r13, 8(sp)
+ lda sp, 16(sp)
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_alpha/op_equnul.m64 b/sr_alpha/op_equnul.m64
new file mode 100644
index 0000000..713ecc3
--- /dev/null
+++ b/sr_alpha/op_equnul.m64
@@ -0,0 +1,61 @@
+; ################################################################
+; # #
+; # Copyright 2001, 2008 Fidelity Information Services, Inc #
+; # #
+; # This source code contains the intellectual property #
+; # of its copyright holder(s), and is made available #
+; # under a license. If you do not know the terms of #
+; # the license, please stop and do not read further. #
+; # #
+; ################################################################
+
+ .title OP_EQUNUL "Compare mval to null string"
+
+ mval$def
+
+
+ $linkage_section
+
+a_undef_inhibit:
+ .address undef_inhibit
+
+
+ $code_section
+
+ $routine OP_EQUNUL, entry=OP_EQUNUL_CA, kind=null
+ .base r27, $ls
+
+ mv_if_notdefined (r0), 30$
+
+ mv_if_notstring (r0), 20$
+ ldl r28, mval$l_strlen(r0)
+ bne r28, 20$
+
+; Mval is a null string
+10$: mov 1, r24
+ ret r26
+
+; Mval is not a null string
+20$: clr r24
+ ret r26
+
+; If undef_inhibit is set, then all undefined values are equal to the null string:
+30$: ldq r28, a_undef_inhibit
+ ldq_u r24, (r28)
+ extbl r24, r28, r24
+ bne r24, 10$ ; it's set; treat mval as a null string
+
+; It's not set, so issue a message:
+ lda sp, -8(sp) ; but first,
+ stq r26, (sp) ; save the return address
+ mov r0, r16
+ $call UNDERR, args=<r16>, set_arg_info=false, nonstandard=true
+
+ ldq r26, (sp) ; restore our return address
+ lda sp, 8(sp)
+
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_alpha/op_forlcldo.m64 b/sr_alpha/op_forlcldo.m64
new file mode 100644
index 0000000..b88cdb3
--- /dev/null
+++ b/sr_alpha/op_forlcldo.m64
@@ -0,0 +1,51 @@
+ .title OP_FORLCLDO
+; ###############################################################
+; # #
+; # Copyright 2001, 2003 Sanchez Computer Associates, Inc. #
+; # #
+; # This source code contains the intellectual property #
+; # of its copyright holder(s), and is made available #
+; # under a license. If you do not know the terms of #
+; # the license, please stop and do not read further. #
+; # #
+; ###############################################################
+
+ G_MSF
+
+
+ $linkage_section
+
+a_frame_pointer:
+ .address frame_pointer
+
+
+ $code_section
+
+ $routine OP_FORLCLDOB, entry=OP_FORLCLDO_CA, aliases=<OP_FORLCLDOW,OP_FORLCLDOL>, kind=null
+ lda sp, -16(sp)
+ stq r13, 8(sp)
+ stq r26, (sp)
+ mov r27, r13
+ .base r13, $ls
+
+ ldq r1, a_frame_pointer
+ ldl r1, (r1)
+
+; Bump the return PC past the branch instruction following the jsr that got us here:
+ addl r26, r16, r26 ; length of branch sequence
+ stl r26, msf$mpc_off(r1) ; and store it in the Mumps stack frame
+
+ $call EXFUN_FRAME, set_arg_info=false, nonstandard=true
+
+ ldq r12, a_frame_pointer
+ ldl r12, (r12)
+ ldl r9, msf$temps_ptr_off(r12)
+
+ ldq r26, (sp)
+ ldq r13, 8(sp)
+ lda sp, 16(sp)
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_alpha/op_linestart.m64 b/sr_alpha/op_linestart.m64
new file mode 100644
index 0000000..725b26a
--- /dev/null
+++ b/sr_alpha/op_linestart.m64
@@ -0,0 +1,24 @@
+; ################################################################
+; # #
+; # Copyright 2001, 2008 Fidelity Information Services, Inc #
+; # #
+; # This source code contains the intellectual property #
+; # of its copyright holder(s), and is made available #
+; # under a license. If you do not know the terms of #
+; # the license, please stop and do not read further. #
+; # #
+; ################################################################
+
+ .title op_linestart
+ G_MSF
+
+; op_linestart - establish start of line in GT.M MUMPS stack frame
+
+ $routine name=op_linestart,entry=op_linestart_ca,kind=null
+
+ stl r26, msf$mpc_off(r12)
+ stl r13, msf$ctxt_off(r12)
+
+ ret r26
+
+ $end_routine name=op_linestart
diff --git a/sr_alpha/op_pattern.m64 b/sr_alpha/op_pattern.m64
new file mode 100644
index 0000000..726f0d8
--- /dev/null
+++ b/sr_alpha/op_pattern.m64
@@ -0,0 +1,51 @@
+; ################################################################
+; # #
+; # Copyright 2001, 2008 Fidelity Information Services, Inc #
+; # #
+; # This source code contains the intellectual property #
+; # of its copyright holder(s), and is made available #
+; # under a license. If you do not know the terms of #
+; # the license, please stop and do not read further. #
+; # #
+; ################################################################
+
+ .title OP_PATTERN
+
+ mval$def
+
+ $routine OP_PATTERN, entry=OP_PATTERN_CA, kind=null
+ lda sp, -16(sp)
+ stq r13, 8(sp)
+ stq r26, (sp)
+ mov r27, r13
+ .base r13, $ls
+
+ mov r0, r16
+ mov r1, r17
+
+ ;
+ ; This is an array of unaligned ints. If the first word is zero, then call do_pattern
+ ; instead of do_patfixed. Only the low order byte is significant and so it is the only
+ ; one we need to test. We would do this in assembly because (1) we need the assmembly
+ ; routine anyway to save the return value into $TEST and (2) it saves an extra level of
+ ; call linkage at the C level to do the decision here.
+ ;
+ ldl r28, mval$a_straddr(r1)
+ ldq_u r24, (r28)
+ extbl r24, r28, r24
+ beq r24, 20$
+
+10$: $call DO_PATFIXED, args=<r16, r17>, set_arg_info=false, nonstandard=true
+
+15$: mov r0, r24
+ ldq r26, (sp)
+ ldq r13, 8(sp)
+ lda sp, 16(sp)
+ ret r26
+
+20$: $call DO_PATTERN, args=<r16, r17>, set_arg_info=false, nonstandard=true
+ br 15$
+
+ $end_routine
+
+ .end
diff --git a/sr_alpha/op_sorts_after.m64 b/sr_alpha/op_sorts_after.m64
new file mode 100644
index 0000000..d664244
--- /dev/null
+++ b/sr_alpha/op_sorts_after.m64
@@ -0,0 +1,41 @@
+; ################################################################
+; # #
+; # Copyright 2001, 2008 Fidelity Information Services, Inc #
+; # #
+; # This source code contains the intellectual property #
+; # of its copyright holder(s), and is made available #
+; # under a license. If you do not know the terms of #
+; # the license, please stop and do not read further. #
+; # #
+; ################################################################
+
+ .title OP_SORTS_AFTER
+
+; On entry:
+; r0 -> mval for left hand side
+; r1 -> mval for right hand side
+;
+; On exit:
+; r24 < 0 : lhs ']] rhs (lhs ]] rhs is false)
+; r24 = 0 : lhs = rhs (lhs ]] rhs is false)
+; r24 > 0 : lhs ]] rhs (lhs ]] rhs is true)
+
+
+ $routine OP_SORTS_AFTER, entry=OP_SORTS_AFTER_CA, kind=null
+ lda sp, -8(sp)
+ stq r26, (sp)
+ .base r27, $ls
+
+ mov r0, r16
+ mov r1, r17
+ $call SORTS_AFTER, args=<r16, r17>, set_arg_info=false, nonstandard=true
+ mov r0, r24
+
+ ldq r26, (sp)
+ lda sp, 8(sp)
+
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_alpha/pseudo_ret.m64 b/sr_alpha/pseudo_ret.m64
new file mode 100644
index 0000000..3fa3e45
--- /dev/null
+++ b/sr_alpha/pseudo_ret.m64
@@ -0,0 +1,37 @@
+; ################################################################
+; # #
+; # Copyright 2001, 2008 Fidelity Information Services, Inc #
+; # #
+; # This source code contains the intellectual property #
+; # of its copyright holder(s), and is made available #
+; # under a license. If you do not know the terms of #
+; # the license, please stop and do not read further. #
+; # #
+; ################################################################
+
+ .title PSEUDO_RET
+
+; PSEUDO_RET calls opp_ret (which doesn't return). It executes in a
+; GT.M MUMPS stack frame and is, in fact, normally entered via a
+; getframe/ret instruction sequence.
+;
+; entry:
+; r13 - address of PSEUDO_RET's procedure descriptor (not r27)
+;
+; WARNING: because PSEUDO_RET is designed to be invoked from a GT.M
+; MUMPS stack frame, it does not conform to the Alpha calling
+; standard and cannot be invoked from any high-level language. The
+; invoker should load the address of PSEUDO_RET's procedure descriptor
+; into r13, not r27.
+
+
+ $code_section
+
+ $routine PSEUDO_RET, entry=PSEUDO_RET_CA, kind=null
+ .base r13, $ls
+
+ $call opp_ret, set_arg_info=false, nonstandard=true
+
+ $end_routine
+
+ .end
diff --git a/sr_alpha/zbreaksp.h b/sr_alpha/zbreaksp.h
new file mode 100644
index 0000000..cc91060
--- /dev/null
+++ b/sr_alpha/zbreaksp.h
@@ -0,0 +1,28 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+typedef unsigned short zb_code;
+#define ZB_CODE_MASK 0xffff
+#define INST_TYPE zb_code
+
+/* The ZBreak command operates by finding the generated code for the op_linestart or op_linefetch for the source
+ * line in question and changing the offset in the transfer table load address instruction from the op_linestart or
+ * op_linefetch offset to the appropriate zbreak functionality opcode offset.
+ * In some platforms(IA64 and ZOS) since the INSTRUCTION LAYOUT is complex we need following
+ * macros for instruction manipulation.
+ * EXTRACT_OFFSET_TO_M_OPCODE
+ * FIX_OFFSET_WITH_ZBREAK_OFFSET
+ * EXTRACT_AND_UPDATE_INST
+ * These macros are called only when COMPLEX_INSTRUCTION_UPDATE is defined
+ * If COMPLEX_INSTRUCTION_UPDATE is not defined portable code in the caller of these macros
+ * is invoked.
+ */
+#undef COMPLEX_INSTRUCTION_UPDATE
diff --git a/sr_avms/adawi.c b/sr_avms/adawi.c
new file mode 100644
index 0000000..d76befb
--- /dev/null
+++ b/sr_avms/adawi.c
@@ -0,0 +1,22 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include <builtins.h>
+
+/* __ADAWI on Alpha returns a simulated VAX PSL, NOT a value representing a condition code (-1, 0, or +1).
+ adawi is defined here as a static routine to convert the PSL to an appropriate value. */
+int adawi(short x, short *y)
+{
+ int vax_psl = __ADAWI(x, y);
+ if (vax_psl & 4 /* Z bit */) return 0;
+ if (vax_psl & 8 /* N bit */) return -1;
+ return 1;
+}
diff --git a/sr_avms/aswp.m64 b/sr_avms/aswp.m64
new file mode 100644
index 0000000..df13826
--- /dev/null
+++ b/sr_avms/aswp.m64
@@ -0,0 +1,14 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ;
+; Copyright 2005 Fidelity Information Services, Inc ;
+; ;
+; This source code contains the intellectual property ;
+; of its copyright holder(s), and is made available ;
+; under a license. If you do not know the terms of ;
+; the license, please stop and do not read further. ;
+; ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+GTMSHR_ASWP = 1
+
+.INCLUDE "gtm$src:aswp_src.h"
diff --git a/sr_avms/aswp_secshr.m64 b/sr_avms/aswp_secshr.m64
new file mode 100644
index 0000000..5f4845b
--- /dev/null
+++ b/sr_avms/aswp_secshr.m64
@@ -0,0 +1,14 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ;
+; Copyright 2005 Fidelity Information Services, Inc ;
+; ;
+; This source code contains the intellectual property ;
+; of its copyright holder(s), and is made available ;
+; under a license. If you do not know the terms of ;
+; the license, please stop and do not read further. ;
+; ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+GTMSECSHR_ASWP = 1
+
+.INCLUDE "gtm$src:aswp_src.h"
diff --git a/sr_avms/aswp_src.h b/sr_avms/aswp_src.h
new file mode 100644
index 0000000..5dd6d5a
--- /dev/null
+++ b/sr_avms/aswp_src.h
@@ -0,0 +1,85 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ;
+; Copyright 2005 Fidelity Information Services, Inc ;
+; ;
+; This source code contains the intellectual property ;
+; of its copyright holder(s), and is made available ;
+; under a license. If you do not know the terms of ;
+; the license, please stop and do not read further. ;
+; ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+; Atomic swap operation
+; int aswp(int *loc, int value)
+;
+; set *loc to value and return the old value of *loc,
+; in the equivalent of one atomic operation.
+;
+
+.IF DEFINED GTMSHR_ASWP
+
+ .title ASWP
+
+ $routine ASWP, entry=ASWP_CA, kind=null
+.ELSE
+.IF DEFINED GTMSECSHR_ASWP
+
+ .title ASWP_SECSHR
+
+ $routine ASWP_SECSHR, entry=ASWP_SECSHR_CA, kind=null
+.ELSE
+.ERROR "Unsupported Image"
+.ENDC
+.ENDC
+
+RETRY_COUNT = 1024 ; of times to attempt swap before sleeping
+SLEEP_TIME = 500 ; 1/2 ms
+stack_size = 32
+
+ lda sp, -stack_size(sp)
+ stq r26,0(sp)
+ stq r16,8(sp) ; loc
+ stq r17,16(sp) ; value
+ .base r27, $ls
+
+ mov RETRY_COUNT,r23
+
+; Make sure we know what we're about to pick up.
+ mb
+
+; the ldl_l/stl_c combination detects whether the location has been modified
+; in between load and store.
+retry: ldl_l r22,(r16)
+ mov r22, r0
+ mov r17, r22
+ stl_c r22,(r16)
+; r22 == 0: unsuccessful, retry operation
+; r22 == 1: successful swap
+ beq r22,store_failed
+
+; Make sure what we put down is really there..
+ mb
+
+; Return...
+ ldq r26,0(sp)
+ lda sp, stack_size(sp)
+ ret (r26)
+
+; retry operation immediately unless we've retried too many times. In that
+; case hibernate for a short while defined above.
+store_failed:
+ subq r23,1,r23
+ bne r23,retry
+.IF DEFINED GTMSHR_ASWP
+; for GTMSECSHR, we do not sleep - not a good idea in privileged mode
+ mov SLEEP_TIME,r16
+ $call HIBER_START, args=<r16>, set_arg_info=false, nonstandard=true
+.ENDC
+ mov RETRY_COUNT,r23
+ ldq r16,8(sp)
+ ldq r17,16(sp)
+ br retry
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/auto_zlink.c b/sr_avms/auto_zlink.c
new file mode 100644
index 0000000..80e11cf
--- /dev/null
+++ b/sr_avms/auto_zlink.c
@@ -0,0 +1,110 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include "axp_registers.h"
+#include "axp_gtm_registers.h"
+#include "axp.h"
+#include "urx.h"
+#include <rtnhdr.h>
+#include "stack_frame.h"
+#include "op.h"
+#include <auto_zlink.h>
+
+#define INST_SZ 1
+
+#define LDQ_R17_OFF ((-5)*INST_SZ)
+#define LDQ_R16_OFF ((-4)*INST_SZ)
+#define LDL_R27_OFF ((-3)*INST_SZ)
+#define LDQ_R26_OFF ((-2)*INST_SZ)
+#define JMP_R26_OFF ((-1)*INST_SZ)
+
+#define LDQ_R17_X2_R13 (ALPHA_INS_LDQ | (ALPHA_REG_A1 << ALPHA_SHIFT_RA) | (GTM_REG_PV << ALPHA_SHIFT_RB))
+#define LDQ_R16_X1_R13 (ALPHA_INS_LDQ | (ALPHA_REG_A0 << ALPHA_SHIFT_RA) | (GTM_REG_PV << ALPHA_SHIFT_RB))
+#define LDL_R27_XF_R11 (ALPHA_INS_LDL | (ALPHA_REG_PV << ALPHA_SHIFT_RA) | (GTM_REG_XFER_TABLE << ALPHA_SHIFT_RB))
+#define LDQ_R26_8_R27 (ALPHA_INS_LDQ | (ALPHA_REG_RA << ALPHA_SHIFT_RA) | (ALPHA_REG_PV << ALPHA_SHIFT_RB) \
+ | (8 << ALPHA_SHIFT_DISP))
+#define JMP_R26_R26 (ALPHA_INS_JSR | (ALPHA_REG_RA << ALPHA_SHIFT_RA) | (ALPHA_REG_RA << ALPHA_SHIFT_RB))
+
+GBLREF stack_frame *frame_pointer;
+
+error_def(ERR_LABELUNKNOWN);
+error_def(ERR_ROUTINEUNKNOWN);
+
+rhdtyp *auto_zlink(uint4 *pc, uint4 *line)
+{
+ uint4 *A_proc_desc, *A_labaddr;
+ mstr rname;
+ mval rtn;
+ rhdtyp *rhead;
+ urx_rtnref *rtnurx;
+ mident_fixed rname_local;
+
+/* ASSUMPTION The instructions immediately preceding the current mpc form a transfer table call.
+ * There will be two arguments to this call:
+ * the address of a procedure descriptor and
+ * the address of a pointer to a value which is the offset from the beginning of the routine header to
+ * the address of the first instruction to be executed in the routine to be called, as specified
+ * by the [label][+offset] field (or the beginning of the routine if label and offset are not
+ * specified
+ *
+ * The entire instruction sequence will look like this:
+ * ldq r17, x2(r13)
+ * ldq r16, x1(r13)
+ * ldl r27, 4*xf_off(r11)
+ * ldq r26, 8(r27)
+ * jmp r26, (r26)
+ *
+ * N.B., the instruction sequence above occurs in compiled object modules; in direct mode, the argument
+ * registers are loaded via "ldl" instructions. However, this routine should never be invoked from direct
+ * mode because the applicable routine should have been ZLINK'ed by prior calls to op_labaddr and op_rhdaddr.
+ */
+
+ /* Verify calling sequence. */
+ if ( (*(pc + LDQ_R17_OFF) & ~(ALPHA_MASK_DISP << ALPHA_SHIFT_DISP)) != LDQ_R17_X2_R13
+ || (*(pc + LDQ_R16_OFF) & ~(ALPHA_MASK_DISP << ALPHA_SHIFT_DISP)) != LDQ_R16_X1_R13
+ || (*(pc + LDL_R27_OFF) & ~(ALPHA_MASK_DISP << ALPHA_SHIFT_DISP)) != LDL_R27_XF_R11
+ || (*(pc + LDQ_R26_OFF) != LDQ_R26_8_R27)
+ || (*(pc + JMP_R26_OFF) != JMP_R26_R26) )
+ GTMASSERT;
+ /* Calling sequence O.K.; get address(address(procedure descriptor)) and address(address(label offset)). */
+ A_proc_desc = (*(pc + LDQ_R16_OFF) & (ALPHA_MASK_DISP << ALPHA_SHIFT_DISP)) + frame_pointer->ctxt;
+ A_labaddr = (*(pc + LDQ_R17_OFF) & (ALPHA_MASK_DISP << ALPHA_SHIFT_DISP)) + frame_pointer->ctxt;
+ if (azl_geturxrtn(A_proc_desc, &rname, &rtnurx))
+ {
+ assert(rname.len <= MAX_MIDENT_LEN);
+ assert(0 != rname.addr);
+
+ /* Copy rname into local storage because azl_geturxrtn sets rname.addr to an address that is
+ * free'd during op_zlink and before the call to find_rtn_hdr.
+ */
+ memcpy(rname_local.c, rname.addr, rname.len);
+ rname.addr = rname_local.c;
+ assert(0 != rtnurx);
+ assert(azl_geturxlab(A_labaddr, rtnurx));
+ assert(0 == find_rtn_hdr(&rname));
+ rtn.mvtype = MV_STR;
+ rtn.str.len = rname.len;
+ rtn.str.addr = rname.addr;
+ op_zlink(&rtn, 0);
+ if (0 != (rhead = find_rtn_hdr(&rname)))
+ {
+ *line = *A_labaddr;
+ if (0 == *line)
+ rts_error(VARLSTCNT(1) ERR_LABELUNKNOWN);
+ return rhead;
+ }
+ }
+ rts_error(VARLSTCNT(1) ERR_ROUTINEUNKNOWN);
+}
diff --git a/sr_avms/auto_zlink.h b/sr_avms/auto_zlink.h
new file mode 100644
index 0000000..a93ad3d
--- /dev/null
+++ b/sr_avms/auto_zlink.h
@@ -0,0 +1,17 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef __AUTO_ZLINK_H__
+#define __AUTO_ZLINK_H__
+
+rhdtyp *auto_zlink(uint4 *pc, uint4 *line);
+
+#endif
diff --git a/sr_avms/axp_gtm_registers.h b/sr_avms/axp_gtm_registers.h
new file mode 100644
index 0000000..1a74097
--- /dev/null
+++ b/sr_avms/axp_gtm_registers.h
@@ -0,0 +1,44 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* axp_gtm_registers.h - GT.M OpenVMS AXP register usage.
+ *
+ * Requires "axp_registers.h".
+ *
+ */
+
+
+#define GTM_REG_FRAME_POINTER ALPHA_REG_S10 /* r12 */
+#define GTM_REG_FRAME_VAR_PTR ALPHA_REG_S6 /* r8 */
+#define GTM_REG_FRAME_TMP_PTR ALPHA_REG_S7 /* r9 */
+#define GTM_REG_LITERAL_BASE ALPHA_REG_S12 /* r14 */
+#define GTM_REG_XFER_TABLE ALPHA_REG_S9 /* r11 */
+#define GTM_REG_DOLLAR_TRUTH ALPHA_REG_S8 /* r10 */
+
+#define GTM_REG_R0 ALPHA_REG_R0
+#define GTM_REG_R1 ALPHA_REG_R1
+
+#define GTM_REG_ACCUM ALPHA_REG_T1 /* r23 */
+#define GTM_REG_COND_CODE ALPHA_REG_T2 /* r24 */
+#define GTM_REG_CODEGEN_TEMP ALPHA_REG_VS /* r28 */
+
+
+/* The generated code uses GTM_REG_PV for its PV. Also, the VAX Macro
+ * translator uses S11 (R13) to save the current PV. So, for consistency,
+ * we make the GTM PV the same (S11). In addition, when returning from
+ * C, we usually reload the PV of the procedure to which we are returning
+ * into S11 where it is expected (from the Mumps stack frame). In some
+ * routines (OPP_RET, for example), we intend to "return" to a new procedure
+ * and enter it via its prolog: in that case, we need to set the PV into
+ * R27, the Alpha PV register.
+ */
+
+#define GTM_REG_PV ALPHA_REG_S11 /* r13 */
diff --git a/sr_avms/axp_registers.h b/sr_avms/axp_registers.h
new file mode 100644
index 0000000..ce96ddd
--- /dev/null
+++ b/sr_avms/axp_registers.h
@@ -0,0 +1,56 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* axp_registers.h - OpenVMS AXP register usage. */
+
+
+/* Register names according to OpenVMS usage. */
+
+#define ALPHA_REG_R0 0 /* corresponds to VAX register r0 */
+#define ALPHA_REG_R1 1 /* corresponds to VAX register r1 */
+#define ALPHA_REG_S0 2 /* saved */
+#define ALPHA_REG_S1 3
+#define ALPHA_REG_S2 4
+#define ALPHA_REG_S3 5
+#define ALPHA_REG_S4 6
+#define ALPHA_REG_S5 7
+#define ALPHA_REG_S6 8
+#define ALPHA_REG_S7 9
+#define ALPHA_REG_S8 10
+#define ALPHA_REG_S9 11
+#define ALPHA_REG_S10 12
+#define ALPHA_REG_S11 13
+#define ALPHA_REG_S12 14
+#define ALPHA_REG_S13 15
+#define ALPHA_REG_A0 16 /* argument */
+#define ALPHA_REG_A1 17
+#define ALPHA_REG_A2 18
+#define ALPHA_REG_A3 19
+#define ALPHA_REG_A4 20
+#define ALPHA_REG_A5 21
+#define ALPHA_REG_T0 22 /* temp */
+#define ALPHA_REG_T1 23
+#define ALPHA_REG_T2 24
+#define ALPHA_REG_AI 25 /* arg info */
+#define ALPHA_REG_RA 26 /* return address */
+#define ALPHA_REG_PV 27 /* procedure value */
+#define ALPHA_REG_VS 28 /* volatile scratch */
+#define ALPHA_REG_FP 29 /* frame pointer */
+#define ALPHA_REG_SP 30 /* stack pointer */
+#define ALPHA_REG_ZERO 31 /* hard-wired zero */
+
+#define ALPHA_REG_V0 ALPHA_REG_R0 /* function return value */
+
+
+/* Number of arguments passed in registers. */
+
+#define MACHINE_REG_ARGS 6
+
diff --git a/sr_avms/base_frame.max b/sr_avms/base_frame.max
new file mode 100644
index 0000000..1e3ca12
--- /dev/null
+++ b/sr_avms/base_frame.max
@@ -0,0 +1,168 @@
+ .macro base_frame
+
+; base_frame describes the machine stack frame in which all GT.M MUMPS object code
+; executes. It has a fixed stack size large enough for the saved registers and
+; the condition handler address as expected by GTM$DYN_CH. In addition, there is
+; a stack temporary area large enough for the largest allowable number of parameters
+; (limited by the VAX 'calls' instruction whose count parameter must be <= 255).
+
+; Stack size information. These fields MUST match values in create_object_file() in
+; obj_file.c. Changes to any of these values will require customers both to recompile
+; their GT.M source files and to re-link the new object files.
+
+; Note: the intricacy of the offset calculations is required in order to duplicate
+; the structure expected by the $routine and $return macros which require certain
+; blocks of data in a stack frame to be aligned on 16-byte boundaries.
+
+NQUADS_REQUIRED = 2 ; one at (sp) for r27 and one at 8(sp) for A(condition handler)
+NLOCALS = 16 ; allows room for expansion
+base_frame_regs = "r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, fp"
+NREGS_SAVED = 16 ; <r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,r13,r14,r15,fp> and r26 (default)
+NARGS_SAVED = <1+6> ; r25 (count) and r16-r21
+RSA_END = <<<<<NQUADS_REQUIRED+NLOCALS+NREGS_SAVED>*8>+15>/16>*16> ; end of register save area
+RSA_OFFSET = <RSA_END-<NREGS_SAVED*8>>
+STACK_SIZE = <<<RSA_END+<NARGS_SAVED*8>+15>/16>*16> ; add room for argument save area (round up again)
+ARG_OFFSET = <STACK_SIZE-<NARGS_SAVED*8>> ; offset of r25, r16-r21 save area in stack frame
+
+; Offsets from fp into stack frame for locals:
+GTM_LOCAL_1 = 16
+GTM_LOCAL_2 = 24
+GTM_LOCAL_3 = 32
+GTM_LOCAL_4 = 40
+GTM_LOCAL_5 = 48
+GTM_LOCAL_6 = 56
+GTM_LOCAL_7 = 64
+GTM_LOCAL_8 = 72
+GTM_LOCAL_9 = 80
+GTM_LOCAL_10 = 88
+GTM_LOCAL_11 = 96
+GTM_LOCAL_12 = 104
+GTM_LOCAL_13 = 112
+GTM_LOCAL_14 = 120
+GTM_LOCAL_15 = 128
+GTM_LOCAL_16 = 136
+
+GTM_LOCAL_SIZE = GTM_LOCAL_16+8
+
+; Stack extension area for building argument lists for calling other routines and for internal use.
+ARG_AREA_SZ = 256*8 ; room for 256 arguments + 6 extra quadwords. The VAX 'calls' instruction allows a maximum
+ ; of 255 arguments and we pass the count as an argument sometimes, but because the AXP
+ ; passes the first six arguments and the argument count in registers, we only need 250
+ ; locations for argument-passing and the other 6 quadwords are available for internal
+ ; GT.M use.
+
+; Offsets from fp into stack extension area for internal use-quadwords (hidden locals):
+GTM_INTERNAL_1 = -1*8
+GTM_INTERNAL_2 = -2*8
+GTM_INTERNAL_3 = -3*8
+GTM_INTERNAL_4 = -4*8
+GTM_INTERNAL_5 = -5*8
+GTM_INTERNAL_6 = -6*8
+
+; Here's the stack frame defined by base_frame and created by create_base_frame:
+
+
+; +---------------------------------------+ <- caller's sp -----
+; | r21 (argument 6) |\ (Q-aligned) ^
+; +---------------------------------------+ \ |
+; | r20 (argument 5) | | |
+; +---------------------------------------+ | |
+; | r19 (argument 4) | | |
+; +---------------------------------------+ | home area for arguments |
+; | r18 (argument 3) | |--- passed in registers; must |
+; +---------------------------------------+ | be contiguous with |
+; | r17 (argument 2) | | caller's sp for varargs |
+; +---------------------------------------+ | to work |
+; | r16 (argument 1) | | |
+; +---------------------------------------+ / |
+; | r25 (argument info/count) |/ |
+; +---------------------------------------+ |
+; = <probable alignment padding> = |
+; fp+RSA_END-> +---------------------------------------+ (Q-aligned) |
+; | fp |\ |
+; +---------------------------------------+ \ |
+; | r15 | | |
+; +---------------------------------------+ | |
+; | r14 | | |
+; +---------------------------------------+ | |
+; | r13 | | |
+; +---------------------------------------+ | |
+; | r12 | | |
+; +---------------------------------------+ | |
+; | r11 | | |
+; +---------------------------------------+ | |
+; | r10 | | |
+; +---------------------------------------+ |--- saved registers |
+; | r9 | | |
+; +---------------------------------------+ | |
+; | r8 | | |
+; +---------------------------------------+ | |
+; | r7 | | |
+; +---------------------------------------+ | |
+; | r6 | | |
+; +---------------------------------------+ | |
+; | r5 | | |
+; +---------------------------------------+ | |
+; | r4 | | |
+; +---------------------------------------+ | |--- STACK_SIZE
+; | r3 | | |
+; +---------------------------------------+ / |
+; | r2 |/ |
+; fp+RSA_OFFSET-> +---------------------------------------+ |
+; = <possible alignment padding> = |
+; +---------------------------------------+ |
+; fp+136 | GTM_LOCAL_16 | |
+; +---------------------------------------+ |
+; fp+128 | GTM_LOCAL_15 | |
+; +---------------------------------------+ |
+; fp+120 | GTM_LOCAL_14 | |
+; +---------------------------------------+ |
+; fp+112 | GTM_LOCAL_13 | |
+; +---------------------------------------+ |
+; fp+104 | GTM_LOCAL_12 | |
+; +---------------------------------------+ |
+; fp+96 | GTM_LOCAL_11 | |
+; +---------------------------------------+ |
+; fp+88 | GTM_LOCAL_10 | |
+; +---------------------------------------+ |
+; fp+80 | GTM_LOCAL_9 | |
+; +---------------------------------------+ |
+; fp+72 | GTM_LOCAL_8 | |
+; +---------------------------------------+ |
+; fp+64 | GTM_LOCAL_7 | |
+; +---------------------------------------+ |
+; fp+56 | GTM_LOCAL_6 | |
+; +---------------------------------------+ |
+; fp+48 | GTM_LOCAL_5 | |
+; +---------------------------------------+ |
+; fp+40 | GTM_LOCAL_4 | |
+; +---------------------------------------+ |
+; fp+32 | GTM_LOCAL_3 | |
+; +---------------------------------------+ |
+; fp+24 | GTM_LOCAL_2 | |
+; +---------------------------------------+ |
+; fp+16 | GTM_LOCAL_1 | |
+; +---------------------------------------+ |
+; fp+8 | A(condition handler) | GTM$DYN_CH looks here |
+; +---------------------------------------+ (0 => no handler) |
+; | r27 (PV) | v
+; +---------------------------------------+ <- fp (Q-aligned) -----
+; fp-8 | GTM_INTERNAL_1 |\ ^
+; +---------------------------------------+ \ |
+; fp-16 | GTM_INTERNAL_2 | | |
+; +---------------------------------------+ | |
+; fp-24 | GTM_INTERNAL_3 | | |
+; +---------------------------------------+ |--- internal-use quadwords |
+; fp-32 | GTM_INTERNAL_4 | | (hidden locals) |--- ARG_AREA_SZ
+; +---------------------------------------+ | |
+; fp-40 | GTM_INTERNAL_5 | | |
+; +---------------------------------------+ / |
+; fp-48 | GTM_INTERNAL_6 |/ |
+; +---------------------------------------+ |
+; = <argument build area> = |
+; | (room for 250 arguments) | |
+; = = V
+; fp-ARG_AREA_SZ +---------------------------------------+ <- sp (Q-aligned) -----
+
+
+ .endm base_frame
diff --git a/sr_avms/bci.mar b/sr_avms/bci.mar
new file mode 100644
index 0000000..f727382
--- /dev/null
+++ b/sr_avms/bci.mar
@@ -0,0 +1,9 @@
+ .title bci bit clear interlocked
+VAX = 1
+ code_psect
+ .entry bci,^m<>
+ clrl r0
+ bbcci #0, at 4(ap),10$
+ incl r0
+10$: ret
+ .end
diff --git a/sr_avms/bind_symbol.m64 b/sr_avms/bind_symbol.m64
new file mode 100644
index 0000000..8b85bdd
--- /dev/null
+++ b/sr_avms/bind_symbol.m64
@@ -0,0 +1,32 @@
+ .title BIND_SYMBOL "Utility routine for bndsym macro"
+
+ $routine BIND_SYMBOL, entry=BIND_SYMBOL_CA, kind=null
+ lda sp, -32(sp)
+ stq r13, 24(sp)
+ stq r26, 16(sp)
+ mov r27, r13
+ .base r13, $ls
+
+ stq r18, 8(sp) ; save pointer to linkage pair
+
+ $call LIB$FIND_IMAGE_SYMBOL, args=<r16,r17,sp>, nonstandard=true
+ blbc r0, 10$
+
+ ldq r18, 8(sp) ; r18 -> linkage pair
+ ldl r28, (sp) ; r28 = procedure value returned by LIB$FIND_IMAGE_SYMBOL
+ stq r28, 8(r18) ; store PV in 2nd quadword of linkage pair
+ ldq r28, 8(r28) ; r28 = entry address from procedure descriptor
+ stq r28, (r18) ; store entry in 1st quadword of linkage pair
+
+5$: ldq r28, 16(sp)
+ ldq r13, 24(sp)
+ lda sp, 32(sp)
+ ret r28
+
+10$: mov r0, r16
+ $call LIB$SIGNAL, args=<r16>, nonstandard=true
+ br 5$
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/bndsym.max b/sr_avms/bndsym.max
new file mode 100644
index 0000000..e484b04
--- /dev/null
+++ b/sr_avms/bndsym.max
@@ -0,0 +1,70 @@
+ .macro bndsym symbol, image, ?entry_point, ?proc_value, ?symdesc, ?imdesc
+
+; Bind a universal symbol at run time
+
+
+ $routine symbol, entry=symbol'_CA, kind=null, -
+ data_section=<$bndsym_data,pic,noexe>, data_section_pointer=true
+
+ $data_section
+
+ .align quad
+entry_point: .quad 0 ; entry_point and proc_value together
+proc_value: .quad 0 ; define a linkage pair
+
+ .align long
+symdesc: .ascid /symbol/
+
+ .align long
+imdesc: .ascid /image/
+
+
+ $code_section
+
+ .base r27, $ls
+
+ ldq r22, $dp
+ .base r22, $ds
+
+ ldq r28, entry_point
+ beq r28, 10$
+
+ ldq r27, proc_value
+ jmp r28
+
+
+; Call BIND_SYMBOL to resolve the symbol's address, then jmp to it.
+; This must be transparent, so save (and restore) all of the
+; argument-related registers, as well as the original return address.
+
+10$: lda sp, -80(sp)
+ stq r16, 0(sp)
+ stq r17, 8(sp)
+ stq r18, 16(sp)
+ stq r19, 24(sp)
+ stq r20, 32(sp)
+ stq r21, 40(sp)
+ stq r22, 48(sp) ; data section base register
+ stq r25, 56(sp) ; original argument count
+ stq r26, 64(sp) ; original return address
+
+ $call BIND_SYMBOL, args=<imdesc/a, symdesc/a, entry_point/a>, nonstandard=true
+
+ ldq r16, 0(sp)
+ ldq r17, 8(sp)
+ ldq r18, 16(sp)
+ ldq r19, 24(sp)
+ ldq r20, 32(sp)
+ ldq r21, 40(sp)
+ ldq r22, 48(sp)
+ ldq r25, 56(sp)
+ ldq r26, 64(sp)
+ lda sp, 80(sp)
+
+ ldq r28, entry_point
+ ldq r27, proc_value
+ jmp r28
+
+ $end_routine
+
+ .endm
diff --git a/sr_avms/bsi.mar b/sr_avms/bsi.mar
new file mode 100644
index 0000000..6fc5642
--- /dev/null
+++ b/sr_avms/bsi.mar
@@ -0,0 +1,11 @@
+ .title bsi bit set interlocked
+VAX = 1
+ code_psect
+ .entry bsi,^m<>
+ clrl r0
+ bbssi #0, at 4(ap),10$
+ ret
+
+10$: incl r0
+ ret
+ .end
diff --git a/sr_avms/call_dm.m64 b/sr_avms/call_dm.m64
new file mode 100644
index 0000000..42a1dea
--- /dev/null
+++ b/sr_avms/call_dm.m64
@@ -0,0 +1,33 @@
+ .title CALL_DM
+
+; CALL_DM - call direct mode
+;
+; CALL_DM controls execution of GT.M direct mode. It executes in a
+; GT.M MUMPS stack frame and is, in fact, normally entered via a
+; getframe/ret instruction sequence. CALL_DM invokes OPP_DMODE
+; for each input line.
+;
+; entry:
+; r13 - address of CALL_DM's procedure descriptor (not r27)
+;
+; WARNING: because CALL_DM is designed to be invoked from a GT.M
+; MUMPS stack frame, it does not conform to the Alpha calling
+; standard and cannot be invoked from any high-level language.
+; The invoker should load the address of PSEUDO_RET's procedure
+; descriptor into r13, not r27.
+
+ $linkage_section
+
+ $code_section
+
+ $routine CALL_DM, entry=CALL_DM_CA, kind=null
+
+ .base r13, $ls
+
+loop: $call OPP_DMODE, nonstandard=true
+ $call OP_OLDVAR, nonstandard=true
+ br loop
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/caller_id.m64 b/sr_avms/caller_id.m64
new file mode 100644
index 0000000..b5b9d15
--- /dev/null
+++ b/sr_avms/caller_id.m64
@@ -0,0 +1,18 @@
+ .title CALLER_ID "Get PC of caller's caller"
+
+ $LIBICBDEF
+
+ $routine CALLER_ID, entry=CALLER_ID_CA, kind=stack, saved_regs=<r13,fp>
+ mov r27, r13
+ .base r13, $ls
+
+ lda sp, -LIBICB$K_INVO_CONTEXT_BLK_SIZE(sp) ; Allocate an Invocation Context Block
+ $call LIB$GET_CURR_INVO_CONTEXT, args=<sp> ; Get our invocation context
+ $call LIB$GET_PREV_INVO_CONTEXT, args=<sp> ; Get our caller's invocation context
+ $call LIB$GET_PREV_INVO_CONTEXT, args=<sp> ; Get our caller's caller's invocation context
+ ldq r0, LIBICB$Q_PROGRAM_COUNTER(sp) ; Extract its PC
+ $return
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/callg.mar b/sr_avms/callg.mar
new file mode 100644
index 0000000..367b0e6
--- /dev/null
+++ b/sr_avms/callg.mar
@@ -0,0 +1,12 @@
+ .title callg
+
+ ;callg(rout, args)
+
+VAX = 1
+ code_psect
+ .entry callg,^m<>
+ movl 8(ap),r0
+ callg (r0), at 4(ap)
+ ret
+
+ .end
diff --git a/sr_avms/cmi_symbols.m64 b/sr_avms/cmi_symbols.m64
new file mode 100644
index 0000000..fd4eac9
--- /dev/null
+++ b/sr_avms/cmi_symbols.m64
@@ -0,0 +1,13 @@
+ .title CMI_SYMBOLS "Bind CMISHR at run time"
+
+ bndsym CMI_CLOSE, CMISHR
+ bndsym CMI_INIT, CMISHR
+ bndsym CMI_OPEN, CMISHR
+ bndsym CMI_READ, CMISHR
+ bndsym CMI_WRITE, CMISHR
+ bndsym CMI_WRITE_INT, CMISHR
+ bndsym CMU_GETCLB, CMISHR
+ bndsym CMU_MAKCLB, CMISHR
+ bndsym CMU_NTDROOT, CMISHR
+
+ .end
diff --git a/sr_avms/cmilink.axp b/sr_avms/cmilink.axp
new file mode 100644
index 0000000..a2dd5c3
--- /dev/null
+++ b/sr_avms/cmilink.axp
@@ -0,0 +1,28 @@
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+! !
+! Copyright 2001, 2003 Sanchez Computer Associates, Inc. !
+! !
+! This source code contains the intellectual property !
+! of its copyright holder(s), and is made available !
+! under a license. If you do not know the terms of !
+! the license, please stop and do not read further. !
+! !
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!
+cluster = code_clust
+collect = code_clust,$code
+psect_attr = $char_string_constants,shr,nowrt
+cluster = gtmvector
+collect = gtmvector,gtmvector
+gsmatch = lequal,4,0
+symbol_vector=( -
+ cmi_close = PROCEDURE, -
+ cmi_init = PROCEDURE, -
+ cmi_open = PROCEDURE, -
+ cmi_read = PROCEDURE, -
+ cmi_write = PROCEDURE, -
+ cmi_write_int = PROCEDURE, -
+ cmu_makclb = PROCEDURE, -
+ cmu_getclb = PROCEDURE, -
+ cmu_ntdroot = PROCEDURE -
+ )
diff --git a/sr_avms/code_psect.max b/sr_avms/code_psect.max
new file mode 100644
index 0000000..69e30b7
--- /dev/null
+++ b/sr_avms/code_psect.max
@@ -0,0 +1,3 @@
+ .macro code_psect
+ .psect $code,pic,usr,con,rel,lcl,shr,exe,rd,nowrt,novec
+ .endm
diff --git a/sr_avms/compswap.m64 b/sr_avms/compswap.m64
new file mode 100644
index 0000000..0552bd6
--- /dev/null
+++ b/sr_avms/compswap.m64
@@ -0,0 +1,14 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ;
+; Copyright 2005 Fidelity Information Services, Inc ;
+; ;
+; This source code contains the intellectual property ;
+; of its copyright holder(s), and is made available ;
+; under a license. If you do not know the terms of ;
+; the license, please stop and do not read further. ;
+; ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+GTMSHR_COMPSWAP = 1
+
+.INCLUDE "gtm$src:compswap_src.h"
diff --git a/sr_avms/compswap_secshr.m64 b/sr_avms/compswap_secshr.m64
new file mode 100644
index 0000000..b56eb11
--- /dev/null
+++ b/sr_avms/compswap_secshr.m64
@@ -0,0 +1,14 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ;
+; Copyright 2005 Fidelity Information Services, Inc ;
+; ;
+; This source code contains the intellectual property ;
+; of its copyright holder(s), and is made available ;
+; under a license. If you do not know the terms of ;
+; the license, please stop and do not read further. ;
+; ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+GTMSECSHR_COMPSWAP = 1
+
+.INCLUDE "gtm$src:compswap_src.h"
diff --git a/sr_avms/compswap_src.h b/sr_avms/compswap_src.h
new file mode 100644
index 0000000..522c98b
--- /dev/null
+++ b/sr_avms/compswap_src.h
@@ -0,0 +1,104 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ;
+; Copyright 2005 Fidelity Information Services, Inc ;
+; ;
+; This source code contains the intellectual property ;
+; of its copyright holder(s), and is made available ;
+; under a license. If you do not know the terms of ;
+; the license, please stop and do not read further. ;
+; ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+; Compare and Swap
+; int compswap(gtm_global_latch_t *loc, int cmpvalue1, int cmpvalue2, int newvalue1, int newvalue2)
+;
+; For VMS, the latch is the form of an aligned 8 byte field. The comparison value is
+; constructed from (cmpvalue2 << 32 | cmpvalue1) and likewise the swap value
+; is constructed from (newvalue2 << 32 | cmpvalue1). If the supplied latch contains
+; the constructed comparison value, the constructed swap value is stored in the latch atomically.
+; Return TRUE if store succeeds and lock reset. Otherwise return FALSE.
+
+.IF DEFINED GTMSHR_COMPSWAP
+
+ .title COMPSWAP
+
+ $routine COMPSWAP, entry=COMPSWAP_CA, kind=null
+.ELSE
+.IF DEFINED GTMSECSHR_COMPSWAP
+
+ .title COMPSWAP_SECSHR
+
+ $routine COMPSWAP_SECSHR, entry=COMPSWAP_SECSHR_CA, kind=null
+.ELSE
+.ERROR "Unsupported image"
+.ENDC
+.ENDC
+
+RETRY_COUNT = 1000 ; of times to attempts before sleeping
+SLEEP_TIME = 500 ; 1/2 ms
+TRUE = 1
+FALSE = 0
+stack_size = 56
+
+ lda sp, -stack_size(sp)
+ stq r26, 0(sp)
+ stq r16, 8(sp) ; ->loc
+ stq r17, 16(sp) ; cmpvalue1
+ stq r18, 24(sp) ; cmpvalue2
+ stq r19, 32(sp) ; newvalue1
+ stq r20, 40(sp) ; newvalue2
+ .base r27, $ls
+
+ mov RETRY_COUNT, r24
+
+; Make sure we know what we are about to pick up.
+ mb
+
+; the ldl_l/stl_c combination detects whether the location has been modified
+; in between load and store.
+ mov FALSE,r0 ; assume failure
+retry:
+ sll r18, 32, r21 ; r21 = r18 << 32
+ bis r21, r17, r21 ; add in low order part of comparison value
+ ldq_l r22, (r16) ; load and lock the value
+ cmpeq r22, r21, r23 ; expected value supplied?
+ beq r23, return_now ; return fact that compare failed
+ sll r20, 32, r21 ; create 8 byte swap value
+ bis r21, r19, r21
+ stq_c r21, (r16) ; store and return
+; r22 == 0: unsuccessful, retry operation
+; r22 == 1: successful swap
+ beq r21, store_failed
+
+; Make sure what we put down is really there..
+ mb
+ mov TRUE,r0 ; Store was a success
+return_now: ; both error and normal return
+ ldq r26,0(sp)
+ lda sp, stack_size(sp)
+ ret (r26)
+
+
+; retry operation immediately unless we have retried too many times. In that
+; case hibernate for a short period..
+store_failed:
+ subq r24, 1, r24
+ bne r24, retry
+.IF DEFINED GTMSHR_COMPSWAP
+; for GTMSECSHR, we do not sleep - not a good idea in privileged mode
+ mov SLEEP_TIME, r16
+ $call HIBER_START, args=<r16>, set_arg_info=false, nonstandard=true
+.ENDC
+ mov RETRY_COUNT,r24
+ ldq r16, 8(sp)
+ ldq r17, 16(sp)
+ ldq r18, 24(sp)
+ ldq r19, 32(sp)
+ ldq r20, 40(sp)
+ mov FALSE, r0
+ br retry
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/create_base_frame.max b/sr_avms/create_base_frame.max
new file mode 100644
index 0000000..f6762a6
--- /dev/null
+++ b/sr_avms/create_base_frame.max
@@ -0,0 +1,51 @@
+ .macro create_base_frame
+
+; create_base_frame is the routine prologue code that sets up the machine
+; stack frame in which all GT.M MUMPS object code executes.
+
+ .if ne,$SIZE,STACK_SIZE
+ .error "The stack frame size computed by $routine (%integer(%SIZE)) differs from that defined in the -
+base_frame macro (%integer(STACK_SIZE))."
+ .endc
+
+ .if ne,$SIZE-56,ARG_OFFSET
+ .error "The homed argument list offset computed by $routine (%integer($SIZE-56)) differs from -
+that expected (%integer(ARG_OFFSET))."
+ .endc
+
+ lda sp, -$SIZE(sp)
+ stq r27, (sp) ; linkage Psect pointer
+ stq r26, $RSA_OFFSET(sp)
+ stq r2, $RSA_OFFSET+8(sp)
+ stq r3, $RSA_OFFSET+16(sp)
+ stq r4, $RSA_OFFSET+24(sp)
+ stq r5, $RSA_OFFSET+32(sp)
+ stq r6, $RSA_OFFSET+40(sp)
+ stq r7, $RSA_OFFSET+48(sp)
+ stq r8, $RSA_OFFSET+56(sp)
+ stq r9, $RSA_OFFSET+64(sp)
+ stq r10, $RSA_OFFSET+72(sp)
+ stq r11, $RSA_OFFSET+80(sp)
+ stq r12, $RSA_OFFSET+88(sp)
+ stq r13, $RSA_OFFSET+96(sp)
+ stq r14, $RSA_OFFSET+104(sp)
+ stq r15, $RSA_OFFSET+112(sp)
+ stq fp, $RSA_OFFSET+120(sp)
+ stq r31, 8(sp) ; establish no condition handler
+
+; Copy the register arguments onto the stack (a la varargs).
+ stq r21, $SIZE-8(sp)
+ stq r20, $SIZE-16(sp)
+ stq r19, $SIZE-24(sp)
+ stq r18, $SIZE-32(sp)
+ stq r17, $SIZE-40(sp)
+ stq r16, $SIZE-48(sp)
+ stq r25, $SIZE-56(sp)
+
+ trapb ; synchronize exceptions
+ mov sp, fp ; establish existence of stack frame
+$end_prologue
+
+ lda sp, -ARG_AREA_SZ(sp) ; extend for argument push area
+
+ .endm create_base_frame
diff --git a/sr_avms/data_psect_bound.m64 b/sr_avms/data_psect_bound.m64
new file mode 100644
index 0000000..b4eeb0e
--- /dev/null
+++ b/sr_avms/data_psect_bound.m64
@@ -0,0 +1,34 @@
+ .title data_psect_bound define boundaries of $DATA PSECT's
+ G_MSF
+
+ .psect $DAT9ZZZZZZZZZZ pic,ovr,rel,gbl,noshr,noexe,rd,wrt,novec,long
+datastrt:
+
+ .psect $DATAAAAAAAAAAA pic,ovr,rel,gbl,noshr,noexe,rd,wrt,novec,long
+dataend:
+
+ $linkage_section
+A_datastrt:
+ .address datastrt
+A_dataend:
+ .address dataend
+
+; data_psect_bound
+;
+; arg1 address of pointer to receive address of datastrt
+; arg2 address of pointer to receive address of dataend
+
+ $routine name=data_psect_bound,entry=data_psect_bound_ca,kind=null
+
+ .base r27, $ls
+
+ ldq r28, A_datastrt
+ ldq r22, A_dataend
+ stl r28, (r16)
+ stl r22, (r17)
+
+ ret r26
+
+ $end_routine name=data_psect_bound
+
+ .end
diff --git a/sr_avms/ddp_dal_dispatch.m64 b/sr_avms/ddp_dal_dispatch.m64
new file mode 100644
index 0000000..37df821
--- /dev/null
+++ b/sr_avms/ddp_dal_dispatch.m64
@@ -0,0 +1,113 @@
+ .title ddp_dal_dispatch
+
+
+MAX_SUBSCRIPTS = 12
+MAX_ARG_SIZE = <<<<MAX_SUBSCRIPTS+3>*8>+15>/16>*16 ; space for gtmi$_extgbl, destination, aux owner, all subscripts
+
+
+ $linkage_section
+
+A_subscript_array: .address subscript_array
+A_subscript_count: .address subscript_count
+
+Q_gtmi$_extgbl: .quad gtmi$_extgbl
+
+
+ $routine name=ddp_dal_dispatch, entry=ddp_dal_dispatch_ca, -
+ kind=stack, base_reg_is_fp=true, standard_prologue=true
+
+ .base r27, $ls
+
+ subq sp, MAX_ARG_SIZE, sp
+ ldq r0, A_subscript_count
+ ldq r1, A_subscript_array
+ ldl r0, (r0)
+ addq r0, 1, r25 ; argument count (array starts @ 0, argument count @ 1)
+
+; If destination argument (argument 2) is non-zero, pass it as 2nd argument, else skip it.
+; Rest of argument list to dispatched routine is addresses of elements in subscript array.
+ beq r17, 3$ ; if no destination argument
+ addq r25, 1, r25 ; need another argument position for destination (leave in r17)
+ br 5$
+
+3$: lda r17, (r1) ; if no destination argument, start with first array element in r17
+ addq r1, 8, r1 ; skip over first array element (already in argument list)
+ subq r0, 1, r0 ; remember not to count it twice
+5$: lda r18, (r1)
+ lda r19, 8(r1)
+ lda r20, 16(r1)
+ lda r21, 24(r1)
+ subq r0, 4, r0
+ ble r0, 20$ ; if no more arguments
+
+; Copy rest of array element addresses to stack area.
+ addq r1, 32, r1
+ mov sp, r22
+10$: lda r28, (r1)
+ stq r28, (r22)
+ subq r0, 1, r0
+ addq r1, 8, r1
+ addq r22, 8, r22
+ bgt r0, 10$
+
+20$: ldq r0, Q_gtmi$_extgbl
+ mov r16, r27
+ ldq r26, 8(r16)
+ mov r0, r16
+ jsr r26, (r26)
+
+ $return
+
+ $end_routine name=ddp_dal_dispatch
+
+
+ $routine name=ddp_lock_dispatch, entry=ddp_lock_dispatch_ca, -
+ kind=stack, base_reg_is_fp=true, standard_prologue=true
+
+ .base r27, $ls
+
+ subq sp, MAX_ARG_SIZE, sp
+ ldq r0, A_subscript_count
+ ldq r1, A_subscript_array
+ ldl r0, (r0)
+ addq r0, 2, r25 ; array elements + 1 for auxown
+ mov r16, r22 ; save A(routine to call) for later
+
+; Skip timeout on unlock.
+ and r17, ^Xff, r16
+ bne r16, 3$ ; skip timeout on unlock (otherwise timeout in r16 == 0)
+ mov r18, r17 ; aux owner
+ ldq r18, Q_gtmi$_extgbl
+ addq r25, 1, r25 ; need another argument position
+ br 5$
+
+3$: mov r18, r16 ; aux owner
+ ldq r17, Q_gtmi$_extgbl
+ lda r18, (r1)
+ addq r1, 8, r1 ; skip over first array element (already in argument list)
+ subq r0, 1, r0 ; remember not to count it twice
+5$: lda r19, (r1)
+ lda r20, 8(r1)
+ lda r21, 16(r1)
+ subq r0, 3, r0
+ ble r0, 20$ ; if no more arguments
+
+; Copy rest of array element addresses to stack area.
+ addq r1, 24, r1
+ mov sp, r23
+10$: lda r28, (r1)
+ stq r28, (r23)
+ subq r0, 1, r0
+ addq r1, 8, r1
+ addq r23, 8, r23
+ bgt r0, 10$
+
+20$: ldq r26, 8(r22)
+ mov r22, r27
+ jsr r26, (r26)
+
+ $return
+
+ $end_routine name=ddp_lock_dispatch
+
+ .end
diff --git a/sr_avms/ddpgvusr_symbols.m64 b/sr_avms/ddpgvusr_symbols.m64
new file mode 100644
index 0000000..c6bd258
--- /dev/null
+++ b/sr_avms/ddpgvusr_symbols.m64
@@ -0,0 +1,15 @@
+ .title DDPGVUSR_SYMBOLS "Bind DDPGVUSR at run time"
+
+ bndsym GVUSR_INIT, DDPGVUSR
+ bndsym GVUSR_RUNDOWN, DDPGVUSR
+ bndsym GVUSR_DATA, DDPGVUSR
+ bndsym GVUSR_ORDER, DDPGVUSR
+ bndsym GVUSR_QUERY, DDPGVUSR
+ bndsym GVUSR_ZPREVIOUS,DDPGVUSR
+ bndsym GVUSR_GET, DDPGVUSR
+ bndsym GVUSR_KILL, DDPGVUSR
+ bndsym GVUSR_PUT, DDPGVUSR
+ bndsym GVUSR_LOCK, DDPGVUSR
+ bndsym GVUSR_UNLOCK, DDPGVUSR
+
+ .end
diff --git a/sr_avms/ddplink.axp b/sr_avms/ddplink.axp
new file mode 100644
index 0000000..470055f
--- /dev/null
+++ b/sr_avms/ddplink.axp
@@ -0,0 +1,38 @@
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+! !
+! Copyright 2001, 2003 Sanchez Computer Associates, Inc. !
+! !
+! This source code contains the intellectual property !
+! of its copyright holder(s), and is made available !
+! under a license. If you do not know the terms of !
+! the license, please stop and do not read further. !
+! !
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!
+ddpobj/lib
+gtmshr/share
+gtmsecshr/share
+symbol_vector=( -
+ gvusr_init = PROCEDURE, -
+ gvusr_rundown = PROCEDURE, -
+ gvusr_data = PROCEDURE, -
+ gvusr_order = PROCEDURE, -
+ gvusr_query = PROCEDURE, -
+ gvusr_zprevious = PROCEDURE, -
+ gvusr_get = PROCEDURE, -
+ gvusr_kill = PROCEDURE, -
+ gvusr_put = PROCEDURE, -
+ gvusr_lock = PROCEDURE, -
+ gvusr_unlock = PROCEDURE -
+ )
+gsmatch=lequal,4,0
+! Because the linker creates image sections on a per-cluster
+! basis, create a cluster for all of the code Psect's (whose
+! pages can be shared among processes) and collect all of the
+! code Psect's into it so the pages corresponding to that image
+! section can be shared. Note the MACRO/MIGRATION compiler
+! names its code Psect "$CODE" (as do most of the VAX compilers),
+! while the AXP C compiler and MACRO assembler name their code
+! Psect's "$CODE$".
+cluster = code_clust
+collect = code_clust,$CODE,$CODE$
diff --git a/sr_avms/error_return_vms.m64 b/sr_avms/error_return_vms.m64
new file mode 100644
index 0000000..76e9774
--- /dev/null
+++ b/sr_avms/error_return_vms.m64
@@ -0,0 +1,32 @@
+ .title ERROR_RETURN_VMS
+
+; ERROR_RETURN_VMS calls error_return (which doesn't return).
+;
+; entry:
+; r13 - address of ERROR_RETURN_VMS's procedure descriptor (not r27)
+;
+; WARNING: because ERROR_RETURN_VMS is designed to be invoked from a GT.M
+; MUMPS stack frame, it does not conform to the Alpha calling
+; standard and cannot be invoked from any high-level language.
+; The invoker should load the address of ERROR_RETURN_VMS's procedure
+; descriptor into r13, not r27.
+
+ g_msf
+
+ $linkage_section
+A_frame_pointer:
+ .address frame_pointer
+
+ $code_section
+
+ $routine ERROR_RETURN_VMS, entry=ERROR_RETURN_VMS_CA, kind=null
+ .base r13, $ls
+
+ mov r13, r27
+ $call error_return, set_arg_info=false, nonstandard=true
+ getframe
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/fetch_args.max b/sr_avms/fetch_args.max
new file mode 100644
index 0000000..00ac333
--- /dev/null
+++ b/sr_avms/fetch_args.max
@@ -0,0 +1,50 @@
+ .macro fetch_args sp_save_reg, stack_offset, ?loop, ?skip
+
+; This macro is used to call routine GTM_FETCH, passing a variable-length argument list
+; in which the first argument (i.e. R16) is the argument count. It moves the argument
+; count from R16 to the Argument Information register, R25, and then moves the remaining
+; arguments down one slot in the argument list. Since any arguments after the first six
+; would have been passed on the stack, it also must move these arguments from their
+; position above the current routine's save area to new slots below it.
+;
+; Arguments to this macro are:
+;
+; sp_save_reg : a register in which to save the current value of SP, and from
+; which SP will be restored when done. This register must be
+; one which is normally saved across routine calls, i.e. in the
+; range of R2 to R15.
+;
+; stack_offset : the size, in bytes, of the current routine's save area. This
+; value plus the current value of SP will be the address of the
+; first stacked argument.
+;
+; Registers R16 through R21 and R25 through R28 are modified by this macro.
+
+ mov r16, r25 ; argument count
+ mov r17, r16 ; arg1 (to GTM_FETCH)
+ mov r18, r17 ; arg2
+ mov r19, r18 ; arg3
+ mov r20, r19 ; arg4
+ mov r21, r20 ; arg5
+ ldq r21, stack_offset(sp) ; arg6 was on the stack
+
+ subq r25, 6, r28 ; r28 = the number of arguments left on the stack
+ mov sp, sp_save_reg ; save the current stack pointer
+ ble r28, skip ; skip if no arguments left
+
+ sll r28, 3, r27 ; r27 = the number of arguments to move, times 8 bytes
+ addq r27, stack_offset, r27 ; account for the saved registers
+ addq r27, sp, r27 ; r27 -> ArgN
+loop:
+ ldq r26, (r27)
+ lda sp, -8(sp)
+ lda r27, -8(r27)
+ subq r28, 1, r28
+ stq r26, (sp)
+ bgt r28, loop
+
+skip: $call gtm_fetch, set_arg_info=false, nonstandard=true
+
+ mov sp_save_reg, sp ; restore the stack
+
+ .endm fetch_args
diff --git a/sr_avms/fgncal_dispatch.m64 b/sr_avms/fgncal_dispatch.m64
new file mode 100644
index 0000000..66386b2
--- /dev/null
+++ b/sr_avms/fgncal_dispatch.m64
@@ -0,0 +1,1108 @@
+ .title fgncal_dispatch
+
+
+ G_MSF
+ base_frame
+
+
+; Syntax codes.
+syn0 = 0 ; no mode argument (gtm$xecute)
+syn1 = 1 ; mode is in position 1, counting from 0 (gtm$lock)
+syn2 = 3 ; mode is in position 0, counting from 0 (gtm$get)
+syn3 = 4 ; mode is in position 2, counting from 0 (gtm$lock2)
+
+; Stack offsets and related information.
+
+; Locals.
+SAVE_R13 = GTM_LOCAL_1
+
+
+ $linkage_section
+
+A_active_lv: .address active_lv
+
+A_FGNCAL_CH: .address FGNCAL_CH
+A_fgncal_stack: .address fgncal_stack
+A_fgncal_rtn: .address fgncal_rtn
+A_frame_pointer: .address frame_pointer
+
+A_literal_null: .address literal_null
+A_mdb_condition_handler:.address mdb_condition_handler
+A_msp: .address msp
+A_mumps_status: .address mumps_status
+A_stringpool: .address stringpool
+A_xfer_table: .address xfer_table
+A_dollar_zstatus: .address dollar_zstatus
+
+L_ERR_IFBADPARM: .long ERR_IFBADPARM
+L_ERR_IFNOTINIT: .long ERR_IFNOTINIT
+L_ERR_LCKSTIMOUT: .long ERR_LCKSTIMOUT
+L_ERR_ORDER2: .long ERR_ORDER2
+L_ERR_VAREXPECTED: .long ERR_VAREXPECTED
+
+Q_gtmi$_extgbl: .quad gtmi$_extgbl
+Q_gtmi$_extlcl: .quad gtmi$_extlcl
+Q_gtmi$_global: .quad gtmi$_global
+Q_gtmi$_local: .quad gtmi$_local
+Q_gtmi$_naked: .quad gtmi$_naked
+
+; Strictly speaking, no_timeout should be in the data section,
+; but it'll work here and save a base register.
+no_timeout: .long ^X0007fffe
+
+
+
+;
+ .macro fgncal_entry name, syn, fk, dst, ?A
+
+ $routine name, entry=%string(name)_CA, kind=stack, -
+ saved_regs=<%string(base_frame_regs)>, -
+ rsa_offset=RSA_OFFSET, size=STACK_SIZE, -
+ standard_prologue=false, handler=GTM$DYN_CH, synch_exceptions=true
+
+
+ .if ne,$SIZE,STACK_SIZE
+ .error "The stack frame size computed by $routine (%integer($SIZE)) differs from that expected -
+(%integer(STACK_SIZE))."
+ .endc
+
+ .if ne,$SIZE-56,ARG_OFFSET
+ .error "The homed argument list offset computed by $routine (%integer($SIZE-56)) differs from -
+that expected (%integer(ARG_OFFSET))."
+ .endc
+
+ create_base_frame
+
+ mov r27, r13 ; establish local base register
+ .base r13, $ls
+
+ ldq r28, A_stringpool
+ ldl r28, (r28)
+ bne r28, A ; if stringpool.base == 0, not initialized yet
+ $call lib$signal, args=<L_ERR_IFNOTINIT/L>
+ $return
+
+A: ldq r28, A_FGNCAL_CH
+ stq r28, 8(fp) ; establish fgncal_ch as condition handler
+ lda r2, syn(r31)
+ lda r5, dst(r31) ; [Vinaya 10/30/2002] see note about dst in fgncal_procarg
+ lda r7, fk(r31)
+ ldq r28, A_mumps_status
+ lda r22, 1(r31)
+ stl r22, (r28)
+ ldq r23, A_msp
+ ldq r24, A_fgncal_stack
+ ldl r23, (r23)
+ stl r23, (r24)
+
+ .endm
+
+
+; fgncal_old provides an interface between old DAL entry points
+; and new ones. The old version used separate names for the global
+; and local versions of each function, while the new version uses
+; the same name for both. fgncal_old creates dummy procedures that
+; reset the link register and transfer execution to the new entry
+; point.
+;
+; arguments:
+; newname - name of new entry point
+; gname - name of old global entry point
+; lname - name of old local entry point
+
+ .macro fgncal_old newname, gname, lname
+
+ $linkage_section
+
+L_'newname: .linkage_pair newname
+
+
+ $routine gname, entry=%string(gname)_CA, kind=null
+
+ .base r27, $ls
+
+ ldq r28, L_'newname ; N.B. don't modify r26
+ ldq r27, L_'newname+8
+ jmp r28 ; jump to name as if it were the entry point invoked
+
+ $end_routine name=gname
+
+
+ $routine lname, entry=%string(lname)_CA, kind=null
+
+ .base r27, $ls
+
+ ldq r28, L_'newname ; N.B. don't modify r26
+ ldq r27, L_'newname+8
+ jmp r28 ; jump to name as if it were the entry point invoked
+
+ $end_routine name=lname
+
+ .endm
+
+
+; calls mimics the VAX calls instruction. It assumes all of
+; the arguments to the routine to be called are on the stack.
+; First, it copies the top 6 stack values to argument registers
+; and pops the top 6 (or fewer, if fewer arguments) off the
+; stack. After the call, it further adjusts the stack by
+; removing any arguments after the first six.
+;
+; Arguments:
+; args - number of arguments, must be either a saved
+; register or an integer expression
+; routine - routine to be called
+
+ .macro calls args, routine
+
+; Move arguments from stack to registers.
+ mov args, r25
+ ldq r16, (sp)
+ ldq r17, 8(sp)
+ ldq r18, 16(sp)
+ ldq r19, 24(sp)
+ ldq r20, 32(sp)
+ ldq r21, 40(sp)
+
+; Adjust stack for arguments moved to registers.
+ lda r22, 6(r31)
+ subq r22, args, r28
+ cmovgt r28, args, r22 ; lesser of 6, actual number of arguments
+ s8addq r22, sp, sp ; pop stack accordingly
+
+ $call routine, set_arg_info=false, nonstandard=true
+
+; If more than 6 arguments; remove rest from stack.
+ mov args, r28
+ subq r28, 6, r28
+ cmovlt r28, r31, r28 ; number of arguments not in registers
+ s8addq r28, sp, sp ; adjust stack
+
+ .endm
+
+
+ .macro bind sbc, mode, ?A, ?B, ?C, ?D, ?E, ?F, ?G
+
+ ldq r28, Q_gtmi$_global
+ subq mode, r28, r28
+ beq r28, B
+
+ ldq r28, Q_gtmi$_extgbl
+ subq mode, r28, r28
+ beq r28, D
+
+ ldq r28, Q_gtmi$_local
+ subq mode, r28, r28
+ beq r28, A
+
+ ldq r28, Q_gtmi$_extlcl
+ subq mode, r28, r28
+ beq r28, C
+
+F: br bparm ; unknown mode
+
+C: ; extlcl
+ subq sbc, 2, r28
+ blt r28, F ; too few args
+ ldq mode, (sp)
+ br G
+
+D: ; extgbl
+ subq sbc, 2, r28
+ blt r28, F ; too few args
+ ldq mode, (sp)
+
+; NOTE: The VAX instruction is "calls #0,fgn_glopref" which will not affect
+; the caller's stack and requires the callee to handle its arguments properly.
+; Consequently, we make no stack adjustment after the call here.
+ $call fgn_glopref, args=<8(sp)/Q>, nonstandard=true
+G: stq r31, (sp) ; add 2nd env arg
+ subq sp, 8, sp
+ stq mode, (sp)
+ br E
+
+B: ; global
+; NOTE: The VAX instruction is "calls #0,fgn_glopref" which will not affect
+; the caller's stack and requires the callee to handle its arguments properly.
+; Consequently, we make no stack adjustment after the call here.
+ $call fgn_glopref, args=<0(sp)/Q>, nonstandard=true
+A: subq sp, 8, sp
+ stq r31, (sp)
+E: addq sbc, 1, sbc
+
+; Move arguments to registers and set up stack properly.
+ mov sbc, r25
+ ldq r16, (sp)
+ ldq r17, 8(sp)
+ ldq r18, 16(sp)
+ ldq r19, 24(sp)
+ ldq r20, 32(sp)
+ ldq r21, 40(sp)
+ lda r22, 6(r31) ; number of arguments in registers
+ subq sbc, r22, r28
+ cmovlt r28, sbc, r22 ; lesser of 6, actual number of arguments
+ s8addq r22, sp, sp ; pop register arguments off stack
+ $call op_lkname, set_arg_info=false, nonstandard=true
+ subq sbc, 6, r28
+ cmovlt r28, r31, r28 ; number of arguments not in registers
+ s8addq r28, sp, sp ; pop rest off stack
+ mov r31, sbc
+
+ .endm
+
+
+; fgncal_procarg is called at the beginning of each gtm$ fgncal_entry
+; routine to verify and process input arguments.
+;
+; Entry:
+; r2 - syntax code (syn)
+; r5 - # of output arguments [Vinaya 10/30/2002] see note about dst below
+; r7 - position of first key (fk), minimum # of arguments
+;
+; [Vinaya 10/30/2002] Note about dst. The role of this argument is not clear (to me).
+; Note that this argument is 2 for gtm$data (and other functions
+; that return a value) whereas $data returns only 1 result,
+; i.e., there is only 1 destination argument. Also, $put doesn't
+; provide any result, it takes input from arg in position 1
+; (counting from 0). In the below code, dst argument doesn't seem
+; to be used, and doesn't appear to be stored by fgncal_procarg
+; (in register or stack) for future use. I believe we could use
+; this argument during argument processing.
+;
+; Exit:
+; r0 - if local, pointer to lv_val -ret
+; r2 - syntax code (syn)
+; r3 - # of input arguments, # of subscripts
+; r4 - return address of caller
+; r5 - address of local name
+; r6 - current key descriptor (b.j), mode -ret
+; r7 - position of first key (fk), minimum # of arguments
+; r8 - current arg in r25 (n)
+; stack - sequence of &mval
+
+
+ $routine name=fgncal_procarg, entry=fgncal_procarg_ca, kind=null, local=true
+
+ stq r13, SAVE_R13(fp)
+ mov r27, r13
+ .base r13, $ls
+
+ mov r26, r4 ; save return address
+ ldq r8, ARG_OFFSET(fp) ; n = ac
+ subq r8, r7, r28 ; compare minimum # of arguments
+ bge r28, 0$
+ br bparm ; too few
+
+0$: bne r8, 15$ ; any args?
+ subq r2, syn1, r28 ; might be a lock with no timeout
+ bne r28, 12$
+ ldl r28, no_timeout
+ subq sp, 8, sp
+ stq r28, (sp)
+12$: br fgncal_procarg_ret
+
+15$: mov r31, r3 ; argument count
+
+20$: ; loop top
+ lda r6, ARG_OFFSET(fp)
+ s8addq r8, r6, r6
+ ldq r6, (r6) ; r6 = b.n
+ ldq r28, Q_gtmi$_extlcl ; highest-valued mode
+ subq r6, r28, r28
+ ble r28, 22$ ; is it a mode?
+ br 23$
+
+22$: ldq r28, Q_gtmi$_global ; lowest-valued mode
+ subq r6, r28, r28
+ bge r28, 24$ ; it is a mode
+
+23$: ; It's not a mode.
+ $call push_mval, args=<A_literal_null>, nonstandard=true
+ subq sp, 8, sp
+ stq r0, (sp) ; pointer to mval used by op_xxname (accumulate on the stack)
+ mov r0, r17 ; destination for conversion
+ mov r6, r16 ; source descriptor
+ $call desc2mval, args=<r16, r17>, nonstandard=true ; convert descriptor to mval
+ addq r3, 1, r3
+ subq r8, 1, r8
+ subq r8, r7, r28 ; n - fk cnt, bnd
+ bge r28, 20$ ; more arguments left
+ br pfin ; n == fk
+
+24$: ; It's a mode.
+ subq r2, syn1, r28
+ beq r28, 25$
+ subq r2, syn3, r28
+ beq r28, 25$
+ br bparm ; mode before done, but not a lock
+
+25$: bne r3, 27$ ; any args?
+ subq r8, r7, r28 ; n - fk
+ bne r28, bparm ; should be done
+ subq r8, 1, r8
+ br pfin ; n == fk
+
+27$: bind r3, r6 ; bind.(k, nf, mode)
+ subq r8, 1, r8
+ subq r8, r7, r28 ; n - fk cnt, bnd
+ ble r28, pfin ; n == fk
+ lda r6, ARG_OFFSET(fp)
+ s8addq r8, r6, r6
+ ldq r6, (r6) ; r6 = b.n
+ bne r6, bparm ; should be 0 delimiter between arguments
+ subq r8, 1, r8
+ subq r8, r7, r28 ; n - fk cnt, bnd
+ beq r28, bparm ; should be more to do
+ br 20$
+
+bparm: $call lib$signal, args=<L_ERR_IFBADPARM/L>, nonstandard=true
+ br fgncal_procarg_ret
+
+pfin: ; procarg wrap up
+ subq r2, syn2, r28
+ beq r28, 50$
+ subq r2, syn1, r28
+ beq r28, 30$
+ subq r2, syn0, r28
+ beq r28, 40$
+ lda r28, ARG_OFFSET(fp)
+ s8addq r8, r28, r28
+ ldq r28, (r28)
+ subq sp, 8, sp
+ stq r28, (sp) ; auxowner
+ subq r8, 1, r8
+30$: beq r8, 35$
+ subq r8, 1, r28
+ beq r28, 33$
+ br bparm ; should be down to timeout in position 0, counting from 0
+
+33$: lda r6, ARG_OFFSET(fp)
+ s8addq r8, r6, r6
+ ldq r6, (r6) ; timeout
+ blt r6, 35$
+ subq sp, 8, sp
+ stq r6, (sp)
+ br 40$
+
+35$: ldl r0, no_timeout
+ subq sp, 8, sp
+ stq r0, (sp)
+40$: br fgncal_procarg_ret
+
+50$: subq r3, 1, r28
+ blt r28, bparm ; should have at least one arg
+ ldq r6, ARG_OFFSET+8(fp)
+ ldq r28, Q_gtmi$_global
+ subq r6, r28, r28
+ bne r28, 60$
+ calls r3, op_gvname
+ br fgncal_procarg_ret
+
+60$: ldq r28, Q_gtmi$_naked
+ subq r6, r28, r28
+ bne r28, 70$
+ calls r3, op_gvnaked
+ br fgncal_procarg_ret
+
+70$: ldq r28, Q_gtmi$_extgbl
+ subq r6, r28, r28
+ bne r28, 90$
+ subq r3, 2, r28
+ blt r28, bparm ; extended globals need at least 2 args
+ ldq r1, (sp) ; put new second parameter in for extnam
+ ldq r28, A_literal_null ; second param for extnam is "" string
+ stq r28, (sp)
+ subq sp, 8, sp
+ stq r1, (sp)
+ addq r3, 1, r3
+ calls r3, op_gvextnam
+ br fgncal_procarg_ret
+
+90$: ldq r28, Q_gtmi$_local
+ subq r6, r28, r28
+ bne r28, 95$
+ ldq r5, (sp)
+ $call fgncal_lookup, args=<r5>, nonstandard=true
+ addq sp, 8, sp
+ beq r0, 100$
+ subq sp, 8, sp
+ stq r0, (sp)
+ br fgncal_procarg_ret
+
+95$: br bparm ; unknown mode
+
+100$: $call lib$signal, args=<L_ERR_VAREXPECTED/L>, nonstandard=true
+ br fgncal_procarg_ret
+
+fgncal_procarg_ret:
+ ldq r13, SAVE_R13(fp)
+ ret r4
+
+ $end_routine name=fgncal_procarg
+
+
+; fgncal_dispget sets up a destination mval and calls the op_ routine whose
+; address is in r2.
+;
+; entry:
+; r2 - address of routine to call
+;
+; exit:
+; to fgncal_lclfini
+
+ $routine fgncal_dispget, entry=fgncal_dispget_ca, kind=null, local=true
+
+ mov r27, r13
+ .base r13, $ls
+
+ $call push_mval, args=<A_literal_null>, nonstandard=true ; prepare a destination
+ mov r0, r4 ; save for fgncal_lclfini
+
+; $call (r2), args=<r0> ; do the real thing
+ mov r0, r16
+ lda r25, 1(r31)
+ mov r2, r27
+ ldq r26, 8(r27)
+ jsr r26, (r26)
+
+ $call fgncal_lclfini, set_arg_info=false, local=true, nonstandard=true
+; doesn't return
+
+ $end_routine name=fgncal_dispget
+
+
+; fgncal_lclfini converts that to which r4 points from mval format to descriptor format.
+;
+; entry:
+; r4 - pointer to mval
+;
+; exit:
+; caller's second argument - descriptor created from mval
+
+ $routine fgncal_lclfini, entry=fgncal_lclfini_ca, kind=null, local=true
+
+ mov r27, r13
+ .base R13, $ls
+
+ $call mval2desc, args=<r4, ARG_OFFSET+16(fp)/Q>, nonstandard=true ; convert it for caller
+
+ $call fgncal_dispret, set_arg_info=false, local=true, nonstandard=true
+; doesn't return
+
+ $end_routine name=fgncal_lclfini
+
+
+; fgncal_dispret cleans up the fgncal stack and returns to the foreign caller.
+; This is the routine that returns from the stack frame created by fgncal_entry.
+
+ $routine fgncal_dispret, entry=fgncal_dispret_ca, kind=stack, local=true, -
+ saved_regs=<%string(base_frame_regs)>, -
+ rsa_offset=RSA_OFFSET, size=STACK_SIZE, -
+ standard_prologue=false, handler=GTM$DYN_CH, synch_exceptions=true
+
+; Since fgncal_dispret executes in and returns from the stack frame set up by
+; fgncal_entry, it need not set up its own stack frame although it needs to declare
+; one for the $return macro to work properly.
+
+ $end_prologue
+
+ mov r27, r13
+ .base r13, $ls
+
+ $call fgncal_unwind, set_arg_info=false, nonstandard=true
+ ldq r28, A_mumps_status
+ ldl r0, (r28)
+
+ $return ; to foreign caller
+
+ $end_routine name=fgncal_dispret
+
+
+ fgncal_entry gtm$get, syn2, 3, 2
+
+ $linkage_section
+
+A_op_gvget: .address op_gvget
+
+
+ $code_section
+
+ $call fgncal_procarg, set_arg_info=false, local=true
+ ldq r28, Q_gtmi$_local
+ subq r6, r28, r28
+ beq r28, 1$
+ ldq r2, A_op_gvget
+ $call fgncal_dispget, set_arg_info=false, local=true
+ ; doesn't return
+
+1$: subq r3, 1, r28
+ beq r28, 10$
+ calls r3, op_getindx
+10$: mov r0, r4
+ $call fgncal_lclfini, set_arg_info=false, local=true
+ ; doesn't return
+
+ $end_routine name=gtm$get
+
+ fgncal_old gtm$get, gtm$gblget, gtm$lclget
+
+
+ fgncal_entry gtm$put, syn2, 3, 2
+
+ $call fgncal_procarg, set_arg_info=false, local=true
+ $call push_mval, args=<A_literal_null> ; convert value assigned
+ mov r0, r4
+ $call desc2mval, args=<ARG_OFFSET+16(fp)/Q, r4>
+ ldq r28, Q_gtmi$_local
+ subq r6, r28, r28
+ beq r28, 1$
+ $call op_gvput, args=<r4>
+ $call fgncal_dispret, set_arg_info=false, local=true
+ ; doesn't return
+
+1$: ldq r0, (sp) ; local
+ subq r3, 1, r28
+ beq r28, 10$
+ calls r3, op_putindx
+10$: ldl r16, (r4)
+ ldl r17, 4(r4)
+ ldl r18, 8(r4)
+ ldl r19, 12(r4)
+ ldl r20, 16(r4)
+ stl r16, (r0)
+ stl r17, 4(r0)
+ stl r18, 8(r0)
+ stl r19, 12(r0)
+ stl r20, 16(r0)
+ ldq r28, A_active_lv
+ stl r31, (r28)
+ $call fgncal_dispret, set_arg_info=false, local=true
+ ; doesn't return
+
+ $end_routine name=gtm$put
+
+ fgncal_old gtm$put, gtm$gblput, gtm$lclput
+
+
+ fgncal_entry gtm$kill, syn2, 2, 0
+
+ $call fgncal_procarg, set_arg_info=false, local=true
+ ldq r28, Q_gtmi$_local
+ subq r6, r28, r28
+ beq r28, 1$
+ $call op_gvkill, args=<>
+ $call fgncal_dispret, set_arg_info=false, local=true
+ ; doesn't return
+
+1$: subq r3, 1, r28
+ beq r28, 10$
+ calls r3, op_srchindx
+ subq sp, 8, sp
+ stq r0, (sp)
+10$: calls 1, op_kill
+ $call fgncal_dispret, set_arg_info=false, local=true
+ ; doesn't return
+
+ $end_routine name=gtm$kill
+
+ fgncal_old gtm$kill, gtm$gblkill, gtm$lclkill
+
+
+ fgncal_entry gtm$withdraw, syn2, 2, 0
+
+ $call fgncal_procarg, set_arg_info=false, local=true
+ ldq r28, Q_gtmi$_local
+ subq r6, r28, r28
+ beq r28, 1$
+ $call op_gvzwithdraw, args=<>
+ $call fgncal_dispret, set_arg_info=false, local=true
+ ; doesn't return
+
+1$: subq r3, 1, r28
+ beq r28, 10$
+ calls r3, op_srchindx
+ subq sp, 8, sp
+ stq r0, (sp)
+10$: calls 1, op_lvzwithdraw
+ $call fgncal_dispret, set_arg_info=false, local=true
+ ; doesn't return
+
+ $end_routine name=gtm$withdraw
+
+ fgncal_old gtm$withdraw, gtm$gblwithdraw, gtm$lclwithdraw
+
+ $routine gtm$zkill, entry=gtm$zkill_CA, kind=null
+
+ .base r27, $ls
+
+ ldq r28, L_gtm$withdraw ; defined by previous fgncal_old macro invocation
+ ldq r27, L_gtm$withdraw+8
+ jmp r28
+
+ $end_routine name=gtm$zkill
+
+
+ fgncal_entry gtm$data, syn2, 3, 2
+
+ $linkage_section
+
+A_op_gvdata: .address op_gvdata
+
+
+ $code_section
+
+ $call fgncal_procarg, set_arg_info=false, local=true
+ ldq r28, Q_gtmi$_local
+ subq r6, r28, r28
+ beq r28, 1$
+ ldq r2, A_op_gvdata
+ $call fgncal_dispget, set_arg_info=false, local=true
+ ; doesn't return
+
+1$: subq r3, 1, r28
+ beq r28, 10$
+ calls r3, op_srchindx
+ subq sp, 8, sp
+ stq r0, (sp)
+10$: $call push_mval, args=<A_literal_null>
+ mov r0, r4
+ ldq r0, (sp)
+ addq sp, 8, sp
+ mov r4, r17 ; put return mval underneath lv_val
+ mov r0, r16
+ $call op_fndata, args=<r16, r17>
+ $call fgncal_lclfini, set_arg_info=false, local=true
+ ; doesn't return
+
+ $end_routine name=gtm$data
+
+ fgncal_old gtm$data, gtm$gbldata, gtm$lcldata
+
+
+ fgncal_entry gtm$order, syn2, 4, 2
+
+ $linkage_section
+
+A_op_gvorder: .address op_gvorder
+
+
+ $code_section
+
+ $call fgncal_procarg, set_arg_info=false, local=true
+ ldq r1, ARG_OFFSET+24(fp) ; direction argument
+ addq r1, 1, r28
+ beq r28, 0$ ; -1
+ subq r1, 1, r28
+ beq r28, 1$ ; 1
+ $call lib$signal, args=<L_ERR_ORDER2/L> ; second order arg must be -1 or 1
+ ; shouldn't return
+
+0$: $call prev, set_arg_info=false, local=true ; based on direction, jump to zprevious
+ ; shouldn't return
+
+1$: $call order, set_arg_info=false, local=true
+ ; shouldn't return
+
+ $end_routine name=gtm$order
+
+
+ $routine order, entry=order_ca, kind=null, local=true
+
+ mov r27, r13
+ .base r13, $ls
+
+ ldq r28, Q_gtmi$_local
+ subq r6, r28, r28
+ beq r28, 1$
+ ldq r2, A_op_gvorder
+ $call fgncal_dispget, set_arg_info=false, local=true, nonstandard=true
+ ; doesn't return
+
+1$: $call push_mval, args=<A_literal_null>, nonstandard=true
+ mov r0, r4
+ subq r3, 1, r3
+ beq r3, 10$
+ subq r3, 1, r28
+ beq r28, 20$
+ calls r3, op_srchindx
+ subq sp, 8, sp
+ stq r0, (sp)
+ br 20$
+
+10$: addq sp, 8, sp
+ $call op_fnlvname, args=<r5, r31, r4>, nonstandard=true
+ $call fgncal_lclfini, set_arg_info=false, local=true, nonstandard=true
+ ; doesn't return
+
+20$: ldq r0, (sp) ; put dst under src and key arguments
+ ldq r1, 8(sp)
+ addq sp, 16, sp
+ mov r0, r16
+ mov r1, r17
+ mov r4, r18
+ $call op_fnorder, args=<r16, r17, r18>, nonstandard=true
+ $call fgncal_lclfini, set_arg_info=false, local=true, nonstandard=true
+ ; doesn't return
+
+ $end_routine name=order
+
+
+ fgncal_entry gtm$gblorder, syn2, 3, 2
+
+ $call fgncal_procarg, set_arg_info=false, local=true
+ $call order, set_arg_info=false, local=true
+ ; doesn't return
+
+ $end_routine name=gtm$gblorder
+
+
+ $routine gtm$lclorder, entry=gtm$lclorder_ca, kind=null
+
+ $linkage_section
+
+L_gtm$gblorder: .linkage_pair gtm$gblorder
+
+
+ $code_section
+
+ .base r27, $ls
+
+ ldq r28, L_gtm$gblorder ; N.B. don't modify r26
+ ldq r27, L_gtm$gblorder+8
+ jmp r28 ; jump to gtm$gblorder as if it were the entry point invoked
+
+ $end_routine name=gtm$lclorder
+
+
+ fgncal_entry gtm$previous, syn2, 3, 2
+
+ $linkage_section
+
+A_op_zprevious: .address op_zprevious
+
+
+ $code_section
+
+ $call fgncal_procarg, set_arg_info=false, local=true
+ $call prev, set_arg_info=false, local=true
+ ; shouldn't return
+
+ $end_routine name=gtm$previous
+
+
+ $routine prev, entry=prev_ca, kind=null, local=true
+
+ mov r27, r13
+ .base r13, $ls
+
+ ldq r28, Q_gtmi$_local
+ subq r6, r28, r28
+ beq r28, 1$
+ ldq r2, A_op_zprevious
+ $call fgncal_dispget, set_arg_info=false, nonstandard=true
+ ; doesn't return
+
+1$: $call push_mval, args=<A_literal_null>, nonstandard=true
+ mov r0, r4
+ subq r3, 1, r3
+ beq r3, 10$
+ subq r3, 1, r28
+ beq r28, 20$
+ calls r3, op_srchindx
+ subq sp, 8, sp
+ stq r0, (sp)
+ br 20$
+
+10$: addq sp, 8, sp
+ $call op_fnlvprvname, args=<r5, r4>, nonstandard=true ; put return mval underneath lv name
+ $call fgncal_lclfini, set_arg_info=false, local=true, nonstandard=true
+ ; doesn't return
+
+20$: ldq r0, (sp) ; put dst under src and key arguments
+ ldq r1, 8(sp)
+ addq sp, 16, sp
+ mov r0, r16
+ mov r1, r17
+ $call op_fnzprevious, args=<r16, r17, r4>, nonstandard=true
+ $call fgncal_lclfini, set_arg_info=false, local=true, nonstandard=true
+ ; doesn't return
+
+ $end_routine name=prev
+
+ fgncal_old gtm$previous, gtm$gblprevious, gtm$lclprevious
+
+
+ fgncal_entry gtm$query, syn2, 3, 2
+
+ $linkage_section
+
+A_op_gvquery: .address op_gvquery
+
+
+ $code_section
+
+ $call fgncal_procarg, set_arg_info=false, local=true
+ ldq r28, Q_gtmi$_local
+ subq r6, r28, r28
+ beq r28, 1$
+ ldq r2, A_op_gvquery
+ $call fgncal_dispget, set_arg_info=false, local=true
+ ; doesn't return
+
+1$: subq sp, 8, sp
+ stq r5, (sp)
+ $call push_mval, args=<A_literal_null>
+ mov r0, r4
+ subq sp, 8, sp
+ stq r0, (sp)
+ addq r3, 2, r3
+ calls r3, op_fnquery
+ $call fgncal_lclfini, set_arg_info=false, local=true
+ ; doesn't return
+
+ $end_routine name=gtm$query
+
+ fgncal_old gtm$query, gtm$gblquery, gtm$lclquery
+
+
+ fgncal_entry gtm$gblnext, syn2, 3, 2
+
+ $linkage_section
+
+A_op_gvnext: .address op_gvnext
+
+
+ $code_section
+
+ $call fgncal_procarg, set_arg_info=false, local=true
+ ldq r2, A_op_gvnext
+ $call fgncal_dispget, set_arg_info=false, local=true
+ ; doesn't return
+
+ $end_routine name=gtm$gblnext
+
+
+
+ ; NOTE: For lock transactions, the mode is considered part of the key,
+ ; since there can be multiple keys in a lock transaction.
+ ;
+
+
+ fgncal_entry gtm$lock, syn1, 2, 0
+
+ $call op_unlock, args=<>
+ ldq r0, ARG_OFFSET(fp)
+ and r0, ^Xff, r0 ; number of original arguments
+ bne r0, 100$
+ $call fgncal_dispret, set_arg_info=false, local=true
+ ; doesn't return
+
+100$: $call op_lkinit, args=<>
+ $call fgncal_procarg, set_arg_info=false, local=true
+ ldq r16, (sp)
+ addq sp, 8, sp
+ $call op_lock, args=<r16>
+ subq r0, 1, r28
+ beq r28, 110$
+ ldl r22, L_ERR_LCKSTIMOUT
+ ldq r23, A_mumps_status
+ stl r22, (r23)
+110$: $call fgncal_dispret, set_arg_info=false, local=true
+ ; doesn't return
+
+ $end_routine name=gtm$lock
+
+
+ fgncal_entry gtm$inclock, syn1, 2, 0
+
+ $call op_lkinit, args=<>
+ $call fgncal_procarg, set_arg_info=false, local=true
+ ldq r16, (sp)
+ addq sp, 8, sp
+ $call op_incrlock, args=<r16>
+ subq r0, 1, r28
+ beq r28, 111$
+ ldl r22, L_ERR_LCKSTIMOUT
+ ldq r23, A_mumps_status
+ stl r22, (r23)
+111$: $call fgncal_dispret, set_arg_info=false, local=true
+ ; doesn't return
+
+ $end_routine name=gtm$inclock
+
+
+ fgncal_entry gtm$declock, syn1, 1, 0
+
+ $call op_lkinit, args=<>
+ $call fgncal_procarg, set_arg_info=false, local=true
+ ldq r16, (sp)
+ addq sp, 8, sp
+ $call op_decrlock, args=<r16>
+ $call fgncal_dispret, set_arg_info=false, local=true
+ ; doesn't return
+
+ $end_routine name=gtm$declock
+
+
+ fgncal_entry gtm$zalloc, syn1, 2, 0
+
+ $call op_lkinit, args=<>
+ $call fgncal_procarg, set_arg_info=false, local=true
+ ldq r16, (sp)
+ addq sp, 8, sp
+ $call op_zallocate, args=<r16>
+ subq r0, 1, r28
+ beq r28, 112$
+ ldl r22, L_ERR_LCKSTIMOUT
+ ldq r23, A_mumps_status
+ stl r22, (r23)
+112$: $call fgncal_dispret, set_arg_info=false, local=true
+ ; doesn't return
+
+ $end_routine name=gtm$zalloc
+
+
+ fgncal_entry gtm$zdealloc, syn1, 1, 0
+
+ $call op_lkinit, args=<>
+ $call fgncal_procarg, set_arg_info=false, local=true
+ ldq r16, (sp)
+ addq sp, 8, sp
+ $call op_zdeallocate, args=<r16>
+ $call fgncal_dispret, set_arg_info=false, local=true
+ ; doesn't return
+
+ $end_routine name=gtm$zdealloc
+
+
+ fgncal_entry gtm$lock2, syn3, 3, 0
+
+ $call op_lkinit, args=<>
+ $call fgncal_procarg, set_arg_info=false, local=true
+ ldq r16, (sp)
+ ldq r17, 8(sp)
+ addq sp, 16, sp
+ $call op_lock2, args=<r16, r17>
+ subq r0, 1, r28
+ beq r28, 113$
+ ldl r22, L_ERR_LCKSTIMOUT
+ ldq r23, A_mumps_status
+ stl r22, (r23)
+113$: $call fgncal_dispret, set_arg_info=false, local=true
+
+ $end_routine name=gtm$lock2
+
+
+ fgncal_entry gtm$zdealloc2, syn3, 2, 0
+
+ $call op_lkinit, args=<>
+ $call fgncal_procarg, set_arg_info=false, local=true
+ ldq r16, (sp)
+ ldq r17, 8(sp)
+ addq sp, 16, sp
+ $call op_zdealloc2, args=<r16, r17>
+ $call fgncal_dispret, set_arg_info=false, local=true
+ ; doesn't return
+
+ $end_routine name=gtm$zdealloc2
+
+
+ fgncal_entry gtm$setgbldir, syn0, 1, 0
+
+ $call fgncal_procarg, set_arg_info=false, local=true
+ ldq r17, (sp)
+ addq sp, 8, sp
+ lda r16, 22(r31)
+ $call op_svput, args=<r16, r17>
+ $call fgncal_dispret, set_arg_info=false, local=true
+ ; doesn't return
+
+ $end_routine name=gtm$setgbldir
+
+
+ fgncal_entry gtm$ztstart, syn0, 0, 0
+
+ $call op_ztstart, args=<>
+ $call fgncal_dispret, set_arg_info=false, local=true
+ ; doesn't return
+
+ $end_routine name=gtm$ztstart
+
+
+ fgncal_entry gtm$ztcommit, syn0, 1, 0
+
+ ldq r28, ARG_OFFSET(fp)
+ subq r28, r7, r28
+ bge r28, 10$
+ br bparm
+
+10$: $call op_ztcommit, args=<ARG_OFFSET+8(fp)/Q>
+ $call fgncal_dispret, set_arg_info=false, local=true
+ ; doesn't return
+
+ $end_routine name=gtm$ztcommit
+
+
+ fgncal_entry gtm$mval2subsc, syn0, 2, 0
+
+ ldq r28, ARG_OFFSET(fp)
+ subq r28, r7, r28
+ bge r28, 10$
+ br bparm
+
+10$: $call mval2subsc, args=<ARG_OFFSET+8(fp)/Q, ARG_OFFSET+16(fp)/Q>
+ $call fgncal_dispret, set_arg_info=false, local=true
+ ; doesn't return
+
+ $end_routine name=gtm$mval2subsc
+
+
+ fgncal_entry gtm$rundown, syn0, 0, 0
+
+ $call fgncal_rundown, args=<>
+ $call fgncal_dispret, set_arg_info=false, local=true
+ ; doesn't return
+
+ $end_routine name=gtm$rundown
+
+
+ fgncal_entry gtm$xecute, syn0, 1, 0
+
+ ldq r28, ARG_OFFSET(fp)
+ subq r28, r7, r28
+ bge r28, 10$
+ br bparm
+
+10$: ldq r11, A_xfer_table
+ ldq r10, A_fgncal_rtn ; procedure descriptor
+ ldq r10, 8(r10) ; entry point from procedure descriptor (=> routine header)
+ $call base_frame, args=<r10>
+ $call new_stack_frame, args=<r10, mrt$lnk_ptr(r10)/L, mrt$hdr_size(r10)/A>
+ $call gtm_savetraps, args=<>
+ $call fgncal_procarg, set_arg_info=false, local=true
+ ldq r16, (sp) ; string to execute
+ addq sp, 8, sp
+ lda r17, 19(r31) ; indir_linetail
+ $call op_commarg, args=<r16, r17>
+ ldq r28, A_mdb_condition_handler
+ stq r28, 8(fp) ; establish mdb_condition_handler as condition handler
+ getframe
+ imb
+ ret r26 ; it will go through gtm_ret_code on the way out
+
+ $end_routine name=gtm$xecute
+
+ fgncal_entry gtm$zstatus, syn0, 1, 0
+ ldq r28, ARG_OFFSET(fp)
+ subq r28, r7, r28
+ bge r28, 10$
+ br bparm
+
+10$: ldq r28, A_dollar_zstatus
+ $call mval2desc, args=<r28, ARG_OFFSET+8(fp)/Q>, nonstandard=true ; convert it for caller
+ $call fgncal_dispret, set_arg_info=false, local=true, nonstandard=true
+; doesn't return
+
+ $end_routine name=gtm$zstatus
+
+ .end
diff --git a/sr_avms/fgncal_rtn.m64 b/sr_avms/fgncal_rtn.m64
new file mode 100644
index 0000000..27fa710
--- /dev/null
+++ b/sr_avms/fgncal_rtn.m64
@@ -0,0 +1,136 @@
+ .title fgncal_rtn dummy routine header for gtm$xecute
+
+ G_MSF
+
+
+; The code PSECT must have the MIX attribute in order to contain data.
+$CODE$ = "FGNCAL_RTN,QUAD,PIC,CON,REL,LCL,SHR,EXE,RD,MIX,NOWRT"
+
+ $routine name=fgncal_rtn, entry=fgncal_rtn_ca, kind=stack, -
+ saved_regs=<r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, fp>, -
+ standard_prologue=false, data_section_pointer=true
+
+ $linkage_section
+L_ERR_GTMCHECK: .long ERR_GTMCHECK
+
+ $data_section
+literal_table: .asciz "$FGNXEC"
+
+ $code_section
+
+; This is a dummy GT.M routine header so this routine can be treated as if
+; it had been produced by the GT.M compiler (see rtnhdr.h).
+
+jsb: ; There should be no way to enter this code via the procedure descriptor
+ ; but use the jsb field to handle that if it happens.
+ lda sp, -$SIZE(sp)
+ stq r27, (sp)
+ br check ; jsb field full; finish this later
+
+ .if ne,<.-jsb>,mrt$src_len
+ .error "The dummy routine header jsb size is incorrect; please check it against g_msf.max."
+ .endc
+
+src_full_name:
+ .long 0 ; source file name length
+ address_32 0 ; source file name
+routine_name:
+ .long 7 ; routine name length (sizeof("$FGNXEC") - 1)
+ address_32 $ds ; routine name (dummy)
+vartab_ptr:
+ .long label_table - $cs ; variable table
+vartab_len:
+ .word 0 ; variable table length
+ .word 0 ; padding
+labtab_ptr:
+ .long label_table - $cs ; label table
+labtab_len:
+ .word 2 ; label table length
+ .word 0 ; padding
+lnrtab_ptr:
+ .long line_table - $cs ; line table
+lnrtab_len:
+ .word 1 ; line table length
+ .word 0 ; padding
+ptext_ptr:
+ .long fgncal_rtn_code - $cs ; pointer to start of actual code
+checksum:
+ .long 0
+compiler_qlf:
+ .long 0
+old_rhead_ptr:
+ address_32 0
+current_rhead_ptr:
+ address_32 0
+temp_mvals:
+ .word 0
+temp_size:
+ .word 0
+linkage_ptr:
+ address_32 $ls
+literal_ptr:
+ address_32 $ds
+
+; End of GT.M routine header.
+ .if ne,<.-jsb>,mrt$hdr_size
+ .error "The dummy routine header size is incorrect; please check it against g_msf.max."
+ .endc
+
+
+fgncal_rtn_code:
+ .base r13, $ls ; should be set up by getframe
+ $call opp_ret
+
+; opp_ret shouldn't return; if it does, we have an error
+ br check2 ; skip pseudo prologue
+
+check: ; It should never EVER be possible to execute this from the top (jsb).
+
+ ; First, finish the prologue begun in the jsb field (for debugging purposes)
+ stq r26, $RSA_OFFSET(sp)
+ stq r2, $RSA_OFFSET+8(sp)
+ stq r3, $RSA_OFFSET+16(sp)
+ stq r4, $RSA_OFFSET+24(sp)
+ stq r5, $RSA_OFFSET+32(sp)
+ stq r6, $RSA_OFFSET+48(sp)
+ stq r7, $RSA_OFFSET+56(sp)
+ stq r8, $RSA_OFFSET+64(sp)
+ stq r9, $RSA_OFFSET+72(sp)
+ stq r10, $RSA_OFFSET+80(sp)
+ stq r11, $RSA_OFFSET+88(sp)
+ stq r12, $RSA_OFFSET+96(sp)
+ stq r13, $RSA_OFFSET+104(sp)
+ stq r14, $RSA_OFFSET+112(sp)
+ stq r15, $RSA_OFFSET+120(sp)
+ stq fp, $RSA_OFFSET+128(sp)
+ mov sp, fp
+ $end_prologue
+
+; Set up base register r13 for either path to lib$signal call.
+ mov r27, r13
+ .base r13, $ls
+
+; Next, complain bitterly about the invalid invocation.
+check2: $call lib$signal, args=<L_ERR_GTMCHECK/L>
+
+; lib$signal should never return, but if it does, don't execute data:
+ $return
+
+
+; Standard variable (null), label, and line tables for end of GT.M object module.
+
+
+; Variable table would go here if there were one.
+
+label_table: ; initialize the lab_tabent entry
+ .long 0
+ address_32 0
+ .long lte - fgncal_rtn_ca
+
+line_table:
+ .long fgncal_rtn_code - fgncal_rtn_ca ; line 0
+lte: .long fgncal_rtn_code - fgncal_rtn_ca ; line 1
+
+ $end_routine name=fgncal_rtn
+
+ .end
diff --git a/sr_avms/find_line_call.c b/sr_avms/find_line_call.c
new file mode 100644
index 0000000..f60feb3
--- /dev/null
+++ b/sr_avms/find_line_call.c
@@ -0,0 +1,98 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "axp_registers.h"
+#include "axp_gtm_registers.h"
+#include "axp.h"
+#include "xfer_enum.h"
+#include <rtnhdr.h> /* Needed by zbreak.h */
+#include "zbreak.h"
+
+/* Numeric literals are pushed on the stack or loaded into argument registers with a combination of the following instructions: */
+#define PUSH_NUM_LIT1 (ALPHA_INS_LDAH)
+#define PUSH_NUM_LIT2 (ALPHA_INS_LDA)
+#define PUSH_NUM_LIT3 (ALPHA_INS_STQ | (GTM_REG_ACCUM << ALPHA_SHIFT_RA) | (ALPHA_REG_SP << ALPHA_SHIFT_RB))
+
+/* The first two instructions set up a procedure descriptor and transfer address; the third makes the call. */
+#define LOAD_XFER_ADDR1 (ALPHA_INS_LDL | (ALPHA_REG_PV << ALPHA_SHIFT_RA) | (GTM_REG_XFER_TABLE << ALPHA_SHIFT_RB))
+#define LOAD_XFER_ADDR2 (ALPHA_INS_LDQ | (ALPHA_REG_RA << ALPHA_SHIFT_RA) | (ALPHA_REG_PV << ALPHA_SHIFT_RB) \
+ | ((8 & ALPHA_MASK_DISP) << ALPHA_SHIFT_DISP))
+#define XFER_CALL (ALPHA_INS_JSR | (ALPHA_REG_RA << ALPHA_SHIFT_RA) | (ALPHA_REG_RA << ALPHA_SHIFT_RB))
+
+
+/* find_line_call searches through machine instructions starting at the address corresponding to the
+ * beginning of a MUMPS statement looking for a call to any of op_linestart, op_zbstart, op_linefetch,
+ * or op_zbfetch. It will return the address of the displacement field of the instruction that indexes
+ * to the desired runtime routine in order that its caller may examine or change that field.
+ *
+ * find_line_call will skip over any number of numeric literal arguments to op_linefetch or op_zbfetch
+ * in its search for one of the desired calls. If it doesn't find any, it will return the address of
+ * the offset field of the instruction to which addr points.
+ *
+ * entry
+ * addr address of beginning of MUMPS statement
+ *
+ * exit
+ * returns address of displacement field containing offset into the transfer table in the
+ * instruction that refers to the transfer table
+ */
+
+zb_code *find_line_call(void *addr)
+{
+ uint4 *call_addr;
+ uint4 *xfer_addr;
+ short xfer_offset;
+
+ call_addr = addr;
+ if ((LOAD_XFER_ADDR1 == (*call_addr & ~(ALPHA_MASK_DISP << ALPHA_SHIFT_DISP))) && (LOAD_XFER_ADDR2 == *(call_addr + 1)))
+ {
+ /* It's a transfer table load. */
+ xfer_addr = call_addr;
+ xfer_offset = (*xfer_addr >> ALPHA_SHIFT_DISP) & ALPHA_MASK_DISP;
+ call_addr += 2;
+ assert(XFER_CALL == *call_addr);
+ return ((zb_code *)addr);
+ }
+ /* Locate and skip over series of operand pushes. This is not rigorous, but should catch a series of
+ * numeric constant arguments:
+ */
+ xfer_addr = call_addr;
+ if ( (PUSH_NUM_LIT1 == (*call_addr & (ALPHA_MASK_OP << ALPHA_SHIFT_OP)))
+ || (PUSH_NUM_LIT2 == (*call_addr & (ALPHA_MASK_OP << ALPHA_SHIFT_OP)))
+ || (PUSH_NUM_LIT3 == (*call_addr & ~(ALPHA_MASK_DISP << ALPHA_SHIFT_DISP))))
+ {
+ while ( (PUSH_NUM_LIT1 == (*call_addr & (ALPHA_MASK_OP << ALPHA_SHIFT_OP)))
+ || (PUSH_NUM_LIT2 == (*call_addr & (ALPHA_MASK_OP << ALPHA_SHIFT_OP)))
+ || (PUSH_NUM_LIT3 == (*call_addr & ~(ALPHA_MASK_DISP << ALPHA_SHIFT_DISP))))
+ call_addr++;
+ /* If it's not a transfer table call, give up. */
+ if ( (LOAD_XFER_ADDR1 != (*call_addr & ~(ALPHA_MASK_DISP << ALPHA_SHIFT_DISP)))
+ || (LOAD_XFER_ADDR2 != *(call_addr + 1))
+ || (XFER_CALL != *(call_addr + 2)))
+ return ((zb_code *)addr);
+ xfer_addr = call_addr;
+ xfer_offset = (*call_addr >> ALPHA_SHIFT_DISP) & ALPHA_MASK_DISP;
+ call_addr += 3;
+ if ((xf_linefetch * SIZEOF(int4) != xfer_offset) && (xf_zbfetch * SIZEOF(int4) != xfer_offset))
+ return ((zb_code *)addr);
+ } else if ((LOAD_XFER_ADDR1 == (*call_addr & ~(ALPHA_MASK_DISP << ALPHA_SHIFT_DISP)))
+ && (LOAD_XFER_ADDR2 == *(call_addr + 1))
+ && (XFER_CALL == *(call_addr + 2)))
+ {
+ xfer_addr = call_addr;
+ xfer_offset = (*call_addr >> ALPHA_SHIFT_DISP) & ALPHA_MASK_DISP;
+ if ((xf_linestart * SIZEOF(int4) != xfer_offset) && (xf_zbstart * SIZEOF(int4) != xfer_offset))
+ return ((zb_code *)addr);
+ }
+ return ((zb_code *)xfer_addr);
+}
diff --git a/sr_avms/g_msf.max b/sr_avms/g_msf.max
new file mode 100644
index 0000000..ea06c43
--- /dev/null
+++ b/sr_avms/g_msf.max
@@ -0,0 +1,76 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ;
+; Copyright 2001, 2012 Fidelity Information Services, Inc ;
+; ;
+; This source code contains the intellectual property ;
+; of its copyright holder(s), and is made available ;
+; under a license. If you do not know the terms of ;
+; the license, please stop and do not read further. ;
+; ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ .macro G_MSF
+
+; msf - offsets into the GT.M MUMPS stack frame
+;
+; note: these offsets correspond to fields in the stack frame defined in stack_frame.h
+
+ msf$rvector_off = 0
+ msf$l_symtab_off = 4
+ msf$mpc_off = 8
+ msf$ctxt_off = 12
+ msf$literal_ptr_off = 16
+ msf$temps_ptr_off = 20
+ msf$vartab_ptr_off = 24
+ msf$vartab_len_off = 28
+ msf$temp_mvals = 30
+ msf$old_frame_off = 32
+ msf$typ_off = 36
+ msf$flags_off = 38
+ msf$for_ctrl_stack = 40
+
+ msf$frame_size = 48
+
+; Stack frame type (msf$typ_off) field bits (see also stack_frame.h):
+
+ sft_count = ^X01 ; frame counts (real code) or doesn't (transcendental code)
+ sft_dm = ^X02 ; direct mode
+ sft_rep_op = ^X04 ; frame to replace opcode (zbreak has already occurred)
+ sft_zbrk_act = ^X08 ; action frame for zbreak
+ sft_dev_act = ^X10 ; action frame for device error handler
+ sft_ztrap = ^X20 ; ztrap frame
+ sft_zstep_act = ^X80 ; action frame for a zstep
+ sft_zintr = ^X100 ; $zinterrupt frame
+
+; Stack frame flag (msf$flags_off) bits (see in stack_frame.h)
+
+ sff_indce = ^X01 ; frame requires indr cache entry cleanup in op_unwind
+ sff_etrap_err = ^X10 ; A $ETRAP style error occurred while in this frame.
+
+; mrt - offsets into the GT.M object file routine header
+;
+; note: these offsets correspond to fields in the routine header defined in rtnhdr.h
+
+ mrt$jsb = 0
+ mrt$src_len = 12
+ mrt$src_addr = 16
+ mrt$rtn_len = 20
+ mrt$rtn_addr = 24
+ mrt$var_ptr = 28
+ mrt$var_len = 32
+ mrt$lab_ptr = 36
+ mrt$lab_len = 40
+ mrt$lnr_ptr = 44
+ mrt$lnr_len = 48
+ mrt$ptxt_ptr = 52
+ mrt$checksum = 56
+ mrt$compiler_qlf = 60
+ mrt$oldr_ptr = 64
+ mrt$curr_ptr = 68
+ mrt$tmp_mv = 72
+ mrt$tmp_sz = 74
+ mrt$lnk_ptr = 76
+ mrt$lit_ptr = 80
+
+ mrt$hdr_size = 84
+
+ .endm
diff --git a/sr_avms/get_registers.m64 b/sr_avms/get_registers.m64
new file mode 100644
index 0000000..34de7a5
--- /dev/null
+++ b/sr_avms/get_registers.m64
@@ -0,0 +1,11 @@
+ .title get_registers
+
+; get_registers - copy machine registers into argument array
+;
+; This is a stub.
+
+ $routine name=get_registers,entry=get_registers_ca,kind=null
+
+ ret r26
+
+ $end_routine name=get_registers
diff --git a/sr_avms/getframe.max b/sr_avms/getframe.max
new file mode 100644
index 0000000..bcf39e6
--- /dev/null
+++ b/sr_avms/getframe.max
@@ -0,0 +1,33 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ;
+; Copyright 2001, 2011 Fidelity Information Services, Inc ;
+; ;
+; This source code contains the intellectual property ;
+; of its copyright holder(s), and is made available ;
+; under a license. If you do not know the terms of ;
+; the license, please stop and do not read further. ;
+; ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Restore registers from the current GT.M MUMPS stack frame.
+; Note: This macro puts the code address into some register; you may specify one or it will default to r26.
+
+ .macro getframe reg=r26, ?label
+
+ ; A_frame_pointer must be address of quadword containing the address of frame_pointer
+ ldq r12, A_frame_pointer
+ ldl r12, (r12)
+ lda r8, msf$flags_off(r12)
+ ldq_u r9, (r8)
+ extbl r9, r8, r9
+ and r9, sff_etrap_err, r9
+ beq r9, label
+ $call ERROR_RETURN, set_arg_info=false, nonstandard=true
+ ldq r12, A_frame_pointer
+ ldl r12, (r12)
+label: ldl r8, msf$l_symtab_off(r12)
+ ldl r9, msf$temps_ptr_off(r12)
+ ldl r13, msf$ctxt_off(r12)
+ ldl r14, msf$literal_ptr_off(r12)
+ ldl reg, msf$mpc_off(r12)
+
+ .endm
diff --git a/sr_avms/gtm$defaults.m64 b/sr_avms/gtm$defaults.m64
new file mode 100644
index 0000000..bbb69e2
--- /dev/null
+++ b/sr_avms/gtm$defaults.m64
@@ -0,0 +1,27 @@
+;****************************************************************
+;* *
+;* Copyright 2002, 2011 Fidelity Information Services, Inc *
+;* *
+;* This source code contains the intellectual property *
+;* of its copyright holder(s), and is made available *
+;* under a license. If you do not know the terms of *
+;* the license, please stop and do not read further. *
+;* *
+;****************************************************************/
+
+ .TITLE GTM$DEFAULTS
+GTM$USER_STACK_SIZE == 256 * 1024
+GTM$USER_SPAWN_FLAG == 0
+GTM$USER_INDRCACHE_SIZE == 32
+GTM$USER_STRPL_SIZE == 20480
+GTM$USER_IO_TIMER == 3300000
+GTM$USER_WRITE_FILTER == 0
+GTM$SPECIAL_INPUT == ^X000000
+GTM$UNDEF_INHIBIT == 0
+GTM$CTRLC_ENABLE == 1
+GTM$BREAK_MESSAGE_MASK == 15
+GTM$LOWER_CASE_LABELS == 1
+GTM$LVNULLSUBS == 1
+GTM$ZDIR_FORM == 0
+GTM$ZDATE_FORM == 0
+ .END
diff --git a/sr_avms/gtm$fgncall.m64 b/sr_avms/gtm$fgncall.m64
new file mode 100644
index 0000000..e1da2c0
--- /dev/null
+++ b/sr_avms/gtm$fgncall.m64
@@ -0,0 +1,231 @@
+ .title gtm$fgncall perform calls from foreign languages to MUMPS
+
+
+ G_MSF
+ base_frame
+
+
+MAXARGS = 32 ; maximum number of arguments allowed
+
+; Offsets from frame pointer into stack extension area.
+output = -8
+label = output - 8
+routine = label - 8
+argcnt = routine - 8
+arglist = argcnt - 8
+save_sp = arglist - 8
+
+end = save_sp - 8
+
+ARG_COPY = end - <<MAXARGS+1>*4> ; argument copy area (one extra space for argument count)
+
+
+; Offsets from stack pointer into stack extension area.
+
+args = 0 ; address of local array [0:MAXARGS] into which fgn_parms builds its argument list
+retval = MAXARGS*4 ; address of last element in the array into which fgn_parms puts return value address
+
+
+; Invoked via entry created by MUMPS_BINDING macro.
+;
+; Arguments:
+; r16 address of MUMPS routine
+; r17 address of MUMPS label
+; r18 does MUMPS routine return a value (is it a function)? 1 => yes, 0 => no
+; r19 address of argument list (starting with argument count)
+; r20 = 0, if the MUMPS label has been resolved by VMS linker
+; = length of the MUMPS label, if it hasn't been resolved by VMS linker
+
+; The code PSECT must have the MIX attribute in order to contain data.
+$CODE$ = "GTM$FGNCALL,QUAD,PIC,CON,REL,LCL,SHR,EXE,RD,MIX,NOWRT"
+
+ $routine name=gtm$fgncall, entry=gtm$fgncall_ca, kind=stack, -
+ saved_regs=<%string(base_frame_regs)>, -
+ base_reg_is_fp=true, data_section_pointer=true -
+ rsa_offset=RSA_OFFSET, size=STACK_SIZE, -
+ standard_prologue=false, handler=GTM$DYN_CH, synch_exceptions=true
+
+ .if ne,$SIZE,STACK_SIZE
+ .error "The stack size computed by $routine (%integer($SIZE)) differs from that defined in the -
+base_frame macro (%integer(STACK_SIZE))."
+ .endc
+
+ $linkage_section
+
+A_line1: .address line1
+A_var_on_cstack_ptr: .address var_on_cstack_ptr
+
+L_ERR_GTMCHECK: .long ERR_GTMCHECK
+
+ $data_section
+literal_table: .asciz "$FGNFNC"
+
+ $code_section
+
+jsb:
+ .base r27, $ls
+
+; the no-ops were introduced so that this code remains the same size
+; at that of a generated mumps object file.
+ nop
+ nop
+ jsr r0, (r0) ; gtm$main sets up the actual frame
+
+ $end_prologue
+
+ .if ne,<.-$cs>,mrt$src_len
+ .error "The dummy routine header jsb size is incorrect; please check it against g_msf.max."
+ .endc
+
+src_full_name:
+ .long 0 ; source file name length
+ address_32 0 ; source file name
+routine_name:
+ .long 7 ; routine name length (sizeof("$FGNFNC") - 1)
+ address_32 $ds ; routine name (dummy)
+vartab_ptr:
+ .long label_table - $cs ; variable table
+vartab_len:
+ .word 0 ; variable table length
+ .word 0 ; padding
+labtab_ptr:
+ .long label_table - $cs ; label table
+labtab_len:
+ .word 1 ; label table length
+ .word 0 ; padding
+lnrtab_ptr:
+ .long line_table - $cs ; line table
+lnrtab_len:
+ .word 2 ; line table length
+ .word 0 ; padding
+ptext_ptr:
+ .long gtm$fgncode - $cs ; pointer to start of actual code
+checksum:
+ .long 0
+compiler_qlf:
+ .long 0
+old_rhead_ptr:
+ address_32 0
+current_rhead_ptr:
+ address_32 0
+temp_mvals:
+ .word 0
+temp_size:
+ .word 0
+linkage_ptr:
+ address_32 $ls
+literal_ptr:
+ address_32 $ds
+
+; End of GT.M routine header.
+ .if ne,<.-jsb>,mrt$hdr_size
+ .error "The dummy routine header size is incorrect; please check it against g_msf.max."
+ .endc
+
+gtm$fgncode:
+; gtm$main, among other things, creates a GT.M MUMPS stack frame for this routine;
+; for which this is the entry point to which control is transferred by a
+; "getframe/ret r26" sequence.
+
+ .base r13, $ls ; also set up by getframe/ret sequence
+
+; Reset var_on_cstack_ptr for the new M environment
+ ldq r28, A_var_on_cstack_ptr
+ stl r31, (r28) ; var_on_cstack_ptr = NULL;
+
+; Save the current error trap and NEW it before any error could possibly occur.
+ $call gtm_savetraps, args=<>, set_arg_info=false
+
+; Restore argument info and argument registers (saved here by gtm$main).
+ ldq r20, $SIZE-16(fp) ; MUMPS label length (0 if resolved by LINK)
+ beq r20, resolved
+ $call fgn_resolve_lab, args=<$SIZE-48(fp)/Q, r20, $SIZE-40(fp)/Q>
+ stq r0, $SIZE-40(fp)
+resolved:
+ ldq r16, $SIZE-48(fp) ; A(MUMPS routine)
+ ldq r17, $SIZE-40(fp) ; A(MUMPS label)
+ ldq r18, $SIZE-32(fp) ; output?
+ ldq r19, $SIZE-24(fp) ; A(arg list to interface)
+
+ stq r16, routine(fp)
+ stq r17, label(fp)
+ stq r18, output(fp)
+ stq r19, arglist(fp)
+ stq sp, save_sp(fp)
+ ldq r28, A_line1
+ stl r28, msf$mpc_off(r12)
+line1: ldq r0, arglist(fp) ; original argument list
+ lda r1, ARG_COPY(fp)
+ ldl r22, (r0) ; number of arguments in arglist
+
+; Copy arguments from original arglist to array of longs (or address_32's).
+1$: ldq r28, (r0)
+ stl r28, (r1)
+ lda r0, 8(r0)
+ lda r1, 4(r1)
+ subq r22, 1, r22
+ bge r22, 1$ ; one extra iteration to include the argument count
+ $call fgn_parms, args=<output(fp), sp, MAXARGS/A, ARG_COPY(fp)/A>
+ stq r0, argcnt(fp)
+ bgt r0, 5$ ; if any arguments
+ ldq r28, output(fp)
+ bgt r28, 20$ ; if it's a function
+ $call op_extcall, args=<routine(fp), label(fp)>
+ br after_call
+
+; Extend stack and copy arguments returned from fgn_parms to extension.
+5$: ; Put first argument into appropriate register, then deal with rest.
+ ldl r21, (sp)
+ mov #MAXARGS+1, r22 ; copy entire array, including extra space at end for retval
+ lda r0, 4(sp) ; start of arguments that don't fit into argument registers
+ addq r22, 1, r23 ; round up to even double-quadword boundary
+ bic r23, 1, r23
+ subq r31, r23, r28 ; negate because s8subq works backwards
+ s8addq r28, sp, sp
+ mov sp, r1
+10$: ldl r28, (r0)
+ stq r28, (r1)
+ lda r0, 4(r0)
+ lda r1, 8(r1)
+ subq r22, 1, r22
+ bgt r22, 10$
+20$: ldq r22, save_sp(fp)
+ $call op_extexfun, args=<routine(fp), label(fp), retval(r22)/L, 0/A, argcnt(fp), r21>, set_arg_info=false
+after_call:
+ ldq sp, save_sp(fp)
+ ldl r16, retval(sp)
+ beq r16, gohome
+ $call op_exfunret, args=<r16>
+ ldq r17, arglist(fp)
+ ldq r17, 8(r17)
+ ldl r16, retval(sp)
+ $call mval2desc, args=<r16, r17>
+gohome:
+; Leaving new M environment; reset var_on_cstack_ptr for the old M environment
+ ldq r28, A_var_on_cstack_ptr
+ stl r31, (r28) ; var_on_cstack_ptr = NULL;
+
+ $begin_epilogue
+ $call opp_ret, set_arg_info=false
+
+; shouldn't return
+ $call lib$signal, args=<L_ERR_GTMCHECK/L>
+; also shouldn't return
+
+
+; Standard variable (null), label, and line tables for end of GT.M object module.
+
+; Variable table would go here if there were one.
+
+label_table: ; initialize the lab_tabent entry
+ .long 0
+ address_32 0
+ .long lte - $cs
+
+line_table:
+ .long gtm$fgncode - $cs ; line 0
+lte: .long line1 - $cs ; line 1
+
+ $end_routine name=gtm$fgncall
+
+ .end
diff --git a/sr_avms/gtm_code_address.m64 b/sr_avms/gtm_code_address.m64
new file mode 100644
index 0000000..649b6a6
--- /dev/null
+++ b/sr_avms/gtm_code_address.m64
@@ -0,0 +1,17 @@
+ .title gtm_code_address return code address for a routine given its procedure descriptor address
+
+; gtm$code_address
+;
+; entry:
+; a0 (r16) address of procedure descriptor
+;
+; exit:
+; r0 address of entry point indicated by procedure descriptor
+
+ $routine name=gtm$code_address,entry=gtm$code_address_ca,kind=null
+
+ ldq r0, 8(r16)
+
+ ret r26
+
+ $end_routine name=gtm$code_address
diff --git a/sr_avms/gtm_dyn_ch.m64 b/sr_avms/gtm_dyn_ch.m64
new file mode 100644
index 0000000..078c137
--- /dev/null
+++ b/sr_avms/gtm_dyn_ch.m64
@@ -0,0 +1,80 @@
+ .title GTM_DYN_CH dynamic condition handler interface
+
+; WARNING: This condition handler uses an undocumented convention
+; and library routine in Alpha VMS in order to emulate dynamic
+; condition handlers for Alpha assembly language (MACRO) routines
+; and GT.M-generated object modules.
+;
+; This mechanism should be semantically identical to that of VAX VMS,
+; whereby the address of the condition handler for a frame could be
+; found in the longword at 0(FP) for that frame (0 => no condition
+; handler in effect) at the time the condition occurred. This
+; allowed the condition handler for a frame to be changed by changing
+; the value of that longword.
+;
+; In order for a procedure P to support dynamic condition handler
+; specifications for its activation stack frames:
+;
+; 1. P must be a stack frame procedure
+;
+; 2. P must establish GTM$DYN_CH as its static condition
+; handler (see OpenVMS Calling Standard and OpenVMS
+; Programming Concepts Manual)
+;
+; 3. P must reserve the quadword at 8(FP) for the address
+; of the procedure value of the currently-active condition
+; handler; this quadword should be initialized to zero
+; (indicating no condition handler active) or to the
+; address of a real procedure value during the entry
+; prologue before setting FP to ensure a valid value is
+; always present.
+;
+; 4. It is possible P should also reserve the quadword at
+; 16(FP), although it need not be initialized.
+;
+; It may be necessary to modify this at some future Alpha VMS
+; operating system release to conform to any changes in the condition
+; handler conventions. In this instance, compile the following VAX
+; MACRO program with:
+;
+; macro/migration/machine/lis
+;
+; and examine the resulting .LIS file to determine how the static
+; condition handler works (use it as a basis for the changes to
+; GTM$DYN_CH) and where to store the address of the dynamically-
+; specified condition handler (mdb_condition_handler in the example):
+;
+; .title zero_fp
+;
+; .psect zero_fp pic,usr,rel,gbl,shr,exe,rd,nowrt,novec,quad
+;
+; .call_entry preserve=all,label=zero_fp
+; movl mdb_condition_handler, 0(fp)
+; ret
+; .end
+
+
+ $linkage_section
+
+l_ots$call_proc:
+ .linkage_pair OTS$CALL_PROC
+
+
+ $routine name=gtm$dyn_ch,entry=gtm$dym_ch_ca,kind=null
+
+ .base r27, $ls
+
+ ldq r28, 8(r17) ; 8(a1) = MCH_FRAME in the condition handler mechanism array (second argument)
+ ldl r28, 8(r28) ; 8(establisher's FP) = A(currently established condition handler for that frame)
+ beq r28, no_handler
+ mov r28, r23 ; t2 <- A(condition handler to invoke)
+ ldq r28, l_ots$call_proc ; N.B., don't modify caller's r26
+ bis r31, 1, r24 ; t3 <- 1
+ lda r27, l_ots$call_proc+8
+ jmp r28 ; goto OTS$CALL_PROC
+
+no_handler: ; no established condition handler for that frame
+ lda r0, 2328(r31) ; r0 <- SS$_RESIGNAL
+ ret r26
+
+ $end_routine name=gtm$dyn_ch
diff --git a/sr_avms/gtm_main.m64 b/sr_avms/gtm_main.m64
new file mode 100644
index 0000000..db2d2c0
--- /dev/null
+++ b/sr_avms/gtm_main.m64
@@ -0,0 +1,218 @@
+;****************************************************************
+;* *
+;* Copyright 2002, 2012 Fidelity Information Services, Inc *
+;* *
+;* This source code contains the intellectual property *
+;* of its copyright holder(s), and is made available *
+;* under a license. If you do not know the terms of *
+;* the license, please stop and do not read further. *
+;* *
+;****************************************************************/
+
+ .title gtm_main dispatch code for run-time system
+
+ G_MSF
+ base_frame
+
+$CODE$ = "GTM$INIT,QUAD,PIC,CON,REL,LCL,SHR,EXE,NOWRT"
+$DATA$ = "GTM$VECTOR,OCTA,PIC,OVR,REL,LCL,NOSHR,NOEXE,WRT"
+$LINK$ = "GTM$LINK,OCTA,NOPIC,CON,REL,LCL,NOSHR,NOEXE,WRT"
+
+
+ $data_section
+gtm_vector:
+argcnt: .long <gtm_vector_end - gtm_vector>
+rtn_start: address_32 start
+rtn_end: address_32 end
+zctable_start: address_32 gtm$startzc
+zctable_end: address_32 gtm$endzc
+zcpack_start: address_32 gtm$startzcpack
+zcpack_end: address_32 gtm$endzcpack
+vax_fp: .long 0
+xf_table: .long 0
+frm_ptr: .long 0
+base_addr: .long 0
+gtm_main_inaddr: address_32 gtm$main
+user_stack_size: .long GTM$USER_STACK_SIZE
+user_spawn_flag: .long GTM$USER_SPAWN_FLAG
+user_indrcache_size: .long GTM$USER_INDRCACHE_SIZE
+user_strpl_size: .long GTM$USER_STRPL_SIZE
+user_io_timer: .long GTM$USER_IO_TIMER
+user_write_filter: .long GTM$USER_WRITE_FILTER
+special_input: .long GTM$SPECIAL_INPUT
+undef_inhib: .long GTM$UNDEF_INHIBIT
+ctrlc_enable: .long GTM$CTRLC_ENABLE
+break_message_mask: .long GTM$BREAK_MESSAGE_MASK
+labels: .long GTM$LOWER_CASE_LABELS
+lvnullsubs: .long GTM$LVNULLSUBS
+zdir_form: .long GTM$ZDIR_FORM
+zdate_form: .long GTM$ZDATE_FORM
+sysid: address_32 gtm_sysid_mstr
+dlr_truth: .long 0
+gtm_vector_end = .
+
+gtm_sysid_mstr: .long 9 ;These lines
+ address_32 gtm_sysid ; construct
+gtm_sysid: .ascii "gtm_sysid" ; an mstr
+
+; These dummy PSECT's will be sorted (alphabetically) by the linker
+; to delimit the beginning and end of the initial routines name
+; (rtn_tables) table. In order for this to work, they must have the
+; same significant attributes as those of the PSECT generated by
+; create_object_file (in obj_file.c) and must have alignment requirements
+; no more restrictive than those of rtn_tables.
+
+; GTM$R - beginning of initial routine tables
+ .psect gtm$r pic,rel,gbl,noshr,noexe,rd,wrt,novec,long
+ NUL = ^X00
+ DEL = ^X7F
+start: .long 8 ; length of start_rtn_name
+ address_32 start_rtn_name
+ .long 0 ; dummy address
+
+; GTM$RZZZZZZZZZZZZZZZZZZZZZZZZZZ - end of initial routine tables plus some room for expansion
+ .psect gtm$rzzzzzzzzzzzzzzzzzzzzzzzzzz pic,rel,gbl,noshr,noexe,rd,wrt,novec,long
+end: .long 8 ; length of end_rtn_name
+ address_32 end_rtn_name
+ .long 0 ; dummy address
+ .blkl 17 * 3 ; extra room for expansion (FREE_RTNTBL_SPACE * (sizeof(rtn_tables)/sizeof(long))) (BYPASSOK)
+
+ .psect gtm$rtn_literals pic,rel,gbl,shr,noexe,rd,nowrt,novec,quad
+start_rtn_name: ; name guaranteed to sort before all others
+ .ascii <NUL><NUL><NUL><NUL><NUL><NUL><NUL><NUL>
+ .align quad ; so the next name starts at 8-byte boundary
+end_rtn_name: ; name guaranteed to sort after all others
+ .ascii <DEL><DEL><DEL><DEL><DEL><DEL><DEL><DEL>
+
+
+; gtm$main - GT.M initialization interface
+;
+; The routine header for all GT.M object files contains code to transfer control
+; to gtm$main. This code executes first whenever the GT.M object file is invoked
+; by VMS (e.g., as the first module in an executable image) in order to set up
+; the Alpha stack frame for GT.M and to ensure gtm$startup gets called to initialize
+; the GT.M environment properly.
+;
+; Dynamically-linked GT.M object modules or those not the first to execute are
+; invoked at the address following the routine header and, so, do not invoke gtm$main.
+;
+; gtm$main is invoked by the instruction sequence (see create_object_file in obj_file.c):
+; ldq r0, gtm$main_linkage_pair(r27)
+; ldq r1, gtm$main_linkage_pair+8(r27)
+; jmp r0, (r0)
+; so that gtm$main can execute in its caller's stack frame (and initialize it).
+;
+; Entry:
+; r0 return address in gtm$main's GT.M caller (just after jsb field in routine header)
+; r1 address of gtm$main's procedure descriptor
+
+ $routine gtm$main, entry=gtm$main_ca, kind=stack, -
+ saved_regs=<%string(base_frame_regs)>, -
+ base_reg_is_fp=true, data_section_pointer=true, -
+ rsa_offset=RSA_OFFSET, size=STACK_SIZE, -
+ standard_prologue=false, handler=GTM$DYN_CH, synch_exceptions=true
+
+ create_base_frame ; special prologue code + extend stack for argument push area
+
+ mov r1, r13
+ .base r13, $ls
+
+; init_gtm (<return address (just past jsb field in routine header)>, <caller's and our frame pointer>)
+ mov ^x0, r18 ; indicate that this is not a DAL case
+ $call init_gtm, local=true, nonstandard=true, set_arg_info=false, scratch_regs=<r28>, args=<r0, fp, r18>
+
+ ldq r22, $dp
+ .base r22, $ds
+
+ ldl r10, dlr_truth
+ ldl r11, xf_table
+ ldl r12, frm_ptr
+ ldl r8, msf$l_symtab_off(r12)
+ ldl r9, msf$temps_ptr_off(r12)
+ ldl r28, msf$rvector_off(r12) ; get routine header of GT.M MUMPS routine to invoke
+ ldl r13, mrt$lnk_ptr(r28) ; linkage Psect address not initialized by init_gtm -- obtain from routine header
+ stl r13, msf$ctxt_off(r12)
+ ldl r14, mrt$lit_ptr(r28) ; literal Psect address not initialized by init_gtm -- obtain from routine header
+ stl r14, msf$literal_ptr_off(r12)
+ ldl r26, msf$mpc_off(r12)
+
+; Don't do a normal $return; leave stack unchanged.
+; begin pseudo-epilogue
+ $begin_epilogue
+ trapb ; synchronize exceptions
+ ret r26
+ $end_epilogue
+; end pseudo-epilogue
+
+ $end_routine name=gtm$main
+
+
+; init_gtm - invoke gtm$startup to initialize GT.M
+;
+; init_gtm initializes some fields in the startup vector, gtm_vector,
+; and then invokes gtm$startup to complete GT.M environment
+; initialization.
+;
+; args a0 (r16) - return address of GT.M caller
+; For a GT.M object module, this will be the
+; address immediately following the call to
+; gtm$main and will be in the routine header.
+; For a foreign-language routine, this should
+; have been set to zero by gtm$init.
+;
+; a1 (r17) - fp of condition handler
+; This is the frame pointer of the stack frame
+; that will contain the condition handler address.
+; For GT.M objects that call gtm$main, this will be
+; the first-invoked object module.
+; For foreign-language calls, this will be the
+; stack from for gtm$init.
+;
+; a2 (r18) - flag that indicates whether this function was
+; invoked from gtm$main (0) or gtm$init (1)
+
+ $routine name=init_gtm, entry=init_gtm_ca, local=true, -
+ standard_prologue=true, kind=stack, -
+ base_reg_is_fp=true, saved_regs=<fp>, -
+ data_section_pointer=true
+
+ .base r27, $ls
+ ldq r22, $dp
+ .base r22, $ds
+
+ stl r16, base_addr
+ addq r17, 8, r28 ; add 8 to point to address of handler
+ stl r28, vax_fp
+ $call gtm$startup, args=<gtm_vector/A, r18> ; second parameter indicates whether this is DAL or not
+ $return
+
+ $end_routine name=init_gtm
+
+
+; gtm$init - interface to GT.M for foreign-language routines
+;
+; Foreign-language (non-GT.M) programs that wish to invoke GT.M
+; routines should call gtm$init first to invoke the GT.M initialization
+; code.
+
+ $linkage_section
+A_LIB$SIG_TO_RET:
+ .address LIB$SIG_TO_RET
+
+ $routine name=gtm$init, entry=gtm$init_ca, standard_prologue=true, kind=stack, -
+ base_reg_is_fp=true, rsa_offset=24, saved_regs=<r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,r13,fp>, -
+ handler=GTM$DYN_CH, synch_exceptions=true
+
+ mov r27, r13
+ .base r13, $ls
+
+ ldq r28, A_LIB$SIG_TO_RET
+ stl r28, 8(fp) ; establish LIB$SIG_TO_RET as handler
+ mov ^x1, r18 ; indicate that this is a DAL case
+ $call init_gtm, local=true, args=<r31, fp, r18>
+ lda r0, 1(r31) ; return success
+ $return
+
+ $end_routine name=gtm$init
+
+ .end
diff --git a/sr_avms/gtm_memmove.c b/sr_avms/gtm_memmove.c
new file mode 100644
index 0000000..73e1737
--- /dev/null
+++ b/sr_avms/gtm_memmove.c
@@ -0,0 +1,57 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/*
+ * ---------------------------------------------------
+ * memmove() - Move memory.
+ * This routine may replace any existing memcpy()
+ * calls. It correctly handles overlapping memory
+ * regions.
+ *
+ * Arguments:
+ * same as memcpy()
+ * pdest - pointer to destination
+ * psrc - pointer to source
+ * cnt - # of bytes to copy
+ * Return:
+ * pointer to destination
+ * ---------------------------------------------------
+ */
+
+#include "mdef.h"
+
+char_ptr_t gtm_memmove(char_ptr_t pdest,
+ char_ptr_t psrc,
+ int cnt)
+{
+ register char_ptr_t src, dst;
+
+ assert((0 <= cnt) && (cnt <= MAXPOSINT4)); /* nothing beyond max positive int4 allowed */
+ src = psrc;
+ dst = pdest;
+ if (cnt && dst != src)
+ {
+ if (src < dst && src + cnt > dst)
+ {
+ /* Overlapping region, downward copy, copy backwards */
+ dst += cnt;
+ src += cnt;
+ while (cnt-- > 0)
+ *--dst = *--src;
+ }
+ else
+ {
+ while (cnt-- > 0)
+ *dst++ = *src++;
+ }
+ }
+ return (pdest);
+}
diff --git a/sr_avms/gtm_ret_code.m64 b/sr_avms/gtm_ret_code.m64
new file mode 100644
index 0000000..c8a556b
--- /dev/null
+++ b/sr_avms/gtm_ret_code.m64
@@ -0,0 +1,48 @@
+ .title gtm_ret_code
+
+ base_frame
+
+ $routine gtm_ret_code, entry=gtm_ret_code_ca, kind=stack, -
+ saved_regs=<%string(base_frame_regs)>, -
+ rsa_offset=RSA_OFFSET, size=STACK_SIZE, -
+ standard_prologue=false, base_reg_is_fp=true, rsa_offset=RSA_OFFSET
+
+ .if ne,$SIZE,STACK_SIZE
+ .error "The stack frame size computed by $routine (%integer($SIZE)) differs from that defined in the base_frame -
+macro (%integer(STACK_SIZE))."
+ .endc
+
+ $linkage_section
+
+A_frame_pointer: .address frame_pointer
+A_msp: .address msp
+A_mumps_status: .address mumps_status
+
+
+; Since gtm_ret_code executes in the machine stack frame set up by gtm$main, it need not set
+; up the stack frame and because gtm_ret_code can only be invoked via a getframe/ret sequence,
+; r13 has the address of the procedure descriptor, not r27.
+
+ $code_section
+
+ .base r13, $ls
+ $end_prologue
+
+ stq r31, 8(fp) ; clear pointer to condition handler address
+ $call op_unwind, set_arg_info=false, nonstandard=true
+ ldq r0, A_msp
+ ldl r28, (r0)
+ ldq r1, A_frame_pointer
+ ldl r22, (r28)
+ stl r22, (r1) ; frame_pointer = msp
+ lda r28, 4(r28)
+ stl r28, (r0) ; msp += 4
+ ldq r28, A_mumps_status
+ ldl r0, (r28) ; return code
+
+ $return ; use standard $return macro to ensure epilogue uses values from the
+ ; $routine macro as defined in the base_frame macro
+
+ $end_routine name=gtm_ret_code
+
+ .end
diff --git a/sr_avms/gtm_zc.m64 b/sr_avms/gtm_zc.m64
new file mode 100644
index 0000000..b69fe21
--- /dev/null
+++ b/sr_avms/gtm_zc.m64
@@ -0,0 +1,19 @@
+ .title gtm_zc GTM ZCALL PSECT DEFINITIONS
+
+ .psect gtm$zcalltabaaa pic,ovr,rel,gbl,shr,noexe,rd,nowrt,novec,long
+ .long 0
+gtm$startzc::
+
+ .psect gtm$zcalltabaac pic,ovr,rel,gbl,shr,noexe,rd,nowrt,novec,byte
+gtm$endzc::
+ .byte 0
+
+ .psect gtm$zcallpackaa pic,ovr,rel,gbl,shr,noexe,rd,nowrt,novec,long
+ .long 0
+gtm$startzcpack::
+
+ .psect gtm$zcallpackac pic,ovr,rel,gbl,shr,noexe,rd,nowrt,novec,byte
+gtm$endzcpack::
+ .byte 0
+
+ .end
diff --git a/sr_avms/gtmi$def.m64 b/sr_avms/gtmi$def.m64
new file mode 100644
index 0000000..c7c0263
--- /dev/null
+++ b/sr_avms/gtmi$def.m64
@@ -0,0 +1,14 @@
+ .title gtmi$def definitions for gtm external interface
+gtmi$_global == 1
+gtmi$_naked == 2
+gtmi$_extgbl == 3
+gtmi$_local == 4
+gtmi$_extlcl == 5
+
+gtmi$_lock == 6
+gtmi$_zalloc == 7
+gtmi$_zdealloc== 8
+gtmi$_inclock == 9
+gtmi$_declock == 10
+gtmi$_unlock == 11
+ .end
diff --git a/sr_avms/gtmsecplv.m64 b/sr_avms/gtmsecplv.m64
new file mode 100644
index 0000000..d8790e5
--- /dev/null
+++ b/sr_avms/gtmsecplv.m64
@@ -0,0 +1,60 @@
+ .title gtmsecplv - GTMSECSHR PLV (privileged library vector)
+
+
+; PLV (privileged library vector) for GTMSECSHR.
+;
+; This is the Alpha AXP OpenVMS analogue for the VAX VMS PLV in the GT.M VAX source file: KERN_MODE.MAR
+;
+; NOTE: At the time this was written (10/29/93), the Alpha AXP OpenVMS documentation apparently did not
+; match the actual implementation of this feature. In particular, many of the following fields were
+; described as 64 bits wide when, apparently, they must be 32 bits wide due to an as-yet-undocumented
+; change to VMS. Further, there seemed to be no system-supplied C header files or MACRO macro libraries
+; that defined anything useful related to PLV's; if this situation changes, this file should be modified
+; to use any system-supplied definitions that prove useful.
+;
+; References:
+; OpenVMS Programming Concepts Manual
+; OpenVMS Linker Utility Manual
+;
+; See also:
+; Examples in files whose names start with "UWSS" (for User-Written System Service) in the
+; directory SYS$EXAMPLES. Pay special attention to the comments and revision history comments.
+
+
+PLV$C_TYP_CMOD = 1 ; not yet defined in any usable system include file (see $PLVDEF in some future VMS release?)
+
+ .psect gtmsecplv, QUAD, PIC, CON, LCL, SHR, NOEXE, NOWRT, VEC
+
+
+ .long PLV$C_TYP_CMOD ; PLV$L_TYPE
+ .long 0 ; PLV$L_VERSION - system version number (unused)
+ .long <kernel_routine_list_end - kernel_routine_list>/4 ; PLV$L_KERNEL_ROUTINE_COUNT
+ .long 0 ; PLV$L_EXEC_ROUTINE_COUNT
+ address_32 kernel_routine_list ; PLV$PS_KERNEL_ROUTINE_LIST
+ address_32 0 ; PLV$PS_EXEC_ROUTINE_LIST
+ address_32 rundown_dispatch ; PLV$PS_KERNEL_RUNDOWN_HANDLER
+ .long 0 ; reserved
+ address_32 0 ; PLV$PS_RMS_DISPATCHER
+ .long 0 ; reserved
+ .long 0 ; reserved
+
+
+; NOTE: I believe these addresses need to be in the same order as they appear in the symbol_vector
+; definition in the buildsec.com GTMSECSHR linker options file. That may not be the case, but it
+; keeping them in the same order will probably not cause problems.
+
+kernel_routine_list:
+ address_32 crit_wake
+ address_32 del_sec
+ address_32 init_sec
+ address_32 gtm_enq
+ address_32 gtm_enqw
+ address_32 gtm_deq
+ address_32 gtm_blkast
+ address_32 get_proc_info
+ address_32 init_secshr_addrs
+ address_32 gtm_getlkiw
+ address_32 secshr_db_clnup
+kernel_routine_list_end:
+
+ .end
diff --git a/sr_avms/gtmshrlink.axp b/sr_avms/gtmshrlink.axp
new file mode 100644
index 0000000..d103b0b
--- /dev/null
+++ b/sr_avms/gtmshrlink.axp
@@ -0,0 +1,74 @@
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+! !
+! Copyright 2001, 2013 Fidelity Information Services, Inc !
+! !
+! This source code contains the intellectual property !
+! of its copyright holder(s), and is made available !
+! under a license. If you do not know the terms of !
+! the license, please stop and do not read further. !
+! !
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!
+objlib/lib
+symbol_vector=( -
+ gtm$compile = PROCEDURE, -
+ gtm$startup = PROCEDURE, -
+ gtm$gblget = PROCEDURE, -
+ gtm$gblput = PROCEDURE, -
+ gtm$gblnext = PROCEDURE, -
+ gtm$gblorder = PROCEDURE, -
+ gtm$gblprevious = PROCEDURE, -
+ gtm$gbldata = PROCEDURE, -
+ gtm$gblkill = PROCEDURE, -
+ gtm$gblquery = PROCEDURE, -
+ gtm$lock = PROCEDURE, -
+ gtm$inclock = PROCEDURE, -
+ gtm$declock = PROCEDURE, -
+ gtm$zalloc = PROCEDURE, -
+ gtm$zdealloc = PROCEDURE, -
+ gtm$setgbldir = PROCEDURE, -
+ gtm$ztstart = PROCEDURE, -
+ gtm$ztcommit = PROCEDURE, -
+ gtm$interrupt = PROCEDURE, -
+ gtm$fgncall = PROCEDURE, -
+ gtm$mval2subsc = PROCEDURE, -
+ gtm$gblwithdraw = PROCEDURE, -
+ gtm$lclget = PROCEDURE, -
+ gtm$lclkill = PROCEDURE, -
+ gtm$lclput = PROCEDURE, -
+ gtm$lclwithdraw = PROCEDURE, -
+ gtm$lcldata = PROCEDURE, -
+ gtm$lclquery = PROCEDURE, -
+ gtm$lclorder = PROCEDURE, -
+ gtm$lclprevious = PROCEDURE, -
+ gtm$xecute = PROCEDURE, -
+ gtm$rundown = PROCEDURE, -
+ gtm$get = PROCEDURE, -
+ gtm$kill = PROCEDURE, -
+ gtm$put = PROCEDURE, -
+ gtm$withdraw = PROCEDURE, -
+ gtm$data = PROCEDURE, -
+ gtm$query = PROCEDURE, -
+ gtm$order = PROCEDURE, -
+ gtm$previous = PROCEDURE, -
+ gtm$zkill = PROCEDURE, -
+ gtm$lock2 = PROCEDURE, -
+ gtm$zdealloc2 = PROCEDURE, -
+ gtm$ce_establish = PROCEDURE,-
+ gtm$ce_getinfo = PROCEDURE, -
+ gtm$dyn_ch = PROCEDURE, -
+ gtm_malloc = PROCEDURE, -
+ gtm_free = PROCEDURE, -
+ gtm$zstatus = PROCEDURE -
+ )
+gsmatch=lequal,11,0
+! Because the linker creates image sections on a per-cluster
+! basis, create a cluster for all of the code Psect's (whose
+! pages can be shared among processes) and collect all of the
+! code Psect's into it so the pages corresponding to that image
+! section can be shared. Note the MACRO/MIGRATION compiler
+! names its code Psect "$CODE" (as do most of the VAX compilers),
+! while the AXP C compiler and MACRO assembler name their code
+! Psect's "$CODE$".
+cluster = code_clust
+collect = code_clust,$CODE,$CODE$
diff --git a/sr_avms/gtmstopzc.m64 b/sr_avms/gtmstopzc.m64
new file mode 100644
index 0000000..f5a3760
--- /dev/null
+++ b/sr_avms/gtmstopzc.m64
@@ -0,0 +1,22 @@
+ .TITLE GTMSTOPZC
+ .LIBRARY "GTM$VRT:[PRO]GTMZCALL.MLB"
+ .IDENT "V1.00-1"
+;
+; ZCALL table and routines for GTMSTOP.M and GTCMSTOP.M
+;
+ .EXTERNAL ERR_FORCEDHALT
+ ZCINIT
+
+ ROUTINE CALLNAME=FORCEX, LINKNAME=SYS$FORCEX, INPUTS=3, OUTPUTS=0
+ RETURN CLASS=VALUE, TYPE=LONG
+ INPUT TYPE=LONG, MECHANISM=REFERENCE, POSITION=1, QUALIFIER=REQUIRED
+ INPUT TYPE=LONG, MECHANISM=VALUE, POSITION=2, QUALIFIER=CONSTANT, VALUE=0
+ INPUT TYPE=LONG, MECHANISM=VALUE, POSITION=3, QUALIFIER=CONSTANT, VALUE=ERR_FORCEDHALT
+
+
+ ROUTINE CALLNAME=DELPRC, LINKNAME=SYS$DELPRC, INPUTS=2, OUTPUTS=0
+ RETURN CLASS=VALUE, TYPE=LONG
+ INPUT TYPE=LONG, MECHANISM=REFERENCE, POSITION=1, QUALIFIER=REQUIRED
+ INPUT TYPE=LONG, MECHANISM=VALUE, POSITION=2, QUALIFIER=CONSTANT, VALUE=0
+ ZCALLFIN
+ .END
diff --git a/sr_avms/gtmzcall.max b/sr_avms/gtmzcall.max
new file mode 100644
index 0000000..7d2f4c9
--- /dev/null
+++ b/sr_avms/gtmzcall.max
@@ -0,0 +1,483 @@
+; ****************************************************************
+; * *
+; * Copyright 2001, 2012 Fidelity Information Services, Inc *
+; * This source code contains the intellectual property *
+; * of its copyright holder(s), and is made available *
+; * under a license. If you do not know the terms of *
+; * the license, please stop and do not read further. *
+; * *
+; ****************************************************************
+
+;----------------------------------------------------------------------------------------------------------------------------------
+
+ .macro package zcpackage_name
+ .if ge zc$maxpos
+ endrout
+ .endc
+ .if df zcpack_start
+ endpack
+ .endc
+ .macro labelentry cname ; use of this macro is currently suppressed
+ __GTM$ZC'zcpackage_name'.'cname'::
+ .endm
+
+ zcpack_start = zctalloc
+ zcpack_name = zcvalloc
+ .save_psect local_block
+ .psect gtm$zcallvalues pic,con,rel,gbl,shr,noexe,rd,nowrt,novec,quad
+ . = zcvalloc
+ .ascic "zcpackage_name"
+ zcvalloc = .
+ .psect gtm$zcalltabaab pic,con,rel,gbl,shr,noexe,rd,nowrt,novec,long
+ .restore_psect
+ .endm
+
+;----------------------------------------------------------------------------------------------------------------------------------
+
+ .macro routine callname, linkname, inputs=0, outputs=0, outofband=default
+
+ zc$num_args = inputs + outputs
+
+ .irp $$tmp, <callname, linkname, inputs, outputs>
+ .if b $$tmp
+ .print ;GT.M EXTERNAL CALL FORMAT ERROR: ROUTINE callname, linkname, inputs, outputs
+ .error ;REQUIRED KEYWORD OMITTED
+ .mexit
+ .endc
+ .endr
+
+ .irp $$tmp, <inputs, outputs>
+ .if lt $$tmp
+ .print ;GT.M EXTERNAL CALL FORMAT ERROR: ROUTINE callname, linkname, inputs, outputs
+ .error ;INPUTS AND OUTPUTS MUST BE >= 0
+ .mexit
+ .endc
+ .endr
+
+ .if ndf zc$rout_'outofband
+ .print ;GT.M EXTERNAL CALL FORMAT ERROR: ROUTINE outofband
+ .error ; UNDEFINED OUT-OF-BAND KEYWORD: outofband
+ .mexit
+ .endc
+ .if ge zc$maxpos
+ endrout
+ .endc
+
+ ;labelentry callname ;this is suppressed until case issues are resolved
+ .align long
+ .word <<<<<2+1+1+4+1+1+1+%length(callname)+2+3>/4>*4>+<8*inputs>+<8*outputs>+1+3>/4>*4
+ .byte inputs
+ .byte outputs
+ address_32 linkname
+ .byte zc$rout_'outofband
+ .byte 0 ; padding
+ .ascic "callname"
+ zc$maxpos = 0
+ zc$retlin = 0
+ zc$ip = 0
+ zc$op = 0
+ zc$ips = inputs
+ zc$ops = outputs
+ .endm
+
+;----------------------------------------------------------------------------------------------------------------------------------
+
+ .macro return class=status, type
+
+ .if ne zc$retlin
+ .print ;GT.M EXTERNAL CALL FORMAT ERROR:
+ .error ;RETURN LINE MUST IMMEDIATELY FOLLOW ROUTINE
+ .mexit
+ .endc
+ .irp $$tmp, <class>
+ .if b $$tmp
+ .print ;GT.M EXTERNAL CALL FORMAT ERROR: RETURN class, type
+ .error ;REQUIRED KEYWORD OMITTED
+ .mexit
+ .endc
+ .endr
+ .if ndf zc$retc_'class
+ .print ;GT.M EXTERNAL CALL FORMAT ERROR: RETURN class, type
+ .error ; UNDEFINED RETURN_CLASS KEYWORD: class
+ .mexit
+ .endc
+ .if eq zc$retc_'class - zc$retc_value
+ .if b type
+ .ift
+ .print ;GT.M EXTERNAL CALL FORMAT ERROR: RETURN class, type
+ .error ;REQUIRED KEYWORD OMITTED
+ .mexit
+ .iff
+ .if ndf zc$dtype_'type
+ .print ;GT.M EXTERNAL CALL FORMAT ERROR: RETURN class, type
+ .error ; UNDEFINED RETURN_CLASS KEYWORD: class
+ .mexit
+ .endc
+ .if eq zc$dtype_'type - zc$dtype_string
+ .print ;GT.M EXTERNAL CALL FORMAT ERROR: RETURN class, type
+ .error ;ILLEGAL COMBINATION
+ .mexit
+ .endc
+ .if eq zc$dtype_'type - zc$dtype_h_floating
+ .print ;GT.M EXTERNAL CALL FORMAT ERROR: RETURN class, type
+ .error ;ILLEGAL COMBINATION
+ .mexit
+ .endc
+ .endc
+ .endc
+
+ .byte zc$retc_'class
+ .byte zc$dtype_'type
+ .align long
+ zc$retlin = 1
+ .endm
+
+;----------------------------------------------------------------------------------------------------------------------------------
+
+ .macro input qualifier=required,type,mechanism,position,value
+
+ .if eq zc$retlin
+ return
+ .endc
+ .irp $$tmp, <type,mechanism,position>
+ .if b $$tmp
+ .print ;GT.M EXTERNAL CALL FORMAT ERROR: INPUT type, mechanism, position
+ .error ;REQUIRED KEYWORD OMITTED
+ .mexit
+ .endc
+ .endr
+ .if ndf zc$dtype_'type
+ .print ;GT.M EXTERNAL CALL FORMAT ERROR: INPUT type, mechanism, position
+ .error ; UNDEFINED INPUT_TYPE KEYWORD: type
+ .mexit
+ .endc
+ .if ndf zc$mech_'mechanism
+ .print ;GT.M EXTERNAL CALL FORMAT ERROR: INPUT type, mechanism, position
+ .error ; UNDEFINED INPUT_MECHANISM KEYWORD: mechanism
+ .mexit
+ .endc
+ .if eq zc$dtype_string - zc$dtype_'type
+ .if ne zc$mech_descriptor - zc$mech_'mechanism
+ .if ne zc$mech_descriptor64 - zc$mech_'mechanism
+ .print ;GT.M EXTERNAL CALL FORMAT ERROR: INPUT type, mechanism, position
+ .error ; ILLEGAL COMBINATION
+ .mexit
+ .endc
+ .endc
+ .endc
+ .if ndf zc$iqual_'qualifier
+ .print ;GT.M EXTERNAL CALL FORMAT ERROR: INPUT type, mechanism, position
+ .error ; UNDEFINED INPUT_QUALIFIER KEYWORD: qualifier
+ .mexit
+ .endc
+ .if idn zc$iqual_block,zc$iqual_'qualifier
+ .print ;GT.M EXTERNAL CALL FORMAT ERROR: INPUT type, mechanism, position
+ .error ; UNSUPPORTED INPUT_QUALIFIER KEYWORD: qualifier
+ .mexit
+ .endc
+
+ zc$iqual_constant = 1
+ zc$iqual_optional = 2
+ zc$iqual_optional_0 = 3
+ zc$iqual_default = 4
+ zc$iqual_required = 5
+ zc$iqual_block = 6
+ .if le position
+ .print ;GT.M EXTERNAL CALL FORMAT ERROR: INPUT type, mechanism, position
+ .error ; POSITION MUST BE POSITIVE: position
+ .mexit
+ .endc
+ .if lt zc$num_args - position
+ .print ;GT.M EXTERNAL CALL FORMAT ERROR: INPUT type, mechanism, position
+ .error ; POSITION MUST NOT BE GREATER THAN NUMBER OF ARGUMENTS: position, zc$num_args
+ .mexit
+ .endc
+
+ .byte zc$mech_'mechanism
+ .byte zc$dtype_'type
+ .byte position
+ .byte zc$iqual_'qualifier
+ .if b <value>
+ .ift
+ .if eq zc$iqual_default - zc$iqual_'qualifier
+ .iff
+ .if eq zc$iqual_constant - zc$iqual_'qualifier
+ .iff
+ .long 0
+ .ift
+ putval type,value
+ .endc
+ .ift
+ putval type,value
+ .endc
+ .iff
+ putval type,<value>
+ .endc
+ zc$ip = zc$ip + 1
+ .if lt zc$maxpos - position
+ zc$maxpos = position
+ .endc
+ .endm
+
+;----------------------------------------------------------------------------------------------------------------------------------
+
+ .macro putval t,val
+
+ address_32 zcvalloc
+ .save_psect local_block
+ .psect gtm$zcallvalues pic,con,rel,gbl,shr,noexe,rd,nowrt,novec,quad
+ . = zcvalloc
+ .if eq zc$dtype_string - zc$dtype_'t
+ .ift
+ .ascid /val/
+ .iff
+ .if eq zc$dtype_floating - zc$dtype_'t
+ .ift
+ .f_floating val
+ .iff
+ .'t val
+ .endc
+ .endc
+ zcvalloc = .
+ .psect gtm$zcalltabaab pic,con,rel,gbl,shr,noexe,rd,nowrt,novec,long
+ .restore_psect
+
+ .endm
+
+;----------------------------------------------------------------------------------------------------------------------------------
+
+ .macro output qualifier=required,type,mechanism,position,value
+
+ .if eq zc$retlin
+ .if eq zc$ips
+ return
+ .endc
+ .endc
+ .if ne zc$ips - zc$ip
+ .print ;GT.M EXTERNAL CALL FORMAT ERROR:
+ .error ;NOT ALL INPUT LINES DEFINED BEFORE OUTPUT
+ .mexit
+ .endc
+ .irp $$tmp, <type,mechanism,position>
+ .if b $$tmp
+ .print ;GT.M EXTERNAL CALL FORMAT ERROR: OUTPUT type, mechanism, position
+ .error ;REQUIRED KEYWORD OMITTED
+ .mexit
+ .endc
+ .endr
+
+ .if ndf zc$dtype_'type
+ .print ;GT.M EXTERNAL CALL FORMAT ERROR: OUTPUT type, mechanism, position
+ .error ; UNDEFINED OUTPUT_TYPE KEYWORD: type
+ .mexit
+ .endc
+ .if ndf zc$mech_'mechanism
+ .print ;GT.M EXTERNAL CALL FORMAT ERROR: OUTPUT type, mechanism, position
+ .error ; UNDEFINED OUTPUT_MECHANISM KEYWORD: mechanism
+ .mexit
+ .endc
+ .if eq zc$dtype_string - zc$dtype_'type
+ .if ne zc$mech_descriptor - zc$mech_'mechanism
+ .if ne zc$mech_descriptor64 - zc$mech_'mechanism
+ .print ;GT.M EXTERNAL CALL FORMAT ERROR: OUTPUT type, mechanism, position
+ .error ; ILLEGAL COMBINATION
+ .mexit
+ .endc
+ .endc
+ .endc
+ .if ndf zc$oqual_'qualifier
+ .print ;GT.M EXTERNAL CALL FORMAT ERROR: OUTPUT type, mechanism, position
+ .error ; UNDEFINED INPUT_QUALIFIER KEYWORD: qualifier
+ .mexit
+ .endc
+ .if le position
+ .print ;GT.M EXTERNAL CALL FORMAT ERROR: OUTPUT type, mechanism, position
+ .error ; POSITION MUST BE POSITIVE: position
+ .mexit
+ .endc
+ .if lt zc$num_args - position
+ .print ;GT.M EXTERNAL CALL FORMAT ERROR: OUTPUT type, mechanism, position
+ .error ; POSITION MUST NOT BE GREATER THAN NUMBER OF ARGUMENTS: position, zc$num_args
+ .mexit
+ .endc
+ .if eq zc$mech_value - zc$mech_'mechanism
+ .print ;GT.M EXTERNAL CALL FORMAT ERROR: OUTPUT type, mechanism, position
+ .error ; OUTPUT_MECHANISM MAY NOT BE BY VALUE
+ .mexit
+ .endc
+
+ .if eq zc$oqual_'qualifier - zc$oqual_preallocate
+ .if ne zc$dtype_string - zc$dtype_'type
+ .print ;GT.M EXTERNAL CALL FORMAT ERROR: OUTPUT type, mechanism, position
+ .error ; PREALLOCATE QUALIFIER VALID ONLY WITH STRINGS
+ .mexit
+ .endc
+ .if b value
+ .print ;GT.M EXTERNAL CALL FORMAT ERROR: OUTPUT type, mechanism, position
+ .error ; VALUE REQUIRED WITH PREALLOCATE QUALIFIER
+ .mexit
+ .endc
+ .if le value
+ .print ;GT.M EXTERNAL CALL FORMAT ERROR: OUTPUT type, mechanism, position
+ .error ; PREALLOCATE SIZE MUST BE GREATER THAN ZERO
+ .mexit
+ .endc
+ .if eq zc$mech_descriptor - zc$mech_'mechanism
+ .if gt value - 65535
+ .print ;GT.M EXTERNAL CALL FORMAT ERROR: OUTPUT type, mechanism, position
+ .error ; PREALLOCATE SIZE CANNOT BE GREATER THAN 65535 WITH DESCRIPTOR
+ .mexit
+ .endc
+ .endc
+ .if eq zc$mech_descriptor64 - zc$mech_'mechanism
+ .if gt value - 1048576
+ .print ;GT.M EXTERNAL CALL FORMAT ERROR: OUTPUT type, mechanism, position
+ .error ; PREALLOCATE SIZE CANNOT BE GREATER THAN 1048576 WITH DESCRIPTOR64
+ .mexit
+ .endc
+ .endc
+ .endc
+
+ .byte zc$mech_'mechanism
+ .byte zc$dtype_'type
+ .byte position
+ .byte zc$oqual_'qualifier
+ .if b value
+ .ift
+ .long 0
+ .iff
+ .long value
+ .endc
+ zc$op = zc$op + 1
+ .if lt zc$maxpos - position
+ zc$maxpos = position
+ .endc
+ .endm
+
+;----------------------------------------------------------------------------------------------------------------------------------
+
+ .macro zcinit
+ .macro labelentry cname ;use of this macro is currently suppressed
+ __GTM$ZC.'cname'::
+ .endm
+ .psect gtm$zcallvalues pic,con,rel,gbl,shr,noexe,rd,nowrt,novec,quad
+ zcvalloc = .
+ .psect gtm$zcalltabaab pic,con,rel,gbl,shr,noexe,rd,nowrt,novec,long
+ zctalloc = .
+ zcdef
+ zc$maxpos = -1
+ .endm
+
+;----------------------------------------------------------------------------------------------------------------------------------
+
+ .macro zcallini
+ .psect gtm$zcallvalues pic,con,rel,gbl,shr,noexe,rd,nowrt,novec,quad
+ zcvalloc = .
+ .psect gtm$zcalltabaab pic,con,rel,gbl,shr,noexe,rd,nowrt,novec,long
+ zctalloc = .
+ zcdef
+ zc$maxpos = -1
+ .endm
+
+;----------------------------------------------------------------------------------------------------------------------------------
+
+ .macro zcallfin
+ .if df zc$maxpos
+ endrout
+ .endc
+ .if df zcpack_start
+ endpack
+ .endc
+ .endm
+
+;----------------------------------------------------------------------------------------------------------------------------------
+
+ .macro endrout
+ .if ne zc$ip - zc$ips
+ .print ;GT.M EXTERNAL CALL FORMAT ERROR:
+ .error ;INPUTS DO NOT MATCH INPUT LINES
+ .mexit
+ .endc
+ .if ne zc$op - zc$ops
+ .print ;GT.M EXTERNAL CALL FORMAT ERROR:
+ .error ;OUTPUTS DO NOT MATCH OUTPUT LINES
+ .mexit
+ .endc
+ .if eq zc$ips
+ .if eq zc$ops
+ .if eq zc$retlin
+ return
+ .endc
+ .endc
+ .endc
+ .byte zc$maxpos
+ zc$maxpos = -1
+ zctalloc = .
+ .endm
+
+;----------------------------------------------------------------------------------------------------------------------------------
+
+ .macro endpack
+ .save_psect local_block
+ .psect gtm$zcallpackab pic,con,rel,gbl,shr,noexe,rd,nowrt,novec,long
+ address_32 zcpack_start
+ address_32 zctalloc
+ address_32 zcpack_name
+ .psect gtm$zcalltabaab pic,con,rel,gbl,shr,noexe,rd,nowrt,novec,long
+ .restore_psect
+ .endm
+
+;----------------------------------------------------------------------------------------------------------------------------------
+
+ .macro zcdef
+ $dscdef
+
+ zc$rout_default = 0 ; don't touch out-of-band handling
+ zc$rout_reset = 1 ; set out-of-band handling back to normal
+
+ zc$retc_ = 0 ; Return classes
+ zc$retc_status = 1
+ zc$retc_value = 2
+ zc$retc_ignored = 3
+
+ zc$mech_ = 0 ; Argument-passing mechanisms
+ zc$mech_value = 1
+ zc$mech_reference = 2
+ zc$mech_descriptor = 3
+ zc$mech_descriptor64 = 4
+
+ zc$dtype_ = 0 ; Native data types
+ zc$dtype_string = DSC$K_DTYPE_T
+ zc$dtype_byte = DSC$K_DTYPE_B
+ zc$dtype_byteu = DSC$K_DTYPE_BU
+ zc$dtype_word = DSC$K_DTYPE_W
+ zc$dtype_wordu = DSC$K_DTYPE_WU
+ zc$dtype_long = DSC$K_DTYPE_L
+ zc$dtype_longu = DSC$K_DTYPE_LU
+ zc$dtype_quad = DSC$K_DTYPE_Q
+ zc$dtype_floating = DSC$K_DTYPE_F
+ zc$dtype_double = DSC$K_DTYPE_G
+ zc$dtype_g_floating = DSC$K_DTYPE_G
+ zc$dtype_h_floating = DSC$K_DTYPE_H
+
+ zc$iqual_ = 0 ; Input argument qualifiers
+ zc$iqual_constant = 1
+ zc$iqual_optional = 2
+ zc$iqual_optional_0 = 3
+ zc$iqual_default = 4
+ zc$iqual_required = 5
+ zc$iqual_block = 6
+
+ zc$oqual_ = 0 ; Output argument qualifiers
+ zc$oqual_required = 1
+ zc$oqual_dummy = 2
+ zc$oqual_preallocate = 3
+
+ .endm
+
+;----------------------------------------------------------------------------------------------------------------------------------
+
+ ; create 32-bit address item
+ .macro address_32 item
+ .long item
+ .endm address_32
diff --git a/sr_avms/i2s.mar b/sr_avms/i2s.mar
new file mode 100644
index 0000000..d4d3c8d
--- /dev/null
+++ b/sr_avms/i2s.mar
@@ -0,0 +1,37 @@
+ .title i2s converts integer to string
+
+VAX = 1
+
+;char *i2s(v->num.i)
+
+; The function i2s() recieves an integer as input and returns
+; an address to the first byte after the last character inserted
+; in the globally defined stringpool.
+; STRINGPOOL OFFSETS
+base = 0
+free = 4
+top = 8
+
+ code_psect
+
+ .entry i2s,^m<r2,r3,r4,r5>
+
+ movl stringpool + free,r4 ;store address of stringpool.free
+ movl @4(ap),r5
+ blss 10$ ;if input is negative insert "-"
+ bneq 15$
+ movb #^A"0",(r4)+ ;insert "0" in stringpool
+ movl r4,r0
+ ret
+
+10$: mnegl r5,r5
+ movb #^A"-",(r4)+
+15$: subl2 #24,sp ;get space and convert integer to
+ cvtlp r5,#10,(sp) ;packed decimal, then numeric string
+ cvtps #10,(sp),#10,12(sp)
+ skpc #^A"0",#10,13(sp) ;skip over leading zeroes
+ movc3 r0,(r1),(r4) ;insert string into stringpool and
+ movl r3,r0 ;return address of first byte after
+ ret ;last character insert
+
+ .end
diff --git a/sr_avms/incr_link.c b/sr_avms/incr_link.c
new file mode 100644
index 0000000..8e53b52
--- /dev/null
+++ b/sr_avms/incr_link.c
@@ -0,0 +1,555 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_stdio.h"
+#include "gtm_string.h"
+#include <descrip.h>
+#include <fab.h>
+#include <rab.h>
+#include <rmsdef.h>
+
+#include "zcall.h"
+#include <rtnhdr.h>
+#include "compiler.h"
+#include "obj_gen.h"
+#include "objlangdefs.h"
+#include "urx.h"
+#include "vaxsym.h"
+#include "op.h"
+#include "incr_link.h"
+#include "inst_flush.h"
+#include "op_fgnlookup.h"
+#include "min_max.h"
+
+LITREF char gtm_release_name[];
+LITREF int4 gtm_release_name_len;
+
+GBLREF mident_fixed zlink_mname;
+GBLREF unsigned char *gtm_main_address;
+/* GBLREF unsigned char *gtm_dyn_ch_address; */ /* if we need this variable, it should be defined in gtm$startup */
+
+static short linker_stack_depth;
+static int4 stack_psect;
+static char loading_psect, *reloc_base, *stack;
+static char *load_base[GTM_LASTPSECT], *load_top[GTM_LASTPSECT];
+static int zlink_mname_len;
+
+bool tir(char *buff, int size, urx_rtnref *urx_lcl_anchor);
+
+/* TIR - process Alpha text information and relocation subrecords from a GT.M MUMPS object file record. */
+#define GTMMAIN "GTM$MAIN"
+#define GTMDYNCH "GTM$DYN_CH"
+
+error_def(ERR_INVOBJ);
+error_def(ERR_LOADRUNNING);
+
+/* locc is defined here so that it may be inlined
+ * locc - locate first occurrence of character in string
+ */
+static char *locc(char c, char *string, int length)
+{
+ while (0 < length--)
+ {
+ if (c == *string)
+ return string;
+ ++string;
+ }
+ return 0;
+}
+
+/* ZL_ERROR - perform cleanup and signal errors found in zlinking a mumps object module. */
+void zl_error(unsigned char *fab, bool libr, int4 err, int4 len, char *addr)
+{
+ if (load_base[GTM_LINKAGE])
+ free(load_base[GTM_LINKAGE]);
+ if (!libr)
+ sys$close(fab);
+ else
+ lbr$close(fab); /* close library */
+ if (0 == len)
+ rts_error(VARLSTCNT(1) err);
+ else
+ rts_error(VARLSTCNT(4) err, 2, len, addr);
+}
+
+/* INCR_LINK - read and process a mumps object module. Link said module to currently executing image. */
+bool incr_link(unsigned char *fab, bool libr)
+{
+ struct RAB rab;
+ rhdtyp *hdr, *old_rhead;
+ lab_tabent *lbt_ent, *lbt_bot, *lbt_top, *olbt_ent, *olbt_bot, *olbt_top;
+ int status, rec_count, n1;
+ int4 linkage_size, lit_size, code_size;
+ int4 rhd_diff;
+ char *bptr, *subrec, buff[OBJ_EMIT_BUF_SIZE], fake[SIZEOF(rtn_tabent)];
+ unsigned char *cp, *cp1, tmpch;
+ unsigned short rec_size;
+ urx_rtnref urx_lcl_anchor;
+ char module_name[SIZEOF(mident_fixed)];
+ int order;
+ $DESCRIPTOR(buffdes, buff);
+
+ bptr = buff; /* initialize buffer pointer to first buffer */
+ /* Safety initial values: */
+ loading_psect = -1;
+ reloc_base = -1;
+ load_base[GTM_CODE] = load_top[GTM_CODE] = 0;
+ load_base[GTM_LITERALS] = load_top[GTM_LITERALS] = 0;
+ load_base[GTM_LINKAGE] = load_top[GTM_LINKAGE] = 0;
+ if (!libr)
+ {
+ rab = cc$rms_rab;
+ rab.rab$l_fab = fab;
+ rab.rab$l_ubf = buff;
+ rab.rab$w_usz = OBJ_EMIT_BUF_SIZE;
+ status = sys$connect(&rab);
+ if (RMS$_NORMAL != status)
+ zl_error(fab, libr, status, 0, 0);
+ }
+ /* Although we process the linker commands relating to the GTM_RNAMESAAAAB PSECT,
+ * we never use the data, so we create the image on the stack and ignore it.
+ */
+ load_base[GTM_RNAMESAAAAB] = &fake[0];
+ load_top[GTM_RNAMESAAAAB] = &fake[0] + SIZEOF(rtn_tabent);
+ urx_lcl_anchor.len = 0;
+ urx_lcl_anchor.addr = urx_lcl_anchor.lab = urx_lcl_anchor.next = 0;
+ for (rec_count = 0; rec_count < 3; rec_count++)
+ {
+ if (!libr)
+ {
+ status = sys$get(&rab);
+ rec_size = rab.rab$w_rsz;
+ } else
+ {
+ status = lbr$get_record(fab, 0, &buffdes);
+ rec_size = buffdes.dsc$w_length;
+ bptr = buffdes.dsc$a_pointer;
+ }
+ if (RMS$_EOF == status)
+ zl_error(fab, libr, ERR_INVOBJ, 0, 0);
+ if (!(status & 1))
+ zl_error(fab, libr, status, 0, 0);
+ switch(*(short *)(&bptr[EOBJ$W_RECTYP]))
+ {
+ case EOBJ$C_EMH:
+ if (0 == rec_count)
+ { /* First record must be module header record, subtype main module header. */
+ if (EMH$C_MHD != *(short *)(&bptr[EOBJ$W_SUBTYP]))
+ zl_error(fab, libr, ERR_INVOBJ, 0, 0);
+ zlink_mname_len = bptr[EMH$B_NAMLNG];
+ if (zlink_mname_len > MAX_MIDENT_LEN)
+ zl_error(fab, libr, ERR_INVOBJ, 0, 0);
+ memcpy(&zlink_mname.c[0], &bptr[EMH$B_NAMLNG+1], zlink_mname_len); /* copy module name */
+ zlink_mname.c[zlink_mname_len] = 0;
+ continue;
+ } else if (1 == rec_count)
+ { /* Second record must be module header record, subtype language processor name header. */
+ if (EMH$C_LNM != *(short *)(&bptr[EOBJ$W_SUBTYP]))
+ zl_error(fab, libr, ERR_INVOBJ, 0, 0);
+ n1 = rec_size - 6; /* record size minus bytes used up by header information */
+ if (n1 > gtm_release_name_len)
+ n1 = gtm_release_name_len;
+ for (cp = &bptr[6], cp1 = gtm_release_name; n1 > 0; n1--)
+ {
+ if (*cp++ != (tmpch = *cp1++)) /* verify GT.M release name matches current name */
+ return FALSE;
+ if ('-' == tmpch)
+ break;
+ }
+ /* VMS Linker looks at major and minor version numbers to see if recompile is necessary.
+ * That is, if the current GTM version is V5.2, any object file created using V5.1
+ * or lesser version will automatically be recompiled. But any object file created using
+ * V5.2* version will NOT be automatically recompiled. On the other hand, we want
+ * V5.2-000A to force unconditional recompile on all object files V5.2-000 (and previous)
+ * GTM versions. We want to do that because of C9C05-002003 causing OC_NAMECHK opcode as well
+ * as the xf_namechk/op_namechk transfer table entries to be removed.
+ *
+ * history of object file changes :
+ * code gen changed in V4.4-003A,
+ * dev params in V4.4-004,
+ * $increment/longnames in V4.4-005
+ * OC_NAMECHK opcode nix in V5.2-000A
+ */
+ /* Example &bptr[6] = "GT.M V5.2-000 VMS AXP16-FEB-2007 16:04"
+ * We want the index into bptr where 5.2 starts which is bptr[12]
+ */
+ if (0 > STRNCMP_LIT(&bptr[12], "5.2-000A")) /* was compiled using V5.2-000 */
+ return FALSE;
+ continue;
+ } else
+ zl_error(fab, libr, ERR_INVOBJ, 0, 0);
+ case EOBJ$C_EGSD:
+ if (2 == rec_count)
+ {
+ /* Third record must be global symbol directory record. */
+ subrec = bptr + 8; /* skip over record header to first subrecord header */
+ /* GTM$CODE PSECT program section definition subrecord. */
+ if (EGSD$C_PSC != *(short *)(&subrec[EGPS$W_GSDTYP]))
+ zl_error(fab, libr, ERR_INVOBJ, 0, 0);
+ code_size = *(int4 *)(&subrec[EGPS$L_ALLOC]);
+ subrec += *(short *)(&subrec[EGPS$W_SIZE]); /* skip to next subrecord */
+ /* GTM$LITERALS PSECT program section definition subrecord. */
+ if (EGSD$C_PSC != *(short *)(&subrec[EGPS$W_GSDTYP]))
+ zl_error(fab, libr, ERR_INVOBJ, 0, 0);
+ lit_size = *(int4 *)(&subrec[EGPS$L_ALLOC]);
+ subrec += *(short *)(&subrec[EGPS$W_SIZE]); /* skip to next subrecord */
+ /* GTM$Rname PSECT program section definition subrecord. */
+ if (EGSD$C_PSC != *(short *)(&subrec[EGPS$W_GSDTYP]))
+ zl_error(fab, libr, ERR_INVOBJ, 0, 0);
+ subrec += *(short *)(&subrec[EGPS$W_SIZE]); /* skip to next subrecord */
+ /* $LINKAGE PSECT program section definition subrecord. */
+ if (EGSD$C_PSC != *(short *)(&subrec[EGPS$W_GSDTYP]))
+ zl_error(fab, libr, ERR_INVOBJ, 0, 0);
+ linkage_size = *(int4 *)(&subrec[EGPS$L_ALLOC]);
+ subrec += *(short *)(&subrec[EGPS$W_SIZE]); /* skip to next subrecord */
+ load_base[GTM_LINKAGE] = malloc(code_size + lit_size + linkage_size);
+ load_base[GTM_LITERALS] = load_top[GTM_LINKAGE] = load_base[GTM_LINKAGE] + linkage_size;
+ load_base[GTM_CODE] = load_top[GTM_LITERALS] = load_base[GTM_LITERALS] + lit_size;
+ load_top[GTM_CODE] = load_base[GTM_CODE] + code_size;
+ assert(load_top[GTM_CODE] - load_base[GTM_LINKAGE] == linkage_size + lit_size + code_size);
+ continue;
+ }
+ /* caution : fall through */
+ default:
+ zl_error(fab, libr, ERR_INVOBJ, 0, 0);
+ }
+ break;
+ }
+ linker_stack_depth = 0;
+ for(; ; rec_count++)
+ {
+ if (!libr)
+ {
+ status = sys$get(&rab);
+ rec_size = rab.rab$w_rsz;
+ } else
+ {
+ status = lbr$get_record(fab, 0, &buffdes);
+ rec_size = buffdes.dsc$w_length;
+ bptr = buffdes.dsc$a_pointer;
+ }
+ if (RMS$_EOF == status)
+ {
+ urx_free(&urx_lcl_anchor);
+ zl_error(fab, libr, ERR_INVOBJ, 0, 0);
+ }
+ if (!(status & 1))
+ {
+ urx_free(&urx_lcl_anchor);
+ zl_error(fab, libr, status, 0, 0);
+ }
+ switch(*(short *)(&bptr[EOBJ$W_RECTYP]))
+ {
+ case EOBJ$C_ETIR:
+ assert(*(short *)(&bptr[EOBJ$W_SIZE]) == rec_size);
+ subrec = bptr + 4; /* skip over record header to first subrecord header */
+ if (!tir(subrec, *(short *)(&bptr[EOBJ$W_SIZE]) - (subrec - bptr), &urx_lcl_anchor))
+ {
+ urx_free(&urx_lcl_anchor);
+ zl_error(fab, libr, ERR_INVOBJ, 0, 0);
+ }
+ continue;
+ case EOBJ$C_EGSD:
+ continue;
+ case EOBJ$C_EEOM:
+ if (!libr)
+ {
+ if (RMS$_EOF != sys$get(&rab))
+ {
+ urx_free(&urx_lcl_anchor);
+ zl_error(fab, libr, ERR_INVOBJ, 0, 0);
+ }
+ } else
+ { if (RMS$_EOF != lbr$get_record(fab, 0, &buffdes))
+ {
+ urx_free(&urx_lcl_anchor);
+ zl_error(fab, libr, ERR_INVOBJ, 0, 0);
+ }
+ }
+ break;
+ default:
+ urx_free(&urx_lcl_anchor);
+ zl_error(fab, libr, ERR_INVOBJ, 0, 0);
+ }
+ break;
+ }
+ if (0 != linker_stack_depth)
+ {
+ urx_free(&urx_lcl_anchor);
+ zl_error(fab, libr, ERR_INVOBJ, 0, 0);
+ }
+ hdr = load_base[GTM_CODE];
+ if (!zlput_rname(hdr))
+ {
+ urx_free(&urx_lcl_anchor);
+ /* Copy routine name to local variable because zl_error frees it. */
+ memcpy(&module_name[0], hdr->routine_name.addr, hdr->routine_name.len);
+ zl_error(fab, libr, ERR_LOADRUNNING, hdr->routine_name.len, &module_name[0]);
+ }
+ urx_add(&urx_lcl_anchor);
+ old_rhead = hdr->old_rhead_ptr;
+ lbt_bot = (lab_tabent *)((char *)hdr + hdr->labtab_ptr);
+ lbt_top = lbt_bot + hdr->labtab_len;
+ while (old_rhead)
+ {
+ lbt_ent = lbt_bot;
+ olbt_bot = (lab_tabent *)((char *)old_rhead + old_rhead->labtab_ptr);
+ olbt_top = olbt_bot + old_rhead->labtab_len;
+ for (olbt_ent = olbt_bot; olbt_ent < olbt_top; ++olbt_ent)
+ {
+ for (; lbt_ent < lbt_top; lbt_ent++)
+ {
+ MIDENT_CMP(&olbt_ent->lab_name, &lbt_ent->lab_name, order);
+ if (order <= 0)
+ break;
+ }
+ if ((lbt_ent < lbt_top) && !order)
+ {
+ olbt_ent->lab_ln_ptr = lbt_ent->lab_ln_ptr;
+ olbt_ent->has_parms = lbt_ent->has_parms;
+ } else
+ olbt_ent->lab_ln_ptr = 0;
+ }
+ rhd_diff = (char *)hdr - (char *)old_rhead;
+ old_rhead->src_full_name = hdr->src_full_name;
+ old_rhead->routine_name = hdr->routine_name;
+ old_rhead->vartab_len = hdr->vartab_len;
+ old_rhead->vartab_ptr = hdr->vartab_ptr + rhd_diff;
+ old_rhead->ptext_ptr = hdr->ptext_ptr + rhd_diff;
+ old_rhead->current_rhead_ptr = rhd_diff;
+ old_rhead->temp_mvals = hdr->temp_mvals;
+ old_rhead->temp_size = hdr->temp_size;
+ old_rhead->linkage_ptr = hdr->linkage_ptr;
+ old_rhead->literal_ptr = hdr->literal_ptr;
+ old_rhead = (rhdtyp *)old_rhead->old_rhead_ptr;
+ }
+ urx_resolve (load_base[GTM_CODE], lbt_bot, lbt_top);
+ inst_flush(NULL, 0); /* flush instruction cache for resolved references on VMS, this flushes whole pipe */
+ return TRUE;
+}
+
+bool tir( /* TRUE if no errors encountered; FALSE upon encountering any error */
+ char *buff, /* start of buffer containing TIR commands */
+ int size, /* size of buff */
+ urx_rtnref *urx_lcl_anchor) /* unresovled external local anchor */
+{
+ rhdtyp *rtn;
+ lab_tabent *label, *labtop;
+ mident_fixed rtnid, labid;
+ mstr str;
+ int4 sto_imm_length;
+ unsigned char y;
+ char *top, *loc;
+ int len, len1, lab_len, n;
+ urx_rtnref *urx_rp;
+ urx_addr *urx_tmpaddr;
+ unsigned char *cp1, *cp2, ch;
+ bool now_lower;
+
+ top = buff + size;
+ for(; buff < top;)
+ {
+ switch (loading_psect)
+ {
+ case -1:
+ assert(-1 == reloc_base);
+ break;
+ case GTM_CODE:
+ case GTM_LITERALS:
+ case GTM_RNAMESAAAAB:
+ case GTM_LINKAGE:
+ assert((load_base[loading_psect] <= reloc_base) && (reloc_base <= load_top[loading_psect]));
+ break;
+ default:
+ return FALSE;
+ }
+ /* Note: although the following code uses the term "stack", it should be noted this only works if the
+ * maximum depth of the stack is one (1).
+ */
+ switch(*(short *)(&buff[ETIR$W_RECTYP]))
+ {
+ case ETIR$C_STA_PQ: /* stack PSECT base plus byte offset */
+ if ((0 != linker_stack_depth) || (0 != *(int4 *)(&buff[12]))) /* high-order 32 bits of quadword address */
+ return FALSE;
+ stack_psect = *(int4 *)(&buff[4]);
+ stack = load_base[stack_psect] + *(int4 *)(&buff[8]);
+ linker_stack_depth++;
+ buff += *(short *)(&buff[ETIR$W_SIZE]);
+ continue;
+ case ETIR$C_CTL_SETRB: /* set relocation base */
+ if (0 >= linker_stack_depth)
+ return FALSE;
+ loading_psect = stack_psect;
+ reloc_base = stack;
+ linker_stack_depth--;
+ buff += *(short *)(&buff[ETIR$W_SIZE]);
+ continue;
+ case ETIR$C_STC_BOH_GBL: /* store conditional BSR or hint at global address */
+ case ETIR$C_STC_LDA_GBL: /* store conditional LDA at global address */
+ case ETIR$C_STC_NOP_GBL: /* store conditional NOP at global address */
+ /* These linker commands are used by the OpenVMS Alpha Linker to replace instructions in the
+ * current image with alternative, faster instructions if certain conditions about those
+ * instructions and the displacement from them to other addresses are true. The GT.M linker
+ * does not use the same mechanisms, so these instructions are not generated except in the
+ * routine header JSB prologue (which is never executed for a GT.M module that is dynamically
+ * linked and can therefore be ignored by the GT.M linker).
+ */
+ buff += *(short *)(&buff[ETIR$W_SIZE]);
+ continue;
+ case ETIR$C_STC_LP_PSB: /* store conditional linkage pair plus signature */
+ if (reloc_base + 4 * SIZEOF(int4) > load_top[loading_psect])
+ return FALSE;
+ /* Store dummy values for now (GTM$MAIN and GTM$DYN_CH aren't really used) [lidral] */
+ *((int4 *)reloc_base)++ = 0;
+ *((int4 *)reloc_base)++ = 0;
+ *((int4 *)reloc_base)++ = 0;
+ *((int4 *)reloc_base)++ = 0;
+ buff += *(short *)(&buff[ETIR$W_SIZE]);
+ continue;
+ case ETIR$C_STO_GBL: /* store global */
+ if (reloc_base + 2 * SIZEOF(int4) > load_top[loading_psect])
+ return FALSE;
+ len = buff[4];
+ if ((len > SIZEOF(ZCSYM_PREFIX)) && (0 == MEMCMP_LIT(&buff[5], ZCSYM_PREFIX)))
+ {
+ mval package, extent;
+
+ len1 = len;
+ package.mvtype = extent.mvtype = MV_STR;
+ cp1 = &buff[5] + SIZEOF(ZCSYM_PREFIX) - 1;
+ len1 -= SIZEOF(ZCSYM_PREFIX) - 1;
+ package.str.addr = cp1;
+ loc = locc('.', cp1, len1);
+ assert(0 < loc);
+ package.str.len = (unsigned char *)loc - cp1;
+ len1 -= package.str.len + 1; /* take off package and . */
+ extent.str.len = len1;
+ extent.str.addr = cp1 + 1;
+ if (0 == extent.str.len)
+ return FALSE;
+ if ((package.str.len > 0) && ('_' == *package.str.addr))
+ *package.str.addr = '%';
+ if ('_' == *extent.str.addr)
+ *extent.str.addr = '%';
+ *((int4 *)reloc_base)++ = (int4)op_fgnlookup(&package, &extent);
+ *((int4 *)reloc_base)++ = 0; /* high-order 32 bits of address */
+ } else if (0 != (loc = locc('.', &buff[5], len))) /* global name contains a '.' */
+ {
+ len1 = loc - &buff[5]; /* length of the routine part before the '.' */
+ assert(MAX_MIDENT_LEN >= len1);
+ memcpy(&rtnid.c[0], &buff[5], len1);
+ rtnid.c[len1] = 0;
+ if ('_' == rtnid.c[0])
+ rtnid.c[0] = '%';
+ cp1 = loc + 1;
+ lab_len = len - ((char *)cp1 - &buff[5]); /* length of the label part following the '.' */
+ assert(MAX_MIDENT_LEN >= lab_len);
+ memcpy(&labid.c[0], cp1, lab_len);
+ labid.c[lab_len] = 0;
+ if ('_' == labid.c[0])
+ labid.c[0] = '%';
+ str.addr = &rtnid.c[0];
+ str.len = len1;
+ if (0 != (rtn = find_rtn_hdr(&str))) /* Routine already resolved? */
+ {
+ label = (lab_tabent *)((char *)rtn + rtn->labtab_ptr);
+ labtop = label + rtn->labtab_len;
+ for (; label < labtop && ((lab_len != label->lab_name.len)
+ || memcmp(&labid.c[0], label->lab_name.addr, lab_len)); label++)
+ ;
+ if (label < labtop)
+ {
+ *((int4 *)reloc_base)++ = (char *)&label->lab_ln_ptr;
+ *((int4 *)reloc_base)++ = 0; /* high-order 32 bits of address */
+ buff += *(short *)(&buff[ETIR$W_SIZE]);
+ continue;
+ }
+ }
+ /* This symbol is unknown. Put on the (local) unresolved extern chain --
+ * either for labels or routines
+ */
+ urx_rp = urx_putrtn(&rtnid.c[0], len1, urx_lcl_anchor);
+ urx_putlab(&labid.c[0], lab_len, urx_rp, reloc_base);
+ *((int4 *)reloc_base)++ = 0;
+ *((int4 *)reloc_base)++ = 0;
+ } else if (0 != (loc = locc('$', &buff[5], len))) /* global name contains a '$' */
+ {
+ if ((SIZEOF(GTMMAIN) - 1 == len) && (0 == memcmp(GTMMAIN, &buff[5], len)))
+ *((int4 *)reloc_base)++ = gtm_main_address;
+ else if ((SIZEOF(GTMDYNCH) - 1 == len) && (0 == memcmp(GTMDYNCH, &buff[5], len)))
+ {
+ /* *((int4 *)reloc_base)++ = gtm_dyn_ch_address; */ /* don't need */
+ *((int4 *)reloc_base)++ = 0; /* dummy value; GT.M frames are not machine frames */
+ } else
+ return FALSE;
+ *((int4 *)reloc_base)++ = 0; /* high-order 32 bits of address */
+ } else /* It's a bona fide global name. */
+ {
+ memcpy(&rtnid.c[0], &buff[5], len);
+ rtnid.c[len] = 0;
+ assert(zlink_mname_len > 0 && zlink_mname_len <= MAX_MIDENT_LEN);
+ if (zlink_mname_len == len && !memcmp(&zlink_mname.c[0], &rtnid.c[0], len)) /* program name */
+ {
+ *((int4 *)reloc_base)++ = load_base[GTM_CODE];
+ *((int4 *)reloc_base)++ = 0; /* high-order 32 bits of address */
+ } else
+ {
+ if ('_' == rtnid.c[0])
+ rtnid.c[0] = '%';
+ str.addr = &rtnid.c[0];
+ str.len = len;
+ if (0 != (rtn = find_rtn_hdr(&str)))
+ *((int4 *)reloc_base)++ = rtn->linkage_ptr;
+ else
+ {
+ urx_rp = urx_putrtn(&rtnid.c[0], len, urx_lcl_anchor);
+ urx_tmpaddr = malloc(SIZEOF(urx_addr));
+ urx_tmpaddr->next = urx_rp->addr;
+ urx_tmpaddr->addr = reloc_base;
+ urx_rp->addr = urx_tmpaddr;
+ *((int4 *)reloc_base)++ = 0;
+ }
+ *((int4 *)reloc_base)++ = 0;
+ }
+ }
+ buff += *(short *)(&buff[ETIR$W_SIZE]);
+ continue;
+ case ETIR$C_STO_IMM: /* store immediate */
+ sto_imm_length = *(int4 *)(&buff[4]);
+ if (reloc_base + sto_imm_length > load_top[loading_psect])
+ return FALSE;
+ memcpy(reloc_base, &buff[8], sto_imm_length);
+ reloc_base += sto_imm_length;
+ buff += *(short *)(&buff[ETIR$W_SIZE]);
+ continue;
+ case ETIR$C_STO_LW: /* store longword */
+ if ((0 >= linker_stack_depth) || (reloc_base + SIZEOF(int4) > load_top[loading_psect]))
+ return FALSE;
+ *((int4 *)reloc_base)++ = stack;
+ linker_stack_depth--;
+ buff += *(short *)(&buff[ETIR$W_SIZE]);
+ continue;
+ case ETIR$C_STO_OFF: /* store offset to PSECT */
+ if ((0 >= linker_stack_depth) || (reloc_base + 2 * SIZEOF(int4) > load_top[loading_psect]))
+ return FALSE;
+ *((int4 *)reloc_base)++ = stack; /* low-order 32 bits of quadword address */
+ *((int4 *)reloc_base)++ = 0; /* high-order 32 bits always zero */
+ linker_stack_depth--;
+ buff += *(short *)(&buff[ETIR$W_SIZE]);
+ continue;
+ default:
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
diff --git a/sr_avms/mdefsp.h b/sr_avms/mdefsp.h
new file mode 100644
index 0000000..cc7b4a8
--- /dev/null
+++ b/sr_avms/mdefsp.h
@@ -0,0 +1,130 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef MDEFSP_included
+#define MDEFSP_included
+
+#define INT8_SUPPORTED
+#define INT8_FMT "%llu"
+#define INT8_FMTX "[0x%llx]"
+#define INT8_NATIVE /* on Alpha processors, 8 byte operations are native to the chip and hence atomic */
+
+#include <builtins.h>
+#include <lib$routines>
+
+#define insqhi vax_insqhi
+#define insqti vax_insqti
+#define remqhi vax_remqhi
+#define remqti vax_remqti
+
+/* Use our own malloc and free to guarantee return value is checked for error condition. */
+#ifdef __cplusplus
+extern "C" void *gtm_malloc(int);
+extern "C" void gtm_free(void *);
+/* extern "C" int gtm_memcmp (const void *, const void *, int); */
+#endif
+
+/* NOTE: this redefines stringpool.free as stringpool.gtm_free, but that appears benign. */
+#define malloc gtm_malloc
+#define free gtm_free
+
+#define rts_error lib$signal
+#ifdef __cplusplus
+#define error_def(x) extern x
+#else
+#define error_def(x) globalvalue x
+#endif
+
+#define INTERLOCK_ADD(X,Y,Z) (__ATOMIC_ADD_LONG((sm_vint_ptr_t)(X), (Z)) + (Z))
+
+#undef BIGENDIAN
+
+#ifdef __cplusplus
+#define GBLDEF
+#define GBLREF extern
+#define LITDEF const
+#define LITREF extern const
+#else
+#define GBLDEF globaldef
+#define GBLREF globalref
+#define LITDEF const globaldef
+#define LITREF const globalref
+#endif
+
+/* Reserve enough space in routine header for call to GTM$MAIN. */
+#define RHEAD_JSB_SIZE 12
+typedef struct
+{
+ unsigned short mvtype;
+ unsigned e : 7;
+ unsigned sgn : 1;
+ unsigned char fnpc_indx; /* Index to fnpc_work area this mval is using */
+ mstr str ;
+ int4 m[2] ;
+} mval;
+/* Another version of mval with byte fields instead of bit fields */
+typedef struct
+{
+ unsigned short mvtype;
+ unsigned char sgne;
+ unsigned char fnpc_indx; /* Index to fnpc_work area this mval is using */
+ mstr str ;
+ int4 m[2] ;
+} mval_b;
+
+#define VAR_START(a, b) va_start(a, b)
+#define VARLSTCNT(a) /* stub for argument count. VAX CALLS instruction pushes count automatically */
+
+#define CHF_MCH_DEPTH chf$q_mch_depth
+#define CHF_MCH_SAVR0 chf$q_mch_savr0
+
+typedef struct
+{
+ short flags;
+ short rsa_offset;
+ unsigned char reserved_1;
+ unsigned char fret;
+ short signature_offset;
+ void *entry; /* actually a pointer to a code address, but not representable directly in C */
+ int4 reserved_2; /* other half of quadword pointer (entry) not allocated by C compiler */
+ int4 size;
+ short reserved_3;
+ short entry_length;
+} alpha_procedure_descriptor;
+
+#define CODE_ADDRESS(func) gtm$code_address(func)
+#define GTM_CONTEXT(func) func
+
+/* External symbols (global symbols defined in another module) are represented as belonging to this PSECT: */
+#define GTM_ANOTHER_MODULE -1
+
+/* Under Alpha AXP OpenVMS, the procedure value of a module is defined in the PSECT used for linkage: */
+#define GTM_MODULE_DEF_PSECT GTM_LINKAGE
+
+#define OS_PAGELET_SIZE 512
+#define OS_VIRTUAL_BLOCK_SIZE OS_PAGELET_SIZE
+
+typedef volatile int4 latch_t;
+typedef volatile uint4 ulatch_t;
+
+#define INSIDE_CH_SET "ISO8859-1"
+#define OUTSIDE_CH_SET "ISO8859-1"
+#define EBCDIC_SP 0x40
+#define NATIVE_SP 0x20
+#define DEFAULT_CODE_SET ascii /* enum ascii defined in io.h */
+
+#define util_out_print2 util_out_print
+
+int adawi(short x, short *y);
+
+#define CACHELINE_SIZE 256 /* alpha cache line size */
+
+#endif /* MDEFSP_included */
diff --git a/sr_avms/mem_access.c b/sr_avms/mem_access.c
new file mode 100644
index 0000000..085bde3
--- /dev/null
+++ b/sr_avms/mem_access.c
@@ -0,0 +1,49 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#define PRT$C_NA 0
+
+/* Set a region of memory to be inaccessable */
+void set_noaccess(na_page, prvprt)
+unsigned char *na_page[2]; /* array of addresses: the low and high addresses to be protected */
+unsigned char *prvprt; /* A place to save the previous protection, should the caller later
+ wish to restore the protection */
+{
+ unsigned status;
+ unsigned char *actual[2]; /* array of addresses: actual range of addresses affected by sys$setprt */
+
+ return; /* STUB */
+
+ actual[0] = actual[1] = NULL;
+/* status = sys$setprt (na_page, 0, 0, PRT$C_NA, prvprt); /* [lidral] */
+ status = sys$setprt (na_page, actual, 0, PRT$C_NA, prvprt);
+ if (!(status & 1))
+ rts_error(VARLSTCNT(1) status);
+ return;
+}
+
+/* Return memory protection to the state of affairs which existed prior to a call to set_noaccess */
+void reset_access(na_page, oldprt)
+unsigned char *na_page[2]; /* array of addresses: the low and high addresses to be protected */
+unsigned char oldprt; /* A place to save the previous protection, should the caller later
+ wish to restore the protection */
+{
+ unsigned status;
+
+ return; /* STUB */
+
+ status = sys$setprt (na_page, 0, 0, oldprt, 0);
+ if (!(status & 1))
+ rts_error(VARLSTCNT(1) status);
+ return;
+}
diff --git a/sr_avms/memcmp.mar b/sr_avms/memcmp.mar
new file mode 100644
index 0000000..59b42ce
--- /dev/null
+++ b/sr_avms/memcmp.mar
@@ -0,0 +1,27 @@
+ .title memcmp() compare two char strings
+
+ ;memcmp(a,b,len)
+ ;char *a,*b;
+ ;int len;
+
+ ;compare two character strings
+ ;return 0 iff they are equal
+ ;return < 0 if a < b and > 0 if a > b
+
+ code_psect
+
+ .entry memcmp,^m<r2,r3>
+
+ cmpc3 12(ap), at 4(ap), at 8(ap)
+ blssu 10$
+ bnequ 20$
+ clrl r0
+ ret
+
+10$: movl #-1,r0
+ ret
+
+20$: movl #1,r0
+ ret
+
+ .end
diff --git a/sr_avms/mum_tstart.m64 b/sr_avms/mum_tstart.m64
new file mode 100644
index 0000000..78e445b
--- /dev/null
+++ b/sr_avms/mum_tstart.m64
@@ -0,0 +1,96 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ;
+; Copyright 2001, 2008 Fidelity Information Services, Inc ;
+; ;
+; This source code contains the intellectual property ;
+; of its copyright holder(s), and is made available ;
+; under a license. If you do not know the terms of ;
+; the license, please stop and do not read further. ;
+; ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ .title mum_tstart (re)start a GT.M frame from a sys$unwind
+
+ G_MSF
+ base_frame
+
+; The code PSECT must have the MIX attribute in order to have read access to it.
+$CODE$ = "MUM_TSTART,QUAD,PIC,CON,REL,LCL,SHR,EXE,RD,MIX,NOWRT"
+
+; mum_tstart - (re)start a GT.M MUMPS stack frame
+;
+; mum_tstart calls trans_code if proc_act_type is non-zero. Then
+; mum_tstart (re)loads the GT.M registers (including the code address)
+; from the GT.M MUMPS stack frame, ensures the instruction cache and
+; memory are consistent, reloads r10 with the current address of $TEST
+; (mis-named "dollar_truth"), and then jumps to the code address indicated
+; by the GT.M MUMPS stack frame.
+;
+; mum_tstart is only invoked by sys$unwind after unwinding from a
+; signal and not via the standard call mechanism. Therefore,
+; the context is that of the routine executing in the frame to
+; which sys$unwind unwound and not to mum_tstart. Consequently,
+; we do not know what value may be in any of the registers and
+; must establish pseudo PC-relative addressing in order to refer
+; to any data, including the addresses of external items.
+
+ $code_section
+
+; Pseudo linkage PSECT.
+
+A_dollar_truth: .address dollar_truth ; actually, $TEST
+A_frame_pointer: .address frame_pointer
+A_proc_act_type: .address proc_act_type
+
+L_trans_code: .linkage_pair trans_code
+L_error_return: .linkage_pair error_return
+
+ $routine name=mum_tstart,entry=mum_tstart_ca,kind=null
+
+ br r13, establish_base ; set up for PC-relative addressing
+establish_base:
+ .base r13, establish_base
+
+ lda sp, -ARG_AREA_SZ(fp) ; (re)establish argument list area
+ ldq r0, A_proc_act_type
+ ldq_u r28, (r0)
+ extwl r28, r0, r28
+ beq r28, l1
+ ldq r26, L_trans_code
+ ldq r27, L_trans_code+8
+ mov r31, r25
+ jsr r26, (r26)
+l1: ; We can't use getframe here with its imbedded $call invocation so hard code a getframe equivalent using
+ ; the lobotomized manual linkages this module needs to use..
+ ; start GETFRAME expansion
+ ; A_frame_pointer must be address of quadword containing the address of frame_pointer
+ ldq r12, A_frame_pointer
+ ldl r12, (r12)
+ lda r8, msf$flags_off(r12)
+ ldq_u r9, (r8)
+ extbl r9, r8, r9
+ and r9, sff_etrap_err, r9
+ beq r9, l2
+ ; $call ERROR_RETURN, set_arg_info=false, nonstandard=true
+ ldq r26, L_error_return
+ ldq r27, L_error_return+8
+ mov r31, r25
+ jsr r26,(r26)
+ ldq r12, A_frame_pointer
+ ldl r12, (r12)
+l2: ldl r8, msf$l_symtab_off(r12)
+ ldl r9, msf$temps_ptr_off(r12)
+ ldl r13, msf$ctxt_off(r12)
+ ldl r28, msf$literal_ptr_off(r12)
+ cmovne r28, r28, r14 ; only copy to r14 if initialized to non-zero value
+ ldl r26, msf$mpc_off(r12)
+ ; end getframe expansion
+ br r0, establish_base2 ; r13 modified by getframe, set up another (temporary) base
+establish_base2:
+ .base r0, establish_base2
+ ldq r10, A_dollar_truth
+ imb ; resynchronize instruction cache
+ ret r26
+
+ $end_routine name=mum_tstart
+
+ .end
diff --git a/sr_avms/mumps_binding.max b/sr_avms/mumps_binding.max
new file mode 100644
index 0000000..a32a1b9
--- /dev/null
+++ b/sr_avms/mumps_binding.max
@@ -0,0 +1,96 @@
+;----------------------------------------------------------------------------------------------------------------------------------
+
+ .macro MUMPS_BINDING ENTRYREF, LINKNAME, OUTPUT=no, ?rtnaddr, ?lbladdr
+
+ fgnout_yes = 1
+ fgnout_ye = 1
+ fgnout_y = 1
+ fgnout_no = 0
+ fgnout_n = 0
+
+ .irp $$tmp, <ENTRYREF, LINKNAME>
+ .if b $$tmp
+ .print ;MUMPS BINDING FORMAT ERROR: MUMPS ENTRYREF, LINKNAME, OUTPUT
+ .error ;REQUIRED KEYWORD OMITTED
+ .mexit
+ .endc
+ .endr
+
+ .if ndf fgnout_%EDIT(OUTPUT,LOWERCASE)
+ .print ;MUMPS BINDING FORMAT ERROR: MUMPS ENTRYREF, LINKNAME, OUTPUT
+ .error ;OUTPUT MUST BE YES OR NO
+ .mexit
+ .endc
+
+ lablen = %LOCATE(<^>,ENTRYREF)
+ entlen = %LENGTH(ENTRYREF)
+ .if eq %LENGTH(ENTRYREF)-lablen
+ .print ;MUMPS BINDING FORMAT ERROR: MUMPS ENTRYREF, LINKNAME, OUTPUT
+ .error ;MUMPS ENTRYREF MUST SPECIFY ROUTINE
+ .mexit
+ .endc
+
+ rtnlen = entlen - lablen - 1
+ rstart = lablen+1
+
+ .if gt lablen-31
+ .print ;MUMPS BINDING FORMAT ERROR: MUMPS ENTRYREF, LINKNAME, OUTPUT
+ .error ;LABELS ARE LIMITED TO 31 CHARACTERS
+ .mexit
+ .endc
+
+ .if gt rtnlen-31
+ .print ;MUMPS BINDING FORMAT ERROR: MUMPS ENTRYREF, LINKNAME, OUTPUT
+ .error ;ROUTINES ARE LIMITED TO 31 CHARACTERS
+ .mexit
+ .endc
+
+ $routine LINKNAME, entry=%string(LINKNAME)_CA, kind=stack, -
+ saved_regs=<r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15>, -
+ size=<<<$RSA_END+<7*8>+15>/16>*16>
+
+ $linkage_section
+ ; Always generate the routine symbol in upper case so that routine's linkage
+ ; works correctly even if the call table contains lower case routine name and
+ ; the table is compiled with /NAMES={LOWERCASE,AS_IS}.
+rtnaddr: .address %EDIT(%EXTRACT(rstart, rtnlen, ENTRYREF),UPCASE)
+L_GTM$MAIN: .linkage_pair GTM$MAIN
+
+ .if le entlen-31
+ ; The total length is within 31 chars. Generate a symbolic reference
+ ; in the $linkage_section.
+lbladdr: .address %EXTRACT(rstart, rtnlen, ENTRYREF).%EXTRACT(0, lablen, ENTRYREF)
+ fgnlab_unresolved = 0
+ .else
+lbladdr: .address lblname
+ fgnlab_unresolved = lablen
+ ; The MACRO compiler doesn't allow the symbol names of the form routine.label
+ ; if the total length exceeds 31. So, generate a reference to a location in
+ ; $data_section that stores the label string.
+ $data_section
+lblname: .ascii "%EXTRACT(0, lablen, ENTRYREF)"
+ .endc
+
+
+ $code_section
+
+ .base r27, $ls
+
+; Copy argument registers and argument information register to stack adjacent to any arguments that may be on stack.
+ stq r21, $SIZE-8(fp)
+ stq r20, $SIZE-16(fp)
+ stq r19, $SIZE-24(fp)
+ stq r18, $SIZE-32(fp)
+ stq r17, $SIZE-40(fp)
+ stq r16, $SIZE-48(fp)
+ stq r25, $SIZE-56(fp)
+ ldq r0, L_GTM$MAIN
+ ldq r1, L_GTM$MAIN+8
+
+; gtm$fgncall (A(MUMPS routine), A(MUMPS label), OUTPUT (yes or no), A(start of arguments on stack))
+ $call GTM$FGNCALL, args=<rtnaddr, lbladdr, fgnout_%EDIT(OUTPUT,LOWERCASE)/A, $SIZE-56(fp)/A, fgnlab_unresolved/A>
+ $return
+
+ $end_routine name=LINKNAME
+
+ .endm
diff --git a/sr_avms/mutex.mar b/sr_avms/mutex.mar
new file mode 100644
index 0000000..b860319
--- /dev/null
+++ b/sr_avms/mutex.mar
@@ -0,0 +1,952 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ;
+; Copyright 2000, 2007 Fidelity Information Services, Inc ;
+; ;
+; This source code contains the intellectual property ;
+; of its copyright holder(s), and is made available ;
+; under a license. If you do not know the terms of ;
+; the license, please stop and do not read further. ;
+; ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ .title MUTEX GT.M Mutex Control (VMS)
+;
+; General:
+; Multiple readers are allowed at one time, but only one writer (no readers while there is a writer).
+; A write request blocks access to additional readers until after the writer is granted crit and then
+; releases it. Freeze allows readers, but not writers, and write pendings do not block new readers.
+;
+; Interface:
+; void mutex_init(addr, n, crash) - Initialize a mutex at addr with n queue slots
+; If crash is TRUE, then this is a "crash" reinitialization;
+; otherwise, it's a "clean" initialization
+; enum cdb_sc mutex_lockr(addr, seq, flag, spinparms) - Read access to mutex at addr
+; enum cdb_sc mutex_lockw(addr, seq, flag, spinparms) - Write access to mutex at addr
+; enum cdb_sc mutex_lockwim(addr, seq, flag) - Write access to mutex at addr; if cannot lock, immediately
+; return cdb_sc_nolock
+; enum cdb_sc mutex_lockw_ccp(addr, seq, flag, k) - Write access to mutex at addr; if cannot lock, place CCP in
+; queue for "wakeup" and return cdb_sc_nolock (do NOT hibernate)
+; enum cdb_sc mutex_wtor(addr, rflag, wflag) - Change write access to mutex at addr to read access, do a wakeup
+; enum cdb_sc mutex_unlockr(addr, seq, flag) - Unlock read access to mutex at addr
+; enum cdb_sc mutex_unlockw(addr, seq, flag) - Unlock write access to mutex at addr
+;
+; For routines taking the seq argument, if seq != crash count, return cdb_sc_critreset.
+;
+; See GDSBT.H for related C declarations
+;
+; Mutex structure (must be quadword aligned):
+;
+; ---------------------------------
+; | write pending | ownership cnt | 0
+; ---------------------------------
+; | # of que slots| crash count |
+; ---------------------------------
+; // //
+; ---------------------------------
+; |_ fl waiting process que head _| 64 MUTEX_PROCHEAD
+; |_ bl _|
+; |_ --- unused --- _|
+; | --- unused --- |
+; ---------------------------------
+; // //
+; ---------------------------------
+; |_ fl unused slots queue head _| 128 MUTEX_FREEHEAD
+; |_ bl _|
+; |_ --- unused --- _|
+; | --- unused --- |
+; ---------------------------------
+; |_ fl first queue entry _|
+; |_ bl _|
+; |_ pid _|
+; | super_crit [CCP use only]* |
+; ---------------------------------
+; |_ fl second queue entry _|
+; |_ bl _|
+; |_ pid _|
+; | super_crit [CCP use only]* |
+; ---------------------------------
+; : : : : :
+; ---------------------------------
+; |_ fl last queue entry _|
+; |_ bl _|
+; |_ pid _|
+; | super_crit [CCP use only]* |
+; ---------------------------------
+;
+; * Note: only one entry at a time (at the head of the waiting process queue) will ever use this field.
+
+; Offsets from the beginning of the mutex structure:
+
+MUTEX_OWNCNT = 0
+MUTEX_WRTPND_MASK = ^X10000
+MUTEX_WRTPND_BIT = 16
+MUTEX_WRTPND = 2
+MUTEX_CRASHCNT = 4
+MUTEX_QUESLOTS = 6
+MUTEX_PROCHEAD = 64 ; 8
+MUTEX_FREEHEAD = 128 ; 24
+
+; Offsets of spin counts in mutex_spin_parms, keep these offsets in sync with mutex_spin_parms_struct definition in gdsbt.h
+MUTEX_HARD_SPIN_COUNT_OFFSET = 0
+MUTEX_SLEEP_SPIN_COUNT_OFFSET = 4
+MUTEX_SPIN_SLEEP_MASK_OFFSET = 8
+
+; Offsets from the beginning of a queue entry:
+MUTEX_PID = 8
+MUTEX_SUPER_CRIT = 12
+
+; Retry counts for interlocked queue instructions:
+QUANT_RETRY = 10000
+QUEUE_RETRY = 255
+MAX_WAKE = 37 ;not actually a retry count but another queue loop limiter
+REST_FREQ = ^X3 ;sleep mask of complemented low order bits
+
+; NOTE: The following definitions correspond to items of the same name in CDB_SC.H.
+; Make sure that they are maintained compatibly!
+cdb_sc_nolock = 3
+cdb_sc_dbccerr = 81 ; 'Q'
+cdb_sc_critreset = 82 ; 'R'
+
+
+; NOTE: The following definition corresponds to an item of the same name,
+; defined in CCP.H via inclusion of CCPACT_TAB.H.
+; Make sure that it is maintained compatibly!
+CCTR_SCRIT = 10 ; Super_crit granted
+
+ $psldef
+ $efndef
+
+ code_psect
+
+; void mutex_init(mutex_struct *addr, int N, bool crash);
+;
+; Initialize a mutex with N que entries. If crash is TRUE, then this is
+; a "crash" reinitialization; otherwise it's a "clean" initialization.
+
+
+ .entry mutex_init,^m<r2,r3,r4,r5,r6>
+
+ movl 4(ap),r2 ;r2 -> mutex structure
+ movl 8(ap),r3 ;r3 = number of queue entries
+ blbs 12(ap),crash ;branch if this is a crash reinitialization
+
+; Clean initialization
+clean: movw r3,MUTEX_QUESLOTS(r2) ;set the number of queue entries
+
+ ;initialize the waiting process queue to be empty
+ .disable flagging
+ clrq MUTEX_PROCHEAD(r2)
+ clrq MUTEX_PROCHEAD+8(r2)
+
+ ;initialize the free queue to be empty
+ movaq MUTEX_FREEHEAD(r2),r1
+ clrq (r1)
+ clrq 8(r1)
+
+ movaq 16(r1),r0 ;r0 -> first free entry
+ clrq (r0) ;clear it
+ clrq 8(r0)
+ .enable flagging
+ decl r3
+
+ ;insert each entry into the free queue
+10$: insqti (r0),(r1)
+ bcs 30$ ;branch if the secondary interlock failed
+ addl #16,r0
+ sobgtr r3,10$
+
+ ;initialize the rest of the mutex structure
+ movw #-1,(r2) ;initial semaphore value = -1
+ clrw MUTEX_WRTPND(r2) ;initial flags value = 0;
+ blbs 12(ap),20$ ;if this was a crash, don't clear the count
+ clrw MUTEX_CRASHCNT(r2)
+20$: ret
+
+30$: pushl #ERR_DBCCERR
+ calls #1,G^LIB$SIGNAL
+ ret
+
+
+; Crash reinitialization
+crash: bbssi #0,MUTEX_WRTPND(r2),10$ ;set the write pending bit
+10$: adawi #1,MUTEX_CRASHCNT(r2) ;increment the crash sequence number
+ .disable flagging
+ clrq MUTEX_FREEHEAD(r2) ;assure that no one goes into the wait queue
+ .enable flagging
+
+ ;wake up all sleeping processes; they will crash
+ movab MUTEX_PROCHEAD(r2),r4
+ movl r4,r5 ;r4,r5 -> queue head
+
+ addw3 #1,MUTEX_QUESLOTS(r2),r0 ;r0 = number of queue slots
+ cvtwl r0,r0
+ ashl r0,#4,r0 ;scale by 16
+ movab MUTEX_PROCHEAD(r2)[r0],r6 ;r6 -> top of the queue array
+
+20$: movl (r4),r0
+ beql clean ;the wait queue was empty; do a clean initialization
+
+ addl r0,r4 ;r4 probably -> queue entry
+ cmpl r4,r5 ;if r4 -> queue head, then loop is done
+ blequ clean ;if r4 -> below queue head, then the queue is corrupt
+ ;... either way, do a clean initialization
+ cmpl r4,r6 ;if r4 -> above queue top, then the queue is corrupt
+ bgequ clean ;... so do a clean initialization
+ bitb r4,#3 ;if r4 is not quadword aligned, then the queue is corrupt
+ beqlu 30$
+ brw clean ;... so do a clean initialization
+
+ ;otherwise, wake up the process
+30$: pushal MUTEX_PID(r4)
+ calls #1,G^crit_wake
+ brb 20$
+
+
+; enum cdb_sc mutex_lockr(mutex_struct *addr, int4 crash_count, uint4 *read_lock, mutex_spin_parms_ptr_t spin_parms);
+;
+; Lock read access to the mutex at addr
+
+
+ .entry mutex_lockr,^m<r2,r3,r4,r5,r6>
+
+ movl 4(ap),r2 ;r2 -> mutex structure
+ movl 12(ap),r4 ;r4 -> read lock flag
+
+10$: cmpw 8(ap),MUTEX_CRASHCNT(r2) ;has the crash count changed?
+ bneq 30$ ;if so, return an error
+
+ movl #1,(r4) ;set the read lock flag
+;+
+;
+; Moser and Jordan (Compaq Computer Corporation)) 29-Mar-2001
+;
+; Change manipulation of the mutex owner count and write pending flag
+; to a single atomic operation using ldl_l/stl_c.
+; adawi #1,(r2) ;increment the semaphore
+; bbssi #1,MUTEX_WRTPND(r2),20$ ;force access to the write pending byte
+;20$: blbs MUTEX_WRTPND(r2),40$ ;if write pending, sleep and try again later
+;-
+
+ ASSUME MUTEX_WRTPND EQ MUTEX_OWNCNT+2
+ evax_mb ; need memory barrier
+15$:
+ evax_ldll r16,(r2) ; read mutex locked
+ bbs #16,r16,40$ ; skip, if write pending
+ incw r16 ; incr owner count
+ evax_stlc r16,(r2) ; store mutex
+ .branch_unlikely
+ evax_beq r16,15$ ; retry, if store failed
+ evax_mb ; need memory barrier
+
+ clrl r0 ;return success (cdb_sc_normal == 0)
+ ret
+
+30$: movzbl #cdb_sc_critreset,r0 ;return error
+ ret
+
+40$: movl 16(ap),r6 ;spin_parms
+ movl MUTEX_HARD_SPIN_COUNT_OFFSET(r6),r6 ;spin_parms->mutex_hard_spin_count
+ bsbw sleep ;(clears the read lock flag)
+ brb 10$ ;try again
+
+
+; enum cdb_sc mutex_lockw(mutex_struct *addr, int4 crash_count, uint4 *write_lock, mutex_spin_parms_ptr_t spin_parms);
+;
+; Lock write access to the mutex at addr
+
+
+ .entry mutex_lockw,^m<r2,r3,r4,r5,r6>
+
+ movl 4(ap),r2 ;r2 -> mutex structure
+ movl 12(ap),r4 ;r4 -> write lock flag
+
+10$: cmpw 8(ap),MUTEX_CRASHCNT(r2) ;has the crash count changed?
+ bneq 40$ ;if so, return an error
+
+;+
+; Moser and Jordan (Compaq Computer Corporation)) 29-Mar-2001
+;
+; Change manipulation of the mutex owner count and write pending flag
+; to a single atomic operation using ldl_l/stl_c.
+;
+; bbssi #0,MUTEX_WRTPND(r2),20$ ;set the write pending bit
+;20$: movl #1,(r4) ;set the write lock flag
+; adawi #1,(r2) ;increment the semaphore
+; bgtr 50$ ;branch if semaphore > 0 - there are other owners
+;
+; bbssi #0,MUTEX_WRTPND(r2),30$ ;set write pending again
+;30$: tstw (r2) ;see if any other process has entered crit
+; bneq 60$ ;if so, sleep and try again later
+;-
+ evax_mb ; need memory barrier
+ movl #MUTEX_WRTPND_MASK,r18 ; Get a write pending mask in R18
+ ASSUME MUTEX_WRTPND EQ MUTEX_OWNCNT+2
+15$: evax_ldll r16,(r2) ; read mutex locked
+ evax_extwl r16,#0,r17 ; extract owner count from low word
+ evax_addq r17,#1,r28 ; Owner plus 1
+ evax_extwl r28,#0,r28 ; maintain owner count as a word
+ evax_cmoveq r28,#0,r17 ; If zero we can own, otherwise don't change
+ evax_addq r18,r17,r16 ; set write pending bit
+ evax_stlc r16,(r2) ; store mutex
+ .branch_unlikely
+ evax_beq r16,15$ ; retry, if store failed
+ evax_mb ; need memory barrier
+ evax_bne r28,60$ ; branch, if wait flag set
+
+ movl #1,(r4) ;set the write lock flag
+
+ clrl r0 ;return success (cdb_sc_normal == 0)
+ ret
+
+40$: movzbl #cdb_sc_critreset,r0 ;return error
+ ret
+
+;+
+; Moser and Jordan (Compaq Computer Corporation)) 29-Mar-2001
+;
+; The additional bbssi is not required - with the prior use of
+; multiple interlock operations, the probablity that a writer
+; unlocked the mutex was much greater.
+
+;50$: bbssi #0,MUTEX_WRTPND(r2),60$ ;set write pending again
+;-
+
+60$: movl 16(ap),r6 ;spin_parms
+ movl MUTEX_HARD_SPIN_COUNT_OFFSET(r6),r6 ;spin_parms->mutex_hard_spin_count
+ bsbw sleep ;(clears the write lock flag)
+ brb 10$ ;try again
+
+
+; enum cdb_sc mutex_lockwim(mutex_struct *addr, int4 crash_count, uint4 *write_lock);
+;
+; Lock write access to the mutex at addr; if cannot lock, immediately return cdb_sc_nolock
+
+
+ .entry mutex_lockwim,^m<r2>
+
+ movl 4(ap),r2 ;r2 -> mutex structure
+
+ cmpw 8(ap),MUTEX_CRASHCNT(r2) ;has the crash count changed?
+ bneq 30$ ;if so, return error condition
+
+;+
+; Moser and Jordan (Compaq Computer Corporation)) 29-Mar-2001
+;
+; Change manipulation of the mutex owner count and write pending flag
+; to a single atomic operation using ldl_l/stl_c.
+;
+; bbssi #0,MUTEX_WRTPND(r2),10$ ;set the write pending bit
+;10$: adawi #1,(r2) ;increment the semaphore
+; bgtr 40$ ;branch if semaphore > 0 - there are other owners
+;
+; bbssi #0,MUTEX_WRTPND(r2),20$ ;set write pending again
+;20$: tstw (r2) ;see if any other process has entered crit
+; bneq 40$ ;branch if so
+;-
+ evax_mb ; need memory barrier to force all writes out
+15$: movl #MUTEX_WRTPND_MASK,r19 ; Get a write pending mask in R19
+ ASSUME MUTEX_WRTPND EQ MUTEX_OWNCNT+2
+ evax_ldll r16,(r2) ; read mutex locked
+ evax_addq r16,#1,r19 ; Owner plus 1
+ evax_extwl r19,#0,r28 ; extract owner count
+ tstl r28 ; Can we obtain the mutex?
+ bneq 40$ ; If other owners then no, branch and return error
+ evax_stlc r19,(r2) ; store mutex
+ .branch_unlikely
+ evax_beq r19,15$ ; retry, if store failed
+ evax_mb ; need memory barrier
+
+ movl #1, at 12(ap) ;set the write lock flag
+ clrl r0 ;return success (cdb_sc_normal == 0)
+ ret
+
+30$: movzbl #cdb_sc_critreset,r0 ;return error
+ ret
+
+;+
+; Moser and Jordan (Compaq Computer Corporation)) 29-Mar-2001
+;
+; The mutex manipulation no longer leaves the owner count incremented
+; when the mutex is not acquired. The decrement is thus no longer
+; required. In addition, the Note below no longer applies since
+; the atomic manipulation above can not incorrectly leave the
+; write pending flag set.
+;
+; adawi #-1,(r2) ;decrement the semaphore
+; blss 10$
+;
+;40$:
+;
+; ;Note: this may incorrectly leave write pending set, but as long as there is
+; ; a process in crit, this will produce only a temporary inefficiency
+; -
+
+40$: movzbl #cdb_sc_nolock,r0 ;return failure
+ ret
+
+
+; enum cdb_sc mutex_lockw_ccp(mutex_struct *addr, short crash_count, uint4 *write_lock, long super_crit);
+;
+; Lock write access to the mutex at addr; if cannot lock, queue the CCP process for "wakeup",
+; and return cdb_sc_nolock (do NOT hibernate)
+
+
+ .entry mutex_lockw_ccp,^m<r2,r3,r4,r5>
+
+ movl 4(ap),r2 ;r2 -> mutex structure
+
+ cmpw 8(ap),MUTEX_CRASHCNT(r2) ;has the crash count changed?
+ bneq 30$ ;if so, return an error
+
+;+
+; Moser and Jordan (Compaq Computer Corporation)) 29-Mar-2001
+;
+; Change manipulation of the mutex owner count and write pending flag
+; to a single atomic operation using ldl_l/stl_c.
+;
+; bbssi #0,MUTEX_WRTPND(r2),10$ ;set the write pending bit
+;10$: adawi #1,(r2) ;increment the semaphore
+; bgtr 40$ ;branch if semaphore > 0 - there are other owners
+;
+; bbssi #0,MUTEX_WRTPND(r2),20$ ;set write pending again
+;20$: tstw (r2) ;see if any other process has entered crit
+; bneq 40$ ;branch if so
+;
+;-
+ evax_mb ; need memory barrier to force all writes out
+15$: movl #MUTEX_WRTPND_MASK,r18 ; Get a write pending mask in R18
+ ASSUME MUTEX_WRTPND EQ MUTEX_OWNCNT+2
+ evax_ldll r16,(r2) ; read mutex locked
+
+ evax_extwl r16,#0,r17 ; extract owner count from low word
+ evax_addq r17,#1,r28 ; Owner plus 1
+ evax_extwl r28,#0,r28 ; maintain owner count as a word
+ evax_cmoveq r28,#0,r17 ; If zero we can own, otherwise don't change
+ evax_addq r18,r17,r16 ; set write pending bit
+ evax_stlc r16,(r2) ; store mutex
+ .branch_unlikely
+ evax_beq r16,15$ ; retry, if store failed
+ evax_mb ; need memory barrier
+ evax_bne r28,40$ ; branch, if wait flag set
+
+ movl #1, at 12(ap) ;set the write lock flag
+
+ clrl r0 ;return success (cdb_sc_normal == 0)
+ ret
+
+30$: movzbl #cdb_sc_critreset,r0 ;return error
+ ret
+
+;+
+; Moser and Jordan (Compaq Computer Corporation)) 29-Mar-2001
+;
+; Change manipulation of the mutex owner count and write pending flag
+; to a single atomic operation using ldl_l/stl_c.
+;
+;40$: adawi #-1,(r2) ;decrement the semaphore
+; blss 10$
+;-
+40$:
+
+; Insert the CCP process at the HEAD of the wakeup queue, but do NOT hibernate
+
+;+
+; Moser and Jordan (Compaq Computer Corporation)) 29-Mar-2001
+;
+; Change manipulation of the mutex owner count and write pending flag
+; to a single atomic operation using ldl_l/stl_c.
+;
+; bbssi #0,MUTEX_WRTPND(r2),50$ ;set write pending again
+;
+; I don't know enough about how this mutex code is used and wheter or not
+; this is an issue, but there is a window such that when we are placing a
+; CCP process in the wait queue for a mutex, if the existing owner should release
+; the mutex prior to us getting an entry on the wait queue, then no one will
+; try to wake up the CCP process.
+;-
+
+50$: movl #QUANT_RETRY,r5
+60$: movzbl #QUEUE_RETRY,r1
+
+70$: remqhi MUTEX_FREEHEAD(r2),r3 ;get a free slot
+ bvs 130$ ;branch if the queue was empty or the secondary interlock failed
+
+ movl 16(ap),MUTEX_SUPER_CRIT(r3) ;stash the super_crit value (no need to stash the pid)
+
+ movl #QUANT_RETRY,r5
+80$: movzbl #QUEUE_RETRY,r1
+
+90$: insqhi (R3),MUTEX_PROCHEAD(r2) ;insert at the HEAD of the wait queue
+ bcs 100$ ;branch if the secondary interlock failed
+
+ movzbl #cdb_sc_nolock,r0 ;return failure to lock - successfully queued
+ ret
+
+ ;the secondary interlock failed on an attempt to insert into the wait queue
+100$: sobgtr r1,90$
+ sobgtr r5,120$
+
+ ;too many queue failures
+110$: movzbl #cdb_sc_dbccerr,r0 ;return error
+ ret
+
+120$: calls #0,G^rel_quant
+ brb 80$
+
+ ;the free queue was empty or the secondary interlock failed
+130$: sobgtr r1,70$
+ sobgtr r5,140$
+
+ ;too many queue failures
+ brb 110$
+
+140$: calls #0,G^rel_quant
+ brb 60$
+
+
+; enum cdb_sc mutex_wtor(mutex_struct *addr, uint4 *read_lock, uint4 *write_lock);
+;
+; Change write access to the mutex at addr to read access, and do a wakeup
+
+ .entry mutex_wtor,^m<r2,r3,r4,r5,r6>
+
+ movl 4(ap),r2 ;r2 -> mutex structure
+
+ movl #1, at 8(ap) ;set the read lock flag
+
+; bbcci #0,MUTEX_WRTPND(r2),10$ ;clear the write pending bit
+;10$:
+;-
+
+ ASSUME MUTEX_WRTPND EQ MUTEX_OWNCNT+2
+ evax_mb ; need memory barrier
+15$:
+ evax_ldll r16,(r2) ; read mutex locked
+ clrl r16
+ evax_stlc r16,(r2) ; store mutex as 0
+ .branch_unlikely
+ evax_beq r16,15$ ; retry, if store failed
+ evax_mb ; need memory barrier
+
+ bsbw mutex_wakeup
+
+ clrl r0 ;return success (cdb_sc_normal == 0)
+ ret
+
+
+; enum cdb_sc mutex_unlockr(mutex_struct *addr, short crash_count, uint4 *read_lock);
+;
+; Unlock read access to the mutex at addr
+
+
+ .entry mutex_unlockr,^m<r2,r3,r4,r5,r6>
+
+ movl 4(ap),r2 ;r2 -> mutex structure
+
+ cmpw 8(ap),MUTEX_CRASHCNT(r2) ;has the crash count changed?
+ bneq 20$ ;if so, return an error
+
+ clrl @12(ap) ;clear the read lock flag
+;+
+; Moser and Jordan (Compaq Computer Corporation)) 29-Mar-2001
+;
+; Change manipulation of the mutex owner count and write pending flag
+; to a single atomic operation using ldl_l/stl_c.
+;
+; adawi #-1,(r2) ;decrement the semaphore
+;-
+
+ ASSUME MUTEX_WRTPND EQ MUTEX_OWNCNT+2
+ evax_mb ; need memory barrier
+15$:
+ evax_ldll r16,(r2) ; read mutex locked
+ decw r16 ; decr owner count
+ evax_stlc r16,(r2) ; store mutex
+ .branch_unlikely
+ evax_beq r16,15$ ; retry, if store failed
+ evax_mb
+
+;
+;
+; The following two source lines seem to be an attempt at recovering
+; from a situation in which a writer dies after setting it (and before
+; incrementing the semaphore) causing later readers to block. They are being
+; commented out for the following reasons -
+; a. If this reader clears wrtpnd after a new writer has set wrtpnd (and before
+; incrementing semaphore), a new reader coming after the new writer might
+; successfully grab read crit forcing the new writer to wait in violation of
+; "A write request blocks access to additional readers until after
+; the writer is granted crit and then releases it"
+; as stated above.
+; b. Recovery from failures is anyway incomplete. We can live without this one!
+;
+; Vinaya, 07/21/98
+;
+; bgeq 10$ ;if less than zero, there are no more
+; ;owners <--??? is this logic correct?
+; bbcci #0,MUTEX_WRTPND(r2),10$ ;clear the write pending bit;
+; ;if already clear, skip the wakeup
+
+ bsbw mutex_wakeup
+
+;Label no longer required. See comments above. Vinaya, 07/21/98
+;10$: clrl r0 ;return success (cdb_sc_normal == 0)
+
+ clrl r0 ;return success (cdb_sc_normal == 0)
+ ret
+
+20$: movzbl #cdb_sc_critreset,r0 ;return error
+ ret
+
+
+; enum cdb_sc mutex_unlockw(mutex_struct *addr, short crash_count, uint4 *write_lock);
+;
+; Unlock write access to the mutex at addr
+
+
+ .entry mutex_unlockw,^m<r2,r3,r4,r5,r6>
+
+ movl 4(ap),r2 ;r2 -> mutex structure
+
+ cmpw 8(ap),MUTEX_CRASHCNT(r2) ;has the crash count changed?
+ bneq 20$ ;if so, return an error
+
+ clrl @12(ap) ;clear the write lock flag
+
+;
+;The order in which the semaphore is decremented and wrtpnd is cleared is
+;important. The order "decrement semaphore" and then "clear wrtpnd" might
+;lead to a writer and multiple readers all acquiring crit successfully
+;(violation of mutual exclusion). An example scenario -
+; 0. Writer A in the process of releasing crit, decrements semaphore
+; 1. Writer B acquires crit
+; 2. Writer A clears wrtpnd
+; 3. Readers C, D, etc grab read crit successfully
+;By changing the order to "clear wrtpnd" and then "decrement semaphore", we
+;prevent such scenarios from occuring. But we now have the possibility of
+;new readers beating a prior writer in violation of -
+; "A write request blocks access to additional readers until after
+; the writer is granted crit and then releases it"
+;as stated above. This might happen in the window between clearing wrtpnd and
+;decrementing the semaphore. Note that this won't violate mutual exclusion and
+;hence a better choice.
+;
+; Vinaya, 07/21/98
+;
+; adawi #-1,(r2) ;decrement the semaphore
+;
+; bbcci #0,MUTEX_WRTPND(r2),10$ ;clear the write pending bit
+;10$: bsbw mutex_wakeup
+
+;+
+; Moser and Jordan (Compaq Computer Corporation)) 29-Mar-2001
+;
+; Change manipulation of the mutex owner count and write pending flag
+; to a single atomic operation using ldl_l/stl_c. With the single
+; atomic operation, the ordering issue described above are no longer
+; possible.
+;
+; bbcci #0,MUTEX_WRTPND(r2),10$ ;clear the write pending bit
+;10$: adawi #-1,(r2) ;decrement the semaphore
+;-
+
+ ASSUME MUTEX_WRTPND EQ MUTEX_OWNCNT+2
+ evax_mb ; need memory barrier
+15$:
+ evax_ldll r16,(r2) ; read mutex locked
+ movl #^xffff,r17 ; create free mutex state
+ evax_stlc r17,(r2) ; store mutex
+ .branch_unlikely
+ evax_beq r17,15$ ; retry, if store failed
+ evax_mb
+
+ bsbw mutex_wakeup
+
+ clrl r0 ;return success (cdb_sc_normal == 0)
+ ret
+
+20$: movzbl #cdb_sc_critreset,r0 ;return error
+ ret
+
+
+; Insert this process at the tail of the wait queue,
+; and hibernate for 10 seconds
+;
+; On entry, r2 -> mutex structure
+; r4 -> read lock flag or write lock flag
+
+
+sleep:
+ .jsb32_entry input=<r2,r4,r6>
+
+ clrl (r4) ;clear the lock flag (read or write)
+;+
+; Moser and Jordan (Compaq Computer Corporation)) 29-Mar-2001
+;
+; The mutex manipulation no longer leaves the owner count incremented
+; when the mutex is not acquired. The decrement is thus no longer
+; required.
+;
+; adawi #-1,(r2) ;decrement the semaphore
+; bgeq 10$ ;branch if there are other owners
+;-
+ tstl num_additional_processors ; If no other processors
+ beql 10$ ; .. avoid spinlock and go right to sleep
+ evax_mb ; complete all reads/writes prior to lock ref
+5$:
+ tstw (r2)
+ blss 7$ ; branch if lock is available
+ sobgeq r6,5$
+ brb 10$
+
+
+7$:
+; 06/19/2002 se: In previous incarnations of GT.M we used read locks. Because of that,
+; the jsb to mutex_wakeup below was warranted because we might need to wake up some
+; readers. Now with all locks being write locks what is happening is that if we fail
+; to get a write lock the first time and come here, then within some few number of hard-spin
+; iterations we see the lock available, we don't return to try and get the lock until after
+; we have gone to mutex_wakeup and woken up the first of any sleepers. This is also
+; another potential cause for the AST thrashing being seen at the VA. This sleep
+; routine has no reason to wake up anybody except itself.
+; jsb mutex_wakeup
+ rsb
+
+10$: movl #QUANT_RETRY,r5
+20$: movzbl #QUEUE_RETRY,r1
+
+30$: remqhi MUTEX_FREEHEAD(r2),r3 ;get a free slot
+ bvs 100$ ;branch if the queue was empty or the secondary interlock failed
+
+ movl process_id,MUTEX_PID(r3)
+
+ movl #QUANT_RETRY,r5
+40$: movzbl #QUEUE_RETRY,r1
+
+50$: insqti (R3),MUTEX_PROCHEAD(r2) ;insert at the tail of the wait queue
+ bcs 70$ ;branch if the secondary interlock failed
+
+ ;08/20/2002 nars : we need to redo the crit test after inserting ourselves into the wait queue.
+ ; this is because it is possible that crit became free in the time between our hard spin loop and
+ ; insertion into the wait queue in which case, if we otherwise decide to hibernate for
+ ; 10 seconds there will be nobody to wake us up.
+ ; also note that we will do a mutex_wakeup ONLY IF we see noone holding crit. this is therefore
+ ; not likely to result in cascading wakeups (for large number of processes) since the very
+ ; first process to be woken up and obtain crit will stop future wakeups.
+ tstw (r2) ;see if any other process has entered crit
+ bgeq 60$ ;branch if so
+ jsb mutex_wakeup
+
+ ;hibernate for 10 seconds
+60$:
+ clrl crit_sleep_expired ;clear timer so can know if it expired or we were woken up
+ pushl #-1 ;build the timer quadword on the stack...
+ pushl #-100000000 ;... 10 seconds delta time
+ movl sp,r0 ;save its address
+
+ clrl -(sp) ;flags argument: elapsed time
+ pushl r2 ;reqidt argument: address of the mutex structure
+ pushab mutex_tickle ;astadr argument: see routine below
+ pushl r0 ;daytim argument: address of the timer quadword on the stack
+ pushl #efn$c_enf ;use no efn argument
+ calls #5,G^sys$setimr
+
+ addl #8,sp ;pop the timer quadword
+
+ calls #0,G^sys$hiber
+
+ tstl crit_sleep_expired ;if not expired, return now to try to get lock immediately
+ bnequ 65$ ;branch if expired.
+ pushl #PSL$C_USER ;acmode argument
+ pushl r2 ;reqidt argument: address of the mutex structure
+ calls #2,G^sys$cantim ; kill unpopped timer
+ rsb ; retry lock
+
+65$: pushl r2 ; address of mutex structure
+ calls #1,mutex_deadlock_check ;crit deadlock detection check
+ rsb ;retry lock even though we were not awakened.
+
+ ;the secondary interlock failed on an attempt to insert into the wait queue
+70$: sobgtr r1,50$
+ sobgtr r5,90$
+
+ ;too many queue failures
+80$: movzbl #cdb_sc_dbccerr,r0 ;return error
+; ret *** replaced with rsb below to eliminate compiler warnings. Using a ret here is not valid in the
+; cross compiled environment due to not keeping args/save areas on the stack in
+; the same way the vax did. se 8/2002
+ rsb
+
+90$: calls #0,G^rel_quant
+ brb 40$
+
+ ;the free queue was empty or the secondary interlock failed
+100$: bcs 110$ ;branch if the secondary interlock failed
+
+ ;the free queue was empty - wait a second, then try again
+; 2000/1/25 smw avoid link error for amac$flt_tsf
+; movf #1.0,-(sp) ;store the value on the stack so that it can be passed by reference
+; movl sp,r0 ;the argument to lib$wait is the address of the value
+; pushl r0
+; calls #1,G^lib$wait
+; addl #4,sp ;clean up the stack
+ pushl #1000 ; 1 second
+ calls #1,G^hiber_start ; wait
+ brw 10$
+
+ ;the secondary interlock failed on an attempt to remove an entry from the free queue
+110$: sobgtr r1,120$
+ sobgtr r5,130$
+
+ ;too many queue failures
+ brb 80$
+
+120$: brw 30$
+
+130$: calls #0,G^rel_quant
+ brw 20$
+
+
+; AST routine for the timer in sleep, above
+;
+; The argument is the address of a mutex structure
+
+ .entry mutex_tickle,^m<r2,r3,r4,r5,r6>
+
+ movl #1,crit_sleep_expired ;we waited long and hard..
+ clrl -(sp)
+ clrl -(sp)
+ calls #2,G^sys$wake
+
+ movl 4(ap),r2
+ bsb mutex_wakeup
+
+ ret
+
+
+; Wake up the process at the head of the wait queue
+;
+; On entry, r2 -> mutex structure
+
+
+mutex_wakeup:
+ .jsb32_entry input=<r2>
+
+;+
+; Moser and Jordan (Compaq Computer Corporation)) 29-Mar-2001
+;
+; Perform a quick test to see if there are any processes waiting for the
+; mutex. This avoids the more expensive REMQTI PAL Call at 20$ from
+; performing this test.
+;-
+ movzbl #MAX_WAKE,r6
+3$: evax_mb ; make sure we see changes done by other processor
+ tstl MUTEX_PROCHEAD(r2) ; Are there any waiters?
+ bneq 5$ ; if neq, yes go release them
+ rsb ; otherise return quickly
+
+5$: movl #QUANT_RETRY,r5
+10$: movzbl #QUEUE_RETRY,r1
+
+20$: remqhi MUTEX_PROCHEAD(r2),r3 ;get the first entry from the wait queue
+ bvs 90$ ;branch if the queue was empty or the secondary interlock failed
+
+; movl MUTEX_SUPER_CRIT(r3),r6 ;save the super_crit value in r6 for wake_process - no more CCP 3/2007 RP
+; clrl MUTEX_SUPER_CRIT(r3)
+
+ movl #QUANT_RETRY,r5
+30$: movzbl #QUEUE_RETRY,r1
+
+ movl MUTEX_PID(r3),r0 ;save the pid in r0 for wake_process
+
+40$: insqti (r3),MUTEX_FREEHEAD(r2)
+ bcs 60$ ;branch if the secondary interlock failed
+
+ bsb wake_process
+
+;+
+; Moser and Jordan (Compaq Computer Corporation)) 29-Mar-2001
+;
+; There is no need to force an interlock read on the write pending bit here.
+;
+; bbssi #1,MUTEX_WRTPND(r2),50$ ;force access to the write pending byte
+;50$:
+;-
+ sobgtr r6,50$
+ rsb ;enough waking for one process
+50$: bicl3 #REST_FREQ,r6,r0
+ bneq 55$
+ calls #0,G^rel_quant ;to be sure that some process is awakened, pause and try another if still no pending rp 3/2007
+55$: blbc MUTEX_WRTPND(r2),3$
+ rsb ;write pending is set - stop wakeups
+
+ ;the secondary interlock failed on an attempt to insert into the free queue
+60$: sobgtr r1,40$
+ sobgtr r5,80$
+
+ bsb wake_process
+
+ ;too many queue failures
+70$: movzbl #cdb_sc_dbccerr,r0 ;return error
+; ret *** replaced with rsb below to eliminate compiler warnings. Using a ret here is not valid in the
+; cross compiled environment due to not keeping args/save areas on the stack in
+; the same way the vax did. se 8/2002
+ rsb
+
+80$: calls #0,G^rel_quant
+ brb 30$
+
+ ;the wait queue was empty or the secondary interlock failed
+90$: bcs 100$ ;branch if the secondary interlock failed
+
+ rsb
+
+ ;the secondary interlock failed on an attempt to remove an entry from the wait queue
+100$: sobgtr r1,20$
+ sobgtr r5,110$
+
+ ;too many queue failures
+ brb 70$
+
+110$: calls #0,G^rel_quant
+ brb 10$
+
+
+; Wake up a process
+;
+; This is a subroutine because we wish to insert the queue entry into the free queue prior to
+; doing the wakeup, in order to minimize the time that the queue entry is unattached.
+; Also, we wish to wake up the process even if the insq fails.
+;
+; On entry, r0 == process id,
+; r6 == super_crit value
+
+wake_process:
+ .jsb32_entry input=<r0,r6>
+
+; 07/30/2002 se: Don't disturb pipe for a condition that is no longer needed
+; tstl r6 ;was super_crit set?
+; bneq wake_ccp ;branch if so
+
+ pushl r0 ;store the pid on the stack, so that it can be passed by reference
+ movl sp,r0 ;the argument to crit_wake is the address of the pid
+ pushl r0 ;use two instructions for safety
+ calls #1,G^crit_wake
+ addl #4,sp ;clean up the stack
+
+ rsb
+
+; 07/30/2002 se: The following code is disabled because it is no longer used and the compiler
+; complains about dead (unreachable) code.
+; The CCP never hibernated, so it doesn't get awakened per se;
+; rather, we send it an appropriate message:
+;wake_ccp:
+; pushl r6 ;store the super_crit value on the stack, so that it can be passed by reference
+; movl sp,r0 ;the second argument to ccp_sendmsg is the address of the super_crit value
+; pushl r0 ;use two instructions for safety
+; pushl #CCTR_SCRIT ;the first argument to ccp_sendmsg is the action code: super_crit granted
+; calls #2,G^ccp_sendmsg
+; addl #4,sp ;clean up the stack
+;
+; rsb
+
+ .end
diff --git a/sr_avms/mutex_stoprel.mar b/sr_avms/mutex_stoprel.mar
new file mode 100644
index 0000000..7d3ce57
--- /dev/null
+++ b/sr_avms/mutex_stoprel.mar
@@ -0,0 +1,140 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ;
+; Copyright 2000, 2001 Sanchez Computer Associates, Inc. ;
+; ;
+; This source code contains the intellectual property ;
+; of its copyright holder(s), and is made available ;
+; under a license. If you do not know the terms of ;
+; the license, please stop and do not read further. ;
+; ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ .title mutex_stoprel gtm mutex control
+
+MUTEX_OWNCNT = 0
+MUTEX_WRTPND = 2
+MUTEX_PROCHEAD = 64 ; 8
+MUTEX_FREEHEAD = 128 ; 24
+MQUE_PID = 8
+QUE_RETRY = 128
+
+; NOTE: The following definition corresponds to an item of the same name in CDB_SC.H.
+; Make sure that it is maintained compatibly!
+cdb_sc_dbccerr = 81 ; 'Q'
+
+ code_psect
+
+ .entry mutex_stoprelr,^m<r2,r3>
+ movl 4(ap),r2 ;r2 points to head of structure
+;+
+; Moser and Jordan (Compaq Computer Corporation)) 2-APR-2001
+;
+; Change manipulation of the mutex owner count and write pending flag
+; to a single atomic operation using ldl_l/stl_c. With the single
+; atomic operation, the ordering issue described above are no longer
+; possible.
+;
+; adawi #-1,(r2) ;decrement semaphore
+; bgeq 20$
+; bbcci #0,MUTEX_WRTPND(r2),20$ ;if was a write pending do wakeup
+;-
+
+ ASSUME MUTEX_WRTPND EQ MUTEX_OWNCNT+2
+15$: evax_ldll r16,(r2) ; read mutex locked
+ evax_sll r16,#16,r28 ; Move WRTPND to bit pos 0
+ decw r16 ; decr owner count
+ evax_and r16,#^xffff,r16 ; clear WRTPND bit
+ evax_stlc r16,(r2) ; store mutex
+ .branch_unlikely
+ evax_beq r16,15$ ; retry, if store failed
+ evax_mb
+
+ blbs r28,20$ ; skip, if no write pending
+ bsbw mutex_wakeup
+
+20$: clrl r0 ;return success: cdb_sc_normal == 0
+ ret
+
+
+ .entry mutex_stoprelw,^m<r2,r3>
+ movl 4(ap),r2 ;r2 points to head of structure
+
+;+
+; Moser and Jordan (Compaq Computer Corporation)) 2-APR-2001
+;
+; Change manipulation of the mutex owner count and write pending flag
+; to a single atomic operation using ldl_l/stl_c.
+;
+; adawi #-1,(r2) ;decrement the semaphore
+; bbcci #0,MUTEX_WRTPND(r2),10$
+;-
+
+ ASSUME MUTEX_WRTPND EQ MUTEX_OWNCNT+2
+15$: evax_ldll r16,(r2) ; read mutex locked
+ decw r16 ; decr owner count
+ evax_and r16,#^xffff,r16 ; clear WRTPND bit
+ evax_stlc r16,(r2) ; store mutex
+ .branch_unlikely
+ evax_beq r16,15$ ; retry, if store failed
+ evax_mb
+
+ bsb mutex_wakeup
+ clrl r0 ;return success: cdb_sc_normal == 0
+ ret
+
+
+mutex_wakeup:
+ .jsb32_entry
+
+ movzbl #QUE_RETRY,r1
+5$: remqhi MUTEX_PROCHEAD(r2),r3 ;get first entry in queue
+ bvc 20$ ;got a que entry
+ bcc 70$ ;no entries left...all done
+ sobgtr r1,5$ ;secondary interlock failed
+
+10$: movl #cdb_sc_dbccerr,r0
+ ret
+
+20$: movl MQUE_PID(r3),r0
+ movzbl #QUE_RETRY,r1
+40$: insqti (r3),MUTEX_FREEHEAD(r2)
+ bcc 50$
+ sobgtr r1,40$
+ bsb wake_job
+ brb 10$
+
+50$: bsb wake_job
+
+;+
+; Moser and Jordan (Compaq Computer Corporation)) 29-Mar-2001
+;
+; There is no need to foce an interlock read on the write pending bit here.
+;
+; bbssi #1,MUTEX_WRTPND(r2),60$ ;force access to the write pending byte
+;60$:
+;-
+ blbs MUTEX_WRTPND(r2),70$ ;if write pending set stop wakeups
+ brb mutex_wakeup
+
+70$: rsb
+
+
+; wake up a job
+; enter with r0 containing the pid
+; exit with job awakened, r0,r1 destroyed
+; this is a subroutine, because we wish to insert que entry in free
+; list prior to making service call in order to minimize the time
+; that the que entry is unattached. Also we wish to wake up the
+; job, even if the insq fails
+
+wake_job:
+ .jsb32_entry
+
+ pushl r0 ;store pid on stack, so that it can be
+ ;referenced by address
+ movl sp,r0 ;argument to crit_wake is address of pid
+ pushl r0 ;use two instructions for safety
+ calls #1,G^crit_wake
+ moval 4(sp),sp ;clean-up the stack
+ rsb ;return to calling program
+
+ .end
diff --git a/sr_avms/mval$def.max b/sr_avms/mval$def.max
new file mode 100644
index 0000000..87bf3d4
--- /dev/null
+++ b/sr_avms/mval$def.max
@@ -0,0 +1,149 @@
+;#################################################################
+;# #
+;# Copyright 2006, 2012 Fidelity Information Services, Inc #
+;# #
+;# This source code contains the intellectual property #
+;# of its copyright holder(s), and is made available #
+;# under a license. If you do not know the terms of #
+;# the license, please stop and do not read further. #
+;# #
+;#################################################################
+ .macro mval$def
+
+mval$v_nm = 0
+mval$v_int = 1
+mval$v_str = 2
+mval$v_num_approx = 3
+mval$v_canonical = 4
+mval$v_sym = 5
+mval$v_sublit = 6
+mval$v_retarg = 7
+mval$v_utflen = 8
+mval$v_aliascont = 9
+
+mval$m_nm = ^x1
+mval$m_int = ^x3
+mval$m_str = ^x4
+mval$m_num_approx = ^x8
+mval$m_canonical = ^x10
+mval$m_sym = ^x20
+mval$m_sublit = ^x40
+mval$m_retarg = ^x80
+mval$m_utflen = ^x100
+mval$m_aliascont = ^x200
+
+mval$w_mvtype = 0
+mval$b_exp = 2
+mval$l_strlen = 4
+mval$a_straddr = 8
+mval$q_num = 12
+mval$l_m0 = 12
+mval$l_m1 = 16
+
+mval$size = 20
+
+MV_BIAS = 1000
+MANT_LO = 100000000
+MANT_HI = 1000000000
+INT_HI = 1000000
+
+ .macro mv_force_defined mval, ?label
+ mv_if_defined (mval), label
+ $call underr, args=<mval>, nonstandard=true
+ mov r0, mval
+label: .endm mv_force_defined
+
+ .macro mv_force_defined_strict mval, ?label
+ mv_if_defined (mval), label
+ $call underr_strict, args=<mval>, nonstandard=true
+label: .endm mv_force_defined_strict
+
+ .macro mv_force_str mval, ?label
+ mv_if_string mval, label
+ $call n2s, args=<mval/a>, nonstandard=true
+label: .endm mv_force_str
+
+ .macro mv_force_num mval, ?label
+ mv_if_number mval, label
+ $call s2n, args=<mval/a>, nonstandard=true
+label: .endm mv_force_num
+
+ .macro mv_force_str_if_num_approx mval, ?label
+ mv_if_notnumapprox mval, label
+ $call n2s, args=<mval/a>, nonstandard=true
+label: .endm mv_force_str_if_num_approx
+
+ .macro mv_i2mval int, mval
+ mov MV_BIAS, r22
+ ldl r24, mval$w_mvtype(mval)
+ mov mval$m_int, r23
+ mskwl r24, 0, r24 ; clear mval$w_mvtype
+ mull r22, int, r28
+ or r24, r23, r24
+ stl r28, mval$l_m1(mval)
+ stl r24, (mval)
+ .endm mv_i2mval
+
+ .macro mv_if_string mval, label
+ ldl r28, mval
+ and r28, mval$m_str, r28
+ bne r28, label
+ .endm mv_if_string
+
+ .macro mv_if_notstring mval, label
+ ldl r28, mval
+ and r28, mval$m_str, r28
+ beq r28, label
+ .endm mv_if_notstring
+
+ .macro mv_if_number mval, label
+ ldl r28, mval
+ blbs r28, label
+ .endm mv_if_number
+
+ .macro mv_if_notnumber mval, label
+ ldl r28, mval
+ blbc r28, label
+ .endm mv_if_notnumber
+
+ .macro mv_if_notnumapprox mval, label
+ ldl r28, mval
+ and r28, mval$m_num_approx, r28
+ beq r28, label
+ .endm mv_if_notnumapprox
+
+ .macro mv_if_int mval, label
+ ldl r28, mval
+ and r28, mval$m_int-mval$m_nm, r28
+ bne r28, label
+ .endm mv_if_int
+
+ .macro mv_if_notint mval, label
+ ldl r28, mval
+ and r28, mval$m_int-mval$m_nm, r28
+ beq r28, label
+ .endm mv_if_notint
+
+ .macro mv_if_defined mval, label
+ ldl r28, mval
+ and r28, mval$m_nm+mval$m_str, r28
+ bne r28, label
+ .endm mv_if_defined
+
+ .macro mv_if_notdefined mval, label
+ ldl r28, mval
+ and r28, mval$m_nm+mval$m_str, r28
+ beq r28, label
+ .endm mv_if_notdefined
+
+ .macro mv_if_canonical mval, label, ?label1, ?label2
+ mv_if_notnumber mval, label1
+ and r28, mval$m_num_approx, r28
+ bne label2
+ br label
+label1: $call val_iscan, args=<mval/a>, nonstandard=true
+ bne r0, label
+label2: .endm mv_if_canonical
+
+
+ .endm mval$def
diff --git a/sr_avms/mval2num.m64 b/sr_avms/mval2num.m64
new file mode 100644
index 0000000..abd0ed4
--- /dev/null
+++ b/sr_avms/mval2num.m64
@@ -0,0 +1,39 @@
+;#################################################################
+;# #
+;# Copyright 2006, 2008 Fidelity Information Services, Inc #
+;# #
+;# This source code contains the intellectual property #
+;# of its copyright holder(s), and is made available #
+;# under a license. If you do not know the terms of #
+;# the license, please stop and do not read further. #
+;# #
+;#################################################################
+ .title mval2num "Convert an mval to a number"
+
+; On entry, r1 -> mval
+
+ mval$def
+
+ $routine MVAL2NUM, entry=MVAL2NUM_CA, kind=null
+
+ subq sp, 24, sp
+ stq r26, (sp)
+ stq r13, 8(sp)
+ stq r2, 16(sp)
+ mov r27, r13
+ .base r13, $ls
+
+ mov r1, r2
+ mv_force_defined r2
+ mv_force_num (r2)
+ mv_force_str_if_num_approx (r2)
+
+ ldq r28, (sp)
+ ldq r13, 8(sp)
+ ldq r2, 16(sp)
+ addq sp, 24, sp
+ ret r28
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/obj_file.c b/sr_avms/obj_file.c
new file mode 100644
index 0000000..53840ad
--- /dev/null
+++ b/sr_avms/obj_file.c
@@ -0,0 +1,1283 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include <rms.h>
+
+#include "compiler.h"
+#include <rtnhdr.h>
+#include "obj_gen.h"
+#include "pdscdef.h"
+#include "objlangdefs.h"
+#include "cmd_qlf.h"
+#include "mdq.h"
+#include "stringpool.h"
+#include "axp_registers.h"
+#include "axp_gtm_registers.h"
+#include "axp.h"
+#include "proc_desc.h"
+#include "mmemory.h"
+#include "obj_file.h"
+
+struct sym_table
+{
+ struct sym_table *next;
+ int4 linkage_offset;
+ int4 psect;
+ uint4 value;
+ unsigned short name_len;
+ unsigned char name[1];
+};
+
+struct linkage_entry
+{
+ struct linkage_entry *next;
+ struct sym_table *symbol;
+};
+
+/* values used in the RMS calls and header records */
+#define INITIAL_ALLOC 2
+#define DEFAULT_EXTEN_QUAN 10
+/* N.B., a useful value for the Alpha is 8192 */
+#define MAX_REC_SIZE OBJ_EMIT_BUF_SIZE
+#define MAX_REC_NUM 1024
+#define VERSION_NUM "V1.0"
+#define VERSION_NUM_SIZE SIZEOF(VERSION_NUM) - 1
+#define MAX_IMMED (MAX_REC_SIZE - 2 * SIZEOF(short) - 2 * SIZEOF(short) - SIZEOF(int4))
+#define NO_IMMED 0
+#define MIN_LINK_PSECT_SIZE 56
+
+LITREF char gtm_release_name[];
+LITREF int4 gtm_release_name_len;
+
+GBLREF command_qualifier cmd_qlf;
+GBLREF mident routine_name;
+GBLREF mident module_name;
+GBLREF char rev_time_buf[];
+GBLREF boolean_t run_time;
+GBLREF uint4 code_size, lits_size;
+GBLREF unsigned char *runtime_base;
+
+GBLDEF int4 psect_use_tab[GTM_LASTPSECT]; /* bytes of each psect this module */
+GBLREF char object_file_name[256];
+GBLREF short object_name_len;
+GBLREF struct FAB obj_fab; /* file access block for the object file */
+
+static short int current_psect;
+static int4 linkage_size;
+static struct RAB obj_rab; /* record access block for the object file */
+static char sym_buff[OBJ_SYM_BUF_SIZE]; /* buffer for global symbol defs */
+static short int sym_buff_used; /* number of chars in sym_buff */
+static char emit_buff[OBJ_EMIT_BUF_SIZE]; /* buffer for emit output (must match size of buffer used by incr_link */
+static short int emit_buff_used; /* number of chars in emit_buff */
+static short int emit_last_immed; /* index of last STO_IMM */
+static short int linker_stack_depth; /* linker stack depth */
+
+/* Values that appear in the psect definitions. */
+#define CODE_PSECT_ALIGN 4 /* octaword aligned */
+#define LIT_PSECT_ALIGN 3 /* quadword aligned */
+#define RNAMB_PSECT_ALIGN 2 /* longword aligned */
+#define LINK_PSECT_ALIGN 4 /* octaword aligned */
+#define CODE_PSECT_FLAGS EGPS$M_PIC|EGPS$M_REL|EGPS$M_SHR|EGPS$M_EXE|EGPS$M_GBL|EGPS$M_RD
+#define LIT_PSECT_FLAGS EGPS$M_PIC|EGPS$M_REL|EGPS$M_SHR|EGPS$M_GBL|EGPS$M_RD
+#define RNAMB_PSECT_FLAGS EGPS$M_PIC|EGPS$M_REL|EGPS$M_GBL|EGPS$M_RD|EGPS$M_WRT
+#define LINK_PSECT_FLAGS EGPS$M_REL|EGPS$M_RD|EGPS$M_WRT
+#define CODE_PSECT_NAME "GTM$CODE"
+#define LIT_PSECT_NAME "GTM$LITERALS"
+#define LINK_PSECT_NAME "GTM$LINK"
+#define OBJ_STRUCTURE_LEVEL 2
+#define OBJ_ARCH_1 0
+#define OBJ_ARCH_2 0
+
+/* Values that appear in procedure descriptors. These values MUST match values in gtm$main in gtm_main.m64. */
+/* Note: both RSA_END and STACK_SIZE must be multiples of 16; this may introduce padding at the beginning of each region. */
+#define RSA_END ROUND_UP((1 + 1 + 9)*8, 16) /* r27 + A(condition handler) + 9 saved registers */
+#define RSA_OFFSET (RSA_END - 9*8) /* beginning of register save area */
+#define STACK_SIZE ROUND_UP(RSA_END + (1+6)*8, 16) /* add room for r25 (arg info), r16-r21 (arguments) */
+
+static MSTR_CONST(gtm_dyn_ch_name,"GTM$DYN_CH");
+static MSTR_CONST(main_call_name,"GTM$MAIN");
+
+/* Linkage pair index values. In order to take advantage of linker-time procedure call optimization, we
+ need one linkage pair for each external procedure called. The linkage pair consists of two pointers,
+ each with its own index (the index of the second pointer is 1 plus the index of the first: the first is
+ the address of the called procedure's entry point and the second is the address of its procedure
+ descriptor.
+*/
+#define LP_MAIN 1
+
+error_def(ERR_OBJFILERR);
+
+typedef struct _Addr_ref
+{
+ struct _Addr_ref * next;
+ int psect;
+ int offset;
+ int index;
+} Addr_ref;
+
+static Addr_ref *addr_list = (void *) 0;
+static Addr_ref *addr_list_end = (void *) 0;
+static int addr_index;
+
+void emit_linkages(void);
+void emit_lp_rel( int reltype, int lpx, int psect1, int off1, int repl_ins, int psect2, int off2, int namelen,
+ char *name);
+void emit_sta_pq(int psect, int offset);
+void emit_stc_lp_psb(int lpx, int len, char *name);
+void emit_sto_gbl(int len, char *name);
+void emit_sto_lw(void);
+void set_psect( int psect, int offset);
+void output_symbol(void);
+void buff_emit( char *buff, short size);
+char *emit_psc( char *buf, int align, int flags, int alloc, int length, char *name);
+void emit_sto_off(void);
+void flush_addrs(void);
+
+/*
+ * create_object_file
+ *
+ * Args: routine header for object module
+ *
+ * Description: Create and open object file.
+ * Write module and language processor header records.
+ * Write global symbol directory (GSD) psect definition records.
+ * Write routine procedure descriptor to beginning of linkage psect.
+ * Write linkage pair and address records to linkage section for external procedures.
+ * Generate and write to code psect procedure prologue portion of routine header.
+ * Write rest of routine header to code psect.
+ *
+ */
+
+void create_object_file(rhdtyp *rhead)
+{
+ char obj_name_buff[SIZEOF(mident_fixed) + SIZEOF(".OBJ") - 1];
+ struct NAM nam;
+
+ int stat, mname_len;
+ register char *fast;
+ mstr maincall;
+ char psect_def_rec[MAX_REC_SIZE]; /* psect definition records */
+
+ /* All object files have a PSECT named "GTM$R" followed by the first 8 characters of the name of the
+ routine. This PSECT contains the routines table entry (rtn_tables) for the routine.
+
+ Because the linker sorts PSECT's with the same significant attributes alphabetically in the same
+ image section, this naming convention causes the linker to build the initial routines table for
+ GT.M native object files that are included in the initial (static) link.
+
+ Two dummy PSECT's named "GTM$R" and "GTM$RZZZZZZZZZZ" are defined in GTM_MAIN.M64 and will be sorted
+ by the linker to delimit the beginning and end, respectively, of the initial routines table. In
+ order for this to work properly, the GTM_RNAMESAAAAB PSECT generated here must have the same
+ significant linker attributes as those in GTM_MAIN.M64 and their alignment requirements must be
+ identical to those of entries of the routines name table.
+ */
+ /* GTM_RNAMESAAAAB PSECT name prefix */
+ char rnambuf[RNAMB_PREF_LEN + SIZEOF(mident_fixed) + 1];
+
+ /* First quadword of procedure descriptor contains flags and offset fields. */
+ short pdbuf_head[4] =
+ {
+ PDSC_FLAGS,
+ RSA_OFFSET, /* register save area offset in stack frame */
+ 0, /* includes FRET field */
+ 0 /* offset of call signature */
+ };
+
+ /* Last 2 quadwords of procedure descriptor before handler information. */
+ int4 pdbuf_tail[4] =
+ {
+ STACK_SIZE, /* size of stack frame */
+ 0, /* includes ENTRY_LENGTH field */
+
+ (1 << ALPHA_REG_FP) /* IREG_MASK (N.B. don't set bit for ALPHA_REG_RA) */
+ | (1 << ALPHA_REG_S0) /* r2 */
+ | (1 << ALPHA_REG_S1) /* r3 */
+ | (1 << ALPHA_REG_S2) /* r4 */
+ | (1 << ALPHA_REG_S3) /* r5 */
+ | (1 << ALPHA_REG_S4) /* r6 */
+ | (1 << ALPHA_REG_S5) /* r7 */
+ | (1 << GTM_REG_FRAME_VAR_PTR) /* r8 */
+ | (1 << GTM_REG_FRAME_TMP_PTR) /* r9 */
+ | (1 << GTM_REG_DOLLAR_TRUTH) /* r10 */
+ | (1 << GTM_REG_XFER_TABLE) /* r11 */
+ | (1 << GTM_REG_FRAME_POINTER) /* r12 */
+ | (1 << GTM_REG_PV) /* r13 */
+ | (1 << GTM_REG_LITERAL_BASE), /* r14 */
+
+ 0 /* FREG_MASK */
+ };
+
+ int length;
+ int4 code_buf[MAX_REC_SIZE / 4];
+ int4 *codep;
+ int gtm_main_call, gtm_main_lp;
+
+ assert(!run_time);
+ /* create the object file */
+ obj_fab = cc$rms_fab; /* initialize to default FAB values supplied by <rms.h> */
+ obj_fab.fab$l_dna = obj_name_buff;
+ mname_len = module_name.len;
+ assert(mname_len <= MAX_MIDENT_LEN);
+ if (!mname_len)
+ {
+ MEMCPY_LIT(obj_name_buff, "MDEFAULT.OBJ");
+ obj_fab.fab$b_dns = SIZEOF("MDEFAULT.OBJ") - 1;
+ }
+ else
+ {
+ memcpy(obj_name_buff, module_name.addr, mname_len);
+ MEMCPY_LIT(&obj_name_buff[mname_len], ".OBJ");
+ obj_fab.fab$b_dns = mname_len + SIZEOF(".OBJ") - 1;
+ }
+ obj_fab.fab$l_fop = FAB$M_CBT | FAB$M_TEF | FAB$M_MXV;
+ obj_fab.fab$l_alq = INITIAL_ALLOC;
+ obj_fab.fab$w_deq = DEFAULT_EXTEN_QUAN;
+ obj_fab.fab$b_fac = FAB$M_PUT | FAB$M_UPD | FAB$M_GET;
+ obj_fab.fab$w_mrs = MAX_REC_SIZE;
+ obj_fab.fab$l_mrn = MAX_REC_NUM;
+ obj_fab.fab$b_rfm = FAB$C_VAR;
+ obj_fab.fab$b_org = FAB$C_SEQ;
+ obj_fab.fab$l_nam = &nam;
+ nam = cc$rms_nam; /* initialize to default NAM values supplied by <rms.h> */
+ nam.nam$l_esa = object_file_name;
+ nam.nam$b_ess = 255;
+
+ if (MV_DEFINED(&cmd_qlf.object_file))
+ {
+ obj_fab.fab$b_fns = cmd_qlf.object_file.str.len;
+ obj_fab.fab$l_fna = cmd_qlf.object_file.str.addr;
+ }
+ stat = sys$create(&obj_fab);
+ obj_fab.fab$l_nam = 0;
+ object_name_len = nam.nam$b_esl;
+ object_file_name[object_name_len] = 0;
+ switch (stat)
+ {
+ case RMS$_NORMAL:
+ case RMS$_CREATED:
+ case RMS$_SUPERSEDE:
+ case RMS$_FILEPURGED:
+ break;
+ default:
+ rts_error (VARLSTCNT(6) ERR_OBJFILERR, 2, object_name_len, object_file_name, stat, obj_fab.fab$l_stv);
+ }
+
+ obj_rab = cc$rms_rab; /* initialize to default RAB values supplied by <rms.h> */
+ obj_rab.rab$l_fab = &obj_fab;
+
+ stat = sys$connect(&obj_rab);
+ if(stat!=RMS$_NORMAL)
+ rts_error (VARLSTCNT(6) ERR_OBJFILERR, 2, object_name_len, object_file_name, stat, obj_fab.fab$l_stv);
+
+ linker_stack_depth = 0;
+
+ /* output the Main Module Header Record */
+ fast = emit_buff;
+ *((short *) fast)++ = EOBJ$C_EMH;
+ *((short *) fast)++ = 0; /* record length */
+ *((short *) fast)++ = EMH$C_MHD;
+ *((short *) fast)++ = OBJ_STRUCTURE_LEVEL;
+ *((int4 *) fast)++ = OBJ_ARCH_1;
+ *((int4 *) fast)++ = OBJ_ARCH_2;
+ *((int4 *) fast)++ = MAX_REC_SIZE;
+ *((char *) fast)++ = mname_len;
+ memcpy(fast, module_name.addr, mname_len);
+ fast += mname_len;
+ *((char *) fast)++ = VERSION_NUM_SIZE;
+ memcpy(fast,VERSION_NUM,VERSION_NUM_SIZE);
+ fast += VERSION_NUM_SIZE;
+ memcpy(fast,rev_time_buf,17);
+ fast += 17;
+ memcpy(fast," ",17);
+ fast += 17;
+ length = fast - emit_buff;
+ ((short *) emit_buff)[1] = length;
+ obj_rab.rab$l_rbf = emit_buff;
+ obj_rab.rab$w_rsz = length;
+ stat = sys$put(&obj_rab);
+ if(stat != RMS$_NORMAL)
+ rts_error (VARLSTCNT(6) ERR_OBJFILERR, 2, object_name_len, object_file_name, stat, obj_fab.fab$l_stv);
+
+ /* output the Language Name Header Record */
+ fast = emit_buff;
+ *((short *) fast)++ = EOBJ$C_EMH;
+ *((short *) fast)++ = 6 + gtm_release_name_len;
+ *((short *) fast)++ = EMH$C_LNM;
+ memcpy(fast,>m_release_name[0],gtm_release_name_len);
+ fast += gtm_release_name_len;
+ length = fast - emit_buff;
+ obj_rab.rab$w_rsz = length;
+ stat = sys$put(&obj_rab);
+ if(stat != RMS$_NORMAL)
+ rts_error (VARLSTCNT(6) ERR_OBJFILERR, 2, object_name_len, object_file_name, stat, obj_fab.fab$l_stv);
+
+ /* define psect's */
+ length = routine_name.len;
+ MEMCPY_LIT(&rnambuf[0], RNAMB_PREF);
+ memcpy(&rnambuf[RNAMB_PREF_LEN], routine_name.addr, length);
+ if ('%' == rnambuf[RNAMB_PREF_LEN])
+ rnambuf[RNAMB_PREF_LEN] = '.';
+ length += RNAMB_PREF_LEN;
+ if (length > EGPS$S_NAME) /* Truncate the PSECT name if it exceeeds the maximum allowed length (31) */
+ length = EGPS$S_NAME;
+ if (routine_name.len >= RNAME_SORTED_LEN && !memcmp(routine_name.addr, RNAME_ALL_Z, RNAME_SORTED_LEN))
+ { /* If the first 26 chars of the routine name are all lower case z's (currently routine names cannot be
+ in lower case, but if supported in future), we should not generate the psect name containing
+ the routine name as it could conflict with the dummy anchor gtm$rrzzzzzzzzzzzzzzzzzzzzzzzzzz defined
+ in gtm_main.m64. If such a conflict occurs, linker may not guarantee that the dummy anchor to be the
+ last entry in the routine table. So, if the routine name starts with 26 z's, we generate the psect
+ name changing the last (31st) character to '$' so that all such routines will be concatenated
+ between the anchors. However, they need to be sorted at runtime startup based on the complete
+ routine name (see rtn_tbl_sort.c) */
+ assert(length == EGPS$S_NAME);
+ rnambuf[length - 1] = '$';
+ }
+ ((short *) psect_def_rec)[0] = EOBJ$C_EGSD;
+ fast = psect_def_rec+8;
+ fast = emit_psc(fast, CODE_PSECT_ALIGN, CODE_PSECT_FLAGS, code_size, LEN_AND_LIT(CODE_PSECT_NAME));
+ fast = emit_psc(fast, LIT_PSECT_ALIGN, LIT_PSECT_FLAGS, lits_size, LEN_AND_LIT(LIT_PSECT_NAME));
+ fast = emit_psc(fast, RNAMB_PSECT_ALIGN, RNAMB_PSECT_FLAGS, SIZEOF(rtn_tabent), length, rnambuf);
+ fast = emit_psc(fast, LINK_PSECT_ALIGN, LINK_PSECT_FLAGS, linkage_size, LEN_AND_LIT(LINK_PSECT_NAME));
+ length = fast - psect_def_rec;
+ ((short *) psect_def_rec)[1] = length;
+
+ obj_rab.rab$l_rbf = psect_def_rec;
+ obj_rab.rab$w_rsz = length;
+ stat = sys$put(&obj_rab);
+ if (stat != RMS$_NORMAL)
+ rts_error (VARLSTCNT(6) ERR_OBJFILERR, 2, object_name_len, object_file_name, stat, obj_fab.fab$l_stv);
+
+ /* set the appropriate buffer counts */
+ ((short *) sym_buff)[0] = EOBJ$C_EGSD;
+ ((short *) sym_buff)[1] = 0;
+ sym_buff_used = 8;
+ ((short *) emit_buff)[0] = EOBJ$C_ETIR;
+ ((short *) emit_buff)[1] = 0;
+ emit_buff_used = 4;
+ emit_last_immed = NO_IMMED;
+ memset(psect_use_tab, 0, SIZEOF(psect_use_tab));
+
+ /* Build GTM_LINKAGE ("$LINKAGE") psect. */
+ set_psect(GTM_LINKAGE, 0);
+
+ /* Generate a procedure descriptor pointing to prologue code (beginning of GTM_CODE psect). */
+ /* N.B. This procedure descriptor must be at offset 0 in $LINKAGE; that's the way it's defined in obj_code. */
+ emit_immed(pdbuf_head, SIZEOF(pdbuf_head));
+ emit_sta_pq(GTM_CODE, 0);
+ emit_sto_off();
+ emit_immed(pdbuf_tail, SIZEOF(pdbuf_tail));
+
+ (void)define_symbol(GTM_ANOTHER_MODULE, >m_dyn_ch_name, 0);
+ emit_sto_gbl(gtm_dyn_ch_name.len, gtm_dyn_ch_name.addr);
+
+ /* Emit a linkage pair for to GTM$MAIN. */
+ set_psect(GTM_LINKAGE, ROUND_UP(psect_use_tab[GTM_LINKAGE],8)); /* align to quadword boundary */
+ gtm_main_lp = psect_use_tab[GTM_LINKAGE]; /* remember for later */
+ (void)define_symbol(GTM_ANOTHER_MODULE, &main_call_name, 0);
+ emit_stc_lp_psb(LP_MAIN, main_call_name.len, main_call_name.addr);
+
+ assert (psect_use_tab[GTM_LINKAGE] == MIN_LINK_PSECT_SIZE);
+ emit_linkages ();
+
+ addr_index = 48;
+
+ set_psect(GTM_CODE, 0);
+
+ /* Emit the routine header, including procedure prologue (initialization call to GTM$MAIN). */
+
+ /* Emit initialization call to GTM$MAIN. */
+ /* (This is the routine header jsb field.) */
+ codep = code_buf;
+
+ gtm_main_call = (char *) codep - (char *) code_buf;
+ *codep++ = ALPHA_MEM(ALPHA_INS_LDQ, ALPHA_REG_R0, ALPHA_REG_PV, gtm_main_lp);
+ *codep++ = ALPHA_MEM(ALPHA_INS_LDQ, ALPHA_REG_R1, ALPHA_REG_PV, gtm_main_lp+8);
+ *codep++ = ALPHA_JMP(ALPHA_INS_JSR, ALPHA_REG_R0, ALPHA_REG_R0); /* call GTM$MAIN */
+
+ assert ((char *)codep - (char *)code_buf == RHEAD_JSB_SIZE);
+ emit_immed(code_buf, (char *) codep - (char *) code_buf);
+
+ /* Emit conditional stores for instruction optimization of call to GTM$MAIN: */
+ emit_lp_rel(ETIR$C_STC_NOP_GBL, LP_MAIN,
+ GTM_CODE, gtm_main_call,
+ ALPHA_OPR(ALPHA_INS_BIS, ALPHA_REG_ZERO, ALPHA_REG_ZERO, ALPHA_REG_ZERO),
+ GTM_CODE, gtm_main_call + 12,
+ main_call_name.len, main_call_name.addr);
+ emit_lp_rel(ETIR$C_STC_LDA_GBL, LP_MAIN + 1,
+ GTM_CODE, gtm_main_call + 4,
+ ALPHA_MEM(ALPHA_INS_LDA, ALPHA_REG_R1, ALPHA_REG_PV, 0),
+ GTM_LINKAGE, 0,
+ main_call_name.len, main_call_name.addr);
+ emit_lp_rel(ETIR$C_STC_BOH_GBL, LP_MAIN,
+ GTM_CODE, gtm_main_call + 8,
+ ALPHA_BRA(ALPHA_INS_BSR, ALPHA_REG_R0, 0),
+ GTM_CODE, gtm_main_call + 12,
+ main_call_name.len, main_call_name.addr);
+ /* Now emit the rest of the common part of the routine header (from src_full_name through temp_size). */
+
+ /* src_full_name (mstr) */
+ emit_immed(&rhead->src_full_name.len, SIZEOF(rhead->src_full_name.len));
+ emit_pidr((int4)rhead->src_full_name.addr, GTM_LITERALS);
+ /* routine_name (mident) */
+ emit_immed(&rhead->routine_name.len, SIZEOF(rhead->routine_name.len));
+ emit_pidr((int4)rhead->routine_name.addr, GTM_LITERALS);
+ /* From vartab_off to the end of rhead. */
+ emit_immed((char *)&rhead->vartab_off, ((char *)&rhead->linkage_ptr - (char *)&rhead->vartab_off));
+
+ emit_pidr(0, GTM_LINKAGE); /* Fill in linkage_ptr with the address of the beginning of the linkage Psect. */
+ emit_pidr(0, GTM_LITERALS); /* Fill in literal_ptr with the address of the beginning of the literal Psect. */
+}
+
+
+/*
+ * close_object_file
+ *
+ * Description: Write routine table entry psect.
+ * Write global symbol specifications records for defined global symbols.
+ * Generate and write end of module record.
+ * Close file.
+ *
+ */
+
+void close_object_file(rhdtyp *rhead)
+{
+ int stat;
+ register char *fast;
+
+ flush_addrs();
+
+ /* emit the routine table entry (rtn_tabent) */
+ set_psect(GTM_RNAMESAAAAB, 0);
+ emit_immed(&rhead->routine_name.len, SIZEOF(rhead->routine_name.len));
+ emit_pidr((int4)rhead->routine_name.addr, GTM_LITERALS);
+
+ emit_pidr(0, GTM_CODE);
+
+ /* flush emit buffer */
+ if (emit_buff_used > 4)
+ {
+ ((short *) emit_buff)[0] = EOBJ$C_ETIR;
+ ((short *) emit_buff)[1] = emit_buff_used;
+ obj_rab.rab$l_rbf = emit_buff;
+ obj_rab.rab$w_rsz = emit_buff_used;
+ stat = sys$put(&obj_rab);
+ if (stat != RMS$_NORMAL)
+ rts_error (VARLSTCNT(6) ERR_OBJFILERR, 2, object_name_len, object_file_name, stat, obj_fab.fab$l_stv);
+ }
+ output_symbol();
+
+ /* output the End of Module Record */
+ fast = emit_buff;
+ *((short *) fast)++ = EOBJ$C_EEOM;
+ *((short *) fast)++ = 24;
+ *((int4 *) fast)++ = 2; /* total linkage indices (= linkage pairs / 2) */
+ *((short *) fast)++ = EEOM$C_SUCCESS; /* should be completion code in range [0,3] [lidral] */
+ *((unsigned char *) fast)++ = 1 << EEOM$V_WKTFR; /* EEOM$V_WKTFR = 1 => weak transfer address */
+ *((unsigned char *) fast)++ = 0; /* alignment byte (must be zero) */
+ *((int4 *) fast)++ = GTM_LINKAGE; /* program section index of program section containing transfer address */
+ *((int4 *) fast)++ = 0; /* offset of transfer address within program section */
+ *((int4 *) fast)++ = 0;
+ obj_rab.rab$l_rbf = emit_buff;
+ obj_rab.rab$w_rsz = 24;
+ stat = sys$put(&obj_rab);
+ if (stat != RMS$_NORMAL)
+ rts_error (VARLSTCNT(6) ERR_OBJFILERR, 2, object_name_len, object_file_name, stat, obj_fab.fab$l_stv);
+
+ /* close up */
+ stat = sys$disconnect(&obj_rab);
+ if (stat != RMS$_NORMAL)
+ rts_error (VARLSTCNT(6) ERR_OBJFILERR, 2, object_name_len, object_file_name, stat, obj_fab.fab$l_stv);
+
+ assert (linker_stack_depth == 0);
+}
+
+
+/*
+ * drop_object_file
+ *
+ * Description: Delete object file.
+ */
+
+void drop_object_file(void)
+{
+ obj_fab.fab$l_fop |= FAB$M_DLT;
+ sys$close(&obj_fab);
+ obj_fab = cc$rms_fab;
+}
+
+
+/*
+ * define_symbol
+ *
+ * Args: psect index, symbol name, symbol value.
+ *
+ * Description: Buffers a definition of a global symbol with the given name and value in the given psect.
+ * psect == GTM_ANOTHER_MODULE => external (not defined in this module) symbol
+ *
+ * N.B. the return value for define_symbol is only used in this module; all other modules refer to it as type void.
+ */
+
+
+static struct sym_table *symbols;
+
+struct sym_table* define_symbol(int4 psect, mstr *name, int4 value)
+{
+ int4 cmp;
+ struct sym_table **sym, *newsym;
+
+ sym = &symbols;
+ while(*sym != 0)
+ {
+ if ((cmp = memvcmp(name->addr, name->len, &((*sym)->name[0]), (*sym)->name_len)) <= 0)
+ break;
+ sym = &((*sym)->next);
+ }
+
+ if (cmp != 0 || *sym == 0)
+ {
+ /* Add new symbol in alphabetic order. */
+ newsym = (struct sym_table *) mcalloc(SIZEOF(struct sym_table) + name->len - 1);
+ newsym->name_len = name->len;
+ memcpy(&newsym->name[0], name->addr, name->len);
+ newsym->linkage_offset = 0; /* don't assign linkage psect offset until used */
+ newsym->psect = psect;
+ newsym->value = value;
+ newsym->next = *sym;
+ *sym = newsym;
+ }
+ else if (psect == GTM_CODE) /* if psect is GTM_CODE, this is a def, not a ref */
+ {
+ (*sym)->psect = psect;
+ (*sym)->value = value;
+ }
+ return *sym;
+}
+
+
+/*
+ * emit_immed
+ *
+ * Args: buffer of executable code, and byte count to be output.
+ *
+ * Description: Issues TIR records to store the given number of bytes
+ * from the buffer directly into the image at the current image
+ * location.
+ */
+
+GBLREF spdesc stringpool;
+
+error_def(ERR_STRINGOFLOW);
+
+
+#define CRITICAL 5
+
+void emit_immed(char *source, uint4 size)
+{
+ char buff[MAX_IMMED + 8]; /* MAX_IMMED + 2 * SIZEOF(short) + SIZEOF(int4) */
+ int amount, r, s;
+
+ if (run_time)
+ {
+ if (stringpool.free + size > stringpool.top)
+ rts_error(VARLSTCNT(1) ERR_STRINGOFLOW);
+ memcpy(stringpool.free, source, size);
+ stringpool.free += size;
+ }
+ else
+ {
+ /* Check whether the last piece in the emit_buff is a STO_IMM, and calculate how much of the source
+ can be concatenated with it. Do not make the last immediate longer than the maximum allowed, do
+ not overflow the buffer, and do not bother if we can only add 4 bytes or less.
+ */
+ if (emit_last_immed == NO_IMMED)
+ {
+ r = 0;
+ }
+ else
+ {
+ r = MAX_IMMED - *((int4 *) (emit_buff + emit_last_immed + 2 * SIZEOF(short)));
+ }
+
+ s = OBJ_EMIT_BUF_SIZE - emit_buff_used;
+
+ if(r >= CRITICAL && s >= CRITICAL)
+ {
+ r = (r < s) ? r : s;
+ amount = (size < r) ? size : r;
+ memcpy(emit_buff + emit_buff_used, source, amount);
+
+ /* emit_last_immed is the offset of the start of the last ETIR$C_STO_IMM command;
+ increment the command size and data count fields. */
+ *((short *) (emit_buff + emit_last_immed + SIZEOF(short))) += amount; /* command size */
+ *((int4 *) (emit_buff + emit_last_immed + 2 * SIZEOF(short))) += amount; /* data size */
+ size -= amount;
+ source += amount;
+ psect_use_tab[current_psect] += amount;
+ emit_buff_used += amount;
+ }
+
+ while(size>0)
+ {
+ amount = (size <= MAX_IMMED) ? size : MAX_IMMED;
+ *(short *)(&buff[ETIR$W_RECTYP]) = ETIR$C_STO_IMM;
+ *(short *)(&buff[ETIR$W_SIZE]) = amount + 2 * SIZEOF(short) + SIZEOF(int4); /* command size */
+ *(int4 *) (&buff[ETIR$W_SIZE + SIZEOF(short)]) = amount; /* data size */
+ memcpy(buff + 2 * SIZEOF(short) + SIZEOF(int4), source, amount);
+ emit_last_immed = emit_buff_used;
+ buff_emit(buff, amount + 2 * SIZEOF(short) + SIZEOF(int4));
+ size -= amount;
+ source += amount;
+ psect_use_tab[current_psect] += amount;
+ }
+ }
+}
+
+
+/* emit_linkages
+ *
+ * Description: Write symbol addresses to linkage psect.
+ */
+
+static struct linkage_entry *linkage_first, *linkage_last;
+
+void emit_linkages(void)
+{
+ struct linkage_entry *linkagep;
+
+ for (linkagep = linkage_first; linkagep != 0; linkagep = linkagep->next)
+ {
+ assert (psect_use_tab[GTM_LINKAGE] == linkagep->symbol->linkage_offset);
+ emit_sto_gbl (linkagep->symbol->name_len, linkagep->symbol->name);
+ }
+ assert (psect_use_tab[GTM_LINKAGE] == linkage_size);
+}
+
+
+/*
+ * emit_literals
+ *
+ * Description: Write each value in the literal chain to the literal psect.
+ */
+
+GBLREF mliteral literal_chain;
+GBLREF char source_file_name[];
+GBLREF unsigned short source_name_len;
+
+void emit_literals(void)
+{
+ uint4 offset, padsize;
+ mliteral *p;
+
+ assert (psect_use_tab[GTM_LITERALS] == 0);
+ set_psect(GTM_LITERALS, 0);
+ offset = stringpool.free - stringpool.base;
+ emit_immed(stringpool.base, offset);
+ padsize = PADLEN(offset, NATIVE_WSIZE); /* comp_lits aligns the start of source path on NATIVE_WSIZE boundary.*/
+ if (padsize)
+ {
+ emit_immed(PADCHARS, padsize);
+ offset += padsize;
+ }
+ emit_immed(source_file_name, source_name_len);
+ offset += source_name_len;
+ padsize = PADLEN(offset, NATIVE_WSIZE); /* comp_lits aligns the start of routine_name on NATIVE_WSIZE boundary.*/
+ if (padsize)
+ {
+ emit_immed(PADCHARS, padsize);
+ offset += padsize;
+ }
+ emit_immed(routine_name.addr, routine_name.len);
+ offset += routine_name.len;
+ padsize = PADLEN(offset, NATIVE_WSIZE); /* comp_lits aligns the start of literal area on NATIVE_WSIZE boundary.*/
+ if (padsize)
+ {
+ emit_immed(PADCHARS, padsize);
+ offset += padsize;
+ }
+
+ dqloop(&literal_chain, que, p)
+ {
+ assert (p->rt_addr >= 0);
+ MV_FORCE_NUMD(&p->v);
+ if (p->v.str.len != 0)
+ {
+ emit_immed(&p->v, (int)&p->v.str.addr - (int)&p->v);
+ emit_pidr(p->v.str.addr - (char *)stringpool.base, GTM_LITERALS);
+ emit_immed(&p->v.m, SIZEOF(p->v.m)); /* assumes no fill between end of p->v.str.addr and start of p->m */
+ }
+ else
+ {
+ p->v.str.addr = 0;
+ emit_immed(&p->v, SIZEOF(p->v));
+ }
+ offset += SIZEOF(p->v);
+ }
+ assert(offset == lits_size);
+}
+
+
+/*
+ * find_linkage
+ *
+ * Arg: the name of a global symbol.
+ *
+ * Description: Return the offset into the linkage psect for the address of a global symbol.
+ */
+
+int4 find_linkage(mstr* name)
+{
+ struct linkage_entry *newlnk;
+ struct sym_table *sym;
+
+ sym = define_symbol(GTM_LITERALS, name, 0);
+
+ if (sym->linkage_offset == 0)
+ {
+ /* Add new linkage psect entry at end of list. */
+ sym->linkage_offset = linkage_size;
+
+ newlnk = (struct linkage_entry *) mcalloc(SIZEOF(struct linkage_entry));
+ newlnk->symbol = sym;
+ newlnk->next = 0;
+ if (linkage_first == 0)
+ linkage_first = newlnk;
+ if (linkage_last != 0)
+ linkage_last->next = newlnk;
+ linkage_last = newlnk;
+
+ linkage_size += 2 * SIZEOF(int4);
+ }
+
+ return sym->linkage_offset;
+}
+
+
+/*
+ * flush_addrs
+ *
+ * Description: For every entry in the address pointer list, generate corresponding linkage psect entry.
+ */
+
+void flush_addrs(void)
+{
+ Addr_ref *addrp;
+
+ if (!addr_list) return;
+ set_psect(GTM_LINKAGE, addr_list->index);
+ for (addrp = addr_list; addrp != (void *) 0; addrp = addrp->next)
+ {
+ emit_sta_pq(addrp->psect, addrp->offset);
+ emit_sto_off();
+ }
+}
+
+
+/*
+ * literal_offset
+ *
+ * Description: Return offset to literal from context register.
+ *
+ * Argument: Offset of literal in literal psect.
+ */
+
+int4 literal_offset (UINTPTR_T offset)
+{
+ return (int4)((run_time ? (offset - (UINTPTR_T)runtime_base) : offset));
+}
+
+
+/*
+ * obj_init
+ *
+ * Description: Initialize symbol list, linkage psect list, linkage_size.
+ */
+
+void obj_init(void)
+{
+ symbols = 0;
+
+ linkage_first = linkage_last = 0;
+ linkage_size = MIN_LINK_PSECT_SIZE; /* minimum size of linkage psect, assuming no references from generated code */
+
+ return;
+}
+
+
+/*
+ * buff_emit
+ *
+ * Args: buffer pointer, number of bytes to emit
+ *
+ * Description: Does buffered i/o of TIR records. Assumes that it will
+ * never be given more than OBJ_EMIT_BUF_SIZE-1 bytes to output;
+ * such overlength records should only arise from emit_immed, which
+ * handles the situation by itself.
+ */
+
+void buff_emit(
+char *buff,
+short size)
+{
+
+ int stat;
+
+ if (OBJ_EMIT_BUF_SIZE < (emit_buff_used + size))
+ {
+ *(short *)(&emit_buff[EOBJ$W_RECTYP]) = EOBJ$C_ETIR;
+ *(short *)(&emit_buff[EOBJ$W_SIZE]) = emit_buff_used;
+ obj_rab.rab$l_rbf = emit_buff;
+ obj_rab.rab$w_rsz = emit_buff_used;
+ stat = sys$put(&obj_rab);
+ if (stat != RMS$_NORMAL)
+ lib$stop(stat);
+ emit_buff_used = 2 * SIZEOF(short);
+ emit_last_immed = NO_IMMED;
+ }
+ assert (SIZEOF(emit_buff) >= (emit_buff_used + size));
+ memcpy(emit_buff + emit_buff_used, buff, size);
+ emit_buff_used += size;
+}
+
+
+/*
+ * emit_lp_rel Emit Linkage Pair Relocation (via instruction-related store conditional command for linkage)
+ *
+ * Args: TIR store conditional command, linkage index,
+ * psect, offset at which to replace instruction,
+ * replacement instruction,
+ * psect, offset from which to calculate displacement in determining whether to replace instruction,
+ * length of global symbol name, global symbol name
+ *
+ * Description: Issues specified TIR store conditional command.
+ * These TIR commands instruct the linker to replace the instruction at (psect1 + offset1)
+ * with the specified replacement instruction if the displacement from (psect2 + offset2) to
+ * the procedure descriptor or procedure entry associated with the specified global name
+ * is less than some threshhold value (i.e. will fit into some appropriately-sized bit field).
+ * These commands are typically used to allow the linker to optimize procedure calls, not by
+ * reducing the number of instructions, but by substituting either faster instructions (e.g.,
+ * NOP in place of LDQ) or by eliminating stalls caused by one instruction needing to wait for
+ * the previous instruction to finish.
+ */
+
+void emit_lp_rel(
+int reltype, /* TIR store conditional command for linkage */
+int lpx, /* linkage index of global symbol */
+int psect1, /* psect (program section) in which to place replacement instruction */
+int off1, /* byte offset in psect1 at which to place replacement instruction */
+int repl_ins, /* replacement instruction */
+int psect2, /* psect containing base address from which displacement is to be calculated */
+int off2, /* byte offset in psect2 from which displacement is to be calculated */
+int namelen, /* length of global symbol name */
+char *name) /* global symbol name */
+{
+ int len;
+ register char *fast;
+ char buf[MAX_REC_SIZE];
+
+ fast = buf;
+
+ *((short *) fast)++ = reltype;
+ *((short *) fast)++ = 0; /* record length */
+ *((int4 *) fast)++ = lpx;
+ *((int4 *) fast)++ = psect1;
+ *((int4 *) fast)++ = off1;
+ *((int4 *) fast)++ = 0;
+ *((int4 *) fast)++ = repl_ins;
+ *((int4 *) fast)++ = psect2;
+ *((int4 *) fast)++ = off2;
+ *((int4 *) fast)++ = 0;
+ *fast++ = namelen;
+ memcpy(fast, name, namelen);
+ fast += namelen;
+ len = ROUND_UP(fast - buf, 8); /* round up to next quadword boundary */
+ *((short *) (buf + 2)) = len;
+
+ buff_emit(buf, len);
+ /* No increment of psect_use_tab, because these commands must refer to previously written image locations. */
+ emit_last_immed = NO_IMMED;
+}
+
+
+/*
+ * emit_pidr
+ *
+ * Args: offset from a psect base, that psect index
+ *
+ * Description: Issues TIR records to create an image activation-time adjusted reference.
+ * That is, at activation time, the value in the current image location will be
+ * incremented by the runtime image base address. Assumes the value is the offset
+ * from the base of the given psect of something to which one wants to refer.
+ *
+ * (Originally named after the VAX linker object language command TIR$C_STO_PIDR, for
+ * Position Independent Data Reference; the Alpha implements this with two TIR commands.)
+ */
+
+void emit_pidr(int4 offset, unsigned char psect)
+{
+ emit_sta_pq(psect, offset);
+ emit_sto_lw();
+}
+
+
+/*
+ * emit_psc
+ *
+ * Args: buffer to contain program section (PSECT) definition global symbol directory subrecord,
+ * virtual address boundary at which to align program section,
+ * bit flags indicating attributes of PSECT,
+ * number of bytes in PSECT,
+ * length in bytes of the name of this PSECT, and
+ * the name of this PSECT.
+ *
+ * Description: Puts global symbol directory PSECT definition subrecord into buffer.
+ * Returns pointer to next available byte in buffer.
+ */
+
+char *emit_psc(
+char *buf,
+int align,
+int flags,
+int alloc,
+int length,
+char *name)
+{
+ char *fast;
+
+ fast = buf;
+ *((short *) fast)++ = EGSD$C_PSC;
+ *((short *) fast)++ = 0;
+ *((short *) fast)++ = align;
+ *((short *) fast)++ = flags;
+ *((int4 *) fast)++ = alloc;
+ *((char *) fast)++ = length;
+ memcpy(fast, name, length);
+ fast += length;
+ length = ROUND_UP(fast - buf, 8);
+ fast = buf + length;
+ ((short *) buf)[1] = length;
+ return fast;
+}
+
+
+/*
+ * emit_sta_pq Stack Psect Base Plus Byte Offset
+ *
+ * Args: psect index, byte offset
+ *
+ * Description: Issues TIR command to add program section base and byte offset then push result onto stack.
+ */
+
+void emit_sta_pq (
+int psect, /* psect (program section) index */
+int offset) /* byte offset into psect */
+{
+ char buf[MAX_REC_SIZE];
+ register char *fast;
+
+ fast = buf;
+
+ *((short *) fast)++ = ETIR$C_STA_PQ;
+ *((short *) fast)++ = 2 * SIZEOF(short) + SIZEOF(int4) + 2 * SIZEOF(int4);
+ *((int4 *) fast)++ = psect;
+ *((int4 *) fast)++ = offset;
+ *((int4 *) fast)++ = 0; /* upper half of offset qw */
+ linker_stack_depth++;
+
+ buff_emit(buf, fast - buf);
+ emit_last_immed = NO_IMMED;
+}
+
+
+/*
+ * emit_stc_lp_psb Store Conditional Linkage Pair plus Signature
+ *
+ * Args: linkage index, length of procedure name, procedure name
+ *
+ * Description: Issues TIR command to declare conditional linkage and signature information for the named procedure.
+ * N.B. this TIR command reserves two indices, lpx and (lpx+1).
+ */
+
+void emit_stc_lp_psb(
+int lpx, /* linkage pair index */
+int len, /* length of name */
+char *name) /* procedure name */
+{
+ register char *fast;
+ char buf[MAX_REC_SIZE];
+
+ fast = buf;
+
+ *((short *) fast)++ = ETIR$C_STC_LP_PSB;
+ *((short *) fast)++ = 0; /* record length */
+ *((int4 *) fast)++ = lpx;
+ *fast++ = len;
+ memcpy(fast, name, len);
+ fast += len;
+ *((char *) fast)++ = 1; /* signature length */
+ *((char *) fast)++ = 0; /* signature information */
+ len = ROUND_UP(fast - buf, 8); /* round up to next quadword boundary */
+ *((short *) (buf + 2)) = len;
+
+ buff_emit(buf, len);
+ psect_use_tab[current_psect] += 4 * SIZEOF(int4); /* two quadwords */
+ emit_last_immed = NO_IMMED;
+}
+
+
+/*
+ * emit_sto_gbl Store Global
+ *
+ * Args: length of global symbol name, global symbol name
+ *
+ * Description: Issues TIR command to store a global symbol reference.
+ */
+
+void emit_sto_gbl(
+int len, /* length of global symbol name */
+char *name) /* global symbol name */
+{
+ register char *fast;
+ char buf[MAX_REC_SIZE];
+
+ fast = buf;
+
+ *((short *) fast)++ = ETIR$C_STO_GBL;
+ *((short *) fast)++ = 0; /* record length */
+ *fast++ = len;
+ memcpy(fast, name, len);
+ fast += len;
+ len = ROUND_UP(fast - buf, 8); /* round up to next quadword boundary */
+ *((short *) (buf + 2)) = len;
+
+ buff_emit(buf, len);
+ psect_use_tab[current_psect] += 2 * SIZEOF(int4);
+ emit_last_immed = NO_IMMED;
+}
+
+
+/*
+ * emit_sto_lw Store Longword
+ *
+ * Args: (none)
+ *
+ * Description: Issues TIR command to pop quadword from stack and write low longword to image; value is always treated
+ * as an address and relocated if image is relocatable or fixed up if psect contributed by shareable image.
+ */
+
+void emit_sto_lw(void)
+{
+ char buf[MAX_REC_SIZE];
+ register char *fast;
+
+ fast = buf;
+
+ *((short *) fast)++ = ETIR$C_STO_LW;
+ *((short *) fast)++ = 2 * SIZEOF(short);
+ linker_stack_depth--;
+
+ buff_emit(buf, fast - buf);
+ psect_use_tab[current_psect] += SIZEOF(int4);
+ emit_last_immed = NO_IMMED;
+}
+
+
+/*
+ * emit_sto_off Store Offset to Psect
+ *
+ * Args: (none)
+ *
+ * Description: Issues TIR command to pop quadword from stack and write to image; value is always treated as an address
+ * and relocated if image is relocatable or fixed up if psect contributed by shareable image.
+ */
+
+void emit_sto_off(void)
+{
+ char buf[MAX_REC_SIZE];
+ register char *fast;
+
+ fast = buf;
+
+ *((short *) fast)++ = ETIR$C_STO_OFF;
+ *((short *) fast)++ = 2 * SIZEOF(short);
+ linker_stack_depth--;
+
+ buff_emit(buf, fast - buf);
+ psect_use_tab[current_psect] += 2 * SIZEOF(int4);
+ emit_last_immed = NO_IMMED;
+}
+
+
+/*
+ * output_symbol
+ *
+ * Description: Generate and write global symbol directory (GSD) symbol records for every
+ * global symbol defined or referenced in this module.
+ */
+
+#define GSD_DATA_TYPE 0
+#define GSD_PROC_TYPE 0
+
+void output_symbol(void)
+{
+ int stat, len, reclen;
+ register char *fast;
+ struct sym_table *sym;
+
+ sym = symbols;
+ while (sym)
+ {
+ len = sym->name_len;
+
+ /* Compute length of record exclusive of symbol name field. */
+ reclen = 2 * SIZEOF(short) + 2 * SIZEOF(char); /* common record header definition information */
+ switch (sym->psect)
+ {
+ case GTM_ANOTHER_MODULE: /* reference to psect from some other module */
+ reclen += SIZEOF(short);
+ break;
+
+ case GTM_CODE: /* symbol definition */
+ case GTM_LINKAGE: /* symbol definition */
+ reclen += SIZEOF(short) + 6 * SIZEOF(int4);
+ break;
+
+ default: /* presumably a reference to symbol defined in this module */
+ reclen += SIZEOF(short);
+ }
+ reclen += 1; /* space for length of name following */
+
+ /* Determine whether buffer has enough room; if not, flush it first. */
+ if (OBJ_SYM_BUF_SIZE < ROUND_UP(sym_buff_used + reclen + len,8))
+ {
+ ((short *) sym_buff)[0] = EOBJ$C_EGSD;
+ ((short *) sym_buff)[1] = sym_buff_used;
+ obj_rab.rab$l_rbf = sym_buff;
+ obj_rab.rab$w_rsz = sym_buff_used;
+ stat = sys$put(&obj_rab);
+ if (stat != RMS$_NORMAL)
+ rts_error (VARLSTCNT(6) ERR_OBJFILERR, 2, object_name_len, object_file_name, stat,
+ obj_fab.fab$l_stv);
+ sym_buff_used = 8;
+ emit_last_immed = NO_IMMED;
+ }
+
+ /* Add next symbol to buffer. */
+ fast = sym_buff + sym_buff_used;
+ *((short *) fast)++ = EGSD$C_SYM;
+
+ *((short *) fast)++ = 0; /* EGSY$W_SIZE (record length, after padding) */
+
+ /* Global symbol data type -- currently ignored by linker.
+ WARNING: these values need to be defined properly when the linker starts processing them. [lidral] */
+ if (sym->psect == GTM_ANOTHER_MODULE) /* code for "not defined in this module" */
+ *((char *) fast)++ = GSD_PROC_TYPE;
+ else
+ *((char *) fast)++ = GSD_DATA_TYPE;
+
+ *((char *) fast)++ = '\0'; /* alignment byte (must be zero) */
+
+ switch (sym->psect)
+ {
+ case GTM_ANOTHER_MODULE: /* psect from some other module */
+ *((short *) fast)++ = 0; /* ESRF$W_FLAGS = not defined here, not a weak reference */
+ break; /* no more fields in a reference */
+
+ case GTM_CODE:
+ *((short *) fast)++ = EGSY$M_DEF | EGSY$M_REL; /* ESDF$W_FLAGS */
+ *((int4 *) fast)++ = sym->value; /* ESDF$L_VALUE */
+ *((int4 *) fast)++ = 0;
+ *((int4 *) fast)++ = 0; /* ESDF$L_CODE_ADDRESS */
+ *((int4 *) fast)++ = 0;
+ *((int4 *) fast)++ = 0; /* ESDF$L_CA_PSINDX */
+ *((int4 *) fast)++ = sym->psect; /* ESDF$L_PSINDX */
+ break;
+
+ case GTM_LINKAGE:
+ *((short *) fast)++ = EGSY$M_DEF | EGSY$M_REL | EGSY$M_NORM; /* ESDF$W_FLAGS */
+ *((int4 *) fast)++ = sym->value; /* ESDF$L_VALUE */
+ *((int4 *) fast)++ = 0;
+ *((int4 *) fast)++ = 0; /* ESDF$L_CODE_ADDRESS = offset in GTM_CODE */
+ *((int4 *) fast)++ = 0;
+ *((int4 *) fast)++ = GTM_CODE; /* ESDF$L_CA_PSINDX = psect containing code address */
+ *((int4 *) fast)++ = sym->psect; /* ESDF$L_PSINDX = psect containing procedure descriptor */
+ break;
+
+ default: /* presumably a reference to a symbol defined in this module */
+ *((short *) fast)++ = EGSY$M_REL; /* ESRF$W_FLAGS */
+ break; /* no more fields in a reference */
+ }
+
+ *((char *) fast)++ = len; /* ESDF$B_NAMLNG/ESRF$B_NAMLNG */
+
+ memcpy(fast, &sym->name[0], len);
+
+ fast += len;
+ len = fast - (sym_buff + sym_buff_used);
+ len = ROUND_UP(len, 8); /* round up to quadword boundary */
+ *((short *) (sym_buff + sym_buff_used + 2)) = len; /* fill in EGSD$C_SYM record length (EGSY$W_SIZE) field */
+
+ sym_buff_used += len;
+ sym = sym->next;
+ }
+ /* flush symbol buffer */
+ if (sym_buff_used > 8)
+ {
+ ((short *) sym_buff)[0] = EOBJ$C_EGSD;
+ ((short *) sym_buff)[1] = sym_buff_used;
+ obj_rab.rab$l_rbf = sym_buff;
+ obj_rab.rab$w_rsz = sym_buff_used;
+ stat = sys$put(&obj_rab);
+ if (stat != RMS$_NORMAL)
+ rts_error (VARLSTCNT(6) ERR_OBJFILERR, 2, object_name_len, object_file_name, stat, obj_fab.fab$l_stv);
+ sym_buff_used = 8;
+ emit_last_immed = NO_IMMED;
+ }
+}
+
+
+/*
+ * set_psect
+ *
+ * Args: psect index, byte offset
+ *
+ * Description: Issues TIR commands to set image location to the specified psect's base plus the given byte offset.
+ * Resets current_psect.
+ */
+
+void set_psect(
+int psect, /* psect (program section) index */
+int offset) /* byte offset into psect */
+{
+ register char *fast;
+ char set_psect_rec[MAX_REC_SIZE]; /* TIR records to set the psect */
+
+ assert (offset >= psect_use_tab[psect]); /* not really necessary, but our code works this way */
+
+ if (current_psect != psect || psect_use_tab[current_psect] != offset)
+ {
+ emit_sta_pq(psect, offset);
+
+ fast = set_psect_rec;
+ *((short *) fast)++ = ETIR$C_CTL_SETRB; /* pop stack to set relocation base */
+ *((short *) fast)++ = 2 * SIZEOF(short);
+ linker_stack_depth--;
+
+ buff_emit(set_psect_rec, fast - set_psect_rec);
+
+ current_psect = psect;
+ psect_use_tab[psect] = offset;
+ emit_last_immed = NO_IMMED;
+ }
+}
diff --git a/sr_avms/obj_filesp.h b/sr_avms/obj_filesp.h
new file mode 100644
index 0000000..f8c9164
--- /dev/null
+++ b/sr_avms/obj_filesp.h
@@ -0,0 +1,28 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2004 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef OBJ_FILESP_INCLUDED
+#define OBJ_FILESP_INCLUDED
+
+void emit_pidr(int4 offset, unsigned char psect);
+void emit_reference(uint4 refaddr, mstr *name, uint4 *result);
+struct sym_table *define_symbol(int4 psect, mstr *name, int4 value);
+
+/* Prefix of the psect name generated for every routine table entry (used in obj_file.c */
+#define RNAMB_PREF "GTM$R"
+#define RNAMB_PREF_LEN STR_LIT_LEN(RNAMB_PREF)
+
+/* First significant characters of the routine name on which the table is already sorted by the VMS linker */
+#define RNAME_SORTED_LEN (EGPS$S_NAME - RNAMB_PREF_LEN) /* EGPS$S_NAME defined in objlangdefs.h */
+
+#define RNAME_ALL_Z "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz"
+
+#endif /* OBJ_FILESP_INCLUDED */
diff --git a/sr_avms/op_bkpt.m64 b/sr_avms/op_bkpt.m64
new file mode 100644
index 0000000..ad06c27
--- /dev/null
+++ b/sr_avms/op_bkpt.m64
@@ -0,0 +1,427 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ;
+; Copyright 2001, 2010 Fidelity Information Services, Inc ;
+; ;
+; This source code contains the intellectual property ;
+; of its copyright holder(s), and is made available ;
+; under a license. If you do not know the terms of ;
+; the license, please stop and do not read further. ;
+; ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ .title OP_BKPT
+
+ G_MSF
+
+ $linkage_section
+
+a_opp_ret:
+ .linkage_pair opp_ret
+
+a_op_retarg:
+ .linkage_pair op_retarg
+
+a_frame_pointer:
+ .address frame_pointer
+
+a_zstep_level:
+ .address zstep_level
+
+
+ $code_section
+
+
+;*1*********************************************************************
+ $routine OPP_ZSTEPRET, entry=OPP_ZSTEPRET_CA, kind=null
+ lda sp, -8(sp)
+ stq r3, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ ldl r28, msf$typ_off(r12)
+ blbc r28, 10$
+
+ ldq r28, a_zstep_level
+ ldl r28, (r28)
+ subq r28, r12, r28
+ bgt r28, 10$
+
+ $call op_zstepret, set_arg_info=false, nonstandard=true
+
+10$: ldq r26, a_opp_ret
+ ldq r27, a_opp_ret+8
+ ldq r3, (sp)
+ lda sp, 8(sp)
+ jmp r26
+
+ $end_routine
+
+ .page
+;*2*********************************************************************
+ $routine OPP_ZSTEPRETARG, entry=OPP_ZSTEPRETARG_CA, kind=null
+ lda sp, -24(sp)
+ stq r3, (sp)
+ stq r0, 8(sp)
+ stq r1, 16(sp)
+ mov r27, r3
+ .base r3, $ls
+
+ ldl r28, msf$typ_off(r12)
+ blbc r28, 10$
+
+ ldq r28, a_zstep_level
+ ldl r28, (r28)
+ subq r28, r12, r28
+ bgt r28, 10$
+
+ $call op_zstepret, set_arg_info=false, nonstandard=true
+
+10$: ldq r26, a_op_retarg
+ ldq r27, a_op_retarg+8
+ ldq r3, (sp)
+ ldq r0, 8(sp)
+ ldq r1, 16(sp)
+ lda sp, 24(sp)
+ jmp r26
+
+ $end_routine
+
+
+;*3*********************************************************************
+ $routine OP_ZBFETCH, entry=OP_ZBFETCH_CA, kind=null
+stack_offset = 16
+ lda sp, -stack_offset(sp)
+ stq r3, (sp)
+ stq r2, 8(sp)
+ mov r27, r3
+ .base r3, $ls
+
+ stl r26, msf$mpc_off(r12)
+
+ fetch_args r2, stack_offset
+ $call op_zbreak, args=<r12>, set_arg_info=false, nonstandard=true
+
+ getframe
+ bne r0, 10$
+
+ imb
+
+10$: ldq r3, (sp)
+ ldq r2, 8(sp)
+ lda sp, stack_offset(sp)
+ ret r26
+
+ $end_routine
+
+ .page
+;*4*********************************************************************
+ $routine OP_ZBSTART, entry=OP_ZBSTART_CA, kind=null
+ lda sp, -8(sp)
+ stq r3, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ stl r26, msf$mpc_off(r12)
+
+ $call op_zbreak, args=<r12>, set_arg_info=false, nonstandard=true
+
+ getframe
+ bne r0, 10$
+
+ imb
+
+10$: ldq r3, (sp)
+ lda sp, 8(sp)
+ ret r26
+
+ $end_routine
+
+
+;*5*********************************************************************
+ $routine OP_ZSTEPFETCH, entry=OP_ZSTEPFETCH_CA, kind=null
+stack_offset = 16
+ lda sp, -stack_offset(sp)
+ stq r3, (sp)
+ stq r2, 8(sp)
+ mov r27, r3
+ .base r3, $ls
+
+ stl r26, msf$mpc_off(r12)
+
+ fetch_args r2, stack_offset
+ $call op_zst_break, set_arg_info=false, nonstandard=true
+
+ getframe
+ imb
+
+ ldq r3, (sp)
+ ldq r2, 8(sp)
+ lda sp, stack_offset(sp)
+ ret r26
+
+ $end_routine
+
+ .page
+;*6*********************************************************************
+ $routine OP_ZSTEPSTART, entry=OP_ZSTEPSTART_CA, kind=null
+ lda sp, -8(sp)
+ stq r3, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ stl r26, msf$mpc_off(r12)
+
+ $call op_zst_break, set_arg_info=false, nonstandard=true
+
+ getframe
+ imb
+
+ ldq r3, (sp)
+ lda sp, 8(sp)
+ ret r26
+
+ $end_routine
+
+
+;*7*********************************************************************
+ $routine OP_ZSTZBFETCH, entry=OP_ZSTZBFETCH_CA, kind=null
+stack_offset = 16
+ lda sp, -stack_offset(sp)
+ stq r3, (sp)
+ stq r2, 8(sp)
+ mov r27, r3
+ .base r3, $ls
+
+ stl r26, msf$mpc_off(r12)
+
+ fetch_args r2, stack_offset
+ $call op_zbreak, args=<r12>, set_arg_info=false, nonstandard=true
+ $call op_zst_break, set_arg_info=false, nonstandard=true
+
+ getframe
+ imb
+
+ ldq r3, (sp)
+ ldq r2, 8(sp)
+ lda sp, stack_offset(sp)
+ ret r26
+
+ $end_routine
+
+ .page
+;*8*********************************************************************
+ $routine OP_ZSTZBSTART, entry=OP_ZSTZBSTART_CA, kind=null
+ lda sp, -8(sp)
+ stq r3, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ stl r26, msf$mpc_off(r12)
+
+ $call op_zbreak, args=<r12>, set_arg_info=false, nonstandard=true
+ $call op_zst_break, set_arg_info=false, nonstandard=true
+
+ getframe
+ imb
+
+ ldq r3, (sp)
+ lda sp, 8(sp)
+ ret r26
+
+ $end_routine
+
+ .page
+;*9*********************************************************************
+ $routine OP_ZSTZB_FET_OVER, entry=OP_ZSTZB_FET_OVER_CA, kind=null
+stack_offset = 16
+ lda sp, -stack_offset(sp)
+ stq r3, (sp)
+ stq r2, 8(sp)
+ mov r27, r3
+ .base r3, $ls
+
+ stl r26, msf$mpc_off(r12)
+
+ fetch_args r2, stack_offset
+ $call op_zbreak, args=<r12>, set_arg_info=false, nonstandard=true
+
+ ldq r28, a_zstep_level
+ ldl r28, (r28)
+ subq r28, r12, r28
+ ble r28, 10$
+ beq r0, 20$
+
+ $call op_zst_over, set_arg_info=false, nonstandard=true
+
+ ldl r26, msf$mpc_off(r12)
+ br lbl30a
+
+10$: $call op_zst_break, set_arg_info=false, nonstandard=true
+20$: getframe
+ imb
+
+lbl30a: ldq r3, (sp)
+ ldq r2, 8(sp)
+ lda sp, stack_offset(sp)
+ ret r26
+
+ $end_routine
+
+ .page
+;*10********************************************************************
+ $routine OP_ZSTZB_ST_OVER, entry=OP_ZSTZB_ST_OVER_CA, kind=null
+ lda sp, -8(sp)
+ stq r3, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ stl r26, msf$mpc_off(r12)
+
+ $call op_zbreak, args=<r12>, set_arg_info=false, nonstandard=true
+
+ ldq r28, a_zstep_level
+ ldl r28, (r28)
+ subq r28, r12, r28
+ ble r28, 10$
+ beq r0, 20$
+
+ $call op_zst_over, set_arg_info=false, nonstandard=true
+
+ ldl r26, msf$mpc_off(r12)
+ br lbl30b
+
+10$: $call op_zst_break, set_arg_info=false, nonstandard=true
+20$: getframe
+ imb
+
+lbl30b: ldq r3, (sp)
+ lda sp, 8(sp)
+ ret r26
+
+ $end_routine
+
+ .page
+;*11********************************************************************
+ $routine OP_ZST_FET_OVER, entry=OP_ZST_FET_OVER_CA, kind=null
+stack_offset = 16
+ lda sp, -stack_offset(sp)
+ stq r3, (sp)
+ stq r2, 8(sp)
+ mov r27, r3
+ .base r3, $ls
+
+ stl r26, msf$mpc_off(r12)
+
+ fetch_args r2, stack_offset
+
+ ldq r28, a_zstep_level
+ ldl r28, (r28)
+ subq r28, r12, r28
+ bgt r28, lbl10a
+
+ $call op_zst_break, set_arg_info=false, nonstandard=true
+
+ getframe
+ imb
+ br lbl20a
+
+lbl10a: $call op_zst_over, set_arg_info=false, nonstandard=true
+
+ ldl r26, msf$mpc_off(r12)
+
+lbl20a: ldq r3, (sp)
+ ldq r2, 8(sp)
+ lda sp, stack_offset(sp)
+ ret r26
+
+ $end_routine
+
+ .page
+;*12********************************************************************
+ $routine OP_ZST_ST_OVER, entry=OP_ZST_ST_OVER_CA, kind=null
+ lda sp, -8(sp)
+ stq r3, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ stl r26, msf$mpc_off(r12)
+
+ ldq r28, a_zstep_level
+ ldl r28, (r28)
+ subq r28, r12, r28
+ bgt r28, lbl10b
+
+ $call op_zst_break, set_arg_info=false, nonstandard=true
+
+ getframe
+ imb
+ br lbl20b
+
+lbl10b: $call op_zst_over, set_arg_info=false, nonstandard=true
+
+ ldl r26, msf$mpc_off(r12)
+
+lbl20b: ldq r3, (sp)
+ lda sp, 8(sp)
+ ret r26
+
+ $end_routine
+
+ .page
+;*13********************************************************************
+ $routine OPP_ZST_OVER_RET, entry=OPP_ZST_OVER_RET_CA, kind=null
+ lda sp, -8(sp)
+ stq r3, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ ldl r28, msf$typ_off(r12)
+ blbc r28, 10$
+
+ ldq r28, a_zstep_level
+ ldl r28, (r28)
+ ldl r24, msf$old_frame_off(r12)
+ subq r28, r24, r28
+ bgt r28, 10$
+
+ $call op_zstepret, set_arg_info=false, nonstandard=true
+
+10$: ldq r26, a_opp_ret
+ ldq r27, a_opp_ret+8
+ ldq r3, (sp)
+ lda sp, 8(sp)
+ jmp r26
+
+ $end_routine
+
+
+;*14********************************************************************
+ $routine OPP_ZST_OVER_RETARG, entry=OPP_ZST_OVER_RETARG_CA, kind=null
+ lda sp, -24(sp)
+ stq r3, (sp)
+ stq r0, 8(sp)
+ stq r1, 16(sp)
+ mov r27, r3
+ .base r3, $ls
+
+ ldl r28, msf$typ_off(r12)
+ blbc r28, 10$
+
+ ldq r28, a_zstep_level
+ ldl r28, (r28)
+ ldl r24, msf$old_frame_off(r12)
+ subq r28, r24, r28
+ bgt r28, 10$
+
+ $call op_zstepret, set_arg_info=false, nonstandard=true
+
+10$: ldq r26, a_op_retarg
+ ldq r27, a_op_retarg+8
+ ldq r3, (sp)
+ ldq r0, 8(sp)
+ ldq r1, 16(sp)
+ lda sp, 24(sp)
+ jmp r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/op_call.m64 b/sr_avms/op_call.m64
new file mode 100644
index 0000000..bf33e21
--- /dev/null
+++ b/sr_avms/op_call.m64
@@ -0,0 +1,51 @@
+ .title OP_CALL
+; ###############################################################
+; # #
+; # Copyright 2001, 2003 Sanchez Computer Associates, Inc. #
+; # #
+; # This source code contains the intellectual property #
+; # of its copyright holder(s), and is made available #
+; # under a license. If you do not know the terms of #
+; # the license, please stop and do not read further. #
+; # #
+; ###############################################################
+
+ G_MSF
+
+
+ $linkage_section
+
+a_frame_pointer:
+ .address frame_pointer
+
+
+ $code_section
+
+ $routine OP_CALLB, entry=OP_CALL_CA, aliases=<OP_CALLW, OP_CALLL>, kind=null
+
+ lda sp, -16(sp)
+ stq r3, 8(sp)
+ stq r26, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ ldq r1, a_frame_pointer
+ ldl r1, (r1)
+
+; Bump the return PC past the branch instruction following the jsr that got us here:
+ addl r26, r16, r26 ; length of branch sequence
+ stl r26, msf$mpc_off(r1) ; and store it in the Mumps stack frame
+
+ $call COPY_STACK_FRAME, set_arg_info=false, nonstandard=true
+
+ ldq r12, a_frame_pointer
+ ldl r12, (r12)
+
+ ldq r28, (sp)
+ ldq r3, 8(sp)
+ lda sp, 16(sp)
+ ret r28
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/op_callsp.m64 b/sr_avms/op_callsp.m64
new file mode 100644
index 0000000..ebe27ce
--- /dev/null
+++ b/sr_avms/op_callsp.m64
@@ -0,0 +1,54 @@
+ .title OP_CALLSP
+; ###############################################################
+; # #
+; # Copyright 2001, 2007 Fidelity Information Services, Inc #
+; # #
+; # This source code contains the intellectual property #
+; # of its copyright holder(s), and is made available #
+; # under a license. If you do not know the terms of #
+; # the license, please stop and do not read further. #
+; # #
+; ###############################################################
+
+ G_MSF
+
+
+ $linkage_section
+
+a_frame_pointer:
+ .address frame_pointer
+
+
+ $code_section
+
+ $routine OP_CALLSPB, entry=OP_CALLSP_CA, aliases=<OP_CALLSPW, OP_CALLSPL>, kind=null
+
+ lda sp, -16(sp)
+ stq r3, 8(sp)
+ stq r26, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ ldq r1, a_frame_pointer
+ ldl r1, (r1)
+
+; Bump the return PC past the branch instruction following the jsr that got us here:
+ addl r26, r16, r26 ; length of branch sequence
+ stl r26, msf$mpc_off(r1) ; and store it in the Mumps stack frame
+
+ $call EXFUN_FRAME, set_arg_info=false, nonstandard=true
+ ldl r16, 0(r10) ; Value of $TEST
+ $call PUSH_TVAL, args=<r16>, set_arg_info=false, nonstandard=true
+
+ ldq r12, a_frame_pointer
+ ldl r12, (r12)
+ ldl r9, msf$temps_ptr_off(r12)
+
+ ldq r28, (sp)
+ ldq r3, 8(sp)
+ lda sp, 16(sp)
+ ret r28
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/op_contain.m64 b/sr_avms/op_contain.m64
new file mode 100644
index 0000000..1763445
--- /dev/null
+++ b/sr_avms/op_contain.m64
@@ -0,0 +1,243 @@
+;#################################################################
+;# #
+;# Copyright 2006, 2008 Fidelity Information Services, Inc #
+;# #
+;# This source code contains the intellectual property #
+;# of its copyright holder(s), and is made available #
+;# under a license. If you do not know the terms of #
+;# the license, please stop and do not read further. #
+;# #
+;#################################################################
+ .title op_contain "'[' ('contains') operator"
+
+; OP_CONTAIN implements the MUMPS string relational operator "[" ("contains"):
+;
+; lhs [ rhs
+;
+; lhs ("left-hand-side") and rhs ("right-hand-side") are expressions interpreted
+; as strings. If rhs is contained exactly somewhere in lhs, the resulting
+; relation is true, otherwise, false.
+;
+; On entry to this routine:
+; r0 -> mval for lhs
+; r1 -> mval for rhs
+;
+; This version of OP_CONTAIN is not a simple, straightforward translation of the
+; VAX version. The VAX has a rich set of instructions that can be used for string
+; manipulation, and the VAX version of this routine takes advantage of that, using
+; locc and cmpb instructions, as well as auto-increment addressing mode. None of
+; these features exist in the Alpha architecture. Alpha does have a set of byte
+; manipulation instructions, however, but they work only on data in registers.
+; Thus, it makes sense to load as much of the strings in question into registers
+; as is feasible, rather than working with just one byte at a time.
+
+ mval$def
+
+ $routine OP_CONTAIN, entry=OP_CONTAIN_CA, kind=null
+
+; Routine prologue:
+ lda sp, -48(sp)
+ stq r26, (sp)
+ stq r13, 8(sp)
+ stq r2, 16(sp)
+ stq r3, 24(sp)
+ stq r4, 32(sp)
+ stq r5, 40(sp)
+
+ mov r27, r13 ; Set up a base register
+ .base r13, $ls ; for the linkage section
+; End of prologue
+
+ .page
+; **************************************************************************************
+; Validate the input parameters and handle the trivial cases.
+
+; Make sure that both lhs and rhs are strings:
+ mov r0, r2 ; r2 -> lhs mval
+ mov r1, r3 ; r3 -> rhs mval
+ mv_force_defined r2
+ mv_force_str (r2)
+ mv_force_defined r3
+ mv_force_str (r3)
+
+; If rhs is a null string, we have a match (by definition):
+ ldl r1, mval$l_strlen(r3) ; r1 = length of rhs string
+ beq r1, match
+
+; If lhs is a null string, we don't have a match:
+ ldl r0, mval$l_strlen(r2) ; r0 = length of lhs string
+ beq r0, nomatch
+
+; If lhs is shorter than rhs, there can't possibly be a match:
+ cmplt r0, r1, r24
+ blbs r24, nomatch
+
+
+; **************************************************************************************
+; OK, neither string is null, and their lengths check out; load as much
+; of rhs as possible into r5 (i.e. min (8, length of rhs) characters),
+; then load the same number of characters from lhs into r4.
+
+; Load the first 8 characters of rhs into r5:
+ ldl r3, mval$a_straddr(r3) ; r3 -> rhs string
+ ldq_u r5, (r3)
+ ldq_u r28, 7(r3)
+ extql r5, r3, r5
+ extqh r28, r3, r28
+ or r28, r5, r5
+
+; Load the first 8 characters of lhs into r4:
+ ldl r2, mval$a_straddr(r2) ; r2 -> lhs string
+ ldq_u r4, (r2)
+ ldq_u r28, 7(r2)
+ extql r4, r2, r4
+ extqh r28, r2, r28
+ or r28, r4, r4
+
+; Compute the number of characters to retain in r5 and r4:
+ mov 8, r22
+ cmplt r1, r22, r24
+ cmovlbs r24, r1, r22 ; r22 = min (8, r1)
+
+; Clear any excess characters that may have been loaded above:
+ mov ^xff, r28
+ sll r28, r22, r28
+ zap r5, r28, r5
+ zap r4, r28, r4
+
+; Update the string counters and pointers:
+ subq r1, r22, r1
+ subq r0, r22, r0
+ addq r3, r22, r3
+ addq r2, r22, r2
+
+; Compute a shift count for later use in loading new characters from lhs into r4:
+ subq r22, 1, r22
+ sll r22, 3, r22
+
+
+; **************************************************************************************
+; At this point,
+; r5 contains either all of rhs, or the first 8 characters of rhs
+; r4 contains the corresponding number of characters from lhs
+; r22 = a shift count to use for loading new characters from lhs into r4
+; r1 = the number of characters remaining in rhs (exclusive of what's in r5)
+; r0 = the number of characters remaining in lhs (exclusive of what's in r4)
+; r3 -> the remainder of rhs (meaningful only if r1 > 0)
+; r2 -> the remainder of lhs
+
+main_loop:
+ cmpeq r4, r5, r24
+
+; If there's a match here, go check the remainder of rhs:
+ blbs r24, check_remainder
+
+; There's no match this iteration; if nothing's left in lhs, return false:
+ beq r0, nomatch
+
+; Return here from check_remainder if no match was found there, either:
+restart:
+
+; Load the next character from lhs into r4:
+ srl r4, 8, r4 ; shift everything down by a byte, losing the low order character
+ ldq_u r28, (r2) ; load the quadword containing the next character in lhs
+ extbl r28, r2, r28 ; extract the character
+ sll r28, r22, r28 ; shift it up into the correct position
+ or r28, r4, r4 ; and stick it into r4
+
+; Update the lhs context:
+ subq r0, 1, r0
+ lda r2, 1(r2)
+
+; And try again:
+ br main_loop
+
+ .page
+; **************************************************************************************
+; The main loop found a match somewhere in lhs with the first portion of rhs. We now
+; have to check to see if the remainder of rhs (if any) matches the same number of characters
+; in the remainder of lhs.
+
+check_remainder:
+
+; If there's nothing left in rhs, we have a match:
+ beq r1, match
+
+; If there are fewer characters remaining in lhs than there are in rhs,
+; then there can't possibly be a match:
+ cmplt r0, r1, r28
+ blbs r28, nomatch
+
+; Save context:
+ mov r1, r17 ; r17 = remaining length of rhs
+ mov r3, r19 ; r19 -> remainder of rhs
+ mov r2, r18 ; r18 -> remainder of lhs
+
+; Now loop, comparing the remainders of the two strings.
+
+remainder_loop:
+
+; Load the first 8 characters of the remainder of rhs into r21:
+ ldq_u r21, (r19)
+ ldq_u r28, 7(r19)
+ extql r21, r19, r21
+ extqh r28, r19, r28
+ or r28, r21, r21
+
+; Load the first 8 characters of the remainder of lhs into r20:
+ ldq_u r20, (r18)
+ ldq_u r28, 7(r18)
+ extql r20, r18, r20
+ extqh r28, r18, r28
+ or r28, r20, r20
+
+; Should we compare all 8 characters?
+ cmplt r17, 8, r24
+ blbc r24, compare ; yes; skip
+
+; We need to compare fewer than 8 characters, so
+; clear the excess characters that were loaded above:
+ mov ^xff, r28
+ sll r28, r17, r28
+ zap r21, r28, r21
+ zap r20, r28, r20
+
+compare:
+ cmpeq r20, r21, r24
+
+; If no match, go back to the main loop and try again:
+ blbc r24, restart
+
+; Update for the next iteration:
+ subq r17, 8, r17
+ ble r17, match
+ lda r19, 8(r19)
+ lda r18, 8(r18)
+
+ br remainder_loop
+
+
+; **************************************************************************************
+
+nomatch:
+ clr r0
+ br return
+
+match:
+ mov 1, r0
+
+return:
+ mov r0, r24 ; set condition code (emulator) according to function result
+; Routine epilogue:
+ ldq r28, (sp)
+ ldq r13, 8(sp)
+ ldq r2, 16(sp)
+ ldq r3, 24(sp)
+ ldq r4, 32(sp)
+ ldq r5, 40(sp)
+ lda sp, 48(sp)
+ ret r28
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/op_currtn.m64 b/sr_avms/op_currtn.m64
new file mode 100644
index 0000000..3671c57
--- /dev/null
+++ b/sr_avms/op_currtn.m64
@@ -0,0 +1,39 @@
+;#################################################################
+;# #
+;# Copyright 2006, 2008 Fidelity Information Services, Inc #
+;# #
+;# This source code contains the intellectual property #
+;# of its copyright holder(s), and is made available #
+;# under a license. If you do not know the terms of #
+;# the license, please stop and do not read further. #
+;# #
+;#################################################################
+ .title OP_CURRTN
+
+ g_msf
+ mval$def
+
+ $routine OP_CURRTN, entry=OP_CURRTN_CA, kind=null
+ lda sp, -16(sp)
+ stq r26, (sp)
+ .base r27, $ls
+
+; Set r1->mval$b_mvtype to mval$m_str (r1->mvtype = MV_STR):
+ ldl r28, mval$w_mvtype(r1)
+ mskwl r28, mval$w_mvtype, r28
+ or r28, mval$m_str, r28
+ stl r28, mval$w_mvtype(r1)
+
+ ldl r0, msf$rvector_off(r12)
+ ldl r16, mrt$rtn_len(r0)
+ stl r16, mval$l_strlen(r1) ; r1->str.len = frame_pointer->rvector->routine_name.len
+ ldl r16, mrt$rtn_addr(r0)
+ stl r16, mval$a_straddr(r1) ; r1->str.addr = frame_pointer->rvector->routine_name.addr
+
+ ldq r26, (sp)
+ lda sp, 16(sp)
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/op_equ.m64 b/sr_avms/op_equ.m64
new file mode 100644
index 0000000..4c71901
--- /dev/null
+++ b/sr_avms/op_equ.m64
@@ -0,0 +1,32 @@
+ .title op_equ determine whether two mvals are equal
+
+; op_equ
+;
+; op_equ calls is_equ to compare two mval operands to determine
+; whether they are equal. The actual comparison is performed by
+; the C-callable routine is_equ; op_equ is needed as an interlude
+; between generated GT.M code that passes the arguments in r0
+; and r0 instead of in the argument registers.
+;
+; entry
+; r0, r1 contain addresses of mval's to be compared
+;
+; return
+; r0 1, if the two mval's are equal
+; 0, if they're not equal
+
+ $routine name=op_equ,entry=op_equ_ca,kind=stack, -
+ base_reg_is_fp=true,rsa_offset=24,saved_regs=<fp>
+
+ .base r27, $ls
+
+ mov r0, r16
+ mov r1, r17
+ $call is_equ, args=<r16,r17>, set_arg_info=false
+ mov r0, r24 ; copy is_equ's return value to GT.M's condition code register
+
+ $return
+
+ $end_routine name=op_equ
+
+ .end
diff --git a/sr_avms/op_exfun.m64 b/sr_avms/op_exfun.m64
new file mode 100644
index 0000000..496cfde
--- /dev/null
+++ b/sr_avms/op_exfun.m64
@@ -0,0 +1,85 @@
+ .title op_exfun - invoke (internal) extrinsic function
+; ###############################################################
+; # #
+; # Copyright 2001, 2012 Fidelity Information Services, Inc #
+; # #
+; # This source code contains the intellectual property #
+; # of its copyright holder(s), and is made available #
+; # under a license. If you do not know the terms of #
+; # the license, please stop and do not read further. #
+; # #
+; ###############################################################
+
+ G_MSF
+
+; op_exfun - invoke (internal) extrinsic function
+;
+; arguments:
+; ret_value address for function to place return value
+; offset to this frame's continue (return) point past branch to subroutine
+; mask
+; actualcnt actual argument count
+; actual1 address of actual first argument
+; actual2 address of actual second argument
+; . . .
+
+ $routine name=op_exfun, entry=op_exfun_ca, kind=stack, saved_regs=<r2, r13, r16, r17, r18, r19, r20, r21, fp>, -
+ data_section_pointer=true, -
+ data_section=<$DATA$, QUAD, NOPIC, CON, REL, LCL, NOSHR, MIX, NOEXE, RD, WRT>
+
+ $linkage_section
+
+A_frame_pointer: .address frame_pointer
+
+ $code_section
+
+ mov r27, r13
+ .base r13, $ls
+
+ ldq r1, A_frame_pointer
+ ldl r1, (r1)
+ addl r26, r17, r28 ; add size of jump sequence to get return addr for frame.
+ stl r28, msf$mpc_off(r1)
+ $call exfun_frame, set_arg_info=false
+ ldl r16, 0(r10) ; $TRUTH aka $TEST value
+ bic r16, #^Xfe, r16 ; clear all but low order bit
+ ldq r17, $RSA_OFFSET+24(fp) ; old r16 (ret_value)
+ ldq r18, $RSA_OFFSET+40(fp) ; old r18 (mask)
+ ldq r19, $RSA_OFFSET+48(fp) ; old r19 (actualcnt)
+ ldq r20, $RSA_OFFSET+56(fp) ; old r20 (actual1)
+ ldq r21, $RSA_OFFSET+64(fp) ; old r21 (actual2)
+ lda r25, 4(r19)
+
+; If more than 2 actual arguments, push rest onto stack.
+ subq r19, 2, r28 ; number of arguments originally passed on stack (actual3 . . . actualn)
+ ble r28, zero_in_stack ; all original arguments in registers
+ lda r0, $SIZE(fp)
+ subq r28, 1, r28 ; offset = number - 1
+ s8addq r28, r0, r0 ; address of actualn
+loop: ldq r1, (r0)
+ lda sp, -8(sp)
+ lda r0, -8(r0)
+ stq r1, (sp)
+ subq r28, 1, r28
+ bge r28, loop
+zero_in_stack:
+ $call push_parm, set_arg_info=false ; push_parm ($T, ret_value, mask, actualcnt [, actual1[, actual2 . . .]])
+
+done: ldq r28, A_frame_pointer
+ ldl r2, (r28)
+ mov r2, r12
+ ldl r9, msf$temps_ptr_off(r12)
+
+ $begin_epilogue
+ mov fp, sp
+ ldq r26, $RSA_OFFSET(sp)
+ ldq r2, $RSA_OFFSET+8(sp)
+ ldq r13, $RSA_OFFSET+16(sp)
+ ldq fp, $RSA_OFFSET+72(sp)
+ lda sp, $SIZE(sp)
+ ret r26
+ $end_epilogue
+
+ $end_routine name=op_exfun
+
+ .end
diff --git a/sr_avms/op_extcall.m64 b/sr_avms/op_extcall.m64
new file mode 100644
index 0000000..1d0a021
--- /dev/null
+++ b/sr_avms/op_extcall.m64
@@ -0,0 +1,111 @@
+ .title op_extcall - call external (MUMPS) routine
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ;
+; Copyright 2005, 2012 Fidelity Information Services, Inc ;
+; ;
+; This source code contains the intellectual property ;
+; of its copyright holder(s), and is made available ;
+; under a license. If you do not know the terms of ;
+; the license, please stop and do not read further. ;
+; ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ G_MSF
+ PROCDESC
+
+; op_extcall calls and external GT.M MUMPS routine. If the routine has not yet
+; been linked into the current image, op_extcall will first link it by invoking
+; the auto-ZLINK function.
+;
+; Args:
+; procdsc - address of procedure descriptor of routine to call
+; labaddr - address of offset into routine to which to transfer control
+
+ $routine name=op_extcall, entry=op_extcall_ca, kind=stack, saved_regs=<fp>, -
+ data_section_pointer=true
+
+ $linkage_section
+
+A_frame_pointer: .address frame_pointer
+
+L_ERR_GTMCHECK: .long ERR_GTMCHECK
+L_ERR_LABELUNKNOWN: .long ERR_LABELUNKNOWN
+
+ $data_section
+
+PDSC_FLAGS:
+ .long GTM_PD_FLAGS
+
+
+ $code_section
+
+ .base r27, $ls
+ ldq r22, $dp
+ .base r22, $ds
+
+ putframe r12
+
+ mov r27, r13
+ .base r13, $ls
+
+ beq r16, L20 ; if procdsc == 0, this routine has not yet been linked into current image
+ beq r17, L40 ; if labaddr == 0 (and procdsc != 0), there is some interal error
+
+; Check whether first argument is procedure descriptor or routine header.
+ ldl r28, PDSC_FLAGS
+ ldl r0, (r16)
+ xor r28, r0, r28
+ bne r28, L10 ; if not procedure descriptor, it must be a routine header
+
+ ldq r16, 8(r16) ; rhdaddr = procdsc->entry_point ; entry point address is address of routine header
+L10: ldl r17, (r17) ; *lab_ln_ptr
+ beq r17, L40
+ ldl r28, mrt$curr_ptr(r16)
+ addl r17, r28, r17
+ addl r17, r16, r17 ; rhdaddr + *lab_ln_ptr
+ ldl r17, (r17) ; *labaddr
+ ldl r28, mrt$curr_ptr(r16) ; rhdaddr->current_rhead_ptr
+ addl r16, r28, r18 ; rhdaddr + rhdaddr->current_rhead_ptr
+ addl r17, r18, r18 ; rhdaddr + rhdaddr->current_rhead_ptr + *labaddr
+ $call new_stack_frame, args=<r16, mrt$lnk_ptr(r16)/L, r18>, set_arg_info=false
+
+ $begin_epilogue
+ getframe
+ mov fp, sp
+ ldq fp, $RSA_OFFSET+8(sp)
+ lda sp, $SIZE(sp)
+ ret r26
+ $end_epilogue
+
+L20: bne r17, L40 ; if labaddr != 0 (and procdsc == 0), there is some internal error
+ lda sp, -8(sp) ; auto_zlink will put value here
+ stq r31, (sp)
+ $call auto_zlink, args=<msf$mpc_off(r12)/L, sp>, set_arg_info=false
+ beq r0, L30
+ mov r0, r16 ; rhdaddr of newly-ZLINK'ed routine
+ ldq r17, (sp) ; new labaddr
+ lda sp, 8(sp)
+ beq r17, L30
+ br L10 ; auto_zlink returns pointer to a routine header, not a procedure descriptor
+
+L30: $call lib$signal, args=<L_ERR_GTMCHECK/L>
+ $begin_epilogue
+ getframe
+ mov fp, sp
+ ldq fp, $RSA_OFFSET+8(sp)
+ lda sp, $SIZE(sp)
+ ret r26
+ $end_epilogue
+
+L40: $call lib$signal, args=<L_ERR_LABELUNKNOWN/L>
+ $begin_epilogue
+ getframe
+ mov fp, sp
+ ldq fp, $RSA_OFFSET+8(sp)
+ lda sp, $SIZE(sp)
+ ret r26
+ $end_epilogue
+
+ $end_routine name=op_extcall
+
+ .end
diff --git a/sr_avms/op_extexfun.m64 b/sr_avms/op_extexfun.m64
new file mode 100644
index 0000000..9fba9cd
--- /dev/null
+++ b/sr_avms/op_extexfun.m64
@@ -0,0 +1,161 @@
+ .title op_extexfun - invoke external extrinsic function
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ;
+; Copyright 2005, 2012 Fidelity Information Services, Inc ;
+; ;
+; This source code contains the intellectual property ;
+; of its copyright holder(s), and is made available ;
+; under a license. If you do not know the terms of ;
+; the license, please stop and do not read further. ;
+; ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ G_MSF
+ PROCDESC
+
+; op_extexfun - invoke external extrinsic function
+;
+; arguments:
+; routine address of procedure descriptor of procedure containing extrinsic function
+; label address of offset into routine to which to transfer control
+; ret_value address for function to place return value
+; mask
+; actualcnt actual argument count
+; actual1 address of actual first argument
+; actual2 address of actual second argument
+; . . .
+
+ $routine name=op_extexfun, entry=op_extexfun_ca, kind=stack, saved_regs=<r2, r13, r18, r19, r20, r21, fp>, -
+ data_section_pointer=true, -
+ data_section=<$DATA$, QUAD, NOPIC, CON, REL, LCL, NOSHR, MIX, NOEXE, RD, WRT>
+
+ $linkage_section
+
+A_frame_pointer: .address frame_pointer
+
+L_ERR_FMLLSTMISSING: .long ERR_FMLLSTMISSING
+L_ERR_GTMCHECK: .long ERR_GTMCHECK
+L_ERR_LABELUNKNOWN: .long ERR_LABELUNKNOWN
+
+
+ $data_section
+
+PDSC_FLAGS:
+ .long GTM_PD_FLAGS
+
+
+ $code_section
+
+ .base r27, $ls
+ ldq r2, $dp
+ .base r2, $ds
+
+ putframe
+
+ mov r27, r13
+ .base r13, $ls
+
+L9: beq r16, L20 ; if procdsc == 0, this routine has not yet been linked into current image
+ beq r17, L40 ; if labaddr == 0 (and procdsc != 0), it's an unknown label
+
+; Check whether first argument is procedure descriptor or routine header.
+ ldl r28, PDSC_FLAGS
+ ldl r0, (r16)
+ xor r28, r0, r28
+ bne r28, L10 ; if not procedure descriptor, it must be a routine header
+
+ ldq r16, 8(r16) ; rhdaddr = procdsc->entry_point ; entry point address is address of routine header
+L10: mov r17, r22 ; temporarily save labaddr, so it is not overriden
+ ldl r17, (r17) ; *lab_ln_ptr
+ beq r17, L40
+ ldl r28, mrt$curr_ptr(r16)
+ addl r17, r28, r17
+ addl r17, r16, r17 ; rhdaddr + *lab_ln_ptr
+ ldl r17, (r17) ; *labaddr
+ ldl r28, mrt$curr_ptr(r16) ; rhdaddr->current_rhead_ptr
+ addl r16, r28, r18 ; rhdaddr + rhdaddr->current_rhead_ptr
+ addl r17, r18, r18 ; rhdaddr + rhdaddr->current_rhead_ptr + *labaddr
+ mov r22, r17 ; restore the original labaddr
+
+ addq r17, 4, r17 ; labaddr += 4, to point to has_parms
+ ldl r17, (r17) ; *has_parms
+ beq r17, L50 ; if has_parms == 0, then issue an error
+
+L12: $call new_stack_frame, args=<r16, mrt$lnk_ptr(r16)/L, r18>, set_arg_info=false
+ ldl r16, 0(r10) ; push $TRUTH aka $TEST
+ bic r16, #^Xfe, r16 ; clear all but low order bit
+L15: ldq r17, $RSA_OFFSET+24(fp) ; old r18 (ret_value)
+ ldq r18, $RSA_OFFSET+32(fp) ; old r19 (mask)
+ ldq r19, $RSA_OFFSET+40(fp) ; old r20 (actualcnt)
+ ldq r20, $RSA_OFFSET+48(fp) ; old r21 (actual1)
+ ldq r21, $SIZE(fp) ; actual2, if any
+ lda r25, 4(r19)
+
+; If more than 1 argument, push rest onto stack.
+ subq r19, 2, r28 ; number of arguments to put onto stack (actual3 . . . actualn)
+ ble r28, zero_in_stack ; all original arguments in registers
+ lda r0, $SIZE(fp)
+ s8addq r28, r0, r0 ; address of actualn
+loop: ldq r1, (r0)
+ lda sp, -8(sp)
+ lda r0, -8(r0)
+ stq r1, (sp)
+ subq r28, 1, r28
+ bgt r28, loop
+zero_in_stack:
+ $call push_parm, set_arg_info=false ; push_parm ($T, ret_value, mask, argc[, actual1[, actual2 . . .]])
+
+L16: getframe
+
+ $begin_epilogue
+ mov fp, sp
+ ldq r2, $RSA_OFFSET+8(sp)
+ ldq fp, $RSA_OFFSET+56(sp)
+ lda sp, $SIZE(sp)
+ ret r26
+ $end_epilogue
+
+L20: bne r17, L30 ; procdsc == 0, but label != 0 => internal error
+ lda sp, -8(sp) ; auto_zlink will put value here
+ stq r31, (sp)
+ $call auto_zlink, args=<msf$mpc_off(r12)/L, sp>, set_arg_info=false
+ beq r0, L30
+ mov r0, r16 ; rhdaddr of newly-ZLINK'ed routine
+ ldq r17, (sp) ; new labaddr
+ lda sp, 8(sp)
+ beq r17, L40 ; found routine, but labaddr still 0 => unknown label
+ br L10
+
+L30: $call lib$signal, args=<L_ERR_GTMCHECK/L>
+ $begin_epilogue
+ getframe
+ mov fp, sp
+ ldq r2, $RSA_OFFSET+8(sp)
+ ldq fp, $RSA_OFFSET+56(sp)
+ lda sp, $SIZE(sp)
+ ret r26
+ $end_epilogue
+
+L40: $call lib$signal, args=<L_ERR_LABELUNKNOWN/L>
+ $begin_epilogue
+ getframe
+ mov fp, sp
+ ldq r2, $RSA_OFFSET+8(sp)
+ ldq fp, $RSA_OFFSET+56(sp)
+ lda sp, $SIZE(sp)
+ ret r26
+ $end_epilogue
+
+L50: $call lib$signal, args=<L_ERR_FMLLSTMISSING/L>
+ $begin_epilogue
+ getframe
+ mov fp, sp
+ ldq r2, $RSA_OFFSET+8(sp)
+ ldq fp, $RSA_OFFSET+56(sp)
+ lda sp, $SIZE(sp)
+ ret r26
+ $end_epilogue
+
+ $end_routine name=op_extexfun
+
+ .end
diff --git a/sr_avms/op_extjmp.m64 b/sr_avms/op_extjmp.m64
new file mode 100644
index 0000000..3792f2a
--- /dev/null
+++ b/sr_avms/op_extjmp.m64
@@ -0,0 +1,115 @@
+ .title op_extjmp - jump to a label in an external (MUMPS) routine
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ;
+; Copyright 2005, 2012 Fidelity Information Services, Inc ;
+; ;
+; This source code contains the intellectual property ;
+; of its copyright holder(s), and is made available ;
+; under a license. If you do not know the terms of ;
+; the license, please stop and do not read further. ;
+; ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ G_MSF
+ PROCDESC
+
+; op_extjmp transfers control to a label in an external MUMPS module. If the routine
+; has not yet been linked into the current image, op_extjmp will first link it by
+; invoking the auto-ZLINK function.
+;
+; Args:
+; procdsc - address of procedure descriptor of routine containing the label
+; labaddr - address of offset into routine to which to transfer control
+
+ $routine name=op_extjmp, entry=op_extjmp_ca, kind=stack, saved_regs=<r13, fp>, -
+ data_section_pointer=true
+
+ $linkage_section
+
+A_frame_pointer: .address frame_pointer
+
+L_ERR_GTMCHECK: .long ERR_GTMCHECK
+L_ERR_LABELUNKNOWN: .long ERR_LABELUNKNOWN
+
+
+ $data_section
+
+PDSC_FLAGS:
+ .long GTM_PD_FLAGS
+
+
+ $code_section
+
+ .base r27, $ls
+ ldq r22, $dp
+ .base r22, $ds
+
+ putframe r12
+
+ mov r27, r13
+ .base r13, $ls
+
+ beq r16, L20 ; if procdsc == 0, this routine has not yet been linked into current image
+ beq r17, L40 ; if labaddr == 0 (and procdsc != 0), there is some interal error
+
+; Check whether first argument is a procedure descriptor or routine header.
+ ldl r28, PDSC_FLAGS
+ ldl r0, (r16)
+ xor r28, r0, r28
+ bne r28, L10 ; if not procedure descriptor, it must be a routine header
+
+ ldq r16, 8(r16) ; rhdaddr = procdsc->entry_point ; entry point address is address of routine header
+L10: ldl r17, (r17) ; *lab_ln_ptr
+ beq r17, L40
+ ldl r28, mrt$curr_ptr(r16)
+ addl r17, r28, r17
+ addl r17, r16, r17 ; rhdaddr + *lab_ln_ptr
+ ldl r17, (r17) ; *labaddr
+ ldl r28, mrt$curr_ptr(r16) ; rhdaddr->current_rhead_ptr
+ addl r16, r28, r18 ; rhdaddr + rhdaddr->current_rhead_ptr
+ addl r17, r18, r18 ; rhdaddr + rhdaddr->current_rhead_ptr + *labaddr
+ $call flush_jmp, args=<r16, mrt$lnk_ptr(r16)/L, r18>, set_arg_info=false
+
+ $begin_epilogue
+ getframe
+ imb
+ mov fp, sp
+ ldq fp, $RSA_OFFSET+16(sp)
+ lda sp, $SIZE(sp)
+ ret r26
+ $end_epilogue
+
+L20: bne r17, L40 ; if labaddr != 0 (and procdsc == 0), there is some internal error
+ lda sp, -8(sp) ; auto_zlink will put value here
+ stq r31, (sp)
+ $call auto_zlink, args=<msf$mpc_off(r12)/L, sp>, set_arg_info=false
+ beq r0, L30
+ mov r0, r16 ; rhdaddr of newly-ZLINK'ed routine
+ ldq r17, (sp) ; new labaddr
+ lda sp, 8(sp)
+ beq r17, L40
+ br L10 ; auto_zlink returns pointer to a routine header, not a procedure descriptor
+
+L30: $call lib$signal, args=<L_ERR_GTMCHECK/L>
+ $begin_epilogue
+ getframe
+ imb
+ mov fp, sp
+ ldq fp, $RSA_OFFSET+16(sp)
+ lda sp, $SIZE(sp)
+ ret r26
+ $end_epilogue
+
+L40: $call lib$signal, args=<L_ERR_LABELUNKNOWN/L>
+ $begin_epilogue
+ getframe
+ imb
+ mov fp, sp
+ ldq fp, $RSA_OFFSET+16(sp)
+ lda sp, $SIZE(sp)
+ ret r26
+ $end_epilogue
+
+ $end_routine name=op_extjmp
+
+ .end
diff --git a/sr_avms/op_fetchintrrpt.m64 b/sr_avms/op_fetchintrrpt.m64
new file mode 100644
index 0000000..43b7d43
--- /dev/null
+++ b/sr_avms/op_fetchintrrpt.m64
@@ -0,0 +1,53 @@
+ .title OP_FETCHINTRRPT
+
+ G_MSF
+
+ $linkage_section
+
+a_neterr_pending:
+ .address neterr_pending
+
+a_iott_write_error:
+ .address iott_write_error
+
+ $code_section
+
+ $routine OP_FETCHINTRRPT, entry=OP_FETCHINTRRPT_CA, kind=null
+stack_offset = 16
+ lda sp, -stack_offset(sp)
+ stq r13, (sp)
+ stq r2, 8(sp)
+ mov r27, r13
+ .base r13, $ls
+
+ stl r26, msf$mpc_off(r12)
+
+ fetch_args r2, stack_offset
+
+ ldq r0, a_neterr_pending
+ ldq_u r24, (r0)
+ extbl r24, r0, r24
+ beq r24, 10$
+
+ $call outofband_clear, set_arg_info=false, nonstandard=true
+ $call gvcmz_neterr, args=<0/a>, set_arg_info=false, nonstandard=true
+
+10$: ldq r0, a_iott_write_error
+ ldl r24, (r0)
+ beq r24, 15$
+
+ $call outofband_clear, set_arg_info=false, nonstandard=true
+ $call iott_wrterr, set_arg_info=false, nonstandard=true
+
+15$: $call async_action, args=<1/a>, set_arg_info=false, nonstandard=true
+
+20$: ldl r28, msf$mpc_off(r12)
+
+ ldq r13, (sp)
+ ldq r2, 8(sp)
+ lda sp, stack_offset(sp)
+ ret r28
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/op_fnget.m64 b/sr_avms/op_fnget.m64
new file mode 100644
index 0000000..5061533
--- /dev/null
+++ b/sr_avms/op_fnget.m64
@@ -0,0 +1,52 @@
+;#################################################################
+;# #
+;# Copyright 2006, 2009 Fidelity Information Services, Inc #
+;# #
+;# This source code contains the intellectual property #
+;# of its copyright holder(s), and is made available #
+;# under a license. If you do not know the terms of #
+;# the license, please stop and do not read further. #
+;# #
+;#################################################################
+ .title op_fnget "$Get() function"
+
+; OP_FNGET implements the $Get() function.
+; Upon entry, r1 -> source mval, r0 -> target mval.
+; If the source mval is defined, it is copied to the target,
+; otherwise, the target mval is set to be a null string.
+
+ mval$def
+
+ $routine OP_FNGET, entry=OP_FNGET_CA, kind=null
+
+ beq r1, undefined ; a nonexistent source is undefined
+ mv_if_notdefined (r1), undefined
+
+; Copy the source mval to the target:
+ mov mval$m_aliascont, r24
+ ldl r22, mval$w_mvtype(r1) ; includes mval$b_exp and the unreferenced fnpcid
+ ldl r23, mval$l_strlen(r1)
+ bic r22, r24, r22 ; don't allow propagation of alias container flag
+ ldl r24, mval$a_straddr(r1)
+ stl r22, mval$w_mvtype(r0)
+ stl r23, mval$l_strlen(r0)
+ stl r24, mval$a_straddr(r0)
+ ldl r22, mval$l_m0(r1)
+ ldl r23, mval$l_m1(r1)
+ stl r22, mval$l_m0(r0)
+ stl r23, mval$l_m1(r0)
+
+ ret r26
+
+undefined:
+; Set the target mval to a null string:
+ mov mval$m_str, r22
+ clr r23
+ stl r22, mval$w_mvtype(r0) ; also clears mval$b_exp
+ stl r23, mval$l_strlen(r0)
+
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/op_fnzextract.m64 b/sr_avms/op_fnzextract.m64
new file mode 100644
index 0000000..a4b9924
--- /dev/null
+++ b/sr_avms/op_fnzextract.m64
@@ -0,0 +1,71 @@
+;#################################################################
+;# #
+;# Copyright 2006, 2008 Fidelity Information Services, Inc #
+;# #
+;# This source code contains the intellectual property #
+;# of its copyright holder(s), and is made available #
+;# under a license. If you do not know the terms of #
+;# the license, please stop and do not read further. #
+;# #
+;#################################################################
+ .title OP_FNZEXTRACT
+
+ mval$def
+
+ $routine OP_FNZEXTRACT, entry=OP_FNZEXTRACT_CA, kind=null
+ lda sp, -48(sp)
+ stq r26, (sp)
+ stq r2, 8(sp)
+ stq r3, 16(sp)
+ stq r4, 24(sp)
+ stq r5, 32(sp)
+ stq r13, 40(sp)
+ mov r27, r13
+ .base r13, $ls
+
+ mov r16, r5 ; r5 = second index
+ mov r17, r4 ; r4 = first index
+ mov r18, r2 ; r2 -> source mval
+ mov r19, r3 ; r3 -> result mval
+
+ mv_force_defined r2
+ mv_force_str (r2)
+
+ cmovle r4, 1, r4 ; r4 = start = max(1, first index)
+ ldl r1, mval$l_strlen(r2) ; r1 = length of source string
+ subq r4, r1, r24 ; if start > source length,
+ bgt r24, 20$ ; then result is a null string
+
+ subq r5, r1, r24
+ cmovgt r24, r1, r5 ; r5 = end = min(source length, second index)
+ subq r5, r4, r0
+ addq r0, 1, r0 ; r0 = result length = end - start + 1
+ beq r0, 10$
+ blt r0, 20$
+
+ ldl r28, mval$a_straddr(r2) ; r28 = address of source string
+ addq r4, r28, r4
+ subq r4, 1, r4 ; r4 = result address = source address + start - 1
+ stl r4, mval$a_straddr(r3)
+
+10$: mov mval$m_str, r28
+ stl r0, mval$l_strlen(r3) ; set result length
+ stl r28, mval$w_mvtype(r3) ; set result type (always a string)
+
+ ldq r28, (sp)
+ ldq r2, 8(sp)
+ ldq r3, 16(sp)
+ ldq r4, 24(sp)
+ ldq r5, 32(sp)
+ ldq r13, 40(sp)
+ lda sp, 48(sp)
+
+ ret r28
+
+; Result is a null string:
+20$: clr r0
+ br 10$
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/op_follow.m64 b/sr_avms/op_follow.m64
new file mode 100644
index 0000000..39ed628
--- /dev/null
+++ b/sr_avms/op_follow.m64
@@ -0,0 +1,69 @@
+;#################################################################
+;# #
+;# Copyright 2006, 2008 Fidelity Information Services, Inc #
+;# #
+;# This source code contains the intellectual property #
+;# of its copyright holder(s), and is made available #
+;# under a license. If you do not know the terms of #
+;# the license, please stop and do not read further. #
+;# #
+;#################################################################
+ .title op_follow
+
+; op_follow implements the MUMPS string relational operator "]" ("follows"):
+;
+; lhs ] rhs
+;
+; lhs ("left-hand-side") and rhs ("right-hand-side") are expressions interpreted
+; as strings. If lhs follows rhs in the ASCII collaring sequence, the resulting
+; relation is true, otherwise, false (actually, this function differs slightly --
+; see description of exit conditions below).
+;
+; According to the ANSI standard, ANSI/MDC X11.1-1990, the relation is true iff
+; any of the following is true:
+;
+; a. rhs is empty and lhs is not.
+; b. neither lhs nor rhs is empty and the leftmost character of lhs
+; follows (has numeric code greater than) the leftmost character of rhs.
+; c. There exists a positive integer n such that lhs and rhs have
+; identical heads of length n (i.e., $E(lhs,1,n)=$E(rhs,1,n)) and the
+; remainder of lhs follows the remainder of rhs.
+;
+; Entry:
+; r0 -> lhs mval
+; r1 -> rhs mval
+;
+; Exit:
+; r0 = >0, if lhs follows rhs
+; 0, if lhs equals rhs
+; <0, if rhs follows lhs (allows reversal of operands and subsequent test)
+
+
+ MVAL$DEF
+
+
+ $routine name=op_follow, entry=op_follow_ca, kind=stack, saved_regs=<r2, r3, r13, fp>
+
+ mov r27, r13
+ .base r13, $ls
+
+; Make sure both lhs and rhs are strings.
+ mov r0, r2 ; r2 <- address of lhs mval
+ mov r1, r3 ; r3 <- address of rhs mval
+ mv_force_defined r2
+ mv_force_str (r2)
+ mv_force_defined r3
+ mv_force_str (r3)
+
+; Obtain string lengths.
+ ldl r17, mval$l_strlen(r2)
+ ldl r19, mval$l_strlen(r3)
+
+ $call memvcmp, args=<mval$a_straddr(r2)/L, r17, mval$a_straddr(r3)/L, r19>, set_arg_info=false
+
+ mov r0, r24 ; set condition code (emulator) according to function result
+ $return
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/op_forcenum.m64 b/sr_avms/op_forcenum.m64
new file mode 100644
index 0000000..92d82c6
--- /dev/null
+++ b/sr_avms/op_forcenum.m64
@@ -0,0 +1,96 @@
+;#################################################################
+;# #
+;# Copyright 2006, 2008 Fidelity Information Services, Inc #
+;# #
+;# This source code contains the intellectual property #
+;# of its copyright holder(s), and is made available #
+;# under a license. If you do not know the terms of #
+;# the license, please stop and do not read further. #
+;# #
+;#################################################################
+ .title OP_FORCENUM
+
+ mval$def
+
+
+ $routine OP_FORCENUM, entry=OP_FORCENUM_CA, kind=null
+ lda sp, -32(sp)
+ stq r26, (sp)
+ stq r13, 8(sp)
+ mov r27, r13
+ .base r13, $ls
+
+
+ stq r0, 16(sp)
+ mv_force_defined r1
+ stq r1, 24(sp)
+ mv_force_num (r1)
+ ldq r0, 16(sp)
+ ldq r1, 24(sp)
+
+ mv_if_notstring (r1), 10$
+
+ ldl r28, (r1)
+ and r28, mval$m_num_approx, r28
+ beq r28, 30$
+
+10$: mv_if_notint (r1), 20$
+
+; Set mvtype to int:
+ ldl r28, mval$w_mvtype(r0)
+ mskwl r28, mval$w_mvtype, r28
+ or r28, mval$m_int, r28
+ stl r28, mval$w_mvtype(r0)
+
+; Copy r1->m1 to r0->m1
+ ldl r24, mval$l_m1(r1)
+ stl r24, mval$l_m1(r0)
+
+; Return:
+ ldq r26, (sp)
+ ldq r13, 8(sp)
+ lda sp, 32(sp)
+ ret r26
+
+
+; Copy r1->exp to r0->exp, and set r0->mvtype = nm:
+20$: ldl r28, mval$w_mvtype(r1) ; r28 = longword containing r1->exp
+ zapnot r28, ^X1 at mval$b_exp, r28 ; clear all but the exp field
+ or r28, mval$m_nm, r28 ; set the mvtype field to nm
+ stl r28, mval$w_mvtype(r0)
+
+; Copy r1->(m0,m1) to r0->(m0,m1)
+ ldl r24, mval$l_m0(r1)
+ ldl r28, mval$l_m1(r1)
+ stl r24, mval$l_m0(r0)
+ stl r28, mval$l_m1(r0)
+
+; Return:
+ ldq r26, (sp)
+ ldq r13, 8(sp)
+ lda sp, 32(sp)
+ ret r26
+
+
+; Copy r1->mval to r0->mval
+; (mval's are longword-aligned, and are 5 longwords long [mval$size = 20]):
+30$: ldl r16, (r1)
+ ldl r17, 4(r1)
+ ldl r18, 8(r1)
+ ldl r19, 12(r1)
+ ldl r20, 16(r1)
+ stl r16, (r0)
+ stl r17, 4(r0)
+ stl r18, 8(r0)
+ stl r19, 12(r0)
+ stl r20, 16(r0)
+
+; Return:
+ ldq r26, (sp)
+ ldq r13, 8(sp)
+ lda sp, 32(sp)
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/op_forchk1.m64 b/sr_avms/op_forchk1.m64
new file mode 100644
index 0000000..dd42852
--- /dev/null
+++ b/sr_avms/op_forchk1.m64
@@ -0,0 +1,24 @@
+; ################################################################
+; # #
+; # Copyright 2008 Fidelity Information Services, Inc #
+; # #
+; # This source code contains the intellectual property #
+; # of its copyright holder(s), and is made available #
+; # under a license. If you do not know the terms of #
+; # the license, please stop and do not read further. #
+; # #
+; ################################################################
+
+ .title op_forchk1
+
+; op_forchk1 - dummy routine called at start of FOR-statement
+;
+; During normal execution, this routine would be called at the beginning of a For-statement.
+; However, when it is desired to set a break at that location, the entry in the xfer table
+; pointing to op_forchk1 would be altered to point to the desired alternative routine.
+
+ $routine name=op_forchk1,entry=op_forchk1_ca,kind=null
+
+ ret r26
+
+ $end_routine name=op_forchk1
diff --git a/sr_avms/op_forinit.m64 b/sr_avms/op_forinit.m64
new file mode 100644
index 0000000..6c1dd6a
--- /dev/null
+++ b/sr_avms/op_forinit.m64
@@ -0,0 +1,74 @@
+;#################################################################
+;# #
+;# Copyright 2006, 2008 Fidelity Information Services, Inc #
+;# #
+;# This source code contains the intellectual property #
+;# of its copyright holder(s), and is made available #
+;# under a license. If you do not know the terms of #
+;# the license, please stop and do not read further. #
+;# #
+;#################################################################
+ .title OP_FORINIT
+
+ G_MSF
+ mval$def
+
+ $routine OP_FORINIT, entry=OP_FORINIT_CA, kind=null
+stack_offset = 32
+ lda sp, -stack_offset(sp)
+ stq r13, (sp)
+ stq r2, 8(sp)
+ stq r3, 16(sp)
+ stq r4, 24(sp)
+ mov r27, r13
+ .base r13, $ls
+
+ stl r26, msf$mpc_off(r12)
+
+ mov r16, r2
+ mov r17, r3
+ mov r18, r4
+
+ mv_force_defined r2
+ mv_force_num (r2)
+ mv_force_defined r3
+ mv_force_num (r3)
+ mv_force_defined r4
+ mv_force_num (r4)
+
+ ldl r28, mval$l_m1(r3)
+ blt r28, 40$
+
+ mv_if_int (r3), 30$
+
+; The following sequence emulates the Vax instruction:
+; tstb mval$b_exp(r3)
+
+ ldq_u r28, mval$b_exp(r3)
+ lda r0, mval$b_exp+1(r3)
+ extqh r28, r0, r28
+
+ blt r28, 40$
+
+30$: mov r2, r0
+ mov r4, r1
+ br 50$
+
+40$: mov r4, r0
+ mov r2, r1
+
+50$: $call OP_NUMCMP, set_arg_info=false, nonstandard=true
+
+ ldl r28, msf$mpc_off(r12)
+
+ ldq r13, (sp)
+ ldq r2, 8(sp)
+ ldq r3, 16(sp)
+ ldq r4, 24(sp)
+ lda sp, stack_offset(sp)
+
+ ret r28
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/op_forintrrpt.m64 b/sr_avms/op_forintrrpt.m64
new file mode 100644
index 0000000..1508d12
--- /dev/null
+++ b/sr_avms/op_forintrrpt.m64
@@ -0,0 +1,49 @@
+ .title OP_FORINTRRPT
+
+ G_MSF
+
+call_inst_size = 12
+
+ $linkage_section
+
+a_neterr_pending:
+ .address neterr_pending
+
+a_iott_write_error:
+ .address iott_write_error
+
+ $code_section
+
+ $routine OP_FORINTRRPT, entry=OP_FORINTRRPT_CA, kind=null
+stack_offset = 16
+ lda sp, -stack_offset(sp)
+ stq r26, (sp)
+ stq r13, 8(sp)
+ mov r27, r13
+ .base r13, $ls
+
+ ldq r0, a_neterr_pending
+ ldq_u r24, (r0)
+ extbl r24, r0, r24
+ beq r24, 10$
+
+ $call outofband_clear, set_arg_info=false, nonstandard=true
+ $call gvcmz_neterr, args=<0/a>, set_arg_info=false, nonstandard=true
+
+10$: ldq r0, a_iott_write_error
+ ldl r24, (r0)
+ beq r24, 15$
+
+ $call outofband_clear, set_arg_info=false, nonstandard=true
+ $call iott_wrterr, set_arg_info=false, nonstandard=true
+
+15$: $call async_action, args=<0/a>, set_arg_info=false, nonstandard=true
+
+20$: ldq r26, (sp)
+ ldq r13, 8(sp)
+ lda sp, stack_offset(sp)
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/op_forlcldo.m64 b/sr_avms/op_forlcldo.m64
new file mode 100644
index 0000000..fce281b
--- /dev/null
+++ b/sr_avms/op_forlcldo.m64
@@ -0,0 +1,51 @@
+ .title OP_FORLCLDO
+; ###############################################################
+; # #
+; # Copyright 2001, 2003 Sanchez Computer Associates, Inc. #
+; # #
+; # This source code contains the intellectual property #
+; # of its copyright holder(s), and is made available #
+; # under a license. If you do not know the terms of #
+; # the license, please stop and do not read further. #
+; # #
+; ###############################################################
+
+ G_MSF
+
+
+ $linkage_section
+
+a_frame_pointer:
+ .address frame_pointer
+
+
+ $code_section
+
+ $routine OP_FORLCLDOB, entry=OP_FORLCLDO_CA, aliases=<OP_FORLCLDOW,OP_FORLCLDOL>, kind=null
+ lda sp, -16(sp)
+ stq r3, 8(sp)
+ stq r26, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ ldq r1, a_frame_pointer
+ ldl r1, (r1)
+
+; Bump the return PC past the branch instruction following the jsr that got us here:
+ addl r26, r16, r26 ; length of branch sequence
+ stl r26, msf$mpc_off(r1) ; and store it in the Mumps stack frame
+
+ $call EXFUN_FRAME, set_arg_info=false, nonstandard=true
+
+ ldq r12, a_frame_pointer
+ ldl r12, (r12)
+ ldl r9, msf$temps_ptr_off(r12)
+
+ ldq r28, (sp)
+ ldq r3, 8(sp)
+ lda sp, 16(sp)
+ ret r28
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/op_forloop.m64 b/sr_avms/op_forloop.m64
new file mode 100644
index 0000000..dab7d5e
--- /dev/null
+++ b/sr_avms/op_forloop.m64
@@ -0,0 +1,260 @@
+;#################################################################
+;# #
+;# Copyright 2006, 2012 Fidelity Information Services, Inc #
+;# #
+;# This source code contains the intellectual property #
+;# of its copyright holder(s), and is made available #
+;# under a license. If you do not know the terms of #
+;# the license, please stop and do not read further. #
+;# #
+;#################################################################
+ .title OP_FORLOOP "FOR loop iteration logic"
+
+; On entry:
+;
+; r16 -> index variable
+; r17 -> step mval (guaranteed to be temp or lit and therefore defined as numeric)
+; r18 -> terminator mval
+; r19 -> return address to continue looping
+;
+; The usual return address in R26 is for loop termination.
+
+
+ G_MSF
+ mval$def
+
+
+ $linkage_section
+
+; These are read-only constants; it's convenient to stash them in the linkage section:
+
+mant_lo_val:
+ .quad MANT_LO
+
+mant_hi_val:
+ .quad MANT_HI
+
+
+ $code_section
+
+ $routine OP_FORLOOP, entry=OP_FORLOOP_CA, kind=null
+ lda sp, -40(sp)
+ stq r2, (sp)
+ stq r3, 8(sp)
+ stq r4, 16(sp)
+ stq r13, 24(sp)
+ mov r27, r13
+ .base r13, $ls
+
+; Save the first three arguments in non-volatile registers:
+ mov r16, r2 ; r2 -> index variable mval
+ mov r17, r3 ; r3 -> step mval
+ mov r18, r4 ; r4 -> terminator mval
+
+; Save the loop termination return address in the Mumps stack frame:
+ stl r26, msf$mpc_off(r12)
+
+; Save the loop continuation return address on the stack:
+ stq r19, 32(sp)
+
+ mv_force_defined_strict r2 ; disregard NOUNDEF
+ mv_force_num (r2) ; make sure the index variable is numeric
+
+ mv_if_notint (r2), add_non_int ; branch if index is not int
+ mv_if_notint (r3), add_non_int ; branch if step is not int
+
+
+; Index and step are both int; that makes it easy to compute the new index value:
+ ldl r22, mval$l_m1(r2) ; r22 = index value
+ ldl r23, mval$l_m1(r3) ; r23 = step value
+ addq r22, r23, r22 ; r22 = new index value [= old index + step]
+
+ mv_if_notint (r4), add ; branch if terminator is not int
+
+
+; At this point, index, step, and terminator are all int; that makes it easy to
+; do the appropriate comparison between the new index value and the terminator:
+ ldl r24, mval$l_m1(r4) ; r24 = terminator value
+ cmple r31, r23, r26 ; r26 = (step >= 0)
+ cmple r22, r24, r27 ; r27 = (index <= terminator)
+ and r26, r27, r28 ; r28 = (step >= 0 and index <= terminator)
+ xor r26, 1, r26 ; r26 = (step < 0)
+ cmple r24, r22, r27 ; r27 = (index >= terminator)
+ and r26, r27, r26 ; r26 = (step < 0 and index >= terminator)
+ or r28, r26, r26 ; r26 = ((step >= 0 and index <= terminator) or (step < 0 and index >= terminator))
+ beq r26, terminate_loop ; branch if false; loop has terminated
+
+ stl r22, mval$l_m1(r2) ; store new index value [= old index + step]
+
+; Since index's value has changed, set its mvtype to int only
+; (i.e. clear all bits except mval$m_int):
+ ldl r26, mval$w_mvtype(r2)
+ mskwl r26, mval$w_mvtype, r26
+ or r26, mval$m_int, r26
+ stl r26, mval$w_mvtype(r2)
+
+ br continue_loop
+
+
+; One or both of index and step are not int; add step to index:
+add_non_int:
+ $call ADD_MVALS, args=<r2, r3, 0/a, r2>, set_arg_info=false, nonstandard=true
+
+ br compare
+
+; At this point, index and step are int, but terminator is not;
+; check the new index value (it's in r22):
+
+add:
+ $call CHECK_INDEX, set_arg_info=false, nonstandard=true, local=true
+
+
+; Do the appropriate comparison between the updated index value and the terminator:
+
+compare:
+ mov r2, r0 ; r0 -> index
+ mov r4, r1 ; r1 -> terminator
+
+ mv_if_notint (r3), 15$ ; branch if step is not int
+
+ ldl r28, mval$l_m1(r3)
+ blt r28, 20$ ; branch if step's value is negative
+
+; Branch if either index or terminator is not int:
+5$: mv_if_notint (r0), compare_non_int
+ mv_if_notint (r1), compare_non_int
+
+; Index and terminator are both int; that makes the comparison easy:
+10$: ldl r0, mval$l_m1(r0)
+ ldl r1, mval$l_m1(r1)
+ cmple r0, r1, r0
+ blbs r0, continue_loop
+ br undo ; loop has terminated
+
+; Step is not int; check the sign of its exp field:
+15$: ldq_u r28, mval$b_exp(r3)
+ lda r27, mval$b_exp+1(r3)
+ extqh r28, r27, r28
+ bge r28, 5$ ; branch if step's exp is positive
+
+; Either step's value or its exp field is negative; swap r0 with r1:
+20$: mov r4, r0 ; r0 -> terminator
+ mov r2, r1 ; r1 -> index
+ mv_if_notint (r0), compare_non_int
+ mv_if_int (r1), 10$
+
+
+; Neither index nor terminator is int; use OP_NUMCMP to do the comparison:
+compare_non_int:
+ $call OP_NUMCMP, set_arg_info=false, nonstandard=true ; args are r0 and r1
+ ble r0, continue_loop
+
+; The FOR loop has terminated; before returning we must subtract step from index:
+
+undo:
+ mv_if_notint (r2), sub_non_int ; branch if index is not int
+ mv_if_notint (r3), sub_non_int ; branch if step is not int
+
+ ldl r22, mval$l_m1(r2) ; r22 = new index value
+ ldl r23, mval$l_m1(r3) ; r23 = step value
+ subq r22, r23, r22 ; r22 = old index value [= new index - step]
+
+; Check the new (old) index value:
+ $call CHECK_INDEX, set_arg_info=false, nonstandard=true, local=true
+
+ br terminate_loop
+
+
+; One or both of index and step are not int; subtract step from index:
+sub_non_int:
+ $call ADD_MVALS, args=<r2, r3, 1/a, r2>, set_arg_info=false, nonstandard=true
+
+
+
+; The FOR loop has terminated; return via the address saved in the Mumps stack frame:
+terminate_loop:
+ ldl r26, msf$mpc_off(r12)
+ br epilogue
+
+
+; The FOR loop has not yet terminated; return via the address saved on the stack:
+continue_loop:
+ ldq r26, 32(sp)
+
+
+epilogue:
+ ldq r2, (sp)
+ ldq r3, 8(sp)
+ ldq r4, 16(sp)
+ ldq r13, 24(sp)
+ lda sp, 40(sp)
+
+ ret r26
+
+ $end_routine
+
+; This is a local routine to check and update the value of the index variable.
+;
+; On entry, R22 contains the value to check, and r2 -> the mval for the index variable.
+
+
+ $routine CHECK_INDEX, entry=CHECK_INDEX_CA, local=true, kind=null
+ .base r27, $ls
+
+ ldq r25, mant_hi_val
+ cmplt r22, r25, r28
+ beq r28, 20$ ; branch if index >= MANT_HI
+
+ negq r25, r25
+ cmple r22, r25, r28
+ bne r28, 10$ ; branch if index <= -MANT_HI
+
+; Abs(index value) < MANT_HI; simply store it:
+ stl r22, mval$l_m1(r2)
+
+; Since the value has changed, set mvtype to int (i.e. clear all bits except mval$m_int):
+ ldl r24, mval$w_mvtype(r2)
+ mskwl r24, mval$w_mvtype, r24
+ or r24, mval$m_int, r24
+ stl r24, mval$w_mvtype(r2)
+
+ ret r26
+
+
+; index <= -MANT_HI:
+10$: negq r22, r22 ; make the value positive
+ mov ^x80, r28 ; set the sign bit for exp
+
+; index >= MANT_HI:
+20$: or r28, ^x45, r28 ; exp will be ^x45 (decimal 69)
+
+; Set mvtype (to mval$m_nm) and exp:
+ mov mval$m_nm, r24 ; set mvtype field
+ insbl r28, mval$b_exp, r28 ; move the exp value into position in r28
+ or r24, r28, r24 ; set the new field values into r24
+ stl r24, mval$w_mvtype(r2) ; and store them
+
+; Divide the index value (r22) by 10:
+ ldah r24, -13107
+ negq r22, r25
+ lda r24, -13107(r24)
+ cmovge r22, r22, r25
+ sll r24, 32, r24
+ umulh r25, r24, r25
+ srl r25, 3, r25
+ negq r25, r28
+ cmovge r22, r25, r28 ; r28 = index / 10
+
+ mulq r28, 10, r24 ; r24 = (index / 10) * 10
+ ldq r25, mant_lo_val
+ subq r22, r24, r22 ; r22 = index - ((index / 10) * 10)
+ mulq r22, r25, r22 ; r22 = (index - ((index / 10) * 10)) * MANT_LO
+
+ stl r22, mval$l_m0(r2) ; (index - ((index / 10) * 10)) * MANT_LO
+ stl r28, mval$l_m1(r2) ; index / 10
+
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/op_gettruth.m64 b/sr_avms/op_gettruth.m64
new file mode 100644
index 0000000..5ca6170
--- /dev/null
+++ b/sr_avms/op_gettruth.m64
@@ -0,0 +1,42 @@
+ .title OP_GETTRUTH
+
+ mval$def
+
+
+ $linkage_section
+
+a_literal_zero:
+ .address literal_zero
+
+a_literal_one:
+ .address literal_one
+
+
+ $code_section
+
+ $routine OP_GETTRUTH, entry=OP_GETTRUTH_CA, kind=null
+ .base r27, $ls
+
+ ldl r20, 0(r10) ; $TEST value
+ ldq r24, a_literal_one
+ ldq r28, a_literal_zero
+ cmovne r20, r24, r28
+
+; mval's are longword-aligned, and are 5 longwords long [mval$size = 20]:
+ ldl r16, (r28)
+ ldl r17, 4(r28)
+ ldl r18, 8(r28)
+ ldl r19, 12(r28)
+ ldl r20, 16(r28)
+
+ stl r16, (r1)
+ stl r17, 4(r1)
+ stl r18, 8(r1)
+ stl r19, 12(r1)
+ stl r20, 16(r1)
+
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/op_iretmvad.m64 b/sr_avms/op_iretmvad.m64
new file mode 100644
index 0000000..57df112
--- /dev/null
+++ b/sr_avms/op_iretmvad.m64
@@ -0,0 +1,29 @@
+ .title OP_IRETMVAD
+
+ g_msf
+
+
+ $linkage_section
+a_frame_pointer:
+ .address frame_pointer
+
+
+ $routine OP_IRETMVAD, entry=OP_IRETMVAD_CA, kind=null
+ lda sp, -16(sp)
+ stq r3, (sp)
+ stq r1, 8(sp) ; save r1, restore into r0 later
+ mov r27, r3
+ .base r3, $ls
+
+ putframe
+ $call OP_UNWIND, set_arg_info=false, nonstandard=true
+ getframe
+
+ ldq r0, 8(sp) ; set r0 from saved r1
+ ldq r3, (sp)
+ lda sp, 16(sp)
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/op_linefetch.m64 b/sr_avms/op_linefetch.m64
new file mode 100644
index 0000000..fe053ee
--- /dev/null
+++ b/sr_avms/op_linefetch.m64
@@ -0,0 +1,31 @@
+ .title op_linefetch
+
+ G_MSF
+
+; entry:
+; r16 argument count
+; r17 . . . arguments to pass to fetch
+
+ $routine name=op_linefetch, entry=op_linefetch_ca, kind=stack, saved_regs=<r2, r13, fp>
+
+ stl r26, msf$mpc_off(r12)
+ stl r13, msf$ctxt_off(r12)
+
+ mov r27, r13
+ .base r13, $ls
+
+ fetch_args r2, $SIZE
+
+ $begin_epilogue
+ mov fp, sp
+ ldl r26, msf$mpc_off(r12) ; use the return address from the MUMPS stack frame
+ ldq r2, $RSA_OFFSET+8(sp)
+ ldq r13, $RSA_OFFSET+16(sp)
+ ldq fp, $RSA_OFFSET+24(sp)
+ lda sp, $SIZE(sp)
+ ret r26
+ $end_epilogue
+
+ $end_routine name=op_linefetch
+
+ .end
diff --git a/sr_avms/op_mprofcall.m64 b/sr_avms/op_mprofcall.m64
new file mode 100644
index 0000000..9555d21
--- /dev/null
+++ b/sr_avms/op_mprofcall.m64
@@ -0,0 +1,51 @@
+ .title OP_MPROFCALL
+; ###############################################################
+; # #
+; # Copyright 2001, 2003 Sanchez Computer Associates, Inc. #
+; # #
+; # This source code contains the intellectual property #
+; # of its copyright holder(s), and is made available #
+; # under a license. If you do not know the terms of #
+; # the license, please stop and do not read further. #
+; # #
+; ###############################################################
+
+ G_MSF
+
+
+ $linkage_section
+
+a_frame_pointer:
+ .address frame_pointer
+
+
+ $code_section
+
+ $routine OP_MPROFCALLB, entry=OP_MPROFCALL_CA, aliases=<OP_MPROFCALLW, OP_MPROFCALLL>, kind=null
+
+ lda sp, -16(sp)
+ stq r3, 8(sp)
+ stq r26, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ ldq r1, a_frame_pointer
+ ldl r1, (r1)
+
+; Bump the return PC past the branch instruction following the jsr that got us here:
+ addl r26, r16, r26 ; length of branch sequence
+ stl r26, msf$mpc_off(r1) ; and store it in the Mumps stack frame
+
+ $call COPY_STACK_FRAME_SP, set_arg_info=false, nonstandard=true
+
+ ldq r12, a_frame_pointer
+ ldl r12, (r12)
+
+ ldq r28, (sp)
+ ldq r3, 8(sp)
+ lda sp, 16(sp)
+ ret r28
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/op_mprofcallsp.m64 b/sr_avms/op_mprofcallsp.m64
new file mode 100644
index 0000000..bf12e0f
--- /dev/null
+++ b/sr_avms/op_mprofcallsp.m64
@@ -0,0 +1,54 @@
+ .title OP_MPROFCALLSP
+; ###############################################################
+; # #
+; # Copyright 2001, 2007 Fidelity Information Services, Inc #
+; # #
+; # This source code contains the intellectual property #
+; # of its copyright holder(s), and is made available #
+; # under a license. If you do not know the terms of #
+; # the license, please stop and do not read further. #
+; # #
+; ###############################################################
+
+ G_MSF
+
+
+ $linkage_section
+
+a_frame_pointer:
+ .address frame_pointer
+
+
+ $code_section
+
+ $routine OP_MPROFCALLSPB, entry=OP_MPROFCALLSP_CA, aliases=<OP_MPROFCALLSPW, OP_MPROFCALLSPL>, kind=null
+
+ lda sp, -16(sp)
+ stq r3, 8(sp)
+ stq r26, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ ldq r1, a_frame_pointer
+ ldl r1, (r1)
+
+; Bump the return PC past the branch instruction following the jsr that got us here:
+ addl r26, r16, r26 ; length of branch sequence
+ stl r26, msf$mpc_off(r1) ; and store it in the Mumps stack frame
+
+ $call EXFUN_FRAME_PUSH_DUMMY_FRAME, set_arg_info=false, nonstandard=true
+ ldl r16, 0(r10) ; Fetch $TEST value
+ $call PUSH_TVAL, args=<r16>, set_arg_info=false, nonstandard=true
+
+ ldq r12, a_frame_pointer
+ ldl r12, (r12)
+ ldl r9, msf$temps_ptr_off(r12)
+
+ ldq r28, (sp)
+ ldq r3, 8(sp)
+ lda sp, 16(sp)
+ ret r28
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/op_mprofexfun.m64 b/sr_avms/op_mprofexfun.m64
new file mode 100644
index 0000000..08ee1dc
--- /dev/null
+++ b/sr_avms/op_mprofexfun.m64
@@ -0,0 +1,85 @@
+ .title op_mprofexfun - invoke (internal) extrinsic function mprofiling flavor
+; ###############################################################
+; # #
+; # Copyright 2001, 2012 Fidelity Information Services, Inc #
+; # #
+; # This source code contains the intellectual property #
+; # of its copyright holder(s), and is made available #
+; # under a license. If you do not know the terms of #
+; # the license, please stop and do not read further. #
+; # #
+; ###############################################################
+
+ G_MSF
+
+; op_mprofexfun - invoke (internal) extrinsic function m-profiling flavor
+;
+; arguments:
+; ret_value address for function to place return value
+; offset to this frame's continue (return) point past branch to subroutine
+; mask
+; actualcnt actual argument count
+; actual1 address of actual first argument
+; actual2 address of actual second argument
+; . . .
+
+ $routine name=op_mprofexfun, entry=op_mprofexfun_ca, kind=stack, saved_regs=<r2, r13, r16, r17, r18, r19, r20, r21, fp>, - ; BYPASSOK
+ data_section_pointer=true, -
+ data_section=<$DATA$, QUAD, NOPIC, CON, REL, LCL, NOSHR, MIX, NOEXE, RD, WRT>
+
+ $linkage_section
+
+A_frame_pointer: .address frame_pointer
+
+ $code_section
+
+ mov r27, r13
+ .base r13, $ls
+
+ ldq r1, A_frame_pointer
+ ldl r1, (r1)
+ addl r26, r17, r28 ; add size of jump sequence to get return addr for frame.
+ stl r28, msf$mpc_off(r1)
+ $call exfun_frame_sp, set_arg_info=false
+ ldl r16, 0(r10) ; $TRUTH aka $TEST value
+ bic r16, #^Xfe, r16 ; clear all but low order bit
+ ldq r17, $RSA_OFFSET+24(fp) ; old r16 (ret_value)
+ ldq r18, $RSA_OFFSET+40(fp) ; old r18 (mask)
+ ldq r19, $RSA_OFFSET+48(fp) ; old r19 (actualcnt)
+ ldq r20, $RSA_OFFSET+56(fp) ; old r20 (actual1)
+ ldq r21, $RSA_OFFSET+64(fp) ; old r21 (actual2)
+ lda r25, 4(r19)
+
+; If more than 2 actual arguments, push rest onto stack.
+ subq r19, 2, r28 ; number of arguments originally passed on stack (actual3 . . . actualn)
+ ble r28, zero_in_stack ; all original arguments in registers
+ lda r0, $SIZE(fp)
+ subq r28, 1, r28 ; offset = number - 1
+ s8addq r28, r0, r0 ; address of actualn
+loop: ldq r1, (r0)
+ lda sp, -8(sp)
+ lda r0, -8(r0)
+ stq r1, (sp)
+ subq r28, 1, r28
+ bge r28, loop
+zero_in_stack:
+ $call push_parm, set_arg_info=false ; push_parm ($T, ret_value, mask, actualcnt [, actual1[, actual2 . . .]])
+
+done: ldq r28, A_frame_pointer
+ ldl r2, (r28) ; saved value of frame_pointer
+ mov r2, r12
+ ldl r9, msf$temps_ptr_off(r12)
+
+ $begin_epilogue
+ mov fp, sp
+ ldq r26, $RSA_OFFSET(sp)
+ ldq r2, $RSA_OFFSET+8(sp)
+ ldq r13, $RSA_OFFSET+16(sp)
+ ldq fp, $RSA_OFFSET+72(sp)
+ lda sp, $SIZE(sp)
+ ret r26
+ $end_epilogue
+
+ $end_routine name=op_mprofexfun
+
+ .end
diff --git a/sr_avms/op_mprofextcall.m64 b/sr_avms/op_mprofextcall.m64
new file mode 100644
index 0000000..99eddf0
--- /dev/null
+++ b/sr_avms/op_mprofextcall.m64
@@ -0,0 +1,111 @@
+ .title op_mprofextcall - call external (MUMPS) routine
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ;
+; Copyright 2005, 2012 Fidelity Information Services, Inc ;
+; ;
+; This source code contains the intellectual property ;
+; of its copyright holder(s), and is made available ;
+; under a license. If you do not know the terms of ;
+; the license, please stop and do not read further. ;
+; ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ G_MSF
+ PROCDESC
+
+; op_mprofextcall calls and external GT.M MUMPS routine. If the routine has not yet
+; been linked into the current image, op_mprofextcall will first link it by invoking
+; the auto-ZLINK function.
+;
+; Args:
+; procdsc - address of procedure descriptor of routine to call
+; labaddr - address of offset into routine to which to transfer control
+
+ $routine name=op_mprofextcall, entry=op_mprofextcall_ca, kind=stack, saved_regs=<fp>, -
+ data_section_pointer=true
+
+ $linkage_section
+
+A_frame_pointer: .address frame_pointer
+
+L_ERR_GTMCHECK: .long ERR_GTMCHECK
+L_ERR_LABELUNKNOWN: .long ERR_LABELUNKNOWN
+
+ $data_section
+
+PDSC_FLAGS:
+ .long GTM_PD_FLAGS
+
+
+ $code_section
+
+ .base r27, $ls
+ ldq r22, $dp
+ .base r22, $ds
+
+ putframe r12
+
+ mov r27, r13
+ .base r13, $ls
+
+ beq r16, L20 ; if procdsc == 0, this routine has not yet been linked into current image
+ beq r17, L40 ; if labaddr == 0 (and procdsc != 0), there is some interal error
+
+; Check whether first argument is procedure descriptor or routine header.
+ ldl r28, PDSC_FLAGS
+ ldl r0, (r16)
+ xor r28, r0, r28
+ bne r28, L10 ; if not procedure descriptor, it must be a routine header
+
+ ldq r16, 8(r16) ; rhdaddr = procdsc->entry_point ; entry point address is address of routine header
+L10: ldl r17, (r17) ; *lab_ln_ptr
+ beq r17, L40
+ ldl r28, mrt$curr_ptr(r16)
+ addl r17, r28, r17
+ addl r17, r16, r17 ; rhdaddr + *lab_ln_ptr
+ ldl r17, (r17) ; *labaddr
+ ldl r28, mrt$curr_ptr(r16) ; rhdaddr->current_rhead_ptr
+ addl r16, r28, r18 ; rhdaddr + rhdaddr->current_rhead_ptr
+ addl r17, r18, r18 ; rhdaddr + rhdaddr->current_rhead_ptr + *labaddr
+ $call new_stack_frame_sp, args=<r16, mrt$lnk_ptr(r16)/L, r18>, set_arg_info=false
+
+ $begin_epilogue
+ getframe
+ mov fp, sp
+ ldq fp, $RSA_OFFSET+8(sp)
+ lda sp, $SIZE(sp)
+ ret r26
+ $end_epilogue
+
+L20: bne r17, L40 ; if labaddr != 0 (and procdsc == 0), there is some internal error
+ lda sp, -8(sp) ; auto_zlink will put value here
+ stq r31, (sp)
+ $call auto_zlink, args=<msf$mpc_off(r12)/L, sp>, set_arg_info=false
+ beq r0, L30
+ mov r0, r16 ; rhdaddr of newly-ZLINK'ed routine
+ ldq r17, (sp) ; new labaddr
+ lda sp, 8(sp)
+ beq r17, L30
+ br L10 ; auto_zlink returns pointer to a routine header, not a procedure descriptor
+
+L30: $call lib$signal, args=<L_ERR_GTMCHECK/L>
+ $begin_epilogue
+ getframe
+ mov fp, sp
+ ldq fp, $RSA_OFFSET+8(sp)
+ lda sp, $SIZE(sp)
+ ret r26
+ $end_epilogue
+
+L40: $call lib$signal, args=<L_ERR_LABELUNKNOWN/L>
+ $begin_epilogue
+ getframe
+ mov fp, sp
+ ldq fp, $RSA_OFFSET+8(sp)
+ lda sp, $SIZE(sp)
+ ret r26
+ $end_epilogue
+
+ $end_routine name=op_mprofextcall
+
+ .end
diff --git a/sr_avms/op_mprofextexfun.m64 b/sr_avms/op_mprofextexfun.m64
new file mode 100644
index 0000000..00171b1
--- /dev/null
+++ b/sr_avms/op_mprofextexfun.m64
@@ -0,0 +1,161 @@
+ .title op_mprofextexfun - invoke external extrinsic function
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ;
+; Copyright 2005, 2012 Fidelity Information Services, Inc ;
+; ;
+; This source code contains the intellectual property ;
+; of its copyright holder(s), and is made available ;
+; under a license. If you do not know the terms of ;
+; the license, please stop and do not read further. ;
+; ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+ G_MSF
+ PROCDESC
+
+; op_mprofextexfun - invoke external extrinsic function
+;
+; arguments:
+; routine address of procedure descriptor of procedure containing extrinsic function
+; label address of offset into routine to which to transfer control
+; ret_value address for function to place return value
+; mask
+; actualcnt actual argument count
+; actual1 address of actual first argument
+; actual2 address of actual second argument
+; . . .
+
+ $routine name=op_mprofextexfun, entry=op_mprofextexfun_ca, kind=stack, saved_regs=<r2, r13, r18, r19, r20, r21, fp>, - ; BYPASSOK
+ data_section_pointer=true, -
+ data_section=<$DATA$, QUAD, NOPIC, CON, REL, LCL, NOSHR, MIX, NOEXE, RD, WRT>
+
+ $linkage_section
+
+A_frame_pointer: .address frame_pointer
+
+L_ERR_FMLLSTMISSING: .long ERR_FMLLSTMISSING
+L_ERR_GTMCHECK: .long ERR_GTMCHECK
+L_ERR_LABELUNKNOWN: .long ERR_LABELUNKNOWN
+
+
+ $data_section
+
+PDSC_FLAGS:
+ .long GTM_PD_FLAGS
+
+
+ $code_section
+
+ .base r27, $ls
+ ldq r2, $dp
+ .base r2, $ds
+
+ putframe
+
+ mov r27, r13
+ .base r13, $ls
+
+L9: beq r16, L20 ; if procdsc == 0, this routine has not yet been linked into current image
+ beq r17, L40 ; if labaddr == 0 (and procdsc != 0), it's an unknown label
+
+; Check whether first argument is procedure descriptor or routine header.
+ ldl r28, PDSC_FLAGS
+ ldl r0, (r16)
+ xor r28, r0, r28
+ bne r28, L10 ; if not procedure descriptor, it must be a routine header
+
+ ldq r16, 8(r16) ; rhdaddr = procdsc->entry_point ; entry point address is address of routine header
+L10: mov r17, r22 ; temporarily save labaddr, so it is not overriden
+ ldl r17, (r17) ; *lab_ln_ptr
+ beq r17, L40
+ ldl r28, mrt$curr_ptr(r16)
+ addl r17, r28, r17
+ addl r17, r16, r17 ; rhdaddr + *lab_ln_ptr
+ ldl r17, (r17) ; *labaddr
+ ldl r28, mrt$curr_ptr(r16) ; rhdaddr->current_rhead_ptr
+ addl r16, r28, r18
+ addl r17, r18, r18
+ mov r22, r17 ; restore the original labaddr
+
+ addq r17, 4, r17 ; labaddr += 4, to point to has_parms
+ ldl r17, (r17) ; *has_parms
+ beq r17, L50 ; if has_parms == 0, then issue an error
+
+L12: $call new_stack_frame_sp, args=<r16, mrt$lnk_ptr(r16)/L, r18>, set_arg_info=false
+ ldl r16, 0(r10) ; push $TRUTH aka $TEST
+ bic r16, #^Xfe, r16 ; clear all but low order bit
+L15: ldq r17, $RSA_OFFSET+24(fp) ; old r18 (ret_value)
+ ldq r18, $RSA_OFFSET+32(fp) ; old r19 (mask)
+ ldq r19, $RSA_OFFSET+40(fp) ; old r20 (actualcnt)
+ ldq r20, $RSA_OFFSET+48(fp) ; old r21 (actual1)
+ ldq r21, $SIZE(fp) ; actual2, if any
+ lda r25, 4(r19)
+
+; If more than 1 argument, push rest onto stack.
+ subq r19, 2, r28 ; number of arguments to put onto stack (actual3 . . . actualn)
+ ble r28, zero_in_stack ; all original arguments in registers
+ lda r0, $SIZE(fp)
+ s8addq r28, r0, r0 ; address of actualn
+loop: ldq r1, (r0)
+ lda sp, -8(sp)
+ lda r0, -8(r0)
+ stq r1, (sp)
+ subq r28, 1, r28
+ bgt r28, loop
+zero_in_stack:
+ $call push_parm, set_arg_info=false ; push_parm ($T, ret_value, mask, argc[, actual1[, actual2 . . .]])
+
+L16: getframe
+
+ $begin_epilogue
+ mov fp, sp
+ ldq r2, $RSA_OFFSET+8(sp)
+ ldq fp, $RSA_OFFSET+56(sp)
+ lda sp, $SIZE(sp)
+ ret r26
+ $end_epilogue
+
+L20: bne r17, L30 ; procdsc == 0, but label != 0 => internal error
+ lda sp, -8(sp) ; auto_zlink will put value here
+ stq r31, (sp)
+ $call auto_zlink, args=<msf$mpc_off(r12)/L, sp>, set_arg_info=false
+ beq r0, L30
+ mov r0, r16 ; rhdaddr of newly-ZLINK'ed routine
+ ldq r17, (sp) ; new labaddr
+ lda sp, 8(sp)
+ beq r17, L40 ; found routine, but labaddr still 0 => unknown label
+ br L10
+
+L30: $call lib$signal, args=<L_ERR_GTMCHECK/L>
+ $begin_epilogue
+ getframe
+ mov fp, sp
+ ldq r2, $RSA_OFFSET+8(sp)
+ ldq fp, $RSA_OFFSET+56(sp)
+ lda sp, $SIZE(sp)
+ ret r26
+ $end_epilogue
+
+L40: $call lib$signal, args=<L_ERR_LABELUNKNOWN/L>
+ $begin_epilogue
+ getframe
+ mov fp, sp
+ ldq r2, $RSA_OFFSET+8(sp)
+ ldq fp, $RSA_OFFSET+56(sp)
+ lda sp, $SIZE(sp)
+ ret r26
+ $end_epilogue
+
+L50: $call lib$signal, args=<L_ERR_FMLLSTMISSING/L>
+ $begin_epilogue
+ getframe
+ mov fp, sp
+ ldq r2, $RSA_OFFSET+8(sp)
+ ldq fp, $RSA_OFFSET+56(sp)
+ lda sp, $SIZE(sp)
+ ret r26
+ $end_epilogue
+
+ $end_routine name=op_mprofextexfun
+
+ .end
diff --git a/sr_avms/op_mprofforchk1.m64 b/sr_avms/op_mprofforchk1.m64
new file mode 100644
index 0000000..608afd1
--- /dev/null
+++ b/sr_avms/op_mprofforchk1.m64
@@ -0,0 +1,31 @@
+;#################################################################
+;# #
+;# Copyright 2011 Fidelity Information Services, Inc #
+;# #
+;# This source code contains the intellectual property #
+;# of its copyright holder(s), and is made available #
+;# under a license. If you do not know the terms of #
+;# the license, please stop and do not read further. #
+;# #
+;#################################################################
+ .title op_mprofforloop "FOR loop iteration logic"
+
+ $routine OP_MPROFFORCHK1, entry=OP_MPROFFORCHK1_CA, kind=null
+
+ subq sp, 16, sp
+ stq r26, 0(sp)
+ stq r13, 8(sp)
+ mov r27, r13
+ .base r13, $ls
+
+ mov r26, r16 ; send the return address to forchkhandler
+ $call forchkhandler, args=<r16>, set_arg_info=false, nonstandard=true
+
+ ldq r26, (sp)
+ ldq r13, 8(sp)
+ addq sp, 16, sp
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/op_mprofforlcldo.m64 b/sr_avms/op_mprofforlcldo.m64
new file mode 100644
index 0000000..40ca997
--- /dev/null
+++ b/sr_avms/op_mprofforlcldo.m64
@@ -0,0 +1,51 @@
+ .title OP_MPROFFORLCLDO
+; ###############################################################
+; # #
+; # Copyright 2001, 2012 Fidelity Information Services, Inc #
+; # #
+; # This source code contains the intellectual property #
+; # of its copyright holder(s), and is made available #
+; # under a license. If you do not know the terms of #
+; # the license, please stop and do not read further. #
+; # #
+; ###############################################################
+
+ G_MSF
+
+
+ $linkage_section
+
+a_frame_pointer:
+ .address frame_pointer
+
+
+ $code_section
+
+ $routine OP_MPROFFORLCLDOB, entry=OP_MPROFFORLCLDO_CA, aliases=<OP_MPROFFORLCLDOW,OP_MPROFFORLCLDOL>, kind=null
+ lda sp, -16(sp)
+ stq r3, 8(sp)
+ stq r26, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ ldq r1, a_frame_pointer
+ ldl r1, (r1)
+
+; Bump the return PC past the branch instruction following the jsr that got us here:
+ addl r26, r16, r26 ; length of branch sequence
+ stl r26, msf$mpc_off(r1) ; and store it in the Mumps stack frame
+
+ $call EXFUN_FRAME_SP, set_arg_info=false, nonstandard=true
+
+ ldq r12, a_frame_pointer
+ ldl r12, (r12)
+ ldl r9, msf$temps_ptr_off(r12)
+
+ ldq r28, (sp)
+ ldq r3, 8(sp)
+ lda sp, 16(sp)
+ ret r28
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/op_mproflinefetch.m64 b/sr_avms/op_mproflinefetch.m64
new file mode 100644
index 0000000..9add6f5
--- /dev/null
+++ b/sr_avms/op_mproflinefetch.m64
@@ -0,0 +1,34 @@
+ .title op_mproflinefetch
+ G_MSF
+
+; entry:
+; r16 argument count
+; r17 . . . arguments to pass to fetch
+
+ $routine name=op_mproflinefetch, entry=op_mproflinefetch_ca, kind=stack, saved_regs=<r2, r13, fp>
+
+ stl r26, msf$mpc_off(r12)
+ stl r13, msf$ctxt_off(r12)
+
+ mov r27, r13
+ .base r13, $ls
+
+ fetch_args r2, $SIZE
+
+ $call PCURRPOS, args=<>, set_arg_info=false, nonstandard=true
+
+ $call STACK_LEAK_CHECK, args=<>, set_arg_info=false, nonstandard=true
+
+ $begin_epilogue
+ mov fp, sp
+ ldl r26, msf$mpc_off(r12) ; use the return address from the MUMPS stack frame
+ ldq r2, $RSA_OFFSET+8(sp)
+ ldq r13, $RSA_OFFSET+16(sp)
+ ldq fp, $RSA_OFFSET+24(sp)
+ lda sp, $SIZE(sp)
+ ret r26
+ $end_epilogue
+
+ $end_routine name=op_mproflinefetch
+
+ .end
diff --git a/sr_avms/op_mproflinestart.m64 b/sr_avms/op_mproflinestart.m64
new file mode 100644
index 0000000..303abfe
--- /dev/null
+++ b/sr_avms/op_mproflinestart.m64
@@ -0,0 +1,24 @@
+ .title op_mproflinestart
+ G_MSF
+
+; op_mproflinestart - establish start of line in GT.M MUMPS stack frame
+
+ $routine name=op_mproflinestart, entry=op_mproflinestart_ca, kind=stack, saved_regs=<r2, r13, fp>
+
+ stl r26, msf$mpc_off(r12)
+ stl r13, msf$ctxt_off(r12)
+
+ mov r27, r13
+ .base r13, $ls
+
+ $call PCURRPOS, args=<>, set_arg_info=false, nonstandard=true
+
+ $begin_epilogue
+ mov fp, sp
+ ldl r26, msf$mpc_off(r12) ; use the return address from the MUMPS stack frame
+ ldq r2, $RSA_OFFSET+8(sp)
+ ldq r13, $RSA_OFFSET+16(sp)
+ ldq fp, $RSA_OFFSET+24(sp)
+ lda sp, $SIZE(sp)
+ ret r26
+ $end_routine name=op_mproflinestart
diff --git a/sr_avms/op_neg.m64 b/sr_avms/op_neg.m64
new file mode 100644
index 0000000..8445122
--- /dev/null
+++ b/sr_avms/op_neg.m64
@@ -0,0 +1,98 @@
+;#################################################################
+;# #
+;# Copyright 2006, 2008 Fidelity Information Services, Inc #
+;# #
+;# This source code contains the intellectual property #
+;# of its copyright holder(s), and is made available #
+;# under a license. If you do not know the terms of #
+;# the license, please stop and do not read further. #
+;# #
+;#################################################################
+ .title OP_NEG
+
+ mval$def
+
+
+ $routine OP_NEG, entry=OP_NEG_CA, kind=null
+ lda sp, -32(sp)
+ stq r26, (sp)
+ stq r2, 8(sp)
+ stq r3, 16(sp)
+ stq r13, 24(sp)
+ mov r27, r13
+ .base r13, $ls
+
+ mov r0, r2 ; r2 -> output mval
+ mov r1, r3 ; r3 -> input mval
+
+ mv_force_defined r3
+ mv_force_num (r3)
+
+; Move the mvtype from the input mval to the output mval,
+; except for the str bit:
+ ldq_u r23, mval$w_mvtype(r3)
+ ldq_u r22, mval$w_mvtype(r2)
+ extwl r23, r3, r23
+ mskwl r22, r2, r22
+ and r23, #mval$m_int, r23 ; clear everything except mval$v_nm and mval$v_int
+ inswl r23, r2, r23
+ or r22, r23, r22
+ stq_u r22, mval$w_mvtype(r2)
+
+; Is the input zero?
+ ldl r24, mval$l_m1(r3)
+ beq r24, 10$
+
+; No; is it int?
+ mv_if_notint (r3), 15$
+
+; Yes; output m1 = - input m1
+ ldl r24, mval$l_m1(r3)
+ negl r24, r24
+ stl r24, mval$l_m1(r2)
+
+; Return:
+5$: ldq r28, (sp)
+ ldq r2, 8(sp)
+ ldq r3, 16(sp)
+ ldq r13, 24(sp)
+ lda sp, 32(sp)
+
+ ret r28
+
+
+; Input mval is zero; clear output exp, sign, m0, and m1:
+10$: ldq_u r22, mval$b_exp(r2)
+ lda r23, mval$b_exp(r2)
+ mskbl r22, r23, r22
+ stq_u r22, mval$b_exp(r2)
+ stl r31, mval$l_m0(r2)
+ stl r31, mval$l_m1(r2)
+
+ br 5$
+
+
+; Input is not int; move input m0 and m1 to output
+15$: ldl r22, mval$l_m0(r3)
+ ldl r23, mval$l_m1(r3)
+ stl r22, mval$l_m0(r2)
+ stl r23, mval$l_m1(r2)
+
+; Move exp from input to output, but flip the sign:
+ ldq_u r22, mval$b_exp(r2)
+ ldq_u r23, mval$b_exp(r3)
+ lda r24, mval$b_exp(r2)
+ lda r25, mval$b_exp(r3)
+ mskbl r22, r24, r22
+ extbl r23, r25, r23 ; low order byte of r23 = input exp and sign
+ xor r23, ^x80, r23 ; flip the sign bit
+ insbl r23, r24, r23
+ or r22, r23, r22
+ stq_u r22, mval$b_exp(r2)
+
+ br 5$
+
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/op_numcmp.m64 b/sr_avms/op_numcmp.m64
new file mode 100644
index 0000000..682686a
--- /dev/null
+++ b/sr_avms/op_numcmp.m64
@@ -0,0 +1,22 @@
+ .title OP_NUMCMP "Compare mval's, set condition code"
+
+; On entry, r0 and r1 point to mval's.
+; On exit, r24 contains the appropriate condition.
+
+ $routine OP_NUMCMP, entry=OP_NUMCMP_CA, kind=null
+ lda sp, -8(sp)
+ stq r26, (sp)
+ .base r27, $ls
+
+ mov r0, r16
+ mov r1, r17
+ $call NUMCMP, args=<r16, r17>, set_arg_info=false, nonstandard=true
+ mov r0, r24
+
+ ldq r26, (sp)
+ lda sp, 8(sp)
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/op_restartpc.m64 b/sr_avms/op_restartpc.m64
new file mode 100644
index 0000000..0d471ed
--- /dev/null
+++ b/sr_avms/op_restartpc.m64
@@ -0,0 +1,31 @@
+ .title OP_RESTARTPC "Save PC"
+
+ G_MSF
+
+call_inst_size = 12
+
+ $linkage_section
+
+A_restart_ctxt:
+ .address restart_ctxt
+A_restart_pc:
+ .address restart_pc
+
+
+ $code_section
+
+ $routine OP_RESTARTPC, entry=OP_RESTARTPC_CA, kind=null
+ .base r27, $ls
+
+ ldq r25, A_restart_pc
+ subq r26, call_inst_size, r28
+ stl r28, (r25)
+ ldq r25, A_restart_ctxt
+ ldl r28, msf$ctxt_off(r12)
+ stl r28, (r25)
+
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/op_retarg.m64 b/sr_avms/op_retarg.m64
new file mode 100644
index 0000000..89e7d71
--- /dev/null
+++ b/sr_avms/op_retarg.m64
@@ -0,0 +1,41 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ;
+; Copyright 2009, 2010 Fidelity Information Services, Inc ;
+; ;
+; This source code contains the intellectual property ;
+; of its copyright holder(s), and is made available ;
+; under a license. If you do not know the terms of ;
+; the license, please stop and do not read further. ;
+; ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ .title OP_RETARG
+
+ G_MSF
+
+ $linkage_section
+
+a_frame_pointer:
+ .address frame_pointer
+
+
+ $code_section
+
+ $routine OP_RETARG, entry=OP_RETARG_CA, kind=null
+ lda sp, -8(sp)
+ stq r3, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ mov r0, r16
+ mov r1, r17
+ $call UNW_RETARG, args=<r16,r17>, set_arg_info=false, nonstandard=true
+
+ getframe
+
+ ldq r3, (sp)
+ addq sp, 8, sp
+ jmp r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/op_startintrrpt.m64 b/sr_avms/op_startintrrpt.m64
new file mode 100644
index 0000000..7f4258f
--- /dev/null
+++ b/sr_avms/op_startintrrpt.m64
@@ -0,0 +1,52 @@
+ .title OP_STARTINTRRPT
+
+ G_MSF
+
+ $linkage_section
+
+a_neterr_pending:
+ .address neterr_pending
+
+a_iott_write_error:
+ .address iott_write_error
+
+a_frame_pointer:
+ .address frame_pointer
+
+
+ $code_section
+
+ $routine OP_STARTINTRRPT, entry=OP_STARTINTRRPT_CA, kind=null
+ lda sp, -8(sp)
+ stq r2, (sp)
+ mov r27, r2
+ .base r2, $ls
+
+ putframe
+
+ ldq r0, a_neterr_pending
+ ldq_u r24, (r0)
+ extbl r24, r0, r24
+ beq r24, 10$
+
+ $call outofband_clear, set_arg_info=false, nonstandard=true
+ $call gvcmz_neterr, args=<0/a>, set_arg_info=false, nonstandard=true
+
+10$: ldq r0, a_iott_write_error
+ ldl r24, (r0)
+ beq r24, 15$
+
+ $call outofband_clear, set_arg_info=false, nonstandard=true
+ $call iott_wrterr, set_arg_info=false, nonstandard=true
+
+15$: $call async_action, args=<1/a>, set_arg_info=false, nonstandard=true
+
+20$: getframe
+
+ ldq r2, (sp)
+ lda sp, 8(sp)
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/op_sto.m64 b/sr_avms/op_sto.m64
new file mode 100644
index 0000000..7491e82
--- /dev/null
+++ b/sr_avms/op_sto.m64
@@ -0,0 +1,67 @@
+;#################################################################
+;# #
+;# Copyright 2006, 2012 Fidelity Information Services, Inc #
+;# #
+;# This source code contains the intellectual property #
+;# of its copyright holder(s), and is made available #
+;# under a license. If you do not know the terms of #
+;# the license, please stop and do not read further. #
+;# #
+;#################################################################
+ .title OP_STO
+
+ mval$def
+
+
+ $linkage_section
+
+a_literal_null:
+ .address literal_null
+
+a_undef_inhibit:
+ .address undef_inhibit
+
+l_underr:
+ .linkage_pair underr
+
+
+ $code_section
+
+ $routine OP_STO, entry=OP_STO_CA, kind=null
+ .base r27, $ls
+
+ mv_if_notdefined (r1), 10$
+
+; Copy the mval pointed to by r1 to the mval pointed to by r0
+; (mval's are longword-aligned, and are 5 longwords long [mval$size = 20]):
+5$: mov mval$m_aliascont, r24
+ ldl r16, (r1)
+ ldl r17, 4(r1)
+ bic r16, r24, r16 ; don't allow propagation of alias container flag
+ ldl r18, 8(r1)
+ ldl r19, 12(r1)
+ ldl r20, 16(r1)
+ stl r16, (r0)
+ stl r17, 4(r0)
+ stl r18, 8(r0)
+ stl r19, 12(r0)
+ stl r20, 16(r0)
+ ret r26
+
+10$: ldq r28, a_undef_inhibit
+ ldq_u r24, (r28)
+ extbl r24, r28, r24
+ beq r24, 20$
+ ldq r1, a_literal_null
+ br 5$
+
+; "Call" UNDERR; it will return to our caller, since we haven't changed r26:
+20$: mov r1, r16
+ mov ^x1, r25 ; UNDEF here is never subscripted - use arg cnt 1
+ ldq r28, l_underr
+ ldq r27, l_underr+8
+ jmp r28
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/opp_break.m64 b/sr_avms/opp_break.m64
new file mode 100644
index 0000000..14486ae
--- /dev/null
+++ b/sr_avms/opp_break.m64
@@ -0,0 +1,27 @@
+ .title OPP_BREAK
+
+ g_msf
+
+
+ $linkage_section
+a_frame_pointer:
+ .address frame_pointer
+
+
+ $routine OPP_BREAK, entry=OPP_BREAK_CA, kind=null
+ lda sp, -8(sp)
+ stq r3, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ putframe
+ $call OP_BREAK, set_arg_info=false, nonstandard=true
+ getframe
+
+ ldq r3, (sp)
+ lda sp, 8(sp)
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/opp_commarg.m64 b/sr_avms/opp_commarg.m64
new file mode 100644
index 0000000..0990486
--- /dev/null
+++ b/sr_avms/opp_commarg.m64
@@ -0,0 +1,27 @@
+ .title OPP_COMMARG
+
+ G_MSF
+
+
+ $linkage_section
+a_frame_pointer:
+ .address frame_pointer
+
+
+ $routine OPP_COMMARG, entry=OPP_COMMARG_CA, kind=null
+ lda sp, -8(sp)
+ stq r3, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ putframe
+ $call OP_COMMARG, args=<r16, r17>, set_arg_info=false, nonstandard=true
+ getframe
+
+ ldq r3, (sp)
+ lda sp, 8(sp)
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/opp_dmode.m64 b/sr_avms/opp_dmode.m64
new file mode 100644
index 0000000..97c1775
--- /dev/null
+++ b/sr_avms/opp_dmode.m64
@@ -0,0 +1,27 @@
+ .title OPP_DMODE
+
+ g_msf
+
+
+ $linkage_section
+a_frame_pointer:
+ .address frame_pointer
+
+
+ $routine OPP_DMODE, entry=OPP_DMODE_CA, kind=null
+ lda sp, -8(sp)
+ stq r3, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ putframe
+ $call OP_DMODE, nonstandard=true
+ getframe
+
+ ldq r3, (sp)
+ lda sp, 8(sp)
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/opp_hardret.m64 b/sr_avms/opp_hardret.m64
new file mode 100644
index 0000000..fb2825f
--- /dev/null
+++ b/sr_avms/opp_hardret.m64
@@ -0,0 +1,26 @@
+ .title OPP_HARDRET
+
+ g_msf
+
+
+ $linkage_section
+a_frame_pointer:
+ .address frame_pointer
+
+ $routine OPP_HARDRET, entry=OPP_HARDRET_CA, kind=null
+ lda sp, -8(sp)
+ stq r3, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ putframe
+ $call OP_HARDRET, set_arg_info=false, nonstandard=true
+ getframe
+
+ ldq r3, (sp)
+ lda sp, 8(sp)
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/opp_inddevparms.m64 b/sr_avms/opp_inddevparms.m64
new file mode 100644
index 0000000..b698707
--- /dev/null
+++ b/sr_avms/opp_inddevparms.m64
@@ -0,0 +1,27 @@
+ .title OPP_INDDEVPARMS
+
+ G_MSF
+
+
+ $linkage_section
+a_frame_pointer:
+ .address frame_pointer
+
+
+ $routine OPP_INDDEVPARMS, entry=OPP_INDDEVPARMS_CA, kind=null
+ lda sp, -8(sp)
+ stq r3, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ putframe
+ $call OP_INDDEVPARMS, args=<r16, r17, r18>, set_arg_info=false, nonstandard=true
+ getframe
+
+ ldq r3, (sp)
+ lda sp, 8(sp)
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/opp_indfnname.m64 b/sr_avms/opp_indfnname.m64
new file mode 100644
index 0000000..396fe3c
--- /dev/null
+++ b/sr_avms/opp_indfnname.m64
@@ -0,0 +1,27 @@
+ .title OPP_INDFNNAME
+
+ G_MSF
+
+
+ $linkage_section
+a_frame_pointer:
+ .address frame_pointer
+
+
+ $routine OPP_INDFNNAME, entry=OPP_INDFNNAME_CA, kind=null
+ lda sp, -8(sp)
+ stq r3, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ putframe
+ $call OP_INDFNNAME, args=<r16, r17, r18>, set_arg_info=false, nonstandard=true
+ getframe
+
+ ldq r3, (sp)
+ lda sp, 8(sp)
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/opp_indfun.m64 b/sr_avms/opp_indfun.m64
new file mode 100644
index 0000000..0d496ac
--- /dev/null
+++ b/sr_avms/opp_indfun.m64
@@ -0,0 +1,27 @@
+ .title OPP_INDFUN
+
+ G_MSF
+
+
+ $linkage_section
+a_frame_pointer:
+ .address frame_pointer
+
+
+ $routine OPP_INDFUN, entry=OPP_INDFUN_CA, kind=null
+ lda sp, -8(sp)
+ stq r3, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ putframe
+ $call OP_INDFUN, args=<r16, r17, r18>, set_arg_info=false, nonstandard=true
+ getframe
+
+ ldq r3, (sp)
+ lda sp, 8(sp)
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/opp_indglvn.m64 b/sr_avms/opp_indglvn.m64
new file mode 100644
index 0000000..f499a6c
--- /dev/null
+++ b/sr_avms/opp_indglvn.m64
@@ -0,0 +1,27 @@
+ .title OPP_INDGLVN
+
+ G_MSF
+
+
+ $linkage_section
+a_frame_pointer:
+ .address frame_pointer
+
+
+ $routine OPP_INDGLVN, entry=OPP_INDGLVN_CA, kind=null
+ lda sp, -8(sp)
+ stq r3, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ putframe
+ $call OP_INDGLVN, args=<r16, r17>, set_arg_info=false, nonstandard=true
+ getframe
+
+ ldq r3, (sp)
+ lda sp, 8(sp)
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/opp_indincr.m64 b/sr_avms/opp_indincr.m64
new file mode 100644
index 0000000..e57c0cd
--- /dev/null
+++ b/sr_avms/opp_indincr.m64
@@ -0,0 +1,37 @@
+ .title OPP_INDINCR
+; ###############################################################
+; # #
+; # Copyright 2004 Sanchez Computer Associates, Inc. #
+; # #
+; # This source code contains the intellectual property #
+; # of its copyright holder(s), and is made available #
+; # under a license. If you do not know the terms of #
+; # the license, please stop and do not read further. #
+; # #
+; ###############################################################
+
+ G_MSF
+
+
+ $linkage_section
+a_frame_pointer:
+ .address frame_pointer
+
+
+ $routine OPP_INDINCR, entry=OPP_INDINCR_CA, kind=null
+ lda sp, -8(sp)
+ stq r3, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ putframe
+ $call OP_INDINCR, args=<r16, r17, r18>, set_arg_info=false, nonstandard=true
+ getframe
+
+ ldq r3, (sp)
+ lda sp, 8(sp)
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/opp_indlvadr.m64 b/sr_avms/opp_indlvadr.m64
new file mode 100644
index 0000000..2e7c27e
--- /dev/null
+++ b/sr_avms/opp_indlvadr.m64
@@ -0,0 +1,27 @@
+ .title OPP_INDLVADR
+
+ G_MSF
+
+
+ $linkage_section
+a_frame_pointer:
+ .address frame_pointer
+
+
+ $routine OPP_INDLVADR, entry=OPP_INDLVADR_CA, kind=null
+ lda sp, -8(sp)
+ stq r3, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ putframe
+ $call OP_INDLVADR, args=<r16>, set_arg_info=false, nonstandard=true
+ getframe
+
+ ldq r3, (sp)
+ lda sp, 8(sp)
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/opp_indlvarg.m64 b/sr_avms/opp_indlvarg.m64
new file mode 100644
index 0000000..ffa32bf
--- /dev/null
+++ b/sr_avms/opp_indlvarg.m64
@@ -0,0 +1,27 @@
+ .title OPP_INDLVARG
+
+ G_MSF
+
+
+ $linkage_section
+a_frame_pointer:
+ .address frame_pointer
+
+
+ $routine OPP_INDLVARG, entry=OPP_INDLVARG_CA, kind=null
+ lda sp, -8(sp)
+ stq r3, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ putframe
+ $call OP_INDLVARG, args=<r16, r17>, set_arg_info=false, nonstandard=true
+ getframe
+
+ ldq r3, (sp)
+ lda sp, 8(sp)
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/opp_indlvnamadr.m64 b/sr_avms/opp_indlvnamadr.m64
new file mode 100644
index 0000000..6000814
--- /dev/null
+++ b/sr_avms/opp_indlvnamadr.m64
@@ -0,0 +1,27 @@
+ .title OPP_INDLVNAMADR
+
+ G_MSF
+
+
+ $linkage_section
+a_frame_pointer:
+ .address frame_pointer
+
+
+ $routine OPP_INDLVNAMADR, entry=OPP_INDLVNAMADR_CA, kind=null
+ lda sp, -8(sp)
+ stq r3, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ putframe
+ $call OP_INDLVNAMADR, args=<r16>, set_arg_info=false, nonstandard=true
+ getframe
+
+ ldq r3, (sp)
+ lda sp, 8(sp)
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/opp_indmerge.m64 b/sr_avms/opp_indmerge.m64
new file mode 100644
index 0000000..81decde
--- /dev/null
+++ b/sr_avms/opp_indmerge.m64
@@ -0,0 +1,27 @@
+ .title OPP_INDMERGE
+
+ G_MSF
+
+
+ $linkage_section
+a_frame_pointer:
+ .address frame_pointer
+
+
+ $routine OPP_INDMERGE, entry=OPP_INDMERGE_CA, kind=null
+ lda sp, -8(sp)
+ stq r3, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ putframe
+ $call OP_INDMERGE, args=<r16, r17>, set_arg_info=false, nonstandard=true
+ getframe
+
+ ldq r3, (sp)
+ lda sp, 8(sp)
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/opp_indpat.m64 b/sr_avms/opp_indpat.m64
new file mode 100644
index 0000000..cb21da5
--- /dev/null
+++ b/sr_avms/opp_indpat.m64
@@ -0,0 +1,27 @@
+ .title OPP_INDPAT
+
+ G_MSF
+
+
+ $linkage_section
+a_frame_pointer:
+ .address frame_pointer
+
+
+ $routine OPP_INDPAT, entry=OPP_INDPAT_CA, kind=null
+ lda sp, -8(sp)
+ stq r3, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ putframe
+ $call OP_INDPAT, args=<r16, r17>, set_arg_info=false, nonstandard=true
+ getframe
+
+ ldq r3, (sp)
+ lda sp, 8(sp)
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/opp_indrzshow.m64 b/sr_avms/opp_indrzshow.m64
new file mode 100644
index 0000000..bc91896
--- /dev/null
+++ b/sr_avms/opp_indrzshow.m64
@@ -0,0 +1,27 @@
+ .title OPP_INDRZSHOW
+
+ G_MSF
+
+
+ $linkage_section
+a_frame_pointer:
+ .address frame_pointer
+
+
+ $routine OPP_INDRZSHOW, entry=OPP_INDRZSHOW_CA, kind=null
+ lda sp, -8(sp)
+ stq r3, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ putframe
+ $call OP_INDRZSHOW, args=<r16, r17>, set_arg_info=false, nonstandard=true
+ getframe
+
+ ldq r3, (sp)
+ lda sp, 8(sp)
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/opp_indsavglvn.m64 b/sr_avms/opp_indsavglvn.m64
new file mode 100644
index 0000000..bf509d9
--- /dev/null
+++ b/sr_avms/opp_indsavglvn.m64
@@ -0,0 +1,37 @@
+ .title OPP_INDSAVGLVN
+; ###############################################################
+; # #
+; # Copyright 2012 Fidelity Information Services, Inc #
+; # #
+; # This source code contains the intellectual property #
+; # of its copyright holder(s), and is made available #
+; # under a license. If you do not know the terms of #
+; # the license, please stop and do not read further. #
+; # #
+; ###############################################################
+
+ G_MSF
+
+
+ $linkage_section
+a_frame_pointer:
+ .address frame_pointer
+
+
+ $routine OPP_INDSAVGLVN, entry=OPP_INDSAVGLVN_CA, kind=null
+ lda sp, -8(sp)
+ stq r3, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ putframe
+ $call OP_INDSAVGLVN, args=<r16, r17>, set_arg_info=false, nonstandard=true
+ getframe
+
+ ldq r3, (sp)
+ lda sp, 8(sp)
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/opp_indsavlvn.m64 b/sr_avms/opp_indsavlvn.m64
new file mode 100644
index 0000000..2f63042
--- /dev/null
+++ b/sr_avms/opp_indsavlvn.m64
@@ -0,0 +1,37 @@
+ .title OPP_INDSAVLVN
+; ###############################################################
+; # #
+; # Copyright 2012 Fidelity Information Services, Inc #
+; # #
+; # This source code contains the intellectual property #
+; # of its copyright holder(s), and is made available #
+; # under a license. If you do not know the terms of #
+; # the license, please stop and do not read further. #
+; # #
+; ###############################################################
+
+ G_MSF
+
+
+ $linkage_section
+a_frame_pointer:
+ .address frame_pointer
+
+
+ $routine OPP_INDSAVLVN, entry=OPP_INDSAVLVN_CA, kind=null
+ lda sp, -8(sp)
+ stq r3, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ putframe
+ $call OP_INDSAVLVN, args=<r16, r17>, set_arg_info=false, nonstandard=true
+ getframe
+
+ ldq r3, (sp)
+ lda sp, 8(sp)
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/opp_indset.m64 b/sr_avms/opp_indset.m64
new file mode 100644
index 0000000..ef60935
--- /dev/null
+++ b/sr_avms/opp_indset.m64
@@ -0,0 +1,27 @@
+ .title OPP_INDSET
+
+ G_MSF
+
+
+ $linkage_section
+a_frame_pointer:
+ .address frame_pointer
+
+
+ $routine OPP_INDSET, entry=OPP_INDSET_CA, kind=null
+ lda sp, -8(sp)
+ stq r3, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ putframe
+ $call OP_INDSET, args=<r16, r17>, set_arg_info=false, nonstandard=true
+ getframe
+
+ ldq r3, (sp)
+ lda sp, 8(sp)
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/opp_indtext.m64 b/sr_avms/opp_indtext.m64
new file mode 100644
index 0000000..6e26701
--- /dev/null
+++ b/sr_avms/opp_indtext.m64
@@ -0,0 +1,27 @@
+ .title OPP_INDTEXT
+
+ G_MSF
+
+
+ $linkage_section
+a_frame_pointer:
+ .address frame_pointer
+
+
+ $routine OPP_INDTEXT, entry=OPP_INDTEXT_CA, kind=null
+ lda sp, -8(sp)
+ stq r3, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ putframe
+ $call OP_INDTEXT, args=<r16, r17, r18, r19>, set_arg_info=false, nonstandard=true
+ getframe
+
+ ldq r3, (sp)
+ lda sp, 8(sp)
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/opp_iretmval.m64 b/sr_avms/opp_iretmval.m64
new file mode 100644
index 0000000..70cf603
--- /dev/null
+++ b/sr_avms/opp_iretmval.m64
@@ -0,0 +1,26 @@
+ .title OPP_IRETMVAL
+
+ g_msf
+
+ $linkage_section
+a_frame_pointer:
+ .address frame_pointer
+
+
+ $routine OPP_IRETMVAL, entry=OPP_IRETMVAL_CA, kind=null
+ lda sp, -8(sp)
+ stq r3, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ putframe
+ $call OP_IRETMVAL, args=<r16, r17>, set_arg_info=false, nonstandard=true
+ getframe
+
+ ldq r3, (sp)
+ lda sp, 8(sp)
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/opp_newintrinsic.m64 b/sr_avms/opp_newintrinsic.m64
new file mode 100644
index 0000000..0a0a994
--- /dev/null
+++ b/sr_avms/opp_newintrinsic.m64
@@ -0,0 +1,27 @@
+ .title OPP_NEWINTRINSIC
+
+ G_MSF
+
+
+ $linkage_section
+a_frame_pointer:
+ .address frame_pointer
+
+
+ $routine OPP_NEWINTRINSIC, entry=OPP_NEWINTRINSIC_CA, kind=null
+ lda sp, -8(sp)
+ stq r3, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ putframe
+ $call OP_NEWINTRINSIC, args=<r16>, set_arg_info=false, nonstandard=true
+ getframe
+
+ ldq r3, (sp)
+ lda sp, 8(sp)
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/opp_newvar.m64 b/sr_avms/opp_newvar.m64
new file mode 100644
index 0000000..061674a
--- /dev/null
+++ b/sr_avms/opp_newvar.m64
@@ -0,0 +1,27 @@
+ .title OPP_NEWVAR
+
+ G_MSF
+
+
+ $linkage_section
+a_frame_pointer:
+ .address frame_pointer
+
+
+ $routine OPP_NEWVAR, entry=OPP_NEWVAR_CA, kind=null
+ lda sp, -8(sp)
+ stq r3, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ putframe
+ $call OP_NEWVAR, args=<r16>, set_arg_info=false, nonstandard=true
+ getframe
+
+ ldq r3, (sp)
+ lda sp, 8(sp)
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/opp_ret.m64 b/sr_avms/opp_ret.m64
new file mode 100644
index 0000000..8727cac
--- /dev/null
+++ b/sr_avms/opp_ret.m64
@@ -0,0 +1,112 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ;
+; Copyright 2001, 2008 Fidelity Information Services, Inc ;
+; ;
+; This source code contains the intellectual property ;
+; of its copyright holder(s), and is made available ;
+; under a license. If you do not know the terms of ;
+; the license, please stop and do not read further. ;
+; ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ .title OPP_RET
+
+ G_MSF
+
+ $linkage_section
+
+a_frame_pointer:
+ .address frame_pointer
+
+a_skip_error_ret:
+ .address skip_error_ret
+
+a_error_frame:
+ .address error_frame
+
+a_is_tracing_on:
+ .address is_tracing_on
+
+a_msp:
+ .address msp
+
+a_mv_chain:
+ .address mv_chain
+
+a_tp_pointer:
+ .address tp_pointer
+
+L_ERR_STACKUNDERFLO:
+ .long ERR_STACKUNDERFLO
+
+
+ $code_section
+
+ $routine OPP_RET, entry=OPP_RET_CA, kind=null
+ lda sp, -8(sp)
+ stq r3, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+; Since most QUITs will be simple, check to see if there's anything to unwind:
+ ldq r28, a_mv_chain
+ ldl r28, (r28)
+ cmpule r12, r28, r24
+ blbc r24, lbl20 ; branch if frame_pointer > mv_chain
+
+ ldq r28, a_tp_pointer
+ ldl r26, (r28)
+ bne r26, lbl20 ; if there's a transaction on, go do unwind
+
+ ldq r28, a_skip_error_ret
+ ldl r26, (r28)
+ bne r26, lbl20 ; if skip_error_ret is TRUE, go do unwind (at least to reset it to FALSE)
+
+ ldq r28, a_error_frame
+ ldl r26, (r28)
+ bne r26, lbl20 ; if error_frame is non-NULL, go do unwind
+
+; Check the frame pointer type if it requires special handling by op_unwind
+ ldl r28, msf$typ_off(r12) ; contains msf$flags
+ srl r28, 16, r28 ; shift flags byte to low order
+ and r28, sff_indce, r28 ; isolate indirect bit
+ bne r28, lbl20 ; go do the long version
+
+ ldq r28, a_is_tracing_on
+ ldl r26, (r28)
+ bne r26, lbl20 ; if m-profiling is on, go do unwind
+
+; The frame_pointer is <= the mv_chain, so there's nothing to do but set up
+; the new frame pointer and stack pointer:
+
+ addl r12, msf$frame_size, r26
+ ldq r28, a_msp
+ stl r26, (r28)
+
+ ldl r12, msf$old_frame_off(r12)
+ beq r12, lbl90
+
+ ldq r28, a_frame_pointer
+ stl r12, (r28)
+ getframe
+ mov r13, r27
+
+ ldq r3, (sp)
+ lda sp, 8(sp)
+ jmp r26
+
+
+lbl20: $call OP_UNWIND, set_arg_info=false, nonstandard=true
+
+ getframe
+
+ ldq r3, (sp)
+ lda sp, 8(sp)
+ ret r26
+
+
+; Note that LIB$SIGNAL does not return:
+lbl90: $call LIB$SIGNAL, args=<L_ERR_STACKUNDERFLO/L>, nonstandard=true
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/opp_rterror.m64 b/sr_avms/opp_rterror.m64
new file mode 100644
index 0000000..f34b602
--- /dev/null
+++ b/sr_avms/opp_rterror.m64
@@ -0,0 +1,27 @@
+ .title OPP_RTERROR
+
+ g_msf
+
+
+ $linkage_section
+a_frame_pointer:
+ .address frame_pointer
+
+
+ $routine OPP_RTERROR, entry=OPP_RTERROR_CA, kind=null
+ lda sp, -8(sp)
+ stq r3, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ putframe
+ $call OP_RTERROR, args=<r16, r17>, set_arg_info=false, nonstandard=true
+ getframe
+
+ ldq r3, (sp)
+ lda sp, 8(sp)
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/opp_svput.m64 b/sr_avms/opp_svput.m64
new file mode 100644
index 0000000..fbeb586
--- /dev/null
+++ b/sr_avms/opp_svput.m64
@@ -0,0 +1,27 @@
+ .title OPP_SVPUT
+
+ G_MSF
+
+
+ $linkage_section
+a_frame_pointer:
+ .address frame_pointer
+
+
+ $routine OPP_SVPUT, entry=OPP_SVPUT_CA, kind=null
+ lda sp, -8(sp)
+ stq r3, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ putframe
+ $call OP_SVPUT, args=<r16,r17>, set_arg_info=false, nonstandard=true
+ getframe
+
+ ldq r3, (sp)
+ lda sp, 8(sp)
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/opp_tcommit.m64 b/sr_avms/opp_tcommit.m64
new file mode 100644
index 0000000..a9aaa96
--- /dev/null
+++ b/sr_avms/opp_tcommit.m64
@@ -0,0 +1,27 @@
+ .title OPP_TCOMMIT "Commit a transaction - may result in restart (transfer of control)"
+
+ g_msf
+
+
+ $linkage_section
+a_frame_pointer:
+ .address frame_pointer
+
+
+ $routine OPP_TCOMMIT, entry=OPP_TCOMMIT_CA, kind=null
+ lda sp, -8(sp)
+ stq r3, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ putframe
+ $call OP_TCOMMIT, set_arg_info=false, nonstandard=true
+ getframe
+
+ ldq r3, (sp)
+ lda sp, 8(sp)
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/opp_trestart.m64 b/sr_avms/opp_trestart.m64
new file mode 100644
index 0000000..b1d6589
--- /dev/null
+++ b/sr_avms/opp_trestart.m64
@@ -0,0 +1,26 @@
+ .title OPP_TRESTART "Restart a specified transaction"
+
+ g_msf
+
+
+ $linkage_section
+a_frame_pointer:
+ .address frame_pointer
+
+ $routine OPP_TRESTART, entry=OPP_TRESTART_CA, kind=null
+ lda sp, -8(sp)
+ stq r3, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ putframe
+ $call OP_TRESTART, args=<r16>, set_arg_info=false, nonstandard=true
+ getframe
+
+ ldq r3, (sp)
+ lda sp, 8(sp)
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/opp_trollback.m64 b/sr_avms/opp_trollback.m64
new file mode 100644
index 0000000..96d0627
--- /dev/null
+++ b/sr_avms/opp_trollback.m64
@@ -0,0 +1,24 @@
+ .title OPP_TROLLBACK "Rollback a specified transaction"
+
+ g_msf
+
+ $linkage_section
+a_frame_pointer:
+ .address frame_pointer
+
+ $routine OPP_TROLLBACK, entry=OPP_TROLLBACK_CA, kind=null
+ lda sp, -8(sp)
+ stq r3, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ putframe
+ $call OP_TROLLBACK, args=<r16>, set_arg_info=false, nonstandard=true
+ getframe
+
+ ldq r3, (sp)
+ lda sp, 8(sp)
+ ret r26
+
+ $end_routine
+ .end
diff --git a/sr_avms/opp_tstart.m64 b/sr_avms/opp_tstart.m64
new file mode 100644
index 0000000..651319e
--- /dev/null
+++ b/sr_avms/opp_tstart.m64
@@ -0,0 +1,97 @@
+ .title OPP_TSTART "Initiate a transaction processing frame"
+
+ G_MSF
+
+ $linkage_section
+a_frame_pointer:
+ .address frame_pointer
+
+
+ $code_section
+
+ $routine OPP_TSTART, entry=OPP_TSTART_CA, kind=null
+stack_offset = 16
+ lda sp, -stack_offset(sp)
+ stq r2, (sp)
+ stq r3, 8(sp)
+
+; Note: we use r3 as a base for the linkage section instead of the usual r13,
+; since r13 is saved by putframe and restored by getframe:
+ mov r27, r3
+ .base r3, $ls
+
+ putframe
+
+; On entry to this routine, the value in arg3 (i.e. r18) has the following meaning:
+; = -2 : preserve all variables
+; = -1 : not restartable
+; >= 0 : = the number of variables to preserve
+;
+; IFF (arg3 >= 0), the total number of arguments to this routine is (arg3 + 3);
+; otherwise, there are just 3 arguments. (Note that r25 DOES NOT contain any
+; argument information; calls to this routine emulate the VAX JSB instruction,
+; and do not set up such information.)
+;
+; On the other hand, OP_TSTART, called below, expects $Test as its first argument,
+; followed by all of the arguments passed to this routine.
+;
+; Therefore, we have to create a new argument list with all of our arguments moved
+; UP one slot in the list in order to make room for $Test. The fact that the first
+; six arguments are passed in registers, while any arguments in excess of six are
+; passed on the stack, complicates this task. So...
+;
+; First, move any arguments passed on the stack from their current positions
+; just above our register save area to new positions just below it:
+
+ mov sp, r2 ; save the current stack pointer
+
+ subq r18, 4, r28 ; r28 = the number of arguments on the stack, less 1
+ blt r28, 10$ ; skip if there weren't any on the stack
+
+ sll r28, 3, r0
+ addq r0, stack_offset, r0 ; account for the saved registers
+ addq r0, sp, r0 ; r0 -> the last argument
+loop:
+ ldq r1, (r0)
+ lda sp, -8(sp)
+ lda r0, -8(r0)
+ subq r28, 1, r28
+ stq r1, (sp)
+ bgt r28, loop
+
+; Next, put the original arg6 onto the stack:
+
+10$: lda sp, -8(sp)
+ stq r21, (sp)
+
+; Now, shift the first five arguments up into the next higher registers:
+
+ mov r20, r21
+ mov r19, r20
+ mov r18, r19
+ mov r17, r18
+ mov r16, r17
+
+; Finally, put "tstart-is-implicit" flag into the first argument register, and call OP_TSTART:
+
+ lda r16, 0
+
+; Note that what was in r18 is now in r19:
+ clr r25
+ cmovgt r19, r19, r25 ; iff r19 > 0, number of arguments is r19, ...
+ addq r25, 4, r25 ; ... plus the original 3 arguments, plus $Test
+
+ $call OP_TSTART, set_arg_info=false, nonstandard=true
+
+ getframe
+
+ mov r2, sp ; restore the stack
+
+ ldq r2, (sp)
+ ldq r3, 8(sp)
+ lda sp, stack_offset(sp)
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/opp_xnew.m64 b/sr_avms/opp_xnew.m64
new file mode 100644
index 0000000..19f212a
--- /dev/null
+++ b/sr_avms/opp_xnew.m64
@@ -0,0 +1,66 @@
+ .title OPP_XNEW
+
+ G_MSF
+
+ $linkage_section
+A_frame_pointer:
+ .address frame_pointer
+
+ $routine OPP_XNEW, entry=OPP_XNEW_CA, kind=null
+stack_offset = 16
+ lda sp, -stack_offset(sp)
+ stq r2, (sp)
+ stq r3, 8(sp)
+
+ mov sp, r2 ; save the current stack pointer
+
+; Note: we use r3 as a base for the linkage section instead of the usual r13,
+; since r13 is saved by putframe and restored by getframe:
+ mov r27, r3
+ .base r3, $ls
+
+ putframe
+
+; The variable length argument list that was passed to us must be passed on to OP_XNEW.
+; However, since our first argument is actually the argument count, it has to be moved
+; into the Argument Information register (r25), and the remaining arguments must all be
+; moved down one slot in the list:
+
+ mov r16, r25 ; argument count
+ mov r17, r16 ; arg1
+ mov r18, r17 ; arg2
+ mov r19, r18 ; arg3
+ mov r20, r19 ; arg4
+ mov r21, r20 ; arg5
+ ldq r21, stack_offset(sp) ; arg6 was on the stack
+
+; Any additional arguments that were on the stack must be re-stacked below our register save area:
+
+ subq r25, 6, r28 ; r28 = the number of arguments left on the stack
+ ble r28, 5$ ; skip if none
+
+ sll r28, 3, r0
+ addq r0, stack_offset, r0 ; account for the saved registers
+ addq r0, sp, r0 ; r0 -> argN
+loop:
+ ldq r1, (r0)
+ lda sp, -8(sp)
+ lda r0, -8(r0)
+ subq r28, 1, r28
+ stq r1, (sp)
+ bgt r28, loop
+
+5$: $call OP_XNEW, set_arg_info=false, nonstandard=true
+
+ mov r2, sp ; restore the stack
+
+ getframe
+
+ ldq r2, (sp)
+ ldq r3, 8(sp)
+ lda sp, stack_offset(sp)
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/opp_zcont.m64 b/sr_avms/opp_zcont.m64
new file mode 100644
index 0000000..17b5c77
--- /dev/null
+++ b/sr_avms/opp_zcont.m64
@@ -0,0 +1,26 @@
+ .title OPP_ZCONT
+
+ g_msf
+
+
+ $linkage_section
+a_frame_pointer:
+ .address frame_pointer
+
+ $routine OPP_ZCONT, entry=OPP_ZCONT_CA, kind=null
+ lda sp, -8(sp)
+ stq r3, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ putframe
+ $call OP_ZCONT, set_arg_info=false, nonstandard=true
+ getframe
+
+ ldq r3, (sp)
+ lda sp, 8(sp)
+ ret r26
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/opp_zg1.m64 b/sr_avms/opp_zg1.m64
new file mode 100644
index 0000000..233132a
--- /dev/null
+++ b/sr_avms/opp_zg1.m64
@@ -0,0 +1,34 @@
+ .title OPP_ZG1 "Wrapper for ZGOTO level no entryref"
+; ###############################################################
+; # #
+; # Copyright 2011 Fidelity Information Service, Inc #
+; # #
+; # This source code contains the intellectual property #
+; # of its copyright holder(s), and is made available #
+; # under a license. If you do not know the terms of #
+; # the license, please stop and do not read further. #
+; # #
+; ###############################################################
+
+ g_msf
+
+ $linkage_section
+a_frame_pointer:
+ .address frame_pointer
+
+ $routine OPP_ZG1, entry=OPP_ZG1_CA, kind=null
+ lda sp, -8(sp)
+ stq r3, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ putframe
+ $call OP_ZG1, args=<r16>, set_arg_info=false, nonstandard=true
+ getframe
+
+ ldq r3, (sp)
+ lda sp, 8(sp)
+ ret r26
+
+ $end_routine
+ .end
diff --git a/sr_avms/opp_zgoto.m64 b/sr_avms/opp_zgoto.m64
new file mode 100644
index 0000000..a6508d3
--- /dev/null
+++ b/sr_avms/opp_zgoto.m64
@@ -0,0 +1,34 @@
+ .title OPP_ZGOTO "Wrapper for ZGOTO level with entryref"
+; ###############################################################
+; # #
+; # Copyright 2011 Fidelity Information Service, Inc #
+; # #
+; # This source code contains the intellectual property #
+; # of its copyright holder(s), and is made available #
+; # under a license. If you do not know the terms of #
+; # the license, please stop and do not read further. #
+; # #
+; ###############################################################
+
+ g_msf
+
+ $linkage_section
+a_frame_pointer:
+ .address frame_pointer
+
+ $routine OPP_ZGOTO, entry=OPP_ZGOTO_CA, kind=null
+ lda sp, -8(sp)
+ stq r3, (sp)
+ mov r27, r3
+ .base r3, $ls
+
+ putframe
+ $call OP_ZGOTO, args=<r16>, set_arg_info=false, nonstandard=true
+ getframe
+
+ ldq r3, (sp)
+ lda sp, 8(sp)
+ ret r26
+
+ $end_routine
+ .end
diff --git a/sr_avms/pdscdef.h b/sr_avms/pdscdef.h
new file mode 100644
index 0000000..df105c3
--- /dev/null
+++ b/sr_avms/pdscdef.h
@@ -0,0 +1,99 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* Alpha OpenVMS procedure descriptor values. */
+
+/* FLAGS field. */
+#define PDSC$K_KIND_BOUND 0
+#define PDSC$K_KIND_NULL 8
+#define PDSC$K_KIND_FP_STACK 9
+#define PDSC$K_KIND_FP_REGISTER 10
+#define PDSC$M_HANDLER_VALID 0x10
+#define PDSC$M_HANDLER_REINVOKABLE 0x20
+#define PDSC$M_HANDLER_DATA_VALID 0x40
+#define PDSC$M_BASE_REG_IS_FP 0x80
+#define PDSC$M_REI_RETURN 0x100
+#define PDSC$M_STACK_RETURN_VALUE 0x200
+#define PDSC$M_BASE_FRAME 0x400
+#define PDSC$M_NATIVE 0x1000
+#define PDSC$M_NO_JACKET 0x2000
+#define PDSC$M_TIE_FRAME 0x4000
+
+#define PDSC$M_FUNC_RETURN 0xF
+#define PDSC$K_NULL_SIZE 16
+#define PDSC$K_BOUND_SIZE 24
+#define PDSC$K_MIN_BOUND_SIZE 24
+#define PDSC$K_MIN_LENGTH_SF 32
+#define PDSC$K_MIN_STACK_SIZE 32
+#define PDSC$K_MAX_STACK_SIZE 48
+#define PDSC$K_MIN_LENGTH_RF 24
+#define PDSC$K_MIN_REGISTER_SIZE 24
+#define PDSC$K_MAX_REGISTER_SIZE 40
+#define PDSC$K_BOUND_ENVIRONMENT_SIZE 32
+#define PDSC$W_FLAGS 0
+#define PDSC$S_KIND 4
+
+/* FLAGS field. */
+#define PDSC$V_KIND 0
+#define PDSC$V_HANDLER_VALID 4
+#define PDSC$V_HANDLER_REINVOKABLE 5
+#define PDSC$V_HANDLER_DATA_VALID 6
+#define PDSC$V_BASE_REG_IS_FP 7
+#define PDSC$V_REI_RETURN 8
+#define PDSC$V_STACK_RETURN_VALUE 9
+#define PDSC$V_BASE_FRAME 10
+#define PDSC$V_NATIVE 12
+#define PDSC$V_NO_JACKET 13
+#define PDSC$V_TIE_FRAME 14
+
+#define PDSC$W_RSA_OFFSET 2
+#define PDSC$B_SAVE_FP 2
+#define PDSC$B_SAVE_RA 3
+#define PDSC$B_ENTRY_RA 4
+#define PDSC$S_FUNC_RETURN 4
+#define PDSC$V_FUNC_RETURN 0
+#define PDSC$W_SIGNATURE_OFFSET 6
+#define PDSC$S_ENTRY 8
+#define PDSC$Q_ENTRY 8
+#define PDSC$L_ENTRY 8
+#define PDSC$L_SIZE 16
+#define PDSC$S_PROC_VALUE 8
+#define PDSC$Q_PROC_VALUE 16
+#define PDSC$L_PROC_VALUE 16
+#define PDSC$S_KIND_SPECIFIC 24
+#define PDSC$R_KIND_SPECIFIC 24
+#define PDSC$L_IREG_MASK 24
+#define PDSC$L_FREG_MASK 28
+#define PDSC$S_STACK_HANDLER 8
+#define PDSC$Q_STACK_HANDLER 32
+#define PDSC$S_STACK_HANDLER_DATA 8
+#define PDSC$Q_STACK_HANDLER_DATA 40
+#define PDSC$S_REG_HANDLER 8
+#define PDSC$Q_REG_HANDLER 24
+#define PDSC$S_REG_HANDLER_DATA 8
+#define PDSC$Q_REG_HANDLER_DATA 32
+#define PDSC$L_ENVIRONMENT 24
+#define PDSC$S_ENVIRONMENT 8
+#define PDSC$Q_ENVIRONMENT 24
+#define PDSC$K_LKP_LENGTH 16
+#define PDSC$S_LKP_ENTRY 8
+#define PDSC$Q_LKP_ENTRY 0
+#define PDSC$PS_LKP_ENTRY 0
+#define PDSC$S_LKP_PROC_VALUE 8
+#define PDSC$Q_LKP_PROC_VALUE 8
+#define PDSC$PS_LKP_PROC_VALUE 8
+#define LKP$K_SIZE 16
+#define LKP$S_ENTRY 8
+#define LKP$Q_ENTRY 0
+#define LKP$PS_ENTRY 0
+#define LKP$S_PROC_VALUE 8
+#define LKP$Q_PROC_VALUE 8
+#define LKP$PS_PROC_VALUE 8
diff --git a/sr_avms/prober.mar b/sr_avms/prober.mar
new file mode 100644
index 0000000..c4dfd4f
--- /dev/null
+++ b/sr_avms/prober.mar
@@ -0,0 +1,18 @@
+ .title prober
+ ; returns 1 if address is accessible
+
+VAX = 1
+ code_psect
+
+ .entry prober,^m<>
+; movq 4(ap),r0
+ movl 4(ap),r0
+ movl 8(ap),r1
+ prober #0,r0,(r1)
+ beql 10$
+ movl #1,r0
+ ret
+
+10$: clrl r0
+ ret
+ .end
diff --git a/sr_avms/probew.mar b/sr_avms/probew.mar
new file mode 100644
index 0000000..62bf4c8
--- /dev/null
+++ b/sr_avms/probew.mar
@@ -0,0 +1,19 @@
+ .title probew
+ ; returns 1 if address is accessible
+
+VAX = 1
+
+ code_psect
+
+ .entry probew,^m<>
+; movq 4(ap),r0
+ movl 4(ap),r0
+ movl 8(ap),r1
+ probew #0,r0,(r1)
+ beql 10$
+ movl #1,r0
+ ret
+
+10$: clrl r0
+ ret
+ .end
diff --git a/sr_avms/proc_desc.h b/sr_avms/proc_desc.h
new file mode 100644
index 0000000..e4b5b0c
--- /dev/null
+++ b/sr_avms/proc_desc.h
@@ -0,0 +1,26 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* proc_desc - Alpha OpenVMS procedure descriptor information. */
+
+typedef struct
+{
+ short flags;
+ short rsa_offset;
+ short reserved_1;
+ short signature_offset;
+ int4 *code_address;
+ int4 must_be_zero_1; /* actually, rest of code_address, but DEC C only implements 32-bit pointers */
+ int4 size;
+} proc_desc;
+
+#define PDSC_FLAGS ((PDSC$K_KIND_FP_STACK << PDSC$V_KIND) \
+ | PDSC$M_BASE_REG_IS_FP | PDSC$M_NATIVE | PDSC$M_NO_JACKET | PDSC$M_HANDLER_VALID)
diff --git a/sr_avms/procdesc.max b/sr_avms/procdesc.max
new file mode 100644
index 0000000..e30c2f9
--- /dev/null
+++ b/sr_avms/procdesc.max
@@ -0,0 +1,6 @@
+ .macro PROCDESC
+
+GTM_PD_FLAGS = ^X00183099 ; these bits are set in create_object_file (in obj_file.c) in the beginning
+ ; of the procedure descriptor for all GT.M MUMPS object modules
+
+ .endm
diff --git a/sr_avms/putframe.max b/sr_avms/putframe.max
new file mode 100644
index 0000000..41bce4f
--- /dev/null
+++ b/sr_avms/putframe.max
@@ -0,0 +1,15 @@
+; Save registers into current GT.M MUMPS stack frame
+; Note: this macro requires a scratch register; you may specify one or it will default to r0.
+
+ .macro putframe reg=r0
+
+ ; A_frame_pointer must be address of quadword containing the address of frame_pointer
+ ldq reg, A_frame_pointer
+ ldl reg, (reg)
+ stl r8, msf$l_symtab_off(reg)
+ stl r9, msf$temps_ptr_off(reg)
+ stl r13, msf$ctxt_off(reg)
+ stl r14, msf$literal_ptr_off(reg)
+ stl r26, msf$mpc_off(reg)
+
+ .endm
diff --git a/sr_avms/release_name.h b/sr_avms/release_name.h
new file mode 100644
index 0000000..32baa09
--- /dev/null
+++ b/sr_avms/release_name.h
@@ -0,0 +1,14 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#define GTM_RELEASE_NAME "GT.M V6.0-003 VMS AXP"
+#define GTM_PRODUCT "GT.M"
+#define GTM_VERSION "V6.0"
diff --git a/sr_avms/rundown_dispatch.m64 b/sr_avms/rundown_dispatch.m64
new file mode 100644
index 0000000..174a790
--- /dev/null
+++ b/sr_avms/rundown_dispatch.m64
@@ -0,0 +1,12 @@
+ .title RUNDOWN_DISPATCH
+
+ $routine RUNDOWN_DISPATCH, kind=stack
+ .base r27, $ls
+
+ $call USER_RUNDOWN
+
+ $return
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/secshrlink.axp b/sr_avms/secshrlink.axp
new file mode 100644
index 0000000..307b4b8
--- /dev/null
+++ b/sr_avms/secshrlink.axp
@@ -0,0 +1,32 @@
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+! !
+! Copyright 2001, 2010 Fidelity Information Services, Inc !
+! !
+! This source code contains the intellectual property !
+! of its copyright holder(s), and is made available !
+! under a license. If you do not know the terms of !
+! the license, please stop and do not read further. !
+! !
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!
+protect=yes
+obd/inc=(gtmsecplv,crit_wake,del_sec,init_sec,gtm_enq,gtm_enqw,gtm_deq,gtm_blkast)
+obd/inc=(get_proc_info,init_secshr_addrs,gtm_getlkiw,secshr_db_clnup)
+obd/inc=(adawi,bci,gtm_memmove,mutex_stoprel,probe,prober,probew,relqueop,rundown_dispatch)
+obd/inc=(sec_shr_blk_build,sec_shr_map_build,aswp_secshr,compswap_secshr,is_proc_alive)
+urd
+gsmatch=lequal,13,0
+symbol_vector=( -
+ crit_wake = PROCEDURE, -
+ del_sec = PROCEDURE, -
+ init_sec = PROCEDURE, -
+ gtm_enq = PROCEDURE, -
+ gtm_enqw = PROCEDURE, -
+ gtm_deq = PROCEDURE, -
+ gtm_blkast = PROCEDURE, -
+ get_proc_info = PROCEDURE, -
+ init_secshr_addrs = PROCEDURE, -
+ gtm_getlkiw = PROCEDURE, -
+ secshr_db_clnup = PROCEDURE, -
+ probe = PROCEDURE -
+ )
diff --git a/sr_avms/zc_call.m64 b/sr_avms/zc_call.m64
new file mode 100644
index 0000000..cac7c06
--- /dev/null
+++ b/sr_avms/zc_call.m64
@@ -0,0 +1,363 @@
+; ****************************************************************
+; * *
+; * Copyright 2001, 2012 Fidelity Information Services, Inc *
+; * This source code contains the intellectual property *
+; * of its copyright holder(s), and is made available *
+; * under a license. If you do not know the terms of *
+; * the license, please stop and do not read further. *
+; * *
+; ****************************************************************
+
+ .title ZC_CALL
+
+; Call interface:
+;
+; int zc_call (zcrtn, zcret, lcllist, lcllistend, save_ret);
+; zctabrtn *zcrtn;
+; zctabret *zcret;
+; lclarg *lcllist, *lcllistend;
+; int *save_ret;
+;
+; On entry, lcllist points to a list of local arguments, and lcllistend
+; points to the byte just after the last argument in the list. ZC_CALL
+; passes these arguments to the routine pointed to by zcrtn, and processes
+; the return value as specified by zcret and save_ret.
+
+; The following definitions must reflect the structure layouts in ZCALL.H:
+
+; ZCALL Table routine offsets (correspond to type zctabrtn):
+ rtn_entrypoint = 4
+
+; ZCALL Table return offsets (correspond to type zctabret):
+ ret_class = 0
+ ret_type = 1
+
+; ZCALL Table argument offsets (correspond to types zctabinput and zctaboutput):
+ arg_mechanism = 0
+ arg_type = 1
+ arg_qualifier = 3
+
+
+; Local argument offsets; these definitions reflect the structure layout of
+; type lclarg, which is defined in DO_ZCALL.C:
+ lcl_skip = 0
+ lcl_zctab = 4
+ lcl_dsc = 8
+
+ lcl_size = 48
+
+
+ zcdef
+ macro64$callstd_defs
+
+
+ $linkage_section
+
+a_zcch:
+ .address ZCCH
+
+L_ERR_ZCSTATUS:
+ .long ERR_ZCSTATUS
+
+L_ERR_GTMCHECK:
+ .long ERR_GTMCHECK
+
+
+ $code_section
+
+ $routine ZC_CALL, entry=ZC_CALL_CA, kind=stack, saved_regs=<r2,r3,r13,fp>, -
+ handler=GTM$DYN_CH, rsa_offset=16
+ stq r31, 8(fp)
+ mov r27, r13
+ .base r13, $ls
+
+
+; Process the local arguments in reverse order;
+; r18 = lcllist
+; r19 = lcllistend
+
+ clr r0 ; r0 will count the arguments
+ clr r25 ; r25 will accumulate argument information
+
+loop:
+ subq r19, lcl_size, r19
+ cmple r18, r19, r24
+ blbc r24, setup_call
+
+ ldl r1, lcl_zctab(r19) ; lclarg.zctab, ZCALL Table argument
+
+; Skip this argument?
+ ldl r26, lcl_skip(r19) ; lclarg.skip
+ blbc r26, 10$
+
+; Yes; is this argument optional?
+ ldq_u r24, arg_qualifier(r1)
+ lda r23, arg_qualifier(r1)
+ extbl r24, r23, r24
+ cmpeq r24, zc$iqual_optional, r24
+ blbs r24, loop ; yes; skip it
+
+10$: addq r0, 1, r0 ; bump the argument count
+ lda sp, -8(sp) ; allocate space for the argument
+
+; Shift any previous argument information up one slot:
+ sll r25, macro64$ai_reg_info1_length, r25
+
+ ldq_u r24, arg_mechanism(r1)
+ lda r23, arg_mechanism(r1)
+ extbl r24, r23, r24
+
+ lda r22, lcl_dsc(r19) ; lclarg.dsc
+
+ cmpeq r24, zc$mech_descriptor, r23
+ blbs r23, by_descriptor
+
+ cmpeq r24, zc$mech_descriptor64, r23
+ blbs r23, by_descriptor
+
+ ldl r22, dsc$a_pointer(r22)
+
+ cmpeq r24, zc$mech_reference, r23
+ blbs r23, by_reference
+
+ cmpeq r24, zc$mech_value, r23
+ blbc r23, assertfail
+
+; Argument is to be passed by value:
+ ldq_u r24, arg_type(r1)
+ lda r23, arg_type(r1)
+ extbl r24, r23, r24 ; r24 = data type
+
+ cmpeq r24, zc$dtype_long, r23
+ blbs r23, long
+
+ cmpeq r24, zc$dtype_word, r23
+ blbs r23, word
+
+ cmpeq r24, zc$dtype_byte, r23
+ blbs r23, byte
+
+ cmpeq r24, zc$dtype_longu, r23
+ blbs r23, longu
+
+ cmpeq r24, zc$dtype_wordu, r23
+ blbs r23, wordu
+
+ cmpeq r24, zc$dtype_byteu, r23
+ blbs r23, byteu
+
+ cmpeq r24, zc$dtype_quad, r23
+ blbs r23, quad
+
+ cmpeq r24, zc$dtype_floating, r23
+ blbs r23, float
+
+ cmpeq r24, zc$dtype_double, r23
+ blbs r23, double
+
+ cmpeq r24, zc$dtype_g_floating, r23
+ blbc r23, assertfail
+
+double:
+ mov macro64$ar_fg, r28
+ ldg f0, (r22) ; D_ or G_floating - fall into float_common
+
+float_common:
+ stg f0, (sp)
+ sll r28, macro64$ai_reg_info1_start, r28
+ or r25, r28, r25
+ br loop
+
+float: ldf f0, (r22)
+ mov macro64$ar_ff, r28
+ br float_common
+
+byte: ldq_u r28, (r22)
+ lda r23, 1(r22)
+ extqh r28, r23, r28
+ sra r28, 56, r28
+ stq r28, (sp)
+ br loop
+
+byteu: ldq_u r28, (r22)
+ extbl r28, r22, r28
+ stq r28, (sp)
+ br loop
+
+word: ldq_u r28, (r22)
+ ldq_u r27, 1(r22)
+ extwl r28, r22, r28
+ extwh r27, r22, r27
+ or r27, r28, r28
+ sll r28, 48, r28
+ sra r28, 48, r28
+ stq r28, (sp)
+ br loop
+
+wordu: ldq_u r28, (r22)
+ ldq_u r27, 1(r22)
+ extwl r28, r22, r28
+ extwh r27, r22, r27
+ or r27, r28, r28
+ stq r28, (sp)
+ br loop
+
+long: ldq_u r28, (r22)
+ ldq_u r27, 3(r22)
+ extll r28, r22, r28
+ extlh r27, r22, r27
+ or r27, r28, r28
+ sll r28, 32, r28
+ sra r28, 32, r28
+ stq r28, (sp)
+ br loop
+
+longu: ldq_u r28, (r22)
+ ldq_u r27, 3(r22)
+ extll r28, r22, r28
+ extlh r27, r22, r27
+ or r27, r28, r28
+ stq r28, (sp)
+ br loop
+
+quad: ldq_u r28, (r22)
+ ldq_u r27, 7(r22)
+ extql r28, r22, r28
+ extqh r27, r22, r27
+ or r27, r28, r28
+ stq r28, (sp)
+ br loop
+
+
+; Argument is to be passed by descriptor or by reference:
+by_descriptor:
+ cmovlbs r26, 0, r22 ; if this arg is to be skipped, zero out r22
+
+by_reference:
+ stq r22, (sp) ; stack address of argument
+ br loop
+
+
+; All of the arguments have been processed; set up the ZCALL:
+
+setup_call:
+ addq r19, lcl_size, r19 ; assert (r19 + lcl_size == lcllist);
+ cmpeq r19, r18, r24
+ blbc r24, assertfail
+
+ mov r17, r2 ; save zcret
+ mov r20, r3 ; save save_ret
+
+ ldl r27, rtn_entrypoint(r16); r27 = zcrtn->entrypoint = address of procedure descriptor
+ ldq r26, 8(r27) ; r26 = address of entry point
+
+; Set up the Argument Information register, r25;
+; bits <63:26> must be zero, and the argument count goes in the low order byte:
+ sll r25, 38, r25
+ srl r25, 38, r25
+ or r25, r0, r25
+
+; At this point, all of the arguments are on the stack. Even though there
+; may be fewer than six of them, it's a lot faster and easier to load all six
+; integer argument registers and all six floating point argument registers
+; than it would be to figure out how many to load, and into which registers.
+; If there are actually fewer than six arguments, then the values loaded into
+; some of these registers will be irrelevant. This is not a big deal.
+
+ ldq r16, (sp)
+ ldq r17, 8(sp)
+ ldq r18, 16(sp)
+ ldq r19, 24(sp)
+ ldq r20, 32(sp)
+ ldq r21, 40(sp)
+
+ ldg f16, (sp)
+ ldg f17, 8(sp)
+ ldg f18, 16(sp)
+ ldg f19, 24(sp)
+ ldg f20, 32(sp)
+ ldg f21, 40(sp)
+
+; The stack pointer must also be adjusted to reflect that these arguments have
+; been "popped" off the stack. Only the actual number of arguments (up to six)
+; will be popped. This leaves the seventh and successive arguments on the stack
+; (if any).
+
+ mov 6, r22
+ cmplt r0, r22, r24
+ cmovlbs r24, r0, r22 ; r22 = min(6,r0) = number of arguments popped
+ s8addq r22, sp, sp
+
+
+ ldq r28, a_zcch
+ stq r28, 8(fp) ; establish ZCALL condition handler
+
+ jsr r26, r26 ; ZCALL
+
+ stq r31, 8(fp) ; remove ZCALL condition handler
+
+; Check the return class:
+ ldq_u r28, ret_class(r2)
+ lda r27, ret_class(r2)
+ extbl r28, r27, r28 ; r28 = zcret->class
+
+ cmpeq r28, zc$retc_status, r23
+ blbs r23, check_status
+
+ cmpeq r28, zc$retc_value, r23
+ blbc r23, return
+
+; Return class = value; check the data type:
+ ldq_u r24, ret_type(r2)
+ lda r27, ret_type(r2)
+ extbl r24, r27, r24 ; r24 = zcret->type
+
+ cmpeq r24, zc$dtype_long, r23
+ blbs r23, quad_ret
+
+ cmpeq r24, zc$dtype_longu, r23
+ blbs r23, quad_ret
+
+ cmpeq r24, zc$dtype_quad, r23
+ blbs r23, quad_ret
+
+ cmpeq r24, zc$dtype_floating, r23
+ blbs r23, float_ret
+
+ cmpeq r24, zc$dtype_double, r23
+ blbs r23, double_ret
+
+ cmpeq r24, zc$dtype_g_floating, r23
+ blbc r23, assertfail
+
+double_ret:
+ stg f0, (r3)
+ br return
+
+float_ret:
+ stf f0, (r3)
+ br return
+
+quad_ret:
+ stq r0, (r3)
+
+
+return:
+ $return
+
+
+check_status:
+ stl r0, (r3)
+ blbs r0, return
+ mov r0, r18
+ $call LIB$SIGNAL, args=<L_ERR_ZCSTATUS/L, 0/a, r18, 0/a>, nonstandard=true
+ br return
+
+
+assertfail:
+ $call LIB$SIGNAL, args=L_ERR_GTMCHECK/L, nonstandard=true
+ br return
+
+ $end_routine
+
+ .end
diff --git a/sr_avms/zc_makespace.m64 b/sr_avms/zc_makespace.m64
new file mode 100644
index 0000000..672753a
--- /dev/null
+++ b/sr_avms/zc_makespace.m64
@@ -0,0 +1,55 @@
+; ****************************************************************
+; * *
+; * Copyright 2001, 2004 Sanchez Computer Associates, Inc. *
+; * This source code contains the intellectual property *
+; * of its copyright holder(s), and is made available *
+; * under a license. If you do not know the terms of *
+; * the license, please stop and do not read further. *
+; * *
+; ****************************************************************
+
+ .title ZC_MAKESPACE
+
+;
+; Call interface:
+;
+; void zc_makespace (dst, mask, mvallist, mvallistend, zcrtn, n_tabargs)
+; mval *dst, **mvallist, **mvallistend;
+; long mask;
+; zctabrtn *zcrtn;
+; unsigned n_tabargs;
+;
+; ZC_MAKESPACE calls DO_ZCALL as follows:
+;
+; do_zcall (dst, mask, mvallist, mvallistend, zcrtn, lcllist, lcllistend);
+;
+; where:
+;
+; dst ... zcrtn are simply passed on unchanged;
+; lcllist is the address of the first element of an array of
+; struct lclarg_type [see DO_ZCALL.C for definition]; and
+; lcllistend is the address of the next byte after the last element
+; in the array pointed to by lcllist.
+;
+; Since lcllistend is the seventh argument, it must be passed on the stack.
+; The array is also allocated on the stack; the number of elements is specified
+; by the input parameter n_tabargs, and the size of each element is 48 bytes.
+; See DO_ZCALL.C for details.
+;
+
+ $routine ZC_MAKESPACE, entry=ZC_MAKESPACE_CA, kind=stack
+ .base r27, $ls
+
+; On entry, r21 = n_tabargs
+ mulq r21, 48, r21 ; r21 = n_tabargs * 48
+ subq sp, r21, sp
+ mov sp, r21 ; r21 = lcllist
+
+; lcllistend = fp [= original sp]
+ $call DO_ZCALL, args=<r16,r17,r18,r19,r20,r21,fp>
+
+ $return
+
+ $end_routine
+
+ .end
diff --git a/sr_cmi/cmi_close.c b/sr_cmi/cmi_close.c
new file mode 100644
index 0000000..64381c2
--- /dev/null
+++ b/sr_cmi/cmi_close.c
@@ -0,0 +1,63 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include <iodef.h>
+#include <efndef.h>
+#include "cmihdr.h"
+#include "cmidef.h"
+#include "efn.h"
+
+#define TIMER_FLAGS 0
+
+GBLREF struct NTD *ntd_root;
+
+uint4 cmi_close(struct CLB *lnk)
+{
+ uint4 efn_mask, status;
+ static readonly int4 delta_1_sec[2] = { -10000000, -1 };
+ struct CLB *previous;
+ qio_iosb iosb;
+
+ lnk->sta = CM_CLB_DISCONNECT;
+ previous = RELQUE2PTR(lnk->cqe.fl);
+ remqti(previous);
+ efn_mask = (0x1 << efn_cmi_immed_wait | 0x1 << efn_2timer);
+
+ /* DECnet OSI does not currently time out if the channel is gone, so protect it with our own timer */
+ status = sys$setimr(efn_2timer, &delta_1_sec, 0, lnk, TIMER_FLAGS);
+ if (status & 1)
+ {
+ /* If we can't get the timer (which we believe should be exceedingly rare), just blow it away to prevent a hang */
+
+ /* First, request a disconnect (also transmits all pending messages before disconnecting). */
+ status = SYS$QIO(efn_cmi_immed_wait, lnk->dch, IO$_DEACCESS | IO$M_SYNCH, &iosb, 0, 0, 0, 0, 0, 0, 0, 0);
+ /* Ignore previous status return because we're going to deassign the link regardless. */
+
+ status = sys$wflor(efn_2timer, efn_mask);
+ /* Unless in test, ignore previous status return because we're going to deassign the link regardless. */
+ assert(status & 1);
+ }else
+ assert(0); /* In testing trap the timer failure */
+
+ sys$cantim(lnk, 0); /* in case still running */
+ /* abort the link in case the timer went off */
+ status = SYS$QIOW(EFN$C_ENF, lnk->dch, IO$_DEACCESS | IO$M_ABORT, &iosb, 0, 0, 0, 0, 0, 0, 0, 0);
+ /* Ignore previous status return because we're going to deassign the link regardless. */
+ status = SYS$CANCEL(lnk->dch);
+ /* Ignore previous status for same reason. */
+
+ status = SYS$DASSGN(lnk->dch);
+ if ((status & 1) == 0)
+ return status;
+
+ lib$free_vm(&SIZEOF(*lnk), &lnk, 0);
+ return status;
+}
diff --git a/sr_cmi/cmi_init.c b/sr_cmi/cmi_init.c
new file mode 100644
index 0000000..274cdff
--- /dev/null
+++ b/sr_cmi/cmi_init.c
@@ -0,0 +1,78 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include <descrip.h>
+#include <iodef.h>
+#include <efndef.h>
+#ifdef __Alpha_AXP
+#include nfbdef
+#else
+#include <nfbdef.h>
+#endif
+#include "cmihdr.h"
+#include "cmidef.h"
+
+GBLREF struct NTD *ntd_root;
+
+uint4 cmi_init(cmi_descriptor *tnd, unsigned char tnr, void (*err)(), void (*crq)(), bool (*acc)())
+{
+ uint4 status;
+
+#ifdef __Alpha_AXP
+# pragma member_alignment save
+# pragma nomember_alignment
+#endif
+
+ struct
+ {
+ unsigned char operation;
+ int4 object_number;
+ } nfb;
+
+#ifdef __Alpha_AXP
+# pragma member_alignment restore
+#endif
+
+ struct dsc$descriptor_s nfb_desc;
+ qio_iosb iosb;
+ error_def(CMI_CMICHECK);
+
+ status = cmj_netinit();
+ if ((status & 1) == 0)
+ return status;
+ nfb_desc.dsc$w_length = SIZEOF(nfb);
+ nfb_desc.dsc$b_dtype = DSC$K_DTYPE_T;
+ nfb_desc.dsc$b_class = DSC$K_CLASS_S;
+ nfb_desc.dsc$a_pointer = &nfb;
+ if (tnr != 0)
+ {
+ nfb.operation = NFB$C_DECLOBJ;
+ nfb.object_number = tnr;
+ if (0 != tnd)
+ return CMI_CMICHECK;
+ } else
+ {
+ if (0 == tnd)
+ return CMI_CMICHECK;
+ nfb.operation = NFB$C_DECLNAME;
+ nfb.object_number = 0;
+ }
+ status = sys$qiow(EFN$C_ENF, ntd_root->dch, IO$_ACPCONTROL, &iosb, 0, 0, &nfb_desc, tnd, 0, 0, 0, 0);
+ if (status & 1)
+ status = iosb.status;
+ if ((status & 1) == 0)
+ return status;
+ ntd_root->err = err;
+ ntd_root->crq = crq;
+ ntd_root->acc = acc;
+ status = cmj_mbx_read_start(ntd_root);
+ return status;
+}
diff --git a/sr_cmi/cmi_open.c b/sr_cmi/cmi_open.c
new file mode 100644
index 0000000..b1f19c4
--- /dev/null
+++ b/sr_cmi/cmi_open.c
@@ -0,0 +1,64 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include <descrip.h>
+#include <iodef.h>
+#include <efndef.h>
+#include "cmihdr.h"
+#include "cmidef.h"
+
+GBLREF struct NTD *ntd_root;
+GBLREF struct dsc$descriptor_s cm_netname;
+
+#define TASK_PREFIX "::\"0="
+#define TASK_SUFFIX "\""
+#define MAX_NCB_LENGTH 128
+
+uint4 cmi_open(struct CLB *lnk)
+{
+ uint4 status;
+ struct dsc$descriptor_s ncb;
+ qio_iosb iosb;
+ unsigned char *cp;
+ unsigned char ncb_buffer[MAX_NCB_LENGTH];
+
+ if (ntd_root == 0)
+ {
+ status = cmj_netinit();
+ if ((status & 1) == 0)
+ return status;
+ }
+ ncb.dsc$w_length = lnk->nod.dsc$w_length + lnk->tnd.dsc$w_length + SIZEOF(TASK_PREFIX) - 1 + SIZEOF(TASK_SUFFIX) - 1;
+ ncb.dsc$b_dtype = DSC$K_DTYPE_T;
+ ncb.dsc$b_class = DSC$K_CLASS_S;
+ ncb.dsc$a_pointer = cp = ncb_buffer;
+ assert(ncb.dsc$w_length < SIZEOF(ncb_buffer));
+ memcpy(cp, lnk->nod.dsc$a_pointer, lnk->nod.dsc$w_length);
+ cp += lnk->nod.dsc$w_length;
+ memcpy(cp, TASK_PREFIX, SIZEOF(TASK_PREFIX) - 1);
+ cp += SIZEOF(TASK_PREFIX) - 1;
+ memcpy(cp, lnk->tnd.dsc$a_pointer, lnk->tnd.dsc$w_length);
+ cp += lnk->tnd.dsc$w_length;
+ memcpy(cp, TASK_SUFFIX, SIZEOF(TASK_SUFFIX) - 1);
+ status = sys$assign(&cm_netname, &lnk->dch, 0, 0);
+ if (status & 1)
+ {
+ status = sys$qiow(EFN$C_ENF, lnk->dch, IO$_ACCESS, &iosb, 0, 0, 0, &ncb, 0, 0, 0, 0);
+ if (status & 1)
+ status = iosb.status;
+ if (status & 1)
+ { insqhi(lnk, ntd_root);
+ }else
+ { sys$dassgn(lnk->dch);
+ }
+ }
+ return status;
+}
diff --git a/sr_cmi/cmi_read.c b/sr_cmi/cmi_read.c
new file mode 100644
index 0000000..fd63927
--- /dev/null
+++ b/sr_cmi/cmi_read.c
@@ -0,0 +1,21 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include <iodef.h>
+#include "cmihdr.h"
+#include "cmidef.h"
+
+uint4 cmi_read(lnk)
+struct CLB *lnk;
+{
+ lnk->cbl = lnk->mbl;
+ return cmj_iostart(lnk,IO$_READVBLK, CM_CLB_READ);
+}
diff --git a/sr_cmi/cmi_write.c b/sr_cmi/cmi_write.c
new file mode 100644
index 0000000..0210a17
--- /dev/null
+++ b/sr_cmi/cmi_write.c
@@ -0,0 +1,20 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include <iodef.h>
+#include "cmihdr.h"
+#include "cmidef.h"
+
+uint4 cmi_write(lnk)
+struct CLB *lnk;
+{
+ return cmj_iostart(lnk, IO$_WRITEVBLK, CM_CLB_WRITE);
+}
diff --git a/sr_cmi/cmi_write_int.c b/sr_cmi/cmi_write_int.c
new file mode 100644
index 0000000..6262446
--- /dev/null
+++ b/sr_cmi/cmi_write_int.c
@@ -0,0 +1,28 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include <iodef.h>
+#include <efndef.h>
+#include "cmihdr.h"
+#include "cmidef.h"
+
+uint4 cmi_write_int(struct CLB *lnk)
+{
+ int4 status;
+ qio_iosb iosb;
+
+ /* Note: there is an outstanding read so use unique efn and iosb */
+ status = sys$qiow(EFN$C_ENF, lnk->dch, IO$_WRITEVBLK | IO$M_INTERRUPT,
+ &iosb, 0, 0, lnk->mbf, lnk->cbl, 0, 0, 0, 0);
+ if (status & 1)
+ status = iosb.status;
+ return status;
+}
diff --git a/sr_cmi/cmierrors.msg b/sr_cmi/cmierrors.msg
new file mode 100644
index 0000000..f4cd78d
--- /dev/null
+++ b/sr_cmi/cmierrors.msg
@@ -0,0 +1,20 @@
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+! !
+! Copyright 2001, 2009 Fidelity Information Services, Inc !
+! !
+! This source code contains the intellectual property !
+! of its copyright holder(s), and is made available !
+! under a license. If you do not know the terms of !
+! the license, please stop and do not read further. !
+! !
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ .FACILITY CMI,250/PREFIX=CMI_
+ .TITLE CMIERRORS Error Messages for CMI..GT.CM
+
+DCNINPROG <Attempt to initiate operation while disconnect was in progress>/fatal/fao=0
+LNKNOTIDLE <Attempt to initiate operation before previous operation completed>/fatal/fao=0
+ASSERT <Assert failed !AD line !UL>/error/fao=3
+CMICHECK <Internal CMI error. Report to your GT.M Support Channel.>/fatal/fao=0
+NETFAIL <Failure of Net operation>/error/fao=0
+
+ .end
diff --git a/sr_cmi/cmihdr.h b/sr_cmi/cmihdr.h
new file mode 100644
index 0000000..2b05134
--- /dev/null
+++ b/sr_cmi/cmihdr.h
@@ -0,0 +1,30 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "gtm_sizeof.h"
+
+#define rts_error lib$signal
+#define error_def(x) globalvalue x
+#ifdef DEBUG
+error_def(CMI_ASSERT);
+#define assert(x) ((x) ? 1 : rts_error(CMI_ASSERT, 3, SIZEOF(__FILE__) - 1, __FILE__, __LINE__))
+#else
+#define assert(x)
+#endif
+#define GBLDEF globaldef
+#define GBLREF globalref
+#define LITDEF readonly globaldef
+#define LITREF readonly globalref
+typedef char bool;
+#define ALIGN_QUAD _align(quadword)
+#define TRUE 1
+#define FALSE 0
+
diff --git a/sr_cmi/cmivector.mar b/sr_cmi/cmivector.mar
new file mode 100644
index 0000000..596f9f1
--- /dev/null
+++ b/sr_cmi/cmivector.mar
@@ -0,0 +1,23 @@
+ .title cmivector - transfer vectors for shared images
+ .psect cmivector,page,con,exe,pic,nowrt,shr,gbl
+
+cmivector_size = 16 ;total of 16 transfer vectors
+
+ .macro xfer a
+ .transfer a
+ .mask a
+ jmp l^a+2
+ .endm
+
+cmivector::
+ xfer cmi_close
+ xfer cmi_init
+ xfer cmi_open
+ xfer cmi_read
+ xfer cmi_write
+ xfer cmi_write_int
+ xfer cmu_makclb
+ xfer cmu_getclb
+ xfer cmu_ntdroot
+ .blkq cmivector_size - <<. - cmivector> / 8>
+ .end
diff --git a/sr_cmi/cmj_ast.c b/sr_cmi/cmj_ast.c
new file mode 100644
index 0000000..10623cb
--- /dev/null
+++ b/sr_cmi/cmj_ast.c
@@ -0,0 +1,26 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "cmihdr.h"
+#include "cmidef.h"
+
+void cmj_ast(lnk)
+struct CLB *lnk;
+{
+ uint4 status;
+ error_def(CMI_DCNINPROG);
+ error_def(CMI_LNKNOTIDLE);
+
+ cmj_fini(lnk);
+ if (lnk->ast != 0)
+ (*lnk->ast)(lnk);
+ return;
+}
diff --git a/sr_cmi/cmj_disconn2.c b/sr_cmi/cmj_disconn2.c
new file mode 100644
index 0000000..50843ad
--- /dev/null
+++ b/sr_cmi/cmj_disconn2.c
@@ -0,0 +1,28 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "cmihdr.h"
+#include "cmidef.h"
+
+void cmj_disconn2(lnk)
+struct CLB *lnk;
+{
+ int status;
+ error_def(CMI_NETFAIL);
+
+/* Ignore iosb of previous qio because we're going to deassign the link regardless. */
+
+ status = SYS$DASSGN(lnk->dch);
+ lib$free_vm(&SIZEOF(*lnk), &lnk, 0);
+ if ((status & 1) == 0)
+ rts_error(CMI_NETFAIL,0,status);
+ return;
+}
diff --git a/sr_cmi/cmj_fini.c b/sr_cmi/cmj_fini.c
new file mode 100644
index 0000000..074d357
--- /dev/null
+++ b/sr_cmi/cmj_fini.c
@@ -0,0 +1,33 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "cmihdr.h"
+#include "cmidef.h"
+
+void cmj_fini(lnk)
+struct CLB *lnk;
+{
+ switch (lnk->sta)
+ {
+ case CM_CLB_READ:
+ lnk->cbl = lnk->ios.xfer_count;
+ break;
+ case CM_CLB_WRITE:
+ break;
+ case CM_CLB_IDLE:
+ assert(FALSE);
+ break;
+ case CM_CLB_DISCONNECT:
+ return;
+ }
+ lnk->sta = CM_CLB_IDLE;
+ return;
+}
diff --git a/sr_cmi/cmj_iostart.c b/sr_cmi/cmj_iostart.c
new file mode 100644
index 0000000..65ab55a
--- /dev/null
+++ b/sr_cmi/cmj_iostart.c
@@ -0,0 +1,46 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2002 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include <iodef.h>
+#include <efndef.h>
+#include "cmihdr.h"
+#include "cmidef.h"
+#include "efn.h"
+
+uint4 cmj_iostart(struct CLB *lnk, uint4 operation, unsigned int state)
+{
+ uint4 status;
+ error_def(CMI_DCNINPROG);
+ error_def(CMI_LNKNOTIDLE);
+ void cmj_ast();
+
+ if (lnk->sta != CM_CLB_IDLE)
+ return (lnk->sta == CM_CLB_DISCONNECT) ? CMI_DCNINPROG : CMI_LNKNOTIDLE;
+ lnk->sta = (unsigned char)state;
+ if (lnk->ast)
+ {
+ status = sys$qio(EFN$C_ENF, lnk->dch, operation,
+ &lnk->ios, cmj_ast, lnk,
+ lnk->mbf, lnk->cbl, 0, 0, 0, 0);
+ } else
+ {
+ status = sys$qio(EFN$C_ENF, lnk->dch, operation,
+ &lnk->ios, 0, 0, lnk->mbf, lnk->cbl, 0, 0, 0, 0);
+ if (1 & status)
+ {
+ status = sys$synch(EFN$C_ENF, &lnk->ios);
+ cmj_fini(lnk);
+ if (1 & status)
+ status = lnk->ios.status;
+ }
+ }
+ return status;
+}
diff --git a/sr_cmi/cmj_mbx_ast.c b/sr_cmi/cmj_mbx_ast.c
new file mode 100644
index 0000000..160470e
--- /dev/null
+++ b/sr_cmi/cmj_mbx_ast.c
@@ -0,0 +1,231 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include <descrip.h>
+#include <dvidef.h>
+#include <iodef.h>
+#include <msgdef.h>
+#include <ssdef.h>
+#include "cmihdr.h"
+#include "cmidef.h"
+#include "efn.h"
+
+GBLREF struct dsc$descriptor_s cm_netname;
+error_def(CMI_NETFAIL);
+static void cmj_accept_ast(), cmj_reject_ast(), cmj_mbx_err();
+
+void cmj_mbx_ast(struct NTD *tsk)
+{
+ struct CLB *cmu_makclb();
+ struct dsc$descriptor_s ncb_desc;
+ uint4 status, unit;
+ cm_mbx *mp;
+ struct CLB *lnk;
+ bool newclb;
+ void cmj_ast();
+
+ status = 0;
+ mp = tsk->mbx.dsc$a_pointer;
+ assert(mp->netnum == 3 && mp->netnam[0] == 'N' && mp->netnam[1] == 'E' && mp->netnam[2] == 'T');
+ switch(mp->msg)
+ {
+ case MSG$_CONNECT:
+ lnk = cmj_unit2clb(tsk, mp->unit);
+ if (lnk == 0)
+ {
+ newclb = TRUE;
+ lnk = cmu_makclb();
+ lnk->dch = tsk->dch;
+ lnk->ntd = tsk;
+ }else
+ {
+ newclb = FALSE;
+ assert(lnk->sta == CM_CLB_IDLE);
+ }
+ ncb_desc.dsc$w_length = mp->len;
+ ncb_desc.dsc$b_dtype = DSC$K_DTYPE_T;
+ ncb_desc.dsc$b_class = DSC$K_CLASS_S;
+ ncb_desc.dsc$a_pointer = mp->text;
+ lnk->mbf = 0;
+ /* the statement below and the 3 qio's emulate cmj_iostart which could be used if lnk->clb were a int4 */
+ lnk->sta = CM_CLB_WRITE;
+ if (tsk->crq == 0)
+ {
+ lnk->ast = cmj_reject_ast;
+ status = sys$qio(efn_ignore, lnk->dch, IO$_ACCESS | IO$M_ABORT,
+ &lnk->ios, cmj_ast, lnk,
+ lnk->mbf, &ncb_desc, 0, 0, 0, 0);
+ } else
+ { if (tsk->acc && !(*tsk->acc)(lnk))
+ {
+ lnk->ast = cmj_reject_ast;
+ status = sys$qio(efn_ignore, lnk->dch, IO$_ACCESS | IO$M_ABORT,
+ &lnk->ios, cmj_ast, lnk,
+ lnk->mbf, &ncb_desc, 0, 0, 0, 0);
+ }else
+ {
+ status = sys$assign(&cm_netname, &lnk->dch, 0, &tsk->mnm);
+ if (status & 1)
+ {
+ status = lib$getdvi(&DVI$_UNIT, &lnk->dch, 0, &unit, 0, 0);
+ if (status & 1)
+ {
+ lnk->mun = (unsigned short)unit;
+ lnk->ast = cmj_accept_ast;
+ status = sys$qio(efn_ignore, lnk->dch, IO$_ACCESS,
+ &lnk->ios, cmj_ast, lnk,
+ lnk->mbf, &ncb_desc, 0, 0, 0, 0);
+ }
+ }
+ }
+ }
+ if ((status & 1) == 0)
+ {
+ if (newclb)
+ {
+ lib$free_vm(&SIZEOF(*lnk), &lnk, 0);
+ lnk = 0;
+ }
+ cmj_mbx_err(status, tsk, lnk);
+ break;
+ }
+ return;
+
+ case MSG$_INTMSG:
+ if (tsk->mbx_ast != 0)
+ { (*tsk->mbx_ast)(tsk);
+ break;
+ }
+ /* CAUTION: FALLTHROUGH */
+ case MSG$_DISCON:
+ case MSG$_ABORT:
+ case MSG$_EXIT:
+ case MSG$_PATHLOST:
+ case MSG$_PROTOCOL:
+ case MSG$_THIRDPARTY:
+ case MSG$_TIMEOUT:
+ case MSG$_NETSHUT:
+ case MSG$_REJECT:
+ case MSG$_CONFIRM:
+ if (tsk->err)
+ {
+ lnk = cmj_unit2clb(tsk, mp->unit);
+ (*tsk->err)(tsk, lnk, mp->msg);
+ }else
+ rts_error(CMI_NETFAIL,0,status); /* condition handler would need to close the connection */
+ /* CAUTION: FALLTHROUGH */
+ default:
+ break;
+ }
+
+ status = cmj_mbx_read_start(tsk);
+ if ((status & 1) == 0)
+ {
+ lnk = cmj_unit2clb(tsk, mp->unit);
+ cmj_mbx_err(status, tsk, lnk);
+ }
+}
+
+static void cmj_reject_ast(struct CLB *lnk)
+{
+ struct NTD *tsk;
+ uint4 status;
+
+ tsk = lnk->ntd;
+ status = lnk->ios.status;
+ if ((status & 1) == 0)
+ {
+ if (cmj_unit2clb(tsk, lnk->mun) == 0)
+ {
+ lib$free_vm(&SIZEOF(*lnk), &lnk, 0);
+ lnk = 0;
+ }
+ cmj_mbx_err(status, tsk, lnk);
+ }
+
+ status = cmj_mbx_read_start(tsk);
+ if ((status & 1) == 0)
+ cmj_mbx_err(status, tsk, lnk);
+}
+
+static void cmj_accept_ast(struct CLB *lnk)
+{
+ struct NTD *tsk;
+ uint4 status;
+
+ tsk = lnk->ntd;
+ status = lnk->ios.status;
+ if ((status & 1) == 0)
+ {
+ if (cmj_unit2clb(tsk, lnk->mun) == 0)
+ {
+ lib$free_vm(&SIZEOF(*lnk), &lnk, 0);
+ lnk = 0;
+ }
+ cmj_mbx_err(status, tsk, lnk);
+ }else
+ {
+ insqhi(lnk, tsk);
+ (*tsk->crq)(lnk);
+ }
+
+ status = cmj_mbx_read_start(tsk);
+ if ((status & 1) == 0)
+ cmj_mbx_err(status, tsk, lnk);
+}
+
+static void cmj_mbx_err(uint4 status, struct NTD *tsk, struct CLB *lnk)
+{
+ unsigned int msg;
+
+ if (tsk->err)
+ {
+ switch (status)
+ {
+ case SS$_LINKABORT:
+ msg = MSG$_ABORT;
+ break;
+ case SS$_LINKDISCON:
+ msg = MSG$_DISCON;
+ break;
+ case SS$_LINKEXIT:
+ msg = MSG$_EXIT;
+ break;
+ case SS$_PATHLOST:
+ msg = MSG$_PATHLOST;
+ break;
+ case SS$_PROTOCOL:
+ msg = MSG$_PROTOCOL;
+ break;
+ case SS$_THIRDPARTY:
+ msg = MSG$_THIRDPARTY;
+ break;
+ case SS$_CONNECFAIL:
+ case SS$_TIMEOUT:
+ msg= MSG$_TIMEOUT;
+ break;
+ case SS$_REJECT:
+ msg = MSG$_REJECT;
+ break;
+ default:
+ case SS$_DEVALLOC:
+ case SS$_IVDEVNAM:
+ assert(FALSE);
+ /* CAUTION: FALLTHROUGH */
+ case SS$_NOSUCHNODE:
+ case SS$_UNREACHABLE:
+ msg = MSG$_NODEINACC;
+ break;
+ }
+ (*tsk->err)(tsk, lnk, msg);
+ }else
+ rts_error(CMI_NETFAIL,0,status); /* condition handler would need to close the connection */
+}
diff --git a/sr_cmi/cmj_mbx_read_start.c b/sr_cmi/cmj_mbx_read_start.c
new file mode 100644
index 0000000..1c50049
--- /dev/null
+++ b/sr_cmi/cmj_mbx_read_start.c
@@ -0,0 +1,25 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include <iodef.h>
+#include "cmihdr.h"
+#include "cmidef.h"
+#include "efn.h"
+
+int cmj_mbx_read_start(struct NTD *tsk)
+{
+ void cmj_mbx_ast();
+ int status;
+
+ status = sys$qio(efn_ignore, tsk->mch, IO$_READVBLK, &(tsk->mst),
+ &cmj_mbx_ast, tsk, tsk->mbx.dsc$a_pointer, tsk->mbx.dsc$w_length, 0, 0, 0, 0);
+ return status;
+}
diff --git a/sr_cmi/cmj_netinit.c b/sr_cmi/cmj_netinit.c
new file mode 100644
index 0000000..fb28e83
--- /dev/null
+++ b/sr_cmi/cmj_netinit.c
@@ -0,0 +1,62 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include <descrip.h>
+#include <dvidef.h>
+#include "cmihdr.h"
+#include "cmidef.h"
+
+GBLDEF $DESCRIPTOR(cm_netname,"_NET:");
+GBLDEF struct NTD *ntd_root;
+
+/* CLEAN-UP: 1. replace CMI_CMICHECK with new message
+ 2. find correct size and location of MBX_SIZE
+*/
+
+#define MBX_SIZE 256
+
+uint4 cmj_netinit()
+{
+ error_def(CMI_CMICHECK);
+ uint4 status;
+ int4 maxmsg,bufquo; /* lib$asn_wth_mbx uses longwords by reference for these items */
+ struct NTD *tsk;
+ unsigned char mailbox_name_buffer[128];
+ short unsigned mbx_name_length;
+ uint4 long_mnl;
+
+ if (ntd_root)
+ return CMI_CMICHECK;
+ lib$get_vm(&SIZEOF(*ntd_root), &ntd_root, 0);
+ tsk = ntd_root;
+ memset(tsk, 0, SIZEOF(*tsk));
+ tsk->mbx.dsc$w_length = MBX_SIZE;
+ tsk->mbx.dsc$b_dtype = DSC$K_DTYPE_T;
+ tsk->mbx.dsc$b_class = DSC$K_CLASS_S;
+ lib$get_vm(&MBX_SIZE, &tsk->mbx.dsc$a_pointer, 0);
+ maxmsg = tsk->mbx.dsc$w_length;
+ bufquo = maxmsg;
+ status = lib$asn_wth_mbx(&cm_netname, &maxmsg, &bufquo, &(tsk->dch), &(tsk->mch));
+ if ((status & 1) == 0)
+ return status;
+ tsk->mnm.dsc$w_length = SIZEOF(mailbox_name_buffer);
+ tsk->mnm.dsc$b_dtype = DSC$K_DTYPE_T;
+ tsk->mnm.dsc$b_class = DSC$K_CLASS_S;
+ tsk->mnm.dsc$a_pointer = mailbox_name_buffer;
+ status = lib$getdvi(&DVI$_FULLDEVNAM, &tsk->mch,0,0,&tsk->mnm,&mbx_name_length);
+ if ((status & 1) == 0)
+ return status;
+ long_mnl = mbx_name_length;
+ lib$get_vm(&long_mnl, &tsk->mnm.dsc$a_pointer, 0);
+ tsk->mnm.dsc$w_length = mbx_name_length;
+ memcpy(tsk->mnm.dsc$a_pointer, mailbox_name_buffer, mbx_name_length);
+ return status;
+}
diff --git a/sr_cmi/cmj_unit2clb.c b/sr_cmi/cmj_unit2clb.c
new file mode 100644
index 0000000..f4dc1a3
--- /dev/null
+++ b/sr_cmi/cmj_unit2clb.c
@@ -0,0 +1,27 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "cmihdr.h"
+#include "cmidef.h"
+
+struct CLB *cmj_unit2clb(tsk,unit)
+struct NTD *tsk;
+unsigned short unit;
+{
+ struct CLB *p;
+
+ for (p = RELQUE2PTR(tsk->cqh.fl) ; p != tsk ; p = RELQUE2PTR(p->cqe.fl))
+ {
+ if (p->mun == unit)
+ return p;
+ }
+ return 0;
+}
diff --git a/sr_cmi/cmj_util.mar b/sr_cmi/cmj_util.mar
new file mode 100644
index 0000000..d59c51d
--- /dev/null
+++ b/sr_cmi/cmj_util.mar
@@ -0,0 +1,70 @@
+ .title cmj_util utility routines
+
+; remqti - remove self-relative queue entry from tail interlocked
+;
+; calling sequence:
+;
+; typedef struct
+; {
+; long flink,blink;
+; } self_rel_que;
+;
+; self_rel_que *remqti(queheader)
+; self_rel_que *queheader;
+;
+; return:
+; if successful, then a pointer to the queue entry which was removed
+; if zero, then the queue was empty
+; if -1, then the secondary interlock failed, the instruction may
+; be retried, but should declare a GTMCHECK if the secondary
+; interlock fails repeatedly
+;
+QI_STARVATION = 6
+
+ .entry insqhi,^m<>
+ clrl r0
+ movl #QI_STARVATION,r1
+5$: insqhi @4(ap), at 8(ap)
+ bcs 20$
+ bneq 10$
+ incl r0
+10$: ret
+20$: sobgtr r1,5$
+ decl r0
+ ret
+
+ .entry insqti,^m<>
+ clrl r0
+ movl #QI_STARVATION,r1
+5$: insqti @4(ap), at 8(ap)
+ bcs 20$
+ bneq 10$
+ incl r0
+10$: ret
+20$: sobgtr r1,5$
+ decl r0
+ ret
+
+ .entry remqhi,^m<>
+ movl #QI_STARVATION,r1
+5$: remqhi @4(ap),r0
+ bcs 20$
+ bvc 10$
+ clrl r0
+10$: ret
+20$: sobgtr r1,5$
+ mnegl #1,r0
+ ret
+
+
+ .entry remqti,^m<>
+ movl #QI_STARVATION,r1
+5$: remqti @4(ap),r0
+ bcs 20$
+ bvc 10$
+ clrl r0
+10$: ret
+20$: sobgtr r1,5$
+ mnegl #1,r0
+ ret
+ .end
diff --git a/sr_cmi/cmu_getclb.c b/sr_cmi/cmu_getclb.c
new file mode 100644
index 0000000..8ef11ba
--- /dev/null
+++ b/sr_cmi/cmu_getclb.c
@@ -0,0 +1,35 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "cmihdr.h"
+#include "cmidef.h"
+
+GBLREF struct NTD *ntd_root;
+
+struct CLB *cmu_getclb(node, task)
+cmi_descriptor *node, *task;
+{
+ struct CLB *p;
+ if (ntd_root)
+ {
+ for (p = RELQUE2PTR(ntd_root->cqh.fl) ; p != ntd_root ; p = RELQUE2PTR(p->cqe.fl))
+ {
+ if (p->nod.dsc$w_length == node->dsc$w_length
+ && memcmp(p->nod.dsc$a_pointer, node->dsc$a_pointer, p->nod.dsc$w_length) == 0)
+ {
+ if (p->tnd.dsc$w_length == task->dsc$w_length
+ && memcmp(p->tnd.dsc$a_pointer, task->dsc$a_pointer, p->tnd.dsc$w_length) == 0)
+ return p;
+ }
+ }
+ }
+ return 0;
+}
diff --git a/sr_cmi/cmu_makclb.c b/sr_cmi/cmu_makclb.c
new file mode 100644
index 0000000..b2e025d
--- /dev/null
+++ b/sr_cmi/cmu_makclb.c
@@ -0,0 +1,22 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "cmihdr.h"
+#include "cmidef.h"
+
+struct CLB *cmu_makclb()
+{
+ struct CLB *lnk;
+
+ lib$get_vm(&SIZEOF(*lnk), &lnk, 0);
+ memset(lnk, 0, SIZEOF(*lnk));
+ return lnk;
+}
diff --git a/sr_cmi/cmu_ntdroot.c b/sr_cmi/cmu_ntdroot.c
new file mode 100644
index 0000000..9f081fa
--- /dev/null
+++ b/sr_cmi/cmu_ntdroot.c
@@ -0,0 +1,20 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "cmihdr.h"
+#include "cmidef.h"
+
+GBLREF struct NTD *ntd_root;
+
+struct NTD *cmu_ntdroot()
+{
+ return ntd_root;
+}
diff --git a/sr_i386/emit_code.c b/sr_i386/emit_code.c
index 6492225..66256ce 100644
--- a/sr_i386/emit_code.c
+++ b/sr_i386/emit_code.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -87,6 +87,9 @@ GBLDEF uint4 txtrel_cnt; /* count of text relocation records */
/* its referenced in ind_code.c */
GBLDEF int calculated_code_size, generated_code_size;
+error_def(ERR_UNIMPLOP);
+error_def(ERR_MAXARGCNT);
+
void trip_gen(triple *ct)
{
oprtype **sopr, *opr; /* triple operand */
@@ -99,8 +102,6 @@ void trip_gen(triple *ct)
oprtype *irep_opr;
short *repl, repcnt; /* temp irep ptr */
int4 off;
- error_def (ERR_UNIMPLOP);
- error_def (ERR_MAXARGCNT);
tp = ttt[ct->opcode];
if (tp <= 0)
@@ -125,8 +126,8 @@ void trip_gen(triple *ct)
continue;
}
*sopr++ = opr;
- if (sopr >= ARRAYTOP(saved_opr))
- rts_error(VARLSTCNT(3) ERR_MAXARGCNT, 1, MAX_ARGS);
+ if (sopr >= ARRAYTOP(saved_opr)) /* user-visible max args is MAX_ARGS - 3 */
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_MAXARGCNT, 1, MAX_ARGS - 3);
}
opr++;
}
@@ -752,8 +753,6 @@ void emit_trip(generic_op op, oprtype *opr, bool val_output, unsigned char use_r
int4 offset, literal;
triple *ct;
- error_def (ERR_UNIMPLOP);
-
if (opr->oprclass == TRIP_REF)
{
ct = opr->oprval.tref;
@@ -790,7 +789,7 @@ void emit_trip(generic_op op, oprtype *opr, bool val_output, unsigned char use_r
temp_reg = I386_REG_ECX;
break;
default:
- rts_error(VARLSTCNT(1) ERR_UNIMPLOP);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP);
break;
}
pc_value_idx = code_idx + 5;
@@ -832,7 +831,7 @@ void emit_trip(generic_op op, oprtype *opr, bool val_output, unsigned char use_r
code_idx += 1 + SIZEOF(int4);
break;
default:
- rts_error(VARLSTCNT(1) ERR_UNIMPLOP);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP);
break;
}
break;
@@ -940,7 +939,7 @@ void emit_trip(generic_op op, oprtype *opr, bool val_output, unsigned char use_r
emit_base_offset(use_reg, base_reg, offset);
break;
default:
- rts_error(VARLSTCNT(1) ERR_UNIMPLOP);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP);
break;
}
break;
@@ -970,7 +969,7 @@ void emit_trip(generic_op op, oprtype *opr, bool val_output, unsigned char use_r
temp_reg = I386_REG_ECX;
break;
default:
- rts_error(VARLSTCNT(1) ERR_UNIMPLOP);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP);
break;
}
code_buf[code_idx++] = I386_INS_CALL_Jv;
@@ -1032,7 +1031,7 @@ void emit_trip(generic_op op, oprtype *opr, bool val_output, unsigned char use_r
}
break;
default:
- rts_error(VARLSTCNT(1) ERR_UNIMPLOP);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP);
break;
}
break;
@@ -1146,7 +1145,7 @@ void emit_trip(generic_op op, oprtype *opr, bool val_output, unsigned char use_r
emit_base_offset(use_reg, base_reg, offset);
break;
default:
- rts_error(VARLSTCNT(1) ERR_UNIMPLOP);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP);
break;
}
break;
@@ -1175,9 +1174,6 @@ void emit_xfer(short xfer)
void emit_op_base_offset(generic_op op, short base_reg, int offset, short use_reg)
{
-
- error_def (ERR_UNIMPLOP);
-
switch (op)
{
case CLEAR:
@@ -1221,7 +1217,7 @@ void emit_op_base_offset(generic_op op, short base_reg, int offset, short use_re
code_buf[code_idx++] = 0;
break;
default:
- rts_error(VARLSTCNT(1) ERR_UNIMPLOP);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP);
break;
}
}
@@ -1271,8 +1267,6 @@ void emit_base_offset (short reg_opcode, short base_reg, int4 offset)
void emit_op_alit (generic_op op, unsigned char use_reg)
{
- error_def (ERR_UNIMPLOP);
-
switch (op)
{
case LOAD_ADDRESS:
@@ -1289,7 +1283,7 @@ void emit_op_alit (generic_op op, unsigned char use_reg)
code_buf[code_idx++] = I386_INS_PUSH_Iv;
break;
default:
- rts_error(VARLSTCNT(1) ERR_UNIMPLOP);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP);
break;
}
}
diff --git a/sr_i386/merrors_ansi.h b/sr_i386/merrors_ansi.h
index faa0fe7..38cc6a1 100644
--- a/sr_i386/merrors_ansi.h
+++ b/sr_i386/merrors_ansi.h
@@ -193,7 +193,7 @@ const static readonly int error_ansi[] = {
5, /* TEXTARG */
0, /* TMPSTOREMAX */
0, /* VIEWCMD */
- 12, /* TXTNEGLIN */
+ 0, /* JNI */
0, /* TXTSRCFMT */
0, /* UIDMSG */
0, /* UIDSND */
@@ -202,9 +202,9 @@ const static readonly int error_ansi[] = {
39, /* VAREXPECTED */
0, /* VARRECBLKSZ */
0, /* MAXARGCNT */
- 0, /* WCFAIL */
+ 0, /* GTMSECSHRSEMGET */
0, /* VIEWARGCNT */
- 0, /* XKILLCNTEXC */
+ 0, /* GTMSECSHRDMNSTARTED */
0, /* ZATTACHERR */
0, /* ZDATEFMT */
0, /* ZEDFILSPEC */
@@ -271,14 +271,14 @@ const static readonly int error_ansi[] = {
21, /* MULTFORMPARM */
16, /* QUITARGUSE */
0, /* NAMEEXPECTED */
- 11, /* UNUSEDMSG438 */
+ 11, /* FALLINTOFLST */
16, /* NOTEXTRINSIC */
- 11, /* UNUSEDMSG440 */
+ 0, /* GTMSECSHRREMSEMFAIL */
20, /* FMLLSTMISSING */
58, /* ACTLSTTOOLONG */
0, /* ACTOFFSET */
0, /* MAXACTARG */
- 0, /* GTMDUMPFAIL */
+ 0, /* GTMSECSHRREMSEM */
0, /* JNLTMQUAL2 */
0, /* GDINVALID */
0, /* ASSERT */
@@ -422,13 +422,13 @@ const static readonly int error_ansi[] = {
0, /* BEGINST */
0, /* INVMVXSZ */
0, /* JNLWRTNOWWRTR */
- 0, /* MUPGDERR */
+ 0, /* GTMSECSHRSHMCONCPROC */
0, /* JNLINVALLOC */
0, /* JNLINVEXT */
0, /* MUPCLIERR */
0, /* JNLTMQUAL4 */
- 0, /* UNUSEDMSG594 */
- 0, /* UNUSEDMSG595 */
+ 0, /* GTMSECSHRREMSHM */
+ 0, /* GTMSECSHRREMFILE */
0, /* MUNODBNAME */
0, /* FILECREATE */
0, /* FILENOTCREATE */
@@ -450,7 +450,7 @@ const static readonly int error_ansi[] = {
0, /* WCWRNNOTCHG */
0, /* ZCWRONGDESC */
0, /* MUTNWARN */
- 0, /* JNLNAMLEN */
+ 0, /* GTMSECSHRUPDDBHDR */
0, /* LCKSTIMOUT */
0, /* CTLMNEMAXLEN */
0, /* CTLMNEXPECTED */
@@ -586,14 +586,14 @@ const static readonly int error_ansi[] = {
0, /* GTMSECSHR */
0, /* GTMSECSHRSRVFID */
0, /* GTMSECSHRSRVFIL */
- 0, /* SOCKACTNA */
+ 0, /* FREEBLKSLOW */
0, /* PROTNOTSUP */
0, /* DELIMSIZNA */
0, /* INVCTLMNE */
0, /* SOCKLISTEN */
0, /* LQLENGTHNA */
0, /* ADDRTOOLONG */
- 76, /* UNUSEDMSG760 */
+ 0, /* GTMSECSHRGETSEMFAIL */
0, /* CPBEYALLOC */
0, /* DBRDONLY */
0, /* DUPTN */
@@ -614,7 +614,7 @@ const static readonly int error_ansi[] = {
0, /* NOFORKCORE */
0, /* JNLREAD */
0, /* JNLMINALIGN */
- 0, /* JNLDSKALIGN */
+ 0, /* UNUSEDMSG781 */
0, /* JNLPOOLSETUP */
0, /* JNLSTATEOFF */
0, /* RECVPOOLSETUP */
@@ -677,7 +677,7 @@ const static readonly int error_ansi[] = {
0, /* BUFFLUFAILED */
0, /* MUQUALINCOMP */
0, /* DISTPATHMAX */
- 0, /* MAXTRACEHEIGHT */
+ 0, /* UNUSEDMSG844 */
0, /* IMAGENAME */
0, /* GTMSECSHRPERM */
0, /* GTMDISTUNDEF */
@@ -783,7 +783,7 @@ const static readonly int error_ansi[] = {
0, /* DBMBPFRINT */
0, /* DBMAXKEYEXC */
0, /* DBMXRSEXCMIN */
- 0, /* DBMAXRSEXBL */
+ 0, /* UNUSEDMSG950 */
0, /* DBREADBM */
0, /* DBCOMPTOOLRG */
0, /* DBVERPERFWARN2 */
@@ -805,7 +805,7 @@ const static readonly int error_ansi[] = {
0, /* SEMWT2LONG */
0, /* REPLINSTOPEN */
0, /* REPLINSTCLOSE */
- 0, /* JNLNOTFOUND */
+ 0, /* UNUSEDMSG972 */
0, /* DBCRERR8 */
0, /* NUMPROCESSORS */
0, /* DBADDRANGE8 */
@@ -822,16 +822,16 @@ const static readonly int error_ansi[] = {
0, /* RENAMEFAIL */
0, /* FILERENAME */
0, /* JNLBUFINFO */
- 0, /* JNLQIOLOCKED */
- 0, /* JNLEOFPREZERO */
+ 0, /* UNUSEDMSG989 */
+ 0, /* UNUSEDMSG990 */
0, /* TPNOTACID */
0, /* JNLSETDATA2LONG */
0, /* JNLNEWREC */
0, /* REPLFTOKSEM */
- 0, /* GETCWD */
+ 0, /* UNUSEDMSG995 */
0, /* EXTRIOERR */
0, /* EXTRCLOSEERR */
- 0, /* TRUNCATE */
+ 0, /* UNUSEDMSG998 */
0, /* REPLEXITERR */
0, /* MUDESTROYSUC */
0, /* DBRNDWN */
@@ -912,7 +912,7 @@ const static readonly int error_ansi[] = {
0, /* SYSTEMVALUE */
0, /* SIZENOTVALID4 */
0, /* STRNOTVALID */
- 0, /* RECNOCREJNL */
+ 0, /* UNUSEDMSG1079 */
0, /* ERRWETRAP */
0, /* TRACINGON */
0, /* CITABENV */
@@ -940,9 +940,9 @@ const static readonly int error_ansi[] = {
0, /* ZDIROUTOFSYNC */
0, /* GBLNOEXIST */
0, /* MAXBTLEVEL */
- 0, /* JNLSTRESTFL */
+ 0, /* UNUSEDMSG1107 */
0, /* JNLALIGNSZCHG */
- 0, /* MAXTRACELEVEL */
+ 0, /* UNUSEDMSG1109 */
0, /* GVFAILCORE */
0, /* DBCDBNOCERTIFY */
0, /* DBFRZRESETSUC */
@@ -1187,7 +1187,7 @@ const static readonly int error_ansi[] = {
0, /* TRIGTLVLCHNG */
0, /* TRIGNAMEUNIQ */
0, /* ZTRIGINVACT */
- 0, /* UNUSEDMSG1354 */
+ 0, /* INDRCOMPFAIL */
0, /* QUITALSINV */
0, /* PROCTERM */
0, /* SRCLNNTDSP */
@@ -1200,10 +1200,10 @@ const static readonly int error_ansi[] = {
0, /* SSATTACHSHM */
0, /* TRIGDEFNOSYNC */
0, /* TRESTMAX */
- 0, /* TPLOCKRESTMAX */
+ 0, /* UNUSEDMSG1367 */
0, /* GBLEXPECTED */
0, /* GVZTRIGFAIL */
- 0, /* UNUSEDMSG1370 */
+ 0, /* MUUSERLBK */
0, /* SETINSETTRIGONLY */
0, /* DZTRIGINTRIG */
0, /* SECNODZTRIGINTP */
@@ -1215,7 +1215,7 @@ const static readonly int error_ansi[] = {
0, /* REPLXENDIANFAIL */
0, /* ZGOTOINVLVL2 */
0, /* GTMSECSHRCHDIRF */
- 0, /* UNUSEDMSG1382 */
+ 0, /* JNLORDBFLU */
0, /* ZCCLNUPRTNMISNG */
0, /* ZCINVALIDKEYWORD */
0, /* REPLNOMULTILINETRG */
@@ -1247,7 +1247,7 @@ const static readonly int error_ansi[] = {
0, /* NOSUPPLSUPPL */
0, /* REPL2OLD */
0, /* EXTRFILEXISTS */
- 0, /* UNUSEDMSG1414 */
+ 0, /* MUUSERECOV */
0, /* SECNOTSUPPLEMENTARY */
0, /* SUPRCVRNEEDSSUPSRC */
0, /* UNUSEDMSG1417 */
@@ -1270,7 +1270,7 @@ const static readonly int error_ansi[] = {
0, /* ORLBKNOV4BLK */
0, /* DBROLLEDBACK */
0, /* DSEWCREINIT */
- 0, /* UNUSEDMSG1437 */
+ 0, /* MURNDWNOVRD */
0, /* REPLONLNRLBK */
0, /* SRVLCKWT2LNG */
0, /* IGNBMPMRKFREE */
@@ -1340,4 +1340,25 @@ const static readonly int error_ansi[] = {
0, /* TPRESTNESTERR */
0, /* JNLFILRDOPN */
0, /* SEQNUMSEARCHTIMEOUT */
+ 0, /* FTOKKEY */
+ 0, /* SEMID */
+ 0, /* JNLQIOSALVAGE */
+ 0, /* FAKENOSPCLEARED */
+ 0, /* MMFILETOOLARGE */
+ 0, /* BADZPEEKARG */
+ 0, /* BADZPEEKRANGE */
+ 0, /* BADZPEEKFMT */
+ 0, /* DBMBMINCFREFIXED */
+ 0, /* NULLENTRYREF */
+ 0, /* ZPEEKNORPLINFO */
+ 0, /* MMREGNOACCESS */
+ 0, /* MALLOCMAXUNIX */
+ 0, /* MALLOCMAXVMS */
+ 0, /* HOSTCONFLICT */
+ 0, /* GETADDRINFO */
+ 0, /* GETNAMEINFO */
+ 0, /* SOCKBIND */
+ 0, /* INSTFRZDEFER */
+ 0, /* REGOPENRETRY */
+ 0, /* REGOPENFAIL */
};
diff --git a/sr_i386/merrors_ctl.c b/sr_i386/merrors_ctl.c
index 10346ac..a409df6 100644
--- a/sr_i386/merrors_ctl.c
+++ b/sr_i386/merrors_ctl.c
@@ -195,7 +195,7 @@ LITDEF err_msg merrors[] = {
"TEXTARG", "Invalid argument to $TEXT function", 0,
"TMPSTOREMAX", "Maximum space for temporary values exceeded", 0,
"VIEWCMD", "View parameter is not valid with VIEW command", 0,
- "TXTNEGLIN", "A line prior to line number zero was referenced in $TEXT", 0,
+ "JNI", "!AD", 2,
"TXTSRCFMT", "$TEXT encountered an invalid source program file format", 0,
"UIDMSG", "Unidentified message received", 0,
"UIDSND", "Unidentified sender PID", 0,
@@ -204,9 +204,9 @@ LITDEF err_msg merrors[] = {
"VAREXPECTED", "Variable expected in this context", 0,
"VARRECBLKSZ", "Blocksize must be at least record size + 4 bytes", 0,
"MAXARGCNT", "Maximum number of arguments !UL exceeded", 1,
- "WCFAIL", "The database cache is corrupt", 0,
+ "GTMSECSHRSEMGET", "semget error errno = !UL", 1,
"VIEWARGCNT", "View parameter !AD has inappropriate number of subparameters", 2,
- "XKILLCNTEXC", "Maximum number of arguments (!UL) to exclusive kill exceeded", 1,
+ "GTMSECSHRDMNSTARTED", "gtmsecshr daemon started (key: 0x!XL) for version !AD from !AD", 5,
"ZATTACHERR", "Error attaching to \"!AD\"", 2,
"ZDATEFMT", "$ZDATE format string contains invalid character", 0,
"ZEDFILSPEC", "Illegal ZEDIT file specification: !AD", 2,
@@ -273,14 +273,14 @@ LITDEF err_msg merrors[] = {
"MULTFORMPARM", "This formal parameter is multiply defined", 0,
"QUITARGUSE", "Quit cannot take an argument in this context", 0,
"NAMEEXPECTED", "A local variable name is expected in this context", 0,
- "UNUSEDMSG438", "ACTLSTEXP: Last used in V5.4-002B", 0,
+ "FALLINTOFLST", "Fall-through to a label with formallist is not allowed", 0,
"NOTEXTRINSIC", "Quit does not return to an extrinsic function: argument not allowed", 0,
- "UNUSEDMSG440", "FMLLSTPRESENT: Last used in V5.4-002B", 0,
+ "GTMSECSHRREMSEMFAIL", "error removing semaphore errno = !UL", 1,
"FMLLSTMISSING", "The formal list is absent from a label called with an actual list: !AD", 2,
"ACTLSTTOOLONG", "More actual parameters than formal parameters: !AD", 2,
"ACTOFFSET", "Actuallist not allowed with offset", 0,
"MAXACTARG", "Maximum number of actual arguments exceeded", 0,
- "GTMDUMPFAIL", "Could not create DUMP FILE", 0,
+ "GTMSECSHRREMSEM", "[client pid !UL] Semaphore (!UL) removed", 2,
"JNLTMQUAL2", "Time qualifier LOOKBACK_TIME=\"!AZ\" is later than SINCE_TIME=\"!AZ\"", 2,
"GDINVALID", "Unrecognized Global Directory file format: !AD, expected label: !AD, found: !AD", 6,
"ASSERT", "Assert failed in !AD line !UL for expression (!AD)", 5,
@@ -424,13 +424,13 @@ LITDEF err_msg merrors[] = {
"BEGINST", "Beginning LOAD at record number: !UL", 1,
"INVMVXSZ", "Invalid block size for GOQ load format", 0,
"JNLWRTNOWWRTR", "Journal writer attempting another write", 0,
- "MUPGDERR", "Command aborted due to global directory errors", 0,
+ "GTMSECSHRSHMCONCPROC", "More than one process attached to Shared memory segment (!UL) not removed (!UL)", 2,
"JNLINVALLOC", "Journal file allocation !UL is not within the valid range of !UL to !UL. Journal file not created.", 3,
"JNLINVEXT", "Journal file extension !UL is greater than the maximum allowed size of !UL. Journal file not created.", 2,
"MUPCLIERR", "Action not taken due to CLI errors", 0,
"JNLTMQUAL4", "Time qualifier BEFORE_TIME=\"!AZ\" is less than AFTER_TIME=\"!AZ\"", 2,
- "UNUSEDMSG594", "JNLBUFFTOOLG Last used in V5.5-000", 0,
- "UNUSEDMSG595", "JNLBUFFTOOSM Last used in V5.5-000", 0,
+ "GTMSECSHRREMSHM", "[client pid !UL] Shared memory segment (!UL) removed, nattch = !UL", 3,
+ "GTMSECSHRREMFILE", "[client pid !UL] File (!AD) removed", 3,
"MUNODBNAME", "A database name or the region qualifier must be specified", 0,
"FILECREATE", "!AD file !AD created", 4,
"FILENOTCREATE", "!AD file !AD not created", 4,
@@ -452,7 +452,7 @@ LITDEF err_msg merrors[] = {
"WCWRNNOTCHG", "Not all specified database files were changed", 0,
"ZCWRONGDESC", "A string longer than 65535 is passed via 32-bit descriptor", 0,
"MUTNWARN", "Database file !AD has 0x!16 at XQ more transactions to go before reaching the transaction number limit (0x!16 at XQ). Renew database with MUPIP INTEG TN_RESET", 4,
- "JNLNAMLEN", "Journal file name !AD: for database file !AD exceeds maximum length of !UL", 5,
+ "GTMSECSHRUPDDBHDR", "[client pid !UL] database fileheader (!AD) updated !AD", 5,
"LCKSTIMOUT", "DAL timed lock request expired", 0,
"CTLMNEMAXLEN", "The maximum length of a control mnemonic has been exceeded", 0,
"CTLMNEXPECTED", "Control mnemonic is expected in this context", 0,
@@ -588,14 +588,14 @@ LITDEF err_msg merrors[] = {
"GTMSECSHR", "!UL : Error during gtmsecshr operation", 1,
"GTMSECSHRSRVFID", "!AD: !UL - Attempt to service request failed.!/ client id: !UL, mesg type: !UL, mesg data: !UL", 6,
"GTMSECSHRSRVFIL", "!AD: !UL - Attempt to service request failed.!/ client id: !UL, mesg type: !UL!/file: !AD", 7,
- "SOCKACTNA", "Action not appropriate for current socket", 0,
+ "FREEBLKSLOW", "Only !UL free blocks left out of !UL total blocks for !AD", 4,
"PROTNOTSUP", "Protocol !AD not supported", 2,
"DELIMSIZNA", "Delimiter size is not appropriate", 0,
"INVCTLMNE", "Invalid control mnemonics", 0,
"SOCKLISTEN", "Error listening on a socket", 0,
"LQLENGTHNA", "Listening queue length !UL not appropriate. Must be between 1 and 5.", 1,
"ADDRTOOLONG", "Socket address !AD of length !UL is longer than the maximum permissible length !UL", 4,
- "UNUSEDMSG760", "LSNCONNOTCMP Last used in V5.4-002A", 0,
+ "GTMSECSHRGETSEMFAIL", "error getting semaphore errno = !UL", 1,
"CPBEYALLOC", "Attempt to copy beyond the allocated buffer", 0,
"DBRDONLY", "Database file !AD read only", 2,
"DUPTN", "Duplicate transaction found [TN = 0x!16 at XQ] at offset 0x!XL in journal file !AD", 4,
@@ -616,7 +616,7 @@ LITDEF err_msg merrors[] = {
"NOFORKCORE", "Unable to fork off process to create core. Core creation postponed.", 0,
"JNLREAD", "Error reading from journal file !AD at offset [0x!XL]", 3,
"JNLMINALIGN", "Journal Record Alignment !UL is less than the minimum value of !UL", 2,
- "JNLDSKALIGN", "Journal Record Alignment !UL is not a multiple of 512", 1,
+ "UNUSEDMSG781", "JNLDSKALIGN : Last used in V4.3-000", 0,
"JNLPOOLSETUP", "Journal Pool setup error", 0,
"JNLSTATEOFF", "ROLLBACK or RECOVER BACKWARD cannot proceed as database file !AD does not have journaling ENABLED and ON", 2,
"RECVPOOLSETUP", "Receive Pool setup error", 0,
@@ -679,7 +679,7 @@ LITDEF err_msg merrors[] = {
"BUFFLUFAILED", "Error flushing buffers from !AD for database file !AD", 4,
"MUQUALINCOMP", "Incompatible qualifiers - FILE and REGION", 0,
"DISTPATHMAX", "$gtm_dist path is greater than maximum (!UL)", 1,
- "MAXTRACEHEIGHT", "The maximum trace tree height (!UL) has been exceeded. The trace information will be incomplete.", 1,
+ "UNUSEDMSG844", "MAXTRACEHEIGHT last used in V5.4-002", 0,
"IMAGENAME", "The executing module name should be !AD instead of !AD", 4,
"GTMSECSHRPERM", "The gtmsecshr module in $gtm_dist does not have the correct permission and uid", 0,
"GTMDISTUNDEF", "Environment variable $gtm_dist is not defined", 0,
@@ -785,7 +785,7 @@ LITDEF err_msg merrors[] = {
"DBMBPFRINT", "!AD Master bit map shows this map has space, agreeing with MUPIP INTEG", 2,
"DBMAXKEYEXC", "!AD Maximum key size for database exceeds design maximum", 2,
"DBMXRSEXCMIN", "!AD Maximum record size for database is less than the design minimum", 2,
- "DBMAXRSEXBL", "!AD Maximum record size for database exceeds what the block size can support", 2,
+ "UNUSEDMSG950", "DBMAXRSEXBL : Last used in V5.5-000", 0,
"DBREADBM", "!AD Read error on bitmap", 2,
"DBCOMPTOOLRG", "!AD Record has too large compression count", 2,
"DBVERPERFWARN2", "Peformance warning: Database !AD is not fully upgraded. Run MUPIP REORG UPGRADE for best overall performance", 2,
@@ -807,7 +807,7 @@ LITDEF err_msg merrors[] = {
"SEMWT2LONG", "Process !UL waited !UL second(s) for the !AD lock for region !AD, lock held by pid !UL", 7,
"REPLINSTOPEN", "Error opening replication instance file !AD", 2,
"REPLINSTCLOSE", "Error closing replication instance file !AD", 2,
- "JNLNOTFOUND", "File !AD does not exist -- possibly moved or deleted", 2,
+ "UNUSEDMSG972", "JNLNOTFOUND : Last used in V4.4-000", 0,
"DBCRERR8", "Database file !AD, cr location 0x!XJ blk = 0x!XL error: !AD was 0x!16 at XQ, expecting 0x!16 at XQ -- called from module !AD at line !UL", 11,
"NUMPROCESSORS", "Could not determine number of processors", 0,
"DBADDRANGE8", "Database file !AD, element location 0x!XJ: blk = 0x!XL: control 0x!16 at XQ was outside !AD range 0x!16 at XQ to 0x!16 at XQ", 9,
@@ -824,16 +824,16 @@ LITDEF err_msg merrors[] = {
"RENAMEFAIL", "Rename of file !AD to !AD failed", 4,
"FILERENAME", "File !AD is renamed to !AD", 4,
"JNLBUFINFO", "Pid 0x!XL!/ dsk 0x!XL free 0x!XL bytcnt 0x!XL io_in_prog 0x!XL fsync_in_prog 0x!XL!/ dskaddr 0x!XL freeaddr 0x!XL qiocnt 0x!XL now_writer 0x!XL fsync_pid 0x!XL!/filesize 0x!XL cycle 0x!XL errcnt 0x!XL wrtsize 0x!XL fsync_dskaddr 0x!XL", 16,
- "JNLQIOLOCKED", "Error obtaining io_in_prog lock on jnl-file !AD", 2,
- "JNLEOFPREZERO", "Error while zeroing jnl-file !AD", 2,
+ "UNUSEDMSG989", "JNLQIOLOCKED : Last used in V4.4-000", 0,
+ "UNUSEDMSG990", "JNLEOFPREZERO : Last used in V4.4-000", 0,
"TPNOTACID", "!AD at !AD in a final TP retry violates ACID properties of a TRANSACTION; indefinite RESTARTs may occur !AD !AD", 8,
"JNLSETDATA2LONG", "SET journal record has data of length !UL. Target system cannot handle data more than !UL bytes.", 2,
"JNLNEWREC", "Target system cannot recognize journal record of type !UL, last recognized type is !UL", 2,
"REPLFTOKSEM", "Error with replication semaphores for instance file !AD", 2,
- "GETCWD", "Error getting current working directory for file !AD", 2,
+ "UNUSEDMSG995", "GETCWD : Last used before V4.0-001E", 0,
"EXTRIOERR", "Error writing extract file !AD", 2,
"EXTRCLOSEERR", "Error closing extract file !AD", 2,
- "TRUNCATE", "Error while truncating jnl-file !AD to length !UL", 3,
+ "UNUSEDMSG998", "TRUNCATE : Last used in V4.3-001F", 0,
"REPLEXITERR", "Replication process encountered an error while exiting", 0,
"MUDESTROYSUC", "Global section (!AD) corresponding to file !AD successfully destroyed", 4,
"DBRNDWN", "Error during global database rundown for region !AD.!/Notify those responsible for proper database operation.", 2,
@@ -846,7 +846,7 @@ LITDEF err_msg merrors[] = {
"TCSETATTR", "Error while setting terminal attributes on file descriptor !UL", 1,
"IOWRITERR", "IO Write by pid 0x!XL to blk 0x!XL of database file !AD failed. Pid 0x!XL retrying the IO.", 5,
"REPLINSTWRITE", "Error writing [0x!XL] bytes at offset [0x!16 at XQ] in replication instance file !AD", 4,
- "DBBADFREEBLKCTR", "Database !AD free blocks counter in file header: 0x!XL is incorrect, should be 0x!XL. Auto-corrected.", 4,
+ "DBBADFREEBLKCTR", "Database !AD free blocks counter in file header: 0x!XL appears incorrect, should be 0x!XL. Auto-corrected.", 4,
"REQ2RESUME", "Request to resume suspended processing received from process !UL owned by userid !UL", 2,
"TIMERHANDLER", "Incorrect SIGALRM handler (0x!XJ) found by !AD", 3,
"FREEMEMORY", "Error occurred freeing memory from 0x!XJ", 1,
@@ -914,7 +914,7 @@ LITDEF err_msg merrors[] = {
"SYSTEMVALUE", "Invalid value for $SYSTEM (!AD)", 2,
"SIZENOTVALID4", "Size (in bytes) must be either 1, 2, or 4", 0,
"STRNOTVALID", "Error: cannot convert !AD value to valid value", 2,
- "RECNOCREJNL", "Recover could not create new journal file !AD", 2,
+ "UNUSEDMSG1079", "RECNOCREJNL : Last used in V4.3-001F", 0,
"ERRWETRAP", "Error while processing $ETRAP", 0,
"TRACINGON", "Tracing already turned on", 0,
"CITABENV", "Environment variable for call-in table !AD not set", 2,
@@ -942,9 +942,9 @@ LITDEF err_msg merrors[] = {
"ZDIROUTOFSYNC", "$ZDIRECTORY !AD is not the same as its cached value !AD", 4,
"GBLNOEXIST", "Global !AD no longer exists", 2,
"MAXBTLEVEL", "Global !AD reached maximum level", 2,
- "JNLSTRESTFL", "Failed to restore journaling state for database !AD", 2,
+ "UNUSEDMSG1107", "JNLSTRESTFL : found no evidence it ever was used in a production release", 0,
"JNLALIGNSZCHG", "Journal ALIGNSIZE is rounded up to !UL blocks (closest next higher power of two)", 1,
- "MAXTRACELEVEL", "The maximum traceable level of !UL has been exceeded. The frame information will not be maintained.", 1,
+ "UNUSEDMSG1109", "MAXTRACELEVEL : last used in V5.4-002B", 0,
"GVFAILCORE", "A core file is being created for later analysis if necessary", 0,
"DBCDBNOCERTIFY", "Database !AD HAS NOT been certified due to the preceding errors - rerun DBCERTIFY SCAN", 2,
"DBFRZRESETSUC", "Freeze released successfully on database file !AD", 2,
@@ -1189,7 +1189,7 @@ LITDEF err_msg merrors[] = {
"TRIGTLVLCHNG", "Detected a net transaction level ($TLEVEL) change during trigger !AD. Transaction level must be the same at exit as when the trigger started", 2,
"TRIGNAMEUNIQ", "Unable to make trigger name !AD unique beyond !UL versions already loaded", 3,
"ZTRIGINVACT", "Missing or invalid parameter in position !UL given to $ZTRIGGER()", 1,
- "UNUSEDMSG1354", "ZTRIGNOTP : Last used in V5.4-001", 0,
+ "INDRCOMPFAIL", "Compilation of indirection failed", 0,
"QUITALSINV", "QUIT * return when the extrinsic was not invoked with SET *", 0,
"PROCTERM", "!AD process termination due to !AD (return code !UL) from !AD", 7,
"SRCLNNTDSP", "Source lines exceeding !UL character width are not displayed", 1,
@@ -1202,10 +1202,10 @@ 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,
- "TPLOCKRESTMAX", "Transaction restarts due to unavailability of locks not allowed in a final TP retry more than !UL times", 1,
+ "UNUSEDMSG1367", "TPLOCKRESTMAX : Last used in V5.5-000", 0,
"GBLEXPECTED", "Global variable reference expected in this context", 0,
"GVZTRIGFAIL", "ZTRIGGER of a global variable failed. Failure code: !AD.", 2,
- "UNUSEDMSG1370", "ONLYLDTRIG: Last used in V5.4-001", 0,
+ "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,
@@ -1217,7 +1217,7 @@ LITDEF err_msg merrors[] = {
"REPLXENDIANFAIL", "!AD side encountered error while doing endian conversion at journal sequence number 0x!16 at XQ", 3,
"ZGOTOINVLVL2", "ZGOTO 0:entryref is not valid on VMS (UNLINK is a UNIX only feature)", 0,
"GTMSECSHRCHDIRF", "gtmsecshr unable to chdir to its temporary directory (!AD)", 2,
- "UNUSEDMSG1382", "FORCTRLINDX: Only used in V5.4-002", 0,
+ "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,
@@ -1249,7 +1249,7 @@ LITDEF err_msg merrors[] = {
"NOSUPPLSUPPL", "Instance !AD is configured to perform local updates so it cannot receive from Supplementary Instance !AD", 4,
"REPL2OLD", "Instance !AD uses a GT.M version that does not support connection with the current version on instance !AD", 4,
"EXTRFILEXISTS", "Error opening output file: !AD -- File exists", 2,
- "UNUSEDMSG1414", "!AD : An error encountered with the shared object : !AZ", 3,
+ "MUUSERECOV", "Abnormal shutdown of journaled database !AD detected", 2,
"SECNOTSUPPLEMENTARY", "!AD is a Supplementary Instance and so cannot act as a source to non-Supplementary Instance !AD ", 4,
"SUPRCVRNEEDSSUPSRC", "Instance !AD is not configured to perform local updates so it cannot act as a receiver for non-Supplementary Instance !AD", 4,
"UNUSEDMSG1417", "SYNCTOSAMETYPE: Never used before so slot free for reuse", 0,
@@ -1272,7 +1272,7 @@ LITDEF err_msg merrors[] = {
"ORLBKNOV4BLK", "Region !AD (!AD) has V4 format blocks. Database upgrade required. ONLINE ROLLBACK cannot continue", 4,
"DBROLLEDBACK", "Concurrent ONLINE ROLLBACK detected on one or more regions. The current operation is no longer valid", 0,
"DSEWCREINIT", "Database cache reinitialized by DSE for region !AD", 2,
- "UNUSEDMSG1437", "A total of !UL process(es) skipped database rundown due to a concurrent ONLINE ROLLBACK", 1,
+ "MURNDWNOVRD", "OVERRIDE qualifier used with MUPIP RUNDOWN on database file !AD", 2,
"REPLONLNRLBK", "ONLINE ROLLBACK detected. Starting afresh", 0,
"SRVLCKWT2LNG", "PID !UL is holding the source server lock. Waited for !UL minute(s). Now exiting", 2,
"IGNBMPMRKFREE", "Ignoring bitmap free-up operation for region !AD (!AD) due to concurrent ONLINE ROLLBACK", 4,
@@ -1342,6 +1342,27 @@ LITDEF err_msg merrors[] = {
"TPRESTNESTERR", "TP restart signaled while handing error - treated as nested error - Use TROLLBACK in error handler to avoid this", 0,
"JNLFILRDOPN", "Error opening journal file !AD for read for database file !AD", 4,
"SEQNUMSEARCHTIMEOUT", "Timed out trying to find sequence number !@ZQ [0x!16 at XQ] in Journal File(s). See above messages for details. Source server exiting", 2,
+ "FTOKKEY", "FTOK key 0x!XL", 1,
+ "SEMID", "Semaphore id !UL", 1,
+ "JNLQIOSALVAGE", "Journal IO lock salvaged", 0,
+ "FAKENOSPCLEARED", "DEBUG: All fake ENOSPC flags were cleared !UL heartbeats ago", 1,
+ "MMFILETOOLARGE", "Size of !AD region (!AD) is larger than maximum size supported for memory mapped I/O on this platform", 4,
+ "BADZPEEKARG", "Missing, invalid or surplus !AD parameter for $ZPEEK()", 2,
+ "BADZPEEKRANGE", "Access exception raised in memory range given to $ZPEEK()", 0,
+ "BADZPEEKFMT", "$ZPEEK() value length inappropriate for selected format", 0,
+ "DBMBMINCFREFIXED", "Master bitmap incorrectly marks local bitmap 0x!XL as free. Auto-corrected", 1,
+ "NULLENTRYREF", "JOB command did not specify entryref", 0,
+ "ZPEEKNORPLINFO", "$ZPEEK() unable to access requested replication structure", 0,
+ "MMREGNOACCESS", "Region !AD (!AD) is no longer accessible. See prior error messages in the operator and application error logs", 4,
+ "MALLOCMAXUNIX", "Exceeded maximum allocation defined by $gtm_max_storalloc", 0,
+ "MALLOCMAXVMS", "Exceeded maximum allocation defined by GTM_MAX_STORALLOC", 0,
+ "HOSTCONFLICT", "Host !AD could not open database file !AD because it is marked as already open on node !AD", 6,
+ "GETADDRINFO", "Error in getting address info", 0,
+ "GETNAMEINFO", "Error in getting name info", 0,
+ "SOCKBIND", "Error in binding TCP socket", 0,
+ "INSTFRZDEFER", "Instance Freeze initiated by !AD error on region !AD deferred due to critical resource conflict", 4,
+ "REGOPENRETRY", "Attempt to open region !AD (!AD) using startup shortcut failed due to conflicting database shutdown. Retrying...", 4,
+ "REGOPENFAIL", "Failed to open region !AD (!AD) due to conflicting database shutdown activity", 4,
};
LITDEF int ERR_ACK = 150372361;
@@ -1526,7 +1547,7 @@ LITDEF int ERR_TERMASTQUOTA = 150373786;
LITDEF int ERR_TEXTARG = 150373794;
LITDEF int ERR_TMPSTOREMAX = 150373802;
LITDEF int ERR_VIEWCMD = 150373810;
-LITDEF int ERR_TXTNEGLIN = 150373818;
+LITDEF int ERR_JNI = 150373818;
LITDEF int ERR_TXTSRCFMT = 150373826;
LITDEF int ERR_UIDMSG = 150373834;
LITDEF int ERR_UIDSND = 150373842;
@@ -1535,9 +1556,9 @@ LITDEF int ERR_UNIMPLOP = 150373858;
LITDEF int ERR_VAREXPECTED = 150373866;
LITDEF int ERR_VARRECBLKSZ = 150373874;
LITDEF int ERR_MAXARGCNT = 150373882;
-LITDEF int ERR_WCFAIL = 150373890;
+LITDEF int ERR_GTMSECSHRSEMGET = 150373890;
LITDEF int ERR_VIEWARGCNT = 150373898;
-LITDEF int ERR_XKILLCNTEXC = 150373906;
+LITDEF int ERR_GTMSECSHRDMNSTARTED = 150373907;
LITDEF int ERR_ZATTACHERR = 150373914;
LITDEF int ERR_ZDATEFMT = 150373922;
LITDEF int ERR_ZEDFILSPEC = 150373930;
@@ -1592,7 +1613,7 @@ LITDEF int ERR_GVRUNDOWN = 150374314;
LITDEF int ERR_LKRUNDOWN = 150374322;
LITDEF int ERR_IORUNDOWN = 150374330;
LITDEF int ERR_FILENOTFND = 150374338;
-LITDEF int ERR_MUFILRNDWNFL = 150374347;
+LITDEF int ERR_MUFILRNDWNFL = 150374346;
LITDEF int ERR_JNLTMQUAL1 = 150374354;
LITDEF int ERR_FORCEDHALT = 150374364;
LITDEF int ERR_LOADEOF = 150374370;
@@ -1604,14 +1625,14 @@ LITDEF int ERR_GVZPREVFAIL = 150374410;
LITDEF int ERR_MULTFORMPARM = 150374418;
LITDEF int ERR_QUITARGUSE = 150374426;
LITDEF int ERR_NAMEEXPECTED = 150374434;
-LITDEF int ERR_UNUSEDMSG438 = 150374442;
+LITDEF int ERR_FALLINTOFLST = 150374442;
LITDEF int ERR_NOTEXTRINSIC = 150374450;
-LITDEF int ERR_UNUSEDMSG440 = 150374458;
+LITDEF int ERR_GTMSECSHRREMSEMFAIL = 150374458;
LITDEF int ERR_FMLLSTMISSING = 150374466;
LITDEF int ERR_ACTLSTTOOLONG = 150374474;
LITDEF int ERR_ACTOFFSET = 150374482;
LITDEF int ERR_MAXACTARG = 150374490;
-LITDEF int ERR_GTMDUMPFAIL = 150374498;
+LITDEF int ERR_GTMSECSHRREMSEM = 150374498;
LITDEF int ERR_JNLTMQUAL2 = 150374506;
LITDEF int ERR_GDINVALID = 150374514;
LITDEF int ERR_ASSERT = 150374524;
@@ -1755,13 +1776,13 @@ LITDEF int ERR_LDGOQFMT = 150375618;
LITDEF int ERR_BEGINST = 150375627;
LITDEF int ERR_INVMVXSZ = 150375636;
LITDEF int ERR_JNLWRTNOWWRTR = 150375642;
-LITDEF int ERR_MUPGDERR = 150375650;
+LITDEF int ERR_GTMSECSHRSHMCONCPROC = 150375650;
LITDEF int ERR_JNLINVALLOC = 150375656;
LITDEF int ERR_JNLINVEXT = 150375664;
LITDEF int ERR_MUPCLIERR = 150375674;
LITDEF int ERR_JNLTMQUAL4 = 150375682;
-LITDEF int ERR_UNUSEDMSG594 = 150375690;
-LITDEF int ERR_UNUSEDMSG595 = 150375698;
+LITDEF int ERR_GTMSECSHRREMSHM = 150375691;
+LITDEF int ERR_GTMSECSHRREMFILE = 150375699;
LITDEF int ERR_MUNODBNAME = 150375706;
LITDEF int ERR_FILECREATE = 150375715;
LITDEF int ERR_FILENOTCREATE = 150375723;
@@ -1783,7 +1804,7 @@ LITDEF int ERR_WCERRNOTCHG = 150375842;
LITDEF int ERR_WCWRNNOTCHG = 150375848;
LITDEF int ERR_ZCWRONGDESC = 150375858;
LITDEF int ERR_MUTNWARN = 150375864;
-LITDEF int ERR_JNLNAMLEN = 150375874;
+LITDEF int ERR_GTMSECSHRUPDDBHDR = 150375875;
LITDEF int ERR_LCKSTIMOUT = 150375880;
LITDEF int ERR_CTLMNEMAXLEN = 150375890;
LITDEF int ERR_CTLMNEXPECTED = 150375898;
@@ -1919,14 +1940,14 @@ LITDEF int ERR_MUTEXFRCDTERM = 150376928;
LITDEF int ERR_GTMSECSHR = 150376938;
LITDEF int ERR_GTMSECSHRSRVFID = 150376944;
LITDEF int ERR_GTMSECSHRSRVFIL = 150376952;
-LITDEF int ERR_SOCKACTNA = 150376962;
+LITDEF int ERR_FREEBLKSLOW = 150376960;
LITDEF int ERR_PROTNOTSUP = 150376970;
LITDEF int ERR_DELIMSIZNA = 150376978;
LITDEF int ERR_INVCTLMNE = 150376986;
LITDEF int ERR_SOCKLISTEN = 150376994;
LITDEF int ERR_LQLENGTHNA = 150377002;
LITDEF int ERR_ADDRTOOLONG = 150377010;
-LITDEF int ERR_UNUSEDMSG760 = 150377018;
+LITDEF int ERR_GTMSECSHRGETSEMFAIL = 150377018;
LITDEF int ERR_CPBEYALLOC = 150377026;
LITDEF int ERR_DBRDONLY = 150377034;
LITDEF int ERR_DUPTN = 150377040;
@@ -1947,7 +1968,7 @@ LITDEF int ERR_BCKUPBUFLUSH = 150377154;
LITDEF int ERR_NOFORKCORE = 150377160;
LITDEF int ERR_JNLREAD = 150377170;
LITDEF int ERR_JNLMINALIGN = 150377176;
-LITDEF int ERR_JNLDSKALIGN = 150377184;
+LITDEF int ERR_UNUSEDMSG781 = 150377186;
LITDEF int ERR_JNLPOOLSETUP = 150377194;
LITDEF int ERR_JNLSTATEOFF = 150377202;
LITDEF int ERR_RECVPOOLSETUP = 150377210;
@@ -2010,7 +2031,7 @@ LITDEF int ERR_RECSIZENOTEVEN = 150377658;
LITDEF int ERR_BUFFLUFAILED = 150377666;
LITDEF int ERR_MUQUALINCOMP = 150377674;
LITDEF int ERR_DISTPATHMAX = 150377682;
-LITDEF int ERR_MAXTRACEHEIGHT = 150377691;
+LITDEF int ERR_UNUSEDMSG844 = 150377690;
LITDEF int ERR_IMAGENAME = 150377698;
LITDEF int ERR_GTMSECSHRPERM = 150377706;
LITDEF int ERR_GTMDISTUNDEF = 150377714;
@@ -2116,7 +2137,7 @@ LITDEF int ERR_DBMBPFRDLBM = 150378504;
LITDEF int ERR_DBMBPFRINT = 150378512;
LITDEF int ERR_DBMAXKEYEXC = 150378522;
LITDEF int ERR_DBMXRSEXCMIN = 150378530;
-LITDEF int ERR_DBMAXRSEXBL = 150378538;
+LITDEF int ERR_UNUSEDMSG950 = 150378538;
LITDEF int ERR_DBREADBM = 150378546;
LITDEF int ERR_DBCOMPTOOLRG = 150378554;
LITDEF int ERR_DBVERPERFWARN2 = 150378560;
@@ -2138,7 +2159,7 @@ LITDEF int ERR_MUTEXRSRCCLNUP = 150378683;
LITDEF int ERR_SEMWT2LONG = 150378690;
LITDEF int ERR_REPLINSTOPEN = 150378698;
LITDEF int ERR_REPLINSTCLOSE = 150378706;
-LITDEF int ERR_JNLNOTFOUND = 150378715;
+LITDEF int ERR_UNUSEDMSG972 = 150378714;
LITDEF int ERR_DBCRERR8 = 150378723;
LITDEF int ERR_NUMPROCESSORS = 150378728;
LITDEF int ERR_DBADDRANGE8 = 150378739;
@@ -2155,16 +2176,16 @@ LITDEF int ERR_REPLJNLCLOSED = 150378818;
LITDEF int ERR_RENAMEFAIL = 150378824;
LITDEF int ERR_FILERENAME = 150378835;
LITDEF int ERR_JNLBUFINFO = 150378843;
-LITDEF int ERR_JNLQIOLOCKED = 150378850;
-LITDEF int ERR_JNLEOFPREZERO = 150378858;
+LITDEF int ERR_UNUSEDMSG989 = 150378850;
+LITDEF int ERR_UNUSEDMSG990 = 150378858;
LITDEF int ERR_TPNOTACID = 150378867;
LITDEF int ERR_JNLSETDATA2LONG = 150378874;
LITDEF int ERR_JNLNEWREC = 150378882;
LITDEF int ERR_REPLFTOKSEM = 150378890;
-LITDEF int ERR_GETCWD = 150378898;
+LITDEF int ERR_UNUSEDMSG995 = 150378898;
LITDEF int ERR_EXTRIOERR = 150378906;
LITDEF int ERR_EXTRCLOSEERR = 150378914;
-LITDEF int ERR_TRUNCATE = 150378922;
+LITDEF int ERR_UNUSEDMSG998 = 150378922;
LITDEF int ERR_REPLEXITERR = 150378930;
LITDEF int ERR_MUDESTROYSUC = 150378939;
LITDEF int ERR_DBRNDWN = 150378946;
@@ -2177,7 +2198,7 @@ LITDEF int ERR_TCGETATTR = 150378994;
LITDEF int ERR_TCSETATTR = 150379002;
LITDEF int ERR_IOWRITERR = 150379010;
LITDEF int ERR_REPLINSTWRITE = 150379018;
-LITDEF int ERR_DBBADFREEBLKCTR = 150379027;
+LITDEF int ERR_DBBADFREEBLKCTR = 150379024;
LITDEF int ERR_REQ2RESUME = 150379035;
LITDEF int ERR_TIMERHANDLER = 150379040;
LITDEF int ERR_FREEMEMORY = 150379050;
@@ -2185,11 +2206,11 @@ LITDEF int ERR_MUREPLSECDEL = 150379059;
LITDEF int ERR_MUREPLSECNOTDEL = 150379067;
LITDEF int ERR_MUJPOOLRNDWNSUC = 150379075;
LITDEF int ERR_MURPOOLRNDWNSUC = 150379083;
-LITDEF int ERR_MUJPOOLRNDWNFL = 150379091;
-LITDEF int ERR_MURPOOLRNDWNFL = 150379099;
+LITDEF int ERR_MUJPOOLRNDWNFL = 150379090;
+LITDEF int ERR_MURPOOLRNDWNFL = 150379098;
LITDEF int ERR_MUREPLPOOL = 150379107;
LITDEF int ERR_REPLACCSEM = 150379114;
-LITDEF int ERR_JNLFLUSHNOPROG = 150379122;
+LITDEF int ERR_JNLFLUSHNOPROG = 150379120;
LITDEF int ERR_REPLINSTCREATE = 150379130;
LITDEF int ERR_SUSPENDING = 150379139;
LITDEF int ERR_SOCKBFNOTEMPTY = 150379146;
@@ -2245,7 +2266,7 @@ LITDEF int ERR_NOSUBSCRIPT = 150379538;
LITDEF int ERR_SYSTEMVALUE = 150379546;
LITDEF int ERR_SIZENOTVALID4 = 150379554;
LITDEF int ERR_STRNOTVALID = 150379562;
-LITDEF int ERR_RECNOCREJNL = 150379571;
+LITDEF int ERR_UNUSEDMSG1079 = 150379570;
LITDEF int ERR_ERRWETRAP = 150379578;
LITDEF int ERR_TRACINGON = 150379587;
LITDEF int ERR_CITABENV = 150379594;
@@ -2273,9 +2294,9 @@ LITDEF int ERR_INVZDIRFORM = 150379762;
LITDEF int ERR_ZDIROUTOFSYNC = 150379768;
LITDEF int ERR_GBLNOEXIST = 150379779;
LITDEF int ERR_MAXBTLEVEL = 150379786;
-LITDEF int ERR_JNLSTRESTFL = 150379794;
+LITDEF int ERR_UNUSEDMSG1107 = 150379794;
LITDEF int ERR_JNLALIGNSZCHG = 150379803;
-LITDEF int ERR_MAXTRACELEVEL = 150379811;
+LITDEF int ERR_UNUSEDMSG1109 = 150379810;
LITDEF int ERR_GVFAILCORE = 150379818;
LITDEF int ERR_DBCDBNOCERTIFY = 150379826;
LITDEF int ERR_DBFRZRESETSUC = 150379835;
@@ -2520,7 +2541,7 @@ LITDEF int ERR_TRIGTCOMMIT = 150381738;
LITDEF int ERR_TRIGTLVLCHNG = 150381746;
LITDEF int ERR_TRIGNAMEUNIQ = 150381754;
LITDEF int ERR_ZTRIGINVACT = 150381762;
-LITDEF int ERR_UNUSEDMSG1354 = 150381770;
+LITDEF int ERR_INDRCOMPFAIL = 150381770;
LITDEF int ERR_QUITALSINV = 150381778;
LITDEF int ERR_PROCTERM = 150381784;
LITDEF int ERR_SRCLNNTDSP = 150381795;
@@ -2533,10 +2554,10 @@ LITDEF int ERR_TCOMMITDISALLOW = 150381842;
LITDEF int ERR_SSATTACHSHM = 150381850;
LITDEF int ERR_TRIGDEFNOSYNC = 150381856;
LITDEF int ERR_TRESTMAX = 150381866;
-LITDEF int ERR_TPLOCKRESTMAX = 150381874;
+LITDEF int ERR_UNUSEDMSG1367 = 150381874;
LITDEF int ERR_GBLEXPECTED = 150381882;
LITDEF int ERR_GVZTRIGFAIL = 150381890;
-LITDEF int ERR_UNUSEDMSG1370 = 150381898;
+LITDEF int ERR_MUUSERLBK = 150381898;
LITDEF int ERR_SETINSETTRIGONLY = 150381906;
LITDEF int ERR_DZTRIGINTRIG = 150381914;
LITDEF int ERR_SECNODZTRIGINTP = 150381922;
@@ -2548,7 +2569,7 @@ LITDEF int ERR_REPLNOXENDIAN = 150381962;
LITDEF int ERR_REPLXENDIANFAIL = 150381970;
LITDEF int ERR_ZGOTOINVLVL2 = 150381978;
LITDEF int ERR_GTMSECSHRCHDIRF = 150381986;
-LITDEF int ERR_UNUSEDMSG1382 = 150381994;
+LITDEF int ERR_JNLORDBFLU = 150381994;
LITDEF int ERR_ZCCLNUPRTNMISNG = 150382002;
LITDEF int ERR_ZCINVALIDKEYWORD = 150382010;
LITDEF int ERR_REPLNOMULTILINETRG = 150382018;
@@ -2580,7 +2601,7 @@ LITDEF int ERR_NORESYNCUPDATERONLY = 150382218;
LITDEF int ERR_NOSUPPLSUPPL = 150382226;
LITDEF int ERR_REPL2OLD = 150382234;
LITDEF int ERR_EXTRFILEXISTS = 150382242;
-LITDEF int ERR_UNUSEDMSG1414 = 150382250;
+LITDEF int ERR_MUUSERECOV = 150382250;
LITDEF int ERR_SECNOTSUPPLEMENTARY = 150382258;
LITDEF int ERR_SUPRCVRNEEDSSUPSRC = 150382266;
LITDEF int ERR_UNUSEDMSG1417 = 150382275;
@@ -2603,7 +2624,7 @@ LITDEF int ERR_ORLBKFRZOVER = 150382403;
LITDEF int ERR_ORLBKNOV4BLK = 150382410;
LITDEF int ERR_DBROLLEDBACK = 150382418;
LITDEF int ERR_DSEWCREINIT = 150382427;
-LITDEF int ERR_UNUSEDMSG1437 = 150382435;
+LITDEF int ERR_MURNDWNOVRD = 150382435;
LITDEF int ERR_REPLONLNRLBK = 150382442;
LITDEF int ERR_SRVLCKWT2LNG = 150382450;
LITDEF int ERR_IGNBMPMRKFREE = 150382459;
@@ -2654,7 +2675,7 @@ LITDEF int ERR_JNLBUFFDBUPD = 150382808;
LITDEF int ERR_LOCKINCR2HIGH = 150382818;
LITDEF int ERR_LOCKIS = 150382827;
LITDEF int ERR_LDSPANGLOINCMP = 150382834;
-LITDEF int ERR_MUFILRNDWNFL2 = 150382843;
+LITDEF int ERR_MUFILRNDWNFL2 = 150382842;
LITDEF int ERR_MUINSTFROZEN = 150382851;
LITDEF int ERR_MUINSTUNFROZEN = 150382859;
LITDEF int ERR_GTMEISDIR = 150382866;
@@ -2673,9 +2694,30 @@ LITDEF int ERR_NOTALLDBRNDWN = 150382962;
LITDEF int ERR_TPRESTNESTERR = 150382970;
LITDEF int ERR_JNLFILRDOPN = 150382978;
LITDEF int ERR_SEQNUMSEARCHTIMEOUT = 150382986;
+LITDEF int ERR_FTOKKEY = 150382995;
+LITDEF int ERR_SEMID = 150383003;
+LITDEF int ERR_JNLQIOSALVAGE = 150383011;
+LITDEF int ERR_FAKENOSPCLEARED = 150383019;
+LITDEF int ERR_MMFILETOOLARGE = 150383026;
+LITDEF int ERR_BADZPEEKARG = 150383034;
+LITDEF int ERR_BADZPEEKRANGE = 150383042;
+LITDEF int ERR_BADZPEEKFMT = 150383050;
+LITDEF int ERR_DBMBMINCFREFIXED = 150383056;
+LITDEF int ERR_NULLENTRYREF = 150383066;
+LITDEF int ERR_ZPEEKNORPLINFO = 150383074;
+LITDEF int ERR_MMREGNOACCESS = 150383082;
+LITDEF int ERR_MALLOCMAXUNIX = 150383090;
+LITDEF int ERR_MALLOCMAXVMS = 150383098;
+LITDEF int ERR_HOSTCONFLICT = 150383106;
+LITDEF int ERR_GETADDRINFO = 150383114;
+LITDEF int ERR_GETNAMEINFO = 150383122;
+LITDEF int ERR_SOCKBIND = 150383130;
+LITDEF int ERR_INSTFRZDEFER = 150383139;
+LITDEF int ERR_REGOPENRETRY = 150383147;
+LITDEF int ERR_REGOPENFAIL = 150383154;
GBLDEF err_ctl merrors_ctl = {
246,
"GTM",
&merrors[0],
- 1329};
+ 1350};
diff --git a/sr_i386/ttt.c b/sr_i386/ttt.c
index 0ed8534..fc23248 100644
--- a/sr_i386/ttt.c
+++ b/sr_i386/ttt.c
@@ -13,677 +13,681 @@
#include "vxi.h"
#include "vxt.h"
#include "xfer_enum.h"
-LITDEF short ttt[4205] = {
+LITDEF short ttt[4229] = {
-/* 0 */ 0,0,0,0,321,3396,2839,545,
-/* 8 */ 2217,2824,2854,1907,399,3346,2019,2970,
-/* 16 */ 2096,2087,3579,3616,2060,2069,2135,2081,
-/* 24 */ 2126,2105,2042,745,772,760,799,811,
-/* 32 */ 823,841,883,901,919,940,969,999,
-/* 40 */ 1014,1029,1044,1062,1074,2940,2955,1146,
-/* 48 */ 1179,1212,1251,1314,1365,1641,1656,1671,
-/* 56 */ 1701,1740,1752,1776,1803,1824,1839,3411,
-/* 64 */ 3433,0,0,0,0,560,0,501,
-/* 72 */ 0,1893,0,2926,0,0,0,0,
-/* 80 */ 0,0,353,411,2195,2201,2616,2643,
-/* 88 */ 2661,2764,2702,2693,2779,3485,3569,2875,
-/* 96 */ 0,2905,3036,2999,2984,3014,3360,3212,
-/* 104 */ 3278,3491,3503,3518,3542,3551,3536,3527,
-/* 112 */ 3311,3612,3625,3647,3684,3696,3717,3741,
-/* 120 */ 3807,0,0,2812,2177,3088,4154,633,
-/* 128 */ 4157,687,2673,3054,515,521,4160,2280,
-/* 136 */ 2367,2267,468,2303,2387,2051,2325,2397,
-/* 144 */ 4163,2162,2153,4167,1383,1401,4168,349,
-/* 152 */ 345,3302,423,4172,4175,4178,2891,4181,
-/* 160 */ 4184,4187,4190,4193,4196,3382,0,2788,
-/* 168 */ 2456,2434,1620,2425,2213,2033,2739,1928,
-/* 176 */ 712,2729,0,0,2232,3560,3588,1596,
-/* 184 */ 3512,2315,1921,530,3708,1788,2144,1299,
-/* 192 */ 336,3040,599,665,583,643,3672,1194,
-/* 200 */ 1233,3640,2868,2171,2803,2882,615,1086,
-/* 208 */ 2743,4199,2377,3759,3777,3792,492,2758,
-/* 216 */ 3032,1866,3828,3819,1437,3374,574,1686,
-/* 224 */ 1728,2340,4202,3445,2413,721,859,3071,
-/* 232 */ 3600,3469,3455,3462,3451,697,954,2290,
-/* 240 */ 1128,2254,1116,2114,1101,1161,2352,1566,
-/* 248 */ 1509,1494,1548,1464,1476,1521,1449,1533,
-/* 256 */ 1581,0,3332,0,978,987,3191,3257,
-/* 264 */ 1815,3170,3236,2241,3864,3834,3840,3852,
-/* 272 */ 3874,1338,1350,1272,1284,1326,3423,1716,
-/* 280 */ 1851,3888,3903,3939,3966,3921,3098,3110,
-/* 288 */ 3122,3134,2652,2667,1608,432,787,1419,
-/* 296 */ 624,3146,3158,3951,3957,0,0,0,
-/* 304 */ 0,3663,3978,3989,4001,4010,4024,4037,
-/* 312 */ 4047,4064,4073,4082,4094,4106,4118,4133,
-/* 320 */ 4145,VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,
-/* 328 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_add,VXT_END,
-/* 336 */ VXT_IREPL,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_bindparm,
-/* 344 */ VXT_END,
-/* 345 */ VXI_INCL,VXT_VAL,1,VXT_END,
-/* 349 */ VXI_CLRL,VXT_VAL,0,VXT_END,
-/* 353 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_break,VXT_END,
-/* 357 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callb,VXI_BRB,VXT_JMP,1,VXT_END,
-/* 364 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_calll,VXI_JMP,VXT_JMP,1,VXT_END,
-/* 371 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callw,VXI_BRW,VXT_JMP,1,VXT_END,
-/* 378 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callspb,VXI_BRB,VXT_JMP,1,VXT_END,
-/* 385 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callspl,VXI_JMP,VXT_JMP,1,VXT_END,
-/* 392 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callspw,VXI_BRW,VXT_JMP,1,VXT_END,
-/* 399 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL,
-/* 407 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_cat,VXT_END,
-/* 411 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 419 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_close,VXT_END,
-/* 423 */ VXI_BICB2,VXT_LIT,1,VXT_REG,0x5A,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_dt_false,
-/* 431 */ VXT_END,
-/* 432 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_clralsvars,
-/* 440 */ VXT_END,
-/* 441 */ VXI_TSTL,VXT_VAL,1,VXT_END,
-/* 445 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_mval2bool,
-/* 453 */ VXT_END,
-/* 454 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_mval2mint,
-/* 462 */ VXI_MOVL,VXT_REG,0x50,VXT_VAL,0,VXT_END,
-/* 468 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
-/* 476 */ SIZEOF(char *) * (short int)xf_commarg,VXT_END,
-/* 478 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x50,VXI_MOVL,VXT_VAL,1,
-/* 486 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_mint2mval,VXT_END,
-/* 492 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_mval2num,
-/* 500 */ VXT_END,
-/* 501 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2,
-/* 509 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_contain,VXT_END,
-/* 515 */ VXI_MOVL,VXT_REG,0x6C,VXT_ADDR,0,VXT_END,
-/* 521 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_currtn,
-/* 529 */ VXT_END,
-/* 530 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,
-/* 538 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_cvtparm,VXT_END,
-/* 545 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 553 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_div,VXT_END,
-/* 560 */ VXI_MOVAB,VXT_VAL,2,VXT_REG,0x51,VXI_MOVAB,VXT_VAL,1,
-/* 568 */ VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_equ,VXT_END,
-/* 574 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_equnul,
-/* 582 */ VXT_END,
-/* 583 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
-/* 591 */ 2,VXI_PUSHL,VXT_LIT,0,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_exfun,VXT_END,
-/* 599 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
-/* 607 */ 2,VXI_PUSHAB,VXT_VAL,0,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_exfun,VXT_END,
-/* 615 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_exfunret,
-/* 623 */ VXT_END,
-/* 624 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_exfunretals,
-/* 632 */ VXT_END,
-/* 633 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
-/* 641 */ SIZEOF(char *) * (short int)xf_extcall,VXT_END,
-/* 643 */ VXT_IREPAB,VXT_VAL,5,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
-/* 651 */ 3,VXI_PUSHL,VXT_LIT,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,
-/* 659 */ VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_extexfun,VXT_END,
-/* 665 */ VXT_IREPAB,VXT_VAL,5,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
-/* 673 */ 3,VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,
-/* 681 */ VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_extexfun,VXT_END,
-/* 687 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
-/* 695 */ SIZEOF(char *) * (short int)xf_extjmp,VXT_END,
-/* 697 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 705 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_exp,VXT_END,
-/* 712 */ VXT_IREPL,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fetch,
-/* 720 */ VXT_END,
-/* 721 */ VXT_IREPAB,VXT_VAL,6,VXI_PUSHL,VXT_VAL,5,VXI_PUSHL,VXT_VAL,
-/* 729 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,
-/* 737 */ VXT_LIT,0,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnfgncal,VXT_END,
-/* 745 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL,
-/* 753 */ 2,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnascii,VXT_END,
-/* 760 */ VXT_IREPL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL,
-/* 768 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnchar,VXT_END,
-/* 772 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL,
-/* 780 */ 2,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzascii,VXT_END,
-/* 787 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 795 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzahandle,VXT_END,
-/* 799 */ VXT_IREPL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL,
-/* 807 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzchar,VXT_END,
-/* 811 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 819 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fndata,VXT_END,
-/* 823 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL,
-/* 831 */ 2,VXI_PUSHL,VXT_VAL,3,VXI_CALLS,VXT_LIT,4,VXT_XFER,
-/* 839 */ SIZEOF(char *) * (short int)xf_fnextract,VXT_END,
-/* 841 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL,
-/* 849 */ 2,VXI_PUSHL,VXT_VAL,3,VXI_CALLS,VXT_LIT,4,VXT_XFER,
-/* 857 */ SIZEOF(char *) * (short int)xf_fnzextract,VXT_END,
-/* 859 */ VXT_IREPAB,VXT_VAL,6,VXI_PUSHL,VXT_VAL,5,VXI_PUSHL,VXT_VAL,
-/* 867 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,
-/* 875 */ VXT_VAL,0,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnfgncal,VXT_END,
-/* 883 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
-/* 891 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
-/* 899 */ SIZEOF(char *) * (short int)xf_fnfind,VXT_END,
-/* 901 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
-/* 909 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
-/* 917 */ SIZEOF(char *) * (short int)xf_fnzfind,VXT_END,
-/* 919 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
-/* 927 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
-/* 935 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnfnumber,VXT_END,
-/* 940 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_MOVAB,VXT_VAL,0,
-/* 948 */ VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_fnget,VXT_END,
-/* 954 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 962 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnget2,VXT_END,
-/* 969 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fngvget,
-/* 977 */ VXT_END,
-/* 978 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fngvget1,
-/* 986 */ VXT_END,
-/* 987 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 995 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnget1,VXT_END,
-/* 999 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 1007 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnincr,VXT_END,
-/* 1014 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 1022 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnj2,VXT_END,
-/* 1029 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 1037 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzj2,VXT_END,
-/* 1044 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
-/* 1052 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
-/* 1060 */ SIZEOF(char *) * (short int)xf_fnj3,VXT_END,
-/* 1062 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 1070 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnlength,VXT_END,
-/* 1074 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 1082 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzlength,VXT_END,
-/* 1086 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 1094 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnlvname,VXT_END,
-/* 1101 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,
-/* 1109 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnlvnameo2,VXT_END,
-/* 1116 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 1124 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnlvprvname,VXT_END,
-/* 1128 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL,
-/* 1136 */ 3,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL,2,VXT_XFER,
-/* 1144 */ SIZEOF(char *) * (short int)xf_fnname,VXT_END,
-/* 1146 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 1154 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnnext,VXT_END,
-/* 1161 */ VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,
-/* 1169 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
-/* 1177 */ SIZEOF(char *) * (short int)xf_fno2,VXT_END,
-/* 1179 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 1187 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnorder,VXT_END,
-/* 1194 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
-/* 1202 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
-/* 1210 */ SIZEOF(char *) * (short int)xf_fnp1,VXT_END,
-/* 1212 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
-/* 1220 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
-/* 1228 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnpiece,VXT_END,
-/* 1233 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
-/* 1241 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
-/* 1249 */ SIZEOF(char *) * (short int)xf_fnzp1,VXT_END,
-/* 1251 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
-/* 1259 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
-/* 1267 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpiece,VXT_END,
-/* 1272 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 1280 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnqlength,VXT_END,
-/* 1284 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 1292 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnqsubscript,VXT_END,
-/* 1299 */ VXT_IREPAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 1307 */ 0,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnquery,VXT_END,
-/* 1314 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 1322 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnrandom,VXT_END,
-/* 1326 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 1334 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnreverse,VXT_END,
-/* 1338 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 1346 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnstack1,VXT_END,
-/* 1350 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,
-/* 1358 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnstack2,VXT_END,
-/* 1365 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
-/* 1373 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
-/* 1381 */ SIZEOF(char *) * (short int)xf_fntext,VXT_END,
-/* 1383 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
-/* 1391 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
-/* 1399 */ SIZEOF(char *) * (short int)xf_fntranslate,VXT_END,
-/* 1401 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
-/* 1409 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
-/* 1417 */ SIZEOF(char *) * (short int)xf_fnztranslate,VXT_END,
-/* 1419 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
-/* 1427 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
-/* 1435 */ SIZEOF(char *) * (short int)xf_fnztrigger,VXT_END,
-/* 1437 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL,
-/* 1445 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnview,VXT_END,
-/* 1449 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
-/* 1457 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitand,VXT_END,
-/* 1464 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,
-/* 1472 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitcoun,VXT_END,
-/* 1476 */ VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 1484 */ 1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,4,VXT_XFER,
-/* 1492 */ SIZEOF(char *) * (short int)xf_fnzbitfind,VXT_END,
-/* 1494 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
-/* 1502 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitget,VXT_END,
-/* 1509 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,
-/* 1517 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitlen,VXT_END,
-/* 1521 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,
-/* 1529 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitnot,VXT_END,
-/* 1533 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
-/* 1541 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitor,VXT_END,
-/* 1548 */ VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 1556 */ 1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,4,VXT_XFER,
-/* 1564 */ SIZEOF(char *) * (short int)xf_fnzbitset,VXT_END,
-/* 1566 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
-/* 1574 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitstr,VXT_END,
-/* 1581 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
-/* 1589 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitxor,VXT_END,
-/* 1596 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL,
-/* 1604 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzcall,VXT_END,
-/* 1608 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 1616 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzdata,VXT_END,
-/* 1620 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,
-/* 1628 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
-/* 1636 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzdate,VXT_END,
-/* 1641 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 1649 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzfile,VXT_END,
-/* 1656 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 1664 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngetdvi,VXT_END,
-/* 1671 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,
-/* 1679 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngetjpi,VXT_END,
-/* 1686 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,
-/* 1694 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngetlki,VXT_END,
-/* 1701 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 1709 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngetsyi,VXT_END,
-/* 1716 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 1724 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzjobexam,VXT_END,
-/* 1728 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 1736 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzlkid,VXT_END,
-/* 1740 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 1748 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzm,VXT_END,
-/* 1752 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,
-/* 1760 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,
-/* 1768 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,6,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzparse,VXT_END,
-/* 1776 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 1784 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpid,VXT_END,
-/* 1788 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 1796 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzprevious,VXT_END,
-/* 1803 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 1811 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpriv,VXT_END,
-/* 1815 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzqgblmod,
-/* 1823 */ VXT_END,
-/* 1824 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 1832 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzsearch,VXT_END,
-/* 1839 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 1847 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzsetprv,VXT_END,
-/* 1851 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,
-/* 1859 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzsigproc,VXT_END,
-/* 1866 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,6,VXI_PUSHAB,VXT_VAL,
-/* 1874 */ 5,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,
-/* 1882 */ VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,7,
-/* 1890 */ VXT_XFER,SIZEOF(char *) * (short int)xf_fnztrnlnm,VXT_END,
-/* 1893 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2,
-/* 1901 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_follow,VXT_END,
-/* 1907 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,1,
-/* 1915 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forcenum,VXT_END,
-/* 1921 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forchk1,VXT_END,
-/* 1928 */ VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 1936 */ 1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forinit,VXT_END,
-/* 1941 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forlcldob,VXI_BRB,VXT_JMP,1,VXT_END,
-/* 1948 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forlcldol,VXI_JMP,VXT_JMP,1,VXT_END,
-/* 1955 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forlcldow,VXI_BRW,VXT_JMP,1,VXT_END,
-/* 1962 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_JMP,1,VXI_PUSHAB,VXT_VAL,
-/* 1970 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_JSB,
-/* 1978 */ VXT_XFER,SIZEOF(char *) * (short int)xf_forloop,VXT_END,
-/* 1981 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_JMP,1,VXI_PUSHAB,VXT_VAL,
-/* 1989 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_JSB,
-/* 1997 */ VXT_XFER,SIZEOF(char *) * (short int)xf_forloop,VXT_END,
-/* 2000 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_JMP,1,VXI_PUSHAB,VXT_VAL,
-/* 2008 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_JSB,
-/* 2016 */ VXT_XFER,SIZEOF(char *) * (short int)xf_forloop,VXT_END,
-/* 2019 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_getindx,
-/* 2027 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END,
-/* 2033 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_gettruth,
-/* 2041 */ VXT_END,
-/* 2042 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvdata,
-/* 2050 */ VXT_END,
-/* 2051 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvextnam,
-/* 2059 */ VXT_END,
-/* 2060 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvget,
-/* 2068 */ VXT_END,
-/* 2069 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT,
-/* 2077 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_gvincr,VXT_END,
-/* 2081 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_gvkill,VXT_END,
-/* 2087 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvnaked,
-/* 2095 */ VXT_END,
-/* 2096 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvname,
-/* 2104 */ VXT_END,
-/* 2105 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvnext,
-/* 2113 */ VXT_END,
-/* 2114 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,
-/* 2122 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_gvo2,VXT_END,
-/* 2126 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvorder,
-/* 2134 */ VXT_END,
-/* 2135 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvput,
-/* 2143 */ VXT_END,
-/* 2144 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvquery,
-/* 2152 */ VXT_END,
-/* 2153 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvrectarg,
-/* 2161 */ VXT_END,
-/* 2162 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvsavtarg,
-/* 2170 */ VXT_END,
-/* 2171 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_gvzwithdraw,VXT_END,
-/* 2177 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
-/* 2185 */ 3,VXI_PUSHL,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,
-/* 2193 */ SIZEOF(char *) * (short int)xf_gvzwrite,VXT_END,
-/* 2195 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_halt,VXT_END,
-/* 2201 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 2209 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_hang,VXT_END,
-/* 2213 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_hardret,VXT_END,
-/* 2217 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 2225 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_idiv,VXT_END,
-/* 2232 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_igetsrc,
-/* 2240 */ VXT_END,
-/* 2241 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 2249 */ 1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_inddevparms,VXT_END,
-/* 2254 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
-/* 2262 */ 0,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indfnname,VXT_END,
-/* 2267 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 2275 */ 1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indfun,VXT_END,
-/* 2280 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
-/* 2288 */ SIZEOF(char *) * (short int)xf_indglvn,VXT_END,
-/* 2290 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 2298 */ 0,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indincr,VXT_END,
-/* 2303 */ VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indlvadr,VXI_MOVL,VXT_REG,
-/* 2311 */ 0x50,VXT_ADDR,0,VXT_END,
-/* 2315 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
-/* 2323 */ SIZEOF(char *) * (short int)xf_indlvarg,VXT_END,
-/* 2325 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
-/* 2333 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_indname,VXT_END,
-/* 2340 */ VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indlvnamadr,VXI_MOVL,VXT_REG,
-/* 2348 */ 0x50,VXT_ADDR,0,VXT_END,
-/* 2352 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
-/* 2360 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_indo2,VXT_END,
-/* 2367 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
-/* 2375 */ SIZEOF(char *) * (short int)xf_indpat,VXT_END,
-/* 2377 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
-/* 2385 */ SIZEOF(char *) * (short int)xf_indrzshow,VXT_END,
-/* 2387 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
-/* 2395 */ SIZEOF(char *) * (short int)xf_indset,VXT_END,
-/* 2397 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
-/* 2405 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indtext,VXT_END,
-/* 2413 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,
-/* 2421 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_iocontrol,VXT_END,
-/* 2425 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_iretmvad,
-/* 2433 */ VXT_END,
-/* 2434 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
-/* 2442 */ SIZEOF(char *) * (short int)xf_iretmval,VXT_END,
-/* 2444 */ VXI_BRB,VXT_JMP,1,VXT_END,
-/* 2448 */ VXI_JMP,VXT_JMP,1,VXT_END,
-/* 2452 */ VXI_BRW,VXT_JMP,1,VXT_END,
-/* 2456 */ VXI_JMP,VXT_VAL,1,VXT_END,
-/* 2460 */ VXI_BEQL,VXT_JMP,1,VXT_END,
-/* 2464 */ VXI_BNEQ,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END,
-/* 2471 */ VXI_BNEQ,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END,
-/* 2478 */ VXI_BGEQ,VXT_JMP,1,VXT_END,
-/* 2482 */ VXI_BLSS,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END,
-/* 2489 */ VXI_BLSS,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END,
-/* 2496 */ VXI_BGTR,VXT_JMP,1,VXT_END,
-/* 2500 */ VXI_BLEQ,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END,
-/* 2507 */ VXI_BLEQ,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END,
-/* 2514 */ VXI_BLEQ,VXT_JMP,1,VXT_END,
-/* 2518 */ VXI_BGTR,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END,
-/* 2525 */ VXI_BGTR,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END,
-/* 2532 */ VXI_BLSS,VXT_JMP,1,VXT_END,
-/* 2536 */ VXI_BGEQ,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END,
-/* 2543 */ VXI_BGEQ,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END,
-/* 2550 */ VXI_BNEQ,VXT_JMP,1,VXT_END,
-/* 2554 */ VXI_BNEQ,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END,
-/* 2561 */ VXI_BEQL,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END,
-/* 2568 */ VXI_BLBC,VXT_REG,0x5A,VXT_JMP,1,VXT_END,
-/* 2574 */ VXI_BLBS,VXT_REG,0x5A,VXT_LIT,6,VXI_JMP,VXT_JMP,1,
-/* 2582 */ VXT_END,
-/* 2583 */ VXI_BLBS,VXT_REG,0x5A,VXT_LIT,3,VXI_BRW,VXT_JMP,1,
-/* 2591 */ VXT_END,
-/* 2592 */ VXI_BLBS,VXT_REG,0x5A,VXT_JMP,1,VXT_END,
-/* 2598 */ VXI_BLBC,VXT_REG,0x5A,VXT_LIT,6,VXI_JMP,VXT_JMP,1,
-/* 2606 */ VXT_END,
-/* 2607 */ VXI_BLBC,VXT_REG,0x5A,VXT_LIT,3,VXI_BRW,VXT_JMP,1,
-/* 2615 */ VXT_END,
-/* 2616 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,7,VXI_PUSHL,VXT_VAL,
-/* 2624 */ 6,VXI_PUSHAB,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL,
-/* 2632 */ VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,
-/* 2640 */ VXT_XFER,SIZEOF(char *) * (short int)xf_job,VXT_END,
-/* 2643 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_kill,
-/* 2651 */ VXT_END,
-/* 2652 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_killalias,
-/* 2660 */ VXT_END,
-/* 2661 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_killall,VXT_END,
-/* 2667 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_killaliasall,VXT_END,
-/* 2673 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
-/* 2681 */ 3,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_labaddr,VXI_MOVL,VXT_REG,
-/* 2689 */ 0x50,VXT_ADDR,0,VXT_END,
-/* 2693 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lckdecr,
-/* 2701 */ VXT_END,
-/* 2702 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lckincr,
-/* 2710 */ VXT_END,
-/* 2711 */ VXI_MOVAB,VXT_JMP,1,VXT_ADDR,0,VXT_END,
-/* 2717 */ VXI_MOVAB,VXT_JMP,1,VXT_ADDR,0,VXT_END,
-/* 2723 */ VXI_MOVAB,VXT_JMP,1,VXT_ADDR,0,VXT_END,
-/* 2729 */ VXT_IREPL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,
-/* 2737 */ SIZEOF(char *) * (short int)xf_linefetch,VXT_END,
-/* 2739 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_linestart,VXT_END,
-/* 2743 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
-/* 2751 */ 2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lkname,VXT_END,
-/* 2758 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_lkinit,VXT_END,
-/* 2764 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
-/* 2772 */ 2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lkname,VXT_END,
-/* 2779 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lock,
-/* 2787 */ VXT_END,
-/* 2788 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
-/* 2796 */ 2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lvpatwrite,VXT_END,
-/* 2803 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lvzwithdraw,
-/* 2811 */ VXT_END,
-/* 2812 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,
-/* 2820 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_lvzwrite,VXT_END,
-/* 2824 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 2832 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_flt_mod,VXT_END,
-/* 2839 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 2847 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_mul,VXT_END,
-/* 2854 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,1,
-/* 2862 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_neg,VXT_END,
-/* 2868 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_newintrinsic,VXT_END,
-/* 2875 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_newvar,VXT_END,
-/* 2882 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_nullexp,
-/* 2890 */ VXT_END,
-/* 2891 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2,
-/* 2899 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_numcmp,VXT_END,
-/* 2905 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
-/* 2913 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
-/* 2921 */ VXT_LIT,4,VXT_XFER,SIZEOF(char *) * (short int)xf_open,VXT_END,
-/* 2926 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2,
-/* 2934 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_pattern,VXT_END,
-/* 2940 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 2948 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnpopulation,VXT_END,
-/* 2955 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 2963 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpopulation,VXT_END,
-/* 2970 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_putindx,
-/* 2978 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END,
-/* 2984 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
-/* 2992 */ 0,VXI_CALLS,VXT_LIT,2,VXT_XFER,SIZEOF(char *) * (short int)xf_rdone,VXT_END,
-/* 2999 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
-/* 3007 */ 0,VXI_CALLS,VXT_LIT,2,VXT_XFER,SIZEOF(char *) * (short int)xf_read,VXT_END,
-/* 3014 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,
-/* 3022 */ 1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,3,VXT_XFER,
-/* 3030 */ SIZEOF(char *) * (short int)xf_readfl,VXT_END,
-/* 3032 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_END,
-/* 3036 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_ret,VXT_END,
-/* 3040 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVL,VXT_VAL,2,
-/* 3048 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_retarg,VXT_END,
-/* 3054 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 3062 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_rhdaddr,VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,
-/* 3070 */ VXT_END,
-/* 3071 */ VXI_PUSHL,VXT_LIT,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 3079 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_rhdaddr,VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,
-/* 3087 */ VXT_END,
-/* 3088 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,
-/* 3096 */ SIZEOF(char *) * (short int)xf_rterror,VXT_END,
-/* 3098 */ VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT,
-/* 3106 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setals2als,VXT_END,
-/* 3110 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT,
-/* 3118 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setalsin2alsct,VXT_END,
-/* 3122 */ VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT,
-/* 3130 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setalsctin2als,VXT_END,
-/* 3134 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT,
-/* 3142 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setalsct2alsct,VXT_END,
-/* 3146 */ VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT,
-/* 3154 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setfnretin2als,VXT_END,
-/* 3158 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT,
-/* 3166 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setfnretin2alsct,VXT_END,
-/* 3170 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
-/* 3178 */ 2,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
-/* 3186 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setextract,VXT_END,
-/* 3191 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
-/* 3199 */ 4,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
-/* 3207 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setp1,VXT_END,
-/* 3212 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
-/* 3220 */ 3,VXI_PUSHAB,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,
-/* 3228 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,6,VXT_XFER,SIZEOF(char *) * (short int)xf_setpiece,VXT_END,
-/* 3236 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
-/* 3244 */ 2,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
-/* 3252 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setzextract,VXT_END,
-/* 3257 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
-/* 3265 */ 4,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
-/* 3273 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setzp1,VXT_END,
-/* 3278 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
-/* 3286 */ 3,VXI_PUSHAB,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,
-/* 3294 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,6,VXT_XFER,SIZEOF(char *) * (short int)xf_setzpiece,VXT_END,
-/* 3302 */ VXI_BISB2,VXT_LIT,1,VXT_REG,0x5A,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_dt_true,
-/* 3310 */ VXT_END,
-/* 3311 */ VXI_PUSHL,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
-/* 3319 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,3,VXI_CALLS,
-/* 3327 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setzbrk,VXT_END,
-/* 3332 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2,
-/* 3340 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_sorts_after,VXT_END,
-/* 3346 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_srchindx,
-/* 3354 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END,
-/* 3360 */ VXI_MOVAB,VXT_VAL,2,VXT_REG,0x51,VXI_MOVAB,VXT_VAL,1,
-/* 3368 */ VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_sto,VXT_END,
-/* 3374 */ VXI_MOVC3,VXT_LIT,16,VXT_VAL,2,VXT_VAL,1,VXT_END,
-/* 3382 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_MOVAB,VXT_VAL,0,
-/* 3390 */ VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_sto,VXT_END,
-/* 3396 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 3404 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_sub,VXT_END,
-/* 3411 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 3419 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_svget,VXT_END,
-/* 3423 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,
-/* 3431 */ SIZEOF(char *) * (short int)xf_psvput,VXT_END,
-/* 3433 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 3441 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_svput,VXT_END,
-/* 3445 */ VXI_MOVL,VXT_REG,0x50,VXT_REG,0x5A,VXT_END,
-/* 3451 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_tcommit,VXT_END,
-/* 3455 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_trollback,VXT_END,
-/* 3462 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_trestart,VXT_END,
-/* 3469 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
-/* 3477 */ 2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_tstart,VXT_END,
-/* 3485 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_unlock,VXT_END,
-/* 3491 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 3499 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_use,VXT_END,
-/* 3503 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_view,
-/* 3511 */ VXT_END,
-/* 3512 */ VXI_CMPL,VXT_VAL,1,VXT_VAL,2,VXT_END,
-/* 3518 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_write,
-/* 3526 */ VXT_END,
-/* 3527 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_wteol,
-/* 3535 */ VXT_END,
-/* 3536 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_wtff,VXT_END,
-/* 3542 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_wtone,
-/* 3550 */ VXT_END,
-/* 3551 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_wttab,
-/* 3559 */ VXT_END,
-/* 3560 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_xkill,
-/* 3568 */ VXT_END,
-/* 3569 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,
-/* 3577 */ SIZEOF(char *) * (short int)xf_xnew,VXT_END,
-/* 3579 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zallocate,
-/* 3587 */ VXT_END,
-/* 3588 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 3596 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_zattach,VXT_END,
-/* 3600 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 3608 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zcompile,VXT_END,
-/* 3612 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zcont,VXT_END,
-/* 3616 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zdeallocate,
-/* 3624 */ VXT_END,
-/* 3625 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 3633 */ 1,VXI_CALLS,VXT_LIT,2,VXT_XFER,SIZEOF(char *) * (short int)xf_zedit,VXT_END,
-/* 3640 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zg1,VXT_END,
-/* 3647 */ VXI_PUSHL,VXT_VAL,1,VXI_PUSHL,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,
-/* 3655 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zgoto,VXT_END,
-/* 3663 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zhalt,
-/* 3671 */ VXT_END,
-/* 3672 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 3680 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zhelp,VXT_END,
-/* 3684 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 3692 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zlink,VXT_END,
-/* 3696 */ VXT_IREPAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL,2,VXI_CALLS,VXT_VAL,
-/* 3704 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_zmess,VXT_END,
-/* 3708 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zprevious,
-/* 3716 */ VXT_END,
-/* 3717 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,
-/* 3725 */ 4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,
-/* 3733 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_zprint,VXT_END,
-/* 3741 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_LIT,0,VXI_PUSHL,VXT_VAL,
-/* 3749 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,3,VXT_XFER,
-/* 3757 */ SIZEOF(char *) * (short int)xf_zshow,VXT_END,
-/* 3759 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
-/* 3767 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,3,VXT_XFER,
-/* 3775 */ SIZEOF(char *) * (short int)xf_zshow,VXT_END,
-/* 3777 */ VXI_PUSHL,VXT_LIT,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 3785 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zstep,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zcont,VXT_END,
-/* 3792 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 3800 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zstep,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zcont,VXT_END,
-/* 3807 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 3815 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_zsystem,VXT_END,
-/* 3819 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_ztcommit,
-/* 3827 */ VXT_END,
-/* 3828 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_ztstart,VXT_END,
-/* 3834 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_merge,VXT_END,
-/* 3840 */ VXI_PUSHL,VXT_LIT,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 3848 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_merge_arg,VXT_END,
-/* 3852 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 3860 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_merge_arg,VXT_END,
-/* 3864 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_JSB,VXT_XFER,
-/* 3872 */ SIZEOF(char *) * (short int)xf_indmerge,VXT_END,
-/* 3874 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_m_srchindx,
-/* 3882 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END,
-/* 3888 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 3896 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzconvert2,VXT_END,
-/* 3903 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
-/* 3911 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
-/* 3919 */ SIZEOF(char *) * (short int)xf_fnzconvert3,VXT_END,
-/* 3921 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
-/* 3929 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
-/* 3937 */ SIZEOF(char *) * (short int)xf_fnzsubstr,VXT_END,
-/* 3939 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 3947 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzwidth,VXT_END,
-/* 3951 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_ztrigger,VXT_END,
-/* 3957 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zwritesvn,
-/* 3965 */ VXT_END,
-/* 3966 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 3974 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzwrite,VXT_END,
-/* 3978 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_igetdst,VXI_MOVL,VXT_REG,0x50,
-/* 3986 */ VXT_ADDR,0,VXT_END,
-/* 3989 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 3997 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_indget1,VXT_END,
-/* 4001 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_glvnpop,
-/* 4009 */ VXT_END,
-/* 4010 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_glvnslot,
-/* 4018 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END,
-/* 4024 */ VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 4032 */ 1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indsavglvn,VXT_END,
-/* 4037 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
-/* 4045 */ SIZEOF(char *) * (short int)xf_indsavlvn,VXT_END,
-/* 4047 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 4055 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_rfrshlvn,VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,
-/* 4063 */ VXT_END,
-/* 4064 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_savgvn,
-/* 4072 */ VXT_END,
-/* 4073 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_savlvn,
-/* 4081 */ VXT_END,
-/* 4082 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 4090 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_shareslot,VXT_END,
-/* 4094 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 4102 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_stoglvn,VXT_END,
-/* 4106 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 4114 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_rfrshgvn,VXT_END,
-/* 4118 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
-/* 4126 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_indfnname2,VXT_END,
-/* 4133 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,
-/* 4141 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_indget2,VXT_END,
-/* 4145 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_indmerge2,
-/* 4153 */ VXT_END,
-/* 4154 */ 357,371,364,2444,2452,2448,2711,2723,
-/* 4162 */ 2717,0,0,0,478,454,445,0,
-/* 4170 */ 0,441,1962,2000,1981,2592,2607,2598,
-/* 4178 */ 2568,2583,2574,2460,2471,2464,2550,2561,
-/* 4186 */ 2554,2496,2507,2500,2514,2525,2518,2532,
-/* 4194 */ 2543,2536,2478,2489,2482,1941,1955,1948,
-/* 4202 */ 378,392,385};
+/* 0 */ 0,0,0,0,324,3399,2842,548,
+/* 8 */ 2220,2827,2857,1910,402,3349,2022,2973,
+/* 16 */ 2099,2090,3582,3619,2063,2072,2138,2084,
+/* 24 */ 2129,2108,2045,748,775,763,802,814,
+/* 32 */ 826,844,886,904,922,943,972,1002,
+/* 40 */ 1017,1032,1047,1065,1077,2943,2958,1149,
+/* 48 */ 1182,1215,1254,1317,1368,1644,1659,1674,
+/* 56 */ 1704,1743,1755,1779,1806,1827,1842,3414,
+/* 64 */ 3436,0,0,0,0,563,0,504,
+/* 72 */ 0,1896,0,2929,0,0,0,0,
+/* 80 */ 0,0,356,414,2198,2204,2619,2646,
+/* 88 */ 2664,2767,2705,2696,2782,3488,3572,2878,
+/* 96 */ 0,2908,3039,3002,2987,3017,3363,3215,
+/* 104 */ 3281,3494,3506,3521,3545,3554,3539,3530,
+/* 112 */ 3314,3615,3628,3650,3687,3699,3720,3744,
+/* 120 */ 3810,0,0,2815,2180,3091,4178,636,
+/* 128 */ 4181,690,2676,3057,518,524,4184,2283,
+/* 136 */ 2370,2270,471,2306,2390,2054,2328,2400,
+/* 144 */ 4187,2165,2156,4191,1386,1404,4192,352,
+/* 152 */ 348,3305,426,4196,4199,4202,2894,4205,
+/* 160 */ 4208,4211,4214,4217,4220,3385,0,2791,
+/* 168 */ 2459,2437,1623,2428,2216,2036,2742,1931,
+/* 176 */ 715,2732,0,0,2235,3563,3591,1599,
+/* 184 */ 3515,2318,1924,533,3711,1791,2147,1302,
+/* 192 */ 339,3043,602,668,586,646,3675,1197,
+/* 200 */ 1236,3643,2871,2174,2806,2885,618,1089,
+/* 208 */ 2746,4223,2380,3762,3780,3795,495,2761,
+/* 216 */ 3035,1869,3831,3822,1440,3377,577,1689,
+/* 224 */ 1731,2343,4226,3448,2416,724,862,3074,
+/* 232 */ 3603,3472,3458,3465,3454,700,957,2293,
+/* 240 */ 1131,2257,1119,2117,1104,1164,2355,1569,
+/* 248 */ 1512,1497,1551,1467,1479,1524,1452,1536,
+/* 256 */ 1584,0,3335,0,981,990,3194,3260,
+/* 264 */ 1818,3173,3239,2244,3867,3837,3843,3855,
+/* 272 */ 3877,1341,1353,1275,1287,1329,3426,1719,
+/* 280 */ 1854,3891,3906,3942,3969,3924,3101,3113,
+/* 288 */ 3125,3137,2655,2670,1611,435,790,1422,
+/* 296 */ 627,3149,3161,3954,3960,0,0,0,
+/* 304 */ 0,3666,3981,3992,4004,4013,4027,4040,
+/* 312 */ 4050,4067,4076,4085,4097,4109,4121,4136,
+/* 320 */ 4148,0,0,4157,VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,
+/* 328 */ VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,3,
+/* 336 */ VXT_XFER,SIZEOF(char *) * (short int)xf_add,VXT_END,
+/* 339 */ VXT_IREPL,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_bindparm,
+/* 347 */ VXT_END,
+/* 348 */ VXI_INCL,VXT_VAL,1,VXT_END,
+/* 352 */ VXI_CLRL,VXT_VAL,0,VXT_END,
+/* 356 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_break,VXT_END,
+/* 360 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callb,VXI_BRB,VXT_JMP,1,VXT_END,
+/* 367 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_calll,VXI_JMP,VXT_JMP,1,VXT_END,
+/* 374 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callw,VXI_BRW,VXT_JMP,1,VXT_END,
+/* 381 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callspb,VXI_BRB,VXT_JMP,1,VXT_END,
+/* 388 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callspl,VXI_JMP,VXT_JMP,1,VXT_END,
+/* 395 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callspw,VXI_BRW,VXT_JMP,1,VXT_END,
+/* 402 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL,
+/* 410 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_cat,VXT_END,
+/* 414 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 422 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_close,VXT_END,
+/* 426 */ VXI_BICB2,VXT_LIT,1,VXT_REG,0x5A,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_dt_false,
+/* 434 */ VXT_END,
+/* 435 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_clralsvars,
+/* 443 */ VXT_END,
+/* 444 */ VXI_TSTL,VXT_VAL,1,VXT_END,
+/* 448 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_mval2bool,
+/* 456 */ VXT_END,
+/* 457 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_mval2mint,
+/* 465 */ VXI_MOVL,VXT_REG,0x50,VXT_VAL,0,VXT_END,
+/* 471 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
+/* 479 */ SIZEOF(char *) * (short int)xf_commarg,VXT_END,
+/* 481 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x50,VXI_MOVL,VXT_VAL,1,
+/* 489 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_mint2mval,VXT_END,
+/* 495 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_mval2num,
+/* 503 */ VXT_END,
+/* 504 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2,
+/* 512 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_contain,VXT_END,
+/* 518 */ VXI_MOVL,VXT_REG,0x6C,VXT_ADDR,0,VXT_END,
+/* 524 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_currtn,
+/* 532 */ VXT_END,
+/* 533 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,
+/* 541 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_cvtparm,VXT_END,
+/* 548 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 556 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_div,VXT_END,
+/* 563 */ VXI_MOVAB,VXT_VAL,2,VXT_REG,0x51,VXI_MOVAB,VXT_VAL,1,
+/* 571 */ VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_equ,VXT_END,
+/* 577 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_equnul,
+/* 585 */ VXT_END,
+/* 586 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
+/* 594 */ 2,VXI_PUSHL,VXT_LIT,0,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_exfun,VXT_END,
+/* 602 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
+/* 610 */ 2,VXI_PUSHAB,VXT_VAL,0,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_exfun,VXT_END,
+/* 618 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_exfunret,
+/* 626 */ VXT_END,
+/* 627 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_exfunretals,
+/* 635 */ VXT_END,
+/* 636 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
+/* 644 */ SIZEOF(char *) * (short int)xf_extcall,VXT_END,
+/* 646 */ VXT_IREPAB,VXT_VAL,5,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
+/* 654 */ 3,VXI_PUSHL,VXT_LIT,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,
+/* 662 */ VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_extexfun,VXT_END,
+/* 668 */ VXT_IREPAB,VXT_VAL,5,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
+/* 676 */ 3,VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,
+/* 684 */ VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_extexfun,VXT_END,
+/* 690 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
+/* 698 */ SIZEOF(char *) * (short int)xf_extjmp,VXT_END,
+/* 700 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 708 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_exp,VXT_END,
+/* 715 */ VXT_IREPL,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fetch,
+/* 723 */ VXT_END,
+/* 724 */ VXT_IREPAB,VXT_VAL,6,VXI_PUSHL,VXT_VAL,5,VXI_PUSHL,VXT_VAL,
+/* 732 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,
+/* 740 */ VXT_LIT,0,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnfgncal,VXT_END,
+/* 748 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL,
+/* 756 */ 2,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnascii,VXT_END,
+/* 763 */ VXT_IREPL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL,
+/* 771 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnchar,VXT_END,
+/* 775 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL,
+/* 783 */ 2,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzascii,VXT_END,
+/* 790 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 798 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzahandle,VXT_END,
+/* 802 */ VXT_IREPL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL,
+/* 810 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzchar,VXT_END,
+/* 814 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 822 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fndata,VXT_END,
+/* 826 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL,
+/* 834 */ 2,VXI_PUSHL,VXT_VAL,3,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 842 */ SIZEOF(char *) * (short int)xf_fnextract,VXT_END,
+/* 844 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL,
+/* 852 */ 2,VXI_PUSHL,VXT_VAL,3,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 860 */ SIZEOF(char *) * (short int)xf_fnzextract,VXT_END,
+/* 862 */ VXT_IREPAB,VXT_VAL,6,VXI_PUSHL,VXT_VAL,5,VXI_PUSHL,VXT_VAL,
+/* 870 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,
+/* 878 */ VXT_VAL,0,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnfgncal,VXT_END,
+/* 886 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
+/* 894 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 902 */ SIZEOF(char *) * (short int)xf_fnfind,VXT_END,
+/* 904 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
+/* 912 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 920 */ SIZEOF(char *) * (short int)xf_fnzfind,VXT_END,
+/* 922 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
+/* 930 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
+/* 938 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnfnumber,VXT_END,
+/* 943 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_MOVAB,VXT_VAL,0,
+/* 951 */ VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_fnget,VXT_END,
+/* 957 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 965 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnget2,VXT_END,
+/* 972 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fngvget,
+/* 980 */ VXT_END,
+/* 981 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fngvget1,
+/* 989 */ VXT_END,
+/* 990 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 998 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnget1,VXT_END,
+/* 1002 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1010 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnincr,VXT_END,
+/* 1017 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1025 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnj2,VXT_END,
+/* 1032 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1040 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzj2,VXT_END,
+/* 1047 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
+/* 1055 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 1063 */ SIZEOF(char *) * (short int)xf_fnj3,VXT_END,
+/* 1065 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1073 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnlength,VXT_END,
+/* 1077 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1085 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzlength,VXT_END,
+/* 1089 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1097 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnlvname,VXT_END,
+/* 1104 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,
+/* 1112 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnlvnameo2,VXT_END,
+/* 1119 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1127 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnlvprvname,VXT_END,
+/* 1131 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL,
+/* 1139 */ 3,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL,2,VXT_XFER,
+/* 1147 */ SIZEOF(char *) * (short int)xf_fnname,VXT_END,
+/* 1149 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1157 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnnext,VXT_END,
+/* 1164 */ VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,
+/* 1172 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 1180 */ SIZEOF(char *) * (short int)xf_fno2,VXT_END,
+/* 1182 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1190 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnorder,VXT_END,
+/* 1197 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
+/* 1205 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 1213 */ SIZEOF(char *) * (short int)xf_fnp1,VXT_END,
+/* 1215 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
+/* 1223 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
+/* 1231 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnpiece,VXT_END,
+/* 1236 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
+/* 1244 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 1252 */ SIZEOF(char *) * (short int)xf_fnzp1,VXT_END,
+/* 1254 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
+/* 1262 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
+/* 1270 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpiece,VXT_END,
+/* 1275 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1283 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnqlength,VXT_END,
+/* 1287 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1295 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnqsubscript,VXT_END,
+/* 1302 */ VXT_IREPAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1310 */ 0,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnquery,VXT_END,
+/* 1317 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1325 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnrandom,VXT_END,
+/* 1329 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1337 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnreverse,VXT_END,
+/* 1341 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1349 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnstack1,VXT_END,
+/* 1353 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,
+/* 1361 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnstack2,VXT_END,
+/* 1368 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
+/* 1376 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 1384 */ SIZEOF(char *) * (short int)xf_fntext,VXT_END,
+/* 1386 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
+/* 1394 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 1402 */ SIZEOF(char *) * (short int)xf_fntranslate,VXT_END,
+/* 1404 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
+/* 1412 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 1420 */ SIZEOF(char *) * (short int)xf_fnztranslate,VXT_END,
+/* 1422 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
+/* 1430 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 1438 */ SIZEOF(char *) * (short int)xf_fnztrigger,VXT_END,
+/* 1440 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL,
+/* 1448 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnview,VXT_END,
+/* 1452 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
+/* 1460 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitand,VXT_END,
+/* 1467 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,
+/* 1475 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitcoun,VXT_END,
+/* 1479 */ VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1487 */ 1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 1495 */ SIZEOF(char *) * (short int)xf_fnzbitfind,VXT_END,
+/* 1497 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
+/* 1505 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitget,VXT_END,
+/* 1512 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,
+/* 1520 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitlen,VXT_END,
+/* 1524 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,
+/* 1532 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitnot,VXT_END,
+/* 1536 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
+/* 1544 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitor,VXT_END,
+/* 1551 */ VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1559 */ 1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 1567 */ SIZEOF(char *) * (short int)xf_fnzbitset,VXT_END,
+/* 1569 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
+/* 1577 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitstr,VXT_END,
+/* 1584 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
+/* 1592 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitxor,VXT_END,
+/* 1599 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL,
+/* 1607 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzcall,VXT_END,
+/* 1611 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1619 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzdata,VXT_END,
+/* 1623 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,
+/* 1631 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
+/* 1639 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzdate,VXT_END,
+/* 1644 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1652 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzfile,VXT_END,
+/* 1659 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1667 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngetdvi,VXT_END,
+/* 1674 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,
+/* 1682 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngetjpi,VXT_END,
+/* 1689 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,
+/* 1697 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngetlki,VXT_END,
+/* 1704 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1712 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngetsyi,VXT_END,
+/* 1719 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1727 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzjobexam,VXT_END,
+/* 1731 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1739 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzlkid,VXT_END,
+/* 1743 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1751 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzm,VXT_END,
+/* 1755 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,
+/* 1763 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,
+/* 1771 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,6,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzparse,VXT_END,
+/* 1779 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1787 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpid,VXT_END,
+/* 1791 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1799 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzprevious,VXT_END,
+/* 1806 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1814 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpriv,VXT_END,
+/* 1818 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzqgblmod,
+/* 1826 */ VXT_END,
+/* 1827 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1835 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzsearch,VXT_END,
+/* 1842 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1850 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzsetprv,VXT_END,
+/* 1854 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,
+/* 1862 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzsigproc,VXT_END,
+/* 1869 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,6,VXI_PUSHAB,VXT_VAL,
+/* 1877 */ 5,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,
+/* 1885 */ VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,7,
+/* 1893 */ VXT_XFER,SIZEOF(char *) * (short int)xf_fnztrnlnm,VXT_END,
+/* 1896 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2,
+/* 1904 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_follow,VXT_END,
+/* 1910 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,1,
+/* 1918 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forcenum,VXT_END,
+/* 1924 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forchk1,VXT_END,
+/* 1931 */ VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1939 */ 1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forinit,VXT_END,
+/* 1944 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forlcldob,VXI_BRB,VXT_JMP,1,VXT_END,
+/* 1951 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forlcldol,VXI_JMP,VXT_JMP,1,VXT_END,
+/* 1958 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forlcldow,VXI_BRW,VXT_JMP,1,VXT_END,
+/* 1965 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_JMP,1,VXI_PUSHAB,VXT_VAL,
+/* 1973 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_JSB,
+/* 1981 */ VXT_XFER,SIZEOF(char *) * (short int)xf_forloop,VXT_END,
+/* 1984 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_JMP,1,VXI_PUSHAB,VXT_VAL,
+/* 1992 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_JSB,
+/* 2000 */ VXT_XFER,SIZEOF(char *) * (short int)xf_forloop,VXT_END,
+/* 2003 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_JMP,1,VXI_PUSHAB,VXT_VAL,
+/* 2011 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_JSB,
+/* 2019 */ VXT_XFER,SIZEOF(char *) * (short int)xf_forloop,VXT_END,
+/* 2022 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_getindx,
+/* 2030 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END,
+/* 2036 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_gettruth,
+/* 2044 */ VXT_END,
+/* 2045 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvdata,
+/* 2053 */ VXT_END,
+/* 2054 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvextnam,
+/* 2062 */ VXT_END,
+/* 2063 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvget,
+/* 2071 */ VXT_END,
+/* 2072 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT,
+/* 2080 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_gvincr,VXT_END,
+/* 2084 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_gvkill,VXT_END,
+/* 2090 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvnaked,
+/* 2098 */ VXT_END,
+/* 2099 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvname,
+/* 2107 */ VXT_END,
+/* 2108 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvnext,
+/* 2116 */ VXT_END,
+/* 2117 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,
+/* 2125 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_gvo2,VXT_END,
+/* 2129 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvorder,
+/* 2137 */ VXT_END,
+/* 2138 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvput,
+/* 2146 */ VXT_END,
+/* 2147 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvquery,
+/* 2155 */ VXT_END,
+/* 2156 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvrectarg,
+/* 2164 */ VXT_END,
+/* 2165 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvsavtarg,
+/* 2173 */ VXT_END,
+/* 2174 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_gvzwithdraw,VXT_END,
+/* 2180 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
+/* 2188 */ 3,VXI_PUSHL,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,
+/* 2196 */ SIZEOF(char *) * (short int)xf_gvzwrite,VXT_END,
+/* 2198 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_halt,VXT_END,
+/* 2204 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 2212 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_hang,VXT_END,
+/* 2216 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_hardret,VXT_END,
+/* 2220 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 2228 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_idiv,VXT_END,
+/* 2235 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_igetsrc,
+/* 2243 */ VXT_END,
+/* 2244 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 2252 */ 1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_inddevparms,VXT_END,
+/* 2257 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
+/* 2265 */ 0,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indfnname,VXT_END,
+/* 2270 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 2278 */ 1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indfun,VXT_END,
+/* 2283 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
+/* 2291 */ SIZEOF(char *) * (short int)xf_indglvn,VXT_END,
+/* 2293 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 2301 */ 0,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indincr,VXT_END,
+/* 2306 */ VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indlvadr,VXI_MOVL,VXT_REG,
+/* 2314 */ 0x50,VXT_ADDR,0,VXT_END,
+/* 2318 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
+/* 2326 */ SIZEOF(char *) * (short int)xf_indlvarg,VXT_END,
+/* 2328 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
+/* 2336 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_indname,VXT_END,
+/* 2343 */ VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indlvnamadr,VXI_MOVL,VXT_REG,
+/* 2351 */ 0x50,VXT_ADDR,0,VXT_END,
+/* 2355 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
+/* 2363 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_indo2,VXT_END,
+/* 2370 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
+/* 2378 */ SIZEOF(char *) * (short int)xf_indpat,VXT_END,
+/* 2380 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
+/* 2388 */ SIZEOF(char *) * (short int)xf_indrzshow,VXT_END,
+/* 2390 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
+/* 2398 */ SIZEOF(char *) * (short int)xf_indset,VXT_END,
+/* 2400 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
+/* 2408 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indtext,VXT_END,
+/* 2416 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,
+/* 2424 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_iocontrol,VXT_END,
+/* 2428 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_iretmvad,
+/* 2436 */ VXT_END,
+/* 2437 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
+/* 2445 */ SIZEOF(char *) * (short int)xf_iretmval,VXT_END,
+/* 2447 */ VXI_BRB,VXT_JMP,1,VXT_END,
+/* 2451 */ VXI_JMP,VXT_JMP,1,VXT_END,
+/* 2455 */ VXI_BRW,VXT_JMP,1,VXT_END,
+/* 2459 */ VXI_JMP,VXT_VAL,1,VXT_END,
+/* 2463 */ VXI_BEQL,VXT_JMP,1,VXT_END,
+/* 2467 */ VXI_BNEQ,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END,
+/* 2474 */ VXI_BNEQ,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END,
+/* 2481 */ VXI_BGEQ,VXT_JMP,1,VXT_END,
+/* 2485 */ VXI_BLSS,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END,
+/* 2492 */ VXI_BLSS,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END,
+/* 2499 */ VXI_BGTR,VXT_JMP,1,VXT_END,
+/* 2503 */ VXI_BLEQ,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END,
+/* 2510 */ VXI_BLEQ,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END,
+/* 2517 */ VXI_BLEQ,VXT_JMP,1,VXT_END,
+/* 2521 */ VXI_BGTR,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END,
+/* 2528 */ VXI_BGTR,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END,
+/* 2535 */ VXI_BLSS,VXT_JMP,1,VXT_END,
+/* 2539 */ VXI_BGEQ,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END,
+/* 2546 */ VXI_BGEQ,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END,
+/* 2553 */ VXI_BNEQ,VXT_JMP,1,VXT_END,
+/* 2557 */ VXI_BNEQ,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END,
+/* 2564 */ VXI_BEQL,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END,
+/* 2571 */ VXI_BLBC,VXT_REG,0x5A,VXT_JMP,1,VXT_END,
+/* 2577 */ VXI_BLBS,VXT_REG,0x5A,VXT_LIT,6,VXI_JMP,VXT_JMP,1,
+/* 2585 */ VXT_END,
+/* 2586 */ VXI_BLBS,VXT_REG,0x5A,VXT_LIT,3,VXI_BRW,VXT_JMP,1,
+/* 2594 */ VXT_END,
+/* 2595 */ VXI_BLBS,VXT_REG,0x5A,VXT_JMP,1,VXT_END,
+/* 2601 */ VXI_BLBC,VXT_REG,0x5A,VXT_LIT,6,VXI_JMP,VXT_JMP,1,
+/* 2609 */ VXT_END,
+/* 2610 */ VXI_BLBC,VXT_REG,0x5A,VXT_LIT,3,VXI_BRW,VXT_JMP,1,
+/* 2618 */ VXT_END,
+/* 2619 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,7,VXI_PUSHL,VXT_VAL,
+/* 2627 */ 6,VXI_PUSHAB,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL,
+/* 2635 */ VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,
+/* 2643 */ VXT_XFER,SIZEOF(char *) * (short int)xf_job,VXT_END,
+/* 2646 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_kill,
+/* 2654 */ VXT_END,
+/* 2655 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_killalias,
+/* 2663 */ VXT_END,
+/* 2664 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_killall,VXT_END,
+/* 2670 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_killaliasall,VXT_END,
+/* 2676 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
+/* 2684 */ 3,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_labaddr,VXI_MOVL,VXT_REG,
+/* 2692 */ 0x50,VXT_ADDR,0,VXT_END,
+/* 2696 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lckdecr,
+/* 2704 */ VXT_END,
+/* 2705 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lckincr,
+/* 2713 */ VXT_END,
+/* 2714 */ VXI_MOVAB,VXT_JMP,1,VXT_ADDR,0,VXT_END,
+/* 2720 */ VXI_MOVAB,VXT_JMP,1,VXT_ADDR,0,VXT_END,
+/* 2726 */ VXI_MOVAB,VXT_JMP,1,VXT_ADDR,0,VXT_END,
+/* 2732 */ VXT_IREPL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,
+/* 2740 */ SIZEOF(char *) * (short int)xf_linefetch,VXT_END,
+/* 2742 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_linestart,VXT_END,
+/* 2746 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
+/* 2754 */ 2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lkname,VXT_END,
+/* 2761 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_lkinit,VXT_END,
+/* 2767 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
+/* 2775 */ 2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lkname,VXT_END,
+/* 2782 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lock,
+/* 2790 */ VXT_END,
+/* 2791 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
+/* 2799 */ 2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lvpatwrite,VXT_END,
+/* 2806 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lvzwithdraw,
+/* 2814 */ VXT_END,
+/* 2815 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,
+/* 2823 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_lvzwrite,VXT_END,
+/* 2827 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 2835 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_flt_mod,VXT_END,
+/* 2842 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 2850 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_mul,VXT_END,
+/* 2857 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,1,
+/* 2865 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_neg,VXT_END,
+/* 2871 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_newintrinsic,VXT_END,
+/* 2878 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_newvar,VXT_END,
+/* 2885 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_nullexp,
+/* 2893 */ VXT_END,
+/* 2894 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2,
+/* 2902 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_numcmp,VXT_END,
+/* 2908 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
+/* 2916 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
+/* 2924 */ VXT_LIT,4,VXT_XFER,SIZEOF(char *) * (short int)xf_open,VXT_END,
+/* 2929 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2,
+/* 2937 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_pattern,VXT_END,
+/* 2943 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 2951 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnpopulation,VXT_END,
+/* 2958 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 2966 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpopulation,VXT_END,
+/* 2973 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_putindx,
+/* 2981 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END,
+/* 2987 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
+/* 2995 */ 0,VXI_CALLS,VXT_LIT,2,VXT_XFER,SIZEOF(char *) * (short int)xf_rdone,VXT_END,
+/* 3002 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
+/* 3010 */ 0,VXI_CALLS,VXT_LIT,2,VXT_XFER,SIZEOF(char *) * (short int)xf_read,VXT_END,
+/* 3017 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,
+/* 3025 */ 1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,3,VXT_XFER,
+/* 3033 */ SIZEOF(char *) * (short int)xf_readfl,VXT_END,
+/* 3035 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_END,
+/* 3039 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_ret,VXT_END,
+/* 3043 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVL,VXT_VAL,2,
+/* 3051 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_retarg,VXT_END,
+/* 3057 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3065 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_rhdaddr,VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,
+/* 3073 */ VXT_END,
+/* 3074 */ VXI_PUSHL,VXT_LIT,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3082 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_rhdaddr,VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,
+/* 3090 */ VXT_END,
+/* 3091 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,
+/* 3099 */ SIZEOF(char *) * (short int)xf_rterror,VXT_END,
+/* 3101 */ VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT,
+/* 3109 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setals2als,VXT_END,
+/* 3113 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT,
+/* 3121 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setalsin2alsct,VXT_END,
+/* 3125 */ VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT,
+/* 3133 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setalsctin2als,VXT_END,
+/* 3137 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT,
+/* 3145 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setalsct2alsct,VXT_END,
+/* 3149 */ VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT,
+/* 3157 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setfnretin2als,VXT_END,
+/* 3161 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT,
+/* 3169 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setfnretin2alsct,VXT_END,
+/* 3173 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
+/* 3181 */ 2,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
+/* 3189 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setextract,VXT_END,
+/* 3194 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
+/* 3202 */ 4,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
+/* 3210 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setp1,VXT_END,
+/* 3215 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
+/* 3223 */ 3,VXI_PUSHAB,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,
+/* 3231 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,6,VXT_XFER,SIZEOF(char *) * (short int)xf_setpiece,VXT_END,
+/* 3239 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
+/* 3247 */ 2,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
+/* 3255 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setzextract,VXT_END,
+/* 3260 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
+/* 3268 */ 4,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
+/* 3276 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setzp1,VXT_END,
+/* 3281 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
+/* 3289 */ 3,VXI_PUSHAB,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,
+/* 3297 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,6,VXT_XFER,SIZEOF(char *) * (short int)xf_setzpiece,VXT_END,
+/* 3305 */ VXI_BISB2,VXT_LIT,1,VXT_REG,0x5A,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_dt_true,
+/* 3313 */ VXT_END,
+/* 3314 */ VXI_PUSHL,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
+/* 3322 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,3,VXI_CALLS,
+/* 3330 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setzbrk,VXT_END,
+/* 3335 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2,
+/* 3343 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_sorts_after,VXT_END,
+/* 3349 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_srchindx,
+/* 3357 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END,
+/* 3363 */ VXI_MOVAB,VXT_VAL,2,VXT_REG,0x51,VXI_MOVAB,VXT_VAL,1,
+/* 3371 */ VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_sto,VXT_END,
+/* 3377 */ VXI_MOVC3,VXT_LIT,16,VXT_VAL,2,VXT_VAL,1,VXT_END,
+/* 3385 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_MOVAB,VXT_VAL,0,
+/* 3393 */ VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_sto,VXT_END,
+/* 3399 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 3407 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_sub,VXT_END,
+/* 3414 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3422 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_svget,VXT_END,
+/* 3426 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,
+/* 3434 */ SIZEOF(char *) * (short int)xf_psvput,VXT_END,
+/* 3436 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3444 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_svput,VXT_END,
+/* 3448 */ VXI_MOVL,VXT_REG,0x50,VXT_REG,0x5A,VXT_END,
+/* 3454 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_tcommit,VXT_END,
+/* 3458 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_trollback,VXT_END,
+/* 3465 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_trestart,VXT_END,
+/* 3472 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
+/* 3480 */ 2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_tstart,VXT_END,
+/* 3488 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_unlock,VXT_END,
+/* 3494 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3502 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_use,VXT_END,
+/* 3506 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_view,
+/* 3514 */ VXT_END,
+/* 3515 */ VXI_CMPL,VXT_VAL,1,VXT_VAL,2,VXT_END,
+/* 3521 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_write,
+/* 3529 */ VXT_END,
+/* 3530 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_wteol,
+/* 3538 */ VXT_END,
+/* 3539 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_wtff,VXT_END,
+/* 3545 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_wtone,
+/* 3553 */ VXT_END,
+/* 3554 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_wttab,
+/* 3562 */ VXT_END,
+/* 3563 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_xkill,
+/* 3571 */ VXT_END,
+/* 3572 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,
+/* 3580 */ SIZEOF(char *) * (short int)xf_xnew,VXT_END,
+/* 3582 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zallocate,
+/* 3590 */ VXT_END,
+/* 3591 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3599 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_zattach,VXT_END,
+/* 3603 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3611 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zcompile,VXT_END,
+/* 3615 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zcont,VXT_END,
+/* 3619 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zdeallocate,
+/* 3627 */ VXT_END,
+/* 3628 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 3636 */ 1,VXI_CALLS,VXT_LIT,2,VXT_XFER,SIZEOF(char *) * (short int)xf_zedit,VXT_END,
+/* 3643 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zg1,VXT_END,
+/* 3650 */ VXI_PUSHL,VXT_VAL,1,VXI_PUSHL,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,
+/* 3658 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zgoto,VXT_END,
+/* 3666 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zhalt,
+/* 3674 */ VXT_END,
+/* 3675 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3683 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zhelp,VXT_END,
+/* 3687 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3695 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zlink,VXT_END,
+/* 3699 */ VXT_IREPAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL,2,VXI_CALLS,VXT_VAL,
+/* 3707 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_zmess,VXT_END,
+/* 3711 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zprevious,
+/* 3719 */ VXT_END,
+/* 3720 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,
+/* 3728 */ 4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,
+/* 3736 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_zprint,VXT_END,
+/* 3744 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_LIT,0,VXI_PUSHL,VXT_VAL,
+/* 3752 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,3,VXT_XFER,
+/* 3760 */ SIZEOF(char *) * (short int)xf_zshow,VXT_END,
+/* 3762 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
+/* 3770 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,3,VXT_XFER,
+/* 3778 */ SIZEOF(char *) * (short int)xf_zshow,VXT_END,
+/* 3780 */ VXI_PUSHL,VXT_LIT,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3788 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zstep,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zcont,VXT_END,
+/* 3795 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3803 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zstep,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zcont,VXT_END,
+/* 3810 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3818 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_zsystem,VXT_END,
+/* 3822 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_ztcommit,
+/* 3830 */ VXT_END,
+/* 3831 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_ztstart,VXT_END,
+/* 3837 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_merge,VXT_END,
+/* 3843 */ VXI_PUSHL,VXT_LIT,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3851 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_merge_arg,VXT_END,
+/* 3855 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3863 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_merge_arg,VXT_END,
+/* 3867 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_JSB,VXT_XFER,
+/* 3875 */ SIZEOF(char *) * (short int)xf_indmerge,VXT_END,
+/* 3877 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_m_srchindx,
+/* 3885 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END,
+/* 3891 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 3899 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzconvert2,VXT_END,
+/* 3906 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
+/* 3914 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 3922 */ SIZEOF(char *) * (short int)xf_fnzconvert3,VXT_END,
+/* 3924 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
+/* 3932 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 3940 */ SIZEOF(char *) * (short int)xf_fnzsubstr,VXT_END,
+/* 3942 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3950 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzwidth,VXT_END,
+/* 3954 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_ztrigger,VXT_END,
+/* 3960 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zwritesvn,
+/* 3968 */ VXT_END,
+/* 3969 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3977 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzwrite,VXT_END,
+/* 3981 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_igetdst,VXI_MOVL,VXT_REG,0x50,
+/* 3989 */ VXT_ADDR,0,VXT_END,
+/* 3992 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 4000 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_indget1,VXT_END,
+/* 4004 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_glvnpop,
+/* 4012 */ VXT_END,
+/* 4013 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_glvnslot,
+/* 4021 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END,
+/* 4027 */ VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 4035 */ 1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indsavglvn,VXT_END,
+/* 4040 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
+/* 4048 */ SIZEOF(char *) * (short int)xf_indsavlvn,VXT_END,
+/* 4050 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 4058 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_rfrshlvn,VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,
+/* 4066 */ VXT_END,
+/* 4067 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_savgvn,
+/* 4075 */ VXT_END,
+/* 4076 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_savlvn,
+/* 4084 */ VXT_END,
+/* 4085 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 4093 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_shareslot,VXT_END,
+/* 4097 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 4105 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_stoglvn,VXT_END,
+/* 4109 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 4117 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_rfrshgvn,VXT_END,
+/* 4121 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
+/* 4129 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_indfnname2,VXT_END,
+/* 4136 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,
+/* 4144 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_indget2,VXT_END,
+/* 4148 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_indmerge2,
+/* 4156 */ VXT_END,
+/* 4157 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
+/* 4165 */ 3,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
+/* 4173 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpeek,VXT_END,
+/* 4178 */ 360,374,367,2447,2455,2451,2714,2726,
+/* 4186 */ 2720,0,0,0,481,457,448,0,
+/* 4194 */ 0,444,1965,2003,1984,2595,2610,2601,
+/* 4202 */ 2571,2586,2577,2463,2474,2467,2553,2564,
+/* 4210 */ 2557,2499,2510,2503,2517,2528,2521,2535,
+/* 4218 */ 2546,2539,2481,2492,2485,1944,1958,1951,
+/* 4226 */ 381,395,388};
diff --git a/sr_linux/gtm_env_sp.csh b/sr_linux/gtm_env_sp.csh
index 09eac89..eff718d 100644
--- a/sr_linux/gtm_env_sp.csh
+++ b/sr_linux/gtm_env_sp.csh
@@ -1,6 +1,6 @@
#################################################################
# #
-# Copyright 2001, 2012 Fidelity Information Services, Inc #
+# Copyright 2001, 2013 Fidelity Information Services, Inc #
# #
# This source code contains the intellectual property #
# of its copyright holder(s), and is made available #
diff --git a/sr_linux/gtm_system.c b/sr_linux/gtm_system.c
deleted file mode 100644
index a600659..0000000
--- a/sr_linux/gtm_system.c
+++ /dev/null
@@ -1,27 +0,0 @@
-/****************************************************************
-* *
-* Copyright 2007 Fidelity Information Services, Inc *
-* *
-* This source code contains the intellectual property *
-* of its copyright holder(s), and is made available *
-* under a license. If you do not know the terms of *
-* the license, please stop and do not read further. *
-* *
-****************************************************************/
-
-#ifdef __CYGWIN__
-
-/* The version of system() included in Cygwin 1.54-2 *
- * (aka newlib libc/stdlib/system.c 1.8) does not properly *
- * handle signals or EINTR. For proper functioning of GT.M, *
- * replace this routine with a good version of system() *
- * until a Cygwin version fixes this problem. *
-*/
-
-#include "gtm_stdlib.h"
-
-int gtm_system(const char *line)
-{
- return system(line);
-}
-#endif
diff --git a/sr_linux/release_name.h b/sr_linux/release_name.h
index 8a6cc25..e2eb210 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.0-001 CYGWIN x86"
+#define GTM_RELEASE_NAME "GT.M V6.0-003 CYGWIN x86"
#elif defined(__ia64)
-#define GTM_RELEASE_NAME "GT.M V6.0-001 Linux IA64"
+#define GTM_RELEASE_NAME "GT.M V6.0-003 Linux IA64"
#elif defined(__x86_64__)
-#define GTM_RELEASE_NAME "GT.M V6.0-001 Linux x86_64"
+#define GTM_RELEASE_NAME "GT.M V6.0-003 Linux x86_64"
#elif defined(__s390__)
-#define GTM_RELEASE_NAME "GT.M V6.0-001 Linux S390X"
+#define GTM_RELEASE_NAME "GT.M V6.0-003 Linux S390X"
#else
-#define GTM_RELEASE_NAME "GT.M V6.0-001 Linux x86"
+#define GTM_RELEASE_NAME "GT.M V6.0-003 Linux x86"
#endif
#define GTM_PRODUCT "GT.M"
#define GTM_VERSION "V6.0"
diff --git a/sr_port/actuallist.c b/sr_port/actuallist.c
index 3a57938..cc8c3d0 100644
--- a/sr_port/actuallist.c
+++ b/sr_port/actuallist.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -28,7 +28,6 @@ error_def(ERR_SIDEEFFECTEVAL);
int actuallist (oprtype *opr)
{
boolean_t se_warn;
- char source_line_buff[MAX_SRCLINE + SIZEOF(ARROW)];
int i, j, mask, parmcount;
oprtype ot;
triple *counttrip, *masktrip, *ref0, *ref1, *ref2;
@@ -120,11 +119,7 @@ error_def(ERR_SIDEEFFECTEVAL);
ref0->operand[0].oprval.tref = ref1;
dqins(ref0, exorder, ref1); /* NOTE:this violates information hiding */
if (se_warn)
- {
- TREF(last_source_column) = ref0->src.column;
- show_source_line(source_line_buff, SIZEOF(source_line_buff), TRUE);
- dec_err(VARLSTCNT(1) ERR_SIDEEFFECTEVAL);
- }
+ ISSUE_SIDEEFFECTEVAL_WARNING(ref0->src.column);
}
}
/* the following asserts check we're getting only TRIP_REF or empty operands */
diff --git a/sr_port/advancewindow.c b/sr_port/advancewindow.c
index bcbdfad..6329e7c 100644
--- a/sr_port/advancewindow.c
+++ b/sr_port/advancewindow.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -52,7 +52,7 @@ static readonly unsigned char apos_ok[] =
void advancewindow(void)
{
unsigned char *cp1, *cp2, *cp3, x;
- char *tmp, source_line_buff[MAX_SRCLINE + SIZEOF(ARROW)];
+ char *tmp;
int y, charlen;
# ifdef UNICODE_SUPPORTED
uint4 ch;
@@ -96,7 +96,7 @@ void advancewindow(void)
}
if (!run_time)
{
- show_source_line(source_line_buff, SIZEOF(source_line_buff), TRUE);
+ show_source_line(TRUE);
dec_err(VARLSTCNT(1) ERR_LITNONGRAPH);
}
}
diff --git a/sr_port/alloc_reg.c b/sr_port/alloc_reg.c
index 197277e..d25d2b4 100644
--- a/sr_port/alloc_reg.c
+++ b/sr_port/alloc_reg.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -42,10 +42,12 @@ LITDEF int4 sa_class_sizes[VALUED_REF_TYPES] =
};
LITREF octabstruct oc_tab[];
-#define MAX_TEMP_COUNT 128 /* bad things, which need investigation, happen if we raise this above 1024 */
+#define MAX_TEMP_COUNT 1024
error_def(ERR_TMPSTOREMAX);
+STATICFNDCL void remove_backptr(triple *curtrip, oprtype *opnd, char (*tempcont)[MAX_TEMP_COUNT]);
+
void alloc_reg(void)
{
triple *x, *y, *ref;
@@ -101,7 +103,7 @@ void alloc_reg(void)
# ifdef DEBUG
for (c = temphigh[TVAL_REF]; 0 <= c; c--)
assert(0 == tempcont[TVAL_REF][c]); /* check against leaking TVAL temps */
- if (OC_LINESTART == opc)
+ if (OC_LINESTART == opc)
break;
# endif
case OC_FETCH:
@@ -139,40 +141,14 @@ void alloc_reg(void)
}
break;
}
- for (j = x->operand, y = x; j < ARRAYTOP(y->operand); )
- {
- if (TRIP_REF == j->oprclass)
- {
- ref = j->oprval.tref;
- if (OC_PARAMETER == ref->opcode)
- {
- y = ref;
- j = y->operand;
- continue;
- }
- if (r = ref->destination.oprclass) /* Note assignment */
- {
- dqloop(&ref->backptr, que, b)
- {
- if (b->bpt == y)
- {
- dqdel(b, que);
- break;
- }
- }
- if ((ref->backptr.que.fl == &ref->backptr) && (TVAR_REF != r))
- tempcont[r][j->oprval.tref->destination.oprval.temp] = 0;
- }
- }
- j++;
- }
if (OC_PASSTHRU == x->opcode)
{
COMPDBG(PRINTF(" *** OC_PASSTHRU opcode being NOOP'd\n"););
+ remove_backptr(x, &x->operand[0], tempcont);
x->opcode = OC_NOOP;
continue;
}
- if (!(dest_type = x->destination.oprclass)) /* Note assignment */
+ if (NO_REF == (dest_type = x->destination.oprclass)) /* Note assignment */
{
oct = oc_tab[opc].octype;
if ((oct & OCT_VALUE) && (x->backptr.que.fl != &x->backptr) && !(oct & OCT_CGSKIP))
@@ -194,7 +170,7 @@ void alloc_reg(void)
for (c = 0; tempcont[r][c] && (MAX_TEMP_COUNT > c); c++)
;
if (MAX_TEMP_COUNT <= c)
- rts_error(VARLSTCNT(1) ERR_TMPSTOREMAX);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_TMPSTOREMAX);
tempcont[r][c] = 1;
x->destination.oprclass = r;
x->destination.oprval.temp = c;
@@ -209,6 +185,27 @@ void alloc_reg(void)
assert(x->destination.oprval.tref->destination.oprclass);
x->destination = x->destination.oprval.tref->destination;
}
+ for (j = x->operand, y = x; j < ARRAYTOP(y->operand); )
+ { /* Loop through all the parameters of the current opcode. For each parameter that requires an intermediate
+ * temporary, decrement (this is what remove_backptr does) the "reference count" -- opcodes yet to be
+ * processed that still need the intermediate result -- and if that number is zero, mark the temporary
+ * available. We can then reuse the temp to hold the results of subsequent opcodes. Note that remove_backptr
+ * is essentially the resolve_tref() in resolve_ref.c. resolve_tref increments the "reference count",
+ * while remove_backptr decrements it.
+ */
+ if (TRIP_REF == j->oprclass)
+ {
+ ref = j->oprval.tref;
+ if (OC_PARAMETER == ref->opcode)
+ {
+ y = ref;
+ j = y->operand;
+ continue;
+ }
+ remove_backptr(y, j, tempcont);
+ }
+ j++;
+ }
}
for (r = 0; VALUED_REF_TYPES > r; r++)
sa_temps[r] = temphigh[r] + 1;
@@ -223,3 +220,33 @@ void alloc_reg(void)
size += sa_temps[TCAD_REF] * sa_class_sizes[TCAD_REF];
sa_temps_offset[TCAD_REF] = size;
}
+
+void remove_backptr(triple *curtrip, oprtype *opnd, char (*tempcont)[MAX_TEMP_COUNT])
+{
+ triple *ref;
+ tbp *b;
+ int r;
+
+ assert(TRIP_REF == opnd->oprclass);
+ ref = opnd->oprval.tref;
+ while (OC_PASSTHRU == opnd->oprval.tref->opcode)
+ {
+ ref = ref->operand[0].oprval.tref;
+ opnd = &ref->operand[0];
+ assert(TRIP_REF == opnd->oprclass);
+ }
+ r = ref->destination.oprclass;
+ if (NO_REF != r)
+ {
+ dqloop(&ref->backptr, que, b)
+ {
+ if (b->bpt == curtrip)
+ {
+ dqdel(b, que);
+ break;
+ }
+ }
+ if ((ref->backptr.que.fl == &ref->backptr) && (TVAR_REF != r))
+ tempcont[r][ref->destination.oprval.temp] = 0;
+ }
+}
diff --git a/sr_port/anticipatory_freeze.h b/sr_port/anticipatory_freeze.h
index e398128..ef51450 100644
--- a/sr_port/anticipatory_freeze.h
+++ b/sr_port/anticipatory_freeze.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2012 Fidelity Information Services, Inc *
+ * Copyright 2012, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -24,22 +24,22 @@
#include "wait_for_disk_space.h" /* needed by DB_LSEEKWRITE macro for prototype */
#include "gtmimagename.h" /* needed for IS_GTM_IMAGE */
-boolean_t is_anticipatory_freeze_needed(int msg_id);
-void set_anticipatory_freeze(int msg_id);
+boolean_t is_anticipatory_freeze_needed(sgmnt_addrs *csa, int msg_id);
+void set_anticipatory_freeze(sgmnt_addrs *csa, int msg_id);
boolean_t init_anticipatory_freeze_errors(void);
/* Define function pointers to certain functions to avoid executables like gtmsecshr from unnecessarily
* linking with these functions (which causes the database/replication stuff to be pulled in).
*/
-typedef boolean_t (*is_anticipatory_freeze_needed_t)(int msgid);
-typedef void (*set_anticipatory_freeze_t)(int msg_id);
+typedef boolean_t (*is_anticipatory_freeze_needed_t)(sgmnt_addrs *csa, int msgid);
+typedef void (*set_anticipatory_freeze_t)(sgmnt_addrs *csa, int msg_id);
GBLREF is_anticipatory_freeze_needed_t is_anticipatory_freeze_needed_fnptr;
GBLREF set_anticipatory_freeze_t set_anticipatory_freeze_fnptr;
GBLREF boolean_t pool_init;
GBLREF boolean_t mupip_jnl_recover;
#ifdef DEBUG
-GBLREF uint4 lseekwrite_target;
+GBLREF uint4 lseekwrite_target;
#endif
error_def(ERR_MUINSTFROZEN);
@@ -49,6 +49,7 @@ error_def(ERR_MUNOACTION);
error_def(ERR_REPLINSTFREEZECOMMENT);
error_def(ERR_REPLINSTFROZEN);
error_def(ERR_REPLINSTUNFROZEN);
+error_def(ERR_TEXT);
#define ENABLE_FREEZE_ON_ERROR \
@@ -60,35 +61,36 @@ error_def(ERR_REPLINSTUNFROZEN);
} \
}
-#define CHECK_IF_FREEZE_ON_ERROR_NEEDED(MSG_ID, FREEZE_NEEDED, FREEZE_MSG_ID) \
-{ \
- GBLREF jnlpool_addrs jnlpool; \
- DCL_THREADGBL_ACCESS; \
- \
- SETUP_THREADGBL_ACCESS; \
- if (!FREEZE_NEEDED && ANTICIPATORY_FREEZE_AVAILABLE && (NULL != is_anticipatory_freeze_needed_fnptr)) \
- { /* NOT gtmsecshr */ \
- if (IS_REPL_INST_UNFROZEN && (*is_anticipatory_freeze_needed_fnptr)(MSG_ID)) \
- { \
- FREEZE_NEEDED = TRUE; \
- FREEZE_MSG_ID = MSG_ID; \
- } \
- } \
-}
-
-#define FREEZE_INSTANCE_IF_NEEDED(FREEZE_NEEDED, FREEZE_MSG_ID) \
+#define CHECK_IF_FREEZE_ON_ERROR_NEEDED(CSA, MSG_ID, FREEZE_NEEDED, FREEZE_MSG_ID) \
{ \
GBLREF jnlpool_addrs jnlpool; \
+ DCL_THREADGBL_ACCESS; \
\
- if (FREEZE_NEEDED) \
- { \
- assert(NULL != set_anticipatory_freeze_fnptr); \
- (*set_anticipatory_freeze_fnptr)(FREEZE_MSG_ID); \
- send_msg(VARLSTCNT(3) ERR_REPLINSTFROZEN, 1, jnlpool.repl_inst_filehdr->inst_info.this_instname); \
- send_msg(VARLSTCNT(3) ERR_REPLINSTFREEZECOMMENT, 1, jnlpool.jnlpool_ctl->freeze_comment); \
+ SETUP_THREADGBL_ACCESS; \
+ if (!FREEZE_NEEDED && ANTICIPATORY_FREEZE_AVAILABLE && (NULL != is_anticipatory_freeze_needed_fnptr)) \
+ { /* NOT gtmsecshr */ \
+ if (IS_REPL_INST_UNFROZEN && (*is_anticipatory_freeze_needed_fnptr)((sgmnt_addrs *)CSA, MSG_ID)) \
+ { \
+ FREEZE_NEEDED = TRUE; \
+ FREEZE_MSG_ID = MSG_ID; \
+ } \
} \
}
+#define FREEZE_INSTANCE_IF_NEEDED(CSA, FREEZE_NEEDED, FREEZE_MSG_ID) \
+{ \
+ GBLREF jnlpool_addrs jnlpool; \
+ \
+ if (FREEZE_NEEDED) \
+ { \
+ assert(NULL != set_anticipatory_freeze_fnptr); \
+ (*set_anticipatory_freeze_fnptr)((sgmnt_addrs *)CSA, FREEZE_MSG_ID); \
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_REPLINSTFROZEN, 1, \
+ jnlpool.repl_inst_filehdr->inst_info.this_instname); \
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_REPLINSTFREEZECOMMENT, 1, jnlpool.jnlpool_ctl->freeze_comment); \
+ } \
+}
+
#define CLEAR_ANTICIPATORY_FREEZE(FREEZE_CLEARED) \
{ \
GBLREF jnlpool_addrs jnlpool; \
@@ -100,12 +102,13 @@ error_def(ERR_REPLINSTUNFROZEN);
} \
}
-#define REPORT_INSTANCE_UNFROZEN(FREEZE_CLEARED) \
-{ \
- GBLREF jnlpool_addrs jnlpool; \
- \
- if (FREEZE_CLEARED) \
- send_msg(VARLSTCNT(3) ERR_REPLINSTUNFROZEN, 1, jnlpool.repl_inst_filehdr->inst_info.this_instname); \
+#define REPORT_INSTANCE_UNFROZEN(FREEZE_CLEARED) \
+{ \
+ GBLREF jnlpool_addrs jnlpool; \
+ \
+ if (FREEZE_CLEARED) \
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_REPLINSTUNFROZEN, 1, \
+ jnlpool.repl_inst_filehdr->inst_info.this_instname); \
}
#define AFREEZE_MASK 0x01
@@ -123,16 +126,22 @@ error_def(ERR_REPLINSTUNFROZEN);
#define INST_FROZEN_COMMENT "PID %d encountered %s; Instance frozen"
-#define GENERATE_INST_FROZEN_COMMENT(BUF, BUF_LEN, MSG_ID) \
-{ \
- GBLREF uint4 process_id; \
- const err_ctl *ctl; \
- const err_msg *msginfo; \
- \
- ctl = err_check(MSG_ID); \
- assert(NULL != ctl); \
- GET_MSG_INFO(MSG_ID, ctl, msginfo); \
- SNPRINTF(BUF, BUF_LEN, INST_FROZEN_COMMENT, process_id, msginfo->tag); \
+#define MSGID_TO_ERRMSG(MSG_ID, ERRMSG) \
+{ \
+ const err_ctl *ctl; \
+ \
+ ctl = err_check(MSG_ID); \
+ assert(NULL != ctl); \
+ GET_MSG_INFO(MSG_ID, ctl, ERRMSG); \
+}
+
+#define GENERATE_INST_FROZEN_COMMENT(BUF, BUF_LEN, MSG_ID) \
+{ \
+ GBLREF uint4 process_id; \
+ const err_msg *msginfo; \
+ \
+ MSGID_TO_ERRMSG(MSG_ID, msginfo); \
+ SNPRINTF(BUF, BUF_LEN, INST_FROZEN_COMMENT, process_id, msginfo->tag); \
}
/* This is a version of the macro which waits for the instance freeze to be lifted off assuming the process has
@@ -157,14 +166,14 @@ error_def(ERR_REPLINSTUNFROZEN);
if (!IS_GTM_IMAGE) \
{ \
GET_CUR_TIME; \
- gtm_putmsg(VARLSTCNT(7) ERR_MUINSTFROZEN, 5, CTIME_BEFORE_NL, time_ptr, \
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_MUINSTFROZEN, 5, CTIME_BEFORE_NL, time_ptr, \
jnlpool.repl_inst_filehdr->inst_info.this_instname, DB_LEN_STR(reg)); \
} \
WAIT_FOR_REPL_INST_UNFREEZE_NOCSA; \
if (!IS_GTM_IMAGE) \
{ \
GET_CUR_TIME; \
- gtm_putmsg(VARLSTCNT(7) ERR_MUINSTUNFROZEN, 5, CTIME_BEFORE_NL, time_ptr, \
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_MUINSTUNFROZEN, 5, CTIME_BEFORE_NL, time_ptr, \
jnlpool.repl_inst_filehdr->inst_info.this_instname, DB_LEN_STR(reg)); \
} \
} \
@@ -196,11 +205,12 @@ error_def(ERR_REPLINSTUNFROZEN);
{ \
if (exit_state != 0) \
{ \
- send_msg(VARLSTCNT(1) forced_exit_err); \
- gtm_putmsg(VARLSTCNT(1) forced_exit_err); \
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(1) forced_exit_err); \
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) forced_exit_err); \
exit(-exi_condition); \
} \
SHORT_SLEEP(SLEEP_INSTFREEZEWAIT); \
+ DEBUG_ONLY(CLEAR_FAKE_ENOSPC_IF_MASTER_DEAD); \
} \
}
#define WAIT_FOR_REPL_INST_UNFREEZE_NOCSA_SAFE \
@@ -258,13 +268,34 @@ error_def(ERR_REPLINSTUNFROZEN);
#ifdef DEBUG
#define FAKE_ENOSPC(CSA, FAKE_WHICH_ENOSPC, LSEEKWRITE_TARGET, LCL_STATUS) \
{ \
- if (!IS_DSE_IMAGE) /*DSE does not freeze so let it work as normal */ \
- if ((NULL != CSA) && (NULL != ((sgmnt_addrs *)CSA)->nl) && ((sgmnt_addrs *)CSA)->nl->FAKE_WHICH_ENOSPC) \
+ GBLREF jnlpool_addrs jnlpool; \
+ if (NULL != CSA) \
+ { \
+ if (WBTEST_ENABLED(WBTEST_RECOVER_ENOSPC)) \
+ { /* This test case is only used by mupip */ \
+ gtm_wbox_input_test_case_count++; \
+ if ((0 != gtm_white_box_test_case_count) \
+ && (gtm_white_box_test_case_count <= gtm_wbox_input_test_case_count)) \
+ { \
+ LCL_STATUS = ENOSPC; \
+ if (gtm_white_box_test_case_count == gtm_wbox_input_test_case_count) \
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TEXT, 2, \
+ LEN_AND_LIT("Turning on fake ENOSPC for exit status test")); \
+ } \
+ } else if (!IS_DSE_IMAGE /*DSE does not freeze so let it work as normal */ \
+ && ((NULL != jnlpool.jnlpool_ctl) && (NULL != ((sgmnt_addrs *)CSA)->nl)) \
+ && ((sgmnt_addrs *)CSA)->nl->FAKE_WHICH_ENOSPC) \
{ \
LCL_STATUS = ENOSPC; \
lseekwrite_target = LSEEKWRITE_TARGET; \
} \
+ } \
}
+
+void clear_fake_enospc_if_master_dead(void);
+
+#define CLEAR_FAKE_ENOSPC_IF_MASTER_DEAD clear_fake_enospc_if_master_dead()
+
#else
#define FAKE_ENOSPC(CSA, FAKE_ENOSPC, LSEEKWRITE_TARGET, LCL_STATUS) {}
#endif
@@ -287,12 +318,12 @@ error_def(ERR_REPLINSTUNFROZEN);
if (ENOSPC == lcl_status) \
{ \
wait_for_disk_space(csa, (char *)fnptr, fd, (off_t)new_eof, (char *)buff, (size_t)size, &lcl_status); \
- assert(!((sgmnt_addrs *)csa)->nl->FAKE_WHICH_ENOSPC || (ENOSPC != lcl_status)); \
+ assert((NULL == csa) || (NULL == ((sgmnt_addrs *)csa)->nl) || !((sgmnt_addrs *)csa)->nl->FAKE_WHICH_ENOSPC \
+ || (ENOSPC != lcl_status)); \
} \
status = lcl_status; \
}
-
/* Currently, writes to replication instance files do NOT trigger instance freeze behavior.
* Neither does a pre-existing instance freeze affect replication instance file writes.
* Hence this is defined as simple LSEEKWRITE.
diff --git a/sr_port/asc_hex2i.c b/sr_port/asc_hex2i.c
index 23577db..6710073 100644
--- a/sr_port/asc_hex2i.c
+++ b/sr_port/asc_hex2i.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -11,24 +11,53 @@
#include "mdef.h"
-unsigned int asc_hex2i(p,len)
-char *p;
-int len;
+LITREF unsigned char lower_to_upper_table[];
+
+unsigned int asc_hex2i(uchar_ptr_t p, int len)
+{
+ uchar_ptr_t c;
+ unsigned char ch;
+ int ret;
+
+ ret = 0;
+ for (c = p + len; c > p; p++)
+ {
+ if (('0' <= *p) && ('9' >= *p))
+ ret = (ret << 4) + (*p - '0');
+ else
+ {
+ ch = lower_to_upper_table[*p];
+ if (('A' <= ch) && ('F' >= ch))
+ ret = (ret << 4) + ch - 'A' + 10;
+ else
+ return (unsigned int)-1;
+ }
+ }
+ return ret;
+}
+
+#ifndef VMS
+/* Routine identical to asc_hex2i() but with 8 byte accumulator and return type */
+gtm_uint64_t asc_hex2l(uchar_ptr_t p, int len)
{
- char *c;
- int ret;
+ uchar_ptr_t c;
+ unsigned char ch;
+ gtm_uint64_t ret;
ret = 0;
for (c = p + len; c > p; p++)
{
- if (*p >= '0' && *p <= '9')
- ret = ret * 16 + *p - '0';
- else if (*p >= 'a' && *p <= 'f')
- ret = ret * 16 + *p - 'a' + 10;
- else if (*p >= 'A' && *p <= 'F')
- ret = ret * 16 + *p - 'A' + 10;
+ if (('0' <= *p) && ('9' >= *p))
+ ret = (ret << 4) + (*p - '0');
else
- return (uint4)-1;
+ {
+ ch = lower_to_upper_table[*p];
+ if (('A' <= ch) && ('F' >= ch))
+ ret = (ret << 4) + ch - 'A' + 10;
+ else
+ return (gtm_uint64_t)-1;
+ }
}
return ret;
}
+#endif
diff --git a/sr_port/bm_getfree.c b/sr_port/bm_getfree.c
index 821d792..6faf3e1 100644
--- a/sr_port/bm_getfree.c
+++ b/sr_port/bm_getfree.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -67,6 +67,9 @@ GBLREF uint4 dollar_tlevel;
GBLREF uint4 update_array_size, cumul_update_array_size;
GBLREF unsigned int t_tries;
+error_def(ERR_DBBADFREEBLKCTR);
+error_def(ERR_DBMBMINCFREFIXED);
+
block_id bm_getfree(block_id orig_hint, boolean_t *blk_used, unsigned int cw_work, cw_set_element *cs, int *cw_depth_ptr)
{
cw_set_element *cs1;
@@ -99,7 +102,7 @@ block_id bm_getfree(block_id orig_hint, boolean_t *blk_used, unsigned int cw_wor
hint = 1;
continue;
}
- if (SS_NORMAL != (status = gdsfilext(cs_data->extension_size, total_blks)))
+ if (SS_NORMAL != (status = GDSFILEXT(cs_data->extension_size, total_blks, TRANS_IN_PROG_TRUE)))
return (status);
if (dba_mm == cs_data->acc_meth)
return (FILE_EXTENDED);
@@ -199,14 +202,21 @@ block_id bm_getfree(block_id orig_hint, boolean_t *blk_used, unsigned int cw_wor
if (hint_cycled)
hint_cycled = (hint_limit < hint_cycled) ? hint_limit: 0;
}
- if ((0 == depth) && (FALSE != cs_addrs->now_crit)) /* if it's from the cw_set, its state is murky */
- bit_clear(bml / BLKS_PER_LMAP, MM_ADDR(cs_data)); /* if crit, repair master map error */
+ if ((0 == depth) && cs_addrs->now_crit) /* if it's from the cw_set, its state is murky */
+ {
+ assert(FALSE);
+ send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(3) ERR_DBMBMINCFREFIXED, 1, bml);
+ bit_clear(bml / BLKS_PER_LMAP, MM_ADDR(cs_data)); /* repair master map error */
+ }
}
- /* If not in the final retry, it is possible that free_bit is >= map_size (e.g. if bitmap block gets recycled). */
- if (map_size <= (uint4)free_bit && CDB_STAGNATE <= t_tries)
- { /* bad free bit */
+ /* If not in the final retry, it is possible that free_bit is >= map_size, e.g., if the buffer holding the bitmap block
+ * gets recycled with a non-bitmap block in which case the bit that bm_find_blk returns could be greater than map_size.
+ * But, this should never happen in final retry.
+ */
+ if ((map_size <= (uint4)free_bit) && (CDB_STAGNATE <= t_tries))
+ { /* Bad free bit. */
assert((NO_FREE_SPACE == free_bit) && (lcnt > local_maps)); /* All maps full, should have extended */
- GTMASSERT;
+ assertpro(FALSE);
}
if (0 != depth)
{
@@ -248,8 +258,6 @@ boolean_t is_free_blks_ctr_ok(void)
sm_uc_ptr_t bmp;
unsigned int local_maps, total_blks, free_blocks;
- error_def(ERR_DBBADFREEBLKCTR);
-
assert(&FILE_INFO(gv_cur_region)->s_addrs == cs_addrs && cs_addrs->hdr == cs_data && cs_addrs->now_crit);
total_blks = (dba_mm == cs_data->acc_meth) ? cs_addrs->total_blks : cs_addrs->ti->total_blks;
local_maps = DIVIDE_ROUND_UP(total_blks, BLKS_PER_LMAP);
@@ -281,7 +289,8 @@ boolean_t is_free_blks_ctr_ok(void)
assert(cs_addrs->ti->free_blocks == free_blocks);
if (cs_addrs->ti->free_blocks != free_blocks)
{
- send_msg(VARLSTCNT(6) ERR_DBBADFREEBLKCTR, 4, DB_LEN_STR(gv_cur_region), cs_addrs->ti->free_blocks, free_blocks);
+ send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(6) ERR_DBBADFREEBLKCTR, 4, DB_LEN_STR(gv_cur_region),
+ cs_addrs->ti->free_blocks, free_blocks);
cs_addrs->ti->free_blocks = free_blocks;
return FALSE;
}
diff --git a/sr_port/bm_setmap.c b/sr_port/bm_setmap.c
index 9d61b9b..e575bf2 100644
--- a/sr_port/bm_setmap.c
+++ b/sr_port/bm_setmap.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -35,13 +35,13 @@
#include "gvcst_map_build.h"
#include "mm_read.h"
-GBLREF gd_region *gv_cur_region;
-GBLREF sgmnt_addrs *cs_addrs;
-GBLREF sgmnt_data_ptr_t cs_data;
-GBLREF char *update_array, *update_array_ptr;
-GBLREF cw_set_element cw_set[];
-GBLREF unsigned char rdfail_detail;
-GBLREF unsigned char *non_tp_jfb_buff_ptr;
+GBLREF gd_region *gv_cur_region;
+GBLREF sgmnt_addrs *cs_addrs;
+GBLREF sgmnt_data_ptr_t cs_data;
+GBLREF char *update_array, *update_array_ptr;
+GBLREF cw_set_element cw_set[];
+GBLREF unsigned char rdfail_detail;
+GBLREF jnl_format_buffer *non_tp_jfb_ptr;
void bm_setmap(block_id bml, block_id blk, int4 busy)
{
@@ -96,8 +96,8 @@ void bm_setmap(block_id bml, block_id blk, int4 busy)
if (JNL_ENABLED(cs_data))
{
cse = (cw_set_element *)(&cw_set[0]);
- cse->new_buff = non_tp_jfb_buff_ptr;
- memcpy(non_tp_jfb_buff_ptr, bmp, ((blk_hdr_ptr_t)bmp)->bsiz);
+ cse->new_buff = (unsigned char *)non_tp_jfb_ptr->buff;
+ memcpy(cse->new_buff, bmp, ((blk_hdr_ptr_t)bmp)->bsiz);
gvcst_map_build((uint4 *)cse->upd_addr, (uchar_ptr_t)cse->new_buff, cse, cs_addrs->ti->curr_tn);
cse->done = TRUE;
}
diff --git a/sr_port/bt_init.c b/sr_port/bt_init.c
index d86ea85..2eb0b1e 100644
--- a/sr_port/bt_init.c
+++ b/sr_port/bt_init.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -16,14 +16,17 @@
#include "gdsbt.h"
#include "gdsfhead.h"
-void bt_init(sgmnt_addrs *cs)
+void bt_init(sgmnt_addrs *csa)
{
- sgmnt_data_ptr_t base;
+ sgmnt_data_ptr_t csd;
- base = cs->hdr;
- cs->ti = &base->trans_hist;
- cs->bt_header = (bt_rec_ptr_t)((sm_uc_ptr_t) base + cs->nl->bt_header_off);
- cs->bt_base = (bt_rec_ptr_t)((sm_uc_ptr_t) base + cs->nl->bt_base_off);
- cs->th_base = (th_rec_ptr_t)((sm_uc_ptr_t) base + cs->nl->th_base_off);
+ csd = csa->hdr;
+ csa->ti = &csd->trans_hist;
+ if (dba_mm != csd->acc_meth)
+ { /* BT structures are NOT maintained for MM */
+ csa->bt_header = (bt_rec_ptr_t)((sm_uc_ptr_t) csd + csa->nl->bt_header_off);
+ csa->bt_base = (bt_rec_ptr_t)((sm_uc_ptr_t) csd + csa->nl->bt_base_off);
+ csa->th_base = (th_rec_ptr_t)((sm_uc_ptr_t) csd + csa->nl->th_base_off);
+ }
return;
}
diff --git a/sr_port/bt_put.c b/sr_port/bt_put.c
index c8bf4e8..c1c7a2d 100644
--- a/sr_port/bt_put.c
+++ b/sr_port/bt_put.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -36,7 +36,6 @@ GBLREF uint4 process_id;
GBLREF jnl_gbls_t jgbl;
error_def(ERR_BTFAIL);
-error_def(ERR_WCFAIL);
error_def(ERR_WCBLOCKED);
bt_rec_ptr_t bt_put(gd_region *reg, int4 block)
@@ -92,8 +91,7 @@ bt_rec_ptr_t bt_put(gd_region *reg, int4 block)
bt->killtn = lcl_tn;
insqt((que_ent_ptr_t)bt, (que_ent_ptr_t)hdr);
th = (th_rec_ptr_t)remqh((que_ent_ptr_t)csa->th_base);
- if (EMPTY_QUEUE == (sm_long_t)th)
- GTMASSERT;
+ assertpro(EMPTY_QUEUE != (sm_long_t)th);
break;
}
if (bt->blk == block)
@@ -114,8 +112,7 @@ bt_rec_ptr_t bt_put(gd_region *reg, int4 block)
assert(in_wcs_recover || (bt->tn < lcl_tn) || (jgbl.forw_phase_recovery && !JNL_ENABLED(csa)));
q0 = (bt_rec_ptr_t)((sm_uc_ptr_t)bt + bt->tnque.fl);
th = (th_rec_ptr_t)remqt((que_ent_ptr_t)((sm_uc_ptr_t)q0 + SIZEOF(th->tnque)));
- if (EMPTY_QUEUE == (sm_long_t)th)
- GTMASSERT;
+ assertpro(EMPTY_QUEUE != (sm_long_t)th);
break;
}
if (0 == bt->blkque.fl)
diff --git a/sr_port/bx_boolop.c b/sr_port/bx_boolop.c
index c77ffce..a1455b3 100644
--- a/sr_port/bx_boolop.c
+++ b/sr_port/bx_boolop.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -10,6 +10,7 @@
****************************************************************/
#include "mdef.h"
+#include "cmd_qlf.h"
#include "compiler.h"
#include "opcode.h"
#include "mdq.h"
@@ -19,6 +20,42 @@
LITREF octabstruct oc_tab[];
+GBLREF boolean_t run_time;
+GBLREF command_qualifier cmd_qlf;
+
+#define STOTEMP_IF_NEEDED(REF0, I, T1, OPND) \
+{ /* Input: \
+ * --- REF0: a boolean triple, which may have either 1 input (OC_COBOOL) or 2 (other opcodes). \
+ * --- I: whichever operand of REF0 we are STOTEMPing \
+ * --- T1: STOTEMP triple. NOOPed if not needed \
+ * --- OPND: operand referring to value we need need to pass as input into boolean operation \
+ * If OPND refers to a variable (OC_VAR), we need to STOTEMP it to protect it from subsequent side effects. \
+ * If it refers to a literal, and dynamic literals are enabled, we need to insert an OC_LITC anyway. Doing it \
+ * here in bx_boolop is convenient and ensures the OC_LITC is not skipped at run time. \
+ */ \
+ assert(TRIP_REF == OPND.oprclass); \
+ switch (OPND.oprval.tref->opcode) \
+ { \
+ case OC_VAR: \
+ T1->opcode = OC_STOTEMP; \
+ T1->operand[0] = OPND; \
+ REF0->operand[I] = put_tref(T1); \
+ break; \
+ case OC_LIT: \
+ if (!run_time && (cmd_qlf.qlf & CQ_DYNAMIC_LITERALS)) \
+ { \
+ T1->opcode = OC_LITC; \
+ T1->operand[0] = OPND; \
+ REF0->operand[I] = put_tref(T1); \
+ break; \
+ } \
+ default: \
+ T1->opcode = OC_NOOP; \
+ T1->operand[0].oprclass = NO_REF; \
+ REF0->operand[I] = put_tref(OPND.oprval.tref); \
+ } \
+}
+
void bx_boolop(triple *t, boolean_t jmp_type_one, boolean_t jmp_to_next, boolean_t sense, oprtype *addr)
{
boolean_t expr_fini;
@@ -112,19 +149,7 @@ void bx_boolop(triple *t, boolean_t jmp_type_one, boolean_t jmp_to_next, boolean
dqins(ref1, exorder, ref0);
if (oc_tab[t1->operand[0].oprval.tref->opcode].octype & OCT_MVAL)
{ /* do we need a STOTEMP? */
- switch (t1->operand[0].oprval.tref->opcode)
- {
- case OC_INDGLVN: /* indirect actions not happy without STOTEMP */
- case OC_INDNAME:
- case OC_VAR: /* variable could change so must save it */
- t1->opcode = OC_STOTEMP;
- ref0->operand[0] = put_tref(t1);/* new COBOOL points to this OC_STOTEMP */
- break;
- default: /* else no temporary if it's mval */
- ref0->operand[0] = put_tref(t1->operand[0].oprval.tref);
- t1->opcode = OC_NOOP;
- t1->operand[0].oprclass = NO_REF;
- }
+ STOTEMP_IF_NEEDED(ref0, 0, t1, t1->operand[0]);
} else
{ /* make it an mval instead of COBOOL now */
t1->opcode = OC_COMVAL;
@@ -146,30 +171,12 @@ void bx_boolop(triple *t, boolean_t jmp_type_one, boolean_t jmp_to_next, boolean
assert(TRIP_REF == t1->operand[0].oprclass);
assert(TRIP_REF == t1->operand[1].oprclass);
dqins(ref1, exorder, ref0);
- if (OC_VAR == t1->operand[0].oprval.tref->opcode)
- { /* VAR could change so must save it */
- t1->opcode = OC_STOTEMP; /* overlay the original op with a STOTEMP */
- ref0->operand[0] = put_tref(t1); /* new op points to thi STOTEMP */
- } else
- { /* no need for a temporary unless it's a VAR */
- ref0->operand[0] = put_tref(t1->operand[0].oprval.tref);
- t1->opcode = OC_NOOP;
- }
+ STOTEMP_IF_NEEDED(ref0, 0, t1, t1->operand[0]);
ref1 = t1;
t1 = t1->exorder.fl;
ref2 = maketriple(t1->opcode); /* copy jmp */
ref2->operand[0] = t1->operand[0];
- if (OC_VAR == ref1->operand[1].oprval.tref->opcode)
- { /* VAR could change so must save it */
- ref0->operand[1] = put_tref(t1); /* new op points to STOTEMP overlaying the jmp */
- t1->operand[0] = ref1->operand[1];
- t1->opcode = OC_STOTEMP; /* overlay jmp with 2nd STOTEMP */
- } else
- { /* no need for a temporary unless it's a VAR */
- ref0->operand[1] = put_tref(ref1->operand[1].oprval.tref);
- t1->opcode = OC_NOOP;
- t1->operand[0].oprclass = NO_REF;
- }
+ STOTEMP_IF_NEEDED(ref0, 1, t1, ref1->operand[1]);
if (OC_NOOP == ref1->opcode) /* does op[0] need cleanup? */
ref1->operand[0].oprclass = ref1->operand[1].oprclass = NO_REF;
ref0 = ref2;
@@ -186,7 +193,8 @@ void bx_boolop(triple *t, boolean_t jmp_type_one, boolean_t jmp_to_next, boolean
default:
assertpro(FALSE);
}
- assert((OC_STOTEMP == t1->opcode) || (OC_NOOP == t1->opcode) || (OC_COMVAL == t1->opcode));
+ assert((OC_STOTEMP == t1->opcode) || (OC_NOOP == t1->opcode) || (OC_COMVAL == t1->opcode)
+ || (OC_LITC == t1->opcode));
assert(oc_tab[ref0->opcode].octype & OCT_JUMP);
ref1 = (TREF(boolchain_ptr))->exorder.bl;
dqins(ref1, exorder, ref0); /* common insert for new jmp */
diff --git a/sr_port/cdb_sc_table.h b/sr_port/cdb_sc_table.h
index 8f33c48..fe040c1 100644
--- a/sr_port/cdb_sc_table.h
+++ b/sr_port/cdb_sc_table.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2003, 2012 Fidelity Information Services, Inc *
+ * Copyright 2003, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -117,3 +117,4 @@ CDB_SC_LCHAR_ENTRY(cdb_sc_instancefreeze, FALSE, 's') /* 's' instance freeze
CDB_SC_LCHAR_ENTRY(cdb_sc_gvtrootmod2, FALSE, 't') /* 't' t_end/tp_tend detected root blocks moved by reorg */
CDB_SC_LCHAR_ENTRY(cdb_sc_spansize, FALSE, 'u') /* 'u' chunks of spanning node don't add up */
CDB_SC_LCHAR_ENTRY(cdb_sc_restarted, FALSE, 'v') /* 'v' return value indicating t_retry has already happened */
+CDB_SC_LCHAR_ENTRY(cdb_sc_tqreadnowait, FALSE, 'w') /* 'w' update helper returning from t_qread instead of sleeping */
diff --git a/sr_port/cert_blk.c b/sr_port/cert_blk.c
index 80819ae..46ecb49 100644
--- a/sr_port/cert_blk.c
+++ b/sr_port/cert_blk.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -41,6 +41,7 @@
GBLREF uint4 dollar_tlevel;
GBLREF boolean_t dse_running;
+GBLREF boolean_t mu_reorg_upgrd_dwngrd_in_prog;
error_def(ERR_DBBLEVMX);
error_def(ERR_DBBLEVMN);
@@ -82,23 +83,21 @@ error_def(ERR_DBBDBALLOC);
#define TEXT4 ", "
#define MAX_UTIL_LEN 40
-#define RTS_ERROR_FUNC(err, buff) \
-{ \
- if (gtmassert_on_error) \
- GTMASSERT; \
- rts_error_func(err, buff); \
+#define RTS_ERROR_FUNC(CSA, ERR, BUFF) \
+{ \
+ if (gtmassert_on_error) \
+ GTMASSERT; \
+ rts_error_csa(CSA_ARG(CSA) VARLSTCNT(4) MAKE_MSG_INFO(ERR), 2, LEN_AND_STR((char_ptr_t)BUFF)); \
}
-void rts_error_func(int err, uchar_ptr_t buff);
-
int cert_blk (gd_region *reg, block_id blk, blk_hdr_ptr_t bp, block_id root, boolean_t gtmassert_on_error)
{
block_id child, prev_child;
rec_hdr_ptr_t rp, r_top;
int num_subscripts;
- uint4 bplmap, mask1, offset;
+ uint4 bplmap, mask1, offset, rec_offset, rec_size;
sm_uint_ptr_t chunk_p; /* Value is unaligned so will be assigned to chunk */
- uint4 chunk;
+ uint4 chunk, blk_size;
sm_uc_ptr_t blk_top, blk_id_ptr, next_tp_child_ptr, key_base, mp, b_ptr;
unsigned short rec_cmpc, min_cmpc; /* the minimum cmpc expected in any record (except star-key) in a gvt */
int tmp_cmpc;
@@ -106,14 +105,16 @@ int cert_blk (gd_region *reg, block_id blk, blk_hdr_ptr_t bp, block_id root, boo
unsigned int prior_expkeylen;
unsigned short temp_ushort;
int blk_levl;
- int blk_size, rec_size, comp_length, rec_offset, key_size;
+ int comp_length, key_size;
unsigned char util_buff[MAX_UTIL_LEN];
int util_len;
off_chain chain;
sgmnt_addrs *csa;
sgmnt_data_ptr_t csd;
boolean_t is_gvt, is_directory, first_key, full, prev_char_is_delimiter;
+ DCL_THREADGBL_ACCESS;
+ SETUP_THREADGBL_ACCESS;
csa = &FILE_INFO(reg)->s_addrs;
csd = csa->hdr;
bplmap = csd->bplmap;
@@ -146,18 +147,18 @@ int cert_blk (gd_region *reg, block_id blk, blk_hdr_ptr_t bp, block_id root, boo
{
if ((unsigned char)blk_levl != LCL_MAP_LEVL)
{
- RTS_ERROR_FUNC(MAKE_MSG_INFO(ERR_DBLVLINC), util_buff);
+ RTS_ERROR_FUNC(csa, MAKE_MSG_INFO(ERR_DBLVLINC), util_buff);
return FALSE;
}
if (blk_size != BM_SIZE(bplmap))
{
- RTS_ERROR_FUNC(ERR_DBBMSIZE, util_buff);
+ RTS_ERROR_FUNC(csa, ERR_DBBMSIZE, util_buff);
return FALSE;
}
mp = (sm_uc_ptr_t)bp + SIZEOF(blk_hdr);
if ((*mp & 1) != 0)
{ /* bitmap doesn't protect itself */
- RTS_ERROR_FUNC(ERR_DBBMBARE, util_buff);
+ RTS_ERROR_FUNC(csa, ERR_DBBMBARE, util_buff);
return FALSE;
}
full = TRUE;
@@ -181,14 +182,14 @@ int cert_blk (gd_region *reg, block_id blk, blk_hdr_ptr_t bp, block_id root, boo
mask1 &= chunk; /* check against the original contents */
if (mask1 != 0) /* busy and reused should never appear together */
{
- RTS_ERROR_FUNC(ERR_DBBMINV, util_buff);
+ RTS_ERROR_FUNC(csa, ERR_DBBMINV, util_buff);
return FALSE;
}
}
if (full == (NO_FREE_SPACE != gtm_ffs(blk / bplmap, MM_ADDR(csd), MASTER_MAP_BITS_PER_LMAP)))
{
- RTS_ERROR_FUNC(ERR_DBBMMSTR, util_buff);
+ RTS_ERROR_FUNC(csa, ERR_DBBMMSTR, util_buff);
/* DSE CACHE -VERIFY used to fail occasionally with the DBBMMSTR error because of passing
* an older twin global buffer that contained stale bitmap information. That is now fixed.
* So we dont expect any more such failures. Assert accordingly.
@@ -200,52 +201,57 @@ int cert_blk (gd_region *reg, block_id blk, blk_hdr_ptr_t bp, block_id root, boo
}
if (blk_levl > MAX_BT_DEPTH)
{
- RTS_ERROR_FUNC(ERR_DBBLEVMX, util_buff);
+ RTS_ERROR_FUNC(csa, ERR_DBBLEVMX, util_buff);
return FALSE;
}
if (blk_levl < 0)
{
- RTS_ERROR_FUNC(ERR_DBBLEVMN, util_buff);
+ RTS_ERROR_FUNC(csa, ERR_DBBLEVMN, util_buff);
return FALSE;
}
if (blk_levl == 0)
{ /* data block */
if ((DIR_ROOT == blk) || (blk == root))
{ /* headed for where an index block should be */
- RTS_ERROR_FUNC(ERR_DBROOTBURN, util_buff);
+ RTS_ERROR_FUNC(csa, ERR_DBROOTBURN, util_buff);
return FALSE;
}
- if (blk_size < SIZEOF(blk_hdr))
+ if (blk_size < (uint4)SIZEOF(blk_hdr))
{
- RTS_ERROR_FUNC(ERR_DBBSIZMN, util_buff);
+ RTS_ERROR_FUNC(csa, ERR_DBBSIZMN, util_buff);
return FALSE;
}
} else
{ /* index block */
- if (blk_size < (SIZEOF(blk_hdr) + SIZEOF(rec_hdr) + SIZEOF(block_id)))
+ if (blk_size < (uint4)(SIZEOF(blk_hdr) + SIZEOF(rec_hdr) + SIZEOF(block_id)))
{ /* must have at least one record */
- RTS_ERROR_FUNC(ERR_DBBSIZMN, util_buff);
+ RTS_ERROR_FUNC(csa, ERR_DBBSIZMN, util_buff);
return FALSE;
}
}
- if (blk_size > csd->blk_size)
+ if (blk_size > (uint4)csd->blk_size)
{
- RTS_ERROR_FUNC(ERR_DBBSIZMX, util_buff);
+ RTS_ERROR_FUNC(csa, ERR_DBBSIZMX, util_buff);
return FALSE;
}
- if (0 == root)
- {
+ is_directory = FALSE;
+ is_gvt = FALSE;
+ /* if both "is_directory" and "is_gvt" are FALSE, then we dont know YET if the given block is a directory or gvt */
+ if (DIR_ROOT == root)
+ is_directory = TRUE;
+ if ((0 != root) && (DIR_ROOT != root))
+ is_gvt = TRUE;
+ /* MUPIP REORG -TRUNCATE has some special cases */
+ if (MUSWP_INCR_ROOT_CYCLE == TREF(in_mu_swap_root_state))
+ { /* We could be updating either a gvt root block or a directory leaf block. Don't know yet. */
is_directory = FALSE;
is_gvt = FALSE;
- /* if both "is_directory" and "is_gvt" are FALSE, then we dont know YET if the given block is a directory or gvt */
- } else if (DIR_ROOT == root)
- {
+ } else if (MUSWP_DIRECTORY_SWAP == TREF(in_mu_swap_root_state))
+ { /* We know we're updating a directory block, even though root is not DIR_ROOT. root and gv_target correspond
+ * to the gvt being REORG'ed.
+ */
is_directory = TRUE;
is_gvt = FALSE;
- } else
- {
- is_directory = FALSE;
- is_gvt = TRUE;
}
blk_top = (sm_uc_ptr_t)bp + blk_size;
first_key = TRUE;
@@ -259,7 +265,7 @@ int cert_blk (gd_region *reg, block_id blk, blk_hdr_ptr_t bp, block_id root, boo
for (rp = (rec_hdr_ptr_t)((sm_uc_ptr_t)bp + SIZEOF(blk_hdr)) ; rp < (rec_hdr_ptr_t)blk_top ; rp = r_top)
{
GET_RSIZ(rec_size, rp);
- rec_offset = (int)((sm_ulong_t)rp - (sm_ulong_t)bp);
+ rec_offset = (uint4)((sm_ulong_t)rp - (sm_ulong_t)bp);
/*add util_buff here*/
util_len=0;
@@ -275,14 +281,14 @@ int cert_blk (gd_region *reg, block_id blk, blk_hdr_ptr_t bp, block_id root, boo
util_len += SIZEOF(TEXT2) - 1;
util_buff[util_len] = 0;
- if (rec_size <= SIZEOF(rec_hdr))
+ if (rec_size <= (uint4)SIZEOF(rec_hdr))
{
- RTS_ERROR_FUNC(ERR_DBRSIZMN, util_buff);
+ RTS_ERROR_FUNC(csa, ERR_DBRSIZMN, util_buff);
return FALSE;
}
- if (rec_size > (unsigned short)((sm_ulong_t)blk_top - (sm_ulong_t)rp))
+ if (rec_size > (uint4)((sm_ulong_t)blk_top - (sm_ulong_t)rp))
{
- RTS_ERROR_FUNC(ERR_DBRSIZMX, util_buff);
+ RTS_ERROR_FUNC(csa, ERR_DBRSIZMX, util_buff);
return FALSE;
}
r_top = (rec_hdr_ptr_t)((sm_ulong_t)rp + rec_size);
@@ -291,7 +297,7 @@ int cert_blk (gd_region *reg, block_id blk, blk_hdr_ptr_t bp, block_id root, boo
{
if (rec_cmpc)
{
- RTS_ERROR_FUNC(ERR_DBCMPNZRO, util_buff);
+ RTS_ERROR_FUNC(csa, ERR_DBCMPNZRO, util_buff);
return FALSE;
}
if (0 == blk_levl)
@@ -305,12 +311,12 @@ int cert_blk (gd_region *reg, block_id blk, blk_hdr_ptr_t bp, block_id root, boo
{ /* star key */
if (rec_size != SIZEOF(rec_hdr) + SIZEOF(block_id))
{
- RTS_ERROR_FUNC(ERR_DBSTARSIZ, util_buff);
+ RTS_ERROR_FUNC(csa, ERR_DBSTARSIZ, util_buff);
return FALSE;
}
if (rec_cmpc)
{
- RTS_ERROR_FUNC(ERR_DBSTARCMP, util_buff);
+ RTS_ERROR_FUNC(csa, ERR_DBSTARCMP, util_buff);
return FALSE;
}
blk_id_ptr = (sm_uc_ptr_t)rp + SIZEOF(rec_hdr);
@@ -324,7 +330,7 @@ int cert_blk (gd_region *reg, block_id blk, blk_hdr_ptr_t bp, block_id root, boo
{
if (rec_cmpc >= prior_expkeylen)
{
- RTS_ERROR_FUNC(ERR_DBCMPMX, util_buff);
+ RTS_ERROR_FUNC(csa, ERR_DBCMPMX, util_buff);
return FALSE;
}
for (b_ptr = prior_expkey; b_ptr < (prior_expkey + rec_cmpc); b_ptr++)
@@ -355,7 +361,7 @@ int cert_blk (gd_region *reg, block_id blk, blk_hdr_ptr_t bp, block_id root, boo
prev_char_is_delimiter = FALSE;
if (blk_id_ptr >= (sm_uc_ptr_t)r_top)
{
- RTS_ERROR_FUNC(ERR_DBKEYMX, util_buff);
+ RTS_ERROR_FUNC(csa, ERR_DBKEYMX, util_buff);
return FALSE;
}
}
@@ -366,7 +372,7 @@ int cert_blk (gd_region *reg, block_id blk, blk_hdr_ptr_t bp, block_id root, boo
if (is_gvt)
{ /* this is a contradiction. a block cannot be a directory and gvt at the same time.
* gvt should contain all keys with the same global name */
- RTS_ERROR_FUNC(ERR_DBINVGBL, util_buff);
+ RTS_ERROR_FUNC(csa, ERR_DBINVGBL, util_buff);
return FALSE;
}
is_directory = TRUE; /* no need to do this if it was already TRUE but we save an if check */
@@ -376,19 +382,19 @@ int cert_blk (gd_region *reg, block_id blk, blk_hdr_ptr_t bp, block_id root, boo
if (is_directory)
{ /* this is a contradiction. a block cannot be a directory and gvt at the same time.
* the directory tree should contain only name-level (i.e. unsubscripted) globals */
- RTS_ERROR_FUNC(ERR_DBDIRTSUBSC, util_buff);
+ RTS_ERROR_FUNC(csa, ERR_DBDIRTSUBSC, util_buff);
return FALSE;
}
is_gvt = TRUE; /* no need to do this if it was already TRUE but we save an if check */
}
if (MAX_GVSUBSCRIPTS <= num_subscripts)
{
- RTS_ERROR_FUNC(ERR_DBMAXNRSUBS, util_buff);
+ RTS_ERROR_FUNC(csa, ERR_DBMAXNRSUBS, util_buff);
return FALSE;
}
if (blk_levl && (key_size != (rec_size - SIZEOF(block_id) - SIZEOF(rec_hdr))))
{
- RTS_ERROR_FUNC(ERR_DBKEYMN, util_buff);
+ RTS_ERROR_FUNC(csa, ERR_DBKEYMN, util_buff);
return FALSE;
}
assert(first_key || (rec_cmpc < prior_expkeylen));
@@ -396,12 +402,12 @@ int cert_blk (gd_region *reg, block_id blk, blk_hdr_ptr_t bp, block_id root, boo
{
if (prior_expkey[rec_cmpc] == key_base[0])
{
- RTS_ERROR_FUNC(ERR_DBCMPBAD, util_buff);
+ RTS_ERROR_FUNC(csa, ERR_DBCMPBAD, util_buff);
return FALSE;
}
if (((unsigned int)prior_expkey[rec_cmpc] >= (unsigned int)key_base[0]))
{
- RTS_ERROR_FUNC(ERR_DBKEYORD, util_buff);
+ RTS_ERROR_FUNC(csa, ERR_DBKEYORD, util_buff);
return FALSE;
}
}
@@ -420,22 +426,24 @@ int cert_blk (gd_region *reg, block_id blk, blk_hdr_ptr_t bp, block_id root, boo
{
if (child <= 0)
{
- RTS_ERROR_FUNC(ERR_DBPTRNOTPOS, util_buff);
+ RTS_ERROR_FUNC(csa, ERR_DBPTRNOTPOS, util_buff);
return FALSE;
}
- if (child > csa->ti->total_blks)
- {
- RTS_ERROR_FUNC(ERR_DBPTRMX, util_buff);
+ if ((child > csa->ti->total_blks) && !mu_reorg_upgrd_dwngrd_in_prog)
+ { /* REORG -UPGRADE/DOWNGRADE can update recycled blocks, which may contain children beyond
+ * the total_blks if a truncate happened sometime after the block was killed.
+ */
+ RTS_ERROR_FUNC(csa, ERR_DBPTRMX, util_buff);
return FALSE;
}
if (!(child % bplmap))
{
- RTS_ERROR_FUNC(ERR_DBPTRMAP, util_buff);
+ RTS_ERROR_FUNC(csa, ERR_DBPTRMAP, util_buff);
return FALSE;
}
if (child == prev_child)
{
- RTS_ERROR_FUNC(ERR_DBBDBALLOC, util_buff);
+ RTS_ERROR_FUNC(csa, ERR_DBBDBALLOC, util_buff);
return FALSE;
}
prev_child = child;
@@ -443,7 +451,7 @@ int cert_blk (gd_region *reg, block_id blk, blk_hdr_ptr_t bp, block_id root, boo
{
if ((blk_id_ptr != next_tp_child_ptr) && (NULL != next_tp_child_ptr))
{
- RTS_ERROR_FUNC(ERR_DBPTRNOTPOS, util_buff);
+ RTS_ERROR_FUNC(csa, ERR_DBPTRNOTPOS, util_buff);
return FALSE;
}
next_tp_child_ptr = blk_id_ptr + chain.next_off;
@@ -454,10 +462,4 @@ int cert_blk (gd_region *reg, block_id blk, blk_hdr_ptr_t bp, block_id root, boo
}
assert(!is_directory || !is_gvt); /* the block cannot be a directory AND gvt at the same time */
return TRUE;
-
-}
-
-void rts_error_func(int err, uchar_ptr_t buff)
-{
- rts_error(VARLSTCNT(4) MAKE_MSG_INFO(err), 2, LEN_AND_STR((char_ptr_t)buff));
}
diff --git a/sr_port/cmd_qlf.h b/sr_port/cmd_qlf.h
index 7203c9c..e0e93b1 100644
--- a/sr_port/cmd_qlf.h
+++ b/sr_port/cmd_qlf.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -42,6 +42,7 @@ typedef struct
#define CQ_ALIGN_STRINGS (1 << 11) /* 0x0800 */
#define CQ_UTF8 (1 << 12) /* 0x1000 */
#define CQ_NAMEOFRTN (1 << 13) /* 0x2000 */
+#define CQ_DYNAMIC_LITERALS (1 << 14) /* 0x4000 -- Set via environmental variable gtm_dynamic_literals (gtm_logicals.h) */
/* TODO: add CQ_ALIGN_STRINGS to the default list below when alignment is supported */
#define CQ_DEFAULT (CQ_WARNINGS | CQ_OBJECT | CQ_IGNORE | CQ_LOWER_LABELS | CQ_LINE_ENTRY | CQ_INLINE_LITERALS)
@@ -49,6 +50,16 @@ typedef struct
#define LISTTAB 10
#define PG_WID 132
+#define INIT_CMD_QLF_STRINGS(CMD_QLF, OBJ_FILE, LIST_FILE, CEPREP_FILE, SIZE) \
+{ \
+ CMD_QLF.object_file.str.addr = OBJ_FILE; \
+ CMD_QLF.object_file.str.len = SIZE; \
+ CMD_QLF.list_file.str.addr = LIST_FILE; \
+ CMD_QLF.list_file.str.len = SIZE; \
+ CMD_QLF.ceprep_file.str.addr = CEPREP_FILE; \
+ CMD_QLF.ceprep_file.str.len = SIZE; \
+}
+
typedef struct src_line_type
{
struct
diff --git a/sr_port/comp_fini.c b/sr_port/comp_fini.c
index 98c2e1d..61c108b 100644
--- a/sr_port/comp_fini.c
+++ b/sr_port/comp_fini.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -33,6 +33,7 @@ GBLREF char cg_phase;
GBLREF unsigned char *source_buffer;
error_def(ERR_INDEXTRACHARS);
+error_def(ERR_INDRCOMPFAIL);
int comp_fini(int status, mstr *obj, opctype retcode, oprtype *retopr, oprtype *dst, mstr_len_t src_len)
{
@@ -44,7 +45,11 @@ int comp_fini(int status, mstr *obj, opctype retcode, oprtype *retopr, oprtype *
{
while (TK_SPACE == TREF(window_token)) /* Eat up trailing white space */
advancewindow();
- if (((src_len + 2) != source_column) && ('\0' != source_buffer[source_column]))
+ if (TK_ERROR == TREF(window_token))
+ {
+ status = EXPR_FAIL;
+ stx_error(ERR_INDRCOMPFAIL);
+ } else if ((TK_EOL != TREF(window_token)) || (source_column < src_len))
{
status = EXPR_FAIL;
stx_error(ERR_INDEXTRACHARS);
@@ -77,6 +82,12 @@ int comp_fini(int status, mstr *obj, opctype retcode, oprtype *retopr, oprtype *
ind_code(obj);
indr_stringpool.free = indr_stringpool.base;
}
+ } else
+ { /* If this assert fails, it means a syntax problem could have been caught earlier. Consider placing a more useful
+ * and specific error message at that location.
+ */
+ assert(FALSE);
+ stx_error(ERR_INDRCOMPFAIL);
}
if (EXPR_FAIL == status)
{
diff --git a/sr_port/compiler.h b/sr_port/compiler.h
index b80cf35..21c378c 100644
--- a/sr_port/compiler.h
+++ b/sr_port/compiler.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -383,7 +383,7 @@ typedef struct
TREF(saw_side_effect) = TRUE; \
if (!run_time && (FULL_BOOL_WARN == TREF(gtm_fullbool))) \
{ /* warnings requested by by gtm_fullbool and enabled by eval_expr */ \
- show_source_line(source_line_buff, SIZEOF(source_line_buff), TRUE); \
+ show_source_line(TRUE); \
dec_err(VARLSTCNT(1) ERR_BOOLSIDEFFECT); \
} \
} \
@@ -394,7 +394,7 @@ typedef struct
#define ISSUE_SIDEEFFECTEVAL_WARNING(COLUMN) \
{ \
TREF(last_source_column) = (COLUMN); \
- show_source_line(source_line_buff, SIZEOF(source_line_buff), TRUE); \
+ show_source_line(TRUE); \
dec_err(VARLSTCNT(1) ERR_SIDEEFFECTEVAL); \
}
@@ -447,7 +447,6 @@ typedef struct
#define SUBS_ARRAY_2_TRIPLES(REF1, SB1, SB2, SUBSCRIPTS, XTRA) \
{ \
boolean_t PROTECT_LVN, SE_NOTIFY; \
- char SOURCE_LINE_BUFF[MAX_SRCLINE + SIZEOF(ARROW)]; \
triple *REF2; \
\
if (PROTECT_LVN = (TREF(side_effect_base))[TREF(expr_depth)]) /* NOTE assignment */ \
@@ -462,11 +461,7 @@ typedef struct
REF2->operand[0] = *SB2; \
dqins(SB2->oprval.tref, exorder, REF2); /* NOTE:this violates information hiding */ \
if (SE_NOTIFY) \
- { \
- TREF(last_source_column) = SB2->oprval.tref->src.column + 1; \
- show_source_line(SOURCE_LINE_BUFF, SIZEOF(SOURCE_LINE_BUFF), TRUE); \
- dec_err(VARLSTCNT(1) ERR_SIDEEFFECTEVAL); \
- } \
+ ISSUE_SIDEEFFECTEVAL_WARNING(SB2->oprval.tref->src.column + 1); \
*SB2 = put_tref(REF2); \
} \
REF2 = newtriple(OC_PARAMETER); \
@@ -575,6 +570,7 @@ int f_zechar(oprtype *a, opctype op);
int f_zgetsyi(oprtype *a, opctype op);
int f_zjobexam(oprtype *a, opctype op);
int f_zparse(oprtype *a, opctype op);
+int f_zpeek(oprtype *a, opctype op);
int f_zprevious(oprtype *a, opctype op);
int f_zqgblmod(oprtype *a, opctype op);
int f_zsearch(oprtype *a, opctype op);
diff --git a/sr_port/compiler_startup.c b/sr_port/compiler_startup.c
index a956d6a..10ae217 100644
--- a/sr_port/compiler_startup.c
+++ b/sr_port/compiler_startup.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -67,7 +67,14 @@ boolean_t compiler_startup(void)
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
- assert(NULL == complits_hashtab || NULL == complits_hashtab->base);
+ /* Although we have an invocation of compiler cleanups at the end of this module, there exist ways to avoid this
+ * cleanup by working in direct mode, getting certain types of errors combined with an argumentless ZGOTO that unwinds
+ * pretty much everything that can bypass that cleanup. So do a quick check if it is needed and if so, git-r-done
+ * (test is part of the macro invocation). Note this is the easiest place to make this check rather than complicating
+ * error handling to provide a similar effect.
+ */
+ COMPILE_HASHTAB_CLEANUP;
+ reinit_externs();
memset(&null_mident, 0, SIZEOF(null_mident));
ESTABLISH_RET(compiler_ch, FALSE);
/* Since the stringpool alignment is solely based on mstr_native_align, we need to initialize it based
diff --git a/sr_port/compswap.h b/sr_port/compswap.h
index 6a998ae..9fc0483 100644
--- a/sr_port/compswap.h
+++ b/sr_port/compswap.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -26,8 +26,8 @@
boolean_t compswap(sm_global_latch_ptr_t lock, int compval, int newval1);
# define COMPSWAP_LOCK(LCK, CMPVAL1, CMPVAL2, NEWVAL1, NEWVAL2) compswap(LCK, CMPVAL1, NEWVAL1)
# define COMPSWAP_UNLOCK(LCK, CMPVAL1, CMPVAL2, NEWVAL1, NEWVAL2) compswap(LCK, CMPVAL1, NEWVAL1)
-# elif defined(__HP_cc)
- /* Use compiler inline assembly macros for HP-UX/HP C */
+# elif (defined(__HP_cc) || (defined(__hpux) && defined(__GNUC__)))
+ /* Use compiler inline assembly macros for HP-UX/HP C or GCC on HPUX*/
/* This is assuming 32 bit lock storage, which right now seems to be PIDs
* most of the time. PIDs are currently 32 bit values, but that could change
* someday, so beware
@@ -46,6 +46,8 @@
_Asm_cmpxchg((_Asm_sz)_SZ_W,(_Asm_sem)_SEM_REL,(uint32_t *)LCK, \
(uint64_t)NEWVAL1, (_Asm_ldhint)_LDHINT_NONE) == (uint64_t)CMPVAL1 ? 1 : 0 \
)
+# else
+# error Unsupported Platform sr_port/compswap.h
# endif /* __ia64 */
#else
boolean_t compswap(sm_global_latch_ptr_t lock, int compval1, int compval2, int newval1, int newval2);
diff --git a/sr_port/copy_stack_frame.c b/sr_port/copy_stack_frame.c
index e292678..cdd1221 100644
--- a/sr_port/copy_stack_frame.c
+++ b/sr_port/copy_stack_frame.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -37,18 +37,21 @@ void copy_stack_frame(void)
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);
}
assert(msp < stackbase);
assert((frame_pointer < frame_pointer->old_frame_pointer) || (NULL == frame_pointer->old_frame_pointer));
*sf = *frame_pointer;
sf->old_frame_pointer = frame_pointer;
- sf->flags = 0; /* Don't propagate special flags */
+ sf->flags = 0; /* Don't propagate special flags */
+ sf->type &= SFT_ZINTR_OFF; /* Don't propagate special type - normally can't propagate but if $ZINTERRUPT frame is
+ * rewritten by ZGOTO to a "regular" frame, this frame type *can* propagate.
+ */
SET_GLVN_INDX(sf, GLVN_POOL_UNTOUCHED);
sf->ret_value = NULL;
- sf->dollar_test = -1; /* initialize it with -1 for indication of not yet being used */
+ sf->dollar_test = -1; /* initialize it with -1 for indication of not yet being used */
frame_pointer = sf;
DBGEHND((stderr, "copy_stack_frame: Added stackframe at addr 0x"lvaddr" old-msp: 0x"lvaddr" new-msp: 0x"lvaddr"\n",
sf, msp_save, msp));
diff --git a/sr_port/cre_jnl_file.c b/sr_port/cre_jnl_file.c
index d781205..bcee9e2 100644
--- a/sr_port/cre_jnl_file.c
+++ b/sr_port/cre_jnl_file.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2003, 2012 Fidelity Information Services, Inc *
+ * Copyright 2003, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -112,39 +112,34 @@ uint4 cre_jnl_file(jnl_create_info *info)
{
mstr filestr;
int org_fn_len, rename_fn_len, fstat;
- uint4 ustatus;
char *org_fn, rename_fn[MAX_FN_LEN];
+ boolean_t no_rename;
+ assert(0 != jgbl.gbl_jrec_time);
if (!info->no_rename) /* ***MAY*** be rename is required */
{
+ no_rename = FALSE;
if (SS_NORMAL != (info->status = prepare_unique_name((char *)info->jnl, info->jnl_len, "", "",
- rename_fn, &rename_fn_len, &info->status2)))
- { /* prepare_unique_name calls append_time_stamp which needs to open the info->jnl file.
- * We are here because append_time_stamp failed to open info->jnl or something else.
- * So check if info->jnl is present in the system */
+ rename_fn, &rename_fn_len, jgbl.gbl_jrec_time, &info->status2)))
+ {
+ no_rename = TRUE;
+ } else
+ {
filestr.addr = (char *)info->jnl;
filestr.len = info->jnl_len;
- if (FILE_NOT_FOUND != (fstat = gtm_file_stat(&filestr, NULL, NULL, FALSE, &ustatus)))
+ if (FILE_PRESENT != (fstat = gtm_file_stat(&filestr, NULL, NULL, FALSE, (uint4 *)&info->status)))
{
- if (FILE_STAT_ERROR == fstat)
+ if (FILE_NOT_FOUND != fstat)
{
- STATUS_MSG(info); /* for prepare_unique_name call */
- info->status = ustatus;
- info->status2 = SS_NORMAL;
+ STATUS_MSG(info);
+ return EXIT_ERR;
}
- STATUS_MSG(info);
- return EXIT_ERR;
+ if (IS_GTM_IMAGE)
+ send_msg(VARLSTCNT(4) ERR_JNLFNF, 2, filestr.len, filestr.addr);
+ else
+ gtm_putmsg(VARLSTCNT(4) ERR_JNLFNF, 2, filestr.len, filestr.addr);
+ no_rename = TRUE;
}
- if (IS_GTM_IMAGE)
- send_msg(VARLSTCNT(4) ERR_JNLFNF, 2, filestr.len, filestr.addr);
- else
- gtm_putmsg(VARLSTCNT(4) ERR_JNLFNF, 2, filestr.len, filestr.addr);
- STATUS_MSG(info);
- info->status = info->status2 = SS_NORMAL;
- info->no_rename = TRUE; /* We wanted to rename, but not required */
- info->no_prev_link = TRUE; /* No rename => no prev_link */
- } else
- {
/* Note if info->no_prev_link == TRUE, we do not keep previous link, though rename can happen */
if (JNL_ENABLED(info) && !info->no_prev_link)
{
@@ -153,6 +148,13 @@ uint4 cre_jnl_file(jnl_create_info *info)
} else
assert(info->no_prev_link);
}
+ if (no_rename)
+ {
+ STATUS_MSG(info);
+ info->status = info->status2 = SS_NORMAL;
+ info->no_rename = TRUE; /* We wanted to rename, but not required anymore */
+ info->no_prev_link = TRUE; /* No rename => no prev_link */
+ }
} /* else we know for sure rename is not required */
return (cre_jnl_file_common(info, rename_fn, rename_fn_len));
}
@@ -171,13 +173,13 @@ uint4 cre_jnl_file_common(jnl_create_info *info, char *rename_fn, int rename_fn_
fd_type channel;
char *jrecbuf, *jrecbuf_base;
gd_id jnlfile_id;
-#if defined(VMS)
+# ifdef VMS
struct FAB fab;
struct NAM nam;
char es_buffer[MAX_FN_LEN], name_buffer[MAX_FN_LEN];
uint4 blk, block, zero_size;
io_status_block_disk iosb;
-#elif defined(UNIX)
+# else
struct stat stat_buf;
int fstat_res;
ZOS_ONLY(int realfiletag;)
@@ -186,7 +188,7 @@ uint4 cre_jnl_file_common(jnl_create_info *info, char *rename_fn, int rename_fn_
struct stat sb;
int perm;
struct perm_diag_data pdd;
-#endif
+# endif
int idx;
trans_num db_tn;
uint4 temp_offset, temp_checksum, pfin_offset, eof_offset;
@@ -209,13 +211,13 @@ uint4 cre_jnl_file_common(jnl_create_info *info, char *rename_fn, int rename_fn_
{
create_fn = &fn_buff[0];
if (SS_NORMAL != (info->status = prepare_unique_name((char *)info->jnl, (int)info->jnl_len, "", EXT_NEW,
- (char *)create_fn, &create_fn_len, &info->status2)))
+ (char *)create_fn, &create_fn_len, 0, &info->status2)))
{
STATUS_MSG(info);
return EXIT_ERR;
}
}
-#if defined(UNIX)
+# ifdef UNIX
OPENFILE3((char *)create_fn, O_CREAT | O_EXCL | O_RDWR, 0600, channel);
if (-1 == channel)
{
@@ -223,10 +225,10 @@ uint4 cre_jnl_file_common(jnl_create_info *info, char *rename_fn, int rename_fn_
STATUS_MSG(info);
return EXIT_ERR;
}
-#if defined(__MVS__)
+# ifdef __MVS__
if (-1 == gtm_zos_set_tag(channel, TAG_BINARY, TAG_NOTTEXT, TAG_FORCE, &realfiletag))
TAG_POLICY_SEND_MSG((char *)create_fn, errno, realfiletag, TAG_BINARY);
-#endif
+# endif
FSTAT_FILE(channel, &stat_buf, fstat_res);
if (-1 == fstat_res)
{
@@ -290,7 +292,7 @@ uint4 cre_jnl_file_common(jnl_create_info *info, char *rename_fn, int rename_fn_
jrecbuf = (char *)ROUND_UP2((uintszofptr_t)jrecbuf_base, jnl_fs_block_size);
memset(jrecbuf, 0, jnl_fs_block_size);
set_gdid_from_stat(&jnlfile_id, &stat_buf);
-#elif defined(VMS)
+# else
nam = cc$rms_nam;
nam.nam$l_rsa = name_buffer;
nam.nam$b_rss = SIZEOF(name_buffer);
@@ -334,7 +336,7 @@ uint4 cre_jnl_file_common(jnl_create_info *info, char *rename_fn, int rename_fn_
memcpy(jnlfile_id.did, &nam.nam$w_did, SIZEOF(jnlfile_id.did));
memcpy(jnlfile_id.fid, &nam.nam$w_fid, SIZEOF(jnlfile_id.fid));
jnl_fs_block_size = get_fs_block_size(channel);
-#endif
+# endif
info->checksum = compute_checksum(INIT_CHECKSUM_SEED, (uint4 *)&jnlfile_id, SIZEOF(gd_id));
/* Journal file header size relies on this assert */
assert(256 == GTMCRYPT_RESERVED_HASH_LEN);
diff --git a/sr_port/cre_jnl_file_intrpt_rename.c b/sr_port/cre_jnl_file_intrpt_rename.c
index 34089be..7055e26 100644
--- a/sr_port/cre_jnl_file_intrpt_rename.c
+++ b/sr_port/cre_jnl_file_intrpt_rename.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2003, 2010 Fidelity Information Services, Inc *
+ * Copyright 2003, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -40,7 +40,7 @@ void cre_jnl_file_intrpt_rename(int fn_len, sm_uc_ptr_t fn)
filestr.addr = (char *)fn;
filestr.len = fn_len;
- prepare_unique_name((char *)fn, fn_len, "", EXT_NEW, (char *)ext_new_jnl_fn, &ext_new_jnl_fn_len, &ustatus);
+ prepare_unique_name((char *)fn, fn_len, "", EXT_NEW, (char *)ext_new_jnl_fn, &ext_new_jnl_fn_len, 0, &ustatus);
assert(SS_NORMAL == ustatus);
status1 = gtm_file_stat(&filestr, NULL, NULL, FALSE, &ustatus);
if (FILE_STAT_ERROR == status1)
diff --git a/sr_port/db_auto_upgrade.c b/sr_port/db_auto_upgrade.c
index 7874c41..99dde60 100644
--- a/sr_port/db_auto_upgrade.c
+++ b/sr_port/db_auto_upgrade.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -53,6 +53,7 @@ void db_auto_upgrade(gd_region *reg)
if (0 == csd->mutex_spin_parms.mutex_sleep_spin_count)
csd->mutex_spin_parms.mutex_sleep_spin_count = MUTEX_SLEEP_SPIN_COUNT;
/* zero is a legitimate value for csd->mutex_spin_parms.mutex_spin_sleep_mask; so can't detect if need re-initialization */
+ INIT_NUM_CRIT_ENTRY_IF_NEEDED(csd);
/* Auto upgrade based on minor database version number. This code currently only does auto upgrade and does not
* do auto downgrade although that certainly is possible to implement if necessary. For now, if the current version
@@ -127,8 +128,12 @@ void db_auto_upgrade(gd_region *reg)
UNIX_ONLY(csd->freeze_on_fail = FALSE;)
UNIX_ONLY(csd->span_node_absent = TRUE;)
UNIX_ONLY(csd->maxkeysz_assured = FALSE;)
- break;
case GDSMV60000:
+ case GDSMV60001:
+ /* GT.M V60002 introduced mutex_spin_parms.mutex_que_entry_space_size */
+ NUM_CRIT_ENTRY(csd) = DEFAULT_NUM_CRIT_ENTRY;
+ break;
+ case GDSMV60002:
/* Nothing to do for this version since it is GDSMVCURR for now. */
assert(FALSE); /* When this assert fails, it means a new GDSMV* was created, */
break; /* so a new "case" needs to be added BEFORE the assert. */
diff --git a/sr_port/db_csh_get.c b/sr_port/db_csh_get.c
index a292f56..5ed885e 100644
--- a/sr_port/db_csh_get.c
+++ b/sr_port/db_csh_get.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -36,29 +36,18 @@ cache_rec_ptr_t db_csh_get(block_id block) /* block number to look up */
sgmnt_data_ptr_t csd;
cache_rec_ptr_t cr, cr_hash_base;
int blk_hash, lcnt, ocnt, hmax;
- bool is_mm;
# ifdef DEBUG
cache_rec_ptr_t cr_low, cr_high;
# endif
csa = cs_addrs;
csd = csa->hdr;
- is_mm = (dba_mm == csd->acc_meth);
- assert((FALSE == is_mm) || (csa->now_crit)); /* if MM you should be in crit */
- VMS_ONLY(assert(FALSE == is_mm);) /* in VMS, MM should never call db_csh_get */
+ assert(dba_mm != csd->acc_meth);
hmax = csd->bt_buckets;
blk_hash = (block % hmax);
- if (!is_mm)
- {
- DEBUG_ONLY(cr_low = &csa->acc_meth.bg.cache_state->cache_array[0];)
- DEBUG_ONLY(cr_high = cr_low + csd->bt_buckets + csd->n_bts;)
- cr_hash_base = csa->acc_meth.bg.cache_state->cache_array + blk_hash;
- } else
- {
- DEBUG_ONLY(cr_low = (cache_rec_ptr_t)(csa->acc_meth.mm.mmblk_state->mmblk_array);)
- DEBUG_ONLY(cr_high = (cache_rec_ptr_t)(csa->acc_meth.mm.mmblk_state->mmblk_array + csd->bt_buckets + csd->n_bts);)
- cr_hash_base = (cache_rec_ptr_t)(csa->acc_meth.mm.mmblk_state->mmblk_array + blk_hash);
- }
+ DEBUG_ONLY(cr_low = &csa->acc_meth.bg.cache_state->cache_array[0];)
+ DEBUG_ONLY(cr_high = cr_low + csd->bt_buckets + csd->n_bts;)
+ cr_hash_base = csa->acc_meth.bg.cache_state->cache_array + blk_hash;
ocnt = 0;
do
{
@@ -68,8 +57,7 @@ cache_rec_ptr_t db_csh_get(block_id block) /* block number to look up */
do
{
cr = (cache_rec_ptr_t)((sm_uc_ptr_t)cr + cr->blkque.fl);
- assert(!CR_NOT_ALIGNED(cr, cr_low) && !CR_NOT_IN_RANGE(cr, cr_low, cr_high)
- UNIX_ONLY(|| is_mm));
+ assert(!CR_NOT_ALIGNED(cr, cr_low) && !CR_NOT_IN_RANGE(cr, cr_low, cr_high));
if (BT_QUEHEAD == cr->blk)
{ /* We have reached the end of the queue, validate we have run the queue
* back around to the same queue header or we'll need to retry because the
@@ -84,17 +72,14 @@ cache_rec_ptr_t db_csh_get(block_id block) /* block number to look up */
assert(!csa->now_crit || (0 != cr->blkque.fl) && (0 != cr->blkque.bl));
if (cr->blk == block)
{
- if (!is_mm)
- {
- if (CDB_STAGNATE <= t_tries || mu_reorg_process)
- CWS_INSERT(block);
- /* setting refer outside of crit may not prevent its replacement, but that's an
- * inefficiency, not a tragedy because of concurrency checks in t_end or tp_tend;
- * the real problem is to ensure that the cache_rec layout is such that this
- * assignment does not damage other fields.
- */
- cr->refer = TRUE;
- }
+ if (CDB_STAGNATE <= t_tries || mu_reorg_process)
+ CWS_INSERT(block);
+ /* setting refer outside of crit may not prevent its replacement, but that's an
+ * inefficiency, not a tragedy because of concurrency checks in t_end or tp_tend;
+ * the real problem is to ensure that the cache_rec layout is such that this
+ * assignment does not damage other fields.
+ */
+ cr->refer = TRUE;
return cr;
}
lcnt--;
diff --git a/sr_port/db_csh_getn.c b/sr_port/db_csh_getn.c
index d95a98b..00d9fb3 100644
--- a/sr_port/db_csh_getn.c
+++ b/sr_port/db_csh_getn.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -91,6 +91,7 @@ cache_rec_ptr_t db_csh_getn(block_id block)
SETUP_THREADGBL_ACCESS;
csa = cs_addrs;
csd = csa->hdr;
+ assert(dba_mm != csd->acc_meth);
assert(csa->now_crit);
assert(csa == &FILE_INFO(gv_cur_region)->s_addrs);
max_ent = csd->n_bts;
diff --git a/sr_port/db_csh_ini.c b/sr_port/db_csh_ini.c
index dba19bc..b5935a0 100644
--- a/sr_port/db_csh_ini.c
+++ b/sr_port/db_csh_ini.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2007 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -17,11 +17,10 @@
#include "gdsfhead.h"
-void db_csh_ini(sgmnt_addrs *cs)
+void db_csh_ini(sgmnt_addrs *csa)
{
- if ((INTPTR_T)cs->hdr & 7)
- GTMASSERT;
- cs->acc_meth.bg.cache_state = (cache_que_heads_ptr_t)((sm_uc_ptr_t)cs->hdr + cs->nl->cache_off);
- assert(cs->acc_meth.bg.cache_state);
+ assertpro(0 == ((INTPTR_T)csa->hdr & 7));
+ csa->acc_meth.bg.cache_state = (cache_que_heads_ptr_t)((sm_uc_ptr_t)csa->hdr + csa->nl->cache_off);
+ assert(csa->acc_meth.bg.cache_state);
return;
}
diff --git a/sr_port/db_csh_ref.c b/sr_port/db_csh_ref.c
index 8fae6fa..89fd573 100644
--- a/sr_port/db_csh_ref.c
+++ b/sr_port/db_csh_ref.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -25,7 +25,7 @@
error_def(ERR_WCFAIL);
-GBLREF int4 process_id;
+GBLREF int4 process_id;
#if defined(UNIX) && defined(DEBUG)
GBLREF jnl_gbls_t jgbl;
#endif
@@ -39,49 +39,26 @@ void db_csh_ref(sgmnt_addrs *csa, boolean_t init)
sm_uc_ptr_t bp, bp_top;
cache_rec_ptr_t cr, cr_top, cr1;
int4 buffer_size, rec_size;
- boolean_t is_mm;
csd = csa->hdr;
- /* Note the cr setups for MM should realistically be under a TARGETED_MSYNC_ONLY macro since the MM
- * cache recs are only used in that mode. We don't currently use that mode but since this is one-time
- * open-code, we aren't bothering. Note if targeted msyncs ever do come back into fashion, we should
- * revisit the INTERLOCK_INIT_MM vs INTERLOCK_INIT usage, here and everywhere else too.
- */
- is_mm = (dba_mm == csd->acc_meth);
- if (!is_mm)
- {
- if (init)
- {
- longset((uchar_ptr_t)csa->acc_meth.bg.cache_state,
- SIZEOF(cache_que_heads) + (csd->bt_buckets + csd->n_bts - 1) * SIZEOF(cache_rec),
- 0); /* -1 since there is a cache_rec in cache_que_heads */
- SET_LATCH_GLOBAL(&csa->acc_meth.bg.cache_state->cacheq_active.latch, LOCK_AVAILABLE);
- SET_LATCH_GLOBAL(&csa->acc_meth.bg.cache_state->cacheq_wip.latch, LOCK_AVAILABLE);
- }
- cr = cr1 = csa->acc_meth.bg.cache_state->cache_array;
- buffer_size = csd->blk_size;
- assert(buffer_size > 0);
- assert(0 == buffer_size % DISK_BLOCK_SIZE);
- rec_size = SIZEOF(cache_rec);
- } else
- {
- if (init)
- {
- longset((uchar_ptr_t)csa->acc_meth.mm.mmblk_state,
- SIZEOF(mmblk_que_heads) + (csd->bt_buckets + csd->n_bts - 1) * SIZEOF(mmblk_rec),
- 0); /* -1 since there is a mmblk_rec in mmblk_que_heads */
- SET_LATCH_GLOBAL(&csa->acc_meth.mm.mmblk_state->mmblkq_active.latch, LOCK_AVAILABLE);
- SET_LATCH_GLOBAL(&csa->acc_meth.mm.mmblk_state->mmblkq_wip.latch, LOCK_AVAILABLE);
- }
- cr = cr1 = (cache_rec_ptr_t)csa->acc_meth.mm.mmblk_state->mmblk_array;
- rec_size = SIZEOF(mmblk_rec);
- }
cnl = csa->nl;
if (init)
{
SET_LATCH_GLOBAL(&cnl->wc_var_lock, LOCK_AVAILABLE);
SET_LATCH_GLOBAL(&cnl->db_latch, LOCK_AVAILABLE);
+ if (dba_mm == csd->acc_meth)
+ return;
+ longset((uchar_ptr_t)csa->acc_meth.bg.cache_state,
+ SIZEOF(cache_que_heads) + (csd->bt_buckets + csd->n_bts - 1) * SIZEOF(cache_rec),
+ 0); /* -1 since there is a cache_rec in cache_que_heads */
+ SET_LATCH_GLOBAL(&csa->acc_meth.bg.cache_state->cacheq_active.latch, LOCK_AVAILABLE);
+ SET_LATCH_GLOBAL(&csa->acc_meth.bg.cache_state->cacheq_wip.latch, LOCK_AVAILABLE);
}
+ cr = cr1 = csa->acc_meth.bg.cache_state->cache_array;
+ buffer_size = csd->blk_size;
+ assert(buffer_size > 0);
+ assert(0 == buffer_size % DISK_BLOCK_SIZE);
+ rec_size = SIZEOF(cache_rec);
for (cr_top = (cache_rec_ptr_t)((sm_uc_ptr_t)cr + rec_size * csd->bt_buckets);
cr < cr_top; cr = (cache_rec_ptr_t)((sm_uc_ptr_t)cr + rec_size))
cr->blk = BT_QUEHEAD;
@@ -91,32 +68,21 @@ void db_csh_ref(sgmnt_addrs *csa, boolean_t init)
cnl->cur_lru_cache_rec_off = GDS_ANY_ABS2REL(csa, cr);
cnl->cache_hits = 0;
}
- if (!is_mm)
- {
- bp = (sm_uc_ptr_t)ROUND_UP((sm_ulong_t)cr_top, OS_PAGE_SIZE);
- bp_top = bp + (gtm_uint64_t)csd->n_bts * buffer_size;
- GTMCRYPT_ONLY(
- if (csd->is_encrypted)
- { /* In case of an encrypted database, bp_top is actually the beginning of the encrypted global buffer
- * array (an array maintained parallely with the regular unencrypted global buffer array.
- */
- cnl->encrypt_glo_buff_off = (sm_off_t)((sm_uc_ptr_t)bp_top - (sm_uc_ptr_t)bp);
- }
- )
- }
+ bp = (sm_uc_ptr_t)ROUND_UP((sm_ulong_t)cr_top, OS_PAGE_SIZE);
+ bp_top = bp + (gtm_uint64_t)csd->n_bts * buffer_size;
+ GTMCRYPT_ONLY(
+ if (csd->is_encrypted)
+ { /* In case of an encrypted database, bp_top is actually the beginning of the encrypted global buffer
+ * array (an array maintained parallely with the regular unencrypted global buffer array.
+ */
+ cnl->encrypt_glo_buff_off = (sm_off_t)((sm_uc_ptr_t)bp_top - (sm_uc_ptr_t)bp);
+ }
+ )
for (; cr < cr_top; cr = (cache_rec_ptr_t)((sm_uc_ptr_t)cr + rec_size),
cr1 = (cache_rec_ptr_t)((sm_uc_ptr_t)cr1 + rec_size))
{
if (init)
- {
- if (!is_mm)
- {
- INTERLOCK_INIT(cr);
- } else
- {
- INTERLOCK_INIT_MM(cr);
- }
- }
+ INTERLOCK_INIT(cr);
cr->cycle++; /* increment cycle whenever buffer's blk number changes (for tp_hist) */
cr->blk = CR_BLKEMPTY;
/* Typically db_csh_ref is invoked from db_init (when creating shared memory afresh) in which case cr->bt_index
@@ -128,12 +94,9 @@ void db_csh_ref(sgmnt_addrs *csa, boolean_t init)
cr->bt_index = 0;
if (init)
{
- if (!is_mm)
- {
- assert(bp <= bp_top);
- cr->buffaddr = GDS_ANY_ABS2REL(csa, bp);
- bp += buffer_size;
- }
+ assert(bp <= bp_top);
+ cr->buffaddr = GDS_ANY_ABS2REL(csa, bp);
+ bp += buffer_size;
insqt((que_ent_ptr_t)cr, (que_ent_ptr_t)cr1);
}
cr->refer = FALSE;
diff --git a/sr_port/dbcertify_certify_phase.c b/sr_port/dbcertify_certify_phase.c
index c62da0b..2dc32e7 100644
--- a/sr_port/dbcertify_certify_phase.c
+++ b/sr_port/dbcertify_certify_phase.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2005, 2012 Fidelity Information Services, Inc *
+ * Copyright 2005, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -129,7 +129,7 @@ void dbcertify_certify_phase(void)
if (CLI_PRESENT == cli_present("BLOCKS"))
{
if (!cli_get_hex("BLOCKS", &psa->blocks_to_process))
- exit(1); /* Error message already raised */
+ exit(EXIT_FAILURE); /* Error message already raised */
} else
psa->blocks_to_process = MAXTOTALBLKS_V4;
if (CLI_PRESENT == cli_present("TEMPFILE_DIR"))
diff --git a/sr_port/dbcertify_funcs.c b/sr_port/dbcertify_funcs.c
index 4778acb..c4f67f5 100644
--- a/sr_port/dbcertify_funcs.c
+++ b/sr_port/dbcertify_funcs.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2005, 2012 Fidelity Information Services, Inc *
+ * Copyright 2005, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -9,7 +9,7 @@
* *
****************************************************************/
-#define _POSIX_EXIT /* Needed for VMS system() call */
+#define _POSIX_EXIT /* Needed for VMS system() call */ /* BYPASSOK: system() used insode the comment, no SYSTEM() needed */
#include "mdef.h"
#ifdef VMS
@@ -93,11 +93,12 @@ void dbc_open_command_file(phase_static_area *psa)
dont_sendmsg_on_log2long);
#ifdef UNIX
if (SS_LOG2LONG == status)
- rts_error(VARLSTCNT(5) ERR_LOGTOOLONG, 3, gtm_dist_m.len, gtm_dist_m.addr, SIZEOF(gtm_dist_path_buff) - 1);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_LOGTOOLONG, 3,
+ gtm_dist_m.len, gtm_dist_m.addr, SIZEOF(gtm_dist_path_buff) - 1);
else
#endif
if (SS_NORMAL != status)
- rts_error(VARLSTCNT(1) ERR_GTMDISTUNDEF);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_GTMDISTUNDEF);
assert(0 < gtm_dist_path.len);
VMS_ONLY(dbc_remove_command_file(psa)); /* If we don't do this, the command files versions pile up fast */
psa->tcfp = Fopen((char_ptr_t)psa->tmpcmdfile, "w");
@@ -105,7 +106,7 @@ void dbc_open_command_file(phase_static_area *psa)
{
save_errno = errno;
errmsg = STRERROR(save_errno);
- rts_error(VARLSTCNT(8) ERR_DEVOPENFAIL, 2, psa->tmpcmdfile_len, psa->tmpcmdfile,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_DEVOPENFAIL, 2, psa->tmpcmdfile_len, psa->tmpcmdfile,
ERR_TEXT, 2, RTS_ERROR_TEXT(errmsg));
}
UNIX_ONLY(dbc_write_command_file(psa, SHELL_START));
@@ -128,7 +129,7 @@ void dbc_write_command_file(phase_static_area *psa, char_ptr_t cmd)
{
save_errno = errno;
errmsg = STRERROR(save_errno);
- rts_error(VARLSTCNT(11) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("fprintf()"), CALLFROM, /* BYPASSOK */
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(11) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("fprintf()"), CALLFROM, /* BYPASSOK */
ERR_TEXT, 2, RTS_ERROR_TEXT(errmsg));
}
rc = CHMOD((char_ptr_t)psa->tmpcmdfile, S_IRUSR + S_IWUSR + S_IXUSR + S_IRGRP + S_IROTH); /* Change to 744 */
@@ -136,7 +137,7 @@ void dbc_write_command_file(phase_static_area *psa, char_ptr_t cmd)
{
save_errno = errno;
errmsg = STRERROR(save_errno);
- rts_error(VARLSTCNT(15) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("chmod()"), CALLFROM,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(15) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("chmod()"), CALLFROM,
ERR_TEXT, 2, psa->tmpcmdfile_len, psa->tmpcmdfile,
ERR_TEXT, 2, RTS_ERROR_TEXT(errmsg));
}
@@ -179,7 +180,7 @@ void dbc_run_command_file(phase_static_area *psa, char_ptr_t cmdname, char_ptr_t
*cp = '\0';
dbc_syscmd((char_ptr_t)cmdbuf2);
}
- rts_error(VARLSTCNT(13) ERR_DBCCMDFAIL, 7, rc, cmd_len, cmdbuf1, RTS_ERROR_TEXT(cmdname),
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_DBCCMDFAIL, 7, rc, cmd_len, cmdbuf1, RTS_ERROR_TEXT(cmdname),
RTS_ERROR_TEXT(cmdargs), ERR_TEXT, 2,
RTS_ERROR_LITERAL("Note that the "UNIX_ONLY("environment variable $")VMS_ONLY("logical ")GTM_DIST
" must point to the current GT.M V4 installation"));
@@ -200,7 +201,7 @@ void dbc_remove_command_file(phase_static_area *psa)
{
save_errno = errno;
errmsg = STRERROR(save_errno);
- rts_error(VARLSTCNT(15) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("remove()"), CALLFROM,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(15) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("remove()"), CALLFROM,
ERR_TEXT, 2, psa->tmpcmdfile_len, psa->tmpcmdfile,
ERR_TEXT, 2, RTS_ERROR_TEXT(errmsg));
}
@@ -219,7 +220,7 @@ void dbc_open_result_file(phase_static_area *psa)
{
save_errno = errno;
errmsg = STRERROR(save_errno);
- rts_error(VARLSTCNT(8) ERR_DEVOPENFAIL, 2, psa->tmprsltfile_len, psa->tmprsltfile,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_DEVOPENFAIL, 2, psa->tmprsltfile_len, psa->tmprsltfile,
ERR_TEXT, 2, RTS_ERROR_TEXT(errmsg));
}
}
@@ -240,22 +241,22 @@ uchar_ptr_t dbc_read_result_file(phase_static_area *psa, int rderrmsg, uchar_ptr
{ /* Non-EOF message */
save_errno = errno;
errmsg = STRERROR(save_errno);
- rts_error(VARLSTCNT(11) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("fgets()"), CALLFROM,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(11) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("fgets()"), CALLFROM,
ERR_TEXT, 2, RTS_ERROR_TEXT(errmsg));
} else
{ /* We have EOF */
if (0 != rderrmsg)
- rts_error(VARLSTCNT(4) rderrmsg, 2, RTS_ERROR_TEXT((char_ptr_t)arg));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) rderrmsg, 2, RTS_ERROR_TEXT((char_ptr_t)arg));
else
{
strcpy(emsg, "Temporary results file (");
strcat(emsg, (char_ptr_t)psa->tmprsltfile);
strcat(emsg, " had unexpected values");
- rts_error(VARLSTCNT(6) ERR_PREMATEOF, 0, ERR_TEXT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_PREMATEOF, 0, ERR_TEXT, 2,
RTS_ERROR_TEXT(emsg));
}
}
- exit(1); /* We shouldn't come here but in case... */
+ exit(EXIT_FAILURE); /* We shouldn't come here but in case... */
}
return (uchar_ptr_t)fgs;
}
@@ -282,7 +283,7 @@ void dbc_remove_result_file(phase_static_area *psa)
{
save_errno = errno;
errmsg = STRERROR(save_errno);
- rts_error(VARLSTCNT(15) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("remove()"), CALLFROM,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(15) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("remove()"), CALLFROM,
ERR_TEXT, 2, psa->tmprsltfile_len, psa->tmprsltfile,
ERR_TEXT, 2, RTS_ERROR_TEXT(errmsg));
}
@@ -378,7 +379,7 @@ int dbc_syscmd(char_ptr_t cmdparm)
#endif
#ifdef VMS
- /* Verify system() is supported */
+ /* Verify system() is supported */ /* BYPASSOK: system() used insode the comment, no SYSTEM() needed */
if (0 == SYSTEM(NULL))
GTMASSERT;
#endif
@@ -798,7 +799,7 @@ int dbc_find_record(phase_static_area *psa, dbc_gv_key *key, int blk_index, int
if (!fail_ok)
{
assert(FALSE);
- rts_error(VARLSTCNT(8) ERR_DBCINTEGERR, 2, RTS_ERROR_TEXT((char_ptr_t)psa->ofhdr.dbfn),
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_DBCINTEGERR, 2, RTS_ERROR_TEXT((char_ptr_t)psa->ofhdr.dbfn),
ERR_TEXT, 2, RTS_ERROR_TEXT("Unable to find index record for an existing global"));
}
return -1;
@@ -895,9 +896,9 @@ void dbc_init_db(phase_static_area *psa)
if (0 != ACCESS((char_ptr_t)psa->dbc_gv_cur_region->dyn.addr->fname, (R_OK | W_OK)))
{
if (EACCES == errno)
- rts_error(VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(psa->dbc_gv_cur_region));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(psa->dbc_gv_cur_region));
else
- rts_error(VARLSTCNT(5) ERR_DBOPNERR, 2, DB_LEN_STR(psa->dbc_gv_cur_region), errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_DBOPNERR, 2, DB_LEN_STR(psa->dbc_gv_cur_region), errno);
}
/* Open the database which on VMS gives standalone access (for phase 2) */
psa->fc->op = FC_OPEN;
@@ -908,7 +909,7 @@ void dbc_init_db(phase_static_area *psa)
{ /* Verify the fileid has not changed */
if (!is_gdid_gdid_identical(&psa->ofhdr.unique_id.uid,
&FILE_INFO(psa->dbc_gv_cur_region)->UNIX_ONLY(fileid)VMS_ONLY(file_id)))
- rts_error(VARLSTCNT(1) ERR_DBCNOTSAMEDB);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DBCNOTSAMEDB);
}
/* Read in database file header */
@@ -922,9 +923,9 @@ void dbc_init_db(phase_static_area *psa)
if (0 != memcmp(psa->dbc_cs_data->label, V15_GDS_LABEL, GDS_LABEL_SZ - 1))
{
if (memcmp(psa->dbc_cs_data->label, V15_GDS_LABEL, GDS_LABEL_SZ - 3))
- rts_error(VARLSTCNT(4) ERR_DBNOTGDS, 2, RTS_ERROR_TEXT((char_ptr_t)psa->ofhdr.dbfn));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_DBNOTGDS, 2, RTS_ERROR_TEXT((char_ptr_t)psa->ofhdr.dbfn));
else
- rts_error(VARLSTCNT(4) ERR_BADDBVER, 2, RTS_ERROR_TEXT((char_ptr_t)psa->ofhdr.regname));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_BADDBVER, 2, RTS_ERROR_TEXT((char_ptr_t)psa->ofhdr.regname));
}
if (!psa->phase_one)
@@ -945,12 +946,15 @@ void dbc_init_db(phase_static_area *psa)
#endif
/* Verify reserved_bytes and max_rec_len again and verify kill_in_prog is not set */
if (VMS_ONLY(9) UNIX_ONLY(8) > psa->dbc_cs_data->reserved_bytes)
- rts_error(VARLSTCNT(4) ERR_DBMINRESBYTES, 2, VMS_ONLY(9) UNIX_ONLY(8), psa->dbc_cs_data->reserved_bytes);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_DBMINRESBYTES, 2,
+ VMS_ONLY(9) UNIX_ONLY(8), psa->dbc_cs_data->reserved_bytes);
if (SIZEOF(blk_hdr) > (psa->dbc_cs_data->blk_size - psa->dbc_cs_data->max_rec_size))
- rts_error(VARLSTCNT(5) ERR_DBMAXREC2BIG, 3, psa->dbc_cs_data->max_rec_size, psa->dbc_cs_data->blk_size,
- (psa->dbc_cs_data->blk_size - SIZEOF(blk_hdr)));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_DBMAXREC2BIG, 3,
+ psa->dbc_cs_data->max_rec_size, psa->dbc_cs_data->blk_size,
+ (psa->dbc_cs_data->blk_size - SIZEOF(blk_hdr)));
if (0 != psa->dbc_cs_data->kill_in_prog)
- rts_error(VARLSTCNT(4) ERR_DBCKILLIP, 2, RTS_ERROR_TEXT((char_ptr_t)psa->ofhdr.dbfn));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_DBCKILLIP, 2,
+ RTS_ERROR_TEXT((char_ptr_t)psa->ofhdr.dbfn));
/* Turn off replication and/or journaling for our trip here */
if (jnl_open == psa->dbc_cs_data->jnl_state)
{
diff --git a/sr_port/deviceparameters.c b/sr_port/deviceparameters.c
index 5cf94d3..fddb059 100644
--- a/sr_port/deviceparameters.c
+++ b/sr_port/deviceparameters.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -67,6 +67,7 @@ LITDEF nametabent dev_param_names[] =
,{2,"EB*"} ,{4,"EBCD"}
,{2,"EC*"}
,{2,"ED*"} ,{4,"EDIT"}
+ ,{4,"EMPT*"} ,{7,"EMPTERM"}
,{6,"ERASEL*"}
,{6,"ERASET*"}
,{2,"ES*"}
@@ -81,7 +82,8 @@ LITDEF nametabent dev_param_names[] =
,{3,"FIX*"} ,{5,"FIXED"}
,{3,"FLA*"}
,{3,"FLU*"}
- ,{2,"FO*"}
+ ,{2,"FO"} ,{3,"FOR*"}
+ ,{3,"FOL*"} ,{6,"FOLLOW"}
,{1,"G"} ,{2,"GR*"}
@@ -120,11 +122,13 @@ LITDEF nametabent dev_param_names[] =
,{4,"NOEB*"}
,{4,"NOEC*"} ,{6,"NOECHO"}
,{4,"NOED*"} ,{6,"NOEDIT"}
+ ,{6,"NOEMPT*"} ,{9,"NOEMPTERM"}
,{4,"NOES*"} ,{6,"NOESCA"}
,{5,"NOEXT*"}
,{5,"NOFIL*"}
,{5,"NOFIX*"}
,{5,"NOFLA*"}
+ ,{5,"NOFOL*"} ,{8,"NOFOLLOW"}
,{4,"NOHE*"}
,{5,"NOHOL*"}
,{5,"NOHOS*"} ,{6,"NOHOST"}
@@ -258,27 +262,35 @@ LITDEF nametabent dev_param_names[] =
,{4,"ZWRA*"}
};
/* Offset of letter in dev_param_names */
+/* Following array has reached the maximum value limit(255) for its entry. Hence adddition of the next deviceparameter needs
+ * to change this array to short or int. This will lead to change the interface to namelook() and the type of the first argument
+ * passed to it. Once that is implemented, remove this comment.
+ */
LITDEF unsigned char dev_param_index[27] =
{
/* A B C D E F G H I J K L M N */
- 0, 5, 9, 26, 34, 47, 59, 61, 65, 71, 71, 71, 79, 82,
+ 0, 5, 9, 26, 34, 49, 64, 66, 70, 76, 76, 76, 84, 87,
/* O P Q R S T U V W X Y Z end */
- 144, 149, 168, 169, 182, 200, 209, 215, 216, 231, 232, 233, 247
+ 153, 158, 177, 178, 191, 209, 218, 224, 225, 240, 241, 242, 255
};
/* Offset of string within letter in dev_param_names */
/* maintained in conjunction with zshow_params.h = offset in letter, letter */
LITDEF zshow_index zshow_param_index[] =
{
-/* ALLO BLOC COMMAND CONV CTRA DELE DEST EBCD EDIT EXCE EXTE FIELD FIL FIXED */
- {2,0}, {2,1}, {9,2}, {12,2}, {16,2}, {1,3}, {3,3}, {1,4}, {4,4}, {9,4}, {11,4}, {2,5}, {5,5}, {8,5},
+/* ALLO BLOC COMMAND CONV CTRA DELE DEST EBCD EDIT EMPTERM EXCE EXTE FIELD */
+ {2,0}, {2,1}, {9,2}, {12,2}, {16,2}, {1,3}, {3,3}, {1,4}, {4,4}, {6,4}, {11,4}, {13,4}, {2,5},
+/* FIL FIXED FOLLOW */
+ {5,5}, {8,5}, {14,5},
/* HOST ICHSET INDEPENDENT INSE LAB */
{3,7}, {0,8}, {2,8}, {4,8}, {1,11},
-/* LENG NOCENE NODEST NOECHO NOEDIT NOESCA NOHOST NOINSE */
- {3,11}, {7,13}, {10,13}, {15,13}, {17,13}, {19,13}, {27,13}, {29,13},
+/* LENG NOCENE NODEST NOECHO NOEDIT NOEMPTERM NOESCA NOFOLLOW NOHOST NOINSE */
+ {3,11}, {7,13}, {10,13}, {15,13}, {17,13}, {19,13}, {21,13}, {27,13}, {31,13}, {33,13},
/* NOPAST NOREADS NOTTSY NOTYPE NOWRAP OCHSET PAD PARSE PAST PRMMBX RCHK */
- {35,13}, {40,13}, {51,13}, {53,13}, {59,13}, {1,14}, {8,15}, {11,15}, {13,15}, {17,15}, {1,17},
-/* READ READS REC SHAR SHELL STDERR TERM TTSY TYPE UIC WAIT WCHK WIDTH WRITE */
- {2,17}, {4,17}, {5,17}, {5,18}, {7,18}, {15,18}, {1,19}, {6,19}, {8,19}, {1,20}, {2,22}, {4,22}, {6,22}, {10,22}
+ {39,13}, {44,13}, {55,13}, {57,13}, {63,13}, {1,14}, {8,15}, {11,15}, {13,15}, {17,15}, {1,17},
+/* READ READS REC SHAR SHELL STDERR TERM TTSY TYPE UIC WAIT WCHK */
+ {2,17}, {4,17}, {5,17}, {5,18}, {7,18}, {15,18}, {1,19}, {6,19}, {8,19}, {1,20}, {2,22}, {4,22},
+/* WIDTH WRITE */
+ {6,22}, {10,22}
};
int deviceparameters(oprtype *c, char who_calls)
@@ -331,6 +343,7 @@ int deviceparameters(oprtype *c, char who_calls)
,iop_ebcdic ,iop_ebcdic
,iop_echo
,iop_editing ,iop_editing
+ ,iop_empterm ,iop_empterm
,iop_eraseline
,iop_erasetape
,iop_escape
@@ -345,7 +358,8 @@ int deviceparameters(oprtype *c, char who_calls)
,iop_fixed ,iop_fixed
,iop_flag
,iop_flush
- ,iop_form
+ ,iop_form ,iop_form
+ ,iop_follow ,iop_follow
,iop_g_protection, iop_g_protection
@@ -384,11 +398,13 @@ int deviceparameters(oprtype *c, char who_calls)
,iop_noebcdic
,iop_noecho ,iop_noecho
,iop_noediting ,iop_noediting
+ ,iop_noempterm ,iop_noempterm
,iop_noescape ,iop_noescape
,iop_inhextgap
,iop_nofilter
,iop_nofixed
,iop_noflag
+ ,iop_nofollow ,iop_nofollow
,iop_noheader
,iop_nohold
,iop_nohostsync ,iop_nohostsync
@@ -523,8 +539,14 @@ int deviceparameters(oprtype *c, char who_calls)
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
- assert((SIZEOF(dev_param_names) / SIZEOF(nametabent) == dev_param_index[26]));
- assert((SIZEOF(dev_param_data) / SIZEOF(unsigned char)) == dev_param_index[26]);
+ /* The value of dev_param_index[26] should be 256 but is 255 since that is all that can fit in a unsigned char. That is why
+ * following asserts has (dev_param_index[26] + 1). Once the type of dev_param_index is changed, the "+ 1" in following
+ * assert should be removed.
+ */
+ assert((SIZEOF(dev_param_names) / SIZEOF(nametabent) == dev_param_index[26] + 1));
+ assert((SIZEOF(dev_param_data) / SIZEOF(unsigned char)) == dev_param_index[26] + 1);
+ assert(dev_param_index[26] == 255);
+ assert(SIZEOF(dev_param_index[26] == SIZEOF(char)));
is_parm_list = (TK_LPAREN == TREF(window_token));
if (is_parm_list)
advancewindow();
diff --git a/sr_port/dse.h b/sr_port/dse.h
index c6b54a9..7341530 100644
--- a/sr_port/dse.h
+++ b/sr_port/dse.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -104,7 +104,7 @@ enum dse_fmt
{ \
if(!cli_get_str("CONFIRMATION",(X),&(Y))) \
{ \
- rts_error(VARLSTCNT(1) ERR_DSEWCINITCON); \
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DSEWCINITCON); \
return; \
} \
}
@@ -119,22 +119,18 @@ enum dse_fmt
GET_CONFIRM(confirm, len); \
if (confirm[0] != 'Y' && confirm[0] != 'y') \
{ \
- rts_error(VARLSTCNT(1) ERR_DSEWCINITCON); \
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DSEWCINITCON); \
return; \
} \
}
-#define DSE_WCREINIT(CS_ADDRS) \
-{ \
- assert(CS_ADDRS->now_crit); \
- bt_init(CS_ADDRS); \
- if (CS_ADDRS->hdr->acc_meth == dba_bg) \
- { \
- bt_refresh(CS_ADDRS, TRUE); \
- db_csh_ini(CS_ADDRS); \
- db_csh_ref(CS_ADDRS, TRUE); \
- send_msg(VARLSTCNT(4) ERR_DSEWCREINIT, 2, DB_LEN_STR(gv_cur_region)); \
- } \
+#define DSE_WCREINIT(CS_ADDRS) \
+{ \
+ assert(CS_ADDRS->now_crit); \
+ if (CS_ADDRS->hdr->acc_meth == dba_bg) \
+ bt_refresh(CS_ADDRS, TRUE); \
+ db_csh_ref(CS_ADDRS, TRUE); \
+ send_msg_csa(CSA_ARG(CS_ADDRS) VARLSTCNT(4) ERR_DSEWCREINIT, 2, DB_LEN_STR(gv_cur_region)); \
}
void dse_ctrlc_setup(void);
diff --git a/sr_port/dse.hlp b/sr_port/dse.hlp
index e4da1e7..b10f29e 100644
--- a/sr_port/dse.hlp
+++ b/sr_port/dse.hlp
@@ -1,852 +1,2036 @@
+1 Operations
+ Operations
+
+ The GT.M Database Structure Editor, DSE, is primarily a tool for
+ authorized GT.M consultants to examine and, under unusual circumstances,
+ repair GT.M Database Structure (GDS) databases. With DSE, it is possible
+ to see and change most of the attributes of a GT.M database.
+
+ DSE gives all possible control over a database and therefore, it may cause
+ irreparable damage when used without knowing the consequences. Therefore,
+ you unless you have extensive experience, you should always get guidance
+ from FIS or an equivalently knowledgeable support resource before running
+ any DSE command that changes any attribute of any production database or
+ other database you value. However, you can use those DSE commands that let
+ you see the attributes of your database for collecting database metrics
+ and monitoring status.
+
+ GT.M installation procedure places the DSE utility program in a directory
+ specified by the environment variable gtm_dist.
+
+ Invoke DSE using the "dse" command at the shell prompt. If this does not
+ work, consult your system manager to investigate setup and file access
+ issues.
-1 Overview
- Overview
- The GT.M Database Structure Editor, DSE, examines and repairs
- Greystone Technology Database Structure (GDS) database(s). GT.M uses
- Buffered Global (BG) and Mapped Memory (MM) access methods for GDS
- files. For more information on GDS, refer to the "Greystone Database
- Structure" chapter in the GT.M Administration and Operations Guide.
- MUPIP INTEG provides comprehensive error checking, which serves to
- verify the results of repairs undertaken with DSE. For more
- information on MUPIP INTEG, refer to the "MUMPS Peripheral Interchange
- Program" chapter in the GT.M Administration and Operations Guide. For
- more information on the use of DSE, refer to the "Maintaining Database
- Integrity" chapter in the GT.M Administration and Operations Guide.
+ Example:
+
+ $gtm_dist/dse
+ File/usr/name/mumps.dat
+ Region DEFAULT
+ DSE>
+
+ DSE displays the DSE> prompt.
+
+ You may also specify a command when entering DSE.
+
+ By default, DSE starts with the region that stands first in the list of
+ regions arranged in alphabetical order. In the above example, the first
+ region is DEFAULT.
+
+ You may also specify a command when entering DSE.
+
+ Example:
+
+ $gtm_dist/dse dump -fileheader
+
+ This command displays the fileheader of the region that stands first in
+ the list of regions arranged in alphabetical order and then returns to the
+ shell prompt. To look at other regions, at the DSE prompt you must first
+ issue a FIND -REGION=<desired-region> command.
+
+ As previously mentioned, DSE provides control over most of the attributes
+ of your database. With DSE, it is possible to examine them and,with a few
+ exceptions, change them.
+
+ All DSE commands are divided into two categories-Change commands and
+ Inquiry commands. Change commands allow you to modify the attribute of
+ your database, in most cases without any warning or error. As the low
+ level tool of last resort, Change commands allow you to take certain
+ actions that can cause extensive damage when undertaken without an
+ extensive understanding of the underlying data structures on disk and in
+ memory and with an imperfect understanding of the commands issued. Do not
+ use the Change commands unless you know exactly what you are doing and
+ have taken steps to protect yourself against mistakes, both inadvertent
+ and resulting from an incomplete understanding of the commands you issue.
+ Change commands are not required for normal operation, and are usually
+ only used under the direction of FIS support to recover from the
+ unanticipated consequences of failures not adequately planned for (for
+ example, you should configure GT.M applications such that you never need a
+ Change command to recover from a system crash).
+
+ Inquiry commands let you see the attributes of your database. You may
+ frequently use the inquiry commands for collecting your database metrics
+ and status reporting.
+
+ The list of Change commands is as follows:
+
+ AD[D]
+ AL[L]
+ B[UFFER _FLUSH]
+ CH[ANGE]
+ CR[ITICAL]
+ REM[OVE]
+ RES[TORE]
+ SH[IFT]
+ W[CINIT]
+ OV[ERWRITE]
+ M[APS] -BU[SY] -F[REE] -M[ASTER] -R[ESTORE_ALL]
+
+ The list of Inquiry commands is as follows:
+
+ CL[OSE]
+ D[UMP]
+ EV[ALUATE]
+ EX[IT]
+ F[IND]
+ H[ELP]
+ I[NTEGRIT]
+ M[APS] -BL[OCK]
+ OP[EN]
+ P[AGE]
+ RA[NGE]
+ SA[VE]
+ SP[AWN]
+
+ Although DSE can operate concurrently with other processes that access the
+ same database file, FIS strongly recommends using DSE in standalone mode
+ when using Change commands. Some DSE operations can adversely impact the
+ database when they occur during active use of the database. Other DSE
+ operations may be difficult to perform in a logically sound fashion
+ because a DSE operator works on a block at a time, while normal database
+ operations update all related blocks almost simultaneously.
+
+ **Caution**
+
+ When DSE attaches to a database with a version that does not match the DSE
+ version, DSE issues an informational message and continues. At this point,
+ you should exit DSE and find the version of DSE that matches the database.
+ You should continue after this warning if and only if you are certain that
+ the DSE is indeed from the GT.M version that has the database open (and
+ hence the error results from a damaged database file header or shared
+ memory that you intend to repair, following instructions from FIS).
+
+ Use the DSE EXIT, or QUIT command to leave DSE.
+
+1 Commands
+ Commands
+
+ The format for DSE commands is:
+
+ DSE> command [-qualifier[...]] [object[,...]]
+
+ DSE interprets all numeric input as hexadecimal, except for time values,
+ the values for the following qualifiers when used with CHANGE -FILEHEADER:
+ -BLK_SIZE=, DECLOCATION=, -KEY_MAX_SIZE=, -RECORD_MAX_SIZE,
+ -REFERENCE_COUNT=, -TIMERS_PENDING and -WRITES_PER_FLUSH, and the value
+ for -VERSION= when used with the REMOVE and RESTORE commands. These
+ conventions correspond to the displays provided by DSE and by MUPIP INTEG.
+
+2 ADD
+ ADD
+
+ Adds a record to a block. The format of the ADD command for blocks with a
+ level greater than zero (0) is:
+
+ ADD [-B[LOCK]=[block] {-OFFSET=offset|-RECORD=record} -STAR -POINTER=block
+
+ or
+
+ ADD [-B[LOCK]=[block] {-OFFSET=offset|-RECORD=record} -KEY=key -POINTER=pointer
+
+ The format of the ADD command for level 0 blocks is:
+
+ ADD [-B[LOCK]=[block] {-OFFSET=offset|-RECORD=record} -KEY=key -DATA=string
+
+ The ADD command requires either the -OFFSET or -RECORD qualifier to
+ position the record in the block, and either the -KEY or the -STAR
+ qualifier to define the key for the block.
+
+ The -STAR qualifier is invalid at level 0 (a data block). The ADD command
+ requires the -DATA qualifier at level 0 or the -POINTER qualifier at any
+ other level to provide record content.
+
+3 Qualifiers
+ Qualifiers
+
+ -B[LOCK]=block-number
+
+ Specifies the block to receive the new record.
+
+ On commands with no -BLOCK= qualifier, DSE uses the last block handled by
+ a DSE operation. When no block has been accessed, that is, on the first
+ block-oriented command, DSE uses block one (1).
+
+ -D[ATA]=string
+
+ Specifies the data field for records added to a data block. Use quotation
+ marks around the string and escape codes of the form \a\b, where "a" and
+ "b" are hexadecimal digits representing non-printing characters. \\
+ translates to a single backslash. \'\' translates to a NULL value.
+
+ Incompatible with: -STAR,-POINTER
+
+ -K[EY]=key
+
+ Specifies the key of the new record. Enclose M-style global references,
+ including the leading caret symbol (^), in quotation marks (" ").
+
+ Incompatible with: -STAR
+
+ -O[FFSET]=offset
+
+ Adds the new record at the next record boundary after the specified
+ offset.
+
+ Incompatible with: -RECORD, -STAR
+
+ -P[OINTER]=pointer
+
+ Specifies the block pointer field for records added to an index block. The
+ -POINTER qualifier cannot be used at level 0. Note this means that to add
+ pointers at level 0 of the Directory Tree you must specify a string of
+ bytes or temporarily change the block level.
+
+ Incompatible with: -DATA
+
+ -R[ECORD]=record-number
+
+ Specifies a record number of the new record.
+
+ Incompatible with: -OFFSET,-STAR
+
+ -S[TAR]
+
+ Adds a star record (that is, a record that identifies the last record in
+ an indexed block) at the end of the specified block. The -STAR qualifier
+ cannot be used at level 0.
+
+ Incompatible with: -DATA,-KEY,-OFFSET,-RECORD
+
+3 Examples
+ Examples
+
+ DSE>add -block=6F -record=57 -key="^Capital(""Mongolia"")" -data="Ulan Bator"
+
+ This command adds a new record with key ^Capital("Mongolia") at the
+ specified location. Note that this command is applicable to level 0 blocks
+ only.
+
+ Example:
+
+ DSE>add -star -bl=59A3 -pointer=2
+
+ This command adds a star record in block 59A3. Note that this command is
+ applicable to blocks > level 0.
+
+ Example:
+
+ DSE>add -block=3 -record=4 -key="^Fruits(4)" -data="Grapes"
+
+ Suppose your database has 3 global nodes -- ^Fruits(1)="Apple",
+ ^Fruits(2)="Banana", and ^Fruits(3)="Cherry", then the above command adds
+ a new node ^Fruits(4)="Grapes" at record 4. Note that this command is
+ applicable to level 0 blocks only. The interpreted output as a result of
+ the above command looks like the following:
+
+ Block 3 Size 4B Level 0 TN 6 V5
+
+ Rec:1 Blk 3 Off 10 Size 14 Cmpc 0 Key ^Fruits(1)
+ 10 : | 14 0 0 0 46 72 75 69 74 73 0 BF 11 0 0 41 70 70 6C 65|
+ | . . . . F r u i t s . . . . . A p p l e|
+
+ Rec:2 Blk 3 Off 24 Size D Cmpc 8 Key ^Fruits(2)
+ 24 : | D 0 8 0 21 0 0 42 61 6E 61 6E 61 |
+ | . . . . ! . . B a n a n a |
+
+ Rec:3 Blk 3 Off 31 Size D Cmpc 8 Key ^Fruits(3)
+ 31 : | D 0 8 0 31 0 0 43 68 65 72 72 79 |
+ | . . . . 1 . . C h e r r y |
+
+ Rec:4 Blk 3 Off 3E Size D Cmpc 8 Key ^Fruits(4)
+ 3E : | D 0 8 8 41 0 0 47 72 61 70 65 73 |
+ | . . . . A . . G r a p e s |
+
+ Example:
+
+ $dse add -star -bl=1 -pointer=2
+
+ This command adds a star record in block 1. Note that this command is
+ applicable to blocks > Level 0.
+
+ Example:
+
+ $ dse add -block=4 -key="^Vegetables" -pointer=7 -offset=10
+
+ This command creates a block with key ^Vegetables pointing to block 7.
+
+ Example:
+
+ DSE> add -record=2 -key="^foo" -data=\'\'
+
+ This example adds a new node (set ^foo="") as the second record of the
+ current database block.
+
+2 ALL
+ ALL
+
+ Applies action(s) specified by a qualifier to all GDS regions defined by
+ the current global directory.
+
+ The format of the ALL command is:
+
+ AL[L] -B[UFFER_FLUSH]
+ -C[RITINIT]
+ -[NO]F[REEZE]
+ -O[VERRIDE]]
+ -REF[ERENCE]
+ -REL[EASE]
+ -REN[EW]
+ -S[EIZE]
+ -W[CINIT]
+
+ o This is a very powerful command; use it with caution.
+ o Be especially careful if you have an overlapping database structure
+ (for example, overlapping regions accessed from separate application
+ global directories).
+ o If you use this type of database structure, you may need to construct
+ special Global Directories that exclude overlapped regions to use with
+ DSE.
+
+3 Qualifiers
+ Qualifiers
+
+ -BUFFER_FLUSH
+
+ Flushes to disk the file header and all pooled buffers for all regions of
+ the current global directory.
+
+ Incompatible with: -RENEW
+
+ -C[RITINIT]
+
+ Initializes critical sections for all regions of the current directory.
+
+ Incompatible with: -RENEW, -RELEASE, -SIEZE
+
+ **Caution**
+
+ Never use CRITINIT while concurrent updates are in progress as doing so
+ may damage the database.
+
+ -[NO]F[REEZE]
+
+ Freezes or prevents updates all regions of the current global directory.
+
+ o The FREEZE qualifier freezes all GDS regions except those previously
+ frozen by another process . Regions frozen by a particular process are
+ associated with that process .
+ o A frozen region may be unfrozen for updates in one of two ways: The
+ process which froze the region may unfreeze it with the -NOFREEZE
+ qualifier; or another process may override the freeze in conjunction
+ with the -OVERRIDE qualifier.
+ o By default, the -NOFREEZE qualifier unfreezes only those GDS regions
+ that were previously frozen by a process . Once a region is unfrozen,
+ it may be updated by any process .To unfreeze all GDS regions of the
+ Global Directory, use the -OVERRIDE qualifier.
+ o DSE releases any FREEZE it holds when it exits, therefore, use the
+ same DSE invocation or SPAWN to perform operations after executing the
+ ALL -FREEZE command.
+
+ Incompatible with: -RENEW
+
+ -O[VERRIDE]
+
+ Overrides the ALL -FREEZE or ALL -NOFREEZE operation.
+
+ When used with -NOFREEZE, -OVERRIDE unfreezes all GDS regions, including
+ those frozen by other users.
+
+ When used with -FREEZE, -OVERRIDE freezes all GDS regions, including those
+ frozen by other processes associating all such freezes with the current
+ process. The current process must then use -NOFREEZE to unfreeze the
+ database; any other process attempting a -NOFREEZE should also have to
+ include the -OVERRIDE qualifier.
+
+ Meaningful only with: [NO]FREEZE
+
+ -REF[ERENCE]
+
+ Resets the reference count field to 1 for all regions of the current
+ global directory.
+
+ o A Reference count is a file header element field that tracks how many
+ processes are accessing the database with read/write permissions.
+ o This qualifier is intended for use when DSE is the only process
+ attached to the databases of the curent global directory. Using it
+ when there are other users attached produces an incorrect value.
+
+ Incompatible with: -RENEW
+
+ -REL[EASE]
+
+ Releases critical sections for all regions of the current global
+ directory.
+
+ Incompatible with: -CRITINIT, -RENEW, -SEIZE
+
+ -REN[EW]
+
+ Reinitializes the critical sections (-CRITICAL) and buffers (-WCINIT),
+ resets reference counts (-REFERENCE_COUNT) to 1, and clears freeze
+ (-NOFREEZE) for all regions of the current global directory .
+
+ o -RENEW requires confirmation.
+ o The RENEW action will cause all current accessors of the affected
+ database regions to receive a fatal error on their next access
+ attempt.
+ o This operation is dangerous, drastic, and a last resort if multiple
+ database have hangs that have not yielded to other resolution
+ attempts; there is almost never a good reason to use this option.
+
+ -S[EIZE]
+
+ Seizes the critical section for all regions of the current global
+ directory. The -SEIZE qualifier is useful when you encounter a
+ DSEBLKRDFAIL error, generated when DSE is unable to read a block from the
+ database.
+
+ Incompatible with: -RENEW, -RELEASE, -CRITINIT
+
+ -W[CINIT]
+
+ Reinitializes the buffers for all regions of the current global directory.
+
+ -WCINIT requires confirmation.
+
+ **Caution**
+
+ This operation is likely to cause database damage when used while
+ concurrent updates are in progress.
+
+ Incompatible with: -RENEW
+
+3 Examples
+ Examples
+
+ Example:
+
+ DSE> all flush -buffer_flush
+
+ This command flushes the file header and cache buffers to disk for all
+ regions.
+
+ Example:
+
+ DSE> ALL -CRITINIT
+
+ This command initializes critical sections for all regions of the current
+ directory.
+
+ Example:
+
+ DSE> ALL -FREEZE
+ DSE> SPAWN "mumps -dir"
+
+ The first command freezes all regions of the current global directory. The
+ second command creates an child (shell) process and executes the "mumps
+ -dir" command. Then type S ^A=1 at GTM prompt. Notice that the command
+ hangs because of the DSE FREEZE in place.
+
+ Example:
+
+ DSE> ALL -NOFREEZE -OVERRIDE
+
+ This command removes the FREEZE on all current region including the FREEZE
+ placed by other users.
+
+ Example:
+
+ DSE> ALL -REFERENCE
+
+ This command sets the reference count field in the file header(s) to 1.
+
+ Example:
+
+ DSE> ALL -RELEASE
+
+ This command releases critical sections owned by the current process for
+ all regions of the current global directory.
+
+ Example:
+
+ DSE> ALL -RENEW
+
+ This command reinitializes critical sections, buffers, resets the
+ reference count to 1, and clears freeze for all regions of the current
+ global directory.
+
+ Example:
+
+ DSE> ALL -SEIZE
+
+ This command seizes all critical sections for all regions of the current
+ global directory.
+
+ Example:
+
+ DSE> WCINIT
+
+ This command reinitializes the buffers for all regions of the current
+ global directory.
+
+2 Buffer_flush
+ Buffer_flush
+
+ Flushes the file header and the current region's buffers to disk.
+
+ The format of the BUFFER_FLUSH command is:
+
+ B[UFFER_FLUSH]
+
+ The BUFFER_FLUSH command has no qualifiers.
+
+2 CHange
+ CHange
+
+ The CHANGE command changes fields of a block, file, or record header.
+
+ The format of the CHANGE command is:
+
+ CH[ANGE]
+
+ The CHANGE command either has a -FILEHEADER qualifier or an implicit or
+ explicit -BLOCK qualifier, plus one or more of their associated
+ qualifiers, to define the target of the change.
+
+ -BL[OCK]=block-number and one or more of the following qualifiers:
+
+ -BS[IZ]=block-size
+ -L[EVEL]=level
+ -TN[=transaction-number]
+ -OF[FSET]=offset
+ -RE[CORD]=record-number
+ -CM[PC]=compression-count
+ -RS[IZ]=record-size
+
+ or
+
+ -F[ILEHEADER] and one or more of the following qualifiers:
+
+ -AB[ANDONED_KILLS]=value
+ -AVG_BLKS_READ=Average-blocks-read
+ -B_B[YTESTREAM]=transaction-number
+ -B_C[OMPREHENSIVE]=transaction-number
+ -B_D[ATABASE]=transaction-number
+ -B_I[NCREMENTAL]=transaction-number
+ -B_R[ECORD]=transaction-number
+ -BLK_SIZE=block-size
+ -BLO[CKS_FREE]=free-blocks
+ -CU[RRENT_TN]=transaction-number
+ -COM[MITWAIT_SPIN_COUNT]=boolean
+ -DEC[LOCATION]=value
+ -DEF[_COLLATION]=value
+ -ENCRYPTION_HASH
+ -FL[USH_TIME][=delta-time]
+ -FR[EEZE]=value
+ -FU[LLY_UPGRADED]=boolean
+ -GV[STATSRESET]
+ -HARD_SPIN_CPUNT=Mutex-hard-spin-sount
+ -[HEXLOCATION]=value
+ -INT[ERRUPTED_RECOV]=boolean
+ -JNL_YIELD_LIMIT=journal-yeild-limit
+ -KE[Y_MAX_SIZE]=key-max-size
+ -KI[LL_IN_PROG]=value
+ -M[ACHINE_NAM]=value
+ -N[ULL_SUBSCRIPTS]=value
+ -NO[CRIT]
+ -OV[ERRIDE]
+ -Q[DBRUNDOWN]
+ -RC_SRV_COUNT
+ -RE_READ_TRIGGER=read-trigger
+ -REC[ORD_MAX_SIZE]=record-max-size
+ -REF[ERENCE_COUNT]=reference-count
+ -REG[_SEQNO]=sequence-number
+ -RESERVED_BYTES=reserved-bytes
+ -SLEEP_SPIN_COUNT=mutex-sleep-spin-count
+ -SPIN_SLEEP_TIME=mutex-sleep-time
+ -STRM_NUM=stream-number STRM_REG_SEQNO=hexa
+ -TIM[ERS_PENDING]=integer
+ -TO[TAL_BLKS]=total-blocks
+ -TR[IGGER_FLUSH]=trigger-flus
+ -UPD_RESERVED_AREA=reserved- area
+ -UPD_WRITER_TRIGGER_FACTOR=trigger-factor
+ -W[RITES_PER_FLUSH]=writes-per-flush
+ -WAIT_DISK=wait-disk
+ -Zqgblmod_S[EQNO]=sequence-number
+ -Zqgblmod_T[rans]=sequence-number
+
+3 BLock_Qualifiers
+ BLock Qualifiers
+
+ This section describes -BLOCK and all of its qualifiers.
+
+ -BL[OCK]=block_number
+
+ Specifies the block to modify. The -BLOCK qualifier is incompatible with
+ the -FILEHEADER qualifier and all qualifiers related to -FILEHEADER.
+
+ -BLOCK is the default qualifier. On commands with neither a -BLOCK nor a
+ -FILEHEADER qualifier, DSE uses the last block handled by a DSE operation.
+ When no block has been accessed, that is, on the first block-oriented
+ command, DSE uses block one (1).
+
+ Incompatible with: -FILEHEADER and qualifiers used with -FILEHEADER
+
+ The following qualifiers operate on a block header.
+
+ -BS[IZ]=block_size
+
+ Changes the block size field of the specified block.
+
+ o block_size is in hexadecimal form.
+ o Decreasing the block size can result in loss of existing data.
+
+ **Note**
+
+ The block size must always be less than or equal to the block size in the
+ file header.
+
+ Use only with: -BLOCK, -LEVEL, -TN
+
+ -L[EVEL]=level
+
+ Changes the level field for the specified block.
+
+ **Note**
+
+ DSE lets you change the level of a bitmap block to -1 (the value of the
+ level for a bitmap block) when the bitmap level gets corrupted and takes
+ on an arbitrary value. Note that you should specify -1 in hexadecimal
+ form, that is, FF.
+
+ Use only with: -BLOCK, -BSIZ, -TN
+
+ Example:
+
+ DSE >change -level=FF
+
+ -TN[=transaction_number]
+
+ Changes the transaction number for the current block.
+
+ o When a CHANGE command does not include a -TN=, DSE sets the
+ transaction number to the current transaction number.
+ o Manipulation of the block transaction number affects MUPIP BACKUP
+ -BYTESTREAM, and -ONLINE.
+
+ Use only with: -BLOCK, -BSIZ, -LEVEL
+
+ -OF[FSET]=offset
+
+ Specifies the offset, in bytes, of the target record within the block. If
+ the offset does not point to the beginning of a record, DSE rounds down to
+ the last valid record start (for example, CHANGE -OFFSET=10 starts at
+ -OFFSET=A, if that was the last record).
+
+ Use only with: -BLOCK, -CMPC, and -RSIZ.
+
+ -RE[CORD]=record_number
+
+ Specifies the record number of the target record.
+
+ Use only with: -BLOCK, -CMPC, and -RSIZ.
+
+ -CM[PC]=compression_count
+
+ Change the compression count field of the specified record.
+
+ o The compression count specifies the number of bytes at the beginning
+ of a key that are common to the previous key in the same block.
+ o Because compression counts propagate from the "front" of the block,
+ this can potentially change the keys of all records following it in
+ the block. If the goal is to change only a single record, it may be
+ preferable to add a new record and remove the old one.
+
+ Use only with: -BLOCK, -RECORD, -OFFSET, -RSIZE
+
+ -RS[IZ]=record_size
+
+ Changes the record size field of the specified record.
+
+ **Caution**
+
+ Changing -RSIZ impacts all records following it in the block.
+
+ Use only with: -BLOCK, -RECORD, -CMPC, -OFFSET
+
+ Example:
+
+ DSE> change -record=3 -rsiz=3B -block=2
+
+ This command changes the record size of record 3 block 2 to 59 (Hex: 3B)
+ bytes.
+
+3 FIleheader_Qualifiers
+ FIleheader Qualifiers
+
+ This section describes the -FILEHEADER qualifier and the other qualifiers
+ that operate on a file header.
+
+ -FI[LEHEADER]
+
+ Modifies a file header element that you specify with an associated
+ qualifier.
+
+ Incompatible with: -BSIZ, -CMPC, -TN, -LEVEL, -OFFSET, -RECORD, -RSIZ
+
+ -AB[ANDONED_KILLS]=value
+
+ Changes the value of the Abandoned Kills field. The value can be "NONE" or
+ a positive integer.
+
+ Use only with: -FILEHEADER; decimal
+
+ -BLK[_SIZE]=block_size
+
+ Changes the decimal block size field of the current file.
+
+ o DSE does not allow you to change the block size to any arbitrary
+ value. It always rounds the block size to the next higher multiple of
+ 512.
+ o Use the CHANGE -BLK_SIZE qualifier only upon receiving instructions
+ from FIS and only in conjunction with the -FILEHEADER qualifier. This
+ DSE command cannot change the working block size of a database and is
+ useful only under very limited and extrordinary circumstances. If you
+ need to change the block size on a database file, unload the data with
+ MUPIP EXTRACT (or an appropriate alternative), change the global
+ directory with GDE to specify the new block size, recreate the
+ database with MUPIP CREATE and reload the data with MUPIP LOAD (or
+ appropriate alternative).
+
+ Use only with: -FILEHEADER
+
+ -BLO[CKS_FREE]=free blocks
+
+ Changes the free blocks field of the current file.
+
+ Use this to correct a value that MUPIP INTEG reports as needing a
+ correction, but note that the "correct" value reported by INTEG may go
+ out-of-date with the next update. It may be necessary to calculate a delta
+ value from the INTEG report, FREEZE the region with DSE, DUMP the current
+ -FILEHEADER value, then apply the delta and CHANGE the -BLOCKS_FREE, and
+ finally turn -OFF the FREEZE.
+
+ Use only with: -FILEHEADER
+
+ -B[YTESTREAM]=transaction_number
+
+ Changes the transaction number in the file header of the last incremental
+ backup to the value specified. Use this qualifier only in conjunction with
+ the -FILEHEADER qualifier. For compatibility issues with priot versions,
+ this can still be specified as -B_COMPREHENSIVE.
+
+ -D[ATABASE]=transaction_number
+
+ Changes the transaction number in the file header of the last
+ comprehensive backup to the value specified. Use this qualifier only in
+ conjunction with the -FILEHEADER qualifier. For compatibility issues with
+ prior versions, this can still be specified as -B_COMPREHENSIVE.
+
+ -B_R[ECORD]=transaction_number
+
+ Changes the transaction number in the file header field that maintains
+ this information about the last -RECORD backup.
+
+ -CO[RRUPT_FILE]=boolean
+
+ Indicates whether or not a region completed a successful recovery with the
+ MUPIP JOURNAL -RECOVER command. Possible values are: T[RUE] or F[ALSE].
+
+ Changing this flag does not correct or cause database damage. When
+ CORRUPT_FILE is set to TRUE, the DSE DUMP command displays a message like
+ the following:
+
+ %GTM-W-DBFLCORRP, /home/gtmnode1/mumps.dat Header indicates database file is corrupt
+
+ **Caution**
+
+ After a CHANGE -FILEHEADER -CORRUPT=TRUE, the file is unavailable to
+ future GT.M access other than DSE. Under normal conditions, there should
+ never be a need to change this flag manually. A MUPIP SET
+ -PARTIAL_BYPASS_RECOV sets this flag to false.
+
+ Use only with: -FILEHEADER
+
+ -COM[MITWAIT_SPIN_COUNT]=value
+
+ Specifies the number of times a GT.M process waiting for control of a
+ block to complete a block update should spin before yielding the CPU when
+ GT.M runs on SMP machines. When run on a uniprocessor system, GT.M ignores
+ this parameter. On SMP systems, when a process needs a critical section
+ that another process has, if critical sections are short (as they are by
+ design in GT.M), spinning a little with the expectation that the process
+ with the critical section will release it shortly provides a way to
+ enhance performance at the cost of increased CPU usage. Eventually, a
+ process awaiting a critical section yields the CPU if spinning for a
+ little does not get it the needed critical section. Note that on heavily
+ loaded systems, increasing COMMITWAIT_SPIN_COUNT may not trade off CPU for
+ throughput, but may instead degrade both. If you set the
+ COMMITWAIT_SPIN_COUNT to 0, the waiting process performs a sequence of
+ small sleeps instead of the spins or yields.
+
+ The default value is 16.
+
+ Use only with: -FILEHEADER
+
+ -CU[RRENT_TN]=transaction_number
+
+ Changes the current transaction number for the current region.
+
+ o Raising the -CURRENT_TN can correct "block transaction number too
+ large" errors
+ o This qualifier has implications for MUPIP BACKUP -INCREMENTAL and
+ -ONLINE.
+ o Used with the -BLOCK qualifier, CURRENT_TN places a transaction number
+ in a block header.
+
+ Use only with: -FILEHEADER
+
+ -DECLOCATION
+
+ Specifies an offset with the file header. If -VALUE is specified, GT.M
+ puts it at that location.
+
+ Use only with: -FILEHEADER; decimal
+
+ -E[NCRYPTION_HASH]
+
+ Changes the hash of the password stored in the database file header if and
+ when you change the hash library.
+
+ **Caution**
+
+ An incorrect hash renders the database useless.
+
+ Use only with: -FILEHEADER
+
+ -FL[USH_TIME][=delta_time]
+
+ Changes the flush_time default interval (in delta_time).
+
+ o The time entered must be between zero and one hour. Input is
+ interpreted as decimal.
+ o A -FLUSH_TIME with no value resets the -FLUSH_TIME to the default
+ value (one second for BG and 30 seconds for MM).
+ o The units of delta_time are hours:minutes:seconds:centi-seconds
+ (hundredths of a second). For example, to change the flush time
+ interval to a second, delta_time would be 00:00:01:00. To change it to
+ 30 minutes, delta_time would be 00:30:00:00. Valid values for the
+ qualifier are one centi-second to one hour.
+
+ Use only with: -FILEHEADER
+
+ -FR[EEZE]=value
+
+ Sets availability of the region for update. Possible values are: T[RUE] or
+ F[ALSE]. Use to "freeze" (disable database writes) or "unfreeze" the
+ database.
+
+ Use only with: -FILEHEADER
+
+ DSE releases -FREEZE when it EXITs. To hold the database(s), CHANGE
+ -FILEHEADER -FREEZE=TRUE and then SPAWN to perform other operations.
+
+ -FU[LLY_UPGRADED]=boolean
+
+ Sets a flag that indicates whether or not the database was fully upgraded
+ from V4 to V5 database format.. The value is either T[RUE] or F[ALSE].
+
+ Use only with: -FILEHEADER
+
+ -GV[STATSRESET]
+
+ Resets all the database file header global access statistics to 0. Note
+ that this erases all statistics previously accumulated in the database
+ file header.
+
+ Use only with: -FILEHEADER
+
+ -HEXLOCATION
+
+ Specifies an offset with the file header. If -VALUE is specified, GT.M
+ puts it at that location.
+
+ Use only with: -FILEHEADER; hexadecimal
+
+ -INT[ERRUPTED_RECOV]=boolean
+
+ Sets a flag that indicates whether or not a recovery with the MUPIP
+ JOURNAL -RECOVER command was interrupted. The value is either T[RUE] or
+ F[ALSE].
+
+ Use only with: -FILEHEADER
+
+ -K[EY_MAX_SIZE]=key_max_size
+
+ Changes the decimal value for the maximum allowable key size. Reducing
+ KEY_MAX_SIZE can restrict access to existing data and cause GT.M to report
+ errors. Do not create incompatible key and record sizes.
+
+ Before permanently changing the key size using DSE, use GDE to check that
+ the appropriate Global Directory contains the same key size for the
+ region. This prepares for future MUPIP CREATEs and performs a consistency
+ check on the key and record size values.
+
+ Use only with: -FILEHEADER; decimal
+
+ -KI[LL_IN_PROG]=value
+
+ Changes the value of the KILLs in progress field. The value can be "NONE"
+ or a positive integer.
+
+ Use only with: -FILEHEADER; decimal
+
+ -N[ULL_SUBSCRIPTS]=value
+
+ Controls whether GT.M accepts null subscripts in database keys.
+
+ o value can either be T[RUE], F[ALSE], ALWAYS, NEVER, or EXISTING. See
+ GDE book for more information on these values of null_subscript.
+ o Prohibiting null subscripts can restrict access to existing data and
+ cause GT.M to report errors.
+ o The default value is never.
+ o DSE cannot change the null subscript collation order. Instead, use GDE
+ to change the null subscript collation order, MUPIP EXTRACT the
+ current content, MUPIP CREATE the database file(s) with the updated
+ collation and MUPIP LOAD the content.
+
+ Use only with: -FILEHEADER
+
+ -OV[ERRIDE]
+
+ Releases or "steals" a FREEZE owned by another process.
+
+ Use only with: -FREEZE
+
+ -[NO]Q[DBRUNDOWN]
+
+ Sets a flag that indicates whether or not the database is enabled for
+ quick rundown. The default value is -NOQDBRUNDOWN.
+
+ -REC[ORD_MAX_SIZE]=record_max_size
+
+ Changes the decimal value for the maximum allowable record size. Use the
+ -RECORD_MAX_SIZE qualifier only in conjunction with the -FILEHEADER
+ qualifier. Reducing RECORD_MAX_SIZE can restrict access to existing data
+ and cause GT.M to report errors. Do not create incompatible key and record
+ sizes.
+
+ Before making a permanent change to the records size using DSE, use GDE to
+ check that the appropriate Global Directory contains the same record size
+ for the region. This prepares for future MUPIP CREATEs and performs a
+ consistency check on the key and record size values.
+
+ -REF[ERENCE_COUNT]=reference_count
+
+ Sets a field that tracks how many processes are accessing the database
+ with read/write permissions. MUPIP INTEG and DSE use decimal numbers for
+ -REFERENCE_COUNT. To accurately determine the proper reference count,
+ restrict CHANGE -FILEHEADER -REFERENCE_COUNT to the case where the process
+ running DSE has exclusive (standalone) access to the database file. When
+ DSE has sole access to a database file the -REFERENCE_COUNT should be one
+ (1). This is an informational field and does not have any effect on
+ processing.
+
+ -REG[_SEQNO]=sequence-number
+
+ In an LMS environment, this sets the "Region Seqno" field.
+
+ -RESYNC_S[EQNO]=sequence-number
+
+ In an LMS environment, this sets the "Resync Seqno" field.
+
+ -RESYNC_T[N]=sequence-number
+
+ In an LMS environment, this sets the "Resync transaction" field.
+
+ -STRM_NUM=stream-number -STRM_R[EG_SEQNO]=str_num's_region_sequence_number
+
+ Changes the Stream and its Reg Seqno. Use -STRM_NUM and -STRM_REG_SEQNO
+ together as part of the same CHANGE -FILEHEADER command.
+
+ Use only with: -FILEHEADER; hexa
+
+ -TI[MERS_PENDING]=timers_pending
+
+ -TI[MERS_PENDING]=timers_pending
+
+ Sets a field that tracks the number of processes considering a timed
+ flush. Proper values are 0, 1, and 2.
+
+ Use the CHANGE -TIMERS_PENDING qualifier only upon receiving instructions
+ from FIS.
+
+ Use only with: -FILEHEADER; decimal
+
+ -TO[TAL_BLKS]=total_blocks
+
+ Changes the total blocks field of the current file. Use only with:
+ -FILEHEADER; decimal
+
+ **Caution**
+
+ The total blocks field should always reflect the actual size of the
+ database. Change this field only if it no longer reflects the database
+ size.
+
+ -TR[IGGER_FLUSH]=trigger_flush
+
+ Sets the decimal value for the triggering threshold, in buffers, for
+ flushing the cache-modified queue.
+
+ Use the CHANGE -TRIGGER_FLUSH qualifier only upon receiving instructions
+ from FIS, and only in conjunction with the -FILEHEADER qualifier.
+
+ -WR[ITES_PER_FLUSH]=writes_per_flush
+
+ Set the decimal number of block to write in each flush. The default value
+ is 7.
+
+ Use only with -FILEHEADER
+
+3 Examples
+ Examples
+
+ Example:
+
+ DSE> change -block=3 -bsiz=400
+
+ This command changes the size of block 3 to 1024 bytes.
+
+ Example:
+
+ DSE> change -block=4 -tn=10000
+
+ This command changes sets the transaction number to 65536 (Hex: 10000) for
+ block 4.
+
+ Example:
+
+ DSE> change -block=2 -record=4 -CMPC=10 -key="^CUS(""Jones,Vic"")"
+
+ This command changes the compression count of the key ^CUS(Jones,Vic) to
+ 10. It is assumed that the key CUS(Jones,Tom) already exists. The
+ following table illustrates how GT.M calculates the value of CMPC in this
+ case.
+
+ +----------------------------------------------------------------+
+ | RECORD KEY | COMPRESSION COUNT | RESULTING KEY in Record |
+ |------------------+-------------------+-------------------------|
+ | CUS(Jones,Tom) | 0 | CUS(Jones,Tom) |
+ |------------------+-------------------+-------------------------|
+ | CUS(Jones,Vic) | 10 | Vic) |
+ |------------------+-------------------+-------------------------|
+ | CUS(Jones,Sally) | 10 | Sally) |
+ |------------------+-------------------+-------------------------|
+ | CUS(Smith,John) | 4 | Smith,John) |
+ +----------------------------------------------------------------+
+
+ Example:
+
+ DSE> dump -fileheader
+
+ This command displays fields of the file header.
+
+ Example:
+
+ DSE> change -fileheader -blk_siz=2048
+
+ This command changes the block size field of the fileheader to 2048 bytes.
+ The block field must always be a multiples of 512 bytes.
+
+ Example:
+
+ DSE> change -fileheader -blocks_free=5B
+
+ This command changes the blocks free fields of the file header to 91 (Hex:
+ 5B). Example:
+
+ Example:
+
+ DSE> change -fileheader -b_record=FF
+
+ This command sets the RECORD backup transaction to FF.
+
+ Example:
+
+ DSE> change -fileheader corrupt_file=FALSE
+
+ This command sets the CORRUPT_FILE field to false.
+
+ Example:
+
+ DSE> change -fileheader -current_tn=1001D1BF817
+
+ This command changes the current transaction number to 1100000000023 (Hex:
+ 1001D1BF817). After you execute this command, subsequent transaction
+ numbers will be greater than 1001D1BF817.
+
+ Example:
+
+ DSE> change -fileheader -flush_time=00:00:02:00
+
+ This command changes the flush time field of the file header to 2 seconds.
+
+ Example:
+
+ DSE> change -fileheader -freeze=true
+
+ This command makes the default region unavailable for updates.
+
+ Example:
+
+ DSE> change -fileheader -key_max_size=20
+
+ This command changes the maximum key size to 20. Note that the default max
+ key size is 64.
+
+ Example:
+
+ DSE> CHANGE -FILEHEADER -NULL_SUBSCRIPTS="EXISTING"
+
+ This command changes the Null Subscripts field of the file header to
+ EXISTING. Note that DSE cannot change the null subscript collation order.
+ See GDE book for more information on changing the null subscript
+ collation.
+
+ Example:
+
+ DSE> change -fileheader -reserved_bytes=8 -record_max_size=496
+
+ This command sets the maximum record size as 496 for the default region.
+
+ Example:
+
+ DSE> change -fileheader -reference_count=5
+
+ This command sets the reference count field of the file header to 5.
+
+ Example:
+
+ DSE> change -fileheader -timers_pending=2
+
+ This command sets the timers pending field of the file header to 2.
+
+ Example:
+
+ DSE> change -fileheader -TOTAL_BLKS=64
+
+ This command sets the total size of the database to 100 (Hex: 64) blocks.
+
+ Example:
+
+ DSE> change -fileheader -trigger_flush=1000
+
+ This command sets the Flush Trigger field of the file header to 1000. Note
+ the default value of Flush Trigger is 960.
+
+ Example:
+
+ DSE> change -fileheader -writes_per_flush=10
+
+ This command changes the number of writes/flush field of the file header
+ to 10. Note that the default value for the number of writes/flush is 7.
+
+ Example:
+
+ DSE> change -fileheader -zqgblmod_seqno=FF
+
+ This command changes the ZGBLMOD_SEQNO field to 255(Hex: FF).
+
+2 CAche
+ CAche
+
+ Operates on the cache of a database having BG access method. The format of
+ the CACHE command is:
+
+ CA[CHE] -ALL
+ -RE[COVER
+ -VE[RIFY]
+
+3 Qualifiers
+ Qualifiers
+
+ -RE[COVER] [-ALL]
+
+ Resets the cache of a database having BG access method to a "clean" state.
+
+ o With -ALL specified, DSE includes all region of the current global
+ directory for cache recovery.
+ o Attempt DSE -RECOVER only if a DSE CACHE -VERIFY commands reports the
+ cache is "NOT clean".
+
+ -VE[RIFY] [-ALL]
+
+ Verifies the integrity of the cache data structures as well as the
+ internal consistency of any GDS blocks in the global buffers of the
+ current region.
+
+ o With -ALL specified, DSE performs cache verification on all regions of
+ the current global directory.
+ o It reports the time, the region and a boolean result indicating
+ whether the cache is clean or NOT clean. If you see "NOT clean" in
+ report, execute DSE CACHE -RECOVER as soon as possible to reset the
+ cache in a clean state.
+
+3 Examples
+ Examples
+
+ Example:
+
+ DSE> CACHE -VERIFY
+
+ This command checks the integrity of the cache data structures as well as
+ the internal consistency of GDS blocks in the global buffers of the
+ current region.
+
+ Example:
+
+ DSE> CACHE -VERIFY -ALL
+ Time 26-FEB-2011 14:31:30 : Region DEFAULT : Cache verification is clean
+
+ Execute CACHE recover command if Cache verification is "NOT" clean.
+
+ This command reports the state of database cache for all regions.
+
+ Example:
+
+ DSE> CACHE -RECOVER
+
+ This command reinitializes the cache data structures of the current region
+ and reverts the cache of a database having BG access to "clean" state.
+
+2 CLose
+ CLose
+
+ The CLOSE command closes the currently open output file.
+
+ The format of the CLOSE command is:
+
+ CL[OSE]
+
+ The CLOSE command has no qualifiers.
+
+2 CRitical
+ CRitical
+
+ Displays and/or modifies the status and contents of the critical section
+ for the current region. The format of the CRITICAL command is:
+
+ CR[ITICAL] -I[NIT]
+ -O[WNER]
+ -REL[EASE]
+ -REM[OVE]
+ -RES[ET]
+ -S[EIZE]
+
+ o The critical section field identifies, by its process identification
+ number (PID), the process presently managing updates to database.
+ o Think of a critical section as a common segment of a train track. Just
+ as a train moves through the common segment as quickly as possible,
+ the same way a process moves as quickly as possible through any
+ critical section so that other processes can use it.
+ o By default, the CRITICAL command assumes the -OWNER qualifier, which
+ displays the status of the critical section.
+
+3 Qualifiers
+ Qualifiers
+
+ -I[NIT]
+
+ Reinitializes the critical section.
+
+ o The -INIT and -RESET qualifiers together cause all GT.M processes
+ actively accessing that database file to signal an error.
+ o FIS recommends against using -INIT without the -RESET parameter when
+ other processes are actively accessing the region because it risks
+ damaging the database.
+
+ Use only with: -RESET
+
+ -O[WNER]
+
+ Displays the ID of the process at the head of the critical section. DSE
+ displays a warning message when the current process owns the critical
+ section.
+
+ Use alone
+
+ Example:
+
+ DSE> critical -OWNER
+ Write critical section is currently unowned
+
+ -REL[EASE]
+
+ Releases the critical section if the process running DSE owns the section.
+
+ Use alone.
+
+ -REM[OVE]
+
+ Terminates any write ownership of the critical section. Use this when the
+ critical section is owned by a process that is nonexistent or is known to
+ no longer be running a GT.M image.
+
+ Use alone.
+
+ **Caution**
+
+ Using CRITICAL -REMOVE when the write owner of a critical section is an
+ active GT.M process may cause structural database damage.
+
+ -RES[ET]
+
+ Displays the number of times the critical section has been through an
+ online reinitialization.
+
+ Using -RESET with -INIT causes an error for processes that are attempting
+ to get the critical section of the region. Under the guidance of FIS, use
+ -RESET -INIT as a way to clear certain types of hangs.
+
+ Use only with: -INIT
+
+ -S[EIZE]
+
+ Seizes the critical section (if available).
+
+ o You can also use SEIZE to temporarily suspend database updates.
+ o Subsequently, execute CRITICAL -RELEASE command to restore normal
+ operation.
+
+3 Examples
+ Examples
+
+ Example:
+
+ DSE> critical -OWNER Write critical section owner is process id 4220
+
+ This command displays the ID of the process holding the critical section.
+ Note that on catching a process ID on a lightly loaded (or unloaded)
+ system (for example, text environment) is like catching lightening in a
+ bottle. Therefore, you can artificially hold a critical section using the
+ DSE CRIT -SEIZE command in one session and view the owner using a
+ different session.
+
+2 Dump
+ Dump
+
+ Displays blocks, records, or file headers. DUMP is one of the primary DSE
+ examination commands.
+
+ The format of the DUMP command is:
+
+ D[UMP] -A[LL]
+ -B[LOCK]=block_number
+ -C[OUNT]=count
+ -F[ILEHEADER]
+ -G[LO]
+ -G[VSTATS]
+ -[NO]C[RIT]
+ -[NO]H[EADER]
+ -O[FFSET]=offset
+ -R[ECORD]=record-number
+ -U[PDPROC]
+ -Z[WR]
+
+ Use the error messages reported by MUPIP INTEG to determine what to DUMP
+ and examine in the database. DUMP also can transfer records to a
+ sequential file for future study and/or for input to MUPIP LOAD (see the
+ section on OPEN). The DUMP command requires specification of an object
+ using either -BLOCK, -HEADER, -RECORD, or -FILEHEADER.
+
+3 Qualifiers
+ Qualifiers
+
+ -A[LL]
+
+ When used with -FILEHEADER, the -A[LL] qualifier displays additional
+ information on the database most of which is useful for FIS in diagnosing
+ issues. A complete description of all the elements that show up with the
+ DSE DUMP -FILEHEADER -ALL command are beyond the scope of this book. Use
+ only with -FILEHEADER or -UPDPROC (which is actually redundant as -ALL
+ displays the UPDPROC information).
+
+ -B[LOCK]=block-number
+
+ Specifies the starting block of the dump. For commands without an object
+ qualifier, DSE uses the last block handled by a DSE operation. When no
+ block has been accessed, (thatis, on the first block-oriented command),
+ DSE uses block one (1).
+
+ Incompatible with: -ALL, -FILEHEADER and -UPDPROC.
+
+ -C[OUNT]=count
+
+ Specifies the number of blocks, block headers, or records to DUMP.
+
+ Incompatible with: -ALL, -FILEHEADER and -UPDPROC.
+
+ -F[ILEHEADER]
+
+ Dumps file header information. A DSE dump of a database file header prints
+ a 0x prefix for all fields printed in hexadecimal format. Refer to the
+ "Introduction" section for a description of the file header fields.
+
+ Use only with -ALL or -UPDPROC
+
+ -G[LO]
+
+ Dumps the specified record or blocks into the current output file in
+ Global Output (GO) format. FIS strongly suggests using -ZWR rather than
+ -GLO as the ZWR format handles all possible content values, including some
+ that are problematic with -GLO.
+
+ Incompatible with: -ALL, -FILEHEADER, -UPDPROC and -ZWR.
+
+ -G[VSTATS]
+
+ Displays the access statistics for global variables and database file(s).
+
+ -NO[CRIT]
+
+ Allows DSE DUMP to work even if another process is holding a critical
+ section. Since results in this mode may be inconsistent, it should only be
+ used if the critical section mechanism is not operating normally.
+
+ -[NO]H[EADER]
-1 DSE_Functions
- Functions of DSE
- DSE is primarily a database repair utility.
+ Specifies whether the dump of the specified blocks or records is
+ restricted to, or excludes, headers. -HEADER displays only the header,
+ -NOHEADER displays the block or record with the header suppressed. DUMP
+ without the -[NO]HEADER qualifier dumps both the block/record and the
+ header.
- Use DSE to:
+ By default, DUMP displays all information in a block or record.
- o Dump parts of the database for troubleshooting database errors
+ Incompatible with: -ALL, -FILEHEADER, -GLO, -UPDPROC and -ZWR.
- o Add or delete a record in a block
+ -O[FFSET]=offset
- o Update file, block or record header information
+ Specifies the offset, in bytes, of the starting record for the dump. If
+ the offset does not point to the beginning of a record, DSE rounds down to
+ the last valid record start (e.g., DUMP -OFF=10 starts at -OFF=A if that
+ was the beginning of the record containing offset 10).
- o Update bit maps
+ Incompatible with: -ALL, -FILEHEADER, and -RECORD.
- o Save copies of database fragments for analysis, audit or
- restoration.
+ -R[ECORD]=record_number
- Use the DSE EXIT command to leave DSE.
+ Specifies the record number of the starting record of the dump. If you try
+ to dump a record number that is larger than the last actual record in the
+ block, a DSE error message provides the number of the last record in the
+ block.
-1 Command_Syntax
- Command Syntax
- The format for DSE commands is:
+ Incompatible with: -ALL, -FILEHEADER, and -OFFSET.
- Command qualifier
+ -U[PDPROC]
- DSE interprets all numeric input as hexadecimal, except for time
- values, the -BLK_SIZE=, -KEY_MAX_SIZE=, -RECORD_MAX_SIZE=,
- -REFERENCE_COUNT=, -TIMERS_PENDING= and -WRITES_PER_FLUSH= on CHANGE
- -FILEHEADER, and -VERSION= on the REMOVE and RESTORE commands. This
- convention corresponds to the displays provided by DSE and by MUPIP
- INTEG.
+ Displays the helper process parameters with the fileheader elements.
-1 ADD
- AD[D]
- The ADD command adds a record to a block.
+ Use only with -FILEHEADER.
- The format of the ADD command is:
+ -Z[WR]
- AD[D] [-B[LOCK]=block]
+ Dumps the specified record or blocks into the current output file in
+ ZWRITE (ZWR) format.
- For greater than level 0 blocks add:
+ Incompatible with: -ALL, -GLO, -HEADER and -FILEHEADER.
- -STAR -POINTER=block
+3 Examples
+ Examples
- or
+ Example:
- -OFFSET=offset|-RECORD=record -KEY=key -POINTER=block
+ DSE> DUMP -FILEHEADER
+
+ This command displays an output like the following:
+
+ File /home/gtmuser1/mumps.dat
+ Region DEFAULT
+
+ Date/Time 27-OCT-2009 04:25:12 [$H = 61661,15912]
+ Access method BG Global Buffers 1024
+ Reserved Bytes 0 Block size (in bytes) 1024
+ Maximum record size 256 Starting VBN 129
+ Maximum key size 64 Total blocks 0x00000191
+ Null subscripts NEVER Free blocks 0x0000002A
+ Standard Null Collation FALSE Free space 0x00000000
+ Last Record Backup 0x0000000000000001 Extension Count 100
+ Last Database Backup 0x0000000000000001 Number of local maps 1
+ Last Bytestream Backup 0x0000000000000001 Lock space 0x00000028
+ In critical section 0x00000000 Timers pending 0
+ Cache freeze id 0x00000000 Flush timer 00:00:01:00
+ Freeze match 0x00000000 Flush trigger 960
+ Current transaction 0x0000000000007539 No. of writes/flush 7
+ Maximum TN 0xFFFFFFFFE3FFFFFF Certified for Upgrade to V5
+ Maximum TN Warn 0xFFFFFFFF73FFFFFF Desired DB Format V5
+ Master Bitmap Size 112 Blocks to Upgrade 0x00000000
+ Create in progress FALSE Modified cache blocks 0
+ Reference count 1 Wait Disk 0
+ Journal State [inactive] ON Journal Before imaging TRUE
+ Journal Allocation 100 Journal Extension 100
+ Journal Buffer Size 128 Journal Alignsize 128
+ Journal AutoSwitchLimit 8388600 Journal Epoch Interval 30
+ Journal Yield Limit 8 Journal Sync IO TRUE
+ Journal File: /home/gtmuser1/mumps.mjl
+ Mutex Hard Spin Count 128 Mutex Sleep Spin Count 128
+ Mutex Spin Sleep Time 2048 KILLs in progress 0
+ Replication State OFF Region Seqno 0x0000000000000001
+ Zqgblmod Seqno 0x0000000000000000 Zqgblmod Trans 0x0000000000000000
+ Endian Format LITTLE Commit Wait Spin Count 17
+ Database file encrypted FALSE
+
+ Note that the certain fileheader elements appear depending on the current
+ state of database. For example, as Journaling is not enabled in the
+ database, DSE does not display Journal data element fields.
- For level 0 blocks add:
+ Example:
- -OFFSET=offset|-RECORD=record -KEY=key -D[ATA]=string
+ $ dse dump -fileheader -updproc
- The ADD command requires either the -OFFSET or -RECORD qualifier to
- position the record in the block and either the -KEY or the -STAR
- qualifier to define the key for the block.
+ This command displays the fileheader elements along with the following
+ helper process parameters:
- The -STAR qualifier is not valid at level 0 (i.e., for a data block).
- The ADD command requires the -DATA qualifier at level 0 or the
- -POINTER qualifier at any other level to provide the content of the
- record.
+ Upd reserved area [% global buffers] 50 Avg blks read per 100 records 200
+ Pre read trigger factor [% upd rsrvd] 50 Upd writer trigger [%flshTrgr] 33
-2 Qualifiers
--BLOCK
- -B[LOCK]=block_number
- Specifies the block to receive the new record.
+2 EValuate
+ EValuate
- On commands with no -BLOCK= qualifier, DSE uses the last block
- handled by a DSE operation. In this case, when no block has been
- accessed, .i.e., on the first block oriented command, DSE uses
- block one (1).
-
--DATA
- -D[ATA]=string
- Specifies the data field for records added to a data block. Use
- quotes around string and escape codes of the form \a or \ab,
- where a and b are hexadecimal digits representing non-printing
- characters. \\ translates to a single backslash. The -DATA
- qualifier only applies at level 0 and is incompatible with the
- -STAR and -POINTER qualifiers.
-
--KEY
- -K[EY]=key
- Specifies the key of the new record. Enclose MUMPS-style global
- references in quotes (""). The -KEY qualifier is incompatible
- with the -STAR qualifier.
-
--OFFSET
- -O[FFSET]=offset
- Adds the new record at the next record boundary after the
- specified offset. The -OFFSET qualifier is incompatible with the
- -RECORD and -STAR qualifiers.
-
--POINTER
- -P[OINTER]=pointer
- Specifies the block pointer field for records added to an index
- block. The -POINTER qualifier is incompatible with the -DATA
- qualifier and cannot be used at level 0.
-
--RECORD
- -R[ECORD]=record_number
- Specifies a record number of the new record. The -RECORD
- qualifier is incompatible with the -OFFSET and -STAR qualifiers.
-
--STAR
- -S[TAR]
- Adds a star record (i.e., a record that identifies the last
- record in an indexed block) at the end of the specified block.
- The -STAR qualifier is incompatible with all qualifiers except
- -BLOCK and -POINTER and cannot be used at level 0.
-
-1 ALL
- AL[L]
- The ALL command applies action(s) specified by a qualifier to all GDS
- regions defined by the current Global Directory. This is a very
- powerful command; use caution. Be especially careful if you have an
- overlapping database structure (e.g., overlapping regions accessed
- from separate application global directories).
-
-2 Qualifiers
--BUFFER_FLUSH
- -B[UFFER_FLUSH]
- Flushes to disk buffers all regions specified by the current
- Global Directory. The -BUFFER_FLUSH qualifier is incompatible
- with the -RENEW qualifier.
-
--CRITINIT
- -C[RITINIT]
- Initializes critical sections for all regions specified by the
- current Global Directory. The -CRITINIT qualifier is
- incompatible with the -RENEW, -RELEASE and -SEIZE qualifiers.
-
--FREEZE
- -[NO]F[REEZE]
- Allows a user to freeze, or prevent updates to, GDS regions
- specified by the current Global Directory. The -FREEZE qualifier
- freezes all such GDS regions except those previously frozen by
- another user. Regions frozen by a particular user are associated
- with that user. A frozen region may be updated in one of two
- ways: The user who froze the region may unfreeze it with the
- -NOFREEZE qualifier; or another user may override the freeze
- injunction with the -OVERRIDE qualifier.
-
- The -NOFREEZE qualifier unfreezes only those GDS regions that
- were previously frozen by the operator. Once a region is
- unfrozen, it may be updated by any user. To unfreeze all GDS
- regions, use the -OVERRIDE qualifier.
-
- The -FREEZE qualifier is incompatible with the -RENEW qualifier.
-
- DSE releases -FREEZE when it EXITs. To hold all databases, enter
- ALL -FREEZE and then SPAWN to perform other operations.
-
--OVERRIDE
- -O[VERRIDE]
- The -OVERRIDE qualifier is meaningful only with the -FREEZE or
- -NOFREEZE it unfreezes all GDS regions, including those frozen
- by other users. When used with -FREEZE, the -OVERRIDE qualifier
- freezes all GDS regions, including those frozen by other users,
- associating all such freezes with the current user. The current
- user must then use the -NOFREEZE qualifier to unfreeze the
- database; any other user attempting a -UNFREEZE would also have
- to include the -OVERRIDE qualifier.
-
--REFERENCE
- -REF[ERENCE]
- Resets reference counts to 1 for all regions specified by the
- current Global Directory. The -REFERENCE qualifier is
- incompatible with the -RENEW qualifier.
-
--RELEASE
- -REL[EASE]
- Releases critical sections for all regions specified by the
- current Global Directory. The -RELEASE qualifier is incompatible
- with the -CRITINIT, -RENEW and -SEIZE qualifiers.
-
--RENEW
- -REN[EW]
- Reinitializes critical sections (-CRITICAL) and buffers
- (-WCINIT), resets reference counts to 1 (-REFERENCE_COUNT) and
- clears freeze flags for all regions specified by the current
- Global Directory (-NOFREEZE). -RENEW requires confirmation. The
- -RENEW qualifier is incompatible with all other qualifiers.
-
--SEIZE
- -S[EIZE]
- Seizes the critical section for all regions specified by the
- current Global Directory. The -SEIZE qualifier is incompatible
- with the -CRITINIT, -RELEASE and -RENEW qualifiers.
-
- The SEIZE qualifier can be useful when you encounter a
- DSEBLKRDFAIL error, generated when DSE is unable to read a block
- from the database.
-
--WCINIT
- -W[CINIT]
- Reinitializes buffers for all regions specified by the current
- Global Directory. -WCINIT requires confirmation. The -WCINIT
- qualifier is incompatible with the -RENEW qualifier.
-
-1 BUFFER_FLUSH
- B[UFFER_FLUSH]
- The BUFFER_FLUSH command flushes the current region's buffers to disk.
+ Translates a hexadecimal number to decimal, and vice versa.
+ The format of the EVALUATE command is:
- The format of the BUFFER_FLUSH command is:
+ EV[ALUATE] -D[ECIMAL]
+ -H[EXADECIMAL]
+ -N[UMBER]=number
- B[UFFER_FLUSH]
+ The -DECIMAL and -HEXADECIMAL qualifiers specify the input base for the
+ number. The -NUMBER qualifier is mandatory. By default, EVALUATE treats
+ the number as having a hexadecimal base.
- The BUFFER_FLUSH command has no qualifiers.
+3 Qualifiers
+ Qualifiers
-1 CHANGE
- CH[ANGE]
- The CHANGE command changes fields of a file, block, or record header
- and the bit map.
-
- The CHANGE command either has a -FILEHEADER qualifier or an implicit
- or explicit -BLOCK qualifier plus one or more of their associated
- qualifiers to define the target of the change.
-
-2 Block_Qualifiers
-
--BLOCK
- -BL[OCK]=block_number
- Specifies the block to modify. The -BLOCK qualifier is
- incompatible with the -FILEHEADER qualifier and all qualifiers
- related to -FILEHEADER.
-
- -BLOCK is the default qualifier. On commands with neither a
- -BLOCK nor a -FILEHEADER qualifier, DSE uses the last block
- handled by a DSE operation. In this case, when no block has been
- accessed, that is, on the first block-oriented command, DSE uses
- block one (1).
-
--BSIZ
- -BS[IZ]=block_size
- Changes the block size field of the specified block. Decreasing
- the block size can result in loss of existing data. The -BSIZ
- qualifier is incompatible with all qualifiers except -BLOCK,
- -LEVEL and -TN.
-
--LEVEL
- -L[EVEL]=level
- Changes the level field for the specified block. The -LEVEL
- qualifier is incompatible with all qualifiers except -BLOCK,
- -BSIZ and -TN.
-
--TN
- -TN[=transaction_number]
- Changes the transaction number for the current block. When a
- CHANGE command does not include a -TN=, DSE sets the transaction
- number to the current transaction number. Manipulation of the
- block transaction number affects MUPIP BACKUP -INCREMENTAL. The
- -TN qualifier is incompatible with all qualifiers except -BLOCK,
- -BSIZ and -LEVEL.
-
--OFFSET
- -OF[FSET]=offset
- Specifies the offset within the block of the target record. The
- -OFFSET qualifier is incompatible with all qualifiers except
- -BLOCK, -CMPC and -RSIZ.
-
--RECORD
- -RE[CORD]=record_number
- Specifies the record number of the target record. The -RECORD
- qualifier is incompatible with all qualifiers except -BLOCK,
- -CMPC and -RSIZ.
-
--CMPC
- -CM[PC]=compression_count
- Changes the compression count field of the specified record. The
- -CMPC qualifier is incompatible with all qualifiers except
- -BLOCK, -OFFSET, and -RECORD.
-
--RSIZ
- -RS[IZ]=record_size
- Changes the record size field of the specified record. The -RSIZ
- qualifier is incompatible with all qualifiers except -OFFSET and
- -RECORD.
-
-2 File_header_qualifiers
-
--FILEHEADER
- -FI[LEHEADER]
- Enables modification of specific fields in the file header. The
- -FILEHEADER qualifier is incompatible with the -BLOCK and all
- qualifiers related to -BLOCK (i.e., -BSIZ, -CMPC, -LEVEL,
- -OFFSET, -RECORD, -RSIZ and -TN qualifiers).
-
--BLK_SIZE
- -BLK[_SIZE]=block_size
- Changes the decimal block size field of the current file. Use
- the -BLK_SIZE qualifier only in conjunction with the -FILEHEADER
- qualifier. Do not use this CHANGE qualifier except on
- instructions from Greystone.
-
--BLOCKS_FREE
- -BLO[CKS_FREE]=free blocks
- Changes the free blocks field of the current file. Use the
- -BLOCK_FREE qualifier only in conjunction with the -FILEHEADER
- qualifier. Database operations maintain this field for the
- user's convenience. The field does not control any database
- operations.
-
--B_COMPREHENSIVE
- -B_C[OMPREHENSIVE]=transaction_number
- Changes the transaction number in the fileheader of the last
- comprehensive backup to the value specified. Use this qualifier
- only in conjunction with the -FILEHEADER qualifier.
-
--B_INCREMENTAL
- -B_I[NCREMENTAL]=transaction_number
- Changes the transaction number in the fileheader of the last
- incremental backup to the value specified. Use this qualifier
- only in conjunction with the -FILEHEADER qualifier.
-
--B_RECORD
- -B_R[ECORD]=transaction_number
- Changes the transaction number in the fileheader of the last
- -RECORD backup to the value specified. Use this qualifier only
- in conjunction with the -FILEHEADER qualifier.
-
--CORRUPT_FILE
- -CO[RRUPT_FILE]=value
- Sets the file_corrupt field in the file header. Possible values
- are: TRUE, FALSE and NOCHANGE. Use the -CORRUPT_FILE qualifier
- only in conjunction with the -FILEHEADER qualifier.
-
- WARNING: when DSE EXITs after a CHANGE -FILEHEADER -CORRUPT=TRUE
- without a matching CHANGE -FILEHEADER -CORRUPT=FALSE, the file
- becomes unavailable to all future access.
-
--CURRENT_TN
- -CU[RRENT_TN]=transaction_number
- Changes the current transaction number for the current region.
- Use the -CURRENT_TN qualifier only in conjunction with the
- -FILEHEADER qualifier. This qualifier has implications only for
- MUPIP BACKUP -INCREMENTAL. Raising the -CURRENT_TN corrects
- block transaction number too large errors.
-
--FLUSH_TIME
- -FL[USH_TIME][=delta_time]
- Changes the flush_time default interval (in delta_time). The
- time entered must be between 0 and 1 hour.
-
- Use the -FLUSH_TIME qualifier only in conjunction with the
- -FILEHEADER qualifier. Do not use this CHANGE qualifier except
- on instructions from Greystone. A -FLUSH_TIME with no value
- resets the -FLUSH_TIME to the default value. Input is
- interpreted as decimal.
-
--FREEZE
- -FR[EEZE]=value
- Sets availability of the region for update. Possible values are:
- TRUE, FALSE and NOCHANGE. Use to "freeze" (disable database
- writes) or "unfreeze" the database. Use the -FREEZE qualifier
- only in conjunction with the -FILEHEADER qualifier.
-
- DSE releases -FREEZE when it EXITs. To hold the database(s),
- CHANGE -FILEHEADER -FREEZE=TRUE and then SPAWN to perform other
- operations.
-
--KEY_MAX_SIZE
- -K[EY_MAX_SIZE]=key_max_size
- Changes the decimal value for the maximum allowable key size.
- Use the -KEY_MAX_SIZE qualifier only in conjunction with the
- -FILEHEADER qualifier. Reducing KEY_MAX_SIZE can restrict access
- to existing data and cause GT.M-generated errors. Do not create
- incompatible key and record sizes. If you make a permanent
- change to the key size using DSE, use GDE to check that the
- appropriate Global Directory contains the same key size for the
- region. For more information on key and record sizes, refer to
- the "Global Directory Editor" chapter in the GT.M Administration
- and Operations Guide.
-
--NULL_SUBSCRIPTS
- -N[ULL_SUBSCRIPTS]=value
- Sets the acceptability of null subscripts in database keys.
- Possible values are: TRUE, FALSE and NOCHANGE. Use the
- -NULL_SUBSCRIPTS qualifier only in conjunction with the
- -FILEHEADER qualifier. Prohibiting null-subscripts can restrict
- access to existing data and cause GT.M generated errors.
-
--RECORD_MAX_SIZE
- -REC[ORD_MAX_SIZE]=record_max_size
- Changes the decimal value for the maximum allowable record size.
- Use the -RECORD_MAX_SIZE qualifier only in conjunction with the
- -FILEHEADER qualifier. Reducing the RECORD_MAX_SIZE can restrict
- access to existing data and cause GT.M-generated errors. Do not
- create incompatible key and record sizes. If you make a
- permanent change to the record size using DSE, make sure GDE
- contains the same record size for the appropriate Global
- Directory. For more information on key and record sizes, refer
- to "Global Directory Editor" chapter in GT.M Administration and
- Operations Guide.
-
--REFERENCE_COUNT
- -REF[ERENCE_COUNT]=reference_count
- Sets a field that tracks how many processes are accessing the
- database from the current node. MUPIP INTEG and DSE use decimal
- numbers for -REFERENCE_COUNT. Use the -REFERENCE_COUNT qualifier
- only in conjunction with the -FILEHEADER qualifier. Restrict
- CHANGE -FILEHEADER -REFERENCE_COUNT to the case where the
- process running DSE has exclusive (stand-alone) access to the
- database file. When DSE has sole access to a database file the
- -REFERENCE_COUNT should be 1. This is an informational field and
- does not have any effect on processing.
-
--TIMERS_PENDING
- -TI[MERS_PENDING]=timers_pending
- Sets field that tracks the number of processes considering a
- timed flush. Use the -TIMERS_PENDING qualifier only in
- conjunction with the -FILEHEADER qualifier. Proper values are 0,
- 1, and 2. Do not use this CHANGE qualifier except on
- instructions from Greystone.
-
--TOTAL_BLKS
- -TO[TAL_BLKS]=total_blocks
- Changes the total blocks field of the current file. Use the
- -TOTAL_BLKS qualifier only in conjunction with the -FILEHEADER
- qualifier.
+ -D[ECIMAL]
- WARNING: The total blocks field should always reflect the actual
- size of the database. Change this field only if it no longer
- reflects the size of the database.
-
--TRIGGER_FLUSH
- -TR[IGGER_FLUSH]=trigger_flush
- Sets the decimal value for the triggering threshold, in buffers,
- for flushing the cache modified queue. Use the -TRIGGER_FLUSH
- qualifier only in conjunction with the -FILEHEADER qualifier. Do
- not use this CHANGE qualifier except on instructions from
- Greystone.
-
--WRITES_PER_FLUSH
- -WR[ITES_PER_FLUSH]=writes_per_flush
- Sets the decimal number of blocks to write in each flush. Use
- the -WRITES_PER_FLUSH qualifier only in conjunction with the
- -FILEHEADER qualifier. Do not use this CHANGE qualifier except
- on instructions from Greystone.
-
-1 CLOSE
- CL[OSE]
- The CLOSE command closes the currently open output file. Use to close
- the opened dump file.
+ Specifies that the input number has a decimal base.
- The format of the CLOSE command is:
+ Incompatible with: -HEXADECIMAL .
- CL[OSE]
+ -H[EXADECIMAL]
- The CLOSE command has no qualifiers.
+ Specifies that the input number has a hexadecimal base.
-1 CRITICAL
- CR[ITICAL]
- The CRITICAL command along with its qualifiers displays and/or
- modifies the status and contents of the critical section for the
- current region. The critical section provides a control mechanism.
- This field identifies, by its PID, the process presently managing
- updates to database.
+ Incompatible with: -DECIMAL
- The format of the CRITICAL command is:
+ -N[UMBER]=number
- CR[ITICAL] -I[NIT]
- -O[WNER]
- -REL[EASE]
- -REM[OVE]
- -S[EIZE]
+ Specifies the number to evaluate. Required.
- By default, the CRITICAL command assumes the -OWNER qualifier, which
- displays the status of the critical section.
+3 Examples
+ Examples
-2 Qualifiers
--INIT
- -I[NIT]
- Reinitializes the critical section. The -RESET qualifier causes
- all processes actively accessing that database file to signal an
- error. Do not use -INIT without the -RESET parameter when other
- processes are accessing the region.
+ Example:
+
+ DSE> evaluate -number=10 -decimal
- CAUTION: Using CRITICAL -INIT when the write owner of a critical
- section is an active GT.M process may cause structural database
- damage.
+ Hex: A Dec: 10
--OWNER
- -O[WNER]
- Displays the ID of the process at the head of the critical
- section, the ID of the process running DSE and the count of
- critical read owners. When the current process owns the critical
- section, DSE displays a warning message. The -OWNER qualifier is
- incompatible with other qualifiers.
+ This command displays the hexadecimal equivalent of decimal number 10.
Example:
- DSE> critical-owner
+ DSE> evaluate -number=10 -hexadecimal
- Write critical section is currently unowned
+ Hex: 10 Dec: 16
--RELEASE
- -REL[EASE]
- Releases the critical section if the process running DSE owns
- the section. The -RELEASE qualifier is incompatible with other
- qualifiers.
-
--REMOVE
- -REM[OVE]
- Terminates any write ownership of the critical section. Use this
- when the critical section is owned by a process that is
- nonexistent or is known to no longer be running a GT.M image.
- The -REMOVE qualifier is incompatible with other qualifiers.
-
- CAUTION: Using CRITICAL-REMOVE when the write owner of a
- critical section is an active GT.M process may cause structural
- database damage.
-
--SEIZE
- -S[EIZE]
- Seizes the critical section if the section is available. The
- -SEIZE qualifier is incompatible with other qualifiers.
-
-1 DUMP
- D[UMP]
- The DUMP command displays blocks, records or file headers. DUMP serves
- as one of the primary DSE examination commands. Use the error messages
- reported by MUPIP INTEG to determine what to DUMP and examine from the
- database. DUMP also transfers records to a sequential file for future
- study and/or for input to MUPIP LOAD.
-
- The DUMP command requires specification of either -BLOCK, -HEADER,
- -RECORD or -FILEHEADER.
-
-2 Qualifiers
--BLOCK
- -B[LOCK]=block_number
- Specifies the starting block of the dump. The -BLOCK qualifier
- is incompatible with the -FILEHEADER qualifier.
-
- On commands with no -BLOCK= qualifier, DSE uses the last block
- handled by a DSE operation. In this case, when no block has been
- accessed, .i.e., on the first block oriented command, DSE uses
- block one (1).
-
- Example:
-
- DSE> dump -block=2
-
- Block 2 Size 1B Level 0 TN 2
- Rec:1 Blk 2 Off 7 Size A Cmpc 0 Ptr 8 Key ^a
- 7 : | A 0 0 61 0 0 8 0 0 0
- | . . . a . . . . . .
-
- Rec:2 Blk 2 Off 11 Size A Cmpc 0 Ptr B Key ^b
- 11 : | A 0 0 62 0 0 B 0 0 0
- | . . . b . . . . . .
-
-
--COUNT
- -C[OUNT]=count
- Specifies the number of block headers or records to DUMP. The
- -COUNT qualifier is incompatible with the -FILEHEADER qualifier.
-
--FILEHEADER
- -F[ILEHEADER]
- Dumps file header information. The -FILEHEADER qualifier is
- incompatible with all other qualifiers.
-
--GLO
- -G[LO]
- Dumps the specified record or blocks into the current output
- file in Global Output (GO) format. The -GLO qualifier is
- incompatible with the -HEADER and -FILEHEADER qualifiers.
-
--HEADER
- -[NO]H[EADER]
- Specifies whether the dump of the specified blocks or records is
- restricted to, or excludes, headers. The -HEADER qualifier is
- incompatible with the -GLO and -FILEHEADER qualifiers.
+ This command displays the decimal equivalent of hexadecimal 10.
- By default, DUMP displays all information in a block or record.
+ Example:
--OFFSET
- -O[FFSET]=offset
- Specifies the offset of the starting record for the dump. If the
- offset does not point to the beginning of a record, DSE rounds
- down to the last valid record start (e.g., DUMP -OFF=10 starts
- at -OFF=A if that was the last record). The -OFFSET qualifier is
- incompatible with the -RECORD and -FILEHEADER qualifiers.
-
--RECORD
- -R[ECORD]=record_number
- Specifies the record number of the starting record of the dump.
- The -RECORD qualifier is incompatible with the -OFFSET and
- -FILEHEADER qualifiers.
-
-1 EVALUATE
- EV[ALUATE]
- The EVALUATE command displays a number in both hexadecimal and
- decimal. Use it to translate a hexadecimal number to decimal and vice
- versa. The -DECIMAL and -HEXADECIMAL qualifiers specify the input base
- for the number.
+ $ dse evaluate -number=10
- The format of the EVALUATE command is:
+ Hex: 10 Dec: 16
+
+ This command displays the decimal equivalent of Hexadecimal 10. Note that
+ if you do not specify an qualifier with -NAME, then EVALUATE assumes
+ Hexadecimal input.
+
+2 EXit
+ EXit
- EV[ALUATE] -D[ECIMAL]
- -H[EXADECIMAL]
- -N[UMBER]=number
+ The EXIT command ends a DSE session.
+
+ The format of the EXIT command is:
+
+ EX[IT]
+
+ The EXIT command has no qualifiers.
- The -NUMBER qualifier is required.
+2 Find
+ Find
- By default, EVALUATE treats the number as having a hexadecimal base.
+ Locates a given block or region. The format of the FIND command is:
-2 Qualifiers
--DECIMAL
- -D[ECIMAL]
- Specifies that the input number has a decimal base. The -DECIMAL
- qualifier is incompatible with the -HEXADECIMAL qualifier
+ F[IND] -B[LOCK]=block-number
+ -E[XHAUSTIVE]
+ -F[REEBLOCK] /H[INT]
+ -K[EY]=key
+ -[NO]C[RIT]
+ -R[EGION][=region]
+ -S[IBLINGS]
--HEXADECIMAL
- -H[EXADECIMAL]
- Specifies that the input number has a hexadecimal base. The
- -HEXADECIMAL qualifier is incompatible with the -DECIMAL
- qualifier.
+ o At the beginning of a DSE session, use the FIND -REGION command to
+ select the target region.
+ o The FIND command, except when used with the -FREEBLOCK and -REGION
+ qualifiers, uses the index tree to locate blocks. FIND can locate
+ blocks only within the index tree structure. If you need to locate
+ keys independent of their attachment to the tree, use the RANGE
+ command.
+
+3 Qualifiers
+ Qualifiers
+
+ -B[LOCK]=block_number
+
+ Specifies the block to find.
+
+ On commands without the -BLOCK= qualifier, DSE uses the last block handled
+ by a DSE operation. When no block has been accessed, that is, on the first
+ block-oriented command, DSE uses block one (1).
+
+ Incompatible with: -KEY, -REGION
+
+ -E[XHAUSTIVE]
+
+ Searches the entire index structure for the desired path or siblings.
+
+ o FIND -EXHAUSTIVE locates blocks that are in the tree but not indexed
+ correctly.
+ o FIND -EXHAUSTIVE locates all paths to a "doubly allocated" block.
+
+ **Note**
+
+ A doubly allocated block may cause inappropriate mingling of data. As long
+ as no KILLs occur, double allocation may not cause permanent loss of
+ additional data. However, it may cause the application programs to
+ generate errors and/or inappropriate results. When a block is doubly
+ allocated, a KILL may remove data outside its proper scope. See
+ "Maintaining Database Integrity Chapter" for more information on repairing
+ doubly allocated blocks.
+
+ Incompatible with: -KEY, -REGION, -FREEBLOCK
+
+ -F[REEBLOCK]
+
+ Finds the nearest free block to the block specified by -HINT.
+
+ o The -FREEBLOCK qualifier is incompatible with all other qualifiers
+ except -BLOCK and -HINT.
+ o The -HINT qualifier is required with the -FREEBLOCK qualifier.
+ o FIND -FREEBLOCK relies on the bitmaps to locate its target, so be sure
+ to fix any blocks incorrectly marked "FREE" before using this command.
+ See MAP -BUSY for more information on fixing incorrectly marked free
+ errors.
+
+ Required with -HINT; compatible with -BLOCK and [NO]CRIT.
+
+ -H[INT]=block_number
+
+ Designates the starting point of a -FREEBLOCK search.
+
+ FIND -FREE -HINT locates the "closest" free block to the hint. This
+ provides a tool for locating blocks to add to the B-tree, or to hold block
+ copies created with SAVE that would otherwise be lost when DSE exits. FIND
+ -FREE relies on the bitmaps to locate its target, so be sure to fix any
+ blocks incorrectly marked "FREE" before using this command.
+
+ Required with: -FREEBLOCK; compatible with -BLOCK and [NO]CRIT.
+
+ -K[EY]=key
+
+ Searches the database for the block containing the specified key or if the
+ key does not exist, the block that would contain it, if it existed.
+
+ o Enclose an M-style key in quotation marks (" "). FIND -KEY is useful
+ in locating properly indexed keys. The -KEY qualifier is incompatible
+ with all other qualifiers.
+ o FIND -KEY= uses the index to locate the level zero (0) block , or data
+ block, containing the key. If the key does not exist, it uses the
+ index to locate the block in which it would reside. Note that FIND
+ only works with the index as currently composed. In other words, it
+ cannot FIND the "right" place, only the place pointed to by the index
+ at the time the command is issued. These two locations should be, and
+ may well be, the same; however, remind yourself to search for,
+ understand and take into account all information describing any
+ current database integrity issues.
+
+ Compatible only with [NO]CRIT.
+
+ -[NO]C[RIT]
+
+ Allows FIND to work even if another process is holding a critical section.
+
+ As results in this mode may be inconsistent, it should only be used if the
+ critical section mechanism is not operating normally
+
+ -R[EGION][=region]
+
+ Switches to the named Global Directory region.
+
+ -REGION without a specified region, or -REGION="*", displays all existing
+ regions in the database.
+
+ Use Alone.
+
+ -S[IBLINGS]
+
+ Displays the block number of the specified block and its logical siblings
+ in hexadecimal format.
--NUMBER
- -N[UMBER]=number
- Specifies the number to evaluate. This qualifier is required.
+ The logical siblings are the blocks, if any, that logically exist to the
+ right and left of the given block in the database tree structure.
+
+ Incompatible with: -FREEBLOCK, -HINT, -KEY, -REGION
+
+3 Examples
+ Examples
Example:
- DSE> evaluate-number=61
+ DSE> find -exhaustive -block=180
+ Directory path
+ Path--blk:off
+ 1:10 2:1E
- Hex: 61 Dec: 97
+ Global paths
+ Path--blk:off
+ 6:51 1A4:249 180
+ This command locates block 180 by looking through the B-tree index for any
+ pointer to the block. This command finds even those blocks that are
+ connected to the tree but the first key in the block does not match the
+ index path.
-1 EXIT
- EX[IT]
- The EXIT command ends a DSE session.
+ Example:
- The format of the EXIT command is:
+ DSE> find -free -hint=180
- EX[IT]
+ Next free block is D8F.
- The EXIT command has no qualifiers.
+ This command locates the "closest" free block to block 180.
-1 FIND
- F[IND]
- The FIND command directs DSE to a given block or region. At the
- beginning of a DSE session, use the FIND -REGION command to select the
- target region.
-
- The FIND command, except with the -FREEBLOCK and -REGION qualifiers,
- uses the index tree to locate blocks. FIND can locate blocks only
- within the index tree structure. If you need to locate keys
- independent of their attachment to the tree, use the RANGE command.
-
-2 Qualifiers
--BLOCK
- -B[LOCK]=block_number
- Specifies the block to find. The -BLOCK qualifier is
- incompatible with the -KEY and -REGION qualifiers.
-
- On commands with no -BLOCK= qualifier, DSE uses the last block
- handled by a DSE operation. In this case, when no block has been
- accessed, .i.e., on the first block oriented command, DSE uses
- block one (1).
-
--EXHAUSTIVE
- -E[XHAUSTIVE]
- Instructs DSE to search the entire index structure for the
- desired path or siblings. FIND -EXHAUSTIVE is useful in locating
- blocks that are in the tree but not indexed correctly. The
- -EXHAUSTIVE qualifier is incompatible with the -FREEBLOCK, -KEY
- and -REGION qualifiers.
-
--FREEBLOCK
- -F[REEBLOCK]
- Finds the nearest free block to the block specified by -HINT.
- The -FREEBLOCK qualifier is incompatible with all other
- qualifiers except -BLOCK and -HINT. The -HINT qualifier is
- required with the -FREEBLOCK qualifier.
-
--HINT
- -H[INT]=block_number
- Designates the starting point of a -FREEBLOCK search. The -HINT
- qualifier can be used only in conjunction with the -FREEBLOCK
- qualifier.
+ You can use this command as a tool for locating blocks to add to the
+ B-tree, or to hold block copies created with SAVE that would otherwise be
+ lost when DSE exits.
--KEY
- -K[EY]=key
- Searches the database for the block containing the specified
- key. Enclose a MUMPS style key in quotes (""). The -KEY
- qualifier is incompatible with all other qualifiers.
+ Example:
--REGION
- -R[EGION][=region]
- Switches to the named Global Directory region. The -REGION
- qualifier is incompatible with all other qualifiers.
+ DSE>find -key="^biggbl(1)"
- -REGION without a specified region, or -REGION=*, displays all
- existing regions in the database.
+ This command locates the key ^biggbl(1) in the database.
--SIBLINGS
- -S[IBLINGS]
- Displays the block numbers of the logical siblings of the
- specified block. The logical siblings are the blocks that
- logically exist to the right and left of the given block in the
- database tree structure. The -SIBLINGS qualifier is incompatible
- with the -FREEBLOCK, -KEY and -REGION qualifiers.
+ Example:
-1 HELP
- H[ELP]
- The HELP command explains DSE commands. The format of the HELP command
- is:
+ DSE> find -freeblock -hint=232
- H[ELP] [item]
+ This commands starts to search for free block after block 232.
- Item tells HELP which information to display. Enter the DSE command
- (item) after the HELP command or at the Topic prompt. Use <RETURN> or
- <CTRL Z> to return to the DSE prompt.
+ Example:
-1 INTEGRIT
- I[NTEGRIT]
- The INTEGRIT command checks the internal consistency of a non-bitmap
- block. INTEG reports errors in hexadecimal notation.
+ DSE> FIND -FREEBLOCK -HINT=232 -NOCRIT
- The format of the INTEGRIT command is:
+ This command searches for freeblocks after block 232 even if another
+ process is holding a critical section.
+
+ Example:
+
+ DSE> find -sibling -block=10
+
+ This command operates like FIND -BLOCK; however it reports the numbers of
+ the blocks that logically fall before and after block 180 on the same
+ level. This command produces an output like the following:
- I[NTEGRIT] -B[LOCK]=block_number
+ Left sibling Current block Right sibling
+ 0x0000000F 0x00000010 0x00000011
-2 Qualifiers
--BLOCK
- -B[LOCK]=block_number
- Specifies the block for DSE to check.
+2 Help
+ Help
- On commands with no -BLOCK= qualifier, DSE uses the last block
- handled by a DSE operation. In this case, when no block has been
- accessed, .i.e., on the first block oriented command, DSE uses
- block one (1).
+ The HELP command explains DSE commands. The format of the HELP command is:
-1 MAPS
- M[APS]
- The MAPS command examines or updates bit maps.
+ -H[ELP] [help topic]
- MAPS forces blocks either -BUSY or -FREE. The -MASTER qualifier
- reflects the current status of a local bit map back into the master
- map. The -RESTORE qualifier rebuilds all maps and should be used with
- a great deal of caution as it can destroy important information.
+2 Integrit
+ Integrit
- By default, MAPS shows the status of the bit map for the specified
+ Checks the internal consistency of a single non-bitmap block. INTEGRIT
+ reports errors in hexadecimal notation.
+
+ The format of the INTEGRIT command is:
+
+ I[NTEGRIT] -B[LOCK]=block-number
+
+ **Note**
+
+ Unlike MUPIP INTEG, this command only detects errors internal to a block
+ and cannot detect errors such as indices incorrectly pointing to another
block.
-2 Qualifiers
--BLOCK
- -BL[OCK]=block_number
- Specifies the target block for MAPS. The -BLOCK qualifier is
- incompatible with the -RESTORE_ALL qualifier.
-
- On commands with no -BLOCK= qualifier, DSE uses the last block
- handled by a DSE operation. In this case, when no block has been
- accessed, .i.e., on the first block-oriented command, DSE uses
- block one (1).
-
--BUSY
- -BU[SY]
- Marks the current block busy in the block's local map and
- appropriately updates the master bit map. The -BUSY qualifier is
- incompatible with all qualifiers except -BLOCK.
-
--FREE
- -F[REE]
- Marks the current block free in the block's local map and
- appropriately updates the master bit map. The -FREE qualifier is
- incompatible with all qualifiers except -BLOCK.
-
--MASTER
- -M[ASTER]
- Sets the master bit map bit associated with the current block's
- local map according to whether that local map is full or not.
- The -MASTER qualifier is incompatible with all qualifiers except
- -BLOCK.
-
--RESTORE_ALL
- -R[ESTORE_ALL]
- Sets all local bit maps and the master bit map to reflect the
- blocks used in the database file. Use RESTORE_ALL only if the
- database contents are known to be correct, but a large number of
- the bit maps require correction. The -RESTORE_ALL qualifier is
- incompatible with all other qualifiers.
-
-1 OPEN
- OP[EN]
- The OPEN command opens a file for sequential output of global variable
- data. OPEN a file to which you want to "dump" information.
-
- The format of the OPEN command is:
-
- OP[EN] -F[ILE]=file
-
- If an OPEN command does not have a -FILE qualifier, DSE reports the
- name of the current output file.
-
-2 Qualifiers
--F[ILE]
- -F[ILE]=file
+3 Qualifiers
+ Qualifiers
+
+ -B[LOCK]=block_number
+
+ Specifies the block for DSE to check. On commands with no -BLOCK
+ qualifier, DSE uses the last block handled by a DSE operation. When no
+ block has been accessed, that is, on the first block-oriented command, DSE
+ uses block one (1).
+
+ -NO[CRIT]
+
+ Allows DSE INTEG to work even if another process is holding a critical
+ section. Since results in this mode may be inconsistent, it should only be
+ used if the critical section mechanism is not operating normally.
+
+2 Maps
+ Maps
+
+ Examines or updates bitmaps. The format of the MAPS command is:
+
+ M[APS] -BL[OCK]=block-number
+ -BU[SY]
+ -F[REE]
+ -M[ASTER]
+ -R[ESTORE_ALL]
+
+ MAPS can flag blocks as being either -BUSY or -FREE. The -MASTER qualifier
+ reflects the current status of a local bitmap back into the master map.
+ The -RESTORE_ALL qualifier rebuilds all maps and should be used with
+ caution since it can destroy important information.
+
+ By default, MAPS shows the status of the bitmap for the specified block.
+
+3 Qualifiers_for_MAP
+ Qualifiers for MAP
+
+ -BL[OCK]=block_number
+
+ Specifies the target block for MAPS. The -BLOCK qualifier is incompatible
+ with the -RESTORE_ALL qualifier.
+
+ On commands with no -BLOCK= or -RESTORE_ALL qualifier, DSE uses the last
+ block handled by a DSE operation. When no block has been accessed, that
+ is, on the first block-oriented command, DSE uses block one (1).
+
+ Incompatible with: -RESTORE_ALL
+
+ -BU[SY]
+
+ Marks the current block as busy in the block's local map and appropriately
+ updates the master bitmap.
+
+ Compatible only with: -BLOCK
+
+ -F[REE]
+
+ Marks the current block as free in the block's local map and appropriately
+ updates the master bitmap.
+
+ Compatible only with: -BLOCK
+
+ -M[ASTER]
+
+ Sets the bit in the master bitmap associated with the current block's
+ local map according to whether or not that local map is full.
+
+ Use only with: -BLOCK.
+
+ -R[ESTORE_ALL]
+
+ Sets all local bitmaps and the master bitmap to reflect the blocks used in
+ the database file.
+
+ Use -RESTORE_ALL only if the database contents are known to be correct,
+ but a large number of the bitmaps require correction.
+
+ **Caution**
+
+ The -RESTORE_ALL qualifier rebuilds all maps and should be used with a
+ great deal of caution as it can destroy important information.
+
+ Use alone.
+
+3 Examples_for_MAPS
+ Examples for MAPS
+
+ Example:
+
+ DSE> MAPS -BLOCK=20 -FREE
+
+ This command flags block 20 as free. A sample DSE DUMP output block 0 is
+ as follows:
+
+ Block 0 Size 90 Level -1 TN 10B76A V5 Master Status: Free Space
+ Low order High order
+ Block 0: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX |
+ Block 20: | :XXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX |
+ Block 40: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX |
+ Block 60: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX |
+ Block 80: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX |
+ Block A0: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX |
+ Block C0: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX |
+ Block E0: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX |
+ Block 100: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX |
+ Block 120: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX |
+ Block 140: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX |
+ Block 160: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX |
+ Block 180: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX |
+ Block 1A0: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX |
+ Block 1C0: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX |
+ Block 1E0: | XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX |
+
+ 'X' == BUSY '.' == FREE ':' == REUSABLE '?' == CORRUPT
+
+ Note that BLOCK 20 is marked as REUSABLE, which means FREE but in need of
+ a before-image journal record.
+
+ Example:
+
+ DSE> maps -block=20 -busy
+
+ This command marks block 20 as busy. A sample DSE DUMP output of block 0
+ is as follows:
+
+ Block 0 Size 90 Level -1 TN 1 V5 Master Status: Free Space
+
+ Low order High order
+ Block 0: | XXX..... ........ ........ ........ |
+ Block 20: | X....... ........ ........ ........ |
+ Block 40: | ........ ........ ........ ........ |
+ Block 60: | ........ ........ ........ ........ |
+ Block 80: | ........ ........ ........ ........ |
+ Block A0: | ........ ........ ........ ........ |
+ Block C0: | ........ ........ ........ ........ |
+ Block E0: | ........ ........ ........ ........ |
+ Block 100: | ........ ........ ........ ........ |
+ Block 120: | ........ ........ ........ ........ |
+ Block 140: | ........ ........ ........ ........ |
+ Block 160: | ........ ........ ........ ........ |
+ Block 180: | ........ ........ ........ ........ |
+ Block 1A0: | ........ ........ ........ ........ |
+ Block 1C0: | ........ ........ ........ ........ |
+ Block 1E0: | ........ ........ ........ ........ |
+
+ 'X' == BUSY '.' == FREE ':' == REUSABLE '?' == CORRUPT
+
+ Note that the BLOCK 20 is marked as BUSY.
+
+2 OPen
+ OPen
+
+ Use the OPEN command to open a file for sequential output of global
+ variable data. The format of the OPEN command is:
+
+ OP[EN] F[ILE]=file
+
+ o OPEN a file to which you want to "dump" information.
+ o If an OPEN command does not have a -FILE qualifier, DSE reports the
+ name of the current output file.
+
+3 Qualifiers_for_OPEN
+ Qualifiers for OPEN
+
+ -F[ILE]=file-name
+
Specifies the file to open.
-1 OVERWRITE
- OV[ERWRITE]
- The OVERWRITE command overwrites the specified string onto the given
- offset in the current block. Use extreme caution when using this
- command.
+3 Examples
+ Examples
+
+ Example:
+
+ DSE> OPEN
+
+ Current output file: var.out
+
+ This command displays the current output file. In this case, the output
+ file is var.out.
+
+ Example:
+
+ DSE> OPEN -FILE=var1.out
+
+ The command OPEN -FILE=var1.out sets the output file to var1.out.
+
+2 OVerwrite
+ OVerwrite
+
+ Overwrites the specified string on the given offset in the current block.
+ Use extreme caution when using this command.
The format of the OVERWRITE command is:
- OV[ERWRITE] -D[ATA]=string
- -O[FFSET]=offset
-
-2 Qualifiers
--D[ATA]
- -D[ATA]=string
- Specifies the data to be written. Use quotes around string and
- escape codes of the form \a or \ab, where a and b are
- hexadecimal digits, for non-printing characters. \\ translates
- to a single backslash.
-
--O[FFSET]
- -O[FFSET]=offset
- Specifies the offset in the current block where the overwrite
- should begin.
-
-1 PAGE
- P[AGE]
- The PAGE command sends one form feed to the output device. Use PAGE to
- add form feeds to a dump file, making the hardcopy file easier to
- read. If you plan to use the dump file with MUPIP LOAD, do not use
- PAGE.
+ OV[ERWRITE] -D[ATA]=string
+ -O[FFSET]=offset
+
+3 Qualifiers_for_OVERWRITE
+ Qualifiers for OVERWRITE
+
+ -B[LOCK]=block number
+
+ Directs DSE to OVERWRITE a specific block. If no block number is
+ specified, the default is the current block.
+
+ -D[ATA]=string
+
+ Specifies the data to be written. Use quotation marks around the string
+ and escape codes of the form \a or \ab, where "a" and "b" are hexadecimal
+ digits representing non-printing characters. \\ translates to a single
+ backslash.
+
+ -O[FFSET]=offset
+
+ Specifies the offset in the current block where the overwrite should
+ begin.
+
+3 Examples
+ Examples
+
+ Example:
+
+ DSE>overwrite -block=31 -data="Malvern" -offset=CA
+
+ This command overwrites the data at the specified location.
+
+2 Page
+ Page
+
+ Sends one form feed to the output device. Use PAGE to add form feeds to a
+ dump file, making the hard copy file easier to read. If you plan to use
+ the dump file with MUPIP LOAD, do not use PAGE.
The format of the PAGE command is:
@@ -854,233 +2038,743 @@
The PAGE command has no qualifiers.
-1 RANGE
- RA[NGE]
- The RANGE command finds all blocks in the database whose first key
- falls in the specified range of keys. The RANGE command may take a
- very long time unless the range specified by -FROM and -TO is close
- together. Use FIND -KEY first to determine whether the key appears in
- the tree.
+2 RAnge
+ RAnge
+
+ The RANGE command finds all blocks in the database whose first key falls
+ in the specified range of keys. The RANGE command may take a very long
+ time unless the range specified by -FROM and -TO is small. Use FIND -KEY
+ and/or FIND -KEY -EXHAUSTIVE first to quickly determine whether the key
+ appears in the index tree.
The format of the RANGE command is:
- RA[NGE] -F[ROM]=block
- -T[O]=block
- -L[OWER]=key
- -U[PPER]=key
+ RA[NGE] -F[ROM]=block-number
+ -T[O]=block-number
+ -I[NDEX]
+ -LOS[T]
+ -[NO]C[RIT]
+ -[NO]BU[SY]
+ -S[TAR]
+ -LOW[ER]=key
+ -U[PPER]=key
+
+3 Qualifiers
+ Qualifiers
+
+ -F[ROM]=block_number
-2 Qualifiers
--FROM
- -F[ROM]=block_number
Specifies a starting block number for the range search.
- By default, RANGE starts processing at the beginning of the
- file.
+ By default, RANGE starts processing at the beginning of the file.
+
+ -T[O]=block-number
+
+ Specifies an ending block number for the range search. By default, RANGE
+ stops processing at the end of the file.
+
+ -I[NDEX]
--TO
- -T[O]=block_number
- Specifies an ending block number for the range search.
+ Restricts a search to index blocks.
- By default, RANGE stops processing at the end of the file.
+ -LOS[T]=block_number
+
+ Restricts a search to blocks not found by a FIND -BLOCK.
+
+ -LOW[ER]=key
--LOWER
- -L[OWER]=key
Specifies the lower bound for the key range.
--UPPER
- -U[PPER]=key
+ -[NO]BU[SY]=busy/free
+
+ Restricts a search to either BUSY or FREE blocks.
+
+ -[NO]C[RIT]
+
+ Allows DSE RANGE to work even if another process is holding a critical
+ section. Since results in this mode may be inconsistent, it should only be
+ used if the critical section mechanism is not operating normally.
+
+ -S[TAR]
+
+ Includes index blocks that contain a single star key.
+
+ -U[PPER]=key
+
Specifies the upper bound for the key range.
-1 REMOVE
- REM[OVE]
- The REMOVE command removes one or more records or a save buffer.
+3 Examples
+ Examples
+
+ Example:
+
+ DSE> range -lower="^abcdefgh" -upper="^abcdefghi" -from=A -to=CC
+
+ This command searches for a specified keys between block 10 and block 204.
+ Note that the range (between FROM and TO) of blocks must be valid blocks
+ specified in hexadecimal.
+
+ Example:
+
+ DSE> range -lower="^abcdefgh" -upper="^abcdefghi" -from=A -to=CC -noindex
+
+ This command searches only data blocks for the specified keys between
+ block 10 and block 204.
+
+ Example:
+
+ DSE> range -lower="^abcdefgh" -upper="^abcdefghi" -from=A -to=CC -index
+
+ This command searches only index blocks for the specified keys between
+ block 10 and block 204.
+
+ Example:
+
+ DSE> range -lower="^abcdefgh" -upper="^abcdefghi" -lost
+
+ This command includes lost blocks while searching for the specified keys
+ and reports only blocks which are not currently indexed.
+
+ Example:
+
+ DSE> range -lower="^Fruits(15)" -upper="^Fruits(877)" -from=A -to=F
+
+ Blocks in the specified key range:
+ Block: 0000000A Level: 0
+ Block: 0000000B Level: 0
+ Block: 0000000C Level: 0
+ Block: 0000000D Level: 0
+ Block: 0000000E Level: 0
+ Block: 0000000F Level: 0
+
+ Found 6 blocks
+
+ This command search for keys between ^Fruits(15) and ^Fruits(877).
+
+2 REMove
+ REMove
+
+ Removes one or more records or a save buffer.
The format of the REMOVE command is:
- REM[OVE] -B[LOCK]=block_number
- -C[OUNT]=count
- -O[FFSET]
- -R[ECORD]=record_number
- -V[ERSION]=version_number
+ REM[OVE] -B[LOCK]=block-number
+ -C[OUNT]=count
+ -O[FFSET]=offset
+ -R[ECORD]=record-number
+ -V[ERSION]=version-number
The version number is specified in decimal.
-2 Qualifiers
--BLOCK
- -B[LOCK]=block_number
- Specifies the block associated with the record or buffer being
- deleted.
+3 Qualifiers
+ Qualifiers
+
+ -B[LOCK]=block_number
+
+ Specifies the block associated with the record or buffer being deleted.
+
+ On commands with no -BLOCK= qualifier, DSE uses the last block handled by
+ a DSE operation. When no block has been accessed, that is, on the first
+ block-oriented command, DSE uses block one (1).
- On commands with no -BLOCK= qualifier, DSE uses the last block
- handled by a DSE operation. In this case, when no block has been
- accessed, that is, on the first block-oriented command, DSE uses
- block one (1).
+ -C[OUNT]=count
--COUNT
- -C[OUNT]=count
- Specifies the number of records to remove. The -COUNT qualifier
- is incompatible with the -VERSION qualifier.
+ Specifies the number of records to remove.
By default, REMOVE deletes a single record.
--OFFSET
- -O[FFSET]=offset
- Specifies the offset of the record to remove. The -OFFSET
- qualifier is incompatible with the -RECORD and -VERSION
- qualifiers.
-
--RECORD
- -R[ECORD]=record_number
- Specifies the record number of the record to remove. The -RECORD
- qualifier is incompatible with the -OFFSET and -VERSION
- qualifiers.
-
--VERSION
- -V[ERSION]=version_number
- Specifies the decimal version number in decimal of the save
- buffer to remove. -VERSION is required to REMOVE a SAVE buffer.
- -VERSION is incompatible with all qualifiers except -BLOCK.
-
-1 RESTORE
- RES[TORE]
- The RESTORE command restores saved versions of blocks.
+ Incompatible with: -VERSION
+
+ -O[FFSET]=offset
+
+ Specifies the offset (in bytes) of the record to be removed. If the offset
+ does not point to the beginning of a record, DSE rounds down to the
+ beginning of the record containing the offset (for example, REMOVE -OFF=10
+ starts at OFF=A if that was the last prior record boundry).
+
+ Incompatible with: -VERSION, -RECORD
+
+ -R[ECORD]=record_number
+
+ Specifies the number that identifies the record to remove. The -RECORD
+ qualifier is incompatible with the -OFFSET and -VERSION qualifiers.
+
+ Incompatible with: -VERSION, -OFFSET
+
+ -V[ERSION]=version_number
- The format of the RESTORE command is:
+ Specifies the version number, in decimal, of the save buffer to remove.
+ -VERSION is required to REMOVE a SAVE buffer. -VERSION is incompatible
+ with all qualifiers except -BLOCK.
- RES[TORE] -B[LOCK]=block_number
- -F[ROM]=from
- -R[EGION]=region
- -V[ERSION]=version_number
+ Use only with: -BLOCK; decimal
+
+2 REStore
+ REStore
+
+ The RESTORE command restores saved versions of blocks.
+
+ RES[TORE] B[LOCK]=block-number
+ F[ROM]=from
+ R[EGION]=region
+ V[ERSION]=version-number
The version number is specified in decimal.
-2 Qualifiers
--BLOCK
- -B[LOCK]=block_number
+3 Qualifiers
+ Qualifiers
+
+ -B[LOCK]=block_number
+
Specifies the block to restore.
- On commands with no -BLOCK= qualifier, DSE uses the last block
- handled by a DSE operation. In this case, when no block has been
- accessed, .i.e., on the first block oriented command, DSE uses
- block one (1).
+ For commands with no -BLOCK= qualifier, DSE uses the last block handled by
+ a DSE operation. When no block has been accessed, (i.e., on the first
+ block-oriented command), DSE uses block one (1).
+
+ -F[ROM]=block_number
+
+ Specifies the block number of the SAVE buffer to restore.
--FROM
- -F[ROM]=block_number
- Specifies the block number of the save buffer to restore.
+ DSE restores the block specified with -BLOCK qualifier with the block
+ specified by the -FROM qualifier.
- By default, RESTORE uses the target block number as the SAVE
- block number.
+ By default, RESTORE uses the target block number as the -FROM block
+ number.
+
+ -R[EGION]=region
--REGION
- -R[EGION]=region_number
Specifies the region of the saved buffer to restore.
By default, RESTORE uses SAVE buffers from the current region.
--VERSION
- -V[ERSION]=version_number
- Specifies the decimal version number of the block to restore.
- The version number is required.
+ -V[ERSION]=version_number
+
+ Specifies the decimal version number of the block to restore. The version
+ number is required.
+
+2 SAve
+ SAve
+
+ The SAVE command preserves versions of blocks, or displays a listing of
+ saved versions for the current DSE session. Saved information is lost when
+ DSE EXITs.
-1 SAVE
- SA[VE]
- The SAVE command saves versions of blocks or displays a listing of
- saved versions. Saved information is lost when DSE EXITs. Use with the
- RESTORE command to move blocks. As a safety feature, use SAVE to
- retain fallback copies of database blocks before changing them.
+ Use with the RESTORE command to move SAVEd blocks to a permanent location,
+ and as a safety feature use SAVE to retain copies of database blocks
+ before changing them.
The format of the SAVE command is:
- SA[VE] -B[LOCK]=block_number
- -C[OMMENT]=string
- -L[IST]
-
-2 Qualifiers
--BLOCK
- -B[LOCK]=block_number
- Specifies the block to save.
-
- On commands with no -BLOCK= qualifier, DSE uses the last block
- handled by a DSE operation. In this case, when no block has been
- accessed, .i.e., on the first block-oriented command, DSE uses
- block one (1).
-
--COMMENT
- -C[OMMENT]=string
- Specifies a comment to save with the block. Enclose the comment
- in quotes (""). The -COMMENT qualifier is incompatible with the
- -LIST qualifier.
-
--LIST
- -L[IST]
- Lists saved versions of specified blocks. The -LIST qualifier is
+ SA[VE] -B[LOCK]=block-number
+ -C[OMMENT]=string
+ -L[IST]
+ -[NO]C[RIT]
+
+3 Qualifiers
+ Qualifiers
+
+ -B[LOCK]=block_number
+
+ Specifies the block to restore.
+
+ On commands with no -BLOCK= qualifier, DSE uses the last block handled by
+ a DSE operation. When no block has been accessed, that is, on the first
+ block-oriented command, DSE uses block one (1).
+
+ -C[OMMENT]=string
+
+ Specifies a comment to save with the block. Enclose the comment in
+ quotation marks (" ").
+
+ Incompatible with: -LIST
+
+ -L[IST]
+
+ Lists saved versions of specified blocks. The -LIST qualifier is
incompatible with the -COMMENT qualifier.
By default, SAVE -LIST provides a directory of all SAVEd blocks.
-1 SHIFT
- SH[IFT]
- The SHIFT command shifts data in a block, filling the block with zeros
- or shortening the block. The format of the SHIFT command is:
-
- SH[IFT] -B[ACKWARD]=shift
- -F[ORWARD]=shift
- -O[FFSET]=offset
-
-2 Qualifiers
--BACKWARD
- -B[ACKWARD]=shift
- Specifies the extent to which DSE should shift data backwards
- towards the block header. The -BACKWARD qualifier is
- incompatible with the -FORWARD qualifier.
-
--FORWARD
- -F[ORWARD]=shift
- Specifies the extent to which DSE should shift data forward
- towards the end of the block. The -FORWARD qualifier is
- incompatible with the -BACKWARD qualifier.
-
--OFFSET
- -O[FFSET]=offset
- Specifies the starting offset of the portion of the block to
+ Incompatible with: -COMMENT
+
+ -[NO]C[RIT]
+
+ Allows DSE SAVE to work even if another process is holding a critical
+ section. Since results in this mode may be inconsistent, it should only be
+ used if the critical section mechanism is not operating normally.
+
+2 SHift
+ SHift
+
+ Use the SHIFT command to shift data in a block, filling the block with
+ zeros, or shortening the block. The format of the SHIFT command is:
+
+ SH[IFT] -B[ACKWARD]=b_shift
+ -F[ORWARD]=f_shift
+ -O[FFSET]=offset
+
+ b_shift must always be less than or equal to offset. This means that DSE
+ SHIFT in the backward direction is restricted to the maximum of OFFSET
+ number of bytes. This ensures that the shift does not cross block
+ boundaries, either intentionally or unintentionally.
+
+3 Qualifiers
+ Qualifiers
+
+ -B[ACKWARD]=shift
+
+ Specifies the number of bytes to shift data in the direction of the block
+ header.
+
+ Incompatible with: -FORWARD
+
+ -F[ORWARD]=shift
+
+ Specifies the number of bytes to shift data toward the end of the block.
+
+ Incompatible with: -BACKWARD
+
+ -O[FFSET]=offset
+
+ Specifies the starting offset, in bytes, of the portion of the block to
shift.
-1 SPAWN
- SP[AWN]
- The SPAWN command forks a child process for access to the shell
- without terminating the current DSE environment. Use the SPAWN command
- to suspend a session and issue shell commands such as MUPIP INTEG
- -REGION or GDE. The SPAWN command leaves your terminal at the input
- prompt of the shell of the spawned process.
+ -SPawn
+
+2 SPawn
+ SPawn
+
+ Use the SPAWN command to fork a child process for access to the shell
+ without terminating the current DSE environment.
The format of the SPAWN command is:
- SP[AWN] [command]
+ SP[AWN] [shell-command]
+
+ o The SPAWN command accepts an optional command string for execution by
+ the spawned sub-process. If the SPAWN has no command string parameter,
+ the created sub-process issues a shell prompt and accepts any legal
+ shell command. To terminate the sub-process, use the shell logout
+ command.
+ o The SPAWN command has no qualifiers.
+ o DSE SPAWN works with an argument. If the argument contains spaces,
+ enclose it with quotes.
The SPAWN command has no qualifiers.
-1 WCINIT
- W[CINIT]
- The WCINIT command reinitializes the global buffers of the current
- region. Because it cleans out the cache, WCINIT is a very dangerous
- command and therefore should not be used except under Greystone
- supervision.
+ DSE SPAWN works with an argument. If the argument contains spaces, enclose
+ it with quotes.
- WARNING: A WCINIT command issued while normal database operations are
- in progress can cause catastrophic damage to the database.
+3 Examples
+ Examples
- The format of the WCINIT command is:
+ Example:
- W[CINIT]
+ DSE> SPAWN "mumps -run ^GDE"
+
+ This command suspends a DSE session and executes the shell command mumps
+ -run ^GDE.
- The WCINIT command has no qualifiers.
+2 Wcinit
+ Wcinit
- When you issue the WCINIT command, DSE issues the CONFIRMATION:
- prompt. You must verify the WCINIT command by responding with a "YES."
+ Use the WCINIT command to reinitialize the global buffers of the current
+ region. Because it cleans out the cache, the WCINIT command should not be
+ used except under the guidance of FIS.
- If you do not confirm the WCINIT, DSE issues the message:
+ **Caution**
- No action taken, enter yes at the CONFIRMATION prompt to initialize
- global buffers.
+ A WCINIT command issued while normal database operations are in progress
+ can cause catastrophic damage to the database.
+
+ The format of the WCINIT command is:
+
+ W[CINIT]
+ o The WCINIT command has no qualifiers.
+ o When you issue the WCINIT command, DSE issues the CONFIRMATION:
+ prompt. You must verify the WCINIT command by responding with "YES."
+
+ If you do not confirm the WCINIT, DSE issues the message:
+
+ No action taken, enter yes at the CONFIRMATION prompt to initialize global buffers.
+
+ o WCINIT operations are more safely performed by MUPIP RUNDOWN. Use this
+ command only under instructions from FIS.
+
+1 Summary
+ Summary
+
+ +------------------------------------------------------------------------+
+ | COMMAND | QUALIFIERS | COMMENTS |
+ |-------------+-----------------------------------+----------------------|
+ | AD[D] | -B[LOCK]=block number | - |
+ |-------------+-----------------------------------+----------------------|
+ | - | -D[ATA]=string | Incompatible with |
+ | | | -POINTER, -STAR |
+ |-------------+-----------------------------------+----------------------|
+ | - | -K[EY]=key | Incompatible with |
+ | | | -STAR |
+ |-------------+-----------------------------------+----------------------|
+ | - | -O[FFSET]=offset | Incompatible with |
+ | | | -RECORD, -STAR |
+ |-------------+-----------------------------------+----------------------|
+ | - | -P[OINTER]=pointer | Incompatible with |
+ | | | -DATA |
+ |-------------+-----------------------------------+----------------------|
+ | - | -R[ECORD]=record-number | Incompatible with |
+ | | | -OFFSET, -STAR |
+ |-------------+-----------------------------------+----------------------|
+ | | | Incompatible with |
+ | - | -S[TAR] | -DATA,-KEY, -OFFSET, |
+ | | | -RECORD |
+ |-------------+-----------------------------------+----------------------|
+ | AL[L] | -B[UFFER_FLUSH] | Incompatible with |
+ | | | -RENEW |
+ |-------------+-----------------------------------+----------------------|
+ | | | Incompatible with |
+ | - | -C[RITINIT] | -RENEW, -RELEASE, |
+ | | | -SEIZE |
+ |-------------+-----------------------------------+----------------------|
+ | - | -[NO]F[REEZE] | Incompatible with |
+ | | | -RENEW |
+ |-------------+-----------------------------------+----------------------|
+ | - | -O[VERRIDE] | Meaningful only with |
+ | | | -[NO]FREEZE |
+ |-------------+-----------------------------------+----------------------|
+ | - | -REF[ERENCE] | Incompatible with |
+ | | | -RENEW |
+ |-------------+-----------------------------------+----------------------|
+ | | | Incompatible with |
+ | - | -REL[EASE] | -CRITINIT, |
+ | | | -RENEW,-SEIZE |
+ |-------------+-----------------------------------+----------------------|
+ | - | -REN[EW] | Use alone |
+ |-------------+-----------------------------------+----------------------|
+ | | | Incompatible with |
+ | - | -S[EIZE] | -RENEW, -RELEASE, |
+ | | | -CRITINIT |
+ |-------------+-----------------------------------+----------------------|
+ | - | -W[CINIT] | Incompatible with |
+ | | | -RENEW |
+ |-------------+-----------------------------------+----------------------|
+ | B[UFFER | - | - |
+ | _FLUSH] | | |
+ |-------------+-----------------------------------+----------------------|
+ | | | Incompatible with |
+ | CH[ANGE] | -BL[OCK]=block number | -FILEHEADER and |
+ | | | qualifiers used with |
+ | | | -FILEHEADER |
+ |-------------+-----------------------------------+----------------------|
+ | - | -BS[IZ]=block-size | Use only with |
+ | | | -BLOCK, -LEVEL, -TN |
+ |-------------+-----------------------------------+----------------------|
+ | - | -L[EVEL]=level | Use only with |
+ | | | -BLOCK, -BSIZ, -TN |
+ |-------------+-----------------------------------+----------------------|
+ | | | Use only with |
+ | - | -TN [=transaction number] | -BLOCK, -BSIZ, |
+ | | | -LEVEL |
+ |-------------+-----------------------------------+----------------------|
+ | - | -OF[FSET]=offset | Use only with |
+ | | | -BLOCK, -CMPC, -RSIZ |
+ |-------------+-----------------------------------+----------------------|
+ | - | -RE[CORD]=record number | Use only with |
+ | | | -BLOCK, -CMPC, -RSIZ |
+ |-------------+-----------------------------------+----------------------|
+ | | | Use only with |
+ | - | -CM[PC]= compression count | -BLOCK, -RECORD, |
+ | | | -OFFSET, -RSIZ |
+ |-------------+-----------------------------------+----------------------|
+ | | | Use only with -CMPC |
+ | - | -RS[IZ]=record size | -OFFSET, -RECORD, |
+ | | | -BLOCK |
+ |-------------+-----------------------------------+----------------------|
+ | | | Incompatible with |
+ | - | -F[ILEHEADER] | -BSIZ, -CMPC, -TN, |
+ | | | -LEVEL, -OFFSET, |
+ | | | -RECORD, -RSIZ |
+ |-------------+-----------------------------------+----------------------|
+ | - | AVG_BLKS_READ=Average blocks read | |
+ |-------------+-----------------------------------+----------------------|
+ | - | B_B[YTESTREAM]=transaction number | |
+ |-------------+-----------------------------------+----------------------|
+ | - | -B_C[OMPREHENSIVE]=transaction | Use only with |
+ | | number | -FILEHEADER; decimal |
+ |-------------+-----------------------------------+----------------------|
+ | - | B_D[ATABASE] = transaction number | Use only with |
+ | | | -FILEHEADER; decimal |
+ |-------------+-----------------------------------+----------------------|
+ | - | -B_I[NCREMENTAL] = transaction | Use only with |
+ | | number | -FILEHEADER; decimal |
+ |-------------+-----------------------------------+----------------------|
+ | - | -BLK[_SIZE]=block size | Use only with |
+ | | | -FILEHEADER; decimal |
+ |-------------+-----------------------------------+----------------------|
+ | - | -BLO[CKS_FREE]=free blocks | Use only with |
+ | | | -FILEHEADER; decimal |
+ |-------------+-----------------------------------+----------------------|
+ | - | -B_R[ECORD]=transaction number | Use only with |
+ | | | -FILEHEADER; decimal |
+ |-------------+-----------------------------------+----------------------|
+ | - | -CO[RRUPT_FILE]=value | Use only with |
+ | | | -FILEHEADER |
+ |-------------+-----------------------------------+----------------------|
+ | - | -CU[RRENT_TN]=transaction number | Use only with |
+ | | | -FILEHEADER |
+ |-------------+-----------------------------------+----------------------|
+ | - | DECL[OCATION]=value | Use only with |
+ | | | -FILHEADER; decimal |
+ |-------------+-----------------------------------+----------------------|
+ | - | DEF[_COLLATION]=value | Use only with |
+ | | | -FILEHEADER; |
+ |-------------+-----------------------------------+----------------------|
+ | - | -ENCRYPTION_HASH | Use only with |
+ | | | -FILEHEADER |
+ |-------------+-----------------------------------+----------------------|
+ | - | -FL[USH_TIME][=delta time] | Use only with |
+ | | | -FILEHEADER |
+ |-------------+-----------------------------------+----------------------|
+ | - | -FR[EEZE]=value | Use only with |
+ | | | -FILEHEADER |
+ |-------------+-----------------------------------+----------------------|
+ | - | -FU[LLY_UPGRADED]=boolean | Use only with |
+ | | | -FILEHEADER |
+ |-------------+-----------------------------------+----------------------|
+ | - | -GV[STATSRESET] | Use only with |
+ | | | -FILEHEADER |
+ |-------------+-----------------------------------+----------------------|
+ | - | -HARD_SPIN_CPUNT=Mutex hard spin | Use only with |
+ | | count | -FILEHEADER |
+ |-------------+-----------------------------------+----------------------|
+ | | -HEXL[OCATION]=value | Use only with |
+ | | | -FILEHEADER;hexa |
+ |-------------+-----------------------------------+----------------------|
+ | - | -INT[ERRUPTED_RECOV]=boolean | |
+ |-------------+-----------------------------------+----------------------|
+ | - | -JNL_YIELD_LIMIT=journal yeild | |
+ | | limit | |
+ |-------------+-----------------------------------+----------------------|
+ | - | -K[EY_MAX_SIZE]=key_max_size | Use only with |
+ | | | -FILEHEADER; decimal |
+ |-------------+-----------------------------------+----------------------|
+ | - | -M[ACHINE_NAM]=value | |
+ |-------------+-----------------------------------+----------------------|
+ | - | -N[ULL_SUBSCRIPTS]=value | Use only with |
+ | | | -FILEHEADER |
+ |-------------+-----------------------------------+----------------------|
+ | - | -NO[CRIT] | |
+ |-------------+-----------------------------------+----------------------|
+ | - | -OV[ERRIDE] | |
+ |-------------+-----------------------------------+----------------------|
+ | - | -RC_SRV_COUNT | |
+ |-------------+-----------------------------------+----------------------|
+ | - | -RE_READ_TRIGGER=read trigger | |
+ |-------------+-----------------------------------+----------------------|
+ | - | -Q[UANTUM_INTERVAL] [=delta time] | Use only with |
+ | | | -FILEHEADER; decimal |
+ |-------------+-----------------------------------+----------------------|
+ | - | -REC[ORD_MAX_SIZE]=maximum record | Use only with |
+ | | size | -FILEHEADER; decimal |
+ |-------------+-----------------------------------+----------------------|
+ | - | -REF[ERENCE_COUNT]=reference | Use only with |
+ | | count | -FILEHEADER; decimal |
+ |-------------+-----------------------------------+----------------------|
+ | - | -REG[_SEQNO]=sequence number | Use only with |
+ | | | -FILEHEADER; hexa |
+ |-------------+-----------------------------------+----------------------|
+ | - | -RESERVED_BYTES=reserved bytes | Use only with |
+ | | | -FILEHEADER;decimal |
+ |-------------+-----------------------------------+----------------------|
+ | - | -[NO] RES[PONSE_INTERVAL] [=delta | Use only with |
+ | | time] | -FILEHEADER; decimal |
+ |-------------+-----------------------------------+----------------------|
+ | - | -SLEEP_SPIN_COUNT=mutex sleep | Use only with |
+ | | spin count | -FILEHEADER; |
+ |-------------+-----------------------------------+----------------------|
+ | - | -SPIN_SLEEP_TIME=mutex sleep time | |
+ |-------------+-----------------------------------+----------------------|
+ | - | -[NO]S[TALENESS_TIMER] [=delta | Use only with |
+ | | time] | -FILEHEADER; decimal |
+ |-------------+-----------------------------------+----------------------|
+ | - | -TIC[K_INTERVAL] [=delta time] | Use only with |
+ | | | -FILEHEADER; decimal |
+ |-------------+-----------------------------------+----------------------|
+ | - | -TIM[ERS_PENDING]=timers pending | Use only with |
+ | | | -FILEHEADER; decimal |
+ |-------------+-----------------------------------+----------------------|
+ | - | -TO[TAL_BLKS]=total_blocks | Use only with |
+ | | | -FILEHEADER |
+ |-------------+-----------------------------------+----------------------|
+ | - | -TR[IGGER_FLUSH]=trigger flush | Use only with |
+ | | | -FILEHEADER |
+ |-------------+-----------------------------------+----------------------|
+ | - | -W[RITES_PER_FLUSH]=writes per | Use only with |
+ | | flush | -FILEHEADER; decimal |
+ |-------------+-----------------------------------+----------------------|
+ | - | -WAIT_DISK=wait disk | |
+ |-------------+-----------------------------------+----------------------|
+ | - | -Zqgblmod_S[EQNO] = sequence | Use only with |
+ | | number | -FILEHEADER;hexa |
+ |-------------+-----------------------------------+----------------------|
+ | - | -Zqgblmod_T[rans]=sequence_number | Use only with |
+ | | | -FILEHEADER;hexa |
+ |-------------+-----------------------------------+----------------------|
+ |-------------+-----------------------------------+----------------------|
+ | CL[OSE] | - | - |
+ |-------------+-----------------------------------+----------------------|
+ | CR[ITICAL] | -I[NIT] | Use only with -RESET |
+ |-------------+-----------------------------------+----------------------|
+ | - | -O[WNER] | Use alone |
+ |-------------+-----------------------------------+----------------------|
+ | - | -REL[EASE] | Use alone |
+ |-------------+-----------------------------------+----------------------|
+ | - | -REM[OVE] | Use alone |
+ |-------------+-----------------------------------+----------------------|
+ | - | -RES[ET] | Use only with -INIT |
+ |-------------+-----------------------------------+----------------------|
+ | - | -S[EIZE] | Use alone |
+ |-------------+-----------------------------------+----------------------|
+ | D[UMP] | -B[LOCK]=block_number | Incompatible with |
+ | | | -FILEHEADER |
+ |-------------+-----------------------------------+----------------------|
+ | - | -C[OUNT]=count | Incompatible with |
+ | | | -FILEHEADER |
+ |-------------+-----------------------------------+----------------------|
+ | - | -F[ILEHEADER] | Use alone |
+ |-------------+-----------------------------------+----------------------|
+ | - | -G[LO] | Incompatible with |
+ | | | -FILEHEADER, -HEADER |
+ |-------------+-----------------------------------+----------------------|
+ | - | -G[VSTATS] | Use only with |
+ | | | -FILEHEADER |
+ |-------------+-----------------------------------+----------------------|
+ | - | -[NO]H[EADER] | Incompatible with |
+ | | | -FILEHEADER, -GLO |
+ |-------------+-----------------------------------+----------------------|
+ | - | -O[FFSET]=offset | Incompatible with |
+ | | | -FILEHEADER, -RECORD |
+ |-------------+-----------------------------------+----------------------|
+ | - | -R[ECORD]=record_number | Incompatible with |
+ | | | -FILEHEADER, -OFFSET |
+ |-------------+-----------------------------------+----------------------|
+ | EV[ALUATE] | -D[ECIMAL] | Incompatible with |
+ | | | -HEXADECIMAL |
+ |-------------+-----------------------------------+----------------------|
+ | - | -H[EXADECIMAL] | Incompatible with |
+ | | | -DECIMAL |
+ |-------------+-----------------------------------+----------------------|
+ | - | -N[UMBER]=number | Required |
+ |-------------+-----------------------------------+----------------------|
+ | EX[IT] | | - |
+ |-------------+-----------------------------------+----------------------|
+ | F[IND] | -B[LOCK]=block_number | Incompatible with |
+ | | | -KEY, -REGION |
+ |-------------+-----------------------------------+----------------------|
+ | | | Incompatible with |
+ | - | -E[XHAUSTIVE] | -KEY, -REGION, |
+ | | | -FREEBLOCK |
+ |-------------+-----------------------------------+----------------------|
+ | | | Required with -HINT; |
+ | - | -F[REEBLOCK] | compatible with |
+ | | | -BLOCK |
+ |-------------+-----------------------------------+----------------------|
+ | - | -H[INT]=block_number | Required with |
+ | | | -FREEBLOCK |
+ |-------------+-----------------------------------+----------------------|
+ | - | -K[EY]=key | Use alone |
+ |-------------+-----------------------------------+----------------------|
+ | - | -R[EGION][=region] | Use alone |
+ |-------------+-----------------------------------+----------------------|
+ | | | Incompatible with |
+ | - | -S[BLINGS] | -FREEBLOCK, -HINT, |
+ | | | -KEY, -REGION |
+ |-------------+-----------------------------------+----------------------|
+ | H[ELP] | [help topic] | - |
+ |-------------+-----------------------------------+----------------------|
+ | I[NTEGRIT] | -B[LOCK]=block&_number | - |
+ |-------------+-----------------------------------+----------------------|
+ | M[APS] | -BL[OCK]=block_number | Incompatible with |
+ | | | -RESTORE_ALL |
+ |-------------+-----------------------------------+----------------------|
+ | - | -BU[SY] | Compatible only with |
+ | | | -BLOCK |
+ |-------------+-----------------------------------+----------------------|
+ | - | -F[REE] | - |
+ |-------------+-----------------------------------+----------------------|
+ | - | -M[ASTER] | - |
+ |-------------+-----------------------------------+----------------------|
+ | - | -R[ESTORE_ALL] | Use alone |
+ |-------------+-----------------------------------+----------------------|
+ | OP[EN] | -F[ILE]=file | - |
+ |-------------+-----------------------------------+----------------------|
+ | | -B[LOCK]=block_number | |
+ | OV[ERWRITE] | | - |
+ | | -D[ATA]=string | |
+ |-------------+-----------------------------------+----------------------|
+ | - | -O[FFSET]=offset | - |
+ |-------------+-----------------------------------+----------------------|
+ | P[AGE] | - | - |
+ |-------------+-----------------------------------+----------------------|
+ | RA[NGE] | -F[ROM]=block_number | - |
+ |-------------+-----------------------------------+----------------------|
+ | - | -T[O]=block_number | - |
+ |-------------+-----------------------------------+----------------------|
+ | | -I[NDEX]=block_number | |
+ | | | |
+ | | -L[OST]=block_number | |
+ | | | |
+ | - | -[NOT]BUSY=busy/free | - |
+ | | | |
+ | | -S[TAR]=block_number | |
+ | | | |
+ | | -L[OWER]=key | |
+ |-------------+-----------------------------------+----------------------|
+ | - | -U[PPER]=key | - |
+ |-------------+-----------------------------------+----------------------|
+ | REM[OVE] | -B[LOCK]=block-number | - |
+ |-------------+-----------------------------------+----------------------|
+ | - | -C[OUNT]=count | Incompatible with |
+ | | | -VERSION |
+ |-------------+-----------------------------------+----------------------|
+ | - | -O[FFSET]=offset | Incompatible with |
+ | | | -VERSION, -RECORD |
+ |-------------+-----------------------------------+----------------------|
+ | - | -R[ECORD]=record-number | Incompatible with |
+ | | | -VERSION, -OFFSET |
+ |-------------+-----------------------------------+----------------------|
+ | - | -V[ERSION]=version-number | Use only with |
+ | | | -BLOCK; decimal |
+ |-------------+-----------------------------------+----------------------|
+ | RES[TORE] | -B[LOCK]=block-number | - |
+ |-------------+-----------------------------------+----------------------|
+ | - | -F[ROM]=block-number | - |
+ |-------------+-----------------------------------+----------------------|
+ | - | -R[EGION]=region | - |
+ |-------------+-----------------------------------+----------------------|
+ | - | -V[ERSION]=version-number | Required; decimal |
+ |-------------+-----------------------------------+----------------------|
+ | SA[VE] | -B[LOCK]=block-number | - |
+ |-------------+-----------------------------------+----------------------|
+ | - | -C[OMMENT]=string | Incompatible with |
+ | | | -LIST |
+ |-------------+-----------------------------------+----------------------|
+ | - | -L[IST] | Incompatible with |
+ | | | -COMMENT |
+ |-------------+-----------------------------------+----------------------|
+ | SH[IFT] | -B[ACKWARD]=shift | Incompatible with |
+ | | | -FORWARD |
+ |-------------+-----------------------------------+----------------------|
+ | - | -F[ORWARD]=shift | Incompatible with |
+ | | | -BACKWARD |
+ |-------------+-----------------------------------+----------------------|
+ | - | -O[FFSET]=offset | - |
+ |-------------+-----------------------------------+----------------------|
+ | SP[AWN] | [CLI command] | - |
+ |-------------+-----------------------------------+----------------------|
+ | W[CINIT] | - | - |
+ +------------------------------------------------------------------------+
+
+ * Use these qualifiers only with instructions from FIS.
diff --git a/sr_port/dse_adrec.c b/sr_port/dse_adrec.c
index 6cbe311..d0eb367 100644
--- a/sr_port/dse_adrec.c
+++ b/sr_port/dse_adrec.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -49,8 +49,6 @@ GBLREF char patch_comp_key[MAX_KEY_SZ + 1];
GBLREF unsigned short patch_comp_count;
GBLREF gd_region *gv_cur_region;
GBLREF cw_set_element cw_set[];
-GBLREF unsigned char *non_tp_jfb_buff_ptr;
-
void dse_adrec(void)
{
@@ -247,7 +245,7 @@ void dse_adrec(void)
return;
}
t_write(&blkhist, (unsigned char *)bs1, 0, 0, ((blk_hdr_ptr_t)lbp)->levl, TRUE, FALSE, GDS_WRITE_KILLTN);
- BUILD_AIMG_IF_JNL_ENABLED(cs_data, non_tp_jfb_buff_ptr, cs_addrs->ti->curr_tn);
+ BUILD_AIMG_IF_JNL_ENABLED(cs_data, cs_addrs->ti->curr_tn);
t_end(&dummy_hist, NULL, TN_NOT_SPECIFIED);
free(lbp);
diff --git a/sr_port/dse_adstar.c b/sr_port/dse_adstar.c
index 29b26b1..421ef29 100644
--- a/sr_port/dse_adstar.c
+++ b/sr_port/dse_adstar.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -46,7 +46,6 @@ GBLREF srch_hist dummy_hist;
GBLREF gd_addr *gd_header;
GBLREF block_id patch_curr_blk;
GBLREF cw_set_element cw_set[];
-GBLREF unsigned char *non_tp_jfb_buff_ptr;
void dse_adstar(void)
{
@@ -127,7 +126,7 @@ void dse_adstar(void)
return;
}
t_write(&blkhist, (unsigned char *)bs1, 0, 0, ((blk_hdr_ptr_t)lbp)->levl, TRUE, FALSE, GDS_WRITE_KILLTN);
- BUILD_AIMG_IF_JNL_ENABLED(cs_data, non_tp_jfb_buff_ptr, cs_addrs->ti->curr_tn);
+ BUILD_AIMG_IF_JNL_ENABLED(cs_data, cs_addrs->ti->curr_tn);
t_end(&dummy_hist, NULL, TN_NOT_SPECIFIED);
free(lbp);
diff --git a/sr_port/dse_all.c b/sr_port/dse_all.c
index f57de19..c9dd47c 100644
--- a/sr_port/dse_all.c
+++ b/sr_port/dse_all.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -168,11 +168,10 @@ void dse_all(void)
GTMASSERT;
}
patch_curr_blk = get_dir_root();
-
if (crit)
{
- UNIX_ONLY(gtm_mutex_init(gv_cur_region, NUM_CRIT_ENTRY, TRUE);)
- VMS_ONLY(mutex_init(cs_addrs->critical, NUM_CRIT_ENTRY, TRUE);)
+ UNIX_ONLY(gtm_mutex_init(gv_cur_region, NUM_CRIT_ENTRY(cs_addrs->hdr), TRUE));
+ VMS_ONLY(mutex_init(cs_addrs->critical, NUM_CRIT_ENTRY(cs_addrs->hdr), TRUE));
cs_addrs->nl->in_crit = 0;
cs_addrs->hold_onto_crit = FALSE; /* reset this just before cs_addrs->now_crit is reset */
cs_addrs->now_crit = FALSE;
diff --git a/sr_port/dse_cache.c b/sr_port/dse_cache.c
index bcb7d5e..9d452de 100644
--- a/sr_port/dse_cache.c
+++ b/sr_port/dse_cache.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2003, 2012 Fidelity Information Services, Inc *
+ * Copyright 2003, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -60,7 +60,6 @@ void dse_cache(void)
char temp_str[256], temp_str1[256];
sm_uc_ptr_t chng_ptr;
cache_rec_ptr_t cr_que_lo;
- mmblk_rec_ptr_t mr_que_lo;
boolean_t is_mm, was_hold_onto_crit, wc_blocked_ok;
all_present = (CLI_PRESENT == cli_present("ALL"));
@@ -83,7 +82,7 @@ void dse_cache(void)
if (!cli_get_int("SIZE", &size))
return;
if (!((SIZEOF(char) == size) || (SIZEOF(short) == size) || (SIZEOF(int4) == size)))
- rts_error(VARLSTCNT(1) ERR_SIZENOTVALID4);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_SIZENOTVALID4);
}
if (value_present && !cli_get_hex("VALUE", &value))
return;
@@ -227,14 +226,6 @@ void dse_cache(void)
TRUE, REG_LEN_STR(reg), csa->nl->sec_size VMS_ONLY(* OS_PAGELET_SIZE));
} else
{
- util_out_print("Region !AD : mmblk_state = 0x!XJ",
- TRUE, REG_LEN_STR(reg), DB_ABS2REL(csa->acc_meth.mm.mmblk_state));
- mr_que_lo = &csa->acc_meth.mm.mmblk_state->mmblk_array[0];
- util_out_print("Region !AD : mmblk_que_header = 0x!XJ : Numelems = 0x!XL : Elemsize = 0x!XL",
- TRUE, REG_LEN_STR(reg), DB_ABS2REL(mr_que_lo), csa->hdr->bt_buckets, SIZEOF(mmblk_rec));
- util_out_print("Region !AD : mm_cache_record = 0x!XJ : Numelems = 0x!XL : Elemsize = 0x!XL",
- TRUE, REG_LEN_STR(reg), DB_ABS2REL(mr_que_lo + csa->hdr->bt_buckets), csa->hdr->n_bts,
- SIZEOF(mmblk_rec));
util_out_print("Region !AD : shared_memory_size = 0x!XL",
TRUE, REG_LEN_STR(reg), csa->nl->sec_size VMS_ONLY(* OS_PAGELET_SIZE));
util_out_print("Region !AD : db_file_header = 0x!XJ", TRUE, REG_LEN_STR(reg), csa->hdr);
diff --git a/sr_port/dse_chng_bhead.c b/sr_port/dse_chng_bhead.c
index e41486e..fd35dca 100644
--- a/sr_port/dse_chng_bhead.c
+++ b/sr_port/dse_chng_bhead.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -56,7 +56,6 @@ GBLREF gd_region *gv_cur_region;
GBLREF gd_addr *gd_header;
GBLREF cache_rec *cr_array[((MAX_BT_DEPTH * 2) - 1) * 2]; /* Maximum number of blocks that can be in transaction */
GBLREF boolean_t unhandled_stale_timer_pop;
-GBLREF unsigned char *non_tp_jfb_buff_ptr;
GBLREF cw_set_element cw_set[];
error_def(ERR_DSEBLKRDFAIL);
@@ -176,7 +175,7 @@ void dse_chng_bhead(void)
return;
}
t_write(&blkhist, (unsigned char *)bs1, 0, 0, new_hdr.levl, TRUE, FALSE, GDS_WRITE_KILLTN);
- BUILD_AIMG_IF_JNL_ENABLED(csd, non_tp_jfb_buff_ptr, csa->ti->curr_tn);
+ BUILD_AIMG_IF_JNL_ENABLED(csd, csa->ti->curr_tn);
t_end(&dummy_hist, NULL, TN_NOT_SPECIFIED);
}
if (cli_present("TN") == CLI_PRESENT)
@@ -203,7 +202,7 @@ void dse_chng_bhead(void)
t_write(&blkhist, (unsigned char *)bs1, 0, 0,
((blk_hdr_ptr_t)blkhist.buffaddr)->levl, TRUE, FALSE, GDS_WRITE_KILLTN);
/* Pass the desired tn as argument to bg_update/mm_update below */
- BUILD_AIMG_IF_JNL_ENABLED(csd, non_tp_jfb_buff_ptr, tn);
+ BUILD_AIMG_IF_JNL_ENABLED(csd, tn);
was_hold_onto_crit = csa->hold_onto_crit;
csa->hold_onto_crit = TRUE; /* need this so t_end doesn't release crit (see below comment for why) */
t_end(&dummy_hist, NULL, tn);
diff --git a/sr_port/dse_chng_rhead.c b/sr_port/dse_chng_rhead.c
index bd23d56..bdab67e 100644
--- a/sr_port/dse_chng_rhead.c
+++ b/sr_port/dse_chng_rhead.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -47,7 +47,6 @@ GBLREF sgmnt_addrs *cs_addrs;
GBLREF sgmnt_data_ptr_t cs_data;
GBLREF gd_addr *gd_header;
GBLREF cw_set_element cw_set[];
-GBLREF unsigned char *non_tp_jfb_buff_ptr;
void dse_chng_rhead(void)
{
@@ -158,7 +157,7 @@ void dse_chng_rhead(void)
return;
}
t_write(&blkhist, (unsigned char *)bs1, 0, 0, ((blk_hdr_ptr_t)bp)->levl, TRUE, FALSE, GDS_WRITE_KILLTN);
- BUILD_AIMG_IF_JNL_ENABLED(cs_data, non_tp_jfb_buff_ptr, cs_addrs->ti->curr_tn);
+ BUILD_AIMG_IF_JNL_ENABLED(cs_data, cs_addrs->ti->curr_tn);
t_end(&dummy_hist, NULL, TN_NOT_SPECIFIED);
}
return;
diff --git a/sr_port/dse_crit.c b/sr_port/dse_crit.c
index 319e690..5010c56 100644
--- a/sr_port/dse_crit.c
+++ b/sr_port/dse_crit.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -94,8 +94,8 @@ void dse_crit(void)
if (gv_cur_region->read_only)
rts_error(VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(gv_cur_region));
cs_addrs->hdr->image_count = 0;
- UNIX_ONLY(gtm_mutex_init(gv_cur_region, NUM_CRIT_ENTRY, crash);)
- VMS_ONLY(mutex_init(cs_addrs->critical, NUM_CRIT_ENTRY, crash);)
+ UNIX_ONLY(gtm_mutex_init(gv_cur_region, NUM_CRIT_ENTRY(cs_addrs->hdr), crash));
+ VMS_ONLY(mutex_init(cs_addrs->critical, NUM_CRIT_ENTRY(cs_addrs->hdr), crash));
cs_addrs->nl->in_crit = 0;
cs_addrs->now_crit = FALSE;
util_out_print("!/Reinitialized critical section.!/", TRUE);
diff --git a/sr_port/dse_dmp_fhead.c b/sr_port/dse_dmp_fhead.c
index fa8c087..095c8a0 100644
--- a/sr_port/dse_dmp_fhead.c
+++ b/sr_port/dse_dmp_fhead.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -230,9 +230,7 @@ void dse_dmp_fhead (void)
/* Mutex Stuff */
util_out_print(" Mutex Hard Spin Count !19UL", FALSE, csd->mutex_spin_parms.mutex_hard_spin_count);
util_out_print(" Mutex Sleep Spin Count!12UL", TRUE, csd->mutex_spin_parms.mutex_sleep_spin_count);
- util_out_print(" Mutex Spin Sleep Time !19UL", FALSE,
- (csd->mutex_spin_parms.mutex_spin_sleep_mask == 0) ?
- 0 : (csd->mutex_spin_parms.mutex_spin_sleep_mask + 1));
+ util_out_print(" Mutex Queue Slots !19UL", FALSE, NUM_CRIT_ENTRY(csd));
util_out_print(" KILLs in progress !12UL", TRUE, (csd->kill_in_prog + csd->abandoned_kills));
util_out_print(" Replication State !AD", FALSE, 13,
(csd->repl_state == repl_closed ? " OFF"
diff --git a/sr_port/dse_maps.c b/sr_port/dse_maps.c
index 80f604d..e69085f 100644
--- a/sr_port/dse_maps.c
+++ b/sr_port/dse_maps.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -59,7 +59,11 @@ GBLREF gd_region *gv_cur_region;
GBLREF short crash_count;
GBLREF boolean_t unhandled_stale_timer_pop;
GBLREF srch_hist dummy_hist;
-GBLREF unsigned char *non_tp_jfb_buff_ptr;
+
+error_def(ERR_DBRDONLY);
+error_def(ERR_DSEBLKRDFAIL);
+error_def(ERR_DSEFAIL);
+
void dse_maps(void)
{
@@ -84,10 +88,6 @@ void dse_maps(void)
sgmnt_addrs *csa;
sgmnt_data_ptr_t csd;
- error_def(ERR_DSEBLKRDFAIL);
- error_def(ERR_DBRDONLY);
- error_def(ERR_DSEFAIL);
-
if (CLI_PRESENT == cli_present("BUSY") || CLI_PRESENT == cli_present("FREE") ||
CLI_PRESENT == cli_present("MASTER") || CLI_PRESENT == cli_present("RESTORE_ALL"))
{
@@ -159,7 +159,7 @@ void dse_maps(void)
grab_crit(gv_cur_region);
bml_blk = blk / bplmap * bplmap;
if (dba_mm == csd->acc_meth)
- bp = (sm_uc_ptr_t)csa->acc_meth.mm.base_addr + (off_t)bml_blk * blk_size;
+ bp = MM_BASE_ADDR(csa) + (off_t)bml_blk * blk_size;
else
{
assert(dba_bg == csd->acc_meth);
@@ -220,7 +220,7 @@ void dse_maps(void)
BLK_SEG(bs_ptr, blk_ptr + SIZEOF(blk_hdr), bml_size - SIZEOF(blk_hdr));
BLK_FINI(bs_ptr, bs1);
t_write(&blkhist, (unsigned char *)bs1, 0, 0, LCL_MAP_LEVL, TRUE, FALSE, GDS_WRITE_KILLTN);
- BUILD_AIMG_IF_JNL_ENABLED(csd, non_tp_jfb_buff_ptr, csa->ti->curr_tn);
+ BUILD_AIMG_IF_JNL_ENABLED(csd, csa->ti->curr_tn);
t_end(&dummy_hist, NULL, csa->ti->curr_tn);
}
/* Fill in master map */
diff --git a/sr_port/dse_over.c b/sr_port/dse_over.c
index d38fd38..823dcd9 100644
--- a/sr_port/dse_over.c
+++ b/sr_port/dse_over.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -56,7 +56,6 @@ GBLREF gtm_chset_t dse_over_chset;
GBLREF iconv_t dse_over_cvtcd;
#endif
GBLREF cw_set_element cw_set[];
-GBLREF unsigned char *non_tp_jfb_buff_ptr;
GBLREF UConverter *chset_desc[];
LITREF mstr chset_names[];
GBLREF spdesc stringpool;
@@ -219,7 +218,7 @@ void dse_over(void)
return;
}
t_write(&blkhist, (unsigned char *)bs1, 0, 0, ((blk_hdr_ptr_t)lbp)->levl, TRUE, FALSE, GDS_WRITE_KILLTN);
- BUILD_AIMG_IF_JNL_ENABLED(cs_data, non_tp_jfb_buff_ptr, cs_addrs->ti->curr_tn);
+ BUILD_AIMG_IF_JNL_ENABLED(cs_data, cs_addrs->ti->curr_tn);
t_end(&dummy_hist, NULL, TN_NOT_SPECIFIED);
return;
}
diff --git a/sr_port/dse_rest.c b/sr_port/dse_rest.c
index a8a674e..2e90b9f 100644
--- a/sr_port/dse_rest.c
+++ b/sr_port/dse_rest.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -50,7 +50,6 @@ GBLREF sgmnt_addrs *cs_addrs;
GBLREF sgmnt_data_ptr_t cs_data;
GBLREF gd_addr *original_header;
GBLREF cw_set_element cw_set[];
-GBLREF unsigned char *non_tp_jfb_buff_ptr;
void dse_rest(void)
{
@@ -180,7 +179,7 @@ void dse_rest(void)
return;
}
t_write(&blkhist, (unsigned char *)bs1, 0, 0, ((blk_hdr_ptr_t)lbp)->levl, TRUE, FALSE, GDS_WRITE_KILLTN);
- BUILD_AIMG_IF_JNL_ENABLED(cs_data, non_tp_jfb_buff_ptr, cs_addrs->ti->curr_tn);
+ BUILD_AIMG_IF_JNL_ENABLED(cs_data, cs_addrs->ti->curr_tn);
t_end(&dummy_hist, NULL, TN_NOT_SPECIFIED);
return;
}
diff --git a/sr_port/dse_rmrec.c b/sr_port/dse_rmrec.c
index cb12d9c..31ef91f 100644
--- a/sr_port/dse_rmrec.c
+++ b/sr_port/dse_rmrec.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -50,7 +50,6 @@ GBLREF block_id patch_curr_blk;
GBLREF char patch_comp_key[MAX_KEY_SZ + 1];
GBLREF unsigned short patch_comp_count;
GBLREF cw_set_element cw_set[];
-GBLREF unsigned char *non_tp_jfb_buff_ptr;
error_def(ERR_DBRDONLY);
error_def(ERR_DSEBLKRDFAIL);
@@ -145,7 +144,7 @@ void dse_rmrec(void)
}
t_write(&blkhist, (unsigned char *)bs1, 0, 0,
((blk_hdr_ptr_t)lbp)->levl, TRUE, FALSE, GDS_WRITE_KILLTN);
- BUILD_AIMG_IF_JNL_ENABLED(cs_data, non_tp_jfb_buff_ptr, cs_addrs->ti->curr_tn);
+ BUILD_AIMG_IF_JNL_ENABLED(cs_data, cs_addrs->ti->curr_tn);
t_end(&dummy_hist, NULL, TN_NOT_SPECIFIED);
free(lbp);
return;
@@ -195,7 +194,7 @@ void dse_rmrec(void)
return;
}
t_write(&blkhist, (unsigned char *)bs1, 0, 0, ((blk_hdr_ptr_t)lbp)->levl, TRUE, FALSE, GDS_WRITE_KILLTN);
- BUILD_AIMG_IF_JNL_ENABLED(cs_data, non_tp_jfb_buff_ptr, cs_addrs->ti->curr_tn);
+ BUILD_AIMG_IF_JNL_ENABLED(cs_data, cs_addrs->ti->curr_tn);
t_end(&dummy_hist, NULL, TN_NOT_SPECIFIED);
free(lbp);
return;
diff --git a/sr_port/dse_shift.c b/sr_port/dse_shift.c
index 2f1deb5..3096191 100644
--- a/sr_port/dse_shift.c
+++ b/sr_port/dse_shift.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -46,7 +46,6 @@ GBLREF sgmnt_data_ptr_t cs_data;
GBLREF gd_addr *gd_header;
GBLREF block_id patch_curr_blk;
GBLREF cw_set_element cw_set[];
-GBLREF unsigned char *non_tp_jfb_buff_ptr;
void dse_shift(void)
{
@@ -161,7 +160,7 @@ void dse_shift(void)
return;
}
t_write(&blkhist, (unsigned char *)bs1, 0, 0, ((blk_hdr_ptr_t)bp)->levl, TRUE, FALSE, GDS_WRITE_KILLTN);
- BUILD_AIMG_IF_JNL_ENABLED(cs_data, non_tp_jfb_buff_ptr, cs_addrs->ti->curr_tn);
+ BUILD_AIMG_IF_JNL_ENABLED(cs_data, cs_addrs->ti->curr_tn);
t_end(&dummy_hist, NULL, TN_NOT_SPECIFIED);
return;
}
diff --git a/sr_port/dsewrap.mpt b/sr_port/dsewrap.mpt
index 9a692bf..42dc7fe 100644
--- a/sr_port/dsewrap.mpt
+++ b/sr_port/dsewrap.mpt
@@ -1,6 +1,6 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ;
-; Copyright 2012 Fidelity Information Services, Inc. ;
+; Copyright 2012, 2013 Fidelity Information Services, Inc. ;
; ;
; This source code contains the intellectual property ;
; of its copyright holder(s), and is made available ;
@@ -43,7 +43,7 @@ dump(reglist,output,what,detail) ; dump information
set gtmdist=$select(isVMS:"gtm$dist",1:"gtm_dist")
;
; Applicable regions list
- set reglist=$$reglist($$FUNC^%UCASE($get(reglist,"*")),mod)
+ set reglist=$$reglist($$FUNC^%UCASE($get(reglist,"*")),isVMS)
; What operation? for now, should be just "dump -fileheader [-all]"
if (0=$length($get(what)))!("fileheader"=$$FUNC^%LCASE($get(what))) set what=mod_"fileheader"
else set $ecode=",U254," quit:$quit 254 quit
@@ -121,10 +121,13 @@ dsefilecmd(output,regionlist,cmd,isVMS)
; indicates that the script could find no applicable regions. The second piece
; could be null. If so, that piece represents the first region in which DSE
; starts up
-reglist(reglist,mod)
+reglist(reglist,isVMS)
; reglist - comma separated list of regions
- ; mod - the modifier in use, VMS uses '/' whereas Unix uses '-'
- new reg,regavail,i
+ ; isVMS - use '/' (vms) or '-' (unix) for the modifier
+ ; determine GT.CM regions, '::' (vms) vs ':' (unix)
+ new reg,regavail,i,mod,gtcmKey,regpath
+ set mod=$select(isVMS:"/",1:"-")
+ set gtcmKey=$select(isVMS:"::",1:":")
; determine the applicable regions - reglist vs actual available regions
set reglist=$select($get(reglist)="":"*",reglist="ALL":"*",1:reglist)
set regavail=""
@@ -132,6 +135,8 @@ reglist(reglist,mod)
. set reg=$piece(reglist,",",i) set regavail(reg)=1 ; define the region
kill reg
for i=1:1 set reg=$view("gvnext",$get(reg)) quit:reg="" do
+ . set regpath=$VIEW("GVFILE",reg)
+ . quit:(1<$length(regpath,gtcmKey))
. if ("*"=reglist)!($data(regavail(reg))) do
. . set $piece(regavail,",",$length(regavail,",")+1)=$select(i>1:"find "_mod_"region="_reg,1:"")
quit regavail
@@ -153,6 +158,7 @@ parsefhead(output,active)
. if line?1"File"1." ".E set fcnt=$length(line," "),file=$piece(line," ",fcnt) quit
. if line?1"Region"1." ".E do quit
. . set fcnt=$length(line," "),region=$piece(line," ",fcnt)
+ . . if $data(parsed(region,"File")) kill parsed(region) ; DUPLICATE, throw it away
. . set parsed(region,"File")=file
. quit:$data(region)=0
. if line?1"Date/Time".E set parsed(region,"Date/Time")=$$FUNC^%TRIM($extract(line,10,$length(line))) quit
diff --git a/sr_port/eintr_wrappers.h b/sr_port/eintr_wrappers.h
index 9d57f0e..1d9f07a 100644
--- a/sr_port/eintr_wrappers.h
+++ b/sr_port/eintr_wrappers.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -12,7 +12,7 @@
/* Define macros to do system calls and restart as appropriate
*
* FCNTL, FCNTL3 Loop until fcntl call succeeds or fails with other than EINTR.
- * TCFLUSH Loop until tcflush call succeeds or fails with other than EINTR.
+ * TCFLUSH Loop until tcflush call succeeds or fails with other than EINTR.
* Tcsetattr Loop until tcsetattr call succeeds or fails with other than EINTR.
*/
@@ -31,198 +31,199 @@
#include "wbox_test_init.h"
#endif
-#define ACCEPT_SOCKET(SOCKET, ADDR, LEN, RC) \
-{ \
- do \
- { \
- RC = ACCEPT(SOCKET, ADDR, LEN); \
- } while(-1 == RC && EINTR == errno); \
+#define ACCEPT_SOCKET(SOCKET, ADDR, LEN, RC) \
+{ \
+ do \
+ { \
+ RC = ACCEPT(SOCKET, ADDR, LEN); \
+ } while(-1 == RC && EINTR == errno); \
}
-#define CHG_OWNER(PATH, OWNER, GRP, RC) \
-{ \
- do \
- { \
- RC = CHOWN(PATH, OWNER, GRP); \
- } while(-1 == RC && EINTR == errno); \
+#define CHG_OWNER(PATH, OWNER, GRP, RC) \
+{ \
+ do \
+ { \
+ RC = CHOWN(PATH, OWNER, GRP); \
+ } while(-1 == RC && EINTR == errno); \
}
-#define CLOSEDIR(DIR, RC) \
-{ \
- do \
- { \
- RC = closedir(DIR); \
- } while(-1 == RC && EINTR == errno); \
+#define CLOSEDIR(DIR, RC) \
+{ \
+ do \
+ { \
+ RC = closedir(DIR); \
+ } while(-1 == RC && EINTR == errno); \
}
-#define CONNECT_SOCKET(SOCKET, ADDR, LEN, RC) \
-{ \
- do \
- { \
- RC = CONNECT(SOCKET, ADDR, LEN); \
- } while(-1 == RC && EINTR == errno); \
+#define CONNECT_SOCKET(SOCKET, ADDR, LEN, RC) \
+{ \
+ do \
+ { \
+ RC = CONNECT(SOCKET, ADDR, LEN); \
+ } while(-1 == RC && EINTR == errno); \
}
-#define CREATE_FILE(PATHNAME, MODE, RC) \
-{ \
- do \
- { \
- RC = CREAT(PATHNAME, MODE); \
- } while(-1 == RC && EINTR == errno); \
+#define CREATE_FILE(PATHNAME, MODE, RC) \
+{ \
+ do \
+ { \
+ RC = CREAT(PATHNAME, MODE); \
+ } while(-1 == RC && EINTR == errno); \
}
-#define DOREAD_A_NOINT(FD, BUF, SIZE, RC) \
-{ \
- do \
- { \
- RC = DOREAD_A(FD, BUF, SIZE); \
- } while(-1 == RC && EINTR == errno); \
+#define DOREAD_A_NOINT(FD, BUF, SIZE, RC) \
+{ \
+ do \
+ { \
+ RC = DOREAD_A(FD, BUF, SIZE); \
+ } while(-1 == RC && EINTR == errno); \
}
-#define DUP2(FDESC1, FDESC2, RC) \
-{ \
- do \
- { \
- RC = dup2(FDESC1, FDESC2); \
- } while(-1 == RC && EINTR == errno); \
+#define DUP2(FDESC1, FDESC2, RC) \
+{ \
+ do \
+ { \
+ RC = dup2(FDESC1, FDESC2); \
+ } while(-1 == RC && EINTR == errno); \
}
-#define FCLOSE(STREAM, RC) \
-{ \
- do \
- { \
- RC = fclose(STREAM); \
- } while(-1 == RC && EINTR == errno); \
+#define FCLOSE(STREAM, RC) \
+{ \
+ do \
+ { \
+ RC = fclose(STREAM); \
+ } while(-1 == RC && EINTR == errno); \
}
-#define FCNTL2(FDESC, ACTION, RC) \
-{ \
- do \
- { \
- RC = fcntl(FDESC, ACTION); \
- } while(-1 == RC && EINTR == errno); \
+#define FCNTL2(FDESC, ACTION, RC) \
+{ \
+ do \
+ { \
+ RC = fcntl(FDESC, ACTION); \
+ } while(-1 == RC && EINTR == errno); \
}
-#define FCNTL3(FDESC, ACTION, ARG, RC) \
-{ \
- do \
- { \
- RC = fcntl(FDESC, ACTION, ARG); \
- } while(-1 == RC && EINTR == errno); \
+#define FCNTL3(FDESC, ACTION, ARG, RC) \
+{ \
+ do \
+ { \
+ RC = fcntl(FDESC, ACTION, ARG); \
+ } while(-1 == RC && EINTR == errno); \
}
-#define FGETS_FILE(BUF, LEN, FP, RC) \
-{ \
- do \
- { \
- FGETS(BUF, LEN, FP, RC); \
+#define FGETS_FILE(BUF, LEN, FP, RC) \
+{ \
+ do \
+ { \
+ FGETS(BUF, LEN, FP, RC); \
} while(NULL == RC && !feof(FP) && ferror(FP) && EINTR == errno); \
}
-#define FSTAT_FILE(FDESC, INFO, RC) \
-{ \
- do \
- { \
- RC = fstat(FDESC, INFO); \
- } while(-1 == RC && EINTR == errno); \
+#define FSTAT_FILE(FDESC, INFO, RC) \
+{ \
+ do \
+ { \
+ DEFER_INTERRUPTS(INTRPT_IN_FSTAT); \
+ RC = fstat(FDESC, INFO); \
+ ENABLE_INTERRUPTS(INTRPT_IN_FSTAT); \
+ } while(-1 == RC && EINTR == errno); \
}
-#define FSTATVFS_FILE(FDESC, FSINFO, RC) \
-{ \
- do \
- { \
- FSTATVFS(FDESC, FSINFO, RC); \
- } while(-1 == RC && EINTR == errno); \
+#define FSTATVFS_FILE(FDESC, FSINFO, RC) \
+{ \
+ do \
+ { \
+ FSTATVFS(FDESC, FSINFO, RC); \
+ } while(-1 == RC && EINTR == errno); \
}
-#define FTRUNCATE(FDESC, LENGTH, RC) \
-{ \
- do \
- { \
- RC = ftruncate(FDESC, LENGTH); \
- } while(-1 == RC && EINTR == errno); \
+#define FTRUNCATE(FDESC, LENGTH, RC) \
+{ \
+ do \
+ { \
+ RC = ftruncate(FDESC, LENGTH); \
+ } while(-1 == RC && EINTR == errno); \
}
-#define MSGSND(MSGID, MSGP, MSGSZ, FLG, RC) \
-{ \
- do \
- { \
- RC = msgsnd(MSGID, MSGP, MSGSZ, FLG);\
- } while(-1 == RC && EINTR == errno); \
+#define MSGSND(MSGID, MSGP, MSGSZ, FLG, RC) \
+{ \
+ do \
+ { \
+ RC = msgsnd(MSGID, MSGP, MSGSZ, FLG); \
+ } while(-1 == RC && EINTR == errno); \
}
-#define OPEN_PIPE(FDESC, RC) \
-{ \
- do \
- { \
- RC = pipe(FDESC); \
- } while(-1 == RC && EINTR == errno); \
+#define OPEN_PIPE(FDESC, RC) \
+{ \
+ do \
+ { \
+ RC = pipe(FDESC); \
+ } while(-1 == RC && EINTR == errno); \
}
-#define READ_FILE(FD, BUF, SIZE, RC) \
-{ \
- do \
- { \
- RC = read(FD, BUF, SIZE); \
- } while(-1 == RC && EINTR == errno); \
+#define READ_FILE(FD, BUF, SIZE, RC) \
+{ \
+ do \
+ { \
+ RC = read(FD, BUF, SIZE); \
+ } while(-1 == RC && EINTR == errno); \
}
-#define RECVFROM_SOCK(SOCKET, BUF, LEN, FLAGS, \
- ADDR, ADDR_LEN, RC) \
-{ \
- do \
- { \
- RC = RECVFROM(SOCKET, BUF, LEN, \
- FLAGS, ADDR, ADDR_LEN);\
- } while(-1 == RC && EINTR == errno); \
+#define RECVFROM_SOCK(SOCKET, BUF, LEN, FLAGS, \
+ ADDR, ADDR_LEN, RC) \
+{ \
+ do \
+ { \
+ RC = RECVFROM(SOCKET, BUF, LEN, \
+ FLAGS, ADDR, ADDR_LEN); \
+ } while(-1 == RC && EINTR == errno); \
}
-#define SELECT(FDS, INLIST, OUTLIST, XLIST, \
- TIMEOUT, RC) \
-{ \
- struct timeval eintr_select_timeval; \
- do \
- { \
- eintr_select_timeval = *(TIMEOUT); \
- RC = select(FDS, INLIST, OUTLIST, \
- XLIST, \
- &eintr_select_timeval);\
- } while(-1 == RC && EINTR == errno); \
+#define SELECT(FDS, INLIST, OUTLIST, XLIST, \
+ TIMEOUT, RC) \
+{ \
+ struct timeval eintr_select_timeval; \
+ do \
+ { \
+ eintr_select_timeval = *(TIMEOUT); \
+ RC = select(FDS, INLIST, OUTLIST, \
+ XLIST, &eintr_select_timeval); \
+ } while(-1 == RC && EINTR == errno); \
}
-#define SEND(SOCKET, BUF, LEN, FLAGS, RC) \
-{ \
- do \
- { \
- RC = send(SOCKET, BUF, LEN, FLAGS); \
- } while(-1 == RC && EINTR == errno); \
+#define SEND(SOCKET, BUF, LEN, FLAGS, RC) \
+{ \
+ do \
+ { \
+ RC = send(SOCKET, BUF, LEN, FLAGS); \
+ } while(-1 == RC && EINTR == errno); \
}
-#define SENDTO_SOCK(SOCKET, BUF, LEN, FLAGS, \
- ADDR, ADDR_LEN, RC) \
-{ \
- do \
- { \
- RC = SENDTO(SOCKET, BUF, LEN, FLAGS, \
- ADDR, ADDR_LEN); \
- } while(-1 == RC && EINTR == errno); \
+#define SENDTO_SOCK(SOCKET, BUF, LEN, FLAGS, \
+ ADDR, ADDR_LEN, RC) \
+{ \
+ do \
+ { \
+ RC = SENDTO(SOCKET, BUF, LEN, FLAGS, \
+ ADDR, ADDR_LEN); \
+ } while(-1 == RC && EINTR == errno); \
}
-#define STAT_FILE(PATH, INFO, RC) \
-{ \
- do \
- { \
- RC = Stat(PATH, INFO); \
+#define STAT_FILE(PATH, INFO, RC) \
+{ \
+ do \
+ { \
+ RC = Stat(PATH, INFO); \
} while((uint4)-1 == RC && EINTR == errno); \
}
-#define TCFLUSH(FDESC, REQUEST, RC) \
-{ \
- do \
- { \
- RC = tcflush(FDESC, REQUEST); \
- } while(-1 == RC && EINTR == errno); \
+#define TCFLUSH(FDESC, REQUEST, RC) \
+{ \
+ do \
+ { \
+ RC = tcflush(FDESC, REQUEST); \
+ } while(-1 == RC && EINTR == errno); \
}
#if defined(UNIX)
@@ -234,27 +235,27 @@
SIGPROCMASK(SIG_BLOCK, &block_ttinout, &oldset, rc); \
do \
{ \
- RC = tcsetattr(FDESC, WHEN, TERMPTR); \
+ RC = tcsetattr(FDESC, WHEN, TERMPTR); \
} while(-1 == RC && EINTR == errno); \
ERRNO = errno; \
SIGPROCMASK(SIG_SETMASK, &oldset, NULL, rc); \
}
#endif
-#define TRUNCATE_FILE(PATH, LENGTH, RC) \
-{ \
- do \
- { \
- RC = TRUNCATE(PATH, LENGTH); \
- } while(-1 == RC && EINTR == errno); \
+#define TRUNCATE_FILE(PATH, LENGTH, RC) \
+{ \
+ do \
+ { \
+ RC = TRUNCATE(PATH, LENGTH); \
+ } while(-1 == RC && EINTR == errno); \
}
-#define WAIT(STATUS, RC) \
-{ \
- do \
- { \
- RC = wait(STATUS); \
- } while(-1 == RC && EINTR == errno); \
+#define WAIT(STATUS, RC) \
+{ \
+ do \
+ { \
+ RC = wait(STATUS); \
+ } while(-1 == RC && EINTR == errno); \
}
#define WAITPID(PID, STATUS, OPTS, RC) \
@@ -267,16 +268,16 @@
assert(getpid() != PID); \
do \
{ \
- RC = waitpid(PID, STATUS, OPTS); \
+ RC = waitpid(PID, STATUS, OPTS); \
} while(-1 == RC && EINTR == errno); \
}
-#define GTM_FSYNC(FD, RC) \
-{ \
- do \
- { \
- RC = fsync(FD); \
- } while(-1 == RC && EINTR == errno); \
+#define GTM_FSYNC(FD, RC) \
+{ \
+ do \
+ { \
+ RC = fsync(FD); \
+ } while(-1 == RC && EINTR == errno); \
}
#define SIGPROCMASK(FUNC, NEWSET, OLDSET, RC) \
diff --git a/sr_port/emit_code.c b/sr_port/emit_code.c
index 8995252..aa3b0cc 100644
--- a/sr_port/emit_code.c
+++ b/sr_port/emit_code.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -176,8 +176,8 @@ void trip_gen (triple *ct)
continue;
}
*sopr++ = opr;
- if (sopr >= ARRAYTOP(saved_opr))
- rts_error(VARLSTCNT(3) ERR_MAXARGCNT, 1, MAX_ARGS);
+ if (sopr >= ARRAYTOP(saved_opr)) /* user-visible max args is MAX_ARGS - 3 */
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_MAXARGCNT, 1, MAX_ARGS - 3);
}
opr++;
}
@@ -1743,8 +1743,8 @@ void emit_pop(int count)
void add_to_vax_push_list(int pushes_seen)
{ /* Make sure there's enough room */
- if (pushes_seen > MAX_ARGS)
- rts_error(VARLSTCNT(3) ERR_MAXARGCNT, 1, MAX_ARGS);
+ if (pushes_seen > MAX_ARGS) /* user-visible max args is MAX_ARGS - 3 */
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_MAXARGCNT, 1, MAX_ARGS - 3);
push_list_index++;
if (push_list_index >= PUSH_LIST_SIZE)
{
diff --git a/sr_port/eval_expr.c b/sr_port/eval_expr.c
index b6fdeeb..341ba04 100644
--- a/sr_port/eval_expr.c
+++ b/sr_port/eval_expr.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -31,7 +31,6 @@ LITREF toktabtype tokentable[];
int eval_expr(oprtype *a)
{
boolean_t ind_pat, saw_local, saw_se, se_warn;
- char source_line_buff[MAX_SRCLINE + SIZEOF(ARROW)];
int op_count, se_handling;
opctype bin_opcode;
oprtype optyp_1, optyp_2, *optyp_ptr;
@@ -134,11 +133,7 @@ int eval_expr(oprtype *a)
dqins(t1, exorder, argtrip); /* NOTE: violates infomation hiding */
optyp_ptr->oprval.tref = argtrip;
if (se_warn)
- {
- TREF(last_source_column) = t1->src.column + 1;
- show_source_line(source_line_buff, SIZEOF(source_line_buff), TRUE);
- dec_err(VARLSTCNT(1) ERR_SIDEEFFECTEVAL);
- }
+ ISSUE_SIDEEFFECTEVAL_WARNING(t1->src.column + 1);
}
} /* end of side effect processing */
assert((catbp == catbp->que.fl) && (catbp == catbp->que.bl) && (NULL == catbp->bpt));
@@ -191,11 +186,7 @@ int eval_expr(oprtype *a)
optyp_1 = put_tref(ref);
dqins(ref1, exorder, ref); /* NOTE: another violation of information hiding */
if (se_warn)
- {
- TREF(last_source_column) = ref1->src.column + 1;
- show_source_line(source_line_buff, SIZEOF(source_line_buff), TRUE);
- dec_err(VARLSTCNT(1) ERR_SIDEEFFECTEVAL);
- }
+ ISSUE_SIDEEFFECTEVAL_WARNING(ref1->src.column + 1);
}
ref = newtriple(bin_opcode);
ref->operand[0] = optyp_1;
diff --git a/sr_port/exfun_frame.c b/sr_port/exfun_frame.c
index 5f06dd6..62eb4a9 100644
--- a/sr_port/exfun_frame.c
+++ b/sr_port/exfun_frame.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -39,9 +39,9 @@ void exfun_frame (void)
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);
}
assert (msp < stackbase);
assert((frame_pointer < frame_pointer->old_frame_pointer) || (NULL == frame_pointer->old_frame_pointer));
@@ -52,9 +52,9 @@ void exfun_frame (void)
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);
}
sf->temps_ptr = msp;
assert(msp < stackbase);
@@ -63,6 +63,9 @@ void exfun_frame (void)
sf->ret_value = NULL;
sf->dollar_test = -1;
sf->old_frame_pointer = frame_pointer;
+ sf->type &= SFT_ZINTR_OFF; /* Don't propagate special type - normally can't propagate but if $ZINTERRUPT frame is
+ * rewritten by ZGOTO to a "regular" frame, this frame type *can* propagate.
+ */
frame_pointer = sf;
assert((frame_pointer < frame_pointer->old_frame_pointer) || (NULL == frame_pointer->old_frame_pointer));
DBGEHND((stderr, "exfun_frame: Added stackframe at addr 0x"lvaddr" old-msp: 0x"lvaddr" new-msp: 0x"lvaddr"\n",
diff --git a/sr_port/expritem.c b/sr_port/expritem.c
index 8e3469f..c687029 100644
--- a/sr_port/expritem.c
+++ b/sr_port/expritem.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -263,6 +263,7 @@ LITDEF nametabent fun_names[] =
,{2, "ZM"}, {8, "ZMESSAGE"}
,{2, "ZP"}, {8, "ZPREVIOU*"}
,{6, "ZPARSE"}
+ ,{5, "ZPEEK"}
,{3, "ZPI"}, {6, "ZPIECE"}
,{4, "ZPID"}
,{5, "ZPRIV"}, {8, "ZPRIVILE*"}
@@ -283,7 +284,7 @@ LITDEF unsigned char fun_index[27] =
{
0, 2, 2, 4, 6, 8, 12, 14, 14, /* a b c d e f g h i */
17, 19, 19, 21, 21, 25, 27, 29, 35, /* j k l m n o p q r */
- 39, 43, 47, 47, 48, 48, 48, 48, 115 /* s t u v w x y z ~ */
+ 39, 43, 47, 47, 48, 48, 48, 48, 116 /* s t u v w x y z ~ */
};
/* Each entry corresponds to an entry in fun_names */
@@ -351,6 +352,7 @@ LITDEF fun_data_type fun_data[] =
,{ OC_FNZM, ALL_SYS }, { OC_FNZM, ALL_SYS }
,{ OC_FNZPREVIOUS, ALL_SYS }, { OC_FNZPREVIOUS, ALL_SYS }
,{ OC_FNZPARSE, ALL_SYS }
+ ,{ OC_FNZPEEK, UNIX_OS }
,{ OC_FNZPIECE, ALL_SYS }, { OC_FNZPIECE, ALL_SYS }
,{ OC_FNZPID, VMS_OS }
,{ OC_FNZPRIV, VMS_OS }, { OC_FNZPRIV, VMS_OS }
@@ -427,6 +429,7 @@ GBLDEF int (*fun_parse[])(oprtype *, opctype) = /* contains addresses so can't
f_mint, f_mint,
f_zprevious, f_zprevious,
f_zparse,
+ f_zpeek,
f_piece, f_piece,
f_mint,
f_mstr, f_mstr,
@@ -445,7 +448,6 @@ GBLDEF int (*fun_parse[])(oprtype *, opctype) = /* contains addresses so can't
int expritem(oprtype *a)
{
boolean_t parse_warn, saw_local, saw_se, se_warn;
- char source_line_buff[MAX_SRCLINE + SIZEOF(ARROW)];
oprtype *j, *k, x1;
int i, index, sv_opcode;
tbp argbp, *funcbp, *tripbp;
@@ -712,11 +714,7 @@ int expritem(oprtype *a)
dqins(t1, exorder, ref); /* NOTE:this violates infomation hiding */
k->oprval.tref = ref;
if (se_warn)
- {
- TREF(last_source_column) = t1->src.column + 1;
- show_source_line(source_line_buff, SIZEOF(source_line_buff), TRUE);
- dec_err(VARLSTCNT(1) ERR_SIDEEFFECTEVAL);
- }
+ ISSUE_SIDEEFFECTEVAL_WARNING(t1->src.column + 1);
} else
saw_se = TRUE;
}
diff --git a/sr_port/f_get.c b/sr_port/f_get.c
index d0da0fb..8a515a5 100644
--- a/sr_port/f_get.c
+++ b/sr_port/f_get.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -31,7 +31,6 @@ error_def(ERR_VAREXPECTED);
int f_get(oprtype *a, opctype op)
{
boolean_t ok, used_glvn_slot;
- char source_line_buff[MAX_SRCLINE + SIZEOF(ARROW)];
oprtype control_slot, def_opr, *def_oprptr, indir;
short int column;
triple *oldchain, *opptr, *r, *triptr;
@@ -56,23 +55,24 @@ int f_get(oprtype *a, opctype op)
r->opcode = OC_INDGET2;
if (SHIFT_SIDE_EFFECTS)
START_GVBIND_CHAIN(&save_state, oldchain);
- if (!indirection(&indir))
+ if (ok = indirection(&indir)) /* NOTE: assignment */
{
- if (NULL != oldchain)
- setcurtchain(oldchain);
- return FALSE;
+ used_glvn_slot = TRUE;
+ INSERT_INDSAVGLVN(control_slot, indir, ANY_SLOT, 1);
+ r->operand[0] = control_slot;
}
- ok = TRUE;
- used_glvn_slot = TRUE;
- INSERT_INDSAVGLVN(control_slot, indir, ANY_SLOT, 1);
- r->operand[0] = control_slot;
break;
default:
ok = FALSE;
break;
}
if (!ok)
+ {
+ if (NULL != oldchain)
+ setcurtchain(oldchain);
+ stx_error(ERR_VAREXPECTED);
return FALSE;
+ }
opptr = r;
ins_triple(r);
if (used_glvn_slot)
diff --git a/sr_port/f_incr.c b/sr_port/f_incr.c
index 417409e..b497673 100644
--- a/sr_port/f_incr.c
+++ b/sr_port/f_incr.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -24,7 +24,6 @@ error_def(ERR_VAREXPECTED);
int f_incr(oprtype *a, opctype op)
{
boolean_t ok;
- char source_line_buff[MAX_SRCLINE + SIZEOF(ARROW)];
oprtype *increment;
triple incrchain, *oldchain, *r, *savptr, targchain, tmpexpr, *triptr;
DCL_THREADGBL_ACCESS;
diff --git a/sr_port/f_name.c b/sr_port/f_name.c
index 8065d73..d5260ac 100644
--- a/sr_port/f_name.c
+++ b/sr_port/f_name.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -29,7 +29,6 @@ error_def(ERR_VAREXPECTED);
int f_name(oprtype *a, opctype op)
{
boolean_t gbl;
- char source_line_buff[MAX_SRCLINE + SIZEOF(ARROW)];
oprtype *depth;
short int column;
triple *r, *s;
@@ -78,11 +77,7 @@ int f_name(oprtype *a, opctype op)
if (EXPR_FAIL == expr(depth, MUMPS_STR))
return FALSE;
if (!run_time && (OC_INDFNNAME2 == r->opcode) && (SE_WARN == TREF(side_effect_handling)))
- {
- TREF(last_source_column) = column - 1;
- show_source_line(source_line_buff, SIZEOF(source_line_buff), TRUE);
- dec_err(VARLSTCNT(1) ERR_SIDEEFFECTEVAL);
- }
+ ISSUE_SIDEEFFECTEVAL_WARNING(column - 1);
}
coerce(depth, OCT_MVAL);
ins_triple(r);
diff --git a/sr_port/f_order.c b/sr_port/f_order.c
index 531a61e..18ca797 100644
--- a/sr_port/f_order.c
+++ b/sr_port/f_order.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -43,10 +43,9 @@ LITDEF opctype order_opc[LAST_OBJECT][LAST_DIRECTION] =
int f_order(oprtype *a, opctype op)
{
boolean_t ok, used_glvn_slot;
- char source_line_buff[MAX_SRCLINE + SIZEOF(ARROW)];
enum order_dir direction;
enum order_obj object;
- int4 dummy_intval;
+ int4 intval;
opctype gv_oc;
oprtype control_slot, dir_opr, *dir_oprptr, *next_oprptr;
short int column;
@@ -97,6 +96,7 @@ int f_order(oprtype *a, opctype op)
{
if (NULL != oldchain)
setcurtchain(oldchain);
+ stx_error(ERR_VAREXPECTED);
return FALSE;
}
if (TK_COMMA != TREF(window_token))
@@ -119,11 +119,9 @@ int f_order(oprtype *a, opctype op)
triptr = dir_oprptr->oprval.tref;
if (OC_LIT == triptr->opcode)
{ /* if direction is a literal - pick it up and stop flailing about */
- if (MV_IS_TRUEINT(&triptr->operand[0].oprval.mlit->v, &dummy_intval)
- && ((MV_BIAS == triptr->operand[0].oprval.mlit->v.m[1])
- || (-MV_BIAS == triptr->operand[0].oprval.mlit->v.m[1])))
+ if (MV_IS_TRUEINT(&triptr->operand[0].oprval.mlit->v, &intval) && (1 == intval || -1 == intval))
{
- direction = (MV_BIAS == triptr->operand[0].oprval.mlit->v.m[1]) ? FORWARD : BACKWARD;
+ direction = (1 == intval) ? FORWARD : BACKWARD;
sav_ref->opcode = OC_NOOP;
sav_ref = NULL;
} else
diff --git a/sr_port/f_zpeek.c b/sr_port/f_zpeek.c
new file mode 100644
index 0000000..1006b61
--- /dev/null
+++ b/sr_port/f_zpeek.c
@@ -0,0 +1,78 @@
+/****************************************************************
+ * *
+ * Copyright 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+#include "mdef.h"
+
+#include "compiler.h"
+#include "opcode.h"
+#include "toktyp.h"
+#include "advancewindow.h"
+
+error_def(ERR_COMMA);
+
+#ifdef UNIX
+/* Compile 4 parameter $ZPEEK(baseadr,offset,length<,format>) function where:
+ *
+ * structid - A string containing a set of mnemonics that identify the structure to fetch from (see op_fnzpeek.c)
+ * offset - Offset into the block (error if negative).
+ * length - Length to return (error if negative or > MAX_STRLEN).
+ * format - Option parm contains single char formatting code (see op_fnzpeek.c)
+ */
+int f_zpeek(oprtype *a, opctype op)
+{
+ oprtype x;
+ triple *offset, *length, *format, *r;
+ mval mv;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ r = maketriple(op);
+ if (EXPR_FAIL == expr(&(r->operand[0]), MUMPS_STR)) /* Structure identifier string */
+ return FALSE;
+ if (TK_COMMA != TREF(window_token))
+ {
+ stx_error(ERR_COMMA);
+ return FALSE;
+ }
+ advancewindow();
+ offset = newtriple(OC_PARAMETER);
+ r->operand[1] = put_tref(offset);
+ if (EXPR_FAIL == expr(&(offset->operand[0]), MUMPS_INT))
+ return FALSE;
+ if (TK_COMMA != TREF(window_token))
+ {
+ stx_error(ERR_COMMA);
+ return FALSE;
+ }
+ advancewindow();
+ length = newtriple(OC_PARAMETER);
+ offset->operand[1] = put_tref(length);
+ if (EXPR_FAIL == expr(&(length->operand[0]), MUMPS_INT))
+ return FALSE;
+ format = newtriple(OC_PARAMETER);
+ length->operand[1] = put_tref(format);
+ if (TK_COMMA != TREF(window_token))
+ format->operand[0] = put_str("C", 1); /* Default format if none specified */
+ else
+ {
+ advancewindow();
+ if (EXPR_FAIL == expr(&(format->operand[0]), MUMPS_STR))
+ return FALSE;
+ }
+ ins_triple(r);
+ *a = put_tref(r);
+ return TRUE;
+}
+#else /* VMS - function not supported here */
+int f_zpeek(oprtype *a, opctype op)
+{
+ GTMASSERT;
+}
+#endif
diff --git a/sr_port/fntext_ch.c b/sr_port/fntext_ch.c
index 30bdf75..5919db9 100644
--- a/sr_port/fntext_ch.c
+++ b/sr_port/fntext_ch.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -26,6 +26,7 @@ error_def(ERR_VMSMEMORY);
CONDITION_HANDLER(fntext_ch)
{
START_CH;
+ GTMTRIG_ONLY(TREF(in_op_fntext) = FALSE);
if (!DUMPABLE && (SIGNAL != ERR_TPRETRY))
{
UNWIND(NULL, NULL); /* As per the standard, $TEXT returns null string if there are errors while */
diff --git a/sr_port/gbldefs.c b/sr_port/gbldefs.c
index 66ed226..4b01be1 100644
--- a/sr_port/gbldefs.c
+++ b/sr_port/gbldefs.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -10,8 +10,14 @@
****************************************************************/
/* General repository for global variable definitions. This keeps us from
- pulling in modules and all their references when all we wanted was the
- global data def.. */
+ * pulling in modules and all their references when all we wanted was the
+ * global data def.
+ *
+ * Note, all GBLDEF fields are automatically cleared to zeroes. No initialization to
+ * zero (0) or NULL or any other value that translates to zeroes is necessary on these
+ * fields and should be avoided as it creates extra linker and image startup processing
+ * that can only slow things down even if only by a little.
+ */
#include "mdef.h"
@@ -32,6 +38,9 @@
# include <fab.h>
# include "desblk.h"
#endif
+#ifdef GTM_PTHREAD
+# include <pthread.h>
+#endif
#include "cache.h"
#include "hashtab_addr.h"
#include "hashtab_int4.h"
@@ -92,16 +101,13 @@
#include "mmemory.h"
#include "have_crit.h"
#include "alias.h"
-
/* FOR REPLICATION RELATED GLOBALS */
#include "repl_msg.h"
#include "gtmsource.h"
#include "gtmrecv.h"
-
/* FOR MERGE RELATED GLOBALS */
#include "gvname_info.h"
#include "op_merge.h"
-
#ifdef UNIX
#include "cli.h"
#include "invocation_mode.h"
@@ -111,34 +117,27 @@
#include "gtm_zlib.h"
#include "anticipatory_freeze.h"
#endif
-
#include "jnl_typedef.h"
#include "repl_ctl.h"
-
#ifdef VMS
#include "gtm_logicals.h" /* for GTM_MEMORY_NOACCESS_COUNT */
#endif
-
#include "gds_blk_upgrade.h" /* for UPGRADE_IF_NEEDED flag */
#include "cws_insert.h" /* for CWS_REORG_ARRAYSIZE */
-
#ifdef UNICODE_SUPPORTED
#include "gtm_icu_api.h"
#include "gtm_utf8.h"
#include "gtm_conv.h"
#endif
-
# ifdef GTM_CRYPT
# include "gtmcrypt.h"
# include "gdsblk.h"
# include "muextr.h"
# endif
-
#ifdef GTM_TRIGGER
#include "gv_trigger.h"
#include "gtm_trigger.h"
#endif
-
#define DEFAULT_ZERROR_STR "Unprocessed $ZERROR, see $ZSTATUS"
#define DEFAULT_ZERROR_LEN (SIZEOF(DEFAULT_ZERROR_STR) - 1)
@@ -158,7 +157,6 @@ GBLDEF io_log_name *dollar_principal; /* pointer to log name GTM$PRINCIPAL if de
GBLDEF bool prin_in_dev_failure;
GBLDEF bool prin_out_dev_failure;
GBLDEF io_desc *active_device;
-
GBLDEF bool error_mupip,
file_backed_up,
gv_replopen_error,
@@ -176,7 +174,6 @@ GBLDEF bool error_mupip,
view_debug4,
mupip_error_occurred,
dec_nofac;
-
GBLDEF boolean_t is_updproc,
is_updhelper,
mupip_jnl_recover,
@@ -197,7 +194,6 @@ GBLDEF VSIG_ATOMIC_T forced_exit; /* Asynchronous signal/interrupt handler sets
* hence the VSIG_ATOMIC_T type in the definition.
*/
GBLDEF intrpt_state_t intrpt_ok_state = INTRPT_OK_TO_INTERRUPT; /* any other value implies it is not ok to interrupt */
-
GBLDEF unsigned char *msp,
*mubbuf,
*restart_ctxt,
@@ -242,7 +238,6 @@ GBLDEF mval dollar_zinterrupt;
GBLDEF boolean_t dollar_zininterrupt;
GBLDEF boolean_t dollar_ztexit_bool; /* Truth value of dollar_ztexit when coerced to boolean */
GBLDEF boolean_t dollar_zquit_anyway;
-
GBLDEF mv_stent *mv_chain;
GBLDEF sgm_info *first_sgm_info; /* List of participating regions in the TP transaction with NO ftok ordering */
GBLDEF sgm_info *first_tp_si_by_ftok; /* List of participating regions in the TP transaction sorted on ftok order */
@@ -250,7 +245,7 @@ GBLDEF spdesc indr_stringpool,
rts_stringpool,
stringpool;
GBLDEF stack_frame *frame_pointer;
-GBLDEF stack_frame *zyerr_frame = NULL;
+GBLDEF stack_frame *zyerr_frame;
GBLDEF symval *curr_symval;
GBLDEF tp_frame *tp_pointer;
GBLDEF tp_region *halt_ptr,
@@ -262,14 +257,12 @@ GBLDEF gv_namehead *gv_target_list; /* List of ALL gvts that were allocated (in
GBLDEF gv_namehead *gvt_tp_list; /* List of gvts that were referenced in the current TP transaction */
GBLDEF gvt_container *gvt_pending_list; /* list of gvts that need to be re-examined/re-allocated when region is opened */
GBLDEF buddy_list *gvt_pending_buddy_list;/* buddy_list for maintaining memory for gv_targets to be re-examined/allocated */
-
GBLDEF int4 exi_condition;
GBLDEF uint4 gtmDebugLevel;
GBLDEF caddr_t smCallerId; /* Caller of top level malloc/free */
GBLDEF int process_exiting;
GBLDEF int4 dollar_zsystem;
GBLDEF int4 dollar_zeditor;
-GBLDEF boolean_t sem_incremented;
GBLDEF rtn_tabent *rtn_fst_table, *rtn_names, *rtn_names_top, *rtn_names_end;
GBLDEF int4 break_message_mask;
GBLDEF bool rc_locked;
@@ -307,9 +300,7 @@ GBLDEF char cg_phase; /* code generation phase */
/* Previous code generation phase: Only used by emit_code.c to initialize the push list at the
* beginning of each phase (bug fix: C9D12-002478) */
GBLDEF char cg_phase_last;
-
GBLDEF int cmd_cnt;
-
GBLDEF command_qualifier glb_cmd_qlf = { CQ_DEFAULT },
cmd_qlf = { CQ_DEFAULT };
#ifdef __osf__
@@ -320,12 +311,10 @@ GBLDEF char **cmd_arg;
#ifdef __osf__
#pragma pointer_size (restore)
#endif
-
#ifdef UNIX
-GBLDEF volatile uint4 heartbeat_counter = 0;
+GBLDEF volatile uint4 heartbeat_counter;
GBLDEF boolean_t heartbeat_started;
#endif
-
/* DEFERRED EVENTS */
GBLDEF bool licensed = TRUE;
@@ -340,9 +329,7 @@ GBLDEF boolean_t tp_restart_fail_sig_used;
#else
# error "Unsupported Platform"
#endif
-
-GBLDEF volatile int4 fast_lock_count = 0; /* Used in wcs_stale */
-
+GBLDEF volatile int4 fast_lock_count; /* Used in wcs_stale */
/* REPLICATION RELATED GLOBALS */
GBLDEF gtmsource_options_t gtmsource_options;
GBLDEF gtmrecv_options_t gtmrecv_options;
@@ -363,7 +350,6 @@ GBLDEF boolean_t mu_reorg_in_swap_blk; /* set to TRUE for the duration of the
GBLDEF boolean_t mu_rndwn_process;
GBLDEF gv_key *gv_currkey_next_reorg;
GBLDEF gv_namehead *reorg_gv_target;
-
#ifdef UNIX
GBLDEF struct sockaddr_un gtmsecshr_sock_name;
GBLDEF struct sockaddr_un gtmsecshr_cli_sock_name;
@@ -394,16 +380,15 @@ GBLDEF mmseg *mmseg_head;
GBLDEF ua_list *first_ua, *curr_ua;
GBLDEF char *update_array, *update_array_ptr;
GBLDEF int gv_fillfactor = 100,
- rc_set_fragment; /* Contains offset within data at which data fragment starts */
-GBLDEF uint4 update_array_size = 0,
- cumul_update_array_size = 0; /* the current total size of the update array */
+ rc_set_fragment; /* Contains offset within data at which data fragment starts */
+GBLDEF uint4 update_array_size,
+ cumul_update_array_size; /* the current total size of the update array */
GBLDEF kill_set *kill_set_tail;
-GBLDEF boolean_t pool_init = FALSE;
-GBLDEF boolean_t is_src_server = FALSE;
-GBLDEF boolean_t is_rcvr_server = FALSE;
-GBLDEF jnl_format_buffer *non_tp_jfb_ptr = NULL;
-GBLDEF unsigned char *non_tp_jfb_buff_ptr;
-GBLDEF boolean_t dse_running = FALSE;
+GBLDEF boolean_t pool_init;
+GBLDEF boolean_t is_src_server;
+GBLDEF boolean_t is_rcvr_server;
+GBLDEF jnl_format_buffer *non_tp_jfb_ptr;
+GBLDEF boolean_t dse_running;
GBLDEF jnlpool_addrs jnlpool;
GBLDEF jnlpool_ctl_ptr_t jnlpool_ctl;
GBLDEF jnlpool_ctl_struct temp_jnlpool_ctl_struct;
@@ -412,9 +397,8 @@ GBLDEF sm_uc_ptr_t jnldata_base;
GBLDEF int4 jnlpool_shmid = INVALID_SHMID;
GBLDEF recvpool_addrs recvpool;
GBLDEF int recvpool_shmid = INVALID_SHMID;
-GBLDEF int gtmsource_srv_count = 0;
-GBLDEF int gtmrecv_srv_count = 0;
-
+GBLDEF int gtmsource_srv_count;
+GBLDEF int gtmrecv_srv_count;
/* The following _in_prog counters are needed to prevent deadlocks while doing jnl-qio (timer & non-timer). */
GBLDEF volatile int4 db_fsync_in_prog;
GBLDEF volatile int4 jnl_qio_in_prog;
@@ -438,22 +422,19 @@ GBLDEF enum gtmImageTypes image_type; /* initialized at startup i.e. in dse.c, l
GBLDEF parmblk_struct *param_list; /* call-in parameters block (defined in unix/fgncalsp.h)*/
GBLDEF unsigned int invocation_mode = MUMPS_COMPILE; /* how mumps has been invoked */
GBLDEF char cli_err_str[MAX_CLI_ERR_STR] = ""; /* Parse Error message buffer */
-GBLDEF char *cli_err_str_ptr = NULL;
-GBLDEF boolean_t gtm_pipe_child = FALSE;
+GBLDEF char *cli_err_str_ptr;
+GBLDEF boolean_t gtm_pipe_child;
#endif
-GBLDEF io_desc *gtm_err_dev = NULL;
-
+GBLDEF io_desc *gtm_err_dev;
/* this array is indexed by file descriptor */
-GBLDEF boolean_t *lseekIoInProgress_flags = (boolean_t *)0;
-
+GBLDEF boolean_t *lseekIoInProgress_flags;
#if defined(UNIX)
/* Latch variable for Unix implementations. Used in SUN and HP */
GBLDEF global_latch_t defer_latch;
#endif
-
GBLDEF int num_additional_processors;
GBLDEF int gtm_errno = -1; /* holds the errno (unix) in case of an rts_error */
-GBLDEF int4 error_condition = 0;
+GBLDEF int4 error_condition;
GBLDEF global_tlvl_info *global_tlvl_info_head;
GBLDEF buddy_list *global_tlvl_info_list;
GBLDEF boolean_t job_try_again;
@@ -461,17 +442,15 @@ GBLDEF volatile int4 gtmMallocDepth; /* Recursion indicator */
GBLDEF d_socket_struct *socket_pool;
GBLDEF boolean_t mu_star_specified;
GBLDEF backup_reg_list *mu_repl_inst_reg_list;
-
#ifndef VMS
GBLDEF volatile int suspend_status = NO_SUSPEND;
#endif
-
GBLDEF gv_namehead *reset_gv_target = INVALID_GV_TARGET;
-GBLDEF VSIG_ATOMIC_T util_interrupt = 0;
+GBLDEF VSIG_ATOMIC_T util_interrupt;
GBLDEF sgmnt_addrs *kip_csa;
GBLDEF boolean_t need_kip_incr;
-GBLDEF int merge_args = 0;
-GBLDEF merge_glvn_ptr mglvnp = NULL;
+GBLDEF int merge_args;
+GBLDEF merge_glvn_ptr mglvnp;
GBLDEF int ztrap_form;
GBLDEF boolean_t ztrap_new;
GBLDEF int4 wtfini_in_prog;
@@ -494,47 +473,39 @@ GBLDEF int cs_parscan; /* number of partial scans (partial cache hits) */
GBLDEF int c_clear; /* cleared due to (possible) value change */
GBLDEF boolean_t setp_work;
#endif
-GBLDEF z_records zbrk_recs = {NULL, NULL, NULL};
-
+GBLDEF z_records zbrk_recs;
#ifdef UNIX
GBLDEF ipcs_mesg db_ipcs; /* For requesting gtmsecshr to update ipc fields */
-GBLDEF gd_region *ftok_sem_reg = NULL; /* Last region for which ftok semaphore is grabbed */
+GBLDEF gd_region *ftok_sem_reg; /* Last region for which ftok semaphore is grabbed */
GBLDEF int gtm_non_blocked_write_retries; /* number of retries for non-blocked write to pipe */
#endif
-
#ifdef VMS
/* Following global variables store the state of an erroring sys$qio just before a GTMASSERT in the CHECK_CHANNEL_STATUS macro */
-GBLDEF uint4 check_channel_status = 0; /* stores the qio return status */
-GBLDEF uint4 check_channel_id = 0; /* stores the qio channel id */
+GBLDEF uint4 check_channel_status; /* stores the qio return status */
+GBLDEF uint4 check_channel_id; /* stores the qio channel id */
#endif
-
-GBLDEF boolean_t write_after_image = FALSE; /* true for after-image jnlrecord writing by recover/rollback */
+GBLDEF boolean_t write_after_image; /* true for after-image jnlrecord writing by recover/rollback */
GBLDEF int iott_write_error;
GBLDEF int4 write_filter;
-GBLDEF boolean_t need_no_standalone = FALSE;
-
+GBLDEF boolean_t need_no_standalone;
GBLDEF int4 zdir_form = ZDIR_FORM_FULLPATH; /* $ZDIR shows full path including DEVICE and DIRECTORY */
GBLDEF mval dollar_zdir = DEFINE_MVAL_STRING(MV_STR, 0, 0, 0, NULL, 0, 0);
-
-GBLDEF int * volatile var_on_cstack_ptr = NULL; /* volatile pointer to int; volatile so that nothing gets optimized out */
+GBLDEF int * volatile var_on_cstack_ptr; /* volatile pointer to int; volatile so that nothing gets optimized out */
GBLDEF hash_table_int4 cw_stagnate;
-GBLDEF boolean_t cw_stagnate_reinitialized = FALSE;
+GBLDEF boolean_t cw_stagnate_reinitialized;
GBLDEF uint4 pat_everything[] = { 0, 2, PATM_E, 1, 0, PAT_MAX_REPEAT, 0, PAT_MAX_REPEAT, 1 }; /* pattern = ".e" */
GBLDEF mstr_len_t sizeof_pat_everything = SIZEOF(pat_everything);
-
GBLDEF uint4 *pattern_typemask;
GBLDEF pattern *pattern_list;
GBLDEF pattern *curr_pattern;
-
/* Unicode related data */
GBLDEF boolean_t gtm_utf8_mode; /* Is GT.M running with Unicode Character Set; Set only after ICU initialization */
GBLDEF boolean_t is_gtm_chset_utf8; /* Is gtm_chset environment variable set to UTF8 */
GBLDEF boolean_t utf8_patnumeric; /* Should patcode N match non-ASCII numbers in pattern match ? */
-GBLDEF boolean_t badchar_inhibit = FALSE;/* Suppress malformed UTF-8 characters by default */
+GBLDEF boolean_t badchar_inhibit; /* Suppress malformed UTF-8 characters by default */
GBLDEF MSTR_DEF(dollar_zchset, 1, "M");
GBLDEF MSTR_DEF(dollar_zpatnumeric, 1, "M");
-
/* Standard MUMPS pattern-match table.
* This table holds the current pattern-matching attributes of each ASCII character.
* Bits 0..23 of each entry correspond with the pattern-match characters, A..X.
@@ -548,7 +519,6 @@ GBLDEF pattern mumps_pattern = {
1, /* namlen */
{'M', '\0'} /* name */
};
-
/* mapbit is used by pattab.c and patstr.c. Note that patstr.c uses only entries until PATM_X */
GBLDEF readonly uint4 mapbit[] =
{
@@ -557,7 +527,6 @@ GBLDEF readonly uint4 mapbit[] =
PATM_Q, PATM_R, PATM_S, PATM_T, PATM_U, PATM_V, PATM_W, PATM_X,
PATM_YZ1, PATM_YZ2, PATM_YZ3, PATM_YZ4
};
-
LITDEF uint4 typemask[PATENTS] =
{
PATM_C, PATM_C, PATM_C, PATM_C, PATM_C, PATM_C, PATM_C, PATM_C, /* hex 00-07 : ASCII characters */
@@ -593,9 +562,7 @@ LITDEF uint4 typemask[PATENTS] =
PATM_P, PATM_L, PATM_L, PATM_L, PATM_L, PATM_L, PATM_L, PATM_L, /* hex F0-F7 : non-ASCII characters */
PATM_L, PATM_L, PATM_L, PATM_L, PATM_L, PATM_L, PATM_P, PATM_C /* hex F8-FF : non-ASCII characters */
};
-
GBLDEF uint4 pat_allmaskbits; /* universal set of valid pattern bit codes for currently active pattern table */
-
/* globals related to caching of pattern evaluation match result.
* for a given <strptr, strlen, patptr, depth> tuple, we store the evaluation result.
* in the above,
@@ -669,8 +636,8 @@ GBLDEF uint4 lnkrel_cnt; /* number of entries in linkage Psect to relocate */
GBLDEF int4 sym_table_size; /* size of the symbol table during compilation */
GBLDEF boolean_t stop_non_mandatory_expansion, non_mandatory_expansion; /* Used in stringpool managment */
GBLDEF jnl_fence_control jnl_fence_ctl;
-GBLDEF jnl_process_vector *prc_vec = NULL; /* for current process */
-GBLDEF jnl_process_vector *originator_prc_vec = NULL; /* for client/originator */
+GBLDEF jnl_process_vector *prc_vec; /* for current process */
+GBLDEF jnl_process_vector *originator_prc_vec; /* for client/originator */
LITDEF char *jrt_label[JRT_RECTYPES] =
{
#define JNL_TABLE_ENTRY(rectype, extract_rtn, label, update, fixed_size, is_replicated) label,
@@ -730,7 +697,6 @@ GBLDEF boolean_t is_uchar_wcs_code[] = /* uppercase failure codes that imply da
#undef CDB_SC_UCHAR_ENTRY
#undef CDB_SC_LCHAR_ENTRY
};
-
GBLDEF boolean_t is_lchar_wcs_code[] = /* lowercase failure codes that imply database cache related problem */
{ /* if any of the following failure codes are seen in the final retry, wc_blocked will be set to trigger cache recovery */
#define CDB_SC_NUM_ENTRY(code, value)
@@ -741,7 +707,6 @@ GBLDEF boolean_t is_lchar_wcs_code[] = /* lowercase failure codes that imply da
#undef CDB_SC_UCHAR_ENTRY
#undef CDB_SC_LCHAR_ENTRY
};
-
GBLDEF boolean_t gvdupsetnoop = TRUE; /* if TRUE, duplicate SETs do not change GDS block (and therefore no PBLK journal
* records will be written) although the database transaction number will be
* incremented and logical SET journal records will be written. By default, this
@@ -753,26 +718,21 @@ UNIX_ONLY(GBLDEF int4 gtm_shmflags;) /* Extra flags for shmat */
GBLDEF uint4 gtm_memory_noaccess_defined; /* count of the number of GTM_MEMORY_NOACCESS_ADDR logicals which are defined */
GBLDEF uint4 gtm_memory_noaccess[GTM_MEMORY_NOACCESS_COUNT]; /* see VMS gtm_env_init_sp.c */
#endif
-
-GBLDEF volatile boolean_t in_wcs_recover = FALSE; /* TRUE if in "wcs_recover", used by "bt_put" and "generic_exit_handler" */
-
-
-GBLDEF boolean_t in_gvcst_incr = FALSE; /* set to TRUE by gvcst_incr, set to FALSE by gvcst_put
+GBLDEF volatile boolean_t in_wcs_recover; /* TRUE if in "wcs_recover", used by "bt_put" and "generic_exit_handler" */
+GBLDEF boolean_t in_gvcst_incr; /* set to TRUE by gvcst_incr, set to FALSE by gvcst_put
* distinguishes to gvcst_put, if the current db operation is a SET or $INCR */
GBLDEF mval *post_incr_mval; /* mval pointing to the post-$INCR value */
GBLDEF mval increment_delta_mval; /* mval holding the INTEGER increment value, set by gvcst_incr,
* used by gvcst_put/gvincr_recompute_upd_array which is invoked by t_end */
-GBLDEF boolean_t is_dollar_incr = FALSE; /* valid only if gvcst_put is in the call-stack (i.e. t_err == ERR_GVPUTFAIL);
+GBLDEF boolean_t is_dollar_incr; /* valid only if gvcst_put is in the call-stack (i.e. t_err == ERR_GVPUTFAIL);
* is a copy of "in_gvcst_incr" just before it got reset to FALSE */
GBLDEF int indir_cache_mem_size; /* Amount of memory currently in use by indirect cache */
GBLDEF hash_table_objcode cache_table;
GBLDEF int cache_hits, cache_fails;
-
/* The alignment feature is disabled due to some issues in stringpool garbage collection.
* TODO: When we sort out stringpool issues, change mstr_native_align to TRUE below */
-GBLDEF boolean_t mstr_native_align = FALSE;
+GBLDEF boolean_t mstr_native_align;
GBLDEF boolean_t save_mstr_native_align;
-
GBLDEF mvar *mvartab;
GBLDEF mvax *mvaxtab,*mvaxtab_end;
GBLDEF mlabel *mlabtab;
@@ -799,46 +759,35 @@ VMS_ONLY(
GBLDEF char object_file_name[256];
GBLDEF struct FAB obj_fab; /* file access block for the object file */
)
-
GBLDEF int4 curr_addr, code_size;
GBLDEF mident_fixed zlink_mname;
-
GBLDEF sm_uc_ptr_t reformat_buffer;
GBLDEF int reformat_buffer_len;
GBLDEF volatile int reformat_buffer_in_use; /* used only in DEBUG mode */
-
GBLDEF boolean_t mu_reorg_upgrd_dwngrd_in_prog; /* TRUE if MUPIP REORG UPGRADE/DOWNGRADE is in progress */
GBLDEF boolean_t mu_reorg_nosafejnl; /* TRUE if NOSAFEJNL explicitly specified */
GBLDEF trans_num mu_reorg_upgrd_dwngrd_blktn; /* tn in blkhdr of current block processed by MUPIP REORG {UP,DOWN}GRADE */
-
GBLDEF inctn_opcode_t inctn_opcode = inctn_invalid_op;
GBLDEF inctn_detail_t inctn_detail; /* holds detail to fill in to inctn jnl record */
GBLDEF uint4 region_open_count; /* Number of region "opens" we have executed */
-
GBLDEF uint4 gtm_blkupgrade_flag = UPGRADE_IF_NEEDED; /* by default upgrade only if necessary */
GBLDEF boolean_t disk_blk_read;
-
-GBLDEF boolean_t gtm_dbfilext_syslog_disable = FALSE; /* by default, log every file extension message */
-
+GBLDEF boolean_t gtm_dbfilext_syslog_disable; /* by default, log every file extension message */
GBLDEF int4 cws_reorg_remove_index; /* see mu_swap_blk.c for comments on the need for these two */
GBLDEF block_id cws_reorg_remove_array[CWS_REORG_REMOVE_ARRAYSIZE];
-
GBLDEF uint4 log_interval;
-
#ifdef UNIX
GBLDEF uint4 gtm_principal_editing_defaults; /* ext_cap flags if tt */
-GBLDEF boolean_t in_repl_inst_edit = FALSE; /* used by an assert in repl_inst_read/repl_inst_write */
+GBLDEF boolean_t in_repl_inst_edit; /* used by an assert in repl_inst_read/repl_inst_write */
GBLDEF boolean_t in_repl_inst_create; /* used by repl_inst_read/repl_inst_write */
GBLDEF boolean_t holds_sem[NUM_SEM_SETS][NUM_SRC_SEMS]; /* whether a particular replication semaphore is being held
* by the current process or not. */
GBLDEF boolean_t detail_specified; /* Set to TRUE if -DETAIL is specified in MUPIP REPLIC -JNLPOOL or -EDITINST */
GBLDEF boolean_t in_mupip_ftok; /* Used by an assert in repl_inst_read */
GBLDEF uint4 section_offset; /* Used by PRINT_OFFSET_PREFIX macro in repl_inst_dump.c */
-
GBLDEF uint4 mutex_per_process_init_pid; /* pid that invoked "mutex_per_process_init" */
GBLDEF boolean_t gtm_quiet_halt; /* Suppress FORCEDHALT message */
#endif
-
#ifdef UNICODE_SUPPORTED
/* Unicode line terminators. In addition to the following
* codepoints, the sequence CR LF is considered a single
@@ -854,7 +803,6 @@ LITDEF UChar32 u32_line_term[] =
UTF_PARA_SEPARATOR, /* Paragraph Separator */
0x0000
};
-
/* Given the first byte in a UTF-8 representation, the following array returns the total number of bytes in the encoding
* 00-7F : 1 byte
* C2-DF : 2 bytes
@@ -874,7 +822,6 @@ LITDEF unsigned int utf8_bytelen[] =
1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* C0-DF */
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* E0-FF */
};
-
/* Given the first byte in a UTF-8 representation, the following array returns the number of bytes to follow
* 00-7F : 0 byte
* C2-DF : 1 byte
@@ -894,46 +841,34 @@ LITDEF signed int utf8_followlen[] =
-1,-1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* C0-DF */
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* E0-FF */
};
-
GBLDEF gtm_wcswidth_fnptr_t gtm_wcswidth_fnptr; /* see comment in gtm_utf8.h about this typedef */
#endif
-
GBLDEF uint4 gtm_max_sockets; /* Maximum sockets per socket device supported by this process */
GBLDEF d_socket_struct *newdsocket; /* Commonly used temp socket area */
-
GBLDEF boolean_t dse_all_dump; /* TRUE if DSE ALL -DUMP is specified */
GBLDEF int socketus_interruptus; /* How many times socket reads have been interrutped */
-
GBLDEF int4 pending_errtriplecode; /* if non-zero contains the error code to invoke ins_errtriple with */
GBLDEF uint4 process_id;
GBLDEF uint4 image_count; /* not used in UNIX but defined to preserve VMS compatibility */
-
GBLDEF size_t totalRmalloc; /* Total storage currently (real) malloc'd (includes extent blocks) */
GBLDEF size_t totalAlloc; /* Total allocated (includes allocation overhead but not free space */
GBLDEF size_t totalUsed; /* Sum of user allocated portions (totalAlloc - overhead) */
-
GBLDEF size_t totalRallocGta; /* Total storage currently (real) mmap alloc'd */
GBLDEF size_t totalAllocGta; /* Total mmap allocated (includes allocation overhead but not free space */
GBLDEF size_t totalUsedGta; /* Sum of "in-use" portions (totalAllocGta - overhead) */
-
GBLDEF volatile char *outOfMemoryMitigation; /* Cache that we will freed to help cleanup if run out of memory */
GBLDEF uint4 outOfMemoryMitigateSize;/* Size of above cache (in Kbytes) */
-
GBLDEF int mcavail;
GBLDEF mcalloc_hdr *mcavailptr, *mcavailbase;
-
GBLDEF uint4 max_cache_memsize; /* Maximum bytes used for indirect cache object code */
GBLDEF uint4 max_cache_entries; /* Maximum number of cached indirect compilations */
-
GBLDEF void (*cache_table_relobjs)(void); /* Function pointer to call cache_table_rebuild() */
UNIX_ONLY(GBLDEF ch_ret_type (*ht_rhash_ch)()); /* Function pointer to hashtab_rehash_ch */
UNIX_ONLY(GBLDEF ch_ret_type (*jbxm_dump_ch)()); /* Function pointer to jobexam_dump_ch */
UNIX_ONLY(GBLDEF ch_ret_type (*stpgc_ch)()); /* Function pointer to stp_gcol_ch */
-
#ifdef VMS
GBLDEF boolean_t tp_has_kill_t_cse; /* cse->mode of kill_t_write or kill_t_create got created in this transaction */
#endif
-
GBLDEF cache_rec_ptr_t pin_fail_cr; /* Pointer to the cache-record that we failed while pinning */
GBLDEF cache_rec pin_fail_cr_contents; /* Contents of the cache-record that we failed while pinning */
GBLDEF cache_rec_ptr_t pin_fail_twin_cr; /* Pointer to twin of the cache-record that we failed to pin */
@@ -946,7 +881,6 @@ GBLDEF int4 pin_fail_wcs_active_lvl; /* Number of entries in active queue when
GBLDEF int4 pin_fail_ref_cnt; /* Reference count when we failed to pin */
GBLDEF int4 pin_fail_in_wtstart; /* Count of processes in wcs_wtstart when we failed to pin */
GBLDEF int4 pin_fail_phase2_commit_pidcnt; /* Number of processes in phase2 commit when we failed to pin */
-
GBLDEF zwr_hash_table *zwrhtab; /* How we track aliases during zwrites */
GBLDEF uint4 zwrtacindx; /* When creating $ZWRTACxxx vars for ZWRite, this holds xxx */
GBLDEF uint4 tstartcycle; /* lv_val cycle for tstart operations */
@@ -963,9 +897,7 @@ GBLDEF mval *alias_retarg; /* Points to an alias return arg created by a "QUI
#ifdef DEBUG_ALIAS
GBLDEF boolean_t lvmon_enabled; /* Enable lv_val monitoring */
#endif
-
GBLDEF block_id gtm_tp_allocation_clue; /* block# hint to start allocation for created blocks in TP */
-
#ifdef UNIX
GBLDEF int4 gtm_zlib_cmp_level; /* zlib compression level specified at process startup */
GBLDEF int4 repl_zlib_cmp_level; /* zlib compression level currently in use in replication pipe.
@@ -975,12 +907,10 @@ GBLDEF int4 repl_zlib_cmp_level; /* zlib compression level currently in use in
GBLDEF zlib_cmp_func_t zlib_compress_fnptr;
GBLDEF zlib_uncmp_func_t zlib_uncompress_fnptr;
#endif
-
GBLDEF mlk_stats_t mlk_stats; /* Process-private M-lock statistics */
-
#ifdef UNIX
/* Initialized blockalrm, block_ttinout and block_sigsent can be used by all threads */
-GBLDEF boolean_t blocksig_initialized = FALSE; /* set to TRUE when blockalrm and block_sigsent are initialized */
+GBLDEF boolean_t blocksig_initialized; /* set to TRUE when blockalrm and block_sigsent are initialized */
GBLDEF sigset_t blockalrm;
UNIX_ONLY(GBLDEF sigset_t block_ttinout;)
GBLDEF sigset_t block_sigsent; /* block all signals that can be sent externally
@@ -988,17 +918,14 @@ GBLDEF sigset_t block_sigsent; /* block all signals that can be sent externally
GBLDEF char *gtm_core_file;
GBLDEF char *gtm_core_putenv;
#endif
-
#ifdef __MVS__
GBLDEF char *gtm_utf8_locale_object;
GBLDEF boolean_t gtm_tag_utf8_as_ascii = TRUE;
#endif
-
#ifdef GTM_CRYPT
LITDEF char gtmcrypt_repeat_msg[] = "Please look at prior messages related to encryption for more details";
GBLDEF boolean_t gtmcrypt_initialized; /* Set to TRUE if gtmcrypt_init() completes successfully */
GBLDEF char dl_err[MAX_ERRSTR_LEN];
-
GBLDEF gtmcrypt_init_t gtmcrypt_init_fnptr;
GBLDEF gtmcrypt_close_t gtmcrypt_close_fnptr;
GBLDEF gtmcrypt_hash_gen_t gtmcrypt_hash_gen_fnptr;
@@ -1008,20 +935,19 @@ GBLDEF gtmcrypt_getkey_by_hash_t gtmcrypt_getkey_by_hash_fnptr;
GBLDEF gtmcrypt_getkey_by_name_t gtmcrypt_getkey_by_name_fnptr;
GBLDEF gtmcrypt_strerror_t gtmcrypt_strerror_fnptr;
#endif /* GTM_CRYPT */
-
#ifdef DEBUG
/* Following definitions are related to white_box testing */
-GBLDEF boolean_t gtm_white_box_test_case_enabled = FALSE;
-GBLDEF int gtm_white_box_test_case_number = 0;
-GBLDEF int gtm_white_box_test_case_count = 0;
-GBLDEF int gtm_wbox_input_test_case_count = 0; /* VMS allows maximum 31 characters for external identifer */
-GBLDEF boolean_t stringpool_unusable = FALSE; /* Set to TRUE by any function that does not expect any of its function
+GBLDEF boolean_t gtm_white_box_test_case_enabled;
+GBLDEF int gtm_white_box_test_case_number;
+GBLDEF int gtm_white_box_test_case_count;
+GBLDEF int gtm_wbox_input_test_case_count; /* VMS allows maximum 31 characters for external identifer */
+GBLDEF boolean_t stringpool_unusable; /* Set to TRUE by any function that does not expect any of its function
* callgraph to use/expand the stringpool. */
-GBLDEF boolean_t stringpool_unexpandable = FALSE;/* Set to TRUE by any function for a small period when it has ensured
+GBLDEF boolean_t stringpool_unexpandable; /* Set to TRUE by any function for a small period when it has ensured
* enough space in the stringpool so it does not expect any more garbage
* collections or expansions.
*/
-GBLDEF boolean_t donot_INVOKE_MUMTSTART = FALSE; /* Set to TRUE whenever an implicit TSTART is done in gvcst_put/kill as
+GBLDEF boolean_t donot_INVOKE_MUMTSTART; /* Set to TRUE whenever an implicit TSTART is done in gvcst_put/kill as
* part of an explicit + trigger update. In this situation, we dont expect
* MUM_TSTART macro to be invoked at all (see skip_INVOKE_RESTART below
* for description on why this is needed). So we keep this debug-only
@@ -1030,7 +956,6 @@ GBLDEF boolean_t donot_INVOKE_MUMTSTART = FALSE; /* Set to TRUE whenever an impl
* an rts_error) checks it never gets invoked while this is set.
*/
#endif
-
GBLDEF boolean_t block_is_free; /* Set to TRUE if the caller wants to let t_qread know that the block it is
* attempting to read is actually a FREE block
*/
@@ -1038,7 +963,6 @@ GBLDEF int4 gv_keysize;
GBLDEF gd_addr *gd_header;
GBLDEF gd_binding *gd_map;
GBLDEF gd_binding *gd_map_top;
-
#ifdef GTM_TRIGGER
GBLDEF int4 gtm_trigger_depth; /* 0 if no trigger, 1 if inside trigger; 2 if inside nested trigger etc. */
GBLDEF int4 tstart_trigger_depth; /* gtm_trigger_depth at the time of the outermost "op_tstart"
@@ -1059,7 +983,7 @@ GBLDEF mval *dollar_ztdata,
dollar_ztslate = DEFINE_MVAL_STRING(MV_STR, 0, 0, 0, NULL, 0, 0),
gtm_trigger_etrap; /* Holds $ETRAP value for inside trigger */
GBLDEF int tprestart_state; /* When triggers restart, multiple states possible. See tp_restart.h */
-GBLDEF boolean_t skip_INVOKE_RESTART = FALSE; /* set to TRUE if caller of op_tcommit/t_retry does not want it to
+GBLDEF boolean_t skip_INVOKE_RESTART; /* set to TRUE if caller of op_tcommit/t_retry does not want it to
* use the INVOKE_RESTART macro (which uses an rts_error to trigger
* the restart) instead return code. The reason we dont want to do
* rts_error is that this is an implicit tstart situation where we
@@ -1081,15 +1005,13 @@ GBLDEF boolean_t explicit_update_repl_state; /* Initialized just before an expli
* Value stays untouched across nested trigger invocations.
*/
#endif
-
-GBLDEF boolean_t skip_dbtriggers = FALSE; /* Set to FALSE by default (i.e. triggers are invoked). Set to TRUE
+GBLDEF boolean_t skip_dbtriggers; /* Set to FALSE by default (i.e. triggers are invoked). Set to TRUE
* unconditionally by MUPIP LOAD as it always skips triggers. Also set
* to TRUE by journal recovery/update-process only when they encounter
* updates done by MUPIP LOAD so they too skip trigger processing. In the
* case of update process, this keeps primary/secondary in sync. In the
* case of journal recovery, this keeps the db and jnl in sync.
*/
-
GBLDEF boolean_t expansion_failed; /* used by string pool when trying to expand */
GBLDEF boolean_t retry_if_expansion_fails; /* used by string pool when trying to expand */
@@ -1099,7 +1021,7 @@ GBLDEF boolean_t mupip_exit_status_displayed; /* TRUE if mupip_exit has already
* invoked but we will still go through mur_close_files e.g. if exit is
* done directly without invoking mupip_exit).
*/
-GBLDEF boolean_t implicit_trollback = FALSE; /* Set to TRUE by OP_TROLLBACK macro before calling op_trollback. Set
+GBLDEF boolean_t implicit_trollback; /* Set to TRUE by OP_TROLLBACK macro before calling op_trollback. Set
* to FALSE by op_trollback. Used to indicate op_trollback as to
* whether it is being called from generated code (opp_trollback.s)
* or from C runtime code.
@@ -1109,9 +1031,7 @@ GBLDEF boolean_t ok_to_UNWIND_in_exit_handling; /* see gtm_exit_handler.c for co
GBLDEF boolean_t skip_block_chain_tail_check;
GBLDEF boolean_t in_mu_rndwn_file; /* TRUE if we are in mu_rndwn_file (holding standalone access) */
#endif
-
GBLDEF char gvcst_search_clue;
-
#ifdef UNIX
/* The following are replication related global variables. Ideally if we had a repl_gbls_t structure (like jnl_gbls_t)
* this would be a member in that. But since we dont have one and since we need to initialize this specificially to a
@@ -1139,18 +1059,15 @@ GBLDEF repl_conn_info_t *this_side, *remote_side;
GBLDEF seq_num gtmsource_save_read_jnl_seqno;
GBLDEF gtmsource_state_t gtmsource_state = GTMSOURCE_DUMMY_STATE;
#endif
-
GBLDEF boolean_t gv_play_duplicate_kills; /* A TRUE value implies KILLs of non-existent nodes will continue to
* write jnl records and increment the db curr_tn even though they dont
* touch any GDS blocks in the db (i.e. treat it as a duplicate kill).
* Set to TRUE for the update process & journal recovery currently.
* Set to FALSE otherwise.
*/
-
-GBLDEF boolean_t donot_fflush_NULL = FALSE; /* Set to TRUE whenever we dont want gtm_putmsg to fflush(NULL). BYPASSOK
+GBLDEF boolean_t donot_fflush_NULL; /* Set to TRUE whenever we dont want gtm_putmsg to fflush(NULL). BYPASSOK
* As of Jan 2012, mu_rndwn_all is the only user of this functionality.
*/
-
#ifdef UNIX
GBLDEF boolean_t jnlpool_init_needed; /* TRUE if jnlpool_init should be done at database init time (eg., for
* anticipatory freeze supported configurations). The variable is set
@@ -1159,11 +1076,25 @@ GBLDEF boolean_t jnlpool_init_needed; /* TRUE if jnlpool_init should be done at
GBLDEF boolean_t span_nodes_disallowed; /* Indicates whether spanning nodes are not allowed. For example,
* they are not allowed for GT.CM OMI and GNP. */
GBLDEF boolean_t argumentless_rundown;
-
GBLDEF is_anticipatory_freeze_needed_t is_anticipatory_freeze_needed_fnptr;
GBLDEF set_anticipatory_freeze_t set_anticipatory_freeze_fnptr;
+GBLDEF boolean_t is_jnlpool_creator;
+GBLDEF char gtm_dist[GTM_PATH_MAX]; /* Value of $gtm_dist env variable */
#endif
-
-GBLDEF boolean_t in_jnl_file_autoswitch; /* set to TRUE for a short window inside jnl_file_extend when we are about to
- * autoswitch; used by jnl_write.
+GBLDEF boolean_t in_jnl_file_autoswitch; /* Set to TRUE for a short window inside jnl_file_extend when we are about to
+ * autoswitch; used by jnl_write. */
+#ifdef GTM_PTHREAD
+GBLDEF pthread_t gtm_main_thread_id; /* ID of the main GT.M thread. */
+GBLDEF boolean_t gtm_main_thread_id_set; /* Indicates whether the thread ID is set. */
+GBLDEF boolean_t gtm_jvm_process; /* Indicates whether we are running with JVM or stand-alone. */
+#endif
+GBLDEF size_t gtm_max_storalloc; /* Maximum that GTM allows to be allocated - used for testing */
+#ifdef VMS
+GBLDEF sgmnt_addrs *vms_mutex_check_csa; /* On VMS, mutex_deadlock_check() is directly called from mutex.mar. In
+ * order to avoid passing csa parameter from the VMS assembly, we set this
+ * global from mutex_lock* callers.
+ */
+#endif
+GBLDEF boolean_t ipv4_only; /* If TRUE, only use AF_INET.
+ * Reflects the value of the gtm_ipv4_only environment variable, so is process wide.
*/
diff --git a/sr_port/gde.hlp b/sr_port/gde.hlp
index 50a1a96..150c735 100644
--- a/sr_port/gde.hlp
+++ b/sr_port/gde.hlp
@@ -1,219 +1,593 @@
-
1 Overview
- GDE Overview
- The GT.M Global Directory Editor, GDE, is a tool for creating,
- examining, and modifying Global Directories (GDs). A Global Directory
- is a file that identifies:
+ Overview
+
+ The GT.M Global Directory Editor (GDE) is a utility that enables you to
+ create, examine, and modify a global directory. GDE is a program written
+ in M and you can invoke it from the shell with $gtm_dist/mumps -run ^GDE,
+ with the gtm alias gtm -run GDE, or from inside the direct mode with Do
+ ^GDE.
+
+ **Note**
+
+ The input to GDE can be a text file. In a production environment, FIS
+ recommends using text files to define database configurations, and putting
+ these text files under version control.
+
+ A global directory stores database attributes and mapping rules. The
+ mapping rules are like a sieve for globals that determines which database
+ files hold which global names. The database attributes serve as a
+ blueprint that MUPIP CREATE uses to create new database file(s). Once a
+ database file is created, GT.M continues to use the global directory as a
+ sieve. However, once MUPIP CREATE applies the database attributes
+ (blueprint) to create a database file, GT.M does not use the blueprint
+ until the next MUPIP CREATE. Therefore, if you use MUPIP SET (or DSE) to
+ change the attributes of a database file, always perform an equivalent
+ change to any global directory used for a subsequent MUPIP CREATE.
+
+2 Identifying_the_Current_Global_Directory
+ Identifying the Current Global Directory
+
+ GT.M identifies the current Global Directory by referring to the
+ environment variable gtmgbldir. GDE, MUPIP, LKE, DSE, and the GT.M
+ run-time system use this environment variable. The run-time system
+ normally uses this environment variable, but may also access a Global
+ Directory by setting $ZGBLDIR or by using the extended global reference ||
+ or {} syntax.
+
+ If you maintain multiple Global Directories, define gtmgbldir to point to
+ the currently active Global Directory. You may want to define gtmgbldir in
+ your login file. Note that this definition is a pathname. If it does not
+ start with a "/", then it is a relative pathname and GT.M searches for it
+ starting in the current working directory.
+
+ To change the current Global Directory assignment, specify a new
+ definition for gtmgbldir.
+
+ Example:
- o What global variables go to what database files
+ $ gtmgbldir=prod.gld
+ $ export gtmgbldir
- o The size limits for names and values of global variables
+2 Creating_a_Default_Global_Directory
+ Creating a Default Global Directory
- o Other database characteristics
+ When you invoke GDE and no Global Directory exists for gtmgbldir, GDE
+ produces a default Global Directory that contains a minimal set of
+ required components and values for database characteristics. It can be
+ used for purposes such as development and testing work. A default Global
+ Directory also serves as a starting point or template for building custom
+ global directories.
- o If and what type of journaling should take place
+ To retain this default Global Directory, exit GDE without making any
+ changes.
- All MUMPS programs that use the same Global Directory share all the
- same global variables, unless the Global Directory uses environment
- variables for which users have varying definitions. The local
- variables are accessible only among programs executed within a single
- process scope.
+ Example:
+
+ $ gtmgbldir=./mumps.gld
+ $ export gtmgbldir
+ $ gtm
+ GTM>d ^GDE
+ %GDE-I-GDUSEDEFS, Using defaults for Global Directory
+ /usr/accntg/jones/mumps.gld
+ GDE> EXIT
+ %GDE-I-VERIFY, Verification OK
+ %GDE-I-GDCREATE, Creating Global Directory file
+ /usr/accntg/jones/mumps.gld
+
+2 Mapping_Global_Variables_in_a_Global_Directory
+ Mapping Global Variables in a Global Directory
+
+ Mapping is the process of connecting a global variable name to a database
+ file.
-2 Functions
- GDE Functions
- The main functions of the Global Directory Editor are to:
+ A complete mapping has the following four components:
- o Define the mapping of global variables to database files
+ o NAME
+ o REGION
+ o SEGMENT
+ o FILE
- o Define the character limitations of global variable names and
- records
+ These components may be defined in any order, but the final result must be
+ a complete logical path from name to file:
- o Provide the MUMPS Peripheral Interchange Program (MUPIP) with
- characteristics (e.g., -ALLOCATION size) used in creating and
- extending a database file
+ NAME(s) ---> REGION ---> SEGMENT ---> FILE
- o Define whether a database file should be journaled and how
+ The default Global Directory contains one complete mapping that comprises
+ these entries for name, region, segment, and file.
+
+ * ---> DEFAULT ---> DEFAULT ---> mumps.dat
+ (NAME) (REGION) (SEGMENT) (FILE)
+
+ The * wildcard identifies all possible global names. Subsequent edits
+ create entries for individual global names or name prefixes.
+
+ Regions and segments store information used to control the creation of the
+ file. The characteristics stored with the region and segment are passed to
+ MUPIP only when creating the database file using the CREATE command, so
+ subsequent changes to these characteristics in the Global Directory have
+ no effect on an existing database.
+
+ When you create a new mapping, GDE ensures that it has all these
+ components by refusing to complete the EXIT command until all components
+ of the mapping exist. Informational messages inform you of any missing or
+ extra components.
+
+2 Examining_the_Default_Global_Directory
+ Examining the Default Global Directory
+
+ The default Global Directory looks like this:
+
+ *** TEMPLATES ***
+ Std Inst
+ Def Rec Key Null Null Freeze Qdb
+ Region Coll Size Size Subs Coll Jnl on Error Rndwn
+ ----------------------------------------------------------------------------------------------------
+ <default> 0 4080 255 NEVER Y Y DISABLED DISABLED
+ 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
+ LOCK = 40
+ RES = 0
+ ENCR = OFF
+ <default> MM DYN 4096 5000 10000 DEFER
+ LOCK = 40
+
+ *** NAMES ***
+ Global Region
+ ------------------------------------------------------------------------------
+ * DEFAULT
+
+ *** REGIONS ***
+ Std Inst
+ Dynamic Def Rec Key Null Null Freeze Qdb
+ Region Segment Coll Size Size Subs Coll Jnl on Error Rndwn
+ -----------------------------------------------------------------------------------------------------------------
+ DEFAULT DEFAULT 0 4080 255 NEVER Y Y DISABLED DISABLED
+
+ *** JOURNALING INFORMATION ***
+ Region Jnl File (def ext: .mjl) Before Buff Alloc Exten AutoSwitch
+ --------------------------------------------------------------------------------------------------------
+ DEFAULT $gtmdir/$gtmver/g/gtm.mjl
+ Y 2308 2048 2048 8386560
+
+ *** SEGMENTS ***
+ Segment File (def ext: .dat)Acc Typ Block Alloc Exten Options
+ -------------------------------------------------------------------------------------------
+ DEFAULT $gtmdir/$gtmver/g/gtm.dat
+ BG DYN 4096 5000 10000 GLOB=1000
+ LOCK= 40
+ RES = 0
+ ENCR=OFF
+
+ *** MAP ***
+ - - - - - - - - - - Names - - - - - - - - - -
+ From Up to Region / Segment / File(def ext: .dat)
+ --------------------------------------------------------------------------------------------------------
+ % ... REG = DEFAULT
+ SEG = DEFAULT
+ FILE = $gtmdir/$gtmver/g/gtm.dat
+ LOCAL LOCKS REG = DEFAULT
+ SEG = DEFAULT
+ FILE = $gtmdir/$gtmver/g/gtm.dat
+ GDE>
+
+ There are five primary sections in a Global Directory:
+
+ o TEMPLATES
+ o NAMES
+ o REGIONS
+ o SEGMENTS
+ o MAP
+
+ The function of each section in the Global Directory is described as
+ follows:
+
+ TEMPLATES
+
+ This section of the Global Directory provides a default value for every
+ database or file parameter passed to GT.M as part of a region or segment
+ definition. GDE uses templates to complete a region or segment definition
+ where one of these necessary values is not explicitly defined.
+
+ GDE provides initial default values when creating a new Global Directory.
+ You can then change any of the values using the appropriate -REGION or
+ -SEGMENT qualifiers with the TEMPLATE command.
+
+ NAMES
+
+ An M program sees a monolithic global variable name space. The NAMES
+ section of the Global Directory partitions the name space so that
+ different globals reside in different files. While each M global can
+ reside in only one file, each file can store many M globals.
+
+ REGIONS
+
+ The REGIONS section lists all of the regions in the Global Directory. Each
+ region defines common properties for all the M global variables;
+ therefore, multiple sets of names from the NAMES section map onto a single
+ region.
+
+ You assign these values by specifying the appropriate qualifier when you
+ create or modify individual regions. If you do not specify a value for a
+ particular parameter, GDE assigns the default value from the TEMPLATES
+ section.
+
+ SEGMENTS
+
+ This section of the Global Directory lists currently defined segments.
+ While regions specify properties of global variables, segments specify the
+ properties of files. There is a one-to-one mapping between regions and
+ segments. You assign these values by specifying the appropriate qualifier
+ when you create or modify individual segments. If you do not specify a
+ value for a particular parameter, GDE assigns the default value from the
+ TEMPLATES section.
+
+ MAP
+
+ This section of the Global Directory lists the current mapping of names to
+ region to segment to file. In the default Global Directory, there are two
+ lines in this section: one specifies the destination for all globals, the
+ other one is for local locks. If you add any new mapping component
+ definitions (that is, any new names, regions, or segments), this section
+ displays the current status of that mapping. Any components of the mapping
+ not currently defined display "NONE". Because GDE requires all elements of
+ a mapping to be defined, you will not be able to EXIT (and save) your
+ Global Directory until you complete all mappings.
+
+2 Global_Directory_Abbreviations
+ Global Directory Abbreviations
+
+ GDE uses the following abbreviations to display the output of a global
+ directory. The following list show global directory abbreviations with the
+ associated qualifiers. For a description of the function of individual
+ qualifiers, see "GDE Command Summary".
+
+ Abbreviation Full Form
+ Acc ACCESS_METHOD
+ Alloc ALLOCATION
+ AutoSwitch AUTOSWITCHLIMIT
+ Block BLOCK_SIZE
+ Buff BUFFER_SIZE
+ Def Coll COLLATION_DEFAULT
+ Exten EXTENSION_COUNT
+ File FILE_NAME
+ GLOB GLOBAL_BUFFER_COUNT
+ Inst Freeze On Error INST_FREEZE_ON_ERROR
+ JNL JOURNAL
+ KeySize KEY_SIZE
+ LOCK LOCK_SPACE
+ Null Subs NULL_SUBSCRIPTS
+ Qdb Rndwn QDBRUNDOWN
+ Std Null Coll STDNULLCOLL
+ Rec Size RECORD_SIZE
+ RES RESERVED_BYTES
+ Region REGION
+ Typ DYNAMIC_SEGMENT
- o Define the -ACCESS_METHOD used to access the database files and
- other database characteristics
+2 Customizing_a_Global_Directory
+ Customizing a Global Directory
-2 Mapping
- Mapping
- Defining a "map," i.e., where GT.M stores a global variable,
- requires defining, not only the NAME of the global variable and the
- database FILE in the Global Directory, but also the REGION and
- SEGMENT.
+ Once you have installed GT.M and verified its operation, create a Global
+ Directory based on your needs. To create this customized Global Directory,
+ use the appropriate GDE commands and qualifiers to build the desired
+ Global Directory. The GDE commands are described later in this chapter.
- A REGION is a logical structure that holds information such as key-
- and record-size about a portion of a database. GT.M and the
- operating system handle data stored in a REGION together by storing
- it in the same place or places, backing it up as a unit, etc. A
- REGION must map to a SEGMENT.
+ You can also create a text file of GDE commands with a standard text
+ editor and process this file with GDE. In a production environment, this
+ gives better configuration control than interactive usage with GDE.
- A SEGMENT defines additional database storage characteristics not
- required for UNIX files. A SEGMENT must map to a FILE. The SEGMENT
- exists primarily for future design considerations, when a
- one-to-one correspondence between the REGION and SEGMENT will no
- longer be required.
+3 Adding_a_Journaling_Information_Section
+ Adding a Journaling Information Section
- The connection in the map between a name and a file is very
- important and is used by the run-time system and most GT.M
- utilities. Specifying a map requires entering (a) NAME(S) with a
- connection to a REGION, a REGION with a connection to a SEGMENT,
- and a SEGMENT with a connection to a database file. The commands
- may be issued in any order, but the final result must be a complete
- logical path from name to file.
+ If you select the -JOURNAL option when you ADD or CHANGE a region in a
+ Global Directory, the following section is added to your Global Directory
+ and displays when you invoke SHOW. The columns provided display the values
+ you selected with the journal options, or defaults provided by FIS for any
+ options not explicitly defined.
- NAME(s) ---> REGION ---> SEGMENT ---> FILE
+ *** JOURNALING INFORMATION ***
+ Region Jnl File (def ext: .mjl) Before Buff Alloc Exten AutoSwitch
+ ------------------------------------------------------------------------------------------
+ DEFAULT $gtmdir/$gtmver/g/gtm.mjl
+ Y 2308 2048 2048 8386560
-2 Default_GD
- Creating a Default Global Directory
- The Global Directory Editor creates a quick default Global
- Directory for purposes such as development and testing work. A
- default Global Directory also serves as a starting point or
- template for a custom Global Directory.
-
- To create a default Global Directory structure, invoke and
- immediately EXIT GDE. GDE creates a Global Directory mapping of all
- NAMEs to the REGION DEFAULT, the default REGION to the SEGMENT
- DEFAULT and the default SEGMENT to the default file-name MUMPS with
- the default file extension of .DAT.
-
-2 Custom_GD
- Creating a Custom Global Directory
- When a default Global Directory does not meet your needs, you need
- to customize a Global Directory. Usually you customize the Global
- Directory when you define your production database file. This
- enables you to optimize the sharing and location of your data.
-
- To create a custom Global Directory, invoke GDE and issue the
- commands necessary to build the desired Global Directory. For more
- information about mapping, refer to the "How to Map Global
- Variables" section.
-
-2 GTM$GBLDIR
- Defining the gtmgbldir Environment Variable
- GT.M identifies the current Global Directory by the environment
- variable gtmgbldir. GDE, MUPIP, LKE, DSE and the GT.M run-time
- system use this environment variable to identify the file used as
- the Global Directory. The run-time system normally uses this
- environment variable, but may also access a Global Directory by
- setting $ZGBLDIR or the extended global reference ([]) syntax.
-
- If you maintain multiple Global Directories, define gtmgbldir to
- the Global Directory you currently want to use. You may want to
- define gtmgbldir in your login file.
-
- Example
+1 Using_GDE
+ Using GDE
- $ gtmgbldir=prod.gld
- $ export gtmgbldir
+ The default installation procedure places the GDE utility into a directory
+ assigned to the environment variable gtm_dist.
+
+ To invoke GDE:
+
+ from within GTM, use the command:
+
+ GTM>do ^GDE
+
+ from the shell, enter:
+
+ $ mumps -r GDE
+
+ GDE displays informational messages like the following, and then the GDE>
+ prompt:
+
+ %GDE-I-LOADGD, loading Global Directory file /prod/mumps.gld
+ %GDE-I-VERIFY, Verification OK
+ GDE>
+
+ If this does not work, contact your system manager to investigate setup
+ and file access issues.
+
+ To leave GDE:
+
+ 1. Use the GDE EXIT command to save all changes and return to the shell.
+
+ GDE> EXIT
+
+ 2. Use the GDE QUIT command to discard all changes and return to the
+ shell. This will not save any changes.
+
+ GDE> QUIT
+
+2 Guidelines_for_Mapping
+ Guidelines for Mapping
+
+ This section lists the parameters that apply to defining each component of
+ a mapping.
+
+ NAME
+
+ The name is the portion of the global variable name without subscripts.
+ More than one name can map to a single region, but a single name can only
+ map to one region.
+
+ A name:
+
+ o Maps to only one region in the Global Directory.
+ o Is case sensitive.
+ o Must begin with an alphabetic character or a percent sign (%).
+ o Can be one to 31 alphanumeric characters.
+ o Can be a discrete "global" name, for example, aaa corresponds to the
+ global variable ^aaa.
+ o Can be a partial name ending with a wild card ("*"), for example, abc*
+ represents all globals beginning with the letters ^abc.
+
+ REGION
+
+ A region is a logical structure that holds information about a portion of
+ a database, such as key-size and record-size. A key is the internal
+ representation of a global variable name. In this chapter the terms global
+ variable name and key are used interchangeably. A record refers to a key
+ and its data.
+
+ A Global Directory must have at least one region. A region only maps to a
+ single segment. More than one name may map to a region.
+
+ A region name:
+
+ o Can include alphanumerics, dollar signs ($), and underscores ( _ ).
+ o Can have from 1 to 16 characters.
+
+ GDE automatically converts region names to uppercase, and uses DEFAULT for
+ the default region name.
+
+ SEGMENT
+
+ A segment defines file-related database storage characteristics. A segment
+ must map to a single file. A segment can be mapped by only one region.
+
+ GT.M uses a segment to define a physical file and access method for the
+ database stored in that file.
+
+ A segment-name:
+
+ o Can include alphanumerics, dollar signs ($), and underscores ( _ )
+ o Can have from one to 16 characters
+
+ GDE automatically converts segment names to uppercase. GDE uses DEFAULT
+ for the default segment name.
+
+ FILE
+
+ Files are the structures provided by UNIX for the storage and retrieval of
+ information. Files used by GT.M must be random-access files resident on
+ disk.
+
+ By default, GDE uses the file-name mumps.dat for the DEFAULT segment. GDE
+ adds the .dat to the file name when you do not specify an extension.
+ Generally, avoid non-graphic and punctuation with potential semantic
+ significance to the file system in file names as they tend to produce
+ operational difficulties.
+
+3 Example_of_a_Basic_Mapping
+ Example of a Basic Mapping
+
+ To complete this procedure, you must have already opened a Global
+ Directory.
+
+ o ADD a new global variable name.
+
+ GDE> add -name cus -region=cusreg
+
+ This maps the global name cus to the region cusreg.
+
+ o ADD region cusreg, if it does not exist.
+
+ GDE> add -region cusreg -d=cusseg
+
+ This creates the region cusreg and connects it to the segment cusseg.
+ -d[ynamic] is a required qualifier that takes the associated
+ segment-name as a value.
+
+ o ADD segment cusreg, if it does not exist, and link it to a file.
+
+ GDE> add -segment cusseg -file=cus
+
+ This creates the segment cusseg and connects it to the file cus.dat.
+
+ To review the information you have added to the Global Directory, enter
+ the command SHOW.
+
+ To perform a base consistency check in the configuration, enter the
+ command VERIFY.
+
+ To exit the Global Directory and save your changes, enter the command
+ EXIT. At this point, GDE performs an automatic verification. If
+ successfully confirmed, the mappings and database specifications become
+ part of the Global Directory, available for access by processes,
+ utilities, and the run-time system.
+
+ Only MUPIP CREATE uses the database specifications; run-time processes and
+ other utility functions use only the map and ignore the other information
+ in a global directory.
+
+1 Commands
+ Commands
+
+ This section describes the GDE commands. GDE allows abbreviations of
+ commands. The section describing each command provides the minimum
+ abbreviation for that command and a description of any qualifiers that are
+ not object-related. The section discussing the object-type describes all
+ the associated object-related qualifiers.
+
+ Command Syntax:
-1 Command_syntax
- Command Syntax
The general format for GDE commands is:
- command [-object-type] [object-name] [-qualifier...]
- ex: -NAME Name-space -region-qualifier...
- -REGION Region-name -region-qualifier...
- -SEGMENT Segment-name -segment-qualifier...
+ command [-object-type] [object-name] [-qualifier]
where:
- Object-type Indicates whether the command operates on a
- -N[AME],
- - R[EGION] or -S[EGMENT].
+ -object-type
- Object-name Specifies the name of a N[AME] space, R[EGION] or
- S[EGMENT]. Object-names of different types may
- have the same name.
+ Indicates whether the command operates on a -N[AME] space,
+ -R[EGION], or -S[EGMENT].
- Name-space Specifies a name or name prefix that maps to a
- REGION. Names may include the wildcard operator *
- as a suffix.
+ object-name
- Region-name Specifies a REGION name.
+ Specifies the name of the N[AME] space, R[EGION], or S[EGMENT].
+ Objects of different types may have the same name. Name spaces may
+ include the wildcard operator (*) as a suffix.
- Segment-name Specifies a SEGMENT name.
+ -qualifier
- Qualifier Indicates a command or object qualifier.
+ Indicates an object qualifier.
- The format for each command specifies required qualifiers for the
- command.
+ The format description for each individual command specifies required
+ qualifiers for that command.
+
+ The @, EXIT, HELP, LOG, QUIT, SETGD, and SPAWN commands do not use this
+ general format. For the applicable format, refer to the section explaining
+ each of these commands.
+
+ Comments on the command line may be delimited by an exclamation mark (!).
- The @, EXIT, HELP, LOG, QUIT and SPAWN commands do not use this
- general format. For the applicable format, refer to the section
- explaining each of these commands.
+ **Caution**
- Comments on the command line may be delimited by an exclamation mark
- (!). An exclamation mark not enclosed in quotes (") causes GDE to
- ignore the rest of the input line.
+ An exclamation mark not enclosed in quotation marks ("") causes GDE to
+ ignore the rest of that input line.
-1 at-sign
- @
- The @ command executes a GDE command file. Use the @ command to run
- stored GDE command sequences from an interactive session.
+2 at-sign
+ at-sign
+
+ The @ command executes a GDE command file. Use the @ command to execute
+ GDE commands stored in a text file.
The format of the @ command is:
- @ file-name
+ @file-name
- The file-name specifies the command file to execute. GDE provides the
- default file extension ".COM" in creating the file-name.
+ The file-name specifies the command file to execute. Use the file-name
+ alone for a file in the current working directory, or specify the relative
+ path, or the full path.
- GDE executes each line of the command file as if the line had been
- typed at the terminal.
+ GDE executes each line of the command file as if it were entered at the
+ terminal.
- Example
+ Example:
GDE> @standard
- This command transfers the GDE input to STANDARD.COM in the current
- default directory. STANDARD.COM should contain GDE commands; any
- comments should start with an exclamation mark (!).
+ This command executes the GDE commands in the file to standard in the
+ current working directory. standard should contain GDE commands; comments
+ should start with an exclamation mark (!).
+
+2 Add
+ Add
-1 ADD
- A[DD]
- The ADD command inserts a new NAME, REGION, or SEGMENT into the Global
+ The ADD command inserts a new name, region, or segment into the Global
Directory.
- The format of the ADD command is:
+ The format of the ADD command is one of the f ollowing:
- A[DD]-N[AME] name-space -R[EGION]=region-name
- A[DD]-R[EGION] region-name -D[YNAMIC]=segment-name [-region-qual...]
- A[DD]-S[EGMENT] segment-name -F[ILE_NAME]=file-name [-segment-qual...]
+ A[DD]-N[AME] name-space -R[EGION]=region-name
+ A[DD]-R[EGION] region-name -D[YNAMIC]=segment-name [-REGION-qualifier...]
+ A[DD]-S[EGMENT] segment-name [-SEGMENT-qualifier...] -F[ILE_NAME]=file-name
- The ADD command requires specification of an object-type and
- object-name. GDE supplies default values for qualifiers not supplied.
+ The ADD command requires specification of an object-type and object-name.
+ GDE supplies default values from the templates for qualifiers not
+ explicitly supplied in the command.
- Name-spaces and file namesare case-sensitive while other objects are
- not.
+ Name spaces and file-names are case-sensitive; other objects are not
+ case-sensitive.
-1 CHANGE
- C[HANGE]
- The CHANGE command alters the NAME to REGION or REGION to SEGMENT
- mapping and the environment for a REGION or SEGMENT.
+ Example:
+
+ GDE> add -segment temp -file_name=scratch
+
+ This command creates a segment-name TEMP and maps it to the file
+ scratch.dat in the current working directory. However, if you specify
+ scratch is as the file-name, in other words specify it in the form of an
+ environment variable, GT.M finds the file using the translation of that
+ environment variable.
+
+2 Change
+ Change
+
+ The CHANGE command alters the name-to-region or region-to-segment mapping
+ and /or the environment for a region or segment.
The format of the CHANGE command is:
- C[HANGE]-N[AME] name-space -R[EGION]=new-region
- C[HANGE]-R[EGION] region-name [-region-qualifier...]
- C[HANGE]-S[EGMENT] segment-name [-segment-qualifier...]
+ C[HANGE]-N[AME] name-space -R[EGION]=new-region
+ C[HANGE]-R[EGION] region-name [-REGION-qualifier...]
+ C[HANGE]-S[EGMENT] segment-name [-SEGMENT-qualifier...]
- The CHANGE command requires specification of an object-type and
+ The CHANGE command requires specification of an object-type and
object-name.
- Changes to the database environment characteristics take effect the
- next time you create a new file with the MUPIP CREATE command. Mapping
- changes take effect for subsequent image activation, for example
- following the next RUN or MUMPS-DIRECT command.
+ Once you exit GDE, mapping changes take effect for any subsequent image
+ activation (for example, the next RUN or the mumps -direct command).
+ Changes to database parameters only take effect for new database files
+ created with subsequent MUPIP CREATE commands that use the modified Global
+ Directory. Use the MUPIP SET command (or in some cases DSE) to change
+ characteristics of existing database files.
+
+ Example:
-1 DELETE
- D[ELETE]
- The DELETE command removes a NAME, REGION, or SEGMENT from the Global
- Directory. The DELETE command does not delete the actual data from the
- database but can make the data inaccessible to MUMPS images using the
- resulting directory.
+ GDE> change -region master -dynamic=temp -key=100
+
+ This command changes the region master to use the segment temp and
+ establishes a maximum KEY_SIZE of 100 characters for the next creation of
+ a file for this region. The segment change takes effect the first time the
+ system uses the Global Directory after the GDE session EXITs, while the
+ KEY_SIZE change takes effect after the next MUPIP CREATE that creates a
+ new database file for segment temp.
+
+2 Delete
+ Delete
+
+ The DELETE command removes a name, region, or segment from the Global
+ Directory. The DELETE command does not delete any actual data. However,
+ GT.M does not access database files that do not have mapped global
+ variables except through extended references using an alternative global
+ directory that does not map to them. Note that GT.M replication does not
+ support global updates made with extended references, unless they actually
+ map to the same file as they would with the master global directory of the
+ instance.
The format of the DELETE command is:
@@ -221,77 +595,99 @@
D[ELETE]-R[EGION] region-name
D[ELETE]-S[EGMENT] segment-name
- The DELETE command requires specification of an object-type and
+ The DELETE command requires specification of an object-type and
object-name.
- Deleting a NAME removes the NAME to REGION mapping. Deleting a REGION
- unmaps all NAMES mapped to the REGION. Deleting a SEGMENT unmaps the
- REGION mapped to the SEGMENT.
+ Deleting a name removes the name-to-region mapping. Deleting a region
+ unmaps all names mapped to the region. Deleting a segment unmaps the
+ region mapped to the segment.
+
+ You may map the deleted names to another region or the deleted region to
+ another segment using the CHANGE command.
- Map the deleted names to another REGION or the deleted REGION to
- another SEGMENT using the CHANGE command.
- The default name-space (*) can not be deleted.
+ The default name-space (*) cannot be deleted.
-1 EXIT
- E[XIT]
- The EXIT command writes all changes made in the current GDE editing
- session to the Global Directory.
+ Example:
+
+ GDE> del -name T*
+
+ This command deletes the explicit mapping of all global names starting
+ with the letter "T." This command does not delete any global variables.
+ However, it may make preexisting globals starting with the letter "T"
+ invisible, at least while using this global directory, because the T*
+ global names map to the default namespace going forward.
+
+2 Exit
+ Exit
+
+ The EXIT command writes all changes made in the current GDE editing
+ session to the Global Directory and terminates the current editing
+ session.
The format of the EXIT command is:
E[XIT]
- GDE performs a full verification test (VERIFY) on the data. If the
- verification succeeds, GDE writes the new Global Directory to disk and
- issues a verification message.
+ GDE performs a full verification test (VERIFY) on the data. If the
+ verification succeeds, GDE writes the new Global Directory to file system
+ and issues a verification message.
- If the verification fails, GDE displays a listing of all unverifiable
- mappings and waits for corrections. Make appropriate corrections or
- leave the Global Directory in its original, unedited state by using
- the QUIT command.
+ If the verification fails, GDE displays a listing of all unverifiable
+ mappings and waits for corrections. Make appropriate corrections, or leave
+ the Global Directory in its original, unedited state by using the QUIT
+ command.
+
+ If you have not made any changes to the Global Directory, GDE does not
+ save a new Global Directory unless the original global directory had an
+ older format which GDE has automatically upgraded. Note that while GDE
+ upgrades older global directories to the current version, there is no
+ facility to downgrade global directories to prior versions, so you should
+ always save copies of any global directories that might be needed to
+ retrieve archival data.
- If you have not made any changes to the Global Directory, GDE does not
- create a new Global Directory.
+2 Help
+ Help
-1 HELP
- H[ELP]
- The HELP command explains the GDE commands. The format of the HELP
- command is:
+ The HELP command displays online information about GDE commands and
+ qualifiers.
- HE[LP] [keyword...]
+ The format of the HELP command is:
- Specify the GDE command for which you want information at the Topic
- prompt. The help facility also provides an "Overview."
+ H[ELP] [topic...]
- Use <RETURN> or <CTRL Z> to return to the GDE prompt.
+ where topic specifies the GDE command for which you want information. If
+ you omit the topic, GDE prompts you for it.
-1 LOCKS
- LOC[KS]
- The LOCKS command specifies the REGION into which GT.M maps locks on
- names not starting with ^. GDE maps locks on global names (starting
- with ^) to the region of the database specified for that name.
+2 LOCks
+ LOCks
+
+ The LOCKS command specifies the region into which GT.M maps locks on
+ resource names not starting with a caret symbol (^). GDE maps locks on
+ resource names, starting with a caret symbol (^), to the database region
+ mapped for the global variable name matching the resource name.
The format of the LOCKS command is:
LOC[KS] -R[EGION]=region-name
- The LOCK -REGION= qualifier allows specification of a region for local
+ The LOCKS -REGION= qualifier allows specification of a region for local
locks. By default, GDE maps local locks to the default region DEFAULT.
+ Example:
- Example
+ GDE> lock -region=main
- GDE> LOCK-REGION=MAIN
+ This command maps all locks on resource names that don't start with the
+ caret symbol, "^" to the region main.
- This command maps all locks on resource names that don't start with
- "^" to region MAIN.
+2 LOG
+ LOG
-1 LOG
- LOG
- The LOG command creates a log file of all GDE commands and displays
- for the current editing session. Because the system places an
- exclamation point (i.e., the comment symbol) before all display lines
- in the log, a log can be used with the @ sign as a command procedure.
+ The LOG command creates a log file of all GDE commands and displays for
+ the current editing session. Because the system places an exclamation
+ point (!) (i.e., the comment symbol) before all display lines that are not
+ entered by the user. In the log, the log can be used with the @ symbol as
+ a command procedure.
The format of the LOG command is:
@@ -299,152 +695,238 @@
LOG -ON[=file-name]
LOG -OF[F]
- The LOG command without a qualifier reports the current status of GDE
- logging. The LOG command displays a message showing whether logging is
- in effect and the specification of the current log file for the GDE
- session.
+ The LOG command, without a qualifier, reports the current status of GDE
+ logging. The LOG command displays a message showing whether logging is in
+ effect and the specification of the current log file for the GDE session.
- The log facility can be turned on and off using the -ON or -OFF
- qualifiers any time during a GDE session. However, GDE closes the log
- files only when the GDE session ends.
+ The log facility can be turned on and off using the -ON or -OFF qualifiers
+ any time during a GDE session. However, GDE closes the log files only when
+ the GDE session ends.
- The -ON qualifier has an optional argument of a file-name, which must
- identify a legal UNIX file. GDE uses the default file extension
- ".LOG". If LOG -ON has no file-name argument, GDE uses the previous
- log file for the editing session. If no log file has previously been
- specified during this editing session, GDE uses the default log file
+ The -ON qualifier has an optional argument of a file, which must identify
+ a legal UNIX file. If LOG -ON has no file-argument, GDE uses the previous
+ log file for the editing session. If no log file has previously been
+ specified during this editing session, GDE uses the default log file
GDELOG.LOG.
-1 QUIT
- Q[UIT]
- The QUIT command ends the current editing session without saving any
- changes to the Global Directory. GDE does not create an updated Global
- Directory file.
+ Example:
+
+ GDE> log -on="standard.log"
+
+ This command turns on logging of the session and directs the output to
+ standard.log.
+
+2 Quit
+ Quit
+
+ The QUIT command ends the current editing session without saving any
+ changes to the Global Directory. GDE does not update the Global Directory
+ file.
The format of the QUIT command is:
Q[UIT]
- If the session made changes to the Global Directory, GDE issues a
- message warning that the Global Directory has not been updated.
+ If the session made changes to the Global Directory, GDE issues a message
+ warning that the Global Directory has not been updated.
+
+2 Rename
+ Rename
-1 RENAME
- R[ENAME]
- The RENAME command allows changes of a NAME, the name of a REGION or
- the name of a SEGMENT.
+ The RENAME command allows you to change a name-space, the name of a
+ region, or the name of a segment.
The format of the RENAME command is:
R[ENAME]-N[AME] old-name new-name
- R[ENAME]-R[EGION] old-reg-name new-reg-name
- R[ENAME]-S[EGMENT] old-seg-name new-seg-name
+ R[ENAME]-R[EGION] old-region-name new-region-name
+ R[ENAME]-S[EGMENT] old-segment-name new-segment-name
- The RENAME command requires specification of an object-type and two
+ The RENAME command requires specification of an object-type and two
object-names.
- When renaming a REGION, GDE transfers all NAME mappings to the new
- REGION. When renaming a SEGMENT, GDE transfers the REGION mappings to
- the new SEGMENT.
+ When renaming a region, GDE transfers all name mappings to the new region.
+ When renaming a segment, GDE transfers the region mapping to the new
+ segment.
+
+ Example:
+
+ GDE> rename -segment stable table
+
+ This command renames segment stable to table and shifts any region mapped
+ to stable so it is mapped to table.
-1 SETGD
- SE[TGD]
- The SETGD command closes out edits on one Global Directory and opens
- edits on another.
+2 SEtgd
+ SEtgd
+
+ The SETGD command closes out edits on one Global Directory and opens edits
+ on another.
The format of the SETGD command is:
SE[TGD] -F[ILE]=file-name [-Q[UIT]]
- The -FILE=file-name qualifier identifies the new Global Directory.
- When you provide a partial file-name, GDE uses the current default
- directory and defaults the type to .GLD.
+ The -FILE=file-name specifies a different Global Directory file. When you
+ provide a file-name without a full or relative pathname GDE uses the
+ current working directory; if the file is missing an extension, then GDE
+ defaults the type to .gld.
+
+ The -QUIT qualifier specifies that any changes made to the current Global
+ Directory are not written and are lost when you change Global Directories.
+
+ SETGD changes the Global Directory that GDE is editing. If the current
+ Global Directory has not been modified, or the -QUIT qualifier appears in
+ the command, the change simply occurs. However, if the current Global
+ Directory has been modified, GDE verifies the Global Directory, and if the
+ verification is successful, writes that Global Directory. If the
+ verification is not successful, the SETGD fails.
+
+ Example:
+
+ GDE> SETGD -f="temp"
- The -QUIT qualifier specifies that any changes that have been made to
- the current Global Directory are not written, i.e., are lost, during
- the change of Global Directory.
+ This changes the Global Directory being edited to temp. The quotation
+ marks around the file name identifies the name of the file unequivocally
+ to UNIX. If the -f is the final qualifier on the line, then the quotation
+ marks are unnecessary.
- A SETGD changes the Global Directory on which the GDE edits act. If
- the current Global Directory has not been modified or the -QUIT
- qualifier appears in the command, the change simply occurs. However,
- if the current Global Directory has been modified, GDE verifies the
- Global Directory, and if the verification is successful, writes that
- Global Directory. If the verification is not successful, the SETGD
- fails.
+2 SHow
+ SHow
-1 SHOW
- SH[OW]
- The SHOW command displays information about NAMEs, REGIONs and
- SEGMENTs.
+ The SHOW command displays information contained in the Global Directory
+ about names, regions, and segments.
The format of the SHOW command is:
+ SH[OW] -C[OMMAND] -F[ILE]=[gde-command-file]
SH[OW] -N[AME] [name-space]
SH[OW] -R[EGION] [region-name]
SH[OW] -S[EGMENT] [segment-name]
- SH[OW] -M[AP] [R[EGION]=region-name]
+ SH[OW] -M[AP] [-R[EGION]=region-name]
SH[OW] -T[EMPLATE]
SH[OW] -A[LL]
- The object-type is optional. -MAP, -TEMPLATE, and -ALL are special
- qualifiers used as follows:
+ -COMMAND: Displays GDE commands that recreate the current Global Directory
+ state.
- o -MAP - displays the mapping of all NAMES, REGIONs, SEGMENTs, and
- files
+ -F[ILE]=gde-command-file: Optionally specifies a file to hold the GDE
+ commands produced by -COMMAND. -FILE must must always appear after
+ -COMMAND.
- o -TEMPLATE - displays the current REGION and SEGMENT templates
+ -NAME, -REGION, -SEGMENT, -MAP, -TEMPLATE, and -ALL are qualifiers that
+ cause GDE to display selected portions of the Global Directory as follows:
- o -ALL - displays all templates, the map, and information about each
- defined NAME, REGION, and SEGMENT
+ -MAP: Displays the current mapping of all names, regions, segments, and
+ files. This qualifier corresponds to the section of the SHOW report titled
+ ***MAP***. The output of a SHOW -MAP may be restricted to a particular
+ region by specifying a -REGION qualifier with a region name argument.
- By default, SHOW displays -ALL.
+ -TEMPLATE: Displays the current region and segment templates. This
+ qualifier corresponds to the section of the SHOW report titled:
+ ***TEMPLATES***
-1 SPAWN
- SP[AWN]
- The SPAWN command creates a child process for access to the shell
- without terminating the current GDE environment. Use the SPAWN command
- to suspend a session and issue shell commands such as ls or printenv.
- The SPAWN command spawns (forks) a child process with an optional
- command string. If SPAWN has no command string parameter, the GDE
- command leaves the terminal at the prompt for the shell of the spawned
- process.
+ -ALL: Displays the entire Global Directory. This qualifier corresponds to
+ displaying "all" sections of the SHOW report:
- The format of the SPAWN command is:
+ ***TEMPLATES***, ***NAMES***, ***REGIONS***, ***SEGMENTS***, ***MAP***.
- SP[AWN] [shell command]
+ By default, SHOW displays -ALL.
- Example
+ If you want to print the Global Directory, create a log file by executing
+ LOG -ON= before executing the SHOW command. The -LOG command captures all
+ the commands entered and output. You can print the log file if you want a
+ hard copy record.
+
+ If you want to export the current Global Directory state, create a GDE
+ command file with the SHOW -COMMAND -FILE=gde-command-file and run it in
+ the target environment.
+
+ Example:
+
+ GDE>show -template
+ *** TEMPLATES ***
+ Std Inst
+ Def Rec Key Null Null Freeze Qdb
+ Region Coll Size Size Subs Coll Jnl on Error Rndwn
+ ----------------------------------------------------------------------------------------------
+ <default> 0 4080 255 NEVER Y Y DISABLED DISABLED
+ 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
+ LOCK = 40
+ RES = 0
+ ENCR = OFF
+ <default> MM DYN 4096 5000 10000 DEFER
+ LOCK = 40
+
+ This displays only the TEMPLATES section of the Global Directory.
+
+ GDE>SHOW -command
+ TEMPLATE -SEGMENT -ACCESS_METHOD=MM -BLOCK_SIZE=4096 -ALLOCATION=5000 -EXTENSION_COUNT=10000
+ -LOCK_SPACE=40 -RESERVED_BYTES=0 -DEFER
+ TEMPLATE -SEGMENT -ACCESS_METHOD=BG -BLOCK_SIZE=4096 -ALLOCATION=5000 -EXTENSION_COUNT=10000
+ -LOCK_SPACE=40 -RESERVED_BYTES=0 -GLOBAL_BUFFER_COUNT=1000
+ TEMPLATE -REGION -RECORD_SIZE=4080 -KEY_SIZE=255 -NULL_SUBSCRIPTS=NEVER -STDNULLCOLL
+ -NOINST_FREEZE_ON_ERROR -NOQDBRUNDOWN
+ TEMPLATE -REGION
+ -JOURNAL=(BEFORE_IMAGE,BUFFER_SIZE=2308,ALLOCATION=2048,EXTENSION=2048,AUTOSWITCHLIMIT=8386560)
+ !
+ LOCKS -REGION=DEFAULT
+
+ CHANGE -REGION DEFAULT -DYNAMIC=DEFAULT -COLLATION_DEFAULT=0 -RECORD_SIZE=4080 -KEY_SIZE=255
+ -NULL_SUBSCRIPTS=NEVER -STDNULLCOLL
+ -JOURNAL=(BEFORE_IMAGE,BUFFER_SIZE=2308,ALLOCATION=2048,EXTENSION=2048,AUTOSWITCHLIMIT=8386560,
+ FILE="$gtmdir/$gtmver/g/gtm.mjl") -NOINST_FREEZE_ON_ERROR -NOQDBRUNDOWN
+ !
+ CHANGE -SEGMENT DEFAULT -ACCESS_METHOD=BG -BLOCK_SIZE=4096 -ALLOCATION=5000 -EXTENSION_COUNT=10000
+ -LOCK_SPACE=40 -RESERVED_BYTES=0 -GLOBAL_BUFFER_COUNT=1000 -FILE=$gtmdir/$gtmver/g/gtm.dat
+ !
+
+ This command displays the GDE commands to recreate the current global
+ directory state.
+
+2 Template
+ Template
+
+ The TEMPLATE command maintains a set of -REGION and -SEGMENT qualifier
+ values for use as templates when ADDing regions and segments. When an ADD
+ command omits qualifiers, GDE uses the template values as defaults.
+
+ GDE maintains a separate set of -SEGMENT qualifier values for each
+ ACCESS_METHOD. When GDE modifies the ACCESS_METHOD, it activates the
+ appropriate set of TEMPLATEs and sets all unspecified qualifiers to the
+ template defaults for the new ACCESS_METHOD. Use the GDE SHOW command to
+ display qualifier values for all ACCESS_METHODs.
- GDE> SPAWN "ls *.DAT"
+ The format of the TEMPLATE command is:
- This command invokes a directory listing of all files in the current
- default directory with a .DAT extension.
+ T[EMPLATE] -R[EGION] [-REGION-qualifier...]
+ T[EMPLATE] -S[EGMENT] [-SEGMENT-qualifier...]
-1 TEMPLATE
- T[EMPLATE]
- The TEMPLATE command maintains a set of REGION and SEGMENT qualifier
- values for use as templates when ADDing regions and segments. When an
- ADD command omits qualifiers, GDE uses the template values as
- defaults. GDE maintains a separate set of SEGMENT qualifier values for
- each ACCESS_METHOD. When GDE modifies the ACCESS_METHOD, it activates
- the appropriate set of TEMPLATEs and sets all unspecified qualifiers
- to the template defaults for the new ACCESS_METHOD. Use the GDE SHOW
- command to display qualifier values for all ACCESS_METHODs.
+ The TEMPLATE command requires specification of an object-type.
- The format of the TEMPLATE command is:
+ Example:
- T[EMPLATE]-R[EGION] [-region-qualifier...]
- T[EMPLATE]-S[EGMENT] [-segment-qualifier...]
+ GDE> template -segment -allocation=200000
- The TEMPLATE command requires specification of an object-type.
+ This command modifies the segment template so that any segments ADDed
+ after this time produce database files with an ALLOCATION of 200,000 GDS
+ blocks.
+
+2 Verify
+ Verify
-1 VERIFY
- V[ERIFY]
- The VERIFY command checks the NAME to REGION mappings to insure all
- NAMES map to a REGION. The VERIFY command checks REGION to SEGMENT
- mappings to insure each REGION maps to a SEGMENT, each SEGMENT maps to
- only one REGION and the SEGMENT maps to a UNIX file. The EXIT command
- implicitly performs a VERIFY -ALL.
+ The VERIFY command validates information entered into the current Global
+ Directory. It checks the name-to-region mappings to ensure all names map
+ to a region. The VERIFY command checks region-to-segment mappings to
+ ensure each region maps to a segment, each segment maps to only one
+ region, and the segment maps to a UNIX file. The EXIT command implicitly
+ performs a VERIFY -ALL.
The format of the VERIFY command is:
@@ -456,425 +938,743 @@
V[ERIFY] -T[EMPLATE]
V[ERIFY] -A[LL]
- The object-type is optional. -MAP, -TEMPLATE, and -ALL are special
+ The object-type is optional. -MAP, -TEMPLATE, and -ALL are special
qualifiers used as follows:
- o -MAP - checks that all NAMES map to a REGION, all REGIONs map to a
- SEGMENT, and all SEGMENTs map to a FILE
+ -MAP
+
+ Checks that all names map to a region, all regions map to a
+ segment, and all segments map to a file.
+
+ -TEMPLATE
- o -TEMPLATE - checks that all templates currently are consistent and
- useable
+ Checks that all templates currently are consistent and useable.
- o -ALL - checks all map and template data
+ -ALL
- VERIFY with no qualifier, VERIFY -MAP and VERIFY -ALL each check all
+ Checks all map and template data.
+
+ VERIFY with no qualifier, VERIFY -MAP, and VERIFY -ALL each check all
current information.
+ Example:
+
+ GDE> verify -region regis
+
+ This command verifies the region regis.
+
1 Qualifiers
- GDE Command Qualifiers
- The -NAME, -REGION, and -SEGMENT qualifiers each have additional
- qualifiers used to further define or specify characteristics of a
- NAME, REGION, or SEGMENT. This section discusses these additional
- qualifiers.
+ Qualifiers
+
+ The -NAME, -REGION, and -SEGMENT qualifiers each have additional
+ qualifiers used to further define or specify characteristics of a name,
+ region, or segment. For more information, refer to the additional topics.
2 Name_Qualifiers
- Name Qualifiers
- The only -NAME qualifier, used with the commands ADD or CHANGE, is
- the -REGION qualifier.
+ Name Qualifiers
+
+ The following -NAME qualifier can be used with the ADD or CHANGE commands.
+
+ -REGION=region-name
+
+ Specifies the name of a region. Region names are not case-sensitive, but
+ are represented as uppercase by GDE.
-3 -REGION
- -R[EGION]=region-name
- Specifies the name of a REGION.
+ The minimum length is one alphabetic character.
The maximum length is 16 alphanumeric characters.
- Example
+ Example:
- GDE> add-Name a*-Region=areg
+ GDE> add -name a* -region=areg
- This command creates the name "a," if it does not exist and maps
- it to the region "areg."
+ This command creates the name-space a*, if it does not exist, and maps it
+ to the region areg.
+ Summary
+
+ +------------------------------------------------------------------+
+ | GDE NAME Qualifiers |
+ |------------------------------------------------------------------|
+ | QUALIFIER | DEFAULT | MINIMUM | MAXIMUM |
+ |------------------------------------+---------+---------+---------|
+ | -R[EGION]=region-name (characters) | (none) | 1A | 16A/N |
+ +------------------------------------------------------------------+
2 Region_Qualifiers
- Region Qualifiers
- The following -REGION qualifiers can be used with the ADD, CHANGE
- or TEMPLATE commands.
+ Region Qualifiers
+
+ The following -REGION qualifiers can be used with the ADD, CHANGE, or
+ TEMPLATE commands.
+
+ -C[OLLATION_SEQUENCE]=id number
+
+ Specifies the number of the collation sequence definition to be used as
+ the default for this database file. The number can be any integer from 0
+ to 255. The number you assign as a value must match the number of a
+ defined collation sequence that resides in the shared library pointed to
+ by the environment variable gtm_collate_n. For information on defining
+ this environment variable and creating an alternate collation sequence,
+ refer to the "Internationalization" chapter in the GT.M Programmer's
+ Guide.
-3 -DYNAMIC_SEGMENT
- -D[YNAMIC_SEGMENT]=segment-name
- Specifies the name of a dynamic SEGMENT. A dynamic segment
- allows read-write access.
+ The minimum COLLATION_SEQUENCE ID number is zero, which is the standard M
+ collation sequence.
- The minimum length is 1 alpha character.
+ The maximum COLLATION_SEQUENCE ID number is 255.
+
+ By default, GDE uses zero (0) as the COLLATION_SEQUENCE ID.
+
+ -D[YNAMIC_SEGMENT]=segment-name
+
+ Specifies the name of the segment to which the region is mapped.
+ Segment-names are not case-sensitive, but are displayed as uppercase by
+ GDE.
+
+ The minimum length is one alphabetic character.
The maximum length is 16 alphanumeric characters.
-3 -KEY_SIZE
- -K[EY_SIZE]=size in bytes
- Specifies the maximum size of keys, in bytes, which can be
- stored in the region.
+ -K[EY_SIZE]=size in bytes
- CAUTION: The key size must be less than the record size. GDE
- rejects the command if the key size is greater than the record
- size.
+ Specifies the maximum size of keys, in bytes, which can be stored in the
+ region. The KEY_SIZE must be less than the RECORD_SIZE. GDE rejects the
+ command if the KEY_SIZE is inappropriate for the RECORD_SIZE.
- The minimum key size is 3 bytes.
+ The minimum KEY_SIZE is three bytes.
- The maximum key size is 255 bytes.
+ The maximum KEY_SIZE is 1019 bytes.
- By default, GDE uses a key size of 64 bytes.
+ When determining the maximum key size, applications should consider the
+ following:
-3 -RECORD_SIZE
- -R[ECORD_SIZE]=size in bytes
- Specifies the maximum record size, in bytes, which can be stored
- in the region.
+ o A key must fit within one database block and the maximum KEY_SIZE is
+ limited to 40 bytes less than the block size. For example, a 1024 byte
+ block can support a maximum KEY_SIZE of 984 bytes and a 1536 byte
+ block size is the smallest that supports a maximum KEY_SIZE of 1019
+ bytes.
+ o GT.M uses packed decimal representation for numeric subscripts which
+ may be larger or smaller than the original representation.
+ o GT.M substitutes an element terminator for the caret (^), any comma
+ (,), and any right parenthesis ()).
+ o GT.M adds an extra byte for every string element, including the global
+ name.
- CAUTION: The key size must be less than the record size. GDE
- rejects the command if the key size exceeds the record size.
+ For example, the key ^ACN ("Name", "Type") internally occupies 17 bytes.
- The record size must be less than half the block size of the
- segment to which the region maps. If the record size is not less
- than half the block size minus 7 bytes, GDE issues an error
- message. To VERIFY or EXIT, you must change the record size.
+ By default, GDE uses a KEY_SIZE of 64 bytes.
- The minimum record size is 7 bytes.
+ -R[ECORD_SIZE]=size in bytes
- The maximum record size is 32,508 bytes.
+ Specifies the maximum size (in bytes) of a global variable node's value
+ that can be stored in a region. The KEY_SIZE must be less than the
+ RECORD_SIZE. GDE rejects the command if the KEY_SIZE is inappropriate for
+ the RECORD_SIZE.
- By default, GDE uses a record size of 256 bytes.
+ If the size of a global exceeds one database block, GT.M implicitly spans
+ that global across multiple database blocks. In the event a global
+ variable node spans multiple blocks, and the process is not already within
+ a TP transaction, the GT.M run-time system automatically and transparently
+ performs the entire operation within an implicit TP transaction (just as
+ is the case with triggers).
-3 -NULL_SUBSCRIPTS
- -[NO]N[ULL_SUBSCRIPTS]
- Indicates whether GT.M allows null subscripts for global
- variables stored in the region, i.e., whether GT.M permits
- reference such as ^aaa("",1).
+ The minimum RECORD_SIZE is seven or eight, depending on your platform.
- By default, REGIONS have -NONULL_SUBSCRIPTS.
+ The maximum RECORD_SIZE is 1,048,576 bytes (1MiB).
-3 -JOURNAL
- -[NO]J[OURNAL][=journal-option-list]
- Specifies whether the database file allows journaling and, if it
- does, establishes characteristics for the journal file.
+ By default, GDE uses a RECORD_SIZE of 256 bytes.
- -NOJOURNAL specifies that the database file does not allow
- journaling. -NOJOURNAL does not accept an argument assignment.
+ -[NO]N[ULL_SUBSCRIPTS]=[ALWAYS|NEVER|EXISTING]
- -JOURNAL specifies that journaling is allowed. -JOURNAL takes
- one or more arguments in a journal-option-list. The
- journal-option-list contains keywords separated with commas (,)
- enclosed in parentheses (). When the list contains only one
- keyword, the parentheses are optional.
+ Indicates whether GT.M allows null subscripts for global variables stored
+ in the region (that is, whether GT.M permits references such as
+ ^aaa("",1)).
- For more information about journaling, refer to the GT.M
- Journaling chapter of the GT.M Administration and Operations
- Guide.
+ ALWAYS indicates that the null subscripts for global variables are
+ allowed.
-4 BEFORE_IMAGE
- [NO]BE[FORE_IMAGE]
- [NO]BEFORE_IMAGE controls whether the journal should capture
- before images of information that an update is about to
- modify.
+ NEVER indicates that null subscripts for global variables are not allowed.
- A BEFORE_IMAGE journal permits the possibility of performing
- "roll-back" recovery (i.e., Backward Recovery) of the
- associated database file. BEFORE_IMAGE increases the load on
- I/O and CPU resources and therefore may affect performance.
+ EXISTING indicates that null subscripts for global variable can be
+ accessed and updated, but not created anew.
-4 FILE_NAME
- F[ILE_NAME]=file-name
- FILE_NAME=file-name specifies the name of the journal file.
+ By default, regions have -NULL_SUBSCRIPTS=NEVER.
- Journal file-name are limited to 255 characters.
+ -[NO]STDNULLCOLL[=TRUE|FALSE]
- By default, GDE derives the file-name from the database file
- name.
+ Determines whether GT.M null subscripts collate in conformance to the M
+ standard.
- By default, GDE uses a journal file type of .MJL.
+ If -STDNULLCOLL is set to TRUE or -STDNULLCOLL is specified, subscripts of
+ globals in the database follow the M standard where the null subscript
+ collates before all other subscripts.
-4 ALLOCATION
- A[LLOCATION]=blocks
- ALLOCATION=blocks specifies the initial size of the journal
- file in blocks. Because frequent journal file extensions
- degrade run-time performance, make journal file allocation
- ample for a production database file.
+ If -STDNULLCOLL is set to FALSE or -NOSTDNULLCOLL is specified, null
+ subscripts collate between numeric and string subscripts.
- When you change the ALLOCATION and do not also specify
- EXTENSION, the EXTENSION automatically changes to equal the
- ALLOCATION.
+ -[NO]INST[_FREEZE_ON_ERROR]
- The minimum allocation is 10 blocks.
+ Controls whether custom errors in a region should automatically cause an
+ Instance Freeze. This qualifier modifies the value of "Inst Freeze on
+ Error" file header element.
- The maximum allocation is 16777216 blocks.
+ -[NO]Q[DBRUNDOWN]
- By default, GDE uses an allocation of 100 blocks.
+ Quickens normal process shutdown where a large number of processes
+ accessing a database file are required to shutdown almost simultaneously,
+ for example, in benchmarking scenarios. When a terminating GT.M process
+ observes that a large number of processes are attached to a database file
+ and QDBRUNDOWN is enabled, it bypasses checking whether it is the last
+ process accessing the database. Such a check occurs in a critical section
+ and bypassing it also bypasses the usual RUNDOWN actions which accelerates
+ process shutdown removing a possible impediment to process startup. By
+ default, QDBRUNDOWN is disabled.
-4 EXTENSION
- E[XTENSION]=blocks
- EXTENSION=blocks specifies the size by which a journal file
- extends when it becomes full. EXTENSION=0 prevents automatic
- journal file extension. Because frequent journal file
- extensions degrade run-time performance, make the journal
- file extension ample for a production database file.
+ Note that with QDBRUNDOWN there is a possibility of race condition that
+ might leave the database fileheader and IPC resources in need of cleanup.
+ Although QDBRUNDOWN minimizes the probability of such a race condition, it
+ cannot eliminate it. When using QDBRUNDOWN, FIS recommends an explicit
+ MUPIP RUNDOWN of the database file after the last process exits, to ensure
+ the cleanup of database fileheader and IPC resources.
- When you change the ALLOCATION and do not also specify
- EXTENSION, the EXTENSION automatically changes to equal the
- ALLOCATION.
+ -[NO]J[OURNAL][=journal-option-list]
- The minimum EXTENSION is 0 blocks.
+ Specifies whether the database file allows journaling. If it does, this
+ qualifier establishes characteristics for the journal file.
- The maximum EXTENSION is 65536 blocks.
+ -NOJOURNAL specifies that updates to the database file are not journaled.
+ -NOJOURNAL does not accept an argument assignment.
- By default, GDE uses an EXTENSION of 100 blocks.
+ -JOURNAL specifies that journaling is allowed. -JOURNAL takes one or more
+ arguments in a journal-option-list. The journal-option-list contains
+ keywords separated with commas (,) enclosed in parentheses ( ). If the
+ list contains only one keyword, the parentheses are optional.
-4 BUFFER_SIZE
- BU[FFER_SIZE]=pages
- BUFFER_SIZE=pages specifies the amount of memory used to
- buffer journal file output. A larger BUFFER_SIZE usually
- smooths and improves run-time performance.
+ Although you do not have to establish the criteria for your journaling
+ process at this point, it is efficient to do so, even if you are not
+ entirely sure you will use journaling. The options available for -JOURNAL
+ set up the environment, so it is ready for you to enable with MUPIP SET
+ -JOURNAL. You can also change or add any of the established options at
+ that time.
- A larger BUFFER_SIZE requires more memory resources, which
- may be scarce. A larger BUFFER_SIZE provides more room for
- journal records in memory on their way to the disk and
- therefore increases the number of update records that may be
- lost in a system failure.
+ The journal-option-list includes:
- The minimum BUFFER_SIZE is enough 512-byte pages to hold 2
- GDS database blocks.
+ o [NO]BE[FORE_IMAGE]
+ o F[ILE_NAME]=file-specification-name
- The maximum BUFFER_SIZE is 2000 pages.
+ o AUTOSWITCHLIMIT=blocks
- By default, GDE uses a BUFFER_SIZE of 128 pages.
+ o A[LLOCATION]=blocks
-2 Segment_Qualifiers
- Segment Qualifiers
- The following -SEGMENT qualifiers can be used with the ADD, CHANGE,
- or TEMPLATE commands.
+ o E[XTENSION]=blocks
+ o BU[FFER_SIZE]=pages
-3 -FILE_NAME
- -F[ILE_NAME]="filename"
- Specifies the file name for a SEGMENT. The filename must appear
- in quotes to distinguish its slashes from those of the command
- qualifiers. GT.M allows the use of environment variables in the
- filename.
+ The following section describes some -JOURNAL options.
- The maximum filename length is 255 characters.
+ Specifies the limit on the size of a journal file. When the journal file
+ size reaches the limit, GT.M automatically performs an implicit online
+ switch to a new journal file.
- By default, GDE uses a file name of MUMPS.
+ -[NO]BE[FORE_IMAGE]
- By default, GDE uses a file extension of .DAT.
+ [NO]BEFORE_IMAGE controls whether the journal should capture before images
+ of information that an update is about to modify.
-3 -ACCESS_METHOD
- -AC[CESS_METHOD]=code
- Specifies the access method GT.M uses to store and retrieve data
- from the global database file. The two methods are Buffered
- Global (BG) and Mapped Memory (MM).
+ The BEFORE_IMAGE option is required if you plan to consider "roll-back"
+ (Backward) recovery of the associated database file or if you plan to use
+ certain database replication options.
- GDE maintains a separate set of SEGMENT qualifier values for
- each ACCESS_METHOD. When GDE modifies the ACCESS_METHOD, it
- activates the appropriate set of TEMPLATEs and sets all
- unspecified qualifiers to the template defaults for the new
- ACCESS_METHOD.
+ -F[ILE_NAME]="file-name"
- By default, GDE uses an access method of BG.
+ Specifies the name of the journal file.
+ The name should always be enclosed in quotation marks in this context.
-3 -BLOCK_SIZE
- -BL[OCK_SIZE]=size
- Specifies the size, in bytes, of each database block on disk.
- The block-size must be a multiple of 512. If the block-size is
- not a multiple of 512, GDE rounds off the block-size to the next
- highest multiple of 512 and issues a warning message.
+ Journal file-specifications-names are limited to 255 characters.
- If the specified block-size is less than the minimum, GDE uses
- the minimum block-size. If the specified block-size is greater
- than the maximum, GDE issues an error message.
+ By default, GDE derives the file-specification-name from the database
+ "file-name".
- A 1024 byte or 2048 byte block-size serves well for most
- applications.
+ By default, GDE uses a journal file extension of .mjl.
+ JOL Summary
- The minimum block-size is 512 bytes.
+ With GDE, you can create the journal files and define the journal
+ parameters; however, you must use MUPIP SET to actually enable journaling.
- The maximum block-size is 65,024 bytes.
+ Summary
- By default, GDE uses a block-size of 1024 bytes for BG and MM
- files.
+ The following table summarizes GDE region qualifiers. It provides their
+ abbreviations, defaults (as provided by FIS), and allowable minimum and
+ maximum values.
-3 -ALLOCATION
- -AL[LOCATION]=size
- Specifies the number of blocks GT.M allocates to a disk file
- when MUPIP creates the file. For GDS files, the number of bytes
- allocated is ALLOCATION size times the BLOCK_SIZE.
+ +-----------------------------------------------------------------------------+
+ | GDE REGION Qualifiers |
+ |-----------------------------------------------------------------------------|
+ | QUALIFIER | DEFAULT | MINIMUM | MAXIMUM |
+ |--------------------------------------------+----------+---------+-----------|
+ |-C[OLLATION_SEQUENCE]=id-number (integer) |0 |0 |255 |
+ |--------------------------------------------+----------+---------+-----------|
+ |-D[YNAMIC_SEGMENT] =segment-name (char) |- |1 |16 |
+ |--------------------------------------------+----------+---------+-----------|
+ |-K[EY_SIZE]=size in bytes (integer) |64 |3 |1019 |
+ |--------------------------------------------+----------+---------+-----------|
+ |-R[ECORD_SIZE]=size in bytes (integer) |256 |7 |1,048,576 |
+ | | | |(1 MiB) |
+ |--------------------------------------------+----------+---------+-----------|
+ |-N[ULL_SUBSCRIPTS]=[ALWAYS|NEVER|EXISTING] |NEVER |- |- |
+ |--------------------------------------------+----------+---------+-----------|
+ |-[NO]STDNULLCOLL |N |- |- |
+ |--------------------------------------------+----------+---------+-----------|
+ |-[NO]INST[_FREEZE_ON_ERROR] |DISABLED |- |- |
+ |--------------------------------------------+----------+---------+-----------|
+ |-[NO]Q[DBRUNDOWN] |DISABLED |- |- |
+ |--------------------------------------------+----------+---------+-----------|
+ |-[NO]J[OURNAL] [=journal-option-list] |-NOJ |- |- |
+ +-----------------------------------------------------------------------------+
- The default allocation was chosen for small development
- projects. Use larger allocations for production files and large
- projects. Because file fragmentation impairs performance, make
- the initial allocation large enough to hold the anticipated
- contents of the file for a length of time consistent with your
- UNIX file reorganization schedule.
+2 Segment_Qualifiers
+ Segment Qualifiers
+
+ The following -SEGMENT qualifiers can be used with the ADD, CHANGE, or
+ TEMPLATE commands.
+
+ -AC[CESS_METHOD]=code
+
+ Specifies the access method or the GT.M buffering strategy for storing and
+ retrieving data from the global database file.
+
+ o code can have 2 values - Buffered Global (BG) or Memory Mapped (MM).
+ The default value is BG.
+ o With BG, the global buffer pool manages the buffers (the OS/file
+ system may also provide additional buffering). You get the choice of
+ using BEFORE_IMAGE or NOBEFORE_IMAGE journaling for your database.
+
+ o BG supports both forward and backward recovery and rollback to
+ recover a database without a restore.
+ o BG is a likely choice when you need faster recovery times from
+ system failures.
+
+ o With MM, GT.M bypasses the global buffer pool and relies entirely on
+ the OS/file system to manage the data traffic between memory and disk.
+ GT.M has no control over the timing of disk updates, therefore there
+ is a greater reliance on the OS/file system for database performance.
- The minimum ALLOCATION is 10 blocks.
+ o MM supports NOBEFORE_IMAGE journaling only. GT.M triggers an
+ error if you use MM with BEFORE_IMAGE Journaling. MM also
+ supports MUPIP FORWARD -RECOVER and MUPIP JOURNAL -ROLLBACK with
+ the -RESYNC or -FETCHRESYNC qualifiers to generate lost and
+ broken transaction files. For more information, see the
+ Journaling chapter.
+ o MM does not support backward recovery/rollback.
+ o MM is a possible choice when you need performance advantage in
+ situations where the above restrictions are acceptable.
+
+ o GDE maintains a separate set of segment qualifier values for each
+ ACCESS_METHOD.
+ o When GDE modifies the ACCESS_METHOD, it activates the appropriate set
+ of TEMPLATEs and sets all unspecified qualifiers to the default values
+ of the new ACCESS_METHOD.
- The maximum ALLOCATION is 16777216 blocks.
+ Example:
- By default, GDE uses an ALLOCATION of 100 blocks.
+ GDE> change -segment DEFAULT -access_method=MM
-3 -EXTENSION_COUNT
- -E[XTENSION_COUNT]=size
- Specifies the number of extra GDS blocks of disk space by which
- the file should extend. The extend amount is interpreted as the
- number of usable GDS blocks to create with the extension. To
- calculate the number of host operating system blocks added with
- each extension, multiply the number of GDS blocks added by (GDS
- block size/host block size); to this amount, add one local bit
- map block for each 512-byte block added in each extension, plus
- one for any remaining bytes.
+ This command sets MM as the access method or the GT.M buffering strategy
+ for storing and retrieving database for segment DEFAULT.
- The default extension amount was chosen for small development
- projects. Use larger extensions for larger files. Because many
- file extensions adversely affect performance, set up extensions
- appropriate to the file allocation.
+ -AL[LOCATION]=blocks
- BG files may extend automatically when the file is full. A zero
- extension size prevents a BG file from automatically extending.
+ Specifies the number of blocks GT.M allocates to a disk file when MUPIP
+ creates the file. For GDS files, the number of bytes allocated is the size
+ of the database file header plus the ALLOCATION size times the BLOCK_SIZE.
- BG files may be, and MM files must be, extended with MUPIP
- EXTEND. When a MUPIP EXTEND command does not include a -BLOCKS=
- qualifier, EXTEND uses the extension size in the database
- header. The extension amount may be changed with the MUPIP SET
- command. To require explicit expansion for BG files with MUPIP
- EXTEND, set -EXTENSION_COUNT to zero.
+ o The minimum ALLOCATION is 10 blocks.
+ o The maximum ALLOCATION is 1,040,187,392 blocks.
+ o By default, GDE uses an ALLOCATION of 100 blocks.
+ o The maximum size of a database file is 1,040,187,392(992Mi) blocks.
+ o Out of the requested allocation, GT.M always reserves 32 global
+ buffers for BG access method for read-only use to ensure that
+ non-dirty global buffers are always available.
+ o The default ALLOCATION was chosen for initial development and
+ experimentation with GT.M. Because file fragmentation impairs
+ performance, make the initial allocation for production files and
+ large projects large enough to hold the anticipated contents of the
+ file for a length of time consistent with your UNIX file
+ reorganization schedule.
- The minimum EXTENSION is 0 blocks.
+ -BL[OCK_SIZE]=size
- The maximum EXTENSION is 65,535 blocks.
+ Specifies the size, in bytes, of each database block in the file system.
+ The BLOCK_SIZE must be a multiple of 512. If the BLOCK_SIZE is not a
+ multiple of 512, GDE rounds off the BLOCK_SIZE to the next highest
+ multiple of 512 and issues a warning message.
- By default, GDE uses an EXTENSION of 100 blocks.
+ If the specified BLOCK_SIZE is less than the minimum, GDE uses the minimum
+ BLOCK_SIZE. If the specified BLOCK_SIZE is greater than the maximum, GDE
+ issues an error message.
-3 -GLOBAL_BUFFER_COUNT
- -G[LOBAL_BUFFER_COUNT]=size
- Specifies the number of global buffers for a file. Global
- buffers serve as part of the database caching mechanisms.
-
- Avoid inadequate settings of this factor. However, if your
- system is memory constrained and the database file traffic is
- not heavy enough to hold the cache in memory, increasing
- GLOBAL_BUFFER_COUNT may induce paging. Therefore, do not
- increase this factor to a large value without careful
- observation.
-
- The proper number of GLOBAL_BUFFERs depends on the application
- and the amount of primary memory available on the system. Most
- production databases exhibit a direct relationship between the
- number of GLOBAL_BUFFERs and performance. However, the
- relationship is not linear, but rather more parabolic, so that
- increases past some point have progressively less benefit. This
- point of diminishing returns depends on the application. For
- most applications, Greystone expects the optimum number of
- GLOBAL_BUFFERs to be between 512 and 2048.
-
- Generally, you should increase the number of GLOBAL_BUFFERs for
- production GDS databases. This is because GT.M uses the shared
- memory database cache associated with each GDS file for the vast
- majority of caching.
-
- The minimum for BG is 64 blocks.
-
- The maximum for BG is 4096 blocks.
-
- By default, GDE uses a GLOBAL_BUFFER_COUNT of 1024 blocks.
-
-3 -DEFER
- -[NO]D[EFER]
- Instructs GT.M whether or not to store updates on the disk
- immediately.
-
- DEFER has a significant performance benefit for heavily updated
- database files. However, DEFER should only be used for files,
- such as those containing temporary storage for reports, which
- can be recreated if the system crashes.
-
- By default, GDE makes MM database files -DEFER.
-
-3 -LOCK_SPACE
- -LOC[K_SPACE]=size
- Specifies the number of pages of space to use for the lock
- database stored with this segment. If GT.M runs out of space to
- store locks, the system becomes slightly less efficient. The
- default amount is generous for most MUMPS applications.
+ A BLOCK_SIZE that is equal to the page size used by your UNIX
+ implementation serves well for most applications, and is a good starting
+ point.
- The minimum LOCK_SPACE is 10 pages.
+ You should determine the block sizes for your application through
+ performance timing and benchmarking. In general, larger block sizes are
+ more efficient from the perspective of the input/output subsystem.
+ However, larger block sizes use more system resources (CPU and shared
+ memory) and may increase collision and retry rates for transaction
+ processing.
- The maximum LOCK_SPACE is 1000 pages.
+ **Note**
- By default, GDE uses a LOCK_SPACE of 20 pages.
+ Global nodes that span blocks incur some overhead and optimum application
+ performance is likely to be obtained from a BLOCK_SIZE that accommodates
+ the majority of nodes within a single block. If you adjust the BLOCK_SIZE,
+ you should also adjust GLOBAL_BUFFER_COUNT.
-1 Guidelines
- Mapping Guidelines
- Global Directory maps consist of a hierarchy of NAMEs, REGIONs,
- SEGMENTs and FILEs. The following section provides guidelines for
- defining and using these mapping components.
+ GDE does not allow you to change the block size to an arbitrary number. It
+ always rounds the block size to the next higher multiple of 512, because
+ the database block size must always be a multiple of 512.
-2 Names
- NAME Guidelines
- GT.M uses a NAME to place global variables in a physical database
- file.
- A NAME:
+ The minimum BLOCK_SIZE is 512 bytes.
+
+ The maximum BLOCK_SIZE is 65,024 bytes.
+
+ **Note**
+
+ FIS recommends against using databases with block sizes larger than 16KB.
+ If a specific global variable has records that have large record sizes,
+ FIS recommends placing that global variable in a file by itself with large
+ block sizes and using more appropriate block sizes for other global
+ variables. 4KB and 8KB are popular database block sizes.
- o Maps to only one REGION in the Global Directory
+ By default, GDE uses a BLOCK_SIZE of 1024 bytes.
- o Can be a discrete "global" name, e.g., aaa is a discrete global
+ -[NO]ENcryption
- o Can be a partial name ending with a wild card ("*")
+ Specifies whether or not the database file for a segment is flagged for
+ encryption. Note that MUPIP CREATE acquires an encryption key for this
+ file and puts a cryptographic hash of the key in the database file header.
- o Must begin with an alphabetic character or a % sign
+ -EX[TENSION_COUNT]=blocks
- o Can be 1 to 8 alphanumeric characters
+ Specifies the number of extra GDS blocks of disk space by which the file
+ should extend. The extend amount is interpreted as the number of usable
+ GDS blocks to create with the extension. To calculate the number of host
+ operating system blocks added with each extension, multiply the number of
+ GDS blocks added by (GDS BLOCK_SIZE/host BLOCK_SIZE); add one local bitmap
+ block for each 512 blocks added in each extension to the amount from step
+ 1. If the extension is not a multiple of 512, remember to roundup when
+ figuring the number of bitmap blocks.
- o Is case sensitive
+ When a MUPIP EXTEND command does not include a -BLOCKS= qualifier, EXTEND
+ uses the extension size in the database header.
- A wild card defines all names starting with the characters of the
- partial name. For example, abc*, defines the range of all global
- names beginning with the three characters "abc."
+ The extension amount may be changed with the MUPIP SET command.
-2 Regions
- REGION Guidelines
- GT.M uses a REGION to logically define a portion of the database
- with the same characteristics, such as key and record-size. A
- REGION maps to a SEGMENT. More than one NAME may map to a REGION. A
- Global Directory must have at least one REGION.
+ The minimum EXTENSION is zero blocks.
- A region-name:
+ The maximum EXTENSION is 65,535 blocks.
- o Must begin with an alphabetic character, except for DEFAULT
+ By default, GDE uses an EXTENSION of 100 blocks.
- o Can include alphanumerics, a dollar sign and an underscore
+ Like allocation, the default extension amount was chosen for initial
+ development and experimentation with GT.M projects. Use larger extensions
+ for larger files. Because multiple file extensions adversely affect
+ performance, set up extensions appropriate to the file allocation.
- o Can be 1 to 15 characters
+ -F[ILE_NAME]=file-name
- GDE automatically converts region-names to upper-case.
+ Specifies the file for a segment.
- By default, GDE uses DEFAULT for the default region-name.
+ The maximum file name length is 255 characters.
-2 Segments
- SEGMENT Guidelines
- GT.M uses a SEGMENT to define a physical file and access method for
- the database stored in that file. A SEGMENT maps to only one UNIX
- file. A SEGMENT can be mapped by only one REGION.
+ By default, GDE uses a file-name of mumps followed by the default
+ extension, which is .dat.
- A segment-name:
+ -G[LOBAL_BUFFER_COUNT]=size
+
+ Specifies the number of global buffers for a file. Global buffers reside
+ in shared memory and are part of the database caching mechanisms. Global
+ buffers do not apply to MM databases.
+
+ Choose the settings for this qualifier carefully. Small numbers of global
+ buffers tend to throttle database performance. However, if your system has
+ limited memory and the database file traffic is not heavy enough to hold
+ the cache in memory, increasing GLOBAL_BUFFER_COUNT may trigger paging.
- o Must begin with an alphabetic character
+ If database global buffers are paged out, it may result in poor
+ performance. Therefore, do not increase this factor to a large value
+ without careful observation.
- o Can include alphanumerics, a dollar sign and an underscore
+ The proper number of GLOBAL_BUFFERs depends on the application and the
+ amount of primary memory available on the system. Most production
+ databases exhibit a direct relationship between the number of
+ GLOBAL_BUFFERs and performance. However, the relationship is not linear,
+ but asymptotic, so that increases past some point have progressively less
+ benefit. This point of diminishing returns depends on the application. For
+ most applications, FIS expects the optimum number of GLOBAL_BUFFERs to be
+ between 1K and 64K.
- o Can be 1 to 15 characters
+ Because transaction processing can be involved in an update and a
+ transaction is limited to half the GLOBAL_BUFFER_COUNT, the value for
+ GLOBAL_BUFFER_COUNT should therefore be at least twenty-six plus twice the
+ number of the blocks required by the largest global variable node in your
+ application.
- GDE automatically converts segment-names to upper-case.
+ Generally, you should increase the number of GLOBAL_BUFFERs for production
+ GDS databases. This is because GT.M uses the shared memory database cache
+ associated with each GDS file for the majority of caching.
- By default, GDE uses the file name MUMPS for the DEFAULT default
- segment. By default, GDE uses the file extension .DAT for database
- files.
+ The minimum GLOBAL_BUFFER_COUNT for BG is 64 blocks.
+
+ The maximum for GLOBAL_BUFFER_COUNT for BG is 2147483647 blocks, but may
+ vary depending on your platform.
+
+ By default, GDE uses a GLOBAL_BUFFER_COUNT that is appropriate for the
+ typical size of the platform.
+
+ **Note**
+
+ If global buffers are "paged out," improvements in system performance
+ resulting from more global buffers will be more than offset by the
+ dramatic slowdown that results from globals buffers that are "paged out."
+
+ -L[OCK_SPACE]=integer
+
+ Specifies the number of pages of space to use for the lock database stored
+ with this segment. The size of a page is always 512 bytes.
+
+ As GT.M runs out of space to store LOCK control information, LOCKs become
+ progressively less efficient. If a single process consumes all the LOCK
+ space, it cannot continue, and any other processes cannot proceed using
+ LOCKs.
+
+ The minimum LOCK_SPACE is 10 pages.
+ The maximum LOCK_SPACE is 65,536 pages.
+
+ By default, GDE uses a LOCK_SPACE of 40 pages.
+
+ LOCK_SPACE usage depends on the number of locks and the number of
+ processes waiting for locks. To estimate lock space needs, here is a rule
+ of thumb:
+
+ o 1.5KB overhead for the lock space, plus
+ o 640 bytes for each lock base name, plus
+ o 128 bytes for each subscript, plus
+ o 128 bytes for each waiting process.
+
+ Generally, you would limit LOCK_SPACE when memory is scarce or you want to
+ be made aware of unexpected levels of LOCK usage. For most other cases,
+ there is no reason to limit the LOCK_SPACE. If you are introducing new
+ code, FIS recommends using TSTART and TCOMMIT as a more efficient
+ alternate for most LOCKs because it pushes the responsibility for
+ Isolation onto GT.M, which internally manages them with optimistic
+ algorithms.
+
+ -R[ESERVED_BYTES]=size
+
+ Specifies the size to be reserved in each database block. RESERVED_BYTES
+ is generally used to reserve room for compatibility with other
+ implementations of M or to observe communications protocol restrictions.
+ RESERVED_BYTES may also be used as a user-managed fill factor.
+
+ The minimum RESERVED_BYTES is zero bytes.
+
+ The maximum Reserved_Bytes is the block size minus the size of the block
+ header (which is 7 or 8 depending on your platform) minus the maximum
+ record size.
+
+ By default, GDE uses a RESERVED_BYTES size of zero bytes.
+
+ Summary
+
+ The following table summarizes GDE segment qualifiers. It provides
+ abbreviations, defaults (as provided by FIS), and allowable minimum and
+ maximum values.
+
+ +------------------------------------------------------------------------+
+ | GDE SEGMENT Qualifiers |
+ |------------------------------------------------------------------------|
+ | QUALIFIER | DEFAULT | MIN | MAX |
+ |------------------------------------------------------------------------|
+ | ** BLOCK_SIZE minus the size of the block header |
+ |------------------------------------------------------------------------|
+ | * May vary by platform |
+ |------------------------------------------------------------------------|
+ | -AC[CESS_METHOD]=BG|MM | BG | - | - |
+ |-------------------------------+-----------+-----+----------------------|
+ | -AL[LOCATION]=size (blocks) | 100 | 10 | 1,040,187,392(992Mi) |
+ |-------------------------------+-----------+-----+----------------------|
+ | -BL[OCK_SIZE]=size (bytes) | 1024 | 512 | 65024 |
+ |-------------------------------+-----------+-----+----------------------|
+ | -[NO]EN[CRYPTION] | 0 | | |
+ |-------------------------------+-----------+-----+----------------------|
+ | -EX[TENSION_COUNT]=size | 100 | 0 | 65,535 |
+ | (blocks) | | | |
+ |-------------------------------+-----------+-----+----------------------|
+ | -F[ILE_NAME]=file-name | mumps.dat | - | 255 |
+ | (chars) | | | |
+ |-------------------------------+-----------+-----+----------------------|
+ | -G[LOBAL_BUFFER_COUNT]=size | 1024* | 64 | 2147483647 |
+ | (blocks) | | | |
+ |-------------------------------+-----------+-----+----------------------|
+ | -L[OCK_SPACE]=size (pages) | 40 | 10 | 65536 |
+ |-------------------------------+-----------+-----+----------------------|
+ | -R[ESERVED_BYTES]=size | 0 | 0 | block size-7 |
+ | (bytes) | | | |
+ +------------------------------------------------------------------------+
+
+1 Summary
+ Summary
+
+ The following table summarizes GDE commands, abbreviations, object types,
+ required object names, and optional qualifiers.
+
+ +------------------------------------------------------------------------+
+ | GDE Command Summary |
+ |------------------------------------------------------------------------|
+ | Command | Specified Object | Required Object Name/[Optional] |
+ | | Type | Qualifier |
+ |------------------------------------------------------------------------|
+ | * -ALL is the default for the SHOW and VERIFY commands. |
+ |------------------------------------------------------------------------|
+ | @ | N/A | file-name |
+ |------------+------------------+----------------------------------------|
+ | | | name-space |
+ | A[DD] | -N[AME] | |
+ | | | -R[EGION]=region-name |
+ |------------+------------------+----------------------------------------|
+ | | | region-name |
+ | - | -R[EGION] | |
+ | | | -D[YNAMIC]=segment-name |
+ | | | [-REGION-qualifier...] |
+ |------------+------------------+----------------------------------------|
+ | | | segment-name |
+ | - | -S[EGMENT] | |
+ | | | -F[ILE_NAME]=file-name |
+ | | | [-SEGMENT-qualifier...] |
+ |------------+------------------+----------------------------------------|
+ | | | name-space |
+ | C[HANGE] | -N[AME] | |
+ | | | -R[EGION]=new-region |
+ |------------+------------------+----------------------------------------|
+ | | | region-name |
+ | - | -R[EGION] | |
+ | | | [-REGION-qualifier...] |
+ |------------+------------------+----------------------------------------|
+ | | | segment-name |
+ | - | -S[EGMENT] | |
+ | | | [-SEGMENT-qualifier] |
+ |------------+------------------+----------------------------------------|
+ | D[ELETE] | -N[AME] | name-space |
+ |------------+------------------+----------------------------------------|
+ | - | -R[EGION] | region-name |
+ |------------+------------------+----------------------------------------|
+ | - | -S[EGMENT] | segment-name |
+ |------------+------------------+----------------------------------------|
+ | E[XIT] | N/A | N/A |
+ |------------+------------------+----------------------------------------|
+ | HE[LP] | N/A | Keyword |
+ |------------+------------------+----------------------------------------|
+ | LOC[KS] | N/A | -R[EGION]=region-name |
+ |------------+------------------+----------------------------------------|
+ | | | [-ON][=file-name] |
+ | LOG | N/A | |
+ | | | [-OF[F]] |
+ |------------+------------------+----------------------------------------|
+ | Q[UIT] | N/A | N/A |
+ |------------+------------------+----------------------------------------|
+ | R[ENAME] | -N[AME] | old-name new-name |
+ |------------+------------------+----------------------------------------|
+ | - | -R[EGION] | old-reg-name new-reg-name |
+ |------------+------------------+----------------------------------------|
+ | - | -S[EGMENT] | old-seg-name new-seg-name |
+ |------------+------------------+----------------------------------------|
+ | SE[TGD] | N/A | -F[ILE]=file-name [-Q[UIT]] |
+ |------------+------------------+----------------------------------------|
+ | SH[OW] | -N[AME] | [name-space] |
+ |------------+------------------+----------------------------------------|
+ | - | -R[EGION] | [region-name] |
+ |------------+------------------+----------------------------------------|
+ | - | -S[EGMENT] | [segment-name] |
+ |------------+------------------+----------------------------------------|
+ | - | -M[AP] | [R[EGION]=region-name] |
+ |------------+------------------+----------------------------------------|
+ | - | T[EMPLATE] | N/A |
+ |------------+------------------+----------------------------------------|
+ | - | -A[LL]* | N/A |
+ |------------+------------------+----------------------------------------|
+ | T[EMPLATE] | -R[EGION] | [-REGION-qualifier...] |
+ |------------+------------------+----------------------------------------|
+ | - | -S[EGMENT] | [ -SEGMENT-qualifier...] |
+ |------------+------------------+----------------------------------------|
+ | V[ERIFY] | -N[AME] | [name-space] |
+ |------------+------------------+----------------------------------------|
+ | - | -R[EGION] | [region-name] |
+ |------------+------------------+----------------------------------------|
+ | - | -S[EGMENT] | [segment-name] |
+ |------------+------------------+----------------------------------------|
+ | - | -M[AP] | N/A |
+ |------------+------------------+----------------------------------------|
+ | - | -T[EMPLATE] | N/A |
+ |------------+------------------+----------------------------------------|
+ | - | -A[LL]* | N/A |
+ +------------------------------------------------------------------------+
+
+2 Qualifier_Summary
+ Qualifier Summary
+
+ The following table summarizes all qualifiers for the ADD, CHANGE, and
+ TEMPLATE commands. The defaults are those supplied by FIS.
+
+ +------------------------------------------------------------------------------------------------+
+ | GDE Command Qualifiers |
+ |------------------------------------------------------------------------------------------------|
+ | QUALIFIER | DEF | MIN | MAX | NAM | REG | SEG |
+ |------------------------------------------------------------------------------------------------|
+ | * DEFAULT is the default region- and segment-name |
+ | ** MUMPS is the default file-name |
+ | *** May vary by platform |
+ | **** -NONULL_SUBSCRIPTS |
+ |------------------------------------------------------------------------------------------------|
+ |-AC[CESS_METHOD]=code |BG |- |- |- |- |X |
+ |--------------------------------------------+-------+-----+-------------------+-----+-----+-----|
+ |-AL[LOCATION]=size(blocks) |100 |10 |1040187392(992Mi) |- |- |X |
+ |--------------------------------------------+-------+-----+-------------------+-----+-----+-----|
+ |-BL[OCK_SIZE]=size(bytes) |1024 |512 |65024 |- |- |X |
+ |--------------------------------------------+-------+-----+-------------------+-----+-----+-----|
+ |-C[OLLATION_SEQUENCE]=id-number (integer) |0 |0 |255 |- |X |- |
+ |--------------------------------------------+-------+-----+-------------------+-----+-----+-----|
+ |-D[YNAMIC_SEGMENT]=segment-name (chars) |* |1A |16A/N |- |X |- |
+ |--------------------------------------------+-------+-----+-------------------+-----+-----+-----|
+ |-EX[TENSION_COUNT]=size (blks) |100 |0 |65535 |- |- |X |
+ |--------------------------------------------+-------+-----+-------------------+-----+-----+-----|
+ |-F[ILE_NAME]=file-name (chars) |** |1A |255A/N |- |- |X |
+ |--------------------------------------------+-------+-----+-------------------+-----+-----+-----|
+ |-G[LOBAL_BUFFER_COUNT]=size (blocks) |1024 |64 |2147483647 *** |- |- |X |
+ | |*** | | | | | |
+ |--------------------------------------------+-------+-----+-------------------+-----+-----+-----|
+ |-K[EY_SIZE]=size (bytes) |64 |3 |1019 |- |X |- |
+ |--------------------------------------------+-------+-----+-------------------+-----+-----+-----|
+ |-L[OCK_SPACE]=size (pages) |40 |10 |65536 |- |- |X |
+ |--------------------------------------------+-------+-----+-------------------+-----+-----+-----|
+ |-[NO]INST[_FREEZE_ON_ERROR] |FALSE |- |- |- |X |- |
+ |--------------------------------------------+-------+-----+-------------------+-----+-----+-----|
+ |-[NO]Q[DBRUNDOWN] |FALSE |- |- |- |X |- |
+ |--------------------------------------------+-------+-----+-------------------+-----+-----+-----|
+ |-[NO]J[OURNAL]=option-list |-NOJ |- |- |- |X |- |
+ |--------------------------------------------+-------+-----+-------------------+-----+-----+-----|
+ |-N[ULL_SUBSCRIPTS]=[ALWAYS|NEVER|EXISTING] |NEVER |- |- |- |X |- |
+ | |or ****| | | | | |
+ |--------------------------------------------+-------+-----+-------------------+-----+-----+-----|
+ |-[NO]STDNULLCOLL[=TRUE|FALSE] |FALSE |- |- |- |X |- |
+ |--------------------------------------------+-------+-----+-------------------+-----+-----+-----|
+ |-R[ECORD_SIZE]=size (bytes) |256 |7 |1048576 |- |X |- |
+ |--------------------------------------------+-------+-----+-------------------+-----+-----+-----|
+ |-R[EGION] region-name (chars) |* |1A |16A/N |X |- |- |
+ |--------------------------------------------+-------+-----+-------------------+-----+-----+-----|
+ |-R[ESERVED_BYTES]=size (bytes) |0 |0 |blocksize |- |- |X |
+ +------------------------------------------------------------------------------------------------+
diff --git a/sr_port/gdemap.m b/sr_port/gdemap.m
index 46deb78..db15bd6 100644
--- a/sr_port/gdemap.m
+++ b/sr_port/gdemap.m
@@ -1,6 +1,6 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ;
-; Copyright 2010 Fidelity Information Services, Inc ;
+; Copyright 2010, 2013 Fidelity Information Services, Inc ;
; ;
; This source code contains the intellectual property ;
; of its copyright holder(s), and is made available ;
@@ -39,48 +39,141 @@ SHOWNAM
q
;----------------------------------------------------------------------------------------------------------------------------------
MAP2NAM(list)
- n ar,l,s,x,xl,xn,xp,xt,xv
- s x=$o(list("")) q:x'="#)" 0
- s x=$o(list(x))
- i x="%" s list("$")=list("%") k list("%")
- e q:x'="$" 0
- s s=$ztr($zj("",SIZEOF("mident"))," ",$zch(255)),x=$o(list(""),-1) q:x'=s 0
- k ar,nams s nams=0,ar(0,s)="",x=$o(list(x),-1)
- i x'="$",list(x)'=list(s) s xp="z" f q:xp="" s xn=xp_"*",(nams(xn),ar(1,xn))="",xp=$$lexprev(xp)
- f q:x="$" d s x=$o(list(x),-1)
- . i $d(list(x_")")) q
- . s xl=$zl(x)
- . i $ze(x,xl)=")" s xn=$ze(x,1,xl-1),(nams(xn))="" q
- . i xl+1'<SIZEOF("mident") s (ar(SIZEOF("mident")+1,x),nams(x))="" q
- . s xp=x,(ip,in)=0,star=$s(xl<(SIZEOF("mident")-1):"*",1:"")
- . f s xp=$$lexprev(xp),l=$zl(xp) q:'l s ip=ip+1 q:l=xl&$d(list(xp))
- . i ip'=1 s xn=x f s xn=$$lexnext(xn),l=$zl(xn) q:'l s in=in+1 q:l'>xl&($d(list(xn))!$d(list(xn_")")))
- . i ip,ip'>in!($zl($ztr(x,"z"))&(xl+1=SIZEOF("mident")!'in)) do
- . . s xp=x f ip=1:1:ip s xp=$$lexprev(xp),xn=xp_star,(nams(xn),ar(xl,xn))=""
- . e s:'in&'$zl($ztr(x,"z")) in=1 s xn=x f in=1:1:in d q:$d(nams(xn))!$d(list(xn_")"))
- . . s xp=xn_star,(nams(xp),ar($zl(xn),xp))="",xn=$$lexnext(xn)
- s x="",ok=1
- f xl=1:1:SIZEOF("mident") d q:'ok
- . f s x=$o(ar(xl,x)) q:x="" d q:'ok
- . . s xt=$o(list(x))
- . . i '$zl(xt) s ok=0 q
- . . s xv=list(xt)
- . . i '$zl(xv) s ok=0 q
- . . s xn=$$lexnext($ze(x,1,xl))
- . . f l=xl-1:-1:0 d chkprojection q:$zl(xp)
- i 'ok q 0
- f s x=$o(nams(x)) q:x="" s xn=$o(list(x)),nams(x)=list(xn),nams=nams+1
- s xl=SIZEOF("mident")+1,x=$o(ar(xl,""))
- i $zl(x) f s xt=$o(ar(xl,x)) s xv=nams(x),xn=$$lexnext(x) d q:""=xt s x=xt
- . f l=xl-3:-1:0 d chkprojection q:$zl(xp)
- . i $zl(xt),xt'=xn,$d(nams(x)) f s nams(xn)=nams(x),nams=nams+1,xn=$$lexnext(xn) q:xt']xn
- s nams("#")=list("#)"),nams("*")=list("$"),nams=nams+2
+ n maxMap,currMap,currMapLen,prevMap,prevMapLen,currReg,prevPrefix,currPrefix
+ n namSpc,currNam,currNamLen,stopLoop,i,startMap,midentSize,prevPrevMap
+ s currMap=$o(list("")) q:currMap'="#)" 0
+ s currMap=$o(list(currMap))
+ i currMap="%" s list("$")=list("%") ; if "$" is missing, assign it the same value as "%"
+ e q:currMap'="$" 0
+ s maxMap=$ztr($zj("",SIZEOF("mident"))," ",$zch(255)),currMap=$o(list(""),-1) q:currMap'=maxMap 0
+ k nams
+ f q:currMap="$" s prevMap=$o(list(currMap),-1) d s currMap=prevMap
+ . s currReg=list(currMap)
+ . ; Note that with the above mapping, all keys in the range [prevMap,currMap) are mapped to currReg.
+ . ; where [ denotes closed interval and ) denotes open interval i.e. prevMap <= key < currMap
+ . ; Case (1a) : If currMap contains ")" (e.g. "abc)"), it most likely means prevMap would be "abc".
+ . ; In this case, just add "abc" as a namespace. No more processing needed for currMap.
+ . ; Case (1b) : But it is also possible prevMap is not "abc".
+ . ; In this case, do the "abc" namespace addition (as if prevMap was "abc").
+ . ; But also proceed with the current iteration of the for loop as if "currMap" was "abc".
+ . s currMapLen=$zl(currMap)
+ . i $ze(currMap,currMapLen)=")" d q:prevMap=namSpc
+ . . s namSpc=$ze(currMap,1,currMapLen-1),nams(namSpc)=currReg
+ . . i prevMap'=namSpc s currMap=namSpc,currMapLen=currMapLen-1
+ . ; Case (3) : If prevMap contains ")" (e.g. "abc)"), then check to see if its previous entry (say prevPrevMap)
+ . ; is the same region as currReg. If so, we can coalesce the entire range [prevPrevMap,currMap) into one with the
+ . ; exception of "abc" for which add an explicit namespace. Do this for as many ")" prevMap entries that you can find
+ . ; as long as its prevPrevMap entry is the same region as currReg. This could potentially coalesce a lot of intervals.
+ . ; Note: Need to handle a situation like Case (1b) here too. We do this by keeping prevMap as it is but adjusting
+ . ; just prevMapLen to be 1 byte less (to remove trailing ")").
+ . s stopLoop=0
+ . f d q:stopLoop
+ . . s prevMapLen=$zl(prevMap)
+ . . i $ze(prevMap,prevMapLen)'=")" s stopLoop=1 q
+ . . s namSpc=$ze(prevMap,1,$i(prevMapLen,-1))
+ . . s prevPrevMap=$o(list(prevMap),-1)
+ . . i prevPrevMap'=namSpc s stopLoop=1 q
+ . . s nams(namSpc)=list(prevMap)
+ . . i list(prevMap)'=currReg s stopLoop=1 q
+ . . s prevMap=$o(list(prevMap),-1)
+ . . i prevMap="$" s stoploop=1,prevMapLen=1 q
+ . ; Note: At this point prevMap could contain a trailing ")" but in that case prevMapLen would have been adjusted to
+ . ; not consider that last byte. As long as all following usages of prevMap are of the form $ze(prevMap,1,prevMapLen)
+ . ; we will never see the ")" in prevMap.
+ . ; Case (4) : The map entry "currMap" exists and "prevMap" is the previous map entry.
+ . ; Determine the namespaces that potentially lie between the two map entries.
+ . ; And add them to the "nams" array.
+ . f i=1:1:currMapLen i $ze(currMap,i)'=$ze(prevMap,i) q
+ . s matchLen=i-1 ; the length of the maximal common prefix between prevMap and currMap
+ . ; Subcase (4a) : matchLen == prevMapLen
+ . ; In this case we are guaranteed that prevMapLen < currMapLen, and we need to add only ONE namespace.
+ . ; Example prevMap="ag", currMap="agk". Here, matchLen=2, prevMapLen=2, currMapLen=3. Add only "ag*".
+ . i (matchLen=prevMapLen)&(prevMapLen<currMapLen) s namSpc=$ze(prevMap,1,prevMapLen)_"*",nams(namSpc)=currReg q
+ . ; Subcase (4b) : matchLen < prevMapLen
+ . ; Again we are guaranteed that matchLen < currMapLen.
+ . ; Example prevMap="agxy", currMap="ajk". Here, matchLen=1, prevMapLen=4, currMapLen=3
+ . ; In this case, we need to add namespace for "aj*", "ai*", "ah*" as a first step.
+ . ; Whether or not we can add "ag*" depends on an optimization check explained below.
+ . ; If "ag*" can be added, then we add it and are done.
+ . ; If not, then we need to add one or more smaller namespaces under "ag" explained below as the SECOND PART.
+ . ; To explain the optimization check, let us say the "list" variable contains the following.
+ . ; list("ag")="DEFAULT"
+ . ; list("ag)")="STAR2"
+ . ; list("agQ")="STAR1"
+ . ; .
+ . ; .
+ . ; list("agwx")="STAR1"
+ . ; list("agxy")="STAR2"
+ . ; list("ajk")="STAR1" <-- currMap points here
+ . ; Let us say currMap = "ajk". So prevMap = "agxy". In this case, we would definitely add "aj*", "ai*" and "ah*".
+ . ; To determine whether we need to add "ag*", we take a look at where the start of "ag*" namespace maps to.
+ . ; And that would be the entry following list("ag") i.e. list("ag)"). This maps to STAR2 but since it is a point
+ . ; mapping (no * specification), we can skip that as an exception. The next entry list("agQ") maps to STAR1 region.
+ . ; Since this is the same region as the region of currMap, we can safely add just one namespace "ag*" to cover
+ . ; the entire range from list("ag)") to list("ajk") with entries in between covering sub-namespaces that are
+ . ; exceptions (i.e. those which dont map to STAR1). If list("agQ") maps to a region other than STAR1, we need to
+ . ; add more sub-namespaces under the "ag*" namespace which is explained in the SECOND PART below.
+ . ; The FIRST PART of adding "aj*", "ai*" and "ah*" is taken care of by the simple for loop below.
+ . ; There is one exception though.
+ . ; a) If prevMap="ER1" and currMap="ER2", matchLen=2, prevMapLen=3, currMapLen=3
+ . ; But we should not add the "ER2*" namespace.
+ . ; This is achieved by the "i<currMapLen" check before the for loop.
+ . i currMap=maxMap s currMapLen=1,currMap=$zch(1+$za("z")) ; needed to help lexPrev call return "z"
+ . s prevPrefix=$ze(prevMap,1,i),currPrefix=$ze(currMap,1,i)
+ . i (i<currMapLen) s namSpc=currPrefix_"*",nams(namSpc)=currReg
+ . ; Note: If i=1, it is possible that prevMap="$" in which case, $$lexprev would return "%" and then "" (but not "$").
+ . ; So currPrefix=prevPrefix will not work in that case. Hence the additional check for "" return below.
+ . f s currPrefix=$$lexprev(currPrefix) q:(currPrefix=prevPrefix)!('$zl(currPrefix)) d
+ . . s namSpc=currPrefix_"*",nams(namSpc)=currReg
+ . ; Do the optimization check.
+ . s currPrefix=prevPrefix ; reset currPrefix to be equal to prevPrefix just in case it is ""
+ . s startMap=$$findStartMap(currPrefix)
+ . i list(startMap)=currReg s i=prevMapLen ; set i to force skip of SECOND PART of processing below.
+ . ; The SECOND PART does the additional "ag" specific processing. Since the stop point is "agxy", we need to add
+ . ; namespaces "agz*", "agy*" first. And then by the same reasoning (for not adding "ag*" in the FIRST PART),
+ . ; we cannot add "agx*" unless the optimization check says it is okay to do so. Assuming it says that is not okay,
+ . ; we go further down by adding "agxz*" and then "agxy*" and then stop.
+ . f s i=i+1 q:i>prevMapLen d
+ . . s currPrefix=prevPrefix_"z",prevPrefix=$ze(prevMap,1,i)
+ . . f q:currPrefix=prevPrefix s namSpc=currPrefix_"*",nams(namSpc)=currReg,currPrefix=$$lexprev(currPrefix)
+ . . ; Do optimization check at each sub-namespaces level. If it succeeds, stop processing any higher level sub-namespaces.
+ . . s startMap=$$findStartMap(currPrefix)
+ . . i list(startMap)=currReg s i=prevMapLen q ; set i to force quit out of for loop
+ . s namSpc=currPrefix_"*",nams(namSpc)=currReg
+ ; Update "nams" variable to contain # of elements in "nams" array
+ ; Take this opportunity to remove redundant namespaces.
+ ; Example : If "a*" and "ab*" both map to the same region, the namespace "ab*" can be safely removed.
+ ; But if "a*" maps to AREG, "aa*" maps to BREG, and "aaa*" maps to AREG, we cannot remove "aaa*" because
+ ; "a*" and "aaa*" maps to the same reg. This is because there is a more restrictive mapping "aa*" which
+ ; maps to a different region than "aaa*". That should prevail.
+ ; Similarly if "ab*" and "abc" both map to the same region, the namespace "abc" can be safely removed.
+ ; But if "abc*" also is mapped and to a different region than "abc", then "abc" cannot be removed.
+ s currNam="",nams=0
+ ; With SIZEOF("mident")=32, we allow a max of 31-byte global name specifications.
+ ; But with SIZEOF("mident")=8 (for older versions with no longnames support, we allow a max of 8-byte global names.
+ ; Handle this 1-byte discrepancy for the 8-byte case by setting the variable midentSize accordingly.
+ s midentSize=$s(SIZEOF("mident")=8:9,1:SIZEOF("mident"))
+ s nams("*")=list("$")
+ f s currNam=$o(nams(currNam)) q:currNam="" s nams=nams+1 d
+ . s currNamLen=$zl(currNam)
+ . s currReg=nams(currNam)
+ . s killed=0,quitLoop=0
+ . f i=$s($ze(currNam,currNamLen)="*":(currNamLen-2),1:currNamLen):-1:0 d q:quitLoop
+ . . s currPrefix=$ze(currNam,1,i)_"*"
+ . . s prevReg=$g(nams(currPrefix))
+ . . i (""'=prevReg) d
+ . . . s quitLoop=1
+ . . . i currReg=prevReg k nams(currNam) s nams=nams-1,killed=1
+ . i 'killed,currNamLen'<midentSize k nams(currNam) s nams($ze(currNam,1,midentSize-1))=currReg
+ ; Do some final cleanup
+ s nams("#")=list("#)"),nams=nams+1
q 1
;----------------------------------------------------------------------------------------------------------------------------------
lexins:(s)
n x,l
- i s["*" s l=$zl(s),x=$ze(s,1,l),lexnams(l,x)=nams(s)
- e s lexnams(0,s)=nams(s)
+ i s["*" s l=$zl(s)
+ e s l=0
+ s lexnams(l,s)=nams(s)
q
showstar:(i)
s j=""
@@ -120,13 +213,9 @@ lexprev:(s)
i prio]"Z" q s_"Z"
i prio]"9" q:len=1 "%" q s_"9"
q ""
-chkprojection: ; assumes l,x,xt,xv and may change ok & xp
- n xr,xs
- s (xp,xs)=$ze(x,1,l)
- f s xp=$o(ar(l,xp)) s xr=$s('$zl(xp):"",'l:"$",$ze(xp,1,l)'=xs:xt,1:$o(list(xp))) i xs']xr!'$zl(xr)!'l q
- s:'$zl(xr) xp="" q:'$zl(xp)
- i xt=xr&(xl>1) s xp=" " q
- s xp=list(xr)
- i '$zl(xp) s ok=0 q
- i xv=xp k nams(x)
- q
+findStartMap:(key)
+ n startMap
+ s startMap=$o(list(key))
+ s startMapLen=$zl(startMap)
+ i ($ze(startMap,startMapLen)=")")&($ze(startMap,1,startMapLen-1)=key) s startMap=$o(list(startMap))
+ q startMap
diff --git a/sr_port/gdeshow.m b/sr_port/gdeshow.m
index 44ce82f..70240d3 100644
--- a/sr_port/gdeshow.m
+++ b/sr_port/gdeshow.m
@@ -1,6 +1,6 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ;
-; Copyright 2001, 2012 Fidelity Information Services, Inc ;
+; Copyright 2001, 2013 Fidelity Information Services, Inc ;
; ;
; This source code contains the intellectual property ;
; of its copyright holder(s), and is made available ;
@@ -15,7 +15,6 @@ ALL
COMMANDS
s BOL="!"
set delim=$select("VMS"=ver:"/",1:"-")
- set defconst=$select("VMS"=ver:"$DEFAULT",1:"DEFAULT")
i $l($get(cfile)) o cfile:(newversion:exc="w !,$ztatus c cfile zgoto $zl:cfilefail") u cfile d
. d namec,segmentc,regionc,templatec
. c cfile
@@ -44,8 +43,7 @@ namec:
w !,"LOCKS "_delim_"REGION=",nams(s)
f s s=$o(nams(s)) q:'$l(s) d
. i "*"'=s w !,"ADD "_delim_"NAME ",s," "_delim_"REGION=",nams(s) q
- . s defreg=nams(s)
- . i defconst'=defreg w !,"RENAME "_delim_"REGION "_defconst_" ",defreg
+ . i defreg'=nams(s) w !,"CHANGE "_delim_"NAME "_s_" "_delim_"REGION=",nams(s)
w !
q
REGION
@@ -85,10 +83,12 @@ onejnl:
w !,BOL
q
regionc:
- s s=""
+ n defseen,cmd
+ s s="",defseen=FALSE
f s s=$o(regs(s)) q:'$l(s) d
- . i s=defreg s defseg=regs(s,"DYNAMIC_SEGMENT")
- . w !,$s(s=defreg:"CHANGE",1:"ADD")," "_delim_"REGION ",s," "_delim_"DYNAMIC=",regs(s,"DYNAMIC_SEGMENT")
+ . i s=defreg s defseen=TRUE,cmd="CHANGE"
+ . e s cmd="ADD"
+ . w !,cmd," "_delim_"REGION ",s," "_delim_"DYNAMIC=",regs(s,"DYNAMIC_SEGMENT")
. f q="COLLATION_DEFAULT","RECORD_SIZE","KEY_SIZE" w " "_delim,q,"=",regs(s,q)
. w " "_delim_"NULL_SUBSCRIPTS=",$s(regs(s,"NULL_SUBSCRIPTS")=1:"ALWAYS",regs(s,"NULL_SUBSCRIPTS")=2:"EXISTING",1:"NEVER")
. i regs(s,"STDNULLCOLL") w " "_delim_"STDNULLCOLL"
@@ -101,7 +101,7 @@ regionc:
. else w " "_delim_"NOJOURNAL"
. i (ver'="VMS") w " "_delim_$s(regs(s,"INST_FREEZE_ON_ERROR"):"",1:"NO")_"INST_FREEZE_ON_ERROR"
. i (ver'="VMS") w " "_delim_$s(regs(s,"QDBRUNDOWN"):"",1:"NO")_"QDBRUNDOWN"
- i defconst'=defseg w !,"DELETE "_delim_"SEGMENT "_defconst
+ i (FALSE=defseen) w !,"DELETE "_delim_"REGION "_defreg
w !,BOL
q
SEGMENT
@@ -139,9 +139,12 @@ MM w ?x(8),$s(segs(s,"DEFER"):"DEFER",1:"NODEFER")
i $ZVersion'["VMS" w !,BOL,?x(8),"ENCR=OFF"
q
segmentc:
- s s=""
+ n defseen,cmd
+ s s="",defseen=FALSE
f s s=$o(segs(s)) q:'$l(s) s am=segs(s,"ACCESS_METHOD") d
- . w !,$s(s=defseg:"CHANGE",1:"ADD")," "_delim_"SEGMENT ",s," "_delim_"ACCESS_METHOD=",segs(s,"ACCESS_METHOD")
+ . i s=defseg s defseen=TRUE,cmd="CHANGE"
+ . e s cmd="ADD"
+ . w !,cmd," "_delim_"SEGMENT ",s," "_delim_"ACCESS_METHOD=",segs(s,"ACCESS_METHOD")
. i am="USER" q
. f q="BLOCK_SIZE","ALLOCATION","EXTENSION_COUNT","LOCK_SPACE","RESERVED_BYTES" w " "_delim,q,"=",segs(s,q)
. i "BG"=am d
@@ -149,6 +152,7 @@ segmentc:
.. i $zver'["VMS",encsupportedplat=TRUE,segs(s,"ENCRYPTION_FLAG") w " "_delim_"ENCRYPT"
. i "MM"=am w " "_delim,$s(segs(s,"DEFER"):"DEFER",1:"NODEFER")
. w " "_delim_"FILE=",segs(s,"FILE_NAME")
+ i (FALSE=defseen) w !,"DELETE "_delim_"SEGMENT "_defseg
w !,BOL
q
MAP
diff --git a/sr_port/gds_map_moved.c b/sr_port/gds_map_moved.c
index 39030bf..46aba9e 100644
--- a/sr_port/gds_map_moved.c
+++ b/sr_port/gds_map_moved.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -31,7 +31,7 @@ GBLREF sgmnt_data_ptr_t cs_data;
GBLREF gv_namehead *gv_target_list;
-void gds_map_moved(sm_uc_ptr_t new_base, sm_uc_ptr_t old_base, sm_uc_ptr_t old_top, off_t new_eof)
+void gds_map_moved(sm_uc_ptr_t new_base, sm_uc_ptr_t old_base, sm_uc_ptr_t old_top, size_t mmap_sz)
{
int hist_index;
sm_long_t adj;
@@ -41,16 +41,11 @@ void gds_map_moved(sm_uc_ptr_t new_base, sm_uc_ptr_t old_base, sm_uc_ptr_t old_t
csa = cs_addrs;
assert(csa->now_crit);
- /* This initialization has to be done irrespective of whether new_base is different from old_base or not. */
- cs_data = csa->hdr = (sgmnt_data_ptr_t)new_base;
- if (NULL != csa->mm_core_hdr)
- *((sgmnt_data_ptr_t *)csa->mm_core_hdr) = cs_data;
- csa->db_addrs[1] = new_base + new_eof - 1;
- csa->bmm = MM_ADDR(cs_data);
- csa->acc_meth.mm.base_addr = (sm_uc_ptr_t)((sm_uc_ptr_t)cs_data + (cs_data->start_vbn - 1) * DISK_BLOCK_SIZE);
- if (NULL != csa->sgm_info_ptr)
- csa->sgm_info_ptr->tp_csd = csa->hdr;
- bt_init(csa);
+ assert(cs_data == csa->hdr);
+ assert((NULL == csa->sgm_info_ptr) || (csa->hdr == csa->sgm_info_ptr->tp_csd));
+ assert(csa->bmm == MM_ADDR(cs_data));
+ assert(csa->ti == &cs_data->trans_hist);
+ csa->db_addrs[1] = new_base + mmap_sz - 1;
/* The following adjustment needs to be done only if new_base is different from old_base */
if (new_base == old_base)
return;
diff --git a/sr_port/gds_map_moved.h b/sr_port/gds_map_moved.h
index 7a37e5f..f04a2aa 100644
--- a/sr_port/gds_map_moved.h
+++ b/sr_port/gds_map_moved.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2008 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 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 GDS_MAP_MOVED_INCLUDED
#define GDS_MAP_MOVED_INCLUDED
-void gds_map_moved(sm_uc_ptr_t new_base, sm_uc_ptr_t old_base, sm_uc_ptr_t old_top, off_t new_eof);
+void gds_map_moved(sm_uc_ptr_t new_base, sm_uc_ptr_t old_base, sm_uc_ptr_t old_top, size_t mmap_sz);
#endif /* GDS_MAP_MOVED_INCLUDED */
diff --git a/sr_port/gds_rundown.h b/sr_port/gds_rundown.h
index 7f8c548..380fb0b 100644
--- a/sr_port/gds_rundown.h
+++ b/sr_port/gds_rundown.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -15,6 +15,27 @@
#ifdef UNIX
int4 gds_rundown(void);
+#define CAN_BYPASS(SEMVAL, CANCELLED_TIMER, INST_IS_FROZEN) \
+ (((IS_GTM_IMAGE && csd->mumps_can_bypass) && !CANCELLED_TIMER && (PROC_FACTOR * (num_additional_processors + 1) < SEMVAL)) \
+ || ((2 < SEMVAL) && (IS_LKE_IMAGE || IS_DSE_IMAGE)) || INST_IS_FROZEN)
+
+#define CANCEL_DB_TIMERS(region, csa, cancelled_timer, cancelled_dbsync_timer) \
+{ \
+ if (csa->timer) \
+ { \
+ cancel_timer((TID)region); \
+ if (NULL != csa->nl) \
+ DECR_CNT(&csa->nl->wcs_timers, &csa->nl->wc_var_lock); \
+ cancelled_timer = TRUE; \
+ csa->timer = FALSE; \
+ } \
+ if (csa->dbsync_timer) \
+ { \
+ CANCEL_DBSYNC_TIMER(csa); \
+ cancelled_dbsync_timer = TRUE; \
+ } \
+}
+
/* A multiplicative factor to the # of processors used in determining if a GT.M process in gds_rundown can bypass semaphores */
#ifdef DEBUG
# define PROC_FACTOR 2
@@ -26,9 +47,4 @@ int4 gds_rundown(void);
void gds_rundown(void);
#endif
-#define CAN_BYPASS(SEMVAL, CANCELLED_TIMER, INST_IS_FROZEN) \
- (((IS_GTM_IMAGE && csd->mumps_can_bypass) && !CANCELLED_TIMER && (PROC_FACTOR * (num_additional_processors + 1) < SEMVAL)) \
- || ((2 < SEMVAL) && (IS_LKE_IMAGE || IS_DSE_IMAGE)) || INST_IS_FROZEN)
-
-
#endif /* GDS_RUNDOWN_INCLUDED */
diff --git a/sr_port/gdsbgtr.h b/sr_port/gdsbgtr.h
index 949d6a3..ed25755 100644
--- a/sr_port/gdsbgtr.h
+++ b/sr_port/gdsbgtr.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2005 Fidelity Information Services, Inc *
+ * Copyright 2005, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -19,7 +19,7 @@
*/
-#define BG_TRACE_PRO_ANY(C, X) {C->hdr->X##_cntr++; C->hdr->X##_tn = C->ti->curr_tn;}
+#define BG_TRACE_PRO_ANY(C, X) {C->hdr->X##_cntr++; C->hdr->X##_tn = C->hdr->trans_hist.curr_tn ;}
#define BG_TRACE_PRO(Q) BG_TRACE_PRO_ANY(cs_addrs, Q)
#ifdef DEBUG
diff --git a/sr_port/gdsbml.h b/sr_port/gdsbml.h
index df30ca1..da27e4d 100644
--- a/sr_port/gdsbml.h
+++ b/sr_port/gdsbml.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -55,7 +55,7 @@
UNIX_ONLY(DEBUG_ONLY(|| (gtm_white_box_test_case_enabled \
&& (WBTEST_ANTIFREEZE_DBBMLCORRUPT == gtm_white_box_test_case_number))))) \
{ \
- send_msg(VARLSTCNT(9) ERR_DBBMLCORRUPT, 7, DB_LEN_STR(region), \
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_DBBMLCORRUPT, 7, DB_LEN_STR(region), \
blk, (bp)->bsiz, (bp)->levl, &(bp)->tn, &csa->ti->curr_tn); \
status = FALSE; \
} else \
@@ -84,6 +84,50 @@
#define MASTER_MAP_BITS_PER_LMAP 1
+
+#define DETERMINE_BML_FUNC_COMMON(FUNC, CS, CSA) \
+{ \
+ FUNC = (CS->reference_cnt > 0) ? bml_busy : (CSA->hdr->db_got_to_v5_once ? bml_recycled : bml_free); \
+}
+#ifndef UNIX
+ #define DETERMINE_BML_FUNC(FUNC, CS, CSA) DETERMINE_BML_FUNC_COMMON(FUNC, CS, CSA)
+#else
+# define DETERMINE_BML_FUNC(FUNC, CS, CSA) \
+{ \
+ GBLREF boolean_t mu_reorg_upgrd_dwngrd_in_prog; \
+ \
+ if (CSA->nl->trunc_pid) \
+ { /* A truncate is in progress. If we are acquiring a block, we need to update cnl->highest_lbm_with_busy_blk to \
+ * avoid interfering with the truncate. If we are truncate doing a t_recycled2free mini-transaction, we need to \
+ * select bml_free. \
+ */ \
+ if (cs->reference_cnt > 0) \
+ { \
+ FUNC = bml_busy; \
+ CSA->nl->highest_lbm_with_busy_blk = MAX(CS->blk, CSA->nl->highest_lbm_with_busy_blk); \
+ } else if (cs->reference_cnt < 0) \
+ { \
+ if (CSA->hdr->db_got_to_v5_once && (CSE_LEVEL_DRT_LVL0_FREE != CS->level)) \
+ FUNC = bml_recycled; \
+ else \
+ { /* always set the block as free when gvcst_bmp_mark_free a level-0 block in DIR tree; reset \
+ * level since t_end will call bml_status_check which has an assert for bitmap block level \
+ */ \
+ FUNC = bml_free; \
+ CS->level = LCL_MAP_LEVL; \
+ } \
+ } else /* cs->reference_cnt == 0 */ \
+ { \
+ if (CSA->hdr->db_got_to_v5_once && mu_reorg_upgrd_dwngrd_in_prog) \
+ FUNC = bml_recycled; \
+ else \
+ FUNC = bml_free; \
+ } \
+ } else /* Choose bml_func as it was chosen before truncate feature. */ \
+ DETERMINE_BML_FUNC_COMMON(FUNC, CS, CSA); \
+}
+#endif
+
int4 bml_find_free(int4 hint, uchar_ptr_t base_addr, int4 total_bits);
int4 bml_init(block_id bml);
uint4 bml_busy(uint4 setbusy, sm_uc_ptr_t map);
diff --git a/sr_port/gdsbt.h b/sr_port/gdsbt.h
index 137b70f..8856aef 100644
--- a/sr_port/gdsbt.h
+++ b/sr_port/gdsbt.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -218,8 +218,8 @@ typedef struct
typedef struct { /* keep this structure and member offsets defined in sr_avms/mutex.mar in sync */
int4 mutex_hard_spin_count;
int4 mutex_sleep_spin_count;
- int4 mutex_spin_sleep_mask;
- int4 filler1;
+ int4 mutex_spin_sleep_mask; /* currently unused */
+ int4 mutex_que_entry_space_size; /* total number of entries */
} mutex_spin_parms_struct;
enum crit_ops
@@ -475,7 +475,7 @@ typedef struct node_local_struct
cnl->crit_ops_array[coidx].epid = process_id; \
cnl->crit_ops_array[coidx].crit_act = (X); \
cnl->crit_ops_array[coidx].curr_tn = (NULL != csa->hdr) ? \
- csa->ti->curr_tn : 0; \
+ csa->hdr->trans_hist.curr_tn : 0; \
}
/* The following macro checks that curr_tn and early_tn are equal right before beginning a transaction commit.
@@ -592,12 +592,28 @@ typedef struct node_local_struct
#define BT_NOT_ALIGNED(bt, bt_base) (!IS_PTR_ALIGNED((bt), (bt_base), SIZEOF(bt_rec)))
#define BT_NOT_IN_RANGE(bt, bt_lo, bt_hi) (!IS_PTR_IN_RANGE((bt), (bt_lo), (bt_hi)))
-#define NUM_CRIT_ENTRY 1024
-#define CRIT_SPACE (NUM_CRIT_ENTRY * SIZEOF(mutex_que_entry) + SIZEOF(mutex_struct))
-#define NODE_LOCAL_SIZE (ROUND_UP(SIZEOF(node_local), OS_PAGE_SIZE))
-#define NODE_LOCAL_SPACE (ROUND_UP(CRIT_SPACE + NODE_LOCAL_SIZE, OS_PAGE_SIZE))
+#define MIN_CRIT_ENTRY 1024
+#define MAX_CRIT_ENTRY 32768
+#define DEFAULT_NUM_CRIT_ENTRY 1024
+#define NUM_CRIT_ENTRY(CSD) (CSD)->mutex_spin_parms.mutex_que_entry_space_size
+#define CRIT_SPACE(ENTRIES) ((ENTRIES) * SIZEOF(mutex_que_entry) + SIZEOF(mutex_struct))
+#define JNLPOOL_CRIT_SPACE CRIT_SPACE(DEFAULT_NUM_CRIT_ENTRY)
+#define NODE_LOCAL_SIZE (ROUND_UP(SIZEOF(node_local), OS_PAGE_SIZE))
+#define NODE_LOCAL_SPACE(CSD) (ROUND_UP(CRIT_SPACE(NUM_CRIT_ENTRY(CSD)) + NODE_LOCAL_SIZE, OS_PAGE_SIZE))
+#define MIN_NODE_LOCAL_SPACE (ROUND_UP(CRIT_SPACE(MIN_CRIT_ENTRY) + NODE_LOCAL_SIZE, OS_PAGE_SIZE))
/* In order for gtmsecshr not to pull in OTS library, NODE_LOCAL_SIZE_DBS is used in secshr_db_clnup instead of NODE_LOCAL_SIZE */
-#define NODE_LOCAL_SIZE_DBS (ROUND_UP(SIZEOF(node_local), DISK_BLOCK_SIZE))
+#define NODE_LOCAL_SIZE_DBS (ROUND_UP(SIZEOF(node_local), DISK_BLOCK_SIZE))
+
+#define INIT_NUM_CRIT_ENTRY_IF_NEEDED(CSD) \
+{ /* The layout of shared memory depends on the number of mutex queue entries specified in the file header. Thus in \
+ * order to set, for example, csa->critical or csa->shmpool_buffer, we need to know this number. However, this \
+ * number can be zero if we have not yet done db_auto_upgrade. So go ahead and upgrade to the value that will \
+ * eventually be used, which is DEFAULT_NUM_CRIT_ENTRY. \
+ */ \
+ /* Be safe in PRO and check if we need to initialize crit entries, even for GDSMV60002 and later. */ \
+ if (0 == NUM_CRIT_ENTRY(CSD)) \
+ NUM_CRIT_ENTRY(CSD) = DEFAULT_NUM_CRIT_ENTRY; \
+}
/* Define pointer types for above structures that may be in shared memory and need 64
bit pointers. */
diff --git a/sr_port/gdsdbver.h b/sr_port/gdsdbver.h
index 75fc484..fbaa364 100644
--- a/sr_port/gdsdbver.h
+++ b/sr_port/gdsdbver.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2005, 2012 Fidelity Information Services, Inc *
+ * Copyright 2005, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -67,6 +67,8 @@ enum mdb_ver
* before_trunc_file_size) for fixing interrupted MUPIP REORG -TRUNCATE.
*/
GDSMV60000, /* New freeze_on_fail field for anticipatory freeze; the wc_blocked field moved to shared memory */
+ GDSMV60001,
+ GDSMV60002, /* New field mutex_spin_parms.mutex_que_entry_space_size for configurable mutex queue size */
GDSMVLAST
};
#define GDSMVCURR ((enum mdb_ver)(GDSMVLAST - 1))
diff --git a/sr_port/gdsfhead.h b/sr_port/gdsfhead.h
index bb76995..eba3477 100644
--- a/sr_port/gdsfhead.h
+++ b/sr_port/gdsfhead.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -40,6 +40,7 @@ error_def(ERR_DBENDIAN);
error_def(ERR_DBFLCORRP);
error_def(ERR_GVIS);
error_def(ERR_GVSUBOFLOW);
+error_def(ERR_MMFILETOOLARGE);
error_def(ERR_REPLINSTMISMTCH);
error_def(ERR_REPLREQROLLBACK);
error_def(ERR_SCNDDBNOUPD);
@@ -51,64 +52,7 @@ error_def(ERR_STACKOFLOW);
error_def(ERR_TNTOOLARGE);
error_def(ERR_TNWARN);
-/* all this record's fields should exactly be the first members of the cache_rec in the same order */
-typedef struct mmblk_rec_struct
-{
- struct
- {
- sm_off_t fl;
- sm_off_t bl;
- }
- blkque, /* cache records whose block numbers hash to the same location */
- state_que; /* cache records in same state (either wip or active) */
- union
- {
- short semaphore;
- volatile int4 latch; /* int required for atomic swap on Unix */
- /* volatile required as this value is referenced outside of the lock in db_csh_getn() */
- } interlock;
- block_id blk;
- uint4 refer;
- enum db_ver ondsk_blkver; /* Actual block version from block header as it exists on disk
- (prior to any dynamic conversion that may have occurred when read in).
- */
- trans_num dirty;
-} mmblk_rec;
-
-/* all the fields of this record should exactly be the first members of the cache_state_rec in the same order */
-typedef struct mmblk_state_rec_struct
-{
- struct
- {
- sm_off_t fl;
- sm_off_t bl;
- }
- state_que; /* WARNING -- from this point onwards this should be identical to a mmblk_rec */
- union
- {
- short semaphore;
- volatile int4 latch; /* int required for atomic swap on Unix */
- /* volatile required as this value is referenced outside of the lock in db_csh_getn() */
- } interlock;
- block_id blk;
- uint4 refer;
- enum db_ver ondsk_blkver; /* Actual block version from block header as it exists on disk
- (prior to any dynamic conversion that may have occurred when read in).
- */
- trans_num dirty;
-} mmblk_state_rec;
-
-typedef struct
-{
- mmblk_que_head mmblkq_wip, /* write-in-progress queue -- unused in Unix */
- mmblkq_active; /* active queue */
- mmblk_rec mmblk_array[1]; /* the first mmblk record */
-} mmblk_que_heads;
-
-
- /* need to keep quadword aligned */
-
-/* Cache record -- NOTE: the head portion of this should exactly match with mmblk_rec */
+/* Cache record */
typedef struct cache_rec_struct
{
struct
@@ -179,7 +123,7 @@ typedef struct cache_rec_struct
on some platforms where processes are already running near the edge.
*/
-/* cache_state record -- NOTE: the first few fields of this should be identical to that of mmblk_state_rec */
+/* cache_state record */
typedef struct
{
struct
@@ -270,12 +214,6 @@ 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;
-typedef mmblk_que_head *mmblk_que_head_ptr_t;
-typedef mmblk_rec *mmblk_rec_ptr_t;
-typedef mmblk_rec **mmblk_rec_ptr_ptr_t;
-typedef mmblk_state_rec *mmblk_state_rec_ptr_t;
-typedef mmblk_que_heads *mmblk_que_heads_ptr_t;
-
void verify_queue_lock(que_head_ptr_t qhdr);
void verify_queue(que_head_ptr_t qhdr);
@@ -293,6 +231,34 @@ void verify_queue(que_head_ptr_t qhdr);
#define VERIFY_QUEUE_LOCK(base,latch)
#endif
+#define BLK_ZERO_OFF(CSD) ((CSD->start_vbn - 1) * DISK_BLOCK_SIZE)
+#ifdef UNIX
+# ifdef GTM64
+# define CHECK_LARGEFILE_MMAP(REG, MMAP_SZ)
+# else
+# define CHECK_LARGEFILE_MMAP(REG, MMAP_SZ) \
+{ \
+ assert(SIZEOF(gtm_uint64_t) == SIZEOF(MMAP_SZ)); \
+ assert(0 < MMAP_SZ); \
+ if (MAXUINT4 < (gtm_uint64_t)(MMAP_SZ)) \
+ rts_error_csa(CSA_ARG(REG2CSA(REG)) VARLSTCNT(6) ERR_MMFILETOOLARGE, 4, REG_LEN_STR(REG), \
+ DB_LEN_STR(REG)); \
+}
+# endif
+# define MMAP_FD(FD, SIZE, OFFSET, READ_ONLY) mmap((caddr_t)NULL, SIZE, MM_PROT_FLAGS(READ_ONLY), GTM_MM_FLAGS, FD, OFFSET)
+# define MSYNC(BEGPTR, ENDPTR) (BEGPTR ? DBG_ASSERT(BEGPTR < ENDPTR) msync(BEGPTR, (ENDPTR - BEGPTR), MS_SYNC) \
+ : 0)
+# define MM_PROT_FLAGS(READ_ONLY) (READ_ONLY ? PROT_READ : (PROT_READ | PROT_WRITE))
+# define MM_BASE_ADDR(CSA) (sm_uc_ptr_t)CSA->db_addrs[0]
+# define SET_MM_BASE_ADDR(CSA, CSD)
+#else
+# define MM_BASE_ADDR(CSA) (sm_uc_ptr_t)CSA->acc_meth.mm.base_addr
+# define SET_MM_BASE_ADDR(CSA, CSD) \
+{ \
+ CSA->acc_meth.mm.base_addr = (sm_uc_ptr_t)((sm_long_t)CSD + (off_t)(CSD->start_vbn - 1) * DISK_BLOCK_SIZE); \
+}
+#endif
+
/* The following 3 macros were introduced while solving a problem with $view where a call to $view in */
/* mumps right after a change to $zgbldir gave the old global directory - not the new one. On VMS it */
/* caused a core dump. If one were to access a global variable via $data right after the change, however, */
@@ -542,10 +508,7 @@ void verify_queue(que_head_ptr_t qhdr);
assert(cse->blk == cache_start[bufindx].blk); \
assert(dse_running || write_after_image || (process_id == cache_start[bufindx].in_cw_set)); \
} else \
- { \
- assert(cse->old_block == csa->db_addrs[0] + (off_t)cse->blk * csd->blk_size \
- + (off_t)(csd->start_vbn - 1) * DISK_BLOCK_SIZE); \
- } \
+ assert(cse->old_block == MM_BASE_ADDR(csa) + (off_t)cse->blk * csd->blk_size); \
} \
}
@@ -960,7 +923,7 @@ GBLREF int4 pin_fail_phase2_commit_pidcnt; /* Number of processes in phase2 com
jnlpool_detach(); \
assert(NULL == jnlpool.jnlpool_ctl); \
assert(FALSE == pool_init); \
- rts_error(VARLSTCNT(1) ERR_SCNDDBNOUPD); \
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_SCNDDBNOUPD); \
} \
CSA->jnlpool_validate_check |= SCNDDBNOUPD_CHECK_DONE; \
} \
@@ -993,8 +956,9 @@ GBLREF int4 pin_fail_phase2_commit_pidcnt; /* Number of processes in phase2 com
jnlpool_detach(); \
assert(NULL == jnlpool.jnlpool_ctl); \
assert(FALSE == pool_init); \
- rts_error(VARLSTCNT(10) ERR_REPLINSTMISMTCH, 8, LEN_AND_STR(instfilename_copy), jnlpool_shmid, \
- DB_LEN_STR(REG), LEN_AND_STR(CNL->replinstfilename), CNL->jnlpool_shmid); \
+ rts_error_csa(CSA_ARG(CSA) VARLSTCNT(10) ERR_REPLINSTMISMTCH, 8, \
+ LEN_AND_STR(instfilename_copy), jnlpool_shmid, DB_LEN_STR(REG), \
+ LEN_AND_STR(CNL->replinstfilename), CNL->jnlpool_shmid); \
} \
CSA->jnlpool_validate_check |= REPLINSTMISMTCH_CHECK_DONE; \
} \
@@ -1016,6 +980,27 @@ GBLREF int4 pin_fail_phase2_commit_pidcnt; /* Number of processes in phase2 com
} \
}
+#define ASSERT_VALID_JNLPOOL(CSA) \
+{ \
+ GBLREF jnlpool_ctl_ptr_t jnlpool_ctl; \
+ GBLREF jnlpool_addrs jnlpool; \
+ \
+ assert(CSA && CSA->critical && CSA->nl); /* should have been setup in mu_rndwn_replpool */ \
+ assert(jnlpool_ctl && (jnlpool_ctl == jnlpool.jnlpool_ctl)); \
+ assert(CSA->critical == (mutex_struct_ptr_t)((sm_uc_ptr_t)jnlpool.jnlpool_ctl + JNLPOOL_CTL_SIZE)); \
+ assert(CSA->nl == (node_local_ptr_t) ((sm_uc_ptr_t)CSA->critical + JNLPOOL_CRIT_SPACE \
+ + SIZEOF(mutex_spin_parms_struct))); \
+ assert(jnlpool_ctl->filehdr_off); \
+ assert(jnlpool_ctl->srclcl_array_off > jnlpool.jnlpool_ctl->filehdr_off); \
+ assert(jnlpool_ctl->sourcelocal_array_off > jnlpool.jnlpool_ctl->srclcl_array_off); \
+ assert(jnlpool.repl_inst_filehdr == (repl_inst_hdr_ptr_t) ((sm_uc_ptr_t)jnlpool_ctl \
+ + jnlpool_ctl->filehdr_off)); \
+ assert(jnlpool.gtmsrc_lcl_array == (gtmsrc_lcl_ptr_t)((sm_uc_ptr_t)jnlpool_ctl \
+ + jnlpool_ctl->srclcl_array_off)); \
+ assert(jnlpool.gtmsource_local_array == (gtmsource_local_ptr_t)((sm_uc_ptr_t)jnlpool_ctl \
+ + jnlpool_ctl->sourcelocal_array_off)); \
+}
+
/* Explanation for why we need the following macro.
*
* Normally a cdb_sc_blkmod check is done using the "bt". This is done in t_end and tp_tend.
@@ -1235,10 +1220,11 @@ GBLREF int4 pin_fail_phase2_commit_pidcnt; /* Number of processes in phase2 com
jpc = csa->jnl; \
assert(NULL != jpc); \
if (SS_NORMAL != jpc->status) \
- rts_error(VARLSTCNT(7) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(gv_cur_region), \
- jpc->status); \
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(7) jnl_status, 4, JNL_LEN_STR(csd), \
+ DB_LEN_STR(gv_cur_region), jpc->status); \
else \
- rts_error(VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(gv_cur_region)); \
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd), \
+ DB_LEN_STR(gv_cur_region)); \
} \
} \
}
@@ -1351,11 +1337,14 @@ enum tp_blkmod_type /* used for accounting in cs_data->tp_cdb_sc_blkmod[] */
* the restart will anyway be detected before commit. In this cases, this variable will take on non-zero values.
* The commit logic will assert that this variable is indeed zero after validation but before proceeding with commit.
*/
-#define DONOTCOMMIT_TPHIST_BLKTARGET_MISMATCH (1 << 0) /* Restartable situation encountered in tp_hist */
-#define DONOTCOMMIT_GVCST_DELETE_BLK_CSE_TLEVEL (1 << 1) /* Restartable situation encountered in gvcst_delete_blk */
-#define DONOTCOMMIT_JNLGETCHECKSUM_NULL_CR (1 << 2) /* Restartable situation encountered in jnl_get_checksum.h */
-#define DONOTCOMMIT_GVCST_KILL_ZERO_TRIGGERS (1 << 3) /* Restartable situation encountered in gvcst_kill */
-#define DONOTCOMMIT_GVCST_BLK_BUILD_TPCHAIN (1 << 4) /* Restartable situation encountered in gvcst_blk_build */
+#define DONOTCOMMIT_TPHIST_BLKTARGET_MISMATCH (1 << 0) /* Restartable situation encountered in tp_hist */
+#define DONOTCOMMIT_GVCST_DELETE_BLK_CSE_TLEVEL (1 << 1) /* Restartable situation encountered in gvcst_delete_blk */
+#define DONOTCOMMIT_JNLGETCHECKSUM_NULL_CR (1 << 2) /* Restartable situation encountered in jnl_get_checksum.h */
+#define DONOTCOMMIT_GVCST_KILL_ZERO_TRIGGERS (1 << 3) /* Restartable situation encountered in gvcst_kill */
+#define DONOTCOMMIT_GVCST_BLK_BUILD_TPCHAIN (1 << 4) /* Restartable situation encountered in gvcst_blk_build */
+#define DONOTCOMMIT_T_QREAD_BAD_PVT_BUILD (1 << 5) /* Restartable situation due to bad private build in t_qread */
+#define DONOTCOMMIT_GVCST_SEARCH_LEAF_BUFFADR_NOTSYNC (1 << 6) /* Restartable situation encountered in gvcst_search */
+#define DONOTCOMMIT_GVCST_SEARCH_BLKTARGET_MISMATCH (1 << 7) /* Restartable situation encountered in gvcst_search */
#define TAB_BG_TRC_REC(A,B) B,
enum bg_trc_rec_type
@@ -1391,7 +1380,8 @@ typedef union
endian32_struct check_endian; \
check_endian.word32 = (CSD)->minor_dbver; \
if (!check_endian.shorts.ENDIANCHECKTHIS) \
- rts_error(VARLSTCNT(6) ERR_DBENDIAN, 4, FNLEN, FNNAME, ENDIANOTHER, ENDIANTHIS); \
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_DBENDIAN, 4, FNLEN, FNNAME, ENDIANOTHER, \
+ ENDIANTHIS); \
}
/* This is the structure describing a segment. It is used as a database file header (for MM or BG access methods).
@@ -1708,8 +1698,11 @@ typedef struct
typedef struct
{
+# ifdef VMS
FILL8DCL(sm_uc_ptr_t, base_addr, 1);
- FILL8DCL(mmblk_que_heads_ptr_t, mmblk_state, 2); /* pointer to beginnings of state and blk queues */
+# else
+ int filler;
+# endif
} sgmm_addrs;
#define MAX_NM_LEN MAX_MIDENT_LEN
@@ -1746,9 +1739,11 @@ typedef struct
if (MEMCMP_LIT(TSD->label, GDS_LABEL)) \
{ \
if (memcmp(TSD->label, GDS_LABEL, GDS_LABEL_SZ - 3)) \
- rts_error(VARLSTCNT(4) ERR_DBNOTGDS, 2, DB_LEN_STR(REG)); \
+ rts_error_csa(CSA_ARG(REG2CSA(REG)) VARLSTCNT(4) ERR_DBNOTGDS, 2, \
+ DB_LEN_STR(REG)); \
else \
- rts_error(VARLSTCNT(4) ERR_BADDBVER, 2, DB_LEN_STR(REG)); \
+ rts_error_csa(CSA_ARG(REG2CSA(REG)) VARLSTCNT(4) ERR_BADDBVER, 2, \
+ DB_LEN_STR(REG)); \
} \
}
@@ -1768,12 +1763,17 @@ typedef struct
if (IS_DSE_IMAGE) \
{ \
gtm_errcode = MAKE_MSG_WARNING(gtm_errcode); \
- gtm_putmsg(VARLSTCNT(4) gtm_errcode, 2, DB_LEN_STR(REG)); \
+ gtm_putmsg_csa(CSA_ARG(REG2CSA(REG)) VARLSTCNT(4) gtm_errcode, 2, \
+ DB_LEN_STR(REG)); \
} else \
- rts_error(VARLSTCNT(4) gtm_errcode, 2, DB_LEN_STR(REG)); \
+ rts_error_csa(CSA_ARG(REG2CSA(REG)) VARLSTCNT(4) gtm_errcode, 2, \
+ DB_LEN_STR(REG)); \
} \
}
+#define REG2CSA(REG) (((REG) && (REG)->dyn.addr && (REG)->dyn.addr->file_cntl) ? (&FILE_INFO(REG)->s_addrs) : NULL)
+#define JCTL2CSA(JCTL) (((JCTL) && (JCTL->reg_ctl)) ? (JCTL->reg_ctl->csa) : NULL)
+
typedef struct file_control_struct
{
sm_uc_ptr_t op_buff;
@@ -1955,10 +1955,6 @@ typedef struct sgmnt_addrs_struct
* dirty buffers to disk and when the idle flush timer (5 seconds) popped.
*/
/* 8-byte aligned at this point on all platforms (32-bit, 64-bit or Tru64 which is a mix of 32-bit and 64-bit pointers) */
- sgmnt_data_ptr_t mm_core_hdr; /* Most OSs don't include memory mapped files in the core dump. For MM access
- * mode, this is a pointer to a copy of the header that will be in the corefile.
- * The pointer is only used for MM and that too only in Unix.
- */
size_t fullblockwrite_len; /* Length of a full block write */
uint4 total_blks; /* Last we knew, file was this big. Used to signal MM processing file was
* extended and needs to be remapped. In V55000 was used with BG to detect
@@ -1981,7 +1977,6 @@ typedef struct sgmnt_addrs_struct
block_id reorg_last_dest; /* last destinition block used for swap */
boolean_t jnl_before_image;
boolean_t read_write;
- boolean_t extending;
boolean_t persistent_freeze; /* if true secshr_db_clnup() won't unfreeze this region */
/* The following 3 fields are in cs_addrs instead of in the file-header since they are a function
* of the journal-record sizes that can change with journal-version-numbers (for the same database).
@@ -2477,7 +2472,8 @@ GBLREF sgmnt_addrs *cs_addrs;
assert(KEY_DELIMITER == GVKEY->base[GVKEY->end]); \
endBuff = format_targ_key(fmtBuff, ARRAYSIZE(fmtBuff), GVKEY, TRUE); \
GV_SET_LAST_SUBSCRIPT_INCOMPLETE(fmtBuff, endBuff); /* Note: might update "endBuff" */ \
- rts_error(VARLSTCNT(6) ERR_GVSUBOFLOW, 0, ERR_GVIS, 2, endBuff - fmtBuff, fmtBuff); \
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_GVSUBOFLOW, 0, ERR_GVIS, 2, \
+ endBuff - fmtBuff, fmtBuff); \
}
#define COPY_SUBS_TO_GVCURRKEY(mvarg, max_key, gv_currkey, was_null, is_null) \
@@ -2729,12 +2725,14 @@ typedef enum
\
if ((CSA)->hdr->max_tn <= (TN)) \
{ \
- rts_error(VARLSTCNT(5) ERR_TNTOOLARGE, 3, DB_LEN_STR((CSA)->region), &(CSA)->hdr->max_tn); \
+ rts_error_csa(CSA_ARG(CSA) VARLSTCNT(5) ERR_TNTOOLARGE, 3, DB_LEN_STR((CSA)->region), \
+ &(CSA)->hdr->max_tn); \
assert(FALSE); /* should not come here */ \
} \
assert((CSD)->max_tn > (TN)); \
trans_left = (CSD)->max_tn - (TN); \
- send_msg(VARLSTCNT(6) ERR_TNWARN, 4, DB_LEN_STR((CSA)->region), &trans_left, &(CSD)->max_tn); \
+ send_msg_csa(CSA_ARG(CSA) VARLSTCNT(6) ERR_TNWARN, 4, DB_LEN_STR((CSA)->region), &trans_left, \
+ &(CSD)->max_tn); \
(CSD)->max_tn_warn = (TN) + 1 + ((trans_left - 1) >> 1); \
assert((TN) < (CSD)->max_tn_warn); \
assert((CSD)->max_tn_warn <= (CSD)->max_tn); \
@@ -2781,8 +2779,6 @@ typedef enum
#define CACHE_CONTROL_SIZE(X) \
(ROUND_UP((ROUND_UP((X->bt_buckets + X->n_bts) * SIZEOF(cache_rec) + SIZEOF(cache_que_heads), OS_PAGE_SIZE) \
+ ((gtm_uint64_t)X->n_bts * X->blk_size * (X->is_encrypted ? 2 : 1))), OS_PAGE_SIZE))
-#define MMBLK_CONTROL_SIZE(X) (ROUND_UP((((sgmnt_data_ptr_t)X)->bt_buckets + ((sgmnt_data_ptr_t)X)->n_bts) * SIZEOF(mmblk_rec) \
- + SIZEOF(mmblk_que_heads), OS_PAGE_SIZE))
OS_PAGE_SIZE_DECLARE
@@ -3066,8 +3062,10 @@ 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 */
+#endif
#define RESET_SHMID_CTIME(X) \
{ \
@@ -3105,10 +3103,11 @@ typedef replpool_identifier *replpool_id_ptr_t;
}
#define STANDALONE(x) mu_rndwn_file(x, TRUE)
-#define DBFILOP_FAIL_MSG(status, msg) gtm_putmsg(VARLSTCNT(5) msg, 2, DB_LEN_STR(gv_cur_region), status);
+#define DBFILOP_FAIL_MSG(status, msg) gtm_putmsg_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(5) msg, 2, \
+ DB_LEN_STR(gv_cur_region), status);
#elif defined(VMS)
#define STANDALONE(x) mu_rndwn_file(TRUE) /* gv_cur_region needs to be equal to "x" */
-#define DBFILOP_FAIL_MSG(status, msg) gtm_putmsg(VARLSTCNT(6) msg, 2, DB_LEN_STR(gv_cur_region), status, \
+#define DBFILOP_FAIL_MSG(status, msg) gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) msg, 2, DB_LEN_STR(gv_cur_region), status, \
FILE_INFO(gv_cur_region)->fab->fab$l_stv);
#else
#error unsupported platform
@@ -3116,8 +3115,6 @@ typedef replpool_identifier *replpool_id_ptr_t;
#define CR_NOT_ALIGNED(cr, cr_base) (!IS_PTR_ALIGNED((cr), (cr_base), SIZEOF(cache_rec)))
#define CR_NOT_IN_RANGE(cr, cr_lo, cr_hi) (!IS_PTR_IN_RANGE((cr), (cr_lo), (cr_hi)))
-#define MBR_NOT_ALIGNED(mbr, mbr_base) (!IS_PTR_ALIGNED((mbr), (mbr_base), SIZEOF(mmblk_rec)))
-#define MBR_NOT_IN_RANGE(mbr, mbr_lo, mbr_hi) (!IS_PTR_IN_RANGE((mbr), (mbr_lo), (mbr_hi)))
/* Examine that cr->buffaddr is indeed what it should be. If not, this macro fixes its value by
* recomputing from the cache_array.
@@ -3141,8 +3138,9 @@ typedef replpool_identifier *replpool_id_ptr_t;
bp = bp_lo + ((cr) - (cr_lo)) * csd->blk_size; \
if (bp != cr->buffaddr) \
{ \
- send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk, \
- RTS_ERROR_TEXT("cr->buffaddr"), cr->buffaddr, bp, CALLFROM); \
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), \
+ cr, cr->blk, RTS_ERROR_TEXT("cr->buffaddr"), \
+ cr->buffaddr, bp, CALLFROM); \
cr->buffaddr = bp; \
} \
DEBUG_ONLY(bp_top = bp_lo + (gtm_uint64_t)csd->n_bts * csd->blk_size;) \
@@ -3339,8 +3337,8 @@ typedef replpool_identifier *replpool_id_ptr_t;
{ /* Error encountered outside crit is genuine. Indicate MUPIP INTEG that the \
* snapshot is no more valid \
*/ \
- send_msg(VARLSTCNT(4) ERR_SSATTACHSHM, 1, lcl_ss_ctx->nl_shmid, \
- lcl_failure_errno); \
+ send_msg_csa(CSA_ARG(CSA) VARLSTCNT(4) ERR_SSATTACHSHM, 1, \
+ lcl_ss_ctx->nl_shmid, lcl_failure_errno); \
ss_shm_ptr->failure_errno = lcl_failure_errno; \
ss_shm_ptr->failed_pid = process_id; \
} else /* snapshot context creation done while things were in flux */ \
@@ -3353,7 +3351,7 @@ typedef replpool_identifier *replpool_id_ptr_t;
{ /* Error encountered outside crit is genuine. Indicate MUPIP INTEG that the \
* snapshot is no more valid \
*/ \
- send_msg(VARLSTCNT(7) ERR_SSFILOPERR, 4, LEN_AND_LIT("open"), \
+ send_msg_csa(CSA_ARG(CSA) VARLSTCNT(7) ERR_SSFILOPERR, 4, LEN_AND_LIT("open"), \
LEN_AND_STR(lcl_ss_ctx->shadow_file), lcl_failure_errno); \
ss_shm_ptr->failure_errno = lcl_failure_errno; \
ss_shm_ptr->failed_pid = process_id; \
@@ -3497,7 +3495,7 @@ typedef struct redo_root_search_context_struct
* the necessary stuff. \
*/ \
assert(gtm_trigger_depth == tstart_trigger_depth); \
- rts_error(VARLSTCNT(1) ERR_DBROLLEDBACK); \
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DBROLLEDBACK); \
default: \
break; \
} \
@@ -3573,7 +3571,7 @@ typedef struct redo_root_search_context_struct
ASSERT_BEGIN_OF_FRESH_TP_TRANS; \
frame_pointer->flags |= SFF_IMPLTSTART_CALLD; \
if (est_first_pass && (cdb_sc_onln_rlbk2 == LAST_RESTART_CODE)) \
- rts_error(VARLSTCNT(1) ERR_DBROLLEDBACK); \
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DBROLLEDBACK); \
tp_set_sgm(); \
GVCST_ROOT_SEARCH; \
}
@@ -3782,7 +3780,7 @@ typedef struct
error_def(ERR_UNIMPLOP); /* BYPASSOK */ \
\
if (span_nodes_disallowed) \
- rts_error(VARLSTCNT(6) ERR_UNIMPLOP, 0, ERR_TEXT, 2, \
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_UNIMPLOP, 0, ERR_TEXT, 2, \
LEN_AND_LIT("GT.CM Server does not support spanning nodes")); \
}
# define IF_SN_DISALLOWED_AND_NO_SPAN_IN_DB(STATEMENT) \
@@ -3950,7 +3948,8 @@ void bt_malloc(sgmnt_addrs *csa);
void bt_refresh(sgmnt_addrs *csa, boolean_t init);
void db_common_init(gd_region *reg, sgmnt_addrs *csa, sgmnt_data_ptr_t csd);
void grab_crit(gd_region *reg);
-void grab_lock(gd_region *reg, uint4 onln_rlbk_action);
+boolean_t grab_crit_immediate(gd_region *reg);
+boolean_t grab_lock(gd_region *reg, boolean_t is_blocking_wait, uint4 onln_rlbk_action);
void gv_init_reg(gd_region *reg);
void gvcst_init(gd_region *greg);
enum cdb_sc gvincr_compute_post_incr(srch_blk_status *bh);
diff --git a/sr_port/gdsfilext.h b/sr_port/gdsfilext.h
index b6a7d79..2afb24f 100644
--- a/sr_port/gdsfilext.h
+++ b/sr_port/gdsfilext.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -12,6 +12,15 @@
#ifndef __GDSFILEXT_H__
#define __GDSFILEXT_H__
+#ifdef UNIX
+uint4 gdsfilext(uint4 blocks, uint4 filesize, boolean_t trans_in_prog);
+# define GDSFILEXT(BLOCKS, FILESIZE, TRANS_IN_PROG) gdsfilext(BLOCKS, FILESIZE, TRANS_IN_PROG)
+#else
uint4 gdsfilext(uint4 blocks, uint4 filesize);
+# define GDSFILEXT(BLOCKS, FILESIZE, DUMMY) gdsfilext(BLOCKS, FILESIZE)
+#endif
+
+#define TRANS_IN_PROG_FALSE FALSE
+#define TRANS_IN_PROG_TRUE TRUE
#endif
diff --git a/sr_port/gdsroot.h b/sr_port/gdsroot.h
index 74b9ab7..f3523df 100644
--- a/sr_port/gdsroot.h
+++ b/sr_port/gdsroot.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -41,6 +41,12 @@
*/
#define DBKEYSIZE(KSIZE) (ROUND_UP((KSIZE + MAX_GVKEY_PADDING_LEN), 4))
+/* Possible states for TREF(in_mu_swap_root_state) (part of MUPIP REORG -TRUNCATE) */
+#define MUSWP_NONE 0 /* default; not in mu_swap_root */
+#define MUSWP_INCR_ROOT_CYCLE 1 /* moving a root block; need to increment root_search_cycle */
+#define MUSWP_FREE_BLK 2 /* freeing a directory block; need to write leaf blocks to snapshot file */
+#define MUSWP_DIRECTORY_SWAP 3 /* moving a directory block; just checked by cert_blk */
+
typedef gtm_uint64_t trans_num;
typedef uint4 trans_num_4byte;
diff --git a/sr_port/get_cmd_qlf.c b/sr_port/get_cmd_qlf.c
index 07af250..fc05f60 100644
--- a/sr_port/get_cmd_qlf.c
+++ b/sr_port/get_cmd_qlf.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -14,6 +14,16 @@
#include "cmd_qlf.h"
#include "cli.h"
+#define INIT_QUALIF_STR(QUALIF, CQCODE, FIELD) \
+{ \
+ if ((glb_cmd_qlf.qlf & CQCODE) && (MV_STR == glb_cmd_qlf.FIELD.mvtype) && (0 < glb_cmd_qlf.FIELD.str.len)) \
+ { \
+ QUALIF->FIELD.mvtype = MV_STR; \
+ QUALIF->FIELD.str.len = glb_cmd_qlf.FIELD.str.len; \
+ memcpy(QUALIF->FIELD.str.addr, glb_cmd_qlf.FIELD.str.addr, glb_cmd_qlf.FIELD.str.len); \
+ } \
+}
+
GBLDEF list_params lst_param;
GBLREF command_qualifier glb_cmd_qlf;
@@ -30,6 +40,9 @@ void get_cmd_qlf(command_qualifier *qualif)
qualif->qlf = glb_cmd_qlf.qlf;
qualif->object_file.mvtype = qualif->list_file.mvtype = qualif->ceprep_file.mvtype = 0;
+ INIT_QUALIF_STR(qualif, CQ_OBJECT, object_file);
+ INIT_QUALIF_STR(qualif, CQ_LIST, list_file);
+ INIT_QUALIF_STR(qualif, CQ_CE_PREPROCESS, ceprep_file);
if (gtm_utf8_mode)
qualif->qlf |= CQ_UTF8; /* Mark as being compiled in UTF8 mode */
if (cli_present("OBJECT") == CLI_PRESENT)
@@ -157,4 +170,8 @@ void get_cmd_qlf(command_qualifier *qualif)
s->len = len;
} else if (cli_negated("CE_PREPROCESS") == TRUE)
qualif->qlf &= ~CQ_CE_PREPROCESS;
+# ifdef USHBIN_SUPPORTED
+ if (CLI_PRESENT == cli_present("DYNAMIC_LITERALS"))
+ qualif->qlf |= CQ_DYNAMIC_LITERALS;
+# endif
}
diff --git a/sr_port/get_fs_block_size.c b/sr_port/get_fs_block_size.c
index a4be034..f605a0c 100644
--- a/sr_port/get_fs_block_size.c
+++ b/sr_port/get_fs_block_size.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2010, 2012 Fidelity Information Services, Inc *
+ * Copyright 2010, 2013 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"
+#include "have_crit.h"
+#include "eintr_wrappers.h"
#include "get_fs_block_size.h"
#ifndef VMS
diff --git a/sr_port/golevel.h b/sr_port/golevel.h
index 9d47e76..8d90983 100644
--- a/sr_port/golevel.h
+++ b/sr_port/golevel.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -11,12 +11,11 @@
#ifndef __GOLEVEL_H__
#define __GOLEVEL_H__
-
-
-/* golevel() will unwind up to the counted frame corresponding to level specified by the parm. In a trigger
- * environment, an additional flag that determines if landing on a trigger frame means the unwind should continue
- * or not is supplied. This flag is passed to goframes() which does the actual unwind of a specific number
- * of frames (counted and uncounted). Note goframes is used by both golevel and goerrorframe.
+/* golevel() will unwind up to the counted frame corresponding to level specified by the parm. The first flag indicates
+ * whether or not it is ok to land on a $ZINTERRUPT frame or not (which it is not ok when unwinding a $ZINTERRUPT). Also,
+ * In a trigger environment, an additional flag that determines if landing on a trigger frame means the unwind should
+ * continue or not is supplied. This flag is passed to goframes() which does the actual unwind of a specific number of
+ * rames (counted and uncounted). Note goframes is used by both golevel and goerrorframe.
*/
#ifdef GTM_TRIGGER
#define GOLEVEL(level, unwtrigrframe) golevel(level, unwtrigrframe)
@@ -26,9 +25,10 @@ void goframes(int4 frames, boolean_t unwtrigrframe, boolean_t fromzgoto);
#else
#define GOLEVEL(level, unwtrigrframe) golevel(level)
#define GOFRAMES(frames, unwtrigrframe, fromzgoto) goframes(frames)
-void golevel(int4 level); /* unwind upto the counted frame corresponding to frame level "level" */
-void goframes(int4 frames); /* unwind "frames" number of frames */
+void golevel(int4 level); /* unwind upto the counted frame corresponding to frame level "level" */
+void goframes(int4 frames); /* unwind "frames" number of frames */
#endif
-void goerrorframe(void); /* unwind upto (but not including) the frame pointed to by the "error_frame" global */
-
+void goerrorframe(void); /* unwind upto (but not including) the frame pointed to by the "error_frame"
+ * global
+ */
#endif
diff --git a/sr_port/gtm_common_defs.h b/sr_port/gtm_common_defs.h
index 13b1424..4b75d9c 100644
--- a/sr_port/gtm_common_defs.h
+++ b/sr_port/gtm_common_defs.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2012 Fidelity Information Services, Inc *
+ * Copyright 2012, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -11,61 +11,73 @@
#ifndef GTM_COMMON_DEFS_H
#define GTM_COMMON_DEFS_H
-#ifndef __vms
-# define readonly
-# define GBLDEF
-# define GBLREF extern
-# define LITDEF const
-# define LITREF extern const
-# define error_def(x) LITREF int x
+#if defined(__ia64) || defined(__x86_64__) || defined(__sparc) || defined(__s390__) || defined (_AIX)
+# define GTM64
+#endif
+
+#ifdef GTM64
+# define GTM64_ONLY(X) X
+# define NON_GTM64_ONLY(X)
#else
-# ifdef __cplusplus
+# define GTM64_ONLY(X)
+# define NON_GTM64_ONLY(X) X
+#endif
+
+#ifndef __vms
+# define readonly
# define GBLDEF
-# define GBLREF extern
-# define LITDEF const
-# define LITREF extern const
-# else
-# define GBLDEF globaldef
-# define GBLREF globalref
-# define LITDEF const globaldef
-# define LITREF const globalref
-# endif
+# define GBLREF extern
+# define LITDEF const
+# define LITREF extern const
+# define error_def(x) LITREF int x
+#else
+# ifdef __cplusplus
+# define GBLDEF
+# define GBLREF extern
+# define LITDEF const
+# define LITREF extern const
+# else
+# define GBLDEF globaldef
+# define GBLREF globalref
+# define LITDEF const globaldef
+# define LITREF const globalref
+# endif
#endif
/* Use GBLDEF to define STATICDEF for variables and STATICFNDEF, STATICFNDCL for functions. Define STATICDEF to "GBLDEF". This way
* we know such usages are intended to be "static" but yet can effectively debug these variables since they are externally
* visible. For functions, do not use the "static" keyword to make them externally visible. Note that a STATICREF for variables
* does not make sense since statics are supposed to be used only within one module.
*/
-#define STATICDEF GBLDEF
-#define STATICFNDCL extern
+#define STATICDEF GBLDEF
+#define STATICFNDCL extern
#define STATICFNDEF
#ifndef TRUE
-# define TRUE 1
+# define TRUE 1
#endif
#ifndef FALSE
-# define FALSE 0
+# define FALSE 0
#endif
#ifndef NULL
-# define NULL ((void *) 0)
+# define NULL ((void *) 0)
#endif
#if defined(__ia64) || defined(__MVS__)
-# define INTCAST(X) ((int)(X))
-# define UINTCAST(X) ((uint4)(X))
-# define STRLEN(X) ((int)(strlen(X)))
-# define USTRLEN(X) ((unsigned int)(strlen(X)))
-# define OFFSETOF(X,Y) ((int)(offsetof(X,Y)))
+# define INTCAST(X) ((int)(X))
+# define UINTCAST(X) ((uint4)(X))
+# define STRLEN(X) ((int)(strlen(X)))
+# define USTRLEN(X) ((unsigned int)(strlen(X)))
+# define OFFSETOF(X,Y) ((int)(offsetof(X,Y)))
#else
-# define INTCAST(X) X
-# define UINTCAST(X) X
-# define STRLEN(X) strlen(X)
-# define USTRLEN(X) strlen(X)
-# define OFFSETOF(X,Y) offsetof(X,Y)
+# define INTCAST(X) X
+# define UINTCAST(X) X
+# define STRLEN(X) strlen(X)
+# define USTRLEN(X) strlen(X)
+# define OFFSETOF(X,Y) offsetof(X,Y)
#endif
#ifndef __vms
-#define DIR_SEPARATOR '/'
+# define DIR_SEPARATOR '/'
#endif
/* the LITERAL version of the macro should be used over STRING whenever possible for efficiency reasons */
diff --git a/sr_port/gtm_env_init.c b/sr_port/gtm_env_init.c
index e9d9f9a..3c0675c 100644
--- a/sr_port/gtm_env_init.c
+++ b/sr_port/gtm_env_init.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2004, 2012 Fidelity Information Services, Inc *
+ * Copyright 2004, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -74,6 +74,8 @@ GBLREF uint4 max_cache_entries; /* Maximum number of cached indirect compilatio
GBLREF block_id gtm_tp_allocation_clue; /* block# hint to start allocation for created blocks in TP */
GBLREF boolean_t gtm_stdxkill; /* Use M Standard exclusive kill instead of historical GTM */
GBLREF boolean_t ztrap_new; /* Each time $ZTRAP is set it is automatically NEW'd */
+GBLREF size_t gtm_max_storalloc; /* Used for testing: creates an allocation barrier */
+GBLREF boolean_t ipv4_only; /* If TRUE, only use AF_INET. */
void gtm_env_init(void)
{
@@ -85,8 +87,9 @@ void gtm_env_init(void)
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
- if (!TREF(gtm_env_init_done))
+ if (!TREF(gtm_env_init_started))
{
+ TREF(gtm_env_init_started) = TRUE;
/* See if a debug level has been specified. Do this first since gtmDebugLevel needs
* to be initialized before any mallocs are done in the system.
*/
@@ -299,8 +302,17 @@ void gtm_env_init(void)
val.addr = ZTRAP_NEW;
val.len = SIZEOF(ZTRAP_NEW) - 1;
ztrap_new = logical_truth_value(&val, FALSE, NULL);
+ /* See if $gtm_max_storalloc is set */
+ val.addr = GTM_MAX_STORALLOC;
+ val.len = SIZEOF(GTM_MAX_STORALLOC) - 1;
+ gtm_max_storalloc = trans_numeric(&val, &is_defined, TRUE);
+# ifdef UNIX
+ /* See if gtm_ipv4_only is set */
+ val.addr = GTM_IPV4_ONLY;
+ val.len = SIZEOF(GTM_IPV4_ONLY) - 1;
+ ipv4_only = logical_truth_value(&val, FALSE, NULL);
+# endif
/* Platform specific initializations */
gtm_env_init_sp();
- TREF(gtm_env_init_done) = TRUE;
}
}
diff --git a/sr_port/gtm_inet.h b/sr_port/gtm_inet.h
index 60fd19c..7f973ab 100644
--- a/sr_port/gtm_inet.h
+++ b/sr_port/gtm_inet.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -20,6 +20,9 @@
#endif
#include <arpa/inet.h>
+#ifndef __MVS__
+#include <netinet/tcp.h>
+#endif
#ifdef NeedInAddrPort
typedef uint32_t in_addr_t;
diff --git a/sr_port/gtm_ipv6.h b/sr_port/gtm_ipv6.h
new file mode 100644
index 0000000..60441ca
--- /dev/null
+++ b/sr_port/gtm_ipv6.h
@@ -0,0 +1,134 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* gtm_ipv6.h - interlude to <sys/socket.h> system header file. */
+#ifndef GTM_IPV6H
+#define GTM_IPV6H
+
+#include <gtm_netdb.h> /* Make sure we have AI_V4MAPPED/AI_NUMERICSERV defined if available */
+
+GBLREF boolean_t ipv4_only; /* If TRUE, only use AF_INET. */
+
+/* ai_canonname must be set NULL for AIX. Otherwise, freeaddrinfo() freeing the ai_canonname will hit SIG-11
+ * other field which were not initialized as 0 will also causes getaddrinfo()to fail
+ * Setting AI_PASSIVE will give you a wildcard address if addr is NULL, i.e. INADDR_ANY or IN6ADDR_ANY
+ * AI_NUMERICSERV is to pass the numeric port to address, it is to inhibit the name resolution to improve efficience
+ * AI_ADDRCONFIG: IPv4 addresses are returned only if the local system has at least one IPv4 address
+ configured; IPv6 addresses are only returned if the local system has at least one IPv6
+ address configured. For now we only use IPv6 address. So not use this flag here.
+ * AI_V4MAPPED: IPv4 mapped addresses are acceptable
+ * (Note: for snail, AI_V4MAPPED is defined but AI_NUMERICSERV is not defined)
+ */
+
+#if (defined(__hppa) || defined(__vms) || defined(__osf__))
+#define GTM_IPV6_SUPPORTED FALSE
+#else
+#define GTM_IPV6_SUPPORTED TRUE
+#endif
+
+#if !GTM_IPV6_SUPPORTED
+#define SERVER_HINTS(hints, af) \
+{ \
+ assert(AF_INET6 != af); \
+ memset(&hints, 0, SIZEOF(struct addrinfo)); \
+ hints.ai_family = AF_INET; \
+ hints.ai_socktype = SOCK_STREAM; \
+ hints.ai_protocol = IPPROTO_TCP; \
+ hints.ai_flags = AI_PASSIVE; \
+}
+#define CLIENT_HINTS(hints) \
+{ \
+ memset(&hints, 0, SIZEOF(struct addrinfo)); \
+ hints.ai_family = AF_INET; \
+ hints.ai_socktype = SOCK_STREAM; \
+ hints.ai_protocol = IPPROTO_TCP; \
+ hints.ai_flags = 0; \
+}
+
+#define CLIENT_HINTS_AF(hints, af) \
+{ \
+ assert(AF_INET == af); \
+ memset(&hints, 0, SIZEOF(struct addrinfo)); \
+ hints.ai_family = AF_INET; \
+ hints.ai_socktype = SOCK_STREAM; \
+ hints.ai_protocol = IPPROTO_TCP; \
+ hints.ai_flags = 0; \
+}
+
+#elif (defined(AI_V4MAPPED) && defined(AI_NUMERICSERV))
+#define SERVER_HINTS(hints, af) \
+{ \
+ memset(&hints, 0, SIZEOF(struct addrinfo)); \
+ hints.ai_family = af; \
+ hints.ai_socktype = SOCK_STREAM; \
+ hints.ai_protocol = IPPROTO_TCP; \
+ hints.ai_flags = AI_V4MAPPED | AI_PASSIVE | AI_NUMERICSERV; \
+}
+#define CLIENT_HINTS(hints) \
+{ \
+ memset(&hints, 0, SIZEOF(struct addrinfo)); \
+ hints.ai_family = (ipv4_only ? AF_INET : AF_UNSPEC); \
+ hints.ai_socktype = SOCK_STREAM; \
+ hints.ai_protocol = IPPROTO_TCP; \
+ hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG; \
+}
+#define CLIENT_HINTS_AF(hints, af) \
+{ \
+ memset(&hints, 0, SIZEOF(struct addrinfo)); \
+ hints.ai_family = af; \
+ hints.ai_socktype = SOCK_STREAM; \
+ hints.ai_protocol = IPPROTO_TCP; \
+ hints.ai_flags = AI_V4MAPPED; \
+}
+
+#else
+#error "Ok, so we do have non-AI_V4MAPPED/AI_NUMERICSERV machines with IPv6 support"
+#define SERVER_HINTS(hints, af) \
+{ \
+ memset(&hints, 0, SIZEOF(struct addrinfo)); \
+ hints.ai_family = af; \
+ hints.ai_socktype = SOCK_STREAM; \
+ hints.ai_protocol = IPPROTO_TCP; \
+ hints.ai_flags = AI_PASSIVE; \
+}
+#define CLIENT_HINTS(hints) \
+{ \
+ memset(&hints, 0, SIZEOF(struct addrinfo)); \
+ hints.ai_family = (ipv4_only ? AF_INET : AF_UNSPEC); \
+ hints.ai_socktype = SOCK_STREAM; \
+ hints.ai_protocol = IPPROTO_TCP; \
+ hints.ai_flags = AI_ADDRCONFIG; \
+}
+#define CLIENT_HINTS_AF(hints, af) \
+{ \
+ memset(&hints, 0, SIZEOF(struct addrinfo)); \
+ hints.ai_family = AF_INET; \
+ hints.ai_socktype = SOCK_STREAM; \
+ hints.ai_protocol = IPPROTO_TCP; \
+ hints.ai_flags = 0; \
+}
+#endif
+
+#define FREEADDRINFO(ai_ptr) \
+{ \
+ if(ai_ptr) \
+ freeaddrinfo(ai_ptr); \
+}
+
+union gtm_sockaddr_in46
+{
+ struct sockaddr_in ipv4;
+# if GTM_IPV6_SUPPORTED
+ struct sockaddr_in6 ipv6;
+# endif
+};
+
+#endif
diff --git a/sr_port/gtm_malloc_src.h b/sr_port/gtm_malloc_src.h
index e213927..984b125 100644
--- a/sr_port/gtm_malloc_src.h
+++ b/sr_port/gtm_malloc_src.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -71,6 +71,7 @@
#include "cache.h"
#include "gtm_malloc.h"
#include "have_crit.h"
+#include "gtm_env_init.h"
#ifdef UNIX
# include "gtmio.h"
# include "deferred_signal_handler.h"
@@ -111,48 +112,62 @@
#ifdef VMS
/* These routines for VMS are AST-safe */
-# define MALLOC(size, addr) \
-{ \
- int msize, errnum; \
- void *maddr; \
- msize = size; \
- errnum = lib$get_vm(&msize, &maddr); \
- if (SS$_NORMAL != errnum) \
- { \
- gtmMallocErrorSize = size; \
- gtmMallocErrorCallerid = CALLERID; \
- gtmMallocErrorErrno = errnum; \
- raise_gtmmemory_error(); \
- } \
- addr = (void *)maddr; \
+# define MALLOC(size, addr) \
+{ \
+ int msize, errnum; \
+ void *maddr; \
+ if ((0 < gtm_max_storalloc) && ((size + totalRmalloc + totalRallocGta) > gtm_max_storalloc)) \
+ { /* Boundary check for $gtm_max_storalloc (if set) */ \
+ gtmMallocErrorSize = size; \
+ gtmMallocErrorCallerid = CALLERID; \
+ gtmMallocErrorErrno = ERR_MALLOCMAXVMS; \
+ raise_gtmmemory_error(); \
+ } \
+ msize = size; \
+ errnum = lib$get_vm(&msize, &maddr); \
+ if (SS$_NORMAL != errnum) \
+ { \
+ gtmMallocErrorSize = size; \
+ gtmMallocErrorCallerid = CALLERID; \
+ gtmMallocErrorErrno = errnum; \
+ raise_gtmmemory_error(); \
+ } \
+ addr = (void *)maddr; \
}
-# define FREE(size, addr) \
-{ \
- int msize, errnum; \
- void *maddr; \
- msize = size; \
- maddr = addr; \
- errnum = lib$free_vm(&msize, &maddr); \
- if (SS$_NORMAL != errnum) \
- { \
- --gtmMallocDepth; \
- assert(FALSE); \
- rts_error(VARLSTCNT(4) ERR_FREEMEMORY, 1, CALLERID, errnum); \
- } \
+# define FREE(size, addr) \
+{ \
+ int msize, errnum; \
+ void *maddr; \
+ msize = size; \
+ maddr = addr; \
+ errnum = lib$free_vm(&msize, &maddr); \
+ if (SS$_NORMAL != errnum) \
+ { \
+ --gtmMallocDepth; \
+ assert(FALSE); \
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_FREEMEMORY, 1, CALLERID, errnum); \
+ } \
}
# define GTM_MALLOC_REENT
#else
/* These routines for Unix are NOT thread-safe */
-# define MALLOC(size, addr) \
-{ \
- addr = (void *)malloc(size); \
- if (NULL == (void *)addr) \
- { \
- gtmMallocErrorSize = size; \
- gtmMallocErrorCallerid = CALLERID; \
- gtmMallocErrorErrno = errno; \
- raise_gtmmemory_error(); \
- } \
+# define MALLOC(size, addr) \
+{ \
+ if ((0 < gtm_max_storalloc) && ((size + totalRmalloc + totalRallocGta) > gtm_max_storalloc)) \
+ { /* Boundary check for $gtm_max_storalloc (if set) */ \
+ gtmMallocErrorSize = size; \
+ gtmMallocErrorCallerid = CALLERID; \
+ gtmMallocErrorErrno = ERR_MALLOCMAXUNIX; \
+ raise_gtmmemory_error(); \
+ } \
+ addr = (void *)malloc(size); \
+ if (NULL == (void *)addr) \
+ { \
+ gtmMallocErrorSize = size; \
+ gtmMallocErrorCallerid = CALLERID; \
+ gtmMallocErrorErrno = errno; \
+ raise_gtmmemory_error(); \
+ } \
}
# define FREE(size, addr) free(addr);
#endif
@@ -337,6 +352,8 @@ GBLREF volatile void *outOfMemoryMitigation; /* Reserve that we will freed to h
GBLREF uint4 outOfMemoryMitigateSize; /* Size of above reserve in Kbytes */
GBLREF int mcavail;
GBLREF mcalloc_hdr *mcavailptr, *mcavailbase;
+GBLREF size_t totalRallocGta; /* Size allocated by gtm_text_alloc if at all */
+GBLREF size_t gtm_max_storalloc; /* Max value for $ZREALSTOR or else memory error is raised */
GBLREF void (*cache_table_relobjs)(void); /* Function pointer to call cache_table_rebuild() */
UNIX_ONLY(GBLREF ch_ret_type (*ht_rhash_ch)();) /* Function pointer to hashtab_rehash_ch */
UNIX_ONLY(GBLREF ch_ret_type (*jbxm_dump_ch)();) /* Function pointer to jobexam_dump_ch */
@@ -435,8 +452,10 @@ error_def(ERR_INVMEMRESRV);
error_def(ERR_MEMORYRECURSIVE);
UNIX_ONLY(error_def(ERR_MEMORY);)
UNIX_ONLY(error_def(ERR_SYSCALL);)
+UNIX_ONLY(error_def(ERR_MALLOCMAXUNIX);)
VMS_ONLY(error_def(ERR_FREEMEMORY);)
VMS_ONLY(error_def(ERR_VMSMEMORY);)
+VMS_ONLY(error_def(ERR_MALLOCMAXVMS);)
/* Internal prototypes */
void gtmSmInit(void);
@@ -475,7 +494,19 @@ void gtmSmInit(void) /* Note renamed to gtmSmInit_dbg when included in gtm_mallo
char *ascNum;
storElem *uStor;
int i, sizeIndex, testSize, blockSize, save_errno;
+ DCL_THREADGBL_ACCESS;
+ SETUP_THREADGBL_ACCESS;
+ /* If this routine is entered and environment vars have not yet been processed with a call to gtm_env_init(),
+ * then do this now. Since this will likely trigger a call to this routine *again*, verify if we still need
+ * to do this and if not, just return.
+ */
+ if (!TREF(gtm_env_init_started))
+ {
+ gtm_env_init();
+ if (gtmSmInitialized)
+ return; /* A nested call took care of this already so we're done! */
+ }
/* WARNING!! Since this is early initialization, the following asserts are not well behaved if they do
* indeed trip. The best that can be hoped for is they give a condition handler exhausted error on
* GTM startup. Unfortunately, more intelligent responses are somewhat elusive since no output devices
@@ -518,7 +549,6 @@ void gtmSmInit(void) /* Note renamed to gtmSmInit_dbg when included in gtm_mallo
}
);
dqinit(&storExtHdrQ, links);
-
/* One last task before we consider ourselves initialized. Allocate the out-of-memory mitigation storage
* that we will hold onto but not use. If we get an out-of-memory error, this storage will be released back
* to the OS for it or GTM to use as necessary while we try to go about an orderly shutdown of our process.
@@ -533,7 +563,7 @@ void gtmSmInit(void) /* Note renamed to gtmSmInit_dbg when included in gtm_mallo
if (NULL == outOfMemoryMitigation)
{
save_errno = errno;
- gtm_putmsg(VARLSTCNT(5) ERR_INVMEMRESRV, 2,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_INVMEMRESRV, 2,
RTS_ERROR_LITERAL(UNIX_ONLY("$gtm_memory_reserve")VMS_ONLY("GTM_MEMORY_RESERVE")),
save_errno);
exit(save_errno);
@@ -703,9 +733,8 @@ void *gtm_malloc(size_t size) /* Note renamed to gtm_malloc_dbg when included in
if (gtmSmInitialized)
{
hdrSize = OFFSETOF(storElem, userStorage); /* Size of storElem header */
- NON_GTM64_ONLY(if ((size + hdrSize) < size) GTMASSERT); /* Check for wrap in 32 bit platforms */
+ NON_GTM64_ONLY(assertpro((size + hdrSize) >= size)); /* Check for wrap in 32 bit platforms */
assert((hdrSize + SIZEOF(markerChar)) < MINTWO);
-
NON_GMR_ONLY(fast_lock_count++);
++gtmMallocDepth; /* Nesting depth of memory calls */
reentered = (1 < gtmMallocDepth);
@@ -714,7 +743,7 @@ void *gtm_malloc(size_t size) /* Note renamed to gtm_malloc_dbg when included in
{
--gtmMallocDepth;
assert(FALSE);
- rts_error(VARLSTCNT(1) ERR_MEMORYRECURSIVE);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MEMORYRECURSIVE);
}
);
INCR_CNTR(totalMallocs);
@@ -878,8 +907,7 @@ void gtm_free(void *addr) /* Note renamed to gtm_free_dbg when included in gtm_m
if (GDL_None == gtmDebugLevel)
{
# endif
- if (!gtmSmInitialized) /* Storage must be init'd before can free anything */
- GTMASSERT;
+ assertpro(gtmSmInitialized); /* Storage must be init'd before can free anything */
/* If we are exiting, don't bother with frees. Process destruction can do it *UNLESS* we are handling an
* out of memory condition with the proviso that we can't return memory if we are already nested.
*/
@@ -897,8 +925,7 @@ void gtm_free(void *addr) /* Note renamed to gtm_free_dbg when included in gtm_m
if ((unsigned char *)addr != &NullStruct.nullStr[0])
{
dqIndex = gtmMallocDepth - 2; /* 0 origin index into defer queues */
- if (MAXDEFERQUEUES <= dqIndex) /* Can't run out of queues */
- GTMASSERT;
+ assertpro(MAXDEFERQUEUES > dqIndex); /* Can't run out of queues */
hdrSize = offsetof(storElem, userStorage);
uStor = (storElem *)((unsigned long)addr - hdrSize); /* Backup ptr to element header */
uStor->userStorage.deferFreeNext = deferFreeQueues[dqIndex];
@@ -914,7 +941,7 @@ void gtm_free(void *addr) /* Note renamed to gtm_free_dbg when included in gtm_m
{
--gtmMallocDepth;
assert(FALSE);
- rts_error(VARLSTCNT(1) ERR_MEMORYRECURSIVE);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MEMORYRECURSIVE);
}
# endif
INCR_CNTR(smTn); /* Bump the transaction number */
@@ -1130,7 +1157,7 @@ void raise_gtmmemory_error(void) /* Note renamed to raise_gtmmemory_error_dbg wh
if (GDL_None == gtmDebugLevel)
{
# endif
- if (NULL != (addr = (void *)outOfMemoryMitigation)
+ if (NULL != (addr = (void *)outOfMemoryMitigation) /* Note assignment */
UNIX_ONLY(&& !(ht_rhash_ch == active_ch->ch || jbxm_dump_ch == active_ch->ch || stpgc_ch == active_ch->ch)))
{ /* Free our reserve only if not in certain condition handlers (on UNIX) since it is
* going to unwind this error and ignore it. On VMS the error will not be trapped.
@@ -1148,8 +1175,9 @@ void raise_gtmmemory_error(void) /* Note renamed to raise_gtmmemory_error_dbg wh
--gtmMallocDepth;
UNIX_ONLY(--fast_lock_count);
DEFERRED_EXIT_HANDLING_CHECK;
- UNIX_ONLY(rts_error(VARLSTCNT(5) ERR_MEMORY, 2, gtmMallocErrorSize, gtmMallocErrorCallerid, gtmMallocErrorErrno));
- VMS_ONLY(rts_error(VARLSTCNT(4) ERR_VMSMEMORY, 2, gtmMallocErrorSize, gtmMallocErrorCallerid));
+ UNIX_ONLY(rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_MEMORY, 2, gtmMallocErrorSize, gtmMallocErrorCallerid,
+ gtmMallocErrorErrno));
+ VMS_ONLY(rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_VMSMEMORY, 2, gtmMallocErrorSize, gtmMallocErrorCallerid));
# ifndef DEBUG
} else
/* If not a debug module and debugging is enabled, reroute call to the debugging version. */
diff --git a/sr_port/gtm_netdb.h b/sr_port/gtm_netdb.h
index 3e6212e..b38ee61 100644
--- a/sr_port/gtm_netdb.h
+++ b/sr_port/gtm_netdb.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2006 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -16,8 +16,28 @@
#include <netdb.h>
#define MAX_GETHOST_TRIES 8
-#define GETHOSTBYNAME gethostbyname
-#define GETHOSTBYADDR gethostbyaddr
-#define HSTRERROR hstrerror
+
+/* Macro to issue an rts_error_csa() with the results of getaddrinfo() or getnameinfo().
+ * Takes ERR_GETADDRINFO or ERR_GETNAMEINFO as the mnemonic.
+ */
+#define RTS_ERROR_ADDRINFO(CSA, MNEMONIC, ERRCODE) \
+{ \
+ if (EAI_SYSTEM == ERRCODE) \
+ rts_error_csa(CSA_ARG(CSA) VARLSTCNT(4) MNEMONIC, 0, errno, 0); \
+ else \
+ rts_error_csa(CSA_ARG(CSA) VARLSTCNT(6) MNEMONIC, 0, \
+ ERR_TEXT, 2, RTS_ERROR_STRING(gai_strerror(ERRCODE))); \
+}
+/* Same as above, but with a literal string context description. */
+#define RTS_ERROR_ADDRINFO_CTX(CSA, MNEMONIC, ERRCODE, CONTEXT) \
+{ \
+ if (EAI_SYSTEM == ERRCODE) \
+ rts_error_csa(CSA_ARG(CSA) VARLSTCNT(8) MNEMONIC, 0, \
+ ERR_TEXT, 2, RTS_ERROR_LITERAL(CONTEXT), errno, 0); \
+ else \
+ rts_error_csa(CSA_ARG(CSA) VARLSTCNT(10) MNEMONIC, 0, \
+ ERR_TEXT, 2, RTS_ERROR_LITERAL(CONTEXT), \
+ ERR_TEXT, 2, RTS_ERROR_STRING(gai_strerror(ERRCODE))); \
+}
#endif
diff --git a/sr_port/gtm_putmsg_list.h b/sr_port/gtm_putmsg_list.h
index 4e7dc06..39dad9c 100644
--- a/sr_port/gtm_putmsg_list.h
+++ b/sr_port/gtm_putmsg_list.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2005 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 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 GTM_PUTMSG_LIST_H
#define GTM_PUTMSG_LIST_H
-void gtm_putmsg_list(int arg_count, va_list var);
+void gtm_putmsg_list(void *csa, int arg_count, va_list var);
#endif
diff --git a/sr_port/gtm_rename.h b/sr_port/gtm_rename.h
index 811bd7d..65d7935 100644
--- a/sr_port/gtm_rename.h
+++ b/sr_port/gtm_rename.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2003 Sanchez Computer Associates, Inc. *
+ * Copyright 2003, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -17,11 +17,17 @@
#define RENAME_NOT_REQD 1
#define RENAME_FAILED 2
+#ifdef UNIX
+# define JNLSWITCH_TM_FMT "_%Y%j%H%M%S" /* yearjuliandayhoursminutesseconds */
+#else
+# define JNLSWITCH_TM_FMT "|!Y4|!H04!M0!S0|" /* 'julian' day is added by append_time_stamp() explicitly */
+#endif
+
int rename_file_if_exists(char *org_fn, int org_fn_len, char *rename_fn, int *rename_fn_len, uint4 *ustatus);
uint4 gtm_rename(char *org_fn, int org_fn_len, char *rename_fn, int rename_len, uint4 *ustatus);
-uint4 prepare_unique_name(char *org_fn, int org_fn_len, char *prefix, char *suffix, char *rename_fn,
- int *rename_fn_len, uint4 *ustatus);
-uint4 append_time_stamp(char *fn, int fn_len, int *app_len, uint4 *ustatus);
+uint4 prepare_unique_name(char *org_fn, int org_fn_len, char *prefix, char *suffix, char *rename_fn, int *rename_fn_len,
+ jnl_tm_t now, uint4 *ustatus);
+uint4 append_time_stamp(char *fn, int *fn_len, jnl_tm_t now);
void cre_jnl_file_intrpt_rename(int fn_len, sm_uc_ptr_t fn);
#endif
diff --git a/sr_port/gtm_socket.h b/sr_port/gtm_socket.h
index 64b6d52..b1c5839 100644
--- a/sr_port/gtm_socket.h
+++ b/sr_port/gtm_socket.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -13,20 +13,23 @@
#ifndef GTM_SOCKETH
#define GTM_SOCKETH
+#ifdef VMS
+#include <socket.h>
+#else
#include <sys/socket.h>
+#endif
#define BIND bind
#define CONNECT connect
#define ACCEPT accept
#define RECVFROM recvfrom
#define SENDTO sendto
+typedef struct sockaddr *sockaddr_ptr;
#if defined(__osf__) && defined(__alpha)
#define GTM_SOCKLEN_TYPE size_t
#elif defined(VMS)
#define GTM_SOCKLEN_TYPE size_t
-#elif defined(__sparc)
-#define GTM_SOCKLEN_TYPE int
#else
#define GTM_SOCKLEN_TYPE socklen_t
#endif
@@ -44,4 +47,27 @@
int gtm_socket(int domain, int type, int protocol);
int gtm_connect(int socket, struct sockaddr *address, size_t address_len);
+#if defined(VMS) && !defined(_SS_PAD2SIZE)
+/* No sockaddr_storage on OpenVMS 7.2-1, but we only support AF_INET on VMS, so use sockaddr_in. */
+#define sockaddr_storage sockaddr_in
+/* getnameinfo() inexplicably throws an ACCVIO/NOPRIV on OpenVMS 7.2-1, so revert to the old API. */
+#define GETNAMEINFO(SA, SALEN, HOST, HOSTLEN, SERV, SERVLEN, FLAGS, RES) \
+{ \
+ assert(((struct sockaddr *)(SA))->sa_family == AF_INET); \
+ assert((FLAGS & NI_NUMERICHOST) || (NULL == HOST)); \
+ assert((FLAGS & NI_NUMERICSERV) || (NULL == SERV)); \
+ assert(FLAGS & (NI_NUMERICHOST | NI_NUMERICSERV)); \
+ if ((FLAGS & NI_NUMERICHOST) && (NULL != HOST)) \
+ STRNCPY(HOST, inet_ntoa(((struct sockaddr_in *)(SA))->sin_addr), HOSTLEN); \
+ if ((FLAGS & NI_NUMERICSERV) && (NULL != SERV)) \
+ i2asc((uchar_ptr_t)(SERV), ntohs(((struct sockaddr_in *)(SA))->sin_port)); \
+ RES = 0; \
+}
+#else
+#define GETNAMEINFO(SA, SALEN, HOST, HOSTLEN, SERV, SERVLEN, FLAGS, RES) \
+{ \
+ RES = getnameinfo(SA, SALEN, HOST, HOSTLEN, SERV, SERVLEN, FLAGS); \
+}
+#endif
+
#endif
diff --git a/sr_port/gtm_stdlib.h b/sr_port/gtm_stdlib.h
index 209b911..225827a 100644
--- a/sr_port/gtm_stdlib.h
+++ b/sr_port/gtm_stdlib.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2007 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -40,11 +40,11 @@ char *gtm_getenv(char *varname);
#define STRTOU64L strtoull
#endif
#define MKSTEMP(template,mkstemp_res) (mkstemp_res = mkstemp(template))
-#ifndef __CYGWIN__
-#define SYSTEM system
+#ifdef VMS
+#define SYSTEM system
#else
#define SYSTEM gtm_system
-int gtm_system(const char *line);
+int gtm_system(const char *cmdline);
#endif
#endif
diff --git a/sr_port/gtm_string.h b/sr_port/gtm_string.h
index 8da5d1a..c542726 100644
--- a/sr_port/gtm_string.h
+++ b/sr_port/gtm_string.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -18,17 +18,14 @@
#include <string.h>
#define STRERROR strerror
-
#define STRCPY(DEST, SOURCE) strcpy((char *)(DEST), (char *)(SOURCE))
#define STRNCPY_LIT(DEST, LITERAL) strncpy((char *)(DEST), (char *)(LITERAL), SIZEOF(LITERAL) - 1) /* BYPASSOK */
#define STRNCPY_STR(DEST, STRING, LEN) strncpy((char *)(DEST), (char *)(STRING), LEN)
-
#define STRCMP(SOURCE, DEST) strcmp((char *)(SOURCE), (char *)(DEST))
#define STRNCMP_LIT(SOURCE, LITERAL) strncmp(SOURCE, LITERAL, SIZEOF(LITERAL) - 1) /* BYPASSOK */
/* Make sure that SIZEOF(SOURCE) > 0 or SOURCE != NULL before running. */
#define STRNCMP_LIT_FULL(SOURCE, LITERAL) strncmp(SOURCE, LITERAL, SIZEOF(LITERAL)) /* BYPASSOK */
#define STRNCMP_STR(SOURCE, STRING, LEN) strncmp(SOURCE, STRING, LEN)
-
/* We need to catch any memcpy() that is used when the source and target strings overlap in any fashion so we can change
* them to a memmove. So in debug builds, assert fail if this is the case.
*/
@@ -39,5 +36,28 @@
# endif
# define memcpy(TARGET, SRC, LEN) gtm_memcpy_validate_and_execute((void *)(TARGET), (const void *)(SRC), (LEN))
#endif
+/* The strnlen() function is POSIX-2008 so not widely avaiable yet so use it or our own critter as appropriate */
+#if (defined(__linux__) || defined(AIX))
+# define STRNLEN(str, maxlen, rslt) rslt = strnlen(str, maxlen)
+#else
+# define STRNLEN(str, maxlen, rslt) \
+{ \
+ unsigned char *c, *cend; \
+ \
+ for (c = (unsigned char *)str, cend = c + maxlen; c < cend; ++c) \
+ if ('\0' == *c) \
+ break; \
+ rslt = c - (unsigned char *)str; \
+}
+#endif
+#define STRNDUP(STR, MAXLEN, DST) \
+{ \
+ size_t local_len; \
+ \
+ STRNLEN(STR, MAXLEN, local_len); \
+ DST = (char *) malloc(local_len + 1); \
+ memcpy(DST, STR, local_len); \
+ DST[local_len] = '\0'; \
+}
#endif
diff --git a/sr_port/gtm_threadgbl_defs.h b/sr_port/gtm_threadgbl_defs.h
index b912280..778cd8c 100644
--- a/sr_port/gtm_threadgbl_defs.h
+++ b/sr_port/gtm_threadgbl_defs.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2010, 2012 Fidelity Information Services, Inc *
+ * Copyright 2010, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -101,8 +101,10 @@ THREADGBLDEF(in_op_gvget, boolean_t) /* TRUE if op_gvget() is a C-stack call
THREADGBLDEF(issue_DBROLLEDBACK_anyways, boolean_t) /* currently set by MUPIP LOAD */
THREADGBLDEF(last_fnquery_return_subcnt, int) /* count subscript in last_fnquery_return_sub */
THREADGBLDEF(last_fnquery_return_varname, mval) /* returned varname of last $QUERY() */
+#ifdef VMS
THREADGBLDEF(new_dbinit_ipc, int4) /* indicates whether shared memory/semaphore is
* created by db_init (also used by dbinit_ch) */
+#endif
THREADGBLDEF(ok_to_call_wcs_recover, boolean_t) /* Set to TRUE before a few wcs_recover callers.
* Any call to wcs_recover in the final retry
* assert to prevent cache recovery while in a
@@ -148,6 +150,7 @@ THREADGBLDEF(max_lcl_coll_xform_bufsiz, int) /* max size of local collation
/* Replication variables */
THREADGBLDEF(replgbl, replgbl_t) /* set of global variables needed by the source
* server */
+THREADGBLDEF(tqread_nowait, boolean_t) /* avoid sleeping in t_qread if TRUE */
/* Miscellaneous */
THREADGBLDEF(collseq_list, collseq *) /* list of pointers to currently mapped collation
* algorithms - since this seems only used in
@@ -170,7 +173,12 @@ THREADGBLDEF(fnzsearch_sub_mval, mval) /* UNIX op_fnzsearch subscript constu
THREADGBLDEF(fnzsearch_nullsubs_sav, int) /* UNIX op_fnzsearch temp for null subs control */
#endif
THREADGBLDEF(glvn_pool_ptr, glvn_pool *) /* Pointer to the glvn pool */
-THREADGBLDEF(gtm_env_init_done, boolean_t) /* gtm_env_init flag for completion */
+#if defined(UNIX) && defined(GTMDBGFLAGS_ENABLED)
+THREADGBLDEF(gtmdbgflags, int)
+THREADGBLDEF(gtmdbgflags_freq, int)
+THREADGBLDEF(gtmdbgflags_freq_cntr, int)
+#endif
+THREADGBLDEF(gtm_env_init_started, boolean_t) /* gtm_env_init flag envvar processing */
THREADGBLFPTR(gtm_env_xlate_entry, int, ()) /* gtm_env_xlate() function pointer */
THREADGBLDEF(gtm_environment_init, boolean_t) /* indicates GT.M development environment rather
* than a production environment */
@@ -214,6 +222,9 @@ THREADGBLDEF(open_shlib_root, open_shlib *) /* Anchor for open shared librar
THREADGBLDEF(parm_pool_ptr, parm_pool *) /* Pointer to the parameter pool */
THREADGBLDEF(parms_cnt, unsigned int) /* Parameters count */
#ifdef UNIX
+THREADGBLAR1DEF(zpeek_regname, char, NAME_ENTRY_SZ) /* Last $ZPEEK() region specified */
+THREADGBLDEF(zpeek_regname_len, int) /* Length of zpeekop_regname */
+THREADGBLDEF(zpeek_reg_ptr, gd_region *) /* Resolved pointer for zpeekop_regname */
THREADGBLDEF(pipefifo_interrupt, int) /* count of number of times a pipe or fifo device is
* interrupted */
#endif
@@ -274,6 +285,8 @@ THREADGBLDEF(ci_table, callin_entry_list *) /* Callin table in the form of
THREADGBLDEF(extcall_package_root, struct extcall_package_list *) /* External call table package list */
#ifdef UNIX
THREADGBLDEF(gtmci_nested_level, unsigned int) /* Current nested depth of callin environments */
+THREADGBLDEF(in_gtmci, boolean_t) /* Indicates if we are in one of the gtm_ci...
+ * functions. */
#endif
THREADGBLDEF(want_empty_gvts, boolean_t) /* set to TRUE by MUPIP REORG when it is selecting
@@ -314,6 +327,7 @@ THREADGBLDEF(gvt_triggers_read_this_tn, boolean_t) /* if non-zero, indicates
* useful to invalidate all those triggers in case
* of a transaction restart or rollback.
*/
+THREADGBLDEF(in_op_fntext, boolean_t) /* Denote the trigger was processed in $Text() */
#endif
/* Debug values */
diff --git a/sr_port/gtm_threadgbl_deftypes.c b/sr_port/gtm_threadgbl_deftypes.c
index 4368a6a..4c0ba8d 100644
--- a/sr_port/gtm_threadgbl_deftypes.c
+++ b/sr_port/gtm_threadgbl_deftypes.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2010, 2012 Fidelity Information Services, Inc *
+ * Copyright 2010, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -96,6 +96,7 @@
#include "trace_table.h"
#include "parm_pool.h"
#include "util.h" /* for util_outbuff manipulations */
+#include "nametabtyp.h"
/* FOR REPLICATION RELATED GLOBALS */
#include "repl_msg.h"
diff --git a/sr_port/gtm_threadgbl_init.c b/sr_port/gtm_threadgbl_init.c
index bdc8049..0479aec 100644
--- a/sr_port/gtm_threadgbl_init.c
+++ b/sr_port/gtm_threadgbl_init.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2010, 2012 Fidelity Information Services, Inc *
+ * Copyright 2010, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -105,6 +105,7 @@
#include "zroutines.h"
#include "parm_pool.h"
#include "util.h" /* for util_outbuff manipulations */
+#include "nametabtyp.h"
/* FOR REPLICATION RELATED GLOBALS */
#include "repl_msg.h"
diff --git a/sr_port/gtm_time.h b/sr_port/gtm_time.h
index 13a694d..b529405 100644
--- a/sr_port/gtm_time.h
+++ b/sr_port/gtm_time.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2003 Sanchez Computer Associates, Inc. *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -15,13 +15,12 @@
#include <time.h>
-/* CTIME collides with linux define in termios */
-
-#define GTM_CTIME ctime
-#define GTM_CTIME_R ctime_r
-
#define STRFTIME(dest, maxsize, format, timeptr, res) \
- res = strftime(dest, maxsize, format, timeptr)
+{ \
+ DEFER_INTERRUPTS(INTRPT_IN_X_TIME_FUNCTION); \
+ res = strftime(dest, maxsize, format, timeptr); \
+ ENABLE_INTERRUPTS(INTRPT_IN_X_TIME_FUNCTION); \
+}
/* To use GET_CUR_TIME macro these definitions are required
* now_t now; char *time_ptr; char time_str[CTIME_BEFORE_NL + 2];
@@ -59,15 +58,48 @@ typedef time_t now_t;
{ \
if ((time_t)-1 == (now = time(NULL))) \
time_ptr = "****** time failed *****\n"; /* keep string len same as CTIME_BEFORE_NL */ \
- else if (NULL == (time_ptr = (char *)GTM_CTIME(&now))) \
- time_ptr = "***** ctime failed *****\n"; /* keep string len same as CTIME_BEFORE_NL */ \
else \
{ \
- memcpy(time_str, time_ptr, CTIME_BEFORE_NL + 2); \
- time_ptr = time_str; \
+ GTM_CTIME(time_ptr, &now); \
+ if (NULL == time_ptr) \
+ time_ptr = "***** ctime failed *****\n"; /* keep string len same as CTIME_BEFORE_NL */ \
+ else \
+ { \
+ memcpy(time_str, time_ptr, CTIME_BEFORE_NL + 2); \
+ time_ptr = time_str; \
+ } \
} \
}
+#define GTM_MKTIME(VAR, TIME) \
+{ \
+ DEFER_INTERRUPTS(INTRPT_IN_X_TIME_FUNCTION); \
+ VAR = mktime(TIME); \
+ ENABLE_INTERRUPTS(INTRPT_IN_X_TIME_FUNCTION); \
+}
+
+#define GTM_GMTIME(VAR, TIME) \
+{ \
+ DEFER_INTERRUPTS(INTRPT_IN_X_TIME_FUNCTION); \
+ VAR = gmtime(TIME); \
+ ENABLE_INTERRUPTS(INTRPT_IN_X_TIME_FUNCTION); \
+}
+
#endif /* UNIX, VMS */
+#define GTM_LOCALTIME(VAR, TIME) \
+{ \
+ DEFER_INTERRUPTS(INTRPT_IN_X_TIME_FUNCTION); \
+ VAR = localtime(TIME); \
+ ENABLE_INTERRUPTS(INTRPT_IN_X_TIME_FUNCTION); \
+}
+
+/* CTIME collides with linux define in termios */
+#define GTM_CTIME(VAR, TIME) \
+{ \
+ DEFER_INTERRUPTS(INTRPT_IN_X_TIME_FUNCTION); \
+ VAR = ctime(TIME); \
+ ENABLE_INTERRUPTS(INTRPT_IN_X_TIME_FUNCTION); \
+}
+
#endif
diff --git a/sr_port/gtm_unistd.h b/sr_port/gtm_unistd.h
index b031d22..7cae350 100644
--- a/sr_port/gtm_unistd.h
+++ b/sr_port/gtm_unistd.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -39,7 +39,11 @@
#define GTM_MAX_DIR_LEN (PATH_MAX + 1) /* DIRECTORY + terminating '\0' */
#define GETCWD(buffer, size, getcwd_res) \
- (getcwd_res = getcwd(buffer, size))
+{ \
+ DEFER_INTERRUPTS(INTRPT_IN_FUNC_WITH_MALLOC); \
+ getcwd_res = getcwd(buffer, size); \
+ ENABLE_INTERRUPTS(INTRPT_IN_FUNC_WITH_MALLOC); \
+}
#endif
diff --git a/sr_port/gtmmsg.h b/sr_port/gtmmsg.h
index c6cb1f5..d76ee3b 100644
--- a/sr_port/gtmmsg.h
+++ b/sr_port/gtmmsg.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -15,10 +15,13 @@
#ifdef VMS
void gtm_getmsg(uint4 msgnum, mstr *msgbuf);
void gtm_putmsg(int4 msgid, ...);
+#define gtm_putmsg_csa gtm_putmsg
#elif defined(UNIX)
void gtm_getmsg(int4 msgnum, mstr *msgbuf);
void gtm_putmsg(int argcnt, ...);
+void gtm_putmsg_csa(void *, int argcnt, ...); /* Use CSA_ARG(CSA) for portability */
void gtm_putmsg_noflush(int argcnt, ...);
+void gtm_putmsg_noflush_csa(void *, int argcnt, ...);
# define GET_MSG_IDX(MSG_ID, CTL, IDX) \
{ \
diff --git a/sr_port/gtmrecv_comm_init.c b/sr_port/gtmrecv_comm_init.c
index cff041d..d08162d 100644
--- a/sr_port/gtmrecv_comm_init.c
+++ b/sr_port/gtmrecv_comm_init.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -13,6 +13,8 @@
#include "gtm_string.h"
#include "gtm_socket.h"
+#include "gtm_netdb.h" /* for NI_MAXSERV and AI_V4MAPPED */
+#include "gtm_ipv6.h"
#include "gtm_inet.h"
#include "gtm_fcntl.h"
@@ -33,57 +35,77 @@
#include "gtmrecv.h"
#include "repl_sp.h"
#include "gtmio.h"
+#include "util.h"
+#include "repl_log.h"
GBLDEF int gtmrecv_listen_sock_fd = FD_INVALID;
+error_def(ERR_GETADDRINFO);
error_def(ERR_REPLCOMM);
error_def(ERR_TEXT);
/* Initialize communication stuff */
int gtmrecv_comm_init(in_port_t port)
{
- struct sockaddr_in secondary_addr;
- const int enable_reuseaddr = 1;
- struct linger disable_linger = {0, 0};
- int rc;
+ struct addrinfo *ai_ptr = NULL, hints;
+ const int enable_reuseaddr = 1;
+ struct linger disable_linger = {0, 0};
+ int rc;
+ int errcode;
+ char port_buffer[NI_MAXSERV];
+ int port_buffer_len;
+ int temp_sock_fd;
+ int af;
if (FD_INVALID != gtmrecv_listen_sock_fd) /* Initialization done already */
return (0);
/* Create the socket used for communicating with primary */
- if (FD_INVALID == (gtmrecv_listen_sock_fd = socket(AF_INET, SOCK_STREAM, 0)))
+ af = ((GTM_IPV6_SUPPORTED && !ipv4_only) ? AF_INET6 : AF_INET);
+ if (FD_INVALID == (temp_sock_fd = socket(af, SOCK_STREAM, IPPROTO_TCP)))
{
- rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
- RTS_ERROR_LITERAL("Error with receiver server socket create"), ERRNO);
- return (-1);
+ af = AF_INET;
+ if (FD_INVALID == (temp_sock_fd = socket(af, SOCK_STREAM, IPPROTO_TCP)))
+ {
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Error with receiver server socket create"), ERRNO);
+ return (-1);
+ }
+ }
+
+ /* Make it known to the world that you are ready for a Source Server */
+ SERVER_HINTS(hints, af);
+ SPRINTF(port_buffer, "%hu", port);
+ if (0 != (errcode = getaddrinfo(NULL, port_buffer, &hints, &ai_ptr)))
+ {
+ CLOSEFILE(temp_sock_fd, rc);
+ RTS_ERROR_ADDRINFO_CTX(NULL, ERR_GETADDRINFO, errcode, "FAILED in obtaining IP address on receiver server.");
+ return -1;
}
+
+ gtmrecv_listen_sock_fd = temp_sock_fd;
if (0 > setsockopt(gtmrecv_listen_sock_fd, SOL_SOCKET, SO_LINGER, (const void *)&disable_linger, SIZEOF(disable_linger)))
- rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Error with receiver server listen socket disable linger"), ERRNO);
if (0 > setsockopt(gtmrecv_listen_sock_fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&enable_reuseaddr,
SIZEOF(enable_reuseaddr)))
{
- rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Error with receiver server listen socket enable reuseaddr"), ERRNO);
}
-
- /* Make it known to the world that you are ready for a Source Server */
- memset((char *)&secondary_addr, 0, SIZEOF(secondary_addr));
- secondary_addr.sin_family = AF_INET;
- secondary_addr.sin_addr.s_addr = htonl(INADDR_ANY);
- secondary_addr.sin_port = htons(port);
-
- if (0 > BIND(gtmrecv_listen_sock_fd, (struct sockaddr *)&secondary_addr, SIZEOF(secondary_addr)))
+ if (0 > BIND(gtmrecv_listen_sock_fd, ai_ptr->ai_addr, ai_ptr->ai_addrlen))
{
- rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Could not bind local address"), ERRNO);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Could not bind local address"), ERRNO);
CLOSEFILE_RESET(gtmrecv_listen_sock_fd, rc); /* resets "gtmrecv_listen_sock_fd" to FD_INVALID */
return (-1);
}
if (0 > listen(gtmrecv_listen_sock_fd, 5))
{
- rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Could not listen"), ERRNO);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Could not listen"), ERRNO);
CLOSEFILE_RESET(gtmrecv_listen_sock_fd, rc); /* resets "gtmrecv_listen_sock_fd" to FD_INVALID */
return (-1);
}
diff --git a/sr_port/gtmrecv_helpers_init.c b/sr_port/gtmrecv_helpers_init.c
index 6829b24..88d806e 100644
--- a/sr_port/gtmrecv_helpers_init.c
+++ b/sr_port/gtmrecv_helpers_init.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2005, 2012 Fidelity Information Services, Inc. *
+ * Copyright 2005, 2013 Fidelity Information Services, Inc.*
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -14,6 +14,7 @@
#ifdef UNIX
#include <sys/types.h>
#include "gtm_unistd.h"
+#include "fork_init.h"
#include <sys/wait.h>
#elif defined(VMS)
#include <descrip.h> /* Required for gtmrecv.h */
@@ -84,11 +85,12 @@ static int helper_init(upd_helper_entry_ptr_t helper, recvpool_user helper_type)
save_shutdown = helper->helper_shutdown;
helper->helper_shutdown = NO_SHUTDOWN;
#ifdef UNIX
- if (0 > (helper_pid = fork())) /* BYPASSOK: we exec immediately, no FORK_CLEAN needed */
+ FORK(helper_pid); /* BYPASSOK: we exec immediately, no FORK_CLEAN needed */
+ if (0 > helper_pid)
{
save_errno = errno;
helper->helper_shutdown = save_shutdown;
- gtm_putmsg(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
LEN_AND_LIT("Could not fork update process"), save_errno);
repl_errno = EREPL_UPDSTART_FORK;
return UPDPROC_START_ERR;
@@ -103,10 +105,11 @@ static int helper_init(upd_helper_entry_ptr_t helper, recvpool_user helper_type)
dont_sendmsg_on_log2long)))
{
helper->helper_shutdown = save_shutdown;
- gtm_putmsg(VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
LEN_AND_LIT("Could not find path of Helper Process. Check value of $gtm_dist"));
if (SS_LOG2LONG == i4status)
- gtm_putmsg(VARLSTCNT(5) ERR_LOGTOOLONG, 3, LEN_AND_LIT(UPDHELPER_CMD), SIZEOF(helper_cmd) - 1);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_LOGTOOLONG, 3,
+ LEN_AND_LIT(UPDHELPER_CMD), SIZEOF(helper_cmd) - 1);
repl_errno = EREPL_UPDSTART_BADPATH;
return UPDPROC_START_ERR;
}
@@ -116,7 +119,7 @@ static int helper_init(upd_helper_entry_ptr_t helper, recvpool_user helper_type)
{
save_errno = errno;
helper->helper_shutdown = save_shutdown;
- gtm_putmsg(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
LEN_AND_LIT("Could not exec Helper Process"), save_errno);
repl_errno = EREPL_UPDSTART_EXEC;
return UPDPROC_START_ERR;
@@ -132,7 +135,8 @@ static int helper_init(upd_helper_entry_ptr_t helper, recvpool_user helper_type)
UPDHELPER_MBX_PREFIX, mbx_suffix, &cmd_channel, &helper->helper_pid_prev,
ERR_RECVPOOLSETUP)))
{
- gtm_putmsg(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, LEN_AND_LIT("Unable to spawn Helper process"), status);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0,
+ ERR_TEXT, 2, LEN_AND_LIT("Unable to spawn Helper process"), status);
helper->helper_shutdown = save_shutdown;
repl_errno = EREPL_UPDSTART_FORK;
return UPDPROC_START_ERR;
@@ -150,7 +154,7 @@ static int helper_init(upd_helper_entry_ptr_t helper, recvpool_user helper_type)
/* Deassign the send-cmd mailbox channel */
if (SS_NORMAL != (status = sys$dassgn(cmd_channel)))
{
- gtm_putmsg(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Unable to close upd-send-cmd mbox channel"), status);
helper->helper_shutdown = save_shutdown;
repl_errno = EREPL_UPDSTART_BADPATH; /* Just to make an auto-shutdown */
diff --git a/sr_port/gtmrecv_upd_proc_init.c b/sr_port/gtmrecv_upd_proc_init.c
index 2b024cd..4e14fde 100644
--- a/sr_port/gtmrecv_upd_proc_init.c
+++ b/sr_port/gtmrecv_upd_proc_init.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc.*
+ * Copyright 2001, 2013 Fidelity Information Services, Inc.*
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -17,6 +17,7 @@
#include "gtm_inet.h"
#ifdef UNIX
#include <sys/wait.h>
+#include "fork_init.h"
#elif defined(VMS)
#include <descrip.h>
#endif
@@ -83,17 +84,19 @@ int gtmrecv_upd_proc_init(boolean_t fresh_start)
if ((upd_status = is_updproc_alive()) == SRV_ERR)
{
save_errno = errno; /* errno from get_sem_info() called from is_updproc_alive() */
- gtm_putmsg(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
- RTS_ERROR_LITERAL("Receive pool semctl failure"), UNIX_ONLY(save_errno) VMS_ONLY(REPL_SEM_ERRNO));
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Receive pool semctl failure"),
+ UNIX_ONLY(save_errno) VMS_ONLY(REPL_SEM_ERRNO));
repl_errno = EREPL_UPDSTART_SEMCTL;
return(UPDPROC_START_ERR);
} else if (upd_status == SRV_ALIVE && !fresh_start)
{
- gtm_putmsg(VARLSTCNT(4) ERR_TEXT, 2, RTS_ERROR_LITERAL("Update process already exists. Not starting it"));
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Update process already exists. Not starting it"));
return(UPDPROC_EXISTS);
} else if (upd_status == SRV_ALIVE)
{
- gtm_putmsg(VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Update process already exists. Please kill it before a fresh start"));
return(UPDPROC_EXISTS);
}
@@ -102,10 +105,11 @@ int gtmrecv_upd_proc_init(boolean_t fresh_start)
recvpool.upd_proc_local->upd_proc_shutdown = NO_SHUTDOWN;
#ifdef UNIX
- if (0 > (upd_pid = fork())) /* BYPASSOK: we exec immediately, no FORK_CLEAN needed */
+ FORK(upd_pid); /* BYPASSOK: we exec immediately, no FORK_CLEAN needed */
+ if (0 > upd_pid)
{
recvpool.upd_proc_local->upd_proc_shutdown = save_upd_status;
- gtm_putmsg(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Could not fork update process"), errno);
repl_errno = EREPL_UPDSTART_FORK;
return(UPDPROC_START_ERR);
@@ -119,17 +123,18 @@ int gtmrecv_upd_proc_init(boolean_t fresh_start)
dont_sendmsg_on_log2long);
if (status != SS_NORMAL)
{
- gtm_putmsg(VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Could not find path of Update Process. Check value of $gtm_dist"));
if (SS_LOG2LONG == status)
- gtm_putmsg(VARLSTCNT(5) ERR_LOGTOOLONG, 3, LEN_AND_LIT(UPDPROC_CMD), SIZEOF(upd_proc_cmd) - 1);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5)
+ ERR_LOGTOOLONG, 3, LEN_AND_LIT(UPDPROC_CMD), SIZEOF(upd_proc_cmd) - 1);
repl_errno = EREPL_UPDSTART_BADPATH;
return(UPDPROC_START_ERR);
}
upd_proc_cmd[upd_proc_trans_cmd.len] = '\0';
if (EXECL(upd_proc_cmd, upd_proc_cmd, UPDPROC_CMD_ARG1, UPDPROC_CMD_ARG2, NULL) < 0)
{
- gtm_putmsg(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Could not exec Update Process"), errno);
repl_errno = EREPL_UPDSTART_EXEC;
return(UPDPROC_START_ERR);
@@ -140,7 +145,7 @@ int gtmrecv_upd_proc_init(boolean_t fresh_start)
status = repl_create_server(&cmd_desc, "GTMU", "", &cmd_channel, &upd_pid, ERR_RECVPOOLSETUP);
if (SS_NORMAL != status)
{
- gtm_putmsg(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Unable to spawn Update process"), status);
recvpool.upd_proc_local->upd_proc_shutdown = save_upd_status;
repl_errno = EREPL_UPDSTART_FORK;
@@ -167,7 +172,7 @@ int gtmrecv_upd_proc_init(boolean_t fresh_start)
/* Deassign the send-cmd mailbox channel */
if (SS_NORMAL != (status = sys$dassgn(cmd_channel)))
{
- gtm_putmsg(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Unable to close upd-send-cmd mbox channel"), status);
recvpool.upd_proc_local->upd_proc_shutdown = save_upd_status;
repl_errno = EREPL_UPDSTART_BADPATH; /* Just to make an auto-shutdown */
@@ -184,12 +189,12 @@ int gtmrecv_start_updonly(void)
if ((upd_status = is_updproc_alive()) == SRV_ALIVE)
{
- gtm_putmsg(VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Update Process exists already. New process not started"));
return(UPDPROC_START_ERR);
} else if (upd_status == SRV_ERR)
{
- gtm_putmsg(VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Error in starting up update process"));
return(UPDPROC_START_ERR);
}
@@ -205,7 +210,8 @@ int gtmrecv_start_updonly(void)
if (start_status == UPDPROC_STARTED)
{
- gtm_putmsg(VARLSTCNT(4) ERR_REPLINFO, 2, RTS_ERROR_LITERAL("Update Process started successfully"));
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_REPLINFO, 2,
+ RTS_ERROR_LITERAL("Update Process started successfully"));
return(UPDPROC_STARTED);
}
#ifdef VMS
@@ -213,14 +219,15 @@ int gtmrecv_start_updonly(void)
#endif
if (start_status == UPDPROC_START)
{
- gtm_putmsg(VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Receiver server is not alive to start update process. Please start receiver server"));
} else if (start_status == UPDPROC_START_ERR)
{
- gtm_putmsg(VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Error starting update process"));
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Error starting update process"));
} else if (start_status == UPDPROC_EXISTS)
{
- gtm_putmsg(VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Update Process exists already. New process not started"));
}
return(UPDPROC_START_ERR);
diff --git a/sr_port/gtmsource_comm_init.c b/sr_port/gtmsource_comm_init.c
index 1898cac..0ffb772 100644
--- a/sr_port/gtmsource_comm_init.c
+++ b/sr_port/gtmsource_comm_init.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -21,6 +21,8 @@
#include "gtm_stdio.h"
#include "gtm_string.h"
#include "gtm_socket.h"
+#include "gtm_netdb.h"
+#include "gtm_ipv6.h"
#include "gtm_inet.h"
#include "gtm_fcntl.h"
#include "gtm_unistd.h"
@@ -39,11 +41,14 @@
#include "gtmsource.h"
#include "repl_sp.h"
#include "repl_comm.h"
+#include "repl_log.h"
GBLDEF int gtmsource_sock_fd = FD_INVALID;
GBLREF jnlpool_addrs jnlpool;
+GBLREF FILE *gtmsource_log_fp;
error_def(ERR_REPLCOMM);
+error_def(ERR_GETADDRINFO);
error_def(ERR_TEXT);
int gtmsource_comm_init(void)
@@ -52,26 +57,62 @@ int gtmsource_comm_init(void)
struct linger disable_linger = {0, 0};
char error_string[1024];
int err_status;
+ struct addrinfo *ai_ptr = NULL, *ai_head = NULL, hints;
+ gtmsource_local_ptr_t gtmsource_local;
+ char *host;
+ char port_buffer[NI_MAXSERV];
+ int port_len;
+ int errcode;
+ int tries;
if (FD_INVALID != gtmsource_sock_fd) /* Initialization done already */
return(0);
-
- /* Create the socket used for communicating with secondary */
- if (FD_INVALID == (gtmsource_sock_fd = socket(AF_INET, SOCK_STREAM, 0)))
+ gtmsource_local = jnlpool.gtmsource_local;
+ port_len = 0;
+ I2A(port_buffer, port_len, gtmsource_local->secondary_port);
+ port_buffer[port_len] = '\0';
+ host = gtmsource_local->secondary_host;
+ CLIENT_HINTS(hints);
+ for (tries = 0;
+ tries < MAX_GETHOST_TRIES &&
+ EAI_AGAIN == (errcode = getaddrinfo(host, port_buffer, &hints, &ai_head));
+ tries++);
+ if (0 != errcode)
+ RTS_ERROR_ADDRINFO(NULL, ERR_GETADDRINFO, errcode);
+ /* find one address valid for creating socket */
+ assert(ai_head);
+ for(ai_ptr = ai_head; NULL != ai_ptr; ai_ptr = ai_ptr->ai_next)
{
- err_status = ERRNO;
- SNPRINTF(error_string, SIZEOF(error_string), "Error with source server socket create : %s", STRERROR(err_status));
- rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(error_string));
- return(-1);
+ if (FD_INVALID == (gtmsource_sock_fd = socket(ai_ptr->ai_family, ai_ptr->ai_socktype,
+ ai_ptr->ai_protocol)))
+ err_status = errno;
+ else
+ {
+ err_status = 0;
+ break;
+ }
}
-
+ if (0 != err_status)
+ {
+ freeaddrinfo(ai_head); /* prevent mem-leak */
+ SNPRINTF(error_string, SIZEOF(error_string), "Error with source server socket create : %s",
+ STRERROR(err_status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(error_string));
+ }
+ assert(NULL != ai_ptr);
+ assert(SIZEOF(gtmsource_local->secondary_inet_addr) >= ai_ptr->ai_addrlen);
+ /* only save the addrinfo and address after the socket is successfuly created */
+ gtmsource_local->secondary_af = ai_ptr->ai_family;
+ gtmsource_local->secondary_addrlen = ai_ptr->ai_addrlen;
+ memcpy((struct sockaddr*)(>msource_local->secondary_inet_addr), ai_ptr->ai_addr, ai_ptr->ai_addrlen);
+ freeaddrinfo(ai_head); /* prevent mem-leak */
/* A connection breakage should get rid of the socket */
if (-1 == setsockopt(gtmsource_sock_fd, SOL_SOCKET, SO_LINGER, (const void *)&disable_linger, SIZEOF(disable_linger)))
{
err_status = ERRNO;
SNPRINTF(error_string, SIZEOF(error_string), "Error with source server socket disable linger : %s",
STRERROR(err_status));
- rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(error_string));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(error_string));
}
return(0);
}
diff --git a/sr_port/gtmsource_heartbeat.h b/sr_port/gtmsource_heartbeat.h
index ed4291e..b6de3e8 100644
--- a/sr_port/gtmsource_heartbeat.h
+++ b/sr_port/gtmsource_heartbeat.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2003 Sanchez Computer Associates, Inc. *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -12,15 +12,14 @@
#ifndef GTMSOURCE_HEARTBEAT_H
#define GTMSOURCE_HEARTBEAT_H
-#define gtmsource_stall_heartbeat heartbeat_stalled = TRUE;
-#define gtmsource_restart_heartbeat heartbeat_stalled = FALSE;
#define gtmsource_is_heartbeat_stalled (heartbeat_stalled)
+
#ifndef REPL_DISABLE_HEARTBEAT
-#define gtmsource_is_heartbeat_due(now) \
+#define GTMSOURCE_IS_HEARTBEAT_DUE(NOW) \
(0 != last_sent_time \
- && difftime(*(now), last_sent_time) >= (double)jnlpool.gtmsource_local->connect_parms[GTMSOURCE_CONN_HEARTBEAT_PERIOD])
+ && difftime(*(NOW), last_sent_time) >= (double)jnlpool.gtmsource_local->connect_parms[GTMSOURCE_CONN_HEARTBEAT_PERIOD])
#else
-#define gtmsource_is_heartbeat_due(now) FALSE
+#define GTMSOURCE_IS_HEARTBEAT_DUE(NOW) FALSE
#endif
GBLREF boolean_t heartbeat_stalled;
diff --git a/sr_port/gtmsource_poll_actions.c b/sr_port/gtmsource_poll_actions.c
index 47f3f89..e30dd43 100644
--- a/sr_port/gtmsource_poll_actions.c
+++ b/sr_port/gtmsource_poll_actions.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc.*
+ * Copyright 2001, 2013 Fidelity Information Services, Inc.*
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -85,7 +85,7 @@ int gtmsource_poll_actions(boolean_t poll_secondary)
repl_log(gtmsource_log_fp, TRUE, TRUE, "Shutdown signalled\n");
gtmsource_end(); /* Won't return */
}
-#ifdef UNIX
+# ifdef UNIX
if (jnlpool.jnlpool_ctl->freeze != last_seen_freeze_flag)
{
last_seen_freeze_flag = jnlpool.jnlpool_ctl->freeze;
@@ -104,13 +104,14 @@ int gtmsource_poll_actions(boolean_t poll_secondary)
repl_log(gtmsource_log_fp, TRUE, TRUE, print_msg);
}
}
-#endif
+# endif
if (GTMSOURCE_START == gtmsource_state)
return (SS_NORMAL);
- if (GTMSOURCE_CHANGING_MODE != gtmsource_state && GTMSOURCE_MODE_PASSIVE == gtmsource_local->mode)
+ if (GTMSOURCE_CHANGING_MODE != gtmsource_state && GTMSOURCE_MODE_PASSIVE_REQUESTED == gtmsource_local->mode)
{
repl_log(gtmsource_log_fp, TRUE, TRUE, "Changing mode from ACTIVE to PASSIVE\n");
gtmsource_state = GTMSOURCE_CHANGING_MODE;
+ gtmsource_local->mode = GTMSOURCE_MODE_PASSIVE;
UNIX_ONLY(gtmsource_local->gtmsource_state = gtmsource_state;)
return (SS_NORMAL);
}
@@ -123,7 +124,7 @@ int gtmsource_poll_actions(boolean_t poll_secondary)
* cause sig. time4 and temp_time are used as temporary variable for converting time to string.*/
GET_LONG(time4, &overdue_heartbeat.ack_time[0]);
temp_time = time4;
- time_ptr = GTM_CTIME(&temp_time);
+ GTM_CTIME(time_ptr, &temp_time);
memcpy(time_str, time_ptr, CTIME_BEFORE_NL);
time_str[CTIME_BEFORE_NL] = '\0';
VMS_ONLY(SPRINTF(msg_str, "No response received for heartbeat sent at %s with SEQNO %llu in %0.f seconds. "
@@ -145,7 +146,7 @@ int gtmsource_poll_actions(boolean_t poll_secondary)
return (SS_NORMAL);
}
- if (gtmsource_is_heartbeat_due(&now) && !gtmsource_is_heartbeat_stalled)
+ if (GTMSOURCE_IS_HEARTBEAT_DUE(&now) && !heartbeat_stalled)
{
gtmsource_send_heartbeat(&now);
if (GTMSOURCE_WAITING_FOR_CONNECTION == gtmsource_state ||
diff --git a/sr_port/gv_bind_name.c b/sr_port/gv_bind_name.c
index 9118da5..d1c14fb 100644
--- a/sr_port/gv_bind_name.c
+++ b/sr_port/gv_bind_name.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -54,6 +54,7 @@ void gv_bind_name(gd_addr *addr, mstr *targ)
int keylen;
char format_key[MAX_MIDENT_LEN + 1]; /* max key length + 1 byte for '^' */
gv_namehead *tmp_gvt;
+ sgmnt_addrs *csa;
gd_map = addr->maps;
gd_map_top = gd_map + addr->n_maps;
@@ -119,13 +120,13 @@ void gv_bind_name(gd_addr *addr, mstr *targ)
* and gv_currkey to get out of sync in case of an error condition.
*/
}
- change_reg();
if ((keylen = gvent.var_name.len + 2) > gv_cur_region->max_key_size) /* caution: embedded assignment of "keylen" */
{
assert(ARRAYSIZE(format_key) >= (1 + gvent.var_name.len));
format_key[0] = '^';
memcpy(&format_key[1], gvent.var_name.addr, gvent.var_name.len);
- rts_error(VARLSTCNT(10) ERR_KEY2BIG, 4, keylen, (int4)gv_cur_region->max_key_size,
+ csa = &FILE_INFO(gv_cur_region)->s_addrs;
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(10) ERR_KEY2BIG, 4, keylen, (int4)gv_cur_region->max_key_size,
REG_LEN_STR(gv_cur_region), ERR_GVIS, 2, 1 + gvent.var_name.len, format_key);
}
memcpy(gv_currkey->base, gvent.var_name.addr, gvent.var_name.len);
@@ -134,5 +135,6 @@ void gv_bind_name(gd_addr *addr, mstr *targ)
gv_currkey->base[gvent.var_name.len] = 0;
gv_currkey->end = gvent.var_name.len;
gv_currkey->prev = 0;
+ change_reg();
return;
}
diff --git a/sr_port/gv_rundown.c b/sr_port/gv_rundown.c
index c0c9e7b..f2cabb3 100644
--- a/sr_port/gv_rundown.c
+++ b/sr_port/gv_rundown.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -109,11 +109,11 @@ void gv_rundown(void)
# if defined(DEBUG) && defined(UNIX)
if (is_jnlpool_creator && ANTICIPATORY_FREEZE_AVAILABLE && TREF(gtm_test_fake_enospc))
{ /* Clear ENOSPC faking now that we are running down */
- csa = &FILE_INFO(r_local)->s_addrs;
+ csa = REG2CSA(r_local);
if (csa->nl->fake_db_enospc || csa->nl->fake_jnl_enospc)
{
- send_msg(VARLSTCNT(8) ERR_TEXT, 2, DB_LEN_STR(r_local), ERR_TEXT, 2,
- LEN_AND_LIT("Resetting fake_db_enospc and fake_jnl_enospc"));
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_TEXT, 2, DB_LEN_STR(r_local), ERR_TEXT,
+ 2, LEN_AND_LIT("Resetting fake_db_enospc and fake_jnl_enospc"));
csa->nl->fake_db_enospc = FALSE;
csa->nl->fake_jnl_enospc = FALSE;
}
@@ -244,5 +244,5 @@ void gv_rundown(void)
# endif
if (EXIT_NRM != rundown_status)
- rts_error(VARLSTCNT(1) ERR_NOTALLDBRNDWN);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOTALLDBRNDWN);
}
diff --git a/sr_port/gv_select.c b/sr_port/gv_select.c
index 1c032e3..8bf81be 100644
--- a/sr_port/gv_select.c
+++ b/sr_port/gv_select.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -111,7 +111,7 @@ void gv_select(char *cli_buff, int n_len, boolean_t freeze, char opname[], glist
}
if (0 >= len)
{
- gtm_putmsg(VARLSTCNT(4) ERR_SELECTSYNTAX, 2, LEN_AND_STR(opname));
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_SELECTSYNTAX, 2, LEN_AND_STR(opname));
mupip_exit(ERR_MUNOACTION);
}
c = gmap_beg.addr;
@@ -123,7 +123,7 @@ void gv_select(char *cli_buff, int n_len, boolean_t freeze, char opname[], glist
len--;
} else
{
- gtm_putmsg(VARLSTCNT(4) ERR_SELECTSYNTAX, 2, LEN_AND_STR(opname));
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_SELECTSYNTAX, 2, LEN_AND_STR(opname));
mupip_exit(ERR_MUNOACTION);
}
num_quote--;
@@ -153,7 +153,7 @@ void gv_select(char *cli_buff, int n_len, boolean_t freeze, char opname[], glist
*c = '~';
} else if (':' != *c)
{
- gtm_putmsg(VARLSTCNT(4) ERR_SELECTSYNTAX, 2, LEN_AND_STR(opname));
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_SELECTSYNTAX, 2, LEN_AND_STR(opname));
mupip_exit(ERR_MUNOACTION);
} else
{
@@ -170,7 +170,7 @@ void gv_select(char *cli_buff, int n_len, boolean_t freeze, char opname[], glist
MSTR_CMP(gmap_beg, gmap_end, rslt);
if (((c - gmap_end.addr) != gmap_end.len) || (0 < rslt))
{
- gtm_putmsg(VARLSTCNT(4) ERR_SELECTSYNTAX, 2, LEN_AND_STR(opname));
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_SELECTSYNTAX, 2, LEN_AND_STR(opname));
mupip_exit(ERR_MUNOACTION);
}
}
@@ -253,7 +253,7 @@ void gv_select(char *cli_buff, int n_len, boolean_t freeze, char opname[], glist
{
if (cs_addrs->hdr->freeze)
{
- gtm_putmsg(VARLSTCNT(4) ERR_FREEZE, 2, gv_cur_region->rname_len,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_FREEZE, 2, gv_cur_region->rname_len,
gv_cur_region->rname);
mupip_exit(ERR_MUNOFINISH);
}
@@ -261,7 +261,7 @@ void gv_select(char *cli_buff, int n_len, boolean_t freeze, char opname[], glist
if (gv_cur_region->read_only)
{
util_out_print("Cannot freeze the database",TRUE);
- gtm_putmsg(VARLSTCNT(4) ERR_DBRDONLY, 2,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_DBRDONLY, 2,
DB_LEN_STR(gv_cur_region));
mupip_exit(ERR_MUNOFINISH);
}
@@ -270,7 +270,7 @@ void gv_select(char *cli_buff, int n_len, boolean_t freeze, char opname[], glist
hiber_start(1000);
if (mu_ctrly_occurred || mu_ctrlc_occurred)
{
- gtm_putmsg(VARLSTCNT(1) ERR_FREEZECTRL);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_FREEZECTRL);
mupip_exit(ERR_MUNOFINISH);
}
}
@@ -281,7 +281,7 @@ void gv_select(char *cli_buff, int n_len, boolean_t freeze, char opname[], glist
gl_ptr = (glist*)malloc(SIZEOF(glist) - 1 + curr_gbl_name.str.len);
gl_ptr->name.mvtype = MV_STR;
gl_ptr->name.str.addr = (char*)gl_ptr->nbuf;
- gl_ptr->name.str.len = curr_gbl_name.str.len;
+ gl_ptr->name.str.len = MIN(curr_gbl_name.str.len, MAX_MIDENT_LEN);
memcpy(gl_ptr->nbuf, curr_gbl_name.str.addr, curr_gbl_name.str.len);
gl_ptr->next = 0;
if (append_gbl)
diff --git a/sr_port/gvcst_bmp_mark_free.c b/sr_port/gvcst_bmp_mark_free.c
index 86b031c..f90bd20 100644
--- a/sr_port/gvcst_bmp_mark_free.c
+++ b/sr_port/gvcst_bmp_mark_free.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -114,7 +114,7 @@ trans_num gvcst_bmp_mark_free(kill_set *ks)
assert(cs_data->db_got_to_v5_once); /* assert all V4 fmt blocks (including RECYCLED) have space for V5 upgrade */
inctn_detail.blknum_struct.blknum = 0; /* to indicate no adjustment to "blks_to_upgrd" necessary */
/* If any of the mini transaction below restarts because of an online rollback, we don't want the application
- * refresh to happen (like $ZONLNRLBK++ or rts_error(DBROLLEDBACK). This is because, although we are currently in
+ * refresh to happen (like $ZONLNRLBK++ or rts_error(DBROLLEDBACK). This is because, although we are currently in {BYPASSOK}
* non-tp (dollar_tleve = 0), we could actually be in a TP transaction and have actually faked dollar_tlevel. In
* such a case, we should NOT * be issuing a DBROLLEDBACK error as TP transactions are supposed to just restart in
* case of an online rollback. So, set the global variable that gtm_onln_rlbk_clnup can check and skip doing the
@@ -225,8 +225,8 @@ trans_num gvcst_bmp_mark_free(kill_set *ks)
* to the application. But, before that reset only_reset_clues_if_onln_rlbk to FALSE
*/
TREF(in_gvcst_bmp_mark_free) = FALSE;
- send_msg(VARLSTCNT(6) ERR_IGNBMPMRKFREE, 4, REG_LEN_STR(gv_cur_region),
- DB_LEN_STR(gv_cur_region));
+ send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(6) ERR_IGNBMPMRKFREE, 4,
+ REG_LEN_STR(gv_cur_region), DB_LEN_STR(gv_cur_region));
t_abort(gv_cur_region, cs_addrs);
return ret_tn; /* actually 0 */
}
diff --git a/sr_port/gvcst_expand_any_key.c b/sr_port/gvcst_expand_any_key.c
index 65ada75..0e52c77 100644
--- a/sr_port/gvcst_expand_any_key.c
+++ b/sr_port/gvcst_expand_any_key.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -83,7 +83,7 @@ enum cdb_sc gvcst_expand_any_key (sm_uc_ptr_t blk_base, sm_uc_ptr_t rec_top, sm_
GET_RSIZ(*rec_size, curptr);
if (0 == cur_level || BSTAR_REC_SIZE != *rec_size)
{
- READ_RECORD(cur_level, curptr, *keycmpc, *rec_size, expanded_key, *keylen, status);
+ READ_RECORD(status, rec_size, keycmpc, keylen, expanded_key, cur_level, blk_base, curptr);
if (cdb_sc_normal != status)
{
assert(t_tries < CDB_STAGNATE);
@@ -140,7 +140,7 @@ enum cdb_sc gvcst_expand_any_key (sm_uc_ptr_t blk_base, sm_uc_ptr_t rec_top, sm_
return status;
if (*keylen + *keycmpc) /* Previous key exists */
{
- GET_CMPC(*keycmpc, expanded_key, &expanded_star_key[0]);
+ GET_CMPC(*keycmpc, expanded_key, expanded_star_key);
}
memcpy(expanded_key, expanded_star_key, star_keylen + star_keycmpc);
*keylen = star_keylen + star_keycmpc - *keycmpc;
diff --git a/sr_port/gvcst_expand_free_subtree.c b/sr_port/gvcst_expand_free_subtree.c
index bce0b5d..218f835 100644
--- a/sr_port/gvcst_expand_free_subtree.c
+++ b/sr_port/gvcst_expand_free_subtree.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 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 gvcst_expand_free_subtree(kill_set *ks_head)
*/
free(temp_buff);
rel_crit(gv_cur_region);
- send_msg(VARLSTCNT(6) ERR_IGNBMPMRKFREE, 4, REG_LEN_STR(gv_cur_region),
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_IGNBMPMRKFREE, 4, REG_LEN_STR(gv_cur_region),
DB_LEN_STR(gv_cur_region));
return;
}
@@ -109,7 +109,7 @@ void gvcst_expand_free_subtree(kill_set *ks_head)
if (!(bp = (blk_hdr_ptr_t)t_qread(blk, (sm_int_ptr_t)&cycle, &cr)))
{ /* This should have worked because t_qread was done in crit */
free(temp_buff);
- rts_error(VARLSTCNT(4) ERR_GVKILLFAIL, 2, 1, &rdfail_detail);
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_GVKILLFAIL, 2, 1, &rdfail_detail);
}
if (NULL != cr)
{ /* It is possible that t_qread returned a buffer from first_tp_srch_status.
@@ -143,7 +143,7 @@ void gvcst_expand_free_subtree(kill_set *ks_head)
assert(FALSE);
kill_error = cdb_sc_rmisalign;
free(temp_buff);
- rts_error(VARLSTCNT(4) ERR_GVKILLFAIL, 2, 1, &kill_error);
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_GVKILLFAIL, 2, 1, &kill_error);
}
GET_LONG(temp_long, (block_id_ptr_t)((sm_uc_ptr_t)rp1 - SIZEOF(block_id)));
if (dollar_tlevel)
diff --git a/sr_port/gvcst_init.c b/sr_port/gvcst_init.c
index db56ca0..98000df 100644
--- a/sr_port/gvcst_init.c
+++ b/sr_port/gvcst_init.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -58,6 +58,9 @@
#ifdef UNIX
#include "heartbeat_timer.h"
#include "anticipatory_freeze.h"
+#include "wbox_test_init.h"
+
+#define MAX_DBINIT_RETRY 4
#endif
#ifdef GTM_FD_TRACE
@@ -77,7 +80,6 @@ GBLREF ua_list *first_ua, *curr_ua;
GBLREF short crash_count;
GBLREF uint4 dollar_tlevel;
GBLREF jnl_format_buffer *non_tp_jfb_ptr;
-GBLREF unsigned char *non_tp_jfb_buff_ptr;
GBLREF boolean_t mupip_jnl_recover;
GBLREF buddy_list *global_tlvl_info_list;
GBLREF tp_region *tp_reg_free_list; /* Ptr to list of tp_regions that are unused */
@@ -109,6 +111,7 @@ error_def(ERR_DBNOTGDS);
error_def(ERR_DBVERPERFWARN1);
error_def(ERR_DBVERPERFWARN2);
error_def(ERR_MMNODYNUPGRD);
+error_def(ERR_REGOPENFAIL);
void assert_jrec_member_offsets(void)
{
@@ -187,9 +190,10 @@ void assert_jrec_member_offsets(void)
/* Assumption about the structures in code */
assert(0 == MIN_ALIGN_RECLEN % JNL_REC_START_BNDRY);
assert(SIZEOF(uint4) == SIZEOF(jrec_suffix));
- assert((MAX_JNL_REC_SIZE - MAX_LOGI_JNL_REC_SIZE) > MIN_PBLK_RECLEN);
+ assert((SIZEOF(jnl_record) + MAX_LOGI_JNL_REC_SIZE + SIZEOF(jrec_suffix)) < MAX_JNL_REC_SIZE);
assert((DISK_BLOCK_SIZE * JNL_DEF_ALIGNSIZE) >= MAX_JNL_REC_SIZE);/* default alignsize supports max jnl record length */
- assert(MAX_DB_BLK_SIZE < MAX_JNL_REC_SIZE); /* Ensure a PBLK record can accommodate a full GDS block */
+ assert(MAX_MAX_NONTP_JNL_REC_SIZE <= MAX_JNL_REC_SIZE);
+ assert(MAX_DB_BLK_SIZE < MAX_MAX_NONTP_JNL_REC_SIZE); /* Ensure a PBLK record can accommodate a full GDS block */
assert(MAX_JNL_REC_SIZE <= (1 << 24));
/* Ensure that the 24-bit length field in the journal record can accommodate the maximum journal record size */
assert(tcom_record.prefix.forwptr == tcom_record.suffix.backptr);
@@ -206,6 +210,8 @@ void gvcst_init(gd_region *greg)
sgmnt_data_ptr_t temp_cs_data;
# endif
uint4 segment_update_array_size;
+ int4 bsize;
+ boolean_t realloc_alt_buff;
file_control *fc;
gd_region *prev_reg, *reg_top;
# ifdef DEBUG
@@ -232,6 +238,7 @@ void gvcst_init(gd_region *greg)
# ifdef UNIX
replpool_identifier replpool_id;
unsigned int full_len;
+ int4 db_init_retry;
# endif
DCL_THREADGBL_ACCESS;
@@ -243,8 +250,9 @@ void gvcst_init(gd_region *greg)
assert(SIZEOF(th_rec) == (SIZEOF(bt_rec) - SIZEOF(bt->blkque)));
assert(SIZEOF(cache_rec) == (SIZEOF(cache_state_rec) + SIZEOF(cr->blkque)));
DEBUG_ONLY(assert_jrec_member_offsets();)
+ assert(MAX_DB_BLK_SIZE < (1 << NEXT_OFF_MAX_BITS)); /* Ensure a off_chain record's next_off member
+ * can work with all possible block sizes */
set_num_additional_processors();
-
DEBUG_ONLY(
/* Note that the "block" member in the blk_ident structure in gdskill.h has 30 bits.
* Currently, the maximum number of blocks is 2**30. If ever this increases, something
@@ -339,11 +347,13 @@ void gvcst_init(gd_region *greg)
}
GTM_FD_TRACE_ONLY(gtm_dbjnl_dupfd_check();) /* check if any of db or jnl fds collide (D9I11-002714) */
greg->was_open = FALSE;
- /* we shouldn't have crit on any region unless we are in TP and in the final retry or we are in
- * mupip_set_journal trying to switch journals across all regions. Currently, there is no fine-granular
- * checking for mupip_set_journal, hence a coarse MUPIP_IMAGE check for image_type
+ /* We shouldn't have crit on any region unless we are in TP and in the final retry or we are in mupip_set_journal trying to
+ * switch journals across all regions. WBTEST_HOLD_CRIT_ENABLED is an exception because it exercises a deadlock situation so
+ * it needs to hold multiple crits at the same time. Currently, there is no fine-granular checking for mupip_set_journal,
+ * hence a coarse MUPIP_IMAGE check for image_type.
*/
- assert(dollar_tlevel && (CDB_STAGNATE <= t_tries) || IS_MUPIP_IMAGE || (0 == have_crit(CRIT_HAVE_ANY_REG)));
+ assert(dollar_tlevel && (CDB_STAGNATE <= t_tries) || IS_MUPIP_IMAGE || (0 == have_crit(CRIT_HAVE_ANY_REG))
+ || WBTEST_ENABLED(WBTEST_HOLD_CRIT_ENABLED));
if (dollar_tlevel && (0 != have_crit(CRIT_HAVE_ANY_REG)))
{ /* To avoid deadlocks with currently holding crits and the DLM lock request to be done in db_init(),
* we should insert this region in the tp_reg_list and tp_restart should do the gvcst_init after
@@ -368,9 +378,9 @@ void gvcst_init(gd_region *greg)
csa->jnl = NULL;
csa->persistent_freeze = FALSE; /* want secshr_db_clnup() to clear an incomplete freeze/unfreeze codepath */
csa->regcnt = 1; /* At this point, only one region points to this csa */
-# ifdef VMS
csa->db_addrs[0] = csa->db_addrs[1] = NULL;
csa->lock_addrs[0] = csa->lock_addrs[1] = NULL;
+# ifdef VMS
greg_acc_meth = greg->dyn.addr->acc_meth;
assert(dba_cm != greg_acc_meth);
temp_cs_data = (sgmnt_data_ptr_t)cs_data_buff;
@@ -469,8 +479,23 @@ void gvcst_init(gd_region *greg)
* thus would be left over in the system.
*/
DEFER_INTERRUPTS(INTRPT_IN_GVCST_INIT);
- VMS_ONLY(db_init(greg, temp_cs_data);)
- UNIX_ONLY(db_init(greg);)
+ VMS_ONLY(db_init(greg, temp_cs_data));
+# ifdef UNIX
+ db_init_retry = 0;
+ GTM_WHITE_BOX_TEST(WBTEST_HOLD_FTOK_UNTIL_BYPASS, db_init_retry, 3);
+ for (; db_init_retry < MAX_DBINIT_RETRY; db_init_retry++)
+ {
+ if (0 == db_init(greg))
+ break;
+ db_init_err_cleanup(MAX_DBINIT_RETRY > (db_init_retry + 1));
+ }
+ if (MAX_DBINIT_RETRY == db_init_retry) /* We retried enough. Error out. */
+ {
+ assert(IS_LKE_IMAGE || IS_DSE_IMAGE);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REGOPENFAIL, 4, REG_LEN_STR(greg), DB_LEN_STR(greg));
+ }
+
+# endif
/* At this point, we have initialized the database, but haven't yet set reg->open to TRUE. If any rts_errors happen in
* the meantime, there are no condition handlers established to handle the rts_error. More importantly, it is non-trivial
* to add logic to such a condition handler to undo the effects of db_init. Also, in some cases, the rts_error can can
@@ -490,17 +515,6 @@ void gvcst_init(gd_region *greg)
/* set csd and fill in selected fields */
assert(greg->dyn.addr->acc_meth == csd->acc_meth); /* db_init should have made sure this assert holds good */
greg_acc_meth = csd->acc_meth;
- switch (greg_acc_meth)
- {
- case dba_mm:
- csa->acc_meth.mm.base_addr = (sm_uc_ptr_t)((sm_ulong_t)csd + (int)(csd->start_vbn - 1) * DISK_BLOCK_SIZE);
- break;
- case dba_bg:
- db_csh_ini(csa);
- break;
- default:
- GTMASSERT;
- }
/* It is necessary that we do the pending gv_target list reallocation BEFORE db_common_init as the latter resets
* greg->max_key_size to be equal to the csd->max_key_size and hence process_gvt_pending_list might wrongly conclude
* that NO reallocation (since it checks greg->max_key_size with csd->max_key_size) is needed when in fact a
@@ -524,9 +538,9 @@ void gvcst_init(gd_region *greg)
&& COMPSWAP_LOCK(&csd->next_upgrd_warn.time_latch, next_warn_uint4, 0, (curr_time_uint4 + UPGRD_WARN_INTERVAL), 0))
{ /* The msg is due and we have successfully updated the next time interval */
if (GDSVCURR != csd->desired_db_format)
- send_msg(VARLSTCNT(4) ERR_DBVERPERFWARN1, 2, DB_LEN_STR(greg));
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_DBVERPERFWARN1, 2, DB_LEN_STR(greg));
else
- send_msg(VARLSTCNT(4) ERR_DBVERPERFWARN2, 2, DB_LEN_STR(greg));
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_DBVERPERFWARN2, 2, DB_LEN_STR(greg));
}
/* Compute the maximum journal space requirements for a PBLK (including possible ALIGN record).
@@ -573,22 +587,37 @@ void gvcst_init(gd_region *greg)
assert(global_tlvl_info_list || !csa->sgm_info_ptr);
if (JNL_ALLOWED(csa))
{
+ bsize = csd->blk_size;
+ realloc_alt_buff = FALSE;
if (NULL == non_tp_jfb_ptr)
{
non_tp_jfb_ptr = (jnl_format_buffer *)malloc(SIZEOF(jnl_format_buffer));
- non_tp_jfb_buff_ptr = (unsigned char *)malloc(MAX_JNL_REC_SIZE);
- non_tp_jfb_ptr->buff = (char *)non_tp_jfb_buff_ptr;
- /* If the journal records need to be encrypted in the journal file and if replication is in use,
- * we will need access to both the encrypted (for the journal file) and unencrypted (for the
- * journal pool) journal record contents. Since this code is executed only once (for the first
- * journaled database opened) by this process, we will have to allocate an alternate buffer
- * for this purpose (to hold the unencrypted data) as long as this GT.M version supports encryption.
- */
- GTMCRYPT_ONLY(
- non_tp_jfb_ptr->alt_buff = (char *)malloc(MAX_JNL_REC_SIZE);
- )
+ non_tp_jfb_ptr->hi_water_bsize = bsize;
+ non_tp_jfb_ptr->buff = (char *)malloc(MAX_NONTP_JNL_REC_SIZE(bsize));
non_tp_jfb_ptr->record_size = 0; /* initialize it to 0 since TOTAL_NONTPJNL_REC_SIZE macro uses it */
+ GTMCRYPT_ONLY(non_tp_jfb_ptr->alt_buff = NULL);
+ } else if (bsize > non_tp_jfb_ptr->hi_water_bsize)
+ { /* Need a larger buffer to accommodate larger non-TP journal records */
+ non_tp_jfb_ptr->hi_water_bsize = bsize;
+ free(non_tp_jfb_ptr->buff);
+ non_tp_jfb_ptr->buff = (char *)malloc(MAX_NONTP_JNL_REC_SIZE(bsize));
+# ifdef GTM_CRYPT
+ if (NULL != non_tp_jfb_ptr->alt_buff)
+ {
+ free(non_tp_jfb_ptr->alt_buff);
+ realloc_alt_buff = TRUE;
+ }
+# endif
}
+ /* If the journal records need to be encrypted in the journal file and if replication is in use,
+ * we will need access to both the encrypted (for the journal file) and unencrypted (for the
+ * journal pool) journal record contents. Allocate an alternative buffer if any open journaled region
+ * is encrypted.
+ */
+# ifdef GTM_CRYPT
+ if (realloc_alt_buff || (csd->is_encrypted && (NULL == non_tp_jfb_ptr->alt_buff)))
+ non_tp_jfb_ptr->alt_buff = (char *)malloc(MAX_NONTP_JNL_REC_SIZE(non_tp_jfb_ptr->hi_water_bsize));
+# endif
/* csa->min_total_tpjnl_rec_size represents the minimum journal buffer space needed for a TP transaction.
* It is a conservative estimate assuming that one ALIGN record and one PINI record will be written for
* one set of fixed size jnl records written.
diff --git a/sr_port/gvcst_kill.c b/sr_port/gvcst_kill.c
index 85c0ef8..d2f99d2 100644
--- a/sr_port/gvcst_kill.c
+++ b/sr_port/gvcst_kill.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -746,9 +746,8 @@ research:
WAIT_ON_INHIBIT_KILLS(cnl, MAXWAIT2KILL);
}
if ((trans_num)0 == t_end(gvt_hist, alt_hist, TN_NOT_SPECIFIED))
- { /* In case this is MM and t_end caused a database extension, reset csd */
- assert(is_mm || (csd == cs_data));
- csd = cs_data;
+ {
+ assert(csd == cs_data); /* To ensure they are the same even if MM extensions happened in between */
if (jnl_fence_ctl.level && next_fenced_was_null && actual_update && write_logical_jnlrecs)
{ /* If ZTransaction and first KILL and the kill resulted in an update
* Note that "write_logical_jnlrecs" is used above instead of JNL_WRITE_LOGICAL_RECS(csa)
@@ -770,9 +769,7 @@ research:
update_trans = UPDTRNS_DB_UPDATED_MASK;
continue;
}
- /* In case this is MM and t_end caused a database extension, reset csd */
- assert(is_mm || (csd == cs_data));
- csd = cs_data;
+ assert(csd == cs_data); /* To ensure they are the same even if MM extensions happened in between */
} else
{
cdb_status = tp_hist(alt_hist);
@@ -787,7 +784,7 @@ research:
assert(gvt_root);
GVTR_OP_TCOMMIT(cdb_status);
if (cdb_sc_normal != cdb_status)
- GOTO_RETRY(SKIP_ASSERT_FALSE);
+ GOTO_RETRY(SKIP_ASSERT_TRUE);
}
# endif
if (!killing_chunks)
@@ -815,11 +812,7 @@ research:
assert(!csd->dsid);
ENABLE_WBTEST_ABANDONEDKILL;
gvcst_expand_free_subtree(&kill_set_head);
- /* In case this is MM and "gvcst_expand_free_subtree" called "gvcst_bmp_mark_free"
- * which in turn called "t_retry" which remapped an extended database, reset csd.
- */
- assert(is_mm || (csd == cs_data));
- csd = cs_data;
+ assert(csd == cs_data); /* To ensure they are the same even if MM extensions happened in between */
DECR_KIP(csd, csa, kip_csa);
}
assert(0 < kill_set_head.used || (NULL == kip_csa));
@@ -892,8 +885,6 @@ retry:
*/
update_trans = UPDTRNS_DB_UPDATED_MASK;
}
- /* In case this is MM and "t_retry" remapped an extended database, reset csd */
- assert(is_mm || (csd == cs_data));
- csd = cs_data;
+ assert(csd == cs_data); /* To ensure they are the same even if MM extensions happened in between */
}
}
diff --git a/sr_port/gvcst_map_build.c b/sr_port/gvcst_map_build.c
index a2fcec5..5871c0f 100644
--- a/sr_port/gvcst_map_build.c
+++ b/sr_port/gvcst_map_build.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -27,8 +27,6 @@
GBLREF gd_region *gv_cur_region;
GBLREF sgmnt_addrs *cs_addrs;
-GBLREF boolean_t dse_running;
-GBLREF boolean_t mu_reorg_upgrd_dwngrd_in_prog;
void gvcst_map_build(uint4 *array, sm_uc_ptr_t base_addr, cw_set_element *cs, trans_num ctn)
{
@@ -47,33 +45,7 @@ void gvcst_map_build(uint4 *array, sm_uc_ptr_t base_addr, cw_set_element *cs, tr
((blk_hdr_ptr_t)base_addr)->tn = ctn;
base_addr += SIZEOF(blk_hdr);
assert(cs_addrs->now_crit); /* Don't want to be messing with highest_lbm_with_busy_blk outside crit */
- if (cs_addrs->nl->trunc_pid)
- { /* A truncate is in progress. We need to 1) update cnl->highest_lbm_with_busy_blk if needed and 2) select bml_free if
- * this is a t_recycled2free transaction.
- */
- if (cs->reference_cnt > 0)
- {
- bml_func = bml_busy;
- cs_addrs->nl->highest_lbm_with_busy_blk = MAX(cs->blk, cs_addrs->nl->highest_lbm_with_busy_blk);
- } else if (cs->reference_cnt < 0)
- {
- if (cs_addrs->hdr->db_got_to_v5_once && (CSE_LEVEL_DRT_LVL0_FREE != cs->level))
- bml_func = bml_recycled;
- else /* always set the block as free when gvcst_bmp_mark_free a level-0 block in DIR tree */
- {
- bml_func = bml_free;
- /* reset level since t_end will call bml_status_check which has an assert for bitmap block level */
- cs->level = LCL_MAP_LEVL;
- }
- } else /* cs->reference_cnt == 0 */
- {
- if (cs_addrs->hdr->db_got_to_v5_once && mu_reorg_upgrd_dwngrd_in_prog)
- bml_func = bml_recycled;
- else
- bml_func = bml_free;
- }
- } else /* Choose bml_func as it was chosen before truncate feature. */
- bml_func = (cs->reference_cnt > 0) ? bml_busy : (cs_addrs->hdr->db_got_to_v5_once ? bml_recycled : bml_free);
+ DETERMINE_BML_FUNC(bml_func, cs, cs_addrs);
DEBUG_ONLY(prev_bitnum = -1;)
while (bitnum = *array) /* caution : intended assignment */
{
diff --git a/sr_port/gvcst_protos.h b/sr_port/gvcst_protos.h
index fd5c8fb..343450b 100644
--- a/sr_port/gvcst_protos.h
+++ b/sr_port/gvcst_protos.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2004, 2012 Fidelity Information Services, Inc *
+ * Copyright 2004, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -18,7 +18,8 @@ void db_auto_upgrade(gd_region *reg);
#ifdef VMS
void db_init(gd_region *reg, sgmnt_data_ptr_t tsd);
#else
-void db_init(gd_region *reg);
+int db_init(gd_region *reg);
+void db_init_err_cleanup(boolean_t retry_dbinit);
void gvcst_redo_root_search(void);
#endif
gd_region *dbfilopn (gd_region *reg);
diff --git a/sr_port/gvcst_put.c b/sr_port/gvcst_put.c
index e05c1d7..98bf645 100644
--- a/sr_port/gvcst_put.c
+++ b/sr_port/gvcst_put.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -151,7 +151,7 @@ error_def(ERR_UNIMPLOP);
/* Before issuing an error, add GVT to the list of known gvts in this TP transaction in case it is not already done.
* This GVT addition is usually done by "tp_hist" but that function has most likely not yet been invoked in gvcst_put.
* Doing this addition will ensure we remember to reset any non-zero clue in dir_tree as part of tp_clean_up when a TROLLBACK
- * or TRESTART (implicit or explicit) occurs. Not doing so could means if an rts_error(ERR_REC2BIG) happens here, control will
+ * or TRESTART (implicit or explicit) occurs. Not doing so could means if an ERR_REC2BIG happens here, control will
* go to the error trap and if it does a TROLLBACK (which does a tp_clean_up) we would be left with a potentially out-of-date
* clue of GVT which if used for later global references could result in db integ errors.
*/
@@ -163,7 +163,7 @@ error_def(ERR_UNIMPLOP);
{ \
if (0 == (end = format_targ_key(buff, MAX_ZWR_KEY_SZ, gv_currkey, TRUE))) \
end = &buff[MAX_ZWR_KEY_SZ - 1]; \
- rts_error(VARLSTCNT(10) ERR_REC2BIG, 4, VMS_ONLY(gv_currkey->end + 1 + SIZEOF(rec_hdr) +) \
+ rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(10) ERR_REC2BIG, 4, VMS_ONLY(gv_currkey->end + 1 + SIZEOF(rec_hdr) +) \
value.len, (int4)gv_cur_region->max_rec_size, \
REG_LEN_STR(gv_cur_region), ERR_GVIS, 2, end - buff, buff); \
} \
@@ -179,7 +179,7 @@ error_def(ERR_UNIMPLOP);
*/ \
if (0 == (end = format_targ_key(buff, MAX_ZWR_KEY_SZ, gv_currkey, TRUE))) \
end = &buff[MAX_ZWR_KEY_SZ - 1]; \
- rts_error(VARLSTCNT(11) ERR_RSVDBYTE2HIGH, 5, new_blk_size_single, \
+ rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(11) ERR_RSVDBYTE2HIGH, 5, new_blk_size_single, \
REG_LEN_STR(gv_cur_region), blk_size, blk_reserved_bytes, \
ERR_GVIS, 2, end - buff, buff); \
}
@@ -334,7 +334,7 @@ void gvcst_put(mval *val)
* as in the case of implicit TP for triggers, we issue a DBROLLEDBACK error that the application
* programmer can catch.
*/
- rts_error(VARLSTCNT(1) ERR_DBROLLEDBACK);
+ rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(1) ERR_DBROLLEDBACK);
}
tp_set_sgm();
GVCST_ROOT_SEARCH;
@@ -483,6 +483,7 @@ void gvcst_put2(mval *val, span_parms *parms)
mval *lcl_val; /* local copy of "val" at function entry.
* used to restore "val" in case of TP restarts */
mval *lcl_val_forjnl;
+ mval *pval; /* copy of "value" (an mstr), protected from stp gcol */
DEBUG_ONLY(enum cdb_sc save_cdb_status;)
# endif
# ifdef DEBUG
@@ -614,11 +615,7 @@ tn_restart:
dbg_trace_array[dbg_num_iters].retry_line = 0;
split_targ = NULL;
)
- /* If MM and file extension occurred, reset csd to cs_data to avoid out-of-date value. If BG we dont need the reset
- * but if checks are costlier than unconditional sets in a pipelined architecture so we choose not to do the if.
- */
- assert(is_mm || (csd == cs_data));
- csd = cs_data;
+ assert(csd == cs_data); /* To ensure they are the same even if MM extensions happened in between */
# ifdef GTM_TRIGGER
gvtr_parms.num_triggers_invoked = 0; /* clear any leftover value */
assert(!ztval_gvcst_put_redo || IS_PTR_INSIDE_M_STACK(val));
@@ -1027,7 +1024,15 @@ tn_restart:
ztold_mval->str.len = data_len;
if (data_len)
{
- ENSURE_STP_FREE_SPACE(data_len);
+ if (!(IS_STP_SPACE_AVAILABLE(data_len)))
+ {
+ PUSH_MV_STENT(MVST_MVAL); /* protect "value" mstr from stp gcol */
+ pval = &mv_chain->mv_st_cont.mvs_mval;
+ pval->str = value;
+ ENSURE_STP_FREE_SPACE(data_len);
+ value = pval->str;
+ POP_MV_STENT(); /* pval */
+ }
ztold_mval->str.addr = (char *)stringpool.free;
memcpy(ztold_mval->str.addr, (sm_uc_ptr_t)rp + cur_val_offset, data_len);
stringpool.free += data_len;
@@ -1264,7 +1269,7 @@ tn_restart:
* definition for why the below macro call is necessary.
*/
ADD_TO_GVT_TP_LIST(gv_target, RESET_FIRST_TP_SRCH_STATUS_FALSE);
- rts_error(VARLSTCNT(4) ERR_GVINCRISOLATION, 2,
+ rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_GVINCRISOLATION, 2,
gv_target->gvname.var_name.len, gv_target->gvname.var_name.addr);
}
if (NULL == cse->recompute_list_tail ||
@@ -1304,7 +1309,6 @@ tn_restart:
assert(blk_reserved_size >= blk_fill_size);
extra_record_orig_size = 0;
prev_rec_offset = bh->prev_rec.offset;
- assert(new_blk_size_single <= new_blk_size_r);
/* Decide which side (left or right) the new record goes. Ensure either side has at least one record.
* This means we might not honor the desired FillFactor if the only record in a block exceeds the
* blk_fill_size, but in this case we are guaranteed the block has room for the current reserved bytes.
@@ -2575,7 +2579,7 @@ retry:
* Issue DBROLLEDBACK error that the application programmer can catch and do the necessary stuff.
*/
assert(gtm_trigger_depth == tstart_trigger_depth);
- rts_error(VARLSTCNT(1) ERR_DBROLLEDBACK);
+ rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(1) ERR_DBROLLEDBACK);
}
/* Note: In case of cdb_sc_onln_rlbk1, the restart logic will take care of doing the root search */
# endif
diff --git a/sr_port/gvcst_search.c b/sr_port/gvcst_search.c
index 786b471..ae1b082 100644
--- a/sr_port/gvcst_search.c
+++ b/sr_port/gvcst_search.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -78,7 +78,9 @@ enum cdb_sc gvcst_search(gv_key *pKey, /* Key to search for */
sm_uc_ptr_t buffaddr;
trans_num blkhdrtn, oldest_hist_tn;
int hist_size;
+ DCL_THREADGBL_ACCESS;
+ SETUP_THREADGBL_ACCESS;
pTarg = gv_target;
assert(NULL != pTarg);
assert(pTarg->root);
@@ -156,6 +158,7 @@ enum cdb_sc gvcst_search(gv_key *pKey, /* Key to search for */
*/
tp_srch_status = NULL;
leaf_blk_hist = &pTarg->hist.h[0];
+ assert(leaf_blk_hist->blk_target == pTarg);
assert(0 == leaf_blk_hist->level);
chain1 = *(off_chain *)&leaf_blk_hist->blk_num;
if (chain1.flag == 1)
@@ -179,7 +182,7 @@ enum cdb_sc gvcst_search(gv_key *pKey, /* Key to search for */
cse = (NULL != tp_srch_status) ? tp_srch_status->cse : NULL;
}
assert(!cse || !cse->high_tlevel);
- if ((NULL == tp_srch_status) || (tp_srch_status->blk_target == leaf_blk_hist->blk_target))
+ if ((NULL == tp_srch_status) || (tp_srch_status->blk_target == pTarg))
{ /* Either the leaf level block in clue is not already present in the current TP transaction's
* hashtable OR it is already present and the corresponding globals match. If they dont match
* we know for sure the clue is out-of-date (i.e. using it will lead to a transaction restart)
@@ -235,19 +238,33 @@ enum cdb_sc gvcst_search(gv_key *pKey, /* Key to search for */
leaf_blk_hist->cycle = CYCLE_PVT_COPY;
leaf_blk_hist->buffaddr = cse->new_buff;
} else
- { /* Keep leaf_blk_hist->buffaddr and cse->new_buff in sync. Dont know how they
- * cannot be the same but it seems possible if the gvcst_blk_build happened as
- * part of a t_qread call (which does not have enough information to update the
- * search history buffer address) without going through gvcst_search. Since the
- * consequences of these two not being in sync are database damage, we fix them
- * in pro just in case they are different.
+ { /* Keep leaf_blk_hist->buffaddr and cse->new_buff in sync. If a TP transaction
+ * updates two different globals and the second update invoked t_qread for a leaf
+ * block corresponding to the first global and ended up constructing a private block
+ * then leaf_blk_hist->buffaddr of the first global will be out-of-sync with the
+ * cse->new_buff. However, the transaction validation done in tp_hist/tp_tend
+ * should detect this and restart. Set donot_commit to verify that a restart happens
*/
- assert(leaf_blk_hist->buffaddr == cse->new_buff);
- leaf_blk_hist->buffaddr = cse->new_buff;
+# ifdef DEBUG
+ if (leaf_blk_hist->buffaddr != cse->new_buff)
+ TREF(donot_commit) |= DONOTCOMMIT_GVCST_SEARCH_LEAF_BUFFADR_NOTSYNC;
+# endif
+ leaf_blk_hist->buffaddr = cse->new_buff; /* sync the buffers in pro, just in case */
}
}
} else
- status = cdb_sc_lostcr; /* two different gv_targets point to same block; discard out-of-date clue */
+ { /* Two different gv_targets point to same block; discard out-of-date clue. */
+# ifdef DEBUG
+ if ((pTarg->read_local_tn >= local_tn) && (NULL != leaf_blk_hist->first_tp_srch_status))
+ { /* Since the clue was used in *this* transaction, it cannot successfully complete. Set
+ * donot_commit to verify that a restart happens (either in tp_hist or tp_tend)
+ */
+ assert(pTarg->read_local_tn == local_tn);
+ TREF(donot_commit) |= DONOTCOMMIT_GVCST_SEARCH_BLKTARGET_MISMATCH;
+ }
+# endif
+ status = cdb_sc_lostcr;
+ }
}
/* Validate EVERY level in the clue before using it for ALL retries. This way we avoid unnecessary restarts.
* This is NECESSARY for the final retry (e.g. in a TP transaction that does LOTS of reads of different globals,
diff --git a/sr_port/have_crit.c b/sr_port/have_crit.c
index 04aa469..d9d69cb 100644
--- a/sr_port/have_crit.c
+++ b/sr_port/have_crit.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -64,7 +64,7 @@ uint4 have_crit(uint4 crit_state)
UNIX_ONLY(assert(!jgbl.onlnrlbk)); /* should not request crit to be released if online rollback */
crit_state |= CRIT_ALL_REGIONS;
}
- if (0 != crit_count)
+ if ((0 != crit_count) && (crit_state & CRIT_HAVE_ANY_REG))
{
crit_reg_cnt++;
if (0 == (crit_state & CRIT_ALL_REGIONS))
@@ -79,7 +79,7 @@ uint4 have_crit(uint4 crit_state)
csa = &FILE_INFO(r_local)->s_addrs;
if (NULL != csa)
{
- if (csa->now_crit)
+ if ((csa->now_crit) && (crit_state & CRIT_HAVE_ANY_REG))
{
crit_reg_cnt++;
/* It is possible that if DSE has done a CRIT REMOVE and stolen our crit, it
@@ -98,12 +98,11 @@ uint4 have_crit(uint4 crit_state)
(0 == (crit_state & CRIT_NOT_TRANS_REG) ||
crit_deadlock_check_cycle != csa->crit_check_cycle))
{
- assert(FALSE);
+ assert(WBTEST_HOLD_CRIT_ENABLED);
assert(!csa->hold_onto_crit);
rel_crit(r_local);
- send_msg(VARLSTCNT(8) ERR_MUTEXRELEASED, 6,
- process_id, process_id, DB_LEN_STR(r_local),
- dollar_tlevel, t_tries);
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_MUTEXRELEASED, 6, process_id,
+ process_id, DB_LEN_STR(r_local), dollar_tlevel, t_tries);
}
if (0 == (crit_state & CRIT_ALL_REGIONS))
return crit_reg_cnt;
@@ -132,7 +131,7 @@ uint4 have_crit(uint4 crit_state)
if (NULL != jnlpool.jnlpool_ctl)
{
csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs;
- if (NULL != csa && csa->now_crit)
+ if ((NULL != csa) && csa->now_crit && (crit_state & CRIT_HAVE_ANY_REG))
{
crit_reg_cnt++;
if (0 != (crit_state & CRIT_RELEASE))
diff --git a/sr_port/have_crit.h b/sr_port/have_crit.h
index 6791130..c515bf6 100644
--- a/sr_port/have_crit.h
+++ b/sr_port/have_crit.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -18,18 +18,12 @@
#endif
/* states of CRIT passed as argument to have_crit() */
-#define CRIT_IN_COMMIT 0x00000001
-#define CRIT_NOT_TRANS_REG 0x00000002
-#define CRIT_RELEASE 0x00000004
-#define CRIT_ALL_REGIONS 0x00000008
-
-#define CRIT_IN_WTSTART 0x00000010 /* check if csa->in_wtstart is true */
-
-/* Note absence of any flags is default value which finds if any region
- * or the replication pool have crit or are getting crit. It returns
- * when one is found without checking further.
-*/
-#define CRIT_HAVE_ANY_REG 0x00000000
+#define CRIT_HAVE_ANY_REG 0x00000001
+#define CRIT_IN_COMMIT 0x00000002
+#define CRIT_NOT_TRANS_REG 0x00000004
+#define CRIT_RELEASE 0x00000008
+#define CRIT_ALL_REGIONS 0x00000010
+#define CRIT_IN_WTSTART 0x00000020 /* check if csa->in_wtstart is true */
#ifdef DEBUG
#include "wbox_test_init.h"
@@ -62,22 +56,55 @@ typedef enum
INTRPT_IN_WCS_WTSTART, /* Deferring interrupts until cnl->intent_wtstart is decremented and dbsync timer is
* started */
INTRPT_IN_REFORMAT_BUFFER_USE, /* Deferring interrupts until buffer is reformatted */
+ INTRPT_IN_X_TIME_FUNCTION, /* Deferring interrupts in non-nesting functions, such as localtime, ctime, and mktime. */
+ INTRPT_IN_FUNC_WITH_MALLOC, /* Deferring interrupts while in libc- or system functions that do a malloc internally. */
+ INTRPT_IN_FDOPEN, /* Deferring interrupts in fdopen. */
+ INTRPT_IN_LOG_FUNCTION, /* Deferring interrupts in openlog, syslog, or closelog. */
+ INTRPT_IN_FORK_OR_SYSTEM, /* Deferring interrupts in fork or system. */
+ INTRPT_IN_FSTAT, /* Deferring interrupts in fstat. */
INTRPT_NUM_STATES /* Should be the *last* one in the enum */
} intrpt_state_t;
GBLREF intrpt_state_t intrpt_ok_state;
GBLREF boolean_t deferred_timers_check_needed;
-/* Macro to check if we are in a state that is ok to interrupt (or to do deferred signal handling).
- * We do not want to interrupt if the global variable intrpt_ok_state indicates it is not ok to interrupt,
- * if we are in the midst of a malloc, if we are holding crit, if we are in the midst of commit, or in
- * wcs_wtstart. In the last case, we could be causing another process HOLDING CRIT on the region to wait
- * in bg_update_phase1 if we hold the write interlock. Hence it is important for us to finish that as soon
- * as possible and not interrupt it.
+/* Macro to check if we are in a state that is ok to interrupt (or to do deferred signal handling). We do not want to interrupt if
+ * the global variable intrpt_ok_state indicates it is not ok to interrupt, if we are in the midst of a malloc, if we are holding
+ * crit, if we are in the midst of commit, or in wcs_wtstart. In the last case, we could be causing another process HOLDING CRIT on
+ * the region to wait in bg_update_phase1 if we hold the write interlock. Hence it is important for us to finish that as soon as
+ * possible and not interrupt it.
*/
#define OK_TO_INTERRUPT ((INTRPT_OK_TO_INTERRUPT == intrpt_ok_state) && (0 == gtmMallocDepth) \
&& (0 == have_crit(CRIT_HAVE_ANY_REG | CRIT_IN_COMMIT | CRIT_IN_WTSTART)))
+/* Set the value of forced_exit to 1. This should indicate that we want a deferred signal handler to be invoked first upon leaving
+ * the current deferred window. Since we do not want forced_exit state to ever regress, and there might be several signals delivered
+ * within the same deferred window, assert that forced_exit is either 0 or 1 before setting it to 1.
+ */
+#define SET_FORCED_EXIT_STATE \
+{ \
+ GBLREF VSIG_ATOMIC_T forced_exit; \
+ \
+ assert((0 == forced_exit) || (1 == forced_exit)); \
+ forced_exit = 1; \
+}
+
+/* Set the value of forced_exit to 2. This should indicate that we are already in the exit processing, and do not want to handle any
+ * deferred events, from timers or other interrupts, anymore. Ensure that forced_exit state does not regress by asserting that the
+ * current value is 0 or 1 before setting it to 2. Note that on UNIX forced_exit can progress to 2 only from 1, while on VMS it is
+ * possible to generic_exit_handler or dbcertify_exit_handler to change forced_exit from 0 to 2 directly. This design ensures that
+ * on VMS we will not invoke sys$exit from DEFERRED_EXIT_HANDLING_CHECK after we started exit processing; on UNIX process_exiting
+ * flag servs the same purpose (and is also checked by DEFERRED_EXIT_HANDLING_CHECK), so it is not necessary for either
+ * generic_signal_handler or dbcertify_signal_handler to set forced_exit to 2.
+ */
+#define SET_FORCED_EXIT_STATE_ALREADY_EXITING \
+{ \
+ GBLREF VSIG_ATOMIC_T forced_exit; \
+ \
+ assert(VMS_ONLY((0 == forced_exit) || ) (1 == forced_exit)); \
+ forced_exit = 2; \
+}
+
/* Macro to be used whenever we want to handle any signals that we deferred handling and exit in the process.
* In VMS, we dont do any signal handling, only exit handling.
*/
@@ -88,21 +115,29 @@ GBLREF boolean_t deferred_timers_check_needed;
GBLREF VSIG_ATOMIC_T forced_exit; \
GBLREF volatile int4 gtmMallocDepth; \
\
- if (forced_exit) \
- { \
- if (!process_exiting && OK_TO_INTERRUPT) \
+ /* The forced_exit state of 2 indicates that the exit is already in progress, so we do not \
+ * need to process any deferred events. \
+ */ \
+ if (2 > forced_exit) \
+ { /* If forced_exit was set while in a deferred state, disregard any deferred timers and \
+ * invoke deferred_signal_handler directly. \
+ */ \
+ if (forced_exit) \
{ \
- UNIX_ONLY(deferred_signal_handler();) \
- VMS_ONLY(sys$exit(exi_condition);) \
+ if (!process_exiting && OK_TO_INTERRUPT) \
+ { \
+ UNIX_ONLY(deferred_signal_handler();) \
+ VMS_ONLY(sys$exit(exi_condition);) \
+ } \
+ } \
+ UNIX_ONLY( \
+ else if (deferred_timers_check_needed) \
+ { \
+ if (!process_exiting && OK_TO_INTERRUPT) \
+ check_for_deferred_timers(); \
} \
- } \
- UNIX_ONLY( \
- else if (deferred_timers_check_needed) \
- { \
- if (!process_exiting && OK_TO_INTERRUPT) \
- check_for_deferred_timers(); \
- } \
- ) \
+ ) \
+ } \
}
/* Macro to cause deferrable interrupts to be deferred recording the cause.
@@ -153,6 +188,10 @@ 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_FORK_OR_SYSTEM != intrpt_ok_state))
+
uint4 have_crit(uint4 crit_state);
#endif /* HAVE_CRIT_H_INCLUDED */
diff --git a/sr_port/indirection.c b/sr_port/indirection.c
index 1282906..be0b419 100644
--- a/sr_port/indirection.c
+++ b/sr_port/indirection.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -23,9 +23,11 @@
GBLREF boolean_t run_time;
GBLREF char *lexical_ptr;
GBLREF spdesc stringpool;
+GBLREF unsigned char *source_buffer;
GBLREF short int source_column;
error_def(ERR_BOOLSIDEFFECT);
+error_def(ERR_EXPR);
error_def(ERR_LPARENMISSING);
error_def(ERR_MAXNRSUBSCRIPTS);
error_def(ERR_RPARENMISSING);
@@ -33,7 +35,7 @@ error_def(ERR_SIDEEFFECTEVAL);
int indirection(oprtype *a)
{
- char c, source_line_buff[MAX_SRCLINE + SIZEOF(ARROW)];
+ char c;
oprtype *sb1, *sb2, subs[MAX_INDSUBSCRIPTS], x;
triple *next, *ref;
int parens, oldlen, len;
@@ -49,6 +51,7 @@ int indirection(oprtype *a)
if (!expratom(a))
{
DECREMENT_EXPR_DEPTH;
+ stx_error(ERR_EXPR);
return FALSE;
}
coerce(a, OCT_MVAL);
@@ -67,22 +70,14 @@ int indirection(oprtype *a)
stx_error(ERR_LPARENMISSING);
return FALSE;
}
- for (parens = 1; (0 != parens) && (TK_EOL != TREF(window_token)); )
- {
- advancewindow();
- if (TK_LPAREN == TREF(window_token))
- parens++;
- else if (TK_RPAREN == TREF(window_token))
- parens--;
- }
- if (0 != parens)
+ advancewindow();
+ if (!parse_until_rparen_or_space() || (TK_RPAREN != TREF(window_token)))
{
stx_error(ERR_RPARENMISSING);
return FALSE;
}
- for (end = lexical_ptr - 1; *end != ')'; )
- end--;
- len = INTCAST(end - start) + 1;
+ end = (char *)source_buffer + (INTPTR_T)source_column - 1; /* lexical_ptr before last advancewindow */
+ len = INTCAST(end - start);
oldlen = (TREF(indirection_mval)).str.len;
ENSURE_STP_FREE_SPACE(oldlen + len);
/* Ok to copy from beginning each iteration because we generally expect no more than two iterations,
diff --git a/sr_port/insert_region.c b/sr_port/insert_region.c
index 2c77917..bb47273 100644
--- a/sr_port/insert_region.c
+++ b/sr_port/insert_region.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -54,7 +54,6 @@
#include "dbfilop.h"
#include "gtmmsg.h"
#include "is_file_identical.h"
-#include "tp_grab_crit.h"
#include "t_retry.h"
#include "wcs_mm_recover.h"
#include "gtmimagename.h"
@@ -205,7 +204,7 @@ tp_region *insert_region( gd_region *reg,
* tp_restart() (invoked through t_retry from gvcst_init) will open "reg" as well as get crit on it for us.
*/
DEBUG_ONLY(TREF(ok_to_call_wcs_recover) = TRUE;)
- if (FALSE == tp_grab_crit(reg)) /* Attempt lockdown now */
+ if (FALSE == grab_crit_immediate(reg)) /* Attempt lockdown now */
{
DEBUG_ONLY(TREF(ok_to_call_wcs_recover) = FALSE;)
t_retry(cdb_sc_needcrit); /* avoid deadlock -- restart transaction */
diff --git a/sr_port/io.h b/sr_port/io.h
index 8badfc4..5c83006 100644
--- a/sr_port/io.h
+++ b/sr_port/io.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -40,6 +40,7 @@ error_def(ERR_BADCHSET);
#define MAX_DEVCTL_LENGTH 256
#define IO_ESC 0x1b
#define MAX_DEV_TYPE_LEN 7
+#define DD_BUFLEN 80
#define CHAR_FILTER 128
#define ESC1 1
@@ -125,6 +126,8 @@ typedef struct io_desc_struct
unsigned short zeof;
unsigned short za;
unsigned char zb[ESC_LEN];
+ char key[DD_BUFLEN];
+ char device[DD_BUFLEN];
}dollar;
unsigned char esc_state;
void *dev_sp;
@@ -263,6 +266,7 @@ ioxx_open(ff);
#ifdef UNIX
ioxx_open(pi);
xxdlr(iopi); /* we need iopi_iocontrol(), iopi_dlr_device() and iopi_dlr_key() */
+xxdlr(iott); /* we need iott_iocontrol(), iott_dlr_device() and iott_dlr_key() */
#endif
ioxx_wttab(us);
/* iott_ prototypes */
@@ -297,7 +301,6 @@ boolean_t iosocket_wait(io_desc *iod, int4 timepar);
void iosocket_poolinit(void);
/* iotcp_ prototypes */
-char *iotcp_name2ip(char *name);
int iotcp_fillroutine(void);
int iotcp_getlsock(io_log_name *dev);
void iotcp_rmlsock(io_desc *iod);
@@ -406,7 +409,7 @@ LITREF unsigned char ebcdic_spaces_block[];
if (0 <= chset_idx) \
(CHSET) = (gtm_chset_t)chset_idx; \
else \
- rts_error(VARLSTCNT(4) ERR_BADCHSET, 2, (CHSET_MSTR)->len, (CHSET_MSTR)->addr); \
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_BADCHSET, 2, (CHSET_MSTR)->len, (CHSET_MSTR)->addr); \
}
#endif /* IO_H */
diff --git a/sr_port/io_dev_dispatch.h b/sr_port/io_dev_dispatch.h
index 0892642..3911f1b 100644
--- a/sr_port/io_dev_dispatch.h
+++ b/sr_port/io_dev_dispatch.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -17,7 +17,11 @@
UNIX_ONLY(GBLDEF) VMS_ONLY(LITDEF) dev_dispatch_struct io_dev_dispatch[] =
{
+# ifdef UNIX
+ iotype(iott, iott, iott),
+# else
iotype(iott, iott, nil),
+# endif
iotype(iomt, iomt, nil),
# ifdef UNIX
iotype(iorm, iorm, iopi),
diff --git a/sr_port/iop.h b/sr_port/iop.h
index 5b6ee90..d7ed558 100644
--- a/sr_port/iop.h
+++ b/sr_port/iop.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -210,4 +210,8 @@ IOP_DESC(192, iop_parse, 0, IOP_OPEN_OK, 0),
IOP_DESC(193, iop_destroy, 0, IOP_CLOSE_OK, 0),
IOP_DESC(194, iop_nodestroy, 0, IOP_CLOSE_OK, 0),
IOP_DESC(195, iop_rundown, 0, IOP_CLOSE_OK, 0),
-IOP_DESC(196, n_iops, 0, 0, 0)
+IOP_DESC(196, iop_follow, 0, IOP_OPEN_OK|IOP_USE_OK, 0),
+IOP_DESC(197, iop_nofollow, 0, IOP_OPEN_OK|IOP_USE_OK, 0),
+IOP_DESC(198, iop_empterm, 0, IOP_OPEN_OK|IOP_USE_OK, 0),
+IOP_DESC(199, iop_noempterm, 0, IOP_OPEN_OK|IOP_USE_OK, 0),
+IOP_DESC(200, n_iops, 0, 0, 0)
diff --git a/sr_port/iosocket_bind.c b/sr_port/iosocket_bind.c
index 7daf73e..f3912d8 100644
--- a/sr_port/iosocket_bind.c
+++ b/sr_port/iosocket_bind.c
@@ -1,13 +1,13 @@
/****************************************************************
- * *
- * Copyright 2001, 2009 Fidelity Information Services, Inc *
- * *
- * This source code contains the intellectual property *
- * of its copyright holder(s), and is made available *
- * under a license. If you do not know the terms of *
- * the license, please stop and do not read further. *
- * *
- ****************************************************************/
+* *
+* Copyright 2001, 2013 Fidelity Information Services, Inc *
+* *
+* This source code contains the intellectual property *
+* of its copyright holder(s), and is made available *
+* under a license. If you do not know the terms of *
+* the license, please stop and do not read further. *
+* *
+****************************************************************/
/* iosocket_bind.c */
#include "mdef.h"
@@ -15,7 +15,8 @@
#include "gtm_time.h"
#include "gtm_socket.h"
#include "gtm_inet.h"
-#include <netinet/tcp.h>
+#include "gtm_netdb.h"
+#include "gtm_ipv6.h"
#include "gtm_stdio.h"
#include "gtm_string.h"
#include "gt_timer.h"
@@ -24,59 +25,64 @@
#include "iotcpdef.h"
#include "iosocketdef.h"
#include "iotcproutine.h"
+#include "gtm_stdlib.h"
#define BOUND "BOUND"
+#define IPV6_UNCERTAIN 2
GBLREF tcp_library_struct tcp_routines;
+error_def(ERR_GETNAMEINFO);
+error_def(ERR_GETSOCKNAMERR);
+error_def(ERR_GETSOCKOPTERR);
+error_def(ERR_SETSOCKOPTERR);
+error_def(ERR_SOCKBIND);
+error_def(ERR_SOCKINIT);
+error_def(ERR_TEXT);
+
boolean_t iosocket_bind(socket_struct *socketptr, int4 timepar, boolean_t update_bufsiz)
{
- int temp_1 = 1;
- char *errptr;
- int4 errlen, msec_timeout, real_errno;
- short len;
- in_port_t actual_port;
- boolean_t no_time_left = FALSE;
- d_socket_struct *dsocketptr;
- ABS_TIME cur_time, end_time;
+ int temp_1 = 1;
+ char *errptr;
+ int4 errlen, msec_timeout, real_errno;
+ short len;
+ in_port_t actual_port;
+ boolean_t no_time_left = FALSE;
+ d_socket_struct *dsocketptr;
+ struct addrinfo *ai_ptr;
+ char port_buffer[NI_MAXSERV];
+ int errcode;
+ ABS_TIME cur_time, end_time;
GTM_SOCKLEN_TYPE addrlen;
GTM_SOCKLEN_TYPE sockbuflen;
- error_def(ERR_SOCKINIT);
- error_def(ERR_GETSOCKOPTERR);
- error_def(ERR_SETSOCKOPTERR);
- error_def(ERR_GETSOCKNAMERR);
-
dsocketptr = socketptr->dev;
+ ai_ptr = (struct addrinfo*)(&socketptr->local.ai);
assert(NULL != dsocketptr);
- dsocketptr->dollar_key[0] = '\0';
- if (timepar != NO_M_TIMEOUT)
- {
- msec_timeout = timeout2msec(timepar);
- sys_get_curr_time(&cur_time);
- add_int_to_abs_time(&cur_time, msec_timeout, &end_time);
- }
+ dsocketptr->iod->dollar.key[0] = '\0';
+ if (FD_INVALID != socketptr->temp_sd)
+ {
+ socketptr->sd = socketptr->temp_sd;
+ socketptr->temp_sd = FD_INVALID;
+ }
+ if (timepar != NO_M_TIMEOUT)
+ {
+ msec_timeout = timeout2msec(timepar);
+ sys_get_curr_time(&cur_time);
+ add_int_to_abs_time(&cur_time, msec_timeout, &end_time);
+ }
do
- {
- if (1 != temp_1)
- tcp_routines.aa_close(socketptr->sd);
- if (-1 == (socketptr->sd = tcp_routines.aa_socket(AF_INET, SOCK_STREAM, 0)))
- {
- real_errno = errno;
- errptr = (char *)STRERROR(real_errno);
- errlen = STRLEN(errptr);
- rts_error(VARLSTCNT(5) ERR_SOCKINIT, 3, real_errno, errlen, errptr);
- return FALSE;
- }
+ {
temp_1 = 1;
if (-1 == tcp_routines.aa_setsockopt(socketptr->sd,
SOL_SOCKET, SO_REUSEADDR, &temp_1, SIZEOF(temp_1)))
{
real_errno = errno;
errptr = (char *)STRERROR(real_errno);
- errlen = STRLEN(errptr);
- rts_error(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5,
+ errlen = STRLEN(errptr);
+ SOCKET_FREE(socketptr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5,
RTS_ERROR_LITERAL("SO_REUSEADDR"), real_errno, errlen, errptr);
return FALSE;
}
@@ -87,8 +93,9 @@ boolean_t iosocket_bind(socket_struct *socketptr, int4 timepar, boolean_t update
{
real_errno = errno;
errptr = (char *)STRERROR(real_errno);
- errlen = STRLEN(errptr);
- rts_error(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5,
+ errlen = STRLEN(errptr);
+ SOCKET_FREE(socketptr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5,
RTS_ERROR_LITERAL("TCP_NODELAY"), real_errno, errlen, errptr);
return FALSE;
}
@@ -100,9 +107,10 @@ boolean_t iosocket_bind(socket_struct *socketptr, int4 timepar, boolean_t update
{
real_errno = errno;
errptr = (char *)STRERROR(real_errno);
- errlen = STRLEN(errptr);
- rts_error(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5,
- RTS_ERROR_LITERAL("SO_RCVBUF"), real_errno, errlen, errptr);
+ errlen = STRLEN(errptr);
+ SOCKET_FREE(socketptr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5,
+ RTS_ERROR_LITERAL("SO_RCVBUF"), real_errno, errlen, errptr);
return FALSE;
}
} else
@@ -113,20 +121,20 @@ boolean_t iosocket_bind(socket_struct *socketptr, int4 timepar, boolean_t update
{
real_errno = errno;
errptr = (char *)STRERROR(real_errno);
- errlen = STRLEN(errptr);
- rts_error(VARLSTCNT(7) ERR_GETSOCKOPTERR, 5,
+ errlen = STRLEN(errptr);
+ SOCKET_FREE(socketptr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_GETSOCKOPTERR, 5,
RTS_ERROR_LITERAL("SO_RCVBUF"), real_errno, errlen, errptr);
return FALSE;
}
}
- temp_1 = tcp_routines.aa_bind(socketptr->sd,
- (struct sockaddr *)&socketptr->local.sin, SIZEOF(struct sockaddr));
+ temp_1 = tcp_routines.aa_bind(socketptr->sd, SOCKET_LOCAL_ADDR(socketptr), ai_ptr->ai_addrlen);
if (temp_1 < 0)
{
real_errno = errno;
- no_time_left = TRUE;
- switch (real_errno)
- {
+ no_time_left = TRUE;
+ switch (real_errno)
+ {
case EADDRINUSE:
if (NO_M_TIMEOUT != timepar)
{
@@ -139,37 +147,56 @@ boolean_t iosocket_bind(socket_struct *socketptr, int4 timepar, boolean_t update
case EINTR:
break;
default:
- errptr = (char *)STRERROR(real_errno);
- errlen = STRLEN(errptr);
- rts_error(VARLSTCNT(5) ERR_SOCKINIT, 3, real_errno, errlen, errptr);
+ SOCKET_FREE(socketptr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_SOCKBIND, 0, real_errno, 0);
break;
- }
- if (no_time_left)
- return FALSE;
- hiber_start(100);
- }
+ }
+ if (no_time_left)
+ return FALSE;
+ hiber_start(100);
+ tcp_routines.aa_close(socketptr->sd);
+ if (-1 == (socketptr->sd = tcp_routines.aa_socket(ai_ptr->ai_family,ai_ptr->ai_socktype,
+ ai_ptr->ai_protocol)))
+ {
+ real_errno = errno;
+ errptr = (char *)STRERROR(real_errno);
+ errlen = STRLEN(errptr);
+ SOCKET_FREE(socketptr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, real_errno, errlen, errptr);
+ return FALSE;
+ }
+ }
} while (temp_1 < 0);
- addrlen = SIZEOF(socketptr->local.sin);
- if (-1 == tcp_routines.aa_getsockname(socketptr->sd, (struct sockaddr *)&socketptr->local.sin, &addrlen))
+ /* obtain actual port from the bound address if port 0 was specified */
+ addrlen = SOCKET_ADDRLEN(socketptr, ai_ptr, local);
+ if (-1 == tcp_routines.aa_getsockname(socketptr->sd, SOCKET_LOCAL_ADDR(socketptr), &addrlen))
{
real_errno = errno;
errptr = (char *)STRERROR(real_errno);
errlen = STRLEN(errptr);
- rts_error(VARLSTCNT(5) ERR_GETSOCKNAMERR, 3, real_errno, errlen, errptr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_GETSOCKNAMERR, 3, real_errno, errlen, errptr);
return FALSE;
}
- actual_port = GTM_NTOHS(socketptr->local.sin.sin_port);
- if (0 == socketptr->local.port)
- socketptr->local.port = actual_port;
- assert(socketptr->local.port == actual_port);
+ assert(ai_ptr->ai_addrlen == addrlen);
+ GETNAMEINFO(SOCKET_LOCAL_ADDR(socketptr), addrlen, NULL, 0, port_buffer, NI_MAXSERV, NI_NUMERICSERV, errcode);
+ if (0 != errcode)
+ {
+ SOCKET_FREE(socketptr);
+ RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode);
+ return FALSE;
+ }
+ actual_port = ATOI(port_buffer);
+ if (0 == socketptr->local.port)
+ socketptr->local.port = actual_port;
+ assert(socketptr->local.port == actual_port);
socketptr->state = socket_bound;
len = SIZEOF(BOUND) - 1;
- memcpy(&dsocketptr->dollar_key[0], BOUND, len);
- dsocketptr->dollar_key[len++] = '|';
- memcpy(&dsocketptr->dollar_key[len], socketptr->handle, socketptr->handle_len);
+ memcpy(&dsocketptr->iod->dollar.key[0], BOUND, len);
+ dsocketptr->iod->dollar.key[len++] = '|';
+ memcpy(&dsocketptr->iod->dollar.key[len], socketptr->handle, socketptr->handle_len);
len += socketptr->handle_len;
- dsocketptr->dollar_key[len++] = '|';
- SPRINTF(&dsocketptr->dollar_key[len], "%d", socketptr->local.port);
+ dsocketptr->iod->dollar.key[len++] = '|';
+ SPRINTF(&dsocketptr->iod->dollar.key[len], "%d", socketptr->local.port);
return TRUE;
}
diff --git a/sr_port/iosocket_close.c b/sr_port/iosocket_close.c
index 33fffe4..a1b6f87 100644
--- a/sr_port/iosocket_close.c
+++ b/sr_port/iosocket_close.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -107,7 +107,7 @@ void iosocket_close(io_desc *iod, mval *pp)
{
if (0 > (index = iosocket_handle(sock_handle, &handle_len, FALSE, dsocketptr)))
{
- rts_error(VARLSTCNT(4) ERR_SOCKNOTFND, 2, handle_len, sock_handle);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_SOCKNOTFND, 2, handle_len, sock_handle);
return;
}
start = end = index;
@@ -121,11 +121,7 @@ void iosocket_close(io_desc *iod, mval *pp)
{
socketptr = dsocketptr->socket[ii];
tcp_routines.aa_close(socketptr->sd);
- iosocket_delimiter((unsigned char *)NULL, 0, socketptr, TRUE); /* free the delimiter space */
- free(socketptr->buffer);
- if (NULL != socketptr->zff.addr)
- free(socketptr->zff.addr);
- free(socketptr);
+ SOCKET_FREE(socketptr);
if (dsocketptr->current_socket >= ii)
dsocketptr->current_socket--;
for (jj = ii + 1; jj <= dsocketptr->n_socket - 1; jj++)
diff --git a/sr_port/iosocket_connect.c b/sr_port/iosocket_connect.c
index be089eb..70626f9 100644
--- a/sr_port/iosocket_connect.c
+++ b/sr_port/iosocket_connect.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -15,7 +15,6 @@
#include "gtm_time.h"
#include "gtm_socket.h"
#include "gtm_inet.h"
-#include <netinet/tcp.h>
#include "gtm_stdio.h"
#include "gtm_string.h"
#include "stringpool.h"
@@ -29,6 +28,8 @@
#include "stack_frame.h"
#include "mv_stent.h"
#include "outofband.h"
+#include "gtm_netdb.h"
+#include "gtm_ipv6.h"
#define ESTABLISHED "ESTABLISHED"
@@ -42,16 +43,17 @@ GBLREF int socketus_interruptus;
GBLREF d_socket_struct *newdsocket; /* in case jobinterrupt */
GBLREF int4 gtm_max_sockets;
-error_def(ERR_SOCKINIT);
-error_def(ERR_OPENCONN);
-error_def(ERR_TEXT);
+error_def(ERR_GETNAMEINFO);
error_def(ERR_GETSOCKOPTERR);
+error_def(ERR_OPENCONN);
error_def(ERR_SETSOCKOPTERR);
-error_def(ERR_ZINTRECURSEIO);
+error_def(ERR_SOCKINIT);
error_def(ERR_STACKCRIT);
error_def(ERR_STACKOFLOW);
+error_def(ERR_TEXT);
+error_def(ERR_ZINTRECURSEIO);
-boolean_t iosocket_connect(socket_struct *socketptr, int4 timepar, boolean_t update_bufsiz)
+boolean_t iosocket_connect(socket_struct *sockptr, int4 timepar, boolean_t update_bufsiz)
{
int temp_1;
char *errptr;
@@ -67,19 +69,21 @@ boolean_t iosocket_connect(socket_struct *socketptr, int4 timepar, boolean_t upd
ABS_TIME cur_time, end_time;
struct timeval *sel_time;
mv_stent *mv_zintdev;
+ struct addrinfo *remote_ai_ptr, *raw_ai_ptr;
+ int errcode, real_errno;
+ char ipaddr[SA_MAXLEN + 1];
GTM_SOCKLEN_TYPE sockbuflen;
DBGSOCK((stdout, "socconn: ************* Entering socconn - timepar: %d\n",timepar));
/* check for validity */
- dsocketptr = socketptr->dev;
+ dsocketptr = sockptr->dev;
assert(NULL != dsocketptr);
sockintr = &dsocketptr->sock_save_state;
iod = dsocketptr->iod;
real_dsocketptr = (d_socket_struct *)iod->dev_sp; /* not newdsocket which is not saved on error */
real_sockintr = &real_dsocketptr->sock_save_state;
- dsocketptr->dollar_key[0] = '\0';
- real_dsocketptr->dollar_key[0] = '\0';
+ iod->dollar.key[0] = '\0';
need_socket = need_connect = TRUE;
need_select = FALSE;
@@ -89,7 +93,7 @@ boolean_t iosocket_connect(socket_struct *socketptr, int4 timepar, boolean_t upd
if (sockwhich_invalid == sockintr->who_saved)
GTMASSERT; /* Interrupt should never have an invalid save state */
if (dollar_zininterrupt)
- rts_error(VARLSTCNT(1) ERR_ZINTRECURSEIO);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZINTRECURSEIO);
if (sockwhich_connect != sockintr->who_saved)
GTMASSERT; /* ZINTRECURSEIO should have caught */
DBGSOCK((stdout, "socconn: *#*#*#*#*#*#*# Restarted interrupted connect\n"));
@@ -99,7 +103,7 @@ boolean_t iosocket_connect(socket_struct *socketptr, int4 timepar, boolean_t upd
if (sockintr->end_time_valid)
/* Restore end_time for timeout */
end_time = sockintr->end_time;
- if (socket_connect_inprogress == socketptr->state && FD_INVALID != socketptr->sd)
+ if ((socket_connect_inprogress == sockptr->state) && (FD_INVALID != sockptr->sd))
{
need_select = TRUE;
need_socket = need_connect = FALSE; /* sd still good */
@@ -127,77 +131,127 @@ boolean_t iosocket_connect(socket_struct *socketptr, int4 timepar, boolean_t upd
real_sockintr->end_time_valid = sockintr->end_time_valid = FALSE;
last_errno = 0;
+ remote_ai_ptr = (struct addrinfo*)(&(sockptr->remote.ai));
do
{
- if (need_socket && FD_INVALID != socketptr->sd)
+ /* If the connect was failed, we may have already changed the remote.
+ * So, the remote ai_addr should be restored.
+ */
+ assertpro(NULL != sockptr->remote.ai_head);
+ memcpy(remote_ai_ptr, sockptr->remote.ai_head, SIZEOF(struct addrinfo));
+ if (need_socket && (FD_INVALID != sockptr->sd))
{
- tcp_routines.aa_close(socketptr->sd);
- socketptr->sd = FD_INVALID;
+ tcp_routines.aa_close(sockptr->sd);
+ sockptr->sd = FD_INVALID;
}
assert(FD_INVALID == -1);
if (need_socket)
{
- if (-1 == (socketptr->sd = tcp_routines.aa_socket(AF_INET, SOCK_STREAM, 0)))
- {
- errptr = (char *)STRERROR(errno);
+ real_errno = -2;
+ for (raw_ai_ptr = remote_ai_ptr; NULL != raw_ai_ptr; raw_ai_ptr = raw_ai_ptr->ai_next)
+ {
+ if (-1 == (sockptr->sd = tcp_routines.aa_socket(raw_ai_ptr->ai_family, raw_ai_ptr->ai_socktype,
+ raw_ai_ptr->ai_protocol)))
+ real_errno = errno;
+ else
+ {
+ real_errno = 0;
+ break;
+ }
+ }
+ if (0 != real_errno)
+ {
+ if (NULL != sockptr->remote.ai_head)
+ {
+ freeaddrinfo(sockptr->remote.ai_head);
+ sockptr->remote.ai_head = NULL;
+ }
+ assertpro(-2 != real_errno);
+ errptr = (char *)STRERROR(real_errno);
errlen = STRLEN(errptr);
- rts_error(VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr);
- return FALSE;
- }
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr);
+ return FALSE;
+ }
+ assertpro(NULL != raw_ai_ptr);/* either there is an IPv6 or an IPv4 address */
+ memcpy(remote_ai_ptr, raw_ai_ptr, SIZEOF(struct addrinfo));
+ SOCKET_AI_TO_REMOTE_ADDR(sockptr, raw_ai_ptr);
+ remote_ai_ptr->ai_addr = SOCKET_REMOTE_ADDR(sockptr);
+ remote_ai_ptr->ai_addrlen = raw_ai_ptr->ai_addrlen;
+ remote_ai_ptr->ai_next = NULL;
need_socket = FALSE;
temp_1 = 1;
- if (-1 == tcp_routines.aa_setsockopt(socketptr->sd, SOL_SOCKET, SO_REUSEADDR, &temp_1, SIZEOF(temp_1)))
+ if (-1 == tcp_routines.aa_setsockopt(sockptr->sd, SOL_SOCKET, SO_REUSEADDR, &temp_1, SIZEOF(temp_1)))
{
save_errno = errno;
errptr = (char *)STRERROR(save_errno);
errlen = STRLEN(errptr);
- tcp_routines.aa_close(socketptr->sd); /* Don't leave a dangling socket around */
- socketptr->sd = FD_INVALID;
- rts_error(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5,
+ tcp_routines.aa_close(sockptr->sd); /* Don't leave a dangling socket around */
+ sockptr->sd = FD_INVALID;
+ if (NULL != sockptr->remote.ai_head)
+ {
+ freeaddrinfo(sockptr->remote.ai_head);
+ sockptr->remote.ai_head = NULL;
+ }
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5,
RTS_ERROR_LITERAL("SO_REUSEADDR"), save_errno, errlen, errptr);
return FALSE;
}
#ifdef TCP_NODELAY
- temp_1 = socketptr->nodelay ? 1 : 0;
- if (-1 == tcp_routines.aa_setsockopt(socketptr->sd,
+ temp_1 = sockptr->nodelay ? 1 : 0;
+ if (-1 == tcp_routines.aa_setsockopt(sockptr->sd,
IPPROTO_TCP, TCP_NODELAY, &temp_1, SIZEOF(temp_1)))
{
save_errno = errno;
errptr = (char *)STRERROR(save_errno);
errlen = STRLEN(errptr);
- tcp_routines.aa_close(socketptr->sd); /* Don't leave a dangling socket around */
- socketptr->sd = FD_INVALID;
- rts_error(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5,
+ tcp_routines.aa_close(sockptr->sd); /* Don't leave a dangling socket around */
+ sockptr->sd = FD_INVALID;
+ if (NULL != sockptr->remote.ai_head)
+ {
+ freeaddrinfo(sockptr->remote.ai_head);
+ sockptr->remote.ai_head = NULL;
+ }
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5,
RTS_ERROR_LITERAL("TCP_NODELAY"), save_errno, errlen, errptr);
return FALSE;
}
#endif
if (update_bufsiz)
{
- if (-1 == tcp_routines.aa_setsockopt(socketptr->sd,
- SOL_SOCKET, SO_RCVBUF, &socketptr->bufsiz, SIZEOF(socketptr->bufsiz)))
+ if (-1 == tcp_routines.aa_setsockopt(sockptr->sd,
+ SOL_SOCKET, SO_RCVBUF, &sockptr->bufsiz, SIZEOF(sockptr->bufsiz)))
{
save_errno = errno;
errptr = (char *)STRERROR(save_errno);
errlen = STRLEN(errptr);
- tcp_routines.aa_close(socketptr->sd); /* Don't leave a dangling socket around */
- socketptr->sd = FD_INVALID;
- rts_error(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5,
+ tcp_routines.aa_close(sockptr->sd); /* Don't leave a dangling socket around */
+ sockptr->sd = FD_INVALID;
+ if (NULL != sockptr->remote.ai_head)
+ {
+ freeaddrinfo(sockptr->remote.ai_head);
+ sockptr->remote.ai_head = NULL;
+ }
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5,
RTS_ERROR_LITERAL("SO_RCVBUF"), save_errno, errlen, errptr);
return FALSE;
}
} else
{
- sockbuflen = SIZEOF(socketptr->bufsiz);
- if (-1 == tcp_routines.aa_getsockopt(socketptr->sd,
- SOL_SOCKET, SO_RCVBUF, &socketptr->bufsiz, &sockbuflen))
+ sockbuflen = SIZEOF(sockptr->bufsiz);
+ if (-1 == tcp_routines.aa_getsockopt(sockptr->sd,
+ SOL_SOCKET, SO_RCVBUF, &sockptr->bufsiz, &sockbuflen))
{
save_errno = errno;
errptr = (char *)STRERROR(save_errno);
errlen = STRLEN(errptr);
- tcp_routines.aa_close(socketptr->sd); /* Don't leave a dangling socket around */
- socketptr->sd = FD_INVALID;
- rts_error(VARLSTCNT(7) ERR_GETSOCKOPTERR, 5,
+ tcp_routines.aa_close(sockptr->sd); /* Don't leave a dangling socket around */
+ sockptr->sd = FD_INVALID;
+ if (NULL != sockptr->remote.ai_head)
+ {
+ freeaddrinfo(sockptr->remote.ai_head);
+ sockptr->remote.ai_head = NULL;
+ }
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_GETSOCKOPTERR, 5,
RTS_ERROR_LITERAL("SO_RCVBUF"), save_errno, errlen, errptr);
return FALSE;
}
@@ -207,8 +261,8 @@ boolean_t iosocket_connect(socket_struct *socketptr, int4 timepar, boolean_t upd
if (need_connect)
{
/* Use plain connect to allow jobinterrupt */
- assert(FD_INVALID != socketptr->sd);
- res = connect(socketptr->sd, (struct sockaddr *)&socketptr->remote.sin, SIZEOF(socketptr->remote.sin));
+ assert(FD_INVALID != sockptr->sd);
+ res = connect(sockptr->sd, SOCKET_REMOTE_ADDR(sockptr), remote_ai_ptr->ai_addrlen);
if (res < 0)
{
save_errno = errno;
@@ -284,12 +338,12 @@ boolean_t iosocket_connect(socket_struct *socketptr, int4 timepar, boolean_t upd
}
}
FD_ZERO(&writefds);
- FD_SET(socketptr->sd, &writefds);
- res = select(socketptr->sd + 1, NULL, &writefds, NULL, sel_time);
+ FD_SET(sockptr->sd, &writefds);
+ res = select(sockptr->sd + 1, NULL, &writefds, NULL, sel_time);
if (0 < res)
{ /* check for socket error */
sockbuflen = SIZEOF(sockerror);
- res = getsockopt(socketptr->sd, SOL_SOCKET, SO_ERROR,
+ res = getsockopt(sockptr->sd, SOL_SOCKET, SO_ERROR,
&sockerror, &sockbuflen);
if (0 == res && 0 == sockerror)
{ /* got it */
@@ -337,38 +391,55 @@ boolean_t iosocket_connect(socket_struct *socketptr, int4 timepar, boolean_t upd
}
if (save_errno)
{
- if (FD_INVALID != socketptr->sd)
+ if (FD_INVALID != sockptr->sd)
+ {
+ tcp_routines.aa_close(sockptr->sd); /* Don't leave a dangling socket around */
+ sockptr->sd = FD_INVALID;
+ }
+ if (NULL != sockptr->remote.ai_head)
{
- tcp_routines.aa_close(socketptr->sd); /* Don't leave a dangling socket around */
- socketptr->sd = FD_INVALID;
+ freeaddrinfo(sockptr->remote.ai_head);
+ sockptr->remote.ai_head = NULL;
}
errptr = (char *)STRERROR(save_errno);
errlen = STRLEN(errptr);
if (dev_open == iod->state)
{
iod->dollar.za = 9;
- memcpy(real_dsocketptr->dollar_device, ONE_COMMA, SIZEOF(ONE_COMMA));
- memcpy(&real_dsocketptr->dollar_device[SIZEOF(ONE_COMMA) - 1],
+ memcpy(iod->dollar.device, ONE_COMMA, SIZEOF(ONE_COMMA));
+ memcpy(&iod->dollar.device[SIZEOF(ONE_COMMA) - 1],
errptr, errlen + 1); /* + 1 for null */
}
- if (socketptr->ioerror)
- rts_error(VARLSTCNT(6) ERR_OPENCONN, 0, ERR_TEXT, 2, errlen, errptr);
+ if (sockptr->ioerror)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_OPENCONN, 0, ERR_TEXT, 2, errlen, errptr);
errno = save_errno;
return FALSE;
}
if (no_time_left)
+ {
+ if (NULL != sockptr->remote.ai_head)
+ {
+ freeaddrinfo(sockptr->remote.ai_head);
+ sockptr->remote.ai_head = NULL;
+ }
return FALSE; /* caller will close socket */
+ }
if (res < 0 && outofband) /* if connected delay outofband */
{
DBGSOCK((stdout, "socconn: outofband interrupt received (%d) -- "
"queueing mv_stent for wait intr\n", outofband));
if (need_connect)
{ /* no connect in progress */
- tcp_routines.aa_close(socketptr->sd); /* Don't leave a dangling socket around */
- socketptr->sd = FD_INVALID;
- socketptr->state = socket_created;
+ tcp_routines.aa_close(sockptr->sd); /* Don't leave a dangling socket around */
+ sockptr->sd = FD_INVALID;
+ sockptr->state = socket_created;
} else
- socketptr->state = socket_connect_inprogress;
+ sockptr->state = socket_connect_inprogress;
+ if (NULL != sockptr->remote.ai_head)
+ {
+ freeaddrinfo(sockptr->remote.ai_head);
+ sockptr->remote.ai_head = NULL;
+ }
real_sockintr->who_saved = sockintr->who_saved = sockwhich_connect;
if (NO_M_TIMEOUT != timepar)
{
@@ -384,7 +455,7 @@ boolean_t iosocket_connect(socket_struct *socketptr, int4 timepar, boolean_t upd
PUSH_MV_STENT(MVST_ZINTDEV);
mv_chain->mv_st_cont.mvs_zintdev.buffer_valid = FALSE;
mv_chain->mv_st_cont.mvs_zintdev.io_ptr = NULL;
- mv_chain->mv_st_cont.mvs_zintdev.socketptr = socketptr; /* for sd and to free structure */
+ mv_chain->mv_st_cont.mvs_zintdev.socketptr = sockptr; /* for sd and to free structure */
mv_chain->mv_st_cont.mvs_zintdev.curr_sp_buffer.len = d_socket_struct_len;
mv_chain->mv_st_cont.mvs_zintdev.curr_sp_buffer.addr = (char *)stringpool.free;
memcpy (stringpool.free, (unsigned char *)newdsocket, d_socket_struct_len);
@@ -401,20 +472,36 @@ boolean_t iosocket_connect(socket_struct *socketptr, int4 timepar, boolean_t upd
hiber_start(100);
} while (res < 0);
- /* handle the local information later.
- SPRINTF(socketptr->local.saddr_ip, "%s", tcp_routines.aa_inet_ntoa(socketptr->remote.sin.sin_addr));
- socketptr->local.port = GTM_NTOHS(socketptr->remote.sin.sin_port);
- */
- socketptr->state = socket_connected;
- socketptr->first_read = socketptr->first_write = TRUE;
+ sockptr->state = socket_connected;
+ sockptr->first_read = sockptr->first_write = TRUE;
/* update dollar_key */
len = SIZEOF(ESTABLISHED) - 1;
- memcpy(&dsocketptr->dollar_key[0], ESTABLISHED, len);
- dsocketptr->dollar_key[len++] = '|';
- memcpy(&dsocketptr->dollar_key[len], socketptr->handle, socketptr->handle_len);
- len += socketptr->handle_len;
- dsocketptr->dollar_key[len++] = '|';
- strcpy(&dsocketptr->dollar_key[len], socketptr->remote.saddr_ip); /* Also copies in trailing null */
+ memcpy(&iod->dollar.key[0], ESTABLISHED, len);
+ iod->dollar.key[len++] = '|';
+ memcpy(&iod->dollar.key[len], sockptr->handle, sockptr->handle_len);
+ len += sockptr->handle_len;
+ iod->dollar.key[len++] = '|';
+ /* translate internal address to numeric ip address */
+ assert(FALSE == need_socket);
+ if (NULL != sockptr->remote.ai_head)
+ {
+ freeaddrinfo(sockptr->remote.ai_head);
+ sockptr->remote.ai_head = NULL;
+ }
+ GETNAMEINFO(SOCKET_REMOTE_ADDR(sockptr), remote_ai_ptr->ai_addrlen, ipaddr, SA_MAXLEN, NULL, 0, NI_NUMERICHOST, errcode);
+ if (0 != errcode)
+ {
+ if (FD_INVALID != sockptr->sd)
+ {
+ tcp_routines.aa_close(sockptr->sd); /* Don't leave a dangling socket around */
+ sockptr->sd = FD_INVALID;
+ }
+ RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode);
+ return FALSE;
+ }
+ STRNDUP(ipaddr, SA_MAXLEN, sockptr->remote.saddr_ip);
+ strncpy(&iod->dollar.key[len], sockptr->remote.saddr_ip, DD_BUFLEN - 1 - len);
+ iod->dollar.key[DD_BUFLEN-1] = '\0'; /* In case we fill the buffer */
return TRUE;
}
diff --git a/sr_port/iosocket_create.c b/sr_port/iosocket_create.c
index 879d490..474d494 100644
--- a/sr_port/iosocket_create.c
+++ b/sr_port/iosocket_create.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -12,8 +12,8 @@
/* iosocket_create.c */
/* this module takes care of
* 1. allocate the space
- * 2. for passive: local.sin.sin_addr.s_addr & local.sin.sin_port
- * for active : remote.sin.sin_addr.s_addr & remote.sin.sin_port
+ * 2. for passive: local.sa & local.ai
+ * for active : remote.sa & remote.ai
* for $principal: via getsockname and getsockpeer
* 3. socketptr->protocol
* 4. socketptr->sd (initialized to -1) unless already open via inetd
@@ -29,6 +29,8 @@
#include "gtm_netdb.h"
#include "gtm_socket.h"
#include "gtm_inet.h"
+#include "gtm_ipv6.h"
+#include "gtm_stdlib.h"
#include "io.h"
#include "iotcproutine.h"
@@ -37,128 +39,214 @@
#include "iosocketdef.h"
#include "min_max.h"
#include "gtm_caseconv.h"
-
-#ifdef __osf__
-/* Tru64 does not have the prototype for "hstrerror" even though the function is available in the library.
- * Until we revamp the TCP communications setup stuff to use the new(er) POSIX definitions, we cannot move
- * away from "hstrerror". Declare prototype for this function in Tru64 manually until then.
- */
-const char *hstrerror(int err);
-#endif
+#include "util.h"
GBLREF tcp_library_struct tcp_routines;
error_def(ERR_GETSOCKNAMERR);
+error_def(ERR_GETADDRINFO);
+error_def(ERR_GETNAMEINFO);
error_def(ERR_INVPORTSPEC);
error_def(ERR_INVADDRSPEC);
error_def(ERR_PROTNOTSUP);
error_def(ERR_TEXT);
+error_def(ERR_SOCKINIT);
+
+/* PORT_PROTO_FORMAT defines the format for <port>:<protocol> */
+#define PORT_PROTO_FORMAT "%hu:%3[^:]"
+#define SEPARATOR ':'
socket_struct *iosocket_create(char *sockaddr, uint4 bfsize, int file_des)
{
- socket_struct *socketptr;
- bool passive = FALSE;
- unsigned short port;
- int ii, save_errno, tmplen;
- GTM_SOCKLEN_TYPE socknamelen;
- char temp_addr[SA_MAXLITLEN], addr[SA_MAXLEN], tcp[4], *adptr;
- const char *errptr;
+ socket_struct *socketptr;
+ socket_struct *prev_socketptr;
+ socket_struct *socklist_head;
+ bool passive = FALSE;
+ unsigned short port;
+ int ii, save_errno, tmplen, errlen;
+ char temp_addr[SA_MAXLITLEN], tcp[4], *adptr;
+ const char *errptr;
+ struct addrinfo *ai_ptr;
+ struct addrinfo hints, *addr_info_ptr = NULL;
+ int af;
+ int sd;
+ int errcode;
+ char port_buffer[NI_MAXSERV];
+ int port_buffer_len;
+ int colon_cnt;
+ char *last_2colon;
+ int addrlen;
+ GTM_SOCKLEN_TYPE tmp_addrlen;
- socketptr = (socket_struct *)malloc(SIZEOF(socket_struct));
- memset(socketptr, 0, SIZEOF(socket_struct));
if (0 > file_des)
{ /* no socket descriptor yet */
- if (SSCANF(sockaddr, "%[^:]:%hu:%3[^:]", temp_addr, &port, tcp) < 3)
+ memset(&hints, 0, SIZEOF(hints));
+
+ colon_cnt = 0;
+ for (ii = strlen(sockaddr) - 1; 0 <= ii; ii--)
+ {
+ if (SEPARATOR == sockaddr[ii])
+ {
+ colon_cnt++;
+ if (2 == colon_cnt)
+ {
+ last_2colon = &sockaddr[ii];
+ break;
+ }
+ }
+ }
+ if (0 == colon_cnt)
{
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVPORTSPEC);
+ return NULL;
+ }
+ if (1 == colon_cnt)
+ { /* for listening socket or broadcasting socket */
+ if (SSCANF(sockaddr, PORT_PROTO_FORMAT, &port, tcp) < 2)
+ {
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVPORTSPEC);
+ return NULL;
+ }
passive = TRUE;
- socketptr->local.sin.sin_addr.s_addr = INADDR_ANY;
- if(SSCANF(sockaddr, "%hu:%3[^:]", &port, tcp) < 2)
+ /* We always first try using IPv6 address, if supported */
+ af = ((GTM_IPV6_SUPPORTED && !ipv4_only) ? AF_INET6 : AF_INET);
+ if (-1 == (sd = tcp_routines.aa_socket(af, SOCK_STREAM, IPPROTO_TCP)))
{
- free(socketptr);
- rts_error(VARLSTCNT(1) ERR_INVPORTSPEC);
+ /* Try creating IPv4 socket */
+ af = AF_INET;
+ if (-1 == (sd = tcp_routines.aa_socket(af, SOCK_STREAM, IPPROTO_TCP)))
+ {
+ save_errno = errno;
+ errptr = (char *)STRERROR(save_errno);
+ errlen = STRLEN(errptr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, save_errno, errlen, errptr);
+ return NULL;
+ }
+ }
+ SERVER_HINTS(hints, af);
+ port_buffer_len = 0;
+ I2A(port_buffer, port_buffer_len, port);
+ port_buffer[port_buffer_len]='\0';
+ if (0 != (errcode = getaddrinfo(NULL, port_buffer, &hints, &addr_info_ptr)))
+ {
+ tcp_routines.aa_close(sd);
+ RTS_ERROR_ADDRINFO(NULL, ERR_GETADDRINFO, errcode);
return NULL;
}
- socketptr->local.sin.sin_port = GTM_HTONS(port);
- socketptr->local.sin.sin_family = AF_INET;
+ SOCKET_ALLOC(socketptr);
socketptr->local.port = port;
+ socketptr->temp_sd = sd;
+ socketptr->sd = FD_INVALID;
+ ai_ptr = &(socketptr->local.ai);
+ memcpy(ai_ptr, addr_info_ptr, SIZEOF(struct addrinfo));
+ SOCKET_AI_TO_LOCAL_ADDR(socketptr, addr_info_ptr);
+ ai_ptr->ai_addr = SOCKET_LOCAL_ADDR(socketptr);
+ ai_ptr->ai_addrlen = addr_info_ptr->ai_addrlen;
+ ai_ptr->ai_next = NULL;
+ freeaddrinfo(addr_info_ptr);
} else
- {
- for (ii = 0; ISDIGIT_ASCII(temp_addr[ii]) || '.' == temp_addr[ii]; ii++) /* NOTE: only ASCII digits */
- ; /* allowed for dotted notation address */
- if (temp_addr[ii] != '\0')
+ { /* connection socket */
+ assert(2 == colon_cnt);
+ if (SSCANF(last_2colon + 1, PORT_PROTO_FORMAT, &port, tcp) < 2)
{
- SPRINTF(socketptr->remote.saddr_lit, "%s", temp_addr);
- adptr = iotcp_name2ip(temp_addr);
- if (NULL == adptr)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVPORTSPEC);
+ return NULL;
+ }
+ /* for connection socket */
+ SPRINTF(port_buffer, "%hu", port);
+ addrlen = last_2colon - sockaddr;
+ if ('[' == sockaddr[0])
+ {
+ if (NULL == memchr(sockaddr, ']', addrlen))
{
- free(socketptr);
-#if !defined(__hpux) && !defined(__MVS__)
- errptr = HSTRERROR(h_errno);
- rts_error(VARLSTCNT(6) ERR_INVADDRSPEC, 0, ERR_TEXT, 2, LEN_AND_STR(errptr));
-#else
- /* Grumble grumble HPUX and z/OS don't have hstrerror() */
- rts_error(VARLSTCNT(1) ERR_INVADDRSPEC);
-#endif
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVPORTSPEC);
return NULL;
}
-
- SPRINTF(addr, "%s", adptr);
+ addrlen -= 2;
+ memcpy(temp_addr, &sockaddr[1], addrlen);
} else
- SPRINTF(addr, "%s", temp_addr);
- if ((unsigned int)-1 == (socketptr->remote.sin.sin_addr.s_addr = tcp_routines.aa_inet_addr(addr)))
- { /* Errno not set by inet_addr() */
- free(socketptr);
- rts_error(VARLSTCNT(1) ERR_INVADDRSPEC);
+ memcpy(temp_addr, sockaddr, addrlen);
+ temp_addr[addrlen] = 0;
+ CLIENT_HINTS(hints);
+ if (0 != (errcode = getaddrinfo(temp_addr, port_buffer, &hints, &addr_info_ptr)))
+ {
+ RTS_ERROR_ADDRINFO(NULL, ERR_GETADDRINFO, errcode);
return NULL;
}
- socketptr->remote.sin.sin_port = GTM_HTONS(port);
- socketptr->remote.sin.sin_family = AF_INET;
+ /* we will test all address families in iosocket_connect() */
+ SOCKET_ALLOC(socketptr);
+ socketptr->remote.ai_head = addr_info_ptr;
socketptr->remote.port = port;
- SPRINTF(socketptr->remote.saddr_ip, "%s", addr);
+ socketptr->sd = socketptr->temp_sd = FD_INVALID; /* don't mess with 0 */
}
lower_to_upper((uchar_ptr_t)tcp, (uchar_ptr_t)tcp, SIZEOF("TCP") - 1);
if (0 == MEMCMP_LIT(tcp, "TCP"))
+ {
socketptr->protocol = socket_tcpip;
- else
+ } else
{
- free(socketptr);
- rts_error(VARLSTCNT(4) ERR_PROTNOTSUP, 2, MIN(strlen(tcp), SIZEOF("TCP") - 1), tcp);
+ SOCKET_FREE(socketptr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_PROTNOTSUP, 2, MIN(strlen(tcp), SIZEOF("TCP") - 1), tcp);
return NULL;
}
- socketptr->sd = FD_INVALID; /* don't mess with 0 */
- socketptr->state = socket_created; /* Is this really useful? */
+ socketptr->state = socket_created;
+ SOCKET_BUFFER_INIT(socketptr, bfsize);
+ socketptr->passive = passive;
+ socketptr->moreread_timeout = DEFAULT_MOREREAD_TIMEOUT;
+
+ return socketptr;
} else
{ /* socket already setup by inetd */
+ SOCKET_ALLOC(socketptr);
socketptr->sd = file_des;
- socknamelen = SIZEOF(socketptr->local.sin);
- if (-1 == tcp_routines.aa_getsockname(socketptr->sd, (struct sockaddr *)&socketptr->local.sin, &socknamelen))
+ socketptr->temp_sd = FD_INVALID;
+ ai_ptr = &(socketptr->local.ai);
+ tmp_addrlen = SIZEOF(struct sockaddr_storage);
+ if (-1 == tcp_routines.aa_getsockname(socketptr->sd, SOCKET_LOCAL_ADDR(socketptr), &tmp_addrlen))
{
save_errno = errno;
errptr = (char *)STRERROR(save_errno);
tmplen = STRLEN(errptr);
- free(socketptr);
- rts_error(VARLSTCNT(5) ERR_GETSOCKNAMERR, 3, save_errno, tmplen, errptr);
+ SOCKET_FREE(socketptr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_GETSOCKNAMERR, 3, save_errno, tmplen, errptr);
+ return NULL;
+ }
+ ai_ptr->ai_addrlen = tmp_addrlen;
+ /* extract port information */
+ GETNAMEINFO(SOCKET_LOCAL_ADDR(socketptr), tmp_addrlen, NULL, 0, port_buffer, NI_MAXSERV, NI_NUMERICSERV, errcode);
+ if (0 != errcode)
+ {
+ SOCKET_FREE(socketptr);
+ RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode);
return NULL;
}
- socketptr->local.port = GTM_NTOHS(socketptr->local.sin.sin_port);
- socknamelen = SIZEOF(socketptr->remote.sin);
- if (-1 == getpeername(socketptr->sd, (struct sockaddr *)&socketptr->remote.sin, (GTM_SOCKLEN_TYPE *)&socknamelen))
+ socketptr->local.port = ATOI(port_buffer);
+ tmp_addrlen = SIZEOF(struct sockaddr_storage);
+ if (-1 == getpeername(socketptr->sd, SOCKET_REMOTE_ADDR(socketptr), &tmp_addrlen))
{
save_errno = errno;
errptr = (char *)STRERROR(save_errno);
tmplen = STRLEN(errptr);
- free(socketptr);
- rts_error(VARLSTCNT(5) ERR_GETSOCKNAMERR, 3, save_errno, tmplen, errptr); /* need new error */
+ SOCKET_FREE(socketptr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_GETSOCKNAMERR, 3, save_errno, tmplen, errptr);
+ return NULL;
+ }
+ socketptr->remote.ai.ai_addrlen = tmp_addrlen;
+ assert(0 != SOCKET_REMOTE_ADDR(socketptr)->sa_family);
+ GETNAMEINFO(SOCKET_REMOTE_ADDR(socketptr), socketptr->remote.ai.ai_addrlen, NULL, 0, port_buffer, NI_MAXSERV,
+ NI_NUMERICSERV, errcode);
+ if (0 != errcode)
+ {
+ SOCKET_FREE(socketptr);
+ RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode);
return NULL;
}
- socketptr->remote.port = GTM_NTOHS(socketptr->remote.sin.sin_port);
+ socketptr->remote.port = ATOI(port_buffer);
socketptr->state = socket_connected;
socketptr->protocol = socket_tcpip;
+ SOCKET_BUFFER_INIT(socketptr, bfsize);
+ socketptr->passive = passive;
+ socketptr->moreread_timeout = DEFAULT_MOREREAD_TIMEOUT;
+ return socketptr;
}
- socketptr->buffer = (char *)malloc(bfsize);
- socketptr->buffer_size = bfsize;
- socketptr->buffered_length = socketptr->buffered_offset = 0;
- socketptr->passive = passive;
- socketptr->moreread_timeout = DEFAULT_MOREREAD_TIMEOUT;
- return socketptr;
}
diff --git a/sr_port/iosocket_flush.c b/sr_port/iosocket_flush.c
index edb78fd..d5f627c 100644
--- a/sr_port/iosocket_flush.c
+++ b/sr_port/iosocket_flush.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -16,7 +16,6 @@
#include "gtm_socket.h"
#include "gtm_inet.h"
#include <errno.h>
-#include <netinet/tcp.h>
#include "gtm_stdio.h"
#include "gtm_string.h"
@@ -28,6 +27,10 @@
GBLREF tcp_library_struct tcp_routines;
+error_def(ERR_SOCKWRITE);
+error_def(ERR_TEXT);
+error_def(ERR_CURRSOCKOFR);
+
void iosocket_flush(io_desc *iod)
{
#ifdef C9A06001531
@@ -39,10 +42,6 @@ void iosocket_flush(io_desc *iod)
char *errptr;
int4 errlen;
- error_def(ERR_SOCKWRITE);
- error_def(ERR_TEXT);
- error_def(ERR_CURRSOCKOFR);
-
assert(gtmsocket == iod->type);
dsocketptr = (d_socket_struct *)iod->dev_sp;
@@ -50,20 +49,20 @@ void iosocket_flush(io_desc *iod)
if (dsocketptr->current_socket >= dsocketptr->n_socket)
{
- rts_error(VARLSTCNT(4) ERR_CURRSOCKOFR, 2, dsocketptr->current_socket, dsocketptr->n_socket);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_CURRSOCKOFR, 2, dsocketptr->current_socket, dsocketptr->n_socket);
return;
}
- memcpy(dsocketptr->dollar_device, "0", SIZEOF("0"));
- if( -1 == tcp_routines.aa_setsockopt(socketptr->sd, SOL_SOCKET, TCP_NODELAY, &on, SIZEOF(on)) ||
+ memcpy(iod->dollar.device, "0", SIZEOF("0"));
+ if ( -1 == tcp_routines.aa_setsockopt(socketptr->sd, SOL_SOCKET, TCP_NODELAY, &on, SIZEOF(on)) ||
(-1 == tcp_routines.aa_setsockopt(socketptr->sd, SOL_SOCKET, TCP_NODELAY, &off, SIZEOF(off))))
{
errptr = (char *)STRERROR(errno);
errlen = strlen(errptr);
iod->dollar.za = 9;
- MEMCPY_LIT(dsocketptr->dollar_device, "1,");
- memcpy(&dsocketptr->dollar_device[SIZEOF("1,") - 1], errptr, errlen + 1); /* we want the null */
+ MEMCPY_LIT(iod->dollar.device, "1,");
+ memcpy(&iod->dollar.device[SIZEOF("1,") - 1], errptr, errlen + 1); /* we want the null */
if (socketptr->ioerror)
- rts_error(VARLSTCNT(6) ERR_SOCKWRITE, 0, ERR_TEXT, 2, errlen, errptr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_SOCKWRITE, 0, ERR_TEXT, 2, errlen, errptr);
return;
}
diff --git a/sr_port/iosocket_iocontrol.c b/sr_port/iosocket_iocontrol.c
index 81d97b8..f1fb417 100644
--- a/sr_port/iosocket_iocontrol.c
+++ b/sr_port/iosocket_iocontrol.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -66,7 +66,7 @@ void iosocket_iocontrol(mstr *d)
timeout = NO_M_TIMEOUT;
iosocket_wait(io_curr_device.out, timeout); /* depth really means timeout here. */
} else
- rts_error(VARLSTCNT(1) ERR_INVCTLMNE);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVCTLMNE);
return;
}
@@ -75,15 +75,12 @@ void iosocket_dlr_device(mstr *d)
{
io_desc *iod;
int len;
- d_socket_struct *dsocketptr;
iod = io_curr_device.out;
- dsocketptr = (d_socket_struct *)iod->dev_sp;
-
- len = STRLEN(dsocketptr->dollar_device);
+ len = STRLEN(iod->dollar.device);
/* verify internal buffer has enough space for $DEVICE string value */
assert((int)d->len > len);
- memcpy(d->addr, dsocketptr->dollar_device, len);
+ memcpy(d->addr, iod->dollar.device, len);
d->len = len;
return;
}
@@ -92,16 +89,13 @@ void iosocket_dlr_key(mstr *d)
{
io_desc *iod;
int len;
- d_socket_struct *dsocketptr;
iod = io_curr_device.out;
- dsocketptr = (d_socket_struct *)iod->dev_sp;
-
- len = STRLEN(dsocketptr->dollar_key);
+ len = STRLEN(iod->dollar.key);
/* verify internal buffer has enough space for $DEVICE string value */
assert((int)d->len > len);
if (len > 0)
- memcpy(d->addr, dsocketptr->dollar_key, len);
+ memcpy(d->addr, iod->dollar.key, len);
d->len = len;
return;
}
diff --git a/sr_port/iosocket_listen.c b/sr_port/iosocket_listen.c
index 247b867..e944291 100644
--- a/sr_port/iosocket_listen.c
+++ b/sr_port/iosocket_listen.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -29,67 +29,58 @@
#include "gt_timer.h"
#include "iosocketdef.h"
+GBLREF tcp_library_struct tcp_routines;
+
+error_def(ERR_CURRSOCKOFR);
+error_def(ERR_LISTENPASSBND);
+error_def(ERR_LQLENGTHNA);
+error_def(ERR_SOCKLISTEN);
+error_def(ERR_TEXT);
+
#define LISTENING "LISTENING"
#define MAX_LISTEN_QUEUE_LENGTH 5
-GBLREF tcp_library_struct tcp_routines;
-
boolean_t iosocket_listen(io_desc *iod, unsigned short len)
{
+ char *errptr;
+ int4 errlen;
d_socket_struct *dsocketptr;
socket_struct *socketptr;
- char *errptr;
- int4 errlen;
-
- error_def(ERR_SOCKLISTEN);
- error_def(ERR_TEXT);
- error_def(ERR_LQLENGTHNA);
- error_def(ERR_SOCKACTNA);
- error_def(ERR_CURRSOCKOFR);
- error_def(ERR_LISTENPASSBND);
if (MAX_LISTEN_QUEUE_LENGTH < len)
{
- rts_error(VARLSTCNT(3) ERR_LQLENGTHNA, 1, len);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_LQLENGTHNA, 1, len);
return FALSE;
}
-
- assert(iod->type == gtmsocket);
- dsocketptr = (d_socket_struct *)iod->dev_sp;
+ assert(gtmsocket == iod->type);
+ dsocketptr = (d_socket_struct *)iod->dev_sp;
socketptr = dsocketptr->socket[dsocketptr->current_socket];
-
if (dsocketptr->current_socket >= dsocketptr->n_socket)
{
- rts_error(VARLSTCNT(4) ERR_CURRSOCKOFR, 2, dsocketptr->current_socket, dsocketptr->n_socket);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_CURRSOCKOFR, 2, dsocketptr->current_socket, dsocketptr->n_socket);
return FALSE;
}
-
- if ((socketptr->state != socket_bound) || (socketptr->passive != TRUE))
+ if ((socketptr->state != socket_bound) || (TRUE != socketptr->passive))
{
- rts_error(VARLSTCNT(1) ERR_LISTENPASSBND);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_LISTENPASSBND);
+ return FALSE;
+ }
+ dsocketptr->iod->dollar.key[0] = '\0';
+ /* establish a queue of length len for incoming connections */
+ if (-1 == tcp_routines.aa_listen(socketptr->sd, len))
+ {
+ errptr = (char *)STRERROR(errno);
+ errlen = STRLEN(errptr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_SOCKLISTEN, 0, ERR_TEXT, 2, errlen, errptr);
return FALSE;
}
-
- dsocketptr->dollar_key[0] = '\0';
-
- /* establish a queue of length len for incoming connections */
- if (-1 == tcp_routines.aa_listen(socketptr->sd, len))
- {
- errptr = (char *)STRERROR(errno);
- errlen = STRLEN(errptr);
- rts_error(VARLSTCNT(6) ERR_SOCKLISTEN, 0, ERR_TEXT, 2, errlen, errptr);
- return FALSE;
- }
-
socketptr->state = socket_listening;
-
len = SIZEOF(LISTENING) - 1;
- memcpy(&dsocketptr->dollar_key[0], LISTENING, len);
- dsocketptr->dollar_key[len++] = '|';
- memcpy(&dsocketptr->dollar_key[len], socketptr->handle, socketptr->handle_len);
+ memcpy(&dsocketptr->iod->dollar.key[0], LISTENING, len);
+ dsocketptr->iod->dollar.key[len++] = '|';
+ memcpy(&dsocketptr->iod->dollar.key[len], socketptr->handle, socketptr->handle_len);
len += socketptr->handle_len;
- dsocketptr->dollar_key[len++] = '|';
- SPRINTF(&dsocketptr->dollar_key[len], "%d", socketptr->local.port);
-
+ dsocketptr->iod->dollar.key[len++] = '|';
+ SPRINTF(&dsocketptr->iod->dollar.key[len], "%d", socketptr->local.port);
return TRUE;
}
diff --git a/sr_port/iosocket_open.c b/sr_port/iosocket_open.c
index d5bb778..7673162 100644
--- a/sr_port/iosocket_open.c
+++ b/sr_port/iosocket_open.c
@@ -1,12 +1,13 @@
/****************************************************************
* *
+ * Copyright 2012, 2013 Fidelity Information Services, Inc *
+ * *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
* under a license. If you do not know the terms of *
* the license, please stop and do not read further. *
* *
****************************************************************/
-
#include "mdef.h"
#include <errno.h>
@@ -29,6 +30,7 @@
#include "stringpool.h"
#include "gtm_conv.h"
#include "gtm_utf8.h"
+#include "gtm_netdb.h"
GBLREF tcp_library_struct tcp_routines;
GBLREF d_socket_struct *socket_pool, *newdsocket;
@@ -41,25 +43,21 @@ LITREF mstr chset_names[];
error_def(ERR_ABNCOMPTINC);
error_def(ERR_ADDRTOOLONG);
-error_def(ERR_SOCKETEXIST);
error_def(ERR_DELIMSIZNA);
error_def(ERR_DELIMWIDTH);
error_def(ERR_DEVPARINAP);
error_def(ERR_DEVPARMNEG);
+error_def(ERR_GETNAMEINFO);
error_def(ERR_ILLESOCKBFSIZE);
error_def(ERR_MRTMAXEXCEEDED);
+error_def(ERR_SOCKETEXIST);
error_def(ERR_SOCKMAX);
+error_def(ERR_TEXT);
error_def(ERR_ZFF2MANY);
error_def(ERR_ZINTRECURSEIO);
#define ESTABLISHED "ESTABLISHED"
-#define FREE_SOCKPTR(sockptr) \
-{ \
- if (NULL != sockptr->buffer) free(sockptr->buffer); \
- free(sockptr); \
-}
-
short iosocket_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 timepar)
{
char addr[SA_MAXLITLEN], *errptr, sockaddr[SA_MAXLITLEN],
@@ -71,7 +69,6 @@ short iosocket_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4
int d_socket_struct_len;
ABS_TIME cur_time, end_time;
io_desc *ioptr;
- struct sockaddr_in peer; /* socket address + port */
fd_set tcp_fd;
uint4 bfsize = DEFAULT_SOCKET_BUFFER_SIZE, ibfsize;
d_socket_struct *dsocketptr;
@@ -95,6 +92,9 @@ short iosocket_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4
char ioerror, ip[3], tcp[4],
sock_handle[MAX_HANDLE_LEN], delimiter[MAX_DELIM_LEN + 1];
int socketptr_delim_len;
+ char ipaddr[SA_MAXLEN];
+ int errcode;
+ struct addrinfo *ai_ptr, *remote_ai_ptr;
ioptr = dev->iod;
assert((params) *(pp->str.addr + p_offset) < (unsigned char)n_iops);
@@ -142,7 +142,7 @@ short iosocket_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4
{
dsocketptr->mupintr = FALSE;
sockintr->who_saved = sockwhich_invalid;
- rts_error(VARLSTCNT(1) ERR_ZINTRECURSEIO);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZINTRECURSEIO);
}
if (sockwhich_connect != sockintr->who_saved)
GTMASSERT; /* ZINTRECURSEIO should have caught */
@@ -165,7 +165,7 @@ short iosocket_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4
if (NULL == newdsocket)
newdsocket = (d_socket_struct *)malloc(d_socket_struct_len);
memcpy(newdsocket, dsocketptr, d_socket_struct_len);
- memcpy(newdsocket->dollar_device, "0", SIZEOF("0"));
+ memcpy(ioptr->dollar.device, "0", SIZEOF("0"));
zff_len = -1; /* indicates neither ZFF nor ZNOFF specified */
delimiter_len = -1; /* indicates neither DELIM nor NODELIM specified */
ichset_specified = ochset_specified = FALSE;
@@ -178,7 +178,7 @@ short iosocket_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4
if (((MAX_DELIM_LEN + 1) * MAX_N_DELIMITER) >= delimiter_len)
memcpy(delimiter_buffer, (pp->str.addr + p_offset + 1), delimiter_len);
else
- rts_error(VARLSTCNT(1) ERR_DELIMSIZNA);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DELIMSIZNA);
break;
case iop_ipchset:
UNICODE_ONLY(
@@ -263,13 +263,13 @@ short iosocket_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4
case iop_zbfsize:
GET_ULONG(bfsize, pp->str.addr + p_offset);
if ((0 == bfsize) || (MAX_SOCKET_BUFFER_SIZE < bfsize))
- rts_error(VARLSTCNT(3) ERR_ILLESOCKBFSIZE, 1, bfsize);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_ILLESOCKBFSIZE, 1, bfsize);
break;
case iop_zibfsize:
ibfsize_specified = TRUE;
GET_ULONG(ibfsize, pp->str.addr + p_offset);
if ((0 == ibfsize) || (MAX_INTERNAL_SOCBUF_SIZE < ibfsize))
- rts_error(VARLSTCNT(3) ERR_ILLESOCKBFSIZE, 1, bfsize);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_ILLESOCKBFSIZE, 1, bfsize);
break;
case iop_zlisten:
listen_specified = TRUE;
@@ -279,8 +279,8 @@ short iosocket_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4
memset(sockaddr, 0, SIZEOF(sockaddr));
memcpy(sockaddr, pp->str.addr + p_offset + 1, len);
} else
- rts_error(VARLSTCNT(6) ERR_ADDRTOOLONG, 4, len, pp->str.addr + p_offset + 1,
- len, SA_MAXLITLEN);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_ADDRTOOLONG, 4, len,
+ pp->str.addr + p_offset + 1, len, SA_MAXLITLEN);
break;
case iop_connect:
connect_specified = TRUE;
@@ -290,8 +290,8 @@ short iosocket_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4
memset(sockaddr, 0, SIZEOF(sockaddr));
memcpy(sockaddr, pp->str.addr + p_offset + 1, len);
} else
- rts_error(VARLSTCNT(6) ERR_ADDRTOOLONG, 4, len, pp->str.addr + p_offset + 1,
- len, SA_MAXLITLEN);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_ADDRTOOLONG, 4,
+ len, pp->str.addr + p_offset + 1, len, SA_MAXLITLEN);
break;
case iop_ioerror:
ioerror_specified = TRUE;
@@ -310,13 +310,13 @@ short iosocket_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4
memcpy(sock_handle, pp->str.addr + p_offset + 1, handle_len);
break;
case iop_socket:
- rts_error(VARLSTCNT(1) ERR_DEVPARINAP);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DEVPARINAP);
break;
case iop_zff:
if (MAX_ZFF_LEN >= (zff_len = (int4)(unsigned char)*(pp->str.addr + p_offset)))
memcpy(zff_buffer, (char *)(pp->str.addr + p_offset + 1), zff_len);
else
- rts_error(VARLSTCNT(4) ERR_ZFF2MANY, 2, zff_len, MAX_ZFF_LEN);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZFF2MANY, 2, zff_len, MAX_ZFF_LEN);
break;
case iop_znoff:
zff_len = 0;
@@ -333,9 +333,10 @@ short iosocket_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4
if (-1 == moreread_timeout)
moreread_timeout = DEFAULT_MOREREAD_TIMEOUT;
else if (-1 > moreread_timeout)
- rts_error(VARLSTCNT(1) ERR_DEVPARMNEG);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DEVPARMNEG);
else if (MAX_MOREREAD_TIMEOUT < moreread_timeout)
- rts_error(VARLSTCNT(3) ERR_MRTMAXEXCEEDED, 1, MAX_MOREREAD_TIMEOUT);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_MRTMAXEXCEEDED, 1,
+ MAX_MOREREAD_TIMEOUT);
moreread_specified = TRUE;
break;
default:
@@ -354,13 +355,13 @@ short iosocket_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4
get_chset_desc(&chset_names[ioptr->ochset]);
if (listen_specified && connect_specified)
{
- rts_error(VARLSTCNT(8) ERR_ABNCOMPTINC, 6, LEN_AND_LIT("CONNECT"),
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ABNCOMPTINC, 6, LEN_AND_LIT("CONNECT"),
LEN_AND_LIT("ZLISTEN"), LEN_AND_LIT("OPEN"));
return FALSE;
}
if (delay_specified && nodelay_specified)
{
- rts_error(VARLSTCNT(8) ERR_ABNCOMPTINC, 6, LEN_AND_LIT("DELAY"),
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ABNCOMPTINC, 6, LEN_AND_LIT("DELAY"),
LEN_AND_LIT("NODELAY"), LEN_AND_LIT("OPEN"));
return FALSE;
}
@@ -384,9 +385,11 @@ short iosocket_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4
{
if (iosocket_handle(sock_handle, &handle_len, FALSE, newdsocket) >= 0)
{
- FREE_SOCKPTR(socketptr);
+ if (FD_INVALID != socketptr->temp_sd)
+ tcp_routines.aa_close(socketptr->temp_sd);
+ SOCKET_FREE(socketptr);
assert(ioptr->newly_created == FALSE);
- rts_error(VARLSTCNT(4) ERR_SOCKETEXIST, 2, handle_len, sock_handle);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_SOCKETEXIST, 2, handle_len, sock_handle);
return FALSE;
}
} else
@@ -399,18 +402,18 @@ short iosocket_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4
if (ioptr->wrap && 0 != socketptr->n_delimiter && ioptr->width < socketptr->delimiter[0].len)
{
socketptr_delim_len = socketptr->delimiter[0].len;
- iosocket_delimiter((unsigned char *)NULL, 0, socketptr, TRUE);
- FREE_SOCKPTR(socketptr);
- rts_error(VARLSTCNT(4) ERR_DELIMWIDTH, 2, ioptr->width, socketptr_delim_len);
+ SOCKET_FREE(socketptr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_DELIMWIDTH, 2, ioptr->width, socketptr_delim_len);
assert(FALSE);
}
/* connects newdsocket and socketptr (the new socket) */
if (gtm_max_sockets <= newdsocket->n_socket)
{
assert(ioptr->newly_created == FALSE);
- iosocket_delimiter((unsigned char *)NULL, 0, socketptr, TRUE);
- FREE_SOCKPTR(socketptr);
- rts_error(VARLSTCNT(3) ERR_SOCKMAX, 1, gtm_max_sockets);
+ if (FD_INVALID != socketptr->temp_sd)
+ tcp_routines.aa_close(socketptr->temp_sd);
+ SOCKET_FREE(socketptr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_SOCKMAX, 1, gtm_max_sockets);
return FALSE;
}
socketptr->dev = newdsocket;
@@ -436,24 +439,37 @@ short iosocket_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4
{
if (socketptr->sd > 0)
(void)tcp_routines.aa_close(socketptr->sd);
- iosocket_delimiter((unsigned char *)NULL, 0, socketptr, TRUE);
- if (NULL != socketptr->zff.addr)
- free(socketptr->zff.addr);
- FREE_SOCKPTR(socketptr);
+ SOCKET_FREE(socketptr);
return FALSE;
} else if (is_principal)
{ /* fill in what bind or connect would */
- strncpy(socketptr->local.saddr_ip, tcp_routines.aa_inet_ntoa(socketptr->local.sin.sin_addr),
- SIZEOF(socketptr->local.saddr_ip));
- strncpy(socketptr->remote.saddr_ip, tcp_routines.aa_inet_ntoa(socketptr->remote.sin.sin_addr),
- SIZEOF(socketptr->remote.saddr_ip));
+ ai_ptr = &(socketptr->local.ai);
+ remote_ai_ptr = &(socketptr->remote.ai);
+ /* translate internal address to numeric ip address */
+ GETNAMEINFO(SOCKET_LOCAL_ADDR(socketptr), ai_ptr->ai_addrlen, ipaddr, SIZEOF(ipaddr), NULL, 0, NI_NUMERICHOST,
+ errcode);
+ if (0 != errcode)
+ {
+ RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode);
+ return FALSE;
+ }
+ STRNDUP(ipaddr, SIZEOF(ipaddr), socketptr->local.saddr_ip);
+ GETNAMEINFO(SOCKET_REMOTE_ADDR(socketptr), remote_ai_ptr->ai_addrlen, ipaddr, SIZEOF(ipaddr), NULL, 0,
+ NI_NUMERICHOST, errcode);
+ if (0 != errcode)
+ {
+ RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode);
+ return FALSE;
+ }
+ STRNDUP(ipaddr, SIZEOF(ipaddr), socketptr->remote.saddr_ip);
len = SIZEOF(ESTABLISHED) - 1;
- memcpy(&newdsocket->dollar_key[0], ESTABLISHED, len);
- newdsocket->dollar_key[len++] = '|';
- memcpy(&newdsocket->dollar_key[len], socketptr->handle, socketptr->handle_len);
+ memcpy(&ioptr->dollar.key[0], ESTABLISHED, len);
+ ioptr->dollar.key[len++] = '|';
+ memcpy(&ioptr->dollar.key[len], socketptr->handle, socketptr->handle_len);
len += socketptr->handle_len;
- newdsocket->dollar_key[len++] = '|';
- strcpy(&newdsocket->dollar_key[len], socketptr->remote.saddr_ip); /* Copies in terminating NULL */
+ ioptr->dollar.key[len++] = '|';
+ strncpy(&ioptr->dollar.key[len], socketptr->remote.saddr_ip, DD_BUFLEN - 1 - len);
+ ioptr->dollar.key[DD_BUFLEN-1] = '\0'; /* In case we fill the buffer */
}
/* commit the changes to the list */
if (listen_specified || connect_specified || is_principal)
diff --git a/sr_port/iosocket_readfl.c b/sr_port/iosocket_readfl.c
index 537384d..814b7b2 100644
--- a/sr_port/iosocket_readfl.c
+++ b/sr_port/iosocket_readfl.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -110,13 +110,13 @@ void iosocket_readfl_badchar(mval *vmvalptr, int datalen, int delimlen, unsigned
{ /* Set $KEY and $ZB with the failing badchar */
memcpy(iod->dollar.zb, delimptr, MIN(delimlen, ESC_LEN - 1));
iod->dollar.zb[MIN(delimlen, ESC_LEN - 1)] = '\0';
- memcpy(dsocketptr->dollar_key, delimptr, MIN(delimlen, DD_BUFLEN - 1));
- dsocketptr->dollar_key[MIN(delimlen, DD_BUFLEN - 1)] = '\0';
+ memcpy(iod->dollar.key, delimptr, MIN(delimlen, DD_BUFLEN - 1));
+ iod->dollar.key[MIN(delimlen, DD_BUFLEN - 1)] = '\0';
}
}
len = SIZEOF(ONE_COMMA) - 1;
- memcpy(dsocketptr->dollar_device, ONE_COMMA, len);
- memcpy(&dsocketptr->dollar_device[len], BADCHAR_DEVICE_MSG, SIZEOF(BADCHAR_DEVICE_MSG));
+ memcpy(iod->dollar.device, ONE_COMMA, len);
+ memcpy(&iod->dollar.device[len], BADCHAR_DEVICE_MSG, SIZEOF(BADCHAR_DEVICE_MSG));
}
#endif
@@ -156,13 +156,13 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout)
if (0 >= dsocketptr->n_socket)
{
iod->dollar.za = 9;
- rts_error(VARLSTCNT(1) ERR_NOSOCKETINDEV);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOSOCKETINDEV);
return 0;
}
if (dsocketptr->n_socket <= dsocketptr->current_socket)
{
iod->dollar.za = 9;
- rts_error(VARLSTCNT(4) ERR_CURRSOCKOFR, 2, dsocketptr->current_socket, dsocketptr->n_socket);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_CURRSOCKOFR, 2, dsocketptr->current_socket, dsocketptr->n_socket);
return 0;
}
utf8_active = NON_UNICODE_ONLY(FALSE) UNICODE_ONLY(gtm_utf8_mode ? IS_UTF_CHSET(ichset) : FALSE);
@@ -192,7 +192,7 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout)
assertpro(sockwhich_invalid != sockintr->who_saved); /* Interrupt should never have an invalid save state */
/* Check we aren't recursing on this device */
if (dollar_zininterrupt)
- rts_error(VARLSTCNT(1) ERR_ZINTRECURSEIO);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZINTRECURSEIO);
assertpro(sockwhich_readfl == sockintr->who_saved); /* ZINTRECURSEIO should have caught */
DBGSOCK((stdout, "socrfl: *#*#*#*#*#*#*# Restarted interrupted read\n"));
dsocketptr->mupintr = FALSE;
@@ -335,8 +335,9 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout)
iod->dollar.za = 9;
save_errno = errno;
errptr = (char *)STRERROR(errno);
- rts_error(VARLSTCNT(7) ERR_GETSOCKOPTERR, 5, LEN_AND_LIT("F_GETFL FOR NON BLOCKING I/O"),
- save_errno, LEN_AND_STR(errptr));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_GETSOCKOPTERR, 5,
+ LEN_AND_LIT("F_GETFL FOR NON BLOCKING I/O"),
+ save_errno, LEN_AND_STR(errptr));
}
FCNTL3(socketptr->sd, F_SETFL, flags & (~(O_NDELAY | O_NONBLOCK)), fcntl_res);
if (fcntl_res < 0)
@@ -344,8 +345,9 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout)
iod->dollar.za = 9;
save_errno = errno;
errptr = (char *)STRERROR(errno);
- rts_error(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, LEN_AND_LIT("F_SETFL FOR NON BLOCKING I/O"),
- save_errno, LEN_AND_STR(errptr));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5,
+ LEN_AND_LIT("F_SETFL FOR NON BLOCKING I/O"),
+ save_errno, LEN_AND_STR(errptr));
}
# endif
sys_get_curr_time(&cur_time);
@@ -375,7 +377,7 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout)
}
}
sockintr->end_time_valid = FALSE;
- dsocketptr->dollar_key[0] = '\0';
+ iod->dollar.key[0] = '\0';
iod->dollar.zb[0] = '\0';
more_data = TRUE;
real_errno = 0;
@@ -536,7 +538,7 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout)
if (CHSET_UTF16LE == ichset)
{
iod->dollar.za = 9;
- rts_error(VARLSTCNT(6) ERR_BOMMISMATCH, 4,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_BOMMISMATCH, 4,
chset_names[CHSET_UTF16BE].len,
chset_names[CHSET_UTF16BE].addr,
chset_names[CHSET_UTF16LE].len,
@@ -552,7 +554,7 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout)
if (CHSET_UTF16BE == ichset)
{
iod->dollar.za = 9;
- rts_error(VARLSTCNT(6) ERR_BOMMISMATCH, 4,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_BOMMISMATCH, 4,
chset_names[CHSET_UTF16LE].len,
chset_names[CHSET_UTF16LE].addr,
chset_names[CHSET_UTF16BE].len,
@@ -618,9 +620,9 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout)
memcpy(iod->dollar.zb, socketptr->idelimiter[ii].addr,
MIN(socketptr->idelimiter[ii].len, ESC_LEN - 1));
iod->dollar.zb[MIN(socketptr->idelimiter[ii].len, ESC_LEN - 1)] = '\0';
- memcpy(dsocketptr->dollar_key, socketptr->idelimiter[ii].addr,
+ memcpy(iod->dollar.key, socketptr->idelimiter[ii].addr,
MIN(socketptr->idelimiter[ii].len, DD_BUFLEN - 1));
- dsocketptr->dollar_key[MIN(socketptr->idelimiter[ii].len, DD_BUFLEN - 1)] = '\0';
+ iod->dollar.key[MIN(socketptr->idelimiter[ii].len, DD_BUFLEN - 1)] = '\0';
break;
}
}
@@ -645,7 +647,7 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout)
if (bytes_read > MAX_STRLEN)
{
iod->dollar.za = 9;
- rts_error(VARLSTCNT(1) ERR_MAXSTRLEN);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MAXSTRLEN);
}
orig_bytes_read = bytes_read;
if (0 != bytes_read)
@@ -763,8 +765,9 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout)
iod->dollar.za = 9;
save_errno = errno;
errptr = (char *)STRERROR(errno);
- rts_error(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, LEN_AND_LIT("F_SETFL FOR RESTORING SOCKET OPTIONS"),
- save_errno, LEN_AND_STR(errptr));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5,
+ LEN_AND_LIT("F_SETFL FOR RESTORING SOCKET OPTIONS"),
+ save_errno, LEN_AND_STR(errptr));
}
# endif
if (out_of_time)
@@ -846,13 +849,13 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout)
} else
{
v->str.len = 0;
- v->str.addr = dsocketptr->dollar_key;
+ v->str.addr = iod->dollar.key;
}
if (status >= 0)
{ /* No real problems */
iod->dollar.zeof = FALSE;
iod->dollar.za = 0;
- memcpy(dsocketptr->dollar_device, "0", SIZEOF("0"));
+ memcpy(iod->dollar.device, "0", SIZEOF("0"));
} else
{ /* There's a significant problem */
DBGSOCK((stdout, "socrfl: Error handling triggered - status: %d\n", status));
@@ -860,10 +863,10 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout)
iod->dollar.x = 0;
iod->dollar.za = 9;
len = SIZEOF(ONE_COMMA) - 1;
- memcpy(dsocketptr->dollar_device, ONE_COMMA, len);
+ memcpy(iod->dollar.device, ONE_COMMA, len);
errptr = (char *)STRERROR(real_errno);
errlen = STRLEN(errptr);
- memcpy(&dsocketptr->dollar_device[len], errptr, errlen + 1); /* + 1 for null */
+ memcpy(&iod->dollar.device[len], errptr, errlen + 1); /* + 1 for null */
# ifdef UNIX
if (io_curr_device.in == io_std_device.in)
{
@@ -871,7 +874,7 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout)
prin_in_dev_failure = TRUE;
else
{
- send_msg(VARLSTCNT(1) ERR_NOPRINCIO);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOPRINCIO);
stop_image_no_core();
}
}
@@ -880,7 +883,7 @@ int iosocket_readfl(mval *v, int4 width, int4 timeout)
{
iod->dollar.zeof = TRUE;
if (socketptr->ioerror)
- rts_error(VARLSTCNT(6) ERR_IOEOF, 0, ERR_TEXT, 2, errlen, errptr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_IOEOF, 0, ERR_TEXT, 2, errlen, errptr);
} else
iod->dollar.zeof = TRUE;
}
diff --git a/sr_port/iosocket_use.c b/sr_port/iosocket_use.c
index 34dff3d..1dc798b 100644
--- a/sr_port/iosocket_use.c
+++ b/sr_port/iosocket_use.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -20,7 +20,6 @@
#include <errno.h>
#include "gtm_inet.h"
-#include <netinet/tcp.h>
#include "copy.h"
#include "io.h"
#include "io_params.h"
@@ -117,7 +116,7 @@ void iosocket_use(io_desc *iod, mval *pp)
if (dsocketptr->mupintr)
{ /* And if we are in $zinterrupt code this is not allowed */
if (dollar_zininterrupt)
- rts_error(VARLSTCNT(1) ERR_ZINTRECURSEIO);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZINTRECURSEIO);
/* We are not in $zinterrupt code and this device was not resumed properly
so clear its restartability.
*/
@@ -146,7 +145,7 @@ void iosocket_use(io_desc *iod, mval *pp)
tab = pp->str.addr + p_offset + 1;
if ((fil_type = namelook(filter_index, filter_names, tab, len)) < 0)
{
- rts_error(VARLSTCNT(1) ERR_TTINVFILTER);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_TTINVFILTER);
return;
}
switch (fil_type)
@@ -184,13 +183,13 @@ void iosocket_use(io_desc *iod, mval *pp)
n_specified++;
connect_specified = TRUE;
len = *(pp->str.addr + p_offset);
- if (len < SA_MAXLITLEN)
+ if (len < USR_SA_MAXLITLEN)
{
memcpy(sockaddr, (char *)(pp->str.addr + p_offset + 1), len);
sockaddr[len] = '\0';
} else
- rts_error(VARLSTCNT(6) ERR_ADDRTOOLONG,
- 4, len, pp->str.addr + p_offset + 1, len, SA_MAXLITLEN);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_ADDRTOOLONG,
+ 4, len, pp->str.addr + p_offset + 1, len, USR_SA_MAXLITLEN);
break;
case iop_delimiter:
n_specified++;
@@ -198,7 +197,7 @@ void iosocket_use(io_desc *iod, mval *pp)
if (((MAX_DELIM_LEN + 1) * MAX_N_DELIMITER) >= delimiter_len)
memcpy(delimiter_buffer, (pp->str.addr + p_offset + 1), delimiter_len);
else
- rts_error(VARLSTCNT(1) ERR_DELIMSIZNA);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DELIMSIZNA);
break;
case iop_nodelimiter:
delimiter_len = 0;
@@ -213,13 +212,13 @@ void iosocket_use(io_desc *iod, mval *pp)
bfsize_specified = TRUE;
GET_ULONG(bfsize, pp->str.addr + p_offset);
if ((0 == bfsize) || (MAX_SOCKET_BUFFER_SIZE < bfsize))
- rts_error(VARLSTCNT(3) ERR_ILLESOCKBFSIZE, 1, bfsize);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_ILLESOCKBFSIZE, 1, bfsize);
break;
case iop_zibfsize:
ibfsize_specified = TRUE;
GET_ULONG(ibfsize, pp->str.addr + p_offset);
if ((0 == ibfsize) || (MAX_INTERNAL_SOCBUF_SIZE < ibfsize))
- rts_error(VARLSTCNT(3) ERR_ILLESOCKBFSIZE, 1, ibfsize);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_ILLESOCKBFSIZE, 1, ibfsize);
break;
case iop_ioerror:
n_specified++;
@@ -230,13 +229,13 @@ void iosocket_use(io_desc *iod, mval *pp)
n_specified++;
listen_specified = TRUE;
len = *(pp->str.addr + p_offset);
- if (len < SA_MAXLITLEN)
+ if (len < USR_SA_MAXLITLEN)
{
memcpy(sockaddr, (char *)(pp->str.addr + p_offset + 1), len);
sockaddr[len] = '\0';
} else
- rts_error(VARLSTCNT(6) ERR_ADDRTOOLONG,
- 4, len, pp->str.addr + p_offset + 1, len, SA_MAXLITLEN);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_ADDRTOOLONG,
+ 4, len, pp->str.addr + p_offset + 1, len, USR_SA_MAXLITLEN);
break;
case iop_socket:
n_specified++;
@@ -266,7 +265,7 @@ void iosocket_use(io_desc *iod, mval *pp)
if (MAX_ZFF_LEN >= (zff_len = (int4)(unsigned char)*(pp->str.addr + p_offset)))
memcpy(zff_buffer, (char *)(pp->str.addr + p_offset + 1), zff_len);
else
- rts_error(VARLSTCNT(4) ERR_ZFF2MANY, 2, zff_len, MAX_ZFF_LEN);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZFF2MANY, 2, zff_len, MAX_ZFF_LEN);
break;
case iop_znoff:
zff_len = 0;
@@ -274,14 +273,14 @@ void iosocket_use(io_desc *iod, mval *pp)
case iop_length:
GET_LONG(length, pp->str.addr + p_offset);
if (length < 0)
- rts_error(VARLSTCNT(1) ERR_DEVPARMNEG);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DEVPARMNEG);
iod->length = length;
break;
case iop_width:
/* SOCKET WIDTH is handled the same way as TERMINAL WIDTH */
GET_LONG(width, pp->str.addr + p_offset);
if (width < 0)
- rts_error(VARLSTCNT(1) ERR_DEVPARMNEG);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DEVPARMNEG);
if (0 == width)
{
iod->width = TCPDEF_WIDTH;
@@ -304,9 +303,9 @@ void iosocket_use(io_desc *iod, mval *pp)
if (-1 == moreread_timeout)
moreread_timeout = DEFAULT_MOREREAD_TIMEOUT;
else if (-1 > moreread_timeout)
- rts_error(VARLSTCNT(1) ERR_DEVPARMNEG);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DEVPARMNEG);
else if (MAX_MOREREAD_TIMEOUT < moreread_timeout)
- rts_error(VARLSTCNT(3) ERR_MRTMAXEXCEEDED, 1, MAX_MOREREAD_TIMEOUT);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_MRTMAXEXCEEDED, 1, MAX_MOREREAD_TIMEOUT);
moreread_specified = TRUE;
break;
default:
@@ -322,17 +321,20 @@ void iosocket_use(io_desc *iod, mval *pp)
/* ------------------------------ compatibility verification -------------------------------- */
if ((socket_specified) && ((n_specified > 2) || ((2 == n_specified) && (0 >= delimiter_len))))
{
- rts_error(VARLSTCNT(8) ERR_ACOMPTBINC, 6, LEN_AND_LIT("SOCKET"), LEN_AND_LIT("DELIMITER"), LEN_AND_LIT("USE"));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ACOMPTBINC, 6, LEN_AND_LIT("SOCKET"), LEN_AND_LIT("DELIMITER"),
+ LEN_AND_LIT("USE"));
return;
}
if (connect_specified && listen_specified)
{
- rts_error(VARLSTCNT(8) ERR_ABNCOMPTINC, 6, LEN_AND_LIT("CONNECT"), LEN_AND_LIT("ZLISTEN"), LEN_AND_LIT("USE"));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ABNCOMPTINC, 6, LEN_AND_LIT("CONNECT"), LEN_AND_LIT("ZLISTEN"),
+ LEN_AND_LIT("USE"));
return;
}
if (delay_specified && nodelay_specified)
{
- rts_error(VARLSTCNT(8) ERR_ABNCOMPTINC, 6, LEN_AND_LIT("DELAY"), LEN_AND_LIT("NODELAY"), LEN_AND_LIT("OPEN"));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_ABNCOMPTINC, 6, LEN_AND_LIT("DELAY"), LEN_AND_LIT("NODELAY"),
+ LEN_AND_LIT("OPEN"));
return;
}
/* ------------------ make a local copy of device structure to play with -------------------- */
@@ -343,7 +345,7 @@ void iosocket_use(io_desc *iod, mval *pp)
{
if (1 < n_specified)
{
- rts_error(VARLSTCNT(6) ERR_ANCOMPTINC, 4, LEN_AND_LIT("DETACH"), LEN_AND_LIT("USE"));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_ANCOMPTINC, 4, LEN_AND_LIT("DETACH"), LEN_AND_LIT("USE"));
return;
}
if (NULL == socket_pool)
@@ -365,12 +367,12 @@ void iosocket_use(io_desc *iod, mval *pp)
*/
if (1 < n_specified)
{
- rts_error(VARLSTCNT(6) ERR_ANCOMPTINC, 4, LEN_AND_LIT("ATTACH"), LEN_AND_LIT("USE"));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_ANCOMPTINC, 4, LEN_AND_LIT("ATTACH"), LEN_AND_LIT("USE"));
return;
}
if (NULL == socket_pool)
{
- rts_error(VARLSTCNT(4) ERR_SOCKNOTFND, 2, handlea_len, handlea);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_SOCKNOTFND, 2, handlea_len, handlea);
return;
}
iosocket_switch(handlea, handlea_len, socket_pool, newdsocket);
@@ -395,7 +397,7 @@ void iosocket_use(io_desc *iod, mval *pp)
/* use the socket flag to identify which socket to apply changes */
if (0 > (index = iosocket_handle(handles, &handles_len, FALSE, newdsocket)))
{
- rts_error(VARLSTCNT(4) ERR_SOCKNOTFND, 2, handles_len, handles);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_SOCKNOTFND, 2, handles_len, handles);
return;
}
newdsocket->current_socket = index;
@@ -406,10 +408,12 @@ void iosocket_use(io_desc *iod, mval *pp)
if (newdsocket->n_socket <= newdsocket->current_socket)
{
assert(FALSE);
- rts_error(VARLSTCNT(4) ERR_CURRSOCKOFR, 2, newdsocket->current_socket, newdsocket->n_socket);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_CURRSOCKOFR, 2, newdsocket->current_socket,
+ newdsocket->n_socket);
return;
}
}
+ socketptr->temp_sd = FD_INVALID;
}
newsocket = *socketptr;
/* ---------------------- apply changes to the local copy of the socket --------------------- */
@@ -438,7 +442,7 @@ void iosocket_use(io_desc *iod, mval *pp)
&newsocket.delimiter[0], NULL, NULL);
if (MAX_DELIM_LEN < new_len)
{
- rts_error(VARLSTCNT(1) ERR_DELIMSIZNA);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DELIMSIZNA);
return;
}
} else
@@ -456,7 +460,7 @@ void iosocket_use(io_desc *iod, mval *pp)
}
}
if (iod->wrap && 0 != newsocket.n_delimiter && iod->width < newsocket.delimiter[0].len)
- rts_error(VARLSTCNT(4) ERR_DELIMWIDTH, 2, iod->width, newsocket.delimiter[0].len);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_DELIMWIDTH, 2, iod->width, newsocket.delimiter[0].len);
if (0 <= zff_len && /* ZFF or ZNOFF specified */
0 < (newsocket.zff.len = zff_len)) /* assign the new ZFF len, might be 0 from ZNOFF, or ZFF="" */
{ /* ZFF="non-zero-len-string" specified */
@@ -467,7 +471,7 @@ void iosocket_use(io_desc *iod, mval *pp)
lcl_zff.len = zff_len;
new_len = gtm_conv(chset_desc[CHSET_UTF8], chset_desc[iod->ochset], &lcl_zff, NULL, NULL);
if (MAX_ZFF_LEN < new_len)
- rts_error(VARLSTCNT(4) ERR_ZFF2MANY, 2, new_len, MAX_ZFF_LEN);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZFF2MANY, 2, new_len, MAX_ZFF_LEN);
if (NULL == newsocket.zff.addr) /* we rely on newsocket.zff.addr being set to 0 in iosocket_create() */
newsocket.zff.addr = (char *)malloc(MAX_ZFF_LEN);
newsocket.zff.len = new_len;
@@ -512,7 +516,8 @@ void iosocket_use(io_desc *iod, mval *pp)
{
save_errno = errno;
errptr = (char *)STRERROR(save_errno);
- rts_error(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, LEN_AND_LIT("TCP_NODELAY"), save_errno, LEN_AND_STR(errptr));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, LEN_AND_LIT("TCP_NODELAY"), save_errno,
+ LEN_AND_STR(errptr));
return;
}
#endif
@@ -522,13 +527,14 @@ void iosocket_use(io_desc *iod, mval *pp)
{
save_errno = errno;
errptr = (char *)STRERROR(save_errno);
- rts_error(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, LEN_AND_LIT("SO_RCVBUF"), save_errno, LEN_AND_STR(errptr));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, LEN_AND_LIT("SO_RCVBUF"), save_errno,
+ LEN_AND_STR(errptr));
return;
}
if (socketptr->buffer_size != newsocket.buffer_size)
{
if (socketptr->buffered_length > bfsize)
- rts_error(VARLSTCNT(4) ERR_SOCKBFNOTEMPTY, 2, bfsize, socketptr->buffered_length);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_SOCKBFNOTEMPTY, 2, bfsize, socketptr->buffered_length);
newsocket.buffer = (char *)malloc(bfsize);
if (0 < socketptr->buffered_length)
{
@@ -544,12 +550,7 @@ void iosocket_use(io_desc *iod, mval *pp)
{ /* error message should be printed from bind/connect */
if (socketptr->sd > 0)
(void)tcp_routines.aa_close(socketptr->sd);
- iosocket_delimiter((unsigned char *)NULL, 0, &newsocket, TRUE);
- if (NULL != socketptr->zff.addr)
- free(socketptr->zff.addr);
- if (NULL != socketptr->buffer)
- free(socketptr->buffer);
- free(socketptr);
+ SOCKET_FREE(socketptr);
return;
}
/* ------------------------------------ commit changes -------------------------------------- */
@@ -557,7 +558,7 @@ void iosocket_use(io_desc *iod, mval *pp)
{
if (gtm_max_sockets <= newdsocket->n_socket)
{
- rts_error(VARLSTCNT(3) ERR_SOCKMAX, 1, gtm_max_sockets);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_SOCKMAX, 1, gtm_max_sockets);
return;
}
/* a new socket is created. so add to the list */
diff --git a/sr_port/iosocket_wait.c b/sr_port/iosocket_wait.c
index 71e7c5b..a4a676f 100644
--- a/sr_port/iosocket_wait.c
+++ b/sr_port/iosocket_wait.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -37,6 +37,8 @@
#include <rtnhdr.h>
#include "stack_frame.h"
#include "mv_stent.h"
+#include "gtm_netdb.h"
+#include "gtm_stdlib.h"
#define CONNECTED "CONNECT"
#define READ "READ"
@@ -50,6 +52,7 @@ GBLREF stack_frame *frame_pointer;
GBLREF unsigned char *stackbase, *stacktop, *msp, *stackwarn;
GBLREF mv_stent *mv_chain;
+error_def(ERR_GETNAMEINFO);
error_def(ERR_SOCKACPT);
error_def(ERR_SOCKWAIT);
error_def(ERR_TEXT);
@@ -62,269 +65,234 @@ boolean_t iosocket_wait(io_desc *iod, int4 timepar)
{
struct timeval utimeout;
ABS_TIME cur_time, end_time;
- struct sockaddr_in peer; /* socket address + port */
- fd_set tcp_fd;
- d_socket_struct *dsocketptr;
- socket_struct *socketptr, *newsocketptr;
+ struct sockaddr_storage peer; /* socket address + port */
+ fd_set tcp_fd;
+ d_socket_struct *dsocketptr;
+ socket_struct *socketptr, *newsocketptr;
socket_interrupt *sockintr;
- char *errptr;
- int4 errlen, ii, msec_timeout;
+ char *errptr;
+ int4 errlen, ii, msec_timeout;
int rv, max_fd, len;
GTM_SOCKLEN_TYPE size;
boolean_t zint_restart;
mv_stent *mv_zintdev;
int retry_num;
+ struct sockaddr *peer_sa_ptr;
+ char port_buffer[NI_MAXSERV], ipaddr[SA_MAXLEN + 1];
+ int errcode;
/* check for validity */
- assert(iod->type == gtmsocket);
- dsocketptr = (d_socket_struct *)iod->dev_sp;
+ assert(iod->type == gtmsocket);
+ dsocketptr = (d_socket_struct *)iod->dev_sp;
sockintr = &dsocketptr->sock_save_state;
+ peer_sa_ptr = ((struct sockaddr *)(&peer));
/* Check for restart */
- if (!dsocketptr->mupintr)
- /* Simple path, no worries*/
- zint_restart = FALSE;
- else
- { /* We have a pending wait restart of some sort - check we aren't recursing on this device */
- if (sockwhich_invalid == sockintr->who_saved)
- GTMASSERT; /* Interrupt should never have an invalid save state */
- if (dollar_zininterrupt)
- rts_error(VARLSTCNT(1) ERR_ZINTRECURSEIO);
- if (sockwhich_wait != sockintr->who_saved)
- GTMASSERT; /* ZINTRECURSEIO should have caught */
- DBGSOCK((stdout, "socwait: *#*#*#*#*#*#*# Restarted interrupted wait\n"));
- mv_zintdev = io_find_mvstent(iod, FALSE);
- if (mv_zintdev)
- {
- if (sockintr->end_time_valid)
- /* Restore end_time for timeout */
- end_time = sockintr->end_time;
+ if (!dsocketptr->mupintr)
+ /* Simple path, no worries*/
+ zint_restart = FALSE;
+ else
+ { /* We have a pending wait restart of some sort - check we aren't recursing on this device */
+ if (sockwhich_invalid == sockintr->who_saved)
+ GTMASSERT; /* Interrupt should never have an invalid save state */
+ if (dollar_zininterrupt)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZINTRECURSEIO);
+ if (sockwhich_wait != sockintr->who_saved)
+ GTMASSERT; /* ZINTRECURSEIO should have caught */
+ DBGSOCK((stdout, "socwait: *#*#*#*#*#*#*# Restarted interrupted wait\n"));
+ mv_zintdev = io_find_mvstent(iod, FALSE);
+ if (mv_zintdev)
+ {
+ if (sockintr->end_time_valid)
+ /* Restore end_time for timeout */
+ end_time = sockintr->end_time;
- /* Done with this mv_stent. Pop it off if we can, else mark it inactive. */
- if (mv_chain == mv_zintdev)
- POP_MV_STENT(); /* pop if top of stack */
- else
- { /* else mark it unused */
- mv_zintdev->mv_st_cont.mvs_zintdev.buffer_valid = FALSE;
- mv_zintdev->mv_st_cont.mvs_zintdev.io_ptr = NULL;
- }
+ /* Done with this mv_stent. Pop it off if we can, else mark it inactive. */
+ if (mv_chain == mv_zintdev)
+ POP_MV_STENT(); /* pop if top of stack */
+ else
+ { /* else mark it unused */
+ mv_zintdev->mv_st_cont.mvs_zintdev.buffer_valid = FALSE;
+ mv_zintdev->mv_st_cont.mvs_zintdev.io_ptr = NULL;
+ }
zint_restart = TRUE;
DBGSOCK((stdout, "socwait: mv_stent found - endtime: %d/%d\n", end_time.at_sec, end_time.at_usec));
- } else
+ } else
DBGSOCK((stdout, "socwait: no mv_stent found !!\n"));
- dsocketptr->mupintr = FALSE;
+ dsocketptr->mupintr = FALSE;
sockintr->who_saved = sockwhich_invalid;
- }
-
+ }
/* check for events */
- max_fd = 0;
FD_ZERO(&tcp_fd);
- for (ii = 0; ii < dsocketptr->n_socket; ii++)
- {
- socketptr = dsocketptr->socket[ii];
- if ((socket_listening == socketptr->state) || (socket_connected == socketptr->state))
- {
- FD_SET(socketptr->sd, &tcp_fd);
- max_fd = MAX(max_fd, socketptr->sd);
- }
- }
- utimeout.tv_sec = timepar;
- utimeout.tv_usec = 0;
- msec_timeout = timeout2msec(timepar);
- sys_get_curr_time(&cur_time);
- if (!zint_restart || !sockintr->end_time_valid)
- add_int_to_abs_time(&cur_time, msec_timeout, &end_time);
- else
- { /* end_time taken from restart data. Compute what msec_timeout should be so timeout timer
- gets set correctly below.
- */
- DBGSOCK((stdout, "socwait: Taking timeout end time from wait restart data\n"));
- cur_time = sub_abs_time(&end_time, &cur_time);
- if (0 > cur_time.at_sec)
- {
- msec_timeout = -1;
- utimeout.tv_sec = 0;
- utimeout.tv_usec = 0;
- } else
- {
- msec_timeout = (int4)(cur_time.at_sec * 1000 + cur_time.at_usec / 1000);
- utimeout.tv_sec = cur_time.at_sec;
- utimeout.tv_usec = (gtm_tv_usec_t)cur_time.at_usec;
- }
- }
- sockintr->end_time_valid = FALSE;
-
- for ( ; ; )
+ while (TRUE)
{
- rv = select(max_fd + 1, (void *)&tcp_fd, (void *)0, (void *)0,
- (timepar == NO_M_TIMEOUT ? (struct timeval *)0 : &utimeout));
- if (0 > rv && EINTR == errno)
+ max_fd = 0;
+ for (ii = 0; ii < dsocketptr->n_socket; ii++)
{
- if (0 != outofband)
+ socketptr = dsocketptr->socket[ii];
+ if ((socket_listening == socketptr->state) || (socket_connected == socketptr->state))
{
- DBGSOCK((stdout, "socwait: outofband interrupt received (%d) -- "
- "queueing mv_stent for wait intr\n", outofband));
- PUSH_MV_STENT(MVST_ZINTDEV);
- mv_chain->mv_st_cont.mvs_zintdev.io_ptr = iod;
- mv_chain->mv_st_cont.mvs_zintdev.buffer_valid = FALSE;
- sockintr->who_saved = sockwhich_wait;
- sockintr->end_time = end_time;
- sockintr->end_time_valid = TRUE;
- dsocketptr->mupintr = TRUE;
- socketus_interruptus++;
- DBGSOCK((stdout, "socwait: mv_stent queued - endtime: %d/%d interrupts: %d\n",
- end_time.at_sec, end_time.at_usec, socketus_interruptus));
- outofband_action(FALSE);
- GTMASSERT; /* Should *never* return from outofband_action */
- return FALSE; /* For the compiler.. */
+ FD_SET(socketptr->sd, &tcp_fd);
+ max_fd = MAX(max_fd, socketptr->sd);
}
- sys_get_curr_time(&cur_time);
+ }
+ utimeout.tv_sec = timepar;
+ utimeout.tv_usec = 0;
+ msec_timeout = timeout2msec(timepar);
+ sys_get_curr_time(&cur_time);
+ if (!zint_restart || !sockintr->end_time_valid)
+ add_int_to_abs_time(&cur_time, msec_timeout, &end_time);
+ else
+ { /* end_time taken from restart data. Compute what msec_timeout should be so timeout timer
+ gets set correctly below.
+ */
+ DBGSOCK((stdout, "socwait: Taking timeout end time from wait restart data\n"));
cur_time = sub_abs_time(&end_time, &cur_time);
if (0 > cur_time.at_sec)
{
- rv = 0; /* time out */
- break;
+ 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;
}
- utimeout.tv_sec = cur_time.at_sec;
- utimeout.tv_usec = (gtm_tv_usec_t)cur_time.at_usec;
- } else
- break; /* either other error or done */
- }
- if (rv == 0)
- {
- dsocketptr->dollar_key[0] = '\0';
- return FALSE;
- } else if (rv < 0)
- {
- errptr = (char *)STRERROR(errno);
- errlen = STRLEN(errptr);
- rts_error(VARLSTCNT(6) ERR_SOCKWAIT, 0, ERR_TEXT, 2, errlen, errptr);
- return FALSE;
- }
- /* find out which socket is ready */
- for (ii = 0; ii < dsocketptr->n_socket; ii++)
- {
- socketptr = dsocketptr->socket[ii];
- if (0 != FD_ISSET(socketptr->sd, &tcp_fd))
- break;
- }
- assert(ii < dsocketptr->n_socket);
- if (socket_listening == socketptr->state)
- {
- if (gtm_max_sockets <= dsocketptr->n_socket)
- {
- rts_error(VARLSTCNT(3) ERR_SOCKMAX, 1, gtm_max_sockets);
- return FALSE;
- }
- size = SIZEOF(struct sockaddr_in);
- rv = tcp_routines.aa_accept(socketptr->sd, &peer, &size);
- if (-1 == rv)
- {
-#ifdef __hpux
- /*ENOBUFS in HP-UX is either because of a memory problem or when we have received a RST just
- after a SYN before an accept call. Normally this is not fatal and is just a transient state. Hence
- exiting just after a single error of this kind should not be done. So retry in case of HP-UX and ENOBUFS error.*/
- if (ENOBUFS == errno)
+ }
+ sockintr->end_time_valid = FALSE;
+ for ( ; ; )
{
- /*In case of succeeding with select in first go, accept will still get 5ms time difference*/
- retry_num = 0;
- while (HPUX_MAX_RETRIES > retry_num)
+ rv = select(max_fd + 1, (void *)&tcp_fd, (void *)0, (void *)0,
+ (timepar == NO_M_TIMEOUT ? (struct timeval *)0 : &utimeout));
+ if (0 > rv && EINTR == errno)
{
- SHORT_SLEEP(5);
- for ( ; HPUX_MAX_RETRIES > retry_num; retry_num++)
+ if (0 != outofband)
{
- utimeout.tv_sec = 0;
- utimeout.tv_usec = HPUX_SEL_TIMEOUT;
- FD_ZERO(&tcp_fd);
- FD_SET(socketptr->sd, &tcp_fd);
- rv = select(max_fd + 1, (void *)&tcp_fd, (void *)0, (void *)0,
- &utimeout);
- if (0 < rv)
- break;
- if (0 > rv && (EINTR == errno))
- {
- if (0 != outofband)
- {
- DBGSOCK((stdout, "socwait: outofband interrupt received (%d) -- "
- "queueing mv_stent for wait intr\n", outofband));
- PUSH_MV_STENT(MVST_ZINTDEV);
- mv_chain->mv_st_cont.mvs_zintdev.io_ptr = iod;
- mv_chain->mv_st_cont.mvs_zintdev.buffer_valid = FALSE;
- sockintr->who_saved = sockwhich_wait;
- sockintr->end_time = end_time;
- sockintr->end_time_valid = TRUE;
- dsocketptr->mupintr = TRUE;
- socketus_interruptus++;
- DBGSOCK((stdout, "socwait: mv_stent queued - endtime: %d/%d interrupts:"
- " %d\n", end_time.at_sec, end_time.at_usec,
- socketus_interruptus));
- outofband_action(FALSE);
- GTMASSERT; /* Should *never* return from outofband_action */
- return FALSE; /* For the compiler.. */
- }
- }
- else
- SHORT_SLEEP(5);
- }
- if (0 > rv)
- {
- errptr = (char *)STRERROR(errno);
- errlen = STRLEN(errptr);
- rts_error(VARLSTCNT(6) ERR_SOCKWAIT, 0, ERR_TEXT, 2, errlen, errptr);
- return FALSE;
+ DBGSOCK((stdout, "socwait: outofband interrupt received (%d) -- "
+ "queueing mv_stent for wait intr\n", outofband));
+ PUSH_MV_STENT(MVST_ZINTDEV);
+ mv_chain->mv_st_cont.mvs_zintdev.io_ptr = iod;
+ mv_chain->mv_st_cont.mvs_zintdev.buffer_valid = FALSE;
+ sockintr->who_saved = sockwhich_wait;
+ sockintr->end_time = end_time;
+ sockintr->end_time_valid = TRUE;
+ dsocketptr->mupintr = TRUE;
+ socketus_interruptus++;
+ DBGSOCK((stdout, "socwait: mv_stent queued - endtime: %d/%d interrupts: %d\n",
+ end_time.at_sec, end_time.at_usec, socketus_interruptus));
+ outofband_action(FALSE);
+ GTMASSERT; /* Should *never* return from outofband_action */
+ return FALSE; /* For the compiler.. */
}
- rv = tcp_routines.aa_accept(socketptr->sd, &peer, &size);
- if ((-1 == rv) && (ENOBUFS == errno))
- retry_num++;
- else
+ sys_get_curr_time(&cur_time);
+ cur_time = sub_abs_time(&end_time, &cur_time);
+ if (0 > cur_time.at_sec)
+ {
+ rv = 0; /* time out */
break;
- }
+ }
+ utimeout.tv_sec = cur_time.at_sec;
+ utimeout.tv_usec = (gtm_tv_usec_t)cur_time.at_usec;
+ } else
+ break; /* either other error or done */
}
- if (-1 == rv)
-#endif
+ if (rv == 0)
+ {
+ iod->dollar.key[0] = '\0';
+ return FALSE;
+ } else if (rv < 0)
{
errptr = (char *)STRERROR(errno);
errlen = STRLEN(errptr);
- rts_error(VARLSTCNT(6) ERR_SOCKACPT, 0, ERR_TEXT, 2, errlen, errptr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_SOCKWAIT, 0, ERR_TEXT, 2, errlen, errptr);
return FALSE;
}
- }
- /* got the connection, create a new socket in the device socket list */
- newsocketptr = (socket_struct *)malloc(SIZEOF(socket_struct));
- *newsocketptr = *socketptr;
- newsocketptr->sd = rv;
- memcpy(&newsocketptr->remote.sin, &peer, SIZEOF(struct sockaddr_in));
- SPRINTF(newsocketptr->remote.saddr_ip, "%s", tcp_routines.aa_inet_ntoa(peer.sin_addr));
- newsocketptr->remote.port = GTM_NTOHS(peer.sin_port);
- newsocketptr->state = socket_connected;
- newsocketptr->passive = FALSE;
- iosocket_delimiter_copy(socketptr, newsocketptr);
- newsocketptr->buffer = (char *)malloc(socketptr->buffer_size);
- newsocketptr->buffer_size = socketptr->buffer_size;
- newsocketptr->buffered_length = socketptr->buffered_offset = 0;
- newsocketptr->first_read = newsocketptr->first_write = TRUE;
- /* put the new-born socket to the list and create a handle for it */
- iosocket_handle(newsocketptr->handle, &newsocketptr->handle_len, TRUE, dsocketptr);
- dsocketptr->socket[dsocketptr->n_socket++] = newsocketptr;
- dsocketptr->current_socket = dsocketptr->n_socket - 1;
- len = SIZEOF(CONNECTED) - 1;
- memcpy(&dsocketptr->dollar_key[0], CONNECTED, len);
- dsocketptr->dollar_key[len++] = '|';
- memcpy(&dsocketptr->dollar_key[len], newsocketptr->handle, newsocketptr->handle_len);
- len += newsocketptr->handle_len;
- dsocketptr->dollar_key[len++] = '|';
- strcpy(&dsocketptr->dollar_key[len], newsocketptr->remote.saddr_ip);
- } else
- {
- assert(socket_connected == socketptr->state);
- dsocketptr->current_socket = ii;
- len = SIZEOF(READ) - 1;
- memcpy(&dsocketptr->dollar_key[0], READ, len);
- dsocketptr->dollar_key[len++] = '|';
- memcpy(&dsocketptr->dollar_key[len], socketptr->handle, socketptr->handle_len);
- len += socketptr->handle_len;
- dsocketptr->dollar_key[len++] = '|';
- strcpy(&dsocketptr->dollar_key[len], socketptr->remote.saddr_ip);
+ /* find out which socket is ready */
+ for (ii = 0; ii < dsocketptr->n_socket; ii++)
+ {
+ socketptr = dsocketptr->socket[ii];
+ if (0 != FD_ISSET(socketptr->sd, &tcp_fd))
+ break;
+ }
+ assert(ii < dsocketptr->n_socket);
+ if (socket_listening == socketptr->state)
+ {
+ if (gtm_max_sockets <= dsocketptr->n_socket)
+ {
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_SOCKMAX, 1, gtm_max_sockets);
+ return FALSE;
+ }
+
+ size = SIZEOF(struct sockaddr_storage);
+ rv = tcp_routines.aa_accept(socketptr->sd, peer_sa_ptr, &size);
+ if (-1 == rv)
+ {
+# ifdef __hpux
+ if (ENOBUFS == errno)
+ continue; /* On HP-UX, ENOBUFS may indicate a transient condition; retry */
+# endif
+ errptr = (char *)STRERROR(errno);
+ errlen = STRLEN(errptr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_SOCKACPT, 0, ERR_TEXT, 2, errlen, errptr);
+ return FALSE;
+ }
+ SOCKET_DUP(socketptr, newsocketptr);
+ newsocketptr->sd = rv;
+ SOCKET_ADDR_COPY(newsocketptr->remote, peer_sa_ptr, size);
+ /* translate internal address to numeric ip address */
+ GETNAMEINFO(peer_sa_ptr, size, ipaddr, SA_MAXLEN, NULL, 0, NI_NUMERICHOST, errcode);
+ if (0 != errcode)
+ {
+ SOCKET_FREE(newsocketptr);
+ RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode);
+ return FALSE;
+ }
+ if (NULL != newsocketptr->remote.saddr_ip)
+ free(newsocketptr->remote.saddr_ip);
+ STRNDUP(ipaddr, SA_MAXLEN, newsocketptr->remote.saddr_ip);
+ /* translate internal address to port number*/
+ GETNAMEINFO(peer_sa_ptr, size, NULL, 0, port_buffer, NI_MAXSERV, NI_NUMERICSERV, errcode);
+ if (0 != errcode)
+ {
+ SOCKET_FREE(newsocketptr);
+ RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode);
+ return FALSE;
+ }
+ newsocketptr->remote.port = ATOI(port_buffer);
+ newsocketptr->state = socket_connected;
+ newsocketptr->passive = FALSE;
+ newsocketptr->first_read = newsocketptr->first_write = TRUE;
+ /* put the new-born socket to the list and create a handle for it */
+ iosocket_handle(newsocketptr->handle, &newsocketptr->handle_len, TRUE, dsocketptr);
+ dsocketptr->socket[dsocketptr->n_socket++] = newsocketptr;
+ dsocketptr->current_socket = dsocketptr->n_socket - 1;
+ len = SIZEOF(CONNECTED) - 1;
+ memcpy(&iod->dollar.key[0], CONNECTED, len);
+ iod->dollar.key[len++] = '|';
+ memcpy(&iod->dollar.key[len], newsocketptr->handle, newsocketptr->handle_len);
+ len += newsocketptr->handle_len;
+ iod->dollar.key[len++] = '|';
+ strncpy(&iod->dollar.key[len], newsocketptr->remote.saddr_ip, DD_BUFLEN - 1 - len);
+ iod->dollar.key[DD_BUFLEN-1] = '\0'; /* In case we fill the buffer */
+ } else
+ {
+ assert(socket_connected == socketptr->state);
+ dsocketptr->current_socket = ii;
+ len = SIZEOF(READ) - 1;
+ memcpy(&iod->dollar.key[0], READ, len);
+ iod->dollar.key[len++] = '|';
+ memcpy(&iod->dollar.key[len], socketptr->handle, socketptr->handle_len);
+ len += socketptr->handle_len;
+ iod->dollar.key[len++] = '|';
+ if (NULL != socketptr->remote.saddr_ip)
+ {
+ strncpy(&iod->dollar.key[len], socketptr->remote.saddr_ip, DD_BUFLEN - 1 - len);
+ iod->dollar.key[DD_BUFLEN-1] = '\0';
+ } else
+ iod->dollar.key[len] = '\0';
+ }
+ break;
}
return TRUE;
}
diff --git a/sr_port/iosocket_write.c b/sr_port/iosocket_write.c
index a130a1b..aa97211 100644
--- a/sr_port/iosocket_write.c
+++ b/sr_port/iosocket_write.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -72,11 +72,11 @@ void iosocket_write_real(mstr *v, boolean_t convert_output)
socketptr = dsocketptr->socket[dsocketptr->current_socket];
if (dsocketptr->n_socket <= dsocketptr->current_socket)
{
- rts_error(VARLSTCNT(4) ERR_CURRSOCKOFR, 2, dsocketptr->current_socket, dsocketptr->n_socket);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_CURRSOCKOFR, 2, dsocketptr->current_socket, dsocketptr->n_socket);
return;
}
if (dsocketptr->mupintr)
- rts_error(VARLSTCNT(1) ERR_ZINTRECURSEIO);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZINTRECURSEIO);
#ifdef MSG_NOSIGNAL
flags = MSG_NOSIGNAL; /* return EPIPE instead of SIGPIPE */
#else
@@ -99,7 +99,7 @@ void iosocket_write_real(mstr *v, boolean_t convert_output)
DBGSOCK2((stdout, "socwrite: TCP send of BOM-BE with rc %d\n", status));
if (0 != status)
{
- SOCKERROR(iod, dsocketptr, socketptr, ERR_SOCKWRITE, status);
+ SOCKERROR(iod, socketptr, ERR_SOCKWRITE, status);
return;
}
#ifdef UNIX
@@ -114,7 +114,7 @@ void iosocket_write_real(mstr *v, boolean_t convert_output)
new_len = gtm_conv(chset_desc[CHSET_UTF8], chset_desc[iod->ochset], &socketptr->zff, NULL,
NULL);
if (MAX_ZFF_LEN < new_len)
- rts_error(VARLSTCNT(4) ERR_ZFF2MANY, 2, new_len, MAX_ZFF_LEN);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZFF2MANY, 2, new_len, MAX_ZFF_LEN);
if (NULL != socketptr->zff.addr) /* we rely on newsocket.zff.addr being set to NULL
in iosocket_create() */
socketptr->zff.addr = (char *)malloc(MAX_ZFF_LEN);
@@ -129,7 +129,7 @@ void iosocket_write_real(mstr *v, boolean_t convert_output)
&socketptr->delimiter[0], NULL, NULL);
if (MAX_DELIM_LEN < new_len)
{
- rts_error(VARLSTCNT(1) ERR_DELIMSIZNA);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DELIMSIZNA);
return;
}
socketptr->odelimiter0.len = new_len;
@@ -140,7 +140,7 @@ void iosocket_write_real(mstr *v, boolean_t convert_output)
}
socketptr->first_write = FALSE;
}
- memcpy(dsocketptr->dollar_device, "0", SIZEOF("0"));
+ memcpy(iod->dollar.device, "0", SIZEOF("0"));
if (CHSET_M != iod->ochset)
{ /* For ochset == UTF-8, validate the output,
* For ochset == UTF-16[B|L]E, convert the output (and validate during conversion)
@@ -194,7 +194,7 @@ void iosocket_write_real(mstr *v, boolean_t convert_output)
socketptr->odelimiter0.len, status));
if (0 != status)
{
- SOCKERROR(iod, dsocketptr, socketptr, ERR_SOCKWRITE, status);
+ SOCKERROR(iod, socketptr, ERR_SOCKWRITE, status);
return;
}
#ifdef UNIX
@@ -234,7 +234,7 @@ void iosocket_write_real(mstr *v, boolean_t convert_output)
DBGSOCK2((stdout, "socwrite: TCP data send of %d bytes with rc %d\n", b_len, status));
if (0 != status)
{
- SOCKERROR(iod, dsocketptr, socketptr, ERR_SOCKWRITE, status);
+ SOCKERROR(iod, socketptr, ERR_SOCKWRITE, status);
return;
}
#ifdef UNIX
diff --git a/sr_port/iosocket_wteol.c b/sr_port/iosocket_wteol.c
index 01f4c30..c265c16 100644
--- a/sr_port/iosocket_wteol.c
+++ b/sr_port/iosocket_wteol.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -16,7 +16,6 @@
#include "gtm_socket.h"
#include "gtm_inet.h"
-#include <netinet/tcp.h>
#include "gt_timer.h"
#include "io.h"
diff --git a/sr_port/iosocketdef.h b/sr_port/iosocketdef.h
index 3f305cf..951f67b 100644
--- a/sr_port/iosocketdef.h
+++ b/sr_port/iosocketdef.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -20,6 +20,9 @@
#include <sys/types.h>
#include "gtm_inet.h"
+#include "gtm_netdb.h"
+#include "gtm_socket.h" /* for using sockaddr_storage */
+#include "iotcpdef.h"
#ifndef GTM_MB_LEN_MAX
#include "gtm_utf8.h"
@@ -74,28 +77,110 @@
#define ONE_COMMA "1,"
-#define SOCKERROR(iod, dsocketptr, socketptr, gtmerror, syserror) \
-{ \
- int errlen; \
- char *errptr; \
- iod->dollar.za = 9; \
- memcpy(dsocketptr->dollar_device, ONE_COMMA, SIZEOF(ONE_COMMA)); \
- errptr = (char *)STRERROR(syserror); \
- errlen = STRLEN(errptr); \
- memcpy(&dsocketptr->dollar_device[SIZEOF(ONE_COMMA) - 1], errptr, errlen + 1); /* + 1 for null */ \
- assert(ERR_SOCKWRITE == gtmerror); \
- UNIX_ONLY(if (iod == io_std_device.out) \
- { \
- if (!prin_out_dev_failure) \
- prin_out_dev_failure = TRUE; \
- else \
- { \
- send_msg(VARLSTCNT(1) ERR_NOPRINCIO); \
- stop_image_no_core(); \
- } \
- }) \
- if (socketptr->ioerror) \
- rts_error(VARLSTCNT(6) gtmerror, 0, ERR_TEXT, 2, errlen, errptr); \
+#define SOCKERROR(iod, socketptr, gtmerror, syserror) \
+{ \
+ int errlen; \
+ char *errptr; \
+ iod->dollar.za = 9; \
+ memcpy(iod->dollar.device, ONE_COMMA, SIZEOF(ONE_COMMA)); \
+ errptr = (char *)STRERROR(syserror); \
+ errlen = STRLEN(errptr); \
+ memcpy(&iod->dollar.device[SIZEOF(ONE_COMMA) - 1], errptr, errlen + 1); /* + 1 for null */ \
+ assert(ERR_SOCKWRITE == gtmerror); \
+ UNIX_ONLY(if (iod == io_std_device.out) \
+ { \
+ if (!prin_out_dev_failure) \
+ prin_out_dev_failure = TRUE; \
+ else \
+ { \
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOPRINCIO); \
+ stop_image_no_core(); \
+ } \
+ }) \
+ if (socketptr->ioerror) \
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) gtmerror, 0, ERR_TEXT, 2, errlen, errptr); \
+}
+
+#define SOCKET_ALLOC(SOCKPTR) \
+{ \
+ SOCKPTR = (socket_struct *)malloc(SIZEOF(socket_struct)); \
+ memset(SOCKPTR, 0, SIZEOF(socket_struct)); \
+}
+
+#define SOCKET_ADDR(SOCKPTR, SOCKEND) \
+ ((sockaddr_ptr)(SOCKPTR->SOCKEND.sa \
+ ? SOCKPTR->SOCKEND.sa \
+ : (SOCKPTR->SOCKEND.sa = (struct sockaddr *)malloc(SIZEOF(struct sockaddr_storage)))))
+
+#define SOCKET_LOCAL_ADDR(SOCKPTR) SOCKET_ADDR(SOCKPTR, local)
+#define SOCKET_REMOTE_ADDR(SOCKPTR) SOCKET_ADDR(SOCKPTR, remote)
+
+#define SOCKET_ADDR_COPY(SOCKADDRESS, SOCKADDRPTR, SOCKADDRLEN) \
+{ \
+ if (SOCKADDRESS.sa) \
+ free(SOCKADDRESS.sa); \
+ SOCKADDRESS.sa = (struct sockaddr *)malloc(SOCKADDRLEN); \
+ memcpy(SOCKADDRESS.sa, SOCKADDRPTR, SOCKADDRLEN); \
+}
+
+#define SOCKET_AI_TO_ADDR(SOCKPTR, AIPTR, SOCKEND) SOCKET_ADDR_COPY((SOCKPTR)->SOCKEND, (AIPTR)->ai_addr, (AIPTR)->ai_addrlen)
+#define SOCKET_AI_TO_LOCAL_ADDR(SOCKPTR, AIPTR) SOCKET_AI_TO_ADDR(SOCKPTR, AIPTR, local)
+#define SOCKET_AI_TO_REMOTE_ADDR(SOCKPTR, AIPTR) SOCKET_AI_TO_ADDR(SOCKPTR, AIPTR, remote)
+
+#define SOCKET_ADDRLEN(SOCKPTR, AIPTR, SOCKEND) \
+ (((SOCKPTR)->SOCKEND.sa) ? ((AIPTR)->ai_addrlen) : (SIZEOF(struct sockaddr_storage)))
+
+#define SOCKET_BUFFER_INIT(SOCKPTR, SIZE) \
+{ \
+ SOCKPTR->buffer = (char *)malloc(SIZE); \
+ SOCKPTR->buffer_size = SIZE; \
+ SOCKPTR->buffered_length = SOCKPTR->buffered_offset = 0; \
+}
+
+#define SOCKET_FREE(SOCKPTR) \
+{ \
+ if (NULL != SOCKPTR->buffer) \
+ free(SOCKPTR->buffer); \
+ if (NULL != SOCKPTR->zff.addr) \
+ free(SOCKPTR->zff.addr); \
+ if (NULL != SOCKPTR->local.sa) \
+ free(SOCKPTR->local.sa); \
+ if (NULL != SOCKPTR->remote.sa) \
+ free(SOCKPTR->remote.sa); \
+ if (NULL != SOCKPTR->local.saddr_ip) \
+ free(SOCKPTR->local.saddr_ip); \
+ if (NULL != SOCKPTR->remote.saddr_ip) \
+ free(SOCKPTR->remote.saddr_ip); \
+ iosocket_delimiter((unsigned char *)NULL, 0, SOCKPTR, TRUE); \
+ free(SOCKPTR); \
+}
+
+#define SOCKET_DUP(SOCKPTR, NEWSOCKPTR) \
+{ \
+ NEWSOCKPTR = (socket_struct *)malloc(SIZEOF(socket_struct)); \
+ *NEWSOCKPTR = *SOCKPTR; \
+ if (NULL != SOCKPTR->buffer) \
+ NEWSOCKPTR->buffer = (char *)malloc(SOCKPTR->buffer_size); \
+ if (NULL != SOCKPTR->zff.addr) \
+ { \
+ NEWSOCKPTR->zff.addr = (char *)malloc(MAX_ZFF_LEN); \
+ memcpy(NEWSOCKPTR->zff.addr, SOCKPTR->zff.addr, SOCKPTR->zff.len); \
+ } \
+ if (NULL != SOCKPTR->local.sa) \
+ { \
+ NEWSOCKPTR->local.sa = (struct sockaddr *)malloc(SOCKPTR->local.ai.ai_addrlen); \
+ memcpy(NEWSOCKPTR->local.sa, SOCKPTR->local.sa, SOCKPTR->local.ai.ai_addrlen); \
+ } \
+ if (NULL != SOCKPTR->remote.sa) \
+ { \
+ NEWSOCKPTR->remote.sa = (struct sockaddr *)malloc(SOCKPTR->remote.ai.ai_addrlen); \
+ memcpy(NEWSOCKPTR->remote.sa, SOCKPTR->remote.sa, SOCKPTR->remote.ai.ai_addrlen); \
+ } \
+ if (NULL != SOCKPTR->local.saddr_ip) \
+ STRNDUP(SOCKPTR->local.saddr_ip, SA_MAXLEN, NEWSOCKPTR->local.saddr_ip); \
+ if (NULL != SOCKPTR->remote.saddr_ip) \
+ STRNDUP(SOCKPTR->remote.saddr_ip, SA_MAXLEN, NEWSOCKPTR->remote.saddr_ip); \
+ iosocket_delimiter_copy(SOCKPTR, NEWSOCKPTR); \
}
enum socket_state
@@ -124,15 +209,17 @@ enum socket_which /* which module saved the interrupted info */
typedef struct socket_address_type
{
- struct sockaddr_in sin; /* accurate one */
+ struct sockaddr *sa;
+ struct addrinfo ai;
+ struct addrinfo *ai_head; /* store the head of addrinfo linked list */
unsigned short port;
- char saddr_ip[SA_MAXLEN];
- char saddr_lit[SA_MAXLITLEN];
+ char *saddr_ip;
} socket_address;
typedef struct socket_struct_type
{
int sd; /* socket descriptor */
+ int temp_sd; /* a temp socket descriptor only to test whether IPv6 can be created */
struct d_socket_struct_type *dev; /* point back to the driver */
boolean_t passive,
ioerror,
@@ -181,8 +268,6 @@ typedef struct d_socket_struct_type
boolean_t mupintr; /* We were mupip interrupted */
int4 current_socket; /* current socket index */
int4 n_socket; /* number of sockets */
- char dollar_device[DD_BUFLEN];
- char dollar_key[DD_BUFLEN];
struct io_desc_struct *iod; /* Point back to main IO descriptor block */
struct socket_struct_type *socket[1]; /* Array size determined by gtm_max_sockets */
} d_socket_struct;
diff --git a/sr_port/iotcp_close.c b/sr_port/iotcp_close.c
index aafb0ef..76f2ad9 100644
--- a/sr_port/iotcp_close.c
+++ b/sr_port/iotcp_close.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * Copyright 2001, 2013 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 "mdef.h"
#include "gtm_stdio.h"
-#include <netinet/in.h>
+#include "gtm_inet.h"
#include "copy.h"
#include "io_params.h"
diff --git a/sr_port/iotcp_fillroutine.c b/sr_port/iotcp_fillroutine.c
index 6d71024..0126610 100644
--- a/sr_port/iotcp_fillroutine.c
+++ b/sr_port/iotcp_fillroutine.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -119,14 +119,6 @@ int iotcp_fillroutine(void)
tcp_routines.aa_connect = gtm_connect;
tcp_routines.aa_getsockname = getsockname;
tcp_routines.aa_getsockopt = getsockopt;
-#ifndef htons /* if htons is not a macro, assign the routine */
- tcp_routines.aa_htons = htons;
-#endif
- tcp_routines.aa_inet_addr = INET_ADDR;
- tcp_routines.aa_inet_ntoa = INET_NTOA;
-#ifndef ntohs
- tcp_routines.aa_ntohs = ntohs;
-#endif
tcp_routines.aa_listen = listen;
tcp_routines.aa_recv = (int (*)())gtm_recv;
tcp_routines.aa_select = select;
diff --git a/sr_port/iotcp_flush.c b/sr_port/iotcp_flush.c
index b8ddc9f..d731116 100644
--- a/sr_port/iotcp_flush.c
+++ b/sr_port/iotcp_flush.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -12,7 +12,7 @@
#include "mdef.h"
#include "gtm_stdio.h"
-#include <netinet/in.h>
+#include "gtm_inet.h"
#include "io.h"
#include "iotcpdef.h"
diff --git a/sr_port/iotcp_iocontrol.c b/sr_port/iotcp_iocontrol.c
index ed725c4..76959d8 100644
--- a/sr_port/iotcp_iocontrol.c
+++ b/sr_port/iotcp_iocontrol.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2007 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -12,7 +12,7 @@
#include "mdef.h"
#include <sys/types.h>
-#include <netinet/in.h>
+#include "gtm_inet.h"
#include "gtm_string.h"
#include "io.h"
@@ -30,15 +30,12 @@ void iotcp_dlr_device(mstr *d)
{
io_desc *iod;
int len;
- d_tcp_struct *tcpptr;
iod = io_curr_device.out;
- tcpptr = (d_tcp_struct *)iod->dev_sp;
-
- len = STRLEN(tcpptr->dollar_device);
+ len = STRLEN(iod->dollar.device);
/* verify internal buffer has enough space for $DEVICE string value */
assert((int)d->len > len);
- memcpy(d->addr, tcpptr->dollar_device, len);
+ memcpy(d->addr, iod->dollar.device, len);
d->len = len;
return;
}
@@ -48,15 +45,12 @@ void iotcp_dlr_key(mstr *d)
{
io_desc *iod;
int len;
- d_tcp_struct *tcpptr;
iod = io_curr_device.out;
- tcpptr = (d_tcp_struct *)iod->dev_sp;
-
- len = STRLEN(tcpptr->saddr);
+ len = STRLEN(iod->dollar.key);
/* verify internal buffer has enough space for $KEY string value */
assert((int)d->len > len);
- memcpy(d->addr, tcpptr->saddr, len);
+ memcpy(d->addr, iod->dollar.key, len);
d->len = len;
return;
}
diff --git a/sr_port/iotcp_list.c b/sr_port/iotcp_list.c
index f7b37f4..d1f5442 100644
--- a/sr_port/iotcp_list.c
+++ b/sr_port/iotcp_list.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -25,11 +25,15 @@
#include "iotcproutine.h"
#include "iotcpdef.h"
+error_def(ERR_SOCKINIT);
+error_def(ERR_TEXT);
+
/* list of listening sockets */
typedef struct lsock_rec_s
{
int socket;
- struct sockaddr_in sin;
+ struct sockaddr_storage sas;
+ struct addrinfo ai;
struct lsock_rec_s *next;
io_log_name *ldev; /* listening device record */
} lsock_rec;
@@ -55,8 +59,8 @@ int iotcp_getlsock(io_log_name *dev)
tcpptr = (d_tcp_struct *)dev->iod->dev_sp;
for (ls = lsock_list; ls != NULL; ls = ls->next)
- if (tcpptr->sin.sin_addr.s_addr == ls->sin.sin_addr.s_addr && tcpptr->sin.sin_port == ls->sin.sin_port)
- return ls->socket;
+ if (0 == memcmp(&(tcpptr->sas), &(ls->sas), SIZEOF(tcpptr->sas)))
+ return ls->socket;
return iotcp_newlsock(dev, tcpptr);
}
@@ -76,20 +80,16 @@ int iotcp_newlsock(io_log_name *dev, d_tcp_struct *tcpptr)
char *errptr;
int4 errlen;
- error_def(ERR_SOCKINIT);
- error_def(ERR_TEXT);
-
-
#ifdef DEBUG_TCP
PRINTF("iotcp_newlsock ---\n");
#endif
- lsock = tcp_routines.aa_socket(AF_INET, SOCK_STREAM, 0);
+ lsock = tcp_routines.aa_socket(tcpptr->ai.ai_family, tcpptr->ai.ai_socktype, tcpptr->ai.ai_protocol);
if (lsock == -1)
{
errptr = (char *)STRERROR(errno);
errlen = STRLEN(errptr);
- rts_error(VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr);
return 0;
}
@@ -99,16 +99,16 @@ int iotcp_newlsock(io_log_name *dev, d_tcp_struct *tcpptr)
errptr = (char *)STRERROR(errno);
errlen = STRLEN(errptr);
(void)tcp_routines.aa_close(lsock);
- rts_error(VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr);
return 0;
}
- if (tcp_routines.aa_bind(lsock, (struct sockaddr *)&tcpptr->sin, SIZEOF(struct sockaddr)) == -1)
+ if (-1 == tcp_routines.aa_bind(lsock, tcpptr->ai.ai_addr, tcpptr->ai.ai_addrlen))
{
errptr = (char *)STRERROR(errno);
errlen = STRLEN(errptr);
(void)tcp_routines.aa_close(lsock);
- rts_error(VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr);
return 0;
}
@@ -118,7 +118,7 @@ int iotcp_newlsock(io_log_name *dev, d_tcp_struct *tcpptr)
errptr = (char *)STRERROR(errno);
errlen = STRLEN(errptr);
(void)tcp_routines.aa_close(lsock);
- rts_error(VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr);
return 0;
}
@@ -154,7 +154,9 @@ int iotcp_newlsock(io_log_name *dev, d_tcp_struct *tcpptr)
/* add to our list of tcp listening sockets */
new_lsock = (lsock_rec *)malloc(SIZEOF(lsock_rec));
new_lsock->socket = lsock;
- new_lsock->sin = tcpptr->sin;
+ new_lsock->ai = tcpptr->ai;
+ new_lsock->sas = tcpptr->sas;
+ new_lsock->ai.ai_addr = (struct sockaddr *)(&new_lsock->sas);
new_lsock->next = lsock_list;
new_lsock->ldev = ldev;
lsock_list = new_lsock;
@@ -171,7 +173,11 @@ void iotcp_rmlsock(io_desc *iod)
for (prev = NULL, ls = lsock_list; ls != NULL;)
{
next = ls->next;
- if (tcpptr->sin.sin_port == ls->sin.sin_port)
+ /* Actually it's enough to just compare the port number, however extracting port from
+ * sas needs to call getnameinfo(). Same sas can guarantee the same port, so
+ * it's enough to use sas to detect whether the device is what we want to delete
+ */
+ if (0 == memcmp(&(tcpptr->sas), &(ls->sas), SIZEOF(tcpptr->sas)))
{
if (prev)
prev->next = ls->next;
diff --git a/sr_port/iotcp_name2ip.c b/sr_port/iotcp_name2ip.c
deleted file mode 100644
index 2bb36a7..0000000
--- a/sr_port/iotcp_name2ip.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/****************************************************************
- * *
- * Copyright 2001, 2006 Fidelity Information Services, Inc *
- * *
- * This source code contains the intellectual property *
- * of its copyright holder(s), and is made available *
- * under a license. If you do not know the terms of *
- * the license, please stop and do not read further. *
- * *
- ****************************************************************/
-
-/* iotcp_name2ip.c - convert a host name to its ip address
- *
- * Parameters-
- * name - the pointer to the string of hostname.
- *
- * Returns-
- * ip - the pointer to the string of ip address.
- * NULL - convert operation failed, host not reachable.
- */
-
-#include "mdef.h"
-
-#include "gtm_socket.h"
-#include "gtm_netdb.h"
-#include "gtm_inet.h"
-#include "gtm_stdio.h"
-#include "io.h"
-
-char *iotcp_name2ip(char *name)
-{ /* only ASCII range characters allowed in hostnames, we are not using libidn to resolve hostnames that might have international
- characters in their name */
-
- struct hostent *host_ptr;
-
- if (NULL == (host_ptr = GETHOSTBYNAME(name)))
- return NULL;
- return INET_NTOA(*((struct in_addr *)host_ptr->h_addr_list[0]));
-}
diff --git a/sr_port/iotcp_open.c b/sr_port/iotcp_open.c
index 31bc10a..262bd15 100644
--- a/sr_port/iotcp_open.c
+++ b/sr_port/iotcp_open.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -27,11 +27,12 @@
#include "gtm_fcntl.h"
#include "gtm_time.h"
#include "gtm_socket.h"
+#include "gtm_netdb.h" /* gtm_netdb must be in front so that AI_V4MAPPED will be defined */
+#include "gtm_ipv6.h"
#include "gtm_inet.h"
#include "gtm_ctype.h"
#include "gtm_string.h"
#include "gtm_stdio.h"
-#include "gtm_netdb.h"
#include "copy.h"
#include "gt_timer.h"
@@ -45,25 +46,32 @@
#include "stringpool.h"
#include "outofband.h"
#include "wake_alarm.h"
-
-#ifdef __osf__
-/* Tru64 does not have the prototype for "hstrerror" even though the function is available in the library.
- * Until we revamp the TCP communications setup stuff to use the new(er) POSIX definitions, we cannot move
- * away from "hstrerror". Declare prototype for this function in Tru64 manually until then.
- */
-const char *hstrerror(int err);
-#endif
+#include "util.h"
GBLREF tcp_library_struct tcp_routines;
GBLREF bool out_of_time;
GBLREF volatile int4 outofband;
LITREF unsigned char io_params_size[];
+error_def(ERR_DEVPARMNEG);
+error_def(ERR_GETADDRINFO);
+error_def(ERR_GETNAMEINFO);
+error_def(ERR_INVADDRSPEC);
+error_def(ERR_INVPORTSPEC);
+error_def(ERR_IPADDRREQ);
+error_def(ERR_OPENCONN);
+error_def(ERR_SOCKACPT);
+error_def(ERR_SOCKINIT);
+error_def(ERR_SOCKPARMREQ);
+error_def(ERR_SOCKWAIT);
+error_def(ERR_TEXT);
+
short iotcp_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 timeout)
{
boolean_t no_time_left = FALSE, timed;
- char addr[SA_MAXLEN+1], *errptr, sockaddr[SA_MAXLEN+1],
- temp_addr[SA_MAXLEN+1], temp_ch, *adptr;
+ char addr[SA_MAXLEN + 1], *errptr, sockaddr[SA_MAXLEN + 1],
+ temp_addr[SA_MAXLEN + 1], temp_ch;
+ char ipname[SA_MAXLEN];
unsigned char ch, len;
int4 length, width;
unsigned short port;
@@ -77,22 +85,18 @@ short iotcp_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 ti
ABS_TIME cur_time, end_time, time_for_read, lcl_time_for_read;
d_tcp_struct *tcpptr, newtcp;
io_desc *ioptr;
- struct sockaddr_in peer; /* socket address + port */
+ struct sockaddr_storage peer_sas; /* socket address + port */
fd_set tcp_fd;
int lsock;
short retry_num;
const char *terrptr;
-
- error_def(ERR_DEVPARMNEG);
- error_def(ERR_INVADDRSPEC);
- error_def(ERR_INVPORTSPEC);
- error_def(ERR_IPADDRREQ);
- error_def(ERR_OPENCONN);
- error_def(ERR_SOCKACPT);
- error_def(ERR_SOCKINIT);
- error_def(ERR_SOCKPARMREQ);
- error_def(ERR_SOCKWAIT);
- error_def(ERR_TEXT);
+ int errcode;
+ char port_buffer[NI_MAXSERV];
+ int port_len;
+ struct addrinfo *ai_ptr = NULL, *remote_ai_ptr = NULL, *tmp_ai_ptr, hints;
+ int host_len; /* addr_len + port_len + delimeters */
+ int af;
+ int test_ipv6_sd;
#ifdef DEBUG_TCP
PRINTF("iotcp_open.c >>> tt = %d\n", t);
@@ -119,7 +123,7 @@ short iotcp_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 ti
}
ioptr->dollar.zeof = FALSE;
newtcp = *tcpptr;
- memcpy(newtcp.dollar_device, LITZERO, SIZEOF(LITZERO));
+ memcpy(ioptr->dollar.device, LITZERO, SIZEOF(LITZERO));
newtcp.passive = FALSE;
while (iop_eol != *(pp->str.addr + p_offset))
{
@@ -132,7 +136,7 @@ short iotcp_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 ti
else if (width > 0)
newtcp.width = width;
else
- rts_error(VARLSTCNT(1) ERR_DEVPARMNEG);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DEVPARMNEG);
break;
case iop_length:
GET_LONG(length, pp->str.addr + p_offset);
@@ -141,62 +145,73 @@ short iotcp_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 ti
else if (length > 0)
newtcp.length = length;
else
- rts_error(VARLSTCNT(1) ERR_DEVPARMNEG);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DEVPARMNEG);
break;
case iop_listen:
newtcp.passive = TRUE;
break;
case iop_socket:
+ /* test whether ipv6 socket is supported on local system */
+ af = ((GTM_IPV6_SUPPORTED && !ipv4_only) ? AF_INET6 : AF_INET);
+ if (AF_INET6 == af)
+ {
+ test_ipv6_sd = tcp_routines.aa_socket(af, SOCK_STREAM, IPPROTO_TCP);
+ if (-1 == test_ipv6_sd)
+ af = AF_INET;
+ else
+ tcp_routines.aa_close(test_ipv6_sd);
+ }
len = *(pp->str.addr + p_offset);
- memset(sockaddr, 0, SA_MAXLEN+1);
- memcpy(sockaddr, pp->str.addr + p_offset + 1, (len <= SA_MAXLEN) ? len : SA_MAXLEN);
+ memset(sockaddr, 0, SA_MAXLEN + 1);
+ memcpy(sockaddr, pp->str.addr + p_offset + 1, (len <= USR_SA_MAXLITLEN) ? len : USR_SA_MAXLITLEN);
*temp_addr = '\0';
*addr = '\0';
port = 0;
if (SSCANF(sockaddr, "%[^,], %hu", temp_addr, &port) < 2)
{
- newtcp.sin.sin_addr.s_addr = INADDR_ANY;
if (SSCANF(sockaddr, ",%hu", &port) < 1)
{
- rts_error(VARLSTCNT(1) ERR_INVPORTSPEC);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVPORTSPEC);
return FALSE;
}
- } else
- {
- ii = 0;
- temp_ch = temp_addr[0];
- while(ISDIGIT_ASCII(temp_ch) || ('.' == temp_ch))
+ SERVER_HINTS(hints, af);
+ port_len = 0;
+ I2A(port_buffer, port_len, port);
+ port_buffer[port_len]='\0';
+ if (0 != (errcode = getaddrinfo(NULL, port_buffer, &hints, &ai_ptr)))
{
- ii++;
- temp_ch = temp_addr[ii];
+ RTS_ERROR_ADDRINFO(NULL, ERR_GETADDRINFO, errcode);
+ return FALSE;
}
+ memcpy(&(newtcp.ai), ai_ptr, SIZEOF(*ai_ptr));
+ memcpy(&(newtcp.sas), ai_ptr->ai_addr, ai_ptr->ai_addrlen);
+ freeaddrinfo(ai_ptr);
+ newtcp.ai.ai_addr = (struct sockaddr*)(&newtcp.sas);
- if ('\0' != temp_ch)
+ } else
+ { /* client side (connection side) */
+ SPRINTF(addr, "%s", temp_addr);
+ SPRINTF(port_buffer, "%hu", port);
+ CLIENT_HINTS_AF(hints, af);
+ if (0 != (errcode = getaddrinfo(addr, port_buffer, &hints, &remote_ai_ptr)))
{
- adptr = iotcp_name2ip(temp_addr);
- if (NULL == adptr)
+ if(AF_INET6 == af)
{
-#if !defined(__hpux) && !defined(__MVS__)
- terrptr = HSTRERROR(h_errno);
- rts_error(VARLSTCNT(6) ERR_INVADDRSPEC, 0, ERR_TEXT, 2, LEN_AND_STR(terrptr));
-#else
- /* Grumble grumble HPUX and z/OS don't have hstrerror() */
- rts_error(VARLSTCNT(1) ERR_INVADDRSPEC);
-#endif
+ af = AF_INET;
+ CLIENT_HINTS_AF(hints, af);
+ errcode = getaddrinfo(addr, port_buffer, &hints, &remote_ai_ptr);
+ }
+ if(errcode)
+ {
+ RTS_ERROR_ADDRINFO(NULL, ERR_GETADDRINFO, errcode);
return FALSE;
}
- SPRINTF(addr, "%s", adptr);
- } else
- SPRINTF(addr, "%s", temp_addr);
-
- if ((in_addr_t)-1 == (newtcp.sin.sin_addr.s_addr = tcp_routines.aa_inet_addr(addr)))
- {
- rts_error(VARLSTCNT(1) ERR_INVADDRSPEC);
- return FALSE;
}
+ memcpy(&(newtcp.ai), remote_ai_ptr, SIZEOF(struct addrinfo));
+ memcpy(&(newtcp.sas), remote_ai_ptr->ai_addr, remote_ai_ptr->ai_addrlen);
+ newtcp.ai.ai_addr = (struct sockaddr*)(&newtcp.sas);
+ freeaddrinfo(remote_ai_ptr);
}
- newtcp.sin.sin_port = GTM_HTONS(port);
- newtcp.sin.sin_family = AF_INET;
break;
case iop_exception:
ioptr->error_handler.len = *(pp->str.addr + p_offset);
@@ -209,163 +224,114 @@ short iotcp_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 ti
p_offset += ((IOP_VAR_SIZE == io_params_size[ch]) ?
(unsigned char)*(pp->str.addr + p_offset) + 1 : io_params_size[ch]);
}
- if ((0 == newtcp.sin.sin_port) && (0 == newtcp.sin.sin_addr.s_addr))
- {
- rts_error(VARLSTCNT(1) ERR_SOCKPARMREQ);
- return FALSE;
- }
+ /* the previous check if ((0 == newtcp.sin.sin_port) && (0 == newtcp.sin.sin_addr.s_addr)) is no longer needed as
+ * getaddrinfo() will return error for the above case
+ */
/* active connection must have a complete address specification */
- if ((INADDR_ANY == newtcp.sin.sin_addr.s_addr) && !newtcp.passive)
- {
- rts_error(VARLSTCNT(1) ERR_IPADDRREQ);
- return FALSE;
- }
if (dev_closed == ioptr->state)
{
- if (newtcp.passive) /* passive connection */
+ if (newtcp.passive) /* server side */
{
/* no listening socket for this addr? make one. */
memcpy(ioptr->dev_sp, &newtcp, SIZEOF(d_tcp_struct));
if (!(lsock = iotcp_getlsock(dev)))
return FALSE; /* could not create listening socket */
timer_id = (TID)iotcp_open;
- out_of_time = FALSE;
time_for_read.at_sec = ((0 == timeout) ? 0 : 1);
time_for_read.at_usec = 0;
- if (NO_M_TIMEOUT == timeout)
- {
- timed = FALSE;
- msec_timeout = NO_M_TIMEOUT;
- } else
- {
- timed = TRUE;
- msec_timeout = timeout2msec(timeout);
- if (msec_timeout > 0)
- { /* there is time to wait */
- sys_get_curr_time(&cur_time);
- add_int_to_abs_time(&cur_time, msec_timeout, &end_time);
- start_timer(timer_id, msec_timeout, wake_alarm, 0, NULL);
- } else
- out_of_time = TRUE;
- }
- for (status = 0; 0 == status; )
+ while (TRUE)
{
- FD_ZERO(&tcp_fd);
- FD_SET(lsock, &tcp_fd);
- /*
- * Note: the check for EINTR from the select below should remain, as aa_select is a
- * function, and not all callers of aa_select behave the same when EINTR is returned.
- */
- lcl_time_for_read = time_for_read;
- status = tcp_routines.aa_select(lsock + 1, (void *)&tcp_fd, (void *)0, (void *)0,
- &lcl_time_for_read);
- if (0 > status)
+ out_of_time = FALSE;
+ if (NO_M_TIMEOUT == timeout)
{
- if (EINTR == errno && FALSE == out_of_time)
- /* interrupted by a signal which is not OUR timer */
- status = 0;
- else
- break;
- }
- if (outofband)
- break;
- if (timed)
+ timed = FALSE;
+ msec_timeout = NO_M_TIMEOUT;
+ } else
{
+ timed = TRUE;
+ msec_timeout = timeout2msec(timeout);
if (msec_timeout > 0)
- {
+ { /* there is time to wait */
sys_get_curr_time(&cur_time);
- cur_time = sub_abs_time(&end_time, &cur_time);
- if (cur_time.at_sec <= 0)
- {
- out_of_time = TRUE;
- cancel_timer(timer_id);
- break;
- }
+ add_int_to_abs_time(&cur_time, msec_timeout, &end_time);
+ start_timer(timer_id, msec_timeout, wake_alarm, 0, NULL);
} else
- break;
- }
- }
- if (timed)
- {
- if (0 != msec_timeout)
- {
- cancel_timer(timer_id);
- if (out_of_time || outofband)
- return FALSE;
- /*if (outofband)
- outofband_action(FALSE);*/
+ out_of_time = TRUE;
}
- }
- if (0 > status)
- {
- errptr = (char *)STRERROR(errno);
- errlen = STRLEN(errptr);
- iotcp_rmlsock((io_desc *)dev->iod);
- rts_error(VARLSTCNT(6) ERR_SOCKWAIT, 0, ERR_TEXT, 2, errlen, errptr);
- return FALSE;
- }
- size = SIZEOF(struct sockaddr_in);
- status = tcp_routines.aa_accept(lsock, &peer, &size);
- if (-1 == status)
- {
-#ifdef __hpux
- /*ENOBUFS in HP-UX is either because of a memory problem or when we have received a RST just
- after a SYN before an accept call. Normally this is not fatal and is just a transient state.
- Hence exiting just after a single error of this kind should not be done.
- So retry in case of HP-UX and ENOBUFS error.*/
- if (ENOBUFS == errno)
+ for (status = 0; 0 == status; )
{
- retry_num = 0;
- while (HPUX_MAX_RETRIES > retry_num)
+ FD_ZERO(&tcp_fd);
+ FD_SET(lsock, &tcp_fd);
+ /*
+ * Note: the check for EINTR from the select below should remain, as aa_select is a
+ * function, and not all callers of aa_select behave the same when EINTR is returned.
+ */
+ lcl_time_for_read = time_for_read;
+ status = tcp_routines.aa_select(lsock + 1, (void *)&tcp_fd, (void *)0, (void *)0,
+ &lcl_time_for_read);
+ if (0 > status)
+ {
+ if (EINTR == errno && FALSE == out_of_time)
+ /* interrupted by a signal which is not OUR timer */
+ status = 0;
+ else
+ break;
+ }
+ if (outofband)
+ break;
+ if (timed)
{
- /*In case of succeeding with select in first go, accept will still get 5ms time difference*/
- SHORT_SLEEP(5);
- for ( ; HPUX_MAX_RETRIES > retry_num; retry_num++)
+ if (msec_timeout > 0)
{
- lcl_time_for_read.at_sec = 0;
- lcl_time_for_read.at_usec = HPUX_SEL_TIMEOUT;
- FD_ZERO(&tcp_fd);
- FD_SET(lsock, &tcp_fd);
- status = tcp_routines.aa_select(lsock + 1, (void *)&tcp_fd, (void *)0,
- (void *)0, &lcl_time_for_read);
- if (0 < status)
+ sys_get_curr_time(&cur_time);
+ cur_time = sub_abs_time(&end_time, &cur_time);
+ if (cur_time.at_sec <= 0)
+ {
+ out_of_time = TRUE;
+ cancel_timer(timer_id);
break;
- else if (outofband)
- break;
- else
- SHORT_SLEEP(5);
- }
- if (outofband)
- return FALSE;
- if (0 >= status)
- {
- errptr = (char *)STRERROR(errno);
- errlen = STRLEN(errptr);
- iotcp_rmlsock((io_desc *)dev->iod);
- rts_error(VARLSTCNT(6) ERR_SOCKWAIT, 0, ERR_TEXT, 2, errlen, errptr);
- return FALSE;
- }
- status = tcp_routines.aa_accept(lsock, &peer, &size);
- if ((-1 == status) && (ENOBUFS == errno))
- retry_num++;
- else
+ }
+ } else
break;
}
}
+ if (timed)
+ {
+ if (0 != msec_timeout)
+ {
+ cancel_timer(timer_id);
+ if (out_of_time || outofband)
+ return FALSE;
+ /*if (outofband)
+ outofband_action(FALSE);*/
+ }
+ }
+ if (0 > status)
+ {
+ errptr = (char *)STRERROR(errno);
+ errlen = STRLEN(errptr);
+ iotcp_rmlsock((io_desc *)dev->iod);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_SOCKWAIT, 0, ERR_TEXT, 2, errlen, errptr);
+ return FALSE;
+ }
+ size = SIZEOF(struct sockaddr_storage);
+ status = tcp_routines.aa_accept(lsock, (struct sockaddr*)&peer_sas, &size);
if (-1 == status)
-#endif
{
+# ifdef __hpux
+ if (ENOBUFS == errno)
+ continue;
+# endif
errptr = (char *)STRERROR(errno);
errlen = STRLEN(errptr);
iotcp_rmlsock((io_desc *)dev->iod);
- rts_error(VARLSTCNT(6) ERR_SOCKACPT, 0, ERR_TEXT, 2, errlen, errptr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_SOCKACPT, 0, ERR_TEXT, 2, errlen, errptr);
return FALSE;
}
+ newtcp.socket = status;
+ break;
}
- SPRINTF(newtcp.saddr, "%s,%d", tcp_routines.aa_inet_ntoa(peer.sin_addr),
- GTM_NTOHS(newtcp.sin.sin_port));
- newtcp.socket = status;
- } else /* active connection */
+ } else /* client side */
{
if (NO_M_TIMEOUT != timeout)
{
@@ -377,14 +343,15 @@ short iotcp_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 ti
temp_1 = 1;
do
{
- if(1 != temp_1)
+ if (1 != temp_1)
tcp_routines.aa_close(newtcp.socket);
- newtcp.socket = tcp_routines.aa_socket(AF_INET, SOCK_STREAM, 0);
+ newtcp.socket = tcp_routines.aa_socket(newtcp.ai.ai_family, newtcp.ai.ai_socktype,
+ newtcp.ai.ai_protocol);
if (-1 == newtcp.socket)
{
errptr = (char *)STRERROR(errno);
errlen = STRLEN(errptr);
- rts_error(VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr);
return FALSE;
}
/* allow multiple connections to the same IP address */
@@ -393,7 +360,7 @@ short iotcp_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 ti
(void)tcp_routines.aa_close(newtcp.socket);
errptr = (char *)STRERROR(errno);
errlen = STRLEN(errptr);
- rts_error(VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr);
return FALSE;
}
size=SIZEOF(newtcp.bufsiz);
@@ -402,20 +369,21 @@ short iotcp_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 ti
(void)tcp_routines.aa_close(newtcp.socket);
errptr = (char *)STRERROR(errno);
errlen = STRLEN(errptr);
- rts_error(VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, errno, errlen, errptr);
return FALSE;
}
/*
* Note: the check for EINTR from the connect need not be converted to an EINTR wrapper macro,
* since the connect is not retried on EINTR.
*/
- temp_1 = tcp_routines.aa_connect(newtcp.socket, (struct sockaddr *)&newtcp.sin, SIZEOF(newtcp.sin));
+ temp_1 = tcp_routines.aa_connect(newtcp.socket, (struct sockaddr *)&newtcp.sas,
+ newtcp.ai.ai_addrlen);
if ((temp_1 < 0) && (ECONNREFUSED != errno) && (EINTR != errno))
{
(void)tcp_routines.aa_close(newtcp.socket);
errptr = (char *)STRERROR(errno);
errlen = STRLEN(errptr);
- rts_error(VARLSTCNT(6) ERR_OPENCONN, 0, ERR_TEXT, 2, errlen, errptr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_OPENCONN, 0, ERR_TEXT, 2, errlen, errptr);
return FALSE;
}
if ((temp_1 < 0) && (EINTR == errno))
@@ -438,13 +406,6 @@ short iotcp_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 ti
tcp_routines.aa_close(newtcp.socket);
return FALSE;
}
-#ifdef ntohs /* if it's a macro, use it instead of tcp_routines.aa_ntohs */
- SPRINTF(newtcp.saddr, "%s,%d", tcp_routines.aa_inet_ntoa(newtcp.sin.sin_addr),
- ntohs(newtcp.sin.sin_port));
-#else
- SPRINTF(newtcp.saddr, "%s,%d", tcp_routines.aa_inet_ntoa(newtcp.sin.sin_addr),
- tcp_routines.aa_ntohs(newtcp.sin.sin_port));
-#endif
}
memcpy(ioptr->dev_sp, &newtcp, SIZEOF(d_tcp_struct));
ioptr->state = dev_open;
diff --git a/sr_port/iotcp_readfl.c b/sr_port/iotcp_readfl.c
index 352644b..6bff9ad 100644
--- a/sr_port/iotcp_readfl.c
+++ b/sr_port/iotcp_readfl.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -41,6 +41,11 @@ GBLREF spdesc stringpool;
GBLREF tcp_library_struct tcp_routines;
GBLREF int4 outofband;
+error_def(ERR_IOEOF);
+error_def(ERR_TEXT);
+error_def(ERR_GETSOCKOPTERR);
+error_def(ERR_SETSOCKOPTERR);
+
int iotcp_readfl(mval *v, int4 width, int4 timeout)
/* 0 == width is a flag that the caller is read and the length is not actually fixed */
/* timeout in seconds */
@@ -59,11 +64,6 @@ int iotcp_readfl(mval *v, int4 width, int4 timeout)
char *errptr;
int4 errlen;
- error_def(ERR_IOEOF);
- error_def(ERR_TEXT);
- error_def(ERR_GETSOCKOPTERR);
- error_def(ERR_SETSOCKOPTERR);
-
#ifdef DEBUG_TCP
PRINTF("%s >>>\n", __FILE__);
#endif
@@ -114,7 +114,8 @@ int iotcp_readfl(mval *v, int4 width, int4 timeout)
{
save_errno = errno;
errptr = (char *)STRERROR(errno);
- rts_error(VARLSTCNT(7) ERR_GETSOCKOPTERR, 5, LEN_AND_LIT("F_GETFL FOR NON BLOCKING I/O"),
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_GETSOCKOPTERR, 5,
+ LEN_AND_LIT("F_GETFL FOR NON BLOCKING I/O"),
save_errno, LEN_AND_STR(errptr));
}
FCNTL3(tcpptr->socket, F_SETFL, flags & (~(O_NDELAY | O_NONBLOCK)), fcntl_res);
@@ -122,7 +123,8 @@ int iotcp_readfl(mval *v, int4 width, int4 timeout)
{
save_errno = errno;
errptr = (char *)STRERROR(errno);
- rts_error(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, LEN_AND_LIT("F_SETFL FOR NON BLOCKING I/O"),
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5,
+ LEN_AND_LIT("F_SETFL FOR NON BLOCKING I/O"),
save_errno, LEN_AND_STR(errptr));
}
#endif
@@ -213,7 +215,8 @@ int iotcp_readfl(mval *v, int4 width, int4 timeout)
{
save_errno = errno;
errptr = (char *)STRERROR(errno);
- rts_error(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5, LEN_AND_LIT("F_SETFL FOR RESTORING SOCKET OPTIONS"),
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5,
+ LEN_AND_LIT("F_SETFL FOR RESTORING SOCKET OPTIONS"),
save_errno, LEN_AND_STR(errptr));
}
errno = real_errno;
@@ -252,29 +255,29 @@ int iotcp_readfl(mval *v, int4 width, int4 timeout)
if (tcp_routines.aa_select(tcpptr->socket + 1, (void *)(tcpptr->urgent ? &tcp_fd : 0), (void *)0,
(void *)(tcpptr->urgent ? 0 : &tcp_fd), &zero) > 0)
{
- memcpy(tcpptr->dollar_device, "1,", len);
+ memcpy(io_ptr->dollar.device, "1,", len);
if (tcpptr->urgent)
{
- memcpy(&tcpptr->dollar_device[len], "No ",SIZEOF("No "));
+ memcpy(&io_ptr->dollar.device[len], "No ",SIZEOF("No "));
len += SIZEOF("No ") - 1;
}
- memcpy(&tcpptr->dollar_device[len], "Urgent Data", SIZEOF("Urgent Data"));
+ memcpy(&io_ptr->dollar.device[len], "Urgent Data", SIZEOF("Urgent Data"));
} else
*/
- memcpy(tcpptr->dollar_device, "0", SIZEOF("0"));
+ memcpy(io_ptr->dollar.device, "0", SIZEOF("0"));
} else
{ /* there's a significant problem */
if (0 == i)
io_ptr->dollar.x = 0;
io_ptr->dollar.za = 9;
- memcpy(tcpptr->dollar_device, "1,", len);
+ memcpy(io_ptr->dollar.device, "1,", len);
errptr = (char *)STRERROR(errno);
errlen = STRLEN(errptr);
- memcpy(&tcpptr->dollar_device[len], errptr, errlen);
+ memcpy(&io_ptr->dollar.device[len], errptr, errlen);
if (io_ptr->dollar.zeof || -1 == status || 0 < io_ptr->error_handler.len)
{
io_ptr->dollar.zeof = TRUE;
- rts_error(VARLSTCNT(6) ERR_IOEOF, 0, ERR_TEXT, 2, errlen, errptr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_IOEOF, 0, ERR_TEXT, 2, errlen, errptr);
} else
io_ptr->dollar.zeof = TRUE;
}
diff --git a/sr_port/iotcp_write.c b/sr_port/iotcp_write.c
index 7a301bb..a85ff9d 100644
--- a/sr_port/iotcp_write.c
+++ b/sr_port/iotcp_write.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -26,6 +26,9 @@
GBLREF io_pair io_curr_device;
GBLREF tcp_library_struct tcp_routines;
+error_def(ERR_SOCKWRITE);
+error_def(ERR_TEXT);
+
void iotcp_write(mstr *v)
{
io_desc *iod;
@@ -35,16 +38,13 @@ void iotcp_write(mstr *v)
char *errptr;
int4 errlen;
- error_def(ERR_SOCKWRITE);
- error_def(ERR_TEXT);
-
#ifdef DEBUG_TCP
PRINTF("%s >>>\n", __FILE__);
#endif
iod = io_curr_device.out;
tcpptr = (d_tcp_struct *)iod->dev_sp;
tcpptr->lastop = TCP_WRITE;
- memcpy(tcpptr->dollar_device, LITZERO, SIZEOF(LITZERO));
+ memcpy(iod->dollar.device, LITZERO, SIZEOF(LITZERO));
inlen = v->len;
outlen = iod->width - iod->dollar.x;
@@ -59,11 +59,11 @@ void iotcp_write(mstr *v)
if ((size = tcp_routines.aa_send(tcpptr->socket, out, outlen, (tcpptr->urgent ? MSG_OOB : 0))) == -1)
{
iod->dollar.za = 9;
- memcpy(tcpptr->dollar_device, LITONE_COMMA, SIZEOF(LITONE_COMMA));
+ memcpy(iod->dollar.device, LITONE_COMMA, SIZEOF(LITONE_COMMA));
errptr = (char *)STRERROR(errno);
errlen = STRLEN(errptr);
- memcpy(&tcpptr->dollar_device[SIZEOF(LITONE_COMMA) - 1], errptr, errlen);
- rts_error(VARLSTCNT(6) ERR_SOCKWRITE, 0, ERR_TEXT, 2, errlen, errptr);
+ memcpy(&iod->dollar.device[SIZEOF(LITONE_COMMA) - 1], errptr, errlen);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_SOCKWRITE, 0, ERR_TEXT, 2, errlen, errptr);
}
assert(size == outlen);
iod->dollar.x += size;
diff --git a/sr_port/iotcpdef.h b/sr_port/iotcpdef.h
index 9a49a83..f4e97a1 100644
--- a/sr_port/iotcpdef.h
+++ b/sr_port/iotcpdef.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -12,6 +12,8 @@
#ifndef __IOTCPDEF_H__
#define __IOTCPDEF_H__
#include "gtm_inet.h"
+#include "gtm_socket.h" /* for NI_MAXHOST */
+#include "gtm_netdb.h"
/* iotcpdef.h UNIX - TCP header file */
#define TCPDEF_WIDTH 255
@@ -21,9 +23,17 @@
#define TCP_WRITE 1
#define TCP_READ 2
-#define SA_MAXLEN 32 /* SIZEOF(123.567.901.345,78901) */
-#define SA_MAXLITLEN 128 /* maximun size of beowulf.sanchez.com */
-#define DD_BUFLEN 80
+#define SA_MAXLEN NI_MAXHOST /* NI_MAXHOST is 1025, large enough to hold any IPV6 address format
+ * e.g.(123:567:901:345:215:0:0:0)
+ */
+#define SA_MAXLITLEN NI_MAXHOST /* large enough to hold any host name, e.g.
+ * host name google: dfw06s16-in-x12.1e100.net
+ */
+#define USR_SA_MAXLITLEN 128 /* maximum size of host GTM user can specify
+ * the reason why the number is so small is because the host name size
+ * is stored as one byte in socket parameter list (refer to iosocket_use)
+ */
+
#ifdef VMS
#define VMS_MAX_TCP_IO_SIZE (64 * 1024 - 512) /* Hard limit for TCP send or recv size. On some implementations, the limit is
@@ -32,40 +42,34 @@
*/
#endif
-/*Definitions in case of ENOBUFs error in HPUX*/
-#ifdef __hpux
-#define HPUX_MAX_RETRIES 8
-#define HPUX_SEL_TIMEOUT (20 * 1000) /*20 milliseconds(reperesented in micro secs)*/
-#endif
-
-
-#define DOTCPSEND(SDESC, SBUFF, SBUFF_LEN, SFLAGS, RC) \
-{ \
- ssize_t gtmioStatus; \
- size_t gtmioBuffLen; \
- size_t gtmioChunk; \
- sm_uc_ptr_t gtmioBuff; \
- gtmioBuffLen = SBUFF_LEN; \
- gtmioBuff = (sm_uc_ptr_t)(SBUFF); \
- for (;;) \
- { \
+#define DOTCPSEND(SDESC, SBUFF, SBUFF_LEN, SFLAGS, RC) \
+{ \
+ ssize_t gtmioStatus; \
+ size_t gtmioBuffLen; \
+ size_t gtmioChunk; \
+ sm_uc_ptr_t gtmioBuff; \
+ \
+ gtmioBuffLen = SBUFF_LEN; \
+ gtmioBuff = (sm_uc_ptr_t)(SBUFF); \
+ for (;;) \
+ { \
gtmioChunk = gtmioBuffLen VMS_ONLY(> VMS_MAX_TCP_IO_SIZE ? VMS_MAX_TCP_IO_SIZE : gtmioBuffLen); \
- if ((ssize_t)-1 != (gtmioStatus = tcp_routines.aa_send(SDESC, gtmioBuff, gtmioChunk, SFLAGS))) \
- { \
- gtmioBuffLen -= gtmioStatus; \
- if (0 == gtmioBuffLen) \
- break; \
- gtmioBuff += gtmioStatus; \
- } \
- else if (EINTR != errno) \
- break; \
- } \
- if ((ssize_t)-1 == gtmioStatus) /* Had legitimate error - return it */ \
- RC = errno; \
- else if (0 == gtmioBuffLen) \
- RC = 0; \
- else \
- RC = -1; /* Something kept us from sending what we wanted */ \
+ if ((ssize_t)-1 != (gtmioStatus = tcp_routines.aa_send(SDESC, gtmioBuff, gtmioChunk, SFLAGS))) \
+ { \
+ gtmioBuffLen -= gtmioStatus; \
+ if (0 == gtmioBuffLen) \
+ break; \
+ gtmioBuff += gtmioStatus; \
+ } \
+ else if (EINTR != errno) \
+ break; \
+ } \
+ if ((ssize_t)-1 == gtmioStatus) /* Had legitimate error - return it */ \
+ RC = errno; \
+ else if (0 == gtmioBuffLen) \
+ RC = 0; \
+ else \
+ RC = -1; /* Something kept us from sending what we wanted */ \
}
/* ***************************************************** */
@@ -75,8 +79,8 @@
typedef struct
{
char saddr[SA_MAXLEN]; /* socket address */
- char dollar_device[DD_BUFLEN];
- struct sockaddr_in sin; /* socket address + port */
+ struct sockaddr_storage sas; /* socket address + port */
+ struct addrinfo ai;
unsigned char lastop;
int bufsiz; /* OS internal buffer size */
int socket; /* socket descriptor */
@@ -84,20 +88,6 @@ typedef struct
int4 length;
bool passive; /* passive connection */
bool urgent; /* urgent data mode */
-}d_tcp_struct; /* tcp */
-
-/* if ntohs/htons are macros, use them, otherwise, use the tcp_routines */
-
-#define MAX_DELIM_BUFF 64
-#ifdef ntohs
-# define GTM_NTOHS ntohs
-#else
-# define GTM_NTOHS tcp_routines.aa_ntohs
-#endif
-#ifdef htons
-# define GTM_HTONS htons
-#else
-# define GTM_HTONS tcp_routines.aa_htons
-#endif
+} d_tcp_struct; /* tcp */
#endif
diff --git a/sr_port/iotcproutine.h b/sr_port/iotcproutine.h
index a79763b..1cd0d9a 100644
--- a/sr_port/iotcproutine.h
+++ b/sr_port/iotcproutine.h
@@ -1,40 +1,30 @@
/****************************************************************
- * *
- * Copyright 2001, 2005 Fidelity Information Services, Inc *
- * *
- * This source code contains the intellectual property *
- * of its copyright holder(s), and is made available *
- * under a license. If you do not know the terms of *
- * the license, please stop and do not read further. *
- * *
- ****************************************************************/
+* *
+* Copyright 2001, 2013 Fidelity Information Services, Inc *
+* *
+* This source code contains the intellectual property *
+* of its copyright holder(s), and is made available *
+* under a license. If you do not know the terms of *
+* the license, please stop and do not read further. *
+* *
+****************************************************************/
/* pointers for tcp/ip routines */
typedef struct
{
- int (*aa_accept)();
- int (*aa_bind)();
- int (*aa_close)();
- int (*aa_connect)();
- int (*aa_getsockopt)();
+ int (*aa_accept)();
+ int (*aa_bind)();
+ int (*aa_close)();
+ int (*aa_connect)();
+ int (*aa_getsockopt)();
int (*aa_getsockname)();
- unsigned short (*aa_htons)(in_port_t);
-/* smw 1999/12/15 STDC is not a good flag to use so why is it here
- perhaps should define in_addr_t somewhere if needed. */
-#if !defined(__STDC__)
- uint4 (*aa_inet_addr)();
-#else
- in_addr_t (*aa_inet_addr)(const char *);
-#endif
- char *(*aa_inet_ntoa)();
- unsigned short (*aa_ntohs)(in_port_t);
- int (*aa_listen)();
- int (*aa_recv)();
- int (*aa_select)();
- int (*aa_send)();
- int (*aa_setsockopt)();
- int (*aa_shutdown)();
- int (*aa_socket)();
- bool using_tcpware; /* use tcpware(1) or ucx(0) */
+ int (*aa_listen)();
+ int (*aa_recv)();
+ int (*aa_select)();
+ int (*aa_send)();
+ int (*aa_setsockopt)();
+ int (*aa_shutdown)();
+ int (*aa_socket)();
+ bool using_tcpware; /* use tcpware(1) or ucx(0) */
}tcp_library_struct;
diff --git a/sr_port/jnl.h b/sr_port/jnl.h
index e2eabd7..cce76cc 100644
--- a/sr_port/jnl.h
+++ b/sr_port/jnl.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -139,7 +139,9 @@ error_def(ERR_JNLENDIANLITTLE);
#endif
/* one more disk-block for PBLK record header/footer */
#define MAX_JNL_REC_SIZE (MAX_LOGI_JNL_REC_SIZE + DISK_BLOCK_SIZE)
-#define MAX_PHY_JNL_REC_SIZE(csd) (csd->blk_size + DISK_BLOCK_SIZE)
+/* Very large records require spanning nodes, which only happen in TP. */
+#define MAX_NONTP_JNL_REC_SIZE(BSIZE) ((BSIZE) + DISK_BLOCK_SIZE)
+#define MAX_MAX_NONTP_JNL_REC_SIZE MAX_NONTP_JNL_REC_SIZE(MAX_DB_BLK_SIZE)
#ifdef GTM_TRIGGER
/* Define maximum size that $ZTWORMHOLE can be. Since $ZTWORMHOLE should be able to fit in a journal record and the
@@ -762,13 +764,13 @@ typedef struct jnl_format_buff_struct
# endif
enum jnl_record_type rectype;
int4 record_size;
+ int4 hi_water_bsize;
char *buff;
uint4 checksum;
jnl_action ja;
# ifdef GTM_CRYPT
char *alt_buff; /* for storing the unencrypted jnl *SET and *KILL records to be pushed
* into the jnl pool. */
- NON_GTM64_ONLY(int4 dummy_filler;) /* for alignment in 32 bit machines. */
# endif
} jnl_format_buffer;
@@ -1215,10 +1217,11 @@ typedef struct
* But to write it out, we should have it already built before bg_update().
* Hence, we pre-build the block here itself before invoking t_end().
*/
-#define BUILD_AIMG_IF_JNL_ENABLED(CSD, JFB, TN) \
+#define BUILD_AIMG_IF_JNL_ENABLED(CSD, TN) \
{ \
GBLREF cw_set_element cw_set[]; \
GBLREF unsigned char cw_set_depth; \
+ GBLREF jnl_format_buffer *non_tp_jfb_ptr; \
\
cw_set_element *cse; \
\
@@ -1226,7 +1229,7 @@ typedef struct
{ \
assert(1 == cw_set_depth); /* Only DSE uses this macro and it updates one block at a time */ \
cse = (cw_set_element *)(&cw_set[0]); \
- cse->new_buff = JFB; \
+ cse->new_buff = (unsigned char *)non_tp_jfb_ptr->buff; \
gvcst_blk_build(cse, (uchar_ptr_t)cse->new_buff, TN); \
cse->done = TRUE; \
} \
@@ -1305,19 +1308,19 @@ typedef struct
#define ASSERT_JNLFILEID_NOT_NULL(csa) assert(0 != memcmp(csa->nl->jnl_file.jnl_file_id.fid, zero_fid, SIZEOF(zero_fid)));
#define NULLIFY_JNL_FILE_ID(csa) memset(&csa->nl->jnl_file.jnl_file_id, 0, SIZEOF(gds_file_id))
#endif
-#define JNL_INIT(csa, reg, csd) \
-{ \
- csa->jnl_state = csd->jnl_state; \
- csa->jnl_before_image = csd->jnl_before_image; \
- csa->repl_state = csd->repl_state; \
- if JNL_ALLOWED(csa) \
- { \
- JPC_ALLOC(csa); \
- csa->jnl->region = reg; \
- csa->jnl->jnl_buff = (jnl_buffer_ptr_t)((sm_uc_ptr_t)(csa->nl) + NODE_LOCAL_SPACE + JNL_NAME_EXP_SIZE); \
- csa->jnl->channel = NOJNL; \
- } else \
- csa->jnl = NULL; \
+#define JNL_INIT(csa, reg, csd) \
+{ \
+ csa->jnl_state = csd->jnl_state; \
+ csa->jnl_before_image = csd->jnl_before_image; \
+ csa->repl_state = csd->repl_state; \
+ if JNL_ALLOWED(csa) \
+ { \
+ JPC_ALLOC(csa); \
+ csa->jnl->region = reg; \
+ csa->jnl->jnl_buff = (jnl_buffer_ptr_t)((sm_uc_ptr_t)(csa->nl) + NODE_LOCAL_SPACE(csd) + JNL_NAME_EXP_SIZE); \
+ csa->jnl->channel = NOJNL; \
+ } else \
+ csa->jnl = NULL; \
}
#define JNL_FD_CLOSE(CHANNEL, RC) \
{ \
@@ -1435,6 +1438,13 @@ typedef struct
DEST = jnl_buffer_adj_value; \
}
+#ifdef UNIX
+# define CURRENT_JNL_IO_WRITER(JB) JB->io_in_prog_latch.u.parts.latch_pid
+# define CURRENT_JNL_FSYNC_WRITER(JB) JB->fsync_in_prog_latch.u.parts.latch_pid
+#else
+# define CURRENT_JNL_IO_WRITER(JB) JB->now_writer
+#endif
+
/* jnl_ prototypes */
uint4 jnl_file_extend(jnl_private_control *jpc, uint4 total_jnl_rec_size);
uint4 jnl_file_lost(jnl_private_control *jpc, uint4 jnl_stat);
diff --git a/sr_port/jnl_file_close.c b/sr_port/jnl_file_close.c
index d20ff63..46cb49f 100644
--- a/sr_port/jnl_file_close.c
+++ b/sr_port/jnl_file_close.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2003, 2012 Fidelity Information Services, Inc *
+ * Copyright 2003, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -113,11 +113,11 @@ void jnl_file_close(gd_region *reg, bool clean, bool dummy)
jnl_write_eof_rec(csa, &eof_record);
if (SS_NORMAL != (jpc->status = jnl_flush(reg)))
{
- send_msg(VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(csd),
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(csd),
ERR_TEXT, 2, RTS_ERROR_TEXT("Error with journal flush during jnl_file_close"),
jpc->status);
assert(FALSE);
- rts_error(VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(csd),
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(csd),
ERR_TEXT, 2, RTS_ERROR_TEXT("Error with journal flush during jnl_file_close"),
jpc->status);
}
@@ -154,17 +154,17 @@ void jnl_file_close(gd_region *reg, bool clean, bool dummy)
if (SYSCALL_ERROR(jpc->status))
{
assert(FALSE);
- rts_error(VARLSTCNT(5) ERR_JNLWRERR, 2, JNL_LEN_STR(csd), jpc->status);
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_JNLWRERR, 2, JNL_LEN_STR(csd), jpc->status);
}
UNIX_ONLY(
GTM_JNL_FSYNC(csa, jpc->channel, rc);
if (-1 == rc)
{
save_errno = errno;
- send_msg(VARLSTCNT(9) ERR_JNLFSYNCERR, 2, JNL_LEN_STR(csd),
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_JNLFSYNCERR, 2, JNL_LEN_STR(csd),
ERR_TEXT, 2, RTS_ERROR_TEXT("Error with fsync during jnl_file_close"), save_errno);
assert(FALSE);
- rts_error(VARLSTCNT(9) ERR_JNLFSYNCERR, 2, JNL_LEN_STR(csd),
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_JNLFSYNCERR, 2, JNL_LEN_STR(csd),
ERR_TEXT, 2, RTS_ERROR_TEXT("Error with fsync during jnl_file_close"), save_errno);
}
)
@@ -188,6 +188,6 @@ void jnl_file_close(gd_region *reg, bool clean, bool dummy)
{
status = jpc->status; /* jnl_send_oper resets jpc->status, so save it */
jnl_send_oper(jpc, ERR_JNLCLOSE);
- rts_error(VARLSTCNT(5) ERR_JNLCLOSE, 2, JNL_LEN_STR(csd), status);
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_JNLCLOSE, 2, JNL_LEN_STR(csd), status);
}
}
diff --git a/sr_port/jnl_file_lost.c b/sr_port/jnl_file_lost.c
index 045a9eb..41d348b 100644
--- a/sr_port/jnl_file_lost.c
+++ b/sr_port/jnl_file_lost.c
@@ -76,7 +76,7 @@ uint4 jnl_file_lost(jnl_private_control *jpc, uint4 jnl_stat)
*/
# endif
assert(csa->now_crit);
- /* We issue an rts_error (instead of shutting off journaling) in the following cases :
+ /* We issue an rts_error (instead of shutting off journaling) in the following cases : {BYPASSOK}
* 1) $gtm_error_on_jnl_file_lost is set to issue runtime error (if not already issued) in case of journaling issues.
* 2) The process has $gtm_custom_errors set (indicative of anticipatory freeze setup) in which case the goal is to
* never shut-off journaling
@@ -95,9 +95,11 @@ uint4 jnl_file_lost(jnl_private_control *jpc, uint4 jnl_stat)
csa->jnl->error_reported = TRUE;
in_wcs_recover = FALSE; /* in case we're called in wcs_recover() */
if (SS_NORMAL != jpc->status)
- rts_error(VARLSTCNT(7) jnl_stat, 4, JNL_LEN_STR(csa->hdr), DB_LEN_STR(gv_cur_region), jpc->status);
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(7) jnl_stat, 4, JNL_LEN_STR(csa->hdr),
+ DB_LEN_STR(gv_cur_region), jpc->status);
else
- rts_error(VARLSTCNT(6) jnl_stat, 4, JNL_LEN_STR(csa->hdr), DB_LEN_STR(gv_cur_region));
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(6) jnl_stat, 4, JNL_LEN_STR(csa->hdr),
+ DB_LEN_STR(gv_cur_region));
}
return jnl_stat;
}
@@ -111,9 +113,10 @@ uint4 jnl_file_lost(jnl_private_control *jpc, uint4 jnl_stat)
csa->hdr->repl_state = repl_was_open;
reg_seqno = csa->hdr->reg_seqno;
jnlseqno = (NULL != jnlpool.jnlpool_ctl) ? jnlpool.jnlpool_ctl->jnl_seqno : MAX_SEQNO;
- send_msg(VARLSTCNT(8) ERR_REPLJNLCLOSED, 6, DB_LEN_STR(jpc->region), ®_seqno, ®_seqno, &jnlseqno, &jnlseqno);
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_REPLJNLCLOSED, 6, DB_LEN_STR(jpc->region), ®_seqno, ®_seqno,
+ &jnlseqno, &jnlseqno);
} else
- send_msg(VARLSTCNT(5) ERR_JNLCLOSED, 3, DB_LEN_STR(jpc->region), &csa->ti->curr_tn);
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_JNLCLOSED, 3, DB_LEN_STR(jpc->region), &csa->ti->curr_tn);
#ifdef VMS
/* We can get a jnl_file_lost before the file is even created, so locking is done only if the lock exist */
if (0 != csa->jnl->jnllsb->lockid)
diff --git a/sr_port/jnl_file_open_common.c b/sr_port/jnl_file_open_common.c
index 2095da3..9ff0a4d 100644
--- a/sr_port/jnl_file_open_common.c
+++ b/sr_port/jnl_file_open_common.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2003, 2012 Fidelity Information Services, Inc *
+ * Copyright 2003, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -143,7 +143,7 @@ uint4 jnl_file_open_common(gd_region *reg, off_jnl_t os_file_size)
}
if (!is_gdid_file_identical(&FILE_ID(reg), (char *)header->data_file_name, header->data_file_name_length))
{
- rts_error(VARLSTCNT(7) ERR_JNLOPNERR, 4, JNL_LEN_STR(csd), DB_LEN_STR(reg), ERR_FILEIDMATCH);
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(7) ERR_JNLOPNERR, 4, JNL_LEN_STR(csd), DB_LEN_STR(reg), ERR_FILEIDMATCH);
assert(FALSE); /* we dont expect the rts_error in the line above to return */
return ERR_JNLOPNERR;
}
@@ -170,7 +170,7 @@ uint4 jnl_file_open_common(gd_region *reg, off_jnl_t os_file_size)
GTMCRYPT_ONLY(
if (memcmp(header->encryption_hash, csd->encryption_hash, GTMCRYPT_HASH_LEN))
{
- send_msg(VARLSTCNT(6) ERR_CRYPTJNLWRONGHASH, 4, JNL_LEN_STR(csd), DB_LEN_STR(reg));
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_CRYPTJNLWRONGHASH, 4, JNL_LEN_STR(csd), DB_LEN_STR(reg));
jpc->status = ERR_CRYPTJNLWRONGHASH;
return ERR_JNLOPNERR;
}
@@ -187,7 +187,7 @@ uint4 jnl_file_open_common(gd_region *reg, off_jnl_t os_file_size)
if ((ROUND_UP2((header_virtual_size * DISK_BLOCK_SIZE), jnl_fs_block_size) < os_file_size)
|| (header->jnl_deq && 0 != ((header_virtual_size - header->jnl_alq) % header->jnl_deq)))
{
- send_msg(VARLSTCNT(8) ERR_JNLVSIZE, 6, JNL_LEN_STR(csd), header->virtual_size,
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_JNLVSIZE, 6, JNL_LEN_STR(csd), header->virtual_size,
header->jnl_alq, header->jnl_deq, os_file_size, jnl_fs_block_size);
jpc->status = ERR_JNLVSIZE;
return ERR_JNLOPNERR;
@@ -202,8 +202,9 @@ uint4 jnl_file_open_common(gd_region *reg, off_jnl_t os_file_size)
VMS_ONLY(jb->buff_off = 0;)
jb->size = ROUND_DOWN2(csd->jnl_buffer_size * DISK_BLOCK_SIZE - jb->buff_off, jnl_fs_block_size);
/* Assert that journal buffer does NOT spill past the allocated journal buffer size in shared memory */
- assert((sm_uc_ptr_t)&jb->buff[jb->buff_off + jb->size] < ((sm_uc_ptr_t)csa->nl + NODE_LOCAL_SPACE + JNL_SHARE_SIZE(csd)));
- assert((sm_uc_ptr_t)jb == ((sm_uc_ptr_t)csa->nl + NODE_LOCAL_SPACE + JNL_NAME_EXP_SIZE));
+ assert((sm_uc_ptr_t)&jb->buff[jb->buff_off + jb->size] < ((sm_uc_ptr_t)csa->nl + NODE_LOCAL_SPACE(csd)
+ + JNL_SHARE_SIZE(csd)));
+ assert((sm_uc_ptr_t)jb == ((sm_uc_ptr_t)csa->nl + NODE_LOCAL_SPACE(csd) + JNL_NAME_EXP_SIZE));
jb->freeaddr = jb->dskaddr = UNIX_ONLY(jb->fsync_dskaddr = ) header->end_of_data;
jb->fs_block_size = jnl_fs_block_size;
/* The following is to make sure that the data in jnl_buffer is aligned with the data in the
@@ -256,7 +257,7 @@ uint4 jnl_file_open_common(gd_region *reg, off_jnl_t os_file_size)
JNL_DO_FILE_WRITE(csa, csd->jnl_file_name, jpc->channel, 0, header, read_write_size, jpc->status, jpc->status2);
if (SS_NORMAL != jpc->status)
{
- assert(FALSE);
+ assert(WBTEST_ENABLED(WBTEST_RECOVER_ENOSPC));
return ERR_JNLWRERR;
}
if (!jb->prev_jrec_time || !header->prev_jnl_file_name_length)
diff --git a/sr_port/jnl_file_open_switch.c b/sr_port/jnl_file_open_switch.c
index 976ea25..682f85c 100644
--- a/sr_port/jnl_file_open_switch.c
+++ b/sr_port/jnl_file_open_switch.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2003, 2011 Fidelity Information Services, Inc *
+ * Copyright 2003, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -25,6 +25,7 @@
#include "gtmio.h"
#include "repl_sp.h"
#include "iosp.h" /* for SS_NORMAL */
+#include "wbox_test_init.h"
GBLREF jnl_gbls_t jgbl;
@@ -54,7 +55,7 @@ uint4 jnl_file_open_switch(gd_region *reg, uint4 sts)
set_jnl_info(reg, &create);
create.no_prev_link = TRUE;
create.no_rename = FALSE;
- assert(!jgbl.forw_phase_recovery);
+ assert(!jgbl.forw_phase_recovery || WBTEST_ENABLED(WBTEST_RECOVER_ENOSPC));
if (!jgbl.dont_reset_gbl_jrec_time)
SET_GBL_JREC_TIME; /* needed for cre_jnl_file() */
/* else mur_output_record() would have already set jgbl.gbl_jrec_time */
@@ -70,7 +71,7 @@ uint4 jnl_file_open_switch(gd_region *reg, uint4 sts)
csa->hdr->jnl_checksum = create.checksum;
csa->hdr->jnl_eovtn = csa->hdr->trans_hist.curr_tn;
}
- send_msg(VARLSTCNT(6) ERR_PREVJNLLINKCUT, 4, JNL_LEN_STR(csa->hdr), DB_LEN_STR(reg));
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_PREVJNLLINKCUT, 4, JNL_LEN_STR(csa->hdr), DB_LEN_STR(reg));
assert(csa->hdr->jnl_file_len == create.jnl_len);
assert(0 == memcmp(csa->hdr->jnl_file_name, create.jnl, create.jnl_len));
return 0;
diff --git a/sr_port/jnl_send_oper.c b/sr_port/jnl_send_oper.c
index 492ca3b..324eff9 100644
--- a/sr_port/jnl_send_oper.c
+++ b/sr_port/jnl_send_oper.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2007 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -22,6 +22,7 @@
#include "error.h"
#include "send_msg.h"
#include "caller_id.h"
+#include "wbox_test_init.h"
#define ENOSPC_LOGGING_PERIOD 100 /* every 100th ENOSPC error is logged to avoid flooding the operator log */
@@ -53,8 +54,8 @@ void jnl_send_oper(jnl_private_control *jpc, uint4 status)
}
csd = csa->hdr;
jb = jpc->jnl_buff;
- UNIX_ONLY(assert((ENOSPC != jpc->status) || jb->enospc_errcnt);)
- UNIX_ONLY(assert((SS_NORMAL == jpc->status) || (ENOSPC == jpc->status) || !jb->enospc_errcnt);)
+ UNIX_ONLY(assert((ENOSPC != jpc->status) || jb->enospc_errcnt || WBTEST_ENABLED(WBTEST_RECOVER_ENOSPC)));
+ UNIX_ONLY(assert((SS_NORMAL == jpc->status) || (ENOSPC == jpc->status) || !jb->enospc_errcnt));
VMS_ONLY(assert(!jb->enospc_errcnt)); /* currently not updated in VMS, so should be 0 */
ok_to_log = (jb->enospc_errcnt ? (1 == (jb->enospc_errcnt % ENOSPC_LOGGING_PERIOD)) : TRUE);
diff --git a/sr_port/jnl_write_attempt.c b/sr_port/jnl_write_attempt.c
index 09fd809..bfb0381 100644
--- a/sr_port/jnl_write_attempt.c
+++ b/sr_port/jnl_write_attempt.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -48,21 +48,15 @@ GBLREF jnlpool_addrs jnlpool;
GBLREF pid_t process_id;
GBLREF uint4 image_count;
+error_def(ERR_JNLACCESS);
error_def(ERR_JNLCNTRL);
error_def(ERR_JNLFLUSH);
error_def(ERR_JNLFLUSHNOPROG);
error_def(ERR_JNLPROCSTUCK);
+error_def(ERR_JNLQIOSALVAGE);
error_def(ERR_JNLWRTDEFER);
error_def(ERR_JNLWRTNOWWRTR);
error_def(ERR_TEXT);
-error_def(ERR_JNLWRTDEFER);
-error_def(ERR_JNLWRTNOWWRTR);
-
-#ifdef VMS
-# define CURRENT_WRITER jb->now_writer
-#else
-# define CURRENT_WRITER jb->io_in_prog_latch.u.parts.latch_pid
-#endif
static uint4 jnl_sub_write_attempt(jnl_private_control *jpc, unsigned int *lcnt, uint4 threshold)
{
@@ -147,9 +141,9 @@ static uint4 jnl_sub_write_attempt(jnl_private_control *jpc, unsigned int *lcnt,
UNIX_ONLY(assert(ERR_JNLWRTNOWWRTR != status);) /* dont have asynchronous jnl writes in Unix */
if ((ERR_JNLWRTNOWWRTR != status) && (ERR_JNLWRTDEFER != status))
return status;
- if ((writer != CURRENT_WRITER) || (1 == *lcnt))
+ if ((writer != CURRENT_JNL_IO_WRITER(jb)) || (1 == *lcnt))
{
- writer = CURRENT_WRITER;
+ writer = CURRENT_JNL_IO_WRITER(jb);
loop_image_count = jb->image_count;
*lcnt = 1; /* !!! this should be detected and limited by the caller !!! */
break;
@@ -160,21 +154,19 @@ static uint4 jnl_sub_write_attempt(jnl_private_control *jpc, unsigned int *lcnt,
break;
}
VMS_ONLY(
- if ((CURRENT_WRITER == process_id) && (jpc->qio_active == TRUE) && (jb->iosb.cond == -2))
+ if ((CURRENT_JNL_IO_WRITER(jb) == process_id) && (jpc->qio_active == TRUE) && (jb->iosb.cond == -2))
{ /* this an "impossible" condition where the private flag and the io have lost sync */
GTMASSERT; /* this should only occur in VMS; secshr_db_clnup should clear the problem */
}
)
- if (writer == CURRENT_WRITER)
+ if (writer == CURRENT_JNL_IO_WRITER(jb))
{
if (!was_crit)
grab_crit(jpc->region); /* jnl_write_attempt has an assert about have_crit that this relies on */
if (VMS_ONLY(0 == writer ||) FALSE == is_proc_alive(writer, jb->image_count))
{ /* no one home, clear the semaphore; */
BG_TRACE_PRO_ANY(csa, jnl_blocked_writer_lost);
- jnl_send_oper(jpc, ERR_JNLFLUSH);
- send_msg(VARLSTCNT(3) ERR_JNLPROCSTUCK, 1, writer);
- send_msg(VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_LIT("Journal IO writer changed during wait"));
+ jnl_send_oper(jpc, ERR_JNLQIOSALVAGE);
VMS_ONLY(jb->io_in_prog = 0);
UNIX_ONLY(COMPSWAP_UNLOCK(&jb->io_in_prog_latch, writer, jb->image_count, LOCK_AVAILABLE, 0));
if (!was_crit)
@@ -188,7 +180,7 @@ static uint4 jnl_sub_write_attempt(jnl_private_control *jpc, unsigned int *lcnt,
BG_TRACE_PRO_ANY(csa, jnl_blocked_writer_stuck);
jpc->status = status;
jnl_send_oper(jpc, ERR_JNLFLUSH);
- send_msg(VARLSTCNT(3) ERR_JNLPROCSTUCK, 1, writer);
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(3) ERR_JNLPROCSTUCK, 1, writer);
stuck_cnt++;
GET_C_STACK_FROM_SCRIPT("JNLPROCSTUCK", process_id, writer, stuck_cnt);
*lcnt = 1; /* ??? is it necessary to limit this, and if so, how ??? */
@@ -212,7 +204,7 @@ static uint4 jnl_sub_write_attempt(jnl_private_control *jpc, unsigned int *lcnt,
uint4 jnl_write_attempt(jnl_private_control *jpc, uint4 threshold)
{
jnl_buffer_ptr_t jb;
- unsigned int lcnt, prev_lcnt, cnt, proc_stuck_cnt;
+ unsigned int lcnt, prev_lcnt, cnt;
sgmnt_addrs *csa;
unsigned int status;
boolean_t was_crit, jnlfile_lost, exact_check;
@@ -237,7 +229,7 @@ uint4 jnl_write_attempt(jnl_private_control *jpc, uint4 threshold)
* the grab_crit calls (done in jnl_write_attempt and jnl_sub_write_attempt) to ensure no deadlocks are possible.
*/
assert(was_crit || (0 == have_crit(CRIT_HAVE_ANY_REG)));
- for (prev_lcnt = lcnt = cnt = 1, proc_stuck_cnt = 0;
+ for (prev_lcnt = lcnt = cnt = 1;
(was_crit || (NOJNL != jpc->channel)) && (exact_check ? jb->dskaddr != threshold : jb->dskaddr < threshold);
lcnt++, prev_lcnt = lcnt, cnt++)
{
@@ -251,28 +243,19 @@ uint4 jnl_write_attempt(jnl_private_control *jpc, uint4 threshold)
}
if (SS_NORMAL == status)
{
- if (JNL_FLUSH_PROG_TRIES > lcnt)
- {
- proc_stuck_cnt = 0;
- /* In VMS, jnl writes are asynchronous. The above call to "jnl_sub_write_attempt" has returned
- * SS_NORMAL status. This means the jnl qio lock is not in use by anyone else and is up for grabs.
- * We would have scheduled a jnl qio write through a sys$dclast call. We have no control of when
- * the AST routine "jnl_start_ast" will actually get control and start the write. Until then
- * we dont want to keep reinvoking "jnl_sub_write_attempt" in a hard spin loop. So sleep.
- * In Unix, writes are synchronous so SS_NORMAL status return implies we have completed a jnl
- * write and "jb->dskaddr" is closer to "threshold" than it was in the previous iteration.
- * A sleep at this point will only slow things down unnecessarily. Hence no sleep if Unix.
- */
- VMS_ONLY(wcs_sleep(lcnt);)
- continue;
- }
- jpc->status = SS_NORMAL;
- jnl_send_oper(jpc, ERR_JNLFLUSH);
- send_msg(VARLSTCNT(8) ERR_JNLFLUSHNOPROG, 2, JNL_LEN_STR(csa->hdr),
- ERR_TEXT, 2, LEN_AND_LIT("Could not flush all the buffered journal data"));
- GTMASSERT; /* too many attempts to flush journal data */
+ /* In VMS, jnl writes are asynchronous. The above call to "jnl_sub_write_attempt" has returned
+ * SS_NORMAL status. This means the jnl qio lock is not in use by anyone else and is up for grabs.
+ * We would have scheduled a jnl qio write through a sys$dclast call. We have no control of when
+ * the AST routine "jnl_start_ast" will actually get control and start the write. Until then
+ * we dont want to keep reinvoking "jnl_sub_write_attempt" in a hard spin loop. So sleep.
+ * In Unix, writes are synchronous so SS_NORMAL status return implies we have completed a jnl
+ * write and "jb->dskaddr" is closer to "threshold" than it was in the previous iteration.
+ * A sleep at this point will only slow things down unnecessarily. Hence no sleep if Unix.
+ */
+ VMS_ONLY(wcs_sleep(lcnt);)
+ continue;
}
- if ((ERR_JNLCNTRL == status)
+ if ((ERR_JNLCNTRL == status) || (ERR_JNLACCESS == status)
|| (csa->now_crit
&& (ERR_JNLWRTDEFER != status) && (ERR_JNLWRTNOWWRTR != status) && (ERR_JNLPROCSTUCK != status)))
{ /* If JNLCNTRL or if holding crit and not waiting for some other writer (or self in VMS)
@@ -281,7 +264,10 @@ uint4 jnl_write_attempt(jnl_private_control *jpc, uint4 threshold)
if (was_crit)
jb->blocked = 0;
else
+ {
+ assertpro(0 == have_crit(CRIT_HAVE_ANY_REG));
grab_crit(jpc->region); /* jnl_write_attempt has an assert about have_crit that this relies on */
+ }
jnlfile_lost = FALSE;
if (jb->free_update_pid)
{
@@ -290,7 +276,7 @@ uint4 jnl_write_attempt(jnl_private_control *jpc, uint4 threshold)
{
assert((gtm_white_box_test_case_enabled
&& (WBTEST_JNL_FILE_LOST_DSKADDR == gtm_white_box_test_case_number))
- UNIX_ONLY(|| TREF(gtm_test_fake_enospc)));
+ UNIX_ONLY(|| TREF(gtm_test_fake_enospc) || WBTEST_ENABLED(WBTEST_RECOVER_ENOSPC)));
if (JNL_ENABLED(csa->hdr))
{ /* We ignore the return value of jnl_file_lost() since we always want to report the journal
* error, whatever its error handling method is. Also, an operator log will be sent by some
@@ -314,16 +300,9 @@ uint4 jnl_write_attempt(jnl_private_control *jpc, uint4 threshold)
}
# ifdef UNIX
if ((ERR_JNLWRTDEFER == status) && IS_REPL_INST_FROZEN)
- { /* Check if instance freeze is in effect and this db has instance freeze activation enabled.
- * In that case, we do not want to keep retrying the jnl_qio as that might cause lcnt to increase
- * and eventually GTMASSERT implying this is an IO issue whereas it is possible some other process
- * is holding the jnl_qio lock on this region and is not able to write to the journal file for a
- * long time because the instance is frozen. To avoid false GTMASSERTs, wait for freeze to be
- * lifted before continuing with normal flow (which is to increment lcnt and keep retrying the
- * attempt at the jnl_qio lock). Note that this process is guaranteed not to have set the instance
- * freeze due to a ENOSPC situation as in that case we would never have allowed any interrupt to occur
- * until we succeed with that write and will clear the freeze before moving on.
- * Note that the below macro takes care of the "db has instance freeze activation enabled" check too.
+ { /* Check if the write was deferred because the instance is frozen.
+ * In that case, wait until the freeze is lifted instead of wasting time spinning on the latch
+ * in jnl_qio.
*/
WAIT_FOR_REPL_INST_UNFREEZE(csa);
}
@@ -344,28 +323,11 @@ uint4 jnl_write_attempt(jnl_private_control *jpc, uint4 threshold)
} else if (prev_lcnt != lcnt)
{
assert(1 == lcnt);
- if (ERR_JNLWRTDEFER == status)
+ if ((ERR_JNLWRTDEFER == status) && (JNL_FLUSH_PROG_TRIES <= cnt))
{ /* Change of writer */
- if (JNL_FLUSH_PROG_TRIES <= cnt)
- {
- send_msg(VARLSTCNT(8) ERR_JNLFLUSHNOPROG, 2, JNL_LEN_STR(csa->hdr),
- ERR_TEXT, 2, LEN_AND_LIT("No progress even with multiple writers"));
- GTMASSERT;
- }
- proc_stuck_cnt = 0;
- } else if (ERR_JNLPROCSTUCK == status && (JNL_FLUSH_PROG_FACTOR <= ++proc_stuck_cnt))
- {
- send_msg(VARLSTCNT(8) ERR_JNLFLUSHNOPROG, 2, JNL_LEN_STR(csa->hdr), ERR_TEXT, 2,
- LEN_AND_LIT("Progress prevented by a process stuck flushing journal data"));
- VMS_ONLY(
- if (TREF(gtm_environment_init))
- {
- proc_stuck_cnt = 0;
- continue;
- }
- )
-
- GTMASSERT;
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_JNLFLUSHNOPROG, 2, JNL_LEN_STR(csa->hdr),
+ ERR_TEXT, 2, LEN_AND_LIT("No progress even with multiple writers"));
+ cnt = 0;
}
}
}
diff --git a/sr_port/jnl_write_logical.c b/sr_port/jnl_write_logical.c
index b7958cd..ea1e0b8 100644
--- a/sr_port/jnl_write_logical.c
+++ b/sr_port/jnl_write_logical.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -85,7 +85,7 @@ void jnl_write_logical(sgmnt_addrs *csa, jnl_format_buffer *jfb, uint4 com_csum)
jrec->prefix.checksum = compute_checksum(INIT_CHECKSUM_SEED, (uint4 *)jrec, SIZEOF(struct_jrec_null));
# ifdef GTM_CRYPT
- if (REPL_ALLOWED(csa))
+ if (csa->hdr->is_encrypted && REPL_ALLOWED(csa))
{
jrec_alt = (struct_jrec_upd *)jfb->alt_buff;
jrec_alt->prefix = jrec->prefix;
diff --git a/sr_port/job_addr.c b/sr_port/job_addr.c
index 31664c4..1faf9d6 100644
--- a/sr_port/job_addr.c
+++ b/sr_port/job_addr.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -18,7 +18,7 @@
error_def(ERR_JOBLABOFF);
-void 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)
{
rhdtyp *rt_hdr;
int4 *lp;
@@ -38,7 +38,7 @@ void job_addr(mstr *rtn, mstr *label, int4 offset, char **hdr, char **labaddr)
/* Label offset with routine compiled with NOLINE_ENTRY should cause error. */
lp = find_line_addr(rt_hdr, label, offset, NULL);
if (!lp)
- rts_error(VARLSTCNT(1) ERR_JOBLABOFF);
+ return (FALSE);
/* Set the pointer to address / offset for line number entry storage in lab_proxy. */
USHBIN_ONLY((TREF(lab_proxy)).lnr_adr = lp;)
/* On non-shared-binary, calculcate the offset to the corresponding lnr_tabent record by subtracting
@@ -49,4 +49,5 @@ void job_addr(mstr *rtn, mstr *label, int4 offset, char **hdr, char **labaddr)
if (NULL != labaddr)
*labaddr = (char *)LINE_NUMBER_ADDR(rt_hdr, lp);
*hdr = (char *)rt_hdr;
+ return (TRUE);
}
diff --git a/sr_port/job_addr.h b/sr_port/job_addr.h
index 2ef8f5b..b07094f 100644
--- a/sr_port/job_addr.h
+++ b/sr_port/job_addr.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * Copyright 2001, 2013 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_
-void 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);
#endif
diff --git a/sr_port/jobexam_process.c b/sr_port/jobexam_process.c
index fbfb33c..5d6942f 100644
--- a/sr_port/jobexam_process.c
+++ b/sr_port/jobexam_process.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -213,7 +213,7 @@ void jobexam_dump(mval *dump_filename_arg, mval *dump_file_spec)
parms.str.len = SIZEOF(dumpable_error_dump_file_noparms);
op_close(dump_file_spec, &parms);
/* Notify operator dump was taken */
- send_msg(VARLSTCNT(5) ERR_JOBEXAMDONE, 3, process_id, dump_file_spec->str.len, dump_file_spec->str.addr);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_JOBEXAMDONE, 3, process_id, dump_file_spec->str.len, dump_file_spec->str.addr);
REVERT;
}
@@ -240,7 +240,7 @@ CONDITION_HANDLER(jobexam_dump_ch)
UNIX_ONLY(util_out_print(0, OPER));
VMS_ONLY(sig->chf$l_sig_args -= 2);
VMS_ONLY(callg(send_msg, &sig->chf$l_sig_args));
- send_msg(VARLSTCNT(3) ERR_JOBEXAMFAIL, 1, process_id);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_JOBEXAMFAIL, 1, process_id);
/* Stop the errors here and return to caller */
UNIX_ONLY(util_out_print("", RESET)); /* Prevent rts_error from flushing this error later */
diff --git a/sr_port/jobinterrupt_event.c b/sr_port/jobinterrupt_event.c
index e492199..a0e089b 100644
--- a/sr_port/jobinterrupt_event.c
+++ b/sr_port/jobinterrupt_event.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2007 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -24,6 +24,9 @@
# include <ssdef.h>
# include "efn.h"
#endif
+#ifdef GTM_PTHREAD
+# include <pthread.h>
+#endif
#include "gtm_stdio.h"
#include "io.h"
@@ -34,17 +37,19 @@
#include "jobinterrupt_event.h"
#include "fix_xfer_entry.h"
-GBLREF xfer_entry_t xfer_table[];
+GBLREF xfer_entry_t xfer_table[];
GBLREF volatile int4 outofband;
GBLREF volatile boolean_t dollar_zininterrupt;
/* Routine called when an interrupt event occurs (signaled by mupip intrpt or other future method
- of signaling interrupts). This code is driven as a signal handler on Unix and from the START_CH
- macro on VMS where it intercepts the posix signal.
-*/
+ * of signaling interrupts). This code is driven as a signal handler on Unix and from the START_CH
+ * macro on VMS where it intercepts the posix signal.
+ */
UNIX_ONLY(void jobinterrupt_event(int sig, siginfo_t *info, void *context))
VMS_ONLY(void jobinterrupt_event(void))
-{ /* Note the (presently unused) args are to match signature for signal handlers in Unix */
+{
+ FORWARD_SIG_TO_MAIN_THREAD_IF_NEEDED(sig);
+ /* Note the (presently unused) args are to match signature for signal handlers in Unix */
if (!dollar_zininterrupt)
(void)xfer_set_handlers(outofband_event, &jobinterrupt_set, 0);
}
@@ -52,14 +57,14 @@ VMS_ONLY(void jobinterrupt_event(void))
/* Call back routine from xfer_set_handlers to complete outofband setup */
void jobinterrupt_set(int4 dummy_val)
{
- int4 status;
+# ifdef VMS
+ int4 status;
- VMS_ONLY(
- status = sys$setef(efn_outofband);
- assert(SS$_WASCLR == status);
- if (SS$_WASCLR != status && SS$_WASSET != status)
- GTMASSERT;
- )
+ status = sys$setef(efn_outofband);
+ assert(SS$_WASCLR == status);
+ if ((SS$_WASCLR != status) && (SS$_WASSET != status))
+ GTMASSERT;
+# endif
if (jobinterrupt != outofband)
{ /* We need jobinterrupt out of band processing at our earliest convenience */
outofband = jobinterrupt;
@@ -70,5 +75,5 @@ void jobinterrupt_set(int4 dummy_val)
FIX_XFER_ENTRY(xf_forchk1, op_startintrrpt);
FIX_XFER_ENTRY(xf_forloop, op_forintrrpt);
}
- VMS_ONLY(sys$wake(0,0);)
+ VMS_ONLY(sys$wake(0,0));
}
diff --git a/sr_port/line.c b/sr_port/line.c
index a2f6350..7624953 100644
--- a/sr_port/line.c
+++ b/sr_port/line.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -27,6 +27,7 @@ GBLREF command_qualifier cmd_qlf;
error_def(ERR_BLKTOODEEP);
error_def(ERR_COMMAORRPAREXP);
+error_def(ERR_FALLINTOFLST);
error_def(ERR_LSEXPECTED);
error_def(ERR_MULTFORMPARM);
error_def(ERR_MULTLAB);
@@ -35,12 +36,12 @@ error_def(ERR_NESTFORMP);
boolean_t line(uint4 *lnc)
{
- boolean_t success;
+ boolean_t success, embed_error = FALSE;
int parmcount, varnum;
short int dot_count;
mlabel *x;
mline *curlin;
- triple *first_triple, *parmbase, *parmtail, *r;
+ triple *first_triple, *parmbase, *parmtail, *r, *e;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
@@ -89,43 +90,64 @@ boolean_t line(uint4 *lnc)
{
advancewindow();
parmbase = parmtail = newtriple(OC_BINDPARM);
- for (parmcount = 0; TK_RPAREN != TREF(window_token); parmcount++)
+ /* To error out on fall-throughs to labels with a formallist, we are inserting an error immediately before
+ * the LINESTART/LINEFETCH opcode. So, first we need to find the LINESTART/LINEFETCH preceding the
+ * BINDPARM we just inserted.
+ */
+ assert((OC_LINESTART == parmbase->exorder.bl->opcode) || (OC_LINEFETCH == parmbase->exorder.bl->opcode));
+ assert(0 != parmbase->exorder.bl->src.line);
+ /* No error should be inserted before the first label of the routine. */
+ if ((mlabtab->rson != x) || TREF(code_generated))
{
- if (TK_IDENT != TREF(window_token))
- {
- stx_error(ERR_NAMEEXPECTED);
- success = FALSE;
- break;
- } else
+ e = maketriple(OC_RTERROR);
+ e->operand[0] = put_ilit(ERR_FALLINTOFLST);
+ /* Not a subroutine/func reference. */
+ e->operand[1] = put_ilit(FALSE);
+ r = parmbase->exorder.bl->exorder.bl;
+ dqins(r, exorder, e);
+ embed_error = TRUE;
+ }
+ if (success)
+ {
+ for (parmcount = 0; TK_RPAREN != TREF(window_token); parmcount++)
{
- varnum = get_mvaddr(&(TREF(window_ident)))->mvidx;
- for (r = parmbase->operand[1].oprval.tref; r; r = r->operand[1].oprval.tref)
+ if (TK_IDENT != TREF(window_token))
+ {
+ stx_error(ERR_NAMEEXPECTED);
+ success = FALSE;
+ break;
+ } else
{
- assert(TRIP_REF == r->operand[0].oprclass);
- assert(ILIT_REF == r->operand[0].oprval.tref->operand[0].oprclass);
- assert((TRIP_REF == r->operand[1].oprclass) || (NO_REF == r->operand[1].oprclass));
- if (r->operand[0].oprval.tref->operand[0].oprval.ilit == varnum)
+ varnum = get_mvaddr(&(TREF(window_ident)))->mvidx;
+ for (r = parmbase->operand[1].oprval.tref; r; r = r->operand[1].oprval.tref)
{
- stx_error(ERR_MULTFORMPARM);
- success = FALSE;
- break;
+ assert(TRIP_REF == r->operand[0].oprclass);
+ assert(ILIT_REF == r->operand[0].oprval.tref->operand[0].oprclass);
+ assert((TRIP_REF == r->operand[1].oprclass)
+ || (NO_REF == r->operand[1].oprclass));
+ if (r->operand[0].oprval.tref->operand[0].oprval.ilit == varnum)
+ {
+ stx_error(ERR_MULTFORMPARM);
+ success = FALSE;
+ break;
+ }
}
+ if (!success)
+ break;
+ r = newtriple(OC_PARAMETER);
+ parmtail->operand[1] = put_tref(r);
+ r->operand[0] = put_ilit(varnum);
+ parmtail = r;
+ advancewindow();
}
- if (!success)
+ if (TK_COMMA == TREF(window_token))
+ advancewindow();
+ else if (TK_RPAREN != TREF(window_token))
+ {
+ stx_error(ERR_COMMAORRPAREXP);
+ success = FALSE;
break;
- r = newtriple(OC_PARAMETER);
- parmtail->operand[1] = put_tref(r);
- r->operand[0] = put_ilit(varnum);
- parmtail = r;
- advancewindow();
- }
- if (TK_COMMA == TREF(window_token))
- advancewindow();
- else if (TK_RPAREN != TREF(window_token))
- {
- stx_error(ERR_COMMAORRPAREXP);
- success = FALSE;
- break;
+ }
}
}
if (success)
@@ -201,12 +223,19 @@ boolean_t line(uint4 *lnc)
assert(TREF(for_stack_ptr) == TADR(for_stack));
if (first_triple->exorder.fl == TREF(curtchain))
newtriple(OC_NOOP); /* empty line (comment, blank, etc) */
- curlin->externalentry = first_triple->exorder.fl;
- /* First_triple points to the last triple before this line was processed. Its forward link will point to a
- * LINEFETCH or a LINESTART, or possibly a NOOP. It the line was a comment, there is only a LINESTART, and
- * hence no "real" code yet.
- */
- TREF(code_generated) = TREF(code_generated) | ((OC_NOOP != first_triple->exorder.fl->opcode)
- && (first_triple->exorder.fl->exorder.fl != TREF(curtchain)));
+ if (embed_error)
+ { /* The entry point to the label should be LINESTART/LINEFETCH, not the RTERROR. */
+ curlin->externalentry = e->exorder.fl;
+ TREF(code_generated) = TRUE;
+ } else
+ {
+ curlin->externalentry = first_triple->exorder.fl;
+ /* First_triple points to the last triple before this line was processed. Its forward link will point to a
+ * LINEFETCH or a LINESTART, or possibly a NOOP. If the line was a comment, there is only a LINESTART, and
+ * hence no "real" code yet.
+ */
+ TREF(code_generated) = TREF(code_generated) | ((OC_NOOP != first_triple->exorder.fl->opcode)
+ && (first_triple->exorder.fl->exorder.fl != TREF(curtchain)));
+ }
return success;
}
diff --git a/sr_port/lke.hlp b/sr_port/lke.hlp
index 495a584..2a80563 100644
--- a/sr_port/lke.hlp
+++ b/sr_port/lke.hlp
@@ -1,241 +1,554 @@
+1 Introduction
+ Introduction
-1 Overview
- The MUMPS LOCK Utility
- The GT.M LOCK Utility, LKE, provides a tool for examining and changing
- the GT.M LOCK environment. In MUMPS, the LOCK command reserves one or
- more resource names. Only one process at a time can reserve a resource
- name. No other process sharing the same environment can successfully
- LOCK that resource name at the same time. MUMPS code commonly uses
- LOCKs as flags controlling access to global data. Generally a LOCK
- specifies the same as the name of the global variable that requires
- protected access. However, this is only a convention. A LOCK argument
- may contain any subscripted or unsubscripted MUMPS name including a
- name with no preceding caret (^). Because they have the appearance of
- local variable names, resource names with no preceding caret (^) are
- commonly referred to as "local LOCKs."
-
- The ZALLOCATE and ZDEALLOCATE commands provide an alternative,
- non-standard, mechanism for managing LOCKs.
-
-2 Functions
- Functions
- The two primary functions of the MUMPS LOCK Utility (LKE) are:
-
- o SHOW all or specified LOCKs currently active on the system
-
- o CLEAR all or specified LOCKs currently active on the system
-
- When debugging a MUMPS application, you may use LKE to identify and
- clear a possible deadlock situation, i.e., two or more processes
- have LOCKs and are waiting to add resource names LOCKed by the
- other(s).
-
- When used with GT.CM, LKE may display and change information on
- other nodes of a distributed database system.
-
-2 LOCK_database
- MUMPS LOCKs and Global Directories
- GT.M distributes the LOCK database among the database files
- identified by the Global Directory (GD). The Global Directory
- Editor (GDE) creates and maintains Global Directories.
-
- GT.M maps LOCKs of resource names starting with a caret (^) to the
- database file used to map variables with the same name. If the
- Global Directory maps the name A to file A.DAT, GT.M maps all LOCKs
- on resource name ^A to file A.DAT.
-
- GT.M maps LOCKs on names not starting with a caret (^) to the
- region of the database specified with the GDE command LOCK -REGION.
- By default, GDE creates Global Directories mapping local LOCKs to
- the region DEFAULT.
-
- These two factors result in the following:
-
- o ^ LOCKs automatically intersect for all users of the same data
- in any database file, because GT.M stores the ^ LOCKs in the
- same file as the data
-
- o "local" LOCKs intersect dependent on the Global Directory,
- because users may access the database through different Global
- Directories.
-
-2 Global_Directories
- Establishing a Global Directory
- GDE and LKE use the environment variable gtmgbldir to identify
- which file to use for the Global Directory. gtmgbldir should be
- defined by individual users in their login files.
-
- Example
-
- $ gtmgbldir=prod.gld
- $ export gtmgbldir
-
- When a process invokes a GT.M image, GT.M identifies the current
- Global Directory by the environment variable gtmgbldir. Within
- MUMPS, SET $zgbldir=expr changes the Global Directory. $zgbldir is
- an intrinsic special variable. An individual LOCK, ZALLOCATE or
- ZDEALLOCATE argument may specify a Global Directory with the
- extended global syntax.
-
-1 CLEAR
- C[LEAR]
- The CLEAR command removes active LOCKs. The format of the CLEAR
- command is:
+ The M Lock Utility (LKE) is a tool for examining and changing the GT.M
+ LOCK environment. For a description of M LOCKs, refer to the LOCKs section
+ in the General Language Features of M chapter and the description of the
+ LOCK command in the Commands chapter of the GT.M Programmer's Guide.
+
+ The two primary functions of the M Lock Utility (LKE) are:
+
+ o SHOW all or specified LOCKs currently active
+ o CLEAR all or specified LOCKs currently active
+
+ When debugging an M application, you may use LKE to identify a possible
+ deadlock situation, that is, two or more processes have LOCKs and are
+ waiting to add resource names LOCKed by the other(s).
+
+ Process 1 Process 2
+ LOCK A
+ LOCK B
+ LOCK +A
+ LOCK +B
+
+ Process 1 has A LOCKed and attempts to LOCK B. Process 2 has B LOCKed and
+ attempts to LOCK A. Because these processes do not release their current
+ LOCKs before adding additional LOCKs, nor do they provide a timeout to
+ detect the problem, they are deadlocked. Neither process can proceed
+ normally. You can use LKE to release one of the LOCKs so both processes
+ may execute. However, because releasing a LOCK may cause the process to
+ violate its design assumptions, terminating one process is generally a
+ safer way to break the deadlock.
+
+ **Note**
+
+ When a process leaves M, GT.M normally releases any LOCKs or ZALLOCATEs
+ held by that process. If a GT.M process terminates abnormally, or if the
+ system "crashes" while a GT.M process is active, GT.M cannot perform
+ normal clean-up. However, as soon as any other process waits several
+ seconds for a LOCK owned by a process that no longer exists, GT.M
+ automatically clears the "orphaned" LOCK.
+
+2 Invoke
+ Invoke
+
+ GT.M installation procedure places the LKE utility package in a directory
+ specified by the environment variable gtm_dist.
+
+ LKE requires that the environment variable gtmgbldir be defined.
+
+ Invoke LKE using the following command at the shell prompt. If this does
+ not work, consult your system manager to investigate setup and file access
+ issues.
+
+ $gtm_dist/lke LKE>
+
+ **Important**
+
+ Always run LKE on the node where the lock is held.
+
+ When LKE is ready to accept commands, it displays the LKE> prompt. To
+ leave LKE, enter the EXIT command at the LKE> prompt.
+
+ When additional information is entered on the command line after the LKE
+ command, LKE processes the additional information as its command.
+
+ $gtm_dist/lke show -all
+
+ This command displays all current LOCKs and then returns to the shell
+ prompt.
+
+ If your LKE argument contains quotes, precede each quote in the argument
+ by a back-slash (\) or enclose the entire argument in a set of quotes
+ (matching single or double). Apply this convention only for those LKE
+ commands that you run from the shell.
+
+ $gtm_dist/lke show -lock="^Account(\"Name\")"
+ $gtm_dist/lke show -lock='^Account("Name")'
+
+ Both these commands display the status of LOCK ^Account("Name") in the
+ default region.
+
+1 Commands
+ Commands
+
+ The format for the LKE commands is:
+
+ command [-qualifier[=qualifier-value]]
+
+ LKE accepts command and qualifier abbreviations. The section describing
+ each command provides the minimal abbreviation that can be used for that
+ command, and the command qualifiers, if any. FIS recommends the use of a
+ minimum of four characters for key words in scripts to ensure new keywords
+ do not conflict with older scripts.
+
+2 Clear
+ Clear
+
+ Use the CLEAR command to remove active LOCKs.
+
+ **Caution**
+
+ FIS recommends restricting the use of the LKE CLEAR facility to debugging
+ environments; removing LOCKs in a production environment typically
+ violates application design assumptions and can cause aberrant process
+ behavior. GT.M automatically removes abandoned LOCKs so it is typically
+ safer to MUPIP STOP a process that is inappropriately hanging on to a
+ LOCK.
+
+ The format of the CLEAR command is:
C[LEAR] [-qualifier...]
- The optional CLEAR command qualifiers are:
+ The optional qualifiers are:
-A[LL]
- -I[NTERACTIVE]
- -O[UTPUT]=file-spec
+ -L[OCK]
+ -[NO]C[RIT]
+ -[NO]EXACT
+ -[NO]I[NTERACTIVE]
+ -O[UTPUT]="file-name"
-P[ID]=pid
-R[EGION]=region-name
By default, CLEAR operates interactively (-INTERACTIVE).
-2 Qualifiers
+ Qualifiers for CLEAR
--ALL
- -A[LL]
- Specifies the removal of all current LOCKs. If used with the
- -REGION qualifier -ALL removes all LOCKs in the region. Issue a
- CLEAR -ALL only when there are no active GT.M processes using
- LOCKs or when you can predict the effect on the application.
+ -A[LL]
- The -ALL qualifier is incompatible with the -INTERACTIVE
- qualifier.
+ Specifies all current LOCKs.
--INTERACTIVE
- -I[NTERACTIVE]
- Clears one LOCK at a time interactively. LKE displays each
- current LOCK with the PID of the owner process and prompts for
- verification that the LOCK should be cleared. LKE retains the
- LOCK for any response other than Y[ES].
+ o -ALL removes all current LOCKs.
+ o If used, CLEAR and -REGION qualifier, -ALL removes all LOCKs in that
+ region.
+ o Issue a CLEAR - ALL only when there are no active GT.M processes using
+ LOCKs, or when you can predict the effect on the application.
+ o By default, CLEAR -ALL operates interactively (-INTERACTIVE).
- The -INTERACTIVE qualifier is incompatible with the -ALL
- qualifier.
+ -[NO]C[RIT]
- By default, CLEAR operates interactively (-INTERACTIVE).
+ Allows LKE CLEAR to work even if another process is holding a critical
+ section.
--OUTPUT
- -OUTPUT=file-spec
- Directs the reporting of all cleared LOCKs. If you specify an
- existing file, LKE overwrites that file.
+ **Caution**
- The -OUTPUT qualifier is compatible with all other qualifiers.
+ This can damage current LOCKs and the LOCK mechanism. It is intended for
+ use only under the direction of FIS.
- By default, CLEAR sends its messages to the standard output.
+ By default LKE operates in CRIT mode and ensures a consistent view of
+ LOCKs by using the database critical section(s).
--PID
- -/P[ID]=pid
- Clears all LOCKs associated with the specified process
- identification number. LKE interprets the PID as a decimal
- number. This command provides a means for directing CLEAR to
- LOCKs held by a process that is behaving abnormally.
+ -[NO]EXACT
- The -PID qualifier is compatible with all other qualifiers.
+ Limits the CLEAR command to the exact resource name specified with
+ -LOCK=resource_name. NOEXACT (the default) treats the specified resource
+ name as a prefix and works not only on it, but also on any of its
+ descendants, since their existence effectively LOCK their parent tree.
--REGION
- -/R[EGION]=region-name
- Clears LOCKs mapped by the current Global Directory to a region
- specified by the region-name.
+ -L[OCK]=""resource_name""
- The -REGION qualifier is compatible with all other qualifiers.
+ Unless used with -EXACT, specifies the leading prefix for an implicit wild
+ card search of all locks that start with the resource_name.
- By default, CLEAR -REGION= operates interactively (-INTERACTIVE).
+ o The resource_name is enclosed in two double quotation marks ("" "").
+ Because M resource names are formatted the same as global nodes with
+ punctuation characters, in this context they are usually enclosed in
+ sets of double quotation marks with string subscripts enclosed in sets
+ of two double quotations.
+ o When used with CLEAR, -LOCK removes the locks that start with
+ resource_name.
+ o When used with SHOW,-LOCK provides a precise way to examine the
+ specified lock.
-1 EXIT
- E[XIT]
- The EXIT command ends an LKE session. The format of the EXIT command
- is:
+ -[NO]I[NTERACTIVE]
- E[XIT]
+ Interactively clears one LOCK at a time. LKE displays each current LOCK
+ with the PID of the owner process and prompts for verification that the
+ LOCK should be cleared. LKE retains the LOCK for any response other than
+ Y[ES].
-1 HELP
- H[ELP]
- The HELP command explains LKE commands. The format of the HELP command
- is:
+ o By default, CLEAR operates interactively (-INTERACTIVE).
+ o To avoid holding a lock resource too long, LKE skips to the next
+ matching LOCK if there is no operator response for several seconds.
+ o -NOINTERACTIVE forces the action to take place without user
+ confirmation of each change. Using -NOINTERACTIVE prevents the LKE
+ operator from controlling the LOCK subsystem for potentially long
+ periods of time when many locks are held. To do this, it limits the
+ amount of time it waits for each response.
- H[ELP] [options...]
+ -O[UTPUT]="file-name"
- Enter the LKE command for which you want information at the Topic
- prompt(s). Use <RETURN> or <CTRL Z> to return to the LKE prompt.
+ Directs the reporting of all specified LOCKs to a file.
- Example
+ o If you specify an existing file, LKE creates a new version and
+ overwrites that file.
+ o If file-name has permission issues, OUTPUT reports the cause of the
+ error.
+ o The -OUTPUT qualifier is compatible with all other qualifiers.
+ o By default, CLEAR sends output messages to stdout.
- LKE> HELP SHOW
+ -P[ID]=pid
- This command displays help for the SHOW command.
+ Specifies the process identification number that holds a LOCK on a
+ resource name.
+
+ o LKE interprets pid as a decimal number.
+ o PID clears LOCKs held by the process with the specified process
+ identification number.
+ o Provides a means for directing CLEAR to LOCKs held by a process that
+ is behaving abnormally.
+ o The -PID qualifier is compatible with all other qualifiers.
+
+ -R[EGION]=region-name
+
+ region-namespecifies the region that holds the locked resource names.
+
+ o REGION clears LOCKs mapped by the current global directory to a region
+ specified by the region-name.
+ o The -REGION qualifier is compatible with all other qualifiers.
+ o By default, CLEAR -REGION= operates interactively (-INTERACTIVE).
+
+ Example:
+
+ LKE>CLEAR -ALL
+
+ This command clears all current LOCKs.
+
+ Example:
+
+ LKE>clear -pid=2325 -interactive
+
+ This command presents all LOCKs held by the process with PID equal to
+ 2325. You can choose whether or not to clear each LOCK.
+
+ LKE>clear -reg=areg -interactive
+
+ This command produces an output like the following:
+
+ AREG ^a Owned by PID= 2083 which is an existing
+ process Clear lock ?
+
+ Type Yes or Y in response to the prompt.
+
+ LKE responds with an informational message:
+
+ %GTM-S-LCKGONE, Lock removed : ^a
+
+ Type Yes or N or No or N until all LOCKs are displayed and acted upon.
+
+ LKE> clear -pid=4208 -nointeractive
+
+ This command clears the lock held by a process with PID 4208. This command
+ produces an output like the following:
+ DEFAULT Lock removed : ^A
-1 SHOW
- SH[OW]
- The SHOW command provides a status report on the LOCK mechanism and
- the LOCK database. The format of the SHOW command is:
+ Note that -NOINTERACTIVE forced the action without asking for a
+ confirmation.
- SH[OW] [ -qualifier...]
+ Example:
- By default, SHOW displays -ALL.
+ LKE>clear -lock="^a("b")
+ Clear lock ? y
+ Lock removed : ^a("b")
+ LKE>
- The SHOW command reports active LOCKs. Information displayed about
- specific LOCKs includes the LOCK resource name and the process
- identification (PID) of the LOCK owner. The results of a SHOW may be
- immediately "outdated" by MUMPS LOCK activity.
+ This command clears lock ^a("b") in the default region.
-2 Qualifiers
--ALL
- -A[LL]
- Specifies a display of all current LOCKs in all regions and
- information about the state of processes owning these LOCKs. The
- -ALL qualifier is compatible with all other qualifiers. SHOW
- -ALL -WAIT displays both -ALL and -WAIT information.
+ Example:
- By default, SHOW displays -ALL.
+ LKE>clear -lock="^a" -nointeractive
--OUTPUT
- -OUTPUT=file-spec
- Directs the reporting of the current LOCKs. When you specify a
- file, LKE overwrites that file.
+ This command clears all the locks that start with "^a" in the default
+ region. -NOINTERACTIVE qualifier instructs LKE to clear these locks
+ without further user intervention.
- The -OUTPUT qualifier is compatible with all other qualifiers.
+ Example:
- By default, SHOW directs all messages to SYS$OUTPUT.
+ LKE>clear -lock="^a" -exact -nointeractive
--PID
- -P[ID]=process-identification
- Displays all LOCKs owned by the specified PID.
+ This command clears lock ^a in the default region. -NOINTERACTIVE
+ instructs LKE to clear lock ^a without further user intervention.
- The -PID qualifier is compatible with all other qualifiers.
+ Example:
- By default, SHOW displays the LOCKs for all PIDs.
+ LKE>CLEAR -PID=4109 -LOCK=""^A""
+ Clear lock ? Y
+ Lock removed : ^A
+ LKE>
--REGION
- -R[EGION]=region-name
- Displays LOCKs for the specified region.
+ This command clears LOCK ^A held by process with PID 4109.
- The -REGION qualifier is compatible with all other qualifiers.
+2 SHow
+ SHow
- By default, SHOW displays the LOCKs for all regions.
+ Use the SHOW command to get status of the LOCK mechanism and the LOCK
+ database. The format of the SHOW command is:
--WAIT
- -W[AIT]
- Displays the LOCK resource name and the process state
- information of all processes waiting for the LOCK to be granted.
- LKE does not display the owner of the LOCK. SHOW -ALL -WAIT
- displays both -ALL and -WAIT information.
+ SH[OW] [-qualifier...]
-1 SPAWN
- SP[AWN]
- The SPAWN command creates a sub-process for access to the shell
- without terminating the current LKE environment. Use the SPAWN command
- to suspend a session and issue shell commands such as ls or printenv.
- The SPAWN command accepts an optional command string for execution by
- the spawned sub-process. If the SPAWN has command string parameter,
- the created sub-process prompts and accepts any legal shell command.
- To terminate the sub-process use the shell logout command.
+ The optional qualifiers are:
+
+ -A[LL]
+ -L[OCK]
+ -[NO]C[RIT]
+ -O[UTPUT]="file-name"
+ -P[ID]=pid
+ -R[EGION]=region-name
+ -W[AIT]
+
+ o By default, SHOW displays -A[LL].
+ o The SHOW command reports active LOCKs. Information includes the LOCK
+ resource name and the process identification (PID) of the LOCK owner.
+ o LKE SHOW displays lock space usage with a message in the form of:
+ "%GTM-I-LOCKSPACEUSE, Estimated free lock space: xxx% of pppp pages."
+ If the lock space is full, it also displays a LOCKSPACEFULL error.
+ o A LOCK command which finds no room in LOCK_SPACE to queue a waiting
+ LOCK, does a slow poll waiting for LOCK_SPACE to become available. If
+ LOCK does not acquire the ownership of the named resource with the
+ specified timeout, it returns control to the application with $TEST=0.
+ If timeout is not specified, the LOCK command continues to do a slow
+ poll till the space becomes available.
+ o LOCK commands which find no available lock space send a LOCKSPACEFULL
+ message to the operator log. To prevent flooding the operator log,
+ GT.M suppresses further such messages until the lock space usage drops
+ below 75% full.
+ o The results of a SHOW may be immediately "outdated" by M LOCK
+ activity.
+ o If the LOCK is owned by a GT.CM server on behalf of a client GT.M
+ process, then LKE SHOW displays the client NODENAME (limited to the
+ first 15 characters) and clientPID. The client PID (CLNTPID) is a
+ decimal value in UNIX.
+
+ **Note**
+
+ GT.CM is an RPC-like way of remotely accessing a GT.M database.
+
+ -ALL
+
+ Specifies all current LOCKs.
+
+ o -ALL displays all current LOCKs in all regions and information about
+ the state of processes owning these LOCKs.
+ o The -ALL qualifier is compatible with all other qualifiers.
+ o When -ALL is combined with -PID or -REGION, the most restrictive
+ qualifier prevails.
+ o SHOW -ALL and -WAIT displays both -ALL and -WAIT information.
+
+ -L[OCK]=resource_name
+
+ resource_name specifies a single lock.
+
+ o The resource_name is enclosed in double quotation marks ("" "").
+ Because M resource names are formatted the same as global nodes with
+ punctuation characters, in this context they are usually enclosed in
+ sets of double quotation marks with string subscripts enclosed in sets
+ of two double quotations.
+ o When used with the CLEAR command, the LOCK qualifier removes the
+ specified lock.
+ o When used with the SHOW command, the LOCK qualifier provides a precise
+ way to examine the specified lock and any descendant LOCKed resources.
+
+ -[NO]C[RIT]
+
+ Allows the SHOW command to work even if another process is holding a
+ critical section.
+
+ o By default LKE operates in CRIT mode and ensures a consistent view of
+ LOCKs by using the database critical section(s).
+ o Use NOCRIT with SHOW only when normal operation is unsuccessful, as
+ NOCRIT may cause LKE to report incomplete or inconsistent information.
+
+ -O[UTPUT]="file-name"
+
+ Directs the reporting of all specified LOCKs to a file.
+
+ o If you specify an existing file, LKE creates a new version and
+ overwrites that file.
+ o The -OUTPUT qualifier is compatible with all other qualifiers.
+ o By default, the SHOW command send output messages to stdout.
+
+ -P[ID]=pid
+
+ Specifies the process identification number that holds a LOCK on a
+ resource name.
+
+ o LKE interprets pid as a decimal number.
+ o PID displays all LOCKs owned by the specified process identification
+ number.
+ o The -PID qualifier is compatible with all other qualifiers; the most
+ restrictive of the qualifiers prevails.
+ o By default, SHOW displays the LOCKs for all PIDs.
+
+ -R[EGION]=region-name
+
+ Specifies the region that holds the locked resource names.
+
+ o The REGION qualifier displays LOCKs of that specified region.
+ o The REGION qualifier is compatible with all other qualifiers; the most
+ restrictive of the qualifiers prevails.
+ o By default, SHOW displays the LOCKs for all regions.
+
+ -W[AIT]
+
+ Displays the LOCK resource name and the process state information of all
+ processes waiting for the LOCK to be granted.
+
+ o SHOW -WAIT does not display the owner of the LOCK.
+ o SHOW -ALL -WAIT displays both -ALL and -WAIT information.
+ o When a process abandons a "wait" request, that request may continue to
+ appear in LKE SHOW -WAIT displays. This appearance is harmless, and is
+ automatically eliminated if the GT.M lock management requires the
+ space which it occupies.
+
+ Use the following procedure to display all LOCKs active in the database(s)
+ defined by the current global directory.
+
+ LKE> SHOW -ALL -WAIT
+
+ This produces an output like the following:
+
+ No locks were found in DEFAULT
+ AREG
+ ^a Owned by PID=2080 which is an existing process
+ BREG
+ ^b(2) Owned by PID= 2089 which is a nonexistent process
+ No locks were found in CREG
+
+ Example:
+
+ LKE>SHOW -ALL
+
+ This command displays all LOCKs mapped to all regions of the current
+ global directory. It produces an output like the following:
+
+ DEFAULT
+ ^A Owned by PID= 5052 which is an existing process
+ ^B Owned by PID= 5052 which is an existing process
+ %GTM-I-LOCKSPACEUSE, Estimated free lock space: 99% of 40 pages
+
+ Example:
+
+ LKE>show -lock="^a"(""b"")"
+
+ This command shows lock ^a("b") in the default region.
+
+ Example:
+
+ LKE>SHOW -CRIT
+
+ This command displays all the applicable locks held by a process that is
+ holding a critical section.
+
+ Example:
+
+ LKE>show -all -output="abc.lk"
+
+ This command create a new file called abc.lk that contains the output of
+ the SHOW -ALL command.
+
+ Example:
+
+ LKE>show -pid=4109
+
+ This command displays all locks held by process with PID 4109 and the
+ total lock space usage.
+
+ Example:
+
+ LKE>show -region=DEFAULT -lock=""^A""
+
+ This command displays the lock on ^A in the region DEFAULT. It produces an
+ output like the following:
+
+ DEFAULT
+ ^A Owned by PID= 5052 which is an existing process
+ %GTM-I-LOCKSPACEUSE, Estimated free lock space: 99% of 40 pages
+
+2 Exit
+ Exit
+
+ The EXIT command ends an LKE session. The format of the EXIT command is:
+
+ E[XIT]
+
+2 Help
+ Help
+
+ The HELP command explains LKE commands. The format of the HELP command is:
+
+ H[ELP] [options...]
+
+ Enter the LKE command for which you want information at the Topic
+ prompt(s) and then press RETURN or CTRL-Z to return to the LKE prompt.
+
+ Example:
+
+ LKE> HELP SHOW
+
+ This command displays help for the SHOW command.
+
+2 SPawn
+ SPawn
+
+ Use the SPAWN command to create a sub-process for access to the shell
+ without terminating the current LKE environment. Use the SPAWN command to
+ suspend a session and issue shell commands such as ls or printenv.
The format of the SPAWN command is:
SP[AWN]
+ The SPAWN command has no qualifiers.
+
+ Example:
+
+ LKE>spawn
+
+ This command creates a sub-process for access to the current shell without
+ terminating the current LKE environment. Type exit to return to LKE.
+
+1 Summary
+ Summary
+
+ +-------------------------------------------------------------------+
+ | COMMAND | QUALIFIER | COMMENTS |
+ |---------+---------------------+-----------------------------------|
+ | | -ALL | |
+ | | -L[OCK] | |
+ | | -[NO]CRIT | |
+ | | -[NO]EXACT | |
+ | C[LEAR] | | Use CLEAR with care and planning. |
+ | | -[NO]I[NTERACTIVE] | |
+ | | -O[UTPUT]=file-name | |
+ | | -P[ID]=pid | |
+ | | -R[EGION]=name | |
+ |---------+---------------------+-----------------------------------|
+ | E[XIT] | none | - |
+ |---------+---------------------+-----------------------------------|
+ | H[ELP] | [option] | - |
+ |---------+---------------------+-----------------------------------|
+ | | -ALL | |
+ | | -L[OCK] | |
+ | | -[NO]CRIT | |
+ | | -N[OINTERACTIVE] | |
+ | SH[OW] | | - |
+ | | -O[UTPUT]=file-name | |
+ | | -P[ID]=pid | |
+ | | -R[EGION]=name | |
+ | | -W[AIT] | |
+ |---------+---------------------+-----------------------------------|
+ | SP[AWN] | none | shellcommand |
+ +-------------------------------------------------------------------+
+
diff --git a/sr_port/lke_clear.c b/sr_port/lke_clear.c
index 4b1cc02..e80b6c2 100644
--- a/sr_port/lke_clear.c
+++ b/sr_port/lke_clear.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -94,7 +94,7 @@ void lke_clear(void)
locks = gtcmtr_lke_clearreq(gv_cur_region->dyn.addr->cm_blk, gv_cur_region->cmx_regnum,
all, interactive, pid, &node);
# else
- gtm_putmsg(VARLSTCNT(10) ERR_UNIMPLOP, 0, ERR_TEXT, 2,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_UNIMPLOP, 0, ERR_TEXT, 2,
LEN_AND_LIT("GT.CM region - locks must be cleared on the local node"),
ERR_TEXT, 2, REG_LEN_STR(gv_cur_region));
continue;
@@ -117,18 +117,18 @@ void lke_clear(void)
rel_crit(gv_cur_region);
} else
{
- gtm_putmsg(VARLSTCNT(2) ERR_BADREGION, 0);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(2) ERR_BADREGION, 0);
locks = TRUE;
}
if (!locks)
{
- gtm_putmsg(VARLSTCNT(4) ERR_NOLOCKMATCH, 2, REG_LEN_STR(gv_cur_region));
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_NOLOCKMATCH, 2, REG_LEN_STR(gv_cur_region));
}
}
}
if (!match && reg.len != 0)
- rts_error(VARLSTCNT(4) ERR_NOREGION, 2, reg.len, reg.addr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_NOREGION, 2, reg.len, reg.addr);
}
diff --git a/sr_port/lke_getki.c b/sr_port/lke_getki.c
index 5ef7a2a..3edcf4f 100644
--- a/sr_port/lke_getki.c
+++ b/sr_port/lke_getki.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2006, 2011 Fidelity Information Services, Inc *
+ * Copyright 2006, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -13,6 +13,7 @@
#include "gtm_string.h"
#include "lke_getcli.h"
+#include "gtm_ctype.h" /* Needed for TOUPPER() */
/* This routine performs the necessary transformation of the LOCK keys passed in
* from the CLI layer and produces a canonical formatted key. This routine
@@ -30,7 +31,8 @@ int lke_getki(char* src, int srclen, char* outbuff)
{
char *inptr, *nextptr, *intop, *outptr, *tmpptr;
mval subsc = DEFINE_MVAL_STRING(MV_STR, 0, 0, 0, NULL, 0, 0);
- char one_lockbuf[MAX_ZWR_KEY_SZ + 1];
+ char one_lockbuf[MAX_ZWR_KEY_SZ + 1], *one_char;
+ char *valid_char = "HAR"; /* This is used for validating characters following $ZCH and $C */
if (srclen > 1 && '"' == src[0] && '"' == src[srclen - 1])
{
@@ -55,9 +57,37 @@ int lke_getki(char* src, int srclen, char* outbuff)
outptr += inptr - src;
for (intop = src + srclen; inptr < intop; inptr = nextptr)
{
- if ('$' == *inptr)
- { /* the entire subscript is within $C() or $ZCH() */
- *outptr++ = *inptr++;
+ if (')' == *inptr) /* Catches incomplete lists or string concatenations */
+ return -1;
+ else if ('$' == *inptr)
+ { /* the entire subscript is within $C() or $ZCH */
+ *outptr++ = '$';
+ inptr++;
+ if (('z' == *inptr) || ('Z' == *inptr))
+ { /* Very likely $ZCHAR() */
+ *outptr++ = 'Z';
+ inptr++;
+ }
+ if (('c' == *inptr) || ('C' == *inptr))
+ {
+ *outptr++ = 'C';
+ inptr++;
+ if (('Z' == *(outptr - 2)) && (('h' == *inptr) || ('H' == *inptr)))
+ {
+ *outptr++ ='H';
+ inptr++;
+ one_char = valid_char + 1;
+ }
+ else
+ one_char = valid_char;
+ /* Validate/skip letters following C so that we allow C, CH, CHA, CHAR */
+ while (('\0' != *one_char) && ('(' != *inptr))
+ if (TOUPPER(*inptr++) != *one_char++)
+ return -1;
+ if ('(' != *inptr)
+ return -1;
+ } else /* We don't support anything other than $C() or $ZCH in locks */
+ return -1;
nextptr = memchr(inptr, ')', intop - inptr);
if (NULL == nextptr)
return -1;
@@ -65,14 +95,35 @@ int lke_getki(char* src, int srclen, char* outbuff)
memcpy(outptr, inptr, nextptr - inptr);
outptr += nextptr - inptr;
} else
- { /* unquoted string or a number */
- nextptr = memchr(inptr, ',', intop - inptr);
- if (NULL == nextptr)
- {
- nextptr = intop - 1;;
- if (')' != *nextptr)
- return -1;
+ {
+ if ('"' == *inptr) /* Is this a quoted string? */
+ { /*Process character by character because '_' or ',' can be used within the quotes. */
+ for (nextptr = inptr + 1; nextptr < intop; nextptr++)
+ if ('"' == *nextptr && (nextptr + 1 < intop))
+ {
+ nextptr++;
+ if ('"' != *nextptr)
+ /* This is not a two double-quote so terminate. */
+ break;
+ }
+ } else
+ { /* Fast-forward to the next separator */
+ nextptr = memchr(inptr, '_', intop - inptr);
+ if (NULL == nextptr)
+ { /* Not a string concatineated with $C() or $ZCH() */
+ nextptr = memchr(inptr, ',', intop - inptr);
+ if (NULL == nextptr)
+ nextptr = intop - 1;
+ }
}
+ if (intop - 1 == nextptr)
+ { /* If it reached to the end, it had better closed the paran */
+ if (')' != *nextptr)
+ return -1;
+ }
+ else if ((',' != *nextptr) && ('_' != *nextptr))
+ /* If we are not at the end, it must be a separator*/
+ return -1;
subsc.str.len = INTCAST(nextptr - inptr);
subsc.str.addr = inptr;
if (val_iscan(&subsc))
@@ -83,13 +134,9 @@ int lke_getki(char* src, int srclen, char* outbuff)
{
if (nextptr - 1 > inptr && '"' == *inptr && '"' == *(nextptr - 1))
{ /* The string is already enclosed by a pair of quotes */
- *outptr++ = *inptr++; /* initial quote */
- for (; inptr < nextptr - 1; *outptr++ = *inptr++)
- {
- if ('"' == *inptr && (++inptr >= nextptr - 1 || *inptr != '"'))
- return -1; /* invalid (unescaped) quote within a quoted string */
- }
- *outptr++ = *inptr++; /* final quote */
+ memcpy(outptr, inptr, nextptr - inptr);
+ outptr += nextptr - inptr;
+ inptr += nextptr - inptr;
} else
{ /* unquoted string: add quotes */
*outptr++ = '"';
@@ -98,12 +145,17 @@ int lke_getki(char* src, int srclen, char* outbuff)
*outptr++ = *tmpptr;
if ('"' == *tmpptr)
*outptr++ = '"';
+ if ('_' == *tmpptr)
+ {
+ *--outptr;
+ nextptr = tmpptr;
+ }
}
*outptr++ = '"';
}
}
}
- if (',' != *nextptr && ')' != *nextptr)
+ if ((',' != *nextptr) && (')' != *nextptr) && ('_' != *nextptr))
return -1;
*outptr++ = *nextptr++;
}
diff --git a/sr_port/m_zcompile.c b/sr_port/m_zcompile.c
index 57bd43c..f4c1061 100644
--- a/sr_port/m_zcompile.c
+++ b/sr_port/m_zcompile.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -24,6 +24,6 @@ int m_zcompile(void)
return FALSE;
triptr = newtriple(OC_ZCOMPILE);
triptr->operand[0] = x;
- triptr->operand[1] = put_ilit(FALSE); /* mExtReqd arg */
+ triptr->operand[1] = put_ilit(FALSE); /* ignore_dollar_zcompile arg */
return TRUE;
}
diff --git a/sr_port/mdb_condition_handler.c b/sr_port/mdb_condition_handler.c
index 7d75138..2fbb902 100644
--- a/sr_port/mdb_condition_handler.c
+++ b/sr_port/mdb_condition_handler.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -174,6 +174,7 @@ error_def(ERR_RTSLOC);
error_def(ERR_SRCLOCUNKNOWN);
error_def(ERR_STACKCRIT);
error_def(ERR_STACKOFLOW);
+error_def(ERR_TLVLZERO);
error_def(ERR_TPRETRY);
error_def(ERR_TPRESTNESTERR);
error_def(ERR_TPSTACKCRIT);
@@ -183,22 +184,25 @@ error_def(ERR_UNSOLCNTERR);
error_def(ERR_VMSMEMORY);
boolean_t clean_mum_tstart(void);
-void setup_error(int argcnt, ...);
+void setup_error(sgmnt_addrs *csa, int argcnt, ...);
-#ifdef GTM_TRIGGER
-/* When we go to restart generated code after handling an error, verify that we are not in frame or one created on its
- * behalf that invoked a trigger and caused a dynamic TSTART to be done on its behalf. This can happen for example if
- * a trigger is invoked for the first time but get a compilation or link failure error. This error is thrown from
- * gtm_trigger() while no trigger based error handling is in effect so no rollback of the dynamic frame occurs which
- * will result in unhandled TPQUIT errors, perhaps interminably.
+#ifdef UNIX
+/* When we restart generated code after handling an error, verify that we are not in the frame or one created on its
+ * behalf that invoked a trigger or spanning node and caused a dynamic TSTART to be done on its behalf. This can happen
+ * for example if a trigger is invoked for the first time but gets a compilation or link failure error or if a spanning
+ * node fetch or update drives an error. In the trigger case, the relevant error is thrown from gtm_trigger() while no
+ * trigger based error handling is in effect so no rollback of the dynamic frame occurs which results in unhandled TPQUIT
+ * errors, perhaps interminably. In both the trigger and spanning-node cases, the MUM_TSTART we are about to execute unrolls
+ * the C stack preventing any return to the C frame that did the implicit tstart and prevents it from being committed so
+ * it must be rolled back.
*/
-#define MUM_TSTART_FRAME_CHECK \
-{ \
- if ((0 == gtm_trigger_depth) && tp_pointer && tp_pointer->implicit_tstart) \
- { \
- DEBUG_ONLY(donot_INVOKE_MUMTSTART = FALSE); \
- OP_TROLLBACK(-1); /* Unroll implicit TP frame */ \
- } \
+#define MUM_TSTART_FRAME_CHECK \
+{ \
+ if (GTMTRIG_ONLY((0 == gtm_trigger_depth) &&) tp_pointer && tp_pointer->implicit_tstart) \
+ { \
+ DEBUG_ONLY(donot_INVOKE_MUMTSTART = FALSE); \
+ OP_TROLLBACK(-1); /* Unroll implicit TP frame */ \
+ } \
}
#else
#define MUM_TSTART_FRAME_CHECK
@@ -235,12 +239,12 @@ boolean_t clean_mum_tstart(void)
/* Routine to setup an error in util_outbuff as if rts_error had put it there. Used when we morph ERR_TPRETRY
* to ERR_TPRESTNESTERR. Requires a va_list var containing the args so do this in this separate routine.
*/
-void setup_error(int argcnt, ...)
+void setup_error(sgmnt_addrs *csa, int argcnt, ...)
{
va_list var;
VAR_START(var, argcnt);
- gtm_putmsg_list(argcnt, var);
+ gtm_putmsg_list(csa, argcnt, var);
va_end(var);
}
#endif
@@ -251,7 +255,6 @@ CONDITION_HANDLER(mdb_condition_handler)
boolean_t dm_action; /* did the error occur on a action from direct mode */
boolean_t trans_action; /* did the error occur during "transcendental" code */
char src_line[MAX_ENTRYREF_LEN];
- char source_line_buff[MAX_SRCLINE + SIZEOF(ARROW)];
mstr src_line_d;
io_desc *err_dev;
tp_region *tr;
@@ -370,7 +373,7 @@ CONDITION_HANDLER(mdb_condition_handler)
# endif
rc = tp_restart(1, TP_RESTART_HANDLES_ERRORS);
DBGEHND((stderr, "mdb_condition_handler: tp_restart returned with rc=%d. state=%d, and SIGNAL=%d\n",
- rc, GTMTRIG_ONLY(tprestart_state) NOT_GTMTRIG_ONLY(0), error_condition));
+ rc, GTMTRIG_ONLY(tprestart_state) NON_GTMTRIG_ONLY(0), error_condition));
# ifdef GTM_TRIGGER
if (0 != rc)
{ /* The only time "tp_restart" will return non-zero is if the error needs to be
@@ -421,12 +424,17 @@ CONDITION_HANDLER(mdb_condition_handler)
}
# ifdef UNIX
else
- { /* TP restart occurred during error handling - treat as nested error to prevent issues with errors being
- * rethrown during a TP restart. Change the error from TPRETRY to TPRESTNESTERR so we don't give
- * internal use only error name to user and let error continue through regular processing.
+ {
+ if (0 == dollar_tlevel)
+ SIGNAL = ERR_TLVLZERO; /* TPRESTART specified but not in TP */
+ else
+ SIGNAL = ERR_TPRESTNESTERR; /* Only if actually in TP */
+ /* TPRETRY encountered or requested during error handling - treat as nested error to prevent issues
+ * with errors being rethrown during a TP restart. Change the error from TPRETRY to either TLVLZERO or
+ * TPRESTNESTERR as appropriate so we don't give internal use only error name to user and let error
+ * continue through regular processing (both treated as nested error since error_frame non-NULL).
*/
- SIGNAL = ERR_TPRESTNESTERR;
- setup_error(VARLSTCNT(1) SIGNAL);
+ setup_error(gv_target ? gv_target->gd_csa : NULL, VARLSTCNT(1) SIGNAL);
}
# endif
}
@@ -469,10 +477,9 @@ CONDITION_HANDLER(mdb_condition_handler)
}
/* Fix gv_currkey to null-str in case gv_target points to dir_tree (possible in case of name-level-$order).
* This is similar to how we fix gv_currkey for a successful name-level-$order operation (see op_gvorder.c).
- * Do same in case gv_target points to cs_addrs->hasht_tree (no idea how this is possible, but better to fix
- * it so we dont take the fast path in op_gvname when gv_target is clearly not GVT of a user-visible global.
+ * Do same in case gv_target points to cs_addrs->hasht_tree so we dont take the fast path in op_gvname
+ * when gv_target is clearly not GVT of a user-visible global.
*/
- GTMTRIG_ONLY(assert(gv_target != csa->hasht_tree);)
if ((gv_target == csa->dir_tree) GTMTRIG_ONLY(|| (gv_target == csa->hasht_tree)))
{
gv_currkey->end = 0;
@@ -534,9 +541,9 @@ CONDITION_HANDLER(mdb_condition_handler)
* duplicate message.
*/
assert(ERR_VMSMEMORY == SIGNAL);
- send_msg(VARLSTCNT(4) ERR_VMSMEMORY, 2, *(int **)(&sig->chf$is_sig_arg1 + 1),
+ send_msg(VARLSTCNT(4) ERR_VMSMEMORY, 2, *(int **)(&sig->chf$is_sig_arg1 + 1), /* BYPASSOK - send_msg */
*(int **)(&sig->chf$is_sig_arg1 + 2));
- gtm_putmsg(VARLSTCNT(4) ERR_VMSMEMORY, 2, *(int **)(&sig->chf$is_sig_arg1 + 1),
+ gtm_putmsg(VARLSTCNT(4) ERR_VMSMEMORY, 2, *(int **)(&sig->chf$is_sig_arg1 + 1), /* BYPASSOK - gtm_putmsg */
*(int **)(&sig->chf$is_sig_arg1 + 2));
SIGNAL = ERR_GTMERREXIT; /* Override reason for "stop" */
# endif
@@ -668,7 +675,7 @@ CONDITION_HANDLER(mdb_condition_handler)
/* Verify not indirect or that context is unchanged before reset context */
assert(NULL != restart_pc);
assert((!(SFF_INDCE & frame_pointer->flags)) || (restart_ctxt == frame_pointer->ctxt));
- DBGEHND((stderr, "mdb_condition_handler(1): Resetting frame 0x"lvaddr" mpc/context with restart_pc/ctxt"
+ DBGEHND((stderr, "mdb_condition_handler(1): Resetting frame 0x"lvaddr" mpc/context with restart_pc/ctxt "
"0x"lvaddr"/0x"lvaddr" - frame has type 0x%04lx\n", frame_pointer, restart_pc, restart_ctxt,
frame_pointer->type));
frame_pointer->mpc = restart_pc;
@@ -681,7 +688,7 @@ CONDITION_HANDLER(mdb_condition_handler)
{ /* Verify not indirect or that context is unchanged before reset context */
assert(NULL != restart_pc);
assert((!(SFF_INDCE & frame_pointer->flags)) || (restart_ctxt == frame_pointer->ctxt));
- DBGEHND((stderr, "mdb_condition_handler(2): Resetting frame 0x"lvaddr" mpc/context with restart_pc/ctxt"
+ DBGEHND((stderr, "mdb_condition_handler(2): Resetting frame 0x"lvaddr" mpc/context with restart_pc/ctxt "
"0x"lvaddr"/0x"lvaddr" - frame has type 0x%04lx\n", frame_pointer, restart_pc, restart_ctxt,
frame_pointer->type));
frame_pointer->mpc = restart_pc;
@@ -819,7 +826,7 @@ CONDITION_HANDLER(mdb_condition_handler)
} else
{
PRN_ERROR;
- rts_error(VARLSTCNT(1) ERR_NOEXCNOZTRAP);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOEXCNOZTRAP);
}
}
if (clean_mum_tstart())
@@ -856,7 +863,7 @@ CONDITION_HANDLER(mdb_condition_handler)
{ /* Verify not indirect or that context is unchanged before reset context */
assert(NULL != restart_pc);
assert((!(SFF_INDCE & frame_pointer->flags)) || (restart_ctxt == frame_pointer->ctxt));
- DBGEHND((stderr, "mdb_condition_handler(4): Resetting frame 0x"lvaddr" mpc/context with restart_pc/ctxt"
+ DBGEHND((stderr, "mdb_condition_handler(4): Resetting frame 0x"lvaddr" mpc/context with restart_pc/ctxt "
"0x"lvaddr"/0x"lvaddr" - frame has type 0x%04lx\n", frame_pointer, restart_pc, restart_ctxt,
frame_pointer->type));
frame_pointer->mpc = restart_pc;
@@ -933,7 +940,6 @@ CONDITION_HANDLER(mdb_condition_handler)
"re-dispatching error frame\n"));
MUM_TSTART_FRAME_CHECK;
MUM_TSTART; /* unwind the current C-stack and restart executing from the top of the current M-stack */
- assert(FALSE);
} else if ((0 != dollar_etrap.str.len) || (0 != dollar_ztrap.str.len))
{
assert(!ztrap_explicit_null);
@@ -1159,7 +1165,7 @@ CONDITION_HANDLER(mdb_condition_handler)
{
PRN_ERROR;
if (TREF(compile_time) && (((int)ERR_LABELMISSING) != SIGNAL))
- show_source_line(source_line_buff, SIZEOF(source_line_buff), TRUE);
+ show_source_line(TRUE);
}
}
/* Slight divergence in how we handle otherwise unhandled errors on UNIX and VMS. UNIX now has a strict no-unsolicited
diff --git a/sr_port/mdef.h b/sr_port/mdef.h
index 3f78102..6c474cf 100644
--- a/sr_port/mdef.h
+++ b/sr_port/mdef.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -88,18 +88,22 @@ typedef unsigned int uint4; /* 4-byte unsigned integer */
#include <inttypes.h>
#include "mdefsa.h"
+#include "gtm_common_defs.h"
#include <mdefsp.h>
#include "gtm_sizeof.h"
-#include "gtm_common_defs.h"
#include "gtm_threadgbl.h"
/* Anchor for thread-global structure rather than individual global vars */
GBLREF void *gtm_threadgbl; /* Accessed through TREF macro in gtm_threadgbl.h */
#ifdef DEBUG
error_def(ERR_ASSERT);
-#define assert(x) ((x) ? 1 : rts_error(VARLSTCNT(7) ERR_ASSERT, 5, LEN_AND_LIT(__FILE__), __LINE__, (SIZEOF(#x) - 1), (#x)))
+# define assert(x) ((x) ? 1 : rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_ASSERT, 5, LEN_AND_LIT(__FILE__), __LINE__, \
+ (SIZEOF(#x) - 1), (#x)))
+# ifdef UNIX
+# define GTMDBGFLAGS_ENABLED
+# endif
#else
-#define assert(x)
+# define assert(x)
#endif
#ifdef GTM64
@@ -128,6 +132,16 @@ error_def(ERR_ASSERT);
# define FD_INVALID_NONPOSIX 0 /* fd of 0 is invalid in VMS if using RMS sys$open calls (non-posix interface) */
#endif
+#if defined(UNIX)
+# define USE_POLL
+# define POLL_ONLY(X) X
+# define SELECT_ONLY(X)
+#else
+# define USE_SELECT
+# define POLL_ONLY(X)
+# define SELECT_ONLY(X) X
+#endif
+
/* INTPTR_T is an integer that has the same length as a pointer on each platform. Its basic use is for arithmetic
* or generic parameters. For all platforms except Tru64/VMS (alpha platforms), the [U]INTPTR_T types will be
* equivalenced to [u]intptr_t. But since this type is used for alignment and other checking, and since Tru64/VMS
@@ -152,8 +166,6 @@ typedef UINTPTR_T uintszofptr_t;
#ifdef GTM64
# define USER_STACK_SIZE 8192
-# define GTM64_ONLY(X) X
-# define NON_GTM64_ONLY(X)
# define VA_ARG_TYPE long
# define VA_ARG_TYPE_BOOL int
# define GTM_IS_64BIT TRUE
@@ -161,8 +173,6 @@ typedef UINTPTR_T uintszofptr_t;
# define GTM_BITNESS_OTHER "32-bit"
#else
# define USER_STACK_SIZE 4096
-# define GTM64_ONLY(X)
-# define NON_GTM64_ONLY(X) X
# define VA_ARG_TYPE int
# define VA_ARG_TYPE_BOOL int
# define GTM_IS_64BIT FALSE
@@ -200,6 +210,13 @@ typedef UINTPTR_T uintszofptr_t;
# define UNALIGNED_ACCESS_SUPPORTED
#endif
+#if defined(__i386) || defined(__x86_64__) || defined(_AIX) || defined (__sun)
+# define GTM_PTHREAD
+# define GTM_PTHREAD_ONLY(X) X
+#else
+# define GTM_PTHREAD_ONLY(X)
+#endif
+
#if defined(__ia64)
# define IA64_ONLY(X) X
# define NON_IA64_ONLY(X)
@@ -371,7 +388,12 @@ typedef long ulimit_t; /* NOT int4; the Unix ulimit function returns a value of
#define MAX_NUM_SIZE 64
#define MAX_FORM_NUM_SUBLEN 128 /* this is enough to hold the largest numeric subscript */
#define PERIODIC_FLUSH_CHECK_INTERVAL (30 * 1000)
-#define MAX_ARGS 256 /* in formallist */
+
+#ifndef __sparc
+# define MAX_ARGS 256 /* in formallist */
+#else /* Sparc super frame has room for 256 args, but functions or concatenate are limited to somewhat fewer */
+# define MAX_ARGS 242
+#endif
#ifdef UNIX
# define MAX_KEY_SZ 1023 /* maximum database key size */
@@ -438,9 +460,9 @@ mval *underr_strict(mval *start, ...);
#define MV_FORCE_MVAL(M,I) (((I) >= 1000000 || (I) <= -1000000) ? i2mval((M),(int)(I)) : \
(void)( (M)->mvtype = MV_NM | MV_INT , (M)->m[1] = (int)(I)*MV_BIAS ))
#ifdef GTM64
-#define MV_FORCE_ULMVAL(M,L) (((L) >= 1000000) ? ul2mval((M),(unsigned long)(L)) : \
+#define MV_FORCE_ULMVAL(M,L) (((L) >= 1000000) ? ui82mval((M),(gtm_uint64_t)(L)) : \
(void)( (M)->mvtype = MV_NM | MV_INT , (M)->m[1] = (int)(L)*MV_BIAS ))
-#define MV_FORCE_LMVAL(M,L) (((L) >= 1000000 || (L) <= -1000000) ? l2mval((M),(long)(L)) : \
+#define MV_FORCE_LMVAL(M,L) (((L) >= 1000000 || (L) <= -1000000) ? i82mval((M),(gtm_int64_t)(L)) : \
(void)( (M)->mvtype = MV_NM | MV_INT , (M)->m[1] = (int)(L)*MV_BIAS ))
#else
#define MV_FORCE_ULMVAL MV_FORCE_UMVAL
@@ -585,8 +607,12 @@ int gtm_assert2(int condlen, char *condtext, int file_name_len, char file_name[]
#define DBG_MARK_RTS_ERROR_UNUSABLE
#endif
int rts_error(int argcnt, ...);
+int rts_error_csa(void *csa, int argcnt, ...); /* Use CSA_ARG(CSA) for portability */
+#define CSA_ARG(CSA) (CSA),
void dec_err(uint4 argcnt, ...);
#elif defined(VMS)
+#define rts_error_csa rts_error
+#define CSA_ARG(CSA) /* no csa arg on VMS */
void dec_err(int4 msgnum, ...);
#else
#error unsupported platform
@@ -641,67 +667,12 @@ int m_usleep(int useconds);
# define SHORT_SLEEP(x) hiber_start(x);
#endif
-/* The following "MSYNC" defines are for the MM access method
- * NO_MSYNC -- minimum number of msyncs -- only in run down
- * UNTARGETED_MSYNC -- msync the entire file
- * TARGETED_MSYNC -- keep track of changed buffers and only msync them
- * REGULAR_MSYNC -- do regular file I/O on the mapped file (ignoring the fact it is mapped)
- *
- * If none of the MSYNCs are explicitly defined, the ifdef and elif defined sequence will fall through
- * to the else case, defining NO_MSYNC as the default.
- */
#ifdef UNIX
# define UNIX_ONLY(X) X
# define UNIX_ONLY_COMMA(X) X,
-# if defined UNTARGETED_MSYNC
-# define UNTARGETED_MSYNC_ONLY(X) X
-# define NON_UNTARGETED_MSYNC_ONLY(X)
-# define TARGETED_MSYNC_ONLY(X)
-# define NON_TARGETED_MSYNC_ONLY(X) X
-# define REGULAR_MSYNC_ONLY(X)
-# define NON_REGULAR_MSYNC_ONLY(X) X
-# define NO_MSYNC_ONLY(X)
-# define NON_NO_MSYNC_ONLY(X)
-# elif defined TARGETED_MSYNC
-# define UNTARGETED_MSYNC_ONLY(X)
-# define NON_UNTARGETED_MSYNC_ONLY(X) X
-# define TARGETED_MSYNC_ONLY(X) X
-# define NON_TARGETED_MSYNC_ONLY(X)
-# define REGULAR_MSYNC_ONLY(X)
-# define NON_REGULAR_MSYNC_ONLY(X) X
-# define NO_MSYNC_ONLY(X)
-# define NON_NO_MSYNC_ONLY(X)
-# elif defined REGULAR_MSYNC
-# define UNTARGETED_MSYNC_ONLY(X)
-# define NON_UNTARGETED_MSYNC_ONLY(X) X
-# define TARGETED_MSYNC_ONLY(X)
-# define NON_TARGETED_MSYNC_ONLY(X) X
-# define REGULAR_MSYNC_ONLY(X) X
-# define NON_REGULAR_MSYNC_ONLY(X)
-# define NO_MSYNC_ONLY(X)
-# define NON_NO_MSYNC_ONLY(X)
-# else
-# define NO_MSYNC
-# define UNTARGETED_MSYNC_ONLY(X)
-# define NON_UNTARGETED_MSYNC_ONLY(X)
-# define TARGETED_MSYNC_ONLY(X)
-# define NON_TARGETED_MSYNC_ONLY(X)
-# define REGULAR_MSYNC_ONLY(X)
-# define NON_REGULAR_MSYNC_ONLY(X)
-# define NO_MSYNC_ONLY(X) X
-# define NON_NO_MSYNC_ONLY(X)
-# endif
#else
# define UNIX_ONLY(X)
# define UNIX_ONLY_COMMA(X)
-# define UNTARGETED_MSYNC_ONLY(X)
-# define TARGETED_MSYNC_ONLY(X)
-# define REGULAR_MSYNC_ONLY(X)
-# define NON_UNTARGETED_MSYNC_ONLY(X)
-# define NON_TARGETED_MSYNC_ONLY(X)
-# define NON_REGULAR_MSYNC_ONLY(X)
-# define NO_MSYNC_ONLY(X)
-# define NON_NO_MSYNC_ONLY(X)
#endif
/* HP-UX on PA-RISC and z/OS are not able to have dynamic file extensions while running in MM access mode
@@ -859,7 +830,7 @@ typedef struct
sm_off_t bl; /* backward link - relative offset from beginning of this element to previous element in queue */
global_latch_t latch; /* required for platforms without atomic operations to modify both fl and bl concurrently;
* unused on platforms with such instructions. */
-} que_head, cache_que_head, mmblk_que_head;
+} que_head, cache_que_head;
#define IS_PTR_ALIGNED(ptr, ptr_base, elemSize) \
(0 == ((((sm_uc_ptr_t)(ptr)) - ((sm_uc_ptr_t)(ptr_base))) % elemSize))
@@ -1224,11 +1195,11 @@ typedef INTPTR_T ptroff_t;
# define CACHELINE_PAD_COND(fieldSize, fillnum)
#endif
-#define MEMCP(dst,src,start,count,limit){ \
- if (start+count > limit) \
- rts_error(VARLSTCNT(1) ERR_CPBEYALLOC); \
- else \
- memcpy(dst+start,src,count); \
+#define MEMCP(dst,src,start,count,limit){ \
+ if (start+count > limit) \
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_CPBEYALLOC); \
+ else \
+ memcpy(dst+start,src,count); \
}
#ifndef USING_ICONV
@@ -1269,7 +1240,8 @@ uchar_ptr_t i2asc(uchar_ptr_t p, unsigned int n);
/* ascii conversion functions */
int4 asc2i(uchar_ptr_t p, int4 len);
qw_num asc2l(uchar_ptr_t p, int4 len);
-unsigned int asc_hex2i(char *p, int len);
+unsigned int asc_hex2i(uchar_ptr_t p, int len);
+gtm_uint64_t asc_hex2l(uchar_ptr_t p, int len);
/* This macro converts an integer to a decimal string (a more efficient alternative to i2asc).
* It is used by format2zwr() which is called a lot during MUPIP EXTRACT (which can be time-consuming
@@ -1778,17 +1750,42 @@ enum
* how many parameters are allowed to be passed between M and C.
*/
#if defined(DEBUG) && defined(UNIX)
-#define OPERATOR_LOG_MSG \
+#define OPERATOR_LOG_MSG \
+{ \
+ error_def(ERR_TEXT); /* BYPASSOK */ \
+ if (gtm_white_box_test_case_enabled && (WBTEST_OPER_LOG_MSG == gtm_white_box_test_case_number)) \
+ { \
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_LIT("Send message to operator log")); \
+ } \
+}
+#else
+#define OPERATOR_LOG_MSG
+#endif
+
+#ifdef GTM_PTHREAD
+/* If we detect a case when the signal came to a thread other than the main GT.M thread, this macro will redirect the signal to the
+ * main thread if such is defined. Such scenarios is possible, for instance, if we are running along a JVM, which, upon receiving a
+ * signal, dispatches a new thread to invoke signal handlers other than its own. The ptrhead_kill() enables us to target the signal
+ * to a specific thread rather than rethrow it to the whole process.
+ */
+#define FORWARD_SIG_TO_MAIN_THREAD_IF_NEEDED(SIG) \
{ \
- error_def(ERR_TEXT); /* BYPASSOK */ \
- if (gtm_white_box_test_case_enabled && (WBTEST_OPER_LOG_MSG == gtm_white_box_test_case_number)) \
- { \
- send_msg(VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_LIT("Send message to operator log")); \
+ GBLREF pthread_t gtm_main_thread_id; \
+ GBLREF boolean_t gtm_main_thread_id_set; \
+ \
+ if (gtm_main_thread_id_set && !pthread_equal(gtm_main_thread_id, pthread_self())) \
+ { /* Only redirect the signal if the main thread ID has been defined, and we are not that. */ \
+ pthread_kill(gtm_main_thread_id, SIG); \
+ return; \
} \
}
#else
-#define OPERATOR_LOG_MSG
+#define FORWARD_SIG_TO_MAIN_THREAD_IF_NEEDED(SIG)
#endif
+#ifdef DEBUG
+# define MVAL_IN_RANGE(V, START, END) (((char *)(V) >= (char *)(START)) \
+ && ((char *)(V) < ((char *)(START) + (INTPTR_T)(END) * SIZEOF(mval))))
+#endif
#endif /* MDEF_included */
diff --git a/sr_port/merrors.msg b/sr_port/merrors.msg
index 92406e8..eb1e35f 100644
--- a/sr_port/merrors.msg
+++ b/sr_port/merrors.msg
@@ -144,25 +144,27 @@
! ERR_OPCOMMISSED 150381275 (sent via $SNDOPR in util_output.c if prior errors)
!
! List of known undocumented messages follows (along with a comment)
-! ERR_JNLREQUIRED message referenced only in GT.CX code (not supported currently)
-! ERR_LKSECINIT message referenced only in GT.CX code (not supported currently)
-! ERR_JNLWRTNOWWRTR internal error (not displayed to the users)
! ERR_ACK internal error (not displayed to the users)
-! ERR_ENQ internal error (not displayed to the users)
-! ERR_REPEATERROR internal error (not displayed to the users)
-! ERR_TPRETRY internal error (not displayed to the users)
-! ERR_INVDBGLVL referenced only if "gtmdbglvl" is set to non-zero value (which is a debugging feature)
+! ERR_ASC2EBCDICCONV not yet documented since zOS is not officially supported
! ERR_DEFEREVENT referenced only if #define DEBUG is TRUE (i.e. for debug builds only)
+! ERR_ENQ internal error (not displayed to the users)
! ERR_FREEZEID referenced only if #define DEBUG_FREEZE is TRUE.
+! ERR_INVDBGLVL referenced only if "gtmdbglvl" is set to non-zero value (which is a debugging feature)
+! ERR_JNLREQUIRED message referenced only in GT.CX code (not supported currently)
+! ERR_JNLWRTNOWWRTR internal error (not displayed to the users)
+! ERR_JOBINTRRETRHOW internal error (not displayed to users - drives rethrow of jobinterrupt)
+! ERR_JOBINTRRQST internal error (not displayed to users - drives jobinterrupt)
+! ERR_LKSECINIT message referenced only in GT.CX code (not supported currently)
! ERR_MUDESTROYFAIL referenced only if #define IPCRM_FOR_SANCHEZ_ONLY is TRUE.
! ERR_MUDESTROYSUC referenced only if #define IPCRM_FOR_SANCHEZ_ONLY is TRUE.
-! ERR_ASC2EBCDICCONV not yet documented since zOS is not officially supported
+! ERR_RBWRNNOTCHG not seen by user since return status of mupip_set_file (that triggers this) is not displayed.
+! ERR_REPEATERROR internal error (not displayed to the users)
! ERR_SYSTEMVALUE code is not executed (set $system won't reach op_svput at all to signal the error)
+! ERR_TPRETRY internal error (not displayed to the users)
+! ERR_WILLEXPIRE error triggered by the license management code which has been since disabled.
! ERR_YDIRTSZ used by a percent utility, which is not documented intentionally
! ERR_ZDEFACTIVE functionality not documented (GT.CM related weirdness)
! ERR_ZDEFOFLOW functionality not documented (GT.CM related weirdness)
-! ERR_WILLEXPIRE error triggered by the license management code which has been since disabled.
-! ERR_RBWRNNOTCHG not seen by user since return status of mupip_set_file (that triggers this) is not displayed.
!
!
! ----- Buffer to introduce new undocumented error messages without affecting UNUSEDMSGnnn match with corresponding line numbers.
@@ -171,8 +173,6 @@
!
!
!
-!
-!
! In addition all messages of the LMU and GTLP message facility are not documented as Licensing is out of GT.M since V4.2.
!
ACK <>/success/fao=0!/ansi=0
@@ -357,7 +357,7 @@ TERMASTQUOTA <Process AST quota exceeded, cannot open terminal>/error/fao=0!/ans
TEXTARG <Invalid argument to $TEXT function>/error/fao=0!/ansi=5
TMPSTOREMAX <Maximum space for temporary values exceeded>/error/fao=0!/ansi=0
VIEWCMD <View parameter is not valid with VIEW command>/error/fao=0!/ansi=0
-TXTNEGLIN <A line prior to line number zero was referenced in $TEXT>/error/fao=0!/ansi=12
+JNI <!AD>/error/fao=2!/ansi=0
TXTSRCFMT <$TEXT encountered an invalid source program file format>/error/fao=0!/ansi=0
UIDMSG <Unidentified message received>/error/fao=0!/ansi=0
UIDSND <Unidentified sender PID>/error/fao=0!/ansi=0
@@ -366,9 +366,9 @@ UNIMPLOP <Unimplemented construct encountered>/error/fao=0!/ansi=0
VAREXPECTED <Variable expected in this context>/error/fao=0!/ansi=39
VARRECBLKSZ <Blocksize must be at least record size + 4 bytes>/error/fao=0!/ansi=0
MAXARGCNT <Maximum number of arguments !UL exceeded>/error/fao=1!/ansi=0
-WCFAIL <The database cache is corrupt>/error/fao=0!/ansi=0
+GTMSECSHRSEMGET <semget error errno = !UL>/error/fao=1!/ansi=0
VIEWARGCNT <View parameter !AD has inappropriate number of subparameters>/error/fao=2!/ansi=0
-XKILLCNTEXC <Maximum number of arguments (!UL) to exclusive kill exceeded>/error/fao=1!/ansi=0
+GTMSECSHRDMNSTARTED <gtmsecshr daemon started (key: 0x!XL) for version !AD from !AD>/info/fao=5!/ansi=0
ZATTACHERR <Error attaching to "!AD">/error/fao=2!/ansi=0
ZDATEFMT <$ZDATE format string contains invalid character>/error/fao=0!/ansi=0
ZEDFILSPEC <Illegal ZEDIT file specification: !AD> /error/fao=2!/ansi=0
@@ -423,7 +423,7 @@ GVRUNDOWN <Error during global database rundown>/error/fao=0!/ansi=0
LKRUNDOWN <Error during lock database rundown>/error/fao=0!/ansi=0
IORUNDOWN <Error during image rundown>/error/fao=0!/ansi=0
FILENOTFND <File !AD not found>/error/fao=2!/ansi=0
-MUFILRNDWNFL <File !AD rundown failed>/info/fao=2!/ansi=0
+MUFILRNDWNFL <File !AD rundown failed>/error/fao=2!/ansi=0
JNLTMQUAL1 <Time qualifier BEFORE_TIME="!AZ" is less than SINCE_TIME="!AZ">/error/fao=2!/ansi=0
FORCEDHALT <Image HALTed by MUPIP STOP>/fatal/fao=0!/ansi=0
LOADEOF <Load error: EOF reached prior to BEGIN record !UL. No records loaded.>/error/fao=1!/ansi=0
@@ -435,14 +435,14 @@ GVZPREVFAIL <Global variable $ZPREVIOUS function failed. Failure code: !AD.>/er
MULTFORMPARM <This formal parameter is multiply defined>/error/fao=0!/ansi=21
QUITARGUSE <Quit cannot take an argument in this context>/error/fao=0!/ansi=16
NAMEEXPECTED <A local variable name is expected in this context>/error/fao=0!/ansi=0
-UNUSEDMSG438 <ACTLSTEXP: Last used in V5.4-002B>/error/fao=0!/ansi=11
+FALLINTOFLST <Fall-through to a label with formallist is not allowed>/error/fao=0!/ansi=11
NOTEXTRINSIC <Quit does not return to an extrinsic function: argument not allowed>/error/fao=0!/ansi=16
-UNUSEDMSG440 <FMLLSTPRESENT: Last used in V5.4-002B>/error/fao=0!/ansi=11
+GTMSECSHRREMSEMFAIL <error removing semaphore errno = !UL>/error/fao=1!/ansi=0
FMLLSTMISSING <The formal list is absent from a label called with an actual list: !AD>/error/fao=2!/ansi=20
ACTLSTTOOLONG <More actual parameters than formal parameters: !AD>/error/fao=2!/ansi=58
ACTOFFSET <Actuallist not allowed with offset>/error/fao=0!/ansi=0
MAXACTARG <Maximum number of actual arguments exceeded>/error/fao=0!/ansi=0
-GTMDUMPFAIL <Could not create DUMP FILE>/error/fao=0!/ansi=0
+GTMSECSHRREMSEM <[client pid !UL] Semaphore (!UL) removed>/error/fao=2!/ansi=0
JNLTMQUAL2 <Time qualifier LOOKBACK_TIME="!AZ" is later than SINCE_TIME="!AZ">/error/fao=2!/ansi=0
GDINVALID <Unrecognized Global Directory file format: !AD, expected label: !AD, found: !AD>/error/fao=6!/ansi=0
ASSERT <Assert failed in !AD line !UL for expression (!AD)>/fatal/fao=5!/ansi=0
@@ -586,13 +586,13 @@ LDGOQFMT <Corrupt GOQ format header information!/>/error/fao=0!/ansi=0
BEGINST <Beginning LOAD at record number: !UL>/info/fao=1!/ansi=0
INVMVXSZ <Invalid block size for GOQ load format>/fatal/fao=0!/ansi=0
JNLWRTNOWWRTR <Journal writer attempting another write>/error/fao=0!/ansi=0
-MUPGDERR <Command aborted due to global directory errors>/error/fao=0!/ansi=0
+GTMSECSHRSHMCONCPROC <More than one process attached to Shared memory segment (!UL) not removed (!UL)>/error/fao=2!/ansi=0
JNLINVALLOC <Journal file allocation !UL is not within the valid range of !UL to !UL. Journal file not created.>/warning/fao=3!/ansi=0
JNLINVEXT <Journal file extension !UL is greater than the maximum allowed size of !UL. Journal file not created.>/warning/fao=2!/ansi=0
MUPCLIERR <Action not taken due to CLI errors>/error/fao=0!/ansi=0
JNLTMQUAL4 <Time qualifier BEFORE_TIME="!AZ" is less than AFTER_TIME="!AZ">/error/fao=2!/ansi=0
-UNUSEDMSG594 <JNLBUFFTOOLG Last used in V5.5-000>/error/fao=0!/ansi=0
-UNUSEDMSG595 <JNLBUFFTOOSM Last used in V5.5-000>/error/fao=0!/ansi=0
+GTMSECSHRREMSHM <[client pid !UL] Shared memory segment (!UL) removed, nattch = !UL>/info/fao=3!/ansi=0
+GTMSECSHRREMFILE <[client pid !UL] File (!AD) removed>/info/fao=3!/ansi=0
MUNODBNAME <A database name or the region qualifier must be specified>/error/fao=0!/ansi=0
FILECREATE <!AD file !AD created>/info/fao=4!/ansi=0
FILENOTCREATE <!AD file !AD not created>/info/fao=4!/ansi=0
@@ -614,7 +614,7 @@ WCERRNOTCHG <Not all specified database files were changed>/error/fao=0!/ansi=0
WCWRNNOTCHG <Not all specified database files were changed>/warning/fao=0!/ansi=0
ZCWRONGDESC <A string longer than 65535 is passed via 32-bit descriptor>/error/fao=0!/ansi=0
MUTNWARN <Database file !AD has 0x!16 at XQ more transactions to go before reaching the transaction number limit (0x!16 at XQ). Renew database with MUPIP INTEG TN_RESET>/warning/fao=4!/ansi=0
-JNLNAMLEN <Journal file name !AD: for database file !AD exceeds maximum length of !UL>/error/fao=5!/ansi=0
+GTMSECSHRUPDDBHDR <[client pid !UL] database fileheader (!AD) updated !AD>/info/fao=5!/ansi=0
LCKSTIMOUT <DAL timed lock request expired>/warning/fao=0!/ansi=0
CTLMNEMAXLEN <The maximum length of a control mnemonic has been exceeded>/error/fao=0!/ansi=0
CTLMNEXPECTED <Control mnemonic is expected in this context>/error/fao=0!/ansi=0
@@ -750,14 +750,14 @@ MUTEXFRCDTERM <Mutual Exclusion subsystem detected forced termination of process
GTMSECSHR <!UL : Error during gtmsecshr operation>/error/fao=1!/ansi=0
GTMSECSHRSRVFID <!AD: !UL - Attempt to service request failed.!/ client id: !UL, mesg type: !UL, mesg data: !UL>/warning/fao=6!/ansi=0
GTMSECSHRSRVFIL <!AD: !UL - Attempt to service request failed.!/ client id: !UL, mesg type: !UL!/file: !AD>/warning/fao=7!/ansi=0
-SOCKACTNA <Action not appropriate for current socket>/error/fao=0!/ansi=0
+FREEBLKSLOW <Only !UL free blocks left out of !UL total blocks for !AD>/warning/fao=4!/ansi=0
PROTNOTSUP <Protocol !AD not supported>/error/fao=2!/ansi=0
DELIMSIZNA <Delimiter size is not appropriate>/error/fao=0!/ansi=0
INVCTLMNE <Invalid control mnemonics>/error/fao=0!/ansi=0
SOCKLISTEN <Error listening on a socket>/error/fao=0!/ansi=0
LQLENGTHNA <Listening queue length !UL not appropriate. Must be between 1 and 5.>/error/fao=1!/ansi=0
ADDRTOOLONG <Socket address !AD of length !UL is longer than the maximum permissible length !UL>/error/fao=4!/ansi=0
-UNUSEDMSG760 <LSNCONNOTCMP Last used in V5.4-002A>/error/fao=0!/ansi=76
+GTMSECSHRGETSEMFAIL <error getting semaphore errno = !UL>/error/fao=1!/ansi=0
CPBEYALLOC <Attempt to copy beyond the allocated buffer>/error/fao=0!/ansi=0
DBRDONLY <Database file !AD read only>/error/fao=2!/ansi=0
DUPTN <Duplicate transaction found [TN = 0x!16 at XQ] at offset 0x!XL in journal file !AD>/warning/fao=4!/ansi=0
@@ -778,7 +778,7 @@ 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
JNLMINALIGN <Journal Record Alignment !UL is less than the minimum value of !UL>/warning/fao=2!/ansi=0
-JNLDSKALIGN <Journal Record Alignment !UL is not a multiple of 512>/warning/fao=1!/ansi=0
+UNUSEDMSG781 <JNLDSKALIGN : Last used in V4.3-000>/error/fao=0!/ansi=0
JNLPOOLSETUP <Journal Pool setup error>/error/fao=0!/ansi=0
JNLSTATEOFF <ROLLBACK or RECOVER BACKWARD cannot proceed as database file !AD does not have journaling ENABLED and ON>/error/fao=2!/ansi=0
RECVPOOLSETUP <Receive Pool setup error>/error/fao=0!/ansi=0
@@ -841,7 +841,7 @@ RECSIZENOTEVEN <RECORDSIZE [!UL] needs to be a multiple of 2 if ICHSET or OCHSET
BUFFLUFAILED <Error flushing buffers from !AD for database file !AD>/error/fao=4!/ansi=0
MUQUALINCOMP <Incompatible qualifiers - FILE and REGION>/error/fao=0!/ansi=0
DISTPATHMAX <$gtm_dist path is greater than maximum (!UL)>/error/fao=1!/ansi=0
-MAXTRACEHEIGHT <The maximum trace tree height (!UL) has been exceeded. The trace information will be incomplete.>/info/fao=1!/ansi=0
+UNUSEDMSG844 <MAXTRACEHEIGHT last used in V5.4-002>/error/fao=0!/ansi=0
IMAGENAME <The executing module name should be !AD instead of !AD>/error/fao=4!/ansi=0
GTMSECSHRPERM <The gtmsecshr module in $gtm_dist does not have the correct permission and uid>/error/fao=0!/ansi=0
GTMDISTUNDEF <Environment variable $gtm_dist is not defined>/error/fao=0!/ansi=0
@@ -947,7 +947,7 @@ DBMBPFRDLBM <!AD Master bit map shows this map has space, agreeing with disk loc
DBMBPFRINT <!AD Master bit map shows this map has space, agreeing with MUPIP INTEG>/warning/fao=2!/ansi=0
DBMAXKEYEXC <!AD Maximum key size for database exceeds design maximum>/error/fao=2!/ansi=0
DBMXRSEXCMIN <!AD Maximum record size for database is less than the design minimum>/error/fao=2!/ansi=0
-DBMAXRSEXBL <!AD Maximum record size for database exceeds what the block size can support>/error/fao=2!/ansi=0
+UNUSEDMSG950 <DBMAXRSEXBL : Last used in V5.5-000>/error/fao=0!/ansi=0
DBREADBM <!AD Read error on bitmap>/error/fao=2!/ansi=0
DBCOMPTOOLRG <!AD Record has too large compression count>/error/fao=2!/ansi=0
DBVERPERFWARN2 <Peformance warning: Database !AD is not fully upgraded. Run MUPIP REORG UPGRADE for best overall performance>/warning/fao=2!/ansi=0
@@ -969,7 +969,7 @@ MUTEXRSRCCLNUP <Mutex subsystem leftover resource !AD removed>/info/fao=2!/ansi=
SEMWT2LONG <Process !UL waited !UL second(s) for the !AD lock for region !AD, lock held by pid !UL>/error/fao=7!/ansi=0
REPLINSTOPEN <Error opening replication instance file !AD>/error/fao=2!/ansi=0
REPLINSTCLOSE <Error closing replication instance file !AD>/error/fao=2!/ansi=0
-JNLNOTFOUND <File !AD does not exist -- possibly moved or deleted> /info /fao=2!/ansi=0
+UNUSEDMSG972 <JNLNOTFOUND : Last used in V4.4-000>/error/fao=0!/ansi=0
DBCRERR8 <Database file !AD, cr location 0x!XJ blk = 0x!XL error: !AD was 0x!16 at XQ, expecting 0x!16 at XQ -- called from module !AD at line !UL> /info /fao=11!/ansi=0
NUMPROCESSORS <Could not determine number of processors>/warning/fao=0!/ansi=0
DBADDRANGE8 <Database file !AD, element location 0x!XJ: blk = 0x!XL: control 0x!16 at XQ was outside !AD range 0x!16 at XQ to 0x!16 at XQ> /info /fao=9!/ansi=0
@@ -986,16 +986,16 @@ REPLJNLCLOSED <Replication in jeopardy as journaling got closed for database fil
RENAMEFAIL <Rename of file !AD to !AD failed>/warning/fao=4!/ansi=0
FILERENAME <File !AD is renamed to !AD>/info/fao=4!/ansi=0
JNLBUFINFO <Pid 0x!XL!/ dsk 0x!XL free 0x!XL bytcnt 0x!XL io_in_prog 0x!XL fsync_in_prog 0x!XL!/ dskaddr 0x!XL freeaddr 0x!XL qiocnt 0x!XL now_writer 0x!XL fsync_pid 0x!XL!/filesize 0x!XL cycle 0x!XL errcnt 0x!XL wrtsize 0x!XL fsync_dskaddr 0x!XL>/info/fao=16!/ansi=0
-JNLQIOLOCKED <Error obtaining io_in_prog lock on jnl-file !AD>/error/fao=2!/ansi=0
-JNLEOFPREZERO <Error while zeroing jnl-file !AD>/error/fao=2!/ansi=0
+UNUSEDMSG989 <JNLQIOLOCKED : Last used in V4.4-000>/error/fao=0!/ansi=0
+UNUSEDMSG990 <JNLEOFPREZERO : Last used in V4.4-000>/error/fao=0!/ansi=0
TPNOTACID <!AD at !AD in a final TP retry violates ACID properties of a TRANSACTION; indefinite RESTARTs may occur !AD !AD>/info/fao=8!/ansi=0
JNLSETDATA2LONG <SET journal record has data of length !UL. Target system cannot handle data more than !UL bytes.>/error/fao=2!/ansi=0
JNLNEWREC <Target system cannot recognize journal record of type !UL, last recognized type is !UL>/error/fao=2!/ansi=0
REPLFTOKSEM <Error with replication semaphores for instance file !AD>/error/fao=2!/ansi=0
-GETCWD <Error getting current working directory for file !AD>/error/fao=2!/ansi=0
+UNUSEDMSG995 <GETCWD : Last used before V4.0-001E>/error/fao=0!/ansi=0
EXTRIOERR <Error writing extract file !AD>/error/fao=2!/ansi=0
EXTRCLOSEERR <Error closing extract file !AD>/error/fao=2!/ansi=0
-TRUNCATE <Error while truncating jnl-file !AD to length !UL>/error/fao=3!/ansi=0
+UNUSEDMSG998 <TRUNCATE : Last used in V4.3-001F>/error/fao=0!/ansi=0
REPLEXITERR <Replication process encountered an error while exiting>/error/fao=0!/ansi=0
MUDESTROYSUC <Global section (!AD) corresponding to file !AD successfully destroyed>/info/fao=4!/ansi=0
DBRNDWN <Error during global database rundown for region !AD.!/Notify those responsible for proper database operation.>/error/fao=2!/ansi=0
@@ -1008,7 +1008,7 @@ TCGETATTR <Error while getting terminal attributes on file descriptor !UL>/error
TCSETATTR <Error while setting terminal attributes on file descriptor !UL>/error/fao=1!/ansi=0
IOWRITERR <IO Write by pid 0x!XL to blk 0x!XL of database file !AD failed. Pid 0x!XL retrying the IO.>/error/fao=5!/ansi=0
REPLINSTWRITE <Error writing [0x!XL] bytes at offset [0x!16 at XQ] in replication instance file !AD>/error/fao=4!/ansi=0
-DBBADFREEBLKCTR <Database !AD free blocks counter in file header: 0x!XL is incorrect, should be 0x!XL. Auto-corrected.>/info/fao=4!/ansi=0
+DBBADFREEBLKCTR <Database !AD free blocks counter in file header: 0x!XL appears incorrect, should be 0x!XL. Auto-corrected.>/warning/fao=4!/ansi=0
REQ2RESUME <Request to resume suspended processing received from process !UL owned by userid !UL>/info/fao=2!/ansi=0
TIMERHANDLER <Incorrect SIGALRM handler (0x!XJ) found by !AD>/warning/fao=3!/ansi=0
FREEMEMORY <Error occurred freeing memory from 0x!XJ>/error/fao=1!/ansi=0
@@ -1016,11 +1016,11 @@ MUREPLSECDEL <Replication section !AD deleted>/info/fao=2!/ansi=0
MUREPLSECNOTDEL <Replication section !AD not deleted>/info/fao=2!/ansi=0
MUJPOOLRNDWNSUC <Jnlpool section (id = !AD) belonging to the replication instance !AD successfully rundown>/info/fao=4!/ansi=0
MURPOOLRNDWNSUC <Recvpool section (id = !AD) belonging to the replication instance !AD successfully rundown>/info/fao=4!/ansi=0
-MUJPOOLRNDWNFL <Jnlpool section (id = !AD) belonging to the replication instance !AD rundown failed>/info/fao=4!/ansi=0
-MURPOOLRNDWNFL <Recvpool section (id = !AD) belonging to the replication instance !AD rundown failed>/info/fao=4!/ansi=0
+MUJPOOLRNDWNFL <Jnlpool section (id = !AD) belonging to the replication instance !AD rundown failed>/error/fao=4!/ansi=0
+MURPOOLRNDWNFL <Recvpool section (id = !AD) belonging to the replication instance !AD rundown failed>/error/fao=4!/ansi=0
MUREPLPOOL <Error with replpool section !AD>/info/fao=2!/ansi=0
REPLACCSEM <Error with replication access semaphore (id = !UL) for instance file !AD>/error/fao=3!/ansi=0
-JNLFLUSHNOPROG <No progress while attempting to flush journal file !AD>/error/fao=2!/ansi=0
+JNLFLUSHNOPROG <No progress while attempting to flush journal file !AD>/warning/fao=2!/ansi=0
REPLINSTCREATE <Error creating replication instance file !AD>/error/fao=2!/ansi=0
SUSPENDING <Process Received Signal !UL. Suspending processing on user request or attempt to do terminal I/O while running in the background>/info/fao=1!/ansi=0
SOCKBFNOTEMPTY <Socket buffer size cannot be set to 0x!XL due to 0x!XL bytes of buffered data. Read first.>/error/fao=2!/ansi=0
@@ -1076,7 +1076,7 @@ NOSUBSCRIPT <No such subscript found (!SL)>/error/fao=1!/ansi=0
SYSTEMVALUE <Invalid value for $SYSTEM (!AD)>/error/fao=2!/ansi=0
SIZENOTVALID4 <Size (in bytes) must be either 1, 2, or 4>/error/fao=0!/ansi=0
STRNOTVALID <Error: cannot convert !AD value to valid value>/error/fao=2!/ansi=0
-RECNOCREJNL <Recover could not create new journal file !AD>/info/fao=2!/ansi=0
+UNUSEDMSG1079 <RECNOCREJNL : Last used in V4.3-001F>/error/fao=0!/ansi=0
ERRWETRAP <Error while processing $ETRAP>/error/fao=0!/ansi=0
TRACINGON <Tracing already turned on>/info/fao=0!/ansi=0
CITABENV <Environment variable for call-in table !AD not set>/error/fao=2!/ansi=0
@@ -1104,9 +1104,9 @@ INVZDIRFORM <Invalid value (!UL) specified for ZDIR_FORM>/error/fao=1!/ansi=0
ZDIROUTOFSYNC <$ZDIRECTORY !AD is not the same as its cached value !AD>/warning/fao=4!/ansi=0
GBLNOEXIST <Global !AD no longer exists>/info/fao=2!/ansi=0
MAXBTLEVEL <Global !AD reached maximum level>/error/fao=2!/ansi=0
-JNLSTRESTFL <Failed to restore journaling state for database !AD>/error/fao=2!/ansi=0
+UNUSEDMSG1107 <JNLSTRESTFL : found no evidence it ever was used in a production release>/error/fao=0!/ansi=0
JNLALIGNSZCHG <Journal ALIGNSIZE is rounded up to !UL blocks (closest next higher power of two)>/info/fao=1!/ansi=0
-MAXTRACELEVEL <The maximum traceable level of !UL has been exceeded. The frame information will not be maintained.>/info/fao=1!/ansi=0
+UNUSEDMSG1109 <MAXTRACELEVEL : last used in V5.4-002B>/error/fao=0!/ansi=0
GVFAILCORE <A core file is being created for later analysis if necessary>/error/fao=0!/ansi=0
DBCDBNOCERTIFY <Database !AD HAS NOT been certified due to the preceding errors - rerun DBCERTIFY SCAN>/error/fao=2!/ansi=0
DBFRZRESETSUC <Freeze released successfully on database file !AD>/info/fao=2!/ansi=0
@@ -1351,7 +1351,7 @@ TRIGTCOMMIT <TCOMMIT at $ZTLEVEL=!UL not allowed as corresponding TSTART was don
TRIGTLVLCHNG <Detected a net transaction level ($TLEVEL) change during trigger !AD. Transaction level must be the same at exit as when the trigger started>/error/fao=2!/ansi=0
TRIGNAMEUNIQ <Unable to make trigger name !AD unique beyond !UL versions already loaded>/error/fao=3!/ansi=0
ZTRIGINVACT <Missing or invalid parameter in position !UL given to $ZTRIGGER()>/error/fao=1!/ansi=0
-UNUSEDMSG1354 <ZTRIGNOTP : Last used in V5.4-001>/error/fao=0!/ansi=0
+INDRCOMPFAIL <Compilation of indirection failed>/error/fao=0!/ansi=0
QUITALSINV <QUIT * return when the extrinsic was not invoked with SET *>/error/fao=0!/ansi=0
PROCTERM <!AD process termination due to !AD (return code !UL) from !AD>/warning/fao=7!/ansi=0
SRCLNNTDSP <Source lines exceeding !UL character width are not displayed>/info/fao=1!/ansi=0
@@ -1364,10 +1364,10 @@ 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
-TPLOCKRESTMAX <Transaction restarts due to unavailability of locks not allowed in a final TP retry more than !UL times>/error/fao=1!/ansi=0
+UNUSEDMSG1367 <TPLOCKRESTMAX : Last used in V5.5-000>/error/fao=0!/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
-UNUSEDMSG1370 <ONLYLDTRIG: Last used in V5.4-001>/error/fao=0!/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
@@ -1379,7 +1379,7 @@ REPLNOXENDIAN <!AD side is running on a GT.M version that does not support cross
REPLXENDIANFAIL <!AD side encountered error while doing endian conversion at journal sequence number 0x!16 at XQ>/error/fao=3!/ansi=0
ZGOTOINVLVL2 <ZGOTO 0:entryref is not valid on VMS (UNLINK is a UNIX only feature)>/error/fao=0!/ansi=0
GTMSECSHRCHDIRF <gtmsecshr unable to chdir to its temporary directory (!AD)>/error/fao=2!/ansi=0
-UNUSEDMSG1382 <FORCTRLINDX: Only used in V5.4-002>/error/fao=0!/ansi=0
+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
@@ -1411,7 +1411,7 @@ NORESYNCUPDATERONLY <NORESYNC qualifier only allowed on a Supplementary Instance
NOSUPPLSUPPL <Instance !AD is configured to perform local updates so it cannot receive from Supplementary Instance !AD>/error/fao=4!/ansi=0
REPL2OLD <Instance !AD uses a GT.M version that does not support connection with the current version on instance !AD>/error/fao=4!/ansi=0
EXTRFILEXISTS <Error opening output file: !AD -- File exists>/error/fao=2!/ansi=0
-UNUSEDMSG1414 <!AD : An error encountered with the shared object : !AZ>/error/fao=3!/ansi=0
+MUUSERECOV <Abnormal shutdown of journaled database !AD detected>/error/fao=2!/ansi=0
SECNOTSUPPLEMENTARY <!AD is a Supplementary Instance and so cannot act as a source to non-Supplementary Instance !AD >/error/fao=4!/ansi=0
SUPRCVRNEEDSSUPSRC <Instance !AD is not configured to perform local updates so it cannot act as a receiver for non-Supplementary Instance !AD>/error/fao=4!/ansi=0
UNUSEDMSG1417 <SYNCTOSAMETYPE: Never used before so slot free for reuse>/info/fao=0!/ansi=0
@@ -1434,7 +1434,7 @@ ORLBKFRZOVER <!AD : FREEZE on region !AD (!AD) cleared>/info/fao=6!/ansi=0
ORLBKNOV4BLK <Region !AD (!AD) has V4 format blocks. Database upgrade required. ONLINE ROLLBACK cannot continue>/error/fao=4!/ansi=0
DBROLLEDBACK <Concurrent ONLINE ROLLBACK detected on one or more regions. The current operation is no longer valid>/error/fao=0!/ansi=0
DSEWCREINIT <Database cache reinitialized by DSE for region !AD>/info/fao=2!/ansi=0
-UNUSEDMSG1437 <A total of !UL process(es) skipped database rundown due to a concurrent ONLINE ROLLBACK>/info/fao=1!/ansi=0
+MURNDWNOVRD <OVERRIDE qualifier used with MUPIP RUNDOWN on database file !AD>/info/fao=2!/ansi=0
! The following error message is NOT issued to the user and is only internal to GT.M
REPLONLNRLBK <ONLINE ROLLBACK detected. Starting afresh>/error/fao=0!/ansi=0
!
@@ -1487,7 +1487,7 @@ JNLBUFFDBUPD <Journal file buffer size for database file !AD has been adjusted f
LOCKINCR2HIGH <Attempt to increment a LOCK more than !UL times>/error/fao=1!/ansi=0
LOCKIS <!_!_Resource name: !AD>/info/fao=2!/ansi=0
LDSPANGLOINCMP <Incomplete spanning node found during load>/error/fao=0!/ansi=0
-MUFILRNDWNFL2 <Database section (id = !UL) belonging to database file !AD rundown failed>/info/fao=3!/ansi=0
+MUFILRNDWNFL2 <Database section (id = !UL) belonging to database file !AD rundown failed>/error/fao=3!/ansi=0
MUINSTFROZEN <!AD : Instance !AZ is frozen. Waiting for instance to be unfrozen before proceeding with writes to database file !AD>/info/fao=5!/ansi=0
MUINSTUNFROZEN <!AD : Instance !AZ is now Unfrozen. Continuing with writes to database file !AD>/info/fao=5!/ansi=0
GTMEISDIR <!AD : Is a directory>/error/fao=2!/ansi=0
@@ -1506,6 +1506,27 @@ NOTALLDBRNDWN <Not all regions were successfully rundown>/error/fao=0!/ansi=0
TPRESTNESTERR <TP restart signaled while handing error - treated as nested error - Use TROLLBACK in error handler to avoid this>/error/fao=0!/ansi=0
JNLFILRDOPN <Error opening journal file !AD for read for database file !AD>/error/fao=4!/ansi=0
SEQNUMSEARCHTIMEOUT <Timed out trying to find sequence number !@ZQ [0x!16 at XQ] in Journal File(s). See above messages for details. Source server exiting>/error/fao=2!/ansi=0
+FTOKKEY <FTOK key 0x!XL>/info/fao=1!/ansi=0
+SEMID <Semaphore id !UL>/info/fao=1!/ansi=0
+JNLQIOSALVAGE <Journal IO lock salvaged>/info/fao=0!/ansi=0
+FAKENOSPCLEARED <DEBUG: All fake ENOSPC flags were cleared !UL heartbeats ago>/info/fao=1!/ansi=0
+MMFILETOOLARGE <Size of !AD region (!AD) is larger than maximum size supported for memory mapped I/O on this platform>/error/fao=4!/ansi=0
+BADZPEEKARG <Missing, invalid or surplus !AD parameter for $ZPEEK()>/error/fao=2!/ansi=0
+BADZPEEKRANGE <Access exception raised in memory range given to $ZPEEK()>/error/fao=0!/ansi=0
+BADZPEEKFMT <$ZPEEK() value length inappropriate for selected format>/error/fao=0!/ansi=0
+DBMBMINCFREFIXED <Master bitmap incorrectly marks local bitmap 0x!XL as free. Auto-corrected>/warning/fao=1!/ansi=0
+NULLENTRYREF <JOB command did not specify entryref>/error/fao=0!/ansi=0
+ZPEEKNORPLINFO <$ZPEEK() unable to access requested replication structure>/error/fao=0!/ansi=0
+MMREGNOACCESS <Region !AD (!AD) is no longer accessible. See prior error messages in the operator and application error logs>/error/fao=4!/ansi=0
+MALLOCMAXUNIX <Exceeded maximum allocation defined by $gtm_max_storalloc>/error/fao=0!/ansi=0
+MALLOCMAXVMS <Exceeded maximum allocation defined by GTM_MAX_STORALLOC>/error/fao=0!/ansi=0
+HOSTCONFLICT <Host !AD could not open database file !AD because it is marked as already open on node !AD>/error/fao=6!/ansi=0
+GETADDRINFO <Error in getting address info>/error/fao=0!/ansi=0
+GETNAMEINFO <Error in getting name info>/error/fao=0!/ansi=0
+SOCKBIND <Error in binding TCP socket>/error/fao=0!/ansi=0
+INSTFRZDEFER <Instance Freeze initiated by !AD error on region !AD deferred due to critical resource conflict>/info/fao=4!/ansi=0
+REGOPENRETRY <Attempt to open region !AD (!AD) using startup shortcut failed due to conflicting database shutdown. Retrying...>/info/fao=4!/ansi=0
+REGOPENFAIL <Failed to open region !AD (!AD) due to conflicting database shutdown activity>/error/fao=4!/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/mm_read.c b/sr_port/mm_read.c
index 9f4d5da..7c1df66 100644
--- a/sr_port/mm_read.c
+++ b/sr_port/mm_read.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -30,7 +30,7 @@ sm_uc_ptr_t mm_read(block_id blk)
INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_dsk_read, 1);
if (blk < cs_addrs->total_blks) /* use the private copy of total_blks */
- return (cs_addrs->acc_meth.mm.base_addr + (off_t)cs_addrs->hdr->blk_size * blk);
+ return (MM_BASE_ADDR(cs_addrs) + (off_t)cs_addrs->hdr->blk_size * blk);
rdfail_detail = (blk < cs_addrs->ti->total_blks) ? cdb_sc_helpedout : cdb_sc_blknumerr;
return (sm_uc_ptr_t)NULL;
diff --git a/sr_port/mprof_funcs.c b/sr_port/mprof_funcs.c
index c512dad..c80b460 100644
--- a/sr_port/mprof_funcs.c
+++ b/sr_port/mprof_funcs.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -37,7 +37,7 @@
#include "mprof.h"
#include "outofband.h"
#include "op.h"
-#include "lv_val.h" /* needed for "callg.h" */
+#include "lv_val.h" /* Needed for callg.h. */
#include "callg.h"
#include "gtmmsg.h"
#include "str2gvargs.h"
@@ -46,50 +46,64 @@ GBLREF boolean_t is_tracing_on;
GBLREF stack_frame *frame_pointer;
GBLREF mval dollar_job;
GBLREF uint4 process_id;
-GBLREF int * volatile var_on_cstack_ptr; /* volatile so that nothing gets optimized out */
+GBLREF int * volatile var_on_cstack_ptr; /* Volatile so that nothing gets optimized out. */
GBLREF int4 gtm_trigger_depth;
-STATICDEF boolean_t save_to_gbl = TRUE; /* indicates whether profiling info is to be saved to db */
-STATICDEF boolean_t mdb_ch_set; /* indicates whether we can rely on mdb_condition_handler and issue
- * an rts_error */
-STATICDEF gtm_uint64_t child_system, child_user; /* store system and user CPU time for child processes */
-STATICDEF gtm_uint64_t process_system, process_user; /* store system and user CPU time for current process */
-STATICDEF mstr mprof_mstr; /* area to hold global and subscripts */
-STATICDEF boolean_t use_realtime_flag = FALSE; /* indicates whether clock_gettime is unable to use CLOCK_MONOTONIC
- * flag and so should use CLOCK_REALTIME instead */
+STATICDEF boolean_t save_to_gbl = TRUE; /* Indicates whether profiling info is to be saved to db. */
+STATICDEF boolean_t mdb_ch_set; /* Indicates whether we can rely on mdb_condition_handler and issue
+ * an rts_error. */
+STATICDEF gtm_uint64_t child_system, child_user; /* Store system and user CPU time for child processes. */
+STATICDEF gtm_uint64_t process_system, process_user; /* Store system and user CPU time for current process. */
+STATICDEF mstr mprof_mstr; /* Area to hold global and subscripts. */
+STATICDEF boolean_t use_realtime_flag = FALSE; /* Indicates whether clock_gettime is unable to use CLOCK_MONOTONIC
+ * flag and so should use CLOCK_REALTIME instead. */
+#ifdef __osf__
+STATICDEF struct rusage last_usage = {0, 0}; /* Contains the last value obtained via getrusage() on Tru64. */
+#endif
LITDEF MIDENT_CONST(above_routine, "*above*");
-#define CHILDREN_TIME "*CHILDREN" /* label to store CPU time for child processes */
-#define PROCESS_TIME "*RUN" /* label to store CPU time for current process */
+#ifdef DEBUG
+# define RUNTIME_LIMIT 604800000000.0 /* Not a long because on 32-bit platforms longs are only 4 bytes. */
+#endif
+
+#define CHILDREN_TIME "*CHILDREN" /* Label to store CPU time for child processes. */
+#define PROCESS_TIME "*RUN" /* Label to store CPU time for current process. */
#define MPROF_NULL_LABEL "^"
#define MPROF_FOR_LOOP "FOR_LOOP"
-/* on VMS we do not record the child processes' time */
+/* On VMS we do not record the child processes' time. */
#ifdef UNIX
# define TIMES times_usec
# define CHILDREN_TIMES children_times_usec
-# define MPROF_RTS_ERROR(x) rts_error x
+# define MPROF_RTS_ERROR(x) rts_error_csa x
#elif defined(VMS)
# define TIMES get_cputime
# define MPROF_RTS_ERROR(x) \
{ \
if (mdb_ch_set) \
- rts_error x; \
+ rts_error_csa x; \
else \
{ \
- gtm_putmsg x; \
+ gtm_putmsg_csa x; \
exit(EXIT_FAILURE); \
} \
}
#endif
-#define UPDATE_TIME(x) x->e.usr_time += ((TREF(mprof_ptr))->tcurr.tms_utime - (TREF(mprof_ptr))->tprev.tms_utime); \
- x->e.sys_time += ((TREF(mprof_ptr))->tcurr.tms_stime - (TREF(mprof_ptr))->tprev.tms_stime); \
- x->e.elp_time += ((TREF(mprof_ptr))->tcurr.tms_etime - (TREF(mprof_ptr))->tprev.tms_etime);
+#define UPDATE_TIME(x) \
+{ \
+ x->e.usr_time += ((TREF(mprof_ptr))->tcurr.tms_utime - (TREF(mprof_ptr))->tprev.tms_utime); \
+ x->e.sys_time += ((TREF(mprof_ptr))->tcurr.tms_stime - (TREF(mprof_ptr))->tprev.tms_stime); \
+ x->e.elp_time += ((TREF(mprof_ptr))->tcurr.tms_etime - (TREF(mprof_ptr))->tprev.tms_etime); \
+ /* It should be a reasonable assumption that in debug no M process will use more than a week of either user, \
+ * system, or even absolute runtime. \
+ */ \
+ assert((x->e.usr_time < RUNTIME_LIMIT) && (x->e.sys_time < RUNTIME_LIMIT) && (x->e.elp_time < RUNTIME_LIMIT)); \
+}
-#define RTS_ERROR_VIEWNOTFOUND(x) MPROF_RTS_ERROR((VARLSTCNT(8) ERR_VIEWNOTFOUND, 2, gvn->str.len, gvn->str.addr, \
- ERR_TEXT, 2, RTS_ERROR_STRING(x)));
+#define RTS_ERROR_VIEWNOTFOUND(x) MPROF_RTS_ERROR((CSA_ARG(NULL) VARLSTCNT(8) ERR_VIEWNOTFOUND, 2, gvn->str.len, \
+ gvn->str.addr, ERR_TEXT, 2, RTS_ERROR_STRING(x)));
/* do the MPROF initialization */
@@ -107,7 +121,7 @@ LITDEF MIDENT_CONST(above_routine, "*above*");
(TREF(prof_fp))->rout_name = NULL; \
(TREF(prof_fp))->label_name = NULL;
-/* monotonic flag for clock_gettime() is defined differently on every platform */
+/* Monotonic flag for clock_gettime() is defined differently on every platform. */
#ifndef CLOCK_MONOTONIC
# ifdef __sparc
# define CLOCK_MONOTONIC CLOCK_HIGHRES
@@ -117,7 +131,6 @@ LITDEF MIDENT_CONST(above_routine, "*above*");
#endif
error_def(ERR_MAXNRSUBSCRIPTS);
-error_def(ERR_MAXTRACELEVEL);
error_def(ERR_NOTGBL);
error_def(ERR_STRUNXEOR);
error_def(ERR_SYSCALL);
@@ -133,11 +146,30 @@ STATICFNDEF void times_usec(ext_tms *curr)
struct timespec elp_time;
res = getrusage(RUSAGE_SELF, &usage);
- if (res == -1)
- MPROF_RTS_ERROR((VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("getrusage"), CALLFROM, errno));
+ if (-1 == res)
+ MPROF_RTS_ERROR((CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("getrusage"), CALLFROM, errno));
+# ifdef __osf__
+ /* On Tru64 getrusage sometimes fails to increment the seconds value when the microseconds wrap around at 1M. If we detect
+ * this, we make a second call to getrusage if so. A more complete check would be to also verify whether the new seconds
+ * value is less than the previous one, but we anyway have an assert in UPDATE_TIME that would catch that, and our testing
+ * on Tru64 has not shown that type of faulty behavior.
+ */
+ if (((usage.ru_utime.tv_sec == last_usage.ru_utime.tv_sec) && (usage.ru_utime.tv_usec < last_usage.ru_utime.tv_usec))
+ || ((usage.ru_stime.tv_sec == last_usage.ru_stime.tv_sec) && (usage.ru_stime.tv_usec < last_usage.ru_stime.tv_usec)))
+ {
+ DEBUG_ONLY(last_usage = usage);
+ res = getrusage(RUSAGE_SELF, &usage);
+ if (-1 == res)
+ MPROF_RTS_ERROR((CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("getrusage"), CALLFROM, errno));
+ /* In debug also ensure that a subsequent call to getrusage restored the seconds value. */
+ assert((usage.ru_utime.tv_sec > last_usage.ru_utime.tv_sec)
+ || (usage.ru_stime.tv_sec > last_usage.ru_stime.tv_sec));
+ }
+ last_usage = usage;
+# endif
curr->tms_utime = (usage.ru_utime.tv_sec * (gtm_uint64_t)1000000) + usage.ru_utime.tv_usec;
curr->tms_stime = (usage.ru_stime.tv_sec * (gtm_uint64_t)1000000) + usage.ru_stime.tv_usec;
- /* also start recording the elapsed time */
+ /* Also start recording the elapsed time. */
while (TRUE)
{
res = clock_gettime(use_realtime_flag ? CLOCK_REALTIME : CLOCK_MONOTONIC, &elp_time);
@@ -148,7 +180,8 @@ STATICFNDEF void times_usec(ext_tms *curr)
use_realtime_flag = TRUE;
continue;
} else
- MPROF_RTS_ERROR((VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("clock_gettime"), CALLFROM, errno));
+ MPROF_RTS_ERROR((CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5,
+ LEN_AND_LIT("clock_gettime"), CALLFROM, errno));
}
break;
}
@@ -163,7 +196,7 @@ STATICFNDEF void child_times_usec(void)
res = getrusage(RUSAGE_CHILDREN, &usage);
if (res == -1)
- MPROF_RTS_ERROR((VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("getrusage"), CALLFROM, errno));
+ MPROF_RTS_ERROR((CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("getrusage"), CALLFROM, errno));
child_user = (usage.ru_utime.tv_sec * (gtm_uint64_t)1000000) + usage.ru_utime.tv_usec;
child_system = (usage.ru_stime.tv_sec * (gtm_uint64_t)1000000) + usage.ru_stime.tv_usec;
return;
@@ -176,48 +209,47 @@ STATICFNDEF void get_cputime (ext_tms *curr)
int jpi_code = JPI$_CPUTIM;
if ((status = lib$getjpi(&jpi_code, &process_id, 0, &cpu_time_used, 0, 0)) != SS$_NORMAL)
- MPROF_RTS_ERROR((VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("LIB$GETJPI"), CALLFROM, status));
+ MPROF_RTS_ERROR((CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("LIB$GETJPI"), CALLFROM, status));
curr->tms_utime = cpu_time_used;
curr->tms_stime = 0;
return;
}
#endif
-/* Enables tracing and ensures that all critical structures are initialized */
+/* Enables tracing and ensures that all critical structures are initialized. */
void turn_tracing_on(mval *gvn, boolean_t from_env, boolean_t save_gbl)
{
- ext_tms curr;
trace_entry tmp_trc_tbl_entry;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
mdb_ch_set = !from_env;
- /* if tracing is on explicitly, or if it is implicit with saving */
+ /* If tracing is on explicitly, or if it is implicit with saving. */
if (save_gbl || !from_env)
{
if (is_tracing_on)
{
- gtm_putmsg(VARLSTCNT(1) ERR_TRACINGON);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_TRACINGON);
return;
}
if ((0 == gvn->str.len) || ('^' != gvn->str.addr[0]))
- MPROF_RTS_ERROR((VARLSTCNT(4) ERR_NOTGBL, 2, gvn->str.len, gvn->str.addr));
+ MPROF_RTS_ERROR((CSA_ARG(NULL) VARLSTCNT(4) ERR_NOTGBL, 2, gvn->str.len, gvn->str.addr));
}
- /* the following should only be a one-time operation */
+ /* The following should only be a one-time operation. */
if (!TREF(mprof_ptr))
{
TREF(mprof_ptr) = (mprof_wrapper *)malloc(SIZEOF(mprof_wrapper));
memset(TREF(mprof_ptr), 0, SIZEOF(mprof_wrapper));
}
- /* only need to have the gvn if we are going to save the data */
+ /* Only need to have the gvn if we are going to save the data. */
if (save_gbl && (0 < gvn->str.len))
{
parse_gvn(gvn);
(TREF(mprof_ptr))->gbl_to_fill = *gvn;
- (TREF(mprof_ptr))->gbl_to_fill.str.addr = (char *)malloc(gvn->str.len); /* len was already set up */
+ (TREF(mprof_ptr))->gbl_to_fill.str.addr = (char *)malloc(gvn->str.len); /* Since len was already set up. */
memcpy((TREF(mprof_ptr))->gbl_to_fill.str.addr, gvn->str.addr, gvn->str.len);
}
- /* preallocate some space */
+ /* Preallocate some space. */
if (!(TREF(mprof_ptr))->pcavailbase)
{
(TREF(mprof_ptr))->pcavailbase = (char **)malloc(PROFCALLOC_DSBLKSIZE);
@@ -226,13 +258,10 @@ void turn_tracing_on(mval *gvn, boolean_t from_env, boolean_t save_gbl)
(TREF(mprof_ptr))->pcavailptr = (TREF(mprof_ptr))->pcavailbase;
(TREF(mprof_ptr))->pcavail = PROFCALLOC_DSBLKSIZE - OFFSET_LEN;
memset((TREF(mprof_ptr))->pcavailptr + 1, 0, (TREF(mprof_ptr))->pcavail);
- curr = (TREF(mprof_ptr))->tprev;
- TIMES(&curr);
+ TIMES(&(TREF(mprof_ptr))->tprev);
UNIX_ONLY(child_times_usec();)
mprof_stack_init();
- /* if tracing is started explicitly, we are in a good frame, so we can
- * initialize things and start counting time
- */
+ /* If tracing is started explicitly, we are in a good frame, so we can initialize things and start counting time. */
if (!from_env)
{
TREF(prof_fp) = mprof_stack_push();
@@ -240,22 +269,22 @@ void turn_tracing_on(mval *gvn, boolean_t from_env, boolean_t save_gbl)
tmp_trc_tbl_entry.rout_name = NULL;
tmp_trc_tbl_entry.label_name = NULL;
(TREF(mprof_ptr))->curr_tblnd = (TREF(mprof_ptr))->head_tblnd = NULL;
- (TREF(prof_fp))->start.tms_stime = curr.tms_stime;
- (TREF(prof_fp))->start.tms_utime = curr.tms_utime;
- (TREF(prof_fp))->start.tms_etime = curr.tms_etime;
+ (TREF(prof_fp))->start.tms_stime = (TREF(mprof_ptr))->tprev.tms_stime;
+ (TREF(prof_fp))->start.tms_utime = (TREF(mprof_ptr))->tprev.tms_utime;
+ (TREF(prof_fp))->start.tms_etime = (TREF(mprof_ptr))->tprev.tms_etime;
(TREF(prof_fp))->carryover.tms_stime = 0;
(TREF(prof_fp))->carryover.tms_utime = 0;
(TREF(prof_fp))->carryover.tms_etime = 0;
(TREF(prof_fp))->dummy_stack_count = 0;
(TREF(prof_fp))->rout_name = (TREF(prof_fp))->label_name = NULL;
}
- /* make necessary xfer_table substitutions before we begin */
+ /* Make necessary xfer_table substitutions before we begin. */
if (!is_tracing_on)
{
POPULATE_PROFILING_TABLE();
is_tracing_on = TRUE;
}
- /* remember if we need to save results to a global at the end */
+ /* Remember if we need to save results to a global at the end. */
if (!save_gbl)
save_to_gbl = FALSE;
mdb_ch_set = TRUE;
@@ -263,7 +292,7 @@ void turn_tracing_on(mval *gvn, boolean_t from_env, boolean_t save_gbl)
}
/* Disables tracing and properly disposes of allocated resources; additionally,
- * saves data to the database if save_to_gbl was set to TRUE
+ * saves data to the database if save_to_gbl was set to TRUE.
*/
void turn_tracing_off(mval *gvn)
{
@@ -277,7 +306,7 @@ void turn_tracing_off(mval *gvn)
UNIX_ONLY(child_times_usec();)
process_system = (TREF(mprof_ptr))->tcurr.tms_stime;
process_user = (TREF(mprof_ptr))->tcurr.tms_utime;
- /* update the time of previous M line if there was one */
+ /* Update the time of previous M line if there was one. */
if (NULL != (TREF(mprof_ptr))->curr_tblnd)
{
UPDATE_TIME((TREF(mprof_ptr))->curr_tblnd);
@@ -285,8 +314,8 @@ void turn_tracing_off(mval *gvn)
if (NULL != gvn)
parse_gvn(gvn);
assert(!save_to_gbl || (0 != (TREF(mprof_ptr))->gbl_to_fill.str.addr));
- /* if tracing was initialized from an environment variable, and it had a proper global name, save results
- * to that global; otherwise, just toss the collected data
+ /* If tracing was initialized from an environment variable, and it had a proper global name, save results
+ * to that global; otherwise, just toss the collected data.
*/
if (save_to_gbl)
{
@@ -303,7 +332,7 @@ void turn_tracing_off(mval *gvn)
mprof_stack_free();
(TREF(mprof_ptr))->pcavailptr = (TREF(mprof_ptr))->pcavailbase;
(TREF(mprof_ptr))->pcavail = PROFCALLOC_DSBLKSIZE - OFFSET_LEN;
- CLEAR_PROFILING_TABLE(); /* restore the original xfer_table links */
+ CLEAR_PROFILING_TABLE(); /* Restore the original xfer_table links. */
TREF(prof_fp) = NULL;
return;
}
@@ -320,7 +349,7 @@ void forchkhandler(char *return_address)
SETUP_THREADGBL_ACCESS;
get_entryref_information(TRUE, &tmp_trc_tbl_entry);
- /* starting tracing now; save the info about the current FOR loop */
+ /* Starting tracing now; save the info about the current FOR loop. */
if (FALSE == (TREF(mprof_ptr))->is_tracing_ini)
{
(TREF(mprof_ptr))->is_tracing_ini = TRUE;
@@ -335,24 +364,24 @@ void forchkhandler(char *return_address)
(TREF(mprof_ptr))->curr_tblnd =
(mprof_tree *)mprof_tree_insert(&((TREF(mprof_ptr))->head_tblnd), &tmp_trc_tbl_entry);
if (NULL == (TREF(mprof_ptr))->curr_tblnd->loop_link)
- { /* first FOR for this node */
+ { /* First FOR for this node. */
for_node = (mprof_tree *)new_for_node(&tmp_trc_tbl_entry, return_address);
for_node->e.count = 1;
for_node->e.loop_level = 1;
(TREF(mprof_ptr))->curr_tblnd->loop_link = (mprof_tree *)for_node;
return;
}
- /* some FORs have been already recorded for this line, so keep checking for more */
+ /* Some FORs have been already recorded for this line, so keep checking for more. */
for_link = (mprof_tree *)(TREF(mprof_ptr))->curr_tblnd->loop_link;
for_level_on_line = 1;
while (TRUE)
- { /* same FOR, so just update the count */
+ { /* Same FOR, so just update the count. */
if (for_link->e.raddr == return_address)
{
for_link->e.count++;
break;
}
- /* new FOR for this line */
+ /* New FOR for this line. */
if (NULL == for_link->loop_link)
{
for_node = (mprof_tree *)new_for_node(&tmp_trc_tbl_entry, return_address);
@@ -361,7 +390,7 @@ void forchkhandler(char *return_address)
for_link->loop_link = (mprof_tree *)for_node;
break;
} else
- { /* same FOR as last one, so increase the loop level for the line and keep searching */
+ { /* Same FOR as last one, so increase the loop level for the line and keep searching. */
for_link = (mprof_tree *)for_link->loop_link;
for_level_on_line++;
}
@@ -369,9 +398,7 @@ void forchkhandler(char *return_address)
return;
}
-/* Records the typical line-to-line deltas in CPU and absolute time.
- * Called on each linestart and linefetch.
- */
+/* Records the typical line-to-line deltas in CPU and absolute time. Called on each linestart and linefetch. */
void pcurrpos(void)
{
trace_entry tmp_trc_tbl_entry;
@@ -384,8 +411,8 @@ void pcurrpos(void)
}
assert(TREF(mprof_ptr));
assert(TREF(prof_fp));
- TIMES(&(TREF(mprof_ptr))->tcurr); /* remember the new time */
- /* update the time of previous M line */
+ TIMES(&(TREF(mprof_ptr))->tcurr); /* Remember the new time. */
+ /* Update the time of previous M line. */
if (NULL != (TREF(mprof_ptr))->curr_tblnd)
{
UPDATE_TIME((TREF(mprof_ptr))->curr_tblnd);
@@ -444,9 +471,9 @@ void new_prof_frame(int real_frame)
}
assert(TREF(mprof_ptr));
assert(TREF(prof_fp));
- /* a call to a routine, not IF or FOR with a DO */
+ /* A call to a routine, not IF or FOR with a DO. */
if (real_frame)
- { /* update the time of the line in the parent frame */
+ { /* Update the time of the line in the parent frame. */
if (NULL != (TREF(mprof_ptr))->curr_tblnd)
{
TIMES(&(TREF(mprof_ptr))->tcurr);
@@ -454,7 +481,7 @@ void new_prof_frame(int real_frame)
}
(TREF(prof_fp))->curr_node = (TREF(mprof_ptr))->curr_tblnd;
(TREF(mprof_ptr))->curr_tblnd = NULL;
- /* create a new frame on the stack */
+ /* Create a new frame on the stack. */
TREF(prof_fp) = mprof_stack_push();
(TREF(prof_fp))->rout_name = NULL;
(TREF(prof_fp))->label_name = NULL;
@@ -483,35 +510,35 @@ void unw_prof_frame(void)
SETUP_THREADGBL_ACCESS;
assert(TREF(mprof_ptr));
- /* do not assert on prof_fp not being NULL, as it will be NULL in
- * case we quit from a function without ever disabling tracing
+ /* Do not assert on prof_fp not being NULL, as it will be NULL in
+ * case we quit from a function without ever disabling tracing.
*/
if (NULL == TREF(prof_fp))
return;
- /* we are leaving a real frame, not an IF or FOR with a DO */
+ /* We are leaving a real frame, not an IF or FOR with a DO. */
if (0 >= (TREF(prof_fp))->dummy_stack_count)
{
TIMES(&(TREF(mprof_ptr))->tcurr);
- /* update the time of last line in this frame before returning */
+ /* Update the time of last line in this frame before returning. */
if (NULL != (TREF(mprof_ptr))->curr_tblnd)
{
UPDATE_TIME((TREF(mprof_ptr))->curr_tblnd);
}
get_entryref_information(TRUE, &tmp_trc_tbl_entry);
- /* if prof_fp is NULL, it was set so in get_entryref_information, which means
+ /* If prof_fp is NULL, it was set so in get_entryref_information, which means
* that we are not in a valid frame, so there is no point in recording timing for
- * some unreal label; besides, the line timing has already been updated
+ * some unreal label; besides, the line timing has already been updated.
*/
if (NULL == TREF(prof_fp))
return;
if ((TREF(prof_fp))->rout_name == &above_routine)
- { /* it should have been filled in get_entryref_information */
+ { /* It should have been filled in get_entryref_information. */
e.label_name = tmp_trc_tbl_entry.label_name;
e.rout_name = tmp_trc_tbl_entry.rout_name;
} else
- { /* note that this memory allocated for the label and routine names might need
+ { /* Note that this memory allocated for the label and routine names might need
* to be reclaimed, so set up the corresponding flag, reset the allocation count,
- * and the address of the current allocation bucket
+ * and the address of the current allocation bucket.
*/
TREF(mprof_alloc_reclaim) = TRUE;
TREF(mprof_reclaim_addr) = (char *)(TREF(mprof_ptr))->pcavailptr;
@@ -524,16 +551,16 @@ void unw_prof_frame(void)
e.rout_name->len = (TREF(prof_fp))->rout_name->len;
e.rout_name->addr = pcalloc((unsigned int)e.rout_name->len);
memcpy(e.rout_name->addr, (TREF(prof_fp))->rout_name->addr, (TREF(prof_fp))->rout_name->len);
- TREF(mprof_alloc_reclaim) = FALSE; /* memory should not have to be reclaimed after this point,
- * so stop updating the count */
+ TREF(mprof_alloc_reclaim) = FALSE; /* Memory should not have to be reclaimed after this point,
+ * so stop updating the count. */
}
e.line_num = -1;
- /* insert/find a frame entry into/in the MPROF tree, -1 indicating that it is not a
- * real line number, but rather an aggregation of several lines (comprising a label)
+ /* Insert/find a frame entry into/in the MPROF tree, -1 indicating that it is not a
+ * real line number, but rather an aggregation of several lines (comprising a label).
*/
t = mprof_tree_insert(&((TREF(mprof_ptr))->head_tblnd), &e);
- TREF(mprof_reclaim_cnt) = 0; /* reset the memory allocation count */
- /* update count and timing (from prof_fp) of frame I'm leaving */
+ TREF(mprof_reclaim_cnt) = 0; /* Reset the memory allocation count. */
+ /* Update count and timing (from prof_fp) of frame I'm leaving. */
t->e.count++;
frame_usr_time = ((TREF(mprof_ptr))->tcurr.tms_utime
- (TREF(prof_fp))->start.tms_utime - (TREF(prof_fp))->carryover.tms_utime);
@@ -544,21 +571,21 @@ void unw_prof_frame(void)
t->e.usr_time += frame_usr_time;
t->e.sys_time += frame_sys_time;
t->e.elp_time += frame_elp_time;
- /* not the first frame on the stack */
+ /* Not the first frame on the stack. */
if ((TREF(prof_fp))->prev)
{
carryover = (TREF(prof_fp))->carryover;
- /* move back up to parent frame */
+ /* Move back up to parent frame. */
TREF(prof_fp) = mprof_stack_pop();
(TREF(prof_fp))->carryover.tms_utime += (frame_usr_time + carryover.tms_utime);
(TREF(prof_fp))->carryover.tms_stime += (frame_sys_time + carryover.tms_stime);
(TREF(prof_fp))->carryover.tms_etime += (frame_elp_time + carryover.tms_etime);
- /* restore the context of the parent frame */
+ /* Restore the context of the parent frame. */
(TREF(mprof_ptr))->tprev = (TREF(mprof_ptr))->tcurr;
(TREF(mprof_ptr))->curr_tblnd = (TREF(prof_fp))->curr_node;
(TREF(prof_fp))->curr_node = NULL;
} else
- { /* This should only be true only if the View command is not at the top-most stack level, in which case
+ { /* This should only be true only if the VIEW command is not at the top-most stack level, in which case
* add profiling information for the current frame. To prevent stack underflow, add a new frame before
* unwinding from this frame.
*/
@@ -569,15 +596,15 @@ void unw_prof_frame(void)
save_fp = frame_pointer;
# ifdef GTM_TRIGGER
if (frame_pointer->type & SFT_TRIGR)
- { /* in a trigger base frame, old_frame_pointer is NULL */
+ { /* In a trigger base frame, old_frame_pointer is NULL. */
assert(NULL == frame_pointer->old_frame_pointer);
- /* have a trigger baseframe, pick up stack continuation frame_pointer stored by base_frame() */
+ /* Have a trigger baseframe, pick up stack continuation frame_pointer stored by base_frame(). */
frame_pointer = *(stack_frame **)(frame_pointer + 1);
} else
# endif
frame_pointer = frame_pointer->old_frame_pointer;
- /* if frame_pointer is NULL, we are likely dealing with call-ins, so there is no point trying to unwind
- * any further; just restore the frame_pointer and return
+ /* If frame_pointer is NULL, we are likely dealing with call-ins, so there is no point trying to unwind
+ * any further; just restore the frame_pointer and return.
*/
if (!frame_pointer)
{
@@ -586,9 +613,9 @@ void unw_prof_frame(void)
}
get_entryref_information(FALSE, NULL);
frame_pointer = save_fp;
- /* if for some reason we made it all the way here, but prof_fp was still set to NULL by
+ /* If for some reason we made it all the way here, but prof_fp was still set to NULL by
* get_entryref_information(), then just silently quit out of this routine to prevent unwinding into some
- * nowhere land
+ * nowhere land.
*/
if (NULL == TREF(prof_fp))
return;
@@ -596,7 +623,7 @@ void unw_prof_frame(void)
(TREF(prof_fp))->carryover.tms_utime = 0;
(TREF(prof_fp))->carryover.tms_stime = 0;
(TREF(prof_fp))->carryover.tms_etime = 0;
- /* tag it, so that next time it picks up label/routine info from current loc */
+ /* Tag it, so that next time it picks up label/routine info from current loc. */
(TREF(prof_fp))->rout_name = (mident *)&above_routine;
(TREF(prof_fp))->label_name = NULL;
(TREF(prof_fp))->dummy_stack_count = 0;
@@ -606,7 +633,7 @@ void unw_prof_frame(void)
return;
}
-/* Allocate storage for profiling information */
+/* Allocate storage for profiling information. */
char *pcalloc(unsigned int n)
{
char **x;
@@ -614,9 +641,9 @@ char *pcalloc(unsigned int n)
SETUP_THREADGBL_ACCESS;
# if defined (GTM64) || defined(__osf__) || defined(VMS)
- n = ((n + 7) & ~7); /* same logic applied for alignment */
+ n = ((n + 7) & ~7); /* Same logic applied for alignment. */
# else
- n = ((n + 3) & ~3); /* make sure that it is quad-word aligned */
+ n = ((n + 3) & ~3); /* Make sure that it is quad-word aligned. */
# endif
if (n > (TREF(mprof_ptr))->pcavail)
{
@@ -634,7 +661,7 @@ char *pcalloc(unsigned int n)
}
(TREF(mprof_ptr))->pcavail -= n;
if (TREF(mprof_alloc_reclaim))
- (TREF(mprof_reclaim_cnt)) += n; /* update the memory allocation count if needed */
+ (TREF(mprof_reclaim_cnt)) += n; /* Update the memory allocation count if needed. */
assert((TREF(mprof_ptr))->pcavail >= 0);
return (char *)(TREF(mprof_ptr))->pcavailptr + (TREF(mprof_ptr))->pcavail + OFFSET_LEN;
}
@@ -646,13 +673,13 @@ void mprof_reclaim_slots(void)
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
- if (0 < TREF(mprof_reclaim_cnt)) /* in case some memory needs to be reclaimed, do so */
+ if (0 < TREF(mprof_reclaim_cnt)) /* In case some memory needs to be reclaimed, do so. */
{
alloc_diff = (PROFCALLOC_DSBLKSIZE - (TREF(mprof_ptr))->pcavail - OFFSET_LEN);
- if (alloc_diff >= TREF(mprof_reclaim_cnt)) /* allocation did not need a new bucket, we are good */
+ if (alloc_diff >= TREF(mprof_reclaim_cnt)) /* Allocation did not need a new bucket, we are good. */
(TREF(mprof_ptr))->pcavail += TREF(mprof_reclaim_cnt);
else
- { /* go back to the previous allocation bucket and set the pcavail accordingly for the older bucket */
+ { /* Go back to the previous allocation bucket and set the pcavail accordingly for the older bucket. */
(TREF(mprof_ptr))->pcavailptr = (char **)TREF(mprof_reclaim_addr);
(TREF(mprof_ptr))->pcavail = (TREF(mprof_reclaim_cnt) - alloc_diff);
}
@@ -666,9 +693,9 @@ void crt_gbl(mprof_tree *p, boolean_t is_for)
int count, arg_index, subsc_len, tmp_str_len;
INTPTR_T start_point;
mval data;
- char dataval[96]; /* big enough for data value */
- unsigned char subsval[12]; /* see i2asc + 1 for null char */
- unsigned char asc_line_num[12]; /* to hold the ascii equivalent of the line_num */
+ char dataval[96]; /* Big enough for data value. */
+ unsigned char subsval[12]; /* See i2asc + 1 for null char. */
+ unsigned char asc_line_num[12]; /* To hold the ascii equivalent of the line_num. */
unsigned char *tmpnum, *end;
mval *spt;
DCL_THREADGBL_ACCESS;
@@ -678,7 +705,7 @@ void crt_gbl(mprof_tree *p, boolean_t is_for)
return;
count = (int)(TREF(mprof_ptr))->gvargs.count;
spt = &(TREF(mprof_ptr))->subsc[count];
- /* global name --> ^PREFIX(<OPTIONAL ARGUMENTS>, "rout-name", "label-name", "line-num", "forloop") */
+ /* Global name --> ^PREFIX(<OPTIONAL ARGUMENTS>, "rout-name", "label-name", "line-num", "forloop"). */
spt->mvtype = MV_STR;
spt->str.len = p->e.rout_name->len;
spt->str.addr = (char *)pcalloc((unsigned int)spt->str.len);
@@ -691,7 +718,7 @@ void crt_gbl(mprof_tree *p, boolean_t is_for)
spt->str.addr = (char *)pcalloc((unsigned int)spt->str.len);
memcpy(spt->str.addr, p->e.label_name->addr, spt->str.len);
} else
- { /* place holder before first label */
+ { /* Place holder before first label. */
spt->str.len = SIZEOF(MPROF_NULL_LABEL) - 1;
spt->str.addr = (char *)pcalloc((unsigned int)spt->str.len);
memcpy(spt->str.addr, MPROF_NULL_LABEL, spt->str.len);
@@ -708,7 +735,7 @@ void crt_gbl(mprof_tree *p, boolean_t is_for)
count++;
spt++;
}
- /* for FOR loops */
+ /* For FOR loops. */
if (is_for)
{
spt->mvtype = MV_STR;
@@ -716,7 +743,7 @@ void crt_gbl(mprof_tree *p, boolean_t is_for)
spt->str.addr = (char *)pcalloc(SIZEOF(MPROF_FOR_LOOP) - 1);
memcpy(spt->str.addr, MPROF_FOR_LOOP, spt->str.len);
(TREF(mprof_ptr))->gvargs.args[count++] = spt++;
- /* write for level into the subscript as well */
+ /* Write for level into the subscript as well. */
spt->mvtype = MV_STR;
tmpnum = i2asc(subsval, p->e.loop_level);
spt->str.len = INTCAST(tmpnum - subsval);
@@ -727,13 +754,13 @@ void crt_gbl(mprof_tree *p, boolean_t is_for)
(TREF(mprof_ptr))->gvargs.count = count;
callg((INTPTR_T(*)(intszofptr_t count_arg, ...))op_gvname, (gparam_list *)&(TREF(mprof_ptr))->gvargs);
(TREF(mprof_ptr))->gvargs.count = (TREF(mprof_ptr))->curr_num_subscripts;
- /* data --> "count:cpu-time in user mode:cpu-time in sys mode:cpu-time total" */
+ /* Data --> 'count:cpu-time in user mode:cpu-time in sys mode:cpu-time total'. */
start_point = (INTPTR_T)&dataval[0];
/* get count */
tmpnum = (unsigned char *)&dataval[0];
end = i2asc(tmpnum, p->e.count);
tmpnum += ((end - tmpnum) > 0) ? (end - tmpnum) : (tmpnum - end);
- /* for non-FOR stuff get CPU time as well */
+ /* For non-FOR stuff get CPU time as well. */
if (!is_for)
{
*tmpnum = ':';
@@ -764,13 +791,13 @@ void crt_gbl(mprof_tree *p, boolean_t is_for)
return;
}
-/* Save total CPU times for the current and all child processes */
+/* Save total CPU times for the current and all child processes. */
STATICFNDEF void insert_total_times(boolean_t for_process)
{
int count;
INTPTR_T start_point;
mval data;
- char dataval[96]; /* big enough for data value */
+ char dataval[96]; /* Big enough for data value. */
unsigned char *tmpnum, *end;
mval *spt;
DCL_THREADGBL_ACCESS;
@@ -846,7 +873,7 @@ STATICFNDEF void get_entryref_information(boolean_t line, trace_entry *tmp_trc_t
if (fp->type & SFT_TRIGR)
{
assert(NULL == fp->old_frame_pointer);
- /* have a trigger baseframe, pick up stack continuation frame_pointer stored by base_frame() */
+ /* Have a trigger baseframe, pick up stack continuation frame_pointer stored by base_frame(). */
fp = *(stack_frame **)(fp + 1);
}
# endif
@@ -908,21 +935,21 @@ STATICFNDEF void get_entryref_information(boolean_t line, trace_entry *tmp_trc_t
return;
}
-/* Parses the global variable name that the information will be dumped into, to make sure it is a valid gvn */
+/* Parses the global variable name that the information will be dumped into, to make sure it is a valid gvn. */
STATICFNDEF void parse_gvn(mval *gvn)
{
boolean_t dot_seen;
mval *spt;
char *c_top, *c_ref, ch;
unsigned int count = 0;
- char *mpsp; /* pointer into mprof_mstr area */
+ char *mpsp; /* Pointer into mprof_mstr area. */
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
c_ref = gvn->str.addr;
c_top = c_ref + gvn->str.len;
if (!gvn->str.len || ('^' != *c_ref++))
- MPROF_RTS_ERROR((VARLSTCNT(4) ERR_NOTGBL, 2, gvn->str.len, gvn->str.addr));
+ MPROF_RTS_ERROR((CSA_ARG(NULL) VARLSTCNT(4) ERR_NOTGBL, 2, gvn->str.len, gvn->str.addr));
if (mprof_mstr.len < 4 * gvn->str.len)
{ /* We are going to return an array of mvals pointing to global-name and subscript. We should
* never be needing more than 4 * gvn->str.len since the only expandable entity that can be
@@ -938,7 +965,7 @@ STATICFNDEF void parse_gvn(mval *gvn)
mprof_mstr.addr = (char *)malloc(mprof_mstr.len);
}
mpsp = mprof_mstr.addr;
- /* parse the global variable passed to insert the information */
+ /* Parse the global variable passed to insert the information. */
spt = &(TREF(mprof_ptr))->subsc[0];
spt->mvtype = MV_STR;
spt->str.addr = mpsp;
@@ -954,7 +981,7 @@ STATICFNDEF void parse_gvn(mval *gvn)
spt->str.len = INTCAST(mpsp - spt->str.addr);
(TREF(mprof_ptr))->gvargs.args[count++] = spt++;
spt->str.addr = (char *)mpsp;
- /* process subscripts, if any */
+ /* Process subscripts, if any. */
if (c_ref++ < c_top)
{
for ( ; c_ref < c_top; )
@@ -983,7 +1010,7 @@ STATICFNDEF void parse_gvn(mval *gvn)
RTS_ERROR_VIEWNOTFOUND("Intrinsic value is incomplete");
if (*c_ref != 'J' && *c_ref != 'j')
RTS_ERROR_VIEWNOTFOUND("Intrinsic value passed is not $j");
- c_ref++; /* past 'J' */
+ c_ref++; /* Past 'J'. */
if ((c_ref < c_top) && (ISALPHA_ASCII(*c_ref)))
{
ch = *c_ref;
@@ -997,7 +1024,7 @@ STATICFNDEF void parse_gvn(mval *gvn)
} else
RTS_ERROR_VIEWNOTFOUND("Intrinsic value is incomplete");
}
- assert(10 > dollar_job.str.len); /* to take care of 4 * gvn->str.len allocation above */
+ assert(10 > dollar_job.str.len); /* To take care of 4 * gvn->str.len allocation above. */
memcpy(mpsp, dollar_job.str.addr, dollar_job.str.len);
mpsp += dollar_job.str.len;
} else
@@ -1033,7 +1060,7 @@ STATICFNDEF void parse_gvn(mval *gvn)
}
spt->str.len = INTCAST(mpsp - spt->str.addr);
if (MAX_GVSUBSCRIPTS <= count)
- MPROF_RTS_ERROR((VARLSTCNT(1) ERR_MAXNRSUBSCRIPTS));
+ MPROF_RTS_ERROR((CSA_ARG(NULL) VARLSTCNT(1) ERR_MAXNRSUBSCRIPTS));
(TREF(mprof_ptr))->gvargs.args[count++] = spt++;
if (',' != *c_ref)
break;
@@ -1048,7 +1075,7 @@ STATICFNDEF void parse_gvn(mval *gvn)
if (++c_ref < c_top)
RTS_ERROR_VIEWNOTFOUND("There are trailing characters after the global name");
}
- assert((char *)mpsp <= mprof_mstr.addr + mprof_mstr.len); /* ensure we haven't overrun the malloced buffer */
+ assert((char *)mpsp <= mprof_mstr.addr + mprof_mstr.len); /* Ensure we haven't overrun the malloced buffer. */
(TREF(mprof_ptr))->gvargs.count = count;
(TREF(mprof_ptr))->curr_num_subscripts = (int)(TREF(mprof_ptr))->gvargs.count;
return;
@@ -1067,10 +1094,10 @@ void stack_leak_check(void)
if (NULL == var_on_cstack_ptr)
var_on_cstack_ptr = &var_on_cstack;
if ((&var_on_cstack != var_on_cstack_ptr)
-# ifdef __i386 /* for 32-bit Linux allow a two pointer variation to accommodate ZHELP */
- && ((SIZEOF(var_on_cstack) * 2) < ABS(&var_on_cstack - var_on_cstack_ptr))
-# endif
- )
- GTMASSERT;
+# ifdef __i386 /* For 32-bit Linux allow a two pointer variation to accommodate ZHELP. */
+ && ((SIZEOF(var_on_cstack) * 2) < ABS(&var_on_cstack - var_on_cstack_ptr))
+# endif
+ )
+ assertpro(FALSE);
return;
}
diff --git a/sr_port/mprof_tree.c b/sr_port/mprof_tree.c
index f4b3b29..3b49bfa 100644
--- a/sr_port/mprof_tree.c
+++ b/sr_port/mprof_tree.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -64,7 +64,7 @@ mprof_tree *new_node(trace_entry *arg)
tree->e.rout_name = arg->rout_name;
tree->e.label_name = arg->label_name;
tree->e.line_num = arg->line_num;
- tree->e.count = tree->e.usr_time = tree->e.sys_time = tree->e.loop_level = 0;
+ tree->e.count = tree->e.usr_time = tree->e.sys_time = tree->e.elp_time = tree->e.loop_level = 0;
tree->e.raddr = NULL;
tree->link[LEFT] = tree->link[RIGHT] = tree->loop_link = NULL;
tree->desc_dir = NEITHER;
diff --git a/sr_port/mtables.c b/sr_port/mtables.c
index f2b7c38..97f5c5e 100644
--- a/sr_port/mtables.c
+++ b/sr_port/mtables.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -37,6 +37,7 @@
# include "trigger.h"
# include "gv_trigger.h"
#endif
+#include "mtables.h"
LITDEF char ctypetab[NUM_CHARS] =
{
@@ -174,14 +175,14 @@ LITDEF boolean_t mvs_save[] =
TRUE, /* MVST_STAB */
FALSE, /* MVST_IARR */
TRUE, /* MVST_NTAB */
- FALSE, /* MVST_ZINTCMD */
+ TRUE, /* MVST_ZINTCMD */
TRUE, /* MVST_PVAL */
FALSE, /* MVST_STCK */
TRUE, /* MVST_NVAL */
TRUE, /* MVST_TVAL */
TRUE, /* MVST_TPHOLD */
TRUE, /* MVST_ZINTR */
- FALSE, /* MVST_ZINTDEV */
+ TRUE, /* MVST_ZINTDEV */
TRUE, /* MVST_STCK_SP */
TRUE, /* MVST_LVAL */
FALSE, /* MVST_TRIGR */
@@ -953,4 +954,13 @@ LITDEF char vxi_opcode[][6] =
"CVTHD "
};
+/* Routine invoked in debug mode by init_gtm() on UNIX to verify certain assumptions about some of the
+ * tables in this routine. Routine must be resident in this module to do these checks since dimensions
+ * are not known in other routines using a LITREF.
+ */
+void mtables_chk(void)
+{
+ assert(SIZEOF(mvs_size) == (MVST_LAST + 1));
+ assert(SIZEOF(mvs_save) == (SIZEOF(boolean_t) * (MVST_LAST + 1)));
+}
#endif
diff --git a/sr_port/mtables.h b/sr_port/mtables.h
new file mode 100644
index 0000000..b3a6654
--- /dev/null
+++ b/sr_port/mtables.h
@@ -0,0 +1,16 @@
+/****************************************************************
+ * *
+ * Copyright 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+#ifndef MTABLE_H_DEFINED
+#define MTABLE_H_DEFINED
+
+void mtables_chk(void); /* Routine invoked in debug builds to check some mtable assertions */
+
+#endif
diff --git a/sr_port/mu_clsce.c b/sr_port/mu_clsce.c
index 5bdddc7..9a60d6d 100644
--- a/sr_port/mu_clsce.c
+++ b/sr_port/mu_clsce.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -181,7 +181,8 @@ enum cdb_sc mu_clsce(int level, int i_max_fill, int d_max_fill, kill_set *kill_s
old_levelp_cur_keysz = uncompressed size of the key
old_levelp_cur_keylen = compressed size of the key
*/
- READ_RECORD(levelp, rec_base, tkeycmpc, rec_size, &old_levelp_cur_key[0], old_levelp_cur_keylen, status);
+ READ_RECORD(status, &rec_size, &tkeycmpc, &old_levelp_cur_keylen, old_levelp_cur_key,
+ levelp, old_levelp_blk_base, rec_base);
if (cdb_sc_normal != status)
{
assert(t_tries < CDB_STAGNATE);
@@ -198,8 +199,9 @@ enum cdb_sc mu_clsce(int level, int i_max_fill, int d_max_fill, kill_set *kill_s
old_levelp_cur_next_keylen = comressed size of the key
Note: we may not have a next key (old_levelp_cur_next_keysz = 0)
*/
- BLK_ADDR(old_levelp_cur_next_key, gv_cur_region->max_key_size + 1, unsigned char);
- READ_RECORD(levelp, rec_base, tkeycmpc, rec_size, old_levelp_cur_next_key, old_levelp_cur_next_keylen, status);
+ BLK_ADDR(old_levelp_cur_next_key, MAX_KEY_SZ + 1, unsigned char);
+ READ_RECORD(status, &rec_size, &tkeycmpc, &old_levelp_cur_next_keylen, old_levelp_cur_next_key,
+ levelp, old_levelp_blk_base, rec_base);
if (cdb_sc_starrecord == status)
levelp_next_is_star = TRUE;
else if (cdb_sc_normal != status)
@@ -222,7 +224,7 @@ enum cdb_sc mu_clsce(int level, int i_max_fill, int d_max_fill, kill_set *kill_s
oldblk1_last_cmpc = compression count of last key of working block
old_last_rec_hdr1 = New working index block's last record header
*/
- BLK_ADDR(oldblk1_last_key, gv_cur_region->max_key_size + 1, unsigned char);
+ BLK_ADDR(oldblk1_last_key, MAX_KEY_SZ + 1, unsigned char);
if (0 == level) /* data block */
{
if (cdb_sc_normal != (status = gvcst_expand_any_key (old_blk1_base, old_blk1_base + old_blk1_sz,
@@ -248,7 +250,7 @@ enum cdb_sc mu_clsce(int level, int i_max_fill, int d_max_fill, kill_set *kill_s
assert(t_tries < CDB_STAGNATE);
return cdb_sc_blkmod;
}
- GET_CMPC(oldblk1_last_cmpc, &oldblk1_prev_key[0], &old_levelp_cur_key[0]);
+ GET_CMPC(oldblk1_last_cmpc, oldblk1_prev_key, old_levelp_cur_key);
oldblk1_last_keylen = old_levelp_cur_keysz - oldblk1_last_cmpc;
}
else /* working block has a *-key record only */
@@ -271,9 +273,10 @@ enum cdb_sc mu_clsce(int level, int i_max_fill, int d_max_fill, kill_set *kill_s
complete_merge = TRUE, rtsib can be completely merged with working block
piece_len = Size of data from old rtsibling to be merged into working block (includes rec_hdr size)
*/
- BLK_ADDR(newblk1_last_key, gv_cur_region->max_key_size + 1, unsigned char);
+ BLK_ADDR(newblk1_last_key, MAX_KEY_SZ + 1, unsigned char);
rec_base = old_blk2_base + SIZEOF(blk_hdr);
- READ_RECORD(level, rec_base, newblk1_last_cmpc, rec_size, newblk1_last_key, newblk1_last_keylen, status);
+ READ_RECORD(status, &rec_size, &newblk1_last_cmpc, &newblk1_last_keylen, newblk1_last_key,
+ level, old_blk2_base, rec_base);
if (cdb_sc_starrecord == status) /* rtsib index block has *-record only */
{
if (old_blk1_sz + oldblk1_last_keylen + BSTAR_REC_SIZE > i_max_fill ) /* cannot fit even one record */
@@ -328,10 +331,11 @@ enum cdb_sc mu_clsce(int level, int i_max_fill, int d_max_fill, kill_set *kill_s
complete_merge = FALSE;
break;
}
- READ_RECORD(level, rec_base, newblk1_last_cmpc, rec_size, newblk1_last_key, newblk1_last_keylen, status);
+ READ_RECORD(status, &rec_size, &newblk1_last_cmpc, &newblk1_last_keylen, newblk1_last_key,
+ level, old_blk2_base, rec_base);
if (cdb_sc_normal != status)
{
- assert(t_tries < CDB_STAGNATE);;
+ assert(t_tries < CDB_STAGNATE);
return cdb_sc_blkmod;
}
newblk1_last_keysz = newblk1_last_keylen + newblk1_last_cmpc;
@@ -354,11 +358,11 @@ enum cdb_sc mu_clsce(int level, int i_max_fill, int d_max_fill, kill_set *kill_s
piece_len += rec_size;
break; /* already we know we can fit this *-record in working block */
}
- READ_RECORD(level, rec_base, newblk1_last_cmpc, rec_size,
- newblk1_last_key, newblk1_last_keylen, status);
+ READ_RECORD(status, &rec_size, &newblk1_last_cmpc, &newblk1_last_keylen, newblk1_last_key,
+ level, old_blk2_base, rec_base);
if (cdb_sc_normal != status)
{
- assert(t_tries < CDB_STAGNATE);;
+ assert(t_tries < CDB_STAGNATE);
return cdb_sc_blkmod;
}
newblk1_last_keysz = newblk1_last_keylen + newblk1_last_cmpc;
@@ -384,14 +388,14 @@ enum cdb_sc mu_clsce(int level, int i_max_fill, int d_max_fill, kill_set *kill_s
new_blk2_remain = base pointer of buffer including 1st record but exclude rec_header and key
new_blk2_first_keysz = size of new rtsib block's first key
*/
- BLK_ADDR(newblk2_first_key, gv_cur_region->max_key_size + 1, unsigned char);
- READ_RECORD(level, new_blk2_first_rec_base, tkeycmpc, rec_size,
- newblk2_first_key, newblk2_first_keylen, status);
+ BLK_ADDR(newblk2_first_key, MAX_KEY_SZ + 1, unsigned char);
+ READ_RECORD(status, &rec_size, &tkeycmpc, &newblk2_first_keylen, newblk2_first_key,
+ level, old_blk2_base, new_blk2_first_rec_base);
if (cdb_sc_starrecord == status) /* new rtsib will have a *-record only */
new_rtsib_star_only = TRUE;
else if (cdb_sc_normal != status)
{
- assert(t_tries < CDB_STAGNATE);;
+ assert(t_tries < CDB_STAGNATE);
return cdb_sc_blkmod;
} else
{
@@ -430,12 +434,13 @@ enum cdb_sc mu_clsce(int level, int i_max_fill, int d_max_fill, kill_set *kill_s
blk2_ances_hdr = new rtsib's ancestor's 1st record's header
*/
delete_all_blk2_ances = FALSE;
- BLK_ADDR(new_blk2_ances_first_key, gv_cur_region->max_key_size + 1, unsigned char);
+ BLK_ADDR(new_blk2_ances_first_key, MAX_KEY_SZ + 1, unsigned char);
rec_base = blk2ptr->h[level2].buffaddr + SIZEOF(blk_hdr);
- READ_RECORD(level2, rec_base, tkeycmpc, rec_size, new_blk2_ances_first_key, tkeylen, status);
+ READ_RECORD(status, &rec_size, &tkeycmpc, &tkeylen, new_blk2_ances_first_key,
+ level2, blk2ptr->h[level2].buffaddr, rec_base);
if (cdb_sc_normal != status)
{
- assert(t_tries < CDB_STAGNATE);;
+ assert(t_tries < CDB_STAGNATE);
return cdb_sc_blkmod;
}
/* newblk1_last_key was the last key before *-key.
@@ -446,7 +451,8 @@ enum cdb_sc mu_clsce(int level, int i_max_fill, int d_max_fill, kill_set *kill_s
memcpy(newblk1_last_key, new_blk2_ances_first_key, newblk1_last_keysz);
/* 2nd record will become 1st record of current block at level2 */
rec_base += rec_size;
- READ_RECORD(level2, rec_base, tkeycmpc, rec_size, new_blk2_ances_first_key, tkeylen, status);
+ READ_RECORD(status, &rec_size, &tkeycmpc, &tkeylen, new_blk2_ances_first_key,
+ level2, blk2ptr->h[level2].buffaddr, rec_base);
blk2_ances_remain = rec_base + rec_size - SIZEOF(block_id);
if (cdb_sc_starrecord == status)
blk2_ances_star_only = TRUE;
@@ -466,19 +472,6 @@ enum cdb_sc mu_clsce(int level, int i_max_fill, int d_max_fill, kill_set *kill_s
} /* end for level2 */
} /* end if/else complete_merge */
- /* for following case newblk1_last_key is the 2nd last key. old_levelp_cur_next_key can be taken as last key */
- /*
- if (delete_all_blk2_ances && complete_merge && !levelp_next_is_star)
- {
- GET_CMPC(newblk1_last_cmpc, newblk1_last_key, &old_levelp_cur_next_key[0]);
- newblk1_last_keysz = old_levelp_cur_next_keysz;
- newblk1_last_keylen = newblk1_last_keysz - newblk1_last_cmpc;
- newblk1_last_key = old_levelp_cur_next_key;
- }
- */
- /* else if (delete_all_blk2_ances && complete_merge && levelp_next_is_star),
- we do not need newblk1_last_key's real value */
-
/*
new_levelp_cur_hdr = new ancestor level curr_key header
new_levelp_cur_keylen = new ancestor level curr_key length
@@ -493,7 +486,7 @@ enum cdb_sc mu_clsce(int level, int i_max_fill, int d_max_fill, kill_set *kill_s
new_levelp_cur_keylen = newblk1_last_keysz;
} else /* If the previous record exists */
{
- GET_CMPC(new_levelp_cur_cmpc, &old_levelp_cur_prev_key[0], newblk1_last_key);
+ GET_CMPC(new_levelp_cur_cmpc, old_levelp_cur_prev_key, newblk1_last_key);
new_levelp_cur_keylen = newblk1_last_keysz - new_levelp_cur_cmpc;
}
/*
@@ -530,7 +523,7 @@ enum cdb_sc mu_clsce(int level, int i_max_fill, int d_max_fill, kill_set *kill_s
new_levelp_cur_next_keylen = old_levelp_cur_next_keysz;
} else /* If the previous record exists */
{
- GET_CMPC(new_levelp_cur_next_cmpc, &old_levelp_cur_prev_key[0], old_levelp_cur_next_key);
+ GET_CMPC(new_levelp_cur_next_cmpc, old_levelp_cur_prev_key, old_levelp_cur_next_key);
new_levelp_cur_next_keylen = old_levelp_cur_next_keysz - new_levelp_cur_next_cmpc;
}
}
diff --git a/sr_port/mu_extr_gblout.c b/sr_port/mu_extr_gblout.c
index b3c0857..a765db9 100644
--- a/sr_port/mu_extr_gblout.c
+++ b/sr_port/mu_extr_gblout.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -45,10 +45,10 @@
#endif
#include "gvcst_protos.h"
-#define INTEG_ERROR_RETURN \
-{ \
- gtm_putmsg(VARLSTCNT(4) ERR_EXTRFAIL, 2, gn->str.len, gn->str.addr); \
- return FALSE; \
+#define INTEG_ERROR_RETURN \
+{ \
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_EXTRFAIL, 2, gn->str.len, gn->str.addr); \
+ return FALSE; \
}
GBLREF bool mu_ctrlc_occurred;
@@ -63,8 +63,6 @@ GBLREF sgmnt_data_ptr_t cs_data;
error_def(ERR_EXTRFAIL);
error_def(ERR_RECORDSTAT);
-STATICDEF readonly unsigned char gt_lit[] = "TOTAL";
-
#if defined(UNIX) && defined(GTM_CRYPT)
boolean_t mu_extr_gblout(mval *gn, mu_extr_stats *st, int format, muext_hash_hdr_ptr_t hash_array,
boolean_t is_any_file_encrypted)
@@ -158,7 +156,7 @@ boolean_t mu_extr_gblout(mval *gn, struct RAB *outrab, mu_extr_stats *st, int fo
return FALSE;
if (mu_ctrlc_occurred)
{
- gtm_putmsg(VARLSTCNT(8) ERR_RECORDSTAT, 6, LEN_AND_LIT(gt_lit),
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) ERR_RECORDSTAT, 6, LEN_AND_LIT("TOTAL"),
st->recknt, st->keylen, st->datalen, st->reclen);
mu_ctrlc_occurred = FALSE;
}
diff --git a/sr_port/mu_int_fhead.c b/sr_port/mu_int_fhead.c
index 4921f55..f5135c7 100644
--- a/sr_port/mu_int_fhead.c
+++ b/sr_port/mu_int_fhead.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -54,7 +54,6 @@ error_def(ERR_DBTTLBLK0);
error_def(ERR_DBTNNEQ);
error_def(ERR_DBMAXKEYEXC);
error_def(ERR_DBMXRSEXCMIN);
-error_def(ERR_DBMAXRSEXBL);
error_def(ERR_DBUNDACCMT);
error_def(ERR_DBHEADINV);
error_def(ERR_DBFGTBC);
diff --git a/sr_port/mu_int_reg.c b/sr_port/mu_int_reg.c
index ef5a1bb..d626c42 100644
--- a/sr_port/mu_int_reg.c
+++ b/sr_port/mu_int_reg.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -122,13 +122,6 @@ void mu_int_reg(gd_region *reg, boolean_t *return_value)
}
}
# endif
- if (dba_mm == cs_data->acc_meth && read_only)
- {
- util_out_print("!/MM database is read only. MM database cannot be frozen without write access.", TRUE);
- gtm_putmsg(VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(gv_cur_region));
- mu_int_skipreg_cnt++;
- return;
- }
assert(NULL != mu_int_master);
/* Ensure that we don't see an increase in the file header and master map size compared to it's maximum values */
assert(SGMNT_HDR_LEN >= SIZEOF(sgmnt_data) && (MASTER_MAP_SIZE_MAX >= MASTER_MAP_SIZE(cs_data)));
@@ -175,7 +168,7 @@ void mu_int_reg(gd_region *reg, boolean_t *return_value)
default:
assert(FALSE);
}
- if (read_only && !mu_int_wait_rdonly(csa, MUPIP_INTEG))
+ if (read_only && (dba_bg == csa->hdr->acc_meth) && !mu_int_wait_rdonly(csa, MUPIP_INTEG))
{
mu_int_skipreg_cnt++;
return;
diff --git a/sr_port/mu_reorg.c b/sr_port/mu_reorg.c
index 73424a4..9a91804 100644
--- a/sr_port/mu_reorg.c
+++ b/sr_port/mu_reorg.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -128,7 +128,7 @@ error_def(ERR_MUREORGFAIL);
ABORT_TRANS_IF_GBL_EXIST_NOMORE(LCL_T_TRIES, tn_aborted); \
if (tn_aborted) \
{ \
- gtm_putmsg(VARLSTCNT(4) ERR_GBLNOEXIST, 2, gn->str.len, gn->str.addr); \
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_GBLNOEXIST, 2, gn->str.len, gn->str.addr); \
reorg_finish(dest_blk_id, blks_processed, blks_killed, blks_reused, file_extended, lvls_reduced, blks_coalesced,\
blks_split, blks_swapped); \
return TRUE; /* It is not an error if the global (that once existed) doesn't exist anymore (due to ROLLBACK) */ \
@@ -254,13 +254,18 @@ boolean_t mu_reorg(mval *gn, glist *exclude_glist_ptr, boolean_t *resume, int in
SETUP_TRIGGER_GLOBAL;
INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
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, gn->str.len, gn->str.addr, REG_LEN_STR(gv_cur_region));
+ }
} else
# endif /* Initialization for current global */
op_gvname(VARLSTCNT(1) gn);
/* Cannot proceed for read-only data files */
if (gv_cur_region->read_only)
{
- gtm_putmsg(VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(gv_cur_region));
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(gv_cur_region));
return FALSE;
}
if (0 == gv_target->root)
@@ -275,7 +280,7 @@ boolean_t mu_reorg(mval *gn, glist *exclude_glist_ptr, boolean_t *resume, int in
if (*resume && 0 != cs_data->reorg_restart_key[0])
{
/* resume from last key reorged in GVT */
- GET_KEY_LEN(tkeysize, &cs_data->reorg_restart_key[0]);
+ tkeysize = get_key_len(NULL, &cs_data->reorg_restart_key[0]);
memcpy(gv_currkey->base, cs_data->reorg_restart_key, tkeysize);
gv_currkey->end = tkeysize - 1;
dest_blk_id = cs_data->reorg_restart_block;
@@ -370,7 +375,8 @@ boolean_t mu_reorg(mval *gn, glist *exclude_glist_ptr, boolean_t *resume, int in
status = mu_split(level, i_max_fill, d_max_fill, &cnt1, &cnt2);
if (cdb_sc_maxlvl == status)
{
- gtm_putmsg(VARLSTCNT(4) ERR_MAXBTLEVEL, 2, gn->str.len, gn->str.addr);
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_MAXBTLEVEL, 2, gn->str.len,
+ gn->str.addr);
reorg_finish(dest_blk_id, blks_processed, blks_killed, blks_reused,
file_extended, lvls_reduced, blks_coalesced, blks_split, blks_swapped);
return FALSE;
@@ -499,7 +505,8 @@ boolean_t mu_reorg(mval *gn, glist *exclude_glist_ptr, boolean_t *resume, int in
* here gv_currkey_next_reorg will be set from right sibling
*/
cw_set_depth = cw_map_depth = 0;
- GET_KEY_LEN(tkeysize, rtsib_hist->h[0].buffaddr + SIZEOF(blk_hdr) + SIZEOF(rec_hdr));
+ tkeysize = get_key_len(rtsib_hist->h[0].buffaddr, rtsib_hist->h[0].buffaddr
+ + SIZEOF(blk_hdr) + SIZEOF(rec_hdr));
if (2 < tkeysize && MAX_KEY_SZ >= tkeysize)
{
memcpy(&(gv_currkey_next_reorg->base[0]), rtsib_hist->h[0].buffaddr
diff --git a/sr_port/mu_reorg.h b/sr_port/mu_reorg.h
index 973173a..03755fb 100644
--- a/sr_port/mu_reorg.h
+++ b/sr_port/mu_reorg.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -25,9 +25,6 @@
#define DATA_FILL_TOLERANCE 10
#define INDEX_FILL_TOLERANCE 10
-/* On UNIX, keys with hidden subscripts are allowed in the database. */
-#define REORG_KEY_SZ_LIMIT (gv_cur_region->max_key_size UNIX_ONLY( + SPAN_SUBS_LEN + 1))
-
/*********************************************************************
block_number is used for swap
*********************************************************************/
@@ -40,111 +37,51 @@
/* DECR_BLK_NUM has no check for bit-map because it is always followed by INCR_BLK_NUM */
#define DECR_BLK_NUM(block_number) (block_number)--
-/*********************************************************************
- Get global variable length.
- Start scanning from KEY_BASE.
- rPtr1 = unsigned char pointer already defined
- KEY_BASE = where to start scan
- KEY_LEN = length found
- **********x**********************************************************/
-#define GET_GBLNAME_LEN(KEY_LEN, KEY_BASE) \
-{ \
- for (rPtr1 = (KEY_BASE); ; ) \
- { \
- if (0 == *rPtr1++) \
- break; \
- } \
- KEY_LEN = (int)(rPtr1 - (KEY_BASE)); \
-}
+/*
+ * If INVALID_RECORD evaluates to TRUE, it means some necessary record/key relations are incongruent, and we cannot proceed
+ * with update array calculations. Restart.
+ * Input:
+ * LEVEL := level of current block
+ * REC_SIZE := record size
+ * KEYLEN := key length
+ * KEYCMPC := key compression count
+ */
+#define INVALID_RECORD(LEVEL, REC_SIZE, KEYLEN, KEYCMPC) \
+ ( (MAX_KEY_SZ < ((int)(KEYLEN) + (KEYCMPC))) \
+ || (BSTAR_REC_SIZE > ((REC_SIZE) + (0 == (LEVEL) ? 1 : 0))) \
+ || ((0 == (LEVEL)) && (2 >= (KEYLEN))) \
+ )
-/**********************************************************************
- Get key length scanning from key_base.
- rPtr1 = unsigned char pointer already defined
- KEY_BASE = where to start scan
- KEY_LEN = length returned
- **********************************************************************/
-#define GET_KEY_LEN(KEY_LEN, KEY_BASE) \
-{ \
- for (rPtr1 = (KEY_BASE); ; ) \
- { \
- if ((0 == *rPtr1++) && (0 == *rPtr1)) \
- break; \
- } \
- KEY_LEN = (int)(rPtr1 + 1 - (KEY_BASE)); \
-}
+/* Key allocation better be big enough. We can check array sizes, so we do. But we can't check arbitrary pointers, so if a pointer
+ * is passed to DBG_CHECK_KEY_ALLOCATION_SIZE, we ignore it. The complication below is for distinguishing arrays from pointers
+ * on Tru64, where pointers can be either 32-bit or 64-bit.
+ */
+#if defined(__osf__) && defined(DEBUG)
+# pragma pointer_size(save)
+# pragma pointer_size(long)
+typedef char *dbg_osf_long_char_ptr_t; /* 64-bit */
+# pragma pointer_size(short)
+typedef char *dbg_osf_short_char_ptr_t; /* 32-bit */
+# pragma pointer_size(restore)
+# define DBG_CHECK_KEY_ALLOCATION_SIZE(KEY) assert((MAX_KEY_SZ < ARRAYSIZE((KEY))) \
+ || (SIZEOF(dbg_osf_long_char_ptr_t) == SIZEOF((KEY))) || (SIZEOF(dbg_osf_short_char_ptr_t) == SIZEOF((KEY))))
+#else /* normal platforms; non-Tru64 */
+typedef char *dbg_osf_long_char_ptr_t;
+typedef char *dbg_osf_short_char_ptr_t;
+# define DBG_CHECK_KEY_ALLOCATION_SIZE(KEY) assert((MAX_KEY_SZ < ARRAYSIZE((KEY))) || (SIZEOF(char_ptr_t) == SIZEOF((KEY))))
+#endif
-/***********************************************************************
- Get compression count of SECOND_KEY with resprect to FIRST_KEY
- CMPC = returned compression count
- rPtr1, rPtr2 are unsigned character pointer defined earlier
- ************************************************************************/
-#define GET_CMPC(CMPC, FIRST_KEY, SECOND_KEY) \
-{ \
- CMPC = 0; \
- if ((FIRST_KEY) != (SECOND_KEY)) \
- { \
- for (rPtr1 = (FIRST_KEY), rPtr2 = (SECOND_KEY); \
- CMPC < MAX_KEY_SZ; \
- (CMPC)++) \
- { \
- if (*rPtr1++ != *rPtr2++) \
- break; \
- } \
- } \
+#define GET_CMPC(KEY_CMPC, FIRST_KEY, SECOND_KEY) \
+{ \
+ DBG_CHECK_KEY_ALLOCATION_SIZE(FIRST_KEY); \
+ DBG_CHECK_KEY_ALLOCATION_SIZE(SECOND_KEY); \
+ KEY_CMPC = get_cmpc(FIRST_KEY, SECOND_KEY); \
}
-/************************************************************************
- validate a reocrd from
- LEVEL, REC_SIZE, KEYLEN and KEYCMPC
- ************************************************************************/
-#define INVALID_RECORD(LEVEL, REC_SIZE, KEYLEN, KEYCMPC) \
- (( ((0 == (LEVEL)) && (2 >= (KEYLEN)) ) || \
- (BSTAR_REC_SIZE > ((REC_SIZE) + (0 == (LEVEL) ? 1 : 0)) ) || \
- (REORG_KEY_SZ_LIMIT < ((int)(KEYLEN) + (KEYCMPC))) ) \
- ? TRUE:FALSE )
-
-/*************************************************************************
- Process a record and read.
- Input Parameter:
- LEVEL = where reading
- REC_BASE = Starting address of record
- Output Parameter:
- KEY_CMPC = Key compression count
- REC_SIZE = record size
- KEY = pointer to key read
- KEY_LEN = Key length
- STATUS = Status of read
- *************************************************************************/
-#define READ_RECORD(LEVEL, REC_BASE, KEY_CMPC, REC_SIZE, KEY, KEY_LEN, STATUS) \
-{ \
- int tmp_cmpc; \
- \
- GET_USHORT(temp_ushort, &(((rec_hdr_ptr_t)(REC_BASE))->rsiz)); \
- REC_SIZE = temp_ushort; \
- KEY_CMPC = EVAL_CMPC((rec_hdr_ptr_t)(REC_BASE)); \
- if (0 != (LEVEL) && BSTAR_REC_SIZE == (REC_SIZE)) \
- { \
- KEY_LEN = 0; \
- STATUS = cdb_sc_starrecord; \
- } \
- else \
- { \
- for (rPtr1 = (KEY) + KEY_CMPC, rPtr2 = (REC_BASE) + SIZEOF(rec_hdr); \
- (REORG_KEY_SZ_LIMIT - 1) > (rPtr2 - (REC_BASE) - SIZEOF(rec_hdr)) && \
- (REORG_KEY_SZ_LIMIT - 1) > (rPtr1 - (KEY)) ;) \
- { \
- if ((0 == (*rPtr1++ = *rPtr2++)) && (0 == *rPtr2)) \
- break; \
- } \
- *rPtr1++ = *rPtr2++; \
- KEY_LEN = (int)(rPtr2 - (REC_BASE) - SIZEOF(rec_hdr)); \
- if ((REORG_KEY_SZ_LIMIT < ((int)(KEY_LEN)+ (KEY_CMPC))) || \
- (BSTAR_REC_SIZE > ((REC_SIZE) + ((0 == (LEVEL)) ? 1 : 0))) || \
- (2 >= (KEY_LEN)) || (0 != *(rPtr1 - 1) || 0 != *(rPtr1 - 2))) \
- STATUS = cdb_sc_blkmod; \
- else \
- STATUS = cdb_sc_normal; \
- } \
+#define READ_RECORD(STATUS, REC_SIZE_PTR, KEY_CMPC_PTR, KEY_LEN_PTR, KEY, LEVEL, BLK_BASE, REC_BASE) \
+{ \
+ DBG_CHECK_KEY_ALLOCATION_SIZE(KEY); \
+ STATUS = read_record(REC_SIZE_PTR, KEY_CMPC_PTR, KEY_LEN_PTR, KEY, LEVEL, BLK_BASE, REC_BASE); \
}
enum reorg_options { DEFAULT = 0,
@@ -153,3 +90,9 @@ enum reorg_options { DEFAULT = 0,
NOSPLIT = 0x0004,
NOSWAP = 0x0008,
DETAIL = 0x0010};
+
+int get_gblname_len(sm_uc_ptr_t blk_base, sm_uc_ptr_t key_base);
+int get_key_len(sm_uc_ptr_t blk_base, sm_uc_ptr_t key_base);
+int get_cmpc(sm_uc_ptr_t first_key, sm_uc_ptr_t second_key);
+enum cdb_sc read_record(int *rec_size_ptr, int *key_cmpc_ptr, int *key_len_ptr, sm_uc_ptr_t key,
+ int level, sm_uc_ptr_t blk_base, sm_uc_ptr_t rec_base);
diff --git a/sr_port/mu_reorg_upgrd_dwngrd.c b/sr_port/mu_reorg_upgrd_dwngrd.c
index 1b0ad9c..d249306 100644
--- a/sr_port/mu_reorg_upgrd_dwngrd.c
+++ b/sr_port/mu_reorg_upgrd_dwngrd.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2005, 2012 Fidelity Information Services, Inc *
+ * Copyright 2005, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -603,8 +603,7 @@ void mu_reorg_upgrd_dwngrd(void)
lcl_update_trans = update_trans; /* take a copy before t_end modifies it */
if ((trans_num)0 != t_end(&alt_hist, NULL, TN_NOT_SPECIFIED))
{ /* In case this is MM and t_end() remapped an extended database, reset csd */
- assert((dba_mm == cs_data->acc_meth) || (csd == cs_data));
- csd = cs_data;
+ assert(csd == cs_data);
if (!lcl_update_trans)
{
assert(lcnt);
@@ -620,9 +619,7 @@ void mu_reorg_upgrd_dwngrd(void)
reorg_stats.blks_converted_nonbmp++;
break;
}
- /* In case this is MM and t_end() remapped an extended database, reset csd */
- assert((dba_mm == cs_data->acc_meth) || (csd == cs_data));
- csd = cs_data;
+ assert(csd == cs_data);
}
}
}
diff --git a/sr_port/mu_split.c b/sr_port/mu_split.c
index 586b97a..375fd37 100644
--- a/sr_port/mu_split.c
+++ b/sr_port/mu_split.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -137,8 +137,9 @@ enum cdb_sc mu_split(int cur_level, int i_max_fill, int d_max_fill, int *blks_cr
return cdb_sc_oprnotneeded;
old_right_piece_len = old_blk1_sz - new_leftblk_top_off;
new_blk2_frec_base = old_blk1_base + new_leftblk_top_off;
- BLK_ADDR(newblk2_first_key, gv_cur_region->max_rec_size + 1, unsigned char);
- READ_RECORD(level, new_blk2_frec_base, tkeycmpc, rec_size, newblk2_first_key, newblk2_first_keylen, status);
+ BLK_ADDR(newblk2_first_key, MAX_KEY_SZ + 1, unsigned char);
+ READ_RECORD(status, &rec_size, &tkeycmpc, &newblk2_first_keylen, newblk2_first_key,
+ level, old_blk1_base, new_blk2_frec_base);
if (cdb_sc_normal != status) /* restart for cdb_sc_starrecord too, because we eliminated the possibility already */
{
assert(t_tries < CDB_STAGNATE);
@@ -243,7 +244,7 @@ enum cdb_sc mu_split(int cur_level, int i_max_fill, int d_max_fill, int *blks_cr
}
else
{
- BLK_ADDR(ances_currkey, gv_cur_region->max_rec_size + 1, unsigned char);
+ BLK_ADDR(ances_currkey, MAX_KEY_SZ + 1, unsigned char);
key_base = rec_base + SIZEOF(rec_hdr);
}
new_ances_currkeysz = old_ances_currkeycmpc + old_ances_currkeylen;
@@ -268,7 +269,7 @@ enum cdb_sc mu_split(int cur_level, int i_max_fill, int d_max_fill, int *blks_cr
if (SIZEOF(blk_hdr) != gv_target->hist.h[level].curr_rec.offset)
{
/* new_ins_key will be inseted after curr_prev_key */
- GET_CMPC(new_ins_keycmpc, &curr_prev_key[0], new_ins_key);
+ GET_CMPC(new_ins_keycmpc, curr_prev_key, new_ins_key);
}
else
new_ins_keycmpc = 0; /* new_ins_key will be the 1st key */
@@ -314,9 +315,9 @@ enum cdb_sc mu_split(int cur_level, int i_max_fill, int d_max_fill, int *blks_cr
else
/* process 1st record of new right block */
{
- BLK_ADDR(newblk2_first_key, gv_cur_region->max_rec_size + 1, unsigned char);
- READ_RECORD(level, new_blk2_frec_base, tkeycmpc, rec_size,
- newblk2_first_key, newblk2_first_keylen, status);
+ BLK_ADDR(newblk2_first_key, MAX_KEY_SZ + 1, unsigned char);
+ READ_RECORD(status, &rec_size, &tkeycmpc, &newblk2_first_keylen, newblk2_first_key,
+ level, old_blk1_base, new_blk2_frec_base);
if (cdb_sc_normal == status)
{
memcpy(newblk2_first_key, &new_blk1_last_key[0], tkeycmpc); /* compressed piece */
@@ -666,7 +667,8 @@ int *last_rec_size, unsigned char last_key[], int *last_keysz, int *top_off)
rec_base = blk_base + SIZEOF(blk_hdr);
while (*top_off < max_fill)
{
- READ_RECORD(level, rec_base, tkeycmpc, rec_size, &last_key[0], *last_keysz, status);
+ READ_RECORD(status, &rec_size, &tkeycmpc, last_keysz, last_key,
+ level, blk_base, rec_base);
*top_off += rec_size;
*last_keysz += tkeycmpc;
rec_base += rec_size;
diff --git a/sr_port/mu_swap_blk.c b/sr_port/mu_swap_blk.c
index 6dc63a7..c71b358 100644
--- a/sr_port/mu_swap_blk.c
+++ b/sr_port/mu_swap_blk.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -106,7 +106,7 @@ enum cdb_sc mu_swap_blk(int level, block_id *pdest_blk_id, kill_set *kill_set_pt
cache_rec_ptr_t dest_child_cr;
blk_segment *bs1, *bs_ptr;
sm_uc_ptr_t saved_blk, work_blk_ptr, work_parent_ptr, dest_parent_ptr, dest_blk_ptr,
- bn_ptr, bmp_buff, tblk_ptr, rec_base, rPtr1;
+ bn_ptr, bmp_buff, tblk_ptr, rec_base, key_base;
boolean_t gbl_target_was_set, blk_was_free, deleted;
gv_namehead *save_targ;
srch_blk_status bmlhist, destblkhist, *hist_ptr;
@@ -243,9 +243,9 @@ enum cdb_sc mu_swap_blk(int level, block_id *pdest_blk_id, kill_set *kill_set_pt
if (SIZEOF(blk_hdr) >= ((blk_hdr_ptr_t)tblk_ptr)->bsiz)
continue;
/* get length of global variable name (do not read subscript) for dest_blk_id */
- GET_GBLNAME_LEN(key_len_dir, rec_base + SIZEOF(rec_hdr));
+ key_len_dir = get_gblname_len(tblk_ptr, rec_base + SIZEOF(rec_hdr));
/* key_len = length of 1st key value (including subscript) for dest_blk_id */
- GET_KEY_LEN(key_len, rec_base + SIZEOF(rec_hdr));
+ key_len = get_key_len(tblk_ptr, rec_base + SIZEOF(rec_hdr));
if ((1 >= key_len_dir || MAX_MIDENT_LEN + 1 < key_len_dir) || (2 >= key_len || MAX_KEY_SZ < key_len))
{ /* Earlier used to restart here always. But dest_blk_id can be a block,
* which is just killed and still marked busy. Skip it, if we are in last retry.
@@ -299,10 +299,10 @@ enum cdb_sc mu_swap_blk(int level, block_id *pdest_blk_id, kill_set *kill_set_pt
*/
memcpy(&((TREF(gv_reorgkey))->base[0]), rec_base + SIZEOF(rec_hdr), key_len);
(TREF(gv_reorgkey))->end = key_len - 1;
- GET_KEY_LEN(key_len_dir, dir_hist_ptr->h[0].buffaddr + dir_hist_ptr->h[0].curr_rec.offset + SIZEOF(rec_hdr));
+ key_base = dir_hist_ptr->h[0].buffaddr + dir_hist_ptr->h[0].curr_rec.offset + SIZEOF(rec_hdr);
+ key_len_dir = get_key_len(dir_hist_ptr->h[0].buffaddr, key_base);
/* Get root of GVT for dest_blk_id */
- GET_LONG(gv_target->root,
- dir_hist_ptr->h[0].buffaddr + dir_hist_ptr->h[0].curr_rec.offset + SIZEOF(rec_hdr) + key_len_dir);
+ GET_LONG(gv_target->root, key_base + key_len_dir);
if ((0 == gv_target->root) || (gv_target->root > (cs_data->trans_hist.total_blks - 1)))
{
assert(t_tries < CDB_STAGNATE);
diff --git a/sr_port/mucregini.c b/sr_port/mucregini.c
index 025d9bd..af74e34 100644
--- a/sr_port/mucregini.c
+++ b/sr_port/mucregini.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -95,6 +95,7 @@ void mucregini(int4 blk_init_size)
cs_data->lock_space_size = gv_cur_region->dyn.addr->lock_space * OS_PAGELET_SIZE;
else
cs_data->lock_space_size = DEF_LOCK_SIZE;
+ NUM_CRIT_ENTRY(cs_data) = DEFAULT_NUM_CRIT_ENTRY;
cs_data->staleness[0] = -300000000; /* staleness timer = 30 seconds */
cs_data->staleness[1] = -1;
cs_data->ccp_quantum_interval[0] = -20000000; /* 2 sec */
diff --git a/sr_port/mupip.hlp b/sr_port/mupip.hlp
index 1092a83..906036f 100644
--- a/sr_port/mupip.hlp
+++ b/sr_port/mupip.hlp
@@ -1,2180 +1,7131 @@
-1 BACKUP
- B[ACKUP]
- BACKUP copies blocks from one or more Greystone Technology Database
- Structure (GDS) files to a new file or files. BACKUP suspends updates
- to all regions specified by the BACKUP command from the time it starts
- the first region until it finishes the last region. This ensures that
- BACKUP captures a consistent application state. BACKUP does not
- suspend processes that only perform retrievals.
-
- The format of the BACKUP command is:
-
- B[ACKUP][-qualifier[...]] region-list[,...] file-spec
-
-
- By default, BACKUP is -COMPREHENSIVE.
-
- The first argument may specify more than one region of the current
- Global Directory in a list separated with commas.
-
- To BACKUP only one region, the file-specification must resolve to a
- UNIX file or directory name. To BACKUP several regions, the
- file-specification must be a directory specification. If the
- file-specification is a directory, MUPIP assigns the backup files the
- same name as the file associated with the dynamic segment of each
- region. Therefore, the target directory must not contain any of the
- regions included in the BACKUP.
-
-2 Qualifiers
--COMPREHENSIVE
- -C[OMPREHENSIVE]
- Specifies that BACKUP copy the entire file from disk to disk. On
- completion, the result is ready for use as a GT.M database. This
- option does not support operation to magnetic tape.
-
- BACKUP -COMPREHENSIVE has the following advantages:
-
- o It does not require exclusive access to the file
-
- o It can interlock multiple files simultaneously
-
- The -COMPREHENSIVE qualifier is not compatible with any other
- qualifier.
-
- By default, BACKUP operates -COMPREHENSIVE.
-
--INCREMENTAL
- -I[NCREMENTAL]
- Specifies that BACKUP include only blocks from the database that
- have changed since a prior point specified by the -SINCE or
- -TRANSACTION qualifier. MUPIP RESTORE integrates the results of
- a BACKUP -INCREMENTAL into a database.
-
- The -INCREMENTAL qualifier is not compatible with the
- -COMPREHENSIVE qualifier.
-
--RECORD
- -R[ECORD]
- Specifies that the BACKUP utility record this backup as a
- reference point for subsequent backups. Each time a BACKUP
- specifies -RECORD, that backup replaces the previous recorded
- backup as the RECORD reference point for the file.
-
--SINCE
- -S[INCE]=keyword
- Specifies that a BACKUP -INCREMENTAL includes blocks changed
- since the last specified BACKUP.
-
- -SINCE accepts the keywords:
-
- o C[OMPREHENSIVE] - Backup all changes since the last BACKUP
- -COMPREHENSIVE
-
- o I[NCREMENTAL] - Backup all changes since the last BACKUP
- -INCREMENTAL
-
- o R[ECORD] - Backup all changes since the last BACKUP -RECORD
-
- The -SINCE qualifier is incompatible with the -COMPREHENSIVE and
- -TRANSACTION qualifiers.
-
- By default, BACKUP -INCREMENTAL operates -SINCE=COMPREHENSIVE.
-
--TRANSACTION
- -T[RANSACTION]=transaction-number
- Specifies a hexadecimal starting transaction which causes BACKUP
- -INCREMENTAL to copy all blocks that have been changed by the
- specified and all subsequent transactions. Transaction numbers
- appear in a DSE DUMP -FILEHEADER, with a "Current TN" label. If
- the transaction number is invalid, BACKUP reports an error and
- rejects the command.
-
- BACKUP -INCREMENTAL -TRANSACTION=1 copies all in-use blocks and
- has the following advantages:
-
- o It does not require exclusive access to the file
-
- o It can interlock multiple files simultaneously
-
- Different regions do not normally have a single transaction
- number that marks a meaningful point. Therefore, a BACKUP
- command specifying multiple regions and using the -TRANSACTION
- qualifier with arguments other than one (1) is unlikely to
- produce desirable results.
-
- The -TRANSACTION qualifier is incompatible with the
- -COMPREHENSIVE and -SINCE qualifiers.
-
-1 CREATE
- CR[EATE]
- CREATE generates database files using the characteristics stored in a
- Global Directory by the Global Directory Editor (GDE). CREATE uses the
- Global Directory to map a region to a segment and a segment to a file.
- Use the MUPIP CREATE command to create a new database or a new copy of
- a previously existing file during a database reorganization. If a
- database file already exists for the segment, CREATE takes no action.
- If a file does not exist, CREATE sets up the file. CREATE also
- initializes the database structure (GDS).
+1 Introduction
+ Introduction
+
+ GT.M uses M Peripheral Interchange Program (MUPIP) for GT.M database
+ management, database journaling, and logical multisite replication (LMS).
+ This chapter summarizes the MUPIP commands pertaining to GT.M database
+ management and serves as a foundation for more advanced GT.M functionality
+ described for Journaling and LMS.
+
+ **Note**
+
+ Two MUPIP operations - INTRPT and STOP - perform process management
+ functions. All other MUPIP operations relate to the operation of the
+ database.
+
+ The GT.M installation procedure places the MUPIP utility program in a
+ directory specified by $gtm_dist.
+
+ Invoke MUPIP by executing the mupip program at the shell prompt. If this
+ does not work, consult your system manager (MUPIP requires that the
+ $gtm_dist point to the directory containing the MUPIP executable image).
+
+ $gtm_dist/mupip
+ MUPIP>
+
+ MUPIP asks for commands, with the MUPIP> prompt. Enter the EXIT command at
+ the MUPIP> prompt to stop the utility. MUPIP performs one operation at a
+ time, and automatically terminates after most operations.
+
+ When additional information appears on the command line after the mupip
+ program name, MUPIP processes the additional information as its command,
+ for example:
+
+ $gtm_dist/mupip stop 1158
+
+ This starts MUPIP and stops the process with Process ID (PID) 1158.
+
+ Some MUPIP commands require information contained in the global directory.
+ Therefore, a process must have access to a valid global directory before
+ using any MUPIP commands other than EXIT, INTRPT, JOURNAL, RESTORE, STOP
+ and the -file option of any command that has that option.
+
+ The environment variable gtmgbldir specifies the active global directory.
+
+ A gtmgbldir value of mumps.gld tells MUPIP to look for a global directory
+ file mumps.gld in the current directory. See the "Global Directory Editor"
+ chapter for more information on the global directory.
+
+2 Operations
+ Operations
+
+ While most MUPIP operations can be performed when GT.M processes are
+ actively accessing database files, some operations require stand-alone
+ access. When using standalone access, no other process can access the
+ database file(s). When using concurrent access, other processes can read
+ or update the database file(s) while MUPIP accesses them. A few operations
+ permit concurrent access to read database files, but not to update them.
+ All MUPIP operations can be performed with stand-alone access - there is
+ never a requirement for another process to be accessing database files
+ when MUPIP operates on them.
+
+ Most MUPIP operations require write access to the database files with
+ which they interact. The exceptions are INTRPT and STOP, which do not
+ require database access, but may require other privileges; EXTRACT, which
+ requires read access; and INTEG, which may require write access, depending
+ on the circumstances it encounters and the qualifiers with which it is
+ invoked. The following table displays some of the MUPIP operations and
+ their database access requirements.
+
+ +------------------------------------------------------------------------+
+ | Operations | MUPIP command | Database Access Requirements |
+ |------------------------+---------------+-------------------------------|
+ | | | Backup never requires |
+ | Backup database files | MUPIP BACKUP | standalone access and |
+ | | | concurrent write access is |
+ | | | controlled by -[NO]ONLINE. |
+ |------------------------+---------------+-------------------------------|
+ | Create and initialize | MUPIP CREATE | Standalone access |
+ | database files | | |
+ |------------------------+---------------+-------------------------------|
+ | Converts a database | | |
+ | file from one endian | MUPIP | |
+ | format to the other | ENDIANCVT | Standalone access |
+ | (BIG to LITTLE or | | |
+ | LITTLE to BIG) | | |
+ |------------------------+---------------+-------------------------------|
+ | Recover database files | | |
+ | (for example, after a | | |
+ | system crash) and | MUPIP JOURNAL | Standalone access |
+ | extract journal | | |
+ | records | | |
+ |------------------------+---------------+-------------------------------|
+ | Restore databases from | | |
+ | bytestream backup | MUPIP RESTORE | Standalone access |
+ | files | | |
+ |------------------------+---------------+-------------------------------|
+ | Properly close | | |
+ | database files when | MUPIP RUNDOWN | Standalone access |
+ | processes terminate | | |
+ | abnormally. | | |
+ |------------------------+---------------+-------------------------------|
+ | | | Standalone access is required |
+ | | | if the MUPIP SET command |
+ | Modify database and/or | | specifies -ACCESS_METHOD, |
+ | journal file | MUPIP SET | -GLOBAL_BUFFERS, LOCK_SPACE |
+ | characteristics | | or -NOJOURNAL, or if any of |
+ | | | the -JOURNAL options ENABLE, |
+ | | | DISABLE, or BUFFER_SIZE are |
+ | | | specified. |
+ |------------------------+---------------+-------------------------------|
+ | Backup database files | MUPIP BACKUP | Concurrent access. |
+ |------------------------+---------------+-------------------------------|
+ | Grow the size of BG | MUPIP EXTEND | Concurrent access. |
+ | database files | | |
+ |------------------------+---------------+-------------------------------|
+ | | | Although MUPIP EXTRACT |
+ | | | command works with concurrent |
+ | Export data from | | access, it implicitly freezes |
+ | database files into | | the database to prevent |
+ | sequential (flat) or | MUPIP EXTRACT | updates. Therefore, from an |
+ | binary files | | application standpoint, you |
+ | | | might plan for a standalone |
+ | | | access during a MUPIP EXTRACT |
+ | | | operation. |
+ |------------------------+---------------+-------------------------------|
+ | Prevent updates to | MUPIP FREEZE | Standalone access. |
+ | database files | | |
+ |------------------------+---------------+-------------------------------|
+ | | | Concurrent access. However, |
+ | Check the integrity of | MUPIP INTEG | standalone access is required |
+ | GDS databases | | if MUPIP INTEG specifies |
+ | | | -FILE. |
+ |------------------------+---------------+-------------------------------|
+ | | | Although MUPIP LOAD works |
+ | | | with concurrent access, you |
+ | | | should always assess the |
+ | Import data into | | significance of performing a |
+ | databases | MUPIP LOAD | MUPIP LOAD operation when an |
+ | | | application is running |
+ | | | because it may result in an |
+ | | | inconsistent application |
+ | | | state for the database. |
+ |------------------------+---------------+-------------------------------|
+ | Defragment database | | |
+ | files to improve | MUPIP REORG | Concurrent access. |
+ | performance | | |
+ |------------------------+---------------+-------------------------------|
+ | Send an asynchronous | | |
+ | signal to a GT.M | MUPIP INTRPT | Non-database access. |
+ | process | | |
+ |------------------------+---------------+-------------------------------|
+ | Stop GT.M processes | MUPIP STOP | Non-database access. |
+ +------------------------------------------------------------------------+
+
+2 Syntax
+ Syntax
+
+ The general format of MUPIP commands is:
+
+ mupip command [-qualifier[...]] [object[,...]] [destination]
+
+ MUPIP allows the abbreviation of commands and qualifiers. In each section
+ describing a command or qualifier, the abbreviation is also shown (for
+ example, B[ACKUP]). The abbreviated version of the command you can use on
+ the command line is B. To avoid future compatibility problems and improve
+ the readability, specify at least four characters when using MUPIP
+ commands in scripts.
+
+ Although you can enter commands in both upper and lower case (the mupip
+ program name itself must be in lower case on UNIX/Linux), the
+ typographical convention used in this chapter is all small letters for
+ commands. Another convention is in the presentation of command syntax. If
+ the full format of the command is too long for a single line of print, the
+ presentation wraps around into additional lines.
+
+ mupip backup -bytestream -transaction=1 accounts,history,tables,miscellaneous /var/production/backup/
+
+ When you enter a MUPIP command, one of its variable arguments is the
+ region-list. region-list identify the target of the command and may
+ include the UNIX wildcards "?" and "*". Region-lists containing UNIX
+ wildcard characters must always be quoted, for example, "*" to prevent
+ inappropriate expansion by the UNIX shell. Similarly, for file and
+ directory names you might want to avoid non-graphic characters and most
+ punctuations except underbars (_), not because of GT.M conventions but
+ because of inappropriate expansion by UNIX shells.
+
+ MUPIP qualifier values are restricted only by the maximum size of the
+ command input line, which is 4KB on some systems and upto 64KB on others.
+
+1 GDM
+ GDM
+
+ The MUPIP commands described in this seciton are used for common database
+ operations and serves as the foundation for more advanced functionality
+ like Journaling and Replication.
+
+2 BACKUP
+ BACKUP
+
+ Saves the contents of the database. It provides a consistent application
+ snapshot across all database regions involved in the backup operation.
+
+ The format of the MUPIP BACKUP command is:
+
+ B[ACKUP]
+ [
+ -BK[UPDBJNL]={DISABLE|OFF}]
+ -B[YTESTREAM] [-NET[TIMEOUT]]
+ -DA[TABASE]
+ -DBG
+ -[NO]NEWJNLFILES[=[NO]PREVLINK],[NO]S[YNC_IO]]
+ -O[NLINE]
+ -REC[ORD]
+ -REPL[ACE]
+ -REPLINSTANCE=target_location
+ -S[INCE]={DATABASE|BYTESTREAM|RECORD}
+ -T[RANSACTION]=hexadecimal_transaction_number
+ ] region-list[,...] destination-list
+
+ **Important**
+
+ MUPIP BACKUP does a more comprehensive job of managing backup activities
+ than other backup techniques such as a SAN backup, breaking a disk mirror,
+ or a file system snapshot because it integrates journal management,
+ instance file management, and records timestamps in the database file
+ headers. To use other techniques, you must first freeze all regions
+ concurrently with a command such as MUPIP FREEZE -ON "*" in order to
+ ensure a consistent copy of files with internal structural integrity. FIS
+ neither endorses nor tests any third party products for backing up a GT.M
+ database.
+
+ o MUPIP BACKUP supports two methods of database backup: -BYTESTREAM and
+ -DATABASE. MUPIP BACKUP -BYTESTREAM directs the output to a broad
+ range of devices, including disks, TCP sockets, and pipes. MUPIP
+ BACKUP -DATABASE directs the output to random access devices (that is,
+ disks).
+ o [NO]ONLINE qualifier determines whether MUPIP BACKUP should suspend
+ updates to regions. For example, MUPIP BACKUP -NOONLINE suspends
+ updates to all regions from the time it starts the first region until
+ it finishes the last region. However, it does not suspend processes
+ that only read from the database.
+ o By default, MUPIP BACKUP is -DATABASE -ONLINE.
+ o If any region name does not map to an existing accessible file, or if
+ any element of the destination list is invalid, BACKUP rejects the
+ command with an error.
+ o region-list may specify more than one region of the current global
+ directory in a list. Regions are separated by a comma, and wildcards
+ can be used to specify them. Any region-name may include the wildcard
+ characters * and % (remember to escape them to protect them from
+ inappropriate expansion by the shell). Any region name expansion
+ occurs in M (ASCII) collation order.
+ o Depending on the type of backup, destination-list may be a single
+ directory, or a comma separated list of destinations including files,
+ piped commands, or TCP sockets.
+ o Region-list and destination-list items are matched in order - the
+ first region is mapped to the first destination, the second to the
+ second destination, and so on. If GT.M encounters a region mapped to a
+ directory, GT.M treats that directory as the destination for all
+ subsequent regions in the region-list.
+ o GT.M implicitly timestamps both BYTESTREAM and DATABASE backups using
+ relative timestamps (transaction numbers). You can also explicitly
+ specific a RECORD timestamp for custom-control (SANS or mirrored disk)
+ backup protocol. You might want to use these timestamps as reference
+ points for subsequent backups.
+ o It takes approximately one (1) minute (per region) for BACKUP -ONLINE
+ to give up and bypass a KILLs in progress; backup does not wait for
+ Abandoned Kills to clear.
+ o The environment variable gtm_baktmpdir specifies the directory where
+ mupip backup creates temporary files. If gtm_baktmpdir is not defined,
+ GT.M uses the deprecated GTM_BAKTMPDIR environment variable if
+ defined, and otherwise uses the current working directory.
+ o When you restrict access to a database file, GT.M propagates those
+ restrictions to shared resources associated with the database file,
+ such as semaphores, shared memory, journals and temporary files used
+ in the course of MUPIP BACKUP.
+ o GT.M supports only one concurrent -ONLINE backup on a database. MUPIP
+ BACKUP displays the BKUPRUNNING message if started when there is an
+ already running BACKUP.
+ o MUPIP BACKUP protects against overwriting of existing destination
+ files. However, it cannot protect other destinations, for example, if
+ the destination is a pipe into a shell command that overwrites a file.
+
+ Before starting a MUPIP BACKUP
+
+ Perform the following tasks before you begin a database backup.
+
+ o Ensure adequate disk space for target location and temporary files.
+ Set the environment variable gtm_baktmpdir to specify the directory
+ where MUPIP BACKUP creates temporary files. If gtm_baktmpdir is not
+ defined, GT.M uses the deprecated GTM_BAKTMPDIR environment variable
+ if defined, and otherwise uses the current working directory. Do not
+ place temporary files in the current directory for large databases in
+ production environments.
+ o When using replication, ensure that the Source/Receiver process is
+ alive (MUPIP REPLIC -SOURCE/-RECEIVER -CHECKHEALTH). Always backup the
+ replicating instance file with the database (BACKUP -REPLINST).
+ o If you intend to use a -DATABASE backup at the same time in the same
+ computer system as the source database, be sure to disable journaling
+ in the backed up database with -BKUPDBJNL=DISABLE.
+ o When doing a complete backup, switch journal files as part of the
+ backup command using -NEWJNLFILES=NOPREVLINK. This aligns the journal
+ files with the backup and simplifies journal file retention.
+ o If you follow separate procedures for backup and archive (moving to
+ secondary storage), you can save time by starting archive as soon as
+ MUPIP BACKUP completes the process of creating a backup database file
+ for a region. You do not need to wait for MUPIP BACKUP to complete
+ processing for all regions before starting archive. For example, a
+ message like:
+
+ DB file /home/jdoe/.fis-gtm/V6.0-001_x86_64/g/gtm.dat backed up in file /backup/gtm.dat
+ Transactions up to 0x0000000000E92E04 are backed up.
+
+ confirms that gtm.dat is backed up correctly and is ready for archive.
+
+ o Determine an appropriate frequency, timing, and backup method
+ (-BYTESTREAM or -COMPREHENSIVE) based on the situation.
+ o Ensure the user issuing backup commands has appropriate permissions
+ before starting the backup. Backup files hav e the ownership of the
+ user running MUPIP BACKUP.
+ o There is one circumstance under which a MUPIP BACKUP is not advised.
+ When your operational procedures call for taking backups of unmodified
+ databases and journal files on rebooting a system after a crash, then
+ use an underlying operating system command (cp, cpio, gzip, tar, and
+ so on) which will open the files read-only. Note that for ordinary
+ system crashes where the system simply stops writing to open files at
+ power down, you can use MUPIP JOURNAL to recover journaled database
+ files, and taking backups on reboot should not be required. However,
+ for system crashes with the possibility of damage to files already
+ written to disk (for example, if the crash involved an IO controller
+ with the potential for having written random data to disk immediately
+ prior to power down), such backups on reboot are appropriate.
+
+ Example:
+
+ $ mupip backup "*" /gtm/bkup
+
+ This example creates ready-to-run database backup of all regions.
+
+3 BKupdbjnl
+ BKupdbjnl
+
+ A backup database shares the same journaling characteristics of the source
+ database. However, with BKUPDBJNL you can disable or turns off journaling
+ in the backup database. Use this qualifier if you intend to open your
+ backup database at the same time in the same environment as the source
+ database.
+
+ The format of the BKUPDBJNL qualifier is:
+
+ -BK[UPDBJNL]={DISABLE|OFF}
+
+ o Specify DISABLE to disable journaling in the backup database.
+ o Specify OFF to turn off journaling is in the backup database.
+ o Only one of the qualifiers DISABLE or OFF can be specified at any
+ given point.
+
+3 Bytestream
+ Bytestream
+
+ Ttransfers MUPIP BACKUP output to a TCP connection, file (or a backup
+ directory), or a pipe. If there are multiple .dat files, BYTESTREAM
+ transfers output to a comma separated list of TCP connections, incremental
+ backup files and/or directories, or pipes. When used with -SINCE or
+ -TRANSACTION, MUPIP BACKUP allow incremental backup, that is, include
+ database blocks that have changed since a prior point specified by the
+ -SINCE or -TRANSACTION.
+
+ **Note**
+
+ MUPIP BACKUP output to a TCP connection saves disk I/O bandwidth on the
+ current system.
+
+ All bytream backups needs to be restored to a random access file (with
+ MUPIP RESTORE) before being used as a database file. -BYTESTREAM can also
+ send the output directly to a listening MUPIP RESTORE process via a TCP/IP
+ connection or a pipe.
+
+ The format of the BYTESTREAM qualifier is:
+
+ -B[YTESTREAM]
+
+ o -BYTESTREAM is compatible with -SINCE and -TRANSACTION.
+ o -INCREMENTAL is deprecated in favor of -BYTESTREAM. For upward
+ compatibility, MUPIP temporarily continues to support the deprecated
+ -INCREMENTAL.
+
+3 Database
+ Database
+
+ Creates a disk-to-disk backup copy of the files of all selected regions.
+ DATABASE backup copy is a ready-to-use a GT.M database unlike BYTESREAM
+ backup which is required to be restored to a random access file.
+
+ **Note**
+
+ The DATABASE qualifier does not support backup to magnetic tape.
+
+ The format of the DATABASE qualifier is:
+
+ -D[ATABASE]
+
+ o By default, MUPIP BACKUP uses -DATABASE.
+ o The DATABASE qualifier is only compatible with the -[NO]NEW[JNLFILES],
+ -ONLINE, and -RECORD qualifiers.
+ o -COMPREHENSIVE is depreciated in favor of -DATABASE. For upward
+ compatibility, MUPIP temporarily continues to support the deprecated
+ -COMPREHENSIVE.
+
+3 NETtimeout
+ NETtimeout
+
+ Specifies the timeout period when a bytestream BACKUP data is sent over a
+ TCP/IP connection. The format of the NETTIMEOUT qualifier is:
+
+ NET[TIMEOUT]=seconds
+
+ o The default value is 30 seconds.
+ o Use only with: -BYTESTREAM.
+
+3 NEWJNLFILES
+ NEWJNLFILES
+
+ Determines the journaling charactertistics of the database files being
+ backed-up. All the established journaling characteristics apply to new
+ journal files. This qualifier is effective only for an ONLINE backup (the
+ default), when the database has journaling enabled.
+
+ The format of the NEWJNLFILES qualifier is:
+
+ -[NO]NEWJNLFILES[=[NO]PREVLINK], [NO]S[YNC_IO]]
+
+ o -NEWJNLFILES can take the following three values:
+
+ o PREVLINK: Back links new journal files with the prior generation
+ journal files. This is the default value.
+ o NOPREVLINK: Indicates that there should be no back link between
+ the newly created journals and prior generation journal files.
+ o SYNC_IO: Specifies that every WRITE to a journal file to be
+ committed directly to disk. On high-end disk subsystems (for
+ example, those that include non-volatile cache and that consider
+ the data to be committed when it reaches this cache), this might
+ result in better performance than the NOSYNC_IO option. NOSYNC_IO
+ turn off this option.
+
+ o -NONEWJNLFILES causes journaling to continue with the current journal
+ files. It does not accept any arguments.
+ o The default is -NEWJNLFILES=PREVLINK.
+
+3 Online
+ Online
+
+ Specifies that while a MUPIP BACKUP operation is active, other processes
+ can update the database without affecting the result of the backup. The
+ format of the ONLINE qualifier is:
+
+ -[NO]O[NLINE]
+
+ o MUPIP BACKUP -ONLINE creates a backup of the database as of the moment
+ the backup starts. If the running processes subsequently update the
+ database, the backup does not reflect those updates.
+ o MUPIP BACKUP -ONLINE on regions(s) waits for up to one minute so any
+ concurrent KILL or MUPIP REORG operations can complete. If the KILL or
+ MUPIP REORG operations do not complete within one minute, MUPIP BACKUP
+ -ONLINE starts the backup with a warning that the backup may contain
+ incorrectly marked busy blocks. Such blocks waste space and can
+ desensitize operators to much more dangerous errors, but otherwise
+ don't affect database integrity. If you get such an error, it may be
+ better to stop the backup and restart it when KILL or MUPIP REORG
+ operations are less likely to interfere. Performing MUPIP STOP on a
+ process performing a KILL or MUPIP REORG operation may leave the
+ database with incorrectly marked busy blocks. In this situation, GT.M
+ converts the ongoing KILLs flag to abandoned KILLs flag. If MUPIP
+ BACKUP -ONLINE encounters ADANDONED_KILLS, it gives a message and then
+ starts the backup. An ABANDONED_KILLS error means both the original
+ database and the backup database possibly have incorrectly busy blocks
+ which should be corrected promptly.
+ o By default, MUPIP BACKUP is -ONLINE.
+
+3 Record
+ Record
+
+ Timestamps (in the form of a transaction number) a database file to mark a
+ reference point for subsequent bytestream, database, or custom backup
+ (SANS or disk mirror) protocols. Even though -DATABASE and -BYTESTREAM
+ both mark their own relative timestamps, -RECORD provides an additional
+ timestamp option. MUPIP FREEZE also provides the -RECORD qualifier because
+ a FREEZE may be used to set the database up for a SAN or disk-mirror based
+ backup mechanism.
+
+ The format of the RECORD qualifier is:
+
+ -R[ECORD]
+
+ o Use -RECORD (with the hypen) to timpestamp a refererence point and use
+ RECORD as a keyword (as in -SINCE=RECORD) to specific the starting
+ point for a MUPIP BACKUP operation.
+ o -RECORD replaces the previously RECORDed transaction identifier for
+ the database file.
+
+3 REPLace
+ REPLace
+
+ Overwrites the existing destination files.
+
+ The format of the REPLACE qualifier is:
+
+ -[REPL]ACE
+
+ o By default, MUPIP BACKUP protect against overwriting the destination
+ files. -REPLACE disables this default behavior.
+ o -REPLACE is compatible only with -DATABASE.
+
+3 REPLInstance
+ REPLInstance
+
+ Specifies the target location to place the backup of the replication
+ instance file.
+
+ **Note**
+
+ The replication instance file should always be backed up with the database
+ file.
+
+ The format of the REPLINSTANCE qualifier is:
+
+ -REPLI[NSTANCE]=<target_location>
+
+3 Since
+ Since
+
+ Includes blocks changed since the last specified backup. The format of the
+ SINCE qualifier is:
+
+ -S[INCE]={DATABASE|BYTESTREAM|RECORD}
+
+ o keyword can include any one of the following:
+
+ o D[ATABASE] - Backup all changes since the last MUPIP BACKUP
+ -DATABASE.
+ o B[YTESTREAM] - Backup all changes since the last MUPIP BACKUP
+ -BYTESTREAM.
+ o R[ECORD] - Backup all changes since the last MUPIP BACKUP
+ -RECORD.
+
+ o By default, MUPIP BACKUP -BYTESTREAM operates as -SINCE=DATABASE.
+ o Incompatible with: -TRANSACTION.
+
+3 Transaction
+ Transaction
+
+ Specifies the transaction number of a starting transaction that causes
+ BACKUP -BYTESTREAM to copy all blocks that have been changed by that
+ transaction and all subsequent transactions. The format of the TRANSACTION
+ qualifier is:
+
+ -T[RANSACTION]=transaction-number
+
+ o A Transaction number is always 16 digit hexadecimal number. It appears
+ in a DSE DUMP -FILEHEADER with the label "Current transaction".
+ o If the transaction number is invalid, MUPIP BACKUP reports an error
+ and rejects the command.
+ o It may be faster than a DATABASE backup, if the database is mostly
+ empty.
+ o Incompatible with: -DATABASE, -SINCE
+
+ **Note**
+
+ A point in time that is consistent from an application perspective is
+ unlikely to have the same transaction number in all database regions.
+ Therefore, except for -TRANSACTION=1, this qualifier is not likely to be
+ useful for any backup involving multiple regions.
+
+3 Examples
+ Examples
+
+ Example:
+
+ $ mupip backup -bytestream REPTILES,BIRDS bkup
+
+ Suppose that the environment variable gtmgbldir has regions REPTILES and
+ BIRDS that map to files called REPTILES.DAT and BIRDS.DAT (no matter which
+ directory or directories the files reside in). Then the above example
+ creates bytestream backup files REPTILES.DAT and BIRDS.DAT in the bkup
+ directory since the last DATABASE backup.
+
+ Example:
+
+ $ mupip backup -bkupdbjnl="OFF" "*"
+
+ This command turns off journaling in the backup database.
+
+ Example:
+
+ $ mupip backup -bytestream "*" tcp://philadelphia:7883,tcp://tokyo:8892
+
+ Assuming a Global Directory with two regions pointing to ACN.DAT and
+ HIST.DAT, this example creates a backup of ACN.DAT to a possible MUPIP
+ RESTORE process listening at port 7883 on server philadelphia and HIST.DAT
+ to a possible MUPIP RESTORE process listening at port 8893 on server
+ tokyo.
+
+ Always specify the <machine name> and <port> even if both backup and
+ restore are on the same system, and ensure that the MUPIP RESTORE process
+ is started before the MUPIP BACKUP process.
+
+ Example:
+
+ $ 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
+ current database in directory bkup. GT.M freezes all the regions during
+ the backup operation.
+
+ Example:
+
+ $ mupip backup -bytestream -nettimeout=420 DEFAULT tcp://${org_host}:6200
+
+ This command creates a backup copy of the DEFAULT region with timeout of
+ 420 seconds.
+
+ Example:
+
+ $ mupip backup -bytestream DEFAULT '"| gzip -c > online5pipe.inc.gz"'
+
+ This command sends (via a pipe) the backup of the DEFAULT region to a gzip
+ command.
+
+ Example:
+
+ $ 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
+ database in directory bkup. During the backup operation, other processes
+ can read and update the database.
+
+ Example:
+
+ $ mupip backup -record DEFAULT bkup
+
+ This command sets a reference point and creates a backup copy of the
+ DEFAULT region of the current database in directory bkup.
+
+ Example:
+
+ $ mupip backup -online -record DEFAULT bkup1921
+ DB file /home/reptiles/mumps.dat backed up in file bkup1921/mumps.dat
+ Transactions up to 0x00000000000F4351 are backed up.
+
+ Example:
+
+ $ mupip backup -bytestream -since=record DEFAULT bkup1921onwards
+ MUPIP backup of database file /home/reptiles/mumps.dat to bkup1921onwards/mumps.dat
+ 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
+ DEFAULT region of the current database in directory bkup1921. The second
+ command completes a bytestream backup starting from the reference point
+ set by the first command.
+
+ Example:
+
+ $ mupip backup -bytestream -transaction=1 DEFAULT bkup_dir
+ MUPIP backup of database file /gtmnode1/gtmuser1/mumps.dat to bkup_dir/mumps.dat
+ 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
+ database to directory bkup_dir.
+
+ Example:
+
+ $ mupip backup -newjnlfiles=noprevlink,sync_io "*" backupdir
+
+ This example creates new journal files for the current regions, cuts the
+ previous journal file link for all regions in the global directory,
+ enables the SYNC_IO option and takes a backup of all databases in the
+ directory backupdir.
+
+2 CREATE
+ CREATE
+
+ Creates and initializes database files using the information in a Global
+ Directory file. If a file already exists for any segment, MUPIP CREATE
+ takes no action for that segment.
The format of the CREATE command is:
CR[EATE] [-R[EGION]=region-name]
-
- The optional -REGION qualifier specifies a single region for which to
+
+ The single optional -REGION qualifier specifies a region for which to
create a database file.
- By default, CREATE sets up database files for all regions in the
- current Global Directory.
+ Note that one GT.M database file grows to a maximum size of 224M
+ (234,881,024) blocks. This means, for example, that with an 8KB block
+ size, the maximum single database file size is 1,792GB (8KB*224M). Note
+ that this is the size of one database file -- a logical database (an M
+ global variable name space) can consist of an arbitrary number of database
+ files.
-2 Qualifiers
--REGION
- -R[EGION]=region-name
- Specifies a single region for creation of a database file. By
- default, CREATE sets up (creates) database files for all regions
- in the current Global Directory.
+3 Region
+ Region
-1 EXIT
- EXI[T]
- EXIT terminates MUPIP and returns control to the point where MUPIP was
- invoked. This command is useful when you invoke MUPIP without an
- action and wish to leave without performing one, or after using MUPIP
- HELP.
+ Specifies a single region for creation of a database file. By default,
+ MUPIP CREATE creates database files for all regions in the current Global
+ Directory that do not already have a database file.
- The format of the EXIT command is:
+ The format of the REGION qualifier is:
- EXI[T]
+ -R[EGION]=region-name
- The Exit command does not accept any qualifiers.
-
-1 EXTEND
- EXTE[ND]
- EXTEND expands a GDS database file. Databases generally extend
- automatically, but this command allows you to control the time and
- amount of extension.
-
- The format of the EXTEND command is:
-
- EXTE[ND] region-name [-B[LOCKS]=blocks]
-
- The required region-name parameter specifies the name of the region to
- expand. EXTEND uses the Global Directory to map the region to the
- dynamic segment and the segment to the file.
-
-2 Qualifiers
--BLOCKS
- -B[LOCKS]=blocks
- Specifies the number of GDS database blocks by which GT.M should
- extend the file. GDS files use some blocks for bit maps. EXTEND
- adds the specified number of blocks and the bit map blocks
- required as overhead. For more information about bit maps, refer
- to the "GDS" chapter of the GT.M Administration and Operations
- Guide.
-
- EXTEND uses the value in the fileheader as the number of GDS
- blocks by which to extend the database file.
-
-1 EXTRACT
- EXTR[ACT]
- EXTRACT copies specified globals from the current database to a
- sequential output file in one of two formats (i.e., GO, or BINARY).
- Use EXTRACT to back up specific globals or when extracting data from
- the database for use by another system. EXTRACT uses the Global
- Directory to determine which database files to use. EXTRACT may
- operate concurrently with normal GT.M database access. To ensure that
- an EXTRACT reflects a consistent application state, suspend database
- updates to all regions involved in the extract with the -FREEZE
- qualifier.
-
- The format of the EXTRACT command is:
-
- EXTR[ACT][-qualifier[...]] file-specification
-
- EXTRACT places its output in the file defined by the
- file-specification. EXTRACT may output to a UNIX file on any device
- that supports such files, including magnetic tapes. Note that magnetic
- tapes may have a smaller file maximum size than disks. <CTRL C>
- produces a status message from EXTRACT. Entering <CTRL C> twice in
- quick succession aborts EXTRACT. An EXTRACT terminated abnormally by
- operator action or error produces incomplete output.
-
-2 Qualifiers
--SELECT
- -S[ELECT]=global-name-list
- Specifies the globals to extract. The "^" in the specification
- of the global name is optional. Enclose lowercase global names
- in quotes ("").
+3 Examples
+ Examples
- The global-specification can be:
+ Example:
- o A global name, such as MEF
+ $ mupip create -region=REPTILES
- o A range of global names, such as A7:B6
+ This command creates the database file specified by the Global Directory
+ (named by the GT.M Global Directory environment variable) for region
+ REPTILES.
- o A list, such as A,B,C
+2 DOWNGRADE
+ DOWNGRADE
- o Global names with the same prefix, such as TMP*
+ The MUPIP DOWNGRADE command changes the file header format to V4 or V5.
+ The format of the MUPIP DOWNGRADE command is:
- In the first case, EXTRACT selects only global ^MEF. In the
- second case, EXTRACT selects all global names between ^A7 and
- ^B6, inclusive. In the third case, EXTRACT selects globals ^A,
- ^B, and ^C. In the fourth case, EXTRACT selects all global names
- from ^TMP through ^TMPzzzzz.
+ D[OWNGRADE] -V[ERSION]={V4|V5} file-name
- By default, EXTRACT selects all globals, as if it had the
- qualifier -SELECT=*.
+ For V4:
--FORMAT
- -FO[RMAT]=GO|B[INARY]
- Specifies the format of the output file.
+ o It reduces the size from 8 bytes to 4 bytes for fields like current
+ transaction (CTN), maximum tn (MTN) and others that contain
+ transaction numbers.
+ o It removes the results of any prior DBCERTIFY run on the database.
+ o You cannot downgrade a V5 database which has standard null collation.
+ In such a case, perform a MUPIP EXTRACT -FORMAT=ZWR operation on the
+ V5 database and then perform a MUPIP LOAD operation on a V4 database.
- The format codes are:
+3 VERSION
+ VERSION
- o GO - Global Output format, used for files you want to
- transport or archive
+ Specifies file header format. For more information on the downgrade
+ criteria for your database, refer to the release notes document of your
+ current GT.M version.
- o B[INARY] - Binary format, used for database reorganization
- or short term backups
+3 Examples
+ Examples
- -FORMAT=GO stores the data in record pairs. Each global node
- produces one record for the key and one for the data. FORMAT=GO
- has two header records.
+ Example:
- -FORMAT=BINARY only applies for Greystone Technology Database
- Structure (GDS) files. EXTRACT -FORMAT=BINARY works much faster
- than EXTRACT -FORMAT=GO.
+ $ mupip downgrade mumps.dat
- By default, EXTRACT uses -FORMAT=GO.
+ This command changes the file-header of mumps.dat to V4 format.
--FREEZE
- -FR[EEZE]
- Prevents database updates to all regions of the Global Directory
- used by the EXTRACT for the duration of the EXTRACT.
+2 ENDIANCVT
+ ENDIANCVT
- By default, EXTRACT does not freeze regions during operation.
+ Converts a database file from one endian format to the other (BIG to
+ LITTLE or LITTLE to BIG). The format of the MUPIP ENDIANCVT command is:
--LABEL
- -LA[BEL]=text
- Specifies a text string which becomes the first record in the
- output file. Enclose labels containing punctuation or lowercase
- labels in quotes (""). EXTRACT -FORMAT=BINARY truncates the
- label text to 32 characters.
+ ENDIANCVT [-OUTDB=<outdb-file>] -OV[ERRIDE] <db-file>
- By default, EXTRACT uses the label "GT.M MUPIP EXTRACT".
+ o <db-file> is the source database for endian conversion. By default
+ ENDIANCVT converts <db-file> in place.
+ o outdb writes the converted output to <outdb-file>. In this case,
+ ENDIANCVT does not modify the source database <db-file>.
+ o ENDIANCVT produces a <outdb-file>of exactly the same size as
+ <db-file>.
- For a description of the -FORMAT=BINARY header label, refer to
- the subsequent section on EXTRACT -FORMAT=BINARY.
+ **Important**
--LOG
- -[NO]LO[G]
- Specifies whether or not to display a message on SYS$OUTPUT for
- each global extracted. The message shows the number of global
- nodes, the maximum subscript length and maximum data length for
- each global.
+ Ensure adequate storage for <outdb-file> to complete the endian
+ conversion successfully.
- By default, EXTRACT operates -LOG.
+ o ENDIANCVT requires standalone access to the database.
+ o GT.M displays a confirmation request with the "from" and "to" endian
+ formats to perform the conversion. Conversion begins only upon
+ receiving positive confirmation, which is a case insensitive "yes".
+ o In a multi-site replication configuration, the receiver server
+ automatically detects the endian format of an incoming replication
+ stream and converts it into the native endian format. See Database
+ Replication chapter for more information.
+ o Encrypted database files converted with ENDIANCVT require the same key
+ and the same cipher that were used to encrypt them.
-1 Global_dir
- MUPIP and the Global Directory
- Some of the MUPIP commands require information contained in the Global
- Directory. Therefore, a process must have access to a valid Global
- Directory before using any MUPIP database service commands other than
- JOURNAL, RESTORE, and the -FILE options of INTEG and SET.
+ **Note**
- The environment variable gtmgbldir specifies the Global Directory.
- Define gtmgbldir at the shell level. Individual users define gtmgbldir
- in their login or other shell scripts.
+ GT.M on a big endian platform can convert a little endian database into
+ big endian and vice versa; as can GT.M on a little endian platform. GT.M
+ (run-time and utilities other than MUPIP ENDIANCVT) on a given endian
+ platform opens and processes only those databases that are in the same
+ endian format. An attempt to open a database of a format other than the
+ native endian format produces an error.
- Example
+3 OVerride
+ OVerride
- $ gtmgbldir=prod.gld
- $ export gtmgbldir
+ Enables MUPIP ENDIANCVT to continue operations even if GT.M encounters the
+ following errors:
-1 HELP
- H[ELP]
- HELP provides online information about MUPIP commands and qualifiers.
+ o "minor database format is not the current version"
+ o "kills in progress"
+ o "a GT.CM server is accessing the database"
- The format of the HELP command is:
+ Note that the OVERRIDE qualifier does not override critical errors
+ (database integrity errors, and so on) that prevent a successful endian
+ format conversion.
- H[ELP] [options...]
+3 Examples
+ Examples
- The HELP command does not accept any qualifiers. Enter the MUPIP
- command for which you want information at the Topic prompt. Use
- <RETURN> or <CTRL Z> to leave the help facility.
+ $ mupip endiancvt mumps.dat -outdb=mumps_cvt.dat
+ Converting database file mumps.dat from LITTLE endian to BIG endian on a LITTLE endian system
-1 INTEG
- I[NTEG]
- The INTEG command performs an integrity check on a GDS database file.
- INTEG operates on one or more regions in the current global directory
- by suspending concurrent updates to those regions. INTEG of a single
- file database without a Global Directory requires exclusive
- (stand-alone) access to that file.
+ Converting to new file mumps_cvt.dat
- Use INTEG at the following times:
+ Proceed [yes/no] ?
- o Periodically - to insure ongoing integrity of database(s); frequent
- INTEGs help catch integrity problems before they spread through the
- database file
+ This command detects the endian format of mumps.dat and converts it to the
+ other endian format if you type yes to confirm.
- o After a crash - to insure the database was not corrupted
+2 EXIT
+ EXIT
- o When database errors are reported - to troubleshoot the problem
+ Stops a MUPIP process and return control to the process from which MUPIP
+ was invoked.
- The format of the INTEG command is:
+ The format of the MUPIP EXIT command is:
- I[NTEG][-qualifier[...]] file-spec | region-list
+ EXI[T]
- The filename directly identifies the GDS file to INTEG. The
- region-list identifies one or more regions that in turn identify GDS
- files through the current Global Directory.
+ The EXIT command does not accept any qualifiers.
- Always analyze errors reported by INTEG immediately to prevent further
- corruption. Greystone strongly recommends fixing the following errors
- as soon as they are discovered:
+2 EXTEND
+ EXTEND
- o Blocks incorrectly marked free - these may cause accelerating
- damage when processes make updates to any part of the database
- region.
+ Increases the size of a database file. By default, GT.M automatically
+ extends a database file when there is available space.
- o Integrity errors in an index block - these may cause accelerating
- damage when processes make updates to that area of the database
- region that uses the faulty index.
+ The format of the MUPIP EXTEND command is:
- INTEG -FAST and the "regular" INTEG both report these errors. Other
- database errors do not pose the threat of rapidly spreading problems
- in GDS files, but if operations continue the errors may cause the
- following:
+ EXTE[ND] [-BLOCKS=<data-blocks-to-add>] region-name
- o Invalid application operation due to "missing" data
+ o The only qualifier for MUPIP EXTEND is BLOCKS.
+ o The required region-name parameter specifies the name of the region to
+ expand.
+ o EXTEND uses the Global Directory to map the region to the dynamic
+ segment and the segment to the file.
- o Process errors when a database access encounters an error
+3 Blocks
+ Blocks
- o Degrading application level integrity as a result of incomplete
- update sequences caused by the prior symptoms
+ 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:
+
+ -BLOCKS=data-blocks-to-add
+
+ By default, EXTEND uses the extension value in the file header as the
+ number of GDS blocks by which to extend the database file. You can specify
+ as many blocks as needed as long as you are within the maximum total
+ blocks limit (which could be as high as 224 million GDS blocks).
+
+3 Examples
+ Examples
+
+ $ mupip extend DEFAULT -blocks=400
+
+ This command adds 400 GDE database block to region DEFAULT.
+
+ Example:
+
+ $ mupip extend REPTILES -blocks=100
+
+ This command adds 100 GDE database blocks to the region REPTILES.
+
+2 EXTRACT
+ EXTRACT
+
+ Backups certain globals or to extract data from the database for use by
+ another system. The MUPIP EXTRACT command copies globals from the current
+ database to a sequential output file in one of three formats-GO, BINARY,
+ or ZWR. The format of the EXTRACT command is:
+
+ EXTR[ACT]
+ [
+ -FO[RMAT]={GO|B[INARY]|Z[WR]}
+ -FR[EEZE]
+ -LA[BEL]=text
+ -[NO]L[OG]
+ -S[ELECT]=global-name-list]
+ ]
+ {-ST[DOUT]|file-name}
+
+ o By default, MUPIP EXTRACT uses -FORMAT=ZWR.
+ o MUPIP EXTRACT uses the Global Directory to determine which database
+ files to use.
+ o MUPIP EXTRACT supports user collation routines. When used without the
+ -FREEZE qualifier, EXTRACT may operate concurrently with normal GT.M
+ database access.
+ o To ensure that MUPIP EXTRACT reflects a consistent application state,
+ suspend the database updates to all regions involved in the extract,
+ typically with the FREEZE qualifier, or backup the database with the
+ ONLINE qualifier and extract files from the backup.
+ o EXTRACT places its output in the file defined by the file- name.
+ EXTRACT may output to a UNIX file on any device that supports such
+ files, including magnetic tapes.
+ o In UTF-8 mode, MUPIP EXTRACT write sequential output file in the UTF-8
+ character encoding. Ensure that MUPIP EXTRACT commands and
+ corresponding MUPIP LOAD commands execute with the same setting for
+ the environment variable gtm_chset.
+
+ **Note**
+
+ Magnetic tapes may have a smaller maximum file size than disks.
+
+ For information on extracting globals with the %GO utility, refer to "M
+ Utility Routines" chapter of the GT.M Programmer's Guide. MUPIP EXTRACT is
+ typically faster, but %GO can be customized.
+
+ The following sections describe the qualifiers of MUPIP EXTRACT command.
+
+3 FOrmat
+ FOrmat
+
+ Specifies the format of the output file. The format of the FORMAT
+ qualifier is:
+
+ -FO[RMAT]=format_code
+
+ The format code is any one of the following:
+
+ o B[INARY] - Binary format, used for database reorganization or short
+ term backups. MUPIP EXTRACT -FORMAT=BINARY works much faster than
+ MUPIP EXTRACT -FORMAT=GO and MUPIP EXTRACT -FORMAT=ZWR. Note: There is
+ no defined standard to transport binary data from one GT.M
+ implementation to another. Further, FIS reserves the right to modify
+ the binary format in new versions. The first record of a BINARY format
+ data file contains the header label. The header label is 87 characters
+ long. The following table illustrates the components of the header
+ label.
+
+ +--------------------------------------------------------------------+
+ | BINARY Format Data File Header Label |
+ |--------------------------------------------------------------------|
+ | CHARACTERS | EXPLANATION |
+ |------------+-------------------------------------------------------|
+ | 1-26 | Fixed-length ASCII text: "GDS BINARY EXTRACT LEVEL |
+ | | 4". |
+ |------------+-------------------------------------------------------|
+ | 27-40 | Date and time of extract in the $ZDATE() format: |
+ | | "YEARMMDD2460SS". |
+ |------------+-------------------------------------------------------|
+ | 41-45 | Decimal maximum block size of the union of each |
+ | | region from which data was extracted. |
+ |------------+-------------------------------------------------------|
+ | 46-50 | Decimal maximum record size of the union of each |
+ | | region from which data was extracted. |
+ |------------+-------------------------------------------------------|
+ | 51-55 | Decimal maximum key size of the union of each region |
+ | | from which data was extracted. |
+ |------------+-------------------------------------------------------|
+ | | Space-padded label specified by the -LABEL qualifier. |
+ | 56-87 | For extracts in UTF-8 mode, GT.M prefixes UTF-8 and a |
+ | | space to -LABEL. The default LABEL is "GT.M MUPIP |
+ | | EXTRACT" |
+ +--------------------------------------------------------------------+
+
+ o GO - Global Output format, used for files to transport or archive.
+ -FORMAT=GO stores the data in record pairs. Each global node produces
+ one record for the key and one for the data. MUPIP EXTRACT -FORMAT=GO
+ has two header records - the first is a test label (refer to the LABEL
+ qualifier) and the second contains a data, and time.
+ o ZWR - ZWRITE format, used for files to transport or archive that may
+ contain non-graphical information. Each global node produces one
+ record with both key and data. MUPIP EXTRACT -FORMAT=ZWR has two
+ header records, which are the same as for FORMAT=GO, except that the
+ second record ends with the text " ZWR"
+
+3 FReeze
+ FReeze
+
+ Prevents database updates to all database files from which the MUPIP
+ EXTRACT command is copying records. FREEZE ensures that a MUPIP EXTRACT
+ operation captures a "sharp" image of the globals, rather than one
+ "blurred" by updates occurring while the copy is in progress.
+
+ The format of the FREEZE qualifier is:
+
+ -FR[EEZE]
+
+ By default, MUPIP EXTRACT does not "freeze" regions during operation.
+
+3 LAbel
+ LAbel
+
+ Specifies the text string that becomes the first record in the output
+ file. MUPIP EXTRACT -FORMAT=BINARY truncates the label text to 32
+ characters. The format of the LABEL qualifier is:
+
+ -LA[BEL]=text
+
+ o By default, EXTRACT uses the label "GT.M MUPIP EXTRACT."
+ o For more detailed information about the -FORMAT=BINARY header label,
+ refer to the description of EXTRACT -FORMAT=BINARY.
+
+3 LOg
+ LOg
+
+ Displays a message on stdout for each global extracted with the MUPIP
+ EXTRACT command. The message displays the number of global nodes, the
+ maximum subscript length and maximum data length for each global. The
+ format of the LOG qualifier is:
+
+ -[NO]LO[G]
- You must assess the type of damage, the risk of continued operations,
- and the disruption of stopping normal operation for database repair.
- For information on analyzing and correcting database errors, refer to
- the "Database Integrity" chapter in the GT.M Administration and
- Operations Guide.
+ By default, EXTRACT operates -LOG.
- <CTRL C> aborts INTEG. Because INTEG does most of its reporting at the
- end, aborting the process before it completes may not give you all the
- information you need.
+3 Select
+ Select
-2 -FAST
- -FA[ST]
- Specifies that INTEG checks only index blocks. INTEG -FAST does not
- check data blocks. INTEG -FAST produces results dramatically faster
- than a full INTEG. While INTEG -FAST is not a replacement for a
- full INTEG, it very quickly detects the most dangerous structural
- errors in a database.
+ Specifies globals for a MUPIP EXTRACT operation. The format of the SELECT
+ qualifier is:
- The -FAST qualifier is incompatible with the -TN_RESET qualifier.
+ -S[ELECT]= global-specification
- By default, INTEG checks all active index and data blocks in the
- database.
+ o By default, EXTRACT selects all globals, as if it had the qualifier
+ -SELECT=*
+ o The caret symbol (^) in the specification of the global name is
+ optional.
-2 -REGION
- -R[EGION]
- Specifies that the INTEG parameter identifies one or more regions
- rather than a database file.
-
- INTEG -REGION does not require sole access to databases. Instead,
- it freezes updates to the database during the check. The
- region-list argument may specify more than one region of the
- current Global Directory in a list separated with commas. INTEG
- -REGION requires the environment variable gtmgbldir to specify a
- valid Global Directory. For more information on defining gtmgbldir,
- refer to the "Global Directory Editor" chapter of the GT.M
- Administration and Operations Guide.
-
- Note: Because a KILL may briefly defer marking the blocks it
- releases "free" in the bit maps, INTEG -REGION may report spurious
- block incorrectly marked busy errors. Because block incorrectly
- marked busy errors are benign, ignore these errors unless INTEG
- consistently reports a block as incorrectly marked busy.
-
- The -REGION qualifier is incompatible with the -FILE and -TN_RESET
- qualifiers.
-
- By default, INTEG operates -FILE.
-
-2 -FILE
- -FI[LE]
- Specifies that the parameter to the INTEG command is a filename.
- INTEG -FILE requires exclusive (stand-alone) access to a database
- file and does not require a Global Directory. Because it has
- stand-alone access to the file, INTEG -FILE is able to check
- reference counts.
-
- The -FILE qualifier is incompatible with the -REGION qualifier.
-
- By default, INTEG operates -FILE.
-
-2 -TN_RESET
- -TN[_RESET]
- Instructs an INTEG -FILE to reset the transaction number to one in
- every database block currently holding valid data.
-
- Transaction number overflow back to 0 disrupts the integrity of the
- database.
+ The global-specification can be:
- The -TN_RESET qualifier is incompatible with the -BLOCK, -FAST,
- -REGION and -SUBSCRIPT qualifiers.
+ o A parenthetical list, such as (a,B,C). In this case, MUPIP EXTRACT
+ selects all globals except ^a, ^B, and ^C.
+ o A global name, such as MEF. In this case, MUPIP EXTRACT selects only
+ global ^MEF.
+ o A range of global names, such as A7:B6. In this case, MUPIP EXTRACT
+ selects all global names between ^A7 and ^B6, inclusive.
+ o A list, such as A,B,C. In this case, MUPIP EXTRACT selects globals ^A,
+ ^B, and ^C.
+ o Global names with the same prefix, such as PIGEON*. In this case,
+ EXTRACT selects all global names from ^PIGEON through ^PIGEONzzzzz.
- By default, INTEG does not modify the block transaction numbers.
+ **Note**
-2 -SUBSCRIPT
- -S[UBSCRIPT]=subscript
- Specifies a global or a range of keys to INTEG. Enclose the global
- key in quotes ("") and identify a range by separating two
- subscripts with a colon (:). -SUBSCRIPT limits map checking to
- incorrectly marked free errors.
+ If the rules for selection are complex, it may be easier to construct an
+ ad hoc Global Directory that maps the global variables to be extracted to
+ the database file. This may not be permissible if the database file is
+ part of a replicated instance. If this is the case, work with a backup of
+ the database.
- Use -SUBSCRIPT only if you know the path to the keys in the
- subscript and have reason to believe the path is not damaged. If
- the path is questionable or known to be damaged, use DSE to find
- the block(s) and INTEG -BLOCK.
+3 STdout
+ STdout
- The -SUBSCRIPT qualifier is incompatible with the -BLOCK and
- -TN_RESET qualifiers.
+ Redirects database extract to the standard output stream. The format of
+ the STDOUT qualifier is:
- Use -FULL to have INTEG report all global-names covered by a range.
+ -ST[DOUT]
-2 Examples
- INTEG -SUBSCRIPT= Examples
+3 Examples
+ Examples
- Example
+ Example:
- MUPIP INTEG -SUBSCRIPT="^a" MUMPS.DAT
+ $ mupip extract -format=go -freeze big.glo
- This INTEGs the global variable ^a in the database file MUMPS.DAT.
+ This command prevents database updates during a MUPIP EXTRACT operation.
- Example
+ Example:
- MUPIP INTEG-SUBSCRIPT="^a(100)":"^b(""c"")"-reg DEFAULT
+ $ mupip extract -format=GO mumps_i.go
- This INTEGs all global variables greater than or equal to ^a(100)
- and less than ^b("c") in the default region.
+ This command creates an extract file called mumps_i.go in "Global Output"
+ format. Use this format to transport or archive files. The first record of
+ a GO format file contains the header label, "GT.M MUPIP EXTRACT," as text.
- Note: To specify a literal in the command string, use double quotes
- e.g., ^b(""c"").
+ Example:
-2 -BLOCK
- -BL[OCK]=block-number
- Specifies the block at which to start checking a sub-tree of the
- database. -BLOCK limits map checking to incorrectly marked free
- errors.
+ $ mupip extract -format=BINARY v5.bin
- The -BLOCK qualifier is incompatible with the -SUBSCRIPT and
- -TN_RESET qualifiers.
+ This command creates an extract file called v5.bin in Binary format. Use
+ this format for reorganizing a database or for short-term backups.
-2 -KEYRANGES
- -[NO]K[EYRANGES]
- Specifies whether or not the INTEG report includes key ranges that
- identify the data suspected of problems detected by INTEG.
+ Example:
- By default, INTEG displays -KEYRANGES.
+ $ mupip extract -format=ZWR -LABEL=My_Label My_Extract_File
-2 -MAP
- -[NO]MAP[=integer]
- Specifies the maximum number of incorrectly marked busy errors that
- INTEG reports.
+ This example extracts all globals from the current database to file
+ My_Extract_File (in ZWRITE format) with label My_Label.
- -NOMAP removes limits on incorrectly marked busy reporting, i.e.,
- INTEG reports all map errors. -NOMAP does not accept assignment of
- an argument.
+ Example:
- Because incorrectly marked free errors are very dangerous, INTEG
- always reports them, and -MAP does not affect them.
-
- An error in an index block prevents INTEG from processing
- potentially large areas of the database. A single "primary" error
- may cause large numbers of "secondary" incorrectly marked busy
- errors. Because "real" or primary incorrectly marked busy errors
- only make "empty" blocks unavailable to the system, they are
- relatively benign.
-
- By default, INTEG reports a maximum of 10 map errors (-MAP=10).
-
-2 -MAXKEYSIZE
- -[NO]MAX[KEYSIZE][=integer]
- Specifies the maximum number of key size too large errors that
- INTEG reports.
-
- -NOMAXKEYSIZE removes limits on key size reporting, i.e., INTEG
- reports all key size too large errors. -NOMAXKEYSIZE does not
- accept assignment of an argument.
-
- Key size too large error should only occur after someone uses DSE
- CHANGE -FILEHEADER -KEY_MAX_SIZE to reduce the maximum key-size.
-
- By default, INTEG reports a maximum of 10 key size errors
- (-NOMAXKEYSIZE=10).
-
-2 -TRANSACTION
- -[NO]TR[ANSACTION][=integer]
- Specifies the maximum number of block transaction number too large
- errors that INTEG reports.
-
- -NOTRANSACTION removes limits on transaction reporting, i.e.,
- INTEG reports all transaction number errors. -NOTRANSACTION does
- not accept assignment of an argument.
-
- A system crash may generate many block transaction number too large
- errors. These errors can cause problems for BACKUP -INCREMENTAL,
- but have no effect on the run-time environment. The DSE CHANGE
- -FILEHEADER -BLOCKS_FREE= command quickly fixes block transaction
- number too large number errors.
-
- By default, INTEG reports a maximum of 10 block transaction errors
- (-TRANSACTION=10).
-
-2 -BRIEF
- -BR[IEF]
- Specifies an INTEG summary report which displays the total number
- of directory, index and data blocks. The -BRIEF qualifier is
- incompatible with the -FULL qualifier.
-
- By default, INTEG reports are -BRIEF.
-
-2 -FULL
- -FU[LL]
- Specifies an expanded INTEG report which displays the number of
- index and data blocks in the directory tree and in each global tree
- as well as the total number of directory, index and data blocks.
- The -FULL qualifier is incompatible with the -BRIEF qualifier.
+ $ mupip extract -nolog FL.GLO
- By default, INTEG reports are -BRIEF.
+ This command creates a global output file, FL.GLO, (which consists of all
+ global variables in the database) without displaying statistics on a
+ global-by-global basis. As there is no label specified, the first record
+ in FL.GLO contains the text string "GT.M MUPIP EXTRACT."
-2 -ADJACENCY
- -A[DJACENCY]=integer
- Specifies the range of blocks within which INTEG considers a block
- adjacent to another database block on the same level. The adjacency
- report from INTEG gives an approximation of physical data density
- which directly affects efficient database access. Use the
- -ADJACENCY qualifier to adjust the reporting to reflect
- characteristics of your disks, e.g., pick a factor that matches the
- number of sectors on a drive.
+ Example:
- By default, INTEG uses -ADJACENCY=10.
+ $ mupip extract -select=Tyrannosaurus /dev/tty
-1 JOURNAL
- J[OURNAL]
+ This command instructs EXTRACT to dump the global ^Tyrannosaurus to the
+ device (file-name) /dev/tty.
- The MUPIP JOURNAL command analyzes, extracts from, reports on, and
- recovers journal files.
+2 FREEZE
+ FREEZE
- Another MUPIP command, SET, turns journaling on and off, identifies
- the type of journaling, and sets some database journaling
- characteristics.
+ Temporarily suspends (freezes) updates to the database. If you prefer a
+ non-GT.M utility to perform a backup or reorganization, you might use this
+ facility to provide standalone access to your GT.M database. You might use
+ MUPIP FREEZE to suspend (and later resume) database updates for creating
+ mirrored disk configuration or re-integrating a mirror.
- The format for the JOURNAL command is:
+ GT.M BACKUP, INTEG, and REORG operations may implicitly freeze and
+ unfreeze database regions. However, for most operations, this
+ freeze/unfreeze happens internally and is transparent to the application.
- MUPIP J[OURNAL] -qualifier[...] file-specification[,...]
-
+ The format of the MUPIP FREEZE command is:
-2 Action_qualifiers
- Action Qualifiers
+ F[REEZE] {-OF[F] [-OV[ERRIDE]]|-ON [-R[ECORD]]} region-list
--RECOVER
- -REC[OVER]
- Instructs the JOURNAL command to replay database updates in the
- specified journal file into the appropriate database. -RECOVER
- initiates the central JOURNAL operation. JOURNAL commands may
- specify -RECOVER alone or with other action qualifiers.
+ o The region-list identifies the target of the FREEZE.
+ o MUPIP FREEZE waits for one minute so that concurrent KILL or MUPIP
+ REORG operations can complete. If the KILL or MUPIP REORG commands do
+ not complete within one minute, MUPIP FREEZE terminates operations and
+ unfreezes any regions it had previously marked as frozen.
+ o To ensure that a copy or reorganized version of a database file
+ contains a consistent set of records, concurrent MUPIP utilities, such
+ as BACKUP (without the ONLINE qualifier) and EXTRACT, include
+ mechanisms to ensure that the database does not change while the MUPIP
+ utility is performing an action. FIS recommends the use of the -ONLINE
+ qualifier with BACKUP.
+ o A MUPIP FREEZE can be removed only by the user who sets the FREEZE or
+ by using -OVERRIDE.
+ o After MUPIP FREEZE -ON, processes that are attempting updates "hang"
+ until the FREEZE is removed by the MUPIP FREEZE -OFF command or DSE.
+ Make sure that procedures for using MUPIP FREEZE, whether manual or
+ automated, include provisions for removing the FREEZE in all
+ appropriate cases, including when errors disrupt the normal flow.
+ o A -RECOVER/-ROLLBACK for a database reverts to a prior database update
+ state. Therefore, a -RECOVER/-ROLLBACK immediately after a MUPIP
+ FREEZE -ON removes the freeze. However, -RECOVER/-ROLLBACK does not
+ succeed if there are processes attached (for example when a process
+ attempt a database update immediately after a MUPP FREEZE -ON) to the
+ database.
--VERIFY
- -[NO]V[ERIFY]
- Checks a journal file for proper form. JOURNAL commands may
- specify -VERIFY alone or with other action qualifiers. JOURNAL
- -RECOVER commands implicitly -VERIFY the file(s) on which they
- operate. JOURNAL -RECOVER ignores -NOVERIFY for all qualifier
- combinations that do not include -FORWARD and -FENCES=NONE.
+ FREEZE must include one of the qualifiers:
--EXTRACT
- -EX[TRACT][=file-specification]
- Specifies that JOURNAL transfer the contents of one or more
- journal files to a single output file in a format intended for
- processing by a MUMPS program. For a description of -EXTRACT
- output record formats, refer to the section on JOURNAL -EXTRACT
- output records. JOURNAL commands may specify -EXTRACT alone or
- with other action qualifiers.
+ -OF[F]
+ -ON
- -EXTRACT takes an optional argument, which provides an output
- file-specification.
+ The optional qualifiers are:
- By default, MUPIP JOURNAL derives the output file specification
- using the name of the original database file associated with the
- journal and a file type of .MJF. If the command specifies more
- than one journal file, JOURNAL -EXTRACT derives the default
- output file specification from the name of the first database.
+ -OV[ERRIDE]
+ -R[ECORD]
--SHOW
- -SH[OW]=show-option-list
- Specifies what information the JOURNAL command displays about a
- journal file. JOURNAL commands may specify -SHOW alone or with
- other action qualifiers.
+3 OFf
+ OFf
- For information on the options refer to the show-option-list
- topic.
+ Clears a freeze set by another process with the same userid.
-2 show-option-list
- show-option-list
+ The format of the OFF qualifier is:
- The following topics detail the show-option-list elements.
+ OF[F]
-3 ALL
- AL[L]
- ALL displays every available type of information about the
- journal file. For additional information, refer to the
- descriptions of each of the other SHOW keywords.
+ o When used with -OVERRIDE, -OFF stops a freeze operation set by a
+ process with a different userid.
+ o Incompatible with: -ON, -RECORD
-3 HEADER
- H[EADER]
- HEADER displays the journal file header information.
+3 ON
+ ON
- This includes:
+ Specifies the start of a MUPIP FREEZE operation. The format of the ON
+ qualifier is:
- o Database file name
+ -ON
- o Journal file name
+ Incompatible with: -OFF, -OVERRIDE
- o Journal file version label (.e.g. GDSJNLnn)
+3 OVERRIDE
+ OVERRIDE
- o Whether before-images were captured
+ Release a freeze set by a process with a different userid. GT.M provides
+ OVERRIDE to allow error recovery in case a procedure with a freeze fails
+ to release. The format of the OVERRIDE qualifier is:
- o Journal creation time/date
+ -OV[ERRIDE]
- o Journal creator
+ o OVERRIDE should not be necessary (and may even be dangerous) in most
+ schemes.
+ o Incompatible with: -ON, -RECORD
- o The last user to open the journal
+3 Record
+ Record
- o The last time the journal file was opened
+ Specifies that a MUPIP FREEZE operation should record an event as a
+ reference point. You might use MUPIP FREEZE to set up your database for a
+ custom-backup mechanism (SAN or mirror-based).
- The information for the creator and last user includes:
+ The format of the RECORD qualifier is:
- o Process Name
+ -R[ECORD]
- o Process Identification Number
+ o You might use -RECORD to integrate MUPIP BACKUP -BYTESTREAM with an
+ external backup mechanism.
+ o -RECORD replaces the previously RECORDed transaction identifier for
+ the database file.
+ o Incompatiable with: -OFF and -OVERRIDE.
- o Node Name
+3 Examples
+ Examples
- o Terminal Number
+ Example:
-3 PROCESSES
- P[ROCESSES]
- PROCESSES displays all processes active during the period
- specified implicitly or explicitly by JOURNAL command time
- qualifiers.
+ $ mupip freeze -off DEFAULT
-3 ACTIVE_PROCESSES
- AC[TIVE_PROCESSES]
- ACTIVE_PROCESSES displays all processes active at the end of the
- period specified implicitly or explicitly by JOURNAL command
- time qualifiers.
+ This command stops an ongoing MUPIP FREEZE operation on the region
+ DEFAULT.
-3 BROKEN_TRANSACTIONS
- B[ROKEN_TRANSACTIONS]
- BROKEN_TRANSACTIONS displays all processes that had incomplete
- fenced transactions at the end of the period covered by the
- JOURNAL command.
+ Example:
-3 STATISTICS
- S[TATISTICS]
- STATISTICS displays a count of all journal record types
- processed during the period specified implicitly or explicitly
- by JOURNAL command time qualifiers.
+ $ mupip freeze -on "*"
-2 Direction_qualifiers
- Direction Qualifiers
+ This command prevents updates to all regions in the current Global
+ Directory.
--FORWARD
- -FO[RWARD]
- Specifies that JOURNAL processing should proceed from the
- beginning of the given journal files. If the actions include
- -RECOVER, the target database file should contain a copy of that
- database made at the time when MUPIP SET -JOURNAL= created the
- journal files.
+ Example:
- -FORWARD is incompatible with -BACKWARD.
+ $ set +e
+ $ mupip freeze -on -record "*"
+ $ tar cvf /dev/tape /prod/appl/*.dat
+ $ mupip freeze -off
+ $ set -e
--BACKWARD
- -BA[CKWARD]
- Specifies that JOURNAL processing should proceed from the end of
- the journal files. If the actions include -RECOVER, JOURNAL
- -BACKWARD starts restoring before-images starting at the end of
- the file, back to an explicitly or implicitly specified point
- before it "reverses" and processes database updates in the
- forward direction. The target database file should "match" the
- end of the journal file, i.e., be the same as when GT.M wrote
- the last record of the journal.
+ The set +e command instructs the shell to attempt all commands in the
+ sequence , regardless of errors encountered by any command. This ensures
+ that the freeze -off is processed even if the tar command fails. FREEZE
+ prevents updates to all database files identified by the current Global
+ Directory. The -record qualifier specifies that the current transaction in
+ each database be stored in the RECORD portion of the database file header.
+ The tar command creates a tape archive file on the device /dev/tape,
+ containing all the files from /prod/app that have an extension of .dat.
+ Presumably all database files in the current Global Directory are stored
+ in that directory, with that extension. The second FREEZE command
+ re-enables updates that were suspended by the first FREEZE. The set -e
+ command re-enables normal error handling by the shell.
- -BACKWARD is incompatible with -FORWARD.
+ Example:
-2 Time_qualifiers
- Journal time specifications
- Journal qualifiers specifying time take arguments in absolute or
- delta time format. Enclose time arguments in quotes ("") and
- include all leading delimiters. Absolute format is "day-mm-yyyy
- hh:mm:ss:cc" , where cc represents hundredths of a second. Absolute
- time may indicate today's date with "--" before the hours. Delta
- format is "day hh:mm:ss:cc" , where cc represents hundredths of a
- second. If delta time is less than a day, it must start with zero
- (0) followed by a space, or just a space, before the hours. Delta
- time is always relative to the time of the last record in all
- journal file arguments to the MUPIP JOURNAL command. A normal
- database closure, caused by the last accessing process leaving
- GT.M, also properly closes the associated journal file.
- Alternatively, a system failure causes the journal to end in an
- abnormal or "disorganized" fashion. JOURNAL processing deals with
- both cases.
-
- The time qualifiers perform as follows:
-
- o -AFTER= only applies to JOURNAL -EXTRACT -FORWARD and specifies
- a starting time; processing for all other -FORWARD actions must
- start at the beginning of the journal files
-
- o -BEFORE= specifies an ending time for any action -FORWARD or
- -BACKWARD
-
- o -SINCE= specifies a starting time for any action -BACKWARD
-
- o -LOOKBACK_LIMIT= specifies a "safety zone" for resolving open
- fenced transactions when processing any action -BACKWARD; the
- -LOOKBACK_LIMIT= argument may be a list of limits: "TIME=time"
- and/or "OPERATIONS=integer"
-
- Because GT.M rounds time-stamps within the journal to hundredths of
- a second and the JOURNAL processing can only determine time as
- exactly as the journal records permit, the JOURNAL command
- processes specified times in a "fuzzy" fashion. Because they deal
- with processing completed logical transactions, -SINCE= and
- -LOOKBACK= times have more "blur" than -AFTER= and -BEFORE= times.
-
--AFTER
- -A[FTER]=time
- Specifies the starting time for JOURNAL -EXTRACT -FORWARD to
- commence output. The time specified references time stamps in
- the journal and identifies the point after which JOURNAL
- processing starts extracting information out of the journal
- file. -AFTER= specifies time in absolute or delta time formats.
- Delta format specifies an offset from the time of the last
- record of the journal file. If -AFTER= provides a time following
- the last time recorded in the journal file or following any
- -BEFORE= time, JOURNAL processing produces no result. Using
- -BEFORE= with -AFTER= restricts -EXTRACT to a particular period
- of time.
-
- -AFTER= is incompatible with -BACKWARD and with all action
- qualifiers except -EXTRACT.
-
- By default, -EXTRACT starts at the beginning of the journal
- file.
+ $ mupip freeze -override -off DEFAULT
--BEFORE
- -BE[FORE]=time
- Specifies the ending time at which JOURNAL processing stops
- extracting or recovering data. The time specified references
- time stamps in the journal files. -BEFORE= specifies time in
- absolute or delta time formats. Delta format specifies an offset
- from the time stamp in the last record of each the journal file.
- If -BEFORE= provides a time preceding the first time recorded in
- the journal file or preceding any -AFTER= or -SINCE= time,
- JOURNAL processing produces no result.
+ This command unfreezes the DEFAULT region even if the freeze was set by a
+ process with a different userid.
- -BEFORE= is compatible with all other JOURNAL qualifiers.
+2 FTOK
+ FTOK
- By default, JOURNAL processing terminates at the end of the
- journal file.
+ Produces the "public" (system generated) IPC Keys (essentially hash
+ values) of a given file.
--SINCE
- -SI[NCE]=time
- Specifies how far back in time JOURNAL -BACKWARD should process
- from the end of the journal file, before starting its forward
- processing. The time specified references time stamps in the
- journal files. -SINCE= specifies time in absolute or delta time
- formats. Delta format specifies an offset from the time of the
- last record of the journal file. When JOURNAL -BACKWARD locates
- the -SINCE= time, if it has open fenced transactions, it
- continues processing backward to resolve them unless the command
- also specifies -FENCES=NONE. The -LOOKBACK= qualifier controls
- the length of processing backward past the -SINCE= time.
-
- If -SINCE= time exceeds the last time recorded in the journal
- files, JOURNAL processing effectively ignores the qualifier.
- -SINCE= is incompatible with -FORWARD. If -SINCE= provides a
- time preceding any -BEFORE= time, JOURNAL processing produces no
- result.
-
- By default, JOURNAL -BACKWARD processes the last five (5)
- minutes of the journal file(s).
-
--LOOKBACK_LIMIT
- -[NO]LOO[KBACK_LIMIT][=lookback-option-list]
- Specifies how far JOURNAL -BACKWARD processes back past the
- explicit (-SINCE=) or implicit turn around time while attempting
- to resolve open transaction fences. -LOOKBACK= options include
- time and transaction counts.
-
- -NOLOOKBACK_LIMIT specifies that JOURNAL -BACKWARD can process
- all the way to the beginning of the journal file, if necessary,
- to resolve open transaction fences.
-
- -LOOKBACK_LIMIT= is incompatible with -FORWARD. When
- -FENCES=NONE, JOURNAL processing ignores -LOOKBACK_LIMIT=.
-
- The lookback-options are:
-
- TIME=time - limits lookback by a specified amount of delta or
- absolute journal time.
-
- OPERATIONS=integer - limits lookback to some number of database
- updates.
-
- The lookback-option names and values must be enclosed in quotes
- (""), e.g., "Time=0 00:05" or "Oper=10." When -LOOKBACK=
- specifies both options, they must be enclosed in parentheses ()
- and separated by a comma (,). When -LOOKBACK= specifies both
- options, the first limit reached terminates the lookback.
-
- By default, MUPIP JOURNAL uses -LOOKBACK_LIMIT="TIME=0 00:05"
- providing five minutes of journal time prior to -SINCE= in which
- to resolve open fences.
-
-2 Control_qualifiers
- Control Qualifiers
-
--REDIRECT
- -RED[IRECT]=file-pair-list
- Specifies that JOURNAL -RECOVER replay the journal file to a
- database different than the one for which it was created. Use
- this qualifier to create or maintain databases for training or
- testing.
+ The format of the MUPIP FTOK command is:
- JOURNAL rejects -REDIRECT unless it appears with -RECOVER.
+ FT[OK] [-DB] [-JNLPOOL] [-RECVPOOL] file-name
- The file-pair-list consists of one or more pairs of
- file-specifications enclosed in parentheses () and separated by
- commas (,). The pairs are separated by an equal sign in the
- form:
+3 DB
+ DB
- old-file-specification=new-file-specification
-
- where the first file-specification names the original database
- file and the second file-specification names the target of the
- -RECOVER. When -REDIRECT specifies only one file pair, the
- parentheses are optional.
+ Specifies that the file-name is a database file. By default, MUPIP FTOK
+ uses -DB.
- By default, JOURNAL directs -RECOVER to the database file from
- which the journal was made.
+3 JNLPOOL
+ JNLPOOL
--FENCES
- -FE[NCES]=fence-option
- Specifies how JOURNAL processes fenced transactions. Fenced
- transactions are logical transactions made up of database
- updates preceded in MUMPS by a ZTSTART command and followed by a
- ZTCOMMIT command. All updates between a ZTSTART and a ZTCOMMIT
- are designed such that they should all occur together, i.e., no
- one of them should reach the database unless they all do.
+ Specifies that the reported key is for the Journal Pool of the instance
+ created by the current Global Directory.
- The fence options are:
+3 RECVPOOL
+ RECVPOOL
- o NONE, which causes JOURNAL to apply all individual updates as
- if transaction fences did not exist
+ Specifies that the reported key is for the Receive Pool of the instance
+ created by the current Global Directory.
- o ALWAYS, which causes JOURNAL to treat any unfenced or
- improperly fenced updates as errors
+2 INTEG
+ INTEG
- o PROCESS, which causes JOURNAL to accept unfenced database
- updates, and also to observe fences when they appear,
- generating an error in the case of a ZTSTART with no
- corresponding ZTCOMMIT
+ Performs an integrity check on a GT.M database file. You can perform
+ structural integrity checks on one or more regions in the current Global
+ Directory without bringing down (suspending database updates) your
+ application. However, a MUPIP INTEG on a single file database requires
+ standalone access but does not need a Global Directory. The order in which
+ the MUPIP INTEG command selects database regions is a function of file
+ system layout and may vary as files are moved or created. Execute a MUPIP
+ INTEG operations one database file at a time to generate an report where
+ the output always lists database files in a predictable sequence. For
+ example, to compare output with a reference file, run INTEG on one file at
+ a time.
- By default, MUPIP JOURNAL uses -FENCES=PROCESS.
+ Always use MUPIP INTEG in the following conditions:
--INTERACTIVE
- -[NO]IN[TERACTIVE]
- Specifies whether, for each error over the -ERROR_LIMIT, JOURNAL
- processing prompts the invoking operator for an answer
- controlling continuation of processing. If the operator responds
- that processing should not continue, the JOURNAL command
- terminates.
-
- -NOINTERACTIVE terminates the journal processing as soon as the
- process generates the number of errors specified in
- -ERROR_LIMIT.
-
- When processing in INTERACTIVE mode, the default is
- -INTERACTIVE, otherwise, e.g., BATCH mode, the default is
- -NOINTERACTIVE.
-
--ERROR_LIMIT
- -[NO]ER[ROR_LIMIT][=integer]
- Specifies the number of errors that JOURNAL processing treats as
- acceptable. When the number of errors exceeds the -ERROR_LIMIT,
- the -INTERACTIVE qualifier determines whether JOURNAL processing
- halts or defers to the operator.
-
- -NOERROR_LIMIT prevents JOURNAL from stopping because of errors.
- Journal processing will continue until it reaches the end of the
- journal file, regardless of the number of errors. Note that
- -NOERROR_LIMIT is not the same as -ERROR_LIMIT=0.
-
- By default, MUPIP JOURNAL uses -ERROR_LIMIT=0, causing the first
- error to initiate the appropriate error action.
-
--CHECKTN
- -[NO]C[HECKTN]
- -CHECKTN specifies that JOURNAL -FORWARD must ensure that the
- first database update in the journal file has the next
- transaction number after the current transaction in the database
- file.
+ o Periodically - to ensure ongoing integrity of the database(s); regular
+ INTEGs help detect any integrity problems before they spread and
+ extensively damage the database file.
+ o After a crash - to ensure the database was not corrupted. (Note: When
+ using before-image journaling, when the database is recovered from the
+ journal file after a crash, an integ is not required).
+ o When database errors are reported - to troubleshoot the problem.
- -NOCHECKTN suppresses checking of the starting journal
- transaction against the ending database transaction number.
-
- -CHECKTN is incompatible with the -BACKWARD qualifier.
-
- By default, JOURNAL -FORWARD uses -CHECKTN.
-
-2 Selection_qualifiers
- Selection Qualifiers
-
--GLOBAL
- -G[LOBAL]=global-list
- Specifies globals for JOURNAL to include or exclude from
- processing. You may find this qualifier useful for extracting
- and analyzing specific data.
-
- The global-list contains names of one or more global-names (not
- including subscripts) preceded by "^" enclosed in parentheses ()
- and separated by commas (,). If -GLOBAL specifies only one item,
- the parentheses are optional. The names may include the
- wildcards ? and *. The entire list or each name may optionally
- be preceded by a minus (-), requiring JOURNAL to exclude
- database updates that update the specified global(s). When the
- global-list with a JOURNAL -GLOBAL does not start with a minus,
- JOURNAL processes only the explicitly named globals.
-
- By default, JOURNAL processes all globals.
-
--USER
- -U[SER]=user-list
- Specifies that JOURNAL processing include or exclude database
- updates generated by one or more users. You may use this
- qualifier to "back-out" database updates erroneously entered by
- a specific user.
-
- The user-list contains names of one or more users enclosed in
- parentheses () and separated by commas (,). If -USER specifies
- only one item, the parentheses are optional. The names may
- include the wildcards ? and *. The entire list or each name may
- optionally be preceded by a minus (-), requiring JOURNAL to
- exclude database updates initiated by the specified user(s).
- When the user-list with a JOURNAL -USER does not start with a
- minus, JOURNAL processes only database updates generated by the
- explicitly named users.
-
- By default, JOURNAL processes database updates regardless of the
- user by which they were initiated.
-
--ID
- -ID=pid-list
- Specifies that JOURNAL processing include or exclude database
- updates generated by one or more processes, identified by
- process identification numbers (PIDs) in hexadecimal. You may
- use this qualifier for troubleshooting or analysis of data.
-
- The pid-list contains one or more PIDs enclosed in parentheses
- () and separated by commas (,). If -ID specifies only one item,
- the parentheses are optional. The entire list or each PID may
- optionally be preceded by a minus (-), requiring JOURNAL to
- exclude database updates associated with the specified PID(s).
- When the pid-list with a JOURNAL -ID does not start with a
- minus, JOURNAL processes only database updates associated with
- the explicitly listed PIDs.
-
- By default, JOURNAL processes database updates regardless of the
- process by which they were initiated.
-
--PROCESS
- -P[ROCESS]=process-name-list
- Specifies that JOURNAL processing include or exclude database
- updates generated by one or more processes, identified by names.
- You may use this qualifier to extract specific process-related
- data for testing or troubleshooting.
-
- The process-name-list contains names of one or more processes
- enclosed in parentheses () and separated by commas (,). If
- -PROCESS specifies only one item, the parentheses are optional.
- The names may include the wildcards ? and *. The entire list or
- each process-name may optionally be preceded by a minus (-)
- requiring JOURNAL to exclude database updates associated with
- the specified process name(s). When the process-name-list with a
- JOURNAL -PROCESS does not start with a minus, JOURNAL processes
- only database updates associated with the explicitly named
- processes.
+ Improving the logical and physical adjacency of global nodes may result in
+ faster disk I/O. A global node is logically adjacent when it is stored
+ within a span of contiguous serial block numbers. A global node is
+ physically adjacent when it resides on adjacent hard disk sectors in a way
+ that a single seek operation can access it. Database updates (SETs/KILLs)
+ over time affect the logical adjacency of global nodes. A MUPIP INTEG
+ reports the logical adjacency of your global nodes which may indicate
+ whether a MUPIP REORG could improve the database performance. A native
+ file system defragmentation improves physical adjacency.
+
+ **Note**
- By default, JOURNAL processes database updates regardless of the
- process by which they were initiated.
+ Most modern SAN and I/O devices often mask the performance impact of the
+ adjustments in logical and physical adjacency. If achieving a particular
+ performance benchmark is your goal, increasing the logical and physical
+ adjacency should be only one of many steps that you might undertake. While
+ designing the database, try to ensure that the logical adjacency is close
+ to the number of blocks that can physically reside on your hard disk's
+ cylinder. You can also choose two or three cylinders, with the assumption
+ that short seeks are fast.
--TRANSACTION
- -T[RANSACTION]=transaction-type
- Specifies transaction-types for JOURNAL to include or exclude
- from processing. For example, you may use this qualifier to
- exclude KILL transactions and prevent an accidental KILL from
- reoccurring during replay.
+ The format of the INTEG command is:
- The transaction-types are:
+ I[NTEG]
+ [
+ -A[DJACENCY]=integer
+ -BL[OCK]=hexa;block-number
+ -BR[IEF]
+ -FA[ST]
+ -FU[LL]
+ -[NO]K[EYRANGES]
+ -[NO]MAP[=integer]
+ -[NO]MAXK[EYSIZE][=integer]
+ -S[UBSCRIPT]=subscript]
+ -TN[_RESET]
+ -[NO]TR[ANSACTION][=integer]
+ -[NO]O[NLINE]
+ ]
+ {[-FILE] file-name|-REG[ION] region-name}
+
+ o MUPIP INTEG requires specification of either file(s) or region(s).
+ o Press <CTRL-C> to stop MUPIP INTEG before the process completes.
+ o The file-name identifies the database file for a MUPIP INTEG
+ operation.The region-list identifies one or more regions that, in
+ turn, identify database files through the current Global Directory.
+ o MUPIP INTEG operation keeps track of the number of blocks that do not
+ have the current block version during a non-fast integ (default or
+ full) and matches this value against the blocks to upgrade counter in
+ the file-header. It issues an error if the values are unmatched and
+ corrects the count in the file header if there are no other integrity
+ errors.
+
+ **Important**
+
+ Promptly analyze and fix all errors that MUPIP INTEG reports. Some errors
+ may be benign while others may be a signs of corruption or compromised
+ database integrity. If operations continue without fixes to serious
+ errors, the following problems may occur:
+
+ o Invalid application operation due to missing or incorrect data.
+ o Process errors, including inappropriate indefinite looping, when a
+ database access encounters an error.
+ o Degrading application level consistency as a result of incomplete
+ update sequences caused by the prior symptoms.
+
+ FIS strongly recommends fixing the following errors as soon as they are
+ discovered:
+
+ o Blocks incorrectly marked free - these may cause accelerating damage
+ when processes make updates to any part of the database region.
+ o Integrity errors in an index block - these may cause accelerating
+ damage when processes make updates to that area of the database region
+ using the faulty index.
+
+ MUPIP INTEG -FAST and the "regular" INTEG both report these errors (These
+ qualifiers are described later in this section). Other database errors do
+ not pose the threat of rapidly spreading problems in GDS files. After the
+ GT.M database repair, assess the type of damage, the risk of continued
+ operations, and the disruption in normal operation caused by the time
+ spent repairing the database. Contact your GT.M support channel for help
+ assessing INTEG errors.
+
+ The following sections describe the qualifiers of the INTEG command.
+
+3 ADjacency
+ ADjacency
- SET
+ Specifies the logical adjacency of data blocks that MUPIP INTEG should
+ assume while diagnosing the database. By default, MUPIP INTEG operates
+ with -ADJACENCY=10 and reports the logical adjacency in the "Adjacent"
+ column of the MUPIP INTEG report.
- KILL
+ o The complexity of contemporary disk controllers and the native file
+ system may render this report superfluous. But when it is meaningful,
+ this report measures the logical adjacency of data.
+ o A MUPIP REORG improves logical adjacency and a native file system
+ defragmentation improves physical adjacency.
- These types correspond to the MUMPS commands of the same names.
- The transaction-type may optionally be preceded by a minus (-)
- requiring JOURNAL to exclude transactions of the specified type.
- When the transaction-type with a JOURNAL -TRANSACTION does not
- start with a minus, JOURNAL processes only transactions of the
- explicitly named type.
+ The format of the ADJACENCY qualifier is:
- By default, JOURNAL processes transactions regardless of type.
+ -AD[JACENCY]=integer
-2 Examples
- Journal Examples
+3 BLock
+ BLock
- Example
+ Specifies the block for MUPIP INTEG command to start checking a sub-tree
+ of the database. MUPIP INTEG -BLOCK cannot detect "incorrectly marked busy
+ errors"
- $ cp /dat/cus.cat
- $ mupip journal -recover -forward -fences=none cus.mjl
-
- The cp command copies a backup copy of the database for use in
- recovery. The MUPIP JOURNAL command recovers the database using the
- cus.mjl journal file. The JOURNAL command processes the journal
- file in a forward direction (from the beginning of the journal).
- The -FENCES=NONE directs JOURNAL to ignore any fences and recover
- all individual updates.
+ The format of the BLOCK qualifier is:
- Example
+ -BL[OCK]=block-number
- $ mupip set -file -journal=(before,buff=128) cus.dat
- $ mupip set -file -journal=(before,buff=128) acc.dat
- ...
- $ mupip journal -recover -verify -back -error=2 cus.mjl,acc.mjl
-
- The first two command lines initiate journaling for the two
- specified database files. MUPIP JOURNAL does not accept wildcards
- in database file names. Because the MUPIP SET command specifies
- JOURNAL=BEFORE, subsequent JOURNAL -RECOVER may have either
- -FORWARD or -BACKWARD direction. The last line contains the command
- to recover the two database files using the two specified journal
- files. The journal recover processes in a BACKWARD direction using
- before-image processing. If JOURNAL processing encounters two or
- more errors (-ERROR=2), the recovery process terminates.
+ o Block numbers are displayed in an INTEG error report or by using DSE.
+ o Incompatible with: -SUBSCRIPT and -TN_RESET
- Example
+3 BRief
+ BRief
- $ mupip journal -forw -befo="-- 10:30" -glob="^bv%r*" -extr=bv
- cus.mjl
-
- This command line extracts database updates that occurred from the
- beginning of the journal until 10:30 to global variables with the
- prefix ^bv , followed by some character, followed by r, optionally
- followed by more characters. The JOURNAL -EXTRACT places the
- updates in a file called bv.mjf
-
- Because the command does not specify an extension, JOURNAL assigns
- the default extension .mjf to the output file.
+ Displays a single summary report by database file of the total number of
+ directory, index and data blocks. The format of the BRIEF qualifier is:
- Example
+ -BR[IEF]
+
+ o By default, MUPIP INTEG uses the BRIEF qualifier.
+ o Incompatible with: -FULL
- $ mupip jour -rec -back -befo="-- 10:30" -since="-- 9:30"
- -lookback="time=0 00:05" cus.mjl
-
- This command line performs a -RECOVERY -BACKWARD of the database
- file that corresponds to the journal file cus.mjl. JOURNAL
- -RECOVER processes from the journal time 9:30 to journal time
- 10:30. If the JOURNAL finds open fenced transactions, it "looks
- back" an additional five minutes to resolve them. The -BEFORE= and
- -SINCE= qualifiers in this example use absolute time. Because the
- time specification omits the date, JOURNAL assumes today's date.
+3 FAst
+ FAst
-2 extract_formats
- JOURNAL -EXTRACT formats
- EXTRACT output records are constructed of fields or "pieces"
- delimited by back-slashes (\).
+ Checks only index blocks. FAST does not check data blocks.
- The first piece of an EXTRACT output record always contains the
- two-digit decimal transaction record type, e.g., 01 for a process
- initialization record.
+ The format of the FAST qualifier is:
- The second piece always contains the full date and time of
- operation, represented in $HOROLOG-format, with decimal seconds,
- e.g., 54271,44580.55.
+ -FA[ST]
- The third piece always contains the process id (PID) of the process
- that performed the operation, represented as a decimal number. The
- remainder of the record depends on the record type.
+ o -FAST produces results significantly faster than a full INTEG because
+ the majority of blocks in a typical database are data blocks.
+ o While INTEG -FAST is not a replacement for a full INTEG, it very
+ quickly detects those errors that must be repaired immediately to
+ prevent accelerated database damage.
+ o By default, INTEG checks all active index and data blocks in the
+ database.
+ o Incompatible with: -TN_RESET.
- The fields described as "database transaction number" contain a
- GT.M assigned number that is unique within the journal file.
+3 FIle
+ FIle
-3 proc_initialization
- Process Initialization Record
- A type 1 record indicates an image-initiated contact with the
- GT.M database region for the first time. The format for a
- process initialization record is:
+ Specifies the name of the database file for the MUPIP INTEG operation.
+ FILE requires exclusive (stand-alone) access to a database file and does
+ not require a Global Directory. The format of the FILE qualifier is:
- 01\time\pid\nnam\unam\term
-
- where
+ -FI[LE]
- time full time/date
+ o With stand-alone access to the file, MUPIP INTEG -FILE is able to
+ check whether the reference count is zero. A non-zero reference count
+ indicates prior abnormal termination of the database.
+ o The -FILE qualifier is incompatible with the -REGION qualifier.
+ o By default, INTEG operates on -FILE.
- pid process id
+3 FUll
+ FUll
- nnam node name
+ Displays an expanded report for a MUPIP INTEG operation. With -FULL
+ specified, MUPIP INTEG displays the number of index and data blocks in the
+ directory tree and in each global variable tree as well as the total
+ number of directory, index and data blocks. The format of the FULL
+ qualifier is:
- unam user name
+ -FU[LL]
- term terminal name
+ o The -FULL qualifier is incompatible with the -BRIEF qualifier.
+ o By default, INTEG reports are -BRIEF.
+ o Use -FULL to have INTEG report all global names in a region or list of
+ regions.
+3 Keyranges
+ Keyranges
-3 proc_termination
- Type 2 - Process Termination Record
- A type 2 record indicates an image terminated and dropped
- interest in the GT.M database region. The format for a process
- termination record is:
+ Specify whether the MUPIP INTEG report includes key ranges that identify
+ the data suspected of problems it detects. The format of the KEYRANGES
+ qualifier is:
- 02\time\pid\nnam\unam\term\tnum
+ -[NO]K[EYRANGES]
- where
+ By default, INTEG displays -KEYRANGES.
- time full time/date
+3 MAP
+ MAP
+
+ Specifies the maximum number of "incorrectly marked busy errors" that
+ MUPIP INTEG reports. The format of the MAP qualifier is:
+
+ -[NO]MAP[=max_imb_errors]
+
+ o <max_imb_errors> specifies the threshold limit for the number of
+ incorrectly marked busy errors.
+ o -NOMAP automatically sets a high threshold limit of 1000000 (1
+ million) incorrectly marked busy errors (-MAP=1000000).
+ o By default, INTEG reports a maximum of 10 map errors (-MAP=10).
+
+ **Note**
+
+ MUPIP INTEG reports "incorrectly marked free" errors as they require
+ prompt action. MAP does not restrict them.
+
+ An error in an index block prevents INTEG from processing potentially
+ large areas of the database. A single "primary" error may cause large
+ numbers of "secondary" incorrectly marked busy errors, which are actually
+ useful in identifying valid blocks that have no valid index pointer.
+ Because "real" or primary incorrectly marked busy errors only make "empty"
+ blocks unavailable to the system, they are low impact and do not require
+ immediate repair.
+
+ **Note**
+
+ After a database recovery with -RECOVER (for example, using -BEFORE_TIME)
+ or -ROLLBACK (for example, using -FETCHRESYNC), the database may contain
+ incorrectly marked busy errors. Although these errors are benign, they
+ consume available space. Schedule repairs on the next opportunity.
+
+3 MAXkeysize
+ MAXkeysize
+
+ Specifies the maximum number of "key size too large" errors that a MUPIP
+ INTEG operation reports. The format of the MAXKEYSIZE qualifier is:
+
+ -[NO]MAX[KEYSIZE][=integer]
+
+ o By default, INTEG reports a maximum of 10 key size errors (-
+ MAXKEYSIZE=10).
+ o -NOMAXKEYSIZE removes limits on key size reporting so that INTEG
+ reports all key size too large errors.
+ o -NOMAXKEYSIZE does not accept assignment of an argument.
+ o "Key size too large" errors normally occur only if a DSE CHANGE
+ -FILEHEADER -KEY_MAX_SIZE command reduces the maximum key size.
+
+3 Online
+ Online
+
+ Specifies that while a MUPIP INTEG operation is active, other processes
+ can update the database without affecting the result of the backup. Allows
+ checking database structural integrity to run concurrently with database
+ updates. The format of the ONLINE qualifier is:
+
+ -[NO]O[NLINE]
+
+ o -NOONLINE specifies that the database should be frozen during MUPIP
+ INTEG.
+ o By default, MUPIP INTEG is online except for databases containing V4
+ blocks for which the default is -NOONLINE. Note that databases
+ containing V4 blocks should exist only in databases that are in the
+ process of being migrated from V4 to V5; please complete your
+ migration to the V5 format before using MUPIP INTEG -ONLINE.
+ o Since MUPIP INTEG -ONLINE does not freeze database updates, it cannot
+ safely correct errors in the "blocks to upgrade" and "free blocks"
+ fields in the file header, while MUPIP INTEG -NOONLINE can correct
+ these fields.
+ o As it checks each database file, MUPIP INTEG -ONLINE creates a sparse
+ file of the same size as the database. As each GT.M process updates
+ the database, it places a copy of the old block in the sparse file
+ before updating the database. For any database blocks with a newer
+ transaction number than the start of the INTEG, MUPIP uses the copy in
+ the sparse file. Thus, analogous with MUPIP BACKUP -ONLINE, INTEG
+ reports on the state of the database as of when it starts, not as of
+ when it completes. Note: a command such as ls -l command shows sparse
+ files at their full size, but does not show actual disk usage. Use a
+ command such as du -sh to see actual disk usage.
+ o The environment variable GTM_BAKTMPDIR (unlike most GT.M environment
+ variables, this is upper case; it is the same directory used for MUPIP
+ BACKUP -ONLINE) can be used to indicate a directory where MUPIP should
+ place the snapshot files (used by MUPIP INTEG -ONLINE). If
+ GTM_BAKTMPDIR does not exist, MUPIP places the snapshot files in the
+ current directory at the time you issue the INTEG command. MUPIP and
+ GT.M processes automatically cleans up these temporary snapshot files
+ under a wider variety of conditions.
+ o Temporary directory security settings must allow write access by the
+ the MUPIP process and read access by all processes updating the
+ database. MUPIP creates the temporary file with the same access as the
+ database file so processes updating the database can write to the
+ temporary file. If the database is encrypted, the updating processes
+ write encrypted blocks to the snapshot file and the MUPIP INTEG
+ process must start with access to appropriate key information as it
+ does even -NOONLINE.
+ o MUPIP INTEG -NOONLINE [-FAST] {-REGION|-FILE} clears the KILLs in
+ progress and Abandoned Kills flags if the run includes the entire
+ database and there are no incorrectly marked busy blocks.
+ o Only one online integ can be active per database region. If an online
+ integ is already active, a subsequent one issues an error and
+ immediately terminates. If an online integ does not successfully
+ complete, GT.M cleans it up in one of the following ways:
+
+ o A subsequent online integ detects that an earlier one did not
+ successfully complete and releases the resources held by the
+ prior online integ before proceeding.
+ o If a MUPIP STOP was issued to the online integ process, the
+ process cleans up any resources it held. Note: since the process
+ was stopped the results of the integ may not be valid.
+ o subsequent MUPIP RUNDOWN ensures the release of resources held by
+ prior unsuccessful online integs for the specified regions.
+ o For every 64K transactions after the online integ initiation,
+ online integ checks GT.M health for improperly abandoned online
+ integs and releases resources held by any it finds.
+
+ o Incompatible with: -FILE, -TN_RESET (there should be no need to use
+ -TN_RESET on a GT.M V5 database).
+
+3 Region
+ Region
+
+ Specifies that the INTEG parameter identifies one or more regions rather
+ than a database file. The format of the REGION qualifier is:
+
+ -R[EGION]
+
+ o MUPIP INTEG -REGION does not require stand alone access to databases.
+ Instead, it freezes updates (but not reads) to the database during the
+ check. The region-list argument may specify more than one region of
+ the current Global Directory in a list separated with commas. INTEG
+ -REGION requires the environment variable gtmgbldir to specify a valid
+ Global Directory. For more information on defining gtmgbldir, refer to
+ the "Global Directory Editor" chapter.
+ o Because a KILL may briefly defer marking the blocks it releases "free"
+ in the bit maps, INTEG -REGION may report spurious block incorrectly
+ marked busy errors. These errors are benign. If these errors occur in
+ conjunction with a "Kill in progress" error, resolve the errors after
+ the "Kill in progress" error is no longer present.
+ o By default, INTEG operates -FILE.
+ o Incompatible with: -FILE, -TN_RESET
+
+3 Subscript
+ Subscript
+
+ Specifies a global or a range of keys to INTEG. The global key may be
+ enclosed in quotation marks (" "). Identify a range by separating two
+ subscripts with a colon (:). -SUBSCRIPT cannot detect incorrectly marked
+ busy errors. The format of the SUBSCRIPT qualifier is:
+
+ -S[UBSCRIPT]=subscript
+
+ Specify SUBSCRIPT only if the path to the keys in the subscript is not
+ damaged. If the path is questionable or known to be damaged, use DSE to
+ find the block(s) and INTEG -BLOCK.
+
+ Incompatible with: -BLOCK, -TN_RESET
+
+3 TN_reset
+ TN_reset
+
+ Resets block transaction numbers and backup event recorded transaction
+ numbers to (one) 1, and the current transaction number to two (2) which
+ makes the backup event recorded transaction numbers more meaningful and
+ useful. It also issues an advisory message to perform a backup.
+
+ The format of the TN_RESET qualifier is:
+
+ -TN[_RESET]
+
+ o Transaction numbers can go up to 18,446,744,073,709,551,615. This
+ means that a transaction processing application that runs flat out at
+ a non-stop rate of 1,000,000 updates per second would need a TN reset
+ approximately every 584,554 years.
+ o The -TN_RESET qualifier rewrites all blocks holding data. If the
+ transaction overflow resets to zero (0) database operation is
+ disrupted.
+ o The -TN_RESET qualifier is a protective mechanism that prevents the
+ transaction overflow from resetting to 0.
+ o By default, INTEG does not modify the block transaction numbers.
+
+ **Important**
+
+ There should never be a need for a -TN_RESET on a database with only
+ V5 blocks, even when cleaning up after a runaway process.
+
+ o The -TN_RESET qualifier is incompatible with the -FAST, -BLOCK,
+ -REGION, and -SUBSCRIPT qualifiers.
- pid process id
+ **Note**
- nnam node name
+ Any time a GT.M update opens a database file that was not properly closed,
+ GT.M increments the transaction number by 1000. This automatic increment
+ prevents problems induced by abnormal database closes, but users must
+ always consider this factor in their operational procedures. The rate at
+ which GT.M "uses up" transaction numbers is a function of operational
+ procedures and real database updates.
- unam user name
+3 TRansaction
+ TRansaction
- term terminal name
+ Specifies the maximum number of block transaction- number-too-large errors
+ that MUPIP INTEG reports. The format of the TRANSACTION qualifier is:
- tnum database transaction number
+ -[NO]TR[ANSACTION][=integer]
-3 end_of_file
- Type 3 - End of File Record
- A type 3 record indicates all GT.M images dropped interest in
- the region and the journal file was closed normally. The format
- for an end-of-file record is:
+ o -NOTRANSACTION removes limits on transaction reporting so MUPIP INTEG
+ reports all transaction number errors.
+ o -NOTRANSACTION does not accept assignment of an argument.
+ o A system crash may generate many "block transaction number too large"
+ errors. These errors can cause problems for BACKUP -INCREMENTAL and
+ for transaction processing. Normally, the automatic increment of 1000
+ blocks that GT.M adds when a database is reopened averts these errors.
+ If a problem still exists after the database is reopened, users can
+ use a value in the DSE CHANGE -FILEHEADER -CURRENT_TN= command to
+ quickly fix "block transaction number too large number" errors.
+ o By default, INTEG reports a maximum of 10 block transaction errors
+ (-TRANSACTION=10).
- 03\time\pid\nnam\unam\term\tnum
+3 Examples
+ Examples
- where
+ Example:
- time full time/date
+ $ mupip integ -block=4 mumps.dat
- pid process id
+ This command performs a MUPIP INTEG operation on the BLOCK 4 of mumps.dat.
- nnam node name
+ Example:
- unam user name
+ $ mupip integ -adjacency=20
- term terminal name
+ A sample output from the above command follows:
- tnum database transaction number
+ Type Blocks Records % Used Adjacent
-3 Kill
- Type 4 - Kill Record
- A type 4 record indicates a database update caused by a KILL
- command. The format for a KILL record is:
+ Directory 2 5 4.150 NA
+ Index 18 1151 77.018 1
+ Data 1137 94189 97.894 1030
+ Free 43 NA NA NA
+ Total 1200 95345 NA 1031
- 04\time\pid\tnum\node
-
- where
+ This example performs a MUPIP INTEG operation assuming that logically
+ related data occupies 20 data blocks in the current database. The sample
+ output shows that out of 1137 data blocks, 1030 data blocks are adjacent
+ to each other. One can improve the performance of a database if the all
+ blocks are as adjacent as possible.
- time full time/date
+ Example:
- pid process id
+ $ mupip integ -brief mumps.dat
- tnum database transaction number
+ This command performs a MUPIP INTEG operation on the database mumps.dat. A
+ sample output from the above command follows:
- node a MUMPS node reference in external format
+ No errors detected by integ.
-3 Set
- Type 5 - Set Record
- A type 5 record indicates a database update caused by a SET
- command. The format for a SET record is:
+ Type Blocks Records % Used Adjacent
- 05\time\pid\tnum\sarg
+ Directory 2 2 2.490 NA
+ Index 1 1 2.343 1
+ Data 1 3 6.738 1
+ Free 96 NA NA NA
+ Total 100 6 NA 2
- where
+ Example:
- time full time/date
+ $ mupip integ -fast mumps.dat
- pid process id
+ This command performs a MUPIP INTEG operation only on the index block of
+ the database file mumps.dat. A sample output from the above command
+ follows:
- tnum database transaction number
+ No errors detected by fast integ.
- sarg a MUMPS set argument
+ Type Blocks Records % Used Adjacent
- Note a MUMPS SET argument has a node reference followed by an
- equal-sign (=) and MUMPS data string expression.
+ Directory 2 2 2.490 NA
+ Index 1 1 2.343 1
+ Data 1 NA NA NA
+ Free 96 NA NA NA
+ Total 100 NA NA 1
-3 tr_start
- Type 6 - Transaction Start Record
- A type 6 record indicates a ZTSTART command. The format for a
- transaction start record is:
+ Note the NA entries (highlighted in bold) for Data type. It means that the
+ MUPIP INTEG -FAST operation checked only index blocks.
- 06\time\pid
+ $ mupip integ -full mumps.dat
- where
+ The sample output from the above command follows:
- time full time/date
+ Directory tree
+ Level Blocks Records % Used Adjacent
+ 1 1 1 2.343 NA
+ 0 1 1 2.636 NA
- pid process id
+ Global variable ^Dinosaur
+ Level Blocks Records % Used Adjacent
+ 1 1 6 8.398 1
+ 0 6 500 83.902 6
-3 tr_commit
- Type 7 - Transaction Commit Record
- A type 7 record indicates a ZTCOMMIT command. The format for a
- transaction commit record is:
+ No errors detected by integ.
- 07\time\pid\tnum\part
-
- where
+ Type Blocks Records % Used Adjacent
- time full time/date
+ Directory 2 2 2.490 NA
+ Index 1 6 8.398 1
+ Data 6 500 83.902 6
+ Free 91 NA NA NA
+ Total 100 508 NA 7
- pid process id
+ Example:
- tnum database transaction number
+ $ mupip integ -map=20 -maxkeysize=20 -transaction=2 mumps.dat
- part number of journal entries in the transaction
+ This command performs a MUPIP INTEG operation and restricts the maximum
+ number of "key size too large" errors to 20.
-1 Jrnl_examples
- Journaling Examples
- The following examples present a typical use of database journaling to
- prevent loss of data. In our examples the database consists of three
- regions, ACC, MAIN, and TMP, mapped respectively to files
- /usr/prod/acc.dat, /usr/prod/mumps.dat and /usr/prod/tmp.dat.
+ Example:
-2 Setting_Database_Regions_for_Journaling
- We assume that region TMP holds only process-local data, and,
- therefore, does not require backups or journaling. We assume, on the
- other hand, that regions ACC and MAIN hold production application data
- that should be protected by journaling. Moreover, our application
- requires a high degree of availability. Therefore, we set up
- journaling with BEFORE_IMAGES for regions ACC and MAIN. The
- BEFORE_IMAGES allow for JOURNAL RECOVER -BACKWARD, which generally
- works faster than JOURNAL RECOVER -FORWARD. Because both our journaled
- regions map to the database files on the usr device, we choose a
- different disk with a different controller to accommodate the journal
- files. This choice improves resiliency against hardware failures.
+ $ mupip integ -map=20 -transaction=2 mumps.dat
- Example
+ This command performs a MUPIP INTEG operation and restricts the maximum
+ number of "block transaction- number-too-large errors" to 2.
- $ mupip set -region -journal=(off,buff=200,file=/jnl/prod/acc) ACC
- $ mupip set -region -journal=(off,buff=200,file=/jnl/prod/main) MAIN
-
- These commands must be issued when the database files are available
- for exclusive (stand-alone) access. They establish several journal
- characteristics. The example increases the journal buffer size from
- the default of 128 pages to 200 pages.
+ $ mupip integ -file mumps.dat -tn_reset
-2 Journal_Maintenance
- First backup the database files. Copy and store your existing journal
- files, thencreate and initialize new journal files.
+ This command resets the transaction number to one in every database block.
- Example
+ Example:
- $ mupip backup ACC,MAIN /dev/rst8/051590
- $ mupip set -region -journal=(on,before) ACC,MAIN
-
- This sequence of commands backs up the database files to disk and
- initializes new journal files for each. MUPIP BACKUP can operate
- without exclusive access to the database files by freezing all
- updates. However, in order to ensure that the BACKUP captures an
- application state matching the beginning of the journal files, it
- should run stand-alone.
-
- Some applications with high rates of updates may create considerable
- amount of journaling data. To save the disk space, you may archive
- journal files to magnetic tapes until the next database backup. Before
- archiving a journal file, first create a new one.
+ $ mupip integ -subscript="^Parrots" mumps.dat
- Example
+ This example performs a MUPIP INTEG operation on the global variable
+ ^Parrots in the database file mumps.dat.
- $ mupip set -file -journal=(on,before) ACC.DAT
- $ cp /dev/rst8/jnl.bck acc.mjl ~{
- $ purge JNL:[PROD]ACC.MJL\
-
- This sequence creates a new journal file and backs up the old journal
- file to the tape. Notice that the MUPIP SET requires exclusive access
- to the database file to ensure that the old journal stops and the new
- journal starts with consistent transaction states.
+ Example:
-2 Recovery_from_Journal_Files
- Because we set up our databases with BEFORE_IMAGE journaling, when
- both the database and journal files are available after a failure
- event, we can use JOURNAL -RECOVER -BACKWARD.
+ $ mupip integ -subscript="^Amsterdam(100)":"^Bolivia(""Chimes"")" -region DEFAULT
- Example
+ This example performs a MUPIP INTEG operation all global variables greater
+ than or equal to ^Amsterdam (100) and less than or equal to
+ ^Bolivia("Chimes") in the default region(s).
- $ delete /usr/prod/tmp.dat
- $ mupip create -region=tmp
- $ mupip journal -reco -show -back -nointer
- /jnl/prod/acc./jnl/prod/main
- $ mupip integ -region *
-
- This first deletes and recreates tmp.dat. The MUPIP JOURNAL command
- includes the -SHOW qualifier to generate a report on the status of
- activity in the journal files. It also includes the -NOINTERACTIVE
- qualifier to prevent operator interaction when JOURNAL processing
- encounters an error. By default, this JOURNAL -RECOVER has an implicit
- -ERROR_LIMIT=0, which causes the first broken transaction to terminate
- processing. In addition to checking database integrity, the MUPIP
- INTEG -REGION acts as the first database access after the recovery
- and, if the old journal file terminates improperly, creates a new
- journal file. Unlike INTEG -REGION, the command MUPIP INTEG -FILE does
- not initialize a new journal file. However, if the old journal file
- has damage, any other access to the data base creates a new version.
- If MUPIP JOURNAL -RECOVER reports broken transactions during recovery,
- reenter the transactions.
-
- WARNING: The new journal file created by commands such as mupip integ
- -region will overwrite the existing journal file. To preserve the
- existing file, save it under a different name before executing any
- commands that will cause a new journal file to be created.
-
- If the databases were lost, for instance due to a disk drive failure,
- we would have to use JOURNAL -RECOVER -FORWARD after replacing the
- drive and retrieving backups of the databases. This recovery may take
- much longer than backward recovery, depending on the amount of data in
- the journal.
+ **Note**
- Example
+ To specify a literal in the command string, use two double quotation marks
+ for example, ^b(""c"").
- $ lprm /usr/prod/*.dat
- $ cp /usr/prod /usr/051590/acc.dat
- $ cp /usr/prod /usr/051190/mumps.dat
- $ mupip journal -reco -forw -err=5 /jnl/jnl/acc,/jnl/jnl/main
- $ mupip create -region=TMP
- $ mupip integ -region -fast *
-
- This sequence of commands recreates the databases to the point of the
- last backup. Then it recovers all updates from the journal files. The
- -ERROR_LIMIT= qualifier causes JOURNAL -RECOVER to attempt processing
- through up to five (5) errors. By default, when the JOURNAL -RECOVER
- executes in batch, processing terminates after five errors. However if
- the command executes interactively, after five errors, MUPIP JOURNAL
- prompts the the operator at the invoking terminal to choose between
- continuing or terminating. Also by default, the JOURNAL -RECOVER
- command implies a -VERIFY, causing a check of the journal prior to
- -RECOVER processing. The commands up to this point require exclusive
- (stand-alone) access to the database files. MUPIP INTEG -REGION
- verifies the integrity of the recovered database. If the journal was
- not properly closed, the INTEG -REGION also creates a new version of
- the journal file, overwriting the existing version. Because the
- databases are large, we use the -FAST qualifier on the INTEG. Because
- INTEG freezes all updates and we wish to ensure database integrity
- before going back into production, we continue to restrict access to
- the database until the INTEG completes. Once the database has been
- verified, we can resume work. One of the first items of business
- should be to reenter any broken transactions.
-
- Should the system crash again and something such as a hard disk
- failure prevent backward recovery, we must recover the database
- forward, twice. First, restore the database from backup, then recover
- to the point of the first crash, then finally, recover from that point
- to the point of the second crash.
+2 INTRPT
+ INTRPT
- Example
+ Sends an interrupt signal to the specified process. The signal used is
+ [POSIX] SIGUSR1. The format of the MUPIP INTRPT command is:
- $ delete *.DAT;*
- $ mupip restore acc.dat usr/051590/acc.bck
- $ cp /usr/prod /usr/051590/acc.dat
- $ cp /usr/prod /usr/051590/mumps.dat
- $ mupip journal -reco -veri -forw -err=5 /jnl/acc.mjl
- $ mupip journal -reco -veri -forw -err=5 /jnl/acc.mjl
- $ mupip create -region=TMP
- $ mupip integ -region -fast *
-
- This is similar to the previous example, however, this sequence
- recovers the database regions from two consecutive journal files.
-
-1 Jrnl_overview
- Journaling overview
- Journaling records an extra copy of information during database
- updates in order to provide resiliency against hardware and software
- failures. Journaling can reduce the "window of exposure" from some of
- the most common types of failure: power loss and media loss due to
- head-to-disk interference. Journals also provide a valuable tool in
- cases of software errors and operational miscues. A journal file has
- questionable value only in the case where the database and the journal
- share a common point of failure that affects the information in both,
- over a significant period of time. Therefore, using different disks
- and, when possible, different disk controllers for the journal and the
- database files improves the likelihood of the journal serving its
- intended purpose.
-
- The database management portion of a MUMPS implementation ensures that
- multiple concurrent updates and retrievals of the same information (or
- information "close together" in ordered sequence) are handled in a
- predictable and logical fashion. The database manager may have to
- change multiple records, usually indices, as a result of a single
- update. Therefore, interrupting a process performing such a
- "multi-point" update violates a design assumption of the MUMPS
- implementation and results in a malformed database. Access to a
- damaged area of the database does not produce the desired result.
- Instead, such an "integrity" problem causes symptoms including system
- hangs, misplaced updates, failure to find information that exists,
- finding information out of sequence, and run-time errors. If the bad
- records contain no valid information or redundant information, the
- simplest cures for integrity errors entail deleting incorrectly
- formatted records. However, sometimes crashes damage information of
- value and, in any case, database repair requires time and skill. GT.M
- journaling provides a means to recover or replace databases that have
- integrity problems. Use of journaling at this "global" level requires
- no MUMPS programming.
-
- MUPIP and its documentation uses the term transaction to mean database
- update. In journaling, the term transaction may refer to multiple
- related database updates.
-
-2 Forward_Recovery
- Forward Recovery
- Forward Recovery consists of restoring a backup copy of the
- database and applying the journal file to that database file. The
- journal file contains copies of each database update. Forward
- Recovery reads the entire journal file from beginning to end (in a
- "forward" direction) and updates the backup copy of the database.
- The optional MUPIP JOURNAL -BEFORE= qualifier specifies a journal
- ending time that stops journal processing before the physical end
- of the journal file. In general, Forward Recovery takes longer than
- Backward Recovery. However, if the current database is somehow
- destroyed, you must use Forward Recovery. Also, if a journal file
- was created NOBEFORE_IMAGE with a MUPIP SET, that journal only
- permits Forward Recovery.
-
- Example of Forward Recovery:
-
- MUPIP JOURNAL -RECOVER -FORWARD
-
-
- -BEFORE
- |
- --------------------------------V-----------X--------->time
- 10:30 10:32
- >>+++++++++++++++++++++++++++++>>++++++++++>>
-
-
- This shows a recovery after a system crash at 10:32, which
- processes the entire journal file forward. If we add -BEFORE="--
- 10:30" to the command, the recovery stops when processing
- encounters updates that originally occurred after 10:30.
-
-2 Backward_Recovery
- Backward Recovery
- Backward Recovery works by processing from the end of the journal
- file that contains information for the period just prior to the
- failure event, thereby minimizing recovery time. Backward Recovery
- uses "before-image" journaling. With "before-image" journaling,
- GT.M captures the database updates, as well as "snap-shots" of
- portions of the database immediately prior to the change caused by
- the update. In effect, MUPIP JOURNAL=BEFORE_IMAGE creates
- "mini-backups" preceding each database update. Backward Recovery
- uses the mini-backups to restore the database as far back in time
- as specified, then it goes forward in time replaying the database
- updates. Using Backward Recovery with the MUPIP JOURNAL qualifiers
- -BEFORE=, -SINCE=, and -LOOKBACK=, you can specify a block of time
- to recover. JOURNAL -RECOVER -BACKWARD only works if the production
- database is useable, and if the MUPIP SET command that created the
- journal file specified the BEFORE_IMAGE characteristic.
-
- Note: Before-images require more disk I/O and storage space.
-
- Example of Backward Recovery:
-
- MUPIP JOURNAL -RECOVER -BACKWARD -SINCE="-- 9:30"
-
-
- -LOOKBACK_LIMIT
- | -SINCE
- | | -BEFORE
- | | |
- ----------------V-------V-------V------X--------->time
- 9:30 10:30 10:32
- <*******<++++++++++++++<<
- ********++++++++>++++++>>
-
-
-
- This shows a recovery after a system crash at 10:32. The recovery
- "undoes" the database updates backward to 9:30 and then forward
- until the crash. If we add -BEFORE="-- 10:30" to the command, the
- recovery stops when forward processing encounters updates that
- originally occurred after 10:30. If the application includes
- ZTSTART and ZTCOMMIT commands to fence a group of transactions,
- backwards processing may continue back prior to 9:30 searching to
- resolve fenced transactions that were incomplete at 9:30. The
- -LOOKBACK_LIMIT= qualifier controls the maximum amount of
- additional backward processing.
-
-2 Fencing_Transactions
- Fencing Transactions
- Journaling without fences in MUMPS addresses the fact that a system
- crash can damage the database integrity. However, sound design
- frequently dictates modelling a single "real-world" event in
- updates to more than one global variable. Such real-world events
- are usually captured in a single data entry session and are
- referred to as logical transactions. Therefore, interrupting a
- process performing a "multi-node" logical transaction violates a
- design assumption of the application and results in logical
- inconsistencies in the database. Such logical inconsistencies
- produce symptoms including run-time errors, inappropriate branching
- and incorrect reports. Sometimes logical inconsistencies are
- referred to as application-level database integrity problems.
-
- Standard MUMPS does not yet include a method to identify the fact
- that a single logical transaction may be made up of multiple global
- updates. Therefore, a journal recovery that corrects database
- integrity problems may perform an update that is part of an
- incomplete sequence of updates intended as a single logical unit.
-
- GT.M provides the MUMPS commands ZTSTART to mark the beginning of a
- logical transaction and ZTCOMMIT to mark the end of a logical
- transaction. When ZTSTART and ZTCOMMIT fence a logical transaction,
- the journal recovery can refrain from starting an incomplete
- update. To take advantage of this additional level of journaling
- functionality, the application must use ZTSTART and ZTCOMMIT
- commands.
-
- Journaling does not require modification of application programs.
- However, using ZTSTART and ZTCOMMIT to add transaction fences
- around updates that comprise a logical unit significantly improves
- the benefit of journaling. For instance, the logical transaction
- "transfer funds between accounts" consists of a debit update to one
- account and a credit update to another account. One of the updates
- made without the other is not valid. When recovering from journal
- files, JOURNAL processing recovers either all updates within the
- transaction fences or none of them. MUPIP JOURNAL -RECOVER reports
- the latter case during recovery.
-
-1 LOAD
- L[OAD]
- LOAD enters global variable names and their corresponding data values
- into a GT.M database from a sequential file. LOAD uses the Global
- Directory to determine which database files to use. LOAD may operate
- concurrently with normal GT.M database access. However, a LOAD does
- not use MUMPS LOCKs and therefore may produce application-level
- integrity problems if run concurrently with many applications.
+ INTRPT process-id
- The format of the LOAD command is:
+ **Important**
- L[OAD] [qualifier...] file-specification
+ Ensure that signal SIGUSR1 is not be used by any C external function calls
+ or any (initially non-GT.M) processes that use call-in support, as it is
+ interpreted by GT.M as a signal to trigger the $ZINTERRUPT mechanism.
- LOAD takes its input from the file defined by the file-specification.
+ o To INTRPT a process belonging to its own account, a process requires
+ no UNIX privilege.
+ o To INTRPT a process belonging to its own GROUP, a process requires
+ UNIX membership in the user group of the target process privilege. To
+ INTRPT a process belonging to an account outside its own GROUP, a
+ process requires UNIX superuser privilege.
- <CTRL C> produces a status message from LOAD. Entering <CTRL C> twice
- in quick succession aborts LOAD. A LOAD terminated abnormally by
- operator action or error is incomplete but does not adversely affect
- the database structure.
+2 LOAD
+ LOAD
-2 -FORMAT
- -FO[RMAT]=keyword
- Specifies the format of the input file. The format must match the
- actual format of the input file for LOAD to operate.
+ Puts the global variable names and their corresponding data values into a
+ GT.M database from a sequential file.
- At present, the only available format code is:
+ 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]]}
+ -S[TDIN]
+ ]
+ file-name
+
+ **Caution**
+
+ From an application perspective, performing a MUPIP LOAD operation while
+ 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
+ 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
+ such files.
+ o 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
+ %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
+ <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
+ database structure unless terminated with a kill -9.
+
+ **Note**
+
+ The MUPIP EXTRACT or MUPIP LOAD procedure for large databases are time
+ consuming due to the volume of data that has to be converted from binary
+ to ZWR format (on source) and vice versa (on target). One must also
+ consider the fact that the extract file can be very large for a large
+ database. Users must ensure adequate storage support the size of the
+ extract file and the space occupied by the source and target databases. In
+ order to reduce the total time and space it takes to transfer database
+ content from one endian platform to another, it is efficient to convert
+ the endian format in-place for a database and transfer the converted
+ database. See MUPIP ENDIANCVT for more information on converting the
+ endian format of a database file.
+
+ The following sections describe the optional qualifiers of the MUPIP LOAD
+ command.
+
+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.
+
+ The format codes are:
GO - Global Output format
+ B[INARY] - Binary format
+ Z[WR] - ZWRITE format
-3 GO
- -FORMAT=GO
- -FORMAT=GO stores the data in record pairs. Each global node produces
- one record for the key
- and one for the data. -FORMAT=GO has two header records, therefore
- LOAD -FORMAT=GO
- starts active work with record number three (3).
+ o By default, LOAD uses FORMAT=ZWR.
+ o -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)
+ 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).
-2 -BEGIN
- -BE[GIN]=integer
- Specifies the record number of the input file with which LOAD should
- begin. Directing LOAD to begin
- at a point other than the beginning of a valid key causes an error.
+3 BEgin
+ BEgin
- It is important to consider the number of header records when choosing a
- -BEGIN point. For more
- information, refer to the section on -FORMAT.
+ Specifies the record number of the input file with which LOAD should
+ begin. Directing LOAD to begin at a point other than the beginning of a
+ valid key causes an error. The format of the BEGIN qualifier is:
- For -FORMAT=GO input, normally the value should be an odd number.
+ -BE[GIN]=integer
- By default, LOAD starts at the beginning of the input file.
+ **Important**
+
+ 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
+ -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
+ 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.
+
+3 End
+ End
-2 -END
- -E[ND]=integer
Specifies the record number of the input file at which LOAD should stop.
- The -END=integer must be
- greater than the -BEGIN=integer for LOAD to operate. LOAD terminates
- after processing the record of
- the number specified by -END or reaching the end of the input file.
+ -END=integer must be greater than the -BEGIN=integer for LOAD to operate.
+ LOAD terminates after processing the record of the number specified by
+ -END or reaching the end of the input file. The format of the END
+ qualifier is:
+
+ -E[ND]=integer
- For -FORMAT=GO input, normally the value should be an even number.
+ The value of -FORMAT=GO input should normally be an even number. By
+ default, LOAD continues to the end of the input file.
- By default, LOAD continues to the end of the input file.
+3 FIll_factor
+ FIll_factor
-2 -FILL_FACTOR
- -FI[LL_FACTOR]=integer
- Specifies the target fill density for the data blocks updated in the
- database file. -FILL_FACTOR must be
- an integer between 5 and 100 specifying the percentage fill rate for the
- block.
+ Specifies the quantity of data stored in a database block. Subsequent
+ run-time updates to the block fill the remaining available space reserved
+ by the FILL_FACTOR. Blocks that avoid block splits operate more
+ efficiently. The format of the FILL_FACTOR qualifier is:
- In general, maximum data densities provide the best performance.
- However, if you have an
- understanding of the update patterns of your application, you may
- achieve a performance benefit over
- time from lowering the initial fill-factor.
+ -FI[LL_FACTOR]=integer
- By default, LOAD uses -FILL_FACTOR=100 for maximum data density.
+ o 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
+ 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.
-1 Overview
- MUPIP overview
- The GT.M MUMPS Peripheral Interchange Program, MUPIP, is a utility
- that provides an assortment of tools for GT.M database management and
- database journaling.
+ **Note**
- MUPIP provides the following commands:
+ FILL_FACTOR is useful when updates add or grow records reasonably
+ uniformly across a broad key range. If updates are at ever ascending or
+ descending keys, or if the record set and record sizes are relatively
+ static in the face of updates, FILL_FACTOR won't provide much benefit.
- For stand-alone database services:
+3 Stdin
+ Stdin
- o CREATE database files
+ Specifies that MUPIP LOAD takes input from standard input (stdin). The
+ format of the STDIN qualifier is:
- o EXTEND Mapped Memory database files
+ -S[TDIN]
- o JOURNAL, recover database files and extract journal records
+3 Examples
+ Examples
- o INTEG, check the integrity of GDS database files
+ Example:
- o RESTORE incremental backups to GDS database files
+ $ mupip load ex_file.go
- o SET database file characteristics
+ This command loads the content of the extract file ex_file.go to the
+ current database.
- For concurrent database services:
+ Example:
- o BACKUP GDS database files
+ $ mupip load -format=go big.glo
- o BACKUP-INCREMENTAL changes to GDS database files
+ This command loads an extract file big.glo in the current database.
- o EXTEND Buffered Global database files
+ Example:
- o EXTRACT data from GDS databases
+ $ mupip load -begin=5 -end=10 rs.glo
- o INTEG, check the integrity of GDS databases
+ This command begins MUPIP LOAD operation from record number 5 and ends at
+ record number 10. Note that the value for BEGIN is an odd number. A sample
+ output from the above command follows:
- o LOAD databases from sequential files
+ GT.M MUPIP EXTRACT
+ 02-MAR-2011 18:25:47 ZWR
+ Beginning LOAD at record number: 5
- o REORGanize database files to optimize performance
+ LOAD TOTAL Key Cnt: 6 Max Subsc Len: 7 Max Data Len: 1
+ Last LOAD record number: 10
- o RUNDOWN database files that are not currently accessed
+ Example:
- For non-database services:
+ $ mupip load -fill_factor=5 reobs.glo
- o HELP for MUPIP commands
+ This command set the FILL_FACTOR to 5 for loading an extract file in the
+ current database.
- o STOP GT.M processes
+ Example:
-1 REORG
- REO[RG]
- MUPIP REORG offers a tool for optimizing your database files for peak
- database performance. REORG
- requires minimal operator resources, and runs concurrently with other
- database activity, including updates.
- Competing activity generally increases the time to perform a REORG, as
- well as that of the competing
- operations. If you use REORG concurrently with normal database access, you
- may wish to lower the priority
- of the process performing the REORG to minimize its impact on normal
- operations.
+ $cat big.glo | mupip load -stdin
+ $mupip load -stdin < big.glo
- Note that while REORG optimizes the GDS structure of database files, it
- does not deal with native file system
- file fragmentation. Because native file fragmentation may significantly
- impair database performance, its
- prevention and control is still important. Always create files with
- appropriate allocations and extensions, on
- disks with large contiguous free-space. Use native utilities and,
- depending on your procedures, MUPIP
- utilities to eliminate file fragmentation when database files have been
- extended more than a dozen times.
+ These commands loads the extract file big.glo using -stdin.
+
+2 REORG
+ REORG
+
+ Improves database performance by defragmenting and reorganizing database
+ files and attempts to reduce the size of the database file. MUPIP REORG
+ runs concurrently with other database activity, including updates.
+ Competing activity generally increases the time required to perform a
+ REORG, as well as that of the competing operations.
The format of the REORG command is:
- REO[RG] [qualifier...] file-specification
+ REO[RG]
+ [
+ -D[OWNGRADE]
+ -E[XCLUDE]=global-name-list
+ -FI[LL_FACTOR]=integer
+ -I[NDEX_FILL_FACTOR]=integer
+ -R[ESUME]
+ -SAFEJNL
+ -S[ELECT]=global-name-list
+ -STA[RTBLK]=hexa
+ -STO[PBLK]=hexa
+ -T[RUNCATE][=percentage]
+ -UP[GRADE]
+ -US[ER_DEFINED_REORG]=reorg_list
+ -REG[ION]=region-list
+ ]
- <CTRL C> produces a status message from REORG. Entering <CTRL C> twice in
- quick succession
- aborts REORG. A REORG terminated abnormally by operator action or error is
- incomplete but does not
- adversely affect the database structure.
+ **Note**
-2 Qualifiers
+ While REORG optimizes the GDS structure of database files, it does not
+ handle native file system file fragmentation. In most cases, fragmentation
+ at the native file system level is more likely than fragmentation at the
+ GDS structure level. Therefore, FIS recommends users create files with
+ appropriate allocations and extensions, on disks with large amounts of
+ contiguous free space. Use native utilities and MUPIP utilities (depending
+ on operational procedures) to eliminate file fragmentation when database
+ files have been extended more than a dozen times.
--SELECT
- -SELECT=global-name-list
- Restricts REORG operation to a subset of specified globals. By
- default, REORG operates on all
- globals in all database files identified by the current global
- directory for the process executing the
- MUPIP command.
+ o Using REORG concurrently with normal database access affects the
+ performance of normal operation. To reduce this impact, lower the
+ priority of the process performing the REORG.
+ o MUPIP REORG does not change the logical contents of the database, and
+ can run on either the originating instance or replicating instance of
+ an LMS application. In such cases, resuming REORGs in process should
+ be part of the batch restart. See "GT.M Database Replication" chapter
+ for more information about running REORG on a dual site application.
+ o If you run MUPIP STOP for an ongoing MUPIP REORG process, it may leave
+ the database blocks in an inconsistent state. In this situation, GT.M
+ converts the ongoing KILLs flag to abandoned KILLs flag. If a
+ subsequent MUPIP REORG encounters these abandoned KILLs flags, it
+ gives a message and then starts its REORG actions.
+ o <CTRL-C> terminates REORG. A REORG terminated abnormally by operator
+ action or error is incomplete but does not adversely affect the
+ database structure, unless terminated with a kill -9.
- Arguments to this qualifier may be an individual global name, a prefix
- followed by an asterisk (*)
- wild-card symbol, or a list of names and/or prefixes followed by the
- wild-card symbol. The "^" in
- the specification of the global name is optional. Enclose lowercase
- global names in quotes ("").
+ Assume two scenarios of putting values of ^x(1) to ^x(10000). In the first
+ scenarios, fill values in a sequential manner. In the second scenario,
+ enter values for odd subscripts and then enter values for the even
+ subscripts.
- The global-specification can be:
+ Scenario 1:
+
+ At the GT.M prompt, execute the following command sequence:
+
+ GTM>for i=1:1:10000 set ^x(i)=$justify(i,200)
+
+ Then, execute the following MUPIP INTEG command.
+
+ $ mupip integ -region "*"
+
+ This command produces an output like the following:
- o A global name, such as MEF
-
- o A range of global names, such as A7:B6
-
- o A list, such as A,B,C
-
- o Global names with the same prefix, such as TMP*
-
- In the first case, EXTRACT selects only global ^MEF. In the second
- case, EXTRACT selects all
- global names between ^A7 and ^B6, inclusive. In the third case,
- EXTRACT selects globals ^A, ^B,
- and ^C. In the fourth case, EXTRACT selects all global names from ^TMP
- through ^TMPzzzzz.
-
--FILL_FACTOR
- -FILL_FACTOR=percent-qualifier
- Directs REORG to leave free space within blocks for future updates.
- Arguments to this qualifier
- must be integers from 5 to 100. REORG uses this figure in deciding
- whether to place more
- information in a block; currently REORG does not move information out
- of a block to make more
- room. By default, REORG attempts to fill blocks to their maximum
- capacity.
-
-1 RESTORE
- RE[STORE]
- RESTORE integrates one or more BACKUP -INCREMENTAL files into a
- corresponding database. For a
- RESTORE to work, the transaction numbers in the incremental file(s) must
- sequentially follow those in the
- database. Gaps or overlaps in the transaction numbers at RESTORE input
- file boundaries cause RESTORE to
- issue errors.
+ 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
+ Free 69 NA NA NA
+ Total 2600 12530 NA 2500
+
+ Note the high density (percent used) for index and data blocks from the
+ report.
+
+ Scenario 2:
+
+ 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:
+
+ $ mupip integ -region "*"
+
+ 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
+ Free 95 NA NA NA
+ Total 4000 13904 NA 1307
+
+ Note that there are more and less dense index and data blocks used than in
+ scenario 1. MUPIP REORG addresses such issues and makes the database
+ (depending on the FILL_FACTOR) more compact.
+
+ The optional qualifiers for MUPIP REORG are:
+
+3 Exclude
+ Exclude
+
+ Specifies that REORG not handle blocks that contain information about the
+ globals in the associated list-this means they are neither reorganized nor
+ swapped in the course of reorganizing other globals; -EXCLUDE can reduce
+ the efficiency of REORG because it complicates and interferes with the
+ block swapping actions that try to improve adjacency.
+
+ The format of the EXCLUDE qualifier is:
+
+ -E[XCLUDE]=global-name-list
+
+ o Assume that a single MUPIP command organizes a subset of the globals
+ in a database or region. If a second MUPIP REORG command selects the
+ remaining globals, it may tend to disrupt the results of the first
+ REORG by de-optimizing the previously organized blocks. This is
+ because there is no information passed from the previous MUPIP REORG
+ command to the next command. The EXCLUDE qualifier allows users to
+ list the name of the previously REORGed globals, so that the MUPIP
+ REORG bypasses the GDS blocks containing these globals.
+ o If global-name-list contains globals that do not exist, REORG issues a
+ message to the terminal and continues to process any specified globals
+ that exist. If REORG is unable to process any globals, it terminates
+ with an error.
+ o Global-name-list can be an individual global name, a range of global
+ names, or a list of names and prefixes followed by the wildcard
+ symbol. For example:
+
+ 1. A global name, such as ACN.
+ 2. A range of global names, such as A7:B7.
+ 3. A list, such as A,B,C.
+ 4. Global names with the same prefix such as TMP*.
+
+ In the first case, REORG only excludes global ^ACN. In the second case,
+ REORG excludes all global names in the collating sequence A7 to B7. For
+ the third case, REORG excludes A, B, and C. In the last case, REORG
+ excludes all globals prefixed with TMP.
+
+ o Enclose wildcards in double-quotes ("") to prevent inappropriate
+ expansion by the shell. The caret symbol (^) in the specification of
+ the global is optional.
+ o By default, REORG does not EXCLUDE any globals.
+ o In case any global appears in the argument lists of both -SELECT and
+ -EXCLUDE, REORG terminates with an error.
+
+3 Fill_factor
+ Fill_factor
+
+ Specifies how full you want each database block to be. This is a target
+ number. Individual blocks may be more or less full than the fill factor.
+ The format of the FILL_FACTOR qualifier is:
+
+ F[ILL_FACTOR]=integer
+
+ o The arguments for the FILL_FACTOR qualifier must be integers from 30
+ to 100. These integers represent the percentage of the data block that
+ REORG can fill. By default, the FILL_FACTOR value is 100 for maximum
+ data density.
+ o Users who come upon database performance issues or a high rate of
+ database updates must examine the defined FILL_FACTORs. Unless the
+ application uses entirely uniform records, which is not typical for
+ most applications, FILL_FACTORs do not work precisely.
+ o The FILL_FACTOR for data that is relatively static, or grows by the
+ addition of new nodes that collate before or after pre-existing nodes,
+ should be 100 percent. The FILL_FACTOR for data that is growing by
+ additions to existing nodes may be chosen to leave room in the typical
+ node for the forecast growth for some period. Generally, this is the
+ time between the LOAD and first REORG, or between two REORGs. This is
+ also true for additions of nodes that are internal to the existing
+ collating sequence.
+
+3 Index_fill_factor
+ Index_fill_factor
+
+ Directs REORG to leave free space within index blocks for future updates.
+ Arguments to this qualifier must be integers from 30 to 100 that represent
+ the percentage of the index block that REORG can fill. REORG uses this
+ number to decide whether to place more information in an index block, or
+ create space by moving data to another block. The format of the
+ INDEX_FILL_FACTOR qualifier is:
+
+ -I[NDEX_FILL_FACTOR]=integer
+
+ Under certain conditions, especially with large database block sizes, it
+ may be possible to achieve faster throughput by using a smaller fill
+ factor for index blocks than for data blocks. By default, the
+ INDEX_FILL_FACTOR is the value of FILL_FACTOR regardless of whether that
+ value is explicitly specified or implicitly obtained by default.
+
+3 Resume
+ Resume
+
+ For an interrupted REORG operation, -RESUME allows the user to resume the
+ REORG operation from the point where the operation stopped. REORG stores
+ the last key value in the database file header. The format of the RESUME
+ qualifier is:
+
+ -R[ESUME]
+
+ o With RESUME specified, the program retrieves the last key value, from
+ the database file header, and restarts operations from that key.
+
+3 Region
+ Region
+
+ Specifies that REORG operate in the regions in the associated list and
+ restricts REORG to the globals in those regions that are mapped by the
+ current global directory; it does not have the same interactions as
+ -EXCLUDE and -SELECT, but it does not mitigate those interactions when
+ combined with them.
+
+ The format of the REGION qualifier is:
+
+ -R[EGION]=region-list
+
+3 Select
+ Select
+
+ Specifies that REORG reorganizes only the globals in the associated list;
+ globals not on the list may be modified by block swaps with selected
+ globals unless they are named with -EXCLUDE; -SELECT can be difficult to
+ use efficiently because it tends to deoptimize unselected globals unless
+ they are name in an -EXCLUDE list (which introduces inefficiency).
+
+ The format of the SELECT qualifier is:
+
+ -S[ELECT]=global-name-list
+
+ o By default, REORG operates on all globals in all database files
+ identified by the current Global Directory for the process executing
+ the MUPIP command.
+ o One of the functions performed by REORG is to logically order the
+ globals on which it operates within the file. Unless the EXCLUDE and
+ SELECT qualifiers are properly used in tandem, repeating the command
+ with different selections in the same file wastes work and leaves only
+ the last selection well organized.
+ o If you enter the REORG -SELECT=global-name-list command and the
+ specified globals do not exist, REORG issues a message to the screen
+ and continues to process any specified globals that exist. If REORG is
+ unable to process any globals, it terminates with an error.
+ o Arguments for this qualifier may be an individual global name, a range
+ of global names, or a list of names and prefixes followed by the
+ wildcard symbol. The caret symbol (^) in the specification of the
+ global is optional.
+ o The global name can be:
+
+ 1. A global name, such as ACN
+ 2. A range of global names, such as A7:B7
+ 3. A list, such as A,B,C.
+ 4. Global names with the same prefix such as TMP*.
+
+ o In the first case, REORG only includes global ^ACN. In the second
+ case, REORG includes all global names in the collating sequence A7 to
+ B7. For the third case, REORG includes A, B, and C. In the last case,
+ REORG includes all globals prefixed with TMP.
+ o By default, REORG selects all globals.
+
+3 Truncate
+ Truncate
+
+ Specifies that REORG, after it has rearranged some or all of a region's
+ contents, should attempt to reduce the size of the database file and
+ return free space to the file system. The format of the TRUNCATE qualifier
+ is:
+
+ -T[RUNCATE][=percentage]
+
+ The optional percentage (0-99) provides a minimum amount for the
+ reclamation; in other words, REORG won't bother performing a file truncate
+ unless it can give back at least this percentage of the file; the default
+ (0) has it give back anything it can. TRUNCATE always returns space
+ aligned with bit map boundaries, which fall at 512 database block
+ intervals. TRUNCATE analyses the bit maps, and if appropriate, produces
+ before image journal records as needed for recycled (formerly used)
+ blocks; The journal extract of a truncated database file may contain INCTN
+ records having the inctn opcode value 9 indicating that the specific block
+ was marked from recycled to free by truncate.
+
+ **Note**
+
+ TRUNCATE does not complete if there is a concurrent online BACKUP or use
+ of the snapshot mechanism, for example by INTEG.
+
+3 Examples
+ Examples
+
+ Example:
+
+ $ mupip reorg -exclude="^b2a,^A4gsEQ2e:^A93"
+
+ This example performs a MUPIP REORG operation on all globals excluding
+ ^b2a and all globals ranging from ^A4gsEQ2e to ^A93.
+
+ Example:
+
+ If the forecasted growth of a global is 5% per month from relatively
+ uniformly distributed updates, and REORGs are scheduled every quarter, the
+ FILL_FACTOR for both the original LOAD and subsequent REORGs might be 80
+ percent 100 - ((3 months + 1 month "safety" margin) * five percent per
+ month). The REORG command based on the above assumptions is as follows:
+
+ $ mupip reorg -fill_factor=80
+
+2 RESTORE
+ RESTORE
+
+ Integrates one or more BACKUP -INCREMENTAL files into a corresponding
+ database. The transaction number in the first incremental backup must be
+ one more than the current transaction number of the database. Otherwise,
+ MUPIP RESTORE terminates with an error.
The format of the RESTORE command is:
- RE[STORE] [qualifier] file-spec file-list
-
- The file-specification identifies the name of the database file that
- RESTORE uses as a starting point. The
- transaction number in the database must match the starting transaction
- number of each successive input to the
- RESTORE. If the BACKUP -INCREMENTAL was created using -TRANSACTION=1, set
- the database up
- with MUPIP CREATE and do not access it with anything except the MUPIP
- commands INTEG, EXTEND,
- and SET before initiating the RESTORE.
-
- The file list specifies one or more files produced by BACKUP -INCREMENTAL
- to RESTORE into the
- database. The file-specifications are separated by commas (,) and must be
- in sequential order, from the oldest
- transaction number to the most recent. RESTORE may take its input from a
- UNIX file on any device that
- supports such files.
-
-2 Qualifiers
-
--EXTEND
- -[NO]EXTEND
- Specifies whether RESTORE should extend automatically if its target
- database file is smaller than
- the file size identified by the input BACKUP -INCREMENTAL file. MUMPS
- activity between
- backups may automatically extend a database file. Therefore, the
- database file specified as the
- starting point for a RESTORE may require an extension before the
- RESTORE. If the database needs
- an extension, MUPIP displays a message. The message gives the sizes of
- the input and output
- database files and the number of blocks by which to extend the
- database. If the RESTORE specifies
- more than one incremental backup with a file list, the database file
- may require more than one
- extension.
-
- By default, RESTORE automatically extends the database file.
-1 RUNDOWN
- RU[NDOWN]
- When database files have not been properly closed, RUNDOWN closes those
- currently inactive databases and
- releases the central memory they claim. In normal operation, the last
- process to close a database file performs
- the RUNDOWN actions.
+ RE[STORE] [-[NO]E[XTEND]] file-name file-list
+
+ o file-name identifies the name of the database file that RESTORE uses
+ as a starting point.
+ o file-list specifies one or more files produced by BACKUP -INCREMENTAL
+ to RESTORE into the database. The file-name are separated by commas
+ (,) and must be in sequential order, from the oldest transaction
+ number to the most recent transaction number. RESTORE may take its
+ input from a UNIX file on any device that supports such files.
+ o The current transaction number in the database must match the starting
+ transaction number of each successive input to the RESTORE.
+ o If the BACKUP -INCREMENTAL was created using -TRANSACTION=1, create a
+ new database with MUPIP CREATE and do not access it, except the
+ standalone MUPIP commands INTEG -FILE, EXTEND, and SET before
+ initiating the RESTORE.
+
+3 Extend
+ Extend
+
+ Specifies whether a MUPIP RESTORE operation should extend the database
+ file automatically if it is smaller than the size required to load the
+ data.
+
+ The format of the EXTEND qualifier is:
+
+ -[NO]E[XTEND]
+
+ M activity between backups may automatically extend a database file.
+ Therefore, the database file specified as the starting point for a RESTORE
+ may require an extension before the RESTORE. If the database needs an
+ extension and the command specifies -NOEXTEND, MUPIP displays a message
+ and terminates. The message provides the sizes of the input and output
+ database files and the number of blocks by which to extend the database.
+ If the RESTORE specifies more than one incremental backup with a file
+ list, the database file may require more than one extension.
+
+ By default, RESTORE automatically extends the database file.
+
+3 Examples
+ Examples
+
+ $ mupip restore backup.dat $backup_dir/backup.bk1, $backup_dir/backup.bk2, $backup_dir/backup.bk3
+
+ This command restores backup.dat from incremental backups stored in
+ directory specified by the environment variable backup_dir.
+
+ $ mupip restore gtm.dat '"gzip -d -c online5pipe.inc.gz |"'
+
+ This command uses a pipe to restore gtm.dat since its last DATABASE backup
+ from the bytestream backup stored in online5pipe.inc.gz.
+
+2 RUNDOWN
+ RUNDOWN
+
+ When database access has not been properly terminated, RUNDOWN properly
+ closes currently inactive databases, removes abandoned GT.M database
+ semaphores, and releases any IPC resources used. Under normal operations,
+ the last process to close a database file performs the RUNDOWN actions,
+ and a MUPIP RUNDOWN is not required. If a database file is already
+ properly rundown, a MUPIP RUNDOWN has no effect. If in doubt, it is always
+ to safe to perform a rundown. FIS recommends the following method to
+ shutdown a GT.M application or the system:
+
+ o Terminate all GT.M processes, and
+ o Rundown any and all database files that may be active.
+
+ MUPIP RUNDOWN checks for version mismatch. If there is a mismatch, it
+ skips the region and continues with the next region. This makes it easier
+ for multiple (non-interacting) GT.M versions to co-exist on the same
+ machine. Note that GT.M does not support concurrent access to the same
+ database file by multiple versions of the software.
The format of the RUNDOWN command is:
- RU[NDOWN] [-qualifier file-spec or region-list]
-
- The filename or region-list identifies the target of the RUNDOWN. If
- RUNDOWN has no parameter, it
- ignores any qualifier and flushes the memory associated with all database
- files that currently have associated
- memory and no active users.
-
- Use RUNDOWN after a system crash or after the last process accessing a
- database terminates abnormally.
- RUNDOWN ensures that an inactive database is properly closed and ready for
- subsequent use. RUNDOWN
- has no effect on any database that is actively being accessed at the time
- the RUNDOWN is issued.
-
- A RUNDOWN that specifies a target file or region can correct file state
- problems which a RUNDOWN with
- no parameters does not find.
-
-2 Qualifiers
--FILE
- -F[ILE]
- Specifies that the argument is a filename for a single database file.
- The -FILE qualifier is
- incompatible with the -REGION qualifier. If the rundown parameter
- consists of a list of files, the
- command only operates on the first item in the list.
-
--REGION
- -R[EGION]
- Specifies that the argument contains one or more region-names which
- identify database files mapped
- by the current Global Directory. The -REGION qualifier is incompatible
- with the -FILE qualifier.
-
-2 SEt
- SET modifies certain database characteristics. SET requires exclusive
- (stand-alone) access to the
- database file. SET operates on either regions or files.
+ RU[NDOWN] {-FILE file-name|-REGION region-list]}
+
+ MUPIP RUNDOWN clears certain fields in a file that is already closed. This
+ facilitates recovery from a system crash or other operational anomaly.
+
+ Use RUNDOWN after a system crash or after the last process accessing a
+ database terminates abnormally. RUNDOWN ensures that open databases are
+ properly closed and ready for subsequent use. RUNDOWN has no effect on any
+ database that is actively being accessed at the time the RUNDOWN is
+ issued.
+
+ To ensure database integrity, all system shutdown algorithms should
+ include scripts that stop at GT.M processes and perform RUNDOWN on all
+ database files.
+
+ The RUNDOWN command may include one of the following qualifiers:
+
+ -F[ile]
+ -R[egion]
+
+ 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
+ associated with a GT.M database, attempts to rundown that file.
+
+3 File
+ File
+
+ Specifies that the argument is a file-name for a single database file. The
+ -FILE qualifier is incompatible with the REGION qualifier. If the rundown
+ parameter consists of a list of files, the command only operates on the
+ first item in the list.
+
+ Incompatible with: -REGION
+
+3 Region
+ Region
+
+ Specifies that the argument contains one or more region-names that
+ identify database files mapped by the current Global Directory. Use the
+ wild card "*" to rundown all inactive regions in a global directory.
+
+ Incompatible with: -FILE
+
+ When MUPIP RUNDOWN has no qualifier, it performs rundown on all inactive
+ database memory sections on the node. Because this form has no explicit
+ list of databases, it does not perform any clean up on regions that have
+ no abandoned memory segments but may not have been shutdown in a crash.
+
+2 SET
+ SET
+
+ Modifies certain database characteristics. MUPIP SET operates on either
+ regions or files.
+
+ **Note**
+
+ In regions that have journaling enabled and on, users can switch journal
+ files without either requiring standalone access or freezing updates.
The format of the SET command is:
- SE[T] -qualifier... filename or region-list
+ SE[T] {-FI[LE] file-name|-REG[ION] region-list}
+ -A[CCESS_METHOD]={BG|MM}
+ -B[YPASS]
+ -DE[FER_TIME]=seconds
+ -E[XTENSION_COUNT]=integer(no of blocks)
+ -F[LUSH_TIME]=integer
+ -G[LOBAL_BUFFERS]=<integer>
+ -JN[LFILE]
+ -JO[URNAL]=journal-option-list
+ -L[OCK_SPACE]=integer
+ -[NO]INST[_FREEZE_ON_ERROR]
+ -PA[RTIAL_RECOV_BYPASS]
+ -REP[LICATION]={ON|OFF}
+ -RES[ERVED_BYTES]=integer]
+ -S[TANDALONENOT]
+ -V[ERSION]={V4|V6}
+ -W[AIT_DISK]=integer
- The filename or region-list identifies the target of the SET.
+ o The file-name (or region-list) identifies the target of the SET.
+ o The SET command must include one of the following qualifiers which
+ determine whether the argument to the SET is a file-name or a
+ region-list.
+ o Exclusive access to the database is required if the MUPIP SET command
+ specifies -ACCESS_METHOD, -GLOBAL_BUFFERS, -LOCK_SPACE or -NOJOURNAL,
+ or if any of the -JOURNAL options ENABLE, DISABLE, or BUFFER_SIZE are
+ specified.
- The SET command must include one of the following qualifiers:
+ The following section describe the qualifiers of the MUPIP SET command.
- o -FILE
+3 Access_method
+ Access_method
- o -REGION
+ Specifies the access method (GT.M buffering strategy) for storing and
+ retrieving data from the global database file. The format of the
+ ACCESS_METHOD qualifier is:
- The optional qualifiers are:
+ -A[CCESS_METHOD]=code
+
+3 PArtial_recov_bypass
+ PArtial_recov_bypass
+
+ Sets the CORRUPT_FILE flag in the database fileheader to FALSE. The
+ CORRUPT_FILE flag indicates whether a region completed a successful
+ recovery.
- o -G[LOBAL_BUFFERS]=integer
+3 File
+ File
- o -[NO]JOURNAL[=journal-option-list]
+ Specifies that the argument is a file-name for a single database file. The
+ format of the FILE qualifier is:
+ -F[ILE]
-2 Qualifiers
--FILE
- -F[ILE]
- Specifies that the argument is a filename for a single database file.
- The -FILE qualifier is
- incompatible with the -REGION qualifier.
+ Incompatible with: -REGION
+
+3 Region
+ Region
--REGION
- -R[EGION]
Specifies that the argument is a region-list which identifies database
- file(s) mapped by the current
- Global Directory. SET -REGION changes multiple files when the
- parameter contains a list and-or
- wildcards. The -REGION qualifier is incompatible with the -FILE
- qualifier.
-
- The following qualifiers determine the action(s) for the SET.
-
--GLOBAL_BUFFERS
- -G[LOBAL_BUFFERS]=integer
- Specifies the number of cache buffers for a BG database. For
- information on determining good
- working sizes for GLOBAL_BUFFERS, refer to the "Global Directory
- Editor" chapter of the GT.M
- Administration and Operations Guide.
-
- The minimum is 64 buffers and the maximum is 4096 buffers. By default,
- MUPIP CREATE
- establishes GLOBAL_BUFFERS using information entered in the Global
- Directory with GDE.
-
--JOURNAL
- -[NO]J[OURNAL][=journal-option-list]
- Specifies whether the database allows journaling and, if it does,
- characteristics for the journal file.
-
- -NOJOURNAL specifies the database does not allow journaling.
- -NOJOURNAL does not accept an
- argument assignment.
-
- -JOURNAL specifies journaling is allowed. -JOURNAL takes one or more
- arguments in a
- journal-option-list.
+ file(s) mapped by the current Global Directory. The format of the REGION
+ qualifier is:
- For a full description of the -JOURNAL qualifier and its keywords,
- refer the "GT.M Journaling"
- chapter in the GT.M Administration and Operations Guide.
-
-1 SET
- SE[T]
-
- MUPIP SET -JOURNAL determines whether a specified file or region(s)
- have journaling activated. SET requires sole access to the database.
- SET operates on either regions or files.
-
- The format for the SET command is:
-
- SE[T] -qualifier... file-spec or region-list
-
- The file-specification or region-list identifies the target of the
- SET. Region-names separated by commas (,) make up a region-list. For
- a summary table of MUPIP commands and qualifiers including MUPIP SET,
- refer to the MUPIP chapter in the GT.M Administration and Operations
- Guide.
-
-2 Object_qualifiers
- Object Qualifiers
-
--FILE
- -F[ILE]
- Specifies that the argument contains a file-specification for a
- single database file. The -FILE qualifier is incompatible with
- the -REGION qualifier.
-
--REGION
- -R[EGION]
- Specifies that the argument contains a region-name which,
- through the mapping of the current Global Directory, identifies
- a database file. SET -REGION modifies multiple files when the
- parameter contains more than one name. The -REGION qualifier is
- incompatible with the -FILE qualifier.
-
-2 Action_qualifiers
- Action Qualifiers
-
-/GLOBAL_BUFFERS
- /G[LOBAL_BUFFERS]=integer
- Specifies the number of cache buffers for a BG database. For
- information on determining good working sizes of GLOBAL_BUFFERS,
- refer to the "Global Directory Editor" chapter of the GT.M
- Administration and Operations Guide.
-
- The minimum is 64 buffers and the maximum is 4096 buffers. By
- default, MUPIP CREATE establishes GLOBAL_BUFFERS from
- information entered in the Global Directory with GDE.
-
--JOURNAL
- -[NO]J[OURNAL][=journal-option-list]
- Specifies whether the database allows journaling and, if it
- does, characteristics for the journal file.
-
- -NOJOURNAL specifies that the database does not allow
- journaling. -NOJOURNAL does not accept an argument assignment.
- -NOJOURNAL does not create new journal files. When a database
- has been SET -NOJOURNAL, it appears to have no journaling file
- name or other characteristics.
-
- -JOURNAL= enables journaling for a database file. -JOURNAL=
- takes one or more arguments in a journal-option-list. Except
- when used with the OFF option, SET -JOURNAL= always overwrites
- any existing versions of the specified journal file(s). The
- journal-option-list contains keywords separated with commas (,)
- enclosed in parentheses (). When the list contains only one
- keyword, the parentheses are optional.
-
- For details on the list refer to the journal-option-list topic.
-
-2 journal-option-list
- journal-option-list elements
-
- The following topics detail the journal-option-list elements.
+ -R[EGION]
-3 ON
- ON
- ON specifies that MUPIP create a new journal file and that GT.M
- record subsequent updates to the database in that journal file.
- A SET -JOURNAL=ON must include either BEFORE_IMAGE or
- NOBEFORE_IMAGE in the accompanying journal-option-list. When a
- database has been SET -JOURNAL=ON, GT.M journals updates to that
- file.
+ SET -REGION changes multiple files when the parameter contains a list
+ and/or wildcards.
- By default, SET -JOURNAL= turns journaling on.
-
-3 OFF
- OFF
- OFF specifies that GT.M not record subsequent updates to the
- database in the journal file. OFF may also be used to set up
- journaling characteristics without creating a journal file or
- starting journaling. When a database has been SET -JOURNAL=OFF,
- it has established journal characteristics ready to turn ON, but
- GT.M does not journal updates to that file.
-
- By default, SET -JOURNAL= turns journaling on.
-
-3 BEFORE_IMAGE
- [NO]BE[FORE_IMAGE]
- [NO]BEFORE_IMAGE controls whether the journal should capture
- before-images of information that an update is about to modify.
- MM databases must use NOBEFORE_IMAGE journaling. A SET
- -JOURNAL=ON must include either BEFORE_IMAGE or NOBEFORE_IMAGE
- in the accompanying journal-option-list.
-
- A BEFORE_IMAGE journal permits the possibility of performing
- "roll-back" recovery (i.e., Backward Recovery) of the associated
- database. BEFORE_IMAGE increases the load on I/O and CPU
- resources and therefore may affect performance.
-
-3 FILE_NAME
- F[ILE_NAME]=file-specification
- FILE_NAME=file-specification specifies the name of the journal
- file. FILE_NAME is incompatible with SET -REGION.
-
- Journal file-specifications are limited to 55 characters.
-
- By default, MUPIP CREATE establishes the journal
- file-specification from the Global Directory. If the Global
- Directory does not contain a journal file-specification SET
- -JOURNAL derives the journal file-specification from the
- database file-specification using a file type of .MJL. Note that
- because the default usually places the journal file on the same
- disk drive as the database file, it does not protect well
- against disk hardware failures.
-
-3 ALLOCATION
- A[LLOCATION]=blocks
- ALLOCATION=blocks specifies the initial size of the journal file
- in blocks. Because frequent journal file extensions degrade
- run-time performance, make journal file allocation ample for a
- production database.
-
- The minimum ALLOCATION is 10 blocks and the maximum is
- 16,777,216 blocks.
-
- If journaling characteristics have not been previously
- established by GDE or a prior SET -FILE -JOURNAL and a SET
- -JOURNAL= specifies ALLOCATION but does not specify EXTENSION,
- the command automatically changes EXTENSION to equal 10% of the
- new ALLOCATION.
-
- By default, MUPIP CREATE establishes the ALLOCATION from the
- Global Directory, where the Greystone supplied default is 100
- blocks. If the Global Directory does not contain ALLOCATION
- information, SET -JOURNAL uses a default of 100 blocks.
-
-3 EXTENSION=blocks
- E[XTENSION]=blocks
- EXTENSION=blocks specifies the size by which a journal file
- extends when it becomes full. EXTENSION=0 disables automatic
- journal file extension. While this technique exerts firm control
- over disk space consumption by a journal file, running out of
- journal file space terminates journaling for the region. Because
- frequent journal file extensions degrade run-time performance,
- make the journal file extension ample for a production database.
-
- The minimum EXTENSION is 0 blocks and the maximum is 65,536
- blocks.
-
- If journaling characteristics have not been previously
- established by GDE or a prior SET -FILE -JOURNAL and a SET
- -JOURNAL= specifies ALLOCATION but does not specify EXTENSION,
- the command automatically changes EXTENSION to equal 10% of the
- new ALLOCATION.
-
- By default, MUPIP CREATE establishes the EXTENSION from the
- Global Directory, where the Greystone-supplied default is 100
- blocks. If the Global Directory does not contain EXTENSION
- information and the SET -JOURNAL does not specify either
- ALLOCATION or EXTENSION, MUPIP uses a default of 100 blocks.
-
-3 BUFFER_SIZE=pages
- BU[FFER_SIZE]=pages
- BUFFER_SIZE=pages specifies the amount of memory used to buffer
- journal file output.
-
- A larger BUFFER_SIZE usually smooths and improves run-time
- performance by allowing larger, less frequent writes. On the
- other hand, a larger BUFFER_SIZE requires more memory resources,
- which may be scarce. A larger BUFFER_SIZE provides more room for
- journal records in buffered memory and therefore increases the
- number of update records that may be lost in a system failure.
-
- The minimum BUFFER_SIZE is enough 512-byte pages to hold two GDS
- database blocks and the maximum is 2000 pages.
-
- By default, MUPIP CREATE establishes the BUFFER_SIZE from the
- Global Directory, where the Greystone-supplied default is 128
- pages. If the Global Directory does not contain BUFFER_SIZE
- information, SET -JOURNAL uses a default of 128 pages.
-
-2 Examples
- SET -JOURNAL Examples
+ Incompatible with: -FILE
- Example
+3 Extension_count
+ Extension_count
- $ mupip set -file -journal=(nobefore,buff=128) cus.dat
-
- This initiates journaling for the database file cus.dat. Because
- the parameters include NOBEFORE, subsequent JOURNAL commands to
- -RECOVER the database updates in the journal must specify -FORWARD.
- The journal file created has the name cus.mjl.
+ Specifies the number of GDS blocks by which an existing database file
+ extends. A file or region name is required. This qualifier requires
+ standalone access.
- Example
+ The format of the EXTENSION_COUNT qualifier is:
- mupip set -region -journal=(before,alloc=50000,ext=5000)
+ -E[XTENSION_COUNT]=integer
- This enables journaling with BEFORE_IMAGES on all regions of the
- current Global Directory and gives each journal an ALLOCATION of
- 50000 blocks and an EXTENSION of 5000 blocks. If the regions have
- significantly different levels of update, either set the ALLOCATION
- and EXTENSION in the Global Directory before the MUPIP CREATE(s)
- or use several MUPIP SET -FILE commands.
+3 Flush_time
+ Flush_time
- Example
+ Specifies the amount of time between deferred writes of stale cache
+ buffers. The default value is 1 second and the maximum value is 1 hour.
+ -FLUSH_TIME requires standalone access. The format of the FLUSH_TIME
+ qualifier is:
- mupip set -region -journal=before joel.dat
-
- This declares journaling active with before-images for all regions
- of the current Global Directory when they are next opened.
+ -F[LUSH_TIME]=[[[HOURS:]MINUTES:]SECONDS:]CENTISECONDS
- Example
+3 Global_buffers
+ Global_buffers
- mupip set -file -nojournal MUMPS.DAT
-
- This disables journaling on the database file MUMPS.DAT in the
- current default directory.
+ Specifies the number of cache buffers for a BG database. This qualifier
+ requires standalone access.The format of the GLOBAL_BUFFERS qualifier is:
-1 STOP
- ST[OP]
- STOP terminates a GT.M image. The image executes an orderly rundown of all
- databases in which it
- currently has an interest and then exits. A MUPIP STOP may also be used to
- stop non-GT.M images.
+ -G[LOBAL_BUFFERS]=integer
- The format of the STOP command is:
+ In general, increasing the number of global buffers improves performance
+ by smoothing the peaks of I/O load on the system. However, increasing the
+ number of global buffers also increases the memory requirements of the
+ system, and a larger number of global buffers can increase the probability
+ of the buffers getting swapped out. If global buffers are swapped out, any
+ performance gain from increasing the number of global buffers will be more
+ than offset by the performance impact of swapping global buffers. Most
+ applications use from 1,000 to 4,000 global buffers for database regions
+ that are heavily used. FIS does not recommend using fewer than 256 buffers
+ except under special circumstances.
+
+ The minimum is 64 buffers and the maximum is 65536 buffers. By default,
+ MUPIP CREATE establishes GLOBAL_BUFFERS using information entered in the
+ Global Directory.
+
+ On many UNIX systems, default kernel parameters may be inadequate for GT.M
+ global buffers, and may need to be adjusted by a system administrator.
+
+3 Lock_space
+ Lock_space
+
+ Specifies the number of pages allocated to the management of M locks
+ associated with the database. The size of a page is always 512 bytes.
+
+ The format of the LOCK_SPACE qualifier is:
+
+ -L[OCK]_SPACE=integer
+
+ o The maximum LOCK_SPACE is 65,536 pages.
+ o The minimum LOCK_SPACE is 10 pages.
+ o The default LOCK_SPACE is 40 pages.
+ o A file or region name is required to assign lock space.
+ o
+ o This qualifier requires standalone access.
+
+3 INST_freeze_on_error
+ INST_freeze_on_error
+
+ Enables or disables custom errors in a region to automatically cause an
+ Instance Freeze. This flag modifies the "Inst Freeze on Error" file header
+ flag.
+
+3 Journal
+ Journal
+
+ Specifies whether the database allows journaling and, if it does,
+ characteristics for the journal file. The format of the JOURNAL qualifier
+ is:
+
+ -[NO]J[OURNAL][=journal-option-list]
+
+ o -NOJOURNAL specifies that the database does not allow journaling. And
+ also it does not accept an argument assignment.
+ o -JOURNAL specifies journaling is allowed. It takes one or more
+ arguments in a journal-option-list.
+
+3 Qdbrundown
+ Qdbrundown
+
+ Quickens normal process shutdown where a large number of processes
+ accessing a database file are required to shutdown almost simultaneously,
+ for example, in benchmarking scenarios. When a terminating GT.M process
+ observes that a large number of processes are attached to a database file
+ and QDBRUNDOWN is enabled, it bypasses checking whether it is the last
+ process accessing the database. Such a check occurs in a critical section
+ and bypassing it also bypasses the usual RUNDOWN actions which accelerates
+ process shutdown removing a possible impediment to process startup. By
+ default, QDBRUNDOWN is disabled.
+
+ Note that with QDBRUNDOWN there is a possibility of race condition that
+ might leave the database fileheader and IPC resources in need of cleanup.
+ Although QDBRUNDOWN minimizes the probability of such a race condition, it
+ cannot eliminate it. When using QDBRUNDOWN, FIS recommends an explicit
+ MUPIP RUNDOWN of the database file after the last process exits, to ensure
+ the cleanup of database fileheader and IPC resources.
+
+3 REServed_bytes
+ REServed_bytes
+
+ Specifies the size to be reserved in each database block. RESERVED_BYTES
+ is generally used to reserve room for compatibility with other
+ implementations of M or to observe communications protocol restrictions.
+ The format of the RESERVED_BYTES qualifier is:
+
+ -RES[ERVED_BYTES]=size
+
+ o RESERVED_BYTES may also be used as a user-managed fill factor.
+ o The minimum RESERVED_BYTES is 0 bytes. The maximum RESERVED_BYTES is
+ the block size minus the size of the block header which is 7 or 8
+ depending on your platform. Realistic determinations of this amount
+ should leave room for at least one record of maximum size.
+
+3 Version
+ Version
+
+ Sets the block format version (Desired DB Format field in the file header)
+ for all subsequent new blocks. The format of the VERSION qualifier is:
+
+ -V[ERSION]={V4|V6}
+
+ o MUPIP UPGRADE and MUPIP REORG -UPGRADE set the Desired DB Format field
+ in the database file header to V6 while MUPIP REORG -DOWNGRADE sets it
+ to V4.
+ o To set the version to V4, the current transaction number (CTN) of the
+ database must be within the range of a 32-bit maximum.
+ o V6 block format is compatible with the V5 block format. The longer key
+ and longer records (spanning nodes) features of V6 format are
+ automatically disabled when used with GT.M V5.* versions.
+ o For more information on the upgrading or downgrading your database,
+ refer to the release notes document of your current GT.M version.
+
+3 Examples
+ Examples
+
+ Example:
+
+ $ mupip set -journal=on,nobefore -region "*"
+
+ This example enables NOBEFORE image journaling and turns on journaling for
+ all regions.
+
+ $ mupip set -version=V4 -file mumps.dat
+
+ Database file mumps.dat now has d esired DB format V4
+
+ This example sets the block format to V4 for all subsequent new blocks in
+ V6 database file mumps.dat.
+
+ 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
+ V4 database file mumps.dat.
+
+ Example:
+
+ mupip set -flush_time=01:00:00:00 -region DEFAULT
+
+ This example sets flush time to 1 hour. You can also specify flush time in
+ any combination of [[[HOURS:]MINUTES:]SECONDS:]CENTISECONDS. MUPIP
+ interprets -FLUSH_TIME=360000 or -FLUSH_TIME=00:60:00:00 as
+ -FLUSH_TIME=01:00:00:00.
+
+ Example:
+
+ $ mupip set -region REPTILES -inst_freeze_on_error
+
+ This example enables custom errors in region REPTILES to cause an Instance
+ Freeze.
+
+2 SIZE
+ SIZE
+
+ Estimates and reports the size of global variables using a format that is
+ similar to the one that appears at the end of the MUPIP INTEG -FULL
+ report. In comparison with MUPIP INTEG -FAST -FULL, MUPIP SIZE provides
+ the option of choosing any one of the three estimation techniques to
+ estimate the size of global variables in a database file. These techniques
+ vary in measurement speed and estimate accuracy. The format of the MUPIP
+ SIZE command is:
+
+ MUPIP SI[ZE] [-h[euristic]=estimation_technique] [-s[elect]=global-name-list] [-r[egion]=region-list]
+
+ The optional qualifiers of MUPIP SIZE are:
+
+ -Heuristic=estimation_technique
+
+ Specifies the estimation technique that MUPIP SIZE should use to estimate
+ the size of global variables. The format of the -HEURISTIC qualifier is:
+
+ -h[euristic]={sc[an][,level=<lvl>] | a[rsample][,samples=<smpls>] | i[mpsample][,samples=<smpls>]}
+
+ o smpls is the number of samples and must be greater than zero (0)
+ o lvl is a positive or negative tree level designation and -(level of
+ the root block) <= lvl <= (level of the root block)
+
+ estimation-technique is one of the following:
+
+ o scan,level=<lvl>
+
+ Traverses the global variable tree and counts the actual number of
+ records and blocks at levels from the root down to the level specified
+ by lvl (default is 0, the data blocks). If the given level is
+ non-negative, it is the lowest block level of the global for which the
+ count is requested. So, 0 means all blocks, 1 means all index blocks,
+ 2 means all index blocks of level 2 and above, and so on. SCAN counts
+ a negative level from the root of the global tree where -1 means
+ children of the root.
+
+ o arsample,samples=<smpls>
+
+ Uses acceptance/rejection sampling of random tree traversals to
+ estimate the number of blocks at each level. It continues until the
+ specified number of samples (default is 1,000) is accepted.
+
+ o impsample,samples=<smpls>
+
+ Uses importance sampling of random tree traversals to weight each
+ sample of the specified number of samples (default is 1,000) in order
+ to estimate size of the tree at each level.
+
+ o If -HEURISTIC is not specified, MUPIP SIZE uses the
+ ARSAMPLE,SAMPLE=1000 estimation technique.
+
+ **Important**
+
+ For large databases, MUPIP SIZE is faster than MUPIP INTEG -FAST -FULL.
+ IMPSAMPLE is expected to be the fastest estimation technique, followed by
+ ARSAMPLE and then SCAN.
+
+ In terms of accuracy, MUPIP INTEG -FAST -FULL is the most accurate.
+
+ -Select
+
+ Specifies the global variables on which MUPIP SIZE runs. If -SELECT is not
+ specified, MUPIP SIZE selects all global variables.
+
+ The format of the SELECT qualifier is:
+
+ -s[elect]=global-name-list
+
+ global-name-list can be:
+
+ o A comma separated list of global variables.
+ o A range of global variables denoted by start:end syntax. For example,
+ -select="g1:g4".
+ o A global variable with wildcards, for example, "g*" (the name must be
+ escaped to avoid shell filename expansion)
+ o "*" to select all global variables.
+
+ -Region
+
+ Specifies the region on which MUPIP SIZE runs. If REGION is not specified,
+ MUPIP SIZE selects all regions. The format of the REGION qualifier is:
+
+ -R[EGION]=region-list
+
+ Examples:
+
+ $ mupip size -heuristic="impsample,samples=2000" -select="y*" -region="AREG"
+
+ This example estimates the size of all global variable starting with "y".
+ It uses importance sampling with 2000 samples on the region AREG.
+
+ $ mupip size -heuristic="scan,level=-1"
+
+ This example counts the number of blocks and records at 1 level below the
+ root of the database tree.
+
+ $ mupip size -heuristic="arsample" -select="g1:g3"
+
+ This example estimates the size of global variables g1, g2 and g3 using
+ accept/reject sampling with the default number of samples regardless of
+ the region in which they reside.
+
+ **Note**
+
+ Apart from randomness caused by sampling heuristics, MUPIP SIZE also has
+ randomness from concurrent updates because it does not use the snapshot
+ technique that MUPIP INTEG uses.
+
+2 STOP
+ STOP
+
+ Terminates a GT.M image. The image executes an orderly disengagement from
+ all databases that are currently open by the process, and then exits. A
+ MUPIP STOP performs a kill -15 and therefore may also be used to stop
+ non-GT.M images.
+
+ The format of the STOP command is:
+
+ MUPIP ST[OP] process-id
+
+ o Use the shell command ps to display a list of active process names and
+ process identifiers (PIDs).
+ o To STOP a process belonging to its own account, a process requires no
+ privileges. To STOP a process belonging to another account, MUPIP STOP
+ must execute as root.
+
+2 TRIGGER
+ TRIGGER
+
+ 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>]}
+
+ Before you run the MUPIP TRIGGER command:
+
+ 1. Set the value of the environment variable gtmgbldir: to specify the
+ value of a current global directory.
+ 2. Ensure that the key size, record size, block size of your database is
+ sufficient for storing trigger definition. You may have to set the key
+ and record sizes larger than the database content would otherwise
+ require.
+
+ The qualifiers of the MUPIP TRIGGER command are as follows:
+
+ TRIGgerfile=<trigger_definitions_file>
+
+ Loads a trigger definition file to the database. The format of the
+ TRIGGERFILE qualifier is:
+
+ -TRIG[GERFILE]=<trigger_definitions_file> [-NOPR[OMPT]]
+
+ o For information on the syntax and usage of a trigger definition file,
+ refer to GT.M Programmer's Guide.
+ o 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
+ 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
+ if the compilation has errors.
+ o 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
+ process from updating different nodes with triggers using a different
+ character set, however, GT.M prevents a process from updating the same
+ triggering node with different character sets. Your coding practice,
+ 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 Incompatible with: -SELECT
+
+ **Note**
+
+ The trigger update summary reports count not only names and option changes
+ as "modified" but also cases where a -COMMANDS list changed, even though
+ those are functionally additions or deletions of separate trigger
+ definitions.
+
+ SELECT=name-list
+
+ Provides a facility to examine the current trigger definition. SELECT
+ 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>]
+
+ 1. 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
+ extracts a list of all current triggers.
+ 3. 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.
+
+ **Note**
+
+ The output from the MUPIP TRIGGER -SELECT command may not be identical to
+ your trigger definition file. This is because GT.M converts some
+ semantically identical syntax into a single internal representation; while
+ -SELECT output may not be identical to the -TRIGGERFILE input, it has the
+ same meaning. Additionally, MUPIP TRIGGER -SELECT displays a field called
+ "Cycle" as part of a comment. Cycle is the number of trigger definition
+ updates (addition, modification, or deletion) performed on a global.
+
+3 Examples
+ Examples
+
+ This section provides step-by-step instructions for creating, modifying,
+ and deleting triggers. Triggers affect all processes updating a database
+ unlike, for example, environment variables such as $gtmroutines which work
+ on a per process basis. Therefore, FIS recommends that you should always
+ have carefully planned procedures for changing triggers in your production
+ environment.
+
+ To create a new trigger for global node ^Acct("ID"):
+
+ 1. Using your editor, create a trigger definition file called
+ triggers.trg with the following entry:
+
+ +^Acct("ID") -name=ValidateAccount -commands=S -xecute="Write ""Hello Earth!"""
+
+ 2. Execute a command like the following:
+
+ $ mupip trigger -triggerfile=triggers.trg
+
+ This command adds a trigger for ^Acct("ID"). On successful trigger
+ load, this command displays an output like the following:
+
+ File triggers.trg, Line 1: ^Acct trigger added with index 1
+ =========================================
+ 1 triggers added
+ 0 triggers deleted
+ 0 trigger file entries not changed
+ 0 triggers modified
+ =========================================
+
+ Now, every S[et] operation on the global node ^Acct("ID") executes the
+ trigger.
+
+ 3. Execute a command like the following:
+
+ $ mupip trigger -select="^Acct*"
+
+ This command displays the triggers. A sample output looks like the
+ following:
+
+ ;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"):
+
+ You cannot directly replace an existing trigger definition with a new one.
+ With the exception of -NAME and -OPTIONS, to change an existing trigger,
+ you have to delete the existing trigger definition and then add the
+ modified trigger definition as a new trigger. Note that GT.M performs two
+ different trigger comparisons to match trigger definitions depending on
+ whether or not S[ET] is the trigger invocation command. If there is a
+ S[ET], then the comparison is based on the global name and subscripts,
+ PIECES, [Z]DELIM, and XECUTE. If there is no SET, GT.M compares only the
+ global node with subscripts and the -XECUTE code value.
+
+ 1. Begin by executing the following command:
+
+ $ mupip trigger -select="^Acct*"
+ Output file:
+
+ 2. Specify trigger_mod.trg as the output file. This file contains entries
+ like the following:
+
+ ;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 -
+ (minus) for the trigger definition entry for ValidateAccount and add a
+ new trigger definition for ^Acct("ID"). To avoid inconsistent
+ application behavior, it is important to replace an old trigger with a
+ 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!"""
+
+ 4. Execute a command like the following:
+
+ $ mupip trigger -triggerfile=trigger_mod.trg
+
+ 5. This command displays an output like the following:
+
+ File trigger_mod.trg, Line 1: ^Acct trigger deleted
+ File trigger_mod.trg, Line 3: ^Acct trigger added with index 1
+ =========================================
+ 1 triggers added
+ 1 triggers deleted
+ 0 trigger file entries not changed
+ 0 triggers modified
+ =========================================
+
+ Congratulations! You have successfully modified the xecute string of
+ ValidateAccount with the new one.
+
+ To delete an existing trigger for global node ^Acct("ID"):
+
+ 1. Begin by executing the following command:
+
+ $ mupip trigger -select="^Acct*"
+ Output file:
+
+ 2. Specify trigger_delete.trg as the output file. This file contains
+ entries like the following:
+
+ ;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
+ definition entry for ValidateAccount. Alternatively, you can create a
+ file with an entry like -ValidateAccount.
+ 4. Now, execute a command like the following:
+
+ $ mupip trigger -triggerfile=trigger_delete.trg
+
+ This command displays an output like the following:
+
+ File trigger_delete.trg, Line 2: ^Acct trigger deleted
+ =========================================
+ 0 triggers added
+ 1 triggers deleted
+ 0 trigger file entries not changed
+ 0 triggers modified
+ =========================================
+
+ You have successfully deleted trigger "ValidateAccount".
+
+ To change a trigger name for global node ^Acct("ID"):
+
+ 1. Using your editor, create a new file called trigger_rename.trg and add
+ a trigger definition entry for ValidateAcct with the same trigger
+ signature as ValidateAccount. Your trigger definition would look
+ something like:
+
+ +^Acct("ID") -name=ValidateAcct -commands=S -xecute="Write ""Hello Mars!"""
+
+ 2. Verify that the ValidateAccount trigger exists by executing the
+ following command:
+
+ $ mupip trigger -select="^Acct*"
+ Output file:
+
+ 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
+ +^Acct("ID") -name=ValidateAccount -commands=S -xecute="Write ""Hello Mars!"""
+
+ 4. Now, execute a command like the following:
+
+ $ mupip trigger -triggerfile=trigger_rename.trg
+
+ This command displays an output like the following:
+
+ =========================================
+ 0 triggers added
+ 0 triggers deleted
+ 0 trigger file entries not changed
+ 1 triggers modified
+ =========================================
+
+ You have successfully changed the trigger name ValidateAccount to
+ ValidateAcct.
+
+2 UPGRADE
+ UPGRADE
+
+ Upgrades the file-header of a database. The format of the MUPIP UPGRADE
+ command is:
+
+ UP[GRADE]
+
+ o It increases the size from 4 bytes to 8 bytes of file-header fields
+ such as current transaction number (CTN), maximum TN and others that
+ contain transaction numbers.
+ o It resets the various trace counters and changes the database format
+ to V5. This change does not upgrade the individual database blocks but
+ sets the database format flag to V5.
+ o It also initializes a counter of the current blocks that are still in
+ V4 format. It decrements this counter each time an existing V4 format
+ block is converted to V5 format. When the counter is 0, the entire
+ database gets converted.
+
+3 Example
+ Example
+
+ Example:
+
+ $ mupip upgrade mumps.dat
+
+ This example upgrades the file-header of mumps.dat to V5 format.
+
+1 Journaling
+ Journaling
+
+2 SET
+ SET
+
+ MUPIP SET is the primary utility used to establish and activate journaling
+ (using the -JOURNAL) and replication (using the -REPLICATION).
+
+ When GDE creates a Global Directory, it stores either the explicitly
+ specified journaling information, or the GDE default value for any
+ unspecified characteristics.
+
+ MUPIP CREATE copies existing journaling information from the Global
+ Directory to the database file, establishing journaling characteristics
+ for all GDE supported journal-options.
+
+ **Important**
+
+ GT.M applies journaling information in the Global Directory to a database
+ file only when it is created. Thereafter use MUPIP, or possibly DSE, to
+ change journaling characteristics in database files. Be sure to use GDE to
+ reflect current journaling needs so that the next time you use MUPIP
+ CREATE you get the desired journaling characteristics.
+
+ DSE DUMP -FILEHEADER displays the current values for all established
+ journaling characteristics.
+
+ This section provides a description of the MUPIP SET command with specific
+ reference to the journaling related qualifiers.
+
+ MUPIP SET -JOURNAL can change some database characteristics when
+ journaling is active for a specific file or region(s). The first run of
+ MUPIP SET -JOURNAL on an older database automatically changes the
+ maximum/minimum journal settings to match those required by the current
+ GT.M version. MUPIP SET operates on either regions or files.
+
+ The format for the MUPIP SET command is:
+
+ MUPIP SE[T] -qualifier... {-F[ILE] file-name|-REG[ION] region-list}
+
+ The file-specification or region-list identifies the target of the SET.
+ Region-names separated by commas (,) make up a region-list.
+
+ To establish journaling characteristics, use the MUPIP SET command with
+ the -[NO]JOURNAL[=journal-option-list] qualifier and one of the following
+ SET object identifying qualifiers:
+
+ -F[ILE]
+ -R[EGION]
+
+ Together with one or more of the SET action qualifiers:
+
+ -[NO]JOURNAL[=journal-option-list] -REPLICATION=<replication-option>'
+
+3 Object_Identifying_Qualifiers
+ Object Identifying Qualifiers
+
+ The following qualifiers identify the journaling targets:
+
+ -F[ILE]
+
+ Specify that the argument to the SET is a file-specification for a single
+ database file. A Journal file's name can now include characters in
+ Unicode.
+
+ Old journal files stay open for about 10 seconds after a switch to a new
+ journal file.
+
+ -R[EGION]
+
+ Specify that the argument to the SET is a list of one or more
+ region-names, possibly including wildcards, which, through the mapping of
+ the current Global Directory, identifies a set of database files. SET
+ -REGION modifies multiple files when the parameter contains more than one
+ name.
+
+ The -REGION qualifier is incompatible with the -FILE qualifier.
+
+ -J[NLFILE]
+
+ Specifies that the target for SET is a journal file. The format of the
+ JNLFILE qualifier is:
+
+ -jnlfile jnl_file [-[no]prevjnlfile=jnlfilename] [-bypass]
+ [-repl_state={on|off}] [-dbfilename=file_name]
+
+ jnl_file specifies the name of the target journal file.
+
+ -prevjnlfile=jnlfilename
+
+ Changes the name of the previous generation of the journal file in the
+ header of jnl_file to jnlfilename (for example, when moving the previous
+ generation journal file to a different location). The file name can be a
+ full path-name or a relative path name; however, before the file-name is
+ stored in the header, it is expanded to its full path-name.
+
+ -noprevjnlfile
+
+ Cuts the generation link of the journal file jnl_file.The name of the
+ previous generation journal file is nullified in the header of jnl_file.
+ Such an operation is appropriate when it is assured that there will never
+ be a reason for a rollback to the previous generation journal file.
+
+ -bypass
+
+ Override the requirement that database files (or their corresponding
+ journal files) affected by the set command be available standalone.
+
+ **Caution**
+
+ Changing the previous generation file link when a rollback operation is in
+ progress or when the Source Server is actively replicating, can damage the
+ journal file and hamper recoverability.
+
+ -repl_state={on|off}
+
+ Change the replication state of a journal file; this command is intended
+ for use only under instructions from your GT.M support provider.
+
+ -dbfilename=file_name
+
+ Associates a journal file with a different database file; this command may
+ be useful in arranging unusual RECOVER or ROLLBACK scenarios.
+
+3 Action_Qualifiers
+ Action Qualifiers
+
+ The -JOURNAL and -REPLICATION qualifiers are the only SET qualifiers
+ relevant for journaling.
+
+ -[NO]J[OURNAL][=journal-option-list]
+
+ Enables or disables journaling for the specified database file or
+ region(s). MUPIP SET commands with this qualifier also establish the
+ characteristics for journal files. FIS believes the defaults and minimum
+ for journal file characteristics are in line with current hardware
+ capabilities and suitable for a production environment.
+
+ The journal-option-list contains keywords separated with commas (,)
+ enclosed in double quotes "". These double quotes are optional when the
+ list contains only one keyword. This option list is a super set of the
+ journal-option-list available through GDE.
+
+ o -NOJOURNAL specifies that the database does not allow journaling, or
+ disables journaling for a database that currently has it enabled. It
+ is equivalent to -JOURNAL=DISABLE.
+ o -NOJOURNAL does not accept an argument assignment. It does not create
+ new journal files. When a database has been SET -NOJOURNAL, it appears
+ to have no journaling file name or other characteristics.
+ o -JOURNAL= enables journaling for a database file. -JOURNAL= takes one
+ or more arguments in a journal-option-list. As long as journaling is
+ ENABLED and turned ON at the end of the command, SET -JOURNAL= always
+ creates a new version of the specified journal file(s).
+ o -NOJOURNAL specifies that the database does not allow journaling, or
+ disable journaling for a database where journaling is active.
+ o Enable BEFORE_IMAGE or NOBEFORE_IMAGE journaling for a database file.
+ o As long as journaling is ENABLED and turned ON at the end of the
+ command, SET -JOURNAL= always creates a new version of the specified
+ journal file(s).
+ o Every MUPIP SET -JOURNAL command on a database file that specifies an
+ ON or OFF journal-activation option causes the values of all
+ explicitly specified journal-file-options to be stored in the database
+ overriding any previously established characteristics for those
+ options.
+ o If you specify both -JOURNAL and -NOJOURNAL in the same command line,
+ the latter takes effect.
+ o Whenever MUPIP SET creates a new journal file, it uses all values for
+ journal-file-options that the user explicitly specifies in the command
+ line for the new journal file. If you do not specify a
+ journal-file-option, MUPIP SET takes the char acteristics of the
+ existing journal file.
+ o MUPIP SET supports qualifiers (like -ACCESS_METHOD, and so on) to
+ change non-journaling characteristics of database file(s). If you
+ specify these qualifiers -JOURNAL , MUPIP SET modifies the
+ non-journaling characteristics first and then moves on to modify the
+ journaling characteristics. Command execution stops when it encounters
+ an error. If MUPIP SET encounters an error in processing the command
+ line or the non-journaling characteristics, it makes no changes to any
+ characteristics. However, if MUPIP SET encounters an error in
+ processing the journaling characteristics, the non-journaling
+ characteristics have already been successfully changed.
+ o -NOJOURNAL is equivalent to -JOURNAL=DISABLE.
+ o -NOJOURNAL does not accept an argument assignment. It does not create
+ new journal files. When a database has been SET -NOJOURNAL, it appears
+ to have no journaling file name or other characteristics.
+
+ -REPLI[CATION]=replication-option
+
+ -REPLICATION sets journal characteristics and changes the replication
+ state simultaneously. It can also be used with the -JOURNAL qualifier. If
+ journaling is ENABLED and turned ON, SET -REPLICATION=ON creates new set
+ of journal files, cuts the back-link to the prior generation journal
+ files, and turns replication ON.
+
+4 JOURNAL_Options
+ JOURNAL Options
+
+ ALI[GNSIZE]=blocks
+
+ o Specifies the number of 512-byte-blocks in the ALIGNSIZE of the
+ journal file.
+ o If the ALIGNSIZE is not a perfect power of 2, GT.M rounds it up to the
+ nearest power of 2.
+ o The default and minimum ALIGNSIZE value is 4096 blocks. The maximum
+ value is 4194304 (=2 GigaBytes).
+ o A journal file consists of a sequential stream of journal records each
+ of varying size. It is typically not easy to detect the beginning of
+ the last valid journal record in an abnormally terminated journal file
+ (for example, system crash). To facilitate journal recovery in the
+ event of a system crash, the GT.M run-time system ensures that offsets
+ in the journal file which are multiple of ALIGNSIZE (excepting offset
+ 0 which houses the journal file header) is always the beginning of a
+ valid journal record. In order to ensure this, GT.M run-time system
+ writes padding data (if necessary) in the form of ALIGN journal
+ records just before the ALIGNSIZE boundary. These ALIGN records also
+ help in skipping past invalid records in the middle of a journal file
+ allowing MUPIP JOURNAL -EXTRACT -FORWARD -FULL to extract as much data
+ of a corrupt journal file as possible.
+ o While a larger align size trade off crash recovery time in favor of
+ increased journaling throughput, especially when before image
+ journaling is in use, there is marginal value in using an align size
+ larger than a few MB.
+ o The minimum ALIGNSIZE supported is always be greater than or equal to
+ the maximum journal record size, which in turn depends on the maximum
+ database block size.
+ o Note that a large value of ALIGNSIZE implies less aligned boundaries
+ for recovery to use and hence slows backward recovery down so
+ drastically that, for example, the maximum value of 4194304 causes
+ backward recovery (in case of a crash) to take as much time as forward
+ recovery on that journal file.
+
+ ALL[OCATION]=blocks
+
+ Sets the allocation size of the journal file. GT.M uses this information
+ to determine when it should first review the disk space available for the
+ journal file. The size of the journal file at creation time is a constant
+ (depending on the GT.M version) but once the journal file reaches the size
+ specified by ALLOCATION, every extension produces a check of free space
+ available on the device used for the journal file.
+
+ GT.M issues informational messages to the system log whenever the free
+ space available is not much more than the extension size. GT.M provides
+ these extension checks as an operational aid for identifying, before space
+ runs out, that a file system holding the journal file is low on space.
+ When there is no more free space available on the file system holding a
+ journal file, GT.M shuts off journaling for the corresponding database
+ file.
+
+ The default ALLOCATION value is 2048 blocks. The minimum value allowed is
+ 2048. The maximum value is 8,388,607 (4GB-512 bytes, the maximum journal
+ file size).
+
+ AU[TOSWITCHLIMIT]=blocks
+
+ Specifies the limit on the size of a journal file. When the journal file
+ size reaches the limit, GT.M automatically performs an implicit online
+ switch to a new journal file.
+
+ **Note**
+
+ It is possible to set the AUTOSWITCHLIMIT to a value higher than the
+ maximum file size (in blocks) for the file system. Currently GT.M does not
+ attempt to check for this condition at specification time. GT.M produces a
+ run-time error when a journal file reaches the maximum size for the file
+ system. Therefore, ensure that the AUTOSWITCHLIMIT never exceeds the
+ file-system limit.
+
+ The default value for AUTOSWITCHLIMIT is 8388600 & the maximum value is
+ 8388607 blocks (4GB-512 bytes). The minimum value for AUTOSWITCHLIMIT is
+ 16384. GT.M produces an error if the AUTOSWITCHLIMIT value is less than
+ the sum of allocation and extension values. If the difference between the
+ AUTOSWITCHLIMIT and the allocation value is not a multiple of the
+ extension value, GT.M rounds-down the value to make it a multiple of the
+ extension value and displays an informational message. GT.M produces an
+ error when the rounded value of AUTOSWITCHLIMIT is less that the minimum
+ value.
+
+ If you specify values for ALLOCATION, EXTENSION, and AUTOSWITCHLIMIT for a
+ region such that (ALLOCATION+EXTENSION>AUTOSWITCHLIMIT), either using GDE
+ or MUPIP SET -JOURNAL, GT.M sets ALLOCATION to match the AUTOSWITCHLIMIT,
+ and produces a JNLALLOCGROW message.
+
+ At journal extension time, including journal autoswitch time, if
+ (ALLOCATION+EXTENSION>AUTOSWITCHLIMIT) for a region, GT.M uses the larger
+ of EXTENSION and AUTOSWITCHLIMIT as the increment to warn of low available
+ journal disk space. Otherwise, it uses EXTENSION.
+
+ [NO]BEFORE_IMAGES
+
+ Controls whether the journal should capture BEFORE_IMAGES of GDS blocks
+ that an update is about to modify. A SET -JOURNAL=ON must include either
+ BEFORE_IMAGES or NOBEFORE_IMAGES in the accompanying journal-option-list.
+
+ If you specify both NOBEFORE_IMAGES and BEFORE_IMAGES in the same
+ journal-option-list, the last specification overrides any previous one(s).
+
+ As GT.M creates new journal files only with the ON option and every ON
+ specification must include either BEFORE_IMAGES or NOBEFORE_IMAGES. If the
+ user specifies [NO]BEFORE_IMAGES along with the OFF option serve no
+ purpose.
+
+ Although it is possible to perform an online switch of a database from (or
+ to) NOBEFORE-IMAGE journaling to (or from) BEFORE-IMAGE journaling, it is
+ important to understand that backward recovery can never succeed if it
+ encounters even one in a set of journal files for a database without
+ BEFORE-IMAGES.
+
+ BU[FFER_SIZE]=blocks
+
+ Specifies the amount of memory used to buffer journal file output.
+
+ MUPIP requires standalone access to the database to modify BUFFER_SIZE.
+ Therefore, GT.M restricts the use of the BUFFER_SIZE option to change the
+ current journal-buffer-size as part of an online switch of the journal
+ files.
+
+ The default value is 2308 blocks. The minimum BUFFER_SIZE is 2307 blocks.
+ The maximum BUFFER_SIZE is 32K blocks which means that the maximum buffer
+ you can set for your journal file output is 16MB.
+
+ DISABLE
+
+ Equivalent to the -NOJOURNAL qualifier of MUPIP SET. It specifies that
+ journaling is not an option for the region or file named. If the user
+ specifies DISABLE, then MUPIP SET ignores all other options in the
+ journal-option-list.
+
+ ENABLE
+
+ Makes the database file or region available for journaling. By default,
+ ENABLE turns journaling ON unless OFF is specified in the same option
+ list. A command that includes ENABLE must also specify BEFORE_IMAGES or
+ NOBEFORE_IMAGES.
+
+ EP[OCH_INTERVAL]=seconds
+
+ seconds specifies the elapsed time interval between two successive EPOCHs.
+ An EPOCH is a checkpoint, at which all updates to a database file are
+ committed to disk. All journal files contain epoch records.
+
+ A smaller EPOCH_INTERVAL reduces the time to recover after a crash at the
+ cost of increased I/O load on the run-time system (due to more frequent
+ checkpoints). A larger EPOCH_INTERVAL has the opposite effect. Therefore,
+ set EPOCH=interval for a more efficient run-time with larger values of
+ interval and more efficient ROLLBACK processing with smaller values of
+ interval.
+
+ The default EPOCH_INTERVAL value is 300 seconds (5 minutes). The minimum
+ value is 1 second. The maximum value is 32,767 (one less than 32K)
+ seconds, or approximately 9.1 hours. If you enable journaling and do not
+ specify a value for EPOCH_INTERVAL, GT.M inherits the value of
+ EPOCH_INTERVAL of the last journal file in that region. EPOCH_INTERVAL
+ only makes takes effect when the user turns journaling ON and there is no
+ earlier journal file.
+
+ EX[TENSION]=blocks
+
+ blocks specifies the size of the journal file extension by which file
+ expands and becomes full.
+
+ EXTENSION=blocks specifies when GT.M should review disk space available
+ for the journal file after the ALLOCATION has been used up. It also
+ specifies how much space should be available at each review.
+
+ As UNIX file systems use lazy allocation schemes, allocation and extension
+ values do not result in physical disk block allocation for the journal
+ file.
+
+ The values determine when GT.M checks the file systems to see if it has
+ enough space to hold an extension worth of journal data. When a journal
+ file reaches the size of ALLOCATION and any multiple of EXTENSION, GT.M
+ checks the file system for room, and if the available space is less than
+ three times the EXTENSION, it writes warnings to the operator log. GT.M
+ provides these extension checks as an operational aid for identifying,
+ before space runs out, that a file system holding the journal file is low
+ on space. When there is no more free space available ) on the file system
+ holding a journal file or there is no authorization of a process
+ attempting to autoswitch a journal file, GT.M shuts off journaling for the
+ corresponding database file.
+
+ The default EXTENSION value is 2048 blocks. The minimum EXTENSION is zero
+ (0) blocks and the maximum is 1073741823 (one less than 1 giga) blocks.
+
+ F[ILENAME]=journal_filename
+
+ journal_filename specifies the name of the journal file. FILENAME is
+ incompatible with SET -REGION, if you specify more than one region.
+
+ GT.M treats the filename as having two components - basename and
+ extension. The format of the journal filename is basename.extension, where
+ extension does not contain any periods (.), but if the filename contains
+ more than one period (.), basename contains all but the last period (.).
+ Also note that "extension" is the empty string ("") if the filename does
+ not contain any periods (.).
+
+ The convention of the default value for the FILENAME is as follows:
+
+ o GT.M takes the basename of the database filename as the basename for
+ the journal file with an extension of mjl if the database has a dat
+ extension. For example, database name mumps.dat results in a default
+ name mumps.mjl. If the database filename does not have a dat
+ extension, GT.M replaces all occurrences of periods (.) with
+ underscores (_) with an extension of mjl and takes the full database
+ filename. For example, database name mumps.acn results in a default
+ name mumps_acn.mjl. Therefore, by default, a journal file has an
+ extension of mjl unless you explicitly specify a different extension
+ with the FILENAME journal option. If the new journal filename (the one
+ specified in the FILENAME option or the default) already exists, GT.M
+ renames the existing file with the string "_YYYYJJJHHMMSS" appended to
+ the existing file extension where the string denotes the time of
+ creation of the existing journal file in the following format:
+
+ YYYY 4-digit-year such as 2011
+ JJ 3-digit-Julian-day (between 1 and 366) such as 199
+ HH 2-digit-hour in 24 hr format such as 14
+ MM 2-digit minute such as 40
+ SS 2-digit seconds such as 30
+
+ Assuming the above example for the string value, GT.M renames a
+ journal file mumps.mjl to mumps.mjl_2010199144030 when it switches to
+ a new journal file.
+
+ o If GT.M detects that the rename-logic yields a filename that already
+ exists, the string "_N[N[N[N...]]]" is appended to the renamed
+ filename where "N[N[N...]]" denotes the sequence of numbers
+ 0,1,2,3,4,5,6,7,8,9,90,91,92,93,94,95,96,97,98,99,990,991,...
+
+ GT.M tries all numbers from the order in the above sequence until it
+ finds a non-existing rename-filename.
+
+ Taking the same example as above, in case mumps.mjl_2010199144030 and
+ mumps.mjl_2010119144030_0 already exists, the rename string would be
+ mumps.mjl_2010199144030_1.
+
+ o If the existing file renaming scheme or the default journal file
+ naming scheme discussed above results in a filename longer than 255
+ characters (due to the suffix creation rules), GT.M produces an error
+ and turns off journaling.
+
+ A journal file name can include characters in Unicode.
+
+ **Note**
+
+ Whenever GT.M implicitly turns off journaling due to run-time conditions
+ such as no available disk space or no authorization for a process
+ attempting to auto-switch a journal file (and so on) , it produces an
+ error and accompanying messages identify the reason for that condition.
+
+ For journal recovery, GT.M maintains a field in every journal file's
+ header that stores the name of the previous generation journal file for
+ the same database file. When a MUPIP SET changes the journal state from
+ DISABLED or OFF to ON, GT.M creates new journal files with no previous
+ generation journal file name. This indicates that this is a fresh start of
+ journaling for the particular database. When journaling is already ON, and
+ GT.M is implicitly (due to AUTOSWITCHLIMIT being reached) or explicitly
+ (due to MUPIP SET JOURNAL) required to create new journal files, GT.M
+ maintains the previous generation journal filename (after any appropriate
+ rename), in the new journal file's header.
+
+ In all cases where journaling is ON both before and after a journal file
+ switch, GT.M maintains the previous generation journal file name in the
+ new journal file's header except when GT.M creates a new journal file due
+ to an implicit switch because it detects an abnormal termination of the
+ current journal file or if the current journal file was not properly
+ closed due to a system crash and the database was the subject of a MUPIP
+ RUNDOWN afterwards.
+
+ **Note**
+
+ In the event of a crash, FIS strongly recommends performing a MUPIP
+ JOURNAL ROLLBACK on a database with replication, MUPIP JOURNAL RECOVER on
+ a journaled database, and MUPIP RUNDOWN only if using neither journaling
+ nor replication. GT.M error messages provide context-specific instructions
+ to promote this decision-making model which helps protect and recover data
+ after a crash.
+
+ The previous generation journal filename is a back link from the current
+ generation journal.
+
+ GT.M produces an error and makes no change to the journaling state of the
+ database when the FILENAME is an existing file and is not the active
+ journal file for that database. In this way, GT.M prevents possible cycles
+ in the back-links (such as, a3.mjl has a back-link to a2.mjl which in turn
+ has a back-link to a1.mjl which in turn has a back-link to a3.mjl thereby
+ creating a cycle). Cycles could prevent journal recovery. Also, note that
+ cycles in back-links are possible only due to explicit FILENAME
+ specifications and never due to an existing FILENAME characteristics from
+ the database or by using the default FILENAME.
+
+ NOPREVJNLFILE
+
+ Eliminates the back link of a journal file.
+
+ [NO]S[YNC_IO]
+
+ Directs GT.M to open the journal file with certain additional IO flags
+ (the exact set of flags varies by the platform where SYNC_IO is supported,
+ for example on Linux you might utilize the O_DIRECT flag). Under normal
+ operation, data is written to but not read from the journal files.
+ Therefore, depending on your actual workload and your computer system, you
+ may see better throughput by using the SYNC_IO journal option.
+
+ You should empirically determine the effect of this option, because there
+ is no way to predict the performance gain or impact in advance. There is
+ no functional difference in GT.M behavior with the use of SYNC_IO. If you
+ determine that different workloads perform best with a different setting
+ of SYNC_IO, you can change it with MUPIP SET at any time.
+
+ The default is NOSYNC_IO. If you specify both NOSYNC_IO and SYNC_IO in the
+ same journal-option-list, GT.M uses the last occurrence.
+
+ OFF
+
+ Stops recording subsequent database updates in the journal file. Specify
+ OFF to establish journaling characteristics without creating a journal
+ file or starting journaling.
+
+ The default for SET -JOURNAL= is ON.
+
+ ON
+
+ Records subsequent database updates in that journal file. MUPIP SET
+ -JOURNAL=ON must include either BEFORE_IMAGES or NOBEFORE_IMAGES in the
+ accompanying journal-option-list. By default GT.M sets journal operation
+ to BEFORE_IMAGE if this command changes the database replication state
+ from OFF to ON and JOURNAL=NOBEFORE_IMAGE is not specified.
+
+ **Important**
+
+ ON keyword works only on previously ENABLEd regions. GT.M ignores ON if
+ Journaling is DISABLEd. In other words, an ENable / DISable is like the
+ power switch on the back of many television sets and ON/OFF is like the
+ ON/OFF on the remote control. The ON/OFF on the remote control works only
+ when the power switch on the back of the television set is enabled.
+
+ If the current generation journal file is damaged/missing, MUPIP SET
+ -JOURNAL=ON implicitly turns off journaling for the specified region,
+ creates a new journal file with no back pointers to the prior generation
+ journal file, and turns journaling back on. Further, if replication is
+ enabled, MUPIP SET -JOURNAL=ON temporarily switches the replication WAS_ON
+ state in the time window when MUPIP SET command turns off journaling and
+ returns normal as long as it operates out of the journal pool buffer and
+ doesn't need to reference the damaged journal file(s). During this
+ operation, MUPIP SET -JOURNAL=ON also sends the PREJNLLINKCUT message for
+ the region to the application and the operator log. While this operation
+ ensures that journaling continues even if the current generation journal
+ file is damaged/missing, creating a new journal file with no back pointers
+ creates a discontinuity with the previous journal files. Therefore, FIS
+ recommends taking a database backup at the earliest convenience because a
+ MUPIP RECOVER/ROLLBACK will not be able to go back past this
+ discontinuity. Also, consider switching the journal files on all regions
+ in the instance (with REGION "*") to ensure the RECOVER/ROLLBACK for other
+ regions remains unaffected.
+
+ The default for SET -JOURNAL= is ON.
+
+ Y[IELD_LIMIT]=yieldcount
+
+ yieldcount specifies the number of times a process that tries to flush
+ journal buffer contents to disk yields its timeslice and waits for
+ additional journal buffer content to be filled-in by concurrently active
+ processes, before initiating a less than optimal I/O operation.
+
+ A smaller YIELD_LIMIT is appropriate for light load conditions while
+ larger values are appropriate as the load increases.
+
+ **Note**
+
+ A small YIELD_LIMIT may cause performance loss due to partial page writes
+ while a large YIELD_LIMIT may cause performance loss due to significant
+ idle times (due to a lot of yields).
+
+ The minimum YIELD_LIMIT is zero (0), the maximum YIELD_LIMIT is 2048 and
+ the default YIELD_LIMIT is 8.
+
+ As the disk can only write entire blocks of data, many I/O subsystems
+ perform a READ-MODIFY-WRITE operation when data to be written is a partial
+ block as opposed to simple writes for an entire block. The YIELD_LIMIT
+ qualifier tries to reduce the frequency of sub-optimal partial block
+ writes by deferring such writes as much as possible in the hope that in
+ the meantime the journal buffer accumulates more content and qualifies for
+ an optimal entire block write.
+
+3 Examples
+ Examples
+
+ $ mupip set -journal="enable,nobefore" -file mumps.dat
+
+ This example enables NOBEFORE_IMAGE journaling on mumps.dat. If journaling
+ is already enabled, this command switches the current journal file.
+
+ Example:
+
+ $ mupip set -journal=on,enable,before -region "*"
+
+ This example turn on journaling with BEFORE_IMAGE journaling. If
+ journaling is already enabled, this command switches the current journal
+ file for all regions.
+
+ $ mupip set -file -journal="nobefore,buff=2307" gtm.dat
+
+ This example initiates NOBEFORE_IMAGE journaling for the database file
+ gtm.dat with a journal buffer size of 2307 blocks. It also switches to new
+ journal file. This command assumes that some prior MUPIP SET -JOURNAL
+ specified ENABLE for gtm.dat.
+
+ Example:
+
+ $ mupip set -region -journal=enable,before_images,allocation=50000,ext=5000 "*"
+
+ This example enables journaling with BEFORE_IMAGES on all regions of the
+ current Global Directory and gives each journal file an ALLOCATION of
+ 50000 blocks and an EXTENSION of 5000 blocks. If the regions have
+ significantly different levels of update, use several MUPIP SET -FILE or
+ -REGION commands.
+
+ Example:
+
+ $ mupip set -region -journal="enable,before" areg,breg
+
+ This example declares journaling active with BEFORE_IMAGES for the regions
+ areg and breg of the current Global Directory.
+
+ Example:
+
+ $ mupip set -file -nojournal mumps.dat
+
+ This example disables journaling on the database file mumps.dat.
+
+ Example:
+
+ $ mupip set -journal="ENABLE,BEFORE_IMAGES" -region "AREG"
+ $ mupip set -journal="ON,BEFORE_IMAGES" -region "*"
+
+ This example turns on journaling only for the region AREG. Note that AGREG
+ is the only region that is "available" for journaling.
+
+ Example:
+
+ $ mupip set -access_method=MM -file gtm.dat
+
+ This example sets MM (Memory Mapped) as the access method or GT.M
+ buffering strategy for storing and retrieving data from the database file
+ gtm.dat. Since MM is not supported with BEFORE_IMAGE journaling, this
+ example produces an error on a database with BEFORE_IMAGE journaling
+ enabled. You can also use -access_method=BG to set BG (Buffered Global) as
+ your buffering strategy.
+
+ Example:
+
+ $ mupip set -journal=before,noprevjnlfile,file=newmumps.mjl -file mumps.dat
+
+ The above command cuts the back link of the newly created journal file
+ newmumps.mjl.
+
+2 JOURNAL
+ JOURNAL
+
+ MUPIP JOURNAL command analyzes, extracts from, reports on, and recovers
+ journal files. The format for the MUPIP JOURNAL command is:
+
+ MUPIP J[OURNAL] -qualifier[...] file-selection-argument
+
+ file-selection-argument is a comma-separated list of journal files.
+
+ -qualifier [...] is a combination of Action, Direction, Time, Sequence
+ Number, Control, and Selection qualifiers that perform various MUPIP
+ JOURNAL operations. To create any MUPIP JOURNAL command, select an
+ appropriate combination of qualifiers by moving horizontally from the
+ Action column extending to the Selection column:
+
+ +---------------------------------------------------------------------------------------+
+ | | | | Sequence | Control | Selection |
+ | Action |Direction| Time (optional) | Number | (optional) | (optional) |
+ | | | |(optional)| | |
+ |---------------+---------+--------------------+----------+--------------+--------------|
+ |One or more |Only one |One or more |Only one |One or more |One or more |
+ |---------------+---------+--------------------+----------+--------------+--------------|
+ | | | | |-[NO]AP | |
+ | | | | | | |
+ | | | | |-BR=extract | |
+ | | | | |file name | |
+ | | | | | | |
+ | | | | |-[NO]CHA | |
+ | | | | | | |
+ | | | | |-[NO]CHE | |
+ |-EX[=file | | | | | |
+ |specification] | | | |-[NO]ER[= | |
+ | | |-A=time | |integer] |-G=global list|
+ |-REC | | |-FET=port | | |
+ | | |-BE=time |number |-FE=fence |-ID=pid list |
+ |-RO |-BA -FO | | |option | |
+ | | |-[NO]LOO= lookback |-RES=jnl | |-T=transaction|
+ |-SH=show option| |option list] |sequence |-FU |type |
+ |list] | | |number | | |
+ | | |-SI=time | |-[NO]IN |-U=user list |
+ |-[NO]V | | | | | |
+ | | | | |-LOST=extract | |
+ | | | | |file name | |
+ | | | | | | |
+ | | | | |-RED=file pair| |
+ | | | | |list | |
+ | | | | | | |
+ | | | | |-VERB | |
+ | | | | | | |
+ | | | | |-DE | |
+ +---------------------------------------------------------------------------------------+
+
+ Also ensure that you adhere to the following rules:
+
+ 1. -BEFORE is compatible with all other JOURNAL qualifiers except
+ -ROLLBACK.
+ 2. -AFTER is incompatible with -BACKWARD and all action qualifiers,
+ except -EXTRACT, -SHOW, and -VERIFY.
+ 3. -APPLY_AFTER_IMAGE is compatible only with -RECOVER, or -ROLLBACK.
+ 4. -BACKWARD is incompatible with -FORWARD, -AFTER, -CHECKTN, -NOCHAIN,
+ and -REDIRECT.
+ 5. -BROKENTRANS is compatible only with -RECOVER, -ROLLBACK, or -EXTRACT.
+ 6. -CHAIN is only compatible with -FORWARD.
+ 7. -DETAIL is compatible only with -EXTRACT.
+ 8. -FETCHRESYNC or -RESYNC are compatible only with -ROLLBACK.
+ 9. -FORWARD is incompatible with -BACKWARD, -ROLLBACK, -SINCE, and
+ -LOOKBACK_LIMIT.
+ 10. -FULL is compatible only with -EXTRACT, -SHOW, or -VERIFY.
+ 11. -LOSTTRANS is compatible only with -RECOVER, -ROLLBACK, or -EXTRACT.
+ 12. -REDIRECT is compatible only with -RECOVER.
+ 13. -ROLLBACK is incompatible with -RECOVER, FORWARD, -CHAIN, -CHECKTN,
+ -REDIRECT, time qualifiers of -SHOW.
+ 14. -SINCE is incompatible with -FORWARD.
+ 15. -TRANSACTION is compatible only with -EXTRACT and -SHOW.
+ 16. -USER is compatible only with -EXTRACT and -SHOW.
+ 17. file list must not be asterisk (*) for -REDIRECT.
+ 18. file list must be asterisk (*) for -ROLLBACK.
+ 19. Journal selection qualifiers are incompatib le with -RECOVER,
+ -ROLLBACK, and -VERIFY.
+ 20. Journal time qualifiers are incompatible with -ROLLBACK.
+
+ For example, MUPIP JOURNAL -EXTRACT=gtm.mjf -FORWARD -DETAIL is a valid
+ command which performs forward processing to extract detailed the journal
+ records to gtm.mjf. However, MUPIP JOURNAL -EXTRACT
+ -REDIRECT=gtm.dat=test/gtm.dat -FORWARD is an invalid command because
+ -REDIRECT is not compatible with -EXTRACT.
+
+ MUPIP JOURNAL manipulates an inactive journal file that is available for
+ exclusive (standalone) use. You can transcribe Journal files to tape.
+ However, you must always restore them to disk for processing by MUPIP
+ JOURNAL.
+
+ Press CTRL+C to stop JOURNAL processing. A JOURNAL command that terminates
+ abnormally by operator action or error produces an incomplete result. In
+ this case, the resulting database may be corrupt. If you stop a JOURNAL
+ operation by mistake, reissue the command to produce the proper result for
+ -RECOVER (or -ROLLBACK) -BACKWARD. For -RECOVER -FORWARD, restore the
+ database from backup and reissue the command.
+
+3 Action_Qualifiers
+ Action Qualifiers
+
+ This section describes the journaling action qualifiers.
+
+4 EXtract
+ EXtract
+
+ Transfers information from journal files into files formatted for
+ processing by M routines. It reports the journal time stamps using the $H
+ format, as controlled by the time zone setting from the OS and the process
+ environment for the process running the EXTRACT.
+
+ -EXTRACT takes <file-name> or -stdout as an optional argument.
+
+ <file-name> specifies the name of the output file. -stdout specifies that
+ -EXTRACT write to standard output (stdout) instead of writing to a file.
+
+ With no arguments, MUPIP JOURNAL derives the output file specification of
+ the extract file using the name of the first journal file that is
+ processed in the forward processing phase and a file type of .mjf. Note
+ that, if multiple journal names are specified in the command line the
+ first journal specified might be different from the first journal
+ processed in the forward phase. When -EXTRACT is specified with -RECOVER
+ (or -ROLLBACK), the -JOURNAL command extracts all the journal records
+ processed during a -RECOVER -FORWARD command or the forward phase of
+ (-RECOVER or -ROLLBACK) -BACKWARD command.
+
+ -EXTRACT applies to forward processing of the journal file; if the
+ combined state of the journal file and the Journal Time qualifiers does
+ not cause forward processing, -EXTRACT does not create an output file.
+
+ When used independent of -RECOVER (or -ROLLBACK), -EXTRACT option can
+ produce a result even though the database file does not exist, although it
+ does try to access the database if it is available.
+
+ If a database having custom collation is inaccessible or the replication
+ instance is frozen with a critical section required for the access held by
+ another process and the environment variable gtm_extract_nocol is defined
+ and evaluates to a non-zero integer or any case-independent string or
+ leading substrings of "TRUE" or "YES", MUPIP JOURNAL -EXTRACT issues the
+ DBCOLLREQ warning and proceeds with the extract using the default
+ collation. If gtm_extract_nocol is not set or evaluates to a value other
+ than a positive integer or any case-independent string or leading
+ substrings of "FALSE" or "NO", MUPIP JOURNAL -EXTRACT exits with the
+ SETEXTRENV error if it encounters such a situation. Note that if default
+ collation is used for a database with custom collation, the subscripts
+ reported by MUPIP JOURNAL -EXTRACT are those stored in the database, which
+ may differ from those read and written by application programs.
+
+ Note that, a broken transaction, if found, is extracted to a broken
+ transaction file for details), and all future complete transactions are
+ considered as lost transactions, and are extracted to a lost transaction
+ file for details).
+
+ 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
+ -RECOVER/-ROLLBACK is also specified.
+
+4 RECover
+ RECover
+
+ Instructs MUPIP JOURNAL to initiate database recovery. -RECOVER initiates
+ the central JOURNAL operation for non-replicated database. From the list
+ of JOURNAL action qualifiers, select RECOVER alone or with any other
+ action qualifiers except -ROLLBACK.
+
+ -RECOVER -FORWARD with time qualifiers initiates forward recovery. Forward
+ recovery ignores the current journaling state of the target database file.
+ It disables journaling of the target database file, (if currently ENABLE
+ and ON), while playing forward the database updates. However, it restores
+ the journaling state of the database at the end of a successful recovery
+ (if necessary), except when journaling is ENABLE'd and ON before the
+ recovery. In the latter case, the journaling state at the end of a
+ successful recovery, is switched to ENABLE and OFF. No journaling is
+ performed for the logical updates to the database for JOURNAL -RECOVER
+ -FORWARD. If the target database's current transaction number is less than
+ first transaction number to be processed in the specified journal file for
+ that region, -RECOVER attempts to include previous generation journal
+ file(s) in its processing, unless the -NOCHAIN qualifier is specified.
+ Following the successive previous links of journal files -RECOVER tries to
+ include previous generations of journal files until the transaction number
+ when the journal file was created is less than, or equal to that of the
+ target database. -RECOVER issues one or more informational messages when
+ it includes previous generation journal files. If target database's
+ current transaction number is not equal to the first transaction number of
+ the earliest journal file to be processed for a region, -RECOVER exits
+ with an error. If multiple journal files for a single region are specified
+ with -RECOVER -FORWARD, it behaves as if -NOCHAIN was specified. If the
+ journal files are not a complete set (for example mumps1.mjl and
+ mumps3.mjl were specified, with mumps2.mjl missing from the command line),
+ MUPIP JOURNAL produces an error because the journal files specified are
+ discontinuous in terms of database transaction numbers. On the other hand,
+ specifying just mumps3.mjl automatically includes mumps2.mjl and
+ mumps1.mjl in the recovery.
+
+ -RECOVER -BACKWARD with time qualifiers initiates backward recovery. For
+ backward recovery, the target database file should be the same as when
+ GT.M wrote the last complete transaction to the journal. Because the
+ database may be in an indeterminate state due to a failure, exact checks
+ for this match are not possible. If the target database has journaling
+ DISABLE'd (or ENABLE, OFF), -RECOVER -BACKWARD exits with an error
+ message.
+
+ If the target database has journaling ENABLE, ON, but the journal file
+ name in database file header does not match the latest generation journal
+ file name specified for that region, -RECOVER exits with an error.
+
+ During forward processing phase of JOURNAL -RECOVER -BACKWARD, MUPIP
+ journals the logical updates to the database. It also creates before
+ images. It is always required to have journaling ENABLE'd and ON for
+ -RECOVER -BACKWARD or -ROLLBACK.
+
+ If a transaction is found with incomplete fence, it is considered broken.
+ During forward phase of recovery, if a complete transaction (fenced or
+ unfenced) is found after a broken transaction. -RECOVER increments the
+ error count. If -ERRORLIMIT is reached, the complete transaction goes to
+ lost transaction file, otherwise, it is applied to the database.
+
+ All broken and lost transactions are made available as the result of the
+ -RECOVERY. They are written as journal extract format in two different
+ text files. They are the broken transaction file and the lost transaction
+ file.
+
+ When performing JOURNAL -RECOVER with fences (FENCES="PROCESS" or
+ FENCES="ALWAYS"), it is essential for the command to include all the
+ journal files corresponding to the complete set of database files that
+ make up the logical database. If the specified set of journals is
+ incomplete, the recovery reports all transactions that included any
+ missing region as broken. Typically, this means that the results of the
+ recovery are unsatisfactory or even unusable.
+
+ MUPIP JOURNAL -RECOVER requires exclusive access to database files before
+ recovery can occur. It keeps the exclusive access to the database files,
+ which means that the database files become inaccessible during the time of
+ recovery.
+
+ If time qualifiers are not specified, -BACKWARD -RECOVER/-ROLLBACK
+ performs optimal recovery. An optimal recovery checks whether the
+ datatabase is in a wholesome state and attempts to perform an automatic
+ recovery if there is a crash. If needed, optimal recovery goes back to
+ include some previous generation files in order to get a consistent
+ starting point and then comes forward as far as the available journal
+ record allow it to while preserving consistent application state. At the
+ end, the journaling state of the database stays ENABLE, ON. Note that the
+ gtm script performs an optimal recovery on every run.
+
+ When a database file is rolled back by -RECOVER -BACKWARD, the
+ corresponding journal file is also rolled back so that the two are
+ synchronized. -RECOVER -BACKWARD then creates a new journal file. If no
+ forward play of journal records is neccessary, the newly created journal
+ file stays empty and the database points to the new journal file. The
+ values for journal allocation and extension in the new journal file, are
+ copied over from the database. The autoswitchlimit value in the new
+ journal file is the maximum of the autoswitchlimit values of all journal
+ files from the latest generation journal file until the turnaround point
+ journal file generation (turnaround point is the point in the journal file
+ where backward processing stops and forward processing begins). The
+ journal allocation/extension values in the new journal file are picked up
+ from the earliest generation of the set of those journal files sharing the
+ maximum autoswitchlimit value.
+
+ GT.M adds a prefix rolled_bak_ to the journal file whose entire contents
+ are eliminated (rolled back) by -RECOVER -BACKWARD. GT.M does not use
+ these files after a successful recovery therefore you might want to
+ consider moving or deleting them. You should never use rolled_bak* files
+ for any future database recovery. If there is a need to process
+ rolled_bak* files, you should extract the journal records from
+ rolled_back* files and process them using a M program.
+
+4 ROLLBACK
+ ROLLBACK
+
+ -ROLLBACK initiates the central JOURNAL operation for a replicated
+ database. MUPIP JOURNAL commands may specify -ROLLBACK with other action
+ qualifiers but not with -RECOVER. If you do not use -FETCHRESYNC, the
+ database rolls back to the last consistent state. Only asterisk (*)
+ qualifier is allowed for the journal file selection, that is, -ROLLBACK
+ selects journal files by itself.
+
+ -NOO[NLINE]
+
+ Specifies that ROLLBACK requires exclusive access to the database and the
+ replication instance file. This means that the database and the
+ replication instance files are inaccessible during a -ROLLBACK -NOONLINE.
+
+ By default, MUPIP JOURNAL -ROLLBACK is -NOONLINE.
+
+ -ON[LINE]
+
+ Specifies that ROLLBACK should run without requiring exclusive access to
+ the database and the replication instance file.
+
+ GT.M increments ISV $ZONLNRLBK every time a process detects a concurrent
+ MUPIP JOURNAL -ONLINE -ROLLBACK.
+
+ If the logical state of the database after the completion of MUPIP JOURNAL
+ -ONLINE -ROLLBACK matches the logical state of the database at the start
+ of MUPIP JOURNAL -ONLINE -ROLLBACK, that is, only removes or commits an
+ uncommitted TP transaction or non-TP mini-transaction, any transaction (TP
+ or Non-TP) incurs a restart.
+
+ If MUPIP JOURNAL -ONLINE -ROLLBACK changes the logical state of the
+ database, the behavior is as follows:
+
+ o -ONLINE -ROLLBACK increments ISV $ZONLNRLBK
+ o In a TP transaction including trigger code within a transaction,
+ -ONLINE -ROLLBACK restarts the transaction.
+ o In a non-TP mini-transaction, including within an implicit transaction
+ caused by a trigger, -ONLINE -ROLLBACK produces a DBROLLEDBACK error,
+ which, in turn, invokes the error trap if $ETRAP or $ZTRAP are in
+ effect.
+
+ Any utility/command attempted while MUPIP JOURNAL -ONLINE -ROLLBACK
+ operates waits for ROLLBACK to complete; the $gtm_db_startup_max_wait
+ environment variable configures the wait period.
+
+ **Note**
+
+ Because MUPIP ROLLBACK -ONLINE can take a database backwards in state
+ space, please make sure that you understand what it is that you intend it
+ to do when you invoke it. FIS developed it as a step towards a much larger
+ project and anticipates that it will not be broadly useful as is.
+
+ -ROLLBACK -BACKWARD exits with an error message for following conditions:
+
+ 1. Any database region corresponding to a journal file processed has
+ replication state turned OFF. Note that, a configuration where there
+ are replicated regions and at least one non-replicated-but-journaled
+ region is not permitted by the replication source server. The source
+ server errors out at startup on such a configuration without having
+ set up the journal pool. Since all GT.M updates to replicated regions
+ need the source server to have set up a journal pool, no updates are
+ possible until the configuration is changed to have only replicated
+ regions or non-replicated-and-non-journaled regions.
+ 2. Any database region corresponding to a journal file identified by the
+ command argument has journaling state DISABLE'd or ENABLE'd and OFF.
+ 3. Any database region corresponding to a journal file has journal state
+ ENABLE'd and ON, but the journal file name specified in the database
+ file header is different than one identified by the command argument.
+
+ If a transaction is found with incomplete fence, it is considered broken.
+ For the duration of the rollback, replication is turned OFF on all regions
+ and turned back ON at the end of the rollback.
+
+ During the forward phase of rollback, if a complete transaction (fenced or
+ unfenced) is found after a broken transaction, it is considered as a lost
+ transaction. During forward phase of rollback, MUPIP journals the logical
+ updates to the database. All broken and lost transactions are made
+ available as a result of the rollback. These are written as journal
+ extract format in two different text files.
+
+ When a database file is rolled back by -ROLLBACK, the corresponding
+ journal file is also rolled back so that the two are synchronized.
+ -ROLLBACK then creates a new journal file. If no forward play of journal
+ records is necessary, the newly created journal file is empty and the
+ database points to the new journal file. The journal
+ allocation/extension/autoswitchlimit values in the new journal file is set
+ in the way as described for -RECOVER -BACKWARD in the previous section
+ under -RECOVER.
+
+ A prefix rolled_bak_ is added to the journal file, whose entire contents
+ are eliminated by a -ROLLBACK. These files are not used by GT.M after the
+ MUPIP JOURNAL -RECOVER, and can be moved/deleted as needed.
+
+ For -ROLLBACK the target database file should be the same as when GT.M
+ wrote the last complete transaction to the journal.
+
+ If the -FETCHRESYNC or -RESYNC qualifiers are not specified, MUPIP does an
+ optimal rollback (that is, check whether the database is in a wholesome
+ state and attempt to automatically recover a database if there is a
+ crash).
+
+ **Note**
+
+ If ROLLBACK (either -NOONLINE or -ONLINE) terminates abnormally (say
+ because of a kill -9), it leaves the database in a potentially
+ inconsistent state indicated by the FILE corrupt field in the database
+ file header. When a ROLLBACK terminates leaving this field set, all other
+ processes receive DBFLCORRP errors any time they attempt to interact with
+ the database. You can clear this condition as following in descending
+ order of risk:
+
+ o Rerun ROLLBACK to completion
+ o MUPIP SET -FILE -PARTIAL_RECOV_BYPASS
+ o DSE CHANGE -FILEHEADER -CORRUPT=FALSE -NOCRIT
+
+ However, the MUPIP and DSE actions do not ensure that the database has
+ consistent state; check for database integrity with MUPIP INTEG.
+
+4 SHow
+ SHow
+
+ Specifies which information for the JOURNAL command to display about a
+ journal file.
+
+ Use -FORWARD with -SHOW together (but without -RECOVER ) to process the
+ entire journal file. Specify -SHOW with -RECOVER (or -ROLLBACK) to
+ consider all the journal files/records processed during a -RECOVER
+ -FORWARD command or forward phase of a -RECOVER (or -ROLLBACK) -BACKWARD
+ command. Without -RECOVER (or -ROLLBACK), -SHOW does not require database
+ access.
+
+ The show-option-list includes (these are not case-sensitive):
+
+ o AL[L]
+
+ Displays all the available type of information about the journal file.
+ ALL is the default if you omits the show-option-list.
+
+ o AC[TIVE_PROCESSES]
+
+ Displays all processes active at the end of the period specified
+ implicitly or explicitly by the JOURNAL command time qualifiers.
+
+ o B[ROKEN_TRANSACTIONS]
+
+ Display all processes that had incomplete fenced transactions at the
+ end of the period covered by the JOURNAL command.
+
+ o H[EADER]
+
+ Displays the journal file header information. If the MUPIP JOURNAL
+ command includes only the -SHOW=HEADER action qualifier, GT.M
+ processes only the journal file header (not the contents) even if you
+ specify -BACKWARD or -FORWARD with it. The size of a journal file
+ header is 64K.
+
+ HEADER displays almost all the fields in the journal file header. The
+ NODE field is printed up to a maximum of the first 12 characters. The
+ following is an example of SHOW=HEADER output:
+
+ -------------------------------------------------------------------------------
+ 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
+ Journal file checksum seed 2272485152 [0x87735F20]
+ Crash FALSE
+ Recover interrupted FALSE
+ Journal file encrypted FALSE
+ Journal file hash 00000000000000000000000000000000000
+ Blocks to Upgrade Adjustment 0 [0x00000000]
+ End of Data 65960 [0x000101A8]
+ Prev Recovery End of Data 0 [0x00000000]
+ Endian Format LITTLE
+ Journal Creation Time 2012/11/06 17:30:33
+ Time of last update 2012/11/06 17:30:33
+ Begin Transaction 1 [0x0000000000000001]
+ End Transaction 1 [0x0000000000000001]
+ Align size 2097152 [0x00200000] bytes
+ Epoch Interval 300
+ Replication State CLOSED
+ Jnlfile SwitchLimit 8386560 [0x007FF800] blocks
+ Jnlfile Allocation 2048 [0x00000800] blocks
+ Jnlfile Extension 2048 [0x00000800] blocks
+ Maximum Journal Record Length 1048672 [0x00100060]
+ Turn Around Point Offset 0 [0x00000000]
+ 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
+
+ o P[ROCESSES]
+
+ Displays all processes active during the period specified implicitly
+ or explicitly by the JOURNAL command time qualifiers.
+
+ o S[TATISTICS]
+
+ Displays a count of all journal record types processed during the
+ period specified implicitly or explicitly by the JOURNAL command time
+ qualifiers.The following is an example of SHOW=STATISTICS output:
+
+ -------------------------------------------------------------------------------
+ SHOW output for journal file /home/jdoe/.fis-gtm/V6.0-000_x86/g/gtm.mjl
+ -------------------------------------------------------------------------------
+
+ Record type Count
+ ----------------------
+ *BAD* 0
+ PINI 2
+ PFIN 2
+ ZTCOM 0
+ KILL 1333533
+ FKILL 0
+ GKILL 0
+ SET 0
+ FSET 0
+ GSET 0
+ PBLK 4339
+ EPOCH 2
+ EOF 1
+ TKILL 0
+ UKILL 0
+ TSET 0
+ USET 0
+ TCOM 0
+ ALIGN 49
+ NULL 0
+ ZKILL 0
+ FZKIL 0
+ GZKIL 0
+ TZKIL 0
+ UZKIL 0
+ INCTN 4314
+ AIMG 0
+ TZTWO 0
+ UZTWO 0
+ 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
+
+ The following example displays the cryptographic hash of the symmetric key
+ 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
+ 0FDF04C8ECE52A4261975B89A2
+
+4 Verify
+ Verify
+
+ Verifies a journal file for integrity. This qualifier cannot have a value.
+ -VERIFY scans the files and checks if it is in legal form, if not, it
+ terminates without affecting the database files.
+
+ -VERIFY when specified along with -FORWARD verifies the entire journal
+ file For -NOVERIFY -FORWARD, only the tail of a journal file is verified
+ for cross region integrity. In both cases, if -RECOVER is also specified,
+ the forward play of journal records is done in a separate pass only after
+ the verification pass is complete and error-free.
+
+ -VERIFY along with -BACKWARD verifies all journal records from the end of
+ the journal file till the turn around point. When -VERIFY -BACKWARD is
+ specified along with -RECOVER or -ROLLBACK, backward processing involves
+ two passes, the first pass to do the verification until the turn around
+ point, and the second pass to apply before image (PBLK) records.
+
+ When -NOVERIFY -BACKWARD is specified along with -RECOVER or -ROLLBACK,
+ PBLKs are applied to the database in the same pass as the verification.
+ This speeds up processing. But the disadvantage of this approach is that
+ in the event of verification terminating in the middle of backward
+ processing, there is no protection of cross-region integrity. FIS
+ recommends the use of -VERIFY with -RECOVER or -ROLLBACK.
+
+ When used independent of -RECOVER (or -ROLLBACK), -[NO]VERIFY option does
+ not need database access. The default is -VERIFY.
+
+3 Direction_Qualifiers
+ Direction Qualifiers
+
+ The following two qualifiers control the journal processing direction:
+
+ -BACKWARD
+
+ Specifies that MUPIP JOURNAL processing should proceed from the end of the
+ journal file. If the actions include -RECOVER, JOURNAL -BACKWARD restores
+ before-images from the end-of the file back to an explicitly or implicitly
+ specified point (the turn around point), before it reverses and processes
+ database updates in the forward direction (the forward phase).
+
+ **Note**
+
+ -BACKWARD is incompatible with -FORWARD.
+
+ -FO[RWARD]
+
+ Specifies that MUPIP JOURNAL processing for the specified action qualifier
+ should proceed from the beginning of the given journal file. When
+ processing a -RECOVER action qualifier, in certain cases, MUPIP JOURNAL
+ may need to go before the first record of the specified journal file, that
+ is, it can start from a previous generation journal file.
+
+ If multiple journal files are specified in the command line, -FORWARD
+ sorts the journal files within each region based on creation time and
+ processes them starting from the earliest journal file. Unless the
+ -NOCHECKTN qualifier is specified, -FORWARD performs checks on journal
+ files corresponding to each region to ensure they are contiguous, both in
+ terms of time span, as well as, transaction number span. -FORWARD errors
+ out if it detects a discontinuity.
+
+ **Note**
+
+ -FORWARD is incompatible with -BACKWARD and -ROLLBACK.
+
+3 Time_Qualifiers
+ Time Qualifiers
+
+ Journal qualifiers specifying time accept arguments in absolute or delta
+ time format. Enclose time arguments in quotation marks (" ") . Include a
+ back-slash (\) delimiter before both, the beginning and ending quotation
+ marks to escape it from being processed by the UNIX shell.
+
+ Absolute format is day-mon-yyyy hh:mm:ss , where day denotes the date of
+ the month, mon indicates the abbreviated 3-letter month name (for example,
+ Jan, Feb,..) and the year yyyy and hour hh are separated by a space.
+ Absolute time may indicate today's date with "-- " before the hours.
+
+ Delta format is day hh:mm:ss, indicating the number of days, hours,
+ minutes, and seconds; where the day and the hours (hh) are separated by a
+ space. If delta time is less than a day, it must start with zero (0)
+ followed by a space.
+
+ Delta time is always relative to the maximum time of the last record in
+ all journal files specified by arguments to the MUPIP JOURNAL command.
+
+ **Note**
+
+ All time qualifiers are incompatible with -ROLLBACK.
+
+ The following section describes the time qualifiers in more detail:
+
+ -A[FTER]=time
+
+ Specifies reference time stamps in the journal and identifies the point
+ after which JOURNAL starts processing in the journal file(s). This time
+ qualifier applies to -FORWARD only.
+
+ If -AFTER= provides a time following the last time recorded in the journal
+ file or following any -BEFORE= time, JOURNAL processing produces no result
+ and a warning message is displayed. If -AFTER provides a time preceding
+ the first time recorded in the journal file specified in the command line,
+ and, previous generation journal file(s) exists for that journal file,
+ then previous generation journal file(s) are not included for the
+ processing. You must specify previous generation journal files explicitly
+ in the command line in order for them to be considered.
+
+ Using -BEFORE with -AFTER restricts processing to a particular period of
+ time in the journal file.
+
+ -BE[FORE]=time
+
+ Specifies an ending time for any action -FORWARD or -BACKWARD. The time
+ specified references time stamps in the journal files. If -BEFORE=
+ specifies a time preceding the first time recorded in the journal file, or
+ preceding any -AFTER= or -SINCE= time, JOURNAL processing produces no
+ result, and a warning message is displayed.
+
+ If -BEFORE= time exceeds the last time recorded in journal files, JOURNAL
+ processing effectively ignores the qualifier and terminates at the end of
+ the journal file. By default, JOURNAL processing terminates a t the end of
+ the journal file.
+
+ -[NO]LOO[KBACK_LIMIT][=lookback-option-list]
+
+ Specifies how far JOURNAL -BACKWARD processes past the turnaround point
+ (the explicit or implicit point in journal file up to which -RECOVER
+ proceeds backward before it reverses and processes database in forward
+ direction), while attempting to resolve open transaction fences. This
+ option is applicable only for transactions fenced with ZTSTART and
+ ZTCOMMIT. For transaction fenced with TSTART and TCOMMIT, -RECOVER always
+ resolves open transaction fences.
+
+ -LOOKBACK_LIMIT=options, include time and transaction counts.
+ -NOLOOKBACK_LIMIT specifies that JOURNAL -BACKWARD can process all the way
+ to the beginning of the journal file, if necessary, to resolve open
+ transaction fences. -LOOKBACK_LIMIT= is incompatible with -FORWARD.
+
+ When -FENCES=NONE, JOURNAL processing ignores -LOOKBACK_LIMIT.
+
+ The -LOOKBACK_LIMIT options are:
+
+ o TIME=time
+
+ This limits LOOKBACK by a specified amount of delta or absolute
+ journal time.
+
+ o OPERATIONS=integer
+
+ This limits LOOKBACK to the specified number of database transactions.
+
+ The TIME LOOKBACK option name and its value must be enclosed in quotes
+ ("").
+
+ For example:
+
+ -lookback=\"time=0 00:00:30\"
+
+ When -LOOKBACK_LIMIT= specifies both options, they must be separated by a
+ comma (,), for example:
+
+ -lookback=\"time=0 00:00:30,operations=35\"
+
+ When -LOOKBACK_LIMIT= specifies both options, the first limit reached
+ terminates the LOOKBACK.
+
+ By default, MUPIP JOURNAL uses -LOOKBACK_LIMIT=\"TIME=0 00:05\" providing
+ five minutes of journal time prior to -SINCE= to resolve open fences. A
+ -LOOKBACK_LIMIT that specifies a limit much before the beginning of the
+ earliest journal file acts as if -NOLOOKBACK_LIMIT was specified.
+
+ -SI[NCE]=time
+
+ Specifies a starting (or checkpoint) time for an action qualifier with
+ -BACKWARD, that is, -SINCE specifies how far back in time JOURNAL
+ -BACKWARD should process (from the end of the journal file), before
+ starting the forward processing.
+
+ The time specified references time stamps in the journal files. If there
+ are open fenced transactions when JOURNAL -BACKWARD locates the -SINCE=
+ time, it continues processing backward to resolve them, unless the command
+ also specifies -FENCES=NONE. If -SINCE= time exceeds the last time
+ recorded in the journal files or, follows any -BEFORE=time, JOURNAL
+ processing effectively ignores the qualifier, and displays a warning
+ message.
+
+ By default, -SINCE= time is 0 00:00:00 which denotes the time at the end
+ of the journal file (the time when the last journal record was updated).
+
+3 SEQNO_Qualifiers
+ SEQNO Qualifiers
+
+ These qualifiers are compatible only with -ROLLBACK.
+
+ -FET[CHRESYNC]=<port number>
+
+ In an LMS configuration, rollbacks the replicating instance to a common
+ synchronization point from which the originating instance can transmit
+ updates to allow it to catch up. This command rolls back a former
+ originating instance to the journal sequence number at which the current
+ originating instance took over. The format of the fetchresync qualifier
+ is:
+
+ -fetchresync=<port number> -losttrans=<extract file> file-list
+
+ The <port number> is the communication port number that the rollback
+ command uses when fetching the reference point. Always use the same <port
+ number> on the originating instance for rollback as the one used by the
+ Receiver Server.
+
+ **Important**
+
+ FIS recommends you to unconditionally script the mupip journal -rollback
+ -fetchresync command prior to starting any Source Server on the
+ replicating instance to avoid a possible out-of-sync situation.
+
+ The reference point sent by the originating instance is the RESYNC_SEQNO
+ (explained later) that the originating instance once maintained. The
+ database/journal files are rolled back to the earlier RESYNC_SEQNO (that
+ is, the one received from originating instance or the one maintained
+ locally). If you do not use -fetchresync, the database rolls back to the
+ last consistent replicating instance state.
+
+ The system stores extracted lost transactions in the file <extract file>
+ specified by this mandatory qualifier. The starting point for the search
+ for lost transactions is the JNL_SEQNO obtained from the originating
+ instance in the -fetchresync operation. If -fetchresync is not specified,
+ <extract file> lists the post-consistent-state transactions that were
+ undone by the rollback procedure to reach a consistent state.
+
+ **Note**
+
+ The extracted lost transactions list may contain broken transactions due
+ to system failures that occurred during processing. Do not resolve these
+ transactions --they are not considered to be committed.
+
+ **Caution**
+
+ The database header may get corrupted if you suspend an ongoing ROLLBACK
+ -FETECHRESYNC operation or if the TCP connection between the two instances
+ gets broken. The workaround is to restart the ROLLBACK -FETCHRESYNC
+ operation or wait 60 seconds for the FETCHRESYNC operation to timeout.
+
+ Example:
+
+ $ mupip journal -rollback -fetchresync=2299 -losttrans="glo.lost" -backward
+
+ This command performs a ROLLBACK -FETCHRESYNC operation on a replicating
+ instance to bring it to a common synchronization point from where the
+ originating instance can begin to transmit updates to allow it to catch
+ up. It also generates a lost transaction file glo.lost of all those
+ transactions that are present on the replicating instance but not on the
+ originating instance at port 2299.
+
+ -RES[YNC]=<journal sequence number>
+
+ Specifies the journal sequence number to which GT.M must rollback the the
+ database/journal files need to be rolled back to a specific point. If you
+ specify a journal sequence number that is greater than the last consistent
+ state, GT.M rolls back the database/journal files to the last consistent
+ state. Under normal operating conditions, this qualifier is not needed.
+
+3 Control_Qualifiers
+ Control Qualifiers
+
+ The following qualifiers control journal processing:
+
+ -[NO]AP[PLY_AFTER_IMAGE]
+
+ Specifies that after image records (AIMG) be applied to the database as
+ part of forward processing of backward recovery or rollback. AIMG are
+ "snapshots" of the database updates captured by GTM immediately after the
+ change caused by a DSE update. By default, during forward phase of
+ backward recovery or rollback, AIMG records are applied to the database.
+
+ By default, -RECOVER -FORWARD does not apply AIMG record into the
+ database. -APPLY_AFTER_IMAGE is compatible with -RECOVER, or -ROLLBACK
+ action qualifiers only.
+
+ -BR[OKENTRANS]=<extract file>
+
+ -BROKENTRANS is an optional qualifier for -ROLLBACK, -RECOVER and
+ -EXTRACT. If this is not specified and a broken transaction file creation
+ is necessary, MUPIP JOURNAL creates one using the name of the current
+ journal file being processed with a .broken extension.
+
+ Note that, if selection qualifiers are specified, the broken transaction
+ determination (and therefore lost transaction determination as well) is
+ done based on the journal file that is filtered by the selection
+ qualifiers. This means that a transaction's journal records may be
+ considered complete or broken or lost, depending on the nature of the
+ selection qualifiers. Using -FENCES=NONE along with the selection
+ qualifiers will result in every journal record to be considered complete
+ and hence prevent broken or lost transaction processing.
+
+ -[NO]CHA[IN]
+
+ -CHAIN allows JOURNAL processing to include previous generations of
+ journal files with -FORWARD. If JOURNAL -RECOVER needs to process previous
+ generation journal file(s) and -NOCHAIN is specified, MUPIP JOURNAL exits
+ with an error.
+
+ -CHAIN is the default.
+
+ -[NO]CHE[CKTN]
+
+ -CHECKTN specifies that JOURNAL -FORWARD must verify for each region that
+ the begin transaction number of the earliest journal file to be processed
+ for that region is same as the current transaction in the database file
+ and that the end transaction number of every journal file is equal to the
+ the begin transaction number of the next generation journal file for a
+ given region. By default, -FORWARD uses -CHECKTN.
+
+ -NOCHECKTN forces forward recovery by overriding inbuilt mechanisms for
+ checking transaction integrity. Use -NOCHECKTN with caution because it may
+ lead to integrity issues in the recovered database and journal files.
+
+ -CHECKTN is incompatible with -BACKWARD and -ROLLBACK.
+
+ -[NO]ER[ROR_LIMIT][=integer]
+
+ Specifies the number of errors that MUPIP JOURNAL processing accepts. When
+ the number of errors exceeds the -ERROR_LIMIT, the -INTERACTIVE qualifier
+ determines whether JOURNAL processing halts or defers to the operator.
+ -NOERROR_LIMIT prevents MUPIP JOURNAL from stopping because of errors.
+ Journal processing continues until it reaches the end of the journal file,
+ regardless of the number of errors.
+
+ Note that, -NOERROR_LIMIT is not the same as -ERROR_LIMIT=0.
+
+ By default, MUPIP JOURNAL uses -ERROR_LIMIT=0, causing the first error to
+ initiate the appropriate error action. In case of a crash there could be
+ some incomplete journal records at the end of a journal file. MUPIP
+ JOURNAL does not consider these as errors. In addition, fenced
+ transactions that are broken are not considered as errors.
+
+ During the forward phase of recovery, if a broken transaction is found,
+ all the logical records processed afterwards are considered suspect. If a
+ complete transaction is found after any broken transactions, MUPIP JOURNAL
+ -RECOVER increments the error count and, if it is less than the error
+ limit, it is applied to the database. Otherwise, it is treated as a lost
+ transaction and extracted. If a complete transaction is found after any
+ broken transactions, MUPIP JOURNAL -ROLLBACK treats it as a lost
+ transaction and extracts it irrespective of the error limit.
+
+ If MUPIP JOURNAL needs to increment error count during its processing, a
+ warning message is issued for every error encountered except in the
+ following cases when the error count is incremented but no warning message
+ is displayed:
+
+ o When a complete transaction is found after a broken transaction
+ o When -EXTRACT -FULL encounters errors
+
+ If MUPIP JOURNAL completes successfully with a non-zero value of error
+ count, the return status is not a success, but a warning.
+
+ -FE[NCES][=fence-option]
+
+ Specifies how JOURNAL processes fenced transactions. Fenced transactions
+ are logical transactions made up of database updates preceded by a TSTART
+ or ZTSTART command and followed, respectively, by a TCOMMIT or ZTCOMMIT
+ command. All updates between a TSTART or ZTSTART and a TCOMMIT or ZTCOMMIT
+ are designed to occur together so that after journal recovery the database
+ contains either all the updates corresponding to a fenced transaction, or
+ none of them.
+
+ The argument values for -FENCES option for MUPIP -RECOVER are not
+ case-sensitive.
+
+ The fence options are:
+
+ o NONE
+
+ This causes MUPIP JOURNAL to apply all individual updates as if
+ transaction fences did not exist. Note that, this means a SET/KILL
+ within a TP or ZTP transaction would be played as if it was an
+ unfenced SET/KILL. This may cause the database and new journals
+ created (if -BACKWARD is specified), to be different from the state
+ before the recovery took place.
+
+ o ALWAYS
+
+ This causes MUPIP JOURNAL to treat any unfenced or improperly fenced
+ updates as broken transactions.
+
+ o PROCESS
+
+ This causes MUPIP JOURNAL to accept unfenced database updates, and
+ also to observe fences when they appear, generating broken transaction
+ files in the case of a TSTART with no corresponding TCOMMIT, or a
+ ZTSTART with no corresponding ZTCOMMIT. It also generates broken
+ transactions if a multi-region transaction with TSTART and TCOMMIT
+ expects N regions to participate, but the number of TSTART/TCOMMIT
+ pairs found is less than N. The same happens for multi-region ZTSTART
+ and ZTCOMMIT.
+
+ By default, MUPIP JOURNAL uses -FENCES=PROCESS.
+
+ -FU[LL]
+
+ -FULL when used with -EXTRACT, specifies that all journal records be
+ extracted. A journal file's contents can be rolled back in case of
+ backward recovery or rollback in order to keep the database and journal in
+ sync. This is achieved not by truncating the contents of the journal file
+ but instead setting a field in the journal file header, which shows up as
+ "Prev Recovery End of Data" in a MUPIP JOURNAL -SHOW=HEADER output, to
+ indicate the end of the journal file before rolling back and setting
+ another field in the file header to indicate the new end of the journal
+ file (this field shows up as "End of Data" in a MUPIP JOURNAL -SHOW=HEADER
+ output). Once a journal file's contents are rolled back, all future MUPIP
+ JOURNAL commands (including -EXTRACT) operate on the rolled back journal
+ file only. But if -FULL is specified along with -EXTRACT, the entire
+ journal file contents (including those records that were rolled back) are
+ extracted. This qualifier is to be used only as a diagnostic tool and not
+ in normal operation.
+
+ -FULL qualifier is compatible with -EXTRACT only.
+
+ -[NO]IN[TERACTIVE]
+
+ Specifies whether, for each error over the -ERROR_LIMIT, JOURNAL
+ processing prompts the invoking operator for a response to control
+ continuation of processing. If the operator responds that processing
+ should not continue, the MUPIP JOURNAL command terminates.
+
+ -NOINTERACTIVE terminates the journal processing as soon as the MUPIP
+ JOURNAL command generates the number of errors specified in -ERROR_LIMIT.
+
+ This qualifier is applicable only to interactive mode or terminal mode.
+ The default is -INTERACTIVE.
+
+ -LOST[TRANS]=<extract file>
+
+ -LOSTTRANS is an optional qualifier for -RECOVER, -ROLLBACK and -EXTRACT.
+ If this is not specified and a lost transaction file creation is
+ necessary, MUPIP JOURNAL creates one using the name of the current journal
+ file being processed with a .lost extension.
+
+ Any complete transactions after a broken transaction is considered a lost
+ transaction. They are written into the lost transaction file. For -RECOVER
+ it might be considered as good transaction and applied to the database, if
+ -ERROR_LIMIT qualifier allows it to do so.
+
+ Note that, if selection qualifiers are specified, the broken transaction
+ determination (and therefore lost transaction determination as well) is
+ done based on the journal file that is filtered by the selection
+ qualifiers. This means that a transaction's journal records may be
+ considered complete or broken or lost, depending on the nature of the
+ selection qualifiers. Using -FENCES=NONE along with the selection
+ qualifiers will result in every journal record to be considered complete
+ and hence prevent broken or lost transaction processing.
+
+ In the case of a replicated database, lost transaction can have an
+ additional cause. If failover occurs (that is, the originating Source
+ Server, A, fails and the replicating Source Server, B, assumes the
+ originating instance's role), some transactions committed to A's database
+ may not be reflected in B's database. Before the former originating
+ instance becomes the new replicating instance, these transactions must be
+ rolled back. These transactions are known as "lost transactions". Note
+ that these are complete transactions and different from a broken
+ transaction. MUPIP JOURNAL -ROLLBACK stores extracted lost transactions in
+ the extract-file specified by this qualifier. The starting point for the
+ search for lost transactions is the journal sequence number obtained from
+ the originating Source Server in the -FETCHRESYNC operation.
+
+ -RED[IRECT]=file-pair-list
+
+ Replays the journal file to a database different than the one for which it
+ was created. Use -REDIRECT to create or maintain databases for training or
+ testing.
+
+ This qualifier applies to -RECOVER action and -FORWARD direction qualifier
+ only. JOURNAL rejects -REDIRECT unless it appears with -RECOVER.
+
+ The file-pair-list consists of one or more pairs of file-names enclosed in
+ parentheses () and separated by commas (,). The pairs are separated by an
+ equal sign in the form:
+
+ old-file-name=new-file-name
+
+ where the old file-name identifies the original database file and the new
+ file-specification file-name identifies the target of the -RECOVER. The
+ old-file-specification can always be determined using -SHOW.
+
+ By default, JOURNAL directs -RECOVER to the database file from which the
+ journal was made. -REDIRECT is not compatible with -ROLLBACK.
+
+ Example:
+
+ $ mupip journal -recover -forward -redirect="bgdbb.dat=test.dat" bgdbb.mjl
+
+ This JOURNAL command does a forward recovery that -REDIRECTs the updates
+ in bgdbb.mjl from bgdbb.dat to test.dat.
+
+ -VERB[OSE]
+
+ Prints verbose output in the course of processing. It is not negatable and
+ it is set to OFF by default.
+
+3 Selection_Qualifiers
+ Selection Qualifiers
+
+ Journal Selection Qualifiers are compatible with -EXTRACT and -SHOW
+ operations only. This is because most applications are not constructed to
+ safely remove a subset of transactions based on criteria that is exterior
+ to the application design. To exclude transactions from a recovery based
+ on some selection criteria, the methodology is to -EXTRACT the records,
+ and then reapply them through application logic rather than by journal
+ recovery. This approach permits the application logic to appropriately
+ handle any interactions between the removed and the retained transactions.
+ Note that, selection qualifiers might result in only a subset of a fenced
+ transaction's journal records to be extracted (for example, a TSTART
+ record may not be extracted because the first update in that transaction
+ was filtered out by a selection qualifier, while the corresponding TCOMMIT
+ record may get extracted). This can cause a fenced transaction to seem
+ broken when actually it is not.
+
+ The following qualifiers control the selection criteria for journal
+ processing.
+
+ Except for -TRANSACTION, all qualifiers allow for specifying a comma (,)
+ seperated list of values.
+
+ -G[LOBAL]=global-list
+
+ Specifies globals for MUPIP JOURNAL to include or exclude from processing.
+ You might find this qualifier useful for extracting and analyzing specific
+ data.
+
+ The global-list contains one or more global-names (without subscripts)
+ preceded by a caret symbol (^). To include more than one global use one of
+ the following syntaxes.
+
+ $ mupip journal -forward -extract -global="^A*,^C" mumps.mjl
+
+ or
+
+ $ mupip journal -forward -extract -global="(^A*,^C)" mumps.mjl
+
+ The names may include the asterisk (*) wildcard. That is, -GLOBAL="^A*"
+ selects all global variables with names starting with A. The entire list
+ or each name may optionally be preceded by a tilda sign (~), requiring
+ JOURNAL to exclude database updates to the specified global(s). When the
+ global-list with a MUPIP JOURNAL -GLOBAL does not start with a tilda sign
+ (~), JOURNAL processes only the explicitly named globals. By default,
+ JOURNAL processes all globals.
+
+ To specify subscripts, using -GLOBAL="^A(1)" results in all keys under the
+ ^A(1) tree to be included, that is, it is equivalent to using
+ -GLOBAL="^A(1,*)". An asterisk (*) or a percent (%) anywhere in the global
+ specification is permitted. Percent (%) matches any character, and
+ asterisk (*) matches any string (possibly zero length too). The asterisk
+ (*) or percent (%) specification can be used for -USER qualifier too.
+
+ Example:
+
+ To extract all ^GBL* except for ^GBLTMP:
+
+ $ mupip journal -extract -global="^GBL*,~^GBLTMP" -forward mumps.mjl
+
+ To extract all ^GBL except for ^GBL(1,"TMP"):
+
+ $ mupip journal -extract -global=\"^GBL,~^GBL\(1,\"\"TMP\"\"\)\" -forward mumps.mjl
+
+ The backslash (\) delimiter characters are required in UNIX to pass MUPIP
+ the double quotes (") of the string subscript.
+
+ An INVGLOBALQUAL error is issued along with the error offset in the
+ command line, whenever a parse error of the global qualifier string is
+ encountered.
+
+ -ID=pid-list
+
+ Specifies that JOURNAL processing include or exclude database updates
+ generated by one or more processes, identified by process identification
+ numbers (PIDs). The entire list or each PID may optionally be preceded by
+ a tilda sign (~), requiring JOURNAL to exclude database updates initiated
+ by the specified PID. You may use this qualifier for trouble shooting or
+ analyzing data.
+
+ By default, JOURNAL processes database updates regardless of the PID that
+ initiated it.
+
+ -T[RANSACTION]=transaction-type
+
+ Specifies transaction-types for JOURNAL to include or exclude from
+ processing. For example, you may use this qualifier to report only on KILL
+ operations to locate possible causes for missing data.
+
+ The transaction-types are SET and KILL and can be negated. These types
+ correspond to the M commands of the same names. When the transaction-type
+ with a JOURNAL -TRANSACTION is not negated, JOURNAL processes only
+ transactions of the type named (for example, -TRANSACTION=KILL), whereas
+ if it is negated, JOURNAL does not process transactions of the type named
+ (for exmaple, -TRANSACTION=NOKILL).
+
+ By default, JOURNAL processes transactions, regardless of its type.
+
+ -U[SER]=user-list
+
+ Specifies that MUPIP JOURNAL processing include or exclude database
+ updates generated by one or more users. You can use this qualifier to
+ audit the actions of a particular user. The user-list contains names of
+ one or more users. Indicate multiple users by separating the names with
+ commas (,). The names may include the wildcard asterisk (*). The entire
+ list or each name may optionally be preceded by a minus sign (-) tilda
+ sign (~), requiring JOURNAL to exclude database updates initiated by the
+ specified user(s). When the user-list with a JOURNAL -USER does not start
+ with a tilda sign (~), JOURNAL processes only those database updates,
+ which are generated by explicitly named users. The asterisk (*) or percent
+ (%) specification can be used for -USER qualifier. Percent (%) matches any
+ character, and asterisk (*) matches any string (possibly zero length too).
+
+ By default, JOURNAL processes database updates regardless of the user who
+ initiated them.
+
+2 Extract_Formats
+ Extract Formats
+
+ Journal EXTRACT files always start with a label. For the current release
+ of GT.M, the label is GDSJEX06 for a simple journal extract file. This
+ label is necessary to identify the format of the file.
+
+ If the environment variable gtm_chset is set of UTF-8, then file format
+ label is followed by another label called "UTF-8" to indicate UTF-8 mode.
+
+ After this label, the journal record extracts follow. These journal record
+ extracts include fields or pieces delimited by a back slash (\).
+
+ The first piece of an -EXTRACT output record contains a two-digit decimal
+ transaction record type (for example, 01 for a process initialization
+ record). The second piece contains the full date and time of the
+ operation, represented in the $HOROLOG format. The third piece contains a
+ GT.M assigned number (database transaction number) which uniquely
+ identifies the transaction within the time covered by the journal file.
+ The fourth piece contains the process ID (PID) of the process that
+ performed the operation, represented as a decimal number. The remainder of
+ the record depends on the record type.
+
+ Records of type SET, KILL, ZKILL, TSTART, and TCOMMIT include the
+ token_seq as part of the output. It is the sixth field in the output of
+ the journal record extract. When replication is in use, token_seq is a
+ journal sequence number (jsnum) that uniquely identifies each transaction.
+ When replication is not in use and the transaction is a TP or ZTP
+ transaction, token_seq is an 8-byte token that uniquely identifies the
+ entire TP or ZTP transaction. For non-replicated, non-TP, and non-ZTP
+ journal records, token_seq has a zero (0) value.
+
+ The format of the plain journal extract is as follows:
+
+ NULL 00\time\tnum\pid\clntpid\jsnum\strm_num\strm_seq
+ PINI(U) 01\time\tnum\pid\nnam\unam\term\clntpid\clntnnam\clntunam\clntterm
+ PINI(V) 01\time\tnum\pid\nnam\unam\term\mode\logintime\image_count\pname\clntpid\clntnnam\clntunam\clntterm\clntmode\clntlogintime\clntimage_count\clntpname
+ PFIN 02\time\tnum\pid\clntpid
+ EOF 03\time\tnum\pid\clntpid\jsnum
+ KILL 04\time\tnum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node
+ SET 05\time\tnum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node=sarg
+ ZTSTART 06\time\tnum\pid\clntpid\token
+ ZTCOM 07\time\tnum\pid\clntpid\token\partners
+ TSTART 08\time\tnum\pid\clntpid\token_seq\strm_num\strm_seq
+ TCOM 09\time\tnum\pid\clntpid\token_seq\strm_num\strm_seq\partners\tid
+ ZKILL 10\time\tnum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node
+ ZTWORM 11\time\tnum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\ztwormhole
+ ZTRIG 12\time\tnum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node
+
+ where:
+
+ 01 record indicates a process/image-initiated update (PINI) into the
+ current journal file for the first time.
+
+ 02 record indicates a process/image dropped interest (PFIN) in the current
+ journal file.
+
+ 03 record indicates all GT.M images dropped interest in this journal file
+ and the journal file was closed normally.
+
+ 04 record indicates a database update caused by a KILL command.
+
+ 05 record indicates a database update caused by a SET command.
+
+ 06 record indicates a ZTSTART command.
+
+ 07 record indicates a ZTCOMMIT command.
+
+ 08 record indicates a TSTART command.
+
+ 09 record indicates a TCOMMIT command.
+
+ 10 record indicates a database update caused by a ZKILL command.
+
+ 11 records indicates a value for/from $ZTWORMHOLE (when replication is
+ turned on).
+
+ 12 record indicates a ZTRIGGER command.
+
+ Journal extracts contain NULL records only in a multisite replication
+ configuration where triggers or external M-filters are active. Here are
+ two examples when NULL records are sent to the journal files:
+
+ o An external filter on an instance transforms a SET record to a NULL
+ record that has a different schema.
+ o If the source side has triggers enabled and its receiver side either
+ runs a pre-trigger version of GT.M or runs on a platform where
+ triggers are not supported (for example, AXP VMS or HPUX HPPA),
+ trigger definition journal records from the source side are
+ transformed to NULL records on the receiver side.
+
+ **Important**
+
+ A NULL record does not have global information. Therefore, it resides in
+ the alphabetically last replicated region of the global directory.
+
+ The format of the detail journal extract is as follows:
+
+ PINI(U) time\tnum\chksum\pid\nnam\unam\term\clntpid\clntnnam\clntunam\clntterm
+ PINI(V) time\tnum\chksum\pid\nnam\unam\term\mode\logintime\image_count\pname\clntpid\clntnnam\clntunam\clntterm\clntmode\clntlogintime\clntimage_count\clntpname
+ PFIN time\tnum\chksum\pid\clntpid
+ EOF time\tnum\chksum\pid\clntpid\jsnum
+ SET time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node=sarg
+ KILL time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node
+ ZKILL time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node
+ ZTWORM time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\ztwormhole
+ ZTRIG time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node
+ TSTART time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq
+ TSET time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node=sarg
+ TKILL time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node
+ TZKILL time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node
+ TZTWORM time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\ztwormhole
+ TZTRIG time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node
+ USET time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodef
+ lags\node=sarg
+ UKILL time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node
+ UZKILL time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node
+ UZTWORM time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\ztwormhole
+ UZTRIG time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node
+ TCOM time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\partners\tid
+ INCTN time\tnum\chksum\pid\clntpid\opcode\incdetail
+ EPOCH time\tnum\chksum\pid\clntpid\jsnum\blks_to_upgrd\free_blocks\total_blks\fully_upgraded[\strm_num\strm_seq]...
+ PBLK time\tnum\chksum\pid\clntpid\blknum\bsiz\blkhdrtn\ondskbver
+ AIMG time\tnum\chksum\pid\clntpid\blknum\bsiz\blkhdrtn\ondskbver
+ NULL time\tnum\pid\clntpid\jsnum\strm_num\strm_seq
+ ZTSTART time\tnum\chksum\pid\clntpid\token
+ FSET time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node=sarg
+ FKILL time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node
+ FZKILL time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node
+ GSET time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node=sarg
+ GKILL time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node
+ GZKILL time\tnum\chksum\pid\clntpid\token_seq\strm_num\strm_seq\updnum\nodeflags\node
+ ZTCOM time\tnum\chksum\pid\clntpid\token\partners
+ ALIGN time\tnum\chksum\pid\clntpid
+
+ where:
+
+ AIMG records are unique to DSE action and exist because those actions do
+ not have a "logical" representation.
+
+ EPOCH records are status records that record information related to check
+ pointing of the journal.
+
+ NCTN records are the transaction numbers of the sequence of critical
+ sections in which the process and marked the database blocks of the
+ globals as previously used but no longer in use in the bit maps.
+
+ PBLK records are the before image records of the bit maps.
+
+ ALIGN records pad journal records so every alignsize boundary (set with
+ MUPIP SET -JOURNAL and is visible in DSE DUMP -FILEHEADER output) in the
+ journal file starts with a fresh journal record. The sole purpose of these
+ records is to help speed up journal recovery.
+
+ Legend (All hexadecimal fields have a 0x prefix. All numeric fields
+ otherwise are decimal):
+
+ +------------------------------------------------------------------------+
+ | tnum | Transaction number |
+ |----------------+-------------------------------------------------------|
+ | chksum | Checksum for the record. |
+ |----------------+-------------------------------------------------------|
+ | fully_upgraded | 1 if the db was fully upgraded (indicated by a dse |
+ | | dump -file -all) at the time of writing the EPOCH |
+ |----------------+-------------------------------------------------------|
+ | pid | Process id that wrote the jnl record. |
+ |----------------+-------------------------------------------------------|
+ | clntpid | If non-zero, clntpid is the process id of the GT.CM |
+ | | client that initiated this update on the server side. |
+ |----------------+-------------------------------------------------------|
+ | jsnum | Journal sequence number. |
+ |----------------+-------------------------------------------------------|
+ | token | Unique 8-byte token. |
+ |----------------+-------------------------------------------------------|
+ | | If replication is true and this update originated in |
+ | | a non-supplementary instance but was replicated to |
+ | | and updated a supplementary instance, this number is |
+ | | a non-zero value anywhere from 1 to 15 (both |
+ | | inclusive) indicating the non-supplementary stream |
+ | strm_num | number. In all other cases, this stream # value is 0. |
+ | | In case of an EPOCH record, anywhere from 0 to 16 |
+ | | such "strm_num" numbers might be displayed depending |
+ | | on how many sources of supplementary instance |
+ | | replication have replicated to the instance in its |
+ | | lifetime. |
+ |----------------+-------------------------------------------------------|
+ | | If replication is true and this update originated in |
+ | | a non-supplementary instance but was replicated to |
+ | | and updated a supplementary instance, this is the |
+ | | journal sequence number of the update on the |
+ | | originating non-supplementary instance. If |
+ | | replication is true and this update originated in a |
+ | | supplementary instance, this is the journal sequence |
+ | strm_seq | number of the update on the originating supplementary |
+ | | instance. In all other cases, this stream sequence |
+ | | number is 0. Note that the journal seqno is actually |
+ | | 1 more than the most recent update originating on |
+ | | that stream number. In case of an EPOCH record, |
+ | | anywhere from 0 to 16 such "strm_seq" numbers might |
+ | | be displayed depending on how many sources of |
+ | | supplementary instance replication have replicated to |
+ | | the instance in its lifetime. |
+ |----------------+-------------------------------------------------------|
+ | | TRANSACTIONID string (BATCH or any string of |
+ | | descriptive text chosen by the application) specified |
+ | | as an argument of the corresponding TSTART command. |
+ | tid | If TRANSACTIONID is not specified with TSTART, GT.M |
+ | | sets tid to null. TRANSACTIONID can specify any value |
+ | | for tid but affects GT.M behavior only when |
+ | | TRANSACTIONID specifies BATCH or BA. |
+ |----------------+-------------------------------------------------------|
+ | token_seq | If replication is turned on, it is the journal |
+ | | sequence number. If not, it is a unique 8-byte token. |
+ |----------------+-------------------------------------------------------|
+ | | =n where this is the nth update in the TP or ZTP |
+ | updnum | transaction. n=1 for the 1st update etc. 0 for |
+ | | non-TP. |
+ |----------------+-------------------------------------------------------|
+ | | Decimal number interpreted as a binary mask.. |
+ | | Currently only 5 bits are used. |
+ | | |
+ | | o 00001 (1) => update journaled but NOT replicated |
+ | | (For example, update inside a trigger) |
+ | | o 00010 (2) => update to a global that had at least |
+ | | one trigger defined, even if no trigger matched |
+ | | this update |
+ | | o 00100 (4) => $ZTWORMHOLE holds the empty string |
+ | | ("") at the time of this update or was not |
+ | | referenced during this update |
+ | | o 01000 (8) => update did not invoke any triggers |
+ | | even if they existed (For example, MUPIP LOAD) |
+ | | o 10000 (16) => whether the update (set or kill) is |
+ | nodeflags | a duplicate. In case of a KILL, it is a kill of |
+ | | some non-existing node aka duplicate kill. Note |
+ | | that the dupkill occurs only in case of the |
+ | | Update Process. In case of GT.M, the KILL is |
+ | | entirely skipped. In both cases (duplicate set or |
+ | | kill), only a jnl record is written, the db is |
+ | | untouched. |
+ | | |
+ | | Combinations of the above bits would mean each of the |
+ | | individual bit characteristics. For example, 00011 => |
+ | | update within a trigger context, and to a global with |
+ | | at least one trigger defined. For example, 00011 => |
+ | | update inside a trigger and to a global with at least |
+ | | one trigger defined. Certain bit combinations are |
+ | | impossible. For example, 01001 since GT.M replicates |
+ | | any update that does not invoke triggers. |
+ |----------------+-------------------------------------------------------|
+ | node | Key that is being updated in a SET or KILL. |
+ |----------------+-------------------------------------------------------|
+ | sarg | Right-hand side argument to the SET (that is, the |
+ | | value that the key is being SET to). |
+ |----------------+-------------------------------------------------------|
+ | | Number of journaled regions participating in this TP |
+ | partners | or ZTP transaction (TCOM/ZTCOM record written in this |
+ | | TP or ZTP) . |
+ |----------------+-------------------------------------------------------|
+ | opcode | Inctn opcode. See gdsfhead.h inctn_opcode_t for all |
+ | | possible values. |
+ |----------------+-------------------------------------------------------|
+ | blknum | Block number corresponding to a PBLK or AIMG or INCTN |
+ | | record. |
+ |----------------+-------------------------------------------------------|
+ | bsiz | Block size from the header field of a PBLK or AIMG |
+ | | record. |
+ |----------------+-------------------------------------------------------|
+ | blkhdrtn | Transaction number from the block header of a PBLK or |
+ | | AIMG record. |
+ |----------------+-------------------------------------------------------|
+ | ondskbver | On disk block version of this block at the time of |
+ | | writing the PBLK or AIMG record. 0 => V4, 1 => V5. |
+ |----------------+-------------------------------------------------------|
+ | incdetail | 0 if opcode=1,2,3; blks2upgrd if opcode=4,5,6; blknum |
+ | | if opcode=7,8,9,10,11,12,13 |
+ |----------------+-------------------------------------------------------|
+ | ztwormhole | string corresponding to $ZTWORMHOLE |
+ |----------------+-------------------------------------------------------|
+ | blks2upgrd | # of new V4 format bitmap blocks created if |
+ | | opcode=4,5; csd->blks_to_upgrd if opcode=6 |
+ |----------------+-------------------------------------------------------|
+ | uname | Name of the user that wrote this PINI record. |
+ |----------------+-------------------------------------------------------|
+ | clntunam | If non-empty, clntunam is the name of the GT.CM |
+ | | client that initiated this update on the server side. |
+ +------------------------------------------------------------------------+
+
+1 Replication
+ Replication
+
+ The following MUPIP commands and qualifiers control database replication
+ in a GT.M environment.
+
+2 Change_replication_state
+ Change replication state
+
+ Command Syntax:
+
+ mupip set {-file db-file|-region reg-list} -replication={ON|OFF}
+
+ Qualifiers:
+
+ -file and -region
+
+ Use these qualifiers in the same manner that you would use them for a
+ MUPIP SET.
+
+ -replication=replication-state
+
+ Switches the GT.M replication subsystem ON/OFF and possibly modify the
+ current journaling [no-]before image field (which is stored in the
+ database file header).
+
+ replication-state is either of the following keywords:
+
+ OFF
+
+ Disable replication of the database file(s) or region(s). Even if you turn
+ off replication, journaling continues to operate as before.
+
+ **Important**
+
+ GT.M creates a new set of journal files and cuts the back link to the
+ previous journal files if the replication-state is OFF and then turned ON
+ again. The database cannot rollback to a state prior to ON. Therefore,
+ ensure that replication-state remains ON throughout the span of database
+ replication. Turn replication-state OFF only if database replication is no
+ longer needed or the instance is about to be refreshed from the backup of
+ the originating instance.
+
+ ON
+
+ Enables replication for the selected database file(s) or region(s). When
+ the JOURNAL qualifier is not specified, this action turns BEFORE_IMAGE
+ journaling on. Specify -JOURNAL=NOBEFORE_IMAGE to enable replication with
+ no-before-image journaling. In both cases, GT.M creates a new journal file
+ for each database file or region, and switches the current journal file.
+ FIS recommends you to specify the desired journaling characteristics
+ (MUPIP SET -JOURNAL=BEFORE_IMAGE or MUPIP SET -JOURNAL=NOBEFORE_IMAGE).
+
+ When replication is ON, a MUPIP SET REPLICATION=ON command with no JOURNAL
+ qualifier assumes the current journaling characteristics (which are stored
+ in the database file header). By default GT.M sets journal operation to
+ BEFORE_IMAGE if this command changes the replication state from OFF to ON
+ and JOURNAL=NOBEFORE_IMAGE is not specified. Therefore, conservative
+ scripting should always specify the desired journaling characteristics
+ using the JOURNAL qualifier of the MUPIP SET command.
+
+ The replication state ON in the file header denotes normal replication
+ operation.
+
+ [WAS_ON] OFF
+
+ Denotes an implicit replication state when GT.M attempts to keep
+ replication working even if run-time conditions such as no available disk
+ space or no authorization for a process attempting to auto-switch a
+ journal file cause GT.M to turn journaling off. Even with journaling
+ turned off, the Source Server attempts to continue replication using the
+ records available in the replication journal pool. In this state,
+ replication can only continue as long as all the information it needs is
+ in the replication journal pool. Events such as an operationally
+ significant change on the replicating instance(s) or communication
+ problems are likely to cause the Source Server to need information older
+ than that in the replication journal pool and because it cannot look for
+ that information in journal files, at that point the Source Server shuts
+ down.
+
+ **Note**
+
+ If the replication ON state is like a bicycle running smoothly on the
+ road, replication WAS_ON is like a bicycle with a flat front tire being
+ ridden like a unicycle - the system is operating outside its intended mode
+ of use and is more subject to misfortune.
+
+ WAS_ON is an implicit replication state. At all times during the WAS_ON
+ state, you can see the current backlog of transactions and the content of
+ the Journal Pool (MUPIP REPLICATE -SOURCE -SHOWBACKLOG and MUPIP REPLICATE
+ -SOURCE -JNLPOOL -SHOW). This information is not available in the
+ replication OFF state.
+
+ Example:
+
+ $ mupip set -replication=on -file mumps.dat
+
+ This example enables database replication and turns before-image
+ journaling on for mumps.dat.
+
+ $ mupip set -replication=on -journal=nobefore_image -file mumps.dat
+
+ This example enables database replication and turns no-before-image
+ journaling on for mumps.dat.
+
+ $ mupip set -replication=off -file mumps.dat
+
+ This example turns off database replication for mumps.dat.
+
+2 Create_instance
+ Create instance
+
+ Command Syntax:
+
+ mupip replicate -instance_create -name=<instance name> [-noreplace] [-supplementary]
+
+ Qualifiers:
+
+ -instance_create
+
+ Creates a replication instance file. mupip replicate -instance_create
+ takes the file name of the replication instance file from the environment
+ variable gtm_repl_instance.
+
+ If an instance file already exists, GT.M renames it with a timestamp
+ suffix, and creates a new replication instance file. This behavior is
+ similar to the manner in which GT.M renames existing journal files while
+ creating new journal files. Creating an instance file requires standalone
+ access.
+
+ -name
+
+ Specifies the instance name that uniquely identifies the instance and is
+ immutable. The instance name can be from 1 to 16 characters. GT.M takes
+ the instance name (not the same as instance file name) from the
+ environment variable gtm_repl_instname. If gtm_repl_instname is not set
+ and -name is not specified, GT.M produces an error.
+
+ -noreplace
+
+ Prevents the renaming of an existing replication instance file.
+
+ -supplementary
+
+ Specifies that the replication instance file is suitable for use in a
+ supplementary instance.
+
+ Example:
+
+ $ export gtm_repl_instance=mutisite.repl
+ $ export gtm_repl_instname=America
+ $ mupip replicate -instance_create
+
+ This example creates a replication instance file called multisite.repl
+ specified by gtm_repl_instance with an instance name America specified by
+ environment variable gtm_repl_instname.
+
+2 Edit_instance
+ Edit instance
+
+ Command Syntax:
+
+ mupip replicate
+ -edit[instance] {<instance-file>|-source -jnlpool}
+ {-show [-detail]|-change [-offset=] [-size=] [-value=]}
+ [-name=<new-name>]
+
+ -editinstance
+
+ Displays or changes the attributes of the specified instance-file. Use
+ -editinstance in combination with SHOW or CHANGE qualifiers.
+
+ -jnlpool
+
+ Displays or changes the attributes of Journal Pool. Always specify -source
+ with -jnlpool. Use -jnlpool in combination with SHOW or CHANGE qualifiers.
+
+ -change
+
+ The CHANGE qualifier is intended only for use under the guidance of FIS
+ and serves two purposes. When used with -editinstance -offset -size, it
+ changes the contents of the replication instance file. When used with
+ -jnlpool, it changes the contents of journal pool header. Although MUPIP
+ does not enforce standalone access when using this feature on the instance
+ file or the journal pool, doing so when replication is actively occurring
+ can lead to catastrophic failures.
+
+ -name=<new-name>
+
+ Changes the instance name in the replication instance file header to the
+ new-name. Note that changing an instance name preserves the instance
+ history.
+
+ -show
+
+ Displays File Header, Source Server slots, and History Records from the
+ Replication Instance file.
+
+ -detail
+
+ When specified, all fields within each section are displayed along with
+ their offset from the beginning of the file and the size of each field.
+ Use this qualifier to find the -offset and -size of the displayed field.
+ To edit any displayed field, use the -change qualifier.
+
+ -size
+
+ Indicates the new size of the new value in bytes. The value of size can be
+ either 1, 2, 4, or 8.
+
+ -offset
+
+ Takes a hexadecimal value that is a multiple of -size. With no -offset
+ specified, GT.M produces an error. GT.M also produces an error if the
+ offset is greater than the size of the instance file or the journal pool
+ header.
+
+ -value
+
+ Specifies the new hexadecimal value of the field having the specified
+ -offset and -size. With no value specified, GT.M displays the current
+ value at the specified offset and does not perform any change. Specifying
+ -value=<new_value> makes the change and displays both the old and new
+ values.
+
+ **Caution**
+
+ Change the instance file or the journal pool only on explicit instructions
+ from FIS.
+
+ -show
+
+ The SHOW qualifier serves two purposes. When used with -editinstance, it
+ displays the content of the replication instance file. When used with
+ -jnlpool, it displays the content of the journal pool.
+
+ Example:
+
+ $ mupip replicate -editinstance -show -detail multisite.repl
+
+ This example displays the content of the replication instance file
+ multisite.repl. The optional detail qualifier displays each section along
+ with its offset from the beginning of the file and the size of each field.
+ Use this information when there is a need to edit the instance file.
+
+ Example:
+
+ $ mupip replicate -editinstance -change -offset=0x00000410 -size=0x0008 -value=0x010 multisite.repl
+
+ This command sets the value of the field having the specified offset and
+ size to 16. Note that mupip replicate -editinstance -show -detail command
+ displays the offset and size of all fields in an instance file.
+
+2 Start_Source_Server
+ Start Source Server
+
+ Command syntax:
+
+ mupip replicate -source -start
+ {-secondary=<hostname:port>|-passive}
+ [-buffsize=<Journal Pool size in bytes>]
+ [-filter=<filter command>]
+ [-freeze[=on|off] -[no]comment[='"<string>"']
+ [-connectparams=<hard tries>,<hard tries period>,
+ <soft tries period>, <alert time>, <heartbeat period>,
+ <max heartbeat wait>]
+ -instsecondary=<replicating instance name>
+ -log=<log file name> [-log_interval=<integer>]
+ {-rootprimary|-propagateprimary} [{-updok|-updnotok}]
+ [-cmplvl=<compression level>]
+
+ Qualifiers:
+
+ -replicate
+
+ Use this qualifier to access the replication subsystem.
+
+ -source
+
+ Identifies the Source Server.
+
+ -start
+
+ Starts the Source Server.
+
+ -secondary=<hostname:port>
+
+ Identifies the replicating instance. <hostname:port> includes an IP
+ address (or a hostname that resolves to an IP address) and the port at
+ which the Receiver Server is waiting for a connection.
+
+ -passive
+
+ Starts the Source Server in passive mode.
+
+ -log=<log file name>
+
+ Specifies the location of the log file. The Source Server logs its
+ unsuccessful connection attempts starting frequently and slowing to
+ approximately once every five minutes. This interval does not affect the
+ rate of connection attempts.
+
+ -log_interval=<integer>
+
+ Specifies the number of transactions for which the Source Server should
+ wait before writing to the log file. The default logging interval is 1000
+ transactions.
+
+ -log_interval=0 sets the logging interval to the default value.
+
+ -buffsize=<Journal Pool size in bytes>
+
+ Specifies the size of the Journal Pool. The server rounds the size up or
+ down to suit its needs. Any size less than 1 MB is rounded up to 1 MB. If
+ you do not specify a qualifier, the size defaults to the GT.M default
+ value of 64 MB. Remember that you cannot exceed the system-provided
+ maximum shared memory. For systems with high update rates, specify a
+ larger buffer size to avoid the overflows and file I/O that occur when the
+ Source Server reads journal records from journal files.
+
+ -filter=<filter command>
+
+ Specifies the complete path of the filter program and any associated
+ arguments. If you specify arguments, then enclose the command string in
+ quotation marks. If a filter is active, the Source Server passes the
+ entire output stream to the filter as input. Then, the output from the
+ filter stream passes to the replicating instance. If the filter program is
+ an M program with entry-ref OLD2NEW^FILTER, specify the following path:
+
+ filter='"$gtm_dist/mumps -run OLD2NEW^FILTER"'
+
+ Write the filter as a UNIX process that takes its input from STDIN and
+ writes its output to STDOUT.
+
+ The format of the input and output data is the MUPIP journal file extract
+ format. The filter must maintain a strict 1:1 relationship between
+ transactions on the input stream and transactions on the output stream. If
+ a transaction on the input results in no sets and kills in the output, the
+ filter must still write an empty transaction to the output stream.
+
+ Example:
+
+ extfilter
+ ; A command like mupip replic -source -start -buffsize=$gtm_buffsize
+ ;-instsecondary=$secondary_instance -secondary=$IP_Address:$portno
+ ;-filter='"$gtm_exe/mumps -run ^extfilter"' -log=$SRC_LOG_FILE
+ ;deploys this filter on the Source Server.
+ set $ztrap="goto err"
+ set TSTART="08"
+ set TCOMMIT="09"
+ set EOT="99"
+ set log=$ztrnlnm("filterlog")
+ ; use the environment variable filterlog" (if defined)
+ ;to specify which logfile to use
+ if logersion="" set log="logcharout" char
+ if $zv["VMS" sechar EOL=$C(13)_$C(10)
+ else set EOL=$C(10)
+ open log:newve:sion
+ use $principal:nowrap
+ for do
+ . use $principal
+ . read extrRec
+ . if $zeof halt
+ . set rectype=$piece(extrRec,"\",1)
+ . if rectype'=EOT do
+ .. if rectype'=TSTART set filtrOut=extrRec_EOL
+ .. else do
+ ... set filtrOut=extrRec_EOL
+ ... for read extrRec set filtrOut=filtrOut_extrRec_EOL quit:$zextract(extrRec,1,2)=TCOMMIT
+ ... if $zeof halt
+ .. ; set $x=0 is needed so every write starts at beginning of record position
+ .. ; do not write more than width characters in one output operation to avoid "chopping".
+ .. ; and/or eol in the middle of output stream
+ .. ; default width=32K-1
+ .. ; use $zsubstr to chop at valid character boundary (single or multi byte character)
+ .. set cntr=0,tmp=filtrOut
+ .. for quit:tmp="" do
+ ... set cntr=cntr+1,$x=0,record(cntr)=$zsubstr(tmp,1,32767),tmp=$zextract(tmp,$zlength(record(cntr))+1,$zlength(tmp))
+ ... write record(cntr)
+ . use log
+ . write "Received: ",EOL,$s(rectype'=TSTART:extrRec_EOL,1:filtrOut)
+ . if rectype'=EOT write "Sent: ",EOL,filtrOut
+ . else write "EOT received, halting..." halt
+ quit
+ err
+ set $ztrap=""
+ use log
+ write !!!,"**** ERROR ENCOUNTERED ****",!!!
+ zshow "*"
+ halt
+
+ This example reads logical database updates associated with a transaction
+ from STDIN and writes them to log.out and STDOUT just like the UNIX tee
+ command. It runs on GT.M V5.5-000 where it is no longer required to treat
+ filter output as a transaction. To run this example on a pre-GT.M V5.5-000
+ version, replace the line:
+
+ .. if rectype'=TSTART set filtrOut=extrRec_EOL
+
+ with
+
+ .. if rectype'=TSTART set filtrOut=TSTART_EOL_extrRec_EOL_TCOMMIT_EOL
+
+ to wrap mini-transactions in 08 09.
+
+ -freeze[=on|off] -[no]comment[='"<string>"']
+
+ Promptly sets or clears an Instance Freeze on an instance irrespective of
+ whether a region is enabled for an Instance Freeze. -freeze with no
+ arguments displays the current state of the Instance Freeze on the
+ instance.
+
+ -[no]comment[='"<string>"'] allows specifying a comment/reason associated
+ with an Instance Freeze. Specify -nocomment if you do not wish to specify
+ a comment/reason.
+
+ -connectparams=<hard tries>,<hard tries period>, <soft tries
+ period>,<alert time>,<heartbeat period><max heartbeat wait>
+
+ Specifies the connection retry parameters. If the connection between the
+ Source and Receiver Servers is broken or the Source Server fails to
+ connect to the Receiver Server at startup, the Source Server applies these
+ parameters to the reconnection attempts.
+
+ First, the Source Server makes the number of reconnection attempts
+ specified by the <hard tries> value every <hard tries period>
+ milliseconds. Then, the Source Server attempts reconnection every <soft
+ tries period> seconds and logs an alert message every <alert time>
+ seconds. If the specified <alert time> value is less than <hard
+ tries>*<hard tries period>/1000 + lt;soft tries period>, it is set to the
+ larger value. The Source Server sends a heartbeat message to the Receiver
+ Server every <heartbeat period> seconds and expects a response back from
+ the Receiver Server within <max heartbeat wait> seconds.
+
+ -instsecondary
+
+ Identifies the replicating instance to which the Source Server replicates
+ data.
+
+ With no -instsecondary specified, the Source Server uses the environment
+ variable gtm_repl_instsecondary for the name of the replicating instance.
+
+ With no -instsecondary specified and environment variable
+ gtm_repl_instsecondary not set, mupip replicate -source -checkhealth looks
+ at all the Source Servers (Active or Passive) that are alive and running
+ and those that were abnormally shutdown (kill -9ed). Any Source Server
+ that was kill -15ed or MUPIP STOPped is ignored because GT.M considers
+ those Source Server shut down in the normal way. This command reports
+ something only if it finds at least one Source Server that is alive and
+ running or was abnormally shutdown (kill -9ed). Otherwise it returns a
+ zero (0) status without anything to report even when the Journal Pool
+ exists and GT.M processes (Update Process or Receiver Server on the
+ replicating instance) are up and running.
+
+ You can start multiple Source Servers from the same originating instance
+ as long as each of them specifies a different name for -instsecondary.
+
+ Specify -instsecondary explicitly (by providing a value) or implicitly
+ (through the environment variable gtm_repl_instsecondary) even for
+ starting a Passive Source Server. Whenever it activates, a Passive Source
+ Server connects to this replicating instance.
+
+ Example:
+
+ $ mupip replicate -source -start -buffsize=$gtm_buffsize -secondary=localhost:1234 -log=A2B.log -instsecondary=B
+
+ This command starts the Source Server for the originating instance with
+ instance B as its replicating instance.
+
+ -rootprimary
+
+ Assign the current instance as the originating instance. You can specify
+ -rootprimary either explicitly or implicitly to start an instance as an
+ originating instance.
+
+ -updok
+
+ Instructs the Source Server to allow local updates on this instance. This
+ is a synonym for -rootprimary but is named so it better conveys its
+ purpose.
+
+ -propagate[primary]
+
+ Use this optional qualifier to assign the current instance as a
+ propagating instance. Specifying -propagateprimary disables updates on the
+ current instance.
+
+ Note that it is not possible to transition an originating instance to a
+ propagating instance without bringing down the Journal Pool. However, it
+ is possible to transition a propagating instance to an originating
+ instance without bringing down the Journal Pool for an already running
+ passive Source Server (start one with -propagateprimary if none is
+ running).
+
+ Both -rootprimary and -propagateprimary are optional and mutually
+ exclusive. However, FIS recommends you to specify both -rootprimary and
+ -propagateprimary explicitly in the script for clarity.
+
+ Example:
+
+ $ mupip replicate -source -activate -rootprimary
+
+ This command transitions a propagating originating instance to an
+ originating instance without bringing down the Journal Pool.
+
+ With neither -rootprimary nor -propagateprimary specified, GT.M uses a
+ default value of -propagateprimary for the passive Source Server startup
+ command (mupip replic -source -start -passive) and the deactivate
+ qualifier (mupip replicate -source -deactivate). GT.M uses a default value
+ of -rootprimary for the mupip replicate -source -start -secondary=... and
+ the mupip replic -source -activate commands. These default values make the
+ replication script simpler for users who are planning to limit themselves
+ to one originating instance and multiple replicating instance (without any
+ further replicating instances downstream).
+
+ $ export gtm_repl_instance=multisite.repl
+ $ mupip set -journal="enable,before,on" -replication=on -region "*"
+ $ mupip replicate -instance_create -name=America
+ $ mupip replicate -source -start -buffsize=$jnlpool_size -secondary=localhost:1234 -log=A2B.log -instsecondary=Brazil
+
+ This example starts the Source Server at port 1234 for the replicating
+ instance Brazil. The Source Server creates a Journal Pool. A GT.M Process
+ writes the updated journal records to the Journal Pool. Then, the Source
+ Server process transports each record from the Journal Pool to Brazil via
+ a TCP/IP connection.
+
+ **Note**
+
+ Before starting replication, always remember to rundown every replicated
+ database region then start the Source Server.
+
+ **Important**
+
+ GT.M updates to replicated regions are permitted only on the originating
+ instance and disabled on ALL other replicating instances.
+
+ The Source Server records actions and errors in A2B.log. It also
+ periodically record statistics such as the current backlog, the number of
+ journal records sent since the last log, the rate of transmission, the
+ starting and current JNL_SEQNO, and the path of the filter program, if
+ any.
+
+ -updnotok
+
+ Instructs the Source Server to not allow local updates on this instance.
+ This is a synonym for -propagateprimary but is named so it better conveys
+ its purpose.
+
+ -cmplvl=n
+
+ Specifies the desired compression level for the replication stream. n is a
+ positive integer value indicating the level of compression desired. Level
+ 0 offers no compression. Level 1 offers the least compression while Level
+ 9 (as of version 1.2.3.3 of the zlib library) offers the most compression
+ (at the cost of the most CPU usage). Specifying -cmplvl without an
+ accompanying -start produces an error. In the case of the source server,
+ if N specifies any value outside of the range accepted by the zlib library
+ or if -cmplvl is not specified, the compression level defaults to zero
+ (0). In the case of the receiver server, as long as N is non-zero the
+ decompression feature is enabled; since the source server setting
+ determines the actual level, any legal non-zero value enables compressed
+ operation at the receiver.
+
+ Alternatively, the environment variable gtm_zlib_cmp_level can specify the
+ desired compression level (in the same value range as N above) and the
+ source server can then be started without -cmplvl. This has the same
+ effect as starting it with -cmplvl specified. An explicitly specified
+ value on the command line overrides any value specified by the environment
+ variable.
+
+ Whenever the source and receiver server connect with each other, if the
+ source server was started with a valid non-zero compression level, they
+ first determine whether the receiver server is running a version of GT.M
+ which handles compressed records and has been started with a non-zero
+ compression level. Only if this is true, do they agree to use compressed
+ journal records. They also verify with a test message that
+ compression/decompression works correctly before sending any compressed
+ journal data across. They automatically fall back to uncompressed mode of
+ transmission if this test fails or if, at any point, either side detects
+ that compression or decompression has failed. That is, any runtime error
+ in the compression/decompression logic results in uncompressed replication
+ (thereby reducing replication throughput) but never jeopardizes the
+ functional health of replication.
+
+ The Source and Receiver Servers log all compression related events and/or
+ messages in their respective logs. The source server also logs the length
+ of the compressed data (in addition to the uncompressed data length) in
+ its logfile.
+
+ **Note**
+
+ If you plan to use the optional compression facility for replication, you
+ must provide the compression library. The GT.M interface for compression
+ libraries accepts the zlib compression libraries without any need for
+ adaptation. These libraries are included in many UNIX distributions and
+ are downloadable from the zlib home page. If you prefer to use other
+ compression libraries, you need to configure or adapt them to provide the
+ same API provided by zlib. Simple instructions for compiling zlib on a
+ number of platforms follow. Although GT.M uses zlib, zlib is not FIS
+ software and FIS does not support zlib. These instructions are merely
+ provided as a convenience to you.
+
+ If a package for zlib is available with your operating system, FIS
+ suggests that you use it rather than building your own.
+
+ Solaris/cc compiler from Sun Studio:
+
+ ./configure --shared
+ make CFLAGS="-KPIC -m64"
+
+ HP-UX(IA64)/HP C compiler:
+
+ ./configure --shared
+ make CFLAGS="+DD64"
+
+ AIX/XL compiler:
+
+ ./configure --shared
+ Add -q64 to the LDFLAGS line of the Makefile
+ make CFLAGS="-q64"
+
+ Linux/gcc:
+
+ ./configure --shared
+ make CFLAGS="-m64"
+
+ z/OS:
+
+ Download the zlib 1.1.4 from the libpng project's download page on
+ SourceForge.com. Use a transfer mechanism that does not perform automatic
+ conversion to download a source tarball. If pax cannot read the archive,
+ it is a sign that the download mangled the archive. Use pax to unpack the
+ tarball, converting files from ASCII to EBCDIC.
+
+ pax -r -o setfiletag -ofrom=ISO8859-1,to=IBM-1047 -f zlib-1.1.4.tar.gz
+
+ Apply the following patch to the zlib 1.1.4 sources:
+
+ ---------------------------------- zlib_1.1.4_zos.patch
+ --------------------------------------------------diff -purN
+ downloads/zlib/src.orig/configure downloads/zlib/src/configure---
+ downloads/zlib/src.orig/configure Tue Dec 16 14:09:57 2008+++
+ downloads/zlib/src/configure Mon Feb 9 14:30:49 2009@@ -116,6 +116,11 @@
+ else SFLAGS=${CFLAGS-"-Kconform_pic -O"} CFLAGS=${CFLAGS-"-O"}
+ LDSHARED=${LDSHARED-"cc -G"};;+ OS/390*)+ CC=xlc+ SFLAGS=${CFLAGS-"-qascii
+ -q64 -Wc,DLL,LP64,XPLINK,EXPORTALL -D_ALL_SOURCE_NOTHREADS"}+
+ CFLAGS=${CFLAGS-"-qascii -q64 -Wc,DLL,LP64,XPLINK,EXPORTALL
+ -D_ALL_SOURCE_NOTHREADS"}+ LDSHARED=${LDSHARED-"xlc -qascii -q64
+ -Wl,dll,LP64,XPLINK "};; # send working options for other systems to
+ support at gzip.org *) SFLAGS=${CFLAGS-"-O"} CFLAGS=${CFLAGS-"-O"}
+
+ Build and install the zlib DLL, placing the xlc compilers in compatibility
+ to mode by setting the environment variable C89_CCMODE to 1. When not in
+ compatibility mode, xlc follows strict placement of command line options.
+ Configure and build the zlib software with ./configure --shared && make.
+ By default, the configure script places zlib in /usr/local/lib. Install
+ the software with make install. To ensure that GT.M finds zlib, include
+ /usr/local/lib in LIBPATH, the environment variable that provides a search
+ path for processes to use when they link DLLs.
+
+ By default, GT.M searches for the libz.so shared library (libz.sl on HPUX
+ PA-RISC) in the standard system library directories (for example,
+ /usr/lib, /usr/local/lib, /usr/local/lib64). If the shared library is
+ installed in a non-standard location, before starting replication, you
+ must ensure that the environment variable $LIBPATH (AIX and z/OS) or
+ $LD_LIBRARY_PATH (other UNIX platforms) includes the directory containung
+ the library. The Source and Receiver Server link the shared library at
+ runtime. If this fails for any reason (such as file not found, or
+ insufficient authorization), the replication logic logs a DLLNOOPEN error
+ and continues with no compression.
+
+2 Shutdown_Source_Server
+ Shutdown Source Server
+
+ Command syntax:
+
+ mupip replicate -source -shutdown [-timeout=<timeout in seconds>]
+
+ Qualifiers:
+
+ -shutdown
+
+ Shuts down the Source Server.
+
+ -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.
+
+2 Activate_Passive_Source_Server
+ Activate Passive Source Server
+
+ Command syntax:
+
+ mupip replicate -source -activate
+ -secondary=<hostname:port>
+ -log=<log file name>
+ -connectparams=<hard tries>,<hard tries period>,
+ <soft tries period>,<alert time>,<heartbeat period>,
+ <max heartbeat wait>]
+ -instsecondary=<instance_name>
+ {-rootprimary|-propagateprimary}
+
+ Qualifiers:
+
+ -activate
+
+ Activates a passive Source Server. Once activated, the Source Server reads
+ journal records from the Journal Pool and transports them to the system
+ specified by -secondary.
+
+ -instsecondary=<instance_name>
+
+ Identifies the replicating instance to which the passive Source Server
+ connects after activation.
+
+ With no -instsecondary specified, the passive Source Server uses the
+ environment variable gtm_repl_instsecondary as the value of
+ -instsecondary.
+
+ -rootprimary
+
+ Specifies that the passive Source Server activation occurs on an
+ originating instance.
+
+ -propagateprimary
+
+ Specifies that the passive Source Server activation occurs on a
+ propagating instance.
+
+ If neither -rootprimary nor -propagateprimary are specified, this command
+ assumes -propagateprimary.
+
+ Example:
+
+ $ mupip replicate -source -activate -secondary=localhost:8998 -log=A2B.log -instsecondary=America
+
+ This example activates a Source Server from passive mode.
+
+2 Deactive_Active_Source_Server
+ Deactive Active Source Server
+
+ Command syntax:
+
+ mupip replicate -source -deactivate -instsecondary=<instance_name>
+
+ Qualifiers:
+
+ -deactivate
+
+ Makes an active Source Server passive. To change the replicating instance
+ with which the Source Server is communicating, deactivate the Source
+ Server and then activate it with a different replicating instance.
+
+ -instsecondary=<instance_name>
+
+ Identifies the active Source Server to transition to the passive (standby)
+ state.
+
+ With no -instsecondary specified, $gtm_repl_instsecondary determines the
+ active Source Server.
+
+ -rootprimary
+
+ Specifies that the active Source Server is on originating instance.
+
+ -propagateprimary
+
+ Specifies that the active Source Server is on a propagating instance.
+
+ If neither -rootprimary nor -propagateprimary are specified, this command
+ assumes -propagateprimary.
+
+2 Stop_Source_Filter
+ Stop Source Filter
+
+ There are two ways to stop an active filter on the Source Server.
+
+ o Execute mupip replicate -source -stopsourcefilter on the originating
+ Source Server.
+ o Specify -stopsourcefilter as an option for starting the Receiver
+ Server.
+
+2 Check_Server_Health
+ Check Server Health
+
+ Use the following command and qualifier to determine whether the Source
+ Server is running.
+
+ Command syntax:
+
+ mupip replicate -source -checkhealth
+ [-instsecondary=<instance_instance>] [-he[lpers]]
+
+ Qualifiers:
+
+ -checkhealth
+
+ Determine whether the Source Server is running. If the Source Server is
+ running, the exit code is 0 (zero). If the Source Server is not running or
+ an error exists, the exit code is not 0.
+
+ With helpers specified, -checkhealth displays the status of Helper
+ Processes in addition to the status of Receiver Server and Update Process.
+
+ -instsecondary=<instance_name>
+
+ Identifies a Source Server process.
+
+ If -instsecondary is not specified, -checkhealth checks all Source Server
+ processes.
+
+ 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
+ %GTM-E-SRCSRVNOTEXIST, Source server for secondary instance INSTB is not alive
+
+2 Change_Source_log
+ Change Source log
+
+ Command syntax:
+
+ mupip replicate -source -changelog -log=<log file name> [-log_interval=<integer>] -instsecondary=<instance_name>
+
+ Qualfiers:
+
+ -changelog
+
+ -instsecondary=<instance_name>
+
+ Identifies a Source Server process.
+
+ Instructs the Source Server to change its log file.
+
+ -log=<log file name>
+
+ Use this mandatory qualifier to specify the name of the new log file. If
+ you specify the name of the current log file, no change occurs.
+
+ Example:
+
+ $ mupip replicate -source -changelog -log=/more_disk_space/newA2B.log -instsecondary=Brazil
+
+ -log_interval=<integer>
+
+ Specifies the number of transactions for which the Source Server should
+ wait before writing to the log file. The default logging interval is 1000
+ transactions.
+
+ -log_interval=0 reverts the logging interval to the prior value.
+
+2 Source_Logging
+ Source Logging
+
+ Command syntax:
+
+ mupip replicate -source -statslog={ON|OFF}
+ [-log_interval=<integer>
+
+ Qualifiers:
+
+ -statslog={ON | OFF}
+
+ Enables or disables detailed logging. When ON, the system logs
+ current-state information of the Source Server and messages exchanged
+ between the Source and Receiver Servers. By default, detailed logging is
+ OFF. Once you enable it (ON), changing -statslog to OFF can stop detailed
+ logging.
+
+ -log_interval=<integer>
+
+ Specifies the number of transactions for which the Source Server should
+ wait before writing to the log file. The default logging interval is 1000
+ transactions.
+
+ -log_interval=0 reverts the logging interval to the prior value.
+
+2 Stop_Source_Server
+ Stop Source Server
+
+ Command Syntax:
+
+ mupip replic -source -shutdown [-instsecondary=<instance_name>] [-timeout=<seconds>]
+
+ Qualifiers:
+
+ -instsecondary=<instance_name>
+
+ Identifies a Source Server process.
+
+ If -instsecondary is not specified, -shutdown stops all Source Server
+ processes.
+
+ -timeout=<seconds>
+
+ Specifies the period of time (in seconds) a Source Server should wait
+ before shutting down. If you do not specify -timeout, the default timeout
+ period is 30 seconds. If you specify -timeout=0, shutdown occurs
+ immediately.
+
+2 Source_backlog
+ Source backlog
+
+ Command syntax:
+
+ mupip replicate -source -showbacklog
+
+ Qualifiers:
+
+ -showbacklog
+
+ Reports the current backlog of journal records (in terms of JNL_SEQNO) on
+ the output device (normally the standard output device). This qualifier
+ does not affect the statistics logged in the log file. The backlog is the
+ difference between the last JNL_SEQNO written to the Journal Pool and the
+ last JNL_SEQNO sent by the Source Server to the Receiver Server. In the
+ WAS_ON state, -showbacklog reports the backlog information even if the
+ Source Server is shut down.
+
+ Example:
+
+ $ mupip replic -source -showbacklog -inst=INSTB
+ Wed May 19 18:58:29 2010 : Initiating SHOWBACKLOG operation on source server pid [0] for secondary
+ instance [INSTB]
+ 101 : backlog number of transactions written to journal pool and yet to be sent by the source server
+ 102 : sequence number of last transaction written to journal pool
+ 1 : sequence number of last transaction sent by source server
+ %GTM-E-SRCSRVNOTEXIST, Source server for secondary instance INSTB is not alive
+
+2 Process_Lost_Transactions
+ Process Lost Transactions
+
+ Except following a failover when the backlog is zero, whenever a former
+ originating instance comes up as a new replicating instance, there is
+ always a lost transaction file. Apply this lost transaction file at the
+ new originating instance as soon as practicable because there could be
+ additional lost transaction files in the event of other failovers. For
+ example, failure of the new originating instance before the lost
+ transaction file is processed. These additional lost transactions files
+ can complicate the logic needed for lost transaction processing.
+
+ Apply the lost transactions on the new originating instance either
+ manually or in a semi-automated fashion using the M-intrinsic function
+ $ZQGBLMOD(). If you use $ZQGBLMOD() , two perform 2 additional steps (
+ mupip replicate -source -needrestart and mupip replicate -source
+ -losttncomplete ) as part of lost transaction processing. Failure to run
+ these steps can cause $ZQGBLMOD() to return false negatives that in turn
+ can result in application data consistency issues.
+
+ Command Syntax:
+
+ mupip replicate -source
+ {-losttncomplete | -needrestart}
+ -instsecondary=<replicating instance name>
+
+ -losttncomplete
+
+ Indicate to GT.M that all lost transaction processing using $ZQGBLMOD() is
+ complete. Use this qualifier either explicitly or implicitly to prevent a
+ future $ZQGBLMOD() on an instance from returning false positives when
+ applying future lost transactions. This ensures accuracy of future
+ $ZQGBLMOD() results.
+
+ Always use this qualifier when an originating instance comes up as a
+ replicating instance.
+
+ Always run MUPIP REPLICATE -SOURCE -LOSTTNCOMPLETE on each of the
+ replicating instances after applying all lost transaction files except on
+ the following occasions:
+
+ o The replicating instance is connected to the originating instance at
+ the time the command is run on the originating instance.
+ o The replicating instance is not connected at the time the command is
+ run on the originating instance but connects to the originating
+ instance, before the originating instance is brought down.
+
+ -needrestart
+
+ Checks whether the originating instance ever communicated with the
+ specified replicating instance (if the receiver server or a fetchresync
+ rollback on the replicating instance communicated with the Source Server)
+ since the originating instance was brought up. If so, this command
+ displays the message SECONDARY INSTANCE xxxx DOES NOT NEED TO BE RESTARTED
+ indicating that the replicating instance communicated with the originating
+ instnace and hence does not need to be restarted. If not, this command
+ displays the message SECONDARY INSTANCE xxxx NEEDS TO BE RESTARTED FIRST.
+ In this case, bring up the specified instance as a replicating instance
+ before the lost transactions from this instance are applied. Failure to do
+ so before applying the corresponding lost transactions causes $ZQGBLMOD()
+ to return false negatives which can result in application data
+ inconsistencies.
+
+ The mupip replic -source -needrestart command should be invoked once for
+ each lost transaction file that needs to be applied. It should be invoked
+ on the new originating instance before applying lost transactions. Specify
+ -instsecondary to provide the instance name of the replicating instance
+ where the lost transaction file was generated. If not, the environment
+ variable gtm_repl_instsecondary is implicitly assumed to hold the name of
+ the replicating instance.
+
+ If the lost transaction file was generated from the same instance to which
+ it is to be applied, a mupip replicate -source -needrestart command is not
+ required.
+
+ Always remember to bring the replicating instance (specified in the
+ -needrestart command) as an immediate replicating instance of the current
+ originating instance. If it is brought up as a replicating instance
+ through a different intermediate replicating instance, the -needrestart
+ command unconditionally considers the instance as not having communicated
+ with the originating instance even though it might be up and running.
+
+ The Source Server on the originating instance and/or Receiver Server or
+ fetchresync rollback on the replicating instance need not be up and
+ running at the time you run this command.
+
+ However, it is adequate if they were up at some point in time after the
+ originating instance was brought up.
+
+ This command protects against a scenario where the originating instance
+ when the lost transaction file is generated is different from the primary
+ instance when the lost transactions are applied (note that even though
+ they can never be different in case of a dual-site configuration, use of
+ this command is nevertheless still required).
+
+ $ZQGBLMOD() relies on two fields in the database file header of the
+ originating instance to be set appropriately. Zqgblmod Trans and Zqgblmod
+ Seqno. In an LMS configuration, if there are more than two instances, and
+ no instances other than the originating and replicating instances are
+ involved in the rollback -fetchresync participate in the sequence number
+ determination. Hence, they do not have their Zqgblmod Seqno (and hence
+ Zqgblmod Trans) set when that particular lost transaction file is
+ generated. If any of the non-participating instances is brought up as the
+ new originating instance and that particular lost transaction file is
+ applied on the originating instance, the return values of $ZQGBLMOD() will
+ be unreliable since the reference point (Zqgblmod Trans) was not set
+ appropriately. Hence, this command checks whether the replicating instance
+ where the lost transaction was previously generated has communicated with
+ the current originating instance after it came up as the originating
+ instance. If it is affirmative, the Zqgblmod Seqno and Zqgbl mod Trans
+ fields would have been appropriately set and hence $ZQGBLMOD() values will
+ be correct.
+
+ Example:
+
+ $ mupip replic -source -losttncomplete
+
+ This command updates the Zqgblmod Seqno and Zqgblmod Trans fields
+ (displayed by a dse dump -fileheader command) in the database file headers
+ of all regions in the global directory to the value 0. Doing so causes a
+ subsequent $ZQGBLMOD() to return the safe value of one unconditionally
+ until the next lost transaction file is created.
+
+2 Start_Receiver_Server
+ Start Receiver Server
+
+ Command syntax:
+
+ mupip replicate -receiver -start
+ -listenport=<port number>
+ -log=<log file name> [-log_interval="[integer1],[integer2]"]
+ [-autorollback[=verbose]]
+ [-buffsize=<Receive Pool size in bytes>]
+ [-filter=<filter command>]
+ [-noresync]
+ [-stopsourcefilter]
+ [-updateresync=</path/to/bkup-orig-repl-inst-file>
+ {[-resume=<strm_num>|-reuse=<instname>]}
+ [-initialize] [-cmplvl=n]
+
+ Qualifiers:
+
+ -receiver
+
+ Identifies the Receiver Server.
+
+ -listenport=<port number>
+
+ Specifies the TCP port number the Receiver Server will listen to for
+ incoming connections from a Source Server. Note that the current
+ implementation of the Receiver Server does not support machines with
+ multiple IP addresses.
+
+ -autorollback[=verbose]
+
+ Allows the receiving instance of SI or BC replication to roll back as
+ required when the source instance rolls back with a mupip journal
+ -rollback -backward command. The optional value keyword VERBOSE allows
+ roll back to provide more diagnostic information.
+
+ **Caution**
+
+ As autorollback uses mupip online rollback under the covers, it should be
+ considered field test grade functionality as long as that function is
+ considered field test grade functionality.
+
+ -log_interval="[integer1],[integer2]"
+
+ integer1 specifies the number of transactions for which the Receiver
+ Server should wait before writing to the log file. integer2 specifies the
+ number of transactions for which the Update Process should wait before
+ writing to the log file. The default logging interval is 1000
+ transactions.
+
+ If integer1 or integer2 is 0, the logging interval is set to the default
+ value.
+
+ -stopsourcefilter
+
+ Starting the Receiver Server with -stopsourcefilter turns off any active
+ filter on the originating Source Server. Use this option at the time of
+ restarting the Receiver Server after a rolling upgrade is complete.
+
+ -updateresync=</path/to/bkup-orig-repl-inst-file>
+
+ -updateresync guarantees GT.M that the replicating instance was, or is, in
+ sync with the originating instance and it is now safe to resume
+ replication. Use -updateresync only in the following situations:
+
+ o To replace an existing replication instance files when an upgrade to a
+ GT.M version changes the instance file format. Consult the release
+ notes to determine whether this applies to your upgrade.
+ o When an existing replication instance file is unusable because it was
+ damaged or deleted, and is replaced by a new replication instance
+ file.
+ o Setting up an A->P configuration for the first time if P is an
+ existing instance with existing updates that are not, and not expected
+ to be, in the originating instance.
+ o Setting up a new replicating instance from a backup of the originating
+ instance (A->P only) or one of its replicating secondary instances.
+ o If you are running a GT.M version prior to V5.5-000 and you have to
+ set up a replicating instance from a backup of an originating
+ instance.
+
+ -updateresync uses the journal sequence number stored in the replicating
+ instance's database and the history record available in the backup copy of
+ the replication instance file of the originating instance
+ (</path/to/bkup-orig-repl-inst-file>) to determine the journal sequence
+ number at which to start replication.
+
+ When replication resumes after a suspension (due to network or maintenance
+ issues), GT.M compares the history records stored in the replication
+ instance file of the replicating instance with the history records stored
+ in the replication instance file of the originating instance to determine
+ the point at which to resume replication. This mechanism ensures that two
+ instances always remain in sync when a replication connection resumes
+ after an interruption. -updateresync bypasses this mechanism by ignoring
+ the replication history of the replicating instance and relying solely on
+ the current journal sequence number and its history record in the
+ originating instance's history to determine the point for resuming
+ replication. As it overrides a safety check, use -updateresync only after
+ careful consideration. You can check with your GT.M support channel as to
+ whether -updateresync is appropriate in your situation.
+
+ To perform an updateresync, the originating instance must have at least
+ one history record. You need to take a backup (BACKUP -REPLINST) of the
+ replication instance file of the originating instance while the Source
+ Server is running. This ensures that the instance file has at least one
+ history record. Even though it is safe to use a copy (for example, an scp)
+ of the replication instance file of the originating instance taken after
+ shutting down its Source Server, BACKUP -REPLINST is recommended because
+ it does not require Source Server shutdown. You also need an empty
+ instance file (-INSTANCE_CREATE) of the replicating instance to ensure
+ that it bypasses the history information of the current and prior states.
+
+ You also need use -updateresync to replace your existing replication
+ instance files if a GT.M version upgrade changes the instance file format.
+ The instance file format was changed in V5.5-000. Therefore, upgrading a
+ replicating instance from a version prior to GT.M V5.5-000 up to V5.5-000
+ or higher requires replacing its instance file.
+
+ Prior to V5.5-000, -updateresync did not require the argument
+ (<bckup_orig_repl_inst_file>). The syntax for -updateresync depends on the
+ GT.M version.
+
+ -initialize
+
+ Used when starting a Receiver Server of an SI replication stream with
+ -updateresync to specify that this is the first connection between the
+ instances. MUPIP ignores these qualifiers when starting BC replication
+ (that is, no updates permitted on the instance with the Receiver Server).
+ This qualifier provides additional protection against inadvertent errors.
+
+ -resume=<strm_num>
+
+ Used when starting a Receiver Server of an SI replication stream with
+ -updateresync in case the receiver instance has previously received from
+ the same source but had only its instance file (not database files)
+ recreated in between (thereby erasing all information about the source
+ instance and the stream number it corresponds to recorded in the receiver
+ instance file). In this case, the command mupip replic -receiv -start
+ -updateresync=<instfile> -resume=<strm_num>, where strm_num is a number
+ from 1 to 15, instructs the receiver server to use the database file
+ headers to find out the current stream sequence number of the receiver
+ instance for the stream number specified as <strm_num>, but uses the input
+ instance file (specified with -updateresync) to locate the history record
+ corresponding to this stream sequence number and then exchange history
+ with the source to verify the two instances are in sync before resuming
+ replication. Note that in case -resume is not specified and only
+ -updateresync is specified for a SI replication stream, it uses the input
+ instance file name specified with -updateresync to determine the stream
+ sequence number as well as provide history records to exchange with the
+ source instance (and verify the two are in sync). Assuming that instance
+ files are never recreated (unless they are also accompanied by a database
+ recreate), this qualifier should not be required in normal usage
+ situations.
+
+ -reuse=<instname>
+
+ Used when starting a Receiver Server of an SI replication stream with
+ -updateresync in case the receiver instance has previously received from
+ fifteen (all architecturally allowed) different externally sourced streams
+ and is now starting to receive from yet another source stream. The command
+ mupip replic -receiv -start -updateresync=<instfile> -reuse=<instname>,
+ where instname is the name of a replication instance, instructs the
+ receiver server to look for an existing stream in the replication instance
+ file header whose Group Instance Name (displayed by a mupip replic
+ -editinstance -show command on the receiver replication instance file)
+ matches the instance name specified and if one does, reuse that stream
+ number for the current source connection (erasing any record of the older
+ Group using the same stream number).
+
+ -noresync
+
+ Instructs the Receiver Server to accept a SI replication stream even when
+ the receiver is ahead of the source. In this case, the source and receiver
+ servers exchange history records from the replication instance file to
+ determine the common journal stream sequence number and replication
+ resumes from that point onwards. Specifying -noresync on a BC replication
+ stream is produces a NORESYNCSUPPLONLY error. Specifying -noresync on a SI
+ replication stream receiver server where the receiving instance was
+ started with -UPDNOTOK (updates are disabled) produces a
+ NORESYNCUPDATERONLY error. Note also that the noresync qualifier is not
+ the opposite of the resync qualifier of rollback (mupip journal -rollback
+ -resync), which is intended for use under the direction of FIS GT.M
+ support.
+
+2 Start_Update_Process
+ Start Update Process
+
+ The following command starts the Update Process only, if it has been
+ shutdown independent of the Receiver Server.
+
+ Command syntax:
+
+ mupip replicate -receiver -start {-updateonly|-helpers[=m[,n]]
+
+ Qualifiers:
+
+ -updateonly
+
+ If the Update Process has been shutdown independent of the Receiver
+ Server, use this qualifier to restart the Update Process.
+
+ -helpers[=m[,n]]
+
+ Starts additional processes to help improve the rate at which updates from
+ an incoming replication stream are applied on a replicating instance.
+
+ o m is the total number of helper processes and n is the number of
+ reader helper processes, in other words m>=n.
+ o Helper processes can start only on a receiver server.
+ o If helper processes are already running, specifying -helpers[=m[,n]]
+ again starts additional helper processes. There can be a maximum of
+ 128 helper processes for a receiver server.
+ o If -helpers=0[,n] is specified, GT.M starts no helper processes.
+ o With the HELPERS qualifier specified but neither m nor n specified,
+ GT.M starts the default number of helper processes with the default
+ proportion of roles. The default number of aggregate helper processes
+ is 8, of which 5 are reader helpers and 3 writers.
+ o With only m specified, helper processes are started of which
+ floor(5*m/8) processes are reader helpers.
+ o With both m and n specified, GT.M starts m helper processes of which n
+ are reader helpers and m-n are writers. If m<n, mupip starts m
+ readers, effectively reducing n to m and starting no writers.
+ o GT.M reports helper processes (for example, by the ps command and in
+ /proc/<pid>/cmdline on platforms that implement a /proc filesystem) as
+ mupip replicate -updhelper -reader and mupip replicate -updhelper
+ -writer.
+
+ Example:
+
+ $ mupip replicate -receiver -start -listenport=1234 -helpers -log=B2C.log -buffsize=$recpool_size
+
+ This command starts the Receiver Server with Helper Processes. The
+ following sample output from the ps command shows that there are 5 reader
+ processes and 3 writer processes.
+
+ gtmuser1 11943 1 0 06:42 ? 00:00:00 /usr/library/GTM/mupip replicate -receiver -start
+ -listenport=1234 -helpers -log=B2C.log -buff=$rec_pool_size
+ gtmuser1 11944 11943 0 06:42 ? 00:00:00 /usr/library/GTM/mupip replicate -updateproc
+ gtmuser1 11945 11943 0 06:42 ? 00:00:00 /usr/library/GTM/mupip replicate -updhelper -reader
+ gtmuser1 11946 11943 0 06:42 ? 00:00:00 /usr/library/GTM/mupip replicate -updhelper -reader
+ gtmuser1 11947 11943 0 06:42 ? 00:00:00 /usr/library/GTM/mupip replicate -updhelper -reader
+ gtmuser1 11948 11943 0 06:42 ? 00:00:00 /usr/library/GTM/mupip replicate -updhelper -reader
+ gtmuser1 11949 11943 0 06:42 ? 00:00:00 /usr/library/GTM/mupip replicate -updhelper -reader
+ gtmuser1 11950 11943 0 06:42 ? 00:00:00 /usr/library/GTM/mupip replicate -updhelper -writer
+ gtmuser1 11951 11943 0 06:42 ? 00:00:00 /usr/library/GTM/mupip replicate -updhelper -writer
+ gtmuser1 11952 11943 0 06:42 ? 00:00:00 /usr/library/GTM/mupip replicate -updhelper -writer
+
+2 Stop_Update_Process
+ Stop Update Process
+
+ Command syntax:
+
+ mupip replicate -receiver -shutdown [-updateonly|-helpers] [-timeout=<timeout in seconds>]
+
+ Qualifiers:
+
+ -updateonly
+
+ Use this qualifier to stop only the Update Process. If neither -updateonly
+ nor -helper are specified, the Update Process, all helper processes (if
+ any), and Receiver Server shut down.
+
+ -helper
+
+ Shuts down only the Helper Processes and leaves the Receiver Server and
+ Update Process to continue operating as before. All helpers processes shut
+ down even if -helper values are specified.
+
+ -timeout
+
+ Specifies the period of time (in seconds) the Receiver Server should wait
+ before shutting down. If you do not specify -timeout, the default timeout
+ period is 30 seconds. If you specify -timeout=0, shutdown occurs
+ immediately.
+
+ Example:
+
+ $ mupip replicate -receiver -shutdown -helper
+
+ This example shuts down only the helper processes of the current Receiver
+ Server. Note that all helpers processes shut down even if HELPER values
+ are specified.
+
+2 Check_Receiver_Health
+ Check Receiver Health
+
+ Use the following command to determine whether the Receiver Server is
+ running.
+
+ Command syntax:
+
+ mupip replicate -receiver -checkhealth
+
+2 Change_Receiver_log
+ Change Receiver log
+
+ Command syntax:
+
+ mupip replicate -receiver -changelog -log=<log file name> [-log_interval="[integer1],[integer2]"]
+
+ -log_interval="[integer1],[integer2]"
+
+ integer1 specifies the number of transactions for which the Receiver
+ Server should wait before writing to the log file. integer2 specifies the
+ number of transactions for which the Update Process should wait before
+ writing to the log file. The default logging interval is 1000
+ transactions.
+
+ If integer1 or integer2 is 0, the logging interval reverts to the prior
+ value.
+
+2 Receiver_logging
+ Receiver logging
+
+ Command syntax:
+
+ mupip replicate -receiver -statslog={ON|OFF}
+ [-log_interval="[integer1],[integer2]"]
+
+ -log_interval="[integer1],[integer2]"
+
+ integer1 specifies the number of transactions for which the Receiver
+ Server should wait before writing to the log file. integer2 specifies the
+ number of transactions for which the Update Process should wait before
+ writing to the log file. The default logging interval is 1000
+ transactions.
+
+ If integer1 or integer2 is 0, the logging interval reverts to the prior
+ value.
+
+2 Receiver_backlog
+ Receiver backlog
+
+ Command syntax:
+
+ mupip replicate -receiver -showbacklog
+
+ Qualifiers:
+
+ -showbacklog
+
+ Use this qualifier to report the current backlog (that is, the difference
+ between the last JNL_SEQNO written to the Receive Pool and the last
+ JNLSEQNO processed by the Update Process) of journal records on the
+ Receiver Server.
+
+2 Rollback_Database
+ Rollback Database
+
+ Command syntax:
+
+ mupip journal -rollback
+ {[-fetchresync=<port number>|-resync=<JNL_SEQNO>]
+ [-rsync_strm=<strm_num>]}
+ -losttrans=<extract file> -backward *
+
+ Qualifiers:
+
+ -rollback
+
+ Use this qualifier to rollback the database. If you do not use the
+ -fetchresync qualifier, the database rolls back to the last consistent
+ state.
+
+ -fetchresync=<port number>
+
+ The <port number> is the communication port number that the rollback
+ command uses when fetching the reference point. Always use the same <port
+ number> on the originating instance for rollback as the one used by the
+ Receiver Server.
+
+ **Important**
- ST[OP] process-id
+ FIS recommends you to unconditionally script the mupip journal -rollback
+ -fetchresync command prior to starting any Source Server on the
+ replicating instance to avoid a possible out-of-sync situation.
- Use the shell command ps to display a list of active process names and
- process identifiers (PIDs).
+ The reference point sent by the originating instance is the RESYNC_SEQNO
+ (explained later) that the originating instance once maintained. The
+ database/journal files are rolled back to the earlier RESYNC_SEQNO (that
+ is, the one received from originating instance or the one maintained
+ locally). If you do not use -fetchresync, the database rolls back to the
+ last consistent replicating instance state.
+ The system stores extracted lost transactions in the file <extract file>
+ specified by this mandatory qualifier. The starting point for the search
+ for lost transactions is the JNL_SEQNO obtained from the originating
+ instance in the -fetchresync operation. If -fetchresync is not specified,
+ <extract file> lists the post-consistent-state transactions that were
+ undone by the rollback procedure to reach a consistent state.
+
+ **Note**
+
+ The extracted lost transactions list may contain broken transactions due
+ to system failures that occurred during processing. Do not resolve these
+ transactions-they are not considered to be committed.
+
+ **Caution**
+
+ The database header may get corrupted if you suspend an ongoing ROLLBACK
+ -FETECHRESYNC operation or if the TCP connection between the two instances
+ gets broken. The workaround is to restart the ROLLBACK -FETCHRESYNC
+ operation or wait 60 seconds for the FETCHRESYNC operation to timeout.
+
+ Example:
+
+ $ mupip journal -rollback -fetchresync=2299 -losttrans="glo.lost" -backward *
+
+ This command performs a ROLLBACK -FETCHRESYNC operation on a replicating
+ instance to bring it to a common synchronization point from where the
+ originating instance can begin to transmit updates to allow it to catch
+ up. It also generates a lost transaction file glo.lost of all those
+ transactions that are present on the replicating instance but not on the
+ originating instance at port 2299.
+
+ -resync=<JNL_SEQNO>
+
+ Use this qualifier to roll back to the transaction identified by JNL_SEQNO
+ (in decimal) only when the database/ journal files need to be rolled back
+ to a specific point. If you specify a JNL_SEQNO that is greater than the
+ last consistent state, the database/journal files will be rolled back to
+ the last consistent state. Under normal operating conditions, you would
+ not need this qualifier.
+
+ -losttrans=<extract file>
+
+ If failover occurs (that is, originating instance fails and replicating
+ instance assumes the originating instance role), some transactions
+ committed to A's database may not be reflected in B's database. Before the
+ former originating instance becomes the new replicating instance, these
+ transactions must be rolled off before it can assume the role of an
+ originating instance. These transactions are known as "lost transactions".
+
+ The system stores extracted lost transactions in the file <extract file>
+ specified by this mandatory qualifier. The starting point for the search
+ for lost transactions is the JNL_SEQNO obtained from the originating
+ instance in the -fetchresync operation. If -fetchresync is not specified,
+ <extract file> lists the post-consistent-state transactions that were
+ undone by the rollback procedure to reach a consistent state.
+
+ **Note**
+
+ The extracted lost transactions list may contain broken transactions due
+ to system failures that occurred during processing. Do not resolve these
+ transactions-they are not considered to be committed.
+
+ -rsync_strm=<strm_num>
+
+ Used when starting a rollback command with the -resync qualifier. The
+ command mupip journal -rollback -resync=<sequence_num>
+ -rsync_strm=<strm_num> instructs rollback to roll back the database to a
+ sequence number specified with the -resync=<sequence_num> qualifier but
+ that <sequence_num> is a journal stream sequence number (not a journal
+ sequence number) corresponding to the stream number <strm_num> which can
+ be any value from 0 to 15. Note that like the -resync qualifier, the
+ -rsync_strm qualifier is also intended for use under the direction of your
+ GT.M support channel.
+
+1 Summary
+ Summary
+
+ +------------------------------------------------------------------------------+
+ | COMMAND | OBJECTS | MAIN QUALIFIER |
+ |-------------+----------------+-----------------------------------------------|
+ | | |-BK[UPDBJNL]=DISABLE | OFF |
+ | | |-B[YTESTREAM] -NET[TIMEOUT]=seconds |
+ | | |-C[OMPREHENSIVE] |
+ | | |-DA[TABASE] -REPLA[CE] |
+ | | |-DBG |
+ | | |-I[NCREMENTAL] |
+ | |region-name |-[NO]J[OURNAL][=journal-options-list] |
+ |B[ACKUP] | | |
+ | |file-name |-NETTIMEOUT |
+ | | |-[NO]NEWJNLFILES[=[NO]PREVLINK],[NO]S[YNC_IO] |
+ | | |-O[NLINE] |
+ | | |-RECORD |
+ | | |-REPLI[NSTANCE]=OFF | ON |
+ | | |-S[INCE]={DATABASE|BYTESTREAM|RECORD} |
+ | | |-T[RANSACTION=hexa;transaction_number] |
+ |-------------+----------------+-----------------------------------------------|
+ |CR[EATE] |- |-R[EGION]=region-name |
+ |-------------+----------------+-----------------------------------------------|
+ | | |-OUTDB=<outdb-file> |
+ |EN[DIANCVT] |file-name | |
+ | | |-OV[ERRIDE] |
+ |-------------+----------------+-----------------------------------------------|
+ |EXI[T] |- |- |
+ |-------------+----------------+-----------------------------------------------|
+ |EXTE[ND] |region-name |-B[LOCKS]=blocks |
+ |-------------+----------------+-----------------------------------------------|
+ | | |-FO[RMAT]=GO|B[INARY]|Z[WR] |
+ | | |-FR[EEZE] |
+ | | |-LA[BEL]=text |
+ |EXTR[ACT] |- | |
+ | | |-[NO]L[OG] |
+ | | |-S[ELECT]=global-name-list |
+ | | |-O[CHSET]=character-set |
+ |-------------+----------------+-----------------------------------------------|
+ | | |-DBG |
+ | | |-OF[F] |
+ |F[REEZE] |region-list | |
+ | | |-OV[ERRIDE] |
+ | | |-ON[-R[ECORD]] |
+ |-------------+----------------+-----------------------------------------------|
+ | | |-D[B] |
+ |FT[OK] |File-name |-J[NLPOOL] |
+ | | |-R[ECVPOOL] |
+ |-------------+----------------+-----------------------------------------------|
+ |H[ELP] |command-option |- |
+ |-------------+----------------+-----------------------------------------------|
+ | | |-A[DJACENCY]=integer] |
+ | | |-BL[OCK]=hexa;block-number] |
+ | | |-BR[IEF] |
+ | | |-FA[ST] |
+ | | |-FI[LE] |
+ | | |-FU[LL] |
+ | |File-name or | |
+ |I[NTEG] |region-list |-NO]K[EYRANGES |
+ | | |-[NO][MAP]=integer |
+ | | |-[NO]MAXK[EYSIZE]=integer |
+ | | |-R[EGION] |
+ | | |-S[UBSCRIPT]=subscript |
+ | | |-TN[_RESET] |
+ | | |-[NO]TR[ANSACTION][=integer] |
+ |-------------+----------------+-----------------------------------------------|
+ | | |-EX[TRACT][=file-specification|-stdout] |
+ | | |-REC[OVER] | -RO[LLBACK] |
+ |J[OURNAL] |file-name |-SH[OW][=show-option-list] |
+ | | |-[NO]V[ERIFY] |
+ | | |-BA[CKWARD] | -FO[RWARD] |
+ |-------------+----------------+-----------------------------------------------|
+ | | |-BE[GIN]=integer |
+ | | |-BLOCK_DENSITY |
+ | | |-E[ND]=integer |
+ |L[OAD] |file-name | |
+ | | |-FI[LLFACTOR]=integer |
+ | | |-FO[RMAT]=GO|B[INARY]|Z[WR] |
+ | | |-S[TDIN] |
+ |-------------+----------------+-----------------------------------------------|
+ | | |-DOWNGRADE |
+ | | |-E[XCLUDE]=global-name-list |
+ | | |-FI[LL_FACTOR]=integer |
+ | | |-I[NDEX_FILL_FACTOR]=integer |
+ | | |-REG[ION] |
+ | | |-RES[UME] |
+ |REO[RG] | |-SA[FEJNL] |
+ | | |-S[ELECT]=global-name-list |
+ | | |-STA[RTBLK]=hexa |
+ | | |-STO[PBLK]=hexa |
+ | | |-T[RUNCATE][=percentage] |
+ | | |-UP[GRAD E] |
+ | | |-USER_DEFINED_REORG=reorg_list |
+ |-------------+----------------+-----------------------------------------------|
+ | | |-E[DITINSTANCE] |
+ | | |-I[NSTANCE_CREATE] |
+ | | |-R[ECEIVER |
+ |REP[LICATE] |file-name | |
+ | | |-S[OURCE] |
+ | | |-UPDA[TEPROC] |
+ | | |-UPDH[ELPER] |
+ |-------------+----------------+-----------------------------------------------|
+ |RE[STORE] |file-name or |-[NO]E[XTEND] |
+ | |file-list | |
+ |-------------+----------------+-----------------------------------------------|
+ | |file-name or |-F[ILE] |
+ |RU[NDOWN] |region-name | |
+ | | |-R[EGION] |
+ |-------------+----------------+-----------------------------------------------|
+ | | |-A[CCESS_METHOD=BG|MM] |
+ | | |-B[YPASS] |
+ | | |-DB[FILENAME]=database_file |
+ | | |-DE[FER_TIME]=seconds |
+ | | |-E[XTENSION_COUNT]=integer(no of blocks) |
+ | | |-FILE |
+ | | |-F[LUSH_TIME]= integer |
+ | | |-G[LOBAL_BUFFERS]=integer |
+ | | |-JN[LFILE] |
+ | |file-name or |-JO[URNAL]=journal-option-list |
+ |SE[T] |region-name | |
+ | | |-L[OCK_SPACE]=integer |
+ | | |-PA[RTIAL_RECOV_BYPASS] |
+ | | |-PR[EVJNLFILE]=jnl_file_name |
+ | | |-RE[GION] |
+ | | |-REPLI[CATION]=ON|OFF |
+ | | |-REPL_[STATE]=ON|OFF |
+ | | |-RES[ERVED_BYTES]=integer |
+ | | |-S[TANDALONENOT] |
+ | | |-V[ERSION]=V4|V5 |
+ | | |-W[AIT_DISK]=integer |
+ |-------------+----------------+-----------------------------------------------|
+ |ST[OP] |process-id |process-id |
+ |-------------+----------------+-----------------------------------------------|
+ |UP[GRADE] |- |- |
+ +------------------------------------------------------------------------------+
+
+ +------------------------------------------------------------------------------------------------------------+
+ | Main Qualifier | MUPIP Command | Options/Qualifiers |
+ |--------------------------------------+--------------------------+------------------------------------------|
+ | | |-CHANGE |
+ | | |-DETAIL |
+ | | |-OFFSET=hexa |
+ |-EDITINSTANCE |REPLICATE | |
+ | | |-VALUE=hexa |
+ | | |-SIZE=hexa |
+ | | |-VALUE=hexa |
+ |--------------------------------------+--------------------------+------------------------------------------|
+ | | |ALWAYS |
+ |-FENCES=<fence-options-list> |JOURNAL-RECOVER-ROLLBACK |NONE |
+ | | |PROCESS |
+ |--------------------------------------+--------------------------+------------------------------------------|
+ | | |ALIGNSIZE=integer |
+ | | |ALLOCATION=integer |
+ | | |AUTOSWITCHLIMIT=integer |
+ | | |BEFORE_IMAGES |
+ | | |BUFFER_SIZE=integer |
+ | | |DISABLE |
+ | |BACKUP |ENABLE |
+ |-JOURNAL=<journal-options-list> | | |
+ | |SET |EPOCH_INTERVAL=integer |
+ | | |EXTENSION=integer |
+ | | |FILENAME=file_name |
+ | | |OFF |
+ | | |ON |
+ | | |SYNC_IO |
+ | | |YIELD_LIMIT=integer |
+ |--------------------------------------+--------------------------+------------------------------------------|
+ | |-RECOVER |TIME="time" |
+ |-LOOKBACK_LIMIT=lookback-option-list | | |
+ | |-ROLLBACK |OPERATIONS=integer |
+ |--------------------------------------+--------------------------+------------------------------------------|
+ | | |-BUFFSIZE=integer |
+ | | |-CHANGELOG |
+ | | |-CHECKHEALTH |
+ | | |-CMPLVL=integer |
+ | | |-FILTER=filter_name |
+ | | |-he[lpers]=[m[,n]] |
+ | | |-LISTENPORT=integer |
+ | | |-LOG=logfile |
+ |-RECEIVER |REPLICATE |-LOG_INTERVAL=integer |
+ | | |-SHOWBACKLOG |
+ | | |-SHUTDOWN |
+ | | |-START |
+ | | |-STATSLOG=[ON|OFF] |
+ | | |-STOPSOURCEFILTER |
+ | | |TIMEOUT=seconds |
+ | | |-UPDATEONLY |
+ | | |-UPDATERESYNC |
+ |--------------------------------------+--------------------------+------------------------------------------|
+ | | |-AFTER=time |
+ | | |-APPLY_AFTER_IMAGE |
+ | | |-BACKWARD |
+ | | |-BEFORE=time |
+ | | |-BROKENTRANS=file |
+ | | |-CHAIN |
+ | | |-CHECKTN |
+ | | |-[NO]ER[ROR_LIMIT][=integer] |
+ | | |-FENCES=fence-option-list |
+ | | |-FORWARD |
+ |-RECOVER |JOURNAL | |
+ | | |-FULL |
+ | | |-GLOBAL=<global_list> |
+ | | |-ID=<pid_list> |
+ | | |-INTERACTIVE |
+ | | |-LOOKBACK_LIMIT=<lookback_limit_options> |
+ | | |-LOSTTRANS[=file] |
+ | | |-RED[IRECT]=file-pair-list |
+ | | |-SINCE=time |
+ | | |-VERBOSE |
+ | | |-VERIFY |
+ |--------------------------------------+--------------------------+------------------------------------------|
+ | | |-AFTER=time |
+ | | |-BEFORE=time |
+ | | |-BROKENTRANS=file |
+ | | |-CHAIN |
+ | | |-CHECKTN |
+ | | |-[NO]ER[ROR_LIMIT]=integer] |
+ | | |-FENCES=fence-option-list |
+ | | |-FULL |
+ |-EXTRACT |JOURNAL | |
+ | | |-GLOBAL=<global_list> |
+ | | |-ID=<pid_list> |
+ | | |-INTERACTIVE |
+ | | |-LOOKBACK_LIMIT=<lookback_limit_options> |
+ | | |-LOSTTRANS[=file] |
+ | | |-SINCE=time |
+ | | |-VERBOSE |
+ | | |-VERIFY |
+ |--------------------------------------+--------------------------+------------------------------------------|
+ | | |-APPLY_AFTER_IMAGE |
+ | | |-BACKWARD |
+ | | |-BEFORE=time |
+ | | |-BROKENTRANS=file |
+ | | |-[NO]ER[ROR_LIMIT][=integer] |
+ | | |-FENCES=fence-option-list |
+ |-ROLLBACK |JOURNAL | |
+ | | |-FETCHRESYNC |
+ | | |-LOOKBACK_LIMIT=<lookback_limit_options> |
+ | | |-LOSTTRANS[=file] |
+ | | |-RES[YNC]=hexa;journal_sequence_number |
+ | | |-VERBOSE |
+ | | |-VERIFY |
+ |--------------------------------------+--------------------------+------------------------------------------|
+ | | |-ACTIVE_PROCESSES |
+ | | |-ALL |
+ | | |-BROKEN_TRANSACTIONS |
+ | | |-HEADER |
+ | | |-PROCESSES |
+ | | |-STATISTICS |
+ |-SHOW=<show-option-list> |JOURNAL |-AFTER=time |
+ | | |-USER=user-list |
+ | | |-TRANSACTION=[KILL|SET] |
+ | | |-INTERACTIVE |
+ | | |-GLOBAL=<global_list> |
+ | | |-ID=<pid_list> |
+ | | |-INTERACTIVE |
+ |--------------------------------------+--------------------------+------------------------------------------|
+ | | |-BYTESTREAM |
+ | | |-COMPREHENSIVE |
+ |-SINCE |BACKUP |-DATABASE |
+ | | |-INCREMENTAL |
+ | | |-RECORD |
+ |--------------------------------------+--------------------------+------------------------------------------|
+ | | |-ACTIVATE |
+ | | |-BUFFSIZE=Buffer_size |
+ | | |-CHANGELOG |
+ | | |-CHECKHEALTH |
+ | | |-CMPLVL=integer |
+ | | |-CONNECTPARAMS=connection_options |
+ | | |-DEACTIVATE |
+ | | |-DETAIL |
+ | | |-FILTER=filter_name |
+ | | |-INSTSECONDARY=secondary_instance name |
+ | | |-JNLPOOL-LOG=log_file |
+ | | |-LOG_INTERVAL=integer |
+ |-SO[URCE] |REPLICATE | |
+ | | |-LOSTTNCOMPLETE |
+ | | |-NEEDRESTART |
+ | | |-PASSIVE |
+ | | |-PROPAGATEPRIMARY |
+ | | |-ROOTPRIMARY |
+ | | |-SECONDARY=secondary_instance_name |
+ | | |-SHOWBACKLOG |
+ | | |-SHUTDOWN |
+ | | |-START |
+ | | |-STATSLOG |
+ | | |-STOPSOURCEFILTER |
+ | | |-TIMEOUT=seconds |
+ +------------------------------------------------------------------------------------------------------------+
diff --git a/sr_port/mupip_backup.c b/sr_port/mupip_backup.c
index 85953b4..eb7bbcb 100644
--- a/sr_port/mupip_backup.c
+++ b/sr_port/mupip_backup.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -435,7 +435,7 @@ void mupip_backup(void)
if (mu_ctrly_occurred || mu_ctrlc_occurred)
{
mubclnup(NULL, need_to_free_space);
- gtm_putmsg(VARLSTCNT(1) ERR_BACKUPCTRL);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_BACKUPCTRL);
mupip_exit(ERR_MUNOFINISH);
}
# ifdef UNIX
@@ -450,12 +450,13 @@ void mupip_backup(void)
{ /* make sure backup files do not already exist */
if (FILE_PRESENT == (fstat_res = gtm_file_stat(replinstfile, NULL, NULL, FALSE, &ustatus)))
{
- gtm_putmsg(VARLSTCNT(4) ERR_FILEEXISTS, 2, LEN_AND_STR((char *)replinstfile->addr));
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_FILEEXISTS, 2,
+ LEN_AND_STR((char *)replinstfile->addr));
error_mupip = TRUE;
} else if (FILE_STAT_ERROR == fstat_res)
{ /* stat doesn't usually return with an error. Assert so we can analyze */
assert(FALSE);
- gtm_putmsg(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("stat"), CALLFROM, ustatus);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("stat"), CALLFROM, ustatus);
error_mupip = TRUE;
}
}
@@ -481,7 +482,7 @@ void mupip_backup(void)
{ /* make sure that backup won't be overwriting the database file itself */
if (TRUE == is_file_identical(file->addr, (char *)rptr->reg->dyn.addr->fname))
{
- gtm_putmsg(VARLSTCNT(4) ERR_MUSELFBKUP, 2, DB_LEN_STR(rptr->reg));
+ gtm_putmsg_csa(CSA_ARG(REG2CSA(rptr->reg)) VARLSTCNT(4) ERR_MUSELFBKUP, 2, DB_LEN_STR(rptr->reg));
error_mupip = TRUE;
}
# ifdef UNIX
@@ -489,12 +490,14 @@ void mupip_backup(void)
{ /* make sure backup files do not already exist */
if (FILE_PRESENT == (fstat_res = gtm_file_stat(file, NULL, NULL, FALSE, &ustatus)))
{
- gtm_putmsg(VARLSTCNT(4) ERR_FILEEXISTS, 2, LEN_AND_STR((char *)file->addr));
+ gtm_putmsg_csa(CSA_ARG(REG2CSA(rptr->reg)) VARLSTCNT(4) ERR_FILEEXISTS, 2,
+ LEN_AND_STR((char *)file->addr));
error_mupip = TRUE;
} else if (FILE_STAT_ERROR == fstat_res)
{ /* stat doesn't usually return with an error. Assert so we can analyze */
assert(FALSE);
- gtm_putmsg(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("stat"), CALLFROM, ustatus);
+ gtm_putmsg_csa(CSA_ARG(REG2CSA(rptr->reg)) VARLSTCNT(8) ERR_SYSCALL, 5,
+ LEN_AND_LIT("stat"), CALLFROM, ustatus);
error_mupip = TRUE;
}
}
@@ -513,7 +516,7 @@ void mupip_backup(void)
}
} else if (!incremental)
{ /* non-incremental backups to "exec" and "tcp" are not supported*/
- gtm_putmsg(VARLSTCNT(1) ERR_NOTRNDMACC);
+ gtm_putmsg_csa(CSA_ARG(REG2CSA(rptr->reg)) VARLSTCNT(1) ERR_NOTRNDMACC);
error_mupip = TRUE;
}
}
@@ -582,7 +585,7 @@ void mupip_backup(void)
TP_CHANGE_REG(gv_cur_region);
if (gv_cur_region->read_only)
{
- gtm_putmsg(VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(gv_cur_region));
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(gv_cur_region));
rptr->not_this_time = give_up_before_create_tempfile;
continue;
}
@@ -595,8 +598,8 @@ void mupip_backup(void)
* overcome with more code to deal with the larger block sizes much like the regular
* backup does but this is not being done as part of this (64bittn) project. SE 2/2005
*/
- gtm_putmsg(VARLSTCNT(5) MAKE_MSG_TYPE(ERR_MUNOSTRMBKUP, ERROR), 3, DB_LEN_STR(gv_cur_region),
- 32 * 1024 - DISK_BLOCK_SIZE);
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(5) MAKE_MSG_TYPE(ERR_MUNOSTRMBKUP, ERROR), 3,
+ DB_LEN_STR(gv_cur_region), 32 * 1024 - DISK_BLOCK_SIZE);
rptr->not_this_time = give_up_before_create_tempfile;
continue;
}
@@ -637,7 +640,8 @@ void mupip_backup(void)
/* verify the accessibility of the tempdir */
if (FILE_STAT_ERROR == (fstat_res = gtm_file_stat(&tempdir_trans, NULL, &tempdir_full, FALSE, &ustatus)))
{
- gtm_putmsg(VARLSTCNT(5) ERR_FILEPARSE, 2, tempdir_trans.len, tempdir_trans.addr, ustatus);
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(5) ERR_FILEPARSE, 2, tempdir_trans.len,
+ tempdir_trans.addr, ustatus);
mubclnup(rptr, need_to_del_tempfile);
mupip_exit(ustatus);
}
@@ -655,7 +659,8 @@ void mupip_backup(void)
} else
util_out_print("!/Cannot create the temporary file in directory !AD for online backup",
TRUE, tempdir_trans.len, tempdir_trans.addr);
- gtm_putmsg(VARLSTCNT(1) status);
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(1) status);
+ error_condition = status;
util_out_print("!/MUPIP cannot start backup with above errors!/", TRUE);
mubclnup(rptr, need_to_del_tempfile);
mupip_exit(status);
@@ -676,7 +681,8 @@ void mupip_backup(void)
{
status = errno;
util_out_print("!/Error re-opening temporary file created by mkstemp()!/", TRUE);
- gtm_putmsg(VARLSTCNT(1) status);
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(1) status);
+ error_condition = status;
util_out_print("!/MUPIP cannot start backup with above errors!/", TRUE);
mubclnup(rptr, need_to_del_tempfile);
mupip_exit(status);
@@ -697,12 +703,12 @@ void mupip_backup(void)
if (-1 != fstat_res)
if (gtm_set_group_and_perm(&stat_buf, &group_id, &perm, PERM_FILE, &pdd) < 0)
{
- send_msg(VARLSTCNT(6+PERMGENDIAG_ARG_COUNT)
+ send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(6+PERMGENDIAG_ARG_COUNT)
ERR_PERMGENFAIL, 4, RTS_ERROR_STRING("backup file"),
RTS_ERROR_STRING(
((unix_db_info *)(gv_cur_region->dyn.addr->file_cntl->file_info))->fn),
PERMGENDIAG_ARGS(pdd));
- gtm_putmsg(VARLSTCNT(6+PERMGENDIAG_ARG_COUNT)
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(6+PERMGENDIAG_ARG_COUNT)
ERR_PERMGENFAIL, 4, RTS_ERROR_STRING("backup file"),
RTS_ERROR_STRING(
((unix_db_info *)(gv_cur_region->dyn.addr->file_cntl->file_info))->fn),
@@ -717,7 +723,8 @@ void mupip_backup(void)
|| ((-1 != group_id) && (-1 == fchown(rptr->backup_fd, -1, group_id))))
{
status = errno;
- gtm_putmsg(VARLSTCNT(1) status);
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(1) status);
+ error_condition = status;
util_out_print("!/MUPIP cannot start backup with above errors!/", TRUE);
mubclnup(rptr, need_to_del_tempfile);
mupip_exit(status);
@@ -745,7 +752,7 @@ void mupip_backup(void)
{
util_out_print("!/Unable to resolve concealed definition for file !AD ", TRUE,
temp_file_name_len, tempfilename);
- gtm_putmsg(VARLSTCNT(1) ustatus);
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(1) ustatus);
mubclnup(rptr, need_to_del_tempfile);
mupip_exit(ERR_MUNOACTION);
}
@@ -778,7 +785,7 @@ void mupip_backup(void)
{
util_out_print("!/Cannot create the temporary file !AD for online backup.", TRUE,
LEN_AND_STR(tempfilename));
- gtm_putmsg(VARLSTCNT(1) status);
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(1) status);
mubclnup(rptr, need_to_del_tempfile);
mupip_exit(ERR_MUNOACTION);
}
@@ -796,7 +803,7 @@ void mupip_backup(void)
if ((TRUE == mu_ctrly_occurred) || (TRUE == mu_ctrlc_occurred))
{
mubclnup(rptr, need_to_del_tempfile);
- gtm_putmsg(VARLSTCNT(1) ERR_FREEZECTRL);
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(1) ERR_FREEZECTRL);
mupip_exit(ERR_MUNOFINISH);
}
}
@@ -808,7 +815,7 @@ void mupip_backup(void)
if ((TRUE == mu_ctrly_occurred) || (TRUE == mu_ctrlc_occurred))
{
mubclnup(rptr, need_to_del_tempfile);
- gtm_putmsg(VARLSTCNT(1) ERR_BACKUPCTRL);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_BACKUPCTRL);
mupip_exit(ERR_MUNOFINISH);
}
# ifdef UNIX
@@ -861,14 +868,14 @@ void mupip_backup(void)
{
if (!ftok_sem_get(jnlpool.jnlpool_dummy_reg, TRUE, REPLPOOL_ID, FALSE))
{
- gtm_putmsg(VARLSTCNT(1) ERR_JNLPOOLSETUP);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JNLPOOLSETUP);
error_mupip = TRUE;
goto repl_inst_bkup_done1;
}
decr_cnt = TRUE;
} else if (!ftok_sem_lock(reg, FALSE, FALSE))
{
- gtm_putmsg(VARLSTCNT(1) ERR_JNLPOOLSETUP);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JNLPOOLSETUP);
error_mupip = TRUE;
goto repl_inst_bkup_done1;
}
@@ -878,7 +885,7 @@ void mupip_backup(void)
assert(udi->ftok_semid && (INVALID_SEMID != udi->ftok_semid));
if (!ftok_sem_lock(jnlpool.jnlpool_dummy_reg, FALSE, FALSE))
{
- gtm_putmsg(VARLSTCNT(1) ERR_JNLPOOLSETUP);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JNLPOOLSETUP);
error_mupip = TRUE;
goto repl_inst_bkup_done1;
}
@@ -896,11 +903,11 @@ void mupip_backup(void)
{
assert(inst_hdr->crash);
semarg.buf = &semstat;
- if (-1 == semctl(sem_id, 0, IPC_STAT, semarg))
+ if (-1 == semctl(sem_id, DB_CONTROL_SEM, IPC_STAT, semarg))
{
save_errno = errno;
SNPRINTF(scndry_msg, OUT_BUFF_SIZE, "Error with semctl on Journal Pool SEMID (%d)", sem_id);
- gtm_putmsg(VARLSTCNT(9) ERR_REPLREQROLLBACK, 2, full_len, udi->fn,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_REPLREQROLLBACK, 2, full_len, udi->fn,
ERR_TEXT, 2, LEN_AND_STR(scndry_msg), save_errno);
error_mupip = TRUE;
goto repl_inst_bkup_done1;
@@ -908,7 +915,7 @@ void mupip_backup(void)
{
SNPRINTF(scndry_msg, OUT_BUFF_SIZE, "Creation time for Journal Pool SEMID (%d) is %d; Expected %d",
sem_id, semarg.buf->sem_ctime, inst_hdr->jnlpool_semid_ctime);
- gtm_putmsg(VARLSTCNT(8) ERR_REPLREQROLLBACK, 2, full_len, udi->fn,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_REPLREQROLLBACK, 2, full_len, udi->fn,
ERR_TEXT, 2, LEN_AND_STR(scndry_msg));
error_mupip = TRUE;
goto repl_inst_bkup_done1;
@@ -918,13 +925,14 @@ void mupip_backup(void)
if (SS_NORMAL != status)
{
save_errno = errno;
- gtm_putmsg(VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Error with journal pool access semaphore"),
UNIX_ONLY(save_errno) VMS_ONLY(REPL_SEM_ERRNO));
error_mupip = TRUE;
goto repl_inst_bkup_done1;
}
udi->grabbed_access_sem = TRUE;
+ udi->counter_acc_incremented = TRUE;
}
/* At this point, we either hold the access control lock on the journal pool OR the journal pool
* semaphore doesn't exist. In either case, we can proceed with the "cp" of the instance file
@@ -933,7 +941,7 @@ void mupip_backup(void)
if (inst_hdr->file_corrupt)
{
SNPRINTF(scndry_msg, OUT_BUFF_SIZE, "Instance file header has file_corrupt field set to TRUE");
- gtm_putmsg(VARLSTCNT(8) ERR_REPLREQROLLBACK, 2, full_len, udi->fn,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_REPLREQROLLBACK, 2, full_len, udi->fn,
ERR_TEXT, 2, LEN_AND_STR(scndry_msg));
error_mupip = TRUE;
}
@@ -1055,7 +1063,7 @@ repl_inst_bkup_done1:
}
assert(!kip_count);
UNIX_ONLY(GET_C_STACK_FOR_KIP(kip_pids_arr_ptr, crit_counter, MAX_CRIT_TRY, 2, MAX_KIP_PID_SLOTS));
- gtm_putmsg(VARLSTCNT(4) ERR_BACKUPKILLIP, 2, DB_LEN_STR(gv_cur_region));
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_BACKUPKILLIP, 2, DB_LEN_STR(gv_cur_region));
}
/* Now that we have crit, check if this region is actively journaled and if gbl_jrec_time needs to be
* adjusted (to ensure time ordering of journal records within this region's journal file).
@@ -1096,7 +1104,8 @@ repl_inst_bkup_done1:
memcpy(cmdptr, mu_repl_inst_reg_list->backup_file.addr, mu_repl_inst_reg_list->backup_file.len);
cmdptr += mu_repl_inst_reg_list->backup_file.len;
*cmdptr = '\0';
- if (0 != (rv = SYSTEM((char *)command)))
+ rv = SYSTEM(((char *)command));
+ if (0 != rv)
{
if (-1 == rv)
{
@@ -1121,9 +1130,9 @@ repl_inst_bkup_done1:
if (-1 == shmctl(shm_id, IPC_STAT, &shm_buf))
{
save_errno = errno;
- gtm_putmsg(VARLSTCNT(5) ERR_REPLPOOLINST, 3, shm_id,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_REPLPOOLINST, 3, shm_id,
RTS_ERROR_STRING(udi->fn));
- gtm_putmsg(VARLSTCNT(8) ERR_SYSCALL, 5,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5,
RTS_ERROR_LITERAL("shmctl()"), CALLFROM, save_errno);
error_mupip = TRUE;
goto repl_inst_bkup_done2;
@@ -1131,10 +1140,10 @@ repl_inst_bkup_done1:
if (-1 == (sm_long_t)(start_addr = (sm_uc_ptr_t) do_shmat(shm_id, 0, 0)))
{
save_errno = errno;
- gtm_putmsg(VARLSTCNT(5) ERR_REPLPOOLINST, 3, shm_id,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_REPLPOOLINST, 3, shm_id,
RTS_ERROR_STRING(udi->fn));
- gtm_putmsg(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("shmat()"), CALLFROM,
- save_errno);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5,
+ RTS_ERROR_LITERAL("shmat()"), CALLFROM, save_errno);
error_mupip = TRUE;
goto repl_inst_bkup_done2;
}
@@ -1165,7 +1174,7 @@ repl_inst_bkup_done1:
assert(!csa->hold_onto_crit);
jnlpool.jnlpool_ctl = (jnlpool_ctl_ptr_t)start_addr;
csa->critical = (mutex_struct_ptr_t)((sm_uc_ptr_t)jnlpool.jnlpool_ctl + JNLPOOL_CTL_SIZE);
- csa->nl = (node_local_ptr_t)((sm_uc_ptr_t)csa->critical + CRIT_SPACE
+ csa->nl = (node_local_ptr_t)((sm_uc_ptr_t)csa->critical + JNLPOOL_CRIT_SPACE
+ SIZEOF(mutex_spin_parms_struct));
/* Do the per process initialization of mutex stuff (needed before grab_lock is done) */
csa->onln_rlbk_cycle = jnlpool.jnlpool_ctl->onln_rlbk_cycle;
@@ -1174,7 +1183,7 @@ repl_inst_bkup_done1:
mutex_per_process_init();
UNIX_ONLY(START_HEARTBEAT_IF_NEEDED;)
} /* else journal pool already initialized in gvcst_init */
- grab_lock(jnlpool.jnlpool_dummy_reg, ASSERT_NO_ONLINE_ROLLBACK);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK);
jnl_seqno = jnlpool.jnlpool_ctl->jnl_seqno;
assert(0 != jnl_seqno);
/* All the cleanup we want is exactly done by the "repl_inst_histinfo_truncate" function. But
@@ -1196,10 +1205,10 @@ repl_inst_bkup_done1:
if (-1 == shmdt((caddr_t)start_addr))
{
save_errno = errno;
- gtm_putmsg(VARLSTCNT(5) ERR_REPLPOOLINST, 3, shm_id,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_REPLPOOLINST, 3, shm_id,
RTS_ERROR_STRING(udi->fn));
- gtm_putmsg(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("shmdt()"), CALLFROM,
- save_errno);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5,
+ RTS_ERROR_LITERAL("shmdt()"), CALLFROM, save_errno);
error_mupip = TRUE;
goto repl_inst_bkup_done2;
}
@@ -1278,7 +1287,7 @@ repl_inst_bkup_done2:
{
if (0 != cs_addrs->hdr->abandoned_kills)
{
- gtm_putmsg(VARLSTCNT(6) ERR_KILLABANDONED, 4, DB_LEN_STR(rptr->reg),
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(6) ERR_KILLABANDONED, 4, DB_LEN_STR(rptr->reg),
LEN_AND_LIT("backup database could have incorrectly marked busy integrity errors"));
}
sbufh_p = cs_addrs->shmpool_buffer;
@@ -1287,7 +1296,7 @@ repl_inst_bkup_done2:
if (TRUE == is_proc_alive(sbufh_p->backup_pid, sbufh_p->backup_image_count))
{
/* someone else is doing the backup */
- gtm_putmsg(VARLSTCNT(5) ERR_BKUPRUNNING, 3,
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(5) ERR_BKUPRUNNING, 3,
sbufh_p->backup_pid, REG_LEN_STR(rptr->reg));
rptr->not_this_time = give_up_after_create_tempfile;
/* Decerement counter so that inhibited KILLs can now proceed */
@@ -1325,7 +1334,7 @@ repl_inst_bkup_done2:
{
util_out_print("!/Journal file !AD not closed:",
TRUE, jnl_info.jnl_len, jnl_info.jnl);
- gtm_putmsg(VARLSTCNT(1) status);
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(1) status);
rptr->not_this_time = give_up_after_create_tempfile;
DECR_INHIBIT_KILLS(cs_addrs->nl);
rel_crit(rptr->reg);
@@ -1340,7 +1349,7 @@ repl_inst_bkup_done2:
if (FILE_STAT_ERROR == (jnl_fstat =
gtm_file_stat(&filestr, NULL, NULL, FALSE, &ustatus)))
{
- gtm_putmsg(VARLSTCNT(5) ERR_JNLFNF, 2,
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(5) ERR_JNLFNF, 2,
filestr.len, filestr.addr, ustatus);
rptr->not_this_time = give_up_after_create_tempfile;
DECR_INHIBIT_KILLS(cs_addrs->nl);
@@ -1365,15 +1374,15 @@ repl_inst_bkup_done2:
jnl_info.jnl_state = jnl_open;
jnl_info.repl_state = repl_open;
jnl_info.no_prev_link = TRUE;
- gtm_putmsg(VARLSTCNT(8) ERR_REPLSTATE, 6,
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) ERR_REPLSTATE, 6,
LEN_AND_LIT(FILE_STR), DB_LEN_STR(gv_cur_region),
LEN_AND_STR(repl_state_lit[repl_open]));
- gtm_putmsg(VARLSTCNT(8) ERR_JNLSTATE, 6,
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) ERR_JNLSTATE, 6,
LEN_AND_LIT(FILE_STR), DB_LEN_STR(gv_cur_region),
LEN_AND_STR(jnl_state_lit[jnl_open]));
} else if (!REPL_ALLOWED(cs_data))
{
- gtm_putmsg(VARLSTCNT(8) ERR_REPLSTATEERR, 2,
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) ERR_REPLSTATEERR, 2,
DB_LEN_STR(gv_cur_region), ERR_TEXT, 2,
LEN_AND_LIT("Standalone access required"));
rptr->not_this_time = give_up_after_create_tempfile;
@@ -1386,7 +1395,7 @@ repl_inst_bkup_done2:
{ /* Do not switch journal file when replication was turned
OFF by jnl_file_lost() */
assert(cs_data->jnl_state == jnl_closed);
- gtm_putmsg(VARLSTCNT(10) ERR_REPLJNLCNFLCT, 8,
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(10) ERR_REPLJNLCNFLCT, 8,
LEN_AND_STR(jnl_state_lit[jnl_open]),
DB_LEN_STR(gv_cur_region),
LEN_AND_STR(repl_state_lit[repl_closed]),
@@ -1406,7 +1415,7 @@ repl_inst_bkup_done2:
if (EXIT_NRM == cre_jnl_file(&jnl_info))
{
if (jnl_info.no_prev_link && (save_no_prev_link != jnl_info.no_prev_link))
- gtm_putmsg(VARLSTCNT(6) ERR_PREVJNLLINKCUT, 4,
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(6) ERR_PREVJNLLINKCUT, 4,
JNL_LEN_STR(cs_data), DB_LEN_STR(rptr->reg));
memcpy(cs_data->jnl_file_name, jnl_info.jnl, jnl_info.jnl_len);
cs_data->jnl_file_name[jnl_info.jnl_len] = '\0';
@@ -1421,12 +1430,13 @@ repl_inst_bkup_done2:
cs_data->jnl_sync_io = sync_io;
cs_data->jnl_checksum = jnl_info.checksum;
cs_data->jnl_eovtn = cs_data->trans_hist.curr_tn;
- gtm_putmsg(VARLSTCNT(10) ERR_JNLCREATE, 8, jnl_info.jnl_len, jnl_info.jnl,
- LEN_AND_LIT("region"), REG_LEN_STR(gv_cur_region),
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(10) ERR_JNLCREATE, 8,
+ jnl_info.jnl_len, jnl_info.jnl, LEN_AND_LIT("region"),
+ REG_LEN_STR(gv_cur_region),
LEN_AND_STR(before_image_lit[(jnl_info.before_images ? 1 : 0)]));
if (JNL_ENABLED(cs_data) &&
(jnl_options[jnl_noprevjnlfile] || !keep_prev_link))
- gtm_putmsg(VARLSTCNT(6) ERR_PREVJNLLINKCUT,
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(6) ERR_PREVJNLLINKCUT,
4, JNL_LEN_STR(cs_data), DB_LEN_STR(gv_cur_region));
fc = gv_cur_region->dyn.addr->file_cntl;
fc->op = FC_WRITE;
@@ -1436,9 +1446,11 @@ repl_inst_bkup_done2:
status = dbfilop(fc);
if (SS_NORMAL != status)
{
- UNIX_ONLY(gtm_putmsg(VARLSTCNT(7) ERR_DBFILERR, 2,
+ UNIX_ONLY(gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(7)
+ ERR_DBFILERR, 2,
DB_LEN_STR(gv_cur_region), 0, status, 0);)
- VMS_ONLY(gtm_putmsg(VARLSTCNT(9) ERR_DBFILERR, 2,
+ VMS_ONLY(gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(9)
+ ERR_DBFILERR, 2,
DB_LEN_STR(gv_cur_region), 0, status, 0,
gds_info->fab->fab$l_stv, 0);)
rptr->not_this_time = give_up_after_create_tempfile;
@@ -1448,13 +1460,15 @@ repl_inst_bkup_done2:
continue;
}
} else
- gtm_putmsg(VARLSTCNT(4) ERR_JNLNOCREATE, 2, jnl_info.jnl_len, jnl_info.jnl);
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_JNLNOCREATE, 2,
+ jnl_info.jnl_len, jnl_info.jnl);
} else
- gtm_putmsg(VARLSTCNT(4) MAKE_MSG_WARNING(ERR_JNLDISABLE),
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) MAKE_MSG_WARNING(ERR_JNLDISABLE),
2, DB_LEN_STR(gv_cur_region));
} else if (replication_on && !REPL_ENABLED(cs_data))
{
- gtm_putmsg(VARLSTCNT(8) ERR_REPLSTATEERR, 2, DB_LEN_STR(gv_cur_region),
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(8)
+ ERR_REPLSTATEERR, 2, DB_LEN_STR(gv_cur_region),
ERR_TEXT, 2,
LEN_AND_LIT("Cannot turn replication ON without also switching journal file"));
rptr->not_this_time = give_up_after_create_tempfile;
@@ -1465,7 +1479,7 @@ repl_inst_bkup_done2:
}
if (FALSE == shmpool_lock_hdr(gv_cur_region))
{
- gtm_putmsg(VARLSTCNT(9) ERR_DBCCERR, 2, REG_LEN_STR(gv_cur_region),
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(9) ERR_DBCCERR, 2, REG_LEN_STR(gv_cur_region),
ERR_ERRCALL, 3, CALLFROM);
rptr->not_this_time = give_up_after_create_tempfile;
DECR_INHIBIT_KILLS(cs_addrs->nl);
@@ -1548,7 +1562,7 @@ repl_inst_bkup_done2:
}
if (jnl_options[jnl_off] || bkdbjnl_off_specified ||
jnl_options[jnl_disable] || bkdbjnl_disable_specified)
- gtm_putmsg(VARLSTCNT(8) ERR_JNLSTATE, 6, LEN_AND_LIT(FILE_STR),
+ gtm_putmsg_csa(CSA_ARG(REG2CSA(rptr->reg)) VARLSTCNT(8) ERR_JNLSTATE, 6, LEN_AND_LIT(FILE_STR),
rptr->backup_file.len, rptr->backup_file.addr,
LEN_AND_STR(jnl_state_lit[rptr->backup_hdr->jnl_state]));
}
@@ -1567,7 +1581,7 @@ repl_inst_bkup_done2:
* In either case, the BACKUP is unreliable. Cleanup and exit
*/
error_mupip = TRUE;
- gtm_putmsg(VARLSTCNT(1) ERR_DBROLLEDBACK);
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(1) ERR_DBROLLEDBACK);
break;
}
# endif
@@ -1586,7 +1600,7 @@ repl_inst_bkup_done2:
} else
{
mubclnup((backup_reg_list *)halt_ptr, need_to_rel_crit);
- gtm_putmsg(VARLSTCNT(1) ERR_BACKUPCTRL);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_BACKUPCTRL);
mupip_exit(ERR_MUNOFINISH);
}
/* =============================== STEP 5. clean up ============================================== */
@@ -1594,7 +1608,7 @@ repl_inst_bkup_done2:
REVERT;
if (mu_ctrly_occurred || mu_ctrlc_occurred)
{
- gtm_putmsg(VARLSTCNT(1) ERR_BACKUPCTRL);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_BACKUPCTRL);
ret = ERR_MUNOFINISH;
} else if (TRUE == error_mupip)
ret = ERR_MUNOFINISH;
diff --git a/sr_port/mupip_extend.c b/sr_port/mupip_extend.c
index e4f69da..0be62ed 100644
--- a/sr_port/mupip_extend.c
+++ b/sr_port/mupip_extend.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -79,7 +79,7 @@ void mupip_extend(void)
r_len = SIZEOF(regionname);
UNIX_ONLY(jnlpool_init_needed = TRUE);
if (cli_get_str("REG_NAME", regionname, &r_len) == FALSE)
- rts_error(VARLSTCNT(1) ERR_MUNODBNAME);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MUNODBNAME);
if (cli_get_int("BLOCKS",&tblocks))
{
if (tblocks < 1)
@@ -98,7 +98,7 @@ void mupip_extend(void)
}
if (i >= gd_header->n_regions)
{
- gtm_putmsg(VARLSTCNT(4) ERR_NOREGION, 2, r_len, regionname);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_NOREGION, 2, r_len, regionname);
mupip_exit(ERR_MUNOACTION);
}
if ((dba_bg != gv_cur_region->dyn.addr->acc_meth) && (dba_mm != gv_cur_region->dyn.addr->acc_meth))
@@ -127,7 +127,7 @@ void mupip_extend(void)
gvcst_init(gv_cur_region);
if (gv_cur_region->was_open)
{ /* This should not happen as extend works on only one region at a time, but handle for safety */
- gtm_putmsg(VARLSTCNT(4) ERR_DBOPNERR, 2, DB_LEN_STR(gv_cur_region));
+ gtm_putmsg_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(4) ERR_DBOPNERR, 2, DB_LEN_STR(gv_cur_region));
DB_IPCS_RESET(gv_cur_region);
mupip_exit(ERR_MUNOACTION);
}
@@ -147,7 +147,7 @@ void mupip_extend(void)
/* cannot extend for read_only database. */
if (gv_cur_region->read_only)
{
- gtm_putmsg(VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(gv_cur_region));
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(gv_cur_region));
DB_IPCS_RESET(gv_cur_region);
mupip_exit(ERR_MUNOACTION);
}
@@ -158,7 +158,7 @@ void mupip_extend(void)
grab_crit(gv_cur_region);
GRAB_UNFROZEN_CRIT(gv_cur_region, cs_addrs, cs_data);
old_total = cs_addrs->ti->total_blks;
- if ((uint4)NO_FREE_SPACE == (status = gdsfilext(blocks, old_total)))
+ if ((uint4)NO_FREE_SPACE == (status = GDSFILEXT(blocks, old_total, TRANS_IN_PROG_FALSE)))
{
rel_crit(gv_cur_region);
util_out_print("The extension failed on file !AD; check disk space and permissions.", TRUE,
diff --git a/sr_port/mupip_io_dev_dispatch.h b/sr_port/mupip_io_dev_dispatch.h
index d7a7932..cc5fe00 100644
--- a/sr_port/mupip_io_dev_dispatch.h
+++ b/sr_port/mupip_io_dev_dispatch.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -20,7 +20,7 @@
UNIX_ONLY(GBLDEF) VMS_ONLY(LITDEF) dev_dispatch_struct io_dev_dispatch_mupip[] =
{
# ifdef UNIX
- iotype(iott, iott, nil),
+ iotype(iott, iott, iott),
# else
ionil_dev,
# endif
diff --git a/sr_port/mupip_reorg.c b/sr_port/mupip_reorg.c
index 43a2b96..45a2882 100644
--- a/sr_port/mupip_reorg.c
+++ b/sr_port/mupip_reorg.c
@@ -1,6 +1,6 @@
/***************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -83,7 +83,8 @@ GBLREF bool mu_ctrly_occurred;
GBLREF boolean_t mu_reorg_process;
GBLREF gd_addr *gd_header;
GBLREF gd_region *gv_cur_region;
-GBLREF gv_key *gv_currkey_next_reorg;
+GBLREF gv_key *gv_currkey_next_reorg, *gv_currkey, *gv_altkey;
+GBLREF int gv_keysize;
GBLREF gv_namehead *reorg_gv_target;
GBLREF sgmnt_data_ptr_t cs_data;
GBLREF sgmnt_addrs *cs_addrs;
@@ -113,6 +114,7 @@ void mupip_reorg(void)
node_local_ptr_t cnl;
trunc_region *reg_list, *tmp_reg, *reg_iter, *prev_reg;
uint4 fs;
+ uint4 lcl_pid;
# endif
DCL_THREADGBL_ACCESS;
@@ -215,7 +217,7 @@ void mupip_reorg(void)
/* gv_select will select globals for this clause */
gv_select(cli_buff, n_len, FALSE, "EXCLUDE", &exclude_gl_head, ®_max_rec, ®_max_key, ®_max_blk, FALSE);
if (!exclude_gl_head.next)
- gtm_putmsg(VARLSTCNT(1) ERR_NOEXCLUDE);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOEXCLUDE);
}
n_len = SIZEOF(cli_buff);
memset(cli_buff, 0, n_len);
@@ -234,7 +236,7 @@ void mupip_reorg(void)
gv_select(cli_buff, n_len, FALSE, "SELECT", &gl_head, ®_max_rec, ®_max_key, ®_max_blk, restrict_reg);
if (!gl_head.next)
{
- rts_error(VARLSTCNT(1) ERR_NOSELECT);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOSELECT);
mupip_exit(ERR_NOSELECT);
}
TREF(want_empty_gvts) = FALSE;
@@ -242,7 +244,10 @@ void mupip_reorg(void)
root_swap_statistic = 0;
mu_reorg_process = TRUE;
assert(NULL == gv_currkey_next_reorg);
- GVKEY_INIT(gv_currkey_next_reorg, DBKEYSIZE(MAX_KEY_SZ));
+ gv_keysize = DBKEYSIZE(MAX_KEY_SZ);
+ GVKEY_INIT(gv_currkey_next_reorg, gv_keysize);
+ GVKEY_INIT(gv_currkey, gv_keysize);
+ GVKEY_INIT(gv_altkey, gv_keysize);
reorg_gv_target = targ_alloc(MAX_KEY_SZ, NULL, NULL);
reorg_gv_target->hist.depth = 0;
reorg_gv_target->alt_hist->depth = 0;
@@ -252,7 +257,7 @@ void mupip_reorg(void)
util_out_print("Global: !AD ", FLUSH, gl_ptr->name.str.len, gl_ptr->name.str.addr);
if (in_exclude_list((uchar_ptr_t)gl_ptr->name.str.addr, gl_ptr->name.str.len, &exclude_gl_head))
{
- gtm_putmsg(VARLSTCNT(4) ERR_EXCLUDEREORG, 2, gl_ptr->name.str.len, gl_ptr->name.str.addr);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_EXCLUDEREORG, 2, gl_ptr->name.str.len, gl_ptr->name.str.addr);
reorg_success = FALSE;
continue;
}
@@ -266,52 +271,50 @@ void mupip_reorg(void)
SET_GV_CURRKEY_FROM_REORG_GV_TARGET;
# ifdef GTM_TRUNCATE
if (truncate)
- /* No need to move root blocks unless truncating */
+ { /* No need to move root blocks unless truncating */
cur_success &= mu_swap_root(&gl_ptr->name, &root_swap_statistic);
- /* if we successfully reorged this global, add its corresponding region to the set (list) of regions to truncate */
- if (cur_success)
- {
- for (reg_iter = reg_list, prev_reg = reg_list; reg_iter; reg_iter = reg_iter->next)
- if (reg_iter->reg == gv_cur_region)
- break;
- else
- prev_reg = reg_iter;
- if (NULL == reg_iter)
- {
- tmp_reg = (trunc_region *)malloc(SIZEOF(trunc_region));
- tmp_reg->reg = gv_cur_region;
- tmp_reg->next = NULL;
- if (NULL == reg_list)
- reg_list = tmp_reg;
- else
- prev_reg->next = tmp_reg;
-# ifdef GTM_TRIGGER
- if (truncate)
- { /* Reorg ^#t in this region to move it out of the way. */
- gn = literal_hasht;
- util_out_print(" ", FLUSH);
- util_out_print("Global: !AD (region !AD)", FLUSH,
- gn.str.len, gn.str.addr, REG_LEN_STR(gv_cur_region));
- reorg_gv_target->gvname.var_name.addr = gn.str.addr;
- reorg_gv_target->gvname.var_name.len = gn.str.len;
- reorg_success &= mu_reorg(&gn, &exclude_gl_head, &resume, index_fill_factor,
- data_fill_factor, reorg_op);
- SET_GV_CURRKEY_FROM_REORG_GV_TARGET;
- reorg_success &= mu_swap_root(&gn, &root_swap_statistic);
+ if (cur_success)
+ { /* add region corresponding to this global to the set (list) of regions to truncate */
+ for (reg_iter = reg_list, prev_reg = reg_list; reg_iter; reg_iter = reg_iter->next)
+ if (reg_iter->reg == gv_cur_region)
+ break;
+ else
+ prev_reg = reg_iter;
+ if (NULL == reg_iter)
+ {
+ tmp_reg = (trunc_region *)malloc(SIZEOF(trunc_region));
+ tmp_reg->reg = gv_cur_region;
+ tmp_reg->next = NULL;
+ if (NULL == reg_list)
+ reg_list = tmp_reg;
+ else
+ prev_reg->next = tmp_reg;
+# ifdef GTM_TRIGGER
+ if (truncate)
+ { /* Reorg ^#t in this region to move it out of the way. */
+ gn = literal_hasht;
+ reorg_gv_target->gvname.var_name.addr = gn.str.addr;
+ reorg_gv_target->gvname.var_name.len = gn.str.len;
+ cur_success = mu_reorg(&gn, &exclude_gl_head, &resume, index_fill_factor,
+ data_fill_factor, reorg_op);
+ reorg_success &= cur_success;
+ SET_GV_CURRKEY_FROM_REORG_GV_TARGET;
+ reorg_success &= mu_swap_root(&gn, &root_swap_statistic);
+ }
+# endif
}
-# endif
}
}
# endif
if (mu_ctrlc_occurred || mu_ctrly_occurred)
{
- gtm_putmsg(VARLSTCNT(1) ERR_REORGCTRLY);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_REORGCTRLY);
mupip_exit(ERR_MUNOFINISH);
}
}
if (!reorg_success)
{
- rts_error(VARLSTCNT(1) ERR_REORGINC);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_REORGINC);
mupip_exit(ERR_REORGINC);
}
else if (truncate)
@@ -324,7 +327,7 @@ void mupip_reorg(void)
cli_get_int("TRUNCATE", (int4 *)&truncate_percent);
if (99 < truncate_percent)
{
- gtm_putmsg(VARLSTCNT(1) ERR_MUTRUNCPERCENT);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MUTRUNCPERCENT);
mupip_exit(ERR_MUTRUNCFAIL);
}
for (reg_iter = reg_list; reg_iter; reg_iter = reg_iter->next)
@@ -336,10 +339,12 @@ void mupip_reorg(void)
cnl = csa->nl;
/* Ensure only one truncate process at a time operates on given region */
grab_crit(gv_cur_region);
- if (cnl->trunc_pid && is_proc_alive(cnl->trunc_pid, 0))
+ lcl_pid = cnl->trunc_pid;
+ if (lcl_pid && is_proc_alive(lcl_pid, 0))
{
rel_crit(gv_cur_region);
- send_msg(VARLSTCNT(4) ERR_MUTRUNC1ATIME, 3, cnl->trunc_pid, REG_LEN_STR(gv_cur_region));
+ send_msg_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(4) ERR_MUTRUNC1ATIME, 3, lcl_pid,
+ REG_LEN_STR(gv_cur_region));
continue;
}
cnl->trunc_pid = process_id;
@@ -353,7 +358,7 @@ void mupip_reorg(void)
rel_crit(gv_cur_region);
if (mu_ctrlc_occurred || mu_ctrly_occurred)
{
- gtm_putmsg(VARLSTCNT(1) ERR_REORGCTRLY);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_REORGCTRLY);
mupip_exit(ERR_MUNOFINISH);
}
}
diff --git a/sr_port/mupip_reorg.h b/sr_port/mupip_reorg.h
index 7e03441..d6a749d 100644
--- a/sr_port/mupip_reorg.h
+++ b/sr_port/mupip_reorg.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -10,9 +10,6 @@
****************************************************************/
#ifndef MUPIP_REORG_DEFINED
-#define MUSWP_NONE 0
-#define MUSWP_INCR_ROOT_CYCLE 1
-#define MUSWP_FREE_BLK 2
/* prototypes */
diff --git a/sr_port/mupip_set.c b/sr_port/mupip_set.c
index 69d7535..8b0b19e 100644
--- a/sr_port/mupip_set.c
+++ b/sr_port/mupip_set.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -89,6 +89,7 @@ void mupip_set(void)
cli_present("RESERVED_BYTES") == CLI_PRESENT ||
cli_present("FLUSH_TIME") == CLI_PRESENT ||
cli_present("LOCK_SPACE") == CLI_PRESENT ||
+ cli_present("MUTEX_SLOTS") == CLI_PRESENT ||
cli_present("DEFER_TIME") == CLI_PRESENT ||
cli_present("WAIT_DISK") == CLI_PRESENT ||
cli_present("PARTIAL_RECOV_BYPASS") == CLI_PRESENT ||
diff --git a/sr_port/mupip_set_journal.c b/sr_port/mupip_set_journal.c
index 6062a2a..d02d7b8 100644
--- a/sr_port/mupip_set_journal.c
+++ b/sr_port/mupip_set_journal.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -145,7 +145,8 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn)
max_reg_seqno = 1;
if (!mupip_set_journal_parse(&jnl_options, &jnl_info))
{
- gtm_putmsg(VARLSTCNT(1) ERR_MUPCLIERR);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MUPCLIERR);
+ error_condition = ERR_MUPCLIERR;
return ERR_MUPCLIERR;
}
if (region && (NULL == grlist))
@@ -178,7 +179,7 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn)
{
if (dba_usr == rptr->reg->dyn.addr->acc_meth)
{
- gtm_putmsg(VARLSTCNT(6) ERR_UNIMPLOP, 0, ERR_TEXT, 2,
+ gtm_putmsg_csa(CSA_ARG(REG2CSA(rptr->reg)) VARLSTCNT(6) ERR_UNIMPLOP, 0, ERR_TEXT, 2,
LEN_AND_LIT("Journaling is not supported for access method USR"));
exit_status |= EXIT_WRN;
continue;
@@ -217,7 +218,7 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn)
assert(!gv_cur_region->was_open); /* In case mupip_set_file opened it, they must have closed */
if (gv_cur_region->read_only)
{
- gtm_putmsg(VARLSTCNT(4) ERR_DBPRIVERR, 2, DB_LEN_STR(gv_cur_region));
+ gtm_putmsg_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(4) ERR_DBPRIVERR, 2, DB_LEN_STR(gv_cur_region));
exit_status |= EXIT_RDONLY;
continue;
}
@@ -303,7 +304,8 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn)
rptr->state = ALLOCATED;
} else
{
- gtm_putmsg(VARLSTCNT(4) ERR_MUSTANDALONE, 2, DB_LEN_STR(gv_cur_region));
+ gtm_putmsg_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(4) ERR_MUSTANDALONE, 2,
+ DB_LEN_STR(gv_cur_region));
exit_status |= EXIT_ERR;
continue;
}
@@ -379,10 +381,7 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn)
jnl_info.alloc = (0 == csd->jnl_alq) ? JNL_ALLOC_DEF : csd->jnl_alq;
assert(JNL_ALLOC_DEF >= JNL_ALLOC_MIN);
if (JNL_ALLOC_MIN > jnl_info.alloc)
- { /* Fix file header in addition to fixing new journal file settings */
- csd->jnl_alq = JNL_ALLOC_MIN;
- jnl_info.alloc = JNL_ALLOC_MIN;
- }
+ jnl_info.alloc = JNL_ALLOC_MIN; /* Fix new journal settings. */
}
if (!jnl_options.alignsize_specified)
{
@@ -390,19 +389,18 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn)
csd->alignsize; /* In bytes */
assert(JNL_DEF_ALIGNSIZE >= JNL_MIN_ALIGNSIZE);
if ((DISK_BLOCK_SIZE * JNL_MIN_ALIGNSIZE) > jnl_info.alignsize)
- { /* Fix file header in addition to fixing new journal file settings */
- csd->alignsize = (DISK_BLOCK_SIZE * JNL_MIN_ALIGNSIZE);
- jnl_info.alignsize = (DISK_BLOCK_SIZE * JNL_MIN_ALIGNSIZE);
- }
+ jnl_info.alignsize = (DISK_BLOCK_SIZE * JNL_MIN_ALIGNSIZE); /* Fix new journal settings. */
}
if (jnl_info.alignsize <= csd->blk_size)
{
if (region)
- gtm_putmsg(VARLSTCNT(9) ERR_JNLALIGNTOOSM, 7, jnl_info.alignsize, csd->blk_size,
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(9) ERR_JNLALIGNTOOSM, 7,
+ jnl_info.alignsize, csd->blk_size,
LEN_AND_LIT("region"), REG_LEN_STR(gv_cur_region),
(DISK_BLOCK_SIZE * JNL_DEF_ALIGNSIZE));
else
- gtm_putmsg(VARLSTCNT(9) ERR_JNLALIGNTOOSM, 7, jnl_info.alignsize, csd->blk_size,
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(9) ERR_JNLALIGNTOOSM, 7,
+ jnl_info.alignsize, csd->blk_size,
LEN_AND_LIT("database file"), jnl_info.fn_len, jnl_info.fn,
(DISK_BLOCK_SIZE * JNL_DEF_ALIGNSIZE));
@@ -454,18 +452,19 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn)
*/
if (jnl_info.autoswitchlimit < jnl_info.alloc)
{
- gtm_putmsg(VARLSTCNT(7) ERR_JNLSWITCHTOOSM, 5, jnl_info.autoswitchlimit,
- jnl_info.alloc, DB_LEN_STR(gv_cur_region));
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(7) ERR_JNLSWITCHTOOSM, 5,
+ jnl_info.autoswitchlimit, jnl_info.alloc, DB_LEN_STR(gv_cur_region));
if (newjnlfiles)
- gtm_putmsg(VARLSTCNT(4) ERR_JNLNOCREATE, 2, jnl_info.jnl_len, jnl_info.jnl);
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_JNLNOCREATE, 2,
+ jnl_info.jnl_len, jnl_info.jnl);
exit_status |= EXIT_ERR;
break;
#ifdef UNIX
} else if (jnl_info.alloc + jnl_info.extend > jnl_info.autoswitchlimit
&& jnl_info.alloc != jnl_info.autoswitchlimit)
{
- gtm_putmsg(VARLSTCNT(8) ERR_JNLALLOCGROW, 6, jnl_info.alloc, jnl_info.autoswitchlimit,
- "database file", DB_LEN_STR(gv_cur_region));
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) ERR_JNLALLOCGROW, 6, jnl_info.alloc,
+ jnl_info.autoswitchlimit, "database file", DB_LEN_STR(gv_cur_region));
jnl_info.alloc = jnl_info.autoswitchlimit;
#endif
} else
@@ -482,15 +481,15 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn)
if (jnl_options.autoswitchlimit_specified || jnl_options.extension_specified
|| jnl_options.allocation_specified)
{ /* print rounding down of autoswitchlimit only if journal options were specified */
- gtm_putmsg(VARLSTCNT(8) ERR_JNLSWITCHSZCHG, 6,
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) ERR_JNLSWITCHSZCHG, 6,
jnl_info.autoswitchlimit, align_autoswitch,
jnl_info.alloc, jnl_info.extend, DB_LEN_STR(gv_cur_region));
}
jnl_info.autoswitchlimit = align_autoswitch;
if (JNL_AUTOSWITCHLIMIT_MIN > jnl_info.autoswitchlimit)
{
- gtm_putmsg(VARLSTCNT(5) ERR_JNLINVSWITCHLMT, 3, jnl_info.autoswitchlimit,
- JNL_AUTOSWITCHLIMIT_MIN, JNL_ALLOC_MAX);
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(5) ERR_JNLINVSWITCHLMT, 3,
+ jnl_info.autoswitchlimit, JNL_AUTOSWITCHLIMIT_MIN, JNL_ALLOC_MAX);
exit_status |= EXIT_ERR;
break;
}
@@ -506,9 +505,11 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn)
jnldef.len = SIZEOF(JNL_EXT_DEF) - 1;
if (FILE_STAT_ERROR == (new_stat_res = gtm_file_stat(&jnlfile, &jnldef, &tmpjnlfile, TRUE, &status)))
{
- gtm_putmsg(VARLSTCNT(5) ERR_FILEPARSE, 2, jnlfile.len, jnlfile.addr, status);
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(5) ERR_FILEPARSE, 2, jnlfile.len,
+ jnlfile.addr, status);
if (newjnlfiles)
- gtm_putmsg(VARLSTCNT(4) ERR_JNLNOCREATE, 2, jnlfile.len, jnlfile.addr);
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_JNLNOCREATE, 2,
+ jnlfile.len, jnlfile.addr);
exit_status |= EXIT_ERR;
break;
}
@@ -518,8 +519,9 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn)
/* Note: At this point jnlfile should have expanded journal name with extension */
if (MAX_FN_LEN + 1 < jnl_info.jnl_len)
{
- gtm_putmsg(VARLSTCNT(1) ERR_FILENAMETOOLONG);
- gtm_putmsg(VARLSTCNT(4) ERR_JNLNOCREATE, 2, jnl_info.jnl_len, jnl_info.jnl);
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(1) ERR_FILENAMETOOLONG);
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_JNLNOCREATE, 2,
+ jnl_info.jnl_len, jnl_info.jnl);
exit_status |= EXIT_ERR;
break;
}
@@ -531,9 +533,11 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn)
{
if (FILE_STAT_ERROR == (curr_stat_res = gtm_file_stat(&jnlfile, NULL, NULL, TRUE, &status)))
{
- gtm_putmsg(VARLSTCNT(5) ERR_FILEPARSE, 2, jnlfile.len, jnlfile.addr, status);
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(5) ERR_FILEPARSE, 2,
+ jnlfile.len, jnlfile.addr, status);
if (newjnlfiles)
- gtm_putmsg(VARLSTCNT(4) ERR_JNLNOCREATE, 2, jnl_info.jnl_len, jnl_info.jnl);
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_JNLNOCREATE, 2,
+ jnl_info.jnl_len, jnl_info.jnl);
exit_status |= EXIT_ERR;
break;
}
@@ -605,8 +609,10 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn)
}
if ((FILE_PRESENT & new_stat_res) && !safe_to_switch)
{
- gtm_putmsg(VARLSTCNT(4) ERR_FILEEXISTS, 2, jnl_info.jnl_len, jnl_info.jnl);
- gtm_putmsg(VARLSTCNT(4) ERR_JNLNOCREATE, 2, jnl_info.jnl_len, jnl_info.jnl);
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_FILEEXISTS, 2,
+ jnl_info.jnl_len, jnl_info.jnl);
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_JNLNOCREATE, 2,
+ jnl_info.jnl_len, jnl_info.jnl);
exit_status |= EXIT_ERR;
break;
}
@@ -625,14 +631,17 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn)
{
if (FILE_READONLY & curr_stat_res)
{
- gtm_putmsg(VARLSTCNT(4) ERR_JNLRDONLY, 2, JNL_LEN_STR(csd));
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_JNLRDONLY, 2,
+ JNL_LEN_STR(csd));
if (newjnlfiles)
- gtm_putmsg(VARLSTCNT(4) ERR_JNLNOCREATE, 2, jnl_info.jnl_len, jnl_info.jnl);
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4)
+ ERR_JNLNOCREATE, 2, jnl_info.jnl_len, jnl_info.jnl);
exit_status |= EXIT_RDONLY;
continue;
}
} else
- gtm_putmsg(VARLSTCNT(4) ERR_JNLFNF, 2, JNL_LEN_STR(csd));
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_JNLFNF, 2,
+ JNL_LEN_STR(csd));
}
if (!rptr->exclusive)
{
@@ -696,8 +705,10 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn)
# ifdef VMS
if (!jnlname_same && (FILE_PRESENT & new_stat_res))
{
- gtm_putmsg(VARLSTCNT(4) ERR_FILEEXISTS, 2, jnl_info.jnl_len, jnl_info.jnl);
- gtm_putmsg(VARLSTCNT(4) ERR_JNLNOCREATE, 2, jnl_info.jnl_len, jnl_info.jnl);
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4)
+ ERR_FILEEXISTS, 2, jnl_info.jnl_len, jnl_info.jnl);
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4)
+ ERR_JNLNOCREATE, 2, jnl_info.jnl_len, jnl_info.jnl);
exit_status |= EXIT_ERR;
break;
}
@@ -727,20 +738,21 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn)
if (EXIT_NRM != (status = cre_jnl_file(&jnl_info)))
{ /* There was an error attempting to create the journal file */
exit_status |= status;
- gtm_putmsg(VARLSTCNT(4) ERR_JNLNOCREATE, 2, jnl_info.jnl_len, jnl_info.jnl);
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_JNLNOCREATE, 2,
+ jnl_info.jnl_len, jnl_info.jnl);
continue;
}
csd->jnl_checksum = jnl_info.checksum;
csd->jnl_eovtn = csd->trans_hist.curr_tn;
- gtm_putmsg(VARLSTCNT(10) ERR_JNLCREATE, 8, jnl_info.jnl_len, jnl_info.jnl,
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(10) ERR_JNLCREATE, 8, jnl_info.jnl_len, jnl_info.jnl,
db_or_reg_len, db_or_reg, db_reg_name_len, db_reg_name,
LEN_AND_STR(before_image_lit[(jnl_info.before_images ? 1 : 0)]));
if ((!curr_jnl_present && (jnl_open == jnl_curr_state))
|| (curr_jnl_present && jnl_info.no_prev_link) || this_iter_prevlinkcut_error)
{
- gtm_putmsg(VARLSTCNT(6) ERR_PREVJNLLINKCUT, 4,
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(6) ERR_PREVJNLLINKCUT, 4,
jnl_info.jnl_len, jnl_info.jnl, DB_LEN_STR(gv_cur_region));
- send_msg(VARLSTCNT(6) ERR_PREVJNLLINKCUT, 4,
+ send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(6) ERR_PREVJNLLINKCUT, 4,
jnl_info.jnl_len, jnl_info.jnl, DB_LEN_STR(gv_cur_region));
}
}
@@ -757,13 +769,13 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn)
if (jnl_buffer_invalid)
{
SNPRINTF(s, JNLBUFFUPDAPNDX_SIZE, JNLBUFFUPDAPNDX, JNL_BUFF_PORT_MIN(csd), JNL_BUFFER_MAX);
- gtm_putmsg(VARLSTCNT(10)
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(10)
(region ? ERR_JNLBUFFREGUPD : ERR_JNLBUFFDBUPD), 4,
(region ? gv_cur_region->rname_len : jnl_info.fn_len),
(region ? gv_cur_region->rname : jnl_info.fn),
jnl_info.buffer, jnl_buffer_size, ERR_TEXT, 2, LEN_AND_STR(s));
} else
- gtm_putmsg(VARLSTCNT(6)
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(6)
(region ? ERR_JNLBUFFREGUPD : ERR_JNLBUFFDBUPD), 4,
(region ? gv_cur_region->rname_len : jnl_info.fn_len),
(region ? gv_cur_region->rname : jnl_info.fn),
@@ -793,11 +805,11 @@ uint4 mupip_set_journal(unsigned short db_fn_len, char *db_fn)
UNIX_ONLY(csd->yield_lmt = DEFAULT_YIELD_LIMIT;)
}
if (CLI_ABSENT != jnl_options.cli_journal || CLI_ABSENT != jnl_options.cli_replic_on)
- gtm_putmsg(VARLSTCNT(8) ERR_JNLSTATE, 6, db_or_reg_len, db_or_reg, db_reg_name_len, db_reg_name,
- LEN_AND_STR(jnl_state_lit[rptr->jnl_new_state]));
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) ERR_JNLSTATE, 6, db_or_reg_len, db_or_reg, db_reg_name_len,
+ db_reg_name, LEN_AND_STR(jnl_state_lit[rptr->jnl_new_state]));
if (CLI_ABSENT != jnl_options.cli_replic_on)
- gtm_putmsg(VARLSTCNT(8) ERR_REPLSTATE, 6, db_or_reg_len, db_or_reg, db_reg_name_len, db_reg_name,
- LEN_AND_STR(repl_state_lit[jnl_info.repl_state]));
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) ERR_REPLSTATE, 6, db_or_reg_len, db_or_reg, db_reg_name_len,
+ db_reg_name, LEN_AND_STR(repl_state_lit[jnl_info.repl_state]));
/* Write the updated information back to the database file */
fc->op = FC_WRITE;
fc->op_buff = (sm_uc_ptr_t)csd;
diff --git a/sr_port/muprec.h b/sr_port/muprec.h
index 2003d58..c175e98 100644
--- a/sr_port/muprec.h
+++ b/sr_port/muprec.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -154,7 +154,7 @@ error_def(ERR_MUJNLSTAT);
struct tm *tsp; \
\
short_time = (time_t)input_time; \
- tsp = localtime((const time_t *)&short_time); \
+ GTM_LOCALTIME(tsp, (const time_t *)&short_time); \
SPRINTF(time_str, "%04d/%02d/%02d %02d:%02d:%02d", \
(1900 + tsp->tm_year), (1 + tsp->tm_mon), tsp->tm_mday, tsp->tm_hour, tsp->tm_min, tsp->tm_sec); \
}
@@ -1088,27 +1088,6 @@ typedef struct onln_rlbk_reg_list_struct
assert(!holds_sem[RECV][RECV_SERV_OPTIONS_SEM]); \
}
-#define ASSERT_VALID_JNLPOOL(CSA) \
-{ \
- GBLREF jnlpool_ctl_ptr_t jnlpool_ctl; \
- GBLREF jnlpool_addrs jnlpool; \
- \
- assert(CSA && CSA->critical && CSA->nl); /* should have been setup in mu_rndwn_replpool */ \
- assert(jnlpool_ctl && (jnlpool_ctl == jnlpool.jnlpool_ctl)); \
- assert(CSA->critical == (mutex_struct_ptr_t)((sm_uc_ptr_t)jnlpool.jnlpool_ctl + JNLPOOL_CTL_SIZE)); \
- assert(CSA->nl == (node_local_ptr_t) ((sm_uc_ptr_t)CSA->critical + CRIT_SPACE \
- + SIZEOF(mutex_spin_parms_struct))); \
- assert(jnlpool_ctl->filehdr_off); \
- assert(jnlpool_ctl->srclcl_array_off > jnlpool.jnlpool_ctl->filehdr_off); \
- assert(jnlpool_ctl->sourcelocal_array_off > jnlpool.jnlpool_ctl->srclcl_array_off); \
- assert(jnlpool.repl_inst_filehdr == (repl_inst_hdr_ptr_t) ((sm_uc_ptr_t)jnlpool_ctl \
- + jnlpool_ctl->filehdr_off)); \
- assert(jnlpool.gtmsrc_lcl_array == (gtmsrc_lcl_ptr_t)((sm_uc_ptr_t)jnlpool_ctl \
- + jnlpool_ctl->srclcl_array_off)); \
- assert(jnlpool.gtmsource_local_array == (gtmsource_local_ptr_t)((sm_uc_ptr_t)jnlpool_ctl \
- + jnlpool_ctl->sourcelocal_array_off)); \
-}
-
/* Prototypes */
#ifdef UNIX
seq_num mur_get_max_strm_reg_seqno(int strm_index);
@@ -1122,7 +1101,7 @@ uint4 mur_back_processing(jnl_ctl_list **jjctl, boolean_t apply_pblk, seq_num
jnl_tm_t alt_tp_resolve_time);
uint4 mur_block_count_correct(reg_ctl_list *rctl);
int4 mur_blocks_free(reg_ctl_list *rctl);
-void mur_close_files(void);
+boolean_t mur_close_files(void);
void mur_close_file_extfmt(void);
int4 mur_cre_file_extfmt(jnl_ctl_list *jctl, int recstat);
boolean_t mur_do_wildcard(char *jnl_str, char *pat_str, int jnl_len, int pat_len);
diff --git a/sr_port/mur_apply_pblk.c b/sr_port/mur_apply_pblk.c
index 27f2c3d..b9e7a1a 100644
--- a/sr_port/mur_apply_pblk.c
+++ b/sr_port/mur_apply_pblk.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2003, 2012 Fidelity Information Services, Inc *
+ * Copyright 2003, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -46,17 +46,18 @@
#include "repl_msg.h"
#include "gtmsource.h"
#include <signal.h>
-GBLREF gd_region *gv_cur_region;
GBLREF volatile int4 db_fsync_in_prog; /* for DB_FSYNC macro usage */
GBLREF sigset_t block_sigsent;
GBLREF boolean_t blocksig_initialized;
GBLREF jnlpool_addrs jnlpool;
#endif
+GBLREF gd_region *gv_cur_region;
GBLREF reg_ctl_list *mur_ctl;
GBLREF mur_gbls_t murgbl;
GBLREF mur_opt_struct mur_options;
GBLREF seq_num seq_num_zero;
GBLREF jnl_gbls_t jgbl;
+GBLREF sgmnt_data_ptr_t cs_data;
error_def(ERR_JNLREAD);
error_def(ERR_JNLREADBOF);
@@ -84,6 +85,7 @@ uint4 mur_apply_pblk(boolean_t apply_intrpt_pblk)
for (rctl = mur_ctl, rctl_top = mur_ctl + murgbl.reg_total; rctl < rctl_top; rctl++)
{
+ TP_CHANGE_REG(rctl->gd);
if (!apply_intrpt_pblk)
{
assert(NULL != rctl->jctl_turn_around);
@@ -257,8 +259,8 @@ uint4 mur_apply_pblk(boolean_t apply_intrpt_pblk)
} else if (jctl->rec_offset < jctl->jfh->turn_around_offset)
{
PRINT_VERBOSE_STAT(jctl, "mur_apply_blk:turn_around_offset is bad");
- gtm_putmsg(VARLSTCNT(5) ERR_JNLBADRECFMT, 3, jctl->jnl_fn_len,
- jctl->jnl_fn, jctl->rec_offset);
+ gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(5) ERR_JNLBADRECFMT, 3,
+ jctl->jnl_fn_len, jctl->jnl_fn, jctl->rec_offset);
return ERR_JNLBADRECFMT;
}
}
@@ -273,17 +275,17 @@ uint4 mur_apply_pblk(boolean_t apply_intrpt_pblk)
break;
if (ERR_NOPREVLINK == status)
{
- gtm_putmsg(VARLSTCNT(4) ERR_NOPREVLINK, 2, jctl->jnl_fn_len, jctl->jnl_fn);
+ gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(4) ERR_NOPREVLINK, 2, jctl->jnl_fn_len, jctl->jnl_fn);
return ERR_NOPREVLINK;
} else if (ERR_JNLREADBOF == status)
{
- gtm_putmsg(VARLSTCNT(4) ERR_JNLREADBOF, 2, jctl->jnl_fn_len, jctl->jnl_fn);
+ gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(4) ERR_JNLREADBOF, 2, jctl->jnl_fn_len, jctl->jnl_fn);
return ERR_JNLREADBOF;
} else if (ERR_JNLREAD == status) /* This message is already issued in mur_read_file */
return ERR_JNLREAD;
if ((NULL != jctl->next_gen) || (jctl->rec_offset < jctl->jfh->end_of_data))
{
- gtm_putmsg(VARLSTCNT(5) ERR_JNLBADRECFMT, 3, jctl->jnl_fn_len,
+ gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(5) ERR_JNLBADRECFMT, 3, jctl->jnl_fn_len,
jctl->jnl_fn, jctl->rec_offset);
return status;
}
@@ -294,17 +296,17 @@ uint4 mur_apply_pblk(boolean_t apply_intrpt_pblk)
if (SS_NORMAL != mur_fread_eof_crash(jctl, jctl->jfh->end_of_data, jctl->rec_offset))
return ERR_JNLBADRECFMT;
} /* end infinite for */
- UNIX_ONLY(
- gv_cur_region = rctl->csa->region;
- udi = FILE_INFO(gv_cur_region);
- DB_FSYNC(gv_cur_region, udi, rctl->csa, db_fsync_in_prog, save_errno);
- if (0 != save_errno)
- {
- send_msg(VARLSTCNT(5) ERR_DBFSYNCERR, 2, DB_LEN_STR(gv_cur_region), save_errno);
- gtm_putmsg(VARLSTCNT(5) ERR_DBFSYNCERR, 2, DB_LEN_STR(gv_cur_region), save_errno);
- return ERR_DBFSYNCERR;
- }
- )
+# ifdef UNIX
+ assert(gv_cur_region == rctl->gd && rctl->gd == rctl->csa->region);
+ udi = FILE_INFO(gv_cur_region);
+ DB_FSYNC(gv_cur_region, udi, rctl->csa, db_fsync_in_prog, save_errno);
+ if (0 != save_errno)
+ {
+ send_msg_csa(CSA_ARG(rctl->csa) VARLSTCNT(5) ERR_DBFSYNCERR, 2, DB_LEN_STR(gv_cur_region), save_errno);
+ gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(5) ERR_DBFSYNCERR, 2, DB_LEN_STR(gv_cur_region), save_errno);
+ return ERR_DBFSYNCERR;
+ }
+# endif
}
return SS_NORMAL;
}
@@ -315,7 +317,8 @@ uint4 mur_output_pblk(reg_ctl_list *rctl)
file_control *db_ctl;
struct_jrec_blk pblkrec;
uchar_ptr_t pblkcontents, pblk_jrec_start;
- int4 size, fbw_size, fullblockwrite_len, blks_in_lmap;
+ int4 fullblockwrite_len, blks_in_lmap;
+ uint4 size, fbw_size;
sgmnt_addrs *csa, *repl_csa;
node_local *cnl;
sgmnt_data_ptr_t csd;
@@ -376,8 +379,8 @@ uint4 mur_output_pblk(reg_ctl_list *rctl)
db_ctl->op_pos = ((gtm_int64_t)(csd->blk_size / DISK_BLOCK_SIZE) * pblkrec.blknum) + csd->start_vbn;
/* Use jrec size even if downgrade may have shrunk block. If the block has an integ error, we don't run into any trouble. */
size = pblkrec.bsiz;
- assert(size <= csd->blk_size);
- if (size > csd->blk_size) /* safety check in pro to avoid buffer overflows */
+ assert(size <= (uint4)csd->blk_size);
+ if (size > (uint4)csd->blk_size) /* safety check in pro to avoid buffer overflows */
size = csd->blk_size;
/* If full-block-writes are enabled, round size up to next full logical filesys block. We want to use "dbfilop" to
* do the write but it does not honour full-block-writes setting. So prepare the buffer accordingly before invoking it.
@@ -451,8 +454,8 @@ uint4 mur_output_pblk(reg_ctl_list *rctl)
murgbl.incr_onln_rlbk_cycle = TRUE;
/* Now that we have started updating the database, do NOT honor any more interrupts like MUPIP STOP */
assert(NULL != jnlpool.repl_inst_filehdr);
- send_msg(VARLSTCNT(1) ERR_ORLBKNOSTP);
- gtm_putmsg(VARLSTCNT(1) ERR_ORLBKNOSTP);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ORLBKNOSTP);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ORLBKNOSTP);
assert(blocksig_initialized); /* set to TRUE at process startup time */
savemask = block_sigsent;
sigdelset(&savemask, SIGALRM); /* Block all signals except SIGALRM */
diff --git a/sr_port/mur_back_process.c b/sr_port/mur_back_process.c
index 4e46bdf..297249f 100644
--- a/sr_port/mur_back_process.c
+++ b/sr_port/mur_back_process.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -48,6 +48,7 @@
#ifdef GTM_TRUNCATE
#include "gdsfilext_nojnl.h"
#endif
+#include "have_crit.h"
GBLREF mur_gbls_t murgbl;
GBLREF reg_ctl_list *mur_ctl;
@@ -75,38 +76,54 @@ error_def(ERR_TEXT);
#define MAX_BACK_PROCESS_REDO_CNT 8
-#define SAVE_PRE_RESOLVE_SEQNO(rectype, rec_time, rec_token_seq, pre_resolve_seqno) \
+#define SAVE_PRE_RESOLVE_SEQNO(rectype, rec_time, rec_token_seq, pre_resolve_seqno) \
+{ \
+ if ((JRT_EPOCH == rectype) || (JRT_EOF == rectype)) \
+ { \
+ if (rec_token_seq > *pre_resolve_seqno) \
+ *pre_resolve_seqno = rec_token_seq; \
+ } else \
+ { \
+ if ((rec_token_seq + 1) > *pre_resolve_seqno) \
+ *pre_resolve_seqno = rec_token_seq + 1; \
+ } \
+ if (mur_options.verbose) \
+ { \
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_MUINFOUINT8, 4, LEN_AND_LIT("Pre-resolve seqno"), \
+ pre_resolve_seqno, pre_resolve_seqno); \
+ } \
+}
+
+#define MUR_BACK_PROCESS_ERROR(JCTL, JJCTL, MESSAGE_STRING) \
{ \
- if ((JRT_EPOCH == rectype) || (JRT_EOF == rectype)) \
- { \
- if (rec_token_seq > *pre_resolve_seqno) \
- *pre_resolve_seqno = rec_token_seq; \
- } else \
+ if (JCTL->after_end_of_data) \
{ \
- if ((rec_token_seq + 1) > *pre_resolve_seqno) \
- *pre_resolve_seqno = rec_token_seq + 1; \
+ *JJCTL = JCTL; \
+ return ERR_JNLBADRECFMT; \
} \
- if (mur_options.verbose) \
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_LIT(MESSAGE_STRING)); \
+ if (!mur_report_error(JCTL, MUR_JNLBADRECFMT)) \
{ \
- gtm_putmsg(VARLSTCNT(6) ERR_MUINFOUINT8, 4, LEN_AND_LIT("Pre-resolve seqno"), \
- pre_resolve_seqno, pre_resolve_seqno); \
- } \
+ *JJCTL = JCTL; \
+ return ERR_JNLBADRECFMT; \
+ } else \
+ continue; \
}
-#define MUR_BACK_PROCESS_ERROR(JCTL, JJCTL, MESSAGE_STRING) \
-{ \
- if (JCTL->after_end_of_data) \
- { \
- *JJCTL = JCTL; \
- return ERR_JNLBADRECFMT; \
- } \
- gtm_putmsg(VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_LIT(MESSAGE_STRING)); \
- if (!mur_report_error(JCTL, MUR_JNLBADRECFMT)) \
- { \
- *JJCTL = JCTL; \
- return ERR_JNLBADRECFMT; \
- } else \
- continue; \
+#define MUR_BACK_PROCESS_ERROR_STR(JCTL, JJCTL, MESSAGE_STRING) \
+{ \
+ if (JCTL->after_end_of_data) \
+ { \
+ *JJCTL = JCTL; \
+ return ERR_JNLBADRECFMT; \
+ } \
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_STR(MESSAGE_STRING)); \
+ if (!mur_report_error(JCTL, MUR_JNLBADRECFMT)) \
+ { \
+ *JJCTL = JCTL; \
+ return ERR_JNLBADRECFMT; \
+ } else \
+ continue; \
}
#ifdef VMS
@@ -186,6 +203,10 @@ error_def(ERR_TEXT);
} \
}
+#define TRANS_NUM_CONT_CHK_FAILED "Transaction number continuity check failed: [0x%08X] vs [0x%08X]"
+#define SEQ_NUM_CONT_CHK_FAILED "Sequence number continuity check failed: [0x%08X] vs [0x%08X]"
+#define TRANS_OR_SEQ_NUM_CONT_CHK_FAILED_SZ (MAX(SIZEOF(TRANS_NUM_CONT_CHK_FAILED), SIZEOF(SEQ_NUM_CONT_CHK_FAILED)) + 2 * 20)
+
STATICFNDCL void save_turn_around_point(reg_ctl_list *rctl, jnl_ctl_list *jctl, boolean_t apply_pblk);
STATICFNDEF void save_turn_around_point(reg_ctl_list *rctl, jnl_ctl_list *jctl, boolean_t apply_pblk)
@@ -258,8 +279,8 @@ boolean_t mur_back_process(boolean_t apply_pblk, seq_num *pre_resolve_seqno)
} else if (ERR_CHNGTPRSLVTM == status)
{
jnlrec = jctl->reg_ctl->mur_desc->jnlrec;
- gtm_putmsg(VARLSTCNT(6) ERR_CHNGTPRSLVTM, 4, jgbl.mur_tp_resolve_time, jnlrec->prefix.time,
- jctl->jnl_fn_len, jctl->jnl_fn);
+ gtm_putmsg_csa(CSA_ARG(jctl->reg_ctl->csa) VARLSTCNT(6) ERR_CHNGTPRSLVTM, 4, jgbl.mur_tp_resolve_time,
+ jnlrec->prefix.time, jctl->jnl_fn_len, jctl->jnl_fn);
assert(jgbl.mur_tp_resolve_time > jnlrec->prefix.time);
alt_tp_resolve_time = jnlrec->prefix.time;
} else /* An error message must have already been printed if status != SS_NORMAL */
@@ -315,6 +336,7 @@ uint4 mur_back_processing_one_region(mur_back_opt_t *mur_back_options)
# ifdef GTM_CRYPT
int gtmcrypt_errno;
# endif
+ char s[TRANS_OR_SEQ_NUM_CONT_CHK_FAILED_SZ]; /* for appending sequence or transaction number */
# ifdef GTM_TRUNCATE
uint4 cur_total, old_total;
# endif
@@ -360,13 +382,17 @@ uint4 mur_back_processing_one_region(mur_back_opt_t *mur_back_options)
MUR_BACK_PROCESS_ERROR(jctl, jjctl, "Checksum validation failed");
if ((jnlrec->prefix.tn != rec_tn) && (jnlrec->prefix.tn != (rec_tn - 1)))
{
+ SNPRINTF(s, TRANS_OR_SEQ_NUM_CONT_CHK_FAILED_SZ, TRANS_NUM_CONT_CHK_FAILED,
+ jnlrec->prefix.tn, rec_tn);
rec_tn = jnlrec->prefix.tn;
- MUR_BACK_PROCESS_ERROR(jctl, jjctl, "Transaction number continuty check failed");
+ MUR_BACK_PROCESS_ERROR_STR(jctl, jjctl, s);
}
if (mur_options.rollback && REC_HAS_TOKEN_SEQ(rectype) && (GET_JNL_SEQNO(jnlrec) > rec_token_seq))
{
+ SNPRINTF(s, TRANS_OR_SEQ_NUM_CONT_CHK_FAILED_SZ, SEQ_NUM_CONT_CHK_FAILED,
+ GET_JNL_SEQNO(jnlrec), rec_token_seq);
rec_token_seq = GET_JNL_SEQNO(jnlrec);
- MUR_BACK_PROCESS_ERROR(jctl, jjctl, "Sequence number continuty check failed");
+ MUR_BACK_PROCESS_ERROR_STR(jctl, jjctl, s);
}
if (IS_SET_KILL_ZKILL_ZTRIG_ZTWORM(rectype))
{
@@ -535,7 +561,7 @@ uint4 mur_back_processing_one_region(mur_back_opt_t *mur_back_options)
(NULL != rctl->csd) && (rec_tn > rctl->csd->trans_hist.curr_tn))
{
assert(FALSE);
- gtm_putmsg(VARLSTCNT(7) ERR_EPOCHTNHI, 5, jctl->rec_offset,
+ gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(7) ERR_EPOCHTNHI, 5, jctl->rec_offset,
jctl->jnl_fn_len, jctl->jnl_fn, &rec_tn, &rctl->csd->trans_hist.curr_tn);
MUR_BACK_PROCESS_ERROR(jctl, jjctl, "Epoch transaction number check failed");
}
@@ -543,10 +569,10 @@ uint4 mur_back_processing_one_region(mur_back_opt_t *mur_back_options)
{
if (mur_options.verbose)
{
- gtm_putmsg(VARLSTCNT(6) ERR_MUINFOUINT4, 4,
+ gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(6) ERR_MUINFOUINT4, 4,
LEN_AND_LIT(" First Epoch Record Offset"),
jctl->rec_offset, jctl->rec_offset);
- gtm_putmsg(VARLSTCNT(6) ERR_MUINFOUINT4, 4,
+ gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(6) ERR_MUINFOUINT4, 4,
LEN_AND_LIT(" First Epoch Record timestamp"), rec_time, rec_time);
}
first_epoch = FALSE;
@@ -797,7 +823,8 @@ uint4 mur_back_processing_one_region(mur_back_opt_t *mur_back_options)
save_turn_around_point(rctl, jctl, apply_pblk_this_region);
} else
{
- gtm_putmsg(VARLSTCNT(4) ERR_NOPREVLINK, 2, jctl->jnl_fn_len, jctl->jnl_fn);
+ gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(4) ERR_NOPREVLINK,
+ 2, jctl->jnl_fn_len, jctl->jnl_fn);
*jjctl = jctl;
return ERR_NOPREVLINK;
}
@@ -923,14 +950,14 @@ uint4 mur_back_processing(jnl_ctl_list **jjctl, boolean_t apply_pblk, seq_num *p
}
}
if (murgbl.resync_seqno)
- gtm_putmsg(VARLSTCNT(4) ERR_RESOLVESEQNO, 2, &murgbl.resync_seqno, &murgbl.resync_seqno);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_RESOLVESEQNO, 2, &murgbl.resync_seqno, &murgbl.resync_seqno);
UNIX_ONLY(
if (murgbl.resync_strm_seqno_nonzero)
{
for (idx = 0; idx < MAX_SUPPL_STRMS; idx++)
{
if (murgbl.resync_strm_seqno[idx])
- gtm_putmsg(VARLSTCNT(5) ERR_RESOLVESEQSTRM, 3, idx,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_RESOLVESEQSTRM, 3, idx,
&murgbl.resync_strm_seqno[idx], &murgbl.resync_strm_seqno[idx]);
}
/* If -resync=<strm_seqno> is specified, we dont yet know what jnl_seqno it maps back to.
@@ -991,8 +1018,8 @@ uint4 mur_back_processing(jnl_ctl_list **jjctl, boolean_t apply_pblk, seq_num *p
assert(jctl->reg_ctl == rctl);
assert(NULL == jctl->next_gen);
if (mur_options.verbose)
- gtm_putmsg(VARLSTCNT(6) ERR_MUINFOSTR, 4, LEN_AND_LIT("Processing started for journal file"),
- jctl->jnl_fn_len, jctl->jnl_fn);
+ gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(6) ERR_MUINFOSTR, 4,
+ LEN_AND_LIT("Processing started for journal file"), jctl->jnl_fn_len, jctl->jnl_fn);
jctl->rec_offset = jctl->lvrec_off;
status = mur_prev(jctl, jctl->rec_offset);
mur_desc = rctl->mur_desc;
diff --git a/sr_port/mur_block_count_correct.c b/sr_port/mur_block_count_correct.c
index e96f82b..3746950 100644
--- a/sr_port/mur_block_count_correct.c
+++ b/sr_port/mur_block_count_correct.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -102,7 +102,7 @@ uint4 mur_block_count_correct(reg_ctl_list *rctl)
bplmap = cs_data->bplmap;
new_blocks = (native_size - size)/(mu_data->blk_size / DISK_BLOCK_SIZE);
new_bit_maps = DIVIDE_ROUND_UP(total_blks + new_blocks, bplmap) - DIVIDE_ROUND_UP(total_blks, bplmap);
- if (SS_NORMAL != (status = gdsfilext(new_blocks - new_bit_maps, total_blks)))
+ if (SS_NORMAL != (status = GDSFILEXT(new_blocks - new_bit_maps, total_blks, TRANS_IN_PROG_FALSE)))
{
jgbl.dont_reset_gbl_jrec_time = TRUE;
return (status);
diff --git a/sr_port/mur_close_file_extfmt.c b/sr_port/mur_close_file_extfmt.c
index e33891b..4e93fb5 100644
--- a/sr_port/mur_close_file_extfmt.c
+++ b/sr_port/mur_close_file_extfmt.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2003, 2011 Fidelity Information Services, Inc *
+ * Copyright 2003, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -47,9 +47,10 @@
pars.str.len = SIZEOF(no_param); \
pars.str.addr = (char *)&no_param; \
val.mvtype = MV_STR; \
- \
val.str.len = ((unix_file_info *)file_info)->fn_len; \
val.str.addr = (char *) (((unix_file_info *)(file_info))->fn); \
+ if (NULL == val.str.addr) \
+ continue; \
op_close(&val, &pars); \
}
#elif defined(VMS)
diff --git a/sr_port/mur_close_files.c b/sr_port/mur_close_files.c
index b177259..4393974 100644
--- a/sr_port/mur_close_files.c
+++ b/sr_port/mur_close_files.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2003, 2012 Fidelity Information Services, Inc *
+ * Copyright 2003, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -66,18 +66,18 @@
#endif
#include "interlock.h"
-#define WARN_STATUS(jctl) \
-if (SS_NORMAL != jctl->status) \
-{ \
- assert(FALSE); \
- if (SS_NORMAL != jctl->status2) \
- gtm_putmsg(VARLSTCNT1(6) ERR_JNLWRERR, 2, jctl->jnl_fn_len, jctl->jnl_fn, \
- jctl->status, PUT_SYS_ERRNO(jctl->status2)); \
- else \
- gtm_putmsg(VARLSTCNT(5) ERR_JNLWRERR, \
- 2, jctl->jnl_fn_len, jctl->jnl_fn, jctl->status); \
- wrn_count++; \
-} \
+#define WARN_STATUS(jctl) \
+if (SS_NORMAL != jctl->status) \
+{ \
+ assert(FALSE); \
+ if (SS_NORMAL != jctl->status2) \
+ gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT1(6) ERR_JNLWRERR, 2, jctl->jnl_fn_len, jctl->jnl_fn, \
+ jctl->status, PUT_SYS_ERRNO(jctl->status2)); \
+ else \
+ gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_JNLWRERR, \
+ 2, jctl->jnl_fn_len, jctl->jnl_fn, jctl->status); \
+ wrn_count++; \
+} \
GBLREF void (*call_on_signal)();
GBLREF jnl_gbls_t jgbl;
@@ -103,7 +103,6 @@ error_def(ERR_JNLACTINCMPLT);
error_def(ERR_JNLBADLABEL);
error_def(ERR_JNLREAD);
error_def(ERR_JNLSTATE);
-error_def(ERR_JNLSTRESTFL);
error_def(ERR_JNLSUCCESS);
error_def(ERR_JNLWRERR);
error_def(ERR_MUJNLSTAT);
@@ -120,8 +119,7 @@ UNIX_ONLY(error_def(ERR_REPLFTOKSEM);)
UNIX_ONLY(error_def(ERR_RLBKSTRMSEQ);)
VMS_ONLY(error_def(ERR_SETREG2RESYNC);)
-
-void mur_close_files(void)
+boolean_t mur_close_files(void)
{
char *head_jnl_fn, *rename_fn, fn[MAX_FN_LEN];
int head_jnl_fn_len, wrn_count = 0, rename_fn_len;
@@ -158,7 +156,7 @@ void mur_close_files(void)
if (mur_close_files_done)
{
assert(mupip_exit_status_displayed);
- return;
+ return TRUE;
}
call_on_signal = NULL; /* Do not recurs via call_on_signal if there is an error */
SET_PROCESS_EXITING_TRUE; /* In case the database is encrypted, this value is used to avoid using
@@ -308,11 +306,13 @@ void mur_close_files(void)
csa->repl_state = csd->repl_state = rctl->repl_state;
/* After recover replication state is always closed */
if (rctl->repl_state != csd->repl_state)
- gtm_putmsg(VARLSTCNT(8) ERR_REPLSTATE, 6, LEN_AND_LIT(FILE_STR),
- DB_LEN_STR(reg), LEN_AND_STR(repl_state_lit[csd->repl_state]));
+ gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_REPLSTATE, 6,
+ LEN_AND_LIT(FILE_STR), DB_LEN_STR(reg),
+ LEN_AND_STR(repl_state_lit[csd->repl_state]));
if (rctl->jnl_state != csd->jnl_state)
- gtm_putmsg(VARLSTCNT(8) ERR_JNLSTATE, 6, LEN_AND_LIT(FILE_STR),
- DB_LEN_STR(reg), LEN_AND_STR(jnl_state_lit[csd->jnl_state]));
+ gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_JNLSTATE, 6,
+ LEN_AND_LIT(FILE_STR), DB_LEN_STR(reg),
+ LEN_AND_STR(jnl_state_lit[csd->jnl_state]));
# ifdef UNIX
if ((NULL != rctl->jctl) && !mur_options.rollback_losttnonly)
{
@@ -364,8 +364,9 @@ void mur_close_files(void)
{
csd->resync_seqno = csd->reg_seqno;
if (mur_options.verbose)
- gtm_putmsg(VARLSTCNT(6) ERR_SETREG2RESYNC, 4,
- &csd->resync_seqno, &csd->reg_seqno, DB_LEN_STR(reg));
+ gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_SETREG2RESYNC,
+ 4, &csd->resync_seqno, &csd->reg_seqno,
+ DB_LEN_STR(reg));
}
csd->reg_seqno = murgbl.consist_jnl_seqno;
if (csd->resync_seqno > murgbl.consist_jnl_seqno)
@@ -519,17 +520,17 @@ void mur_close_files(void)
* the rolled_bak prefix. user can decide to delete these */
rename_fn = fn;
prepare_unique_name((char *)end_jctl->jnl_fn, end_jctl->jnl_fn_len,
- PREFIX_ROLLED_BAK, "", rename_fn, &rename_fn_len, &ustatus);
+ PREFIX_ROLLED_BAK, "", rename_fn, &rename_fn_len, 0, &ustatus);
UNIX_ONLY(WAIT_FOR_REPL_INST_UNFREEZE_SAFE(csa));
/* wait for instance freeze before journal file renames */
if (SS_NORMAL == gtm_rename((char *)end_jctl->jnl_fn, end_jctl->jnl_fn_len,
rename_fn, rename_fn_len, &ustatus))
{
- gtm_putmsg(VARLSTCNT (6) ERR_FILERENAME, 4, end_jctl->jnl_fn_len,
+ gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT (6) ERR_FILERENAME, 4, end_jctl->jnl_fn_len,
end_jctl->jnl_fn, rename_fn_len, rename_fn);
} else
{
- gtm_putmsg(VARLSTCNT(6) ERR_RENAMEFAIL, 4,
+ gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_RENAMEFAIL, 4,
end_jctl->jnl_fn_len, end_jctl->jnl_fn, rename_fn_len, rename_fn);
wrn_count++;
}
@@ -587,7 +588,7 @@ void mur_close_files(void)
if (this_strm_seqno)
{
assert(0 == GET_STRM_INDEX(this_strm_seqno));
- gtm_putmsg(VARLSTCNT(5) ERR_RLBKSTRMSEQ, 3, idx,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_RLBKSTRMSEQ, 3, idx,
&this_strm_seqno, &this_strm_seqno);
}
}
@@ -606,7 +607,7 @@ void mur_close_files(void)
assert(!jgbl.onlnrlbk);
assert(anticipatory_freeze_available);
assert(!csa->hold_onto_crit);
- grab_lock(jnlpool.jnlpool_dummy_reg, ASSERT_NO_ONLINE_ROLLBACK);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK);
}
last_histinfo_seqno = repl_inst_histinfo_truncate(murgbl.consist_jnl_seqno);
if ((NULL != jnlpool_ctl) && !was_crit)
@@ -711,15 +712,17 @@ void mur_close_files(void)
UNIX_ONLY(rundown_status =) gds_rundown(); /* does the final rel_crit */
if (EXIT_NRM != rundown_status)
wrn_count++;
- assert(!rctl->standalone || (1 == (semval = semctl(udi->semid, 0, GETVAL))));
+ assert((EXIT_NRM != rundown_status) || !rctl->standalone
+ || (1 == (semval = semctl(udi->semid, 0, GETVAL))));
assert(!cs_addrs->now_crit && !cs_addrs->hold_onto_crit);
}
/* If this was a RECOVER/ROLLBACK and rctl->standalone is FALSE, then gvcst_init/mu_rndwn_file did not happen in
* successfully for this region. Increment wrn_count in this case
*/
assert(!mur_options.update || rctl->standalone || !murgbl.clean_exit);
- if (rctl->standalone && !db_ipcs_reset(reg))
- wrn_count++;
+ if (rctl->standalone UNIX_ONLY(&& EXIT_NRM == rundown_status))
+ if (!db_ipcs_reset(reg))
+ wrn_count++;
rctl->standalone = FALSE;
rctl->gd = NULL;
rctl->csa = NULL;
@@ -798,7 +801,8 @@ void mur_close_files(void)
}
ipcs_ptr = i2asc((uchar_ptr_t)ipcs_buff, repl_instance.jnlpool_shmid);
*ipcs_ptr = '\0';
- gtm_putmsg(VARLSTCNT(6) ERR_MUJPOOLRNDWNSUC, 4, LEN_AND_STR(ipcs_buff), LEN_AND_STR(udi->fn));
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_MUJPOOLRNDWNSUC, 4, LEN_AND_STR(ipcs_buff),
+ LEN_AND_STR(udi->fn));
/* Now that the journal pool shared memory is removed, go ahead and invalidate it in the file
* header
*/
@@ -851,17 +855,17 @@ void mur_close_files(void)
{ /* If inst_hdr is NULL, it means we exited even before getting standalone access on the journal pool.
* No point issuing the ORLBKCMPLT or ORLBKTERMNTD message because ORLBKSTART will not even be issued.
*/
- gtm_putmsg(VARLSTCNT(6) finish_err_code, 4, LEN_AND_STR(inst_hdr->inst_info.this_instname),
- LEN_AND_STR(udi->fn));
- send_msg(VARLSTCNT(6) finish_err_code, 4, LEN_AND_STR(inst_hdr->inst_info.this_instname),
- LEN_AND_STR(udi->fn));
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) finish_err_code, 4,
+ LEN_AND_STR(inst_hdr->inst_info.this_instname), LEN_AND_STR(udi->fn));
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(6) finish_err_code, 4,
+ LEN_AND_STR(inst_hdr->inst_info.this_instname), LEN_AND_STR(udi->fn));
}
}
# endif
mur_close_file_extfmt();
mur_free(); /* free up whatever was allocated by "mur_init" */
if (wrn_count)
- gtm_putmsg(VARLSTCNT (1) ERR_JNLACTINCMPLT);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT (1) ERR_JNLACTINCMPLT);
else if (!mupip_exit_status_displayed)
{ /* This exit path is not coming through "mupip_exit". Print an error message indicating incomplete recovery.
* The || in the assert below is to take care of a white-box test that primarily tests the
@@ -873,15 +877,22 @@ void mur_close_files(void)
&& ((WBTEST_MUR_ABNORMAL_EXIT_EXPECTED == gtm_white_box_test_case_number)
|| (WBTEST_TP_HIST_CDB_SC_BLKMOD == gtm_white_box_test_case_number)
|| (WBTEST_JNL_FILE_OPEN_FAIL == gtm_white_box_test_case_number)
- || (WBTEST_JNL_CREATE_FAIL == gtm_white_box_test_case_number)));
+ || (WBTEST_JNL_CREATE_FAIL == gtm_white_box_test_case_number)
+ || (WBTEST_RECOVER_ENOSPC == gtm_white_box_test_case_number)
+ || (WBTEST_WCS_FLU_FAIL == gtm_white_box_test_case_number)));
assert(!murgbl.clean_exit);
if (murgbl.wrn_count)
- gtm_putmsg(VARLSTCNT (1) ERR_JNLACTINCMPLT);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT (1) ERR_JNLACTINCMPLT);
else
- gtm_putmsg(VARLSTCNT (1) ERR_MUNOACTION);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT (1) ERR_MUNOACTION);
} else if (murgbl.clean_exit && !murgbl.wrn_count)
JNL_SUCCESS_MSG(mur_options);
JNL_PUT_MSG_PROGRESS("End processing");
mupip_exit_status_displayed = TRUE;
mur_close_files_done = TRUE;
+# if defined(UNIX) && defined(DEBUG)
+ if (WBTEST_ENABLED(WBTEST_RECOVER_ENOSPC) && (0 == gtm_white_box_test_case_count))
+ util_out_print("Total number of writes !UL",TRUE, gtm_wbox_input_test_case_count);
+# endif
+ return (0 == wrn_count);
}
diff --git a/sr_port/mur_forward.c b/sr_port/mur_forward.c
index f2d1787..e273751 100644
--- a/sr_port/mur_forward.c
+++ b/sr_port/mur_forward.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -168,7 +168,6 @@ uint4 mur_forward(jnl_tm_t min_broken_time, seq_num min_broken_seqno, seq_num lo
rctl->csa = cs_addrs;
cs_addrs->rctl = rctl;
rctl->csd = cs_data;
- cs_addrs->mm_core_hdr = (sgmnt_data_ptr_t)&(rctl->csd);
rctl->sgm_info_ptr = cs_addrs->sgm_info_ptr;
assert(!reg->open || (NULL != cs_addrs->dir_tree));
gv_target = cs_addrs->dir_tree;
diff --git a/sr_port/mur_get_pini.c b/sr_port/mur_get_pini.c
index 3d1fba0..d775463 100644
--- a/sr_port/mur_get_pini.c
+++ b/sr_port/mur_get_pini.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2003, 2010 Fidelity Information Services, Inc *
+ * Copyright 2003, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -35,6 +35,10 @@ GBLREF mur_gbls_t murgbl;
GBLREF mur_opt_struct mur_options;
GBLREF jnl_gbls_t jgbl;
+error_def(ERR_JNLREAD);
+error_def(ERR_JNLBADRECFMT);
+error_def(ERR_NOPINI);
+
#define PROCEED_IF_EXTRACT_SHOW_VERIFY(JCTL, PINI_ADDR, PLST, PPLST) \
{ /* allow EXTRACT/SHOW/VERIFY to proceed after printing BAD PINI error if error_limit permits. \
* the way we proceed is by returning as if PINI_ADDR was the first journal record in the file. \
@@ -76,10 +80,6 @@ uint4 mur_get_pini(jnl_ctl_list *jctl, off_jnl_t pini_addr, pini_list_struct **p
reg_ctl_list *rctl;
mur_read_desc_t *mur_desc;
- error_def(ERR_JNLREAD);
- error_def(ERR_JNLBADRECFMT);
- error_def(ERR_NOPINI);
-
if (NULL != (tabent = lookup_hashtab_int4(&jctl->pini_list, (uint4 *)&pini_addr)))
plst = tabent->value;
else
@@ -98,8 +98,9 @@ uint4 mur_get_pini(jnl_ctl_list *jctl, off_jnl_t pini_addr, pini_list_struct **p
{
if (mur_options.update && jctl->after_end_of_data && !jgbl.forw_phase_recovery)
return ERR_JNLBADRECFMT;
- gtm_putmsg(VARLSTCNT(5) ERR_JNLBADRECFMT, 3, jctl->jnl_fn_len, jctl->jnl_fn, jctl->rec_offset);
- gtm_putmsg(VARLSTCNT(5) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, pini_addr);
+ gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(5) ERR_JNLBADRECFMT, 3, jctl->jnl_fn_len, jctl->jnl_fn,
+ jctl->rec_offset);
+ gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(5) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, pini_addr);
assert(FALSE);
murgbl.wrn_count++;
PROCEED_IF_EXTRACT_SHOW_VERIFY(jctl, pini_addr, plst, pplst);
@@ -111,9 +112,10 @@ uint4 mur_get_pini(jnl_ctl_list *jctl, off_jnl_t pini_addr, pini_list_struct **p
{
if (mur_options.update && jctl->after_end_of_data && !jgbl.forw_phase_recovery)
return ERR_JNLBADRECFMT;
- gtm_putmsg(VARLSTCNT(5) ERR_JNLBADRECFMT, 3, jctl->jnl_fn_len, jctl->jnl_fn, jctl->rec_offset);
+ gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(5) ERR_JNLBADRECFMT, 3, jctl->jnl_fn_len, jctl->jnl_fn,
+ jctl->rec_offset);
if (JRT_PINI != pinirec->prefix.jrec_type)
- gtm_putmsg(VARLSTCNT(5) ERR_NOPINI, 3, jctl->jnl_fn_len, jctl->jnl_fn, pini_addr);
+ gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(5) ERR_NOPINI, 3, jctl->jnl_fn_len, jctl->jnl_fn, pini_addr);
assert(FALSE);
murgbl.wrn_count++;
PROCEED_IF_EXTRACT_SHOW_VERIFY(jctl, pini_addr, plst, pplst);
diff --git a/sr_port/mur_init.c b/sr_port/mur_init.c
index b6c0608..1fb511c 100644
--- a/sr_port/mur_init.c
+++ b/sr_port/mur_init.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2003, 2011 Fidelity Information Services, Inc *
+ * Copyright 2003, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -93,7 +93,6 @@ void mur_init(void)
*/
for (index = 0; index < CDB_STAGNATE; index++)
t_fail_hist[index] = '0';
- call_on_signal = mur_close_files;
DEBUG_ONLY(assert_jrec_member_offsets();)
}
diff --git a/sr_port/mur_insert_prev.c b/sr_port/mur_insert_prev.c
index 2f7fcc8..8545082 100644
--- a/sr_port/mur_insert_prev.c
+++ b/sr_port/mur_insert_prev.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -66,8 +66,8 @@ boolean_t mur_insert_prev(jnl_ctl_list **jjctl)
}
if (SS_NORMAL != (new_jctl->status = mur_fread_eof(new_jctl, rctl)))
{
- gtm_putmsg(VARLSTCNT(6) ERR_JNLBADRECFMT, 3, new_jctl->jnl_fn_len, new_jctl->jnl_fn,
- new_jctl->rec_offset, new_jctl->status);
+ gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(6) ERR_JNLBADRECFMT, 3, new_jctl->jnl_fn_len,
+ new_jctl->jnl_fn, new_jctl->rec_offset, new_jctl->status);
free(new_jctl);
return FALSE;
}
@@ -79,7 +79,7 @@ boolean_t mur_insert_prev(jnl_ctl_list **jjctl)
assert((new_jctl->properly_closed && !new_jctl->jfh->crash) || (jctl->jfh->recover_interrupted &&
!new_jctl->jfh->recover_interrupted));
assert(!mur_options.forward || (!(jctl->jfh->recover_interrupted && !new_jctl->jfh->recover_interrupted)));
- /* Skip the continuty of journal files check if both of these are true:
+ /* Skip the continuity of journal files check if both of these are true:
* 1) if current generation was created by recover and
* 2) the new one to be inserted was not created by recover
*/
@@ -96,7 +96,7 @@ boolean_t mur_insert_prev(jnl_ctl_list **jjctl)
}
if ((!mur_options.forward || !mur_options.notncheck) && (new_jctl->jfh->eov_tn != jctl->jfh->bov_tn))
{
- gtm_putmsg(VARLSTCNT(8) ERR_JNLTNOUTOFSEQ, 6,
+ gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(8) ERR_JNLTNOUTOFSEQ, 6,
&new_jctl->jfh->eov_tn, new_jctl->jnl_fn_len, new_jctl->jnl_fn,
&jctl->jfh->bov_tn, jctl->jnl_fn_len, jctl->jnl_fn);
free(new_jctl);
@@ -115,9 +115,9 @@ boolean_t mur_insert_prev(jnl_ctl_list **jjctl)
}
if (NULL == rl_ptr)
{
- gtm_putmsg(VARLSTCNT(8) ERR_DBJNLNOTMATCH, 6, DB_LEN_STR(rctl->gd), new_jctl->jnl_fn_len,
- new_jctl->jnl_fn, new_jctl->jfh->data_file_name_length,
- new_jctl->jfh->data_file_name);
+ gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(8) ERR_DBJNLNOTMATCH,
+ 6, DB_LEN_STR(rctl->gd), new_jctl->jnl_fn_len, new_jctl->jnl_fn,
+ new_jctl->jfh->data_file_name_length, new_jctl->jfh->data_file_name);
free(new_jctl);
return FALSE;
}
@@ -127,7 +127,8 @@ boolean_t mur_insert_prev(jnl_ctl_list **jjctl)
if (new_jctl->jfh->prev_jnl_file_name_length == cur_jctl->jnl_fn_len &&
0 == memcmp(new_jctl->jfh->prev_jnl_file_name, cur_jctl->jnl_fn, cur_jctl->jnl_fn_len))
{
- gtm_putmsg(VARLSTCNT(6) ERR_JNLCYCLE, 4, cur_jctl->jnl_fn_len, cur_jctl->jnl_fn, DB_LEN_STR(rctl->gd));
+ gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(6) ERR_JNLCYCLE, 4, cur_jctl->jnl_fn_len,
+ cur_jctl->jnl_fn, DB_LEN_STR(rctl->gd));
free(new_jctl);
return FALSE;
}
@@ -153,6 +154,7 @@ boolean_t mur_insert_prev(jnl_ctl_list **jjctl)
rctl->jctl = rctl->jctl_head = new_jctl;
assert(new_jctl->reg_ctl == rctl);
*jjctl = new_jctl;
- gtm_putmsg(VARLSTCNT(6) ERR_MUJNLPREVGEN, 4, new_jctl->jnl_fn_len, new_jctl->jnl_fn, DB_LEN_STR(rctl->gd));
+ gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(6) ERR_MUJNLPREVGEN, 4, new_jctl->jnl_fn_len,
+ new_jctl->jnl_fn, DB_LEN_STR(rctl->gd));
return TRUE;
}
diff --git a/sr_port/mur_open_files.c b/sr_port/mur_open_files.c
index 5ed938c..d6d40da 100644
--- a/sr_port/mur_open_files.c
+++ b/sr_port/mur_open_files.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2003, 2012 Fidelity Information Services, Inc *
+ * Copyright 2003, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -84,26 +84,26 @@
#include "is_proc_alive.h"
#include "anticipatory_freeze.h"
-#define RELEASE_ACCESS_CONTROL(REGLIST) \
-{ \
- unix_db_info *lcl_udi; \
- gd_region *lcl_reg; \
- reg_ctl_list *lcl_rctl; \
- int save_errno; \
- \
- lcl_reg = REGLIST->reg; \
- lcl_rctl = REGLIST->rctl; \
- lcl_udi = FILE_INFO(lcl_reg); \
- assert(INVALID_SEMID != lcl_udi->semid); \
- assert(lcl_udi->grabbed_access_sem && lcl_rctl->standalone); \
- if (0 != (save_errno = do_semop(lcl_udi->semid, 0, -1, SEM_UNDO))) \
- { \
- assert(FALSE); /* we hold it, so we should be able to release it*/ \
- rts_error(VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(lcl_reg), ERR_SYSCALL, 5,\
- RTS_ERROR_LITERAL("semop()"), CALLFROM, save_errno); \
- } \
- lcl_udi->grabbed_access_sem = FALSE; \
- lcl_rctl->standalone = FALSE; \
+#define RELEASE_ACCESS_CONTROL(REGLIST) \
+{ \
+ unix_db_info *lcl_udi; \
+ gd_region *lcl_reg; \
+ reg_ctl_list *lcl_rctl; \
+ int save_errno; \
+ \
+ lcl_reg = REGLIST->reg; \
+ lcl_rctl = REGLIST->rctl; \
+ lcl_udi = FILE_INFO(lcl_reg); \
+ assert(INVALID_SEMID != lcl_udi->semid); \
+ assert(lcl_udi->grabbed_access_sem && lcl_rctl->standalone); \
+ if (0 != (save_errno = do_semop(lcl_udi->semid, DB_CONTROL_SEM, -1, SEM_UNDO))) \
+ { \
+ assert(FALSE); /* we hold it, so we should be able to release it*/ \
+ rts_error(VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(lcl_reg), ERR_SYSCALL, 5, \
+ RTS_ERROR_LITERAL("semop()"), CALLFROM, save_errno); \
+ } \
+ lcl_udi->grabbed_access_sem = FALSE; \
+ lcl_rctl->standalone = FALSE; \
}
#define GRAB_ACCESS_CONTROL(REGLIST) \
@@ -132,7 +132,7 @@
rts_error(VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(lcl_reg), ERR_SYSCALL, 5,\
RTS_ERROR_LITERAL("semop()"), CALLFROM, save_errno); \
} \
- lcl_udi->grabbed_access_sem = TRUE; \
+ lcl_udi->grabbed_access_sem = TRUE; \
lcl_rctl->standalone = TRUE; \
} \
}
@@ -565,7 +565,7 @@ boolean_t mur_open_files()
*/
if (NULL != jnlpool_ctl)
{ /* Validate the journal pool is accessible and the offsets of various structures within it are intact */
- grab_lock(jnlpool.jnlpool_dummy_reg, GRAB_LOCK_ONLY);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, GRAB_LOCK_ONLY);
csa->hold_onto_crit = TRUE; /* No more unconditional rel_lock() */
assert(jnlpool.repl_inst_filehdr->crash); /* since we haven't removed the journal pool */
repl_inst_flush_jnlpool(FALSE, FALSE);
@@ -580,7 +580,7 @@ boolean_t mur_open_files()
TP_CHANGE_REG(reg);
# ifdef DEBUG
udi = FILE_INFO(reg);
- assert(1 == (semval = semctl(udi->semid, 0, GETVAL)));
+ assert(1 == (semval = semctl(udi->semid, DB_CONTROL_SEM, GETVAL)));
# endif
assert(cs_addrs->now_crit);
cs_addrs->hold_onto_crit = TRUE; /* No more unconditional grab_crit/rel_crit on this region */
diff --git a/sr_port/mur_output_show.c b/sr_port/mur_output_show.c
index 973f9d4..804c8b4 100644
--- a/sr_port/mur_output_show.c
+++ b/sr_port/mur_output_show.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2003, 2012 Fidelity Information Services, Inc *
+ * Copyright 2003, 2013 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 <jpidef.h>
#endif
#include "real_len.h" /* for real_len() prototype */
+#include "have_crit.h"
GBLREF mur_opt_struct mur_options;
GBLREF reg_ctl_list *mur_ctl;
@@ -133,7 +134,7 @@ int format_time(jnl_proc_time proc_time, char *string, int string_len, int time_
short_time = MID_TIME(proc_time);
else
short_time = (time_t)proc_time;
- tsp = localtime((const time_t *)&short_time);
+ GTM_LOCALTIME(tsp, (const time_t *)&short_time);
SPRINTF(string, "%04d/%02d/%02d %02d:%02d:%02d", (1900 + tsp->tm_year), (1 + tsp->tm_mon), tsp->tm_mday,
tsp->tm_hour, tsp->tm_min, tsp->tm_sec);
assert(LENGTH_OF_TIME >= strlen(string));
diff --git a/sr_port/mur_process_intrpt_recov.c b/sr_port/mur_process_intrpt_recov.c
index e1e83df..6f3112f 100644
--- a/sr_port/mur_process_intrpt_recov.c
+++ b/sr_port/mur_process_intrpt_recov.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2003, 2012 Fidelity Information Services, Inc *
+ * Copyright 2003, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -30,6 +30,7 @@
#include "gdsbt.h"
#include "gtm_facility.h"
#include "fileinfo.h"
+#include "gtmio.h"
#include "gdsfhead.h"
#include "filestruct.h"
#include "jnl.h"
@@ -40,7 +41,6 @@
#include "muprec.h"
#include "iosp.h"
#include "jnl_typedef.h"
-#include "gtmio.h"
#include "gtmmsg.h"
#include "anticipatory_freeze.h"
#include "wcs_flu.h" /* for wcs_flu() prototype */
@@ -78,14 +78,14 @@ uint4 mur_process_intrpt_recov()
io_status_block_disk iosb;
)
boolean_t jfh_changed;
- jnl_record *jnlrec;
- jnl_file_header *jfh;
+ jnl_record *jnlrec;
+ jnl_file_header *jfh;
+ jnl_tm_t now;
for (rctl = mur_ctl, rctl_top = mur_ctl + murgbl.reg_total; rctl < rctl_top; rctl++)
{
- gv_cur_region = rctl->gd; /* wcs_flu requires this to be set */
- cs_addrs = rctl->csa;
- csd = cs_data = rctl->csd; /* MM logic after wcs_flu call requires this to be set */
+ TP_CHANGE_REG(rctl->gd);
+ csd = cs_data; /* MM logic after wcs_flu call requires this to be set */
assert(csd == rctl->csa->hdr);
jctl = rctl->jctl_turn_around;
max_jnl_alq = max_jnl_deq = max_autoswitchlimit = 0;
@@ -219,8 +219,8 @@ uint4 mur_process_intrpt_recov()
* is in progress
*/
bt_refresh(cs_addrs, FALSE); /* sets earliest bt TN to be the turn around TN */
- db_csh_ref(cs_addrs, FALSE);
}
+ db_csh_ref(cs_addrs, FALSE);
assert(NULL != cs_addrs->jnl);
jpc = cs_addrs->jnl;
assert(NULL != jpc->jnl_buff);
@@ -253,8 +253,10 @@ uint4 mur_process_intrpt_recov()
assert((dba_mm == cs_data->acc_meth) || (rctl->csd == cs_data));
rctl->csd = cs_data;
}
+ JNL_SHORT_TIME(now);
for (rctl = mur_ctl, rctl_top = mur_ctl + murgbl.reg_total; rctl < rctl_top; rctl++)
{
+ TP_CHANGE_REG_IF_NEEDED(rctl->gd);
if (!rctl->jfh_recov_interrupted)
jctl = rctl->jctl_turn_around;
else
@@ -274,7 +276,7 @@ uint4 mur_process_intrpt_recov()
assert(rctl->csd->jnl_file_len == jctl->jnl_fn_len); /* latest gener file name */
assert(0 == memcmp(rctl->csd->jnl_file_name, jctl->jnl_fn, jctl->jnl_fn_len)); /* should match db header */
if (SS_NORMAL != (status = prepare_unique_name((char *)jctl->jnl_fn, jctl->jnl_fn_len, "", "",
- rename_fn, &rename_fn_len, &status2)))
+ rename_fn, &rename_fn_len, now, &status2)))
return status;
jctl->jnl_fn_len = rename_fn_len; /* change the name in memory to the proposed name */
memcpy(jctl->jnl_fn, rename_fn, rename_fn_len + 1);
@@ -336,10 +338,10 @@ uint4 mur_process_intrpt_recov()
{
assert(FALSE);
if (SS_NORMAL == jctl->status2)
- gtm_putmsg(VARLSTCNT(5) ERR_JNLWRERR, 2, jctl->jnl_fn_len,
+ gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(5) ERR_JNLWRERR, 2, jctl->jnl_fn_len,
jctl->jnl_fn, jctl->status);
else
- gtm_putmsg(VARLSTCNT1(6) ERR_JNLWRERR, 2, jctl->jnl_fn_len,
+ gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT1(6) ERR_JNLWRERR, 2, jctl->jnl_fn_len,
jctl->jnl_fn, jctl->status, PUT_SYS_ERRNO(jctl->status2));
return jctl->status;
}
@@ -349,7 +351,7 @@ uint4 mur_process_intrpt_recov()
{
jctl->status2 = errno;
assert(FALSE);
- gtm_putmsg(VARLSTCNT(9) ERR_JNLFSYNCERR, 2,
+ gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(9) ERR_JNLFSYNCERR, 2,
jctl->jnl_fn_len, jctl->jnl_fn,
ERR_TEXT, 2, RTS_ERROR_TEXT("Error with fsync"), jctl->status2);
return ERR_JNLFSYNCERR;
@@ -373,7 +375,7 @@ uint4 mur_process_intrpt_recov()
jgbl.gbl_jrec_time = rctl->jctl_turn_around->turn_around_time; /* time needed for cre_jnl_file_common() */
if (EXIT_NRM != cre_jnl_file_common(&jnl_info, rename_fn, rename_fn_len))
{
- gtm_putmsg(VARLSTCNT(4) ERR_JNLNOCREATE, 2, jnl_info.jnl_len, jnl_info.jnl);
+ gtm_putmsg_csa(CSA_ARG(rctl->csa) VARLSTCNT(4) ERR_JNLNOCREATE, 2, jnl_info.jnl_len, jnl_info.jnl);
return jnl_info.status;
}
# ifdef UNIX
diff --git a/sr_port/mur_process_timequal.c b/sr_port/mur_process_timequal.c
index 8c73a8b..4619d19 100644
--- a/sr_port/mur_process_timequal.c
+++ b/sr_port/mur_process_timequal.c
@@ -1,6 +1,6 @@
/****************************************************************
*
- * Copyright 2005 Fidelity Information Services, Inc *
+ * Copyright 2005, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -31,9 +31,16 @@
#include "gtmmsg.h" /* for gtm_putmsg() prototype */
#include "cli.h"
#include "mupip_exit.h"
+#include "have_crit.h"
GBLREF mur_opt_struct mur_options;
+error_def (ERR_JNLTMQUAL1);
+error_def (ERR_JNLTMQUAL2);
+error_def (ERR_JNLTMQUAL3);
+error_def (ERR_JNLTMQUAL4);
+error_def (ERR_MUNOACTION);
+
#ifdef VMS
static int4 mur_rel2abstime(jnl_proc_time deltatime, jnl_proc_time basetime, boolean_t roundup)
{
@@ -107,12 +114,6 @@ void mur_process_timequal(jnl_tm_t max_lvrec_time, jnl_tm_t min_bov_time)
{
char time_str1[LENGTH_OF_TIME + 1], time_str2[LENGTH_OF_TIME + 1];
- error_def (ERR_JNLTMQUAL1);
- error_def (ERR_JNLTMQUAL2);
- error_def (ERR_JNLTMQUAL3);
- error_def (ERR_JNLTMQUAL4);
- error_def (ERR_MUNOACTION);
-
/* All time qualifiers are specified in delta time or absolute time.
* mur_options.since_time == 0 means no since time was specified
* mur_options.since_time < 0 means it is the delta since time.
diff --git a/sr_port/mur_put_aimg_rec.c b/sr_port/mur_put_aimg_rec.c
index 92b5675..0cd2607 100644
--- a/sr_port/mur_put_aimg_rec.c
+++ b/sr_port/mur_put_aimg_rec.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -47,7 +47,7 @@ GBLREF srch_hist dummy_hist;
GBLREF sgmnt_addrs *cs_addrs;
GBLREF sgmnt_data_ptr_t cs_data;
GBLREF cw_set_element cw_set[];
-GBLREF unsigned char *non_tp_jfb_buff_ptr;
+GBLREF jnl_format_buffer *non_tp_jfb_ptr;
/* Modified on the similar lines of dse AIMG record logic, needed for recover to write journal records */
void mur_put_aimg_rec(jnl_record *rec)
@@ -87,7 +87,7 @@ void mur_put_aimg_rec(jnl_record *rec)
if (JNL_ENABLED(cs_data))
{
cse = (cw_set_element *)(&cw_set[0]);
- cse->new_buff = non_tp_jfb_buff_ptr;
+ cse->new_buff = (unsigned char *)non_tp_jfb_ptr->buff;
gvcst_blk_build(cse, (uchar_ptr_t)cse->new_buff, cs_addrs->ti->curr_tn);
cse->done = TRUE;
}
diff --git a/sr_port/mur_read_file.c b/sr_port/mur_read_file.c
index 5b80fc6..0bcd56d 100644
--- a/sr_port/mur_read_file.c
+++ b/sr_port/mur_read_file.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2003, 2012 Fidelity Information Services, Inc *
+ * Copyright 2003, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -109,8 +109,8 @@ uint4 mur_prev_rec(jnl_ctl_list **jjctl)
if (JRT_EOF != mur_desc->jnlrec->prefix.jrec_type)
return SS_NORMAL;
/* unexpected EOF record in the middle of the file */
- gtm_putmsg(VARLSTCNT(9) ERR_JNLUNXPCTERR, 3, jctl->jnl_fn_len, jctl->jnl_fn, jctl->rec_offset,
- ERR_TEXT, 2, LEN_AND_LIT("Unexpected EOF record found [prev_rec]"));
+ gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(9) ERR_JNLUNXPCTERR, 3, jctl->jnl_fn_len, jctl->jnl_fn,
+ jctl->rec_offset, ERR_TEXT, 2, LEN_AND_LIT("Unexpected EOF record found [prev_rec]"));
status = ERR_JNLBADRECFMT;
}
if (ERR_JNLBADRECFMT != status)
@@ -128,8 +128,8 @@ uint4 mur_prev_rec(jnl_ctl_list **jjctl)
* Notice that the offset jctl->rec_offset points to a good record. The badly formatted
* journal record is actually one record BEFORE the printed offset.
*/
- gtm_putmsg(VARLSTCNT(9) ERR_JNLBADRECFMT, 3, jctl->jnl_fn_len, jctl->jnl_fn, jctl->rec_offset,
- ERR_TEXT, 2, LEN_AND_LIT("Error accessing previous record"));
+ gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(9) ERR_JNLBADRECFMT, 3, jctl->jnl_fn_len, jctl->jnl_fn,
+ jctl->rec_offset, ERR_TEXT, 2, LEN_AND_LIT("Error accessing previous record"));
} else
{ /* offset is at tail of journal file after crash. Caller could be backward recovery or
* forward recovery or even extract/verify/show if they are in tail_analysis. We expect
@@ -192,8 +192,8 @@ uint4 mur_next_rec(jnl_ctl_list **jjctl)
assert(jctl->rec_offset <= jctl->lvrec_off);
if (JRT_EOF != mur_desc->jnlrec->prefix.jrec_type || jctl->rec_offset == jctl->lvrec_off)
return SS_NORMAL;
- gtm_putmsg(VARLSTCNT(9) ERR_JNLUNXPCTERR, 3, jctl->jnl_fn_len, jctl->jnl_fn, jctl->rec_offset,
- ERR_TEXT, 2, LEN_AND_LIT("Unexpected EOF record found [next_rec]"));
+ gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(9) ERR_JNLUNXPCTERR, 3, jctl->jnl_fn_len, jctl->jnl_fn,
+ jctl->rec_offset, ERR_TEXT, 2, LEN_AND_LIT("Unexpected EOF record found [next_rec]"));
status = ERR_JNLBADRECFMT;
}
if (ERR_JNLBADRECFMT != status)
@@ -206,8 +206,8 @@ uint4 mur_next_rec(jnl_ctl_list **jjctl)
/* continue in distress, look for other valid records */
return mur_valrec_next(jctl, jctl->rec_offset + rec_size);
}
- gtm_putmsg(VARLSTCNT(9) ERR_JNLBADRECFMT, 3, jctl->jnl_fn_len, jctl->jnl_fn, jctl->rec_offset,
- ERR_TEXT, 2, LEN_AND_LIT("Error accessing next record"));
+ gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(9) ERR_JNLBADRECFMT, 3, jctl->jnl_fn_len, jctl->jnl_fn,
+ jctl->rec_offset, ERR_TEXT, 2, LEN_AND_LIT("Error accessing next record"));
return status;
}
assert(jctl->rec_offset == jctl->lvrec_off);
@@ -248,16 +248,16 @@ uint4 mur_prev(jnl_ctl_list *jctl, off_jnl_t dskaddr)
assert(dskaddr >= JNL_HDR_LEN);
if (dskaddr >= jctl->eof_addr || dskaddr < JNL_HDR_LEN)
{
- gtm_putmsg(VARLSTCNT(9) ERR_JNLUNXPCTERR, 3, jctl->jnl_fn_len, jctl->jnl_fn, dskaddr,
- ERR_TEXT, 2, LEN_AND_LIT("Requested offset out of range [prev]"));
+ gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(9) ERR_JNLUNXPCTERR, 3, jctl->jnl_fn_len, jctl->jnl_fn,
+ dskaddr, ERR_TEXT, 2, LEN_AND_LIT("Requested offset out of range [prev]"));
return (dskaddr >= jctl->eof_addr ? ERR_JNLREADEOF : ERR_JNLREADBOF);
}
assert(dskaddr == ROUND_UP2(dskaddr, JNL_REC_START_BNDRY)); /* dskaddr must be aligned at JNL_REC_START_BNDRY */
MUR_FREAD_CANCEL(jctl, mur_desc, status);
if (SS_NORMAL != status)
{
- gtm_putmsg(VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, dskaddr,
- ERR_TEXT, 2, LEN_AND_LIT("Could not cancel prior read [prev]"), jctl->status);
+ gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn,
+ dskaddr, ERR_TEXT, 2, LEN_AND_LIT("Could not cancel prior read [prev]"), jctl->status);
return jctl->status;
}
mur_desc->buff_index = 1;
@@ -270,8 +270,9 @@ uint4 mur_prev(jnl_ctl_list *jctl, off_jnl_t dskaddr)
/* we rely on reading at least up to the record length field (forwptr) */
if (SS_NORMAL != (status = mur_freadw(jctl, mur_desc->cur_buff)))
{
- gtm_putmsg(VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, mur_desc->cur_buff->dskaddr,
- ERR_TEXT, 2, LEN_AND_LIT("Error from synchronous read into cur_buff [prev]"), status);
+ gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn,
+ mur_desc->cur_buff->dskaddr, ERR_TEXT, 2,
+ LEN_AND_LIT("Error from synchronous read into cur_buff [prev]"), status);
return status;
}
mur_desc->jnlrec = (jnl_record *)(mur_desc->cur_buff->base + buff_offset);
@@ -285,8 +286,8 @@ uint4 mur_prev(jnl_ctl_list *jctl, off_jnl_t dskaddr)
MUR_FREAD_START(jctl, mur_desc->sec_buff, status);
if (SS_NORMAL != status)
{
- gtm_putmsg(VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn,
- mur_desc->sec_buff->dskaddr, ERR_TEXT, 2,
+ gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len,
+ jctl->jnl_fn, mur_desc->sec_buff->dskaddr, ERR_TEXT, 2,
LEN_AND_LIT("Could not initiate read into sec_buff in [prev] (dskaddr > 0)"),
status);
return status;
@@ -305,15 +306,15 @@ uint4 mur_prev(jnl_ctl_list *jctl, off_jnl_t dskaddr)
{
if (SS_NORMAL != (status = mur_freadw(jctl, &mur_desc->aux_buff2)))
{
- gtm_putmsg(VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn,
- mur_desc->aux_buff2.dskaddr, ERR_TEXT, 2,
- LEN_AND_LIT("Error in synchronous read into aux_buff [prev]"), status);
+ gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(10) ERR_JNLREAD, 3,
+ jctl->jnl_fn_len, jctl->jnl_fn, mur_desc->aux_buff2.dskaddr, ERR_TEXT, 2,
+ LEN_AND_LIT("Error in synchronous read into aux_buff [prev]"), status);
return status;
}
} else
{
- gtm_putmsg(VARLSTCNT(9) ERR_JNLUNXPCTERR, 3, jctl->jnl_fn_len,
- jctl->jnl_fn, dskaddr, ERR_TEXT, 2,
+ gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(9) ERR_JNLUNXPCTERR, 3,
+ jctl->jnl_fn_len, jctl->jnl_fn, dskaddr, ERR_TEXT, 2,
LEN_AND_LIT("Requested offset beyond end of file [prev] (dskaddr > 0)"));
return ERR_JNLBADRECFMT;
}
@@ -338,10 +339,9 @@ uint4 mur_prev(jnl_ctl_list *jctl, off_jnl_t dskaddr)
MUR_FREAD_START(jctl, mur_desc->sec_buff, status);
if (SS_NORMAL != status)
{
- gtm_putmsg(VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn,
- mur_desc->sec_buff->dskaddr, ERR_TEXT, 2,
- LEN_AND_LIT("Could not initiate read into sec_buff [prev] (dskaddr == 0)"),
- status);
+ gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len,
+ jctl->jnl_fn, mur_desc->sec_buff->dskaddr, ERR_TEXT, 2,
+ LEN_AND_LIT("Could not initiate read into sec_buff [prev] (dskaddr == 0)"), status);
return status;
}
}
@@ -361,8 +361,8 @@ uint4 mur_prev(jnl_ctl_list *jctl, off_jnl_t dskaddr)
MUR_FREAD_WAIT(jctl, mur_desc->sec_buff, status);
if (SS_NORMAL != status)
{
- gtm_putmsg(VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn,
- mur_desc->sec_buff->dskaddr, ERR_TEXT, 2,
+ gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len,
+ jctl->jnl_fn, mur_desc->sec_buff->dskaddr, ERR_TEXT, 2,
LEN_AND_LIT("Error waiting for sec_buff read to complete [prev]"),
status);
return status;
@@ -378,8 +378,8 @@ uint4 mur_prev(jnl_ctl_list *jctl, off_jnl_t dskaddr)
MUR_FREAD_START(jctl, mur_desc->cur_buff, status);
if (SS_NORMAL != status)
{
- gtm_putmsg(VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn,
- mur_desc->cur_buff->dskaddr, ERR_TEXT, 2,
+ gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len,
+ jctl->jnl_fn, mur_desc->cur_buff->dskaddr, ERR_TEXT, 2,
LEN_AND_LIT("Could not initiate read into cur_buff [prev]"), status);
return status;
}
@@ -399,9 +399,9 @@ uint4 mur_prev(jnl_ctl_list *jctl, off_jnl_t dskaddr)
mur_desc->jreclen = suffix->backptr;
if (jctl->rec_offset < mur_desc->jreclen + JNL_HDR_LEN)
{
- gtm_putmsg(VARLSTCNT(9) ERR_JNLUNXPCTERR, 3, jctl->jnl_fn_len, jctl->jnl_fn,
- jctl->rec_offset, ERR_TEXT, 2,
- LEN_AND_LIT("Requested offset beyond beginning of file [prev]"));
+ gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(9) ERR_JNLUNXPCTERR, 3, jctl->jnl_fn_len,
+ jctl->jnl_fn, jctl->rec_offset, ERR_TEXT, 2,
+ LEN_AND_LIT("Requested offset beyond beginning of file [prev]"));
return ERR_JNLBADRECFMT;
}
}
@@ -437,16 +437,16 @@ uint4 mur_next(jnl_ctl_list *jctl, off_jnl_t dskaddr)
assert(dskaddr >= JNL_HDR_LEN);
if (dskaddr >= jctl->eof_addr || dskaddr < JNL_HDR_LEN)
{
- gtm_putmsg(VARLSTCNT(9) ERR_JNLUNXPCTERR, 3, jctl->jnl_fn_len, jctl->jnl_fn, dskaddr,
- ERR_TEXT, 2, LEN_AND_LIT("Requested offset out of range [next]"));
+ gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(9) ERR_JNLUNXPCTERR, 3, jctl->jnl_fn_len, jctl->jnl_fn,
+ dskaddr, ERR_TEXT, 2, LEN_AND_LIT("Requested offset out of range [next]"));
return (dskaddr >= jctl->eof_addr ? ERR_JNLREADEOF : ERR_JNLREADBOF);
}
assert(dskaddr == ROUND_UP2(dskaddr, JNL_REC_START_BNDRY)); /* dskaddr must be aligned at JNL_REC_START_BNDRY */
MUR_FREAD_CANCEL(jctl, mur_desc, status);
if (SS_NORMAL != status)
{
- gtm_putmsg(VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, dskaddr,
- ERR_TEXT, 2, LEN_AND_LIT("Could not cancel prior read [next]"), jctl->status);
+ gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn,
+ dskaddr, ERR_TEXT, 2, LEN_AND_LIT("Could not cancel prior read [next]"), jctl->status);
return jctl->status;
}
mur_desc->buff_index = 0;
@@ -459,9 +459,9 @@ uint4 mur_next(jnl_ctl_list *jctl, off_jnl_t dskaddr)
* the record length field (forwptr) */
if (SS_NORMAL != (status = mur_freadw(jctl, mur_desc->cur_buff)))
{
- gtm_putmsg(VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, mur_desc->cur_buff->dskaddr,
- ERR_TEXT, 2, LEN_AND_LIT("Error from synchronous read into cur_buff [next]"),
- status);
+ gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn,
+ mur_desc->cur_buff->dskaddr, ERR_TEXT, 2,
+ LEN_AND_LIT("Error from synchronous read into cur_buff [next]"), status);
return status;
}
mur_desc->jnlrec = (jnl_record *)(mur_desc->cur_buff->base + buff_offset);
@@ -475,8 +475,8 @@ uint4 mur_next(jnl_ctl_list *jctl, off_jnl_t dskaddr)
MUR_FREAD_START(jctl, mur_desc->sec_buff, status);
if (SS_NORMAL != status)
{
- gtm_putmsg(VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn,
- mur_desc->sec_buff->dskaddr, ERR_TEXT, 2,
+ gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len,
+ jctl->jnl_fn, mur_desc->sec_buff->dskaddr, ERR_TEXT, 2,
LEN_AND_LIT("Could not initiate read into sec_buff [next] (dskaddr > 0)"),
status);
return status;
@@ -487,10 +487,11 @@ uint4 mur_next(jnl_ctl_list *jctl, off_jnl_t dskaddr)
MUR_FREAD_WAIT(jctl, mur_desc->sec_buff, status);
if (SS_NORMAL != status)
{
- gtm_putmsg(VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn,
- mur_desc->sec_buff->dskaddr, ERR_TEXT, 2,
- LEN_AND_LIT("Error waiting for sec_buff read to complete [next] (dskaddr > 0)"),
- status);
+ gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(10) ERR_JNLREAD, 3,
+ jctl->jnl_fn_len, jctl->jnl_fn, mur_desc->sec_buff->dskaddr, ERR_TEXT, 2,
+ LEN_AND_LIT("Error waiting for sec_buff read to complete [next] "
+ "(dskaddr > 0)"),
+ status);
return status;
}
/* is the record available in its entirety? */
@@ -502,8 +503,9 @@ uint4 mur_next(jnl_ctl_list *jctl, off_jnl_t dskaddr)
/* is the record available in its entirety? */
if (!good_prefix)
{
- gtm_putmsg(VARLSTCNT(9) ERR_JNLUNXPCTERR, 3, jctl->jnl_fn_len, jctl->jnl_fn, dskaddr,
- ERR_TEXT, 2, LEN_AND_LIT("Requested offset beyond end of file [next] (dskaddr > 0)"));
+ gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(9) ERR_JNLUNXPCTERR, 3, jctl->jnl_fn_len,
+ jctl->jnl_fn, dskaddr, ERR_TEXT, 2,
+ LEN_AND_LIT("Requested offset beyond end of file [next] (dskaddr > 0)"));
return ERR_JNLBADRECFMT;
}
} /* end good_prefix */
@@ -528,10 +530,10 @@ uint4 mur_next(jnl_ctl_list *jctl, off_jnl_t dskaddr)
MUR_FREAD_START(jctl, mur_desc->sec_buff, status);
if (SS_NORMAL != status)
{
- gtm_putmsg(VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn,
- mur_desc->sec_buff->dskaddr, ERR_TEXT, 2,
- LEN_AND_LIT("Could not initiate read into sec_buff [next] (dskaddr == 0)"),
- status);
+ gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len,
+ jctl->jnl_fn, mur_desc->sec_buff->dskaddr, ERR_TEXT, 2,
+ LEN_AND_LIT("Could not initiate read into sec_buff [next] (dskaddr == 0)"),
+ status);
return status;
}
}
@@ -551,10 +553,10 @@ uint4 mur_next(jnl_ctl_list *jctl, off_jnl_t dskaddr)
MUR_FREAD_WAIT(jctl, mur_desc->sec_buff, status);
if (SS_NORMAL != status)
{
- gtm_putmsg(VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn,
- mur_desc->sec_buff->dskaddr, ERR_TEXT, 2,
- LEN_AND_LIT("Error waiting for sec_buff read to complete [next] (dskaddr == 0)"),
- status);
+ gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len,
+ jctl->jnl_fn, mur_desc->sec_buff->dskaddr, ERR_TEXT, 2,
+ LEN_AND_LIT("Error waiting for sec_buff read to complete [next] (dskaddr == 0)"),
+ status);
return status;
}
}
@@ -568,8 +570,8 @@ uint4 mur_next(jnl_ctl_list *jctl, off_jnl_t dskaddr)
MUR_FREAD_START(jctl, mur_desc->cur_buff, status);
if (SS_NORMAL != status)
{
- gtm_putmsg(VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn,
- mur_desc->cur_buff->dskaddr, ERR_TEXT, 2,
+ gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(10) ERR_JNLREAD, 3, jctl->jnl_fn_len,
+ jctl->jnl_fn, mur_desc->cur_buff->dskaddr, ERR_TEXT, 2,
LEN_AND_LIT("Could not initiate read into cur_buff [next]"), status);
return status;
}
@@ -593,7 +595,7 @@ uint4 mur_next(jnl_ctl_list *jctl, off_jnl_t dskaddr)
{
if (!jctl->tail_analysis)
{
- gtm_putmsg(VARLSTCNT(9) ERR_JNLUNXPCTERR, 3, jctl->jnl_fn_len,
+ gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(9) ERR_JNLUNXPCTERR, 3, jctl->jnl_fn_len,
jctl->jnl_fn, jctl->rec_offset,
ERR_TEXT, 2, LEN_AND_LIT("Requested offset beyond end of file [next] (dskaddr == 0)"));
return ERR_JNLBADRECFMT;
@@ -786,8 +788,8 @@ uint4 mur_valrec_prev(jnl_ctl_list *jctl, off_jnl_t lo_off, off_jnl_t hi_off)
mur_desc->random_buff.blen = blen;
if (SS_NORMAL != (status = mur_read(jctl)))
{
- gtm_putmsg(VARLSTCNT(6) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, mur_desc->random_buff.dskaddr,
- status);
+ gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(6) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn,
+ mur_desc->random_buff.dskaddr, status);
return status;
}
rec = (jnl_record *)mur_desc->random_buff.base;
@@ -839,7 +841,7 @@ uint4 mur_valrec_prev(jnl_ctl_list *jctl, off_jnl_t lo_off, off_jnl_t hi_off)
rec_offset = jctl->rec_offset;
if (SS_NORMAL != (status = mur_next(jctl, rec_offset)))
{
- gtm_putmsg(VARLSTCNT(9) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, rec_offset,
+ gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(9) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, rec_offset,
ERR_TEXT, 2, LEN_AND_LIT("Error received from mur_valrec_prev calling mur_next(rec_offset)"));
return status;
}
@@ -959,14 +961,15 @@ boolean_t mur_fopen(jnl_ctl_list *jctl)
*/
jfh->data_file_name_length = 0;
if (ERR_JNLINVALID == jctl->status)
- gtm_putmsg(VARLSTCNT(10) ERR_JNLINVALID, 4, jctl->jnl_fn_len, jctl->jnl_fn, jfh->data_file_name_length,
- jfh->data_file_name, ERR_TEXT, 2,
+ gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(10) ERR_JNLINVALID, 4, jctl->jnl_fn_len, jctl->jnl_fn,
+ jfh->data_file_name_length, jfh->data_file_name, ERR_TEXT, 2,
LEN_AND_LIT("Journal file does not have complete file header"));
else if (SS_NORMAL != jctl->status2)
- gtm_putmsg(VARLSTCNT1(7) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, 0, jctl->status,
- PUT_SYS_ERRNO(jctl->status2));
+ gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT1(7) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, 0,
+ jctl->status, PUT_SYS_ERRNO(jctl->status2));
else
- gtm_putmsg(VARLSTCNT(6) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, 0, jctl->status);
+ gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(6) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, 0,
+ jctl->status);
return FALSE;
}
if (SS_NORMAL == jctl->status)
@@ -984,12 +987,13 @@ boolean_t mur_fopen(jnl_ctl_list *jctl)
DO_FILE_READ(jctl->channel, JNL_HDR_LEN, jrecbuf, cre_jnl_rec_size, jctl->status, jctl->status2);
if (SS_NORMAL != jctl->status)
{
- gtm_putmsg(VARLSTCNT(6) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn, JNL_HDR_LEN, jctl->status);
+ gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(6) ERR_JNLREAD, 3, jctl->jnl_fn_len, jctl->jnl_fn,
+ JNL_HDR_LEN, jctl->status);
return FALSE;
}
} else
{
- gtm_putmsg(VARLSTCNT(10) ERR_JNLINVALID, 4, jctl->jnl_fn_len, jctl->jnl_fn,
+ gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(10) ERR_JNLINVALID, 4, jctl->jnl_fn_len, jctl->jnl_fn,
jfh->data_file_name_length, jfh->data_file_name,
ERR_TEXT, 2, LEN_AND_LIT("File size is less than minimum expected for a valid journal file"));
return FALSE;
@@ -999,10 +1003,12 @@ boolean_t mur_fopen(jnl_ctl_list *jctl)
VMS_ONLY(assert(!mur_options.rollback_losttnonly);)
if (mur_options.rollback_losttnonly)
{ /* Already prepared for a LOSTTNONLY rollback. Allow NOBEFORE_IMAGE journal file but issue a warning. */
- gtm_putmsg(VARLSTCNT(4) ERR_RLBKJNLNOBIMG, 2, jctl->jnl_fn_len, jctl->jnl_fn);
+ gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(4) ERR_RLBKJNLNOBIMG, 2, jctl->jnl_fn_len,
+ jctl->jnl_fn);
} else
{
- gtm_putmsg(VARLSTCNT(4) ERR_JNLNOBIJBACK, 2, jctl->jnl_fn_len, jctl->jnl_fn);
+ gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(4) ERR_JNLNOBIJBACK, 2, jctl->jnl_fn_len,
+ jctl->jnl_fn);
return FALSE;
}
}
@@ -1010,14 +1016,14 @@ boolean_t mur_fopen(jnl_ctl_list *jctl)
assert(REPL_ALLOWED(jfh) == REPL_ENABLED(jfh));
if (!REPL_ENABLED(jfh) && mur_options.rollback)
{
- gtm_putmsg(VARLSTCNT(4) ERR_REPLNOTON, 2, jctl->jnl_fn_len, jctl->jnl_fn);
+ gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(4) ERR_REPLNOTON, 2, jctl->jnl_fn_len, jctl->jnl_fn);
return FALSE;
}
jrec = (jnl_record *)jrecbuf;
if (!IS_VALID_JNLREC(jrec, jfh) || JRT_PINI != jrec->prefix.jrec_type)
{
- gtm_putmsg(VARLSTCNT(9) ERR_JNLBADRECFMT, 3, jctl->jnl_fn_len, jctl->jnl_fn, JNL_HDR_LEN,
- ERR_TEXT, 2, LEN_AND_LIT("Invalid or no PINI record found"));
+ gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(9) ERR_JNLBADRECFMT, 3, jctl->jnl_fn_len, jctl->jnl_fn,
+ JNL_HDR_LEN, ERR_TEXT, 2, LEN_AND_LIT("Invalid or no PINI record found"));
return FALSE;
}
/* We have at least one good record */
@@ -1026,27 +1032,29 @@ boolean_t mur_fopen(jnl_ctl_list *jctl)
jrec = (jnl_record *)((char *)jrec + PINI_RECLEN);
if (!IS_VALID_JNLREC(jrec, jfh) || JRT_EPOCH != jrec->prefix.jrec_type)
{
- gtm_putmsg(VARLSTCNT(9) ERR_JNLBADRECFMT, 3, jctl->jnl_fn_len, jctl->jnl_fn, JNL_HDR_LEN + PINI_RECLEN,
- ERR_TEXT, 2, LEN_AND_LIT("Invalid or no EPOCH record found"));
+ gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(9) ERR_JNLBADRECFMT, 3, jctl->jnl_fn_len, jctl->jnl_fn,
+ JNL_HDR_LEN + PINI_RECLEN, ERR_TEXT, 2, LEN_AND_LIT("Invalid or no EPOCH record found"));
return FALSE;
}
/* We have at least one valid EPOCH */
}
if (mur_options.update && jfh->bov_tn > jfh->eov_tn)
{
- gtm_putmsg(VARLSTCNT(6) ERR_BOVTNGTEOVTN, 4, jctl->jnl_fn_len, jctl->jnl_fn, &jfh->bov_tn, &jfh->eov_tn);
+ gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(6) ERR_BOVTNGTEOVTN, 4, jctl->jnl_fn_len, jctl->jnl_fn,
+ &jfh->bov_tn, &jfh->eov_tn);
return FALSE;
}
if (jfh->bov_timestamp > jfh->eov_timestamp)
{ /* This is not a severe error to exit, may be user changed system time which we do not allow now.
- * But we can still try to continue recovery. We already removed time continuty check from mur_fread_eof().
+ * But we can still try to continue recovery. We already removed time continuity check from mur_fread_eof().
* So if error limit allows, we will continue recovery */
if (!mur_report_error(jctl, MUR_BOVTMGTEOVTM))
return FALSE;
}
if (mur_options.rollback && (jfh->start_seqno > jfh->end_seqno))
{
- gtm_putmsg(VARLSTCNT(6) ERR_BEGSEQGTENDSEQ, 4, jctl->jnl_fn_len, jctl->jnl_fn, &jfh->start_seqno, &jfh->end_seqno);
+ gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(6) ERR_BEGSEQGTENDSEQ, 4, jctl->jnl_fn_len, jctl->jnl_fn,
+ &jfh->start_seqno, &jfh->end_seqno);
return FALSE;
}
init_hashtab_int4(&jctl->pini_list, MUR_PINI_LIST_INIT_ELEMS, HASHTAB_COMPACT, HASHTAB_SPARE_TABLE);
@@ -1084,6 +1092,7 @@ boolean_t mur_fclose(jnl_ctl_list *jctl)
return TRUE;
UNIX_ONLY(jctl->status = errno;)
assert(FALSE);
- gtm_putmsg(VARLSTCNT(5) ERR_JNLFILECLOSERR, 2, jctl->jnl_fn_len, jctl->jnl_fn, jctl->status);
+ gtm_putmsg_csa(CSA_ARG(JCTL2CSA(jctl)) VARLSTCNT(5) ERR_JNLFILECLOSERR, 2, jctl->jnl_fn_len, jctl->jnl_fn,
+ jctl->status);
return FALSE;
}
diff --git a/sr_port/mutex_deadlock_check.c b/sr_port/mutex_deadlock_check.c
index 963a19e..9875827 100644
--- a/sr_port/mutex_deadlock_check.c
+++ b/sr_port/mutex_deadlock_check.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -63,13 +63,25 @@ GBLREF gd_region *gv_cur_region;
GBLREF sgmnt_addrs *cs_addrs;
GBLREF volatile boolean_t in_mutex_deadlock_check;
GBLREF volatile int4 crit_count;
+VMS_ONLY(GBLREF sgmnt_addrs *vms_mutex_check_csa;)
+#ifdef VMS /* VMS calls this function from mutex.mar which does not pass *csa as a parameter */
void mutex_deadlock_check(mutex_struct_ptr_t criticalPtr)
+#else
+void mutex_deadlock_check(mutex_struct_ptr_t criticalPtr, sgmnt_addrs *csa)
+#endif
{
tp_region *tr;
- sgmnt_addrs *csa;
+ sgmnt_addrs *tp_list_csa_element, *repl_csa;
int4 save_crit_count;
+ boolean_t passed_cur_region;
+ gd_region *region;
+# ifdef VMS
+ sgmnt_addrs *csa;
+ csa = vms_mutex_check_csa; /* vms_mutex_check_csa should be set by mutex_lock* callers */
+# endif
+ assert(csa);
if (in_mutex_deadlock_check)
return;
in_mutex_deadlock_check = TRUE;
@@ -105,53 +117,51 @@ void mutex_deadlock_check(mutex_struct_ptr_t criticalPtr)
*/
if (is_replicator || mu_reorg_process)
{
+ ++crit_deadlock_check_cycle;
+ repl_csa = ((NULL != jnlpool.jnlpool_dummy_reg) && jnlpool.jnlpool_dummy_reg->open)
+ ? &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs : NULL;
if (!dollar_tlevel)
{
- if ((NULL != jnlpool.jnlpool_dummy_reg) && jnlpool.jnlpool_dummy_reg->open)
- {
- ++crit_deadlock_check_cycle;
- if (FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs.critical == criticalPtr)
- { /* grab_lock going for crit on the jnlpool region. gv_cur_region points to the current
- * region of interest, which better have REPL_ENABLED or REPL_WAS_ENABLED, and be now crit
- */
- assert(cs_addrs == &FILE_INFO(gv_cur_region)->s_addrs);
- csa = &FILE_INFO(gv_cur_region)->s_addrs;
- csa->crit_check_cycle = crit_deadlock_check_cycle; /* allow for crit in gv_cur_region */
- }
+ if ((NULL != repl_csa) && (repl_csa->critical == criticalPtr))
+ { /* grab_lock going for crit on the jnlpool region. gv_cur_region points to the current region of
+ * interest, which better have REPL_ENABLED or REPL_WAS_ENABLED, and be now crit
+ */
+ assert(cs_addrs == &FILE_INFO(gv_cur_region)->s_addrs);
+ cs_addrs->crit_check_cycle = crit_deadlock_check_cycle; /* allow for crit in gv_cur_region */
}
} else
- { /* Need to mark the regions allowed to have crit as follows:
- * Place the current cycle into the csa's of regions allowed to have crit so have_crit() can easily test.
- * Note that should the system be up long enough for the 2**32 cycle value to
- * wrap and a region be unused for most of that time, such a region might not be entitled to crit
- * but have an old csa->crit_cycle_check matching the current crit_deadlock_cycle_check -
- * that case would not trigger have_crit() to release crit on that region;
- * however, the next call to this routine increments crit_deadlock_check_cycle and so
- * crit on that region gets released after two calls instead of (the usual) one.
+ { /* Need to mark the regions allowed to have crit as follows: Place the current cycle into the csa's of
+ * regions allowed to have crit so have_crit() can easily test. Note that should the system be up long
+ * enough for the 2**32 cycle value to wrap and a region be unused for most of that time, such a region
+ * might not be entitled to crit but have an old csa->crit_cycle_check matching the current
+ * crit_deadlock_cycle_check - that case would not trigger have_crit() to release crit on that region;
+ * however, the next call to this routine increments crit_deadlock_check_cycle and so crit on that region
+ * gets released after two calls instead of (the usual) one.
*/
- ++crit_deadlock_check_cycle;
+ passed_cur_region = FALSE;
for (tr = tp_reg_list; NULL != tr; tr = tr->fPtr)
- {
+ { /* Keep in mind that We may not have a tp_reg_list with a multiple elements. If we are about to grab
+ * crit on only one region among this list, it is not a deadlock situation (valid FTOK order).
+ */
if (!tr->reg->open)
continue;
- csa = &FILE_INFO(tr->reg)->s_addrs;
- if (csa->now_crit)
- csa->crit_check_cycle = crit_deadlock_check_cycle;
- else
- { /* Seen first non-crit region. Make sure either of the following is true.
- * (i) this is the region we are currently grabbing crit on
- * (ii) we do not hold crit on any region in the tp_reg_list.
- * If neither of the above, we have an out of design condition that can only
- * warrant blowing the process up..
- */
- if ((csa->critical != criticalPtr) && (tr != tp_reg_list))
- GTMASSERT;
- break;
+ tp_list_csa_element = &FILE_INFO(tr->reg)->s_addrs;
+ /* Make sure csa is at the end of this list */
+ if (tp_list_csa_element == csa)
+ passed_cur_region = TRUE;
+ if (tp_list_csa_element->now_crit)
+ {
+ tp_list_csa_element->crit_check_cycle = crit_deadlock_check_cycle;
+ if (passed_cur_region)
+ break;
}
}
+ /* All regions including current must be in the tp_reg_list. */
+ /* Journal pool dummy region will NEVER be in the tp_reg_list */
+ assert(passed_cur_region || (csa == repl_csa));
}
/* Release crit in regions not legitimately part of this TP/non-TP transaction */
- have_crit(CRIT_RELEASE | CRIT_NOT_TRANS_REG);
+ have_crit(CRIT_HAVE_ANY_REG | CRIT_RELEASE | CRIT_NOT_TRANS_REG);
}
/* Reset "crit_count" before resetting "in_mutex_deadlock_check" to FALSE. The order of the sets is important.
* The periodic dbsync timer "wcs_clean_dbsync" depends on this order to correctly check if mainline code is
diff --git a/sr_port/mutex_deadlock_check.h b/sr_port/mutex_deadlock_check.h
index 6cabbf5..49cce6b 100644
--- a/sr_port/mutex_deadlock_check.h
+++ b/sr_port/mutex_deadlock_check.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2002 Sanchez Computer Associates, Inc. *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -12,6 +12,10 @@
#ifndef MUTEX_DEADLOCK_CHECK_INCLUDED
#define MUTEX_DEADLOCK_CHECK_INCLUDED
+#ifdef VMS
void mutex_deadlock_check(mutex_struct_ptr_t addr);
+#else
+void mutex_deadlock_check(mutex_struct_ptr_t addr, sgmnt_addrs *csa);
+#endif
#endif
diff --git a/sr_port/mvalconv.c b/sr_port/mvalconv.c
index 03cc6c1..a1a94ac 100644
--- a/sr_port/mvalconv.c
+++ b/sr_port/mvalconv.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -18,11 +18,10 @@
#include "gtm_stdio.h" /* this is here due to the need for an SPRINTF,
* which is in turn due the kudge that is the current double2mval routine
*/
-#ifdef GTM64
/* we return strings for >18 digit 64-bit numbers, so pull in stringpool */
#include "stringpool.h"
+
GBLREF spdesc stringpool;
-#endif
LITREF int4 ten_pwr[];
@@ -68,9 +67,9 @@ void i2smval(mval *v, uint4 i)
assert(v->m[1] < MANT_HI);
}
-void xi2mval(mval *v, unsigned int i);
+void xi2mval(mval *v, unsigned int i);
-void i2usmval(mval *v, unsigned int i)
+void i2usmval(mval *v, unsigned int i)
{
v->mvtype = MV_NM;
v->sgn = 0;
@@ -78,7 +77,7 @@ void i2usmval(mval *v, unsigned int i)
xi2mval(v, i);
}
-void i2mval(mval *v, int i)
+void i2mval(mval *v, int i)
{
int4 n;
@@ -100,7 +99,7 @@ void i2mval(mval *v, int i)
* The primary routines set the sgn flag and pass the absolute value
* to xi2mval. */
-void xi2mval(mval *v, unsigned int i)
+void xi2mval(mval *v, unsigned int i)
{
int exp;
@@ -128,20 +127,19 @@ void xi2mval(mval *v, unsigned int i)
}
}
-#ifdef GTM64
-void xl2mval(mval *v, unsigned long i);
+void xi82mval(mval *v, gtm_uint64_t i);
-void ul2mval(mval *v, unsigned long i)
+void ui82mval(mval *v, gtm_uint64_t i)
{
v->mvtype = MV_NM;
v->sgn = 0;
- xl2mval(v, i);
+ xi82mval(v, i);
}
-void l2mval(mval *v, long i)
+void i82mval(mval *v, gtm_int64_t i)
{
- gtm_uint8 absi;
+ gtm_uint64_t absi;
v->mvtype = MV_NM;
if (i < 0)
@@ -154,21 +152,19 @@ void l2mval(mval *v, long i)
absi = i;
}
- xl2mval(v, absi);
+ xi82mval(v, absi);
}
-/* xl2mval does the bulk of the conversion for l2mval and ul2mval.
- * The primary routines set the sgn flag and pass the absolute value
- * to xl2mval. In the case of a >18 digit number, xl2mval examines the
- * sgn flag to determine whether to convert back to signed before string
- * conversion. */
-
-void xl2mval(mval *v, unsigned long i)
+/* This function does the bulk of the conversion for i82mval and ui82mval. The primary routines set the sgn flag and pass the
+ * absolute value to xi82mval(). In the case of a >18 digit number, xi82mval() examines the sgn flag to determine whether to
+ * switch back to a signed value before string conversion.
+ */
+void xi82mval(mval *v, gtm_uint64_t i)
{
int exp;
uint4 low;
uint4 high;
- char buf[21]; /* [possible] sign, [up to] 19L/20UL digits, and terminator */
+ char buf[21]; /* [possible] sign, [up to] 19L/20UL digits, and terminator. */
int len;
if (i < INT_HI)
@@ -190,43 +186,38 @@ void xl2mval(mval *v, unsigned long i)
v->e = exp;
v->m[0] = low;
v->m[1] = high;
- } else if (i < (unsigned long)MANT_HI*MANT_HI)
+ } else if (i < (gtm_uint64_t)MANT_HI * MANT_HI)
{
low = i % MANT_HI;
high = i / MANT_HI;
exp = EXP_IDX_BIAL + 9;
-
while (high < MANT_LO)
{
- high = high*10 + low/MANT_LO;
- low = low%MANT_LO * 10;
+ high = (high * 10) + (low / MANT_LO);
+ low = (low % MANT_LO) * 10;
exp--;
}
v->e = exp;
v->m[0] = low;
v->m[1] = high;
} else
- {
- /* the value won't fit in 18 digits, so return a string */
+ { /* The value won't fit in 18 digits, so return a string. */
if (v->sgn)
- len = SPRINTF(buf, "%ld", -(long)i);
+ len = SPRINTF(buf, "%lld", -(gtm_int64_t)i);
else
- len = SPRINTF(buf, "%lu", i);
-
+ len = SPRINTF(buf, "%llu", i);
+ assert(18 < len);
ENSURE_STP_FREE_SPACE(len);
memcpy(stringpool.free, buf, len);
-
v->mvtype = MV_STR;
v->str.len = len;
v->str.addr = (char *)stringpool.free;
-
stringpool.free += len;
}
- assert(v->mvtype != MV_NM || v->m[1] < MANT_HI);
- assert(v->mvtype != MV_NM || v->m[1] >= MANT_LO);
+ assert((v->mvtype != MV_NM) || (v->m[1] < MANT_HI));
+ assert((v->mvtype != MV_NM) || (v->m[1] >= MANT_LO));
}
}
-#endif
double mval2double(mval *v)
{
@@ -241,7 +232,7 @@ double mval2double(mval *v)
{
exp = v->e;
y = v->m[0];
- y = y/MANT_HI;
+ y = y / MANT_HI;
while (exp > EXP_IDX_BIAL)
{
x *= MANT_HI;
@@ -262,11 +253,17 @@ double mval2double(mval *v)
return x;
}
-/* a (barely suitable) double2mval */
-void double2mval(mval *dst, double src)
+void float2mval(mval *dst, float src)
{
- char buf[67]; /* [possible] sign, decimal-point, [up to] 64 digits, and terminator */
- SPRINTF(buf, "%lf", src);
+ char buf[16]; /* The maximum-length value in the 'F' representation would look like -0.123457 (that is,
+ * sign[1] + zero[1] + dot[1] + digits[6] = 9). Note that for values below -1 the number would
+ * be shorter, since the integer part would be counted against the precision capacity. However,
+ * a longer representation is possible in the 'E' format: -1.23456E+12 (that is, sign[1] +
+ * digit[1] + dot[1] + digits[5] + E[1] + sign[1] + exp[2] = 12). Although we only need to
+ * additionally worry about one termination character, we will be safe and allocate 16 bytes
+ * instead of 13. */
+
+ SPRINTF(buf, "%.6G", src);
dst->mvtype = MV_STR;
dst->str.len = STRLEN(buf);
dst->str.addr = buf;
@@ -275,8 +272,26 @@ void double2mval(mval *dst, double src)
return;
}
+void double2mval(mval *dst, double src)
+{
+ char buf[32]; /* The maximum-length value in the 'F' representation would look like -0.123456789012345
+ * (that is, sign[1] + zero[1] + dot[1] + digits[15] = 18). Note that for values below -1
+ * the number would be shorter, since the integer part would be counted against the
+ * precision capacity. However, a longer representation is possible in the 'E' format:
+ * -1.234567890123456E+123 (that is, sign[1] + digit[1] + dot[1] + digits[14] + E[1] +
+ * sign[1] + exp[3] = 23). Although we only need to additionally worry about one termination
+ * character, we will be safe and allocate 32 bytes instead of 24. */
+
+ SPRINTF(buf, "%.15G", src);
+ dst->mvtype = MV_STR;
+ dst->str.len = STRLEN(buf);
+ dst->str.addr = buf;
+ s2n(dst);
+ dst->mvtype &= ~MV_STR;
+ return;
+}
-/* converts an mval into a 32-bit signed integer, or MAXPOSINT4 on overflow */
+/* Converts an mval into a 32-bit signed integer, or MAXPOSINT4 on overflow. */
int4 mval2i(mval *v)
{
int4 i;
@@ -285,7 +300,7 @@ int4 mval2i(mval *v)
MV_FORCE_NUM(v);
if (v->mvtype & MV_INT)
- i = v->m[1]/MV_BIAS;
+ i = v->m[1] / MV_BIAS;
else
{
exp = v->e;
@@ -301,7 +316,7 @@ int4 mval2i(mval *v)
return i;
}
-/* converts an mval into a 32-bit unsigned integer, or MAXUINT4 on overflow */
+/* Converts an mval into a 32-bit unsigned integer, or MAXUINT4 on overflow. */
uint4 mval2ui(mval *v)
{
uint4 i;
@@ -310,7 +325,7 @@ uint4 mval2ui(mval *v)
MV_FORCE_NUM(v);
if (v->mvtype & MV_INT)
- i = v->m[1]/MV_BIAS;
+ i = v->m[1] / MV_BIAS;
else
{
exp = v->e;
@@ -326,13 +341,79 @@ uint4 mval2ui(mval *v)
return i;
}
+
+/* Converts an mval into a 64-bit unsigned integer. */
+gtm_uint64_t mval2ui8(mval *v)
+{
+ return (gtm_uint64_t)mval2i8(v);
+}
+
+gtm_int64_t mval2i8(mval *v)
+{
+ gtm_int64_t x, y;
+ int exp;
+
+ MV_FORCE_NUM(v);
+ if (v->mvtype & MV_INT)
+ x = v->m[1] / MV_BIAS;
+ else
+ {
+ exp = v->e;
+ if (exp > EXP_IDX_BIAL)
+ { /* Case where to get the actual value we need to multiply by power of exponent. */
+ x = v->m[1];
+ y = v->m[0];
+ if (y > 0)
+ { /* Both m[0] and m[1] are used, so multiply in parallel, but first ensure that the m[1] part has
+ * a decimal exponent of MANT_HI order.
+ */
+ x *= MANT_HI;
+ while (exp > EXP_IDX_BIAL + 18)
+ { /* Keep multiplying by 10^9, but keep a precision "buffer" of 18 to prevent further
+ * divisions, as we might otherwise compromise the available precision of mval.
+ */
+ x *= MANT_HI;
+ y *= MANT_HI;
+ exp -= 9;
+ }
+ if (exp >= EXP_IDX_BIAL + 9)
+ { /* Multiply by the remaining power of the exponent. */
+ x *= ten_pwr[exp - EXP_IDX_BIAL - 9];
+ y *= ten_pwr[exp - EXP_IDX_BIAL - 9];
+ } else
+ { /* Case where exponent indicates a total power of less than 10^9, which, given that both
+ * m[0] and m[1] are used and that x has already been multiplied by 10^9, requires a
+ * division to make the sum of m[0] and m[1] represent the right number.
+ */
+ x /= ten_pwr[EXP_IDX_BIAL + 9 - exp];
+ y /= ten_pwr[EXP_IDX_BIAL + 9 - exp];
+ }
+ } else
+ { /* Since m[0] is not used, just multiply x by the excess power of the exponent. */
+ while (exp > EXP_IDX_BIAL + 9)
+ {
+ x *= MANT_HI;
+ exp -= 9;
+ }
+ x *= ten_pwr[exp - EXP_IDX_BIAL];
+ }
+
+ x = (v->sgn ? -x - y : x + y);
+ } else if (exp < MV_XBIAS)
+ x = 0;
+ else
+ x = (v->sgn ? -v->m[1] : v->m[1]) / ten_pwr[EXP_IDX_BIAL - exp];
+ }
+ return x;
+}
+
/* isint == v can be represented as a 9 digit (or less) integer (positive or negative).
* If return value is TRUE, then "*intval" contains the integer value stored in "v".
* Note: "*intval" could have been updated even if return value is FALSE.
*/
boolean_t isint(mval *v, int4 *intval)
{
- int exp, m1, mvtype, divisor, m1_div, m1_sgn;
+ int exp, m1, mvtype, divisor, m1_div;
DEBUG_ONLY(boolean_t is_canonical;)
mvtype = v->mvtype;
diff --git a/sr_port/mvalconv.h b/sr_port/mvalconv.h
index c71a069..a32e26f 100644
--- a/sr_port/mvalconv.h
+++ b/sr_port/mvalconv.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -19,13 +19,14 @@
void i2smval(mval *v, uint4 i);
void i2usmval(mval *v, unsigned int i);
void i2mval(mval *v, int i);
-#ifdef GTM64
-void ul2mval(mval *v, unsigned long i);
-void l2mval(mval *v, long i);
-#endif
+void ui82mval(mval *v, gtm_uint64_t i);
+void i82mval(mval *v, gtm_int64_t i);
+void float2mval(mval *dst, float src);
void double2mval(mval *dst, double src);
double mval2double(mval *v);
int4 mval2i(mval *v);
+gtm_int64_t mval2i8(mval *v);
+gtm_uint64_t mval2ui8(mval *v);
uint4 mval2ui(mval *v);
boolean_t isint (mval *v, int4 *intval);
diff --git a/sr_port/objlabel.h b/sr_port/objlabel.h
index 56d17b4..be31810 100644
--- a/sr_port/objlabel.h
+++ b/sr_port/objlabel.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -33,7 +33,7 @@
* Note that OBJ_UNIX_LABEL and OBJ_PLATFORM_LABEL should not exceed 255.
*/
-#define OBJ_UNIX_LABEL 24 /* When changed, be sure to zero the platform specific numbers below (if any non-0) */
+#define OBJ_UNIX_LABEL 25 /* 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 5641158..beffda0 100644
--- a/sr_port/one_job_param.c
+++ b/sr_port/one_job_param.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -63,9 +63,15 @@ LITDEF jp_datatype job_param_datatypes[] =
#include "jobparams.h"
};
+/* Maximum length string for any JOB parameter. Length limit
+ * dictated by having only one byte to represent the string
+ * length. That translates to 255 characters*/
+#define MAXJOBPARSTRLEN 255
+
error_def(ERR_JOBPARNOVAL);
error_def(ERR_JOBPARNUM);
error_def(ERR_JOBPARSTR);
+error_def(ERR_JOBPARTOOLONG);
error_def(ERR_JOBPARUNK);
error_def(ERR_JOBPARVALREQ);
@@ -118,6 +124,11 @@ int one_job_param (char **parptr)
return FALSE;
}
len = (TREF(window_mval)).str.len;
+ if (MAXJOBPARSTRLEN < len)
+ {
+ stx_error (ERR_JOBPARTOOLONG);
+ return FALSE;
+ }
*(*parptr)++ = len;
memcpy(*parptr, (TREF(window_mval)).str.addr, len);
*parptr += len;
diff --git a/sr_port/op.h b/sr_port/op.h
index 205d304..07f1140 100644
--- a/sr_port/op.h
+++ b/sr_port/op.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -54,9 +54,9 @@ void op_fnascii(int4 num, mval *in, mval *out);
void op_fnchar(UNIX_ONLY_COMMA(int cnt) mval *dst, ...);
void op_fnextract(int last, int first, mval *src, mval *dest);
#ifdef __sun
-void op_fnfgncal(uint4 n_mvals, ...);
int op_fnfgncal_rpc(unsigned int n_mvals, ...); /* typ to keep the compiler happy as set into xfer_table, which is int */
-#elif defined(UNIX)
+#endif
+#if defined(UNIX)
void op_fnfgncal(uint4 n_mvals, mval *dst, mval *package, mval *extref, uint4 mask, int4 argcnt, ...);
#elif defined(VMS)
void op_fnfgncal(mval *dst, ...);
@@ -127,6 +127,9 @@ void op_fnzlkid(mint boolex, mval *retval);
void op_fnzm(mint x, mval *v);
void op_fnzp1(mval *src, int del, int trgpcidx, UNIX1_VMS2(mval *dst, boolean_t srcisliteral));
void op_fnzparse(mval *file, mval *field, mval *def1, mval *def2, mval *type, mval *ret);
+#ifdef UNIX
+void op_fnzpeek(mval *baseaddr, int offset, int len, mval *format, mval *ret);
+#endif
void op_fnzpid(mint boolexpr, mval *ret);
void op_fnzpiece(mval *src, mval *del, int first, int last, UNIX1_VMS2(mval *dst, boolean_t srcisliteral));
void op_fnzpopulation(mval *arg1, mval *arg2, mval *dst);
@@ -208,6 +211,7 @@ void op_killall(void);
void op_killall(void);
int op_linefetch();
int op_linestart();
+void op_litc(mval *dst, mval *src);
void op_lkinit(void);
void op_lkname(UNIX_ONLY_COMMA(int subcnt) mval *extgbl1, ...);
int op_lock(int timeout);
@@ -245,6 +249,7 @@ int op_startintrrpt();
#elif defined(VMS)
void op_startintrrpt();
#endif
+void op_stolitc(mval *val);
void op_sub(mval *u, mval *v, mval *s);
void op_sub(mval *u, mval *v, mval *s);
void op_svget(int varnum, mval *v);
@@ -279,13 +284,11 @@ void op_wtone(int c);
void op_wttab(mint x);
void op_xkill(UNIX_ONLY_COMMA(int n) mval *lvname_arg, ...);
void op_xnew(UNIX_ONLY_COMMA(unsigned int argcnt_arg) mval *s_arg, ...);
-int op_zalloc2(int4 timeout, UINTPTR_T auxown);
int op_zallocate(int timeout);
-int op_zallocate(int timeout); /***type int added***/
void op_zattach(mval *);
int op_zbfetch();
int op_zbstart();
-void op_zcompile(mval *v, boolean_t mExtReqd);
+void op_zcompile(mval *v, boolean_t ignore_dollar_zcompile);
void op_zcont(void);
void op_zdealloc2(int4 timeout, UINTPTR_T auxown);
void op_zdeallocate(int4 timeout);
diff --git a/sr_port/op_bindparm.c b/sr_port/op_bindparm.c
index 1e7aedb..501f4a3 100644
--- a/sr_port/op_bindparm.c
+++ b/sr_port/op_bindparm.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -69,9 +69,12 @@ void op_bindparm(UNIX_ONLY_COMMA(int frmc) int frmp_arg, ...)
prev_count = *prev_count_ptr;
/* If we were dealing with a new job, then push_parm would not have been called if the number of
* actuals was 0; so, by checking for proper frame value stored in the parameter pool we ensure
- * that we are not looking at some uninitialized value here.
+ * that we are not looking at some uninitialized value here. Note that although we protect against
+ * fall-throughs into labels with a formallist now, in case two consecutive invocations to
+ * op_bindparm happen without a push_parm in between, do not attempt to use a previously utilized
+ * parameter set.
*/
- if (PARM_ACT_FRAME(curr_slot, prev_count) != frame_pointer)
+ if ((PARM_ACT_FRAME(curr_slot, prev_count) != frame_pointer) || (SAFE_TO_OVWRT <= prev_count))
actc = 0;
else
{ /* Acquire mask, actual count, and pointer to actual list from the parameter pool. */
@@ -91,7 +94,7 @@ void op_bindparm(UNIX_ONLY_COMMA(int frmc) int frmp_arg, ...)
{
error = TRUE;
*prev_count_ptr += SAFE_TO_OVWRT;
- rts_error(VARLSTCNT(1) ERR_ACTLSTTOOLONG);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ACTLSTTOOLONG);
}
VAR_START(var, frmp_arg);
for (i = 0; i < frmc; i++, frmp = va_arg(var, int4), actp++)
diff --git a/sr_port/op_fntext.c b/sr_port/op_fntext.c
index 14daecb..4687862 100644
--- a/sr_port/op_fntext.c
+++ b/sr_port/op_fntext.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -25,7 +25,6 @@
GBLREF spdesc stringpool;
-error_def(ERR_TXTNEGLIN);
error_def(ERR_TXTSRCMAT);
error_def(ERR_ZLINKFILE);
error_def(ERR_ZLMODULE);
@@ -42,7 +41,9 @@ void op_fntext(mval *label, int int_exp, mval *rtn, mval *ret)
uint4 stat;
rhdtyp *rtn_vector;
boolean_t is_trigger;
+ DCL_THREADGBL_ACCESS;
+ SETUP_THREADGBL_ACCESS;
MV_FORCE_STR(label);
MV_FORCE_STR(rtn);
temp_rtn = &temp_mval;
@@ -56,8 +57,16 @@ void op_fntext(mval *label, int int_exp, mval *rtn, mval *ret)
stat = ZEROLINE;
else
{
- GTMTRIG_ONLY(if (is_trigger) DBGTRIGR((stderr, "op_fntext: fetching $TEXT() source for a trigger\n")));
+#ifdef GTM_TRIGGER
+ if (is_trigger)
+ {
+ DBGTRIGR((stderr, "op_fntext: fetching $TEXT() source for a trigger\n"));
+ assert(FALSE == TREF(in_op_fntext));
+ TREF(in_op_fntext) = TRUE;
+ }
+#endif
stat = get_src_line(temp_rtn, label, int_exp, &sld, VERIFY);
+ GTMTRIG_ONLY(TREF(in_op_fntext) = FALSE);
}
if (0 == (stat & (CHECKSUMFAIL | NEGATIVELINE)))
{
diff --git a/sr_port/op_fnview.c b/sr_port/op_fnview.c
index caf020f..adcef90 100644
--- a/sr_port/op_fnview.c
+++ b/sr_port/op_fnview.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -38,6 +38,7 @@
#include "alias.h"
#include "gtmimagename.h"
#include "fullbool.h"
+#include "wbox_test_init.h"
GBLREF spdesc stringpool;
GBLREF int4 cache_hits, cache_fails;
@@ -268,7 +269,7 @@ void op_fnview(UNIX_ONLY_COMMA(int numarg) mval *dst, ...)
case VTK_NOISOLATION:
if (NOISOLATION_NULL != parmblk.ni_list.type || NULL == parmblk.ni_list.gvnh_list
|| NULL != parmblk.ni_list.gvnh_list->next)
- rts_error(VARLSTCNT(1) ERR_VIEWFN);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_VIEWFN);
n = parmblk.ni_list.gvnh_list->gvnh->noisolation;
break;
case VTK_PATCODE:
@@ -276,23 +277,35 @@ void op_fnview(UNIX_ONLY_COMMA(int numarg) mval *dst, ...)
s2pool(&tmpstr);
dst->str = tmpstr;
break;
+#ifdef DEBUG
+ case VTK_PROBECRIT:
+ if (!gd_header) /* IF GD_HEADER ==0 THEN OPEN GBLDIR */
+ gvinit();
+ if (!parmblk.gv_ptr->open)
+ gv_init_reg(parmblk.gv_ptr);
+ reg = parmblk.gv_ptr;
+ grab_crit(reg);
+ if (!WBTEST_ENABLED(WBTEST_HOLD_CRIT_ENABLED))
+ rel_crit(reg);
+ break;
+#endif
case VTK_REGION:
- /* if gd_header is null then get the current one, and update the gd_map */
- if (!gd_header)
- {
- SET_GD_HEADER(v);
- SET_GD_MAP;
- }
- DEBUG_ONLY(else GD_HEADER_ASSERT);
- map = gd_map;
- map++; /* get past local locks */
- for (; memcmp(parmblk.ident.c, map->name, SIZEOF(mident_fixed)) >= 0; map++)
- assert(map < gd_map_top);
- reg = map->reg.addr;
- tmpstr.addr = (char *)reg->rname;
- tmpstr.len = reg->rname_len;
- s2pool(&tmpstr);
- dst->str = tmpstr;
+ /* if gd_header is null then get the current one, and update the gd_map */
+ if (!gd_header)
+ {
+ SET_GD_HEADER(v);
+ SET_GD_MAP;
+ }
+ DEBUG_ONLY(else GD_HEADER_ASSERT);
+ map = gd_map;
+ map++; /* get past local locks */
+ for (; memcmp(parmblk.ident.c, map->name, SIZEOF(mident_fixed)) >= 0; map++)
+ assert(map < gd_map_top);
+ reg = map->reg.addr;
+ tmpstr.addr = (char *)reg->rname;
+ tmpstr.len = reg->rname_len;
+ s2pool(&tmpstr);
+ dst->str = tmpstr;
break;
case VTK_RTNEXT:
view_routines(dst, &parmblk.ident);
@@ -405,15 +418,11 @@ void op_fnview(UNIX_ONLY_COMMA(int numarg) mval *dst, ...)
n = -1;
if (arg)
{
- if (!MEMCMP_LIT(arg->str.addr, "nct"))
+ if (0 == MEMCMP_LIT(arg->str.addr, "nct"))
n = TREF(local_coll_nums_as_strings) ? 1 : 0;
- else
- {
- assert(!MEMCMP_LIT(arg->str.addr, "ncol"));
+ else if (0 == MEMCMP_LIT(arg->str.addr, "ncol"))
n = TREF(local_collseq_stdnull);
- }
- }
- if (-1 == n)
+ } else
n = TREF(local_collseq) ? (TREF(local_collseq))->act : 0;
break;
case VTK_ZDEFBUFF:
@@ -472,13 +481,13 @@ void op_fnview(UNIX_ONLY_COMMA(int numarg) mval *dst, ...)
case VTK_LOGTPRESTART:
n = TREF(tprestart_syslog_delta);
break;
-#ifndef VMS
+# ifndef VMS
case VTK_JNLERROR:
n = TREF(error_on_jnl_file_lost);
break;
-#endif
+# endif
default:
- rts_error(VARLSTCNT(1) ERR_VIEWFN);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_VIEWFN);
}
dst->mvtype = vtp->restype;
if (MV_NM == vtp->restype)
diff --git a/sr_port/op_halt.c b/sr_port/op_halt.c
index 7ab626b..d8124b8 100644
--- a/sr_port/op_halt.c
+++ b/sr_port/op_halt.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -47,6 +47,6 @@ void op_halt(void)
0, zposition.str.len, zposition.str.addr);
}
# endif
- exit(0);
+ exit(EXIT_SUCCESS);
#endif
}
diff --git a/sr_port/op_hang.c b/sr_port/op_hang.c
index 1dfc336..28ace8f 100644
--- a/sr_port/op_hang.c
+++ b/sr_port/op_hang.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -81,6 +81,10 @@ error_def(ERR_SYSCALL);
* Any caught signal will terminate the sleep
* following the execution of that signal's catching routine.
*
+ * The actual hang duration should be NO LESS than the specified
+ * duration for specified durations greater than .001 seconds.
+ * Certain applications depend on this assumption.
+ *
* Arguments:
* num - time to sleep
*
@@ -91,6 +95,7 @@ error_def(ERR_SYSCALL);
void op_hang(mval* num)
{
int ms;
+ double tmp;
mv_stent *mv_zintcmd;
ABS_TIME cur_time, end_time;
# ifdef VMS
@@ -110,16 +115,16 @@ void op_hang(mval* num)
ms = num->m[1] * (1000 / MV_BIAS);
}
} else if (0 == num->sgn) /* if sign is not 0 it means num is negative */
- ms = mval2i(num) * 1000; /* too big to care about fractional amounts */
+ {
+ tmp = mval2double(num) * (double)1000;
+ ms = ((double)MAXPOSINT4 >= tmp) ? (int)tmp : (int)MAXPOSINT4;
+ }
if (ms)
{
if (TREF(tpnotacidtime) * 1000 < ms)
TPNOTACID_CHECK(HANGSTR);
# if defined(DEBUG) && defined(UNIX)
- if (gtm_white_box_test_case_enabled
- && (WBTEST_DEFERRED_TIMERS == gtm_white_box_test_case_number)
- && (3 > gtm_white_box_test_case_count)
- && (123000 == ms))
+ if (WBTEST_ENABLED(WBTEST_DEFERRED_TIMERS) && (3 > gtm_white_box_test_case_count) && (123000 == ms))
{
DEFER_INTERRUPTS(INTRPT_NO_TIMER_EVENTS);
DBGFPF((stderr, "OP_HANG: will sleep for 20 seconds\n"));
@@ -128,23 +133,16 @@ void op_hang(mval* num)
ENABLE_INTERRUPTS(INTRPT_NO_TIMER_EVENTS);
return;
}
- if (gtm_white_box_test_case_enabled
- && (WBTEST_BREAKMPC == gtm_white_box_test_case_number)
- && (0 == gtm_white_box_test_case_count)
- && (999 == ms))
+ if (WBTEST_ENABLED(WBTEST_BREAKMPC)&& (0 == gtm_white_box_test_case_count) && (999 == ms))
{
frame_pointer->old_frame_pointer->mpc = (unsigned char *)GTM64_ONLY(0xdeadbeef12345678)
NON_GTM64_ONLY(0xdead1234);
return;
}
- /* Upon seeing a .999s hang this white-box test launches a timer that pops with a period of UTIL_OUT_SYSLOG_INTERVAL
- * and prints a long message via util_out_ptr.
- */
- if (gtm_white_box_test_case_enabled
- && (WBTEST_UTIL_OUT_BUFFER_PROTECTION == gtm_white_box_test_case_number)
- && (0 == gtm_white_box_test_case_count)
- && (999 == ms))
- {
+ if (WBTEST_ENABLED(WBTEST_UTIL_OUT_BUFFER_PROTECTION) && (0 == gtm_white_box_test_case_count) && (999 == ms))
+ { /* Upon seeing a .999s hang this white-box test launches a timer that pops with a period of
+ * UTIL_OUT_SYSLOG_INTERVAL and prints a long message via util_out_ptr.
+ */
start_timer((TID)&util_out_syslog_dump, UTIL_OUT_SYSLOG_INTERVAL, util_out_syslog_dump, 0, NULL);
return;
}
@@ -177,28 +175,27 @@ void op_hang(mval* num)
if (0 == ms)
return; /* done HANGing */
}
- UNIX_ONLY(hiber_start(ms);)
- VMS_ONLY(
- time[0] = -time_low_ms(ms);
- time[1] = -time_high_ms(ms) - 1;
- efn_mask = (1 << efn_outofband | 1 << efn_timer);
- if (SS$_NORMAL != (status = sys$setimr(efn_timer, &time, NULL, &time, 0)))
- rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("$setimr"), CALLFROM, status);
- if (SS$_NORMAL != (status = sys$wflor(efn_outofband, efn_mask)))
- rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("$wflor"), CALLFROM, status);
- )
+# ifdef UNIX
+ hiber_start(ms);
+# elif defined(VMS)
+ time[0] = -time_low_ms(ms);
+ time[1] = -time_high_ms(ms) - 1;
+ efn_mask = (1 << efn_outofband | 1 << efn_timer);
+ if (SS$_NORMAL != (status = sys$setimr(efn_timer, &time, NULL, &time, 0)))
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("$setimr"), CALLFROM, status);
+ if (SS$_NORMAL != (status = sys$wflor(efn_outofband, efn_mask)))
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("$wflor"), CALLFROM, status);
if (outofband)
{
- VMS_ONLY(
- if (SS$_WASCLR == (status = sys$readef(efn_timer, &efn_mask)))
- {
- if (SS$_NORMAL != (status = sys$cantim(&time, 0)))
- rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("$cantim"), CALLFROM,
- status);
- } else
- assertpro(SS$_WASSET == status);
- )
+ if (SS$_WASCLR == (status = sys$readef(efn_timer, &efn_mask)))
+ {
+ if (SS$_NORMAL != (status = sys$cantim(&time, 0)))
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("$cantim"),
+ CALLFROM, status);
+ } else
+ assertpro(SS$_WASSET == status);
}
+# endif
} else
rel_quant();
if (outofband)
diff --git a/sr_port/op_indlvnamadr.c b/sr_port/op_indlvnamadr.c
index 37067b1..c238d3d 100644
--- a/sr_port/op_indlvnamadr.c
+++ b/sr_port/op_indlvnamadr.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -17,6 +17,7 @@
#include "cache.h"
#include "hashtab_objcode.h"
#include "op.h"
+#include "advancewindow.h"
error_def(ERR_VAREXPECTED);
@@ -42,6 +43,7 @@ void op_indlvnamadr(mval *target)
case TK_IDENT:
rval = EXPR_GOOD;
v = put_mvar(&(TREF(window_ident)));
+ advancewindow();
break;
case TK_ATSIGN:
if (EXPR_FAIL != (rval = indirection(&v))) /* NOTE assignment */
diff --git a/sr_port/op_litc.c b/sr_port/op_litc.c
new file mode 100644
index 0000000..132b3b3
--- /dev/null
+++ b/sr_port/op_litc.c
@@ -0,0 +1,34 @@
+/****************************************************************
+ * *
+ * Copyright 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "cmd_qlf.h"
+#include "op.h"
+#include <rtnhdr.h>
+#include "stack_frame.h"
+#include "stringpool.h"
+
+GBLREF stack_frame *frame_pointer;
+
+void op_litc(mval *dst, mval *src)
+{
+# ifdef USHBIN_SUPPORTED
+ assert(DYNAMIC_LITERALS_ENABLED(frame_pointer->rvector));
+ assert((char *)frame_pointer->literal_ptr == (char *)frame_pointer->rvector->literal_adr);
+ assert(MVAL_IN_RANGE(src, frame_pointer->literal_ptr, frame_pointer->rvector->literal_len)); /* src is a literal mval */
+ assert(!MVAL_IN_RANGE(dst, frame_pointer->literal_ptr, frame_pointer->rvector->literal_len)); /* dst is NOT a literal */
+ *dst = *src;
+ dst->str.addr += (INTPTR_T)(frame_pointer->rvector->literal_text_adr);
+# else
+ assert(FALSE);
+# endif
+ return;
+}
diff --git a/sr_port/op_lock2.c b/sr_port/op_lock2.c
index 79c4210..815cafb 100644
--- a/sr_port/op_lock2.c
+++ b/sr_port/op_lock2.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -78,6 +78,7 @@ error_def(ERR_LOCKINCR2HIGH);
error_def(ERR_LOCKIS);
#define LOCKTIMESTR "LOCK time too long"
+#define ZALLOCTIMESTR "ZALLOCATE time too long"
/* We made this a error seperate function because we did not wanted to do the MAXSTR_BUFF_DECL(buff) declartion in op_lock2,
* because MAXSTR_BUFF_DECL macro would allocate a huge stack every time op_lock2 is called.
@@ -96,7 +97,6 @@ STATICFNDCL void level_err(mlk_pvtblk *pvt_ptr)
/*
* -----------------------------------------------
- * Maintain in parallel with op_zalloc2
* Arguments:
* timeout - max. time to wait for locks before giving up
* laflag - passed to gvcmx* routines as "laflag" argument;
@@ -124,7 +124,6 @@ int op_lock2(int4 timeout, unsigned char laflag) /* timeout is in seconds */
unsigned char action;
ABS_TIME cur_time, end_time, remain_time;
mv_stent *mv_zintcmd;
-
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
@@ -134,7 +133,12 @@ int op_lock2(int4 timeout, unsigned char laflag) /* timeout is in seconds */
if (timeout < 0)
timeout = 0;
else if (TREF(tpnotacidtime) < timeout)
- TPNOTACID_CHECK(LOCKTIMESTR);
+ {
+ if (CM_ZALLOCATES == cm_action)
+ TPNOTACID_CHECK(ZALLOCTIMESTR)
+ else
+ TPNOTACID_CHECK(LOCKTIMESTR)
+ }
if (!(timer_on = (NO_M_TIMEOUT != timeout))) /* NOTE assignment */
msec_timeout = NO_M_TIMEOUT;
else
@@ -219,6 +223,9 @@ int op_lock2(int4 timeout, unsigned char laflag) /* timeout is in seconds */
else
level_err(pvt_ptr1);
break;
+ case CM_ZALLOCATES:
+ pvt_ptr1->zalloc = TRUE;
+ break;
default:
GTMASSERT;
break;
@@ -241,7 +248,8 @@ int op_lock2(int4 timeout, unsigned char laflag) /* timeout is in seconds */
action = LOCKED;
break;
case INCREMENTAL:
- action = INCREMENTAL;
+ case CM_ZALLOCATES:
+ action = cm_action;
break;
default:
GTMASSERT;
@@ -256,7 +264,10 @@ int op_lock2(int4 timeout, unsigned char laflag) /* timeout is in seconds */
if (dollar_tlevel && (CDB_STAGNATE <= t_tries))
{ /* upper TPNOTACID_CHECK conditioned on no short timeout; this one rel_crits to avoid potential deadlock */
assert(TREF(tpnotacidtime) >= timeout);
- TPNOTACID_CHECK(LOCKTIMESTR);
+ if (CM_ZALLOCATES == action)
+ TPNOTACID_CHECK(ZALLOCTIMESTR)
+ else
+ TPNOTACID_CHECK(LOCKTIMESTR)
}
for (;;)
{
diff --git a/sr_port/op_setfnretin2als.c b/sr_port/op_setfnretin2als.c
index d6e3ce7..89283ac 100644
--- a/sr_port/op_setfnretin2als.c
+++ b/sr_port/op_setfnretin2als.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2010, 2011 Fidelity Information Services, Inc *
+ * Copyright 2010, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -60,14 +60,10 @@ void op_setfnretin2als(mval *srcmv, int destindx)
int4 srcsymvlvl;
boolean_t added;
- error_def(ERR_ALIASEXPECTED);
-
assert(alias_retarg == srcmv);
assert(srcmv);
assert(srcmv->mvtype & MV_ALIASCONT);
- /* Verify is a temp mval */
- assert((char *)srcmv >= (char *)frame_pointer->temps_ptr
- && (char *)srcmv < ((char *)frame_pointer->temps_ptr + (SIZEOF(char *) * frame_pointer->temp_mvals)));
+ assert(MVAL_IN_RANGE(srcmv, frame_pointer->temps_ptr, frame_pointer->temp_mvals)); /* Verify is a temp mval */
srclvc = (lv_val *)srcmv->str.addr;
assert(srclvc);
assert(LV_IS_BASE_VAR(srclvc)); /* Verify base var */
diff --git a/sr_port/op_setfnretin2alsct.c b/sr_port/op_setfnretin2alsct.c
index 4390fb1..8f6b1df 100644
--- a/sr_port/op_setfnretin2alsct.c
+++ b/sr_port/op_setfnretin2alsct.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2010, 2011 Fidelity Information Services, Inc *
+ * Copyright 2010, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -50,9 +50,7 @@ void op_setfnretin2alsct(mval *srcmv, lv_val *dstlv)
assert(srcmv == alias_retarg);
assert(!LV_IS_BASE_VAR(dstlv)); /* Verify subscripted var */
assert(srcmv->mvtype & MV_ALIASCONT);
- /* Verify is a temp mval */
- assert((char *)srcmv >= (char *)frame_pointer->temps_ptr
- && (char *)srcmv < ((char *)frame_pointer->temps_ptr + (SIZEOF(char *) * frame_pointer->temp_mvals)));
+ assert(MVAL_IN_RANGE(srcmv, frame_pointer->temps_ptr, frame_pointer->temp_mvals)); /* Verify is a temp mval */
assert(MV_IS_STRING(srcmv) && (0 == srcmv->str.len));
src_lvref = (lv_val *)srcmv->str.addr;
assert(src_lvref);
diff --git a/sr_port/op_stolitc.c b/sr_port/op_stolitc.c
new file mode 100644
index 0000000..45f9bbe
--- /dev/null
+++ b/sr_port/op_stolitc.c
@@ -0,0 +1,32 @@
+/****************************************************************
+ * *
+ * Copyright 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "cmd_qlf.h"
+#include "op.h"
+#include <rtnhdr.h>
+#include "stack_frame.h"
+#include "stringpool.h"
+
+GBLREF stack_frame *frame_pointer;
+
+void op_stolitc(mval *val)
+{
+# ifdef USHBIN_SUPPORTED
+ assert(DYNAMIC_LITERALS_ENABLED(frame_pointer->rvector));
+ assert((char *)frame_pointer->literal_ptr == (char *)frame_pointer->rvector->literal_adr);
+ assert(!MVAL_IN_RANGE(val, frame_pointer->literal_ptr, frame_pointer->rvector->literal_len)); /* val is NOT a literal */
+ val->str.addr += (INTPTR_T)(frame_pointer->rvector->literal_text_adr);
+# else
+ assert(FALSE);
+# endif
+ return;
+}
diff --git a/sr_port/op_svget.c b/sr_port/op_svget.c
index 8106723..ff84916 100644
--- a/sr_port/op_svget.c
+++ b/sr_port/op_svget.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -49,7 +49,10 @@
#include "get_reference.h"
#include "dollar_quit.h"
#ifdef UNIX
-#include "iormdef.h"
+# include "iormdef.h"
+# ifdef DEBUG
+# include "wbox_test_init.h"
+# endif
#endif
#define ESC_OFFSET 4
@@ -117,7 +120,7 @@ void op_svget(int varnum, mval *v)
{
io_log_name *tl;
int count;
- unsigned int ucount;
+ gtm_uint64_t ucount;
char *c1, *c2;
mval *mvp;
# ifdef UNIX
@@ -126,6 +129,27 @@ void op_svget(int varnum, mval *v)
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
+# if defined(UNIX) && defined(DEBUG)
+ if (gtm_white_box_test_case_enabled && (WBTEST_HUGE_ALLOC == gtm_white_box_test_case_number))
+ {
+ if (1 == gtm_white_box_test_case_count)
+ totalAlloc = totalAllocGta = totalRmalloc = totalRallocGta = totalUsed = totalUsedGta = 0xffff;
+ else if (2 == gtm_white_box_test_case_count)
+ totalAlloc = totalAllocGta = totalRmalloc = totalRallocGta = totalUsed = totalUsedGta = 0xfffffff;
+ else if (3 == gtm_white_box_test_case_count)
+ {
+# ifdef GTM64
+ if (8 == SIZEOF(size_t))
+ totalAlloc = totalAllocGta = totalRmalloc = totalRallocGta
+ = totalUsed = totalUsedGta = 0xfffffffffffffff;
+ else
+# endif
+ totalAlloc = totalAllocGta = totalRmalloc = totalRallocGta = totalUsed = totalUsedGta = 0xfffffff;
+ } else
+ totalAlloc = totalAllocGta = totalRmalloc = totalRallocGta = totalUsed
+ = totalUsedGta = GTM64_ONLY(SIZEOF(size_t)) NON_GTM64_ONLY(SIZEOF(size_t) > 4 ? 4 : SIZEOF(size_t));
+ }
+# endif
switch (varnum)
{
case SV_HOROLOG:
@@ -384,16 +408,16 @@ void op_svget(int varnum, mval *v)
*v = dollar_ztexit;
break;
case SV_ZALLOCSTOR:
- ucount = (unsigned int)(totalAlloc + totalAllocGta);
- MV_FORCE_UMVAL(v, ucount);
+ ucount = (gtm_uint64_t)totalAlloc + (gtm_uint64_t)totalAllocGta;
+ ui82mval(v, ucount);
break;
case SV_ZREALSTOR:
- ucount = (unsigned int)(totalRmalloc + totalRallocGta);
- MV_FORCE_UMVAL(v, ucount);
+ ucount = (gtm_uint64_t)totalRmalloc + (gtm_uint64_t)totalRallocGta;
+ ui82mval(v, ucount);
break;
case SV_ZUSEDSTOR:
- ucount = (unsigned int)(totalUsed + totalUsedGta);
- MV_FORCE_UMVAL(v, ucount);
+ ucount = (gtm_uint64_t)totalUsed + (gtm_uint64_t)totalUsedGta;
+ ui82mval(v, ucount);
break;
case SV_ZCHSET:
v->mvtype = MV_STR;
diff --git a/sr_port/op_tcommit.c b/sr_port/op_tcommit.c
index 40d17d0..1b56735 100644
--- a/sr_port/op_tcommit.c
+++ b/sr_port/op_tcommit.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -109,6 +109,68 @@ error_def(ERR_TRIGTCOMMIT);
error_def(ERR_TCOMMITDISALLOW);
#endif
+STATICFNDCL void fix_updarray_and_oldblock_ptrs(sm_uc_ptr_t old_db_addrs[2], sgm_info *si);
+
+STATICFNDEF void fix_updarray_and_oldblock_ptrs(sm_uc_ptr_t old_db_addrs[2], sgm_info *si)
+{
+ cw_set_element *cse;
+ srch_blk_status *t1;
+ blk_segment *array, *seg, *stop_ptr;
+ sm_long_t delta;
+ sgmnt_addrs *csa;
+# ifdef DEBUG
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+# endif
+ csa = si->tp_csa;
+ delta = (sm_long_t)(csa->db_addrs[0] - old_db_addrs[0]);
+ assert(0 != delta);
+ /* update cse's update array and old_block */
+ for (cse = si->first_cw_set; NULL != cse; cse = cse->next_cw_set)
+ {
+ TRAVERSE_TO_LATEST_CSE(cse);
+ if (gds_t_writemap != cse->mode)
+ {
+ array = (blk_segment *)cse->upd_addr;
+ stop_ptr = cse->first_copy ? array : array + 1;
+ seg = (blk_segment *)array->addr;
+ while (seg != stop_ptr)
+ {
+ if ((old_db_addrs[0] <= seg->addr) && (old_db_addrs[1] >= seg->addr))
+ seg->addr += delta;
+ seg--;
+ }
+ }
+ if (NULL != cse->old_block)
+ {
+ if ((old_db_addrs[0] <= cse->old_block) && (old_db_addrs[1] >= cse->old_block))
+ cse->old_block += delta;
+ /* else, old_block is already updated -- this is mostly the case with gds_t_writemap in which case
+ * bm_getfree invokes t_write_map
+ */
+# ifdef DEBUG
+ if (!((csa->db_addrs[0] <= cse->old_block) && (csa->db_addrs[1] >= cse->old_block)))
+ { /* cse->old_block is pointing outside mmap bounds; most likely it points to the private memory.
+ * But cse->old_block, at all times should point to the before image of the database block and so
+ * should NOT point to private memory. This indicates that t_qread (below) did a private build on
+ * an incorrect block and tp_tend will detect this and restart. To be sure, set donot_commit.
+ */
+ assert(CDB_STAGNATE > t_tries);
+ TREF(donot_commit) |= DONOTCOMMIT_T_QREAD_BAD_PVT_BUILD;
+ }
+# endif
+ }
+ }
+ /* update all the tp_hist */
+ for (t1 = si->first_tp_hist; t1 != si->last_tp_hist; t1++)
+ {
+ if ((old_db_addrs[0] <= t1->buffaddr) && (old_db_addrs[1] >= t1->buffaddr))
+ t1->buffaddr += delta;
+ }
+ return;
+}
+
enum cdb_sc op_tcommit(void)
{
boolean_t blk_used, is_mm, was_crit;
@@ -128,12 +190,7 @@ enum cdb_sc op_tcommit(void)
kill_set *ks;
off_chain chain1;
tp_region *tr;
- /* for MM extend */
- cw_set_element *update_cse;
- blk_segment *seg, *stop_ptr, *array;
- sm_long_t delta;
- sm_uc_ptr_t old_db_addrs[2];
- srch_blk_status *t1;
+ sm_uc_ptr_t old_db_addrs[2]; /* for MM extend */
jnl_buffer_ptr_t jbp; /* jbp is non-NULL only if before-image journaling */
blk_hdr_ptr_t old_block;
boolean_t read_before_image; /* TRUE if before-image journaling or online backup in progress
@@ -154,7 +211,7 @@ enum cdb_sc op_tcommit(void)
skip_invoke_restart = FALSE; /* no triggers so set local variable to default state */
# endif
if (!dollar_tlevel)
- rts_error(VARLSTCNT(1) ERR_TLVLZERO);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_TLVLZERO);
assert(0 == jnl_fence_ctl.level);
status = cdb_sc_normal;
tp_kill_bitmaps = FALSE;
@@ -175,7 +232,8 @@ enum cdb_sc op_tcommit(void)
* trigger invocation to be done before completing the explicit (outside-trigger) update.
* Cannot commit such a transaction. Issue error.
*/
- rts_error(VARLSTCNT(4) ERR_TRIGTCOMMIT, 2, gtm_trigger_depth, tstart_trigger_depth);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TRIGTCOMMIT, 2, gtm_trigger_depth,
+ tstart_trigger_depth);
}
if (tp_pointer->cannot_commit)
{ /* If this TP transaction was implicit, any unhandled error when crossing the trigger boundary
@@ -184,7 +242,7 @@ enum cdb_sc op_tcommit(void)
* transaction so we should never see an implicit TP inside op_tcommit.
*/
assert(!tp_pointer->implicit_tstart);
- rts_error(VARLSTCNT(1) ERR_TCOMMITDISALLOW);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_TCOMMITDISALLOW);
}
)
save_cur_region = gv_cur_region;
@@ -198,7 +256,7 @@ enum cdb_sc op_tcommit(void)
csa = cs_addrs;
csd = cs_data;
cnl = csa->nl;
- is_mm = (dba_mm == cs_addrs->hdr->acc_meth);
+ is_mm = (dba_mm == csa->hdr->acc_meth);
si->cr_array_index = 0;
if (!is_mm && (si->cr_array_size < (si->num_of_blks + (si->cw_set_depth * 2))))
{ /* reallocate a bigger cr_array. We need atmost read-set (si->num_of_blks) +
@@ -260,67 +318,23 @@ enum cdb_sc op_tcommit(void)
if (gds_t_create == cse->mode)
{
old_cw_depth = si->cw_set_depth;
- old_db_addrs[0] = csa->db_addrs[0];
- old_db_addrs[1] = csa->db_addrs[1];
first_cse = si->first_cw_set;
TRAVERSE_TO_LATEST_CSE(first_cse);
+ old_db_addrs[0] = csa->db_addrs[0];
+ old_db_addrs[1] = csa->db_addrs[1];
while (FILE_EXTENDED == (new_blk = bm_getfree(cse->blk, &blk_used,
cw_depth, first_cse, &si->cw_set_depth)))
{
assert(is_mm);
- was_crit = csa->now_crit;
- if (!csa->hold_onto_crit && !was_crit)
- grab_crit(si->gv_cur_region); /* for wcs_mm_recover */
- wcs_mm_recover(si->gv_cur_region);
- if (!csa->hold_onto_crit && !was_crit)
- rel_crit(si->gv_cur_region);
- delta = (sm_long_t)((sm_uc_ptr_t)csa->hdr - (sm_uc_ptr_t)csd);
- csd = csa->hdr;
- /* update cse's update array and old_block */
- for (update_cse = si->first_cw_set; NULL != update_cse;
- update_cse = update_cse->next_cw_set)
- {
- TRAVERSE_TO_LATEST_CSE(update_cse);
- if (gds_t_writemap != update_cse->mode)
- {
- array = (blk_segment *)update_cse->upd_addr;
- stop_ptr = update_cse->first_copy ?
- array : array + 1;
- seg = (blk_segment *)array->addr;
- while (seg != stop_ptr)
- {
- if ((old_db_addrs[0] < seg->addr)
- && (old_db_addrs[1] >= seg->addr))
- seg->addr += delta;
- seg--;
- }
- }
- if (NULL != update_cse->old_block)
- {
- assert((old_db_addrs[0] < update_cse->old_block) &&
- (old_db_addrs[1] > update_cse->old_block));
- update_cse->old_block += delta;
- }
- }
- /* update all the tp_hist */
- for (t1 = si->first_tp_hist; t1 != si->last_tp_hist; t1++)
- {
- if ((old_db_addrs[0] < t1->buffaddr)
- && (old_db_addrs[1] >= t1->buffaddr))
- t1->buffaddr += delta;
- }
- /* In case the while loop above needs to repeat more than once,
- * the mmaped addresses for the file's start and end could have
- * changed if wcs_mm_recover() caused a file extension. In that
- * case, reset the limits to the new values.
- */
+ MM_DBFILEXT_REMAP_IF_NEEDED(csa, si->gv_cur_region);
if (csa->db_addrs[0] != old_db_addrs[0])
{
+ fix_updarray_and_oldblock_ptrs(old_db_addrs, si);
old_db_addrs[0] = csa->db_addrs[0];
old_db_addrs[1] = csa->db_addrs[1];
- csd = csa->hdr;
}
}
+ assert(csd == csa->hdr);
if (0 > new_blk)
{
GET_CDB_SC_CODE(new_blk, status); /* code is set in status */
@@ -366,9 +380,10 @@ enum cdb_sc op_tcommit(void)
cse->blk = new_blk;
cse->mode = gds_t_acquired;
assert(GDSVCURR == cse->ondsk_blkver);
- assert(CDB_STAGNATE > t_tries ||
- (is_mm ? (cse->blk < csa->total_blks)
- : (cse->blk < csa->ti->total_blks)));
+ /* Assert that in final retry total_blks (private and shared) are in sync */
+ assert((CDB_STAGNATE > t_tries) || !is_mm
+ || (csa->total_blks == csa->ti->total_blks));
+ assert((CDB_STAGNATE > t_tries) || (cse->blk < csa->ti->total_blks));
} /* if (gds_t_create == cse->mode) */
} /* for (all cw_set_elements) */
if (NULL == si->first_cw_bitmap)
@@ -421,7 +436,8 @@ enum cdb_sc op_tcommit(void)
{
if (NULL == (end = format_targ_key(buff, MAX_ZWR_KEY_SZ, gv_currkey, TRUE)))
end = &buff[MAX_ZWR_KEY_SZ - 1];
- rts_error(VARLSTCNT(6) ERR_GBLOFLOW, 0, ERR_GVIS, 2, end - buff, buff);
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_GBLOFLOW, 0, ERR_GVIS, 2, end - buff, buff);
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_GBLOFLOW, 0, ERR_GVIS, 2, end - buff, buff);
} else if (!skip_invoke_restart)
INVOKE_RESTART;
GTMTRIG_ONLY(DBGTRIGR((stderr, "op_tcommit: Return status = %d\n", status));)
diff --git a/sr_port/op_view.c b/sr_port/op_view.c
index ef375cb..c2bda1b 100644
--- a/sr_port/op_view.c
+++ b/sr_port/op_view.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -25,6 +25,7 @@
#include "gtm_facility.h"
#include "fileinfo.h"
#include "gdsbt.h"
+#include "gdsbgtr.h"
#include "gdsfhead.h"
#include "filestruct.h"
#include "cmd_qlf.h"
@@ -51,6 +52,7 @@
#include "gtm_malloc.h"
#include "alias.h"
#include "fullbool.h"
+#include "anticipatory_freeze.h"
#ifdef GTM_TRIGGER
# include "rtnhdr.h" /* for rtn_tabent in gv_trigger.h */
# include "gv_trigger.h"
@@ -64,6 +66,9 @@
# endif
#endif
+STATICFNDCL void view_dbflushop(unsigned char keycode, viewparm *parmblkptr, mval *thirdarg);
+
+GBLREF volatile int4 db_fsync_in_prog;
GBLREF boolean_t certify_all_blocks;
GBLREF bool undef_inhibit, jobpid;
GBLREF bool view_debug1, view_debug2, view_debug3, view_debug4;
@@ -93,6 +98,7 @@ GBLREF pid_t process_id;
error_def(ERR_ACTRANGE);
error_def(ERR_COLLATIONUNDEF);
error_def(ERR_COLLDATAEXISTS);
+error_def(ERR_DBFSYNCERR);
error_def(ERR_INVZDIRFORM);
error_def(ERR_ISOLATIONSTSCHN);
error_def(ERR_JNLFLUSH);
@@ -113,15 +119,15 @@ error_def(ERR_ZDEFACTIVE);
#define WRITE_LITERAL(x) (outval.str.len = SIZEOF(x) - 1, outval.str.addr = (x), op_write(&outval))
/* if changing noisolation status within TP and already referenced the global, then error */
-#define SET_GVNH_NOISOLATION_STATUS(gvnh, status) \
-{ \
- GBLREF uint4 dollar_tlevel; \
- \
- if (!dollar_tlevel || gvnh->read_local_tn != local_tn || status == gvnh->noisolation) \
- gvnh->noisolation = status; \
- else \
- rts_error(VARLSTCNT(6) ERR_ISOLATIONSTSCHN, 4, gvnh->gvname.var_name.len, \
- gvnh->gvname.var_name.addr, gvnh->noisolation, status); \
+#define SET_GVNH_NOISOLATION_STATUS(gvnh, status) \
+{ \
+ GBLREF uint4 dollar_tlevel; \
+ \
+ if (!dollar_tlevel || gvnh->read_local_tn != local_tn || status == gvnh->noisolation) \
+ gvnh->noisolation = status; \
+ else \
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_ISOLATIONSTSCHN, 4, gvnh->gvname.var_name.len, \
+ gvnh->gvname.var_name.addr, gvnh->noisolation, status); \
}
void op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...)
@@ -209,37 +215,13 @@ 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_DBSYNC:
+ case VTK_EPOCH:
case VTK_FLUSH:
- if (NULL == gd_header) /* open gbldir */
- gvinit();
- save_reg = gv_cur_region;
- if (NULL == parmblk.gv_ptr)
- { /* flush all regions */
- reg = gd_header->regions;
- r_top = reg + gd_header->n_regions - 1;
- } else /* flush selected region */
- r_top = reg = parmblk.gv_ptr;
- for (; reg <= r_top; reg++)
- {
- if (!reg->open)
- gv_init_reg(reg);
- if (!reg->read_only)
- {
- gv_cur_region = reg;
- change_reg(); /* for jnl_ensure_open */
- ENSURE_JNL_OPEN(cs_addrs, gv_cur_region);
- /* We should NOT invoke wcs_recover here because it's possible we are in the final retry
- * of a TP transaction. In this case, we likely have pointers to non-dirty global buffers
- * in our transaction histories. Doing cache recovery could dry clean most of these buffers.
- * And that might cause us to get confused, attempt to restart, and incorrectly issue a
- * TPFAIL error because we are already in the final retry. By passing the WCSFLU_IN_COMMIT
- * bit, we instruct wcs_flu to avoid wcs_recover.
- */
- wcs_flu(WCSFLU_FLUSH_HDR | WCSFLU_WRITE_EPOCH | WCSFLU_SYNC_EPOCH | WCSFLU_IN_COMMIT);
- }
- }
- gv_cur_region = save_reg;
- change_reg();
+ case VTK_JNLFLUSH:
+ case VTK_DBFLUSH:
+ arg = (numarg > 1) ? va_arg(var, mval *) : NULL;
+ view_dbflushop(vtp->keycode, &parmblk, arg);
break;
case VTK_FULLBOOL:
TREF(gtm_fullbool) = FULL_BOOL;
@@ -338,58 +320,6 @@ void op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...)
}
break;
# endif
- case VTK_JNLFLUSH:
- if (NULL == gd_header) /* open gbldir */
- gvinit();
- save_reg = gv_cur_region;
- if (NULL == parmblk.gv_ptr)
- { /* flush all journal files */
- reg = gd_header->regions;
- r_top = reg + gd_header->n_regions - 1;
- } else /* flush journal for selected region */
- r_top = reg = parmblk.gv_ptr;
- for (; reg <= r_top; reg++)
- {
- if (!reg->open)
- gv_init_reg(reg);
- gv_cur_region = reg;
- change_reg();
- csa = cs_addrs;
- csd = csa->hdr;
- if (JNL_ENABLED(csd))
- {
- was_crit = csa->now_crit;
- if (!was_crit)
- grab_crit(reg);
- if (JNL_ENABLED(csd))
- {
- jnl_status = jnl_ensure_open();
- if (0 == jnl_status)
- {
- jb = csa->jnl->jnl_buff;
- if (SS_NORMAL == (jnl_status = jnl_flush(reg)))
- {
- assert(jb->dskaddr == jb->freeaddr);
- UNIX_ONLY(jnl_fsync(reg, jb->dskaddr));
- UNIX_ONLY(assert(jb->freeaddr == jb->fsync_dskaddr));
- } else
- {
- send_msg(VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(csd),
- ERR_TEXT, 2,
- RTS_ERROR_TEXT("Error with journal flush during op_view"),
- jnl_status);
- assert(FALSE);
- }
- } else
- send_msg(VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(reg));
- }
- if (!was_crit)
- rel_crit(reg);
- }
- }
- gv_cur_region = save_reg;
- change_reg();
- break;
case VTK_JNLWAIT:
/* go through all regions that could have possibly been open across all global directories */
for (addr_ptr = get_next_gdr(NULL); addr_ptr; addr_ptr = get_next_gdr(addr_ptr))
@@ -437,7 +367,8 @@ void op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...)
if (0 == status)
{
va_end(var);
- rts_error(VARLSTCNT(4) ERR_PATTABNOTFND, 2, parmblk.value->str.len, parmblk.value->str.addr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_PATTABNOTFND, 2, parmblk.value->str.len,
+ parmblk.value->str.addr);
}
break;
case VTK_RESETGVSTATS:
@@ -481,7 +412,7 @@ void op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...)
if (TREF(view_ydirt_str_len) > MAX_YDIRTSTR)
{
va_end(var);
- rts_error(VARLSTCNT(1) ERR_YDIRTSZ);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_YDIRTSZ);
}
if (TREF(view_ydirt_str_len) > 0)
memcpy(TREF(view_ydirt_str), parmblk.value->str.addr, TREF(view_ydirt_str_len));
@@ -514,7 +445,7 @@ void op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...)
else
{
va_end(var);
- rts_error(VARLSTCNT(1) ERR_REQDVIEWPARM);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_REQDVIEWPARM);
}
nextarg = NULL;
ncol = -1;
@@ -538,7 +469,7 @@ void op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...)
if ((lct < MIN_COLLTYPE) || (lct > MAX_COLLTYPE))
{
va_end(var);
- rts_error(VARLSTCNT(3) ERR_ACTRANGE, 1, lct);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_ACTRANGE, 1, lct);
}
}
/* at this point, verify that there is no local data with subscripts */
@@ -553,7 +484,7 @@ void op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...)
if (lv && LV_HAS_CHILD(lv))
{
va_end(var);
- rts_error(VARLSTCNT(1) ERR_COLLDATAEXISTS);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_COLLDATAEXISTS);
}
}
}
@@ -566,7 +497,7 @@ void op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...)
if (0 == new_lcl_collseq)
{
va_end(var);
- rts_error(VARLSTCNT(3) ERR_COLLATIONUNDEF, 1, lct);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_COLLATIONUNDEF, 1, lct);
}
TREF(local_collseq) = new_lcl_collseq;
} else
@@ -590,7 +521,8 @@ void op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...)
if (!load_pattern_table(parmblk.value->str.len, parmblk.value->str.addr))
{
va_end(var);
- rts_error(VARLSTCNT(4) ERR_PATLOAD, 2, parmblk.value->str.len, parmblk.value->str.addr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_PATLOAD, 2, parmblk.value->str.len,
+ parmblk.value->str.addr);
}
break;
case VTK_NOUNDEF:
@@ -607,7 +539,7 @@ void op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...)
if (zdefactive)
{
va_end(var);
- rts_error(VARLSTCNT(1) ERR_ZDEFACTIVE);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZDEFACTIVE);
}
zdefactive = TRUE;
tmpzdefbufsiz = MV_FORCE_INT(parmblk.value);
@@ -629,7 +561,7 @@ void op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...)
if (2 > numarg)
{
va_end(var);
- rts_error(VARLSTCNT(1) ERR_TRACEON);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_TRACEON);
}
arg = va_arg(var, mval *);
MV_FORCE_STR(arg);
@@ -653,7 +585,7 @@ void op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...)
if (!IS_VALID_ZDIR_FORM(testvalue))
{
va_end(var);
- rts_error(VARLSTCNT(3) ERR_INVZDIRFORM, 1, testvalue);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_INVZDIRFORM, 1, testvalue);
}
} else
testvalue = ZDIR_FORM_FULLPATH;
@@ -796,8 +728,121 @@ void op_view(UNIX_ONLY_COMMA(int numarg) mval *keyword, ...)
# endif
default:
va_end(var);
- rts_error(VARLSTCNT(1) ERR_VIEWCMD);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_VIEWCMD);
}
va_end(var);
return;
}
+
+void view_dbflushop(unsigned char keycode, viewparm *parmblkptr, mval *thirdarg)
+{
+ uint4 jnl_status, dummy_errno;
+ int4 nbuffs;
+ int save_errno;
+ int status, lcnt, icnt;
+ gd_region *reg, *r_top, *save_reg;
+ sgmnt_addrs *csa;
+ sgmnt_data_ptr_t csd;
+ jnl_buffer_ptr_t jb;
+ boolean_t was_crit;
+ UNIX_ONLY(unix_db_info *udi;)
+
+ if (NULL == gd_header) /* open gbldir */
+ gvinit();
+ save_reg = gv_cur_region;
+ if (NULL == parmblkptr->gv_ptr)
+ { /* operate on all regions */
+ reg = gd_header->regions;
+ r_top = reg + gd_header->n_regions - 1;
+ } else /* operate on selected region */
+ r_top = reg = parmblkptr->gv_ptr;
+ for (; reg <= r_top; reg++)
+ {
+ if (!reg->open)
+ gv_init_reg(reg);
+ gv_cur_region = reg;
+ switch(keycode)
+ {
+ case VTK_DBSYNC:
+# ifdef UNIX
+ if (!reg->read_only)
+ {
+ change_reg();
+ csa = cs_addrs;
+ udi = FILE_INFO(reg);
+ DB_FSYNC(reg, udi, csa, db_fsync_in_prog, save_errno);
+ if (0 != save_errno)
+ {
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_DBFSYNCERR, 2, DB_LEN_STR(reg),
+ save_errno);
+ save_errno = 0;
+ }
+ }
+# endif
+ break;
+ case VTK_FLUSH:
+ case VTK_EPOCH:
+ if (!reg->read_only)
+ {
+ change_reg(); /* for jnl_ensure_open */
+ ENSURE_JNL_OPEN(cs_addrs, gv_cur_region);
+ /* We should NOT invoke wcs_recover here because it's possible we are in the final retry
+ * of a TP transaction. In this case, we likely have pointers to non-dirty global buffers
+ * in our transaction histories. Doing cache recovery could dry clean most of these buffers.
+ * And that might cause us to get confused, attempt to restart, and incorrectly issue a
+ * TPFAIL error because we are already in the final retry. By passing the WCSFLU_IN_COMMIT
+ * bit, we instruct wcs_flu to avoid wcs_recover.
+ */
+ wcs_flu(WCSFLU_FLUSH_HDR | WCSFLU_WRITE_EPOCH | WCSFLU_SYNC_EPOCH | WCSFLU_IN_COMMIT);
+ }
+ break;
+ case VTK_JNLFLUSH:
+ change_reg();
+ csa = cs_addrs;
+ csd = csa->hdr;
+ if (JNL_ENABLED(csd))
+ {
+ was_crit = csa->now_crit;
+ if (!was_crit)
+ grab_crit(reg);
+ if (JNL_ENABLED(csd))
+ {
+ jnl_status = jnl_ensure_open();
+ if (0 == jnl_status)
+ {
+ jb = csa->jnl->jnl_buff;
+ if (SS_NORMAL == (jnl_status = jnl_flush(reg)))
+ {
+ assert(jb->dskaddr == jb->freeaddr);
+ UNIX_ONLY(jnl_fsync(reg, jb->dskaddr));
+ UNIX_ONLY(assert(jb->freeaddr == jb->fsync_dskaddr));
+ } else
+ {
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_JNLFLUSH, 2,
+ JNL_LEN_STR(csd), ERR_TEXT, 2,
+ RTS_ERROR_TEXT("Error with journal flush during op_view"),
+ jnl_status);
+ assert(FALSE);
+ }
+ } else
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd),
+ DB_LEN_STR(reg));
+ }
+ if (!was_crit)
+ 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);
+ }
+ break;
+ }
+ }
+ gv_cur_region = save_reg;
+ change_reg();
+ return;
+}
diff --git a/sr_port/op_xkill.c b/sr_port/op_xkill.c
index aabd957..1fd6dd4 100644
--- a/sr_port/op_xkill.c
+++ b/sr_port/op_xkill.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -34,8 +34,6 @@ void op_xkill(UNIX_ONLY_COMMA(int n) mval *lvname_arg, ...)
ht_ent_mname *tabent, *top;
boolean_t lcl_stdxkill;
- error_def(ERR_XKILLCNTEXC);
-
active_lv = (lv_val *)NULL; /* if we get here, subscript set was successful. clear active_lv to avoid later
cleanup problems */
/* GTM supports two methods for exclusive kill that affect the way aliases and pass-by-reference (PBR) parameters are
diff --git a/sr_port/op_zalloc2.c b/sr_port/op_zalloc2.c
deleted file mode 100644
index a3aabea..0000000
--- a/sr_port/op_zalloc2.c
+++ /dev/null
@@ -1,311 +0,0 @@
-/****************************************************************
- * *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
- * *
- * This source code contains the intellectual property *
- * of its copyright holder(s), and is made available *
- * under a license. If you do not know the terms of *
- * the license, please stop and do not read further. *
- * *
- ****************************************************************/
-
-#include "mdef.h"
-
-#include "cdb_sc.h"
-#include "cmidef.h"
-#include "hashtab_mname.h" /* needed for cmmdef.h */
-#include "cmmdef.h"
-#include "gdsroot.h"
-#include "gt_timer.h"
-#include "iotimer.h"
-#include "locklits.h"
-#include "mlkdef.h"
-#include "t_retry.h"
-#include "op.h"
-#include "mlk_lock.h"
-#include "mlk_bckout.h"
-#include "mlk_pvtblk_delete.h"
-#include "mlk_unlock.h"
-#include "mlk_unpend.h"
-#include "outofband.h"
-#include "mv_stent.h"
-#include "find_mvstent.h"
-#include "lk_check_own.h"
-#include "gvcmx.h"
-#include "gvcmz.h"
-#include "rel_quant.h"
-#include "lckclr.h"
-#include "wake_alarm.h"
-
-#include "gdskill.h"
-#include "gdsbt.h"
-#include "gtm_facility.h"
-#include "fileinfo.h"
-#include "gdsfhead.h"
-#include "gdscc.h"
-#include "filestruct.h"
-#include "buddy_list.h" /* needed for tp.h */
-#include "io.h"
-#include "jnl.h"
-#include "hashtab_int4.h" /* needed for tp.h */
-#include "tp.h"
-#include "send_msg.h"
-#include "gtmmsg.h" /* for gtm_putmsg() prototype */
-#include "change_reg.h"
-#include "setterm.h"
-#include "getzposition.h"
-#ifdef DEBUG
-#include "have_crit.h" /* for the TPNOTACID_CHECK macro */
-#endif
-
-GBLREF unsigned char cm_action;
-GBLREF uint4 dollar_tlevel;
-GBLREF uint4 dollar_trestart;
-GBLREF unsigned short lks_this_cmd;
-GBLREF mlk_pvtblk *mlk_pvt_root;
-GBLREF mlk_stats_t mlk_stats; /* Process-private M-lock statistics */
-GBLREF mv_stent *mv_chain;
-GBLREF int4 outofband;
-GBLREF bool out_of_time;
-GBLREF uint4 process_id;
-GBLREF bool remlkreq;
-GBLREF unsigned char *restart_ctxt, *restart_pc;
-GBLREF unsigned int t_tries;
-
-#define ZALLOCTIMESTR "ZALLOCATE time too long"
-
-/* -----------------------------------------------
- *
- * Maintain in parallel with op_lock2
- *
- * Arguments:
- * timeout - max. time to wait for locks before giving up
- * auxown - auxillary owner field for use by servers
- *
- * Return:
- * 1 - if not timeout specified
- * if timeout specified:
- * != 0 - all the locks int the list obtained, or
- * 0 - blocked
- * The return result is suited to be placed directly into
- * the $T variable by the caller if timeout is specified.
- * -----------------------------------------------
- */
-int op_zalloc2(int4 timeout, UINTPTR_T auxown) /* timeout in seconds */
-{
- boolean_t blocked, timer_on;
- signed char gotit;
- unsigned short locks_bckout, locks_done;
- int4 msec_timeout; /* timeout in milliseconds */
- mlk_pvtblk *pvt_ptr1, *pvt_ptr2, **prior;
- ABS_TIME cur_time, end_time, remain_time;
- mv_stent *mv_zintcmd;
- DCL_THREADGBL_ACCESS;
-
- SETUP_THREADGBL_ACCESS;
- gotit = -1;
- cm_action = CM_ZALLOCATES;
- out_of_time = FALSE;
- if (timeout < 0)
- timeout = 0;
- else if (TREF(tpnotacidtime) < timeout)
- TPNOTACID_CHECK(ZALLOCTIMESTR);
- if (!(timer_on = (NO_M_TIMEOUT != timeout))) /* NOTE assignment */
- msec_timeout = NO_M_TIMEOUT;
- else
- {
- msec_timeout = timeout2msec(timeout);
- if (0 == msec_timeout)
- {
- out_of_time = TRUE;
- timer_on = FALSE;
- } else
- {
- mv_zintcmd = find_mvstent_cmd(ZINTCMD_LOCK, restart_pc, restart_ctxt, FALSE);
- if (mv_zintcmd)
- {
- remain_time = mv_zintcmd->mv_st_cont.mvs_zintcmd.end_or_remain;
- cur_time = sub_abs_time(&end_time, &cur_time);/* remaining time to wait */
- if (0 <= remain_time.at_sec)
- msec_timeout = (int4)(remain_time.at_sec * 1000 + remain_time.at_usec / 1000);
- else
- msec_timeout = 0;
- TAREF1(zintcmd_active, ZINTCMD_LOCK).restart_pc_last
- = mv_zintcmd->mv_st_cont.mvs_zintcmd.restart_pc_prior;
- TAREF1(zintcmd_active, ZINTCMD_LOCK).restart_ctxt_last
- = mv_zintcmd->mv_st_cont.mvs_zintcmd.restart_ctxt_prior;
- TAREF1(zintcmd_active, ZINTCMD_LOCK).count--;
- assert(0 <= TAREF1(zintcmd_active, ZINTCMD_LOCK).count);
- if (mv_chain == mv_zintcmd)
- POP_MV_STENT(); /* just pop if top of stack */
- else
- { /* flag as not active */
- mv_zintcmd->mv_st_cont.mvs_zintcmd.command = ZINTCMD_NOOP;
- mv_zintcmd->mv_st_cont.mvs_zintcmd.restart_pc_check = NULL;
- }
- }
- if (0 < msec_timeout)
- {
- sys_get_curr_time(&cur_time);
- add_int_to_abs_time(&cur_time, msec_timeout, &end_time);
- start_timer((TID)&timer_on, msec_timeout, wake_alarm, 0, NULL);
- } else
- {
- out_of_time = TRUE;
- timer_on = FALSE;
- }
- }
- }
- lckclr();
- for (blocked = FALSE; !blocked;)
- { /* if this is a request for a remote node */
- if (remlkreq)
- {
- if (gotit >= 0)
- gotit = gvcmx_resremlk(cm_action);
- else
- gotit = gvcmx_reqremlk(cm_action, msec_timeout); /* REQIMMED if 2nd arg == 0 */
- if (!gotit)
- { /* only REQIMMED returns false */
- blocked = TRUE;
- break;
- }
- }
- for (pvt_ptr1 = mlk_pvt_root, locks_done = 0; locks_done < lks_this_cmd; pvt_ptr1 = pvt_ptr1->next, locks_done++)
- { /* Go thru the list of all locks to be obtained attempting to lock
- * each one. If any lock could not be obtained, break out of the loop
- */
- if (pvt_ptr1->old && !pvt_ptr1->zalloc)
- pvt_ptr1->old = FALSE;
- if (!mlk_lock(pvt_ptr1, auxown, TRUE))
- { /* If lock is obtained */
- pvt_ptr1->granted = TRUE;
- pvt_ptr1->zalloc = TRUE;
- } else
- {
- blocked = TRUE;
- break;
- }
- }
- /* If we did not get blocked, we are all done */
- if (!blocked)
- break;
- /* We got blocked and need to keep retrying after some time interval */
- if (remlkreq)
- gvcmx_susremlk(cm_action);
-
- for (pvt_ptr2 = mlk_pvt_root, locks_bckout = 0; locks_bckout < locks_done;
- pvt_ptr2 = pvt_ptr2->next, locks_bckout++)
- {
- assert(pvt_ptr2->granted && (pvt_ptr2 != pvt_ptr1));
- mlk_bckout(pvt_ptr2, ZALLOCATED);
- }
- if (dollar_tlevel && (CDB_STAGNATE <= t_tries))
- { /* upper TPNOTACID_CHECK conditioned on no short timeout; this one rel_crits to avoid potential deadlock */
- assert(TREF(tpnotacidtime) >= timeout);
- TPNOTACID_CHECK(ZALLOCTIMESTR);
- }
- for (;;)
- {
- if (out_of_time || outofband)
- { /* if time expired || control-c, tptimeout, jobinterrupt encountered */
- if (outofband || !lk_check_own(pvt_ptr1))
- { /* If CTL-C, check lock owner */
- if (pvt_ptr1->nodptr) /* Get off pending list to be sent a wake */
- mlk_unpend(pvt_ptr1);
- /* Cancel all remote locks obtained so far */
- if (remlkreq)
- {
- gvcmx_canremlk();
- gvcmz_clrlkreq();
- remlkreq = FALSE;
- }
- if (outofband && !out_of_time)
- {
- if (timer_on)
- {
- cancel_timer((TID)&timer_on);
- timer_on = FALSE;
- }
- if (NO_M_TIMEOUT != timeout)
- { /* get remain = end_time - cur_time */
- sys_get_curr_time(&cur_time);
- remain_time = sub_abs_time(&end_time, &cur_time);
- if (0 <= remain_time.at_sec)
- msec_timeout = (int4)(remain_time.at_sec * 1000
- + remain_time.at_usec / 1000);
- else
- msec_timeout = 0; /* treat as out_of_time */
- if (0 >= msec_timeout)
- {
- out_of_time = TRUE;
- timer_on = FALSE; /* as if LOCK :0 */
- break;
- }
- if ((tptimeout != outofband) && (ctrlc != outofband))
- {
- PUSH_MV_STENT(MVST_ZINTCMD);
- mv_chain->mv_st_cont.mvs_zintcmd.end_or_remain = end_time;
- mv_chain->mv_st_cont.mvs_zintcmd.restart_ctxt_check = restart_ctxt;
- mv_chain->mv_st_cont.mvs_zintcmd.restart_pc_check = restart_pc;
- /* save current information from zintcmd_active */
- mv_chain->mv_st_cont.mvs_zintcmd.restart_ctxt_prior
- = TAREF1(zintcmd_active, ZINTCMD_LOCK).restart_ctxt_last;
- mv_chain->mv_st_cont.mvs_zintcmd.restart_pc_prior
- = TAREF1(zintcmd_active, ZINTCMD_LOCK).restart_pc_last;
- TAREF1(zintcmd_active, ZINTCMD_LOCK).restart_pc_last = restart_pc;
- TAREF1(zintcmd_active, ZINTCMD_LOCK).restart_ctxt_last
- = restart_ctxt;
- TAREF1(zintcmd_active, ZINTCMD_LOCK).count++;
- mv_chain->mv_st_cont.mvs_zintcmd.command = ZINTCMD_LOCK;
- }
- outofband_action(FALSE); /* no return */
- } else
- outofband_action(FALSE); /* no return */
- }
- break;
- }
- }
- if (!mlk_lock(pvt_ptr1, 0, FALSE))
- { /* If we got the lock, break out of timer loop */
- blocked = FALSE;
- if (pvt_ptr1 != mlk_pvt_root)
- {
- rel_quant(); /* attempt to get a full timeslice for maximum chance to get all */
- mlk_unlock(pvt_ptr1);
- }
- break;
- }
- if (pvt_ptr1->nodptr)
- lk_check_own(pvt_ptr1); /* clear an abandoned owner */
- hiber_start_wait_any(LOCK_SELF_WAKE);
- }
- if (blocked && out_of_time)
- break;
- }
- if (remlkreq)
- {
- gvcmz_clrlkreq();
- remlkreq = FALSE;
- }
- if (NO_M_TIMEOUT != timeout)
- { /* was timed or immediate */
- if (timer_on && !out_of_time)
- cancel_timer((TID)&timer_on);
- if (blocked)
- {
- for (prior = &mlk_pvt_root; *prior;)
- {
- if (!(*prior)->granted)
- { /* if entry was never granted, delete list entry */
- mlk_pvtblk_delete(prior);
- } else
- prior = &((*prior)->next);
- }
- mlk_stats.n_user_locks_fail++;
- return (FALSE);
- }
- }
- mlk_stats.n_user_locks_success++;
- return (TRUE);
-}
diff --git a/sr_port/op_zallocate.c b/sr_port/op_zallocate.c
index baf7330..f9e6ae8 100644
--- a/sr_port/op_zallocate.c
+++ b/sr_port/op_zallocate.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -11,6 +11,9 @@
#include "mdef.h"
#include "op.h"
+#include "hashtab_mname.h" /* needed for cmmdef.h */
+#include "cmidefsp.h" /* needed for cmmdef.h */
+#include "cmmdef.h"
/*
* -----------------------------------------------
* This routine is a one-argument front-end for op_zallocate
@@ -32,5 +35,5 @@
int op_zallocate(int timeout)
{
- return (op_zalloc2(timeout,0));
+ return op_lock2(timeout, CM_ZALLOCATES);
}
diff --git a/sr_port/op_zcompile.c b/sr_port/op_zcompile.c
index 1b88d15..bf9fe77 100644
--- a/sr_port/op_zcompile.c
+++ b/sr_port/op_zcompile.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -30,7 +30,7 @@ GBLREF mcalloc_hdr *mcavailptr;
#define FILE_NAME_SIZE 255
-void op_zcompile(mval *v, boolean_t mExtReqd)
+void op_zcompile(mval *v, boolean_t ignore_dollar_zcompile)
{
unsigned status;
command_qualifier save_qlf;
@@ -51,14 +51,17 @@ void op_zcompile(mval *v, boolean_t mExtReqd)
if (!v->str.len)
return;
save_qlf = glb_cmd_qlf;
- glb_cmd_qlf.object_file.str.addr = obj_file;
- glb_cmd_qlf.object_file.str.len = FILE_NAME_SIZE;
- glb_cmd_qlf.list_file.str.addr = list_file;
- glb_cmd_qlf.list_file.str.len = FILE_NAME_SIZE;
- glb_cmd_qlf.ceprep_file.str.addr = ceprep_file;
- glb_cmd_qlf.ceprep_file.str.len = FILE_NAME_SIZE;
- zl_cmd_qlf(&v->str, &glb_cmd_qlf);
- cmd_qlf = glb_cmd_qlf;
+# ifdef UNIX /* VMS retains old behavior, for which $ZCOMPILE only affects ZLINK, not ZCOMPILE or compile mode */
+ if (!ignore_dollar_zcompile)
+ {
+ INIT_CMD_QLF_STRINGS(cmd_qlf, obj_file, list_file, ceprep_file, FILE_NAME_SIZE);
+ zl_cmd_qlf(&(TREF(dollar_zcompile)), &cmd_qlf); /* Process $ZCOMPILE qualifiers */
+ glb_cmd_qlf = cmd_qlf;
+ }
+# endif
+ INIT_CMD_QLF_STRINGS(cmd_qlf, obj_file, list_file, ceprep_file, FILE_NAME_SIZE);
+ zl_cmd_qlf(&v->str, &cmd_qlf); /* Process ZCOMPILE arg. Override any conflicting quals in $ZCOMPILE */
+ glb_cmd_qlf = cmd_qlf;
assert(run_time);
assert(rts_stringpool.base == stringpool.base);
rts_stringpool = stringpool;
@@ -94,7 +97,7 @@ void op_zcompile(mval *v, boolean_t mExtReqd)
status;
status = cli_get_str("INFILE",source_file_string, &len))
{
- compile_source_file(len, source_file_string, mExtReqd);
+ compile_source_file(len, source_file_string, FALSE);
len = FILE_NAME_SIZE;
}
/* Determine if need to remove any added added mc blocks. Min value of mcallocated will ensure
diff --git a/sr_port/op_zgoto.c b/sr_port/op_zgoto.c
index e00c577..165edea 100644
--- a/sr_port/op_zgoto.c
+++ b/sr_port/op_zgoto.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2011, 2012 Fidelity Information Services, Inc *
+ * Copyright 2011, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -64,13 +64,13 @@ void op_zgoto(mval *rtn_name, mval *lbl_name, int offset, int level)
if (0 > level)
{ /* Negative level specified, means to use relative level change */
if ((-level) > curlvl)
- rts_error(VARLSTCNT(1) ERR_ZGOTOLTZERO);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZGOTOLTZERO);
level += curlvl; /* Compute relative desired level */
} else
{ /* Else level is the level we wish to achieve - compute unrolls necessary */
if (0 > (curlvl - level))
/* Couldn't get to the level we were trying to unwind to */
- rts_error(VARLSTCNT(1) ERR_ZGOTOTOOBIG);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZGOTOTOOBIG);
}
/* Migrate mval parm contents to private buffers since the mvals could die as we unwind things */
MV_FORCE_STR(rtn_name);
@@ -90,7 +90,7 @@ void op_zgoto(mval *rtn_name, mval *lbl_name, int offset, int level)
* was NULL.
*/
if (0 == lblname.str.len)
- rts_error(VARLSTCNT(1) ERR_RTNNAME);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_RTNNAME);
rtnhdr = frame_pointer->rvector;
if (0 == level)
{ /* If doing unlink, recall name of routine as well as will need it later */
@@ -118,7 +118,7 @@ void op_zgoto(mval *rtn_name, mval *lbl_name, int offset, int level)
* since the base frame cannot be rewritten as a GTM frame.
*/
if (0 == level)
- rts_error(VARLSTCNT(1) ERR_ZGOTOINVLVL2);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZGOTOINVLVL2);
# endif
# ifdef GTM_TRIGGER
if (!IS_GTM_IMAGE && (1 >= level))
@@ -127,7 +127,7 @@ void op_zgoto(mval *rtn_name, mval *lbl_name, int offset, int level)
* entry ref was coded) and are not resume-able (if no entry ref were specified) so we cannot
* permit ZGOTOs to these levels in a utility.
*/
- rts_error(VARLSTCNT(5) ERR_ZGOTOINVLVL, 3, GTMIMAGENAMETXT(image_type), level);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_ZGOTOINVLVL, 3, GTMIMAGENAMETXT(image_type), level);
# endif
# ifdef UNIX
/* One last check if we are unlinking, make sure no call-in frames exist on our stack */
@@ -140,7 +140,7 @@ void op_zgoto(mval *rtn_name, mval *lbl_name, int offset, int level)
continue;
if (fp->flags & SFF_CI)
/* We have a call-in frame - cannot do unlink */
- rts_error(VARLSTCNT(1) ERR_ZGOCALLOUTIN);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZGOCALLOUTIN);
if (NULL == fpprev)
{ /* Next frame is some sort of base frame */
# ifdef GTM_TRIGGER
diff --git a/sr_port/op_zsystem.c b/sr_port/op_zsystem.c
index a28ec86..72e1c0a 100644
--- a/sr_port/op_zsystem.c
+++ b/sr_port/op_zsystem.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -78,7 +78,7 @@ void op_zsystem(mval *v)
MV_FORCE_STR(v);
#ifdef UNIX
if (v->str.len > (MAXZSYSSTRLEN - 32 - 1)) /* 32 char for shell name, remaining for ZSYSTEM command */
- rts_error(VARLSTCNT(4) ERR_INVSTRLEN, 2, v->str.len, (MAXZSYSSTRLEN - 32 - 1));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_INVSTRLEN, 2, v->str.len, (MAXZSYSSTRLEN - 32 - 1));
/* get SHELL environment */
sh = GETENV("SHELL");
/* use bourn shell as default */
@@ -104,7 +104,7 @@ void op_zsystem(mval *v)
#ifdef UNIX
dollar_zsystem = SYSTEM(cmd);
if (-1 == dollar_zsystem)
- rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("system"), CALLFROM, errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("system"), CALLFROM, errno);
#ifdef _BSD
assert(SIZEOF(wait_stat) == SIZEOF(int4));
wait_stat.w_status = dollar_zsystem;
@@ -120,7 +120,7 @@ void op_zsystem(mval *v)
setterm(io_std_device.in);
#ifdef VMS
if (status != SS$_NORMAL)
- rts_error(VARLSTCNT(1) status);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status);
#endif
return;
}
diff --git a/sr_port/opcode_def.h b/sr_port/opcode_def.h
index 6603955..d652c5e 100644
--- a/sr_port/opcode_def.h
+++ b/sr_port/opcode_def.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -339,3 +339,6 @@ OPCODE_DEF(OC_RFRSHGVN, (OCT_NULL))
OPCODE_DEF(OC_INDFNNAME2, (OCT_MVAL | OCT_EXPRLEAF))
OPCODE_DEF(OC_INDGET2, (OCT_MVAL | OCT_EXPRLEAF))
OPCODE_DEF(OC_INDMERGE2, (OCT_NULL))
+OPCODE_DEF(OC_LITC, (OCT_MVAL | OCT_EXPRLEAF))
+OPCODE_DEF(OC_STOLITC, (OCT_NULL))
+OPCODE_DEF(OC_FNZPEEK, (OCT_MVAL | OCT_EXPRLEAF))
diff --git a/sr_port/prepare_unique_name.c b/sr_port/prepare_unique_name.c
index 470d63b..2a0a649 100644
--- a/sr_port/prepare_unique_name.c
+++ b/sr_port/prepare_unique_name.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2003, 2007 Fidelity Information Services, Inc *
+ * Copyright 2003, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -29,13 +29,13 @@
/* Given org_fn this will create rename_fn
* a) If prefix is not null, rename_fn = prefix + org_fn
- * b) If suffix is not null, rename_fn = org_fn + suffix
- * c) If prefix and suffix both not null Then
+ * b) If suffix is not null, rename_fn = org_fn + suffix
+ * c) If prefix and suffix are both null, then
* rename_fn = org_fn + timestamp
* If rename_fn exists, add numbers to make it non-existance file
*/
uint4 prepare_unique_name(char *org_fn, int org_fn_len, char *prefix, char *suffix,
- char *rename_fn, int *rename_fn_len, uint4 *ustatus)
+ char *rename_fn, int *rename_fn_len, jnl_tm_t now, uint4 *ustatus)
{
mstr filestr;
char *filename_begin, append_char[MAX_CHARS_APPEND] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
@@ -82,9 +82,8 @@ uint4 prepare_unique_name(char *org_fn, int org_fn_len, char *prefix, char *suf
filestr.len = org_fn_len;
rename_fn[filestr.len] = 0;
assert(filestr.len + 1 < MAX_FN_LEN);
- if (SS_NORMAL != (status1 = append_time_stamp(rename_fn, filestr.len, &length, ustatus)))
+ if (SS_NORMAL != (status1 = append_time_stamp(rename_fn, &filestr.len, now)))
return status1;
- filestr.len += length;
if (FILE_PRESENT == (file_stat = gtm_file_stat(&filestr, NULL, NULL, FALSE, ustatus))) /* One already exists */
{ /* new name refers to an existing file - stuff numbers on the end until its unique */
rename_fn[filestr.len] = '_';
diff --git a/sr_port/process_deferred_stale.c b/sr_port/process_deferred_stale.c
index fb45f6c..5757210 100644
--- a/sr_port/process_deferred_stale.c
+++ b/sr_port/process_deferred_stale.c
@@ -87,25 +87,7 @@ void process_deferred_stale(void)
{
gv_cur_region = r_cur;
tp_change_reg();
-# if defined(UNIX) && defined(UNTARGETED_MSYNC)
- if (csa->ti->last_mm_sync != csa->ti->curr_tn)
- {
- boolean_t was_crit;
-
- was_crit = csa->now_crit;
- if (FALSE == was_crit)
- grab_crit(r_cur);
- msync((caddr_t)csa->db_addrs[0],
- (size_t)(csa->db_addrs[1] - csa->db_addrs[0]),
- MS_SYNC);
- /* Save when did last full sync */
- csa->ti->last_mm_sync = csa->ti->curr_tn;
- if (FALSE == was_crit)
- rel_crit(r_cur);
- }
-# else
DCLAST_WCS_WTSTART(r_cur, 0, status);
-# endif
csa->stale_defer = FALSE;
BG_TRACE_ANY(csa, stale_defer_processed);
}
diff --git a/sr_port/region_freeze.c b/sr_port/region_freeze.c
index 1849a7b..7cb5547 100644
--- a/sr_port/region_freeze.c
+++ b/sr_port/region_freeze.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -45,6 +45,7 @@
#include "cli.h"
#include "util.h"
#include "wbox_test_init.h"
+#include "have_crit.h"
GBLREF bool caller_id_flag;
GBLREF bool in_mupip_freeze;
diff --git a/sr_port/region_init.c b/sr_port/region_init.c
index 0c9d028..4b6c7da 100644
--- a/sr_port/region_init.c
+++ b/sr_port/region_init.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2002 Sanchez Computer Associates, Inc. *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -24,11 +24,12 @@ GBLREF gd_region *gv_cur_region;
void region_open(void);
+error_def (ERR_DBNOREGION);
+
boolean_t region_init(bool cm_regions)
{
gd_region *region_top;
boolean_t file_open, is_cm, all_files_open;
- error_def (ERR_DBNOREGION);
file_open = FALSE;
all_files_open = TRUE;
@@ -50,7 +51,7 @@ boolean_t region_init(bool cm_regions)
}
}
if (!file_open)
- rts_error(VARLSTCNT(1) ERR_DBNOREGION);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DBNOREGION);
/* arbitrary assignment of the first region */
for (gv_cur_region = gd_header->regions; gv_cur_region < region_top; gv_cur_region++)
diff --git a/sr_port/rename_file_if_exists.c b/sr_port/rename_file_if_exists.c
index 298b043..97530fb 100644
--- a/sr_port/rename_file_if_exists.c
+++ b/sr_port/rename_file_if_exists.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2003, 2010 Fidelity Information Services, Inc *
+ * Copyright 2003, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -13,6 +13,7 @@
#include "gtm_string.h"
#include "gtm_fcntl.h"
+#include "gtm_time.h"
#include <errno.h>
#include "gdsroot.h"
@@ -31,6 +32,9 @@
#include "gtmmsg.h"
#include "gtm_file_stat.h"
+error_def(ERR_FILERENAME);
+error_def(ERR_RENAMEFAIL);
+
/* --------------------------------------------------------------------------------
This function renames a file, if exists. Otherwise do nothing.
--------------------------------------------------------------------------------- */
@@ -38,8 +42,7 @@ int rename_file_if_exists(char *org_fn, int org_fn_len, char *rename_fn, int *re
{
mstr orgfile;
int status;
- error_def(ERR_FILERENAME);
- error_def(ERR_RENAMEFAIL);
+ jnl_tm_t now;
memcpy(rename_fn, org_fn, org_fn_len + 1); /* Ensure it to be NULL terminated */
*rename_fn_len = org_fn_len;
@@ -51,7 +54,8 @@ int rename_file_if_exists(char *org_fn, int org_fn_len, char *rename_fn, int *re
return RENAME_FAILED;
/* File is present in the system */
assert(0 < MAX_FN_LEN - org_fn_len - 1);
- if (SS_NORMAL != (status = prepare_unique_name(org_fn, org_fn_len, "", "", rename_fn, rename_fn_len, ustatus)))
+ JNL_SHORT_TIME(now);
+ if (SS_NORMAL != (status = prepare_unique_name(org_fn, org_fn_len, "", "", rename_fn, rename_fn_len, now, ustatus)))
return RENAME_FAILED;
assert(0 == rename_fn[*rename_fn_len]);
if (SS_NORMAL != (status= gtm_rename(org_fn, org_fn_len, rename_fn, *rename_fn_len, ustatus)))
diff --git a/sr_port/reorg_funcs.c b/sr_port/reorg_funcs.c
new file mode 100644
index 0000000..2f5807d
--- /dev/null
+++ b/sr_port/reorg_funcs.c
@@ -0,0 +1,184 @@
+/****************************************************************
+ * *
+ * Copyright 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include "cdb_sc.h"
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "jnl.h"
+#include "gdsblkops.h"
+#include "gdskill.h"
+#include "gdscc.h"
+#include "copy.h"
+#include "mu_reorg.h"
+#include "util.h"
+#include "min_max.h"
+
+GBLREF sgmnt_data_ptr_t cs_data;
+GBLREF unsigned int t_tries;
+
+#ifdef DEBUG
+# define DBG_VERIFY_ACCESS(PTR) \
+{ /* Ensure accessible pointer (no SIG-11) */ \
+ unsigned char c; \
+ \
+ c = *(unsigned char *)(PTR); \
+}
+#else
+# define DBG_VERIFY_ACCESS(PTR)
+#endif
+
+/*
+ * Get length of the global variable name contained in the key starting at KEY_BASE.
+ * NOTE: If keys reside outside a GDS block (e.g. in cs_data), allocated buffer should have capacity at least MAX_KEY_SZ.
+ * Input:
+ * BLK_BASE := if non-NULL, base of current block
+ * if NULL, it means we're dealing with a key that is not within a database block
+ * KEY_BASE := starting address of key
+ * Output:
+ * GBLNAME_LEN := length of global variable name
+ */
+int get_gblname_len(sm_uc_ptr_t blk_base, sm_uc_ptr_t key_base)
+{
+ sm_uc_ptr_t rPtr1, blk_end;
+
+ blk_end = (NULL != blk_base) ? (blk_base + cs_data->blk_size) : (key_base + MAX_KEY_SZ);
+ DBG_VERIFY_ACCESS(blk_end - 1);
+ for (rPtr1 = key_base; ; )
+ {
+ if (blk_end <= rPtr1)
+ break;
+ if (KEY_DELIMITER == *rPtr1++)
+ break;
+ }
+ return (int)(rPtr1 - key_base);
+}
+
+/*
+ * Get length of the key starting at KEY_BASE.
+ * NOTE: If keys reside outside a GDS block (e.g. in cs_data), allocated buffer should have capacity at least MAX_KEY_SZ.
+ * Currently, all get_key_len() calls take a key in shared memory; the only "allocated buffer" is csd->reorg_restart_key.
+ * Input:
+ * BLK_BASE := if non-NULL, base of current block
+ * if NULL, it means we're dealing with a key that is not within a database block
+ * KEY_BASE := starting address of key
+ * Output:
+ * KEY_LEN := length of key, including 2 null bytes at the end
+ */
+int get_key_len(sm_uc_ptr_t blk_base, sm_uc_ptr_t key_base)
+{
+ sm_uc_ptr_t rPtr1, blk_end;
+
+ blk_end = (NULL != blk_base) ? (blk_base + cs_data->blk_size) : (key_base + MAX_KEY_SZ);
+ DBG_VERIFY_ACCESS(blk_end - 1);
+ for (rPtr1 = key_base; ; )
+ {
+ if (blk_end <= rPtr1 + 1)
+ break;
+ if ((KEY_DELIMITER == *rPtr1++) && (KEY_DELIMITER == *rPtr1))
+ break;
+ }
+ return (int)(rPtr1 + 1 - key_base);
+}
+
+/*
+ * Get compression count of SECOND_KEY with respect to FIRST_KEY.
+ * NOTE: Each key should reside in a private buffer with capacity at least MAX_KEY_SZ.
+ */
+int get_cmpc(sm_uc_ptr_t first_key, sm_uc_ptr_t second_key)
+{
+ sm_uc_ptr_t rPtr1, rPtr2;
+ int cmpc;
+
+ DBG_VERIFY_ACCESS(first_key + MAX_KEY_SZ - 1);
+ DBG_VERIFY_ACCESS(second_key + MAX_KEY_SZ - 1);
+ /* We don't expect the inputs to be equal, hence the assert. It shouldn't matter, though. If the keys' contents are equal,
+ * we return an indeterminate value between the key length and MAX_KEY_SZ. The value depends on the garbage bytes past the
+ * terminating null bytes. But we don't care because we don't compress a key off an identical key in the final retry.
+ */
+ assert(first_key != second_key);
+ for (rPtr1 = first_key, rPtr2 = second_key, cmpc = 0; cmpc < MAX_KEY_SZ; cmpc++)
+ {
+ if (*rPtr1++ != *rPtr2++)
+ break;
+ }
+ return cmpc;
+}
+
+/*
+ * Copy record info (record size and key) out of a block.
+ * Input:
+ * LEVEL := level of current block
+ * BLK_BASE := base of current block
+ * REC_BASE := starting address of record in current block
+ * KEY := previous key; first KEY_CMPC bytes are retained in output KEY
+ * Output:
+ * STATUS := status of read
+ * REC_SIZE := record size
+ * KEY_CMPC := key compression count
+ * KEY_LEN := key length
+ * KEY := local copy of key copied out of record
+ */
+enum cdb_sc read_record(int *rec_size_ptr, int *key_cmpc_ptr, int *key_len_ptr, sm_uc_ptr_t key,
+ int level, sm_uc_ptr_t blk_base, sm_uc_ptr_t rec_base)
+{
+ sm_uc_ptr_t rPtr1, rPtr2, blk_end, rPtr1_end, rPtr2_end;
+ unsigned short temp_ushort;
+ int key_cmpc, rec_size, key_len;
+ boolean_t invalid;
+
+ blk_end = blk_base + cs_data->blk_size;
+ DBG_VERIFY_ACCESS(blk_end - 1);
+ if (blk_end <= (rec_base + SIZEOF(rec_hdr)))
+ {
+ assert(CDB_STAGNATE > t_tries);
+ return cdb_sc_blkmod;
+ }
+ GET_USHORT(temp_ushort, &(((rec_hdr_ptr_t)rec_base)->rsiz));
+ rec_size = temp_ushort;
+ key_cmpc = EVAL_CMPC((rec_hdr_ptr_t)rec_base);
+ if ((0 != level) && (BSTAR_REC_SIZE == rec_size))
+ {
+ key_len = 0;
+ *key_cmpc_ptr = key_cmpc;
+ *rec_size_ptr = rec_size;
+ *key_len_ptr = key_len;
+ return cdb_sc_starrecord;
+ }
+ rPtr1_end = key + MAX_KEY_SZ - 1;
+ DBG_VERIFY_ACCESS(rPtr1_end);
+ rPtr2_end = MIN(blk_end - 1, rec_base + SIZEOF(rec_hdr) + MAX_KEY_SZ - 1);
+ for (rPtr1 = key + key_cmpc, rPtr2 = rec_base + SIZEOF(rec_hdr); (rPtr1 < rPtr1_end) && (rPtr2 < rPtr2_end); )
+ {
+ if ((KEY_DELIMITER == (*rPtr1++ = *rPtr2++)) && (KEY_DELIMITER == *rPtr2)) /* note assignment */
+ break;
+ }
+ *rPtr1++ = *rPtr2++;
+ key_len = (int)(rPtr2 - rec_base - SIZEOF(rec_hdr));
+ invalid = INVALID_RECORD(level, rec_size, key_len, key_cmpc);
+ if (invalid || ((KEY_DELIMITER != *(rPtr1 - 1)) || (KEY_DELIMITER != *(rPtr1 - 2))))
+ {
+ assert(CDB_STAGNATE > t_tries);
+ return cdb_sc_blkmod;
+ }
+ *key_cmpc_ptr = key_cmpc;
+ *rec_size_ptr = rec_size;
+ *key_len_ptr = key_len;
+ return cdb_sc_normal;
+}
diff --git a/sr_port/repl_comm.c b/sr_port/repl_comm.c
index 7972d5c..a9cacd1 100644
--- a/sr_port/repl_comm.c
+++ b/sr_port/repl_comm.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -11,22 +11,22 @@
#include "mdef.h"
+#include <sys/types.h>
+#include <sys/time.h>
+#include <errno.h>
+#ifdef USE_POLL
+# include <sys/poll.h>
+#endif
+
#include "gtm_stdio.h"
#include "gtm_string.h"
-#include "gtmio.h"
-
-#include <sys/types.h>
#include "gtm_socket.h"
#include "gtm_inet.h"
-#include <sys/time.h>
-#include <errno.h>
#include "gtm_fcntl.h"
#include "gtm_unistd.h"
#include "gtm_stat.h"
-#ifdef GTM_USE_POLL_FOR_SUBSECOND_SELECT
-#include <sys/poll.h>
-#endif
+#include "gtmio.h"
#include "repl_msg.h"
#include "repl_errno.h"
#include "repl_dbg.h"
@@ -39,6 +39,7 @@
#include "iotcpdef.h"
#include "gtmmsg.h"
#include "gt_timer.h"
+
/* These statistics are useful and should perhaps be collected - Vinaya 2003/08/18
*
* Common:
@@ -72,7 +73,7 @@
* # calls to recv that would have blocked (EWOULDBLOCK)
*/
-GBLDEF int repl_max_send_buffsize, repl_max_recv_buffsize;
+GBLDEF int repl_max_send_buffsize, repl_max_recv_buffsize;
#if defined(__hppa) || defined(__vms)
#define REPL_SEND_TRACE_BUFF_SIZE 65536
#define REPL_RECV_TRACE_BUFF_SIZE 65536
@@ -91,187 +92,163 @@ STATICDEF unsigned char * repl_recv_trace_buff = 0;
STATICDEF int repl_recv_size_trace_pos = 0;
STATICDEF int repl_recv_size_trace[REPL_RECV_SIZE_TRACE_SIZE];
+error_def(ERR_GETADDRINFO);
+error_def(ERR_GETNAMEINFO);
error_def(ERR_GETSOCKNAMERR);
error_def(ERR_TEXT);
-int repl_send(int sock_fd, unsigned char *buff, int *send_len, boolean_t skip_pipe_ready_check, struct timeval *max_pipe_ready_wait)
-{ /* On entry, *send_len is the number of bytes to be sent
- * On exit, *send_len contains the number of bytes sent
- */
- int send_size, status, eintr_cnt, eagain_cnt, ewouldblock_cnt, emsgsize_cnt;
+#define REPL_TRACE_BUFF(TRACE_BUFF, TRACE_BUFF_POS, IO_BUFF, IO_SIZE, MAX_TRACE_SIZE) \
+{ \
+ if (IO_SIZE > MAX_TRACE_SIZE) \
+ { \
+ memcpy(TRACE_BUFF, IO_BUFF + IO_SIZE - MAX_TRACE_SIZE, MAX_TRACE_SIZE); \
+ TRACE_BUFF_POS = 0; \
+ } else \
+ { \
+ int space_to_end = MAX_TRACE_SIZE - TRACE_BUFF_POS; \
+ if (IO_SIZE > space_to_end) \
+ { \
+ memcpy(TRACE_BUFF + TRACE_BUFF_POS, IO_BUFF, space_to_end); \
+ memcpy(TRACE_BUFF, IO_BUFF + space_to_end, IO_SIZE - space_to_end); \
+ } else \
+ memcpy(TRACE_BUFF + TRACE_BUFF_POS, IO_BUFF, IO_SIZE); \
+ TRACE_BUFF_POS = (TRACE_BUFF_POS + IO_SIZE) % MAX_TRACE_SIZE; \
+ } \
+}
+
+int fd_ioready(int sock_fd, boolean_t pollin, int timeout)
+{
+ int save_errno, status, EAGAIN_cnt = 0;
+# ifdef USE_POLL
+ struct pollfd fds;
+# else
+ fd_set fds, *readfds, *writefds;
+ struct timeval timeout_spec;
+# endif
+
+ assert(timeout < MILLISECS_IN_SEC);
+ SELECT_ONLY(timeout = timeout * 1000); /* Convert to microseconds (~ 1sec) */
+ assert((timeout >= 0) && (timeout < POLL_ONLY(MILLISECS_IN_SEC) SELECT_ONLY(MICROSEC_IN_SEC)));
+# ifdef USE_POLL
+ fds.fd = sock_fd;
+ fds.events = pollin ? POLLIN : POLLOUT;
+# else
+ readfds = writefds = NULL;
+ timeout_spec.tv_sec = 0;
+ timeout_spec.tv_usec = timeout;
+ FD_ZERO(&fds);
+ FD_SET(sock_fd, &fds);
+ writefds = !pollin ? &fds : NULL;
+ readfds = pollin ? &fds : NULL;
+# endif
+ POLL_ONLY(while (-1 == (status = poll(&fds, 1, timeout))))
+ SELECT_ONLY(while (-1 == (status = select(sock_fd + 1, readfds, writefds, NULL, &timeout_spec))))
+ {
+ save_errno = ERRNO;
+ if (EINTR == save_errno)
+ { /* Give it another shot. But, halve the timeout so we don't keep doing this forever. */
+ timeout = timeout >> 1;
+ } else if (EAGAIN == save_errno)
+ { /* Resource starved system; relinquish the processor in the hope that we may get the required resources
+ * next time around.
+ */
+ if (0 == ++EAGAIN_cnt % REPL_COMM_LOG_EAGAIN_INTERVAL)
+ {
+ repl_log(stderr, TRUE, TRUE, "Communication subsytem warning: System appears to be resource "
+ "starved. EAGAIN returned from select()/poll() %d times\n", EAGAIN_cnt);
+ }
+ rel_quant();
+ } else
+ return -1;
+ /* Just in case select() modifies the incoming arguments, restore fd_set and timeout_spec */
+ SELECT_ONLY(
+ assert(0 == timeout_spec.tv_sec);
+ timeout_spec.tv_usec = timeout; /* Note: timeout is the reduced value (in case of EINTR) */
+ FD_SET(sock_fd, &fds);
+ )
+ }
+ return status;
+}
+
+int repl_send(int sock_fd, unsigned char *buff, int *send_len, int timeout)
+{
+ int send_size, status, eintr_cnt, ewouldblock_cnt = 0, emsgsize_cnt = 0, io_ready, save_errno;
ssize_t bytes_sent;
- long wait_val;
- fd_set output_fds;
- struct timeval timeout;
-#ifdef GTM_USE_POLL_FOR_SUBSECOND_SELECT
- long poll_timeout;
- unsigned long poll_nfds;
- struct pollfd poll_fdlist[1];
-#endif
- int space_to_end;
if (!repl_send_trace_buff)
repl_send_trace_buff = malloc(REPL_SEND_TRACE_BUFF_SIZE);
/* Note: there is no corresponding free for this malloc since it is only done once per process and will not
* accumulate across multiple process invocations. It will be "freed" when the mupip process exits.
*/
+ assert(FD_INVALID != sock_fd);
send_size = *send_len;
/* VMS returns SYSTEM-F-INVBUFLEN if send_size is larger than the hard limit VMS_MAX_TCP_SEND_SIZE (64K - 1 on some
* impelementations, 64K - 512 on some others). VMS_MAX_TCP_SEND_SIZE may be larger than repl_max_send_buffsize, and
* empirically we have noticed send() successfully sending repl_max_send_buffsize or more bytes.
*/
- VMS_ONLY(send_size = MIN(send_size, VMS_MAX_TCP_SEND_SIZE);)
- REPL_DPRINT3("repl_send: called with send_size %d, limiting send_size to %d\n", *send_len, send_size);
+ VMS_ONLY(send_size = MIN(send_size, VMS_MAX_TCP_SEND_SIZE));
*send_len = 0;
- if (!skip_pipe_ready_check)
- { /* Wait till connection pipe is ready for sending */
- assert(max_pipe_ready_wait->tv_sec == 0); /* all callers pass sub-second timeout. We take advantage of this fact
- * to avoid division while computing wait_val */
- assert(max_pipe_ready_wait->tv_usec >= 0 && max_pipe_ready_wait->tv_usec < MICROSEC_IN_SEC);
-#ifndef GTM_USE_POLL_FOR_SUBSECOND_SELECT
- FD_ZERO(&output_fds);
- FD_SET(sock_fd, &output_fds);
-#else
- poll_fdlist[0].fd = sock_fd;
- poll_fdlist[0].events = POLLOUT;
- poll_nfds = 1;
- poll_timeout = max_pipe_ready_wait->tv_usec / 1000; /* convert to millisecs */
-#endif
- /* the check for EINTR below is valid and should not be converted to an EINTR wrapper macro, because EAGAIN is also
- * being checked */
- for (timeout = *max_pipe_ready_wait, eintr_cnt = eagain_cnt = 0;
-#ifndef GTM_USE_POLL_FOR_SUBSECOND_SELECT
- -1 == (status = select(sock_fd + 1, NULL, &output_fds, NULL, &timeout))
-#else
- -1 == (status = poll(&poll_fdlist[0], poll_nfds, poll_timeout))
-#endif
- && (EINTR == errno || EAGAIN == errno); )
- {
- if (EINTR == errno)
- {
- wait_val = (0 == eintr_cnt) ? (max_pipe_ready_wait->tv_usec >> 1) : (wait_val >> 1);
- if (++eintr_cnt > REPL_COMM_MAX_INTR_CNT)
- { /* assume timeout and give up. Note, this may result in a sleep different from intended.
- * But, we can live with it as there is no impact on the user */
- status = 0;
- break;
- }
- timeout.tv_sec = 0;
- timeout.tv_usec = (gtm_tv_usec_t)wait_val;
-#ifdef GTM_USE_POLL_FOR_SUBSECOND_SELECT
- poll_timeout = wait_val / 1000; /* convert to millisecs */
-#endif
- REPL_DPRINT5("repl_send: select interrupted, changing timeout from tv_sec %ld tv_usec %ld to "
- "tv_sec %ld tv_usec %ld\n", 0, (wait_val << 1), timeout.tv_sec, timeout.tv_usec);
- } else
- { /* resource starved system; relinquish the processor in the hope that we may get the required
- * resources the next time around */
- if (0 == ++eagain_cnt % REPL_COMM_LOG_EAGAIN_INTERVAL)
- repl_log(stderr, TRUE, TRUE, "Communication subsystem warning: System appears to be "
- "resource starved; EAGAIN returned from repl_send/select %d times\n", eagain_cnt);
- rel_quant();
- }
-#ifndef GTM_USE_POLL_FOR_SUBSECOND_SELECT
- FD_SET(sock_fd, &output_fds); /* Linux/gcc does not like this in the iterator */
-#endif
- }
- } else
- status = 1; /* assume connection pipe is ready for sending */
- if (0 < status)
- { /* Ready for sending */
- /*
- * the check for EINTR below is valid and should not be converted to an EINTR wrapper macro, because other errno
- * values are being checked.
- */
+ if (0 < (io_ready = fd_ioready(sock_fd, FALSE, timeout)))
+ {
/* Trace last REPL_SEND_SIZE_TRACE_SIZE sizes of what was sent */
repl_send_size_trace[repl_send_size_trace_pos++] = send_size;
repl_send_size_trace_pos %= ARRAYSIZE(repl_send_size_trace);
/* Trace last REPL_SEND_TRACE_BUFF_SIZE bytes sent. */
- if (send_size > REPL_SEND_TRACE_BUFF_SIZE)
- {
- /* if the message size > our buffer just copy the last our buffer-size-worth starting from the
- * beginning of our buffer and reset pos to the beginning of our buffer.
- */
- memcpy(repl_send_trace_buff, buff + send_size - REPL_SEND_TRACE_BUFF_SIZE, REPL_SEND_TRACE_BUFF_SIZE);
- repl_send_trace_buff_pos = 0;
- }
- else
- {
- space_to_end = REPL_SEND_TRACE_BUFF_SIZE - repl_send_trace_buff_pos;
- if (send_size > space_to_end)
- {
- memcpy(repl_send_trace_buff + repl_send_trace_buff_pos, buff, space_to_end);
- memcpy(repl_send_trace_buff, buff + space_to_end, send_size - space_to_end);
- }
- else
- {
- memcpy(repl_send_trace_buff + repl_send_trace_buff_pos, buff, send_size);
- }
- repl_send_trace_buff_pos = (repl_send_trace_buff_pos + send_size) % REPL_SEND_TRACE_BUFF_SIZE;
- }
- if (0 < send_size)
+ assert(0 < send_size);
+ REPL_TRACE_BUFF(repl_send_trace_buff, repl_send_trace_buff_pos, buff, send_size, REPL_SEND_TRACE_BUFF_SIZE);
+ /* The check for EINTR below is valid and should not be converted to an EINTR wrapper macro, because other errno
+ * values are being checked.
+ */
+ while (0 > (bytes_sent = send(sock_fd, (char *)buff, send_size, 0)))
{
- for (ewouldblock_cnt = emsgsize_cnt = 0;
- (((bytes_sent = send(sock_fd, (char *)buff, send_size, 0)) < 0)
- && (EINTR == errno || EMSGSIZE == errno || EWOULDBLOCK == errno)); )
+ save_errno = ERRNO;
+ assert((EMSGSIZE != save_errno) && (EWOULDBLOCK != save_errno));
+ if (EINTR == save_errno)
+ continue;
+ if (EMSGSIZE == save_errno)
+ { /* Reduce the send size if possible */
+ if (send_size > REPL_COMM_MIN_SEND_SIZE)
+ {
+ if ((send_size >> 1) <= REPL_COMM_MIN_SEND_SIZE)
+ send_size = REPL_COMM_MIN_SEND_SIZE;
+ else
+ send_size >>= 1;
+ }
+ if (0 == ++emsgsize_cnt % REPL_COMM_LOG_EMSGSIZE_INTERVAL)
+ {
+ repl_log(stderr, TRUE, TRUE, "Communication subsystem warning: System appears to be "
+ "clogged; EMSGSIZE returned from send %d times\n", emsgsize_cnt);
+ }
+ } else if (EWOULDBLOCK == save_errno)
{
- if (EINTR == errno)
- continue;
- assert(EMSGSIZE != errno); /* since we use blocking sockets, we don't expect to see EMSGSIZE */
- if (EMSGSIZE == errno)
- { /* Reduce the send size if possible */
- if (send_size > REPL_COMM_MIN_SEND_SIZE)
- {
- if ((send_size >> 1) <= REPL_COMM_MIN_SEND_SIZE)
- send_size = REPL_COMM_MIN_SEND_SIZE;
- else
- send_size >>= 1;
- }
- if (0 == ++emsgsize_cnt % REPL_COMM_LOG_EMSGSIZE_INTERVAL)
- repl_log(stderr, TRUE, TRUE, "Communication subsystem warning: System "
- "appears to be clogged; EMSGSIZE returned from send "
- "%d times\n", emsgsize_cnt);
- } else
+ if (0 == ++ewouldblock_cnt % REPL_COMM_LOG_EWDBLCK_INTERVAL)
{
- if (0 == ++ewouldblock_cnt % REPL_COMM_LOG_EWDBLCK_INTERVAL)
- repl_log(stderr, TRUE, TRUE, "Communication subsystem warning: System "
- "appears to be running slow; EWOULDBLOCK returned from "
- "send %d times\n", ewouldblock_cnt);
- rel_quant(); /* we hope the cause for blocking would have cleared by the time
- * we get scheduled next time around */
+ repl_log(stderr, TRUE, TRUE, "Communication subsystem warning: System appears to be "
+ "running slow; EWOULDBLOCK returned from send %d times\n", ewouldblock_cnt);
}
- }
- } else
- bytes_sent = 0;
+ rel_quant(); /* Relinquish our quanta in the hope that things get cleared next time around */
+ } else
+ break;
+ }
if (0 <= bytes_sent)
{
*send_len = (int)bytes_sent;
REPL_DPRINT2("repl_send: returning with send_len %ld\n", bytes_sent);
- return (SS_NORMAL);
+ return SS_NORMAL;
}
repl_errno = EREPL_SEND;
- return (ERRNO);
- } else if (0 == status)
- return (SS_NORMAL);
+ return save_errno;
+ } else if (!io_ready)
+ return SS_NORMAL;
+ save_errno = ERRNO;
repl_errno = EREPL_SELECT;
- return (ERRNO);
+ return save_errno;
}
-int repl_recv(int sock_fd, unsigned char *buff, int *recv_len, boolean_t skip_data_avail_check, struct timeval *max_data_avail_wait)
-{ /* On entry *recv_len is the maximum length to be received.
- * On exit, *recv_len will contain the number of bytes received.
- */
- int status, max_recv_len, eintr_cnt, eagain_cnt;
+int repl_recv(int sock_fd, unsigned char *buff, int *recv_len, int timeout)
+{
+ int status, max_recv_len, eintr_cnt, eagain_cnt, io_ready, save_errno;
ssize_t bytes_recvd;
- long wait_val;
- fd_set input_fds;
- struct timeval timeout;
-#ifdef GTM_USE_POLL_FOR_SUBSECOND_SELECT
- long poll_timeout;
- unsigned long poll_nfds;
- struct pollfd poll_fdlist[1];
-#endif
- int space_to_end;
if (!repl_recv_trace_buff)
repl_recv_trace_buff = malloc(REPL_RECV_TRACE_BUFF_SIZE);
@@ -280,70 +257,15 @@ int repl_recv(int sock_fd, unsigned char *buff, int *recv_len, boolean_t skip_da
*/
assert(FD_INVALID != sock_fd);
max_recv_len = *recv_len;
- /* VMS returns SYSTEM-F-INVBUFLEN if max_recv_len is larger than the hard limit VMS_MAX_TCP_SEND_SIZE (64K - 1 on some
- * impelementations, 64K - 512 on some others). Although VMS_MAX_TCP_RECV_SIZE may be larger than repl_max_recv_buffsize,
- * we have empirically noticed recv() returning with repl_max_recv_buffsize or fewer bytes.
+ /* VMS returns SYSTEM-F-INVBUFLEN if send_size is larger than the hard limit VMS_MAX_TCP_RECV_SIZE (64K - 1 on some
+ * impelementations, 64K - 512 on some others). VMS_MAX_TCP_RECV_SIZE may be larger than repl_max_send_buffsize, and
+ * empirically we have noticed send() successfully sending repl_max_send_buffsize or more bytes.
*/
- VMS_ONLY(max_recv_len = MIN(max_recv_len, VMS_MAX_TCP_RECV_SIZE);)
- REPL_DPRINT3("repl_recv: called with max_recv_len %d, limiting max_recv_len to %d\n", *recv_len, max_recv_len);
+ VMS_ONLY(max_recv_len = MIN(max_recv_len, VMS_MAX_TCP_RECV_SIZE));
*recv_len = 0;
- if (!skip_data_avail_check)
+ if (0 < (io_ready = fd_ioready(sock_fd, TRUE, timeout)))
{
- assert(max_data_avail_wait->tv_sec == 0); /* all callers pass sub-second timeout. We take advantage of this fact
- * to avoid division while computing wait_val */
- assert(max_data_avail_wait->tv_usec >= 0 && max_data_avail_wait->tv_usec < MICROSEC_IN_SEC);
-#ifndef GTM_USE_POLL_FOR_SUBSECOND_SELECT
- FD_ZERO(&input_fds);
- FD_SET(sock_fd, &input_fds);
-#else
- poll_fdlist[0].fd = sock_fd;
- poll_fdlist[0].events = POLLIN;
- poll_nfds = 1;
- poll_timeout = max_data_avail_wait->tv_usec / 1000; /* convert to millisecs */
-#endif
- /* the check for EINTR below is valid and should not be converted to an EINTR wrapper macro, because EAGAIN is also
- * being checked */
- for (timeout = *max_data_avail_wait, eintr_cnt = eagain_cnt = 0;
-#ifndef GTM_USE_POLL_FOR_SUBSECOND_SELECT
- -1 == (status = select(sock_fd + 1, &input_fds, NULL, NULL, &timeout))
-#else
- -1 == (status = poll(&poll_fdlist[0], poll_nfds, poll_timeout))
-#endif
- && (EINTR == errno || EAGAIN == errno); )
- {
- if (EINTR == errno)
- {
- wait_val = (0 == eintr_cnt) ? (max_data_avail_wait->tv_usec >> 1) : (wait_val >> 1);
- if (++eintr_cnt > REPL_COMM_MAX_INTR_CNT)
- { /* assume timeout and give up. Note, this may result in a sleep different from intended.
- * But, we can live with it as there is no impact on the user */
- status = 0;
- break;
- }
- timeout.tv_sec = 0;
- timeout.tv_usec = (gtm_tv_usec_t)wait_val;
-#ifdef GTM_USE_POLL_FOR_SUBSECOND_SELECT
- poll_timeout = wait_val / 1000; /* convert to millisecs */
-#endif
- REPL_DPRINT5("repl_recv: select interrupted, changing timeout from tv_sec %ld tv_usec %ld to "
- "tv_sec %ld tv_usec %ld\n", 0, (wait_val << 1), timeout.tv_sec, timeout.tv_usec);
- } else
- { /* resource starved system; relinquish the processor in the hope that we may get the required
- * resources the next time around */
- if (0 == ++eagain_cnt % REPL_COMM_LOG_EAGAIN_INTERVAL)
- repl_log(stderr, TRUE, TRUE, "Communication subsystem warning: System appears to be "
- "resource starved; EAGAIN returned from select %d times\n", eagain_cnt);
- rel_quant();
- }
-#ifndef GTM_USE_POLL_FOR_SUBSECOND_SELECT
- FD_SET(sock_fd, &input_fds); /* Linux/gcc does not like this in the iterator */
-#endif
- }
- } else
- status = 1; /* assume data is available, consequence is recv() may block if data is not available */
- if (0 < status)
- { /* Data available on the pipe */
- while (0 > (bytes_recvd = recv(sock_fd, (char *)buff, max_recv_len, 0)) && EINTR == errno)
+ while (0 > (bytes_recvd = recv(sock_fd, (char *)buff, max_recv_len, 0)) && EINTR == ERRNO)
;
if (0 < bytes_recvd)
{
@@ -353,56 +275,34 @@ int repl_recv(int sock_fd, unsigned char *buff, int *recv_len, boolean_t skip_da
repl_recv_size_trace[repl_recv_size_trace_pos++] = bytes_recvd;
repl_recv_size_trace_pos %= ARRAYSIZE(repl_recv_size_trace);
/* Trace last REPL_RECV_TRACE_BUFF_SIZE bytes received. */
- if (bytes_recvd > REPL_RECV_TRACE_BUFF_SIZE)
- {
- /* if the message size > our buffer just copy the last our buffer-size-worth starting from the
- * beginning of our buffer and reset pos to the beginning of our buffer.
- */
- memcpy(repl_recv_trace_buff, buff + bytes_recvd - REPL_RECV_TRACE_BUFF_SIZE,
+ REPL_TRACE_BUFF(repl_recv_trace_buff, repl_recv_trace_buff_pos, buff, bytes_recvd,
REPL_RECV_TRACE_BUFF_SIZE);
- repl_recv_trace_buff_pos = 0;
- }
- else
- {
- space_to_end = REPL_RECV_TRACE_BUFF_SIZE - repl_recv_trace_buff_pos;
- if (bytes_recvd > space_to_end)
- {
- memcpy(repl_recv_trace_buff + repl_recv_trace_buff_pos, buff, space_to_end);
- memcpy(repl_recv_trace_buff, buff + space_to_end, bytes_recvd - space_to_end);
- }
- else
- {
- memcpy(repl_recv_trace_buff + repl_recv_trace_buff_pos, buff, bytes_recvd);
- }
- repl_recv_trace_buff_pos = (repl_recv_trace_buff_pos + bytes_recvd) %
- REPL_RECV_TRACE_BUFF_SIZE;
- }
return (SS_NORMAL); /* always process the received buffer before dealing with any errno */
}
+ save_errno = ERRNO;
if (0 == bytes_recvd) /* Connection reset */
- errno = ECONNRESET;
-#ifdef UNIX
- else if (ETIMEDOUT == errno)
+ save_errno = errno = ECONNRESET;
+ else if (ETIMEDOUT == save_errno)
{
repl_log(stderr, TRUE, TRUE, "Communication subsystem warning: network may be down;"
" socket recv() returned ETIMEDOUT\n");
- errno = ETIMEDOUT;
- }
-#endif
- else if (EWOULDBLOCK == errno)
- { /* NOTE: Although we use non blocking sockets, it is possible to get EWOULDBLOCK error status if receive
- * timeout has been set and the timeout expired before data was received (from man recv on RH 8 Linux). Some
- * systems return ETIMEDOUT for the timeout condition. */
+ } else if (EWOULDBLOCK == save_errno)
+ { /* NOTE: Although we use blocking sockets, it is possible to get EWOULDBLOCK error status if receive timeout
+ * has been set and the timeout expired before data was received (from man recv on RH 8 Linux). Some systems
+ * return ETIMEDOUT for the timeout condition.
+ */
+ assert(EWOULDBLOCK != save_errno);
repl_log(stderr, TRUE, TRUE, "Communication subsystem warning: network I/O failed to complete; "
"socket recv() returned EWOULDBLOCK\n");
- errno = ETIMEDOUT; /* will be treated as a bad connection and the connection closed */
+ save_errno = errno = ETIMEDOUT; /* will be treated as a bad connection and the connection closed */
}
repl_errno = EREPL_RECV;
- return (ERRNO);
- } else if (0 == status)
- return (SS_NORMAL);
+ return save_errno;
+ } else if (!io_ready)
+ return SS_NORMAL;
+ save_errno = ERRNO;
repl_errno = EREPL_SELECT;
- return (ERRNO);
+ return save_errno;
}
int repl_close(int *sock_fd)
@@ -437,11 +337,11 @@ int get_recv_sock_buff_size(int sockfd, int *recv_buffsize)
static int set_sock_buff_size(int sockfd, int buflen, int which_buf)
{
int status;
-#ifndef sun
+# ifndef sun
size_t optlen;
-#else
+# else
int optlen;
-#endif
+# endif
optlen = SIZEOF(buflen);
status = setsockopt(sockfd, SOL_SOCKET, which_buf, (void *)&buflen, (GTM_SOCKLEN_TYPE)optlen);
return (0 == status) ? 0 : ERRNO;
@@ -459,45 +359,55 @@ int set_recv_sock_buff_size(int sockfd, int buflen)
void repl_log_conn_info(int sock_fd, FILE *log_fp)
{
- struct sockaddr_in local, remote;
+ struct sockaddr_storage local, remote;
+ struct sockaddr *local_sa_ptr, *remote_sa_ptr;
GTM_SOCKLEN_TYPE len;
int save_errno;
- size_t errlen;
- char *errptr, local_ip[16], remote_ip[16];
- in_port_t local_port, remote_port;
+ char *errptr, local_ip[SA_MAXLEN], remote_ip[SA_MAXLEN];
+ char port_buffer[NI_MAXSERV];
+ char local_port_buffer[NI_MAXSERV], remote_port_buffer[NI_MAXSERV];
+ int errcode;
len = SIZEOF(local);
- if (0 == getsockname(sock_fd, (struct sockaddr *)&local, (GTM_SOCKLEN_TYPE *)&len))
+ local_sa_ptr = (struct sockaddr *)&local;
+ remote_sa_ptr = (struct sockaddr *)&remote;
+ if (0 == getsockname(sock_fd, local_sa_ptr, (GTM_SOCKLEN_TYPE *)&len))
{
- local_port = ntohs(local.sin_port);
- strcpy(local_ip, inet_ntoa(local.sin_addr));
+ /* translate internal address to numeric ip address */
+ GETNAMEINFO(local_sa_ptr, len, local_ip, SA_MAXLEN, local_port_buffer, NI_MAXSERV, NI_NUMERICSERV, errcode);
+ if (0 != errcode)
+ {
+ repl_log(log_fp, TRUE, TRUE, "Error getting local name info: %s\n", gai_strerror(errcode));
+ strcpy(local_port_buffer, "*UNKNOWN*");
+ strcpy(local_ip, "*UNKNOWN*");
+ }
} else
{
save_errno = errno;
errptr = (char *)STRERROR(save_errno);
- errlen = strlen(errptr);
- gtm_putmsg(VARLSTCNT(9) ERR_GETSOCKNAMERR, 3, save_errno, errlen, errptr, ERR_TEXT, 2,
- LEN_AND_LIT("LOCAL"));
-
- local_port = (unsigned short)-1;
+ repl_log(log_fp, TRUE, TRUE, "Error getting local name: %s\n", errptr);
+ strcpy(local_port_buffer, "*UNKNOWN*");
strcpy(local_ip, "*UNKNOWN*");
}
len = SIZEOF(remote);
- if (0 == getpeername(sock_fd, (struct sockaddr *)&remote, (GTM_SOCKLEN_TYPE *)&len))
+ if (0 == getpeername(sock_fd, remote_sa_ptr, (GTM_SOCKLEN_TYPE *)&len))
{
- remote_port = ntohs(remote.sin_port);
- strcpy(remote_ip, inet_ntoa(remote.sin_addr));
+ GETNAMEINFO(remote_sa_ptr, len, remote_ip, SA_MAXLEN, remote_port_buffer, NI_MAXSERV, NI_NUMERICSERV, errcode);
+ if (0 != errcode)
+ {
+ repl_log(log_fp, TRUE, TRUE, "Error getting remote name info: %s\n", gai_strerror(errcode));
+ strcpy(remote_port_buffer, "*UNKNOWN*");
+ strcpy(remote_ip, "*UNKNOWN*");
+ }
} else
{
save_errno = errno;
errptr = (char *)STRERROR(save_errno);
- errlen = strlen(errptr);
- gtm_putmsg(VARLSTCNT(9) ERR_GETSOCKNAMERR, 3, save_errno, errlen, errptr, ERR_TEXT, 2,
- LEN_AND_LIT("REMOTE"));
- remote_port = (unsigned short)-1;
+ repl_log(log_fp, TRUE, TRUE, "Error getting remote name: %s\n", errptr);
+ strcpy(remote_port_buffer, "*UNKNOWN*");
strcpy(remote_ip, "*UNKNOWN*");
}
- repl_log(log_fp, TRUE, TRUE, "Connection information:: Local: %s:%d Remote: %s:%d\n", local_ip, local_port,
- remote_ip, remote_port);
+ repl_log(log_fp, TRUE, TRUE, "Connection information:: Local: %s:%s Remote: %s:%s\n", local_ip, local_port_buffer,
+ remote_ip, remote_port_buffer);
return;
}
diff --git a/sr_port/repl_comm.h b/sr_port/repl_comm.h
index 42900d2..ec8bc54 100644
--- a/sr_port/repl_comm.h
+++ b/sr_port/repl_comm.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -27,11 +27,11 @@
* b. when repl_send() fails, in which case sent_len contains the number of bytes successfully sent, and tosend_len is the
* length that we failed to send.
*/
-#define REPL_SEND_LOOP(SOCK_FD, BUFF, LEN, SKIP_PIPE_READY_CHECK, TIMEOUT) \
-assert(LEN > 0);\
-for (msg_ptr = (unsigned char *)(BUFF), sent_len = 0, sent_this_iter = tosend_len = (LEN); \
- SS_NORMAL == (status = repl_send(SOCK_FD, msg_ptr, &sent_this_iter, SKIP_PIPE_READY_CHECK, TIMEOUT)) \
- && ((sent_len += sent_this_iter), (tosend_len -= sent_this_iter), (tosend_len > 0)); \
+#define REPL_SEND_LOOP(SOCK_FD, BUFF, LEN, TIMEOUT) \
+assert(LEN > 0); \
+for (msg_ptr = (unsigned char *)(BUFF), sent_len = 0, sent_this_iter = tosend_len = (LEN); \
+ SS_NORMAL == (status = repl_send(SOCK_FD, msg_ptr, &sent_this_iter, TIMEOUT)) \
+ && ((sent_len += sent_this_iter), (tosend_len -= sent_this_iter), (tosend_len > 0)); \
msg_ptr += sent_this_iter, sent_this_iter = tosend_len)
/* Use REPL_RECV_LOOP when the length of the msg to be recieved is already known
@@ -48,10 +48,10 @@ for (msg_ptr = (unsigned char *)(BUFF), sent_len = 0, sent_this_iter = tosend_le
* b. when repl_recv() fails, in which case recvd_len contains the number of bytes successfully received, and torecv_len is the
* length that we failed to receive.
*/
-#define REPL_RECV_LOOP(SOCK_FD, BUFF, LEN, SKIP_DATA_AVAIL_CHECK, TIMEOUT) \
-for (msg_ptr = (unsigned char *)(BUFF), recvd_len = 0, recvd_this_iter = torecv_len = (LEN); \
- (SS_NORMAL == (status = repl_recv(SOCK_FD, msg_ptr, &recvd_this_iter, SKIP_DATA_AVAIL_CHECK, TIMEOUT))) \
- && ((recvd_len += recvd_this_iter), (torecv_len -= recvd_this_iter), (torecv_len > 0)); \
+#define REPL_RECV_LOOP(SOCK_FD, BUFF, LEN, TIMEOUT) \
+for (msg_ptr = (unsigned char *)(BUFF), recvd_len = 0, recvd_this_iter = torecv_len = (LEN); \
+ (SS_NORMAL == (status = repl_recv(SOCK_FD, msg_ptr, &recvd_this_iter, TIMEOUT))) \
+ && ((recvd_len += recvd_this_iter), (torecv_len -= recvd_this_iter), (torecv_len > 0)); \
msg_ptr += recvd_this_iter, recvd_this_iter = torecv_len)
#define REPL_COMM_MAX_INTR_CNT 3 /* # of iterations we'll let select() be interrupted before we give up and assume timeout */
@@ -67,11 +67,14 @@ for (msg_ptr = (unsigned char *)(BUFF), recvd_len = 0, recvd_this_iter = torecv_
#define VMS_MAX_TCP_SEND_SIZE VMS_MAX_TCP_IO_SIZE
#define VMS_MAX_TCP_RECV_SIZE VMS_MAX_TCP_IO_SIZE
+#define GTMSOURCE_IDLE_POLL_WAIT 100 /* 100ms sleep in case nothing sent to the other side */
+#define REPL_POLL_WAIT (MILLISECS_IN_SEC - 1) /* Maximum time (in ms) for select()/poll() to timeout */
+#define REPL_POLL_NOWAIT 0 /* Forces poll()/select() to return immediately */
+
/* Replication communcation subsystem function prototypes */
-int repl_send(int sock_fd, unsigned char *buff, int *send_len, boolean_t skip_pipe_ready_check,
- struct timeval *max_pipe_ready_wait);
-int repl_recv(int sock_fd, unsigned char *buff, int *recv_len, boolean_t skip_data_avail_check,
- struct timeval *max_data_avail_wait);
+int fd_ioready(int sock_fd, boolean_t pollin, int timeout);
+int repl_send(int sock_fd, unsigned char *buff, int *send_len, int timeout);
+int repl_recv(int sock_fd, unsigned char *buff, int *recv_len, int timeout);
int repl_close(int *sock_fd);
int get_send_sock_buff_size(int sockfd, int *buflen);
int get_recv_sock_buff_size(int sockfd, int *buflen);
diff --git a/sr_port/repl_ctl.h b/sr_port/repl_ctl.h
index f145291..aa2439b 100644
--- a/sr_port/repl_ctl.h
+++ b/sr_port/repl_ctl.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -47,6 +47,11 @@ typedef struct {
uint4 buffremaining; /* Remaining buffer space */
unsigned char *base_buff; /* Actual malloced buffer start : Not necessarily "gtm_fs_block_size" aligned */
unsigned char *base; /* "gtm_fs_block_size" aligned buffer start */
+# ifdef DEBUG
+ uint4 save_readaddr; /* copy of readaddr before repl_read_file updates it */
+ uint4 save_dskaddr; /* copy of dskaddr noted down, in repl_read_file, from shared memory */
+ uint4 save_buffremaining; /* copy of buffremaining before repl_read_file updates it */
+# endif
} repl_buff_desc;
#define REPL_BLKSIZE(x) ((x)->fc->jfh->alignsize)
diff --git a/sr_port/resolve_ref.c b/sr_port/resolve_ref.c
index 96e7425..c0ee025 100644
--- a/sr_port/resolve_ref.c
+++ b/sr_port/resolve_ref.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -35,11 +35,11 @@ error_def(ERR_ACTLSTTOOLONG);
int resolve_ref(int errknt)
{
- triple *curtrip, *tripref, *chktrip;
+ triple *curtrip, *tripref, *chktrip, *ref, *y;
tbp *tripbp;
mline *mxl;
mlabel *mlbx;
- oprtype *opnd;
+ oprtype *opnd, *j, *k;
int actcnt;
DCL_THREADGBL_ACCESS;
@@ -50,6 +50,73 @@ int resolve_ref(int errknt)
walktree((mvar *)mlabtab, resolve_lab, (char *)&errknt);
} else
{
+ if (!run_time && (cmd_qlf.qlf & CQ_DYNAMIC_LITERALS))
+ { /* OC_LIT --> OC_LITC wherever OC_LIT is actually used, i.e. not a dead end */
+ dqloop(&t_orig, exorder, curtrip)
+ {
+ switch (curtrip->opcode)
+ { /* Do a few literal optimizations typically done later in alloc_reg. It's convenient to
+ * check for OC_LIT parameters here, before we start sliding OC_LITC opcodes in the way.
+ */
+ case OC_NOOP:
+ case OC_PARAMETER:
+ case OC_LITC: /* possibly already inserted in bx_boolop */
+ continue;
+ case OC_STO: /* see counterpart in alloc_reg.c */
+ if ((cmd_qlf.qlf & CQ_INLINE_LITERALS)
+ && (TRIP_REF == curtrip->operand[1].oprclass)
+ && (OC_LIT == curtrip->operand[1].oprval.tref->opcode))
+ {
+ curtrip->opcode = OC_STOLITC;
+ continue;
+ }
+ break;
+ case OC_EQU: /* see counterpart in alloc_reg.c */
+ if ((TRIP_REF == curtrip->operand[0].oprclass)
+ && (OC_LIT == curtrip->operand[0].oprval.tref->opcode)
+ && (0 == curtrip->operand[0].oprval.tref->operand[0].oprval.mlit->v.str.len))
+ {
+ curtrip->operand[0] = curtrip->operand[1];
+ curtrip->operand[1].oprclass = NO_REF;
+ curtrip->opcode = OC_EQUNUL;
+ continue;
+ } else if ((TRIP_REF == curtrip->operand[1].oprclass)
+ && (OC_LIT == curtrip->operand[1].oprval.tref->opcode)
+ && (0 == curtrip->operand[1].oprval.tref->operand[0].oprval.mlit->v.str.len))
+ {
+ curtrip->operand[1].oprclass = NO_REF;
+ curtrip->opcode = OC_EQUNUL;
+ continue;
+ }
+ break;
+ }
+ for (j = curtrip->operand, y = curtrip; j < ARRAYTOP(y->operand); )
+ { /* Iterate over all parameters of the current triple */
+ k = j;
+ while (INDR_REF == k->oprclass)
+ k = k->oprval.indr;
+ if (TRIP_REF == k->oprclass)
+ {
+ tripref = k->oprval.tref;
+ if (OC_PARAMETER == tripref->opcode)
+ {
+ y = tripref;
+ j = y->operand;
+ continue;
+ }
+ if (OC_LIT == tripref->opcode)
+ { /* Insert an OC_LITC to relay the OC_LIT result to curtrip */
+ ref = maketriple(OC_LITC);
+ ref->src = tripref->src;
+ ref->operand[0] = put_tref(tripref);
+ dqins(curtrip->exorder.bl, exorder, ref);
+ *k = put_tref(ref);
+ }
+ }
+ j++;
+ }
+ }
+ }
COMPDBG(PRINTF(" ************************************* Begin resolve_ref scan ******************************\n"););
dqloop(&t_orig, exorder, curtrip)
{
diff --git a/sr_port/sec_shr_map_build.c b/sr_port/sec_shr_map_build.c
index cd6f80a..7e11964 100644
--- a/sr_port/sec_shr_map_build.c
+++ b/sr_port/sec_shr_map_build.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -20,14 +20,21 @@
#include "gdsbml.h"
#include "probe.h"
#include "sec_shr_map_build.h"
+#include "min_max.h"
int sec_shr_map_build(sgmnt_addrs *csa, uint4 *array, unsigned char *base_addr, cw_set_element *cs, trans_num ctn, int bplmap)
{
- boolean_t busy, recycled;
uint4 setbit;
unsigned char *ptr;
- sgmnt_data_ptr_t csd;
uint4 bitnum, ret, prev;
+#ifdef UNIX
+ uint4 (*bml_func)();
+#else /* gtmsecshr on VMS uses a very minimal set of modules so we dont want to pull in bml_*() functions there
+ * and hence avoid using function pointers
+ */
+ uint4 bml_func;
+ uint4 bml_busy = 1, bml_free = 2, bml_recycled = 3;
+#endif
#ifdef DEBUG
int4 prev_bitnum, actual_cnt = 0;
#endif
@@ -41,22 +48,23 @@ int sec_shr_map_build(sgmnt_addrs *csa, uint4 *array, unsigned char *base_addr,
assert(FALSE);
return FALSE;
}
- busy = (cs->reference_cnt > 0);
- if (!busy)
+ /* The following PROBE's are needed before DETERMINE_BML_FUNC, as the macro uses these pointers. */
+ if (!GTM_PROBE(SIZEOF(sgmnt_addrs), csa, READ))
{
- if (!GTM_PROBE(SIZEOF(sgmnt_addrs), csa, READ))
- {
- assert(FALSE);
- return FALSE;
- }
- csd = csa->hdr;
- if (!GTM_PROBE(SIZEOF(sgmnt_data), csd, READ))
- {
- assert(FALSE);
- return FALSE;
- }
- recycled = csd->db_got_to_v5_once ? TRUE : FALSE;
+ assert(FALSE);
+ return FALSE;
+ }
+ if (!(GTM_PROBE(NODE_LOCAL_SIZE_DBS, csa->nl, WRITE)))
+ {
+ assert(FALSE);
+ return FALSE;
+ }
+ if (!GTM_PROBE(SIZEOF(sgmnt_data), csa->hdr, READ))
+ {
+ assert(FALSE);
+ return FALSE;
}
+ DETERMINE_BML_FUNC(bml_func, cs, csa);
DEBUG_ONLY(prev_bitnum = -1;)
for (;;)
{
@@ -82,7 +90,7 @@ int sec_shr_map_build(sgmnt_addrs *csa, uint4 *array, unsigned char *base_addr,
return FALSE;
}
setbit &= 7;
- if (busy)
+ if (bml_busy == bml_func)
{
*ptr &= ~(3 << setbit); /* mark block as BUSY (00) */
DEBUG_ONLY(actual_cnt++);
@@ -93,7 +101,7 @@ int sec_shr_map_build(sgmnt_addrs *csa, uint4 *array, unsigned char *base_addr,
if (!prev)
actual_cnt--;
)
- if (recycled)
+ if (bml_recycled == bml_func)
*ptr |= (3 << setbit); /* mark block as RECYCLED (11) */
else
{ /* mark block as FREE (01) */
diff --git a/sr_port/secshr_db_clnup.c b/sr_port/secshr_db_clnup.c
index 964b2aa..b1bbf68 100644
--- a/sr_port/secshr_db_clnup.c
+++ b/sr_port/secshr_db_clnup.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -1178,7 +1178,7 @@ void secshr_db_clnup(enum secshr_db_state secshr_state)
blk_ptr = (sm_uc_ptr_t)GDS_ANY_REL2ABS(csa, cr->buffaddr);
} else
{ /* access method is MM */
- blk_ptr = (sm_uc_ptr_t)csa->acc_meth.mm.base_addr + (off_t)csd->blk_size * cs->blk;
+ blk_ptr = MM_BASE_ADDR(csa) + (off_t)csd->blk_size * cs->blk;
if (!GTM_PROBE(csd->blk_size, blk_ptr, WRITE))
{
SECSHR_ACCOUNTING(7);
@@ -1187,7 +1187,7 @@ void secshr_db_clnup(enum secshr_db_state secshr_state)
SECSHR_ACCOUNTING(cs->blk);
SECSHR_ACCOUNTING((INTPTR_T)blk_ptr);
SECSHR_ACCOUNTING(csd->blk_size);
- SECSHR_ACCOUNTING((INTPTR_T)csa->acc_meth.mm.base_addr);
+ SECSHR_ACCOUNTING((INTPTR_T)(MM_BASE_ADDR(csa)));
assert(FALSE);
continue;
}
@@ -1746,7 +1746,7 @@ void secshr_db_clnup(enum secshr_db_state secshr_state)
csd->trans_hist.early_tn = csd->trans_hist.curr_tn;
}
assert(csd->trans_hist.early_tn == csd->trans_hist.curr_tn);
- if (GTM_PROBE(CRIT_SPACE, csa->critical, WRITE))
+ if (GTM_PROBE(CRIT_SPACE(NUM_CRIT_ENTRY(csd)), csa->critical, WRITE))
{
/* ONLINE ROLLBACK can come here holding crit ONLY due to commit errors but NOT during
* process exiting as secshr_db_clnup during process exiting is always preceded by
@@ -1792,7 +1792,7 @@ void secshr_db_clnup(enum secshr_db_state secshr_state)
SECSHR_ACCOUNTING((INTPTR_T)cnl);
SECSHR_ACCOUNTING(NODE_LOCAL_SIZE_DBS);
SECSHR_ACCOUNTING((INTPTR_T)csa->critical);
- SECSHR_ACCOUNTING(CRIT_SPACE);
+ SECSHR_ACCOUNTING(CRIT_SPACE(NUM_CRIT_ENTRY(csd)));
assert(FALSE);
}
}
@@ -1828,7 +1828,7 @@ void secshr_db_clnup(enum secshr_db_state secshr_state)
}
#ifdef UNIX
/* All releases done now. Double check latch is really cleared */
- if (GTM_PROBE(CRIT_SPACE, csa->critical, WRITE))
+ if (GTM_PROBE(CRIT_SPACE(NUM_CRIT_ENTRY(csd)), csa->critical, WRITE))
{
/* as long as csa->hold_onto_crit is FALSE, we should have released crit if we held it at entry */
assert(!csa->now_crit || csa->hold_onto_crit);
@@ -1847,9 +1847,6 @@ void secshr_db_clnup(enum secshr_db_state secshr_state)
SECSHR_PROBE_REGION(reg); /* SECSHR_PROBE_REGION sets csa */
if (csa->now_crit)
{
- /* for normal termination we should not have been holding the journal pool crit lock */
- assert((NORMAL_TERMINATION) != secshr_state || ((gtm_white_box_test_case_enabled
- && (WBTEST_ANTIFREEZE_DSKNOSPCAVAIL == gtm_white_box_test_case_number))));
jpl = (jnlpool_ctl_ptr_t)((sm_uc_ptr_t)csa->critical - JNLPOOL_CTL_SIZE); /* see jnlpool_init() for
* relationship between
* critical and jpl */
@@ -1904,7 +1901,7 @@ void secshr_db_clnup(enum secshr_db_state secshr_state)
}
cnl = csa->nl;
if ((GTM_PROBE(NODE_LOCAL_SIZE_DBS, cnl, WRITE)) &&
- (GTM_PROBE(CRIT_SPACE, csa->critical, WRITE)))
+ (GTM_PROBE(JNLPOOL_CRIT_SPACE, csa->critical, WRITE)))
{
/* ONLINE ROLLBACK can come here holding crit ONLY due to commit errors but NOT during
* process exiting as secshr_db_clnup during process exiting is always preceded by
diff --git a/sr_port/send_msg.h b/sr_port/send_msg.h
index 9c0e13b..52e4962 100644
--- a/sr_port/send_msg.h
+++ b/sr_port/send_msg.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2005 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -12,6 +12,12 @@
#ifndef SEND_MSG_included
#define SEND_MSG_included
-void send_msg(UNIX_ONLY(int arg_count) VMS_ONLY(int msg_id_arg), ...);
+#if defined(UNIX)
+void send_msg(int arg_count, ...);
+void send_msg_csa(void *csa, int arg_count, ...); /* Use CSA_ARG(CSA) for portability */
+#elif defined(VMS)
+void send_msg(int msg_id_arg, ...);
+#define send_msg_csa send_msg
+#endif
#endif /* SEND_MSG_included */
diff --git a/sr_port/setzdir.c b/sr_port/setzdir.c
index ca26409..a0d3888 100644
--- a/sr_port/setzdir.c
+++ b/sr_port/setzdir.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -17,25 +17,26 @@
#include "gtm_limits.h"
#include <errno.h>
+#include "have_crit.h"
#include "setzdir.h"
UNSUPPORTED_PLATFORM_CHECK
static char directory_buffer[GTM_MAX_DIR_LEN];
-void setzdir(mval *newdir, mval *full_path_of_newdir)
-{ /* newdir is the directory to change to; NULL to set full_path_of_newdir to current working directory.
- * If full_path_of_newdir is non NULL, return the full path of the new directory in full_path_of_newdir.
- * NOTE : the full path of directory is stored in a static buffer which might get overwritten by the next call to setzdir.
- * Callers should save return value if needed. */
+error_def(ERR_SETZDIR);
+error_def(ERR_SYSCALL);
+error_def(ERR_TEXT);
+void setzdir(mval *newdir, mval *full_path_of_newdir)
+{ /* newdir is the directory to change to; NULL to set full_path_of_newdir to current working directory.
+ * If full_path_of_newdir is non NULL, return the full path of the new directory in full_path_of_newdir.
+ * NOTE : the full path of directory is stored in a static buffer which might get overwritten by the next call to setzdir.
+ * Callers should save return value if needed.
+ */
char directory[GTM_MAX_DIR_LEN], *getcwd_res, *err_str;
uint4 length, status;
- error_def(ERR_SETZDIR);
- error_def(ERR_SYSCALL);
- error_def(ERR_TEXT);
-
assert(NULL != newdir || NULL != full_path_of_newdir);
if (NULL != newdir)
{
@@ -44,27 +45,29 @@ void setzdir(mval *newdir, mval *full_path_of_newdir)
memcpy(directory, newdir->str.addr, newdir->str.len);
directory[newdir->str.len] = '\0';
if (-1 == CHDIR(directory))
- { /* On VMS, chdir(directory, 0) [actually, any non 1 value] is supposed to restore the process startup cwd at exit
- * (see help cc run). We've noticed that it doesn't behave the way it has been documented in the mumps executable.
- * Vinaya, 08/22/2001 */
+ { /* On VMS, chdir(directory, 0) [actually, any non 1 value] is supposed to restore the process startup cwd at
+ * exit (see help cc run). We've noticed that it doesn't behave the way it has been documented in the mumps
+ * executable. Vinaya, 08/22/2001.
+ */
err_str = STRERROR(errno);
rts_error(VARLSTCNT(8) ERR_SETZDIR, 2, newdir->str.len, newdir->str.addr, ERR_TEXT, 2,
LEN_AND_STR(err_str));
}
}
/* We need to find the full path of the current working directory because newdir might be a relative path, in which case
- * $ZDIR will show up as a relative path */
+ * $ZDIR will show up as a relative path.
+ */
if (NULL != full_path_of_newdir)
{
- if (NULL != GETCWD(directory_buffer, SIZEOF(directory_buffer), getcwd_res))
+ GETCWD(directory_buffer, SIZEOF(directory_buffer), getcwd_res);
+ if (NULL != getcwd_res)
{
length = USTRLEN(directory_buffer);
UNIX_ONLY(directory_buffer[length++] = '/';)
} else
{
err_str = STRERROR(errno);
- rts_error(VARLSTCNT(11) ERR_SYSCALL, 5, LEN_AND_LIT("getcwd"), CALLFROM, ERR_TEXT, 2,
- LEN_AND_STR(err_str));
+ rts_error(VARLSTCNT(11) ERR_SYSCALL, 5, LEN_AND_LIT("getcwd"), CALLFROM, ERR_TEXT, 2, LEN_AND_STR(err_str));
}
full_path_of_newdir->mvtype = MV_STR;
full_path_of_newdir->str.addr = directory_buffer;
diff --git a/sr_port/show_source_line.c b/sr_port/show_source_line.c
index ff6e2cc..5a59c96 100644
--- a/sr_port/show_source_line.c
+++ b/sr_port/show_source_line.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -31,16 +31,20 @@ error_def(ERR_ARROWNTDSP);
#define MAXLINESIZEFORDISPLAY 1023
-void show_source_line(char* buf, ssize_t buflen, boolean_t warn)
+void show_source_line(boolean_t warn)
{
- char *b, *b_top, *c, *c_top;
- int chlen, chwidth;
- unsigned int ch, line_chwidth = 0;
- boolean_t unable_to_complete_arrow = FALSE;
- mstr msgstr;
+ char *b, *b_top, *c, *c_top, *buf;
+ char source_line_buff[MAX_SRCLINE + SIZEOF(ARROW)];
+ ssize_t buflen;
+ int chlen, chwidth;
+ unsigned int ch, line_chwidth = 0;
+ boolean_t unable_to_complete_arrow = FALSE;
+ mstr msgstr;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
+ buf = source_line_buff;
+ buflen = SIZEOF(source_line_buff);
b_top = buf + buflen - STR_LIT_LEN(ARROW) - 1; /* allow room for arrow and string terminator */
for (c = (char *)source_buffer, b = buf, c_top = c + TREF(last_source_column) - 1; c < c_top;)
{
diff --git a/sr_port/show_source_line.h b/sr_port/show_source_line.h
index 9ce830e..513cbe9 100644
--- a/sr_port/show_source_line.h
+++ b/sr_port/show_source_line.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -14,6 +14,6 @@
#define ARROW "^-----"
-void show_source_line(char* buf, ssize_t buflen, boolean_t warn);
+void show_source_line(boolean_t warn);
#endif /* SHOW_SOURCE_LINE_INCLUDED */
diff --git a/sr_port/sleep_cnt.h b/sr_port/sleep_cnt.h
index 6746096..9f996e9 100644
--- a/sr_port/sleep_cnt.h
+++ b/sr_port/sleep_cnt.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 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 "min_max.h"
-/* Note: GT.M code *MUST*NOT* make use of the sleep() function because use of the sleep() function
+/* Note: GT.M code *MUST*NOT* make use of the sleep() function because use of the sleep() function (BYPASSOK - sleep())
causes problems with GT.M's timers on some platforms. Specifically, the sleep() function
causes the SIGARLM handler to be silently deleted on Solaris systems (through Solaris 9 at least).
This leads to lost timer pops and has the potential for system hangs. The proper long sleep mechanism
@@ -42,7 +42,8 @@
#define JNL_FLUSH_PROG_FACTOR 2
#define JNL_FLUSH_PROG_TRIES (JNL_MAX_FLUSH_TRIES * JNL_FLUSH_PROG_FACTOR)
#define MAX_LCK_TRIES SLEEP_ONE_MIN /* vms only: wait in mu_rndwn_file */
-#define MAX_FSYNC_WAIT_CNT (2 * SLEEP_ONE_MIN) /* 2 mins of total wait for fsync, before GTMASSERTing */
+#define FSYNC_WAIT_TIME (2 * SLEEP_ONE_MIN) /* 2 mins of wait for fsync between JNLFSYNCSTUCK complaints */
+#define FSYNC_WAIT_HALF_TIME SLEEP_ONE_MIN /* 1 min of wait for fsync between DEBUG JNLFSYNCSTUCK complaints */
#define PHASE2_COMMIT_SLEEP MAXSLPTIME /* 10 msec inter-iteration sleep wait for active phase2 commits */
#define PHASE2_COMMIT_WAIT SLEEP_ONE_MIN
diff --git a/sr_port/stack_frame.h b/sr_port/stack_frame.h
index e51a50d..116d226 100644
--- a/sr_port/stack_frame.h
+++ b/sr_port/stack_frame.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -88,6 +88,8 @@ typedef struct stack_frame_struct /* contents of the GT.M MUMPS stack frame */
#define SFT_ZINTR (1 << 8) /* 0x0100 $zinterrupt frame */
#define SFT_TRIGR (1 << 9) /* 0x0200 Trigger base frame */
+#define SFT_ZINTR_OFF ~(SFT_ZINTR) /* Mask to turn off SFF_ZINTR */
+
/* The following definition identifies a frame that is running a line of code - either in a routine or what amounts to an XECUTE
* it excludes frames dealing with @ indirection and frames generated for various nefarious internal purposes.
* As of this writing, it's used in op_unwind to identify a frame that should receive a relocated for_ctrl_stack created by an @
diff --git a/sr_port/stp_gcol_src.h b/sr_port/stp_gcol_src.h
index 87ca78f..c0e817a 100644
--- a/sr_port/stp_gcol_src.h
+++ b/sr_port/stp_gcol_src.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -146,8 +146,8 @@ error_def(ERR_STPEXPFAIL);
* gives compiler warnings in HPUX Itanium since source is 2-byte aligned whereas destination \
* is 8-byte aligned. The void * in between makes the compiler forget the 2-byte alignment. \
*/ \
- UNIX_ONLY(MSTR_STPG_ADD((mstr *)(void *)&NODE->key_mvtype);) \
- VMS_ONLY(MSTR_STPG_ADD((mstr *)(void *)&NODE->key_len);) \
+ UNIX_ONLY(MSTR_STPG_ADD((mstr *)(void *)&NODE->key_mvtype)); \
+ VMS_ONLY(MSTR_STPG_ADD((mstr *)(void *)&NODE->key_len)); \
} \
}
@@ -346,7 +346,6 @@ error_def(ERR_STPEXPFAIL);
#else
#define DBGSTPGCOL(x)
#endif
-
static void expand_stp(unsigned int new_size) /* BYPASSOK */
{
if (retry_if_expansion_fails)
@@ -458,7 +457,7 @@ void stp_gcol(int space_asked) /* BYPASSOK */
int *low_reclaim_passes;
int *incr_factor;
int killcnt;
- long stp_incr, space_needed_rounded_up;
+ long stp_incr;
ht_ent_objcode *tabent_objcode, *topent;
ht_ent_mname *tabent_mname, *topent_mname;
ht_ent_addr *tabent_addr, *topent_addr;
@@ -684,7 +683,7 @@ void stp_gcol(int space_asked) /* BYPASSOK */
if (NULL != (symtab = mvs->mv_st_cont.mvs_stab))
{ /* if initalization of the table was successful */
for (lv_blk_ptr = symtab->lv_first_block; NULL != lv_blk_ptr;
- lv_blk_ptr = lv_blk_ptr->next)
+ lv_blk_ptr = lv_blk_ptr->next)
{
for (lvp = (lv_val *)LV_BLK_GET_BASE(lv_blk_ptr),
lvlimit = LV_BLK_GET_FREE(lv_blk_ptr, lvp);
@@ -704,11 +703,11 @@ void stp_gcol(int space_asked) /* BYPASSOK */
}
}
for (lv_blk_ptr = symtab->lvtreenode_first_block; NULL != lv_blk_ptr;
- lv_blk_ptr = lv_blk_ptr->next)
+ lv_blk_ptr = lv_blk_ptr->next)
{
for (node = (lvTreeNode *)LV_BLK_GET_BASE(lv_blk_ptr),
- node_limit = LV_BLK_GET_FREE(lv_blk_ptr, node);
- node < node_limit; node++)
+ node_limit = LV_BLK_GET_FREE(lv_blk_ptr, node);
+ node < node_limit; node++)
{
/* node could be actively in use or free (added to the symval's
* lvtreenode_flist). Ignore the free ones. Those should have
@@ -752,7 +751,7 @@ void stp_gcol(int space_asked) /* BYPASSOK */
continue;
case MVST_NVAL:
/* The var_name field is only present in a debug build */
- DEBUG_ONLY(MSTR_STPG_ADD(&mvs->mv_st_cont.mvs_nval.name.var_name);)
+ DEBUG_ONLY(MSTR_STPG_ADD(&mvs->mv_st_cont.mvs_nval.name.var_name));
continue;
# ifdef GTM_TRIGGER
case MVST_TRIGR:
@@ -838,7 +837,7 @@ void stp_gcol(int space_asked) /* BYPASSOK */
}
}
space_before_compact = stringpool.top - stringpool.free; /* Available space before compaction */
- DEBUG_ONLY(blklen = stringpool.free - stringpool.base;)
+ DEBUG_ONLY(blklen = stringpool.free - stringpool.base);
stringpool.free = stringpool.base;
if (topstr != array)
{
@@ -893,11 +892,17 @@ void stp_gcol(int space_asked) /* BYPASSOK */
* occurrences of the stringpool filling up, and compaction not reclaiming enough space.
* In such cases, if the stringpool is expanded, we create more room, resulting in fewer calls
* to stp_gcol.
+ *
+ * Note it is not uncommon for space_needed to be a negative value. That can occur in here if we
+ * recovered enough space from the GC to satisfy the immediate need but we have identified that
+ * so little space is still available that we are best served by expanding the stringpool so as to
+ * prevent another almost immediate need for another GC. This is also known as a non-mandatory
+ * expansion. Assert that if space_needed is negative, we have a non-mandatory expansion.
*/
+ assert((0 <= space_needed) || non_mandatory_expansion);
strpool_base = stringpool.base;
/* Grow stringpool geometrically */
stp_incr = (stringpool.top - stringpool.base) * *incr_factor / STP_NUM_INCRS;
- space_needed_rounded_up = ROUND_UP(space_needed, OS_PAGE_SIZE);
first_expansion_try = TRUE;
while (first_expansion_try || (retry_if_expansion_fails && expansion_failed))
{
@@ -917,19 +922,25 @@ void stp_gcol(int space_asked) /* BYPASSOK */
stp_incr = (stringpool.top - stringpool.base) * *incr_factor / STP_NUM_INCRS;
} else
/* if we are already at the lowest incr_factor half our way down */
- if (stp_incr > space_needed_rounded_up)
+ if (stp_incr > space_needed)
stp_incr = stp_incr / 2;
}
first_expansion_try = FALSE;
- stp_incr = ROUND_UP(stp_incr, OS_PAGE_SIZE);
if (stp_incr < space_needed)
- stp_incr = space_needed_rounded_up;
+ stp_incr = space_needed;
/* If we are asking for more than is actually needed we want to try again if we do not get it. */
- retry_if_expansion_fails = (stp_incr > space_needed_rounded_up);
- expansion_failed = FALSE; /* will be set to TRUE by condition handler if can't get memory */
- assert(stp_incr + stringpool.top - stringpool.base >= space_needed + blklen);
- DBGSTPGCOL((stderr, "incr_factor=%i stp_incr=%i space_needed=%i\n", *incr_factor, stp_incr,
- space_needed_rounded_up));
+ retry_if_expansion_fails = (stp_incr > space_needed);
+ /* If this is a non-mandatory expansion (which also means space_needed is likely negative but this is
+ * not *always* the case) and stp_incr has come down to less than the size of a page, then there's really
+ * no point in continuing this loop - probably all the way to stp_incr = 0. But for a non-mandatory
+ * expansion, leaving early carries no significiant penalty - especially since we're already operating
+ * on the the edge.
+ */
+ if (non_mandatory_expansion && (0 == stp_incr))
+ break; /* stp_incr can't get smaller - give up and use what we have */
+ expansion_failed = FALSE; /* will be set to TRUE by condition handler if can't get memory */
+ assert((stp_incr + stringpool.top - stringpool.base) >= (space_needed + blklen));
+ DBGSTPGCOL((stderr, "incr_factor=%i stp_incr=%i space_needed=%i\n", *incr_factor, stp_incr, space_needed));
expand_stp((unsigned int)(stp_incr + stringpool.top - stringpool.base));
}
if (strpool_base != stringpool.base) /* expanded successfully */
@@ -944,10 +955,11 @@ void stp_gcol(int space_asked) /* BYPASSOK */
/* Adjust incr_factor */
if (*incr_factor < STP_NUM_INCRS) *incr_factor = *incr_factor + 1;
} else
- { /* could not expand during forced expansion */
+ { /* Could not expand during forced expansion */
assert(non_mandatory_expansion && stop_non_mandatory_expansion);
if (space_after_compact < space_needed)
- rts_error(VARLSTCNT(3) ERR_STPEXPFAIL, 1, stp_incr + stringpool.top - stringpool.base);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_STPEXPFAIL, 1,
+ (stp_incr + stringpool.top - stringpool.base));
}
*low_reclaim_passes = 0;
} else
diff --git a/sr_port/stx_error.c b/sr_port/stx_error.c
index 25207fc..d452430 100644
--- a/sr_port/stx_error.c
+++ b/sr_port/stx_error.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -98,7 +98,7 @@ void stx_error(int in_error, ...)
arg3 = va_arg(args, VA_ARG_TYPE);
arg4 = va_arg(args, VA_ARG_TYPE);
va_end(args);
- rts_error(VARLSTCNT(6) in_error, cnt, arg1, arg2, arg3, arg4);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) in_error, cnt, arg1, arg2, arg3, arg4);
} else if ((ERR_LABELMISSING == in_error)
|| (ERR_FMLLSTMISSING == in_error)
|| (ERR_ACTLSTTOOLONG == in_error)
@@ -110,18 +110,18 @@ void stx_error(int in_error, ...)
arg1 = va_arg(args, VA_ARG_TYPE);
arg2 = va_arg(args, VA_ARG_TYPE);
va_end(args);
- rts_error(VARLSTCNT(4) in_error, cnt, arg1, arg2);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) in_error, cnt, arg1, arg2);
} else if ((ERR_CEUSRERROR == in_error) || (ERR_INVDLRCVAL == in_error) || (ERR_FOROFLOW == in_error))
{
cnt = va_arg(args, VA_ARG_TYPE);
assert(cnt == 1);
arg1 = va_arg(args, VA_ARG_TYPE);
va_end(args);
- rts_error(VARLSTCNT(3) in_error, cnt, arg1);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) in_error, cnt, arg1);
} else
{
va_end(args);
- rts_error(VARLSTCNT(1) in_error);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) in_error);
}
} else if ((CGP_PARSE == cg_phase) && (ERR_INVCMD != in_error)) /* if INVCMD has morphed into an error, won't match here */
ins_errtriple(in_error);
@@ -152,8 +152,7 @@ void stx_error(int in_error, ...)
warn = FALSE; /* if listing is going to $P, don't double output */
if (ERR_BADCHAR == in_error)
{
- memset(buf, ' ', LISTTAB);
- show_source_line(&buf[LISTTAB], SIZEOF(buf), warn);
+ show_source_line(warn);
cnt = va_arg(args, VA_ARG_TYPE);
assert(cnt == 4);
arg1 = va_arg(args, VA_ARG_TYPE);
@@ -165,8 +164,6 @@ void stx_error(int in_error, ...)
dec_err(VARLSTCNT(6) in_error, 4, arg1, arg2, arg3, arg4);
dec_err(VARLSTCNT(4) ERR_SRCNAM, 2, source_name_len, source_file_name);
}
- if (list)
- list_line(buf);
arg1 = arg2 = arg3 = arg4 = 0;
} else if ((ERR_LABELMISSING == in_error)
|| (ERR_FMLLSTMISSING == in_error)
@@ -185,8 +182,7 @@ void stx_error(int in_error, ...)
}
} else
{
- memset(buf, ' ', LISTTAB);
- show_source_line(&buf[LISTTAB], SIZEOF(buf), warn);
+ show_source_line(warn);
if (warn)
{
if ((ERR_CEUSRERROR != in_error) && (ERR_INVDLRCVAL != in_error) && (ERR_FOROFLOW != in_error))
@@ -199,8 +195,6 @@ void stx_error(int in_error, ...)
dec_err(VARLSTCNT(3) in_error, 1, arg1);
}
}
- if (list)
- list_line(buf);
arg1 = arg2 = 0;
}
va_end(args);
diff --git a/sr_port/t_begin.c b/sr_port/t_begin.c
index 4684c45..dfd627d 100644
--- a/sr_port/t_begin.c
+++ b/sr_port/t_begin.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -44,6 +44,8 @@ GBLREF sgm_info *first_sgm_info;
GBLREF boolean_t need_kip_incr;
GBLREF boolean_t mu_reorg_process;
+error_def(ERR_MMREGNOACCESS);
+
void t_begin(uint4 err, uint4 upd_trans) /* err --> error code for current gvcst_routine */
{
srch_blk_status *s;
@@ -60,7 +62,11 @@ void t_begin(uint4 err, uint4 upd_trans) /* err --> error code for current gvcs
* incremented for the current transaction.
*/
t_err = err;
-
+ if ((NULL == cs_addrs->db_addrs[0]) && (dba_mm == cs_addrs->hdr->acc_meth))
+ {
+ rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(6) ERR_MMREGNOACCESS, 4, REG_LEN_STR(cs_addrs->region),
+ DB_LEN_STR(cs_addrs->region));
+ }
/* If we use a clue then we must consider the oldest tn in the search history to be the start tn for this transaction */
/* start_tn manipulation for TP taken care of in tp_hist */
if (cs_addrs->critical)
diff --git a/sr_port/t_create.c b/sr_port/t_create.c
index fac8c82..47193e8 100644
--- a/sr_port/t_create.c
+++ b/sr_port/t_create.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -26,6 +26,15 @@
#include "tp.h"
#include "t_create.h"
+#define TP_ALLOCATION_CLUE_INCREMENT 1 /* This is the default value. Defined below (under a #ifdef) is another value
+ * Enable below #ifdef/#endif block if you want that value instead.
+ */
+#ifdef TP_ALLOCATION_CLUE_BUMP_BY_512
+#define TP_ALLOCATION_CLUE_INCREMENT 512 /* Change this to some other number if you want a different bump to the
+ * tp allocation clue each time it is used.
+ */
+#endif
+
GBLREF cw_set_element cw_set[];
GBLREF sgmnt_data_ptr_t cs_data;
GBLREF unsigned char cw_set_depth;
@@ -61,11 +70,15 @@ block_index t_create (
{
if (!tp_allocation_clue)
{
- tp_allocation_clue = gtm_tp_allocation_clue + 1;
- hint = tp_allocation_clue;
+ tp_allocation_clue = gtm_tp_allocation_clue + 1; /* + 1 so we dont start out with 0 value for "hint" */
+ hint = tp_allocation_clue; /* this is copied over to cse->blk which is asserted
+ * in gvcst_put as never being 0.
+ */
} else
{
- hint = ++tp_allocation_clue;
+ tp_allocation_clue += TP_ALLOCATION_CLUE_INCREMENT;
+ hint = tp_allocation_clue;
+ /* What if hint becomes greater than total_blks. Should we wrap back to 0? */
if (tp_allocation_clue < 0)
GTMASSERT;
}
@@ -73,9 +86,9 @@ block_index t_create (
assert(gv_target);
cse->blk_target = gv_target;
}
-
cse->mode = gds_t_create;
cse->blk_checksum = 0;
+ assert(hint); /* various callers (particularly gvcst_put) rely on gds_t_create cse to have a non-zero "blk" */
cse->blk = hint;
cse->upd_addr = upd_addr;
cse->ins_off = ins_off;
diff --git a/sr_port/t_end.c b/sr_port/t_end.c
index 780698c..abc5b51 100644
--- a/sr_port/t_end.c
+++ b/sr_port/t_end.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -56,6 +56,7 @@
#include "gtmrecv.h"
#include "deferred_signal_handler.h"
#include "repl_instance.h"
+#include "format_targ_key.h"
#endif
/* Include prototypes */
@@ -87,7 +88,6 @@
#include "bml_status_check.h"
#include "is_proc_alive.h"
#include "muextr.h"
-#include "mupip_reorg.h"
GBLREF bool rc_locked;
GBLREF unsigned char t_fail_hist[CDB_MAX_TRIES];
@@ -131,6 +131,7 @@ GBLREF inctn_detail_t inctn_detail; /* holds detail to fill in to inctn jnl r
GBLREF boolean_t block_is_free;
GBLREF boolean_t gv_play_duplicate_kills;
GBLREF boolean_t pool_init;
+GBLREF gv_key *gv_currkey;
#ifdef GTM_TRIGGER
GBLREF boolean_t skip_dbtriggers; /* see gbldefs.c for description of this global */
#endif
@@ -142,6 +143,7 @@ GBLREF int4 strm_index;
GBLREF boolean_t mupip_jnl_recover;
#endif
+error_def(ERR_GBLOFLOW);
error_def(ERR_GVKILLFAIL);
error_def(ERR_GVPUTFAIL);
error_def(ERR_JNLFILOPN);
@@ -184,8 +186,11 @@ if (history) \
#define BUSY2FREE 0x00000001
#define RECYCLED2FREE 0x00000002
-#define FREE_DIR_DATA 0x00000004
-/* free_dir_data denotes the block to be freed is the data block in directory tree */
+#define FREE_DIR_DATA 0x00000004 /* denotes the block to be freed is a data block in directory tree */
+
+#define SAVE_2FREE_IMAGE(MODE, FREE_SEEN, CSD) \
+ (((gds_t_busy2free == MODE) && (!CSD->db_got_to_v5_once || (FREE_SEEN & FREE_DIR_DATA))) \
+ || (gds_t_recycled2free == MODE))
trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn)
{
@@ -206,7 +211,7 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn)
sgm_info *dummysi = NULL; /* needed as a dummy parameter for {mm,bg}_update */
srch_blk_status *t1;
trans_num valid_thru, oldest_hist_tn, dbtn, blktn, temp_tn, epoch_tn, old_block_tn;
- unsigned char cw_depth, cw_bmp_depth;
+ unsigned char cw_depth, cw_bmp_depth, buff[MAX_ZWR_KEY_SZ], *end;
jnldata_hdr_ptr_t jnl_header;
uint4 total_jnl_rec_size, tmp_cumul_jnl_rec_len, tmp_cw_set_depth, prev_cw_set_depth;
DEBUG_ONLY(unsigned int tot_jrec_size;)
@@ -297,8 +302,9 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn)
assert(!gv_cur_region->read_only || !update_trans);
cr_array_index = 0; /* be safe and reset it in PRO even if it is not zero */
if (cnl->wc_blocked || (is_mm && (csa->total_blks != csa->ti->total_blks)))
- { /* If blocked, or we have MM and file has been extended, force repair */
+ { /* If blocked, or we have MM and file has been extended, force repair */
status = cdb_sc_helpedout; /* force retry with special status so philanthropy isn't punished */
+ assert((CDB_STAGNATE > t_tries) || !is_mm || (csa->total_blks == csa->ti->total_blks));
goto failed_skip_revert;
} else
{
@@ -352,6 +358,9 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn)
return csa->ti->curr_tn;
}
}
+ assert((gds_t_committed < gds_t_busy2free) && (n_gds_t_op > gds_t_busy2free));
+ assert((gds_t_committed < gds_t_recycled2free) && (n_gds_t_op > gds_t_recycled2free));
+ assert((gds_t_committed < gds_t_write_root) && (n_gds_t_op > gds_t_write_root));
free_seen = 0;
cw_depth = cw_set_depth;
cw_bmp_depth = cw_depth;
@@ -364,22 +373,21 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn)
} else if (gds_t_busy2free == cw_set[0].mode)
{
assert(TREF(in_gvcst_bmp_mark_free));
- assert(2 == cw_set_depth);
+ free_seen |= BUSY2FREE;
if (CSE_LEVEL_DRT_LVL0_FREE == cw_set[0].level)
- {
- /* the block is in fact level-0 block in directory tree */
+ { /* the block is in fact a level-0 block in the directory tree */
assert(MUSWP_FREE_BLK == TREF(in_mu_swap_root_state));
free_seen |= FREE_DIR_DATA;
}
+ assert(2 == cw_set_depth);
cw_depth = 0;
- free_seen |= BUSY2FREE;
cw_bmp_depth = 1;
} else if (gds_t_recycled2free == cw_set[0].mode)
- {
- assert(2 == cw_set_depth);
- assert(process_id == cnl->trunc_pid && in_mu_truncate); /* In phase 1 of MUPIP REORG -TRUNCATE */
- cw_depth = 1;
+ { /* in phase 1 of MUPIP REORG -TRUNCATE, and we need to free a recycled block */
+ assert(in_mu_truncate);
free_seen |= RECYCLED2FREE;
+ assert(2 == cw_set_depth);
+ cw_depth = 0;
cw_bmp_depth = 1;
}
}
@@ -425,9 +433,23 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn)
} else
{
GET_CDB_SC_CODE(cs->blk, status); /* code is set in status */
+# ifdef UNIX
+ if (is_mm && (cdb_sc_gbloflow == status))
+ {
+ assert(NULL != gv_currkey);
+ if (NULL == (end = format_targ_key(buff, MAX_ZWR_KEY_SZ, gv_currkey, TRUE)))
+ end = &buff[MAX_ZWR_KEY_SZ - 1];
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_GBLOFLOW, 0,
+ ERR_GVIS, 2, end - buff, buff);
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_GBLOFLOW, 0,
+ ERR_GVIS, 2, end - buff, buff);
+ }
+# endif
}
goto failed_skip_revert;
}
+ assert(!is_mm || (cs->blk < csa->total_blks));
+ assert((CDB_STAGNATE > t_tries) || (cs->blk < csa->ti->total_blks));
blk_used ? BIT_SET_RECYCLED_AND_CLEAR_FREE(cs->blk_prior_state)
: BIT_CLEAR_RECYCLED_AND_SET_FREE(cs->blk_prior_state);
BEFORE_IMAGE_NEEDED(read_before_image, cs, csa, csd, cs->blk, before_image_needed);
@@ -443,6 +465,7 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn)
status = (enum cdb_sc)rdfail_detail;
goto failed_skip_revert;
}
+ ASSERT_IS_WITHIN_SHM_BOUNDS((sm_uc_ptr_t)cs->old_block, csa);
if (!WAS_FREE(cs->blk_prior_state) && (NULL != jbbp) && (old_block->tn < jbbp->epoch_tn))
{ /* Compute CHECKSUM for writing PBLK record before getting crit.
* It is possible that we are reading a block that is actually marked free in
@@ -490,6 +513,7 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn)
status = (enum cdb_sc)rdfail_detail;
goto failed_skip_revert;
}
+ ASSERT_IS_WITHIN_SHM_BOUNDS((sm_uc_ptr_t)cs->old_block, csa);
}
}
}
@@ -502,19 +526,14 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn)
tmp_cw_set_depth = cw_map_depth ? cw_map_depth : cw_set_depth;
TOTAL_NONTPJNL_REC_SIZE(total_jnl_rec_size, non_tp_jfb_ptr, csa, tmp_cw_set_depth);
/* For a non-tp update maximum journal space we may need is total size of
- * 1) space for maximum CDB_CW_SET_SIZE PBLKs, that is, MAX_JNL_REC_SIZE * CDB_CW_SET_SIZE
+ * 1) space for maximum CDB_CW_SET_SIZE PBLKs, that is, MAX_MAX_NONTP_JNL_REC_SIZE * CDB_CW_SET_SIZE
* 2) space for a logical record itself, that is, MAX_LOGI_JNL_REC_SIZE and
* 3) overhead records (MIN_TOTAL_NONTPJNL_REC_SIZE + JNL_FILE_TAIL_PRESERVE)
* This requirement is less than the minimum autoswitchlimit size (JNL_AUTOSWITCHLIMIT_MIN) as asserted below.
* Therefore we do not need any check to issue JNLTRANS2BIG error like is being done in tp_tend.c
*/
-# ifdef UNIX
- assert((CDB_CW_SET_SIZE * MAX_PHY_JNL_REC_SIZE(csd) + MAX_LOGI_JNL_REC_SIZE +
- MIN_TOTAL_NONTPJNL_REC_SIZE + JNL_FILE_TAIL_PRESERVE) <= (JNL_AUTOSWITCHLIMIT_MIN * DISK_BLOCK_SIZE));
-# else
- assert((CDB_CW_SET_SIZE * MAX_JNL_REC_SIZE + MAX_LOGI_JNL_REC_SIZE +
+ assert((CDB_CW_SET_SIZE * MAX_MAX_NONTP_JNL_REC_SIZE + MAX_LOGI_JNL_REC_SIZE +
MIN_TOTAL_NONTPJNL_REC_SIZE + JNL_FILE_TAIL_PRESERVE) <= (JNL_AUTOSWITCHLIMIT_MIN * DISK_BLOCK_SIZE));
-# endif
DEBUG_ONLY(tot_jrec_size = MAX_REQD_JNL_FILE_SIZE(total_jnl_rec_size));
assert(tot_jrec_size <= csd->autoswitchlimit);
/* The SET_GBL_JREC_TIME done below should be done before any journal writing activity
@@ -527,7 +546,7 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn)
assert(jgbl.gbl_jrec_time);
}
block_saved = FALSE;
- ESTABLISH_RET(t_ch, 0);
+ ESTABLISH_NOUNWIND(t_ch); /* avoid hefty setjmp call, which is ok since we never unwind t_ch */
assert(!csa->hold_onto_crit || csa->now_crit);
if (!csa->now_crit)
{
@@ -852,21 +871,9 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn)
cs = t1->cse;
if (cs)
{
- /* we do not pin cache record for gds_t_recycled2free here since its cw_depth is larger
- * than 0 so we will pin it later during PINing cache record for every cs if
- * update_trans and before_image is true
- */
- if (n_gds_t_op > cs->mode && gds_t_recycled2free != cs->mode) /* don't pass histories... */
+ if (n_gds_t_op > cs->mode)
{
assert(update_trans);
- assert(gds_t_busy2free > gds_t_committed);
- assert(gds_t_busy2free < n_gds_t_op);
- assert(gds_t_write_root > gds_t_committed);
- assert(gds_t_write_root < n_gds_t_op);
- assert(gds_t_recycled2free > gds_t_committed);
- assert(gds_t_recycled2free < n_gds_t_op);
- assert((gds_t_committed > cs->mode)
- || ((free_seen & BUSY2FREE) && (gds_t_busy2free == cs->mode)));
PIN_CACHE_RECORD(cr, cr_array, cr_array_index);
/* If cs->mode is gds_t_busy2free, then the corresponding cache-record needs
* to be pinned to write the before-image right away but this cse is not going
@@ -876,7 +883,12 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn)
* that the cache-record corresponding to the gds_t_busy2free cse is always the
* first one in the cr_array.
*/
+ assert((gds_t_committed > cs->mode)
+ || (gds_t_busy2free == cs->mode) || (gds_t_recycled2free == cs->mode));
assert((gds_t_busy2free != cs->mode) || (1 == cr_array_index));
+ assert((gds_t_recycled2free != cs->mode) || (1 == cr_array_index));
+ assert((gds_t_busy2free != cs->mode) || (free_seen & BUSY2FREE));
+ assert((gds_t_recycled2free != cs->mode) || (free_seen & RECYCLED2FREE));
}
t1->cse = NULL; /* reset for next transaction */
}
@@ -1021,8 +1033,8 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn)
* or online integ) and did not rely on it for constructing the transaction.
* Restart if block is not present in cache now or is being read in currently.
*/
- assert(gds_t_busy2free != cs->mode);
- if ((gds_t_acquired == cs->mode || gds_t_recycled2free == cs->mode) && (NULL != cs->old_block))
+ assert((gds_t_busy2free != cs->mode) && (gds_t_recycled2free != cs->mode));
+ if ((gds_t_acquired == cs->mode) && (NULL != cs->old_block))
{
assert(read_before_image == ((JNL_ENABLED(csa) && csa->jnl_before_image)
|| csa->backup_in_prog
@@ -1125,7 +1137,7 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn)
{
repl_csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs;
if (!repl_csa->hold_onto_crit)
- grab_lock(jnlpool.jnlpool_dummy_reg, ASSERT_NO_ONLINE_ROLLBACK);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK);
assert(repl_csa->now_crit);
jnlpool_crit_acquired = TRUE;
# ifdef UNIX
@@ -1229,7 +1241,7 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn)
* across multiple generation journal files. */
if (SS_NORMAL != (jnl_status = jnl_flush(jpc->region)))
{
- send_msg(VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(csd),
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(csd),
ERR_TEXT, 2, RTS_ERROR_TEXT("Error with journal flush during t_end"),
jnl_status);
assert((!JNL_ENABLED(csd)) && (JNL_ENABLED(csa)));
@@ -1274,10 +1286,11 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn)
} else
{
if (SS_NORMAL != jpc->status)
- rts_error(VARLSTCNT(7) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(gv_cur_region),
- jpc->status);
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(7) jnl_status, 4, JNL_LEN_STR(csd),
+ DB_LEN_STR(gv_cur_region), jpc->status);
else
- rts_error(VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(gv_cur_region));
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd),
+ DB_LEN_STR(gv_cur_region));
}
}
assert(!TREF(donot_commit)); /* We should never commit a transaction that was determined restartable */
@@ -1322,10 +1335,7 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn)
*/
assert((gds_t_write_root == mode) || (gds_t_busy2free == mode)
|| (gds_t_recycled2free == mode));
- if ((gds_t_write_root == mode)
- || ((gds_t_busy2free == mode)
- && csd->db_got_to_v5_once
- && !(free_seen & FREE_DIR_DATA)))
+ if (!SAVE_2FREE_IMAGE(mode, free_seen, csd))
continue;
}
old_block = (blk_hdr_ptr_t)cs->old_block;
@@ -1451,27 +1461,18 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn)
} else
jnl_write_ztp_logical(csa, non_tp_jfb_ptr, com_csum);
}
- /* write to snapshot and backup file for busy2free and recycled2free mode. */
if (free_seen)
- {
- /* gds_t_busy2free or gds_t_recycled2free mode only appears in mupip reorg -truncate or v4-v5 upgrade.
- * mupip reorg -truncate works only for BG mode, and for MM, we must have blks_to_upgrd == 0, therefore
- * we will never have MM for gds_t_busy2free and gds_t_recycled2free mode
+ { /* Write to snapshot and backup file for busy2free and recycled2free mode. These modes only appear in
+ * mupip reorg -truncate or v4-v5 upgrade, neither of which can occur with MM.
*/
assert(!is_mm);
- assert((2 == cw_set_depth) && (gds_t_writemap == cw_set[1].mode));
cs = &cw_set[0];
- mode = cs->mode;
- blkid = cs->blk;
- /* we always need to write the block to snapshot file when the block is data block in gv tree */
- if ((gds_t_busy2free == mode && (!csd->db_got_to_v5_once || (FREE_DIR_DATA & free_seen)))
- || (gds_t_recycled2free == mode))
+ if (SAVE_2FREE_IMAGE(cs->mode, free_seen, csd))
{
- if (gds_t_busy2free == mode)
- {
- DEBUG_ONLY(csa->backup_in_prog = (BACKUP_NOT_IN_PROGRESS != cnl->nbb);)
- cr = db_csh_get(blkid);
- }
+ blkid = cs->blk;
+ assert(!IS_BITMAP_BLK(blkid) && (blkid == cr_array[0]->blk));
+ csa->backup_in_prog = (BACKUP_NOT_IN_PROGRESS != cnl->nbb);
+ cr = cr_array[0];
backup_cr = cr;
blk_ptr = (sm_uc_ptr_t)GDS_REL2ABS(cr->buffaddr);
backup_blk_ptr = blk_ptr;
@@ -1479,14 +1480,13 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn)
dummysi->backup_block_saved);
# ifdef GTM_SNAPSHOT
if (SNAPSHOTS_IN_PROG(csa))
- {
- lcl_ss_ctx = SS_CTX_CAST(cs_addrs->ss_ctx);
- /* we write the before-image to snapshot file only for FAST_INTEG and not for
+ { /* we write the before-image to snapshot file only for FAST_INTEG and not for
* regular integ because the block is going to be marked free at this point
* and in case of a regular integ a before image will be written to the snapshot
* file eventually when the free block gets reused. So the before-image writing
* effectively gets deferred but does happen.
*/
+ lcl_ss_ctx = SS_CTX_CAST(cs_addrs->ss_ctx);
if (lcl_ss_ctx && FASTINTEG_IN_PROG(lcl_ss_ctx))
WRITE_SNAPSHOT_BLOCK(cs_addrs, cr, NULL, blkid, lcl_ss_ctx);
}
@@ -1529,11 +1529,9 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn)
{
mode = cs->mode;
assert((gds_t_write_root != mode) || ((cs - cw_set) + 1 == cw_depth));
+ assert((gds_t_committed > mode) ||
+ (gds_t_busy2free == mode) || (gds_t_recycled2free == mode) || (gds_t_write_root == mode));
cs->old_mode = (int4)mode; /* note down before being reset to gds_t_committed */
- assert(gds_t_committed < gds_t_write_root);
- assert(gds_t_committed < gds_t_busy2free);
- assert((n_gds_t_op != mode) && (gds_t_committed != mode));
- assert((kill_t_write != mode) && (kill_t_create != mode));
if (gds_t_committed > mode)
{
DEBUG_ONLY(
@@ -1629,28 +1627,12 @@ trans_num t_end(srch_hist *hist1, srch_hist *hist2, trans_num ctn)
# endif
}
start_tn = dbtn; /* start_tn temporarily used to store currtn (for bg_update_phase2) before releasing crit */
- }
- if (free_seen)
- {
- assert(!is_mm);
- if (free_seen & BUSY2FREE)
- {
- assert((gds_t_busy2free == cw_set[0].mode) && cr_array_index && (cw_set[0].blk == cr_array[0]->blk));
- assert(process_id == cr_array[0]->in_cw_set);
- /* need to do below BEFORE releasing crit as we have no other lock on this buffer */
+ if (free_seen)
+ { /* need to do below BEFORE releasing crit as we have no other lock on this buffer */
+ VMS_ONLY(assert((BUSY2FREE == free_seen) && (2 <= cr_array_index) && (cr_array_index <= 3)));
+ UNIX_ONLY(assert(2 == cr_array_index)); /* Unlike VMS, no chance to pin a twin for bitmap update */
+ assert((2 == cw_set_depth) && (process_id == cr_array[0]->in_cw_set));
UNPIN_CACHE_RECORD(cr_array[0]);
- } else if (free_seen & RECYCLED2FREE)
- {
- assert(gds_t_recycled2free == cw_set[0].mode);
- if (read_before_image)
- {
- assert(cr_array_index == 2);
- assert(cw_set[0].blk = cr_array[1]->blk);
- assert(process_id == cr_array[1]->in_cw_set);
- UNPIN_CACHE_RECORD(cr_array[1]);
- } else
- assert(cr_array_index == 1);
- /* Never pinned it in the first place */
}
}
if (!csa->hold_onto_crit)
@@ -1765,7 +1747,7 @@ skip_cr_array:
if (REPL_ALLOWED(csa) && IS_DSE_IMAGE)
{
temp_tn = dbtn + 1;
- send_msg(VARLSTCNT(6) ERR_NOTREPLICATED, 4, &temp_tn, LEN_AND_LIT("DSE"), process_id);
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_NOTREPLICATED, 4, &temp_tn, LEN_AND_LIT("DSE"), process_id);
}
INCR_GVSTATS_COUNTER(csa, cnl, n_nontp_readwrite, 1);
INCR_GVSTATS_COUNTER(csa, cnl, n_nontp_blkread, n_blks_validated);
@@ -1802,21 +1784,21 @@ failed_skip_revert:
gvnh->clue.end = 0;
if ((NULL != hist2) && (NULL != (gvnh = hist2->h[0].blk_num ? hist2->h[0].blk_target : NULL)))
gvnh->clue.end = 0;
- DEBUG_ONLY(
- /* Ensure we dont have t1->cse set for any gv_targets that also have their clue non-zero.
- * As this can cause following transactions to rely on out-of-date information and do wrong things.
- * (e.g. in t_end of the following transaction, we will see t1->cse non-NULL and conclude the buffer
- * needs to be pinned when actually it is not necessary).
- */
- for (gvnh = gv_target_list; NULL != gvnh; gvnh = gvnh->next_gvnh)
+# ifdef DEBUG
+ /* Ensure we dont have t1->cse set for any gv_targets that also have their clue non-zero.
+ * As this can cause following transactions to rely on out-of-date information and do wrong things.
+ * (e.g. in t_end of the following transaction, we will see t1->cse non-NULL and conclude the buffer
+ * needs to be pinned when actually it is not necessary).
+ */
+ for (gvnh = gv_target_list; NULL != gvnh; gvnh = gvnh->next_gvnh)
+ {
+ if (gvnh->clue.end)
{
- if (gvnh->clue.end)
- {
- for (t1 = &gvnh->hist.h[0]; t1->blk_num; t1++)
- assert(NULL == t1->cse);
- }
+ for (t1 = &gvnh->hist.h[0]; t1->blk_num; t1++)
+ assert(NULL == t1->cse);
}
- )
+ }
+# endif
/* t_commit_cleanup releases crit as long as the transition is from 2nd to 3rd retry or 3rd to 3rd retry. The only exception
* is if hold_onto_crit is set to TRUE in which case t_commit_cleanup honors it. Assert accordingly.
*/
diff --git a/sr_port/t_end_sysops.c b/sr_port/t_end_sysops.c
index cfecdb5..fb44ef8 100644
--- a/sr_port/t_end_sysops.c
+++ b/sr_port/t_end_sysops.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2007, 2012 Fidelity Information Services, Inc *
+ * Copyright 2007, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -107,6 +107,7 @@
#endif
error_def(ERR_DBFILERR);
+error_def(ERR_FREEBLKSLOW);
error_def(ERR_GBLOFLOW);
UNIX_ONLY(error_def(ERR_TEXT);)
error_def(ERR_WCBLOCKED);
@@ -135,8 +136,10 @@ void wcs_stale(TID tid, int4 hd_len, gd_region **region);
/* For fast integ, do NOT write the data block in global variable tree to snapshot file */ \
blk_hdr *blk_hdr_ptr; \
boolean_t is_in_gv_tree; \
- /* level-0 block in DIR tree was already processed */ \
+ \
+ /* level-0 block in DIR tree was already processed */ \
assert((CSE_LEVEL_DRT_LVL0_FREE != cs->level) || (gds_t_writemap == cs->mode)); \
+ assert(blkid < lcl_ss_ctx->total_blks); \
blk_hdr_ptr = (blk_hdr_ptr_t)old_block; \
if (WAS_FREE(cs->blk_prior_state)) \
write_to_snapshot_file = FALSE; \
@@ -147,15 +150,12 @@ void wcs_stale(TID tid, int4 hd_len, gd_region **region);
is_in_gv_tree = (IN_GV_TREE == (cs->blk_prior_state & KEEP_TREE_STATUS)); \
write_to_snapshot_file = !((0 == blk_hdr_ptr->levl) && is_in_gv_tree); \
} \
- /* For recycled block: If we decide to write the before image to the snapshot file, we will mark the shadow bitmap \
- * right then. If we decide not to, we will still mark the shadow bitmap. This is so we prevent writing \
- * the before-image to the snapshot file after the recycled block becomes a busy block. \
- * For free block: Similar reason as above \
- * For busy block: level-0 block in gv_tree may change level after swapping with another block, if it's not marked in \
- * shadow bitmap, when it is updated again, it would be mistakenly required to be written to snapshot file \
+ /* If we decide not to write this block to snapshot file, then mark it as written in the snapshot file anyways because: \
+ * (a) For free and recycled blocks, we prevent writing the before-image later when this block becomes busy \
+ * (b) For busy blocks, level-0 block in GV tree may change level after swapping with another block. So, by marking it \
+ * in the shadow bitmap, we prevent writing the before-image later. \
*/ \
- if (!write_to_snapshot_file && (blkid < lcl_ss_ctx->total_blks) \
- && !ss_chk_shdw_bitmap(cs_addrs, lcl_ss_ctx, blkid)) \
+ if (!write_to_snapshot_file && !ss_chk_shdw_bitmap(cs_addrs, lcl_ss_ctx, blkid)) \
ss_set_shdw_bitmap(cs_addrs, lcl_ss_ctx, blkid); \
}
@@ -204,25 +204,26 @@ void fileheader_sync(gd_region *reg)
# if defined(UNIX)
size_t flush_len, sync_size, rounded_flush_len;
int4 save_errno;
- unix_db_info *gds_info;
+ unix_db_info *udi;
# elif defined(VMS)
file_control *fc;
int4 flush_len;
- vms_gds_info *gds_info;
+ vms_gds_info *udi;
# endif
- gds_info = FILE_INFO(reg);
- csa = &gds_info->s_addrs;
+ udi = FILE_INFO(reg);
+ csa = &udi->s_addrs;
csd = csa->hdr;
assert(csa->now_crit); /* only way high water mark code works is if in crit */
/* Adding lock code to it would remove this restriction */
+ assert(!reg->read_only);
assert(0 == memcmp(csd->label, GDS_LABEL, GDS_LABEL_SZ - 1));
cnl = csa->nl;
gvstats_rec_cnl2csd(csa); /* Periodically transfer statistics from database shared-memory to file-header */
high_blk = cnl->highest_lbm_blk_changed;
cnl->highest_lbm_blk_changed = -1; /* Reset to initial value */
flush_len = SGMNT_HDR_LEN;
- if (0 <= high_blk) /* If not negative, flush at least one map block */
+ if (0 <= high_blk) /* If not negative, flush at least one master map block */
flush_len += ((high_blk / csd->bplmap / DISK_BLOCK_SIZE / BITS_PER_UCHAR) + 1) * DISK_BLOCK_SIZE;
if (csa->do_fullblockwrites)
{ /* round flush_len up to full block length. This is safe since we know that
@@ -240,48 +241,14 @@ void fileheader_sync(gd_region *reg)
fc->op_pos = 1;
dbfilop(fc);
# elif defined(UNIX)
- if (dba_mm != csd->acc_meth)
+ DB_LSEEKWRITE(csa, udi->fn, udi->fd, 0, (sm_uc_ptr_t)csd, flush_len, save_errno);
+ if (0 != save_errno)
{
- DB_LSEEKWRITE(csa, gds_info->fn, gds_info->fd, 0, (sm_uc_ptr_t)csd, flush_len, save_errno);
- if (0 != save_errno)
- {
- rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg),
- ERR_TEXT, 2, RTS_ERROR_TEXT("Error during FileHeader Flush"), save_errno);
- }
- return;
- } else
- {
- UNTARGETED_MSYNC_ONLY(
- cti = csa->ti;
- if (cti->last_mm_sync != cti->curr_tn)
- {
- sync_size = (size_t)ROUND_UP((size_t)csa->db_addrs[0] + flush_len, MSYNC_ADDR_INCS)
- - (size_t)csa->db_addrs[0];
- if (-1 == msync((caddr_t)csa->db_addrs[0], sync_size, MS_ASYNC))
- {
- rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), ERR_TEXT, 2,
- RTS_ERROR_TEXT("Error during file msync for fileheader"), errno);
- }
- cti->last_mm_sync = cti->curr_tn; /* save when did last full sync */
- }
- )
- TARGETED_MSYNC_ONLY(
- if (-1 == msync((caddr_t)csa->db_addrs[0], (size_t)ROUND_UP(flush_len, MSYNC_ADDR_INCS), MS_ASYNC))
- {
- rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg),
- ERR_TEXT, 2, RTS_ERROR_TEXT("Error during file msync for fileheader"), errno);
- }
- )
- REGULAR_MSYNC_ONLY(
- DB_LSEEKWRITE(csa, gds_info->fn, gds_info->fd, 0, csa->db_addrs[0], flush_len, save_errno);
- if (0 != save_errno)
- {
- rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg),
- ERR_TEXT, 2, RTS_ERROR_TEXT("Error during FileHeader Flush"), save_errno);
- }
- )
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg),
+ ERR_TEXT, 2, RTS_ERROR_TEXT("Error during FileHeader Flush"), save_errno);
}
# endif
+ return;
}
/* update a bitmap */
@@ -330,6 +297,10 @@ void bm_update(cw_set_element *cs, sm_uc_ptr_t lclmap, boolean_t is_mm)
{
bit_clear(blkid / bplmap, MM_ADDR(csd));
change_bmm = TRUE;
+ if ((0 == csd->extension_size) /* no extension and less than a bit map or less than 1/32 (3.125%) */
+ && ((BLKS_PER_LMAP > cti->free_blocks) || ((cti->total_blks >> 5) > cti->free_blocks)))
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_FREEBLKSLOW, 4, cti->free_blocks, cti->total_blks,
+ DB_LEN_STR(gv_cur_region));
}
} else if (0 > reference_cnt)
{ /* blocks were freed up in this bitmap. check if local bitmap became non-full as a result. if so update mastermap */
@@ -387,36 +358,14 @@ enum cdb_sc mm_update(cw_set_element *cs, trans_num ctn, trans_num effective_tn,
cw_set_element *cs_ptr, *nxt;
off_chain chain;
sm_uc_ptr_t chain_ptr, db_addr[2];
-#ifdef GTM_SNAPSHOT
+# ifdef GTM_SNAPSHOT
boolean_t write_to_snapshot_file;
snapshot_context_ptr_t lcl_ss_ctx;
-#endif
+# endif
# if defined(VMS)
unsigned int status;
io_status_block_disk iosb;
# endif
-# if defined(UNIX)
-# if !defined(UNTARGETED_MSYNC) && !defined(NO_MSYNC)
- /* The earlier_dirty and mmblkr arrays should be declared as
- * boolean_t earlier_dirty[DIVIDE_ROUND_UP(MAX_DB_BLK_SIZE, MSYNC_ADDR_INCS) + 1]
- * but MSYNC_ADDR_INCS is based on OS_PAGE_SIZE which reduces to a function call and therefore can't be
- * used for an array declaration. The alternative is to use a value that is larger than what will be needed.
- * Since DISK_BLOCK_SIZE will always be smaller than OS_PAGE_SIZE and the array isn't very large anyway, use
- * DISK_BLOCK_SIZE instead. This assumption is checked with an assert.
- */
- boolean_t earlier_dirty[DIVIDE_ROUND_UP(MAX_DB_BLK_SIZE, DISK_BLOCK_SIZE) + 1];
- mmblk_rec_ptr_t mmblkr[DIVIDE_ROUND_UP(MAX_DB_BLK_SIZE, DISK_BLOCK_SIZE) + 1];
- uint4 indx;
- int4 lcnt, ocnt, n, blk, blk_first_piece, blk_last_piece;
- uint4 max_ent;
-# if defined(TARGETED_MSYNC)
- sm_uc_ptr_t desired_first, desired_last;
-# else
- unix_db_info *udi;
- int4 save_errno;
-# endif
-# endif
-# endif
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
@@ -425,131 +374,7 @@ enum cdb_sc mm_update(cw_set_element *cs, trans_num ctn, trans_num effective_tn,
INCR_DB_CSH_COUNTER(cs_addrs, n_bgmm_updates, 1);
blkid = cs->blk;
assert((0 <= blkid) && (blkid < cs_addrs->ti->total_blks));
- db_addr[0] = cs_addrs->acc_meth.mm.base_addr + (sm_off_t)cs_data->blk_size * (blkid);
-
-# if defined(UNIX) && !defined(UNTARGETED_MSYNC) && !defined(NO_MSYNC)
- if (0 < cs_data->defer_time)
- {
- TARGETED_MSYNC_ONLY(
- desired_first = db_addr[0];
- desired_last = desired_first + (sm_off_t)(cs_data->blk_size) - 1;
- blk_first_piece = DIVIDE_ROUND_DOWN(desired_first - cs_addrs->db_addrs[0], MSYNC_ADDR_INCS);
- blk_last_piece = DIVIDE_ROUND_DOWN(desired_last - cs_addrs->db_addrs[0], MSYNC_ADDR_INCS);
- )
- REGULAR_MSYNC_ONLY(
- blk_first_piece = blkid;
- blk_last_piece = blkid;
- )
- assert(DISK_BLOCK_SIZE <= MSYNC_ADDR_INCS);
- assert((DIVIDE_ROUND_UP(MAX_DB_BLK_SIZE, DISK_BLOCK_SIZE) + 1) >= (blk_last_piece - blk_first_piece));
- for (blk = blk_first_piece, indx = 0; blk <= blk_last_piece; blk++, indx++)
- {
- mmblkr[indx] = (mmblk_rec_ptr_t)db_csh_get(blk);
- earlier_dirty[indx] = FALSE;
-
- if (NULL == mmblkr[indx])
- {
- mmblk_rec_ptr_t hdr, cur_mmblkr, start_mmblkr, q0;
-
- max_ent = cs_addrs->hdr->n_bts;
- cur_mmblkr = (mmblk_rec_ptr_t)GDS_REL2ABS(cs_addrs->nl->cur_lru_cache_rec_off);
- hdr = cs_addrs->acc_meth.mm.mmblk_state->mmblk_array + (blk % cs_addrs->hdr->bt_buckets);
- start_mmblkr = cs_addrs->acc_meth.mm.mmblk_state->mmblk_array + cs_addrs->hdr->bt_buckets;
-
- for (lcnt = 0; lcnt <= (MAX_CYCLES * max_ent); )
- {
- cur_mmblkr++;
- assert(cur_mmblkr <= (start_mmblkr + max_ent));
- if (cur_mmblkr >= start_mmblkr + max_ent)
- cur_mmblkr = start_mmblkr;
- if (cur_mmblkr->refer)
- {
- lcnt++;
- cur_mmblkr->refer = FALSE;
- continue;
- }
- if ((blk_first_piece <= cur_mmblkr->blk) && (blk_last_piece >= cur_mmblkr->blk))
- { /* If we've already claimed and locked this cache record for another OS block
- * in the current DB block; or we'll be finding it soon, we need to keep looking.
- */
- lcnt++;
- continue;
- }
- if (0 != cur_mmblkr->dirty)
- wcs_get_space(gv_cur_region, 0, (cache_rec_ptr_t)cur_mmblkr);
- cur_mmblkr->blk = blk;
- q0 = (mmblk_rec_ptr_t)((sm_uc_ptr_t)cur_mmblkr + cur_mmblkr->blkque.fl);
- shuffqth((que_ent_ptr_t)q0, (que_ent_ptr_t)hdr);
- cs_addrs->nl->cur_lru_cache_rec_off = GDS_ABS2REL(cur_mmblkr);
-
- earlier_dirty[indx] = FALSE;
- mmblkr[indx] = cur_mmblkr;
- /* Here we cannot call LOCK_NEW_BUFF_FOR_UPDATE directly, because in wcs_wtstart
- * csr->dirty is reset before it releases the LOCK in the buffer.
- * To avoid this very small window followings are needed.
- */
- for (ocnt = 1; ; ocnt++)
- {
- LOCK_BUFF_FOR_UPDATE(mmblkr[indx], n, &cs_addrs->nl->db_latch);
- if (!OWN_BUFF(n))
- {
- if (BUF_OWNER_STUCK < ocnt)
- {
- assert(FALSE);
- if (0 == mmblkr[indx]->dirty)
- {
- LOCK_NEW_BUFF_FOR_UPDATE(mmblkr[indx]);
- break;
- } else
- return cdb_sc_comfail;
- }
- if (WRITER_STILL_OWNS_BUFF(mmblkr[indx], n))
- wcs_sleep(ocnt);
- } else
- {
- break;
- }
- }
- break;
- }
- assert(lcnt <= (MAX_CYCLES * max_ent));
- } else if ((mmblk_rec_ptr_t)CR_NOTVALID == mmblkr[indx])
- { /* ------------- yet to write recovery mechanisms if hashtable is corrupt ------*/
- /* ADD CODE LATER */
- GTMASSERT;
- } else
- { /* See comment (few lines above) about why LOCK_NEW_BUFF_FOR_UPDATE cannot be called here */
- for (ocnt = 1; ; ocnt++)
- {
- LOCK_BUFF_FOR_UPDATE(mmblkr[indx], n, &cs_addrs->nl->db_latch);
- if (!OWN_BUFF(n))
- {
- if (BUF_OWNER_STUCK < ocnt)
- {
- assert(FALSE);
- if (0 == mmblkr[indx]->dirty)
- {
- LOCK_NEW_BUFF_FOR_UPDATE(mmblkr[indx]);
- break;
- } else
- return cdb_sc_comfail;
- }
- if (WRITER_STILL_OWNS_BUFF(mmblkr[indx], n))
- wcs_sleep(ocnt);
- } else
- {
- break;
- }
- }
-
- if (0 != mmblkr[indx]->dirty)
- earlier_dirty[indx] = TRUE;
- else
- earlier_dirty[indx] = FALSE;
- }
- }
- }
-# endif
+ db_addr[0] = MM_BASE_ADDR(cs_addrs) + (sm_off_t)cs_data->blk_size * (blkid);
/* check for online backup -- ATTN: this part of code is similar to the BG_BACKUP_BLOCK macro */
if ((blkid >= cs_addrs->nl->nbb) && (NULL != cs->old_block)
&& (0 == cs_addrs->shmpool_buffer->failed)
@@ -567,29 +392,20 @@ enum cdb_sc mm_update(cw_set_element *cs, trans_num ctn, trans_num effective_tn,
{
lcl_ss_ctx = SS_CTX_CAST(cs_addrs->ss_ctx);
assert(lcl_ss_ctx);
- if (FASTINTEG_IN_PROG(lcl_ss_ctx))
+ if (blkid < lcl_ss_ctx->total_blks)
{
- DO_FAST_INTEG_CHECK(db_addr[0], cs_addrs, cs, lcl_ss_ctx, blkid, write_to_snapshot_file);
- } else
- write_to_snapshot_file = TRUE;
- if (write_to_snapshot_file)
- WRITE_SNAPSHOT_BLOCK(cs_addrs, NULL, db_addr[0], blkid, lcl_ss_ctx);
- /* If the block id is greater than the db size at the start of the snapshot, no before image is written by
- * either fast or regular integ
- * If regular MUPIP INTEG is in progress then the current block better be before imaged in the snapshot file.
- * Only exception is when the current block transaction number is greater than or equal to the snapshot
- * transaction number in which case the before image will not be written to the snapshot file.
- * If fast MUPIP INTEG is in progress, we dont write before-image in various cases (e.g. data block in GV tree,
- * or if block was free etc.) even if the block transaction number is less than the snapshot tn. But in those
- * cases write_to_snapshot is set to FALSE. So we can still assert that as long as write_to_snapshot is true,
- * the block must have been before-imaged to the snapshot file.
- */
- assert((blkid >= lcl_ss_ctx->total_blks)
- || !FASTINTEG_IN_PROG(lcl_ss_ctx)
- && (((blk_hdr_ptr_t)db_addr[0])->tn >= lcl_ss_ctx->ss_shm_ptr->ss_info.snapshot_tn)
- || ss_chk_shdw_bitmap(cs_addrs, lcl_ss_ctx, blkid)
- || FASTINTEG_IN_PROG(lcl_ss_ctx)
- && (!write_to_snapshot_file || ss_chk_shdw_bitmap(cs_addrs, lcl_ss_ctx, blkid)));
+ if (FASTINTEG_IN_PROG(lcl_ss_ctx))
+ {
+ DO_FAST_INTEG_CHECK(db_addr[0], cs_addrs, cs, lcl_ss_ctx, blkid, write_to_snapshot_file);
+ } else
+ write_to_snapshot_file = TRUE;
+ if (write_to_snapshot_file)
+ WRITE_SNAPSHOT_BLOCK(cs_addrs, NULL, db_addr[0], blkid, lcl_ss_ctx);
+ assert(!FASTINTEG_IN_PROG(lcl_ss_ctx) || !write_to_snapshot_file
+ || ss_chk_shdw_bitmap(cs_addrs, lcl_ss_ctx, blkid));
+ assert(FASTINTEG_IN_PROG(lcl_ss_ctx) || ss_chk_shdw_bitmap(cs_addrs, lcl_ss_ctx, blkid)
+ || ((blk_hdr_ptr_t)(db_addr[0]))->tn >= lcl_ss_ctx->ss_shm_ptr->ss_info.snapshot_tn);
+ }
}
# endif
if (gds_t_writemap == cs->mode)
@@ -681,74 +497,8 @@ enum cdb_sc mm_update(cw_set_element *cs, trans_num ctn, trans_num effective_tn,
if (SS$_NOTMODIFIED != status) /* don't expect notmodified, but no harm to go on */
return cdb_sc_comfail;
}
-# elif defined(UNTARGETED_MSYNC)
- if (cs_addrs->ti->last_mm_sync != cs_addrs->ti->curr_tn)
- { /* msync previous transaction as part of updating first block in the current transaction */
- if (-1 == msync((caddr_t)cs_addrs->db_addrs[0],
- (size_t)(cs_addrs->db_addrs[1] - cs_addrs->db_addrs[0]), MS_SYNC))
- {
- assert(FALSE);
- return cdb_sc_comfail;
- }
- cs_addrs->ti->last_mm_sync = cs_addrs->ti->curr_tn; /* Save when did last full sync */
- }
-# elif defined(TARGETED_MSYNC)
- caddr_t start;
-
- start = (caddr_t)ROUND_DOWN2((sm_off_t)db_addr[0], MSYNC_ADDR_INCS);
- if (-1 == msync(start,
- (size_t)ROUND_UP((sm_off_t)((caddr_t)db_addr[0] - start) + cs_data->blk_size, MSYNC_ADDR_INCS), MS_SYNC))
- {
- assert(FALSE);
- return cdb_sc_comfail;
- }
-# elif !defined(NO_MSYNC)
- udi = FILE_INFO(gv_cur_region);
- DB_LSEEKWRITE(csa, udi->fn, udi->fd, (db_addr[0] - (sm_uc_ptr_t)cs_data),
- db_addr[0], cs_data->blk_size, save_errno);
- if (0 != save_errno)
- {
- gtm_putmsg(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region),
- ERR_TEXT, 2, RTS_ERROR_TEXT("Error during MM Block Write"), save_errno);
- assert(FALSE);
- return cdb_sc_comfail;
- }
# endif
}
-# if defined(UNIX) && !defined(UNTARGETED_MSYNC) && !defined(NO_MSYNC)
- if (0 < cs_data->defer_time)
- {
- int4 n;
-
- for (blk = blk_first_piece, indx = 0; blk <= blk_last_piece; blk++, indx++)
- {
- mmblkr[indx]->dirty = cs_addrs->ti->curr_tn;
- mmblkr[indx]->refer = TRUE;
-
- if (FALSE == earlier_dirty[indx])
- {
- ADD_ENT_TO_ACTIVE_QUE_CNT(&cs_addrs->nl->wcs_active_lvl, &cs_addrs->nl->wc_var_lock);
- DECR_CNT(&cs_addrs->nl->wc_in_free, &cs_addrs->nl->wc_var_lock);
- if (INTERLOCK_FAIL == INSQTI((que_ent_ptr_t)&mmblkr[indx]->state_que,
- (que_head_ptr_t)&cs_addrs->acc_meth.mm.mmblk_state->mmblkq_active))
- {
- assert(FALSE);
- return cdb_sc_comfail;
- }
- }
- RELEASE_BUFF_UPDATE_LOCK(mmblkr[indx], n, &cs_addrs->nl->db_latch);
- if (WRITER_BLOCKED_BY_PROC(n))
- { /* it's off the active queue, so put it back at the head */
- if (INTERLOCK_FAIL == INSQHI((que_ent_ptr_t)&mmblkr[indx]->state_que,
- (que_head_ptr_t)&cs_addrs->acc_meth.mm.mmblk_state->mmblkq_active))
- {
- assert(FALSE);
- return cdb_sc_comfail;
- }
- }
- }
- }
-# endif
return cdb_sc_normal;
}
@@ -846,7 +596,7 @@ enum cdb_sc bg_update_phase1(cw_set_element *cs, trans_num ctn, sgm_info *si)
}
)
BG_TRACE_PRO(wcb_t_end_sysops_nocr_invcr);
- send_msg(VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_LIT("wcb_t_end_sysops_nocr_invcr"),
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_LIT("wcb_t_end_sysops_nocr_invcr"),
process_id, &ctn, DB_LEN_STR(gv_cur_region));
return cdb_sc_cacheprob;
}
@@ -857,7 +607,7 @@ enum cdb_sc bg_update_phase1(cw_set_element *cs, trans_num ctn, sgm_info *si)
{
assert(gtm_white_box_test_case_enabled);
BG_TRACE_PRO(wcb_t_end_sysops_cr_invcr);
- send_msg(VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_LIT("wcb_t_end_sysops_cr_invcr"),
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_LIT("wcb_t_end_sysops_cr_invcr"),
process_id, &ctn, DB_LEN_STR(gv_cur_region));
return cdb_sc_cacheprob;
} else if (-1 != cr->read_in_progress)
@@ -871,7 +621,7 @@ enum cdb_sc bg_update_phase1(cw_set_element *cs, trans_num ctn, sgm_info *si)
if (!read_finished)
{
BG_TRACE_PRO(wcb_t_end_sysops_rip_wait);
- send_msg(VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_LIT("wcb_t_end_sysops_rip_wait"),
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_LIT("wcb_t_end_sysops_rip_wait"),
process_id, &ctn, DB_LEN_STR(gv_cur_region));
return cdb_sc_cacheprob;
}
@@ -894,26 +644,27 @@ enum cdb_sc bg_update_phase1(cw_set_element *cs, trans_num ctn, sgm_info *si)
assert(LATCH_CLEAR == WRITE_LATCH_VAL(cr));
LOCK_NEW_BUFF_FOR_UPDATE(cr); /* not on the active queue and this process is crit */
)
- UNIX_ONLY(
- /* Since the only case where the write interlock is not clear in Unix is a two-instruction window
- * (described in the above comment), we dont expect the lock-not-clear situation to be frequent.
- * Hence, for performance reasons we do the check before invoking the wcs_write_in_progress_wait function
- * (instead of moving the if check into the function which would mean an unconditional function call).
- */
- if (LATCH_CLEAR != WRITE_LATCH_VAL(cr))
+# ifdef UNIX
+ /* Since the only case where the write interlock is not clear in Unix is a two-instruction window
+ * (described in the above comment), we dont expect the lock-not-clear situation to be frequent.
+ * Hence, for performance reasons we do the check before invoking the wcs_write_in_progress_wait function
+ * (instead of moving the if check into the function which would mean an unconditional function call).
+ */
+ if (LATCH_CLEAR != WRITE_LATCH_VAL(cr))
+ {
+ write_finished = wcs_write_in_progress_wait(cnl, cr, WBTEST_BG_UPDATE_DIRTYSTUCK1);
+ if (!write_finished)
{
- write_finished = wcs_write_in_progress_wait(cnl, cr, WBTEST_BG_UPDATE_DIRTYSTUCK1);
- if (!write_finished)
- {
- assert(gtm_white_box_test_case_enabled);
- BG_TRACE_PRO(wcb_t_end_sysops_dirtystuck1);
- send_msg(VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_LIT("wcb_t_end_sysops_dirtystuck1"),
- process_id, &ctn, DB_LEN_STR(gv_cur_region));
- return cdb_sc_cacheprob;
- }
- } else
- LOCK_NEW_BUFF_FOR_UPDATE(cr); /* writer has released interlock and this process is crit */
- )
+ assert(gtm_white_box_test_case_enabled);
+ BG_TRACE_PRO(wcb_t_end_sysops_dirtystuck1);
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_WCBLOCKED,
+ 6, LEN_AND_LIT("wcb_t_end_sysops_dirtystuck1"), process_id, &ctn,
+ DB_LEN_STR(gv_cur_region));
+ return cdb_sc_cacheprob;
+ }
+ } else
+ LOCK_NEW_BUFF_FOR_UPDATE(cr); /* writer has released interlock and this process is crit */
+# endif
assert(LATCH_SET <= WRITE_LATCH_VAL(cr));
BG_TRACE(new_buff);
cr->bt_index = GDS_ABS2REL(bt);
@@ -939,8 +690,9 @@ enum cdb_sc bg_update_phase1(cw_set_element *cs, trans_num ctn, sgm_info *si)
{
assert(gtm_white_box_test_case_enabled);
BG_TRACE_PRO(wcb_t_end_sysops_intend_wait);
- send_msg(VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_LIT("wcb_t_end_sysops_intend_wait"),
- process_id, &ctn, DB_LEN_STR(gv_cur_region));
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_WCBLOCKED,
+ 6, LEN_AND_LIT("wcb_t_end_sysops_intend_wait"),
+ process_id, &ctn, DB_LEN_STR(gv_cur_region));
return cdb_sc_cacheprob;
}
}
@@ -961,8 +713,9 @@ enum cdb_sc bg_update_phase1(cw_set_element *cs, trans_num ctn, sgm_info *si)
{
assert(gtm_white_box_test_case_enabled);
BG_TRACE_PRO(wcb_t_end_sysops_dirtystuck2);
- send_msg(VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_LIT("wcb_t_end_sysops_dirtystuck2"),
- process_id, &ctn, DB_LEN_STR(gv_cur_region));
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_WCBLOCKED,
+ 6, LEN_AND_LIT("wcb_t_end_sysops_dirtystuck2"),
+ process_id, &ctn, DB_LEN_STR(gv_cur_region));
return cdb_sc_cacheprob;
}
}
@@ -1010,8 +763,9 @@ enum cdb_sc bg_update_phase1(cw_set_element *cs, trans_num ctn, sgm_info *si)
}
)
BG_TRACE_PRO(wcb_t_end_sysops_dirty_invcr);
- send_msg(VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_LIT("wcb_t_end_sysops_dirty_invcr"),
- process_id, &ctn, DB_LEN_STR(gv_cur_region));
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_WCBLOCKED,
+ 6, LEN_AND_LIT("wcb_t_end_sysops_dirty_invcr"),
+ process_id, &ctn, DB_LEN_STR(gv_cur_region));
return cdb_sc_cacheprob;
}
assert(NULL != cr1);
@@ -1046,7 +800,7 @@ enum cdb_sc bg_update_phase1(cw_set_element *cs, trans_num ctn, sgm_info *si)
{
assert(gtm_white_box_test_case_enabled);
BG_TRACE_PRO(wcb_t_end_sysops_wtfini_fail);
- send_msg(VARLSTCNT(8) ERR_WCBLOCKED, 6,
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_WCBLOCKED, 6,
LEN_AND_LIT("wcb_t_end_sysops_wtfini_fail"),
process_id, &ctn, DB_LEN_STR(gv_cur_region));
return cdb_sc_cacheprob;
@@ -1072,7 +826,7 @@ enum cdb_sc bg_update_phase1(cw_set_element *cs, trans_num ctn, sgm_info *si)
{
status = sys$dclast(wcs_wtstart, gv_cur_region, 0);
if (SS$_NORMAL != status)
- send_msg(VARLSTCNT(6) ERR_DBFILERR, 2,
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_DBFILERR, 2,
DB_LEN_STR(gv_cur_region), 0, status);
wcs_sleep(lcnt);
}
@@ -1084,7 +838,7 @@ enum cdb_sc bg_update_phase1(cw_set_element *cs, trans_num ctn, sgm_info *si)
{
assert(gtm_white_box_test_case_enabled);
BG_TRACE_PRO(wcb_t_end_sysops_twin_stuck);
- send_msg(VARLSTCNT(8) ERR_WCBLOCKED, 6,
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_WCBLOCKED, 6,
LEN_AND_LIT("wcb_t_end_sysops_twin_stuck"),
process_id, &ctn, DB_LEN_STR(gv_cur_region));
return cdb_sc_cacheprob;
@@ -1171,7 +925,7 @@ enum cdb_sc bg_update_phase1(cw_set_element *cs, trans_num ctn, sgm_info *si)
{
assert(gtm_white_box_test_case_enabled);
BG_TRACE_PRO(wcb_t_end_sysops_dirtyripwait);
- send_msg(VARLSTCNT(8) ERR_WCBLOCKED, 6,
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_WCBLOCKED, 6,
LEN_AND_LIT("wcb_t_end_sysops_dirtyripwait"),
process_id, &ctn, DB_LEN_STR(gv_cur_region));
return cdb_sc_cacheprob;
@@ -1249,7 +1003,7 @@ enum cdb_sc bg_update_phase1(cw_set_element *cs, trans_num ctn, sgm_info *si)
INCR_BLKS_TO_UPGRD(csa, csd, 1);
break;
default:
- GTMASSERT;
+ assertpro(FALSE);
}
}
assert((gds_t_writemap != mode) || dse_running /* generic dse_running variable is used for caller = dse_maps */
@@ -1405,35 +1159,25 @@ enum cdb_sc bg_update_phase2(cw_set_element *cs, trans_num ctn, trans_num effect
/* Update cr->ondsk_blkver to reflect the current desired_db_format. */
SET_ONDSK_BLKVER(cr, csd, ctn);
# ifdef GTM_SNAPSHOT
- if (SNAPSHOTS_IN_PROG(csa) && (NULL != cs->old_block))
+ if (SNAPSHOTS_IN_PROG(cs_addrs) && (NULL != cs->old_block))
{
lcl_ss_ctx = SS_CTX_CAST(csa->ss_ctx);
assert(lcl_ss_ctx);
- if (FASTINTEG_IN_PROG(lcl_ss_ctx))
+ if (blkid < lcl_ss_ctx->total_blks)
{
- DO_FAST_INTEG_CHECK(blk_ptr, csa, cs, lcl_ss_ctx, blkid, write_to_snapshot_file);
- } else
- write_to_snapshot_file = TRUE;
- if (write_to_snapshot_file)
- WRITE_SNAPSHOT_BLOCK(csa, cr, NULL, blkid, lcl_ss_ctx);
- /* If the block id is greater than the db size at the start of the snapshot, no before image is written by
- * either fast or regular integ
- * If regular MUPIP INTEG is in progress then the current block better be before imaged in the snapshot file.
- * Only exception is when the current block transaction number is greater than or equal to the snapshot
- * transaction number in which case the before image will not be written to the snapshot file.
- * If fast MUPIP INTEG is in progress, we dont write before-image in various cases (e.g. data block in GV tree,
- * or if block was free etc.) even if the block transaction number is less than the snapshot tn. But in those
- * cases write_to_snapshot is set to FALSE. So we can still assert that as long as write_to_snapshot is true,
- * the block must have been before-imaged to the snapshot file.
- */
- assert((blkid >= lcl_ss_ctx->total_blks)
- || !FASTINTEG_IN_PROG(lcl_ss_ctx)
- && (((blk_hdr_ptr_t)blk_ptr)->tn >= lcl_ss_ctx->ss_shm_ptr->ss_info.snapshot_tn)
- || ss_chk_shdw_bitmap(cs_addrs, lcl_ss_ctx, blkid)
- || FASTINTEG_IN_PROG(lcl_ss_ctx)
- && (!write_to_snapshot_file || ss_chk_shdw_bitmap(cs_addrs, lcl_ss_ctx, blkid)));
+ if (FASTINTEG_IN_PROG(lcl_ss_ctx))
+ {
+ DO_FAST_INTEG_CHECK(blk_ptr, csa, cs, lcl_ss_ctx, blkid, write_to_snapshot_file);
+ } else
+ write_to_snapshot_file = TRUE;
+ if (write_to_snapshot_file)
+ WRITE_SNAPSHOT_BLOCK(csa, cr, NULL, blkid, lcl_ss_ctx);
+ assert(!FASTINTEG_IN_PROG(lcl_ss_ctx) || !write_to_snapshot_file
+ || ss_chk_shdw_bitmap(csa, lcl_ss_ctx, blkid));
+ assert(FASTINTEG_IN_PROG(lcl_ss_ctx) || ss_chk_shdw_bitmap(csa, lcl_ss_ctx, blkid)
+ || ((blk_hdr_ptr_t)(blk_ptr))->tn >= lcl_ss_ctx->ss_shm_ptr->ss_info.snapshot_tn);
+ }
}
-
# endif
SET_DATA_INVALID(cr); /* data_invalid should be set signaling intent to update contents of a valid block */
if (gds_t_writemap == mode)
@@ -1544,7 +1288,7 @@ enum cdb_sc bg_update_phase2(cw_set_element *cs, trans_num ctn, trans_num effect
{
assert(gtm_white_box_test_case_enabled);
BG_TRACE_PRO(wcb_bg_update_lckfail1);
- send_msg(VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_LIT("wcb_bg_update_lckfail1"),
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_LIT("wcb_bg_update_lckfail1"),
process_id, &ctn, DB_LEN_STR(gv_cur_region));
return cdb_sc_cacheprob;
}
@@ -1578,7 +1322,7 @@ enum cdb_sc bg_update_phase2(cw_set_element *cs, trans_num ctn, trans_num effect
{
assert(gtm_white_box_test_case_enabled);
BG_TRACE_PRO(wcb_bg_update_lckfail2);
- send_msg(VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_LIT("wcb_bg_update_lckfail2"),
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_LIT("wcb_bg_update_lckfail2"),
process_id, &ctn, DB_LEN_STR(gv_cur_region));
return cdb_sc_cacheprob;
}
@@ -1797,43 +1541,23 @@ void wcs_stale(gd_region *reg)
BG_TRACE_PRO_ANY(csa, stale);
switch (acc_meth)
{
- case dba_bg:
- /* Flush at least some of our cache */
- UNIX_ONLY(wcs_wtstart(reg, 0);)
- VMS_ONLY(wcs_wtstart(reg);)
- /* If there is no dirty buffer left in the active queue, then no need for new timer */
- if (0 == csa->acc_meth.bg.cache_state->cacheq_active.fl)
- need_new_timer = FALSE;
- break;
-
-# if defined(UNIX)
- case dba_mm:
-# if defined(UNTARGETED_MSYNC)
- if (csa->ti->last_mm_sync != csa->ti->curr_tn)
- {
- boolean_t was_crit;
-
- was_crit = csa->now_crit;
- if (FALSE == was_crit)
- grab_crit(reg);
- msync((caddr_t)csa->db_addrs[0], (size_t)(csa->db_addrs[1] - csa->db_addrs[0]),
- MS_SYNC);
- csa->ti->last_mm_sync = csa->ti->curr_tn; /* Save when did last full sync */
- if (FALSE == was_crit)
- rel_crit(reg);
- need_new_timer = FALSE; /* All sync'd up -- don't need another one */
- }
-# else
- /* note that wcs_wtstart is called for TARGETED_MSYNC or FILE_IO */
- wcs_wtstart(reg, 0);
- assert(csd == csa->hdr);
- if (0 == csa->acc_meth.mm.mmblk_state->mmblkq_active.fl)
+ case dba_bg:
+ /* Flush at least some of our cache */
+ UNIX_ONLY(wcs_wtstart(reg, 0);)
+ VMS_ONLY(wcs_wtstart(reg);)
+ /* If there is no dirty buffer left in the active queue, then no need for new timer */
+ if (0 == csa->acc_meth.bg.cache_state->cacheq_active.fl)
+ need_new_timer = FALSE;
+ break;
+# if defined(UNIX)
+ case dba_mm:
+ wcs_wtstart(reg, 0);
+ assert(csd == csa->hdr);
need_new_timer = FALSE;
+ break;
# endif
- break;
-# endif
- default:
- break;
+ default:
+ break;
}
} else
{
diff --git a/sr_port/t_qread.c b/sr_port/t_qread.c
index 20bf234..1678027 100644
--- a/sr_port/t_qread.c
+++ b/sr_port/t_qread.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -95,6 +95,13 @@ GBLREF boolean_t mupip_jnl_recover;
(first_tp_srch_status)->cycle = (newcycle); \
(first_tp_srch_status)->buffaddr = (sm_uc_ptr_t)GDS_REL2ABS((newcr)->buffaddr);
+#define REL_CRIT_IF_NEEDED(CSA, REG, WAS_CRIT, HOLD_ONTO_CRIT) \
+{ /* If currently have crit, but didn't have it upon entering, release crit now. */ \
+ assert(!WAS_CRIT || CSA->now_crit); \
+ if ((WAS_CRIT != CSA->now_crit) && !HOLD_ONTO_CRIT) \
+ rel_crit(REG); \
+}
+
error_def(ERR_BUFOWNERSTUCK);
error_def(ERR_CRYPTBADCONFIG);
error_def(ERR_DBFILERR);
@@ -127,7 +134,9 @@ sm_uc_ptr_t t_qread(block_id blk, sm_int_ptr_t cycle, cache_rec_ptr_ptr_t cr_out
# ifdef GTM_CRYPT
gd_segment *seg;
# endif
+ DCL_THREADGBL_ACCESS;
+ SETUP_THREADGBL_ACCESS;
lcl_blk_free = block_is_free;
block_is_free = FALSE; /* Reset to FALSE so that if t_qread fails below, we don't have an incorrect state of this var */
first_tp_srch_status = NULL;
@@ -273,11 +282,13 @@ sm_uc_ptr_t t_qread(block_id blk, sm_int_ptr_t cycle, cache_rec_ptr_ptr_t cr_out
}
}
}
- if ((blk >= csa->ti->total_blks) || (blk < 0))
- { /* requested block out of range; could occur because of a concurrency conflict */
- if ((&FILE_INFO(gv_cur_region)->s_addrs != csa) || (csd != cs_data))
- GTMASSERT;
- assert(FALSE == csa->now_crit);
+ if ((uint4)blk >= (uint4)csa->ti->total_blks)
+ { /* Requested block out of range; could occur because of a concurrency conflict. mm_read and dsk_read assume blk is
+ * never negative or greater than the maximum possible file size. If a concurrent REORG truncates the file, t_qread
+ * can proceed despite blk being greater than total_blks. But dsk_read handles this fine; see comments below.
+ */
+ assert((&FILE_INFO(gv_cur_region)->s_addrs == csa) && (csd == cs_data));
+ assert(!csa->now_crit);
rdfail_detail = cdb_sc_blknumerr;
return (sm_uc_ptr_t)NULL;
}
@@ -363,7 +374,8 @@ sm_uc_ptr_t t_qread(block_id blk, sm_int_ptr_t cycle, cache_rec_ptr_ptr_t cr_out
assert(0 == cr->dirty);
assert(cr->read_in_progress >= 0);
CR_BUFFER_CHECK(gv_cur_region, csa, csd, cr);
- if (SS_NORMAL != (status = dsk_read(blk, GDS_REL2ABS(cr->buffaddr), &ondsk_blkver, lcl_blk_free)))
+ buffaddr = (sm_uc_ptr_t)GDS_REL2ABS(cr->buffaddr);
+ if (SS_NORMAL != (status = dsk_read(blk, buffaddr, &ondsk_blkver, lcl_blk_free)))
{ /* buffer does not contain valid data, so reset blk to be empty */
cr->cycle++; /* increment cycle for blk number changes (for tp_hist and others) */
cr->blk = CR_BLKEMPTY;
@@ -386,17 +398,22 @@ sm_uc_ptr_t t_qread(block_id blk, sm_int_ptr_t cycle, cache_rec_ptr_ptr_t cr_out
if (was_crit)
{
assert(FALSE);
- rts_error(VARLSTCNT(5) status, 3, blk, DB_LEN_STR(gv_cur_region));
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(5) status, 3, blk,
+ DB_LEN_STR(gv_cur_region));
} else
{
rdfail_detail = cdb_sc_lostcr;
return (sm_uc_ptr_t)NULL;
}
}
- if (-1 == status)
- {
- /* could have been concurrent truncate, and we read a blk >= csa->ti->total_blks */
- /* restart */
+ if ((-1 == status) && !was_crit)
+ { /* LSEEKREAD and, consequently, dsk_read return -1 in case pread is unable to fetch
+ * a full database block's length of data. This can happen if the requested read is
+ * past the end of the file, which can happen if a concurrent truncate occurred
+ * after the blk >= csa->ti->total_blks comparison above. Allow for this scenario
+ * by restarting. However, if we've had crit the whole time, no truncate could have
+ * happened. -1 indicates a problem with the file, so fall through to DBFILERR.
+ */
rdfail_detail = cdb_sc_truncate;
return (sm_uc_ptr_t)NULL;
}
@@ -408,7 +425,18 @@ sm_uc_ptr_t t_qread(block_id blk, sm_int_ptr_t cycle, cache_rec_ptr_ptr_t cr_out
}
# endif
else
- rts_error(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region), status);
+ { /* A DBFILERR can be thrown for two possible reasons:
+ * (1) LSEEKREAD returned an unexpected error due to a filesystem problem; or
+ * (2) csa/cs_addrs/csd/cs_data are out of sync, and we're trying to read a block
+ * number for one region from another region with fewer total_blks.
+ * We suspect the former is what happened in GTM-7623. Apparently the latter
+ * has been an issue before, too. If either occurs again in pro, this assertpro
+ * distinguishes the two possibilities.
+ */
+ assertpro((&FILE_INFO(gv_cur_region)->s_addrs == csa) && (csd == cs_data));
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region),
+ status);
+ }
}
disk_blk_read = TRUE;
assert(0 <= cr->read_in_progress);
@@ -424,7 +452,7 @@ sm_uc_ptr_t t_qread(block_id blk, sm_int_ptr_t cycle, cache_rec_ptr_ptr_t cr_out
{ /* keep the parantheses for the if (although single line) since the following is a macro */
RESET_FIRST_TP_SRCH_STATUS(first_tp_srch_status, cr, *cycle);
}
- return (sm_uc_ptr_t)GDS_REL2ABS(cr->buffaddr);
+ return buffaddr;
} else if (!was_crit && (BAD_LUCK_ABOUNDS > ocnt))
{
assert(!hold_onto_crit);
@@ -484,8 +512,7 @@ sm_uc_ptr_t t_qread(block_id blk, sm_int_ptr_t cycle, cache_rec_ptr_ptr_t cr_out
)
if (cr->blk != blk)
break;
- if ((was_crit != csa->now_crit) && !hold_onto_crit)
- rel_crit(gv_cur_region);
+ REL_CRIT_IF_NEEDED(csa, gv_cur_region, was_crit, hold_onto_crit);
assert(was_crit == csa->now_crit);
/* Check if "cr" is locked for phase2 update by a concurrent process. Before doing so, need to
* do a read memory barrier to ensure we read a consistent state. Otherwise, we could see
@@ -540,10 +567,18 @@ sm_uc_ptr_t t_qread(block_id blk, sm_int_ptr_t cycle, cache_rec_ptr_ptr_t cr_out
blocking_pid = 0; /* do not sleep in the for loop below */
}
}
- if (blocking_pid && !wcs_phase2_commit_wait(csa, cr))
- { /* Timed out waiting for cr->in_tend to become non-zero. Restart. */
- rdfail_detail = cdb_sc_phase2waitfail;
- return NULL;
+ if (blocking_pid)
+ {
+ if (TREF(tqread_nowait) && ((sm_int_ptr_t)&gv_target->hist.h[0].cycle == cycle))
+ { /* We're an update helper. Don't waste time waiting on a leaf blk */
+ rdfail_detail = cdb_sc_tqreadnowait;
+ return (sm_uc_ptr_t)NULL;
+ }
+ if (!wcs_phase2_commit_wait(csa, cr))
+ { /* Timed out waiting for cr->in_tend to become non-zero. Restart. */
+ rdfail_detail = cdb_sc_phase2waitfail;
+ return (sm_uc_ptr_t)NULL;
+ }
}
}
if (reset_first_tp_srch_status)
@@ -596,10 +631,11 @@ sm_uc_ptr_t t_qread(block_id blk, sm_int_ptr_t cycle, cache_rec_ptr_ptr_t cr_out
{
if (!hold_onto_crit)
rel_crit(gv_cur_region);
- send_msg(VARLSTCNT(4) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region));
- send_msg(VARLSTCNT(9) ERR_BUFOWNERSTUCK, 7, process_id, blocking_pid,
- cr->blk, cr->blk, (lcnt / BUF_OWNER_STUCK),
- cr->read_in_progress, cr->rip_latch.u.parts.latch_pid);
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_DBFILERR, 2,
+ DB_LEN_STR(gv_cur_region));
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_BUFOWNERSTUCK, 7, process_id,
+ blocking_pid, cr->blk, cr->blk, (lcnt / BUF_OWNER_STUCK),
+ cr->read_in_progress, cr->rip_latch.u.parts.latch_pid);
stuck_cnt++;
GET_C_STACK_FROM_SCRIPT("BUFOWNERSTUCK", process_id, blocking_pid,
stuck_cnt);
@@ -630,10 +666,15 @@ sm_uc_ptr_t t_qread(block_id blk, sm_int_ptr_t cycle, cache_rec_ptr_ptr_t cr_out
LOCK_BUFF_FOR_READ(cr, dummy);
}
}
- if ((was_crit != csa->now_crit) && !hold_onto_crit)
- rel_crit(gv_cur_region);
+ REL_CRIT_IF_NEEDED(csa, gv_cur_region, was_crit, hold_onto_crit);
} else
{
+ if (TREF(tqread_nowait) && ((sm_int_ptr_t)&gv_target->hist.h[0].cycle == cycle))
+ { /* We're an update helper. Don't waste time waiting on a leaf blk; move on to useful work */
+ REL_CRIT_IF_NEEDED(csa, gv_cur_region, was_crit, hold_onto_crit);
+ rdfail_detail = cdb_sc_tqreadnowait;
+ return (sm_uc_ptr_t)NULL;
+ }
BG_TRACE_PRO_ANY(csa, t_qread_ripsleep_cnt);
if (!sleep_invoked) /* Count # of blks for which we ended up sleeping on the read */
BG_TRACE_PRO_ANY(csa, t_qread_ripsleep_nblks);
@@ -659,8 +700,7 @@ sm_uc_ptr_t t_qread(block_id blk, sm_int_ptr_t cycle, cache_rec_ptr_ptr_t cr_out
} while (TRUE);
assert(set_wc_blocked && (cnl->wc_blocked || !csa->now_crit));
SET_CACHE_FAIL_STATUS(rdfail_detail, csd);
- if ((was_crit != csa->now_crit) && !hold_onto_crit)
- rel_crit(gv_cur_region);
+ REL_CRIT_IF_NEEDED(csa, gv_cur_region, was_crit, hold_onto_crit);
assert(was_crit == csa->now_crit);
return (sm_uc_ptr_t)NULL;
}
diff --git a/sr_port/t_retry.c b/sr_port/t_retry.c
index 3f0f7c1..1a13d4c 100644
--- a/sr_port/t_retry.c
+++ b/sr_port/t_retry.c
@@ -294,7 +294,6 @@ void t_retry(enum cdb_sc failure)
}
# endif
assert(csa->now_crit);
- CHECK_MM_DBFILEXT_REMAP_IF_NEEDED(csa, gv_cur_region);
DEBUG_ONLY(TREF(ok_to_call_wcs_recover) = FALSE;)
csd = cs_data;
if (CDB_STAGNATE == t_tries)
@@ -310,7 +309,6 @@ void t_retry(enum cdb_sc failure)
assert((failure != cdb_sc_helpedout) && (failure != cdb_sc_jnlclose)
&& (failure != cdb_sc_jnlstatemod) && (failure != cdb_sc_bkupss_statemod)
&& (failure != cdb_sc_inhibitkills));
- assert(csa->now_crit);
local_t_tries = t_tries;
if (!csa->hold_onto_crit)
{
@@ -320,24 +318,29 @@ void t_retry(enum cdb_sc failure)
if (NULL == (end = format_targ_key(buff, MAX_ZWR_KEY_SZ, gv_currkey, TRUE)))
end = &buff[MAX_ZWR_KEY_SZ - 1];
if (cdb_sc_gbloflow == failure)
- rts_error(VARLSTCNT(6) ERR_GBLOFLOW, 0, ERR_GVIS, 2, end - buff, buff);
+ {
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_GBLOFLOW, 0, ERR_GVIS, 2, end - buff, buff);
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_GBLOFLOW, 0, ERR_GVIS, 2, end - buff, buff);
+ }
if (IS_DOLLAR_INCREMENT)
{
assert(ERR_GVPUTFAIL == t_err);
t_err = ERR_GVINCRFAIL; /* print more specific error message */
}
- UNIX_ONLY(send_msg(VARLSTCNT(9) t_err, 2, local_t_tries, t_fail_hist,
+ UNIX_ONLY(send_msg_csa(CSA_ARG(csa) VARLSTCNT(9) t_err, 2, local_t_tries, t_fail_hist,
ERR_GVIS, 2, end-buff, buff, ERR_GVFAILCORE));
#ifdef DEBUG
/* Core is not needed. We intentionally create this error. */
if (!gtm_white_box_test_case_enabled)
#endif
UNIX_ONLY(gtm_fork_n_core());
- VMS_ONLY(send_msg(VARLSTCNT(8) t_err, 2, local_t_tries, t_fail_hist,
+ VMS_ONLY(send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) t_err, 2, local_t_tries, t_fail_hist,
ERR_GVIS, 2, end-buff, buff));
- rts_error(VARLSTCNT(8) t_err, 2, local_t_tries, t_fail_hist, ERR_GVIS, 2, end-buff, buff);
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(8) t_err, 2, local_t_tries, t_fail_hist, ERR_GVIS, 2, end-buff,
+ buff);
}
}
+ CHECK_MM_DBFILEXT_REMAP_IF_NEEDED(csa, gv_cur_region);
if ((cdb_sc_blockflush == failure) && !CCP_SEGMENT_STATE(cnl, CCST_MASK_HAVE_DIRTY_BUFFERS))
{
assert(csa->hdr->clustered);
@@ -380,14 +383,14 @@ void t_retry(enum cdb_sc failure)
* KILL. So, assert that kip_csa is still NULL
*/
assert(NULL == kip_csa);
- rts_error(VARLSTCNT(1) ERR_DBROLLEDBACK);
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(1) ERR_DBROLLEDBACK);
}
}
assert(!redo_root_search_done);
if (WANT_REDO_ROOT_SEARCH)
gvcst_redo_root_search();
if (is_updproc)
- rts_error(VARLSTCNT(1) ERR_REPLONLNRLBK);
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(1) ERR_REPLONLNRLBK);
}
# ifdef DEBUG
else
diff --git a/sr_port/tcp_open.c b/sr_port/tcp_open.c
index ed49293..7cf6e49 100644
--- a/sr_port/tcp_open.c
+++ b/sr_port/tcp_open.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -32,11 +32,12 @@
#include <errno.h>
#include "gtm_time.h"
#include "gtm_socket.h"
+#include "gtm_netdb.h"
+#include "gtm_ipv6.h"
#include "gtm_inet.h"
#include "gtm_string.h"
#include "gtm_ctype.h"
#include "gtm_stdio.h"
-#include "gtm_netdb.h"
#include "copy.h"
#include "gt_timer.h"
@@ -62,85 +63,83 @@ const char *hstrerror(int err);
GBLREF tcp_library_struct tcp_routines;
+error_def(ERR_GETADDRINFO);
+error_def(ERR_GETNAMEINFO);
error_def(ERR_INVADDRSPEC);
error_def(ERR_IPADDRREQ);
error_def(ERR_SETSOCKOPTERR);
-error_def(ERR_SOCKINIT);
-error_def(ERR_SYSCALL);
error_def(ERR_SOCKACPT);
+error_def(ERR_SOCKINIT);
error_def(ERR_SOCKLISTEN);
+error_def(ERR_SYSCALL);
error_def(ERR_TEXT);
int tcp_open(char *host, unsigned short port, int4 timeout, boolean_t passive) /* host needs to be NULL terminated */
{
boolean_t no_time_left = FALSE, error_given = FALSE;
char temp_addr[SA_MAXLEN + 1], addr[SA_MAXLEN + 1];
- char *from, *to, *errptr, *temp_ch, *adptr;
+ char *from, *to, *errptr, *temp_ch;
+ char ipname[SA_MAXLEN];
int match, sock, sendbufsize, ii, on = 1, temp_1 = -2;
GTM_SOCKLEN_TYPE size;
int4 rv, msec_timeout;
- struct sockaddr_in sin;
- in_addr_t temp_sin_addr;
+ struct addrinfo *ai_ptr = NULL, *remote_ai_ptr = NULL, *remote_ai_head, hints;
+ char port_buffer[NI_MAXSERV], *brack_pos;
+
+ int host_len, addr_len, port_len;
char msg_buffer[1024];
mstr msg_string;
ABS_TIME cur_time, end_time;
fd_set tcp_fd;
- struct sockaddr_in peer;
+ struct sockaddr_storage peer;
short retry_num;
int save_errno, errlen;
const char *terrptr;
+ int errcode;
+ boolean_t af;
- temp_sin_addr = 0;
msg_string.len = SIZEOF(msg_buffer);
msg_string.addr = msg_buffer;
- memset((char *)&sin, 0, SIZEOF(struct sockaddr_in));
/* ============================= initialize structures ============================== */
if (NULL != host)
{
- temp_ch = host;
- while(ISDIGIT_ASCII(*temp_ch) || ('.' == *temp_ch))
- temp_ch++;
- if ('\0' != *temp_ch)
+ host_len = strlen(host);
+ if ('[' == host[0])
{
- adptr = iotcp_name2ip(host);
- if (NULL == adptr)
+ brack_pos = memchr(host, ']', SA_MAXLEN);
+ if (NULL == brack_pos || (&host[1] == brack_pos))
{
-# if !defined(__hpux) && !defined(__MVS__)
- terrptr = HSTRERROR(h_errno);
- rts_error(VARLSTCNT(6) ERR_INVADDRSPEC, 0, ERR_TEXT, 2, LEN_AND_STR(terrptr));
-# else
- /* Grumble grumble HPUX and z/OS don't have hstrerror() */
- rts_error(VARLSTCNT(1) ERR_INVADDRSPEC);
-# endif
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVADDRSPEC);
+ return -1;
+ }
+ addr_len = brack_pos - &(host[1]);
+ memcpy(addr, &host[1], addr_len);
+ if ('\0' != *(brack_pos + 1))
+ { /* not allowed to have special symbols other than [ and ] */
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVADDRSPEC);
return -1;
}
- SPRINTF(addr, "%s", adptr);
} else
- SPRINTF(addr, "%s", host);
-
- if ((unsigned int)-1 == (temp_sin_addr = tcp_routines.aa_inet_addr(addr)))
- {
- gtm_putmsg(VARLSTCNT(1) ERR_INVADDRSPEC);
- assert(FALSE);
- return -1;
+ { /* IPv4 address only */
+ addr_len = strlen(host);
+ if (0 == addr_len)
+ {
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVADDRSPEC);
+ return -1;
+ }
+ memcpy(addr, &host[0], addr_len);
}
- }
- if (passive)
- /* We can only listen on our own system */
- sin.sin_addr.s_addr = INADDR_ANY;
- else
- {
- if (0 == temp_sin_addr)
- { /* If no address was specified */
- gtm_putmsg(VARLSTCNT(1) ERR_IPADDRREQ);
- assert(FALSE);
+ addr[addr_len] = '\0';
+ CLIENT_HINTS(hints);
+ port_len = 0;
+ I2A(port_buffer, port_len, port);
+ port_buffer[port_len]='\0';
+ if (0 != (errcode = getaddrinfo(addr, port_buffer, &hints, &remote_ai_head)))
+ {
+ RTS_ERROR_ADDRINFO(NULL, ERR_GETADDRINFO, errcode);
return -1;
}
- /* Set where to send the connection attempt */
- sin.sin_addr.s_addr = temp_sin_addr;
}
- sin.sin_port = GTM_HTONS(port);
- sin.sin_family = AF_INET;
/* ============================== do the connection ============================== */
if (passive)
@@ -148,15 +147,31 @@ int tcp_open(char *host, unsigned short port, int4 timeout, boolean_t passive) /
struct timeval utimeout, save_utimeout;
int lsock;
- lsock = tcp_routines.aa_socket(AF_INET, SOCK_STREAM, 0);
+ af = ((GTM_IPV6_SUPPORTED && !ipv4_only) ? AF_INET6 : AF_INET);
+ lsock = tcp_routines.aa_socket(af, SOCK_STREAM, IPPROTO_TCP);
if (-1 == lsock)
{
- save_errno = errno;
- errptr = (char *)STRERROR(save_errno);
- errlen = STRLEN(errptr);
- gtm_putmsg(VARLSTCNT(5) ERR_SOCKINIT, 3, save_errno, errlen, errptr);
- assert(FALSE);
+ af = AF_INET;
+ if (-1 == (lsock = tcp_routines.aa_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)))
+ {
+ save_errno = errno;
+ errptr = (char *)STRERROR(save_errno);
+ errlen = STRLEN(errptr);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, save_errno, errlen, errptr);
+ assert(FALSE);
+ return -1;
+ }
+ }
+ SERVER_HINTS(hints, af);
+ /* We can only listen on our own system */
+ port_len = 0;
+ I2A(port_buffer, port_len, port);
+ port_buffer[port_len]='\0';
+ if (0 != (errcode = getaddrinfo(NULL, port_buffer, &hints, &ai_ptr)))
+ {
+ RTS_ERROR_ADDRINFO(NULL, ERR_GETADDRINFO, errcode);
return -1;
+
}
/* allow multiple connections to the same IP address */
if (-1 == tcp_routines.aa_setsockopt(lsock, SOL_SOCKET, SO_REUSEADDR, &on, SIZEOF(on)))
@@ -165,19 +180,20 @@ int tcp_open(char *host, unsigned short port, int4 timeout, boolean_t passive) /
(void)tcp_routines.aa_close(lsock);
errptr = (char *)STRERROR(save_errno);
errlen = STRLEN(errptr);
- gtm_putmsg(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5,
- RTS_ERROR_LITERAL("SO_REUSEADDR"), save_errno, errlen, errptr);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5,
+ LEN_AND_LIT("SO_REUSEADDR"), save_errno, errlen, errptr);
assert(FALSE);
return -1;
}
- if (-1 == tcp_routines.aa_bind(lsock, (struct sockaddr *)&sin, SIZEOF(struct sockaddr)))
+ if (-1 == tcp_routines.aa_bind(lsock, ai_ptr->ai_addr, ai_ptr->ai_addrlen))
{
save_errno = errno;
(void)tcp_routines.aa_close(lsock);
- gtm_putmsg(VARLSTCNT(8) ERR_SYSCALL, 5,
- RTS_ERROR_LITERAL("bind()"), CALLFROM, save_errno);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5,
+ LEN_AND_LIT("bind()"), CALLFROM, save_errno);
return -1;
}
+ freeaddrinfo(ai_ptr);
/* establish a queue of length MAX_CONN_PENDING for incoming connections */
if (-1 == tcp_routines.aa_listen(lsock, MAX_CONN_PENDING))
{
@@ -185,7 +201,7 @@ int tcp_open(char *host, unsigned short port, int4 timeout, boolean_t passive) /
(void)tcp_routines.aa_close(lsock);
errptr = (char *)STRERROR(save_errno);
errlen = STRLEN(errptr);
- gtm_putmsg(VARLSTCNT(6) ERR_SOCKLISTEN, 0, ERR_TEXT, 2, errlen, errptr);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_SOCKLISTEN, 0, ERR_TEXT, 2, errlen, errptr);
assert(FALSE);
return -1;
}
@@ -197,15 +213,14 @@ int tcp_open(char *host, unsigned short port, int4 timeout, boolean_t passive) /
utimeout.tv_sec = timeout;
utimeout.tv_usec = 0;
}
- while(1)
+ FD_ZERO(&tcp_fd);
+ while (TRUE)
{
- while(1)
+ while (TRUE)
{
- /*
- * the check for EINTR below is valid and should not be converted to an EINTR
- * wrapper macro, since it might be a timeout.
+ /* The check for EINTR below is valid and should not be converted to an EINTR wrapper macro
+ * since it might be a timeout.
*/
- FD_ZERO(&tcp_fd);
FD_SET(lsock, &tcp_fd);
save_utimeout = utimeout;
rv = tcp_routines.aa_select(lsock + 1, (void *)&tcp_fd, (void *)0, (void *)0,
@@ -234,110 +249,46 @@ int tcp_open(char *host, unsigned short port, int4 timeout, boolean_t passive) /
} else if (0 > rv)
{
(void)tcp_routines.aa_close(lsock);
- gtm_putmsg(VARLSTCNT(8) ERR_SYSCALL, 5,
- RTS_ERROR_LITERAL("select()"), CALLFROM, save_errno);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5,
+ LEN_AND_LIT("select()"), CALLFROM, save_errno);
assert(FALSE);
return -1;
}
- size = SIZEOF(struct sockaddr_in);
- sock = tcp_routines.aa_accept(lsock, &peer, &size);
- save_errno = errno;
- if (-1 == sock)
+ size = SIZEOF(struct sockaddr_storage);
+ sock = tcp_routines.aa_accept(lsock, (struct sockaddr*)(&peer), &size);
+ if (FD_INVALID == sock)
{
+ save_errno = errno;
# ifdef __hpux
- /* ENOBUFS in HP-UX is either because of a memory problem or when we have received a RST just
- * after a SYN before an accept call. Normally this is not fatal and is just a transient state.
- * Hence exiting just after a single error of this kind should not be done. So retry in case
- * of HP-UX and ENOBUFS error.
- */
if (ENOBUFS == save_errno)
- {
- retry_num = 0;
- while (HPUX_MAX_RETRIES > retry_num)
- { /* In case of succeeding with select in first go, accept will still get 5ms time
- * difference.
- */
- SHORT_SLEEP(5);
- for ( ; HPUX_MAX_RETRIES > retry_num; retry_num++)
- {
- utimeout.tv_sec = 0;
- utimeout.tv_usec = HPUX_SEL_TIMEOUT;
- FD_ZERO(&tcp_fd);
- FD_SET(lsock, &tcp_fd);
- rv = tcp_routines.aa_select(lsock + 1, (void *)&tcp_fd, (void *)0,
- (void *)0, &utimeout);
- save_errno = errno;
- if (0 < rv)
- break;
- else
- SHORT_SLEEP(5);
- }
- if (0 > rv)
- {
- (void)tcp_routines.aa_close(lsock);
- gtm_putmsg(VARLSTCNT(8) ERR_SYSCALL, 5,
- RTS_ERROR_LITERAL("select()"),
- CALLFROM, save_errno);
- assert(FALSE);
- return -1;
- }
- if (0 == rv)
- {
- (void)tcp_routines.aa_close(lsock);
- util_out_print("Select timed out.\n", TRUE);
- assert(FALSE);
- return -1;
- }
- sock = tcp_routines.aa_accept(lsock, &peer, &size);
- save_errno = errno;
- if ((-1 == sock) && (ENOBUFS == save_errno))
- retry_num++;
- else
- break;
- }
- }
- if (-1 == sock)
+ continue;
# endif
- {
- (void)tcp_routines.aa_close(lsock);
- errptr = (char *)STRERROR(save_errno);
- errlen = STRLEN(errptr);
- gtm_putmsg(VARLSTCNT(6) ERR_SOCKACPT, 0, ERR_TEXT, 2, errlen, errptr);
- assert(FALSE);
- return -1;
- }
+ (void)tcp_routines.aa_close(lsock);
+ errptr = (char *)STRERROR(save_errno);
+ errlen = STRLEN(errptr);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_SOCKACPT, 0, ERR_TEXT, 2, errlen, errptr);
+ assert(FALSE);
+ return -1;
+ }
+ GETNAMEINFO((struct sockaddr*)(&peer), size, temp_addr, SA_MAXLEN + 1, NULL, 0, NI_NUMERICHOST, errcode);
+ if (0 != errcode)
+ {
+ RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode);
+ return -1;
}
- SPRINTF(&temp_addr[0], "%s", tcp_routines.aa_inet_ntoa(peer.sin_addr));
# ifdef DEBUG_ONLINE
PRINTF("Connection is from : %s\n", &temp_addr[0]);
# endif
- /* Check if connection is from whom we want it to be from. Note that this is not a robust check
- (potential for multiple IP addrs for a resolved name but workarounds for this exist so not a lot
- of effort has been expended here at this time. Especially since the check is easily spoofed with
- raw sockets anyway. It is more for the accidental "oops" type check than serious security..
- */
- if ((0 == temp_sin_addr) || (0 == memcmp(&addr[0], &temp_addr[0], strlen(addr))))
- break;
- else
- { /* Connection not from expected host */
- (void)tcp_routines.aa_close(sock);
- if (NO_M_TIMEOUT != timeout)
- {
- sys_get_curr_time(&cur_time);
- cur_time = sub_abs_time(&end_time, &cur_time);
- utimeout.tv_sec = ((cur_time.at_sec > 0) ? cur_time.at_sec : 0);
- }
- if (!error_given)
- {
- util_out_print("Connection from !AD rejected and ignored (expected from !AD)", TRUE,
- LEN_AND_STR(&temp_addr[0]), LEN_AND_STR(&addr[0]));
- error_given = TRUE;
- }
- }
+ break;
+ /* previously there is following check here
+ * if ((0 == temp_sin_addr) || (0 == memcmp(&addr[0], &temp_addr[0], strlen(addr))))
+ * However, temp_sin_addr is always 0 on server side, and addr(local address) shoud not equal to
+ * temp_addr(remote address), so the entire check should be removed
+ */
}
(void)tcp_routines.aa_close(lsock);
} else
- {
+ { /* client side (connection side) */
if (NO_M_TIMEOUT != timeout)
{
msec_timeout = timeout2msec(timeout);
@@ -350,47 +301,44 @@ int tcp_open(char *host, unsigned short port, int4 timeout, boolean_t passive) /
{
if (1 != temp_1)
tcp_routines.aa_close(sock);
- sock = tcp_routines.aa_socket(AF_INET, SOCK_STREAM, 0);
- if (-1 == sock)
+ assert(NULL != remote_ai_head);
+ for (remote_ai_ptr = remote_ai_head; NULL != remote_ai_ptr; remote_ai_ptr = remote_ai_ptr->ai_next)
+ {
+ sock = tcp_routines.aa_socket(remote_ai_ptr->ai_family, remote_ai_ptr->ai_socktype,
+ remote_ai_ptr->ai_protocol);
+ if (FD_INVALID != sock)
+ break;
+ }
+ if (FD_INVALID == sock)
{
save_errno = errno;
errptr = (char *)STRERROR(save_errno);
errlen = STRLEN(errptr);
- gtm_putmsg(VARLSTCNT(5) ERR_SOCKINIT, 3, save_errno, errlen, errptr);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SOCKINIT, 3, save_errno, errlen, errptr);
assert(FALSE);
return -1;
}
/* Allow multiple connections to the same IP address */
- if (-1 == tcp_routines.aa_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, SIZEOF(on)))
+ if (-1 == tcp_routines.aa_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, SIZEOF(on)))
{
save_errno = errno;
(void)tcp_routines.aa_close(sock);
errptr = (char *)STRERROR(save_errno);
errlen = STRLEN(errptr);
- gtm_putmsg(VARLSTCNT(7) ERR_SETSOCKOPTERR, 5,
- RTS_ERROR_LITERAL("SO_REUSEADDR"), save_errno, errlen, errptr);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_SETSOCKOPTERR, 5,
+ LEN_AND_LIT("SO_REUSEADDR"), save_errno, errlen, errptr);
assert(FALSE);
return -1;
}
- temp_1 = tcp_routines.aa_connect(sock, (struct sockaddr *)(&sin), SIZEOF(sin));
+ temp_1 = tcp_routines.aa_connect(sock, remote_ai_ptr->ai_addr, remote_ai_ptr->ai_addrlen);
save_errno = errno;
- /*
- * the check for EINTR below is valid and should not be converted to an EINTR
- * wrapper macro, because other error conditions are checked, and a retry is not
- * immediately performed.
- */
- if ((0 > temp_1) && (ECONNREFUSED != save_errno) && (EINTR != save_errno))
- {
- (void)tcp_routines.aa_close(sock);
- gtm_putmsg(VARLSTCNT(8) ERR_SYSCALL, 5,
- RTS_ERROR_LITERAL("connect()"), CALLFROM, save_errno);
- assert(FALSE);
- return -1;
- }
- if ((0 > temp_1) && (EINTR == save_errno))
+ /* tcp_routines.aa_connect == gtm_connect should have handled EINTR. Assert that */
+ assert((0 <= temp_1) || (EINTR != save_errno));
+ if ((0 > temp_1) && (ECONNREFUSED != save_errno))
{
(void)tcp_routines.aa_close(sock);
- util_out_print("Interrupted.", TRUE);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5,
+ LEN_AND_LIT("connect()"), CALLFROM, save_errno);
assert(FALSE);
return -1;
}
@@ -404,6 +352,7 @@ int tcp_open(char *host, unsigned short port, int4 timeout, boolean_t passive) /
SHORT_SLEEP(NAP_LENGTH); /* Sleep for NAP_LENGTH ms */
} while ((FALSE == no_time_left) && (0 > temp_1));
+ freeaddrinfo(remote_ai_head);
if (0 > temp_1) /* out of time */
{
tcp_routines.aa_close(sock);
diff --git a/sr_port/tp.h b/sr_port/tp.h
index d90cf52..d0681f4 100644
--- a/sr_port/tp.h
+++ b/sr_port/tp.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -160,15 +160,25 @@ typedef struct sgm_info_struct
uint4 tot_jrec_size; /* maximum journal space needs for this transaction */
} sgm_info;
+/* Define macros to reflect the size of cw_index and next_off in the off_chain structure.
+ * If the structure layout changes, these formulas might need corresponding adjustment.
+ * Note that ideally we should be using SIZEOF(off_chain) * 8 instead of 32 in the NEXT_OFF_MAX_BITS definition
+ * (currently commented due to a gengtmdeftypes issue). But that introduces a cyclic dependency causing a compiler error.
+ */
+#define CW_INDEX_MAX_BITS 15
+/* Remove the next line and uncomment the following line once gengtmdeftypes is fixed to allow expressions in bitfield members */
+#define NEXT_OFF_MAX_BITS 16
+/* #define NEXT_OFF_MAX_BITS (32 - CW_INDEX_MAX_BITS - 1) */
+
typedef struct
{
#ifdef BIGENDIAN
unsigned flag : 1;
- unsigned cw_index : 15;
- unsigned next_off : 16;
+ unsigned cw_index : CW_INDEX_MAX_BITS;
+ unsigned next_off : NEXT_OFF_MAX_BITS;
#else
- unsigned next_off : 16;
- unsigned cw_index : 15;
+ unsigned next_off : NEXT_OFF_MAX_BITS;
+ unsigned cw_index : CW_INDEX_MAX_BITS;
unsigned flag : 1;
#endif
} off_chain;
@@ -374,6 +384,7 @@ GBLREF trans_num tp_fail_histtn[], tp_fail_bttn[];
typedef struct trans_restart_hist_struct
{
uint4 t_tries;
+ uint4 dollar_tlevel;
enum cdb_sc retry_code;
caddr_t call_from;
union
@@ -400,6 +411,7 @@ typedef struct trans_restart_hist_struct
curidx = TREF(trans_restart_hist_index) = 0; \
this_restart_hist = (TADR(trans_restart_hist_array) + curidx); \
this_restart_hist->t_tries = t_tries; \
+ this_restart_hist->dollar_tlevel = dollar_tlevel; \
this_restart_hist->retry_code = RETRY_CODE; \
this_restart_hist->call_from = (caddr_t)caller_id(); \
if (NULL != jnlpool.jnlpool_ctl) \
@@ -804,9 +816,9 @@ typedef struct trans_restart_hist_struct
code in mdb_condition_handler). The number of extra parameters need to be 2 more than the largest
number of parameters for an rts_error in tp_restart().
*/
-#define INVOKE_RESTART rts_error(VARLSTCNT(6) ERR_TPRETRY, 4, 0, 0, 0, 0, 0, 0, 0, 0);
+#define INVOKE_RESTART rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TPRETRY, 4, 0, 0, 0, 0, 0, 0, 0, 0);
#else
-#define INVOKE_RESTART rts_error(VARLSTCNT(1) ERR_TPRETRY);
+#define INVOKE_RESTART rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_TPRETRY);
#endif
/* the following macros T_BEGIN_READ_NONTP_OR_TP and T_BEGIN_SETORKILL_NONTP_OR_TP are similar except for one difference
@@ -910,7 +922,8 @@ GBLREF unsigned int t_tries;
assert(!mupip_jnl_recover); \
TP_FINAL_RETRY_DECREMENT_T_TRIES_IF_OK; \
getzposition(&zpos); \
- send_msg(VARLSTCNT(6) ERR_TPNOTACID, 4, LEN_AND_LIT(CALLER_STR), zpos.str.len, zpos.str.addr); \
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_TPNOTACID, 4, LEN_AND_LIT(CALLER_STR), zpos.str.len, \
+ zpos.str.addr); \
} \
}
diff --git a/sr_port/tp_clean_up.c b/sr_port/tp_clean_up.c
index 06934c1..140aae5 100644
--- a/sr_port/tp_clean_up.c
+++ b/sr_port/tp_clean_up.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -180,9 +180,14 @@ void tp_clean_up(boolean_t rollback_flag)
}
# endif
local_tn++; /* to effectively invalidate first_tp_srch_status of all gv_targets */
+ tp_allocation_clue = gtm_tp_allocation_clue; /* Reset clue to what it was at beginning of transaction */
} else
{
GTMTRIG_ONLY(TP_INVALIDATE_TRIGGER_CYCLES_IF_NEEDED(FALSE, TRUE));
+ gtm_tp_allocation_clue = tp_allocation_clue; /* Update tp allocation clue for next transaction to skip
+ * past values used in this transaction now that this one
+ * is successfully committed.
+ */
}
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*/
@@ -289,7 +294,7 @@ void tp_clean_up(boolean_t rollback_flag)
}
} else
{
- t1->buffaddr = cs_addrs->acc_meth.mm.base_addr
+ t1->buffaddr = MM_BASE_ADDR(cs_addrs)
+ (sm_off_t)cs_data->blk_size * cseblk;
assert(NULL == t1->cr);
}
@@ -306,8 +311,7 @@ void tp_clean_up(boolean_t rollback_flag)
blk_target->root = cseblk;
t1->blk_num = cseblk;
if (is_mm)
- t1->buffaddr =
- cs_addrs->acc_meth.mm.base_addr
+ t1->buffaddr = MM_BASE_ADDR(cs_addrs)
+ (sm_off_t)cs_data->blk_size * cseblk;
else
{
@@ -425,7 +429,6 @@ void tp_clean_up(boolean_t rollback_flag)
CWS_RESET; /* reinitialize the hashtable before restarting/committing the TP transaction */
} /* if (any database work in the transaction) */
VMS_ONLY(tp_has_kill_t_cse = FALSE;)
- tp_allocation_clue = gtm_tp_allocation_clue + 1;
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
diff --git a/sr_port/tp_cw_list.c b/sr_port/tp_cw_list.c
index 7122257..26985c6 100644
--- a/sr_port/tp_cw_list.c
+++ b/sr_port/tp_cw_list.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -32,23 +32,26 @@ GBLREF sgmnt_addrs *cs_addrs;
GBLREF boolean_t is_updproc;
GBLREF boolean_t mupip_jnl_recover;
+error_def(ERR_TRANS2BIG);
+
void tp_cw_list(cw_set_element **cs)
{
- cw_set_element *last_cse, *tempcs, *prev_last;
-
- error_def(ERR_TRANS2BIG);
+ cw_set_element *last_cse, *tempcs, *prev_last;
+ boolean_t is_bg;
+ sgmnt_data_ptr_t csd;
/* Don't allow a single transaction to use more cw_set_elements than half of the global buffers or
- * more than 32K cw_set_elements. This because the "cw_index" field in "off_chain" structure is 15-bits.
+ * more than 32K cw_set_elements. This because the "cw_index" field in "off_chain" structure is CW_INDEX_MAX_BITS-bits.
*/
- if (dba_bg == cs_addrs->hdr->acc_meth)
- if (sgm_info_ptr->cw_set_depth + 2 >= (cs_addrs->hdr->n_bts >> 1) ||
- sgm_info_ptr->cw_set_depth + 2 > (32 * 1024))
- { /* catch the case where MUPIP recover or update process gets into this situation */
- assert(!mupip_jnl_recover && !is_updproc);
- rts_error(VARLSTCNT(4) ERR_TRANS2BIG, 2, REG_LEN_STR(gv_cur_region));
- }
-
+ csd = cs_addrs->hdr;
+ is_bg = (dba_bg == csd->acc_meth);
+ assert(is_bg || (dba_mm == csd->acc_meth));
+ if ((sgm_info_ptr->cw_set_depth + 2 > (1 << CW_INDEX_MAX_BITS))
+ || (is_bg && ((sgm_info_ptr->cw_set_depth + 2) >= (csd->n_bts >> 1))))
+ { /* catch the case where MUPIP recover or update process gets into this situation */
+ assert(!mupip_jnl_recover && !is_updproc);
+ rts_error(VARLSTCNT(4) ERR_TRANS2BIG, 2, REG_LEN_STR(gv_cur_region));
+ }
tempcs = (cw_set_element *)get_new_element(sgm_info_ptr->cw_set_list, 1);
/* secshr_db_clnup relies on the cw_set_element (specifically the "mode" field) being initialized to a value
* that is not "gds_t_committed". This needs to be done before setting sgm_info_ptr->first_cw_set. */
diff --git a/sr_port/tp_grab_crit.h b/sr_port/tp_grab_crit.h
deleted file mode 100644
index efa4c31..0000000
--- a/sr_port/tp_grab_crit.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/****************************************************************
- * *
- * Copyright 2001 Sanchez Computer Associates, Inc. *
- * *
- * This source code contains the intellectual property *
- * of its copyright holder(s), and is made available *
- * under a license. If you do not know the terms of *
- * the license, please stop and do not read further. *
- * *
- ****************************************************************/
-
-#ifndef __TP_GRAP_CRIT_H__
-#define __TP_GRAP_CRIT_H__
-
-bool tp_grab_crit(gd_region *reg);
-
-#endif
diff --git a/sr_port/tp_hist.c b/sr_port/tp_hist.c
index 146d65f..963118e 100644
--- a/sr_port/tp_hist.c
+++ b/sr_port/tp_hist.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -35,7 +35,6 @@
#ifdef UNIX
#include "repl_msg.h" /* needed for gtmsource.h */
#include "gtmsource.h" /* needed for SYNC_ONLN_RLBK_CYCLES */
-#include "tp_grab_crit.h"
#endif
#define REPOSITION_PTR(ptr, type, delta, begin, end) \
@@ -343,7 +342,8 @@ enum cdb_sc tp_hist(srch_hist *hist1)
delete_hashtab_int4(si->blks_in_use,(uint4 *)&blk);
si->num_of_blks--;
assert(si->num_of_blks == si->tp_hist_size);
- rts_error(VARLSTCNT(4) ERR_TRANS2BIG, 2, REG_LEN_STR(gv_cur_region));
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_TRANS2BIG, 2,
+ REG_LEN_STR(gv_cur_region));
}
/* Either history has a clue or not.
* If yes, then it could have been constructed in an earlier
@@ -447,8 +447,8 @@ enum cdb_sc tp_hist(srch_hist *hist1)
# ifdef UNIX
if (MISMATCH_ROOT_CYCLES(csa, csa->nl))
{ /* We want to sync the online rollback cycles ONLY under crit. So, grab_crit and sync the
- * cycles. While tp_grab_crit would have been a better choice, the reason we don't use
- * tp_grab_crit here is because if we don't sync cycles because we don't hold crit but
+ * cycles. While grab_crit_immediate would have been a better choice, the reason we don't use
+ * grab_crit_immediate here is because if we don't sync cycles because we don't hold crit but
* do invoke t_retry which increments $zonlnrlbk and on the subsequent retry we remain
* unlucky in getting crit, we will end up incrementing $zonlnrlbk more than once for a
* single online rollback event. In the worst case we will have $zonlnrlbk=3 which from
diff --git a/sr_port/tp_restart.c b/sr_port/tp_restart.c
index df40960..140aad3 100644
--- a/sr_port/tp_restart.c
+++ b/sr_port/tp_restart.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -118,7 +118,6 @@ error_def(ERR_REPLONLNRLBK);
#endif
error_def(ERR_TLVLZERO);
error_def(ERR_TPFAIL);
-error_def(ERR_TPLOCKRESTMAX);
error_def(ERR_TPRESTART);
error_def(ERR_TPRETRY);
error_def(ERR_TRESTLOC);
@@ -682,8 +681,8 @@ int tp_restart(int newlevel, boolean_t handle_errors_internally)
* this frame, op_xnew creates a NEW symtab just for this frame. But when this code
* unwound back to the TSTART, we also unwound the l_symtab this frame was using. So here
* we verify this frame is a simple call frame from the previous and restore the use of its
- * l_symtab if so. If not, GTMASSERT. Note the outer SFF_UWN_SYMVAL check keeps us from having
- * non-existant l_symtab issues which is possible when we are MUPIP.
+ * l_symtab if so. If not, assertpro/GTMASSERT2. Note the outer SFF_UWN_SYMVAL check keeps
+ * us from having non-existant l_symtab issues which is possible when we are MUPIP.
*/
if ((frame_pointer->rvector == frame_pointer->old_frame_pointer->rvector)
&& (frame_pointer->vartab_ptr == frame_pointer->old_frame_pointer->vartab_ptr))
@@ -691,7 +690,7 @@ int tp_restart(int newlevel, boolean_t handle_errors_internally)
frame_pointer->l_symtab = frame_pointer->old_frame_pointer->l_symtab;
frame_pointer->flags &= SFF_UNW_SYMVAL_OFF; /* No need to clear symtab now */
} else
- GTMASSERT;
+ assertpro(FALSE);
} else
{ /* Otherwise the l_symtab needs to be cleared so its references get re-resolved to *this* symtab */
memset(frame_pointer->l_symtab, 0, frame_pointer->vartab_len * SIZEOF(ht_ent_mname *));
diff --git a/sr_port/tp_set_sgm.c b/sr_port/tp_set_sgm.c
index 8a63375..6a3f0c6 100644
--- a/sr_port/tp_set_sgm.c
+++ b/sr_port/tp_set_sgm.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -39,6 +39,8 @@ GBLREF gd_region *gv_cur_region;
GBLREF sgmnt_addrs *cs_addrs;
GBLREF sgmnt_data_ptr_t cs_data;
+error_def(ERR_MMREGNOACCESS);
+
void tp_set_sgm(void)
{
sgm_info *si;
@@ -49,6 +51,9 @@ void tp_set_sgm(void)
si = csa->sgm_info_ptr;
assert(si->tp_csa == csa);
assert(si->tp_csd == cs_data);
+ assert(csa->hdr == cs_data);
+ if ((NULL == csa->db_addrs[0]) && (dba_mm == cs_data->acc_meth))
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_MMREGNOACCESS, 4, REG_LEN_STR(csa->region), DB_LEN_STR(csa->region));
if (!si->tp_set_sgm_done)
{
si->next_sgm_info = first_sgm_info;
diff --git a/sr_port/tp_tend.c b/sr_port/tp_tend.c
index 1539729..99182d8 100644
--- a/sr_port/tp_tend.c
+++ b/sr_port/tp_tend.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -319,6 +319,7 @@ boolean_t tp_tend()
csa = cs_addrs;
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));
@@ -327,11 +328,10 @@ boolean_t tp_tend()
sgm_info_ptr = si;
*prev_tp_si_by_ftok = si;
prev_tp_si_by_ftok = &si->next_tp_si_by_ftok;
- if ((cnl->wc_blocked) || /* If blocked, or.. */
- ((dba_mm == csd->acc_meth) && /* we have MM and.. */
- (csa->total_blks != csd->trans_hist.total_blks))) /* and file has been extended */
- { /* Force repair */
+ if ((cnl->wc_blocked) || (is_mm && (csa->total_blks != csd->trans_hist.total_blks)))
+ { /* If blocked, or we have MM and file has been extended, force repair */
status = cdb_sc_helpedout; /* special status to prevent punishing altruism */
+ assert((CDB_STAGNATE > t_tries) || !is_mm || (csa->total_blks == csd->trans_hist.total_blks));
TP_TRACE_HIST(CR_BLKEMPTY, NULL);
goto failed_skip_revert;
}
@@ -340,8 +340,8 @@ boolean_t tp_tend()
* (b) If we are in the final retry and we don't hold crit on some region.
* (c) If we are in the final retry and we hold crit on a frozen region that we want to update.
* This is possible if:
- * (1) We did a tp_grab_crit through one of the gvcst_* routines when we first encountered the region
- * in the TP transaction and it wasn't locked down although it was frozen then.
+ * (1) We did a grab_crit_immediate() through one of the gvcst_* routines when we first encountered the
+ * region in the TP transaction and it wasn't locked down although it was frozen then.
* (2) tp_crit_all_regions notices that at least one of the participating regions did ONLY READs, it
* will not wait for any freeze on THAT region to complete before grabbing crit. Later, in the
* final retry, if THAT region did an update which caused op_tcommit to invoke bm_getfree ->
@@ -363,7 +363,7 @@ boolean_t tp_tend()
: (!csa->now_crit || region_is_frozen))
{
assert(!csa->hold_onto_crit);
- send_msg(VARLSTCNT(8) ERR_DLCKAVOIDANCE, 6, DB_LEN_STR(tr->reg),
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_DLCKAVOIDANCE, 6, DB_LEN_STR(tr->reg),
&csd->trans_hist.curr_tn, t_tries, dollar_trestart, csa->now_crit);
/* The only possible case we know of is (c). assert to that effect. Use local variable region_is_frozen
* instead of csd->freeze as it could be concurrently changed even though we hold crit (freeze holding
@@ -399,7 +399,6 @@ boolean_t tp_tend()
} else
{
do_validation = TRUE;
- is_mm = (dba_mm == cs_data->acc_meth);
/* We are still out of crit if this is not our last attempt. If so, run the region list and check
* that we have sufficient free blocks for our update. If not, get them now while we can.
* We will repeat this check later in crit but it will hopefully have little or nothing to do.
@@ -418,7 +417,7 @@ boolean_t tp_tend()
/* check if current TP transaction's jnl size needs are greater than max jnl file size */
if (si->tot_jrec_size > csd->autoswitchlimit)
/* can't fit in current transaction's journal records into one journal file */
- rts_error(VARLSTCNT(6) ERR_JNLTRANS2BIG, 4, si->tot_jrec_size,
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_JNLTRANS2BIG, 4, si->tot_jrec_size,
JNL_LEN_STR(csd), csd->autoswitchlimit);
}
if (REPL_ALLOWED(csa))
@@ -453,7 +452,8 @@ boolean_t tp_tend()
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(VARLSTCNT(4) ERR_REPLOFFJNLON, 2, DB_LEN_STR(save_gv_cur_region));
+ rts_error_csa(CSA_ARG(REG2CSA(save_gv_cur_region)) VARLSTCNT(4) ERR_REPLOFFJNLON, 2,
+ DB_LEN_STR(save_gv_cur_region));
}
if (!do_validation)
{
@@ -507,7 +507,7 @@ boolean_t tp_tend()
* file being operated on, the obtains will always occurr in a consistent manner. Therefore, we
* will grab crit on each file with wait since deadlock should not be able to occurr.
*/
- ESTABLISH_RET(t_ch, FALSE);
+ ESTABLISH_NOUNWIND(t_ch); /* avoid hefty setjmp call, which is ok since we never unwind t_ch */
for (lcnt = 0; ; lcnt++)
{
x_lock = TRUE; /* Assume success */
@@ -747,17 +747,17 @@ boolean_t tp_tend()
ctn = csd->trans_hist.curr_tn;
assert(csd->trans_hist.early_tn == ctn);
if (SS_NORMAL != jpc->status)
- rts_error(VARLSTCNT(7) jnl_status, 4, JNL_LEN_STR(csd),
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(7) jnl_status, 4, JNL_LEN_STR(csd),
DB_LEN_STR(gv_cur_region), jpc->status);
else
- rts_error(VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd),
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd),
DB_LEN_STR(gv_cur_region));
}
if (DISK_BLOCKS_SUM(jbp->freeaddr, si->total_jnl_rec_size) > jbp->filesize)
{ /* Moved here to prevent jnlrecs split across multiple generation journal files. */
if (SS_NORMAL != (jnl_status = jnl_flush(jpc->region)))
{
- send_msg(VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(csd),
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(csd),
ERR_TEXT, 2, RTS_ERROR_TEXT("Error with journal flush in tp_tend"),
jnl_status);
assert((!JNL_ENABLED(csd)) && JNL_ENABLED(csa));
@@ -1245,7 +1245,7 @@ boolean_t tp_tend()
jpl = jnlpool_ctl;
tjpl = temp_jnlpool_ctl;
if (!repl_csa->hold_onto_crit)
- grab_lock(jnlpool.jnlpool_dummy_reg, ASSERT_NO_ONLINE_ROLLBACK);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK);
# ifdef UNIX
if (jnlpool.jnlpool_ctl->freeze)
{
diff --git a/sr_port/tp_timeout.c b/sr_port/tp_timeout.c
index fda77ae..20d2999 100644
--- a/sr_port/tp_timeout.c
+++ b/sr_port/tp_timeout.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -86,7 +86,7 @@
char asccurtime[10]; \
size_t len; \
now = time(NULL); \
- tm_struct = localtime(&now); \
+ GTM_LOCALTIME(tm_struct, &now); \
STRFTIME(asccurtime, SIZEOF(asccurtime), TIME_EXT_FMT, tm_struct, len); \
DBGTPTDFRL(x); \
}
diff --git a/sr_port/tp_unwind.c b/sr_port/tp_unwind.c
index 663f19f..8e426ff 100644
--- a/sr_port/tp_unwind.c
+++ b/sr_port/tp_unwind.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -41,11 +41,17 @@
#include "tp.h"
#include "tp_restart.h"
#ifdef UNIX
-#include "deferred_signal_handler.h"
+# include "deferred_signal_handler.h"
#endif
#ifdef GTM_TRIGGER
-#include "gv_trigger.h"
-#include "gtm_trigger.h"
+# include "gv_trigger.h"
+# include "gtm_trigger.h"
+# include "gt_timer.h"
+# include "wbox_test_init.h"
+#endif
+#ifdef DEBUG
+# include "gtmio.h"
+# include "gtm_stdio.h"
#endif
GBLREF stack_frame *frame_pointer;
@@ -56,10 +62,36 @@ GBLREF unsigned char *tp_sp, *tpstackbase, *tpstacktop;
GBLREF mlk_pvtblk *mlk_pvt_root;
GBLREF uint4 dollar_tlevel;
GBLREF symval *curr_symval;
+GBLREF uint4 process_id;
+GBLREF sgmnt_addrs *csa;
#ifdef GTM_TRIGGER
GBLREF int tprestart_state; /* When triggers restart, multiple states possible. See tp_restart.h */
#endif
+/* Define whitebox test case as a macro only for a debug build */
+#ifdef DEBUG
+# define TPUNWND_WBOX_TEST \
+{ \
+ if (WBTEST_ENABLED(WBTEST_TRIGR_TPRESTART_MSTOP)) \
+ { /* For this white box test, we're going to send ourselves a SIGTERM termination signal at a specific point \
+ * in the processing to make sure it succeeds without exploding during rundown. To test the condition GTM-7811 \
+ * fixes, where TPUNWND_WBOX_TEST is seen, move the reset for dollar_tlevel from before the ENABLE_INTERRUTPS \
+ * macro to after the TPUNWND_WBOX_TEST, rebuild and re-run test to see it explode. \
+ */ \
+ kill(process_id, SIGTERM); \
+ hiber_start(20 * 1000); /* Wait up to 20 secs - don't use wait_any as the heartbeat timer \
+ * will kill this wait in 0-7 seconds or so. \
+ */ \
+ /* We sent, we waited, wait expired - weird - funky condition is for identification purposes (to identify the \
+ * actual assert). We should be dead or dying, not trying to resume. \
+ */ \
+ assertpro(WBTEST_TRIGR_TPRESTART_MSTOP == 0); \
+ } \
+}
+#else
+# define TPUNWND_WBOX_TEST
+#endif
+
error_def(ERR_STACKUNDERFLO);
error_def(ERR_TPRETRY);
@@ -78,18 +110,20 @@ void tp_unwind(uint4 newlevel, enum tp_unwind_invocation invocation_type, int *t
/* We are about to clean up structures. Defer MUPIP STOP/signal handling until function end. */
DEFER_INTERRUPTS(INTRPT_IN_TP_UNWIND);
-
- DBGRFCT((stderr, "\ntp_unwind: Beginning TP unwind process\n"));
- restore_lv = (invocation_type == RESTART_INVOCATION);
+ /* Unwind the requested TP levels */
+# if defined(DEBUG_REFCNT) || defined(DEBUG_ERRHND)
+ DBGFPF((stderr, "\ntp_unwind: Beginning TP unwind process\n"));
+# endif
+ restore_lv = (RESTART_INVOCATION == invocation_type);
lvscan = &first_lvscan;
lvscan->next = NULL;
lvscan->elemcnt = 0;
- assert(tp_sp <= tpstackbase && tp_sp > tpstacktop);
- assert(tp_pointer <= (tp_frame *)tpstackbase && tp_pointer > (tp_frame *)tpstacktop);
+ assert((tp_sp <= tpstackbase) && (tp_sp > tpstacktop));
+ assert((tp_pointer <= (tp_frame *)tpstackbase) && (tp_pointer > (tp_frame *)tpstacktop));
for (tl = dollar_tlevel; tl > newlevel; --tl)
{
DBGRFCT((stderr, "\ntp_unwind: Unwinding level %d -- tp_pointer: 0x"lvaddr"\n", tl, tp_pointer));
- assert(NULL != tp_pointer);
+ assertpro(NULL != tp_pointer);
for (restore_ent = tp_pointer->vars; NULL != restore_ent; restore_ent = tp_pointer->vars)
{
/*********************************************************************************/
@@ -115,9 +149,10 @@ void tp_unwind(uint4 newlevel, enum tp_unwind_invocation invocation_type, int *t
# ifdef GTM_TRIGGER
if (0 != rc)
{
+ dollar_tlevel = tl; /* Record fact if we unwound some tp_frames */
ENABLE_INTERRUPTS(INTRPT_IN_TP_UNWIND); /* drive any MUPIP STOP/signals deferred
* while in this function */
- dollar_tlevel = tl; /* Record fact if we unwound some tp_frames */
+ TPUNWND_WBOX_TEST; /* Debug-only wbox-test to simulate SIGTERM */
INVOKE_RESTART;
}
# endif
@@ -165,23 +200,25 @@ void tp_unwind(uint4 newlevel, enum tp_unwind_invocation invocation_type, int *t
tp_pointer->vars = restore_ent->next;
free(restore_ent);
}
- if (tp_pointer->fp == frame_pointer && mv_chain->mv_st_type == MVST_TPHOLD && msp == (unsigned char *)mv_chain)
+ if ((tp_pointer->fp == frame_pointer) && (MVST_TPHOLD == mv_chain->mv_st_type)
+ && (msp == (unsigned char *)mv_chain))
POP_MV_STENT();
if (NULL == tp_pointer->old_tp_frame)
tp_sp = tpstackbase;
else
tp_sp = (unsigned char *)tp_pointer->old_tp_frame;
if (tp_sp > tpstackbase)
- rts_error(VARLSTCNT(1) ERR_STACKUNDERFLO);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_STACKUNDERFLO);
if (tp_pointer->tp_save_all_flg)
--tp_pointer->sym->tp_save_all;
if ((NULL != (tp_pointer = tp_pointer->old_tp_frame)) /* Note assignment */
- && ((tp_pointer < (tp_frame *)tp_sp) || (tp_pointer > (tp_frame *)tpstackbase)
+ && ((tp_pointer < (tp_frame *)tp_sp) || (tp_pointer > (tp_frame *)tpstackbase)
|| (tp_pointer < (tp_frame *)tpstacktop)))
- rts_error(VARLSTCNT(1) ERR_STACKUNDERFLO);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_STACKUNDERFLO);
}
if ((0 != newlevel) && restore_lv)
{ /* Restore current context (without releasing) */
+ assertpro(NULL != tp_pointer);
DBGRFCT((stderr, "\n\n** tp_unwind: Newlevel (%d) != 0 loop processing\n", newlevel));
for (restore_ent = tp_pointer->vars; NULL != restore_ent; restore_ent = restore_ent->next)
{
@@ -198,9 +235,10 @@ void tp_unwind(uint4 newlevel, enum tp_unwind_invocation invocation_type, int *t
# ifdef GTM_TRIGGER
if (0 != rc)
{
+ dollar_tlevel = tl; /* Record fact if we unwound some levels */
ENABLE_INTERRUPTS(INTRPT_IN_TP_UNWIND); /* drive any MUPIP STOP/signals deferred while
* in this function */
- dollar_tlevel = tl; /* Record fact if we unwound some levels */
+ TPUNWND_WBOX_TEST; /* Debug-only wbox-test to simulate SIGTERM */
INVOKE_RESTART;
}
# endif
@@ -242,7 +280,7 @@ void tp_unwind(uint4 newlevel, enum tp_unwind_invocation invocation_type, int *t
}
}
assert(0 == lvscan->elemcnt); /* verify no elements queued that were not scanned */
- rollback_locks = (invocation_type != COMMIT_INVOCATION);
+ rollback_locks = (COMMIT_INVOCATION != invocation_type);
for (prior = &mlk_pvt_root, mlkp = *prior; NULL != mlkp; mlkp = *prior)
{
if (mlkp->granted)
@@ -265,11 +303,11 @@ void tp_unwind(uint4 newlevel, enum tp_unwind_invocation invocation_type, int *t
mlkp->zalloc = oldlock->zalloc;
}
}
- if (NULL != oldlock && oldlock->tplevel == newlevel)
+ if ((NULL != oldlock) && (oldlock->tplevel == newlevel))
{ /* Remove lock reference from level being unwound to,
* now that any {level,zalloc} state information has been restored.
*/
- assert(NULL == oldlock->next || oldlock->next->tplevel < newlevel);
+ assert((NULL == oldlock->next) || (oldlock->next->tplevel < newlevel));
mlkp->tp = oldlock->next; /* update root reference pointer */
free(oldlock);
} else
@@ -315,7 +353,7 @@ int tp_unwind_restlv(lv_val *curr_lv, lv_val *save_lv, tp_var *restore_ent, lvsc
*/
if (curr_symval != tp_pointer->sym)
{ /* Unwind as many stackframes as are necessary up to the max */
- while(curr_symval != tp_pointer->sym && frame_pointer < tp_pointer->fp)
+ while((curr_symval != tp_pointer->sym) && (frame_pointer < tp_pointer->fp))
{
# ifdef GTM_TRIGGER
if (SFT_TRIGR & frame_pointer->type)
@@ -335,15 +373,14 @@ int tp_unwind_restlv(lv_val *curr_lv, lv_val *save_lv, tp_var *restore_ent, lvsc
if (curr_symval != tp_pointer->sym)
{ /* Unwind as many mv_stents as are necessary up to the max */
mvc = mv_chain;
- while(curr_symval != tp_pointer->sym && mvc < tp_pointer->mvc)
+ while((curr_symval != tp_pointer->sym) && (mvc < tp_pointer->mvc))
{
unw_mv_ent(mvc);
mvc = (mv_stent *)(mvc->mv_st_next + (char *)mvc);
}
mv_chain = mvc;
/* Final check */
- if (curr_symval != tp_pointer->sym)
- GTMASSERT;
+ assertpro(curr_symval == tp_pointer->sym);
}
}
var_cloned = curr_lv->tp_var->var_cloned;
@@ -361,7 +398,7 @@ int tp_unwind_restlv(lv_val *curr_lv, lv_val *save_lv, tp_var *restore_ent, lvsc
* it is no longer used) and replace with desired previous lv_val whose use count
* was incremented when it was saved.
*/
- if (curr_lv != (inuse_lv = (lv_val *)tabent->value))
+ if (curr_lv != (inuse_lv = (lv_val *)tabent->value)) /* Note assignment */
{
if (inuse_lv)
DECR_BASE_REF_RQ(tabent, inuse_lv, FALSE);
@@ -414,7 +451,7 @@ int tp_unwind_restlv(lv_val *curr_lv, lv_val *save_lv, tp_var *restore_ent, lvsc
assert(LVT_PARENT(lvt_child) == ((lvTreeNode *)curr_lv->tp_var->save_value));
LV_CHILD(save_lv) = NULL; /* now that curr_lv->tp_var->var_cloned has been reset */
LVT_PARENT(lvt_child) = (lvTreeNode *)curr_lv;
- if (curr_lv->has_aliascont && NULL != lvscan_anchor)
+ if (curr_lv->has_aliascont && (NULL != lvscan_anchor))
{ /* Some ref counts need to be restored for arrays this tree points to -- but only if the
* array contains pointers (alias containers).
*/
@@ -434,7 +471,7 @@ int tp_unwind_restlv(lv_val *curr_lv, lv_val *save_lv, tp_var *restore_ent, lvsc
*lvscan_anchor = newlvscan;
lvscan = newlvscan;
}
- assert(ARY_SCNCNTNR_MAX >= elemindx && 0 <= elemindx);
+ assert((ARY_SCNCNTNR_MAX >= elemindx) && (0 <= elemindx));
lvscan->ary_scncntnr[elemindx] = curr_lv;
}
}
diff --git a/sr_port/trans_code.c b/sr_port/trans_code.c
index 1bc5c84..fc8ae78 100644
--- a/sr_port/trans_code.c
+++ b/sr_port/trans_code.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 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/unw_mv_ent.c b/sr_port/unw_mv_ent.c
index 5027f2b..5a5b474 100644
--- a/sr_port/unw_mv_ent.c
+++ b/sr_port/unw_mv_ent.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -366,7 +366,7 @@ void unw_mv_ent(mv_stent *mv_st_ent)
if (NULL != mv_st_ent->mv_st_cont.mvs_zintdev.io_ptr)
{ /* This mv_stent has not been processed yet */
rm_ptr = (d_rm_struct *)(mv_st_ent->mv_st_cont.mvs_zintdev.io_ptr->dev_sp);
- assert(rm_ptr->pipe || rm_ptr->fifo);
+ assert(rm_ptr->pipe || rm_ptr->fifo || rm_ptr->follow);
rm_ptr->mupintr = FALSE;
rm_ptr->pipe_save_state.who_saved = pipewhich_invalid;
mv_st_ent->mv_st_cont.mvs_zintdev.buffer_valid = FALSE;
diff --git a/sr_port/updhelper_reader.c b/sr_port/updhelper_reader.c
index b2f183a..977cf5c 100644
--- a/sr_port/updhelper_reader.c
+++ b/sr_port/updhelper_reader.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2005, 2012 Fidelity Information Services, Inc. *
+ * Copyright 2005, 2013 Fidelity Information Services, Inc. *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -171,7 +171,9 @@ boolean_t updproc_preread(void)
unsigned char buff[MAX_ZWR_KEY_SZ], *end;
uint4 write, write_wrap;
#endif
+ DCL_THREADGBL_ACCESS;
+ SETUP_THREADGBL_ACCESS;
maxspins = num_additional_processors ? MAX_LOCK_SPINS(LOCK_SPINS, num_additional_processors) : 1;
upd_proc_local = recvpool.upd_proc_local;
recvpool_ctl = recvpool.recvpool_ctl;
@@ -219,7 +221,8 @@ boolean_t updproc_preread(void)
}
if (0 == retries)
{
- gtm_putmsg(VARLSTCNT(9) ERR_DBCCERR, 2, LIT_AND_LEN("Pre-reader"), ERR_ERRCALL, 3, CALLFROM);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_DBCCERR, 2, LIT_AND_LEN("Pre-reader"),
+ ERR_ERRCALL, 3, CALLFROM);
return FALSE;
}
#ifdef REPL_DEBUG
@@ -336,6 +339,7 @@ boolean_t updproc_preread(void)
&& (key_len == keystr->length)) /* If the shared copy changed underneath us, what
we copied over is potentially a bad record */
{
+ TREF(tqread_nowait) = FALSE; /* don't screw up gvcst_root_search */
UPD_GV_BIND_NAME_APPROPRIATE(gd_header, mname, lcl_key, key_len); /* if ^#t do
special processing */
/* the above would have set gv_target and gv_cur_region appropriately */
@@ -356,7 +360,11 @@ boolean_t updproc_preread(void)
gv_currkey->end = key_len;
disk_blk_read = FALSE;
DEBUG_ONLY(num_helped++);
+ TREF(tqread_nowait) = TRUE;
+ assert(!csa->now_crit);
status = gvcst_search(gv_currkey, NULL);
+ assert(!csa->now_crit);
+ TREF(tqread_nowait) = FALSE; /* reset as soon as possible */
if (cdb_sc_normal != status)
{ /* If gvcst_search returns abnormal status, no need to retry since
* we are a pre-reader but we need to reset clue to avoid fast-path
diff --git a/sr_port/updproc.c b/sr_port/updproc.c
index 1a9a679..da2456c 100644
--- a/sr_port/updproc.c
+++ b/sr_port/updproc.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -101,7 +101,6 @@
#include "gvcst_jrt_null.h" /* for gvcst_jrt_null prototype */
#include "preemptive_db_clnup.h"
-#define MAX_IDLE_HARD_SPINS 1000 /* Fail-safe count to avoid hanging CPU in tight loop while it's idle */
#define UPDPROC_WAIT_FOR_READJNLSEQNO 100 /* ms */
#define UPDPROC_WAIT_FOR_STARTJNLSEQNO 100 /* ms */
@@ -168,60 +167,61 @@ error_def(ERR_TRIGDEFNOSYNC);
error_def(ERR_UPDREPLSTATEOFF);
/* The below logic does "jnl_ensure_open" and other pre-requisites. This code is very similar to t_end.c */
-#define DO_JNL_ENSURE_OPEN(CSA, JPC) \
-{ \
- jnl_buffer_ptr_t jbp; \
- uint4 jnl_status; \
- \
- assert(CSA = &FILE_INFO(gv_cur_region)->s_addrs); /* so we can use gv_cur_region below */ \
- assert(JPC == CSA->jnl); \
- SET_GBL_JREC_TIME; /* needed for jnl_put_jrt_pini() */ \
- jbp = JPC->jnl_buff; \
- /* Before writing to jnlfile, adjust jgbl.gbl_jrec_time if needed to maintain time order \
- * of jnl records. This needs to be done BEFORE the jnl_ensure_open as that could write \
- * journal records (if it decides to switch to a new journal file). \
- */ \
- ADJUST_GBL_JREC_TIME(jgbl, jbp); \
- /* Make sure timestamp of this seqno is >= timestamp of previous seqno. Note: The below \
- * macro invocation should be done AFTER the ADJUST_GBL_JREC_TIME call as the below resets \
- * jpl->prev_jnlseqno_time. Doing it the other way around would mean the reset will happen \
- * with a potentially lower value than the final adjusted time written in the jnl record. \
- */ \
- ADJUST_GBL_JREC_TIME_JNLPOOL(jgbl, jnlpool_ctl); \
- if (JNL_ENABLED(CSA)) \
- { \
- jnl_status = jnl_ensure_open(); \
- if (0 == jnl_status) \
- { \
- if (0 == JPC->pini_addr) \
- jnl_put_jrt_pini(CSA); \
- } else \
- { \
- if (SS_NORMAL != JPC->status) \
- rts_error(VARLSTCNT(7) jnl_status, 4, JNL_LEN_STR(CSA->hdr), \
- DB_LEN_STR(gv_cur_region), JPC->status); \
- else \
- rts_error(VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(CSA->hdr), \
- DB_LEN_STR(gv_cur_region)); \
- } \
- } \
+#define DO_JNL_ENSURE_OPEN(CSA, JPC) \
+{ \
+ jnl_buffer_ptr_t jbp; \
+ uint4 jnl_status; \
+ \
+ assert(CSA = &FILE_INFO(gv_cur_region)->s_addrs); /* so we can use gv_cur_region below */ \
+ assert(JPC == CSA->jnl); \
+ SET_GBL_JREC_TIME; /* needed for jnl_put_jrt_pini() */ \
+ jbp = JPC->jnl_buff; \
+ /* Before writing to jnlfile, adjust jgbl.gbl_jrec_time if needed to maintain time order \
+ * of jnl records. This needs to be done BEFORE the jnl_ensure_open as that could write \
+ * journal records (if it decides to switch to a new journal file). \
+ */ \
+ ADJUST_GBL_JREC_TIME(jgbl, jbp); \
+ /* Make sure timestamp of this seqno is >= timestamp of previous seqno. Note: The below \
+ * macro invocation should be done AFTER the ADJUST_GBL_JREC_TIME call as the below resets \
+ * jpl->prev_jnlseqno_time. Doing it the other way around would mean the reset will happen \
+ * with a potentially lower value than the final adjusted time written in the jnl record. \
+ */ \
+ ADJUST_GBL_JREC_TIME_JNLPOOL(jgbl, jnlpool_ctl); \
+ if (JNL_ENABLED(CSA)) \
+ { \
+ jnl_status = jnl_ensure_open(); \
+ if (0 == jnl_status) \
+ { \
+ if (0 == JPC->pini_addr) \
+ jnl_put_jrt_pini(CSA); \
+ } else \
+ { \
+ if (SS_NORMAL != JPC->status) \
+ rts_error_csa(CSA_ARG(CSA) VARLSTCNT(7) jnl_status, 4, JNL_LEN_STR(CSA->hdr), \
+ DB_LEN_STR(gv_cur_region), JPC->status); \
+ else \
+ rts_error_csa(CSA_ARG(CSA) VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(CSA->hdr), \
+ DB_LEN_STR(gv_cur_region)); \
+ } \
+ } \
}
#ifdef UNIX
-# define UPDPROC_ONLN_RLBK_CLNUP(REG) \
-{ \
- sgmnt_addrs *csa; \
- \
- assert(0 != have_crit(CRIT_HAVE_ANY_REG)); \
- csa = &FILE_INFO(REG)->s_addrs; \
- assert(csa->now_crit); \
- SYNC_ONLN_RLBK_CYCLES; \
- if (REG == jnlpool.jnlpool_dummy_reg) \
- rel_lock(REG); \
- else \
- rel_crit(REG); \
- RESET_ALL_GVT_CLUES; \
- rts_error(VARLSTCNT(1) ERR_REPLONLNRLBK); /* transfers control back to updproc_ch */ \
+# define UPDPROC_ONLN_RLBK_CLNUP(REG) \
+{ \
+ sgmnt_addrs *csa; \
+ \
+ assert(0 != have_crit(CRIT_HAVE_ANY_REG)); \
+ csa = &FILE_INFO(REG)->s_addrs; \
+ assert(csa->now_crit); \
+ SYNC_ONLN_RLBK_CYCLES; \
+ if (REG == jnlpool.jnlpool_dummy_reg) \
+ rel_lock(REG); \
+ else \
+ rel_crit(REG); \
+ RESET_ALL_GVT_CLUES; \
+ /* transfers control back to updproc_ch */ \
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_REPLONLNRLBK); \
}
/* Receiver eventually sees the upd_proc_local->onln_rlbk_flag being set, drains the replication pipe, closes the connection and
@@ -270,7 +270,7 @@ CONDITION_HANDLER(updproc_ch)
INT8_PRINT(recvpool.upd_proc_local->read_jnl_seqno),
INT8_PRINTX(recvpool.upd_proc_local->read_jnl_seqno));
/* This is a kludge. We can come here from 2 places.
- * ( i) From a call to t_retry which does a rts_error(ERR_TPRETRY).
+ * ( i) From a call to t_retry which does a rts_error(ERR_TPRETRY)
* (ii) From updproc_actions() where immediately after op_tcommit we detect that dollar_tlevel is non-zero.
* In the first case, we need to do a tp_restart. In the second, op_tcommit would have already done it for us.
* The way we detect the second case is from the value of first_sgm_info since it is NULLified in tp_restart.
@@ -357,7 +357,7 @@ int updproc(void)
proc_name_desc.dsc$b_dtype = DSC$K_DTYPE_T;
proc_name_desc.dsc$b_class = DSC$K_CLASS_S;
if (SS$_NORMAL != (status = sys$setprn(&proc_name_desc)))
- rts_error(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Unable to change update process name"), status);
# else
/* In the update process, we want every replicated update from an originating instances to end up in a replicated region
@@ -377,7 +377,10 @@ int updproc(void)
NON_GTMTRIG_ONLY(skip_dbtriggers = TRUE;)
memset((uchar_ptr_t)&recvpool, 0, SIZEOF(recvpool)); /* For util_base_ch and mupip_exit */
if (updproc_init(&gld_db_files, &start_jnl_seqno) == UPDPROC_EXISTS) /* we got the global directory header already */
- rts_error(VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Update Process already exists"));
+ {
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 0,
+ ERR_TEXT, 2, RTS_ERROR_LITERAL("Update Process already exists"));
+ }
OPERATOR_LOG_MSG;
/* Initialization of all the relevant global datastructures and allocation for TP */
repl_csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs;
@@ -432,7 +435,7 @@ int updproc(void)
{ /* A concurrent online rollback. Handle it */
LOG_ONLINE_ROLLBACK_EVENT;
assert(!repl_csa->now_crit && !set_onln_rlbk_flg);
- grab_lock(jnlpool.jnlpool_dummy_reg, GRAB_LOCK_ONLY);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, GRAB_LOCK_ONLY);
SYNC_ONLN_RLBK_CYCLES;
rel_lock(jnlpool.jnlpool_dummy_reg);
upd_proc_local->onln_rlbk_flg = TRUE; /* let receiver know about the online rollback */
@@ -466,7 +469,7 @@ int updproc(void)
repl_log(updproc_log_fp, TRUE, TRUE,
"JNLSEQNO of last transaction written to journal pool = "INT8_FMT" "INT8_FMTX"\n",
INT8_PRINT(jnlpool_ctl->jnl_seqno), INT8_PRINTX(jnlpool_ctl->jnl_seqno));
- rts_error(VARLSTCNT(1) ERR_SECONDAHEAD);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_SECONDAHEAD);
}
# else
/* The SECONDAHEAD check is performed in the receiver server after it has connected with the source
@@ -538,27 +541,22 @@ void updproc_actions(gld_dbname_list *gld_db_files)
upd_proc_local_ptr_t upd_proc_local;
gtmrecv_local_ptr_t gtmrecv_local;
upd_helper_ctl_ptr_t upd_helper_ctl;
- sgmnt_addrs *csa, *repl_csa;
+ sgmnt_addrs *csa, *repl_csa, *tmpcsa = NULL;
sgmnt_data_ptr_t csd;
char gv_mname[MAX_KEY_SZ];
unsigned char buff[MAX_ZWR_KEY_SZ], *end, scan_char, next_char;
boolean_t log_switched = FALSE;
# ifdef UNIX
boolean_t suppl_root_primary, suppl_propagate_primary;
+ repl_histinfo histinfo;
+ repl_old_triple_jnl_t *input_old_triple;
+ repl_histrec_jnl_ptr_t input_histjrec;
+ uint4 expected_rec_len;
# endif
jnl_private_control *jpc;
gld_dbname_list *curr;
gd_region *save_reg;
- int4 wtstart_errno;
- boolean_t buffers_flushed;
- uint4 idle_flush_count = 0; /* Number of times buffers were flushed without an intermediate sleep */
uint4 write_wrap, cntr, last_nullsubs, last_subs, keyend;
- UNIX_ONLY(
- repl_histinfo histinfo;
- repl_old_triple_jnl_ptr_t input_old_triple;
- repl_histrec_jnl_ptr_t input_histjrec;
- uint4 expected_rec_len;
- )
# ifdef GTM_TRIGGER
uint4 nodeflags;
boolean_t primary_has_trigdef, secondary_has_trigdef;
@@ -673,63 +671,16 @@ void updproc_actions(gld_dbname_list *gld_db_files)
*/
assert((0 == recvpool.recvpool_ctl->jnl_seqno) || (jnl_seqno <= recvpool.recvpool_ctl->jnl_seqno));
/* the 0 == check takes care of the startup case where jnl_seqno is 0 in the recvpool_ctl */
- /* If any dirty buffers, write them out since nothing else is happening now.
- * wcs_wtstart only writes a few buffer a call and putting the call in a loop would flush the
- * entire dirty buffer set, but there is no need for a loop around the call since we're already in
- * the main updproc loop and this is the only place it really sleeps. */
- save_reg = gv_cur_region;
- /* Make sure cs_addrs and cs_data are in sync with gv_cur_region before TP_CHANGE_REG changes them */
- assert((NULL == gv_cur_region) || (cs_addrs == &FILE_INFO(gv_cur_region)->s_addrs));
- assert((NULL == gv_cur_region) || (cs_data == cs_addrs->hdr));
- buffers_flushed = FALSE;
- for (curr = gld_db_files; NULL != curr; curr = curr->next)
- {
- TP_CHANGE_REG(curr->gd);
- if (cs_addrs->nl->wcs_active_lvl && (FALSE == gv_cur_region->read_only))
- {
- DCLAST_WCS_WTSTART(gv_cur_region, 0, wtstart_errno);
- /* DCLAST_WCS_WTSTART macro does not set the wtstart_errno variable in VMS. But in
- * any case, we do not support database file extensions with MM on VMS. So we could
- * never get a ERR_GBLOFLOW error there. Therefore the file extension check below is
- * done only in Unix.
- */
-# ifdef UNIX
- if ((dba_mm == cs_data->acc_meth) && (ERR_GBLOFLOW == wtstart_errno))
- {
- assert(!cs_addrs->hold_onto_crit);
- grab_crit(gv_cur_region);
- if (cs_addrs->onln_rlbk_cycle != cs_addrs->nl->onln_rlbk_cycle)
- UPDPROC_ONLN_RLBK_CLNUP(gv_cur_region); /* No return */
- wcs_recover(gv_cur_region);
- rel_crit(gv_cur_region);
- }
-# endif
- buffers_flushed = TRUE;
- }
- }
- TP_CHANGE_REG(save_reg);
- /* To avoid a potential infinite cpu-bound loop if the wcs_active_lvl field is bogus and wcs_wtstart()
- * returns immediately, we count the number of times a buffer flush has (potentially) occurred. When
- * this count gets to an arbitrarily "large" value or there were no buffers to flush, we will sleep
- * and start the count over again. If there are more than the "large" number of dirty buffers to flush,
- * this logic only causes an extra benign sleep whenever the count is "large". */
- if (buffers_flushed && (MAX_IDLE_HARD_SPINS > idle_flush_count))
- idle_flush_count++;
- else
- {
- idle_flush_count = 0;
- SHORT_SLEEP(10);
- }
+ SHORT_SLEEP(10);
# ifdef UNIX
if (!upd_proc_local->onln_rlbk_flg && (repl_csa->onln_rlbk_cycle != jnlpool.jnlpool_ctl->onln_rlbk_cycle))
{ /* A concurrent online rollback happened. Start afresh */
- grab_lock(jnlpool.jnlpool_dummy_reg, GRAB_LOCK_ONLY);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, GRAB_LOCK_ONLY);
UPDPROC_ONLN_RLBK_CLNUP(jnlpool.jnlpool_dummy_reg); /* No return */
} /* else onln_rlbk_flag is already set and the receiver should take the next appropriate action */
# endif
continue;
}
- idle_flush_count = 0;
/* The update process reads "recvpool_ctl->write" first and assumes that all data in the receive pool
* that it then reads (upto the "write" offset) is valid. In order for this assumption to hold good, the
* receiver server needs to do a write memory barrier after updating the receive pool data but before
@@ -909,7 +860,7 @@ void updproc_actions(gld_dbname_list *gld_db_files)
rel_crit(gv_cur_region);
}
TP_CHANGE_REG(save_reg);
- grab_lock(jnlpool.jnlpool_dummy_reg, GRAB_LOCK_ONLY);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, GRAB_LOCK_ONLY);
if (repl_csa->onln_rlbk_cycle != jnlpool_ctl->onln_rlbk_cycle)
UPDPROC_ONLN_RLBK_CLNUP(jnlpool.jnlpool_dummy_reg); /* No return */
jnlpool_ctl->strm_seqno[histinfo.strm_index] = strm_seqno;
@@ -922,7 +873,7 @@ void updproc_actions(gld_dbname_list *gld_db_files)
assert(jnlpool.jnlpool_ctl->upd_disabled || (strm_index == histinfo.strm_index));
}
/* Now that we have constructed the history, add it to the instance file. */
- grab_lock(jnlpool.jnlpool_dummy_reg, GRAB_LOCK_ONLY);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, GRAB_LOCK_ONLY);
if (repl_csa->onln_rlbk_cycle != jnlpool_ctl->onln_rlbk_cycle)
UPDPROC_ONLN_RLBK_CLNUP(jnlpool.jnlpool_dummy_reg); /* No return */
repl_inst_histinfo_add(&histinfo);
@@ -1052,21 +1003,26 @@ void updproc_actions(gld_dbname_list *gld_db_files)
}
if (upd_good_record == bad_trans_type)
{
- UNIX_ONLY(
- if (suppl_propagate_primary)
+# ifdef UNIX
+ if (suppl_propagate_primary)
+ {
+ rec_strm_seqno = GET_STRM_SEQNO(rec);
+ strm_index = GET_STRM_INDEX(rec_strm_seqno);
+ rec_strm_seqno = GET_STRM_SEQ60(rec_strm_seqno);
+ strm_seqno = jnlpool_ctl->strm_seqno[strm_index];
+ /* In the event of a concurrent ONLINE ROLLBACK, it is likely that the strm_seqno is less than
+ * rec_strm_seqno. In that case, do not issue STRMSEQMISMTCH error as that would be incorrect.
+ * Instead, continue and eventually, either the update process or the transaction processing logic
+ * will detect the online rollback and take appropriate action.
+ */
+ if ((rec_strm_seqno != strm_seqno) && (repl_csa->onln_rlbk_cycle == jnlpool_ctl->onln_rlbk_cycle))
{
- rec_strm_seqno = GET_STRM_SEQNO(rec);
- strm_index = GET_STRM_INDEX(rec_strm_seqno);
- rec_strm_seqno = GET_STRM_SEQ60(rec_strm_seqno);
- strm_seqno = jnlpool_ctl->strm_seqno[strm_index];
- if (rec_strm_seqno != strm_seqno)
- {
- assert(FALSE);
- rts_error(VARLSTCNT(5) ERR_STRMSEQMISMTCH, 3,
- strm_index, &rec_strm_seqno, &strm_seqno);
- }
+ assert(FALSE);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_STRMSEQMISMTCH, 3,
+ strm_index, &rec_strm_seqno, &strm_seqno);
}
- )
+ }
+# endif
if (JRT_NULL == rectype)
{ /* Play the NULL transaction into the database and journal files */
save_reg = gv_cur_region;
@@ -1135,7 +1091,7 @@ void updproc_actions(gld_dbname_list *gld_db_files)
* the journal seqno on the secondary database will get out-of-sync with that of
* the primary database.
*/
- gtm_putmsg(VARLSTCNT(6) ERR_UPDREPLSTATEOFF, 4,
+ gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_UPDREPLSTATEOFF, 4,
mname.len, mname.addr, DB_LEN_STR(gv_cur_region));
/* Shut down the update process normally */
upd_proc_local->upd_proc_shutdown = SHUTDOWN;
@@ -1147,6 +1103,7 @@ void updproc_actions(gld_dbname_list *gld_db_files)
if (gv_currkey->end + 1 > gv_cur_region->max_key_size)
{
bad_trans_type = upd_bad_key_size;
+ tmpcsa = csa;
assert(gtm_white_box_test_case_enabled
&& (WBTEST_UPD_PROCESS_ERROR == gtm_white_box_test_case_number));
} else
@@ -1231,6 +1188,7 @@ void updproc_actions(gld_dbname_list *gld_db_files)
gv_cur_region->max_rec_size)
{
bad_trans_type = upd_bad_val_size;
+ tmpcsa = csa;
assert(gtm_white_box_test_case_enabled
&& (WBTEST_UPD_PROCESS_ERROR == gtm_white_box_test_case_number));
} else
@@ -1255,9 +1213,9 @@ void updproc_actions(gld_dbname_list *gld_db_files)
trigdef_inst = "replicating";
no_trigdef_inst = "originating";
}
- send_msg(VARLSTCNT(9) ERR_TRIGDEFNOSYNC, 7, mname.len, mname.addr,
- LEN_AND_STR(trigdef_inst), LEN_AND_STR(no_trigdef_inst),
- &jnl_seqno);
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_TRIGDEFNOSYNC, 7,
+ mname.len, mname.addr, LEN_AND_STR(trigdef_inst),
+ LEN_AND_STR(no_trigdef_inst), &jnl_seqno);
}
}
# endif
@@ -1342,7 +1300,9 @@ void updproc_actions(gld_dbname_list *gld_db_files)
GV_SET_LAST_SUBSCRIPT_INCOMPLETE(fmtBuff, endBuff);
if (NULL != gv_failed_key) /* Free memory if it has been used */
free(gv_failed_key);
- rts_error(VARLSTCNT(6) ERR_GVSUBOFLOW, 0, ERR_GVIS, 2, endBuff - fmtBuff, fmtBuff);
+ assert(NULL != tmpcsa);
+ rts_error_csa(CSA_ARG(tmpcsa) VARLSTCNT(6) ERR_GVSUBOFLOW, 0,
+ ERR_GVIS, 2, endBuff - fmtBuff, fmtBuff);
break;
case upd_bad_val_size:
if (0 == (end = format_targ_key(buff, MAX_ZWR_KEY_SZ,
@@ -1350,7 +1310,8 @@ void updproc_actions(gld_dbname_list *gld_db_files)
end = &buff[MAX_ZWR_KEY_SZ - 1];
if (NULL != gv_failed_key) /* Free memory if it has been used */
free(gv_failed_key);
- rts_error(VARLSTCNT(10) ERR_REC2BIG, 4,
+ 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),
ERR_GVIS, 2, end - buff, buff);
diff --git a/sr_port/updproc_open_files.c b/sr_port/updproc_open_files.c
index 8f703fc..2cea8ed 100644
--- a/sr_port/updproc_open_files.c
+++ b/sr_port/updproc_open_files.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2005, 2012 Fidelity Information Services, Inc *
+ * Copyright 2005, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -168,7 +168,7 @@ boolean_t updproc_open_files(gld_dbname_list **gld_db_files, seq_num *start_jnl_
* loops instead of one is because we don't want to do gvcst_init while holding the journal pool lock as the former
* acquires ftok and access control semaphores and holding the journal pool lock is a potential recipe for deadlocks
*/
- UNIX_ONLY(grab_lock(jnlpool.jnlpool_dummy_reg, GRAB_LOCK_ONLY));
+ UNIX_ONLY(grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, GRAB_LOCK_ONLY));
for (curr = *gld_db_files; NULL != curr; curr = curr->next)
{
reg = curr->gd;
diff --git a/sr_port/viewtab.h b/sr_port/viewtab.h
index d1f0258..14a5665 100644
--- a/sr_port/viewtab.h
+++ b/sr_port/viewtab.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -16,10 +16,13 @@ VIEWTAB("0", VTP_NULL, VTK_GDSCERT0, MV_STR),
VIEWTAB("1", VTP_NULL, VTK_GDSCERT1, MV_STR),
VIEWTAB("BADCHAR", VTP_NULL, VTK_BADCHAR, MV_NM),
VIEWTAB("BREAKMSG", VTP_NULL | VTP_VALUE, VTK_BREAKMSG, MV_NM),
+VIEWTAB("DBFLUSH", VTP_DBREGION | VTP_NULL, VTK_DBFLUSH, MV_STR),
+VIEWTAB("DBSYNC", VTP_DBREGION | VTP_NULL, VTK_DBSYNC, MV_STR),
VIEWTAB("DEBUG1", VTP_VALUE | VTP_NULL, VTK_DEBUG1, MV_STR),
VIEWTAB("DEBUG2", VTP_VALUE | VTP_NULL, VTK_DEBUG2, MV_STR),
VIEWTAB("DEBUG3", VTP_VALUE | VTP_NULL, VTK_DEBUG3, MV_STR),
VIEWTAB("DEBUG4", VTP_VALUE | VTP_NULL, VTK_DEBUG4, MV_STR),
+VIEWTAB("EPOCH", VTP_DBREGION | VTP_NULL, VTK_EPOCH, MV_STR),
VIEWTAB("FILL_FACTOR", VTP_VALUE | VTP_NULL, VTK_FILLFACTOR, MV_NM),
VIEWTAB("FLUSH", VTP_DBREGION | VTP_NULL, VTK_FLUSH, MV_STR),
VIEWTAB("FREEBLOCKS", VTP_DBREGION, VTK_BLFREE, MV_NM),
@@ -72,6 +75,9 @@ 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("RCHITS", VTP_NULL, VTK_RCHITS, MV_NM),
VIEWTAB("RCMISSES", VTP_NULL, VTK_RCMISSES, MV_NM),
VIEWTAB("RCSIZE", VTP_NULL, VTK_RCSIZE, MV_NM),
diff --git a/sr_port/wbox_test_init.h b/sr_port/wbox_test_init.h
index 1e37881..4e8b996 100644
--- a/sr_port/wbox_test_init.h
+++ b/sr_port/wbox_test_init.h
@@ -1,7 +1,7 @@
/****************************************************************
* *
- * Copyright 2005, 2012 Fidelity Information Services, Inc *
+ * Copyright 2005, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -71,7 +71,7 @@ typedef enum {
WBTEST_JNL_FILE_OPEN_FAIL, /* 43 : Unix only. Journal file open always return ERR_JNLFILOPN */
WBTEST_FAIL_ON_SHMGET, /* 44 : Unix only. Cause db_init() to fail on shmget */
WBTEST_EXTEND_JNL_FSYNC, /* 45 : enter a long loop upon trying to do jnl_fsync */
- WBTEST_CMP_SOLVE_TIMEOUT, /* 46 : !!! UNUSED !!! */
+ WBTEST_TRIGR_TPRESTART_MSTOP, /* 46 : Trigger being restarted gets a MUPIP STOP - shouldn't fail */
WBTEST_SENDTO_EPERM, /* 47 : Will sleep in grab_crit depending on gtm_white_box_test_case_number */
WBTEST_ALLOW_ARBITRARY_FULLY_UPGRADED, /* 48 : Allows csd->fully_upgraded to take arbitrary values (via DSE) and prevents
* assert in mur_process_intrpt_recov.c */
@@ -99,8 +99,8 @@ typedef enum {
WBTEST_HOLD_CRIT_TILL_LCKALERT, /* 66 : Grab and hold crit until 15 seconds past what triggers a lock alert message
* which should invoke a mutex salvage */
WBTEST_OPER_LOG_MSG, /* 67 : send message to operator log */
+ WBTEST_UNUSED_1, /* 68 : */
/* Begin ANTIFREEZE related white box test cases */
- WBTEST_ANTIFREEZE_DSKNOSPCAVAIL, /* 68 : */
WBTEST_ANTIFREEZE_JNLCLOSE, /* 69 : */
WBTEST_ANTIFREEZE_DBBMLCORRUPT, /* 70 : */
WBTEST_ANTIFREEZE_DBDANGER, /* 71 : */
@@ -120,9 +120,24 @@ typedef enum {
WBTEST_LONGSLEEP_IN_REPL_SHUTDOWN, /* 84 : Sleep in Source/Receiver shutdown logic to ensure sem/shm is not removed */
WBTEST_FORCE_WCS_GET_SPACE, /* 85 : Simulate state in which nearly all global buffers are dirty, forcing
* wcs_get_space to be called before committing an update */
- /* HugeTLB tests */
+ /* Begin HugeTLB tests */
WBTEST_HUGETLB_DLOPEN, /* 86 : Fail dlopen(libhugetlbfs.so) */
- WBTEST_HUGETLB_DLSYM /* 87 : Fail dlsym(shmget) */
+ WBTEST_HUGETLB_DLSYM, /* 87 : Fail dlsym(shmget) */
+ WBTEST_FSYNC_SYSCALL_FAIL, /* 88 : Force error from fsync() */
+ WBTEST_HUGE_ALLOC, /* 89 : Force ZALLOCSTOR, ZREALSTOR, and ZUSEDSTOR to be values exceeding
+ * the capacity of four-byte ints */
+ WBTEST_MMAP_SYSCALL_FAIL, /* 90 : Force mmap() to return an error */
+ WBTEST_TAMPER_HOSTNAME, /* 91 : Change host name in db_init to call condition handler */
+ WBTEST_RECOVER_ENOSPC, /* 92 : Cause ENOSPC error on Xth write to test return status on error */
+ WBTEST_WCS_FLU_FAIL, /* 93 : Simulates a failure in wcs_flu */
+ WBTEST_PREAD_SYSCALL_FAIL, /* 94 : Simulate pread() error in dsk_read */
+ WBTEST_HOLD_CRIT_ENABLED, /* 95 : Enable $view("PROBECRIT","REGION") command to cold crit */
+ WBTEST_HOLD_FTOK_UNTIL_BYPASS /* 96 : Hold the ftok semaphore until another process comes and bypasses
+ * it*/
+ /* 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.
+ */
} wbtest_code_t;
#ifdef DEBUG
@@ -144,6 +159,7 @@ typedef enum {
#endif
#ifdef DEBUG
+#define WBTEST_ENABLED(WBTEST_NUMBER) (gtm_white_box_test_case_enabled && (WBTEST_NUMBER == gtm_white_box_test_case_number))
#define ENABLE_WBTEST_ABANDONEDKILL \
{ \
int sleep_counter; \
@@ -161,9 +177,18 @@ typedef enum {
#define WB_PHASE1_COMMIT_ERR (WBTEST_BG_UPDATE_BTPUTNULL == gtm_white_box_test_case_number)
#define WB_PHASE2_COMMIT_ERR (WBTEST_BG_UPDATE_PHASE2FAIL == gtm_white_box_test_case_number)
#define WB_COMMIT_ERR_ENABLED (WB_PHASE1_COMMIT_ERR || WB_PHASE2_COMMIT_ERR) /* convoluted definition to simplify usage */
+#define WBTEST_ASSIGN_ONLY(WBTEST_NUMBER, LHS, RHS) \
+{ \
+ if (WBTEST_ENABLED(WBTEST_NUMBER)) \
+ { \
+ LHS = RHS; \
+ } \
+}
#else
+#define WBTEST_ENABLED(WBTEST_NUMBER) FALSE
#define ENABLE_WBTEST_ABANDONEDKILL
#define WB_COMMIT_ERR_ENABLED
+#define WBTEST_ASSIGN_ONLY(WBTEST_NUMBER, LHS, RHS)
#endif
#endif
diff --git a/sr_port/wcs_mm_recover.h b/sr_port/wcs_mm_recover.h
index b15b002..3db0560 100644
--- a/sr_port/wcs_mm_recover.h
+++ b/sr_port/wcs_mm_recover.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2008 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -16,7 +16,7 @@
{ \
if (csa->total_blks != csa->ti->total_blks) \
wcs_mm_recover(reg); \
- assert(csa->total_blks == csa->ti->total_blks); \
+ assert(!csa->now_crit || (csa->total_blks == csa->ti->total_blks)); \
}
#define CHECK_MM_DBFILEXT_REMAP_IF_NEEDED(csa, reg) \
diff --git a/sr_port/wcs_recover.c b/sr_port/wcs_recover.c
index 70b015c..e922f62 100644
--- a/sr_port/wcs_recover.c
+++ b/sr_port/wcs_recover.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -103,16 +103,15 @@ GBLREF boolean_t in_mu_rndwn_file;
error_def(ERR_BUFRDTIMEOUT);
error_def(ERR_DBADDRALIGN);
error_def(ERR_DBADDRANGE);
-error_def(ERR_DBCCERR);
error_def(ERR_DBCNTRLERR);
error_def(ERR_DBCRERR);
error_def(ERR_DBDANGER);
error_def(ERR_DBFILERR);
-error_def(ERR_ERRCALL);
error_def(ERR_INVALIDRIP);
error_def(ERR_GBLOFLOW);
error_def(ERR_GVIS);
error_def(ERR_STOPTIMEOUT);
+error_def(ERR_SYSCALL);
error_def(ERR_TEXT);
void wcs_recover(gd_region *reg)
@@ -201,7 +200,7 @@ void wcs_recover(gd_region *reg)
if (wcs_verify(reg, TRUE, TRUE)) /* expect_damage is TRUE, in_wcs_recover is TRUE */
{ /* if it passes verify, then recover can't help ??? what to do */
BG_TRACE_PRO_ANY(csa, wc_blocked_wcs_verify_passed);
- send_msg(VARLSTCNT(4) ERR_DBCNTRLERR, 2, DB_LEN_STR(reg));
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_DBCNTRLERR, 2, DB_LEN_STR(reg));
}
if (gtmDebugLevel)
verifyAllocatedStorage();
@@ -247,13 +246,13 @@ void wcs_recover(gd_region *reg)
old_block = (INTPTR_T)GDS_ANY_REL2ABS(csa, cr->twin);
if (!IS_PTR_IN_RANGE(old_block, bp_lo, bp_top))
{
- send_msg(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg),
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg),
cr, cr->blk, old_block, RTS_ERROR_TEXT("bkup_before_image_range"), bp_lo, bp_top);
assert(FALSE);
continue;
} else if (!IS_PTR_ALIGNED(old_block, bp_lo, csd->blk_size))
{
- send_msg(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg), cr, cr->blk,
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg), cr, cr->blk,
RTS_ERROR_TEXT("bkup_before_image_align"), old_block, bp_lo, csd->blk_size);
assert(FALSE);
continue;
@@ -266,26 +265,28 @@ void wcs_recover(gd_region *reg)
/* Do other checks to validate before-image buffer */
if (cr_alt == cr)
{
- send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk,
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk,
RTS_ERROR_TEXT("bkup_before_image_cr_same"), cr_alt, FALSE, CALLFROM);
assert(FALSE);
continue;
} else if (cr->blk != cr_alt->blk)
{
- send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk,
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk,
RTS_ERROR_TEXT("bkup_before_image_blk"), cr_alt->blk, cr->blk, CALLFROM);
assert(FALSE);
continue;
} else if (!cr_alt->in_cw_set)
{
- send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr_alt, cr_alt->blk,
- RTS_ERROR_TEXT("bkup_before_image_in_cw_set"), cr_alt->in_cw_set, TRUE, CALLFROM);
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr_alt,
+ cr_alt->blk, RTS_ERROR_TEXT("bkup_before_image_in_cw_set"),
+ cr_alt->in_cw_set, TRUE, CALLFROM);
assert(FALSE);
continue;
} else if (cr_alt->stopped)
{
- send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr_alt, cr_alt->blk,
- RTS_ERROR_TEXT("bkup_before_image_stopped"), cr_alt->stopped, FALSE, CALLFROM);
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr_alt,
+ cr_alt->blk, RTS_ERROR_TEXT("bkup_before_image_stopped"),
+ cr_alt->stopped, FALSE, CALLFROM);
assert(FALSE);
continue;
}
@@ -360,7 +361,7 @@ void wcs_recover(gd_region *reg)
r_epid = cr->r_epid;
if (cr->read_in_progress < -1)
{
- send_msg(VARLSTCNT(4) ERR_INVALIDRIP, 2, DB_LEN_STR(reg));
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_INVALIDRIP, 2, DB_LEN_STR(reg));
INTERLOCK_INIT(cr);
cr->cycle++; /* increment cycle whenever blk number changes (tp_hist depends on this) */
cr->blk = CR_BLKEMPTY;
@@ -388,9 +389,9 @@ void wcs_recover(gd_region *reg)
GTMASSERT;
/* process still active but not playing fair or cache is corrupted */
GET_C_STACK_FROM_SCRIPT("BUFRDTIMEOUT", process_id, r_epid, TWICE);
- send_msg(VARLSTCNT(8) ERR_BUFRDTIMEOUT, 6, process_id, cr->blk, cr, r_epid,
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_BUFRDTIMEOUT, 6, process_id, cr->blk, cr, r_epid,
DB_LEN_STR(reg));
- send_msg(VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_LIT("Buffer forcibly seized"));
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_LIT("Buffer forcibly seized"));
INTERLOCK_INIT(cr);
cr->cycle++; /* increment cycle whenever blk number changes (tp_hist depends on this) */
cr->blk = CR_BLKEMPTY;
@@ -427,8 +428,10 @@ void wcs_recover(gd_region *reg)
GTMASSERT;
if (0 != epid)
{ /* process still active, but not playing fair */
- send_msg(VARLSTCNT(5) ERR_STOPTIMEOUT, 3, epid, DB_LEN_STR(reg));
- send_msg(VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_LIT("Buffer forcibly seized"));
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_STOPTIMEOUT, 3, epid,
+ DB_LEN_STR(reg));
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TEXT, 2,
+ LEN_AND_LIT("Buffer forcibly seized"));
cr->epid = 0;
}
continue;
@@ -615,7 +618,8 @@ void wcs_recover(gd_region *reg)
* In Unix, no rebuild would have been attempted since no kernel extension routine currently available.
* In either case, we do not want to discard this buffer so send a warning to the user and proceed.
*/
- send_msg(VARLSTCNT(7) ERR_DBDANGER, 5, cr->data_invalid, cr->data_invalid, DB_LEN_STR(reg), cr->blk);
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(7) ERR_DBDANGER, 5, cr->data_invalid, cr->data_invalid,
+ DB_LEN_STR(reg), cr->blk);
cr->data_invalid = 0;
}
if (cr->in_tend)
@@ -824,57 +828,65 @@ void wcs_recover(gd_region *reg)
return;
}
-#ifdef UNIX
-
#ifdef MM_FILE_EXT_OK
void wcs_mm_recover(gd_region *reg)
{
- int mm_prot;
+ int save_errno;
+ gtm_uint64_t mmap_sz;
INTPTR_T status;
struct stat stat_buf;
- sm_uc_ptr_t old_base[2];
- sigset_t savemask;
- boolean_t need_to_restore_mask = FALSE, was_crit;
+ sm_uc_ptr_t old_db_addrs[2], mmap_retaddr;
+ boolean_t was_crit, read_only;
unix_db_info *udi;
+ const char *syscall = "munmap()";
+ VMS_ONLY(assert(FALSE));
assert(&FILE_INFO(reg)->s_addrs == cs_addrs);
assert(cs_addrs->hdr == cs_data);
- if (!(was_crit = cs_addrs->now_crit) && !(cs_addrs->hdr->clustered))
+ assert(!cs_addrs->hdr->clustered);
+ assert(!cs_addrs->hold_onto_crit || cs_addrs->now_crit);
+ if (!(was_crit = cs_addrs->now_crit))
grab_crit(gv_cur_region);
SET_TRACEABLE_VAR(cs_addrs->nl->wc_blocked, FALSE);
- if (cs_addrs->total_blks == cs_addrs->ti->total_blks)
- {
- /* I am the one who actually did the extension, don't need to remap again */
+ assert((NULL != cs_addrs->db_addrs[0]) || process_exiting);
+ if ((cs_addrs->total_blks == cs_addrs->ti->total_blks) || (NULL == cs_addrs->db_addrs[0]))
+ { /* I am the one who actually did the extension, don't need to remap again OR an munmap/mmap failed and we are in
+ * shutdown logic
+ */
if (!was_crit)
rel_crit(gv_cur_region);
return;
}
- mm_prot = cs_addrs->read_write ? (PROT_READ | PROT_WRITE) : PROT_READ;
- /* Block SIGALRM to ensure cs_data and cs_addrs are always in-sync / No IO in this period */
- sigprocmask(SIG_BLOCK, &blockalrm, &savemask);
- old_base[0] = cs_addrs->db_addrs[0];
- old_base[1] = cs_addrs->db_addrs[1];
- status = (INTPTR_T)munmap((caddr_t)old_base[0], (size_t)(old_base[1] - old_base[0]));
+ old_db_addrs[0] = cs_addrs->db_addrs[0];
+ old_db_addrs[1] = cs_addrs->db_addrs[1];
+ cs_addrs->db_addrs[0] = NULL;
+ status = (INTPTR_T)munmap((caddr_t)old_db_addrs[0], (size_t)(old_db_addrs[1] - old_db_addrs[0]));
if (-1 != status)
{
udi = FILE_INFO(gv_cur_region);
FSTAT_FILE(udi->fd, &stat_buf, status);
- status = (sm_long_t)(cs_addrs->db_addrs[0] = (sm_uc_ptr_t)mmap((caddr_t)NULL, (size_t)stat_buf.st_size,
- mm_prot, GTM_MM_FLAGS, udi->fd, (off_t)0));
+ mmap_sz = stat_buf.st_size - BLK_ZERO_OFF(cs_data);
+ CHECK_LARGEFILE_MMAP(gv_cur_region, mmap_sz); /* can issue rts_error MMFILETOOLARGE */
+ read_only = gv_cur_region->read_only;
+ syscall = "mmap()";
+ status = (sm_long_t)(mmap_retaddr = (sm_uc_ptr_t)MMAP_FD(udi->fd, mmap_sz, BLK_ZERO_OFF(cs_data), read_only));
+ GTM_WHITE_BOX_TEST(WBTEST_MMAP_SYSCALL_FAIL, status, -1);
}
if (-1 == status)
{
- sigprocmask(SIG_SETMASK, &savemask, NULL);
+ save_errno = errno;
+ WBTEST_ASSIGN_ONLY(WBTEST_MMAP_SYSCALL_FAIL, save_errno, ENOMEM);
if (!was_crit)
rel_crit(gv_cur_region);
- rts_error(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), errno);
+ assert(WBTEST_ENABLED(WBTEST_MMAP_SYSCALL_FAIL));
+ rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(12) ERR_DBFILERR, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5,
+ LEN_AND_STR(syscall), CALLFROM, save_errno);
}
- /* In addition to updating the internal map values, gds_map_moved also updates cs_data to point to the remapped file */
- gds_map_moved(cs_addrs->db_addrs[0], old_base[0], old_base[1], (off_t)stat_buf.st_size);
+ gds_map_moved(mmap_retaddr, old_db_addrs[0], old_db_addrs[1], mmap_sz); /* updates cs_addrs->db_addrs[1] */
+ cs_addrs->db_addrs[0] = mmap_retaddr;
cs_addrs->total_blks = cs_addrs->ti->total_blks;
if (!was_crit)
rel_crit(gv_cur_region);
- sigprocmask(SIG_SETMASK, &savemask, NULL);
return;
}
#else /* !MM_FILE_EXT_OK */
@@ -882,29 +894,13 @@ void wcs_mm_recover(gd_region *reg)
{
unsigned char *end, buff[MAX_ZWR_KEY_SZ];
- if (NULL == (end = format_targ_key(buff, MAX_ZWR_KEY_SZ, gv_currkey, TRUE)))
- end = &buff[MAX_ZWR_KEY_SZ - 1];
- rts_error(VARLSTCNT(6) ERR_GBLOFLOW, 0, ERR_GVIS, 2, end - buff, buff);
- return;
-}
-#endif
-#elif defined(VMS)
-/* wcs_mm_recover is not yet implemented on VMS */
-void wcs_mm_recover(gd_region *reg)
-{
- unsigned char *end, buff[MAX_ZWR_KEY_SZ];
-
assert(&FILE_INFO(reg)->s_addrs == cs_addrs);
- assert(cs_addrs->now_crit);
assert(cs_addrs->hdr == cs_data);
- if (!cs_addrs->hold_onto_crit)
- rel_crit(gv_cur_region);
+ if (cs_addrs->now_crit && !cs_addrs->hold_onto_crit)
+ rel_crit(reg);
if (NULL == (end = format_targ_key(buff, MAX_ZWR_KEY_SZ, gv_currkey, TRUE)))
end = &buff[MAX_ZWR_KEY_SZ - 1];
- rts_error(VARLSTCNT(6) ERR_GBLOFLOW, 0, ERR_GVIS, 2, end - buff, buff);
+ rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(6) ERR_GBLOFLOW, 0, ERR_GVIS, 2, end - buff, buff);
return;
}
-
-#else
-# error UNSUPPORTED PLATFORM
#endif
diff --git a/sr_port/wcs_verify.c b/sr_port/wcs_verify.c
index 87f9caf..1284bf8 100644
--- a/sr_port/wcs_verify.c
+++ b/sr_port/wcs_verify.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -33,7 +33,12 @@
/* global refs/defs */
/* defines */
-#define FAKE_DIRTY ((trans_num)(-1))
+#define FAKE_DIRTY ((trans_num)(-1))
+#ifdef UNIX
+#define SEND_MSG_CSA(...) send_msg_csa(CSA_ARG(csa) __VA_ARGS__) /* to avoid formatting various send_msg calls */
+#else
+#define SEND_MSG_CSA send_msg
+#endif
GBLREF uint4 process_id;
@@ -85,14 +90,14 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
csd = csa->hdr;
cnl = csa->nl;
ret = TRUE;
- send_msg(VARLSTCNT(7) ERR_DBWCVERIFYSTART, 5, DB_LEN_STR(reg), process_id, process_id, &csd->trans_hist.curr_tn);
+ SEND_MSG_CSA(VARLSTCNT(7) ERR_DBWCVERIFYSTART, 5, DB_LEN_STR(reg), process_id, process_id, &csd->trans_hist.curr_tn);
/* while some errors terminate loops, as of this writing, no errors are treated as terminal */
if ((csa->now_crit == FALSE) && (csd->clustered == FALSE))
{
assert(expect_damage);
assert(!csa->hold_onto_crit);
ret = FALSE;
- send_msg(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg), RTS_ERROR_TEXT("now_crit"), csa->now_crit, TRUE);
+ SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg), RTS_ERROR_TEXT("now_crit"), csa->now_crit, TRUE);
grab_crit(reg); /* what if it has it but lost track of it ??? should there be a crit reset ??? */
}
if (dba_mm != csd->acc_meth)
@@ -102,7 +107,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(8) ERR_DBFHEADERRANY, 6, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERRANY, 6, DB_LEN_STR(reg),
RTS_ERROR_TEXT("bt_header_off"), cnl->bt_header_off, offset);
cnl->bt_header_off = offset;
}
@@ -110,7 +115,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(8) ERR_DBFHEADERRANY, 6, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERRANY, 6, DB_LEN_STR(reg),
RTS_ERROR_TEXT("bt_header"), csa->bt_header, (sm_uc_ptr_t)csd + cnl->bt_header_off);
csa->bt_header = (bt_rec_ptr_t)((sm_uc_ptr_t)csd + cnl->bt_header_off);
}
@@ -119,7 +124,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(8) ERR_DBFHEADERRANY, 6, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERRANY, 6, DB_LEN_STR(reg),
RTS_ERROR_TEXT("th_base_off"), cnl->th_base_off, offset + SIZEOF(bt->blkque));
cnl->th_base_off = (offset + SIZEOF(bt->blkque));
}
@@ -127,7 +132,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(8) ERR_DBFHEADERRANY, 6, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERRANY, 6, DB_LEN_STR(reg),
RTS_ERROR_TEXT("th_base"), csa->th_base, (sm_uc_ptr_t)csd + cnl->th_base_off);
csa->th_base = (th_rec_ptr_t)((sm_uc_ptr_t)csd + cnl->th_base_off);
}
@@ -136,7 +141,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(8) ERR_DBFHEADERRANY, 6, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERRANY, 6, DB_LEN_STR(reg),
RTS_ERROR_TEXT("bt_base_off"), cnl->bt_base_off, offset);
cnl->bt_base_off = offset;
}
@@ -144,7 +149,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(8) ERR_DBFHEADERRANY, 6, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERRANY, 6, DB_LEN_STR(reg),
RTS_ERROR_TEXT("bt_base"), csa->bt_base, (sm_uc_ptr_t)csd + cnl->bt_base_off);
csa->bt_base = (bt_rec_ptr_t)((sm_uc_ptr_t)csd + cnl->bt_base_off);
}
@@ -154,7 +159,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(8) ERR_DBFHEADERRANY, 6, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERRANY, 6, DB_LEN_STR(reg),
RTS_ERROR_TEXT("csa->ti"), (sm_uc_ptr_t)csa->ti, (sm_uc_ptr_t)&csd->trans_hist);
csa->ti = &csd->trans_hist;
}
@@ -166,7 +171,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(8) ERR_DBFHEADERRANY, 6, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERRANY, 6, DB_LEN_STR(reg),
RTS_ERROR_TEXT("cache_off"), cnl->cache_off, -CACHE_CONTROL_SIZE(csd));
cnl->cache_off = -CACHE_CONTROL_SIZE(csd);
}
@@ -174,7 +179,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(8) ERR_DBFHEADERRANY, 6, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERRANY, 6, DB_LEN_STR(reg),
RTS_ERROR_TEXT("cache_state"), csa->acc_meth.bg.cache_state, (sm_uc_ptr_t)csd + cnl->cache_off);
csa->acc_meth.bg.cache_state = (cache_que_heads_ptr_t)((sm_uc_ptr_t)csd + cnl->cache_off);
}
@@ -182,7 +187,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg),
RTS_ERROR_TEXT("bt_buckets"), csd->bt_buckets, getprime(n_bts));
csd->bt_buckets = getprime(n_bts);
}
@@ -190,19 +195,19 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
if (JNL_ALLOWED(csd))
{
if (NULL == csa->jnl)
- send_msg(VARLSTCNT(8) ERR_DBFHEADERRANY, 6, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERRANY, 6, DB_LEN_STR(reg),
RTS_ERROR_TEXT("csa->jnl"), csa->jnl, (UINTPTR_T)-1);
else if (NULL == csa->jnl->jnl_buff)
- send_msg(VARLSTCNT(8) ERR_DBFHEADERRANY, 6, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERRANY, 6, DB_LEN_STR(reg),
RTS_ERROR_TEXT("csa->jnl->jnl_buff"), csa->jnl->jnl_buff, (UINTPTR_T)-1);
else
{
- jnl_buff_expected = ((sm_uc_ptr_t)(cnl) + NODE_LOCAL_SPACE + JNL_NAME_EXP_SIZE);
+ jnl_buff_expected = ((sm_uc_ptr_t)(cnl) + NODE_LOCAL_SPACE(csd) + JNL_NAME_EXP_SIZE);
if (csa->jnl->jnl_buff != (jnl_buffer_ptr_t)jnl_buff_expected)
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(8) ERR_DBFHEADERRANY, 6, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERRANY, 6, DB_LEN_STR(reg),
RTS_ERROR_TEXT("csa->jnl->jnl_buff_expected"), csa->jnl->jnl_buff, jnl_buff_expected);
csa->jnl->jnl_buff = (jnl_buffer_ptr_t)jnl_buff_expected;
}
@@ -224,7 +229,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{ /* in UNIX this blocks the writer */
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg),
RTS_ERROR_TEXT("wc_blocked"), cnl->wc_blocked, TRUE);
SET_TRACEABLE_VAR(cnl->wc_blocked, TRUE);
}
@@ -232,7 +237,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
if (0 != in_wtstart)
{ /* caller should outwait active writers */
ret = FALSE;
- send_msg(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg), RTS_ERROR_TEXT("in_wtstart"),
+ SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg), RTS_ERROR_TEXT("in_wtstart"),
in_wtstart, 0);
assert(expect_damage);
cnl->in_wtstart = 0;
@@ -255,7 +260,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
* happens first. The INCR_INTENT_WTSTART macro has a double increment to take care of this
* case.
*/
- send_msg(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg),
RTS_ERROR_TEXT("intent_wtstart"), intent_wtstart, 0);
cnl->intent_wtstart = 0;
SHM_WRITE_MEMORY_BARRIER;
@@ -264,7 +269,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
if (0 != wcs_phase2_commit_pidcnt)
{ /* caller should outwait active committers */
ret = FALSE;
- send_msg(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg),
RTS_ERROR_TEXT("wcs_phase2_commit_pidcnt"), wcs_phase2_commit_pidcnt, 0);
assert(expect_damage);
cnl->wcs_phase2_commit_pidcnt = 0;
@@ -276,7 +281,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg),
RTS_ERROR_TEXT("th_base->blk"), th->blk, BT_QUEHEAD);
th->blk = BT_QUEHEAD;
}
@@ -290,7 +295,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg), th_prev, -1,
+ SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg), th_prev, -1,
RTS_ERROR_TEXT("th->tnque"), bt, bt_lo, SIZEOF(bt_rec));
break;
}
@@ -298,7 +303,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), th_prev, -1,
+ SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), th_prev, -1,
bt, RTS_ERROR_TEXT("th->tnque"), bt_lo, bt_hi);
break;
}
@@ -306,8 +311,9 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), th, th->blk, RTS_ERROR_TEXT("tnque.bl"),
- (UINTPTR_T)th->tnque.bl, (sm_uc_ptr_t)th_prev - (sm_uc_ptr_t)th);
+ SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), th, th->blk,
+ RTS_ERROR_TEXT("tnque.bl"), (UINTPTR_T)th->tnque.bl,
+ (sm_uc_ptr_t)th_prev - (sm_uc_ptr_t)th);
}
if (th->tn != 0)
{
@@ -316,7 +322,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
assert(expect_damage);
ret = FALSE;
tmp_8byte = 1;
- send_msg(VARLSTCNT(11) ERR_DBADDRANGE8, 9, DB_LEN_STR(reg), th, th->blk, &max_tn,
+ SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRANGE8, 9, DB_LEN_STR(reg), th, th->blk, &max_tn,
RTS_ERROR_TEXT("tnque transaction number"), &tmp_8byte, &th->tn);
}
/* ideally, the following max_tn assignment should have been in the else part of the above if. but
@@ -332,7 +338,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg),
th, th->blk, th->blk, RTS_ERROR_TEXT("th->blk"), 0, csd->trans_hist.total_blks);
}
if (((int)(th->cache_index) != CR_NOTVALID) &&
@@ -340,21 +346,21 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg),
th, th->blk, th->cache_index, RTS_ERROR_TEXT("th->cache_index"), cr_base, cr_top);
}
if (th->flushing != FALSE) /* ??? this is a gt.cx item that may require more synchronization at the top */
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg),
RTS_ERROR_TEXT("th->flushing"), th->flushing, FALSE);
}
if (0 == th->tnque.fl)
{ /* No point proceeding to next iteration of loop as "th + th->tnque.fl" will be the same as "th" */
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg),
th, th->blk, RTS_ERROR_TEXT("tnque.fl"), (UINTPTR_T)th->tnque.fl, (UINTPTR_T)-1);
break;
}
@@ -363,20 +369,20 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg),
RTS_ERROR_TEXT("tnque entries"), n_bts - cnt, n_bts - 1);
} else if ((th == csa->th_base) && ((th_rec_ptr_t)((sm_uc_ptr_t)th + th->tnque.bl) != th_prev))
{ /* at this point "th" is csa->th_base and its backlink does not point to the last entry in the th queue */
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), th, th->blk,
+ SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), th, th->blk,
RTS_ERROR_TEXT("tnque th_base"), (UINTPTR_T)th->tnque.bl, (sm_uc_ptr_t)th_prev - (sm_uc_ptr_t)th);
}
if (max_tn > csd->trans_hist.curr_tn)
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(8) ERR_DBFHEADERR8, 6, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERR8, 6, DB_LEN_STR(reg),
RTS_ERROR_TEXT("MAX(th_base->tn)"), &max_tn, &csd->trans_hist.curr_tn);
}
/* loop through bt blkques */
@@ -388,7 +394,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg),
RTS_ERROR_TEXT("queue head bt->blk"), bt0->blk, BT_QUEHEAD);
bt0->blk = BT_QUEHEAD;
}
@@ -400,7 +406,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg), bt_prev, -1,
+ SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg), bt_prev, -1,
RTS_ERROR_TEXT("bt->blkque"), bt, bt_lo, SIZEOF(bt_rec));
break;
}
@@ -408,7 +414,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), bt_prev, -1,
+ SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), bt_prev, -1,
bt, RTS_ERROR_TEXT("bt->blkque"), bt_lo, bt_hi);
break;
}
@@ -416,7 +422,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), bt, bt->blk,
+ SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), bt, bt->blk,
RTS_ERROR_TEXT("bt->blkque.bl"), (UINTPTR_T)bt->blkque.bl,
(sm_uc_ptr_t)bt_prev - (sm_uc_ptr_t)bt);
}
@@ -426,7 +432,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), bt, bt->blk,
+ SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), bt, bt->blk,
RTS_ERROR_TEXT("bt hash"), (bt0 - csa->bt_header),
(UINTPTR_T)(bt->blk % csd->bt_buckets));
}
@@ -438,19 +444,19 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg),
bt, bt->blk, cr, RTS_ERROR_TEXT("bt->cache_index"), cr_lo, cr_hi);
} else if (CR_NOT_ALIGNED(cr, cr_lo))
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg), bt, bt->blk,
+ SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg), bt, bt->blk,
RTS_ERROR_TEXT("bt->cache_index"), cr, cr_lo, SIZEOF(cache_rec));
} else if (cr->blk != bt->blk)
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr,
+ SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr,
bt->blk, RTS_ERROR_TEXT("bt block"), cr->blk, bt->blk,
CALLFROM);
}
@@ -461,7 +467,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{ /* No point proceeding to next iteration as "bt + bt->blkque.fl" will be the same as "bt" */
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), bt, bt->blk,
+ SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), bt, bt->blk,
RTS_ERROR_TEXT("bt->blkque.fl"), (UINTPTR_T)bt->blkque.fl, (UINTPTR_T)-1);
break;
}
@@ -470,13 +476,13 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(8) ERR_DBFHEADERR4, 6, DB_LEN_STR(reg),
RTS_ERROR_TEXT("btque entries"), n_bts + 1 - cnt, n_bts + 1);
} else if ((bt == bt0) && ((bt_rec_ptr_t)((sm_uc_ptr_t)bt + bt->blkque.bl) != bt_prev))
{ /* at this point "bt" is bt0 and its backlink does not point to last entry in the bt0'th queue */
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), bt, bt->blk,
+ SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), bt, bt->blk,
RTS_ERROR_TEXT("btque bt_base"), (UINTPTR_T)bt->blkque.bl,
(sm_uc_ptr_t)bt_prev - (sm_uc_ptr_t)bt);
}
@@ -488,7 +494,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), bt, bt->blk,
+ SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), bt, bt->blk,
RTS_ERROR_TEXT("bt blkque hash"), (UINTPTR_T)-1, (UINTPTR_T)(bt->blk % csd->bt_buckets));
}
}
@@ -508,7 +514,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
"secshr_max_index exceeded. max_index = %d [0x%08x] : ops_index = %d [0x%08x]",
SECSHR_OPS_ARRAY_SIZE, SECSHR_OPS_ARRAY_SIZE,
cnl->secshr_ops_index, cnl->secshr_ops_index);
- send_msg(VARLSTCNT(6) ERR_DBCLNUPINFO, 4, DB_LEN_STR(reg), RTS_ERROR_TEXT(secshr_string));
+ SEND_MSG_CSA(VARLSTCNT(6) ERR_DBCLNUPINFO, 4, DB_LEN_STR(reg), RTS_ERROR_TEXT(secshr_string));
cnl->secshr_ops_index = SECSHR_OPS_ARRAY_SIZE;
}
for (i = 0; (i + 1) < cnl->secshr_ops_index; i += (int4)cnl->secshr_ops_array[i])
@@ -519,7 +525,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
SPRINTF(secshr_string_delta, " : [0x%08lx]", cnl->secshr_ops_array[lcnt]);
strcat(secshr_string, secshr_string_delta);
}
- send_msg(VARLSTCNT(6) ERR_DBCLNUPINFO, 4, DB_LEN_STR(reg), RTS_ERROR_TEXT(secshr_string));
+ SEND_MSG_CSA(VARLSTCNT(6) ERR_DBCLNUPINFO, 4, DB_LEN_STR(reg), RTS_ERROR_TEXT(secshr_string));
}
cnl->secshr_ops_index = 0;
}
@@ -532,7 +538,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg),
cr, cr->blk, cr->blk, RTS_ERROR_TEXT("cr->blk"), 0, csd->trans_hist.total_blks);
}
if (cr->tn > csd->trans_hist.curr_tn)
@@ -540,7 +546,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
assert(expect_damage);
ret = FALSE;
tmp_8byte = 0;
- send_msg(VARLSTCNT(11) ERR_DBADDRANGE8, 9, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRANGE8, 9, DB_LEN_STR(reg),
cr, cr->blk, &cr->tn, RTS_ERROR_TEXT("cr->tn"), &tmp_8byte, &csd->trans_hist.curr_tn);
}
if (0 != cr->bt_index)
@@ -549,14 +555,14 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg),
cr, cr->blk, cr->bt_index, RTS_ERROR_TEXT("cr->bt_index"), bt_base_off,
bt_top_off);
} else if (!IS_PTR_ALIGNED(cr->bt_index, bt_base_off, SIZEOF(bt_rec)))
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg),
cr, cr->blk, RTS_ERROR_TEXT("cr->bt_index"), cr->bt_index, bt_base_off,
SIZEOF(bt_rec));
} else
@@ -566,7 +572,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr,
+ SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr,
cr->blk, RTS_ERROR_TEXT("cr block"), cr->blk, bt->blk,
CALLFROM);
}
@@ -576,33 +582,33 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg),
cr, cr->blk, cr->buffaddr, RTS_ERROR_TEXT("cr->buffaddr"), bp_lo, bp_top);
} else if (!IS_PTR_ALIGNED(cr->buffaddr, bp_lo, csd->blk_size))
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg),
cr, cr->blk, RTS_ERROR_TEXT("cr->buffaddr"), cr->buffaddr, bp_lo, csd->blk_size);
} else if (cr->buffaddr != bp)
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg),
cr, cr->blk, RTS_ERROR_TEXT("cr->buffaddr"), cr->buffaddr, bp, CALLFROM);
}
if (cr->in_tend)
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg),
cr, cr->blk, RTS_ERROR_TEXT("cr->in_tend"), cr->in_tend, FALSE, CALLFROM);
}
if (cr->data_invalid)
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg),
cr, cr->blk, RTS_ERROR_TEXT("cr->data_invalid"), cr->data_invalid, FALSE, CALLFROM);
}
if (cr->r_epid != 0)
@@ -611,7 +617,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg),
cr, cr->blk, RTS_ERROR_TEXT("cr->r_epid"), cr->r_epid, 0, CALLFROM);
}
} else if ((-1 == cr->read_in_progress) && !caller_is_wcs_recover && (CR_BLKEMPTY != cr->blk)
@@ -634,10 +640,10 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg),
cr, cr->blk, RTS_ERROR_TEXT("Block certification result"),
FALSE, TRUE, CALLFROM);
- send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk,
+ SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk,
RTS_ERROR_TEXT("Block certification result buffer"),
bptmp, csa->lock_addrs[0], CALLFROM);
}
@@ -646,7 +652,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg),
cr, cr->blk, RTS_ERROR_TEXT("cr->in_cw_set"), (uint4)cr->in_cw_set, 0, CALLFROM);
}
assert(!JNL_ALLOWED(csd) || (NULL != csa->jnl) && (NULL != csa->jnl->jnl_buff));
@@ -657,7 +663,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), cr, cr->blk,
+ SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), cr, cr->blk,
(uint4)cr->jnl_addr, RTS_ERROR_TEXT("cr->jnl_addr"), 0,
csa->jnl->jnl_buff->freeaddr);
}
@@ -665,14 +671,14 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg),
cr, cr->blk, RTS_ERROR_TEXT("cr->jnl_addr"), (uint4)cr->jnl_addr, 0, CALLFROM);
}
if ((WRITE_LATCH_VAL(cr) < LATCH_CLEAR) || (WRITE_LATCH_VAL(cr) > LATCH_CONFLICT))
{ /* the message would read cr->interlock.semaphore although in Unix it means cr->interlock.latch */
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), cr, cr->blk,
+ SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), cr, cr->blk,
WRITE_LATCH_VAL(cr), RTS_ERROR_TEXT("cr->interlock.semaphore"), LATCH_CLEAR,
LATCH_CONFLICT);
}
@@ -682,7 +688,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk,
+ SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk,
RTS_ERROR_TEXT("cr->rip_latch"), cr->rip_latch.u.parts.latch_pid, 0, CALLFROM);
}
if (cr->iosb.cond != 0)
@@ -697,17 +703,17 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
dummy_tn = (trans_num)TRUE;
- send_msg(VARLSTCNT(13) ERR_DBCRERR8, 11, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR8, 11, DB_LEN_STR(reg),
cr, cr->blk, RTS_ERROR_TEXT("cr->cr->dirty"), &cr->dirty, &dummy_tn, CALLFROM);
- send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg),
cr, cr->blk, RTS_ERROR_TEXT("cr->cr->iosb"), cr->iosb.cond, 0, CALLFROM);
}
if (0 == cr->epid)
{
assert(expect_damage);
- send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg),
cr, cr->blk, RTS_ERROR_TEXT("cr->epid"), cr->epid, -1, CALLFROM);
- send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg),
cr, cr->blk, RTS_ERROR_TEXT("cr->iosb"), cr->iosb.cond, 0, CALLFROM);
}
}
@@ -716,7 +722,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
assert(expect_damage);
ret = FALSE;
dummy_tn = (trans_num)TRUE;
- send_msg(VARLSTCNT(13) ERR_DBCRERR8, 11, DB_LEN_STR(reg), cr, cr->blk,
+ SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR8, 11, DB_LEN_STR(reg), cr, cr->blk,
RTS_ERROR_TEXT("cr->dirty"), &cr->dirty, &dummy_tn, CALLFROM);
}
if (cr->twin != 0)
@@ -726,19 +732,19 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg),
cr, cr->blk, cr_tmp, RTS_ERROR_TEXT("cr->twin"), cr_lo, cr_hi);
} else if (CR_NOT_ALIGNED(cr_tmp, cr_lo))
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg),
cr, cr->blk, RTS_ERROR_TEXT("cr->twin"), cr_tmp, cr_lo, SIZEOF(cache_rec));
} else if (cr != (cache_rec_ptr_t)GDS_ANY_REL2ABS(csa, cr_tmp->twin))
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr_tmp, cr->blk,
+ SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr_tmp, cr->blk,
RTS_ERROR_TEXT("cr->twin->twin"), GDS_ANY_REL2ABS(csa, cr_tmp->twin), cr,
CALLFROM);
}
@@ -749,21 +755,21 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg),
cr, cr->blk, RTS_ERROR_TEXT("cr->twin"), cr->twin, 0, CALLFROM);
}
if (0 != cr->image_count)
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg),
cr, cr->blk, RTS_ERROR_TEXT("cr->image_count"), cr->image_count, 0, CALLFROM);
}
if ((0 != cr->epid) && caller_is_wcs_recover)
{ /* if called from DSE CACHE -VERIFY, we do not wait for concurrent writers to finish */
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg),
cr, cr->blk, RTS_ERROR_TEXT("cr->epid"), cr->epid, 0, CALLFROM);
}
#endif
@@ -771,14 +777,14 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk,
+ SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk,
RTS_ERROR_TEXT("cr->wip_stopped"), cr->wip_stopped, FALSE, CALLFROM);
}
if (FALSE != cr->stopped)
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk,
+ SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk,
RTS_ERROR_TEXT("cr->stopped"), cr->stopped, FALSE, CALLFROM);
}
}
@@ -789,7 +795,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr0, cr0->blk,
+ SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr0, cr0->blk,
RTS_ERROR_TEXT("queue head cr->blk"), cr0->blk, BT_QUEHEAD, CALLFROM);
cr0->blk = BT_QUEHEAD;
}
@@ -801,7 +807,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg),
cr0, -1, cr, RTS_ERROR_TEXT("cr->blkque"), cr_lo, cr_hi);
break;
}
@@ -809,7 +815,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg),
cr0, -1, RTS_ERROR_TEXT("cr->blkque"), cr, cr_lo, SIZEOF(cache_rec));
break;
}
@@ -817,7 +823,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), cr, cr->blk,
+ SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), cr, cr->blk,
RTS_ERROR_TEXT("cr->blkque.bl"), (UINTPTR_T)cr->blkque.bl,
(sm_uc_ptr_t)cr_prev - (sm_uc_ptr_t)cr);
}
@@ -825,7 +831,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk,
+ SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk,
RTS_ERROR_TEXT("cr hash"), cr0 - cr_qbase, cr->blk % csd->bt_buckets, CALLFROM);
if (caller_is_wcs_recover && !cr->stopped)
{ /* if cr->stopped is TRUE, then the buffer was created by secshr_db_clnup(),
@@ -859,7 +865,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{ /* No point proceeding to next iteration as "cr + cr->blkque.fl" will be the same as "cr" */
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), cr, cr->blk,
+ SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), cr, cr->blk,
RTS_ERROR_TEXT("cr->blkque.fl"), (UINTPTR_T)cr->blkque.fl, (UINTPTR_T)-1);
break;
}
@@ -868,13 +874,13 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg),
cr_qbase, 0, RTS_ERROR_TEXT("crque entries"), (UINTPTR_T)(n_bts + 1), (UINTPTR_T)(n_bts));
} else if ((cr == cr0) && ((cache_rec_ptr_t)((sm_uc_ptr_t)cr + cr->blkque.bl) != cr_prev))
{ /* at this point "cr" is cr0 and its backlink does not point to last entry in the cr0'th queue */
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), cr, cr->blk,
+ SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), cr, cr->blk,
RTS_ERROR_TEXT("crque cr_base"), (UINTPTR_T)cr->blkque.bl,
(sm_uc_ptr_t)cr_prev - (sm_uc_ptr_t)cr);
}
@@ -886,7 +892,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk,
+ SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), cr, cr->blk,
RTS_ERROR_TEXT("cr blkque hash"), -1, cr->blk % csd->bt_buckets, CALLFROM);
if (caller_is_wcs_recover && !cr->stopped) /* see comment above ("cr hash") for similar handling */
{
@@ -901,7 +907,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), que_head, 0, RTS_ERROR_TEXT("cacheq_active"),
+ SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), que_head, 0, RTS_ERROR_TEXT("cacheq_active"),
que_head, ((sm_long_t)que_head / SIZEOF(que_head->fl)) * SIZEOF(que_head->fl));
}
/* loop through the active queue */
@@ -915,7 +921,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), que_head, -1,
+ SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), que_head, -1,
cr, RTS_ERROR_TEXT("active cstt->state_que"), cr_lo, cr_hi);
break;
}
@@ -923,7 +929,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg), que_head, -1,
+ SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg), que_head, -1,
RTS_ERROR_TEXT("active cstt->state_que"), cr, cr_lo, SIZEOF(cache_rec));
break;
}
@@ -931,7 +937,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), cstt, cstt->blk,
+ SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), cstt, cstt->blk,
RTS_ERROR_TEXT("active queue.bl"), (UINTPTR_T)cstt->state_que.bl,
(sm_uc_ptr_t)cstt_prev - (sm_uc_ptr_t)cstt);
}
@@ -940,7 +946,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
assert(expect_damage);
ret = FALSE;
dummy_tn = (trans_num)TRUE;
- send_msg(VARLSTCNT(13) ERR_DBCRERR8, 11, DB_LEN_STR(reg), cr, cstt->blk,
+ SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR8, 11, DB_LEN_STR(reg), cr, cstt->blk,
RTS_ERROR_TEXT("active cr->dirty"), &cstt->dirty, &dummy_tn, CALLFROM);
}
if (((0 != cstt->flushed_dirty_tn) && (cstt->dirty <= cstt->flushed_dirty_tn))
@@ -949,7 +955,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
assert(expect_damage);
ret = FALSE;
dummy_tn = cstt->flushed_dirty_tn + 1;
- send_msg(VARLSTCNT(11) ERR_DBADDRANGE8, 9, DB_LEN_STR(reg), cstt + SIZEOF(que_head), cstt->blk,
+ SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRANGE8, 9, DB_LEN_STR(reg), cstt + SIZEOF(que_head), cstt->blk,
&cstt->dirty, RTS_ERROR_TEXT("active dirty (tn)"), &dummy_tn, &csd->trans_hist.curr_tn);
}
/* if caller_is_wcs_recover, we would have waited for all writers to stop manipulating the active/wip queues
@@ -961,7 +967,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{ /* No point proceeding to next iteration as "cstt + cstt->state_que.fl" will be same as "cstt" */
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), cstt, cstt->blk,
+ SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), cstt, cstt->blk,
RTS_ERROR_TEXT("active queue.fl"), (UINTPTR_T)cstt->state_que.fl, (UINTPTR_T)-1);
break;
}
@@ -970,14 +976,14 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg),
que_head, 0, RTS_ERROR_TEXT("active queue entries"), (UINTPTR_T)(n_bts + 1), (UINTPTR_T)n_bts);
} else if ((cstt == (cache_state_rec_ptr_t)que_head)
&& ((cache_state_rec_ptr_t)((sm_uc_ptr_t)cstt + cstt->state_que.bl) != cstt_prev))
{ /* at this point "cstt" is active que_head and its backlink does not point to last entry in active queue */
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), cstt, 0, RTS_ERROR_TEXT("active queue base"),
+ SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), cstt, 0, RTS_ERROR_TEXT("active queue base"),
(UINTPTR_T)cstt->state_que.bl, (sm_uc_ptr_t)cstt_prev - (sm_uc_ptr_t)cstt);
}
@@ -987,7 +993,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), que_head, 0, RTS_ERROR_TEXT("cacheq_wip"),
+ SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), que_head, 0, RTS_ERROR_TEXT("cacheq_wip"),
que_head, ((sm_long_t)que_head / SIZEOF(que_head->fl)) * SIZEOF(que_head->fl));
}
#ifdef VMS
@@ -1000,7 +1006,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), que_head, -1,
+ SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), que_head, -1,
cr, RTS_ERROR_TEXT("wip cstt->state_que"), cr_lo, cr_hi);
break;
}
@@ -1008,7 +1014,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg), que_head, -1,
+ SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg), que_head, -1,
RTS_ERROR_TEXT("wip cstt->state_que"), cr, cr_lo, SIZEOF(cache_rec));
break;
}
@@ -1016,7 +1022,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), cstt, cstt->blk,
+ SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), cstt, cstt->blk,
RTS_ERROR_TEXT("wip queue.bl"), (UINTPTR_T)cstt->state_que.bl,
(sm_uc_ptr_t)cstt_prev - (sm_uc_ptr_t)cstt);
}
@@ -1025,7 +1031,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
* {
* assert(expect_damage);
* ret = FALSE;
- * send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg),
+ * SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg),
* cr, cstt->blk, RTS_ERROR_TEXT("wip cr->epid"), cstt->epid, -1, CALLFROM);
* }
*/
@@ -1034,7 +1040,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
assert(expect_damage);
ret = FALSE;
dummy_tn = (trans_num)TRUE;
- send_msg(VARLSTCNT(13) ERR_DBCRERR8, 11, DB_LEN_STR(reg), cr, cstt->blk,
+ SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR8, 11, DB_LEN_STR(reg), cr, cstt->blk,
RTS_ERROR_TEXT("wip cr->dirty"), &cstt->dirty, &dummy_tn, CALLFROM);
}
if (((0 != cstt->flushed_dirty_tn) && (cstt->dirty <= cstt->flushed_dirty_tn))
@@ -1043,8 +1049,9 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
assert(expect_damage);
ret = FALSE;
dummy_tn = cstt->flushed_dirty_tn + 1;
- send_msg(VARLSTCNT(11) ERR_DBADDRANGE8, 9, DB_LEN_STR(reg), (int)cstt + SIZEOF(que_head), cstt->blk,
- &cstt->dirty, RTS_ERROR_TEXT("wip dirty (tn)"), &dummy_tn, &csd->trans_hist.curr_tn);
+ SEND_MSG_CSA(VARLSTCNT(11) ERR_DBADDRANGE8, 9, DB_LEN_STR(reg), (int)cstt + SIZEOF(que_head),
+ cstt->blk, &cstt->dirty, RTS_ERROR_TEXT("wip dirty (tn)"), &dummy_tn,
+ &csd->trans_hist.curr_tn);
}
/* if caller_is_wcs_recover, we would have waited for all writers to stop manipulating the active/wip queues
* and so it is ok to do the FAKE_DIRTY check. but otherwise it is not.
@@ -1055,7 +1062,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), cstt, cstt->blk,
+ SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), cstt, cstt->blk,
RTS_ERROR_TEXT("wip queue.fl"), (UINTPTR_T)cstt->state_que.fl, (UINTPTR_T)-1);
break;
}
@@ -1064,14 +1071,14 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg),
que_head, 0, RTS_ERROR_TEXT("wip queue entries"), (UINTPTR_T)(n_bts + 1), (UINTPTR_T)n_bts);
} else if ((cstt == (cache_state_rec_ptr_t)que_head)
&& ((cache_state_rec_ptr_t)((sm_uc_ptr_t)cstt + cstt->state_que.bl) != cstt_prev))
{ /* at this point "cstt" is wip que_head and its backlink does not point to last entry in the wip queue */
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), cstt, 0, RTS_ERROR_TEXT("active queue base"),
+ SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), cstt, 0, RTS_ERROR_TEXT("active queue base"),
(UINTPTR_T)cstt->state_que.bl, (sm_uc_ptr_t)cstt_prev - (sm_uc_ptr_t)cstt);
}
#else
@@ -1079,7 +1086,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg),
que_head, 0, RTS_ERROR_TEXT("wip queue head fl"), (UINTPTR_T)que_head->fl, (UINTPTR_T)0);
que_head->fl = 0;
}
@@ -1087,7 +1094,7 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
{
assert(expect_damage);
ret = FALSE;
- send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg),
+ SEND_MSG_CSA(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg),
que_head, 0, RTS_ERROR_TEXT("wip queue head bl"), (UINTPTR_T)que_head->bl, (UINTPTR_T)0);
que_head->bl = 0;
}
@@ -1108,222 +1115,15 @@ boolean_t wcs_verify(gd_region *reg, boolean_t expect_damage, boolean_t caller_i
assert(expect_damage);
ret = FALSE;
dummy_tn = (trans_num)FALSE;
- send_msg(VARLSTCNT(13) ERR_DBCRERR8, 11, DB_LEN_STR(reg), cr, cr->blk,
+ SEND_MSG_CSA(VARLSTCNT(13) ERR_DBCRERR8, 11, DB_LEN_STR(reg), cr, cr->blk,
RTS_ERROR_TEXT("non-state cr->dirty"), &cr->dirty, &dummy_tn, CALLFROM);
}
}
}
}
- } else
- {
-# if defined(UNIX) && !defined(UNTARGETED_MSYNC) && !defined(NO_MSYNC)
- mbr_lo = (mmblk_rec_ptr_t)csa->acc_meth.mm.mmblk_state->mmblk_array + csd->bt_buckets;
- mbr_hi = mbr_lo + n_bts;
- /* loop through the mbr blkques */
- for (mbr0 = (mmblk_rec_ptr_t)csa->acc_meth.mm.mmblk_state->mmblk_array, mbr_qbase = mbr0; mbr0 < mbr_lo; mbr0++)
- {
- if (mbr0->blk != BT_QUEHEAD)
- {
- assert(expect_damage);
- ret = FALSE;
- send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), mbr0, mbr0->blk,
- RTS_ERROR_TEXT("queue head mbr->blk"), mbr0->blk, BT_QUEHEAD, CALLFROM);
- mbr0->blk = BT_QUEHEAD;
- }
- for (mbr_prev = mbr0, mbr = (mmblk_rec_ptr_t)((sm_uc_ptr_t)mbr0 + mbr0->blkque.fl), cnt = n_bts + 1;
- (mbr != mbr0) && (cnt > 0);
- mbr_prev = mbr, cnt--, mbr = (mmblk_rec_ptr_t)((sm_uc_ptr_t)mbr + mbr->blkque.fl))
- {
- if (MBR_NOT_IN_RANGE(mbr, mbr_lo, mbr_hi))
- {
- assert(expect_damage);
- ret = FALSE;
- send_msg(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg),
- mbr0, -1, mbr, RTS_ERROR_TEXT("mbr->blkque"), mbr_lo, mbr_hi);
- break;
- }
- if (MBR_NOT_ALIGNED(mbr, mbr_lo))
- {
- assert(expect_damage);
- ret = FALSE;
- send_msg(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg),
- mbr0, -1, RTS_ERROR_TEXT("mbr->blkque"), mbr, mbr_lo, SIZEOF(mmblk_rec));
- break;
- }
- if ((mmblk_rec_ptr_t)((sm_uc_ptr_t)mbr + mbr->blkque.bl) != mbr_prev)
- {
- assert(expect_damage);
- ret = FALSE;
- send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), mbr, mbr->blk,
- RTS_ERROR_TEXT("mbr->blkque.bl"), (UINTPTR_T)mbr->blkque.bl,
- (sm_uc_ptr_t)mbr_prev - (sm_uc_ptr_t)mbr);
- }
- if (((int)(mbr->blk) != MBR_BLKEMPTY) && ((mbr_qbase + (mbr->blk % csd->bt_buckets)) != mbr0))
- {
- assert(expect_damage);
- ret = FALSE;
- send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), mbr, mbr->blk,
- RTS_ERROR_TEXT("mbr hash"), mbr0 - mbr_qbase, mbr->blk % csd->bt_buckets,
- CALLFROM);
- }
- (*blkque_array)[mbr - mbr_lo] = TRUE; /* note: mbr's blkque hash validity is already checked */
- if (0 == mbr->blkque.fl)
- { /* Don't proceed to next iteration as "mbr + mbr->blkque.fl" will be the same as "mbr" */
- assert(expect_damage);
- ret = FALSE;
- send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), mbr, mbr->blk,
- RTS_ERROR_TEXT("mbr->blkque.fl"), (UINTPTR_T)mbr->blkque.fl, (UINTPTR_T)-1);
- break;
- }
- }
- if (cnt == 0)
- {
- assert(expect_damage);
- ret = FALSE;
- send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg),
- mbr_qbase, 0, RTS_ERROR_TEXT("mbrque entries"), (UINTPTR_T)(n_bts + 1),
- (UINTPTR_T)(n_bts));
- } else if ((mbr == mbr0) && ((mmblk_rec_ptr_t)((sm_uc_ptr_t)mbr + mbr->blkque.bl) != mbr_prev))
- { /* at this point "mbr" is mbr0 and its backlink does not point to last entry in the mbr0'th queue */
- assert(expect_damage);
- ret = FALSE;
- send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), mbr, mbr->blk,
- RTS_ERROR_TEXT("mbrque mbr_base"), (UINTPTR_T)mbr->blkque.bl,
- (sm_uc_ptr_t)mbr_prev - (sm_uc_ptr_t)mbr);
- }
- }
- /* scan all mbrs looking for non-empty mbr->blks whose mbrs were not in any blkque */
- for (mbr = mbr_lo; mbr < mbr_hi; mbr++)
- {
- if ((FALSE == (*blkque_array)[mbr - mbr_lo]) && ((int)(mbr->blk) != MBR_BLKEMPTY))
- {
- assert(expect_damage);
- ret = FALSE;
- send_msg(VARLSTCNT(13) ERR_DBCRERR, 11, DB_LEN_STR(reg), mbr, mbr->blk,
- RTS_ERROR_TEXT("mbr blkque hash"), -1, mbr->blk % csd->bt_buckets, CALLFROM);
- }
- }
- que_head = &csa->acc_meth.mm.mmblk_state->mmblkq_active;
- if ((sm_long_t)que_head % SIZEOF(que_head->fl) != 0)
- {
- assert(expect_damage);
- ret = FALSE;
- send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), que_head, 0, RTS_ERROR_TEXT("mmblkq_active"),
- que_head, ((sm_long_t)que_head / SIZEOF(que_head->fl)) * SIZEOF(que_head->fl));
- }
- /* loop through the active queue */
- for (mbstt_prev = (mmblk_state_rec_ptr_t)que_head,
- mbstt = (mmblk_state_rec_ptr_t)((sm_uc_ptr_t)que_head + que_head->fl), cnt = n_bts;
- (mbstt != (mmblk_state_rec_ptr_t)que_head) && (cnt > 0);
- mbstt_prev = mbstt, cnt--, mbstt = (mmblk_state_rec_ptr_t)((sm_uc_ptr_t)mbstt + mbstt->state_que.fl))
- {
- mbr = (mmblk_rec_ptr_t)((sm_uc_ptr_t)mbstt - SIZEOF(mbr->blkque));
- if (MBR_NOT_IN_RANGE((mmblk_rec_ptr_t)mbr, mbr_lo, mbr_hi))
- {
- assert(expect_damage);
- ret = FALSE;
- send_msg(VARLSTCNT(11) ERR_DBADDRANGE, 9, DB_LEN_STR(reg), que_head, -1,
- mbr, RTS_ERROR_TEXT("active mbstt->state_que"), mbr_lo, mbr_hi);
- break;
- }
- if (MBR_NOT_ALIGNED(mbr, mbr_lo))
- {
- assert(expect_damage);
- ret = FALSE;
- send_msg(VARLSTCNT(11) ERR_DBADDRALIGN, 9, DB_LEN_STR(reg), que_head, -1,
- RTS_ERROR_TEXT("active mbstt->state_que"), mbr, mbr_lo, SIZEOF(mmblk_rec));
- break;
- }
- if ((mmblk_state_rec_ptr_t)((sm_uc_ptr_t)mbstt + mbstt->state_que.bl) != mbstt_prev)
- {
- assert(expect_damage);
- ret = FALSE;
- send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), mbstt, mbstt->blk,
- RTS_ERROR_TEXT("active queue.bl"), (UINTPTR_T)mbstt->state_que.bl,
- (sm_uc_ptr_t)mbstt_prev - (sm_uc_ptr_t)mbstt);
- }
- if (0 == mbstt->dirty)
- {
- assert(expect_damage);
- ret = FALSE;
- dummy_tn = (trans_num)TRUE;
- send_msg(VARLSTCNT(13) ERR_DBCRERR8, 11, DB_LEN_STR(reg), mbr, mbstt->blk,
- RTS_ERROR_TEXT("active mbr->dirty"), &mbstt->dirty, &dummy_tn, CALLFROM);
- }
- /* if caller_is_wcs_recover, we would have waited for all writers to stop manipulating the active/wip queues
- * and so it is ok to do the FAKE_DIRTY check. but otherwise it is not.
- */
- if (caller_is_wcs_recover)
- mbstt->dirty = FAKE_DIRTY; /* change the flag to indicate it was found in a state queue */
- if (0 == mbstt->state_que.fl)
- { /* No point proceeding to next iteration as "mbstt + mbstt->state_que.fl" will be same as "mbstt" */
- assert(expect_damage);
- ret = FALSE;
- send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), mbstt, mbstt->blk,
- RTS_ERROR_TEXT("active queue.fl"), (UINTPTR_T)mbstt->state_que.fl, (UINTPTR_T)-1);
- break;
- }
- }
- if (cnt == 0)
- {
- assert(expect_damage);
- ret = FALSE;
- send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg),
- que_head, 0, RTS_ERROR_TEXT("active queue entries"), (UINTPTR_T)(n_bts + 1), (UINTPTR_T)n_bts);
- } else if ((mbstt == (mmblk_state_rec_ptr_t)que_head)
- && ((mmblk_state_rec_ptr_t)((sm_uc_ptr_t)mbstt + mbstt->state_que.bl) != mbstt_prev))
- { /* at this point "mbstt" is active que_head and its backlink does not point to last entry in active queue */
- assert(expect_damage);
- ret = FALSE;
- send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), mbstt, 0, RTS_ERROR_TEXT("active queue base"),
- (UINTPTR_T)mbstt->state_que.bl, (sm_uc_ptr_t)mbstt_prev - (sm_uc_ptr_t)mbstt);
- }
-
- /* loop through the wip queue */
- que_head = &csa->acc_meth.mm.mmblk_state->mmblkq_wip;
- if ((sm_long_t)que_head % SIZEOF(que_head->fl) != 0)
- {
- assert(expect_damage);
- ret = FALSE;
- send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg), que_head, 0, RTS_ERROR_TEXT("mmblkq_wip"),
- que_head, ((sm_long_t)que_head / SIZEOF(que_head->fl)) * SIZEOF(que_head->fl));
- }
- if (que_head->fl != 0)
- {
- assert(expect_damage);
- ret = FALSE;
- send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg),
- que_head, 0, RTS_ERROR_TEXT("wip queue head fl"), (UINTPTR_T)que_head->fl, (UINTPTR_T)0);
- que_head->fl = 0;
- }
- if (que_head->bl != 0)
- {
- assert(expect_damage);
- ret = FALSE;
- send_msg(VARLSTCNT(10) ERR_DBQUELINK, 8, DB_LEN_STR(reg),
- que_head, 0, RTS_ERROR_TEXT("wip queue head bl"), (UINTPTR_T)que_head->bl, (UINTPTR_T)0);
- que_head->bl = 0;
- }
- /* if caller_is_wcs_recover, we would have waited for all writers to stop manipulating the active/wip queues
- * and so it is ok to do the FAKE_DIRTY check. but otherwise it is not.
- */
- if (caller_is_wcs_recover)
- { /* loop through the mmblk_recs again to look for lost dirties */
- for (mbr = mbr_lo, cnt = n_bts; cnt > 0; mbr++, cnt--)
- {
- if (0 != mbr->dirty)
- {
- assert(expect_damage);
- ret = FALSE;
- dummy_tn = (trans_num)FALSE;
- send_msg(VARLSTCNT(13) ERR_DBCRERR8, 11, DB_LEN_STR(reg), mbr, mbr->blk,
- RTS_ERROR_TEXT("non-state mbr->dirty"), &mbr->dirty, &dummy_tn, CALLFROM);
- }
- }
- }
-# endif
}
- send_msg(VARLSTCNT(7) ERR_DBWCVERIFYEND, 5, DB_LEN_STR(reg), process_id, process_id, &csd->trans_hist.curr_tn);
- if (NULL != blkque_array) free(blkque_array);
+ SEND_MSG_CSA(VARLSTCNT(7) ERR_DBWCVERIFYEND, 5, DB_LEN_STR(reg), process_id, process_id, &csd->trans_hist.curr_tn);
+ if (NULL != blkque_array)
+ free(blkque_array);
return ret;
}
diff --git a/sr_port/xfer.h b/sr_port/xfer.h
index 03d6151..0ec34f6 100644
--- a/sr_port/xfer.h
+++ b/sr_port/xfer.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -297,4 +297,9 @@ XFER(xf_stoglvn, op_stoglvn),
XFER(xf_rfrshgvn, op_rfrshgvn),
XFER(xf_indfnname2, op_indfnname2),
XFER(xf_indget2, op_indget2),
-XFER(xf_indmerge2, op_indmerge2)
+XFER(xf_indmerge2, op_indmerge2),
+#ifdef UNIX
+XFER(xf_fnzpeek, op_fnzpeek),
+#endif
+XFER(xf_litc, op_litc),
+XFER(xf_stolitc, op_stolitc)
diff --git a/sr_port/zlput_rname.c b/sr_port/zlput_rname.c
index 2e43608..3a84593 100644
--- a/sr_port/zlput_rname.c
+++ b/sr_port/zlput_rname.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -12,6 +12,7 @@
#include "mdef.h"
#include "gtm_string.h"
+#include "cmd_qlf.h"
#include <rtnhdr.h>
#include "stack_frame.h"
#include "hashtab_mname.h"
@@ -188,47 +189,45 @@ bool zlput_rname (rhdtyp *hdr)
tabent->value = NULL;
}
}
- NON_USHBIN_ONLY(
- hdr->old_rhead_ptr = (int4)old_rhead;
- if (!old_rhead->old_rhead_ptr)
- {
- fix_pages((unsigned char *)old_rhead, (unsigned char *)LNRTAB_ADR(old_rhead)
- + (SIZEOF(lnr_tabent) * old_rhead->lnrtab_len));
- }
- )
- USHBIN_ONLY(
- if (!old_rhead->shlib_handle)
- { /* Migrate text literals pointing into text area we are about to throw away into the stringpool.
- We also can release the read-only releasable segment as it is no longer needed.
+# ifndef USHBIN_SUPPORTED
+ hdr->old_rhead_ptr = (int4)old_rhead;
+ if (!old_rhead->old_rhead_ptr)
+ {
+ fix_pages((unsigned char *)old_rhead, (unsigned char *)LNRTAB_ADR(old_rhead)
+ + (SIZEOF(lnr_tabent) * old_rhead->lnrtab_len));
+ }
+# else /* USHBIN_SUPPORTED */
+ if (!old_rhead->shlib_handle)
+ { /* Migrate text literals pointing into text area we are about to throw away into the stringpool.
+ We also can release the read-only releasable segment as it is no longer needed.
+ */
+ stp_move((char *)old_rhead->literal_text_adr,
+ (char *)(old_rhead->literal_text_adr + old_rhead->literal_text_len));
+ if (tabent)
+ { /* There was (at one time) a $TEXT source section for this routine. We may have just
+ released it but whether the source was for the routine just replaced or for an earlier
+ replacement, the key for that segment is pointing into the readonly storage we
+ are just about to release. Replace the key with the current one for this routine.
*/
- stp_move((char *)old_rhead->literal_text_adr,
- (char *)(old_rhead->literal_text_adr + old_rhead->literal_text_len));
- if (tabent)
- { /* There was (at one time) a $TEXT source section for this routine. We may have just
- released it but whether the source was for the routine just replaced or for an earlier
- replacement, the key for that segment is pointing into the readonly storage we
- are just about to release. Replace the key with the current one for this routine.
- */
- assert(MSTR_EQ(&tabent->key.var_name, rtn_name));
- tabent->key.var_name = *rtn_name; /* Update key with newly saved mident */
- }
- zlmov_lnames(old_rhead); /* copy the label names from literal pool to malloc'd area */
- GTM_TEXT_FREE(old_rhead->ptext_adr);
- /* Reset the routine header pointers to the sections we just freed up.
- * NOTE: literal_text_adr shouldn't be reset as it points to the label area malloc'd
- * in zlmov_lnames() */
- old_rhead->ptext_adr = old_rhead->ptext_end_adr = NULL;
- old_rhead->lnrtab_adr = NULL;
+ assert(MSTR_EQ(&tabent->key.var_name, rtn_name));
+ tabent->key.var_name = *rtn_name; /* Update key with newly saved mident */
}
- urx_remove(old_rhead);
- free(old_rhead->literal_adr); /* Release the read-write releasable segments */
- old_rhead->literal_adr = NULL;
- old_rhead->vartab_adr = NULL;
-
- free(old_rhead->linkage_adr); /* Release the old linkage section */
- old_rhead->linkage_adr = NULL;
- hdr->old_rhead_adr = old_rhead;
- )
+ zlmov_lnames(old_rhead); /* copy the label names from literal pool to malloc'd area */
+ GTM_TEXT_FREE(old_rhead->ptext_adr);
+ /* Reset the routine header pointers to the sections we just freed up.
+ * NOTE: literal_text_adr shouldn't be reset as it points to the label area malloc'd
+ * in zlmov_lnames() */
+ old_rhead->ptext_adr = old_rhead->ptext_end_adr = NULL;
+ old_rhead->lnrtab_adr = NULL;
+ }
+ urx_remove(old_rhead);
+ free(RW_REL_START_ADR(old_rhead)); /* Release the read-write releasable segments */
+ old_rhead->literal_adr = NULL;
+ old_rhead->vartab_adr = NULL;
+ free(old_rhead->linkage_adr); /* Release the old linkage section */
+ old_rhead->linkage_adr = NULL;
+ hdr->old_rhead_adr = old_rhead;
+# endif
mid->rt_name = *rtn_name;
}
mid->rt_adr= hdr;
diff --git a/sr_port/zshow_params.h b/sr_port/zshow_params.h
index 36a6b76..d7ef7f7 100644
--- a/sr_port/zshow_params.h
+++ b/sr_port/zshow_params.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -27,11 +27,13 @@ zshow_dele,
zshow_dest,
zshow_ebcd,
zshow_edit,
+zshow_empterm,
zshow_exce,
zshow_exte,
zshow_field,
zshow_fil,
zshow_fixed,
+zshow_follow,
zshow_host,
zshow_ichset,
zshow_independent,
@@ -42,7 +44,9 @@ zshow_nocene,
zshow_nodest,
zshow_noecho,
zshow_noedit,
+zshow_noempterm,
zshow_noesca,
+zshow_nofollow,
zshow_nohost,
zshow_noinse,
zshow_nopast,
diff --git a/sr_port/zshow_stack.c b/sr_port/zshow_stack.c
index ab32008..ad81d17 100644
--- a/sr_port/zshow_stack.c
+++ b/sr_port/zshow_stack.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -60,8 +60,10 @@ void zshow_stack(zshow_out *output)
# endif
break; /* Endpoint.. */
}
- if (!(fp->type & SFT_COUNT) || (fp->type & SFT_ZINTR))
- {
+ if (!(fp->type & SFT_COUNT) || ((fp->type & SFT_ZINTR) && (fp->flags & SFF_INDCE)))
+ { /* SFT_ZINTR is normally indirect but if the frame has been replaced by non-indirect frame via ZGOTO or GOTO
+ * then do not include it in the indirect list here.
+ */
if (nfp < &nocount_frames[MAX_INDR_PER_COUNTED])
/* If room in array, save indirect frame type */
*nfp++ = fp->type;
diff --git a/sr_unix/CMakeLists.txt b/sr_unix/CMakeLists.txt
index b4fff87..9f3b229 100644
--- a/sr_unix/CMakeLists.txt
+++ b/sr_unix/CMakeLists.txt
@@ -26,7 +26,7 @@ foreach(lang ${languages})
endforeach()
# Defaults
-set(version V6.0-001)
+set(version GTM_RELEASE_VERSION)
if("${version}" STREQUAL "")
set(version V9.9-0)
endif()
@@ -37,7 +37,7 @@ if(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE)
endif()
# If it's a debug build make sure GT.M uses all of its debug options
-set(CMAKE_C_FLAGS_DEBUG -DDEBUG)
+set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DDEBUG")
set(install_permissions_script
OWNER_READ OWNER_EXECUTE OWNER_WRITE
@@ -56,6 +56,7 @@ set(gtm_osarch_libs "")
# Define these ahead of establishing platforms
set(gt_src_list)
set(sources_used "")
+set(extralibs "")
set(is_encryption_supported 1)
set(libmumpsrestoreregex "")
message("--> OS = ${CMAKE_SYSTEM_NAME} / ARCH = ${CMAKE_SYSTEM_PROCESSOR}")
@@ -374,6 +375,7 @@ foreach(lib
mupip
stub
mumps
+ ${extralibs}
)
add_library(lib${lib} STATIC ${lib${lib}_SOURCES})
set_property(TARGET lib${lib} PROPERTY OUTPUT_NAME ${lib})
@@ -441,7 +443,7 @@ target_link_libraries(ftok libmumps libstub)
if("${CMAKE_SYSTEM_NAME}" STREQUAL "SunOS")
add_executable(gtm_svc ${gtm_svc_SOURCES})
- target_link_libraries(gtm_svc libmumps libcmisockettcp libgnpclient libgtmrpc)
+ target_link_libraries(gtm_svc libmumps libgnpclient libcmisockettcp libgtmrpc)
endif()
foreach(t ${with_export})
set_target_properties(${t} PROPERTIES
@@ -465,9 +467,7 @@ if(is_encryption_supported)
# Iterate over the list of GPG related libraries
foreach(gpglib gpg-error gpgme gcrypt)
# For each library, we need a new CMake variable, hence GPGLIB_${gpglib}
- find_library(GPGLIB_${gpglib}
- NAME ${gpglib}
- PATHS ${CMAKE_LIBRARY_PATH} /usr/local/lib64 /usr/local/lib)
+ find_library(GPGLIB_${gpglib} NAME ${gpglib} PATHS ${CMAKE_LIBRARY_PATH})
# Append the found library to the list
set(GPG_LIBRARIES ${GPG_LIBRARIES} ${GPGLIB_${gpglib}})
endforeach()
@@ -717,7 +717,10 @@ endforeach()
#-----------------------------------------------------------------------------
set(gtm_hlp mumps.hlp)
set(gde_hlp gde.hlp)
-foreach(help gtm gde)
+set(mupip_hlp mupip.hlp)
+set(dse_hlp dse.hlp)
+set(lke_hlp lke.hlp)
+foreach(help gtm gde mupip dse lke)
set(CMAKE_CONFIGURABLE_FILE_CONTENT
"Change -segment DEFAULT -block=2048 -file=\$gtm_dist/${help}help.dat
Change -region DEFAULT -record=1020 -key=255
diff --git a/sr_unix/anticipatory_freeze.c b/sr_unix/anticipatory_freeze.c
index aa3bafc..98cd4a3 100644
--- a/sr_unix/anticipatory_freeze.c
+++ b/sr_unix/anticipatory_freeze.c
@@ -28,6 +28,10 @@
#include "eintr_wrappers.h"
#include "gtmmsg.h"
#include "anticipatory_freeze.h"
+#ifdef DEBUG
+#include "dpgbldir.h"
+#include "is_proc_alive.h"
+#endif
#define MAX_TAG_LEN 128 /* Maximum size of an error mnemonic */
#define MAX_READ_SZ 1024 /* Mnemonic + flags shouldn't exceed this limit */
@@ -47,6 +51,7 @@
} \
}
+error_def(ERR_ASSERT);
error_def(ERR_CUSTERRNOTFND);
error_def(ERR_CUSTERRSYNTAX);
error_def(ERR_CUSTOMFILOPERR);
@@ -55,13 +60,16 @@ error_def(ERR_ENOSPCQIODEFER);
error_def(ERR_REPLINSTFREEZECOMMENT);
error_def(ERR_REPLINSTFROZEN);
error_def(ERR_TEXT);
+error_def(ERR_INSTFRZDEFER);
GBLREF jnlpool_addrs jnlpool;
GBLREF jnlpool_ctl_ptr_t jnlpool_ctl;
GBLREF boolean_t is_src_server;
GBLREF boolean_t holds_sem[NUM_SEM_SETS][NUM_SRC_SEMS];
-GBLREF sgmnt_addrs *cs_addrs;
-GBLREF gd_region *gv_cur_region;
+#ifdef DEBUG
+GBLREF uint4 process_id;
+GBLREF volatile boolean_t timer_in_handler;
+#endif
/* Typically prototypes are included in the header file. But, in this case the static function - get_mnemonic_offset - has the
* hash_table_str as one of the function parameters which means all the files which includes anticipatory_freeze.h needs to include
@@ -137,20 +145,24 @@ STATICFNDEF int get_mnemonic_offset(hash_table_str **err_hashtab, char *mnemoni
}
/* Determine whether a given msg_id qualifies for an anticipatory freeze or not */
-boolean_t is_anticipatory_freeze_needed(int msg_id)
+boolean_t is_anticipatory_freeze_needed(sgmnt_addrs *csa, int msg_id)
{
const err_ctl *ctl;
int idx;
- sgmnt_addrs *csa;
assert(NULL != jnlpool.jnlpool_ctl);
/* Certain error messages should NOT trigger a freeze even if they are so configured in the custom errors file as they might
- * result in instance freezes that can be set indefinitely. Currently, we know of at least two such messages:
- * 1. ENOSPCQIODEFER : To ensure we don't set anticipatory freeze if we don't/can't hold crit (due to possible deadlock)
+ * result in instance freezes that can be set indefinitely. Currently, we know of at least 3 such messages:
+ * 1. ENOSPCQIODEFER and INSTFRZDEFER : To ensure we don't set anticipatory freeze if we don't/can't hold crit
+ * (due to possible deadlock)
* 2. DSKSPCAVAILABLE : To ensure we don't set anticipatory freeze if the disk space becomes available after an initial
* lack of space.
+ * These messages have csa == NULL so they are guarranteed to not trigger a freeze.
*/
- if ((ERR_ENOSPCQIODEFER == msg_id) || (ERR_DSKSPCAVAILABLE == msg_id))
+
+ assert(((ERR_ENOSPCQIODEFER != msg_id) && (ERR_DSKSPCAVAILABLE != msg_id) && (ERR_INSTFRZDEFER != msg_id))
+ || (NULL == csa));
+ if (!csa || !csa->nl || !csa->hdr || !csa->hdr->freeze_on_fail)
return FALSE;
ctl = err_check(msg_id);
if (NULL != ctl)
@@ -158,28 +170,23 @@ boolean_t is_anticipatory_freeze_needed(int msg_id)
GET_MSG_IDX(msg_id, ctl, idx);
assert(idx < ARRAYSIZE(jnlpool_ctl->merrors_array));
if (jnlpool_ctl->merrors_array[idx] & AFREEZE_MASK)
- {
- assert(NULL != gv_cur_region);
- assert(&FILE_INFO(gv_cur_region)->s_addrs == cs_addrs);
- csa = &FILE_INFO(gv_cur_region)->s_addrs;
- if (csa && csa->hdr && csa->hdr->freeze_on_fail)
- return TRUE;
- }
+ return TRUE;
}
return FALSE;
}
/* set the anticipatory freeze in the journal pool */
-void set_anticipatory_freeze(int msg_id)
+void set_anticipatory_freeze(sgmnt_addrs *csa, int msg_id)
{
boolean_t was_crit;
sgmnt_addrs *repl_csa;
+ const err_msg *msginfo;
# ifdef DEBUG
qw_off_t write_addr;
uint4 write;
# endif
- assert(is_anticipatory_freeze_needed(msg_id));
+ assert(is_anticipatory_freeze_needed(csa, msg_id));
DEBUG_ONLY(
write_addr = jnlpool_ctl->write_addr;
write = jnlpool_ctl->write;
@@ -188,13 +195,23 @@ void set_anticipatory_freeze(int msg_id)
repl_csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs;
assert(NULL != repl_csa);
was_crit = repl_csa->now_crit;
- if (!was_crit && !repl_csa->hold_onto_crit)
- grab_lock(jnlpool.jnlpool_dummy_reg, GRAB_LOCK_ONLY);
+ if (!was_crit)
+ {
+ if (csa->now_crit)
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, GRAB_LOCK_ONLY);
+ else if (FALSE == grab_lock(jnlpool.jnlpool_dummy_reg, FALSE, GRAB_LOCK_ONLY))
+ {
+ MSGID_TO_ERRMSG(msg_id, msginfo);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_INSTFRZDEFER, 4, LEN_AND_STR(msginfo->tag),
+ REG_LEN_STR(csa->region));
+ return;
+ }
+ }
/* Now that we hold necessary locks, set the freeze and the comment field */
jnlpool.jnlpool_ctl->freeze = TRUE;
GENERATE_INST_FROZEN_COMMENT(jnlpool.jnlpool_ctl->freeze_comment, SIZEOF(jnlpool.jnlpool_ctl->freeze_comment), msg_id);
/* TODO : Do we need a SHM_WRITE_MEMORY_BARRIER ? */
- if (!was_crit && !repl_csa->hold_onto_crit)
+ if (!was_crit)
rel_lock(jnlpool.jnlpool_dummy_reg);
}
@@ -223,10 +240,10 @@ boolean_t init_anticipatory_freeze_errors()
if (NULL == handle)
{
save_errno = errno;
- send_msg(VARLSTCNT(6) ERR_CUSTOMFILOPERR, 4, LEN_AND_LIT("fopen"), custom_err_file.len, custom_err_file.addr,
- save_errno);
- gtm_putmsg(VARLSTCNT(6) ERR_CUSTOMFILOPERR, 4, LEN_AND_LIT("fopen"), custom_err_file.len, custom_err_file.addr,
- save_errno);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_CUSTOMFILOPERR, 4, LEN_AND_LIT("fopen"), custom_err_file.len,
+ custom_err_file.addr, save_errno);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_CUSTOMFILOPERR, 4, LEN_AND_LIT("fopen"), custom_err_file.len,
+ custom_err_file.addr, save_errno);
return FALSE;
}
line_no = 0;
@@ -266,10 +283,12 @@ boolean_t init_anticipatory_freeze_errors()
/* The first character has to be alpha-numeric or a comment */
if (!ISALNUM_ASCII(*buffptr) && (COMMENT_DELIMITER != *buffptr))
{
- send_msg(VARLSTCNT(9) ERR_CUSTERRSYNTAX, 3, custom_err_file.len, custom_err_file.addr, line_no,
- ERR_TEXT, 2, LEN_AND_LIT("First character should be comment (;) or alpha numeric"));
- gtm_putmsg(VARLSTCNT(9) ERR_CUSTERRSYNTAX, 3, custom_err_file.len, custom_err_file.addr, line_no,
- ERR_TEXT, 2, LEN_AND_LIT("First character should be comment (;) or alpha numeric"));
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_CUSTERRSYNTAX, 3, custom_err_file.len, custom_err_file.addr,
+ line_no, ERR_TEXT, 2,
+ LEN_AND_LIT("First character should be comment (;) or alpha numeric"));
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_CUSTERRSYNTAX, 3, custom_err_file.len, custom_err_file.addr,
+ line_no, ERR_TEXT, 2,
+ LEN_AND_LIT("First character should be comment (;) or alpha numeric"));
return FALSE;
}
while (ISALNUM_ASCII(*buffptr))
@@ -277,10 +296,10 @@ boolean_t init_anticipatory_freeze_errors()
*errptr++ = *buffptr++;
if (errptr > errptr_top)
{
- send_msg(VARLSTCNT(9) ERR_CUSTERRSYNTAX, 3, custom_err_file.len, custom_err_file.addr, line_no,
- ERR_TEXT, 2, LEN_AND_LIT("Mnemonic too long"));
- gtm_putmsg(VARLSTCNT(9) ERR_CUSTERRSYNTAX, 3, custom_err_file.len, custom_err_file.addr, line_no,
- ERR_TEXT, 2, LEN_AND_LIT("Mnemonic too long"));
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_CUSTERRSYNTAX, 3, custom_err_file.len,
+ custom_err_file.addr, line_no, ERR_TEXT, 2, LEN_AND_LIT("Mnemonic too long"));
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_CUSTERRSYNTAX, 3, custom_err_file.len,
+ custom_err_file.addr, line_no, ERR_TEXT, 2, LEN_AND_LIT("Mnemonic too long"));
return FALSE;
}
assert(buffptr < buff_top); /* errptr > errptr_top should fail before this */
@@ -290,8 +309,8 @@ boolean_t init_anticipatory_freeze_errors()
{ /* Non-empty error mnemonic found; look it up */
if (-1 == (offset = get_mnemonic_offset(&err_hashtab, mnemonic_buf, mnemonic_len)))
{
- send_msg(VARLSTCNT(4) ERR_CUSTERRNOTFND, 2, mnemonic_len, mnemonic_buf);
- gtm_putmsg(VARLSTCNT(4) ERR_CUSTERRNOTFND, 2, mnemonic_len, mnemonic_buf);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_CUSTERRNOTFND, 2, mnemonic_len, mnemonic_buf);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_CUSTERRNOTFND, 2, mnemonic_len, mnemonic_buf);
return FALSE;
}
jnlpool_ctl->merrors_array[offset] |= AFREEZE_MASK; /* duplicate entries are not considered an error */
@@ -304,10 +323,10 @@ boolean_t init_anticipatory_freeze_errors()
assert(buffptr < buff_top);
if (COMMENT_DELIMITER != *buffptr)
{
- send_msg(VARLSTCNT(9) ERR_CUSTERRSYNTAX, 3, custom_err_file.len, custom_err_file.addr, line_no,
- ERR_TEXT, 2, LEN_AND_LIT("Unexpected character found after mnemonic"));
- gtm_putmsg(VARLSTCNT(9) ERR_CUSTERRSYNTAX, 3, custom_err_file.len, custom_err_file.addr, line_no,
- ERR_TEXT, 2, LEN_AND_LIT("Unexpected character found after mnemonic"));
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_CUSTERRSYNTAX, 3, custom_err_file.len, custom_err_file.addr,
+ line_no, ERR_TEXT, 2, LEN_AND_LIT("Unexpected character found after mnemonic"));
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_CUSTERRSYNTAX, 3, custom_err_file.len, custom_err_file.addr,
+ line_no, ERR_TEXT, 2, LEN_AND_LIT("Unexpected character found after mnemonic"));
return FALSE;
}
/* Need to ignore the rest of the current buffer and exhaust the current line */
@@ -322,22 +341,53 @@ boolean_t init_anticipatory_freeze_errors()
if (!feof(handle))
{
save_errno = errno;
- send_msg(VARLSTCNT(6) ERR_CUSTOMFILOPERR, 4, LEN_AND_LIT("fgets"), custom_err_file.len, custom_err_file.addr,
- save_errno);
- gtm_putmsg(VARLSTCNT(6) ERR_CUSTOMFILOPERR, 4, LEN_AND_LIT("fgets"), custom_err_file.len, custom_err_file.addr,
- save_errno);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_CUSTOMFILOPERR, 4, LEN_AND_LIT("fgets"), custom_err_file.len,
+ custom_err_file.addr, save_errno);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_CUSTOMFILOPERR, 4, LEN_AND_LIT("fgets"), custom_err_file.len,
+ custom_err_file.addr, save_errno);
return FALSE;
}
FCLOSE(handle, status);
if (SS_NORMAL != status)
{
save_errno = errno;
- send_msg(VARLSTCNT(6) ERR_CUSTOMFILOPERR, 4, LEN_AND_LIT("fclose"), custom_err_file.len, custom_err_file.addr,
- save_errno);
- gtm_putmsg(VARLSTCNT(6) ERR_CUSTOMFILOPERR, 4, LEN_AND_LIT("fclose"), custom_err_file.len, custom_err_file.addr,
- save_errno);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_CUSTOMFILOPERR, 4, LEN_AND_LIT("fclose"), custom_err_file.len,
+ custom_err_file.addr, save_errno);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_CUSTOMFILOPERR, 4, LEN_AND_LIT("fclose"), custom_err_file.len,
+ custom_err_file.addr, save_errno);
return FALSE;
}
jnlpool_ctl->instfreeze_environ_inited = TRUE;
return TRUE;
}
+
+#ifdef DEBUG
+void clear_fake_enospc_if_master_dead(void)
+{
+ gd_addr *addr_ptr;
+ gd_region *r_top, *r_local;
+ sgmnt_addrs *csa;
+
+ if((jnlpool_ctl->jnlpool_creator_pid != process_id) && !is_proc_alive(jnlpool_ctl->jnlpool_creator_pid, 0))
+ {
+ for (addr_ptr = get_next_gdr(NULL); addr_ptr; addr_ptr = get_next_gdr(addr_ptr))
+ {
+ for (r_local = addr_ptr->regions, r_top = r_local + addr_ptr->n_regions; r_local < r_top; r_local++)
+ {
+ if ((dba_bg != r_local->dyn.addr->acc_meth) && (dba_mm != r_local->dyn.addr->acc_meth))
+ continue;
+ csa = REG2CSA(r_local);
+ if ((NULL != csa) && (NULL != csa->nl))
+ if (csa->nl->fake_db_enospc || csa->nl->fake_jnl_enospc)
+ {
+ csa->nl->fake_db_enospc = FALSE;
+ csa->nl->fake_jnl_enospc = FALSE;
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_TEXT, 2, DB_LEN_STR(r_local), ERR_TEXT,
+ 2, LEN_AND_LIT("Resetting fake_db_enospc and fake_jnl_enospc because "
+ "fake ENOSPC master is dead"));
+ }
+ }
+ }
+ }
+}
+#endif
diff --git a/sr_unix/append_time_stamp.c b/sr_unix/append_time_stamp.c
index 48ec375..7599ce6 100644
--- a/sr_unix/append_time_stamp.c
+++ b/sr_unix/append_time_stamp.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2003, 2007 Fidelity Information Services, Inc *
+ * Copyright 2003, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -13,31 +13,26 @@
#include <errno.h>
#include "gtm_string.h"
-#include "gtm_stat.h"
#include "gtm_time.h"
#include "gtm_rename.h"
+
#include "eintr_wrappers.h"
#include "iosp.h"
-#define TIME_EXT_FMT "_%Y%j%H%M%S" /* .yearjuliendayhoursminutesseconds */
-
-/* This appends timestamp from file (fn) last modified status time. Result is returned in same string fn.
- * Return SS_NORMAL for success */
-uint4 append_time_stamp(char *fn, int fn_len, int *app_len, uint4 *ustatus)
+/* Append the formatted timestamp to the file name (fn); *fn_len contains the current length of the filename and at exit from this
+ * function, it is updated to reflect the new length.
+ */
+uint4 append_time_stamp(char *fn, int *fn_len, jnl_tm_t now)
{
- struct stat stat_buf;
struct tm *tm_struct;
- int status;
- size_t tt;
+ time_t tt_now;
+ size_t tm_str_len;
- *ustatus = SS_NORMAL;
- STAT_FILE(fn, &stat_buf, status);
- if (-1 == status) /* if file fn does not exist */
- return errno;
- assert(0 < MAX_FN_LEN - fn_len - 1);
- tm_struct = localtime(&(stat_buf.st_ctime));
- STRFTIME(&fn[fn_len], MAX_FN_LEN - fn_len - 1, TIME_EXT_FMT, tm_struct, tt);
- *app_len = (int)tt;
+ assert(0 < MAX_FN_LEN - *fn_len - 1);
+ tt_now = (time_t)now;
+ GTM_LOCALTIME(tm_struct, &tt_now);
+ STRFTIME(&fn[*fn_len], MAX_FN_LEN - *fn_len - 1, JNLSWITCH_TM_FMT, tm_struct, tm_str_len);
+ *fn_len += (int)tm_str_len;
return SS_NORMAL;
}
diff --git a/sr_unix/badd.txt b/sr_unix/badd.txt
index a6a6c8e..49eb4a1 100644
--- a/sr_unix/badd.txt
+++ b/sr_unix/badd.txt
@@ -1,6 +1,6 @@
#################################################################
# #
-# Copyright 2011, 2012 Fidelity Information Services, Inc #
+# Copyright 2011, 2013 Fidelity Information Services, Inc #
# #
# This source code contains the intellectual property #
# of its copyright holder(s), and is made available #
@@ -30,4 +30,9 @@ zzz_insert%-r--r----- source.tar
pro/utf8:
TTTGEN.m -> ../TTTGEN.m%lrwxrwxrwx README.txt -> ../README.txt
dse -> ../dse%lrwxrwxrwx custom_errors_sample.txt -> ../custom_errors_sample.txt
+gtmstart.gtc -> ../gtmstart.gtc%-r-sr-x--- gtmsecshr
+gtmstart.gtc -> ../gtmstart.gtc%dr-x------ gtmsecshrdir
lke -> ../lke%-r-xr-x--- libgtmutil.so
+
+pro/utf8/gtmsecshrdir:
+zzz_insert%-r-s------ gtmsecshr
diff --git a/sr_unix/bdelete.txt b/sr_unix/bdelete.txt
index 43a2439..20fd7ac 100644
--- a/sr_unix/bdelete.txt
+++ b/sr_unix/bdelete.txt
@@ -1,6 +1,6 @@
#################################################################
# #
-# Copyright 2011, 2012 Fidelity Information Services, Inc #
+# Copyright 2011, 2013 Fidelity Information Services, Inc #
# #
# This source code contains the intellectual property #
# of its copyright holder(s), and is made available #
@@ -80,6 +80,8 @@ configure -> ../configure
dbcertify -> ../dbcertify
gtmhelp.dmp -> ../gtmhelp.dmp
gtminstall -> ../gtminstall
+gtmsecshr -> ../gtmsecshr
+gtmsecshrdir -> ../gtmsecshrdir
lowerc_cp -> ../lowerc_cp
map -> ../map
mumps.gld -> ../mumps.gld
diff --git a/sr_unix/bin_load.c b/sr_unix/bin_load.c
index cec815d..9e8af6b 100644
--- a/sr_unix/bin_load.c
+++ b/sr_unix/bin_load.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -59,6 +59,7 @@ GBLREF gv_key *gv_currkey;
GBLREF gv_namehead *gv_target;
GBLREF int4 gv_keysize;
GBLREF gd_region *gv_cur_region;
+GBLREF sgmnt_addrs *cs_addrs;
#ifdef GTM_CRYPT
GBLREF io_pair io_curr_device;
#endif
@@ -125,7 +126,7 @@ error_def(ERR_LDSPANGLOINCMP);
if (file_offset != last_sn_error_offset) \
{ \
last_sn_error_offset = file_offset; \
- gtm_putmsg(VARLSTCNT(1) ERR_LDSPANGLOINCMP); \
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_LDSPANGLOINCMP); \
util_out_print("!_!_at File offset : [0x!XL]", TRUE, file_offset); \
if (sn_gvkey->end && expected_sn_chunk_number) \
{ \
@@ -167,8 +168,6 @@ error_def(ERR_LDSPANGLOINCMP);
util_out_print(0, TRUE); \
}
-static readonly unsigned char gt_lit[] = "LOAD TOTAL";
-
/* starting extract file format 3, we have an extra record for each gvn, that contains the
* collation information of the database at the time of extract. This record is transparent
* to the user, so the semantics of the command line options, 'begin' and 'end' to MUPIP LOAD
@@ -255,7 +254,7 @@ void bin_load(uint4 begin, uint4 end)
(('7' == hdr_lvl) && (BIN_HEADER_SZ == len)) ||
(('4' > hdr_lvl) && (V3_BIN_HEADER_SZ == len))))
{
- rts_error(VARLSTCNT(1) ERR_LDBINFMT);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_LDBINFMT);
mupip_exit(ERR_LDBINFMT);
}
/* expecting the level in a single character */
@@ -263,7 +262,7 @@ void bin_load(uint4 begin, uint4 end)
if (0 != memcmp(ptr, BIN_HEADER_LABEL, SIZEOF(BIN_HEADER_LABEL) - 2) || ('2' > hdr_lvl) ||
*(BIN_HEADER_VERSION_ENCR) < hdr_lvl)
{ /* ignore the level check */
- rts_error(VARLSTCNT(1) ERR_LDBINFMT);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_LDBINFMT);
mupip_exit(ERR_LDBINFMT);
}
/* check if extract was generated in UTF-8 mode */
@@ -271,9 +270,9 @@ void bin_load(uint4 begin, uint4 end)
if ((utf8_extract && !gtm_utf8_mode) || (!utf8_extract && gtm_utf8_mode))
{ /* extract CHSET doesn't match $ZCHSET */
if (utf8_extract)
- rts_error(VARLSTCNT(4) ERR_LOADINVCHSET, 2, LEN_AND_LIT("UTF-8"));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_LOADINVCHSET, 2, LEN_AND_LIT("UTF-8"));
else
- rts_error(VARLSTCNT(4) ERR_LOADINVCHSET, 2, LEN_AND_LIT("M"));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_LOADINVCHSET, 2, LEN_AND_LIT("M"));
mupip_exit(ERR_LDBINFMT);
}
if ('4' >= hdr_lvl)
@@ -303,8 +302,8 @@ void bin_load(uint4 begin, uint4 end)
extr_std_null_coll = STRTOUL(std_null_coll, NULL, 10);
if (0 != extr_std_null_coll && 1!= extr_std_null_coll)
{
- rts_error(VARLSTCNT(5) ERR_TEXT, 2, RTS_ERROR_TEXT("Corrupted null collation field in header"),
- ERR_LDBINFMT);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_TEXT, 2,
+ RTS_ERROR_TEXT("Corrupted null collation field in header"), ERR_LDBINFMT);
mupip_exit(ERR_LDBINFMT);
}
} else
@@ -335,20 +334,21 @@ void bin_load(uint4 begin, uint4 end)
len = file_input_bin_get((char **)&ptr, &file_offset_base, (char **)&ptr_base);
if (SIZEOF(coll_hdr) != len)
{
- rts_error(VARLSTCNT(5) ERR_TEXT, 2, RTS_ERROR_TEXT("Corrupt collation header"), ERR_LDBINFMT);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_TEXT, 2, RTS_ERROR_TEXT("Corrupt collation header"),
+ ERR_LDBINFMT);
mupip_exit(ERR_LDBINFMT);
}
extr_collhdr = *((coll_hdr *)(ptr));
new_gvn = TRUE;
} else
- gtm_putmsg(VARLSTCNT(3) ERR_OLDBINEXTRACT, 1, hdr_lvl - '0');
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_OLDBINEXTRACT, 1, hdr_lvl - '0');
if (begin < 2)
begin = 2;
for (iter = 2; iter < begin; iter++)
{
if (!(len = file_input_bin_get((char **)&ptr, &file_offset_base, (char **)&ptr_base)))
{
- gtm_putmsg(VARLSTCNT(3) ERR_LOADEOF, 1, begin);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_LOADEOF, 1, begin);
util_out_print("Error reading record number: !UL\n", TRUE, iter);
mupip_error_occurred = TRUE;
return;
@@ -384,7 +384,7 @@ void bin_load(uint4 begin, uint4 end)
if (mu_ctrlc_occurred)
{
util_out_print("!AD:!_ Key cnt: !UL max subsc len: !UL max data len: !UL", TRUE,
- LEN_AND_LIT(gt_lit), key_count, max_subsc_len, max_data_len);
+ 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);
mu_gvis();
util_out_print(0, TRUE);
@@ -452,14 +452,15 @@ void bin_load(uint4 begin, uint4 end)
{
if (!do_verify(extr_collseq, extr_collhdr.act, extr_collhdr.ver))
{
- gtm_putmsg(VARLSTCNT(8) ERR_COLLTYPVERSION, 2, extr_collhdr.act,
- extr_collhdr.ver, ERR_GVIS, 2, gv_altkey->end - 1, gv_altkey->base);
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) ERR_COLLTYPVERSION, 2,
+ extr_collhdr.act, extr_collhdr.ver, ERR_GVIS, 2,
+ gv_altkey->end - 1, gv_altkey->base);
mupip_exit(ERR_COLLTYPVERSION);
}
} else
{
- gtm_putmsg(VARLSTCNT(7) ERR_COLLATIONUNDEF, 1, extr_collhdr.act,
- ERR_GVIS, 2, gv_altkey->end - 1, gv_altkey->base);
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(7) ERR_COLLATIONUNDEF, 1,
+ extr_collhdr.act, ERR_GVIS, 2, gv_altkey->end - 1, gv_altkey->base);
mupip_exit(ERR_COLLATIONUNDEF);
}
}
@@ -469,13 +470,14 @@ void bin_load(uint4 begin, uint4 end)
{
if (!do_verify(db_collseq, db_collhdr.act, db_collhdr.ver))
{
- gtm_putmsg(VARLSTCNT(8) ERR_COLLTYPVERSION, 2, db_collhdr.act,
- db_collhdr.ver, ERR_GVIS, 2, gv_altkey->end - 1, gv_altkey->base);
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) ERR_COLLTYPVERSION, 2,
+ db_collhdr.act, db_collhdr.ver, ERR_GVIS, 2,
+ gv_altkey->end - 1, gv_altkey->base);
mupip_exit(ERR_COLLTYPVERSION);
}
} else
{
- gtm_putmsg(VARLSTCNT(7) ERR_COLLATIONUNDEF, 1, db_collhdr.act,
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(7) ERR_COLLATIONUNDEF, 1, db_collhdr.act,
ERR_GVIS, 2, gv_altkey->end - 1, gv_altkey->base);
mupip_exit(ERR_COLLATIONUNDEF);
}
@@ -789,7 +791,7 @@ void bin_load(uint4 begin, uint4 end)
util_out_print("Last LOAD record number: !UL\n", TRUE, key_count ? (rec_count - 1) : 0);
if (mu_ctrly_occurred)
{
- gtm_putmsg(VARLSTCNT(1) ERR_LOADCTRLY);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_LOADCTRLY);
mupip_exit(ERR_MUNOFINISH);
}
}
@@ -810,7 +812,7 @@ void bin_call_db(int routine, INTPTR_T parm1, INTPTR_T parm2)
GV_BIND_NAME_AND_ROOT_SEARCH((gd_addr *)parm1, (mstr *)parm2);
break;
case ERR_COR:
- rts_error(VARLSTCNT(4) ERR_CORRUPT, 2, parm1, parm2);
+ rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_CORRUPT, 2, parm1, parm2);
case BIN_KILL:
gvcst_kill(FALSE);
break;
diff --git a/sr_unix/build.sh b/sr_unix/build.sh
index 7a145de..e4ed958 100644
--- a/sr_unix/build.sh
+++ b/sr_unix/build.sh
@@ -1,7 +1,7 @@
#!/bin/sh
#################################################################
# #
-# Copyright 2009, 2012 Fidelity Information Services, Inc #
+# Copyright 2009, 2013 Fidelity Information Services, Inc #
# #
# This source code contains the intellectual property #
# of its copyright holder(s), and is made available #
@@ -81,7 +81,7 @@ options_incpath="-I /usr/local/include/ -I /usr/include -I $builddir -I $gtm_dis
base_libname="libgtmcrypt"
# Common CC options for various platforms
if [ "AIX" = "$hostos" ] ; then
- cc_common="-c -qchars=signed -qsrcmsg -qmaxmem=8192 -D_BSD=43 -D_LARGE_FILES -D_TPARM_COMPAT -D_AIO_AIX_SOURCE -DCOMPAT_43"
+ cc_common="-c -qchars=signed -qsrcmsg -qmaxmem=8192 -D_BSD=43 -D_LARGE_FILES -D_TPARM_COMPAT -D_AIO_AIX_SOURCE"
cc_common="$cc_common -qro -qroconst -D_USE_IRS -q64"
ld_common="-q64 -brtl"
aix_loadmap_option="-bcalls:$builddir/$base_libname.so.map -bmap:$builddir/$base_libname.so.map"
diff --git a/sr_unix/buildaux.csh b/sr_unix/buildaux.csh
index 000f625..511f172 100644
--- a/sr_unix/buildaux.csh
+++ b/sr_unix/buildaux.csh
@@ -557,7 +557,7 @@ if ($buildaux_gtmcrypt == 1) then
# build maskpass with libgcrypt dependency rather than libcrypto dependency on non-AIX platforms.
if ($HOSTOS != "AIX") then
set supported_list_reorder = `echo $supported_list | sed 's/gcrypt//;s/$/ gcrypt/'`
- set supported_list = "$supported_list_reorder"
+ set supported_list = `echo $supported_list_reorder`
endif
# Build all possible encryption libraries based on what encryption libraries are supported in this platform.
foreach supported_lib ($supported_list)
@@ -588,13 +588,14 @@ if ($buildaux_gtmcrypt == 1) then
# third-party library and algorithm) randomly and install that.
set rand = `$gtm_dist/mumps -run %XCMD 'write 1+$random('$#supported_list')'`
set encryption_lib = $supported_list[$rand]
- if (("gcrypt" == "$encryption_lib") || ("AIX" != $HOSTOS)) then
- # Force AES as long as the plugin is linked against libgcrypt OR this is a non-AIX platform
+ if ("gcrypt" == "$encryption_lib") then
+ # Force AES as long as the plugin is linked against libgcrypt
set algorithm = "AES256CFB"
else
- # OpenSSL, V9* build and AIX. Go ahead and randomize the algorithm
- set algorithms = ("AES256CFB" "BLOWFISHCFB")
- set rand = `$gtm_dist/mumps -run %XCMD 'write 1+$random(2)'`
+ # OpenSSL, V9* build. Go ahead and randomize the algorithm
+ # increase probability of AES256CFB, the industry standard and the one we officially support
+ set algorithms = ("AES256CFB" "AES256CFB" "BLOWFISHCFB")
+ set rand = `$gtm_dist/mumps -run %XCMD 'write 1+$random('$#algorithms')'`
set algorithm = $algorithms[$rand]
endif
endif
diff --git a/sr_unix/check_unicode_support.csh b/sr_unix/check_unicode_support.csh
index 18def7d..a59ef7c 100644
--- a/sr_unix/check_unicode_support.csh
+++ b/sr_unix/check_unicode_support.csh
@@ -1,6 +1,6 @@
#################################################################
# #
-# Copyright 2007, 2010 Fidelity Information Services, Inc #
+# Copyright 2007, 2013 Fidelity Information Services, Inc #
# #
# This source code contains the intellectual property #
# of its copyright holder(s), and is made available #
@@ -19,17 +19,17 @@
###########################################################################################
set found_icu = 0
-set utflocale = `locale -a | grep -i en_us | grep -i utf | grep '8$'`
+set utflocale = `locale -a | grep -i en_us | grep -i utf | grep '8$' | head -n 1`
if ("OS/390" == $HOSTOS) then
# z/OS has both en_US.UTF-8 and En_US.UTF-8 with both .xplink and .lp64 suffixes - we need .lp64
- set utflocale = `locale -a | grep En_US.UTF-8.lp64 | sed 's/.lp64$//'`
+ set utflocale = `locale -a | grep En_US.UTF-8.lp64 | sed 's/.lp64$//' | head -n 1`
endif
# This _could_ not work on new platforms or newly installed supported platforms.
# It should be manually tested using this command :
# ssh <some host> ls -l {/usr/local,/usr,}/lib{64,,32}/libicuio.{a,so,sl}
-foreach libdir ( {/usr/local,/usr,}/lib{64,,32}/libicuio.{a,so,sl} )
+foreach libdir ( {/usr/local,/usr,}/lib{64,/x86_64-linux-gnu,,32,/i386-linux-gnu}/libicuio.{a,so,sl} )
# 36 is the least version GT.M supports for ICU.
# We have to get the numeric value from the ICU library. On non-AIX platforms, this can be done by
# first getting the library to which libicuio.so is pointing to (this is always TRUE, in the sense
diff --git a/sr_unix/clear_cache_array.c b/sr_unix/clear_cache_array.c
index 1d834fe..0096d88 100644
--- a/sr_unix/clear_cache_array.c
+++ b/sr_unix/clear_cache_array.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2012 Fidelity Information Services, Inc *
+ * Copyright 2012, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -65,51 +65,43 @@ void clear_cache_array(sgmnt_addrs *csa, sgmnt_data_ptr_t csd, gd_region* reg, u
SETUP_THREADGBL_ACCESS;
/* If called from db_init, assure we've grabbed the access semaphor and are the only process attached to the database.
- * Otherwise, we should have crit when called from wcs_recover or mu_truncate. */
+ * Otherwise, we should have crit when called from wcs_recover or mu_truncate.
+ */
udi = FILE_INFO(reg);
assert((udi->grabbed_access_sem && (1 == (semval = semctl(udi->semid, 1, GETVAL)))) || csa->now_crit);
hash_hdr = (cache_rec_ptr_t)csa->acc_meth.bg.cache_state->cache_array;
cr_lo = hash_hdr + csd->bt_buckets;
cr_top = cr_lo + csd->n_bts;
cnl = csa->nl;
- /* CLear all the cached blocks(FREE AND RECYCLED)
- * that are greater than the post-truncate total_blks
- * Done in crit, near the end of truncate.
- */
+ /* Last thing we did was wcs_flu, so no buffers should have been dirtied in the meantime. */
+ assert(0 == cnl->wcs_active_lvl);
for (cr = cr_lo; cr < cr_top; cr++)
{
- if (CR_BLKEMPTY != cr->blk && cr->blk >= new_total)
- {
- if ((0 == cr->dirty)
- VMS_ONLY(|| ((0 != cr->iosb.cond) && (0 == cr->bt_index))))
- { /* cache record has no valid buffer attached, or its contents
- * are in the database, or it has a more recent twin so we don't
- * even have to care how its write terminated
- */
- cr->cycle++;
- if (CR_BLKEMPTY != cr->blk)
+ assert(0 == cr->dirty);
+ if ((CR_BLKEMPTY != cr->blk) && (new_total <= cr->blk))
+ { /* Invalidate this cache record. */
+ cr->cycle++;
+ if (CR_BLKEMPTY != cr->blk)
+ {
+ bt = bt_get(cr->blk);
+ if (NULL != bt)
{
- bt = bt_get(cr->blk);
- if (bt)
- bt->cache_index = CR_NOTVALID;
+ bt->cache_index = CR_NOTVALID;
+ bt->blk = BT_NOTVALID;
}
- cr->blk = BT_NOTVALID; /* -1 */
- /* when cr->blk is empty, ensure no bt points to this cache-record */
- cr->bt_index = 0; /* offset to bt_rec */
- cr->data_invalid = 0; /* process_id */
- cr->dirty = 0;
- cr->flushed_dirty_tn = 0; /* value of dirty at the time of flush */
- cr->in_tend = 0;
- /* release of a shmpool reformat block if the current cache record is pointing to it */
- SHMPOOL_FREE_CR_RFMT_BLOCK(reg, csa, cr);
- WRITE_LATCH_VAL(cr) = LATCH_CLEAR;
- VMS_ONLY(cr->iosb.cond = 0;)
- cr->jnl_addr = 0;
- cr->refer = FALSE;
- cr->stopped = FALSE;
- /* increment number of write cache records in free queue */
- cnl->wc_in_free++;
}
+ cr->blk = CR_BLKEMPTY;
+ /* when cr->blk is empty, ensure no bt points to this cache-record */
+ cr->bt_index = 0; /* offset to bt_rec */
+ cr->data_invalid = 0; /* process_id */
+ cr->flushed_dirty_tn = 0; /* value of dirty at the time of flush */
+ cr->in_tend = 0;
+ /* release of a shmpool reformat block if the current cache record is pointing to it */
+ SHMPOOL_FREE_CR_RFMT_BLOCK(reg, csa, cr);
+ WRITE_LATCH_VAL(cr) = LATCH_CLEAR;
+ cr->jnl_addr = 0;
+ cr->refer = FALSE;
+ assert(!cr->stopped);
}
}
}
diff --git a/sr_unix/cli_lex.c b/sr_unix/cli_lex.c
index 898c105..4840889 100644
--- a/sr_unix/cli_lex.c
+++ b/sr_unix/cli_lex.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -47,6 +47,13 @@ GBLREF boolean_t gtm_utf8_mode;
#define CLI_ISSPACE(CHAR) ISSPACE_ASCII(CHAR)
#endif
+/* Don't use toupper() because, with Turkish unicode settings, toupper('i') does not have well-defined behavior. On some platforms
+ * it returns back 'i' itself. This is because, in Turkish, the actual uppercase version of 'i' is 'I' with a dot on top, which is
+ * not an ascii character. Thus cli_strupper would incorrectly convert some qualifiers, resulting in CLIERR errors. For example it
+ * would convert "-dynamic_literals" to "-DYNAMiC_LiTERALS" or "-warnings" to "-WARNiNGS".
+ */
+#define CLI_TOUPPER(C) (('a' <= (C) && (C) <= 'z') ? ((C) + ('A' - 'a')) : (C))
+
static int tok_string_extract(void)
{
int token_len;
@@ -204,7 +211,7 @@ void cli_strupper(char *sp)
int c;
while (c = *sp)
- *sp++ = IS_ASCII(c) ? TOUPPER(c) : c;
+ *sp++ = IS_ASCII(c) ? CLI_TOUPPER(c) : c;
}
/*
@@ -221,7 +228,7 @@ int cli_is_hex(char *p)
if (('+' == *p) || ('-' == *p))
p++;
- if (('0' == *p) && ('X' == TOUPPER(*(p + 1))))
+ if (('0' == *p) && ('X' == CLI_TOUPPER(*(p + 1))))
{
p = p + 2;
}
@@ -338,7 +345,7 @@ static int tok_extract (void)
token_len = 1;
} else if (ch) /* only if something there */
{
- /* smw if quotable, need to unicode isspace */
+ /* smw if quotable, need to unicode isspace (BYPASSOK) */
/* '-' is not a token separator */
while(ch && !CLI_ISSPACE(ch)
&& ch != '=')
diff --git a/sr_unix/cmidefsp.h b/sr_unix/cmidefsp.h
index f933e82..bf22284 100644
--- a/sr_unix/cmidefsp.h
+++ b/sr_unix/cmidefsp.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2007 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -59,6 +59,8 @@ typedef mstr cmi_descriptor;
#include <signal.h>
#include "gtm_unistd.h"
+#include "gtm_netdb.h"
+#include "gtm_socket.h" /* for sockaddr_storage */
typedef struct
{
@@ -84,7 +86,7 @@ typedef struct clb_stat_struct
* Individual link connections doubly linked list
*/
-#include <netinet/in.h>
+#include "gtm_inet.h"
#ifdef __MVS__
/* need fd_set */
#include <sys/time.h>
@@ -92,26 +94,27 @@ typedef struct clb_stat_struct
struct CLB
{
- que_ent cqe; /* forward/backward links */
- struct NTD *ntd; /* back pointer to ntd */
- cmi_descriptor nod; /* node */
- cmi_descriptor tnd; /* taskname */
- struct sockaddr_in peer; /* peer */
- int mun; /* endpoint's file descriptor */
- void *usr; /* client specific storage */
- qio_iosb ios; /* used for tracking inprocess I/O */
- unsigned short cbl; /* number of bytes read */
- unsigned short mbl; /* max size buffer */
- unsigned char *mbf; /* pointer to buffer */
- unsigned char urgdata; /* buffer for urgent data */
- int fd_async; /* TRUE --> fd is in async mode */
- int deferred_event; /* TRUE --> deferred event signaled */
- cmi_reason_t deferred_reason; /* reason for deferred event */
- cmi_status_t deferred_status; /* status for deferred event */
- int sta; /* CM_ state */
- int prev_sta; /* CM_ state before URG WRITE, to be restored after URG WRITE completes */
- void (*err)(struct CLB *); /* link status error callback - not used */
- void (*ast)(struct CLB *); /* I/O call back for async read/write */
+ que_ent cqe; /* forward/backward links */
+ struct NTD *ntd; /* back pointer to ntd */
+ cmi_descriptor nod; /* node */
+ cmi_descriptor tnd; /* taskname */
+ struct sockaddr_storage peer_sas; /* peer */
+ struct addrinfo peer_ai; /* peer */
+ int mun; /* endpoint's file descriptor */
+ void *usr; /* client specific storage */
+ qio_iosb ios; /* used for tracking inprocess I/O */
+ unsigned short cbl; /* number of bytes read */
+ unsigned short mbl; /* max size buffer */
+ unsigned char *mbf; /* pointer to buffer */
+ unsigned char urgdata; /* buffer for urgent data */
+ int fd_async; /* TRUE --> fd is in async mode */
+ int deferred_event; /* TRUE --> deferred event signaled */
+ cmi_reason_t deferred_reason; /* reason for deferred event */
+ cmi_status_t deferred_status; /* status for deferred event */
+ int sta; /* CM_ state */
+ int prev_sta; /* CM_ state before URG WRITE, to be restored after URG WRITE completes */
+ void (*err)(struct CLB *); /* link status error callback - not used */
+ void (*ast)(struct CLB *); /* I/O call back for async read/write */
struct clb_stat_struct stt;
};
@@ -215,8 +218,7 @@ cmi_status_t cmj_write_start(struct CLB *lnk);
cmi_status_t cmj_write_urg_start(struct CLB *lnk);
void cmj_write_interrupt(struct CLB *lnk, int signo);
void cmj_init_clb(struct NTD *tsk, struct CLB *lnk);
-cmi_status_t cmj_resolve_nod_tnd(cmi_descriptor *nod, cmi_descriptor *tnd, struct sockaddr_in *inp);
-cmi_status_t cmj_getsockaddr(cmi_descriptor *tnd, struct sockaddr_in *inp);
+cmi_status_t cmj_getsockaddr(cmi_descriptor *nod, cmi_descriptor *tnd, struct addrinfo **ai_ptr);
cmi_status_t cmi_write_urg(struct CLB *c, unsigned char data);
cmi_status_t cmi_init(
cmi_descriptor *tnd,
diff --git a/sr_unix/comlist.csh b/sr_unix/comlist.csh
index 909021c..1dbd4c3 100644
--- a/sr_unix/comlist.csh
+++ b/sr_unix/comlist.csh
@@ -1,6 +1,6 @@
#################################################################
# #
-# Copyright 2001, 2012 Fidelity Infromation Services, Inc #
+# Copyright 2001, 2013 Fidelity Infromation Services, Inc #
# #
# This source code contains the intellectual property #
# of its copyright holder(s), and is made available #
@@ -495,8 +495,18 @@ endif
if ( $?gt_as_use_prebuilt == 0 ) then
# Finally assemble any sources originally in native dialect so they
# can supersede any conflicting non-native dialect sources:
- foreach asm (${gs[1]}/*${gt_as_src_suffix})
- $shell $gtm_tools/gt_as.csh $asm
+ @ asm_batch_size=25
+ @ asm_batch_tail = ${asm_batch_size} + 1
+ set asmlist=(`echo ${gs[1]}/*${gt_as_src_suffix}`)
+ while ($#asmlist)
+ if (${#asmlist} > ${asm_batch_size}) then
+ set asmsublist=(${asmlist[1-${asm_batch_size}]})
+ set asmlist=(${asmlist[${asm_batch_tail}-]})
+ else
+ set asmsublist=(${asmlist})
+ set asmlist=()
+ endif
+ $shell $gtm_tools/gt_as.csh ${asmsublist}
end
else
cp -p $gtm_vrt/$gt_as_use_prebuilt/*.o .
@@ -657,40 +667,77 @@ rm -f GTMDefinedTypesInit.m >& /dev/null
echo "Generating GTMDefinedTypesInit.m"
if ($?work_dir) then
if (-e $work_dir/tools/cms_tools/gengtmdeftypes.csh) then
+ echo "Using gengtmdeftypes.csh from $work_dir"
$work_dir/tools/cms_tools/gengtmdeftypes.csh >& obj/gengtmdeftypes.log
+ @ savestatus = $status
else
$cms_tools/gengtmdeftypes.csh >& obj/gengtmdeftypes.log
+ @ savestatus = $status
endif
else
$cms_tools/gengtmdeftypes.csh >& obj/gengtmdeftypes.log
-endif
-if ((0 != $status) || (! -e GTMDefinedTypesInit.m)) then
@ savestatus = $status
- if (`expr $gtm_verno \< V900`) @ comlist_status = $savestatus # note no errors for development versions
- echo "gengtmdeftypes.csh failed to create GTMDefinedTypesInit.m - see log in $gtm_obj/gengtmdeftypes.log" >> \
- $gtm_log/error.`basename $gtm_exe`.log
+endif
+if ((0 != $savestatus) || (! -e GTMDefinedTypesInit.m)) then
+ set errmsg = "COMLIST-E-FAIL gengtmdeftypes.csh failed to create GTMDefinedTypesInit.m "
+ set errmsg = "$errmsg - see log in $gtm_obj/gengtmdeftypes.log"
+ if (`expr $gtm_verno \< V900`) then
+ @ comlist_status = $savestatus # No errors for development - this fails the build
+ else
+ echo "Warning: Build of $gtm_verno on $HOST, $errmsg" | \
+ mailx -s "${HOST}: Build for $gtm_verno failed to create GTMDefinedTypes.m" $USER
+ endif
+ echo $errmsg >> $gtm_log/error.`basename $gtm_exe`.log
endif
if (-e GTMDefinedTypesInit.m) then
# Need a different name for each build type as they can be different
cp -f GTMDefinedTypesInit.m $gtm_pct/GTMDefinedTypesInit${bldtype}.m
+ setenv LC_CTYPE C
+ setenv gtm_chset M
./mumps GTMDefinedTypesInit.m
- if (0 != $status) then
- if (`expr $gtm_verno \>= V900`) @ comlist_status = $status
- echo "Failed to compile $gtm_exe/GTMDefinedTypes.m" >> $gtm_log/error.`basename $gtm_exe`.log
+ @ savestatus = $status
+ if (0 != $savestatus) then
+ set errmsg = "COMLIST-E-FAIL Failed to compile generated $gtm_exe/GTMDefinedTypes.m"
+ if (`expr $gtm_verno \< V900`) then
+ @ comlist_status = $savestatus
+ else
+ echo "Warning: During build of $gtm_verno on $HOST, ${errmsg}" | \
+ mailx -s "${HOST}: Compile for GTMDefinedTypes.m failed during build of $gtm_verno" $USER
+ endif
+ echo "${errmsg}" >> $gtm_log/error.`basename $gtm_exe`.log
endif
- # If we have a utf8 dir (created by buildaux.csh called from buildbdp.csh above), add a link to it for GTMDefinedTypesInit.m
- if (-e $gtm_dist/utf8) then
+ # If we have a utf8 dir (created by buildaux.csh called from buildbdp.csh above), add a link to it for
+ # GTMDefinedTypesInit.m and compile it in UTF8 mode
+ source $gtm_tools/set_library_path.csh
+ source $gtm_tools/check_unicode_support.csh
+ if (-e $gtm_dist/utf8 && ("TRUE" == "$is_unicode_support")) then
if (! -e $gtm_dist/utf8/GTMDefinedTypesInit.m) then
ln -s $gtm_dist/GTMDefinedTypesInit.m $gtm_dist/utf8/GTMDefinedTypesInit.m
endif
pushd utf8
+ # Switch to UTF8 mode
+ if ( "OS/390" == $HOSTOS ) setenv gtm_chset_locale $utflocale # LC_CTYPE not picked up right
+ setenv LC_CTYPE $utflocale
+ unsetenv LC_ALL
+ setenv gtm_chset UTF-8 # switch to "UTF-8" mode
# mumps executable not yet linked to utf8 dir so access it in parent directory
../mumps GTMDefinedTypesInit.m
- if (0 != $status) then
- if (`expr $gtm_verno \>= V900`) @ comlist_status = $status
- echo "Failed to compile $gtm_exe/GTMDefinedTypes.m" >> $gtm_log/error.`basename $gtm_exe`.log
+ @ savestatus = $status
+ if (0 != $savestatus) then
+ set errmsg = "COMLIST_E-FAIL Failed to compile generated $gtm_exe/utf8/GTMDefinedTypes.m"
+ if (`expr $gtm_verno \< V900`) then
+ @ comlist_status = $savestatus
+ else
+ echo "Warning: During build of $gtm_verno on $HOST, ${errmsg}" | \
+ mailx -s "${HOST}: Compile for utf8/GTMDefinedTypes.m failed during build of $gtm_verno" \
+ $USER
+ endif
+ echo "${errmsg}" >> $gtm_log/error.`basename $gtm_exe`.log
endif
popd
+ setenv LC_CTYPE C
+ unsetenv gtm_chset # switch back to "M" mode
+ if ( "OS/390" == $HOSTOS ) unsetenv gtm_chset_locale
endif
endif
@@ -701,40 +748,27 @@ exit
GDE_in1
if (0 != $status) @ comlist_status = $status
-# Create the GT.M help database file.
-setenv gtmgbldir $gtm_dist/gtmhelp.gld
-gde <<GDE_in_gtmhelp
-Change -segment DEFAULT -block=2048 -file=$gtm_dist/gtmhelp.dat
+# Create the GT.M/GDE/MUPIP/DSE/LKE help databases
+foreach hlp (*.hlp)
+ 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_gtmhelp
-if (0 != $status) @ comlist_status = $status
+GDE_in_help
+ if (0 != $status) @ comlist_status = $status
-mupip create
-if (0 != $status) @ comlist_status = $status
+ mupip create
+ if (0 != $status) @ comlist_status = $status
-gtm <<GTM_in_gtmhelp
+ gtm <<GTM_in_gtmhelp
Do ^GTMHLPLD
-$gtm_dist/mumps.hlp
+$gtm_dist/${hlp}
Halt
GTM_in_gtmhelp
-if (0 != $status) @ comlist_status = $status
-
-# Create the GDE help database file.
-setenv gtmgbldir $gtm_dist/gdehelp.gld
-gde <<GDE_in_gdehelp
-Change -segment DEFAULT -block=2048 -file=$gtm_dist/gdehelp.dat
-Change -region DEFAULT -record=1020 -key=255
-GDE_in_gdehelp
-if (0 != $status) @ comlist_status = $status
-
-mupip create
-if (0 != $status) @ comlist_status = $status
-
-gtm <<GTM_in_gdehelp
-Do ^GTMHLPLD
-$gtm_dist/gde.hlp
-GTM_in_gdehelp
-if (0 != $status) @ comlist_status = $status
+ if (0 != $status) @ comlist_status = $status
+end
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/configure.gtc b/sr_unix/configure.gtc
index 7db8be7..6409351 100644
--- a/sr_unix/configure.gtc
+++ b/sr_unix/configure.gtc
@@ -15,6 +15,10 @@
# Path to the correct echo program
if [ $arch = "sun" -o $arch = "solaris" ]; then
echo=/usr/5bin/echo
+ # Solaris 11 does not have /usr/5bin/echo
+ if [ ! -f $echo ]; then
+ echo=/usr/bin/echo
+ fi
elif [ $arch = "linux" ]; then
echo="/bin/echo -e"
else
@@ -92,7 +96,7 @@ if [ $deliver_gtcm_gnp = "yes" ]; then
fi
# Other files
-hlpfiles="gdehelp.dat gtmhelp.dat *.h"
+hlpfiles="*help.dat *help.gld *.h"
if [ $arch = "sco" ]; then
ofiles="$hlpfiles esnecil"
elif [ $arch = "sun" -o $arch = "solaris" ]; then
@@ -128,10 +132,10 @@ if [ $arch = "zos" ]; then
# use uid 0 for super user and group
defowner=0
rootuser=0
- binuser=0
+ bingroup=0
else
rootuser=root
- binuser=bin
+ bingroup=bin
defowner=bin
fi
@@ -152,15 +156,15 @@ if [ 0 != "$?" ] ; then
exit
fi
-$echo "What group should own the files? ($binuser) \c"
+$echo "What group should own the files? ($bingroup) \c"
read resp
if [ "$resp" != "" ] ; then
- binuser=$resp
+ bingroup=$resp
fi
-chgrp $binuser tmp_owngrp 2> /dev/null
+chgrp $bingroup tmp_owngrp 2> /dev/null
if [ 0 != "$?" ] ; then
- $echo $binuser is not a valid group name - exiting!
+ $echo $bingroup is not a valid group name - exiting!
rm tmp_owngrp
exit 1
fi
@@ -168,7 +172,7 @@ fi
$echo "Should execution of GT.M be restricted to this group? (y or n) \c"
read resp
if [ "$resp" = "Y" -o "$resp" = "y" ] ; then
- group=$binuser
+ group=$bingroup
fi
rm tmp_owngrp
@@ -191,7 +195,7 @@ if [ -d $gtmdist ]; then
if [ "$resp" = "Y" -o "$resp" = "y" ] ; then
chmod 0755 $gtmdist
chown $owner $gtmdist
- chgrp $binuser $gtmdist
+ chgrp $bingroup $gtmdist
else
exit
fi
@@ -205,7 +209,7 @@ else
mkdir -p $gtmdist/plugin/r $gtmdist/plugin/o
chmod 0755 $gtmdist
chown $owner $gtmdist
- chgrp $binuser $gtmdist
+ chgrp $bingroup $gtmdist
else
exit
fi
@@ -347,7 +351,7 @@ if [ -d "utf8" ]; then
fi
fi
# Look for locale
- utflocale=`locale -a | grep -i .utf | sed 's/.lp64$//' | grep '8$' | head -n1`
+ utflocale=`locale -a | grep -i .utf | sed 's/.lp64$//' | grep '8$' | head -n 1`
if [ "$utflocale" = "" ] ; then
$echo "WARNING: UTF8 locale not found. Not installing UTF-8 support."
fi
@@ -465,17 +469,17 @@ done
for i in $binaries
do
if [ $arch = "sun" -o $arch = "linux" ]; then
- install -g $binuser -o $owner -m 644 $i $gtmdist
+ install -g $bingroup -o $owner -m 644 $i $gtmdist
elif [ $arch = "ibm" ]; then
- /usr/bin/install -f $gtmdist -M 644 -O $owner -G $binuser $i
+ /usr/bin/install -f $gtmdist -M 644 -O $owner -G $bingroup $i
elif [ -x /usr/sbin/install ]; then
- /usr/sbin/install -f $gtmdist -m 644 -u $owner -g $binuser $i $gtmdist
+ /usr/sbin/install -f $gtmdist -m 644 -u $owner -g $bingroup $i $gtmdist
elif [ $arch = "zos" ]; then
cp $i $gtmdist/
chmod 644 $gtmdist/$i
- chown $user:$binuser $gtmdist/$i
+ chown $user:$bingroup $gtmdist/$i
else
- install -f $gtmdist -m 644 -u $owner -g $binuser $i $gtmdist
+ install -f $gtmdist -m 644 -u $owner -g $bingroup $i $gtmdist
fi
# strip $gtmdist/$i >/dev/null 2>&1
done
@@ -535,10 +539,10 @@ if [ -d "$plugin_gtmcrypt" ]; then
mkdir -p $gtmdist/plugin/gtmcrypt
chmod 0755 $gtmdist/plugin
chown $owner $gtmdist/plugin
- chgrp $binuser $gtmdist/plugin
+ chgrp $bingroup $gtmdist/plugin
chmod 0755 $gtmdist/plugin/gtmcrypt
chown $owner $gtmdist/plugin/gtmcrypt/
- chgrp $binuser $gtmdist/plugin/gtmcrypt
+ chgrp $bingroup $gtmdist/plugin/gtmcrypt
#Install the plugin related scripts
@@ -547,25 +551,25 @@ if [ -d "$plugin_gtmcrypt" ]; then
cp $plugin_gtmcrypt/$i $gtmdist/$plugin_gtmcrypt/$i
chmod 0755 $gtmdist/$plugin_gtmcrypt/$i
chown $owner $gtmdist/$plugin_gtmcrypt/$i
- chgrp $binuser $gtmdist/$plugin_gtmcrypt/$i
+ chgrp $bingroup $gtmdist/$plugin_gtmcrypt/$i
done
# Install the plugin binaries
for i in $gtmcryptbinaries
do
if [ $arch = "sun" -o $arch = "linux" ]; then
- install -g $binuser -o $owner -m 755 $plugin_gtmcrypt/$i $gtmdist/$plugin_gtmcrypt
+ install -g $bingroup -o $owner -m 755 $plugin_gtmcrypt/$i $gtmdist/$plugin_gtmcrypt
elif [ $arch = "ibm" ]; then
- /usr/bin/install -f $gtmdist/$plugin_gtmcrypt -M 755 -O $owner -G $binuser $plugin_gtmcrypt/$i
+ /usr/bin/install -f $gtmdist/$plugin_gtmcrypt -M 755 -O $owner -G $bingroup $plugin_gtmcrypt/$i
elif [ $arch = "zos" ]; then
cp $plugin_gtmcrypt/$i $gtmdist/$plugin_gtmcrypt
chmod 755 $gtmdist/$plugin_gtmcrypt/$i
- chown $user:$binuser $gtmdist/$plugin_gtmcrypt/$i
+ chown $user:$bingroup $gtmdist/$plugin_gtmcrypt/$i
elif [ -x /usr/sbin/install ]; then
- /usr/sbin/install -f $gtmdist/$plugin_gtmcrypt -m 755 -u $owner -g $binuser \
+ /usr/sbin/install -f $gtmdist/$plugin_gtmcrypt -m 755 -u $owner -g $bingroup \
$plugin_gtmcrypt/$i $gtmdist/$plugin_gtmcrypt
else
- install -f $gtmdist/$plugin_gtmcrypt -m 755 -u $owner -g $binuser \
+ install -f $gtmdist/$plugin_gtmcrypt -m 755 -u $owner -g $bingroup \
$plugin_gtmcrypt/$i $gtmdist/$plugin_gtmcrypt
fi
done
@@ -574,21 +578,21 @@ if [ -d "$plugin_gtmcrypt" ]; then
for i in $gtmcryptsharedlibs
do
# Install only files (and not symlinks) that exist
- if [ ! -e $plugin/$i -o -L $plugin/$i ]; then
- # CMake builds generate only one library - GCRYPT with AES256CFB
+ # CMake builds generate only one library - GCRYPT with AES256CFB
+ if [ -L $plugin/$i -o ! -f $plugin/$i ]; then
continue
elif [ $arch = "sun" -o $arch = "linux" ]; then
- install -g $binuser -o $owner -m 755 $plugin/$i $gtmdist/$plugin
+ install -g $bingroup -o $owner -m 755 $plugin/$i $gtmdist/$plugin
elif [ $arch = "ibm" ]; then
- /usr/bin/install -f $gtmdist/$plugin -M 755 -O $owner -G $binuser $plugin/$i
+ /usr/bin/install -f $gtmdist/$plugin -M 755 -O $owner -G $bingroup $plugin/$i
elif [ $arch = "zos" ]; then
cp $plugin/$i $gtmdist/$plugin
chmod 755 $gtmdist/$plugin/$i
- chown $user:$binuser $gtmdist/$plugin/$i
+ chown $user:$bingroup $gtmdist/$plugin/$i
elif [ -x /usr/sbin/install ]; then
- /usr/sbin/install -f $gtmdist/$plugin -m 755 -u $owner -g $binuser $plugin/$i $gtmdist/$plugin
+ /usr/sbin/install -f $gtmdist/$plugin -m 755 -u $owner -g $bingroup $plugin/$i $gtmdist/$plugin
else
- install -f $gtmdist/$plugin -m 755 -u $owner -g $binuser $plugin/$i $gtmdist/$plugin
+ install -f $gtmdist/$plugin -m 755 -u $owner -g $bingroup $plugin/$i $gtmdist/$plugin
fi
done
@@ -602,7 +606,7 @@ if [ -d "$plugin_gtmcrypt" ]; then
cp $plugin_gtmcrypt/$gtmcryptmfile $gtmdist/$plugin_gtmcrypt/$gtmcryptmfile
chmod 0644 $gtmdist/$plugin_gtmcrypt/$gtmcryptmfile
chown $owner $gtmdist/$plugin_gtmcrypt/$gtmcryptmfile
- chgrp $binuser $gtmdist/$plugin_gtmcrypt/$gtmcryptmfile
+ chgrp $bingroup $gtmdist/$plugin_gtmcrypt/$gtmcryptmfile
# Install other plugin files
for i in $gtmcryptofiles
@@ -610,7 +614,7 @@ if [ -d "$plugin_gtmcrypt" ]; then
cp $plugin_gtmcrypt/$i $gtmdist/$plugin_gtmcrypt
chmod 0644 $gtmdist/$plugin_gtmcrypt/$i
chown $owner $gtmdist/$plugin_gtmcrypt/$i
- chgrp $binuser $gtmdist/$plugin_gtmcrypt/$i
+ chgrp $bingroup $gtmdist/$plugin_gtmcrypt/$i
done
# Install gpgagent.tab
@@ -619,10 +623,10 @@ if [ -d "$plugin_gtmcrypt" ]; then
cat $plugin/gpgagent.tab | sed 1d >> $gtmdist/$plugin/gpgagent.tab
# Tar the source files
- (cd $plugin_gtmcrypt; chmod 0644 $gtmcryptsrcfiles; chown $owner $gtmcryptsrcfiles; chgrp $binuser $gtmcryptsrcfiles)
- (cd $plugin_gtmcrypt; chmod 0555 $gtmcryptbldfiles; chown $owner $gtmcryptbldfiles; chgrp $binuser $gtmcryptbldfiles)
+ (cd $plugin_gtmcrypt; chmod 0644 $gtmcryptsrcfiles; chown $owner $gtmcryptsrcfiles; chgrp $bingroup $gtmcryptsrcfiles)
+ (cd $plugin_gtmcrypt; chmod 0555 $gtmcryptbldfiles; chown $owner $gtmcryptbldfiles; chgrp $bingroup $gtmcryptbldfiles)
(cd $plugin_gtmcrypt; tar -cvf source.tar $gtmcryptsrcfiles >/dev/null 2>&1; mv source.tar $gtmdist/$plugin_gtmcrypt)
- (cd $gtmdist/$plugin_gtmcrypt; chmod 0644 source.tar; chown $owner source.tar; chgrp $binuser source.tar)
+ (cd $gtmdist/$plugin_gtmcrypt; chmod 0644 source.tar; chown $owner source.tar; chgrp $bingroup source.tar)
fi
# Install GDE, GTMHELP, and all the percent routines
@@ -637,6 +641,10 @@ if [ "$doutf8" -ne 0 ]; then
if [ -d $file ]; then
continue
fi
+ # Skip gtmsecshr/dir
+ if [ "$file" = "gtmsecshr" -o "$file" = "gtmsecshrdir" ]; then
+ continue
+ fi
# Install .o files
base="`basename $file .o`"
if [ "$base" != "$file" ]; then
@@ -699,9 +707,9 @@ if [ "$doutf8" -ne 0 ]; then
# Enclose UTF-8 operations inside a subshell. This avoids changing the current M mode execution
(
# Ensure we ARE in UTF-8 mode
- utflocale=`locale -a | grep -i en_us | grep -i utf | grep '8$'`
+ utflocale=`locale -a | grep -i en_us | grep -i utf | grep '8$' | head -n 1`
if [ $arch = "zos" ]; then
- utflocale=`locale -a | grep -i en_us | grep -i utf | sed 's/.lp64$//' | grep '8$' | head -n1`
+ utflocale=`locale -a | grep -i en_us | grep -i utf | sed 's/.lp64$//' | grep '8$' | head -n 1`
fi
if [ $utflocale = "" ]; then
@@ -743,9 +751,9 @@ chmod 0644 $gtmdist/*.o
chown $owner $gtmdist/*.m
chown $owner $gtmdist/*.o
chown $owner $gtmdist/*.txt
-chgrp $binuser $gtmdist/*.m
-chgrp $binuser $gtmdist/*.o
-chgrp $binuser $gtmdist/*.txt
+chgrp $bingroup $gtmdist/*.m
+chgrp $bingroup $gtmdist/*.o
+chgrp $bingroup $gtmdist/*.txt
if [ "$doutf8" -ne 0 ]; then
chmod 0644 $gtmdist/utf8/*.m
@@ -754,15 +762,15 @@ if [ "$doutf8" -ne 0 ]; then
chown $owner $gtmdist/utf8/*.m
chown $owner $gtmdist/utf8/*.o
chown $owner $gtmdist/utf8/*.txt
- chgrp $binuser $gtmdist/utf8/*.m
- chgrp $binuser $gtmdist/utf8/*.o
- chgrp $binuser $gtmdist/utf8/*.txt
+ chgrp $bingroup $gtmdist/utf8/*.m
+ chgrp $bingroup $gtmdist/utf8/*.o
+ chgrp $bingroup $gtmdist/utf8/*.txt
fi
if [ "$dogtmcrypt" -ne 0 ]; then
chmod 0644 $gtmdist/plugin/gtmcrypt/*.m
chown $owner $gtmdist/plugin/gtmcrypt/*.m
- chgrp $binuser $gtmdist/plugin/gtmcrypt/*.m
+ chgrp $bingroup $gtmdist/plugin/gtmcrypt/*.m
fi
gtm_dist=$gtmdist
@@ -775,28 +783,6 @@ else
fi
export gtmroutines
-# Create the global directories for the help databases.
-
-gtmgbldir=$gtmdist/gtmhelp.gld
-export gtmgbldir
-
-cat <<GDE.in1 | $gtmdist/mumps -direct
-Do ^GDE
-Change -segment DEFAULT -block=2048 -file=\$gtm_dist/gtmhelp.dat
-Change -region DEFAULT -record=1020 -key=255
-Exit
-GDE.in1
-
-gtmgbldir=$gtmdist/gdehelp.gld
-export gtmgbldir
-
-cat <<GDE.in2 | $gtmdist/mumps -direct
-Do ^GDE
-Change -segment DEFAULT -block=2048 -file=\$gtm_dist/gdehelp.dat
-Change -region DEFAULT -record=1020 -key=255
-Exit
-GDE.in2
-
other_object_files="CHK2LEV.o CHKOP.o GENDASH.o GENOUT.o GETNEAR.o GTMHLPLD.o LOAD.o LOADOP.o"
other_object_files="$other_object_files LOADVX.o MSG.o TTTGEN.o TTTSCAN.o UNLOAD.o GTMDefinedTypesInit.o"
csh_script_files=""
@@ -804,11 +790,6 @@ if [ $arch = "zos" ]; then
other_object_files="$other_object_files GENEXPORT.o"
fi
-if [ "$doutf8" -ne 0 ]; then
- # make symbolic links to gtmhelp.gld and gdehelp.gld
- (cd $gtmdist/utf8; ln -s ../gtmhelp.gld gtmhelp.gld; ln -s ../gdehelp.gld gdehelp.gld)
-fi
-
# make database files read only
chmod 0444 $gtmdist/*.dat
chmod 0444 $gtmdist/*.gld
@@ -828,12 +809,16 @@ cd $savedir
# Optionally remove .o files if they are in a shared library
if [ -f $gtm_dist/libgtmutil$ext ] ; then
- $echo ""
- $echo "Object files of M routines placed in shared library $gtm_dist/libgtmutil$ext"
- $echo "Keep original .o object files (y or n)? \c"
- read resp
- if [ "n" = $resp -o "N" = $resp ] ; then rm -f $gtm_dist/*.o $gtm_dist/utf8/*.o ; fi
- $echo ""
+ chown ${owner}:${bingroup} $gtm_dist/libgtmutil$ext
+ $echo ""
+ $echo "Object files of M routines placed in shared library $gtm_dist/libgtmutil$ext"
+ $echo "Keep original .o object files (y or n)? \c"
+ read resp
+ if [ "n" = $resp -o "N" = $resp ] ; then rm -f $gtm_dist/*.o $gtm_dist/utf8/*.o ; fi
+ $echo ""
+ if [ -f $gtm_dist/utf8/libgtmutil$ext ] ; then
+ chown ${owner}:${bingroup} $gtm_dist/utf8/libgtmutil$ext
+ fi
fi
# change group ownership of all files if group restricted
@@ -846,43 +831,59 @@ if [ "$group" != "" ] ; then
chmod -R o-rwx $gtmdist
fi
else
- chgrp -R $binuser $gtmdist
+ chgrp -R $bingroup $gtmdist
fi
# Install real gtmsecshr with special permissions in $gtmdist/gtmsecshrdir
tgtmsecshrdir=$gtmdist/gtmsecshrdir
mkdir $tgtmsecshrdir
chmod 700 $tgtmsecshrdir
-chgrp $binuser $tgtmsecshrdir
+chgrp $bingroup $tgtmsecshrdir
# Install gtmsecshr and the wrapper with special permissions
if [ $arch = "sun" -o $arch = "linux" ]; then
- install -m 4555 -o root -g $binuser gtmsecshr $gtmdist
- install -m 4500 -o root -g $binuser gtmsecshrdir/gtmsecshr $tgtmsecshrdir/gtmsecshr
+ install -m 4555 -o root -g $bingroup gtmsecshr $gtmdist
+ install -m 4500 -o root -g $bingroup gtmsecshrdir/gtmsecshr $tgtmsecshrdir/gtmsecshr
elif [ $arch = "ibm" ]; then
- /usr/bin/install -f $gtmdist -M 4555 -O root -G $binuser gtmsecshr
- /usr/bin/install -f $tgtmsecshrdir -M 4500 -O root -G $binuser gtmsecshrdir/gtmsecshr
+ /usr/bin/install -f $gtmdist -M 4555 -O root -G $bingroup gtmsecshr
+ /usr/bin/install -f $tgtmsecshrdir -M 4500 -O root -G $bingroup gtmsecshrdir/gtmsecshr
elif [ -x /usr/sbin/install ]; then
- /usr/sbin/install -f $gtmdist -m 4555 -u root -g $binuser gtmsecshr $gtmdist
- /usr/sbin/install -f $tgtmsecshrdir -m 4500 -u root -g $binuser gtmsecshrdir/gtmsecshr $tgtmsecshrdir
+ /usr/sbin/install -f $gtmdist -m 4555 -u root -g $bingroup gtmsecshr $gtmdist
+ /usr/sbin/install -f $tgtmsecshrdir -m 4500 -u root -g $bingroup gtmsecshrdir/gtmsecshr $tgtmsecshrdir
elif [ $arch = "zos" ]; then
cp gtmsecshr $gtmdist/gtmsecshr
cp gtmsecshrdir/gtmsecshr $tgtmsecshrdir/gtmsecshr
- chown $rootuser:$binuser $gtmdist/gtmsecshr $tgtmsecshrdir/gtmsecshr
+ chown $rootuser:$bingroup $gtmdist/gtmsecshr $tgtmsecshrdir/gtmsecshr
chmod 4555 $gtmdist/gtmsecshr
chmod 4500 $tgtmsecshrdir/gtmsecshr
else
- install -f $gtmdist -m 4555 -u root -g $binuser gtmsecshr $gtmdist
- install -f $tgtmsecshrdir -m 4500 -u root -g $binuser gtmsecshrdir/gtmsecshr $tgtmsecshrdir
-fi
-
-if [ -d $gtmdist/utf8 ]; then
- (cd $gtmdist/utf8; ln -s ../gtmsecshrdir gtmsecshrdir; ln -s ../gtmsecshr gtmsecshr)
+ install -f $gtmdist -m 4555 -u root -g $bingroup gtmsecshr $gtmdist
+ install -f $tgtmsecshrdir -m 4500 -u root -g $bingroup gtmsecshrdir/gtmsecshr $tgtmsecshrdir
fi
strip $gtmdist/gtmsecshr > /dev/null 2>&1
strip $tgtmsecshrdir/gtmsecshr > /dev/null 2>&1
+if [ -d $gtmdist/utf8 ]; then
+
+ # Delete the gtmsecshr symlink
+ if [ -f $gtmdist/utf8/gtmsecshr -o -h $gtmdist/utf8/gtmsecshr ]; then
+ rm -f $gtmdist/utf8/gtmsecshr
+ fi
+ ln $gtmdist/gtmsecshr $gtmdist/utf8/gtmsecshr || \
+ echo ln $gtmdist/gtmsecshr $gtmdist/utf8/gtmsecshr
+
+ # Delete the gtmsecshrdir symlink
+ if [ -f $gtmdist/utf8/gtmsecshrdir -o -h $gtmdist/utf8/gtmsecshrdir ]; then
+ rm -f $gtmdist/utf8/gtmsecshrdir
+ fi
+ mkdir -p $gtmdist/utf8/gtmsecshrdir
+ chmod 0500 $gtmdist/utf8/gtmsecshrdir
+ ln $gtmdist/gtmsecshrdir/gtmsecshr $gtmdist/utf8/gtmsecshrdir/gtmsecshr || \
+ echo ln $gtmdist/gtmsecshrdir/gtmsecshr $gtmdist/utf8/gtmsecshrdir/gtmsecshr
+
+fi
+
# change group ownership of wrapper if group restricted
# also remove user privileges for wrapper if group changed
if [ "$group" != "" ] ; then
@@ -928,7 +929,7 @@ read resp
if [ "$resp" = "Y" -o "$resp" = "y" ] ; then
\rm -rf $binaries $pathmods $rscripts $nscripts $dirs configure \
*.gtc gtm* gde* GDE*.o _*.m _*.o mumps.dat mumps.gld geteuid $other_object_files $csh_script_files lowerc_cp\
- esnecil *.hlp core *.h libgtmrpc.a *.m gdehelp.* COPYING README.txt
+ esnecil *.hlp core *.h libgtmrpc.a *.m *help.dat *help.gld COPYING README.txt
\rm -rf GETPASS.o plugin PINENTRY.o GTMHELP.o custom_errors_sample.txt
if [ -d utf8 ]; then
\rm -rf utf8
diff --git a/sr_unix/continue_handler.c b/sr_unix/continue_handler.c
index d5d8eb1..c8cca0a 100644
--- a/sr_unix/continue_handler.c
+++ b/sr_unix/continue_handler.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -12,6 +12,9 @@
#include <mdef.h>
#include <signal.h>
+#ifdef GTM_PTHREAD
+# include <pthread.h>
+#endif
#include "gtm_syslog.h"
#include "gtm_limits.h"
@@ -24,7 +27,7 @@
GBLREF volatile int suspend_status;
GBLREF io_pair io_std_device;
-GBLREF pid_t process_id;
+GBLREF uint4 process_id;
error_def(ERR_REQ2RESUME);
@@ -34,6 +37,7 @@ void continue_handler(int sig, siginfo_t *info, void *context)
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
+ FORWARD_SIG_TO_MAIN_THREAD_IF_NEEDED(sig);
/* Count how many times we get a continue-process signal (in DEBUG) */
DEBUG_ONLY(DBGGSSHR((LOGFLAGS, "continue_handler: pid %d, continue_proc_cnt bumped from %d to %d\n",
process_id, TREF(continue_proc_cnt), TREF(continue_proc_cnt) + 1)));
diff --git a/sr_unix/ctrlc_handler.c b/sr_unix/ctrlc_handler.c
index cf74c15..583c641 100644
--- a/sr_unix/ctrlc_handler.c
+++ b/sr_unix/ctrlc_handler.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -13,6 +13,10 @@
#include <errno.h>
#include <signal.h>
+#ifdef GTM_PTHREAD
+# include <pthread.h>
+#endif
+
#include "ctrlc_handler.h"
#include "std_dev_outbndset.h"
@@ -21,8 +25,9 @@ void ctrlc_handler(int sig)
int4 ob_char;
int save_errno;
- if (sig == SIGINT)
+ if (SIGINT == sig)
{
+ FORWARD_SIG_TO_MAIN_THREAD_IF_NEEDED(sig);
save_errno = errno;
ob_char = 3;
std_dev_outbndset(ob_char);
diff --git a/sr_unix/db_ipcs_reset.c b/sr_unix/db_ipcs_reset.c
index 934f150..d341e30 100644
--- a/sr_unix/db_ipcs_reset.c
+++ b/sr_unix/db_ipcs_reset.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -106,7 +106,7 @@ boolean_t db_ipcs_reset(gd_region *reg)
return FALSE;
}
assert((udi->semid == csd->semid) || (INVALID_SEMID == csd->semid));
- semval = semctl(udi->semid, 1, GETVAL); /* Get the counter semaphore's value */
+ semval = semctl(udi->semid, DB_COUNTER_SEM, GETVAL); /* Get the counter semaphore's value */
assert(1 <= semval);
if (1 < semval)
{
@@ -114,14 +114,14 @@ boolean_t db_ipcs_reset(gd_region *reg)
assert(!reg->read_only); /* ONLINE ROLLBACK must be a read/write process */
if (!reg->read_only)
{
- if (0 != (save_errno = do_semop(udi->semid, 1, -1, SEM_UNDO)))
+ if (0 != (save_errno = do_semop(udi->semid, DB_COUNTER_SEM, -1, SEM_UNDO)))
{
gtm_putmsg(VARLSTCNT(8) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_TEXT, 2,
RTS_ERROR_TEXT("db_ipcs_reset - write semaphore release"), save_errno);
return FALSE;
}
- assert(1 == (semval = semctl(udi->semid, 0, GETVAL)));
- if (0 != (save_errno = do_semop(udi->semid, 0, -1, SEM_UNDO)))
+ assert(1 == (semval = semctl(udi->semid, DB_CONTROL_SEM, GETVAL)));
+ if (0 != (save_errno = do_semop(udi->semid, DB_CONTROL_SEM, -1, SEM_UNDO)))
{
gtm_putmsg(VARLSTCNT(8) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_TEXT, 2,
RTS_ERROR_TEXT("db_ipcs_reset - access control semaphore release"), save_errno);
@@ -185,6 +185,7 @@ boolean_t db_ipcs_reset(gd_region *reg)
}
}
udi->grabbed_access_sem = FALSE;
+ udi->counter_acc_incremented = FALSE;
CLOSEFILE_RESET(udi->fd, status); /* resets "udi->fd" to FD_INVALID */
if (0 != status)
gtm_putmsg(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), status);
diff --git a/sr_unix/dbcertify_deferred_signal_handler.c b/sr_unix/dbcertify_deferred_signal_handler.c
index 1605bec..146b958 100644
--- a/sr_unix/dbcertify_deferred_signal_handler.c
+++ b/sr_unix/dbcertify_deferred_signal_handler.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2005, 2010 Fidelity Information Services, Inc *
+ * Copyright 2005, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -33,9 +33,9 @@
#include "gdsfhead.h"
#include "v15_gdsfhead.h"
#include "gdsblkops.h"
+#include "have_crit.h"
#include "dbcertify.h"
-GBLREF VSIG_ATOMIC_T forced_exit;
GBLREF int4 exi_condition;
GBLREF int forced_exit_err;
GBLREF uint4 process_id;
@@ -45,16 +45,16 @@ GBLREF boolean_t exit_handler_active;
LITREF gtmImageName gtmImageNames[];
+error_def(ERR_KILLBYSIG);
+error_def(ERR_KILLBYSIGUINFO);
+error_def(ERR_KILLBYSIGSINFO1);
+error_def(ERR_KILLBYSIGSINFO2);
+error_def(ERR_KILLBYSIGSINFO3);
+
void dbcertify_deferred_signal_handler(void)
{
- error_def(ERR_KILLBYSIG);
- error_def(ERR_KILLBYSIGUINFO);
- error_def(ERR_KILLBYSIGSINFO1);
- error_def(ERR_KILLBYSIGSINFO2);
- error_def(ERR_KILLBYSIGSINFO3);
-
- /* To avoid nested calls to this routine, we set forced_exit to FALSE at the very beginning */
- forced_exit = FALSE;
+ /* To avoid nested calls to this routine, we advance the status of forced_exit. */
+ SET_FORCED_EXIT_STATE_ALREADY_EXITING;
if (exit_handler_active)
{
@@ -68,36 +68,38 @@ void dbcertify_deferred_signal_handler(void)
/* note can't use switch here because ERR_xxx are not defined as constants */
if (ERR_KILLBYSIG == forced_exit_err)
{
- send_msg(VARLSTCNT(6) ERR_KILLBYSIG, 4, GTMIMAGENAMETXT(image_type), process_id, signal_info.signal);
- gtm_putmsg(VARLSTCNT(6) ERR_KILLBYSIG, 4, GTMIMAGENAMETXT(image_type), process_id, signal_info.signal);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_KILLBYSIG, 4,
+ GTMIMAGENAMETXT(image_type), process_id, signal_info.signal);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_KILLBYSIG, 4,
+ GTMIMAGENAMETXT(image_type), process_id, signal_info.signal);
} else if (ERR_KILLBYSIGUINFO == forced_exit_err)
{
- send_msg(VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, GTMIMAGENAMETXT(image_type), process_id,
- signal_info.signal, signal_info.send_pid, signal_info.send_uid);
- gtm_putmsg(VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, GTMIMAGENAMETXT(image_type), process_id,
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, GTMIMAGENAMETXT(image_type), process_id,
+ signal_info.signal, signal_info.send_pid, signal_info.send_uid);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, GTMIMAGENAMETXT(image_type), process_id,
signal_info.signal, signal_info.send_pid, signal_info.send_uid);
} else if (ERR_KILLBYSIGSINFO1 == forced_exit_err)
{
- send_msg(VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, GTMIMAGENAMETXT(image_type),
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, GTMIMAGENAMETXT(image_type),
process_id, signal_info.signal, signal_info.int_iadr, signal_info.bad_vadr);
- gtm_putmsg(VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, GTMIMAGENAMETXT(image_type),
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, GTMIMAGENAMETXT(image_type),
process_id, signal_info.signal, signal_info.int_iadr, signal_info.bad_vadr);
} else if (ERR_KILLBYSIGSINFO2 == forced_exit_err)
{
- send_msg(VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, GTMIMAGENAMETXT(image_type),
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, GTMIMAGENAMETXT(image_type),
process_id, signal_info.signal, signal_info.int_iadr);
- gtm_putmsg(VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, GTMIMAGENAMETXT(image_type),
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, GTMIMAGENAMETXT(image_type),
process_id, signal_info.signal, signal_info.int_iadr);
} else if (ERR_KILLBYSIGSINFO3 == forced_exit_err)
{
- send_msg(VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, GTMIMAGENAMETXT(image_type),
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, GTMIMAGENAMETXT(image_type),
process_id, signal_info.signal, signal_info.bad_vadr);
- gtm_putmsg(VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, GTMIMAGENAMETXT(image_type),
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, GTMIMAGENAMETXT(image_type),
process_id, signal_info.signal, signal_info.bad_vadr);
} else
{
- send_msg(VARLSTCNT(1) forced_exit_err);
- gtm_putmsg(VARLSTCNT(1) forced_exit_err);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(1) forced_exit_err);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) forced_exit_err);
}
/* Drive the exit handler to terminate */
exit(-exi_condition);
diff --git a/sr_unix/dbcertify_signal_handler.c b/sr_unix/dbcertify_signal_handler.c
index f92cee6..d28368d 100644
--- a/sr_unix/dbcertify_signal_handler.c
+++ b/sr_unix/dbcertify_signal_handler.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2005, 2012 Fidelity Information Services, Inc *
+ * Copyright 2005, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -53,7 +53,6 @@ GBLDEF siginfo_t exi_siginfo;
GBLDEF gtm_sigcontext_t exi_context;
-GBLREF VSIG_ATOMIC_T forced_exit;
GBLREF int4 forced_exit_err;
GBLREF int4 exi_condition;
GBLREF enum gtmImageTypes image_type;
@@ -133,15 +132,15 @@ 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) && (psa_gbl->dbc_critical || exit_handler_active))
{
- forced_exit = TRUE;
+ SET_FORCED_EXIT_STATE;
exit_state++; /* Make exit pending, may still be tolerant though */
return;
}
exit_state = EXIT_IMMED;
- send_msg(VARLSTCNT(1) forced_exit_err);
- gtm_putmsg(VARLSTCNT(1) forced_exit_err);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(1) forced_exit_err);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) forced_exit_err);
dont_want_core = TRUE;
break;
case SIGQUIT: /* Handle SIGQUIT specially which we ALWAYS want to defer if possible as it is always sent */
@@ -169,9 +168,9 @@ void dbcertify_signal_handler(int sig, siginfo_t *info, void *context)
GTMASSERT;
}
/* 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) && (psa_gbl->dbc_critical || exit_handler_active))
{
- forced_exit = TRUE;
+ SET_FORCED_EXIT_STATE;
exit_state++; /* Make exit pending, may still be tolerant though */
return;
}
@@ -179,32 +178,36 @@ void dbcertify_signal_handler(int sig, siginfo_t *info, void *context)
switch(signal_info.infotype)
{
case GTMSIGINFO_NONE:
- send_msg(VARLSTCNT(6) ERR_KILLBYSIG, 4, GTMIMAGENAMETXT(image_type), process_id, sig);
- gtm_putmsg(VARLSTCNT(6) ERR_KILLBYSIG, 4, GTMIMAGENAMETXT(image_type), process_id, sig);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_KILLBYSIG, 4,
+ GTMIMAGENAMETXT(image_type), process_id, sig);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_KILLBYSIG, 4,
+ GTMIMAGENAMETXT(image_type), process_id, sig);
break;
case GTMSIGINFO_USER:
- send_msg(VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, GTMIMAGENAMETXT(image_type),
- process_id, sig, signal_info.send_pid, signal_info.send_uid);
- gtm_putmsg(VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, GTMIMAGENAMETXT(image_type),
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, GTMIMAGENAMETXT(image_type),
process_id, sig, signal_info.send_pid, signal_info.send_uid);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6,
+ GTMIMAGENAMETXT(image_type), process_id, sig,
+ signal_info.send_pid, signal_info.send_uid);
break;
case GTMSIGINFO_ILOC + GTMSIGINFO_BADR:
- send_msg(VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, GTMIMAGENAMETXT(image_type),
- process_id, sig, signal_info.int_iadr, signal_info.bad_vadr);
- gtm_putmsg(VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, GTMIMAGENAMETXT(image_type),
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, GTMIMAGENAMETXT(image_type),
process_id, sig, signal_info.int_iadr, signal_info.bad_vadr);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6,
+ GTMIMAGENAMETXT(image_type), process_id, sig,
+ signal_info.int_iadr, signal_info.bad_vadr);
break;
case GTMSIGINFO_ILOC:
- send_msg(VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, GTMIMAGENAMETXT(image_type),
- process_id, sig, signal_info.int_iadr);
- gtm_putmsg(VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, GTMIMAGENAMETXT(image_type),
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, GTMIMAGENAMETXT(image_type),
process_id, sig, signal_info.int_iadr);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5,
+ GTMIMAGENAMETXT(image_type), process_id, sig, signal_info.int_iadr);
break;
case GTMSIGINFO_BADR:
- send_msg(VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, GTMIMAGENAMETXT(image_type),
- process_id, sig, signal_info.bad_vadr);
- gtm_putmsg(VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, GTMIMAGENAMETXT(image_type),
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, GTMIMAGENAMETXT(image_type),
process_id, sig, signal_info.bad_vadr);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5,
+ GTMIMAGENAMETXT(image_type), process_id, sig, signal_info.bad_vadr);
break;
}
break;
@@ -212,15 +215,15 @@ 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) && (psa_gbl->dbc_critical || exit_handler_active))
{
- forced_exit = TRUE;
+ SET_FORCED_EXIT_STATE;
exit_state++; /* Make exit pending, may still be tolerant though */
return;
}
exit_state = EXIT_IMMED;
- send_msg(VARLSTCNT(1) forced_exit_err);
- gtm_putmsg(VARLSTCNT(1) forced_exit_err);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(1) forced_exit_err);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) forced_exit_err);
dont_want_core = TRUE;
break;
#endif
@@ -230,47 +233,51 @@ void dbcertify_signal_handler(int sig, siginfo_t *info, void *context)
{
case GTMSIGINFO_NONE:
exit_state = EXIT_IMMED;
- send_msg(VARLSTCNT(6) ERR_KILLBYSIG, 4, GTMIMAGENAMETXT(image_type), process_id, sig);
- gtm_putmsg(VARLSTCNT(6) ERR_KILLBYSIG, 4, GTMIMAGENAMETXT(image_type), process_id, sig);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_KILLBYSIG, 4,
+ GTMIMAGENAMETXT(image_type), process_id, sig);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_KILLBYSIG, 4,
+ GTMIMAGENAMETXT(image_type), process_id, sig);
break;
case GTMSIGINFO_USER:
/* 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) && (psa_gbl->dbc_critical || exit_handler_active))
{
- forced_exit = TRUE;
+ SET_FORCED_EXIT_STATE;
exit_state++; /* Make exit pending, may still be tolerant though */
need_core = TRUE;
gtm_fork_n_core(); /* Generate "virgin" core while we can */
return;
}
exit_state = EXIT_IMMED;
- send_msg(VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, GTMIMAGENAMETXT(image_type),
- process_id, sig, signal_info.send_pid, signal_info.send_uid);
- gtm_putmsg(VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, GTMIMAGENAMETXT(image_type),
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, GTMIMAGENAMETXT(image_type),
process_id, sig, signal_info.send_pid, signal_info.send_uid);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6,
+ GTMIMAGENAMETXT(image_type), process_id, sig,
+ signal_info.send_pid, signal_info.send_uid);
break;
case GTMSIGINFO_ILOC + GTMSIGINFO_BADR:
exit_state = EXIT_IMMED;
- send_msg(VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, GTMIMAGENAMETXT(image_type),
- process_id, sig, signal_info.int_iadr, signal_info.bad_vadr);
- gtm_putmsg(VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, GTMIMAGENAMETXT(image_type),
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, GTMIMAGENAMETXT(image_type),
process_id, sig, signal_info.int_iadr, signal_info.bad_vadr);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6,
+ GTMIMAGENAMETXT(image_type), process_id, sig,
+ signal_info.int_iadr, signal_info.bad_vadr);
break;
case GTMSIGINFO_ILOC:
exit_state = EXIT_IMMED;
- send_msg(VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, GTMIMAGENAMETXT(image_type),
- process_id, sig, signal_info.int_iadr);
- gtm_putmsg(VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, GTMIMAGENAMETXT(image_type),
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, GTMIMAGENAMETXT(image_type),
process_id, sig, signal_info.int_iadr);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5,
+ GTMIMAGENAMETXT(image_type), process_id, sig, signal_info.int_iadr);
break;
case GTMSIGINFO_BADR:
exit_state = EXIT_IMMED;
- send_msg(VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, GTMIMAGENAMETXT(image_type),
- process_id, sig, signal_info.bad_vadr);
- gtm_putmsg(VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, GTMIMAGENAMETXT(image_type),
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, GTMIMAGENAMETXT(image_type),
process_id, sig, signal_info.bad_vadr);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5,
+ GTMIMAGENAMETXT(image_type), process_id, sig, signal_info.bad_vadr);
break;
default:
exit_state = EXIT_IMMED;
@@ -278,8 +285,8 @@ void dbcertify_signal_handler(int sig, siginfo_t *info, void *context)
}
if (0 != signal_info.sig_err)
{
- send_msg(VARLSTCNT(1) signal_info.sig_err);
- gtm_putmsg(VARLSTCNT(1) signal_info.sig_err);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(1) signal_info.sig_err);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) signal_info.sig_err);
}
break;
} /* switch (sig) */
diff --git a/sr_unix/dbinit_ch.c b/sr_unix/dbinit_ch.c
index 4e29918..f2a2f53 100644
--- a/sr_unix/dbinit_ch.c
+++ b/sr_unix/dbinit_ch.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -25,6 +25,7 @@
#include "gdsfhead.h"
#include "error.h"
#include "filestruct.h"
+#include "gvcst_protos.h"
#include "jnl.h"
#include "do_semop.h"
#include "mmseg.h"
@@ -36,30 +37,36 @@
#include "have_crit.h"
GBLREF gd_region *db_init_region;
-GBLREF boolean_t sem_incremented;
CONDITION_HANDLER(dbinit_ch)
{
- unix_db_info *udi;
- gd_segment *seg;
- sgmnt_addrs *csa;
- int rc, lcl_new_dbinit_ipc;
-
START_CH;
if (SUCCESS == SEVERITY || INFO == SEVERITY)
{
PRN_ERROR;
CONTINUE;
}
+ db_init_err_cleanup(FALSE);
+ NEXTCH
+}
+
+void db_init_err_cleanup(boolean_t retry_dbinit)
+{
+ unix_db_info *udi;
+ gd_segment *seg;
+ sgmnt_addrs *csa;
+ int rc, lcl_new_dbinit_ipc;
+
+ assert(NULL != db_init_region);
seg = db_init_region->dyn.addr;
udi = NULL;
if (NULL != seg->file_cntl)
udi = FILE_INFO(db_init_region);
if (NULL != udi)
{
- if (FD_INVALID != udi->fd)
+ if (FD_INVALID != udi->fd && !retry_dbinit)
CLOSEFILE_RESET(udi->fd, rc); /* resets "udi->fd" to FD_INVALID */
- assert(FD_INVALID == udi->fd);
+ assert(FD_INVALID == udi->fd || retry_dbinit);
csa = &udi->s_addrs;
# ifdef GTM_CRYPT
if (NULL != csa->encrypted_blk_contents)
@@ -68,11 +75,10 @@ CONDITION_HANDLER(dbinit_ch)
csa->encrypted_blk_contents = NULL;
}
# endif
- if (NULL != csa->hdr)
+ if ((NULL != csa->hdr) && (dba_mm == db_init_region->dyn.addr->acc_meth))
{
- if (dba_mm == db_init_region->dyn.addr->acc_meth)
- munmap((caddr_t)csa->db_addrs[0], (size_t)(csa->db_addrs[1] - csa->db_addrs[0]));
- csa->hdr = (sgmnt_data_ptr_t)NULL;
+ assert((NULL != csa->db_addrs[1]) && (csa->db_addrs[1] > csa->db_addrs[0]));
+ munmap((caddr_t)csa->db_addrs[0], (size_t)(csa->db_addrs[1] - csa->db_addrs[0]));
}
if (NULL != csa->jnl)
{
@@ -84,48 +90,45 @@ CONDITION_HANDLER(dbinit_ch)
shmdt((caddr_t)csa->nl);
csa->nl = (node_local_ptr_t)NULL;
}
- lcl_new_dbinit_ipc = TREF(new_dbinit_ipc);
- if (lcl_new_dbinit_ipc)
+ if (udi->new_shm && (INVALID_SHMID != udi->shmid))
{
- if ((lcl_new_dbinit_ipc & NEW_DBINIT_SHM_IPC_MASK) && (INVALID_SHMID != udi->shmid))
- {
- shm_rmid(udi->shmid);
- udi->shmid = INVALID_SHMID;
- }
- if ((lcl_new_dbinit_ipc & NEW_DBINIT_SEM_IPC_MASK) && (INVALID_SEMID != udi->semid))
- {
- sem_rmid(udi->semid);
- udi->semid = INVALID_SEMID;
- udi->grabbed_access_sem = FALSE;
- }
- TREF(new_dbinit_ipc) = 0;
+ shm_rmid(udi->shmid);
+ udi->shmid = INVALID_SHMID;
+ udi->new_shm = FALSE;
}
- if (sem_incremented)
+ if (udi->new_sem && (INVALID_SEMID != udi->semid))
{
- if (INVALID_SEMID != udi->semid)
- {
- if (FALSE == db_init_region->read_only)
- do_semop(udi->semid, 1, -1, SEM_UNDO); /* decrement the read-write sem */
- do_semop(udi->semid, 0, -1, SEM_UNDO); /* release the startup-shutdown sem */
- }
- sem_incremented = FALSE;
+ sem_rmid(udi->semid);
+ udi->semid = INVALID_SEMID;
+ udi->new_sem = FALSE;
+ udi->grabbed_access_sem = FALSE;
+ udi->counter_acc_incremented = FALSE;
+ }
+ if (udi->counter_acc_incremented)
+ {
+ assert((INVALID_SEMID != udi->semid) && !db_init_region->read_only);
+ do_semop(udi->semid, DB_COUNTER_SEM, -1, SEM_UNDO | IPC_NOWAIT); /* decrement the read-write sem */
+ udi->counter_acc_incremented = FALSE;
+ }
+ if (udi->grabbed_access_sem)
+ {
+ do_semop(udi->semid, DB_CONTROL_SEM, -1, SEM_UNDO | IPC_NOWAIT); /* release the startup-shutdown sem */
+ udi->grabbed_access_sem = FALSE;
}
-
if (udi->grabbed_ftok_sem)
- ftok_sem_release(db_init_region, TRUE, TRUE);
- if (!IS_GTCM_GNP_SERVER_IMAGE) /* gtcm_gnp_server reuses file_cntl */
+ ftok_sem_release(db_init_region, udi->counter_ftok_incremented, TRUE);
+ else if (udi->counter_ftok_incremented)
+ do_semop(udi->ftok_semid, DB_COUNTER_SEM, -1, SEM_UNDO | IPC_NOWAIT);
+ udi->counter_ftok_incremented =FALSE;
+ udi->grabbed_ftok_sem = FALSE;
+ if (!IS_GTCM_GNP_SERVER_IMAGE && !retry_dbinit) /* gtcm_gnp_server reuses file_cntl */
{
free(seg->file_cntl->file_info);
free(seg->file_cntl);
seg->file_cntl = NULL;
}
}
- /* Reset intrpt_ok_state to OK_TO_INTERRUPT in case we got called (due to an rts_error) with intrpt_ok_state
- * being set to INTRPT_IN_GVCST_INIT.
- * We should actually be calling RESTORE_INTRPT_OK_STATE macro but since we don't have access to local variable
- * save_intrpt_ok_state, set intrpt_ok_state directly.
- */
- assert((INTRPT_OK_TO_INTERRUPT == intrpt_ok_state) || (INTRPT_IN_GVCST_INIT == intrpt_ok_state));
- intrpt_ok_state = INTRPT_OK_TO_INTERRUPT;
- NEXTCH;
+ /* Enable interrupts in case we are here with intrpt_ok_state == INTRPT_IN_GVCST_INIT due to an rts error. */
+ if (!retry_dbinit)
+ ENABLE_INTERRUPTS(INTRPT_IN_GVCST_INIT);
}
diff --git a/sr_unix/deferred_signal_handler.c b/sr_unix/deferred_signal_handler.c
index dc2ccbf..5d61b3c 100644
--- a/sr_unix/deferred_signal_handler.c
+++ b/sr_unix/deferred_signal_handler.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -31,7 +31,6 @@
#include "io.h"
#endif
-GBLREF VSIG_ATOMIC_T forced_exit;
GBLREF int4 exi_condition;
GBLREF void (*call_on_signal)();
GBLREF int forced_exit_err;
@@ -57,8 +56,8 @@ void deferred_signal_handler(void)
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
- /* To avoid nested calls to this routine, we set forced_exit to FALSE at the very beginning */
- forced_exit = FALSE;
+ /* To avoid nested calls to this routine, progress the forced_exit state. */
+ SET_FORCED_EXIT_STATE_ALREADY_EXITING;
if (exit_handler_active)
{
@@ -72,36 +71,38 @@ void deferred_signal_handler(void)
/* note can't use switch here because ERR_xxx are not defined as constants */
if (ERR_KILLBYSIG == forced_exit_err)
{
- send_msg(VARLSTCNT(6) ERR_KILLBYSIG, 4, GTMIMAGENAMETXT(image_type), process_id, signal_info.signal);
- gtm_putmsg(VARLSTCNT(6) ERR_KILLBYSIG, 4, GTMIMAGENAMETXT(image_type), process_id, signal_info.signal);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_KILLBYSIG, 4, GTMIMAGENAMETXT(image_type),
+ process_id, signal_info.signal);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_KILLBYSIG, 4, GTMIMAGENAMETXT(image_type),
+ process_id, signal_info.signal);
} else if (ERR_KILLBYSIGUINFO == forced_exit_err)
{
- send_msg(VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, GTMIMAGENAMETXT(image_type), process_id,
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, GTMIMAGENAMETXT(image_type), process_id,
signal_info.signal, signal_info.send_pid, signal_info.send_uid);
- gtm_putmsg(VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, GTMIMAGENAMETXT(image_type), process_id,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, GTMIMAGENAMETXT(image_type), process_id,
signal_info.signal, signal_info.send_pid, signal_info.send_uid);
} else if (ERR_KILLBYSIGSINFO1 == forced_exit_err)
{
- send_msg(VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, GTMIMAGENAMETXT(image_type),
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, GTMIMAGENAMETXT(image_type),
process_id, signal_info.signal, signal_info.int_iadr, signal_info.bad_vadr);
- gtm_putmsg(VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, GTMIMAGENAMETXT(image_type),
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, GTMIMAGENAMETXT(image_type),
process_id, signal_info.signal, signal_info.int_iadr, signal_info.bad_vadr);
} else if (ERR_KILLBYSIGSINFO2 == forced_exit_err)
{
- send_msg(VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, GTMIMAGENAMETXT(image_type),
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, GTMIMAGENAMETXT(image_type),
process_id, signal_info.signal, signal_info.int_iadr);
- gtm_putmsg(VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, GTMIMAGENAMETXT(image_type),
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, GTMIMAGENAMETXT(image_type),
process_id, signal_info.signal, signal_info.int_iadr);
} else if (ERR_KILLBYSIGSINFO3 == forced_exit_err)
{
- send_msg(VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, GTMIMAGENAMETXT(image_type),
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, GTMIMAGENAMETXT(image_type),
process_id, signal_info.signal, signal_info.bad_vadr);
- gtm_putmsg(VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, GTMIMAGENAMETXT(image_type),
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, GTMIMAGENAMETXT(image_type),
process_id, signal_info.signal, signal_info.bad_vadr);
} else if (ERR_FORCEDHALT != forced_exit_err || !gtm_quiet_halt)
{ /* No HALT messages if quiet halt is requested */
- send_msg(VARLSTCNT(1) forced_exit_err);
- gtm_putmsg(VARLSTCNT(1) forced_exit_err);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(1) forced_exit_err);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) forced_exit_err);
}
assert(OK_TO_INTERRUPT);
/* Signal intent to exit BEFORE driving condition handlers. This avoids checks that will otherwise fail (for example
diff --git a/sr_unix/dircompare.m.txt b/sr_unix/dircompare.m.txt
index fb3359f..a0fd6b1 100644
--- a/sr_unix/dircompare.m.txt
+++ b/sr_unix/dircompare.m.txt
@@ -1,6 +1,6 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ;
-; Copyright 2011 Fidelity Information Services, Inc ;
+; Copyright 2011, 2013 Fidelity Information Services, Inc ;
; ;
; This source code contains the intellectual property ;
; of its copyright holder(s), and is made available ;
@@ -9,30 +9,50 @@
; ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; dircompare
-; mumps -r dircompare <filename> <deletefilename | NOP> <addfilename | NOP> <deletedirectory | NOP>, where filename
-; is the output of ls -lR
-; of pro in either the build directory or the install directory.
-; If the deletefilename is NOP then there are no delete entries.
-; If the addfilename is NOP then there are no add entries.
-; If the deletedirectory is NOP then there are no deldirectory entries.
-; The first few lines of the three files are the copyright lines. Other comment lines may be included after
-; the copyright lines and all are eaten before the data is read into the database. No spaces are allowed between the comments
-; lines.
-; The format of the deletefile is shown below. Its purpose is to delete files from the list of permissions and files
-; which are written to standard output.
-; The format of the addfile is shown below. Its purpose is to add files to the list of permissions and files
-; which are written to standard output. To add files before an existing entry, the tryadd function is used.
+; The purpose of this routine is to take the ls -lR output of the regular
+; GT.M development directory and massage it to look like what we expect from
+; the installed directory
+;
+; mumps -r dircompare <filename> <deletefilename | NOP> <addfilename | NOP> <deletedirectory | NOP>
+;
+; <filename> is the output of ls -lR of pro in either the build directory or the install directory
+; For each of the following NOP indicates that there are none
+; <deletefilename> - delete entries - aka files missing from PRO
+; <addfilename> - added entries - aka files added on to of PRO
+; <deletedirectory> - deleted directories - aka dirs missing from PRO
+;
+; The first few lines of the three files are the copyright lines. Other
+; comment lines may be included after ; the copyright lines and all are eaten
+; before the data is read into the database. No spaces are allowed between the
+; comments lines.
+;
+; <deletefilename>
+; The format of the deletefile is shown below.
+; Its purpose is to delete files from the list of permissions and files which
+; are written to standard output.
+;
+; <addfilename>
+; The format of the addfile is shown below.
+; Its purpose is to add files to the list of permissions and files which are
+; written to standard output. To add files before an existing entry, the tryadd
+; function is used.
+;
; To add files after the last file in a directory, the same format is used in the addfile, but the filename must be
; after the last entry (i.e. must not exist). The tryinsert function adds files to the end of a directory. It
; assumes that at least one file exists in the directory. An example of both forms is given prior to the loadadd function.
-
+;
+; <deletedirectory>
+; The format of the deldirfile is shown below.
+;
dircompare
; set etrap so we get debug info and exit mumps
- set $etrap="use $P write $zstatus,!,""Error line: "" zprint @$zposition halt"
+ set $etrap="use $P write $zstatus,!,""Error line: "" zprint @$zposition s x=$zjobexam() halt"
; read the delete file into global memory
kill ^delentries
kill ^addentries
kill ^deldirentries
+ kill ^debug
+ ; Parse command line
if 4'=$LENGTH($ZCMDLINE," ") do
. write "Usage: dircompare <filename> <deletefilename | NOP> <addfilename | NOP> <deletedirectory | NOP>",! halt
set infile=$PIECE($ZCMDLINE," ",1)
@@ -53,15 +73,17 @@ dircompare
set (directorydelete,nonewline)=1
open infile:(readonly)
use infile:exception="GOTO EOF"
- for read dirname,x do; read a directory and eat the next line which is size info; ; terminated by exception="GOTO EOF"
+ for read dirname,x do ; read a directory and eat the next line which is size info; ; terminated by exception="GOTO EOF"
+ . set ^debug($i(readdirloop))=dirname
. if $DATA(^deldirentries(dirname)) set directorydelete=1 ; flag directory to delete
. else do
.. use $P
.. if 'nonewline write !
.. write dirname,!
- .. set (^addmatch,directorydelete,nonewline)=0
+ .. set (directorydelete,nonewline)=0
+ . set ^debug(readdirloop,dirname,"state")=$select(directorydelete=1:"delete me",1:"use me")
. for use infile read x do quit:""=x
- .. if ""=x do quit; if it is a blank line then tryinsert
+ .. if ""=x do quit ; if it is a blank line then tryinsert
... ;in case a file(s) need(s) to be added to the end of the directory
... if $DATA(^addentries(dirname)) do tryinsert(dirname)
.. if directorydelete quit
@@ -81,6 +103,8 @@ dircompare
EOF
if ('directorydelete&$DATA(^addentries(dirname))) do tryinsert(dirname)
+ for set unused=$order(^addentries($get(unused))) quit:unused="" do
+ . use $p write !,unused,! do tryinsert(unused)
close infile
halt
@@ -89,18 +113,28 @@ trydelete(dirname,filename)
tryadd(dirname,filename,infile)
set ret=0
- if $DATA(^addentries(dirname,filename)),$increment(^addmatch) do
+ if $DATA(^addentries(dirname,filename)) do
. use $P
- . for j=1:1:^addentries(dirname,filename) write ^addentries(dirname,filename,j),!
+ . for j=1:1:^addentries(dirname,filename) do
+ . . write ^addentries(dirname,filename,j),!
+ . . set ^debug(readdirloop,dirname,$i(action))=$R
+ . set ^addentries(dirname)=$increment(^addentries(dirname),-j)
+ . kill ^addentries(dirname,filename)
+ . if $data(^addentries(dirname))<10 kill ^addentries(dirname)
. use infile
. quit
quit
tryinsert(dirname)
set nummatch=^addentries(dirname)
- if nummatch>^addmatch&$DATA(^addentries(dirname,"zzz_insert")) do
+ if $DATA(^addentries(dirname,"zzz_insert")) do
. use $P
- . for j=1:1:^addentries(dirname,"zzz_insert") write ^addentries(dirname,"zzz_insert",j),!
+ . for j=1:1:^addentries(dirname,"zzz_insert") do
+ . . write ^addentries(dirname,"zzz_insert",j),!
+ . . set ^debug(readdirloop,dirname,$i(action))=$R
+ . set ^addentries(dirname)=$increment(^addentries(dirname),-j)
+ . kill ^addentries(dirname,"zzz_insert")
+ . if $data(^addentries(dirname))<10 kill ^addentries(dirname)
. use infile
quit
@@ -174,10 +208,14 @@ loaddelete(fdelete)
close fdelete
quit
-; loadadd(fadd) - fadd is the name of the add file to load
+; loadadd(fadd)
+; - fadd is the name of the add file to load
+;
; assume addfile starts with a directory name follwed by a colon and has a blank line before each subdirectory
; assumes the last line is not blank. It is ok to have a directory with no entries under it
+;
; the field separators must be a %
+;
; the add entries start with a existing file before which the following permission and file will be inserted
; The exception to this rule is if the file or files is to be entered after the last entry in a directory
; In this case, you must use the file name zzz_insert which will not match any file in the directory
@@ -258,15 +296,24 @@ loaddeldir(fdeldir)
use $P
quit
+; Ensure that the routine uses a file as input only once and that the target file exists
+; f - is the name of a local which was just set by the CLI parser
uniquefile(f)
- new fn,ok
- set ok=1
- set same=0
- for fn="infile","deletefile","addfile","deletedirfile" do
- . if f'=fn,$DATA(@fn), at f=@fn set ok=0 write !,f," and ",fn," files (", at f,") can't be the same",! set same=1 quit
- if same quit ok
- if ""=$ZSEARCH(@f) set ok=0 write !,f," file: ", at f," does not exist",!
- quit ok
+ new fn,status,same
+ set status=1
+ for fn="infile","deletefile","addfile","deldirfile" do
+ . ; Skip when f and fn point to the same local
+ . quit:f=fn
+ . ; If the local (fn points to) DOES NOT exist in memory, quit
+ . quit:$data(@fn)=0
+ . ; The local (fn points to) exists in memory, quit if f and fn DO NOT point to the same file
+ . quit:@f'=@fn
+ . set status=0,same=1
+ . write !,f," and ",fn," files (", at f,") can't be the same",!
+ . quit
+ if $data(same) quit status
+ if ""=$ZSEARCH(@f) set status=0 write !,f," file: ", at f," does not exist",!
+ quit status
getext(file)
; return the extension of the filename or null if none
diff --git a/sr_unix/disk_block_available.c b/sr_unix/disk_block_available.c
index c637c0a..5b7a518 100644
--- a/sr_unix/disk_block_available.c
+++ b/sr_unix/disk_block_available.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -42,6 +42,7 @@
#endif
+#include "have_crit.h"
#include "eintr_wrappers.h"
#include "disk_block_available.h"
diff --git a/sr_unix/dollarh.c b/sr_unix/dollarh.c
index 867261d..3a010d8 100644
--- a/sr_unix/dollarh.c
+++ b/sr_unix/dollarh.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -11,47 +11,44 @@
#include "mdef.h"
-#include <signal.h>
#include "gtm_time.h"
#include <sys/time.h>
#include "dollarh.h"
#include "gtmimagename.h"
-
-GBLREF boolean_t run_time;
-GBLREF boolean_t blocksig_initialized;
-GBLREF sigset_t block_sigsent;
+#include "have_crit.h"
void dollarh(time_t intime, uint4 *days, time_t *seconds)
{
uint4 tdays;
int isdst;
struct tm *ttime;
- sigset_t savemask;
+ time_t mktime_ret;
#ifdef DEBUG
static uint4 old_days = 0, old_seconds = 0;
static time_t old_intime = 0;
static int old_isdst;
#endif
- /* When dollarh() is processing and a signal occurs, the signal processing can eventually lead to nested system time
+ /* The comment below is now obsolete as GTM-6802 took care of protecting time-related functions from nested
+ * invocations, making the presence of sigprocmasks unnecessary. If several years pass without more incidents
+ * of time-caused hangs, remove the comment. (SOPINI, 2013/02/20)
+ *
+ * When dollarh() is processing and a signal occurs, the signal processing can eventually lead to nested system time
* routine calls. If a signal arrives during a system time call (__tzset() in linux) we end up in a generic signal
* handler which invokes syslog which in turn tries to call the system time routine (__tz_convert() in linux) which
* seems to get suspended presumably waiting for the same interlock that __tzset() has already obtained. A work around
* is to block signals (SIGINT, SIGQUIT, SIGTERM, SIGTSTP, SIGCONT, SIGALRM) during the function and then restore them
* at the end. [C9D06-002271] [C9I03-002967].
*/
- assert(blocksig_initialized); /* the set of blocking signals should be initialized at process startup */
- if (blocksig_initialized) /* In pro, dont take chances and handle case where it is not initialized */
- sigprocmask(SIG_BLOCK, &block_sigsent, &savemask);
- ttime = localtime(&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 UCT other than hourly */
*seconds = (time_t)(ttime->tm_hour * HOUR) + (ttime->tm_min * MINUTE) + ttime->tm_sec;
isdst = ttime->tm_isdst;
- ttime = gmtime(&intime); /* represent intime as UCT */
- ttime->tm_isdst = isdst; /* use localtime() to tell mktime whether daylight savings needs to be applied */
- tdays = (uint4)((intime + (time_t)difftime(intime, mktime(ttime))) / ONEDAY) + DAYS; /* adjust relative to UTC */
+ GTM_GMTIME(ttime, &intime); /* represent intime as UCT */
+ 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 */
- if (blocksig_initialized)
- sigprocmask(SIG_SETMASK, &savemask, NULL);
/* 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,
diff --git a/sr_unix/dse_cmd.c b/sr_unix/dse_cmd.c
index 380d3dd..2c2a81d 100644
--- a/sr_unix/dse_cmd.c
+++ b/sr_unix/dse_cmd.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc. *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc. *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -37,6 +37,7 @@
#include "dse_exit.h"
#include "util_spawn.h"
+#include "util_help.h"
#include "dse_cmd_disallow.h"
/*************************************************************
@@ -367,7 +368,7 @@ GBLDEF CLI_ENTRY dse_cmd_ary[] = {
{ "EVALUATE", dse_eval, dse_eval_qual, 0, 0, 0, 0, VAL_DISALLOWED, 0, 0, 0, 0 },
{ "EXIT", dse_exit, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, 0, 0, 0 },
{ "FIND", dse_f_blk, dse_find_qual, 0, 0, cli_disallow_dse_find, 0, VAL_DISALLOWED, 0, 0, 0, 0 },
-{ "HELP", dse_help, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, 0, 0, 0 },
+{ "HELP", util_help, 0, 0, 0, 0, 0, VAL_DISALLOWED, 1, 0, 0, 0 },
{ "INTEGRIT", dse_integ, dse_integrit_qual, 0, 0, 0, 0, VAL_DISALLOWED, 0, 0, 0, 0 },
{ "MAPS", dse_maps, dse_map_qual, 0, 0, cli_disallow_dse_maps, 0, VAL_DISALLOWED, 0, 0, 0, 0 },
{ "OPEN", dse_open, dse_open_qual, 0, 0, 0, 0, VAL_DISALLOWED, 0, 0, 0, 0 },
diff --git a/sr_unix/dse_help.c b/sr_unix/dse_help.c
index abf60ea..cb7dc40 100644
--- a/sr_unix/dse_help.c
+++ b/sr_unix/dse_help.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -21,6 +21,7 @@
void dse_help(void)
{
+ /* This function is a STUB to avoid editting sr_port/dse.h */
}
void dse_version(void)
diff --git a/sr_unix/dsk_read.c b/sr_unix/dsk_read.c
index e70c966..13f40e2 100644
--- a/sr_unix/dsk_read.c
+++ b/sr_unix/dsk_read.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -39,12 +39,24 @@
#include "min_max.h"
#include "gtmimagename.h"
#include "memcoherency.h"
+#include "gdskill.h"
+#include "gdscc.h"
+#include "jnl.h"
+#include "buddy_list.h" /* needed for tp.h */
+#include "hashtab_int4.h" /* needed for tp.h */
+#include "tp.h"
GBLREF gd_region *gv_cur_region;
GBLREF sgmnt_addrs *cs_addrs;
GBLREF sgmnt_data_ptr_t cs_data;
GBLREF volatile int4 fast_lock_count;
GBLREF boolean_t dse_running;
+GBLREF boolean_t mu_reorg_upgrd_dwngrd_in_prog;
+GBLREF unsigned int t_tries;
+GBLREF uint4 dollar_tlevel;
+GBLREF sgm_info *sgm_info_ptr;
+GBLREF sgmnt_addrs *kip_csa;
+GBLREF jnl_gbls_t jgbl;
error_def(ERR_DYNUPGRDFAIL);
@@ -56,10 +68,12 @@ int4 dsk_read (block_id blk, sm_uc_ptr_t buff, enum db_ver *ondsk_blkver, boolea
sm_uc_ptr_t save_buff = NULL, enc_save_buff;
boolean_t fully_upgraded, buff_is_modified_after_lseekread;
int bsiz;
- DEBUG_ONLY(
- blk_hdr_ptr_t blk_hdr_val;
- static int in_dsk_read;
- )
+# ifdef DEBUG
+ unsigned int effective_t_tries;
+ boolean_t killinprog;
+ blk_hdr_ptr_t blk_hdr_val;
+ static int in_dsk_read;
+# endif
/* It is possible that the block that we read in from disk is a V4 format block. The database block scanning routines
* (gvcst_*search*.c) that might be concurrently running currently assume all global buffers (particularly the block
* headers) are V5 format. They are not robust enough to handle a V4 format block. Therefore we do not want to
@@ -77,7 +91,9 @@ int4 dsk_read (block_id blk, sm_uc_ptr_t buff, enum db_ver *ondsk_blkver, boolea
char *in, *out;
boolean_t is_encrypted;
# endif
+ DCL_THREADGBL_ACCESS;
+ SETUP_THREADGBL_ACCESS;
/* Note: Even in snapshots, only INTEG requires dsk_read to read FREE blocks. The assert below should be modified
* if we later introduce a scheme where we can figure out as to who started the snapshots and assert accordingly
*/
@@ -133,6 +149,7 @@ int4 dsk_read (block_id blk, sm_uc_ptr_t buff, enum db_ver *ondsk_blkver, boolea
size,
save_errno);
assert((0 == save_errno) GTM_TRUNCATE_ONLY(|| (-1 == save_errno)));
+ WBTEST_ASSIGN_ONLY(WBTEST_PREAD_SYSCALL_FAIL, save_errno, EIO);
# ifdef GTM_CRYPT
if (is_encrypted && (0 == save_errno))
{
@@ -141,12 +158,10 @@ int4 dsk_read (block_id blk, sm_uc_ptr_t buff, enum db_ver *ondsk_blkver, boolea
buff_is_modified_after_lseekread = TRUE;
/* Do not do encryption/decryption if block is FREE */
if (!blk_free && (IS_BLK_ENCRYPTED(((blk_hdr_ptr_t)enc_save_buff)->levl, in_len)))
- {
- /* The below assert cannot be moved before BLOCK_REQUIRE_ENCRYPTION check done above as tmp_ptr could
- * potentially point to a V4 block in which case the assert might fail when a V4 block is casted to
- * a V5 block header.
+ { /* Due to concurrency conflicts, we are potentially reading a free block even though blk_free is
+ * FALSE. Go ahead and safely "decrypt" such a block, even though it contains no valid contents.
+ * We expect GTMCRYPT_DECRYPT to return success even if it is presented with garbage data.
*/
- assert((bsiz <= cs_data->blk_size) && (bsiz >= SIZEOF(blk_hdr)));
ASSERT_ENCRYPTION_INITIALIZED;
memcpy(buff, enc_save_buff, SIZEOF(blk_hdr));
in = (char *)(enc_save_buff + SIZEOF(blk_hdr));
@@ -200,15 +215,25 @@ int4 dsk_read (block_id blk, sm_uc_ptr_t buff, enum db_ver *ondsk_blkver, boolea
*/
SHM_WRITE_MEMORY_BARRIER;
}
- DEBUG_ONLY(
- in_dsk_read--;
- 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.
- */
- blk_hdr_val = (NULL != save_buff) ? (blk_hdr_ptr_t)save_buff : (blk_hdr_ptr_t)buff;
- GDS_BLK_HDR_CHECK(cs_data, blk_hdr_val, fully_upgraded);
- }
- )
+# ifdef DEBUG
+ in_dsk_read--;
+ /* 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)
+ */
+ 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)));
+ 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.
+ */
+ blk_hdr_val = (NULL != save_buff) ? (blk_hdr_ptr_t)save_buff : (blk_hdr_ptr_t)buff;
+ GDS_BLK_HDR_CHECK(cs_data, blk_hdr_val, fully_upgraded);
+ }
+# endif
return save_errno;
}
diff --git a/sr_unix/err_init.c b/sr_unix/err_init.c
index d70b84a..b9b6558 100644
--- a/sr_unix/err_init.c
+++ b/sr_unix/err_init.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -10,14 +10,31 @@
****************************************************************/
#include "mdef.h"
+
+#include <sys/types.h>
#include <setjmp.h>
+#include <errno.h>
+#include "unistd.h"
+#include "gtm_stdlib.h"
+#include "gtm_stdio.h"
+
#include "invocation_mode.h"
#include "gtmimagename.h"
#include "error.h"
+#include "send_msg.h"
+
+#define COREDUMPFILTERFN "/proc/%i/coredump_filter"
+#define FILTERPARMSIZE (8 + 1)
+#define FILTERENABLEBITS 0x00000073 /* Represents bits 0, 1, 4, 5, 6 */
GBLREF enum gtmImageTypes image_type;
-/* Allocate a basic initial condition handler stack that can be expanded later if necessary */
+error_def(ERR_SYSCALL);
+
+/* 1. Allocate a basic initial condition handler stack that can be expanded later if necessary.
+ * 2. On Linux, make sure bits 0,1, 4, 5, and 6 are set in /proc/PID/coredump_filter so dumps the sections that GT.M
+ * cores need to have in them.
+ */
void err_init(void (*x)())
{
chnd = (condition_handler *)malloc((CONDSTK_INITIAL_INCR + CONDSTK_RESERVE) * SIZEOF(condition_handler));
@@ -27,4 +44,81 @@ void err_init(void (*x)())
ctxt->ch = x;
chnd_end = &chnd[CONDSTK_INITIAL_INCR]; /* chnd_end is the end of the condition handler stack */
chnd_incr = CONDSTK_INITIAL_INCR * 2;
+# ifdef __linux__
+ /* Read the coredump_filter value from /proc for this process, update the value if necessary so we have the proper
+ * flags set to get the info we (and gtmpcat) need to properly process a core file. Note any errors we encounter just
+ * send a message to the operator log and return as nothing here should prevent GT.M from running.
+ *
+ * Note "man 5 core" on x86-64 Linux (Ubuntu 12.04) notes that the /proc/PID/coredump_filter file is only provided when
+ * the Linux kernel is built with the CONFIG_ELF_CORE configuration option. This *seems* to control whether or not the
+ * kernel supports the ELF loader or not. To date, all Linux flavors GT.M supports use ELF so we regard this as largely
+ * mandatory though in the future it may happen that GT.M works yet runs with something other than ELF. In that case,
+ * we'd need to change the below to avoid the operator log messages every time GT.M initializes.
+ */
+ {
+ int rc;
+ unsigned int filterbits;
+ char procfn[SIZEOF(COREDUMPFILTERFN) + MAX_DIGITS_IN_INT]; /* File name of file to update */
+ char filter[FILTERPARMSIZE], *filterend; /* Value read in & written out */
+ char *rcc;
+ FILE *filterstrm; /* filter stream file block */
+
+ /* Note use simple basic methods since this early in initialization not everything is necessarily setup to
+ * be able to properly use the *print*() wrapper functions.
+ */
+ rc = snprintf(procfn, SIZEOF(procfn), COREDUMPFILTERFN, getpid());
+ if (0 > rc)
+ {
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("sprintf()"), CALLFROM, rc);
+ return;
+ }
+ filterstrm = fopen(procfn, "r");
+ if (NULL == filterstrm)
+ {
+ rc = errno;
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("fopen()"), CALLFROM, rc);
+ return;
+ }
+ rcc = fgets(filter, SIZEOF(filter), filterstrm);
+ if (NULL == rcc)
+ {
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("fgets()"), CALLFROM, rc);
+ return;
+ }
+ rc = fclose(filterstrm);
+ if (0 > rc)
+ {
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("fclose()"), CALLFROM, rc);
+ return;
+ }
+ filterend = filter + SIZEOF(filter);
+ filterbits = (unsigned int)strtol(filter, &filterend, 16);
+ if (FILTERENABLEBITS != (filterbits & FILTERENABLEBITS))
+ { /* At least one flag was missing - reset them */
+ filterbits = filterbits | FILTERENABLEBITS;
+ filterstrm = fopen(procfn, "w");
+ if (NULL == filterstrm)
+ {
+ rc = errno;
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("fopen()"),
+ CALLFROM, rc);
+ return;
+ }
+ rc = fprintf(filterstrm, "0x%08x", filterbits);
+ if (0 > rc)
+ {
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("fprintf"),
+ CALLFROM, rc);
+ return;
+ }
+ fclose(filterstrm);
+ if (0 > rc)
+ {
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("fclose()"),
+ CALLFROM, rc);
+ return;
+ }
+ }
+ }
+# endif
}
diff --git a/sr_unix/errorsp.h b/sr_unix/errorsp.h
index 6b4e2d4..a9f0cbd 100644
--- a/sr_unix/errorsp.h
+++ b/sr_unix/errorsp.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -15,6 +15,7 @@
#include <setjmp.h>
#include "gtm_stdio.h"
+#include "have_crit.h"
#ifdef __MVS__
# define GTMCORENAME "gtmcore"
@@ -173,8 +174,8 @@ void ch_trace_point() {return;}
}
#endif
-#define ESTABLISH_RET(x, ret) { \
- CHTRACEPOINT; \
+#define GTM_ASM_ESTABLISH { /* So named because gtm_asm_establish does exactly this */ \
+ CHTRACEPOINT; \
ctxt++; \
if (ctxt >= (chnd_end + (!process_exiting ? 0 : CONDSTK_RESERVE))) \
condstk_expand(); \
@@ -182,59 +183,37 @@ void ch_trace_point() {return;}
ctxt->save_active_ch = active_ch; \
ctxt->ch_active = FALSE; \
active_ch = ctxt; \
+ }
+#define ESTABLISH_NOJMP(x) { \
+ GTM_ASM_ESTABLISH; \
ctxt->ch = x; \
- if (setjmp(ctxt->jmp) == -1) \
- { \
- REVERT; \
- return ret; \
- } \
}
-#ifdef __cplusplus /* must specify return value (if any) for C++ */
-#define ESTABLISH(x, ret) { \
- CHTRACEPOINT; \
- ctxt++; \
- if (ctxt >= (chnd_end + (!process_exiting ? 0 : CONDSTK_RESERVE))) \
- condstk_expand(); \
- CHECKHIGHBOUND(ctxt); \
- ctxt->save_active_ch = active_ch; \
- ctxt->ch_active = FALSE; \
- active_ch = ctxt; \
- ctxt->ch = x; \
+#define ESTABLISH_NOUNWIND(x) ESTABLISH_NOJMP(x)
+#define ESTABLISH_RET(x, ret) { \
+ ESTABLISH_NOJMP(x); \
if (setjmp(ctxt->jmp) == -1) \
{ \
REVERT; \
return ret; \
} \
}
+
+#ifdef __cplusplus /* must specify return value (if any) for C++ */
+# define ESTABLISH(x, ret) ESTABLISH_RET(x, ret)
#else
-#define ESTABLISH(x) { \
- CHTRACEPOINT; \
- ctxt++; \
- if (ctxt >= (chnd_end + (!process_exiting ? 0 : CONDSTK_RESERVE))) \
- condstk_expand(); \
- CHECKHIGHBOUND(ctxt); \
- ctxt->save_active_ch = active_ch; \
- ctxt->ch_active = FALSE; \
- active_ch = ctxt; \
- ctxt->ch = x; \
+# define ESTABLISH(x) { \
+ ESTABLISH_NOJMP(x); \
if (setjmp(ctxt->jmp) == -1) \
{ \
REVERT; \
return; \
} \
}
-#define ESTABLISH_NORET(x, did_long_jump) { \
+# define ESTABLISH_NORET(x, did_long_jump) \
+ { \
did_long_jump = FALSE; \
- CHTRACEPOINT; \
- ctxt++; \
- if (ctxt >= (chnd_end + (!process_exiting ? 0 : CONDSTK_RESERVE))) \
- condstk_expand(); \
- CHECKHIGHBOUND(ctxt); \
- ctxt->save_active_ch = active_ch; \
- ctxt->ch_active = FALSE; \
- active_ch = ctxt; \
- ctxt->ch = x; \
+ ESTABLISH_NOJMP(x); \
if (setjmp(ctxt->jmp) == -1) \
did_long_jump = TRUE; \
}
@@ -301,17 +280,24 @@ void ch_trace_point() {return;}
CONTINUE; \
}
-#define UNWIND(dummy1, dummy2) { \
- GBLREF int process_exiting; \
- GBLREF boolean_t ok_to_UNWIND_in_exit_handling; \
- \
- assert(!process_exiting || ok_to_UNWIND_in_exit_handling); \
- CHTRACEPOINT; \
- chnd[current_ch].ch_active = FALSE; \
- active_ch++; \
- CHECKHIGHBOUND(active_ch); \
- ctxt = active_ch; \
- longjmp(active_ch->jmp, -1); \
+/* Should never unwind a condition handler established with ESTABLISH_NOUNWIND. Currently t_ch and dbinit_ch are the only ones. */
+#define UNWINDABLE(unw_ch) ((&t_ch != unw_ch->ch) && (&dbinit_ch != unw_ch->ch))
+#define UNWIND(dummy1, dummy2) { \
+ GBLREF int process_exiting; \
+ GBLREF boolean_t ok_to_UNWIND_in_exit_handling; \
+ \
+ assert(!process_exiting || ok_to_UNWIND_in_exit_handling); \
+ /* When we hit an error in the midst of commit, t_ch/t_commit_cleanup should be invoked \
+ * and clean it up before any condition handler on the stack unwinds. \
+ */ \
+ assert(0 == have_crit(CRIT_IN_COMMIT)); \
+ CHTRACEPOINT; \
+ chnd[current_ch].ch_active = FALSE; \
+ active_ch++; \
+ CHECKHIGHBOUND(active_ch); \
+ ctxt = active_ch; \
+ assert(UNWINDABLE(active_ch)); \
+ longjmp(active_ch->jmp, -1); \
}
#define START_CH int current_ch; \
@@ -385,7 +371,7 @@ unsigned char *set_zstatus(mstr *src, int arg, unsigned char **ctxtp, boolean_t
#define EXIT_HANDLER(x)
-#define SEND_CALLERID(callee) send_msg(VARLSTCNT(5) ERR_CALLERID, 3, LEN_AND_STR((callee)), caller_id());
+#define SEND_CALLERID(callee) send_msg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_CALLERID, 3, LEN_AND_STR((callee)), caller_id());
#define PRINT_CALLERID util_out_print(" -- generated from 0x!XJ.", NOFLUSH, caller_id())
#define UNIX_EXIT_STATUS_MASK 0xFF
@@ -430,5 +416,7 @@ CONDITION_HANDLER(gvcst_put_ch);
CONDITION_HANDLER(gvcst_query_ch);
CONDITION_HANDLER(gvcst_queryget_ch);
CONDITION_HANDLER(gvcst_zprevious_ch);
+CONDITION_HANDLER(op_fnzpeek_ch);
+CONDITION_HANDLER(op_fnzpeek_getpool_ch);
#endif
diff --git a/sr_unix/extract_signal_info.c b/sr_unix/extract_signal_info.c
index dde025c..ce5607d 100644
--- a/sr_unix/extract_signal_info.c
+++ b/sr_unix/extract_signal_info.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -33,35 +33,40 @@
#include "gtmsiginfo.h"
+/* GCC on HPPA does not have SI_USER defined */
+#if !defined(SI_USER) && defined(__GNUC__)
+# define SI_USER 0
+#endif
+
/* OS/390 (R7) does not define SI_USER but for code expansions purposes, define the value it uses
in its place */
#if !defined(SI_USER) && defined(__MVS__)
# define SI_USER 0
#endif
+error_def(ERR_SIGACCERR);
+error_def(ERR_SIGADRALN);
+error_def(ERR_SIGADRERR);
+error_def(ERR_SIGBADSTK);
+error_def(ERR_SIGCOPROC);
+error_def(ERR_SIGFLTDIV);
+error_def(ERR_SIGFLTINV);
+error_def(ERR_SIGFLTOVF);
+error_def(ERR_SIGFLTRES);
+error_def(ERR_SIGFLTUND);
+error_def(ERR_SIGILLADR);
+error_def(ERR_SIGILLOPC);
+error_def(ERR_SIGILLOPN);
+error_def(ERR_SIGILLTRP);
+error_def(ERR_SIGINTDIV);
+error_def(ERR_SIGINTOVF);
+error_def(ERR_SIGMAPERR);
+error_def(ERR_SIGOBJERR);
+error_def(ERR_SIGPRVOPC);
+error_def(ERR_SIGPRVREG);
+
void extract_signal_info(int sig, siginfo_t *info, gtm_sigcontext_t *context, gtmsiginfo_t *gtmsi)
{
- error_def(ERR_SIGILLOPC);
- error_def(ERR_SIGILLOPN);
- error_def(ERR_SIGILLADR);
- error_def(ERR_SIGILLTRP);
- error_def(ERR_SIGPRVOPC);
- error_def(ERR_SIGPRVREG);
- error_def(ERR_SIGCOPROC);
- error_def(ERR_SIGBADSTK);
- error_def(ERR_SIGADRALN);
- error_def(ERR_SIGADRERR);
- error_def(ERR_SIGOBJERR);
- error_def(ERR_SIGINTDIV);
- error_def(ERR_SIGINTOVF);
- error_def(ERR_SIGFLTDIV);
- error_def(ERR_SIGFLTOVF);
- error_def(ERR_SIGFLTUND);
- error_def(ERR_SIGFLTRES);
- error_def(ERR_SIGFLTINV);
- error_def(ERR_SIGMAPERR);
- error_def(ERR_SIGACCERR);
-
memset(gtmsi, 0, SIZEOF(*gtmsi));
gtmsi->signal = sig;
if (NULL != info)
@@ -90,7 +95,7 @@ void extract_signal_info(int sig, siginfo_t *info, gtm_sigcontext_t *context, gt
gtmsi->infotype |= GTMSIGINFO_BADR;
if (NULL != context)
{
-#ifndef __ia64
+#if !defined(__ia64) && !defined(__GNUC__)
if (0 == (context->uc_mcontext.ss_flags & SS_NARROWISINVALID))
{
/* Interrupt location is in narrow area */
diff --git a/sr_unix/exttab_parse.c b/sr_unix/exttab_parse.c
index f8fffd2..d3f4e2c 100644
--- a/sr_unix/exttab_parse.c
+++ b/sr_unix/exttab_parse.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -80,7 +80,15 @@ const int parm_space_needed[] =
SIZEOF(gtm_char_t **) + SIZEOF(gtm_char_t *),
SIZEOF(gtm_double_t *) + SIZEOF(gtm_double_t),
SIZEOF(gtm_pointertofunc_t),
- SIZEOF(gtm_pointertofunc_t *) + SIZEOF(gtm_pointertofunc_t)
+ SIZEOF(gtm_pointertofunc_t *) + SIZEOF(gtm_pointertofunc_t),
+ SIZEOF(gtm_int_t *) + SIZEOF(gtm_int_t),
+ SIZEOF(gtm_int_t *) + SIZEOF(gtm_int_t),
+ SIZEOF(gtm_long_t *) + SIZEOF(gtm_long_t),
+ SIZEOF(gtm_float_t *) + SIZEOF(gtm_float_t),
+ SIZEOF(gtm_double_t *) + SIZEOF(gtm_double_t),
+ SIZEOF(gtm_string_t *) + SIZEOF(gtm_string_t),
+ SIZEOF(gtm_string_t *) + SIZEOF(gtm_string_t),
+ SIZEOF(gtm_string_t *) + SIZEOF(gtm_string_t)
};
error_def(ERR_CIDIRECTIVE);
@@ -191,47 +199,55 @@ STATICFNDEF enum gtm_types scan_keyword(char **c)
enum gtm_types typ[MAXIMUM_STARS + 1]; /* One entry for each level of indirection eg [1] is type* */
} xctab[] =
{
- /* typename type type * type ** */
-
- {"void", gtm_void, gtm_notfound, gtm_notfound },
-
- {"gtm_int_t", gtm_int, gtm_int_star, gtm_notfound },
- {"xc_int_t", gtm_int, gtm_int_star, gtm_notfound },
- {"int", gtm_int, gtm_int_star, gtm_notfound },
-
- {"gtm_uint_t", gtm_uint, gtm_uint_star, gtm_notfound },
- {"xc_uint_t", gtm_uint, gtm_uint_star, gtm_notfound },
- {"uint", gtm_uint, gtm_uint_star, gtm_notfound },
-
- {"gtm_long_t", gtm_long, gtm_long_star, gtm_notfound },
- {"xc_long_t", gtm_long, gtm_long_star, gtm_notfound },
- {"long", gtm_long, gtm_long_star, gtm_notfound },
-
- {"gtm_ulong_t", gtm_ulong, gtm_ulong_star, gtm_notfound },
- {"xc_ulong_t", gtm_ulong, gtm_ulong_star, gtm_notfound },
- {"ulong", gtm_ulong, gtm_ulong_star, gtm_notfound },
-
- {"gtm_status_t", gtm_status, gtm_notfound, gtm_notfound },
- {"xc_status_t", gtm_status, gtm_notfound, gtm_notfound },
-
- {"gtm_char_t", gtm_notfound, gtm_char_star, gtm_char_starstar },
- {"xc_char_t", gtm_notfound, gtm_char_star, gtm_char_starstar },
- {"char", gtm_notfound, gtm_char_star, gtm_char_starstar },
-
- {"gtm_string_t", gtm_notfound, gtm_string_star, gtm_notfound },
- {"xc_string_t", gtm_notfound, gtm_string_star, gtm_notfound },
- {"string", gtm_notfound, gtm_string_star, gtm_notfound },
-
- {"gtm_float_t", gtm_float, gtm_float_star, gtm_notfound },
- {"xc_float_t", gtm_float, gtm_float_star, gtm_notfound },
- {"float", gtm_float, gtm_float_star, gtm_notfound },
-
- {"gtm_double_t", gtm_double, gtm_double_star, gtm_notfound },
- {"xc_double_t", gtm_double, gtm_double_star, gtm_notfound },
- {"double", gtm_double, gtm_double_star, gtm_notfound },
-
- {"gtm_pointertofunc_t", gtm_pointertofunc, gtm_pointertofunc_star, gtm_notfound },
- {"xc_pointertofunc_t", gtm_pointertofunc, gtm_pointertofunc_star, gtm_notfound }
+ /* typename type type * type ** */
+
+ {"void", gtm_void, gtm_notfound, gtm_notfound },
+
+ {"gtm_int_t", gtm_int, gtm_int_star, gtm_notfound },
+ {"gtm_jboolean_t", gtm_jboolean, gtm_notfound, gtm_notfound },
+ {"gtm_jint_t", gtm_jint, gtm_notfound, gtm_notfound },
+ {"xc_int_t", gtm_int, gtm_int_star, gtm_notfound },
+ {"int", gtm_int, gtm_notfound, gtm_notfound },
+
+ {"gtm_uint_t", gtm_uint, gtm_uint_star, gtm_notfound },
+ {"xc_uint_t", gtm_uint, gtm_uint_star, gtm_notfound },
+ {"uint", gtm_uint, gtm_uint_star, gtm_notfound },
+
+ {"gtm_long_t", gtm_long, gtm_long_star, gtm_notfound },
+ {"gtm_jlong_t", gtm_jlong, gtm_notfound, gtm_notfound },
+ {"xc_long_t", gtm_long, gtm_long_star, gtm_notfound },
+ {"long", gtm_long, gtm_long_star, gtm_notfound },
+
+ {"gtm_ulong_t", gtm_ulong, gtm_ulong_star, gtm_notfound },
+ {"xc_ulong_t", gtm_ulong, gtm_ulong_star, gtm_notfound },
+ {"ulong", gtm_ulong, gtm_ulong_star, gtm_notfound },
+
+ {"gtm_status_t", gtm_status, gtm_notfound, gtm_notfound },
+ {"xc_status_t", gtm_status, gtm_notfound, gtm_notfound },
+
+ {"gtm_char_t", gtm_notfound, gtm_char_star, gtm_char_starstar },
+ {"gtm_jstring_t", gtm_jstring, gtm_notfound, gtm_notfound },
+ {"gtm_jbyte_array_t", gtm_jbyte_array, gtm_notfound, gtm_notfound },
+ {"gtm_jbig_decimal_t", gtm_jbig_decimal, gtm_notfound, gtm_notfound },
+ {"xc_char_t", gtm_notfound, gtm_char_star, gtm_char_starstar },
+ {"char", gtm_notfound, gtm_char_star, gtm_char_starstar },
+
+ {"gtm_string_t", gtm_notfound, gtm_string_star, gtm_notfound },
+ {"xc_string_t", gtm_notfound, gtm_string_star, gtm_notfound },
+ {"string", gtm_notfound, gtm_string_star, gtm_notfound },
+
+ {"gtm_float_t", gtm_float, gtm_float_star, gtm_notfound },
+ {"gtm_jfloat_t", gtm_jfloat, gtm_notfound, gtm_notfound },
+ {"xc_float_t", gtm_float, gtm_float_star, gtm_notfound },
+ {"float", gtm_float, gtm_float_star, gtm_notfound },
+
+ {"gtm_double_t", gtm_double, gtm_double_star, gtm_notfound },
+ {"gtm_jdouble_t", gtm_jdouble, gtm_notfound, gtm_notfound },
+ {"xc_double_t", gtm_double, gtm_double_star, gtm_notfound },
+ {"double", gtm_double, gtm_double_star, gtm_notfound },
+
+ {"gtm_pointertofunc_t", gtm_pointertofunc, gtm_pointertofunc_star, gtm_notfound },
+ {"xc_pointertofunc_t", gtm_pointertofunc, gtm_pointertofunc_star, gtm_notfound }
};
char *b = *c;
char *d;
@@ -267,12 +283,11 @@ STATICFNDEF int scan_array_bound(char **b,int curr_type)
{
char number[MAX_DIGITS_IN_INT];
char *c;
- char *line;
int index;
const static int default_pre_alloc_value[] =
{
- 0, /* Unknown Type */
+ 0, /* unknown Type */
0, /* void */
0, /* status */
0, /* int */
@@ -283,20 +298,28 @@ STATICFNDEF int scan_array_bound(char **b,int curr_type)
0, /* double */
1, /* pointer to int */
1, /* pointer to unsigned int */
- 1, /* Pointer to long */
- 1, /* Pointer to unsigned long */
- 1, /* Pointer to string */
- 1, /* Pointer to float */
- 100, /* Pointer to char */
- 1, /* Pointer to pointer of char */
- 1, /* Pointer to double */
- 1, /* Pointer to function */
- 1 /* Pointer to pointer to function */
+ 1, /* pointer to long */
+ 1, /* pointer to unsigned long */
+ 1, /* pointer to string */
+ 1, /* pointer to float */
+ 100, /* pointer to char */
+ 1, /* pointer to pointer of char */
+ 1, /* pointer to double */
+ 1, /* pointer to function */
+ 1, /* pointer to pointer to function */
+ 1, /* java int */
+ 1, /* java int */
+ 1, /* java long */
+ 1, /* java float */
+ 1, /* java double */
+ 1, /* java string */
+ 1, /* java byte array */
+ 1 /* java big decimal */
};
c = *b;
/* Already found '[' */
- for (index=0, c++; ']' != *c; c++)
+ for (index = 0, c++; ']' != *c; c++)
{
if ('\0' != *c)
{
@@ -318,6 +341,7 @@ STATICFNDEF int scan_array_bound(char **b,int curr_type)
STATICFNDEF char *read_table(char *b, int l, FILE *f)
{
char *t;
+ int fclose_res;
ext_source_column = 0;
FGETS(b, l, f, t);
@@ -325,10 +349,9 @@ STATICFNDEF char *read_table(char *b, int l, FILE *f)
{
if (0 != ferror(f))
{
- int fclose_res;
FCLOSE(f, fclose_res);
/* Expand error message */
- rts_error(VARLSTCNT(1) errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) errno);
} else
assert(feof(f) != 0);
} else
@@ -415,13 +438,13 @@ struct extcall_package_list *exttab_parse(mval *package)
if (NULL == ext_table_file_name)
{
/* Environment variable for the package not found */
- rts_error(VARLSTCNT(4) ERR_ZCCTENV, 2, LEN_AND_STR(str_buffer));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZCCTENV, 2, LEN_AND_STR(str_buffer));
}
ext_table_file_handle = Fopen(ext_table_file_name, "r");
if (NULL == ext_table_file_handle)
{
/* Package's external call table could not be found */
- rts_error(VARLSTCNT(4) ERR_ZCCTOPN, 2, LEN_AND_STR(ext_table_file_name));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZCCTOPN, 2, LEN_AND_STR(ext_table_file_name));
}
ext_source_line_num = 0;
/* Pick-up name of shareable library */
@@ -429,7 +452,7 @@ struct extcall_package_list *exttab_parse(mval *package)
if (NULL == tbp)
{
/* External call table is a null file */
- rts_error(VARLSTCNT(4) ERR_ZCCTNULLF, 2, package->str.len, package->str.addr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZCCTNULLF, 2, package->str.len, package->str.addr);
}
STRNCPY_STR(str_temp_buffer, str_buffer, MAX_TABLINE_LEN);
val.addr = str_temp_buffer;
@@ -444,13 +467,13 @@ struct extcall_package_list *exttab_parse(mval *package)
if (SS_LOG2LONG == TRANS_LOG_NAME(&val, &trans, str_buffer, SIZEOF(str_buffer), dont_sendmsg_on_log2long))
{
/* Env variable expansion in the pathname caused buffer overflow */
- rts_error(VARLSTCNT(5) ERR_LOGTOOLONG, 3, val.len, val.addr, SIZEOF(str_buffer) - 1);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_LOGTOOLONG, 3, val.len, val.addr, SIZEOF(str_buffer) - 1);
}
pakhandle = fgn_getpak(str_buffer, INFO);
if (NULL == pakhandle)
{
/* Unable to obtain handle to the shared library */
- rts_error(VARLSTCNT(4) ERR_ZCUNAVAIL, 2, package->str.len, package->str.addr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZCUNAVAIL, 2, package->str.len, package->str.addr);
}
pak = get_memory(SIZEOF(*pak));
pak->first_entry = 0;
@@ -535,6 +558,14 @@ struct extcall_package_list *exttab_parse(mval *package)
case gtm_char_starstar:
case gtm_pointertofunc:
case gtm_pointertofunc_star:
+ case gtm_jboolean:
+ case gtm_jint:
+ case gtm_jlong:
+ case gtm_jfloat:
+ case gtm_jdouble:
+ case gtm_jstring:
+ case gtm_jbyte_array:
+ case gtm_jbig_decimal:
break;
default:
ext_stx_error(ERR_ZCRTNTYP, ext_table_file_name);
@@ -631,6 +662,7 @@ struct extcall_package_list *exttab_parse(mval *package)
for (i = 0 ; i < parameter_count; i++)
{
entry_ptr->parms[i] = parameter_types[i];
+ assert(gtm_void != parameter_types[i]);
entry_ptr->parmblk_size += parm_space_needed[parameter_types[i]];
entry_ptr->param_pre_alloc_size[i] = parameter_alloc_values[i];
}
@@ -662,15 +694,15 @@ callin_entry_list* citab_parse (void)
enum gtm_types ret_tok, parameter_types[MAX_ACTUALS], pr;
char str_buffer[MAX_TABLINE_LEN], *tbp, *end;
FILE *ext_table_file_handle;
- callin_entry_list *entry_ptr, *save_entry_ptr = 0;
+ callin_entry_list *entry_ptr = NULL, *save_entry_ptr = NULL;
ext_table_file_name = GETENV(CALLIN_ENV_NAME);
if (!ext_table_file_name) /* environment variable not set */
- rts_error(VARLSTCNT(4) ERR_CITABENV, 2, LEN_AND_STR(CALLIN_ENV_NAME));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_CITABENV, 2, LEN_AND_STR(CALLIN_ENV_NAME));
ext_table_file_handle = Fopen(ext_table_file_name, "r");
if (!ext_table_file_handle) /* call-in table not found */
- rts_error(VARLSTCNT(11) ERR_CITABOPN, 2, LEN_AND_STR(ext_table_file_name),
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(11) ERR_CITABOPN, 2, LEN_AND_STR(ext_table_file_name),
ERR_SYSCALL, 5, LEN_AND_LIT("fopen"), CALLFROM, errno);
ext_source_line_num = 0;
while (read_table(LIT_AND_LEN(str_buffer), ext_table_file_handle))
@@ -696,6 +728,14 @@ callin_entry_list* citab_parse (void)
case gtm_float_star:
case gtm_double_star:
case gtm_string_star:
+ case gtm_jboolean:
+ case gtm_jint:
+ case gtm_jlong:
+ case gtm_jfloat:
+ case gtm_jdouble:
+ case gtm_jstring:
+ case gtm_jbyte_array:
+ case gtm_jbig_decimal:
break;
default:
ext_stx_error(ERR_CIRTNTYP, ext_table_file_name);
@@ -742,6 +782,14 @@ callin_entry_list* citab_parse (void)
case gtm_float_star:
case gtm_double_star:
case gtm_string_star:
+ case gtm_jboolean:
+ case gtm_jint:
+ case gtm_jlong:
+ case gtm_jfloat:
+ case gtm_jdouble:
+ case gtm_jstring:
+ case gtm_jbyte_array:
+ case gtm_jbig_decimal:
break;
default:
ext_stx_error(ERR_CIUNTYPE, ext_table_file_name);
@@ -793,5 +841,5 @@ STATICFNDEF void ext_stx_error(int in_error, ...)
dec_err(VARLSTCNT(6) ERR_EXTSRCLIN, 4, ext_source_line_len, ext_source_line, b - &buf[0], &buf[0]);
dec_err(VARLSTCNT(6) ERR_EXTSRCLOC, 4, ext_source_column, ext_source_line_num, LEN_AND_STR(ext_table_name));
- rts_error(VARLSTCNT(1) in_error);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) in_error);
}
diff --git a/sr_unix/fgncalsp.h b/sr_unix/fgncalsp.h
index 3526462..e13f387 100644
--- a/sr_unix/fgncalsp.h
+++ b/sr_unix/fgncalsp.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -87,7 +87,15 @@ enum gtm_types
gtm_char_starstar,
gtm_double_star,
gtm_pointertofunc,
- gtm_pointertofunc_star
+ gtm_pointertofunc_star,
+ gtm_jboolean,
+ gtm_jint,
+ gtm_jlong,
+ gtm_jfloat,
+ gtm_jdouble,
+ gtm_jstring,
+ gtm_jbyte_array,
+ gtm_jbig_decimal
};
enum callintogtm_fncs
diff --git a/sr_unix/filestruct.h b/sr_unix/filestruct.h
index 7cb82cb..55893c4 100644
--- a/sr_unix/filestruct.h
+++ b/sr_unix/filestruct.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -29,8 +29,12 @@ typedef struct unix_db_info_struct
int shmid;
time_t gt_shm_ctime;
int ftok_semid;
+ boolean_t new_shm;
+ boolean_t new_sem;
boolean_t grabbed_ftok_sem;
boolean_t grabbed_access_sem;
+ boolean_t counter_acc_incremented;
+ boolean_t counter_ftok_incremented;
key_t key;
bool raw;
} unix_db_info;
diff --git a/sr_unix/fork_init.h b/sr_unix/fork_init.h
index 8aea125..d14a369 100644
--- a/sr_unix/fork_init.h
+++ b/sr_unix/fork_init.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2011, 2012 Fidelity Information Services, Inc.*
+ * Copyright 2011, 2013 Fidelity Information Services, Inc.*
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -12,6 +12,8 @@
#ifndef _FORK_INIT_H
#define _FORK_INIT_H
+#include "have_crit.h"
+
/* This macro takes care of safely clearing the timer queue and resetting the
* timer-related globals when we need to fork-off a process. Please note that
* it is unnecessary to use this macro when the fork is immediately followed
@@ -20,11 +22,19 @@
* situations, append BYPASSOK comment directives to the lines with fork
* instances.
*/
+
#define FORK_CLEAN(pid) \
{ \
- pid = fork(); \
+ FORK(pid); \
if (0 == pid) \
clear_timers(); \
}
+#define FORK(pid) \
+{ \
+ DEFER_INTERRUPTS(INTRPT_IN_FORK_OR_SYSTEM) \
+ pid = fork(); \
+ ENABLE_INTERRUPTS(INTRPT_IN_FORK_OR_SYSTEM) \
+}
+
#endif
diff --git a/sr_unix/ftok.c b/sr_unix/ftok.c
index d523db1..97f74f5 100644
--- a/sr_unix/ftok.c
+++ b/sr_unix/ftok.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -33,7 +33,7 @@
FPRINTF(stderr, "\nUsage:\n"); \
FPRINTF(stderr, "\t%s [%s<number>] <file1> <file2> ... <filen>\n\n", argv[0], ID_PREFIX); \
FPRINTF(stderr, "Reports IPC Key(s) (using id 1, or <number>) of <file1> <file2> ... <filen>\n\n"); \
- exit(1); \
+ exit(EXIT_FAILURE); \
}
int main (int argc, char *argv[])
diff --git a/sr_unix/ftok_sems.c b/sr_unix/ftok_sems.c
index 59ad563..3e4b050 100644
--- a/sr_unix/ftok_sems.c
+++ b/sr_unix/ftok_sems.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -144,7 +144,10 @@ boolean_t ftok_sem_get2(gd_region *reg, uint4 start_hrtbt_cntr, semwait_status_t
SET_GTM_SOP_ARRAY(ftok_sop, ftok_sopcnt, TRUE, (SEM_UNDO | IPC_NOWAIT)); /* First try is always IPC_NOWAIT */
SEMOP(ftokid, ftok_sop, ftok_sopcnt, status, NO_WAIT);
if (-1 != status)
+ {
+ udi->counter_ftok_incremented = TRUE;
RETURN_SUCCESS(reg);
+ }
assert(EINTR != errno);
save_errno = errno;
if (EAGAIN == save_errno)
@@ -158,8 +161,10 @@ boolean_t ftok_sem_get2(gd_region *reg, uint4 start_hrtbt_cntr, semwait_status_t
} else if (do_blocking_semop(ftokid, gtm_ftok_sem, start_hrtbt_cntr, retstat, reg, bypass))
{
if (*bypass)
+ {
+ udi->counter_ftok_incremented = TRUE;
return TRUE;
- else
+ } else
RETURN_SUCCESS(reg);
} else if (!SEM_REMOVED(retstat->save_errno))
return FALSE; /* retstat will already have the necessary error information */
@@ -250,6 +255,7 @@ boolean_t ftok_sem_get(gd_region *reg, boolean_t incr_cnt, int project_id, boole
if (-1 != status)
{
SENDMSG_SEMOP_SUCCESS_IF_NEEDED(stacktrace_issued, gtm_ftok_sem);
+ udi->counter_ftok_incremented = incr_cnt;
RETURN_SUCCESS(reg);
}
save_errno = errno;
@@ -257,7 +263,7 @@ boolean_t ftok_sem_get(gd_region *reg, boolean_t incr_cnt, int project_id, boole
ISSUE_CRITSEMFAIL_AND_RETURN(reg, "semop()", save_errno);
if (EAGAIN == save_errno)
{ /* Someone else is holding it */
- sem_pid = semctl(udi->ftok_semid, 0, GETPID);
+ sem_pid = semctl(udi->ftok_semid, DB_CONTROL_SEM, GETPID);
if (-1 != sem_pid)
{
ftok_sop[0].sem_flg = ftok_sop[1].sem_flg = ftok_sop[2].sem_flg = SEM_UNDO; /* blocking calls */
@@ -274,13 +280,14 @@ boolean_t ftok_sem_get(gd_region *reg, boolean_t incr_cnt, int project_id, boole
if (-1 != status) /* success ? */
{
SENDMSG_SEMOP_SUCCESS_IF_NEEDED(stacktrace_issued, gtm_ftok_sem);
+ udi->counter_ftok_incremented = incr_cnt;
CANCEL_TIMER_AND_RETURN_SUCCESS(reg);
}
save_errno = errno;
if (EINTR == save_errno)
{ /* Timer popped. If not, we would have continued in the do..while loop */
assert(TREF(semwait2long));
- sem_pid = semctl(udi->ftok_semid, 0, GETPID);
+ sem_pid = semctl(udi->ftok_semid, DB_CONTROL_SEM, GETPID);
if (-1 != sem_pid)
{
stuck_cnt++;
@@ -354,11 +361,11 @@ boolean_t ftok_sem_lock(gd_region *reg, boolean_t incr_cnt, boolean_t immediate)
udi = FILE_INFO(reg);
csa = &udi->s_addrs;
assert(!csa->now_crit);
- /* The following two asserts are to ensure we never hold more than one FTOK semaphore at any point in time.
- * The only exception is if we were MUPIP STOPped (or kill -3ed) while having ftok_sem lock on one region and we
- * came to rundown code that invoked ftok_sem_lock() on a different region. Hence the process_exiting check below.
- * In the pro version, we will do the right thing by returning TRUE right away if udi->grabbed_ftok_sem is TRUE.
- * This is because incr_cnt is FALSE always (asserted below too).
+ /* The following two asserts are to ensure we never hold more than one FTOK semaphore at any point in time. The only
+ * exception is if we were MUPIP STOPped (or kill -3ed) while having ftok_sem lock on one region and we came to rundown code
+ * that invoked ftok_sem_lock() on a different region. Hence the process_exiting check below. In the pro version, we will
+ * do the right thing by returning TRUE right away if udi->grabbed_ftok_sem is TRUE. This is
+ * because incr_cnt is FALSE always (asserted below too).
*/
assert(!udi->grabbed_ftok_sem || (FALSE != process_exiting));
assert((NULL == ftok_sem_reg) || (FALSE != process_exiting));
@@ -367,14 +374,14 @@ boolean_t ftok_sem_lock(gd_region *reg, boolean_t incr_cnt, boolean_t immediate)
ftok_sopcnt = 0;
if (!udi->grabbed_ftok_sem)
{ /* Guarantee no one else accesses database file header while we update semid/shmid fields in the file header */
- ftok_sop[0].sem_num = 0; ftok_sop[0].sem_op = 0; /* Wait for 0 (unlocked) */
- ftok_sop[1].sem_num = 0; ftok_sop[1].sem_op = 1; /* Then lock it */
+ ftok_sop[0].sem_num = DB_CONTROL_SEM; ftok_sop[0].sem_op = 0; /* Wait for 0 (unlocked) */
+ ftok_sop[1].sem_num = DB_CONTROL_SEM; ftok_sop[1].sem_op = 1; /* Then lock it */
ftok_sopcnt = 2;
} else if (!incr_cnt)
return TRUE;
if (incr_cnt)
{
- ftok_sop[ftok_sopcnt].sem_num = 1; ftok_sop[ftok_sopcnt].sem_op = 1; /* increment counter */
+ ftok_sop[ftok_sopcnt].sem_num = DB_COUNTER_SEM; ftok_sop[ftok_sopcnt].sem_op = 1; /* increment counter */
ftok_sopcnt++;
}
ftok_sop[0].sem_flg = ftok_sop[1].sem_flg = ftok_sop[2].sem_flg = SEM_UNDO | IPC_NOWAIT;
@@ -405,9 +412,8 @@ boolean_t ftok_sem_lock(gd_region *reg, boolean_t incr_cnt, boolean_t immediate)
ISSUE_CRITSEMFAIL_AND_RETURN(reg, "semop()", save_errno);
}
}
- udi->grabbed_ftok_sem = TRUE;
- ftok_sem_reg = reg;
- return TRUE;
+ udi->counter_ftok_incremented = TRUE;
+ RETURN_SUCCESS(reg);
}
/*
@@ -420,11 +426,10 @@ boolean_t ftok_sem_lock(gd_region *reg, boolean_t incr_cnt, boolean_t immediate)
*/
boolean_t ftok_sem_incrcnt(gd_region *reg)
{
- int semflag, save_errno, status;
+ int save_errno, status;
unix_db_info *udi;
sgmnt_addrs *csa;
- struct sembuf ftok_sop[3];
- int ftok_sopcnt;
+ struct sembuf ftok_sop;
assert(NULL != reg);
assert(NULL == ftok_sem_reg); /* assert that we never hold more than one FTOK semaphore at any point in time */
@@ -432,18 +437,16 @@ boolean_t ftok_sem_incrcnt(gd_region *reg)
csa = &udi->s_addrs;
assert(!csa->now_crit);
assert(INVALID_SEMID != udi->ftok_semid);
- semflag = SEM_UNDO;
- ftok_sopcnt = 0;
- ftok_sop[ftok_sopcnt].sem_num = 1;
- ftok_sop[ftok_sopcnt].sem_op = 1; /* increment counter */
- ftok_sop[ftok_sopcnt].sem_flg = SEM_UNDO;
- ftok_sopcnt++;
- SEMOP(udi->ftok_semid, ftok_sop, ftok_sopcnt, status, NO_WAIT);
+ ftok_sop.sem_num = DB_COUNTER_SEM;
+ ftok_sop.sem_op = 1; /* increment counter */
+ ftok_sop.sem_flg = SEM_UNDO;
+ SEMOP(udi->ftok_semid, (&ftok_sop), 1, status, NO_WAIT);
if (-1 == status) /* We couldn't get it in one shot -- see if we already have it */
{
save_errno = errno;
ISSUE_CRITSEMFAIL_AND_RETURN(reg, "semop()", save_errno);
}
+ udi->counter_ftok_incremented = TRUE;
return TRUE;
}
@@ -482,7 +485,7 @@ boolean_t ftok_sem_release(gd_region *reg, boolean_t decr_cnt, boolean_t immedi
semflag = SEM_UNDO | (immediate ? IPC_NOWAIT : 0);
if (decr_cnt)
{
- if (-1 == (ftok_semval = semctl(udi->ftok_semid, 1, GETVAL)))
+ if (-1 == (ftok_semval = semctl(udi->ftok_semid, DB_COUNTER_SEM, GETVAL)))
{
save_errno = errno;
GTM_SEM_CHECK_EINVAL(TREF(gtm_environment_init), save_errno, udi);
@@ -499,15 +502,17 @@ boolean_t ftok_sem_release(gd_region *reg, boolean_t decr_cnt, boolean_t immedi
udi->ftok_semid = INVALID_SEMID;
ftok_sem_reg = NULL;
udi->grabbed_ftok_sem = FALSE;
+ udi->counter_ftok_incremented = FALSE;
return TRUE;
}
- if (0 != (save_errno = do_semop(udi->ftok_semid, 1, -1, semflag)))
+ if (0 != (save_errno = do_semop(udi->ftok_semid, DB_COUNTER_SEM, -1, semflag)))
{
GTM_SEM_CHECK_EINVAL(TREF(gtm_environment_init), save_errno, udi);
ISSUE_CRITSEMFAIL_AND_RETURN(reg, "semop()", save_errno);
}
+ udi->counter_ftok_incremented = FALSE;
}
- if (0 != (save_errno = do_semop(udi->ftok_semid, 0, -1, semflag)))
+ if (0 != (save_errno = do_semop(udi->ftok_semid, DB_CONTROL_SEM, -1, semflag)))
{
GTM_SEM_CHECK_EINVAL(TREF(gtm_environment_init), save_errno, udi);
ISSUE_CRITSEMFAIL_AND_RETURN(reg, "semop()", save_errno);
diff --git a/sr_unix/gds_rundown.c b/sr_unix/gds_rundown.c
index 02d6cf1..8db5389 100644
--- a/sr_unix/gds_rundown.c
+++ b/sr_unix/gds_rundown.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -33,7 +33,6 @@
#include "gdsblk.h"
#include "gt_timer.h"
#include "jnl.h"
-#include "interlock.h"
#include "error.h"
#include "iosp.h"
#include "gdsbgtr.h"
@@ -68,38 +67,22 @@
#include "gtmimagename.h"
#include "gtmio.h"
#include "have_crit.h"
-#include "wcs_clean_dbsync.h"
#include "is_proc_alive.h"
#include "shmpool.h"
#include "db_snapshot.h"
-#include "tp_grab_crit.h"
#include "ss_lock_facility.h"
#include "anticipatory_freeze.h"
+#include "wcs_clean_dbsync.h"
+#include "interlock.h"
+#include "gds_rundown_err_cleanup.h"
#ifndef GTM_SNAPSHOT
# error "Snapshot facility not available on this platform"
#endif
-#define CANCEL_DB_TIMERS(region, csa, cancelled_timer, cancelled_dbsync_timer) \
-{ \
- if (csa->timer) \
- { \
- cancel_timer((TID)region); \
- if (NULL != csa->nl) \
- DECR_CNT(&csa->nl->wcs_timers, &csa->nl->wc_var_lock); \
- cancelled_timer = TRUE; \
- csa->timer = FALSE; \
- } \
- if (csa->dbsync_timer) \
- { \
- CANCEL_DBSYNC_TIMER(csa); \
- cancelled_dbsync_timer = TRUE; \
- } \
-}
-
GBLREF VSIG_ATOMIC_T forced_exit;
GBLREF boolean_t mupip_jnl_recover;
-GBLREF boolean_t created_core, need_core, dont_want_core, is_src_server, is_updproc;
+GBLREF boolean_t is_src_server, is_updproc;
GBLREF gd_region *gv_cur_region;
GBLREF sgmnt_addrs *cs_addrs;
GBLREF sgmnt_data_ptr_t cs_data;
@@ -112,9 +95,7 @@ GBLREF boolean_t dse_running;
GBLREF int num_additional_processors;
GBLREF jnlpool_addrs jnlpool;
GBLREF int process_exiting;
-#ifdef DEBUG
GBLREF boolean_t ok_to_UNWIND_in_exit_handling;
-#endif
LITREF char gtm_release_name[];
LITREF int4 gtm_release_name_len;
@@ -142,7 +123,7 @@ error_def(ERR_STACKOFLOW);
int4 gds_rundown(void)
{
- boolean_t cancelled_dbsync_timer, cancelled_timer, have_standalone_access, ipc_deleted;
+ boolean_t cancelled_dbsync_timer, cancelled_timer, have_standalone_access, ipc_deleted, err_caught;
boolean_t is_cur_process_ss_initiator, remove_shm, vermismatch, we_are_last_user, we_are_last_writer, is_mm;
now_t now; /* for GET_CUR_TIME macro */
char *time_ptr, time_str[CTIME_BEFORE_NL + 2]; /* for GET_CUR_TIME macro */
@@ -192,22 +173,26 @@ int4 gds_rundown(void)
gvusr_rundown();
return EXIT_NRM;
}
- ESTABLISH_RET(gds_rundown_ch, EXIT_ERR);
+ /* If the process has standalone access, it has udi->grabbed_access_sem set to TRUE at this point. Note that down in a local
+ * variable as the udi->grabbed_access_sem is set to TRUE even for non-standalone access below and hence we can't rely on
+ * that later to determine if the process had standalone access or not when it entered this function. We need to guarantee
+ * that none else access database file header when semid/shmid fields are reset. We already have created ftok semaphore in
+ * db_init or, mu_rndwn_file and did not remove it. So just lock it. We do it in blocking mode.
+ */
+ have_standalone_access = udi->grabbed_access_sem; /* process holds standalone access */
+ ESTABLISH_NORET(gds_rundown_ch, err_caught);
+ if (err_caught)
+ {
+ gds_rundown_err_cleanup(have_standalone_access);
+ ENABLE_INTERRUPTS(INTRPT_IN_GDS_RUNDOWN);
+ REVERT;
+ DEBUG_ONLY(ok_to_UNWIND_in_exit_handling = FALSE);
+ return EXIT_ERR;
+ }
assert(reg->open); /* if we failed to open, dbinit_ch should have taken care of proper clean up */
assert(!reg->opening); /* see comment above */
- switch(csd->acc_meth)
- { /* Pass mm and bg through */
- case dba_bg:
- is_mm = FALSE;
- break;
- case dba_mm:
- is_mm = TRUE;
- break;
- case dba_usr:
- assert(FALSE);
- default:
- GTMASSERT;
- }
+ assert((dba_bg == csd->acc_meth) || (dba_mm == csd->acc_meth));
+ is_mm = (dba_bg != csd->acc_meth);
assert(!csa->hold_onto_crit || (csa->now_crit && jgbl.onlnrlbk));
/* If we are online rollback, we should already be holding crit and should release it only at the end of this module. This
* is usually done by noting down csa->now_crit in a local variable (was_crit) and using it whenever we are about to
@@ -230,14 +215,6 @@ int4 gds_rundown(void)
mutex_cleanup(reg);
}
DEFER_INTERRUPTS(INTRPT_IN_GDS_RUNDOWN);
- /* If the process has standalone access, it has udi->grabbed_access_sem set to TRUE at this point. Note that down
- * in a local variable as the udi->grabbed_access_sem is set to TRUE even for non-standalone access below and hence
- * we can't rely on that later to determine if the process had standalone access or not when it entered this function.
- * We need to guarantee that none else access database file header when semid/shmid fields are reset.
- * We already have created ftok semaphore in db_init or, mu_rndwn_file and did not remove it.
- * So just lock it. We do it in blocking mode.
- */
- have_standalone_access = udi->grabbed_access_sem; /* process holds standalone access */
/* The only process that can invoke gds_rundown while holding access control semaphore is RECOVER/ROLLBACK. All the others
* (like MUPIP SET -FILE/MUPIP EXTEND would have invoked db_ipcs_reset() before invoking gds_rundown (from
* mupip_exit_handler). The only exception is when these processes encounter a terminate signal and they reach
@@ -254,7 +231,7 @@ int4 gds_rundown(void)
if (-1 == (ftok_semval = semctl(udi->ftok_semid, 1, GETVAL))) /* Check # of processes counted on FTOK. */
{
save_errno = errno;
- rts_error(VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5,
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5,
RTS_ERROR_TEXT("gds_rundown SEMCTL failed to get ftok_semval"), CALLFROM, errno);
}
/* If csa->timer was true, this process may flush buffers, so it must follow regular protocol.*/
@@ -269,34 +246,38 @@ int4 gds_rundown(void)
{
/* We did a non-blocking wait. It's ok to proceed without locking */
bypassed_ftok = TRUE;
- holder_pid = semctl(udi->ftok_semid, 0, GETPID);
+ holder_pid = semctl(udi->ftok_semid, DB_CONTROL_SEM, GETPID);
if ((uint4)-1 == holder_pid)
- rts_error(VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5,
- RTS_ERROR_TEXT("gds_rundown SEMCTL failed to get holder_pid"), CALLFROM, errno);
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg),
+ ERR_SYSCALL, 5,
+ RTS_ERROR_TEXT("gds_rundown SEMCTL failed to get holder_pid"),
+ CALLFROM, errno);
if (!IS_GTM_IMAGE) /* MUMPS processes should not flood syslog with bypass messages. */
{
- send_msg(VARLSTCNT(12) ERR_RESRCINTRLCKBYPAS, 10,
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(12) ERR_RESRCINTRLCKBYPAS, 10,
LEN_AND_STR(gtmImageNames[image_type].imageName), process_id, LEN_AND_LIT("FTOK"),
REG_LEN_STR(reg), DB_LEN_STR(reg), holder_pid);
- send_msg(VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_LIT("FTOK bypassed at rundown"));
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TEXT, 2,
+ LEN_AND_LIT("FTOK bypassed at rundown"));
}
} else
{ /* We did a blocking wait but something bad happened. */
FTOK_TRACE(csa, csa->ti->curr_tn, ftok_ops_lock, process_id);
- rts_error(VARLSTCNT(4) ERR_DBFILERR, 2, DB_LEN_STR(reg));
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_DBFILERR, 2, DB_LEN_STR(reg));
}
}
- sop[0].sem_num = 0; sop[0].sem_op = 0; /* Wait for 0 */
- sop[1].sem_num = 0; sop[1].sem_op = 1; /* Lock */
+ sop[0].sem_num = DB_CONTROL_SEM; sop[0].sem_op = 0; /* Wait for 0 */
+ sop[1].sem_num = DB_CONTROL_SEM; sop[1].sem_op = 1; /* Lock */
sopcnt = 2;
sop[0].sem_flg = sop[1].sem_flg = SEM_UNDO | IPC_NOWAIT; /* Don't wait the first time thru */
SEMOP(udi->semid, sop, sopcnt, status, NO_WAIT);
if (0 != status)
{
save_errno = errno;
- if (-1 == (semval = semctl(udi->semid, 1, GETVAL))) /* Check # of processes counted on access sem. */
- rts_error(VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5,
+ /* Check # of processes counted on access sem. */
+ if (-1 == (semval = semctl(udi->semid, DB_COUNTER_SEM, GETVAL)))
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5,
RTS_ERROR_TEXT("gds_rundown SEMCTL failed to get semval"), CALLFROM, errno);
/* If csa->timer was true, this process may flush buffers so it must follow regular protocol.*/
bypassed_access = CAN_BYPASS(semval, cancelled_timer, inst_is_frozen) || onln_rlbk_pid || csd->file_corrupt;
@@ -304,15 +285,16 @@ int4 gds_rundown(void)
* If so, it is likely we won't get the access control semaphore anytime soon. In that case, we
* are better off skipping rundown and continuing with sanity cleanup and exit.
*/
- holder_pid = semctl(udi->semid, 0, GETPID);
+ holder_pid = semctl(udi->semid, DB_CONTROL_SEM, GETPID);
if ((uint4)-1 == holder_pid)
- rts_error(VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5,
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5,
RTS_ERROR_TEXT("gds_rundown SEMCTL failed to get holder_pid"), CALLFROM, errno);
if (!bypassed_access)
{ /* We couldn't get it in one shot-- see if we already have it */
if (holder_pid == process_id)
{
- send_msg(VARLSTCNT(5) MAKE_MSG_INFO(ERR_CRITSEMFAIL), 2, DB_LEN_STR(reg), ERR_RNDWNSEMFAIL);
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(5) MAKE_MSG_INFO(ERR_CRITSEMFAIL), 2, DB_LEN_STR(reg),
+ ERR_RNDWNSEMFAIL);
REVERT;
ENABLE_INTERRUPTS(INTRPT_IN_GDS_RUNDOWN);
assert(FALSE);
@@ -321,20 +303,25 @@ int4 gds_rundown(void)
if (EAGAIN != save_errno)
{
assert(FALSE);
- rts_error(VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5,
- RTS_ERROR_TEXT("gds_rundown SEMOP on access control semaphore"), CALLFROM,
- save_errno);
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg),
+ ERR_SYSCALL, 5,
+ RTS_ERROR_TEXT("gds_rundown SEMOP on access control semaphore"),
+ CALLFROM, save_errno);
}
sop[0].sem_flg = sop[1].sem_flg = SEM_UNDO; /* Try again - blocking this time */
SEMOP(udi->semid, sop, 2, status, FORCED_WAIT);
if (-1 == status) /* We couldn't get it at all.. */
- rts_error(VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5,
- RTS_ERROR_TEXT("gds_rundown SEMOP on access control semaphore"), CALLFROM, errno);
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg),
+ ERR_SYSCALL, 5,
+ RTS_ERROR_TEXT("gds_rundown SEMOP on access control semaphore"),
+ CALLFROM, errno);
} else if (!IS_GTM_IMAGE)
{
- send_msg(VARLSTCNT(12) ERR_RESRCINTRLCKBYPAS, 10, LEN_AND_STR(gtmImageNames[image_type].imageName),
- process_id, LEN_AND_LIT("access control"), REG_LEN_STR(reg), DB_LEN_STR(reg), holder_pid);
- send_msg(VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_LIT("Access control bypassed at rundown"));
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(12) ERR_RESRCINTRLCKBYPAS, 10,
+ LEN_AND_STR(gtmImageNames[image_type].imageName), process_id,
+ LEN_AND_LIT("access control"), REG_LEN_STR(reg), DB_LEN_STR(reg), holder_pid);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TEXT, 2,
+ LEN_AND_LIT("Access control bypassed at rundown"));
}
udi->grabbed_access_sem = !bypassed_access;
}
@@ -362,14 +349,14 @@ int4 gds_rundown(void)
if (-1 == shmctl(udi->shmid, IPC_STAT, &shm_buf))
{
save_errno = errno;
- rts_error(VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5, RTS_ERROR_TEXT("gds_rundown shmctl"),
- CALLFROM, save_errno);
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5,
+ RTS_ERROR_TEXT("gds_rundown shmctl"), CALLFROM, save_errno);
} else
we_are_last_user = (1 == shm_buf.shm_nattch) && !vermismatch && !safe_mode;
/* recover => one user except ONLINE ROLLBACK, or standalone with frozen instance */
assert(!have_standalone_access || we_are_last_user || jgbl.onlnrlbk || inst_is_frozen);
- if (-1 == (semval = semctl(udi->semid, 1, GETVAL)))
- rts_error(VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5,
+ if (-1 == (semval = semctl(udi->semid, DB_COUNTER_SEM, GETVAL)))
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5,
RTS_ERROR_TEXT("gds_rundown SEMCTL failed to get semval"), CALLFROM, errno);
/* There's one writer left and I am it */
assert(reg->read_only || semval >= 0);
@@ -380,8 +367,8 @@ int4 gds_rundown(void)
assert(!(have_standalone_access && !reg->read_only) || we_are_last_writer || jgbl.onlnrlbk
|| inst_is_frozen);
GTM_WHITE_BOX_TEST(WBTEST_ANTIFREEZE_JNLCLOSE, we_are_last_writer, 1); /* Assume we are the last writer to invoke wcs_flu */
- if (!have_standalone_access && (-1 == (ftok_semval = semctl(udi->ftok_semid, 1, GETVAL))))
- rts_error(VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5,
+ if (!have_standalone_access && (-1 == (ftok_semval = semctl(udi->ftok_semid, DB_COUNTER_SEM, GETVAL))))
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5,
RTS_ERROR_TEXT("gds_rundown SEMCTL failed to get ftok_semval"), CALLFROM, errno);
if (NULL != csa->ss_ctx)
ss_destroy_context(csa->ss_ctx);
@@ -413,7 +400,7 @@ int4 gds_rundown(void)
{ /* If we had an orphaned block and were interrupted, set wc_blocked so we can invoke wcs_recover. Do it ONLY
* if there is NO concurrent online rollback running (as we need crit to set wc_blocked)
*/
- if (csa->wbuf_dqd)
+ if (csa->wbuf_dqd && !is_mm)
{ /* If we had an orphaned block and were interrupted, mupip_exit_handler will invoke secshr_db_clnup which
* will clear this field and so we should never come to gds_rundown with a non-zero wbuf_dqd. The only
* exception is if we are recover/rollback in which case gds_rundown (from mur_close_files) is invoked
@@ -427,15 +414,10 @@ int4 gds_rundown(void)
grab_crit(reg);
SET_TRACEABLE_VAR(csa->nl->wc_blocked, TRUE);
BG_TRACE_PRO_ANY(csa, wcb_gds_rundown);
- send_msg(VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_LIT("wcb_gds_rundown"),
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_LIT("wcb_gds_rundown"),
process_id, &csa->ti->curr_tn, DB_LEN_STR(reg));
csa->wbuf_dqd = 0;
wcs_recover(reg);
- if (is_mm)
- {
- assert(FALSE);
- csd = csa->hdr;
- }
BG_TRACE_PRO_ANY(csa, lost_block_recovery);
if (!was_crit)
rel_crit(reg);
@@ -448,15 +430,7 @@ int4 gds_rundown(void)
assert(!safe_mode);
if (is_mm)
{
- if (csa->total_blks != csa->ti->total_blks) /* do remap if file had been extended */
- {
- if (!was_crit)
- grab_crit(reg);
- wcs_mm_recover(reg);
- csd = csa->hdr;
- if (!was_crit)
- rel_crit(reg);
- }
+ MM_DBFILEXT_REMAP_IF_NEEDED(csa, reg);
csa->nl->remove_shm = TRUE;
}
if (csa->nl->wc_blocked && jgbl.onlnrlbk)
@@ -559,8 +533,8 @@ int4 gds_rundown(void)
assert(jbp->fsync_dskaddr == jbp->dskaddr);
} else
{
- send_msg(VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(csd),
- ERR_TEXT, 2,
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_JNLFLUSH, 2,
+ JNL_LEN_STR(csd), ERR_TEXT, 2,
RTS_ERROR_TEXT("Error with journal flush in gds_rundown"),
jnl_status);
assert(NOJNL == jpc->channel);/* jnl file lost has been triggered */
@@ -573,7 +547,8 @@ int4 gds_rundown(void)
}
jnl_file_close(reg, we_are_last_writer, FALSE);
} else
- send_msg(VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(reg));
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd),
+ DB_LEN_STR(reg));
}
if (!was_crit)
rel_crit(reg);
@@ -594,30 +569,22 @@ int4 gds_rundown(void)
fileheader_sync(reg);
if (!was_crit)
rel_crit(reg);
- if (FALSE == is_mm)
+ if (!is_mm)
{
GTM_DB_FSYNC(csa, udi->fd, rc); /* Sync it all */
if (-1 == rc)
{
- rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg),
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg),
ERR_TEXT, 2, RTS_ERROR_TEXT("Error during file sync at close"), errno);
}
} else
{ /* Now do final MM file sync before exit */
-# if !defined(TARGETED_MSYNC) && !defined(NO_MSYNC)
- GTM_DB_FSYNC(csa, udi->fd, rc); /* Sync it all */
- if (-1 == rc)
- {
- rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg),
- ERR_TEXT, 2, RTS_ERROR_TEXT("Error during file sync at close"), errno);
- }
-# else
- if (-1 == msync((caddr_t)csa->db_addrs[0], (size_t)(csa->db_addrs[1] - csa->db_addrs[0]), MS_SYNC))
+ assert(csa->ti->total_blks == csa->total_blks);
+ if (-1 == MSYNC((caddr_t)csa->db_addrs[0], (caddr_t)csa->db_addrs[1]))
{
- rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg),
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg),
ERR_TEXT, 2, RTS_ERROR_TEXT("Error during file msync at close"), errno);
}
-# endif
}
}
} /* end if (!reg->read_only && !csa->nl->donotflush_dbjnl) */
@@ -637,29 +604,23 @@ int4 gds_rundown(void)
/* request gtmsecshr to flush. read_only cannot flush itself */
WAIT_FOR_REPL_INST_UNFREEZE_SAFE(csa);
if (0 != send_mesg2gtmsecshr(FLUSH_DB_IPCS_INFO, 0, (char *)NULL, 0))
- rts_error(VARLSTCNT(8) ERR_DBFILERR, 2, DB_LEN_STR(reg),
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_DBFILERR, 2, DB_LEN_STR(reg),
ERR_TEXT, 2, RTS_ERROR_TEXT("gtmsecshr failed to update database file header"));
}
/* Done with file now, close it */
CLOSEFILE_RESET(udi->fd, rc); /* resets "udi->fd" to FD_INVALID */
if (-1 == rc)
{
- rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg),
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg),
ERR_TEXT, 2, LEN_AND_LIT("Error during file close"), errno);
}
/* Unmap storage if mm mode but only the part that is not the fileheader (so shows up in dumps) */
- if (is_mm)
+ if (is_mm && (NULL != csa->db_addrs[0]))
{
- munmap_len = (sm_long_t)((csa->db_addrs[1] - csa->db_addrs[0]) - ROUND_UP(SIZEOF_FILE_HDR(csa->hdr),
- MSYNC_ADDR_INCS));
- if (munmap_len > 0)
- {
- munmap((caddr_t)(csa->db_addrs[0] + ROUND_UP(SIZEOF_FILE_HDR(csa->hdr), MSYNC_ADDR_INCS)),
- (size_t)(munmap_len));
-# ifdef DEBUG_DB64
- rel_mmseg((caddr_t)csa->db_addrs[0]);
-# endif
- }
+ assert(csa->db_addrs[1] > csa->db_addrs[0]);
+ munmap_len = (sm_long_t)(csa->db_addrs[1] - csa->db_addrs[0]);
+ if (0 < munmap_len)
+ munmap((caddr_t)(csa->db_addrs[0]), (size_t)(munmap_len));
}
/* Detach our shared memory while still under lock so reference counts will be correct for the next process to run down
* this region. In the process also get the remove_shm status from node_local before detaching.
@@ -682,16 +643,12 @@ int4 gds_rundown(void)
csa->hold_onto_crit = FALSE;
csa->nl->onln_rlbk_pid = 0;
}
-# ifdef DEBUG
- if (gtm_white_box_test_case_enabled && (WBTEST_HOLD_SEM_BYPASS == gtm_white_box_test_case_number))
- {
- csa->nl->wbox_test_seq_num = 0;
- }
-# endif
+ GTM_WHITE_BOX_TEST(WBTEST_HOLD_SEM_BYPASS, csa->nl->wbox_test_seq_num, 0);
status = shmdt((caddr_t)csa->nl);
csa->nl = NULL; /* dereferencing nl after detach is not right, so we set it to NULL so that we can test before dereference*/
if (-1 == status)
- send_msg(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), ERR_TEXT, 2, LEN_AND_LIT("Error during shmdt"), errno);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), ERR_TEXT, 2,
+ LEN_AND_LIT("Error during shmdt"), errno);
REMOVE_CSA_FROM_CSADDRSLIST(csa); /* remove "csa" from list of open regions (cs_addrs_list) */
reg->open = FALSE;
/* If file is still not in good shape, die here and now before we get rid of our storage */
@@ -705,23 +662,24 @@ int4 gds_rundown(void)
{
ipc_deleted = TRUE;
if (0 != shm_rmid(udi->shmid))
- rts_error(VARLSTCNT(8) ERR_DBFILERR, 2, DB_LEN_STR(reg),
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_DBFILERR, 2, DB_LEN_STR(reg),
ERR_TEXT, 2, RTS_ERROR_TEXT("Unable to remove shared memory"));
} else if (is_src_server || is_updproc)
{
- gtm_putmsg(VARLSTCNT(6) ERR_DBRNDWNWRN, 4, DB_LEN_STR(reg), process_id, process_id);
- send_msg(VARLSTCNT(6) ERR_DBRNDWNWRN, 4, DB_LEN_STR(reg), process_id, process_id);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_DBRNDWNWRN, 4, DB_LEN_STR(reg), process_id, process_id);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_DBRNDWNWRN, 4, DB_LEN_STR(reg), process_id, process_id);
} else
- send_msg(VARLSTCNT(6) ERR_DBRNDWNWRN, 4, DB_LEN_STR(reg), process_id, process_id);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_DBRNDWNWRN, 4, DB_LEN_STR(reg), process_id, process_id);
/* mupip recover/rollback don't release the semaphore here, but do it later in db_ipcs_reset (invoked from
* mur_close_files())
*/
if (!have_standalone_access)
{
if (0 != sem_rmid(udi->semid))
- rts_error(VARLSTCNT(8) ERR_DBFILERR, 2, DB_LEN_STR(reg),
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_DBFILERR, 2, DB_LEN_STR(reg),
ERR_TEXT, 2, RTS_ERROR_TEXT("Unable to remove semaphore"));
udi->grabbed_access_sem = FALSE;
+ udi->counter_acc_incremented = FALSE;
}
} else
{
@@ -729,18 +687,23 @@ int4 gds_rundown(void)
if (!jgbl.onlnrlbk && !have_standalone_access)
{ /* If we were writing, get rid of our writer access count semaphore */
if (!reg->read_only)
- if (0 != (save_errno = do_semop(udi->semid, 1, -1, SEM_UNDO)))
- rts_error(VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5,
- RTS_ERROR_TEXT("gds_rundown access control semaphore release"), CALLFROM,
- save_errno);
+ {
+ if (0 != (save_errno = do_semop(udi->semid, DB_COUNTER_SEM, -1, SEM_UNDO)))
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg),
+ ERR_SYSCALL, 5,
+ RTS_ERROR_TEXT("gds_rundown access control semaphore decrement"),
+ CALLFROM, save_errno);
+ udi->counter_acc_incremented = FALSE;
+ }
assert(safe_mode || !bypassed_access);
/* Now remove the rundown lock */
if (!bypassed_access)
- { /* Do it only if we skipped getting the access control semaphore above */
- if (0 != (save_errno = do_semop(udi->semid, 0, -1, SEM_UNDO)))
- rts_error(VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5,
- RTS_ERROR_TEXT("gds_rundown access control semaphore decrement"), CALLFROM,
- save_errno);
+ {
+ if (0 != (save_errno = do_semop(udi->semid, DB_CONTROL_SEM, -1, SEM_UNDO)))
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg),
+ ERR_SYSCALL, 5,
+ RTS_ERROR_TEXT("gds_rundown access control semaphore release"),
+ CALLFROM, save_errno);
udi->grabbed_access_sem = FALSE;
}
} /* else access control semaphore will be released in db_ipcs_reset */
@@ -749,89 +712,34 @@ int4 gds_rundown(void)
{
if (bypassed_ftok)
{
- if (0 != (save_errno = do_semop(udi->ftok_semid, 1, -1, SEM_UNDO)))
- {
- rts_error(VARLSTCNT(4) ERR_DBFILERR, 2, DB_LEN_STR(reg));
- }
- } else if (!ftok_sem_release(reg, !have_standalone_access, FALSE))
+ if (0 != (save_errno = do_semop(udi->ftok_semid, DB_COUNTER_SEM, -1, SEM_UNDO)))
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_DBFILERR, 2, DB_LEN_STR(reg));
+ } else if (!ftok_sem_release(reg, TRUE, FALSE))
{
- rts_error(VARLSTCNT(4) ERR_DBFILERR, 2, DB_LEN_STR(reg));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_DBFILERR, 2, DB_LEN_STR(reg));
FTOK_TRACE(csa, csa->ti->curr_tn, ftok_ops_release, process_id);
}
+ udi->grabbed_ftok_sem = FALSE;
+ udi->counter_ftok_incremented = FALSE;
}
ENABLE_INTERRUPTS(INTRPT_IN_GDS_RUNDOWN);
if (!ipc_deleted)
{
GET_CUR_TIME;
if (is_src_server)
- gtm_putmsg(VARLSTCNT(8) ERR_IPCNOTDEL, 6, CTIME_BEFORE_NL, time_ptr,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_IPCNOTDEL, 6, CTIME_BEFORE_NL, time_ptr,
LEN_AND_LIT("Source server"), REG_LEN_STR(reg));
if (is_updproc)
- gtm_putmsg(VARLSTCNT(8) ERR_IPCNOTDEL, 6, CTIME_BEFORE_NL, time_ptr,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_IPCNOTDEL, 6, CTIME_BEFORE_NL, time_ptr,
LEN_AND_LIT("Update process"), REG_LEN_STR(reg));
if (mupip_jnl_recover && (!jgbl.onlnrlbk || !we_are_last_user))
{
- gtm_putmsg(VARLSTCNT(8) ERR_IPCNOTDEL, 6, CTIME_BEFORE_NL, time_ptr,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_IPCNOTDEL, 6, CTIME_BEFORE_NL, time_ptr,
LEN_AND_LIT("Mupip journal process"), REG_LEN_STR(reg));
- send_msg(VARLSTCNT(8) ERR_IPCNOTDEL, 6, CTIME_BEFORE_NL, time_ptr,
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_IPCNOTDEL, 6, CTIME_BEFORE_NL, time_ptr,
LEN_AND_LIT("Mupip journal process"), REG_LEN_STR(reg));
}
}
REVERT;
return EXIT_NRM;
}
-
-CONDITION_HANDLER(gds_rundown_ch)
-{
- pid_t sem_pid;
- int semop_res;
- unix_db_info *udi;
- sgmnt_addrs *csa;
- boolean_t cancelled_timer, cancelled_dbsync_timer, have_standalone_access;
-
- START_CH;
- /* To get as virgin a state as possible in the core, take the core now if we
- * would be doing so anyway. This will set created_core so it doesn't happen again.
- */
- if (DUMPABLE && !SUPPRESS_DUMP)
- {
- need_core = TRUE;
- gtm_fork_n_core();
- }
- udi = FILE_INFO(gv_cur_region);
- csa = &udi->s_addrs;
- /* We got here on an error and are going to close the region. Cancel any pending flush timer for this region by this task*/
- CANCEL_DB_TIMERS(gv_cur_region, csa, cancelled_timer, cancelled_dbsync_timer);
- /* release the access control semaphore, if you hold it */
- have_standalone_access = udi->grabbed_access_sem;
- if (udi->grabbed_access_sem)
- {
- if (csa->now_crit) /* Might hold crit if wcs_flu or other failure */
- {
- assert(!csa->hold_onto_crit || jgbl.onlnrlbk);
- if (NULL != csa->nl)
- rel_crit(gv_cur_region); /* also sets csa->now_crit to FALSE */
- else
- csa->now_crit = FALSE;
- }
- sem_pid = semctl(udi->semid, 0, GETPID);
- assert(sem_pid == process_id);
- if (0 != (semop_res = do_semop(udi->semid, 0, -1, SEM_UNDO | IPC_NOWAIT)))
- gtm_putmsg(VARLSTCNT(9) ERR_CRITSEMFAIL, 2, DB_LEN_STR(gv_cur_region),
- ERR_TEXT, 2, RTS_ERROR_TEXT("Error releasing access semaphore"), semop_res);
- udi->grabbed_access_sem = FALSE;
-
- }
- if (udi->grabbed_ftok_sem)
- {
- assert(!have_standalone_access);
- ftok_sem_release(gv_cur_region, !have_standalone_access, TRUE);
- }
- gv_cur_region->open = FALSE;
- csa->nl = NULL;
- REMOVE_CSA_FROM_CSADDRSLIST(csa); /* remove "csa" from list of open regions (cs_addrs_list) */
- PRN_ERROR;
- gtm_putmsg(VARLSTCNT(4) ERR_DBRNDWN, 2, REG_LEN_STR(gv_cur_region));
- DEBUG_ONLY(ok_to_UNWIND_in_exit_handling = TRUE;)
- UNWIND(NULL, NULL);
-}
diff --git a/sr_unix/gds_rundown_ch.c b/sr_unix/gds_rundown_ch.c
new file mode 100644
index 0000000..4106189
--- /dev/null
+++ b/sr_unix/gds_rundown_ch.c
@@ -0,0 +1,39 @@
+/****************************************************************
+* *
+* Copyright 2013 Fidelity Information Services, Inc *
+* *
+* This source code contains the intellectual property *
+* of its copyright holder(s), and is made available *
+* under a license. If you do not know the terms of *
+* the license, please stop and do not read further. *
+* *
+****************************************************************/
+
+#include "mdef.h"
+#include "error.h"
+
+GBLREF boolean_t created_core, need_core, dont_want_core;
+#ifdef DEBUG
+#include "have_crit.h"
+GBLREF boolean_t ok_to_UNWIND_in_exit_handling;
+#endif
+
+CONDITION_HANDLER(gds_rundown_ch)
+{
+ START_CH;
+ /* To get as virgin a state as possible in the core, take the core now if we
+ * would be doing so anyway. This will set created_core so it doesn't happen again.
+ */
+ if (DUMPABLE && !SUPPRESS_DUMP)
+ {
+ need_core = TRUE;
+ gtm_fork_n_core();
+ }
+ assert(INTRPT_IN_GDS_RUNDOWN == intrpt_ok_state);
+ PRN_ERROR;
+ DEBUG_ONLY(ok_to_UNWIND_in_exit_handling = TRUE);
+ UNWIND(NULL, NULL);
+}
+
+
+
diff --git a/sr_unix/gds_rundown_err_cleanup.c b/sr_unix/gds_rundown_err_cleanup.c
new file mode 100644
index 0000000..a25ba36
--- /dev/null
+++ b/sr_unix/gds_rundown_err_cleanup.c
@@ -0,0 +1,91 @@
+/****************************************************************
+* *
+* Copyright 2013 Fidelity Information Services, Inc *
+* *
+* This source code contains the intellectual property *
+* of its copyright holder(s), and is made available *
+* under a license. If you do not know the terms of *
+* the license, please stop and do not read further. *
+* *
+****************************************************************/
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "gds_rundown.h"
+#include "jnl.h"
+#include "gtm_semutils.h"
+#include "do_semop.h"
+#include "add_inter.h"
+#include "ftok_sems.h"
+#include <sys/sem.h>
+#include "wcs_clean_dbsync.h"
+#include "interlock.h"
+#include "wbox_test_init.h"
+#include "gds_rundown_err_cleanup.h"
+
+GBLREF gd_region *gv_cur_region;
+GBLREF jnl_gbls_t jgbl;
+GBLREF uint4 process_id;
+
+error_def(ERR_TEXT);
+error_def(ERR_DBRNDWN);
+
+void gds_rundown_err_cleanup(boolean_t have_standalone_access)
+{
+ pid_t sem_pid;
+ int semop_res;
+ unix_db_info *udi;
+ sgmnt_addrs *csa;
+ boolean_t cancelled_timer, cancelled_dbsync_timer;
+
+ udi = FILE_INFO(gv_cur_region);
+ csa = &udi->s_addrs;
+ /* We got here on an error and are going to close the region. Cancel any pending flush timer for this region by this task*/
+ CANCEL_DB_TIMERS(gv_cur_region, csa, cancelled_timer, cancelled_dbsync_timer);
+ if (csa->now_crit) /* Might hold crit if wcs_flu or other failure */
+ {
+ assert(!csa->hold_onto_crit || jgbl.onlnrlbk);
+ if (NULL != csa->nl)
+ rel_crit(gv_cur_region); /* also sets csa->now_crit to FALSE */
+ else
+ csa->now_crit = FALSE;
+ }
+ if (!have_standalone_access)
+ {
+ if (udi->grabbed_access_sem)
+ { /* release the access control semaphore, if you hold it */
+ sem_pid = semctl(udi->semid, 0, GETPID);
+ assert(sem_pid == process_id);
+ if (0 != (semop_res = do_semop(udi->semid, DB_CONTROL_SEM, -1, SEM_UNDO | IPC_NOWAIT)))
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_CRITSEMFAIL, 2, DB_LEN_STR(gv_cur_region),
+ ERR_TEXT, 2, RTS_ERROR_TEXT("Error releasing access semaphore"), semop_res);
+ udi->grabbed_access_sem = FALSE;
+ }
+ if (udi->counter_acc_incremented)
+ {
+ if (0 != (semop_res = do_semop(udi->semid, DB_COUNTER_SEM, -1, SEM_UNDO | IPC_NOWAIT)))
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_CRITSEMFAIL, 2, DB_LEN_STR(gv_cur_region),
+ ERR_TEXT, 2, RTS_ERROR_TEXT("Error decreasing access semaphore counter"), semop_res);
+ udi->counter_acc_incremented = FALSE;
+ }
+ }
+ if (udi->grabbed_ftok_sem)
+ { /* Decrease counter and release ftok */
+ assert(!have_standalone_access);
+ ftok_sem_release(gv_cur_region, !have_standalone_access, TRUE);
+ } else if (udi->counter_ftok_incremented) /* Just decrease ftok counter */
+ {
+ if (0 != (semop_res = do_semop(udi->ftok_semid, DB_COUNTER_SEM, -1, SEM_UNDO | IPC_NOWAIT)))
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_CRITSEMFAIL, 2, DB_LEN_STR(gv_cur_region),
+ ERR_TEXT, 2, RTS_ERROR_TEXT("Error decreasing ftok semaphore counter"), semop_res);
+ udi->counter_ftok_incremented = FALSE;
+ }
+ gv_cur_region->open = FALSE;
+ csa->nl = NULL;
+ REMOVE_CSA_FROM_CSADDRSLIST(csa); /* remove "csa" from list of open regions (cs_addrs_list) */
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_DBRNDWN, 2, REG_LEN_STR(gv_cur_region));
+}
diff --git a/sr_unix/gds_rundown_err_cleanup.h b/sr_unix/gds_rundown_err_cleanup.h
new file mode 100644
index 0000000..14759cd
--- /dev/null
+++ b/sr_unix/gds_rundown_err_cleanup.h
@@ -0,0 +1,16 @@
+/****************************************************************
+* *
+* Copyright 2013 Fidelity Information Services, Inc *
+* *
+* This source code contains the intellectual property *
+* of its copyright holder(s), and is made available *
+* under a license. If you do not know the terms of *
+* the license, please stop and do not read further. *
+* *
+****************************************************************/
+#ifndef GDS_RUNDOWN_ERR_CLEANUP_INCLUDED
+#define GDS_RUNDOWN_ERR_CLEANUP_INCLUDED
+
+void gds_rundown_err_cleanup(boolean_t have_standalone_access);
+
+#endif
diff --git a/sr_unix/gdsfilext.c b/sr_unix/gdsfilext.c
index 08f3c9a..29e9192 100644
--- a/sr_unix/gdsfilext.c
+++ b/sr_unix/gdsfilext.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -55,12 +55,22 @@
#include "gtmsource.h"
#include "error.h"
-#define GDSFILEXT_CLNUP { if (need_to_restore_mask) \
- sigprocmask(SIG_SETMASK, &savemask, NULL); \
- if (!was_crit) \
- rel_crit(gv_cur_region); \
- cs_addrs->extending = FALSE; \
- }
+#define GDSFILEXT_CLNUP \
+{ \
+ if (!was_crit) \
+ rel_crit(gv_cur_region); \
+}
+
+#define ISSUE_WAITDSKSPACE(TO_WAIT, WAIT_PERIOD, MECHANISM) \
+{ \
+ uint4 seconds; \
+ \
+ seconds = TO_WAIT + (CDB_STAGNATE - t_tries) * WAIT_PERIOD; \
+ MECHANISM(CSA_ARG(cs_addrs) VARLSTCNT(11) ERR_WAITDSKSPACE, 4, process_id, seconds, DB_LEN_STR(gv_cur_region), ERR_TEXT,\
+ 2, LEN_AND_LIT("Please make more disk space available or shutdown GT.M to avoid data loss"), ENOSPC); \
+}
+
+#define SUSPICIOUS_EXTEND (2 * (dollar_tlevel ? sgm_info_ptr->cw_set_depth : cw_set_depth) < cs_addrs->ti->free_blocks)
GBLREF sigset_t blockalrm;
GBLREF sgmnt_addrs *cs_addrs;
@@ -84,64 +94,72 @@ error_def(ERR_DBFILEXT);
error_def(ERR_DSKSPACEFLOW);
error_def(ERR_JNLFLUSH);
error_def(ERR_NOSPACEEXT);
+error_def(ERR_SYSCALL);
error_def(ERR_TEXT);
error_def(ERR_TOTALBLKMAX);
error_def(ERR_WAITDSKSPACE);
OS_PAGE_SIZE_DECLARE
-uint4 gdsfilext (uint4 blocks, uint4 filesize)
+uint4 gdsfilext(uint4 blocks, uint4 filesize, boolean_t trans_in_prog)
{
- sm_uc_ptr_t old_base[2];
- boolean_t was_crit, need_to_restore_mask = FALSE;
- char *buff;
- int mm_prot, result, save_errno, status;
- uint4 new_bit_maps, bplmap, map, new_blocks, new_total, max_tot_blks;
+ sm_uc_ptr_t old_base[2], mmap_retaddr;
+ boolean_t was_crit, is_mm;
+ char buff[DISK_BLOCK_SIZE];
+ int result, save_errno, status;
+ uint4 new_bit_maps, bplmap, map, new_blocks, new_total, max_tot_blks, old_total;
uint4 jnl_status, to_wait, to_msg, wait_period;
- gtm_uint64_t avail_blocks;
- sgmnt_data_ptr_t tmp_csd;
+ gtm_uint64_t avail_blocks, mmap_sz;
off_t new_eof;
trans_num curr_tn;
unix_db_info *udi;
- sigset_t savemask;
inctn_opcode_t save_inctn_opcode;
int4 prev_extend_blks_to_upgrd;
jnl_private_control *jpc;
jnl_buffer_ptr_t jbp;
+ cache_rec_ptr_t cr;
DCL_THREADGBL_ACCESS;
+ assert(!IS_DSE_IMAGE);
assert((cs_addrs->nl == NULL) || (process_id != cs_addrs->nl->trunc_pid)); /* mu_truncate shouldn't extend file... */
+ assert(!process_exiting);
+ DEBUG_ONLY(old_base[0] = old_base[1] = NULL);
+ assert(!gv_cur_region->read_only);
udi = FILE_INFO(gv_cur_region);
+ is_mm = (dba_mm == cs_addrs->hdr->acc_meth);
# if !defined(MM_FILE_EXT_OK)
- if (!udi->grabbed_access_sem && (dba_mm == cs_addrs->hdr->acc_meth))
+ if (!udi->grabbed_access_sem && is_mm)
return (uint4)(NO_FREE_SPACE); /* should this be changed to show extension not allowed ? */
# endif
-
/* Both blocks and total blocks are unsigned ints so make sure we aren't asking for huge numbers that will
overflow and end up doing silly things.
*/
- assert((blocks <= (MAXTOTALBLKS(cs_data) - cs_data->trans_hist.total_blks)) ||
- (gtm_white_box_test_case_enabled && (WBTEST_FILE_EXTEND_ERROR == gtm_white_box_test_case_number)));
-
+ assert((blocks <= (MAXTOTALBLKS(cs_data) - cs_data->trans_hist.total_blks)) || WBTEST_ENABLED(WBTEST_FILE_EXTEND_ERROR));
if (!blocks)
return (uint4)(NO_FREE_SPACE); /* should this be changed to show extension not enabled ? */
bplmap = cs_data->bplmap;
- /* new total of non-bitmap blocks will be number of current, non-bitmap blocks, plus new blocks desired
- There are (bplmap - 1) non-bitmap blocks per bitmap, so add (bplmap - 2) to number of non-bitmap blocks
- and divide by (bplmap - 1) to get total number of bitmaps for expanded database. (must round up in this
- manner as every non-bitmap block must have an associated bitmap)
- Current number of bitmaps is (total number of current blocks + bplmap - 1) / bplmap.
- Subtract current number of bitmaps from number needed for expanded database to get number of new bitmaps needed.
- */
+ /* New total of non-bitmap blocks will be number of current, non-bitmap blocks, plus new blocks desired
+ * There are (bplmap - 1) non-bitmap blocks per bitmap, so add (bplmap - 2) to number of non-bitmap blocks
+ * and divide by (bplmap - 1) to get total number of bitmaps for expanded database. (must round up in this
+ * manner as every non-bitmap block must have an associated bitmap)
+ * Current number of bitmaps is (total number of current blocks + bplmap - 1) / bplmap.
+ * Subtract current number of bitmaps from number needed for expanded database to get number of new bitmaps needed.
+ */
new_bit_maps = DIVIDE_ROUND_UP(cs_data->trans_hist.total_blks
- DIVIDE_ROUND_UP(cs_data->trans_hist.total_blks, bplmap) + blocks, bplmap - 1)
- DIVIDE_ROUND_UP(cs_data->trans_hist.total_blks, bplmap);
new_blocks = blocks + new_bit_maps;
assert(0 < (int)new_blocks);
+ if (new_blocks + cs_data->trans_hist.total_blks > MAXTOTALBLKS(cs_data))
+ {
+ assert(FALSE);
+ send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(1) ERR_TOTALBLKMAX);
+ return (uint4)(NO_FREE_SPACE);
+ }
if (0 != (save_errno = disk_block_available(udi->fd, &avail_blocks, FALSE)))
{
- send_msg(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region), save_errno);
- rts_error(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region), save_errno);
+ send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region), save_errno);
+ rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region), save_errno);
} else
{
if (!(gtmDebugLevel & GDL_IgnoreAvailSpace))
@@ -157,15 +175,15 @@ uint4 gdsfilext (uint4 blocks, uint4 filesize)
if (!ANTICIPATORY_FREEZE_ENABLED(cs_addrs))
return (uint4)(NO_FREE_SPACE);
else
- send_msg(VARLSTCNT(6) MAKE_MSG_WARNING(ERR_NOSPACEEXT), 4,
+ send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(6) MAKE_MSG_WARNING(ERR_NOSPACEEXT), 4,
DB_LEN_STR(gv_cur_region), new_blocks, (uint4)avail_blocks);
} else
- send_msg(VARLSTCNT(5) ERR_DSKSPACEFLOW, 3, DB_LEN_STR(gv_cur_region),
+ send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(5) ERR_DSKSPACEFLOW, 3, DB_LEN_STR(gv_cur_region),
(uint4)(avail_blocks - ((new_blocks <= avail_blocks) ? new_blocks : 0)));
}
}
}
- cs_addrs->extending = TRUE;
+ /* From here on, we need to use GDSFILEXT_CLNUP before returning to the caller */
was_crit = cs_addrs->now_crit;
assert(!cs_addrs->hold_onto_crit || was_crit);
/* If we are coming from mupip_extend (which gets crit itself) we better have waited for any unfreezes to occur.
@@ -206,29 +224,31 @@ uint4 gdsfilext (uint4 blocks, uint4 filesize)
* op_tcommit will recognize (as a cdb_sc_needcrit type of restart) and restart accordingly.
*/
assert(CDB_STAGNATE <= t_tries);
+ GDSFILEXT_CLNUP;
return (uint4)(FINAL_RETRY_FREEZE_PROG);
}
assert(cs_addrs->ti->total_blks == cs_data->trans_hist.total_blks);
- if (cs_data->trans_hist.total_blks != filesize)
- {
- /* somebody else has already extended it, since we are in crit, this is trust-worthy
- * however, in case of MM, we still need to remap the database */
- assert((cs_data->trans_hist.total_blks > filesize) GTM_TRUNCATE_ONLY( || (dba_mm != cs_addrs->hdr->acc_meth)));
+ old_total = cs_data->trans_hist.total_blks;
+ if (old_total != filesize)
+ { /* Somebody else has already extended it, since we are in crit, this is trust-worthy. However, in case of MM,
+ * we still need to remap the database
+ */
+ assert((old_total > filesize) GTM_TRUNCATE_ONLY( || !is_mm));
/* For BG, someone else could have truncated or extended - we have no idea */
GDSFILEXT_CLNUP;
return (SS_NORMAL);
}
- if (IS_GTM_IMAGE && (2 * (dollar_tlevel ? sgm_info_ptr->cw_set_depth : cw_set_depth) < cs_addrs->ti->free_blocks))
+ if (trans_in_prog && SUSPICIOUS_EXTEND)
{
- if (FALSE == was_crit)
+ if (!was_crit)
{
- rel_crit(gv_cur_region);
+ GDSFILEXT_CLNUP;
return (uint4)(EXTEND_SUSPECT);
}
- /* If free_blocks counter is not ok, then correct it. Do the check again. If still fails, then GTMASSERT. */
- if (is_free_blks_ctr_ok() ||
- (2 * (dollar_tlevel ? sgm_info_ptr->cw_set_depth : cw_set_depth) < cs_addrs->ti->free_blocks))
- GTMASSERT; /* held crit through bm_getfree into gdsfilext and still didn't get it right */
+ /* If free_blocks counter is not ok, then correct it. Do the check again. If still fails, then it means we held
+ * crit through bm_getfree into gdsfilext and still didn't get it right.
+ */
+ assertpro(!is_free_blks_ctr_ok() && !SUSPICIOUS_EXTEND);
}
if (JNL_ENABLED(cs_data))
{
@@ -245,125 +265,90 @@ uint4 gdsfilext (uint4 blocks, uint4 filesize)
if (jnl_status)
{
GDSFILEXT_CLNUP;
- send_msg(VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(cs_data), DB_LEN_STR(gv_cur_region));
+ send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(cs_data), DB_LEN_STR(gv_cur_region));
return (uint4)(NO_FREE_SPACE); /* should have better return status */
}
}
- if (dba_mm == cs_addrs->hdr->acc_meth)
+ if (is_mm)
{
-#if defined(UNTARGETED_MSYNC)
- status = msync((caddr_t)cs_addrs->db_addrs[0], (size_t)(cs_addrs->db_addrs[1] - cs_addrs->db_addrs[0]), MS_SYNC);
-#else
cs_addrs->nl->mm_extender_pid = process_id;
status = wcs_wtstart(gv_cur_region, 0);
cs_addrs->nl->mm_extender_pid = 0;
- if (0 != cs_addrs->acc_meth.mm.mmblk_state->mmblkq_active.fl)
- GTMASSERT;
- status = 0;
-#endif
- if (0 == status)
- {
- /* Block SIGALRM for the duration when cs_data and cs_addrs are out of sync */
- sigprocmask(SIG_BLOCK, &blockalrm, &savemask);
- need_to_restore_mask = TRUE;
- tmp_csd = cs_data;
- cs_data = (sgmnt_data_ptr_t)malloc(SIZEOF(*cs_data));
- memcpy((sm_uc_ptr_t)cs_data, (uchar_ptr_t)tmp_csd, SIZEOF(*cs_data));
- status = munmap((caddr_t)cs_addrs->db_addrs[0], (size_t)(cs_addrs->db_addrs[1] - cs_addrs->db_addrs[0]));
- } else
- tmp_csd = NULL;
+ assertpro(SS_NORMAL == status);
+ old_base[0] = cs_addrs->db_addrs[0];
+ old_base[1] = cs_addrs->db_addrs[1];
+ cs_addrs->db_addrs[0] = NULL; /* don't rely on it until the mmap below */
+ status = munmap((caddr_t)old_base[0], (size_t)(old_base[1] - old_base[0]));
if (0 != status)
{
- if (tmp_csd)
- {
- free(cs_data);
- cs_data = tmp_csd;
- }
+ save_errno = errno;
GDSFILEXT_CLNUP;
- send_msg(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region), status);
+ send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(12) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region),
+ ERR_SYSCALL, 5, LEN_AND_LIT("munmap()"), CALLFROM, save_errno);
return (uint4)(NO_FREE_SPACE);
}
- cs_addrs->hdr = cs_data;
- cs_addrs->ti = &cs_data->trans_hist;
- }
- if (new_blocks + cs_data->trans_hist.total_blks > MAXTOTALBLKS(cs_data))
- {
- GDSFILEXT_CLNUP;
- send_msg(VARLSTCNT(1) ERR_TOTALBLKMAX);
- return (uint4)(NO_FREE_SPACE);
+ } else
+ { /* Due to concurrency issues, it is possible some process had issued a disk read of the GDS block# corresponding
+ * to "old_total" right after a truncate wrote a 512-byte block of zeros on disk (to signal end of the db file).
+ * If so, the global buffer containing this block needs to be invalidated now as part of the extend. If not, it is
+ * possible the EOF block on disk is now going to be overwritten by a properly initialized bitmap block (as part
+ * of the gdsfilext below) while the global buffer continues to have an incorrect copy of that bitmap block and
+ * this in turn would cause XXXX failures due to a bad bitmap block in shared memory. (GTM-7519)
+ */
+ cr = db_csh_get((block_id)old_total);
+ if ((NULL != cr) && ((cache_rec_ptr_t)CR_NOTVALID != cr))
+ {
+ assert((0 == cr->dirty) && (0 == cr->bt_index) && !cr->stopped);
+ cr->cycle++;
+ cr->blk = CR_BLKEMPTY;
+ }
}
CHECK_TN(cs_addrs, cs_data, cs_data->trans_hist.curr_tn); /* can issue rts_error TNTOOLARGE */
- new_total = cs_data->trans_hist.total_blks + new_blocks;
+ new_total = old_total + new_blocks;
new_eof = ((off_t)(cs_data->start_vbn - 1) * DISK_BLOCK_SIZE) + ((off_t)new_total * cs_data->blk_size);
- buff = (char *)malloc(DISK_BLOCK_SIZE);
- memset(buff, 0, DISK_BLOCK_SIZE);
DB_LSEEKWRITE(cs_addrs, udi->fn, udi->fd, new_eof, buff, DISK_BLOCK_SIZE, save_errno);
if ((ENOSPC == save_errno) && IS_GTM_IMAGE)
{
- /* try to write it every second, and send message to operator
- * log every 1/20 of cs_data->wait_disk_space
- */
+ /* Attempt to write every second, and send message to operator every 1/20 of cs_data->wait_disk_space */
wait_period = to_wait = DIVIDE_ROUND_UP(cs_data->wait_disk_space, CDB_STAGNATE + 1);
to_msg = (to_wait / 8) ? (to_wait / 8) : 1; /* send around 8 messages during 1 wait_period */
while ((to_wait > 0) && (ENOSPC == save_errno))
{
if ((to_wait == cs_data->wait_disk_space) || (to_wait % to_msg == 0))
- {
- send_msg(VARLSTCNT(11) ERR_WAITDSKSPACE, 4, process_id,
- to_wait + (CDB_STAGNATE - t_tries) * wait_period, DB_LEN_STR(gv_cur_region),
- ERR_TEXT, 2,
- RTS_ERROR_TEXT("Please make more disk space available or shutdown GT.M to avoid data loss"),
- save_errno);
- gtm_putmsg(VARLSTCNT(11) ERR_WAITDSKSPACE, 4, process_id,
- to_wait + (CDB_STAGNATE - t_tries) * wait_period, DB_LEN_STR(gv_cur_region),
- ERR_TEXT, 2,
- RTS_ERROR_TEXT("Please make more disk space available or shutdown GT.M to avoid data loss"),
- save_errno);
- }
- if (!was_crit)
- rel_crit(gv_cur_region);
+ ISSUE_WAITDSKSPACE(to_wait, wait_period, send_msg_csa);
hiber_start(1000);
to_wait--;
- if (!was_crit)
- grab_crit(gv_cur_region);
LSEEKWRITE(udi->fd, new_eof, buff, DISK_BLOCK_SIZE, save_errno);
}
}
- free(buff);
if (0 != save_errno)
{
GDSFILEXT_CLNUP;
- if (ENOSPC == save_errno)
- return (uint4)(NO_FREE_SPACE);
- send_msg(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region), save_errno);
+ if (ENOSPC != save_errno)
+ send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region), save_errno);
return (uint4)(NO_FREE_SPACE);
}
+ if (WBTEST_ENABLED(WBTEST_FILE_EXTEND_INTERRUPT_1))
+ {
+ LONG_SLEEP(600);
+ assert(FALSE);
+ }
/* Ensure the EOF and metadata get to disk BEFORE any bitmap writes. Otherwise, the file size could no longer reflect
* a proper extent and subsequent invocations of gdsfilext could corrupt the database.
*/
- DEBUG_ONLY(
- if ((gtm_white_box_test_case_enabled) && (WBTEST_FILE_EXTEND_INTERRUPT_1 == gtm_white_box_test_case_number))
- {
- LONG_SLEEP(600);
- assert(FALSE); /* Should be killed before that */
- }
- )
GTM_DB_FSYNC(cs_addrs, udi->fd, status);
assert(0 == status);
if (0 != status)
{
GDSFILEXT_CLNUP;
- send_msg(VARLSTCNT(8) ERR_DBFILERR, 5, RTS_ERROR_LITERAL("fsync1()"), CALLFROM, status);
+ send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) ERR_DBFILERR, 5, RTS_ERROR_LITERAL("fsync1()"), CALLFROM, status);
return (uint4)(NO_FREE_SPACE);
}
- DEBUG_ONLY(
- if ((gtm_white_box_test_case_enabled) && (WBTEST_FILE_EXTEND_INTERRUPT_2 == gtm_white_box_test_case_number))
- {
- LONG_SLEEP(600);
- assert(FALSE); /* Should be killed before that */
- }
- )
-
+ if (WBTEST_ENABLED(WBTEST_FILE_EXTEND_INTERRUPT_2))
+ {
+ LONG_SLEEP(600);
+ assert(FALSE); /* Should be killed before that */
+ }
DEBUG_ONLY(prev_extend_blks_to_upgrd = cs_data->blks_to_upgrd;)
/* inctn_detail.blks_to_upgrd_delta holds the increase in "csd->blks_to_upgrd" due to the file extension */
inctn_detail.blks2upgrd_struct.blks_to_upgrd_delta =
@@ -385,7 +370,7 @@ uint4 gdsfilext (uint4 blocks, uint4 filesize)
jnl_status = jnl_flush(gv_cur_region);
if (SS_NORMAL != jnl_status)
{
- send_msg(VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(cs_data),
+ send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(cs_data),
ERR_TEXT, 2, RTS_ERROR_TEXT("Error with journal flush during gdsfilext"),
jnl_status);
assert(NOJNL == jpc->channel); /* jnl file lost has been triggered */
@@ -397,13 +382,13 @@ uint4 gdsfilext (uint4 blocks, uint4 filesize)
}
if (new_bit_maps)
{
- for (map = ROUND_UP(cs_data->trans_hist.total_blks, bplmap); map < new_total; map += bplmap)
+ for (map = ROUND_UP(old_total, bplmap); map < new_total; map += bplmap)
{
DEBUG_ONLY(new_bit_maps--;)
if (SS_NORMAL != (status = bml_init(map)))
{
GDSFILEXT_CLNUP;
- send_msg(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region), status);
+ send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region), status);
return (uint4)(NO_FREE_SPACE);
}
}
@@ -412,52 +397,30 @@ uint4 gdsfilext (uint4 blocks, uint4 filesize)
/* Ensures that if at all the file header write goes to disk before the crash, the bitmap blocks are all
* guaranteed to be initialized and synced to disk as well.
*/
- DEBUG_ONLY(
- if ((gtm_white_box_test_case_enabled) && (WBTEST_FILE_EXTEND_INTERRUPT_3 == gtm_white_box_test_case_number))
- {
- LONG_SLEEP(600);
- assert(FALSE); /* Should be killed before that */
- }
- )
-
+ if (WBTEST_ENABLED(WBTEST_FILE_EXTEND_INTERRUPT_3))
+ {
+ LONG_SLEEP(600);
+ assert(FALSE); /* Should be killed before that */
+ }
GTM_DB_FSYNC(cs_addrs, udi->fd, status);
assert(0 == status);
if (0 != status)
{
GDSFILEXT_CLNUP;
- send_msg(VARLSTCNT(8) ERR_DBFILERR, 5, RTS_ERROR_LITERAL("fsync2()"), CALLFROM, status);
+ send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) ERR_DBFILERR, 5, RTS_ERROR_LITERAL("fsync2()"), CALLFROM, status);
return (uint4)(NO_FREE_SPACE);
}
- DEBUG_ONLY(
- if ((gtm_white_box_test_case_enabled) && (WBTEST_FILE_EXTEND_INTERRUPT_4 == gtm_white_box_test_case_number))
- {
- LONG_SLEEP(600);
- assert(FALSE); /* Should be killed before that */
- }
- )
+ if (WBTEST_ENABLED(WBTEST_FILE_EXTEND_INTERRUPT_4))
+ {
+ LONG_SLEEP(600);
+ assert(FALSE); /* Should be killed before that */
+ }
assert(cs_data->blks_to_upgrd == (inctn_detail.blks2upgrd_struct.blks_to_upgrd_delta + prev_extend_blks_to_upgrd));
- if (dba_mm == cs_addrs->hdr->acc_meth)
- { /* On 32 bit aix, is it possible we can have now increased the file size past what we can map ? */
- mm_prot = cs_addrs->read_write ? (PROT_READ | PROT_WRITE) : PROT_READ;
- old_base[0] = cs_addrs->db_addrs[0];
- old_base[1] = cs_addrs->db_addrs[1];
- if (-1 == ((sm_long_t)(cs_addrs->db_addrs[0] = (sm_uc_ptr_t)mmap((caddr_t)NULL, (size_t)new_eof, mm_prot,
- GTM_MM_FLAGS, udi->fd, (off_t)0))))
- {
- GDSFILEXT_CLNUP;
- send_msg(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region), errno);
- return (uint4)(NO_FREE_SPACE);
- }
- free(cs_data); /* note current assumption that cs_data has not changed since memcpy above */
- /* In addition to updating the internal map values, gds_map_moved sets cs_data to point to the remapped file */
- gds_map_moved(cs_addrs->db_addrs[0], old_base[0], old_base[1], new_eof);
- cs_addrs->total_blks = new_total; /* Local copy to test if file has extended */
- }
assert(0 < (int)blocks);
assert(0 < (int)(cs_addrs->ti->free_blocks + blocks));
cs_addrs->ti->free_blocks += blocks;
- blocks = cs_data->trans_hist.total_blks;
- cs_addrs->ti->total_blks = new_total;
+ cs_addrs->total_blks = cs_addrs->ti->total_blks = new_total;
+ blocks = old_total;
if (blocks / bplmap * bplmap != blocks)
{
bit_set(blocks / bplmap, MM_ADDR(cs_data)); /* Mark old last local map as having space */
@@ -473,25 +436,43 @@ uint4 gdsfilext (uint4 blocks, uint4 filesize)
INCREMENT_CURR_TN(cs_data);
}
/* white box test for interrupted file extension */
- DEBUG_ONLY(
- if ((gtm_white_box_test_case_enabled) && (WBTEST_FILE_EXTEND_INTERRUPT_5 == gtm_white_box_test_case_number))
- {
- LONG_SLEEP(600);
- assert(FALSE); /* Should be killed before that */
- }
- )
+ if (WBTEST_ENABLED(WBTEST_FILE_EXTEND_INTERRUPT_5))
+ {
+ LONG_SLEEP(600);
+ assert(FALSE); /* Should be killed before that */
+ }
fileheader_sync(gv_cur_region);
/* white box test for interrupted file extension */
- DEBUG_ONLY(
- if ((gtm_white_box_test_case_enabled) && (WBTEST_FILE_EXTEND_INTERRUPT_6 == gtm_white_box_test_case_number))
+ if (WBTEST_ENABLED(WBTEST_FILE_EXTEND_INTERRUPT_6))
+ {
+ LONG_SLEEP(600);
+ assert(FALSE); /* Should be killed before that */
+ }
+ if (is_mm)
+ {
+ assert((NULL != old_base[0]) && (NULL != old_base[1]));
+ mmap_sz = new_eof - BLK_ZERO_OFF(cs_data); /* Don't mmap the file header and master map */
+ CHECK_LARGEFILE_MMAP(gv_cur_region, mmap_sz); /* can issue rts_error MMFILETOOLARGE */
+ status = (sm_long_t)(mmap_retaddr = (sm_uc_ptr_t)MMAP_FD(udi->fd, mmap_sz, BLK_ZERO_OFF(cs_data), FALSE));
+ GTM_WHITE_BOX_TEST(WBTEST_MMAP_SYSCALL_FAIL, status, -1);
+ if (-1 == status)
{
- LONG_SLEEP(600);
- assert(FALSE); /* Should be killed before that */
+ save_errno = errno;
+ WBTEST_ASSIGN_ONLY(WBTEST_MMAP_SYSCALL_FAIL, save_errno, ENOMEM);
+ GDSFILEXT_CLNUP;
+ send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(12) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region),
+ ERR_SYSCALL, 5, LEN_AND_LIT("mmap()"), CALLFROM, save_errno);
+ return (uint4)(NO_FREE_SPACE);
}
- )
+ /* In addition to updating the internal map values, gds_map_moved sets cs_data to point to the remapped file */
+ gds_map_moved(mmap_retaddr, old_base[0], old_base[1], mmap_sz); /* updates cs_addrs->db_addrs[1] */
+ cs_addrs->db_addrs[0] = mmap_retaddr;
+ assert(cs_addrs->db_addrs[0] < cs_addrs->db_addrs[1]);
+ }
GDSFILEXT_CLNUP;
INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_db_extends, 1);
if (!gtm_dbfilext_syslog_disable)
- send_msg(VARLSTCNT(7) ERR_DBFILEXT, 5, DB_LEN_STR(gv_cur_region), blocks, new_total, &curr_tn);
+ send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(7) ERR_DBFILEXT, 5, DB_LEN_STR(gv_cur_region), blocks, new_total,
+ &curr_tn);
return (SS_NORMAL);
}
diff --git a/sr_unix/generic_signal_handler.c b/sr_unix/generic_signal_handler.c
index 3bfaa42..9fbb3ed 100644
--- a/sr_unix/generic_signal_handler.c
+++ b/sr_unix/generic_signal_handler.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -26,6 +26,9 @@
#include "gtm_inet.h"
#include <signal.h>
+#ifdef GTM_PTHREAD
+# include <pthread.h>
+#endif
#include "gtm_stdio.h"
#include "error.h"
@@ -43,20 +46,20 @@
(exit_handler_active || !OK_TO_INTERRUPT))
/* Combine send_msg and gtm_putmsg into one macro to conserve space. */
-#define SEND_AND_PUT_MSG(PARAMS) \
-{ \
- send_msg PARAMS; \
- gtm_putmsg PARAMS; \
+#define SEND_AND_PUT_MSG(...) \
+{ \
+ if (OK_TO_SEND_MSG) \
+ send_msg_csa(CSA_ARG(NULL) __VA_ARGS__); \
+ gtm_putmsg_csa(CSA_ARG(NULL) __VA_ARGS__); \
}
/* These fields are defined as globals not because they are used globally but
* so they will be easily retrievable even in 'pro' cores.
*/
-GBLDEF siginfo_t exi_siginfo;
+GBLDEF siginfo_t exi_siginfo;
-GBLDEF gtm_sigcontext_t exi_context;
+GBLDEF gtm_sigcontext_t exi_context;
-GBLREF VSIG_ATOMIC_T forced_exit;
GBLREF int4 forced_exit_err;
GBLREF int4 exi_condition;
GBLREF boolean_t dont_want_core;
@@ -84,14 +87,12 @@ error_def(ERR_KRNLKILL);
void generic_signal_handler(int sig, siginfo_t *info, void *context)
{
- boolean_t exit_now;
gtm_sigcontext_t *context_ptr;
void (*signal_routine)();
- char *save_util_outptr;
- va_list save_last_va_list_ptr;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
+ FORWARD_SIG_TO_MAIN_THREAD_IF_NEEDED(sig);
/* Save parameter value in global variables for easy access in core */
dont_want_core = FALSE; /* (re)set in case we recurse */
created_core = FALSE; /* we can deal with a second core if needbe */
@@ -146,11 +147,11 @@ void generic_signal_handler(int sig, siginfo_t *info, void *context)
*/
if (DEFER_EXIT_PROCESSING)
{
- forced_exit = TRUE;
+ SET_FORCED_EXIT_STATE;
exit_state++; /* Make exit pending, may still be tolerant though */
assert(!IS_GTMSECSHR_IMAGE);
if (exit_handler_active && !gtm_quiet_halt)
- SEND_AND_PUT_MSG((VARLSTCNT(1) forced_exit_err));
+ SEND_AND_PUT_MSG(VARLSTCNT(1) forced_exit_err);
return;
}
exit_state = EXIT_IMMED;
@@ -158,11 +159,12 @@ void generic_signal_handler(int sig, siginfo_t *info, void *context)
* relies on this.
*/
if (ERR_FORCEDHALT != forced_exit_err || !gtm_quiet_halt)
- SEND_AND_PUT_MSG((VARLSTCNT(1) forced_exit_err));
+ SEND_AND_PUT_MSG(VARLSTCNT(1) forced_exit_err);
} else
{ /* Special case for gtmsecshr - no deferral just exit */
forced_exit_err = ERR_GTMSECSHRSHUTDN;
- send_msg(VARLSTCNT(1) forced_exit_err);
+ if (OK_TO_SEND_MSG)
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(1) forced_exit_err);
}
dont_want_core = TRUE;
break;
@@ -193,7 +195,7 @@ void generic_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 (DEFER_EXIT_PROCESSING)
{
- forced_exit = TRUE;
+ SET_FORCED_EXIT_STATE;
exit_state++; /* Make exit pending, may still be tolerant though */
assert(!IS_GTMSECSHR_IMAGE);
return;
@@ -203,24 +205,24 @@ void generic_signal_handler(int sig, siginfo_t *info, void *context)
switch(signal_info.infotype)
{
case GTMSIGINFO_NONE:
- SEND_AND_PUT_MSG((VARLSTCNT(6) ERR_KILLBYSIG, 4, GTMIMAGENAMETXT(image_type),
- process_id, sig));
+ SEND_AND_PUT_MSG(VARLSTCNT(6) ERR_KILLBYSIG, 4, GTMIMAGENAMETXT(image_type),
+ process_id, sig);
break;
case GTMSIGINFO_USER:
- SEND_AND_PUT_MSG((VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, GTMIMAGENAMETXT(image_type),
- process_id, sig, signal_info.send_pid, signal_info.send_uid));
+ SEND_AND_PUT_MSG(VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, GTMIMAGENAMETXT(image_type),
+ process_id, sig, signal_info.send_pid, signal_info.send_uid);
break;
case GTMSIGINFO_ILOC + GTMSIGINFO_BADR:
- SEND_AND_PUT_MSG((VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, GTMIMAGENAMETXT(image_type),
- process_id, sig, signal_info.int_iadr, signal_info.bad_vadr));
+ SEND_AND_PUT_MSG(VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, GTMIMAGENAMETXT(image_type),
+ process_id, sig, signal_info.int_iadr, signal_info.bad_vadr);
break;
case GTMSIGINFO_ILOC:
- SEND_AND_PUT_MSG((VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, GTMIMAGENAMETXT(image_type),
- process_id, sig, signal_info.int_iadr));
+ SEND_AND_PUT_MSG(VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, GTMIMAGENAMETXT(image_type),
+ process_id, sig, signal_info.int_iadr);
break;
case GTMSIGINFO_BADR:
- SEND_AND_PUT_MSG((VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, GTMIMAGENAMETXT(image_type),
- process_id, sig, signal_info.bad_vadr));
+ SEND_AND_PUT_MSG(VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, GTMIMAGENAMETXT(image_type),
+ process_id, sig, signal_info.bad_vadr);
break;
}
break;
@@ -230,14 +232,14 @@ void generic_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 (DEFER_EXIT_PROCESSING)
{
- forced_exit = TRUE;
+ SET_FORCED_EXIT_STATE;
exit_state++; /* Make exit pending, may still be tolerant though */
assert(!IS_GTMSECSHR_IMAGE);
return;
}
exit_state = EXIT_IMMED;
SET_PROCESS_EXITING_TRUE;
- SEND_AND_PUT_MSG((VARLSTCNT(1) forced_exit_err));
+ SEND_AND_PUT_MSG(VARLSTCNT(1) forced_exit_err);
dont_want_core = TRUE;
break;
# endif
@@ -248,8 +250,8 @@ void generic_signal_handler(int sig, siginfo_t *info, void *context)
case GTMSIGINFO_NONE:
exit_state = EXIT_IMMED;
SET_PROCESS_EXITING_TRUE;
- SEND_AND_PUT_MSG((VARLSTCNT(6) ERR_KILLBYSIG, 4, GTMIMAGENAMETXT(image_type),
- process_id, sig));
+ SEND_AND_PUT_MSG(VARLSTCNT(6) ERR_KILLBYSIG, 4, GTMIMAGENAMETXT(image_type),
+ process_id, sig);
break;
case GTMSIGINFO_USER:
/* This signal was SENT to us so it can wait until we are out of crit to cause an exit */
@@ -258,7 +260,7 @@ void generic_signal_handler(int sig, siginfo_t *info, void *context)
if (DEFER_EXIT_PROCESSING)
{
assert(!IS_GTMSECSHR_IMAGE);
- forced_exit = TRUE;
+ SET_FORCED_EXIT_STATE;
exit_state++; /* Make exit pending, may still be tolerant though */
need_core = TRUE;
gtm_fork_n_core(); /* Generate "virgin" core while we can */
@@ -266,26 +268,26 @@ void generic_signal_handler(int sig, siginfo_t *info, void *context)
}
exit_state = EXIT_IMMED;
SET_PROCESS_EXITING_TRUE;
- SEND_AND_PUT_MSG((VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, GTMIMAGENAMETXT(image_type),
- process_id, sig, signal_info.send_pid, signal_info.send_uid));
+ SEND_AND_PUT_MSG(VARLSTCNT(8) ERR_KILLBYSIGUINFO, 6, GTMIMAGENAMETXT(image_type),
+ process_id, sig, signal_info.send_pid, signal_info.send_uid);
break;
case GTMSIGINFO_ILOC + GTMSIGINFO_BADR:
exit_state = EXIT_IMMED;
SET_PROCESS_EXITING_TRUE;
- SEND_AND_PUT_MSG((VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, GTMIMAGENAMETXT(image_type),
- process_id, sig, signal_info.int_iadr, signal_info.bad_vadr));
+ SEND_AND_PUT_MSG(VARLSTCNT(8) ERR_KILLBYSIGSINFO1, 6, GTMIMAGENAMETXT(image_type),
+ process_id, sig, signal_info.int_iadr, signal_info.bad_vadr);
break;
case GTMSIGINFO_ILOC:
exit_state = EXIT_IMMED;
SET_PROCESS_EXITING_TRUE;
- SEND_AND_PUT_MSG((VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, GTMIMAGENAMETXT(image_type),
- process_id, sig, signal_info.int_iadr));
+ SEND_AND_PUT_MSG(VARLSTCNT(7) ERR_KILLBYSIGSINFO2, 5, GTMIMAGENAMETXT(image_type),
+ process_id, sig, signal_info.int_iadr);
break;
case GTMSIGINFO_BADR:
exit_state = EXIT_IMMED;
SET_PROCESS_EXITING_TRUE;
- SEND_AND_PUT_MSG((VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, GTMIMAGENAMETXT(image_type),
- process_id, sig, signal_info.bad_vadr));
+ SEND_AND_PUT_MSG(VARLSTCNT(7) ERR_KILLBYSIGSINFO3, 5, GTMIMAGENAMETXT(image_type),
+ process_id, sig, signal_info.bad_vadr);
break;
default:
exit_state = EXIT_IMMED;
@@ -294,7 +296,7 @@ void generic_signal_handler(int sig, siginfo_t *info, void *context)
}
if (0 != signal_info.sig_err)
{
- SEND_AND_PUT_MSG((VARLSTCNT(1) signal_info.sig_err));
+ SEND_AND_PUT_MSG(VARLSTCNT(1) signal_info.sig_err);
}
break;
} /* switch (sig) */
diff --git a/sr_unix/get_full_path.c b/sr_unix/get_full_path.c
index c2f9993..11781a6 100644
--- a/sr_unix/get_full_path.c
+++ b/sr_unix/get_full_path.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -19,10 +19,11 @@
#include "gdsroot.h"
#include "gdsbt.h"
+#include "have_crit.h"
error_def(ERR_FILENAMETOOLONG);
-/* gets the full path name for a given file name. Prepends the CWD, even if the file does not exist */
+/* Gets the full path name for a given file name. Prepends the CWD, even if the file does not exist. */
boolean_t get_full_path(char *orig_fn, unsigned int orig_len, char *full_fn, unsigned int *full_len, int max_len, uint4 *status)
{
char *cptr, *c1;
@@ -32,8 +33,7 @@ boolean_t get_full_path(char *orig_fn, unsigned int orig_len, char *full_fn, uns
char *getcwd_res;
if ('/' == *orig_fn)
- {
- /* The original path is already complete */
+ { /* The original path is already complete */
if (max_len < orig_len)
{
*status = ERR_FILENAMETOOLONG;
@@ -44,7 +44,8 @@ boolean_t get_full_path(char *orig_fn, unsigned int orig_len, char *full_fn, uns
memcpy(full_fn, orig_fn, length);
} else
{
- if (NULL == GETCWD(cwdbuf, SIZEOF(cwdbuf), getcwd_res))
+ GETCWD(cwdbuf, SIZEOF(cwdbuf), getcwd_res);
+ if (NULL == getcwd_res)
{
*status = errno;
return FALSE;
diff --git a/sr_unix/go_load.c b/sr_unix/go_load.c
index 7f27c57..d72e8e8 100644
--- a/sr_unix/go_load.c
+++ b/sr_unix/go_load.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -39,11 +39,12 @@
#include <rtnhdr.h>
#include "gv_trigger.h"
-GBLREF bool mupip_error_occurred;
-GBLREF bool mu_ctrly_occurred;
-GBLREF bool mu_ctrlc_occurred;
-GBLREF spdesc stringpool;
-GBLREF gv_key *gv_currkey;
+GBLREF bool mupip_error_occurred;
+GBLREF bool mu_ctrly_occurred;
+GBLREF bool mu_ctrlc_occurred;
+GBLREF spdesc stringpool;
+GBLREF gv_key *gv_currkey;
+GBLREF sgmnt_addrs *cs_addrs;
error_def(ERR_LOADCTRLY);
error_def(ERR_LOADEOF);
@@ -63,12 +64,11 @@ error_def(ERR_TRIGDATAIGNORE);
*/ \
if ((HASHT_GBL = IS_GVKEY_HASHT_FULL_GBLNAME(KEYLENGTH, PTR)) && !hasht_ignored) \
{ \
- gtm_putmsg(VARLSTCNT(4) ERR_TRIGDATAIGNORE, 2, KEYLENGTH, PTR); \
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TRIGDATAIGNORE, 2, KEYLENGTH, PTR); \
hasht_ignored = TRUE; \
} \
}
-static readonly unsigned char gt_lit[] = "LOAD TOTAL";
void go_call_db(int routine, char *parm1, int parm2, int val_off1, int val_len1);
void go_load(uint4 begin, uint4 end)
@@ -103,9 +103,9 @@ void go_load(uint4 begin, uint4 end)
if ((utf8_extract && !gtm_utf8_mode) || (!utf8_extract && gtm_utf8_mode))
{ /* extract CHSET doesn't match $ZCHSET */
if (utf8_extract)
- gtm_putmsg(VARLSTCNT(4) ERR_LOADINVCHSET, 2, LEN_AND_LIT("UTF-8"));
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_LOADINVCHSET, 2, LEN_AND_LIT("UTF-8"));
else
- gtm_putmsg(VARLSTCNT(4) ERR_LOADINVCHSET, 2, LEN_AND_LIT("M"));
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_LOADINVCHSET, 2, LEN_AND_LIT("M"));
mupip_error_occurred = TRUE;
free(rec_buff);
return;
@@ -131,7 +131,7 @@ void go_load(uint4 begin, uint4 end)
len = file_input_get(&ptr);
if (len < 0) /* The IO device has signalled an end of file */
{
- gtm_putmsg(VARLSTCNT(3) ERR_LOADEOF, 1, begin);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_LOADEOF, 1, begin);
mupip_error_occurred = TRUE;
}
if (mupip_error_occurred)
@@ -155,7 +155,7 @@ void go_load(uint4 begin, uint4 end)
if (mu_ctrlc_occurred)
{
util_out_print("!AD:!_ Key cnt: !UL max subsc len: !UL max data len: !UL", TRUE,
- LEN_AND_LIT(gt_lit), key_count, max_subsc_len, max_data_len);
+ 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);
mu_gvis();
util_out_print(0, TRUE);
@@ -287,7 +287,7 @@ void go_load(uint4 begin, uint4 end)
file_input_close();
if (mu_ctrly_occurred)
{
- gtm_putmsg(VARLSTCNT(1) ERR_LOADCTRLY);
+ 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,
diff --git a/sr_unix/golevel.c b/sr_unix/golevel.c
index 38194c5..74fa095 100644
--- a/sr_unix/golevel.c
+++ b/sr_unix/golevel.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2010, 2011 Fidelity Information Services, Inc *
+ * Copyright 2010, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -22,6 +22,9 @@
GBLREF stack_frame *frame_pointer;
+error_def(ERR_ZGOTOTOOBIG);
+error_def(ERR_ZGOTOLTZERO);
+
#ifdef GTM_TRIGGER
void golevel(int4 level, boolean_t unwtrigrframe)
#else
@@ -31,15 +34,12 @@ void golevel(int4 level)
stack_frame *fp, *fpprev;
int4 unwframes, unwlevels, prevlvl;
- error_def(ERR_ZGOTOTOOBIG);
- error_def(ERR_ZGOTOLTZERO);
-
if (0 > level)
- rts_error(VARLSTCNT(1) ERR_ZGOTOLTZERO);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZGOTOLTZERO);
unwlevels = dollar_zlevel() - level;
if (0 > unwlevels)
/* Couldn't get to the level we were trying to unwind to */
- rts_error(VARLSTCNT(1) ERR_ZGOTOTOOBIG);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZGOTOTOOBIG);
unwframes = 0;
for (fp = frame_pointer; NULL != fp; fp = fpprev)
{
@@ -60,7 +60,7 @@ void golevel(int4 level)
}
unwframes++;
if (SFT_TRIGR & fp->type)
- { /* Unwinding a trigger base frame leave a null frame_pointer so allow us to jump over the
+ { /* Unwinding a trigger base frame leaves a null frame_pointer so allow us to jump over the
* base frame to the rich stack beneath..
*/
assert(NULL == fpprev);
diff --git a/sr_unix/grab_crit_immediate.c b/sr_unix/grab_crit_immediate.c
new file mode 100644
index 0000000..4fb4d4e
--- /dev/null
+++ b/sr_unix/grab_crit_immediate.c
@@ -0,0 +1,108 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <signal.h> /* for VSIG_ATOMIC_T type */
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "gdsbgtr.h"
+#include "filestruct.h"
+#include "send_msg.h"
+#include "mutex.h"
+#include "deferred_signal_handler.h"
+#include "wcs_recover.h"
+#include "caller_id.h"
+#include "is_proc_alive.h"
+#include "gtmimagename.h"
+#include "error.h"
+
+GBLREF short crash_count;
+GBLREF volatile int4 crit_count;
+GBLREF uint4 process_id;
+GBLREF node_local_ptr_t locknl;
+GBLREF boolean_t mupip_jnl_recover;
+
+error_def(ERR_CRITRESET);
+error_def(ERR_DBCCERR);
+error_def(ERR_DBFLCORRP);
+
+boolean_t grab_crit_immediate(gd_region *reg)
+{
+ unix_db_info *udi;
+ sgmnt_addrs *csa;
+ sgmnt_data_ptr_t csd;
+ node_local_ptr_t cnl;
+ enum cdb_sc status;
+ mutex_spin_parms_ptr_t mutex_spin_parms;
+
+ udi = FILE_INFO(reg);
+ csa = &udi->s_addrs;
+ csd = csa->hdr;
+ cnl = csa->nl;
+ if (!csa->now_crit)
+ {
+ assert(0 == crit_count);
+ crit_count++; /* prevent interrupts */
+ DEBUG_ONLY(locknl = cnl;) /* for DEBUG_ONLY LOCK_HIST macro */
+ mutex_spin_parms = (mutex_spin_parms_ptr_t)&csd->mutex_spin_parms;
+ status = mutex_lockwim(reg, mutex_spin_parms, crash_count);
+ DEBUG_ONLY(locknl = NULL;) /* restore "locknl" to default value */
+ if (status != cdb_sc_normal)
+ {
+ crit_count = 0;
+ switch (status)
+ {
+ case cdb_sc_nolock:
+ return(FALSE);
+ case cdb_sc_critreset:
+ rts_error(VARLSTCNT(4) ERR_CRITRESET, 2, REG_LEN_STR(reg));
+ case cdb_sc_dbccerr:
+ rts_error(VARLSTCNT(4) ERR_DBCCERR, 2, REG_LEN_STR(reg));
+ default:
+ GTMASSERT;
+ }
+ return(FALSE);
+ }
+ /* There is only one case we know of when cnl->in_crit can be non-zero and that is when a process holding
+ * crit gets kill -9ed and another process ends up invoking "secshr_db_clnup" which in turn clears the
+ * crit semaphore (making it available for waiters) but does not also clear cnl->in_crit since it does not
+ * hold crit at that point. But in that case, the pid reported in cnl->in_crit should be dead. Check that.
+ */
+ assert((0 == cnl->in_crit) || (FALSE == is_proc_alive(cnl->in_crit, 0)));
+ cnl->in_crit = process_id;
+ CRIT_TRACE(crit_ops_gw); /* see gdsbt.h for comment on placement */
+ crit_count = 0;
+ }
+ else
+ assert(FALSE);
+ if (csd->file_corrupt && !mupip_jnl_recover)
+ {
+ if (!IS_DSE_IMAGE)
+ rts_error(VARLSTCNT(4) ERR_DBFLCORRP, 2, DB_LEN_STR(reg));
+ else
+ gtm_putmsg(VARLSTCNT(4) MAKE_MSG_WARNING(ERR_DBFLCORRP), 2, DB_LEN_STR(reg));
+ }
+ /* Ideally we do not want to do wcs_recover if we are in interrupt code (as opposed to mainline code).
+ * This is easily accomplished in VMS with a library function lib$ast_in_prog but in Unix there is no way
+ * to tell mainline code from interrupt code without the caller providing that information. Hence we
+ * currently do the cache recovery even in case of interrupt code even though it is a heavyweight operation.
+ * If it is found to cause issues, this logic has to be re-examined.
+ */
+ if (cnl->wc_blocked)
+ wcs_recover(reg);
+ return(TRUE);
+}
+
diff --git a/sr_unix/grab_lock.c b/sr_unix/grab_lock.c
index 401096c..22b8dba 100644
--- a/sr_unix/grab_lock.c
+++ b/sr_unix/grab_lock.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -49,14 +49,13 @@ error_def(ERR_TEXT);
* mutex_spin_parms_struct, and node_local in shared memory. Initialize the fields as in
* jnlpool_init(). Pass the address of the dummy region as argument to this function.
*/
-void grab_lock(gd_region *reg, uint4 onln_rlbk_action)
+boolean_t grab_lock(gd_region *reg, boolean_t is_blocking_wait, uint4 onln_rlbk_action)
{
unix_db_info *udi;
- sgmnt_addrs *csa;
+ sgmnt_addrs *csa;
enum cdb_sc status;
mutex_spin_parms_ptr_t mutex_spin_parms;
char scndry_msg[OUT_BUFF_SIZE];
-
# ifdef DEBUG
DCL_THREADGBL_ACCESS;
@@ -65,16 +64,20 @@ void grab_lock(gd_region *reg, uint4 onln_rlbk_action)
udi = FILE_INFO(reg);
csa = &udi->s_addrs;
assert(!csa->hold_onto_crit);
+ assert(!csa->now_crit);
if (!csa->now_crit)
{
assert(0 == crit_count);
crit_count++; /* prevent interrupts */
- DEBUG_ONLY(locknl = csa->nl;) /* for DEBUG_ONLY LOCK_HIST macro */
- mutex_spin_parms = (mutex_spin_parms_ptr_t)((sm_uc_ptr_t)csa->critical + CRIT_SPACE);
- /* This assumes that mutex_spin_parms_t is located immediately after the crit structures */
+ DEBUG_ONLY(locknl = csa->nl); /* for DEBUG_ONLY LOCK_HIST macro */
+ mutex_spin_parms = (mutex_spin_parms_ptr_t)((sm_uc_ptr_t)csa->critical + JNLPOOL_CRIT_SPACE);
+ /* This assumes that mutex_spin_parms_t is located immediately after the crit structures */
/* As of 10/07/98, crashcnt field in mutex_struct is not changed by any function for the dummy region */
- status = mutex_lockw(reg, mutex_spin_parms, 0);
- DEBUG_ONLY(locknl = NULL;) /* restore "locknl" to default value */
+ if (is_blocking_wait)
+ status = mutex_lockw(reg, mutex_spin_parms, 0);
+ else
+ status = mutex_lockwim(reg, mutex_spin_parms, 0);
+ DEBUG_ONLY(locknl = NULL); /* restore "locknl" to default value */
if (status != cdb_sc_normal)
{
crit_count = 0;
@@ -84,10 +87,12 @@ void grab_lock(gd_region *reg, uint4 onln_rlbk_action)
rts_error(VARLSTCNT(4) ERR_CRITRESET, 2, REG_LEN_STR(reg));
case cdb_sc_dbccerr:
rts_error(VARLSTCNT(4) ERR_DBCCERR, 2, REG_LEN_STR(reg));
+ case cdb_sc_nolock:
+ return FALSE;
default:
GTMASSERT;
}
- return;
+ return FALSE;
}
/* There is only one case we know of when csa->nl->in_crit can be non-zero and that is when a process holding
* crit gets kill -9ed and another process ends up invoking "secshr_db_clnup" which in turn clears the
@@ -98,39 +103,42 @@ void grab_lock(gd_region *reg, uint4 onln_rlbk_action)
csa->nl->in_crit = process_id;
CRIT_TRACE(crit_ops_gw); /* see gdsbt.h for comment on placement */
crit_count = 0;
- }
- if (jnlpool.repl_inst_filehdr->file_corrupt && !jgbl.onlnrlbk)
- { /* Journal pool indicates an abnormally terminated online rollback. Cannot continue until the rollback command is
- * re-run to bring the journal pool/file and instance file to a consistent state.
+ if (jnlpool.repl_inst_filehdr->file_corrupt && !jgbl.onlnrlbk)
+ { /* Journal pool indicates an abnormally terminated online rollback. Cannot continue until the rollback
+ * command is re-run to bring the journal pool/file and instance file to a consistent state.
+ */
+ SNPRINTF(scndry_msg, OUT_BUFF_SIZE, "Instance file header has file_corrupt field set to TRUE");
+ /* No need to do rel_lock before rts_error (mupip_exit_handler will do it for us) */
+ rts_error(VARLSTCNT(8) ERR_REPLREQROLLBACK, 2, LEN_AND_STR(udi->fn), ERR_TEXT, 2, LEN_AND_STR(scndry_msg));
+ }
+ /* If ASSERT_NO_ONLINE_ROLLBACK, then no concurrent online rollbacks can happen at this point. So, the jnlpool
+ * should be in in sync. There are two exceptions. If this is GT.CM GNP Server and the last client disconnected, the
+ * server invokes gtcmd_rundown which in-turn invokes gds_rundown thereby running down all active databases at this
+ * point but leaves the journal pool up and running. Now, if an online rollback is attempted, it increments the
+ * onln_rlbk_cycle in the journal pool, but csa->onln_rlbk_cycle is not synced yet. So, the grab_crit done in t_end
+ * will NOT detect a concurrent online rollback and it doesn't need to because the rollback happened AFTER the
+ * rundown. Assert that this is the only case we know of for the cycles to be out-of-sync. In PRO
+ * jnlpool_ctl->onln_rlbk_cycle is used only by the replication servers (which GT.CM is not) and so even if it
+ * continues with an out-of-sync csa->onln_rlbk_cycle, t_end logic does the right thing. The other exception is if
+ * GT.M initialized journal pool while opening database (belonging to a different instance) in gvcst_init (for
+ * anticipatory freeze) followed by an online rollback which increments the jnlpool_ctl->onln_rlbk_cycle but leaves
+ * the repl_csa->onln_rlbk_cycle out-of-sync. At this point, if a replicated database is open for the first time,
+ * we'll reach t_end to commit the update but will end up failing the below assert due to the out-of-sync
+ * onln_rlbk_cycle. So, assert accordingly. Note : even though the cycles are out-of-sync they are not an issue for
+ * GT.M because it always relies on the onln_rlbk_cycle from csa->nl and not from repl_csa. But, we don't remove the
+ * assert as it is valuable for replication servers (Source, Receiver and Update Process).
*/
- SNPRINTF(scndry_msg, OUT_BUFF_SIZE, "Instance file header has file_corrupt field set to TRUE");
- /* No need to do rel_lock before rts_error (mupip_exit_handler will do it for us) */
- rts_error(VARLSTCNT(8) ERR_REPLREQROLLBACK, 2, LEN_AND_STR(udi->fn), ERR_TEXT, 2, LEN_AND_STR(scndry_msg));
- }
- /* If ASSERT_NO_ONLINE_ROLLBACK, then no concurrent online rollbacks can happen at this point. So, the jnlpool should be in
- * in sync. There are two exceptions. If this is GT.CM GNP Server and the last client disconnected, the server invokes
- * gtcmd_rundown which in-turn invokes gds_rundown thereby running down all active databases at this point but leaves the
- * journal pool up and running. Now, if an online rollback is attempted, it increments the onln_rlbk_cycle in the journal
- * pool, but csa->onln_rlbk_cycle is not synced yet. So, the grab_crit done in t_end will NOT detect a concurrent online
- * rollback and it doesn't need to because the rollback happened AFTER the rundown. Assert that this is the only case we
- * know of for the cycles to be out-of-sync. In PRO jnlpool_ctl->onln_rlbk_cycle is used only by the replication servers
- * (which GT.CM is not) and so even if it continues with an out-of-sync csa->onln_rlbk_cycle, t_end logic does the right
- * thing. The other exception is if GT.M initialized journal pool while opening database (belonging to a different
- * instance) in gvcst_init (for anticipatory freeze) followed by an online rollback which increments the
- * jnlpool_ctl->onln_rlbk_cycle but leaves the repl_csa->onln_rlbk_cycle out-of-sync. At this point, if a replicated
- * database is open for the first time, we'll reach t_end to commit the update but will end up failing the below assert due
- * to the out-of-sync onln_rlbk_cycle. So, assert accordingly. Note : even though the cycles are out-of-sync they are not
- * an issue for GT.M because it always relies on the onln_rlbk_cycle from csa->nl and not from repl_csa. But, we don't
- * remove the assert as it is valuable for replication servers (Source, Receiver and Update Process).
- */
- assert((ASSERT_NO_ONLINE_ROLLBACK != onln_rlbk_action) || (csa->onln_rlbk_cycle == jnlpool.jnlpool_ctl->onln_rlbk_cycle)
- || IS_GTCM_GNP_SERVER_IMAGE || (jnlpool_init_needed && ANTICIPATORY_FREEZE_AVAILABLE));
- if ((HANDLE_CONCUR_ONLINE_ROLLBACK == onln_rlbk_action) && (csa->onln_rlbk_cycle != jnlpool.jnlpool_ctl->onln_rlbk_cycle))
- {
- assert(is_src_server);
- SYNC_ONLN_RLBK_CYCLES;
- gtmsource_onln_rlbk_clnup(); /* side-effect : sets gtmsource_state */
- rel_lock(reg); /* caller knows to disconnect and re-establish the connection */
+ assert((ASSERT_NO_ONLINE_ROLLBACK != onln_rlbk_action)
+ || (csa->onln_rlbk_cycle == jnlpool.jnlpool_ctl->onln_rlbk_cycle) || IS_GTCM_GNP_SERVER_IMAGE
+ || (jnlpool_init_needed && ANTICIPATORY_FREEZE_AVAILABLE));
+ if ((HANDLE_CONCUR_ONLINE_ROLLBACK == onln_rlbk_action)
+ && (csa->onln_rlbk_cycle != jnlpool.jnlpool_ctl->onln_rlbk_cycle))
+ {
+ assert(is_src_server);
+ SYNC_ONLN_RLBK_CYCLES;
+ gtmsource_onln_rlbk_clnup(); /* side-effect : sets gtmsource_state */
+ rel_lock(reg); /* caller knows to disconnect and re-establish the connection */
+ }
}
- return;
+ return TRUE;
}
diff --git a/sr_unix/gt_as.csh b/sr_unix/gt_as.csh
index a4a3bc0..61b8940 100644
--- a/sr_unix/gt_as.csh
+++ b/sr_unix/gt_as.csh
@@ -1,6 +1,6 @@
#################################################################
# #
-# Copyright 2001, 2009 Fidelity Information Services, Inc #
+# Copyright 2001, 2013 Fidelity Information Services, Inc #
# #
# This source code contains the intellectual property #
# of its copyright holder(s), and is made available #
@@ -34,23 +34,53 @@ endif
alias gt_as_local "$comlist_gt_as"
-set platform_name = `uname | sed 's/-//g' | sed 's,/,,' | tr '[A-Z]' '[a-z]'`
+set os = `uname`
+set platform_name = ${os:gs/-//:s,/,,:al}
set mach_type = `uname -m`
-if ( "ia64" == $mach_type && "linux" == $platform_name ) then
- set lfile = `basename $1`:r
- set file = $lfile:r
+set asmlist=($*)
+set cmdfile="$gtm_log/gt_as_$$__batch.csh"
+set background="&"
+if ($HOST:r:r:r =~ {snail,turtle,lespaul,pfloyd,strato}) set background=""
- gt_cpp -E $1 > ${gtm_obj}/${file}_cpp.s
- gt_as_local ${gtm_obj}/${file}_cpp.s -o ${gtm_obj}/${file}.o
- \rm ${gtm_obj}/${file}_cpp.s
-else if ( "os390" == $platform_name ) then
- set file = `basename $1`
- set file = $file:r
+echo 'alias gt_as_local "$comlist_gt_as"' >> $cmdfile
- gt_as_local $1
- if ( -e $gtm_obj/${file}.dbg ) chmod ugo+r $gtm_obj/${file}.dbg
+foreach asm ($asmlist)
+ set outfile="$gtm_log/gt_as_$$_${asm:t:r}.out"
+ set redir=">& $outfile"
+ if ( "ia64" == $mach_type && "linux" == $platform_name ) then
+ set file=$asm:t:r:r
+ set sfile="${gtm_obj}/${file}_cpp.s"
+ set ofile="${gtm_obj}/${file}.o"
+ echo "(eval 'gt_cpp -E $asm' > $sfile ; eval 'gt_as_local $sfile -o $ofile' ; /bin/rm $sfile)" \
+ "$redir $background" >> $cmdfile
+ else if ( "os390" == $platform_name ) then
+ set file=$asm:t:r
+ set dbgfile="${gtm_obj}/${file}.dbg"
+ echo "(eval 'gt_as_local $asm' ; if ( -e $dbgfile ) chmod ugo+r $dbgfile) $redir $background" >> $cmdfile
+ else
+ echo "eval 'gt_as_local $asm' $redir $background" >> $cmdfile
+ endif
+end
+
+echo "wait" >> $cmdfile
+
+set cmdout="$gtm_log/gt_as_$$__batch.out"
+source $cmdfile >& $cmdout
+
+set stat=$status
+
+foreach asm ($asmlist)
+ set outfile="$gtm_log/gt_as_$$_${asm:t:r}.out"
+ /bin/cat $outfile
+ /bin/rm $outfile
+end
+
+if ($stat) then
+ /bin/cat $cmdout
else
- gt_as_local $1
+ /bin/rm $cmdfile
+ /bin/rm $cmdout
endif
+exit 0
diff --git a/sr_unix/gt_cc.csh b/sr_unix/gt_cc.csh
index 025d4aa..ac730bd 100644
--- a/sr_unix/gt_cc.csh
+++ b/sr_unix/gt_cc.csh
@@ -1,6 +1,6 @@
#################################################################
# #
-# Copyright 2001, 2012 Fidelity Information Services, Inc #
+# Copyright 2001, 2013 Fidelity Information Services, Inc #
# #
# This source code contains the intellectual property #
# of its copyright holder(s), and is made available #
@@ -31,36 +31,39 @@ if ( $?comlist_gt_cc == "0" ) then
exit 1
endif
-# Bourne shell is less verbose about background processes, so use that.
+alias gt_cc_local "comlist_gt_cc"
-# However, comlist_gt_cc is generally an alias, which we can't pass to the Bourne shell,
-# so expand it repeatedly until it isn't an alias anymore.
-# Assumes aliases expand as basic commands.
+set cfilelist=($*)
+set cmdfile="$gtm_log/gt_cc_$$__batch.csh"
+set background="&"
+if ($HOST:r:r:r =~ {snail,turtle}) set background=""
-set comlist_gt_cc=($comlist_gt_cc)
+echo 'alias gt_cc_local "$comlist_gt_cc"' >> $cmdfile
-while(`alias $comlist_gt_cc[1]` != "")
- set comlist_gt_cc= ( `alias $comlist_gt_cc[1]` $comlist_gt_cc[2-$#comlist_gt_cc] )
+foreach cfile ($cfilelist)
+ set outfile="$gtm_log/gt_cc_$$_${cfile:t:r}.out"
+ set redir=">& $outfile"
+ echo "(echo $cfile ; eval 'gt_cc_local $cfile') $redir $background" >> $cmdfile
end
-/bin/sh <<ENDSH
-files="$*"
+echo "wait" >> $cmdfile
-for i in \$files
-do
- outfile="$gtm_log/gt_cc_local_$$_\`basename \$i\`.out"
- echo \$i > \$outfile
- $comlist_gt_cc \$i >> \$outfile 2>&1 &
-done
+set cmdout="$gtm_log/gt_cc_$$__batch.out"
+source $cmdfile >& $cmdout
-wait
+set stat=$status
-for i in \$files
-do
- outfile="$gtm_log/gt_cc_local_$$_\`basename \$i\`.out"
- /bin/cat \$outfile
- /bin/rm \$outfile
-done
-ENDSH
+foreach cfile ($cfilelist)
+ set outfile="$gtm_log/gt_cc_$$_${cfile:t:r}.out"
+ /bin/cat $outfile
+ /bin/rm $outfile
+end
+
+if ($stat) then
+ /bin/cat $cmdout
+else
+ /bin/rm $cmdfile
+ /bin/rm $cmdout
+endif
exit 0
diff --git a/sr_unix/gt_timer.h b/sr_unix/gt_timer.h
index c697379..29bb4ee 100644
--- a/sr_unix/gt_timer.h
+++ b/sr_unix/gt_timer.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -86,12 +86,20 @@ typedef struct st_timer_alloc
#define MAX_TIMER_HNDLRS 10 /* Max # of safe timer handlers */
#define GT_WAKE
+/* 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)
+ */
+#define SLACKTIME 10
+
int4 abs_time_comp(ABS_TIME *atp1, ABS_TIME *atp2);
void add_int_to_abs_time(ABS_TIME *atps, int4 ival, ABS_TIME *atpd);
void cancel_timer(TID tid);
void clear_timers(void);
void hiber_start(uint4 hiber);
void hiber_start_wait_any(uint4 hiber);
+void gtm_start_timer(TID tid, int4 time_to_expir, void(* handler)(), int4 data_length, void *handler_data);
void start_timer(TID tid, int4 time_to_expir, void(* handler)(), int4 data_length, void *handler_data);
ABS_TIME sub_abs_time(ABS_TIME *atp1, ABS_TIME *atp2);
void sys_get_curr_time(ABS_TIME *atp);
@@ -105,12 +113,14 @@ void sys_canc_timer(void);
STATICFNDCL void hiber_wake(TID tid, int4 hd_len, int4 **waitover_flag);
STATICFNDCL void gt_timers_alloc(void);
-STATICFNDCL void start_timer_int(TID tid, int4 time_to_expir, void (*handler)(), int4 hdata_len, void *hdata);
+STATICFNDCL void start_timer_int(TID tid, int4 time_to_expir, void (*handler)(), int4 hdata_len,
+ void *hdata, boolean_t safe_timer);
STATICFNDCL void sys_settimer (TID tid, ABS_TIME *time_to_expir, void (*handler)());
STATICFNDCL void start_first_timer(ABS_TIME *curr_time);
STATICFNDCL void timer_handler(int why);
STATICFNDCL GT_TIMER *find_timer(TID tid, GT_TIMER **tprev);
-STATICFNDCL void add_timer(ABS_TIME *atp, TID tid, int4 time_to_expir, void (*handler)(), int4 hdata_len, void *hdata);
+STATICFNDCL void add_timer(ABS_TIME *atp, TID tid, int4 time_to_expir, void (*handler)(), int4 hdata_len,
+ void *hdata, boolean_t safe_timer);
STATICFNDCL void remove_timer(TID tid);
STATICFNDCL void uninit_all_timers(void);
STATICFNDCL void cancel_all_timers(void);
diff --git a/sr_unix/gt_timers.c b/sr_unix/gt_timers.c
index 3d6b514..123e9d7 100644
--- a/sr_unix/gt_timers.c
+++ b/sr_unix/gt_timers.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -45,6 +45,10 @@
#include <errno.h>
#include <stddef.h>
#include <stdarg.h>
+#ifdef GTM_PTHREAD
+# include <pthread.h>
+#endif
+#include <signal.h>
#include "gtm_time.h"
#include "gtm_string.h"
#include "gtmimagename.h"
@@ -71,6 +75,7 @@
#include "gtmio.h"
#include "have_crit.h"
#include "util.h"
+#include "sleep.h"
#if defined(__osf__)
# define HZ CLK_TCK
#elif defined(__MVS__)
@@ -88,18 +93,10 @@ int4 time();
# endif
#endif
-/* 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)
- */
-#ifndef SLACKTIME
-# define SLACKTIME 10
-#endif
-
#define TIMER_BLOCK_SIZE 64 /* # of timer entries allocated initially as well as at every expansion */
#define GT_TIMER_EXPAND_TRIGGER 8 /* if the # of timer entries in the free queue goes below this, allocate more */
#define GT_TIMER_INIT_DATA_LEN 8
+#define MAX_TIMER_POP_TRACE_SZ 32
#define ADD_SAFE_HNDLR(HNDLR) \
{ \
@@ -132,13 +129,16 @@ STATICDEF int safe_handlers_cnt;
STATICDEF boolean_t stolen_timer = FALSE; /* only complain once, used in check_for_timer_pops() */
STATICDEF char *whenstolen[] = {"check_for_timer_pops", "check_for_timer_pops first time"}; /* for check_for_timer_pops */
-GBLREF boolean_t blocksig_initialized; /* set to TRUE when blockalrm, block_ttinout and block_sigsent are initialized */
-GBLREF sigset_t blockalrm;
-GBLREF sigset_t block_ttinout;
-GBLREF sigset_t block_sigsent;
-GBLREF boolean_t heartbeat_started;
-GBLREF void (*heartbeat_timer_ptr)(void); /* Initialized only in gtm_startup() */
-GBLREF int4 error_condition;
+#ifdef DEBUG
+STATICDEF int trc_timerpop_idx;
+STATICDEF GT_TIMER trc_timerpop_array[MAX_TIMER_POP_TRACE_SZ];
+
+# define TRACE_TIMER_POP(TIMER_INFO) \
+{ \
+ memcpy(&trc_timerpop_array[trc_timerpop_idx], TIMER_INFO, SIZEOF(GT_TIMER)); \
+ trc_timerpop_idx = (trc_timerpop_idx + 1) % MAX_TIMER_POP_TRACE_SZ; \
+}
+#endif
/* Flag signifying timer is active. Especially useful when the timer handlers get nested. This has not been moved to a
* threaded framework because we do not know how timers will be used with threads.
@@ -146,12 +146,22 @@ GBLREF int4 error_condition;
GBLDEF volatile boolean_t timer_active = FALSE;
GBLDEF volatile int4 timer_stack_count = 0;
GBLDEF volatile boolean_t timer_in_handler = FALSE;
-GBLREF int4 outofband;
-GBLREF int process_exiting;
-GBLDEF void (*wcs_clean_dbsync_fptr)(); /* Reference to wcs_clean_dbsync() to be used * in gt_timers.c */
-GBLDEF void (*wcs_stale_fptr)(); /* Reference to wcs_stale() to be used in gt_timers.c */
+GBLDEF void (*wcs_clean_dbsync_fptr)(); /* Reference to wcs_clean_dbsync() to be used in gt_timers.c. */
+GBLDEF void (*wcs_stale_fptr)(); /* Reference to wcs_stale() to be used in gt_timers.c. */
GBLDEF boolean_t deferred_timers_check_needed; /* Indicator whether check_for_deferred_timers() should be called
- upon leaving deferred zone */
+ * upon leaving deferred zone. */
+
+GBLREF boolean_t blocksig_initialized; /* Set to TRUE when blockalrm, block_ttinout, and block_sigsent are
+ * initialized. */
+GBLREF sigset_t blockalrm;
+GBLREF sigset_t block_ttinout;
+GBLREF sigset_t block_sigsent;
+GBLREF boolean_t heartbeat_started;
+GBLREF void (*heartbeat_timer_ptr)(void); /* Initialized only in gtm_startup(). */
+GBLREF int4 error_condition;
+GBLREF int4 outofband;
+GBLREF int process_exiting;
+
error_def(ERR_TIMERHANDLER);
/* Called when a hiber_start timer pops. Set flag so a given timer will wake up (not go back to sleep). */
@@ -253,18 +263,18 @@ void prealloc_gt_timers(void)
* First step, fill in the safe timers contained within this module which are always available.
*/
ADD_SAFE_HNDLR(&hiber_wake); /* Resident in this module */
+ ADD_SAFE_HNDLR(&hiber_start_wait_any); /* Resident in this module */
ADD_SAFE_HNDLR(&wake_alarm); /* Standalone module containing on one global reference */
}
/* Get current clock time. Fill-in the structure with the absolute time of system clock.
* Arguments: atp - pointer to structure of absolute time
*/
-void sys_get_curr_time (ABS_TIME *atp)
+void sys_get_curr_time(ABS_TIME *atp)
{
# ifdef BSD_TIMER
struct timeval tv;
struct timezone tz;
- struct tm *dtp;
/* getclock or clock_gettime perhaps to avoid tz just to ignore */
gettimeofday(&tv, &tz);
@@ -277,29 +287,42 @@ void sys_get_curr_time (ABS_TIME *atp)
}
/* Start hibernating by starting a timer and waiting for it. */
-void hiber_start (uint4 hiber)
+void hiber_start(uint4 hiber)
{
int4 waitover;
int4 *waitover_addr;
TID tid;
sigset_t savemask;
- assertpro(1 > timer_stack_count); /* timer services are unavailable from within a timer handler */
+ assertpro(1 > timer_stack_count); /* timer services are unavailable from within a timer handler */
sigprocmask(SIG_BLOCK, &blockalrm, &savemask); /* block SIGALRM signal */
- waitover = FALSE; /* when OUR timer pops, it will set this flag */
- waitover_addr = &waitover;
- tid = (TID)waitover_addr; /* unique id of this timer */
- start_timer_int((TID)tid, hiber, hiber_wake, SIZEOF(waitover_addr), &waitover_addr);
- /* we will loop here until OUR timer pops and sets OUR flag */
- do
+ /* sigsuspend() sets the signal mask to 'savemask' and waits for an ALARM signal. If the SIGALRM is a member of savemask,
+ * this process will never receive SIGALRM, and it will hang indefinitely. One such scenario would be if we interrupted a
+ * timer handler with kill -15, thus getting all timer setup reset by generic_signal_handler, and the gtm_exit_handler
+ * ended up invoking hiber_start (when starting gtmsecshr server, for instance). In such situations rely on something other
+ * than GT.M timers.
+ */
+ if (sigismember(&savemask, SIGALRM))
+ {
+ NANOSLEEP(hiber);
+ } else
{
- sigsuspend(&savemask); /* unblock SIGALRM and wait for timer interrupt */
- if (outofband)
+ waitover = FALSE; /* when OUR timer pops, it will set this flag */
+ waitover_addr = &waitover;
+ tid = (TID)waitover_addr; /* unique id of this timer */
+ start_timer_int((TID)tid, hiber, hiber_wake, SIZEOF(waitover_addr), &waitover_addr, TRUE);
+ /* we will loop here until OUR timer pops and sets OUR flag */
+ do
{
- cancel_timer(tid);
- break;
- }
- } while(FALSE == waitover);
+ assert(!sigismember(&savemask, SIGALRM));
+ sigsuspend(&savemask); /* unblock SIGALRM and wait for timer interrupt */
+ if (outofband)
+ {
+ cancel_timer(tid);
+ break;
+ }
+ } while(FALSE == waitover);
+ }
sigprocmask(SIG_SETMASK, &savemask, NULL); /* reset signal handlers */
}
@@ -315,12 +338,41 @@ void hiber_start_wait_any(uint4 hiber)
}
assertpro(1 > timer_stack_count); /* timer services are unavailable from within a timer handler */
sigprocmask(SIG_BLOCK, &blockalrm, &savemask); /* block SIGALRM signal and set new timer */
- start_timer_int((TID)hiber_start_wait_any, hiber, NULL, 0, NULL);
- sigsuspend(&savemask); /* unblock SIGALRM and wait for timer interrupt */
+ /* 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
+ * 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.
+ */
+ assert(!sigismember(&savemask, SIGALRM));
+ start_timer_int((TID)hiber_start_wait_any, hiber, NULL, 0, NULL, TRUE);
+ sigsuspend(&savemask); /* unblock SIGALRM and wait for timer interrupt */
cancel_timer((TID)hiber_start_wait_any); /* cancel timer block before reenabling */
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.
+ * Arguments: tid - timer id
+ * time_to_expir - time to expiration in msecs
+ * handler - pointer to handler routine
+ * hdata_len - length of handler data next arg
+ * hdata - data to pass to handler (if any)
+ */
+void gtm_start_timer(TID tid,
+ int4 time_to_expir,
+ void (*handler)(),
+ int4 hdata_len,
+ void *hdata)
+{
+ if (0 >= time_to_expir)
+ time_to_expir = SLACKTIME;
+ start_timer(tid, time_to_expir, handler, hdata_len, hdata);
+}
+
/* Start the timer. If timer chain is empty or this is the first timer to expire, actually start the system timer.
* Arguments: tid - timer id
* time_to_expir - time to expiration in msecs
@@ -334,18 +386,41 @@ void start_timer(TID tid,
int4 hdata_len,
void *hdata)
{
- sigset_t savemask;
+ sigset_t savemask;
+ boolean_t safe_timer = FALSE, safe_to_add = FALSE;
+ int i;
assertpro(0 < time_to_expir); /* Callers should verify non-zero time */
+ if (NULL == handler)
+ {
+ safe_to_add = TRUE;
+ safe_timer = TRUE;
+ } else if ((wcs_clean_dbsync_fptr == handler) || (wcs_stale_fptr == handler))
+ safe_to_add = TRUE;
+ else
+ {
+ for (i = 0; NULL != safe_handlers[i]; i++)
+ if (safe_handlers[i] == handler)
+ {
+ safe_to_add = TRUE;
+ safe_timer = TRUE;
+ break;
+ }
+ }
+ if (!safe_to_add && (process_exiting || (INTRPT_OK_TO_INTERRUPT != intrpt_ok_state)))
+ {
+ assert(WBTEST_ENABLED(WBTEST_RECOVER_ENOSPC));
+ return;
+ }
sigprocmask(SIG_BLOCK, &blockalrm, &savemask); /* block SIGALRM signal */
- start_timer_int(tid, time_to_expir, handler, hdata_len, hdata);
+ start_timer_int(tid, time_to_expir, handler, hdata_len, hdata, safe_timer);
sigprocmask(SIG_SETMASK, &savemask, NULL); /* reset signal handlers */
}
/* Internal version of start_timer that does not protect itself, assuming this has already been done.
* Otherwise does as explained above in start_timer.
*/
-STATICFNDEF void start_timer_int(TID tid, int4 time_to_expir, void (*handler)(), int4 hdata_len, void *hdata)
+STATICFNDEF void start_timer_int(TID tid, int4 time_to_expir, void (*handler)(), int4 hdata_len, void *hdata, boolean_t safe_timer)
{
ABS_TIME at;
@@ -368,7 +443,7 @@ 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();
- add_timer(&at, tid, time_to_expir, handler, hdata_len, hdata); /* Link new timer into timer chain */
+ add_timer(&at, tid, time_to_expir, handler, hdata_len, hdata, safe_timer); /* Put new timer in the queue. */
if ((timeroot->tid == tid) || !timer_active)
start_first_timer(&at);
}
@@ -532,7 +607,6 @@ STATICFNDEF void timer_handler(int why)
int4 cmp, save_error_condition;
GT_TIMER *tpop, *tpop_prev = NULL;
ABS_TIME at;
- sigset_t savemask;
int save_errno, timer_defer_cnt, offset;
TID *deferred_tid;
boolean_t tid_found;
@@ -542,6 +616,12 @@ STATICFNDEF void timer_handler(int why)
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
+ 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.
+ */
+ FORWARD_SIG_TO_MAIN_THREAD_IF_NEEDED(SIGALRM);
+ }
# ifdef DEBUG
if (IS_GTM_IMAGE)
{
@@ -568,7 +648,7 @@ STATICFNDEF void timer_handler(int why)
/* A timer might pop while we are in the non-zero intrpt_ok_state zone, which could cause collisions. Instead,
* we will defer timer events and drive them once the deferral is removed, unless the timer is safe.
*/
- if ((INTRPT_OK_TO_INTERRUPT == intrpt_ok_state) && (FALSE == process_exiting) || tpop->safe)
+ if (((INTRPT_OK_TO_INTERRUPT == intrpt_ok_state) && (FALSE == process_exiting)) || (tpop->safe))
{
if (NULL != tpop_prev)
tpop_prev->next = tpop->next;
@@ -595,6 +675,7 @@ STATICFNDEF void timer_handler(int why)
timer_in_handler = FALSE;
if (!tpop->safe) /* if safe, avoid a system call */
sys_get_curr_time(&at); /* refresh current time if called a handler */
+ DEBUG_ONLY(TRACE_TIMER_POP(tpop));
}
tpop->next = (GT_TIMER *)timefree; /* put timer block on the free chain */
timefree = tpop;
@@ -693,13 +774,14 @@ STATICFNDEF GT_TIMER *find_timer(TID tid, GT_TIMER **tprev)
* handler - pointer to handler routine
* hdata_len - length of data to follow
* hdata - data to pass to timer rtn if any
+ * safe_timer - timer's handler is in safe_handlers array
*/
-STATICFNDEF void add_timer(ABS_TIME *atp, TID tid, int4 time_to_expir, void (*handler)(), int4 hdata_len, void *hdata)
+STATICFNDEF void add_timer(ABS_TIME *atp, TID tid, int4 time_to_expir, void (*handler)(), int4 hdata_len,
+ void *hdata, boolean_t safe_timer)
{
GT_TIMER *tp, *tpp, *ntp, *lastntp;
int4 cmp, i;
st_timer_alloc *new_alloc;
- boolean_t safe_to_add = FALSE;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
@@ -740,26 +822,13 @@ STATICFNDEF void add_timer(ABS_TIME *atp, TID tid, int4 time_to_expir, void (*ha
}
ntp->tid = tid;
ntp->handler = handler;
- ntp->safe = FALSE;
- if (NULL == handler)
+ if (safe_timer)
{
ntp->safe = TRUE;
safe_timer_cnt++;
assert(0 < safe_timer_cnt);
} else
- {
- for (i = 0; NULL != safe_handlers[i]; i++)
- if (safe_handlers[i] == handler)
- {
- ntp->safe = TRUE; /* known to just set flags, etc. */
- safe_timer_cnt++;
- break;
- }
- }
- if (ntp->safe || (wcs_clean_dbsync_fptr == handler) || (wcs_stale_fptr == handler))
- safe_to_add = TRUE;
- assertpro((INTRPT_OK_TO_INTERRUPT == intrpt_ok_state) || safe_to_add);
- assertpro(!process_exiting || safe_to_add);
+ ntp->safe = FALSE;
ntp->hd_len = hdata_len;
if (0 < hdata_len)
memcpy(ntp->hd_data, hdata, hdata_len);
@@ -791,7 +860,7 @@ STATICFNDEF void remove_timer(TID tid)
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
- if (tp = find_timer(tid, &tprev))
+ if (tp = find_timer(tid, &tprev)) /* Warning: assignment */
{
if (tprev)
tprev->next = tp->next;
@@ -870,9 +939,9 @@ STATICFNDEF void init_timers()
(SIG_IGN != prev_alrm_handler.sa_handler) && /* as set by sig_init */
(SIG_DFL != prev_alrm_handler.sa_handler)) /* utils, compile */
{
- send_msg(VARLSTCNT(5) ERR_TIMERHANDLER, 3, prev_alrm_handler.sa_handler,
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_TIMERHANDLER, 3, prev_alrm_handler.sa_handler,
LEN_AND_LIT("init_timers"));
- rts_error(VARLSTCNT(5) ERR_TIMERHANDLER, 3, prev_alrm_handler.sa_handler,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_TIMERHANDLER, 3, prev_alrm_handler.sa_handler,
LEN_AND_LIT("init_timers"));
assert(FALSE);
}
@@ -935,9 +1004,9 @@ void check_for_timer_pops()
}
if (stolenwhen)
{
- send_msg(VARLSTCNT(5) ERR_TIMERHANDLER, 3, current_sa.sa_handler,
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_TIMERHANDLER, 3, current_sa.sa_handler,
LEN_AND_STR(whenstolen[stolenwhen - 1]));
- rts_error(VARLSTCNT(5) ERR_TIMERHANDLER, 3, current_sa.sa_handler,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_TIMERHANDLER, 3, current_sa.sa_handler,
LEN_AND_STR(whenstolen[stolenwhen - 1]));
assert(FALSE); /* does not return here */
}
diff --git a/sr_unix/gtm.gtc b/sr_unix/gtm.gtc
index c66604a..ca4808f 100644
--- a/sr_unix/gtm.gtc
+++ b/sr_unix/gtm.gtc
@@ -1,7 +1,7 @@
#!/bin/sh
#################################################################
# #
-# Copyright 2010 Fidelity Information Services, Inc #
+# Copyright 2010,2013 Fidelity Information Services, Inc #
# #
# This source code contains the intellectual property #
# of its copyright holder(s), and is made available #
@@ -19,6 +19,10 @@ else
find . -name \*.mjl_\* -mtime +$gtm_retention -exec rm -vf {} \; )
if [ 0 = $# ] ; then
$gtm_dist/mumps -direct
+ elif [ "-help" = "$1" -o "-h" = "$1" -o "-?" = "$1" ] ; then
+ echo "gtm -dir[ect] to enter direct mode (halt returns to shell)"
+ echo "gtm -run <entryref> to start executing at an entryref"
+ echo "gtm -help / gtm -h / gtm -? to display this text"
else
$gtm_dist/mumps $*
fi
diff --git a/sr_unix/gtm_asm_establish.c b/sr_unix/gtm_asm_establish.c
index 9b501ba..b80f7d0 100644
--- a/sr_unix/gtm_asm_establish.c
+++ b/sr_unix/gtm_asm_establish.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2012 Fidelity Information Services, Inc *
+ * Copyright 2012, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -20,12 +20,5 @@ void gtm_asm_establish(void); /* Only needs to be declared here as is only call
void gtm_asm_establish(void)
{
- CHTRACEPOINT;
- ctxt++;
- if (ctxt >= (chnd_end + (!process_exiting ? 0 : CONDSTK_RESERVE)))
- condstk_expand();
- CHECKHIGHBOUND(ctxt);
- ctxt->save_active_ch = active_ch;
- ctxt->ch_active = FALSE;
- active_ch = ctxt;
+ GTM_ASM_ESTABLISH;
}
diff --git a/sr_unix/gtm_bintim.c b/sr_unix/gtm_bintim.c
index 6882c40..f360afc 100644
--- a/sr_unix/gtm_bintim.c
+++ b/sr_unix/gtm_bintim.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2007 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -50,6 +50,7 @@
#include "gdsfhead.h"
#include "filestruct.h"
#include "jnl.h" /* jnl_proc_time needs this. jnl.h needs some of the above */
+#include "have_crit.h"
#include "gtm_bintim.h"
#define monthalphas "abcdefgjlmnoprstuvyABCDEFGJLMNOPRSTUVY"
@@ -58,110 +59,97 @@ static int getmon(char *month);
int gtm_bintim(char *toscan, jnl_proc_time *timep)
{
- time_t now, mktime_ret;
- struct tm time_tm, *now_tm;
- int num, sec, min, hour, day, year;
- int len = STRLEN(toscan), matched = 0;
- char month[256];
-
- num = SSCANF(toscan, "%d %d", &day, &hour);
- if (2 == num)
- { /* delta time format. note: this is the same code as in VMS gtm_bintim.c */
- num = SSCANF(toscan, "%d %d:%d:%d%n", &day, &hour, &min, &sec, &matched);
- if (matched < len)
- {
- num = SSCANF(toscan, "%d %d:%d:%d:%*d%n", &day, &hour, &min, &sec,
- &matched);
- if (matched < len)
- {
- sec = 0;
- num = SSCANF(toscan, "%d %d:%d%n", &day, &hour, &min, &matched);
+ time_t now, mktime_ret;
+ struct tm time_tm, *now_tm;
+ int num, sec, min, hour, day, year;
+ int len = STRLEN(toscan), matched = 0;
+ char month[256];
+
+ num = SSCANF(toscan, "%d %d", &day, &hour);
+ if (2 == num)
+ { /* delta time format. note: this is the same code as in VMS gtm_bintim.c */
+ num = SSCANF(toscan, "%d %d:%d:%d%n", &day, &hour, &min, &sec, &matched);
if (matched < len)
- return -1;
- }
- }
- *timep = - (day*86400 + hour*3600 + min*60 + sec);
- return 0;
- } else /* absolute time format */
- {
- *month = '\0';
- now = time((time_t *) 0);
- now_tm = localtime(&now);
- num = SSCANF(toscan, "%d-%[" monthalphas "]-%d %d:%d:%d%n", &day, month, &year,
- &hour, &min, &sec, &matched);
-
- if (matched < len)
+ {
+ num = SSCANF(toscan, "%d %d:%d:%d:%*d%n", &day, &hour, &min, &sec, &matched);
+ if (matched < len)
+ {
+ sec = 0;
+ num = SSCANF(toscan, "%d %d:%d%n", &day, &hour, &min, &matched);
+ if (matched < len)
+ return -1;
+ }
+ }
+ *timep = -((day * 86400) + (hour * 3600) + (min * 60) + sec);
+ return 0;
+ } else /* absolute time format */
{
- num = SSCANF(toscan, "%d-%[" monthalphas "]-%d %d:%d:%d:%*d%n", &day, month,
- &year, &hour, &min, &sec, &matched);
-
- if (matched < len)
- {
- sec = 0;
- num = SSCANF(toscan, "%d-%[" monthalphas "]-%d %d:%d%n", &day, month, &year,
- &hour, &min, &matched);
-
+ *month = '\0';
+ now = time((time_t *) 0);
+ GTM_LOCALTIME(now_tm, &now);
+ num = SSCANF(toscan, "%d-%[" monthalphas "]-%d %d:%d:%d%n", &day, month, &year, &hour, &min, &sec, &matched);
if (matched < len)
{
- hour = min = sec = 0;
- num = SSCANF(toscan, "%d-%[" monthalphas "]-%d%n", &day, month, &year,
- &matched);
- if (matched < len)
- {
- day = now_tm->tm_mday;
- year = now_tm->tm_year + 1900;
- num = SSCANF(toscan, "-- %d:%d:%d%n", &hour, &min, &sec,
- &matched);
+ num = SSCANF(toscan, "%d-%[" monthalphas "]-%d %d:%d:%d:%*d%n",
+ &day, month, &year, &hour, &min, &sec, &matched);
if (matched < len)
{
- num = SSCANF(toscan, "-- %d:%d:%d:%*d%n", &hour, &min,
- &sec, &matched);
- if (matched < len)
- {
sec = 0;
- num = SSCANF(toscan, "-- %d:%d%n", &hour, &min,
- &matched);
+ num = SSCANF(toscan, "%d-%[" monthalphas "]-%d %d:%d%n", &day, month, &year, &hour, &min, &matched);
if (matched < len)
- return -1;
- }
+ {
+ hour = min = sec = 0;
+ num = SSCANF(toscan, "%d-%[" monthalphas "]-%d%n", &day, month, &year, &matched);
+ if (matched < len)
+ {
+ day = now_tm->tm_mday;
+ year = now_tm->tm_year + 1900;
+ num = SSCANF(toscan, "-- %d:%d:%d%n", &hour, &min, &sec, &matched);
+ if (matched < len)
+ {
+ num = SSCANF(toscan, "-- %d:%d:%d:%*d%n", &hour, &min, &sec, &matched);
+ if (matched < len)
+ {
+ sec = 0;
+ num = SSCANF(toscan, "-- %d:%d%n", &hour, &min, &matched);
+ if (matched < len)
+ return -1;
+ }
+ }
+ }
+ }
}
- }
}
- }
+ time_tm.tm_sec = sec;
+ time_tm.tm_min = min;
+ time_tm.tm_hour = hour;
+ if (*month)
+ time_tm.tm_mon = getmon(month);
+ else
+ time_tm.tm_mon = now_tm->tm_mon;
+ time_tm.tm_mday = day;
+ time_tm.tm_year = year-1900;
+ time_tm.tm_isdst = -1;
+ GTM_MKTIME(mktime_ret, &time_tm);
+ if ((time_t)-1 == mktime_ret)
+ return -1;
+ *timep = (jnl_proc_time)mktime_ret;
+ return 0;
}
- time_tm.tm_sec = sec;
- time_tm.tm_min = min;
- time_tm.tm_hour = hour;
- if (*month)
- time_tm.tm_mon = getmon(month);
- else
- time_tm.tm_mon = now_tm->tm_mon;
- time_tm.tm_mday = day;
- time_tm.tm_year = year-1900;
- time_tm.tm_isdst = -1;
-
- mktime_ret = mktime(&time_tm);
- if ((time_t)-1 == mktime_ret)
- return -1;
- *timep = (jnl_proc_time)mktime_ret;
- return 0;
- }
}
static int getmon(char *month)
{
- char *p;
- int i;
- static char *m[] = { "jan", "feb", "mar", "apr", "may", "jun",
- "jul", "aug", "sep", "oct", "nov", "dec" };
-
- for(p=month; *p; p++)
- if (ISUPPER(*p))
- *p = TOLOWER(*p);
-
- for(i=0; i<12; i++)
- if (!strcmp(month,m[i]))
- return i;
-
- return -1;
+ char *p;
+ int i;
+ static char *m[] = { "jan", "feb", "mar", "apr", "may", "jun",
+ "jul", "aug", "sep", "oct", "nov", "dec" };
+
+ for (p = month; *p; p++)
+ if (ISUPPER_ASCII(*p))
+ *p = TOLOWER(*p);
+ for (i = 0; i < 12; i++)
+ if (!strcmp(month,m[i]))
+ return i;
+ return -1;
}
diff --git a/sr_unix/gtm_c_stack_trace.c b/sr_unix/gtm_c_stack_trace.c
index f28dc02..83e5203 100644
--- a/sr_unix/gtm_c_stack_trace.c
+++ b/sr_unix/gtm_c_stack_trace.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
-* Copyright 2012 Fidelity Information Services, Inc *
+* Copyright 2012, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -101,12 +101,12 @@ void gtm_c_stack_trace(char *message, pid_t waiting_pid, pid_t blocking_pid, uin
currpos = (char *)i2asc((unsigned char*)currpos, (unsigned int)count);
*currpos++ = 0;
assert(currpos - (TREF(gtm_waitstuck_script)).addr <= (TREF(gtm_waitstuck_script)).len);
- status = SYSTEM((char *)((TREF(gtm_waitstuck_script)).addr));
+ status = SYSTEM(((char *)((TREF(gtm_waitstuck_script)).addr)));
if (-1 == status)
{ /* SYSTEM failed */
save_errno = errno;
- send_msg(VARLSTCNT(6) ERR_STUCKACT, 4, LEN_AND_LIT("FAILURE"), LEN_AND_STR(command));
- send_msg(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("system"), CALLFROM, save_errno);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_STUCKACT, 4, LEN_AND_LIT("FAILURE"), LEN_AND_STR(command));
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("system"), CALLFROM, save_errno);
} else
{ /* check on how the command did */
assert(SIZEOF(wait_stat) == SIZEOF(int4));
@@ -119,23 +119,27 @@ void gtm_c_stack_trace(char *message, pid_t waiting_pid, pid_t blocking_pid, uin
{
status = WEXITSTATUS(wait_stat);
if (!status)
- send_msg(VARLSTCNT(6) ERR_STUCKACT, 4, LEN_AND_LIT("SUCCESS"), LEN_AND_STR(command));
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_STUCKACT, 4,
+ LEN_AND_LIT("SUCCESS"), LEN_AND_STR(command));
else
{
- send_msg(VARLSTCNT(6) ERR_STUCKACT, 4, LEN_AND_LIT("FAILURE"), LEN_AND_STR(command));
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_STUCKACT, 4,
+ LEN_AND_LIT("FAILURE"), LEN_AND_STR(command));
if (WIFSIGNALED(wait_stat))
{
status = WTERMSIG(wait_stat);
- send_msg(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("PROCSTUCK terminated by signal"),
- CALLFROM, status);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5,
+ LEN_AND_LIT("PROCSTUCK terminated by signal"), CALLFROM, status);
} else
- send_msg(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("PROCSTUCK"), CALLFROM, status);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5,
+ LEN_AND_LIT("PROCSTUCK"), CALLFROM, status);
}
} else
{ /* it's gone rogue' */
- send_msg(VARLSTCNT(6) ERR_STUCKACT, 4, LEN_AND_LIT("FAILURE"), LEN_AND_STR(command));
- send_msg(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("PROCSTUCK did not report status"), CALLFROM,
- status);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_STUCKACT, 4,
+ LEN_AND_LIT("FAILURE"), LEN_AND_STR(command));
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5,
+ LEN_AND_LIT("PROCSTUCK did not report status"), CALLFROM, status);
assert(FALSE);
}
}
diff --git a/sr_unix/gtm_compare_dir.csh b/sr_unix/gtm_compare_dir.csh
index 10e6f9a..7fec051 100644
--- a/sr_unix/gtm_compare_dir.csh
+++ b/sr_unix/gtm_compare_dir.csh
@@ -1,7 +1,7 @@
#!/usr/local/bin/tcsh
#################################################################
# #
-# Copyright 2011 Fidelity Information Services, Inc #
+# Copyright 2011, 2013 Fidelity Information Services, Inc #
# #
# This source code contains the intellectual property #
# of its copyright holder(s), and is made available #
@@ -22,13 +22,18 @@ exit
GDE_EOF
mupip create >& /dev/null
cp $gtm_tools/dircompare.m.txt ./dircompare.m
-mumps -r dircompare $2/build.dir $3 $4 $5 > bout
-mumps -r dircompare $2/install.dir NOP NOP $5 > iout
+echo "setenv gtm_dist $gtm_dist" >&! repeat
+echo "setenv gtmroutines '$gtmroutines'" >>& repeat
+echo "setenv gtmgbldir mumps.gld" >>& repeat
+echo "$gtm_dist/mumps -r dircompare $2/build.dir $3 $4 $5" >>& repeat
+echo "$gtm_dist/mumps -r dircompare $2/install.dir NOP NOP $5" >>& repeat
+$gtm_dist/mumps -r dircompare $2/build.dir $3 $4 $5 > dev.out
+$gtm_dist/mumps -r dircompare $2/install.dir NOP NOP $5 > install.out
if ($6 == "os390") then
# we expect 4 diff lines at the beginning on zos so account for them
- diff bout iout | tail -n +5 > diff.out
+ diff dev.out install.out | tail -n +5 > diff.out
else
- diff bout iout > diff.out
+ diff dev.out install.out > diff.out
endif
set numdiff=`wc -l < diff.out`
echo
diff --git a/sr_unix/gtm_compile.c b/sr_unix/gtm_compile.c
index c8b05fc..ebf3230 100644
--- a/sr_unix/gtm_compile.c
+++ b/sr_unix/gtm_compile.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -40,8 +40,10 @@
#include "gdsfhead.h"
#include "alias.h"
#include "gt_timers_add_safe_hndlrs.h"
+#include "zco_init.h"
GBLREF command_qualifier glb_cmd_qlf, cmd_qlf;
+GBLREF IN_PARMS *cli_lex_in_ptr;
GBLREF stack_frame *frame_pointer;
GBLREF unsigned char *stackbase,*stacktop,*stackwarn,*msp;
GBLREF mv_stent *mv_chain;
@@ -51,12 +53,14 @@ GBLREF spdesc rts_stringpool, stringpool;
int gtm_compile (void)
{
- int status;
- unsigned short len;
- char source_file_string[MAX_FBUFF + 1];
- char obj_file[MAX_FBUFF + 1], list_file[MAX_FBUFF + 1], ceprep_file[MAX_FBUFF + 1];
- unsigned char *mstack_ptr;
- void gtm_ret_code();
+ int status;
+ unsigned short len;
+ char source_file_string[MAX_FBUFF + 1];
+ char obj_file[MAX_FBUFF + 1], list_file[MAX_FBUFF + 1], ceprep_file[MAX_FBUFF + 1];
+ unsigned char *mstack_ptr;
+ void gtm_ret_code();
+ command_qualifier save_qlf;
+ mstr orig_cmdstr;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
@@ -90,13 +94,21 @@ int gtm_compile (void)
LVVAL_INIT((TREF(zsearch_dir1)), curr_symval);
LVVAL_INIT((TREF(zsearch_dir2)), curr_symval);
/* command qualifier processing stuff */
- cmd_qlf.object_file.str.addr = obj_file;
- cmd_qlf.object_file.str.len = MAX_FBUFF;
- cmd_qlf.list_file.str.addr = list_file;
- cmd_qlf.list_file.str.len = MAX_FBUFF;
- cmd_qlf.ceprep_file.str.addr = ceprep_file;
- cmd_qlf.ceprep_file.str.len = MAX_FBUFF;
- get_cmd_qlf(&cmd_qlf);
+ zco_init();
+ assert(cli_lex_in_ptr);
+ save_qlf = glb_cmd_qlf;
+ /* Save the original MUMPS command line qualifers. These are processed after, and take precedence over, $ZCOMPILE. */
+ orig_cmdstr.len = strlen(cli_lex_in_ptr->in_str) - strlen("MUMPS ");
+ orig_cmdstr.addr = (char *)malloc(orig_cmdstr.len);
+ memcpy(orig_cmdstr.addr, cli_lex_in_ptr->in_str + strlen("MUMPS "), orig_cmdstr.len);
+ INIT_CMD_QLF_STRINGS(cmd_qlf, obj_file, list_file, ceprep_file, MAX_FBUFF);
+ zl_cmd_qlf(&(TREF(dollar_zcompile)), &cmd_qlf); /* Initialize $ZCOMPILE as default command qualifiers */
+ glb_cmd_qlf = cmd_qlf;
+ INIT_CMD_QLF_STRINGS(cmd_qlf, obj_file, list_file, ceprep_file, MAX_FBUFF);
+ zl_cmd_qlf(&orig_cmdstr, &cmd_qlf); /* Next, process MUMPS command line qualifers */
+ free(orig_cmdstr.addr);
+ glb_cmd_qlf = save_qlf;
+ /* end command qualifier processing stuff */
initialize_pattern_table();
ce_init(); /* initialize compiler escape processing */
prealloc_gt_timers();
diff --git a/sr_unix/gtm_dump_core.c b/sr_unix/gtm_dump_core.c
index f72e2b1..10905fe 100644
--- a/sr_unix/gtm_dump_core.c
+++ b/sr_unix/gtm_dump_core.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -66,5 +66,5 @@ void gtm_dump_core(void)
sigprocmask(SIG_UNBLOCK, &unblock_sigquit, NULL);
kill(getpid(), SIGQUIT);
sleep(60); /* In case of async kill */
- _exit(1);
+ _exit(EXIT_FAILURE);
}
diff --git a/sr_unix/gtm_env_init_sp.c b/sr_unix/gtm_env_init_sp.c
index cb3a97a..145d5e8 100644
--- a/sr_unix/gtm_env_init_sp.c
+++ b/sr_unix/gtm_env_init_sp.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2004, 2012 Fidelity Information Services, Inc *
+ * Copyright 2004, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -95,15 +95,17 @@ LITDEF mval default_mupip_trigger_etrap = DEFINE_MVAL_LITERAL(MV_STR, 0 , 0 , (S
static readonly nametabent editing_params[] =
{
{7, "EDITING"},
+ {7, "EMPTERM"},
{6, "INSERT"},
{9, "NOEDITING"},
+ {9, "NOEMPTERM"},
{8, "NOINSERT"}
};
static readonly unsigned char editing_index[27] =
{
- 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2,
- 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4
+ 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 3,
+ 3, 3, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6
};
static readonly unsigned char init_break[1] = {'B'};
@@ -197,13 +199,19 @@ void gtm_env_init_sp(void)
case 0: /* EDITING */
gtm_principal_editing_defaults |= TT_EDITING;
break;
- case 1: /* INSERT */
+ case 1: /* EMPTERM */
+ gtm_principal_editing_defaults |= TT_EMPTERM;
+ break;
+ case 2: /* INSERT */
gtm_principal_editing_defaults &= ~TT_NOINSERT;
break;
- case 2: /* NOEDITING */
+ case 3: /* NOEDITING */
gtm_principal_editing_defaults &= ~TT_EDITING;
break;
- case 3: /* NOINSERT */
+ case 4: /* NOEMPTERM */
+ gtm_principal_editing_defaults &= ~TT_EMPTERM;
+ break;
+ case 5: /* NOINSERT */
gtm_principal_editing_defaults |= TT_NOINSERT;
break;
}
@@ -334,4 +342,12 @@ void gtm_env_init_sp(void)
if (!is_defined)
TREF(gtm_test_fake_enospc) = FALSE;
# endif
+# ifdef GTMDBGFLAGS_ENABLED
+ val.addr = GTMDBGFLAGS;
+ val.len = SIZEOF(GTMDBGFLAGS) - 1;
+ TREF(gtmdbgflags) = trans_numeric(&val, &is_defined, TRUE);
+ val.addr = GTMDBGFLAGS_FREQ;
+ val.len = SIZEOF(GTMDBGFLAGS_FREQ) - 1;
+ TREF(gtmdbgflags_freq) = trans_numeric(&val, &is_defined, TRUE);
+# endif
}
diff --git a/sr_unix/gtm_fd_trace.c b/sr_unix/gtm_fd_trace.c
index 601a495..5f85764 100644
--- a/sr_unix/gtm_fd_trace.c
+++ b/sr_unix/gtm_fd_trace.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2009 Fidelity Information Services, Inc *
+ * Copyright 2009, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -65,6 +65,9 @@ GBLDEF int4 fd_ops_array_index = -1;
GBLDEF int4 fd_ops_array_num_wraps = 0; /* to get an idea how many total files were opened/closed */
GBLDEF fd_trace fd_ops_array[FD_OPS_ARRAY_SIZE]; /* space for FD_TRACE macro to record info */
+error_def(ERR_CLOSEFAIL);
+error_def(ERR_CALLERID);
+
/* Determine on what platforms and build types we want to get caller_id information. In pro builds, invoke caller_id only on
* those platforms where caller_id is lightweight (i.e. caller_id.s exists). Thankfully AIX (necessary for D9I11-002714)
* falls in this category. For debug builds, invoke caller_id unconditionally since performance is not a big concern.
@@ -149,13 +152,14 @@ int gtm_pipe1(int pipefd[2])
return status;
}
-int gtm_socket(int domain, int type, int protocol)
+int gtm_socket(int family, int type, int protocol)
{
int fd;
- fd = socket(domain, type, protocol);
- FD_TRACE(fd_ops_socket, fd, 0);
- assert(-1 != fd);
+ fd = socket(family, type, protocol);
+ if (-1 != fd)
+ FD_TRACE(fd_ops_socket, fd, 0);
+ /* it is possible that fd will be -1 if the address family is not supported */
return fd;
}
@@ -164,15 +168,12 @@ int gtm_close(int fd)
int status;
int save_errno;
- error_def(ERR_CLOSEFAIL);
- error_def(ERR_CALLERID);
-
status = close(fd);
save_errno = errno;
FD_TRACE(fd_ops_close, fd, status);
if ((-1 == status) && (EINTR != save_errno))
{
- send_msg(VARLSTCNT(4) ERR_CLOSEFAIL, 1, fd, save_errno);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_CLOSEFAIL, 1, fd, save_errno);
SEND_CALLERID("gtm_close()");
assert(FALSE);
}
diff --git a/sr_unix/gtm_fork_n_core.c b/sr_unix/gtm_fork_n_core.c
index 9188c05..31b0911 100644
--- a/sr_unix/gtm_fork_n_core.c
+++ b/sr_unix/gtm_fork_n_core.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -42,6 +42,7 @@
#include "gdsfhead.h"
#include "filestruct.h"
#include "dpgbldir.h"
+#include "fork_init.h"
GBLREF boolean_t created_core; /* core file was created */
GBLREF unsigned int core_in_progress;
@@ -150,8 +151,8 @@ DEBUG_ONLY( struct rlimit rlim;)
{
if (1 == core_in_progress)
{ /* only report once */
- send_msg(VARLSTCNT(1) ERR_COREINPROGRESS, 0);
- gtm_putmsg(VARLSTCNT(1) ERR_COREINPROGRESS, 0);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_COREINPROGRESS, 0);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_COREINPROGRESS, 0);
}
return;
}
@@ -165,14 +166,14 @@ DEBUG_ONLY( struct rlimit rlim;)
/* block SIGALRM signal */
sigprocmask(SIG_BLOCK, &blockalrm, &savemask);
- childid = fork(); /* BYPASSOK: we exit immediately, no FORK_CLEAN needed */
+ FORK(childid); /* BYPASSOK: we exit immediately, no FORK_CLEAN needed */
if (childid)
{
if (-1 == childid)
{ /* restore interrupt handler */
sigaction(SIGINT, &intr, 0);
sigprocmask(SIG_SETMASK, &savemask, NULL);
- gtm_putmsg(VARLSTCNT(3) ERR_NOFORKCORE, 0, errno);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_NOFORKCORE, 0, errno);
return; /* Fork failed, no core done */
}
WAITPID(childid, &status, 0, waitrc);
@@ -189,29 +190,6 @@ DEBUG_ONLY( struct rlimit rlim;)
created_core = TRUE;
} else
{
- for (addr_ptr = get_next_gdr(NULL); addr_ptr; addr_ptr = get_next_gdr(addr_ptr))
- {
- for (reg = addr_ptr->regions, r_top = reg + addr_ptr->n_regions; reg < r_top; reg++)
- {
- if (reg->open && !reg->was_open && (dba_mm == reg->dyn.addr->acc_meth))
- { /* Because most OSs don't include mapped memory in the core file, copy file header
- * to temporary location that'll show up in the core.
- */
- csa = (sgmnt_addrs *)&FILE_INFO(reg)->s_addrs;
- tmp_csd = csa->hdr;
- if ((NULL != tmp_csd) && (MM_MALLOC_ALREADY_TRIED != csa->mm_core_hdr))
- {
- csa->mm_core_hdr = MM_MALLOC_ALREADY_TRIED;
- csd = (sgmnt_data_ptr_t)malloc(SIZEOF(*csd));
- if (NULL != csd)
- {
- memcpy((sm_uc_ptr_t)csd, (uchar_ptr_t)tmp_csd, SIZEOF(*csd));
- csa->mm_core_hdr = csd;
- }
- }
- }
- }
- }
DUMP_CORE; /* This will (should) not return */
_exit(-1); /* Protection to kill fork'd process with no rundown by exit handler(s) */
}
diff --git a/sr_unix/gtm_logicals.h b/sr_unix/gtm_logicals.h
index a96d0c5..94a8a01 100644
--- a/sr_unix/gtm_logicals.h
+++ b/sr_unix/gtm_logicals.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -119,3 +119,7 @@
#define GTM_PROCSTUCKEXEC "$gtm_procstuckexec"
#define GTM_QUIET_HALT "$gtm_quiet_halt"
#define GTM_EXTRACT_NOCOL "$gtm_extract_nocol"
+#define GTMDBGFLAGS "$gtmdbgflags"
+#define GTMDBGFLAGS_FREQ "$gtmdbgflags_freq"
+#define GTM_MAX_STORALLOC "$gtm_max_storalloc"
+#define GTM_IPV4_ONLY "$gtm_ipv4_only"
diff --git a/sr_unix/gtm_pipe.c b/sr_unix/gtm_pipe.c
index d9d0bb1..6227f7d 100644
--- a/sr_unix/gtm_pipe.c
+++ b/sr_unix/gtm_pipe.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -35,6 +35,7 @@
#include "gtm_pipe.h"
#include "eintr_wrappers.h"
#include "gtmio.h"
+#include "fork_init.h"
GBLDEF uint4 pipe_child;
@@ -46,13 +47,13 @@ int gtm_pipe(char *command, pipe_type pt)
parent = (int)pt;
child = 1 - parent;
-
if (0 > pipe(pfd))
{
PERROR("pipe : ");
return -2;
}
- if (-1 == (child_pid = fork())) /* BYPASSOK: we exit immediately, no FORK_CLEAN needed */
+ FORK(child_pid); /* BYPASSOK: we exit immediately, no FORK_CLEAN needed */
+ if (-1 == child_pid)
{
PERROR("fork : ");
return -1;
@@ -61,21 +62,17 @@ int gtm_pipe(char *command, pipe_type pt)
CLOSEFILE_RESET(pfd[parent], rc); /* resets "pfd[parent]" to FD_INVALID */
DUP2(pfd[child], child, dup2_res);
CLOSEFILE_RESET(pfd[child], rc); /* resets "pfd[child]" to FD_INVALID */
- /* We should have used exec instead of SYSTEM. Earlier it was followed by exit(0), which calls exit_handler.
- * So both child and parent will do exit handling. This can make ref_cnt < 0, or, it can release semaphores,
- * which we should not release until parent exists. So we just call _exit(0). Add the do nothing if to
- * keep compiler happy since exiting anyway.
+ /* We should have used exec instead of SYSTEM. Earlier it was followed by exit(EXIT_SUCCESS), which calls
+ * exit_handler. So both child and parent will do exit handling. This can make ref_cnt < 0, or, it can release
+ * semaphores, which we should not release until parent exists. So we just call _exit(EXIT_SUCCESS). Add the do
+ * nothing if to keep compiler happy since exiting anyway.
*/
- if (-1 == SYSTEM(command));
- _exit(0); /* just exit from here */
+ rc = SYSTEM(command);
+ _exit(EXIT_SUCCESS); /* just exit from here */
} else
{ /* parent process */
pipe_child = child_pid;
CLOSEFILE_RESET(pfd[child], rc); /* resets "pfd[child]" to FD_INVALID */
return pfd[parent];
}
-
- assert(FALSE);
- /* It should never get here, just to keep compiler happy. */
- return -3;
}
diff --git a/sr_unix/gtm_putmsg.c b/sr_unix/gtm_putmsg.c
index 8b97539..1cf9280 100644
--- a/sr_unix/gtm_putmsg.c
+++ b/sr_unix/gtm_putmsg.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -17,6 +17,16 @@
#include "gtmmsg.h"
#include "gtm_putmsg_list.h"
#include "gtmimagename.h"
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "repl_msg.h"
+#include "gtmsource.h"
+#include "anticipatory_freeze.h"
+
+GBLREF gd_region *gv_cur_region;
+GBLREF jnlpool_addrs jnlpool;
/* WARNING: For chained error messages, all messages MUST be followed by an fao count;
* ======= zero MUST be specified if there are no parameters.
@@ -25,9 +35,23 @@
void gtm_putmsg(int argcnt, ...)
{
va_list var;
+ sgmnt_addrs *csa;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ csa = (ANTICIPATORY_FREEZE_AVAILABLE && jnlpool.jnlpool_ctl) ? REG2CSA(gv_cur_region) : NULL;
+ VAR_START(var, argcnt);
+ gtm_putmsg_list(csa, argcnt, var);
+ va_end(var);
+ util_out_print("",TRUE);
+}
+
+void gtm_putmsg_csa(void *csa, int argcnt, ...)
+{
+ va_list var;
VAR_START(var, argcnt);
- gtm_putmsg_list(argcnt, var);
+ gtm_putmsg_list(csa, argcnt, var);
va_end(var);
util_out_print("",TRUE);
}
@@ -35,8 +59,21 @@ void gtm_putmsg(int argcnt, ...)
void gtm_putmsg_noflush(int argcnt, ...)
{
va_list var;
+ sgmnt_addrs *csa;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ csa = (ANTICIPATORY_FREEZE_AVAILABLE && jnlpool.jnlpool_ctl) ? REG2CSA(gv_cur_region) : NULL;
+ VAR_START(var, argcnt);
+ gtm_putmsg_list(csa, argcnt, var);
+ va_end(var);
+}
+
+void gtm_putmsg_noflush_csa(void *csa, int argcnt, ...)
+{
+ va_list var;
VAR_START(var, argcnt);
- gtm_putmsg_list(argcnt, var);
+ gtm_putmsg_list(csa, argcnt, var);
va_end(var);
}
diff --git a/sr_unix/gtm_putmsg_list.c b/sr_unix/gtm_putmsg_list.c
index d130715..f17fab5 100644
--- a/sr_unix/gtm_putmsg_list.c
+++ b/sr_unix/gtm_putmsg_list.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -39,12 +39,11 @@ GBLREF boolean_t donot_fflush_NULL;
* ----------------------------------------------------------------------------------------
*/
-void gtm_putmsg_list(int arg_count, va_list var)
+void gtm_putmsg_list(void *csa, int arg_count, va_list var)
{
int i, msg_id, fao_actual, fao_count, dummy, freeze_msg_id;
char msg_buffer[1024];
mstr msg_string;
- boolean_t first_error;
const err_msg *msg;
const err_ctl *ctl;
boolean_t freeze_needed = FALSE;
@@ -64,22 +63,15 @@ void gtm_putmsg_list(int arg_count, va_list var)
flush_pio();
}
assert(0 < arg_count);
- first_error = TRUE;
for (; ; )
{
msg_id = va_arg(var, int);
- CHECK_IF_FREEZE_ON_ERROR_NEEDED(msg_id, freeze_needed, freeze_msg_id);
+ CHECK_IF_FREEZE_ON_ERROR_NEEDED(csa, msg_id, freeze_needed, freeze_msg_id);
--arg_count;
if (NULL == (ctl = err_check(msg_id)))
msg = NULL;
else
GET_MSG_INFO(msg_id, ctl, msg);
- if (first_error)
- {
- first_error = FALSE;
- error_condition = msg_id;
- severity = NULL == msg ? ERROR : SEVMASK(msg_id);
- }
msg_string.addr = msg_buffer;
msg_string.len = sizeof msg_buffer;
gtm_getmsg(msg_id, &msg_string);
@@ -134,5 +126,5 @@ void gtm_putmsg_list(int arg_count, va_list var)
if (!IS_GTMSECSHR_IMAGE)
util_out_print("!/", NOFLUSH);
}
- FREEZE_INSTANCE_IF_NEEDED(freeze_needed, freeze_msg_id);
+ FREEZE_INSTANCE_IF_NEEDED(csa, freeze_needed, freeze_msg_id);
}
diff --git a/sr_unix/gtm_semutils.h b/sr_unix/gtm_semutils.h
index 344ba12..fefc96b 100644
--- a/sr_unix/gtm_semutils.h
+++ b/sr_unix/gtm_semutils.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2011, 2012 Fidelity Information Services, Inc *
+ * Copyright 2011, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -21,6 +21,9 @@
#define MAX_C_STACK_TRACES_FOR_SEMWAIT 2
+#define DB_CONTROL_SEM 0
+#define DB_COUNTER_SEM 1
+
error_def(ERR_CRITSEMFAIL);
error_def(ERR_DBFILERR);
error_def(ERR_FTOKERR);
@@ -158,11 +161,11 @@ boolean_t do_blocking_semop(int semid, enum gtm_semtype semtype, uint4 start_hrt
/* Typically, multiple statements are not specified in a single line. However, each of the 2 lines below represent \
* "one" semaphore operation and hence an acceptible exception to the coding guidelines. \
*/ \
- SOP[0].sem_num = 0; SOP[0].sem_op = 0; /* Wait for 0 (unlocked) */ \
- SOP[1].sem_num = 0; SOP[1].sem_op = 1; /* Then lock it */ \
+ SOP[0].sem_num = DB_CONTROL_SEM; SOP[0].sem_op = 0; /* Wait for 0 (unlocked) */ \
+ SOP[1].sem_num = DB_CONTROL_SEM; SOP[1].sem_op = 1; /* Then lock it */ \
if (INCR_CNT) \
{ \
- SOP[2].sem_num = 1; SOP[2].sem_op = 1; /* Increment counter semaphore */ \
+ SOP[2].sem_num = DB_COUNTER_SEM; SOP[2].sem_op = 1; /* Increment counter semaphore */ \
SOPCNT = 3; \
} else \
SOPCNT = 2; \
diff --git a/sr_unix/gtm_startup_chk.c b/sr_unix/gtm_startup_chk.c
index 5a4e73b..d327451 100644
--- a/sr_unix/gtm_startup_chk.c
+++ b/sr_unix/gtm_startup_chk.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -39,7 +39,9 @@
#include "is_file_identical.h"
#include "gtm_startup_chk.h"
#include "gtmimagename.h"
+#include "have_crit.h"
+GBLREF char gtm_dist[GTM_PATH_MAX];
LITREF gtmImageName gtmImageNames[];
error_def(ERR_DISTPATHMAX);
@@ -51,7 +53,6 @@ error_def(ERR_IMAGENAME);
int gtm_chk_dist(char *image)
{
- char *ptr1;
char pre_buff[MAX_FBUFF];
char *prefix;
int prefix_len;
@@ -59,14 +60,17 @@ int gtm_chk_dist(char *image)
int status;
char mbuff[MAX_FBUFF + 1];
parse_blk pblk;
+ char *dist;
- if (NULL != (ptr1 = (char *)GETENV(GTM_DIST)))
+ if (NULL != (dist = (char *)GETENV(GTM_DIST)))
{
assert(IS_VALID_IMAGE && (n_image_types > image_type)); /* assert image_type is initialized */
- if ((GTM_PATH_MAX - 2) <= (STRLEN(ptr1) + gtmImageNames[image_type].imageNameLen))
- rts_error(VARLSTCNT(3) ERR_DISTPATHMAX, 1, GTM_PATH_MAX - gtmImageNames[image_type].imageNameLen - 2);
+ if ((GTM_PATH_MAX - 2) <= (STRLEN(dist) + gtmImageNames[image_type].imageNameLen))
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_DISTPATHMAX, 1,
+ GTM_PATH_MAX - gtmImageNames[image_type].imageNameLen - 2);
} else
- rts_error(VARLSTCNT(1) ERR_GTMDISTUNDEF);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_GTMDISTUNDEF);
+ memcpy(gtm_dist, dist, STRLEN(dist));
memset(&pblk, 0, SIZEOF(pblk));
pblk.buffer = mbuff;
pblk.buff_size = MAX_FBUFF;
@@ -76,16 +80,16 @@ int gtm_chk_dist(char *image)
/* strings returned in pblk are not null terminated */
status = parse_file(>m_name, &pblk);
if (!(status & 1))
- rts_error(VARLSTCNT(5) ERR_FILEPARSE, 2, gtm_name.len, gtm_name.addr, status);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_FILEPARSE, 2, gtm_name.len, gtm_name.addr, status);
assert(NULL != pblk.l_name);
if ((!(pblk.fnb & F_HAS_DIR) && !pblk.b_dir) || (DIR_SEPARATOR != pblk.l_dir[0]))
{
- if (NULL == GETCWD(pre_buff, MAX_FBUFF, prefix))
- rts_error(VARLSTCNT(8) ERR_SYSCALL, 5,
- LEN_AND_LIT("getcwd"), CALLFROM, errno);
+ GETCWD(pre_buff, MAX_FBUFF, prefix);
+ if (NULL == prefix)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("getcwd"), CALLFROM, errno);
prefix_len = STRLEN(prefix);
if (MAX_FBUFF < prefix_len + pblk.b_esl + 1)
- rts_error(VARLSTCNT(3) ERR_MAXGTMPATH, 1, MAX_FBUFF - pblk.b_name);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_MAXGTMPATH, 1, MAX_FBUFF - pblk.b_name);
if (DIR_SEPARATOR != prefix[prefix_len - 1])
{
prefix[prefix_len] = DIR_SEPARATOR;
@@ -100,6 +104,6 @@ int gtm_chk_dist(char *image)
prefix[pblk.b_dir] = 0;
}
if (IS_GTM_IMAGE && memcmp(pblk.l_name, GTM_IMAGE_NAME, GTM_IMAGE_NAMELEN))
- rts_error(VARLSTCNT(6) ERR_IMAGENAME, 4, LEN_AND_LIT(GTM_IMAGE_NAME), pblk.b_name, pblk.l_name);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_IMAGENAME, 4, LEN_AND_LIT(GTM_IMAGE_NAME), pblk.b_name, pblk.l_name);
return 0;
}
diff --git a/sr_unix/gtm_statvfs.h b/sr_unix/gtm_statvfs.h
index 7f4e549..2497427 100644
--- a/sr_unix/gtm_statvfs.h
+++ b/sr_unix/gtm_statvfs.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -16,6 +16,11 @@
#include <sys/statvfs.h>
#define STATVFS(pathname,fsinfo,statvfs_res) (statvfs_res = statvfs(pathname, fsinfo))
-#define FSTATVFS(filedesc,fstatvfsinfo,fstatvfs_res) (fstatvfs_res = fstatvfs(filedesc, fstatvfsinfo))
+#define FSTATVFS(filedesc,fstatvfsinfo,fstatvfs_res) \
+{ \
+ DEFER_INTERRUPTS(INTRPT_IN_FSTAT); \
+ fstatvfs_res = fstatvfs(filedesc, fstatvfsinfo); \
+ ENABLE_INTERRUPTS(INTRPT_IN_FSTAT); \
+}
#endif
diff --git a/sr_unix/gtm_stdio.h b/sr_unix/gtm_stdio.h
index c26ebba..3b63fbd 100644
--- a/sr_unix/gtm_stdio.h
+++ b/sr_unix/gtm_stdio.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2010 Fidelity Information Services, Inc *
+ * Copyright 2010, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -22,7 +22,16 @@
#include <stdio.h>
-#define FDOPEN fdopen
+/* 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.
+ */
+#define FDOPEN(VAR, FILE_DES, MODE) \
+{ \
+ DEFER_INTERRUPTS(INTRPT_IN_FDOPEN); \
+ VAR = fdopen(FILE_DES, MODE); \
+ ENABLE_INTERRUPTS(INTRPT_IN_FDOPEN); \
+}
+
#define FGETS(strg, n, strm, fgets_res) (fgets_res = fgets(strg,n,strm))
#define Fopen fopen
#define GETS(buffer, gets_res) syntax error
diff --git a/sr_unix/gtm_syslog.h b/sr_unix/gtm_syslog.h
index daef709..b6ac34b 100644
--- a/sr_unix/gtm_syslog.h
+++ b/sr_unix/gtm_syslog.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -17,5 +17,6 @@
#define OPENLOG openlog
#define SYSLOG syslog
+#define CLOSELOG closelog
#endif
diff --git a/sr_unix/gtm_system.c b/sr_unix/gtm_system.c
new file mode 100644
index 0000000..76f2850
--- /dev/null
+++ b/sr_unix/gtm_system.c
@@ -0,0 +1,88 @@
+/****************************************************************
+* *
+* Copyright 2013 Fidelity Information Services, Inc *
+* *
+* This source code contains the intellectual property *
+* of its copyright holder(s), and is made available *
+* under a license. If you do not know the terms of *
+* the license, please stop and do not read further. *
+* *
+****************************************************************/
+#include "mdef.h"
+#include <sys/wait.h>
+#include <errno.h>
+#include "have_crit.h"
+#include "fork_init.h"
+#include "gtm_unistd.h"
+#include "gtm_stdlib.h"
+#include "eintr_wrappers.h"
+
+#define RESTOREMASK \
+{ \
+ sigaction(SIGINT, &old_intrpt, NULL); \
+ sigaction(SIGQUIT, &old_quit, NULL); \
+ sigprocmask(SIG_SETMASK, &savemask, NULL); \
+}
+
+int gtm_system(const char *cmdline)
+{
+ struct sigaction ignore, old_intrpt, old_quit;
+ sigset_t mask, savemask;
+ pid_t pid;
+ int stat; /* child exit status */
+ int ret; /* return value from waitpid */
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ DEFER_INTERRUPTS(INTRPT_IN_FORK_OR_SYSTEM);
+
+ sigemptyset(&ignore.sa_mask);
+ ignore.sa_handler = SIG_IGN;
+ ignore.sa_flags = 0;
+
+ if (sigaction(SIGINT, &ignore, &old_intrpt))
+ {
+ ENABLE_INTERRUPTS(INTRPT_IN_FORK_OR_SYSTEM);
+ return -1;
+ }
+ if (sigaction(SIGQUIT, &ignore, &old_quit))
+ {
+ sigaction(SIGINT, &old_intrpt, NULL);
+ ENABLE_INTERRUPTS(INTRPT_IN_FORK_OR_SYSTEM);
+ return -1;
+ }
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGCHLD);
+ if (sigprocmask(SIG_BLOCK, &mask, &savemask))
+ {
+ sigaction(SIGINT, &old_intrpt, NULL);
+ sigaction(SIGQUIT, &old_quit, NULL);
+ ENABLE_INTERRUPTS(INTRPT_IN_FORK_OR_SYSTEM);
+ return -1;
+ }
+
+ /* Below FORK is not used as interrupts are already disabled at the
+ * beginning of this function
+ */
+ pid = fork(); /* BYPASSOK */
+ if (0 > pid)
+ {
+ RESTOREMASK;
+ ENABLE_INTERRUPTS(INTRPT_IN_FORK_OR_SYSTEM);
+ return -1;
+ }
+ else if (0 == pid)
+ {
+ RESTOREMASK;
+ execl("/bin/sh", "sh", "-c", cmdline, (char *)0);
+ _exit(127);
+ } else
+ {
+ ENABLE_INTERRUPTS(INTRPT_IN_FORK_OR_SYSTEM);
+ WAITPID(pid, &stat, 0, ret);
+ if ((-1 == ret) && (EINTR != errno))
+ stat = -1;
+ RESTOREMASK;
+ return stat;
+ }
+}
diff --git a/sr_unix/gtm_test_install.csh b/sr_unix/gtm_test_install.csh
index b133e09..08ade96 100644
--- a/sr_unix/gtm_test_install.csh
+++ b/sr_unix/gtm_test_install.csh
@@ -1,7 +1,7 @@
#!/usr/local/bin/tcsh
#################################################################
# #
-# Copyright 2011, 2012 Fidelity Information Services, Inc #
+# Copyright 2011, 2013 Fidelity Information Services, Inc #
# #
# This source code contains the intellectual property #
# of its copyright holder(s), and is made available #
@@ -13,11 +13,12 @@ echo ""
echo "------------------------------------------------------------------------"
set arch = `grep arch $gtm_ver/pro/arch.gtc | awk -F= '{print $2}' | tr -d '\"'`
cd $1
+# Source the installed GT.M's configuration
source ./gtmcshrc
setenv gtmgbldir mumps.gld
gde exit
mupip create
-gtm << \EOF >&! gtm_test_install.out
+gtm << \EOF >&! gtm_test_install.out
set ^X=1
set x=2
write $ORDER(^%),!
@@ -31,13 +32,7 @@ zhelp
zwrite ^X
halt
EOF
-cat << EOF
-Please run zhelp manually:
-cd `pwd`
-source ./gtmcshrc
-gtm
-zhelp
-EOF
+
mkdir test_gtm
cd test_gtm
@@ -57,10 +52,11 @@ setenv save_gtm_dist $gtm_dist
unsetenv gtm_dist
# set to test directory
setenv gtmdir $save_gtm_dist/test_gtm
+# NOTE: this is not the alias gtm, but the script sr_unix/gtm.gtc
../gtm -r sim >& gtm.out
# get $ZCHSET
-echo "" >>&! $save_gtm_dist/gtm_test_install.out
-grep ZCHSET gtm.out >>&! $save_gtm_dist/gtm_test_install.out
+echo "" >>&! $save_gtm_dist/gtm_test_install.out
+grep ZCHSET gtm.out >>&! $save_gtm_dist/gtm_test_install.out
#get version number
@@ -71,13 +67,13 @@ cd $gtmver/g
setenv gtm_dist $save_gtm_dist
-$gtm_dist/mupip journal -extract -forward gtm.mjl >& mupip.out
-(setenv gtmgbldir $gtm_dist/test_gtm/mumps.gld; $gtm_dist/mupip integ -reg "*" >& integ.out)
+$gtm_dist/mupip journal -extract -forward gtm.mjl >& mupip.out
+env gtmgbldir=$gtm_dist/test_gtm/mumps.gld $gtm_dist/mupip integ -reg "*" >& integ.out
# output the change lines
-echo "" >>&! $gtm_dist/gtm_test_install.out
-echo "Global changes in the gtm.mjl file:" >>&! $gtm_dist/gtm_test_install.out
-grep = gtm.mjf | awk -F\\ '{print ($NF)}' >>&! $gtm_dist/gtm_test_install.out
-cat integ.out >>&! $gtm_dist/gtm_test_install.out
+echo "" >>&! $gtm_dist/gtm_test_install.out
+echo "Global changes in the gtm.mjl file:" >>&! $gtm_dist/gtm_test_install.out
+grep = gtm.mjf | awk -F\\ '{print ($NF)}' >>&! $gtm_dist/gtm_test_install.out
+cat integ.out >>&! $gtm_dist/gtm_test_install.out
cd $gtm_dist
@@ -181,13 +177,13 @@ end
set msg2 = `ls -al * | grep -v \> | grep w- | wc -l`
@ msg2 = $msg2 - 7
if ( $msg2 ) then
- echo "Number of writeable lines = $msg2" >>&! gtm_test_install.out
- ls -al * | grep -v \> | grep w- >>&! gtm_test_install.out
+ echo "Number of writeable lines = $msg2" >>&! gtm_test_install.out
+ ls -al * | grep -v \> | grep w- >>&! gtm_test_install.out
endif
setenv gtm_dist .
-gtm << EOF >>&! gtm_test_install.out
+gtm << EOF >>&! gtm_test_install.out
write \$zchset
EOF
@@ -197,14 +193,14 @@ if ( -d utf8) then
setenv LD_LIBRARY_PATH $libpath
setenv LIBPATH $libpath
setenv gtm_chset utf-8
- set utflocale = `locale -a | grep -i en_us | grep -i utf | sed 's/.lp64$//' | grep '8$' | head -n1`
+ set utflocale = `locale -a | grep -i en_us | grep -i utf | sed 's/.lp64$//' | grep '8$' | head -n 1`
if ( "OS/390" == `uname` ) then
setenv gtm_chset_locale $utflocale
else
setenv LC_ALL $utflocale
endif
-gtm << EOF >>&! gtm_test_install.out
+gtm << EOF >>&! gtm_test_install.out
write \$zchset
EOF
@@ -220,24 +216,33 @@ EOF
# make gtm set the utf locale
unsetenv LC_CTYPE
../gtm -r sim >& gtm.out
+
# get $ZCHSET
- echo "" >>&! $save_gtm_dist/gtm_test_install.out
- grep ZCHSET gtm.out >>&! $save_gtm_dist/gtm_test_install.out
+ echo "" >>&! $save_gtm_dist/gtm_test_install.out
+ grep ZCHSET gtm.out >>&! $save_gtm_dist/gtm_test_install.out
+ # test gtmsecshr with an alternate user
+ set XCMD='do ^GTMHELP("",$ztrnlnm("gtm_dist")_"/gtmhelp.gld")'
+ su - gtmtest1 -c "env LD_LIBRARY_PATH=$libpath LC_ALL=$LC_ALL gtm_chset=UTF-8 gtm_dist=$gtm_dist gtmroutines='$gtmroutines' $gtm_dist/mumps -run %XCMD '${XCMD:q}' < /dev/null" > gtmtest.out #BYPASSOK line length
+ # if we see the 'Topic? ' prompt, all is well
+ grep -q '^Topic. $' gtmtest.out
+ if ( $status ) cat gtmtest.out >>&! $save_gtm_dist/gtm_test_install.out
# get journal output
cd V*/g
- $save_gtm_dist/mupip journal -extract -forward gtm.mjl >& mupip.out
- (setenv gtmgbldir $save_gtm_dist/test_gtm/mumps.gld; $save_gtm_dist/mupip integ -reg "*" >& integ.out)
+ $save_gtm_dist/mupip journal -extract -forward gtm.mjl >& mupip.out
+ env gtmgbldir=$save_gtm_dist/test_gtm/mumps.gld $save_gtm_dist/mupip integ -reg "*" >& integ.out
+
# output the change lines
- echo "" >>&! $save_gtm_dist/gtm_test_install.out
- echo "Global changes in the gtm.mjl file:" >>&! $save_gtm_dist/gtm_test_install.out
- grep = gtm.mjf | awk -F\\ '{print ($NF)}' >>&! $save_gtm_dist/gtm_test_install.out
- cat integ.out >>&! $save_gtm_dist/gtm_test_install.out
+ echo "" >>&! $save_gtm_dist/gtm_test_install.out
+ echo "Global changes in the gtm.mjl file:" >>&! $save_gtm_dist/gtm_test_install.out
+ awk -F\\ '/=/{print ($NF)}' gtm.mjf >>&! $save_gtm_dist/gtm_test_install.out
+ cat integ.out >>&! $save_gtm_dist/gtm_test_install.out
+ $gtm_dist/gtmsecshr >>&! $save_gtm_dist/gtm_test_install.out
cd $save_gtm_dist
else
-
-cat <<EOF >>&! gtm_test_install.out
+ # BEGIN - Fake the UTF-8 mode run for platforms that don't support it
+cat <<EOF >>&! gtm_test_install.out
GTM>
UTF-8
@@ -262,6 +267,7 @@ Data 2 2 0.585 2
Free 4994 NA NA NA
Total 5000 7 NA 4
EOF
+ # END - Fake the UTF-8 mode run for platforms that don't support it
endif
# strip off the copyright lines
diff --git a/sr_unix/gtm_text_alloc.c b/sr_unix/gtm_text_alloc.c
index aa36d3a..1d218e6 100644
--- a/sr_unix/gtm_text_alloc.c
+++ b/sr_unix/gtm_text_alloc.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2007, 2012 Fidelity Information Services, Inc *
+ * Copyright 2007, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -10,14 +10,14 @@
****************************************************************/
/* Storage manager for mmap() allocated storage used for executable code.
- Uses power-of-two "buddy" system as described by Knuth. Allocations up to
- size <pagesize> - SIZEOF(header) are managed by the buddy system. Larger
- sizes are only "tracked" and then released via munmap() when they are freed.
-
- The algorithms used in this module are very similar to those used in
- gtm_malloc.c with some changes and fewer of the generation options
- since this is a more special purpose type allocation mechanism.
-*/
+ * Uses power-of-two "buddy" system as described by Knuth. Allocations up to
+ * size <pagesize> - SIZEOF(header) are managed by the buddy system. Larger
+ * sizes are only "tracked" and then released via munmap() when they are freed.
+ *
+ * The algorithms used in this module are very similar to those used in
+ * gtm_malloc.c with some changes and fewer of the generation options
+ * since this is a more special purpose type allocation mechanism.
+ */
#include "mdef.h"
@@ -45,30 +45,32 @@
GBLREF int process_exiting; /* Process is on it's way out */
GBLREF volatile int4 fast_lock_count; /* Stop stale/epoch processing while we have our parts exposed */
GBLREF uint4 gtmDebugLevel;
+GBLREF size_t gtm_max_storalloc; /* Max value for $ZREALSTOR or else memory error is raised */
OS_PAGE_SIZE_DECLARE
#ifdef COMP_GTA /* Only build this routine if it is going to be called */
/* This module is built in two different ways: (1) For z/OS the allocation and free routines will just call
- __malloc31() and free() respectively since mmap() on z/OS does not support the necessary features as of this
- writing (12/2008). (2) For all other platforms that use this module (Linux and Tru64 builds currently), the
- module will expand with the mmap code. [SE 12/2008]
-*/
+ * __malloc31() and free() respectively since mmap() on z/OS does not support the necessary features as of this
+ * writing (12/2008). (2) For all other platforms that use this module (Linux and Tru64 builds currently), the
+ * module will expand with the mmap code. [SE 12/2008]
+ */
/* The MAXTWO is set to pagesize and MINTWO to 5 sizes below that. Our systems have page
- sizes of 16K, 8K, and 4K.
-*/
+ * sizes of 16K, 8K, and 4K.
+ */
#define MAXTWO gtm_os_page_size
#define MINTWO TwoTable[0] /* Computed by gtaSmInit() */
#define MAXINDEX 5
/* Fields to help instrument our algorithm */
-GBLREF ssize_t totalRallocGta; /* Total storage currently (real) mmap alloc'd */
-GBLREF ssize_t totalAllocGta; /* Total mmap allocated (includes allocation overhead but not free space */
-GBLREF ssize_t totalUsedGta; /* Sum of "in-use" portions (totalAllocGta - overhead) */
+GBLREF size_t totalRmalloc; /* Total storage allocated through malloc() */
+GBLREF size_t totalRallocGta; /* Total storage currently (real) mmap alloc'd */
+GBLREF size_t totalAllocGta; /* Total mmap allocated (includes allocation overhead but not free space */
+GBLREF size_t totalUsedGta; /* Sum of "in-use" portions (totalAllocGta - overhead) */
static int totalAllocs; /* Total alloc requests */
static int totalFrees; /* Total free requests */
-static ssize_t rAllocMax; /* Maximum value of totalRalloc */
+static size_t rAllocMax; /* Maximum value of totalRallocGta */
static int allocCnt[MAXINDEX + 2]; /* Alloc count satisfied by each queue size */
static int freeCnt[MAXINDEX + 2]; /* Free count for element in each queue size */
static int elemSplits[MAXINDEX + 2]; /* Times a given queue size block was split */
@@ -110,19 +112,19 @@ static uint4 TwoTable[MAXINDEX + 2];
#include "obj_file.h"
/* This function is meant as a temporary replacement for the gtm_text_alloc code that uses mmap.
- ABS 2008/12 - It is deficient in two regards:
- 1) It abuses textElem - the abuse stems from account needs. It was hoped that we could simply
- abuse textElem to hold the actual length of memory allocated and then use the size of textElem
- as the offset to the original start of memory address that was malloc'ed. However, the
- userStart of memory needs to be SECTION_ALIGN_BOUNDARY byte aligned.
- action: don't use textElem
- 2) SECTION_ALIGN_BOUNDARY is 16 bytes in 64bit world. Since __malloc31 is returning 8 byte
- aligned memory, we really only needed a pad of 8 bytes. But that left no real mechanism to
- return to the original start of memory. So we have a pad of 24 bytes. The first 8 bytes point
- back to the start of memory. If the next 8 bytes are 16 byte aligned that is returned to the
- caller. If not, then we store the start of memory there and return the next 8 bytes. This allows
- us to free() the correct address.
- action: remove SECTION_ALIGN_BOUNDARY as a restriction for all 64bit platforms except IA64
+ * ABS 2008/12 - It is deficient in two regards:
+ * 1) It abuses textElem - the abuse stems from account needs. It was hoped that we could simply
+ * abuse textElem to hold the actual length of memory allocated and then use the size of textElem
+ * as the offset to the original start of memory address that was malloc'ed. However, the
+ * userStart of memory needs to be SECTION_ALIGN_BOUNDARY byte aligned.
+ * action: don't use textElem
+ * 2) SECTION_ALIGN_BOUNDARY is 16 bytes in 64bit world. Since __malloc31 is returning 8 byte
+ * aligned memory, we really only needed a pad of 8 bytes. But that left no real mechanism to
+ * return to the original start of memory. So we have a pad of 24 bytes. The first 8 bytes point
+ * back to the start of memory. If the next 8 bytes are 16 byte aligned that is returned to the
+ * caller. If not, then we store the start of memory there and return the next 8 bytes. This allows
+ * us to free() the correct address.
+ * action: remove SECTION_ALIGN_BOUNDARY as a restriction for all 64bit platforms except IA64
*/
void *gtm_text_alloc(size_t size)
{
@@ -150,21 +152,19 @@ void *gtm_text_alloc(size_t size)
INCR_SUM(totalAllocGta, tSize);
INCR_SUM(totalUsedGta, tSize);
INCR_CNTR(totalAllocs);
- SET_MAX(rAllocMax, totalUsedGta);
+ SET_MAX(rAllocMax, totalRallocGta);
TRACE_TXTALLOC(aligned, tSize);
return (void *)aligned;
}
-
save_errno = errno;
if (ENOMEM == save_errno)
{
assert(FALSE);
- rts_error(VARLSTCNT(5) ERR_MEMORY, 2, tSize, CALLERID, save_errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_MEMORY, 2, tSize, CALLERID, save_errno);
}
/* On non-allocate related error, give more general error and GTMASSERT */
- gtm_putmsg(VARLSTCNT(14) ERR_SYSCALL, 5, LEN_AND_LIT("gtm_text_alloc()"), CALLFROM,
- save_errno, 0,
- ERR_TEXT, 3, LEN_AND_LIT("Storage call made from"), CALLERID);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(14) ERR_SYSCALL, 5, LEN_AND_LIT("gtm_text_alloc()"), CALLFROM,
+ save_errno, 0, ERR_TEXT, 3, LEN_AND_LIT("Storage call made from"), CALLERID);
GTMASSERT;
}
@@ -195,6 +195,12 @@ void gtm_text_free(void *addr)
# define TEXT_ALLOC(rsize, addr) \
{ \
int save_errno; \
+ if ((0 < gtm_max_storalloc) && ((rsize + totalRmalloc + totalRallocGta) > gtm_max_storalloc)) \
+ { /* Boundary check for $gtm_max_storalloc (if set) */ \
+ --gtaSmDepth; \
+ --fast_lock_count; \
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_MEMORY, 2, rsize, CALLERID, ERR_MALLOCMAXUNIX); \
+ } \
addr = mmap(NULL, rsize, (PROT_READ + PROT_WRITE + PROT_EXEC), (MAP_PRIVATE + MAP_ANONYMOUS), -1, 0); \
if (MAP_FAILED == addr) \
{ \
@@ -204,12 +210,11 @@ void gtm_text_free(void *addr)
if (ENOMEM == save_errno) \
{ \
assert(FALSE); \
- rts_error(VARLSTCNT(5) ERR_MEMORY, 2, rsize, CALLERID, save_errno); \
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_MEMORY, 2, rsize, CALLERID, save_errno); \
} \
/* On non-allocate related error, give more general error and GTMASSERT */ \
- gtm_putmsg(VARLSTCNT(14) ERR_SYSCALL, 5, LEN_AND_LIT("mmap()"), CALLFROM, \
- save_errno, 0, \
- ERR_CALLERID, 3, LEN_AND_LIT("TEXT_ALLOC"), CALLERID); \
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(14) ERR_SYSCALL, 5, LEN_AND_LIT("mmap()"), CALLFROM, \
+ save_errno, 0, ERR_CALLERID, 3, LEN_AND_LIT("TEXT_ALLOC"), CALLERID); \
GTMASSERT; \
} \
}
@@ -222,18 +227,17 @@ void gtm_text_free(void *addr)
--gtaSmDepth; \
--fast_lock_count; \
save_errno = errno; \
- gtm_putmsg(VARLSTCNT(14) ERR_SYSCALL, 5, LEN_AND_LIT("munmap"), CALLFROM, \
- save_errno, 0, \
- ERR_CALLERID, 3, LEN_AND_LIT("TEXT_FREE"), CALLERID); \
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(14) ERR_SYSCALL, 5, LEN_AND_LIT("munmap"), CALLFROM, \
+ save_errno, 0, ERR_CALLERID, 3, LEN_AND_LIT("TEXT_FREE"), CALLERID); \
GTMASSERT; \
} \
}
-
#define STE_FP(p) p->userStorage.links.fPtr
#define STE_BP(p) p->userStorage.links.bPtr
/* Following are values used in queueIndex in a storage element. Note that both
- values must be less than zero for the current code to function correctly. */
+ * values must be less than zero for the current code to function correctly.
+ */
#define QUEUE_ANCHOR -1
#define REAL_ALLOC -2
@@ -244,7 +248,8 @@ void gtm_text_free(void *addr)
#endif
/* Define "routines" to enqueue and dequeue storage elements. Use define so we don't
- have to depend on each implementation's compiler inlining to get efficient code here */
+ * have to depend on each implementation's compiler inlining to get efficient code here.
+ */
#define ENQUEUE_STOR_ELEM(idx, elem) \
{ \
textElem *qHdr, *fElem; \
@@ -284,7 +289,7 @@ GBLREF readonly struct
static uint4 TwoTable[MAXINDEX + 2];
static textElem freeStorElemQs[MAXINDEX + 1]; /* Need full element as queue anchor for dbl-linked
- list since ptrs not at top of element */
+ * list since ptrs not at top of element */
static volatile int4 gtaSmDepth; /* If we get nested... */
static boolean_t gtaSmInitialized; /* Initialized indicator */
@@ -300,17 +305,19 @@ error_def(ERR_SYSCALL);
error_def(ERR_MEMORYRECURSIVE);
error_def(ERR_CALLERID);
error_def(ERR_TEXT);
+error_def(ERR_MALLOCMAXUNIX);
/* Initialize the storage manangement system. Things to initialize:
-
- - Initialize size2Index table. This table is used to convert a malloc request size
- to a storage queue index.
- - Initialize queue anchor fwd/bkwd pointers to point to queue anchors so we
- build a circular queue. This allows elements to be added and removed without
- end-of-queue special casing. The queue anchor element is easily recognized because
- it's queue index size will be set to a special value.
- - Initialize debug mode. See if gtm_debug_level environment variable is set and
- retrieve it's value if yes. */
+ *
+ * - Initialize size2Index table. This table is used to convert a malloc request size
+ * to a storage queue index.
+ * - Initialize queue anchor fwd/bkwd pointers to point to queue anchors so we
+ * build a circular queue. This allows elements to be added and removed without
+ * end-of-queue special casing. The queue anchor element is easily recognized because
+ * it's queue index size will be set to a special value.
+ * - Initialize debug mode. See if gtm_debug_level environment variable is set and
+ * retrieve it's value if yes.
+ */
void gtaSmInit(void)
{
char *ascNum;
@@ -318,11 +325,10 @@ void gtaSmInit(void)
int i, sizeIndex, twoSize;
/* WARNING!! Since this is early initialization, the assert(s) below are not well behaved if they do
- indeed trip. The best that can be hoped for is they give a condition handler exhausted error on
- GTM startup. Unfortunately, more intelligent responses are somewhat elusive since no output devices
- are setup nor (potentially) most of the GTM runtime.
- */
-
+ * indeed trip. The best that can be hoped for is they give a condition handler exhausted error on
+ * GTM startup. Unfortunately, more intelligent responses are somewhat elusive since no output devices
+ * are setup nor (potentially) most of the GTM runtime.
+ */
/* Initialize the TwoTable fields for our given page size */
TwoTable[MAXINDEX + 1] = 0xFFFFFFFF;
for (sizeIndex = MAXINDEX, twoSize = gtm_os_page_size; 0 <= sizeIndex; --sizeIndex, twoSize >>= 1)
@@ -331,7 +337,6 @@ void gtaSmInit(void)
TwoTable[sizeIndex] = twoSize;
assert(TwoTable[sizeIndex] < TwoTable[sizeIndex + 1]);
}
-
/* Need to initialize the fwd/bck ptrs in the anchors to point to themselves */
for (uStor = &freeStorElemQs[0], i = 0; i <= MAXINDEX; ++i, ++uStor)
{
@@ -342,12 +347,13 @@ void gtaSmInit(void)
}
/* Recursive routine used to obtain an element on a given size queue. If no
- elements of that size are available, we recursively call ourselves to get
- an element of the next larger queue which we will then split in half to
- get the one we need and place the remainder back on the free queue of its
- new smaller size. If we run out of queues, we obtain a fresh new 'hunk' of
- storage, carve it up into the largest block size we handle and process as
- before. */
+ * elements of that size are available, we recursively call ourselves to get
+ * an element of the next larger queue which we will then split in half to
+ * get the one we need and place the remainder back on the free queue of its
+ * new smaller size. If we run out of queues, we obtain a fresh new 'hunk' of
+ * storage, carve it up into the largest block size we handle and process as
+ * before.
+ */
textElem *gtaFindStorElem(int sizeIndex)
{
unsigned char *uStorAlloc;
@@ -381,9 +387,7 @@ textElem *gtaFindStorElem(int sizeIndex)
uStor->state = TextFree;
sizeIndex = MAXINDEX;
}
-
assert(sizeIndex >= 0 && sizeIndex <= MAXINDEX);
-
uStor->queueIndex = sizeIndex; /* This is now a smaller block */
return uStor;
}
@@ -396,12 +400,11 @@ int getSizeIndex(size_t size)
testSize = MAXTWO;
sizeIndex = MAXINDEX;
-
/* Theory here is to hunt for first significant bit. Then if there is more to the word, bump back
- to previous queue size. Note that in the following loop, the sizeIndex can go negative if the
- value of size is less than MINTWO (which is queue index 0) but since we guarantee there will be a
- remainder, we will increment back to 0. */
-
+ * to previous queue size. Note that in the following loop, the sizeIndex can go negative if the
+ * value of size is less than MINTWO (which is queue index 0) but since we guarantee there will be a
+ * remainder, we will increment back to 0.
+ */
while (0 == (testSize & size))
{
--sizeIndex; /* Try next smaller queue */
@@ -410,10 +413,8 @@ int getSizeIndex(size_t size)
else /* Else leave loop with last valid testSize */
break;
}
-
if (0 != (size & (testSize - 1))) /* Is there a remainder? */
++sizeIndex; /* .. if yes, round up a size */
-
return sizeIndex;
}
@@ -427,7 +428,8 @@ void *gtm_text_alloc(size_t size)
boolean_t reentered;
/* Note that this if is also structured for maximum fallthru. The else will
- be near the end of this entry point */
+ * be near the end of this entry point.
+ */
if (gtaSmInitialized)
{
hdrSize = OFFSETOF(textElem, userStorage); /* Size of textElem header */
@@ -442,7 +444,7 @@ void *gtm_text_alloc(size_t size)
{
--gtaSmDepth;
assert(FALSE);
- rts_error(VARLSTCNT(1) ERR_MEMORYRECURSIVE);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MEMORYRECURSIVE);
}
INCR_CNTR(totalAllocs);
if (0 != size)
@@ -495,17 +497,14 @@ void gtm_text_free(void *addr)
return;
if (!gtaSmInitialized) /* Storage must be init'd before can free anything */
GTMASSERT;
-
++fast_lock_count;
++gtaSmDepth; /* Recursion indicator */
-
if (1 < gtaSmDepth)
{
--gtaSmDepth;
assert(FALSE);
- rts_error(VARLSTCNT(1) ERR_MEMORYRECURSIVE);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MEMORYRECURSIVE);
}
-
INCR_CNTR(totalFrees);
if ((unsigned char *)addr != &NullStruct.nullStr[0])
{
@@ -561,10 +560,10 @@ void gtm_text_free(void *addr)
#endif /* not __MVS__ */
/* Routine to print the end-of-process info -- either allocation statistics or malloc trace dump.
- Note that the use of FPRINTF here instead of util_out_print is historical. The output was at one
- time going to stdout and util_out_print goes to stderr. If necessary or desired, these could easily
- be changed to use util_out_print instead of FPRINTF
-*/
+ * Note that the use of FPRINTF here instead of util_out_print is historical. The output was at one
+ * time going to stdout and util_out_print goes to stderr. If necessary or desired, these could easily
+ * be changed to use util_out_print instead of FPRINTF
+ */
void printAllocInfo(void)
{
textElem *eHdr, *uStor;
diff --git a/sr_unix/gtm_trigger.c b/sr_unix/gtm_trigger.c
index a451d60..1856e63 100644
--- a/sr_unix/gtm_trigger.c
+++ b/sr_unix/gtm_trigger.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2010, 2012 Fidelity Information Services, Inc *
+ * Copyright 2010, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -19,6 +19,7 @@
#include <errno.h>
+#include "cmd_qlf.h"
#include "compiler.h"
#include "error.h"
#include <rtnhdr.h>
@@ -454,7 +455,7 @@ int gtm_trigger_complink(gv_trigger_t *trigdsc, boolean_t dolink)
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 */
- op_zcompile(&zcompprm, FALSE); /* Compile but don't require a .m file extension */
+ 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))
{ /* Someone err'd.. */
@@ -975,7 +976,7 @@ void gtm_trigger_cleanup(gv_trigger_t *trigdsc)
stp_move((char *)rtnhdr->literal_text_adr,
(char *)(rtnhdr->literal_text_adr + rtnhdr->literal_text_len));
GTM_TEXT_FREE(rtnhdr->ptext_adr); /* R/O releasable section */
- free(rtnhdr->literal_adr); /* R/W releasable section part 1 */
+ free(RW_REL_START_ADR(rtnhdr)); /* R/W releasable section part 1 */
free(rtnhdr->linkage_adr); /* R/W releasable section part 2 */
free(rtnhdr->labtab_adr); /* Usually non-releasable but triggers don't have labels so
* this is just cleaning up a dangling null malloc
diff --git a/sr_unix/gtm_unlink_all.c b/sr_unix/gtm_unlink_all.c
index 97402dc..0b00753 100644
--- a/sr_unix/gtm_unlink_all.c
+++ b/sr_unix/gtm_unlink_all.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2011, 2012 Fidelity Information Services, Inc *
+ * Copyright 2011, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -15,6 +15,7 @@
#include "error_trap.h"
#include "golevel.h"
#include "cache.h"
+#include "cmd_qlf.h"
#include "hashtab.h"
#include "hashtab_objcode.h"
#include "hashtab_mname.h"
@@ -156,7 +157,7 @@ void gtm_unlink_all(void)
if (NULL == rtnhdr->shlib_handle)
/* We can only release this section if this is not a shared library */
GTM_TEXT_FREE(rtnhdr->ptext_adr); /* R/O releasable section */
- free(rtnhdr->literal_adr); /* R/W releasable section part 1 */
+ free(RW_REL_START_ADR(rtnhdr)); /* R/W releasable section part 1 */
free(rtnhdr->linkage_adr); /* R/W releasable section part 2 */
free(rtnhdr->labtab_adr); /* Usually non-releasable but not in this case */
/* Run the chain of old (replaced) versions freeing them also */
diff --git a/sr_unix/gtmci.c b/sr_unix/gtmci.c
index cb5df8e..0f66971 100644
--- a/sr_unix/gtmci.c
+++ b/sr_unix/gtmci.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -13,6 +13,9 @@
#include <stdarg.h>
#include "gtm_stdio.h"
#include <errno.h>
+#ifdef GTM_PTHREAD
+# include <pthread.h>
+#endif
#include "gtm_stdlib.h"
#include "gtm_string.h"
#include "cli.h"
@@ -61,6 +64,9 @@ GBLREF u_casemap_t gtm_strToTitle_ptr; /* Function pointer for gtm_strToTitle
#include "compiler.h"
#include "gt_timer.h"
#include "have_crit.h"
+#include "callg.h"
+#include "min_max.h"
+#include "gtm_limits.h"
GBLREF parmblk_struct *param_list;
GBLREF stack_frame *frame_pointer;
@@ -75,17 +81,79 @@ GBLREF mval dollar_zstatus;
GBLREF unsigned char *fgncal_stack;
GBLREF uint4 dollar_tlevel;
GBLREF int process_exiting;
+#ifdef GTM_PTHREAD
+GBLREF boolean_t gtm_jvm_process;
+GBLREF pthread_t gtm_main_thread_id;
+GBLREF boolean_t gtm_main_thread_id_set;
+#endif
+GBLREF char gtm_dist[GTM_PATH_MAX];
GTMTRIG_DBG_ONLY(GBLREF ch_ret_type (*ch_at_trigger_init)();)
+LITREF gtmImageName gtmImageNames[];
+error_def(ERR_ACTLSTTOOLONG);
error_def(ERR_CALLINAFTERXIT);
error_def(ERR_CIMAXLEVELS);
error_def(ERR_CINOENTRY);
error_def(ERR_CIRCALLNAME);
error_def(ERR_CITPNESTED);
error_def(ERR_INVGTMEXIT);
+error_def(ERR_JOBLABOFF);
error_def(ERR_MAXACTARG);
error_def(ERR_MAXSTRLEN);
+#define REVERT_AND_RETURN \
+{ \
+ REVERT; /* gtmci_ch */ \
+ TREF(in_gtmci) = FALSE; \
+ return 0; \
+}
+
+/* When passing arguments from Java, ensure that the expected types match the actual ones. If not,
+ * use the arg_types array to pass back the information needed for a detailed error message.
+ */
+#define CHECK_FOR_TYPE_MISMATCH(INDEX, EXP_TYPE, ACT_TYPE) \
+{ \
+ if (EXP_TYPE != ACT_TYPE) \
+ { \
+ arg_types[3] = ACT_TYPE; \
+ arg_types[2] = EXP_TYPE; \
+ arg_types[1] = INDEX; \
+ arg_types[0] = -1; \
+ REVERT_AND_RETURN; \
+ } \
+}
+
+/* When passing arguments from Java, ensure that the either of the expected types matches the actual one.
+ * If not, use the arg_types array to pass back the information needed for a detailed error message.
+ */
+#define CHECK_FOR_TYPES_MISMATCH(INDEX, EXP_TYPE1, EXP_TYPE2, ACT_TYPE) \
+{ \
+ if ((EXP_TYPE1 != ACT_TYPE) && (EXP_TYPE2 != ACT_TYPE)) \
+ { \
+ arg_types[4] = ACT_TYPE; \
+ arg_types[3] = EXP_TYPE1; \
+ arg_types[2] = EXP_TYPE2; \
+ arg_types[1] = INDEX; \
+ arg_types[0] = -1; \
+ REVERT_AND_RETURN; \
+ } \
+}
+
+/* When returning a typed value, ensure that the declared type matches the expected one. If not,
+ * use the arg_types array to pass back the information needed for a detailed error message.
+ */
+#define CHECK_FOR_RET_TYPE_MISMATCH(INDEX, EXP_TYPE, ACT_TYPE) \
+{ \
+ if ((0 == INDEX) && (EXP_TYPE != ACT_TYPE)) \
+ { \
+ arg_types[3] = ACT_TYPE; \
+ arg_types[2] = EXP_TYPE; \
+ arg_types[1] = 0; \
+ arg_types[0] = -1; \
+ REVERT_AND_RETURN; \
+ } \
+}
+
static callin_entry_list* get_entry(const char* call_name)
{ /* Lookup in a hashtable for entry corresponding to routine name */
ht_ent_str *callin_entry;
@@ -100,6 +168,327 @@ static callin_entry_list* get_entry(const char* call_name)
return (callin_entry ? callin_entry->value : NULL);
}
+int gtm_is_main_thread()
+{
+# ifdef GTM_PTHREAD
+ if (!gtm_main_thread_id_set)
+ return -1;
+ if (pthread_equal(gtm_main_thread_id, pthread_self()))
+ return 1;
+ return 0;
+# else
+ return -1;
+# endif
+}
+
+/* Java-specific version of call-in handler. */
+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)
+{
+ callin_entry_list *entry;
+ mstr label, routine;
+ int has_return, i, len;
+ rhdtyp *base_addr;
+ uint4 inp_mask, out_mask, mask;
+ mval arg_mval, *arg_ptr;
+ enum gtm_types arg_type;
+ gtm_string_t *mstr_parm;
+ parmblk_struct param_blk;
+ void op_extcall(), op_extexfun(), flush_pio(void);
+ volatile int *save_var_on_cstack_ptr; /* Volatile to match global var type */
+ int status;
+ boolean_t added;
+ stringkey symkey;
+ ht_ent_str *syment;
+ intrpt_state_t old_intrpt_state;
+ char **arg_blob_ptr;
+ int *java_arg_type;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ set_blocksig();
+ added = FALSE;
+ /* A prior invocation of gtm_exit would have set process_exiting = TRUE. Use this to disallow gtm_ci to be
+ * invoked after a gtm_exit
+ */
+ if (process_exiting)
+ {
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_CALLINAFTERXIT);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_CALLINAFTERXIT);
+ return ERR_CALLINAFTERXIT;
+ }
+ TREF(in_gtmci) = TRUE;
+ if (!gtm_startup_active || !(frame_pointer->flags & SFF_CI))
+ {
+ if ((status = gtm_init()) != 0)
+ {
+ TREF(in_gtmci) = FALSE;
+ return status;
+ }
+ }
+ GTM_PTHREAD_ONLY(assert(gtm_main_thread_id_set && pthread_equal(gtm_main_thread_id, pthread_self())));
+ ESTABLISH_RET(gtmci_ch, mumps_status);
+ if (msp < fgncal_stack) /* Unwind all arguments left on the stack by previous gtm_cij. */
+ fgncal_unwind();
+ if (!c_rtn_name)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_CIRCALLNAME);
+ if (!TREF(ci_table)) /* Load the call-in table only once from env variable GTMCI. */
+ {
+ TREF(ci_table) = citab_parse();
+ if (!TREF(callin_hashtab))
+ {
+ TREF(callin_hashtab) = (hash_table_str *)malloc(SIZEOF(hash_table_str));
+ (TREF(callin_hashtab))->base = NULL;
+ /* Need to initialize hash table. */
+ init_hashtab_str(TREF(callin_hashtab), CALLIN_HASHTAB_SIZE,
+ HASHTAB_NO_COMPACT, HASHTAB_NO_SPARE_TABLE);
+ assert((TREF(callin_hashtab))->base);
+ }
+ for (entry = TREF(ci_table); NULL != entry; entry = entry->next_entry)
+ { /* Loop over the list and populate the hash table. */
+ symkey.str.addr = entry->call_name.addr;
+ symkey.str.len = entry->call_name.len;
+ COMPUTE_HASH_STR(&symkey);
+ added = add_hashtab_str(TREF(callin_hashtab), &symkey, entry, &syment);
+ assert(added);
+ assert(syment->value == entry);
+ }
+ }
+ if (!(entry = get_entry(c_rtn_name))) /* c_rtn_name not found in the table. */
+ 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))
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBLABOFF);
+ memset(¶m_blk, 0, SIZEOF(param_blk));
+ param_blk.rtnaddr = (void *)base_addr;
+ /* lnr_entry below is a pointer to the code offset for this label from the
+ * beginning of text base(on USHBIN platforms) or from the beginning of routine
+ * header (on NON_USHBIN platforms).
+ * On NON_USHBIN platforms -- 2nd argument to EXTCALL is this pointer
+ * On USHBIN -- 2nd argument to EXTCALL is the pointer to this pointer (&lnr_entry)
+ */
+ /* Assign the address for line number entry storage, so that the adjacent address holds has_parms value. */
+ param_blk.labaddr = &(TREF(lab_proxy)).LABENT_LNR_OFFSET;
+ if (MAX_ACTUALS < entry->argcnt)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MAXACTARG);
+ if (entry->argcnt < count)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ACTLSTTOOLONG, 2, (int)label.len, label.addr);
+ param_blk.argcnt = count;
+ has_return = (gtm_void != entry->return_type);
+ if (has_return)
+ { /* Create mval slot for return value */
+ MV_INIT(&arg_mval);
+ param_blk.retaddr = (void *)push_lvval(&arg_mval);
+ arg_blob_ptr = &arg_blob[0] + GTM64_ONLY(1) NON_GTM64_ONLY(2);
+ java_arg_type = arg_types + 1;
+ } else
+ {
+ param_blk.retaddr = 0;
+ arg_blob_ptr = &arg_blob[0];
+ java_arg_type = arg_types;
+ }
+ inp_mask = entry->input_mask;
+ out_mask = entry->output_mask;
+ *io_vars_mask = out_mask;
+ if (*has_ret_value != has_return)
+ {
+ *has_ret_value = has_return;
+ REVERT_AND_RETURN;
+ }
+ *has_ret_value = has_return;
+ for (i = 0, mask = ~inp_mask; i < count; ++i, mask >>= 1, java_arg_type++, arg_blob_ptr += GTM64_ONLY(1) NON_GTM64_ONLY(2))
+ { /* Copy the arguments' values into mval containers. Since some arguments might be declared as output-only,
+ * we need to go over all of them unconditionally, but only do the copying for the ones that are used for
+ * the input direction (I or IO). The integer values passed to CHECK_FOR_TYPE_MISMATCH as a second argument
+ * indicate the types to expect according to the call-in table definition, and are in correspondence with the
+ * constants declared in GTMContainerType class in gtmji.jar: 0 for GTMBoolean, 1 for GTMInteger, and so on.
+ */
+ arg_mval.mvtype = MV_XZERO;
+ switch (entry->parms[i])
+ {
+ case gtm_jboolean:
+ CHECK_FOR_TYPE_MISMATCH(i + 1, 0, *java_arg_type);
+ if (!(mask & 1))
+ i2mval(&arg_mval, *(int *)arg_blob_ptr);
+ break;
+ case gtm_jint:
+ CHECK_FOR_TYPE_MISMATCH(i + 1, 1, *java_arg_type);
+ if (!(mask & 1))
+ i2mval(&arg_mval, *(int *)arg_blob_ptr);
+ break;
+ case gtm_jlong:
+ CHECK_FOR_TYPE_MISMATCH(i + 1, 2, *java_arg_type);
+ if (!(mask & 1))
+ i82mval(&arg_mval, *(gtm_int64_t *)arg_blob_ptr);
+ break;
+ case gtm_jfloat:
+ CHECK_FOR_TYPE_MISMATCH(i + 1, 3, *java_arg_type);
+ if (!(mask & 1))
+ float2mval(&arg_mval, *(float *)arg_blob_ptr);
+ break;
+ case gtm_jdouble:
+ CHECK_FOR_TYPE_MISMATCH(i + 1, 4, *java_arg_type);
+ if (!(mask & 1))
+ double2mval(&arg_mval, *(double *)arg_blob_ptr);
+ break;
+ case gtm_jstring:
+ CHECK_FOR_TYPES_MISMATCH(i + 1, 7, 5, *java_arg_type);
+ if (!(mask & 1))
+ {
+ mstr_parm = *(gtm_string_t **)arg_blob_ptr;
+ arg_mval.mvtype = MV_STR;
+ if (MAX_STRLEN < (uint4)mstr_parm->length)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MAXSTRLEN);
+ arg_mval.str.len = (mstr_len_t)mstr_parm->length;
+ arg_mval.str.addr = mstr_parm->address;
+ s2pool(&arg_mval.str);
+ }
+ break;
+ case gtm_jbyte_array:
+ CHECK_FOR_TYPES_MISMATCH(i + 1, 8, 6, *java_arg_type);
+ if (!(mask & 1))
+ {
+ mstr_parm = *(gtm_string_t **)arg_blob_ptr;
+ arg_mval.mvtype = MV_STR;
+ if (MAX_STRLEN < (uint4)mstr_parm->length)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MAXSTRLEN);
+ arg_mval.str.len = (mstr_len_t)mstr_parm->length;
+ arg_mval.str.addr = mstr_parm->address;
+ s2pool(&arg_mval.str);
+ }
+ break;
+ case gtm_jbig_decimal:
+ CHECK_FOR_TYPE_MISMATCH(i + 1, 9, *java_arg_type);
+ if (!(mask & 1))
+ {
+ mstr_parm = *(gtm_string_t **)arg_blob_ptr;
+ arg_mval.mvtype = MV_STR;
+ if (MAX_STRLEN < (uint4)mstr_parm->length)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MAXSTRLEN);
+ arg_mval.str.len = (mstr_len_t)mstr_parm->length;
+ arg_mval.str.addr = mstr_parm->address;
+ s2pool(&arg_mval.str);
+ }
+ break;
+ default: /* Indicate an invalid type. */
+ arg_types[1] = i + 1;
+ arg_types[0] = -2;
+ REVERT_AND_RETURN;
+ }
+ param_blk.args[i] = push_lvval(&arg_mval);
+ }
+ param_blk.mask = out_mask;
+ param_blk.ci_rtn = (!has_return && param_blk.argcnt <= 0)
+ ? (void (*)())CODE_ADDRESS_TYPE(op_extcall)
+ : (void (*)())CODE_ADDRESS_TYPE(op_extexfun);
+ /* The params block needs to be saved and restored across multiple GT.M environments. So, instead of storing it
+ * explicitely, setting the global param_list to point to local param_blk will do the job.
+ */
+ param_list = ¶m_blk;
+ old_intrpt_state = intrpt_ok_state;
+ intrpt_ok_state = INTRPT_OK_TO_INTERRUPT; /* Reset interrupt state for the new M session. */
+ save_var_on_cstack_ptr = var_on_cstack_ptr;
+ var_on_cstack_ptr = NULL; /* Reset var_on_cstack_ptr for the new M environment. */
+ assert(frame_pointer->flags & SFF_CI);
+ frame_pointer->mpc = frame_pointer->ctxt = PTEXT_ADR(frame_pointer->rvector);
+ REVERT; /* Revert gtmci_ch. */
+
+ ESTABLISH_RET(stop_image_conditional_core, mumps_status);
+ dm_start(); /* Kick off execution. */
+ REVERT;
+
+ intrpt_ok_state = old_intrpt_state; /* Restore the old interrupt state. */
+ var_on_cstack_ptr = save_var_on_cstack_ptr; /* Restore the old environment's var_on_cstack_ptr. */
+ if (1 != mumps_status)
+ {
+ TREF(in_gtmci) = FALSE;
+ /* dm_start() initializes mumps_status to 1 before execution. If mumps_status is not 1,
+ * it is either the unhandled error code propaged by $ZT/$ET (from mdb_condition_handler)
+ * or zero on returning from ZGOTO 0 (ci_ret_code_quit).
+ */
+ return mumps_status;
+ }
+ ESTABLISH_RET(gtmci_ch, mumps_status);
+ /* Convert mval args designated for output-only or input-output use to C types. */
+ arg_blob_ptr = &arg_blob[0];
+ for (i = 0; i <= count; ++i, arg_blob_ptr += GTM64_ONLY(1) NON_GTM64_ONLY(2))
+ {
+ if (0 == i) /* Special case for return value. */
+ {
+ if (!has_return)
+ {
+ arg_blob_ptr -= GTM64_ONLY(1) NON_GTM64_ONLY(2);
+ continue;
+ }
+ arg_ptr = &((lv_val *)(param_blk.retaddr))->v;
+ mask = 1;
+ arg_type = entry->return_type;
+ } else
+ {
+ arg_ptr = ¶m_blk.args[i - 1]->v;
+ mask = out_mask;
+ arg_type = entry->parms[i - 1];
+ out_mask >>= 1;
+ }
+ /* Do not process parameters that are either input-only(I) or output(O/IO)
+ * parameters that are not modified by the M routine.
+ */
+ if ((mask & 1) && MV_DEFINED(arg_ptr))
+ { /* Process all output (O/IO) parameters modified by the M routine */
+ switch (arg_type)
+ {
+ case gtm_jboolean:
+ CHECK_FOR_RET_TYPE_MISMATCH(i, 0, *arg_types);
+ *(gtm_int_t *)arg_blob_ptr = mval2double(arg_ptr) ? 1 : 0;
+ break;
+ case gtm_jint:
+ CHECK_FOR_RET_TYPE_MISMATCH(i, 1, *arg_types);
+ *(gtm_int_t *)arg_blob_ptr = mval2i(arg_ptr);
+ break;
+ case gtm_jlong:
+ CHECK_FOR_RET_TYPE_MISMATCH(i, 2, *arg_types);
+ *(gtm_int64_t *)arg_blob_ptr = mval2i8(arg_ptr);
+ break;
+ case gtm_jfloat:
+ CHECK_FOR_RET_TYPE_MISMATCH(i, 3, *arg_types);
+ *(gtm_float_t *)arg_blob_ptr = mval2double(arg_ptr);
+ break;
+ case gtm_jdouble:
+ CHECK_FOR_RET_TYPE_MISMATCH(i, 4, *arg_types);
+ *(gtm_double_t *)arg_blob_ptr = mval2double(arg_ptr);
+ break;
+ case gtm_jstring:
+ CHECK_FOR_RET_TYPE_MISMATCH(i, 7, *arg_types);
+ MV_FORCE_STR(arg_ptr);
+ (*(gtm_string_t **)arg_blob_ptr)->address = arg_ptr->str.addr;
+ (*(gtm_string_t **)arg_blob_ptr)->length = arg_ptr->str.len;
+ if (((unsigned char *)arg_ptr->str.addr + arg_ptr->str.len) == stringpool.top) /*BYPASSOK*/
+ { /* Since the ci_gateway.c code temporarily switches the character following the
+ * string's content in memory to '\n' (for generation of a proper Unicode string),
+ * ensure that this character is in the stringpool and not elsewhere.
+ */
+ ENSURE_STP_FREE_SPACE(1);
+ }
+ break;
+ case gtm_jbyte_array:
+ CHECK_FOR_RET_TYPE_MISMATCH(i, 8, *arg_types);
+ MV_FORCE_STR(arg_ptr);
+ (*(gtm_string_t **)arg_blob_ptr)->address = arg_ptr->str.addr;
+ (*(gtm_string_t **)arg_blob_ptr)->length = arg_ptr->str.len;
+ break;
+ case gtm_jbig_decimal: /* We currently do not support output for big decimal. */
+ break;
+ default:
+ GTMASSERT;
+ }
+ }
+ }
+ REVERT;
+ TREF(in_gtmci) = FALSE;
+ return 0;
+}
+
int gtm_ci_exec(const char *c_rtn_name, void *callin_handle, int populate_handle, va_list temp_var)
{
va_list var;
@@ -108,7 +497,6 @@ int gtm_ci_exec(const char *c_rtn_name, void *callin_handle, int populate_handle
int has_return, i;
rhdtyp *base_addr;
uint4 inp_mask, out_mask, mask;
- uint4 *lnr_entry;
mval arg_mval, *arg_ptr;
enum gtm_types arg_type;
gtm_string_t *mstr_parm;
@@ -132,18 +520,24 @@ int gtm_ci_exec(const char *c_rtn_name, void *callin_handle, int populate_handle
*/
if (process_exiting)
{
- gtm_putmsg(VARLSTCNT(1) ERR_CALLINAFTERXIT);
- send_msg(VARLSTCNT(1) ERR_CALLINAFTERXIT);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_CALLINAFTERXIT);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_CALLINAFTERXIT);
return ERR_CALLINAFTERXIT;
}
+ TREF(in_gtmci) = TRUE;
if (!gtm_startup_active || !(frame_pointer->flags & SFF_CI))
{
if ((status = gtm_init()) != 0)
+ {
+ TREF(in_gtmci) = FALSE;
return status;
+ }
}
ESTABLISH_RET(gtmci_ch, mumps_status);
if (msp < fgncal_stack) /* unwind all arguments left on the stack by previous gtm_ci */
fgncal_unwind();
+ if (!c_rtn_name)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_CIRCALLNAME);
if (!TREF(ci_table)) /* load the call-in table only once from env variable GTMCI */
{
TREF(ci_table) = citab_parse();
@@ -166,19 +560,18 @@ int gtm_ci_exec(const char *c_rtn_name, void *callin_handle, int populate_handle
assert(syment->value == entry);
}
}
- if (!c_rtn_name)
- rts_error(VARLSTCNT(1) ERR_CIRCALLNAME);
if (NULL == callin_handle)
{
if (!(entry = get_entry(c_rtn_name))) /* c_rtn_name not found in the table */
- rts_error(VARLSTCNT(4) ERR_CINOENTRY, 2, LEN_AND_STR(c_rtn_name));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_CINOENTRY, 2, LEN_AND_STR(c_rtn_name));
if (populate_handle)
callin_handle = entry;
} else
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 */
- job_addr(&routine, &label, 0, (char **)&base_addr, NULL);
+ if(!job_addr(&routine, &label, 0, (char **)&base_addr, NULL))
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBLABOFF);
memset(¶m_blk, 0, SIZEOF(param_blk));
param_blk.rtnaddr = (void *)base_addr;
/* lnr_entry below is a pointer to the code offset for this label from the
@@ -192,7 +585,7 @@ int gtm_ci_exec(const char *c_rtn_name, void *callin_handle, int populate_handle
param_blk.labaddr = &(TREF(lab_proxy)).LABENT_LNR_OFFSET;
param_blk.argcnt = entry->argcnt;
if (MAX_ACTUALS < param_blk.argcnt)
- rts_error(VARLSTCNT(1) ERR_MAXACTARG);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MAXACTARG);
has_return = (gtm_void == entry->return_type) ? 0 : 1;
if (has_return)
{ /* Create mval slot for return value */
@@ -268,14 +661,14 @@ int gtm_ci_exec(const char *c_rtn_name, void *callin_handle, int populate_handle
break;
case gtm_long:
# ifdef GTM64
- l2mval(&arg_mval, (long)va_arg(var, gtm_long_t));
+ i82mval(&arg_mval, (gtm_int64_t)va_arg(var, gtm_long_t));
# else
i2mval(&arg_mval, (int)va_arg(var, gtm_long_t));
# endif
break;
case gtm_ulong:
# ifdef GTM64
- ul2mval(&arg_mval, (unsigned long)va_arg(var, gtm_ulong_t));
+ ui82mval(&arg_mval, (gtm_uint64_t)va_arg(var, gtm_ulong_t));
# else
i2usmval(&arg_mval, (int)va_arg(var, gtm_ulong_t));
# endif
@@ -288,24 +681,26 @@ int gtm_ci_exec(const char *c_rtn_name, void *callin_handle, int populate_handle
break;
case gtm_long_star:
# ifdef GTM64
- l2mval(&arg_mval, (long)*va_arg(var, gtm_long_t *));
+ i82mval(&arg_mval, (gtm_int64_t)*va_arg(var, gtm_long_t *));
# else
i2mval(&arg_mval, (int)*va_arg(var, gtm_long_t *));
# endif
break;
case gtm_ulong_star:
# ifdef GTM64
- ul2mval(&arg_mval, (unsigned long)*va_arg(var, gtm_ulong_t *));
+ ui82mval(&arg_mval, (gtm_uint64_t)*va_arg(var, gtm_ulong_t *));
# else
i2usmval(&arg_mval, (int)*va_arg(var, gtm_ulong_t *));
# endif
break;
- case gtm_float: /* fall through */
+ case gtm_float:
+ float2mval(&arg_mval, (gtm_float_t)va_arg(var, gtm_double_t));
+ break;
case gtm_double:
double2mval(&arg_mval, va_arg(var, gtm_double_t));
break;
case gtm_float_star:
- double2mval(&arg_mval, *va_arg(var, gtm_float_t *));
+ float2mval(&arg_mval, *va_arg(var, gtm_float_t *));
break;
case gtm_double_star:
double2mval(&arg_mval, *va_arg(var, gtm_double_t *));
@@ -317,7 +712,7 @@ int gtm_ci_exec(const char *c_rtn_name, void *callin_handle, int populate_handle
if (MAX_STRLEN < arg_mval.str.len)
{
va_end(var);
- rts_error(VARLSTCNT(1) ERR_MAXSTRLEN);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MAXSTRLEN);
}
s2pool(&arg_mval.str);
break;
@@ -327,7 +722,7 @@ int gtm_ci_exec(const char *c_rtn_name, void *callin_handle, int populate_handle
if (MAX_STRLEN < (uint4)mstr_parm->length)
{
va_end(var);
- rts_error(VARLSTCNT(1) ERR_MAXSTRLEN);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MAXSTRLEN);
}
arg_mval.str.len = (mstr_len_t)mstr_parm->length;
arg_mval.str.addr = mstr_parm->address;
@@ -365,7 +760,9 @@ int gtm_ci_exec(const char *c_rtn_name, void *callin_handle, int populate_handle
intrpt_ok_state = old_intrpt_state; /* restore the old interrupt state */
var_on_cstack_ptr = save_var_on_cstack_ptr; /* restore the old environment's var_on_cstack_ptr */
if (1 != mumps_status)
- { /* dm_start() initializes mumps_status to 1 before execution. If mumps_status is not 1,
+ {
+ TREF(in_gtmci) = FALSE;
+ /* dm_start() initializes mumps_status to 1 before execution. If mumps_status is not 1,
* it is either the unhandled error code propaged by $ZT/$ET (from mdb_condition_handler)
* or zero on returning from ZGOTO 0 (ci_ret_code_quit).
*/
@@ -451,10 +848,12 @@ int gtm_ci_exec(const char *c_rtn_name, void *callin_handle, int populate_handle
*va_arg(temp_var, gtm_uint_t *) = mval2ui(arg_ptr);
break;
case gtm_long_star:
- *va_arg(temp_var, gtm_long_t *) = mval2i(arg_ptr);
+ *va_arg(temp_var, gtm_long_t *) =
+ GTM64_ONLY(mval2i8(arg_ptr)) NON_GTM64_ONLY(mval2i(arg_ptr));
break;
case gtm_ulong_star:
- *va_arg(temp_var, gtm_ulong_t *) = mval2ui(arg_ptr);
+ *va_arg(temp_var, gtm_ulong_t *) =
+ GTM64_ONLY(mval2ui8(arg_ptr)) NON_GTM64_ONLY(mval2ui(arg_ptr));
break;
case gtm_float_star:
*va_arg(temp_var, gtm_float_t *) = mval2double(arg_ptr);
@@ -482,12 +881,13 @@ int gtm_ci_exec(const char *c_rtn_name, void *callin_handle, int populate_handle
}
va_end(temp_var);
REVERT;
+ TREF(in_gtmci) = FALSE;
return 0;
}
int gtm_ci(const char *c_rtn_name, ...)
{
- va_list var;
+ va_list var;
VAR_START(var, c_rtn_name);
return gtm_ci_exec(c_rtn_name, NULL, FALSE, var);
@@ -496,16 +896,25 @@ int gtm_ci(const char *c_rtn_name, ...)
/* Functionality is same as that of gtmci but accepts a struct containing information about the routine. */
int gtm_cip(ci_name_descriptor* ci_info, ...)
{
- va_list var;
+ va_list var;
VAR_START(var, ci_info);
return gtm_ci_exec(ci_info->rtn_name.address, ci_info->handle, TRUE, var);
}
+#ifdef GTM_PTHREAD
+int gtm_jinit()
+{
+ gtm_jvm_process = TRUE;
+ return gtm_init();
+}
+#endif
+
int gtm_init()
{
rhdtyp *base_addr;
unsigned char *transfer_addr;
+ char *dist;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
@@ -519,10 +928,12 @@ int gtm_init()
*/
if (process_exiting)
{
- gtm_putmsg(VARLSTCNT(1) ERR_CALLINAFTERXIT);
- send_msg(VARLSTCNT(1) ERR_CALLINAFTERXIT);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_CALLINAFTERXIT);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_CALLINAFTERXIT);
return ERR_CALLINAFTERXIT;
}
+ if (!TREF(in_gtmci))
+ return 0;
if (!gtm_startup_active)
{ /* call-in invoked from C as base. GT.M hasn't been started up yet. */
gtm_imagetype_init(GTM_IMAGE);
@@ -544,6 +955,14 @@ int gtm_init()
invocation_mode = MUMPS_CALLIN;
init_gtm();
gtm_savetraps(); /* nullify default $ZTRAP handling */
+ if (NULL != (dist = (char *)GETENV(GTM_DIST)))
+ {
+ assert(IS_VALID_IMAGE && (n_image_types > image_type)); /* assert image_type is initialized */
+ if ((GTM_PATH_MAX - 2) <= (STRLEN(dist) + gtmImageNames[image_type].imageNameLen))
+ dist = NULL;
+ else
+ memcpy(gtm_dist, dist, STRLEN(dist));
+ }
assert(gtm_startup_active);
assert(frame_pointer->flags & SFF_CI);
TREF(gtmci_nested_level) = 1;
@@ -555,13 +974,13 @@ int gtm_init()
fgncal_stack = msp;
/* generate CIMAXLEVELS error if gtmci_nested_level > CALLIN_MAX_LEVEL */
if (CALLIN_MAX_LEVEL < TREF(gtmci_nested_level))
- rts_error(VARLSTCNT(3) ERR_CIMAXLEVELS, 1, TREF(gtmci_nested_level));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_CIMAXLEVELS, 1, TREF(gtmci_nested_level));
/* Disallow call-ins within a TP boundary since TP restarts are not supported
* currently across nested call-ins. When we implement TP restarts across call-ins,
* this error needs be changed to a Warning or Notification
*/
if (dollar_tlevel)
- rts_error(VARLSTCNT(1) ERR_CITPNESTED);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_CITPNESTED);
base_addr = make_cimode();
transfer_addr = PTEXT_ADR(base_addr);
gtm_init_env(base_addr, transfer_addr);
@@ -590,7 +1009,7 @@ int gtm_exit()
assert(NULL != frame_pointer);
/* Do not allow gtm_exit() to be invoked from external calls */
if (!(SFF_CI & frame_pointer->flags) || !(MUMPS_CALLIN & invocation_mode) || (1 < TREF(gtmci_nested_level)))
- rts_error(VARLSTCNT(1) ERR_INVGTMEXIT);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVGTMEXIT);
/* Now get rid of the whole M stack - end of GT.M environment */
while (NULL != frame_pointer)
{
diff --git a/sr_unix/gtmci_ch.c b/sr_unix/gtmci_ch.c
index b5cc546..823f915 100644
--- a/sr_unix/gtmci_ch.c
+++ b/sr_unix/gtmci_ch.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -47,6 +47,7 @@ CONDITION_HANDLER(gtmci_ch)
src_line.len = 0;
src_line.addr = &src_buf[0];
set_zstatus(&src_line, SIGNAL, NULL, FALSE);
+ TREF(in_gtmci) = FALSE;
if (msp < fgncal_stack) /* restore stack to the last marked position */
fgncal_unwind();
mumps_status = SIGNAL;
diff --git a/sr_unix/gtmcrypt.h b/sr_unix/gtmcrypt.h
index 456fb78..b628213 100644
--- a/sr_unix/gtmcrypt.h
+++ b/sr_unix/gtmcrypt.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2009, 2012 Fidelity Information Services, Inc *
+ * Copyright 2009, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -51,6 +51,7 @@ GBLREF boolean_t gtmcrypt_initialized;
LITREF char gtmcrypt_repeat_msg[];
error_def(ERR_CRYPTDLNOOPEN);
+error_def(ERR_CRYPTDLNOOPEN2);
error_def(ERR_CRYPTHASHGENFAILED);
error_def(ERR_CRYPTINIT);
error_def(ERR_CRYPTKEYFETCHFAILED);
@@ -102,7 +103,7 @@ uint4 gtmcrypt_entry(void);
#define CLEAR_CRYPTERR_MASK(ERRID) (ERRID = ((ERRID) & ~CRYPTERR_MASK))
#define CLEAR_REPEAT_MSG_MASK(ERRID) (ERRID = ((ERRID) & ~REPEAT_MSG_MASK))
-#define GTMCRYPT_REPORT_ERROR(ERRID, MECHANSIM, LEN, PTR) \
+#define GTMCRYPT_REPORT_ERROR(ERRID, MECHANISM, LEN, PTR) \
{ \
GBLREF char dl_err[]; \
\
@@ -114,16 +115,18 @@ uint4 gtmcrypt_entry(void);
CLEAR_CRYPTERR_MASK(errid); \
if (IS_REPEAT_MSG_MASK(errid)) \
errptr = >mcrypt_repeat_msg[0]; \
- else if ((ERR_CRYPTDLNOOPEN == errid) || (MAKE_MSG_WARNING(ERR_CRYPTDLNOOPEN) == errid)) \
+ else if ((ERR_CRYPTDLNOOPEN == errid) || (ERR_CRYPTDLNOOPEN2 == errid) \
+ || (MAKE_MSG_WARNING(ERR_CRYPTDLNOOPEN2) == errid) || (MAKE_MSG_WARNING(ERR_CRYPTDLNOOPEN) == errid)) \
+ { \
errptr = (const char *) &dl_err[0]; \
- else \
+ } else \
{ \
DEFER_INTERRUPTS(INTRPT_IN_CRYPT_SECTION); \
errptr = (const char *) (*gtmcrypt_strerror_fnptr)(); \
ENABLE_INTERRUPTS(INTRPT_IN_CRYPT_SECTION); \
} \
CLEAR_REPEAT_MSG_MASK(errid); \
- MECHANSIM(VARLSTCNT(6) errid, 4, LEN, PTR, LEN_AND_STR(errptr)); \
+ MECHANISM(VARLSTCNT(6) errid, 4, LEN, PTR, LEN_AND_STR(errptr)); \
}
@@ -189,7 +192,9 @@ uint4 gtmcrypt_entry(void);
RC = 0; \
prompt_passwd = PROMPT_PASSWD(ptr); \
if (prompt_passwd && dollar_tlevel) \
- rts_error(VARLSTCNT(1) ERR_CRYPTNOPSWDINTP); /* GT.M call-ins don't support TP transactions (see gtm_ci_exec)*/ \
+ { /* GT.M call-ins don't support TP transactions (see gtm_ci_exec) */ \
+ rts_error_csa(CSA_ARG(CSA) VARLSTCNT(1) ERR_CRYPTNOPSWDINTP); \
+ } \
assert(!IS_MUMPS_IMAGE || !(frame_pointer->flags & SFF_CI)); /* ensures not already in gtm_ci */ \
/* ALLOC_BUFF_GET_ENCR_KEY eventually invokes gtmcrypt_getkey_by_hash to obtain the encryption key for the concerned \
* database. At this point encryption initialization is already done (as part of INIT_PROC_ENCRYPTION) even if the \
@@ -234,7 +239,7 @@ uint4 gtmcrypt_entry(void);
prompt_passwd = PROMPT_PASSWD(ptr); \
if (prompt_passwd && dollar_tlevel) \
{ /* GT.M call-ins don't support TP transactions (see gtm_ci_exec)*/ \
- rts_error(VARLSTCNT(1) ERR_CRYPTNOPSWDINTP); \
+ rts_error_csa(CSA_ARG(CSA) VARLSTCNT(1) ERR_CRYPTNOPSWDINTP); \
} \
assert(!IS_MUMPS_IMAGE || !(frame_pointer->flags & SFF_CI)); /* ensures not already in gtm_ci */ \
/* If password is set to empty string, gtmcrypt_init (called below) invokes gtm_ci to obtain the \
diff --git a/sr_unix/gtmdbgflags.h b/sr_unix/gtmdbgflags.h
new file mode 100644
index 0000000..6b9903f
--- /dev/null
+++ b/sr_unix/gtmdbgflags.h
@@ -0,0 +1,49 @@
+/****************************************************************
+ * *
+ * Copyright 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef _GTMDBGFLAGS_H
+#define _GTMDBGFLAGS_H
+
+#ifdef GTMDBGFLAGS_ENABLED
+# define GTMDBGFLAGS_MASK_SET(MASK) (TREF(gtmdbgflags) & MASK)
+# define GTMDBGFLAGS_ONLY(MASK, ...) \
+{ \
+ DCL_THREADGBL_ACCESS; \
+ \
+ SETUP_THREADGBL_ACCESS; \
+ if (GTMDBGFLAGS_MASK_SET(MASK)) \
+ { \
+ (TREF(gtmdbgflags_freq_cntr))++; \
+ if (TREF(gtmdbgflags_freq) == TREF(gtmdbgflags_freq_cntr)) \
+ { \
+ __VA_ARGS__; \
+ TREF(gtmdbgflags_freq_cntr) = 0; \
+ } \
+ } \
+}
+# define GTMDBGFLAGS_NOFREQ_ONLY(MASK, ...) \
+{ \
+ DCL_THREADGBL_ACCESS; \
+ \
+ SETUP_THREADGBL_ACCESS; \
+ if (GTMDBGFLAGS_MASK_SET(MASK)) \
+ { \
+ __VA_ARGS__; \
+ } \
+}
+# define GTMSOURCE_FORCE_READ_FILE_MODE 0x00000001
+#else
+# define GTMDBGFLAGS_MASK_SET(MASK) FALSE
+# define GTMDBGFLAGS_ONLY(MASK, FREQ, ...)
+# define GTMDBGFLAGS_NOFREQ_ONLY(MASK, ...)
+#endif
+
+#endif
diff --git a/sr_unix/gtmio.h b/sr_unix/gtmio.h
index 6871f94..e1cf0ec 100644
--- a/sr_unix/gtmio.h
+++ b/sr_unix/gtmio.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -428,7 +428,6 @@ error_def(ERR_PREMATEOF);
RC = errno; \
else \
RC = -1; /* Something kept us from writing what we wanted */ \
- GTM_WHITE_BOX_TEST(WBTEST_ANTIFREEZE_DSKNOSPCAVAIL, RC, ENOSPC); \
}
#else /* real lseek and read/write - still need to protect against interrupts inbetween calls */
@@ -663,13 +662,15 @@ error_def(ERR_PREMATEOF);
} \
FCNTL3(FDESC, F_SETFL, FLAGS, tfcntl_res); \
if (0 > tfcntl_res) \
- rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fcntl"), CALLFROM, errno); \
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, \
+ 5, LEN_AND_LIT("fcntl"), CALLFROM, errno); \
*BLOCKED_IN = TRUE; \
if (PIPE_ZERO_TIMEOUT) \
{ \
TOFLAG = FALSE; \
/* Set a timer for 1 sec so atomic read x:0 will still work on \
- loaded systems but timeout on incomplete reads. Any characters \
+ loaded systems but timeout on incomplete reads. \
+ Any characters \
read to this point will be returned. */ \
*MSEC_TIMEOUT = timeout2msec(1); \
start_timer(TIMER_ID, *MSEC_TIMEOUT, wake_alarm, 0, NULL); \
@@ -779,12 +780,12 @@ error_def(ERR_PREMATEOF);
#define DOLLAR_DEVICE_SET(DEVPTR,STATUS) \
{ \
len = SIZEOF(ONE_COMMA) - 1; \
- memcpy(DEVPTR->dollar_device, ONE_COMMA, len); \
+ memcpy(DEVPTR->dollar.device, ONE_COMMA, len); \
errptr = (char *)STRERROR(STATUS); \
/* make sure there is room for the 1, and the null at the end */ \
- errlen = MIN(STRLEN(errptr), SIZEOF(DEVPTR->dollar_device) - SIZEOF(ONE_COMMA)); \
- memcpy(&DEVPTR->dollar_device[len], errptr, errlen); \
- DEVPTR->dollar_device[len + errlen] = '\0'; \
+ errlen = MIN(STRLEN(errptr), SIZEOF(DEVPTR->dollar.device) - SIZEOF(ONE_COMMA)); \
+ memcpy(&DEVPTR->dollar.device[len], errptr, errlen); \
+ DEVPTR->dollar.device[len + errlen] = '\0'; \
}
#define DOLLAR_DEVICE_WRITE(DEVPTR,STATUS) \
@@ -796,7 +797,7 @@ error_def(ERR_PREMATEOF);
if (EAGAIN == STATUS) \
{ \
len = SIZEOF(ONE_COMMA_UNAVAILABLE); \
- memcpy(DEVPTR->dollar_device, ONE_COMMA_UNAVAILABLE, len); \
+ memcpy(DEVPTR->dollar.device, ONE_COMMA_UNAVAILABLE, len); \
} else \
DOLLAR_DEVICE_SET(DEVPTR,STATUS); \
}
diff --git a/sr_unix/gtmprofile.gtc b/sr_unix/gtmprofile.gtc
index 0e3ab7b..04c9caf 100644
--- a/sr_unix/gtmprofile.gtc
+++ b/sr_unix/gtmprofile.gtc
@@ -1,6 +1,6 @@
#################################################################
# #
-# Copyright 2010, 2012 Fidelity Information Services, Inc.#
+# Copyright 2010, 2013 Fidelity Information Services, Inc.#
# #
# This source code contains the intellectual property #
# of its copyright holder(s), and is made available #
@@ -89,7 +89,7 @@ if [ $gtm_dist != "$old_gtm_dist" ] ; then
# Note that if UTF-8 mode cannot be properly set, GT.M remains configured for M mode
if [ "zos" = $arch ] ; then
# for z/OS make sure the en_US.UTF-8 locale is available and set $gtm_chset_locale if it is
- utflocale=`locale -a | grep -i en_us | grep -i utf | sed 's/.lp64$//' | grep '8$' | head -n1`
+ utflocale=`locale -a | grep -i en_us | grep -i utf | sed 's/.lp64$//' | grep '8$' | head -n 1`
if [ "`echo $gtm_chset|tr utf UTF`" = "UTF-8" -a -d $gtm_dist/utf8 -a $utflocale = en_US.UTF-8 ] ; then
gtm_chset_locale=$utflocale; export gtm_chset_locale
if [ "`echo Halt | gtm_prompt='GTM>' $gtm_dist/utf8/mumps -dir | tail -n 1`" = 'GTM>' ] ; then
@@ -247,7 +247,8 @@ if [ $gtm_dist != "$old_gtm_dist" ] ; then
fi
if [ -z "$gtm_repl_instance" ] ; then
gtm_repl_instance=$gtmdir/$gtmver/g/gtm.repl ; export gtm_repl_instance
- else gtm_repl_instance=`echo $gtm_repl_instance | sed "s;$old_gtmver;$gtmver;"`
+ elif [ -n "$old_gtmver" ] ; then
+ gtm_repl_instance=`echo $gtm_repl_instance | sed "s;$old_gtmver;$gtmver;"`
fi
if [ -z "$gtm_retention" ] ; then
gtm_retention=42 ; export gtm_retention
diff --git a/sr_unix/gtmrecv.c b/sr_unix/gtmrecv.c
index af5a52d..0a78f83 100644
--- a/sr_unix/gtmrecv.c
+++ b/sr_unix/gtmrecv.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2006, 2012 Fidelity Information Services, Inc *
+ * Copyright 2006, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -111,12 +111,13 @@ int gtmrecv(void)
int log_init_status;
int updresync_instfile_fd; /* fd of the instance file name specified in -UPDATERESYNC= */
boolean_t cross_endian;
+ int null_fd, rc;
call_on_signal = gtmrecv_sigstop;
ESTABLISH_RET(gtmrecv_ch, SS_NORMAL);
memset((uchar_ptr_t)&recvpool, 0, SIZEOF(recvpool));
if (-1 == gtmrecv_get_opt())
- rts_error(VARLSTCNT(1) ERR_MUPCLIERR);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MUPCLIERR);
if (gtmrecv_options.start || gtmrecv_options.shut_down)
{
jnlpool_init(GTMRECEIVE, (boolean_t)FALSE, (boolean_t *)NULL);
@@ -130,14 +131,15 @@ int gtmrecv(void)
*/
if (gtmrecv_options.updateresync && jnlpool.repl_inst_filehdr->num_histinfo
&& !(jnlpool.repl_inst_filehdr->is_supplementary && !jnlpool.jnlpool_ctl->upd_disabled))
- rts_error(VARLSTCNT(1) ERR_UPDSYNC2MTINS); /* replication instance file is NOT empty. Issue error */
+ /* replication instance file is NOT empty. Issue error */
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UPDSYNC2MTINS);
if (gtmrecv_options.noresync)
{ /* If -NORESYNC was specified on a non-supplementary receiver instance, issue an error */
if (!jnlpool.repl_inst_filehdr->is_supplementary)
- rts_error(VARLSTCNT(1) ERR_NORESYNCSUPPLONLY);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NORESYNCSUPPLONLY);
/* If -NORESYNC was specified on a receiver instance where updates are disabled, issue an error */
if (jnlpool.jnlpool_ctl->upd_disabled)
- rts_error(VARLSTCNT(1) ERR_NORESYNCUPDATERONLY);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NORESYNCUPDATERONLY);
}
}
if (gtmrecv_options.shut_down)
@@ -172,18 +174,18 @@ int gtmrecv(void)
if (SRV_ALIVE == (status = is_recv_srv_alive()) && 0 != gtmrecv_options.listen_port)
{
rel_sem(RECV, RECV_SERV_OPTIONS_SEM);
- rts_error(VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Receiver Server already exists"));
} else if (SRV_DEAD == status && 0 == gtmrecv_options.listen_port)
{
rel_sem(RECV, RECV_SERV_OPTIONS_SEM);
- rts_error(VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Receiver server does not exist. Start it first"));
} else if (SRV_ERR == status)
{
status = errno;
rel_sem(RECV, RECV_SERV_OPTIONS_SEM);
- rts_error(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Receiver server semaphore error"), status);
}
if (gtmrecv_options.updateonly)
@@ -207,21 +209,21 @@ int gtmrecv(void)
if (FD_INVALID == updresync_instfile_fd)
{
rel_sem(RECV, RECV_SERV_OPTIONS_SEM);
- rts_error(VARLSTCNT(5) ERR_REPLINSTOPEN, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_REPLINSTOPEN, 2,
LEN_AND_STR(gtmrecv_options.updresync_instfilename), errno);
}
LSEEKREAD(updresync_instfile_fd, 0, &updresync_inst_hdr, SIZEOF(updresync_inst_hdr), status);
if (0 != status)
{ /* Encountered an error reading the full file header */
rel_sem(RECV, RECV_SERV_OPTIONS_SEM);
- rts_error(VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Input file does not even have a full instance file header"));
}
/* Check if it is the right version */
if (memcmp(updresync_inst_hdr.label, GDS_REPL_INST_LABEL, GDS_REPL_INST_LABEL_SZ - 1))
{
rel_sem(RECV, RECV_SERV_OPTIONS_SEM);
- rts_error(VARLSTCNT(10) ERR_UPDSYNCINSTFILE, 0,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_UPDSYNCINSTFILE, 0,
ERR_REPLINSTFMT, 6, LEN_AND_STR(gtmrecv_options.updresync_instfilename),
GDS_REPL_INST_LABEL_SZ - 1, GDS_REPL_INST_LABEL,
GDS_REPL_INST_LABEL_SZ - 1, updresync_inst_hdr.label);
@@ -243,7 +245,7 @@ int gtmrecv(void)
if (updresync_inst_hdr.crash)
{ /* The instance file cannot be used for updateresync if it was not cleanly shutdown */
rel_sem(RECV, RECV_SERV_OPTIONS_SEM);
- rts_error(VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Input instance file was not cleanly shutdown"));
}
if (cross_endian)
@@ -262,7 +264,7 @@ int gtmrecv(void)
if (!updresync_inst_hdr.jnl_seqno)
{ /* The instance file cannot be used for updateresync if it has a ZERO seqno */
rel_sem(RECV, RECV_SERV_OPTIONS_SEM);
- rts_error(VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Non-supplementary input instance file cannot be used"
" on supplementary instance when it is empty (has seqno of 0)"));
}
@@ -278,7 +280,7 @@ int gtmrecv(void)
if (IS_REPL_INST_UUID_NULL(updresync_inst_hdr.lms_group_info))
{ /* The input instance has a NULL LMS group. Cannot be used to fill in current instance */
rel_sem(RECV, RECV_SERV_OPTIONS_SEM);
- rts_error(VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Input instance file has NULL LMS group"));
}
if (updresync_inst_hdr.is_supplementary)
@@ -288,7 +290,7 @@ int gtmrecv(void)
if (!jnlpool.repl_inst_filehdr->is_supplementary)
{
rel_sem(RECV, RECV_SERV_OPTIONS_SEM);
- rts_error(VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2,
LEN_AND_LIT("Input instance file must be non-supplementary"
" to match current instance"));
assert(FALSE);
@@ -296,7 +298,7 @@ int gtmrecv(void)
if (!jnlpool.jnlpool_ctl->upd_disabled)
{
rel_sem(RECV, RECV_SERV_OPTIONS_SEM);
- rts_error(VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2,
LEN_AND_LIT("Input instance file must be non-supplementary"
" as current instance is a supplementary root primary"));
}
@@ -307,14 +309,14 @@ int gtmrecv(void)
* instance is non-supplementary or if it is a supplementary root primary.
*/
rel_sem(RECV, RECV_SERV_OPTIONS_SEM);
- rts_error(VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2,
LEN_AND_LIT("Input instance file must be supplementary"
" to match current instance"));
}
if (!gtmrecv_options.resume_specified && !gtmrecv_options.initialize_specified)
{
rel_sem(RECV, RECV_SERV_OPTIONS_SEM);
- rts_error(VARLSTCNT(1) ERR_INITORRESUME);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INITORRESUME);
}
}
if (!jnlpool.repl_inst_filehdr->is_supplementary || jnlpool.jnlpool_ctl->upd_disabled)
@@ -322,13 +324,13 @@ int gtmrecv(void)
if (gtmrecv_options.resume_specified)
{
rel_sem(RECV, RECV_SERV_OPTIONS_SEM);
- rts_error(VARLSTCNT(6) ERR_RESUMESTRMNUM, 0, ERR_TEXT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RESUMESTRMNUM, 0, ERR_TEXT, 2,
LEN_AND_LIT("RESUME allowed only on root primary supplementary instance"));
}
if (gtmrecv_options.reuse_specified)
{
rel_sem(RECV, RECV_SERV_OPTIONS_SEM);
- rts_error(VARLSTCNT(6) ERR_REUSEINSTNAME, 0, ERR_TEXT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REUSEINSTNAME, 0, ERR_TEXT, 2,
LEN_AND_LIT("REUSE allowed only on root primary supplementary instance"));
}
}
@@ -354,7 +356,7 @@ int gtmrecv(void)
} else if (0 > pid)
{
status = errno;
- rts_error(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Unable to fork"), status);
}
# endif
@@ -373,6 +375,16 @@ int gtmrecv(void)
gtmrecv_exit(gtmrecv_showbacklog() - NORMAL_SHUTDOWN);
else
gtmrecv_exit(gtmrecv_statslog() - NORMAL_SHUTDOWN);
+ /* Point stdin to /dev/null */
+ OPENFILE("/dev/null", O_RDONLY, null_fd);
+ if (0 > null_fd)
+ rts_error_csa(CSA_ARG(NULL) ERR_REPLERR, RTS_ERROR_LITERAL("Failed to open /dev/null for read"), errno, 0);
+ FCNTL3(null_fd, F_DUPFD, 0, rc);
+ if (0 > rc)
+ rts_error_csa(CSA_ARG(NULL) ERR_REPLERR, RTS_ERROR_LITERAL("Failed to set stdin to /dev/null"), errno, 0);
+ CLOSEFILE(null_fd, rc);
+ if (0 > rc)
+ rts_error_csa(CSA_ARG(NULL) ERR_REPLERR, RTS_ERROR_LITERAL("Failed to close /dev/null"), errno, 0);
assert(!holds_sem[RECV][RECV_POOL_ACCESS_SEM]);
assert(holds_sem[RECV][RECV_SERV_OPTIONS_SEM]);
is_rcvr_server = TRUE;
@@ -443,7 +455,7 @@ int gtmrecv(void)
assert(SS_NORMAL == log_init_status);
repl_log_fd2fp(>mrecv_log_fp, gtmrecv_log_fd);
if (-1 == (procgp = setsid()))
- rts_error(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Receiver server error in setsid"), errno);
gtm_event_log_init();
gtmrecv_local->recv_serv_pid = process_id;
@@ -529,13 +541,13 @@ int gtmrecv(void)
* that. Do that while the parent is still waiting for our okay.
*/
if (!ftok_sem_incrcnt(recvpool.recvpool_dummy_reg))
- rts_error(VARLSTCNT(1) ERR_RECVPOOLSETUP);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_RECVPOOLSETUP);
/* Lock the receiver server count semaphore. Its value should be atmost 1. */
if (0 > grab_sem_immediate(RECV, RECV_SERV_COUNT_SEM))
{
save_errno = errno;
- rts_error(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Receive pool semop failure"),
- save_errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Receive pool semop failure"), save_errno);
}
# ifdef REPL_DEBUG_NOBACKGROUND
rel_sem(RECV, RECV_SERV_OPTIONS_SEM);
diff --git a/sr_unix/gtmrecv.h b/sr_unix/gtmrecv.h
index b160579..af3cd9e 100644
--- a/sr_unix/gtmrecv.h
+++ b/sr_unix/gtmrecv.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2006, 2012 Fidelity Information Services, Inc.*
+ * Copyright 2006, 2013 Fidelity Information Services, Inc.*
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -205,7 +205,6 @@ typedef struct
typedef struct
{
uint4 recv_serv_pid; /* Process identification of receiver server */
- int4 primary_inet_addr; /* IP address of the primary system */
int4 lastrecvd_time; /* unused */
/* Data items used in communicating action qualifiers (show statistics, shutdown) and
* qualifier values (log file, shutdown time, etc). */
@@ -329,10 +328,13 @@ typedef enum
UPDPROC,
UPD_HELPER_READER,
UPD_HELPER_WRITER,
- GTMRECV
-#ifdef VMS
- , GTMRECV_CHILD
-#endif
+ GTMRECV,
+# ifdef UNIX
+ GTMZPEEK
+# endif
+# ifdef VMS
+ GTMRECV_CHILD
+# endif
} recvpool_user;
typedef struct
diff --git a/sr_unix/gtmrecv_fetchresync.c b/sr_unix/gtmrecv_fetchresync.c
index fbe997b..e147167 100644
--- a/sr_unix/gtmrecv_fetchresync.c
+++ b/sr_unix/gtmrecv_fetchresync.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -64,10 +64,28 @@
#define MAX_WAIT_FOR_FETCHRESYNC_CONN 60 /* max-wait in seconds to establish connection with the source server */
#define FETCHRESYNC_PRIMARY_POLL (MICROSEC_IN_SEC - 1) /* micro seconds, almost 1 second */
+#define CHECK_SEND_RECV_LOOP_ERROR(STATUS, WAIT_COUNT, MESSAGE) \
+{ \
+ if (SS_NORMAL != STATUS) \
+ { \
+ if (EREPL_RECV == repl_errno) \
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, \
+ LEN_AND_LIT("Error in recv() for " MESSAGE), STATUS); \
+ else if (EREPL_SEND == repl_errno) \
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, \
+ LEN_AND_LIT("Error in send() for " MESSAGE), STATUS); \
+ else if (EREPL_SELECT == repl_errno) \
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, \
+ LEN_AND_LIT("Error in select() for " MESSAGE), STATUS); \
+ } \
+ if (0 >= WAIT_COUNT) \
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, \
+ LEN_AND_LIT("Waited too long to get/send" MESSAGE " from primary. Check if primary is alive."));\
+}
+
GBLREF uint4 process_id;
GBLREF int recvpool_shmid;
GBLREF int gtmrecv_listen_sock_fd, gtmrecv_sock_fd;
-GBLREF struct sockaddr_in primary_addr;
GBLREF seq_num seq_num_zero;
GBLREF jnl_gbls_t jgbl;
GBLREF int repl_max_send_buffsize, repl_max_recv_buffsize;
@@ -100,7 +118,6 @@ CONDITION_HANDLER(gtmrecv_fetchresync_ch)
int gtmrecv_fetchresync(int port, seq_num *resync_seqno, seq_num max_reg_seqno)
{
- GTM_SOCKLEN_TYPE primary_addr_len;
repl_resync_msg_t resync_msg;
repl_msg_t msg;
uchar_ptr_t msgp;
@@ -109,13 +126,12 @@ int gtmrecv_fetchresync(int port, seq_num *resync_seqno, seq_num max_reg_seqno)
int torecv_len, recvd_len, recvd_this_iter; /* needed for REPL_RECV_LOOP */
int status; /* needed for REPL_{SEND,RECV}_LOOP */
fd_set input_fds;
- int wait_count;
+ int wait_count, save_errno;
char seq_num_str[32], *seq_num_ptr;
pid_t rollback_pid;
int rollback_status;
int wait_status;
time_t t1, t2;
- struct timeval gtmrecv_fetchresync_max_wait, gtmrecv_fetchresync_poll, sel_timeout_val;
repl_old_instinfo_msg_t old_instinfo_msg;
repl_old_needinst_msg_ptr_t old_need_instinfo_msg;
repl_needinst_msg_t need_instinfo_msg;
@@ -124,116 +140,75 @@ int gtmrecv_fetchresync(int port, seq_num *resync_seqno, seq_num max_reg_seqno)
seq_num histinfo_seqno;
short retry_num;
repl_inst_hdr_ptr_t inst_hdr;
+ repl_logfile_info_msg_t logfile_msg;
+ uint4 len;
+ struct addrinfo primary_ai;
+ struct sockaddr_storage primary_sas;
+ struct timeval repl_poll_wait;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
- repl_log(stdout, TRUE, TRUE, "Assuming primary supports multisite functionality. Connecting "
- "using multisite communication protocol.\n");
+ repl_log(stdout, TRUE, TRUE,
+ "Assuming primary supports multisite functionality. Connecting using multisite communication protocol.\n");
ESTABLISH_RET(gtmrecv_fetchresync_ch, (!SS_NORMAL));
QWASSIGN(*resync_seqno, seq_num_zero);
- gtmrecv_fetchresync_max_wait.tv_sec = MAX_WAIT_FOR_FETCHRESYNC_CONN;
- gtmrecv_fetchresync_max_wait.tv_usec = 0;
- gtmrecv_fetchresync_poll.tv_sec = 0;
- gtmrecv_fetchresync_poll.tv_usec = FETCHRESYNC_PRIMARY_POLL;
gtmrecv_comm_init(port);
- primary_addr_len = SIZEOF(primary_addr);
+ primary_ai.ai_addr = (sockaddr_ptr)&primary_sas;
+ primary_ai.ai_addrlen = SIZEOF(primary_sas);
remote_side->proto_ver = REPL_PROTO_VER_UNINITIALIZED;
repl_log(stdout, TRUE, TRUE, "Waiting for a connection...\n");
- FD_ZERO(&input_fds);
- FD_SET(gtmrecv_listen_sock_fd, &input_fds);
- /* Note - the following call to select checks for EINTR. The SELECT macro is not used because
- * the code also checks for EAGAIN and takes action before retrying the select.
- */
- t1 = time(NULL);
- while ((status = select(gtmrecv_listen_sock_fd + 1, &input_fds, NULL, NULL, >mrecv_fetchresync_max_wait)) < 0)
- {
- if ((EINTR == errno) || (EAGAIN == errno))
- {
- t2 = time(NULL);
- if (0 >= (int)(gtmrecv_fetchresync_max_wait.tv_sec =
- (MAX_WAIT_FOR_FETCHRESYNC_CONN - (int)difftime(t2, t1))))
- {
- status = 0;
- break;
- }
- gtmrecv_fetchresync_max_wait.tv_usec = 0;
- FD_SET(gtmrecv_listen_sock_fd, &input_fds);
- continue;
- } else
- rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
- RTS_ERROR_LITERAL("Error in select on listen socket"), errno);
- }
- if (status == 0)
- {
- repl_log(stdout, TRUE, TRUE, "Waited about %d seconds for connection from primary source server\n",
- MAX_WAIT_FOR_FETCHRESYNC_CONN);
- rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2,
- RTS_ERROR_LITERAL("Waited too long to get a connection request. Check if primary is alive."));
- }
- ACCEPT_SOCKET(gtmrecv_listen_sock_fd, (struct sockaddr *)&primary_addr,
- (GTM_SOCKLEN_TYPE *)&primary_addr_len, gtmrecv_sock_fd);
- if (0 > gtmrecv_sock_fd)
+ while (TRUE)
{
-# ifdef __hpux
- /* ENOBUFS in HP-UX is either because of a memory problem or when we have received a RST just
- after a SYN before an accept call. Normally this is not fatal and is just a transient state.Hence
- exiting just after a single error of this kind should not be done. So retry in case of HP-UX and ENOBUFS error*/
- if (ENOBUFS == errno)
+ t1 = time(NULL);
+ repl_poll_wait.tv_sec = MAX_WAIT_FOR_FETCHRESYNC_CONN;
+ repl_poll_wait.tv_usec = 0;
+ while ((status = select(gtmrecv_listen_sock_fd + 1, &input_fds, NULL, NULL, &repl_poll_wait)) < 0)
{
- retry_num = 0;
- /*In case of succeeding with select in first go, accept will still get 5ms time difference*/
- while (HPUX_MAX_RETRIES > retry_num)
+ if ((EINTR == errno) || (EAGAIN == errno))
{
- SHORT_SLEEP(5);
- FD_ZERO(&input_fds);
- FD_SET(gtmrecv_listen_sock_fd, &input_fds);
- /* Since we use Blocking socket, check before re-trying if there is a connection to be accepted.
- * Timeout of HPUX_SEL_TIMEOUT. In case the earlier connection is not available there can be
- * some time gap between the time the error occured and the new client requests coming in.
- */
- for ( ; HPUX_MAX_RETRIES > retry_num; retry_num++)
- {
- FD_ZERO(&input_fds);
- FD_SET(gtmrecv_listen_sock_fd, &input_fds);
- sel_timeout_val.tv_sec = 0;
- sel_timeout_val.tv_usec = HPUX_SEL_TIMEOUT;
- status = select(gtmrecv_listen_sock_fd + 1, &input_fds, NULL,
- NULL, &sel_timeout_val);
- if (0 < status)
- break;
- else
- SHORT_SLEEP(5);
- }
- if (0 > status)
- rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
- RTS_ERROR_LITERAL("Error in select on listen socket after ENOBUFS error"), errno);
- else
+ t2 = time(NULL);
+ if (0 >= (int)(repl_poll_wait.tv_sec = (MAX_WAIT_FOR_FETCHRESYNC_CONN - (int)difftime(t2, t1))))
{
- ACCEPT_SOCKET(gtmrecv_listen_sock_fd, (struct sockaddr *)&primary_addr,
- (GTM_SOCKLEN_TYPE *)&primary_addr_len, gtmrecv_sock_fd);
- if ((0 > gtmrecv_sock_fd) && (errno == ENOBUFS))
- retry_num++;
- else
- break;
+ status = 0;
+ break;
}
- }
+ repl_poll_wait.tv_usec = 0;
+ FD_SET(gtmrecv_listen_sock_fd, &input_fds);
+ continue;
+ } else
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_LIT("Error in select on listen socket"), errno);
}
- if (0 > gtmrecv_sock_fd)
-# endif
+ if (status == 0)
{
- rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
- RTS_ERROR_LITERAL("Error accepting connection from Source Server"), errno);
+ repl_log(stdout, TRUE, TRUE, "Waited about %d seconds for connection from primary source server\n",
+ MAX_WAIT_FOR_FETCHRESYNC_CONN);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_LIT("Waited too long to get a connection request. Check if primary is alive."));
}
+ ACCEPT_SOCKET(gtmrecv_listen_sock_fd, primary_ai.ai_addr,
+ (GTM_SOCKLEN_TYPE *)&primary_ai.ai_addrlen, gtmrecv_sock_fd);
+ if (FD_INVALID == gtmrecv_sock_fd)
+ {
+ save_errno = errno;
+# ifdef __hpux
+ if (ENOBUFS == save_errno)
+ continue;
+# endif
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0,
+ ERR_TEXT, 2, LEN_AND_LIT("Error accepting connection from Source Server"), save_errno);
+ }
+ break;
}
+ /* Connection established */
repl_close(>mrecv_listen_sock_fd); /* Close the listener socket */
repl_connection_reset = FALSE;
if (0 != (status = get_send_sock_buff_size(gtmrecv_sock_fd, &repl_max_send_buffsize))
|| 0 != (status = get_recv_sock_buff_size(gtmrecv_sock_fd, &repl_max_recv_buffsize)))
{
- rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
LEN_AND_LIT("Error getting socket send/recv buffsizes"), status);
- return ERR_REPLCOMM;
}
repl_log(stdout, TRUE, TRUE, "Connection established, using TCP send buffer size %d receive buffer size %d\n",
repl_max_send_buffsize, repl_max_recv_buffsize);
@@ -252,16 +227,17 @@ int gtmrecv_fetchresync(int port, seq_num *resync_seqno, seq_num max_reg_seqno)
"REPL_FETCH_RESYNC", resync_msg.resync_seqno);
if (repl_connection_reset)
{ /* Connection got reset during the above send */
- rts_error(VARLSTCNT(1) ERR_REPLCOMM);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_REPLCOMM);
return ERR_REPLCOMM;
}
/* Wait for REPL_RESYNC_SEQNO (if dual-site primary) or REPL_OLD_NEED_INSTANCE_INFO (if multi-site primary)
- * or REPL_NEED_INSTINFO (if multi-site primary with supplementary instance support) message */
+ * or REPL_NEED_INSTINFO (if multi-site primary with supplementary instance support) message
+ */
do
{
wait_count = MAX_ATTEMPTS_FOR_FETCH_RESYNC;
assert(SIZEOF(msg) == MIN_REPL_MSGLEN);
- REPL_RECV_LOOP(gtmrecv_sock_fd, &msg, MIN_REPL_MSGLEN, FALSE, >mrecv_fetchresync_poll)
+ REPL_RECV_LOOP(gtmrecv_sock_fd, &msg, MIN_REPL_MSGLEN, REPL_POLL_WAIT)
{
if (0 >= wait_count)
break;
@@ -269,18 +245,7 @@ int gtmrecv_fetchresync(int port, seq_num *resync_seqno, seq_num max_reg_seqno)
" or REPL_NEED_INSTINFO or REPL_NEED_HISTINFO\n");
wait_count--;
}
- if (status != SS_NORMAL)
- {
- if (EREPL_RECV == repl_errno)
- rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
- RTS_ERROR_LITERAL("Error receiving RESYNC JNLSEQNO. Error in recv"), status);
- if (EREPL_SELECT == repl_errno)
- rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
- RTS_ERROR_LITERAL("Error receiving RESYNC JNLSEQNO. Error in select"), status);
- }
- if (wait_count <= 0)
- rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2,
- LEN_AND_LIT("Waited too long to get message from primary. Check if primary is alive."));
+ CHECK_SEND_RECV_LOOP_ERROR(status, wait_count, "RESYNC JNLSEQNO");
if (!remote_side->endianness_known)
{
remote_side->endianness_known = TRUE;
@@ -309,8 +274,9 @@ int gtmrecv_fetchresync(int port, seq_num *resync_seqno, seq_num max_reg_seqno)
if (jnlpool.repl_inst_filehdr->is_supplementary)
{ /* Issue REPL2OLD error because this is a supplementary instance and remote side runs
* on a GT.M version that does not understand the supplementary protocol */
- rts_error(VARLSTCNT(6) ERR_REPL2OLD, 4, LEN_AND_STR(old_need_instinfo_msg->instname),
- LEN_AND_STR(jnlpool.repl_inst_filehdr->inst_info.this_instname));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPL2OLD, 4,
+ LEN_AND_STR(old_need_instinfo_msg->instname),
+ LEN_AND_STR(jnlpool.repl_inst_filehdr->inst_info.this_instname));
}
remote_side->proto_ver = old_need_instinfo_msg->proto_ver;
assert(REPL_PROTO_VER_MULTISITE <= remote_side->proto_ver);
@@ -324,7 +290,7 @@ int gtmrecv_fetchresync(int port, seq_num *resync_seqno, seq_num max_reg_seqno)
gtmrecv_repl_send((repl_msg_ptr_t)&old_instinfo_msg, REPL_OLD_INSTANCE_INFO,
MIN_REPL_MSGLEN, "REPL_OLD_INSTANCE_INFO", MAX_SEQNO);
if (old_instinfo_msg.was_rootprimary && !old_need_instinfo_msg->is_rootprimary)
- rts_error(VARLSTCNT(4) ERR_PRIMARYNOTROOT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_PRIMARYNOTROOT, 2,
LEN_AND_STR((char *)old_need_instinfo_msg->instname));
break;
@@ -333,27 +299,14 @@ int gtmrecv_fetchresync(int port, seq_num *resync_seqno, seq_num max_reg_seqno)
assert(SIZEOF(need_instinfo_msg) > MIN_REPL_MSGLEN);
memcpy(&need_instinfo_msg, &msg, MIN_REPL_MSGLEN);
msgp = (uchar_ptr_t)&need_instinfo_msg + MIN_REPL_MSGLEN;
- REPL_RECV_LOOP(gtmrecv_sock_fd, msgp,
- SIZEOF(need_instinfo_msg) - MIN_REPL_MSGLEN, FALSE, >mrecv_fetchresync_poll)
+ REPL_RECV_LOOP(gtmrecv_sock_fd, msgp, SIZEOF(need_instinfo_msg) - MIN_REPL_MSGLEN, REPL_POLL_WAIT)
{
if (0 >= wait_count)
break;
repl_log(stdout, TRUE, TRUE, "Waiting for REPL_NEED_INSTINFO\n");
wait_count--;
}
- if (status != SS_NORMAL)
- {
- if (EREPL_RECV == repl_errno)
- rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
- RTS_ERROR_LITERAL("Error in recv REPL_NEED_INSTINFO"), status);
- if (EREPL_SELECT == repl_errno)
- rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
- RTS_ERROR_LITERAL("Error in select REPL_NEED_INSTINFO"), status);
- }
- if (wait_count <= 0)
- rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2,
- LEN_AND_LIT("Waited too long to get message from primary."
- " Check if primary is alive."));
+ CHECK_SEND_RECV_LOOP_ERROR(status, wait_count, "REPL_NEED_INSTINFO");
gtmrecv_check_and_send_instinfo(&need_instinfo_msg, IS_RCVR_SRVR_FALSE);
break;
@@ -424,7 +377,7 @@ int gtmrecv_fetchresync(int port, seq_num *resync_seqno, seq_num max_reg_seqno)
if (REPL_PROTO_VER_UNINITIALIZED == remote_side->proto_ver)
{ /* Issue REPL2OLD error because primary is dual-site */
assert(NULL != jnlpool.repl_inst_filehdr);
- rts_error(VARLSTCNT(6) ERR_REPL2OLD, 4, LEN_AND_STR(UNKNOWN_INSTNAME),
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPL2OLD, 4, LEN_AND_STR(UNKNOWN_INSTNAME),
LEN_AND_STR(jnlpool.repl_inst_filehdr->inst_info.this_instname));
}
assert(REPL_PROTO_VER_MULTISITE <= remote_side->proto_ver);
@@ -438,16 +391,51 @@ int gtmrecv_fetchresync(int port, seq_num *resync_seqno, seq_num max_reg_seqno)
*/
break;
+ case REPL_LOGFILE_INFO:
+ /* We got only a part of this message. Get the remaining part as well */
+ assert(SIZEOF(logfile_msg) > MIN_REPL_MSGLEN);
+ assert(MIN_REPL_MSGLEN < msg.len);
+ assert(remote_side->endianness_known);
+ msgp = (uchar_ptr_t)&logfile_msg;
+ memcpy(msgp, &msg, MIN_REPL_MSGLEN);
+ REPL_RECV_LOOP(gtmrecv_sock_fd, msgp + MIN_REPL_MSGLEN, msg.len - MIN_REPL_MSGLEN, REPL_POLL_WAIT)
+ {
+ if (0 >= wait_count)
+ break;
+ wait_count--;
+ }
+ CHECK_SEND_RECV_LOOP_ERROR(status, wait_count, "REPL_LOGFILE_INFO");
+ assert(REPL_PROTO_VER_REMOTE_LOGPATH <= logfile_msg.proto_ver);
+ if (remote_side->cross_endian)
+ {
+ logfile_msg.fullpath_len = GTM_BYTESWAP_32(logfile_msg.fullpath_len);
+ logfile_msg.pid = GTM_BYTESWAP_32(logfile_msg.pid);
+ }
+ assert('\0' == logfile_msg.fullpath[logfile_msg.fullpath_len - 1]);
+ repl_log(stdout, TRUE, TRUE, "Remote side source log file path is %s; Source Server PID = %d\n",
+ logfile_msg.fullpath, logfile_msg.pid);
+ /* Now send our logfile path to the source side. Since the rollback doesn't have a logfile per-se,
+ * send just the $PWD
+ */
+ len = repl_logfileinfo_get(NULL, &logfile_msg, remote_side->cross_endian, (FILE *)stdout);
+ REPL_SEND_LOOP(gtmrecv_sock_fd, &logfile_msg, len, REPL_POLL_WAIT)
+ {
+ if (0 >= wait_count)
+ break;
+ wait_count--;
+ }
+ CHECK_SEND_RECV_LOOP_ERROR(status, wait_count, "REPL_LOGFILE_INFO");
+ break;
default:
repl_log(stdout, TRUE, TRUE, "Message of unknown type (%d) received\n", msg.type);
assert(FALSE);
- rts_error(VARLSTCNT(1) ERR_REPLCOMM);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_REPLCOMM);
break;
}
} while (!repl_connection_reset && (REPL_RESYNC_SEQNO != msg.type));
if (repl_connection_reset)
{ /* Connection got reset during the above send */
- rts_error(VARLSTCNT(1) ERR_REPLCOMM);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_REPLCOMM);
return ERR_REPLCOMM;
}
assert(remote_side->endianness_known); /* only then is remote_side->cross_endian reliable */
@@ -456,7 +444,7 @@ int gtmrecv_fetchresync(int port, seq_num *resync_seqno, seq_num max_reg_seqno)
else
QWASSIGN(*resync_seqno, GTM_BYTESWAP_64(*(seq_num *)&msg.msg[0]));
/* Wait till connection is broken or REPL_CONN_CLOSE is received */
- REPL_RECV_LOOP(gtmrecv_sock_fd, &msg, MIN_REPL_MSGLEN, FALSE, >mrecv_fetchresync_poll)
+ REPL_RECV_LOOP(gtmrecv_sock_fd, &msg, MIN_REPL_MSGLEN, REPL_POLL_WAIT)
{
REPL_DPRINT1("FETCH_RESYNC : Waiting for source to send CLOSE_CONN or connection breakage\n");
}
diff --git a/sr_unix/gtmrecv_poll_actions.c b/sr_unix/gtmrecv_poll_actions.c
index 42cb0f3..e7ae58c 100644
--- a/sr_unix/gtmrecv_poll_actions.c
+++ b/sr_unix/gtmrecv_poll_actions.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2008, 2012 Fidelity Information Services, Inc.*
+ * Copyright 2008, 2013 Fidelity Information Services, Inc.*
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -47,7 +47,6 @@
GBLREF repl_msg_ptr_t gtmrecv_msgp;
GBLREF int gtmrecv_max_repl_msglen;
-GBLREF struct timeval gtmrecv_poll_interval, gtmrecv_poll_immediate;
GBLREF int gtmrecv_listen_sock_fd;
GBLREF int gtmrecv_sock_fd;
GBLREF boolean_t repl_connection_reset;
@@ -232,7 +231,7 @@ int gtmrecv_poll_actions1(int *pending_data_len, int *buff_unprocessed, unsigned
temp_send_seqno = GTM_BYTESWAP_64(send_seqno);
memcpy((uchar_ptr_t)&xoff_msg.msg[0], (uchar_ptr_t)&temp_send_seqno, SIZEOF(seq_num));
}
- REPL_SEND_LOOP(gtmrecv_sock_fd, &xoff_msg, MIN_REPL_MSGLEN, FALSE, >mrecv_poll_immediate)
+ REPL_SEND_LOOP(gtmrecv_sock_fd, &xoff_msg, MIN_REPL_MSGLEN, REPL_POLL_NOWAIT)
; /* Empty Body */
if (SS_NORMAL != status)
{
@@ -246,14 +245,14 @@ int gtmrecv_poll_actions1(int *pending_data_len, int *buff_unprocessed, unsigned
send_badtrans = FALSE;
} else if (EREPL_SEND == repl_errno)
- rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
- RTS_ERROR_LITERAL("Error sending XOFF msg due to BAD_TRANS or UPD crash/shutdown. "
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_LIT("Error sending XOFF msg due to BAD_TRANS or UPD crash/shutdown. "
"Error in send"), status);
else
{
assert(EREPL_SELECT == repl_errno);
- rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
- RTS_ERROR_LITERAL("Error sending XOFF msg due to BAD_TRANS or UPD crash/shutdown. "
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_LIT("Error sending XOFF msg due to BAD_TRANS or UPD crash/shutdown. "
"Error in select"), status);
}
} else
@@ -322,7 +321,7 @@ int gtmrecv_poll_actions1(int *pending_data_len, int *buff_unprocessed, unsigned
{ /* Receive the header of a message */
assert(REPL_MSG_HDRLEN > *buff_unprocessed); /* so we dont pass negative length in REPL_RECV_LOOP */
REPL_RECV_LOOP(gtmrecv_sock_fd, ((unsigned char *)gtmrecv_msgp) + *buff_unprocessed,
- (REPL_MSG_HDRLEN - *buff_unprocessed), FALSE, >mrecv_poll_interval)
+ (REPL_MSG_HDRLEN - *buff_unprocessed), REPL_POLL_WAIT)
; /* Empty Body */
if (SS_NORMAL == status)
{
@@ -345,8 +344,7 @@ int gtmrecv_poll_actions1(int *pending_data_len, int *buff_unprocessed, unsigned
}
if ((SS_NORMAL == status) && (0 != *buff_unprocessed || 0 == *pending_data_len) && (REPL_XOFF_ACK == msg_type))
{ /* Receive the rest of the XOFF_ACK msg and signal the drain as complete */
- REPL_RECV_LOOP(gtmrecv_sock_fd, gtmrecv_msgp, (MIN_REPL_MSGLEN - REPL_MSG_HDRLEN), FALSE,
- >mrecv_poll_interval)
+ REPL_RECV_LOOP(gtmrecv_sock_fd, gtmrecv_msgp, (MIN_REPL_MSGLEN - REPL_MSG_HDRLEN), REPL_POLL_WAIT)
; /* Empty Body */
if (SS_NORMAL == status)
{
@@ -371,7 +369,7 @@ int gtmrecv_poll_actions1(int *pending_data_len, int *buff_unprocessed, unsigned
for ( ; SS_NORMAL == status && 0 < pending_msg_size; pending_msg_size -= gtmrecv_max_repl_msglen)
{
temp_len = (pending_msg_size < gtmrecv_max_repl_msglen)? pending_msg_size : gtmrecv_max_repl_msglen;
- REPL_RECV_LOOP(gtmrecv_sock_fd, gtmrecv_msgp, temp_len, FALSE, >mrecv_poll_interval)
+ REPL_RECV_LOOP(gtmrecv_sock_fd, gtmrecv_msgp, temp_len, REPL_POLL_WAIT)
; /* Empty Body */
}
*buff_unprocessed = 0; *pending_data_len = 0;
@@ -397,13 +395,13 @@ int gtmrecv_poll_actions1(int *pending_data_len, int *buff_unprocessed, unsigned
send_badtrans = FALSE;
return_status = STOP_POLL;
} else
- rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
- RTS_ERROR_LITERAL("Error while draining replication pipe. Error in recv"), status);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_LIT("Error while draining replication pipe. Error in recv"), status);
} else
{
assert(EREPL_SELECT == repl_errno);
- rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
- RTS_ERROR_LITERAL("Error while draining replication pipe. Error in select"), status);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_LIT("Error while draining replication pipe. Error in select"), status);
}
}
} else
@@ -426,7 +424,7 @@ int gtmrecv_poll_actions1(int *pending_data_len, int *buff_unprocessed, unsigned
bad_trans_msg.len = GTM_BYTESWAP_32(MIN_REPL_MSGLEN);
bad_trans_msg.start_seqno = GTM_BYTESWAP_64(send_seqno);
}
- REPL_SEND_LOOP(gtmrecv_sock_fd, &bad_trans_msg, bad_trans_msg.len, FALSE, >mrecv_poll_immediate)
+ REPL_SEND_LOOP(gtmrecv_sock_fd, &bad_trans_msg, bad_trans_msg.len, REPL_POLL_NOWAIT)
; /* Empty Body */
if (SS_NORMAL == status)
{
@@ -451,13 +449,13 @@ int gtmrecv_poll_actions1(int *pending_data_len, int *buff_unprocessed, unsigned
repl_connection_reset = TRUE;
return_status = STOP_POLL;
} else if (EREPL_SEND == repl_errno)
- rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
- RTS_ERROR_LITERAL("Error sending REPL_BADTRANS/REPL_CMP2UNCMP. Error in send"), status);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_LIT("Error sending REPL_BADTRANS/REPL_CMP2UNCMP. Error in send"), status);
else
{
assert(EREPL_SELECT == repl_errno);
- rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
- RTS_ERROR_LITERAL("Error sending REPL_BADTRANS/REPL_CMP2UNCMP. Error in select"), status);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_LIT("Error sending REPL_BADTRANS/REPL_CMP2UNCMP. Error in select"), status);
}
}
send_badtrans = FALSE;
@@ -546,7 +544,7 @@ int gtmrecv_poll_actions1(int *pending_data_len, int *buff_unprocessed, unsigned
* just syncing the journal pool cycles as the databases are not opened. But, to be safe, grab
* the lock and sync the cycles.
*/
- grab_lock(jnlpool.jnlpool_dummy_reg, GRAB_LOCK_ONLY);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, GRAB_LOCK_ONLY);
SYNC_ONLN_RLBK_CYCLES;
rel_lock(jnlpool.jnlpool_dummy_reg);
return_status = STOP_POLL;
diff --git a/sr_unix/gtmrecv_process.c b/sr_unix/gtmrecv_process.c
index eca9ae0..f0874cb 100644
--- a/sr_unix/gtmrecv_process.c
+++ b/sr_unix/gtmrecv_process.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2006, 2012 Fidelity Information Services, Inc.*
+ * Copyright 2006, 2013 Fidelity Information Services, Inc.*
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -25,13 +25,6 @@
#include <sys/time.h>
#include <errno.h>
-#include <netinet/tcp.h>
-#ifdef GTM_USE_POLL_FOR_SUBSECOND_SELECT
-#include <sys/poll.h>
-#endif
-#ifdef VMS
-#include <descrip.h> /* Required for gtmrecv.h */
-#endif
#include "gdsroot.h"
#include "gdsblk.h"
@@ -94,13 +87,9 @@
#define RECVBUFF_REPLMSGLEN_FACTOR 8
-#define GTMRECV_POLL_INTERVAL (1000000 - 1)/* micro sec, almost 1 sec */
-#define MAX_GTMRECV_POLL_INTERVAL 1000000 /* 1 sec in micro sec */
-
#define GTMRECV_WAIT_FOR_STARTJNLSEQNO 100 /* ms */
#define GTMRECV_WAIT_FOR_UPD_PROGRESS 100 /* ms */
-#define GTMRECV_WAIT_FOR_UPD_PROGRESS_US (GTMRECV_WAIT_FOR_UPD_PROGRESS * 1000) /* micro sec */
/* By having different high and low watermarks, we can reduce the # of XOFF/XON exchanges */
#define RECVPOOL_HIGH_WATERMARK_PCTG 90 /* Send XOFF when %age of receive pool space occupied goes beyond this */
@@ -133,13 +122,11 @@
GBLDEF repl_msg_ptr_t gtmrecv_msgp;
GBLDEF int gtmrecv_max_repl_msglen;
-GBLDEF struct timeval gtmrecv_poll_interval, gtmrecv_poll_immediate;
GBLDEF int gtmrecv_sock_fd = FD_INVALID;
GBLDEF boolean_t repl_connection_reset = TRUE;
GBLDEF boolean_t gtmrecv_wait_for_jnl_seqno = FALSE;
GBLDEF boolean_t gtmrecv_bad_trans_sent = FALSE;
GBLDEF boolean_t gtmrecv_send_cmp2uncmp = FALSE;
-GBLDEF struct sockaddr_in primary_addr;
GBLDEF qw_num repl_recv_data_recvd = 0;
GBLDEF qw_num repl_recv_data_processed = 0;
@@ -251,6 +238,14 @@ static int heartbeat_period;
static boolean_t repl_cmp_solve_timer_set;
#endif
+#define ISSUE_REPLCOMM_ERROR(REASON, SAVE_ERRNO) \
+{ \
+ if (0 != SAVE_ERRNO) \
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_LIT(REASON), SAVE_ERRNO);\
+ else \
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_LIT(REASON)); \
+}
+
#define GTMRECV_EXPAND_CMPBUFF_IF_NEEDED(cmpmsglen) \
{ \
int lclcmpmsglen; \
@@ -396,13 +391,13 @@ STATICFNDEF void gtmrecv_repl_send_loop_error(int status, char *msgtypestr)
} else if (EREPL_SEND == repl_errno)
{
SNPRINTF(print_msg, SIZEOF(print_msg), "Error sending %s message. Error in send : %s",
- msgtypestr, STRERROR(status));
- rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(print_msg));
+ msgtypestr, STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(print_msg));
} else if (EREPL_SELECT == repl_errno)
{
SNPRINTF(print_msg, SIZEOF(print_msg), "Error sending %s message. Error in select : %s",
- msgtypestr, STRERROR(status));
- rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(print_msg));
+ msgtypestr, STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(print_msg));
}
}
@@ -613,7 +608,7 @@ STATICFNDEF void do_flow_control(uint4 write_pos)
memcpy((uchar_ptr_t)&xoff_msg.msg[0], (uchar_ptr_t)&temp_seq_num, SIZEOF(seq_num));
xoff_msg.len = GTM_BYTESWAP_32(MIN_REPL_MSGLEN);
}
- REPL_SEND_LOOP(gtmrecv_sock_fd, &xoff_msg, MIN_REPL_MSGLEN, FALSE, >mrecv_poll_immediate)
+ REPL_SEND_LOOP(gtmrecv_sock_fd, &xoff_msg, MIN_REPL_MSGLEN, REPL_POLL_NOWAIT)
{
GTMRECV_POLL_ACTIONS(data_len, buff_unprocessed, buffp);
}
@@ -626,9 +621,6 @@ STATICFNDEF void do_flow_control(uint4 write_pos)
"processed\n", space_used);
xoff_sent = TRUE;
xoff_msg_log_cnt = 1;
- assert(GTMRECV_WAIT_FOR_UPD_PROGRESS_US < MAX_GTMRECV_POLL_INTERVAL);
- gtmrecv_poll_interval.tv_sec = 0;
- gtmrecv_poll_interval.tv_usec = GTMRECV_WAIT_FOR_UPD_PROGRESS_US;
} else if (space_used < recvpool_low_watermark && xoff_sent)
{
if (!remote_side->cross_endian)
@@ -643,7 +635,7 @@ STATICFNDEF void do_flow_control(uint4 write_pos)
memcpy((uchar_ptr_t)&xon_msg.msg[0], (uchar_ptr_t)&temp_seq_num, SIZEOF(seq_num));
xon_msg.len = GTM_BYTESWAP_32(MIN_REPL_MSGLEN);
}
- REPL_SEND_LOOP(gtmrecv_sock_fd, &xon_msg, MIN_REPL_MSGLEN, FALSE, >mrecv_poll_immediate)
+ REPL_SEND_LOOP(gtmrecv_sock_fd, &xon_msg, MIN_REPL_MSGLEN, REPL_POLL_NOWAIT)
{
GTMRECV_POLL_ACTIONS(data_len, buff_unprocessed, buffp);
}
@@ -656,8 +648,6 @@ STATICFNDEF void do_flow_control(uint4 write_pos)
"data\n", recvpool_size - space_used);
xoff_sent = FALSE;
xoff_msg_log_cnt = 0;
- gtmrecv_poll_interval.tv_sec = 0;
- gtmrecv_poll_interval.tv_usec = GTMRECV_POLL_INTERVAL;
}
return;
}
@@ -667,37 +657,26 @@ STATICFNDEF int gtmrecv_est_conn(void)
recvpool_ctl_ptr_t recvpool_ctl;
upd_proc_local_ptr_t upd_proc_local;
gtmrecv_local_ptr_t gtmrecv_local;
- GTM_SOCKLEN_TYPE primary_addr_len;
- fd_set input_fds;
- int status;
boolean_t keepalive;
- int keepalive_opt;
- int optval;
GTM_SOCKLEN_TYPE optlen;
+ int status, keepalive_opt, optval, save_errno;
+ int send_buffsize, recv_buffsize, tcp_r_bufsize;
struct linger disable_linger = {0, 0};
- struct timeval save_gtmrecv_poll_interval, sel_timeout_val;
char print_msg[1024];
- int send_buffsize, recv_buffsize, tcp_r_bufsize;
- short retry_num;
-#ifdef GTM_USE_POLL_FOR_SUBSECOND_SELECT
- long poll_timeout;
- unsigned long poll_nfds;
- struct pollfd poll_fdlist[1];
-#endif
+ struct addrinfo primary_ai;
+ struct sockaddr_storage primary_sas;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
- /* Wait for a connection from a Source Server.
- * The Receiver Server is an iterative server.
- */
+ /* Wait for a connection from a Source Server. The Receiver Server is an iterative server. */
recvpool_ctl = recvpool.recvpool_ctl;
upd_proc_local = recvpool.upd_proc_local;
gtmrecv_local = recvpool.gtmrecv_local;
-
+ /* Create a listen socket */
gtmrecv_comm_init((in_port_t)gtmrecv_local->listen_port);
- primary_addr_len = SIZEOF(primary_addr);
+ primary_ai.ai_addr = (sockaddr_ptr)&primary_sas;
+ primary_ai.ai_addrlen = SIZEOF(primary_sas);
repl_log(gtmrecv_log_fp, TRUE, TRUE, "Waiting for a connection...\n");
-
/* Null initialize fields that need to be initialized only after connecting to the primary.
* It is ok not to hold a lock on the journal pool while updating jnlpool_ctl fields since this will be the only
* process updating those fields.
@@ -705,115 +684,41 @@ STATICFNDEF int gtmrecv_est_conn(void)
assert(remote_side == >mrecv_local->remote_side);
remote_side->proto_ver = REPL_PROTO_VER_UNINITIALIZED;
jnlpool_ctl->primary_instname[0] = '\0';
-
-#ifndef GTM_USE_POLL_FOR_SUBSECOND_SELECT
- FD_ZERO(&input_fds);
- FD_SET(gtmrecv_listen_sock_fd, &input_fds);
- save_gtmrecv_poll_interval = gtmrecv_poll_interval;
-#else
- poll_fdlist[0].fd = gtmrecv_listen_sock_fd;
- poll_fdlist[0].events = POLLIN;
- poll_nfds = 1;
- poll_timeout = gtmrecv_poll_interval.tv_usec / 1000; /* convert to millisecs */
-#endif
- /*
- * Note - the following while loop checks for EINTR on the select. The
- * SELECT macro is not used because the FD_SET is redone before the new
- * call to select (after the continue).
- */
- while (0 >=
-#ifndef GTM_USE_POLL_FOR_SUBSECOND_SELECT
- (status = select(gtmrecv_listen_sock_fd + 1, &input_fds, NULL, NULL, &save_gtmrecv_poll_interval))
-#else
- (status = poll(&poll_fdlist[0], poll_nfds, poll_timeout))
-#endif
- )
- {
-#ifndef GTM_USE_POLL_FOR_SUBSECOND_SELECT
- save_gtmrecv_poll_interval = gtmrecv_poll_interval;
- FD_SET(gtmrecv_listen_sock_fd, &input_fds);
-#endif
- if (0 == status)
- gtmrecv_poll_actions(0, 0, NULL);
- else if (EINTR == errno || EAGAIN == errno)
- continue;
- else
- {
- status = ERRNO;
- SNPRINTF(print_msg, SIZEOF(print_msg), "Error in select on listen socket : %s", STRERROR(status));
- rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(print_msg));
- }
- }
- ACCEPT_SOCKET(gtmrecv_listen_sock_fd, (struct sockaddr *)&primary_addr,
- (GTM_SOCKLEN_TYPE *)&primary_addr_len, gtmrecv_sock_fd);
- if (FD_INVALID == gtmrecv_sock_fd)
+ while (TRUE)
{
- status = ERRNO;
-#ifdef __hpux
- /* ENOBUFS will normally signify a transient state. Hence retry before issuing an error*/
- if (ENOBUFS == status)
+ while (TRUE)
{
- retry_num = 0;
- while (HPUX_MAX_RETRIES > retry_num)
+ if (0 < (status = fd_ioready(gtmrecv_listen_sock_fd, TRUE, REPL_POLL_WAIT)))
+ break;
+ if (-1 == status)
{
- /*In case of succeeding with select in first go, accept will still get 5ms time difference*/
- SHORT_SLEEP(5);
- for ( ; HPUX_MAX_RETRIES > retry_num; retry_num++)
- {
-#ifndef GTM_USE_POLL_FOR_SUBSECOND_SELECT
- sel_timeout_val.tv_sec = 0;
- sel_timeout_val.tv_usec = HPUX_SEL_TIMEOUT;
- FD_ZERO(&input_fds);
- FD_SET(gtmrecv_listen_sock_fd, &input_fds);
- status = select(gtmrecv_listen_sock_fd + 1, &input_fds, NULL, NULL, &sel_timeout_val);
-#else
- poll_fdlist[0].fd = gtmrecv_listen_sock_fd;
- poll_fdlist[0].events = POLLIN;
- poll_nfds = 1;
- poll_timeout = HPUX_SEL_TIMEOUT / 1000; /* convert to millisecs */
- status = poll(&poll_fdlist[0], poll_nfds, poll_timeout);
-#endif
- if (0 == status)
- gtmrecv_poll_actions(0, 0, NULL);
- if (0 < status)
- break;
- else
- SHORT_SLEEP(5);
- }
- if (0 > status)
- {
- status = ERRNO;
- SNPRINTF(print_msg, SIZEOF(print_msg),"Error in select on listen socket after ENOBUFS : %s",
- STRERROR(status));
- rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(print_msg));
- }
- ACCEPT_SOCKET(gtmrecv_listen_sock_fd, (struct sockaddr *)&primary_addr,
- (GTM_SOCKLEN_TYPE *)&primary_addr_len, gtmrecv_sock_fd);
- status = ERRNO;
- if ((FD_INVALID == gtmrecv_sock_fd) && (ENOBUFS == status))
- retry_num++;
- else
- break;
- }
+ save_errno = errno;
+ assert((EAGAIN != save_errno) && (EINTR != save_errno));
+ ISSUE_REPLCOMM_ERROR("Error in select on listen socket", save_errno);
+ } else if (0 == status) /* timeout */
+ gtmrecv_poll_actions(0, 0, NULL);
}
+ ACCEPT_SOCKET(gtmrecv_listen_sock_fd, primary_ai.ai_addr,
+ (GTM_SOCKLEN_TYPE *)&primary_ai.ai_addrlen, gtmrecv_sock_fd);
if (FD_INVALID == gtmrecv_sock_fd)
-#endif
{
- status = ERRNO;
- SNPRINTF(print_msg, SIZEOF(print_msg), "Error accepting connection from Source Server : %s",
- STRERROR(status));
- rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(print_msg));
+ save_errno = errno;
+# ifdef __hpux
+ if (ENOBUFS == save_errno)
+ {
+ gtmrecv_poll_actions(0, 0, NULL);
+ continue;
+ }
+# endif
+ ISSUE_REPLCOMM_ERROR("Error accepting connection from Source Server", save_errno);
}
+ break;
}
/* Connection established */
repl_close(>mrecv_listen_sock_fd); /* Close the listener socket */
repl_connection_reset = FALSE;
if (-1 == setsockopt(gtmrecv_sock_fd, SOL_SOCKET, SO_LINGER, (const void *)&disable_linger, SIZEOF(disable_linger)))
- {
- status = ERRNO;
- SNPRINTF(print_msg, SIZEOF(print_msg), "Error with receiver server socket disable linger : %s", STRERROR(status));
- rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(print_msg));
- }
+ ISSUE_REPLCOMM_ERROR("Error with receiver server socket disable linger", errno);
# ifdef REPL_DISABLE_KEEPALIVE
keepalive = FALSE;
# else
@@ -822,12 +727,9 @@ STATICFNDEF int gtmrecv_est_conn(void)
if (-1 == setsockopt(gtmrecv_sock_fd, SOL_SOCKET, SO_KEEPALIVE, (const void *)&keepalive,
SIZEOF(keepalive)))
{
- status = ERRNO;
- SNPRINTF(print_msg, SIZEOF(print_msg), "Error with receiver server socket enabling keepalive: %s",
- STRERROR(status));
- rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(print_msg));
+ ISSUE_REPLCOMM_ERROR("Error with receiver server socket enable keepalive", errno);
}
- /* set up the keepalive parameters
+ /* Set up the keepalive parameters
* TCP_KEEPCNT : overrides tcp_keepalive_probes
* TCP_KEEPIDLE: overrides tcp_keepalive_time
* TCP_KEEPINTVL: overrides tcp_keepalive_intvl
@@ -835,75 +737,39 @@ STATICFNDEF int gtmrecv_est_conn(void)
# if defined(KEEPALIVE_PROTO_LEVEL)
keepalive_opt = KEEPALIVE_PROBES;
if (-1 == setsockopt(gtmrecv_sock_fd, KEEPALIVE_PROTO_LEVEL, TCP_KEEPCNT, (void*)&keepalive_opt, SIZEOF(keepalive_opt)))
- {
- status = ERRNO;
- SNPRINTF(print_msg, SIZEOF(print_msg), "Error with receiver server socket setting tcp_keepalive_probes : %s",
- STRERROR(status));
- rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(print_msg));
- }
+ ISSUE_REPLCOMM_ERROR("Error with receiver server socket setting tcp_keepalive_probes", errno);
keepalive_opt = KEEPALIVE_TIME;
if (-1 == setsockopt(gtmrecv_sock_fd, KEEPALIVE_PROTO_LEVEL, TCP_KEEPIDLE, (void*)&keepalive_opt, SIZEOF(keepalive_opt)))
- {
- status = ERRNO;
- SNPRINTF(print_msg, SIZEOF(print_msg), "Error with receiver server socket setting tcp_keepalive_time: %s",
- STRERROR(status));
- rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(print_msg));
- }
+ ISSUE_REPLCOMM_ERROR("Error with receiver server socket setting tcp_keepalive_time", errno);
keepalive_opt = KEEPALIVE_INTVL;
if (-1 == setsockopt(gtmrecv_sock_fd, KEEPALIVE_PROTO_LEVEL, TCP_KEEPINTVL, (void*)&keepalive_opt, SIZEOF(keepalive_opt)))
- {
- status = ERRNO;
- SNPRINTF(print_msg, SIZEOF(print_msg), "Error with receiver server socket setting tcp_keepalive_intvl: %s",
- STRERROR(status));
- rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(print_msg));
- }
+ ISSUE_REPLCOMM_ERROR("Error with receiver server socket setting tcp_keepalive_intvl", errno);
# endif
optlen = SIZEOF(optval);
if ( -1 == getsockopt(gtmrecv_sock_fd, SOL_SOCKET, SO_KEEPALIVE, &optval, &optlen))
- {
- status = ERRNO;
- SNPRINTF(print_msg, SIZEOF(print_msg), "Error with receiver server socket checking keepalive enabled or not: %s",
- STRERROR(status));
- rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(print_msg));
- }
+ ISSUE_REPLCOMM_ERROR("Error with receiver server socket checking keepalive enabled or not", errno)
# if !defined(KEEPALIVE_PROTO_LEVEL)
repl_log(gtmrecv_log_fp, TRUE, TRUE, "SO_KEEPALIVE is %s\n", (optval ? "ON" : "OFF"));
# else
repl_log(gtmrecv_log_fp, TRUE, TRUE, "SO_KEEPALIVE is %s. ", (optval ? "ON" : "OFF"));
+
if (-1 == getsockopt(gtmrecv_sock_fd, KEEPALIVE_PROTO_LEVEL, TCP_KEEPCNT, &optval, &optlen))
- {
- status = ERRNO;
- SNPRINTF(print_msg, SIZEOF(print_msg), "Error with receiver server socket getting tcp_keepalive_probes: %s",
- STRERROR(status));
- rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(print_msg));
- }
+ ISSUE_REPLCOMM_ERROR("Error with receiver server socket getting tcp_keepalive_probes", errno);
if (optval)
repl_log(gtmrecv_log_fp, FALSE, TRUE, "TCP_KEEPCNT is %d, ", optval);
if (-1 == getsockopt(gtmrecv_sock_fd, KEEPALIVE_PROTO_LEVEL, TCP_KEEPIDLE, &optval, &optlen))
- {
- status = ERRNO;
- SNPRINTF(print_msg, SIZEOF(print_msg), "Error with receiver server socket getting tcp_keepalive_time: %s",
- STRERROR(status));
- rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(print_msg));
- }
+ ISSUE_REPLCOMM_ERROR("Error with receiver server socket getting tcp_keepalive_time", errno);
if (optval)
repl_log(gtmrecv_log_fp, FALSE, TRUE, "TCP_KEEPIDLE is %d, ", optval);
+
if (-1 == getsockopt(gtmrecv_sock_fd, KEEPALIVE_PROTO_LEVEL, TCP_KEEPINTVL, &optval, &optlen))
- {
- status = ERRNO;
- SNPRINTF(print_msg, SIZEOF(print_msg), "Error with receiver server socket getting tcp_keepalive_intvl: %s",
- STRERROR(status));
- rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(print_msg));
- }
+ ISSUE_REPLCOMM_ERROR("Error with receiver server socket getting tcp_keepalive_intvl", errno);
if (optval)
repl_log(gtmrecv_log_fp, FALSE, TRUE, "TCP_KEEPINTVL is %d.\n", optval);
# endif
if (0 != (status = get_send_sock_buff_size(gtmrecv_sock_fd, &send_buffsize)))
- {
- SNPRINTF(print_msg, SIZEOF(print_msg), "Error getting socket send buffsize : %s", STRERROR(status));
- rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(print_msg));
- }
+ ISSUE_REPLCOMM_ERROR("Error getting socket send buffsize", errno);
if (send_buffsize < GTMRECV_TCP_SEND_BUFSIZE)
{
if (0 != (status = set_send_sock_buff_size(gtmrecv_sock_fd, GTMRECV_TCP_SEND_BUFSIZE)))
@@ -912,20 +778,15 @@ STATICFNDEF int gtmrecv_est_conn(void)
{
SNPRINTF(print_msg, SIZEOF(print_msg), "Could not set TCP send buffer size to %d : %s",
GTMRECV_MIN_TCP_SEND_BUFSIZE, STRERROR(status));
- rts_error(VARLSTCNT(6) MAKE_MSG_INFO(ERR_REPLCOMM), 0, ERR_TEXT, 2, RTS_ERROR_STRING(print_msg));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) MAKE_MSG_INFO(ERR_REPLCOMM), 0,
+ ERR_TEXT, 2, LEN_AND_STR(print_msg));
}
}
}
if (0 != (status = get_send_sock_buff_size(gtmrecv_sock_fd, &repl_max_send_buffsize))) /* may have changed */
- {
- SNPRINTF(print_msg, SIZEOF(print_msg), "Error getting socket send buffsize : %s", STRERROR(status));
- rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(print_msg));
- }
+ ISSUE_REPLCOMM_ERROR("Error getting socket send buffsize", errno);
if (0 != (status = get_recv_sock_buff_size(gtmrecv_sock_fd, &recv_buffsize)))
- {
- SNPRINTF(print_msg, SIZEOF(print_msg), "Error getting socket recv buffsize : %s", STRERROR(status));
- rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(print_msg));
- }
+ ISSUE_REPLCOMM_ERROR("Error getting socket recv buffsize", errno);
if (recv_buffsize < GTMRECV_TCP_RECV_BUFSIZE)
{
for (tcp_r_bufsize = GTMRECV_TCP_RECV_BUFSIZE;
@@ -938,14 +799,12 @@ STATICFNDEF int gtmrecv_est_conn(void)
SNPRINTF(print_msg, SIZEOF(print_msg), "Could not set TCP receive buffer size in range [%d, %d], last "
"known error : %s", GTMRECV_MIN_TCP_RECV_BUFSIZE, GTMRECV_TCP_RECV_BUFSIZE,
STRERROR(status));
- rts_error(VARLSTCNT(6) MAKE_MSG_INFO(ERR_REPLCOMM), 0, ERR_TEXT, 2, RTS_ERROR_STRING(print_msg));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) MAKE_MSG_INFO(ERR_REPLCOMM), 0,
+ ERR_TEXT, 2, LEN_AND_STR(print_msg));
}
}
if (0 != (status = get_recv_sock_buff_size(gtmrecv_sock_fd, &repl_max_recv_buffsize))) /* may have changed */
- {
- SNPRINTF(print_msg, SIZEOF(print_msg), "Error getting socket recv buffsize : %s", STRERROR(status));
- rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(print_msg));
- }
+ ISSUE_REPLCOMM_ERROR("Error getting socket recv buffsize", errno);
repl_log(gtmrecv_log_fp, TRUE, TRUE, "Connection established, using TCP send buffer size %d receive buffer size %d\n",
repl_max_send_buffsize, repl_max_recv_buffsize);
repl_log_conn_info(gtmrecv_sock_fd, gtmrecv_log_fp);
@@ -1063,7 +922,7 @@ void gtmrecv_repl_send(repl_msg_ptr_t msgp, int4 type, int4 len, char *msgtypest
msgp->type = GTM_BYTESWAP_32(type);
msgp->len = GTM_BYTESWAP_32(len);
}
- REPL_SEND_LOOP(gtmrecv_sock_fd, msgp, len, FALSE, >mrecv_poll_immediate)
+ REPL_SEND_LOOP(gtmrecv_sock_fd, msgp, len, REPL_POLL_NOWAIT)
{
GTMRECV_POLL_ACTIONS(data_len, buff_unprocessed, buffp);
}
@@ -1111,8 +970,8 @@ void gtmrecv_check_and_send_instinfo(repl_needinst_msg_ptr_t need_instinfo_msg,
*/
if (is_rcvr_srvr && recvpool.gtmrecv_local->updateresync && (FD_INVALID == recvpool.gtmrecv_local->updresync_instfile_fd))
{
- rts_error(VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2,
- RTS_ERROR_LITERAL("Source side is >= V5.5-000 implies -UPDATERESYNC needs a value specified"));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2,
+ LEN_AND_LIT("Source side is >= V5.5-000 implies -UPDATERESYNC needs a value specified"));
assert(FALSE); /* we dont expect the rts_error to return control */
}
/* We usually expect the LMS group info to be non-NULL on both primary and secondary. An exception is if
@@ -1134,15 +993,16 @@ void gtmrecv_check_and_send_instinfo(repl_needinst_msg_ptr_t need_instinfo_msg,
{ /* this supplementary instance was started with -UPDOK. Issue error if source is also supplementary */
if (need_instinfo_msg->is_supplementary)
{
- rts_error(VARLSTCNT(6) ERR_NOSUPPLSUPPL, 4, LEN_AND_STR((char *)inst_hdr->inst_info.this_instname),
- LEN_AND_STR((char *)need_instinfo_msg->instname));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_NOSUPPLSUPPL, 4,
+ LEN_AND_STR((char *)inst_hdr->inst_info.this_instname),
+ LEN_AND_STR((char *)need_instinfo_msg->instname));
assert(FALSE); /* we dont expect the rts_error to return control */
}
} else
{ /* this supplementary instance was started with -UPDNOTOK. Issue error if source is not supplementary */
if (!need_instinfo_msg->is_supplementary)
{
- rts_error(VARLSTCNT(6) ERR_SUPRCVRNEEDSSUPSRC, 4,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_SUPRCVRNEEDSSUPSRC, 4,
LEN_AND_STR((char *)inst_hdr->inst_info.this_instname),
LEN_AND_STR((char *)need_instinfo_msg->instname));
assert(FALSE); /* we dont expect the rts_error to return control */
@@ -1167,8 +1027,9 @@ void gtmrecv_check_and_send_instinfo(repl_needinst_msg_ptr_t need_instinfo_msg,
*/
if (!inst_hdr->is_supplementary || remote_side_is_supplementary)
{
- rts_error(VARLSTCNT(6) ERR_INSNOTJOINED, 4, LEN_AND_STR((char *)inst_hdr->inst_info.this_instname),
- LEN_AND_STR((char *)need_instinfo_msg->instname));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_INSNOTJOINED, 4,
+ LEN_AND_STR((char *)inst_hdr->inst_info.this_instname),
+ LEN_AND_STR((char *)need_instinfo_msg->instname));
assert(FALSE); /* we dont expect the rts_error to return control */
}
} else
@@ -1178,8 +1039,9 @@ void gtmrecv_check_and_send_instinfo(repl_needinst_msg_ptr_t need_instinfo_msg,
if (inst_hdr->is_supplementary && !remote_side_is_supplementary)
{
assert(!need_instinfo_msg->is_supplementary); /* else NOSUPPLSUPPL error must have been issued */
- rts_error(VARLSTCNT(6) ERR_INSROLECHANGE, 4, LEN_AND_STR((char *)inst_hdr->inst_info.this_instname),
- LEN_AND_STR((char *)need_instinfo_msg->instname));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_INSROLECHANGE, 4,
+ LEN_AND_STR((char *)inst_hdr->inst_info.this_instname),
+ LEN_AND_STR((char *)need_instinfo_msg->instname));
assert(FALSE); /* we dont expect the rts_error to return control */
}
}
@@ -1191,8 +1053,8 @@ void gtmrecv_check_and_send_instinfo(repl_needinst_msg_ptr_t need_instinfo_msg,
if (memcmp(&recvpool.gtmrecv_local->updresync_lms_group,
&need_instinfo_msg->lms_group_info, SIZEOF(inst_hdr->lms_group_info)))
{
- rts_error(VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2,
- RTS_ERROR_LITERAL("Specified input instance file does not have same "
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2,
+ LEN_AND_LIT("Specified input instance file does not have same "
"LMS Group information as source server instance"));
}
}
@@ -1204,7 +1066,7 @@ void gtmrecv_check_and_send_instinfo(repl_needinst_msg_ptr_t need_instinfo_msg,
*/
if (grab_lock_needed)
{
- grab_lock(jnlpool.jnlpool_dummy_reg, GRAB_LOCK_ONLY);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, GRAB_LOCK_ONLY);
if (is_rcvr_srvr)
GTMRECV_ONLN_RLBK_CLNUP_IF_NEEDED;
}
@@ -1230,7 +1092,7 @@ void gtmrecv_check_and_send_instinfo(repl_needinst_msg_ptr_t need_instinfo_msg,
*/
if (grab_lock_needed)
{
- grab_lock(jnlpool.jnlpool_dummy_reg, GRAB_LOCK_ONLY);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, GRAB_LOCK_ONLY);
if (is_rcvr_srvr)
GTMRECV_ONLN_RLBK_CLNUP_IF_NEEDED;
}
@@ -1252,7 +1114,7 @@ void gtmrecv_check_and_send_instinfo(repl_needinst_msg_ptr_t need_instinfo_msg,
if (strm_info == strm_top)
{ /* -REUSE specified an instance name that is not present in any of the 15 strm_group slots */
rel_lock(jnlpool.jnlpool_dummy_reg);
- rts_error(VARLSTCNT(6) ERR_REUSEINSTNAME, 0, ERR_TEXT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REUSEINSTNAME, 0, ERR_TEXT, 2,
LEN_AND_LIT("Instance name in REUSE does not match any of 15 slots in instance file"));
}
assert(reuse_slot);
@@ -1291,15 +1153,16 @@ void gtmrecv_check_and_send_instinfo(repl_needinst_msg_ptr_t need_instinfo_msg,
{
if (grab_lock_needed)
rel_lock(jnlpool.jnlpool_dummy_reg);
- rts_error(VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2,
LEN_AND_LIT("No empty slot found. Specify REUSE to choose one for reuse"));
}
} else
{
if (grab_lock_needed)
rel_lock(jnlpool.jnlpool_dummy_reg);
- rts_error(VARLSTCNT(6) ERR_INSUNKNOWN, 4, LEN_AND_STR((char *)inst_hdr->inst_info.this_instname),
- LEN_AND_STR((char *)need_instinfo_msg->instname));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_INSUNKNOWN, 4,
+ LEN_AND_STR((char *)inst_hdr->inst_info.this_instname),
+ LEN_AND_STR((char *)need_instinfo_msg->instname));
assert(FALSE); /* we dont expect the rts_error to return control */
}
/* Since we did not find the stream in the existing instance file but did find a slot, fill that slot
@@ -1320,13 +1183,13 @@ void gtmrecv_check_and_send_instinfo(repl_needinst_msg_ptr_t need_instinfo_msg,
{ /* If -RESUME was specified, then the slot it matched must be same as slot found without its use */
assert(is_rcvr_srvr);
rel_lock(jnlpool.jnlpool_dummy_reg);
- rts_error(VARLSTCNT(6) ERR_RESUMESTRMNUM, 0, ERR_TEXT, 2, LEN_AND_LIT("Source side LMS "
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RESUMESTRMNUM, 0, ERR_TEXT, 2, LEN_AND_LIT("Source side LMS "
"group is found in instance file but RESUME specifies different stream number"));
} else if (reuse_slot && (reuse_slot != strm_index))
{ /* If -REUSE was specified, then the slot it matched must be same as slot found without its use */
assert(is_rcvr_srvr);
rel_lock(jnlpool.jnlpool_dummy_reg);
- rts_error(VARLSTCNT(6) ERR_REUSEINSTNAME, 0, ERR_TEXT, 2, LEN_AND_LIT("Source side LMS "
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REUSEINSTNAME, 0, ERR_TEXT, 2, LEN_AND_LIT("Source side LMS "
"group is found in instance file but REUSE specifies different instance name"));
}
assert(INVALID_SUPPL_STRM != strm_index);
@@ -1342,10 +1205,12 @@ void gtmrecv_check_and_send_instinfo(repl_needinst_msg_ptr_t need_instinfo_msg,
* update process, issue error. Note: This limitation "might" be removed in the future.
*/
rel_lock(jnlpool.jnlpool_dummy_reg);
- rts_error(VARLSTCNT(4) ERR_RCVRMANYSTRMS, 2, strm_index, recvpool.gtmrecv_local->strm_index);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_RCVRMANYSTRMS, 2,
+ strm_index, recvpool.gtmrecv_local->strm_index);
}
recvpool.gtmrecv_local->strm_index = strm_index;
- repl_log(gtmrecv_log_fp, TRUE, TRUE, "Determined non-supplementary source Stream # = %d\n", strm_index);
+ repl_log(gtmrecv_log_fp, TRUE, TRUE,
+ "Determined non-supplementary source Stream # = %d\n", strm_index);
assert(IS_REPL_INST_UUID_NON_NULL(need_instinfo_msg->lms_group_info));
recvpool.gtmrecv_local->remote_lms_group = need_instinfo_msg->lms_group_info;
rel_lock(jnlpool.jnlpool_dummy_reg);
@@ -1443,7 +1308,7 @@ void gtmrecv_check_and_send_instinfo(repl_needinst_msg_ptr_t need_instinfo_msg,
memcpy(instinfo_msg.instname, inst_hdr->inst_info.this_instname, MAX_INSTNAME_LEN - 1);
if (grab_lock_needed)
{
- grab_lock(jnlpool.jnlpool_dummy_reg, GRAB_LOCK_ONLY);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, GRAB_LOCK_ONLY);
if (is_rcvr_srvr)
GTMRECV_ONLN_RLBK_CLNUP_IF_NEEDED;
}
@@ -1474,15 +1339,19 @@ void gtmrecv_check_and_send_instinfo(repl_needinst_msg_ptr_t need_instinfo_msg,
* In that case, P can never be a root primary of the non-supplementary group and therefore
* cannot be affected by lost transactions being applied from the non-supplementary group.
*/
- if ((!inst_hdr->is_supplementary || remote_side_is_supplementary) && !need_instinfo_msg->is_rootprimary
- && (instinfo_msg.was_rootprimary || (is_rcvr_srvr && jnlpool_ctl->max_zqgblmod_seqno)))
+ if ((!inst_hdr->is_supplementary || remote_side_is_supplementary)
+ && !need_instinfo_msg->is_rootprimary
+ && (instinfo_msg.was_rootprimary
+ || (is_rcvr_srvr && jnlpool_ctl->max_zqgblmod_seqno)))
{
if (is_rcvr_srvr)
{
- gtm_putmsg(VARLSTCNT(4) ERR_PRIMARYNOTROOT, 2, LEN_AND_STR((char *) need_instinfo_msg->instname));
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_PRIMARYNOTROOT, 2,
+ LEN_AND_STR((char *) need_instinfo_msg->instname));
gtmrecv_autoshutdown(); /* should not return */
} else
- rts_error(VARLSTCNT(4) ERR_PRIMARYNOTROOT, 2, LEN_AND_STR((char *) need_instinfo_msg->instname));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_PRIMARYNOTROOT, 2,
+ LEN_AND_STR((char *) need_instinfo_msg->instname));
assert(FALSE);
}
if (is_rcvr_srvr)
@@ -1511,8 +1380,8 @@ STATICFNDEF int gtmrecv_start_onln_rlbk(void)
assert(0 < gtmrecv_local->listen_port);
SNPRINTF(&command[cmdlen], ONLN_RLBK_CMD_MAXLEN, "%d", gtmrecv_local->listen_port); /* will add '\0' at the end */
repl_log(gtmrecv_log_fp, TRUE, TRUE, "Executing %s\n", command);
- if (0 != (status = SYSTEM((char *)command)))
-
+ status = SYSTEM(((char *)command));
+ if (0 != status)
{
if (-1 == status)
{
@@ -1632,8 +1501,8 @@ STATICFNDEF void prepare_recvpool_for_write(int datalen, int pre_filter_write_le
recvpool_ctl = recvpool.recvpool_ctl;
if (datalen > recvpool_size)
{ /* Too large a transaction to be accommodated in the Receive Pool */
- rts_error(VARLSTCNT(7) ERR_REPLTRANS2BIG, 5, &recvpool_ctl->jnl_seqno, datalen, pre_filter_write_len,
- RTS_ERROR_LITERAL("Receive"));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLTRANS2BIG, 5, &recvpool_ctl->jnl_seqno,
+ datalen, pre_filter_write_len, LEN_AND_LIT("Receive"));
}
if ((write_loc + datalen) > recvpool_size)
{
@@ -1851,7 +1720,7 @@ STATICFNDEF void process_tr_buff(int msg_type)
{
if (SS_NORMAL != (status = repl_tr_endian_convert(remote_side->jnl_ver,
recvpool.recvdata_base + write_off, write_len)))
- rts_error(VARLSTCNT(5) ERR_REPLXENDIANFAIL, 3, LEN_AND_LIT("Replicating"),
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_REPLXENDIANFAIL, 3, LEN_AND_LIT("Replicating"),
&recvpool.upd_proc_local->read_jnl_seqno);
}
if (!is_new_histrec)
@@ -1887,17 +1756,19 @@ STATICFNDEF void process_tr_buff(int msg_type)
{
assert(EREPL_INTLFILTER_SECNODZTRIGINTP == repl_errno);
if (EREPL_INTLFILTER_BADREC == repl_errno)
- rts_error(VARLSTCNT(1) ERR_JNLRECFMT);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JNLRECFMT);
else if (EREPL_INTLFILTER_DATA2LONG == repl_errno)
- rts_error(VARLSTCNT(4) ERR_JNLSETDATA2LONG, 2, jnl_source_datalen,
- jnl_dest_maxdatalen);
+ 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(VARLSTCNT(4) ERR_JNLNEWREC, 2, (unsigned int)jnl_source_rectype,
- (unsigned int)jnl_dest_maxrectype);
+ 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(VARLSTCNT(1) ERR_REPLGBL2LONG);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_REPLGBL2LONG);
else if (EREPL_INTLFILTER_SECNODZTRIGINTP == repl_errno)
- rts_error(VARLSTCNT(3) ERR_SECNODZTRIGINTP, 1, &recvpool_ctl->jnl_seqno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_SECNODZTRIGINTP, 1,
+ &recvpool_ctl->jnl_seqno);
else /* (EREPL_INTLFILTER_INCMPLREC == repl_errno) */
GTMASSERT;
}
@@ -2324,21 +2195,22 @@ STATICFNDEF void gtmrecv_updresync_histinfo_find_seqno(seq_num input_seqno, int4
histinfo_num = recvpool.gtmrecv_local->updresync_num_histinfo_strm[strm_num];
if (INVALID_HISTINFO_NUM == histinfo_num)
{ /* The instance file cannot be used for updateresync if it has NO history records. */
- rts_error(VARLSTCNT(9) ERR_UPDSYNCINSTFILE, 0, ERR_STRMNUMIS, 1, strm_num, ERR_TEXT, 2,
- RTS_ERROR_LITERAL("Input instance file has NO history records"));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_UPDSYNCINSTFILE, 0, ERR_STRMNUMIS, 1, strm_num, ERR_TEXT, 2,
+ LEN_AND_LIT("Input instance file has NO history records"));
}
assert(0 <= histinfo_num);
if (!recvpool.gtmrecv_local->updresync_jnl_seqno)
{ /* The instance file cannot be used for updateresync if it has a ZERO seqno */
- rts_error(VARLSTCNT(9) ERR_UPDSYNCINSTFILE, 0, ERR_STRMNUMIS, 1, strm_num,
- ERR_TEXT, 2, RTS_ERROR_LITERAL("Input instance file has jnl_seqno of 0"));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_UPDSYNCINSTFILE, 0, ERR_STRMNUMIS, 1, strm_num,
+ ERR_TEXT, 2, LEN_AND_LIT("Input instance file has jnl_seqno of 0"));
}
if (input_seqno > recvpool.gtmrecv_local->updresync_jnl_seqno)
{ /* Input seqno is greater than the max seqno in the updateresync input instance file. So can never be found. */
SNPRINTF(print_msg, SIZEOF(print_msg), "Seqno "INT8_FMT" "INT8_FMTX" cannot be found in input instance file "
" which has a max seqno of "INT8_FMT" "INT8_FMTX"\n", input_seqno, input_seqno,
recvpool.gtmrecv_local->updresync_jnl_seqno, recvpool.gtmrecv_local->updresync_jnl_seqno);
- rts_error(VARLSTCNT(9) ERR_UPDSYNCINSTFILE, 0, ERR_STRMNUMIS, 1, strm_num, ERR_TEXT, 2, LEN_AND_STR(print_msg));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_UPDSYNCINSTFILE, 0,
+ ERR_STRMNUMIS, 1, strm_num, ERR_TEXT, 2, LEN_AND_STR(print_msg));
}
histinfo->start_seqno = 0;
do
@@ -2351,14 +2223,14 @@ STATICFNDEF void gtmrecv_updresync_histinfo_find_seqno(seq_num input_seqno, int4
* error indicates to the user it is the -updateresync qualifier where the issue is so it is not a big loss.
*/
if (-1 == status)
- rts_error(VARLSTCNT(15) ERR_UPDSYNCINSTFILE, 0,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(15) ERR_UPDSYNCINSTFILE, 0,
ERR_STRMNUMIS, 1, strm_num,
- ERR_TEXT, 2, RTS_ERROR_LITERAL("Error reading history record"),
+ ERR_TEXT, 2, LEN_AND_LIT("Error reading history record"),
ERR_REPLINSTREAD, 4, SIZEOF(repl_histinfo), (qw_off_t *)&offset, LEN_AND_LIT(""));
else
- rts_error(VARLSTCNT(16) ERR_UPDSYNCINSTFILE, 0,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(16) ERR_UPDSYNCINSTFILE, 0,
ERR_STRMNUMIS, 1, strm_num,
- ERR_TEXT, 2, RTS_ERROR_LITERAL("Error reading history record"),
+ ERR_TEXT, 2, LEN_AND_LIT("Error reading history record"),
ERR_REPLINSTREAD, 4, SIZEOF(repl_histinfo), (qw_off_t *)&offset, LEN_AND_LIT(""), status);
}
if (recvpool.gtmrecv_local->updresync_cross_endian)
@@ -2368,9 +2240,11 @@ STATICFNDEF void gtmrecv_updresync_histinfo_find_seqno(seq_num input_seqno, int4
histinfo_num = (INVALID_SUPPL_STRM == strm_num) ? (histinfo_num - 1) : histinfo->prev_histinfo_num;
} while (INVALID_HISTINFO_NUM != histinfo_num);
/* Could not find history record in -updateresync= input instance file */
- SNPRINTF(print_msg, SIZEOF(print_msg), "Receiver side instance seqno "INT8_FMT" "INT8_FMTX" is less than"
- " any history record found in instance file", input_seqno, input_seqno);
- rts_error(VARLSTCNT(9) ERR_UPDSYNCINSTFILE, 0, ERR_STRMNUMIS, 1, strm_num, ERR_TEXT, 2, LEN_AND_STR(print_msg));
+ SNPRINTF(print_msg, SIZEOF(print_msg),
+ "Receiver side instance seqno "INT8_FMT" "INT8_FMTX" is less than"
+ " any history record found in instance file", input_seqno, input_seqno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_UPDSYNCINSTFILE, 0,
+ ERR_STRMNUMIS, 1, strm_num, ERR_TEXT, 2, LEN_AND_STR(print_msg));
}
/* Retrieve the "index"'th history record in the instance file specified using the -UPDATERESYNC qualifier.
@@ -2383,7 +2257,6 @@ STATICFNDEF void gtmrecv_updresync_histinfo_find_seqno(seq_num input_seqno, int4
*/
STATICFNDEF void gtmrecv_updresync_histinfo_get(int4 index, repl_histinfo *histinfo)
{
- char print_msg[1024];
int fd, status;
off_t offset;
@@ -2398,12 +2271,12 @@ STATICFNDEF void gtmrecv_updresync_histinfo_get(int4 index, repl_histinfo *histi
* error indicates to the user it is the -updateresync qualifier where the issue is so it is not a big loss.
*/
if (-1 == status)
- rts_error(VARLSTCNT(12) ERR_UPDSYNCINSTFILE, 0,
- ERR_TEXT, 2, RTS_ERROR_LITERAL("Error reading history record"),
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(12) ERR_UPDSYNCINSTFILE, 0,
+ ERR_TEXT, 2, LEN_AND_LIT("Error reading history record"),
ERR_REPLINSTREAD, 4, SIZEOF(repl_histinfo), (qw_off_t *)&offset, LEN_AND_LIT(""));
else
- rts_error(VARLSTCNT(13) ERR_UPDSYNCINSTFILE, 0,
- ERR_TEXT, 2, RTS_ERROR_LITERAL("Error reading history record"),
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_UPDSYNCINSTFILE, 0,
+ ERR_TEXT, 2, LEN_AND_LIT("Error reading history record"),
ERR_REPLINSTREAD, 4, SIZEOF(repl_histinfo), (qw_off_t *)&offset, LEN_AND_LIT(""), status);
}
if (recvpool.gtmrecv_local->updresync_cross_endian)
@@ -2473,7 +2346,7 @@ STATICFNDEF void gtmrecv_process_need_strminfo_msg(repl_needstrminfo_msg_ptr_t n
{
repl_log(gtmrecv_log_fp, TRUE, TRUE,
"Searching for the desired history in the replication instance file\n");
- grab_lock(jnlpool.jnlpool_dummy_reg, GRAB_LOCK_ONLY);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, GRAB_LOCK_ONLY);
GTMRECV_ONLN_RLBK_CLNUP_IF_NEEDED;
/* above macro will "return" if repl_connection_reset OR gtmrecv_wait_for_jnl_seqno is set */
status = repl_inst_wrapper_histinfo_find_seqno(need_strminfo_seqno, INVALID_SUPPL_STRM, &histinfo);
@@ -2578,7 +2451,7 @@ STATICFNDEF void gtmrecv_process_need_histinfo_msg(repl_needhistinfo_msg_ptr_t n
{ /* The history record needs to be found in the receiver side instance file */
repl_log(gtmrecv_log_fp, TRUE, TRUE,
"Searching for the desired history in the replication instance file\n");
- grab_lock(jnlpool.jnlpool_dummy_reg, GRAB_LOCK_ONLY);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, GRAB_LOCK_ONLY);
GTMRECV_ONLN_RLBK_CLNUP_IF_NEEDED;
/* above macro will "return" if repl_connection_reset OR gtmrecv_wait_for_jnl_seqno is set */
status = repl_inst_histinfo_get(need_histinfo_num, histinfo);
@@ -2667,7 +2540,7 @@ STATICFNDEF void gtmrecv_process_need_histinfo_msg(repl_needhistinfo_msg_ptr_t n
assert(NULL != jnlpool.jnlpool_dummy_reg);
repl_log(gtmrecv_log_fp, TRUE, TRUE,
"Searching for the desired history in the replication instance file\n");
- grab_lock(jnlpool.jnlpool_dummy_reg, GRAB_LOCK_ONLY);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, GRAB_LOCK_ONLY);
GTMRECV_ONLN_RLBK_CLNUP_IF_NEEDED;
status = repl_inst_wrapper_histinfo_find_seqno(need_histinfo_seqno, need_histinfo_strm_num, histinfo);
rel_lock(jnlpool.jnlpool_dummy_reg);
@@ -2711,8 +2584,7 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart)
{
/* The work-horse of the Receiver Server */
boolean_t dont_reply_to_heartbeat = FALSE, is_repl_cmpc;
- boolean_t uncmpfail, send_cross_endian;
- char print_msg[1024];
+ boolean_t uncmpfail, send_cross_endian, preserve_buffp, recvpool_prepared;
gtmrecv_local_ptr_t gtmrecv_local;
gtm_time4_t ack_time;
int4 msghdrlen, strm_num;
@@ -2739,12 +2611,13 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart)
seq_num request_from, recvd_jnl_seqno;
sgmnt_addrs *repl_csa;
uchar_ptr_t old_buffp;
- uint4 recvd_start_flags;
+ uint4 recvd_start_flags, len;
uLong cmplen;
uLongf destlen;
unsigned char *msg_ptr; /* needed for REPL_{SEND,RECV}_LOOP */
unsigned char remote_jnl_ver;
upd_proc_local_ptr_t upd_proc_local;
+ repl_logfile_info_msg_t *logfile_msgp, logfile_msg;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
@@ -2845,7 +2718,7 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart)
msgp->is_supplementary = jnlpool.repl_inst_filehdr->is_supplementary;
msgp->len = send_cross_endian ? GTM_BYTESWAP_32(MIN_REPL_MSGLEN) : MIN_REPL_MSGLEN;
msg_len = MIN_REPL_MSGLEN;
- REPL_SEND_LOOP(gtmrecv_sock_fd, msgp, msg_len, FALSE, >mrecv_poll_immediate)
+ REPL_SEND_LOOP(gtmrecv_sock_fd, msgp, msg_len, REPL_POLL_NOWAIT)
{
GTMRECV_POLL_ACTIONS(0, 0, NULL);
}
@@ -2870,12 +2743,11 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart)
repl_recv_lastlog_data_recvd = 0;
repl_recv_lastlog_data_procd = 0;
msghdrlen = REPL_MSG_HDRLEN;
-
while (TRUE)
{
recvd_len = gtmrecv_max_repl_msglen - buff_unprocessed;
while ((SS_NORMAL == (status = repl_recv(gtmrecv_sock_fd,
- (buffp + buff_unprocessed), &recvd_len, FALSE, >mrecv_poll_interval)))
+ (buffp + buff_unprocessed), &recvd_len, REPL_POLL_WAIT)))
&& (0 == recvd_len))
{
recvd_len = gtmrecv_max_repl_msglen - buff_unprocessed;
@@ -2884,10 +2756,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, gtmrecv_poll_interval is now 0.
- * Force wait before logging any message.
- */
- SHORT_SLEEP(GTMRECV_POLL_INTERVAL >> 10); /* approximate in ms */
+ { /* update process is still running slow, Force wait before logging any message. */
+ SHORT_SLEEP(REPL_POLL_WAIT >> 10); /* approximate in ms */
REPL_DPRINT1("Waiting for Update Process to clear recvpool space\n");
xoff_msg_log_cnt = 0;
} else if (xoff_sent)
@@ -2907,15 +2777,11 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart)
return;
} else
{
- SNPRINTF(print_msg, SIZEOF(print_msg), "Error in receiving from source. "
- "Error in recv : %s", STRERROR(status));
- rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(print_msg));
+ ISSUE_REPLCOMM_ERROR("Error in receiving from source. Error in recv", status);
}
} else if (EREPL_SELECT == repl_errno)
{
- SNPRINTF(print_msg, SIZEOF(print_msg), "Error in receiving from source. Error in select : %s",
- STRERROR(status));
- rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(print_msg));
+ ISSUE_REPLCOMM_ERROR("Error in receiving from source. Error in select", status);
}
}
if (repl_connection_reset)
@@ -2939,6 +2805,7 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart)
if (0 == data_len)
{
assert(0 == ((unsigned long)buffp % REPL_MSG_ALIGN));
+ DEBUG_ONLY(recvpool_prepared = FALSE);
if (!remote_side->endianness_known)
{
remote_side->endianness_known = TRUE;
@@ -3006,14 +2873,21 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart)
} else
{
msg_len = ((repl_msg_ptr_t)buffp)->len - REPL_MSG_HDRLEN;
- buffp += REPL_MSG_HDRLEN;
exp_data_len = msg_len;
+ if (REPL_TR_JNL_RECS == msg_type || REPL_OLD_TRIPLE == msg_type || REPL_HISTREC == msg_type)
+ {
+ /* Target buffer is the receive pool. Prepare the receive pool for write (also
+ * checks if the transaction will fit in).
+ * Note: this is a special case where PREPARE_RECVPOOL_FOR_WRITE is not invoked
+ * right before COPY_TO_RECVPOOL because we want to prepare the receive pool just
+ * once even though the actual data (coming from the other end) might come in
+ * different pieces.
+ */
+ 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;
- /* If the target buffer is the receive pool, prepare the receive pool for the write.
- * In addition, check if transaction will fit in.
- * If the target buffer is not the receive pool, we will do this check after uncompression.
- */
- PREPARE_RECVPOOL_FOR_WRITE(exp_data_len, 0);
}
assert(0 <= buff_unprocessed);
assert(0 == (msg_len % REPL_MSG_ALIGN));
@@ -3027,6 +2901,7 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart)
buffp += buffered_data_len;
buff_unprocessed -= buffered_data_len;
data_len -= buffered_data_len;
+ preserve_buffp = (0 != data_len);
switch(msg_type)
{
case REPL_TR_JNL_RECS:
@@ -3037,6 +2912,7 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart)
is_repl_cmpc = ((REPL_TR_CMP_JNL_RECS == msg_type) || (REPL_TR_CMP_JNL_RECS2 == msg_type));
if (!is_repl_cmpc)
{
+ assert(recvpool_prepared);
COPY_TO_RECVPOOL(old_buffp, buffered_data_len); /* uses and updates "write_loc" */
} else
{
@@ -3051,6 +2927,7 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart)
if (repl_connection_reset || gtmrecv_wait_for_jnl_seqno)
return;
}
+ preserve_buffp = FALSE;
break;
case REPL_LOSTTNCOMPLETE:
@@ -3114,8 +2991,7 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart)
memcpy((uchar_ptr_t)&heartbeat.ack_seqno[0],
(uchar_ptr_t)&temp_ack_seqno, SIZEOF(seq_num));
}
- REPL_SEND_LOOP(gtmrecv_sock_fd, &heartbeat, MIN_REPL_MSGLEN,
- FALSE, >mrecv_poll_immediate)
+ REPL_SEND_LOOP(gtmrecv_sock_fd, &heartbeat, MIN_REPL_MSGLEN, REPL_POLL_NOWAIT)
{
GTMRECV_POLL_ACTIONS(data_len, buff_unprocessed, buffp);
}
@@ -3136,7 +3012,7 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart)
if (jnlpool.repl_inst_filehdr->is_supplementary)
{ /* Issue REPL2OLD error because this is a supplementary instance and remote
* side runs a GT.M version that does not know the supplementary protocol */
- rts_error(VARLSTCNT(6) ERR_REPL2OLD, 4,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPL2OLD, 4,
LEN_AND_STR(old_need_instinfo_msg->instname),
LEN_AND_STR(jnlpool.repl_inst_filehdr->inst_info.this_instname));
}
@@ -3147,11 +3023,14 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart)
if (gtmrecv_local->updateresync
&& (FD_INVALID != gtmrecv_local->updresync_instfile_fd))
{
- rts_error(VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0, ERR_TEXT, 2,
- RTS_ERROR_LITERAL("Source side is non-supplementary implies "
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_UPDSYNCINSTFILE, 0,
+ ERR_TEXT, 2,
+ LEN_AND_LIT("Source side is non-supplementary implies "
"-UPDATERESYNC needs no value specified"));
}
- /* Initialize the remote side protocol version from "proto_ver" field of this msg */
+ /* Initialize the remote side protocol version from "proto_ver"
+ * field of this msg
+ */
remote_side->proto_ver = old_need_instinfo_msg->proto_ver;
assert(REPL_PROTO_VER_MULTISITE <= remote_side->proto_ver);
assert(REPL_PROTO_VER_SUPPLEMENTARY > remote_side->proto_ver);
@@ -3159,7 +3038,7 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart)
memset(&old_instinfo_msg, 0, SIZEOF(old_instinfo_msg));
memcpy(old_instinfo_msg.instname,
jnlpool.repl_inst_filehdr->inst_info.this_instname, MAX_INSTNAME_LEN - 1);
- grab_lock(jnlpool.jnlpool_dummy_reg, GRAB_LOCK_ONLY);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, GRAB_LOCK_ONLY);
GTMRECV_ONLN_RLBK_CLNUP_IF_NEEDED;
old_instinfo_msg.was_rootprimary = (unsigned char)repl_inst_was_rootprimary();
rel_lock(jnlpool.jnlpool_dummy_reg);
@@ -3174,7 +3053,7 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart)
if ((old_instinfo_msg.was_rootprimary || jnlpool_ctl->max_zqgblmod_seqno)
&& !old_need_instinfo_msg->is_rootprimary)
{
- gtm_putmsg(VARLSTCNT(4) ERR_PRIMARYNOTROOT, 2,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_PRIMARYNOTROOT, 2,
LEN_AND_STR((char *) old_need_instinfo_msg->instname));
gtmrecv_autoshutdown(); /* should not return */
assert(FALSE);
@@ -3349,8 +3228,9 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart)
*/
if (REPL_PROTO_VER_UNINITIALIZED == remote_side->proto_ver)
{ /* Issue REPL2OLD error because primary is dual-site */
- rts_error(VARLSTCNT(6) ERR_REPL2OLD, 4, LEN_AND_STR(UNKNOWN_INSTNAME),
- LEN_AND_STR(jnlpool.repl_inst_filehdr->inst_info.this_instname));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPL2OLD, 4,
+ LEN_AND_STR(UNKNOWN_INSTNAME),
+ LEN_AND_STR(jnlpool.repl_inst_filehdr->inst_info.this_instname));
}
/* Assert that endianness_known and cross_endian have already been initialized.
* This ensures that remote_side->cross_endian is reliable */
@@ -3365,7 +3245,7 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart)
* database file headers henceforth controls whether this instance can
* be brought up as a tertiary or not. Flush changes to file on disk.
*/
- grab_lock(jnlpool.jnlpool_dummy_reg, GRAB_LOCK_ONLY);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, GRAB_LOCK_ONLY);
GTMRECV_ONLN_RLBK_CLNUP_IF_NEEDED;
jnlpool.repl_inst_filehdr->was_rootprimary = FALSE;
repl_inst_flush_filehdr();
@@ -3415,7 +3295,7 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart)
gtmrecv_autoshutdown(); /* should not return */
assert(FALSE);
}
- grab_lock(jnlpool.jnlpool_dummy_reg, GRAB_LOCK_ONLY);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, GRAB_LOCK_ONLY);
GTMRECV_ONLN_RLBK_CLNUP_IF_NEEDED;
/* The ONLINE ROLLBACK did not change the physical or the logical state as
* otherwise the above macro would have returned to the caller. But, since
@@ -3552,6 +3432,33 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart)
}
break;
+ case REPL_LOGFILE_INFO:
+ if (0 == data_len)
+ {
+ logfile_msgp = (repl_logfile_info_msg_t *)(buffp - msg_len - REPL_MSG_HDRLEN);
+ assert(REPL_PROTO_VER_REMOTE_LOGPATH <= logfile_msgp->proto_ver);
+ if (remote_side->cross_endian)
+ {
+ logfile_msgp->fullpath_len = GTM_BYTESWAP_32(logfile_msgp->fullpath_len);
+ logfile_msgp->pid = GTM_BYTESWAP_32(logfile_msgp->pid);
+ }
+ assert('\0' == logfile_msgp->fullpath[logfile_msgp->fullpath_len - 1]);
+ repl_log(gtmrecv_log_fp, TRUE, TRUE, "Remote side source log file path is %s; "
+ "Source Server PID = %d\n",
+ logfile_msgp->fullpath, logfile_msgp->pid);
+ /* Now, send our logfile path to the source side */
+ assert(remote_side->endianness_known);
+ len = repl_logfileinfo_get(recvpool.gtmrecv_local->log_file,
+ &logfile_msg,
+ remote_side->cross_endian,
+ gtmrecv_log_fp);
+ REPL_SEND_LOOP(gtmrecv_sock_fd, &logfile_msg, len, REPL_POLL_NOWAIT)
+ {
+ GTMRECV_POLL_ACTIONS(data_len, buff_unprocessed, buffp);
+ }
+ CHECK_REPL_SEND_LOOP_ERROR(status, "REPL_LOGFILE_INFO");
+ }
+ break;
default:
/* Discard the message */
repl_log(gtmrecv_log_fp, TRUE, TRUE, "Received UNKNOWN message (type = %d). "
@@ -3566,13 +3473,16 @@ STATICFNDEF void do_main_loop(boolean_t crash_restart)
return;
}
assert(0 == ((unsigned long)(buffp) % REPL_MSG_ALIGN));
- if ((0 != buff_unprocessed) && (buff_start != buffp))
+ if (!preserve_buffp)
{
- REPL_DPRINT4("Incmpl msg hdr, moving %d bytes from %lx to %lx\n", buff_unprocessed, (caddr_t)buffp,
- (caddr_t)buff_start);
- memmove(buff_start, buffp, buff_unprocessed);
+ if ((0 != buff_unprocessed) && (buff_start != buffp))
+ {
+ REPL_DPRINT4("Incmpl msg hdr, moving %d bytes from %lx to %lx\n", buff_unprocessed, (caddr_t)buffp,
+ (caddr_t)buff_start);
+ memmove(buff_start, buffp, buff_unprocessed);
+ }
+ buffp = buff_start;
}
- buffp = buff_start;
GTMRECV_POLL_ACTIONS(data_len, buff_unprocessed, buffp);
}
}
@@ -3628,7 +3538,6 @@ void gtmrecv_process(boolean_t crash_restart)
* different sized messages only for a few messages types REPL_TR_JNL_RECS, REPL_OLD_TRIPLE and REPL_CMP_SOLVE.
* But post-supplementary it knows to handle different sized messages for various additional message types
* (including REPL_NEED_INSTINFO, REPL_INSTINFO, REPL_HISTREC).
- *
*/
assert(MIN_REPL_MSGLEN == SIZEOF(repl_start_msg_t));
assert(MIN_REPL_MSGLEN == SIZEOF(repl_start_reply_msg_t));
@@ -3644,11 +3553,7 @@ void gtmrecv_process(boolean_t crash_restart)
assert(MIN_REPL_MSGLEN < SIZEOF(repl_old_triple_msg_t));
assert(MIN_REPL_MSGLEN < SIZEOF(repl_histrec_msg_t));
assert(MIN_REPL_MSGLEN == SIZEOF(repl_heartbeat_msg_t));
- assert(GTMRECV_POLL_INTERVAL < MAX_GTMRECV_POLL_INTERVAL);
- gtmrecv_poll_interval.tv_sec = 0;
- gtmrecv_poll_interval.tv_usec = GTMRECV_POLL_INTERVAL;
- gtmrecv_poll_immediate.tv_sec = 0;
- gtmrecv_poll_immediate.tv_usec = 0;
+ assert(REPL_POLL_WAIT < MILLISECS_IN_SEC);
recvpool_size = recvpool_ctl->recvpool_size;
recvpool_high_watermark = (long)((float)RECVPOOL_HIGH_WATERMARK_PCTG / 100 * recvpool_size);
recvpool_low_watermark = (long)((float)RECVPOOL_LOW_WATERMARK_PCTG / 100 * recvpool_size);
diff --git a/sr_unix/gtmrecv_shutdown.c b/sr_unix/gtmrecv_shutdown.c
index 3f1ab83..7c923b1 100644
--- a/sr_unix/gtmrecv_shutdown.c
+++ b/sr_unix/gtmrecv_shutdown.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2006, 2012 Fidelity Information Services, Inc *
+ * Copyright 2006, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -97,7 +97,7 @@ int gtmrecv_shutdown(boolean_t auto_shutdown, int exit_status)
* issues. However, to ensure that a concurrent argument-less rundown doesn't remove these semaphores (in case they
* are orphaned), increment the counter semaphore.
*/
- if (0 != (status = grab_sem(RECV, RECV_SERV_COUNT_SEM)))
+ if (0 != (status = incr_sem(RECV, RECV_SERV_COUNT_SEM)))
{
save_errno = errno;
repl_log(stderr, TRUE, TRUE, "Could not acquire Receive Pool counter semaphore : %s. "
@@ -118,7 +118,7 @@ int gtmrecv_shutdown(boolean_t auto_shutdown, int exit_status)
repl_log(stderr, TRUE, TRUE, "Could not release Receive Pool access control semaphore : %s. "
"Shutdown did not complete\n", STRERROR(save_errno));
repl_inst_ftok_sem_release(); /* see comment above for why this is okay */
- status = rel_sem(RECV, RECV_SERV_COUNT_SEM);
+ status = decr_sem(RECV, RECV_SERV_COUNT_SEM);
assert(0 == status);
return ABNORMAL_SHUTDOWN;
}
@@ -157,12 +157,12 @@ int gtmrecv_shutdown(boolean_t auto_shutdown, int exit_status)
repl_log(stderr, TRUE, TRUE, "Could not acquire Receive Pool access control semaphore : %s. "
"Shutdown did not complete\n", STRERROR(save_errno));
repl_inst_ftok_sem_release();
- status = rel_sem(RECV, RECV_SERV_COUNT_SEM);
+ status = decr_sem(RECV, RECV_SERV_COUNT_SEM);
assert(0 == status);
return ABNORMAL_SHUTDOWN;
}
/* Now that semaphores are acquired, decrement the counter semaphore */
- if (0 != (status = rel_sem(RECV, RECV_SERV_COUNT_SEM)))
+ if (0 != (status = decr_sem(RECV, RECV_SERV_COUNT_SEM)))
{
save_errno = errno;
repl_log(stderr, TRUE, TRUE, "Could not release Receive Pool counter semaphore : %s. "
@@ -182,8 +182,8 @@ int gtmrecv_shutdown(boolean_t auto_shutdown, int exit_status)
{ /* Release all semaphores */
if (!auto_shutdown)
{
- rel_sem_immediate(RECV, UPD_PROC_COUNT_SEM);
- rel_sem_immediate(RECV, RECV_SERV_COUNT_SEM);
+ decr_sem(RECV, UPD_PROC_COUNT_SEM);
+ decr_sem(RECV, RECV_SERV_COUNT_SEM);
}
rel_sem_immediate( RECV, RECV_POOL_ACCESS_SEM);
} else
@@ -194,7 +194,7 @@ int gtmrecv_shutdown(boolean_t auto_shutdown, int exit_status)
* lock if journal pool is available.
*/
if ((NULL != jnlpool.jnlpool_ctl) && !was_crit)
- grab_lock(jnlpool.jnlpool_dummy_reg, ASSERT_NO_ONLINE_ROLLBACK);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK);
repl_inst_recvpool_reset();
if ((NULL != jnlpool.jnlpool_ctl) && !was_crit)
rel_lock(jnlpool.jnlpool_dummy_reg);
diff --git a/sr_unix/gtmsecshr.c b/sr_unix/gtmsecshr.c
index f3bcdb2..415c8d7 100644
--- a/sr_unix/gtmsecshr.c
+++ b/sr_unix/gtmsecshr.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -81,6 +81,7 @@
#include "gtm_imagetype_init.h"
#include "gtm_threadgbl_init.h"
#include "hashtab.h"
+#include "fork_init.h"
#ifdef UNICODE_SUPPORTED
# include "gtm_icu_api.h"
# include "gtm_utf8.h"
@@ -125,14 +126,21 @@ error_def(ERR_GTMCHECK);
error_def(ERR_GTMSECSHR);
error_def(ERR_GTMSECSHRBADDIR);
error_def(ERR_GTMSECSHRCHDIRF);
+error_def(ERR_GTMSECSHRDMNSTARTED);
error_def(ERR_GTMSECSHRFORKF);
+error_def(ERR_GTMSECSHRGETSEMFAIL);
error_def(ERR_GTMSECSHRISNOT);
error_def(ERR_GTMSECSHRNOARG0);
error_def(ERR_GTMSECSHROPCMP);
error_def(ERR_GTMSECSHRRECVF);
+error_def(ERR_GTMSECSHRREMFILE);
+error_def(ERR_GTMSECSHRREMSEM);
+error_def(ERR_GTMSECSHRREMSEMFAIL);
+error_def(ERR_GTMSECSHRREMSHM);
error_def(ERR_GTMSECSHRSCKSEL);
+error_def(ERR_GTMSECSHRSEMGET);
error_def(ERR_GTMSECSHRSENDF);
-error_def(ERR_GTMSECSHRSGIDF);
+error_def(ERR_GTMSECSHRSHMCONCPROC);
error_def(ERR_GTMSECSHRSOCKET);
error_def(ERR_GTMSECSHRSRVFID);
error_def(ERR_GTMSECSHRSRVFIL);
@@ -141,6 +149,7 @@ error_def(ERR_GTMSECSHRSTART);
error_def(ERR_GTMSECSHRSUIDF);
error_def(ERR_GTMSECSHRTMOUT);
error_def(ERR_GTMSECSHRTMPPATH);
+error_def(ERR_GTMSECSHRUPDDBHDR);
error_def(ERR_MEMORY);
error_def(ERR_OUTOFSPACE);
error_def(ERR_STACKOFLOW);
@@ -230,10 +239,10 @@ int main(int argc, char_ptr_t argv[])
gtmsecshr_timer_popped = FALSE;
SELECT(gtmsecshr_sockfd+1, (void *)&wait_on_fd, NULL, NULL, &input_timeval, selstat);
if (0 > selstat)
- rts_error(VARLSTCNT(6) ERR_GTMSECSHR, 1, process_id, ERR_GTMSECSHRSCKSEL, 0, errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_GTMSECSHR, 1, process_id, ERR_GTMSECSHRSCKSEL, 0, errno);
else if (0 == selstat)
{
- send_msg(VARLSTCNT(1) ERR_GTMSECSHRTMOUT);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_GTMSECSHRTMOUT);
gtmsecshr_exit(0, 0); /* Doesn't return */
}
recv_ptr = (char *)&mesg;
@@ -251,7 +260,8 @@ int main(int argc, char_ptr_t argv[])
"-1)\n", gtmsecshr_timer_popped, num_chars_recd, save_errno));
if ((0 >= num_chars_recd) && (gtmsecshr_timer_popped || EINTR != save_errno))
/* Note error includes 0 return from UDP read - should never be possible with UDP */
- rts_error(VARLSTCNT(6) ERR_GTMSECSHR, 1, process_id, ERR_GTMSECSHRRECVF, 0, save_errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_GTMSECSHR, 1,
+ process_id, ERR_GTMSECSHRRECVF, 0, save_errno);
if (0 < num_chars_recd)
recv_complete = TRUE; /* Only complete messages received via UDP datagram */
} while (!recv_complete);
@@ -273,7 +283,8 @@ int main(int argc, char_ptr_t argv[])
DBGGSSHR((LOGFLAGS, "gtmsecshr: timer-popped: %d SENDTO rc = %d errno = %d (only relevant if "
"rc = -1)\n", gtmsecshr_timer_popped, num_chars_recd, save_errno));
if ((0 >= num_chars_sent) && (gtmsecshr_timer_popped || save_errno != EINTR))
- rts_error(VARLSTCNT(6) ERR_GTMSECSHR, 1, process_id, ERR_GTMSECSHRSENDF, 0, save_errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_GTMSECSHR, 1,
+ process_id, ERR_GTMSECSHRSENDF, 0, save_errno);
if (0 < num_chars_sent)
send_complete = TRUE;
} while (!send_complete);
@@ -331,8 +342,8 @@ void gtmsecshr_init(char_ptr_t argv[], char **rundir, int *rundir_len)
rndirln = STRLEN(rndir);
if (0 == rndirln)
{
- send_msg(VARLSTCNT(6) ERR_GTMSECSHRSTART, 3, RTS_ERROR_LITERAL("Server"), process_id,
- ERR_GTMSECSHRNOARG0);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_GTMSECSHRSTART, 3,
+ RTS_ERROR_LITERAL("Server"), process_id, ERR_GTMSECSHRNOARG0);
gtmsecshr_exit(UNABLETODETERMINEPATH, FALSE);
}
for (cp = rndir + rndirln - 1; cp >= rndir; cp--)
@@ -344,8 +355,8 @@ void gtmsecshr_init(char_ptr_t argv[], char **rundir, int *rundir_len)
modlen = (rndir + rndirln) - cp;
if ((STRLEN(execname) != modlen) || (0 != memcmp(execname, cp, modlen)))
{
- send_msg(VARLSTCNT(7) ERR_GTMSECSHRSTART, 3, RTS_ERROR_LITERAL("Server"), process_id,
- ERR_GTMSECSHRISNOT, 2, modlen, cp);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_GTMSECSHRSTART, 3,
+ RTS_ERROR_LITERAL("Server"), process_id, ERR_GTMSECSHRISNOT, 2, modlen, cp);
gtmsecshr_exit(NOTGTMSECSHR, FALSE);
}
rndirln = rndirln - modlen - 1;
@@ -357,8 +368,8 @@ void gtmsecshr_init(char_ptr_t argv[], char **rundir, int *rundir_len)
if (NULL == chrrv)
{
save_errno = errno;
- send_msg(VARLSTCNT(8) ERR_GTMSECSHRSTART, 3, RTS_ERROR_LITERAL("Server"), process_id, ERR_GTMSECSHRISNOT, 0,
- save_errno);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_GTMSECSHRSTART, 3,
+ RTS_ERROR_LITERAL("Server"), process_id, ERR_GTMSECSHRISNOT, 0, save_errno);
gtmsecshr_exit(NOTGTMSECSHR, FALSE);
}
rndirln = STRLEN(realpathaft); /* Record (new) length now that realpath has normalized the path */
@@ -367,7 +378,8 @@ void gtmsecshr_init(char_ptr_t argv[], char **rundir, int *rundir_len)
chrrv = getcwd(gtmdist, GTM_PATH_MAX); /* Use gtmdist 'cause it's convenient */
if ((NULL == chrrv) || (0 != strncmp(gtmdist, realpathaft, GTM_PATH_MAX)))
{
- send_msg(VARLSTCNT(6) ERR_GTMSECSHRSTART, 3, RTS_ERROR_LITERAL("Server"), process_id, ERR_GTMSECSHRBADDIR);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_GTMSECSHRSTART, 3,
+ RTS_ERROR_LITERAL("Server"), process_id, ERR_GTMSECSHRBADDIR);
gtmsecshr_exit(BADGTMDISTDIR, FALSE);
}
realpathaft[rndirln] = '\0'; /* Remove gtmsecshrdir part - Put it back to supplied path ($gtm_dist) */
@@ -379,7 +391,8 @@ void gtmsecshr_init(char_ptr_t argv[], char **rundir, int *rundir_len)
chrrv = realpath(path, gtmdist);
if ((NULL == chrrv) || (0 != strncmp(realpathaft, gtmdist, GTM_PATH_MAX)))
{
- send_msg(VARLSTCNT(6) ERR_GTMSECSHRSTART, 3, RTS_ERROR_LITERAL("Server"), process_id, ERR_GTMSECSHRBADDIR);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_GTMSECSHRSTART, 3,
+ RTS_ERROR_LITERAL("Server"), process_id, ERR_GTMSECSHRBADDIR);
gtmsecshr_exit(BADGTMDISTDIR, FALSE);
}
# ifdef _AIX
@@ -391,16 +404,17 @@ void gtmsecshr_init(char_ptr_t argv[], char **rundir, int *rundir_len)
if (-1 == CHDIR("/etc")) /* Note chdir is changed again below so this is only temporary */
{
save_errno = errno;
- send_msg(VARLSTCNT(10) ERR_GTMSECSHRSTART, 3, RTS_ERROR_LITERAL("Server"), process_id, ERR_TEXT, 2,
- RTS_ERROR_LITERAL("Error during chdir to /etc - TZ cannot be determined"), save_errno);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_GTMSECSHRSTART, 3, RTS_ERROR_LITERAL("Server"), process_id, ERR_TEXT,
+ 2, RTS_ERROR_LITERAL("Error during chdir to /etc - TZ cannot be determined"), save_errno);
} else
{
envfile = fopen("environment", "r");
if (NULL == envfile)
{
save_errno = errno;
- send_msg(VARLSTCNT(10) ERR_GTMSECSHRSTART, 3, RTS_ERROR_LITERAL("Server"), process_id, ERR_TEXT, 2,
- RTS_ERROR_LITERAL("Failed to read /etc/environment - TZ cannot be determined"), save_errno);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_GTMSECSHRSTART, 3,
+ RTS_ERROR_LITERAL("Server"), process_id, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Failed to read /etc/environment - TZ cannot be determined"), save_errno);
} else
{ /* /etc/environments is open, locate TZ= record */
tzfnd = FALSE;
@@ -424,13 +438,15 @@ void gtmsecshr_init(char_ptr_t argv[], char **rundir, int *rundir_len)
if (!feof(envfile))
{
save_errno = errno;
- send_msg(VARLSTCNT(10) ERR_GTMSECSHRSTART, 3, RTS_ERROR_LITERAL("Server"), process_id,
- ERR_TEXT, 2, RTS_ERROR_LITERAL("Error reading /etc/environment - TZ cannot be "
- "determined"), save_errno);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_GTMSECSHRSTART, 3,
+ RTS_ERROR_LITERAL("Server"), process_id, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Error reading /etc/environment - TZ cannot be determined"),
+ save_errno);
} else
/* Have EOF - didn't find TZ */
- send_msg(VARLSTCNT(9) ERR_GTMSECSHRSTART, 3, RTS_ERROR_LITERAL("Server"), process_id,
- ERR_TEXT, 2, RTS_ERROR_LITERAL("TZ cannot be determined"));
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_GTMSECSHRSTART, 3,
+ RTS_ERROR_LITERAL("Server"), process_id, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("TZ cannot be determined"));
} else
{ /* TZ record acquired - isolate TZ - malloc space to put it once determine exact length */
if (NEWLINE == realpathbef[reclen - 1])
@@ -441,8 +457,9 @@ void gtmsecshr_init(char_ptr_t argv[], char **rundir, int *rundir_len)
if (0 != rc)
{
save_errno = errno;
- send_msg(VARLSTCNT(10) ERR_GTMSECSHRSTART, 3, RTS_ERROR_LITERAL("Server"), process_id,
- ERR_TEXT, 2, RTS_ERROR_LITERAL("TZ reset with putenv() failed"), save_errno);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_GTMSECSHRSTART, 3,
+ RTS_ERROR_LITERAL("Server"), process_id, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("TZ reset with putenv() failed"), save_errno);
}
}
fclose(envfile);
@@ -455,26 +472,28 @@ void gtmsecshr_init(char_ptr_t argv[], char **rundir, int *rundir_len)
if (-1 == setuid(ROOTUID))
{
save_errno = errno;
- send_msg(VARLSTCNT(10) MAKE_MSG_WARNING(ERR_GTMSECSHRSTART), 3, RTS_ERROR_LITERAL("Server"), process_id,
- ERR_GTMSECSHRSUIDF, 0, ERR_GTMSECSHROPCMP, 0, save_errno);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(10) MAKE_MSG_WARNING(ERR_GTMSECSHRSTART), 3,
+ RTS_ERROR_LITERAL("Server"), process_id, ERR_GTMSECSHRSUIDF, 0, ERR_GTMSECSHROPCMP, 0, save_errno);
gtmsecshr_exit(SETUIDROOT, FALSE);
}
/* Before we fork, close the system log because when the facility name disappears in this middle-process,
* the logging capability disappears on some systems too - On others, it takes the executable name instead.
* Either one causes our tests to fail.
*/
- closelog();
+ DEFER_INTERRUPTS(INTRPT_IN_LOG_FUNCTION);
+ CLOSELOG();
+ ENABLE_INTERRUPTS(INTRPT_IN_LOG_FUNCTION);
first_syslog = TRUE;
- pid = fork(); /* Timers have not been initialized, no need to do FORK_CLEAN; BYPASSOK */
+ FORK(pid); /* Timers have not been initialized, no need to do FORK_CLEAN; BYPASSOK */
if (0 > pid)
{ /* Fork failed */
save_errno = errno;
- send_msg(VARLSTCNT(8) ERR_GTMSECSHRSTART, 3, RTS_ERROR_LITERAL("Server"), process_id,
- ERR_GTMSECSHRFORKF, 0, save_errno);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_GTMSECSHRSTART, 3,
+ RTS_ERROR_LITERAL("Server"), process_id, ERR_GTMSECSHRFORKF, 0, save_errno);
exit(GNDCHLDFORKFLD);
} else if (0 < pid)
/* This is the original process - it dies quietly (no exit handler of any sort) to isolate us */
- _exit(0);
+ _exit(EXIT_SUCCESS);
/****** We are now in the (isolated) child process ******/
process_id = getpid();
pid = getsid(process_id);
@@ -482,8 +501,8 @@ void gtmsecshr_init(char_ptr_t argv[], char **rundir, int *rundir_len)
{
save_errno = errno;
DEBUG_ONLY(util_out_print("expected sid !UL but have !UL", OPER, process_id, pid));
- send_msg(VARLSTCNT(8) MAKE_MSG_WARNING(ERR_GTMSECSHRSTART), 3, RTS_ERROR_LITERAL("Server"), process_id,
- ERR_GTMSECSHRSSIDF, 0, save_errno);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) MAKE_MSG_WARNING(ERR_GTMSECSHRSTART), 3,
+ RTS_ERROR_LITERAL("Server"), process_id, ERR_GTMSECSHRSSIDF, 0, save_errno);
}
/* 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.
@@ -494,7 +513,7 @@ void gtmsecshr_init(char_ptr_t argv[], char **rundir, int *rundir_len)
/* 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.
*/
- sig_init(gtmsecshr_signal_handler, gtmsecshr_signal_handler, NULL, NULL);
+ sig_init(gtmsecshr_signal_handler, NULL, NULL, NULL);
file_des = sysconf(_SC_OPEN_MAX);
for (file_des = file_des - 1; file_des >= 3; file_des--)
{ /* Close the file only if we have it open. This is to avoid a CLOSEFAIL error in case of
@@ -505,13 +524,13 @@ void gtmsecshr_init(char_ptr_t argv[], char **rundir, int *rundir_len)
if (-1 == CHDIR(P_tmpdir)) /* Switch to temporary directory as CWD */
{
save_errno = errno;
- send_msg(VARLSTCNT(10) ERR_GTMSECSHRSTART, 3, RTS_ERROR_LITERAL("Server"), process_id,
- ERR_GTMSECSHRCHDIRF, 2, LEN_AND_STR(P_tmpdir), save_errno);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_GTMSECSHRSTART, 3,
+ RTS_ERROR_LITERAL("Server"), process_id, ERR_GTMSECSHRCHDIRF, 2, LEN_AND_STR(P_tmpdir), save_errno);
exit(UNABLETOCHDIR);
}
umask(0);
if (0 != gtmsecshr_pathname_init(SERVER, *rundir, *rundir_len))
- rts_error(VARLSTCNT(5) ERR_GTMSECSHRSOCKET, 3, RTS_ERROR_LITERAL("Server path"), process_id);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_GTMSECSHRSOCKET, 3, RTS_ERROR_LITERAL("Server path"), process_id);
if (-1 == (secshr_sem = semget(gtmsecshr_key, FTOK_SEM_PER_ID, RWDALL | IPC_NOWAIT)))
{
secshr_sem = INVALID_SEMID;
@@ -519,7 +538,7 @@ void gtmsecshr_init(char_ptr_t argv[], char **rundir, int *rundir_len)
(-1 == (secshr_sem = semget(gtmsecshr_key, FTOK_SEM_PER_ID, RWDALL | IPC_CREAT | IPC_NOWAIT | IPC_EXCL))))
{
secshr_sem = INVALID_SEMID;
- util_out_print("semget error errno = !UL", OPER, errno);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_GTMSECSHRSEMGET, 1, errno);
gtmsecshr_exit(SEMGETERROR, FALSE);
}
}
@@ -532,21 +551,23 @@ void gtmsecshr_init(char_ptr_t argv[], char **rundir, int *rundir_len)
SEMOP(secshr_sem, sop, 2, semop_res, NO_WAIT);
if (0 > semop_res)
{
- send_msg(VARLSTCNT(10) MAKE_MSG_SEVERE(ERR_GTMSECSHRSTART), 3, RTS_ERROR_LITERAL("Server"), process_id,
- ERR_TEXT, 2, RTS_ERROR_LITERAL("server already running"), errno);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(10) MAKE_MSG_SEVERE(ERR_GTMSECSHRSTART), 3,
+ RTS_ERROR_LITERAL("Server"), process_id, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("server already running"), errno);
/* If gtm_tmp is not defined, show default path */
if (gtm_tmp_ptr = GETENV("gtm_tmp")) /* Warning - assignment */
- send_msg(VARLSTCNT(8) ERR_GTMSECSHRTMPPATH, 2, RTS_ERROR_TEXT(gtm_tmp_ptr),
- ERR_TEXT, 2, RTS_ERROR_TEXT("(from $gtm_tmp)"));
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_GTMSECSHRTMPPATH, 2,
+ RTS_ERROR_TEXT(gtm_tmp_ptr), ERR_TEXT, 2, RTS_ERROR_TEXT("(from $gtm_tmp)"));
else
- send_msg(VARLSTCNT(4) ERR_GTMSECSHRTMPPATH, 2, RTS_ERROR_TEXT("/tmp"));
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_GTMSECSHRTMPPATH, 2, RTS_ERROR_TEXT("/tmp"));
gtmsecshr_exit(SEMAPHORETAKEN, FALSE);
}
if (0 != gtmsecshr_sock_init(SERVER))
- rts_error(VARLSTCNT(5) ERR_GTMSECSHRSOCKET, 3, RTS_ERROR_LITERAL("Server"), process_id);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_GTMSECSHRSOCKET, 3, RTS_ERROR_LITERAL("Server"), process_id);
if (-1 == Stat(gtmsecshr_sock_name.sun_path, &stat_buf))
- send_msg(VARLSTCNT(10) MAKE_MSG_WARNING(ERR_GTMSECSHRSTART), 3, RTS_ERROR_LITERAL("Server"), process_id,
- ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to get status of socket file"), errno);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(10) MAKE_MSG_WARNING(ERR_GTMSECSHRSTART), 3,
+ RTS_ERROR_LITERAL("Server"), process_id, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Unable to get status of socket file"), errno);
/* Get the distribution group */
lib_gid = gtm_get_group_id(&dist_stat_buff);
/* If it is world accessible then make mode 666 */
@@ -558,14 +579,15 @@ void gtmsecshr_init(char_ptr_t argv[], char **rundir, int *rundir_len)
{
/* Change group if different from current user group */
if (lib_gid != GETGID() && (-1 == CHOWN(gtmsecshr_sock_name.sun_path, -1, lib_gid)))
- send_msg(VARLSTCNT(10) MAKE_MSG_WARNING(ERR_GTMSECSHRSTART), 3,
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(10) MAKE_MSG_WARNING(ERR_GTMSECSHRSTART), 3,
RTS_ERROR_LITERAL("Server"), process_id, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Unable to change socket file group"), errno);
stat_buf.st_mode = 0660;
}
if (-1 == CHMOD(gtmsecshr_sock_name.sun_path, stat_buf.st_mode))
- send_msg(VARLSTCNT(10) MAKE_MSG_WARNING(ERR_GTMSECSHRSTART), 3, RTS_ERROR_LITERAL("Server"), process_id,
- ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to change socket file permisions"), errno);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(10) MAKE_MSG_WARNING(ERR_GTMSECSHRSTART), 3,
+ RTS_ERROR_LITERAL("Server"), process_id, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Unable to change socket file permisions"), errno);
name_ptr = strrchr(gtmsecshr_sock_name.sun_path, '/');
while (*name_ptr == '/') /* back off in case of double-slash */
name_ptr--;
@@ -577,8 +599,8 @@ void gtmsecshr_init(char_ptr_t argv[], char **rundir, int *rundir_len)
*/
STR_HASH((char *)gtm_release_name, gtm_release_name_len, TREF(gtmsecshr_comkey), 0);
/* Initialization complete */
- util_out_print("gtmsecshr daemon started (key: 0x!XL) for version !AD from !AD", OPER, gtmsecshr_key, gtm_release_name_len,
- gtm_release_name, *rundir_len, *rundir);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_GTMSECSHRDMNSTARTED, 5,
+ gtmsecshr_key, gtm_release_name_len, gtm_release_name, *rundir_len, *rundir);
return;
}
@@ -595,10 +617,10 @@ void gtmsecshr_exit(int exit_code, boolean_t dump)
if (-1 == (gtmsecshr_sem = semget(gtmsecshr_key, FTOK_SEM_PER_ID, RWDALL | IPC_NOWAIT)))
{
gtmsecshr_sem = INVALID_SEMID;
- util_out_print("error getting semaphore errno = !UL", OPER, errno);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_GTMSECSHRGETSEMFAIL, 1, errno);
}
if (-1 == semctl(gtmsecshr_sem, 0, IPC_RMID, 0))
- util_out_print("error removing semaphore errno = !UL", OPER, errno);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_GTMSECSHRREMSEMFAIL, 1, errno);
}
/* Note shutdown message taken care of by generic_signal_handler */
exit(exit_code);
@@ -640,8 +662,9 @@ void service_request(gtmsecshr_mesg *buf, int msglen, char *rundir, int rundir_l
if (TREF(gtmsecshr_comkey) != buf->comkey)
{
buf->code = INVALID_COMKEY;
- send_msg(VARLSTCNT(12) ERR_GTMSECSHRSRVFID, 6, RTS_ERROR_LITERAL("Server"), process_id, buf->pid,
- save_code, buf->mesg.id, ERR_TEXT, 2, RTS_ERROR_LITERAL("Comkey not correct for this gtmsecshr version"));
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(12) ERR_GTMSECSHRSRVFID, 6,
+ RTS_ERROR_LITERAL("Server"), process_id, buf->pid, save_code, buf->mesg.id, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Comkey not correct for this gtmsecshr version"));
return;
}
/* Process code (with code specific valications) */
@@ -661,9 +684,9 @@ void service_request(gtmsecshr_mesg *buf, int msglen, char *rundir, int rundir_l
if (buf->code = (-1 == kill((pid_t)buf->mesg.id, SIGALRM)) ? errno : 0)
{
save_errno = errno;
- send_msg(VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6, RTS_ERROR_LITERAL("Server"), process_id, buf->pid,
- save_code, buf->mesg.id, ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to wake up process"),
- save_errno);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6,
+ RTS_ERROR_LITERAL("Server"), process_id, buf->pid, save_code, buf->mesg.id, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Unable to wake up process"), save_errno);
}
# ifdef DEBUG
else
@@ -678,10 +701,9 @@ void service_request(gtmsecshr_mesg *buf, int msglen, char *rundir, int rundir_l
if (buf->code = (-1 == kill((pid_t)buf->mesg.id, SIGCONT)) ? errno : 0)
{
save_errno = errno;
- send_msg(VARLSTCNT(13)
- ERR_GTMSECSHRSRVFID, 6, RTS_ERROR_LITERAL("Server"), process_id, buf->pid, save_code,
- buf->mesg.id, ERR_TEXT, 2,
- RTS_ERROR_LITERAL("Unable to request process to resume processing"), save_errno);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6,
+ RTS_ERROR_LITERAL("Server"), process_id, buf->pid, save_code, buf->mesg.id, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Unable to request process to resume processing"), save_errno);
}
# ifdef DEBUG
else
@@ -693,38 +715,38 @@ void service_request(gtmsecshr_mesg *buf, int msglen, char *rundir, int rundir_l
case REMOVE_SEM:
buf->code = (-1 == semctl((int)buf->mesg.id, 0, IPC_RMID, 0)) ? errno : 0;
if (!buf->code)
- util_out_print("[client pid !UL] Semaphore (!UL) removed", OPER, buf->pid, buf->mesg.id);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_GTMSECSHRREMSEM, 2, buf->pid, buf->mesg.id);
else
{
- send_msg(VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6, RTS_ERROR_LITERAL("Server"), process_id, buf->pid,
- save_code, buf->mesg.id, ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to remove semaphore"),
- buf->code);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6,
+ RTS_ERROR_LITERAL("Server"), process_id, buf->pid, save_code, buf->mesg.id, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Unable to remove semaphore"), buf->code);
}
break;
case REMOVE_SHM:
buf->code = (-1 == shmctl((int)buf->mesg.id, IPC_STAT, &temp_shmctl_buf)) ? errno : 0;
if (buf->code)
{
- send_msg(VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6, RTS_ERROR_LITERAL("Server"), process_id, buf->pid,
- save_code, buf->mesg.id, ERR_TEXT, 2,
- RTS_ERROR_LITERAL("Unable to get shared memory statistics"), buf->code);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6,
+ RTS_ERROR_LITERAL("Server"), process_id, buf->pid, save_code, buf->mesg.id, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Unable to get shared memory statistics"), buf->code);
break;
} else if (1 < temp_shmctl_buf.shm_nattch)
{
- util_out_print("More than one process attached to Shared memory segment (!UL) not removed (!UL)",
- OPER, buf->mesg.id, temp_shmctl_buf.shm_nattch);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_GTMSECSHRSHMCONCPROC, 2,
+ buf->mesg.id, temp_shmctl_buf.shm_nattch);
buf->code = EBUSY;
break;
}
buf->code = (-1 == shmctl((int)buf->mesg.id, IPC_RMID, 0)) ? errno : 0;
if (!buf->code)
- util_out_print("[client pid !UL] Shared memory segment (!UL) removed, nattch = !UL", OPER,
- buf->pid, buf->mesg.id, temp_shmctl_buf.shm_nattch);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_GTMSECSHRREMSHM, 3,
+ buf->pid, buf->mesg.id, temp_shmctl_buf.shm_nattch);
else
{
- send_msg(VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6, RTS_ERROR_LITERAL("Server"), process_id, buf->pid,
- save_code, buf->mesg.id, ERR_TEXT, 2,
- RTS_ERROR_LITERAL("Unable to remove shared memory segment"), buf->code);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6,
+ RTS_ERROR_LITERAL("Server"), process_id, buf->pid, save_code, buf->mesg.id, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Unable to remove shared memory segment"), buf->code);
}
break;
# ifndef MUTEX_MSEM_WAKE
@@ -739,10 +761,11 @@ void service_request(gtmsecshr_mesg *buf, int msglen, char *rundir, int rundir_l
}
if ((0 == index) || (index >= SIZEOF(buf->mesg.path)) || (index != (msglen - GTM_MESG_HDR_SIZE - 1)))
{
- send_msg(VARLSTCNT(13) ERR_GTMSECSHRSRVFIL, 7, RTS_ERROR_LITERAL("Server"), process_id, buf->pid,
- buf->code, index >= SIZEOF(buf->mesg.path) ? SIZEOF(buf->mesg.path) - 1 : index,
- buf->mesg.path, ERR_TEXT, 2,
- RTS_ERROR_LITERAL("no file name or length too long or invalid"));
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFIL, 7,
+ RTS_ERROR_LITERAL("Server"), process_id, buf->pid, buf->code,
+ index >= SIZEOF(buf->mesg.path) ? SIZEOF(buf->mesg.path) - 1 : index,
+ buf->mesg.path, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("no file name or length too long or invalid"));
buf->code = EINVAL;
} else
{
@@ -782,44 +805,43 @@ void service_request(gtmsecshr_mesg *buf, int msglen, char *rundir, int rundir_l
{
save_errno = errno;
buf->code = save_errno;
- send_msg(VARLSTCNT(14) ERR_GTMSECSHRSRVFIL, 7,
- RTS_ERROR_LITERAL("Server"), process_id, buf->pid, buf->code,
- index, buf->mesg.path, ERR_TEXT, 2,
- RTS_ERROR_LITERAL("Unable to get file status"), save_errno);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(14) ERR_GTMSECSHRSRVFIL, 7,
+ RTS_ERROR_LITERAL("Server"), process_id, buf->pid, buf->code,
+ index, buf->mesg.path, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Unable to get file status"), save_errno);
}
} else if ((!S_ISSOCK(statbuf.st_mode)) ZOS_ONLY(|| (S_ISCHR(statbuf.st_mode))))
{
buf->code = EINVAL;
- send_msg(VARLSTCNT(13) ERR_GTMSECSHRSRVFIL, 7,
- RTS_ERROR_LITERAL("Server"), process_id, buf->pid, buf->code,
- index, buf->mesg.path, ERR_TEXT, 2,
- RTS_ERROR_LITERAL("File is not a GTM mutex socket file"));
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFIL, 7,
+ RTS_ERROR_LITERAL("Server"), process_id, buf->pid, buf->code,
+ index, buf->mesg.path, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("File is not a GTM mutex socket file"));
} else if (0 != MEMCMP_LIT(basnam, MUTEX_SOCK_FILE_PREFIX))
{
buf->code = EINVAL;
- send_msg(VARLSTCNT(13) ERR_GTMSECSHRSRVFIL, 7,
- RTS_ERROR_LITERAL("Server"), process_id, buf->pid, buf->code,
- index, buf->mesg.path, ERR_TEXT, 2,
- RTS_ERROR_LITERAL("File name does not match the naming convention for a GT.M "
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFIL, 7,
+ RTS_ERROR_LITERAL("Server"), process_id, buf->pid, buf->code,
+ index, buf->mesg.path, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("File name does not match the naming convention for a GT.M "
"mutex socket file"));
} else if (0 != memcmp(gtmsecshr_sock_name.sun_path, buf->mesg.path, gtmsecshr_socket_dir_len))
{
buf->code = EINVAL;
- send_msg(VARLSTCNT(13) ERR_GTMSECSHRSRVFIL, 7,
- RTS_ERROR_LITERAL("Server"), process_id, buf->pid, buf->code,
- index, buf->mesg.path, ERR_TEXT, 2,
- RTS_ERROR_LITERAL("File does not reside in the normal directory for a GT.M "
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFIL, 7,
+ RTS_ERROR_LITERAL("Server"), process_id, buf->pid, buf->code,
+ index, buf->mesg.path, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("File does not reside in the normal directory for a GT.M "
"mutex socket file"));
} else if (buf->code = (-1 == UNLINK(buf->mesg.path)) ? errno : 0)
{
- send_msg(VARLSTCNT(14) ERR_GTMSECSHRSRVFIL, 7, RTS_ERROR_LITERAL("Server"), process_id,
- buf->pid, save_code, RTS_ERROR_STRING(buf->mesg.path),
- ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to remove file"), buf->code);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(14) ERR_GTMSECSHRSRVFIL, 7,
+ RTS_ERROR_LITERAL("Server"), process_id, buf->pid, save_code,
+ RTS_ERROR_STRING(buf->mesg.path), ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Unable to remove file"), buf->code);
} else
- {
- util_out_print("[client pid !UL] File (!AD) removed", OPER, buf->pid,
- RTS_ERROR_STRING(buf->mesg.path));
- }
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_GTMSECSHRREMFILE, 3,
+ buf->pid, RTS_ERROR_STRING(buf->mesg.path));
}
break;
# endif
@@ -833,8 +855,9 @@ void service_request(gtmsecshr_mesg *buf, int msglen, char *rundir, int rundir_l
|| (fn_len != (msglen - GTM_MESG_HDR_SIZE - offsetof(ipcs_mesg, fn[0]) - 1)))
{
buf->code = EINVAL;
- send_msg(VARLSTCNT(12) ERR_GTMSECSHRSRVFID, 6, RTS_ERROR_LITERAL("Server"), process_id, buf->pid,
- save_code, buf->mesg.id, ERR_TEXT, 2, RTS_ERROR_LITERAL("invalid file name argument"));
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(12) ERR_GTMSECSHRSRVFID, 6,
+ RTS_ERROR_LITERAL("Server"), process_id, buf->pid, save_code, buf->mesg.id, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("invalid file name argument"));
break;
}
/* First open and read-in the fileheader */
@@ -842,8 +865,9 @@ void service_request(gtmsecshr_mesg *buf, int msglen, char *rundir, int rundir_l
if (FD_INVALID == fd)
{
save_errno = buf->code = errno;
- send_msg(VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6, RTS_ERROR_LITERAL("Server"), process_id, buf->pid,
- save_code, buf->mesg.id, ERR_DBFILOPERR, 2, fn_len, fn, save_errno);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6,
+ RTS_ERROR_LITERAL("Server"), process_id, buf->pid, save_code,
+ buf->mesg.id, ERR_DBFILOPERR, 2, fn_len, fn, save_errno);
break;
}
# ifdef __MVS__
@@ -864,16 +888,18 @@ void service_request(gtmsecshr_mesg *buf, int msglen, char *rundir, int rundir_l
if (-1 == save_errno)
{
buf->code = save_errno;
- send_msg(VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6, RTS_ERROR_LITERAL("Server"), process_id, buf->pid,
- save_code, buf->mesg.id, ERR_DBFILOPERR, 2, LEN_AND_STR(fn), save_errno);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6,
+ RTS_ERROR_LITERAL("Server"), process_id, buf->pid,
+ save_code, buf->mesg.id, ERR_DBFILOPERR, 2, LEN_AND_STR(fn), save_errno);
CLOSEFILE_RESET(fd, save_errno); /* resets "fd" to FD_INVALID */
break;
}
if (!S_ISREG(statbuf.st_mode) || (SIZEOF(header) > statbuf.st_size))
{
buf->code = ERR_DBNOTGDS;
- send_msg(VARLSTCNT(12) ERR_GTMSECSHRSRVFID, 6, RTS_ERROR_LITERAL("Server"), process_id, buf->pid,
- save_code, buf->mesg.id, ERR_DBNOTGDS, 2, LEN_AND_STR(fn));
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(12) ERR_GTMSECSHRSRVFID, 6,
+ RTS_ERROR_LITERAL("Server"), process_id, buf->pid,
+ save_code, buf->mesg.id, ERR_DBNOTGDS, 2, LEN_AND_STR(fn));
CLOSEFILE_RESET(fd, save_errno); /* resets "fd" to FD_INVALID */
break;
}
@@ -881,16 +907,18 @@ void service_request(gtmsecshr_mesg *buf, int msglen, char *rundir, int rundir_l
if (0 != save_errno)
{
buf->code = save_errno;
- send_msg(VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6, RTS_ERROR_LITERAL("Server"), process_id, buf->pid,
- save_code, buf->mesg.id, ERR_DBFILOPERR, 2, LEN_AND_STR(fn), save_errno);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6,
+ RTS_ERROR_LITERAL("Server"), process_id, buf->pid,
+ save_code, buf->mesg.id, ERR_DBFILOPERR, 2, LEN_AND_STR(fn), save_errno);
CLOSEFILE_RESET(fd, save_errno); /* resets "fd" to FD_INVALID */
break;
}
if (0 != memcmp(header.label, GDS_LABEL, GDS_LABEL_SZ - 1)) /* Verify is GT.M database file */
{
buf->code = ERR_DBNOTGDS;
- send_msg(VARLSTCNT(12) ERR_GTMSECSHRSRVFID, 6, RTS_ERROR_LITERAL("Server"), process_id, buf->pid,
- save_code, buf->mesg.id, ERR_DBNOTGDS, 2, LEN_AND_STR(fn));
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(12) ERR_GTMSECSHRSRVFID, 6,
+ RTS_ERROR_LITERAL("Server"), process_id, buf->pid,
+ save_code, buf->mesg.id, ERR_DBNOTGDS, 2, LEN_AND_STR(fn));
CLOSEFILE_RESET(fd, save_errno); /* resets "fd" to FD_INVALID */
break;
}
@@ -899,8 +927,9 @@ void service_request(gtmsecshr_mesg *buf, int msglen, char *rundir, int rundir_l
if (!check_endian.shorts.ENDIANCHECKTHIS)
{
buf->code = ERR_DBENDIAN;
- send_msg(VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6, RTS_ERROR_LITERAL("Server"), process_id, buf->pid,
- save_code, buf->mesg.id, ERR_DBENDIAN, 4, fn_len, fn, ENDIANOTHER, ENDIANTHIS);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6,
+ RTS_ERROR_LITERAL("Server"), process_id, buf->pid,
+ save_code, buf->mesg.id, ERR_DBENDIAN, 4, fn_len, fn, ENDIANOTHER, ENDIANTHIS);
CLOSEFILE_RESET(fd, save_errno);
break;
}
@@ -932,9 +961,10 @@ void service_request(gtmsecshr_mesg *buf, int msglen, char *rundir, int rundir_l
|| (0 != buf->mesg.db_ipcs.gt_shm_ctime))
{
buf->code = EINVAL;
- send_msg(VARLSTCNT(12) ERR_GTMSECSHRSRVFID, 6, RTS_ERROR_LITERAL("Server"), process_id,
- buf->pid, save_code, buf->mesg.id, ERR_TEXT, 2,
- RTS_ERROR_LITERAL("Invalid header value combination"));
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(12) ERR_GTMSECSHRSRVFID, 6,
+ RTS_ERROR_LITERAL("Server"), process_id,
+ buf->pid, save_code, buf->mesg.id, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Invalid header value combination"));
CLOSEFILE_RESET(fd, save_errno);
break;
}
@@ -950,9 +980,10 @@ void service_request(gtmsecshr_mesg *buf, int msglen, char *rundir, int rundir_l
|| ((INVALID_SEMID != buf->mesg.db_ipcs.shmid) && (0 == buf->mesg.db_ipcs.gt_shm_ctime)))
{
buf->code = EINVAL;
- send_msg(VARLSTCNT(12) ERR_GTMSECSHRSRVFID, 6, RTS_ERROR_LITERAL("Server"), process_id,
- buf->pid, save_code, buf->mesg.id, ERR_TEXT, 2,
- RTS_ERROR_LITERAL("Invalid header value combination"));
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(12) ERR_GTMSECSHRSRVFID, 6,
+ RTS_ERROR_LITERAL("Server"), process_id,
+ buf->pid, save_code, buf->mesg.id, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Invalid header value combination"));
CLOSEFILE_RESET(fd, save_errno);
break;
}
@@ -970,20 +1001,23 @@ void service_request(gtmsecshr_mesg *buf, int msglen, char *rundir, int rundir_l
if (0 != save_errno)
{
buf->code = save_errno;
- send_msg(VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6, RTS_ERROR_LITERAL("Server"), process_id,
- buf->pid, save_code, buf->mesg.id, ERR_TEXT, 2,
- RTS_ERROR_LITERAL("Unable to write database file header"), save_errno);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6,
+ RTS_ERROR_LITERAL("Server"), process_id,
+ buf->pid, save_code, buf->mesg.id, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Unable to write database file header"), save_errno);
CLOSEFILE_RESET(fd, save_errno);
break;
}
- util_out_print("[client pid !UL] database fileheader (!AD) updated !AD", OPER, buf->pid, fn_len, fn,
- RTS_ERROR_STRING(intent));
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_GTMSECSHRUPDDBHDR, 5,
+ buf->pid, fn_len, fn, RTS_ERROR_STRING(intent));
buf->code = 0;
CLOSEFILE_RESET(fd, save_errno);
break;
default:
- send_msg(VARLSTCNT(12) ERR_GTMSECSHRSRVFID, 6, RTS_ERROR_LITERAL("Server"), process_id, buf->pid,
- buf->code, buf->mesg.id, ERR_TEXT, 2, RTS_ERROR_LITERAL("Invalid Service Request"));
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(12) ERR_GTMSECSHRSRVFID, 6,
+ RTS_ERROR_LITERAL("Server"), process_id, buf->pid,
+ buf->code, buf->mesg.id, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Invalid Service Request"));
buf->code = 0x8000; /* Flag for no-ack required - invalid commands get no response */
}
return;
@@ -1024,8 +1058,9 @@ int validate_receiver(gtmsecshr_mesg *buf, char *rundir, int rundir_len, int sav
{
save_errno = errno;
buf->code = save_errno;
- send_msg(VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6, RTS_ERROR_LITERAL("Server"), process_id, buf->pid, save_code,
- buf->mesg.id, ERR_TEXT, 2, RTS_ERROR_LITERAL("Could not open /proc/<pid>/cmdline"), save_errno);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6,
+ RTS_ERROR_LITERAL("Server"), process_id, buf->pid, save_code, buf->mesg.id, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Could not open /proc/<pid>/cmdline"), save_errno);
return save_errno;
}
FGETS(cmdbuf, GTM_PATH_MAX, procstrm, csrv);
@@ -1033,14 +1068,15 @@ int validate_receiver(gtmsecshr_mesg *buf, char *rundir, int rundir_len, int sav
{
save_errno = errno;
buf->code = save_errno;
- send_msg(VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6, RTS_ERROR_LITERAL("Server"), process_id, buf->pid, save_code,
- buf->mesg.id, ERR_TEXT, 2, RTS_ERROR_LITERAL("Could not read /proc/<pid>/cmdline"), save_errno);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6,
+ RTS_ERROR_LITERAL("Server"), process_id, buf->pid, save_code, buf->mesg.id, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Could not read /proc/<pid>/cmdline"), save_errno);
return save_errno;
}
FCLOSE(procstrm, clrv);
if (-1 == clrv)
/* Not a functional issue so just warn about it in op-log */
- send_msg(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fclose()"), CALLFROM, errno);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fclose()"), CALLFROM, errno);
lnln = STRLEN(cmdbuf);
/* Look from the end backwards to find the last '/' to isolate the directory */
for (cptr = cmdbuf + lnln - 1; (cptr >= cmdbuf) && ('/' != *cptr); cptr--)
@@ -1065,15 +1101,16 @@ int validate_receiver(gtmsecshr_mesg *buf, char *rundir, int rundir_len, int sav
{
save_errno = errno;
buf->code = save_errno;
- send_msg(VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6, RTS_ERROR_LITERAL("Server"), process_id, buf->pid, save_code,
- buf->mesg.id, ERR_TEXT, 2, RTS_ERROR_LITERAL("Could not open /proc/<pid>/cmdline"), save_errno);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6,
+ RTS_ERROR_LITERAL("Server"), process_id, buf->pid, save_code, buf->mesg.id, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Could not open /proc/<pid>/cmdline"), save_errno);
return save_errno;
}
/* Insert map reading code TODO */
FCLOSE(procstrm, clrv);
if (-1 == clrv)
/* Not a functional issue so just warn about it in op-log */
- send_msg(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fclose()"), CALLFROM, errno);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fclose()"), CALLFROM, errno);
# endif
return 0;
}
@@ -1084,7 +1121,8 @@ boolean_t gtm_tag_error(char *filename, int realtag, int desiredtag)
char *errmsg;
errmsg = STRERROR(errno);
- send_msg(VARLSTCNT(10) ERR_BADTAG, 4, LEN_AND_STR(filename), realtag, desiredtag, ERR_TEXT, 2, RTS_ERROR_STRING(errmsg));
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_BADTAG, 4, LEN_AND_STR(filename),
+ realtag, desiredtag, ERR_TEXT, 2, RTS_ERROR_STRING(errmsg));
return FALSE;
}
#endif
diff --git a/sr_unix/gtmsecshr_wrapper.c b/sr_unix/gtmsecshr_wrapper.c
index 6e1fc04..79bda13 100644
--- a/sr_unix/gtmsecshr_wrapper.c
+++ b/sr_unix/gtmsecshr_wrapper.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2008, 2012 Fidelity Information Services, Inc *
+ * Copyright 2008, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -13,7 +13,7 @@
#define BYPASS_MEMCPY_OVERRIDE /* Signals gtm_string.h to not override memcpy(). This causes linking problems when libmumps.a
* is not available.
*/
-#/* We want system malloc, not gtm_malloc (which comes from mdef.h --> mdefsp.h). Since gtmsecshr_wrapper runs as root,
+/* We want system malloc, not gtm_malloc (which comes from mdef.h --> mdefsp.h). Since gtmsecshr_wrapper runs as root,
* using the system malloc will increase security over using gtm_malloc. Additionally, by not using gtm_malloc, we
* are reducing code bloat.
*/
@@ -29,19 +29,18 @@
#ifndef __MVS__
# include <malloc.h>
#endif
+#include <signal.h>
#include <errno.h>
#define ROOTUID 0
#define ROOTGID 0
#define MAX_ENV_VAR_VAL_LEN 1024
#define MAX_ALLOWABLE_LEN 256
+#define ASCIICTLMAX 32 /* space character */
+#define ASCIICTLMIN 0 /* NULL character */
#define OVERWRITE 1
#define GTM_TMP "gtm_tmp"
#define GTM_DIST "gtm_dist"
#define GTM_DBGLVL "gtmdbglvl"
-#ifdef __MVS__
-# define GTM_ZOS_AUTOCVT "_BPXK_AUTOCVT"
-# define GTM_ZOS_AUTOCVT_ON "ON"
-#endif
#define SUB_PATH_TO_GTMSECSHRDIR "/gtmsecshrdir"
#define REL_PATH_TO_CURDIR "."
#define REL_PATH_TO_GTMSECSHR "./gtmsecshr"
@@ -66,6 +65,41 @@ extern char **environ;
#pragma pointer_size (restore)
#endif
+/* Since gtmsecshr_wrapper.c is a stand-alone module, we cannot use error_def-style definitions, so use simple macro defines to
+ * initialize all error types used along with their respective mnemonics. Note that we need two '%' to ensure the '%' prefix
+ * in the syslog.
+ */
+#define ERR_SECSHRCHDIRFAILED \
+ "%%GTM-E-SECSHRCHDIRFAILED, chdir failed on %s, errno %d. gtmsecshr will not be started\n"
+#define ERR_SECSHRCLEARENVFAILED \
+ "%%GTM-E-SECSHRCLEARENVFAILED, clearenv failed. gtmsecshr will not be started\n"
+#define ERR_SECSHREXECLFAILED \
+ "%%GTM-E-SECSHREXECLFAILED, execl of %s failed\n"
+#define ERR_SECSHRGTMDBGLVL2LONG \
+ "%%GTM-E-SECSHRGTMDBGLVL2LONG, gtmdbglvl env var too long. gtmsecshr will not be started\n"
+#define ERR_SECSHRGTMDIST2LONG \
+ "%%GTM-E-SECSHRGTMDIST2LONG, gtm_dist env var too long. gtmsecshr will not be started\n"
+#define ERR_SECSHRGTMTMP2LONG \
+ "%%GTM-E-SECSHRGTMTMP2LONG, gtm_tmp env var too long. gtmsecshr will not be started\n"
+#define ERR_SECSHRNOGTMDIST \
+ "%%GTM-E-SECSHRNOGTMDIST, gtm_dist env var does not exist. gtmsecshr will not be started\n"
+#define ERR_SECSHRNOTOWNEDBYROOT \
+ "%%GTM-E-SECSHRNOTOWNEDBYROOT, %s not owned by root. gtmsecshr will not be started\n"
+#define ERR_SECSHRNOTSETUID \
+ "%%GTM-E-SECSHRNOTSETUID, %s not set-uid. gtmsecshr will not be started\n"
+#define ERR_SECSHRPERMINCRCT \
+ "%%GTM-E-SECSHRPERMINCRCT, %s permissions incorrect (%04o). gtmsecshr will not be started\n"
+#define ERR_SECSHRSETGTMDISTFAILED \
+ "%%GTM-E-SECSHRSETGTMDISTFAILED, setenv for gtm_dist failed. gtmsecshr will not be started\n"
+#define ERR_SECSHRSETGTMTMPFAILED \
+ "%%GTM-E-SECSHRSETGTMTMPFAILED, setenv for gtm_tmp failed. gtmsecshr will not be started\n"
+#define ERR_SECSHRSETUIDFAILED \
+ "%%GTM-E-SECSHRSETUIDFAILED, setuid failed. gtmsecshr will not be started\n"
+#define ERR_SECSHRSTATFAILED \
+ "%%GTM-E-SECSHRSTATFAILED, stat failed on %s, errno %d. gtmsecshr will not be started\n"
+#define ERR_SECSHRWRITABLE \
+ "%%GTM-E-SECSHRWRITABLE, %s writable. gtmsecshr will not be started\n"
+
int gtm_setenv(char * env_var_name, char * env_var_val, int overwrite);
int gtm_setenv(char * env_var_name, char * env_var_val, int overwrite)
{ /* The overwrite parameter is not used. In our case we always want to set the value */
@@ -120,6 +154,23 @@ int gtm_clearenv()
return 0;
}
+void strsanitize(char *src, char *dst);
+void strsanitize(char *src, char *dst)
+{
+ int i, srclen;
+
+ /* The calling function already validate the string length. */
+ srclen = strlen(src);
+ for (i = 0; i <= srclen && i < MAX_ENV_VAR_VAL_LEN; i++)
+ {
+ /* Convert all control characters to '*'. */
+ if (ASCIICTLMAX > (int)src[i] && ASCIICTLMIN < (int)src[i])
+ dst[i] = '*';
+ else
+ dst[i] = src[i];
+ }
+}
+
int main()
{
int ret, status;
@@ -130,20 +181,28 @@ int main()
char gtm_tmp_val[MAX_ENV_VAR_VAL_LEN];
char gtm_dbglvl_val[MAX_ENV_VAR_VAL_LEN];
char gtm_secshrdir_path[MAX_ENV_VAR_VAL_LEN];
+ char gtm_secshrdir_path_display[MAX_ENV_VAR_VAL_LEN];
char gtm_secshr_path[MAX_ENV_VAR_VAL_LEN];
+ char gtm_secshr_path_display[MAX_ENV_VAR_VAL_LEN];
char gtm_secshr_orig_path[MAX_ENV_VAR_VAL_LEN];
int gtm_tmp_exists = 0;
int gtm_dbglvl_exists = 0;
+ sigset_t mask;
+ /* Reset the signal mask (since the one inherited from the invoking process might have signals such as SIGALRM or SIGTERM
+ * blocked) to let gtmsecshr manage its own signals using sig_init.
+ */
+ sigemptyset(&mask);
+ sigprocmask(SIG_SETMASK, &mask, NULL);
OPENLOG("GTMSECSHRINIT", LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_USER);
ret = 0; /* start positive */
/* get the ones we need */
if (env_var_ptr = getenv(GTM_DIST)) /* Warning - assignment */
{
- if (MAX_ALLOWABLE_LEN < strlen(env_var_ptr) + STR_LIT_LEN(SUB_PATH_TO_GTMSECSHRDIR)
- + STR_LIT_LEN(GTMSECSHR_BASENAME))
+ if (MAX_ALLOWABLE_LEN < (strlen(env_var_ptr) + STR_LIT_LEN(SUB_PATH_TO_GTMSECSHRDIR)
+ + STR_LIT_LEN(GTMSECSHR_BASENAME)))
{
- SYSLOG(LOG_USER | LOG_INFO, "gtm_dist env var too long. gtmsecshr will not be started\n");
+ SYSLOG(LOG_USER | LOG_INFO, ERR_SECSHRGTMDIST2LONG);
ret = -1;
} else
{
@@ -152,20 +211,22 @@ int main()
strcpy(gtm_secshr_path, env_var_ptr);
strcat(gtm_secshr_path, SUB_PATH_TO_GTMSECSHRDIR);
strcat(gtm_secshr_path, GTMSECSHR_BASENAME);
+ strsanitize(gtm_secshr_path, gtm_secshr_path_display);
/* point the path to the real gtmsecshrdir */
strcpy(gtm_secshrdir_path, env_var_ptr);
strcat(gtm_secshrdir_path, SUB_PATH_TO_GTMSECSHRDIR);
+ strsanitize(gtm_secshrdir_path, gtm_secshrdir_path_display);
}
} else
{
- SYSLOG(LOG_USER | LOG_INFO, "gtm_dist env var does not exist. gtmsecshr will not be started\n");
+ SYSLOG(LOG_USER | LOG_INFO, ERR_SECSHRNOGTMDIST);
ret = -1;
}
if (env_var_ptr = getenv(GTM_TMP)) /* Warning - assignment */
{
if (MAX_ALLOWABLE_LEN < strlen(env_var_ptr))
{
- SYSLOG(LOG_USER | LOG_INFO, "gtm_tmp env var too long. gtmsecshr will not be started\n");
+ SYSLOG(LOG_USER | LOG_INFO, ERR_SECSHRGTMTMP2LONG);
ret = -1;
} else
{
@@ -177,7 +238,7 @@ int main()
{
if (MAX_ALLOWABLE_LEN < strlen(env_var_ptr))
{
- SYSLOG(LOG_USER | LOG_INFO, "gtmdbglvl env var too long. gtmsecshr will not be started\n");
+ SYSLOG(LOG_USER | LOG_INFO, ERR_SECSHRGTMDBGLVL2LONG);
ret = -1;
} else
{
@@ -185,23 +246,19 @@ int main()
strcpy(gtm_dbglvl_val, env_var_ptr);
}
}
-# ifdef __MVS__
- if (!(env_var_ptr = getenv(GTM_ZOS_AUTOCVT))) /* Warning - assignment */
- SYSLOG(LOG_USER | LOG_INFO, "_BPXK_AUTOCVT is not set, forcing autoconversion\n");
-# endif
if (!ret)
{ /* clear all */
status = gtm_clearenv();
if (status)
{
- SYSLOG(LOG_USER | LOG_INFO, "clearenv failed. gtmsecshr will not be started\n");
+ SYSLOG(LOG_USER | LOG_INFO, ERR_SECSHRCLEARENVFAILED);
ret = -1;
}
/* add the ones we need */
status = gtm_setenv(GTM_DIST, gtm_dist_val, OVERWRITE);
if (status)
{
- SYSLOG(LOG_USER | LOG_INFO, "setenv for gtm_dist failed. gtmsecshr will not be started\n");
+ SYSLOG(LOG_USER | LOG_INFO, ERR_SECSHRSETGTMDISTFAILED);
ret = -1;
}
if (gtm_tmp_exists)
@@ -209,50 +266,41 @@ int main()
status = gtm_setenv(GTM_TMP, gtm_tmp_val, OVERWRITE);
if (status)
{
- SYSLOG(LOG_USER | LOG_INFO, "setenv for gtm_tmp failed. gtmsecshr will not be started\n");
+ SYSLOG(LOG_USER | LOG_INFO, ERR_SECSHRSETGTMTMPFAILED);
ret = -1;
}
}
-# ifdef __MVS__
- status = gtm_setenv(GTM_ZOS_AUTOCVT, GTM_ZOS_AUTOCVT_ON, OVERWRITE);
- if (status)
- SYSLOG(LOG_USER | LOG_INFO,
- "setenv for _BPXK_AUTOCVT failed. gtmsecshr logs may contain mixed ASCII and EBCDIC\n");
-# endif
}
if (!ret)
{ /* go to root */
if (-1 == CHDIR(gtm_secshrdir_path))
- SYSLOG(LOG_USER | LOG_INFO, "chdir failed on %s, errno %d. gtmsecshr will not be started\n",
- gtm_secshrdir_path, errno);
+ SYSLOG(LOG_USER | LOG_INFO, ERR_SECSHRCHDIRFAILED, gtm_secshrdir_path_display, errno);
else if (-1 == Stat(REL_PATH_TO_CURDIR, >m_secshrdir_stat))
- SYSLOG(LOG_USER | LOG_INFO, "stat failed on %s, errno %d. gtmsecshr will not be started\n",
- gtm_secshrdir_path, errno);
+ SYSLOG(LOG_USER | LOG_INFO, ERR_SECSHRSTATFAILED, gtm_secshrdir_path_display, errno);
else if (ROOTUID != gtm_secshrdir_stat.st_uid)
- SYSLOG(LOG_USER | LOG_INFO, "%s not owned by root. gtmsecshr will not be started\n", gtm_secshrdir_path);
+ SYSLOG(LOG_USER | LOG_INFO, ERR_SECSHRNOTOWNEDBYROOT, gtm_secshrdir_path_display);
else if (gtm_secshrdir_stat.st_mode & 0277)
- SYSLOG(LOG_USER | LOG_INFO, "%s permissions incorrect (%04o). gtmsecshr will not be started\n",
- gtm_secshrdir_path, gtm_secshrdir_stat.st_mode & 0777);
+ SYSLOG(LOG_USER | LOG_INFO, ERR_SECSHRPERMINCRCT, gtm_secshrdir_path_display,
+ gtm_secshrdir_stat.st_mode & 0777);
else if (-1 == Stat(REL_PATH_TO_GTMSECSHR, >m_secshr_stat))
- SYSLOG(LOG_USER | LOG_INFO, "stat failed on %s, errno %d. gtmsecshr will not be started\n",
- gtm_secshr_path, errno);
+ SYSLOG(LOG_USER | LOG_INFO, ERR_SECSHRSTATFAILED, gtm_secshr_path_display, errno);
else if (ROOTUID != gtm_secshr_stat.st_uid)
- SYSLOG(LOG_USER | LOG_INFO, "%s not owned by root. gtmsecshr will not be started\n", gtm_secshr_path);
+ SYSLOG(LOG_USER | LOG_INFO, ERR_SECSHRNOTOWNEDBYROOT, gtm_secshr_path_display);
else if (gtm_secshr_stat.st_mode & 022)
- SYSLOG(LOG_USER | LOG_INFO, "%s writable. gtmsecshr will not be started\n", gtm_secshr_path);
+ SYSLOG(LOG_USER | LOG_INFO, ERR_SECSHRWRITABLE, gtm_secshr_path_display);
else if (!(gtm_secshr_stat.st_mode & 04000))
- SYSLOG(LOG_USER | LOG_INFO, "%s not set-uid. gtmsecshr will not be started\n", gtm_secshr_path);
+ SYSLOG(LOG_USER | LOG_INFO, ERR_SECSHRNOTSETUID, gtm_secshr_path_display);
else if (-1 == setuid(ROOTUID))
- SYSLOG(LOG_USER | LOG_INFO, "setuid failed. gtmsecshr will not be started\n");
+ SYSLOG(LOG_USER | LOG_INFO, ERR_SECSHRSETUIDFAILED);
else
{ /* call the real gtmsecshr, but have ps display the original gtmsecshr location */
strcpy(gtm_secshr_orig_path, gtm_dist_val);
strcat(gtm_secshr_orig_path, GTMSECSHR_BASENAME);
ret = execl(REL_PATH_TO_GTMSECSHR, gtm_secshr_orig_path, NULL);
if (-1 == ret)
- SYSLOG(LOG_USER | LOG_INFO, "execl of %s failed\n", gtm_secshr_path);
+ SYSLOG(LOG_USER | LOG_INFO, ERR_SECSHREXECLFAILED, gtm_secshr_path_display);
}
}
- closelog();
+ CLOSELOG();
return ret;
}
diff --git a/sr_unix/gtmshr_symbols.exp b/sr_unix/gtmshr_symbols.exp
index 420ae10..db6aed3 100644
--- a/sr_unix/gtmshr_symbols.exp
+++ b/sr_unix/gtmshr_symbols.exp
@@ -1,6 +1,8 @@
gtm_main
gtm_init
+gtm_jinit
gtm_ci
+gtm_cij
gtm_cip
gtm_exit
gtm_zstatus
@@ -13,3 +15,4 @@ gtm_free
gtm_filename_to_id
gtm_is_file_identical
gtm_xcfileid_free
+gtm_is_main_thread
diff --git a/sr_unix/gtmsource.c b/sr_unix/gtmsource.c
index af2f779..93f3d2a 100644
--- a/sr_unix/gtmsource.c
+++ b/sr_unix/gtmsource.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -60,6 +60,7 @@
#include "gtm_zlib.h"
#include "fork_init.h"
#include "heartbeat_timer.h"
+#include "gtmio.h"
GBLDEF boolean_t gtmsource_logstats = FALSE, gtmsource_pool2file_transition = FALSE;
GBLDEF int gtmsource_filter = NO_FILTER;
@@ -83,6 +84,7 @@ GBLREF sgmnt_data_ptr_t cs_data;
GBLREF repl_msg_ptr_t gtmsource_msgp;
GBLREF int gtmsource_msgbufsiz;
GBLREF unsigned char *gtmsource_tcombuff_start;
+GBLREF boolean_t is_jnlpool_creator;
GBLREF uchar_ptr_t repl_filter_buff;
GBLREF int repl_filter_bufsiz;
GBLREF int gtmsource_srv_count;
@@ -96,6 +98,7 @@ error_def(ERR_MUPCLIERR);
error_def(ERR_NOTALLDBOPN);
error_def(ERR_NULLCOLLDIFF);
error_def(ERR_REPLCOMM);
+error_def(ERR_REPLERR);
error_def(ERR_REPLINFO);
error_def(ERR_REPLINSTFREEZECOMMENT);
error_def(ERR_REPLINSTFROZEN);
@@ -108,18 +111,19 @@ int gtmsource()
char print_msg[1024], tmpmsg[1024];
gd_region *reg, *region_top;
sgmnt_addrs *csa, *repl_csa;
- boolean_t jnlpool_creator, all_files_open, isalive;
+ boolean_t all_files_open, isalive;
pid_t pid, ppid, procgp;
seq_num read_jnl_seqno, jnl_seqno;
unix_db_info *udi;
gtmsource_local_ptr_t gtmsource_local;
boolean_t this_side_std_null_coll;
+ int null_fd, rc;
memset((uchar_ptr_t)&jnlpool, 0, SIZEOF(jnlpool_addrs));
call_on_signal = gtmsource_sigstop;
ESTABLISH_RET(gtmsource_ch, SS_NORMAL);
if (-1 == gtmsource_get_opt())
- rts_error(VARLSTCNT(1) ERR_MUPCLIERR);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MUPCLIERR);
if (gtmsource_options.shut_down)
{ /* Wait till shutdown time nears even before going to "jnlpool_init". This is because the latter will return
* with the ftok semaphore and access semaphore held and we do not want to be holding those locks (while
@@ -138,16 +142,16 @@ int gtmsource()
repl_log(stdout, TRUE, TRUE, "Initiating START of source server for secondary instance [%s]\n",
gtmsource_options.secondary_instname);
}
- jnlpool_init(GTMSOURCE, gtmsource_options.start, &jnlpool_creator);
- /* jnlpool_creator == TRUE ==> this process created the journal pool
- * jnlpool_creator == FALSE ==> journal pool already existed and this process simply attached to it.
+ jnlpool_init(GTMSOURCE, gtmsource_options.start, &is_jnlpool_creator);
+ /* is_jnlpool_creator == TRUE ==> this process created the journal pool
+ * is_jnlpool_creator == FALSE ==> journal pool already existed and this process simply attached to it.
*/
if (gtmsource_options.shut_down)
gtmsource_exit(gtmsource_shutdown(FALSE, NORMAL_SHUTDOWN) - NORMAL_SHUTDOWN);
else if (gtmsource_options.activate)
- gtmsource_exit(gtmsource_mode_change(GTMSOURCE_MODE_ACTIVE) - NORMAL_SHUTDOWN);
+ gtmsource_exit(gtmsource_mode_change(GTMSOURCE_MODE_ACTIVE_REQUESTED) - NORMAL_SHUTDOWN);
else if (gtmsource_options.deactivate)
- gtmsource_exit(gtmsource_mode_change(GTMSOURCE_MODE_PASSIVE) - NORMAL_SHUTDOWN);
+ gtmsource_exit(gtmsource_mode_change(GTMSOURCE_MODE_PASSIVE_REQUESTED) - NORMAL_SHUTDOWN);
else if (gtmsource_options.checkhealth)
gtmsource_exit(gtmsource_checkhealth() - NORMAL_SHUTDOWN);
else if (gtmsource_options.changelog)
@@ -180,7 +184,7 @@ int gtmsource()
if (0 > pid)
{
save_errno = errno;
- rts_error(VARLSTCNT(7) ERR_JNLPOOLSETUP, 0,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0,
ERR_TEXT, 2, RTS_ERROR_LITERAL("Could not fork source server"), save_errno);
} else if (0 < pid)
{ /* Parent. Wait until child sets "child_server_running" to FALSE. That is an indication that the child
@@ -199,7 +203,7 @@ int gtmsource()
if (isalive)
{ /* Child process is alive and started with no issues */
if (0 != (save_errno = rel_sem(SOURCE, JNL_POOL_ACCESS_SEM)))
- rts_error(VARLSTCNT(7) ERR_JNLPOOLSETUP, 0,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0,
ERR_TEXT, 2, RTS_ERROR_LITERAL("Error in rel_sem"), save_errno);
ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE);
} else
@@ -207,7 +211,7 @@ int gtmsource()
* If we were the one who created the journal pool, let us clean it up.
*/
repl_log(stdout, TRUE, TRUE, "Source server startup failed. See source server log file\n");
- if (jnlpool_creator)
+ if (is_jnlpool_creator)
status = gtmsource_shutdown(TRUE, NORMAL_SHUTDOWN);
}
/* If the parent is killed (or crashes) between the fork and exit, checkhealth may not detect that startup
@@ -216,6 +220,16 @@ int gtmsource()
*/
gtmsource_exit(isalive ? SRV_ALIVE : SRV_ERR);
}
+ /* Point stdin to /dev/null */
+ OPENFILE("/dev/null", O_RDONLY, null_fd);
+ if (0 > null_fd)
+ rts_error_csa(CSA_ARG(NULL) ERR_REPLERR, RTS_ERROR_LITERAL("Failed to open /dev/null for read"), errno, 0);
+ FCNTL3(null_fd, F_DUPFD, 0, rc);
+ if (0 > rc)
+ rts_error_csa(CSA_ARG(NULL) ERR_REPLERR, RTS_ERROR_LITERAL("Failed to set stdin to /dev/null"), errno, 0);
+ CLOSEFILE(null_fd, rc);
+ if (0 > rc)
+ rts_error_csa(CSA_ARG(NULL) ERR_REPLERR, RTS_ERROR_LITERAL("Failed to close /dev/null"), errno, 0);
/* The parent process (source server startup command) will be holding the ftok semaphore and jnlpool access semaphore
* at this point. The variables that indicate this would have been copied over to the child during the fork. This will
* make the child think it is actually holding them as well when actually it is not. Reset those variables in the child
@@ -246,7 +260,8 @@ int gtmsource()
assert(SS_NORMAL == log_init_status);
repl_log_fd2fp(>msource_log_fp, gtmsource_log_fd);
if (-1 == (procgp = setsid()))
- send_msg(VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Source server error in setsid"), errno);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Source server error in setsid"), errno);
#endif /* REPL_DEBUG_NOBACKGROUND */
if (ZLIB_CMPLVL_NONE != gtm_zlib_cmp_level)
gtm_zlib_init(); /* Open zlib shared library for compression/decompression */
@@ -257,7 +272,7 @@ int gtmsource()
all_files_open = region_init(FALSE);
if (!all_files_open)
{
- gtm_putmsg(VARLSTCNT(1) ERR_NOTALLDBOPN);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOTALLDBOPN);
gtmsource_exit(ABNORMAL_SHUTDOWN);
}
/* Determine primary side null subscripts collation order */
@@ -272,18 +287,18 @@ int gtmsource()
this_side_std_null_coll = csa->hdr->std_null_coll;
else
{
- gtm_putmsg(VARLSTCNT(1) ERR_NULLCOLLDIFF);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NULLCOLLDIFF);
gtmsource_exit(ABNORMAL_SHUTDOWN);
}
}
if (!REPL_ALLOWED(csa) && JNL_ALLOWED(csa))
{
- gtm_putmsg(VARLSTCNT(4) ERR_REPLOFFJNLON, 2, DB_LEN_STR(reg));
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_REPLOFFJNLON, 2, DB_LEN_STR(reg));
gtmsource_exit(ABNORMAL_SHUTDOWN);
}
if (reg->read_only && REPL_ALLOWED(csa))
{
- gtm_putmsg(VARLSTCNT(6) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Source Server does not have write permissions to one or "
"more database files that are replicated"));
gtmsource_exit(ABNORMAL_SHUTDOWN);
@@ -292,8 +307,9 @@ int gtmsource()
/* Initialize source server alive/dead state related fields in "gtmsource_local" before the ftok semaphore is released */
gtmsource_local->gtmsource_pid = process_id;
gtmsource_local->gtmsource_state = GTMSOURCE_START;
- if (jnlpool_creator)
+ if (is_jnlpool_creator)
{
+ DEBUG_ONLY(jnlpool.jnlpool_ctl->jnlpool_creator_pid = process_id);
gtmsource_seqno_init(this_side_std_null_coll);
if (ROOTPRIMARY_SPECIFIED == gtmsource_options.rootprimary)
{ /* Created the journal pool as a root primary. Append a history record to the replication instance file.
@@ -311,18 +327,18 @@ int gtmsource()
* that. Do that while the parent is still holding on to the ftok semaphore waiting for our okay.
*/
if (!ftok_sem_incrcnt(jnlpool.jnlpool_dummy_reg))
- rts_error(VARLSTCNT(1) ERR_JNLPOOLSETUP);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JNLPOOLSETUP);
/* Increment the source server count semaphore */
status = incr_sem(SOURCE, SRC_SERV_COUNT_SEM);
if (0 != status)
{
save_errno = errno;
- rts_error(VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Counter semaphore increment failure in child source server"), save_errno);
}
#else
if (0 != (save_errno = rel_sem_immediate(SOURCE, JNL_POOL_ACCESS_SEM)))
- rts_error(VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Error in rel_sem_immediate"), save_errno);
#endif /* REPL_DEBUG_NOBACKGROUND */
@@ -337,7 +353,7 @@ int gtmsource()
process_id, gtmsource_local->secondary_instname);
sgtm_putmsg(print_msg, VARLSTCNT(4) ERR_REPLINFO, 2, LEN_AND_STR(tmpmsg));
repl_log(gtmsource_log_fp, TRUE, TRUE, print_msg);
- if (jnlpool_creator)
+ if (is_jnlpool_creator)
{
repl_log(gtmsource_log_fp, TRUE, TRUE, "Created jnlpool with shmid = [%d] and semid = [%d]\n",
jnlpool.repl_inst_filehdr->jnlpool_shmid, jnlpool.repl_inst_filehdr->jnlpool_semid);
@@ -374,13 +390,15 @@ int gtmsource()
gtmsource_poll_actions(FALSE);
if (GTMSOURCE_CHANGING_MODE == gtmsource_state)
continue;
+ if (GTMSOURCE_MODE_ACTIVE_REQUESTED == gtmsource_local->mode)
+ gtmsource_local->mode = GTMSOURCE_MODE_ACTIVE;
SPRINTF(tmpmsg, "GTM Replication Source Server now in ACTIVE mode using port %d", gtmsource_local->secondary_port);
sgtm_putmsg(print_msg, VARLSTCNT(4) ERR_REPLINFO, 2, LEN_AND_STR(tmpmsg));
repl_log(gtmsource_log_fp, TRUE, TRUE, print_msg);
gtm_event_log(GTM_EVENT_LOG_ARGC, "MUPIP", "REPLINFO", print_msg);
DEBUG_ONLY(repl_csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs;)
assert(!repl_csa->hold_onto_crit); /* so it is ok to invoke "grab_lock" and "rel_lock" unconditionally */
- grab_lock(jnlpool.jnlpool_dummy_reg, HANDLE_CONCUR_ONLINE_ROLLBACK);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, HANDLE_CONCUR_ONLINE_ROLLBACK);
if (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state)
{
repl_log(gtmsource_log_fp, TRUE, TRUE, "Starting afresh due to ONLINE ROLLBACK\n");
@@ -401,7 +419,7 @@ int gtmsource()
}
rel_lock(jnlpool.jnlpool_dummy_reg);
if (SS_NORMAL != (status = gtmsource_alloc_tcombuff()))
- rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Error allocating initial tcom buffer space. Malloc error"), status);
gtmsource_filter = NO_FILTER;
if ('\0' != gtmsource_local->filter_cmd[0])
diff --git a/sr_unix/gtmsource.h b/sr_unix/gtmsource.h
index abbd69c..3936144 100644
--- a/sr_unix/gtmsource.h
+++ b/sr_unix/gtmsource.h
@@ -13,15 +13,12 @@
#define GTMSOURCE_H
/* for in_addr_t typedef on Linux */
-#ifdef __linux__
#include "gtm_inet.h"
-#else
-#include <netinet/in.h>
GBLREF gd_addr *gd_header;
-#endif
#include "min_max.h"
#include "mdef.h"
#include "gt_timer.h"
+#include "gtm_ipv6.h" /* for union gtm_sockaddr_in46 */
/* Needs mdef.h, gdsfhead.h and its dependencies */
#define JNLPOOL_DUMMY_REG_NAME "JNLPOOL_REG"
@@ -47,7 +44,9 @@ enum
enum
{
GTMSOURCE_MODE_PASSIVE,
- GTMSOURCE_MODE_ACTIVE
+ GTMSOURCE_MODE_ACTIVE,
+ GTMSOURCE_MODE_PASSIVE_REQUESTED,
+ GTMSOURCE_MODE_ACTIVE_REQUESTED
};
enum
@@ -81,9 +80,6 @@ typedef enum
GTMSOURCE_NUM_STATES
} gtmsource_state_t;
-#define MAX_GTMSOURCE_POLL_WAIT 1000000 /* 1s in micro secs */
-#define GTMSOURCE_POLL_WAIT (MAX_GTMSOURCE_POLL_WAIT - 1) /* micro sec, almost 1s */
-
#define GTMSOURCE_WAIT_FOR_RECEIVER_TO_QUIT 5 /* seconds */
#define GTMSOURCE_WAIT_FOR_RECEIVER_CLOSE_CONN (1000 - 1) /* ms */
#define GTMSOURCE_WAIT_FOR_JNLOPEN 10 /* ms */
@@ -178,7 +174,7 @@ typedef struct
boolean_t pool_initialized; /* Set to TRUE only after completely finished with initialization.
* Anyone who does a "jnlpool_init" before this will issue a error.
*/
- uint4 filler_8byte_align;
+ uint4 jnlpool_creator_pid; /* DEBUG-ONLY field used for fake ENOSPC testing */
repl_conn_info_t this_side; /* Replication connection details of this side/instance */
seq_num strm_seqno[MAX_SUPPL_STRMS]; /* the current jnl seqno of each stream */
volatile uint4 onln_rlbk_pid; /* process ID of currently running ONLINE ROLLBACK. 0 if none. */
@@ -335,7 +331,9 @@ typedef struct
* FALSE after the message gets sent.
*/
char secondary_host[MAX_HOST_NAME_LEN]; /* hostname of the secondary */
- uint4 secondary_inet_addr; /* IP address of the secondary */
+ union gtm_sockaddr_in46 secondary_inet_addr; /* IP address of the secondary */
+ int secondary_af; /* address family of the seconary */
+ int secondary_addrlen; /* length of the secondary address */
uint4 secondary_port; /* Port at which Receiver is listening */
boolean_t child_server_running; /* Set to FALSE before starting a source server;
* Set to TRUE by the source server process after its initialization.
@@ -352,6 +350,9 @@ 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;
+#if 0
+ int4 padding; /* Pad structure out to multiple of 8 bytes - un-"#if 0" if needed */
+#endif
} gtmsource_local_struct;
#if defined(__osf__) && defined(__alpha)
@@ -382,7 +383,7 @@ typedef gtmsource_local_struct *gtmsource_local_ptr_t;
/* Push the jnldata_base_off to be aligned to (~JNL_WRT_END_MASK + 1)-byte boundary */
#define JNLPOOL_CTL_SIZE ROUND_UP(SIZEOF(jnlpool_ctl_struct), CACHELINE_SIZE) /* align crit semaphore at cache line */
-#define JNLPOOL_CRIT_SIZE (CRIT_SPACE + SIZEOF(mutex_spin_parms_struct) + SIZEOF(node_local))
+#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
@@ -461,7 +462,6 @@ typedef struct
int4 shutdown_time;
int4 buffsize;
int4 mode;
- in_addr_t sec_inet_addr; /* 32 bits */
int4 secondary_port;
uint4 src_log_interval;
int4 connect_parms[GTMSOURCE_CONN_PARMS_COUNT];
@@ -472,32 +472,11 @@ typedef struct
char freeze_comment[MAX_FREEZE_COMMENT_LEN];
} gtmsource_options_t;
-#define ASSERT_VALID_JNLPOOL(CSA) \
-{ \
- GBLREF jnlpool_ctl_ptr_t jnlpool_ctl; \
- GBLREF jnlpool_addrs jnlpool; \
- \
- assert(CSA && CSA->critical && CSA->nl); /* should have been setup in mu_rndwn_replpool */ \
- assert(jnlpool_ctl && (jnlpool_ctl == jnlpool.jnlpool_ctl)); \
- assert(CSA->critical == (mutex_struct_ptr_t)((sm_uc_ptr_t)jnlpool.jnlpool_ctl + JNLPOOL_CTL_SIZE)); \
- assert(CSA->nl == (node_local_ptr_t) ((sm_uc_ptr_t)CSA->critical + CRIT_SPACE \
- + SIZEOF(mutex_spin_parms_struct))); \
- assert(jnlpool_ctl->filehdr_off); \
- assert(jnlpool_ctl->srclcl_array_off > jnlpool.jnlpool_ctl->filehdr_off); \
- assert(jnlpool_ctl->sourcelocal_array_off > jnlpool.jnlpool_ctl->srclcl_array_off); \
- assert(jnlpool.repl_inst_filehdr == (repl_inst_hdr_ptr_t) ((sm_uc_ptr_t)jnlpool_ctl \
- + jnlpool_ctl->filehdr_off)); \
- assert(jnlpool.gtmsrc_lcl_array == (gtmsrc_lcl_ptr_t)((sm_uc_ptr_t)jnlpool_ctl \
- + jnlpool_ctl->srclcl_array_off)); \
- assert(jnlpool.gtmsource_local_array == (gtmsource_local_ptr_t)((sm_uc_ptr_t)jnlpool_ctl \
- + jnlpool_ctl->sourcelocal_array_off)); \
-}
-
/********** Source server function prototypes **********/
int gtmsource(void);
boolean_t gtmsource_is_heartbeat_overdue(time_t *now, repl_heartbeat_msg_ptr_t overdue_heartbeat);
int gtmsource_alloc_filter_buff(int bufsiz);
-int gtmsource_alloc_msgbuff(int maxbuffsize);
+int gtmsource_alloc_msgbuff(int maxbuffsize, boolean_t discard_oldbuff);
int gtmsource_alloc_tcombuff(void);
void gtmsource_free_filter_buff(void);
void gtmsource_free_msgbuff(void);
@@ -509,7 +488,7 @@ int gtmsource_ctl_close(void);
int gtmsource_ctl_init(void);
int gtmsource_jnlpool(void);
int gtmsource_end1(boolean_t auto_shutdown);
-int gtmsource_est_conn(struct sockaddr_in *secondary_addr);
+int gtmsource_est_conn(void);
int gtmsource_get_jnlrecs(uchar_ptr_t buff, int *data_len, int maxbufflen, boolean_t read_multiple);
int gtmsource_get_opt(void);
int gtmsource_ipc_cleanup(boolean_t auto_shutdown, int *exit_status, int4 *num_src_servers_running);
@@ -528,7 +507,6 @@ int gtmsource_stopfilter(void);
int gtmsource_update_zqgblmod_seqno_and_tn(seq_num resync_seqno);
void gtmsource_end(void);
void gtmsource_exit(int exit_status);
-void gtmsource_init_sec_addr(struct sockaddr_in *secondary_addr);
void gtmsource_seqno_init(boolean_t this_side_std_null_coll);
void gtmsource_stop(boolean_t exit);
void gtmsource_sigstop(void);
diff --git a/sr_unix/gtmsource_checkhealth.c b/sr_unix/gtmsource_checkhealth.c
index 7187307..d9618c0 100644
--- a/sr_unix/gtmsource_checkhealth.c
+++ b/sr_unix/gtmsource_checkhealth.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2006, 2012 Fidelity Information Services, Inc *
+ * Copyright 2006, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -65,6 +65,7 @@ int gtmsource_checkhealth(void)
sgmnt_addrs *csa;
sgmnt_data_ptr_t csd;
char errtxt[OUT_BUFF_SIZE];
+ char *modestr;
assert(holds_sem[SOURCE][JNL_POOL_ACCESS_SEM]);
if (NULL != jnlpool.gtmsource_local) /* Check health of a specific source server */
@@ -92,14 +93,27 @@ int gtmsource_checkhealth(void)
srv_alive = (0 == gtmsource_pid) ? FALSE : is_proc_alive(gtmsource_pid, 0);
if (srv_alive)
{
- repl_log(stderr, FALSE, TRUE, FORMAT_STR1, gtmsource_pid, "Source server", "",
- ((GTMSOURCE_MODE_ACTIVE == gtmsourcelocal_ptr->mode) ? "ACTIVE" : "PASSIVE"));
+ if (GTMSOURCE_MODE_ACTIVE == gtmsourcelocal_ptr->mode)
+ modestr = "ACTIVE";
+ else if (GTMSOURCE_MODE_ACTIVE_REQUESTED == gtmsourcelocal_ptr->mode)
+ modestr = "ACTIVE REQUESTED";
+ else if (GTMSOURCE_MODE_PASSIVE == gtmsourcelocal_ptr->mode)
+ modestr = "PASSIVE";
+ else if (GTMSOURCE_MODE_PASSIVE_REQUESTED == gtmsourcelocal_ptr->mode)
+ modestr = "PASSIVE REQUESTED";
+ else
+ {
+ assert(gtmsourcelocal_ptr->mode != gtmsourcelocal_ptr->mode);
+ modestr = "UNKNOWN";
+ }
+ repl_log(stderr, FALSE, TRUE, FORMAT_STR1, gtmsource_pid, "Source server", "", modestr);
status |= SRV_ALIVE;
num_servers++;
} else
{
repl_log(stderr, FALSE, TRUE, FORMAT_STR, gtmsource_pid, "Source server", " NOT");
- gtm_putmsg(VARLSTCNT(4) ERR_SRCSRVNOTEXIST, 2, LEN_AND_STR(gtmsourcelocal_ptr->secondary_instname));
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_SRCSRVNOTEXIST, 2,
+ LEN_AND_STR(gtmsourcelocal_ptr->secondary_instname));
status |= SRV_DEAD;
}
if (NULL != jnlpool.gtmsource_local)
@@ -133,7 +147,7 @@ int gtmsource_checkhealth(void)
all_files_open = region_init(FALSE);
if (!all_files_open)
{
- gtm_putmsg(VARLSTCNT(1) ERR_NOTALLDBOPN);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOTALLDBOPN);
status |= SRV_ERR;
} else
{
diff --git a/sr_unix/gtmsource_flush_fh.c b/sr_unix/gtmsource_flush_fh.c
index c982be2..c00c6fe 100644
--- a/sr_unix/gtmsource_flush_fh.c
+++ b/sr_unix/gtmsource_flush_fh.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2006, 2012 Fidelity Information Services, Inc *
+ * Copyright 2006, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -42,7 +42,7 @@ void gtmsource_flush_fh(seq_num resync_seqno)
if (jnlpool.gtmsource_local->last_flush_resync_seqno == resync_seqno)
return;
/* need to flush resync_seqno to instance file. Grab the journal pool lock before flushing */
- grab_lock(jnlpool.jnlpool_dummy_reg, HANDLE_CONCUR_ONLINE_ROLLBACK); /* sets gtmsource_state */
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, HANDLE_CONCUR_ONLINE_ROLLBACK); /* sets gtmsource_state */
if (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state)
return;
repl_inst_flush_gtmsrc_lcl(); /* this requires the ftok semaphore to be held */
diff --git a/sr_unix/gtmsource_freeze.c b/sr_unix/gtmsource_freeze.c
index dec4e93..153d166 100644
--- a/sr_unix/gtmsource_freeze.c
+++ b/sr_unix/gtmsource_freeze.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2012 Fidelity Information Services, Inc *
+ * Copyright 2012, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -45,7 +45,7 @@ int gtmsource_setfreeze(void)
if (gtmsource_options.freezeval)
{
assert(holds_sem[SOURCE][JNL_POOL_ACCESS_SEM]);
- grab_lock(jnlpool.jnlpool_dummy_reg, ASSERT_NO_ONLINE_ROLLBACK); /* sets gtmsource_state */
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK); /* sets gtmsource_state */
} else
assert(!holds_sem[SOURCE][JNL_POOL_ACCESS_SEM]);
jnlpool.jnlpool_ctl->freeze = gtmsource_options.freezeval;
diff --git a/sr_unix/gtmsource_get_opt.c b/sr_unix/gtmsource_get_opt.c
index bf5cd94..0510bc9 100644
--- a/sr_unix/gtmsource_get_opt.c
+++ b/sr_unix/gtmsource_get_opt.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2006, 2012 Fidelity Information Services, Inc.*
+ * Copyright 2006, 2013 Fidelity Information Services, Inc.*
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -17,7 +17,7 @@
#include "gtm_inet.h"
#include "gtm_string.h"
#include "gtm_ctype.h"
-#if !defined(__MVS__) && !defined(VMS) && !defined(__CYGWIN__)
+#if !defined(__MVS__) && !defined(VMS) && !defined(__CYGWIN__) && (!defined(__GNUC__) && defined(__hpux))
#include <sys/socketvar.h>
#endif
#ifdef VMS
@@ -56,9 +56,11 @@
GBLREF gtmsource_options_t gtmsource_options;
+error_def(ERR_GETADDRINFO);
error_def(ERR_LOGTOOLONG);
error_def(ERR_REPLINSTSECLEN);
error_def(ERR_REPLINSTSECUNDF);
+error_def(ERR_TEXT);
int gtmsource_get_opt(void)
{
@@ -76,6 +78,9 @@ int gtmsource_get_opt(void)
unsigned short log_file_len, filter_cmd_len;
unsigned short secondary_len, inst_name_len, statslog_val_len, update_val_len, connect_parms_str_len;
unsigned short freeze_val_len, freeze_comment_len;
+ int errcode;
+ int port_len;
+ char *ip_end;
memset((char *)>msource_options, 0, SIZEOF(gtmsource_options));
gtmsource_options.start = (CLI_PRESENT == cli_present("START"));
@@ -137,9 +142,9 @@ int gtmsource_get_opt(void)
} else if (!gtmsource_options.checkhealth && !gtmsource_options.showbacklog && !gtmsource_options.shut_down)
{
if (SS_LOG2LONG == status)
- gtm_putmsg(VARLSTCNT(5) ERR_LOGTOOLONG, 3, log_nam.len, log_nam.addr,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_LOGTOOLONG, 3, log_nam.len, log_nam.addr,
SIZEOF(inst_name) - 1);
- gtm_putmsg(VARLSTCNT(1) ERR_REPLINSTSECUNDF);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_REPLINSTSECUNDF);
return (-1);
}
}
@@ -149,7 +154,7 @@ int gtmsource_get_opt(void)
inst_name[inst_name_len] = '\0';
if ((MAX_INSTNAME_LEN <= inst_name_len) || (0 == inst_name_len))
{
- gtm_putmsg(VARLSTCNT(4) ERR_REPLINSTSECLEN, 2, inst_name_len, inst_name);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_REPLINSTSECLEN, 2, inst_name_len, inst_name);
return (-1);
}
assert((inst_name_len + 1) <= MAX_INSTNAME_LEN);
@@ -169,50 +174,37 @@ int gtmsource_get_opt(void)
* and secondary_port */
c = secondary_sys;
dotted_notation = TRUE;
- while(*c && *c != ':')
+ if ('[' == *c)
{
- if ('.' != *c && !ISDIGIT_ASCII(*c))
- dotted_notation = FALSE;
- gtmsource_options.secondary_host[index++] = *c++;
+ ip_end = strchr(++c, ']');
+ if (NULL == ip_end || 0 == (index = ip_end - c))
+ {
+ util_out_print("Invalid IP address !AD", TRUE,
+ LEN_AND_STR(secondary_sys));
+ return(-1);
+ }
+ memcpy(gtmsource_options.secondary_host, c, index);
+ gtmsource_options.secondary_host[index] = '\0';
+ c = ip_end + 1;
+ } else
+ {
+ while(*c && (':' != *c))
+ gtmsource_options.secondary_host[index++] = *c++;
+ gtmsource_options.secondary_host[index] = '\0';
}
- gtmsource_options.secondary_host[index] = '\0';
if (':' != *c)
{
util_out_print("Secondary port number should be specified", TRUE);
return(-1);
}
+ port_len = strlen(++c);
errno = 0;
- if (((0 == (gtmsource_options.secondary_port = ATOI(++c))) && (0 != errno))
+ if (((0 == (gtmsource_options.secondary_port = ATOI(c))) && (0 != errno))
|| (0 >= gtmsource_options.secondary_port))
{
util_out_print("Error parsing secondary port number !AD", TRUE, LEN_AND_STR(c));
return(-1);
}
- /* Validate the specified secondary host name */
- if (dotted_notation)
- {
- if ((in_addr_t)-1 ==
- (gtmsource_options.sec_inet_addr = INET_ADDR(gtmsource_options.secondary_host)))
- {
- util_out_print("Invalid IP address !AD", TRUE,
- LEN_AND_STR(gtmsource_options.secondary_host));
- return(-1);
- }
- } else
- {
- for (tries = 0;
- tries < MAX_GETHOST_TRIES &&
- !(sec_hostentry = GETHOSTBYNAME(gtmsource_options.secondary_host)) &&
- h_errno == TRY_AGAIN;
- tries++);
- if (NULL == sec_hostentry)
- {
- util_out_print("Could not find IP address for !AD", TRUE,
- LEN_AND_STR(gtmsource_options.secondary_host));
- return(-1);
- }
- gtmsource_options.sec_inet_addr = ((struct in_addr *)sec_hostentry->h_addr_list[0])->s_addr;
- }
}
if (CLI_PRESENT == cli_present("CONNECTPARAMS"))
{
diff --git a/sr_unix/gtmsource_heartbeat.c b/sr_unix/gtmsource_heartbeat.c
index 486e304..bf50cc4 100644
--- a/sr_unix/gtmsource_heartbeat.c
+++ b/sr_unix/gtmsource_heartbeat.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2006, 2012 Fidelity Information Services, Inc *
+ * Copyright 2006, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -46,7 +46,6 @@ GBLREF int gtmsource_sock_fd;
GBLREF boolean_t gtmsource_logstats;
GBLREF int gtmsource_log_fd;
GBLREF FILE *gtmsource_log_fp;
-GBLREF struct timeval gtmsource_poll_wait, gtmsource_poll_immediate;
GBLREF gtmsource_state_t gtmsource_state;
GBLREF gd_addr *gd_header;
@@ -84,8 +83,8 @@ int gtmsource_init_heartbeat(void)
REPL_DPRINT4("Initialized heartbeat, heartbeat_period = %d s, heartbeat_max_wait = %d s, num_q_entries = %d\n",
heartbeat_period, heartbeat_max_wait, num_q_entries);
if (!(repl_heartbeat_que_head = (repl_heartbeat_que_entry_t *)malloc(num_q_entries * SIZEOF(repl_heartbeat_que_entry_t))))
- rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
- RTS_ERROR_LITERAL("Error in allocating heartbeat queue"), errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_LIT("Error in allocating heartbeat queue"), errno);
memset(repl_heartbeat_que_head, 0, num_q_entries * SIZEOF(repl_heartbeat_que_entry_t));
repl_heartbeat_free_head = repl_heartbeat_que_head + 1;
@@ -171,20 +170,17 @@ int gtmsource_send_heartbeat(time_t *now)
heartbeat_element = (repl_heartbeat_que_entry_t *)remqh((que_ent_ptr_t)repl_heartbeat_free_head);
if (NULL == heartbeat_element) /* Too many pending heartbeats, send later */
return (SS_NORMAL);
-
QWASSIGN(*(seq_num *)&heartbeat_element->heartbeat.ack_seqno[0], jnlpool.jnlpool_ctl->jnl_seqno);
*(gtm_time4_t *)&heartbeat_element->heartbeat.ack_time[0] = (gtm_time4_t)(*now);
heartbeat_element->heartbeat.type = REPL_HEARTBEAT;
heartbeat_element->heartbeat.len = MIN_REPL_MSGLEN;
- REPL_SEND_LOOP(gtmsource_sock_fd, &heartbeat_element->heartbeat, MIN_REPL_MSGLEN, FALSE, >msource_poll_immediate)
+ REPL_SEND_LOOP(gtmsource_sock_fd, &heartbeat_element->heartbeat, MIN_REPL_MSGLEN, REPL_POLL_NOWAIT)
{
gtmsource_poll_actions(FALSE); /* Recursive call */
- if (GTMSOURCE_WAITING_FOR_CONNECTION == gtmsource_state ||
- GTMSOURCE_CHANGING_MODE == gtmsource_state)
+ if ((GTMSOURCE_WAITING_FOR_CONNECTION == gtmsource_state) || (GTMSOURCE_CHANGING_MODE == gtmsource_state))
return (SS_NORMAL);
}
-
if (SS_NORMAL == status)
{
insqt((que_ent_ptr_t)heartbeat_element, (que_ent_ptr_t)repl_heartbeat_que_head);
@@ -208,12 +204,12 @@ int gtmsource_send_heartbeat(time_t *now)
return (SS_NORMAL);
}
if (EREPL_SEND == repl_errno)
- rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
- RTS_ERROR_LITERAL("Error sending HEARTBEAT message. Error in send"), status);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_LIT("Error sending HEARTBEAT message. Error in send"), status);
if (EREPL_SELECT == repl_errno)
- rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
- RTS_ERROR_LITERAL("Error sending HEARTBEAT message. Error in select"), status);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_LIT("Error sending HEARTBEAT message. Error in select"), status);
GTMASSERT;
return -1; /* This will never get executed, added to make compiler happy */
diff --git a/sr_unix/gtmsource_losttncomplete.c b/sr_unix/gtmsource_losttncomplete.c
index a95976b..481f864 100644
--- a/sr_unix/gtmsource_losttncomplete.c
+++ b/sr_unix/gtmsource_losttncomplete.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2006, 2012 Fidelity Information Services, Inc *
+ * Copyright 2006, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -54,7 +54,7 @@ int gtmsource_losttncomplete(void)
{
DEBUG_ONLY(repl_csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs;)
assert(!repl_csa->hold_onto_crit); /* so it is ok to invoke "grab_lock" and "rel_lock" unconditionally */
- grab_lock(jnlpool.jnlpool_dummy_reg, ASSERT_NO_ONLINE_ROLLBACK);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK);
jnlpool.jnlpool_ctl->send_losttn_complete = TRUE;
gtmsourcelocal_ptr = jnlpool.gtmsource_local_array;
for (idx = 0; idx < NUM_GTMSRC_LCL; idx++, gtmsourcelocal_ptr++)
diff --git a/sr_unix/gtmsource_mode_change.c b/sr_unix/gtmsource_mode_change.c
index 2c85aa1..bc1470f 100644
--- a/sr_unix/gtmsource_mode_change.c
+++ b/sr_unix/gtmsource_mode_change.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2006, 2012 Fidelity Information Services, Inc.*
+ * Copyright 2006, 2013 Fidelity Information Services, Inc.*
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -18,12 +18,7 @@
#include "gtm_string.h"
#include "gtmio.h"
#include "repl_sp.h"
-
#include <errno.h>
-#ifdef VMS
-#include <descrip.h> /* Required for gtmsource.h */
-#endif
-
#include "gdsroot.h"
#include "gdsblk.h"
#include "gtm_facility.h"
@@ -57,12 +52,20 @@ int gtmsource_mode_change(int to_mode)
assert(holds_sem[SOURCE][JNL_POOL_ACCESS_SEM]);
repl_log(stdout, TRUE, TRUE, "Initiating %s operation on source server pid [%d] for secondary instance [%s]\n",
- (GTMSOURCE_MODE_ACTIVE == to_mode) ? "ACTIVATE" : "DEACTIVATE",
+ (GTMSOURCE_MODE_ACTIVE_REQUESTED == to_mode) ? "ACTIVATE" : "DEACTIVATE",
jnlpool.gtmsource_local->gtmsource_pid, jnlpool.gtmsource_local->secondary_instname);
- if (jnlpool.gtmsource_local->mode == to_mode)
+ if ((jnlpool.gtmsource_local->mode == GTMSOURCE_MODE_ACTIVE_REQUESTED)
+ || (jnlpool.gtmsource_local->mode == GTMSOURCE_MODE_PASSIVE_REQUESTED))
+ {
+ repl_log(stderr, FALSE, TRUE, "Source Server %s already requested, not changing mode\n",
+ (to_mode == GTMSOURCE_MODE_ACTIVE_REQUESTED) ? "ACTIVATE" : "DEACTIVATE");
+ return (ABNORMAL_SHUTDOWN);
+ }
+ if (((GTMSOURCE_MODE_ACTIVE == jnlpool.gtmsource_local->mode) && (GTMSOURCE_MODE_ACTIVE_REQUESTED == to_mode))
+ || ((GTMSOURCE_MODE_PASSIVE == jnlpool.gtmsource_local->mode) && (GTMSOURCE_MODE_PASSIVE_REQUESTED == to_mode)))
{
repl_log(stderr, FALSE, TRUE, "Source Server already %s, not changing mode\n",
- (to_mode == GTMSOURCE_MODE_ACTIVE) ? "ACTIVE" : "PASSIVE");
+ (to_mode == GTMSOURCE_MODE_ACTIVE_REQUESTED) ? "ACTIVE" : "PASSIVE");
return (ABNORMAL_SHUTDOWN);
}
assert(ROOTPRIMARY_UNSPECIFIED != gtmsource_options.rootprimary);
@@ -74,7 +77,7 @@ int gtmsource_mode_change(int to_mode)
if (log_fd < 0) {
save_errno = ERRNO;
err_code = STRERROR(save_errno);
- gtm_putmsg(VARLSTCNT(8) ERR_REPLLOGOPN, 6,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_REPLLOGOPN, 6,
LEN_AND_STR(gtmsource_options.log_file),
LEN_AND_STR(err_code),
LEN_AND_STR(NULL_DEVICE));
@@ -83,7 +86,7 @@ int gtmsource_mode_change(int to_mode)
CLOSEFILE_IF_OPEN(log_fd, close_status);
assert(close_status==0);
}
- if ((GTMSOURCE_MODE_ACTIVE == to_mode)
+ if ((GTMSOURCE_MODE_ACTIVE_REQUESTED == to_mode)
&& (ROOTPRIMARY_SPECIFIED == gtmsource_options.rootprimary) && jnlpool.jnlpool_ctl->upd_disabled)
{ /* ACTIVATE is specified with ROOTPRIMARY on a journal pool that was created with PROPAGATEPRIMARY. This is a
* case of transition from propagating primary to root primary. Enable updates in this journal pool and append
@@ -93,16 +96,16 @@ int gtmsource_mode_change(int to_mode)
}
DEBUG_ONLY(repl_csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs;)
assert(!repl_csa->hold_onto_crit); /* so it is ok to invoke "grab_lock" and "rel_lock" unconditionally */
- grab_lock(jnlpool.jnlpool_dummy_reg, ASSERT_NO_ONLINE_ROLLBACK);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK);
/* Any ACTIVATE/DEACTIVATE versus ROOTPRIMARY/PROPAGATE incompatibilities have already been checked in the
* function "jnlpool_init" so go ahead and document the impending activation/deactivation and return.
* This flag will be eventually detected by the concurrently running source server which will then change mode.
*/
- if (GTMSOURCE_MODE_ACTIVE == to_mode)
+ if (GTMSOURCE_MODE_ACTIVE_REQUESTED == to_mode)
{
jnlpool.gtmsource_local->secondary_port = gtmsource_options.secondary_port;
- jnlpool.gtmsource_local->secondary_inet_addr = gtmsource_options.sec_inet_addr;
STRCPY(jnlpool.gtmsource_local->secondary_host, gtmsource_options.secondary_host);
+ jnlpool.gtmsource_local->secondary_port = gtmsource_options.secondary_port;
memcpy(&jnlpool.gtmsource_local->connect_parms[0], >msource_options.connect_parms[0],
SIZEOF(gtmsource_options.connect_parms));
}
diff --git a/sr_unix/gtmsource_needrestart.c b/sr_unix/gtmsource_needrestart.c
index ddd6e7e..7f1090e 100644
--- a/sr_unix/gtmsource_needrestart.c
+++ b/sr_unix/gtmsource_needrestart.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2006, 2012 Fidelity Information Services, Inc *
+ * Copyright 2006, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -55,7 +55,7 @@ int gtmsource_needrestart(void)
gtmsource_options.secondary_instname);
DEBUG_ONLY(repl_csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs;)
assert(!repl_csa->hold_onto_crit); /* so it is ok to invoke "grab_lock" and "rel_lock" unconditionally */
- grab_lock(jnlpool.jnlpool_dummy_reg, ASSERT_NO_ONLINE_ROLLBACK);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK);
if ((NULL != gtmsource_local) && (gtmsource_local->connect_jnl_seqno >= jnlpool.jnlpool_ctl->start_jnl_seqno))
util_out_print("Secondary Instance [!AZ] DOES NOT NEED to be restarted", TRUE, gtmsource_local->secondary_instname);
else
diff --git a/sr_unix/gtmsource_onln_rlbk_clnup.c b/sr_unix/gtmsource_onln_rlbk_clnup.c
index df9e78c..35c32ac 100644
--- a/sr_unix/gtmsource_onln_rlbk_clnup.c
+++ b/sr_unix/gtmsource_onln_rlbk_clnup.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2012 Fidelity Information Services, Inc *
+ * Copyright 2012, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -77,7 +77,7 @@ void gtmsource_onln_rlbk_clnup()
*/
gtmsource_local->gtmsource_state = gtmsource_state = GTMSOURCE_HANDLE_ONLN_RLBK;
if (!was_crit)
- grab_lock(jnlpool.jnlpool_dummy_reg, ASSERT_NO_ONLINE_ROLLBACK);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK);
/* We have to let the read files logic know that until we have sent data "upto" the current journal sequence number
* at this point, we cannot rely on the journal pool. Indicate this through the gtmsource_save_read_jnl_seqno global
* variable
diff --git a/sr_unix/gtmsource_process.c b/sr_unix/gtmsource_process.c
index 70657da..aca7f0a 100644
--- a/sr_unix/gtmsource_process.c
+++ b/sr_unix/gtmsource_process.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2006, 2012 Fidelity Information Services, Inc.*
+ * Copyright 2006, 2013 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 "gtm_string.h"
#include "gtm_stdio.h"
#include "gtm_socket.h"
+#include "gtm_netdb.h"
#include "gtm_inet.h"
#include "gtm_fcntl.h"
#include "gtm_unistd.h"
@@ -27,10 +28,6 @@
#include <errno.h>
#include <signal.h>
-#ifdef VMS
-#include <descrip.h> /* Required for gtmsource.h */
-#endif
-
#include "gdsroot.h"
#include "gdsblk.h"
#include "gtm_facility.h"
@@ -70,7 +67,7 @@
#include "gtmsource_srv_latch.h"
#include "gv_trigger_common.h"
-#define MAX_HEXDUMP_CHARS_PER_LINE 26 /* 2 characters per byte + space, 80 column assumed */
+#define MAX_HEXDUMP_CHARS_PER_LINE 26 /* 2 characters per byte + space, 80 column assumed */
#define BREAK_IF_CMP_ERROR(CMPRET, SEND_TR_LEN) \
{ \
@@ -143,7 +140,6 @@
#endif
-GBLDEF struct timeval gtmsource_poll_wait, gtmsource_poll_immediate;
GBLDEF repl_msg_ptr_t gtmsource_msgp = NULL;
GBLDEF int gtmsource_msgbufsiz = 0;
GBLDEF repl_msg_ptr_t gtmsource_cmpmsgp = NULL;
@@ -157,6 +153,7 @@ GBLDEF qw_num repl_source_lastlog_msg_sent = 0;
GBLDEF time_t repl_source_prev_log_time;
GBLDEF time_t repl_source_this_log_time;
GBLDEF time_t gtmsource_last_flush_time;
+
GBLREF gtmsource_state_t gtmsource_state;
GBLREF uchar_ptr_t repl_filter_buff;
GBLREF int repl_filter_bufsiz;
@@ -293,7 +290,8 @@ static void repl_tr_endian_convert(repl_msg_ptr_t send_msgp, int send_tr_len, se
if ((-1 == status) || (0 != jlen))
{
assert(FALSE);
- rts_error(VARLSTCNT(5) ERR_REPLXENDIANFAIL, 3, LEN_AND_LIT("Originating"), &pre_read_seqno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_REPLXENDIANFAIL, 3,
+ LEN_AND_LIT("Originating"), &pre_read_seqno);
}
/* move on to the next transaction */
remaining_len -= (buflen + REPL_MSG_HDRLEN);
@@ -304,7 +302,7 @@ static void repl_tr_endian_convert(repl_msg_ptr_t send_msgp, int send_tr_len, se
}
if (0 != remaining_len)
{
- rts_error(VARLSTCNT(5) ERR_REPLXENDIANFAIL, 3, LEN_AND_LIT("Originating"), &pre_read_seqno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_REPLXENDIANFAIL, 3, LEN_AND_LIT("Originating"), &pre_read_seqno);
assert(FALSE);
}
}
@@ -315,7 +313,6 @@ int gtmsource_process(void)
gtmsource_local_ptr_t gtmsource_local;
jnlpool_ctl_ptr_t jctl;
seq_num recvd_seqno, sav_read_jnl_seqno;
- struct sockaddr_in secondary_addr;
seq_num recvd_jnl_seqno, tmp_read_jnl_seqno;
int data_len, srch_status;
unsigned char *msg_ptr; /* needed for REPL_{SEND,RECV}_LOOP */
@@ -323,22 +320,19 @@ int gtmsource_process(void)
int torecv_len, recvd_len, recvd_this_iter; /* needed for REPL_RECV_LOOP */
int status; /* needed for REPL_{SEND,RECV}_LOOP */
int tot_tr_len, send_tr_len, remaining_len, pre_cmpmsglen;
- struct timeval poll_time;
int recvd_msg_type, recvd_start_flags;
uchar_ptr_t in_buff, out_buff, out_buffmsg;
uint4 in_buflen, out_buflen, out_bufsiz;
seq_num log_seqno, diff_seqno, pre_read_seqno, post_read_seqno, jnl_seqno;
char err_string[1024];
- boolean_t xon_wait_logged, prev_catchup, catchup, force_recv_check, already_communicated;
+ boolean_t xon_wait_logged, already_communicated;
double time_elapsed;
seq_num resync_seqno, zqgblmod_seqno, filter_seqno;
gd_region *reg, *region_top;
sgmnt_addrs *csa, *repl_csa;
- qw_num backlog_bytes, backlog_count, delta_sent_cnt, delta_data_sent, delta_msg_sent;
- long prev_msg_sent = 0;
- time_t prev_now = 0, save_now;
- int index;
- struct timeval poll_wait, poll_immediate;
+ qw_num delta_sent_cnt, delta_data_sent, delta_msg_sent;
+ time_t prev_now;
+ int index, poll_time;
uint4 temp_ulong;
unix_db_info *udi;
repl_histinfo remote_histinfo, local_histinfo;
@@ -377,18 +371,11 @@ int gtmsource_process(void)
gtmsource_msgbufsiz = MAX_REPL_MSGLEN;
if (ZLIB_CMPLVL_NONE != gtm_zlib_cmp_level)
gtmsource_cmpmsgp = NULL;
- assert(GTMSOURCE_POLL_WAIT < MAX_GTMSOURCE_POLL_WAIT);
- gtmsource_poll_wait.tv_sec = 0;
- gtmsource_poll_wait.tv_usec = GTMSOURCE_POLL_WAIT;
- poll_wait = gtmsource_poll_wait;
- gtmsource_poll_immediate.tv_sec = 0;
- gtmsource_poll_immediate.tv_usec = 0;
- poll_immediate = gtmsource_poll_immediate;
+ assert(REPL_POLL_WAIT < MILLISECS_IN_SEC);
+ assert(GTMSOURCE_IDLE_POLL_WAIT < REPL_POLL_WAIT);
- gtmsource_init_sec_addr(&secondary_addr);
gtmsource_state = gtmsource_local->gtmsource_state = GTMSOURCE_WAITING_FOR_CONNECTION;
-
gtmsource_srv_latch = >msource_local->gtmsource_srv_latch;
/* Below is a simplistic representation of the state diagram of a source server.
*
@@ -480,7 +467,7 @@ int gtmsource_process(void)
if (GTMSOURCE_WAITING_FOR_CONNECTION == gtmsource_state)
{
gtmsource_start_jnl_release_timer();
- gtmsource_est_conn(&secondary_addr);
+ gtmsource_est_conn();
gtmsource_stop_jnl_release_timer();
if (GTMSOURCE_CHANGING_MODE == gtmsource_state)
return (SS_NORMAL);
@@ -488,7 +475,7 @@ int gtmsource_process(void)
repl_source_lastlog_data_sent = 0;
repl_source_lastlog_msg_sent = 0;
- gtmsource_alloc_msgbuff(MAX_REPL_MSGLEN);
+ gtmsource_alloc_msgbuff(MAX_REPL_MSGLEN, TRUE);
gtmsource_state = gtmsource_local->gtmsource_state = GTMSOURCE_WAITING_FOR_RESTART;
recvd_start_flags = START_FLAG_NONE;
repl_source_prev_log_time = time(NULL);
@@ -511,7 +498,8 @@ int gtmsource_process(void)
{
SNPRINTF(err_string, SIZEOF(err_string),
"Error receiving RESTART SEQNO. Error in recv : %s", STRERROR(status));
- rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(err_string));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_STR(err_string));
}
} else if (EREPL_SEND == repl_errno)
{
@@ -527,12 +515,14 @@ int gtmsource_process(void)
}
SNPRINTF(err_string, SIZEOF(err_string), "Error sending XOFF_ACK_ME message. Error in send : %s",
STRERROR(status));
- rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(err_string));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_STR(err_string));
} else if (EREPL_SELECT == repl_errno)
{
SNPRINTF(err_string, SIZEOF(err_string), "Error receiving RESTART SEQNO/sending XOFF_ACK_ME. "
"Error in select : %s", STRERROR(status));
- rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(err_string));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_STR(err_string));
}
}
if (GTMSOURCE_CHANGING_MODE == gtmsource_state)
@@ -569,7 +559,7 @@ int gtmsource_process(void)
}
rollback_first = FALSE;
secondary_ahead = FALSE;
- grab_lock(jnlpool.jnlpool_dummy_reg, HANDLE_CONCUR_ONLINE_ROLLBACK);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, HANDLE_CONCUR_ONLINE_ROLLBACK);
if (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state)
continue;
local_jnl_seqno = jctl->jnl_seqno;
@@ -669,7 +659,7 @@ int gtmsource_process(void)
* the 0th history record in the instance file corresponds to the 0th stream. So it is
* safe to look at the start_seqno of just the 0th history record in all cases.
*/
- grab_lock(jnlpool.jnlpool_dummy_reg, HANDLE_CONCUR_ONLINE_ROLLBACK);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, HANDLE_CONCUR_ONLINE_ROLLBACK);
if (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state)
continue;
status = repl_inst_histinfo_get(0, &local_histinfo);
@@ -685,7 +675,7 @@ int gtmsource_process(void)
}
if (!skip_last_histinfo_check)
{ /* Find histinfo record in the local instance file corresponding to seqno "recvd_seqno-1" */
- grab_lock(jnlpool.jnlpool_dummy_reg, HANDLE_CONCUR_ONLINE_ROLLBACK);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, HANDLE_CONCUR_ONLINE_ROLLBACK);
if (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state)
continue;
assert(recvd_seqno <= local_jnl_seqno);
@@ -713,7 +703,7 @@ int gtmsource_process(void)
*/
SPRINTF(histdetail, "seqno "INT8_FMT" "INT8_FMTX, recvd_seqno - 1, recvd_seqno - 1);
- gtm_putmsg(VARLSTCNT(6) ERR_REPLINSTNOHIST, 4,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLINSTNOHIST, 4,
LEN_AND_STR(histdetail), LEN_AND_STR(udi->fn));
instnohist_msg.type = REPL_INST_NOHIST;
instnohist_msg.len = MIN_REPL_MSGLEN;
@@ -893,7 +883,7 @@ int gtmsource_process(void)
/* After having established connection, initialize a few fields in the gtmsource_local
* structure and flush those changes to the instance file on disk.
*/
- grab_lock(jnlpool.jnlpool_dummy_reg, HANDLE_CONCUR_ONLINE_ROLLBACK);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, HANDLE_CONCUR_ONLINE_ROLLBACK);
if (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state)
continue;
gtmsource_local->connect_jnl_seqno = jctl->jnl_seqno;
@@ -911,7 +901,7 @@ int gtmsource_process(void)
(*(seq_num *)&reply_msgp->start_seqno[0]), (*(seq_num *)&reply_msgp->start_seqno[0]));
region_top = gd_header->regions + gd_header->n_regions;
assert(NULL != jnlpool.jnlpool_dummy_reg);
- grab_lock(jnlpool.jnlpool_dummy_reg, HANDLE_CONCUR_ONLINE_ROLLBACK);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, HANDLE_CONCUR_ONLINE_ROLLBACK);
if (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state)
continue;
zqgblmod_seqno = jctl->max_zqgblmod_seqno;
@@ -988,7 +978,11 @@ int gtmsource_process(void)
assert(READ_FILE == gtmsource_local->read_state);
gtmsource_set_lookback();
}
- poll_time = poll_immediate;
+ /* The variable poll_time indicates if we should wait for the receive pipe to be I/O ready and should be set to
+ * a non-zero value ONLY if the source server has nothing to send. At this point we have data to send and so
+ * set poll_time to no-wait.
+ */
+ poll_time = REPL_POLL_NOWAIT;
gtmsource_state = gtmsource_local->gtmsource_state = GTMSOURCE_SENDING_JNLRECS;
assert(1 <= gtmsource_local->read_jnl_seqno);
/* Now that "gtmsource_local->read_jnl_seqno" is initialized, ensure the first send gets logged. */
@@ -1022,11 +1016,9 @@ int gtmsource_process(void)
if (NO_FILTER == gtmsource_filter)
gtmsource_free_filter_buff();
}
- catchup = FALSE;
- force_recv_check = TRUE;
xon_wait_logged = FALSE;
- /* Flush "gtmsource_local->read_jnl_seqno" to disk right now.
- * This will serve as a reference point for next timed flush to occur.
+ /* Flush "gtmsource_local->read_jnl_seqno" to disk right now. This will serve as a reference point for next timed
+ * flush to occur.
*/
gtmsource_flush_fh(gtmsource_local->read_jnl_seqno);
if (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state)
@@ -1034,6 +1026,7 @@ int gtmsource_process(void)
gtmsource_local->send_new_histrec = TRUE; /* Send new histinfo unconditionally at start of connection */
gtmsource_local->next_histinfo_seqno = MAX_SEQNO; /* Initial value. Reset by "gtmsource_send_new_histrec" below */
assert(-1 == gtmsource_local->next_histinfo_num);
+ prev_now = gtmsource_now;
while (TRUE)
{
gtmsource_poll_actions(TRUE);
@@ -1047,7 +1040,7 @@ int gtmsource_process(void)
losttncomplete_msg.len = MIN_REPL_MSGLEN;
gtmsource_repl_send((repl_msg_ptr_t)&losttncomplete_msg, "REPL_LOSTTNCOMPLETE",
MAX_SEQNO, INVALID_SUPPL_STRM);
- grab_lock(jnlpool.jnlpool_dummy_reg, HANDLE_CONCUR_ONLINE_ROLLBACK);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, HANDLE_CONCUR_ONLINE_ROLLBACK);
if (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state)
break; /* the outerloop will continue */
gtmsource_local->send_losttn_complete = FALSE;
@@ -1067,109 +1060,45 @@ int gtmsource_process(void)
break;
assert(FALSE == gtmsource_local->send_new_histrec);
}
- /* If the backlog is high, we want to avoid communication overhead as much as possible. We switch
- * our communication mode to *catchup* mode, wherein we don't wait for the pipe to become ready to
- * send. Rather, we assume the pipe is ready for sending. The risk is that the send may block if
- * the pipe is not ready for sending. In the user's perspective, the risk is that the source server
- * may not respond to administrative actions such as "change log", "shutdown" (although mupip stop
- * would work).
- */
- pre_read_seqno = gtmsource_local->read_jnl_seqno;
- prev_catchup = catchup;
- grab_lock(jnlpool.jnlpool_dummy_reg, HANDLE_CONCUR_ONLINE_ROLLBACK);
- if (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state)
- break; /* the outerloop will continue */
- jnl_seqno = jctl->jnl_seqno;
- assert(jctl->write_addr >= gtmsource_local->read_addr);
- backlog_bytes = jctl->write_addr - gtmsource_local->read_addr;
- rel_lock(jnlpool.jnlpool_dummy_reg);
- assert(jnl_seqno >= pre_read_seqno - 1); /* jnl_seqno >= pre_read_seqno is the most common case;
- * see gtmsource_readpool() for when the rare case can occur */
- backlog_count = (jnl_seqno >= pre_read_seqno) ? (jnl_seqno - pre_read_seqno) : 0;
- catchup = (BACKLOG_BYTES_THRESHOLD <= backlog_bytes || BACKLOG_COUNT_THRESHOLD <= backlog_count);
- if (!prev_catchup && catchup) /* transition from non catchup to catchup */
+ if (prev_now != gtmsource_now)
{
- repl_log(gtmsource_log_fp, TRUE, TRUE, "Source server entering catchup mode at Seqno "INT8_FMT" "
- INT8_FMTX" : Current backlog "INT8_FMT" "INT8_FMTX" : Backlog size in journal pool "
- INT8_FMT" "INT8_FMTX" bytes\n", pre_read_seqno, pre_read_seqno,
- backlog_count, backlog_count, backlog_bytes, backlog_bytes);
prev_now = gtmsource_now;
- prev_msg_sent = repl_source_msg_sent;
- force_recv_check = TRUE;
- } else if (prev_catchup && !catchup) /* transition from catchup to non catchup */
- {
- repl_log(gtmsource_log_fp, TRUE, TRUE, "Source server returning to regular mode from catchup mode "
- "at Seqno "INT8_FMT" "INT8_FMTX" : Current backlog "INT8_FMT" "INT8_FMTX
- " : Backlog size in journal pool "INT8_FMT" "INT8_FMTX" bytes\n",
- pre_read_seqno, pre_read_seqno, backlog_count, backlog_count,
- backlog_bytes, backlog_bytes);
if (gtmsource_msgbufsiz - MAX_REPL_MSGLEN > 2 * OS_PAGE_SIZE)
- {/* We have expanded the buffer by too much (could have been avoided had we sent one transaction
- * at a time while reading from journal files); let's revert back to our initial buffer size.
- * If we don't reduce our buffer, it is possible that the buffer keeps growing (while reading
- * from journal file) thus making the size of sends while reading from journal pool very
- * large (> 1 MB). Better to do some house keeping. We will force an expansion if the transaction
- * size dictates it. Ideally, this must be done while switching reading back from files to
- * pool, but we can't afford to free the buffer until we sent the transaction out. That apart,
- * let's wait for some breathing time to do house keeping. In catchup mode, we intend to keep
- * the send size large. */
+ { /* We have expanded the buffer by too much (could have been avoided had we sent one
+ * transaction at a time while reading from journal files); let's revert back to our
+ * initial buffer size. If we don't reduce our buffer, it is possible that the buffer keeps
+ * growing (while reading * from journal file) thus making the size of sends while reading
+ * from journal pool very large (> 1 MB).
+ */
gtmsource_free_filter_buff();
gtmsource_free_msgbuff();
- gtmsource_alloc_msgbuff(MAX_REPL_MSGLEN); /* will also allocate filter buffer */
+ gtmsource_alloc_msgbuff(MAX_REPL_MSGLEN, TRUE); /* will also allocate filter buffer */
}
}
- /* Check if receiver sent us any control message.
- * Typically, the traffic from receiver to source is very low compared to traffic in the other direction.
- * More often than not, there will be nothing on the pipe to receive. Ideally, we should let TCP
- * notify us when there is data on the pipe (async I/O on Unix and VMS). We are not there yet. Until then,
- * we use heuristics - attempt receive every GTMSOURCE_SENT_THRESHOLD_FOR_RECV bytes of sent data, and
- * every heartbeat period, OR whenever we want to force a check
+ /* Check if receiver sent us any control message. Typically, the traffic from receiver to source is very
+ * low compared to traffic in the other direction. More often than not, there will be nothing on the pipe
+ * to receive. Ideally, we should let TCP notify us when there is data on the pipe (async I/O on Unix and
+ * VMS). But, we are not there yet. Since we do a select() before a recv(), we won't block if there is
+ * nothing in the pipe. So, it shouldn't be an expensive operation even if done before every send. Also,
+ * in doing so, we react to an XOFF sooner than later.
*/
- if ((GTMSOURCE_SENDING_JNLRECS != gtmsource_state) || !catchup || prev_now != (save_now = gtmsource_now)
- || (GTMSOURCE_SENT_THRESHOLD_FOR_RECV <= (repl_source_msg_sent - prev_msg_sent))
- || force_recv_check)
+ /* Make sure we don't sleep for an extended period of time if there is something to be sent across */
+ assert((GTMSOURCE_SENDING_JNLRECS != gtmsource_state)
+ || ((0 == poll_time) || (GTMSOURCE_IDLE_POLL_WAIT == poll_time)));
+ REPL_RECV_LOOP(gtmsource_sock_fd, gtmsource_msgp, MIN_REPL_MSGLEN, poll_time)
{
- REPL_EXTRA_DPRINT2("gtmsource_process: receiving because : %s\n",
- (GTMSOURCE_SENDING_JNLRECS != gtmsource_state) ? "state is not SENDING_JNLRECS" :
- !catchup ? "not in catchup mode" :
- (prev_now != save_now) ? "heartbeat interval passed" :
- (GTMSOURCE_SENT_THRESHOLD_FOR_RECV <= repl_source_msg_sent - prev_msg_sent) ?
- "sent bytes threshold for recv crossed" :
- "force recv check");
- REPL_EXTRA_DPRINT6("gtmsource_state : %d prev_now : %ld gtmsource_now : %ld repl_source_msg_sent "
- ": %ld prev_msg_sent : %ld\n", gtmsource_state, prev_now, save_now,
- repl_source_msg_sent, prev_msg_sent);
- REPL_RECV_LOOP(gtmsource_sock_fd, gtmsource_msgp, MIN_REPL_MSGLEN, FALSE, &poll_time)
- {
- if (0 == recvd_len) /* nothing received in the first attempt, let's try again later */
- break;
- gtmsource_poll_actions(TRUE);
- if (GTMSOURCE_CHANGING_MODE == gtmsource_state)
- return (SS_NORMAL);
- if (GTMSOURCE_WAITING_FOR_CONNECTION == gtmsource_state)
- break;
- }
- REPL_EXTRA_DPRINT3("gtmsource_process: %d received, type is %d\n", recvd_len,
- (0 != recvd_len) ? gtmsource_msgp->type : -1);
- if (GTMSOURCE_SENDING_JNLRECS == gtmsource_state && catchup)
- {
- if (prev_now != save_now)
- prev_now = save_now;
- else if (GTMSOURCE_SENT_THRESHOLD_FOR_RECV <= repl_source_msg_sent - prev_msg_sent)
- { /* do not set to repl_source_msg_sent; increment by GTMSOURCE_SENT_THRESHOLD_FOR_RECV
- * instead so that we force recv every GTMSOURCE_SENT_THRESHOLD_FOR_RECV bytes */
- prev_msg_sent += GTMSOURCE_SENT_THRESHOLD_FOR_RECV;
- }
- }
- } else
- { /* behave as if there was nothing to be read */
- status = SS_NORMAL;
- recvd_len = 0;
+ if (0 == recvd_len) /* nothing received in the first attempt, let's try again later */
+ break;
+ gtmsource_poll_actions(TRUE);
+ if (GTMSOURCE_CHANGING_MODE == gtmsource_state)
+ return (SS_NORMAL);
+ if (GTMSOURCE_WAITING_FOR_CONNECTION == gtmsource_state)
+ break;
}
- force_recv_check = FALSE;
- if (SS_NORMAL == status && 0 != recvd_len)
+ if ((SS_NORMAL == status) && (0 != recvd_len))
{ /* Process the received control message */
assert(MIN_REPL_MSGLEN == recvd_len);
+ REPL_DPRINT3("gtmsource_process: %d bytes received, type is %d\n", recvd_len, gtmsource_msgp->type);
/* One is not always guaranteed the received message is in source native endian format.
* See endianness related comments in gtmsource_recv_restart for why. So be safe and handle
* it just like how gtmsource_recv_restart does. The below check works as all messages we
@@ -1184,19 +1113,12 @@ int gtmsource_process(void)
}
assert(MIN_REPL_MSGLEN == gtmsource_msgp->len);
assert(remote_side->endianness_known);
- /* Even though we know the endianness of the remote side at this point, we use
- * msg_is_cross_endian as it should be a safer alternative in case of messages
- * like REPL_XOFF_ACK_ME where the receiver (particularly pre-V55000 versions)
- * is not careful to send in a consistent endian format across versions. So we
- * use the endianness of this particular message rather than the endianness of
- * the connection.
- */
switch(gtmsource_msgp->type)
{
case REPL_XOFF:
case REPL_XOFF_ACK_ME:
gtmsource_state = gtmsource_local->gtmsource_state = GTMSOURCE_WAITING_FOR_XON;
- poll_time = poll_wait;
+ poll_time = REPL_POLL_WAIT; /* because we are waiting for a REPL_XON */
repl_log(gtmsource_log_fp, TRUE, TRUE,
"REPL_XOFF/REPL_XOFF_ACK_ME received. Send stalled...\n");
xon_wait_logged = FALSE;
@@ -1218,25 +1140,10 @@ int gtmsource_process(void)
break;
case REPL_XON:
gtmsource_state = gtmsource_local->gtmsource_state = GTMSOURCE_SENDING_JNLRECS;
- poll_time = poll_immediate;
+ poll_time = REPL_POLL_NOWAIT; /* because we received XON and data ready for send */
repl_log(gtmsource_log_fp, TRUE, TRUE, "REPL_XON received\n");
- gtmsource_restart_heartbeat; /*Macro*/
+ heartbeat_stalled = FALSE;
REPL_DPRINT1("Restarting HEARTBEAT\n");
- xon_wait_logged = FALSE;
- /* In catchup mode, we do not receive as often as we would have in non catchup mode.
- * The consequence of this may be that we do not react to XOFF quickly enough,
- * making it worse for the replication pipe. We may end up with multiple XOFFs (with
- * intervening XONs) sitting on the replication pipe that are yet to be received
- * and processed by the source server. To avoid such a situation, on receipt of
- * an XON, we immediately force a check on the incoming pipe thereby draining
- * all pending XOFF/XONs, keeping the pipe smooth. Also, there is less likelihood
- * of missing a HEARTBEAT response (that is perhaps on the pipe) which may lead to
- * connection breakage although the pipe is alive and well.
- *
- * We will force a check regardless of mode (catchup or non catchup) as we may
- * be pounding the secondary even in non catchup mode
- */
- force_recv_check = TRUE;
break;
case REPL_BADTRANS:
case REPL_CMP2UNCMP:
@@ -1323,14 +1230,16 @@ int gtmsource_process(void)
SNPRINTF(err_string, SIZEOF(err_string),
"Error receiving Control message from Receiver. Error in recv : %s",
STRERROR(status));
- rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(err_string));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_STR(err_string));
}
} else if (EREPL_SELECT == repl_errno)
{
SNPRINTF(err_string, SIZEOF(err_string),
"Error receiving Control message from Receiver. Error in select : %s",
STRERROR(status));
- rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(err_string));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_STR(err_string));
}
}
if (GTMSOURCE_WAITING_FOR_XON == gtmsource_state)
@@ -1338,7 +1247,7 @@ int gtmsource_process(void)
if (!xon_wait_logged)
{
repl_log(gtmsource_log_fp, TRUE, TRUE, "Waiting to receive XON\n");
- gtmsource_stall_heartbeat; /* Macro */
+ heartbeat_stalled = TRUE;
REPL_DPRINT1("Stalling HEARTBEAT\n");
xon_wait_logged = TRUE;
}
@@ -1350,16 +1259,11 @@ int gtmsource_process(void)
}
continue;
}
- if (GTMSOURCE_SEARCHING_FOR_RESTART == gtmsource_state ||
- GTMSOURCE_WAITING_FOR_CONNECTION == gtmsource_state)
- {
- xon_wait_logged = FALSE;
+ if ((GTMSOURCE_SEARCHING_FOR_RESTART == gtmsource_state)
+ || (GTMSOURCE_WAITING_FOR_CONNECTION == gtmsource_state))
break;
- }
assert(gtmsource_state == GTMSOURCE_SENDING_JNLRECS);
- if (force_recv_check) /* we want to poll the incoming pipe for possible XOFF */
- continue;
- assert(pre_read_seqno == gtmsource_local->read_jnl_seqno);
+ pre_read_seqno = gtmsource_local->read_jnl_seqno;
grab_gtmsource_srv_latch(gtmsource_srv_latch, 2 * gd_header->n_regions * max_epoch_interval,
HANDLE_CONCUR_ONLINE_ROLLBACK);
if (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state)
@@ -1530,7 +1434,7 @@ int gtmsource_process(void)
* server will communicate the appropriate sequence number as part of the histinfo
* exchange.
*/
- REPL_SEND_LOOP(gtmsource_sock_fd, send_msgp, send_tr_len, catchup, &poll_immediate)
+ REPL_SEND_LOOP(gtmsource_sock_fd, send_msgp, send_tr_len, REPL_POLL_WAIT)
{
gtmsource_poll_actions(FALSE);
if (GTMSOURCE_CHANGING_MODE == gtmsource_state)
@@ -1565,15 +1469,15 @@ int gtmsource_process(void)
{
SNPRINTF(err_string, SIZEOF(err_string),
"Error sending DATA. Error in send : %s", STRERROR(status));
- rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2,
- RTS_ERROR_STRING(err_string));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_STR(err_string));
}
if (EREPL_SELECT == repl_errno)
{
SNPRINTF(err_string, SIZEOF(err_string),
"Error sending DATA. Error in select : %s", STRERROR(status));
- rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2,
- RTS_ERROR_STRING(err_string));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_STR(err_string));
}
}
if (intfilter_error)
@@ -1670,19 +1574,24 @@ int gtmsource_process(void)
* will take care of re-establishing the connection
*/
}
- poll_time = poll_immediate;
+ /* Because we sent data to the other side and there might be more to be sent across, don't
+ * wait for the receive pipe to be ready.
+ */
+ poll_time = REPL_POLL_NOWAIT;
} else /* data_len == 0 */
{ /* nothing to send */
gtmsource_flush_fh(post_read_seqno);
if (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state)
break; /* the outerloop will continue */
- poll_time = poll_wait;
- rel_quant(); /* give up processor and let other processes run */
+ /* Sleep for a while (as part of the next REPL_RECV_LOOP) to avoid spinning when there is no
+ * data to be sent
+ */
+ poll_time = GTMSOURCE_IDLE_POLL_WAIT;
}
} else /* else tot_tr_len < 0, error */
{
if (0 < data_len) /* Insufficient buffer space, increase the buffer space */
- gtmsource_alloc_msgbuff(data_len + REPL_MSG_HDRLEN);
+ gtmsource_alloc_msgbuff(data_len + REPL_MSG_HDRLEN, TRUE);
else
GTMASSERT; /* Major problems */
}
diff --git a/sr_unix/gtmsource_process_ops.c b/sr_unix/gtmsource_process_ops.c
index d3fe929..a679efa 100644
--- a/sr_unix/gtmsource_process_ops.c
+++ b/sr_unix/gtmsource_process_ops.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2006, 2012 Fidelity Information Services, Inc *
+ * Copyright 2006, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -17,6 +17,7 @@
#include "gtm_stdio.h" /* for FILE * in repl_comm.h */
#include "gtm_socket.h"
+#include "gtm_netdb.h"
#include "gtm_inet.h"
#include <sys/time.h>
#include <errno.h>
@@ -24,9 +25,6 @@
#include "gtm_unistd.h"
#include "gtm_stat.h"
#include "gtm_string.h"
-#ifdef VMS
-#include <descrip.h> /* Required for gtmsource.h */
-#endif
#include "gdsroot.h"
#include "gdsblk.h"
@@ -68,6 +66,20 @@
#include "gtm_zlib.h"
#include "replgbl.h"
#include "repl_inst_dump.h" /* for "repl_dump_histinfo" prototype */
+#include "gtmdbgflags.h"
+
+#define SEND_REPL_LOGFILE_INFO(LOGFILE, LOGFILE_MSG) \
+{ \
+ int len; \
+ \
+ len = repl_logfileinfo_get(LOGFILE, &LOGFILE_MSG, FALSE, gtmsource_log_fp); \
+ REPL_SEND_LOOP(gtmsource_sock_fd, &LOGFILE_MSG, len, REPL_POLL_NOWAIT) \
+ { \
+ gtmsource_poll_actions(FALSE); \
+ if (GTMSOURCE_CHANGING_MODE == gtmsource_state) \
+ return SS_NORMAL; \
+ } \
+}
GBLREF boolean_t gtmsource_logstats;
GBLREF boolean_t gtmsource_pool2file_transition;
@@ -91,11 +103,11 @@ GBLREF repl_msg_ptr_t gtmsource_cmpmsgp;
GBLREF repl_msg_ptr_t gtmsource_msgp;
GBLREF seq_num gtmsource_save_read_jnl_seqno;
GBLREF seq_num seq_num_zero;
-GBLREF struct timeval gtmsource_poll_wait, gtmsource_poll_immediate;
GBLREF uchar_ptr_t repl_filter_buff;
GBLREF uint4 process_id;
GBLREF unsigned char *gtmsource_tcombuffp;
GBLREF unsigned char *gtmsource_tcombuff_start;
+GBLREF gtmsource_options_t gtmsource_options;
error_def(ERR_REPL2OLD);
error_def(ERR_REPLCOMM);
@@ -111,18 +123,7 @@ error_def(ERR_TEXT);
static unsigned char *tcombuff, *msgbuff, *cmpmsgbuff, *filterbuff;
-void gtmsource_init_sec_addr(struct sockaddr_in *secondary_addr)
-{
- gtmsource_local_ptr_t gtmsource_local;
-
- gtmsource_local = jnlpool.gtmsource_local;
- memset((char *)secondary_addr, 0, SIZEOF(*secondary_addr));
- (*secondary_addr).sin_family = AF_INET;
- (*secondary_addr).sin_addr.s_addr = gtmsource_local->secondary_inet_addr;
- (*secondary_addr).sin_port = htons(gtmsource_local->secondary_port);
-}
-
-int gtmsource_est_conn(struct sockaddr_in *secondary_addr)
+int gtmsource_est_conn()
{
int connection_attempts, alert_attempts, save_errno, status;
char print_msg[1024], msg_str[1024], *errmsg;
@@ -130,6 +131,8 @@ int gtmsource_est_conn(struct sockaddr_in *secondary_addr)
int send_buffsize, recv_buffsize, tcp_s_bufsize;
int logging_period, logging_interval; /* logging period = soft_tries_period*logging_interval */
int logging_attempts;
+ sockaddr_ptr secondary_sa;
+ int secondary_addrlen;
gtmsource_local = jnlpool.gtmsource_local;
assert(remote_side == >msource_local->remote_side);
@@ -137,17 +140,19 @@ int gtmsource_est_conn(struct sockaddr_in *secondary_addr)
remote_side->endianness_known = FALSE;
/* Connect to the secondary - use hard tries, soft tries ... */
connection_attempts = 0;
- gtmsource_comm_init();
+ gtmsource_comm_init(); /* set up gtmsource_local.secondary_ai */
repl_log(gtmsource_log_fp, TRUE, TRUE, "Connect hard tries count = %d, Connect hard tries period = %d\n",
gtmsource_local->connect_parms[GTMSOURCE_CONN_HARD_TRIES_COUNT],
gtmsource_local->connect_parms[GTMSOURCE_CONN_HARD_TRIES_PERIOD]);
do
{
- status = gtm_connect(gtmsource_sock_fd, (struct sockaddr *)secondary_addr, SIZEOF(*secondary_addr));
+ secondary_sa = (sockaddr_ptr)(>msource_local->secondary_inet_addr);
+ secondary_addrlen = gtmsource_local->secondary_addrlen;
+ status = gtm_connect(gtmsource_sock_fd, secondary_sa, secondary_addrlen);
if (0 == status)
break;
repl_log(gtmsource_log_fp, FALSE, FALSE, "%d hard connection attempt failed : %s\n", connection_attempts + 1,
- STRERROR(ERRNO));
+ STRERROR(errno));
repl_close(>msource_sock_fd);
if (REPL_MAX_CONN_HARD_TRIES_PERIOD > jnlpool.gtmsource_local->connect_parms[GTMSOURCE_CONN_HARD_TRIES_PERIOD])
SHORT_SLEEP(gtmsource_local->connect_parms[GTMSOURCE_CONN_HARD_TRIES_PERIOD])
@@ -176,14 +181,16 @@ int gtmsource_est_conn(struct sockaddr_in *secondary_addr)
connection_attempts = 0;
do
{
- status = gtm_connect(gtmsource_sock_fd, (struct sockaddr *)secondary_addr, SIZEOF(*secondary_addr));
+ secondary_sa = (sockaddr_ptr)(>msource_local->secondary_inet_addr);
+ secondary_addrlen = gtmsource_local->secondary_addrlen;
+ status = gtm_connect(gtmsource_sock_fd, secondary_sa, secondary_addrlen);
if (0 == status)
break;
repl_close(>msource_sock_fd);
if (0 == (connection_attempts + 1) % logging_interval)
{
repl_log(gtmsource_log_fp, TRUE, TRUE, "%d soft connection attempt failed : %s\n",
- connection_attempts + 1, STRERROR(ERRNO));
+ connection_attempts + 1, STRERROR(errno));
logging_attempts++;
}
LONG_SLEEP(gtmsource_local->connect_parms[GTMSOURCE_CONN_SOFT_TRIES_PERIOD]);
@@ -215,7 +222,7 @@ int gtmsource_est_conn(struct sockaddr_in *secondary_addr)
if (0 != (status = get_send_sock_buff_size(gtmsource_sock_fd, &send_buffsize)))
{
SNPRINTF(msg_str, SIZEOF(msg_str), "Error getting socket send buffsize : %s", STRERROR(status));
- rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(msg_str));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(msg_str));
}
if (send_buffsize < GTMSOURCE_TCP_SEND_BUFSIZE)
{
@@ -229,19 +236,20 @@ int gtmsource_est_conn(struct sockaddr_in *secondary_addr)
SNPRINTF(msg_str, SIZEOF(msg_str), "Could not set TCP send buffer size in range [%d, %d], last "
"known error : %s", GTMSOURCE_MIN_TCP_SEND_BUFSIZE, GTMSOURCE_TCP_SEND_BUFSIZE,
STRERROR(status));
- rts_error(VARLSTCNT(6) MAKE_MSG_INFO(ERR_REPLCOMM), 0, ERR_TEXT, 2, LEN_AND_STR(msg_str));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) MAKE_MSG_INFO(ERR_REPLCOMM), 0, ERR_TEXT, 2, LEN_AND_STR(msg_str));
}
}
if (0 != (status = get_send_sock_buff_size(gtmsource_sock_fd, &repl_max_send_buffsize))) /* may have changed */
{
SNPRINTF(msg_str, SIZEOF(msg_str), "Error getting socket send buffsize : %s", STRERROR(status));
- rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(msg_str));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(msg_str));
}
if (0 != (status = get_recv_sock_buff_size(gtmsource_sock_fd, &recv_buffsize)))
{
errmsg = STRERROR(status);
- rts_error(VARLSTCNT(10) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_LIT("Error getting socket recv buffsize"),
- ERR_TEXT, 2, RTS_ERROR_STRING(errmsg));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_LIT("Error getting socket recv buffsize"),
+ ERR_TEXT, 2, LEN_AND_STR(errmsg));
}
if (recv_buffsize < GTMSOURCE_TCP_RECV_BUFSIZE)
{
@@ -251,14 +259,15 @@ int gtmsource_est_conn(struct sockaddr_in *secondary_addr)
{
SNPRINTF(msg_str, SIZEOF(msg_str), "Could not set TCP recv buffer size to %d : %s",
GTMSOURCE_MIN_TCP_RECV_BUFSIZE, STRERROR(status));
- rts_error(VARLSTCNT(6) MAKE_MSG_INFO(ERR_REPLCOMM), 0, ERR_TEXT, 2, LEN_AND_STR(msg_str));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) MAKE_MSG_INFO(ERR_REPLCOMM), 0, ERR_TEXT, 2,
+ LEN_AND_STR(msg_str));
}
}
}
if (0 != (status = get_recv_sock_buff_size(gtmsource_sock_fd, &repl_max_recv_buffsize))) /* may have changed */
{
SNPRINTF(msg_str, SIZEOF(msg_str), "Error getting socket recv buffsize : %s", STRERROR(status));
- rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(msg_str));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(msg_str));
}
repl_log(gtmsource_log_fp, TRUE, TRUE, "Connected to secondary, using TCP send buffer size %d receive buffer size %d\n",
repl_max_send_buffsize, repl_max_recv_buffsize);
@@ -328,9 +337,8 @@ void gtmsource_free_filter_buff(void)
}
}
-int gtmsource_alloc_msgbuff(int maxbuffsize)
-{ /* Allocate message buffer */
-
+int gtmsource_alloc_msgbuff(int maxbuffsize, boolean_t discard_oldbuff)
+{ /* Allocate message buffer */
repl_msg_ptr_t oldmsgp;
unsigned char *free_msgp;
@@ -346,7 +354,8 @@ int gtmsource_alloc_msgbuff(int maxbuffsize)
if (NULL != free_msgp)
{ /* Copy existing data */
assert(NULL != oldmsgp);
- memcpy((unsigned char *)gtmsource_msgp, (unsigned char *)oldmsgp, gtmsource_msgbufsiz);
+ if (!discard_oldbuff)
+ memcpy((unsigned char *)gtmsource_msgp, (unsigned char *)oldmsgp, gtmsource_msgbufsiz);
free(free_msgp);
}
gtmsource_msgbufsiz = maxbuffsize;
@@ -389,196 +398,250 @@ void gtmsource_free_msgbuff(void)
/* Receive starting jnl_seqno for (re)starting transmission */
int gtmsource_recv_restart(seq_num *recvd_jnl_seqno, int *msg_type, int *start_flags)
{
- boolean_t msg_is_cross_endian;
- fd_set input_fds;
- repl_msg_t msg;
- unsigned char *msg_ptr; /* needed for REPL_{SEND,RECV}_LOOP */
- int tosend_len, sent_len, sent_this_iter; /* needed for REPL_SEND_LOOP */
- int torecv_len, recvd_len, recvd_this_iter; /* needed for REPL_RECV_LOOP */
- int status; /* needed for REPL_{SEND,RECV}_LOOP */
- unsigned char seq_num_str[32], *seq_num_ptr;
- repl_msg_t xoff_ack;
+ boolean_t msg_is_cross_endian, log_waitmsg;
+ fd_set input_fds;
+ repl_msg_t msg;
+ repl_logfile_info_msg_t logfile_msg;
+ unsigned char *msg_ptr; /* needed for REPL_{SEND,RECV}_LOOP */
+ int tosend_len, sent_len, sent_this_iter; /* needed for REPL_SEND_LOOP */
+ int torecv_len, recvd_len, recvd_this_iter; /* needed for REPL_RECV_LOOP */
+ int status; /* needed for REPL_{SEND,RECV}_LOOP */
+ uint4 remaining_len, len;
+ unsigned char seq_num_str[32], *seq_num_ptr, *buffp;
+ repl_msg_t xoff_ack;
# ifdef DEBUG
- boolean_t remote_side_endianness_known;
+ boolean_t remote_side_endianness_known;
# endif
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
status = SS_NORMAL;
assert(remote_side == &jnlpool.gtmsource_local->remote_side);
- for ( ; SS_NORMAL == status; )
+ DEBUG_ONLY(*msg_type = -1);
+ for (log_waitmsg = TRUE; SS_NORMAL == status; )
{
- repl_log(gtmsource_log_fp, TRUE, TRUE, "Waiting for REPL_START_JNL_SEQNO or REPL_FETCH_RESYNC message\n");
- REPL_RECV_LOOP(gtmsource_sock_fd, &msg, MIN_REPL_MSGLEN, FALSE, >msource_poll_wait)
+ if (log_waitmsg)
+ repl_log(gtmsource_log_fp, TRUE, TRUE, "Waiting for REPL_START_JNL_SEQNO or REPL_FETCH_RESYNC message\n");
+ REPL_RECV_LOOP(gtmsource_sock_fd, &msg, MIN_REPL_MSGLEN, REPL_POLL_WAIT)
{
gtmsource_poll_actions(FALSE);
if (GTMSOURCE_CHANGING_MODE == gtmsource_state)
return (SS_NORMAL);
}
DEBUG_ONLY(remote_side_endianness_known = remote_side->endianness_known);
- if (SS_NORMAL == status)
- { /* If endianness of other side is not yet known, determine that now by seeing if the msg.len is
- * greater than expected. If it is, convert it and see if it is now what we expect. If it is,
- * then the other system is of opposite endianness. Note: We would normally use msg.type since
- * it is effectively an enum and we control by adding new messages. But, REPL_START_JNL_SEQNO
- * is lucky number zero which means it is identical on systems of either endianness.
- *
- * If endianness of other side is not yet known, determine that from the message length as we
- * expect it to be MIN_REPL_MSGLEN. There is one exception though. If a pre-V55000 receiver sends
- * a REPL_XOFF_ACK_ME message, it could send it in the receiver's native-endian or cross-endian
- * format (depending on how its global variable "src_node_same_endianness" is initialized). This
- * bug in the receiver server logic is fixed V55000 onwards (proto_ver is REPL_PROTO_VER_SUPPLEMENTARY).
- * Therefore, in this case, we cannot use the endianness of the REPL_XOFF_ACK_ME message to determine
- * the endianness of the connection. In this case, wait for the next non-REPL_XOFF_ACK_ME message
- * to determine the connection endianness. Handle this exception case correctly.
- *
- * If on the other hand, we know the endianness of the other side, we still cannot guarantee which
- * endianness a REPL_XOFF_ACK_ME message is sent in (in pre-V55000 versions for example in V53004A where
- * it is sent in receiver native endian format whereas in V54002B it is sent in source native
- * endian format). So better be safe on the source side and handle those cases like we did when
- * we did not know the endianness of the remote side.
- *
- * The below check works as all messages we expect at this point have a fixed length of MIN_REPL_MSGLEN.
+ if (SS_NORMAL != status)
+ break;
+ if (REPL_LOGFILE_INFO == msg.type) /* No need to endian convert as the receiver converts this to our native fmt */
+ { /* We received a REPL_START_JNL_SEQNO/REPL_FETCH_RESYNC and coming through the loop again
+ * to receive REPL_LOGFILE_INFO. At this point, we should have already established the endianness
+ * of the remote side and even if the remote side is of different endianness, we are going to interpret the
+ * message without endian conversion because the Receiver Server, from REPL_PROTO_VER_SUPPLEMENTARY
+ * onwards, always endian converts the message intended for the Source Server
*/
- msg_is_cross_endian = (((unsigned)MIN_REPL_MSGLEN < (unsigned)msg.len)
- && ((unsigned)MIN_REPL_MSGLEN == GTM_BYTESWAP_32((unsigned)msg.len)));
- if (msg_is_cross_endian)
+ assert(remote_side->endianness_known);
+ assert(REPL_PROTO_VER_REMOTE_LOGPATH <= remote_side->proto_ver);
+ assert(-1 != *msg_type);
+ buffp = (unsigned char *)&logfile_msg;
+ /* First copy what we already received */
+ memcpy(buffp, &msg, MIN_REPL_MSGLEN);
+ assert((logfile_msg.fullpath_len > MIN_REPL_MSGLEN)
+ && logfile_msg.fullpath_len < REPL_LOGFILE_PATH_MAX);
+ /* Now receive the rest of the message */
+ buffp += MIN_REPL_MSGLEN;
+ remaining_len = msg.len - MIN_REPL_MSGLEN;
+ REPL_RECV_LOOP(gtmsource_sock_fd, buffp, remaining_len, REPL_POLL_WAIT)
{
- msg.type = GTM_BYTESWAP_32(msg.type);
- msg.len = GTM_BYTESWAP_32(msg.len);
+ gtmsource_poll_actions(FALSE);
+ if (GTMSOURCE_CHANGING_MODE == gtmsource_state)
+ return SS_NORMAL;
}
- assert(msg.type == REPL_START_JNL_SEQNO || msg.type == REPL_FETCH_RESYNC || msg.type == REPL_XOFF_ACK_ME);
- assert(MIN_REPL_MSGLEN == msg.len);
- /* If we dont yet know the endianness of the other side and the input message is not a REPL_XOFF_ACK_ME
- * we can decide the endianness of the receiver side by the endianness of the input message.
- * REPL_XOFF_ACK_ME is an exception due to its handling by pre-V5500 versions (described in comments above).
- */
- if (!remote_side->endianness_known && (REPL_XOFF_ACK_ME != msg.type))
+ if (SS_NORMAL != status)
+ return status;
+ assert(REPL_PROTO_VER_REMOTE_LOGPATH <= logfile_msg.proto_ver);
+ assert(logfile_msg.proto_ver == remote_side->proto_ver);
+ assert('\0' == logfile_msg.fullpath[logfile_msg.fullpath_len - 1]);
+ if (REPL_FETCH_RESYNC == *msg_type)
{
- remote_side->endianness_known = TRUE;
- remote_side->cross_endian = msg_is_cross_endian;
- if (remote_side->cross_endian)
- repl_log(gtmsource_log_fp, TRUE, TRUE, "Source and Receiver sides have opposite "
- "endianness\n");
- else
- repl_log(gtmsource_log_fp, TRUE, TRUE, "Source and Receiver sides have same endianness\n");
+ repl_log(gtmsource_log_fp, TRUE, TRUE, "Remote side rollback path is %s; Rollback PID = %d\n",
+ logfile_msg.fullpath, logfile_msg.pid);
}
- /* We only expect REPL_START_JNL_SEQNO and REPL_XOFF_ACK_ME messages to be sent once the endianness of
- * the remote side has been determined. We dont expect the REPL_FETCH_RESYNC message to be ever sent in
- * the middle of a handshake (i.e. after the remote side endianness has been determined). Assert that.
- * The logic that sets "msg_is_cross_endian" relies on this. If this assert fails, the logic has to change.
- */
- assert((REPL_FETCH_RESYNC != msg.type) || !remote_side_endianness_known);
- *msg_type = msg.type;
- *start_flags = START_FLAG_NONE;
- memcpy((uchar_ptr_t)recvd_jnl_seqno, (uchar_ptr_t)&msg.msg[0], SIZEOF(seq_num));
- if (REPL_START_JNL_SEQNO == msg.type)
+ else
{
- if (msg_is_cross_endian)
- *recvd_jnl_seqno = GTM_BYTESWAP_64(*recvd_jnl_seqno);
- repl_log(gtmsource_log_fp, TRUE, TRUE, "Received REPL_START_JNL_SEQNO message with SEQNO "
- "%llu [0x%llx]\n", INT8_PRINT(*recvd_jnl_seqno), INT8_PRINT(*recvd_jnl_seqno));
- if (msg_is_cross_endian)
- ((repl_start_msg_ptr_t)&msg)->start_flags =
- GTM_BYTESWAP_32(((repl_start_msg_ptr_t)&msg)->start_flags);
- *start_flags = ((repl_start_msg_ptr_t)&msg)->start_flags;
- assert(!msg_is_cross_endian || (NODE_ENDIANNESS != ((repl_start_msg_ptr_t)&msg)->node_endianness));
- if (*start_flags & START_FLAG_STOPSRCFILTER)
- {
- repl_log(gtmsource_log_fp, TRUE, TRUE,
- "Start JNL_SEQNO msg tagged with STOP SOURCE FILTER\n");
- if (gtmsource_filter & EXTERNAL_FILTER)
- {
- repl_stop_filter();
- gtmsource_filter &= ~EXTERNAL_FILTER;
- } else
- repl_log(gtmsource_log_fp, TRUE, TRUE,
- "Filter is not active, ignoring STOP SOURCE FILTER msg\n");
- *msg_type = REPL_START_JNL_SEQNO;
- }
- /* Determine the protocol version of the receiver side. That information is encoded in the
- * "proto_ver" field of the message from V51 onwards but to differentiate V50 vs V51 we need
- * to check if the START_FLAG_VERSION_INFO bit is set in start_flags. If not the protocol is V50.
- * V51 implies support for multi-site while V50 implies dual-site configuration only.
- */
- if (*start_flags & START_FLAG_VERSION_INFO)
+ assert(REPL_START_JNL_SEQNO == *msg_type);
+ repl_log(gtmsource_log_fp, TRUE, TRUE, "Remote side receiver log file path is %s; "
+ "Receiver Server PID = %d\n", logfile_msg.fullpath, logfile_msg.pid);
+ }
+ /* Now that we've received REPL_LOGFILE_INFO message from the other side, handshake is complete. */
+ return SS_NORMAL;
+ }
+ /* If endianness of other side is not yet known, determine that now by seeing if the msg.len is
+ * greater than expected. If it is, convert it and see if it is now what we expect. If it is,
+ * then the other system is of opposite endianness. Note: We would normally use msg.type since
+ * it is effectively an enum and we control by adding new messages. But, REPL_START_JNL_SEQNO
+ * is lucky number zero which means it is identical on systems of either endianness.
+ *
+ * If endianness of other side is not yet known, determine that from the message length as we
+ * expect it to be MIN_REPL_MSGLEN. There is one exception though. If a pre-V55000 receiver sends
+ * a REPL_XOFF_ACK_ME message, it could send it in the receiver's native-endian or cross-endian
+ * format (depending on how its global variable "src_node_same_endianness" is initialized). This
+ * bug in the receiver server logic is fixed V55000 onwards (proto_ver is REPL_PROTO_VER_SUPPLEMENTARY).
+ * Therefore, in this case, we cannot use the endianness of the REPL_XOFF_ACK_ME message to determine
+ * the endianness of the connection. In this case, wait for the next non-REPL_XOFF_ACK_ME message
+ * to determine the connection endianness. Handle this exception case correctly.
+ *
+ * If on the other hand, we know the endianness of the other side, we still cannot guarantee which
+ * endianness a REPL_XOFF_ACK_ME message is sent in (in pre-V55000 versions for example in V53004A where
+ * it is sent in receiver native endian format whereas in V54002B it is sent in source native
+ * endian format). So better be safe on the source side and handle those cases like we did when
+ * we did not know the endianness of the remote side.
+ *
+ * The below check works as all messages we expect at this point have a fixed length of MIN_REPL_MSGLEN.
+ */
+ msg_is_cross_endian = (((unsigned)MIN_REPL_MSGLEN < (unsigned)msg.len)
+ && ((unsigned)MIN_REPL_MSGLEN == GTM_BYTESWAP_32((unsigned)msg.len)));
+ if (msg_is_cross_endian)
+ {
+ msg.type = GTM_BYTESWAP_32(msg.type);
+ msg.len = GTM_BYTESWAP_32(msg.len);
+ }
+ assert(msg.type == REPL_START_JNL_SEQNO || msg.type == REPL_FETCH_RESYNC || msg.type == REPL_XOFF_ACK_ME);
+ assert(MIN_REPL_MSGLEN == msg.len);
+ /* If we dont yet know the endianness of the other side and the input message is not a REPL_XOFF_ACK_ME
+ * we can decide the endianness of the receiver side by the endianness of the input message.
+ * REPL_XOFF_ACK_ME is an exception due to its handling by pre-V5500 versions (described in comments above).
+ */
+ if (!remote_side->endianness_known && (REPL_XOFF_ACK_ME != msg.type))
+ {
+ remote_side->endianness_known = TRUE;
+ remote_side->cross_endian = msg_is_cross_endian;
+ if (remote_side->cross_endian)
+ repl_log(gtmsource_log_fp, TRUE, TRUE, "Source and Receiver sides have opposite "
+ "endianness\n");
+ else
+ repl_log(gtmsource_log_fp, TRUE, TRUE, "Source and Receiver sides have same endianness\n");
+ }
+ /* We only expect REPL_START_JNL_SEQNO, REPL_LOGFILE_INFO and REPL_XOFF_ACK_ME messages to be sent once the
+ * endianness of the remote side has been determined. We dont expect the REPL_FETCH_RESYNC message to be
+ * ever sent in the middle of a handshake (i.e. after the remote side endianness has been determined).
+ * Assert that. The logic that sets "msg_is_cross_endian" relies on this. If this assert fails, the logic
+ * has to change.
+ */
+ assert((REPL_FETCH_RESYNC != msg.type) || !remote_side_endianness_known);
+ *msg_type = msg.type;
+ *start_flags = START_FLAG_NONE;
+ memcpy((uchar_ptr_t)recvd_jnl_seqno, (uchar_ptr_t)&msg.msg[0], SIZEOF(seq_num));
+ if (REPL_START_JNL_SEQNO == msg.type)
+ {
+ if (msg_is_cross_endian)
+ *recvd_jnl_seqno = GTM_BYTESWAP_64(*recvd_jnl_seqno);
+ repl_log(gtmsource_log_fp, TRUE, TRUE, "Received REPL_START_JNL_SEQNO message with SEQNO "
+ "%llu [0x%llx]\n", INT8_PRINT(*recvd_jnl_seqno), INT8_PRINT(*recvd_jnl_seqno));
+ if (msg_is_cross_endian)
+ ((repl_start_msg_ptr_t)&msg)->start_flags =
+ GTM_BYTESWAP_32(((repl_start_msg_ptr_t)&msg)->start_flags);
+ *start_flags = ((repl_start_msg_ptr_t)&msg)->start_flags;
+ assert(!msg_is_cross_endian || (NODE_ENDIANNESS != ((repl_start_msg_ptr_t)&msg)->node_endianness));
+ if (*start_flags & START_FLAG_STOPSRCFILTER)
+ {
+ repl_log(gtmsource_log_fp, TRUE, TRUE,
+ "Start JNL_SEQNO msg tagged with STOP SOURCE FILTER\n");
+ if (gtmsource_filter & EXTERNAL_FILTER)
{
- assert(REPL_PROTO_VER_DUALSITE != ((repl_start_msg_ptr_t)&msg)->proto_ver);
- remote_side->is_supplementary = ((repl_start_msg_ptr_t)&msg)->is_supplementary;
- remote_side->proto_ver = ((repl_start_msg_ptr_t)&msg)->proto_ver;
+ repl_stop_filter();
+ gtmsource_filter &= ~EXTERNAL_FILTER;
} else
- { /* Issue REPL2OLD error because receiver is dual-site */
- rts_error(VARLSTCNT(6) ERR_REPL2OLD, 4, LEN_AND_STR(UNKNOWN_INSTNAME),
- LEN_AND_STR(jnlpool.repl_inst_filehdr->inst_info.this_instname));
- }
- assert(*start_flags & START_FLAG_HASINFO); /* V4.2+ versions have jnl ver in the start msg */
- remote_side->jnl_ver = ((repl_start_msg_ptr_t)&msg)->jnl_ver;
- REPL_DPRINT3("Local jnl ver is octal %o, remote jnl ver is octal %o\n",
- this_side->jnl_ver, remote_side->jnl_ver);
- repl_check_jnlver_compat(!remote_side->cross_endian);
- assert(remote_side->jnl_ver > V15_JNL_VER || 0 == (*start_flags & START_FLAG_COLL_M));
- if (remote_side->jnl_ver <= V15_JNL_VER)
- *start_flags &= ~START_FLAG_COLL_M; /* zap it for pro, just in case */
- remote_side->is_std_null_coll = (*start_flags & START_FLAG_COLL_M) ? TRUE : FALSE;
- assert((remote_side->jnl_ver >= V19_JNL_VER) || (0 == (*start_flags & START_FLAG_TRIGGER_SUPPORT)));
- if (remote_side->jnl_ver < V19_JNL_VER)
- *start_flags &= ~START_FLAG_TRIGGER_SUPPORT; /* zap it for pro, just in case */
- remote_side->trigger_supported = (*start_flags & START_FLAG_TRIGGER_SUPPORT) ? TRUE : FALSE;
+ repl_log(gtmsource_log_fp, TRUE, TRUE,
+ "Filter is not active, ignoring STOP SOURCE FILTER msg\n");
+ }
+ /* Determine the protocol version of the receiver side. That information is encoded in the
+ * "proto_ver" field of the message from V51 onwards but to differentiate V50 vs V51 we need
+ * to check if the START_FLAG_VERSION_INFO bit is set in start_flags. If not the protocol is V50.
+ * V51 implies support for multi-site while V50 implies dual-site configuration only.
+ */
+ if (*start_flags & START_FLAG_VERSION_INFO)
+ {
+ assert(REPL_PROTO_VER_DUALSITE != ((repl_start_msg_ptr_t)&msg)->proto_ver);
+ remote_side->is_supplementary = ((repl_start_msg_ptr_t)&msg)->is_supplementary;
+ remote_side->proto_ver = ((repl_start_msg_ptr_t)&msg)->proto_ver;
+ } else
+ { /* Issue REPL2OLD error because receiver is dual-site */
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPL2OLD, 4, LEN_AND_STR(UNKNOWN_INSTNAME),
+ LEN_AND_STR(jnlpool.repl_inst_filehdr->inst_info.this_instname));
+ }
+ assert(*start_flags & START_FLAG_HASINFO); /* V4.2+ versions have jnl ver in the start msg */
+ remote_side->jnl_ver = ((repl_start_msg_ptr_t)&msg)->jnl_ver;
+ REPL_DPRINT3("Local jnl ver is octal %o, remote jnl ver is octal %o\n",
+ this_side->jnl_ver, remote_side->jnl_ver);
+ repl_check_jnlver_compat(!remote_side->cross_endian);
+ assert(remote_side->jnl_ver > V15_JNL_VER || 0 == (*start_flags & START_FLAG_COLL_M));
+ if (remote_side->jnl_ver <= V15_JNL_VER)
+ *start_flags &= ~START_FLAG_COLL_M; /* zap it for pro, just in case */
+ remote_side->is_std_null_coll = (*start_flags & START_FLAG_COLL_M) ? TRUE : FALSE;
+ assert((remote_side->jnl_ver >= V19_JNL_VER) || (0 == (*start_flags & START_FLAG_TRIGGER_SUPPORT)));
+ if (remote_side->jnl_ver < V19_JNL_VER)
+ *start_flags &= ~START_FLAG_TRIGGER_SUPPORT; /* zap it for pro, just in case */
+ remote_side->trigger_supported = (*start_flags & START_FLAG_TRIGGER_SUPPORT) ? TRUE : FALSE;
# ifdef GTM_TRIGGER
- if (!remote_side->trigger_supported)
- repl_log(gtmsource_log_fp, TRUE, TRUE, "Warning : Secondary does not support GT.M "
- "database triggers. #t updates on primary will not be replicated\n");
+ if (!remote_side->trigger_supported)
+ repl_log(gtmsource_log_fp, TRUE, TRUE, "Warning : Secondary does not support GT.M "
+ "database triggers. #t updates on primary will not be replicated\n");
# endif
- /* remote_side->null_subs_xform is initialized later in function "gtmsource_process" */
- (TREF(replgbl)).trig_replic_warning_issued = FALSE;
- return (SS_NORMAL);
- } else if (REPL_FETCH_RESYNC == msg.type)
- { /* Determine the protocol version of the receiver side.
- * Take care to set the flush parameter in repl_log calls below to FALSE until at least the
- * first message gets sent back. This is so the fetchresync rollback on the other side does
- * not timeout before receiving a response. */
- remote_side->proto_ver = (RECAST(repl_resync_msg_ptr_t)&msg)->proto_ver;
- remote_side->is_supplementary = (RECAST(repl_resync_msg_ptr_t)&msg)->is_supplementary;
- /* The following fields dont need to be initialized since they are needed (for internal filter
- * transformations) only if we send journal records across. REPL_FETCH_RESYNC causes only
- * protocol messages to be exchanged (no journal records).
- * remote_side->jnl_ver = ...
- * remote_side->is_std_null_coll = ...
- * remote_side->trigger_supported = ...
- * remote_side->null_subs_xform = ...
- */
- if (msg_is_cross_endian)
- *recvd_jnl_seqno = GTM_BYTESWAP_64(*recvd_jnl_seqno);
- repl_log(gtmsource_log_fp, TRUE, FALSE, "Received REPL_FETCH_RESYNC message with SEQNO "
- "%llu [0x%llx]\n", INT8_PRINT(*recvd_jnl_seqno), INT8_PRINT(*recvd_jnl_seqno));
- return (SS_NORMAL);
- } else if (REPL_XOFF_ACK_ME == msg.type)
+ /* remote_side->null_subs_xform is initialized later in function "gtmsource_process" */
+ (TREF(replgbl)).trig_replic_warning_issued = FALSE;
+ if (REPL_PROTO_VER_REMOTE_LOGPATH > remote_side->proto_ver)
+ return SS_NORMAL; /* Remote side doesn't support REPL_LOGFILE_INFO message */
+ SEND_REPL_LOGFILE_INFO(jnlpool.gtmsource_local->log_file, logfile_msg);
+ log_waitmsg = FALSE;
+ } else if (REPL_FETCH_RESYNC == msg.type)
+ { /* Determine the protocol version of the receiver side.
+ * Take care to set the flush parameter in repl_log calls below to FALSE until at least the
+ * first message gets sent back. This is so the fetchresync rollback on the other side does
+ * not timeout before receiving a response. */
+ remote_side->proto_ver = (RECAST(repl_resync_msg_ptr_t)&msg)->proto_ver;
+ remote_side->is_supplementary = (RECAST(repl_resync_msg_ptr_t)&msg)->is_supplementary;
+ /* The following fields dont need to be initialized since they are needed (for internal filter
+ * transformations) only if we send journal records across. REPL_FETCH_RESYNC causes only
+ * protocol messages to be exchanged (no journal records).
+ * remote_side->jnl_ver = ...
+ * remote_side->is_std_null_coll = ...
+ * remote_side->trigger_supported = ...
+ * remote_side->null_subs_xform = ...
+ */
+ if (msg_is_cross_endian)
+ *recvd_jnl_seqno = GTM_BYTESWAP_64(*recvd_jnl_seqno);
+ repl_log(gtmsource_log_fp, TRUE, FALSE, "Received REPL_FETCH_RESYNC message with SEQNO "
+ "%llu [0x%llx]\n", INT8_PRINT(*recvd_jnl_seqno), INT8_PRINT(*recvd_jnl_seqno));
+ if (REPL_PROTO_VER_REMOTE_LOGPATH > remote_side->proto_ver)
+ return SS_NORMAL; /* Remote side doesn't support REPL_LOGFILE_INFO message */
+ SEND_REPL_LOGFILE_INFO(jnlpool.gtmsource_local->log_file, logfile_msg);
+ log_waitmsg = FALSE;
+ } else if (REPL_XOFF_ACK_ME == msg.type)
+ {
+ repl_log(gtmsource_log_fp, TRUE, FALSE, "Received REPL_XOFF_ACK_ME message. "
+ "Possible crash/shutdown of update process\n");
+ /* Send XOFF_ACK */
+ xoff_ack.type = REPL_XOFF_ACK;
+ if (msg_is_cross_endian)
+ *recvd_jnl_seqno = GTM_BYTESWAP_64(*recvd_jnl_seqno);
+ memcpy((uchar_ptr_t)&xoff_ack.msg[0], (uchar_ptr_t)recvd_jnl_seqno, SIZEOF(seq_num));
+ xoff_ack.len = MIN_REPL_MSGLEN;
+ repl_log(gtmsource_log_fp, TRUE, TRUE, "Sending REPL_XOFF_ACK message\n");
+ REPL_SEND_LOOP(gtmsource_sock_fd, &xoff_ack, xoff_ack.len, REPL_POLL_NOWAIT)
{
- repl_log(gtmsource_log_fp, TRUE, FALSE, "Received REPL_XOFF_ACK_ME message. "
- "Possible crash/shutdown of update process\n");
- /* Send XOFF_ACK */
- xoff_ack.type = REPL_XOFF_ACK;
- if (msg_is_cross_endian)
- *recvd_jnl_seqno = GTM_BYTESWAP_64(*recvd_jnl_seqno);
- memcpy((uchar_ptr_t)&xoff_ack.msg[0], (uchar_ptr_t)recvd_jnl_seqno, SIZEOF(seq_num));
- xoff_ack.len = MIN_REPL_MSGLEN;
- repl_log(gtmsource_log_fp, TRUE, TRUE, "Sending REPL_XOFF_ACK message\n");
- REPL_SEND_LOOP(gtmsource_sock_fd, &xoff_ack, xoff_ack.len, FALSE, >msource_poll_immediate)
- {
- gtmsource_poll_actions(FALSE);
- if (GTMSOURCE_CHANGING_MODE == gtmsource_state)
- return (SS_NORMAL);
- }
- } else
- { /* If unknown message is received, close connection. Caller will reopen the same. */
- repl_log(gtmsource_log_fp, TRUE, TRUE, "Received UNKNOWN message (type = %d). "
- "Closing connection.\n", msg.type);
- assert(FALSE);
- repl_close(>msource_sock_fd);
- SHORT_SLEEP(GTMSOURCE_WAIT_FOR_RECEIVER_CLOSE_CONN);
- gtmsource_state = jnlpool.gtmsource_local->gtmsource_state = GTMSOURCE_WAITING_FOR_CONNECTION;
- return (SS_NORMAL);
+ gtmsource_poll_actions(FALSE);
+ if (GTMSOURCE_CHANGING_MODE == gtmsource_state)
+ return (SS_NORMAL);
}
+ log_waitmsg = TRUE; /* Wait for REPL_START_JNL_SEQNO or REPL_FETCH_RESYNC */
+ } else
+ { /* If unknown message is received, close connection. Caller will reopen the same. */
+ repl_log(gtmsource_log_fp, TRUE, TRUE, "Received UNKNOWN message (type = %d). "
+ "Closing connection.\n", msg.type);
+ assert(FALSE);
+ repl_close(>msource_sock_fd);
+ SHORT_SLEEP(GTMSOURCE_WAIT_FOR_RECEIVER_CLOSE_CONN);
+ gtmsource_state = jnlpool.gtmsource_local->gtmsource_state = GTMSOURCE_WAITING_FOR_CONNECTION;
+ return (SS_NORMAL);
}
}
return (status);
@@ -604,9 +667,9 @@ int gtmsource_srch_restart(seq_num recvd_jnl_seqno, int recvd_start_flags)
if (recvd_jnl_seqno > cur_read_jnl_seqno)
{ /* The secondary is requesting a seqno higher than what we last remember having sent but yet it is in sync with us
* upto seqno "recvd_jnl_seqno" as otherwise the caller would have determined it is out of sync and not even call
- * us. To illustrate an example of how this could happen, consider an INSTA->INSTB replication and INSTA->INSTB
- * replication going on. Lets say INSTA's journal sequence number is at 100. INSTB is at 60 and INSTB is at 30.
- * This means, last sequence number sent by INSTA to INSTB is 60 and to INSTB is 30. Now, lets say INSTA is shutdown
+ * us. To illustrate an example of how this could happen, consider an INSTA->INSTB replication and INSTA->INSTC
+ * replication going on. Lets say INSTA's journal sequence number is at 100. INSTB is at 60 and INSTC is at 30.
+ * This means, last sequence number sent by INSTA to INSTB is 60 and to INSTC is 30. Now, lets say INSTA is shutdown
* and INSTB comes up as the primary to INSTC and starts replicating the 30 updates thereby bringing both INSTB and
* INSTC sequence number to 60. Now, if INSTA comes backup again as primary against INSTC, we will have a case where
* gtmsource_local->read_jnl_seqno as 30, but recvd_jnl_seqno as 60. This means that we are going to bump
@@ -618,7 +681,7 @@ int gtmsource_srch_restart(seq_num recvd_jnl_seqno, int recvd_start_flags)
*/
if ((READ_FILE != gtmsource_local->read_state) || (recvd_jnl_seqno > gtmsource_save_read_jnl_seqno))
{
- grab_lock(jnlpool.jnlpool_dummy_reg, ASSERT_NO_ONLINE_ROLLBACK);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK);
gtmsource_local->read_state = READ_FILE;
gtmsource_save_read_jnl_seqno = jctl->jnl_seqno;
gtmsource_local->read_addr = jnlpool.jnlpool_ctl->write_addr;
@@ -790,13 +853,10 @@ int gtmsource_get_jnlrecs(uchar_ptr_t buff, int *data_len, int maxbufflen, boole
read_addr = gtmsource_local->read_addr;
assert(read_addr <= write_addr);
assert((0 != write_addr) || (read_jnl_seqno <= jctl->start_jnl_seqno));
-# ifdef GTMSOURCE_ALWAYS_READ_FILES
- gtmsource_local->read_state = READ_FILE;
-# endif
+ GTMDBGFLAGS_NOFREQ_ONLY(GTMSOURCE_FORCE_READ_FILE_MODE, gtmsource_local->read_state = READ_FILE);
switch(gtmsource_local->read_state)
{
case READ_POOL:
-# ifndef GTMSOURCE_ALWAYS_READ_FILES_STRESS
if (read_addr == write_addr)
{ /* Nothing to read. While reading pool, the comparison of read_addr against write_addr is
* the only reliable indicator if there are any transactions to be read. This is due to
@@ -817,8 +877,6 @@ int gtmsource_get_jnlrecs(uchar_ptr_t buff, int *data_len, int maxbufflen, boole
return (total_tr_len);
if (0 < *data_len)
return (-1);
-# endif /* for GTMSOURCE_ALWAYS_READ_FILES_STRESS, we let the source server switch back and forth between
- pool read and file read */
/* Overflow, switch to READ_FILE */
gtmsource_local->read_state = READ_FILE;
QWASSIGN(gtmsource_save_read_jnl_seqno, read_jnl_seqno);
@@ -903,7 +961,7 @@ void gtmsource_repl_send(repl_msg_ptr_t msg, char *msgtypestr, seq_num optional_
msgtypestr, optional_seqno, optional_seqno, optional_strm_num);
} else
repl_log(gtmsource_log_fp, TRUE, FALSE, "Sending %s message\n", msgtypestr);
- REPL_SEND_LOOP(gtmsource_sock_fd, msg, msg->len, FALSE, >msource_poll_immediate)
+ REPL_SEND_LOOP(gtmsource_sock_fd, msg, msg->len, REPL_POLL_NOWAIT)
{
gtmsource_poll_actions(FALSE);
if ((GTMSOURCE_CHANGING_MODE == gtmsource_state) || (GTMSOURCE_WAITING_FOR_CONNECTION == gtmsource_state))
@@ -925,13 +983,13 @@ void gtmsource_repl_send(repl_msg_ptr_t msg, char *msgtypestr, seq_num optional_
{
SNPRINTF(err_string, SIZEOF(err_string), "Error sending %s message. "
"Error in send : %s", msgtypestr, STRERROR(status));
- rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(err_string));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(err_string));
}
if (EREPL_SELECT == repl_errno)
{
SNPRINTF(err_string, SIZEOF(err_string), "Error sending %s message. "
"Error in select : %s", msgtypestr, STRERROR(status));
- rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(err_string));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(err_string));
}
}
}
@@ -971,7 +1029,7 @@ static boolean_t gtmsource_repl_recv(repl_msg_ptr_t msg, int4 msglen, int4 msgty
* code that passes a 3rd parameter > MIN_REPL_MSGLEN. All such usages need a check inside the body of the
* loop to account for a REPL_XOFF_ACK_ME and if so break.
*/
- REPL_RECV_LOOP(gtmsource_sock_fd, buff, bufflen, FALSE, >msource_poll_wait)
+ REPL_RECV_LOOP(gtmsource_sock_fd, buff, bufflen, REPL_POLL_WAIT)
{
gtmsource_poll_actions(TRUE);
if ((GTMSOURCE_CHANGING_MODE == gtmsource_state) || (GTMSOURCE_WAITING_FOR_CONNECTION == gtmsource_state))
@@ -1003,14 +1061,16 @@ static boolean_t gtmsource_repl_recv(repl_msg_ptr_t msg, int4 msglen, int4 msgty
SNPRINTF(err_string, SIZEOF(err_string),
"Error receiving %s message from Receiver. Error in recv : %s",
msgtypestr, STRERROR(status));
- rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(err_string));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_STR(err_string));
}
} else if (EREPL_SELECT == repl_errno)
{
SNPRINTF(err_string, SIZEOF(err_string),
"Error receiving %s message from Receiver. Error in select : %s",
msgtypestr, STRERROR(status));
- rts_error(VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, RTS_ERROR_STRING(err_string));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_STR(err_string));
}
}
assert(SS_NORMAL == status);
@@ -1226,7 +1286,7 @@ boolean_t gtmsource_get_instance_info(boolean_t *secondary_was_rootprimary, seq_
if (jnlpool.repl_inst_filehdr->is_supplementary)
{ /* Issue REPL2OLD error because this is a supplementary instance and remote side runs
* on a GT.M version that does not understand the supplementary protocol */
- rts_error(VARLSTCNT(6) ERR_REPL2OLD, 4, LEN_AND_STR(old_instinfo_msg.instname),
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPL2OLD, 4, LEN_AND_STR(old_instinfo_msg.instname),
LEN_AND_STR(jnlpool.repl_inst_filehdr->inst_info.this_instname));
}
/* Check if instance name in the REPL_OLD_INSTANCE_INFO message matches that in the source server command line */
@@ -1272,7 +1332,7 @@ boolean_t gtmsource_get_instance_info(boolean_t *secondary_was_rootprimary, seq_
{ /* Issue SECNOTSUPPLEMENTARY error because this is a supplementary primary and secondary
* is not a supplementary instance.
*/
- rts_error(VARLSTCNT(6) ERR_SECNOTSUPPLEMENTARY, 4,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_SECNOTSUPPLEMENTARY, 4,
LEN_AND_STR(jnlpool.repl_inst_filehdr->inst_info.this_instname),
LEN_AND_STR(instinfo_msg.instname));
}
@@ -1411,7 +1471,7 @@ boolean_t gtmsource_check_remote_strm_histinfo(seq_num seqno, boolean_t *rollbac
return FALSE; /* recv did not succeed */
assert(REPL_STRMINFO == strminfo_msg.type);
/* Verify that the list of known streams is identical on both sides */
- grab_lock(jnlpool.jnlpool_dummy_reg, HANDLE_CONCUR_ONLINE_ROLLBACK);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, HANDLE_CONCUR_ONLINE_ROLLBACK);
if (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state)
return FALSE; /* concurrent online rollback happened */
status = repl_inst_histinfo_find_seqno(seqno, INVALID_SUPPL_STRM, &local_histinfo);
@@ -1431,12 +1491,12 @@ boolean_t gtmsource_check_remote_strm_histinfo(seq_num seqno, boolean_t *rollbac
if (!lcl_strm_valid && remote_strm_valid)
{
assert(FALSE);
- rts_error(VARLSTCNT(3) ERR_STRMNUMMISMTCH1, 1, idx);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_STRMNUMMISMTCH1, 1, idx);
}
else if (lcl_strm_valid && !remote_strm_valid)
{
assert(FALSE);
- rts_error(VARLSTCNT(3) ERR_STRMNUMMISMTCH2, 1, idx);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_STRMNUMMISMTCH2, 1, idx);
}
}
/* Now that we know both sides have the exact set of known streams, verify history record for each stream matches */
@@ -1467,7 +1527,7 @@ boolean_t gtmsource_check_remote_strm_histinfo(seq_num seqno, boolean_t *rollbac
return FALSE; /* recv did not succeed */
assert(REPL_HISTINFO == histinfo_msg.type);
/* Find corresponding history record on LOCAL side */
- grab_lock(jnlpool.jnlpool_dummy_reg, HANDLE_CONCUR_ONLINE_ROLLBACK);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, HANDLE_CONCUR_ONLINE_ROLLBACK);
if (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state)
return FALSE; /* concurrent online rollback happened */
status = repl_inst_histinfo_get(lcl_histinfo_num, &local_histinfo);
@@ -1501,7 +1561,7 @@ void gtmsource_histinfo_get(int4 index, repl_histinfo *histinfo)
{
assert(ERR_REPLINSTNOHIST == status); /* currently the only error returned by "repl_inst_histinfo_get" */
SPRINTF(histdetail, "record number %d [0x%x]", index, index);
- gtm_putmsg(VARLSTCNT(6) ERR_REPLINSTNOHIST, 4, LEN_AND_STR(histdetail), LEN_AND_STR(udi->fn));
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLINSTNOHIST, 4, LEN_AND_STR(histdetail), LEN_AND_STR(udi->fn));
/* Send this error status to the receiver server before closing the connection. This way the receiver
* will know to shut down rather than loop back trying to reconnect. This avoids an infinite loop of
* connection open and closes between the source server and receiver server.
@@ -1609,7 +1669,7 @@ seq_num gtmsource_find_resync_seqno(repl_histinfo *local_histinfo, repl_histinfo
{ /* Need to get the previous histinfo record on the primary */
local_histinfo_num = local_histinfo->prev_histinfo_num;
assert(0 <= local_histinfo->histinfo_num);
- grab_lock(jnlpool.jnlpool_dummy_reg, HANDLE_CONCUR_ONLINE_ROLLBACK);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, HANDLE_CONCUR_ONLINE_ROLLBACK);
if (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state)
return MAX_SEQNO;
gtmsource_histinfo_get(local_histinfo_num, local_histinfo);
@@ -1666,7 +1726,7 @@ void gtmsource_send_new_histrec()
if ((GTMSOURCE_WAITING_FOR_CONNECTION == gtmsource_state) || (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state))
return; /* "gtmsource_set_next_histinfo_seqno" encountered REPLINSTNOHIST or concurrent online rollback occurred */
/*************** Read histinfo (to send) from instance file first ***************/
- grab_lock(jnlpool.jnlpool_dummy_reg, HANDLE_CONCUR_ONLINE_ROLLBACK);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, HANDLE_CONCUR_ONLINE_ROLLBACK);
if (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state)
return;
assert(1 <= gtmsource_local->next_histinfo_num);
@@ -1788,7 +1848,7 @@ void gtmsource_set_next_histinfo_seqno(boolean_t detect_new_histinfo)
csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs;
ASSERT_VALID_JNLPOOL(csa);
)
- grab_lock(jnlpool.jnlpool_dummy_reg, HANDLE_CONCUR_ONLINE_ROLLBACK);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, HANDLE_CONCUR_ONLINE_ROLLBACK);
if (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state)
return;
assert(NULL != jnlpool.repl_inst_filehdr); /* journal pool should be set up */
@@ -1821,7 +1881,7 @@ void gtmsource_set_next_histinfo_seqno(boolean_t detect_new_histinfo)
NON_GTM64_ONLY(SPRINTF(histdetail, "seqno [0x%llx]", read_seqno - 1));
GTM64_ONLY(SPRINTF(histdetail, "seqno [0x%lx]", read_seqno - 1));
udi = FILE_INFO(jnlpool.jnlpool_dummy_reg);
- gtm_putmsg(VARLSTCNT(6) ERR_REPLINSTNOHIST, 4,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLINSTNOHIST, 4,
LEN_AND_STR(histdetail), LEN_AND_STR(udi->fn));
/* Send error status to the receiver server before closing the connection. This way the
* receiver will know to shut down rather than loop back trying to reconnect. This avoids
diff --git a/sr_unix/gtmsource_readfiles.c b/sr_unix/gtmsource_readfiles.c
index eabd272..313d75f 100644
--- a/sr_unix/gtmsource_readfiles.c
+++ b/sr_unix/gtmsource_readfiles.c
@@ -58,6 +58,7 @@
#ifdef GTM_CRYPT
#include "gtmcrypt.h"
#endif
+#include "gtmdbgflags.h"
#define LOG_WAIT_FOR_JNL_RECS_PERIOD (10 * 1000) /* ms */
#define LOG_WAIT_FOR_JNLOPEN_PERIOD (10 * 1000) /* ms */
@@ -142,6 +143,11 @@ static int repl_read_file(repl_buff_t *rb)
assert(!fc->jfh->crash);
dskaddr = REAL_END_OF_DATA(fc);
}
+# ifdef DEBUG
+ b->save_readaddr = b->readaddr;
+ b->save_dskaddr = dskaddr;
+ b->save_buffremaining = b->buffremaining;
+# endif
/* Make sure we do not read beyond end of data in the journal file */
/* Note : This logic is always needed when journal file is pre-allocated.
* With no pre-allocation, this logic is needed only when repl_read_file is called from
@@ -166,11 +172,11 @@ static int repl_read_file(repl_buff_t *rb)
if ((off_t)-1 == lseek(fc->fd, (off_t)start_addr, SEEK_SET))
{
repl_errno = EREPL_JNLFILESEEK;
- return (ERRNO);
+ return (errno);
}
READ_FILE(fc->fd, b->base + REPL_BLKSIZE(rb) - b->buffremaining - (b->readaddr - start_addr),
end_addr - start_addr, nb);
- status = ERRNO;
+ status = errno;
if (nb < (b->readaddr - start_addr))
{ /* This case means that we didn't read enough bytes to get from the alignment point in the disk file
* to the start of the actual desired read (the offset we did the lseek to above). This can't happen
@@ -444,7 +450,7 @@ static int update_eof_addr(repl_ctl_element *ctl, int *eof_change)
F_READ_BLK_ALIGNED(fc->fd, 0, fc->jfh, REAL_JNL_HDR_LEN, status);
if (SS_NORMAL != status)
rts_error(VARLSTCNT(9) ERR_REPLFILIOERR, 2, ctl->jnl_fn_len, ctl->jnl_fn,
- ERR_TEXT, 2, RTS_ERROR_LITERAL("Error in reading jfh in update_eof_addr"), status);
+ ERR_TEXT, 2, LEN_AND_LIT("Error in reading jfh in update_eof_addr"), status);
REPL_DPRINT2("Update EOF : Jnl file hdr refreshed from file for %s\n", ctl->jnl_fn);
ctl->eof_addr_final = TRUE; /* No more updates to fc->eof_addr for this journal file */
}
@@ -762,7 +768,7 @@ static void increase_buffer(unsigned char **buff, int *buflen, int buffer_needed
REPL_DPRINT3("Buff space shortage. Attempting to increase buff space. Curr buff space %d. Attempt increase to atleast %d\n",
gtmsource_msgbufsiz, newbuffsize);
old_msgp = (unsigned char *)gtmsource_msgp;
- if ((alloc_status = gtmsource_alloc_msgbuff(newbuffsize)) != SS_NORMAL)
+ if ((alloc_status = gtmsource_alloc_msgbuff(newbuffsize, FALSE)) != SS_NORMAL)
{
rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
LEN_AND_LIT("Error extending buffer space while reading files. Malloc error"), alloc_status);
@@ -872,7 +878,7 @@ static int read_transaction(repl_ctl_element *ctl, unsigned char **buff, int *bu
{
assert(FALSE);
rts_error(VARLSTCNT(7) ERR_REPLBRKNTRANS, 1, &read_jnl_seqno,
- ERR_TEXT, 2, RTS_ERROR_LITERAL("Early EOF found"));
+ ERR_TEXT, 2, LEN_AND_LIT("Early EOF found"));
}
} else if (status == EREPL_JNLRECINCMPL)
{ /* Log warning message for every certain number of attempts. There might have been a crash and the file
@@ -1245,16 +1251,19 @@ static tr_search_state_t position_read(repl_ctl_element *ctl, seq_num read_seqno
lo_addr = ctl->min_seqno_dskaddr;
hi_addr = b->recaddr + b->reclen;
} else
- { /* trying to locate min, better to do linear search */
+ { /* trying to locate min, better to do linear search */
srch_func = do_linear_search;
lo_addr = ctl->min_seqno_dskaddr;
hi_addr = MAXUINT4;
- if (read_seqno == ctl->seqno) /* we are positioned where we want to be, no need for read */
- {
- assert(lo_addr == b->recaddr);
+ /* read_seqno == ctl->seqno == ctl->min_seqno is a special case. But, don't know how that can happen without
+ * lookback set and hence the assert below.
+ */
+ assert((read_seqno != ctl->seqno) || ctl->lookback);
+ if ((read_seqno == ctl->seqno) && (lo_addr == b->recaddr))
+ { /* we are positioned where we want to be, no need for a read */
assert(MIN_JNLREC_SIZE <= b->reclen);
- DEBUG_ONLY(jrec = (jnl_record *)b->recbuff;)
- DEBUG_ONLY(rectype = (enum jnl_record_type)jrec->prefix.jrec_type;)
+ DEBUG_ONLY(jrec = (jnl_record *)b->recbuff);
+ DEBUG_ONLY(rectype = (enum jnl_record_type)jrec->prefix.jrec_type);
assert(b->reclen == jrec->prefix.forwptr);
assert(IS_VALID_JNLREC(jrec, rb->fc->jfh));
assert(IS_REPLICATED(rectype));
@@ -1265,13 +1274,13 @@ static tr_search_state_t position_read(repl_ctl_element *ctl, seq_num read_seqno
}
}
}
-#if defined(GTMSOURCE_READFILES_LINEAR_SEARCH_TEST)
+# if defined(GTMSOURCE_READFILES_LINEAR_SEARCH_TEST)
srch_func = do_linear_search;
hi_addr = MAXUINT4;
-#elif defined(GTMSOURCE_READFILES_BINARY_SEARCH_TEST)
+# elif defined(GTMSOURCE_READFILES_BINARY_SEARCH_TEST)
srch_func = do_binary_search;
hi_addr = rb->fc->eof_addr;
-#endif
+# endif
REPL_DPRINT6("position_read: Using %s search to locate %llu in %s between %u and %u\n",
(srch_func == do_linear_search) ? "linear" : "binary", read_seqno, ctl->jnl_fn, lo_addr, hi_addr);
found = srch_func(ctl, lo_addr, hi_addr, read_seqno, &srch_status);
@@ -1776,9 +1785,7 @@ int gtmsource_readfiles(unsigned char *buff, int *data_len, int maxbufflen, bool
gtmsource_local->read_addr = read_addr;
assert(read_jnl_seqno <= gtmsource_local->next_histinfo_seqno);
gtmsource_local->read_jnl_seqno = read_jnl_seqno;
-#ifdef GTMSOURCE_ALWAYS_READ_FILES
- gtmsource_local->read_state = read_state = READ_FILE;
-#endif
+ GTMDBGFLAGS_NOFREQ_ONLY(GTMSOURCE_FORCE_READ_FILE_MODE, gtmsource_local->read_state = read_state = READ_FILE);
if (read_state == READ_POOL)
{
gtmsource_ctl_close(); /* no need to keep files open now that we are going to read from pool */
@@ -1937,7 +1944,7 @@ int gtmsource_update_zqgblmod_seqno_and_tn(seq_num resync_seqno)
assert(0 < max_zqgblmod_seqno);
assert(resync_seqno >= max_zqgblmod_seqno);
assert(!(FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs.now_crit));
- grab_lock(jnlpool.jnlpool_dummy_reg, HANDLE_CONCUR_ONLINE_ROLLBACK);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, HANDLE_CONCUR_ONLINE_ROLLBACK);
if (GTMSOURCE_HANDLE_ONLN_RLBK == gtmsource_state)
{
assert(process_id != jnlpool.gtmsource_local->gtmsource_srv_latch.u.parts.latch_pid);
diff --git a/sr_unix/gtmsource_rootprimary_init.c b/sr_unix/gtmsource_rootprimary_init.c
index 6a278e0..2d748dc 100644
--- a/sr_unix/gtmsource_rootprimary_init.c
+++ b/sr_unix/gtmsource_rootprimary_init.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2006, 2012 Fidelity Information Services, Inc *
+ * Copyright 2006, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -49,7 +49,7 @@ void gtmsource_rootprimary_init(seq_num start_seqno)
assert(!udi->s_addrs.hold_onto_crit || jgbl.onlnrlbk);
was_crit = udi->s_addrs.now_crit;
if (!was_crit)
- grab_lock(jnlpool.jnlpool_dummy_reg, ASSERT_NO_ONLINE_ROLLBACK);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK);
jnlpool.repl_inst_filehdr->root_primary_cycle++;
jnlpool.repl_inst_filehdr->was_rootprimary = TRUE;
assert(start_seqno >= jnlpool.jnlpool_ctl->start_jnl_seqno);
diff --git a/sr_unix/gtmsource_seqno_init.c b/sr_unix/gtmsource_seqno_init.c
index 0d6a4b4..3374b20 100644
--- a/sr_unix/gtmsource_seqno_init.c
+++ b/sr_unix/gtmsource_seqno_init.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2006, 2012 Fidelity Information Services, Inc *
+ * Copyright 2006, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -14,10 +14,6 @@
#include "gtm_string.h"
#include "gtm_inet.h"
#include "gtm_fcntl.h"
-#ifdef VMS
-#include <descrip.h> /* Required for gtmsource.h */
-#endif
-
#include "gdsroot.h"
#include "gtm_facility.h"
#include "fileinfo.h"
@@ -154,7 +150,7 @@ void gtmsource_seqno_init(boolean_t this_side_std_null_coll)
*/
DEBUG_ONLY(repl_csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs;)
assert(!repl_csa->hold_onto_crit); /* so it is ok to invoke "grab_lock" and "rel_lock" unconditionally */
- grab_lock(jnlpool.jnlpool_dummy_reg, ASSERT_NO_ONLINE_ROLLBACK);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK);
jnlpool_ctl->start_jnl_seqno = db_seqno;
jnlpool_ctl->jnl_seqno = db_seqno;
jnlpool_ctl->max_zqgblmod_seqno = zqgblmod_seqno;
diff --git a/sr_unix/gtmsource_showbacklog.c b/sr_unix/gtmsource_showbacklog.c
index 820eea6..01ff00b 100644
--- a/sr_unix/gtmsource_showbacklog.c
+++ b/sr_unix/gtmsource_showbacklog.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2006, 2010 Fidelity Information Services, Inc *
+ * Copyright 2006, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -47,6 +47,8 @@ GBLREF jnlpool_addrs jnlpool;
GBLREF gtmsource_options_t gtmsource_options;
GBLREF boolean_t holds_sem[NUM_SEM_SETS][NUM_SRC_SEMS];
+error_def(ERR_SRCSRVNOTEXIST);
+
int gtmsource_showbacklog(void)
{
seq_num seq_num, jnl_seqno, read_jnl_seqno;
@@ -55,8 +57,6 @@ int gtmsource_showbacklog(void)
boolean_t srv_alive;
uint4 gtmsource_pid;
- error_def(ERR_SRCSRVNOTEXIST);
-
assert(holds_sem[SOURCE][JNL_POOL_ACCESS_SEM]);
jnl_seqno = jnlpool.jnlpool_ctl->jnl_seqno;
if (NULL != jnlpool.gtmsource_local) /* Show backlog for a specific source server */
@@ -95,9 +95,10 @@ int gtmsource_showbacklog(void)
util_out_print("!@UQ : sequence number of last transaction sent by source server", TRUE, &seq_num);
srv_alive = (0 == gtmsource_pid) ? FALSE : is_proc_alive(gtmsource_pid, 0);
if (!srv_alive)
- gtm_putmsg(VARLSTCNT(4) MAKE_MSG_WARNING(ERR_SRCSRVNOTEXIST), 2,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) MAKE_MSG_WARNING(ERR_SRCSRVNOTEXIST), 2,
LEN_AND_STR(gtmsourcelocal_ptr->secondary_instname));
- else if (gtmsourcelocal_ptr->mode == GTMSOURCE_MODE_PASSIVE)
+ else if ((gtmsourcelocal_ptr->mode == GTMSOURCE_MODE_PASSIVE)
+ || (gtmsourcelocal_ptr->mode == GTMSOURCE_MODE_ACTIVE_REQUESTED))
util_out_print("WARNING - Source Server is in passive mode, transactions are not being replicated", TRUE);
if (NULL != jnlpool.gtmsource_local)
break;
diff --git a/sr_unix/gtmsource_shutdown.c b/sr_unix/gtmsource_shutdown.c
index 4100f88..822eb96 100644
--- a/sr_unix/gtmsource_shutdown.c
+++ b/sr_unix/gtmsource_shutdown.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2006, 2012 Fidelity Information Services, Inc *
+ * Copyright 2006, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -168,17 +168,8 @@ int gtmsource_shutdown(boolean_t auto_shutdown, int exit_status)
}
}
if (!all_dead)
- {
-# if defined(DEBUG)
- if (ANTICIPATORY_FREEZE_AVAILABLE && TREF(gtm_test_fake_enospc))
- /* Check every 5 seconds just in case ENOSPC test for instance freeze is active */
- LONG_SLEEP(5);
- else
- SHORT_SLEEP(GTMSOURCE_WAIT_FOR_SHUTDOWN);
-# else
- SHORT_SLEEP(GTMSOURCE_WAIT_FOR_SHUTDOWN);
-# endif
- } else
+ SHORT_SLEEP(GTMSOURCE_WAIT_FOR_SHUTDOWN)
+ else
break;
}
if (GTMSOURCE_MAX_SHUTDOWN_WAITLOOP < lcnt)
@@ -208,7 +199,6 @@ int gtmsource_shutdown(boolean_t auto_shutdown, int exit_status)
"the shutdown command.\n");
status = decr_sem(SOURCE, SRC_SERV_COUNT_SEM);
assert(0 == status);
- assert(FALSE);
return ABNORMAL_SHUTDOWN;
}
} else
diff --git a/sr_unix/gtmxc_types.h b/sr_unix/gtmxc_types.h
index 6db675c..985738d 100644
--- a/sr_unix/gtmxc_types.h
+++ b/sr_unix/gtmxc_types.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -57,7 +57,8 @@ typedef struct
gtm_string_t rtn_name;
void* handle;
} ci_name_descriptor;
-/* Define deprecated types for backward compatibility */
+
+/* Define deprecated types for backward compatibility. */
typedef gtm_status_t xc_status_t;
typedef gtm_int_t xc_int_t;
typedef gtm_uint_t xc_uint_t;
@@ -69,13 +70,30 @@ typedef gtm_char_t xc_char_t;
typedef gtm_string_t xc_string_t;
typedef gtm_pointertofunc_t xc_pointertofunc_t;
typedef gtm_fileid_ptr_t xc_fileid_ptr_t;
-/* call-in interface */
+
+/* Java types with special names for clarity. */
+typedef gtm_int_t gtm_jboolean_t;
+typedef gtm_int_t gtm_jint_t;
+typedef gtm_long_t gtm_jlong_t;
+typedef gtm_float_t gtm_jfloat_t;
+typedef gtm_double_t gtm_jdouble_t;
+typedef gtm_char_t gtm_jstring_t;
+typedef gtm_char_t gtm_jbyte_array_t;
+typedef gtm_char_t gtm_jbig_decimal_t;
+
+/* Call-in interface. */
gtm_status_t gtm_ci(const char *c_rtn_name, ...);
gtm_status_t gtm_cip(ci_name_descriptor *ci_info, ...);
gtm_status_t gtm_init(void);
+#ifdef GTM_PTHREAD
+gtm_status_t gtm_jinit(void);
+#endif
gtm_status_t gtm_exit(void);
+gtm_status_t 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);
void gtm_zstatus(char* msg, int len);
-/* Other entry points accessable in libgtmshr */
+
+/* Other entry points accessable in libgtmshr. */
gtm_status_t gtm_filename_to_id(gtm_string_t *filename, gtm_fileid_ptr_t *fileid);
void gtm_hiber_start(gtm_uint_t mssleep);
void gtm_hiber_start_wait_any(gtm_uint_t mssleep);
@@ -83,6 +101,7 @@ void gtm_start_timer(gtm_tid_t tid, gtm_int_t time_to_expir, void (*handler)(),
void gtm_cancel_timer(gtm_tid_t tid);
gtm_status_t gtm_is_file_identical(gtm_fileid_ptr_t fileid1, gtm_fileid_ptr_t fileid2);
void gtm_xcfileid_free(gtm_fileid_ptr_t fileid);
+int gtm_is_main_thread(void);
void *gtm_malloc(size_t);
void gtm_free(void *);
diff --git a/sr_unix/gv_trigger.c b/sr_unix/gv_trigger.c
index 85967af..3a4ef22 100644
--- a/sr_unix/gv_trigger.c
+++ b/sr_unix/gv_trigger.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2010, 2012 Fidelity Information Services, Inc *
+ * Copyright 2010, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -179,12 +179,13 @@ LITREF mval literal_zero;
SAVE_RTN_NAME(rt_name, rt_name_len, lcl_trigdsc); \
GVTR_HASHTGBL_READ_CLEANUP(TRUE); \
if (ERR_PATMAXLEN == status) \
- rts_error(VARLSTCNT(6) status, 0, ERR_TRIGIS, 2, rt_name_len, rt_name); \
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) status, 0, ERR_TRIGIS, 2, rt_name_len, \
+ rt_name); \
else if (ERR_TRIGSUBSCRANGE == status) \
- rts_error(VARLSTCNT(10) status, 4, save_var_name_len, save_var_name, SUBSCSTRLEN, \
- SUBSCSTR, ERR_TRIGIS, 2, rt_name_len, rt_name); \
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(10) status, 4, save_var_name_len, save_var_name, \
+ SUBSCSTRLEN, SUBSCSTR, ERR_TRIGIS, 2, rt_name_len, rt_name); \
else /* error return from patstr */ \
- rts_error(VARLSTCNT(1) status); \
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status); \
} \
/* End of a range (in a set of ranges) or a subscript itself. \
* Either case, colon_imbalance can be safely reset. \
@@ -244,7 +245,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) \
+#define HASHT_GVN_DEFINITION_RETRY_OR_ERROR(INDEX,SUBSCRIPT,CSA) \
{ \
if (CDB_STAGNATE > t_tries) \
{ \
@@ -257,13 +258,14 @@ LITREF mval literal_zero;
GVTR_HASHTGBL_READ_CLEANUP(TRUE); \
/* format "INDEX,SUBSCRIPT" of ^#t(GVN,INDEX,SUBSCRIPT) in the error message */ \
SET_PARAM_STRING(util_buff, util_len, INDEX, SUBSCRIPT); \
- rts_error(VARLSTCNT(8) ERR_TRIGDEFBAD, 6, save_var_name_len, save_var_name, \
- save_var_name_len, save_var_name, util_len, util_buff); \
+ rts_error_csa(CSA_ARG(CSA) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, save_var_name_len, \
+ save_var_name, save_var_name_len, save_var_name, util_len, \
+ util_buff); \
} \
}
/* This error macro is used for all definition errors where the target is ^#t(GVN,<#COUNT|#CYCLE>) */
-#define HASHT_DEFINITION_RETRY_OR_ERROR(SUBSCRIPT,MOREINFO) \
+#define HASHT_DEFINITION_RETRY_OR_ERROR(SUBSCRIPT,MOREINFO,CSA) \
{ \
if (CDB_STAGNATE > t_tries) \
{ \
@@ -271,18 +273,18 @@ LITREF mval literal_zero;
t_retry(cdb_sc_triggermod); \
} else \
{ \
- HASHT_DEFINITION_ERROR(SUBSCRIPT,MOREINFO); \
+ HASHT_DEFINITION_ERROR(SUBSCRIPT,MOREINFO,CSA); \
} \
}
-#define HASHT_DEFINITION_ERROR(SUBSCRIPT,MOREINFO) \
+#define HASHT_DEFINITION_ERROR(SUBSCRIPT,MOREINFO,CSA) \
{ \
assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number); \
SAVE_VAR_NAME(save_var_name, save_var_name_len, gvt); \
GVTR_HASHTGBL_READ_CLEANUP(TRUE); \
- rts_error(VARLSTCNT(12) ERR_TRIGDEFBAD, 6, save_var_name_len, save_var_name, \
- save_var_name_len, save_var_name, LEN_AND_LIT(SUBSCRIPT), \
- ERR_TEXT, 2, RTS_ERROR_TEXT(MOREINFO)); \
+ rts_error_csa(CSA_ARG(CSA) VARLSTCNT(12) ERR_TRIGDEFBAD, 6, save_var_name_len, \
+ save_var_name, save_var_name_len, save_var_name, \
+ LEN_AND_LIT(SUBSCRIPT), ERR_TEXT, 2, RTS_ERROR_TEXT(MOREINFO)); \
}
/* This code is modeled around "updproc_ch" in updproc.c */
@@ -438,26 +440,34 @@ STATICFNDEF uint4 gvtr_process_range(gv_namehead *gvt, gvtr_subs_t *subsdsc, int
end--;
}
len = UINTCAST(end - start);
- if (len)
+ if (len || (GVTR_PARSE_POINT == type))
{
gvt_trigger = gvt->gvt_trigger;
- nelems = DIVIDE_ROUND_UP(len, GVTR_LIST_ELE_SIZE);
- dststart = (char *)get_new_element(gvt_trigger->gv_trig_list, nelems);
- dstptr = dststart;
- for (srcptr = start; srcptr < end; srcptr++)
+ if (len == 0)
{
- ch = *srcptr;
- if ('"' == ch)
- { /* A double-quote in the middle of the string better be TWO consecutive double-quotes */
- assert(((srcptr + 1) < end) && ('"' == srcptr[1]));
- srcptr++;
+ tmpmval.mvtype = MV_STR;
+ tmpmval.str.addr = "";
+ tmpmval.str.len = 0;
+ } else
+ {
+ nelems = DIVIDE_ROUND_UP(len, GVTR_LIST_ELE_SIZE);
+ dststart = (char *)get_new_element(gvt_trigger->gv_trig_list, nelems);
+ dstptr = dststart;
+ for (srcptr = start; srcptr < end; srcptr++)
+ {
+ ch = *srcptr;
+ if ('"' == ch)
+ { /* A double-quote in the middle of the string better be TWO consecutive double-quotes */
+ assert(((srcptr + 1) < end) && ('"' == srcptr[1]));
+ srcptr++;
+ }
+ *dstptr++ = ch;
}
- *dstptr++ = ch;
+ assert((dstptr - dststart) <= len);
+ tmpmval.mvtype = MV_STR;
+ tmpmval.str.addr = dststart;
+ tmpmval.str.len = INTCAST(dstptr - dststart);
}
- assert((dstptr - dststart) <= len);
- tmpmval.mvtype = MV_STR;
- tmpmval.str.addr = dststart;
- tmpmval.str.len = INTCAST(dstptr - dststart);
/* switch gv_target for mval2subsc */
save_gvt = gv_target;
gv_target = gvt;
@@ -466,15 +476,20 @@ STATICFNDEF uint4 gvtr_process_range(gv_namehead *gvt, gvtr_subs_t *subsdsc, int
out_key->top = DBKEYSIZE(MAX_KEY_SZ);
mval2subsc(&tmpmval, out_key);
gv_target = save_gvt;
+ if(len > 0)
+ {
/* Now that mval2subsc is done, free up the allocated dststart buffer */
- ret = free_last_n_elements(gvt_trigger->gv_trig_list, nelems);
- assert(ret);
+ ret = free_last_n_elements(gvt_trigger->gv_trig_list, nelems);
+ assert(ret);
+ }
}
- /* else len == 0 means an open range (where left or right side of range is unspecified) */
+ /* else it means an open range (where left or right side of range is unspecified)
+ * null subscript on the right side of a range is treated as negative infinity and
+ * on the left side of a range is treated as positive infinity.
+ */
switch(type)
{
case GVTR_PARSE_POINT:
- assert(len);
assert(&subsdsc->gvtr_subs_type == &subsdsc->gvtr_subs_point.gvtr_subs_type);
len = out_key->end; /* keep trailing 0 */
subsdsc->gvtr_subs_point.len = len;
@@ -710,7 +725,7 @@ void gvtr_db_read_hasht(sgmnt_addrs *csa)
return;
}
if ((STR_LIT_LEN(HASHT_GBL_CURLABEL) != ret_mval->str.len) || MEMCMP_LIT(ret_mval->str.addr, HASHT_GBL_CURLABEL))
- HASHT_DEFINITION_RETRY_OR_ERROR("\"#LABEL\"","#LABEL field is not " HASHT_GBL_CURLABEL);
+ HASHT_DEFINITION_RETRY_OR_ERROR("\"#LABEL\"","#LABEL field is not " HASHT_GBL_CURLABEL, csa);
/* So we can go ahead and read other ^#t("GBL") records */
/* -----------------------------------------------------------------------------
* Now read ^#t("GBL","#CYCLE")
@@ -718,10 +733,10 @@ void gvtr_db_read_hasht(sgmnt_addrs *csa)
*/
is_defined = gvtr_get_hasht_gblsubs((mval *)&literal_hashcycle, ret_mval);
if (!is_defined)
- HASHT_DEFINITION_RETRY_OR_ERROR("\"#CYCLE\"","#CYCLE field is missing");
+ HASHT_DEFINITION_RETRY_OR_ERROR("\"#CYCLE\"","#CYCLE field is missing", csa);
tmpint4 = mval2i(ret_mval); /* decimal values are truncated by mval2i so we will accept a #CYCLE of 1.5 as 1 */
if (0 >= tmpint4) /* ^#t("GBL","#CYCLE") is not a positive integer. Error out */
- HASHT_DEFINITION_ERROR("\"#CYCLE\"","#CYCLE field is negative");
+ HASHT_DEFINITION_ERROR("\"#CYCLE\"","#CYCLE field is negative", csa);
cycle = (uint4)tmpint4;
/* Check if ^#t("GBL") has previously been read from the db. If so, check if cycle is same as ^#t("GBL","#CYCLE"). */
gvt_trigger = gvt->gvt_trigger;
@@ -755,10 +770,10 @@ void gvtr_db_read_hasht(sgmnt_addrs *csa)
*/
is_defined = gvtr_get_hasht_gblsubs((mval *)&literal_hashcount, ret_mval);
if (!is_defined)
- HASHT_DEFINITION_RETRY_OR_ERROR("\"#COUNT\"","#COUNT field is missing");
+ HASHT_DEFINITION_RETRY_OR_ERROR("\"#COUNT\"","#COUNT field is missing", csa);
tmpint4 = mval2i(ret_mval); /* decimal values are truncated by mval2i so we will accept a #COUNT of 1.5 as 1 */
if (0 >= tmpint4) /* ^#t("GBL","#COUNT") is not a positive integer. Error out */
- HASHT_DEFINITION_ERROR("\"#COUNT\"","#COUNT field is negative");
+ HASHT_DEFINITION_ERROR("\"#COUNT\"","#COUNT field is negative", csa);
num_gv_triggers = (uint4)tmpint4;
gvt_trigger->num_gv_triggers = num_gv_triggers;
/* We want a memory store for all the values that are going to be read in from the database. We dont know upfront
@@ -793,7 +808,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\"");
+ 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
@@ -811,7 +826,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\"");
+ HASHT_GVN_DEFINITION_RETRY_OR_ERROR(trigidx,",\"CMD\"", csa);
/* Initialize trigdsc->cmdmask */
ptr = ret_mval->str.addr;
ptr_top = ptr + ret_mval->str.len;
@@ -1074,7 +1089,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\"");
+ 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)
@@ -1083,7 +1098,7 @@ void gvtr_db_read_hasht(sgmnt_addrs *csa)
SAVE_VAR_NAME(save_var_name, save_var_name_len, gvt);
SAVE_RTN_NAME(save_rtn_name, save_rtn_name_len, trigdsc);
GVTR_HASHTGBL_READ_CLEANUP(TRUE);
- rts_error(VARLSTCNT(8) ERR_TRIGINVCHSET, 6, save_rtn_name_len, save_rtn_name,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_TRIGINVCHSET, 6, save_rtn_name_len, save_rtn_name,
save_var_name_len, save_var_name, ret_mval->str.len, ret_mval->str.addr);
}
/* Defer loading xecute string until time to compile it */
@@ -1384,7 +1399,7 @@ void gvtr_init(gv_namehead *gvt, uint4 cycle, boolean_t tp_is_implicit, int err_
break;
}
/* else we encountered a TP restart (which would have triggered a call to t_retry
- * which in turn would have done a rts_error(TPRETRY) which would have been caught
+ * which in turn would have done a rts_error(TPRETRY) which would have been caught {BYPASSOK}
* by gvtr_tpwrap_ch which would in turn have unwound the C-stack upto the point
* where the ESTABLISH is done in gvtr_tpwrap_helper and then returned from there).
* In this case we have to keep retrying the read until there are no tp restarts or
@@ -1405,7 +1420,7 @@ void gvtr_init(gv_namehead *gvt, uint4 cycle, boolean_t tp_is_implicit, int err_
} else if (cdb_sc_onln_rlbk2 == failure)
{
assert(tstart_trigger_depth == gtm_trigger_depth);
- rts_error(VARLSTCNT(1) ERR_DBROLLEDBACK);
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(1) ERR_DBROLLEDBACK);
}
/* update lcl_t_tries to reflect the fact that a restart happened */
lcl_t_tries = t_tries;
@@ -1669,7 +1684,7 @@ int gvtr_match_n_invoke(gtm_trigger_parms *trigparms, gvtr_invoke_parms_t *gvtr_
if (MAX_XECUTE_LEN <= trigdsc->xecute_str.str.len)
{
assert(FALSE);
- rts_error(VARLSTCNT(3) ERR_INDRMAXLEN, 1, MAX_XECUTE_LEN);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_INDRMAXLEN, 1, MAX_XECUTE_LEN);
}
}
gtm_trig_status = gtm_trigger(trigdsc, trigparms);
diff --git a/sr_unix/gv_trigger.h b/sr_unix/gv_trigger.h
index 20385d8..c2cf291 100644
--- a/sr_unix/gv_trigger.h
+++ b/sr_unix/gv_trigger.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2010, 2012 Fidelity Information Services, Inc *
+ * Copyright 2010, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -491,7 +491,8 @@ GBLREF int4 tstart_trigger_depth;
\
if (0 == (end = format_targ_key(buff, MAX_ZWR_KEY_SZ, gv_currkey, TRUE))) \
end = &buff[MAX_ZWR_KEY_SZ - 1]; \
- rts_error(VARLSTCNT(8) ERR_TRIGREPLSTATE, 2, DB_LEN_STR(REG), ERR_GVIS, 2, end - buff, buff); \
+ rts_error_csa(CSA_ARG(CSA) VARLSTCNT(8) ERR_TRIGREPLSTATE, 2, DB_LEN_STR(REG), ERR_GVIS, 2, \
+ end - buff, buff); \
} \
}
diff --git a/sr_unix/gvcst_init_sysops.c b/sr_unix/gvcst_init_sysops.c
index 1e293a2..74acb82 100644
--- a/sr_unix/gvcst_init_sysops.c
+++ b/sr_unix/gvcst_init_sysops.c
@@ -105,6 +105,9 @@
#define REQRUNDOWN_TEXT "semid is invalid but shmid is valid or at least one of sem_ctime or shm_ctime are non-zero"
#define MAX_ACCESS_SEM_RETRIES 2
+#define RTS_ERROR(...) rts_error_csa(CSA_ARG(csa) __VA_ARGS__)
+#define SEND_MSG(...) send_msg_csa(CSA_ARG(csa) __VA_ARGS__)
+
#define SS_INFO_INIT(CSA) \
{ \
shm_snapshot_ptr_t ss_shm_ptr; \
@@ -125,7 +128,7 @@
{ \
if (-1 == status_l) \
{ \
- rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), \
+ RTS_ERROR(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg), \
ERR_TEXT, 2, LEN_AND_LIT("Error attaching to database shared memory"), errno); \
} \
}
@@ -149,16 +152,16 @@
if (!MEMCMP_LIT(csa->nl->label, GDS_LABEL_GENERIC)) \
{ \
if (memcmp(csa->nl->now_running, gtm_release_name, gtm_release_name_len + 1)) \
- { /* Copy csa->nl->now_running into a local variable before passing to rts_error() due to the following \
+ { /* Copy csa->nl->now_running into a local variable before passing to rts_error due to the following \
* issue: \
- * In VMS, a call to rts_error() copies only the error message and its arguments (as pointers) and \
+ * In VMS, a call to rts_error copies only the error message and its arguments (as pointers) and \
* transfers control to the topmost condition handler which is dbinit_ch() in this case. dbinit_ch() \
* does a PRN_ERROR only for SUCCESS/INFO (VERMISMATCH is neither of them) and in addition \
* nullifies csa->nl as part of its condition handling. It then transfers control to the next level \
* condition handler which does a PRN_ERROR but at that point in time, the parameter \
* csa->nl->now_running is no longer accessible and hence no \parameter substitution occurs (i.e. the \
* error message gets displayed with plain !ADs). \
- * In UNIX, this is not an issue since the first call to rts_error() does the error message \
+ * In UNIX, this is not an issue since the first call to rts_error does the error message \
* construction before handing control to the topmost condition handler. But it does not hurt to do \
* the copy. \
*/ \
@@ -171,19 +174,14 @@
} \
}
-#define GTM_VERMISMATCH_ERROR \
-{ \
- if (!vermismatch_already_printed) \
- { \
- vermismatch_already_printed = TRUE; \
- /* for DSE, change VERMISMATCH to be INFO (instead of the more appropriate WARNING) \
- * as we want the condition handler (dbinit_ch) to do a CONTINUE (which it does \
- * only for severity levels SUCCESS or INFO) and resume processing in gvcst_init.c \
- * instead of detaching from shared memory. \
- */ \
- rts_error(VARLSTCNT(8) MAKE_MSG_TYPE(ERR_VERMISMATCH, (!IS_DSE_IMAGE ? ERROR : INFO)), 6, \
- DB_LEN_STR(reg), gtm_release_name_len, gtm_release_name, LEN_AND_STR(now_running)); \
- } \
+#define GTM_VERMISMATCH_ERROR \
+{ \
+ if (!vermismatch_already_printed) \
+ { \
+ vermismatch_already_printed = TRUE; \
+ RTS_ERROR(VARLSTCNT(8) ERR_VERMISMATCH, 6, DB_LEN_STR(reg), gtm_release_name_len, gtm_release_name, \
+ LEN_AND_STR(now_running)); \
+ } \
}
#ifdef GTM_CRYPT
@@ -236,7 +234,6 @@
{ \
file_control *fc; \
\
- assert(dba_bg == CSD->acc_meth); \
fc = REG->dyn.addr->file_cntl; \
fc->file_type = dba_bg; \
fc->op = FC_READ; \
@@ -254,13 +251,13 @@
if (JNL_ENABLED(tsd)) \
{ \
if (REPL_ENABLED(tsd) && tsd->jnl_before_image) \
- rts_error(VARLSTCNT(10 + CNT) ERR_REQROLLBACK, 4, DB_LEN_STR(reg), \
+ RTS_ERROR(VARLSTCNT(10 + CNT) ERR_REQROLLBACK, 4, DB_LEN_STR(reg), \
LEN_AND_STR((ARG)->machine_name), __VA_ARGS__); \
else \
- rts_error(VARLSTCNT(10 + CNT) ERR_REQRECOV, 4, DB_LEN_STR(reg), \
+ RTS_ERROR(VARLSTCNT(10 + CNT) ERR_REQRECOV, 4, DB_LEN_STR(reg), \
LEN_AND_STR((ARG)->machine_name), __VA_ARGS__); \
} else \
- rts_error(VARLSTCNT(10 + CNT) ERR_REQRUNDOWN, 4, DB_LEN_STR(reg), \
+ RTS_ERROR(VARLSTCNT(10 + CNT) ERR_REQRUNDOWN, 4, DB_LEN_STR(reg), \
LEN_AND_STR((ARG)->machine_name), __VA_ARGS__); \
}
@@ -290,7 +287,7 @@ OS_PAGE_SIZE_DECLARE
error_def(ERR_BADDBVER);
ZOS_ONLY(error_def(ERR_BADTAG);)
-error_def(ERR_CLSTCONFLICT);
+error_def(ERR_HOSTCONFLICT);
error_def(ERR_CRITSEMFAIL);
error_def(ERR_DBCREINCOMP);
error_def(ERR_DBFILERR);
@@ -306,6 +303,7 @@ error_def(ERR_PERMGENFAIL);
error_def(ERR_REQROLLBACK);
error_def(ERR_REQRECOV);
error_def(ERR_REQRUNDOWN);
+error_def(ERR_REGOPENRETRY);
error_def(ERR_SYSCALL);
error_def(ERR_TEXT);
error_def(ERR_VERMISMATCH);
@@ -322,11 +320,14 @@ gd_region *dbfilopn (gd_region *reg)
int status;
bool raw;
int stat_res, rc, save_errno;
+ sgmnt_addrs *csa;
ZOS_ONLY(int realfiletag;)
seg = reg->dyn.addr;
assert(seg->acc_meth == dba_bg || seg->acc_meth == dba_mm);
FILE_CNTL_INIT_IF_NULL(seg);
+ udi = FILE_INFO(reg);
+ csa = &udi->s_addrs;
file.addr = (char *)seg->fname;
file.len = seg->fname_len;
memset(&pblk, 0, SIZEOF(pblk));
@@ -355,7 +356,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(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);
@@ -369,7 +370,6 @@ gd_region *dbfilopn (gd_region *reg)
return (gd_region *)-1L;
}
fnptr = (char *)seg->fname + pblk.b_node;
- udi = FILE_INFO(reg);
udi->raw = raw;
udi->fn = (char *)fnptr;
OPENFILE(fnptr, O_RDWR, udi->fd);
@@ -382,7 +382,7 @@ gd_region *dbfilopn (gd_region *reg)
udi->gt_shm_ctime = 0;
}
reg->read_only = FALSE; /* maintain csa->read_write simultaneously */
- udi->s_addrs.read_write = TRUE; /* maintain reg->read_only simultaneously */
+ csa->read_write = TRUE; /* maintain reg->read_only simultaneously */
if (FD_INVALID == udi->fd)
{
OPENFILE(fnptr, O_RDONLY, udi->fd);
@@ -395,10 +395,10 @@ 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(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), save_errno);
}
reg->read_only = TRUE; /* maintain csa->read_write simultaneously */
- udi->s_addrs.read_write = FALSE; /* maintain reg->read_only simultaneously */
+ csa->read_write = FALSE; /* maintain reg->read_only simultaneously */
}
# ifdef __MVS__
if (-1 == gtm_zos_tag_to_policy(udi->fd, TAG_BINARY, &realfiletag))
@@ -408,7 +408,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(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), save_errno);
}
set_gdid_from_stat(&udi->fileid, &buf);
if (prev_reg = gv_match(reg))
@@ -424,44 +424,43 @@ gd_region *dbfilopn (gd_region *reg)
void dbsecspc(gd_region *reg, sgmnt_data_ptr_t csd, gtm_uint64_t *sec_size)
{
+ gtm_uint64_t tmp_sec_size;
+
/* Ensure that all the various sections that the shared memory contains are actually
* aligned at the OS_PAGE_SIZE boundary
*/
- assert(0 == NODE_LOCAL_SPACE % OS_PAGE_SIZE);
+ INIT_NUM_CRIT_ENTRY_IF_NEEDED(csd);
+ assert(MIN_NODE_LOCAL_SPACE <= NODE_LOCAL_SPACE(csd));
+ assert(0 == NODE_LOCAL_SPACE(csd) % OS_PAGE_SIZE);
assert(0 == LOCK_SPACE_SIZE(csd) % OS_PAGE_SIZE);
assert(0 == JNL_SHARE_SIZE(csd) % OS_PAGE_SIZE);
assert(0 == SHMPOOL_SECTION_SIZE % OS_PAGE_SIZE);
- switch(reg->dyn.addr->acc_meth)
+ assert(0 == CACHE_CONTROL_SIZE(csd) % OS_PAGE_SIZE);
+ /* First compute the size based on sections common to both MM and BG */
+ tmp_sec_size = NODE_LOCAL_SPACE(csd) + JNL_SHARE_SIZE(csd) + SHMPOOL_SECTION_SIZE + LOCK_SPACE_SIZE(csd);
+ /* Now, add sections specific to MM and BG */
+ if (dba_mm == reg->dyn.addr->acc_meth)
+ tmp_sec_size += SIZEOF_FILE_HDR(csd);
+ else
{
- case dba_mm:
- assert(0 == MMBLK_CONTROL_SIZE(csd) % OS_PAGE_SIZE);
- *sec_size = ROUND_UP(NODE_LOCAL_SPACE + LOCK_SPACE_SIZE(csd) + MMBLK_CONTROL_SIZE(csd) \
- + JNL_SHARE_SIZE(csd) + SHMPOOL_SECTION_SIZE, OS_PAGE_SIZE);
- break;
- case dba_bg:
- assert(0 == CACHE_CONTROL_SIZE(csd) % OS_PAGE_SIZE);
- /* If Huge Pages are supported align to Huge Pages */
-# ifdef HUGETLB_SUPPORTED
- *sec_size = ROUND_UP(NODE_LOCAL_SPACE + (LOCK_BLOCK(csd) * DISK_BLOCK_SIZE) + LOCK_SPACE_SIZE(csd) \
- + CACHE_CONTROL_SIZE(csd) + JNL_SHARE_SIZE(csd) + SHMPOOL_SECTION_SIZE, OS_HUGEPAGE_SIZE);
-# else
- *sec_size = ROUND_UP(NODE_LOCAL_SPACE + (LOCK_BLOCK(csd) * DISK_BLOCK_SIZE) + LOCK_SPACE_SIZE(csd) \
- + CACHE_CONTROL_SIZE(csd) + JNL_SHARE_SIZE(csd) + SHMPOOL_SECTION_SIZE, OS_PAGE_SIZE);
-# endif
- break;
- default:
- GTMASSERT;
+ 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
return;
}
-void db_init(gd_region *reg)
+int db_init(gd_region *reg)
{
boolean_t is_bg, read_only, sem_created = FALSE, need_stacktrace, have_standalone_access;
boolean_t shm_setup_ok = FALSE, vermismatch = FALSE, vermismatch_already_printed = FALSE;
boolean_t new_shm_ipc, do_crypt_init = FALSE, replinst_mismatch;
char machine_name[MAX_MCNAMELEN];
- int gethostname_res, stat_res, mm_prot, group_id, perm, save_udi_semid;
+ int gethostname_res, stat_res, group_id, perm, save_udi_semid;
int4 status, semval, dblksize, fbwsize, save_errno, wait_time, loopcnt, sem_pid;
sm_long_t status_l;
sgmnt_addrs *csa;
@@ -477,47 +476,53 @@ void db_init(gd_region *reg)
unix_db_info *udi;
char now_running[MAX_REL_NAME];
int init_status;
- gtm_uint64_t sec_size;
+ gtm_uint64_t sec_size, mmap_sz;
semwait_status_t retstat;
struct perm_diag_data pdd;
boolean_t bypassed_ftok = FALSE, bypassed_access = FALSE;
int jnl_buffer_size;
char s[JNLBUFFUPDAPNDX_SIZE]; /* JNLBUFFUPDAPNDX_SIZE is defined in jnl.h */
-
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
- ESTABLISH(dbinit_ch);
+ ESTABLISH_NOUNWIND(dbinit_ch);
assert(INTRPT_IN_GVCST_INIT == intrpt_ok_state); /* we better be called from gvcst_init */
wcs_clean_dbsync_fptr = &wcs_clean_dbsync;
tsd = &tsdbuff;
read_only = reg->read_only;
- TREF(new_dbinit_ipc) = 0; /* we did not create a new ipc resource */
udi = FILE_INFO(reg);
memset(machine_name, 0, SIZEOF(machine_name));
+ csa = &udi->s_addrs;
+ assert(!mutex_per_process_init_pid || mutex_per_process_init_pid == process_id);
+ if (!mutex_per_process_init_pid)
+ mutex_per_process_init();
if (GETHOSTNAME(machine_name, MAX_MCNAMELEN, gethostname_res))
- rts_error(VARLSTCNT(5) ERR_TEXT, 2, LEN_AND_LIT("Unable to get the hostname"), errno);
+ RTS_ERROR(VARLSTCNT(5) ERR_TEXT, 2, LEN_AND_LIT("Unable to get the hostname"), errno);
+ if (WBTEST_ENABLED(WBTEST_TAMPER_HOSTNAME))
+ STRCPY(machine_name, "s_i_l_l_y");
assert(strlen(machine_name) < MAX_MCNAMELEN);
- csa = &udi->s_addrs;
- csa->db_addrs[0] = csa->db_addrs[1] = csa->lock_addrs[0] = NULL; /* to help in dbinit_ch and gds_rundown */
+ assert(NULL == csa->hdr); /* dbinit_ch relies on this to unmap the db (if mm) */
+ assert((NULL == csa->db_addrs[0]) && (NULL == csa->db_addrs[1]));
+ assert((NULL == csa->lock_addrs[0]) && (NULL == csa->lock_addrs[1]));
reg->opening = TRUE;
assert(0 <= udi->fd); /* database file must have been already opened by dbfilopn() done from gvcst_init() */
FSTAT_FILE(udi->fd, &stat_buf, stat_res); /* get the stats for the database file */
if (-1 == stat_res)
- rts_error(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), errno);
+ RTS_ERROR(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), errno);
/* Setup new group and permissions if indicated by the security rules. */
if (gtm_set_group_and_perm(&stat_buf, &group_id, &perm, PERM_IPC, &pdd) < 0)
{
- send_msg(VARLSTCNT(6 + PERMGENDIAG_ARG_COUNT)
+ SEND_MSG(VARLSTCNT(6 + PERMGENDIAG_ARG_COUNT)
ERR_PERMGENFAIL, 4, RTS_ERROR_STRING("ipc resources"), RTS_ERROR_STRING(udi->fn),
PERMGENDIAG_ARGS(pdd));
- rts_error(VARLSTCNT(6 + PERMGENDIAG_ARG_COUNT)
+ RTS_ERROR(VARLSTCNT(6 + PERMGENDIAG_ARG_COUNT)
ERR_PERMGENFAIL, 4, RTS_ERROR_STRING("ipc resources"), RTS_ERROR_STRING(udi->fn),
PERMGENDIAG_ARGS(pdd));
}
- /* if the process has standalone access, it will have udi->grabbed_access_sem set to TRUE at this point. Note that down
- * in a local variable as the udi->grabbed_access_sem will be set to TRUE even for non-standalone access below and hence
- * we can't rely on that later to determine if the process had standalone access or not when it entered this function.
+ /* if the process has standalone access, it will have udi->grabbed_access_sem set to TRUE at
+ * this point. Note that down in a local variable as the udi->grabbed_access_sem will be set
+ * to TRUE even for non-standalone access below and hence we can't rely on that later to determine if the process had
+ * standalone access or not when it entered this function.
*/
have_standalone_access = udi->grabbed_access_sem;
if (!have_standalone_access)
@@ -528,7 +533,7 @@ void db_init(gd_region *reg)
if (!ftok_sem_get2(reg, start_hrtbt_cntr, &retstat, &bypassed_ftok))
ISSUE_SEMWAIT_ERROR((&retstat), reg, udi, "ftok");
if (bypassed_ftok)
- send_msg(VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_LIT("FTOK bypassed at database initialization"));
+ SEND_MSG(VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_LIT("FTOK bypassed at database initialization"));
/* At this point we have ftok_semid semaphore based on ftok key. Any ftok conflicted region will block at this
* point. For example, if a.dat and b.dat both have same ftok and process A tries to open or close a.dat and
* process B tries to open or close b.dat, even though the database accesses don't conflict, the first one to
@@ -546,31 +551,30 @@ void db_init(gd_region *reg)
* as initialization is heavy-weight.
*/
if (!ftok_sem_release(reg, TRUE, FALSE)) /* decrement counter so later increment is correct */
- rts_error(VARLSTCNT(4) ERR_DBFILERR, 2, DB_LEN_STR(reg));
+ RTS_ERROR(VARLSTCNT(4) ERR_DBFILERR, 2, DB_LEN_STR(reg));
INIT_PROC_ENCRYPTION_IF_NEEDED(csa, do_crypt_init, init_status); /* redo initialization */
start_hrtbt_cntr = heartbeat_counter; /* update to reflect time lost in encryption initialization */
if (!ftok_sem_get2(reg, start_hrtbt_cntr, &retstat, &bypassed_ftok))
ISSUE_SEMWAIT_ERROR((&retstat), reg, udi, "ftok");
if (bypassed_ftok)
- send_msg(VARLSTCNT(4) ERR_TEXT, 2,
+ SEND_MSG(VARLSTCNT(4) ERR_TEXT, 2,
LEN_AND_LIT("bypassed at database encryption initialization"));
} /* else encryption is turned off in the file header. Continue as-is. Any encryption initialization done
* before is discarded
*/
}
INIT_DB_ENCRYPTION_IF_NEEDED(do_crypt_init, init_status, reg, csa, tsd);
-# ifdef DEBUG
- if (gtm_white_box_test_case_enabled && (WBTEST_HOLD_ONTO_FTOKSEM_IN_DBINIT == gtm_white_box_test_case_number))
+ if (WBTEST_ENABLED(WBTEST_HOLD_ONTO_FTOKSEM_IN_DBINIT))
{
DBGFPF((stderr, "Holding the ftok semaphore.. Sleeping for 30 seconds\n"));
LONG_SLEEP(30);
DBGFPF((stderr, "30 second sleep exhausted.. continuing with rest of db_init..\n"));
}
-# endif
for (loopcnt = 0; MAX_ACCESS_SEM_RETRIES > loopcnt; loopcnt++)
{
CSD2UDI(tsd, udi); /* sets udi->semid/shmid/sem_ctime/shm_ctime from file header */
- TREF(new_dbinit_ipc) = 0;
+ /* we did not create a new ipc resource */
+ udi->new_sem = udi->new_shm = FALSE;
sem_created = FALSE;
if (INVALID_SEMID == udi->semid)
{ /* access control semaphore does not exist. Create one */
@@ -583,26 +587,26 @@ void db_init(gd_region *reg)
if (-1 == (udi->semid = semget(IPC_PRIVATE, FTOK_SEM_PER_ID, RWDALL | IPC_CREAT)))
{
udi->semid = INVALID_SEMID;
- rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg),
+ RTS_ERROR(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg),
ERR_TEXT, 2, LEN_AND_LIT("Error with database control semget"), errno);
}
udi->shmid = INVALID_SHMID; /* reset shmid so dbinit_ch does not get confused in case we go there */
- TREF(new_dbinit_ipc) |= (NEW_DBINIT_SEM_IPC_MASK | NEW_DBINIT_SHM_IPC_MASK);
+ udi->new_sem = udi->new_shm = TRUE;
sem_created = TRUE;
/* change group and permissions */
semarg.buf = &semstat;
if (-1 == semctl(udi->semid, FTOK_SEM_PER_ID - 1, IPC_STAT, semarg))
- rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg),
+ RTS_ERROR(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg),
ERR_TEXT, 2, LEN_AND_LIT("Error with database control semctl IPC_STAT1"), errno);
if ((-1 != group_id) && (group_id != semstat.sem_perm.gid))
semstat.sem_perm.gid = group_id;
semstat.sem_perm.mode = perm;
if (-1 == semctl(udi->semid, FTOK_SEM_PER_ID - 1, IPC_SET, semarg))
- rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg),
+ RTS_ERROR(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg),
ERR_TEXT, 2, LEN_AND_LIT("Error with database control semctl IPC_SET"), errno);
SET_GTM_ID_SEM(udi->semid, status);
if (-1 == status)
- rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg),
+ RTS_ERROR(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg),
ERR_TEXT, 2, LEN_AND_LIT("Error with database control semctl SETVAL"), errno);
/* WARNING: Because SETVAL changes sem_ctime, we must NOT do any SETVAL after this one; code here
* and elsewhere uses IPC_STAT to get sem_ctime and relies on sem_ctime as the creation time of the
@@ -610,17 +614,33 @@ void db_init(gd_region *reg)
*/
semarg.buf = &semstat;
if (-1 == semctl(udi->semid, FTOK_SEM_PER_ID - 1, IPC_STAT, semarg))
- rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg),
+ RTS_ERROR(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg),
ERR_TEXT, 2, LEN_AND_LIT("Error with database control semctl IPC_STAT2"), errno);
tsd->gt_sem_ctime.ctime = udi->gt_sem_ctime = semarg.buf->sem_ctime;
} else
{ /* "semid" already exists. Need to lock it. Before that do sanity check on "semid" and "shmid" */
if (INVALID_SHMID != udi->shmid)
{
+ if (WBTEST_ENABLED(WBTEST_HOLD_FTOK_UNTIL_BYPASS))
+ {
+ if (4 == semctl(udi->ftok_semid, DB_COUNTER_SEM, GETVAL))
+ { /* We are bypasser */
+ DBGFPF((stderr, "Waiting for all processes to quit.\n"));
+ while (1 < semctl(udi->ftok_semid, DB_COUNTER_SEM, GETVAL))
+ LONG_SLEEP(1);
+ }
+ }
if (-1 == shmctl(udi->shmid, IPC_STAT, &shmstat))
{
+ if (bypassed_ftok)
+ {
+ gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_REGOPENRETRY, 4,
+ REG_LEN_STR(reg), DB_LEN_STR(reg));
+ REVERT;
+ return -1; /* Retry calling db_init. Cleanup in gvcst_init() */
+ }
PRINT_CRASH_MESSAGE(1, tsd, ERR_TEXT, 2,
- LEN_AND_LIT("Error with database control shmctl"), errno);
+ LEN_AND_LIT("Error with database control shmctl"), errno);
} else if (shmstat.shm_ctime != tsd->gt_shm_ctime.ctime)
{
GTM_ATTACH_SHM_AND_CHECK_VERS(vermismatch, shm_setup_ok);
@@ -634,7 +654,7 @@ void db_init(gd_region *reg)
}
}
semarg.buf = &semstat;
- if (-1 == semctl(udi->semid, 0, IPC_STAT, semarg))
+ if (-1 == semctl(udi->semid, DB_CONTROL_SEM, IPC_STAT, semarg))
{ /* file header has valid semid but semaphore does not exist */
PRINT_CRASH_MESSAGE(1, tsd, ERR_TEXT, 2,
LEN_AND_LIT("Error with database control semaphore (IPC_STAT)"), errno);
@@ -661,7 +681,7 @@ void db_init(gd_region *reg)
* In either case, try grabbing the semaphore. If not, wait (depending on the user specified
* wait time). Eventually, we will either get hold of the semaphore OR will error out.
*/
- TREF(new_dbinit_ipc) |= NEW_DBINIT_SHM_IPC_MASK; /* Need to create shared memory */
+ udi->new_shm = TRUE; /* Need to create shared memory */
}
}
/* We already have ftok semaphore of this region, so all we need is the access control semaphore */
@@ -677,10 +697,10 @@ void db_init(gd_region *reg)
{
if (NO_SEMWAIT_ON_EAGAIN == TREF(dbinit_max_hrtbt_delta))
{
- sem_pid = semctl(udi->semid, 0, GETPID);
+ sem_pid = semctl(udi->semid, DB_CONTROL_SEM, GETPID);
if (-1 != sem_pid)
{
- rts_error(VARLSTCNT(13) ERR_DBFILERR, 2, DB_LEN_STR(reg),
+ RTS_ERROR(VARLSTCNT(13) ERR_DBFILERR, 2, DB_LEN_STR(reg),
ERR_SEMWT2LONG, 7, process_id, 0, LEN_AND_LIT("access control"),
DB_LEN_STR(reg), sem_pid);
} else
@@ -688,7 +708,7 @@ void db_init(gd_region *reg)
save_errno = errno;
if (!SEM_REMOVED(save_errno))
{
- rts_error(VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg),
+ RTS_ERROR(VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg),
ERR_SYSCALL, 5, RTS_ERROR_LITERAL("semop()"), CALLFROM,
save_errno);
} /* else semaphore was removed. Fall-through */
@@ -702,14 +722,14 @@ void db_init(gd_region *reg)
} else
{
if (bypassed_access)
- send_msg(VARLSTCNT(4) ERR_TEXT, 2,
+ SEND_MSG(VARLSTCNT(4) ERR_TEXT, 2,
LEN_AND_LIT("Access control bypassed at init"));
save_errno = status = SS_NORMAL;
break;
}
} else if (!SEM_REMOVED(save_errno))
{
- rts_error(VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5, \
+ RTS_ERROR(VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5, \
RTS_ERROR_LITERAL("semop()"), CALLFROM, save_errno);
}
/* this is possible if a concurrent gds_rundown removed the access control semaphore (if
@@ -722,7 +742,7 @@ void db_init(gd_region *reg)
assert(SEM_REMOVED(save_errno));
if (1 == loopcnt)
{
- rts_error(VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5, \
+ RTS_ERROR(VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5, \
RTS_ERROR_LITERAL("semop()"), CALLFROM, save_errno);
}
READ_DB_FILE_HEADER(reg, tsd);
@@ -731,6 +751,8 @@ void db_init(gd_region *reg)
assert(-1 != status || bypassed_access);
if (!bypassed_access)
udi->grabbed_access_sem = TRUE;
+ if(!read_only)
+ udi->counter_acc_incremented = TRUE;
/* Now that we have the access control semaphore, re-read the file header so we have the uptodate information
* in case some of the fields (like access method) were modified concurrently by MUPIP SET -FILE
*/
@@ -754,31 +776,40 @@ void db_init(gd_region *reg)
assert((INVALID_SHMID == udi->shmid) && (0 == udi->gt_shm_ctime));
/* In pro, just clear it and proceed */
udi->shmid = INVALID_SHMID; /* reset shmid so dbinit_ch does not get confused in case we go there */
- TREF(new_dbinit_ipc) |= (NEW_DBINIT_SEM_IPC_MASK | NEW_DBINIT_SHM_IPC_MASK);
+ udi->new_shm = udi->new_sem = TRUE;
}
assert(udi->grabbed_access_sem || bypassed_access);
DO_DB_HDR_CHECK(reg, tsd); /* Basic sanity check on the file header fields */
-# ifdef DEBUG
- if (gtm_white_box_test_case_enabled && (WBTEST_HOLD_ONTO_ACCSEM_IN_DBINIT == gtm_white_box_test_case_number))
+ if (WBTEST_ENABLED(WBTEST_HOLD_ONTO_ACCSEM_IN_DBINIT))
{
DBGFPF((stderr, "Holding the access control semaphore.. Sleeping for 30 seconds\n"));
LONG_SLEEP(30);
DBGFPF((stderr, "30 second sleep exhausted.. continuing with rest of db_init..\n"));
}
-# endif
+ if (WBTEST_ENABLED(WBTEST_HOLD_FTOK_UNTIL_BYPASS))
+ {
+ if (3 == semctl(udi->ftok_semid, DB_COUNTER_SEM, GETVAL))
+ { /* We are ftok semaphore holder */
+ DBGFPF((stderr, "Holding the ftok semaphore until a new process comes along.\n"));
+ while (3 == semctl(udi->ftok_semid, DB_COUNTER_SEM, GETVAL))
+ LONG_SLEEP(1);
+ }
+ }
/* Now that the access control lock is obtained and file header passed all sanity checks, update the acc_meth of the
* region from the one in the file header (in case they are different). This way, any later code that relies on the
* acc_meth dereferenced from the region will work correctly. Instead of checking if they are different, do the assignment
* unconditionally
*/
reg->dyn.addr->acc_meth = tsd->acc_meth;
- new_shm_ipc = (TREF(new_dbinit_ipc) & NEW_DBINIT_SHM_IPC_MASK);
+ new_shm_ipc = udi->new_shm;
if (new_shm_ipc)
{ /* Bypassers are not allowed to create shared memory so we don't end up with conflicting shared memories */
if (bypassed_ftok || bypassed_access)
- PRINT_CRASH_MESSAGE(0, tsd, ERR_TEXT, 2,
- LEN_AND_LIT("DSE/LKE database initialization attempt tried a startup short cut that "
- "failed due to a conflict with a database shutdown - please retry"));
+ {
+ gtm_putmsg_csa(CSA_ARG(csa) ERR_REGOPENRETRY, 2, REG_LEN_STR(reg), DB_LEN_STR(reg));
+ REVERT;
+ return -1; /* Retry calling db_init. Cleanup in gvcst_init() */
+ }
/* Since we are about to allocate new shared memory, if necessary, adjust the journal buffer size right now.
* Note that if the process setting up shared memory is a read-only process, then we might not flush updated
* jnl_buffer_size to the file header, which is fine because the value in shared memory is what all processes
@@ -790,7 +821,7 @@ void db_init(gd_region *reg)
{
ROUND_UP_MIN_JNL_BUFF_SIZE(tsd->jnl_buffer_size, tsd);
SNPRINTF(s, JNLBUFFUPDAPNDX_SIZE, JNLBUFFUPDAPNDX, JNL_BUFF_PORT_MIN(tsd), JNL_BUFFER_MAX);
- send_msg(VARLSTCNT(10) ERR_JNLBUFFREGUPD, 4, REG_LEN_STR(reg),
+ SEND_MSG(VARLSTCNT(10) ERR_JNLBUFFREGUPD, 4, REG_LEN_STR(reg),
jnl_buffer_size, tsd->jnl_buffer_size, ERR_TEXT, 2, LEN_AND_STR(s));
}
dbsecspc(reg, tsd, &sec_size); /* Find db segment size */
@@ -800,26 +831,26 @@ void db_init(gd_region *reg)
{
udi->shmid = (int)INVALID_SHMID;
status_l = INVALID_SHMID;
- rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg),
+ RTS_ERROR(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg),
ERR_TEXT, 2, LEN_AND_LIT("Error with database shmget"), errno);
}
tsd->shmid = udi->shmid;
if (-1 == shmctl(udi->shmid, IPC_STAT, &shmstat))
- rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg),
+ RTS_ERROR(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg),
ERR_TEXT, 2, LEN_AND_LIT("Error with database control shmctl IPC_STAT1"), errno);
/* change group and permissions */
if ((-1 != group_id) && (group_id != shmstat.shm_perm.gid))
shmstat.shm_perm.gid = group_id;
shmstat.shm_perm.mode = perm;
if (-1 == shmctl(udi->shmid, IPC_SET, &shmstat))
- rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg),
+ RTS_ERROR(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg),
ERR_TEXT, 2, LEN_AND_LIT("Error with database control shmctl IPC_SET"), errno);
/* Warning: We must read the shm_ctime using IPC_STAT after IPC_SET, which changes it.
* We must NOT do any more IPC_SET or SETVAL after this. Our design is to use
* shm_ctime as creation time of shared memory and store it in file header.
*/
if (-1 == shmctl(udi->shmid, IPC_STAT, &shmstat))
- rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg),
+ RTS_ERROR(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg),
ERR_TEXT, 2, LEN_AND_LIT("Error with database control shmctl IPC_STAT2"), errno);
tsd->gt_shm_ctime.ctime = udi->gt_shm_ctime = shmstat.shm_ctime;
GTM_ATTACH_SHM;
@@ -844,7 +875,7 @@ void db_init(gd_region *reg)
* The jnl_buff should be initialized irrespective of read/write process
*/
JNL_INIT(csa, reg, tsd);
- csa->shmpool_buffer = (shmpool_buff_hdr_ptr_t)(csa->db_addrs[0] + NODE_LOCAL_SPACE + JNL_SHARE_SIZE(tsd));
+ csa->shmpool_buffer = (shmpool_buff_hdr_ptr_t)(csa->db_addrs[0] + NODE_LOCAL_SPACE(tsd) + JNL_SHARE_SIZE(tsd));
/* Initialize memory for snapshot context */ \
csa->ss_ctx = malloc(SIZEOF(snapshot_context_t));
DEFAULT_INIT_SS_CTX((SS_CTX_CAST(csa->ss_ctx)));
@@ -868,18 +899,20 @@ void db_init(gd_region *reg)
csd = csa->hdr = (sgmnt_data_ptr_t)(csa->lock_addrs[1] + 1 + CACHE_CONTROL_SIZE(tsd));
else
{
- csa->acc_meth.mm.mmblk_state = (mmblk_que_heads_ptr_t)(csa->lock_addrs[1] + 1);
FSTAT_FILE(udi->fd, &stat_buf, stat_res);
if (-1 == stat_res)
- rts_error(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), errno);
- mm_prot = read_only ? PROT_READ : (PROT_READ | PROT_WRITE);
- if (-1 == (sm_long_t)(csa->db_addrs[0] = (sm_uc_ptr_t)mmap((caddr_t)NULL,
- (size_t)stat_buf.st_size,
- mm_prot,
- GTM_MM_FLAGS, udi->fd, (off_t)0)))
- rts_error(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), errno);
- csa->db_addrs[1] = csa->db_addrs[0] + stat_buf.st_size - 1;
- csd = csa->hdr = (sgmnt_data_ptr_t)csa->db_addrs[0];
+ RTS_ERROR(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), errno);
+ mmap_sz = stat_buf.st_size - BLK_ZERO_OFF(tsd);
+ assert(0 < mmap_sz);
+ CHECK_LARGEFILE_MMAP(reg, mmap_sz); /* can issue rts_error MMFILETOOLARGE */
+ if (-1 == (sm_long_t)(csa->db_addrs[0] = (sm_uc_ptr_t)MMAP_FD(udi->fd, mmap_sz, BLK_ZERO_OFF(tsd), read_only)))
+ {
+ RTS_ERROR(VARLSTCNT(12) ERR_DBFILERR, 2, DB_LEN_STR(reg),
+ ERR_SYSCALL, 5, LEN_AND_LIT("mmap()"), CALLFROM, errno);
+ }
+ csa->db_addrs[1] = csa->db_addrs[0] + mmap_sz - 1; /* '- 1' due to 0-based indexing */
+ assert(csa->db_addrs[1] > csa->db_addrs[0]);
+ csd = csa->hdr = (sgmnt_data_ptr_t)((sm_uc_ptr_t)csa->lock_addrs[1] + 1);
}
/* At this point, shm_setup_ok is TRUE so we are guaranteed that vermismatch is FALSE. Therefore, we can safely
* dereference csa->nl->glob_sec_init without worrying about whether or not it could be at a different offset than
@@ -891,15 +924,13 @@ void db_init(gd_region *reg)
assert(new_shm_ipc);
assert(!vermismatch);
csa->dbinit_shm_created = TRUE;
- if (is_bg)
- {
- memcpy(csd, tsd, SIZEOF(sgmnt_data));
- READ_DB_FILE_MASTERMAP(reg, csd);
- }
+ memcpy(csd, tsd, SIZEOF(sgmnt_data));
+ READ_DB_FILE_MASTERMAP(reg, csd);
if (csd->machine_name[0]) /* crash occurred */
{
if (0 != STRNCMP_STR(csd->machine_name, machine_name, MAX_MCNAMELEN)) /* crashed on some other node */
- rts_error(VARLSTCNT(6) ERR_CLSTCONFLICT, 4, DB_LEN_STR(reg), LEN_AND_STR(csd->machine_name));
+ RTS_ERROR(VARLSTCNT(8) ERR_HOSTCONFLICT, 6, LEN_AND_STR(machine_name), DB_LEN_STR(reg),
+ LEN_AND_STR(csd->machine_name));
else
{
PRINT_CRASH_MESSAGE(0, csd, ERR_TEXT, 2,
@@ -908,9 +939,9 @@ void db_init(gd_region *reg)
}
if (is_bg)
{
- bt_malloc(csa);
- csa->nl->cache_off = -CACHE_CONTROL_SIZE(tsd);
+ csa->nl->cache_off = -CACHE_CONTROL_SIZE(csd);
db_csh_ini(csa);
+ bt_malloc(csa);
}
db_csh_ref(csa, TRUE);
shmpool_buff_init(reg);
@@ -951,14 +982,16 @@ void db_init(gd_region *reg)
gvstats_rec_csd2cnl(csa); /* should be called before "db_auto_upgrade" */
reg->dyn.addr->ext_blk_count = csd->extension_size;
mlk_shr_init(csa->lock_addrs[0], csd->lock_space_size, csa, (FALSE == read_only));
+ db_auto_upgrade(reg); /* should be called before "gtm_mutex_init" to ensure NUM_CRIT_ENTRY is nonzero */
DEBUG_ONLY(locknl = csa->nl;) /* for DEBUG_ONLY LOCK_HIST macro */
- gtm_mutex_init(reg, NUM_CRIT_ENTRY, FALSE);
+ gtm_mutex_init(reg, NUM_CRIT_ENTRY(csd), FALSE);
DEBUG_ONLY(locknl = NULL;) /* restore "locknl" to default value */
if (read_only)
csa->nl->remove_shm = TRUE; /* gds_rundown can remove shmem if first process has read-only access */
- db_auto_upgrade(reg);
if (FALSE == csd->multi_site_open)
- { /* first time database is opened after upgrading to a GTM version that supports multi-site replication */
+ { /* first time database is opened after upgrading to a GTM version that supports multi-site
+ * replication
+ */
csd->zqgblmod_seqno = 0;
csd->zqgblmod_tn = 0;
if (csd->pre_multisite_resync_seqno > csd->reg_seqno)
@@ -970,7 +1003,7 @@ void db_init(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(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), save_errno);
}
set_gdid_from_stat(&csa->nl->unique_id.uid, &stat_buf);
# ifdef RELEASE_LATCH_GLOBAL
@@ -991,7 +1024,8 @@ void db_init(gd_region *reg)
if (STRNCMP_STR(csa->nl->machine_name, machine_name, MAX_MCNAMELEN)) /* machine names do not match */
{
if (csa->nl->machine_name[0])
- rts_error(VARLSTCNT(6) ERR_CLSTCONFLICT, 4, DB_LEN_STR(reg), LEN_AND_STR(csa->nl->machine_name));
+ RTS_ERROR(VARLSTCNT(8) ERR_HOSTCONFLICT, 6, LEN_AND_STR(machine_name), DB_LEN_STR(reg),
+ LEN_AND_STR(csa->nl->machine_name));
else
{
PRINT_CRASH_MESSAGE(0, csd, ERR_TEXT, 2,
@@ -1007,7 +1041,7 @@ void db_init(gd_region *reg)
if (-1 == stat_res)
{
save_errno = errno;
- send_msg(VARLSTCNT(13) ERR_REQRUNDOWN, 4, DB_LEN_STR(reg), LEN_AND_STR(csa->nl->machine_name),
+ SEND_MSG(VARLSTCNT(13) ERR_REQRUNDOWN, 4, DB_LEN_STR(reg), LEN_AND_STR(csa->nl->machine_name),
ERR_DBNAMEMISMATCH, 4, DB_LEN_STR(reg), udi->shmid, csa->nl->fname, save_errno);
PRINT_CRASH_MESSAGE(3, csa->nl, ERR_DBNAMEMISMATCH, 4,
DB_LEN_STR(reg), udi->shmid, csa->nl->fname, save_errno);
@@ -1015,7 +1049,7 @@ void db_init(gd_region *reg)
/* Check whether csa->nl->fname and csa->nl->unique_id.uid are in sync. If not error out. */
if (FALSE == is_gdid_stat_identical(&csa->nl->unique_id.uid, &stat_buf))
{
- send_msg(VARLSTCNT(12) ERR_REQRUNDOWN, 4, DB_LEN_STR(reg), LEN_AND_STR(csa->nl->machine_name),
+ SEND_MSG(VARLSTCNT(12) ERR_REQRUNDOWN, 4, DB_LEN_STR(reg), LEN_AND_STR(csa->nl->machine_name),
ERR_DBIDMISMATCH, 4, csa->nl->fname, DB_LEN_STR(reg), udi->shmid);
PRINT_CRASH_MESSAGE(2, csa->nl, ERR_DBIDMISMATCH, 4, csa->nl->fname, DB_LEN_STR(reg), udi->shmid);
}
@@ -1028,7 +1062,7 @@ void db_init(gd_region *reg)
*/
if (FALSE == is_gdid_gdid_identical(&FILE_INFO(reg)->fileid, &csa->nl->unique_id.uid))
{
- send_msg(VARLSTCNT(12) ERR_REQRUNDOWN, 4, DB_LEN_STR(reg), LEN_AND_STR(csa->nl->machine_name),
+ SEND_MSG(VARLSTCNT(12) ERR_REQRUNDOWN, 4, DB_LEN_STR(reg), LEN_AND_STR(csa->nl->machine_name),
ERR_DBSHMNAMEDIFF, 4, DB_LEN_STR(reg), udi->shmid, csa->nl->fname);
PRINT_CRASH_MESSAGE(2, csa->nl, ERR_DBSHMNAMEDIFF, 4, DB_LEN_STR(reg), udi->shmid, csa->nl->fname);
}
@@ -1073,6 +1107,8 @@ void db_init(gd_region *reg)
(uint4)((sm_uc_ptr_t)csa->lock_addrs[0] - (sm_uc_ptr_t)csa->nl), (uint4)csa->nl->lock_addrs);
}
csa->dbinit_shm_created = FALSE;
+ if (is_bg)
+ db_csh_ini(csa);
}
if (REPL_ALLOWED(csd) && is_src_server)
{ /* Bind this database to the journal pool shmid & instance file name that the source server started with.
@@ -1109,7 +1145,7 @@ void db_init(gd_region *reg)
}
/* Replication instance file or jnlpool id mismatch. Issue error. */
if (replinst_mismatch)
- rts_error(VARLSTCNT(10) ERR_REPLINSTMISMTCH, 8,
+ RTS_ERROR(VARLSTCNT(10) ERR_REPLINSTMISMTCH, 8,
LEN_AND_STR(jnlpool.jnlpool_ctl->jnlpool_id.instfilename), jnlpool.repl_inst_filehdr->jnlpool_shmid,
DB_LEN_STR(reg), LEN_AND_STR(csa->nl->replinstfilename), csa->nl->jnlpool_shmid);
}
@@ -1119,10 +1155,10 @@ void db_init(gd_region *reg)
/* Record ftok information as soon as shared memory set up is done */
if (!have_standalone_access && !bypassed_ftok)
FTOK_TRACE(csa, csd->trans_hist.curr_tn, ftok_ops_lock, process_id);
- if (-1 == (semval = semctl(udi->semid, 1, GETVAL))) /* semval = number of process attached */
+ if (-1 == (semval = semctl(udi->semid, DB_COUNTER_SEM, GETVAL))) /* semval = number of process attached */
{
save_errno = errno;
- rts_error(VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5, \
+ RTS_ERROR(VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5, \
RTS_ERROR_LITERAL("semctl()"), CALLFROM, save_errno);
}
if (!read_only && (1 == semval) && !bypassed_ftok && !bypassed_access)
@@ -1141,7 +1177,7 @@ void db_init(gd_region *reg)
DB_LSEEKWRITE(csa, udi->fn, udi->fd, (off_t)0, (sm_uc_ptr_t)csd, SIZEOF(sgmnt_data), save_errno);
if (0 != save_errno)
{
- rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg),
+ RTS_ERROR(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg),
ERR_TEXT, 2, LEN_AND_LIT("Error with database header flush"), save_errno);
}
} else if (read_only && new_shm_ipc)
@@ -1157,7 +1193,7 @@ void db_init(gd_region *reg)
db_ipcs.fn[reg->dyn.addr->fname_len] = 0;
WAIT_FOR_REPL_INST_UNFREEZE_SAFE(csa);
if (0 != send_mesg2gtmsecshr(FLUSH_DB_IPCS_INFO, 0, (char *)NULL, 0))
- rts_error(VARLSTCNT(8) ERR_DBFILERR, 2, DB_LEN_STR(reg),
+ RTS_ERROR(VARLSTCNT(8) ERR_DBFILERR, 2, DB_LEN_STR(reg),
ERR_TEXT, 2, LEN_AND_LIT("gtmsecshr failed to update database file header"));
}
@@ -1188,14 +1224,13 @@ void db_init(gd_region *reg)
} else
{
save_errno = errno;
- send_msg(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fstatvfs"), CALLFROM, save_errno);
+ SEND_MSG(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fstatvfs"), CALLFROM, save_errno);
}
}
++csa->nl->ref_cnt; /* This value is changed under control of the init/rundown semaphore only */
assert(!csa->ref_cnt); /* Increment shared ref_cnt before private ref_cnt increment. */
csa->ref_cnt++; /* Currently journaling logic in gds_rundown() in VMS relies on this order to detect last writer */
-# ifdef DEBUG
- if (!IS_GTM_IMAGE && gtm_white_box_test_case_enabled && (WBTEST_HOLD_SEM_BYPASS == gtm_white_box_test_case_number))
+ if (WBTEST_ENABLED(WBTEST_HOLD_SEM_BYPASS) && !IS_GTM_IMAGE)
{
if (0 == csa->nl->wbox_test_seq_num)
{
@@ -1205,38 +1240,31 @@ void db_init(gd_region *reg)
LONG_SLEEP(1);
}
}
-# endif
if (!have_standalone_access && !jgbl.onlnrlbk && !bypassed_access)
{
/* Release control lockout now that it is init'd */
- if (0 != (save_errno = do_semop(udi->semid, 0, -1, SEM_UNDO)))
+ if (0 != (save_errno = do_semop(udi->semid, DB_CONTROL_SEM, -1, SEM_UNDO)))
{
save_errno = errno;
- rts_error(VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5, \
+ RTS_ERROR(VARLSTCNT(12) ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), ERR_SYSCALL, 5, \
RTS_ERROR_LITERAL("semop()"), CALLFROM, save_errno);
}
udi->grabbed_access_sem = FALSE;
}
-# ifdef DEBUG
- if (gtm_white_box_test_case_enabled && (WBTEST_SEMTOOLONG_STACK_TRACE == gtm_white_box_test_case_number) \
- && (1 == csa->nl->wbox_test_seq_num))
+ if (WBTEST_ENABLED(WBTEST_SEMTOOLONG_STACK_TRACE) && (1 == csa->nl->wbox_test_seq_num))
{
csa->nl->wbox_test_seq_num = 2;
/* Wait till the other process has got some stack traces */
while (csa->nl->wbox_test_seq_num != 3)
LONG_SLEEP(10);
}
-# endif
if (!have_standalone_access && !bypassed_ftok)
{ /* Release ftok semaphore lock so that any other ftok conflicted database can continue now */
if (!ftok_sem_release(reg, FALSE, FALSE))
- rts_error(VARLSTCNT(4) ERR_DBFILERR, 2, DB_LEN_STR(reg));
+ RTS_ERROR(VARLSTCNT(4) ERR_DBFILERR, 2, DB_LEN_STR(reg));
FTOK_TRACE(csa, csd->trans_hist.curr_tn, ftok_ops_release, process_id);
+ udi->grabbed_ftok_sem = FALSE;
}
- /* Do the per process initialization of mutex stuff */
- assert(!mutex_per_process_init_pid || mutex_per_process_init_pid == process_id);
- if (!mutex_per_process_init_pid)
- mutex_per_process_init();
REVERT;
- return;
+ return 0;
}
diff --git a/sr_unix/heartbeat_timer.c b/sr_unix/heartbeat_timer.c
index 83186cc..ab14edb 100644
--- a/sr_unix/heartbeat_timer.c
+++ b/sr_unix/heartbeat_timer.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -34,10 +34,11 @@
#ifdef DEBUG
STATICDEF uint4 next_heartbeat_counter = 1; /* the heartbeat_counter at which enospc manipulations need to happen */
-GBLDEF boolean_t is_jnlpool_creator; /* The purpose of this check is to assign only one process responsible of
+GBLREF boolean_t is_jnlpool_creator; /* The purpose of this check is to assign only one process responsible of
* setting fake ENOSPC flags. If we had multiple processes messing with FREEZE,
* the test would freeze more often and eventually do nothing but freeze.
*/
+STATICDEF uint4 syslog_deferred = 0;
#endif
GBLREF volatile uint4 heartbeat_counter;
@@ -45,110 +46,133 @@ GBLREF boolean_t is_src_server;
GBLREF enum gtmImageTypes image_type;
GBLREF uint4 process_id;
GBLREF jnlpool_addrs jnlpool;
-
+GBLREF volatile int4 gtmMallocDepth;
#ifdef DEBUG
-#define ENOSPC_GOOD_TO_BAD 2 /* 16 seconds */
-#define ENOSPC_BAD_TO_GOOD (2 * (rand() % 120 + 1)) /* 64 minutes */
+#define ENOSPC_FROZEN_DURATION 2 /* 16 seconds */
+#define ENOSPC_UNFROZEN_DURATION (2 * (rand() % 120 + 1)) /* 16 seconds to 32 minutes */
+#define MAX_REGIONS 50
+
+#define NONE 0 /* 1/2 probablility */
+#define DB_ON 1 /* 1/6 probablility */
+#define JNL_ON 2 /* 1/6 probablility */
+#define DB_AND_JNL_ON 3 /* 1/6 probablility */
+#define MAX_ENOSPC_TARGET 4
error_def(ERR_TEXT);
+error_def(ERR_FAKENOSPCLEARED);
-char choose_random_reg_list(char *enospc_enable_list, int n_reg)
+void choose_random_reg_list(char *enospc_enable_list, int n_reg)
{
- char count;
- int target, i;
+ int i;
- assert(n_reg <= 50);
- count = rand() % n_reg + 1;
- for (i = count; 0 < i; i--)
+ assert(MAX_REGIONS >= n_reg);
+ for (i = 0; i < n_reg; i++)
{
- target = rand() % n_reg;
- /* JNL or DAT or BOTH? */
- enospc_enable_list[target] = rand() % 3 + 1;
+ if(rand() % 2) /* Should we trigger fake ENOSPC on this region */
+ enospc_enable_list[i] = rand() % (MAX_ENOSPC_TARGET - 1) + 1; /* What kind? */
+ else
+ enospc_enable_list[i] = NONE;
}
- return count;
}
void set_enospc_if_needed()
{
- int i;
- char enospc_enable_list[50]; /* JNL or DAT or BOTH? 0:NONE 1:DAT 2:JNL 3: BOTH */
- gd_addr *addr_ptr;
- gd_region *r_local, *r_top;
- sgmnt_addrs *csa;
+ gd_addr *addr_ptr;
+ char enospc_enable_list[MAX_REGIONS];
+ boolean_t ok_to_interrupt, is_time_to_act;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
- if (TREF(gtm_test_fake_enospc) && is_jnlpool_creator && ANTICIPATORY_FREEZE_AVAILABLE
- && (next_heartbeat_counter == heartbeat_counter))
+
+ if (TREF(gtm_test_fake_enospc) && is_jnlpool_creator && ANTICIPATORY_FREEZE_AVAILABLE)
{
+ ok_to_interrupt = (INTRPT_OK_TO_INTERRUPT == intrpt_ok_state) && (0 == gtmMallocDepth);
+ is_time_to_act = (next_heartbeat_counter == heartbeat_counter);
+ if (syslog_deferred && ok_to_interrupt)
+ {
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_FAKENOSPCLEARED, 1, (heartbeat_counter - syslog_deferred));
+ syslog_deferred = 0;
+ }
+ if (!is_time_to_act || syslog_deferred || (!ok_to_interrupt && !IS_REPL_INST_FROZEN))
+ {
+ /* We have to skip this because we have just fallen into deferred zone or we are currently in it */
+ if (is_time_to_act)
+ next_heartbeat_counter++; /* Try again in the next heartbeat */
+ return;
+ }
+ assert(0 == syslog_deferred);
srand(time(NULL));
- for (addr_ptr = get_next_gdr(NULL); addr_ptr; addr_ptr = get_next_gdr(addr_ptr))
- { /* Randomly simulate ENOSPC or free up space NO more than 50 regions are allowed. That is do to avoid
- * malloc/free
- */
- memset(enospc_enable_list, 0, 50);
- assert(addr_ptr->n_regions <= 50);
- /* Make sure to turn off FAKE ENOSPC for all regions if it is already on, otherwise test takes too long
- * time.
- */
- if (!IS_REPL_INST_FROZEN)
- {
- /* We are in GOOD state, going to BAD state, means we will be frozen due to ENOSPC */
- choose_random_reg_list(enospc_enable_list, addr_ptr->n_regions);
- next_heartbeat_counter = heartbeat_counter + ENOSPC_GOOD_TO_BAD;
- }
- else
- /* We are in BAD state, going to GOOD state, means disk space will be available */
- next_heartbeat_counter = heartbeat_counter + ENOSPC_BAD_TO_GOOD;
- for (r_local = addr_ptr->regions, r_top = r_local + addr_ptr->n_regions, i = 0;
- r_local < r_top; r_local++, i++)
- {
- /* This assert checks each enospc_enable_list element is a valid one. See the enospc_enable_list
- * declaration above to see what values it can take and what they mean.
- */
- assert((enospc_enable_list[i] < 4) && (enospc_enable_list[i] >= 0));
- if (!r_local->open || r_local->was_open)
- continue;
- if ((dba_bg != r_local->dyn.addr->acc_meth) && (dba_mm != r_local->dyn.addr->acc_meth))
- continue;
- csa = &FILE_INFO(r_local)->s_addrs;
- if (ANTICIPATORY_FREEZE_ENABLED(csa))
- {
- switch(enospc_enable_list[i])
- {
- case 0:
- send_msg(VARLSTCNT(8) ERR_TEXT, 2, DB_LEN_STR(r_local), ERR_TEXT, 2,
- LEN_AND_LIT("Turning off fake ENOSPC for both database and journal file.")
- );
- csa->nl->fake_db_enospc = FALSE;
- csa->nl->fake_jnl_enospc = FALSE;
- break;
- case 1:
- send_msg(VARLSTCNT(8) ERR_TEXT, 2, DB_LEN_STR(r_local), ERR_TEXT, 2,
- LEN_AND_LIT("Turning on fake ENOSPC only for database file."));
- csa->nl->fake_db_enospc = TRUE;
- csa->nl->fake_jnl_enospc = FALSE;
- break;
- case 2:
- send_msg(VARLSTCNT(8) ERR_TEXT, 2, DB_LEN_STR(r_local), ERR_TEXT, 2,
- LEN_AND_LIT("Turning on fake ENOSPC only for journal file."));
- csa->nl->fake_db_enospc = FALSE;
- csa->nl->fake_jnl_enospc = TRUE;
- break;
- case 3:
- send_msg(VARLSTCNT(8) ERR_TEXT, 2, DB_LEN_STR(r_local), ERR_TEXT, 2,
- LEN_AND_LIT("Turning on fake ENOSPC for both database and journal file."));
- csa->nl->fake_db_enospc = TRUE;
- csa->nl->fake_jnl_enospc = TRUE;
- break;
- default:
- assert(FALSE);
- }
+ addr_ptr = get_next_gdr(NULL);
+ if (NULL == addr_ptr) /* Ensure that there is a global directory to operate on. */
+ return;
+ assert(NULL == get_next_gdr(addr_ptr));
+ /* Randomly simulate ENOSPC or free space. NO more than 50 regions are allowed to avoid unnecessary
+ * malloc/frees in debug-only code
+ */
+ assert(MAX_REGIONS >= addr_ptr->n_regions);
+ if (!IS_REPL_INST_FROZEN)
+ { /* We are in an UNFROZEN state, and about to be FROZEN due to ENOSPC */
+ choose_random_reg_list(enospc_enable_list, addr_ptr->n_regions);
+ next_heartbeat_counter = heartbeat_counter + ENOSPC_FROZEN_DURATION;
+ } else
+ { /* We are in a FROZEN state, and about to be UNFROZEN due to free space */
+ memset(enospc_enable_list, 0, MAX_REGIONS);
+ next_heartbeat_counter = heartbeat_counter + ENOSPC_UNFROZEN_DURATION;
+ if (!ok_to_interrupt)
+ syslog_deferred = heartbeat_counter;
+ }
+ set_enospc_flags(addr_ptr, enospc_enable_list, ok_to_interrupt);
+ }
+}
- }
+void set_enospc_flags(gd_addr *addr_ptr, char enospc_enable_list[], boolean_t ok_to_interrupt)
+{
+ gd_region *r_local, *r_top;
+ int i;
+ sgmnt_addrs *csa;
+ const char *syslog_msg;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+
+ for (r_local = addr_ptr->regions, r_top = r_local + addr_ptr->n_regions, i = 0;
+ r_local < r_top; r_local++, i++)
+ {
+ if ((dba_bg != r_local->dyn.addr->acc_meth) && (dba_mm != r_local->dyn.addr->acc_meth))
+ continue;
+ csa = REG2CSA(r_local);
+ if ((NULL != csa) && (NULL != csa->nl) && ANTICIPATORY_FREEZE_ENABLED(csa))
+ {
+ switch(enospc_enable_list[i])
+ {
+ case NONE:
+ syslog_msg = "Turning off fake ENOSPC for both database and journal file.";
+ csa->nl->fake_db_enospc = FALSE;
+ csa->nl->fake_jnl_enospc = FALSE;
+ break;
+ case DB_ON:
+ syslog_msg = "Turning on fake ENOSPC only for database file.";
+ csa->nl->fake_db_enospc = TRUE;
+ csa->nl->fake_jnl_enospc = FALSE;
+ break;
+ case JNL_ON:
+ syslog_msg = "Turning on fake ENOSPC only for journal file.";
+ csa->nl->fake_db_enospc = FALSE;
+ csa->nl->fake_jnl_enospc = TRUE;
+ break;
+ case DB_AND_JNL_ON:
+ syslog_msg = "Turning on fake ENOSPC for both database and journal file.";
+ csa->nl->fake_db_enospc = TRUE;
+ csa->nl->fake_jnl_enospc = TRUE;
+ break;
+ default:
+ assert(FALSE);
}
+ if (ok_to_interrupt)
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_TEXT, 2, DB_LEN_STR(r_local), ERR_TEXT, 2,
+ LEN_AND_STR(syslog_msg));
}
}
}
@@ -167,9 +191,7 @@ void heartbeat_timer(void)
/* It will take heartbeat_counter about 1014 years to overflow. */
heartbeat_counter++;
-# ifdef DEBUG
- set_enospc_if_needed();
-# endif
+ DEBUG_ONLY(set_enospc_if_needed());
/* Check every 1 minute if we have an older generation journal file open. If so, close it.
* The only exceptions are
* a) The source server can have older generations open and they should not be closed.
@@ -190,7 +212,7 @@ void heartbeat_timer(void)
continue;
if ((dba_bg != r_local->dyn.addr->acc_meth) && (dba_mm != r_local->dyn.addr->acc_meth))
continue;
- csa = &FILE_INFO(r_local)->s_addrs;
+ csa = REG2CSA(r_local);
if (csa->now_crit)
continue;
jpc = csa->jnl;
diff --git a/sr_unix/heartbeat_timer.h b/sr_unix/heartbeat_timer.h
index c9569f3..0b0be3c 100644
--- a/sr_unix/heartbeat_timer.h
+++ b/sr_unix/heartbeat_timer.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -40,6 +40,10 @@ void heartbeat_timer(void);
#endif
#ifdef DEBUG
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
void set_enospc_if_needed(void);
-char choose_random_reg_list(char *enospc_enable_list, int);
+void choose_random_reg_list(char *enospc_enable_list, int);
+void set_enospc_flags(gd_addr *addr_ptr, char enospc_enable_list[], boolean_t ok_to_interrupt);
#endif
diff --git a/sr_unix/hpuxia64_badd.txt b/sr_unix/hpuxia64_badd.txt
index 8434d1e..29fecc1 100644
--- a/sr_unix/hpuxia64_badd.txt
+++ b/sr_unix/hpuxia64_badd.txt
@@ -1,6 +1,6 @@
#################################################################
# #
-# Copyright 2012 Fidelity Information Services, Inc #
+# Copyright 2012, 2013 Fidelity Information Services, Inc #
# #
# This source code contains the intellectual property #
# of its copyright holder(s), and is made available #
@@ -30,4 +30,9 @@ zzz_insert%-r--r----- source.tar
pro/utf8:
TTTGEN.m -> ../TTTGEN.m%lrwxr-xr-x README.txt -> ../README.txt
dse -> ../dse%lrwxr-xr-x custom_errors_sample.txt -> ../custom_errors_sample.txt
+gtmstart.gtc -> ../gtmstart.gtc%-r-sr-x--- gtmsecshr
+gtmstart.gtc -> ../gtmstart.gtc%dr-x------ gtmsecshrdir
lke -> ../lke%-r-xr-x--- libgtmutil.so
+
+pro/utf8/gtmsecshrdir:
+zzz_insert%-r-s------ gtmsecshr
diff --git a/sr_unix/hpuxparisc_badd.txt b/sr_unix/hpuxparisc_badd.txt
index d5290b5..b9c9f69 100644
--- a/sr_unix/hpuxparisc_badd.txt
+++ b/sr_unix/hpuxparisc_badd.txt
@@ -1,6 +1,6 @@
#################################################################
# #
-# Copyright 2011, 2012 Fidelity Information Services, Inc #
+# Copyright 2011, 2013 Fidelity Information Services, Inc #
# #
# This source code contains the intellectual property #
# of its copyright holder(s), and is made available #
@@ -21,14 +21,12 @@ gtmsecshr%-r-xr-x--- gtmprofile_preV54000
lke%-r-xr-x--- libgtmutil.sl
semstat2%dr-xr-x--- plugin
-pro/plugin:
-zzz_insert%dr-xr-x--- o
-zzz_insert%dr-xr-x--- r
-
-pro/plugin/gtmcrypt:
-zzz_insert%-r--r----- source.tar
-
pro/utf8:
TTTGEN.m -> ../TTTGEN.m%lrwxr-xr-x README.txt -> ../README.txt
dse -> ../dse%lrwxr-xr-x custom_errors_sample.txt -> ../custom_errors_sample.txt
+gtmstart.gtc -> ../gtmstart.gtc%-r-sr-x--- gtmsecshr
+gtmstart.gtc -> ../gtmstart.gtc%dr-x------ gtmsecshrdir
lke -> ../lke%-r-xr-x--- libgtmutil.sl
+
+pro/utf8/gtmsecshrdir:
+zzz_insert%-r-s------ gtmsecshr
diff --git a/sr_unix/incr_link.c b/sr_unix/incr_link.c
index 4b45ff9..8e4a75a 100644
--- a/sr_unix/incr_link.c
+++ b/sr_unix/incr_link.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -113,6 +113,7 @@ bool incr_link (int file_desc, zro_ent *zro_entry)
pre_v5_mident *pre_v5_routine_name;
urx_rtnref urx_lcl_anchor;
int order;
+ boolean_t dynlits;
size_t offset_correction;
unsigned char *shdr, *rel_base;
mval *curlit, *littop;
@@ -121,6 +122,7 @@ bool incr_link (int file_desc, zro_ent *zro_entry)
char name_buf[PATH_MAX+1];
int name_buf_len, alloc_len;
char marker[SIZEOF(JSB_MARKER) - 1];
+ char *rw_rel_start;
AIX_ONLY(
FILHDR hddr;
@@ -296,11 +298,13 @@ bool incr_link (int file_desc, zro_ent *zro_entry)
*
* Read-only releasable section
*/
+ dynlits = DYNAMIC_LITERALS_ENABLED(hdr);
+ rw_rel_start = RW_REL_START_ADR(hdr); /* Marks end of R/O-release section and start of R/W-release section */
if (shlib)
rel_base = shdr;
else
{
- sect_ro_rel_size = (unsigned int)((INTPTR_T)hdr->literal_adr - (INTPTR_T)hdr->ptext_adr);
+ sect_ro_rel_size = (unsigned int)((INTPTR_T)rw_rel_start - (INTPTR_T)hdr->ptext_adr);
sect_ro_rel = GTM_TEXT_ALLOC(sect_ro_rel_size);
/* It should be aligned well at this point but make a debug level check to verify */
assert((INTPTR_T)sect_ro_rel == ((INTPTR_T)sect_ro_rel & ~(LINKAGE_PSECT_BOUNDARY - 1)));
@@ -336,20 +340,23 @@ bool incr_link (int file_desc, zro_ent *zro_entry)
RELOCATE(hdr->ptext_end_adr, unsigned char *, rel_base);
RELOCATE(hdr->lnrtab_adr, lnr_tabent *, rel_base);
RELOCATE(hdr->literal_text_adr, unsigned char *, rel_base);
+ if (dynlits)
+ RELOCATE(hdr->literal_adr, mval *, rel_base);
/* Read-write releasable section */
- sect_rw_rel_size = (int)((INTPTR_T)hdr->labtab_adr - (INTPTR_T)hdr->literal_adr);
+ sect_rw_rel_size = (int)((INTPTR_T)hdr->labtab_adr - (INTPTR_T)rw_rel_start);
sect_rw_rel = malloc(sect_rw_rel_size);
if (shlib)
- memcpy(sect_rw_rel, shdr + (INTPTR_T)hdr->literal_adr, sect_rw_rel_size);
+ memcpy(sect_rw_rel, shdr + (INTPTR_T)rw_rel_start, sect_rw_rel_size);
else
{
DOREADRC_OBJFILE(file_desc, sect_rw_rel, sect_rw_rel_size, status);
if (0 != status)
zl_error(file_desc, zro_entry, ERR_INVOBJ, 0, 0, 0, 0);
}
- offset_correction = (size_t)hdr->literal_adr;
+ offset_correction = (size_t)rw_rel_start;
rel_base = sect_rw_rel - offset_correction;
- RELOCATE(hdr->literal_adr, mval *, rel_base);
+ if (!dynlits)
+ RELOCATE(hdr->literal_adr, mval *, rel_base);
RELOCATE(hdr->vartab_adr, var_tabent *, rel_base);
/* Also read-write releasable is the linkage section which had no initial value and was thus
* not resident in the object. The values in this section will be setup later by addr_fix()
@@ -366,9 +373,12 @@ bool incr_link (int file_desc, zro_ent *zro_entry)
* variable table entries since they both point to the offsets from the beginning of the
* literal text pool. The relocations for the linkage section is done in addr_fix()
*/
- for (curlit = hdr->literal_adr, littop = curlit + hdr->literal_len; curlit < littop; ++curlit)
- if (curlit->str.len)
- RELOCATE(curlit->str.addr, char *, hdr->literal_text_adr);
+ if (!dynlits)
+ {
+ for (curlit = hdr->literal_adr, littop = curlit + hdr->literal_len; curlit < littop; ++curlit)
+ if (curlit->str.len)
+ RELOCATE(curlit->str.addr, char *, hdr->literal_text_adr);
+ }
for (curvar = hdr->vartab_adr, vartop = curvar + hdr->vartab_len; curvar < vartop; ++curvar)
{
assert(0 < curvar->var_name.len);
@@ -466,6 +476,8 @@ bool incr_link (int file_desc, zro_ent *zro_entry)
old_rhead->temp_size = hdr->temp_size;
old_rhead->linkage_adr = hdr->linkage_adr;
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 = (rhdtyp *)old_rhead->old_rhead_adr;
}
/* Add local unresolves to global chain freeing elements that already existed in the global chain */
diff --git a/sr_unix/init_gtm.c b/sr_unix/init_gtm.c
index 33d36dd..7b1a824 100644
--- a/sr_unix/init_gtm.c
+++ b/sr_unix/init_gtm.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -11,8 +11,12 @@
#include "mdef.h"
+#ifdef GTM_PTHREAD
+# include <pthread.h>
+#endif
#include "gtm_stdlib.h"
#include "gtm_string.h"
+
#include "startup.h"
#include <rtnhdr.h>
#include "stack_frame.h"
@@ -37,6 +41,7 @@
#include "gtm_malloc.h"
#include "stp_parms.h"
#include "create_fatal_error_zshow_dmp.h"
+#include "mtables.h"
GBLREF void (*ctrlc_handler_ptr)();
GBLREF void (*tp_timeout_action_ptr)(void);
@@ -48,6 +53,11 @@ GBLREF void (*op_wteol_ptr)(int4 n);
GBLREF void (*unw_prof_frame_ptr)(void);
GBLREF mstr default_sysid;
+#ifdef GTM_PTHREAD
+GBLREF pthread_t gtm_main_thread_id;
+GBLREF boolean_t gtm_main_thread_id_set;
+GBLREF boolean_t gtm_jvm_process;
+#endif
GBLDEF boolean_t gtm_startup_active = FALSE;
void init_gtm(void)
@@ -80,8 +90,17 @@ void init_gtm(void)
assert(SIZEOF(mval) == SIZEOF(mval_b));
assert(SIZEOF(chkmval.fnpc_indx) == SIZEOF(chkmval_b.fnpc_indx));
assert(OFFSETOF(mval, fnpc_indx) == OFFSETOF(mval_b, fnpc_indx));
+ DEBUG_ONLY(mtables_chk()); /* Validate mtables.c assumptions */
SFPTR(create_fatal_error_zshow_dmp_fptr, create_fatal_error_zshow_dmp);
+# ifdef GTM_PTHREAD
+ assert(!gtm_main_thread_id_set);
+ if (!gtm_main_thread_id_set && gtm_jvm_process)
+ {
+ gtm_main_thread_id = pthread_self();
+ gtm_main_thread_id_set = TRUE;
+ }
+# endif
tp_timeout_start_timer_ptr = tp_start_timer;
tp_timeout_clear_ptr = tp_clear_timeout;
tp_timeout_action_ptr = tp_timeout_action;
diff --git a/sr_unix/interlock.h b/sr_unix/interlock.h
index 12ea2b7..3125629 100644
--- a/sr_unix/interlock.h
+++ b/sr_unix/interlock.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -44,9 +44,6 @@
}
/* On HPPA, SET_LATCH_GLOBAL forces its available value, for others it is the same as SET_LATCH */
-#define INTERLOCK_INIT_MM(X) (SET_LATCH((sm_int_ptr_t)&((X)->interlock.latch), LATCH_CLEAR))
- /* similar to INTERLOCK_INIT except this is for a mmblk_rec */
-
/* New buffer doesn't need interlocked operation. */
#define LOCK_NEW_BUFF_FOR_UPDATE(X) (SET_LATCH((sm_int_ptr_t)&((X)->interlock.latch), LATCH_SET))
@@ -96,13 +93,13 @@
#define INCR_CNT(X,Y) INTERLOCK_ADD(X,Y,1)
#define DECR_CNT(X,Y) INTERLOCK_ADD(X,Y,-1)
-#ifndef __ia64
+#if !defined(__ia64) && !defined(__x86_64__) && !defined(__sparc)
#define GET_SWAPLOCK(X) (COMPSWAP_LOCK((X), LOCK_AVAILABLE, 0, process_id, 0))
#else
/* Doing the simple test before COMPSWAP_LOCK can help performance when a lock is highly contended
*/
#define GET_SWAPLOCK(X) (((X)->u.parts.latch_pid == LOCK_AVAILABLE) && COMPSWAP_LOCK((X), LOCK_AVAILABLE, 0, process_id, 0))
-#endif /* __ia64 */
+#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
diff --git a/sr_unix/io_open_try.c b/sr_unix/io_open_try.c
index b8be824..bbb3d40 100644
--- a/sr_unix/io_open_try.c
+++ b/sr_unix/io_open_try.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -16,8 +16,10 @@
#include "gtm_unistd.h"
#include "gtm_stat.h"
#include "gtm_iconv.h"
+#include "gtm_netdb.h"
#include "gtm_socket.h"
#include "gtm_inet.h"
+#include "gtm_stdlib.h"
#include <errno.h>
#include <sys/ioctl.h>
@@ -59,8 +61,9 @@ GBLREF int4 outofband;
GBLREF int4 write_filter;
LITREF mstr chset_names[];
+error_def(ERR_GETNAMEINFO);
error_def(ERR_GTMEISDIR);
-
+error_def(ERR_TEXT);
bool io_open_try(io_log_name *naml, io_log_name *tl, mval *pp, int4 timeout, mval *mspace) /* timeout in seconds */
{
@@ -97,9 +100,12 @@ bool io_open_try(io_log_name *naml, io_log_name *tl, mval *pp, int4 timeout, mva
int sockstat, sockoptval;
in_port_t sockport;
GTM_SOCKLEN_TYPE socknamelen;
- struct sockaddr_in sockname;
+ struct sockaddr_storage sockname;
GTM_SOCKLEN_TYPE sockoptlen;
boolean_t ichset_specified, ochset_specified;
+ int errcode;
+ unsigned int port_len;
+ char port_buffer[NI_MAXSERV], *port_ptr;
mt_ptr = NULL;
char_or_block_special = FALSE;
@@ -270,9 +276,19 @@ bool io_open_try(io_log_name *naml, io_log_name *tl, mval *pp, int4 timeout, mva
sockstat = getsockname(file_des,
(struct sockaddr *)&sockname,
(GTM_SOCKLEN_TYPE *)&socknamelen);
- if (!sockstat && AF_INET == sockname.sin_family)
+ if (!sockstat && ((AF_INET == ((sockaddr_ptr)&sockname)->sa_family)
+ || (AF_INET6 == ((sockaddr_ptr)&sockname)->sa_family)))
{
- sockport = ntohs(sockname.sin_port);
+ port_len = NI_MAXSERV;
+ if (0 != (errcode = getnameinfo((struct sockaddr *)&sockname,
+ socknamelen, NULL, 0,
+ port_buffer, port_len,
+ NI_NUMERICHOST)))
+ {
+ RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode);
+ return FALSE;
+ }
+ sockport=atoi(port_buffer);
if (RSHELL_PORT != sockport && KSHELL_PORT != sockport)
{
tl->iod->type = gtmsocket;
@@ -375,13 +391,13 @@ bool io_open_try(io_log_name *naml, io_log_name *tl, mval *pp, int4 timeout, mva
/* Check the saved error from mknod() for fifo, also saved error from fstat() or stat()
so error handler (if set) can handle it */
if (ff == tl->iod->type && mknod_err)
- rts_error(VARLSTCNT(1) save_mknod_err);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) save_mknod_err);
/* Error from either stat() or fstat() function */
if (stat_err)
- rts_error(VARLSTCNT(1) save_stat_err);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) save_stat_err);
/* Error from trying to open a dir */
if (dir_err)
- rts_error(VARLSTCNT(4) ERR_GTMEISDIR, 2, LEN_AND_STR(buf));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_GTMEISDIR, 2, LEN_AND_STR(buf));
if (timed)
@@ -493,7 +509,7 @@ bool io_open_try(io_log_name *naml, io_log_name *tl, mval *pp, int4 timeout, mva
}
#endif
if (-1 == file_des)
- rts_error(VARLSTCNT(1) errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) errno);
if (n_io_dev_types == naml->iod->type)
{
@@ -529,6 +545,8 @@ bool io_open_try(io_log_name *naml, io_log_name *tl, mval *pp, int4 timeout, mva
naml->iod->dollar.y = 0;
naml->iod->dollar.za = 0;
naml->iod->dollar.zb[0] = 0;
+ naml->iod->dollar.key[0] = 0;
+ naml->iod->dollar.device[0] = 0;
}
#ifdef __MVS__
/* copy over the content of tl->iod(naml->iod) to (tl->iod->pair.out) */
@@ -568,7 +586,7 @@ bool io_open_try(io_log_name *naml, io_log_name *tl, mval *pp, int4 timeout, mva
{
if ((dev_open == naml->iod->state) && (gtmsocket != naml->iod->type))
naml->iod->state = dev_closed;
- if((gtmsocket == naml->iod->type) && naml->iod->newly_created)
+ if ((gtmsocket == naml->iod->type) && naml->iod->newly_created)
{
assert (naml->iod->state != dev_open);
iosocket_destroy(naml->iod);
diff --git a/sr_unix/iopi_iocontrol.c b/sr_unix/iopi_iocontrol.c
index ce6999a..a587e50 100644
--- a/sr_unix/iopi_iocontrol.c
+++ b/sr_unix/iopi_iocontrol.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2008, 2012 Fidelity Information Services, Inc *
+ * Copyright 2008, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -64,7 +64,7 @@ void iopi_iocontrol(mstr *d)
CLOSEFILE_RESET(d_rm->fildes, rc); /* resets "d_rm->fildes" to FD_INVALID */
}
} else
- rts_error(VARLSTCNT(1) ERR_INVCTLMNE);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INVCTLMNE);
return;
}
@@ -72,15 +72,13 @@ void iopi_dlr_device(mstr *d)
{
io_desc *iod;
int len;
- d_rm_struct *d_rm;
/* We will default to the output device for setting $device, since pipe uses both */
iod = io_curr_device.out;
- d_rm = (d_rm_struct *)iod->dev_sp;
- len = STRLEN(d_rm->dollar_device);
+ len = STRLEN(iod->dollar.device);
/* verify internal buffer has enough space for $DEVICE string value */
assert((int)d->len > len);
- memcpy(d->addr, d_rm->dollar_device, MIN(len,d->len));
+ memcpy(d->addr, iod->dollar.device, MIN(len,d->len));
d->len = len;
return;
}
@@ -89,16 +87,14 @@ void iopi_dlr_key(mstr *d)
{
io_desc *iod;
int len;
- d_rm_struct *d_rm;
iod = io_curr_device.out;
- d_rm = (d_rm_struct *)iod->dev_sp;
- len = STRLEN(d_rm->dollar_key);
+ len = STRLEN(iod->dollar.key);
/* verify internal buffer has enough space for $KEY string value */
assert((int)d->len > len);
if (len > 0)
- memcpy(d->addr, d_rm->dollar_key, MIN(len,d->len));
+ memcpy(d->addr, iod->dollar.key, MIN(len,d->len));
d->len = len;
return;
}
diff --git a/sr_unix/iopi_open.c b/sr_unix/iopi_open.c
index 2e51e1c..8f47bfc 100644
--- a/sr_unix/iopi_open.c
+++ b/sr_unix/iopi_open.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2008, 2012 Fidelity Information Services, Inc *
+ * Copyright 2008, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -8,7 +8,9 @@
* the license, please stop and do not read further. *
* *
****************************************************************/
-#define _REENTRANT
+#ifndef _REENTRANT
+# define _REENTRANT
+#endif
#include "mdef.h"
@@ -30,6 +32,8 @@
#include "gtmio.h"
#include "iosp.h"
#include "jobsp.h"
+#include "have_crit.h"
+#include "fork_init.h"
#ifdef __MVS__
#include "gtm_zos_io.h"
#include "gtm_zos_chset.h"
@@ -97,7 +101,7 @@ int parse_pipe(char *cmd_string, char *ret_token);
*/
int parse_pipe(char *cmd_string, char *ret_token)
{
- char *str1, *str2, *str3, *token;
+ char *str1, *str2, *str3;
char *saveptr1, *saveptr2, *saveptr3;
char *env_var;
int env_inc;
@@ -348,10 +352,10 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
{
PIPE_ERROR_INIT();
if (0 == sparams[PCOMMAND])
- rts_error(VARLSTCNT(8) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io,
ERR_TEXT, 2, LEN_AND_LIT("Missing command string"));
else
- rts_error(VARLSTCNT(8) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io,
ERR_TEXT, 2, LEN_AND_LIT("Command string has no value"));
} else
{
@@ -364,7 +368,7 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
{
PIPE_ERROR_INIT();
SPRINTF(error_str, "%s%s", INVALID_CMD, ret_token);
- rts_error(VARLSTCNT(8) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io,
+ 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));
}
}
@@ -375,7 +379,7 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
if (sparams[PSHELL] && (0 == slen[PSHELL]))
{
PIPE_ERROR_INIT();
- rts_error(VARLSTCNT(8) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io,
ERR_TEXT, 2, LEN_AND_LIT("SHELL parameter has no value"));
} else if (0 != slen[PSHELL])
{
@@ -390,7 +394,7 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
assert(GTM_MAX_DIR_LEN - 1 >= STRLEN(pshell));
SPRINTF(error_str, "Invalid shell: %s", pshell);
PIPE_ERROR_INIT();
- rts_error(VARLSTCNT(8) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io,
+ 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));
}
pshell_name = basename(pshell);
@@ -401,7 +405,7 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
if (sparams[PSTDERR] && (0 == slen[PSTDERR]))
{
PIPE_ERROR_INIT();
- rts_error(VARLSTCNT(8) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io,
ERR_TEXT, 2, LEN_AND_LIT("STDERR parameter has no value"));
} else if (0 != slen[PSTDERR])
{
@@ -416,7 +420,7 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
{
save_errno = errno;
PIPE_ERROR_INIT();
- rts_error(VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io,
+ 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 - pipe(pfd_write) failed"), save_errno);
} else
{
@@ -431,11 +435,12 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
/* child to write stdout (and possibly stderr) to pfd_read[1] and parent to read from pfd_read[0] */
if (return_stdout)
+ {
if (-1 == pipe(pfd_read))
{
save_errno = errno;
PIPE_ERROR_INIT();
- rts_error(VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io,
+ 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 - pipe(pfd_read) failed"), save_errno);
} else
{
@@ -446,14 +451,16 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
#endif
file_des_read = pfd_read[0];
}
+ }
/* child to write to pfd_read_stderr[1] and parent to read from pfd_read_stderr[0] */
if (return_stderr)
+ {
if (-1 == pipe(pfd_read_stderr))
{
save_errno = errno;
PIPE_ERROR_INIT();
- rts_error(VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io,
+ 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 - pipe(pfd_read_stderr) failed"), save_errno);
} else
{
@@ -465,15 +472,15 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
#endif
file_des_read_stderr = pfd_read_stderr[0];
}
-
+ }
file_des_write = pfd_write[1];
/*do the fork and exec */
- cpid = fork(); /* BYPASSOK: we exec() immediately, no FORK_CLEAN needed */
+ FORK(cpid); /* BYPASSOK: we exec() immediately, no FORK_CLEAN needed */
if (-1 == cpid)
{
save_errno = errno;
PIPE_ERROR_INIT();
- rts_error(VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io,
+ 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 - fork() failed"), save_errno); /* BYPASSOK */
}
if (0 == cpid)
@@ -508,7 +515,7 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
{
save_errno = errno;
PIPE_ERROR_INIT();
- rts_error(VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io,
+ 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);
}
if (return_stdout)
@@ -519,7 +526,7 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
{
save_errno = errno;
PIPE_ERROR_INIT();
- rts_error(VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io,
+ 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);
}
/* stderr also becomes pfd_read[1] if return_stderr is false*/
@@ -530,8 +537,9 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
{
save_errno = errno;
PIPE_ERROR_INIT();
- rts_error(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);
+ 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],2) failed in child"), save_errno);
}
}
}
@@ -542,8 +550,10 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
{
save_errno = errno;
PIPE_ERROR_INIT();
- rts_error(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);
+ 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_stderr[1],2) failed in child"),
+ save_errno);
}
}
if (0 == slen[PSHELL])
@@ -562,7 +572,7 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
{
save_errno = errno;
PIPE_ERROR_INIT();
- rts_error(VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io,
+ 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);
}
} else
@@ -593,17 +603,18 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
/* save read file descriptor for stdout return if set */
if (file_des_read)
{
- if (NULL == (d_rm->read_filstr = FDOPEN(file_des_read, "r")))
+ FDOPEN(d_rm->read_filstr, file_des_read, "r");
+ if (NULL == d_rm->read_filstr)
{
save_errno = errno;
PIPE_ERROR_INIT();
- rts_error(VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io,
ERR_TEXT, 2, LEN_AND_LIT("Error in stream open"), save_errno);
}
d_rm->read_fildes = file_des_read;
}
- SPRINTF(&d_rm->dollar_key[0], "%d", cpid); /* save in pipe specific structure for $KEY access */
- memcpy(d_rm->dollar_device, "0", SIZEOF("0"));
+ SPRINTF(&iod->dollar.key[0], "%d", cpid); /* save in pipe specific structure for $KEY access */
+ memcpy(iod->dollar.device, "0", SIZEOF("0"));
iod->state = dev_closed;
d_rm->stream = FALSE;
iod->width = DEF_RM_WIDTH;
@@ -672,7 +683,7 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
io_ptr->dev_sp = (void*)malloc(SIZEOF(d_rm_struct));
memset(io_ptr->dev_sp, 0, SIZEOF(d_rm_struct));
in_d_rm = (d_rm_struct *) io_ptr->dev_sp;
- memcpy(in_d_rm->dollar_device, "0", SIZEOF("0"));
+ memcpy(io_ptr->dollar.device, "0", SIZEOF("0"));
io_ptr->state = dev_closed;
in_d_rm->stream = d_rm->stream;
io_ptr->width = iod->width;
@@ -682,6 +693,8 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
io_ptr->dollar.y = 0;
io_ptr->dollar.za = 0;
io_ptr->dollar.zb[0] = 0;
+ io_ptr->dollar.key[0] = 0;
+ io_ptr->dollar.device[0] = 0;
io_ptr->disp_ptr = iod->disp_ptr;
in_d_rm->fixed = d_rm->fixed;
in_d_rm->noread = TRUE;
@@ -704,9 +717,9 @@ short iopi_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
flags = 0;
FCNTL2(file_des_write, F_GETFL, flags);
if (0 > flags)
- rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fcntl"), CALLFROM, errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fcntl"), CALLFROM, errno);
FCNTL3(file_des_write, F_SETFL, (flags | O_NONBLOCK), fcntl_res);
if (0 > fcntl_res)
- rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fcntl"), CALLFROM, errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fcntl"), CALLFROM, errno);
return iorm_open(dev_name, pp, file_des_write, mspace, timeout);
}
diff --git a/sr_unix/iorm_close.c b/sr_unix/iorm_close.c
index 996264a..94dcfcd 100644
--- a/sr_unix/iorm_close.c
+++ b/sr_unix/iorm_close.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -91,23 +91,23 @@ void iorm_close(io_desc *iod, mval *pp)
path = iod->trans_name->dollar_io;
FSTAT_FILE(rm_ptr->fildes, &fstatbuf, fstat_res);
if (-1 == fstat_res)
- rts_error(VARLSTCNT(1) errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) errno);
STAT_FILE(path, &statbuf, stat_res);
if (-1 == stat_res)
- rts_error(VARLSTCNT(1) errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) errno);
if (CYGWIN_ONLY(rm_ptr->fifo ||) fstatbuf.st_ino == statbuf.st_ino)
if (UNLINK(path) == -1)
- rts_error(VARLSTCNT(1) errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) errno);
break;
case iop_rename:
path = iod->trans_name->dollar_io;
path2 = (char*)(pp->str.addr + p_offset + 1);
FSTAT_FILE(rm_ptr->fildes, &fstatbuf, fstat_res);
if (-1 == fstat_res)
- rts_error(VARLSTCNT(1) errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) errno);
STAT_FILE(path, &statbuf, stat_res);
if (-1 == stat_res)
- rts_error(VARLSTCNT(1) errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) errno);
if (CYGWIN_ONLY(rm_ptr->fifo ||) fstatbuf.st_ino == statbuf.st_ino)
{
/* make a copy of path2 so we can null terminate it */
@@ -121,9 +121,9 @@ void iorm_close(io_desc *iod, mval *pp)
assert(stringpool.free >= stringpool.base);
assert(stringpool.free <= stringpool.top);
if (LINK(path, savepath2) == -1)
- rts_error(VARLSTCNT(1) errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) errno);
if (UNLINK(path) == -1)
- rts_error(VARLSTCNT(1) errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) errno);
}
break;
case iop_destroy:
@@ -181,7 +181,7 @@ void iorm_close(io_desc *iod, mval *pp)
save_fd = rm_ptr->fildes;
CLOSEFILE_RESET(rm_ptr->fildes, rc); /* resets "rm_ptr->fildes" to FD_INVALID */
if (0 != rc)
- rts_error(VARLSTCNT(4) ERR_CLOSEFAIL, 1, save_fd, rc);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_CLOSEFAIL, 1, save_fd, rc);
}
if (rm_ptr->filstr != NULL)
{
@@ -194,7 +194,7 @@ void iorm_close(io_desc *iod, mval *pp)
save_fd = rm_ptr->read_fildes;
CLOSEFILE_RESET(rm_ptr->read_fildes, rc); /* resets "rm_ptr->read_fildes" to FD_INVALID */
if (0 != rc)
- rts_error(VARLSTCNT(4) ERR_CLOSEFAIL, 1, save_fd, rc);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_CLOSEFAIL, 1, save_fd, rc);
}
if (rm_ptr->read_filstr != NULL)
{
diff --git a/sr_unix/iorm_get.c b/sr_unix/iorm_get.c
index 75338d7..e874061 100644
--- a/sr_unix/iorm_get.c
+++ b/sr_unix/iorm_get.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2006, 2012 Fidelity Information Services, Inc *
+ * Copyright 2006, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -71,7 +71,7 @@ int gtm_utf_bomcheck(io_desc *iod, gtm_chset_t *chset, unsigned char *buffer, in
if (CHSET_UTF16LE == *chset)
{
iod->dollar.za = 9;
- rts_error(VARLSTCNT(6) ERR_BOMMISMATCH, 4,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_BOMMISMATCH, 4,
chset_names[CHSET_UTF16BE].len, chset_names[CHSET_UTF16BE].addr,
chset_names[CHSET_UTF16LE].len, chset_names[CHSET_UTF16LE].addr);
}
@@ -82,7 +82,7 @@ int gtm_utf_bomcheck(io_desc *iod, gtm_chset_t *chset, unsigned char *buffer, in
if (CHSET_UTF16BE == *chset)
{
iod->dollar.za = 9;
- rts_error(VARLSTCNT(6) ERR_BOMMISMATCH, 4,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_BOMMISMATCH, 4,
chset_names[CHSET_UTF16LE].len, chset_names[CHSET_UTF16LE].addr,
chset_names[CHSET_UTF16BE].len, chset_names[CHSET_UTF16BE].addr);
}
@@ -103,6 +103,314 @@ int gtm_utf_bomcheck(io_desc *iod, gtm_chset_t *chset, unsigned char *buffer, in
/* When we get to this routine it is guaranteed that rm_ptr->done_1st_read is FALSE. */
+int iorm_get_bom_fol(io_desc *io_ptr, int4 *tot_bytes_read, int4 *msec_timeout, boolean_t timed, boolean_t *bom_timeout)
+{
+ int4 bytes2read, bytes_read, reclen, bom_bytes2read, bom_bytes_read;
+ int status = 0;
+ gtm_chset_t chset;
+ d_rm_struct *rm_ptr;
+ int fildes;
+ int4 sleep_left;
+ int4 sleep_time;
+
+ rm_ptr = (d_rm_struct *)(io_ptr->dev_sp);
+ fildes = rm_ptr->fildes;
+
+ chset = io_ptr->ichset;
+ assert(UTF16BE_BOM_LEN == UTF16LE_BOM_LEN);
+ bom_bytes2read = (int4)((CHSET_UTF8 == chset) ? UTF8_BOM_LEN : UTF16BE_BOM_LEN);
+ PIPE_DEBUG(PRINTF("enter iorm_get_bom_fl: bom_buf_cnt: %d bom_bytes2read: %d bom_read_one_done: %d chset: %d\n",
+ rm_ptr->bom_buf_cnt,bom_bytes2read,rm_ptr->bom_read_one_done,chset); DEBUGPIPEFLUSH;);
+ /* rms-file device in follow mode */
+ if (timed)
+ {
+ /* check iorm_get_bom_fol.... for msc_timeout */
+ if (0 < *msec_timeout)
+ {
+ sleep_left = *msec_timeout;
+ } else
+ sleep_left = 0;
+ }
+ /* if zeof is set in follow mode then ignore any previous zeof */
+ if (TRUE == io_ptr->dollar.zeof)
+ io_ptr->dollar.zeof = FALSE;
+ do
+ {
+ status = read(fildes, &rm_ptr->bom_buf[rm_ptr->bom_buf_cnt], bom_bytes2read - rm_ptr->bom_buf_cnt);
+ if (0 < status) /* we read some chars */
+ {
+ rm_ptr->bom_buf_cnt += status;
+ } else if (0 == status) /* end of file */
+ {
+ if ((TRUE == timed) && (0 >= sleep_left))
+ {
+ *bom_timeout = TRUE;
+ *tot_bytes_read = rm_ptr->bom_buf_cnt;
+ break;
+ }
+ /* if a timed read, sleep the minimum of 100 ms and sleep_left.
+ If not a timed read then just sleep 100 ms */
+ if (TRUE == timed)
+ sleep_time = MIN(100,sleep_left);
+ else
+ sleep_time = 100;
+ SHORT_SLEEP(sleep_time);
+ if (TRUE == timed)
+ sleep_left -= sleep_time;
+ if (outofband)
+ {
+ return 0;
+ }
+ continue; /* for now try and read again if eof or no input ready */
+ } else /* error returned */
+ {
+ if (errno != EINTR)
+ break;
+ }
+ } while (rm_ptr->bom_buf_cnt < bom_bytes2read);
+ PIPE_DEBUG(PRINTF("iorm_get_bom_fl: status: %d, bom_buf_cnt: %d\n", status,rm_ptr->bom_buf_cnt); DEBUGPIPEFLUSH;);
+ if (rm_ptr->bom_buf_cnt >= bom_bytes2read)
+ {
+ PIPE_DEBUG(PRINTF("iorm_get_bom_fl do bomcheck: bom_buf_cnt: %d bom_buf: %o\n",
+ rm_ptr->bom_buf_cnt,rm_ptr->bom_buf[0]); DEBUGPIPEFLUSH;);
+ rm_ptr->bom_buf_off = gtm_utf_bomcheck(io_ptr, &io_ptr->ichset, rm_ptr->bom_buf, rm_ptr->bom_buf_cnt);
+ rm_ptr->file_pos += rm_ptr->bom_buf_off; /* If there is BOM bytes increment file position by bom_buf_off */
+ }
+ else if (CHSET_UTF16 == chset) /* if UTF16 default to UTF16BE */
+ io_ptr->ichset = CHSET_UTF16BE;
+ if (chset != io_ptr->ichset)
+ { /* UTF16 changed to UTF16BE or UTF16LE */
+ chset = io_ptr->ichset;
+ get_chset_desc(&chset_names[chset]);
+ }
+ /* if outofband is not set then we are done getting the bom */
+ if (!outofband)
+ rm_ptr->done_1st_read = TRUE;
+ return 0;
+}
+
+/* If we are in this routine then it is a fixed utf disk read with rm_ptr->follow = TRUE */
+
+int iorm_get_fol(io_desc *io_ptr, int4 *tot_bytes_read, int4 *msec_timeout, boolean_t timed,
+ boolean_t zint_restart, boolean_t *follow_timeout)
+{
+ boolean_t ret;
+ char inchar, *temp;
+ unsigned char *pad_ptr, *nextmb, padchar, padcharray[2];
+ int fcntl_res, save_errno;
+ int4 bytes2read, bytes_read, char_bytes_read, add_bytes, reclen, bytes_already_read, tmp_bytes_read;
+ wint_t utf_code;
+ d_rm_struct *rm_ptr;
+ int4 status, from_bom;
+ gtm_chset_t chset;
+ int fildes;
+ int bytes_count = 0;
+ int4 sleep_left;
+ int4 sleep_time;
+ boolean_t bom_timeout = FALSE;
+
+ assert (io_ptr->state == dev_open);
+ rm_ptr = (d_rm_struct *)(io_ptr->dev_sp);
+ fildes = rm_ptr->fildes;
+ assert(gtm_utf8_mode ? (IS_UTF_CHSET(io_ptr->ichset)) : FALSE);
+ assert(rm_ptr->fixed);
+ if (!zint_restart)
+ {
+ bytes2read = rm_ptr->recordsize;
+ bytes_already_read = 0;
+ rm_ptr->inbuf_pos = rm_ptr->inbuf_top = rm_ptr->inbuf_off = rm_ptr->inbuf;
+ }
+ else
+ {
+ bytes_already_read = rm_ptr->inbuf_top - rm_ptr->inbuf;
+ bytes2read = rm_ptr->recordsize - bytes_already_read;
+ /* skip past if bom already read */
+ if (rm_ptr->done_1st_read)
+ rm_ptr->inbuf_pos = rm_ptr->inbuf_top;
+ else
+ rm_ptr->inbuf_pos = rm_ptr->inbuf_off = rm_ptr->inbuf;
+ }
+ PIPE_DEBUG(PRINTF("iorm_get_fol: bytes2read: %d, zint_restart: %d\n", bytes2read,zint_restart); DEBUGPIPEFLUSH;);
+ bytes_read = 0;
+ assert(rm_ptr->bufsize >= rm_ptr->recordsize);
+ errno = status = 0;
+ /* don't reset this if continuing from an interrupt unless we haven't read the bom yet */
+/* if (!rm_ptr->done_1st_read || FALSE == zint_restart)
+ rm_ptr->inbuf_pos = rm_ptr->inbuf_off = rm_ptr->inbuf;*/
+ chset = io_ptr->ichset;
+ if (!rm_ptr->done_1st_read)
+ {
+ PIPE_DEBUG(PRINTF("do iorm_get_bom_fol: bytes2read: %d\n", bytes2read); DEBUGPIPEFLUSH;)
+ status = iorm_get_bom_fol(io_ptr, tot_bytes_read, msec_timeout, timed, &bom_timeout);
+ if (!rm_ptr->done_1st_read && outofband)
+ {
+ PIPE_DEBUG(PRINTF("return since iorm_get_bom_fol went outofband\n"); DEBUGPIPEFLUSH;);
+ return 0;
+ }
+ if (TRUE == bom_timeout)
+ *follow_timeout = TRUE;
+ chset = io_ptr->ichset; /* UTF16 will have changed to UTF16BE or UTF16LE */
+ }
+ assert(CHSET_UTF16 != chset);
+ PIPE_DEBUG(PRINTF("iorm_get_fol: bom_buf_cnt: %d bom_buf_off: %d\n",rm_ptr->bom_buf_cnt,rm_ptr->bom_buf_off );
+ DEBUGPIPEFLUSH;);
+ if (0 <= status && rm_ptr->bom_buf_cnt > rm_ptr->bom_buf_off)
+ {
+ PIPE_DEBUG(PRINTF("move bom: status: %d\n", status); DEBUGPIPEFLUSH;);
+ from_bom = MIN((rm_ptr->bom_buf_cnt - rm_ptr->bom_buf_off), bytes2read);
+ memcpy(rm_ptr->inbuf, &rm_ptr->bom_buf[rm_ptr->bom_buf_off], from_bom);
+ rm_ptr->bom_buf_off += from_bom;
+ bytes2read -= from_bom; /* now in buffer */
+ rm_ptr->inbuf_pos += from_bom;
+ bytes_read = from_bom;
+ rm_ptr->file_pos += from_bom;
+ status = 0;
+ }
+ /* if outofband then we didn't finish so return 0 */
+ if (outofband)
+ {
+ PIPE_DEBUG(PRINTF("iorm_get_fol: bytes2read: %d bytes_already_read: %d, zint_restart: %d\n",
+ bytes2read,bytes_already_read,zint_restart); DEBUGPIPEFLUSH;);
+ return 0;
+ }
+ if (0 <= status && 0 < bytes2read)
+ {
+ PIPE_DEBUG(PRINTF("iorm_get_fol: bytes2read after bom: %d\n", bytes2read); DEBUGPIPEFLUSH;);
+ if (timed)
+ {
+ if (0 < *msec_timeout)
+ {
+ sleep_left = *msec_timeout;
+ } else
+ sleep_left = 0;
+ }
+ /* if zeof is set in follow mode then ignore any previous zeof */
+ if (TRUE == io_ptr->dollar.zeof)
+ io_ptr->dollar.zeof = FALSE;
+ temp = (char *)rm_ptr->inbuf_pos;
+ do
+ {
+ status = read(fildes, temp, (int)bytes2read - bytes_count);
+ if (0 < status) /* we read some chars */
+ {
+ tot_bytes_read += status;
+ bytes_count += status;
+ temp = temp + status;
+ } else if (0 == status) /* end of file */
+ {
+ if ((TRUE == timed) && (0 >= sleep_left))
+ {
+ /* need to set tot_bytes_read and status for timeout */
+ *follow_timeout = TRUE;
+ break;
+ }
+ /* if a timed read, sleep the minimum of 100 ms and sleep_left.
+ If not a timed read then just sleep 100 ms */
+ if (TRUE == timed)
+ sleep_time = MIN(100,sleep_left);
+ else
+ sleep_time = 100;
+ SHORT_SLEEP(sleep_time);
+ if (TRUE == timed)
+ sleep_left -= sleep_time;
+ if (outofband)
+ break;
+ continue; /* for now try and read again if eof or no input ready */
+ } else /* error returned */
+ {
+ break;
+ }
+ } while (bytes_count < bytes2read);
+ status = bytes_count;
+ }
+ /* if outofband then we didn't finish so just adjust inbuf_top and inbuf_pos and return 0 */
+ if (outofband)
+ {
+ PIPE_DEBUG(PRINTF("iorm_get_fol: outofband: bytes2read: %d status: %d tot_bytes_read: %d\n",
+ bytes2read, status, *tot_bytes_read); DEBUGPIPEFLUSH;);
+ if (0 > status)
+ {
+ rm_ptr->inbuf_top = rm_ptr->inbuf_pos += *tot_bytes_read;
+ return(0);
+ }
+ else
+ {
+ rm_ptr->inbuf_top = rm_ptr->inbuf_pos += status;
+ if ((rm_ptr->inbuf_pos - rm_ptr->inbuf_off) < rm_ptr->recordsize)
+ return(0);
+ }
+ }
+ /* if some bytes were read prior to timeout then process them as if no timeout occurred */
+ if (0 > status && *tot_bytes_read && ((FALSE == timed) || (TRUE == *follow_timeout)))
+ status = *tot_bytes_read;
+ if (0 > status)
+ {
+ bytes_read = 0;
+ if (TRUE == *follow_timeout)
+ status = -2;
+ } else if (bytes_read || status)
+ {
+ bytes_read += status;
+ rm_ptr->file_pos += status;
+ padchar = rm_ptr->padchar;
+ if ((CHSET_UTF16LE == chset) || (CHSET_UTF16BE == chset))
+ { /* strip 2-byte PADCHAR in UTF-16LE or UTF-16BE from tail of line */
+ /* It's possible that only one byte is read if this is an interrupt restart one byte from the width
+ * In that case it's not an error if already_read is non-zero, but we have to adjust bytes_read differently.
+ */
+ PIPE_DEBUG(PRINTF("pipeget: bytes_read: %d bytes_already_read: %d, zint_restart: %d\n",
+ bytes_read,bytes_already_read,zint_restart); DEBUGPIPEFLUSH;);
+ if (zint_restart && bytes_already_read)
+ {
+ tmp_bytes_read = bytes_read + bytes_already_read;
+ } else
+ {
+ tmp_bytes_read = bytes_read;
+ }
+ assert(tmp_bytes_read >= 2);
+ if (CHSET_UTF16LE == chset)
+ {
+ padcharray[0] = padchar;
+ padcharray[1] = '\0';
+ } else
+ {
+ padcharray[0] = '\0';
+ padcharray[1] = padchar;
+ }
+ for (pad_ptr = rm_ptr->inbuf + tmp_bytes_read - 2;
+ 0 < tmp_bytes_read && rm_ptr->inbuf <= pad_ptr; pad_ptr-=2)
+ {
+ PIPE_DEBUG(PRINTF("pad 16 loop: bytes_read: %d pad_ptr: %sx\n",
+ bytes_read,pad_ptr); DEBUGPIPEFLUSH;);
+ if ((padcharray[0] == pad_ptr[0]) && (padcharray[1] == pad_ptr[1]))
+ tmp_bytes_read -= 2;
+ else
+ break;
+ }
+ bytes_read = tmp_bytes_read;
+ } else
+ { /* strip 1-byte PADCHAR in UTF-8 from tail of line */
+ if (zint_restart && bytes_already_read)
+ bytes_read = bytes_read + bytes_already_read;
+ assert(CHSET_UTF8 == chset);
+ for (pad_ptr = rm_ptr->inbuf + bytes_read - 1; 0 < bytes_read && rm_ptr->inbuf <= pad_ptr; pad_ptr--)
+ {
+ PIPE_DEBUG(PRINTF("pad 8 loop: bytes_read: %d pad_ptr: %sx\n",
+ bytes_read,pad_ptr); DEBUGPIPEFLUSH;);
+ if (*pad_ptr == padchar)
+ bytes_read--;
+ else
+ break;
+ }
+ }
+ }
+ rm_ptr->inbuf_top = rm_ptr->inbuf_pos = rm_ptr->inbuf + bytes_read;
+ rm_ptr->inbuf_off = rm_ptr->inbuf;
+ return (0 <= status ? bytes_read : status);
+}
+
+/* When we get to this routine it is guaranteed that rm_ptr->done_1st_read is FALSE. */
+
int iorm_get_bom(io_desc *io_ptr, int *blocked_in, boolean_t ispipe, int flags, int4 *tot_bytes_read,
TID timer_id, int4 *msec_timeout, boolean_t pipe_zero_timeout)
{
@@ -329,7 +637,7 @@ int iorm_get(io_desc *io_ptr, int *blocked_in, boolean_t ispipe, int flags, int4
bytes_read = 0;
if (errno == EINTR && out_of_time)
status = -2;
- } else
+ } else if (bytes_read || status)
{
bytes_read += status;
rm_ptr->file_pos += status;
diff --git a/sr_unix/iorm_open.c b/sr_unix/iorm_open.c
index 810c8bc..d6821c0 100644
--- a/sr_unix/iorm_open.c
+++ b/sr_unix/iorm_open.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -20,6 +20,7 @@
#include "iormdef.h"
#include "io_params.h"
#include "eintr_wrappers.h"
+#include "have_crit.h"
#ifdef __MVS__
#include "gtm_zos_io.h"
#include "gtm_zos_chset.h"
@@ -85,6 +86,7 @@ short iorm_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
d_rm->padchar = DEF_RM_PADCHAR;
d_rm->inbuf = NULL;
d_rm->outbuf = NULL;
+ d_rm->follow = FALSE;
} else
d_rm = (d_rm_struct *)iod->dev_sp;
if (dev_closed == iod->state)
@@ -94,19 +96,21 @@ short iorm_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
d_rm->crlast = FALSE;
d_rm->done_1st_read = FALSE;
d_rm->done_1st_write = FALSE;
+ d_rm->follow = FALSE;
assert(0 <= fd);
d_rm->fildes = fd;
FSTAT_FILE(fd, &statbuf, fstat_res);
if (-1 == fstat_res)
- rts_error(VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io, ERR_TEXT, 2,
- LEN_AND_LIT("Error in fstat"), errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len,
+ dev_name->dollar_io, ERR_TEXT, 2, LEN_AND_LIT("Error in fstat"), errno);
for (p_offset = 0; iop_eol != *(pp->str.addr + p_offset); )
{
if (iop_append == (ch = *(pp->str.addr + p_offset++)))
{
if (!d_rm->fifo && !d_rm->pipe && (off_t)-1 == (size = lseek(fd, (off_t)0, SEEK_END)))
- rts_error(VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io,
- ERR_TEXT, 2, LEN_AND_LIT("Error setting file pointer to end of file"), errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len,
+ dev_name->dollar_io,
+ ERR_TEXT, 2, LEN_AND_LIT("Error setting file pointer to end of file"), errno);
if (0 < statbuf.st_size)
{ /* Only disable BOM writing if there is something in the file already (not empty) */
d_rm->done_1st_read = FALSE;
@@ -121,7 +125,7 @@ short iorm_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
if (!d_rm->fifo && !d_rm->pipe && fd != 0)
{
if ((off_t)-1 == (size = lseek(fd, (off_t)0, SEEK_CUR)))
- rts_error(VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io,
ERR_TEXT, 2, LEN_AND_LIT("Error setting file pointer to the current position"), errno);
if (size == statbuf.st_size)
iod->dollar.zeof = TRUE;
@@ -132,9 +136,18 @@ short iorm_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
}
if (1 == fd)
d_rm->filstr = NULL;
- else if (NULL == (d_rm->filstr = FDOPEN(fd, "r")) && NULL == (d_rm->filstr = FDOPEN(fd, "w")))
- rts_error(VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io,
- ERR_TEXT, 2, LEN_AND_LIT("Error in stream open"), errno);
+ else
+ {
+ FDOPEN(d_rm->filstr, fd, "r");
+ if (NULL == d_rm->filstr)
+ {
+ FDOPEN(d_rm->filstr, fd, "w");
+ if (NULL == d_rm->filstr)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len,
+ dev_name->dollar_io, ERR_TEXT, 2,
+ LEN_AND_LIT("Error in stream open"), errno);
+ }
+ }
}
recsize_before = d_rm->recordsize;
def_recsize_before = d_rm->def_recsize;
@@ -152,8 +165,8 @@ short iorm_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
#ifdef __MVS__
/* need to get file tag info before set policy which can change what is returned */
if (-1 == gtm_zos_check_tag(fd, &file_tag, &text_tag))
- rts_error(VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io, ERR_TEXT, 2,
- LEN_AND_LIT("Error in check_tag fstat"), errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_DEVOPENFAIL, 2, dev_name->len, dev_name->dollar_io, ERR_TEXT,
+ 2, LEN_AND_LIT("Error in check_tag fstat"), errno);
SET_CHSET_FROM_TAG(file_tag, iod->file_chset);
iod->text_flag = text_tag;
if (!d_rm->pipe && 2 < fd)
@@ -172,8 +185,9 @@ short iorm_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
if (-1 == gtm_zos_set_tag(fd, file_tag, text_tag, TAG_FORCE, &realfiletag))
{
errmsg = STRERROR(errno);
- rts_error(VARLSTCNT(10) ERR_BADTAG, 4, dev_name->len, dev_name->dollar_io, realfiletag,
- file_tag, ERR_TEXT, 2, RTS_ERROR_STRING(errmsg));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_BADTAG, 4, dev_name->len,
+ dev_name->dollar_io, realfiletag, file_tag, ERR_TEXT, 2,
+ RTS_ERROR_STRING(errmsg));
}
if (gtm_utf8_mode && gtm_tag_utf8_as_ascii && (CHSET_UTF8 == iod->ochset))
iod->process_chset = iod->ochset;
@@ -192,8 +206,8 @@ short iorm_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
if (-1 == (obtained_tag = gtm_zos_tag_to_policy(fd, file_tag, &realfiletag)))
{
errmsg = STRERROR(errno);
- rts_error(VARLSTCNT(10) ERR_BADTAG, 4, dev_name->len, dev_name->dollar_io, realfiletag,
- file_tag, ERR_TEXT, 2, RTS_ERROR_STRING(errmsg));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_BADTAG, 4, dev_name->len, dev_name->dollar_io,
+ realfiletag, file_tag, ERR_TEXT, 2, RTS_ERROR_STRING(errmsg));
}
SET_CHSET_FROM_TAG(obtained_tag, iod->process_chset);
}
diff --git a/sr_unix/iorm_readfl.c b/sr_unix/iorm_readfl.c
index 365f1f2..a5506a2 100644
--- a/sr_unix/iorm_readfl.c
+++ b/sr_unix/iorm_readfl.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -92,14 +92,14 @@ void iorm_readfl_badchar(mval *vmvalptr, int datalen, int delimlen, unsigned cha
{ /* Set $KEY and $ZB with the failing badchar */
memcpy(iod->dollar.zb, delimptr, MIN(delimlen, ESC_LEN - 1));
iod->dollar.zb[MIN(delimlen, ESC_LEN - 1)] = '\0';
- memcpy(rm_ptr->dollar_key, delimptr, MIN(delimlen, RM_BUFLEN - 1));
- rm_ptr->dollar_key[MIN(delimlen, RM_BUFLEN - 1)] = '\0';
+ memcpy(iod->dollar.key, delimptr, MIN(delimlen, DD_BUFLEN - 1));
+ iod->dollar.key[MIN(delimlen, DD_BUFLEN - 1)] = '\0';
}
}
- /* set dollar_device in the output device */
+ /* set dollar.device in the output device */
len = SIZEOF(ONE_COMMA) - 1;
- memcpy(rm_ptr->dollar_device, ONE_COMMA, len);
- memcpy(&rm_ptr->dollar_device[len], BADCHAR_DEVICE_MSG, SIZEOF(BADCHAR_DEVICE_MSG));
+ memcpy(iod->dollar.device, ONE_COMMA, len);
+ memcpy(&iod->dollar.device[len], BADCHAR_DEVICE_MSG, SIZEOF(BADCHAR_DEVICE_MSG));
}
#endif
@@ -126,6 +126,8 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */
FILE *filstr;
boolean_t pipe_zero_timeout = FALSE;
boolean_t pipe_or_fifo = FALSE;
+ boolean_t follow_timeout = FALSE;
+ boolean_t bom_timeout = FALSE;
int blocked_in = TRUE;
int do_clearerr = FALSE;
int saved_lastop;
@@ -135,6 +137,11 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */
mv_stent *mv_zintdev;
unsigned int *dollarx_ptr;
unsigned int *dollary_ptr;
+ struct timeval poll_interval;
+ int poll_status;
+ fd_set input_fds;
+ int4 sleep_left;
+ int4 sleep_time;
DCL_THREADGBL_ACCESS;
@@ -149,7 +156,7 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */
io_ptr = io_curr_device.in;
/* don't allow a read from a writeonly fifo */
if (((d_rm_struct *)io_ptr->dev_sp)->write_only)
- rts_error(VARLSTCNT(1) ERR_DEVICEWRITEONLY);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DEVICEWRITEONLY);
#ifdef __MVS__
/* on zos if it is a fifo device then point to the pair.out for $X and $Y */
if (((d_rm_struct *)io_ptr->dev_sp)->fifo)
@@ -201,12 +208,12 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */
flags = 0;
FCNTL2(rm_ptr->fildes, F_GETFL, flags);
if (0 > flags)
- rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fcntl"), CALLFROM, errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fcntl"), CALLFROM, errno);
if (flags & O_NONBLOCK)
{
FCNTL3(rm_ptr->fildes, F_SETFL, (flags & ~O_NONBLOCK), fcntl_res);
if (0 > fcntl_res)
- rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fcntl"), CALLFROM, errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fcntl"), CALLFROM, errno);
}
}
@@ -218,7 +225,7 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */
GTMASSERT; /* Interrupt should never have an invalid save state */
/* check we aren't recursing on this device */
if (dollar_zininterrupt)
- rts_error(VARLSTCNT(1) ERR_ZINTRECURSEIO);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZINTRECURSEIO);
if (pipewhich_readfl != pipeintr->who_saved)
GTMASSERT; /* ZINTRECURSEIO should have caught */
PIPE_DEBUG(PRINTF("piperfl: *#*#*#*#*#*#*# Restarted interrupted read\n"); DEBUGPIPEFLUSH);
@@ -341,7 +348,8 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */
temp = (char *)(stringpool.free + bytes_read);
tot_bytes_read = bytes_count = bytes_read;
- width -= bytes_read;
+ if (!(rm_ptr->fixed && rm_ptr->follow))
+ width -= bytes_read;
}
}
@@ -391,7 +399,8 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */
"computed msec_timeout: %d\n", msec_timeout); DEBUGPIPEFLUSH);
}
PIPE_DEBUG(PRINTF("msec_timeout: %d\n", msec_timeout); DEBUGPIPEFLUSH);
- if (0 < msec_timeout)
+ /* if it is a disk read with follow don't start timer, as we use a sleep loop instead */
+ if ((0 < msec_timeout) && !rm_ptr->follow)
start_timer(timer_id, msec_timeout, wake_alarm, 0, NULL);
}
else
@@ -402,10 +411,10 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */
out_of_time = TRUE;
FCNTL2(fildes, F_GETFL, flags);
if (0 > flags)
- rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fcntl"), CALLFROM, errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fcntl"), CALLFROM, errno);
FCNTL3(fildes, F_SETFL, (flags | O_NONBLOCK), fcntl_res);
if (0 > fcntl_res)
- rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fcntl"), CALLFROM, errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fcntl"), CALLFROM, errno);
blocked_in = FALSE;
if (rm_ptr->pipe)
pipe_zero_timeout = TRUE;
@@ -421,62 +430,152 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */
* Note the check for EINTR below is valid and should not be converted to an EINTR
* wrapper macro, since action is taken on EINTR, not a retry.
*/
- /* If it is a pipe and at least one character is read, a timer with timer_id
- will be started. It is canceled later in this routine if not expired
- prior to return */
- DOREADRLTO2(fildes, temp, width, out_of_time, &blocked_in, rm_ptr->pipe, flags, status,
- &tot_bytes_read, timer_id, &msec_timeout, pipe_zero_timeout, FALSE, pipe_or_fifo);
-
- PIPE_DEBUG(PRINTF(" %d fixed\n", pid); DEBUGPIPEFLUSH);
-
- if (0 > status)
+ if (rm_ptr->follow)
{
- if (pipe_or_fifo)
- bytes_count = tot_bytes_read;
- else
- bytes_count = 0;
- if (errno == EINTR && out_of_time)
- status = -2;
+ PIPE_DEBUG(PRINTF(" %d fixed\n", pid); DEBUGPIPEFLUSH);
+ if (timed)
+ {
+ if (0 < msec_timeout)
+ {
+ sleep_left = msec_timeout;
+ } else
+ sleep_left = 0;
+ }
+ /* if zeof is set in follow mode then ignore any previous zeof */
+ if (TRUE == io_ptr->dollar.zeof)
+ io_ptr->dollar.zeof = FALSE;
+ do
+ {
+ status = read(fildes, temp, width - bytes_count);
+ if (0 < status) /* we read some chars */
+ {
+ tot_bytes_read += status;
+ rm_ptr->file_pos += status;
+ bytes_count += status;
+ temp = temp + status;
+ } else if (0 == status) /* end of file */
+ {
+ if ((TRUE == timed) && (0 >= sleep_left))
+ {
+ follow_timeout = TRUE;
+ break;
+ }
+ /* if a timed read, sleep the minimum of 100 ms and sleep_left.
+ If not a timed read then just sleep 100 ms */
+ if (TRUE == timed)
+ sleep_time = MIN(100,sleep_left);
+ else
+ sleep_time = 100;
+ SHORT_SLEEP(sleep_time);
+ if (TRUE == timed)
+ sleep_left -= sleep_time;
+ if (outofband)
+ {
+ PIPE_DEBUG(PRINTF(" %d fixed outofband\n", pid); DEBUGPIPEFLUSH);
+ PUSH_MV_STENT(MVST_ZINTDEV);
+ mv_chain->mv_st_cont.mvs_zintdev.io_ptr = io_ptr;
+ mv_chain->mv_st_cont.mvs_zintdev.curr_sp_buffer.addr =
+ (char *)stringpool.free;
+ mv_chain->mv_st_cont.mvs_zintdev.curr_sp_buffer.len = tot_bytes_read;
+ mv_chain->mv_st_cont.mvs_zintdev.buffer_valid = TRUE;
+ pipeintr->who_saved = pipewhich_readfl;
+ if (0 < msec_timeout && NO_M_TIMEOUT != msec_timeout)
+ {
+ pipeintr->end_time = end_time;
+ pipeintr->end_time_valid = TRUE;
+ }
+ pipeintr->max_bufflen = exp_width;
+ pipeintr->bytes_read = tot_bytes_read;
+ rm_ptr->mupintr = TRUE;
+ stringpool.free += tot_bytes_read; /* Don't step on our parade in
+ the interrupt */
+ (TREF(pipefifo_interrupt))++;
+ outofband_action(FALSE);
+ GTMASSERT; /* Should *never* return from outofband_action */
+ return FALSE; /* For the compiler.. */
+ }
+ continue; /* for now try and read again if eof or no input ready */
+ } else /* error returned */
+ {
+ PIPE_DEBUG(PRINTF("errno= %d fixed\n", errno); DEBUGPIPEFLUSH);
+ if (errno != EINTR)
+ {
+ bytes_count = 0;
+ break;
+ }
+ }
+ } while (bytes_count < width);
} else
{
- tot_bytes_read = bytes_count = status;
- rm_ptr->file_pos += status;
- }
+ /* If it is a pipe and at least one character is read, a timer with timer_id
+ will be started. It is canceled later in this routine if not expired
+ prior to return */
+ DOREADRLTO2(fildes, temp, width, out_of_time, &blocked_in, rm_ptr->pipe, flags, status,
+ &tot_bytes_read, timer_id, &msec_timeout, pipe_zero_timeout, FALSE, pipe_or_fifo);
- if (zint_restart)
- {
- tot_bytes_read += bytes_read;
- bytes_count = tot_bytes_read;
- PIPE_DEBUG(PRINTF(" %d temp= %s tot_bytes_read = %d\n", pid, temp, tot_bytes_read); DEBUGPIPEFLUSH);
- }
+ PIPE_DEBUG(PRINTF(" %d fixed\n", pid); DEBUGPIPEFLUSH);
- if (pipe_or_fifo && outofband)
- {
- PIPE_DEBUG(PRINTF(" %d fixed outofband\n", pid); DEBUGPIPEFLUSH);
- PUSH_MV_STENT(MVST_ZINTDEV);
- mv_chain->mv_st_cont.mvs_zintdev.io_ptr = io_ptr;
- mv_chain->mv_st_cont.mvs_zintdev.curr_sp_buffer.addr = (char *)stringpool.free;
- mv_chain->mv_st_cont.mvs_zintdev.curr_sp_buffer.len = tot_bytes_read;
- mv_chain->mv_st_cont.mvs_zintdev.buffer_valid = TRUE;
- pipeintr->who_saved = pipewhich_readfl;
- if (0 < msec_timeout && NO_M_TIMEOUT != msec_timeout)
+ if (0 > status)
+ {
+ if (pipe_or_fifo)
+ bytes_count = tot_bytes_read;
+ else
+ bytes_count = 0;
+ if (errno == EINTR && out_of_time)
+ status = -2;
+ } else
+ {
+ tot_bytes_read = bytes_count = status;
+ rm_ptr->file_pos += status;
+ }
+ if (zint_restart)
{
- pipeintr->end_time = end_time;
- pipeintr->end_time_valid = TRUE;
- cancel_timer(timer_id); /* Worry about timer if/when we come back */
+ tot_bytes_read += bytes_read;
+ bytes_count = tot_bytes_read;
+ PIPE_DEBUG(PRINTF(" %d temp= %s tot_bytes_read = %d\n", pid, temp, tot_bytes_read);
+ DEBUGPIPEFLUSH);
+ }
+
+ if (pipe_or_fifo && outofband)
+ {
+ PIPE_DEBUG(PRINTF(" %d fixed outofband\n", pid); DEBUGPIPEFLUSH);
+ PUSH_MV_STENT(MVST_ZINTDEV);
+ mv_chain->mv_st_cont.mvs_zintdev.io_ptr = io_ptr;
+ mv_chain->mv_st_cont.mvs_zintdev.curr_sp_buffer.addr = (char *)stringpool.free;
+ mv_chain->mv_st_cont.mvs_zintdev.curr_sp_buffer.len = tot_bytes_read;
+ mv_chain->mv_st_cont.mvs_zintdev.buffer_valid = TRUE;
+ pipeintr->who_saved = pipewhich_readfl;
+ if (0 < msec_timeout && NO_M_TIMEOUT != msec_timeout)
+ {
+ pipeintr->end_time = end_time;
+ pipeintr->end_time_valid = TRUE;
+ cancel_timer(timer_id); /* Worry about timer if/when we come back */
+ }
+ pipeintr->max_bufflen = exp_width;
+ pipeintr->bytes_read = tot_bytes_read;
+ rm_ptr->mupintr = TRUE;
+ stringpool.free += tot_bytes_read; /* Don't step on our parade in the interrupt */
+ (TREF(pipefifo_interrupt))++;
+ outofband_action(FALSE);
+ GTMASSERT; /* Should *never* return from outofband_action */
+ return FALSE; /* For the compiler.. */
}
- pipeintr->max_bufflen = exp_width;
- pipeintr->bytes_read = tot_bytes_read;
- rm_ptr->mupintr = TRUE;
- stringpool.free += tot_bytes_read; /* Don't step on our parade in the interrupt */
- (TREF(pipefifo_interrupt))++;
- outofband_action(FALSE);
- GTMASSERT; /* Should *never* return from outofband_action */
- return FALSE; /* For the compiler.. */
}
} else if (!rm_ptr->pipe && !rm_ptr->fifo)
{ /* rms-file device */
+ if ((rm_ptr->follow) && timed)
+ {
+ if (0 < msec_timeout)
+ {
+ sleep_left = msec_timeout;
+ } else
+ sleep_left = 0;
+ }
+
+ /* if zeof is set and follow is TRUE then ignore any previous zeof */
+ if (rm_ptr->follow && (TRUE == io_ptr->dollar.zeof))
+ io_ptr->dollar.zeof = FALSE;
do
{
if (EOF != (status = getc(filstr)))
@@ -499,6 +598,51 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */
{
status = 0;
clearerr(filstr);
+
+ if (rm_ptr->follow)
+ {
+ if ((TRUE == timed) && (0 >= sleep_left))
+ {
+ follow_timeout = TRUE;
+ break;
+ }
+ /* if a timed read, sleep the minimum of 100 ms and sleep_left.
+ If not a timed read then just sleep 100 ms */
+ if (TRUE == timed)
+ sleep_time = MIN(100,sleep_left);
+ else
+ sleep_time = 100;
+ SHORT_SLEEP(sleep_time);
+ if (TRUE == timed)
+ sleep_left -= sleep_time;
+ if (outofband)
+ {
+ PIPE_DEBUG(PRINTF(" %d outofband\n", pid); DEBUGPIPEFLUSH);
+ PUSH_MV_STENT(MVST_ZINTDEV);
+ mv_chain->mv_st_cont.mvs_zintdev.io_ptr = io_ptr;
+ mv_chain->mv_st_cont.mvs_zintdev.curr_sp_buffer.addr =
+ (char *)stringpool.free;
+ mv_chain->mv_st_cont.mvs_zintdev.curr_sp_buffer.len =
+ tot_bytes_read;
+ mv_chain->mv_st_cont.mvs_zintdev.buffer_valid = TRUE;
+ pipeintr->who_saved = pipewhich_readfl;
+ if (0 < msec_timeout && NO_M_TIMEOUT != msec_timeout)
+ {
+ pipeintr->end_time = end_time;
+ pipeintr->end_time_valid = TRUE;
+ }
+ pipeintr->max_bufflen = exp_width;
+ pipeintr->bytes_read = tot_bytes_read;
+ rm_ptr->mupintr = TRUE;
+ stringpool.free += tot_bytes_read; /* Don't step on our parade
+ in the interrupt */
+ (TREF(pipefifo_interrupt))++;
+ outofband_action(FALSE);
+ GTMASSERT; /* Should *never* return from outofband_action */
+ return FALSE; /* For the compiler.. */
+ }
+ continue; /* for now try and read again if eof or no input ready */
+ }
}
else
do_clearerr = TRUE;
@@ -553,7 +697,7 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */
{
FCNTL3(fildes, F_SETFL, flags, tfcntl_res);
if (0 > tfcntl_res)
- rts_error(VARLSTCNT(8) ERR_SYSCALL, 5,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5,
LEN_AND_LIT("fcntl"), CALLFROM, errno);
blocked_in = TRUE;
out_of_time = FALSE;
@@ -614,14 +758,18 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */
what to do. */
if ((0 == buff_len) || zint_restart)
{ /* need to refill the buffer */
- buff_len = iorm_get(io_ptr, &blocked_in, rm_ptr->pipe, flags, &tot_bytes_read,
+ if (rm_ptr->follow)
+ buff_len = iorm_get_fol(io_ptr, &tot_bytes_read, &msec_timeout, timed, zint_restart,
+ &follow_timeout);
+ else
+ buff_len = iorm_get(io_ptr, &blocked_in, rm_ptr->pipe, flags, &tot_bytes_read,
timer_id, &msec_timeout, pipe_zero_timeout, zint_restart);
if (0 > buff_len)
{
bytes_count = 0;
if (errno == EINTR && out_of_time)
buff_len = -2;
- } else if (pipe_or_fifo && outofband && (buff_len < rm_ptr->recordsize))
+ } else if (outofband && (buff_len < rm_ptr->recordsize))
{
PIPE_DEBUG(PRINTF(" %d utf fixed outofband, buff_len: %d done_1st_read: %d\n", pid,
buff_len, rm_ptr->done_1st_read); DEBUGPIPEFLUSH);
@@ -707,6 +855,9 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */
GTMASSERT;
}
}
+ if (rm_ptr->follow && (char_count == width) && (TRUE == follow_timeout))
+ follow_timeout = FALSE;
+
v->str.len = INTCAST(char_ptr - rm_ptr->inbuf_off);
UNICODE_ONLY(v->str.char_len = char_count;)
if (0 < v->str.len)
@@ -732,8 +883,8 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */
}
} else
{ /* VARIABLE or STREAM */
- PIPE_DEBUG(PRINTF("enter utf stream: %d inbuf_pos: %d inbuf_off: %d\n", rm_ptr->done_1st_read,
- rm_ptr->inbuf_pos, rm_ptr->inbuf_off); DEBUGPIPEFLUSH);
+ PIPE_DEBUG(PRINTF("enter utf stream: %d inbuf_pos: %d inbuf_off: %d follow: %d\n", rm_ptr->done_1st_read,
+ rm_ptr->inbuf_pos, rm_ptr->inbuf_off, rm_ptr->follow); DEBUGPIPEFLUSH);
assert(IS_UTF_CHSET(chset));
if (rm_ptr->inbuf_pos <= rm_ptr->inbuf_off)
{ /* reset buffer pointers */
@@ -758,18 +909,43 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */
status, bytes2read,rm_ptr->utf_start_pos,rm_ptr->utf_tot_bytes_in_buffer,
char_bytes_read, add_bytes); DEBUGPIPEFLUSH);
char_start = rm_ptr->inbuf_off;
+
+ if (rm_ptr->follow)
+ {
+ PIPE_DEBUG(PRINTF(" %d utf streaming with follow\n", pid); DEBUGPIPEFLUSH);
+
+ /* rms-file device in follow mode */
+ if (timed)
+ {
+ if (0 < msec_timeout)
+ {
+ sleep_left = msec_timeout;
+ } else
+ sleep_left = 0;
+ }
+
+ /* if zeof is set in follow mode then ignore any previous zeof */
+ if (TRUE == io_ptr->dollar.zeof)
+ io_ptr->dollar.zeof = FALSE;
+ }
+
do
{
if (!rm_ptr->done_1st_read)
{
/* need to check BOM */
- status = iorm_get_bom(io_ptr, &blocked_in, rm_ptr->pipe, flags, &tot_bytes_read,
+ if (rm_ptr->follow)
+ {
+ status = iorm_get_bom_fol(io_ptr, &tot_bytes_read, &msec_timeout, timed,
+ &bom_timeout);
+ } else
+ status = iorm_get_bom(io_ptr, &blocked_in, rm_ptr->pipe, flags, &tot_bytes_read,
timer_id, &msec_timeout, pipe_zero_timeout);
- /* if we got an interrupt then the iorm_get_bom did not complete so not as much state needs
- to be saved*/
+ /* if we got an interrupt then the iorm_get_bom did not complete so not as much state
+ needs to be saved*/
- if (pipe_or_fifo && outofband)
+ if (outofband && (pipe_or_fifo || rm_ptr->follow))
{
PIPE_DEBUG(PRINTF(" %d utf1 stream outofband\n", pid); DEBUGPIPEFLUSH);
PUSH_MV_STENT(MVST_ZINTDEV);
@@ -782,7 +958,7 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */
{
pipeintr->end_time = end_time;
pipeintr->end_time_valid = TRUE;
- cancel_timer(timer_id); /* Worry about timer if/when we come back */
+ cancel_timer(timer_id); /* Worry about timer if/when we come back */
}
pipeintr->max_bufflen = exp_width;
/* nothing copied to stringpool.free yet */
@@ -832,10 +1008,91 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */
rm_ptr->utf_start_pos = rm_ptr->utf_tot_bytes_in_buffer = 0;
/* Read CHUNK_SIZE bytes from device into the temporary buffer. By doing this
* one-byte reads can be avoided when in UTF mode.
+ *
*/
- DOREADRLTO2(fildes, rm_ptr->utf_tmp_buffer, CHUNK_SIZE, out_of_time, &blocked_in,
- rm_ptr->pipe, flags, status, &utf_tot_bytes_read,
- timer_id, &msec_timeout, pipe_zero_timeout, pipe_or_fifo, pipe_or_fifo);
+
+ if (rm_ptr->follow)
+ {
+ if (FALSE == bom_timeout)
+ {
+ status = read(fildes, rm_ptr->utf_tmp_buffer, CHUNK_SIZE);
+
+ if (0 == status) /* end of file */
+ {
+ if ((TRUE == timed) && (0 >= sleep_left))
+ {
+ follow_timeout = TRUE;
+ break;
+ }
+
+ /* if a timed read, sleep the minimum of 100 ms and
+ sleep_left. If not a timed read then just sleep 100 ms */
+ if (TRUE == timed)
+ sleep_time = MIN(100,sleep_left);
+ else
+ sleep_time = 100;
+ SHORT_SLEEP(sleep_time);
+ if (TRUE == timed)
+ sleep_left -= sleep_time;
+
+ if (outofband)
+ {
+ PIPE_DEBUG(PRINTF(" %d utf2 stream outofband\n",
+ pid); DEBUGPIPEFLUSH);
+ PUSH_MV_STENT(MVST_ZINTDEV);
+ mv_chain->mv_st_cont.mvs_zintdev.io_ptr = io_ptr;
+ mv_chain->mv_st_cont.mvs_zintdev.curr_sp_buffer.addr
+ = (char *)stringpool.free;
+ mv_chain->mv_st_cont.mvs_zintdev.curr_sp_buffer.len
+ = bytes_count;
+ mv_chain->mv_st_cont.mvs_zintdev.buffer_valid =
+ TRUE;
+ pipeintr->who_saved = pipewhich_readfl;
+ if (0 < msec_timeout && NO_M_TIMEOUT !=
+ msec_timeout)
+ {
+ pipeintr->end_time = end_time;
+ pipeintr->end_time_valid = TRUE;
+ }
+ pipeintr->max_bufflen = exp_width;
+ /* streaming mode uses bytes_count to show how many
+ bytes are in *temp, but the interrupt re-entrant
+ code uses bytes_read */
+ pipeintr->bytes_read = bytes_count;
+ pipeintr->bytes2read = bytes2read;
+ pipeintr->char_count = char_count;
+ pipeintr->add_bytes = add_bytes;
+ pipeintr->bytes_count = bytes_count;
+ PIPE_DEBUG(PRINTF("utf2 stream outofband "
+ "char_bytes_read %d add_bytes "
+ "%d bytes_count %d\n",
+ char_bytes_read,
+ add_bytes, bytes_count);
+ DEBUGPIPEFLUSH);
+ rm_ptr->mupintr = TRUE;
+ /* Don't step on our parade in the interrupt */
+ stringpool.free += bytes_count;
+ (TREF(pipefifo_interrupt))++;
+ outofband_action(FALSE);
+ GTMASSERT; /* Should *never* return from
+ outofband_action */
+ return FALSE; /* For the compiler.. */
+ }
+ continue; /* for now try and read again if eof or no input
+ ready */
+ } else if (-1 == status && errno != EINTR) /* error returned */
+ {
+ bytes_count = 0;
+ break;
+ }
+ }
+ } else
+ {
+ DOREADRLTO2(fildes, rm_ptr->utf_tmp_buffer, CHUNK_SIZE,
+ out_of_time, &blocked_in, rm_ptr->pipe, flags,
+ status, &utf_tot_bytes_read, timer_id,
+ &msec_timeout, pipe_zero_timeout, pipe_or_fifo, pipe_or_fifo);
+ }
PIPE_DEBUG(PRINTF("4: read chunk status: %d utf_tot_bytes_read: %d\n",
status, utf_tot_bytes_read); DEBUGPIPEFLUSH);
@@ -1151,7 +1408,7 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */
real_errno = errno;
if (TRUE == do_clearerr)
clearerr(filstr);
- memcpy(rm_ptr->dollar_device, "0", SIZEOF("0"));
+ memcpy(io_ptr->dollar.device, "0", SIZEOF("0"));
io_ptr->dollar.za = 0;
/* On error, getc() returns EOF while read() returns -1. Both code paths converge here. Thankfully EOF is -1 on all
* platforms that we know of so it is enough to check for -1 status here. Assert that below.
@@ -1169,8 +1426,8 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */
cancel_timer(timer_id);
io_ptr->dollar.za = 9;
/* save error in $device */
- DOLLAR_DEVICE_SET(rm_ptr, real_errno);
- rts_error(VARLSTCNT(1) real_errno);
+ DOLLAR_DEVICE_SET(io_ptr, real_errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) real_errno);
}
ret = FALSE;
}
@@ -1185,7 +1442,8 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */
{
FCNTL3(fildes, F_SETFL, flags, fcntl_res);
if (0 > fcntl_res)
- rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fcntl"), CALLFROM, errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fcntl"),
+ CALLFROM, errno);
}
if ((rm_ptr->pipe && (0 == status)) || (rm_ptr->fifo && (0 == status || real_errno == EAGAIN)))
ret = FALSE;
@@ -1193,7 +1451,7 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */
{
if (out_of_time)
ret = FALSE;
- else
+ else if (!rm_ptr->follow) /* if follow then no timer started */
cancel_timer(timer_id);
}
}
@@ -1204,19 +1462,25 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */
v->str.addr = (char *)stringpool.free; /* ensure valid address */
UNICODE_ONLY(v->str.char_len = 0;)
+ if (rm_ptr->follow)
+ {
+ if (TRUE == io_ptr->dollar.zeof)
+ io_ptr->dollar.zeof = FALSE; /* no EOF in follow mode */
+ return(FALSE);
+ }
/* on end of file set $za to 9 */
len = SIZEOF(ONE_COMMA_DEV_DET_EOF);
- memcpy(rm_ptr->dollar_device, ONE_COMMA_DEV_DET_EOF, len);
+ memcpy(io_ptr->dollar.device, ONE_COMMA_DEV_DET_EOF, len);
io_ptr->dollar.za = 9;
if ((TRUE == io_ptr->dollar.zeof) && (RM_READ == saved_lastop))
- rts_error(VARLSTCNT(1) ERR_IOEOF);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_IOEOF);
io_ptr->dollar.zeof = TRUE;
*dollarx_ptr = 0;
(*dollary_ptr)++;
if (io_ptr->error_handler.len > 0)
- rts_error(VARLSTCNT(1) ERR_IOEOF);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_IOEOF);
if ((pipe_zero_timeout || rm_ptr->fifo) && out_of_time)
{
ret = TRUE;
@@ -1231,6 +1495,8 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */
else
ret = FALSE;
}
+ if (rm_ptr->follow && !rm_ptr->fixed && !line_term_seen)
+ ret = FALSE;
if (!utf_active || !rm_ptr->fixed)
{ /* if Unicode and fixed, already setup the mstr */
v->str.len = bytes_count;
@@ -1255,6 +1521,8 @@ int iorm_readfl (mval *v, int4 width, int4 timeout) /* timeout in seconds */
}
}
}
+ if (follow_timeout)
+ ret = FALSE;
assert(FALSE == rm_ptr->mupintr);
return (rm_ptr->pipe && out_of_time) ? FALSE : ret;
}
diff --git a/sr_unix/iorm_use.c b/sr_unix/iorm_use.c
index 616cbe8..dd6a2e8 100644
--- a/sr_unix/iorm_use.c
+++ b/sr_unix/iorm_use.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -40,7 +40,8 @@
if (-1 == fstat_res) \
{ \
save_errno = errno; \
- rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("fstat"), CALLFROM, save_errno); \
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("fstat"), \
+ CALLFROM, save_errno); \
} \
mode = mode1 = statbuf.st_mode; \
fstat_done = TRUE; \
@@ -123,7 +124,7 @@ void iorm_use(io_desc *iod, mval *pp)
case iop_length:
GET_LONG(length, (pp->str.addr + p_offset));
if (length < 0)
- rts_error(VARLSTCNT(1) ERR_DEVPARMNEG);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DEVPARMNEG);
iod->length = length;
break;
case iop_w_protection:
@@ -147,7 +148,7 @@ void iorm_use(io_desc *iod, mval *pp)
{
GET_LONG(padchar, (pp->str.addr + p_offset));
if (!IS_PADCHAR_VALID(iod->ochset, padchar))
- rts_error(VARLSTCNT(2) ERR_PADCHARINVALID, 0);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(2) ERR_PADCHARINVALID, 0);
rm_ptr->padchar = padchar;
}
break;
@@ -169,9 +170,9 @@ void iorm_use(io_desc *iod, mval *pp)
{ /* only if not open, not UTF, or no reads or writes yet */
GET_LONG(recordsize, (pp->str.addr + p_offset));
if (recordsize <= 0)
- rts_error(VARLSTCNT(1) ERR_RMWIDTHPOS);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_RMWIDTHPOS);
else if (MAX_STRLEN < recordsize)
- rts_error(VARLSTCNT(1) ERR_RMWIDTHTOOBIG);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_RMWIDTHTOOBIG);
rm_ptr->recordsize = recordsize;
rm_ptr->def_recsize = FALSE;
}
@@ -182,12 +183,12 @@ void iorm_use(io_desc *iod, mval *pp)
iorm_flush(iod);
if (lseek(rm_ptr->fildes, (off_t)0, SEEK_SET) == -1)
{
- rts_error(VARLSTCNT(9) ERR_IOERROR, 7, RTS_ERROR_LITERAL("lseek"),
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_IOERROR, 7, RTS_ERROR_LITERAL("lseek"),
RTS_ERROR_LITERAL("REWIND"), CALLFROM, errno);
}
if (fseek(rm_ptr->filstr, (long)0, SEEK_SET) == -1) /* Rewind the input stream */
{
- rts_error(VARLSTCNT(9) ERR_IOERROR, 7, RTS_ERROR_LITERAL("fseek"),
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_IOERROR, 7, RTS_ERROR_LITERAL("fseek"),
RTS_ERROR_LITERAL("REWIND"), CALLFROM, errno);
}
iod->dollar.zeof = FALSE;
@@ -229,18 +230,18 @@ void iorm_use(io_desc *iod, mval *pp)
int ftruncate_res;
if (fseek(rm_ptr->filstr, (long)rm_ptr->file_pos, SEEK_SET) == -1)
{
- rts_error(VARLSTCNT(9) ERR_IOERROR, 7, RTS_ERROR_LITERAL("fseek"),
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_IOERROR, 7, RTS_ERROR_LITERAL("fseek"),
RTS_ERROR_LITERAL("TRUNCATE"), CALLFROM, errno);
}
if (lseek(rm_ptr->fildes, (off_t)rm_ptr->file_pos, SEEK_SET) == -1)
{
- rts_error(VARLSTCNT(9) ERR_IOERROR, 7, RTS_ERROR_LITERAL("lseek"),
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_IOERROR, 7, RTS_ERROR_LITERAL("lseek"),
RTS_ERROR_LITERAL("TRUNCATE"), CALLFROM, errno);
}
FTRUNCATE(rm_ptr->fildes, (off_t)rm_ptr->file_pos, ftruncate_res);
if (0 != ftruncate_res)
{
- rts_error(VARLSTCNT(9) ERR_IOERROR, 7, RTS_ERROR_LITERAL("ftruncate"),
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_IOERROR, 7, RTS_ERROR_LITERAL("ftruncate"),
RTS_ERROR_LITERAL("TRUNCATE"), CALLFROM, errno);
}
iod->dollar.zeof = TRUE;
@@ -281,19 +282,19 @@ void iorm_use(io_desc *iod, mval *pp)
}
CHG_OWNER(iod->trans_name->dollar_io, uic.mem, uic.grp, chown_res);
if (-1 == chown_res)
- rts_error(VARLSTCNT(1) errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) errno);
break;
}
case iop_width:
assert(iod->state == dev_open);
GET_LONG(width, (pp->str.addr + p_offset));
if (0 > width || (0 == width && !IS_UTF_CHSET(iod->ochset)))
- rts_error(VARLSTCNT(1) ERR_RMWIDTHPOS);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_RMWIDTHPOS);
else if (MAX_STRLEN < width)
- rts_error(VARLSTCNT(1) ERR_RMWIDTHTOOBIG);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_RMWIDTHTOOBIG);
/* Do not allow a WIDTH of 1 if either ICHSET or OCHSET is UTF-* */
if ((1 == width) && gtm_utf8_mode && ((IS_UTF_CHSET(iod->ochset)) || (IS_UTF_CHSET(iod->ichset))))
- rts_error(VARLSTCNT(1) ERR_WIDTHTOOSMALL);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_WIDTHTOOSMALL);
if (IS_UTF_CHSET(iod->ochset) && rm_ptr->fixed)
iorm_flush(iod); /* need to flush current record first */
rm_ptr->def_width = FALSE;
@@ -372,7 +373,7 @@ void iorm_use(io_desc *iod, mval *pp)
iod->ochset = temp_chset;
ochset_specified = TRUE;
if (gtm_utf8_mode && !IS_PADCHAR_VALID(iod->ochset, rm_ptr->padchar))
- rts_error(VARLSTCNT(2) ERR_PADCHARINVALID, 0);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(2) ERR_PADCHARINVALID, 0);
}
}
break;
@@ -387,7 +388,7 @@ void iorm_use(io_desc *iod, mval *pp)
break; /* ignore UTF chsets if not utf8_mode */
iod->ochset = temp_chset;
if (gtm_utf8_mode && !IS_PADCHAR_VALID(iod->ochset, rm_ptr->padchar))
- rts_error(VARLSTCNT(2) ERR_PADCHARINVALID, 0);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(2) ERR_PADCHARINVALID, 0);
iod->ichset = iod->ochset;
ochset_specified = ichset_specified = TRUE;
}
@@ -413,6 +414,14 @@ void iorm_use(io_desc *iod, mval *pp)
ichset_specified = ochset_specified = TRUE;
}
break;
+ case iop_follow:
+ if (!rm_ptr->fifo && !rm_ptr->pipe)
+ rm_ptr->follow = TRUE;
+ break;
+ case iop_nofollow:
+ if (!rm_ptr->fifo && !rm_ptr->pipe)
+ rm_ptr->follow = FALSE;
+ break;
default:
break;
}
@@ -448,13 +457,13 @@ void iorm_use(io_desc *iod, mval *pp)
assert(DEF_RM_RECORDSIZE == 32767);
rm_ptr->recordsize = ROUND_DOWN2(rm_ptr->recordsize, 4);
} else if (0 != rm_ptr->recordsize % 2)
- rts_error(VARLSTCNT(3) ERR_RECSIZENOTEVEN, 1, rm_ptr->recordsize);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_RECSIZENOTEVEN, 1, rm_ptr->recordsize);
}
}
if (fstat_done && mode != mode1)
{ /* if the mode has been changed by the qualifiers, reset it */
if (-1 == CHMOD(iod->trans_name->dollar_io, mode))
- rts_error(VARLSTCNT(1) errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) errno);
}
return;
}
diff --git a/sr_unix/iorm_write.c b/sr_unix/iorm_write.c
index 84cbe43..3db26d8 100644
--- a/sr_unix/iorm_write.c
+++ b/sr_unix/iorm_write.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -87,9 +87,9 @@ int iorm_write_utf_ascii(io_desc *iod, char *string, int len)
DOWRITERC(rm_ptr->fildes, outstart, outlen, status);
if (0 != status)
{
- DOLLAR_DEVICE_WRITE(rm_ptr,status);
+ DOLLAR_DEVICE_WRITE(iod, status);
iod->dollar.za = 9;
- rts_error(VARLSTCNT(1) status);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status);
}
rm_ptr->out_bytes += outlen;
}
@@ -146,9 +146,9 @@ void iorm_write_utf(mstr *v)
DOWRITERC(rm_ptr->fildes, outstart, outbytes, status);
if (0 != status)
{
- DOLLAR_DEVICE_WRITE(rm_ptr,status);
+ DOLLAR_DEVICE_WRITE(iod, status);
iod->dollar.za = 9;
- rts_error(VARLSTCNT(1) status);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status);
}
outptr = outstart;
rm_ptr->out_bytes = outbytes = 0;
@@ -206,9 +206,9 @@ void iorm_write_utf(mstr *v)
}
if (0 != status)
{
- DOLLAR_DEVICE_WRITE(rm_ptr,status);
+ DOLLAR_DEVICE_WRITE(iod, status);
iod->dollar.za = 9;
- rts_error(VARLSTCNT(1) status);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status);
}
}
iod->dollar.x += usedwidth;
@@ -246,9 +246,9 @@ void iorm_write_utf(mstr *v)
DOWRITERC(rm_ptr->fildes, temppadarray, padsize, status);
if (0 != status)
{
- DOLLAR_DEVICE_WRITE(rm_ptr,status);
+ DOLLAR_DEVICE_WRITE(iod, status);
iod->dollar.za = 9;
- rts_error(VARLSTCNT(1) status);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status);
}
}
assert(rm_ptr->out_bytes == rm_ptr->recordsize);
@@ -320,14 +320,14 @@ void iorm_write(mstr *v)
#else
rm_ptr = (d_rm_struct *)iod->dev_sp;
#endif
- memcpy(rm_ptr->dollar_device, "0", SIZEOF("0"));
+ memcpy(iod->dollar.device, "0", SIZEOF("0"));
if (rm_ptr->noread)
- rts_error(VARLSTCNT(1) ERR_DEVICEREADONLY);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DEVICEREADONLY);
if (!iod->dollar.zeof && !rm_ptr->fifo && !rm_ptr->pipe)
{
iod->dollar.za = 9;
- rts_error(VARLSTCNT(1) ERR_NOTTOEOFONPUT);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOTTOEOFONPUT);
}
/* if it's a fifo and not system output/error, last operation was not a write and O_NONBLOCK is not set
@@ -337,12 +337,12 @@ void iorm_write(mstr *v)
flags = 0;
FCNTL2(rm_ptr->fildes, F_GETFL, flags);
if (0 > flags)
- rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fcntl"), CALLFROM, errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fcntl"), CALLFROM, errno);
if (!(flags & O_NONBLOCK))
{
FCNTL3(rm_ptr->fildes, F_SETFL, (flags | O_NONBLOCK), fcntl_res);
if (0 > fcntl_res)
- rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fcntl"), CALLFROM, errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("fcntl"), CALLFROM, errno);
}
}
@@ -376,9 +376,9 @@ void iorm_write(mstr *v)
}
if (0 != status)
{
- DOLLAR_DEVICE_WRITE(rm_ptr,status);
+ DOLLAR_DEVICE_WRITE(iod, status);
iod->dollar.za = 9;
- rts_error(VARLSTCNT(1) status);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status);
}
iod->dollar.x += len;
if ((inlen -= len) <= 0)
@@ -394,9 +394,9 @@ void iorm_write(mstr *v)
DOWRITERC(rm_ptr->fildes, RMEOL, STRLEN(RMEOL), status);
if (0 != status)
{
- DOLLAR_DEVICE_WRITE(rm_ptr,status);
+ DOLLAR_DEVICE_WRITE(iod, status);
iod->dollar.za = 9;
- rts_error(VARLSTCNT(1) status);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status);
}
}
diff --git a/sr_unix/iorm_wteol.c b/sr_unix/iorm_wteol.c
index 37e90ab..3ad75e6 100644
--- a/sr_unix/iorm_wteol.c
+++ b/sr_unix/iorm_wteol.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -59,11 +59,11 @@ void iorm_wteol(int4 x,io_desc *iod)
rm_ptr = (d_rm_struct *)iod->dev_sp;
}
if (rm_ptr->noread)
- rts_error(VARLSTCNT(1) ERR_DEVICEREADONLY);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DEVICEREADONLY);
if (!iod->dollar.zeof && !rm_ptr->fifo && !rm_ptr->pipe)
{
iod->dollar.za = 9;
- rts_error(VARLSTCNT(1) ERR_NOTTOEOFONPUT);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOTTOEOFONPUT);
}
rm_ptr->lastop = RM_WRITE;
#ifdef __MVS__
@@ -83,9 +83,9 @@ void iorm_wteol(int4 x,io_desc *iod)
if (-1 == res_size)
{
int real_errno = errno;
- DOLLAR_DEVICE_WRITE(rm_ptr,real_errno);
+ DOLLAR_DEVICE_WRITE(iod, real_errno);
iod->dollar.za = 9;
- rts_error(VARLSTCNT(1) real_errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) real_errno);
}
iod->ochset = CHSET_UTF16BE;
get_chset_desc(&chset_names[iod->ochset]);
@@ -130,9 +130,9 @@ void iorm_wteol(int4 x,io_desc *iod)
DOWRITERC(rm_ptr->fildes, temppadarray, bytes_per_char, status);
if (0 != status)
{
- DOLLAR_DEVICE_WRITE(rm_ptr,status);
+ DOLLAR_DEVICE_WRITE(iod, status);
iod->dollar.za = 9;
- rts_error(VARLSTCNT(1) status);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status);
}
}
assert(rm_ptr->out_bytes == rm_ptr->recordsize);
@@ -153,9 +153,9 @@ void iorm_wteol(int4 x,io_desc *iod)
if (-1 == res_size)
{
int real_errno = errno;
- DOLLAR_DEVICE_WRITE(rm_ptr,real_errno);
+ DOLLAR_DEVICE_WRITE(iod, real_errno);
iod->dollar.za = 9;
- rts_error(VARLSTCNT(1) real_errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) real_errno);
}
assert(res_size == pad_size);
}
@@ -164,9 +164,9 @@ void iorm_wteol(int4 x,io_desc *iod)
DOWRITERC(rm_ptr->fildes, RMEOL, STRLEN(RMEOL), status);
if (0 != status)
{
- DOLLAR_DEVICE_WRITE(rm_ptr,status);
+ DOLLAR_DEVICE_WRITE(iod, status);
iod->dollar.za = 9;
- rts_error(VARLSTCNT(1) status);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status);
}
}
*dollarx_ptr = 0;
diff --git a/sr_unix/iormdef.h b/sr_unix/iormdef.h
index e22b45d..ee1b9bc 100644
--- a/sr_unix/iormdef.h
+++ b/sr_unix/iormdef.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -15,7 +15,6 @@
#define DEF_RM_WIDTH 32767
#define DEF_RM_RECORDSIZE 32767
#define DEF_RM_LENGTH 66
-#define RM_BUFLEN 80
#define CHUNK_SIZE 512
#define ONE_COMMA "1,"
@@ -121,6 +120,7 @@ typedef struct
boolean_t def_width; /* WIDTH has not been changed */
boolean_t def_recsize; /* RECORDSIZE has not been changed */
boolean_t bom_read_one_done; /* If pipe/fifo and UTF8, read one byte to check for bom if not set */
+ boolean_t follow; /* True if disk read with follow - similar to tail -f on a file */
pipe_interrupt pipe_save_state; /* Saved state of interrupted IO */
boolean_t mupintr; /* We were mupip interrupted */
unsigned int lastop; /* Last operation done on file */
@@ -130,8 +130,6 @@ typedef struct
struct io_desc_struct *stderr_child; /* pointer to io descriptor for pipe stderr device */
struct io_desc_struct *stderr_parent; /* pointer to io descriptor for pipe which opened stderr device */
pid_t pipe_pid; /* child process id for reaping on close */
- char dollar_key[RM_BUFLEN]; /* String representation of process id of child - $KEY */
- char dollar_device[RM_BUFLEN];/* String representation $DEVICE */
Dev_param_pairs dev_param_pairs;
int bufsize; /* Size of inbuf */
int outbufsize; /* Size of outbuf */
@@ -163,6 +161,9 @@ typedef struct
int gtm_utf_bomcheck(io_desc *iod, gtm_chset_t *chset, unsigned char *buffer, int len);
int iorm_get_bom(io_desc *io_ptr, int *blocked_in, boolean_t ispipe, int flags, int4 *tot_bytes_read,
TID timer_id, int4 *msec_timeout, boolean_t colon_zero);
+int iorm_get_bom_fol(io_desc *io_ptr, int4 *tot_bytes_read, int4 *msec_timeout, boolean_t timed, boolean_t *bom_timeout);
+int iorm_get_fol(io_desc *io_ptr, int4 *tot_bytes_read, int4 *msec_timeout, boolean_t timed, boolean_t zint_restart,
+ boolean_t *follow_timeout);
int iorm_get(io_desc *io_ptr, int *blocked_in, boolean_t ispipe, int flags, int4 *tot_bytes_read,
TID timer_id, int4 *msec_timeout, boolean_t colon_zero, boolean_t zint_restart);
int iorm_write_utf_ascii(io_desc *iod, char *string, int len);
diff --git a/sr_unix/iott_iocontrol.c b/sr_unix/iott_iocontrol.c
new file mode 100644
index 0000000..10ae0cb
--- /dev/null
+++ b/sr_unix/iott_iocontrol.c
@@ -0,0 +1,54 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <sys/types.h>
+#include "gtm_inet.h"
+
+#include "gtm_string.h"
+#include "io.h"
+#include "iotcpdef.h"
+
+GBLREF io_pair io_curr_device;
+
+void iott_iocontrol(mstr *d)
+{
+ return;
+}
+
+void iott_dlr_device(mstr *d)
+{
+ io_desc *iod;
+ int len;
+
+ iod = io_curr_device.out;
+ len = STRLEN(iod->dollar.device);
+ /* verify internal buffer has enough space for $DEVICE string value */
+ assert((int)d->len > len);
+ memcpy(d->addr, iod->dollar.device, len);
+ d->len = len;
+ return;
+}
+
+void iott_dlr_key(mstr *d)
+{
+ io_desc *iod;
+ int len;
+
+ iod = io_curr_device.out;
+ len = STRLEN(iod->dollar.key);
+ /* verify internal buffer has enough space for $KEY string value */
+ assert((int)d->len > len);
+ memcpy(d->addr, iod->dollar.key, len);
+ d->len = len;
+ return;
+}
diff --git a/sr_unix/iott_open.c b/sr_unix/iott_open.c
index 89410bb..495baee 100644
--- a/sr_unix/iott_open.c
+++ b/sr_unix/iott_open.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -32,8 +32,15 @@
GBLREF int COLUMNS, GTM_LINES, AUTO_RIGHT_MARGIN;
GBLREF uint4 gtm_principal_editing_defaults;
GBLREF io_pair io_std_device;
-LITREF unsigned char io_params_size[];
GBLREF boolean_t gtm_utf8_mode;
+LITREF unsigned char io_params_size[];
+
+error_def(ERR_BADCHSET);
+error_def(ERR_NOTERMENTRY);
+error_def(ERR_NOTERMENV);
+error_def(ERR_NOTERMINFODB);
+error_def(ERR_TCGETATTR);
+error_def(ERR_ZINTRECURSEIO);
short iott_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 timeout)
{
@@ -44,13 +51,7 @@ short iott_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
int save_errno;
int p_offset;
mstr chset;
-
- error_def(ERR_NOTERMENV);
- error_def(ERR_NOTERMENTRY);
- error_def(ERR_NOTERMINFODB);
- error_def(ERR_TCGETATTR);
- error_def(ERR_BADCHSET);
- error_def(ERR_ZINTRECURSEIO);
+ boolean_t empt = FALSE;
ioptr = dev_name->iod;
if (ioptr->state == dev_never_opened)
@@ -68,7 +69,7 @@ short iott_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
}
tt_ptr = (d_tt_struct *)dev_name->iod->dev_sp;
if (tt_ptr->mupintr)
- rts_error(VARLSTCNT(1) ERR_ZINTRECURSEIO);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZINTRECURSEIO);
p_offset = 0;
while (*(pp->str.addr + p_offset) != iop_eol)
{
@@ -80,8 +81,12 @@ short iott_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
break;
} else if (ch == iop_canonical)
tt_ptr->canonical = TRUE;
- else if (ch == iop_nocanonical)
+ else if (ch == iop_nocanonical)
tt_ptr->canonical = FALSE;
+ else if (ch == iop_empterm)
+ empt = TRUE;
+ else if (ch == iop_noempterm)
+ empt = FALSE;
else if (iop_m == ch)
ioptr->ichset = ioptr->ochset = CHSET_M;
else if (gtm_utf8_mode && iop_utf8 == ch)
@@ -102,7 +107,7 @@ short iott_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
else
ioptr->ochset = CHSET_UTF8;
else
- rts_error(VARLSTCNT(4) ERR_BADCHSET, 2, chset.len, chset.addr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_BADCHSET, 2, chset.len, chset.addr);
}
p_offset += ((IOP_VAR_SIZE == io_params_size[ch]) ?
(unsigned char)*(pp->str.addr + p_offset) + 1 : io_params_size[ch]);
@@ -119,7 +124,7 @@ short iott_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
{
save_errno = errno;
if (gtm_isanlp(tt_ptr->fildes) == 0)
- rts_error(VARLSTCNT(4) ERR_TCGETATTR, 1, tt_ptr->fildes, save_errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TCGETATTR, 1, tt_ptr->fildes, save_errno);
}
if (IS_GTM_IMAGE)
/* Only the true runtime runs with the modified terminal settings */
@@ -132,12 +137,12 @@ short iott_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
env_term = GETENV("TERM");
if (!env_term)
{
- rts_error(VARLSTCNT(1) ERR_NOTERMENV);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOTERMENV);
env_term = "unknown";
}
- rts_error(VARLSTCNT(4) ERR_NOTERMENTRY, 2, LEN_AND_STR(env_term));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_NOTERMENTRY, 2, LEN_AND_STR(env_term));
} else
- rts_error(VARLSTCNT(1) ERR_NOTERMINFODB);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOTERMINFODB);
}
ioptr->width = COLUMNS;
ioptr->length = GTM_LINES;
@@ -151,6 +156,8 @@ short iott_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 time
ioptr->ichset = ioptr->ochset = gtm_utf8_mode ? CHSET_UTF8 : CHSET_M; /* default */
} else
tt_ptr->ext_cap = 0;
+ if (empt)
+ tt_ptr->ext_cap |= TT_EMPTERM;
if (tt_ptr->default_mask_term)
{
memset(&tt_ptr->mask_term.mask[0], 0, SIZEOF(io_termmask));
diff --git a/sr_unix/iott_rdone.c b/sr_unix/iott_rdone.c
index eaf7807..c01f503 100644
--- a/sr_unix/iott_rdone.c
+++ b/sr_unix/iott_rdone.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -51,6 +51,13 @@ GBLREF boolean_t gtm_utf8_mode;
LITREF unsigned char lower_to_upper_table[];
+error_def(ERR_CTRAP);
+error_def(ERR_IOEOF);
+error_def(ERR_NOPRINCIO);
+error_def(ERR_ZINTRECURSEIO);
+error_def(ERR_STACKOFLOW);
+error_def(ERR_STACKCRIT);
+
int iott_rdone (mint *v, int4 timeout) /* timeout in seconds */
{
boolean_t ret = FALSE, timed, utf8_active, zint_restart, first_time;
@@ -76,13 +83,6 @@ int iott_rdone (mint *v, int4 timeout) /* timeout in seconds */
ABS_TIME cur_time, end_time;
mv_stent *mv_zintdev;
- error_def(ERR_CTRAP);
- error_def(ERR_IOEOF);
- error_def(ERR_NOPRINCIO);
- error_def(ERR_ZINTRECURSEIO);
- error_def(ERR_STACKOFLOW);
- error_def(ERR_STACKCRIT);
-
io_ptr = io_curr_device.in;
assert (io_ptr->state == dev_open);
iott_flush(io_curr_device.out);
@@ -103,7 +103,7 @@ int iott_rdone (mint *v, int4 timeout) /* timeout in seconds */
{
tt_ptr->mupintr = FALSE;
tt_state->who_saved = ttwhichinvalid;
- rts_error(VARLSTCNT(1) ERR_ZINTRECURSEIO);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZINTRECURSEIO);
}
if (ttrdone != tt_state->who_saved)
GTMASSERT; /* ZINTRECURSEIO should have caught */
@@ -151,7 +151,7 @@ int iott_rdone (mint *v, int4 timeout) /* timeout in seconds */
if (0 != status)
{
io_ptr->dollar.za = 9;
- rts_error(VARLSTCNT(1) status);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status);
}
}
}
@@ -249,7 +249,7 @@ int iott_rdone (mint *v, int4 timeout) /* timeout in seconds */
io_ptr->dollar.za = 9;
if (timed && (0 == msec_timeout))
iott_rterm(io_ptr);
- rts_error(VARLSTCNT(1) errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) errno);
break;
}
} else if (0 == selstat)
@@ -350,7 +350,7 @@ int iott_rdone (mint *v, int4 timeout) /* timeout in seconds */
if (0 == msec_timeout)
iott_rterm(io_ptr);
}
- rts_error(VARLSTCNT(3) ERR_CTRAP, 1, ctrap_action_is);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_CTRAP, 1, ctrap_action_is);
ret = FALSE;
break;
}
@@ -430,7 +430,7 @@ int iott_rdone (mint *v, int4 timeout) /* timeout in seconds */
if (0 == msec_timeout)
iott_rterm(io_ptr);
}
- rts_error(VARLSTCNT(1) status);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status);
}
}
break;
@@ -442,7 +442,7 @@ int iott_rdone (mint *v, int4 timeout) /* timeout in seconds */
io_ptr->dollar.za = 9;
if (timed && (0 == msec_timeout))
iott_rterm(io_ptr);
- rts_error(VARLSTCNT(1) errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) errno);
break;
}
} else
@@ -461,20 +461,20 @@ int iott_rdone (mint *v, int4 timeout) /* timeout in seconds */
prin_in_dev_failure = TRUE;
else
{
- send_msg(VARLSTCNT(1) ERR_NOPRINCIO);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOPRINCIO);
stop_image_no_core();
}
}
if (io_ptr->dollar.zeof)
{
io_ptr->dollar.za = 9;
- rts_error(VARLSTCNT(1) ERR_IOEOF);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_IOEOF);
} else
{
io_ptr->dollar.zeof = TRUE;
io_ptr->dollar.za = 0;
if (io_ptr->error_handler.len > 0)
- rts_error(VARLSTCNT(1) ERR_IOEOF);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_IOEOF);
}
break;
}
@@ -492,7 +492,7 @@ int iott_rdone (mint *v, int4 timeout) /* timeout in seconds */
if (0 != status)
{
io_ptr->dollar.za = 9;
- rts_error(VARLSTCNT(1) status);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status);
}
}
@@ -536,9 +536,7 @@ int iott_rdone (mint *v, int4 timeout) /* timeout in seconds */
*zb_ptr++ = 0;
}
else
- {
io_ptr->dollar.zb[0] = '\0';
- }
if ((!(msk_in & tt_ptr->mask_term.mask[msk_num])) && (!(mask & TRM_NOECHO)))
{
if ((io_ptr->dollar.x += inchar_width) >= io_ptr->width && io_ptr->wrap)
@@ -548,10 +546,11 @@ int iott_rdone (mint *v, int4 timeout) /* timeout in seconds */
io_ptr->dollar.y %= io_ptr->length;
io_ptr->dollar.x %= io_ptr->width;
if (io_ptr->dollar.x == 0)
- DOWRITE(tt_ptr->fildes, NATIVE_TTEOL, strlen(NATIVE_TTEOL));
+ DOWRITE(tt_ptr->fildes, NATIVE_TTEOL, STRLEN(NATIVE_TTEOL));
}
}
}
+ memcpy(io_ptr->dollar.key, io_ptr->dollar.zb, (zb_ptr - io_ptr->dollar.zb));
return ret;
}
diff --git a/sr_unix/iott_readfl.c b/sr_unix/iott_readfl.c
index d60fe2a..e93ab9a 100644
--- a/sr_unix/iott_readfl.c
+++ b/sr_unix/iott_readfl.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -80,6 +80,13 @@ static readonly char dc1 = 17;
static readonly char dc3 = 19;
static readonly unsigned char eraser[3] = { NATIVE_BS, NATIVE_SP, NATIVE_BS };
+error_def(ERR_CTRAP);
+error_def(ERR_IOEOF);
+error_def(ERR_NOPRINCIO);
+error_def(ERR_ZINTRECURSEIO);
+error_def(ERR_STACKOFLOW);
+error_def(ERR_STACKCRIT);
+
#ifdef UNICODE_SUPPORTED
/* Maintenance of $ZB on a badchar error and returning partial data (if any) */
@@ -122,6 +129,8 @@ void iott_readfl_badchar(mval *vmvalptr, wint_t *dataptr32, int datalen,
iod = io_curr_device.in;
memcpy(iod->dollar.zb, delimptr, MIN(delimlen, ESC_LEN - 1));
iod->dollar.zb[MIN(delimlen, ESC_LEN - 1)] = '\0';
+ memcpy(iod->dollar.key, delimptr, MIN(delimlen, DD_BUFLEN - 1));
+ iod->dollar.key[MIN(delimlen, DD_BUFLEN - 1)] = '\0';
}
}
}
@@ -151,7 +160,7 @@ int iott_readfl(mval *v, int4 length, int4 timeout) /* timeout in seconds */
int outlen; /* total characters in line so far */
int keypad_len, backspace, delete;
int up, down, right, left, insert_key;
- boolean_t escape_edit;
+ boolean_t escape_edit, empterm;
int4 msec_timeout; /* timeout in milliseconds */
io_desc *io_ptr;
d_tt_struct *tt_ptr;
@@ -165,13 +174,6 @@ int iott_readfl(mval *v, int4 length, int4 timeout) /* timeout in seconds */
struct timeval input_timeval;
struct timeval save_input_timeval;
- error_def(ERR_CTRAP);
- error_def(ERR_IOEOF);
- error_def(ERR_NOPRINCIO);
- error_def(ERR_ZINTRECURSEIO);
- error_def(ERR_STACKOFLOW);
- error_def(ERR_STACKCRIT);
-
assert(stringpool.free >= stringpool.base);
assert(stringpool.free <= stringpool.top);
io_ptr = io_curr_device.in;
@@ -179,6 +181,7 @@ int iott_readfl(mval *v, int4 length, int4 timeout) /* timeout in seconds */
assert(dev_open == io_ptr->state);
iott_flush(io_curr_device.out);
insert_mode = !(TT_NOINSERT & tt_ptr->ext_cap); /* get initial mode */
+ empterm = (TT_EMPTERM & tt_ptr->ext_cap);
ioptr_width = io_ptr->width;
utf8_active = gtm_utf8_mode ? (CHSET_M != io_ptr->ichset) : FALSE;
/* if utf8_active, need room for multi byte characters plus wint_t buffer */
@@ -193,7 +196,7 @@ int iott_readfl(mval *v, int4 length, int4 timeout) /* timeout in seconds */
{
tt_ptr->mupintr = FALSE;
tt_state->who_saved = ttwhichinvalid;
- rts_error(VARLSTCNT(1) ERR_ZINTRECURSEIO);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZINTRECURSEIO);
}
assert(length == tt_state->length);
if (ttread != tt_state->who_saved)
@@ -280,7 +283,7 @@ int iott_readfl(mval *v, int4 length, int4 timeout) /* timeout in seconds */
if (0 != status)
{
io_ptr->dollar.za = 9;
- rts_error(VARLSTCNT(1) status);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status);
}
}
}
@@ -304,7 +307,7 @@ int iott_readfl(mval *v, int4 length, int4 timeout) /* timeout in seconds */
if (0 != status)
{
io_ptr->dollar.za = 9;
- rts_error(VARLSTCNT(1) status);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status);
}
}
#endif
@@ -430,7 +433,7 @@ int iott_readfl(mval *v, int4 length, int4 timeout) /* timeout in seconds */
io_ptr->dollar.y++;
tt_ptr->discard_lf = FALSE;
if (io_ptr->error_handler.len > 0)
- rts_error(VARLSTCNT(1) ERR_IOEOF);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_IOEOF);
break;
} else
io_ptr->dollar.zeof = FALSE;
@@ -518,7 +521,7 @@ int iott_readfl(mval *v, int4 length, int4 timeout) /* timeout in seconds */
GETASCII(asc_inchar,inchar);
if (!edit_mode && (dx >= ioptr_width) && io_ptr->wrap && !(mask & TRM_NOECHO))
{
- DOWRITE(tt_ptr->fildes, NATIVE_TTEOL, strlen(NATIVE_TTEOL));
+ DOWRITE(tt_ptr->fildes, NATIVE_TTEOL, STRLEN(NATIVE_TTEOL));
dx = 0;
}
if ((' ' > INPUT_CHAR) && (tt_ptr->enbld_outofbands.mask & (1 << INPUT_CHAR)))
@@ -529,7 +532,7 @@ int iott_readfl(mval *v, int4 length, int4 timeout) /* timeout in seconds */
SEND_KEYPAD_LOCAL
if (!msec_timeout)
iott_rterm(io_ptr);
- rts_error(VARLSTCNT(3) ERR_CTRAP, 1, ctrap_action_is);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_CTRAP, 1, ctrap_action_is);
break;
}
if (((0 != (mask & TRM_ESCAPE)) || edit_mode)
@@ -576,7 +579,10 @@ int iott_readfl(mval *v, int4 length, int4 timeout) /* timeout in seconds */
assert(0 <= instr);
assert(!edit_mode || 0 <= dx);
assert(outlen >= instr);
- if ((int)inchar == tt_ptr->ttio_struct->c_cc[VERASE]
+ /* For most of the terminal the 'kbs' string capability is a byte in length. It means that it is
+ Not treated as escape sequence. So explicitly check if the input corresponds to the 'kbs' */
+ if ((((int)inchar == tt_ptr->ttio_struct->c_cc[VERASE]) ||
+ (empterm && ('\0' == KEY_BACKSPACE[1]) && (inchar == KEY_BACKSPACE[0])))
&& !(mask & TRM_PASTHRU))
{
if (0 < instr && (edit_mode || 0 < dx))
@@ -628,6 +634,11 @@ int iott_readfl(mval *v, int4 length, int4 timeout) /* timeout in seconds */
}
}
dx_outlen = compute_dx(BUFF_ADDR(0), outlen, ioptr_width, dx_start);
+ } else if (empterm && (0 == outlen))
+ {
+ assert(zb_ptr == io_ptr->dollar.zb);
+ *zb_ptr++ = (unsigned char)INPUT_CHAR;
+ break;
}
} else
{
@@ -913,7 +924,7 @@ int iott_readfl(mval *v, int4 length, int4 timeout) /* timeout in seconds */
prin_in_dev_failure = TRUE;
else
{
- send_msg(VARLSTCNT(1) ERR_NOPRINCIO);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOPRINCIO);
stop_image_no_core();
}
}
@@ -921,14 +932,14 @@ int iott_readfl(mval *v, int4 length, int4 timeout) /* timeout in seconds */
{
io_ptr->dollar.za = 9;
SEND_KEYPAD_LOCAL
- rts_error(VARLSTCNT(1) ERR_IOEOF);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_IOEOF);
} else
{
io_ptr->dollar.zeof = TRUE;
io_ptr->dollar.za = 0;
SEND_KEYPAD_LOCAL
if (0 < io_ptr->error_handler.len)
- rts_error(VARLSTCNT(1) ERR_IOEOF);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_IOEOF);
}
break;
}
@@ -940,7 +951,7 @@ int iott_readfl(mval *v, int4 length, int4 timeout) /* timeout in seconds */
io_ptr->dollar.y++;
SEND_KEYPAD_LOCAL
if (0 < io_ptr->error_handler.len)
- rts_error(VARLSTCNT(1) ERR_IOEOF);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_IOEOF);
break;
}
} else if (EINTR != errno) /* rdlen < 0 */
@@ -948,7 +959,7 @@ int iott_readfl(mval *v, int4 length, int4 timeout) /* timeout in seconds */
term_error_line = __LINE__;
goto term_error;
}
- if (FINI == io_ptr->esc_state)
+ if (FINI == io_ptr->esc_state)
{
int zb_len = (int)(zb_ptr - io_ptr->dollar.zb);
@@ -1006,6 +1017,10 @@ int iott_readfl(mval *v, int4 length, int4 timeout) /* timeout in seconds */
goto term_error;
}
dx_outlen = compute_dx(BUFF_ADDR(0), outlen, ioptr_width, dx_start);
+ } else if (empterm && 0 == outlen)
+ {
+ assert(instr == 0);
+ break;
}
escape_edit = TRUE;
}
@@ -1100,6 +1115,7 @@ int iott_readfl(mval *v, int4 length, int4 timeout) /* timeout in seconds */
}
} while (outlen < length);
*zb_ptr++ = 0;
+ memcpy(io_ptr->dollar.key, io_ptr->dollar.zb, (zb_ptr - io_ptr->dollar.zb));
if (!msec_timeout)
{
iott_rterm(io_ptr);
@@ -1112,7 +1128,7 @@ int iott_readfl(mval *v, int4 length, int4 timeout) /* timeout in seconds */
if (0 != status)
{
io_ptr->dollar.za = 9;
- rts_error(VARLSTCNT(1) status);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status);
}
}
SEND_KEYPAD_LOCAL /* to turn keypad off if possible */
@@ -1157,7 +1173,7 @@ int iott_readfl(mval *v, int4 length, int4 timeout) /* timeout in seconds */
io_ptr->dollar.y %= io_ptr->length;
io_ptr->dollar.x %= ioptr_width;
if (0 == io_ptr->dollar.x)
- DOWRITE(tt_ptr->fildes, NATIVE_TTEOL, strlen(NATIVE_TTEOL));
+ DOWRITE(tt_ptr->fildes, NATIVE_TTEOL, STRLEN(NATIVE_TTEOL));
}
}
return ((short)ret);
@@ -1169,6 +1185,6 @@ term_error:
SEND_KEYPAD_LOCAL /* to turn keypad off if possible */
if (!msec_timeout)
iott_rterm(io_ptr);
- rts_error(VARLSTCNT(1) save_errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) save_errno);
return FALSE;
}
diff --git a/sr_unix/iott_use.c b/sr_unix/iott_use.c
index baefe85..a8ce829 100644
--- a/sr_unix/iott_use.c
+++ b/sr_unix/iott_use.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -94,7 +94,7 @@ void iott_use(io_desc *iod, mval *pp)
{
if (tt_ptr->mupintr)
if (dollar_zininterrupt)
- rts_error(VARLSTCNT(1) ERR_ZINTRECURSEIO);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZINTRECURSEIO);
else
{ /* The interrupted read was not properly resumed so clear it now */
tt_ptr->mupintr = FALSE;
@@ -111,11 +111,11 @@ void iott_use(io_desc *iod, mval *pp)
prin_out_dev_failure = TRUE;
else
{
- send_msg(VARLSTCNT(1) ERR_NOPRINCIO);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOPRINCIO);
stop_image_no_core();
}
}
- rts_error(VARLSTCNT(4) ERR_TCGETATTR, 1, tt_ptr->fildes, save_errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TCGETATTR, 1, tt_ptr->fildes, save_errno);
}
flush_input = FALSE;
d_in = iod->pair.in;
@@ -135,6 +135,12 @@ void iott_use(io_desc *iod, mval *pp)
tt_ptr->canonical = FALSE;
t.c_lflag &= ~(ICANON);
break;
+ case iop_empterm:
+ tt_ptr->ext_cap |= TT_EMPTERM;
+ break;
+ case iop_noempterm:
+ tt_ptr->ext_cap &= ~TT_EMPTERM;
+ break;
case iop_cenable:
temp_ptr = (d_tt_struct *)io_std_device.in->dev_sp;
if (tt_ptr->fildes == temp_ptr->fildes && !ctrlc_on)
@@ -223,7 +229,7 @@ void iott_use(io_desc *iod, mval *pp)
ttab = pp->str.addr + p_offset + 1;
if ((fil_type = namelook(filter_index, filter_names, ttab, len)) < 0)
{
- rts_error(VARLSTCNT(1) ERR_TTINVFILTER);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_TTINVFILTER);
return;
}
switch (fil_type)
@@ -265,7 +271,7 @@ void iott_use(io_desc *iod, mval *pp)
case iop_length:
GET_LONG(length, pp->str.addr + p_offset);
if (0 > length)
- rts_error(VARLSTCNT(1) ERR_DEVPARMNEG);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DEVPARMNEG);
d_out->length = length;
break;
case iop_pasthru:
@@ -282,7 +288,7 @@ void iott_use(io_desc *iod, mval *pp)
temp_ptr = (d_tt_struct *)io_std_device.in->dev_sp;
DOWRITERC(temp_ptr->fildes, &dc1, 1, status);
if (0 != status)
- rts_error(VARLSTCNT(1) status);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status);
mask_in &= (~TRM_READSYNC);
break;
case iop_terminator:
@@ -333,10 +339,10 @@ void iott_use(io_desc *iod, mval *pp)
case iop_width:
GET_LONG(width, pp->str.addr + p_offset);
if (0 > width)
- rts_error(VARLSTCNT(1) ERR_DEVPARMNEG);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_DEVPARMNEG);
/* Do not allow a WIDTH of 1 if UTF mode (ICHSET or OCHSET is not M) */
if ((1 == width) && ((CHSET_M != d_in->ochset) || (CHSET_M != d_in->ichset)))
- rts_error(VARLSTCNT(1) ERR_WIDTHTOOSMALL);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_WIDTHTOOSMALL);
if (0 == width)
{
d_out->wrap = FALSE;
@@ -409,14 +415,14 @@ void iott_use(io_desc *iod, mval *pp)
temp_ptr = (d_tt_struct *)d_in->dev_sp;
Tcsetattr(tt_ptr->fildes, TCSANOW, &t, status, save_errno);
if (0 != status)
- rts_error(VARLSTCNT(4) ERR_TCSETATTR, 1, tt_ptr->fildes, save_errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TCSETATTR, 1, tt_ptr->fildes, save_errno);
temp_ptr->term_ctrl = mask_in;
memcpy(&temp_ptr->mask_term, &mask_term, SIZEOF(io_termmask));
if (flush_input)
{
TCFLUSH(tt_ptr->fildes, TCIFLUSH, status);
if (0 != status)
- rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LIT_AND_LEN("tcflush input"),
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LIT_AND_LEN("tcflush input"),
CALLFROM, errno);
}
} else if (tt_ptr->mupintr && !dollar_zininterrupt)
diff --git a/sr_unix/iottdef.h b/sr_unix/iottdef.h
index 95d83b0..f76bcfc 100644
--- a/sr_unix/iottdef.h
+++ b/sr_unix/iottdef.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -33,6 +33,7 @@
#define TT_EDITING 0x1000
#define TT_NOINSERT 0x2000
+#define TT_EMPTERM 0x4000
enum tt_which
{
diff --git a/sr_unix/ipcrmid.c b/sr_unix/ipcrmid.c
index 8636ec5..794e754 100644
--- a/sr_unix/ipcrmid.c
+++ b/sr_unix/ipcrmid.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -17,6 +17,7 @@
#include <sys/sem.h>
#include <sys/shm.h>
#include <errno.h>
+#include "gtm_string.h"
#include "gtm_limits.h"
#include "io.h"
@@ -41,7 +42,8 @@ error_def(ERR_SYSCALL);
*/
int sem_rmid(int ipcid)
{
- int status, save_errno;
+ int status, save_errno;
+ char buff[128];
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
@@ -52,22 +54,35 @@ int sem_rmid(int ipcid)
if (EPERM != errno)
{
save_errno = errno;
- send_msg(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("semctl(IPC_RMID)"), CALLFROM, save_errno);
+ SNPRINTF(buff, 128, "semctl(IPC_RMID, %d)", ipcid);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_STR(buff), CALLFROM, save_errno);
+ errno = save_errno;
return -1;
} else
{
- if (0 != REMIPC(REMOVE_SEM, ipcid))
+ if (0 != (status = REMIPC(REMOVE_SEM, ipcid)))
+ {
+ errno = status;
return -1;
+ }
}
}
- } DEBUG_ONLY(else if (0 != REMIPC(REMOVE_SEM, ipcid)) return -1);
+ }
+# ifdef DEBUG
+ else if (0 != (status = REMIPC(REMOVE_SEM, ipcid)))
+ {
+ errno = status;
+ return -1;
+ }
+# endif
return 0;
}
/* Remove a shared memory id */
int shm_rmid(int ipcid)
{
- int status, save_errno;
+ int status, save_errno;
+ char buff[128];
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
@@ -78,14 +93,26 @@ int shm_rmid(int ipcid)
if (EPERM != errno)
{
save_errno = errno;
- send_msg(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("shmctl(IPC_RMID)"), CALLFROM, save_errno);
+ SNPRINTF(buff, 128, "semctl(IPC_RMID, %d)", ipcid);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_STR(buff), CALLFROM, save_errno);
+ errno = save_errno;
return -1;
} else
{
- if (0 != REMIPC(REMOVE_SHM, ipcid))
+ if (0 != (status = REMIPC(REMOVE_SHM, ipcid)))
+ {
+ errno = status;
return -1;
+ }
}
}
- } DEBUG_ONLY(else if (0 != REMIPC(REMOVE_SHM, ipcid)) return -1);
+ }
+# ifdef DEBUG
+ else if (0 != (status = REMIPC(REMOVE_SHM, ipcid)))
+ {
+ errno = status;
+ return -1;
+ }
+# endif
return 0;
}
diff --git a/sr_unix/jnl_file_extend.c b/sr_unix/jnl_file_extend.c
index 530e36a..90c4834 100644
--- a/sr_unix/jnl_file_extend.c
+++ b/sr_unix/jnl_file_extend.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -131,24 +131,26 @@ uint4 jnl_file_extend(jnl_private_control *jpc, uint4 total_jnl_rec_size)
SETUP_THREADGBL_ACCESS;
if (!ANTICIPATORY_FREEZE_ENABLED(csa))
{
- send_msg(VARLSTCNT(6) ERR_NOSPACEEXT, 4,
- JNL_LEN_STR(csd), new_blocks, avail_blocks);
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_NOSPACEEXT, 4,
+ JNL_LEN_STR(csd), new_blocks, avail_blocks);
new_blocks = 0;
jpc->status = SS_NORMAL;
break;
} else
- send_msg(VARLSTCNT(6) MAKE_MSG_WARNING(ERR_NOSPACEEXT), 4,
- JNL_LEN_STR(csd), new_blocks, avail_blocks);
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(6) MAKE_MSG_WARNING(ERR_NOSPACEEXT), 4,
+ JNL_LEN_STR(csd), new_blocks, avail_blocks);
} else
- send_msg(VARLSTCNT(5) ERR_DSKSPACEFLOW, 3, JNL_LEN_STR(csd), (avail_blocks - warn_blocks));
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_DSKSPACEFLOW, 3, JNL_LEN_STR(csd),
+ (avail_blocks - warn_blocks));
}
} else
- send_msg(VARLSTCNT(5) ERR_JNLFILEXTERR, 2, JNL_LEN_STR(csd), status);
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_JNLFILEXTERR, 2, JNL_LEN_STR(csd), status);
new_alq = jb->filesize + new_blocks;
/* ensure current journal file size is well within autoswitchlimit --> design constraint */
assert(csd->autoswitchlimit >= jb->filesize);
if (csd->autoswitchlimit < (jb->filesize + (EXTEND_WARNING_FACTOR * new_blocks))) /* close to max */
- send_msg(VARLSTCNT(5) ERR_JNLSPACELOW, 3, JNL_LEN_STR(csd), csd->autoswitchlimit - jb->filesize);
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_JNLSPACELOW, 3, JNL_LEN_STR(csd),
+ csd->autoswitchlimit - jb->filesize);
if (csd->autoswitchlimit < new_alq)
{ /* Reached max, need to autoswitch */
/* Ensure new journal file can hold the entire current transaction's journal record requirements */
@@ -198,10 +200,11 @@ uint4 jnl_file_extend(jnl_private_control *jpc, uint4 total_jnl_rec_size)
} else
{
if (SS_NORMAL != jpc->status)
- rts_error(VARLSTCNT(7) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(gv_cur_region),
- jpc->status);
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(7) jnl_status, 4, JNL_LEN_STR(csd),
+ DB_LEN_STR(gv_cur_region), jpc->status);
else
- rts_error(VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(gv_cur_region));
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd),
+ DB_LEN_STR(gv_cur_region));
}
assert(!jgbl.forw_phase_recovery || (NULL != jgbl.mur_pini_addr_reset_fnptr));
assert(jgbl.forw_phase_recovery || (NULL == jgbl.mur_pini_addr_reset_fnptr));
@@ -220,7 +223,7 @@ uint4 jnl_file_extend(jnl_private_control *jpc, uint4 total_jnl_rec_size)
assert(csd->jnl_before_image == jnl_info.before_images);
csd->jnl_checksum = jnl_info.checksum;
csd->jnl_eovtn = csd->trans_hist.curr_tn;
- send_msg(VARLSTCNT(4) ERR_NEWJNLFILECREAT, 2, JNL_LEN_STR(csd));
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_NEWJNLFILECREAT, 2, JNL_LEN_STR(csd));
fc = gv_cur_region->dyn.addr->file_cntl;
fc->op = FC_WRITE;
fc->op_buff = (sm_uc_ptr_t)csd;
@@ -228,17 +231,18 @@ uint4 jnl_file_extend(jnl_private_control *jpc, uint4 total_jnl_rec_size)
fc->op_pos = 1;
status = dbfilop(fc);
if (SS_NORMAL != status)
- send_msg(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region), status);
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region), status);
assert(JNL_ENABLED(csa));
/* call jnl_ensure_open instead of jnl_file_open to make sure jpc->pini_addr is set to 0 */
jnl_status = jnl_ensure_open(); /* sets jpc->status */
if (0 != jnl_status)
{
if (jpc->status)
- rts_error(VARLSTCNT(7) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(gv_cur_region),
- jpc->status);
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(7) jnl_status, 4, JNL_LEN_STR(csd),
+ DB_LEN_STR(gv_cur_region), jpc->status);
else
- rts_error(VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(gv_cur_region));
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd),
+ DB_LEN_STR(gv_cur_region));
}
assert(jb->filesize == csd->jnl_alq);
if (csd->jnl_alq + csd->jnl_deq <= csd->autoswitchlimit)
@@ -257,7 +261,7 @@ uint4 jnl_file_extend(jnl_private_control *jpc, uint4 total_jnl_rec_size)
}
} else
{
- send_msg(VARLSTCNT(4) ERR_JNLNOCREATE, 2, JNL_LEN_STR(csd));
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_JNLNOCREATE, 2, JNL_LEN_STR(csd));
jpc->status = ERR_JNLNOCREATE;
new_blocks = -1;
}
@@ -273,7 +277,7 @@ uint4 jnl_file_extend(jnl_private_control *jpc, uint4 total_jnl_rec_size)
if (SS_NORMAL != jpc->status)
{
assert(FALSE);
- rts_error(VARLSTCNT(5) ERR_JNLRDERR, 2, JNL_LEN_STR(csd), jpc->status);
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_JNLRDERR, 2, JNL_LEN_STR(csd), jpc->status);
}
assert((header->virtual_size + new_blocks) == new_alq);
jb->filesize = new_alq; /* Actually this is virtual file size blocks */
@@ -282,8 +286,8 @@ uint4 jnl_file_extend(jnl_private_control *jpc, uint4 total_jnl_rec_size)
header, read_write_size, jpc->status, jpc->status2);
if (SS_NORMAL != jpc->status)
{
- assert(FALSE);
- rts_error(VARLSTCNT(5) ERR_JNLWRERR, 2, JNL_LEN_STR(csd), jpc->status);
+ assert(WBTEST_RECOVER_ENOSPC == gtm_white_box_test_case_number);
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_JNLWRERR, 2, JNL_LEN_STR(csd), jpc->status);
}
}
if (0 >= new_blocks)
diff --git a/sr_unix/jnl_fsync.c b/sr_unix/jnl_fsync.c
index 8528b8c..69e36bd 100644
--- a/sr_unix/jnl_fsync.c
+++ b/sr_unix/jnl_fsync.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -34,10 +34,10 @@
#include "gtm_c_stack_trace.h"
#include "gtmsecshr.h" /* for continue_proc */
#include "anticipatory_freeze.h"
+#include "wbox_test_init.h"
#ifdef DEBUG
#include "gt_timer.h"
#include "gtm_stdio.h"
-#include "wbox_test_init.h"
#include "is_proc_alive.h"
#endif
@@ -50,8 +50,6 @@ error_def(ERR_JNLFSYNCERR);
error_def(ERR_JNLFSYNCLSTCK);
error_def(ERR_TEXT);
-#define CURRENT_WRITER jb->fsync_in_prog_latch.u.parts.latch_pid
-
void jnl_fsync(gd_region *reg, uint4 fsync_addr)
{
jnl_private_control *jpc;
@@ -66,54 +64,55 @@ void jnl_fsync(gd_region *reg, uint4 fsync_addr)
csa = &FILE_INFO(reg)->s_addrs;
jpc = csa->jnl;
jb = jpc->jnl_buff;
+ assert(process_id != CURRENT_JNL_FSYNC_WRITER(jb));
if ((NOJNL != jpc->channel) && !JNL_FILE_SWITCHED(jpc))
{
csd = csa->hdr;
for (lcnt = 1; fsync_addr > jb->fsync_dskaddr && !JNL_FILE_SWITCHED(jpc); lcnt++)
{
- if (MAX_FSYNC_WAIT_CNT / 2 == lcnt) /* half way into the wait timeout */
+ if (0 == (lcnt % FSYNC_WAIT_HALF_TIME))
{
saved_status = jpc->status;
jpc->status = SS_NORMAL;
- DEBUG_ONLY(
- if (CURRENT_WRITER)
- GET_C_STACK_FROM_SCRIPT("JNLFSYNCSTUCK_HALF_TIME",
- process_id, CURRENT_WRITER, ONCE);
- )
+# ifdef DEBUG
+ if (CURRENT_JNL_FSYNC_WRITER(jb))
+ GET_C_STACK_FROM_SCRIPT("JNLFSYNCSTUCK_HALF_TIME",
+ process_id, CURRENT_JNL_FSYNC_WRITER(jb), lcnt / FSYNC_WAIT_HALF_TIME);
+# endif
jnl_send_oper(jpc, ERR_JNLFSYNCLSTCK);
jpc->status = saved_status;
- } else if (MAX_FSYNC_WAIT_CNT < lcnt) /* timed-out waiting for the fsync lock */
+ }
+ else if (0 == (lcnt % FSYNC_WAIT_TIME))
{
saved_status = jpc->status;
jpc->status = SS_NORMAL;
- if (CURRENT_WRITER)
- GET_C_STACK_FROM_SCRIPT("JNLFSYNCSTUCK", process_id, CURRENT_WRITER, TWICE);
+ if (CURRENT_JNL_FSYNC_WRITER(jb))
+ GET_C_STACK_FROM_SCRIPT("JNLFSYNCSTUCK",
+ process_id, CURRENT_JNL_FSYNC_WRITER(jb), lcnt / FSYNC_WAIT_HALF_TIME);
jnl_send_oper(jpc, ERR_JNLFSYNCLSTCK);
jpc->status = saved_status;
- send_msg(VARLSTCNT(4) ERR_FSYNCTIMOUT, 2, JNL_LEN_STR(csd));
- GTMASSERT;
}
BG_TRACE_PRO_ANY(csa, n_jnl_fsync_tries);
if (GET_SWAPLOCK(&jb->fsync_in_prog_latch))
break;
wcs_sleep(lcnt);
/* trying to wake up the lock holder one iteration before calling c_script */
- if ((MAX_FSYNC_WAIT_CNT / 2 - 1 == lcnt) || (MAX_FSYNC_WAIT_CNT == lcnt))
+ if ((lcnt % FSYNC_WAIT_HALF_TIME) == (FSYNC_WAIT_HALF_TIME - 1))
performCASLatchCheck(&jb->fsync_in_prog_latch, TRUE);
}
- DEBUG_ONLY(
- if (gtm_white_box_test_case_enabled
- && (WBTEST_EXTEND_JNL_FSYNC == gtm_white_box_test_case_number))
- {
- FPRINTF(stderr, "JNL_FSYNC: will sleep for 40 seconds\n", process_id);
- LONG_SLEEP(40);
- FPRINTF(stderr, "JNL_FSYNC: done sleeping\n", process_id);
- gtm_white_box_test_case_enabled = FALSE;
- }
- )
+# ifdef DEBUG
+ if (gtm_white_box_test_case_enabled
+ && (WBTEST_EXTEND_JNL_FSYNC == gtm_white_box_test_case_number))
+ {
+ FPRINTF(stderr, "JNL_FSYNC: will sleep for 40 seconds\n", process_id);
+ LONG_SLEEP(40);
+ FPRINTF(stderr, "JNL_FSYNC: done sleeping\n", process_id);
+ gtm_white_box_test_case_enabled = FALSE;
+ }
+# endif
if (fsync_addr > jb->fsync_dskaddr && !JNL_FILE_SWITCHED(jpc))
{
- assert(process_id == jb->fsync_in_prog_latch.u.parts.latch_pid); /* assert we have the lock */
+ assert(process_id == CURRENT_JNL_FSYNC_WRITER(jb)); /* assert we have the lock */
saved_dsk_addr = jb->dskaddr;
if (jpc->sync_io)
{ /* We need to maintain the fsync control fields irrespective of the type of IO, because we might
@@ -131,13 +130,16 @@ void jnl_fsync(gd_region *reg, uint4 fsync_addr)
assert(jgbl.onlnrlbk || !onln_rlbk_pid || !is_proc_alive(onln_rlbk_pid, 0)
|| (onln_rlbk_pid != csa->nl->in_crit));
GTM_JNL_FSYNC(csa, jpc->channel, fsync_ret);
+ GTM_WHITE_BOX_TEST(WBTEST_FSYNC_SYSCALL_FAIL, fsync_ret, -1);
+ WBTEST_ASSIGN_ONLY(WBTEST_FSYNC_SYSCALL_FAIL, errno, EIO);
if (-1 == fsync_ret)
{
save_errno = errno;
- assert(FALSE);
- send_msg(VARLSTCNT(9) ERR_JNLFSYNCERR, 2, JNL_LEN_STR(csd),
+ assert(WBTEST_ENABLED(WBTEST_FSYNC_SYSCALL_FAIL));
+ RELEASE_SWAPLOCK(&jb->fsync_in_prog_latch);
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_JNLFSYNCERR, 2, JNL_LEN_STR(csd),
ERR_TEXT, 2, RTS_ERROR_TEXT("Error with fsync"), save_errno);
- rts_error(VARLSTCNT(9) ERR_JNLFSYNCERR, 2, JNL_LEN_STR(csd),
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_JNLFSYNCERR, 2, JNL_LEN_STR(csd),
ERR_TEXT, 2, RTS_ERROR_TEXT("Error with fsync"), save_errno);
} else
{
@@ -146,8 +148,9 @@ void jnl_fsync(gd_region *reg, uint4 fsync_addr)
}
}
}
- if (process_id == jb->fsync_in_prog_latch.u.parts.latch_pid)
+ if (process_id == CURRENT_JNL_FSYNC_WRITER(jb))
RELEASE_SWAPLOCK(&jb->fsync_in_prog_latch);
}
+ assert(process_id != CURRENT_JNL_FSYNC_WRITER(jb));
return;
}
diff --git a/sr_unix/jnl_output_sp.c b/sr_unix/jnl_output_sp.c
index 0440593..80cb1f9 100644
--- a/sr_unix/jnl_output_sp.c
+++ b/sr_unix/jnl_output_sp.c
@@ -1,6 +1,6 @@
/***************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -92,7 +92,13 @@ uint4 jnl_sub_qio_start(jnl_private_control *jpc, boolean_t aligned_write)
return ERR_JNLWRTDEFER;
}
# ifdef DEBUG
- if (gtm_white_box_test_case_enabled && (WBTEST_SIGTSTP_IN_JNL_OUTPUT_SP == gtm_white_box_test_case_number))
+ /* When jnl_sub_qio_start() is called as part of WBTEST_SIGTSTP_IN_JNL_OUTPUT_SP white-box test case,
+ * aligned_write should always be FALSE. But depending upon the filesystem block size, it is possible that
+ * the function could also be called with aligned_write being TRUE. This could lead to sending SIGTSTP
+ * twice. Hence ensure that SIGTSTP is sent only for the unaligned write.
+ */
+ if (gtm_white_box_test_case_enabled && (WBTEST_SIGTSTP_IN_JNL_OUTPUT_SP == gtm_white_box_test_case_number)
+ && !aligned_write)
kill(process_id, SIGTSTP);
# endif
if (jb->dsk != (jb->dskaddr % jb->size))
@@ -128,8 +134,8 @@ uint4 jnl_sub_qio_start(jnl_private_control *jpc, boolean_t aligned_write)
jnl_qio_in_prog--;
assert(0 <= jnl_qio_in_prog);
/* DBFSYNCERR can potentially cause syslog flooding. Remove the following line if we it becomes an issue. */
- send_msg(VARLSTCNT(5) ERR_DBFSYNCERR, 2, DB_LEN_STR(reg), save_errno);
- rts_error(VARLSTCNT(5) ERR_DBFSYNCERR, 2, DB_LEN_STR(reg), save_errno);
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_DBFSYNCERR, 2, DB_LEN_STR(reg), save_errno);
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_DBFSYNCERR, 2, DB_LEN_STR(reg), save_errno);
assert(FALSE); /* should not come here as the rts_error above should not return */
return ERR_DBFSYNCERR; /* ensure we do not fall through to the code below as we no longer have the lock */
}
diff --git a/sr_unix/jnlpool_init.c b/sr_unix/jnlpool_init.c
index a43456b..5437293 100644
--- a/sr_unix/jnlpool_init.c
+++ b/sr_unix/jnlpool_init.c
@@ -79,7 +79,6 @@ GBLREF err_ctl merrors_ctl;
GBLREF jnl_gbls_t jgbl;
#ifdef DEBUG
-GBLREF boolean_t is_jnlpool_creator;
GBLREF boolean_t is_updhelper;
#endif
@@ -104,7 +103,7 @@ error_def(ERR_SRCSRVNOTEXIST);
error_def(ERR_SRCSRVTOOMANY);
error_def(ERR_TEXT);
-#define REMOVE_OR_RELEASE_SEM(NEW_IPC, UDI) \
+#define REMOVE_OR_RELEASE_SEM(NEW_IPC) \
{ \
if (NEW_IPC) \
remove_sem_set(SOURCE); \
@@ -120,7 +119,7 @@ error_def(ERR_TEXT);
if (NULL != jnlpool.jnlpool_ctl) \
{ \
if (-1 == shmdt((caddr_t)jnlpool.jnlpool_ctl)) \
- gtm_putmsg(VARLSTCNT(5) ERR_REPLWARN, 2, \
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_REPLWARN, 2, \
RTS_ERROR_LITERAL("Could not detach from journal pool"), errno); \
jnlpool_ctl = NULL; \
jnlpool.jnlpool_ctl = NULL; \
@@ -132,7 +131,7 @@ error_def(ERR_TEXT);
} \
assert(INVALID_SHMID != udi->shmid); \
if (0 != shm_rmid(udi->shmid)) \
- gtm_putmsg(VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2, \
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2, \
RTS_ERROR_LITERAL("Error removing jnlpool "), errno); \
remove_sem_set(SOURCE); \
} \
@@ -142,7 +141,8 @@ error_def(ERR_TEXT);
{ \
if ((GTMSOURCE_DUMMY_STATE != gtmsourcelocal_ptr->gtmsource_state) || (0 != gtmsourcelocal_ptr->gtmsource_pid)) \
{ /* Slot is in an out-of-design situation. Send an operator log message with enough debugging detail */ \
- send_msg(VARLSTCNT(7) ERR_JNLPOOLBADSLOT, 5, LEN_AND_STR((char *)gtmsourcelocal_ptr->secondary_instname), \
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLBADSLOT, 5, \
+ LEN_AND_STR((char *)gtmsourcelocal_ptr->secondary_instname), \
gtmsourcelocal_ptr->gtmsource_pid, gtmsourcelocal_ptr->gtmsource_state, \
gtmsourcelocal_ptr->gtmsrc_lcl_array_index); \
} \
@@ -183,7 +183,7 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t
gtmsource_options.showfreeze;
memset(machine_name, 0, SIZEOF(machine_name));
if (GETHOSTNAME(machine_name, MAX_MCNAMELEN, status))
- rts_error(VARLSTCNT(5) ERR_TEXT, 2, RTS_ERROR_TEXT("Unable to get the hostname"), errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_TEXT, 2, RTS_ERROR_TEXT("Unable to get the hostname"), errno);
if (NULL == recvpool.recvpool_dummy_reg)
{
r_save = gv_cur_region;
@@ -222,7 +222,7 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t
* or shut down replication for this instance. We will release ftok semaphore when initialization is done.
*/
if (!ftok_sem_get(jnlpool.jnlpool_dummy_reg, TRUE, REPLPOOL_ID, FALSE))
- rts_error(VARLSTCNT(1) ERR_JNLPOOLSETUP);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JNLPOOLSETUP);
repl_inst_read(udi->fn, (off_t)0, (sm_uc_ptr_t)&repl_instance, SIZEOF(repl_inst_hdr));
is_src_srvr = (GTMSOURCE == pool_user);
/* If caller is source server and secondary instance name has been specified check if it is different from THIS instance */
@@ -231,7 +231,8 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t
if (0 == STRCMP(repl_instance.inst_info.this_instname, gtmsource_options.secondary_instname))
{
ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE);
- rts_error(VARLSTCNT(4) ERR_REPLINSTNMSAME, 2, LEN_AND_STR((char *)repl_instance.inst_info.this_instname));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_REPLINSTNMSAME, 2,
+ LEN_AND_STR((char *)repl_instance.inst_info.this_instname));
}
}
new_ipc = FALSE;
@@ -244,13 +245,14 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t
ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE);
if (GTMRELAXED == pool_user)
return;
- rts_error(VARLSTCNT(4) ERR_NOJNLPOOL, 2, full_len, udi->fn);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_NOJNLPOOL, 2, full_len, udi->fn);
}
if (repl_instance.crash)
{
ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE);
SNPRINTF(scndry_msg, OUT_BUFF_SIZE, "Instance file header has crash field set to TRUE");
- rts_error(VARLSTCNT(8) ERR_REPLREQROLLBACK, 2, full_len, udi->fn, ERR_TEXT, 2, LEN_AND_STR(scndry_msg));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_REPLREQROLLBACK, 2, full_len, udi->fn, ERR_TEXT, 2,
+ LEN_AND_STR(scndry_msg));
}
DEBUG_ONLY(sem_created = TRUE);
new_ipc = TRUE;
@@ -258,7 +260,7 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t
if (INVALID_SEMID == (udi->semid = init_sem_set_source(IPC_PRIVATE, NUM_SRC_SEMS, RWDALL | IPC_CREAT)))
{
ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE);
- rts_error(VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Error creating journal pool semaphore"), errno);
}
/* Following will set semaphore SOURCE_ID_SEM value as GTM_ID. In case we have orphaned semaphore
@@ -270,7 +272,7 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t
save_errno = errno;
remove_sem_set(SOURCE); /* Remove what we created */
ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE);
- rts_error(VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Error with jnlpool semctl SETVAL"), save_errno);
}
/* Warning: We must read the sem_ctime using IPC_STAT after SETVAL, which changes it. We must NOT do any
@@ -282,7 +284,7 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t
save_errno = errno;
remove_sem_set(SOURCE); /* Remove what we created */
ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE);
- rts_error(VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Error with jnlpool semctl IPC_STAT"), save_errno);
}
udi->gt_sem_ctime = semarg.buf->sem_ctime;
@@ -290,20 +292,21 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t
{ /* find create time of semaphore from the file header and check if the id is reused by others */
assert(repl_instance.crash || jgbl.mur_rollback);
semarg.buf = &semstat;
- if (-1 == semctl(repl_instance.jnlpool_semid, 0, IPC_STAT, semarg))
+ if (-1 == semctl(repl_instance.jnlpool_semid, DB_CONTROL_SEM, IPC_STAT, semarg))
{
save_errno = errno;
ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE);
SNPRINTF(scndry_msg, OUT_BUFF_SIZE, "Error with semctl on Journal Pool SEMID (%d)",
repl_instance.jnlpool_semid);
- rts_error(VARLSTCNT(9) ERR_REPLREQROLLBACK, 2, full_len, udi->fn,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_REPLREQROLLBACK, 2, full_len, udi->fn,
ERR_TEXT, 2, LEN_AND_STR(scndry_msg), save_errno);
} else if (semarg.buf->sem_ctime != repl_instance.jnlpool_semid_ctime)
{
ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE);
SNPRINTF(scndry_msg, OUT_BUFF_SIZE, "Creation time for Journal Pool SEMID (%d) is %d; Expected %d",
repl_instance.jnlpool_semid, semarg.buf->sem_ctime, repl_instance.jnlpool_semid_ctime);
- rts_error(VARLSTCNT(8) ERR_REPLREQROLLBACK, 2, full_len, udi->fn, ERR_TEXT, 2, LEN_AND_STR(scndry_msg));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_REPLREQROLLBACK, 2, full_len, udi->fn, ERR_TEXT, 2,
+ LEN_AND_STR(scndry_msg));
}
udi->semid = repl_instance.jnlpool_semid;
udi->gt_sem_ctime = repl_instance.jnlpool_semid_ctime;
@@ -317,10 +320,11 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t
if (SS_NORMAL != status)
{
ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE);
- rts_error(VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Error with journal pool access semaphore"), errno);
}
udi->grabbed_access_sem = TRUE;
+ udi->counter_acc_incremented = TRUE;
}
if (INVALID_SHMID == repl_instance.jnlpool_shmid)
{ /* We have an INVALID shmid in the file header. There are three ways this can happen
@@ -345,10 +349,11 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t
} else if (-1 == shmctl(repl_instance.jnlpool_shmid, IPC_STAT, &shmstat))
{ /* shared memory ID was removed form the system by an IPCRM command or we have a permission issue (or such) */
save_errno = errno;
- REMOVE_OR_RELEASE_SEM(new_ipc, udi);
+ REMOVE_OR_RELEASE_SEM(new_ipc);
ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE);
SNPRINTF(scndry_msg, OUT_BUFF_SIZE, "Error with semctl on Journal Pool SHMID (%d)", repl_instance.jnlpool_shmid);
- rts_error(VARLSTCNT(9) ERR_REPLREQROLLBACK, 2, full_len, udi->fn, ERR_TEXT, 2, LEN_AND_STR(scndry_msg), save_errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_REPLREQROLLBACK, 2, full_len, udi->fn, ERR_TEXT, 2,
+ LEN_AND_STR(scndry_msg), save_errno);
} else if (shmstat.shm_ctime != repl_instance.jnlpool_shmid_ctime)
{ /* shared memory was possibly reused (causing shm_ctime and jnlpool_shmid_ctime to be different. We can't rely
* on the shmid as it could be connected to a valid instance file in a different environment. Create new IPCs
@@ -362,11 +367,11 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t
/* Source server startup is the only command that can create the journal pool. Check that. */
if (new_ipc && (!is_src_srvr || !gtmsource_options.start))
{
- REMOVE_OR_RELEASE_SEM(new_ipc, udi);
+ REMOVE_OR_RELEASE_SEM(new_ipc);
ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE);
if (GTMRELAXED == pool_user)
return;
- rts_error(VARLSTCNT(4) ERR_NOJNLPOOL, 2, full_len, udi->fn);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_NOJNLPOOL, 2, full_len, udi->fn);
}
if (repl_instance.file_corrupt)
{ /* Indicates that a prior rollback was killed and so requires a re-run. It is also possible this process started
@@ -379,10 +384,11 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t
repl_instance.jnlpool_semid_ctime)));
if (repl_instance.file_corrupt)
{
- REMOVE_OR_RELEASE_SEM(new_ipc, udi);
+ REMOVE_OR_RELEASE_SEM(new_ipc);
ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE);
SNPRINTF(scndry_msg, OUT_BUFF_SIZE, "Instance file header has file_corrupt field set to TRUE");
- rts_error(VARLSTCNT(8) ERR_REPLREQROLLBACK, 2, full_len, udi->fn, ERR_TEXT, 2, LEN_AND_STR(scndry_msg));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_REPLREQROLLBACK, 2, full_len, udi->fn, ERR_TEXT, 2,
+ LEN_AND_STR(scndry_msg));
}
}
if (new_ipc)
@@ -393,7 +399,7 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t
save_errno = errno;
remove_sem_set(SOURCE);
ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE);
- rts_error(VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Error with journal pool creation"), save_errno);
}
if (-1 == shmctl(udi->shmid, IPC_STAT, &shmstat))
@@ -401,7 +407,7 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t
save_errno = errno;
DETACH_AND_REMOVE_SHM_AND_SEM; /* remove any sem/shm we had created */
ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE);
- rts_error(VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Error with jnlpool shmctl IPC_STAT"), save_errno);
}
udi->gt_shm_ctime = shmstat.shm_ctime;
@@ -415,7 +421,7 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t
ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE);
/* Assert below ensures we dont try to clean up the journal pool even though we errored out while attaching to it */
assert(NULL == jnlpool.jnlpool_ctl);
- rts_error(VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Error with journal pool shmat"), save_errno);
}
jnlpool.jnlpool_ctl = tmp_jnlpool_ctl;
@@ -453,7 +459,7 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t
assert(MERRORS_ARRAY_SZ > merrors_ctl.msg_cnt);
csa->critical = (mutex_struct_ptr_t)((sm_uc_ptr_t)jnlpool.jnlpool_ctl + JNLPOOL_CTL_SIZE); /* secshr_db_clnup uses this
* relationship */
- jnlpool_mutex_spin_parms = (mutex_spin_parms_ptr_t)((sm_uc_ptr_t)csa->critical + CRIT_SPACE);
+ jnlpool_mutex_spin_parms = (mutex_spin_parms_ptr_t)((sm_uc_ptr_t)csa->critical + JNLPOOL_CRIT_SPACE);
csa->nl = (node_local_ptr_t)((sm_uc_ptr_t)jnlpool_mutex_spin_parms + SIZEOF(mutex_spin_parms_struct));
if (new_ipc)
memset(csa->nl, 0, SIZEOF(node_local)); /* Make csa->nl->glob_sec_init FALSE */
@@ -475,8 +481,10 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t
{
DETACH_AND_REMOVE_SHM_AND_SEM; /* remove any sem/shm we had created */
udi->grabbed_access_sem = FALSE;
+ udi->counter_acc_incremented = FALSE;
ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE);
- rts_error(VARLSTCNT(6) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2, LEN_AND_LIT("Error initializing custom errors"));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ LEN_AND_LIT("Error initializing custom errors"));
}
jnlpool_ctl->critical_off = (sm_uc_ptr_t)csa->critical - (sm_uc_ptr_t)jnlpool_ctl;
jnlpool_ctl->filehdr_off = (sm_uc_ptr_t)jnlpool.repl_inst_filehdr - (sm_uc_ptr_t)jnlpool_ctl;
@@ -493,13 +501,14 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t
* grab_locks to work correctly
*/
DEBUG_ONLY(locknl = csa->nl;) /* for DEBUG_ONLY LOCK_HIST macro */
- gtm_mutex_init(reg, NUM_CRIT_ENTRY, FALSE);
+ gtm_mutex_init(reg, DEFAULT_NUM_CRIT_ENTRY, FALSE);
DEBUG_ONLY(locknl = NULL;) /* restore "locknl" to default value */
jnlpool_mutex_spin_parms->mutex_hard_spin_count = MUTEX_HARD_SPIN_COUNT;
jnlpool_mutex_spin_parms->mutex_sleep_spin_count = MUTEX_SLEEP_SPIN_COUNT;
jnlpool_mutex_spin_parms->mutex_spin_sleep_mask = MUTEX_SPIN_SLEEP_MASK;
+ jnlpool_mutex_spin_parms->mutex_que_entry_space_size = DEFAULT_NUM_CRIT_ENTRY;
assert(!skip_locks);
- grab_lock(jnlpool.jnlpool_dummy_reg, ASSERT_NO_ONLINE_ROLLBACK);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK);
/* Flush the file header to disk so future callers of "jnlpool_init" see the jnlpool_semid and jnlpool_shmid */
repl_inst_flush_filehdr();
/* Initialize GTMSRC_LCL section in journal pool */
@@ -524,8 +533,9 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t
if (udi->grabbed_access_sem)
rel_sem_immediate(SOURCE, JNL_POOL_ACCESS_SEM);
udi->grabbed_access_sem = FALSE;
+ udi->counter_acc_incremented = FALSE;
ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE);
- rts_error(VARLSTCNT(10) ERR_REPLREQRUNDOWN, 4, DB_LEN_STR(reg), LEN_AND_STR(machine_name),
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_REPLREQRUNDOWN, 4, DB_LEN_STR(reg), LEN_AND_STR(machine_name),
ERR_TEXT, 2, RTS_ERROR_TEXT("Journal pool is incompletely initialized. Run MUPIP RUNDOWN first."));
}
slot_needs_init = FALSE;
@@ -597,10 +607,11 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t
assert(!skip_locks);
rel_sem_immediate(SOURCE, JNL_POOL_ACCESS_SEM);
udi->grabbed_access_sem = FALSE;
+ udi->counter_acc_incremented = FALSE;
ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE);
/* Assert we did not create shm or sem so no need to remove any */
assert(!new_ipc);
- rts_error(VARLSTCNT(5) ERR_SRCSRVEXISTS, 3,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SRCSRVEXISTS, 3,
LEN_AND_STR(gtmsource_options.secondary_instname), gtmsource_pid);
}
} else
@@ -624,10 +635,11 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t
if (udi->grabbed_access_sem)
rel_sem_immediate(SOURCE, JNL_POOL_ACCESS_SEM);
udi->grabbed_access_sem = FALSE;
+ udi->counter_acc_incremented = FALSE;
ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE);
/* Assert we did not create shm or sem so no need to remove any */
assert(!new_ipc);
- rts_error(VARLSTCNT(4) ERR_SRCSRVNOTEXIST, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_SRCSRVNOTEXIST, 2,
LEN_AND_STR(gtmsource_options.secondary_instname));
}
}
@@ -648,10 +660,11 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t
if (udi->grabbed_access_sem)
rel_sem_immediate(SOURCE, JNL_POOL_ACCESS_SEM);
udi->grabbed_access_sem = FALSE;
+ udi->counter_acc_incremented = FALSE;
ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE);
/* Assert we did not create shm or sem so no need to remove any */
assert(!new_ipc);
- rts_error(VARLSTCNT(6) ERR_REPLINSTSECNONE, 4,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLINSTSECNONE, 4,
LEN_AND_STR(gtmsource_options.secondary_instname), full_len, udi->fn);
} else
{ /* Find a used slot that can be reused. Find one with least value of "connect_jnl_seqno". */
@@ -675,10 +688,12 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t
if (udi->grabbed_access_sem)
rel_sem_immediate(SOURCE, JNL_POOL_ACCESS_SEM);
udi->grabbed_access_sem = FALSE;
+ udi->counter_acc_incremented = FALSE;
ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE);
/* Assert we did not create shm or sem so no need to remove any */
assert(!new_ipc);
- rts_error(VARLSTCNT(5) ERR_SRCSRVTOOMANY, 3, NUM_GTMSRC_LCL, full_len, udi->fn);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SRCSRVTOOMANY, 3, NUM_GTMSRC_LCL,
+ full_len, udi->fn);
} else
{ /* We want to reinitialize the source server related fields in "gtmsource_local"
* as well as reinitialize any fields that intersect with "gtmsrc_lcl" as this
@@ -709,10 +724,11 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t
if (udi->grabbed_access_sem)
rel_sem_immediate(SOURCE, JNL_POOL_ACCESS_SEM);
udi->grabbed_access_sem = FALSE;
+ udi->counter_acc_incremented = FALSE;
ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE);
/* Assert we did not create shm or sem so no need to remove any */
assert(!new_ipc);
- rts_error(VARLSTCNT(6) ERR_REPLINSTSECNONE, 4,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLINSTSECNONE, 4,
LEN_AND_STR(gtmsource_options.secondary_instname), full_len, udi->fn);
}
}
@@ -736,23 +752,25 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t
if (udi->grabbed_access_sem)
rel_sem_immediate(SOURCE, JNL_POOL_ACCESS_SEM);
udi->grabbed_access_sem = FALSE;
+ udi->counter_acc_incremented = FALSE;
ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE);
- rts_error(VARLSTCNT(4) ERR_PRIMARYISROOT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_PRIMARYISROOT, 2,
LEN_AND_STR((char *)repl_instance.inst_info.this_instname));
}
} else if (is_src_srvr)
{ /* Source server command issued on a propagating primary */
- assert(!skip_locks);
if (ROOTPRIMARY_SPECIFIED == gtmsource_options.rootprimary)
{ /* Journal pool was created with a -PROPAGATEPRIMARY command and current source server command
* has specified -ROOTPRIMARY (or -UPDOK).
*/
+ assert(!skip_locks);
if (!gtmsource_options.activate)
{ /* START or DEACTIVATE was specified. Issue incompatibility error right away */
rel_sem_immediate(SOURCE, JNL_POOL_ACCESS_SEM);
udi->grabbed_access_sem = FALSE;
+ udi->counter_acc_incremented = FALSE;
ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE);
- rts_error(VARLSTCNT(4) ERR_PRIMARYNOTROOT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_PRIMARYNOTROOT, 2,
LEN_AND_STR((char *)repl_instance.inst_info.this_instname));
} else
{ /* ACTIVATE was specified. Check if there is only one process attached to the journal
@@ -767,8 +785,9 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t
{
rel_sem_immediate(SOURCE, JNL_POOL_ACCESS_SEM);
udi->grabbed_access_sem = FALSE;
+ udi->counter_acc_incremented = FALSE;
ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE);
- rts_error(VARLSTCNT(4) ERR_ACTIVATEFAIL, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ACTIVATEFAIL, 2,
LEN_AND_STR(gtmsource_options.secondary_instname));
} else
hold_onto_ftok_sem = TRUE;
@@ -788,8 +807,9 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t
if (udi->grabbed_access_sem)
rel_sem_immediate(SOURCE, JNL_POOL_ACCESS_SEM);
udi->grabbed_access_sem = FALSE;
+ udi->counter_acc_incremented = FALSE;
ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE);
- rts_error(VARLSTCNT(6) ERR_JNLPOOLSETUP, 0,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JNLPOOLSETUP, 0,
ERR_TEXT, 2, RTS_ERROR_LITERAL("Journal pool has not been initialized"));
}
/* Initialize the shared memory fields. */
@@ -806,20 +826,21 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t
QWASSIGNDW(jnlpool_ctl->write_addr, 0);
if (0 < jnlpool.repl_inst_filehdr->num_histinfo)
{
- grab_lock(jnlpool.jnlpool_dummy_reg, ASSERT_NO_ONLINE_ROLLBACK);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK);
status = repl_inst_histinfo_get(jnlpool.repl_inst_filehdr->num_histinfo - 1, &last_histinfo);
rel_lock(jnlpool.jnlpool_dummy_reg);
assert(0 == status);
if (0 != status)
{
assert(ERR_REPLINSTNOHIST == status); /* the only error returned by repl_inst_histinfo_get() */
- grab_lock(jnlpool.jnlpool_dummy_reg, ASSERT_NO_ONLINE_ROLLBACK);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK);
repl_inst_flush_jnlpool(TRUE, TRUE); /* to reset "crash" field in instance file header to FALSE */
rel_lock(jnlpool.jnlpool_dummy_reg);
DETACH_AND_REMOVE_SHM_AND_SEM; /* remove any sem/shm we had created */
udi->grabbed_access_sem = FALSE;
+ udi->counter_acc_incremented = FALSE;
ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE);
- rts_error(VARLSTCNT(6) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
LEN_AND_LIT("Error reading last history record in replication instance file"));
}
instfilehdr_seqno = jnlpool.repl_inst_filehdr->jnl_seqno;
@@ -827,13 +848,14 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t
assert(instfilehdr_seqno);
if (instfilehdr_seqno < last_histinfo.start_seqno)
{ /* The jnl seqno in the instance file header is not greater than the last histinfo's start seqno */
- grab_lock(jnlpool.jnlpool_dummy_reg, ASSERT_NO_ONLINE_ROLLBACK);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK);
repl_inst_flush_jnlpool(TRUE, TRUE); /* to reset "crash" field in instance file header to FALSE */
rel_lock(jnlpool.jnlpool_dummy_reg);
DETACH_AND_REMOVE_SHM_AND_SEM; /* remove any sem/shm we had created */
udi->grabbed_access_sem = FALSE;
+ udi->counter_acc_incremented = FALSE;
ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE);
- rts_error(VARLSTCNT(8) ERR_REPLINSTSEQORD, 6, LEN_AND_LIT("Instance file header"),
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_REPLINSTSEQORD, 6, LEN_AND_LIT("Instance file header"),
&instfilehdr_seqno, &last_histinfo.start_seqno, LEN_AND_STR(udi->fn));
}
jnlpool_ctl->last_histinfo_seqno = last_histinfo.start_seqno;
@@ -852,18 +874,9 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t
assert(0 == offsetof(jnlpool_ctl_struct, jnlpool_id));
/* ensure that the pool identifier is at the top of the pool */
jnlpool_ctl->jnlpool_id.pool_type = JNLPOOL_SEGMENT;
- DEBUG_ONLY(locknl = csa->nl;) /* for DEBUG_ONLY LOCK_HIST macro */
- gtm_mutex_init(reg, NUM_CRIT_ENTRY, FALSE);
- DEBUG_ONLY(locknl = NULL;) /* restore "locknl" to default value */
- jnlpool_mutex_spin_parms->mutex_hard_spin_count = MUTEX_HARD_SPIN_COUNT;
- jnlpool_mutex_spin_parms->mutex_sleep_spin_count = MUTEX_SLEEP_SPIN_COUNT;
- jnlpool_mutex_spin_parms->mutex_spin_sleep_mask = MUTEX_SPIN_SLEEP_MASK;
csa->nl->glob_sec_init = TRUE;
assert(NULL != jnlpool_creator);
*jnlpool_creator = TRUE;
-# ifdef DEBUG
- is_jnlpool_creator = TRUE;
-# endif
} else if (NULL != jnlpool_creator)
*jnlpool_creator = FALSE;
/* If this is a supplementary instance, initialize strm_index to a non-default value.
@@ -880,6 +893,8 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t
}
assert(!(is_src_srvr && gtmsource_options.start) || slot_needs_init);
jnlpool.gtmsource_local = gtmsourcelocal_ptr;
+ assert((NULL == gtmsourcelocal_ptr)
+ || (gtmsourcelocal_ptr->gtmsrc_lcl_array_index == (gtmsourcelocal_ptr - jnlpool.gtmsource_local_array)));
reg->open = TRUE; /* this is used by t_commit_cleanup/tp_restart/mutex_deadlock_check */
reg->read_only = FALSE; /* maintain csa->read_write simultaneously */
csa->read_write = TRUE; /* maintain reg->read_only simultaneously */
@@ -899,11 +914,9 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t
gtmsourcelocal_ptr->read = 0;
gtmsourcelocal_ptr->read_state = READ_POOL;
gtmsourcelocal_ptr->mode = gtmsource_options.mode;
- assert(gtmsourcelocal_ptr->gtmsrc_lcl_array_index == (gtmsourcelocal_ptr - jnlpool.gtmsource_local_array));
gtmsourcelocal_ptr->statslog = FALSE;
gtmsourcelocal_ptr->shutdown = NO_SHUTDOWN;
gtmsourcelocal_ptr->shutdown_time = -1;
- gtmsourcelocal_ptr->secondary_inet_addr = gtmsource_options.sec_inet_addr;
gtmsourcelocal_ptr->secondary_port = gtmsource_options.secondary_port;
STRCPY(gtmsourcelocal_ptr->secondary_host, gtmsource_options.secondary_host);
STRCPY(gtmsourcelocal_ptr->filter_cmd, gtmsource_options.filter_cmd);
@@ -943,7 +956,7 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t
/* Now make the corresponding changes from gtmsource_local to the gtmsrc_lcl structure and flush to disk.
* This assumes "jnlpool.gtmsource_local" is set appropriately.
*/
- grab_lock(jnlpool.jnlpool_dummy_reg, ASSERT_NO_ONLINE_ROLLBACK);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK);
repl_inst_flush_gtmsrc_lcl();
rel_lock(jnlpool.jnlpool_dummy_reg);
}
@@ -969,10 +982,11 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t
ftok_sem_release(jnlpool.jnlpool_dummy_reg, TRUE, TRUE);
/* Assert we did not create shm or sem so no need to remove any */
assert(!new_ipc);
- rts_error(VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Error in rel_sem"), save_errno);
}
udi->grabbed_access_sem = FALSE;
+ udi->counter_acc_incremented = FALSE;
}
} else
{
@@ -981,7 +995,7 @@ void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t
* later when source server connects to receiver */
}
if (!hold_onto_ftok_sem && !ftok_sem_release(jnlpool.jnlpool_dummy_reg, FALSE, FALSE))
- rts_error(VARLSTCNT(1) ERR_JNLPOOLSETUP);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JNLPOOLSETUP);
pool_init = TRUE;
ENABLE_FREEZE_ON_ERROR;
return;
@@ -999,8 +1013,8 @@ void jnlpool_detach(void)
rel_gtmsource_srv_latch(&jnlpool.gtmsource_local->gtmsource_srv_latch);
JNLPOOL_SHMDT(status, save_errno);
if (0 > status)
- rts_error(VARLSTCNT(5) ERR_REPLWARN, 2, RTS_ERROR_LITERAL("Could not detach from journal pool"),
- save_errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_REPLWARN, 2,
+ RTS_ERROR_LITERAL("Could not detach from journal pool"), save_errno);
jnlpool.repl_inst_filehdr = NULL;
jnlpool.gtmsrc_lcl_array = NULL;
jnlpool.gtmsource_local_array = NULL;
diff --git a/sr_unix/jobchild_init.c b/sr_unix/jobchild_init.c
index c35e5e0..d3df53e 100644
--- a/sr_unix/jobchild_init.c
+++ b/sr_unix/jobchild_init.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -35,6 +35,7 @@
#include "invocation_mode.h"
#include "gtmci.h"
#include "send_msg.h"
+#include "have_crit.h"
#define FILE_NAME_SIZE 255
@@ -47,6 +48,7 @@ GBLREF uint4 process_id;
error_def(ERR_RUNPARAMERR);
error_def(ERR_TEXT);
error_def(ERR_SYSCALL);
+error_def(ERR_JOBLABOFF);
CONDITION_HANDLER(job_init_ch)
{
@@ -68,6 +70,7 @@ void jobchild_init(void)
mval job_args[MAX_ACTUALS];
mstr routine, label;
int offset;
+ int rc;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
@@ -82,24 +85,26 @@ void jobchild_init(void)
if (PUTENV(CLEAR_CHILD_FLAG_ENV))
{
util_out_print("Unable to clear gtmj0 process !UL exiting.", TRUE, process_id);
- rts_error(VARLSTCNT(1) errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) errno);
}
/* read parameters into parameter structure */
ojchildparms(&jparms, &job_arglist, job_args);
/* Execute the command to be run before executing the actual M routine */
- if (jparms.startup.len && (0 != SYSTEM(jparms.startup.addr)))
- rts_error(VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_LIT("STARTUP command failed"));
- /* Set up job's input, output and error files. Redirect them, if necessary.
- * It is needed since the middle process would not have always done this(under jobpid == TRUE cases)
- */
- if (!(status = ojchildioset(&jparms)))
- rts_error(VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_LIT("Failed to set STDIN/OUT/ERR for the job"));
- job_addr(&jparms.routine, &jparms.label, jparms.offset, (char **)&base_addr, (char **)&transfer_addr);
+ if (jparms.startup.len)
+ {
+ rc = SYSTEM(jparms.startup.addr);
+ if ((0 != rc))
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_TEXT, 2,
+ LEN_AND_LIT("STARTUP command failed"));
+ }
+ if(!job_addr(&jparms.routine, &jparms.label, jparms.offset,
+ (char **)&base_addr, (char **)&transfer_addr))
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBLABOFF);
/* Set process priority */
if (jparms.baspri)
{ /* send message to system log if nice fails */
if (-1 == nice((int)jparms.baspri))
- send_msg(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("nice"), CALLFROM, errno);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("nice"), CALLFROM, errno);
}
/* Set up $ZMODE to "OTHER" */
(TREF(dollar_zmode)).mvtype = MV_STR;
@@ -130,9 +135,10 @@ void jobchild_init(void)
{
arg_len = FILE_NAME_SIZE;
if (!cli_get_str("INFILE", run_file_name, &arg_len))
- rts_error(VARLSTCNT(1) ERR_RUNPARAMERR);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_RUNPARAMERR);
lref_parse((uchar_ptr_t)run_file_name, &routine, &label, &offset);
- job_addr(&routine, &label, offset, (char **)&base_addr, (char **)&transfer_addr);
+ if(!job_addr(&routine, &label, offset, (char **)&base_addr, (char **)&transfer_addr))
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBLABOFF);
} else if (MUMPS_CALLIN & invocation_mode) /* call-in mode */
{
base_addr = make_cimode();
diff --git a/sr_unix/joberr.h b/sr_unix/joberr.h
index 1b3f962..b0839cb 100644
--- a/sr_unix/joberr.h
+++ b/sr_unix/joberr.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -14,16 +14,31 @@ char *msg;
int len;
}joberr_msg;
+/*
+ * The follwoing array is index by values from the enum joberr_t from jobsp.h.
+ */
LITDEF joberr_msg joberrs[] = {
"", 0,
- "Job error in child process", SIZEOF("Job error in child process")-1,
- "Job error in I/O specification", SIZEOF("Job error in I/O specification")-1,
- "Job error in directory specification", SIZEOF("Job error in directory specification")-1,
- "Job error in routine specification", SIZEOF("Job error in routine specification")-1,
- "Job error in fork", SIZEOF("Job error in fork")-1,
- "Job error in syscall", SIZEOF("Job error in syscall")-1,
- "Job child was stopped by signal", SIZEOF("Job child was stopped by signal")-1,
- "Job child terminated due to signal", SIZEOF("Job child terminated due to signal")-1,
- "", SIZEOF("")-1 /* this is used internally to determine try-again situations */
+ LIT_AND_LEN("Job error in child process"),
+ LIT_AND_LEN("Job error in opening STDIN"),
+ LIT_AND_LEN("Job error in directing input to STDIN"),
+ LIT_AND_LEN("Job error in creating STDOUT"),
+ LIT_AND_LEN("Job error in opening STDOUT"),
+ LIT_AND_LEN("Job error in directing output to STDOUT"),
+ LIT_AND_LEN("Job error in creating STDERR"),
+ LIT_AND_LEN("Job error in opening STDERR"),
+ LIT_AND_LEN("Job error in directing output to STDERR"),
+ LIT_AND_LEN("Job error in directory specification"),
+ LIT_AND_LEN("Job error - CHDIR error"),
+ LIT_AND_LEN("Job error in routine specification. Label and offset not found in created process"),
+ LIT_AND_LEN("Job error in setting independent session"),
+ LIT_AND_LEN("Job error in fork"),
+ LIT_AND_LEN("Job error in renaming standard output file"),
+ LIT_AND_LEN("Job error in renaming standard error file"),
+ LIT_AND_LEN("Job error in middle process to parent process pipe communication"),
+ LIT_AND_LEN("Job error in middle process to grandchild process pipe communication"),
+ LIT_AND_LEN("Job child was stopped by signal"),
+ LIT_AND_LEN("Job child terminated due to signal"),
+ LIT_AND_LEN("") /* this is used internally to determine try-again situations */
};
diff --git a/sr_unix/jobsp.h b/sr_unix/jobsp.h
index baf54b7..4851ebc 100644
--- a/sr_unix/jobsp.h
+++ b/sr_unix/jobsp.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -17,24 +17,25 @@
#define MAX_PIDSTR_LEN 10
#define MAX_MBXNAM_LEN 16
#define MAX_PRCNAM_LEN 15
+#define MAX_STDIOE_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"
+#define CLEAR_CHILD_FLAG_ENV "gtmj0="""
+#define GBLDIR_ENV "gtmgbldir"
+#define CWD_ENV "gtmj2"
+#define IN_FILE_ENV "gtmj3"
+#define OUT_FILE_ENV "gtmj4"
+#define ERR_FILE_ENV "gtmj5"
+#define LOG_FILE_ENV "gtmj6"
+#define ROUTINE_ENV "gtmj7"
+#define LABEL_ENV "gtmj8"
+#define OFFSET_ENV "gtmj9"
+#define PRIORITY_ENV "gtmja"
+#define STARTUP_ENV "gtmjb"
+#define GTMJCNT_ENV "gtmjcnt"
-#define CHILD_FLAG_ENV "gtmj0"
-#define CLEAR_CHILD_FLAG_ENV "gtmj0="""
-#define GBLDIR_ENV "gtmgbldir"
-#define CWD_ENV "gtmj2"
-#define IN_FILE_ENV "gtmj3"
-#define OUT_FILE_ENV "gtmj4"
-#define ERR_FILE_ENV "gtmj5"
-#define LOG_FILE_ENV "gtmj6"
-#define ROUTINE_ENV "gtmj7"
-#define LABEL_ENV "gtmj8"
-#define OFFSET_ENV "gtmj9"
-#define PRIORITY_ENV "gtmja"
-#define STARTUP_ENV "gtmjb"
-#define GTMJCNT_ENV "gtmjcnt"
-
-#define TIMEOUT_ERROR (MAX_SYSERR + 1) /* a special value to differentiate it from the rest of errno's */
+GBLDEF int job_errno;
/********************************************************************************************************************
* Following enum is used to identify the cause of error in the middle process (M) to the main thread (P)
@@ -46,18 +47,30 @@
* it adds joberr_tryagain to the main status (one of the status' upto joberr_tryagain) and exits with the new status.
*********************************************************************************************************************/
-enum joberr_nm
-{ joberr_gen = 1,
- joberr_io,
+typedef enum
+{ joberr_ok,
+ joberr_gen,
+ joberr_io_stdin_open,
+ joberr_io_stdin_dup,
+ joberr_io_stdout_creat,
+ joberr_io_stdout_open,
+ joberr_io_stdout_dup,
+ joberr_io_stderr_creat,
+ joberr_io_stderr_open,
+ joberr_io_stderr_dup,
+ joberr_cd_toolong,
joberr_cd,
joberr_rtn,
+ joberr_sid,
joberr_frk,
- joberr_syscall,
+ joberr_stdout_rename,
+ joberr_stderr_rename,
+ joberr_pipe_mp,
+ joberr_pipe_mgc,
joberr_stp,
joberr_sig,
- joberr_tryagain,
joberr_end
-};
+} joberr_t;
typedef struct job_parm_struct
{ mval *parm;
@@ -90,7 +103,7 @@ typedef enum
#include "jobparams.h"
} jp_type;
-bool ojchildioset(job_params_type *jparms);
+int ojchildioset(job_params_type *jparms);
int ojstartchild(job_params_type *jparms, int argcnt, boolean_t *non_exit_return, int pipe_fds[]);
void ojparams(char *p, job_params_type *job_params);
void ojgetch_env(job_params_type *jparms);
diff --git a/sr_unix/kitstart.csh b/sr_unix/kitstart.csh
index b2f317b..65fd13e 100644
--- a/sr_unix/kitstart.csh
+++ b/sr_unix/kitstart.csh
@@ -1,7 +1,7 @@
#!/usr/local/bin/tcsh
#################################################################
# #
-# Copyright 2011, 2012 Fidelity Information Services, Inc #
+# Copyright 2011, 2013 Fidelity Information Services, Inc #
# #
# This source code contains the intellectual property #
# of its copyright holder(s), and is made available #
@@ -101,19 +101,30 @@ if ($#argv < 1) then
set syntaxerr = 1
else
set testinstall = 0
+ set leavedir = 0
+ # when present, do not fire off a background kitstart
if ("$1" == "logfile") then
set logfile = 1
shift
endif
+ # perform a test installation
if ("$1" == "-ti") then
set testinstall = 1
shift
endif
+ # build a kit on a non-dist server
set allow = 0
if ("$1" == "-allow") then
set allow = 1
shift
endif
+ # Test the test install
+ if ("$1" == "-tti") then
+ set testinstall = 1
+ set leavedir = 1
+ set allow = 1
+ shift
+ endif
if ("$1" == "" || "$2" != "" && "$2" != "pro" && "$2" != "dbg" && "$2" != "bta") then
set syntaxerr = 1
endif
@@ -121,11 +132,12 @@ endif
if ($syntaxerr) then
echo ""
- echo "Usage : $0 [-ti] [-allow] <ver> [pro | dbg | bta]"
+ echo "Usage : $0 [-ti] [-allow] [-tti] <ver> [pro | dbg | bta]"
echo ""
echo "<ver> : Version with no punctuations; create distribution of this GT.M version (must be in $gtm_root)"
echo "-ti : Test installation"
echo "-allow : allow kit to be built on a non-distribution server"
+ echo "-tti : Test the test installation, implies -allow and always leaves dist, tmp_dist, install directories"
echo "[pro | dbg | bta] : Create distribution of this image; or pro and dbg if not specified"
echo ""
exit 1
@@ -181,27 +193,9 @@ chmod 444 $readme_txt
# Set the open source flag and set lib_specific to the platform specific directories that needs to
# be copied as a part of open source distribution (down the script)
set open_source = 0
-set GNU_COPYING_license = ""
-set OPENSOURCE_build_README = ""
-if ("$osname" == "linux" && ( "$arch" == "i686" || "x8664" == "$arch" )) then
- set open_source = 1
- set lib_specific = ($s_linux)
- if ("x8664" == "$arch" ) set lib_specific = ($s_linux64)
-
- set GNU_COPYING_license = "${gtm_com}/COPYING"
- /bin/cp -pf $cms_tools/opensource_COPYING $GNU_COPYING_license
- chmod 444 $GNU_COPYING_license
-
- # create README with current year in it
- set OPENSOURCE_build_README = "${gtm_com}/README"
- sed "s/#YEAR#/$year/" $cms_tools/opensource_README > $OPENSOURCE_build_README
- chmod 444 $OPENSOURCE_build_README
-endif
-if ("$osname" == "osf1" && "$arch" == "alpha") then
+set GNU_COPYING_license = "${gtm_com}/COPYING"
+if (("$osname" == "linux" && ( "$arch" == "i686" || "x8664" == "$arch" )) || ("$osname" == "osf1" && "$arch" == "alpha")) then
set open_source = 1
- set lib_specific = "$s_dux"
-
- set GNU_COPYING_license = "${gtm_com}/COPYING"
/bin/cp -pf $cms_tools/opensource_COPYING $GNU_COPYING_license
chmod 444 $GNU_COPYING_license
endif
@@ -221,18 +215,8 @@ if (-d $dist || -d $tmp_dist || -d $install) then
endif
echo ""
-if ("$GNU_COPYING_license" != "") then
- if (! -r "$GNU_COPYING_license") then
- echo "Could not locate GNU Copying license at $GNU_COPYING_license. Exiting..."
- exit 4
- endif
- if ("$OPENSOURCE_build_README" != "") then
- if (! -r $OPENSOURCE_build_README) then
- echo "Could not locate Open Source Build README at $OPENSOURCE_build_README. Exiting..."
- exit 4
- endif
- endif
- set opensource_dist = "${dist}/opensource"
+set opensource_dist = "${dist}/opensource"
+if (1 == $open_source) then
echo "Creating $dist (for non open source customers) and $opensource_dist (for open source)"
mkdir -p $opensource_dist || exit 4
else
@@ -240,23 +224,6 @@ else
mkdir $dist || exit 4
endif
-if ("$GNU_COPYING_license" != "") then
- if (! -e ${dist}/README) then
- cat > ${dist}/README << OPENSOURCE_EOF
-For paying customers, distribute files in ${dist}
-For non paying customers (Sourceforge) who use the Open Source version,
-distribute files in ${opensource_dist}
-The Open Source binary distribution includes the GNU License (file $GNU_COPYING_license:t)
-The Open Source source distribution includes the GNU License (file $GNU_COPYING_license:t)
-OPENSOURCE_EOF
- if ("$OPENSOURCE_build_README" != "") then
- cat >> ${dist}/README << OPENSOURCE_EOF
-and the build procedure documentation (file $OPENSOURCE_build_README:t)
-OPENSOURCE_EOF
- endif
- chmod a-xw ${dist}/README
- endif
-endif
foreach image ($imagetype)
echo ""
echo "Creating ${tmp_dist}/${image}"
@@ -294,7 +261,7 @@ foreach image ($imagetype)
$package $dist_file README.txt dbcertify V5CBSU.m || exit 10
echo "Gzipping $dist_file"
gzip $dist_file || exit 11
- if ("$GNU_COPYING_license" != "") then
+ if (1 == $open_source) then
echo ""
echo "Creating dbcertify distribution for open source (includes GNU License)"
echo ""
@@ -327,7 +294,7 @@ foreach image ($imagetype)
$package $dist_file README.txt GTMDefinedTypesInit.m || exit 10
echo "Gzipping $dist_file"
gzip $dist_file || exit 11
- if ("$GNU_COPYING_license" != "") then
+ if (1 == $open_source) then
echo ""
echo "Creating GTMDefinedTypesInit distribution for open source (includes GNU License)"
echo ""
@@ -376,7 +343,7 @@ foreach image ($imagetype)
echo ""
echo "Gzipping $dist_file"
gzip $dist_file || exit 11
- if ("$GNU_COPYING_license" != "") then
+ if (1 == $open_source) then
echo ""
echo "Creating distribution for open source (includes GNU License)"
echo ""
@@ -395,91 +362,6 @@ foreach image ($imagetype)
end
echo ""
-# create src tar only for linux and tru64
-if ("$GNU_COPYING_license" != "") then
- cd ${opensource_dist}
- if ("$OPENSOURCE_build_README" != "") then
- echo "Creating source distribution for Opensource including $GNU_COPYING_license:t and $OPENSOURCE_build_README:t"
- else
- echo "Creating source distribution for Opensource including $GNU_COPYING_license:t"
- endif
- echo ""
- # tar only the directories in ${liblist}
- set liblist = ""
- foreach libdir ($lib_specific)
- set liblist = "$liblist $libdir:t"
- end
- echo ""
- set src_tar="${opensource_dist}/${dist_prefix}_src.${package_ext}"
- echo "Creating $src_tar"
-
- echo "Copy in the original sources from ${version}"
- mkdir ${version}
- cp -r $lib_specific ./${version}/
-
- # comlist.mk builds fail on newer 32bit versions of RHEL6 and Ubuntu
- # 12.04 due to a bad interaction between the deprecated -I- option and
- # GCC. See mails with the subject:
- # [GTM-6465] [cmake] #include "" vs #include <>
- # Keep in sync with test/manually_start/u_inref/makebuild.csh
- echo "Massage the source files so that we can build on i386 Linux and other platforms without -I-"
- set hdrlist="emit_code_sp.h|rtnhdr.h|auto_zlink.h|make_mode_sp.h|auto_zlink_sp.h|emit_code.h|mdefsp.h|incr_link_sp.h|gtm_mtio.h|obj_filesp.h|zbreaksp.h|gtm_registers.h|opcode_def.h" #BYPASSOK line length
- set sedlist=${hdrlist:as/|/ /:as/ /\|/} # fixing for use with SED requires some contortions - replace | with space and then space with \|
- grep -rlE "#include .(${hdrlist})." sr_* > changefiles.list
- foreach file (`cat changefiles.list`)
- set orig=${file:h}/.${file:t}
- mv ${file} {$orig}
- sed "s/#include .\(${sedlist}\)./#include <\1>/g" ${orig} > ${file}
- diff -u ${orig} ${file}
- rm ${orig}
- end
-
- echo "Copy in the generated files"
- set srdir = sr_${arch:s/i686/i386/:s/x8664/x86_64/}
- cp ${gtm_ver}/src/ttt.c ${gtm_ver}/src/*_ctl.c ${gtm_ver}/inc/merrors_ansi.h ./$version/$srdir/ || exit 10
-
- echo "Packaging the source from $version"
- cd $version || exit 10
- # Linux uses CMakeLists.txt, tru64 uses comlist.mk
- if ("linux" == "$osname") then
- # this lets the build override $cms_ver/sr_unix/CMakeLists.txt
- sed "s/GTM_RELEASE_VERSION/${releasever}/" ${gtm_ver}/tools/CMakeLists.txt > CMakeLists.txt || exit 10
- set liblist = "$liblist CMakeLists.txt"
- endif
- find . -exec chown 40535:40535 {} \;
- $package $src_tar $liblist || exit 10
-
- cd ${opensource_dist}
- rm -rf ./$version
-
- echo "Package the license and readme files"
- cd $gtm_com || exit 10
- if ("$OPENSOURCE_build_README" != "") then
- $repackage $src_tar $GNU_COPYING_license:t $OPENSOURCE_build_README:t || exit 10
- else
- $repackage $src_tar $GNU_COPYING_license:t $readme_txt:t || exit 10
- endif
-
- echo ""
- echo "Gzipping $src_tar"
- gzip $src_tar || exit 11
- echo ""
- if ("$OPENSOURCE_build_README" != "") then
- cat << EOF_MK
-############################################################################
-!!!!! TEST THE MAKEFILE !!!!!
-First untar the opensource files in a directory:
-mkdir ${opensource_dist}/build
-cd ${opensource_dist}/build
-tar zxvf $src_tar
-Then follow the instructions from $gtm_com/README:
-----------------------------------------------------------------------------
-`cat $gtm_com/README`
-############################################################################
-EOF_MK
- endif
-endif
-
find $dist -type f -exec chmod 444 {} \;
find $dist -type d -exec chmod 755 {} \;
chown -R library:gtc $dist
@@ -487,7 +369,6 @@ echo "Files in $dist"
/bin/ls -lR $dist
echo ""
-set leavedir = 0
set kitver = ${gtm_ver:t:s/V//}
if ($testinstall) then
@@ -552,15 +433,10 @@ n
CONFIGURE_EOF
endif
- # We need for root to be a member of the restricted group. It is a member of the "root" group
- # for all linux OS and it is a member of "lp" for all others except osf1 where it is "vboxusers"
- if("$osname" == "linux") then
- setenv rootgroup "root"
- else if ("$osname" != "osf1") then
- setenv rootgroup "lp"
- else
- setenv rootgroup "vboxusers"
- endif
+ # We need for root to be a member of the restricted group so that it can run tests. root is a
+ # member of the gtmsec NIS group.
+ setenv rootgroup gtmsec
+
# V54002 now asks for an installation group before the restricted group question so response is
# reversed from V54000
# V54003 now asks whether or not to retain .o files if libgtmutil.so is created
@@ -623,12 +499,13 @@ CONFIGURE_EOF
if ("pro" == ${image}) then
# create the build.dir. Only have to do it once
cd $gtm_ver || exit 14
+ # insert "pro:" for non Linux/Solaris
if ((${osname} != linux) && (${osname} != solaris)) echo pro: > ${tmp_dist}/build.dir
ls -lR pro >> ${tmp_dist}/build.dir
if (aix == ${osname}) then
- cat ${tmp_dist}/build.dir | \
-awk '$0 == "pro/gtmsecshrdir:" {printf "\n%s\n", $0} $0 != "pro/gtmsecshrdir:" {printf "%s\n", $0}' > ${tmp_dist}/tbuild.dir
- mv ${tmp_dist}/tbuild.dir ${tmp_dist}/build.dir
+ # insert a newline before "pro/gtmsecshrdir:" on AIX
+ mv ${tmp_dist}/build.dir ${tmp_dist}/tbuild.dir
+ awk '/^pro.gtmsecshrdir:$/{print ""}{print $0}' ${tmp_dist}/tbuild.dir > ${tmp_dist}/build.dir
endif
# make a defgroup directory under ${tmp_dist} and copy in the build.dir for use in
@@ -641,36 +518,38 @@ awk '$0 == "pro/gtmsecshrdir:" {printf "\n%s\n", $0} $0 != "pro/gtmsecshrdir:" {
while (2 > $both)
# create the install.dir from both installations
cd ${install}/$defgroup
+ # insert "pro:" for non Linux/Solaris
if ((${osname} != linux) && (${osname} != solaris)) echo pro: > ${tmp_dist}/$defgroup/install.dir
ls -lR pro >> ${tmp_dist}/$defgroup/install.dir
if (aix == ${osname}) then
- cat ${tmp_dist}/$defgroup/install.dir | \
-awk '$0 == "pro/gtmsecshrdir:" {printf "\n%s\n", $0} $0 != "pro/gtmsecshrdir:" {printf "%s\n", $0}' > \
-${tmp_dist}/$defgroup/tinstall.dir
- mv ${tmp_dist}/$defgroup/tinstall.dir ${tmp_dist}/$defgroup/install.dir
+ # insert a newline before "pro/gtmsecshrdir:" on AIX
+ mv ${tmp_dist}/$defgroup/install.dir ${tmp_dist}/$defgroup/tinstall.dir
+ awk '/^pro.gtmsecshrdir:$/{print ""}{print $0}' ${tmp_dist}/$defgroup/tinstall.dir \
+ > ${tmp_dist}/$defgroup/install.dir
endif
cd ${tmp_dist}/${image}
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
- $comp $gtm_tools/linuxi686_badd.txt $gtm_tools/bdeldir.txt ${osname}
- set teststat = $status
+ set adddir=$gtm_tools/linuxi686_badd.txt
else if (("hpux" == ${osname}) && ("parisc" == ${arch})) then
- $comp $gtm_tools/hpuxparisc_badd.txt $gtm_tools/hpuxparisc_bdeldir.txt ${osname}
- set teststat = $status
+ set adddir=$gtm_tools/hpuxparisc_badd.txt
+ set deldir=$gtm_tools/hpuxparisc_bdeldir.txt
else if (("hpux" == ${osname}) && ("ia64" == ${arch})) then
- $comp $gtm_tools/hpuxia64_badd.txt $gtm_tools/bdeldir.txt ${osname}
- set teststat = $status
+ set adddir=$gtm_tools/hpuxia64_badd.txt
else if (("osf1" == ${osname}) && ("alpha" == ${arch})) then
- $comp $gtm_tools/osf1alpha_badd.txt $gtm_tools/hpuxparisc_bdeldir.txt ${osname}
- set teststat = $status
- else
- $comp $gtm_tools/badd.txt $gtm_tools/bdeldir.txt ${osname}
- set teststat = $status
+ set adddir=$gtm_tools/osf1alpha_badd.txt
+ set deldir=$gtm_tools/hpuxparisc_bdeldir.txt
endif
+ $comp $adddir $deldir ${osname}
+ set teststat = $status
if ($teststat) then
echo ""
echo "Comparison of build and install directories failed."
echo "Look in ${tmp_dist}/$defgroup/dircompare/diff.out"
+ echo "$comp $adddir $deldir ${osname}"
+ chmod -R ugo+rwx ${tmp_dist}/$defgroup/dircompare
exit 16
endif
# to simplify the code to do the gtm_compare_dir.csh for both restricted and unrestricted group
diff --git a/sr_unix/libmupip.list b/sr_unix/libmupip.list
index f354de6..b78fd63 100644
--- a/sr_unix/libmupip.list
+++ b/sr_unix/libmupip.list
@@ -190,7 +190,6 @@ mur_validate_checksum
mur_ztp_lookback
murgetlst
read_db_files_from_gld
-recvpool_init
repl_comm
repl_filter
repl_inst_create
@@ -199,6 +198,7 @@ repl_inst_edit
repl_ipc_cleanup
repl_log
repl_log_init
+repl_logfileinfo_get
repl_tr_good
replic_gbldefs
ss_anal_shdw_file
diff --git a/sr_unix/linuxi686_badd.txt b/sr_unix/linuxi686_badd.txt
index 733c2ed..f7ba825 100644
--- a/sr_unix/linuxi686_badd.txt
+++ b/sr_unix/linuxi686_badd.txt
@@ -1,6 +1,6 @@
#################################################################
# #
-# Copyright 2011, 2012 Fidelity Information Services, Inc #
+# Copyright 2011, 2013 Fidelity Information Services, Inc #
# #
# This source code contains the intellectual property #
# of its copyright holder(s), and is made available #
@@ -29,3 +29,8 @@ zzz_insert%-r--r----- source.tar
pro/utf8:
TTTGEN.m -> ../TTTGEN.m%lrwxrwxrwx README.txt -> ../README.txt
dse -> ../dse%lrwxrwxrwx custom_errors_sample.txt -> ../custom_errors_sample.txt
+gtmstart.gtc -> ../gtmstart.gtc%-r-sr-x--- gtmsecshr
+gtmstart.gtc -> ../gtmstart.gtc%dr-x------ gtmsecshrdir
+
+pro/utf8/gtmsecshrdir:
+zzz_insert%-r-s------ gtmsecshr
diff --git a/sr_unix/list_file.c b/sr_unix/list_file.c
index cb9f76c..962b64d 100644
--- a/sr_unix/list_file.c
+++ b/sr_unix/list_file.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -20,6 +20,7 @@
#include "parse_file.h"
#include "list_file.h"
#include "op.h"
+#include "have_crit.h"
#define LISTEXT ".lis"
@@ -97,7 +98,7 @@ void open_list_file(void)
dev_in_use = io_curr_device;
op_use(&file,&parms);
clock = time(0);
- p = GTM_CTIME(&clock);
+ GTM_CTIME(p, &clock);
memcpy (print_time_buf, p + 4, SIZEOF(print_time_buf));
list_head(0);
return;
diff --git a/sr_unix/lke_cmd.c b/sr_unix/lke_cmd.c
index 541ab6b..93d349e 100644
--- a/sr_unix/lke_cmd.c
+++ b/sr_unix/lke_cmd.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -26,6 +26,7 @@
#include "cli.h"
#include "lke.h"
#include "util_spawn.h"
+#include "util_help.h"
#include "lke_cmd_disallow.h"
static readonly CLI_ENTRY clear_qual[] = {
@@ -58,7 +59,7 @@ static readonly CLI_ENTRY show_qual[] = {
GBLDEF CLI_ENTRY lke_cmd_ary[] = {
{ "CLEAR", lke_clear, clear_qual, 0, 0, cli_disallow_lke_clear, 0, VAL_NOT_REQ, 2, 0, VAL_STR, 0},
{ "EXIT", lke_exit, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, 0, 0, 0},
- { "HELP", lke_help, 0, 0, 0, 0, 0, VAL_NOT_REQ, 5, 0, 0, 0},
+ { "HELP", util_help, 0, 0, 0, 0, 0, VAL_NOT_REQ, 1, 0, 0, 0},
{ "SETGDR", lke_setgdr, 0, 0, 0, 0, 0, VAL_REQ, 1, 0, 0, 0},
{ "SHOW", lke_show, show_qual, 0, 0, 0, 0, VAL_NOT_REQ, 1, 0, VAL_STR, 0},
{ "SPAWN", util_spawn, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, 0, 0, 0},
diff --git a/sr_unix/lke_help.c b/sr_unix/lke_help.c
index 844d6b4..85d2498 100644
--- a/sr_unix/lke_help.c
+++ b/sr_unix/lke_help.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -23,5 +23,5 @@
void lke_help(void)
{
- PRINTF("Help command not implemented in this revision\n");
+ /* This function is a STUB to avoid editting sr_port/lke.h */
}
diff --git a/sr_unix/maskpass.c b/sr_unix/maskpass.c
index bf1e30d..d2e7f09 100644
--- a/sr_unix/maskpass.c
+++ b/sr_unix/maskpass.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2009, 2012 Fidelity Information Services, Inc *
+ * Copyright 2009, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -220,7 +220,7 @@ int main()
{
printf("libgcrypt version mismatch. %s or higher is required.\n",
GCRYPT_VERSION);
- exit(1);
+ exit(EXIT_FAILURE);
}
/* Since we will just be hashing, secure memory is not needed. */
if (!(err = gcry_control(GCRYCTL_DISABLE_SECMEM,0)))
@@ -228,7 +228,7 @@ int main()
if (GPG_ERR_NO_ERROR != err)
{
printf("Libgcrypt error: %s\n", gcry_strerror(err));
- exit(1);
+ exit(EXIT_FAILURE);
}
# endif
@@ -238,7 +238,7 @@ int main()
if (get_hash_via_env_var(hash))
if (get_hash_via_username_and_inode(hash, passwd, &passwd_len))
- exit(1);
+ exit(EXIT_FAILURE);
if ((size_t)-1 == passwd_len)
{
prompt_passwd(passwd);
diff --git a/sr_unix/mdefsa.h b/sr_unix/mdefsa.h
index 5701efc..729fb9d 100644
--- a/sr_unix/mdefsa.h
+++ b/sr_unix/mdefsa.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -74,6 +74,5 @@
#define cancel_timer GTM_PREFIX(cancel_timer)
#define hiber_start GTM_PREFIX(hiber_start)
#define hiber_start_wait_any GTM_PREFIX(hiber_start_wait_any)
-#define start_timer GTM_PREFIX(start_timer)
#endif /* MDEFSA_included */
diff --git a/sr_unix/mdefsp.h b/sr_unix/mdefsp.h
index f60644c..4311150 100644
--- a/sr_unix/mdefsp.h
+++ b/sr_unix/mdefsp.h
@@ -14,10 +14,6 @@
#include <sys/types.h>
-#if defined(__ia64) || defined(__x86_64__) || defined(__sparc) || defined(__s390__)
-#define GTM64
-#endif /* __ia64 */
-
#ifdef GTM64
typedef long int8; /* 8-byte signed integer */
typedef unsigned long uint8; /* 8-byte unsigned integer */
@@ -38,11 +34,6 @@ typedef uint2 mach_inst;
#define INT8_FMTX "[0x%llx]"
#define UNICODE_SUPPORTED
-/* Starting off life as debugging parms and now we need them for the
- short term so define them here */
-#define DEBUG_LEAVE_SM
-#define DEBUG_NOMSYNC
-
#define UNIX 1
#undef VMS
#define BIGENDIAN 1
@@ -50,7 +41,6 @@ typedef uint2 mach_inst;
#ifdef __sparc
#define CACHELINE_SIZE 256
-#define MSYNC_ADDR_INCS OS_PAGE_SIZE
#define USHBIN_SUPPORTED
#define LINKAGE_PSECT_BOUNDARY 8
#define OFF_T_LONG
@@ -78,7 +68,6 @@ typedef uint4 mach_inst;
#endif /* __ia64 */
#ifdef __hpux
-#define MSYNC_ADDR_INCS OS_PAGE_SIZE
#define MUTEX_MSEM_WAKE
#define POSIX_MSEM
#define USHBIN_SUPPORTED
@@ -86,9 +75,12 @@ typedef uint4 mach_inst;
/* Make sure linkage Psect is aligned on appropriate boundary. */
#ifdef __ia64
#define LINKAGE_PSECT_BOUNDARY 8
-#else
+#else /* parisc */
#define LINKAGE_PSECT_BOUNDARY 4
-#endif //__ia64
+#ifdef __GNUC__
+typedef unsigned short in_port_t; /* GCC needs this on PARISC */
+#endif
+#endif
typedef uint4 mach_inst; /* machine instruction */
#endif /* __hpux */
@@ -127,16 +119,14 @@ typedef unsigned short in_port_t;
#define GTM_CONTEXT(func) (unsigned char *)func
#define SSM_SIZE 256*1024*1024 /* Segments on 256M boundary */
#define SHMAT_ADDR_INCS SSM_SIZE
-#define MSYNC_ADDR_INCS OS_PAGE_SIZE
#define USHBIN_SUPPORTED
#endif /* __s390__ */
#ifdef __ia64
# ifdef __linux__
-# define MSYNC_ADDR_INCS OS_PAGE_SIZE
-# undef BIGENDIAN
+# undef BIGENDIAN
# define USHBIN_SUPPORTED
- /* Make sure linkage Psect is aligned on appropriate boundary. */
+ /* Make sure linkage Psect is aligned on appropriate boundary. */
# define LINKAGE_PSECT_BOUNDARY 8
typedef uint4 mach_inst; /* machine instruction */
# elif defined(__hpux)
@@ -149,14 +139,12 @@ void dyncall();
#ifdef __i386
/* Through Pentium Pro/II/III, should use CPUID to get real value perhaps */
#define CACHELINE_SIZE 32
-#define MSYNC_ADDR_INCS OS_PAGE_SIZE
#undef BIGENDIAN
typedef char mach_inst; /* machine instruction */
#endif /* __i386 */
#ifdef __x86_64__
#define CACHELINE_SIZE 64
-#define MSYNC_ADDR_INCS OS_PAGE_SIZE
#define USHBIN_SUPPORTED
#define INO_T_LONG
/*
diff --git a/sr_unix/mu_all_version_standalone.c b/sr_unix/mu_all_version_standalone.c
index ed04ea1..6af0afa 100644
--- a/sr_unix/mu_all_version_standalone.c
+++ b/sr_unix/mu_all_version_standalone.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2005, 2011 Fidelity Information Services, Inc *
+ * Copyright 2005, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -46,6 +46,8 @@ static int ftok_ver[FTOK_ID_CNT] = {0, 0, 1};
error_def(ERR_MUSTANDALONE);
error_def(ERR_DBOPNERR);
+error_def(ERR_FTOKKEY);
+error_def(ERR_SEMID);
error_def(ERR_SYSCALL);
error_def(ERR_TEXT);
ZOS_ONLY(error_def(ERR_BADTAG);)
@@ -105,9 +107,11 @@ 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(4) MAKE_MSG_TYPE(ERR_MUSTANDALONE, ERROR), 2, RTS_ERROR_TEXT(db_fn));
+ 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);
else
- rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("semget()"), CALLFROM, save_errno);
+ rts_error(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)
@@ -115,9 +119,12 @@ 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(4) MAKE_MSG_TYPE(ERR_MUSTANDALONE, ERROR), 2, RTS_ERROR_TEXT(db_fn));
+ rts_error(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);
else
- rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("semop()"), CALLFROM, save_errno);
+ 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);
}
}
@@ -159,7 +166,8 @@ 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(4) MAKE_MSG_TYPE(ERR_MUSTANDALONE, ERROR), 2, RTS_ERROR_TEXT(db_fn));
+ 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);
}
}
diff --git a/sr_unix/mu_extract.c b/sr_unix/mu_extract.c
index be45900..07b0255 100644
--- a/sr_unix/mu_extract.c
+++ b/sr_unix/mu_extract.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -80,7 +80,6 @@ LITDEF mval mu_bin_datefmt = DEFINE_MVAL_LITERAL(MV_STR, 0, 0, SIZEOF(BIN_HEADER
LITREF mstr chset_names[];
static readonly unsigned char datefmt_txt[] = "DD-MON-YEAR 24:60:SS";
-static readonly unsigned char gt_lit[] = "TOTAL";
static readonly unsigned char select_text[] = "SELECT";
static readonly mval datefmt = DEFINE_MVAL_LITERAL(MV_STR, 0, 0, SIZEOF(datefmt_txt) - 1, (char *)datefmt_txt, 0, 0);
static readonly mval null_str = DEFINE_MVAL_LITERAL(MV_STR, 0, 0, 0, 0, 0, 0);
@@ -246,7 +245,7 @@ void mu_extract(void)
gv_select(cli_buff, n_len, freeze, (char *)select_text, &gl_head, ®_max_rec, ®_max_key, ®_max_blk, FALSE);
if (!gl_head.next)
{
- rts_error(VARLSTCNT(1) ERR_NOSELECT);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOSELECT);
mupip_exit(ERR_NOSELECT);
}
/* For binary format, check whether all regions have same null collation order */
@@ -269,7 +268,7 @@ void mu_extract(void)
reg_std_null_coll = reg->std_null_coll;
else
{
- rts_error(VARLSTCNT(1) ERR_NULLCOLLDIFF);
+ rts_error_csa(CSA_ARG(REG2CSA(reg)) VARLSTCNT(1) ERR_NULLCOLLDIFF);
mupip_exit(ERR_NULLCOLLDIFF);
}
}
@@ -292,21 +291,21 @@ void mu_extract(void)
op_val.str = sys_output;
else if (FALSE == cli_get_str("FILE", outfilename, &n_len))
{
- rts_error(VARLSTCNT(1) ERR_MUPCLIERR);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MUPCLIERR);
mupip_exit(ERR_MUPCLIERR);
} else if (-1 == Stat((char *)outfilename, &statbuf))
{ /* Redirect to file */
if (ENOENT != errno)
{
local_errno = errno;
- gtm_putmsg(VARLSTCNT(5) ERR_EXTRACTFILERR, 2, LEN_AND_STR(outfilename), local_errno);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_EXTRACTFILERR, 2, LEN_AND_STR(outfilename), local_errno);
mupip_exit(local_errno);
}
op_val.str.len = filename_len = n_len;
op_val.str.addr = (char *)outfilename;
} else
{
- gtm_putmsg(VARLSTCNT(4) ERR_EXTRFILEXISTS, 2, LEN_AND_STR(outfilename));
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_EXTRFILEXISTS, 2, LEN_AND_STR(outfilename));
mupip_exit(ERR_MUNOACTION);
}
op_pars.mvtype = MV_STR;
@@ -447,7 +446,7 @@ void mu_extract(void)
{
gbl_name_buff[0]='^';
memcpy(&gbl_name_buff[1], gl_ptr->name.str.addr, gl_ptr->name.str.len);
- gtm_putmsg(VARLSTCNT(8) ERR_RECORDSTAT, 6, gl_ptr->name.str.len + 1, gbl_name_buff,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_RECORDSTAT, 6, gl_ptr->name.str.len + 1, gbl_name_buff,
global_total.recknt, global_total.keylen, global_total.datalen, global_total.reclen);
mu_ctrlc_occurred = FALSE;
}
@@ -482,7 +481,7 @@ void mu_extract(void)
{
gbl_name_buff[0]='^';
memcpy(&gbl_name_buff[1], gl_ptr->name.str.addr, gl_ptr->name.str.len);
- gtm_putmsg(VARLSTCNT(8) ERR_RECORDSTAT, 6, gl_ptr->name.str.len + 1, gbl_name_buff,
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) ERR_RECORDSTAT, 6, gl_ptr->name.str.len + 1, gbl_name_buff,
global_total.recknt, global_total.keylen, global_total.datalen, global_total.reclen);
mu_ctrlc_occurred = FALSE;
}
@@ -503,10 +502,10 @@ void mu_extract(void)
REVERT;
if (mu_ctrly_occurred)
{
- gtm_putmsg(VARLSTCNT(1) ERR_EXTRACTCTRLY);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_EXTRACTCTRLY);
mupip_exit(ERR_MUNOFINISH);
}
- gtm_putmsg(VARLSTCNT(8) ERR_RECORDSTAT, 6, LEN_AND_LIT(gt_lit),
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_RECORDSTAT, 6, LEN_AND_LIT("TOTAL"),
grand_total.recknt, grand_total.keylen, grand_total.datalen, grand_total.reclen);
if (MU_FMT_BINARY == format)
{ /* truncate the last newline charactor flushed by op_close */
diff --git a/sr_unix/mu_replpool_grab_sem.c b/sr_unix/mu_replpool_grab_sem.c
index d7d01e6..297e1d7 100644
--- a/sr_unix/mu_replpool_grab_sem.c
+++ b/sr_unix/mu_replpool_grab_sem.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -172,7 +172,7 @@ int mu_replpool_grab_sem(repl_inst_hdr_ptr_t repl_inst_filehdr, char pool_type,
DO_CLNUP_AND_RETURN(save_errno, sem_created, pool_type, instfilename, instfilelen, sem_id, "semctl()");
}
semarg.buf = &semstat;
- if (-1 == semctl(sem_id, 0, IPC_STAT, semarg))
+ if (-1 == semctl(sem_id, DB_CONTROL_SEM, IPC_STAT, semarg))
{
save_errno = errno;
DO_CLNUP_AND_RETURN(save_errno, sem_created, pool_type, instfilename, instfilelen, sem_id, "semctl()");
diff --git a/sr_unix/mu_rndwn_all.c b/sr_unix/mu_rndwn_all.c
index 0fbbc07..b97a907 100644
--- a/sr_unix/mu_rndwn_all.c
+++ b/sr_unix/mu_rndwn_all.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -243,7 +243,7 @@ boolean_t validate_db_shm_entry(shm_parms *parm_buff, char *fname, int *exit_sta
return FALSE;
/* check for the bare minimum size of the shared memory segment that we expect
* (with no fileheader related information at hand) */
- if (NODE_LOCAL_SPACE + SHMPOOL_SECTION_SIZE > parm_buff->sgmnt_siz)
+ if (MIN_NODE_LOCAL_SPACE + SHMPOOL_SECTION_SIZE > parm_buff->sgmnt_siz)
return FALSE;
if (IPC_PRIVATE != parm_buff->key)
return FALSE;
@@ -596,11 +596,14 @@ char *parse_shm_entry(char *entry, int which_field)
for(iter = 1; iter < which_field; iter++)
{
+ /* Strip leading spaces */
while(entry[indx1] == ' ')
indx1++;
+ /* Accept until spaces or NULL */
while(entry[indx1] && entry[indx1] != ' ')
indx1++;
}
+ /* Strip leading spaces */
while(entry[indx1] == ' ')
indx1++;
if ('\0' == entry[indx1])
@@ -609,8 +612,8 @@ char *parse_shm_entry(char *entry, int which_field)
return NULL;
}
parm = (char *)malloc(MAX_PARM_LEN);
- memset(parm, 0, MAX_PARM_LEN);
- while(entry[indx1] && entry[indx1] != ' ')
+ /* Copy value from entry until NULL or a space character */
+ while(entry[indx1] && (entry[indx1] != ' ') && (indx2 < (MAX_PARM_LEN - 1)))
parm[indx2++] = entry[indx1++];
parm[indx2] = '\0';
diff --git a/sr_unix/mu_rndwn_file.c b/sr_unix/mu_rndwn_file.c
index 667b349..424250d 100644
--- a/sr_unix/mu_rndwn_file.c
+++ b/sr_unix/mu_rndwn_file.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -69,6 +69,8 @@
#include "shmpool.h" /* Needed for the shmpool structures */
#include "is_proc_alive.h"
#include "ss_lock_facility.h"
+#include "cli.h"
+#include "gtm_file_stat.h"
#ifndef GTM_SNAPSHOT
# error "Snapshot facility not available in this platform"
@@ -91,103 +93,114 @@ static gd_region *temp_region;
static sgmnt_data_ptr_t temp_cs_data;
static sgmnt_addrs *temp_cs_addrs;
static boolean_t restore_rndwn_gbl;
+static boolean_t mu_rndwn_file_standalone;
LITREF char gtm_release_name[];
LITREF int4 gtm_release_name_len;
error_def(ERR_BADDBVER);
error_def(ERR_DBFILERR);
+error_def(ERR_DBIDMISMATCH);
+error_def(ERR_DBNAMEMISMATCH);
error_def(ERR_DBNOTGDS);
error_def(ERR_DBRDONLY);
-error_def(ERR_DBNAMEMISMATCH);
-error_def(ERR_DBIDMISMATCH);
error_def(ERR_DBSHMNAMEDIFF);
+error_def(ERR_JNLORDBFLU);
+error_def(ERR_MURNDWNOVRD);
+error_def(ERR_MUUSERECOV);
+error_def(ERR_MUUSERLBK);
+error_def(ERR_SEMREMOVED);
+error_def(ERR_SHMREMOVED);
+error_def(ERR_SYSCALL);
error_def(ERR_TEXT);
error_def(ERR_VERMISMATCH);
-error_def(ERR_SYSCALL);
-error_def(ERR_SHMREMOVED);
-error_def(ERR_SEMREMOVED);
-#define RESET_GV_CUR_REGION \
-{ \
- gv_cur_region = temp_region; \
- cs_addrs = temp_cs_addrs; \
- cs_data = temp_cs_data; \
+#define RESET_GV_CUR_REGION \
+{ \
+ gv_cur_region = temp_region; \
+ cs_addrs = temp_cs_addrs; \
+ cs_data = temp_cs_data; \
}
-#define CLNUP_AND_RETURN(REG, UDI, TSD, SEM_CREATED, SEM_INCREMENTED) \
-{ \
- int rc; \
- \
- if (FD_INVALID != UDI->fd) \
- { \
- CLOSEFILE_RESET(UDI->fd, rc); \
- assert(FD_INVALID == UDI->fd); \
- } \
- if (NULL != TSD) \
- { \
- free(TSD); \
- TSD = NULL; \
- } \
- if (SEM_INCREMENTED) \
- { \
- do_semop(udi->semid, 0, -1, IPC_NOWAIT | SEM_UNDO); \
- SEM_INCREMENTED = FALSE; \
- } \
- if (SEM_CREATED) \
- { \
- if (-1 == sem_rmid(UDI->semid)) \
- { \
- RNDWN_ERR("!AD -> Error removing semaphore.", REG); \
- } else \
- SEM_CREATED = FALSE; \
- } \
- REVERT; \
- assert((NULL == ftok_sem_reg) || (REG == ftok_sem_reg)); \
- if (REG == ftok_sem_reg) \
- ftok_sem_release(REG, TRUE, TRUE); \
- if (restore_rndwn_gbl) \
- { \
- RESET_GV_CUR_REGION; \
- restore_rndwn_gbl = FALSE; \
- } \
- return FALSE; \
+#define CLNUP_AND_RETURN(REG, UDI, TSD, SEM_CREATED, SEM_INCREMENTED) \
+{ \
+ int rc; \
+ \
+ if (FD_INVALID != UDI->fd) \
+ { \
+ CLOSEFILE_RESET(UDI->fd, rc); \
+ assert(FD_INVALID == UDI->fd); \
+ } \
+ if (NULL != TSD) \
+ { \
+ free(TSD); \
+ TSD = NULL; \
+ } \
+ if (SEM_INCREMENTED) \
+ { \
+ do_semop(udi->semid, DB_CONTROL_SEM, -1, IPC_NOWAIT | SEM_UNDO); \
+ SEM_INCREMENTED = FALSE; \
+ } \
+ if (SEM_CREATED) \
+ { \
+ if (-1 == sem_rmid(UDI->semid)) \
+ { \
+ RNDWN_ERR("!AD -> Error removing semaphore.", REG); \
+ } else \
+ SEM_CREATED = FALSE; \
+ } \
+ REVERT; \
+ assert((NULL == ftok_sem_reg) || (REG == ftok_sem_reg)); \
+ if (REG == ftok_sem_reg) \
+ ftok_sem_release(REG, TRUE, TRUE); \
+ if (restore_rndwn_gbl) \
+ { \
+ RESET_GV_CUR_REGION; \
+ restore_rndwn_gbl = FALSE; \
+ } \
+ return FALSE; \
}
-#define SEG_SHMATTACH(addr, reg, udi, tsd, sem_created, sem_incremented) \
-{ \
- if (-1 == (sm_long_t)(cs_addrs->db_addrs[0] = (sm_uc_ptr_t) \
- do_shmat(udi->shmid, addr, SHM_RND))) \
- { \
- if (EINVAL != errno) \
- RNDWN_ERR("!AD -> Error attaching to shared memory", (reg)); \
- /* shared memory segment no longer exists */ \
- CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented); \
- } \
+#define SEG_SHMATTACH(addr, reg, udi, tsd, sem_created, sem_incremented) \
+{ \
+ if (-1 == (sm_long_t)(cs_addrs->db_addrs[0] = (sm_uc_ptr_t) \
+ do_shmat(udi->shmid, addr, SHM_RND))) \
+ { \
+ if (EINVAL != errno) \
+ RNDWN_ERR("!AD -> Error attaching to shared memory", (reg)); \
+ /* shared memory segment no longer exists */ \
+ CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented); \
+ } \
}
-#define SEG_MEMMAP(addr, reg, udi, tsd, sem_created, sem_incremented) \
-{ \
- if (-1 == (sm_long_t)(cs_addrs->db_addrs[0] = (sm_uc_ptr_t)mmap((caddr_t)addr, \
- (size_t)stat_buf.st_size, PROT_READ | PROT_WRITE, GTM_MM_FLAGS, udi->fd, (off_t)0))) \
- { \
- RNDWN_ERR("!AD -> Error mapping memory", (reg)); \
- CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented); \
- } \
+#define REMOVE_SEMID_IF_ORPHANED(REG, UDI, TSD, SEM_CREATED, SEM_INCREMENTED) \
+{ \
+ if (is_orphaned_gtm_semaphore(UDI->semid)) \
+ { \
+ if (0 != sem_rmid(UDI->semid)) \
+ { \
+ RNDWN_ERR("!AD -> Error removing semaphore.", reg); \
+ CLNUP_AND_RETURN(REG, UDI, TSD, SEM_CREATED, SEM_INCREMENTED); \
+ } \
+ send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(3) ERR_SEMREMOVED, 1, UDI->semid); \
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(3) ERR_SEMREMOVED, 1, UDI->semid); \
+ UDI->semid = INVALID_SEMID; \
+ } \
}
-#define REMOVE_SEMID_IF_ORPHANED(REG, UDI, TSD, SEM_CREATED, SEM_INCREMENTED) \
+/* Print an error message that, based on whether replication was enabled at the time of the crash, would instruct
+ * the user to a more appropriate operation than RUNDOWN, such as RECOVER or REQROLLBACK.
+ */
+#define PRINT_PREVENT_RUNDOWN_MESSAGE(REG) \
{ \
- if (is_orphaned_gtm_semaphore(UDI->semid)) \
+ if (REPL_ENABLED(tsd) && tsd->jnl_before_image) \
{ \
- if (0 != sem_rmid(UDI->semid)) \
- { \
- RNDWN_ERR("!AD -> Error removing semaphore.", reg); \
- CLNUP_AND_RETURN(REG, UDI, TSD, SEM_CREATED, SEM_INCREMENTED); \
- } \
- send_msg(VARLSTCNT(3) ERR_SEMREMOVED, 1, UDI->semid); \
- gtm_putmsg(VARLSTCNT(3) ERR_SEMREMOVED, 1, UDI->semid); \
- UDI->semid = INVALID_SEMID; \
+ rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) ERR_MUUSERLBK, 2, DB_LEN_STR(REG), \
+ ERR_TEXT, 2, LEN_AND_LIT("Run MUPIP JOURNAL ROLLBACK")); \
+ } else \
+ { \
+ rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) ERR_MUUSERECOV, 2, DB_LEN_STR(REG), \
+ ERR_TEXT, 2, LEN_AND_LIT("Run MUPIP JOURNAL RECOVER")); \
} \
}
@@ -202,6 +215,8 @@ error_def(ERR_SEMREMOVED);
* Parameters:
* standalone = TRUE => create semaphore to get standalone access
* standalone = FALSE => rundown shared memory
+ * Note: Currently there are no callers with standalone == FALSE other
+ * than MUPIP RUNDOWN.
* Return Value:
* TRUE for success
* FALSE for failure
@@ -211,7 +226,7 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone)
int status, save_errno, sopcnt, tsd_size, save_udi_semid = INVALID_SEMID, semop_res, stat_res, rc;
int csd_size;
char now_running[MAX_REL_NAME];
- boolean_t rc_cpt_removed = FALSE, sem_created = FALSE, sem_incremented = FALSE, is_gtm_shm;
+ boolean_t rc_cpt_removed = FALSE, sem_created = FALSE, is_gtm_shm;
boolean_t glob_sec_init, db_shm_in_sync, remove_shmid, no_shm_exists;
sgmnt_data_ptr_t csd, tsd = NULL;
sgmnt_addrs *csa;
@@ -226,14 +241,22 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone)
union semun semarg;
uint4 status_msg, ss_pid;
shm_snapshot_t *ss_shm_ptr;
- gtm_uint64_t sec_size;
+ gtm_uint64_t sec_size, mmap_sz = 0;
# ifdef GTM_CRYPT
gd_segment *seg;
int gtmcrypt_errno;
# endif
+ boolean_t override_present, wcs_flu_success, prevent_mu_rndwn;
+ unsigned char *fn;
+ mstr jnlfile;
+ int jnl_fd;
+ jnl_file_header header;
+ int4 status1;
+ uint4 status2;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
+ mu_rndwn_file_standalone = standalone;
restore_rndwn_gbl = FALSE;
assert(!jgbl.onlnrlbk);
assert(!mupip_jnl_recover || standalone);
@@ -250,7 +273,7 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone)
cs_addrs = csa; /* by gtm_putmsg(), so set it up here. */
if (SS_NORMAL != status)
{
- gtm_putmsg(VARLSTCNT(5) status, 2, DB_LEN_STR(reg), errno);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5) status, 2, DB_LEN_STR(reg), errno);
if (FD_INVALID != udi->fd) /* Since dbfilop failed, close udi->fd only if it was opened */
CLOSEFILE_RESET(udi->fd, rc); /* resets "udi->fd" to FD_INVALID */
return FALSE;
@@ -262,13 +285,13 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone)
*/
if (reg->read_only && !standalone)
{
- gtm_putmsg(VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(reg));
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(reg));
CLOSEFILE_RESET(udi->fd, rc); /* resets "udi->fd" to FD_INVALID */
return FALSE;
}
ESTABLISH_RET(mu_rndwn_file_ch, FALSE);
if (!ftok_sem_get(reg, TRUE, GTM_ID, !standalone))
- CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented);
+ CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented);
/* Now we have standalone access of the database using ftok semaphore. Any other ftok conflicted database suspends
* their operation at this point. At the end of this routine, we release ftok semaphore lock.
*/
@@ -278,7 +301,7 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone)
if (0 != status)
{
RNDWN_ERR("!AD -> Error reading from file.", reg);
- CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented);
+ CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented);
}
csa->hdr = tsd;
csa->region = gv_cur_region;
@@ -293,14 +316,14 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone)
{
seg = reg->dyn.addr;
GTMCRYPT_REPORT_ERROR(gtmcrypt_errno, gtm_putmsg, seg->fname_len, seg->fname);
- CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented);
+ CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented);
}
}
# endif
CSD2UDI(tsd, udi);
semarg.buf = &semstat;
- REMOVE_SEMID_IF_ORPHANED(reg, udi, tsd, sem_created, sem_incremented);
- if (INVALID_SEMID == udi->semid || (-1 == semctl(udi->semid, 0, IPC_STAT, semarg)) ||
+ REMOVE_SEMID_IF_ORPHANED(reg, udi, tsd, sem_created, udi->counter_acc_incremented);
+ if (INVALID_SEMID == udi->semid || (-1 == semctl(udi->semid, DB_CONTROL_SEM, IPC_STAT, semarg)) ||
# ifdef GTM64
(((tsd->gt_sem_ctime.ctime & 0xffffffff) == 0) && ((tsd->gt_sem_ctime.ctime >> 32) != semarg.buf->sem_ctime)) ||
# endif
@@ -312,7 +335,7 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone)
{
udi->semid = INVALID_SEMID;
RNDWN_ERR("!AD -> Error with semget with IPC_CREAT.", reg);
- CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented);
+ CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented);
}
sem_created = TRUE;
tsd->semid = udi->semid;
@@ -325,7 +348,7 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone)
if (-1 == semctl(udi->semid, FTOK_SEM_PER_ID - 1, SETVAL, semarg))
{
RNDWN_ERR("!AD -> Error with semctl with SETVAL.", reg);
- CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented);
+ CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented);
}
/*
* Warning: We must read the sem_ctime after SETVAL, which changes it.
@@ -336,7 +359,7 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone)
if (-1 == semctl(udi->semid, FTOK_SEM_PER_ID - 1, IPC_STAT, semarg))
{
RNDWN_ERR("!AD -> Error with semctl with IPC_STAT.", reg);
- CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented);
+ CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented);
}
udi->gt_sem_ctime = tsd->gt_sem_ctime.ctime = semarg.buf->sem_ctime;
}
@@ -352,10 +375,10 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone)
* specified in a single line. However, each of the 4 lines below represent "one" semaphore operation and hence an
* acceptible exception to the coding guidelines.
*/
- sop[0].sem_num = 0; sop[0].sem_op = 0; /* wait for access control semaphore to be available */
- sop[1].sem_num = 0; sop[1].sem_op = 1; /* lock it */
- sop[2].sem_num = 1; sop[2].sem_op = 0; /* wait for counter semaphore to become 0 */
- sop[3].sem_num = 1; sop[3].sem_op = 1; /* increment the counter semaphore */
+ sop[0].sem_num = DB_CONTROL_SEM; sop[0].sem_op = 0; /* wait for access control semaphore to be available */
+ sop[1].sem_num = DB_CONTROL_SEM; sop[1].sem_op = 1; /* lock it */
+ sop[2].sem_num = DB_COUNTER_SEM; sop[2].sem_op = 0; /* wait for counter semaphore to become 0 */
+ sop[3].sem_num = DB_COUNTER_SEM; sop[3].sem_op = 1; /* increment the counter semaphore */
# if defined(GTM64) && defined(BIGENDIAN)
/* If the shared memory was created by a 32-bit big-endian version of GT.M the correct ctime will be in the
* upper 32 bits and the lower 32 bits will be zero. Detect this case and adjust the time. We expect it to
@@ -389,20 +412,65 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone)
if (-1 == semop_res)
{
RNDWN_ERR("!AD -> File already open by another process.", reg);
- CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented);
+ CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented);
}
udi->grabbed_access_sem = TRUE;
- sem_incremented = no_shm_exists;
- /* Now rundown database if shared memory segment exists. We try this for both values of "standalone" */
+ udi->counter_acc_incremented = no_shm_exists;
+ override_present = (cli_present("OVERRIDE") == CLI_PRESENT);
+ /* Proceed with rundown if either journaling is off or we got here as a result of MUPIP JOURNAL -RECOVER or
+ * MUPIP JOURNAL -ROLLBACK, unless the OVERRIDE qualifier is present (see the following code).
+ */
+ prevent_mu_rndwn = JNL_ENABLED(tsd) && !standalone;
+ /* Now rundown database if shared memory segment exists. We try this for both values of 'standalone'. */
if (no_shm_exists)
- { /* No shared memory exists */
- assert(sem_incremented);
+ {
+ if (prevent_mu_rndwn)
+ {
+ if (override_present)
+ { /* If the rundown should normally be prevented, but the operator specified an OVERRIDE qualifier,
+ * record the fact of the usage in the syslog and continue.
+ */
+ send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) ERR_MURNDWNOVRD, 2, DB_LEN_STR(reg), ERR_TEXT, 2,
+ LEN_AND_LIT("Overriding enabled journaling state"));
+ } else
+ { /* Issue error if the crash bit in the journal file is set thereby preventing the user from doing a
+ * less appropriate operation than RECOVER or ROLLBACK.
+ */
+ jnlfile.addr = (char *)tsd->jnl_file_name;
+ jnlfile.len = tsd->jnl_file_len;
+ if (FILE_PRESENT & gtm_file_stat(&jnlfile, NULL, NULL, TRUE, &status2))
+ { /* The journal file exists. */
+ assert('\0' == jnlfile.addr[jnlfile.len]);
+ jnlfile.addr[jnlfile.len] = '\0'; /* In case the above assert fails. */
+ OPENFILE(jnlfile.addr, O_RDONLY, jnl_fd);
+ if (0 <= jnl_fd)
+ {
+ DO_FILE_READ(jnl_fd, 0, &header, SIZEOF(header), status1, status2);
+ if (SS_NORMAL == status1)
+ { /* FALSE in the call below is to skip gtm_putmsgs even on errors. */
+ CHECK_JNL_FILE_IS_USABLE(&header, status1, FALSE, 0, NULL);
+ if ((SS_NORMAL == status1)
+ && (ARRAYSIZE(header.data_file_name) > header.data_file_name_length))
+ {
+ assert('\0' == header.data_file_name[header.data_file_name_length]);
+ header.data_file_name[header.data_file_name_length] = '\0';
+ if (is_file_identical((char *)header.data_file_name,
+ (char *)gv_cur_region->dyn.addr->fname) && header.crash)
+ {
+ PRINT_PREVENT_RUNDOWN_MESSAGE(reg);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
if (rc_cpt_removed)
{ /* reset RC values if we've rundown the RC CPT */
/* attempt to force-write header */
tsd->rc_srv_cnt = tsd->dsid = tsd->rc_node = 0;
assert(FALSE); /* not sure what to do here. handle it if/when it happens */
- CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented);
+ CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented);
} else
{ /* Note that if creation time does not match, we ignore that shared memory segment. It might result in
* orphaned shared memory segment which can be later removed with argument-less MUPIP RUNDOWN.
@@ -419,7 +487,7 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone)
if (0 != status)
{
RNDWN_ERR("!AD -> Unable to write header to disk.", reg);
- CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented);
+ CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented);
}
} else
{
@@ -430,22 +498,22 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone)
if (!get_full_path((char *)DB_STR_LEN(reg), db_ipcs.fn, &db_ipcs.fn_len,
MAX_TRANS_NAME_LEN, &status_msg))
{
- gtm_putmsg(VARLSTCNT(1) status_msg);
+ gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(1) status_msg);
RNDWN_ERR("!AD -> get_full_path failed.", reg);
- CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented);
+ CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented);
}
db_ipcs.fn[db_ipcs.fn_len] = 0;
WAIT_FOR_REPL_INST_UNFREEZE_SAFE(csa);
if (0 != send_mesg2gtmsecshr(FLUSH_DB_IPCS_INFO, 0, (char *)NULL, 0))
{
RNDWN_ERR("!AD -> gtmsecshr was unable to write header to disk.", reg);
- CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented);
+ CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented);
}
}
if (!ftok_sem_release(reg, FALSE, FALSE))
{
RNDWN_ERR("!AD -> Error from ftok_sem_release.", reg);
- CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented);
+ CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented);
}
CLOSEFILE_RESET(udi->fd, rc); /* resets "udi->fd" to FD_INVALID */
REVERT;
@@ -454,18 +522,18 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone)
return TRUE; /* For "standalone" and "no shared memory existing", we exit here */
} else
{ /* We are here for not standalone (basically the "mupip rundown" command). */
- if (0 != do_semop(udi->semid, 0, -1, IPC_NOWAIT | SEM_UNDO))
+ if (0 != do_semop(udi->semid, DB_CONTROL_SEM, -1, IPC_NOWAIT | SEM_UNDO))
{
assert(FALSE); /* We incremented the semaphore, so we should be able to decrement it */
RNDWN_ERR("!AD -> Error decrementing semaphore.", reg);
- CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented);
+ CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented);
}
- sem_incremented = FALSE;
+ udi->counter_acc_incremented = FALSE;
if (sem_created && (0 != sem_rmid(udi->semid)))
{
assert(FALSE); /* We've created the semaphore, so we should be able to remove it */
RNDWN_ERR("!AD -> Error removing semaphore.", reg);
- CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented);
+ CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented);
}
sem_created = FALSE;
udi->grabbed_access_sem = FALSE;
@@ -481,7 +549,7 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone)
if (0 != status)
{
RNDWN_ERR("!AD -> Unable to write header to disk.", reg);
- CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented);
+ CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented);
}
CLOSEFILE_RESET(udi->fd, rc); /* resets "udi->fd" to FD_INVALID */
free(tsd);
@@ -496,17 +564,17 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone)
}
if (reg->read_only) /* read only process can't succeed beyond this point */
{
- gtm_putmsg(VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(reg));
- CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented);
+ gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(reg));
+ CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented);
}
/* Now we have a pre-existing shared memory section. Do some setup */
if (memcmp(tsd->label, GDS_LABEL, GDS_LABEL_SZ - 1))
{
if (memcmp(tsd->label, GDS_LABEL, GDS_LABEL_SZ - 3))
- gtm_putmsg(VARLSTCNT(4) ERR_DBNOTGDS, 2, DB_LEN_STR(reg));
+ gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_DBNOTGDS, 2, DB_LEN_STR(reg));
else
- gtm_putmsg(VARLSTCNT(4) ERR_BADDBVER, 2, DB_LEN_STR(reg));
- CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented);
+ gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_BADDBVER, 2, DB_LEN_STR(reg));
+ CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented);
}
reg->dyn.addr->acc_meth = acc_meth = tsd->acc_meth;
dbsecspc(reg, tsd, &sec_size);
@@ -529,8 +597,21 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone)
restore_rndwn_gbl = TRUE;
gv_cur_region = reg;
tp_change_reg();
- SEG_SHMATTACH(0, reg, udi, tsd, sem_created, sem_incremented);
+ SEG_SHMATTACH(0, reg, udi, tsd, sem_created, udi->counter_acc_incremented);
cs_addrs->nl = (node_local_ptr_t)cs_addrs->db_addrs[0];
+ if (prevent_mu_rndwn && cs_addrs->nl->jnl_file.u.inode)
+ {
+ if (override_present)
+ { /* If the rundown should normally be prevented, but the operator specified an OVERRIDE qualifier, record
+ * the fact of the usage in the syslog and continue.
+ */
+ send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) ERR_MURNDWNOVRD, 2, DB_LEN_STR(reg), ERR_TEXT, 2,
+ LEN_AND_LIT("Overriding OPEN journal file state in shared memory"));
+ } else
+ { /* Journal file state being still open in shared memory implies a crashed state, so error out. */
+ PRINT_PREVENT_RUNDOWN_MESSAGE(reg);
+ }
+ }
/* The following checks for GDS_LABEL_GENERIC, gtm_release_name, and cs_addrs->nl->glob_sec_init ensure that the
* shared memory under consideration is valid. First, since cs_addrs->nl->label is in the same place for every
* version, a failing check means it is most likely NOT a GT.M created shared memory, so no attempt will be
@@ -546,9 +627,9 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone)
memcpy(now_running, cs_addrs->nl->now_running, MAX_REL_NAME);
if (memcmp(now_running, gtm_release_name, gtm_release_name_len + 1))
{
- gtm_putmsg(VARLSTCNT(8) ERR_VERMISMATCH, 6, DB_LEN_STR(reg), gtm_release_name_len,
+ gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_VERMISMATCH, 6, DB_LEN_STR(reg), gtm_release_name_len,
gtm_release_name, LEN_AND_STR(now_running));
- CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented);
+ CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented);
}
if (cs_addrs->nl->glob_sec_init)
{
@@ -556,12 +637,12 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone)
if (memcmp(cs_addrs->nl->label, GDS_LABEL, GDS_LABEL_SZ - 1))
{
if (memcmp(cs_addrs->nl->label, GDS_LABEL, GDS_LABEL_SZ - 3))
- gtm_putmsg(VARLSTCNT(8) ERR_DBNOTGDS, 2, DB_LEN_STR(reg),
+ gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_DBNOTGDS, 2, DB_LEN_STR(reg),
ERR_TEXT, 2, RTS_ERROR_LITERAL("(from shared segment - nl)"));
else
- gtm_putmsg(VARLSTCNT(8) ERR_BADDBVER, 2, DB_LEN_STR(reg),
+ gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_BADDBVER, 2, DB_LEN_STR(reg),
ERR_TEXT, 2, RTS_ERROR_LITERAL("(from shared segment - nl)"));
- CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented);
+ CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented);
}
/* Since nl is memset to 0 initially and then fname is copied over from gv_cur_region and since "fname" is
* guaranteed to not exceed MAX_FN_LEN, we should have a terminating '\0' at least at
@@ -575,22 +656,24 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone)
{
save_errno = errno;
db_shm_in_sync = FALSE;
- if( ENOENT == save_errno)
+ if (ENOENT == save_errno)
{
- send_msg(VARLSTCNT(7) MAKE_MSG_INFO(ERR_DBNAMEMISMATCH), 4, DB_LEN_STR(reg),
- udi->shmid, cs_addrs->nl->fname, save_errno);
- gtm_putmsg(VARLSTCNT(6) MAKE_MSG_INFO(ERR_DBNAMEMISMATCH), 4, DB_LEN_STR(reg),
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(7) MAKE_MSG_INFO(ERR_DBNAMEMISMATCH), 4,
+ DB_LEN_STR(reg), udi->shmid, cs_addrs->nl->fname, save_errno);
+ gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(6) MAKE_MSG_INFO(ERR_DBNAMEMISMATCH), 4,
+ DB_LEN_STR(reg),
udi->shmid, cs_addrs->nl->fname);
/* In this case, the shared memory no longer points to a valid db file in the filesystem.
* So it is best that we remove this shmid. But remove_shmid is already TRUE. Assert that.
*/
assert(remove_shmid);
- }
- else /* Could be permission issue */
+ } else /* Could be permission issue */
{
- send_msg(VARLSTCNT(7) MAKE_MSG_INFO(ERR_DBNAMEMISMATCH), 4, DB_LEN_STR(reg),
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(7) MAKE_MSG_INFO(ERR_DBNAMEMISMATCH), 4,
+ DB_LEN_STR(reg),
udi->shmid, cs_addrs->nl->fname, save_errno);
- gtm_putmsg(VARLSTCNT(7) MAKE_MSG_INFO(ERR_DBNAMEMISMATCH), 4, DB_LEN_STR(reg),
+ gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(7) MAKE_MSG_INFO(ERR_DBNAMEMISMATCH), 4,
+ DB_LEN_STR(reg),
udi->shmid, cs_addrs->nl->fname, save_errno);
remove_shmid = FALSE; /* Shared memory might be pointing to valid database */
}
@@ -599,11 +682,11 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone)
{ /* Check if csa->nl->fname and csa->nl->dbfid are in sync. If not, then db & shm are not in sync */
if (FALSE == is_gdid_stat_identical(&cs_addrs->nl->unique_id.uid, &stat_buf))
{
- send_msg(VARLSTCNT(10) MAKE_MSG_INFO(ERR_DBIDMISMATCH), 4, cs_addrs->nl->fname,
- DB_LEN_STR(reg), udi->shmid, ERR_TEXT, 2,
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(10) MAKE_MSG_INFO(ERR_DBIDMISMATCH), 4,
+ cs_addrs->nl->fname, DB_LEN_STR(reg), udi->shmid, ERR_TEXT, 2,
LEN_AND_LIT("[MUPIP] Database filename and fileid in shared memory are not in sync"));
- gtm_putmsg(VARLSTCNT(10) MAKE_MSG_INFO(ERR_DBIDMISMATCH), 4, cs_addrs->nl->fname,
- DB_LEN_STR(reg), udi->shmid, ERR_TEXT, 2,
+ gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(10) MAKE_MSG_INFO(ERR_DBIDMISMATCH), 4,
+ cs_addrs->nl->fname, DB_LEN_STR(reg), udi->shmid, ERR_TEXT, 2,
LEN_AND_LIT("[MUPIP] Database filename and fileid in shared memory are not in sync"));
db_shm_in_sync = FALSE;
/* In this case, the shared memory points to a file that exists in the filesystem but
@@ -622,13 +705,14 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone)
*/
if (db_shm_in_sync && !is_file_identical((char *)cs_addrs->nl->fname, (char *)reg->dyn.addr->fname))
{
- send_msg(VARLSTCNT(6) MAKE_MSG_INFO(ERR_DBSHMNAMEDIFF), 4, DB_LEN_STR(reg),
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(6) MAKE_MSG_INFO(ERR_DBSHMNAMEDIFF), 4, DB_LEN_STR(reg),
udi->shmid, cs_addrs->nl->fname);
- gtm_putmsg(VARLSTCNT(6) MAKE_MSG_INFO(ERR_DBSHMNAMEDIFF), 4, DB_LEN_STR(reg),
+ gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(6) MAKE_MSG_INFO(ERR_DBSHMNAMEDIFF), 4, DB_LEN_STR(reg),
udi->shmid, cs_addrs->nl->fname);
db_shm_in_sync = FALSE;
remove_shmid = FALSE;
}
+ wcs_flu_success = TRUE;
/* If db & shm are not in sync at this point, skip the part of flushing shm to db file on disk.
* We still need to reset the fields (shmid, semid etc.) in db file header.
* About deleting the shmid, it depends on the type of out-of-sync between db & shm. This is handled
@@ -636,7 +720,7 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone)
*/
if (db_shm_in_sync)
{
- if (!sem_incremented)
+ if (!udi->counter_acc_incremented)
{ /* Now that we have ensured db & shm are in sync and will be doing the "actual"
* rundown, we need to ensure that no one is attached to the database (counter
* sempahore is 0)
@@ -650,16 +734,16 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone)
if (-1 == semop_res)
{
RNDWN_ERR("!AD -> File already open by another process.", reg);
- CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented);
+ CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented);
}
- sem_incremented = TRUE;
+ udi->counter_acc_incremented = TRUE;
}
/* If db & shm are in sync AND we aren't alone in using it, we can do nothing */
if (0 != shm_buf.shm_nattch)
{
util_out_print("!AD [!UL]-> File is in use by another process.",
TRUE, DB_LEN_STR(reg), udi->shmid);
- CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented);
+ CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented);
}
/* The shared section is valid and up-to-date with respect to the database file header;
* ignore the temporary storage and use the shared section from here on
@@ -670,26 +754,34 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone)
assert(0 == ((INTPTR_T)cs_addrs->critical & (CACHELINE_SIZE - 1)));
# endif
JNL_INIT(cs_addrs, reg, tsd);
- cs_addrs->shmpool_buffer = (shmpool_buff_hdr_ptr_t)(cs_addrs->db_addrs[0] + NODE_LOCAL_SPACE +
+ cs_addrs->shmpool_buffer = (shmpool_buff_hdr_ptr_t)(cs_addrs->db_addrs[0] + NODE_LOCAL_SPACE(tsd) +
JNL_SHARE_SIZE(tsd));
cs_addrs->lock_addrs[0] = (sm_uc_ptr_t)cs_addrs->shmpool_buffer + SHMPOOL_SECTION_SIZE;
cs_addrs->lock_addrs[1] = cs_addrs->lock_addrs[0] + LOCK_SPACE_SIZE(tsd) - 1;
-
if (dba_bg == acc_meth)
- cs_data = csd = cs_addrs->hdr = (sgmnt_data_ptr_t)(cs_addrs->lock_addrs[1] + 1 +
- CACHE_CONTROL_SIZE(tsd));
- else
{
- cs_addrs->acc_meth.mm.mmblk_state = (mmblk_que_heads_ptr_t)(cs_addrs->lock_addrs[1] + 1);
+ cs_data = csd = csa->hdr = (sgmnt_data_ptr_t)(cs_addrs->lock_addrs[1] + 1
+ + CACHE_CONTROL_SIZE(tsd));
+ assert(csa->nl->cache_off == -CACHE_CONTROL_SIZE(csd));
+ db_csh_ini(csa);
+ } else
+ {
+ cs_data = csd = csa->hdr = (sgmnt_data_ptr_t)((sm_uc_ptr_t)csa->lock_addrs[1] + 1);
FSTAT_FILE(udi->fd, &stat_buf, stat_res);
if (-1 == stat_res)
{
RNDWN_ERR("!AD -> Error with fstat.", reg);
- CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented);
+ CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented);
+ }
+ mmap_sz = stat_buf.st_size - BLK_ZERO_OFF(csd);
+ CHECK_LARGEFILE_MMAP(reg, mmap_sz); /* can issue rts_error MMFILETOOLARGE */
+ cs_addrs->db_addrs[0] = (sm_uc_ptr_t) MMAP_FD(udi->fd, mmap_sz, BLK_ZERO_OFF(csd), FALSE);
+ if (-1 == (sm_long_t)(cs_addrs->db_addrs[0]))
+ {
+ RNDWN_ERR("!AD -> Error mapping memory", reg);
+ CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented);
}
- SEG_MEMMAP(NULL, reg, udi, tsd, sem_created, sem_incremented);
- cs_data = csd = cs_addrs->hdr = (sgmnt_data_ptr_t)cs_addrs->db_addrs[0];
- cs_addrs->db_addrs[1] = cs_addrs->db_addrs[0] + stat_buf.st_size - 1;
+ cs_addrs->db_addrs[1] = cs_addrs->db_addrs[0] + mmap_sz - 1;
}
assert(sem_created ||
((csd->semid == tsd->semid) && (csd->gt_sem_ctime.ctime == tsd->gt_sem_ctime.ctime)));
@@ -711,28 +803,25 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone)
{
status_msg = ERR_DBNOTGDS;
if (0 != shm_rmid(udi->shmid))
- gtm_putmsg(VARLSTCNT(8) ERR_DBFILERR, 2, DB_LEN_STR(reg),
+ gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_DBFILERR, 2, DB_LEN_STR(reg),
ERR_TEXT, 2, RTS_ERROR_TEXT("Error removing shared memory"));
else
{
- gtm_putmsg(VARLSTCNT(5) ERR_SHMREMOVED, 3, udi->shmid, DB_LEN_STR(reg));
- send_msg(VARLSTCNT(5) ERR_SHMREMOVED, 3, udi->shmid, DB_LEN_STR(reg));
+ gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_SHMREMOVED, 3, udi->shmid,
+ DB_LEN_STR(reg));
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_SHMREMOVED, 3, udi->shmid,
+ DB_LEN_STR(reg));
}
} else
status_msg = ERR_BADDBVER;
- gtm_putmsg(VARLSTCNT(8) status_msg, 2, DB_LEN_STR(reg),
+ gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(8) status_msg, 2, DB_LEN_STR(reg),
ERR_TEXT, 2, RTS_ERROR_LITERAL("(File header in the shared segment seems corrupt)"));
- CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented);
+ CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented);
}
- if (dba_bg == acc_meth)
- db_csh_ini(cs_addrs);
- else
- cs_addrs->acc_meth.mm.base_addr = (sm_uc_ptr_t)((sm_ulong_t)csd + (int)(csd->start_vbn - 1)
- * DISK_BLOCK_SIZE);
db_common_init(reg, cs_addrs, csd); /* do initialization common to "db_init" and "mu_rndwn_file" */
/* cleanup mutex stuff */
cs_addrs->hdr->image_count = 0;
- gtm_mutex_init(reg, NUM_CRIT_ENTRY, FALSE); /* it is ensured, this is the only process running */
+ gtm_mutex_init(reg, NUM_CRIT_ENTRY(cs_addrs->hdr), FALSE); /* this is the only process running */
assert(!cs_addrs->hold_onto_crit); /* so it is safe to do unconditional grab_crit/rel_crit below */
cs_addrs->nl->in_crit = 0;
cs_addrs->now_crit = FALSE;
@@ -777,8 +866,32 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone)
* So, a new process will switch the journal file and cut the journal file link,
* though it might be a good journal without an EOF
*/
- wcs_flu(WCSFLU_NONE);
- csd = cs_addrs->hdr;
+ wcs_flu_success = wcs_flu(WCSFLU_NONE);
+ if (!wcs_flu_success)
+ {
+ if (override_present && !standalone)
+ { /* Case of MUPIP RUNDOWN with OVERRIDE flag; continue. */
+ send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) ERR_MURNDWNOVRD, 2,
+ DB_LEN_STR(reg), ERR_TEXT, 2, LEN_AND_LIT(
+ "Overriding error during database block flush"));
+ csd = cs_addrs->hdr;
+ } else
+ { /* In case of MUPIP RUNDOWN append a suggestion to use OVERRIDE flag
+ * to bypass the error.
+ */
+ if (standalone)
+ rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(4)
+ ERR_JNLORDBFLU, 2, DB_LEN_STR(reg));
+ else
+ rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(8)
+ ERR_JNLORDBFLU, 2, DB_LEN_STR(reg),
+ ERR_TEXT, 2, LEN_AND_LIT(
+ "To force the operation to proceed, use the "
+ "OVERRIDE qualifier"));
+ assert(FALSE); /* The above rts_error should not return. */
+ return FALSE;
+ }
+ }
}
jpc = cs_addrs->jnl;
if (NULL != jpc)
@@ -808,45 +921,52 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone)
csd_size = tsd_size; /* SIZEOF(sgmnt_data) */
}
reg->open = FALSE;
- /* Note: At this point we have write permission */
- memset(csd->machine_name, 0, MAX_MCNAMELEN);
- if (!mupip_jnl_recover)
- csd->freeze = 0;
- RESET_SHMID_CTIME(csd);
- if (!standalone)
- { /* Invalidate semid in the file header as part of rundown. The actual semaphore still
- * exists and we'll remove that just before releasing the ftok semaphore. However, if the
- * MUPIP RUNDOWN command gets killed AFTER we write the file header but BEFORE we remove
- * the semaphore from the system, we can have an orphaned semaphore. But, this is okay
- * since an arugment-less MUPIP RUNDOWN, if invoked, will remove those orphaned semaphores
- */
- RESET_SEMID_CTIME(csd);
- }
- if (!db_shm_in_sync || (dba_bg == acc_meth))
- {
+ /* If wcs_flu returned FALSE, it better be because of MUPIP RUNDOWN run with OVERRIDE qualifier. */
+ assert(wcs_flu_success || (override_present && !standalone));
+ /* In case MUPIP RUNDOWN is invoked with OVERRIDE qualifier and we ignored a FALSE return from wcs_flu, do
+ * not update the database header, thus forcing the operator to either use a ROLLBACK/RECOVER or supply the
+ * OVERRIDE qualifier with RUNDOWN before GT.M could again be used to access the database.
+ */
+ if (wcs_flu_success)
+ { /* Note: At this point we have write permission */
+ memset(csd->machine_name, 0, MAX_MCNAMELEN);
+ if (!mupip_jnl_recover)
+ csd->freeze = 0;
+ RESET_SHMID_CTIME(csd);
+ if (!standalone)
+ { /* Invalidate semid in the file header as part of rundown. The actual semaphore still
+ * exists and we'll remove that just before releasing the ftok semaphore. However, if the
+ * MUPIP RUNDOWN command gets killed AFTER we write the file header but BEFORE we remove
+ * the semaphore from the system, we can have an orphaned semaphore. But, this is okay
+ * since an arugment-less MUPIP RUNDOWN, if invoked, will remove those orphaned semaphores
+ */
+ RESET_SEMID_CTIME(csd);
+ }
DB_LSEEKWRITE(csa, udi->fn, udi->fd, (off_t)0, csd, csd_size, status);
if (0 != status)
{
RNDWN_ERR("!AD -> Error writing header to disk.", reg);
- CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented);
- }
- if (NULL != tsd)
- {
- assert(!db_shm_in_sync);
- free(tsd);
- tsd = NULL;
+ CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented);
}
- } else
+ }
+ if (NULL != tsd)
+ {
+ assert(!db_shm_in_sync);
+ free(tsd);
+ tsd = NULL;
+ }
+ if (dba_mm == acc_meth)
{
- if (-1 == msync((caddr_t)cs_addrs->db_addrs[0], (size_t)stat_buf.st_size, MS_SYNC))
+ assert(0 != mmap_sz);
+ if (-1 == msync((caddr_t)cs_addrs->db_addrs[0], mmap_sz, MS_SYNC))
{
RNDWN_ERR("!AD -> Error synchronizing mapped memory.", reg);
- CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented);
+ CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented);
}
- if (-1 == munmap((caddr_t)cs_addrs->db_addrs[0], (size_t)stat_buf.st_size))
+ if (-1 == munmap((caddr_t)cs_addrs->db_addrs[0], mmap_sz))
{
RNDWN_ERR("!AD -> Error unmapping mapped memory.", reg);
- CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented);
+ CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented);
}
}
} else
@@ -861,7 +981,7 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone)
{
assert(FALSE);
RNDWN_ERR("!AD -> Error detaching from shared memory.", reg);
- CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented);
+ CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented);
}
cs_addrs->nl = NULL;
/* Remove the shared memory only if it is a GT.M created one. */
@@ -871,13 +991,17 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone)
{
if (0 != shm_rmid(udi->shmid))
{
- assert(FALSE);
- RNDWN_ERR("!AD -> Error removing shared memory.", reg);
- CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented);
+ save_errno = errno;
+ if ((EINVAL != save_errno) && (EIDRM != save_errno))
+ {
+ assert(FALSE);
+ RNDWN_ERR("!AD -> Error removing shared memory.", reg);
+ CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented);
+ }
} else
{
- gtm_putmsg(VARLSTCNT(5) ERR_SHMREMOVED, 3, udi->shmid, DB_LEN_STR(reg));
- send_msg(VARLSTCNT(5) ERR_SHMREMOVED, 3, udi->shmid, DB_LEN_STR(reg));
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SHMREMOVED, 3, udi->shmid, DB_LEN_STR(reg));
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_SHMREMOVED, 3, udi->shmid, DB_LEN_STR(reg));
}
}
udi->shmid = INVALID_SHMID;
@@ -897,7 +1021,7 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone)
if (0 != status)
{
RNDWN_ERR("!AD -> Unable to write header to disk.", reg);
- CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented);
+ CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented);
}
free(tsd);
tsd = NULL;
@@ -905,25 +1029,19 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone)
assert(INVALID_SHMID == udi->shmid);
assert(0 == udi->gt_shm_ctime);
assert(udi->grabbed_access_sem);
- assert(!db_shm_in_sync || sem_incremented);
+ assert(!db_shm_in_sync || udi->counter_acc_incremented);
assert(INVALID_SEMID != udi->semid);
if (!standalone && (db_shm_in_sync || sem_created))
- { /* need to release the access control semaphore */
- if (0 != do_semop(udi->semid, 0, -1, IPC_NOWAIT | SEM_UNDO))
- {
- assert(FALSE); /* We incremented the semaphore, so we should be able to decrement it */
- RNDWN_ERR("!AD -> Error decrementing semaphore.", reg);
- CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented);
- }
- sem_incremented = FALSE;
+ {
if (0 != sem_rmid(udi->semid))
{
assert(FALSE); /* We've created the semaphore, so we should be able to remove it */
RNDWN_ERR("!AD -> Error removing semaphore.", reg);
- CLNUP_AND_RETURN(reg, udi, tsd, sem_created, sem_incremented);
+ CLNUP_AND_RETURN(reg, udi, tsd, sem_created, udi->counter_acc_incremented);
}
sem_created = FALSE;
udi->grabbed_access_sem = FALSE;
+ udi->counter_acc_incremented = FALSE;
udi->semid = INVALID_SEMID;
}
REVERT;
@@ -935,7 +1053,8 @@ boolean_t mu_rndwn_file(gd_region *reg, boolean_t standalone)
*/
if (!ftok_sem_release(reg, !standalone, !standalone))
return FALSE;
- assert(!standalone || udi->grabbed_access_sem); /* if "standalone" we better leave this function with standalone access */
+ /* if "standalone" we better leave this function with standalone access */
+ assert(!standalone || udi->grabbed_access_sem);
CLOSEFILE_RESET(udi->fd, rc); /* resets "udi->fd" to FD_INVALID */
DEBUG_ONLY(in_mu_rndwn_file = FALSE);
return TRUE;
@@ -947,11 +1066,7 @@ CONDITION_HANDLER(mu_rndwn_file_ch)
sgmnt_addrs *csa;
START_CH;
- /* The mu_rndwn_file_ch was introduced in revision 1.54 to account for the ERR_DBIDMISMATCH rts_error that no longer
- * exists. So, it is not expected that mu_rndwn_file_ch will ever be called. Add an assert(FALSE). If the assert does
- * not trip after an year or two, we can remove this condition handler altogether. 2010/07
- */
- assert(FALSE);
+ PRN_ERROR;
assert(NULL != rundown_reg);
if (NULL != rundown_reg)
{
@@ -966,5 +1081,15 @@ CONDITION_HANDLER(mu_rndwn_file_ch)
{
RESET_GV_CUR_REGION;
}
- NEXTCH;
+ rundown_reg->open = FALSE;
+ /* We want to proceed to the next condition handler in case we have stand-alone access, because if an error happens on one
+ * region, we should signal an issue and not proceed to the next region. Otherwise, we try to rundown the next region.
+ */
+ if (mu_rndwn_file_standalone)
+ {
+ NEXTCH;
+ } else
+ {
+ UNWIND(NULL, NULL);
+ }
}
diff --git a/sr_unix/mu_rndwn_repl_instance.c b/sr_unix/mu_rndwn_repl_instance.c
index be25785..b16b1de 100644
--- a/sr_unix/mu_rndwn_repl_instance.c
+++ b/sr_unix/mu_rndwn_repl_instance.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -282,7 +282,7 @@ boolean_t mu_rndwn_repl_instance(replpool_identifier *replpool_id, boolean_t imm
assert(INVALID_SEMID != sem_id);
if (!mur_options.rollback)
{ /* Invoked by MUPIP RUNDOWN in which case the semaphores needs to be removed. But, remove the
- * semaphore ONLY if we created it here OR the journal pool was successfully removed.
+ * semaphore ONLY if we created it here OR the receive pool was successfully removed.
*/
if ((sem_created || (SS_NORMAL == recvpool_stat))
&& (SS_NORMAL == mu_replpool_release_sem(&repl_instance, RECVPOOL_SEGMENT, TRUE)))
@@ -315,7 +315,7 @@ boolean_t mu_rndwn_repl_instance(replpool_identifier *replpool_id, boolean_t imm
START_HEARTBEAT_IF_NEEDED;
mutex_per_process_init();
if (!was_crit)
- grab_lock(jnlpool.jnlpool_dummy_reg, GRAB_LOCK_ONLY);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, GRAB_LOCK_ONLY);
}
repl_inst_recvpool_reset();
if ((NULL != jnlpool_ctl) && !was_crit)
@@ -333,7 +333,7 @@ boolean_t mu_rndwn_repl_instance(replpool_identifier *replpool_id, boolean_t imm
* skip the ones that are present in the ignore list.
*/
assert((sem_created || (SS_NORMAL == recvpool_stat)) || holds_sem[RECV][RECV_POOL_ACCESS_SEM]);
- holds_sem[RECV][RECV_POOL_ACCESS_SEM] = FALSE;
+ DEBUG_ONLY(set_sem_set_recvr(sem_id));
}
} else if (rndwn_both_pools && (INVALID_SHMID != shm_id))
{
diff --git a/sr_unix/mu_rndwn_replpool.c b/sr_unix/mu_rndwn_replpool.c
index 24ba16b..ae3cad7 100644
--- a/sr_unix/mu_rndwn_replpool.c
+++ b/sr_unix/mu_rndwn_replpool.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -151,8 +151,8 @@ int mu_rndwn_replpool(replpool_identifier *replpool_id, repl_inst_hdr_ptr_t rep
LEN_AND_STR(replpool_id->now_running), shm_id, LEN_AND_STR(instfilename));
DETACH_AND_RETURN(start_addr, shm_id, instfilename);
}
- /* Assert that if we haven't yet attached to the journal pool yet, we have the corresponding global vars set to NULL */
- assert((JNLPOOL_SEGMENT != pool_type) || ((NULL == jnlpool.jnlpool_ctl) && (NULL == jnlpool_ctl)));
+ /* Assert that if we haven't yet attached to the journal pool yet, jnlpool_ctl better be NULL */
+ assert((JNLPOOL_SEGMENT != pool_type) || (NULL == jnlpool.jnlpool_ctl));
if (JNLPOOL_SEGMENT == pool_type)
{ /* Initialize variables to simulate a "jnlpool_init". This is required by "repl_inst_flush_jnlpool" called below */
jnlpool_ctl = jnlpool.jnlpool_ctl = (jnlpool_ctl_ptr_t)start_addr;
@@ -160,7 +160,7 @@ int mu_rndwn_replpool(replpool_identifier *replpool_id, repl_inst_hdr_ptr_t rep
udi = FILE_INFO(jnlpool.jnlpool_dummy_reg);
csa = &udi->s_addrs;
csa->critical = (mutex_struct_ptr_t)((sm_uc_ptr_t)jnlpool.jnlpool_ctl + JNLPOOL_CTL_SIZE);
- csa->nl = (node_local_ptr_t)((sm_uc_ptr_t)csa->critical + CRIT_SPACE + SIZEOF(mutex_spin_parms_struct));
+ csa->nl = (node_local_ptr_t)((sm_uc_ptr_t)csa->critical + JNLPOOL_CRIT_SPACE + SIZEOF(mutex_spin_parms_struct));
/* secshr_db_clnup uses this relationship */
assert(jnlpool.jnlpool_ctl->filehdr_off);
assert(jnlpool.jnlpool_ctl->srclcl_array_off > jnlpool.jnlpool_ctl->filehdr_off);
@@ -191,7 +191,7 @@ int mu_rndwn_replpool(replpool_identifier *replpool_id, repl_inst_hdr_ptr_t rep
assert(!jnlpool.repl_inst_filehdr->crash || anticipatory_freeze_available);
/* Refresh local copy (repl_inst_filehdr) with the copy that was just flushed (jnlpool.repl_inst_filehdr) */
memcpy(repl_inst_filehdr, jnlpool.repl_inst_filehdr, SIZEOF(repl_inst_hdr));
- if (!anticipatory_freeze_available)
+ if (!anticipatory_freeze_available || argumentless_rundown)
{ /* Now that jnlpool has been flushed and there is going to be no journal pool, reset
* "jnlpool.repl_inst_filehdr" as otherwise other routines (e.g. "repl_inst_recvpool_reset") are
* affected by whether this is NULL or not.
@@ -205,7 +205,7 @@ int mu_rndwn_replpool(replpool_identifier *replpool_id, repl_inst_hdr_ptr_t rep
}
} /* else we are ONLINE ROLLBACK. repl_inst_flush_jnlpool will be done later after gvcst_init in mur_open_files */
}
- if ((0 == nattch) && (!anticipatory_freeze_available || (RECVPOOL_SEGMENT == pool_type)))
+ if ((0 == nattch) && (!anticipatory_freeze_available || argumentless_rundown || (RECVPOOL_SEGMENT == pool_type)))
{
if (-1 == shmdt((caddr_t)start_addr))
{
@@ -227,6 +227,11 @@ int mu_rndwn_replpool(replpool_identifier *replpool_id, repl_inst_hdr_ptr_t rep
{
repl_inst_filehdr->recvpool_shmid = INVALID_SHMID;
repl_inst_filehdr->recvpool_shmid_ctime = 0;
+ if (NULL != jnlpool.repl_inst_filehdr)
+ {
+ jnlpool.repl_inst_filehdr->recvpool_shmid = INVALID_SHMID;
+ jnlpool.repl_inst_filehdr->recvpool_shmid_ctime = 0;
+ }
*ipc_rmvd = TRUE;
}
} else
diff --git a/sr_unix/mu_size_scan.c b/sr_unix/mu_size_scan.c
index 747db44..0f7d96d 100644
--- a/sr_unix/mu_size_scan.c
+++ b/sr_unix/mu_size_scan.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2012 Fidelity Information Services, Inc *
+ * Copyright 2012, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -344,6 +344,7 @@ enum cdb_sc read_block(block_id nBlkId, sm_uc_ptr_t *pBlkBase_ptr, int *nLevl_pt
}
pCurr->cse = NULL;
pCurr->blk_num = nBlkId;
+ pCurr->buffaddr = pBlkBase;
pCurr->tn = tn;
pCurr->cycle = cycle;
pCurr->cr = cr;
diff --git a/sr_unix/mu_swap_root.c b/sr_unix/mu_swap_root.c
index a958d77..4043154 100644
--- a/sr_unix/mu_swap_root.c
+++ b/sr_unix/mu_swap_root.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2012 Fidelity Information Services, Inc *
+ * Copyright 2012, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -115,9 +115,6 @@ boolean_t mu_swap_root(mval *gn, int *root_swap_statistic_ptr)
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
- csd = cs_data;
- csa = cs_addrs;
- cnl = csa->nl;
assert(mu_reorg_process);
gv_target->root = 0;
gv_target->clue.end = 0;
@@ -127,15 +124,23 @@ boolean_t mu_swap_root(mval *gn, int *root_swap_statistic_ptr)
# ifdef GTM_TRIGGER
if (IS_MNAME_HASHT_GBLNAME(gn->str))
{ /* Initialize ^#t global for this region. */
+ csa = cs_addrs; /* needed for SETUP_TRIGGER_GLOBAL and INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED macros */
SETUP_TRIGGER_GLOBAL;
INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
DBG_CHECK_GVTARGET_GVCURRKEY_IN_SYNC(CHECK_CSA_TRUE);
+ if (0 == gv_target->root)
+ return TRUE;
} else
# endif /* Initialization for current global */
op_gvname(VARLSTCNT(1) (gn));
+ csa = cs_addrs;
+ cnl = csa->nl;
+ csd = cs_data; /* Be careful to keep csd up to date. With MM, cs_data can change, and
+ * dereferencing an older copy can result in a SIG-11.
+ */
if (0 == gv_target->root)
{ /* Global does not exist (online rollback). No problem. */
- gtm_putmsg(VARLSTCNT(4) ERR_GBLNOEXIST, 2, gn->str.len, gn->str.addr);
+ gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_GBLNOEXIST, 2, gn->str.len, gn->str.addr);
return TRUE;
}
if (dba_mm == csd->acc_meth)
@@ -200,7 +205,7 @@ boolean_t mu_swap_root(mval *gn, int *root_swap_statistic_ptr)
ABORT_TRANS_IF_GBL_EXIST_NOMORE(lcl_t_tries, tn_aborted);
if (tn_aborted)
{ /* It is not an error if the global (that once existed) doesn't exist anymore (due to ROLLBACK) */
- gtm_putmsg(VARLSTCNT(4) ERR_GBLNOEXIST, 2, gn->str.len, gn->str.addr);
+ gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_GBLNOEXIST, 2, gn->str.len, gn->str.addr);
return TRUE;
}
continue;
@@ -263,12 +268,15 @@ boolean_t mu_swap_root(mval *gn, int *root_swap_statistic_ptr)
if (!csa->now_crit)
WAIT_ON_INHIBIT_KILLS(cnl, MAXWAIT2KILL);
DEBUG_ONLY(lcl_t_tries = t_tries);
+ TREF(in_mu_swap_root_state) = MUSWP_DIRECTORY_SWAP;
if ((trans_num)0 == (ret_tn = t_end(dir_hist_ptr, NULL, TN_NOT_SPECIFIED)))
{
+ TREF(in_mu_swap_root_state) = MUSWP_NONE;
need_kip_incr = FALSE;
assert(NULL == kip_csa);
continue;
}
+ TREF(in_mu_swap_root_state) = MUSWP_NONE;
gvcst_kill_sort(&kill_set_list);
TREF(in_mu_swap_root_state) = MUSWP_FREE_BLK;
GVCST_BMP_MARK_FREE(&kill_set_list, ret_tn, inctn_mu_reorg, inctn_bmp_mark_free_mu_reorg,
@@ -338,6 +346,13 @@ block_id swap_root_or_directory_block(int parent_blk_lvl, int child_blk_lvl, src
t_retry(cdb_sc_badbitmap);
return RETRY_SWAP;
}
+ if (child_blk_id <= free_blk_id)
+ { /* stop swapping root or DT blocks once the database is truncated well enough. A good heuristic for this is to check
+ * if the block is to be swapped into a higher block number and if so do not swap
+ */
+ t_abort(gv_cur_region, csa);
+ return ABORT_SWAP;
+ }
/* ====== begin update array ======
* Four blocks get changed.
* 1. Free block becomes busy and gains the contents of child (root block/directory tree block)
@@ -348,12 +363,15 @@ block_id swap_root_or_directory_block(int parent_blk_lvl, int child_blk_lvl, src
parent_blk_ptr = dir_hist_ptr->h[parent_blk_lvl].buffaddr; /* parent_blk_lvl is 0 iff we're moving a gvt root block */
parent_blk_id = dir_hist_ptr->h[parent_blk_lvl].blk_num;
CHECK_AND_RESET_UPDATE_ARRAY;
- freeblkhist.blk_num = (block_id)free_blk_id;
- if (NULL == (freeblkhist.buffaddr = t_qread(free_blk_id, (sm_int_ptr_t)&freeblkhist.cycle, &freeblkhist.cr)))
- {
- assert(t_tries < CDB_STAGNATE);
- t_retry((enum cdb_sc)rdfail_detail);
- return RETRY_SWAP;
+ if (free_blk_recycled)
+ { /* Otherwise, it's a completely free block, in which case no need to read. */
+ freeblkhist.blk_num = (block_id)free_blk_id;
+ if (NULL == (freeblkhist.buffaddr = t_qread(free_blk_id, (sm_int_ptr_t)&freeblkhist.cycle, &freeblkhist.cr)))
+ {
+ assert(t_tries < CDB_STAGNATE);
+ t_retry((enum cdb_sc)rdfail_detail);
+ return RETRY_SWAP;
+ }
}
child_blk_size = ((blk_hdr_ptr_t)child_blk_ptr)->bsiz;
BLK_INIT(bs_ptr, bs1);
diff --git a/sr_unix/mu_truncate.c b/sr_unix/mu_truncate.c
index c8bafdf..771a13c 100644
--- a/sr_unix/mu_truncate.c
+++ b/sr_unix/mu_truncate.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2012 Fidelity Information Services, Inc *
+ * Copyright 2012, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -147,17 +147,17 @@ boolean_t mu_truncate(int4 truncate_percent)
csd = cs_data;
if (dba_mm == csd->acc_meth)
{
- gtm_putmsg(VARLSTCNT(4) ERR_MUTRUNCNOTBG, 2, REG_LEN_STR(gv_cur_region));
+ gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_MUTRUNCNOTBG, 2, REG_LEN_STR(gv_cur_region));
return TRUE;
}
if ((GDSVCURR != csd->desired_db_format) || (csd->blks_to_upgrd != 0))
{
- gtm_putmsg(VARLSTCNT(4) ERR_MUTRUNCNOV4, 2, REG_LEN_STR(gv_cur_region));
+ gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_MUTRUNCNOV4, 2, REG_LEN_STR(gv_cur_region));
return TRUE;
}
if (csa->ti->free_blocks < (truncate_percent * csa->ti->total_blks / 100))
{
- gtm_putmsg(VARLSTCNT(5) ERR_MUTRUNCNOSPACE, 3, REG_LEN_STR(gv_cur_region), truncate_percent);
+ gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_MUTRUNCNOSPACE, 3, REG_LEN_STR(gv_cur_region), truncate_percent);
return TRUE;
}
/* already checked for parallel truncates on this region --- see mupip_reorg.c */
@@ -182,7 +182,8 @@ boolean_t mu_truncate(int4 truncate_percent)
assert(csa->ti->total_blks >= old_total); /* otherwise, a concurrent truncate happened... */
if (csa->ti->total_blks != old_total) /* Extend (likely called by mupip extend) -- don't truncate */
{
- gtm_putmsg(VARLSTCNT(5) ERR_MUTRUNCNOSPACE, 3, REG_LEN_STR(gv_cur_region), truncate_percent);
+ gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_MUTRUNCNOSPACE, 3, REG_LEN_STR(gv_cur_region),
+ truncate_percent);
return TRUE;
}
lmap_blk_num = lmap_num * BLKS_PER_LMAP;
@@ -315,13 +316,14 @@ boolean_t mu_truncate(int4 truncate_percent)
if (!wcs_flu(WCSFLU_FLUSH_HDR | WCSFLU_WRITE_EPOCH | WCSFLU_MSYNC_DB))
{
assert(FALSE);
- gtm_putmsg(VARLSTCNT(6) ERR_BUFFLUFAILED, 4, LEN_AND_LIT("MUPIP REORG TRUNCATE"), DB_LEN_STR(gv_cur_region));
+ gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_BUFFLUFAILED, 4, LEN_AND_LIT("MUPIP REORG TRUNCATE"),
+ DB_LEN_STR(gv_cur_region));
rel_crit(gv_cur_region);
return FALSE;
}
csa->nl->highest_lbm_with_busy_blk = MAX(found_busy_blk, csa->nl->highest_lbm_with_busy_blk);
- assert(csa->nl->highest_lbm_with_busy_blk % BLKS_PER_LMAP == 0); /* should be a bitmap block */
- new_total = MIN(old_total, csa->nl->highest_lbm_with_busy_blk + BLKS_PER_LMAP);
+ assert(IS_BITMAP_BLK(csa->nl->highest_lbm_with_busy_blk));
+ new_total = MIN(old_total, csa->nl->highest_lbm_with_busy_blk + BLKS_PER_LMAP);
if (mu_ctrly_occurred || mu_ctrlc_occurred)
{
rel_crit(gv_cur_region);
@@ -329,22 +331,22 @@ boolean_t mu_truncate(int4 truncate_percent)
} else if (csa->ti->total_blks != old_total || new_total == old_total)
{
assert(csa->ti->total_blks >= old_total); /* Better have been an extend, not a truncate... */
- gtm_putmsg(VARLSTCNT(5) ERR_MUTRUNCNOSPACE, 3, REG_LEN_STR(gv_cur_region), truncate_percent);
+ gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_MUTRUNCNOSPACE, 3, REG_LEN_STR(gv_cur_region), truncate_percent);
rel_crit(gv_cur_region);
return TRUE;
} else if (GDSVCURR != csd->desired_db_format || csd->blks_to_upgrd != 0 || !csd->fully_upgraded)
{
- gtm_putmsg(VARLSTCNT(4) ERR_MUTRUNCNOV4, 2, REG_LEN_STR(gv_cur_region));
+ gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_MUTRUNCNOV4, 2, REG_LEN_STR(gv_cur_region));
rel_crit(gv_cur_region);
return TRUE;
} else if (SNAPSHOTS_IN_PROG(csa->nl))
{
- gtm_putmsg(VARLSTCNT(4) ERR_MUTRUNCSSINPROG, 2, REG_LEN_STR(gv_cur_region));
+ gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_MUTRUNCSSINPROG, 2, REG_LEN_STR(gv_cur_region));
rel_crit(gv_cur_region);
return TRUE;
} else if (BACKUP_NOT_IN_PROGRESS != cs_addrs->nl->nbb)
{
- gtm_putmsg(VARLSTCNT(4) ERR_MUTRUNCBACKINPROG, 2, REG_LEN_STR(gv_cur_region));
+ gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_MUTRUNCBACKINPROG, 2, REG_LEN_STR(gv_cur_region));
rel_crit(gv_cur_region);
return TRUE;
}
@@ -362,7 +364,7 @@ boolean_t mu_truncate(int4 truncate_percent)
ADJUST_GBL_JREC_TIME(jgbl, jbp);
jnl_status = jnl_ensure_open();
if (SS_NORMAL != jnl_status)
- send_msg(VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(gv_cur_region));
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(gv_cur_region));
else
{
if (0 == jpc->pini_addr)
@@ -373,7 +375,7 @@ boolean_t mu_truncate(int4 truncate_percent)
jnl_status = jnl_flush(gv_cur_region);
if (SS_NORMAL != jnl_status)
{
- send_msg(VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(csd),
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(csd),
ERR_TEXT, 2, RTS_ERROR_TEXT("Error with journal flush during mu_truncate"),
jnl_status);
assert(NOJNL == jpc->channel); /* jnl file lost has been triggered */
@@ -409,7 +411,7 @@ boolean_t mu_truncate(int4 truncate_percent)
if (0 != save_errno)
{
err_msg = (char *)STRERROR(errno);
- rts_error(VARLSTCNT(6) ERR_MUTRUNCERROR, 4, REG_LEN_STR(gv_cur_region), LEN_AND_STR(err_msg));
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_MUTRUNCERROR, 4, REG_LEN_STR(gv_cur_region), LEN_AND_STR(err_msg));
return FALSE;
}
KILL_TRUNC_TEST(WBTEST_CRASH_TRUNCATE_3); /* 57 : Issue a kill -9 after reducing csa->ti->total_blks, before FTRUNCATE */
@@ -422,7 +424,7 @@ boolean_t mu_truncate(int4 truncate_percent)
if (0 != ftrunc_status)
{
err_msg = (char *)STRERROR(errno);
- rts_error(VARLSTCNT(6) ERR_MUTRUNCERROR, 4, REG_LEN_STR(gv_cur_region), LEN_AND_STR(err_msg));
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_MUTRUNCERROR, 4, REG_LEN_STR(gv_cur_region), LEN_AND_STR(err_msg));
/* should go through recover_truncate now, which will again try to FTRUNCATE */
return FALSE;
}
@@ -445,7 +447,7 @@ boolean_t mu_truncate(int4 truncate_percent)
ENABLE_INTERRUPTS(INTRPT_IN_TRUNC);
curr_tn = csa->ti->curr_tn;
rel_crit(gv_cur_region);
- send_msg(VARLSTCNT(7) ERR_MUTRUNCSUCCESS, 5, DB_LEN_STR(gv_cur_region), old_total, new_total, &curr_tn);
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(7) ERR_MUTRUNCSUCCESS, 5, DB_LEN_STR(gv_cur_region), old_total, new_total, &curr_tn);
util_out_print("Truncated region: !AD. Reduced total blocks from [!UL] to [!UL]. Reduced free blocks from [!UL] to [!UL].",
FLUSH, REG_LEN_STR(gv_cur_region), old_total, new_total, old_free, new_free);
return TRUE;
diff --git a/sr_unix/mu_truncate.h b/sr_unix/mu_truncate.h
index c6c02ff..b79a869 100644
--- a/sr_unix/mu_truncate.h
+++ b/sr_unix/mu_truncate.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2012 Fidelity Information Services, Inc *
+ * Copyright 2012, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -21,8 +21,8 @@
{ \
if (0 != save_errno) \
{ \
- send_msg(VARLSTCNT(5) ERR_DBFSYNCERR, 2, DB_LEN_STR(reg), save_errno); \
- rts_error(VARLSTCNT(5) ERR_DBFSYNCERR, 2, DB_LEN_STR(reg), save_errno); \
+ send_msg_csa(CSA_ARG(REG2CSA(reg)) VARLSTCNT(5) ERR_DBFSYNCERR, 2, DB_LEN_STR(reg), save_errno); \
+ rts_error_csa(CSA_ARG(REG2CSA(reg)) VARLSTCNT(5) ERR_DBFSYNCERR, 2, DB_LEN_STR(reg), save_errno); \
assert(FALSE); /* should not come here as the rts_error above should not return */ \
rel_crit(reg); \
return FALSE; \
diff --git a/sr_unix/mubfilcpy.c b/sr_unix/mubfilcpy.c
index 34705a4..9e388d6 100644
--- a/sr_unix/mubfilcpy.c
+++ b/sr_unix/mubfilcpy.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -93,16 +93,15 @@ bool mubfilcpy (backup_reg_list *list)
mstr *file, tempfile;
unsigned char cmdarray[COMMAND_ARRAY_SIZE], *command = &cmdarray[0];
sgmnt_data_ptr_t header_cpy;
- int4 backup_fd = FD_INVALID, size, vbn, counter, hdrsize, rsize, ntries;
+ int4 backup_fd = FD_INVALID, counter, hdrsize, rsize, ntries;
ssize_t status;
- int4 adjust, blk_num, cmdlen, rv, save_errno, temp, tempfilelen, tmplen;
+ int4 blk_num, cmdlen, rv, save_errno, tempfilelen, tmplen;
struct stat stat_buf;
- off_t filesize, handled, offset;
+ off_t filesize, offset;
char *inbuf, *zero_blk, *ptr, *errptr;
- boolean_t done;
char tempfilename[MAX_FN_LEN + 1], tempdir[MAX_FN_LEN], prefix[MAX_FN_LEN];
int fstat_res;
- uint4 ustatus;
+ uint4 ustatus, size;
muinc_blk_hdr_ptr_t sblkh_p;
ZOS_ONLY(int realfiletag;)
int group_id;
@@ -158,11 +157,12 @@ bool mubfilcpy (backup_reg_list *list)
(ntries > MAX_TEMP_OPEN_TRY))
{
if (FILE_STAT_ERROR != fstat_res)
- gtm_putmsg(VARLSTCNT(8) ERR_TMPFILENOCRE, 2, tempfile.len, tempfile.addr,
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(8) ERR_TMPFILENOCRE, 2, tempfile.len, tempfile.addr,
ERR_TEXT, 2, LEN_AND_LIT("Tried a maximum number of times, clean-up temporary files " \
"in backup directory and retry."));
else
- gtm_putmsg(VARLSTCNT(5) ERR_TMPFILENOCRE, 2, tempfile.len, tempfile.addr, ustatus);
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(5) ERR_TMPFILENOCRE, 2, tempfile.len, tempfile.addr,
+ ustatus);
return FALSE;
}
ntries++;
@@ -183,7 +183,8 @@ bool mubfilcpy (backup_reg_list *list)
command[cmdlen] = 0;
if (debug_mupip)
util_out_print("!/MUPIP INFO: !AD", TRUE, cmdlen, command);
- if (0 != (rv = SYSTEM((char *)command)))
+ rv = SYSTEM(((char *)command));
+ if (0 != rv)
{
if (-1 == rv)
{
@@ -217,11 +218,11 @@ bool mubfilcpy (backup_reg_list *list)
if (-1 != fstat_res)
if (gtm_set_group_and_perm(&stat_buf, &group_id, &perm, PERM_FILE, &pdd) < 0)
{
- send_msg(VARLSTCNT(6+PERMGENDIAG_ARG_COUNT)
+ send_msg_csa(CSA_ARG(cs_addrs) VARLSTCNT(6+PERMGENDIAG_ARG_COUNT)
ERR_PERMGENFAIL, 4, RTS_ERROR_STRING("backup file"),
RTS_ERROR_STRING(((unix_db_info *)(gv_cur_region->dyn.addr->file_cntl->file_info))->fn),
PERMGENDIAG_ARGS(pdd));
- gtm_putmsg(VARLSTCNT(6+PERMGENDIAG_ARG_COUNT)
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(6+PERMGENDIAG_ARG_COUNT)
ERR_PERMGENFAIL, 4, RTS_ERROR_STRING("backup file"),
RTS_ERROR_STRING(((unix_db_info *)(gv_cur_region->dyn.addr->file_cntl->file_info))->fn),
PERMGENDIAG_ARGS(pdd));
@@ -252,7 +253,7 @@ bool mubfilcpy (backup_reg_list *list)
{ /* A concurrent online rollback happened since we did the gvcst_init. The backup is not reliable.
* Cleanup and exit
*/
- gtm_putmsg(VARLSTCNT(1) ERR_DBROLLEDBACK);
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(1) ERR_DBROLLEDBACK);
CLEANUP_AND_RETURN_FALSE;
}
/* if there has been an extend, truncate it */
@@ -309,7 +310,7 @@ bool mubfilcpy (backup_reg_list *list)
if (cs_addrs->nl->wcs_phase2_commit_pidcnt && !wcs_phase2_commit_wait(cs_addrs, NULL))
{
assert(FALSE);
- gtm_putmsg(VARLSTCNT(7) ERR_COMMITWAITSTUCK, 5, process_id, 1,
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(7) ERR_COMMITWAITSTUCK, 5, process_id, 1,
cs_addrs->nl->wcs_phase2_commit_pidcnt, DB_LEN_STR(gv_cur_region));
rel_crit(gv_cur_region);
CLEANUP_AND_RETURN_FALSE;
@@ -327,7 +328,7 @@ bool mubfilcpy (backup_reg_list *list)
backup_buffer_flush(gv_cur_region);
if (++counter > MAX_BACKUP_FLUSH_TRY)
{
- gtm_putmsg(VARLSTCNT(1) ERR_BCKUPBUFLUSH);
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(1) ERR_BCKUPBUFLUSH);
CLEANUP_AND_RETURN_FALSE;
}
if (counter & 0xF)
@@ -337,7 +338,7 @@ bool mubfilcpy (backup_reg_list *list)
if (FALSE == shmpool_lock_hdr(gv_cur_region))
{
assert(FALSE);
- gtm_putmsg(VARLSTCNT(9) ERR_DBCCERR, 2, REG_LEN_STR(gv_cur_region),
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(9) ERR_DBCCERR, 2, REG_LEN_STR(gv_cur_region),
ERR_ERRCALL, 3, CALLFROM);
CLEANUP_AND_RETURN_FALSE;
}
@@ -351,7 +352,7 @@ bool mubfilcpy (backup_reg_list *list)
assert(EACCES == cs_addrs->shmpool_buffer->backup_errno);
util_out_print("Process !UL encountered the following error.", TRUE, cs_addrs->shmpool_buffer->failed);
if (0 != cs_addrs->shmpool_buffer->backup_errno)
- gtm_putmsg(VARLSTCNT(1) cs_addrs->shmpool_buffer->backup_errno);
+ gtm_putmsg_csa(CSA_ARG(cs_addrs) VARLSTCNT(1) cs_addrs->shmpool_buffer->backup_errno);
util_out_print("WARNING: backup file !AD is not valid.", TRUE, file->len, file->addr);
CLEANUP_AND_RETURN_FALSE;
}
@@ -418,8 +419,8 @@ bool mubfilcpy (backup_reg_list *list)
size = (((blk_hdr_ptr_t)inbuf)->bsiz + 1) & ~1;
if (cs_addrs->do_fullblockwrites)
- size = (int4)ROUND_UP(size, cs_addrs->fullblockwrite_len);
- assert(cs_addrs->hdr->blk_size >= size);
+ size = ROUND_UP(size, cs_addrs->fullblockwrite_len);
+ assert((uint4)cs_addrs->hdr->blk_size >= size);
offset = (header_cpy->start_vbn - 1) * DISK_BLOCK_SIZE
+ ((off_t)header_cpy->blk_size * blk_num);
LSEEKWRITE(backup_fd,
@@ -487,7 +488,8 @@ bool mubfilcpy (backup_reg_list *list)
command[cmdlen] = 0;
if (debug_mupip)
util_out_print("MUPIP INFO: !AD", TRUE, cmdlen, command);
- if (0 != (rv = SYSTEM((char *)command)))
+ rv = SYSTEM(((char *)command));
+ if (0 != rv)
{
if (-1 == rv)
{
diff --git a/sr_unix/mumps_clitab.c b/sr_unix/mumps_clitab.c
index a4b1bef..28533de 100644
--- a/sr_unix/mumps_clitab.c
+++ b/sr_unix/mumps_clitab.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -30,6 +30,7 @@ static readonly CLI_ENTRY mumps_qual[] = {
{ "CROSS_REFERENCE", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0},
{ "DEBUG", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0},
{ "DIRECT_MODE", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NON_NEG, VAL_N_A, 0},
+{ "DYNAMIC_LITERALS", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NEG, VAL_N_A, 0},
{ "IGNORE", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NEG, VAL_N_A, 0},
{ "INLINE_LITERALS", 0, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, NEG, VAL_N_A, 0},
{ "LABELS", 0, 0, 0, 0, 0, 0, VAL_REQ, 1, NON_NEG, VAL_STR, 0},
diff --git a/sr_unix/mupip_cmd.c b/sr_unix/mupip_cmd.c
index 20f923b..18310c8 100644
--- a/sr_unix/mupip_cmd.c
+++ b/sr_unix/mupip_cmd.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -37,7 +37,7 @@
#include "mupip_extend.h"
#include "muextr.h"
#include "mupip_freeze.h"
-#include "mupip_help.h"
+#include "util_help.h"
#include "mupip_integ.h"
#include "mupip_intrpt.h"
#include "mupip_quit.h"
@@ -594,8 +594,9 @@ static CLI_PARM mup_rundown_parm[] = {
};
static CLI_ENTRY mup_rundown_qual[] = {
- { "FILE", 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 },
+ { "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 },
{ 0 }
};
@@ -622,6 +623,7 @@ static CLI_ENTRY mup_set_qual[] = {
{ "JOURNAL", mupip_set, 0, 0, mup_set_journal_qual, 0, 0, VAL_NOT_REQ, 1, NEG, VAL_STR, 0 },
{ "KEY_SIZE", mupip_set, 0, 0, 0, 0, 0, VAL_REQ, 1, NON_NEG, VAL_NUM, 0 },
{ "LOCK_SPACE", mupip_set, 0, 0, 0, 0, 0, VAL_REQ, 1, NON_NEG, VAL_NUM, 0 },
+{ "MUTEX_SLOTS", mupip_set, 0, 0, 0, 0, 0, VAL_REQ, 1, NON_NEG, VAL_NUM, 0 },
{ "PARTIAL_RECOV_BYPASS", mupip_set, 0, 0, 0, 0, 0, VAL_DISALLOWED, 1, NON_NEG, VAL_N_A, 0 },
{ "PREVJNLFILE", mupip_set, 0, 0, 0, 0, 0, VAL_REQ, 1, NEG, VAL_STR, 0 },
{ "QDBRUNDOWN", mupip_set, 0, 0, 0, 0, 0, VAL_DISALLOWED, 1, NEG, VAL_N_A, 0 },
@@ -694,7 +696,7 @@ 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 },
-{ "HELP", mupip_help, 0, 0, 0, 0, 0, VAL_DISALLOWED, 0, 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 },
diff --git a/sr_unix/mupip_exit.c b/sr_unix/mupip_exit.c
index ce1ecfc..e4662f3 100644
--- a/sr_unix/mupip_exit.c
+++ b/sr_unix/mupip_exit.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -27,7 +27,7 @@ void mupip_exit(int4 stat)
{
if (error_condition != stat) /* If message not already put out.. */
{
- gtm_putmsg(VARLSTCNT(1) stat);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) stat);
tmp_severity = SEVMASK(stat);
} else
tmp_severity = severity;
diff --git a/sr_unix/mupip_exit_handler.c b/sr_unix/mupip_exit_handler.c
index 1c94034..c1fc50f 100644
--- a/sr_unix/mupip_exit_handler.c
+++ b/sr_unix/mupip_exit_handler.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -94,6 +94,7 @@ void mupip_exit_handler(void)
{
char err_log[1024];
FILE *fp;
+ boolean_t files_closed = TRUE;
if (exit_handler_active) /* Don't recurse if exit handler exited */
return;
@@ -101,7 +102,7 @@ void mupip_exit_handler(void)
SET_PROCESS_EXITING_TRUE;
if (jgbl.mupip_journal)
{
- mur_close_files();
+ files_closed = mur_close_files();
mupip_jnl_recover = FALSE;
}
jgbl.dont_reset_gbl_jrec_time = jgbl.forw_phase_recovery = FALSE;
@@ -152,6 +153,8 @@ void mupip_exit_handler(void)
++core_in_progress;
DUMP_CORE; /* This will not return */
}
+ if (!files_closed)
+ _exit(EXIT_FAILURE);
}
void close_repl_logfiles()
diff --git a/sr_unix/mupip_help.c b/sr_unix/mupip_help.c
index 508328f..0e8cb2d 100644
--- a/sr_unix/mupip_help.c
+++ b/sr_unix/mupip_help.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -9,11 +9,10 @@
* *
****************************************************************/
-/* STUB FILE */
-
#include "mdef.h"
#include "mupip_help.h"
void mupip_help(void)
-{ return;
+{
+ /* This function is a STUB to avoid editting sr_port/mupip.h */
}
diff --git a/sr_unix/mupip_restore.c b/sr_unix/mupip_restore.c
index 70da5d9..d32e2a8 100644
--- a/sr_unix/mupip_restore.c
+++ b/sr_unix/mupip_restore.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -104,7 +104,6 @@ error_def(ERR_TEXT);
CONDITION_HANDLER(iob_io_error)
{
- int dummy1, dummy2;
char s[80];
char *fgets_res;
@@ -117,7 +116,7 @@ CONDITION_HANDLER(iob_io_error)
CONTINUE;
}
PRN_ERROR;
- UNWIND(dummy1, dummy2);
+ UNWIND(NULL, NULL);
}
@@ -128,9 +127,8 @@ void mupip_restore(void)
inc_list_struct *ptr;
inc_header inhead;
sgmnt_data old_data;
- short iosb[4];
unsigned short n_len;
- int4 status, rsize, size, temp, save_errno, old_start_vbn;
+ int4 status, rsize, temp, save_errno, old_start_vbn;
uint4 rest_blks, totblks;
trans_num curr_tn;
uint4 ii;
@@ -139,7 +137,7 @@ void mupip_restore(void)
uint4 cli_status;
BFILE *in;
int i, db_fd;
- uint4 old_blk_size, old_tot_blks, bplmap, old_bit_maps, new_bit_maps;
+ uint4 old_blk_size, size, old_tot_blks, bplmap, old_bit_maps, new_bit_maps;
off_t new_eof, offset;
# ifdef GTM_TRUNCATE
off_t new_size;
@@ -152,7 +150,6 @@ void mupip_restore(void)
backup_type type;
unsigned short port;
int4 timeout, cut, match;
- char debug_info[256];
void (*common_read)();
char *errptr;
pid_t waitpid_res;
@@ -424,7 +421,7 @@ void mupip_restore(void)
util_out_print(" Current input file is !AD with !UL (!XL hex) total blocks!/",
TRUE, ptr->input_file.len, ptr->input_file.addr,
inhead.db_total_blks, inhead.db_total_blks);
- gtm_putmsg(VARLSTCNT(1) status);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) status);
CLNUP_AND_EXIT(ERR_MUPRESTERR, inbuf);
}
/* --- initialize all new bitmaps, just in case they are not touched later --- */
@@ -446,7 +443,7 @@ void mupip_restore(void)
{
util_out_print("Aborting restore!/", TRUE);
util_out_print("Bitmap 0x!XL initialization error!", TRUE, ii);
- gtm_putmsg(VARLSTCNT(1) status);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) status);
free(newmap);
CLNUP_AND_EXIT(ERR_MUPRESTERR, inbuf);
}
@@ -697,7 +694,7 @@ STATICFNDEF void exec_read(BFILE *bf, char *buf, int nbytes)
*/
else if ((EINTR != errno) && (EAGAIN != errno))
{
- gtm_putmsg(VARLSTCNT(1) errno);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) errno);
if ((pipe_child > 0) && (FALSE != is_proc_alive(pipe_child, 0)))
WAITPID(pipe_child, (int *)&status, 0, waitpid_res);
CLOSEFILE_RESET(bf->fd, rc); /* resets "bf->fd" to FD_INVALID */
@@ -747,7 +744,7 @@ STATICFNDEF void tcp_read(BFILE *bf, char *buf, int nbytes)
}
if ((status < 0) && (errno != EINTR))
{
- gtm_putmsg(VARLSTCNT(1) errno);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) errno);
CLOSEFILE_RESET(bf->fd, rc); /* resets "bf->fd" to FD_INVALID */
restore_read_errno = errno;
break;
diff --git a/sr_unix/mupip_set_file.c b/sr_unix/mupip_set_file.c
index 3e49a94..0373696 100644
--- a/sr_unix/mupip_set_file.c
+++ b/sr_unix/mupip_set_file.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -111,8 +111,9 @@ int4 mupip_set_file(int db_fn_len, char *db_fn)
int4 status1;
int glbl_buff_status, defer_status, rsrvd_bytes_status,
extn_count_status, lock_space_status, disk_wait_status,
- inst_freeze_on_error_status, qdbrundown_status;
- int4 new_disk_wait, new_cache_size, new_extn_count, new_lock_space, reserved_bytes, defer_time;
+ inst_freeze_on_error_status, qdbrundown_status, mutex_space_status;
+ int4 new_disk_wait, new_cache_size, new_extn_count, new_lock_space, reserved_bytes, defer_time,
+ new_mutex_space;
int key_size_status, rec_size_status;
int4 new_key_size, new_rec_size;
sgmnt_data_ptr_t csd;
@@ -223,6 +224,28 @@ int4 mupip_set_file(int db_fn_len, char *db_fn)
}
need_standalone = TRUE;
}
+ if (mutex_space_status = cli_present("MUTEX_SLOTS"))
+ {
+ if (cli_get_int("MUTEX_SLOTS", &new_mutex_space))
+ {
+ if (new_mutex_space > MAX_CRIT_ENTRY)
+ {
+ util_out_print("!UL too large, maximum number of mutex slots allowed is !UL", TRUE,
+ new_mutex_space, MAX_CRIT_ENTRY);
+ return (int4)ERR_WCWRNNOTCHG;
+ } else if (new_mutex_space < MIN_CRIT_ENTRY)
+ {
+ util_out_print("!UL too small, minimum number of mutex slots allowed is !UL", TRUE,
+ new_mutex_space, MIN_CRIT_ENTRY);
+ return (int4)ERR_WCWRNNOTCHG;
+ }
+ } else
+ {
+ util_out_print("Error getting MUTEX_SPACE qualifier value", TRUE);
+ return (int4)ERR_WCWRNNOTCHG;
+ }
+ need_standalone = TRUE;
+ }
if (rsrvd_bytes_status = cli_present("RESERVED_BYTES"))
{
if (!cli_get_int("RESERVED_BYTES", &reserved_bytes))
@@ -509,6 +532,8 @@ int4 mupip_set_file(int db_fn_len, char *db_fn)
csd->extension_size = (uint4)new_extn_count;
if (lock_space_status)
csd->lock_space_size = (uint4)new_lock_space * OS_PAGELET_SIZE;
+ if (mutex_space_status)
+ NUM_CRIT_ENTRY(csd) = new_mutex_space;
if (qdbrundown_status)
csd->mumps_can_bypass = CLI_PRESENT == qdbrundown_status;
if (bypass_partial_recov)
@@ -608,6 +633,9 @@ int4 mupip_set_file(int db_fn_len, char *db_fn)
if (lock_space_status)
util_out_print("Database file !AD now has lock space !UL pages",
TRUE, fn_len, fn, csd->lock_space_size/OS_PAGELET_SIZE);
+ if (mutex_space_status)
+ util_out_print("Database file !AD now has !UL mutex queue slots",
+ TRUE, fn_len, fn, NUM_CRIT_ENTRY(csd));
if (qdbrundown_status)
util_out_print("Database file !AD now has quick database rundown flag set to !AD", TRUE,
fn_len, fn, 5, (csd->mumps_can_bypass ? " TRUE" : "FALSE"));
diff --git a/sr_unix/mur_cre_file_extfmt.c b/sr_unix/mur_cre_file_extfmt.c
index 210a0f7..518f5fc 100644
--- a/sr_unix/mur_cre_file_extfmt.c
+++ b/sr_unix/mur_cre_file_extfmt.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2003, 2011 Fidelity Information Services, Inc *
+ * Copyright 2003, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -95,7 +95,7 @@ int4 mur_cre_file_extfmt(jnl_ctl_list *jctl, int recstat)
while (DOT != *ptr) /* we know journal file name alway has a DOT */
ptr--;
base_len = (int)(ptr - (char *)&jctl->jnl_fn[0]);
- file_info = murgbl.file_info[recstat] = (void *)malloc(SIZEOF(fi_type));
+ file_info = (void *)malloc(SIZEOF(fi_type));
if (0 == mur_options.extr_fn_len[recstat])
{
mur_options.extr_fn[recstat] = malloc(MAX_FN_LEN);
@@ -107,6 +107,7 @@ int4 mur_cre_file_extfmt(jnl_ctl_list *jctl, int recstat)
}
file_info->fn_len = mur_options.extr_fn_len[recstat];
file_info->fn = mur_options.extr_fn[recstat];
+ murgbl.file_info[recstat] = file_info;
if (RENAME_FAILED == rename_file_if_exists(file_info->fn, file_info->fn_len, rename_fn, &rename_fn_len, &status))
return status;
op_pars.mvtype = MV_STR;
diff --git a/sr_unix/mutex.c b/sr_unix/mutex.c
index 4b66a20..53421d0 100644
--- a/sr_unix/mutex.c
+++ b/sr_unix/mutex.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -304,7 +304,7 @@ static void crash_initialize(mutex_struct_ptr_t addr, int n, bool crash)
} while (TRUE);
}
-static enum cdb_sc mutex_long_sleep(mutex_struct_ptr_t addr, mutex_lock_t mutex_lock_type)
+static enum cdb_sc mutex_long_sleep(mutex_struct_ptr_t addr, mutex_lock_t mutex_lock_type, sgmnt_addrs *csa)
{
enum cdb_sc status;
boolean_t wakeup_status;
@@ -465,7 +465,7 @@ static enum cdb_sc mutex_long_sleep(mutex_struct_ptr_t addr, mutex_lock_t mutex_
if (MUTEX_LOCK_WRITE == mutex_lock_type)
return (cdb_sc_normal);
} else
- mutex_deadlock_check(addr); /* Timed out: See if any deadlocks and fix if detected */
+ mutex_deadlock_check(addr, csa); /* Timed out: See if any deadlocks and fix if detected */
status = mutex_wakeup(addr); /* Timed out or reader. In case
* of reader this causes
* accelerated wakeup of readers
@@ -576,7 +576,7 @@ static enum cdb_sc mutex_sleep(sgmnt_addrs *csa, mutex_lock_t mutex_lock_type)
{
MUTEX_DPRINT3("%d: Inserted %d into wait queue\n", process_id,
free_slot->pid);
- return (mutex_long_sleep(addr, mutex_lock_type));
+ return (mutex_long_sleep(addr, mutex_lock_type, csa));
}
} while (--queue_retry_counter_insq);
if (!(--quant_retry_counter_insq))
@@ -615,6 +615,7 @@ static enum cdb_sc mutex_sleep(sgmnt_addrs *csa, mutex_lock_t mutex_lock_type)
} else
assert(process_exiting); /* timers might be off, but this adds CPU load at an awkward time */
MICROSEC_SLEEP(ONE_MILLION - 1); /* Wait a second, then try again */
+ mutex_deadlock_check(addr, csa);
if (++redo_cntr < MUTEX_MAX_WAIT_FOR_PROGRESS_CNTR)
break;
return (cdb_sc_normal);
diff --git a/sr_unix/mutex_sock_init.c b/sr_unix/mutex_sock_init.c
index 37e45f2..109993e 100644
--- a/sr_unix/mutex_sock_init.c
+++ b/sr_unix/mutex_sock_init.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -71,7 +71,8 @@ void mutex_sock_init(void)
return;
/* Create the socket used for sending and receiving mutex wake mesgs */
if (FD_INVALID == (mutex_sock_fd = socket(AF_UNIX, SOCK_DGRAM, 0)))
- rts_error(VARLSTCNT(7) ERR_MUTEXERR, 0, ERR_TEXT, 2, RTS_ERROR_TEXT("Error with mutex socket create"), errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_MUTEXERR, 0, ERR_TEXT, 2,
+ RTS_ERROR_TEXT("Error with mutex socket create"), errno);
memset((char *)&mutex_sock_address, 0, SIZEOF(mutex_sock_address));
/* Get the socket path */
mutex_sock_dir_lognam.len = SIZEOF(MUTEX_SOCK_DIR) - 1;
@@ -91,7 +92,8 @@ void mutex_sock_init(void)
mutex_sock_path[mutex_sock_path_len] = '\0';
}
if ((mutex_sock_path_len + MAX_MUTEX_SOCKFILE_NAME_LEN) > SIZEOF(mutex_sock_address.sun_path))
- rts_error(VARLSTCNT(6) ERR_MUTEXERR, 0, ERR_TEXT, 2, RTS_ERROR_TEXT("Mutex socket path too long"));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_MUTEXERR, 0, ERR_TEXT, 2,
+ RTS_ERROR_TEXT("Mutex socket path too long"));
strcpy(mutex_sock_path + mutex_sock_path_len, MUTEX_SOCK_FILE_PREFIX);
mutex_sock_path_len += (SIZEOF(MUTEX_SOCK_FILE_PREFIX) - 1);
mutex_wake_this_proc_prefix_len = mutex_sock_path_len;
@@ -99,7 +101,8 @@ void mutex_sock_init(void)
strcpy(mutex_sock_path + mutex_sock_path_len, (char *)pid2ascx(pid_str, process_id));
mutex_sock_path_len += STRLEN((char *)pid_str);
if (mutex_sock_path_len > SIZEOF(mutex_sock_address.sun_path))
- rts_error(VARLSTCNT(6) ERR_MUTEXERR, 0, ERR_TEXT, 2, RTS_ERROR_TEXT("Mutex socket path too long"));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_MUTEXERR, 0, ERR_TEXT, 2,
+ RTS_ERROR_TEXT("Mutex socket path too long"));
mutex_sock_address.sun_family = AF_UNIX;
strcpy(mutex_sock_address.sun_path, mutex_sock_path);
mutex_sock_len = SIZEOF(mutex_sock_address.sun_family) + mutex_sock_path_len + 1; /* Include NULL byte in length */
@@ -127,29 +130,30 @@ void mutex_sock_init(void)
mutex_sock_path_len + 1)))
{
DEBUG_ONLY(if (existed)) /* Avoid mesg unless socket existed */
- send_msg(VARLSTCNT(8) ERR_MUTEXRSRCCLNUP, 2, mutex_sock_path_len, mutex_sock_path,
- ERR_TEXT, 2, LEN_AND_LIT("Resource removed by gtmsecshr"));
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_MUTEXRSRCCLNUP, 2, mutex_sock_path_len,
+ mutex_sock_path, ERR_TEXT, 2, LEN_AND_LIT("Resource removed by gtmsecshr"));
} else if (ENOENT != status)
- rts_error(VARLSTCNT(10) ERR_MUTEXERR, 0, ERR_TEXT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_MUTEXERR, 0, ERR_TEXT, 2,
LEN_AND_LIT("gtmsecshr failed to remove leftover mutex resource"),
ERR_TEXT, 2, mutex_sock_path_len, mutex_sock_path);
/* else don't bother if somebody removed the file before gtmsecshr got to it */
}
} else /* unlink succeeded - socket must have existed - now cleaned up */
- send_msg(VARLSTCNT(4) ERR_MUTEXRSRCCLNUP, 2, mutex_sock_path_len, mutex_sock_path);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_MUTEXRSRCCLNUP, 2, mutex_sock_path_len, mutex_sock_path);
if (0 > BIND(mutex_sock_fd, (struct sockaddr *)&mutex_sock_address, mutex_sock_len))
- rts_error(VARLSTCNT(7) ERR_MUTEXERR, 0, ERR_TEXT, 2, RTS_ERROR_TEXT("Error with mutex socket bind"), errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_MUTEXERR, 0, ERR_TEXT, 2,
+ RTS_ERROR_TEXT("Error with mutex socket bind"), errno);
/* Set the socket permissions to override any umask settings.
* Allow owner and group read and write access.
*/
STAT_FILE(mutex_sock_address.sun_path, &mutex_sock_stat_buf, status);
if (-1 == status)
- rts_error(VARLSTCNT(7) ERR_MUTEXERR, 0, ERR_TEXT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_MUTEXERR, 0, ERR_TEXT, 2,
RTS_ERROR_TEXT("Error with mutex socket stat"),
errno);
mutex_sock_stat_buf.st_mode |= (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
if (-1 == CHMOD(mutex_sock_address.sun_path, mutex_sock_stat_buf.st_mode))
- rts_error(VARLSTCNT(7) ERR_MUTEXERR, 0, ERR_TEXT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_MUTEXERR, 0, ERR_TEXT, 2,
RTS_ERROR_TEXT("Error with mutex socket chmod"),
errno);
/* Clear the descriptor set used to sense wake up message */
diff --git a/sr_unix/obj_code.c b/sr_unix/obj_code.c
index 2de6411..78b8e02 100644
--- a/sr_unix/obj_code.c
+++ b/sr_unix/obj_code.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -72,17 +72,17 @@ GBLREF spdesc stringpool;
*
* +---------------+
* | rhead | > - R/O - retain
- * +---------------+
- * | generated | \
- * | code | \
- * + - - - - - - - + |
- * | line num tbl | |- R/O releasable
- * + - - - - - - - + /
- * | lit text pool | /
- * +---------------+
- * | lit mval tbl | \
+ * +---------------+ Alternative layout if compiled with GTM_DYNAMIC_LITERALS:
+ * | generated | \ \
+ * | code | \ \
+ * + - - - - - - - + | |
+ * | line num tbl | |- R/O releasable |
+ * + - - - - - - - + / |- R/O releasable
+ * | lit text pool | / |
+ * +---------------+ /
+ * | lit mval tbl | \ /
* +---------------+ |- R/W releasable
- * | variable tbl | /
+ * | variable tbl | / > - R/W releasable
* + - - - - - - - +
* | label tbl | > - R/W retain
* +---------------+
@@ -93,6 +93,10 @@ GBLREF spdesc stringpool;
*
* Note in addition to the above layout, a "linkage section" is allocated at run time and is
* also releasable.
+ *
+ * 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_TEXT);
diff --git a/sr_unix/ojchildioset.c b/sr_unix/ojchildioset.c
index 3098f36..1c24595 100644
--- a/sr_unix/ojchildioset.c
+++ b/sr_unix/ojchildioset.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -27,54 +27,45 @@
#include "gtm_zos_io.h"
#endif
-GBLREF boolean_t job_try_again;
-
-#define NULL_DEV_FNAME "/dev/null" /* Null device file name */
-#define OPEN_RSRC_CRUNCH_FAILURE \
- (EDQUOT == errno || ENFILE == errno || ENOMEM == errno || ENOSPC == errno || ETIMEDOUT == errno)
+GBLREF int job_errno;
+ZOS_ONLY(error_def(ERR_BADTAG);)
+error_def(ERR_JOBFAIL);
+error_def(ERR_TEXT);
/*
* ---------------------------------------------------------
- * Set up input, output and error file descriptors in
+ * Set up output and error file descriptors in
* a child.
* ---------------------------------------------------------
*/
-bool ojchildioset(job_params_type *jparms)
+int ojchildioset(job_params_type *jparms)
{
- int dup_ret, in_fd, out_fd, err_fd, save_errno;
- char fname_buf[1024], buf[1024];
- int rc;
+ int dup_ret, in_fd, out_fd, err_fd;
+ char fname_buf[MAX_STDIOE_LEN], buf[MAX_STDIOE_LEN];
+ int rc;
+ joberr_t joberr = joberr_gen;
ZOS_ONLY(int realfiletag;)
- error_def(ERR_TEXT);
- error_def(ERR_JOBFAIL);
- ZOS_ONLY(error_def(ERR_BADTAG);)
-
- /* Redirect input */
+/*
+ * Redirect input
+ */
strncpy(fname_buf, jparms->input.addr, jparms->input.len);
*(fname_buf + jparms->input.len) = '\0';
OPENFILE(fname_buf, O_RDONLY, in_fd);
if (FD_INVALID == in_fd)
{
- if (OPEN_RSRC_CRUNCH_FAILURE)
- job_try_again = TRUE;
- else
- {
- save_errno = errno;
- SPRINTF(buf, "Error redirecting stdin (open) to %s", fname_buf);
- gtm_putmsg(VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2, LEN_AND_STR(buf), save_errno);
- }
- return FALSE;
+ joberr = joberr_io_stdin_open;
+ job_errno = errno;
+ return joberr;
}
CLOSEFILE(0, rc);
FCNTL3(in_fd, F_DUPFD, 0, dup_ret);
if (-1 == dup_ret)
{
- save_errno = errno;
- SPRINTF(buf, "Error redirecting stdin (fcntl) to %s", fname_buf);
- gtm_putmsg(VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2, LEN_AND_STR(buf), save_errno);
- return FALSE;
+ joberr = joberr_io_stdin_dup;
+ job_errno = errno;
+ return joberr;
}
#ifdef __MVS__
/* policy tagging because by default input is /dev/null */
@@ -82,6 +73,7 @@ bool ojchildioset(job_params_type *jparms)
TAG_POLICY_SEND_MSG(fname_buf, errno, realfiletag, TAG_UNTAGGED);
#endif
CLOSEFILE_RESET(in_fd, rc); /* resets "in_fd" to FD_INVALID */
+
/*
* Redirect Output
*/
@@ -91,17 +83,10 @@ bool ojchildioset(job_params_type *jparms)
CREATE_FILE(fname_buf, 0666, out_fd);
if (FD_INVALID == out_fd)
{
- if (OPEN_RSRC_CRUNCH_FAILURE)
- job_try_again = TRUE;
- else
- {
- save_errno = errno;
- SPRINTF(buf, "Error redirecting stdout (creat) to %s", fname_buf);
- gtm_putmsg(VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2, LEN_AND_STR(buf), save_errno);
- }
- return FALSE;
+ joberr = joberr_io_stdout_creat;
+ job_errno = errno;
+ return joberr;
}
-
#ifdef __MVS__
/* tagging as ASCII is fine now, that might change in the future for gtm_utf8_mode */
if (-1 == gtm_zos_set_tag(out_fd, TAG_ASCII, TAG_TEXT, TAG_FORCE, &realfiletag))
@@ -112,25 +97,18 @@ bool ojchildioset(job_params_type *jparms)
OPENFILE(fname_buf, O_WRONLY, out_fd);
if (FD_INVALID == out_fd)
{
- if (OPEN_RSRC_CRUNCH_FAILURE)
- job_try_again = TRUE;
- else
- {
- save_errno = errno;
- SPRINTF(buf, "Error redirecting stdout (open) to %s", fname_buf);
- gtm_putmsg(VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2, LEN_AND_STR(buf), save_errno);
- }
- return FALSE;
+ joberr = joberr_io_stdout_open;
+ job_errno = errno;
+ return joberr;
}
CLOSEFILE(1, rc);
FCNTL3(out_fd, F_DUPFD, 0, dup_ret);
if (-1 == dup_ret)
{
- save_errno = errno;
- SPRINTF(buf, "Error redirecting stdout (fcntl) to %s", fname_buf);
- gtm_putmsg(VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2, LEN_AND_STR(buf), save_errno);
- return FALSE;
+ joberr = joberr_io_stdout_dup;
+ job_errno = errno;
+ return joberr;
}
CLOSEFILE_RESET(out_fd, rc); /* resets "out_fd" to FD_INVALID */
/*
@@ -142,47 +120,31 @@ bool ojchildioset(job_params_type *jparms)
CREATE_FILE(fname_buf, 0666, err_fd);
if (FD_INVALID == err_fd)
{
- if (OPEN_RSRC_CRUNCH_FAILURE)
- job_try_again = TRUE;
- else
- {
- save_errno = errno;
- SPRINTF(buf, "Error redirecting stderr (creat) to %s", fname_buf);
- gtm_putmsg(VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2, LEN_AND_STR(buf), save_errno);
- }
- return FALSE;
+ joberr = joberr_io_stderr_creat;
+ job_errno = errno;
+ return joberr;
}
-
#ifdef __MVS__
if (-1 == gtm_zos_set_tag(err_fd, TAG_EBCDIC, TAG_TEXT, TAG_FORCE, &realfiletag))
TAG_POLICY_SEND_MSG(fname_buf, errno, realfiletag, TAG_EBCDIC);
#endif
CLOSEFILE_RESET(err_fd, rc); /* resets "err_fd" to FD_INVALID */
-
OPENFILE(fname_buf, O_WRONLY, err_fd);
if (FD_INVALID == err_fd)
{
- if (OPEN_RSRC_CRUNCH_FAILURE)
- job_try_again = TRUE;
- else
- {
- save_errno = errno;
- SPRINTF(buf, "Error redirecting stderr (open) to %s", fname_buf);
- gtm_putmsg(VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2, LEN_AND_STR(buf), save_errno);
- }
- return FALSE;
+ joberr = joberr_io_stderr_open;
+ job_errno = errno;
+ return joberr;
}
-
CLOSEFILE(2, rc);
FCNTL3(err_fd, F_DUPFD, 0, dup_ret);
if (-1 == dup_ret)
{
- save_errno = errno;
- SPRINTF(buf, "Error redirecting stderr (fcntl) to %s", fname_buf);
- gtm_putmsg(VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2, LEN_AND_STR(buf), save_errno);
- return FALSE;
+ joberr = joberr_io_stderr_dup;
+ job_errno = errno;
+ return joberr;
}
CLOSEFILE_RESET(err_fd, rc); /* resets "err_fd" to FD_INVALID */
- return(TRUE);
+ return 0;
}
diff --git a/sr_unix/ojparams.c b/sr_unix/ojparams.c
index f51a083..4adbd2d 100644
--- a/sr_unix/ojparams.c
+++ b/sr_unix/ojparams.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -71,7 +71,7 @@ void ojparams (char *p, job_params_type *job_params)
case jp_default:
if (*p != 0)
{
- job_params->directory.len = *p;
+ job_params->directory.len = (int)((unsigned char) *p);
job_params->directory.addr = (p + 1);
}
break;
@@ -79,7 +79,7 @@ void ojparams (char *p, job_params_type *job_params)
case jp_error:
if (*p != 0)
{
- job_params->error.len = *p;
+ job_params->error.len = (int)((unsigned char) *p);
job_params->error.addr = (p + 1);
}
break;
@@ -87,7 +87,7 @@ void ojparams (char *p, job_params_type *job_params)
case jp_gbldir:
if (*p != 0)
{
- job_params->gbldir.len = *p;
+ job_params->gbldir.len = (int)((unsigned char) *p);
job_params->gbldir.addr = (p + 1);
}
break;
@@ -95,7 +95,7 @@ void ojparams (char *p, job_params_type *job_params)
case jp_input:
if (*p != 0)
{
- job_params->input.len = *p;
+ job_params->input.len = (int)((unsigned char) *p);
job_params->input.addr = p + 1;
}
break;
@@ -103,7 +103,7 @@ void ojparams (char *p, job_params_type *job_params)
case jp_logfile:
if (*p != 0)
{
- job_params->logfile.len = *p;
+ job_params->logfile.len = (int)((unsigned char) *p);
job_params->logfile.addr = p + 1;
}
break;
@@ -111,7 +111,7 @@ void ojparams (char *p, job_params_type *job_params)
case jp_output:
if (*p != 0)
{
- job_params->output.len = *p;
+ job_params->output.len = (int)((unsigned char) *p);
job_params->output.addr = p + 1;
}
break;
@@ -123,7 +123,7 @@ void ojparams (char *p, job_params_type *job_params)
case jp_startup:
if (*p != 0)
{
- job_params->startup.len = *p;
+ job_params->startup.len = (int)((unsigned char) *p);
job_params->startup.addr = p + 1;
}
break;
@@ -131,7 +131,7 @@ void ojparams (char *p, job_params_type *job_params)
case jp_cmdline:
if(*p != 0)
{
- job_params->cmdline.len = *p;
+ job_params->cmdline.len = (int)((unsigned char) *p);
job_params->cmdline.addr = p + 1;
}
break;
@@ -160,7 +160,7 @@ void ojparams (char *p, job_params_type *job_params)
break;
case jpdt_str:
- p += (unsigned)*p + 1;
+ p += ((int)((unsigned char)*p)) + 1;
break;
default:
GTMASSERT;
@@ -180,7 +180,7 @@ void ojparams (char *p, job_params_type *job_params)
else
if (!(status = ojchkfs (job_params->input.addr,
job_params->input.len, TRUE)))
- rts_error(VARLSTCNT(6) ERR_PARFILSPC, 4, 5, "INPUT",
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_PARFILSPC, 4, 5, "INPUT",
job_params->input.len, job_params->input.addr);
/*
@@ -203,7 +203,7 @@ void ojparams (char *p, job_params_type *job_params)
else
if (!(status = ojchkfs (job_params->output.addr,
job_params->output.len, FALSE)))
- rts_error(VARLSTCNT(6) ERR_PARFILSPC, 4, 6,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_PARFILSPC, 4, 6,
"OUTPUT", job_params->output.len,
job_params->output.addr);
/*
@@ -226,7 +226,7 @@ void ojparams (char *p, job_params_type *job_params)
else
if (!(status = ojchkfs (job_params->error.addr,
job_params->error.len, FALSE)))
- rts_error(VARLSTCNT(6) ERR_PARFILSPC, 4, 5, "ERROR",
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_PARFILSPC, 4, 5, "ERROR",
job_params->error.len,
job_params->error.addr);
/*
@@ -235,7 +235,7 @@ void ojparams (char *p, job_params_type *job_params)
if (job_params->gbldir.len)
if (!(status = ojchkfs (job_params->gbldir.addr,
job_params->gbldir.len, FALSE)))
- rts_error(VARLSTCNT(6) ERR_PARFILSPC, 4, 6, "GBLDIR",
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_PARFILSPC, 4, 6, "GBLDIR",
job_params->gbldir.len, job_params->gbldir.addr);
/*
* Startup
@@ -243,7 +243,7 @@ void ojparams (char *p, job_params_type *job_params)
if (job_params->startup.len)
if (!(status = ojchkfs (job_params->startup.addr,
job_params->startup.len, TRUE)))
- rts_error(VARLSTCNT(6) ERR_PARFILSPC, 4, 7, "STARTUP",
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_PARFILSPC, 4, 7, "STARTUP",
job_params->startup.len, job_params->startup.addr);
/*
* Default Directory
@@ -251,7 +251,7 @@ void ojparams (char *p, job_params_type *job_params)
if (job_params->directory.len)
if (!(status = ojchkfs (job_params->directory.addr,
job_params->directory.len, FALSE)))
- rts_error(VARLSTCNT(6) ERR_PARFILSPC, 4, 7, "DEFAULT",
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_PARFILSPC, 4, 7, "DEFAULT",
job_params->directory.len, job_params->directory.addr);
/*
* Logfile
@@ -264,7 +264,7 @@ void ojparams (char *p, job_params_type *job_params)
else
if (!(status = ojchkfs (job_params->logfile.addr,
job_params->logfile.len, FALSE)))
- rts_error(VARLSTCNT(6) ERR_PARFILSPC, 4, 7, "LOGFILE",
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_PARFILSPC, 4, 7, "LOGFILE",
job_params->logfile.len, job_params->logfile.addr);
}
diff --git a/sr_unix/ojstartchild.c b/sr_unix/ojstartchild.c
index 0205b6a..c1b7db1 100644
--- a/sr_unix/ojstartchild.c
+++ b/sr_unix/ojstartchild.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -26,6 +26,8 @@
#include "gtm_stdio.h"
#include "gtm_stat.h"
#include "gtm_string.h"
+#include "gtm_limits.h"
+
#if defined(SYS_ERRLIST_INCLUDE) && !defined(__CYGWIN__)
#include SYS_ERRLIST_INCLUDE
#endif
@@ -44,31 +46,18 @@
#include "gtm_facility.h"
#include "fileinfo.h"
#include "gtmio.h"
+#include "fork_init.h"
-#define MAX_JOB_LEN 8192 /* Arbitrary length maximum used for checking job arguments and parameters */
-#define MAX_PATH 128 /* Maximum file path length */
-#define MAX_LAB_LEN 32 /* Maximum Label string length */
-#define MAX_RTN_LEN 32 /* Maximum Routine string length */
-#define TEMP_BUFF_SIZE 1024
-#define PARM_STRING_SIZE 9
-#define MAX_NUM_LEN 10 /* Maximum length number will be when converted to string */
-#define MAX_JOB_QUALS 12 /* Maximum environ variables set for job qualifiers */
-#define MUMPS_EXE_STR "/mumps"
-#define MUMPS_DIRECT_STR "-direct"
-#define GTMJ_FMT "gtmj%03d="
-#define PARM_STR "gtmj000="
+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;
-static int joberr = joberr_gen;
-static boolean_t job_launched = FALSE;
+static joberr_t joberr = joberr_gen;
+static int pipe_fd;
-GBLREF bool jobpid; /* job's output files should have the pid appended to them. */
-GBLREF volatile boolean_t ojtimeout;
-GBLREF boolean_t job_try_again;
-GBLREF uint4 process_id;
-GBLREF boolean_t gtm_pipe_child;
#ifndef SYS_ERRLIST_INCLUDE
-/* currently either stdio.h or errno.h both of which are included above */
-/* needed by TIMEOUT_ERROR in jobsp.h */
+/* currently either stdio.h or errno.h both of which are included above needed by TIMEOUT_ERROR in jobsp.h */
#if !defined(__sun) && !defined(___MVS__)
GBLREF int sys_nerr;
#endif
@@ -81,15 +70,26 @@ GBLREF int sys_nerr;
#endif
GBLREF char **environ;
+GBLREF char gtm_dist[GTM_PATH_MAX];
#ifdef __osf__
#pragma pointer_size (restore)
#endif
-error_def(ERR_JOBFAIL);
-error_def(ERR_JOBPARTOOLONG);
-error_def(ERR_LOGTOOLONG);
-error_def(ERR_TEXT);
+#define MAX_JOB_LEN 8192 /* Arbitrary length maximum used for checking job arguments and parameters */
+#define MAX_PATH 128 /* Maximum file path length */
+#define MAX_LAB_LEN 32 /* Maximum Label string length */
+#define MAX_RTN_LEN 32 /* Maximum Routine string length */
+#define TEMP_BUFF_SIZE 1024
+#define PARM_STRING_SIZE 9
+#define MAX_NUM_LEN 10 /* Maximum length number will be when converted to string */
+#define MAX_JOB_QUALS 12 /* Maximum environ variables set for job qualifiers */
+#define MUMPS_EXE_STR "/mumps"
+#define MUMPS_DIRECT_STR "-direct"
+#define GTMJ_FMT "gtmj%03d="
+#define PARM_STR "gtmj000="
+#define JOB_CONTINUE 1
+#define JOB_EXIT 0
#define KILL_N_REAP(PROCESS_ID, SIGNAL, RET_VAL) \
{ \
@@ -101,69 +101,137 @@ error_def(ERR_TEXT);
} \
}
-/* Note that this module uses _exit instead of exit to avoid running the inherited
- exit handlers which this mid-level process does not want to run */
+#define FORK_RETRY(PID) \
+{ \
+ FORK(PID); /* BYPASSOK: we die after creating a child, no FORK_CLEAN needed */ \
+ while (-1 == PID) \
+ { \
+ assertpro(EAGAIN == errno || ENOMEM == errno); \
+ usleep(50000); \
+ FORK(PID); /* BYPASSOK: we die after creating a child, no FORK_CLEAN needed */ \
+ } \
+}
-/* if we get an error assembling the child environment,
- we don't want a rogue child running loose */
+error_def(ERR_JOBFAIL);
+error_def(ERR_JOBPARTOOLONG);
+error_def(ERR_LOGTOOLONG);
+error_def(ERR_TEXT);
+
+/* Note that this module uses _exit instead of exit to avoid running the inherited exit handlers which this mid-level process does
+ * not want to run.
+ */
void job_term_handler(int sig);
+static int io_rename(job_params_type *jparms, const int jobid);
-static CONDITION_HANDLER(bad_child)
+/* 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
+ * executed. That condition handler might not be adequate to handle the rts_error happened in the context of middle process.
+ * Hence middle process is provided with its own condition handler.
+ */
+static CONDITION_HANDLER(middle_child)
{
- PRN_ERROR;
+ int pipe_status;
+ /* As of now, middle process could encounter rts_error only while setting entryref. Hence the following assert. */
+ assert(joberr == joberr_rtn);
+ DOWRITERC(pipe_fd, &job_errno, SIZEOF(job_errno), pipe_status);
_exit(joberr);
}
-#define FAILED_TO_LAUNCH 1
+/* Following condition handles the rts_error occurred in the grandchild before doing execv(). Sinec we have not started executing
+ * M-cmd specified as a part of JOB command, it is enough to print the error and exit.
+ */
+static CONDITION_HANDLER(grand_child)
+{
+ PRN_ERROR;
+ _exit(EXIT_SUCCESS);
+}
-/* This is to close the window of racing condition where the timeout occurs and actually
- * by that time, the middle process had already successfully forked the job
+/* This is to close the window of race condition where the timeout occurs and actually by that time, the middle process had already
+ * successfully forked-off the job.
*/
-void job_term_handler(int sig){
- if (job_launched)
- _exit(0);
- else
- _exit(FAILED_TO_LAUNCH);
+void job_term_handler(int sig)
+{
+ int ret;
+ int status;
+ joberr_t exit_status = joberr_gen;
+ /*
+ * ret = 0 - Child is present but not changed the state
+ * < 0 - Error. No child present.
+ * > 0 - Child PID.
+ */
+ ret = waitpid(-1, &status, WNOHANG); /* BYPASSOK */
+ job_errno = errno;
+ if (0 == ret)
+ return;
+ else if ( 0 > ret)
+ _exit(exit_status);
+ else
+ return;
+}
+
+static int io_rename(job_params_type *jparms, const int jobid)
+{
+ char path[MAX_STDIOE_LEN];
+
+ strncpy(path, jparms->output.addr, jparms->output.len);
+ *(jparms->output.addr + jparms->output.len) = '\0';
+ SPRINTF(&path[jparms->output.len], ".%d", jobid);
+ if (rename(jparms->output.addr, path))
+ {
+ job_errno = errno;
+ return(joberr_stdout_rename);
+ }
+ strncpy(path, jparms->error.addr, jparms->error.len);
+ *(jparms->error.addr + jparms->error.len) = '\0';
+ SPRINTF(&path[jparms->error.len], ".%d", jobid);
+ if (rename(jparms->error.addr, path))
+ {
+ job_errno = errno;
+ return(joberr_stderr_rename);
+ }
+ return 0;
}
/*
- * ---------------------------------------------------------------------------------------------------------------------
- * The current process (P) FORKs a middle child process (M) that tests various job parameters. It then forks off the
- * actual Job (J) and exits, culminating the parent's (P) wait. The Job process (J) sets up its env and exexs mumps.
+ * --------------------------------------------------------------------------------------------------------------------------------
+ * The current process (P) FORKs a middle child process (M) that tests various job parameters. It then forks off the actual Job (J)
+ * and exits, culminating the parent's (P) wait. The Job process (J) sets up its env and execs mumps.
*
* Arguments
* First argument is a pointer to the structure holding Job parameter values.
* Second argument is the number of parameters being passed.
- * The third boolean argument indicates to the caller if the return from this function was due to an exit from the
- * middle process or due to reasons other than that. It is set to true for the latter case of return.
- * Fourth argument is the pair of file descriptors [opened by pipe] for the child process (M) to write PID
- * of the jobbed off process (J).
+ * The third boolean argument indicates to the caller if the return from this function was due to an exit from the middle
+ * process or due to reasons other than that. It is set to true for the latter case of return.
+ * Fourth argument is the pair of file descriptors [opened by pipe] for the child process (M) to write PID of the jobbed off
+ * process (J).
*
* Return:
* Exit status of child (that the parent gets by WAITing) in case the return was after an exit from the middle process.
- * errno in other cases with the third argument set to TRUE and returned by pointer.
+ * Errno in other cases with the third argument set to TRUE and returned by pointer.
* TIMEOUT_ERROR in case a timeout occured.
* Return zero indicates success.
- * ---------------------------------------------------------------------------------------------------------------------
+ * --------------------------------------------------------------------------------------------------------------------------------
*/
int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_return, int pipe_fds[])
{
char cbuff[TEMP_BUFF_SIZE], pbuff[TEMP_BUFF_SIZE], cmdbuff[TEMP_BUFF_SIZE];
- char tbuff[MAX_JOB_LEN], tbuff2[MAX_JOB_LEN];
+ char tbuff[MAX_JOB_LEN], tbuff2[MAX_JOB_LEN], fname_buf[MAX_STDIOE_LEN];
char *pgbldir_str;
char *transfer_addr;
int4 index, environ_count, string_len, temp;
int wait_status, save_errno, kill_ret;
- int rc;
- bool status;
+ int rc, dup_ret, in_fd;
+ int status;
pid_t par_pid, child_pid, done_pid;
job_parm *jp;
rhdtyp *base_addr;
struct sigaction act, old_act;
int pipe_status, env_len;
+ int mproc_fds[2]; /* pipe between middle process and grandchild process */
+ int decision;
#ifdef __osf__
/* These must be O/S-compatible 64-bit pointers for OSF/1. */
@@ -179,108 +247,174 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
#ifdef __osf__
#pragma pointer_size (restore)
#endif
- job_launched = FALSE;
- par_pid = process_id;
- if (-1 == (child_pid = fork())) /* BYPASSOK: we die after creating a child, no FORK_CLEAN needed */
- {
- if (EAGAIN == errno || ENOMEM == errno)
- job_try_again = TRUE;
- *non_exit_return = TRUE;
- return (errno);
- }
+ par_pid = getppid();
+ FORK_RETRY(child_pid);
if (child_pid == 0)
{
- /* This is a child process (middle process, M) */
- /* Test out various parameters and setup everything possible for the actual Job (J), so it(J) can
- * start off without much hitch. If any error occurs during this, exit with appropriate status so
- * the waiting parent can diagnose.
+ /* This is a child process (middle process, M)
+ * Test out various parameters and setup everything possible for the actual Job (J), so it(J) can start off without
+ * much hitch. If any error occurs during this, exit with appropriate status so the waiting parent can diagnose.
*/
/* 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;
- ESTABLISH_RET(bad_child, 0);
+ job_errno = -1;
+ pipe_fd = pipe_fds[1];
+ ESTABLISH_RET(middle_child, 0);
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
act.sa_handler = job_term_handler;
sigaction(SIGTERM, &act, &old_act);
- if (!jobpid) /* if the Job pid need not be appended to the std-in/out/err file names */
+ OPEN_PIPE(mproc_fds, pipe_status);
+ if (-1 == pipe_status)
{
- joberr = joberr_io;
- /* attempt to open output files */
- /* this also redirects stdin/out/err, so any error messages by this process during
- * the creation of the Job will get redirected */
- if (!(status = ojchildioset(jparms)))
- {
- if (job_try_again)
- joberr += joberr_tryagain;
- rts_error(VARLSTCNT(6) ERR_JOBFAIL, 0, ERR_TEXT, 2,
- LEN_AND_LIT("Failed to set STDIN/OUT/ERR for the job"));
- }
- } /* else, all the errors during the creation of Job go to the STDOUT/ERR of the parent process */
+ joberr = joberr_pipe_mgc;
+ job_errno = errno;
+ DOWRITERC(pipe_fds[1], &job_errno, SIZEOF(job_errno), pipe_status);
+ _exit(joberr);
+ }
+ /* Redirect input before potentially changing the default directory below.*/
+ strncpy(fname_buf, jparms->input.addr, jparms->input.len);
+ *(fname_buf + jparms->input.len) = '\0';
- joberr = joberr_cd; /* pass current directory to child */
- if (jparms->directory.len != 0)
+ OPENFILE(fname_buf, O_RDONLY, in_fd);
+ if (FD_INVALID == in_fd)
+ {
+ joberr = joberr_io_stdin_open;
+ job_errno = errno;
+ return joberr;
+ }
+ CLOSEFILE(0, rc);
+ FCNTL3(in_fd, F_DUPFD, 0, dup_ret);
+ if (-1 == dup_ret)
+ {
+ joberr = joberr_io_stdin_dup;
+ job_errno = errno;
+ return joberr;
+ }
+#ifdef __MVS__
+ /* policy tagging because by default input is /dev/null */
+ if (-1 == gtm_zos_tag_to_policy(in_fd, TAG_UNTAGGED, &realfiletag))
+ TAG_POLICY_SEND_MSG(fname_buf, errno, realfiletag, TAG_UNTAGGED);
+#endif
+ CLOSEFILE_RESET(in_fd, rc); /* resets "in_fd" to FD_INVALID */
+ if (0 != jparms->directory.len)
{
/* If directory is specified, change it */
if (jparms->directory.len > TEMP_BUFF_SIZE)
- rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG);
-
+ {
+ joberr = joberr_cd_toolong;
+ DOWRITERC(pipe_fds[1], &job_errno, SIZEOF(job_errno), pipe_status);
+ _exit(joberr);
+ }
strncpy(pbuff, jparms->directory.addr, jparms->directory.len);
*(pbuff + jparms->directory.len) = '\0';
+
if (CHDIR(pbuff) != 0)
{
- if (ETIMEDOUT == errno) /* atleast on AIX */
- joberr += joberr_tryagain;
- rts_error(VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2,
- LEN_AND_LIT("Error changing directory for the Job."),errno);
+ joberr = joberr_cd;
+ job_errno = errno;
+ DOWRITERC(pipe_fds[1], &job_errno, SIZEOF(errno), pipe_status);
+ _exit(joberr);
}
}
+ /* attempt to open output files. This also redirects stdin/out/err, so any error messages by this process during the
+ * creation of the Job will get redirected.
+ */
+ if ((status = ojchildioset(jparms)))
+ {
+ DOWRITERC(pipe_fds[1], &job_errno, SIZEOF(job_errno), pipe_status);
+ _exit(status);
+ }
+
joberr = joberr_rtn;
- job_addr(&jparms->routine, &jparms->label, jparms->offset, (char **)&base_addr, &transfer_addr);
+ if (!job_addr(&jparms->routine, &jparms->label, jparms->offset, (char **)&base_addr, &transfer_addr))
+ {
+ DOWRITERC(pipe_fds[1], &job_errno, SIZEOF(job_errno), pipe_status);
+ _exit(joberr);
+ }
- joberr = joberr_syscall;
+ joberr = joberr_sid;
if (-1 == setsid())
- rts_error(VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2,
- LEN_AND_LIT("Error setting session id for the Job."), errno);
+ {
+ job_errno = errno;
+ DOWRITERC(pipe_fds[1], &job_errno, SIZEOF(job_errno), pipe_status);
+ _exit(joberr);
+ }
- joberr = joberr_frk;
/* clone self and exit */
- if (0 != (child_pid = fork())) /* BYPASSOK: we exec immediately, no FORK_CLEAN needed */
+ FORK_RETRY(child_pid);
+ if (child_pid) /* BYPASSOK: we exec immediately, no FORK_CLEAN needed */
{
/* This is still the middle process. */
- if (0 > child_pid)
- {
- if (EAGAIN == errno || ENOMEM == errno)
- joberr += joberr_tryagain;
- rts_error(VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2,
- LEN_AND_LIT("Error forking the Job."), errno);
- } else
+ /* Close the read end of the pipe between middle process and grandchild process. */
+ CLOSEFILE_RESET(mproc_fds[0], pipe_status); /* resets "pipe_fds[0]" to FD_INVALID */
+ assert(SIZEOF(pid_t) == SIZEOF(child_pid));
+ /* if the Job pid need to be appended to the std out/err file names */
+ if (jobpid)
{
- job_launched = TRUE;
-
- assert(SIZEOF(pid_t) == SIZEOF(child_pid));
- /* write child_pid into pipe to be read by parent process(P) for $ZJOB */
- DOWRITERC(pipe_fds[1], &child_pid, SIZEOF(child_pid), pipe_status);
- if (0 != pipe_status)
+ joberr = io_rename(jparms, child_pid);
+ if (joberr)
{
- rts_error(VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2,
- LEN_AND_LIT("Error writing to pipe"), errno);
+ /* Inform grandchild that it will have to exit. If pipe operation failed terminate
+ * the grandchild.
+ */
+ decision = JOB_EXIT;
+ DOWRITERC(mproc_fds[1], &decision, SIZEOF(decision), pipe_status);
+ if (pipe_status)
+ kill(child_pid, SIGTERM);
+ DOWRITERC(pipe_fds[1], &job_errno, SIZEOF(job_errno), pipe_status);
+ _exit(joberr);
}
- _exit(0);
}
+ /* write child_pid into pipe to be read by parent process(P) for $ZJOB */
+ DOWRITERC(pipe_fds[1], &child_pid, SIZEOF(child_pid), pipe_status);
+ /* Failed to send parent new JOBID. Terminate the child and exit middle process. */
+ if (pipe_status)
+ {
+ /* Inform grandchild that it will have to exit. If pipe operation failed terminate the
+ * grandchild.
+ */
+ joberr = joberr_pipe_mp;
+ decision = JOB_EXIT;
+ DOWRITERC(mproc_fds[1], &decision, SIZEOF(decision), pipe_status);
+ if (pipe_status)
+ kill(child_pid, SIGTERM);
+ _exit(joberr);
+ } else
+ {
+ /* 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);
+ /* If pipe_status is non-zero i.e. error occurred in pipe operation or total
+ * SIZEOF(decision) bytes are not written in the pipe. In this case, we let the grandchild
+ * handle its own fate as we have already conveyed back the grandchild's pid to parent
+ * process and all the setup for the grandchild is successfully done.
+ */
+ }
+ _exit(EXIT_SUCCESS);
}
-
- /* This is now the grandchild process (actual Job process) -- an orphan as soon as the exit(0) above occurs. */
- /* set up the environment and exec */
-
+ /* 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;
+ ESTABLISH_RET(grand_child, 0);
sigaction(SIGTERM, &old_act, 0); /* restore the SIGTERM handler */
-
- joberr = joberr_io;
+ CLOSEFILE_RESET(mproc_fds[1], pipe_status); /* resets "mproc_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 */
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2,
+ LEN_AND_LIT("Error reading from pipe"), errno);
+ 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);
@@ -337,7 +471,7 @@ 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)
- rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG);
c1 = (char *)malloc(string_len + 1);
#ifdef KEEP_zOS_EBCDIC
#pragma convlit(suspend)
@@ -354,12 +488,12 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
if (jparms->gbldir.len != 0)
{
if (jparms->gbldir.len > TEMP_BUFF_SIZE)
- rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG);
strncpy(pbuff, jparms->gbldir.addr, jparms->gbldir.len);
*(pbuff + jparms->gbldir.len) = '\0';
string_len = STRLEN("%s=%s") + STRLEN(GBLDIR_ENV) + STRLEN(pbuff) - 4;
if (string_len > TEMP_BUFF_SIZE)
- rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG);
c1 = (char *)malloc(string_len + 1);
#ifdef KEEP_zOS_EBCDIC
#pragma convlit(suspend)
@@ -373,12 +507,12 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
if (jparms->startup.len != 0)
{
if (jparms->startup.len > TEMP_BUFF_SIZE)
- rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG);
strncpy(pbuff, jparms->startup.addr, jparms->startup.len);
*(pbuff + jparms->startup.len) = '\0';
string_len = STRLEN("%s=%s") + STRLEN(STARTUP_ENV) + STRLEN(pbuff) - 4;
if (string_len > TEMP_BUFF_SIZE)
- rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG);
c1 = (char *)malloc(string_len + 1);
#ifdef KEEP_zOS_EBCDIC
#pragma convlit(suspend)
@@ -392,12 +526,12 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
if (jparms->input.len != 0)
{
if (jparms->input.len > TEMP_BUFF_SIZE)
- rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG);
strncpy(pbuff, jparms->input.addr, jparms->input.len);
*(pbuff + jparms->input.len) = '\0';
string_len = STRLEN("%s=%s") + STRLEN(IN_FILE_ENV) + STRLEN(pbuff) - 4;
if (string_len > TEMP_BUFF_SIZE)
- rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG);
c1 = (char *)malloc(string_len + 1);
#ifdef KEEP_zOS_EBCDIC
#pragma convlit(suspend)
@@ -412,14 +546,14 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
if (jparms->output.addr != 0)
{
if (jparms->output.len > TEMP_BUFF_SIZE)
- rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG);
strncpy(pbuff, jparms->output.addr, jparms->output.len);
*(pbuff + jparms->output.len) = '\0';
if (jobpid)
SPRINTF(&pbuff[jparms->output.len], ".%d", getpid());
string_len = STRLEN("%s=%s") + STRLEN(OUT_FILE_ENV) + STRLEN(pbuff) - 4;
if (string_len > TEMP_BUFF_SIZE)
- rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG);
c1 = (char *)malloc(string_len + 1);
#ifdef KEEP_zOS_EBCDIC
#pragma convlit(suspend)
@@ -434,14 +568,14 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
if (jparms->error.len != 0)
{
if (jparms->error.len > TEMP_BUFF_SIZE)
- rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG);
strncpy(pbuff, jparms->error.addr, jparms->error.len);
*(pbuff + jparms->error.len) = '\0';
if (jobpid)
SPRINTF(&pbuff[jparms->error.len], ".%d", getpid());
string_len = STRLEN("%s=%s") + STRLEN(ERR_FILE_ENV) + STRLEN(pbuff) - 4;
if (string_len > TEMP_BUFF_SIZE)
- rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG);
c1 = (char *)malloc(string_len + 1);
#ifdef KEEP_zOS_EBCDIC
#pragma convlit(suspend)
@@ -456,12 +590,12 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
if (jparms->routine.len != 0)
{
if (jparms->routine.len > TEMP_BUFF_SIZE)
- rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG);
strncpy(pbuff, jparms->routine.addr, jparms->routine.len);
*(pbuff + jparms->routine.len) = '\0';
string_len = STRLEN("%s=%s") + STRLEN(ROUTINE_ENV) + STRLEN(pbuff) - 4;
if (string_len > TEMP_BUFF_SIZE)
- rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG);
c1 = (char *)malloc(string_len + 1);
#ifdef KEEP_zOS_EBCDIC
#pragma convlit(suspend)
@@ -474,12 +608,12 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
/* pass label name to child */
if (jparms->label.len > TEMP_BUFF_SIZE)
- rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG);
strncpy(pbuff, jparms->label.addr, jparms->label.len);
*(pbuff + jparms->label.len) = '\0';
string_len = STRLEN("%s=%s") + STRLEN(LABEL_ENV) + STRLEN(pbuff) - 4;
if (string_len > TEMP_BUFF_SIZE)
- rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG);
c1 = (char *)malloc(string_len + 1);
#ifdef KEEP_zOS_EBCDIC
#pragma convlit(suspend)
@@ -492,7 +626,7 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
/* pass the offset */
string_len = STRLEN("%s=%ld") + STRLEN(OFFSET_ENV) + MAX_NUM_LEN - 5;
if (string_len > TEMP_BUFF_SIZE)
- rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG);
c1 = (char *)malloc(string_len + 1);
#ifdef KEEP_zOS_EBCDIC
#pragma convlit(suspend)
@@ -507,7 +641,7 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
{
string_len = STRLEN("%s=%ld") + STRLEN(PRIORITY_ENV) + MAX_NUM_LEN - 5;
if (string_len > TEMP_BUFF_SIZE)
- rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG);
c1 = (char *)malloc(string_len + 1);
#ifdef KEEP_zOS_EBCDIC
#pragma convlit(suspend)
@@ -521,13 +655,13 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
for (index = 0, jp = jparms->parms; jp ; index++, jp = jp->next)
{
if (jp->parm->str.len > MAX_JOB_LEN - 2)
- rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG);
if (0 != jp->parm->mvtype)
{
MV_FORCE_STR(jp->parm);
string_len = STRLEN(PARM_STR) + jp->parm->str.len + 1;
if (string_len > MAX_JOB_LEN)
- rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG);
c1 = (char *)malloc(string_len);
# ifdef KEEP_zOS_EBCDIC
__getEstring1_a_copy(c1, STR_AND_LEN(PARM_STRING));
@@ -542,7 +676,7 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
}
string_len = STRLEN("%s=%ld") + STRLEN(GTMJCNT_ENV) + MAX_NUM_LEN - 5;
if (string_len > TEMP_BUFF_SIZE)
- rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG);
c1 = (char *)malloc(string_len + 1);
#ifdef KEEP_zOS_EBCDIC
#pragma convlit(suspend)
@@ -594,7 +728,7 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
#pragma pointer_size (restore)
#endif
- c1 = GETENV("gtm_dist");
+ c1 = gtm_dist;
string_len = STRLEN(c1);
if ((string_len + SIZEOF(MUMPS_EXE_STR)) < SIZEOF(tbuff))
{
@@ -602,7 +736,8 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
c2 = &tbuff[string_len];
strcpy(c2, MUMPS_EXE_STR);
} else
- rts_error(VARLSTCNT(5) ERR_LOGTOOLONG, 3, string_len, c1, SIZEOF(tbuff) - SIZEOF(MUMPS_EXE_STR));
+ 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)
@@ -616,7 +751,7 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
if (jparms->cmdline.len != 0)
{
if (jparms->cmdline.len > TEMP_BUFF_SIZE)
- rts_error(VARLSTCNT(1) ERR_JOBPARTOOLONG);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JOBPARTOOLONG);
memcpy(cmdbuff, jparms->cmdline.addr, jparms->cmdline.len);
*(cmdbuff + jparms->cmdline.len) = 0;
} else
@@ -634,7 +769,7 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
EXECVE(tbuff, argv, env_ary);
/* if we got here, error starting the Job */
- rts_error(VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2, LEN_AND_LIT("Exec error in Job"), errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2, LEN_AND_LIT("Exec error in Job"), errno);
REVERT;
} else
{
@@ -665,13 +800,13 @@ int ojstartchild (job_params_type *jparms, int argcnt, boolean_t *non_exit_retur
WAITPID(child_pid, &wait_status, 0, done_pid);
if (done_pid == child_pid)
return (wait_status);
- } else if (-1 != kill_ret && done_pid == child_pid && 0 == wait_status)
- return 0; /* timer popped in the window of child fork and middle process exit */
+ } else if (-1 != kill_ret && done_pid == child_pid)
+ return (wait_status); /* timer popped in the window of child fork and middle process exit */
*non_exit_return = TRUE;
return TIMEOUT_ERROR; /* return special value so as to eliminate the window where the timer
* might pop after this routine returns to the callee and before the callee
* analyses the return status (ojtimeout may not be a reliable indicator) */
- } else if (0 > done_pid)
+ } else if (0 > done_pid) /* Some other signal received OR there is no child to be waited on */
{
*non_exit_return = TRUE;
save_errno = errno;
diff --git a/sr_unix/op_fnfgncal.c b/sr_unix/op_fnfgncal.c
index d4b3988..e932216 100644
--- a/sr_unix/op_fnfgncal.c
+++ b/sr_unix/op_fnfgncal.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -14,6 +14,9 @@
#include "gtm_string.h"
#include <stdarg.h>
#include <errno.h>
+#ifdef GTM_PTHREAD
+# include <pthread.h>
+#endif
#include "gtm_stdlib.h"
#include "stringpool.h"
@@ -58,7 +61,7 @@
*
* would result in the following call:
*
- * op_fnfgncal(8, 0, mval*("package"), mval*("bessel"), 4, 3, mval*(p1), mval*(p2), mval*(p3))
+ * op_fnfgncal(8, 0, mval*("mathpak"), mval*("bessel"), 4, 3, mval*(p1), mval*(p2), mval*(p3))
*
* where, mval*(val) indicates the address of an mval that has the string value val.
*
@@ -102,7 +105,13 @@ GBLREF spdesc stringpool;
GBLREF int (*callintogtm_vectortable[])();
GBLREF int mumps_status;
GBLREF volatile int4 gtmMallocDepth;
+#ifdef GTM_PTHREAD
+GBLREF boolean_t gtm_jvm_process;
+GBLREF pthread_t gtm_main_thread_id;
+GBLREF boolean_t gtm_main_thread_id_set;
+#endif
+error_def(ERR_JNI);
error_def(ERR_MAXSTRLEN);
error_def(ERR_TEXT);
error_def(ERR_UNIMPLOP);
@@ -116,22 +125,96 @@ error_def(ERR_ZCSTATUSRET);
error_def(ERR_ZCUSRRTN);
error_def(ERR_ZCVECTORINDX);
-STATICDEF int call_table_initialized = 0;
+STATICDEF int call_table_initialized = 0;
+/* The following are one-letter mnemonics for Java argument types (capital letters to denote output direction):
+ * boolean int long float double String byte[] */
+STATICDEF char gtm_jtype_chars[] = { 'b', 'i', 'l', 'f', 'd', 'j', 'a',
+ 'B', 'I', 'L', 'F', 'D', 'J', 'A' };
+STATICDEF int gtm_jtype_start_idx = gtm_jboolean, /* Value of first gtm_j... type for calculation of table indices. */
+ gtm_jtype_count = gtm_jbyte_array - gtm_jboolean + 1; /* Number of types supported with Java call-outs. */
-STATICFNDCL void extarg2mval(void *src, enum gtm_types typ, mval *dst);
-STATICFNDCL int extarg_getsize(void *src, enum gtm_types typ, mval *dst);
+STATICFNDCL void extarg2mval(void *src, enum gtm_types typ, mval *dst, boolean_t java, boolean_t starred);
+STATICFNDCL int extarg_getsize(void *src, enum gtm_types typ, mval *dst);
+STATICFNDCL void op_fgnjavacal(mval *dst, mval *package, mval *extref, uint4 mask, int4 argcnt, int4 entry_argcnt,
+ struct extcall_package_list *package_ptr, struct extcall_entry_list *entry_ptr, va_list var);
/* Routine to convert external return values to mval's */
-STATICFNDEF void extarg2mval(void *src, enum gtm_types typ, mval *dst)
+STATICFNDEF void extarg2mval(void *src, enum gtm_types typ, mval *dst, boolean_t java, boolean_t starred)
{
- gtm_long_t str_len;
gtm_int_t s_int_num;
+ gtm_long_t str_len, s_long_num;
gtm_uint_t uns_int_num;
- gtm_long_t s_long_num;
gtm_ulong_t uns_long_num;
char *cp;
struct extcall_string *sp;
+ if (java)
+ {
+ switch(typ)
+ {
+ case gtm_notfound:
+ break;
+ case gtm_void:
+ break;
+ case gtm_status:
+ /* Note: reason for double cast is to first turn ptr to same sized int, then big int to little int
+ * (on 64 bit platforms). This avoids a warning msg with newer 64 bit gcc compilers.
+ */
+ s_int_num = (gtm_int_t)(intszofptr_t)src;
+ if (0 != s_int_num)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZCSTATUSRET);
+ MV_FORCE_MVAL(dst, s_int_num);
+ break;
+ case gtm_jboolean:
+ case gtm_jint:
+ if (starred)
+ s_int_num = *((gtm_int_t *)src);
+ else
+ s_int_num = (gtm_int_t)(intszofptr_t)src;
+ MV_FORCE_MVAL(dst, s_int_num);
+ break;
+ case gtm_jlong:
+# ifdef GTM64
+ if (starred)
+ s_long_num = *((gtm_long_t *)src);
+ else
+ s_long_num = (gtm_long_t)src;
+ MV_FORCE_LMVAL(dst, s_long_num);
+# else
+ i82mval(dst, *(gtm_int64_t *)src);
+# endif
+ break;
+ case gtm_jfloat:
+ float2mval(dst, *((float *)src));
+ break;
+ case gtm_jdouble:
+ double2mval(dst, *((double *)src));
+ break;
+ case gtm_jstring:
+ case gtm_jbyte_array:
+ sp = (struct extcall_string *)src;
+ dst->mvtype = MV_STR;
+ if (sp->len > MAX_STRLEN)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MAXSTRLEN);
+ dst->str.len = (mstr_len_t)sp->len;
+ if ((0 < sp->len) && (NULL != sp->addr))
+ {
+ dst->str.addr = sp->addr;
+ s2pool(&dst->str);
+ /* In case of GTMByteArray or GTMString, the buffer is allocated in xc_gateway.c (since the
+ * user might need to return a bigger buffer than the original array size will allow (in
+ * case of a string the content is immutable). So, if we have determined that the provided
+ * value buffer is legitimate (non-null and non-empty), we free it on the GT.M side. */
+ free(sp->addr);
+ }
+ break;
+ default:
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP);
+ break;
+ }
+ return;
+ }
+ /* The following switch is for non-Java call-outs. */
switch(typ)
{
case gtm_notfound:
@@ -144,7 +227,7 @@ STATICFNDEF void extarg2mval(void *src, enum gtm_types typ, mval *dst)
*/
s_int_num = (gtm_int_t)(intszofptr_t)src;
if (0 != s_int_num)
- dec_err(VARLSTCNT(1) ERR_ZCSTATUSRET, 0, s_int_num);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZCSTATUSRET);
MV_FORCE_MVAL(dst, s_int_num);
break;
case gtm_int:
@@ -183,7 +266,7 @@ STATICFNDEF void extarg2mval(void *src, enum gtm_types typ, mval *dst)
sp = (struct extcall_string *)src;
dst->mvtype = MV_STR;
if (sp->len > MAX_STRLEN)
- rts_error(VARLSTCNT(1) ERR_MAXSTRLEN);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MAXSTRLEN);
dst->str.len = (mstr_len_t)sp->len;
if ((0 < sp->len) && (NULL != sp->addr))
{
@@ -192,7 +275,7 @@ STATICFNDEF void extarg2mval(void *src, enum gtm_types typ, mval *dst)
}
break;
case gtm_float_star:
- double2mval(dst, (double)*((float *)src));
+ float2mval(dst, *((float *)src));
break;
case gtm_char_star:
cp = (char *)src;
@@ -200,7 +283,7 @@ STATICFNDEF void extarg2mval(void *src, enum gtm_types typ, mval *dst)
dst->mvtype = MV_STR;
str_len = STRLEN(cp);
if (str_len > MAX_STRLEN)
- rts_error(VARLSTCNT(1) ERR_MAXSTRLEN);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MAXSTRLEN);
dst->str.len = (mstr_len_t)str_len;
dst->str.addr = cp;
s2pool(&dst->str);
@@ -209,13 +292,13 @@ STATICFNDEF void extarg2mval(void *src, enum gtm_types typ, mval *dst)
if (!src)
dst->mvtype = 0;
else
- extarg2mval(*((char **)src), gtm_char_star, dst);
+ extarg2mval(*((char **)src), gtm_char_star, dst, java, starred);
break;
case gtm_double_star:
double2mval(dst, *((double *)src));
break;
default:
- rts_error(VARLSTCNT(1) ERR_UNIMPLOP);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP);
break;
}
return;
@@ -224,15 +307,13 @@ STATICFNDEF void extarg2mval(void *src, enum gtm_types typ, mval *dst)
/* Subroutine to calculate stringpool requirements for an external argument */
STATICFNDEF int extarg_getsize(void *src, enum gtm_types typ, mval *dst)
{
- int4 n;
char *cp, **cpp;
struct extcall_string *sp;
if (!src)
return 0;
switch(typ)
- {
- /* The following group of cases either return nothing or use the numeric part of the mval */
+ { /* The following group of cases either return nothing or use the numeric part of the mval */
case gtm_notfound:
case gtm_void:
case gtm_double_star:
@@ -246,6 +327,11 @@ STATICFNDEF int extarg_getsize(void *src, enum gtm_types typ, mval *dst)
case gtm_uint_star:
case gtm_long_star:
case gtm_ulong_star:
+ case gtm_jboolean:
+ case gtm_jint:
+ case gtm_jlong:
+ case gtm_jfloat:
+ case gtm_jdouble:
return 0;
case gtm_char_starstar:
cpp = (char **)src;
@@ -256,6 +342,8 @@ STATICFNDEF int extarg_getsize(void *src, enum gtm_types typ, mval *dst)
case gtm_char_star:
cp = (char *)src;
return STRLEN(cp);
+ case gtm_jstring:
+ case gtm_jbyte_array:
case gtm_string_star:
sp = (struct extcall_string *)src;
if ((0 < sp->len)
@@ -271,31 +359,326 @@ STATICFNDEF int extarg_getsize(void *src, enum gtm_types typ, mval *dst)
return (int)(sp->len);
break;
default:
- rts_error(VARLSTCNT(1) ERR_UNIMPLOP);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP);
break;
}
return 0; /* This should never get executed, added to make compiler happy */
}
+STATICFNDEF void op_fgnjavacal(mval *dst, mval *package, mval *extref, uint4 mask, int4 argcnt, int4 entry_argcnt,
+ struct extcall_package_list *package_ptr, struct extcall_entry_list *entry_ptr, va_list var)
+{
+ boolean_t error_in_xc = FALSE;
+ char *free_string_pointer, *free_string_pointer_start, jtype_char;
+ char str_buffer[MAX_NAME_LENGTH], *tmp_buff_ptr, *jni_err_buf;
+ char *types_descr_ptr, *types_descr_dptr, *xtrnl_table_name;
+ gparam_list *param_list;
+ gtm_long_t *free_space_pointer;
+ int i, j, save_mumps_status;
+ int4 m1, m2, n;
+ INTPTR_T status;
+ mval *v;
+ va_list var_copy;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+# ifdef GTM_PTHREAD
+ assert(gtm_jvm_process == gtm_main_thread_id_set);
+ gtm_jvm_process = TRUE;
+ if (!gtm_main_thread_id_set)
+ {
+ gtm_main_thread_id = pthread_self();
+ gtm_main_thread_id_set = TRUE;
+ }
+# endif
+ /* This is how many parameters we will use for callg, including the implicit ones described below. So, better make
+ * sure we are not trying to pass more than callg can handle.
+ */
+ if (MAX_ACTUALS < argcnt + 3)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZCMAXPARAM);
+ VAR_COPY(var_copy, var);
+ /* Compute size of parameter block */
+ n = entry_ptr->parmblk_size + (3 * SIZEOF(void *)); /* This is enough for the parameters and the fixed length entries */
+ mask >>= 2; /* Bypass the class and method arguments. */
+ /* The first byte of the first argument (types_descr_ptr) stores the number of expected arguments, according to the external
+ * calls table; the second byte describes the expected return type, and subsequent bytes---the expected argument types using
+ * a one-character mnemonic which gets deciphered in the JNI layer. Note that in case of an error the xc_gateway.c module
+ * would set the first byte to 0xFF, followed by an address at which the error message is stored. For that reason, we
+ * allocate more space than we might strictly need for the arguments, return type, and type descriptor.
+ */
+ types_descr_ptr = (char *)malloc(MAX(SIZEOF(char) * (argcnt + 2), SIZEOF(char *) * 2));
+ types_descr_dptr = types_descr_ptr;
+ *types_descr_dptr = (char)entry_argcnt;
+ types_descr_dptr++;
+ if (dst)
+ { /* Record the expected return type. */
+ switch (entry_ptr->return_type)
+ {
+ case gtm_status:
+ *types_descr_dptr = 'i';
+ break;
+ case gtm_jlong:
+ *types_descr_dptr = 'l';
+ break;
+ default:
+ *types_descr_dptr = 'v';
+ }
+ } else
+ *types_descr_dptr = 'v';
+ types_descr_dptr++;
+ assert(2 * gtm_jtype_count == SIZEOF(gtm_jtype_chars));
+ for (i = argcnt + 2, j = -2, m1 = entry_ptr->input_mask, m2 = mask & entry_ptr->output_mask; 0 < i; i--, j++)
+ { /* Enforce mval values and record expected argument types. */
+ v = va_arg(var, mval *);
+ if (0 > j)
+ {
+ MV_FORCE_STR(v);
+ n += v->str.len + SIZEOF(gtm_long_t) + 1;
+ continue;
+ }
+ if (m1 & 1)
+ {
+ if ((gtm_jstring == entry_ptr->parms[j]) || (gtm_jbyte_array == entry_ptr->parms[j]))
+ {
+ MV_FORCE_STR(v);
+ n += v->str.len + SIZEOF(gtm_long_t) + 1;
+ } else
+ {
+ MV_FORCE_DEFINED(v);
+ }
+ }
+ jtype_char = entry_ptr->parms[j] - gtm_jtype_start_idx;
+ if ((0 > jtype_char) || (gtm_jtype_count <= jtype_char))
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP);
+ else
+ *types_descr_dptr = gtm_jtype_chars[(m2 & 1) ? (gtm_jtype_count + jtype_char) : jtype_char];
+ types_descr_dptr++;
+ m1 >>= 1;
+ m2 >>= 1;
+ }
+ va_end(var);
+ /* Double the size, to take care of any alignments in the middle. */
+ param_list = (gparam_list *)malloc(n * 2);
+ param_list->arg[0] = (void *)types_descr_ptr;
+ /* Adding 3 to account for type descriptions, class name, and method name arguments. */
+ free_space_pointer = (gtm_long_t *)((char *)param_list + SIZEOF(intszofptr_t) + (SIZEOF(void *) * (argcnt + 3)));
+ /* Adding 3 for the same reason as above and another 3 to account for the fact that each of type description, class name,
+ * and method name arguments require room in the free_space buffer, which comes ahead of free_string buffer in memory.
+ */
+ free_string_pointer_start = free_string_pointer = (char *)param_list + entry_ptr->parmblk_size + (SIZEOF(void *) * (3 + 3));
+ /* Load-up the parameter list */
+ VAR_COPY(var, var_copy);
+ /* We need to enter this loop even if argcnt == 0, so that the class and method arguments get set. */
+ for (i = (0 == argcnt ? -1 : 0), j = 1, m1 = entry_ptr->input_mask, m2 = mask & entry_ptr->output_mask; i < argcnt; j++)
+ {
+ v = va_arg(var_copy, mval *);
+ if (j < 3)
+ {
+ param_list->arg[j] = free_string_pointer;
+ if (v->str.len)
+ memcpy(free_string_pointer, v->str.addr, v->str.len);
+ free_string_pointer += v->str.len;
+ *free_string_pointer++ = 0;
+ /* In case there are 0 arguments. */
+ if (2 == j && 0 > i)
+ i = 0;
+ continue;
+ }
+ /* Verify that all input values are defined. */
+ switch (entry_ptr->parms[i])
+ {
+ case gtm_jboolean:
+ if (m2 & 1)
+ { /* Output expected. */
+ param_list->arg[j] = free_space_pointer;
+ *((gtm_int_t *)free_space_pointer) = (m1 & 1) ? ((gtm_int_t)(mval2i(v) ? 1 : 0)) : 0;
+ free_space_pointer++;
+ } else if (m1 & 1)
+ param_list->arg[j] = (void *)((gtm_long_t)(mval2i(v) ? 1 : 0));
+ break;
+ case gtm_jint:
+ if (m2 & 1)
+ { /* Output expected. */
+ param_list->arg[j] = free_space_pointer;
+ *((gtm_int_t *)free_space_pointer) = (m1 & 1) ? (gtm_int_t)mval2i(v) : 0;
+ free_space_pointer++;
+ } else if (m1 & 1)
+ param_list->arg[j] = (void *)(gtm_long_t)mval2i(v);
+ break;
+ case gtm_jlong:
+ if (m2 & 1)
+ { /* Output expected. */
+# ifndef GTM64
+ free_space_pointer = (gtm_long_t *)(ROUND_UP2(((INTPTR_T)free_space_pointer),
+ SIZEOF(gtm_int64_t)));
+# endif
+ param_list->arg[j] = free_space_pointer;
+ *((gtm_int64_t *)free_space_pointer) = (m1 & 1) ? (gtm_int64_t)mval2i8(v) : 0;
+ free_space_pointer = (gtm_long_t *)((char *)free_space_pointer + SIZEOF(gtm_int64_t));
+ } else if (m1 & 1)
+ {
+# ifdef GTM64
+ param_list->arg[j] = (void *)(gtm_int64_t)mval2i8(v);
+# else
+ /* Only need to do this rounding on non-64 it platforms because this one type has a 64 bit
+ * alignment requirement on those platforms.
+ */
+ free_space_pointer = (gtm_long_t *)(ROUND_UP2(((INTPTR_T)free_space_pointer),
+ SIZEOF(gtm_int64_t)));
+ param_list->arg[j] = free_space_pointer;
+ *((gtm_int64_t *)free_space_pointer) = (gtm_int64_t)mval2i8(v);
+ free_space_pointer = (gtm_long_t *)((char *)free_space_pointer + SIZEOF(gtm_int64_t));
+# endif
+ }
+ break;
+ case gtm_jfloat:
+ param_list->arg[j] = free_space_pointer;
+ *((float *)free_space_pointer) = (m1 & 1) ? (float)mval2double(v) : (float)0.0;
+ free_space_pointer++;
+ break;
+ case gtm_jdouble:
+# ifndef GTM64
+ /* Only need to do this rounding on non-64 it platforms because this one type has a 64 bit
+ * alignment requirement on those platforms.
+ */
+ free_space_pointer = (gtm_long_t *)(ROUND_UP2(((INTPTR_T)free_space_pointer), SIZEOF(double)));
+# endif
+ param_list->arg[j] = free_space_pointer;
+ *((double *)free_space_pointer) = (m1 & 1) ? (double)mval2double(v) : (double)0.0;
+ free_space_pointer = (gtm_long_t *)((char *)free_space_pointer + SIZEOF(double));
+ break;
+ case gtm_jstring:
+ case gtm_jbyte_array:
+ param_list->arg[j] = free_space_pointer;
+ *free_space_pointer++ = (gtm_long_t)v->str.len;
+ *(char **)free_space_pointer = (char *)free_string_pointer;
+ free_space_pointer++;
+ if (m1 & 1)
+ {
+ if (v->str.len)
+ memcpy(free_string_pointer, v->str.addr, v->str.len);
+ free_string_pointer += v->str.len;
+ *free_string_pointer++ = 0;
+ }
+ break;
+ default:
+ va_end(var_copy);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP);
+ break;
+ }
+ assert(((char *)free_string_pointer <= ((char *)param_list + n * 2))
+ && ((char *)free_space_pointer <= ((char *)param_list + n * 2)));
+ i++;
+ m1 = m1 >> 1;
+ m2 = m2 >> 1;
+ }
+ assert((char *)free_space_pointer <= free_string_pointer_start);
+ va_end(var_copy);
+ param_list->n = argcnt + 3; /* Take care of the three implicit parameters. */
+ save_mumps_status = mumps_status; /* Save mumps_status as a callin from external call may change it. */
+ status = callg((callgfnptr)entry_ptr->fcn, param_list);
+ mumps_status = save_mumps_status;
+ /* The first byte of the type description argument gets set to 0xFF in case error happened in JNI glue code,
+ * so check for that and act accordingly.
+ */
+ if ((char)0xFF == *(char *)param_list->arg[0])
+ {
+ error_in_xc = TRUE;
+ jni_err_buf = *(char **)((char *)param_list->arg[0] + SIZEOF(char *));
+ if (NULL != jni_err_buf)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_JNI, 2, LEN_AND_STR(jni_err_buf));
+ else
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZCSTATUSRET);
+ }
+ free(types_descr_ptr);
+ /* Exit from the residual call-in environment(SFF_CI and base frames) which might still exist on M stack when the externally
+ * called function in turn called into an M routine.
+ */
+ if (frame_pointer->flags & SFF_CI)
+ ci_ret_code_quit();
+ /* Only process the input-output and output-only arguments if the external call succeeded; otherwise, return -1
+ * if non-void return is expected. */
+ if (!error_in_xc)
+ { /* Compute space requirement for return values. */
+ n = 0;
+ VAR_COPY(var_copy, var);
+ for (i = 0, j = 1, m1 = mask & entry_ptr->output_mask; i < argcnt; j++)
+ {
+ v = va_arg(var, mval *);
+ if (j < 3)
+ continue;
+ if (m1 & 1)
+ n += extarg_getsize(param_list->arg[j], entry_ptr->parms[i], v);
+ i++;
+ m1 = m1 >> 1;
+ }
+ va_end(var);
+ if (dst)
+ n += extarg_getsize((void *)&status, gtm_status, dst);
+ ENSURE_STP_FREE_SPACE(n);
+ /* Convert return values. */
+ VAR_COPY(var, var_copy);
+ for (i = 0, j = 1, m1 = mask & entry_ptr->output_mask; i < argcnt; j++)
+ {
+ v = va_arg(var_copy, mval *);
+ if (j < 3)
+ continue;
+ if (m1 & 1)
+ extarg2mval((void *)param_list->arg[j], entry_ptr->parms[i], v, TRUE, TRUE);
+ i++;
+ m1 = m1 >> 1;
+ }
+ va_end(var);
+ if (dst)
+ {
+ if (entry_ptr->return_type != gtm_void)
+ extarg2mval((void *)status, entry_ptr->return_type, dst, TRUE, FALSE);
+ else
+ {
+ memcpy(str_buffer, PACKAGE_ENV_PREFIX, SIZEOF(PACKAGE_ENV_PREFIX));
+ tmp_buff_ptr = &str_buffer[SIZEOF(PACKAGE_ENV_PREFIX) - 1];
+ if (package->str.len)
+ {
+ assert(package->str.len < MAX_NAME_LENGTH - SIZEOF(PACKAGE_ENV_PREFIX) - 1);
+ *tmp_buff_ptr++ = '_';
+ memcpy(tmp_buff_ptr, package->str.addr, package->str.len);
+ tmp_buff_ptr += package->str.len;
+ }
+ *tmp_buff_ptr = 0;
+ xtrnl_table_name = GETENV(str_buffer);
+ if (NULL == xtrnl_table_name)
+ { /* Environment variable for the package not found. This part of code is for more safety.
+ * We should not come into this path at all.
+ */
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZCCTENV, 2, LEN_AND_STR(str_buffer));
+ }
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_XCVOIDRET, 4,
+ LEN_AND_STR(entry_ptr->call_name.addr), LEN_AND_STR(xtrnl_table_name));
+ }
+ }
+ } else if (dst && (gtm_void != entry_ptr->return_type))
+ i2mval(dst, -1);
+ free(param_list);
+ check_for_timer_pops();
+ return;
+}
+
void op_fnfgncal (uint4 n_mvals, mval *dst, mval *package, mval *extref, uint4 mask, int4 argcnt, ...)
{
- va_list var;
- int i, rslt;
- int4 callintogtm_vectorindex;
- mval *arg, *v;
- int4 n;
+ boolean_t java = FALSE;
+ char *free_string_pointer, *free_string_pointer_start;
+ char str_buffer[MAX_NAME_LENGTH], *tmp_buff_ptr, *xtrnl_table_name;
+ int i, pre_alloc_size, rslt, save_mumps_status;
+ int4 callintogtm_vectorindex, n;
+ gparam_list *param_list;
gtm_long_t *free_space_pointer;
- uint4 m1;
INTPTR_T status;
- char *cp, *free_string_pointer, *free_string_pointer_start;
- int pre_alloc_size;
- int save_mumps_status;
- char *gtmvectortable_temp, *tmp_buff_ptr, str_buffer[MAX_NAME_LENGTH];
- char *xtrnl_table_name;
+ mval *v;
struct extcall_package_list *package_ptr;
struct extcall_entry_list *entry_ptr;
- gparam_list *param_list;
+ uint4 m1;
+ va_list var;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
@@ -303,7 +686,7 @@ void op_fnfgncal (uint4 n_mvals, mval *dst, mval *package, mval *extref, uint4 m
assert(MV_IS_STRING(package)); /* Package and routine are literal strings */
assert(MV_IS_STRING(extref));
if (MAX_ACTUALS < argcnt)
- rts_error(VARLSTCNT(1) ERR_ZCMAXPARAM);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZCMAXPARAM);
assert(INTRPT_OK_TO_INTERRUPT == intrpt_ok_state); /* Interrupts should be enabled for external calls */
/* Find package */
for (package_ptr = TREF(extcall_package_root); package_ptr; package_ptr = package_ptr->next_package)
@@ -322,7 +705,7 @@ void op_fnfgncal (uint4 n_mvals, mval *dst, mval *package, mval *extref, uint4 m
/* At this point, we have a valid package, pointed to by package_ptr */
assert(NULL != package_ptr);
if (NULL == package_ptr->package_handle)
- rts_error(VARLSTCNT(1) errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) errno);
/* Find entry */
for (entry_ptr = package_ptr->first_entry; entry_ptr; entry_ptr = entry_ptr->next_entry)
{
@@ -337,11 +720,22 @@ void op_fnfgncal (uint4 n_mvals, mval *dst, mval *package, mval *extref, uint4 m
}
/* Entry not found */
if ((NULL == entry_ptr) || (NULL == entry_ptr->fcn))
- rts_error(VARLSTCNT(4) ERR_ZCRTENOTF, 2, extref->str.len, extref->str.addr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZCRTENOTF, 2, extref->str.len, extref->str.addr);
+ /* Detect a call-out to Java. */
+ if ((NULL != entry_ptr->call_name.addr) && !strncmp(entry_ptr->call_name.addr, "gtm_xcj", 7))
+ {
+ java = TRUE;
+ argcnt -= 2;
+ }
/* It is an error to have more actual parameters than formal parameters */
if (argcnt > entry_ptr->argcnt)
- rts_error(VARLSTCNT(4) ERR_ZCARGMSMTCH, 2, argcnt, entry_ptr->argcnt);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZCARGMSMTCH, 2, argcnt, entry_ptr->argcnt);
VAR_START(var, argcnt);
+ if (java)
+ {
+ op_fgnjavacal(dst, package, extref, mask, argcnt, entry_ptr->argcnt, package_ptr, entry_ptr, var);
+ return;
+ }
/* Compute size of parameter block */
n = entry_ptr->parmblk_size; /* This is enough for the parameters and the fixed length entries */
/* Now, add enough for the char *'s and the char **'s and string *'s */
@@ -414,12 +808,18 @@ void op_fnfgncal (uint4 n_mvals, mval *dst, mval *package, mval *extref, uint4 m
break;
case gtm_ulong:
if (m1 & 1)
- param_list->arg[i] = (void *)(gtm_long_t)mval2ui(v);
- /* Note: output gtm_long and gtm_ulong is an error as described above */
+ {
+ GTM64_ONLY(param_list->arg[i] = (void *)(gtm_uint64_t)mval2ui8(v));
+ NON_GTM64_ONLY(param_list->arg[i] = (void *)(gtm_ulong_t)mval2ui(v));
+ }
+ /* Note: output xc_long and xc_ulong is an error as described above */
break;
case gtm_long:
if (m1 & 1)
- param_list->arg[i] = (void *)(gtm_ulong_t)mval2i(v);
+ {
+ GTM64_ONLY(param_list->arg[i] = (void *)(gtm_int64_t)mval2i8(v));
+ NON_GTM64_ONLY(param_list->arg[i] = (void *)(gtm_long_t)mval2i(v));
+ }
break;
case gtm_char_star:
param_list->arg[i] = free_string_pointer;
@@ -435,11 +835,11 @@ void op_fnfgncal (uint4 n_mvals, mval *dst, mval *package, mval *extref, uint4 m
{
if (0 == package->str.len)
/* Default package - do not display package name */
- rts_error(VARLSTCNT(7) ERR_ZCNOPREALLOUTPAR, 5, i+1, RTS_ERROR_LITERAL("<DEFAULT>"),
- extref->str.len, extref->str.addr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_ZCNOPREALLOUTPAR, 5, i + 1,
+ RTS_ERROR_LITERAL("<DEFAULT>"), extref->str.len, extref->str.addr);
else
- rts_error(VARLSTCNT(7) ERR_ZCNOPREALLOUTPAR, 5, i+1, package->str.len,
- package->str.addr, extref->str.len, extref->str.addr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_ZCNOPREALLOUTPAR, 5, i + 1,
+ package->str.len, package->str.addr, extref->str.len, extref->str.addr);
}
break;
case gtm_char_starstar:
@@ -467,12 +867,14 @@ void op_fnfgncal (uint4 n_mvals, mval *dst, mval *package, mval *extref, uint4 m
break;
case gtm_long_star:
param_list->arg[i] = free_space_pointer;
- *((gtm_long_t *)free_space_pointer) = (m1 & 1) ? (gtm_long_t)mval2i(v) : 0;
+ GTM64_ONLY(*((gtm_int64_t *)free_space_pointer) = (m1 & 1) ? (gtm_int64_t)mval2i8(v) : 0);
+ NON_GTM64_ONLY(*((gtm_long_t *)free_space_pointer) = (m1 & 1) ? (gtm_long_t)mval2i(v) : 0);
free_space_pointer++;
break;
case gtm_ulong_star:
param_list->arg[i] = free_space_pointer;
- *((gtm_ulong_t *)free_space_pointer) = (m1 & 1) ? (gtm_ulong_t)mval2ui(v) : 0;
+ GTM64_ONLY(*((gtm_uint64_t *)free_space_pointer) = (m1 & 1) ? (gtm_uint64_t)mval2ui8(v) : 0);
+ NON_GTM64_ONLY(*((gtm_ulong_t *)free_space_pointer) = (m1 & 1) ? (gtm_ulong_t)mval2ui(v) : 0);
free_space_pointer++;
break;
case gtm_string_star:
@@ -491,11 +893,11 @@ void op_fnfgncal (uint4 n_mvals, mval *dst, mval *package, mval *extref, uint4 m
{
if (0 == package->str.len)
/* Default package - do not display package name */
- rts_error(VARLSTCNT(7) ERR_ZCNOPREALLOUTPAR, 5, i + 1,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_ZCNOPREALLOUTPAR, 5, i + 1,
RTS_ERROR_LITERAL("<DEFAULT>"),
extref->str.len, extref->str.addr);
else
- rts_error(VARLSTCNT(7) ERR_ZCNOPREALLOUTPAR, 5, i + 1,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_ZCNOPREALLOUTPAR, 5, i + 1,
package->str.len, package->str.addr,
extref->str.len, extref->str.addr);
}
@@ -519,8 +921,8 @@ void op_fnfgncal (uint4 n_mvals, mval *dst, mval *package, mval *extref, uint4 m
if (((callintogtm_vectorindex = (int4)mval2i(v)) >= gtmfunc_unknown_function)
|| (callintogtm_vectorindex < 0))
{
- rts_error(VARLSTCNT(7) ERR_ZCVECTORINDX, 1, callintogtm_vectorindex, ERR_TEXT, 2,
- RTS_ERROR_TEXT("Passing Null vector"));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_ZCVECTORINDX, 1, callintogtm_vectorindex,
+ ERR_TEXT, 2, RTS_ERROR_TEXT("Passing Null vector"));
param_list->arg[i] = 0;
} else
param_list->arg[i] = (void *)callintogtm_vectortable[callintogtm_vectorindex];
@@ -534,7 +936,7 @@ void op_fnfgncal (uint4 n_mvals, mval *dst, mval *package, mval *extref, uint4 m
break;
default:
va_end(var);
- rts_error(VARLSTCNT(1) ERR_UNIMPLOP);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP);
break;
}
}
@@ -571,13 +973,13 @@ void op_fnfgncal (uint4 n_mvals, mval *dst, mval *package, mval *extref, uint4 m
{
v = va_arg(var, mval *);
if (m1 & 1)
- extarg2mval((void *)param_list->arg[i], entry_ptr->parms[i], v);
+ extarg2mval((void *)param_list->arg[i], entry_ptr->parms[i], v, FALSE, TRUE);
}
va_end(var);
if (dst)
{
if (entry_ptr->return_type != gtm_void)
- extarg2mval((void *)status, entry_ptr->return_type, dst);
+ extarg2mval((void *)status, entry_ptr->return_type, dst, FALSE, FALSE);
else
{
memcpy(str_buffer, PACKAGE_ENV_PREFIX, SIZEOF(PACKAGE_ENV_PREFIX));
@@ -597,9 +999,9 @@ void op_fnfgncal (uint4 n_mvals, mval *dst, mval *package, mval *extref, uint4 m
* This part of code is for more safety. We should
* not come into this path at all.
*/
- rts_error(VARLSTCNT(4) ERR_ZCCTENV, 2, LEN_AND_STR(str_buffer));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZCCTENV, 2, LEN_AND_STR(str_buffer));
}
- rts_error(VARLSTCNT(6) ERR_XCVOIDRET, 4,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_XCVOIDRET, 4,
LEN_AND_STR(entry_ptr->call_name.addr), LEN_AND_STR(xtrnl_table_name));
}
}
diff --git a/sr_unix/op_fnzpeek.c b/sr_unix/op_fnzpeek.c
new file mode 100644
index 0000000..2cda909
--- /dev/null
+++ b/sr_unix/op_fnzpeek.c
@@ -0,0 +1,664 @@
+/****************************************************************
+ * *
+ * Copyright 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+#include "mdef.h"
+
+#include <sys/types.h>
+#include <signal.h>
+#include "gtm_unistd.h"
+#include "gtm_string.h"
+
+#include "send_msg.h"
+#include "error.h"
+#include "stringpool.h"
+#include "util.h"
+#include "op.h"
+#include "nametabtyp.h"
+#include "namelook.h"
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "repl_msg.h"
+#include "gtmsource.h"
+#include "gtmrecv.h"
+#include "anticipatory_freeze.h"
+#include "gtm_caseconv.h"
+
+error_def(ERR_BADZPEEKARG);
+error_def(ERR_BADZPEEKFMT);
+error_def(ERR_BADZPEEKRANGE);
+error_def(ERR_MAXSTRLEN);
+error_def(ERR_ZPEEKNORPLINFO);
+
+#define FMTHEXDGT(spfree, digit) *spfree++ = digit + ((digit <= 9) ? '0' : ('A' - 0x0A))
+#define ZPEEKDEFFMT "C"
+#define ZPEEKDEFFMT_LEN (SIZEOF(ZPEEKDEFFMT) - 1)
+#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 */
+
+GBLREF boolean_t created_core;
+GBLREF sigset_t blockalrm;
+GBLREF gd_addr *gd_header;
+GBLREF boolean_t pool_init;
+GBLREF boolean_t jnlpool_init_needed;
+GBLREF jnlpool_addrs jnlpool;
+GBLREF recvpool_addrs recvpool;
+DEBUG_ONLY(GBLREF boolean_t ok_to_UNWIND_in_exit_handling;)
+
+LITDEF mval literal_zpeekdeffmt = DEFINE_MVAL_LITERAL(MV_STR, 0, 0, ZPEEKDEFFMT_LEN, (char *)ZPEEKDEFFMT, 0, 0);
+LITREF unsigned char lower_to_upper_table[];
+
+STATICFNDCL void op_fnzpeek_signal_handler(int sig, siginfo_t *info, void *context);
+STATICFNDCL int op_fnzpeek_stpcopy(char *zpeekadr, int len, mval *ret, char fmtcode);
+STATICFNDCL uchar_ptr_t op_fnzpeek_uint64fmt(uchar_ptr_t p, gtm_uint64_t n);
+STATICFNDCL uchar_ptr_t op_fnzpeek_hexfmt(uchar_ptr_t p, gtm_uint64_t n, int fmtlen);
+STATICFNDEF boolean_t op_fnzpeek_attach_jnlpool(void);
+STATICFNDEF boolean_t op_fnzpeek_attach_recvpool(void);
+
+typedef struct
+{
+ int peekop; /* Peek operation mnemonic id */
+ boolean_t allowargs; /* Number of arguments allowed */
+} zpeek_data_typ;
+
+/* Lookup tables for first argument - Note names are limited to NAME_ENTRY_SZ bytes each */
+LITDEF nametabent zpeek_names[] =
+{ /* Array offsets */
+ {3, "CSA"}, {6, "CSAREG"} /* 0, 1 */
+ ,{2, "FH"}, {5, "FHREG"} /* 2, 3 */
+ ,{3, "GDR"}, {6, "GDRREG"} /* 4, 5 */
+ ,{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 */
+};
+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 ~ */
+};
+LITDEF zpeek_data_typ zpeek_data[] =
+{
+ {PO_CSAREG, 1}, {PO_CSAREG, 1}
+ ,{PO_FHREG, 1}, {PO_FHREG, 1}
+ ,{PO_GDRREG, 1}, {PO_GDRREG, 1}
+ ,{PO_GLFREPL, 1}, {PO_GLFREPL, 1}
+ ,{PO_GRLREPL, 0}, {PO_GRLREPL, 0}
+ ,{PO_GSLREPL, 1}, {PO_GSLREPL, 1}
+ ,{PO_JPCREPL, 0}, {PO_JPCREPL, 0}
+ ,{PO_NLREG, 1}, {PO_NLREG, 1}
+ ,{PO_NLREPL, 0}
+ ,{PO_PEEK, 1}
+ ,{PO_RIHREPL, 0}, {PO_RIHREPL, 0}
+ ,{PO_RPCREPL, 0}, {PO_RPCREPL, 0}
+ ,{PO_UHCREPL, 0}, {PO_UHCREPL, 0}
+ ,{PO_UPLREPL, 0}, {PO_UPLREPL, 0}
+};
+
+/* Condition handler for use during copy of memory range to the stringpool for return. Note this condition handler is itself
+ * never tripped but serves as an unwind target for the signal handler defined below (see its comments).
+ */
+CONDITION_HANDLER(op_fnzpeek_ch)
+{
+ START_CH;
+ NEXTCH; /* In the unlikely event it gets driven, just be a pass-thru */
+}
+
+/* $ZPEEK() is processing a process memory range specified by an M routine so is definitely capable of getting
+ * user inspired address type exceptions. We protect against this by setting up our signal handler to catch any
+ * such exceptions for the duration of this routine and just unwind them so we can throw a non-fatal error
+ * message instead.
+ */
+void op_fnzpeek_signal_handler(int sig, siginfo_t *info, void *context)
+{
+ /* We basically want to do UNWIND(NULL, NULL) logic but the UNWIND macro can only be used in a condition
+ * handler so next is a block that pretends it is our condition handler and does the needful. Note in order
+ * for this to work, we need to be wrapped in a condition handler even if that condition handler is never
+ * actually invoked to serve as the target for the UNWIND().
+ */
+ { /* Needs new block since START_CH declares a new var used in UNWIND() */
+ int arg = 0; /* Needed for START_CH macro if debugging enabled */
+ START_CH;
+ DEBUG_ONLY(ok_to_UNWIND_in_exit_handling = TRUE);
+ UNWIND(NULL, NULL);
+ }
+}
+
+/* Routine to convert gtm_uint64_t to ascii value not losing any precision. Routine is based on i2asc() but
+ * uses gtm_uint64_t as the type.
+ */
+STATICFNDCL uchar_ptr_t op_fnzpeek_uint64fmt(uchar_ptr_t p, gtm_uint64_t n)
+{
+ unsigned char ar[MAX_DIGITS_IN_INT8], *q;
+ gtm_uint64_t m;
+ int len;
+
+ q = ar + SIZEOF(ar);
+ if (!n)
+ *--q = '0';
+ else
+ {
+ while (n)
+ {
+ m = n / 10;
+ *--q = n - (m * 10) + '0';
+ n = m;
+ }
+ }
+ assert((uintszofptr_t)q >= (uintszofptr_t)ar);
+ len = (unsigned int)(ar + SIZEOF(ar) - q);
+ memcpy(p, q, len);
+ return p + len;
+}
+
+/* Routine to format hex output to given length with format 0xhh<hh<hhhh<hhhhhhhh>>>. Similar to i2asclx().
+ *
+ * p - Output buffer (generally stringpool.free)
+ * n - Hex value to format
+ * fmtlen - Length in bytes of output value
+ */
+STATICFNDCL uchar_ptr_t op_fnzpeek_hexfmt(uchar_ptr_t p, gtm_uint64_t n, int fmtlen)
+{
+ unsigned char ar[MAX_HEX_DIGITS_IN_INT8], *q;
+ int m, digits;
+
+ q = ar + SIZEOF(ar);
+ for (digits = fmtlen; (0 < digits); --digits)
+ {
+ m = n & 0xF;
+ if (m <= 9)
+ *--q = m + '0';
+ else
+ *--q = m - 0xa + 'A';
+ n = n >> 4;
+ }
+ assert(0 == n); /* Verify complete number has been output (no truncated digits) */
+ memcpy(p, q, fmtlen);
+ return p + fmtlen;
+}
+
+/* Routine to extract and optionally format the requested data leaving it in the stringpool. This routine is protected
+ * by a signal handler for data access against SIGSEGV or SIGBUS signals. Note the fields that are sub-integer (1 or
+ * 2 bytes) are pulled into integer forms before processing.
+ */
+STATICFNDEF int op_fnzpeek_stpcopy(char *zpeekadr, int len, mval *ret, char fmtcode)
+{
+ unsigned int uint;
+ boolean_t negative;
+ gtm_uint64_t uint64;
+ unsigned char *numstrstart, *numstrend;
+ unsigned char *hexchr, *hexchrend, hexc, hexdgt, *spfree;
+
+ ESTABLISH_RET(op_fnzpeek_ch, ERR_BADZPEEKRANGE); /* If get an exception, likely due to bad range */
+ ret->mvtype = 0; /* Prevent GC of incomplete field */
+ switch(fmtcode)
+ {
+ case 'S': /* Null terminated string processing */
+ STRNLEN(zpeekadr, len, len); /* Reset len to actual len, fall into "C" processing */
+ /* warning - fall through */
+ case 'C': /* Character area (no processing - just copy */
+ if (len > MAX_STRLEN)
+ { /* Requested string return is too large */
+ REVERT;
+ return ERR_MAXSTRLEN;
+ }
+ ENSURE_STP_FREE_SPACE(len);
+ memcpy(stringpool.free, zpeekadr, len);
+ ret->str.addr = (char *)stringpool.free;
+ ret->str.len = len;
+ stringpool.free += len;
+ break;
+ case 'I': /* Initially, treat signed/unsigned the same */
+ case 'U':
+ negative = FALSE;
+ switch(len)
+ {
+ case SIZEOF(gtm_uint64_t):
+ /* Dealing with 8 byte integer style values is not GT.M's forte since its internal
+ * number scheme is limited to 20 digits. So use our own routine to do the conversion.
+ * Note: we could use this routine for all the below cases but on 32 bit platforms
+ * with no native 8 byte values, they would run far slower so only use this for the
+ * 8 byte values we deal with.
+ */
+ uint64 = *(gtm_uint64_t *)zpeekadr;
+ if ('I' == fmtcode)
+ { /* If signed, check if need to add minus sign to value and change value to
+ * positive.
+ */
+ negative = (0 > (gtm_int64_t)uint64);
+ if (negative)
+ uint64 = (gtm_uint64_t)(-(gtm_int64_t)uint64);
+ }
+ fmtcode = 'u'; /* Change fmtcode to skip negative value check below */
+ break;
+ case SIZEOF(unsigned int):
+ uint = *(unsigned int *)zpeekadr;
+ break;
+ case SIZEOF(short):
+ uint = (unsigned int)*(unsigned short *)zpeekadr;
+ break;
+ case SIZEOF(char):
+ uint = (unsigned int)*(unsigned char *)zpeekadr;
+ break;
+ default:
+ REVERT;
+ return ERR_BADZPEEKFMT;
+ }
+ if ('I' == fmtcode)
+ { /* If signed, check if need to add minus sign to value and change value to positive. Note this test
+ * is bypassed for uint64 types because the check is already made (in a differet/longer value).
+ */
+ negative = (0 > (signed int)uint);
+ if (negative)
+ uint = (unsigned int)(-(signed int)uint);
+ }
+ ENSURE_STP_FREE_SPACE(MAX_DIGITS_IN_INT + negative); /* Space to hold # */
+ numstrstart = stringpool.free;
+ if (negative)
+ *stringpool.free++ = '-'; /* Value is negative, record in output */
+ /* Use the correct formmating routine based on size */
+ numstrend = (SIZEOF(gtm_uint64_t) != len) ? i2asc(stringpool.free, uint)
+ : op_fnzpeek_uint64fmt(stringpool.free, uint64);
+ ret->str.addr = (char *)numstrstart;
+ ret->str.len = INTCAST(numstrend - numstrstart);
+ stringpool.free = numstrend;
+ break;
+ case 'X': /* Hex format for numeric values */
+ switch(len)
+ {
+ case SIZEOF(gtm_uint64_t):
+ uint64 = *(gtm_uint64_t *)zpeekadr;
+ break;
+ case SIZEOF(unsigned int):
+ uint64 = (gtm_uint64_t)*(unsigned int *)zpeekadr;
+ break;
+ case SIZEOF(unsigned short):
+ uint64 = (gtm_uint64_t)*(unsigned short *)zpeekadr;
+ break;
+ case SIZEOF(unsigned char):
+ uint64 = (gtm_uint64_t)*(unsigned char *)zpeekadr;
+ break;
+ default:
+ REVERT;
+ return ERR_BADZPEEKFMT;
+ }
+ ENSURE_STP_FREE_SPACE((len * 2) + 2);
+ numstrstart = stringpool.free;
+ *stringpool.free++ = '0';
+ *stringpool.free++ = 'x';
+ numstrend = op_fnzpeek_hexfmt(stringpool.free, uint64, (len * 2));
+ ret->str.addr = (char *)numstrstart;
+ ret->str.len = INTCAST(numstrend - numstrstart);
+ stringpool.free = numstrend;
+ break;
+ case 'Z': /* Hex format (no 0x prefix) of storage as it exists */
+ if ((len * 2) > MAX_STRLEN)
+ { /* Requested string return is too large */
+ REVERT;
+ return ERR_MAXSTRLEN;
+ }
+ ENSURE_STP_FREE_SPACE(len * 2); /* Need enough space for hex string */
+ spfree = stringpool.free;
+ ret->str.addr = (char *)spfree;
+ hexchr = (unsigned char *)zpeekadr;
+ hexchrend = hexchr + len;
+ if (hexchr > hexchrend) /* Wrapped address - range error */
+ {
+ REVERT;
+ return ERR_BADZPEEKRANGE;
+ }
+ for (; hexchr < hexchrend; ++hexchr)
+ { /* Format 2 digits in each character encountered */
+ hexc = *hexchr;
+ hexdgt = (hexc & 0xF0) >> 4;
+ FMTHEXDGT(spfree, hexdgt);
+ hexdgt = (hexc & 0x0F);
+ FMTHEXDGT(spfree, hexdgt);
+ }
+ stringpool.free = spfree; /* "commit" string to stringpool */
+ ret->str.len = len * 2;
+ break;
+ default:
+ REVERT;
+ return ERR_BADZPEEKARG;
+ }
+ REVERT;
+ ret->mvtype = MV_STR;
+ return 0;
+}
+
+/* A condition handler for when we are attaching to either the jnlpool or the gtmrecv pool. We don't
+ * care why we can't get to them. On the fact that we can't is material for $ZPEEK().
+ */
+CONDITION_HANDLER(op_fnzpeek_getpool_ch)
+{
+ START_CH;
+ if (DUMPABLE)
+ NEXTCH; /* Let next (more robust) handler deal with it */
+ UNWIND(NULL, NULL);
+}
+
+/* Attach to the journal pool. Separate routine so can be wrapped in a condition handler */
+STATICFNDEF boolean_t op_fnzpeek_attach_jnlpool(void)
+{
+ ESTABLISH_RET(op_fnzpeek_getpool_ch, FALSE);
+ jnlpool_init(GTMRELAXED, FALSE, NULL); /* Attach to journal pool */
+ REVERT;
+ return pool_init;
+}
+
+/* Attach to the receive pool. Separate routine so can be wrapped in a condition handler */
+STATICFNDEF boolean_t op_fnzpeek_attach_recvpool(void)
+{
+ ESTABLISH_RET(op_fnzpeek_getpool_ch, FALSE);
+ recvpool_init(GTMZPEEK, FALSE); /* Attach to receive pool */
+ REVERT;
+ return ((NULL != recvpool.recvpool_ctl) && recvpool.recvpool_ctl->initialized);
+}
+
+/* Generalized peek facility:
+ *
+ * structid - String that describes the structure
+ * offset - Offset of item within that structure.
+ * len - Length of the fetch.
+ * format - Option format character - codes described below
+ * ret - Return mval
+ */
+void op_fnzpeek(mval *structid, int offset, int len, mval *format, mval *ret)
+{
+ void *zpeekadr;
+ UINTPTR_T prmpeekadr;
+ struct sigaction new_action, prev_action_bus, prev_action_segv;
+ sigset_t savemask;
+ int errtoraise, rslt;
+ char fmtcode;
+ boolean_t arg_supplied, attach_success;
+ unsigned char mnemonic[NAME_ENTRY_SZ], *nptr, *cptr, *cptrend, *argptr;
+ int mnemonic_len, mnemonic_index, mnemonic_opcode, arglen, arryidx;
+ gd_region *r_top, *r_ptr;
+ replpool_identifier replpool_id;
+ unsigned int full_len;
+ unsigned char argument_uc_buf[ARGUMENT_MAX_LEN];
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ /* Make sure lookup table is setup correctly */
+ assert(zpeek_index[26] == (SIZEOF(zpeek_names) / SIZEOF(nametabent)));
+ assert((SIZEOF(zpeek_names) / SIZEOF(nametabent)) == (SIZEOF(zpeek_data) / SIZEOF(zpeek_data_typ)));
+ /* Initialize */
+ fmtcode = 'C'; /* If arg is NULL string (noundef default), provide default */
+ MV_FORCE_STR(structid);
+ if (MV_DEFINED(format))
+ {
+ MV_FORCE_STR(format);
+ } else format = (mval *)&literal_zpeekdeffmt; /* Cast to avoid compiler warning about dropping readonly type attributes */
+ /* Parse and lookup the first arg's mnemonic and arg (if supplied) */
+ for (nptr = mnemonic, cptr = (unsigned char *)structid->str.addr, cptrend = cptr + structid->str.len;
+ cptr < cptrend; ++cptr)
+ {
+ if (':' == *cptr)
+ break; /* End of mnemonic, start of arg */
+ *nptr++ = *cptr;
+ }
+ arg_supplied = (cptr < cptrend);
+ mnemonic_len = INTCAST(nptr - mnemonic);
+ mnemonic_index = namelook(zpeek_index, zpeek_names, (char *)mnemonic, mnemonic_len);
+ if (0 > mnemonic_index)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_BADZPEEKARG, 2, RTS_ERROR_LITERAL("mnemonic type"));
+ mnemonic_opcode = zpeek_data[mnemonic_index].peekop;
+ if ((arg_supplied && !zpeek_data[mnemonic_index].allowargs) || (!arg_supplied && zpeek_data[mnemonic_index].allowargs))
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_BADZPEEKARG, 2, RTS_ERROR_LITERAL("mnemonic argument"));
+ if (arg_supplied)
+ { /* Parse supplied argument */
+ argptr = ++cptr; /* Bump past ":" - if now have end-of-arg then arg is missing */
+ if (argptr == cptrend)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_BADZPEEKARG, 2, RTS_ERROR_LITERAL("mnemonic argument"));
+ arglen = INTCAST(cptrend - cptr);
+ if (ARGUMENT_MAX_LEN < arglen)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_BADZPEEKARG, 2, RTS_ERROR_LITERAL("mnemonic argument"));
+ switch(mnemonic_opcode)
+ {
+ case PO_CSAREG: /* These types have a region name argument */
+ case PO_FHREG:
+ case PO_GDRREG:
+ case PO_NLREG:
+ /* 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 */
+ /* See if region recently used so can avoid lookup */
+ if ((arglen == TREF(zpeek_regname_len)) && (0 == memcmp(argptr, TADR(zpeek_regname), arglen)))
+ { /* Fast path - no lookup necessary */
+ r_ptr = TREF(zpeek_reg_ptr);
+ assert(r_ptr->open && !r_ptr->was_open); /* Make sure truly open */
+ break;
+ }
+ /* Region now defined - make sure it is open */
+ if (!gd_header) /* If gd_header is NULL, open gbldir */
+ gvinit();
+ r_ptr = gd_header->regions;
+ 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_BADZPEEKARG, 2,
+ RTS_ERROR_LITERAL("mnemonic argument (region name)"));
+ if ((r_ptr->rname_len == arglen) && (0 == memcmp(r_ptr->rname, argptr, arglen)))
+ break;
+ }
+ if (!r_ptr->open)
+ gv_init_reg(r_ptr);
+ /* Cache new region access for followup references */
+ memcpy(TADR(zpeek_regname), argptr, arglen);
+ TREF(zpeek_regname_len) = arglen;
+ TREF(zpeek_reg_ptr) = r_ptr;
+ /* r_ptr now points to (open) region */
+ assert(r_ptr->open && !r_ptr->was_open); /* Make sure truly open */
+ break;
+ case PO_GLFREPL: /* These types have an array index argument */
+ case PO_GSLREPL:
+ arryidx = asc2i(argptr, arglen);
+ if ((0 > arryidx) || (NUM_GTMSRC_LCL < arryidx))
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_BADZPEEKARG, 2,
+ RTS_ERROR_LITERAL("mnemonic argument (array index)"));
+ break;
+ case PO_PEEK: /* Argument is address of form 0Xhhhhhhhh[hhhhhhhh] */
+ if (('0' != *cptr++) || ('x' != *cptr) && ('X' != *cptr))
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_BADZPEEKARG, 2,
+ RTS_ERROR_LITERAL("mnemonic argument (peek base address)"));
+ cptr++; /* Bump past 'x' or 'X' - rest of arg should be hex value */
+ prmpeekadr = (UINTPTR_T)GTM64_ONLY(asc_hex2l)NON_GTM64_ONLY(asc_hex2i)(cptr, arglen - 2);
+ if (-1 == (INTPTR_T)prmpeekadr)
+ /* Either an error occurred or the user specified the maximum address. So it's
+ * either an error from the conversion routine or an otherwise useless value.
+ */
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_BADZPEEKARG, 2,
+ RTS_ERROR_LITERAL("mnemonic argument (peek base address)"));
+ break;
+ default:
+ assert(FALSE); /* Only the above types should ever have an argument */
+ }
+ }
+ /* Figure out the address of each block to return */
+ switch(mnemonic_opcode)
+ {
+ case PO_CSAREG: /* r_ptr set from option processing */
+ zpeekadr = &FILE_INFO(r_ptr)->s_addrs;
+ break;
+ case PO_FHREG: /* r_ptr set from option processing */
+ zpeekadr = (&FILE_INFO(r_ptr)->s_addrs)->hdr;
+ break;
+ case PO_GDRREG: /* r_ptr set from option processing */
+ zpeekadr = r_ptr;
+ break;
+ case PO_NLREG: /* r_ptr set from option processing */
+ zpeekadr = (&FILE_INFO(r_ptr)->s_addrs)->nl;
+ break;
+ case PO_GLFREPL: /* This set of opcodes all require the journal pool to be initialized. Verify it */
+ case PO_GSLREPL:
+ case PO_JPCREPL:
+ case PO_NLREPL:
+ case PO_RIHREPL:
+ /* Make sure jnlpool_addrs are availble */
+ if (!REPL_INST_AVAILABLE)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZPEEKNORPLINFO);
+ if (!pool_init)
+ {
+ attach_success = op_fnzpeek_attach_jnlpool();
+ if (!attach_success)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZPEEKNORPLINFO);
+ }
+ switch(mnemonic_opcode)
+ {
+ case PO_GLFREPL: /* arryidx set by option processing */
+ zpeekadr = (jnlpool.gtmsrc_lcl_array + arryidx);
+ break;
+ case PO_GSLREPL: /* arryidx set by option processing */
+ zpeekadr = (jnlpool.gtmsource_local_array + arryidx);
+ break;
+ case PO_NLREPL:
+ zpeekadr = (&FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs)->nl;
+ break;
+ case PO_JPCREPL:
+ zpeekadr = jnlpool.jnlpool_ctl;
+ break;
+ case PO_RIHREPL:
+ zpeekadr = jnlpool.repl_inst_filehdr;
+ break;
+ default:
+ assert(FALSE);
+ }
+ break;
+ case PO_RPCREPL: /* This set of opcodes all require the receive pool to be initialized. Verify it */
+ case PO_GRLREPL:
+ case PO_UPLREPL:
+ case PO_UHCREPL:
+ /* Make sure recvpool_addrs are available */
+ if (!REPL_INST_AVAILABLE)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZPEEKNORPLINFO);
+ if (NULL == recvpool.recvpool_ctl)
+ {
+ attach_success = op_fnzpeek_attach_recvpool();
+ if (!attach_success)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZPEEKNORPLINFO);
+ }
+ switch(mnemonic_opcode)
+ {
+ case PO_RPCREPL:
+ zpeekadr = recvpool.recvpool_ctl;
+ break;
+ case PO_GRLREPL:
+ zpeekadr = recvpool.gtmrecv_local;
+ break;
+ case PO_UPLREPL:
+ zpeekadr = recvpool.upd_proc_local;
+ break;
+ case PO_UHCREPL:
+ zpeekadr = recvpool.upd_helper_ctl;
+ break;
+ default:
+ assert(FALSE);
+ }
+ break;
+ case PO_PEEK: /* prmpeekadr set up in argument processing */
+ zpeekadr = (void *)prmpeekadr;
+ break;
+ default:
+ assert(FALSE);
+ }
+ assert(NULL != zpeekadr);
+ /* Check the rest of the args */
+ if (0 > offset)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_BADZPEEKARG, 2, RTS_ERROR_LITERAL("offset"));
+ zpeekadr = (void *)((char *)zpeekadr + offset);
+ if ((0 > len) || (MAX_STRLEN < len))
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_BADZPEEKARG, 2, RTS_ERROR_LITERAL("length"));
+ if (1 < format->str.len)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_BADZPEEKARG, 2, RTS_ERROR_LITERAL("format"));
+ else if (1 == format->str.len)
+ { /* Validate format option */
+ fmtcode = *format->str.addr;
+ fmtcode = lower_to_upper_table[fmtcode];
+ switch(fmtcode)
+ {
+ 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 '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)
+ * and is returned with no 0x prefix.
+ */
+ break;
+ default:
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_BADZPEEKARG, 2, RTS_ERROR_LITERAL("format"));
+ }
+ }
+ /* Block out timer calls that might trigger processing that could fail. We especially want to prevent
+ * nesting of signal handlers since the longjump() function used by the UNWIND macro is undefined on
+ * Tru64 when signal handlers are nested.
+ */
+ sigprocmask(SIG_BLOCK, &blockalrm, &savemask);
+ /* Setup new signal handler to just drive condition handler which will do the right thing */
+ memset(&new_action, 0, SIZEOF(new_action));
+ sigemptyset(&new_action.sa_mask);
+ new_action.sa_flags = SA_SIGINFO;
+# ifdef __sparc
+ new_action.sa_handler = op_fnzpeek_signal_handler;
+# else
+ new_action.sa_sigaction = op_fnzpeek_signal_handler;
+# endif
+ sigaction(SIGBUS, &new_action, &prev_action_bus);
+ sigaction(SIGSEGV, &new_action, &prev_action_segv);
+ /* Attempt to copy return string to stringpool which protected by our handlers. If the copy completes, the return
+ * mval is updated to point to the return string. Even errors return here so these sigactions can be reversed.
+ */
+ errtoraise = op_fnzpeek_stpcopy(zpeekadr, len, ret, fmtcode);
+ /* Can restore handlers now that access verified */
+ sigaction(SIGBUS, &prev_action_bus, NULL);
+ sigaction(SIGSEGV, &prev_action_segv, NULL);
+ /* Let the timers pop again.. */
+ sigprocmask(SIG_SETMASK, &savemask, NULL);
+ /* If we didn't complete correctly, raise error */
+ if (0 != errtoraise)
+ { /* The only time ERR_BADZPEEKARG is driven is when the format code is not recognized so give that error
+ * specifically with the additional args. Else just raise the error.
+ */
+ if (ERR_BADZPEEKARG == errtoraise)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) errtoraise, 2, RTS_ERROR_LITERAL("format"));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) errtoraise);
+ }
+ return;
+}
diff --git a/sr_unix/op_job.c b/sr_unix/op_job.c
index a98f1e9..5fd3a61 100644
--- a/sr_unix/op_job.c
+++ b/sr_unix/op_job.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -52,25 +52,23 @@
#include "have_crit.h" /* for the TPNOTACID_CHECK macro */
#endif
+void job_timer_handler(void);
+
GBLDEF short jobcnt = 0;
GBLDEF volatile boolean_t ojtimeout = TRUE;
GBLREF uint4 dollar_trestart;
GBLREF int dollar_truth;
GBLREF uint4 dollar_zjob;
-GBLREF boolean_t job_try_again;
GBLREF int4 outofband;
+static int4 tid; /* Job Timer ID */
error_def(ERR_TEXT);
error_def(ERR_JOBFAIL);
+error_def(ERR_NULLENTRYREF);
-static int4 tid; /* Job Timer ID */
-void job_timer_handler(void);
-
-#define MAX_CHAR_CAPACITY 0xFF
#define JOBTIMESTR "JOB time too long"
-
/*
* ---------------------------------------------------
* This handler is executed if job could not be started
@@ -82,7 +80,6 @@ void job_timer_handler(void)
ojtimeout = TRUE;
}
-
/*
* ---------------------------------------------------
* Job command main entry point
@@ -95,12 +92,12 @@ int op_job(int4 argcnt, ...)
mval *label, *inp;
int4 offset;
mval *routine, *param_buf;
- int4 timeout; /* timeout in seconds */
- int4 msec_timeout; /* timeout in milliseconds */
+ int4 timeout; /* timeout in seconds */
+ int4 msec_timeout; /* timeout in milliseconds */
boolean_t timed, single_attempt, non_exit_return;
unsigned char buff[128], *c;
int4 status, exit_stat, term_sig, stop_sig;
- pid_t zjob_pid = 0; /* zjob_pid should exactly match in type with child_pid(ojstartchild.c) */
+ pid_t zjob_pid = 0; /* zjob_pid should exactly match in type with child_pid(ojstartchild.c) */
int pipe_fds[2], pipe_status;
# ifdef _BSD
union wait wait_stat;
@@ -134,7 +131,7 @@ int op_job(int4 argcnt, ...)
if (-1 == pipe_status)
{
va_end(var);
- rts_error(VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2, LEN_AND_LIT("Error creating pipe"), errno);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2, LEN_AND_LIT("Error creating pipe"), errno);
}
jobcnt++;
command.addr = &combuf[0];
@@ -143,11 +140,18 @@ int op_job(int4 argcnt, ...)
job_params.label = label->str;
job_params.offset = offset;
ojparams(param_buf->str.addr, &job_params);
+ /*
+ * Verify that entryref to JOB command is not NULL.
+ */
+ if (!job_params.routine.len)
+ {
+ va_end(var);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_JOBFAIL, 0, ERR_NULLENTRYREF, 0);
+ }
/* Clear the buffers */
flush_pio();
/* Start the timer */
ojtimeout = FALSE;
- single_attempt = FALSE;
if (timeout < 0)
timeout = 0;
else if (TREF(tpnotacidtime) < timeout)
@@ -162,8 +166,6 @@ int op_job(int4 argcnt, ...)
msec_timeout = timeout2msec(timeout);
if (msec_timeout > 0)
start_timer((TID)&tid, msec_timeout, job_timer_handler, 0, NULL);
- else
- single_attempt = TRUE;
}
if (argcnt)
{
@@ -182,48 +184,54 @@ int op_job(int4 argcnt, ...)
} else
job_params.parms = 0;
va_end(var);
- assert(joberr_tryagain + 1 == joberr_end); /* they must be adjacent and the last two */
- assert((joberr_tryagain * 2 - 1) < MAX_CHAR_CAPACITY);
/* Setup parameters and start the job */
- do
+ job_errno = -1;
+ non_exit_return = FALSE;
+ status = ojstartchild(&job_params, argcnt, &non_exit_return, pipe_fds);
+ if (!non_exit_return)
{
- job_try_again = FALSE;
- non_exit_return = FALSE;
- status = ojstartchild(&job_params, argcnt, &non_exit_return, pipe_fds);
- if (status && !non_exit_return)
+#ifdef _BSD
+ assert(SIZEOF(wait_stat) == SIZEOF(int4));
+ wait_stat.w_status = status;
+ /* waitpid in ojstartchild() expects an int wait_status whereas the WIF* macros expect a union wait_stat as an
+ * argument.
+ */
+#else
+ wait_stat = status;
+#endif
+ exit_stat = WIFEXITED(wait_stat) ? WEXITSTATUS(wait_stat) : 0;
+ /* Middle process uses pipe(pipe_fds)
+ * a) to communicate a PID of grandchild to its parent process(i.e. current process)
+ * b) to communicate an errno to current process if any required setup for the grandchild is failed.
+ * exit status joberr_pipe_mp of middle process means it failed WRITE operation on pipe used to communicate
+ * grandchild's PID to current process. In this scenario, grandchild is terminated and middle process do not
+ * communicate errno to current process. Hence this process do not read the errno for joberr_pipe_mp exit status.
+ */
+ if (status && joberr_pipe_mp != exit_stat)
{
- /* check if it was a try_again kind of failure */
-# ifdef _BSD
- assert(SIZEOF(wait_stat) == SIZEOF(int4));
- wait_stat.w_status = status;
- /* waitpid in ojstartchild() expects an int wait_status whereas the WIF* macros expect a
- * union wait_stat as an arg
- */
-# else
- wait_stat = status;
-# endif
- if (WIFEXITED(wait_stat) && (joberr_tryagain < (exit_stat = WEXITSTATUS(wait_stat))))
- {
- /* one of try-again situations */
- job_try_again = TRUE;
- exit_stat -= joberr_tryagain;
- assert(exit_stat < joberr_stp);
- }
+ DOREADRC(pipe_fds[0], &job_errno, SIZEOF(job_errno), pipe_status);
+ if (0 < pipe_status)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, joberrs[exit_stat].len,
+ joberrs[exit_stat].msg, 2, errno);
}
- } while (!single_attempt && status && !ojtimeout && job_try_again);
+
+ }
if (argcnt)
free(job_params.parms);
if (timed && !ojtimeout)
cancel_timer((TID)&tid);
- /* the child process (M), that wrote to pipe, would have been exited by now */
- CLOSEFILE_RESET(pipe_fds[1], pipe_status); /* close the write-end to make the following read non-blocking;
- * also resets "pipe_fds[1]" to FD_INVALID
- */
+ /* the child process (M), that wrote to pipe, would have been exited by now. Close the write-end to make the following read
+ * non-blocking. also resets "pipe_fds[1]" to FD_INVALID
+ */
+ CLOSEFILE_RESET(pipe_fds[1], pipe_status);
assert(SIZEOF(pid_t) == SIZEOF(zjob_pid));
- DOREADRC(pipe_fds[0], &zjob_pid, SIZEOF(zjob_pid), pipe_status); /* read jobbed off PID from pipe */
- if (0 < pipe_status) /* empty pipe (pipe_status == -1) is ignored and not reported as error */
- rts_error(VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2, LEN_AND_LIT("Error reading from pipe"), errno);
- CLOSEFILE_RESET(pipe_fds[0], pipe_status); /* release the pipe; also resets "pipe_fds[0]" to FD_INVALID */
+ DOREADRC(pipe_fds[0], &zjob_pid, SIZEOF(zjob_pid), pipe_status);
+ /* empty pipe (pipe_status == -1) is ignored and not reported as error */
+ if (0 < pipe_status)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2,
+ LEN_AND_LIT("Error reading zjobid from pipe"), errno);
+ /* release the pipe; also resets "pipe_fds[0]" to FD_INVALID */
+ CLOSEFILE_RESET(pipe_fds[0], pipe_status);
if (status)
{
if (timed) /* $test should be modified only for timed job commands */
@@ -231,7 +239,7 @@ int op_job(int4 argcnt, ...)
if (non_exit_return)
{
if (TIMEOUT_ERROR != status) /* one of errno returns, not the wait_status/timeout situation */
- rts_error(VARLSTCNT(3) ERR_JOBFAIL, 0, status);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_JOBFAIL, 0, status);
else
return FALSE;
} else /* wait_status from the child */
@@ -241,31 +249,44 @@ int op_job(int4 argcnt, ...)
term_sig = WTERMSIG(wait_stat); /* signal that caused the termination */
memcpy(buff, joberrs[joberr_sig].msg, joberrs[joberr_sig].len);
c = i2asc(&buff[joberrs[joberr_sig].len], term_sig);
- rts_error(VARLSTCNT(6) ERR_JOBFAIL, 0, ERR_TEXT, 2, c - buff, buff);
+ assert(FALSE);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JOBFAIL, 0, ERR_TEXT, 2, c - buff, buff);
} else if (WIFSTOPPED(wait_stat)) /* child was STOPped */
{
stop_sig = WSTOPSIG(wait_stat); /* signal that caused the stop */
memcpy(buff, joberrs[joberr_stp].msg, joberrs[joberr_stp].len);
c = i2asc(&buff[joberrs[joberr_stp].len], stop_sig);
- rts_error(VARLSTCNT(6) ERR_JOBFAIL, 0, ERR_TEXT, 2, c - buff, buff);
+ assert(FALSE);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JOBFAIL, 0, ERR_TEXT, 2, c - buff, buff);
} else if (WIFEXITED(wait_stat)) /* child EXITed normally */
{
if (exit_stat < joberr_stp) /* one of our EXITs */
{
- rts_error(VARLSTCNT(6) ERR_JOBFAIL, 0, ERR_TEXT, 2,
- joberrs[exit_stat].len, joberrs[exit_stat].msg);
+ if (-1 == job_errno)
+ {
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JOBFAIL, 0, ERR_TEXT, 2,
+ joberrs[exit_stat].len,
+ joberrs[exit_stat].msg);
+ } else
+ {
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JOBFAIL, 0, ERR_TEXT, 2,
+ joberrs[exit_stat].len,
+ joberrs[exit_stat].msg,
+ job_errno);
+
+ }
} else /* unknown exit status */
{
assert(FALSE);
util_out_print("Unknown exit status !UL (status = !UL)", TRUE, exit_stat, status);
- rts_error(VARLSTCNT(6) ERR_JOBFAIL, 0, ERR_TEXT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JOBFAIL, 0, ERR_TEXT, 2,
joberrs[joberr_gen].len, joberrs[joberr_gen].msg);
}
} else
{
assert(FALSE);
util_out_print("Unknown wait status !UL", TRUE, status);
- rts_error(VARLSTCNT(6) ERR_JOBFAIL, 0, ERR_TEXT, 2,
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JOBFAIL, 0, ERR_TEXT, 2,
joberrs[joberr_gen].len, joberrs[joberr_gen].msg);
}
}
diff --git a/sr_unix/op_zedit.c b/sr_unix/op_zedit.c
index 29ec3e5..9ef7204 100644
--- a/sr_unix/op_zedit.c
+++ b/sr_unix/op_zedit.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -25,6 +25,7 @@
#include "stringpool.h"
#include "setterm.h"
#include "op.h"
+#include "fork_init.h"
GBLREF io_pair io_std_device;
GBLREF mval dollar_zsource;
@@ -58,26 +59,26 @@ void op_zedit(mval *v, mval *p)
edt = GETENV("EDITOR");
if (!edt)
edt = "editor";
- rts_error(VARLSTCNT(4) ERR_FILENOTFND, 2, LEN_AND_STR(edt));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_FILENOTFND, 2, LEN_AND_STR(edt));
}
MV_FORCE_STR(v);
MV_FORCE_STR(p);
src.len = v->str.len;
src.addr = v->str.addr;
if (0 == src.len)
- rts_error(VARLSTCNT(4) ERR_ZEDFILSPEC, 2, src.len, src.addr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZEDFILSPEC, 2, src.len, src.addr);
memset(&pblk, 0, SIZEOF(pblk));
pblk.buffer = es;
pblk.buff_size = MAX_FBUFF;
status = parse_file(&src, &pblk);
if (!(status & 1))
- rts_error(VARLSTCNT(5) ERR_ZEDFILSPEC, 2, src.len, src.addr, status);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_ZEDFILSPEC, 2, src.len, src.addr, status);
has_ext = 0 != (pblk.fnb & F_HAS_EXT);
exp_dir = 0 != (pblk.fnb & F_HAS_DIR);
if (!(pblk.fnb & F_HAS_NAME))
{
assert(!has_ext);
- rts_error(VARLSTCNT(4) ERR_ZEDFILSPEC, 2, pblk.b_esl, pblk.buffer);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZEDFILSPEC, 2, pblk.b_esl, pblk.buffer);
}
if (!exp_dir)
{
@@ -96,14 +97,14 @@ void op_zedit(mval *v, mval *p)
{
typ = STR_LIT_LEN(DOTM);
if (path_len + typ > MAX_FBUFF)
- rts_error(VARLSTCNT(4) ERR_ZEDFILSPEC, 2, path_len, es);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZEDFILSPEC, 2, path_len, es);
memcpy(&es[path_len], DOTM, STR_LIT_LEN(DOTM));
path_len += typ;
}
} else
{
if ((STR_LIT_LEN(DOTOBJ) == pblk.b_ext) && !MEMCMP_LIT(ptr + pblk.b_name, DOTOBJ))
- rts_error(VARLSTCNT(4) ERR_ZEDFILSPEC, 2, path_len, es);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZEDFILSPEC, 2, path_len, es);
else if ((STR_LIT_LEN(DOTM) == pblk.b_ext) && !MEMCMP_LIT(ptr + pblk.b_name, DOTM))
typ = STR_LIT_LEN(DOTM);
}
@@ -139,7 +140,7 @@ void op_zedit(mval *v, mval *p)
assert(ZRO_TYPE_SOURCE == srcdir->type);
tslash = ('/' == srcdir->str.addr[srcdir->str.len - 1]) ? 0 : 1;
if (path_len + srcdir->str.len + tslash >= SIZEOF(es))
- rts_error(VARLSTCNT(4) ERR_ZEDFILSPEC, 2, src.len, src.addr);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ZEDFILSPEC, 2, src.len, src.addr);
memmove(&es[ srcdir->str.len + tslash], &es[0], path_len);
if (tslash)
es[ srcdir->str.len ] = '/';
@@ -157,7 +158,7 @@ void op_zedit(mval *v, mval *p)
act.sa_flags = 0;
act.sa_handler = SIG_IGN;
sigaction(SIGINT, &act, &intr);
- childid = fork(); /* BYPASSOK: we exec immediately, no FORK_CLEAN needed */
+ FORK(childid); /* BYPASSOK: we exec immediately, no FORK_CLEAN needed */
if (childid)
{
waitid = (int)childid;
diff --git a/sr_unix/op_ztrigger.c b/sr_unix/op_ztrigger.c
index e832cd5..0724b1f 100644
--- a/sr_unix/op_ztrigger.c
+++ b/sr_unix/op_ztrigger.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2010, 2012 Fidelity Information Services, Inc *
+ * Copyright 2010, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -106,7 +106,7 @@ error_def(ERR_UNIMPLOP);
void op_ztrigger(void)
{
- rts_error(VARLSTCNT(1) ERR_UNIMPLOP);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_UNIMPLOP);
}
#else
void op_ztrigger(void)
@@ -136,7 +136,7 @@ void op_ztrigger(void)
DCL_THREADGBL_ACCESS;
if (gv_cur_region->read_only)
- rts_error(VARLSTCNT(4) ERR_ZTRIGNOTRW, 2, REG_LEN_STR(gv_cur_region));
+ rts_error_csa(CSA_ARG(cs_addrs) VARLSTCNT(4) ERR_ZTRIGNOTRW, 2, REG_LEN_STR(gv_cur_region));
SETUP_THREADGBL_ACCESS;
csa = cs_addrs;
csd = csa->hdr;
diff --git a/sr_unix/osf1alpha_badd.txt b/sr_unix/osf1alpha_badd.txt
index 5b191a0..0b4bd1a 100644
--- a/sr_unix/osf1alpha_badd.txt
+++ b/sr_unix/osf1alpha_badd.txt
@@ -1,6 +1,6 @@
#################################################################
# #
-# Copyright 2011, 2012 Fidelity Information Services, Inc #
+# Copyright 2011, 2013 Fidelity Information Services, Inc #
# #
# This source code contains the intellectual property #
# of its copyright holder(s), and is made available #
@@ -21,10 +21,3 @@ gtmsecshr%-r-xr-x--- gtmprofile_preV54000
lke%-r--r----- libgtmutil.so
semstat2%dr-xr-x--- plugin
zzz_insert%-r--r----- so_locations
-
-pro/plugin:
-zzz_insert%dr-xr-x--- o
-zzz_insert%dr-xr-x--- r
-
-pro/plugin/gtmcrypt:
-zzz_insert%-r--r----- source.tar
diff --git a/sr_unix/parse_file.c b/sr_unix/parse_file.c
index 47523f1..1030085 100644
--- a/sr_unix/parse_file.c
+++ b/sr_unix/parse_file.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -14,8 +14,11 @@
#include "gtm_inet.h" /* for struct in_addr */
#include "gtm_stat.h"
#include "gtm_string.h"
+#include "gtm_stdio.h"
#include "gtm_unistd.h"
+#include "gtm_socket.h" /* for using sockaddr and sockaddr_storage */
#include "gtm_netdb.h"
+#include "gtm_ipv6.h"
#include "parse_file.h"
#include "io.h"
@@ -23,8 +26,18 @@
#include "eintr_wrappers.h"
#include "trans_log_name.h"
#include "setzdir.h"
+#include "gtmmsg.h" /* for gtm_putmsg */
#define LOCALHOSTNAME "localhost"
+#define LOCALHOSTNAME6 "::1"
+
+error_def(ERR_FILENOTFND);
+error_def(ERR_GETADDRINFO);
+error_def(ERR_GETNAMEINFO);
+error_def(ERR_PARBUFSM);
+error_def(ERR_PARNORMAL);
+error_def(ERR_SYSCALL);
+error_def(ERR_TEXT);
enum parse_state
{
@@ -40,7 +53,8 @@ GBLREF mval dollar_zdir;
int4 parse_file(mstr *file, parse_blk *pblk)
{
struct stat statbuf;
- struct hostent *hostinfo;
+ struct addrinfo *ai_ptr = NULL, *localhost_ai_ptr = NULL, *temp_ai_ptr = NULL;
+ struct addrinfo hints;
mstr trans, tmp;
int status, diff, local_node_len, query_node_len, node_name_len;
parse_blk def;
@@ -50,13 +64,10 @@ int4 parse_file(mstr *file, parse_blk *pblk)
char def_string[MAX_FBUFF + 1];
boolean_t hasnode, hasdir, hasname, hasext, wilddir, wildname;
enum parse_state state;
- struct in_addr query_ip, localhost_ip, *local_ip;
+ struct sockaddr_storage query_sas;
+ struct sockaddr localhost_sa, *localhost_sa_ptr;
mval def_trans;
-
- error_def(ERR_PARNORMAL);
- error_def(ERR_PARBUFSM);
- error_def(ERR_FILENOTFND);
- error_def(ERR_SYSCALL);
+ int errcode;
pblk->fnb = 0;
assert(((unsigned int)pblk->buff_size + 1) <= (MAX_FBUFF + 1));
@@ -126,39 +137,61 @@ int4 parse_file(mstr *file, parse_blk *pblk)
assert(':' == *(trans.addr + query_node_len));
memcpy(query_node_name, trans.addr, query_node_len);
query_node_name[query_node_len] = 0;
- local_ip = NULL; /* null value needed in case can't find query node (remote default) */
- if (NULL != (hostinfo = GETHOSTBYNAME(query_node_name)))
- { /* We know about this node -- check further */
- query_ip = *(struct in_addr *)hostinfo->h_addr;
- /* See if is a "localhost" (127.0.0.1 usually) node */
- if (NULL != (hostinfo = GETHOSTBYNAME(LOCALHOSTNAME)))
+ localhost_sa_ptr = NULL; /* null value needed if not find query node (remote default) */
+ CLIENT_HINTS(hints);
+ if (0 != (errcode = getaddrinfo(query_node_name, NULL, &hints, &ai_ptr)))
+ ai_ptr = NULL; /* skip additional lookups */
+ else
+ memcpy((sockaddr_ptr)&query_sas, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
+ CLIENT_HINTS(hints);
+ if (0 == (errcode = getaddrinfo(LOCALHOSTNAME, NULL, &hints, &localhost_ai_ptr)))
+ {
+ if (0 == memcmp(localhost_ai_ptr->ai_addr, (sockaddr_ptr)&query_sas,
+ localhost_ai_ptr->ai_addrlen))
+ localhost_sa_ptr = localhost_ai_ptr->ai_addr;
+ }
+ FREEADDRINFO(localhost_ai_ptr);
+ if (ai_ptr && !localhost_sa_ptr)
+ { /* Have not yet established this is not a local node -- check further */
+ GETHOSTNAME(local_node_name, MAX_HOST_NAME_LEN, status);
+ if (-1 == status)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_SYSCALL, 5,
+ LEN_AND_LIT("gethostname"), CALLFROM, errno);
+ CLIENT_HINTS(hints);
+ if (0 != (errcode = getaddrinfo(local_node_name, NULL, &hints, &localhost_ai_ptr)))
+ localhost_ai_ptr = NULL; /* empty address list */
+ for (temp_ai_ptr = localhost_ai_ptr; temp_ai_ptr!= NULL;
+ temp_ai_ptr = temp_ai_ptr->ai_next)
{
- localhost_ip = *(struct in_addr *)hostinfo->h_addr;
- if (0 == memcmp(&localhost_ip, &query_ip, SIZEOF(struct in_addr)))
- local_ip = &localhost_ip;
+ if (0 == memcmp((sockaddr_ptr)&query_sas, temp_ai_ptr->ai_addr,
+ temp_ai_ptr->ai_addrlen))
+ {
+ localhost_sa_ptr = temp_ai_ptr->ai_addr;
+ break; /* Tiz truly a local node */
+ }
}
- if (!local_ip)
- { /* Have not yet established this as a local node -- check further */
- GETHOSTNAME(local_node_name, MAX_HOST_NAME_LEN, status);
- if (-1 == status)
- rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("gethostname"),
- CALLFROM, errno);
- if (NULL == (hostinfo = GETHOSTBYNAME(local_node_name)))
- rts_error(VARLSTCNT(7) ERR_SYSCALL, 5, LEN_AND_LIT("gethostbyname"),
- CALLFROM);
- for (hostaddrlist = (char **) hostinfo->h_addr_list; ; hostaddrlist++)
+ FREEADDRINFO(localhost_ai_ptr);
+ }
+ if (ai_ptr && !localhost_sa_ptr)
+ {
+ CLIENT_HINTS(hints);
+ if (0 != (errcode = getaddrinfo(LOCALHOSTNAME6, NULL, &hints, &localhost_ai_ptr)))
+ localhost_ai_ptr = NULL; /* empty address list */
+ for (temp_ai_ptr = localhost_ai_ptr; temp_ai_ptr!= NULL;
+ temp_ai_ptr = temp_ai_ptr->ai_next)
+ {
+ if (0 == memcmp((sockaddr_ptr)&query_sas, temp_ai_ptr->ai_addr,
+ temp_ai_ptr->ai_addrlen))
{
- local_ip = (struct in_addr *)*hostaddrlist;
- if (!local_ip) /* End of list -- must be remote */
- break;
- if (0 == memcmp(&query_ip, local_ip, SIZEOF(struct in_addr)))
- break; /* Tiz truly a local node */
+ localhost_sa_ptr = temp_ai_ptr->ai_addr;
+ break; /* Tiz truly a local node */
}
}
- } /* Else, unknown nodename -- treat as remote (probably fail later) */
-
- if (!local_ip) /* Not local (or an unknown) host given */
+ FREEADDRINFO(localhost_ai_ptr);
+ }
+ if (!localhost_sa_ptr) /* Not local (or an unknown) host given */
{ /* Remote node specified -- don't apply any defaults */
+ FREEADDRINFO(ai_ptr);
pblk->l_node = trans.addr;
pblk->b_node = node_name_len;
pblk->l_dir = base;
@@ -169,7 +202,7 @@ int4 parse_file(mstr *file, parse_blk *pblk)
pblk->fnb |= (hasnode << V_HAS_NODE);
return ERR_PARNORMAL;
}
-
+ FREEADDRINFO(ai_ptr);
/* Remove local node name from filename buffer */
assert(0 < trans.len - node_name_len);
memmove(trans.addr, node, trans.len - node_name_len);
diff --git a/sr_unix/recvpool_init.c b/sr_unix/recvpool_init.c
index e01f277..72da7cc 100644
--- a/sr_unix/recvpool_init.c
+++ b/sr_unix/recvpool_init.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -66,7 +66,7 @@ error_def(ERR_TEXT);
#define MAX_RES_TRIES 620 /* Also defined in gvcst_init_sysops.c */
-#define REMOVE_OR_RELEASE_SEM(NEW_IPC, UDI) \
+#define REMOVE_OR_RELEASE_SEM(NEW_IPC) \
{ \
if (NEW_IPC) \
remove_sem_set(RECV); \
@@ -109,7 +109,7 @@ void recvpool_init(recvpool_user pool_user, boolean_t gtmrecv_startup)
* locks the same entity.
* Should have already attached to journal pool only for receiver server startup or shutdown. Assert that.
*/
- assert(gtmrecv_options.start || gtmrecv_options.shut_down);
+ assert(gtmrecv_options.start || gtmrecv_options.shut_down || (GTMZPEEK == pool_user));
reg = recvpool.recvpool_dummy_reg = jnlpool.jnlpool_dummy_reg;
}
udi = FILE_INFO(reg);
@@ -175,7 +175,7 @@ void recvpool_init(recvpool_user pool_user, boolean_t gtmrecv_startup)
} else
{ /* find create time of semaphore from the file header and check if the id is reused by others */
semarg.buf = &semstat;
- if (-1 == semctl(repl_instance.recvpool_semid, 0, IPC_STAT, semarg))
+ if (-1 == semctl(repl_instance.recvpool_semid, DB_CONTROL_SEM, IPC_STAT, semarg))
{
save_errno = errno;
ftok_sem_release(recvpool.recvpool_dummy_reg, TRUE, TRUE);
@@ -205,6 +205,7 @@ void recvpool_init(recvpool_user pool_user, boolean_t gtmrecv_startup)
RTS_ERROR_LITERAL("Error with receive pool semaphores"), errno);
}
udi->grabbed_access_sem = TRUE;
+ udi->counter_acc_incremented = TRUE;
if (INVALID_SHMID == repl_instance.recvpool_shmid)
{ /* We have an INVALID shmid in the file header. There are three ways this can happen
*
@@ -234,7 +235,7 @@ void recvpool_init(recvpool_user pool_user, boolean_t gtmrecv_startup)
} else if (-1 == shmctl(repl_instance.recvpool_shmid, IPC_STAT, &shmstat))
{ /* shared memory ID was removed form the system by an IPCRM command or we have a permission issue (or such) */
save_errno = errno;
- REMOVE_OR_RELEASE_SEM(new_ipc, udi);
+ REMOVE_OR_RELEASE_SEM(new_ipc);
ftok_sem_release(recvpool.recvpool_dummy_reg, TRUE, TRUE);
SNPRINTF(scndry_msg, OUT_BUFF_SIZE, "Error with shmctl on Receive Pool SHMID (%d)", repl_instance.recvpool_shmid);
rts_error(VARLSTCNT(9) ERR_REPLREQROLLBACK, 2, full_len, udi->fn, ERR_TEXT, 2, LEN_AND_STR(scndry_msg), save_errno);
@@ -250,7 +251,7 @@ void recvpool_init(recvpool_user pool_user, boolean_t gtmrecv_startup)
}
if (new_ipc && (GTMRECV != pool_user || !gtmrecv_startup))
{
- REMOVE_OR_RELEASE_SEM(new_ipc, udi);
+ REMOVE_OR_RELEASE_SEM(new_ipc);
ftok_sem_release(recvpool.recvpool_dummy_reg, TRUE, TRUE);
rts_error(VARLSTCNT(4) ERR_NORECVPOOL, 2, full_len, udi->fn);
}
@@ -290,6 +291,7 @@ void recvpool_init(recvpool_user pool_user, boolean_t gtmrecv_startup)
else
rel_sem_immediate(RECV, RECV_POOL_ACCESS_SEM);
udi->grabbed_access_sem = FALSE;
+ udi->counter_acc_incremented = FALSE;
ftok_sem_release(recvpool.recvpool_dummy_reg, TRUE, TRUE);
rts_error(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Error with receive pool shmat"), save_errno);
@@ -314,6 +316,7 @@ void recvpool_init(recvpool_user pool_user, boolean_t gtmrecv_startup)
else
rel_sem_immediate(RECV, RECV_POOL_ACCESS_SEM);
udi->grabbed_access_sem = FALSE;
+ udi->counter_acc_incremented = FALSE;
ftok_sem_release(recvpool.recvpool_dummy_reg, TRUE, TRUE);
rts_error(VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Receive pool has not been initialized"));
@@ -386,7 +389,7 @@ void recvpool_init(recvpool_user pool_user, boolean_t gtmrecv_startup)
assert(NULL != jnlpool.repl_inst_filehdr);
DEBUG_ONLY(repl_csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs;)
assert(!repl_csa->hold_onto_crit); /* so it is ok to invoke "grab_lock" and "rel_lock" unconditionally */
- grab_lock(jnlpool.jnlpool_dummy_reg, ASSERT_NO_ONLINE_ROLLBACK);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK);
jnlpool.repl_inst_filehdr->recvpool_shmid = udi->shmid;
jnlpool.repl_inst_filehdr->recvpool_semid = udi->semid;
jnlpool.repl_inst_filehdr->recvpool_shmid_ctime = udi->gt_shm_ctime;
@@ -404,6 +407,7 @@ void recvpool_init(recvpool_user pool_user, boolean_t gtmrecv_startup)
{
rel_sem(RECV, RECV_POOL_ACCESS_SEM);
udi->grabbed_access_sem = FALSE;
+ udi->counter_acc_incremented = FALSE;
if (!ftok_sem_release(recvpool.recvpool_dummy_reg, FALSE, FALSE))
rts_error(VARLSTCNT(1) ERR_RECVPOOLSETUP);
}
@@ -422,6 +426,7 @@ void recvpool_init(recvpool_user pool_user, boolean_t gtmrecv_startup)
else
rel_sem_immediate(RECV, RECV_POOL_ACCESS_SEM);
udi->grabbed_access_sem = FALSE;
+ udi->counter_acc_incremented = FALSE;
ftok_sem_release(recvpool.recvpool_dummy_reg, TRUE, TRUE);
rts_error(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
RTS_ERROR_LITERAL("Error with receive pool options semaphore"), save_errno);
diff --git a/sr_unix/repl_inst_create.c b/sr_unix/repl_inst_create.c
index 1727498..1c85f1b 100644
--- a/sr_unix/repl_inst_create.c
+++ b/sr_unix/repl_inst_create.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2006, 2011 Fidelity Information Services, Inc *
+ * Copyright 2006, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -81,6 +81,7 @@ void repl_inst_create(void)
gtmsrc_lcl_ptr_t gtmsrc_lcl_array;
mstr log_nam, trans_name;
uint4 status2;
+ jnl_tm_t now;
if (!repl_inst_get_name(inst_fn, &inst_fn_len, MAX_FN_LEN + 1, issue_rts_error))
GTMASSERT; /* rts_error should have been issued by repl_inst_get_name */
@@ -132,8 +133,9 @@ void repl_inst_create(void)
rts_error(VARLSTCNT(4) ERR_REPLINSTSTNDALN, 2, inst_fn_len, inst_fn);
assert(FALSE);
}
+ JNL_SHORT_TIME(now);
if (SS_NORMAL != (status = prepare_unique_name((char *)inst_fn, inst_fn_len, "", "",
- rename_fn, &rename_fn_len, &status2)))
+ rename_fn, &rename_fn_len, now, &status2)))
{
gtm_putmsg(VARLSTCNT(4) ERR_TEXT, 2, LEN_AND_LIT("Error preparing unique name for renaming instance file"));
if (SS_NORMAL != status2)
diff --git a/sr_unix/repl_inst_dump.c b/sr_unix/repl_inst_dump.c
index 7a55b28..06c3cd6 100644
--- a/sr_unix/repl_inst_dump.c
+++ b/sr_unix/repl_inst_dump.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2006, 2012 Fidelity Information Services, Inc *
+ * Copyright 2006, 2013 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 "gtmrecv.h"
#include "repl_inst_dump.h"
#include "repl_log.h" /* for "repl_log" prototype */
+#include "iotcpdef.h" /* for SA_MAXLEN */
LITDEF char state_array[][23] = {
"DUMMY_STATE",
@@ -699,10 +700,12 @@ void repl_inst_dump_jnlpoolctl(jnlpool_ctl_ptr_t jnlpool_ctl)
void repl_inst_dump_gtmsourcelocal(gtmsource_local_ptr_t gtmsourcelocal_ptr)
{
- int idx;
+ int idx, idx2;
char *string;
boolean_t first_time = TRUE;
repl_conn_info_t *remote_side;
+ int errcode;
+ char secondary_addr[SA_MAXLEN + 1];
for (idx = 0; idx < NUM_GTMSRC_LCL; idx++, gtmsourcelocal_ptr++)
{
@@ -731,8 +734,16 @@ void repl_inst_dump_gtmsourcelocal(gtmsource_local_ptr_t gtmsourcelocal_ptr)
gtmsourcelocal_ptr->gtmsource_pid);
PRINT_OFFSET_PREFIX(offsetof(gtmsource_local_struct, mode), SIZEOF(gtmsourcelocal_ptr->mode));
- string = (GTMSOURCE_MODE_PASSIVE == gtmsourcelocal_ptr->mode) ? "PASSIVE" :
- ((GTMSOURCE_MODE_ACTIVE == gtmsourcelocal_ptr->mode) ? "ACTIVE" : "UNKNOWN");
+ if (GTMSOURCE_MODE_ACTIVE == gtmsourcelocal_ptr->mode)
+ string = "ACTIVE";
+ else if (GTMSOURCE_MODE_PASSIVE == gtmsourcelocal_ptr->mode)
+ string = "PASSIVE";
+ else if (GTMSOURCE_MODE_ACTIVE_REQUESTED == gtmsourcelocal_ptr->mode)
+ string = "ACTIVE REQUESTED";
+ else if (GTMSOURCE_MODE_PASSIVE_REQUESTED == gtmsourcelocal_ptr->mode)
+ string = "PASSIVE REQUESTED";
+ else
+ string = "UNKNOWN";
if (MEMCMP_LIT(string, "UNKNOWN"))
util_out_print( PREFIX_SOURCELOCAL "Source Server Mode !R22AZ", TRUE, idx, string);
else
@@ -868,11 +879,24 @@ void repl_inst_dump_gtmsourcelocal(gtmsource_local_ptr_t gtmsourcelocal_ptr)
util_out_print( PREFIX_SOURCELOCAL "Secondary HOSTNAME !AZ",
TRUE, idx, gtmsourcelocal_ptr->secondary_host);
}
+ PRINT_OFFSET_PREFIX(offsetof(gtmsource_local_struct, secondary_af),
+ SIZEOF(gtmsourcelocal_ptr->secondary_af));
+ string = (AF_INET == gtmsourcelocal_ptr->secondary_af)? "IPv4" :
+ ((AF_INET6 == gtmsourcelocal_ptr->secondary_af) ? "IPv6" : "UNKNOWN");
+ util_out_print( PREFIX_SOURCELOCAL "Secondary Address Family !R10AZ",TRUE, idx, string);
PRINT_OFFSET_PREFIX(offsetof(gtmsource_local_struct, secondary_inet_addr),
SIZEOF(gtmsourcelocal_ptr->secondary_inet_addr));
- util_out_print( PREFIX_SOURCELOCAL "Secondary INET Address !10UL [0x!XL]", TRUE, idx,
- gtmsourcelocal_ptr->secondary_inet_addr, gtmsourcelocal_ptr->secondary_inet_addr);
+ errcode = getnameinfo((struct sockaddr *)>msourcelocal_ptr->secondary_inet_addr,
+ gtmsourcelocal_ptr->secondary_addrlen, secondary_addr, SA_MAXLEN, NULL, 0, NI_NUMERICHOST);
+ if (0 == errcode)
+ {
+ util_out_print( PREFIX_SOURCELOCAL "Secondary INET Address !R24AZ", TRUE, idx, secondary_addr);
+ } else
+ {
+ string = "UNKNOWN";
+ util_out_print( PREFIX_SOURCELOCAL "Secondary INET Address !R10AZ", TRUE, idx, string);
+ }
PRINT_OFFSET_PREFIX(offsetof(gtmsource_local_struct, secondary_port), SIZEOF(gtmsourcelocal_ptr->secondary_port));
util_out_print( PREFIX_SOURCELOCAL "Secondary Port !10UL [0x!XL]", TRUE, idx,
diff --git a/sr_unix/repl_instance.c b/sr_unix/repl_instance.c
index d95677e..4311201 100644
--- a/sr_unix/repl_instance.c
+++ b/sr_unix/repl_instance.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -1263,7 +1263,7 @@ int4 repl_inst_reset_zqgblmod_seqno_and_tn(void)
* an online rollback is detected, return without resetting max_zqgblmod_seqno. The caller knows to take appropriate
* action (on seeing -1 as the return code).
*/
- grab_lock(jnlpool.jnlpool_dummy_reg, GRAB_LOCK_ONLY);
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, GRAB_LOCK_ONLY);
if (repl_csa->onln_rlbk_cycle != jnlpool.jnlpool_ctl->onln_rlbk_cycle)
{
assert(is_rcvr_server);
diff --git a/sr_unix/repl_log_init.c b/sr_unix/repl_log_init.c
index b029e3a..893791e 100644
--- a/sr_unix/repl_log_init.c
+++ b/sr_unix/repl_log_init.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -32,6 +32,7 @@
#include "repl_sp.h"
#include "send_msg.h"
#include "gtmmsg.h"
+#include "have_crit.h"
#ifdef __MVS__
#include "gtm_zos_io.h"
#endif
@@ -156,7 +157,7 @@ int repl_log_fd2fp(FILE **fp, int fd)
* FDOPEN will fail returning NULL for the file pointer. */
if (NULL != *fp)
FCLOSE(*fp, fclose_res);
- *fp = FDOPEN(fd, "a");
+ FDOPEN(*fp, fd, "a");
assert(NULL != *fp); /* we don't expect FDOPEN to fail */
return(SS_NORMAL);
}
diff --git a/sr_unix/repl_logfileinfo_get.c b/sr_unix/repl_logfileinfo_get.c
new file mode 100644
index 0000000..0e7777d
--- /dev/null
+++ b/sr_unix/repl_logfileinfo_get.c
@@ -0,0 +1,80 @@
+/****************************************************************
+ * *
+ * Copyright 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+#include <stddef.h>
+#include <errno.h>
+
+#include "mdef.h"
+#include "gtm_limits.h"
+#include "gtm_string.h"
+#include "gtm_stdio.h"
+#include "gtm_unistd.h"
+#include "repl_msg.h"
+#include "repl_log.h"
+#include "gdsroot.h"
+#include "have_crit.h"
+#include "min_max.h"
+
+error_def(ERR_FILENAMETOOLONG);
+
+GBLREF uint4 process_id;
+
+uint4 repl_logfileinfo_get(char *logfile, repl_logfile_info_msg_t *msgp, boolean_t cross_endian, FILE *logfp)
+{
+ uint4 status, fullpath_len, msglen;
+ int save_errno;
+ char fullpath[GTM_PATH_MAX], *cwdptr;
+
+ assert(NULL != msgp);
+ msgp->type = cross_endian ? GTM_BYTESWAP_32(REPL_LOGFILE_INFO) : REPL_LOGFILE_INFO;
+ assert(GTM_PATH_MAX >= REPL_LOGFILE_PATH_MAX);
+ assert(GTM_PATH_MAX >= PATH_MAX);
+ if (NULL == logfile)
+ {
+ GETCWD(fullpath, GTM_PATH_MAX, cwdptr);
+ assert(NULL != cwdptr);
+ if (NULL == cwdptr)
+ {
+ save_errno = errno;
+ assert(FALSE);
+ repl_log(logfp, TRUE, TRUE, "Could not obtain current working directory: %s\n", STRERROR(save_errno));
+ SNPRINTF(fullpath, GTM_PATH_MAX, "Could not obtain current working directory");
+ }
+ fullpath_len = STRLEN(fullpath);
+ } else if (!get_full_path(STR_AND_LEN(logfile), fullpath, &fullpath_len, GTM_PATH_MAX + 1, &status))
+ { /* Either GETCWD failed or buffer not large enough to hold the expanded logfile path. In either case, we don't want
+ * to error out as this is just a supplementary message. Copy whatever possible.
+ */
+ assert(ERR_FILENAMETOOLONG != status);
+ SNPRINTF(fullpath, GTM_PATH_MAX, logfile);
+ fullpath_len = STRLEN(fullpath);
+ /* Print a warning message for diagnostic purposes */
+ if (ERR_FILENAMETOOLONG != status)
+ repl_log(logfp, TRUE, TRUE, "Could not obtain current working directory: %s\n", STRERROR(status));
+ else
+ repl_log(logfp, TRUE, TRUE, "Could not obtain full path of log file: Path name exceeds %d characters\n",
+ GTM_PATH_MAX);
+ }
+ assert('\0' == fullpath[fullpath_len]);
+ fullpath_len = MIN(fullpath_len, REPL_LOGFILE_PATH_MAX);
+ fullpath[fullpath_len] = '\0'; /* truncate if needed */
+ fullpath_len++; /* So that, we copy and send null-terminator as well */
+ memcpy(msgp->fullpath, fullpath, fullpath_len);
+ msgp->fullpath_len = cross_endian ? GTM_BYTESWAP_32(fullpath_len) : fullpath_len;
+ assert(fullpath_len <= REPL_LOGFILE_PATH_MAX);
+ /* Receiver expects 8 byte alignment on data portion of the message. */
+ fullpath_len = ROUND_UP2(fullpath_len, REPL_MSG_ALIGN);
+ assert(fullpath_len <= REPL_LOGFILE_PATH_MAX + 1);
+ msglen = REPL_LOGFILE_INFO_MSGHDR_SZ + fullpath_len;
+ msgp->len = cross_endian ? GTM_BYTESWAP_32(msglen) : msglen;
+ msgp->proto_ver = REPL_PROTO_VER_THIS;
+ msgp->pid = cross_endian ? GTM_BYTESWAP_32(process_id) : process_id;
+ return msglen;
+}
diff --git a/sr_unix/repl_msg.h b/sr_unix/repl_msg.h
index 22518b5..ee47e53 100644
--- a/sr_unix/repl_msg.h
+++ b/sr_unix/repl_msg.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2006, 2012 Fidelity Information Services, Inc *
+ * Copyright 2006, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -50,6 +50,7 @@ enum
REPL_HISTREC, /* 31 */ /* sent in the middle of a journal record stream to signal start of new history */
REPL_NEED_STRMINFO, /* 32 */ /* sent by a supplementary source server to a supplementary receiver server */
REPL_STRMINFO, /* 33 */ /* sent in response to a REPL_NEED_STRMINFO message */
+ REPL_LOGFILE_INFO, /* 34 */ /* sent (at time of handshake) to communicate to one another the $CWD/logfile */
REPL_MSGTYPE_LAST=256 /* 256 */
/* any new message need to be added before REPL_MSGTYPE_LAST */
};
@@ -57,14 +58,22 @@ enum
#define REPL_PROTO_VER_UNINITIALIZED (char)0xFF /* -1, the least of the versions to denote an uninitialized version field */
#define REPL_PROTO_VER_DUALSITE (char)0x0 /* Versions GT.M V5.0 and prior that dont support multi site replication */
#define REPL_PROTO_VER_MULTISITE (char)0x1 /* Versions V5.1-000 and above that support multi site replication */
-#define REPL_PROTO_VER_MULTISITE_CMP (char)0x2 /* Versions V5.3-003 and above that suport multisite replication with
+#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 suport supplementary instances */
-#define REPL_PROTO_VER_THIS REPL_PROTO_VER_SUPPLEMENTARY
+#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_THIS REPL_PROTO_VER_REMOTE_LOGPATH
/* The current/latest version of the communication protocol between the
* primary (source server) and secondary (receiver server or rollback)
*/
+/* Below macro defines the maximum size of the replication logfile path information that will be sent across to the other side.
+ * While the actual path max is defined by GTM_PATH_MAX, the value of GTM_PATH_MAX differ across different platforms and so we
+ * cannot always be sure if this side can store the remote side's logfile path. Since REPL_LOGFILE_INFO message is sent across
+ * only during handshake, malloc too is an overkill. So, have a fixed size buffer (see repl_logfile_info_msg_t beow) bounded by
+ * the below size.
+ */
+#define REPL_LOGFILE_PATH_MAX 1023
/* A few of these flag bits (e.g. START_FLAG_SRCSRV_IS_VMS) are no longer used but they should not be removed just in case prior
* versions that used those bitslots communicate with a newer version that assigns a different meaning to those slots. Any new
@@ -371,6 +380,19 @@ typedef struct /* Used to send a message of type REPL_BADTRANS or REPL_CMP2UNCM
char filler_32[16];
} repl_badtrans_msg_t;
+typedef struct
+{
+ int4 type;
+ int4 len;
+ int4 fullpath_len;
+ uint4 pid;
+ char proto_ver;
+ char filler_32[15]; /* to ensure that at least 32 bytes are sent across (gtmrecv_fetchresync relies on this) */
+ char fullpath[REPL_LOGFILE_PATH_MAX + 1]; /* + 1 for null-terminator */
+} repl_logfile_info_msg_t;
+
+#define REPL_LOGFILE_INFO_MSGHDR_SZ OFFSETOF(repl_logfile_info_msg_t, fullpath[0])
+
#if defined(__osf__) && defined(__alpha)
# pragma pointer_size(save)
# pragma pointer_size(long)
@@ -406,5 +428,6 @@ void gtmsource_send_new_histrec(void);
void gtmrecv_repl_send(repl_msg_ptr_t msgp, int4 type, int4 len, char *msgtypestr, seq_num optional_seqno);
void gtmrecv_send_histinfo(repl_histinfo *histinfo);
void gtmrecv_check_and_send_instinfo(repl_needinst_msg_ptr_t need_instinfo_msg, boolean_t is_rcvr_srvr);
+uint4 repl_logfileinfo_get(char *logfile, repl_logfile_info_msg_t *msgp, boolean_t cross_endian, FILE *logfp);
#endif
diff --git a/sr_unix/repl_sem.c b/sr_unix/repl_sem.c
index a3a1b8f..2277135 100644
--- a/sr_unix/repl_sem.c
+++ b/sr_unix/repl_sem.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -81,12 +81,12 @@ void set_sem_set_src(int semid)
}
int init_sem_set_recvr(sem_key_t key, int nsems, permissions_t sem_flags)
{
+ int semid;
+
assert(IPC_PRIVATE == (key_t)key);
assert(SIZEOF(key_t) >= SIZEOF(sem_key_t));
- sem_set_id[RECV] = semget(key, nsems, sem_flags);
- holds_sem[RECV][RECV_POOL_ACCESS_SEM] = FALSE;
- holds_sem[RECV][RECV_SERV_COUNT_SEM] = FALSE;
- holds_sem[RECV][UPD_PROC_COUNT_SEM] = FALSE;
+ semid = semget(key, nsems, sem_flags);
+ set_sem_set_recvr(semid);
return sem_set_id[RECV];
}
void set_sem_set_recvr(int semid)
@@ -95,6 +95,7 @@ void set_sem_set_recvr(int semid)
holds_sem[RECV][RECV_POOL_ACCESS_SEM] = FALSE;
holds_sem[RECV][RECV_SERV_COUNT_SEM] = FALSE;
holds_sem[RECV][UPD_PROC_COUNT_SEM] = FALSE;
+ holds_sem[RECV][RECV_SERV_OPTIONS_SEM] = FALSE;
}
int grab_sem(int set_index, int sem_num)
diff --git a/sr_unix/rtnhdr.h b/sr_unix/rtnhdr.h
index bc85792..d72f8c9 100644
--- a/sr_unix/rtnhdr.h
+++ b/sr_unix/rtnhdr.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -147,6 +147,9 @@ typedef struct
#define CODE_BASE_ADDR(rtnhdr) ((rtnhdr)->ptext_adr)
#define CODE_OFFSET(rtnhdr, addr) ((char *)(addr) - (char *)(rtnhdr->ptext_adr))
+#define DYNAMIC_LITERALS_ENABLED(rtnhdr) ((rtnhdr)->compiler_qlf & CQ_DYNAMIC_LITERALS)
+#define RW_REL_START_ADR(rtnhdr) (((DYNAMIC_LITERALS_ENABLED(rtnhdr)) ? (char *)VARTAB_ADR(rtnhdr) : (char *)LITERAL_ADR(rtnhdr)))
+
/* Macro to determine if given address is inside code segment. Note that even though
* the PTEXT_END_ADR macro is the address of end_of_code + 1, we still want a <= check
* here because in many cases, the address being tested is the RETURN address from a
diff --git a/sr_unix/rts_error.c b/sr_unix/rts_error.c
index c191cb8..cb2dfd7 100644
--- a/sr_unix/rts_error.c
+++ b/sr_unix/rts_error.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -20,10 +20,20 @@
#include "gtmimagename.h"
#include "error.h"
#include "util.h"
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "gtmmsg.h"
+#include "repl_msg.h"
+#include "gtmsource.h"
+#include "anticipatory_freeze.h"
GBLREF int gtm_errno;
GBLREF boolean_t created_core;
GBLREF boolean_t dont_want_core;
+GBLREF gd_region *gv_cur_region;
+GBLREF jnlpool_addrs jnlpool;
error_def(ERR_ASSERT);
error_def(ERR_GTMASSERT);
@@ -38,15 +48,40 @@ error_def(ERR_REPLONLNRLBK);
error_def(ERR_STACKOFLOW);
error_def(ERR_TPRETRY);
+int rts_error_va(void *csa, int argcnt, va_list var);
+
/* ----------------------------------------------------------------------------------------
* WARNING: For chained error messages, all messages MUST be followed by an fao count;
* ======= zero MUST be specified if there are no parameters.
* ----------------------------------------------------------------------------------------
*/
+
int rts_error(int argcnt, ...)
{
- int msgid;
va_list var;
+ sgmnt_addrs *csa;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ csa = (ANTICIPATORY_FREEZE_AVAILABLE && jnlpool.jnlpool_ctl) ? REG2CSA(gv_cur_region) : NULL;
+ VAR_START(var, argcnt);
+ return rts_error_va(csa, argcnt, var);
+}
+
+int rts_error_csa(void *csa, int argcnt, ...)
+{
+ va_list var;
+
+ VAR_START(var, argcnt);
+ return rts_error_va(csa, argcnt, var);
+}
+
+int rts_error_va(void *csa, int argcnt, va_list var)
+{
+ int msgid;
+ va_list var_dup;
+ const err_msg *msg;
+ const err_ctl *ctl;
# ifdef DEBUG
DCL_THREADGBL_ACCESS;
@@ -61,11 +96,10 @@ int rts_error(int argcnt, ...)
assert(FALSE);
}
# endif
+ VAR_COPY(var_dup, var);
if (-1 == gtm_errno)
gtm_errno = errno;
- VAR_START(var, argcnt);
- msgid = va_arg(var, int);
- va_end(var);
+ msgid = va_arg(var_dup, int);
/* If there was a previous fatal error that did not yet get printed, do it before overwriting the
* util_output buffer with the about-to-be-handled nested error. This way one will see ALL the
* fatal error messages (e.g. assert failures) in the order in which they occurred instead of
@@ -84,14 +118,20 @@ int rts_error(int argcnt, ...)
*/
if (IS_GTMSECSHR_IMAGE)
util_out_print(NULL, RESET);
- VAR_START(var, argcnt); /* restart arg list */
- gtm_putmsg_list(argcnt, var);
- va_end(var);
+ if (NULL == (ctl = err_check(msgid)))
+ msg = NULL;
+ else
+ GET_MSG_INFO(msgid, ctl, msg);
+ error_condition = msgid;
+ severity = NULL == msg ? ERROR : SEVMASK(msgid);
+ gtm_putmsg_list(csa, argcnt, var);
if (DUMPABLE)
created_core = dont_want_core = FALSE; /* We can create a(nother) core now */
if (IS_GTMSECSHR_IMAGE)
util_out_print(NULL, OPER); /* gtmsecshr errors always immediately pushed out */
}
+ va_end(var_dup);
+ va_end(var);
DRIVECH(msgid); /* Drive the topmost (inactive) condition handler */
/* Note -- at one time there was code here to catch if we returned from the condition handlers
* when the severity was error or above. That code had to be removed because of several errors
diff --git a/sr_unix/runall.csh b/sr_unix/runall.csh
index 7a1f6ae..be64b40 100644
--- a/sr_unix/runall.csh
+++ b/sr_unix/runall.csh
@@ -1,7 +1,7 @@
#!/usr/local/bin/tcsh -f
#################################################################
# #
-# Copyright 2001, 2012 Fidelity Information Services, Inc #
+# Copyright 2001, 2013 Fidelity Information Services, Inc #
# #
# This source code contains the intellectual property #
# of its copyright holder(s), and is made available #
@@ -47,39 +47,6 @@ while (0 < $#)
endsw
shift
end
-#set temp=(`getopt nchl $argv:q`)
-#if ($? == 0) then
-# eval set argv=\($temp:q\)
-# while (1)
-# switch ($1:q)
-# case -n :
-# set listonly = 1
-# shift
-# breaksw
-#
-# case -c :
-# set compileonly = 1
-# shift
-# breaksw
-#
-# case -l :
-# set linkonly = 1
-# shift
-# breaksw
-#
-# case -h :
-# set helponly = 1
-# shift
-# breaksw
-#
-# case -- :
-# shift
-# break
-# endsw
-# end
-#else
-# set helponly = 1
-#endif
if ($helponly) then
echo "Usage : `basename $0` [-n|-c|-h] [file...]"
@@ -161,6 +128,7 @@ echo " RUNALL_VERSION ----> [ $RUNALL_VERSION ]"
echo " RUNALL_IMAGE ----> [ $RUNALL_IMAGE ]"
echo " RUNALL_EXTRA_CC_FLAGS ----> [ $RUNALL_EXTRA_CC_FLAGS ]"
echo " RUNALL_EXTRA_AS_FLAGS ----> [ $RUNALL_EXTRA_AS_FLAGS ]"
+echo " gtmroutines ----> [ $gtmroutines ]"
echo ""
if (`uname` == "SunOS") then
@@ -498,12 +466,14 @@ if (! -z ${TMP_DIR}_src_files) then
# gtm_startup_chk requires gtm_dist setup
rm -f ${file}_ctl.c ${file}_ansi.h # in case an old version is lying around
set real_gtm_dist = "$gtm_dist"
+ if ($?gtmroutines) set save_gtmroutines = "$gtmroutines"
setenv gtm_dist "$gtm_root/$gtm_curpro/pro"
setenv gtmroutines "$gtm_obj($gtm_pct)"
$gtm_root/$gtm_curpro/pro/mumps -run msg $gtm_src/$file.msg Unix
if (0 != $status) @ runall_status = $status
setenv gtm_dist "$real_gtm_dist"
unset real_gtm_dist
+ if ($?save_gtmroutines) setenv gtmroutines "$save_gtmroutines"
\mv -f ${file}_ctl.c $gtm_src/${file}_ctl.c
if ( -f ${file}_ansi.h ) then
\mv -f ${file}_ansi.h $gtm_inc
diff --git a/sr_unix/secshr_client.c b/sr_unix/secshr_client.c
index 1ca0a42..f4831ad 100644
--- a/sr_unix/secshr_client.c
+++ b/sr_unix/secshr_client.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -53,6 +53,7 @@
#include "secshr_client.h"
#include "gtm_semutils.h"
#include "hashtab.h" /* for STR_HASH macro */
+#include "fork_init.h"
GBLREF struct sockaddr_un gtmsecshr_sock_name;
GBLREF key_t gtmsecshr_key;
@@ -114,7 +115,7 @@ const static char readonly *secshrstart_error_code[] = {
errorindex = LASTEXITCODE; \
assert(0 <= errorindex); \
assert(ARRAYSIZE(secshrstart_error_code) > errorindex); \
- gtm_putmsg(VARLSTCNT(9) ERR_GTMSECSHRSTART, 3, RTS_ERROR_TEXT("Client"), \
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_GTMSECSHRSTART, 3, RTS_ERROR_TEXT("Client"), \
process_id, ERR_TEXT, 2, \
RTS_ERROR_STRING(secshrstart_error_code[errorindex])); \
if (FATALFAILURE(create_server_status)) \
@@ -197,19 +198,22 @@ int send_mesg2gtmsecshr(unsigned int code, unsigned int id, char *path, int path
if (SS_NORMAL != status)
{
if (SS_LOG2LONG == status)
- send_msg(VARLSTCNT(5) ERR_LOGTOOLONG, 3, gtmsecshr_logname.len, gtmsecshr_logname.addr,
- SIZEOF(gtmsecshr_path) - 1);
- send_msg(VARLSTCNT(9) ERR_GTMSECSHRSTART, 3, RTS_ERROR_TEXT("Client"), process_id,
- ERR_TEXT, 2, RTS_ERROR_STRING(secshrstart_error_code[INVTRANSGTMSECSHR]));
- rts_error(VARLSTCNT(9) ERR_GTMSECSHRSTART, 3, RTS_ERROR_TEXT("Client"), process_id,
- ERR_TEXT, 2, RTS_ERROR_STRING(secshrstart_error_code[INVTRANSGTMSECSHR]));
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_LOGTOOLONG, 3,
+ gtmsecshr_logname.len, gtmsecshr_logname.addr, SIZEOF(gtmsecshr_path) - 1);
+ 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]));
+ rts_error_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]));
}
gtmsecshr_pathname.addr[gtmsecshr_pathname.len] = '\0';
if (-1 == Stat(gtmsecshr_pathname.addr, &stat_buf))
- rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("stat"), CALLFROM, errno);
+ 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))
- rts_error(VARLSTCNT(1) ERR_GTMSECSHRPERM);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_GTMSECSHRPERM);
gtmsecshr_file_check_done = TRUE;
}
if (!gtmsecshr_sock_init_done && (0 < (init_ret_code = gtmsecshr_sock_init(CLIENT)))) /* Note assignment */
@@ -260,9 +264,10 @@ int send_mesg2gtmsecshr(unsigned int code, unsigned int id, char *path, int path
{
if (0 < loop_count)
/* No message unless attempted server start at least once */
- send_msg(VARLSTCNT(11) ERR_GTMSECSHRSRVF, 4, RTS_ERROR_TEXT("Client"), process_id,
- loop_count - 1, ERR_TEXT, 2, RTS_ERROR_TEXT("sendto to gtmsecshr failed"),
- save_errno);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(11) ERR_GTMSECSHRSRVF, 4,
+ RTS_ERROR_TEXT("Client"), process_id,
+ loop_count - 1, ERR_TEXT, 2,
+ RTS_ERROR_TEXT("sendto to gtmsecshr failed"), save_errno);
START_SERVER;
DBGGSSHR((LOGFLAGS, "secshr_client: sendto() failed - restarting server\n"));
}
@@ -303,8 +308,9 @@ int send_mesg2gtmsecshr(unsigned int code, unsigned int id, char *path, int path
continue;
if (EBADF == save_errno)
break;
- send_msg(VARLSTCNT(11) ERR_GTMSECSHRSRVF, 4, RTS_ERROR_TEXT("Client"), process_id, loop_count - 1,
- ERR_TEXT, 2, RTS_ERROR_TEXT("recvfrom from gtmsecshr failed"), save_errno);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(11) ERR_GTMSECSHRSRVF, 4,
+ RTS_ERROR_TEXT("Client"), process_id, loop_count - 1, ERR_TEXT, 2,
+ RTS_ERROR_TEXT("recvfrom from gtmsecshr failed"), save_errno);
if ((ECONNRESET == save_errno) || (ENOTCONN == save_errno))
{
num_chars_recvd = 0;
@@ -337,10 +343,10 @@ int send_mesg2gtmsecshr(unsigned int code, unsigned int id, char *path, int path
req_code, ret_code));
if (INVALID_COMKEY == ret_code)
{ /* Comkey mismatch means for a different version of GT.M - we will not handle it */
- send_msg(VARLSTCNT(13) ERR_GTMSECSHRSRVFIL, 7, RTS_ERROR_TEXT("Client"),
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFIL, 7, RTS_ERROR_TEXT("Client"),
process_id, mesg.pid, req_code, RTS_ERROR_TEXT(mesg.mesg.path),
ERR_TEXT, 2, RTS_ERROR_STRING("Communicating with wrong GT.M version"));
- rts_error(VARLSTCNT(13) ERR_GTMSECSHRSRVFIL, 7, RTS_ERROR_TEXT("Client"),
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFIL, 7, RTS_ERROR_TEXT("Client"),
process_id, mesg.pid, req_code, RTS_ERROR_TEXT(mesg.mesg.path),
ERR_TEXT, 2, RTS_ERROR_STRING("Communicating with wrong GT.M version"));
break; /* rts_error should not return */
@@ -353,10 +359,11 @@ int send_mesg2gtmsecshr(unsigned int code, unsigned int id, char *path, int path
* handles actual error.
*/
if ((-1 != Stat(path, &stat_buf)) || (ENOENT != ret_code))
- send_msg(VARLSTCNT(14) ERR_GTMSECSHRSRVFIL, 7, RTS_ERROR_TEXT("Client"),
- process_id, mesg.pid, req_code, RTS_ERROR_TEXT(mesg.mesg.path),
- ERR_TEXT, 2, RTS_ERROR_STRING(secshr_fail_mesg_code[req_code]),
- mesg.code);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(14) ERR_GTMSECSHRSRVFIL, 7,
+ RTS_ERROR_TEXT("Client"),
+ process_id, mesg.pid, req_code, RTS_ERROR_TEXT(mesg.mesg.path),
+ ERR_TEXT, 2, RTS_ERROR_STRING(secshr_fail_mesg_code[req_code]),
+ mesg.code);
else
ret_code = 0; /* File is gone so this or a previous try actually worked */
break;
@@ -365,10 +372,11 @@ int send_mesg2gtmsecshr(unsigned int code, unsigned int id, char *path, int path
* got a reply confused or lost). If not there, no error. Else error to op-log.
*/
if ((-1 != semctl(id, 0, GETVAL)) && !SEM_REMOVED(errno))
- send_msg(VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6, RTS_ERROR_TEXT("Client"),
- process_id, mesg.pid, req_code, mesg.mesg.id, ERR_TEXT, 2,
- RTS_ERROR_STRING(secshr_fail_mesg_code[req_code]),
- mesg.code);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6,
+ RTS_ERROR_TEXT("Client"),
+ process_id, mesg.pid, req_code, mesg.mesg.id, ERR_TEXT, 2,
+ RTS_ERROR_STRING(secshr_fail_mesg_code[req_code]),
+ mesg.code);
else
ret_code = 0; /* File is gone so this or a previous try actually worked */
case REMOVE_SHM:
@@ -377,21 +385,23 @@ int send_mesg2gtmsecshr(unsigned int code, unsigned int id, char *path, int path
* Note -
*/
if ((-1 != shmctl(id, IPC_STAT, &shm_info)) && !SEM_REMOVED(errno))
- send_msg(VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6, RTS_ERROR_TEXT("Client"),
- process_id, mesg.pid, req_code, mesg.mesg.id, ERR_TEXT, 2,
- RTS_ERROR_STRING(secshr_fail_mesg_code[req_code]),
- mesg.code);
- else
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6,
+ RTS_ERROR_TEXT("Client"),
+ process_id, mesg.pid, req_code, mesg.mesg.id, ERR_TEXT, 2,
+ RTS_ERROR_STRING(secshr_fail_mesg_code[req_code]),
+ mesg.code);
+ else
ret_code = 0; /* File is gone so this or a previous try actually worked */
break;
case FLUSH_DB_IPCS_INFO: /* Errors handled by caller */
break;
default:
if (EPERM != mesg.code && EACCES != mesg.code)
- send_msg(VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6, RTS_ERROR_TEXT("Client"),
- process_id, mesg.pid, req_code, mesg.mesg.id, ERR_TEXT, 2,
- RTS_ERROR_STRING(secshr_fail_mesg_code[req_code]),
- mesg.code);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(13) ERR_GTMSECSHRSRVFID, 6,
+ RTS_ERROR_TEXT("Client"),
+ process_id, mesg.pid, req_code, mesg.mesg.id, ERR_TEXT, 2,
+ RTS_ERROR_STRING(secshr_fail_mesg_code[req_code]),
+ mesg.code);
break;
}
}
@@ -400,14 +410,17 @@ int send_mesg2gtmsecshr(unsigned int code, unsigned int id, char *path, int path
if (MAX_COMM_ATTEMPTS < loop_count)
{
ret_code = -1;
- gtm_putmsg(VARLSTCNT(10) ERR_GTMSECSHRSRVF, 4, RTS_ERROR_TEXT("Client"), process_id, loop_count - 1,
- ERR_TEXT, 2, RTS_ERROR_TEXT("Unable to communicate with gtmsecshr"));
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_GTMSECSHRSRVF, 4,
+ RTS_ERROR_TEXT("Client"), process_id, loop_count - 1,
+ ERR_TEXT, 2, RTS_ERROR_TEXT("Unable to communicate with gtmsecshr"));
/* If gtm_tmp is not defined, show default path */
if (gtm_tmp_ptr = GETENV("gtm_tmp"))
- send_msg(VARLSTCNT(8) ERR_GTMSECSHRTMPPATH, 2, RTS_ERROR_TEXT(gtm_tmp_ptr),
- ERR_TEXT, 2, RTS_ERROR_TEXT("(from $gtm_tmp)"));
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_GTMSECSHRTMPPATH, 2,
+ RTS_ERROR_TEXT(gtm_tmp_ptr),
+ ERR_TEXT, 2, RTS_ERROR_TEXT("(from $gtm_tmp)"));
else
- send_msg(VARLSTCNT(4) ERR_GTMSECSHRTMPPATH, 2, RTS_ERROR_TEXT("/tmp"));
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4)
+ ERR_GTMSECSHRTMPPATH, 2, RTS_ERROR_TEXT("/tmp"));
}
if (ONETIMESOCKET == init_ret_code)
gtmsecshr_sock_cleanup(CLIENT);
@@ -425,14 +438,15 @@ int create_server(void)
# endif
int save_errno;
- if (0 == (child_pid = fork())) /* BYPASSOK: we exec immediately, no FORK_CLEAN needed */
+ FORK(child_pid); /* BYPASSOK: we exec immediately, no FORK_CLEAN needed */
+ if (0 == child_pid)
{
process_id = getpid();
/* Do exec using gtmsecshr_path, which was initialize in file check code - send_mesg2gtmsecshr */
status = EXECL(gtmsecshr_path, gtmsecshr_path, 0);
if (-1 == status)
{
- send_msg(VARLSTCNT(9) ERR_GTMSECSHRSTART, 3, RTS_ERROR_TEXT("Client"), process_id,
+ 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);
}
@@ -441,7 +455,7 @@ int create_server(void)
if (-1 == child_pid)
{
status = GNDCHLDFORKFLD;
- gtm_putmsg(VARLSTCNT(10) ERR_GTMSECSHRSTART, 3, RTS_ERROR_TEXT("Client"), process_id,
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_GTMSECSHRSTART, 3, RTS_ERROR_TEXT("Client"), process_id,
ERR_TEXT, 2, RTS_ERROR_TEXT("Failed to fork off gtmsecshr"), errno);
/* Sleep for a while and hope a subsequent fork will succeed */
hiber_start(1000);
@@ -461,8 +475,9 @@ int create_server(void)
else if (EINTR != errno)
{
status = GNDCHLDFORKFLD;
- gtm_putmsg(VARLSTCNT(10) ERR_GTMSECSHRSTART, 3, RTS_ERROR_TEXT("Client"), process_id,
- ERR_TEXT, 2, RTS_ERROR_TEXT("Error spawning gtmsecshr"), errno);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_GTMSECSHRSTART, 3,
+ RTS_ERROR_TEXT("Client"), process_id,
+ ERR_TEXT, 2, RTS_ERROR_TEXT("Error spawning gtmsecshr"), errno);
}
}
}
diff --git a/sr_unix/semstat2.c b/sr_unix/semstat2.c
index ce779f8..1b53e0d 100644
--- a/sr_unix/semstat2.c
+++ b/sr_unix/semstat2.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -58,7 +58,7 @@ int main (int argc, char *argv[])
if (argc == 1)
{
usage(argv[0]);
- exit(1);
+ exit(EXIT_FAILURE);
}
semarg.buf = &semstat;
for(i=1; i< argc; i++)
@@ -110,5 +110,5 @@ int main (int argc, char *argv[])
PRINTF("sempid=%d)\n", sempid);
}
}
- exit(0);
+ exit(EXIT_SUCCESS);
}
diff --git a/sr_unix/send_msg.c b/sr_unix/send_msg.c
index f08df57..c8c67ea 100644
--- a/sr_unix/send_msg.c
+++ b/sr_unix/send_msg.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -35,11 +35,16 @@ GBLREF bool caller_id_flag;
GBLREF volatile int4 exit_state;
GBLREF volatile boolean_t timer_in_handler;
GBLREF jnlpool_addrs jnlpool;
+GBLREF gd_region *gv_cur_region;
+GBLREF jnlpool_addrs jnlpool;
+GBLREF VSIG_ATOMIC_T forced_exit;
#ifdef DEBUG
static uint4 nesting_level = 0;
#endif
+void send_msg_va(void *csa, int arg_count, va_list var);
+
/*
** WARNING: For chained error messages, all messages MUST be followed by an fao count;
** ======= zero MUST be specified if there are no parameters.
@@ -50,6 +55,27 @@ static uint4 nesting_level = 0;
void send_msg(int arg_count, ...)
{
va_list var;
+ sgmnt_addrs *csa;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ csa = (ANTICIPATORY_FREEZE_AVAILABLE && jnlpool.jnlpool_ctl) ? REG2CSA(gv_cur_region) : NULL;
+ VAR_START(var, arg_count);
+ send_msg_va(csa, arg_count, var);
+ va_end(var);
+}
+
+void send_msg_csa(void *csa, int arg_count, ...)
+{
+ va_list var;
+
+ VAR_START(var, arg_count);
+ send_msg_va(csa, arg_count, var);
+ va_end(var);
+}
+
+void send_msg_va(void *csa, int arg_count, va_list var)
+{
int dummy, fao_actual, fao_count, i, msg_id, freeze_msg_id;
char msg_buffer[1024];
mstr msg_string;
@@ -61,14 +87,15 @@ void send_msg(int arg_count, ...)
SETUP_THREADGBL_ACCESS;
/* Since send_msg uses a global variable buffer, reentrant calls to send_msg will use the same buffer.
- * Ensure we never overwrite an under-construction send_msg buffer with a nested send_msg call. The
- * only exception to this is if the nested call to send_msg is done by exit handling code in which case
- * the latest send_msg call prevails and it is ok since we will never return to the original send_msg()
- * call again. Detect if ever this assmption gets violated with an assert.
+ * Ensure we never overwrite an under-construction send_msg buffer with a nested send_msg call. One
+ * exception to this is if the nested call to send_msg is done by exit handling code in which case the
+ * latest send_msg call prevails and it is ok since we will never return to the original send_msg call
+ * again. The other exception is if enable interrupts in util_out_send_oper results in a new send_msg
+ * in deferred_signal_handler.
*/
- assert((0 == nesting_level) || ((2 > nesting_level) && timer_in_handler) || (EXIT_IMMED == exit_state));
+ assert((0 == nesting_level) || ((2 > nesting_level) && timer_in_handler)
+ || (EXIT_IMMED == exit_state) || (2 == forced_exit));
DEBUG_ONLY(nesting_level++;)
- VAR_START(var, arg_count);
assert(arg_count > 0);
if ((NULL != TREF(util_outptr)) && (TREF(util_outptr) != TREF(util_outbuff_ptr)))
{
@@ -78,7 +105,7 @@ void send_msg(int arg_count, ...)
for (;;)
{
msg_id = (int) va_arg(var, VA_ARG_TYPE);
- CHECK_IF_FREEZE_ON_ERROR_NEEDED(msg_id, freeze_needed, freeze_msg_id);
+ CHECK_IF_FREEZE_ON_ERROR_NEEDED(csa, msg_id, freeze_needed, freeze_msg_id);
--arg_count;
msg_string.addr = msg_buffer;
msg_string.len = SIZEOF(msg_buffer);
@@ -109,12 +136,11 @@ void send_msg(int arg_count, ...)
}
util_out_print("!/", NOFLUSH);
}
- va_end(var);
util_out_print(NULL, OPER);
RESTORE_UTIL_OUT_BUFFER(save_util_outptr, save_last_va_list_ptr, util_copy_saved);
/* it has been suggested that this would be a place to check a view_debugN
* and conditionally enter a "forever" loop on wcs_sleep for unix debugging
*/
DEBUG_ONLY(nesting_level--;)
- FREEZE_INSTANCE_IF_NEEDED(freeze_needed, freeze_msg_id);
+ FREEZE_INSTANCE_IF_NEEDED(csa, freeze_needed, freeze_msg_id);
}
diff --git a/sr_unix/sig_init.c b/sr_unix/sig_init.c
index fd832af..363b9f4 100644
--- a/sr_unix/sig_init.c
+++ b/sr_unix/sig_init.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -21,120 +21,125 @@
#include "sig_init.h"
#include "gtmci_signals.h"
+#ifdef GTM_PTHREAD
+GBLREF boolean_t gtm_jvm_process;
+#endif
+
void null_handler(int sig);
void sig_init(void (*signal_handler)(), void (*ctrlc_handler)(), void (*suspsig_handler)(), void (*continue_handler)())
{
- struct sigaction ignore, act;
+ struct sigaction ignore, null_action, def_action, susp_action,
+ gen_action, ctrlc_action, cont_action;
int sig;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
+ memset(&ignore, 0, SIZEOF(ignore));
+ sigemptyset(&ignore.sa_mask);
- memset(&act, 0, SIZEOF(act));
- sigemptyset(&act.sa_mask);
- ignore = act;
+ /* Copying only up to susp_action here to later specify SA_SIGINFO flag and continue copying with it. */
+ null_action = def_action = susp_action = ignore;
ignore.sa_handler = SIG_IGN;
+ null_action.sa_handler = null_handler;
+ def_action.sa_handler = SIG_DFL;
- for (sig = 1; sig <= NSIG; sig++)
- sigaction(sig, &ignore, NULL);
-
- /* --------------------------------------------------------------
- * Tandem hack: rather than ignore SIGHUP, we must catch it
- * and do nothing with the signal. This prevents ioctls on
- * modem/tty devices from hanging when carrier drops during
- * the system call.
- * --------------------------------------------------------------
- */
- act.sa_handler = null_handler;
- sigaction(SIGHUP, &act, NULL);
-
- /* --------------------------------------------------------------
- * Default handling necessary for SIGCLD signal.
- * CAUTION :consider the affect on JOB (timeout) implementation before
- * changing this behaviour (like defuncts, ECHILD errors etc..)
- * --------------------------------------------------------------
- */
- act.sa_handler = SIG_DFL;
- sigaction(SIGCLD, &act, NULL);
-
- /* --------------------------------------------------------------
- * Give us extra info on the following signals and a full core
- * if necessary.
- * --------------------------------------------------------------
- */
- act.sa_flags = SA_SIGINFO;
-
- /* --------------------------------------------------------------
- * Signals that suspend a process
- * --------------------------------------------------------------
- */
- if (NULL != suspsig_handler)
- {
- act.sa_sigaction = suspsig_handler;
- sigaction(SIGTSTP, &act, NULL);
- sigaction(SIGTTIN, &act, NULL);
- sigaction(SIGTTOU, &act, NULL);
- }
+ /* Give us extra info on the following signals and a full core if necessary. */
+ susp_action.sa_flags = SA_SIGINFO;
+ gen_action = ctrlc_action = cont_action = susp_action;
+ susp_action.sa_sigaction = suspsig_handler;
+ gen_action.sa_sigaction = signal_handler;
+ ctrlc_action.sa_sigaction = ctrlc_handler;
+ cont_action.sa_sigaction = continue_handler;
- /* --------------------------------------------------------------
- * Set special rundown handler for the following terminal signals
- * --------------------------------------------------------------
- */
- act.sa_sigaction = signal_handler;
-
- sigaction(SIGABRT, &act, NULL);
- sigaction(SIGBUS, &act, NULL);
-# ifdef _AIX
- sigaction(SIGDANGER, &act, NULL);
-# endif
- sigaction(SIGFPE, &act, NULL);
-# ifdef __MVS__
- sigaction(SIGABND, &act, NULL);
-# else
-# ifndef __linux__
- sigaction(SIGEMT, &act, NULL);
-# endif
-# ifndef __CYGWIN__
- sigaction(SIGIOT, &act, NULL);
-# endif
-# endif
- sigaction(SIGILL, &act, NULL);
- sigaction(SIGQUIT, &act, NULL);
- sigaction(SIGSEGV, &act, NULL);
-# ifndef __linux__
- sigaction(SIGSYS, &act, NULL);
-# endif
- sigaction(SIGTERM, &act, NULL);
- sigaction(SIGTRAP, &act, NULL);
-
- /* --------------------------------------------------------------
- * If supplied with a control-C handler, install it now.
- * --------------------------------------------------------------
- */
- if (NULL != ctrlc_handler)
- {
- act.sa_sigaction = ctrlc_handler;
- sigaction(SIGINT, &act, NULL);
- }
-
- /* --------------------------------------------------------------
- * Special handling for SIGCONT
- * --------------------------------------------------------------
- */
- if (NULL != continue_handler)
+ for (sig = 1; sig <= NSIG; sig++)
{
-# ifndef DISABLE_SIGCONT_PROCESSING
- if (FALSE == TREF(disable_sigcont))
+ switch (sig)
{
- act.sa_sigaction = continue_handler;
- sigaction(SIGCONT, &act, NULL);
+ case SIGHUP:
+ /* Tandem hack: rather than ignore SIGHUP, we must catch it and do nothing with the signal. This
+ * prevents ioctls on modem/tty devices from hanging when carrier drops during the system call.
+ */
+ sigaction(sig, &null_action, NULL);
+ break;
+ case SIGCLD:
+ /* Default handling necessary for SIGCLD signal. CAUTION: consider the affect on JOB (timeout)
+ * implementation before changing this behavior (like defuncts, ECHILD errors, etc.).
+ */
+ sigaction(sig, &def_action, NULL);
+ break;
+ case SIGTSTP:
+ case SIGTTIN:
+ case SIGTTOU:
+ /* These are all signals that suspend a process. */
+ if (NULL != suspsig_handler)
+ sigaction(sig, &susp_action, NULL);
+ else
+ sigaction(sig, &ignore, NULL);
+ break;
+ case SIGINT:
+ /* If supplied with a control-C handler, install it now. */
+ if (NULL != ctrlc_handler)
+ sigaction(sig, &ctrlc_action, NULL);
+ else
+ sigaction(sig, &ignore, NULL);
+ break;
+ case SIGCONT:
+ /* Special handling for SIGCONT. */
+ if (NULL != continue_handler)
+ {
+# ifndef DISABLE_SIGCONT_PROCESSING
+ if (FALSE == TREF(disable_sigcont))
+ sigaction(SIGCONT, &cont_action, NULL);
+# else
+ TREF(disable_sigcont) = TRUE;
+# endif
+ } else
+ {
+ sigaction(sig, &ignore, NULL);
+ TREF(disable_sigcont) = TRUE;
+ }
+ break;
+ case SIGSEGV:
+# ifdef GTM_PTHREAD
+ if (gtm_jvm_process)
+ break;
+# endif
+ case SIGABRT:
+# ifdef GTM_PTHREAD
+ if (gtm_jvm_process)
+ break;
+# endif
+ case SIGBUS:
+# ifdef _AIX
+ case SIGDANGER:
+# endif
+ case SIGFPE:
+# ifdef __MVS__
+ case SIGABND:
+# else
+ /* On Linux SIGIOT is commonly same as SIGABRT, so to avoid duplicate cases, check for that. */
+# if !defined(__CYGWIN__) && defined (SIGIOT) && (SIGIOT != SIGABRT)
+ case SIGIOT:
+# endif
+# ifndef __linux__
+ case SIGEMT:
+# endif
+# endif
+ case SIGILL:
+ case SIGQUIT:
+# ifndef __linux__
+ case SIGSYS:
+# endif
+ case SIGTERM:
+ case SIGTRAP:
+ /* These are all being handled by the generic_signal_handler. */
+ sigaction(sig, &gen_action, NULL);
+ break;
+ default:
+ sigaction(sig, &ignore, NULL);
}
-# else
- TREF(disable_sigcont) = TRUE;
-# endif
- } else
- TREF(disable_sigcont) = TRUE;
+ }
}
/* Provide null signal handler */
diff --git a/sr_unix/sleep.h b/sr_unix/sleep.h
index 70b9741..3a1bc6a 100644
--- a/sr_unix/sleep.h
+++ b/sr_unix/sleep.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2007 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -12,11 +12,10 @@
#ifndef SLEEP_H
#define SLEEP_H
-/* Note: GT.M code *MUST*NOT* make use of the sleep() function because use of the sleep() function
- causes problems with GT.M's timers on some platforms. Specifically, the sleep() function
- causes the SIGARLM handler to be silently deleted on Solaris systems (through Solaris 9 at least).
- This leads to lost timer pops and has the potential for system hangs. The proper long sleep mechanism
- is hiber_start which can be accessed through the LONG_SLEEP macro defined in mdef.h.
+/* Note: GT.M code *MUST NOT* use the sleep function because it causes problems with GT.M's timers on some platforms. Specifically,
+ * the sleep function results in SIGARLM handler being silently deleted on Solaris systems (through Solaris 9 at least). This leads
+ * to lost timer pops and has the potential for system hangs. The proper long sleep mechanism is hiber_start which can be accessed
+ * through the LONG_SLEEP macro defined in mdef.h.
*/
int m_sleep(int seconds);
@@ -31,6 +30,135 @@ int m_nsleep(int nseconds);
# endif
# endif
+#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 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); \
+ } \
+}
+#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.
+ */
+# 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
diff --git a/sr_unix/source_file.c b/sr_unix/source_file.c
index 5117109..ed67b46 100644
--- a/sr_unix/source_file.c
+++ b/sr_unix/source_file.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -32,6 +32,7 @@
#include "cmd_qlf.h"
#include "min_max.h"
#include "cli.h"
+#include "have_crit.h"
GBLREF unsigned short source_name_len;
GBLREF unsigned char source_file_name[];
@@ -219,7 +220,7 @@ bool open_source_file (void)
int_module_name.len = routine_name.len;
if ('_' == *routine_name.addr)
routine_name.addr[0] = '%';
- p = (char *)GTM_CTIME(&clock);
+ GTM_CTIME(p, &clock);
memcpy(rev_time_buf, p + 4, REV_TIME_BUFF_LEN);
io_curr_device = dev_in_use; /* set it back to make open_list_file save the device */
return TRUE;
diff --git a/sr_unix/ss_initiate.c b/sr_unix/ss_initiate.c
index 2fbbf3a..58bbedb 100644
--- a/sr_unix/ss_initiate.c
+++ b/sr_unix/ss_initiate.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2009, 2012 Fidelity Information Services, Inc *
+ * Copyright 2009, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -187,10 +187,7 @@ void ss_initiate_call_on_signal(void)
csa = &FILE_INFO(gv_cur_region)->s_addrs;
call_on_signal = NULL; /* Do not recurse via call_on_signal if there is an error */
- process_exiting = TRUE; /* Signal function "free" (in gtm_malloc_src.h) not to bother with frees as we are anyways exiting.
- * This avoids assert failures that would otherwise occur due to nested storage mgmt calls
- * just in case we came here because of an interrupt (e.g. SIGTERM) while a malloc was in progress.
- */
+ assert(process_exiting); /* Set by generic_signal_handler() */
assert(NULL != csa->ss_ctx);
ss_release(&csa->ss_ctx);
return;
@@ -387,7 +384,12 @@ boolean_t ss_initiate(gd_region *reg, /* Region in which snapshot has to be s
FSTAT_FILE(((unix_db_info *)(reg->dyn.addr->file_cntl->file_info))->fd, &stat_buf, fstat_res);
assert(-1 != fstat_res);
if (-1 != fstat_res)
- if (gtm_set_group_and_perm(&stat_buf, &group_id, &perm, PERM_FILE, &pdd) < 0)
+ {
+ /* Even though the temporary snapshot file is a physical file, we give it a relaxed IPC permissions to allow
+ * INTEG started by read-only processes to create snapshot files that are writable by processes having write
+ * permissions on the database file.
+ */
+ if (gtm_set_group_and_perm(&stat_buf, &group_id, &perm, PERM_IPC, &pdd) < 0)
{
send_msg(VARLSTCNT(6+PERMGENDIAG_ARG_COUNT)
ERR_PERMGENFAIL, 4, RTS_ERROR_STRING("snapshot file"),
@@ -400,7 +402,7 @@ boolean_t ss_initiate(gd_region *reg, /* Region in which snapshot has to be s
UNFREEZE_REGION_IF_NEEDED(csd, reg);
return FALSE;
}
-
+ }
if ((-1 == fstat_res) || (-1 == FCHMOD(shdw_fd, perm))
|| ((-1 != group_id) && (-1 == fchown(shdw_fd, -1, group_id))))
{
diff --git a/sr_unix/ss_write_block.c b/sr_unix/ss_write_block.c
index c765cf9..75860e8 100644
--- a/sr_unix/ss_write_block.c
+++ b/sr_unix/ss_write_block.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2009, 2010 Fidelity Information Services, Inc *
+ * Copyright 2009, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -39,6 +39,8 @@
GBLREF uint4 process_id;
+error_def(ERR_SSFILOPERR);
+
boolean_t ss_write_block(sgmnt_addrs *csa,
block_id blk,
cache_rec_ptr_t cr,
@@ -49,14 +51,14 @@ boolean_t ss_write_block(sgmnt_addrs *csa,
node_local_ptr_t cnl;
sm_uc_ptr_t blk_ptr;
shm_snapshot_ptr_t ss_shm_ptr;
- int blk_size, pwrite_res, status, size;
+ int save_errno;
+ uint4 size, blk_size;
off_t blk_offset;
boolean_t is_bg;
DEBUG_ONLY(
blk_hdr_ptr_t save_blk_ptr;
)
- error_def(ERR_SSFILOPERR);
assert(NULL != lcl_ss_ctx);
csd = csa->hdr;
cnl = csa->nl;
@@ -74,23 +76,14 @@ boolean_t ss_write_block(sgmnt_addrs *csa,
}
assert(cnl->ss_shmid == lcl_ss_ctx->attach_shmid);
assert(ss_shm_ptr->ss_info.ss_shmid == lcl_ss_ctx->attach_shmid);
- /* If this block falls outside the total number of blocks that were present during the time of snapshot initiation, then
- * we should not be writing the before image as the shadow bitmap might not have that much space. Hence do an early return
- * to let GT.M continue as if the block was already written to the shadow file.
- */
- if (blk >= lcl_ss_ctx->total_blks)
- return TRUE;
/* ss_release (function that invalidates a snapshot and announces GT.M not to write any more
* before images) waits for the active phase 2 commits to complete and hence the below
* assert is safe to be used.
*/
assert(ss_shm_ptr->in_use && SNAPSHOTS_IN_PROG(csa));
assert(!is_bg || ((NULL != cr) && cr->in_cw_set)); /* ensure the buffer has been pinned (from preemption in db_csh_getn) */
- blk_size = csd->blk_size;
- if (is_bg)
- blk_ptr = GDS_ANY_REL2ABS(csa, cr->buffaddr);
- else
- blk_ptr = mm_blk_ptr;
+ blk_size = (uint4)csd->blk_size;
+ blk_ptr = is_bg ? GDS_ANY_REL2ABS(csa, cr->buffaddr) : mm_blk_ptr;
# ifdef GTM_CRYPT
/* If the database is encrypted, the old_block will be in the encrypted twin buffer. Logic similar to the one
* done in backup_block.c
@@ -113,27 +106,27 @@ boolean_t ss_write_block(sgmnt_addrs *csa,
assert(NULL != blk_ptr);
size = ((blk_hdr_ptr_t)blk_ptr)->bsiz;
if (csa->do_fullblockwrites)
- size = (int)(ROUND_UP(size, csa->fullblockwrite_len));
+ size = ROUND_UP(size, csa->fullblockwrite_len);
/* If the block is FREE and block size is zero, we don't want to issue an empty write below. Instead write block of size
* equal to the database block size.
*/
- if (!size || (size > csd->blk_size))
- size = csd->blk_size;
+ if (!size || (size > blk_size))
+ size = blk_size;
assert(size <= ss_shm_ptr->ss_info.db_blk_size);
- assert(((blk_hdr_ptr_t)blk_ptr)->tn < ss_shm_ptr->ss_info.snapshot_tn);
blk_offset = ((off_t)(lcl_ss_ctx->shadow_vbn - 1) * DISK_BLOCK_SIZE + (off_t)blk * blk_size);
/* Note: If a FREE block is being written here, then we could avoid the write below: if the underlying file system
* is guaranteed to give us all zeros for a block and if the block header is empty
*/
assert(-1 != lcl_ss_ctx->shdw_fd);
- LSEEKWRITE(lcl_ss_ctx->shdw_fd, blk_offset, blk_ptr, size, pwrite_res);
- if ((0 != pwrite_res) && SNAPSHOTS_IN_PROG(cnl))
+ LSEEKWRITE(lcl_ss_ctx->shdw_fd, blk_offset, blk_ptr, size, save_errno);
+ if ((0 != save_errno) && SNAPSHOTS_IN_PROG(cnl))
{
- send_msg(VARLSTCNT(7) ERR_SSFILOPERR, 4, LEN_AND_LIT("write"),
+ assert(FALSE);
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(7) ERR_SSFILOPERR, 4, LEN_AND_LIT("write"),
LEN_AND_STR(lcl_ss_ctx->shadow_file),
- pwrite_res);
+ save_errno);
ss_shm_ptr->failed_pid = process_id;
- ss_shm_ptr->failure_errno = pwrite_res;
+ ss_shm_ptr->failure_errno = save_errno;
return FALSE;
}
/* Mark the block as before imaged in the bitmap */
diff --git a/sr_unix/timersp.h b/sr_unix/timersp.h
index 3ad01b8..d4d5124 100644
--- a/sr_unix/timersp.h
+++ b/sr_unix/timersp.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -16,15 +16,6 @@
/* These values are used during file creation but may be changed on the fly */
#define TIM_FLU_MOD_BG (1000 * TIMER_SCALE) /* 1 sec */
-
-#if defined(UNTARGETED_MSYNC)
-#define TIM_FLU_MOD_MM (30000 * TIMER_SCALE) /* 30 sec - longer since is a full sync */
-#elif defined(TARGETED_MSYNC)
-#define TIM_FLU_MOD_MM (10000 * TIMER_SCALE) /* 10 sec */
-#else
#define TIM_FLU_MOD_MM (1000 * TIMER_SCALE) /* 1 sec */
-#endif
-
-#define TIM_AST_WAIT (5 * TIMER_SCALE) /* 5 msec */
-#endif /*TIMERSP_included */
+#endif /* TIMERSP_included */
diff --git a/sr_unix/tp_grab_crit.c b/sr_unix/tp_grab_crit.c
deleted file mode 100644
index aa37f9c..0000000
--- a/sr_unix/tp_grab_crit.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/****************************************************************
- * *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
- * *
- * This source code contains the intellectual property *
- * of its copyright holder(s), and is made available *
- * under a license. If you do not know the terms of *
- * the license, please stop and do not read further. *
- * *
- ****************************************************************/
-
-#include "mdef.h"
-
-#include <signal.h> /* for VSIG_ATOMIC_T type */
-
-#include "gdsroot.h"
-#include "gtm_facility.h"
-#include "fileinfo.h"
-#include "gdsbt.h"
-#include "gdsfhead.h"
-#include "gdsbgtr.h"
-#include "filestruct.h"
-#include "send_msg.h"
-#include "mutex.h"
-#include "tp_grab_crit.h"
-#include "deferred_signal_handler.h"
-#include "wcs_recover.h"
-#include "caller_id.h"
-#include "is_proc_alive.h"
-#include "gtmimagename.h"
-#include "error.h"
-
-GBLREF short crash_count;
-GBLREF volatile int4 crit_count;
-GBLREF uint4 process_id;
-GBLREF node_local_ptr_t locknl;
-GBLREF boolean_t mupip_jnl_recover;
-
-error_def(ERR_CRITRESET);
-error_def(ERR_DBCCERR);
-error_def(ERR_DBFLCORRP);
-
-bool tp_grab_crit(gd_region *reg)
-{
- unix_db_info *udi;
- sgmnt_addrs *csa;
- sgmnt_data_ptr_t csd;
- node_local_ptr_t cnl;
- enum cdb_sc status;
- mutex_spin_parms_ptr_t mutex_spin_parms;
-
- udi = FILE_INFO(reg);
- csa = &udi->s_addrs;
- csd = csa->hdr;
- cnl = csa->nl;
- if (!csa->now_crit)
- {
- assert(0 == crit_count);
- crit_count++; /* prevent interrupts */
- DEBUG_ONLY(locknl = cnl;) /* for DEBUG_ONLY LOCK_HIST macro */
- mutex_spin_parms = (mutex_spin_parms_ptr_t)&csd->mutex_spin_parms;
- status = mutex_lockwim(reg, mutex_spin_parms, crash_count);
- DEBUG_ONLY(locknl = NULL;) /* restore "locknl" to default value */
- if (status != cdb_sc_normal)
- {
- crit_count = 0;
- switch (status)
- {
- case cdb_sc_nolock:
- return(FALSE);
- case cdb_sc_critreset:
- rts_error(VARLSTCNT(4) ERR_CRITRESET, 2, REG_LEN_STR(reg));
- case cdb_sc_dbccerr:
- rts_error(VARLSTCNT(4) ERR_DBCCERR, 2, REG_LEN_STR(reg));
- default:
- GTMASSERT;
- }
- return(FALSE);
- }
- /* There is only one case we know of when cnl->in_crit can be non-zero and that is when a process holding
- * crit gets kill -9ed and another process ends up invoking "secshr_db_clnup" which in turn clears the
- * crit semaphore (making it available for waiters) but does not also clear cnl->in_crit since it does not
- * hold crit at that point. But in that case, the pid reported in cnl->in_crit should be dead. Check that.
- */
- assert((0 == cnl->in_crit) || (FALSE == is_proc_alive(cnl->in_crit, 0)));
- cnl->in_crit = process_id;
- CRIT_TRACE(crit_ops_gw); /* see gdsbt.h for comment on placement */
- crit_count = 0;
- }
- if (csd->file_corrupt && !mupip_jnl_recover)
- {
- if (!IS_DSE_IMAGE)
- rts_error(VARLSTCNT(4) ERR_DBFLCORRP, 2, DB_LEN_STR(reg));
- else
- gtm_putmsg(VARLSTCNT(4) MAKE_MSG_WARNING(ERR_DBFLCORRP), 2, DB_LEN_STR(reg));
- }
- /* Ideally we do not want to do wcs_recover if we are in interrupt code (as opposed to mainline code).
- * This is easily accomplished in VMS with a library function lib$ast_in_prog but in Unix there is no way
- * to tell mainline code from interrupt code without the caller providing that information. Hence we
- * currently do the cache recovery even in case of interrupt code even though it is a heavyweight operation.
- * If it is found to cause issues, this logic has to be re-examined.
- */
- if (cnl->wc_blocked)
- wcs_recover(reg);
- return(TRUE);
-}
-
diff --git a/sr_unix/trigger_compare.c b/sr_unix/trigger_compare.c
index 3e9f1c6..c07e2b2 100644
--- a/sr_unix/trigger_compare.c
+++ b/sr_unix/trigger_compare.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2010, 2011 Fidelity Information Services, Inc *
+ * Copyright 2010, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -151,8 +151,8 @@ boolean_t search_trigger_hash(char *trigvn, int trigvn_len, stringkey *trigger_h
if (!gvcst_get(&key_val))
{ /* There has to be a #TRHASH entry */
assert(FALSE);
- rts_error(VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn, LEN_AND_LIT("\"#TRHASH\""),
- mv_hash.str.len, mv_hash.str.addr);
+ 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);
@@ -226,8 +226,8 @@ boolean_t search_triggers(char *trigvn, int trigvn_len, char **values, uint4 *va
if (!gvcst_get(&key_val))
{ /* There has to be a #TRHASH entry */
assert(FALSE);
- rts_error(VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn, LEN_AND_LIT("\"#TRHASH\""),
- mv_hash.str.len, mv_hash.str.addr);
+ 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);
diff --git a/sr_unix/trigger_delete.c b/sr_unix/trigger_delete.c
index 9ba8161..df0d02e 100644
--- a/sr_unix/trigger_delete.c
+++ b/sr_unix/trigger_delete.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2010, 2012 Fidelity Information Services, Inc *
+ * Copyright 2010, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -68,19 +68,20 @@ error_def(ERR_TRIGMODREGNOTRW);
#define MAX_CMD_LEN 20 /* Plenty of room for S,K,ZK,ZTK */
/* This error macro is used for all definition errors where the target is ^#t("TRHASH",<HASH>) */
-#define TRHASH_DEFINITION_RETRY_OR_ERROR(HASH) \
+#define TRHASH_DEFINITION_RETRY_OR_ERROR(HASH, CSA) \
{ \
if (CDB_STAGNATE > t_tries) \
t_retry(cdb_sc_triggermod); \
else \
{ \
assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number); \
- rts_error(VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn, \
- LEN_AND_LIT("\"#TRHASH\""),HASH->str.len, HASH->str.addr); \
+ 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) \
+#define SEARCH_AND_KILL_BY_HASH(TRIGVN, TRIGVN_LEN, HASH, TRIG_INDEX, CSA) \
{ \
mval mv_hash_indx; \
mval mv_hash_val; \
@@ -94,7 +95,7 @@ error_def(ERR_TRIGMODREGNOTRW);
gvcst_kill(FALSE); \
} else \
{ /* There has to be a #TRHASH entry */ \
- TRHASH_DEFINITION_RETRY_OR_ERROR(HASH); \
+ TRHASH_DEFINITION_RETRY_OR_ERROR(HASH, CSA); \
} \
}
@@ -116,14 +117,14 @@ STATICFNDEF void cleanup_trigger_hash(char *trigvn, int trigvn_len, char **value
SWITCH_TO_DEFAULT_REGION;
assert(0 != gv_target->root);
if (gv_cur_region->read_only)
- rts_error(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));
if (NULL != strchr(values[CMD_SUB], 'S'))
{
- SEARCH_AND_KILL_BY_HASH(trigvn, trigvn_len, set_hash, match_index)
+ 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);
+ SEARCH_AND_KILL_BY_HASH(trigvn, trigvn_len, kill_hash, match_index, csa);
}
RESTORE_TRIGGER_REGION_INFO;
}
@@ -165,7 +166,7 @@ STATICFNDEF void cleanup_trigger_name(char *trigvn, int trigvn_len, char *trigge
if (0 != gv_target->root)
{
if (gv_cur_region->read_only)
- rts_error(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));
if (is_auto_name)
{
/* $get(^#t("#TNAME",<trunc_name>,"#TNCOUNT")) */
@@ -226,7 +227,7 @@ STATICFNDEF int4 update_trigger_name_value(int trigvn_len, char *trig_name, int
SAVE_TRIGGER_REGION_INFO;
SWITCH_TO_DEFAULT_REGION;
if (gv_cur_region->read_only)
- rts_error(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(0 != gv_target->root);
/* $get(^#t("#TNAME",^#t(GVN,index,"#TRIGNAME")) */
BUILD_HASHT_SUB_SUB_CURRKEY(LITERAL_HASHTNAME, STRLEN(LITERAL_HASHTNAME), trig_name, trig_name_len - 1);
@@ -237,7 +238,8 @@ STATICFNDEF int4 update_trigger_name_value(int trigvn_len, char *trig_name, int
else
{
assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
- rts_error(VARLSTCNT(6) ERR_TRIGNAMBAD, 4, LEN_AND_LIT("\"#TNAME\""), trig_name_len - 1, trig_name);
+ 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;
@@ -278,20 +280,20 @@ STATICFNDEF int4 update_trigger_hash_value(char *trigvn, int trigvn_len, char **
SAVE_TRIGGER_REGION_INFO;
SWITCH_TO_DEFAULT_REGION;
if (gv_cur_region->read_only)
- rts_error(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(0 != gv_target->root);
if (NULL != strchr(values[CMD_SUB], 'S'))
{
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);
+ 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);
if (!gvcst_get(&key_val))
{ /* There has to be a #TRHASH entry */
- TRHASH_DEFINITION_RETRY_OR_ERROR(set_hash);
+ 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);
@@ -311,14 +313,14 @@ STATICFNDEF int4 update_trigger_hash_value(char *trigvn, int trigvn_len, char **
}
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);
+ 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);
if (!gvcst_get(&key_val))
{ /* There has to be a #TRHASH entry */
- TRHASH_DEFINITION_RETRY_OR_ERROR(kill_hash);
+ 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);
@@ -385,7 +387,7 @@ boolean_t trigger_delete_name(char *trigger_name, uint4 trigger_name_len, uint4
/* $data(^#t) */
SWITCH_TO_DEFAULT_REGION;
if (gv_cur_region->read_only)
- rts_error(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));
INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
if (0 == gv_target->root)
{
@@ -416,7 +418,7 @@ boolean_t trigger_delete_name(char *trigger_name, uint4 trigger_name_len, uint4
gbl_name.len = trigvn_len;
GV_BIND_NAME_ONLY(gd_header, &gbl_name);
if (gv_cur_region->read_only)
- rts_error(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));
csa = gv_target->gd_csa;
SETUP_TRIGGER_GLOBAL;
INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
@@ -638,8 +640,8 @@ int4 trigger_delete(char *trigvn, int trigvn_len, mval *trigger_count, int index
else
{
assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
- rts_error(VARLSTCNT(8) ERR_TRIGDEFBAD, 6,
- trigvn_len, trigvn, trigvn_len, trigvn,
+ 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]);
}
}
@@ -729,11 +731,11 @@ void trigger_delete_all(void)
for (gvt = gv_target_list; NULL != gvt; gvt = gvt->next_gvnh)
{
if (gvt->trig_local_tn == local_tn)
- rts_error(VARLSTCNT(1) ERR_TRIGMODINTP);
+ rts_error_csa(CSA_ARG(gvt->gd_csa) VARLSTCNT(1) ERR_TRIGMODINTP);
}
SWITCH_TO_DEFAULT_REGION;
if (gv_cur_region->read_only)
- rts_error(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));
INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
if (0 != gv_target->root)
{
@@ -759,7 +761,7 @@ void trigger_delete_all(void)
* of triggers.
*/
if (reg->read_only)
- rts_error(VARLSTCNT(4) ERR_TRIGMODREGNOTRW, REG_LEN_STR(reg));
+ 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
*/
@@ -788,7 +790,7 @@ void trigger_delete_all(void)
else
{
assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number);
- rts_error(VARLSTCNT(12) ERR_TRIGDEFBAD, 6,
+ 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\""),
diff --git a/sr_unix/trigger_gbl_fill_xecute_buffer.c b/sr_unix/trigger_gbl_fill_xecute_buffer.c
index 024903b..e24a335 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, 2011 Fidelity Information Services, Inc *
+ * Copyright 2010, 2013 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 "memcoherency.h"
#include "t_retry.h"
#include "gtmimagename.h"
+#include "filestruct.h" /* for FILE_INFO, needed by REG2CSA */
LITREF mval literal_ten;
@@ -135,7 +136,8 @@ char *trigger_gbl_fill_xecute_buffer(char *trigvn, int trigvn_len, mval *trig_in
assert(FALSE);
trgindx = mval2i(&index);
SET_PARAM_STRING(util_buff, util_len, trgindx, ",\"XECUTE\"");
- rts_error(VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn, trigvn_len, trigvn, util_len, util_buff);
+ rts_error_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn,
+ trigvn_len, trigvn, util_len, util_buff);
}
val_ptr = &key_val;
xecute_buff_len = mval2i(val_ptr);
@@ -154,8 +156,8 @@ char *trigger_gbl_fill_xecute_buffer(char *trigvn, int trigvn_len, mval *trig_in
free(xecute_buff);
assert(FALSE);
SET_PARAM_STRING(util_buff, util_len, num, ",\"XECUTE\"");
- rts_error(VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn, trigvn_len, trigvn, util_len,
- util_buff);
+ rts_error_csa(CSA_ARG(REG2CSA(gv_cur_region)) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn,
+ trigvn_len, trigvn, util_len, util_buff);
}
memcpy(xecute_buff_ptr, key_val.str.addr, key_val.str.len);
xecute_buff_ptr += key_val.str.len;
diff --git a/sr_unix/trigger_read_name_entry.c b/sr_unix/trigger_read_name_entry.c
index 23c88df..780a34a 100644
--- a/sr_unix/trigger_read_name_entry.c
+++ b/sr_unix/trigger_read_name_entry.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2010, 2011 Fidelity Information Services, Inc *
+ * Copyright 2010, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -58,7 +58,11 @@ boolean_t trigger_read_name_entry(mident *trig_name, mval *val)
SAVE_TRIGGER_REGION_INFO;
SWITCH_TO_DEFAULT_REGION;
INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
- assert(0 != gv_target->root);
+ if (0 == gv_target->root)
+ {
+ RESTORE_TRIGGER_REGION_INFO;
+ 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;
diff --git a/sr_unix/trigger_select.c b/sr_unix/trigger_select.c
index 42cde4e..b7cc1fa 100644
--- a/sr_unix/trigger_select.c
+++ b/sr_unix/trigger_select.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2010, 2012 Fidelity Information Services, Inc *
+ * Copyright 2010, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -231,8 +231,8 @@ STATICFNDEF void write_out_trigger(char *gbl_name, uint4 gbl_name_len, uint4 fil
else
{
assert(FALSE);
- rts_error(VARLSTCNT(8) ERR_TRIGDEFBAD, 6, gbl_name_len, gbl_name, gbl_name_len, gbl_name,
- LEN_AND_LIT("\"#LABEL\""));
+ 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;
@@ -253,8 +253,8 @@ STATICFNDEF void write_out_trigger(char *gbl_name, uint4 gbl_name_len, uint4 fil
else
{
assert(FALSE);
- rts_error(VARLSTCNT(8) ERR_TRIGDEFBAD, 6, gbl_name_len, gbl_name, gbl_name_len, gbl_name,
- LEN_AND_LIT("\"#CYCLE\""));
+ 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);
@@ -544,7 +544,7 @@ 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)
{
- char *sel_ptr, *prev_ptr, *ptr1, *ptr2;
+ char *sel_ptr, *strtok_ptr, *prev_ptr, *ptr1, *ptr2;
int gbl_len, prev_len;
mstr gbl_name;
sgmnt_addrs *csa;
@@ -642,7 +642,7 @@ boolean_t trigger_select(char *select_list, uint4 select_list_len, char *file_na
else
{
len = select_list_len;
- sel_ptr = strtok(save_select_list, ",");
+ sel_ptr = strtok_r(save_select_list, ",", &strtok_ptr);
do
{
trig_name = ('^' != *sel_ptr);
@@ -696,7 +696,7 @@ boolean_t trigger_select(char *select_list, uint4 select_list_len, char *file_na
if (0 != gv_target->root)
write_gbls_or_names(gbl_name.addr, gbl_name.len, file_name_len, &op_val, trig_name);
RESTORE_TRIGGER_REGION_INFO;
- } while (NULL != (sel_ptr = strtok(NULL, ","))); /* Embedded assignment is intended */
+ } while (NULL != (sel_ptr = strtok_r(NULL, ",", &strtok_ptr))); /* Embedded assignment is intended */
}
if (0 != file_name_len)
{
diff --git a/sr_unix/trigger_source_read_andor_verify.c b/sr_unix/trigger_source_read_andor_verify.c
index 6af0002..102532e 100644
--- a/sr_unix/trigger_source_read_andor_verify.c
+++ b/sr_unix/trigger_source_read_andor_verify.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2011, 2012 Fidelity Information Services, Inc *
+ * Copyright 2011, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -70,10 +70,12 @@ GBLREF boolean_t donot_INVOKE_MUMTSTART;
LITREF mval literal_batch;
LITREF mval literal_hasht;
+#define TRIG_FAILURE_RC -1
+
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 void trigger_source_raov_trigload(mstr *trigname, gv_trigger_t **ret_trigdsc);
+STATICFNDCL boolean_t trigger_source_raov_trigload(mstr *trigname, gv_trigger_t **ret_trigdsc);
error_def(ERR_DBROLLEDBACK);
error_def(ERR_TPRETRY);
@@ -185,7 +187,7 @@ int trigger_source_read_andor_verify(mstr *trigname, trigger_action trigger_op)
{ /* 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);
- if (0 == src_fetch_status)
+ if ((0 == src_fetch_status) || (TRIG_FAILURE_RC == src_fetch_status))
{
assert(0 == dollar_tlevel); /* op_tcommit should have made sure of this */
break;
@@ -213,9 +215,9 @@ 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);
- assert(0 == src_fetch_status);
+ assert((0 == src_fetch_status) || (TRIG_FAILURE_RC == src_fetch_status));
RESTORE_TRIGGER_REGION_INFO;
- return 0;
+ return src_fetch_status;
}
/* Now TP wrap and fetch the trigger source lines from the ^#t global */
@@ -228,7 +230,7 @@ STATICFNDEF int trigger_source_raov_tpwrap_helper(mstr *trigname, trigger_action
ESTABLISH_RET(trigger_source_raov_ch, SIGNAL);
assert(donot_INVOKE_MUMTSTART);
rc = trigger_source_raov(trigname, trigger_op);
- assert(0 == rc);
+ assert((0 == rc) || (TRIG_FAILURE_RC == rc));
/* Finish it now verifying it completed successfully */
GVTR_OP_TCOMMIT(cdb_status);
if (cdb_sc_normal != cdb_status)
@@ -237,7 +239,7 @@ STATICFNDEF int trigger_source_raov_tpwrap_helper(mstr *trigname, trigger_action
t_retry(cdb_status);
}
REVERT;
- return 0;
+ return rc;
}
/* Routine to do the dirty work of resolving a trigger name into a trigger and perform the missing parts of
@@ -263,7 +265,8 @@ STATICFNDEF int trigger_source_raov(mstr *trigname, trigger_action trigger_op)
/* 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 */
- trigger_source_raov_trigload(trigname, &trigdsc);
+ if(TRIG_FAILURE == trigger_source_raov_trigload(trigname, &trigdsc))
+ return TRIG_FAILURE_RC;
} 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
@@ -329,7 +332,8 @@ STATICFNDEF int trigger_source_raov(mstr *trigname, trigger_action trigger_op)
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));
- trigger_source_raov_trigload(trigname, &trigdsc);
+ if (TRIG_FAILURE == trigger_source_raov_trigload(trigname, &trigdsc))
+ return TRIG_FAILURE_RC;
triggers_reloaded = TRUE;
} else
DBGTRIGR((stderr, "trigger_source_raov: trigger validated\n"));
@@ -390,7 +394,7 @@ STATICFNDEF int trigger_source_raov(mstr *trigname, trigger_action trigger_op)
}
/* Routine called when need triggers loaded for a given global */
-STATICFNDEF void 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)
{
mname_entry gvent;
mval val;
@@ -405,12 +409,18 @@ STATICFNDEF void trigger_source_raov_trigload(mstr *trigname, gv_trigger_t **ret
mval trig_index;
gv_trigger_t *trigdsc;
uint4 cycle_start;
+ DCL_THREADGBL_ACCESS;
+ SETUP_THREADGBL_ACCESS;
/* Find region trigger name is in */
if (!trigger_read_name_entry(trigname, &val))
{ /* Trigger name not found - nothing we can do */
- CLEAR_IMPLICIT_TP_BEFORE_ERROR;
- rts_error(VARLSTCNT(4) ERR_TRIGNAMENF, 2, trigname->len, trigname->addr);
+ if (!TREF(in_op_fntext))
+ {
+ CLEAR_IMPLICIT_TP_BEFORE_ERROR;
+ rts_error(VARLSTCNT(4) ERR_TRIGNAMENF, 2, trigname->len, trigname->addr);
+ }
+ return TRIG_FAILURE;
}
/* Extract region name and trigger index number from result */
ptr = val.str.addr;
@@ -449,7 +459,7 @@ STATICFNDEF void trigger_source_raov_trigload(mstr *trigname, gv_trigger_t **ret
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;
*ret_trigdsc = trigdsc;
- return;
+ return TRIG_SUCCESS;
}
#endif /* GTM_TRIGGER */
diff --git a/sr_unix/trigger_update.c b/sr_unix/trigger_update.c
index b4a5677..3fe6b58 100644
--- a/sr_unix/trigger_update.c
+++ b/sr_unix/trigger_update.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2010, 2012 Fidelity Information Services, Inc *
+ * Copyright 2010, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -110,11 +110,11 @@ LITREF char *trigger_subs[];
#define BUILD_COMMAND_BITMAP(BITMAP, COMMANDS) \
{ \
char lcl_cmds[MAX_COMMANDS_LEN + 1]; \
- char *lcl_ptr; \
+ char *lcl_ptr, *strtok_ptr; \
\
memcpy(lcl_cmds, COMMANDS, STRLEN(COMMANDS) + 1); \
BITMAP = 0; \
- lcl_ptr = strtok(lcl_cmds, ","); \
+ lcl_ptr = strtok_r(lcl_cmds, ",", &strtok_ptr); \
do \
{ \
switch (*lcl_ptr) \
@@ -154,7 +154,7 @@ LITREF char *trigger_subs[];
GTMASSERT; /* Parsing should have found invalid command */ \
break; \
} \
- } while (lcl_ptr = strtok(NULL, ",")); \
+ } while (lcl_ptr = strtok_r(NULL, ",", &strtok_ptr)); \
}
#define COMMAND_BITMAP_TO_STR(COMMANDS, BITMAP, LEN) \
@@ -180,11 +180,11 @@ LITREF char *trigger_subs[];
#define BUILD_OPTION_BITMAP(BITMAP, OPTIONS) \
{ \
char lcl_options[MAX_OPTIONS_LEN + 1]; \
- char *lcl_ptr; \
+ char *lcl_ptr, *strtok_ptr; \
\
memcpy(lcl_options, OPTIONS, STRLEN(OPTIONS) + 1); \
BITMAP = 0; \
- lcl_ptr = strtok(lcl_options, ","); \
+ lcl_ptr = strtok_r(lcl_options, ",", &strtok_ptr); \
if (NULL != lcl_ptr) \
do \
{ \
@@ -215,7 +215,7 @@ LITREF char *trigger_subs[];
GTMASSERT; /* Parsing should have found invalid command */ \
break; \
} \
- } while (lcl_ptr = strtok(NULL, ",")); \
+ } while (lcl_ptr = strtok_r(NULL, ",", &strtok_ptr)); \
}
#define OPTION_BITMAP_TO_STR(OPTIONS, BITMAP, LEN) \
@@ -276,7 +276,7 @@ LITREF char *trigger_subs[];
}
/* 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) \
+#define HASHT_GVN_DEFINITION_RETRY_OR_ERROR(INDEX,SUBSCRIPT,CSA) \
{ \
if (CDB_STAGNATE > t_tries) \
t_retry(cdb_sc_triggermod); \
@@ -285,28 +285,28 @@ LITREF char *trigger_subs[];
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(VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn, \
+ rts_error_csa(CSA_ARG(CSA) VARLSTCNT(8) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn, \
trigvn_len, trigvn, util_len, util_buff); \
} \
}
/* This error macro is used for all definition errors where the target is ^#t(GVN,<#LABEL|#COUNT|#CYCLE>) */
-#define HASHT_DEFINITION_RETRY_OR_ERROR(SUBSCRIPT,MOREINFO) \
+#define HASHT_DEFINITION_RETRY_OR_ERROR(SUBSCRIPT,MOREINFO,CSA) \
{ \
if (CDB_STAGNATE > t_tries) \
t_retry(cdb_sc_triggermod); \
else \
{ \
- HASHT_DEFINITION_ERROR(SUBSCRIPT,MOREINFO); \
+ HASHT_DEFINITION_ERROR(SUBSCRIPT,MOREINFO,CSA); \
} \
}
-#define HASHT_DEFINITION_ERROR(SUBSCRIPT,MOREINFO) \
-{ \
- assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number); \
- rts_error(VARLSTCNT(12) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn, \
- trigvn_len, trigvn, LEN_AND_LIT(SUBSCRIPT), \
- ERR_TEXT, 2, RTS_ERROR_TEXT(MOREINFO)); \
+#define HASHT_DEFINITION_ERROR(SUBSCRIPT,MOREINFO,CSA) \
+{ \
+ assert(WBTEST_HELPOUT_TRIGDEFBAD == gtm_white_box_test_case_number); \
+ rts_error_csa(CSA_ARG(CSA) VARLSTCNT(12) ERR_TRIGDEFBAD, 6, trigvn_len, trigvn, \
+ trigvn_len, trigvn, LEN_AND_LIT(SUBSCRIPT), \
+ ERR_TEXT, 2, RTS_ERROR_TEXT(MOREINFO)); \
}
STATICFNDEF boolean_t validate_label(char *trigvn, int trigvn_len)
@@ -317,7 +317,7 @@ STATICFNDEF boolean_t validate_label(char *trigvn, int trigvn_len)
SETUP_THREADGBL_ACCESS;
BUILD_HASHT_SUB_SUB_CURRKEY(trigvn, trigvn_len, LITERAL_HASHLABEL, STRLEN(LITERAL_HASHLABEL));
if (!gvcst_get(&trigger_label)) /* There has to be a #LABEL */
- HASHT_DEFINITION_RETRY_OR_ERROR("\"#LABEL\"","#LABEL was not found")
+ HASHT_DEFINITION_RETRY_OR_ERROR("\"#LABEL\"","#LABEL was not found", REG2CSA(gv_cur_region))
return ((trigger_label.str.len == STRLEN(HASHT_GBL_CURLABEL))
&& (0 == memcmp(trigger_label.str.addr, HASHT_GBL_CURLABEL, trigger_label.str.len)));
}
@@ -455,7 +455,7 @@ STATICFNDEF int4 add_trigger_hash_entry(char *trigvn, int trigvn_len, char *cmd_
SAVE_TRIGGER_REGION_INFO;
SWITCH_TO_DEFAULT_REGION;
if (gv_cur_region->read_only)
- rts_error(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));
INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
set_cmp = (NULL != strchr(cmd_value, 'S'));
mv_indx_ptr = &mv_indx;
@@ -556,7 +556,7 @@ STATICFNDEF boolean_t trigger_already_exists(char *trigvn, int trigvn_len, char
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\"");
+ 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])));
}
@@ -573,7 +573,7 @@ STATICFNDEF boolean_t trigger_already_exists(char *trigvn, int trigvn_len, char
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\"");
+ 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)));
@@ -590,7 +590,7 @@ STATICFNDEF boolean_t trigger_already_exists(char *trigvn, int trigvn_len, char
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\"");
+ 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])));
}
@@ -855,7 +855,7 @@ STATICFNDEF int4 modify_record(char *trigvn, int trigvn_len, char add_delete, in
i2mval(&trigindx, trigger_index);
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\"");
+ 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';
/* get(^#t(GVN,trigindx,"OPTIONS") */
@@ -985,7 +985,7 @@ STATICFNDEF int4 gen_trigname_sequence(char *trigvn, int trigvn_len, mval *trigg
SAVE_TRIGGER_REGION_INFO;
SWITCH_TO_DEFAULT_REGION;
if (gv_cur_region->read_only)
- rts_error(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));
INITIAL_HASHT_ROOT_SEARCH_IF_NEEDED;
if (0 == user_trigname_len)
{ /* autogenerated name */
@@ -1219,14 +1219,14 @@ boolean_t trigger_update_rec(char *trigger_rec, uint4 len, boolean_t noprompt, u
gbl_name.len = trigvn_len;
GV_BIND_NAME_ONLY(gd_header, &gbl_name);
if (gv_cur_region->read_only)
- rts_error(VARLSTCNT(4) ERR_TRIGMODREGNOTRW, 2, REG_LEN_STR(gv_cur_region));
+ rts_error_csa(CSA_ARG(gv_target->gd_csa) VARLSTCNT(4) ERR_TRIGMODREGNOTRW, 2, REG_LEN_STR(gv_cur_region));
csa = gv_target->gd_csa;
/* 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(VARLSTCNT(1) ERR_TRIGMODINTP);
+ 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
@@ -1649,7 +1649,7 @@ boolean_t trigger_update(char *trigger_rec, uint4 len)
|| !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(VARLSTCNT(1) ERR_DBROLLEDBACK);
+ rts_error_csa(CSA_ARG(gv_target->gd_csa) 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
diff --git a/sr_unix/ttt.txt b/sr_unix/ttt.txt
index e717c28..41ec42a 100644
--- a/sr_unix/ttt.txt
+++ b/sr_unix/ttt.txt
@@ -1,6 +1,6 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ;
-; Copyright 2001, 2012 Fidelity Information Services, Inc ;
+; Copyright 2001, 2013 Fidelity Information Services, Inc ;
; ;
; This source code contains the intellectual property ;
; of its copyright holder(s), and is made available ;
@@ -1019,3 +1019,15 @@ OC_INDGET2: pushab val.1
calls #2,xfer.xf_indget2
OC_INDMERGE2: pushab val.1
calls #1,xfer.xf_indmerge2
+OC_LITC: pushab val.1 ; opcode not in sr_unix_nsb/ttt or sr_vvms/ttt
+ pushab val.0
+ calls #2,xfer.xf_litc
+OC_STOLITC: movc3 #16,val.2,val.1 ; opcode not in sr_unix_nsb/ttt or sr_vvms/ttt
+ pushab val.1
+ calls #1,xfer.xf_stolitc
+OC_FNZPEEK: pushab val.0
+ pushab val.4
+ pushl val.3
+ pushl val.2
+ pushab val.1
+ calls #5,xfer.xf_fnzpeek
diff --git a/sr_unix/util_help.c b/sr_unix/util_help.c
new file mode 100644
index 0000000..6a7cf15
--- /dev/null
+++ b/sr_unix/util_help.c
@@ -0,0 +1,63 @@
+/****************************************************************
+ * *
+ * Copyright 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "util_help.h"
+#include "gtm_stdio.h" /* for snprintf() */
+#include "gtm_string.h" /* for strlen() */
+#include "gtm_stdlib.h" /* for SYSTEM() */
+#include "gtmimagename.h" /* for struct gtmImageName */
+
+
+error_def(ERR_TEXT);
+
+#define HELP_CMD_STRING_SIZE 512
+#define EXEC_GTMHELP "$gtm_dist/mumps -run %%XCMD 'do ^GTMHELP(\"%s\",\"$gtm_dist/%shelp.gld\")'",
+
+#define UTIL_HELP_IMAGES 5
+/* We need the first two entries for compatibility */
+char *utilImageGLDs[UTIL_HELP_IMAGES] =
+{
+#define IMAGE_TABLE_ENTRY(A,B) B,
+IMAGE_TABLE_ENTRY (INVALID_IMAGE, "")
+IMAGE_TABLE_ENTRY (GTM_IMAGE, "gtm")
+IMAGE_TABLE_ENTRY (MUPIP_IMAGE, "mupip")
+IMAGE_TABLE_ENTRY (DSE_IMAGE, "dse")
+IMAGE_TABLE_ENTRY (LKE_IMAGE, "lke")
+#undef IMAGE_TABLE_ENTRY
+};
+
+void util_help(void)
+{
+ int rc;
+ char *help_option;
+ char help_cmd_string[HELP_CMD_STRING_SIZE];
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ assert(1 >= TREF(parms_cnt));
+ assert(GTM_IMAGE < image_type && UTIL_HELP_IMAGES > image_type);
+ if (0 == TREF(parms_cnt))
+ help_option = utilImageGLDs[INVALID_IMAGE];
+ else
+ {
+ assert(TAREF1(parm_ary, TREF(parms_cnt) - 1));
+ assert((char *)-1L != (TAREF1(parm_ary, TREF(parms_cnt) - 1)));
+ help_option = (TAREF1(parm_ary, TREF(parms_cnt) - 1));
+ }
+ SNPRINTF(help_cmd_string, SIZEOF(help_cmd_string),
+ "$gtm_dist/mumps -run %%XCMD 'do ^GTMHELP(\"%s\",\"$gtm_dist/%shelp.gld\")'",
+ help_option, utilImageGLDs[image_type]);
+ rc = SYSTEM(help_cmd_string);
+ if (0 != rc)
+ rts_error_csa(NULL, VARLSTCNT(5) ERR_TEXT, 2, RTS_ERROR_TEXT("HELP command error"), rc);
+}
+
diff --git a/sr_unix/util_help.h b/sr_unix/util_help.h
new file mode 100644
index 0000000..ebc004c
--- /dev/null
+++ b/sr_unix/util_help.h
@@ -0,0 +1,16 @@
+/****************************************************************
+ * *
+ * Copyright 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef UTIL_HELP_INCLUDED
+#define UTIL_HELP_INCLUDED
+
+void util_help(void);
+#endif
diff --git a/sr_unix/util_output.c b/sr_unix/util_output.c
index 9d0f6a9..c44d38d 100644
--- a/sr_unix/util_output.c
+++ b/sr_unix/util_output.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -42,6 +42,7 @@
#include "trans_log_name.h"
#include "gtmio.h"
#include "gtm_logicals.h"
+#include "have_crit.h"
#ifdef UNICODE_SUPPORTED
#include "gtm_icu_api.h"
@@ -708,24 +709,20 @@ void util_out_send_oper(char *addr, unsigned int len)
}
}
}
+ DEFER_INTERRUPTS(INTRPT_IN_LOG_FUNCTION);
(void)OPENLOG(facility, LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_USER);
+ ENABLE_INTERRUPTS(INTRPT_IN_LOG_FUNCTION);
}
/*
* When syslog is processing and a signal occurs, the signal processing might eventually lead to another syslog
* call. But in libc the first syslog has grabbed a lock (syslog_lock), and now the other syslog call will
* block waiting for that lock which can't be released since the first syslog was interrupted by the signal.
- * A work around is to temporarily block signals (SIGINT, SIGQUIT, SIGTERM, SIGTSTP, SIGCONT, SIGALRM) and then
- * restore them after the syslog call returns.
- *
- * It is possible for early process startup code to invoke this function so blocksig_initialized might not yet be set.
- * An example C-stack is main/get_page_size/system-function interrupted by MUPIP STOP/generic_signal_handler/send_msg.
- * Therefore this does not have an assert(blocksig_initialized) that similar code in other places (e.g. dollarh.c) has.
+ * We address this issue by deferring signals for the duration of the call; generic_signal_handler.c will also
+ * skip send_msg invocations if the interrupt comes while INTRPT_IN_LOG_FUNCTION is set.
*/
- if (blocksig_initialized) /* In pro, dont take chances and handle case where it is not initialized */
- sigprocmask(SIG_BLOCK, &block_sigsent, &savemask);
+ DEFER_INTERRUPTS(INTRPT_IN_LOG_FUNCTION);
SYSLOG(LOG_USER | LOG_INFO, "%s", addr);
- if (blocksig_initialized)
- sigprocmask(SIG_SETMASK, &savemask, NULL);
+ ENABLE_INTERRUPTS(INTRPT_IN_LOG_FUNCTION);
}
void util_out_print_vaparm(caddr_t message, int flush, va_list var, int faocnt)
@@ -776,7 +773,8 @@ void util_out_print_vaparm(caddr_t message, int flush, va_list var, int faocnt)
{
if (fmtc >= fmt_top2) /* Check if there is room for 2 bytes. If not stop copying */
break;
- *fmtc++ = '%'; /* escape for '%' */
+ if (flush == SPRINT)
+ *fmtc++ = '%'; /* give buffered users what they expect %% */
*fmtc++ = '%';
(TREF(util_outptr))++;
} else if ('\n' == *(TREF(util_outptr)) && (OPER == flush || SPRINT == flush))
@@ -794,7 +792,7 @@ void util_out_print_vaparm(caddr_t message, int flush, va_list var, int faocnt)
switch (flush)
{
case FLUSH:
- FPRINTF(stderr, fmt_buff);
+ FPRINTF(stderr, "%s", fmt_buff);
break;
case OPER:
util_out_send_oper(fmt_buff, UINTCAST(fmtc - fmt_buff));
diff --git a/sr_unix/util_spawn.c b/sr_unix/util_spawn.c
index 0235664..a9f2b08 100644
--- a/sr_unix/util_spawn.c
+++ b/sr_unix/util_spawn.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -17,6 +17,7 @@
void util_spawn(void)
{
char *cmd;
+ int rc;
DCL_THREADGBL_ACCESS;
SETUP_THREADGBL_ACCESS;
@@ -26,13 +27,15 @@ void util_spawn(void)
cmd = GETENV("SHELL");
if (!cmd)
cmd = "/bin/sh";
- if (-1 == SYSTEM(cmd))
+ rc = SYSTEM(cmd);
+ if (-1 == rc)
PERROR("system : ");
} else
{
assert(TAREF1(parm_ary, TREF(parms_cnt) - 1));
assert((char *)-1L != (TAREF1(parm_ary, TREF(parms_cnt) - 1)));
- if (-1 == SYSTEM(TAREF1(parm_ary, TREF(parms_cnt) - 1)))
+ rc = SYSTEM((TAREF1(parm_ary, TREF(parms_cnt) - 1)));
+ if (-1 == rc)
PERROR("system : ");
}
}
diff --git a/sr_unix/versions.csh b/sr_unix/versions.csh
index 111125f..6f53ac2 100644
--- a/sr_unix/versions.csh
+++ b/sr_unix/versions.csh
@@ -1,6 +1,6 @@
#################################################################
# #
-# Copyright 2001, 2012 Fidelity Information Services, Inc #
+# Copyright 2001, 2013 Fidelity Information Services, Inc #
# #
# This source code contains the intellectual property #
# of its copyright holder(s), and is made available #
@@ -20,7 +20,7 @@
# gtm_curpro is the current production version
if (`uname -s` != "OS/390") then
- setenv gtm_curpro "V60000"
+ setenv gtm_curpro "V60001"
else
setenv gtm_curpro "V53004A" # until newer version built on z/OS
endif
diff --git a/sr_unix/wait_for_disk_space.c b/sr_unix/wait_for_disk_space.c
index b3763b7..5a3b5de 100644
--- a/sr_unix/wait_for_disk_space.c
+++ b/sr_unix/wait_for_disk_space.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2012 Fidelity Information Services, Inc *
+ * Copyright 2012, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -16,7 +16,6 @@
#include "anticipatory_freeze.h"
#include "wait_for_disk_space.h"
#include "gtmio.h"
-#include "tp_grab_crit.h"
#include "have_crit.h"
#include "filestruct.h"
#include "jnl.h"
@@ -48,6 +47,7 @@ void wait_for_disk_space(sgmnt_addrs *csa, char *fn, int fd, off_t offset, char
int fn_len, tmp_errno;
boolean_t freeze_cleared;
char wait_comment[MAX_FREEZE_COMMENT_LEN];
+ sgmnt_addrs *repl_csa;
# ifdef DEBUG
uint4 lcl_lseekwrite_target;
# endif
@@ -62,38 +62,33 @@ void wait_for_disk_space(sgmnt_addrs *csa, char *fn, int fd, off_t offset, char
* or DSKNOSPCAVAIL is not configured as a custom error, return right away.
*/
if (!ANTICIPATORY_FREEZE_ENABLED(csa) || (NULL == is_anticipatory_freeze_needed_fnptr)
- || !(*is_anticipatory_freeze_needed_fnptr)(ERR_DSKNOSPCAVAIL))
+ || !(*is_anticipatory_freeze_needed_fnptr)(csa, ERR_DSKNOSPCAVAIL))
return;
fn_len = STRLEN(fn);
- was_crit = csa->now_crit;
+ repl_csa = &FILE_INFO(jnlpool.jnlpool_dummy_reg)->s_addrs;
+ was_crit = repl_csa->now_crit;
reg = csa->region;
- /* Let us take the case this process has opened the database but does not hold crit on it. If we come in to this
- * function while trying to flush either to the db or jnl, setting the instance freeze would require a "grab_lock"
- * which could hang due to another process holding that and in turn waiting for the exact same db or jnl write
- * to succeed. This has the potential of creating a deadlock so we avoid that by returning right away. Since we
- * dont hold crit, this call to do the jnl or db write is not critical in the sense no process will be affected
- * because this write did not happen. Therefore it is okay to return right away. On the other hand if this
- * process holds crit, then it is not possible that the other process holds the jnlpool lock
- * and is waiting for the db or jnl qio (since that flow usually happens in t_end and tp_tend
- * where db crit is first obtained before jnlpool lock is). Therefore it is safe to do a grab_lock
- * in that case without worrying about potential deadlocks.
- * Update *save_errno to indicate this is not a ENOSPC condition (since we have chosen to defer
- * the ENOSPC condition to some other process that encounters it while holding crit).
- *
- * There is a possibility that if the caller is jnl_wait we will retry this logic indefinitely without ever
- * setting instance freeze because we dont hold crit. To avoid that, do tp_grab_crit to see if it is available.
- * If so, go ahead with freezing the instance. If not issue QIODEFER message and return. It is still possible
- * the same process issues multiple QIODEFER messages before the instance gets frozen. But it should be rare.
- */
if (!was_crit)
- tp_grab_crit(reg);
- if (!csa->now_crit)
- {
- send_msg(VARLSTCNT(4) ERR_ENOSPCQIODEFER, 2, fn_len, fn);
- *save_errno = ERR_ENOSPCQIODEFER;
- return;
+ { /* Setting the instance freeze requires the journal pool lock (grab_lock). However, we need to be careful
+ * to avoid a deadlock. A deadlock is possible if we hold the io_in_prog_latch, and meanwhile another
+ * process has grabbed crit in t_end/tp_tend, grabbed the journal pool lock, and is now waiting on the
+ * io_in_prog_latch (e.g., via jnl_write). By doing a blocking wait in grab_lock here, we would
+ * deadlock. Therefore, we must pass is_blocking_wait = FALSE to grab_lock. If grab_lock does not succeed,
+ * we return right away and do not complete the jnl or db write operation for which we are waiting for disk
+ * space. Since we do not hold crit, we can safely proceed without its completion.
+ * On the other hand, this scenario is not possible if we hold crit on the region of interest. In this
+ * case, a normal grab_lock is fine (is_blocking_wait = TRUE).
+ */
+ if (csa->now_crit)
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, GRAB_LOCK_ONLY);
+ else if (FALSE == grab_lock(jnlpool.jnlpool_dummy_reg, FALSE, GRAB_LOCK_ONLY))
+ {
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_ENOSPCQIODEFER, 2, fn_len, fn);
+ *save_errno = ERR_ENOSPCQIODEFER;
+ return;
+ }
}
- /* We either came into this function holding crit or "tp_grab_crit" succeeded */
+ /* We either came into this function holding journal pool lock or grab_lock() succeeded */
assert(NULL != jnlpool.jnlpool_ctl);
assert(NULL != fn); /* if "csa" is non-NULL, fn better be non-NULL as well */
/* The "send_msg" of DSKNOSPCAVAIL done below will set instance freeze (the configuration file includes it). After that, we
@@ -104,7 +99,7 @@ void wait_for_disk_space(sgmnt_addrs *csa, char *fn, int fd, off_t offset, char
* case. Hence the reason not to allow interrupts.
*/
DEFER_INTERRUPTS(INTRPT_IN_WAIT_FOR_DISK_SPACE);
- send_msg(VARLSTCNT(4) ERR_DSKNOSPCAVAIL, 2, fn_len, fn); /* this should set the instance freeze */
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_DSKNOSPCAVAIL, 2, fn_len, fn); /* this should set the instance freeze */
/* Make a copy of the freeze comment which would be set by the previous message. */
GENERATE_INST_FROZEN_COMMENT(wait_comment, MAX_FREEZE_COMMENT_LEN, ERR_DSKNOSPCAVAIL);
tmp_errno = *save_errno;
@@ -116,23 +111,24 @@ void wait_for_disk_space(sgmnt_addrs *csa, char *fn, int fd, off_t offset, char
{ /* Some other process cleared the instance freeze. But we still dont have our disk
* space issue resolved so set the freeze flag again until space is available for us.
*/
- send_msg(VARLSTCNT(4) ERR_DSKNOSPCAVAIL, 2, fn_len, fn);
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_DSKNOSPCAVAIL, 2, fn_len, fn);
} else if (exit_state != 0)
{
- send_msg(VARLSTCNT(1) forced_exit_err);
- gtm_putmsg(VARLSTCNT(1) forced_exit_err);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(1) forced_exit_err);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) forced_exit_err);
exit(-exi_condition);
}
/* Sleep for a while before retrying the write. Do not use "hiber_start" as that
* uses timers and if we are already in a timer handler now, nested timers wont work.
*/
SHORT_SLEEP(SLEEP_IORETRYWAIT);
+ DEBUG_ONLY(CLEAR_FAKE_ENOSPC_IF_MASTER_DEAD);
/* If some other process froze the instance and changed the comment, a retry of the
* LSEEKWRITE may not be appropriate, so just loop waiting for the freeze to be lifted.
*/
if (IS_REPL_INST_FROZEN && (STRCMP(wait_comment, jnlpool.jnlpool_ctl->freeze_comment) != 0))
{
- send_msg(VARLSTCNT(4) ERR_DSKNOSPCBLOCKED, 2, fn_len, fn);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_DSKNOSPCBLOCKED, 2, fn_len, fn);
WAIT_FOR_REPL_INST_UNFREEZE(csa)
}
LSEEKWRITE(fd, offset, buf, count, tmp_errno);
@@ -144,7 +140,7 @@ void wait_for_disk_space(sgmnt_addrs *csa, char *fn, int fd, off_t offset, char
# endif
}
/* Report that we were able to continue whether we are still frozen or not. */
- send_msg(VARLSTCNT(4) ERR_DSKSPCAVAILABLE, 2, fn_len, fn);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_DSKSPCAVAILABLE, 2, fn_len, fn);
/* Only report if we were the process to set the current freeze comment; otherwise someone else reported it. */
if (STRCMP(wait_comment, jnlpool.jnlpool_ctl->freeze_comment) == 0)
{
@@ -154,6 +150,6 @@ void wait_for_disk_space(sgmnt_addrs *csa, char *fn, int fd, off_t offset, char
*save_errno = tmp_errno;
ENABLE_INTERRUPTS(INTRPT_IN_WAIT_FOR_DISK_SPACE);
if (!was_crit)
- rel_crit(reg);
+ rel_lock(jnlpool.jnlpool_dummy_reg);
return;
}
diff --git a/sr_unix/wcs_clean_dbsync.c b/sr_unix/wcs_clean_dbsync.c
index 8460ee3..0dba4ca 100644
--- a/sr_unix/wcs_clean_dbsync.c
+++ b/sr_unix/wcs_clean_dbsync.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -32,7 +32,6 @@
#include "gdsbgtr.h" /* for the BG_TRACE_PRO macros */
#include "gtmio.h" /* for the GET_LSEEK_FLAG macro */
#include "wcs_clean_dbsync.h"
-#include "tp_grab_crit.h"
#include "wcs_flu.h"
#include "lockconst.h"
@@ -135,17 +134,16 @@ void wcs_clean_dbsync(TID tid, int4 hd_len, sgmnt_addrs **csaptr)
dbsync_defer_timer = TRUE;
GET_LSEEK_FLAG(FILE_INFO(reg)->fd, lseekIoInProgress_flag);
DEBUG_ONLY(
- /* We invoke tp_grab_crit below which can potentially do cache-recoveries if cnl->wc_blocked is set.
+ /* We invoke grab_crit_immediate below which can potentially do cache-recoveries if cnl->wc_blocked is set.
* But wcs_recover has an assert that we never invoke it in the final retry. This is to avoid
- * restarts in the final retry. But wcs_clean_dbsync invokes tp_grab_crit only if we dont already
+ * restarts in the final retry. But wcs_clean_dbsync invokes grab_crit_immediate only if we dont already
* hold crit and that means we have already finished commit on this particular region (e.g. if
* commit is complete on all regions and crit is released on all of them but before we reset t_tries
* to 0 in t_end/tp_tend) so it is okay to invoke wcs_recover in that case. Signal that to wcs_recover
* by setting ok_to_call_wcs_recover to TRUE. Need to save and restore the global as it could be
* TRUE or FALSE depending on where wcs_clean_dbsync interrupted mainline code.
*/
- assert(CDB_STAGNATE >= t_tries ||
- gtm_white_box_test_case_enabled && (WBTEST_ANTIFREEZE_GVDATAFAIL == gtm_white_box_test_case_number));
+ assert(CDB_STAGNATE >= t_tries || WBTEST_ENABLED(WBTEST_ANTIFREEZE_GVDATAFAIL));
if (CDB_STAGNATE <= t_tries)
{
save_ok_to_call_wcs_recover = TREF(ok_to_call_wcs_recover);
@@ -160,12 +158,12 @@ void wcs_clean_dbsync(TID tid, int4 hd_len, sgmnt_addrs **csaptr)
&& (!jpc || !jpc->jnl_buff || (LOCK_AVAILABLE == jpc->jnl_buff->fsync_in_prog_latch.u.parts.latch_pid))
&& ((NULL == check_csaddrs) || !T_IN_CRIT_OR_COMMIT_OR_WRITE(check_csaddrs))
&& !T_IN_CRIT_OR_COMMIT_OR_WRITE(csa)
- && (FALSE != tp_grab_crit(reg)))
- { /* Note that tp_grab_crit invokes wcs_recover in case cnl->wc_blocked is non-zero.
- * This means we could be doing cache recovery even though we are in interrupt code.
- * If this is found undesirable, the logic in tp_grab_crit that invokes wcs_recover has to be re-examined.
+ && (FALSE != grab_crit_immediate(reg)))
+ { /* Note that grab_crit_immediate invokes wcs_recover in case cnl->wc_blocked is non-zero. This means we
+ * could be doing cache recovery even though we are in interrupt code. If this is found undesirable, the
+ * logic in grab_crit_immediate that invokes wcs_recover has to be re-examined.
*/
- /* Note that if we are here, we have obtained crit using tp_grab_crit. */
+ /* Note that if we are here, we have obtained crit using grab_crit_immediate. */
assert(csa->ti->early_tn == csa->ti->curr_tn);
/* Do not invoke wcs_flu if the database has a newer journal file than what this process had open
* when the dbsync timer was started in wcs_wtstart. This is because mainline (non-interrupt) code
@@ -184,9 +182,7 @@ void wcs_clean_dbsync(TID tid, int4 hd_len, sgmnt_addrs **csaptr)
* This way wcs_flu is not redundantly invoked and it ensures that the least number of epochs
* (only the necessary ones) are written OR the least number of db file header flushes are done.
*
- * If MM and not writing EPOCHs, we dont need to even flush the file header since MM by default
- * does NO msyncs of the database file during normal operation but instead only at database rundown.
- * So no need to do wcs_flu in this case.
+ * If MM and not writing EPOCHs, we need to flush the fileheader out as that is not mmap'ed.
*/
/* Write idle/free epoch only if db curr_tn did not change since when the last dirty cache record was
* written in wcs_wtstart to when the dbsync timer (5 seconds) popped. If the curr_tn changed it means
@@ -210,9 +206,10 @@ void wcs_clean_dbsync(TID tid, int4 hd_len, sgmnt_addrs **csaptr)
if ((NULL != jpc) && JNL_HAS_EPOCH(jpc->jnl_buff)
? (((NOJNL == jpc->channel) || !JNL_FILE_SWITCHED(jpc))
&& (jpc->jnl_buff->epoch_tn < csa->ti->curr_tn))
- : !is_mm && (cnl->last_wcsflu_tn < csa->ti->curr_tn))
+ : (cnl->last_wcsflu_tn < csa->ti->curr_tn))
{
- wcs_flu(WCSFLU_FLUSH_HDR | WCSFLU_WRITE_EPOCH | WCSFLU_SYNC_EPOCH | WCSFLU_CLEAN_DBSYNC);
+ wcs_flu(WCSFLU_FLUSH_HDR | WCSFLU_WRITE_EPOCH | WCSFLU_SYNC_EPOCH | WCSFLU_CLEAN_DBSYNC
+ | WCSFLU_SPEEDUP_NOBEFORE);
BG_TRACE_PRO_ANY(csa, n_dbsync_writes);
/* If MM, file could have been remapped by wcs_flu above.
* If so, cs_data needs to be reset.
diff --git a/sr_unix/wcs_flu.c b/sr_unix/wcs_flu.c
index 73e59d3..c106053 100644
--- a/sr_unix/wcs_flu.c
+++ b/sr_unix/wcs_flu.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -121,7 +121,8 @@ error_def(ERR_WRITERSTUCK);
and at that time we do not want the WBTEST_BUFOWNERSTUCK_STACK white box \
mechanism to kick in.*/ \
GTM_WHITE_BOX_TEST(WBTEST_BUFOWNERSTUCK_STACK, gtm_white_box_test_case_enabled, FALSE); \
- send_msg(VARLSTCNT(5) ERR_WRITERSTUCK, 3, cnl->in_wtstart, DB_LEN_STR(gv_cur_region)); \
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_WRITERSTUCK, 3, cnl->in_wtstart, \
+ DB_LEN_STR(gv_cur_region)); \
return FALSE; \
} \
if (-1 == shmctl(udi->shmid, IPC_STAT, &shm_buf)) \
@@ -129,9 +130,10 @@ error_def(ERR_WRITERSTUCK);
save_errno = errno; \
if (1 == lcnt) \
{ \
- send_msg(VARLSTCNT(4) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region)); \
- send_msg(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("shmctl()"), \
- CALLFROM, save_errno); \
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_DBFILERR, 2, \
+ DB_LEN_STR(gv_cur_region)); \
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_SYSCALL, 5, \
+ RTS_ERROR_LITERAL("shmctl()"), CALLFROM, save_errno); \
} \
} else if (1 == shm_buf.shm_nattch) \
{ \
@@ -146,11 +148,18 @@ error_def(ERR_WRITERSTUCK);
} \
}
+#define REL_CRIT_BEFORE_RETURN \
+{ \
+ cnl->wcsflu_pid = 0; \
+ if (!was_crit) \
+ rel_crit(gv_cur_region); \
+}
+
boolean_t wcs_flu(uint4 options)
{
bool success, was_crit;
boolean_t fix_in_wtstart, flush_hdr, jnl_enabled, sync_epoch, write_epoch, need_db_fsync, in_commit;
- boolean_t flush_msync, speedup_nobefore, clean_dbsync;
+ boolean_t flush_msync, speedup_nobefore, clean_dbsync, return_early;
unsigned int lcnt, pass;
int save_errno, wtstart_errno;
jnl_buffer_ptr_t jb;
@@ -215,99 +224,48 @@ boolean_t wcs_flu(uint4 options)
ADJUST_GBL_JREC_TIME(jgbl, jb);
assert(csa == cs_addrs); /* for jnl_ensure_open */
jnl_status = jnl_ensure_open();
+ WBTEST_ASSIGN_ONLY(WBTEST_WCS_FLU_FAIL, jnl_status, ERR_JNLFILOPN);
if (SS_NORMAL != jnl_status)
{
assert(ERR_JNLFILOPN == jnl_status);
- send_msg(VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(gv_cur_region));
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(gv_cur_region));
if (JNL_ENABLED(csd))
{ /* If journaling is still enabled, but we failed to open the journal file,
* we don't want to continue processing.
*/
- if (!was_crit)
- rel_crit(gv_cur_region);
+ REL_CRIT_BEFORE_RETURN;
return FALSE;
}
jnl_enabled = FALSE;
}
}
- if (jnl_enabled && speedup_nobefore && !csd->jnl_before_image)
- { /* Finish easiest option first. This database has NOBEFORE image journaling and caller has asked for processing
- * to be speeded up in that case. Write only an epoch record, dont do heavyweight flush or fsync of db or jnl.
- * This will avoid bunching of IO at the epoch time like is the case with before-image journaling where this is
- * currently necessary for correctness. But for nobefore, there is no need to do this since no backward recovery
- * will be performed. Note that if db has journaling disabled OR enabled with before-image journaling, we skip
- * this portion of code and follow through to the rest of wcs_flu as if WCSFLU_SPEEDUP_NOBEFORE was not specified.
- */
- assert(!jgbl.mur_extract); /* We dont know of a case where journal extract calls us with skip_db_flush set */
- assert(write_epoch);
- assert(flush_hdr);
- /* For Recovery/Rollback logic (even in case of NOBEFORE image journaling) to work correctly, the TN values in the
- * file header - jnl_eovtn and curr_tn - should be greater than eov_tn in the journal file header. Note: eov_tn
- * in the journal file header is the TN of the penultimate EPOCH and so should always be <= current database
- * transaction number. If this relation is not maintained by GT.M, Rollback/Recovery logic can issue JNLDBTNNOMATCH
- * error. To avoid this situation, flush and sync the DB file header.
- */
- fileheader_sync(gv_cur_region);
- assert(NULL != jpc);
- if (0 == jpc->pini_addr)
- jnl_put_jrt_pini(csa);
- JNL_WRITE_EPOCH_REC(csa, cnl, clean_dbsync);
- if (!was_crit)
- rel_crit(gv_cur_region);
- return TRUE;
- }
- BG_TRACE_ANY(csa, total_buffer_flush);
- INCR_GVSTATS_COUNTER(csa, cnl, n_db_flush, 1);
- cnl->wcsflu_pid = process_id;
- if (dba_mm == csd->acc_meth)
- {
-# if !defined(NO_MSYNC) && !defined(UNTARGETED_MSYNC)
- SIGNAL_WRITERS_TO_STOP(cnl); /* to stop all active writers */
- WAIT_FOR_WRITERS_TO_STOP(cnl, lcnt, MAXGETSPACEWAIT);
- if (MAXGETSPACEWAIT == lcnt)
- {
- GET_C_STACK_MULTIPLE_PIDS("WRITERSTUCK", cnl->wtstart_pid, MAX_WTSTART_PID_SLOTS, 1);
- assert(FALSE);
- cnl->wcsflu_pid = 0;
- if (!was_crit)
- rel_crit(gv_cur_region);
- return FALSE;
- }
- SIGNAL_WRITERS_TO_RESUME(cnl);
- /* wcs_flu() is currently also called from wcs_clean_dbsync() which is interrupt driven code. We are about to
- * remap the database in interrupt code. Depending on where the interrupt occurred, all sorts of strange failures
- * can occur in the mainline code after the remap in interrupt code. Thankfully, this code is currently not
- * enabled by default (NO_MSYNC is the default) so we are fine. If ever this gets re-enabled, we need to
- * solve this problem by changing wcs_clean_dbsync not to call wcs_flu. The assert below is a note for this.
- */
- assert(FALSE);
- MM_DBFILEXT_REMAP_IF_NEEDED(csa, gv_cur_region);
- /* MM MM_DBFILEXT_REMAP_IF_NEEDED can remap the file so reset csd which might no long point to the file */
- csd = csa->hdr;
- while (0 != csa->acc_meth.mm.mmblk_state->mmblkq_active.fl)
- {
- wtstart_errno = wcs_wtstart(gv_cur_region, csd->n_bts);
- assert(ERR_GBLOFLOW != wtstart_errno);
- }
-# else
- if (NO_MSYNC_ONLY((csd->freeze || flush_msync) && ) (csa->ti->last_mm_sync != csa->ti->curr_tn))
- {
- if (0 == msync((caddr_t)csa->db_addrs[0], (size_t)(csa->db_addrs[1] - csa->db_addrs[0]), MS_SYNC))
- csa->ti->last_mm_sync = csa->ti->curr_tn; /* Save when did last full sync */
- else
- {
- cnl->wcsflu_pid = 0;
- if (!was_crit)
- rel_crit(gv_cur_region);
- return FALSE;
- }
- }
-# endif
- }
if (jnl_enabled)
{
- jb = jpc->jnl_buff;
assert(SS_NORMAL == jnl_status);
+ if (return_early = (speedup_nobefore && !csd->jnl_before_image))
+ { /* Finish easiest option first. This database has NOBEFORE image journaling and caller has asked for
+ * processing to be speeded up in that case. Write only an epoch record, dont do heavyweight flush or fsync
+ * of db.This will avoid bunching of IO at the epoch time like is the case with before-image journaling
+ * where this is currently necessary for correctness. But for nobefore, there is no need to do this since
+ * no backward recovery will be performed. Note that if db has journaling disabled OR enabled with before-
+ * image journaling, we skip this portion of code and follow through to the rest of wcs_flu as if
+ * WCSFLU_SPEEDUP_NOBEFORE was not specified.
+ */
+ assert(!jgbl.mur_extract); /* Dont know of a case where journal extract calls us with skip_db_flush set */
+ assert(write_epoch);
+ assert(flush_hdr);
+ /* For Recovery/Rollback logic (even in case of NOBEFORE image journaling) to work correctly, the TN values
+ * in the file header - jnl_eovtn and curr_tn - should be greater than eov_tn in the journal file header.
+ * Note: eov_tn in the journal file header is the TN of the penultimate EPOCH and so should always be <=
+ * current database transaction number. If this relation is not maintained by GT.M, Rollback/Recovery logic
+ * can issue JNLDBTNNOMATCH error. To avoid this situation, flush and sync the DB file header.
+ */
+ fileheader_sync(gv_cur_region);
+ assert(NULL != jpc);
+ if (0 == jpc->pini_addr)
+ jnl_put_jrt_pini(csa);
+ JNL_WRITE_EPOCH_REC(csa, cnl, clean_dbsync);
+ }
fsync_dskaddr = jb->fsync_dskaddr; /* take a local copy as it could change concurrently */
if (fsync_dskaddr != jb->freeaddr)
{
@@ -315,30 +273,53 @@ boolean_t wcs_flu(uint4 options)
if (SS_NORMAL != (jnl_status = jnl_flush(gv_cur_region)))
{
assert(NOJNL == jpc->channel); /* jnl file lost */
- if (!was_crit)
- rel_crit(gv_cur_region);
- send_msg(VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(csd),
- ERR_TEXT, 2, RTS_ERROR_TEXT("Error with journal flush during wcs_flu1"),
- jnl_status);
+ REL_CRIT_BEFORE_RETURN;
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(csd), ERR_TEXT, 2,
+ RTS_ERROR_TEXT("Error with journal flush during wcs_flu1"), jnl_status);
return FALSE;
}
assert(jb->freeaddr == jb->dskaddr);
jnl_fsync(gv_cur_region, jb->dskaddr);
assert(jb->fsync_dskaddr == jb->dskaddr);
}
+ if (return_early)
+ {
+ REL_CRIT_BEFORE_RETURN;
+ return TRUE;
+ }
}
- if (dba_mm != csd->acc_meth)
+ BG_TRACE_ANY(csa, total_buffer_flush);
+ INCR_GVSTATS_COUNTER(csa, cnl, n_db_flush, 1);
+ cnl->wcsflu_pid = process_id;
+ if (dba_mm == csd->acc_meth)
{
- /* If not mupip rundown, wait for ALL active phase2 commits to complete first.
+ if (WBTEST_ENABLED(WBTEST_WCS_FLU_FAIL)
+ || ((csd->freeze || flush_msync) && (csa->ti->last_mm_sync != csa->ti->curr_tn)))
+ {
+ if (!(WBTEST_ENABLED(WBTEST_WCS_FLU_FAIL))
+ && (0 == MSYNC((caddr_t)(MM_BASE_ADDR(csa)), (caddr_t)csa->db_addrs[1])))
+ { /* Save when did last full sync */
+ csa->ti->last_mm_sync = csa->ti->curr_tn;
+ } else
+ {
+ REL_CRIT_BEFORE_RETURN;
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region), ERR_TEXT, 2,
+ RTS_ERROR_TEXT("Error during file msync during flush"));
+ return FALSE;
+ }
+ }
+ }
+ if (dba_mm != csd->acc_meth)
+ { /* If not mupip rundown, wait for ALL active phase2 commits to complete first.
* In case of mupip rundown, we know no one else is accessing shared memory so no point waiting.
*/
assert(!in_mu_rndwn_file || (0 == cnl->wcs_phase2_commit_pidcnt));
- if (cnl->wcs_phase2_commit_pidcnt && !wcs_phase2_commit_wait(csa, NULL))
+ if (WBTEST_ENABLED(WBTEST_WCS_FLU_FAIL) || (cnl->wcs_phase2_commit_pidcnt && !wcs_phase2_commit_wait(csa, NULL)))
{
- assert(WBTEST_CRASH_SHUTDOWN_EXPECTED == gtm_white_box_test_case_number); /* see wcs_phase2_commit_wait.c */
- if (!was_crit)
- rel_crit(gv_cur_region);
- return FALSE; /* we expect the caller to trigger cache-recovery which will fix this counter */
+ assert((WBTEST_CRASH_SHUTDOWN_EXPECTED == gtm_white_box_test_case_number) /* see wcs_phase2_commit_wait.c */
+ || (WBTEST_WCS_FLU_FAIL == gtm_white_box_test_case_number));
+ REL_CRIT_BEFORE_RETURN;
+ return FALSE; /* We expect the caller to trigger cache-recovery which will fix this counter */
}
/* Now that all concurrent commits are complete, wait for these dirty buffers to be flushed to disk.
* Note that calling wcs_wtstart just once assumes that if we ask it to flush all the buffers, it will.
@@ -393,9 +374,9 @@ boolean_t wcs_flu(uint4 options)
if ((to_wait == csd->wait_disk_space)
|| (0 == to_wait % to_msg))
{
- send_msg(VARLSTCNT(7) ERR_WAITDSKSPACE, 4,
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(7) ERR_WAITDSKSPACE, 4,
process_id, to_wait, DB_LEN_STR(gv_cur_region), wtstart_errno);
- gtm_putmsg(VARLSTCNT(7) ERR_WAITDSKSPACE, 4,
+ gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(7) ERR_WAITDSKSPACE, 4,
process_id, to_wait, DB_LEN_STR(gv_cur_region), wtstart_errno);
}
hiber_start(1000);
@@ -406,8 +387,10 @@ boolean_t wcs_flu(uint4 options)
}
if ((to_wait <= 0) && (cnl->wcs_active_lvl || crq->fl))
{ /* not enough space became available after the wait */
- send_msg(VARLSTCNT(5) ERR_OUTOFSPACE, 3, DB_LEN_STR(gv_cur_region), process_id);
- rts_error(VARLSTCNT(5) ERR_OUTOFSPACE, 3, DB_LEN_STR(gv_cur_region), process_id);
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_OUTOFSPACE, 3,
+ DB_LEN_STR(gv_cur_region), process_id);
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_OUTOFSPACE, 3,
+ DB_LEN_STR(gv_cur_region), process_id);
}
} else
{ /* There are four different cases we know of currently when this is possible:
@@ -436,11 +419,12 @@ boolean_t wcs_flu(uint4 options)
{
SET_TRACEABLE_VAR(cnl->wc_blocked, TRUE);
BG_TRACE_PRO_ANY(csa, wcb_wcs_flu1);
- send_msg(VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_LIT("wcb_wcs_flu1"),
- process_id, &csa->ti->curr_tn, DB_LEN_STR(gv_cur_region));
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_WCBLOCKED, 6,
+ LEN_AND_LIT("wcb_wcs_flu1"), process_id, &csa->ti->curr_tn,
+ DB_LEN_STR(gv_cur_region));
} else
{ /* Encountered I/O error. Transfer control to error trap */
- rts_error(VARLSTCNT(7) ERR_DBIOERR, 4, REG_LEN_STR(gv_cur_region),
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(7) ERR_DBIOERR, 4, REG_LEN_STR(gv_cur_region),
DB_LEN_STR(gv_cur_region), wtstart_errno);
}
if (in_commit)
@@ -448,6 +432,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->wcsflu_pid = 0;
return FALSE;
}
assert(!jnl_enabled || jb->fsync_dskaddr == jb->freeaddr);
@@ -466,10 +451,9 @@ boolean_t wcs_flu(uint4 options)
if (SS_NORMAL != (jnl_status = jnl_flush(gv_cur_region)))
{
assert(NOJNL == jpc->channel); /* jnl file lost */
- if (!was_crit)
- rel_crit(gv_cur_region);
- send_msg(VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(csd),
- ERR_TEXT, 2,
+ REL_CRIT_BEFORE_RETURN;
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_JNLFLUSH, 2,
+ JNL_LEN_STR(csd), ERR_TEXT, 2,
RTS_ERROR_TEXT("Error with journal flush during wcs_flu2"),
jnl_status);
return FALSE;
@@ -487,9 +471,7 @@ boolean_t wcs_flu(uint4 options)
WAIT_FOR_CONCURRENT_WRITERS_TO_FINISH(fix_in_wtstart, was_crit);
if (cnl->wcs_active_lvl || crq->fl)
{
- cnl->wcsflu_pid = 0;
- if (!was_crit)
- rel_crit(gv_cur_region);
+ REL_CRIT_BEFORE_RETURN;
GTMASSERT;
}
}
@@ -521,9 +503,7 @@ boolean_t wcs_flu(uint4 options)
{
GET_C_STACK_MULTIPLE_PIDS("MAXJNLQIOLOCKWAIT", cnl->wtstart_pid, MAX_WTSTART_PID_SLOTS, 1);
assert(FALSE);
- cnl->wcsflu_pid = 0;
- if (!was_crit)
- rel_crit(gv_cur_region);
+ REL_CRIT_BEFORE_RETURN;
GTMASSERT;
}
wcs_sleep(SLEEP_JNLQIOLOCKWAIT); /* since it is a short lock, sleep the minimum */
@@ -547,9 +527,7 @@ boolean_t wcs_flu(uint4 options)
}
}
cnl->last_wcsflu_tn = csa->ti->curr_tn; /* record when last successful wcs_flu occurred */
- cnl->wcsflu_pid = 0;
- if (!was_crit)
- rel_crit(gv_cur_region);
+ REL_CRIT_BEFORE_RETURN;
/* sync the epoch record in the journal if needed. */
if (jnl_enabled && write_epoch && sync_epoch && (csa->ti->curr_tn == csa->ti->early_tn))
{ /* Note that if we are in the midst of committing and came here through a bizarre
@@ -566,34 +544,11 @@ boolean_t wcs_flu(uint4 options)
DB_FSYNC(gv_cur_region, udi, csa, db_fsync_in_prog, save_errno);
if (0 != save_errno)
{
- send_msg(VARLSTCNT(5) ERR_DBFSYNCERR, 2, DB_LEN_STR(gv_cur_region), save_errno);
- rts_error(VARLSTCNT(5) ERR_DBFSYNCERR, 2, DB_LEN_STR(gv_cur_region), save_errno);
- assert(FALSE); /* should not come here as the rts_error above should not return */
- return FALSE;
- }
- } else
- {
-#ifndef NO_MSYNC
-#ifndef TARGETED_MSYNC
- DB_FSYNC(gv_cur_region, udi, csa, db_fsync_in_prog, save_errno);
- if (0 != save_errno)
- {
- send_msg(VARLSTCNT(5) ERR_DBFSYNCERR, 2, DB_LEN_STR(gv_cur_region), save_errno);
- rts_error(VARLSTCNT(5) ERR_DBFSYNCERR, 2, DB_LEN_STR(gv_cur_region), save_errno);
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_DBFSYNCERR, 2, DB_LEN_STR(gv_cur_region), save_errno);
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_DBFSYNCERR, 2, DB_LEN_STR(gv_cur_region), save_errno);
assert(FALSE); /* should not come here as the rts_error above should not return */
return FALSE;
}
-#else
- if (-1 == msync((caddr_t)csa->db_addrs[0], (size_t)(csa->db_addrs[1] - csa->db_addrs[0]), MS_SYNC))
- {
- save_errno = errno;
- rts_error(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region),
- ERR_TEXT, 2, RTS_ERROR_TEXT("Error during file msync during flush"), save_errno);
- assert(FALSE); /* should not come here as the rts_error above should not return */
- return FALSE;
- }
-#endif
-#endif
}
}
return TRUE;
diff --git a/sr_unix/wcs_get_space.c b/sr_unix/wcs_get_space.c
index 371a23c..034d81e 100644
--- a/sr_unix/wcs_get_space.c
+++ b/sr_unix/wcs_get_space.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2007, 2012 Fidelity Information Services, Inc *
+ * Copyright 2007, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -87,7 +87,6 @@ error_def(ERR_GBLOFLOW);
} \
/* go after a specific number of buffers or a particular buffer */
-/* not called if UNTARGETED_MSYNC and MM mode */
bool wcs_get_space(gd_region *reg, int needed, cache_rec_ptr_t cr)
{
sgmnt_addrs *csa;
@@ -98,7 +97,6 @@ bool wcs_get_space(gd_region *reg, int needed, cache_rec_ptr_t cr)
int maxspins, retries, spins;
uint4 lcnt, size, to_wait, to_msg, this_idx;
wcs_conflict_trace_t wcs_conflict_trace[WCS_CONFLICT_TRACE_ARRAYSIZE];
- boolean_t is_mm;
cache_rec cr_contents;
DCL_THREADGBL_ACCESS;
@@ -108,8 +106,7 @@ bool wcs_get_space(gd_region *reg, int needed, cache_rec_ptr_t cr)
csa = &FILE_INFO(reg)->s_addrs;
csd = csa->hdr;
cnl = csa->nl;
- is_mm = (dba_mm == csd->acc_meth);
- assert(is_mm || (dba_bg == csd->acc_meth));
+ assert(dba_bg == csd->acc_meth);
assert((0 == needed) || ((DB_CSH_RDPOOL_SZ <= needed) && (needed <= csd->n_bts)));
if (FALSE == csa->now_crit)
{
@@ -119,7 +116,6 @@ bool wcs_get_space(gd_region *reg, int needed, cache_rec_ptr_t cr)
/* a macro that ensure jnl is open, invokes wcs_wtstart() and checks for errors etc. */
return TRUE;
}
- UNTARGETED_MSYNC_ONLY(assert(!is_mm);)
csd->flush_trigger = MAX(csd->flush_trigger - MAX(csd->flush_trigger / STEP_FACTOR, 1), MIN_FLUSH_TRIGGER(csd->n_bts));
/* Routine actually serves two purposes:
* 1 - Free up required number of buffers or
@@ -132,8 +128,6 @@ bool wcs_get_space(gd_region *reg, int needed, cache_rec_ptr_t cr)
for (lcnt = 1; (cnl->wc_in_free < needed) && (BUF_OWNER_STUCK > lcnt); ++lcnt)
{
JNL_ENSURE_OPEN_WCS_WTSTART(csa, reg, needed, save_errno);
- if (is_mm && (ERR_GBLOFLOW == save_errno))
- wcs_recover(reg);
if (cnl->wc_in_free < needed)
{
if ((ENOSPC == save_errno) && (csa->hdr->wait_disk_space > 0))
@@ -154,16 +148,14 @@ bool wcs_get_space(gd_region *reg, int needed, cache_rec_ptr_t cr)
if ((to_wait == cs_data->wait_disk_space)
|| (0 == to_wait % to_msg))
{
- send_msg(VARLSTCNT(7) ERR_WAITDSKSPACE, 4,
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(7) ERR_WAITDSKSPACE, 4,
process_id, to_wait, DB_LEN_STR(reg), save_errno);
- gtm_putmsg(VARLSTCNT(7) ERR_WAITDSKSPACE, 4,
+ gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(7) ERR_WAITDSKSPACE, 4,
process_id, to_wait, DB_LEN_STR(reg), save_errno);
}
hiber_start(1000);
to_wait--;
JNL_ENSURE_OPEN_WCS_WTSTART(csa, reg, needed, save_errno);
- if (is_mm && (ERR_GBLOFLOW == save_errno))
- wcs_recover(reg);
if (cnl->wc_in_free >= needed)
break;
}
@@ -199,14 +191,10 @@ bool wcs_get_space(gd_region *reg, int needed, cache_rec_ptr_t cr)
assert(csa->now_crit); /* must be crit to play with queues when not the writer */
BG_TRACE_PRO_ANY(csa, spcfc_buffer_flush);
++fast_lock_count; /* Disable wcs_stale for duration */
- if (!is_mm) /* Determine queue base to use */
- {
- base = &csa->acc_meth.bg.cache_state->cacheq_active;
- /* If another process is concurrently finishing up phase2 of commit, wait for that to complete first. */
- if (cr->in_tend && !wcs_phase2_commit_wait(csa, cr))
- return FALSE; /* assumption is that caller will set wc_blocked and trigger cache recovery */
- } else
- base = &csa->acc_meth.mm.mmblk_state->mmblkq_active;
+ base = &csa->acc_meth.bg.cache_state->cacheq_active;
+ /* If another process is concurrently finishing up phase2 of commit, wait for that to complete first. */
+ if (cr->in_tend && !wcs_phase2_commit_wait(csa, cr))
+ return FALSE; /* assumption is that caller will set wc_blocked and trigger cache recovery */
maxspins = num_additional_processors ? MAX_LOCK_SPINS(LOCK_SPINS, num_additional_processors) : 1;
for (retries = LOCK_TRIES - 1; retries > 0 ; retries--)
{
@@ -232,8 +220,6 @@ bool wcs_get_space(gd_region *reg, int needed, cache_rec_ptr_t cr)
* If this didn't work, flush normal amount next time in the loop.
*/
JNL_ENSURE_OPEN_WCS_WTSTART(csa, reg, 1, save_errno);
- if (is_mm && (ERR_GBLOFLOW == save_errno))
- wcs_recover(reg);
for (lcnt = 1; (0 != cr->dirty) && (UNIX_GETSPACEWAIT > lcnt); ++lcnt)
{
if (0 == (lcnt % LCNT_INTERVAL))
@@ -262,8 +248,6 @@ bool wcs_get_space(gd_region *reg, int needed, cache_rec_ptr_t cr)
{
BG_TRACE_PRO_ANY(csa, spcfc_buffer_flush_retries);
JNL_ENSURE_OPEN_WCS_WTSTART(csa, reg, 0, save_errno);
- if (is_mm && (ERR_GBLOFLOW == save_errno))
- wcs_recover(reg);
}
/* Usually we want to sleep only if we need to wait on someone else
* i.e. (i) if we are waiting for another process' fsync to complete
@@ -274,7 +258,7 @@ bool wcs_get_space(gd_region *reg, int needed, cache_rec_ptr_t cr)
* Right now we know of only one case where there is no point in waiting
* which is if the cache-record is out of the active queue and is dirty.
* But since that is quite rare and we don't lose much in that case by
- * sleeping we do an unconditional sleep (only if cr is dirty).
+ * sleeping we do an unconditional sleep (only if cr is dirty). {BYPASSOK}
*/
if (!cr->dirty)
return TRUE;
@@ -329,7 +313,7 @@ bool wcs_get_space(gd_region *reg, int needed, cache_rec_ptr_t cr)
return TRUE;
}
if (ENOSPC == save_errno)
- rts_error(VARLSTCNT(7) ERR_WAITDSKSPACE, 4, process_id, to_wait, DB_LEN_STR(reg), save_errno);
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(7) ERR_WAITDSKSPACE, 4, process_id, to_wait, DB_LEN_STR(reg), save_errno);
else
assert(FALSE);
INVOKE_C_STACK_APPROPRIATE(cr, csa, 2);
diff --git a/sr_unix/wcs_wtstart.c b/sr_unix/wcs_wtstart.c
index b4e0fca..4074c15 100644
--- a/sr_unix/wcs_wtstart.c
+++ b/sr_unix/wcs_wtstart.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -43,7 +43,6 @@
#include "gt_timer.h"
#include "send_msg.h"
#include "gtmmsg.h"
-#include "tp_grab_crit.h"
#include "wcs_flu.h"
#include "add_inter.h"
#include "wcs_recover.h"
@@ -108,9 +107,8 @@ int4 wcs_wtstart(gd_region *region, int4 writes)
{
blk_hdr_ptr_t bp, save_bp;
boolean_t need_jnl_sync, queue_empty, got_lock, bmp_status;
- cache_que_head_ptr_t ahead; /* serves dual purpose since cache_que_head = mmblk_que_head */
- cache_state_rec_ptr_t csr, csrfirst; /* serves dual purpose for MM and BG */
- /* since mmblk_state_rec is equal to the top of cache_state_rec */
+ cache_que_head_ptr_t ahead;
+ cache_state_rec_ptr_t csr, csrfirst;
int4 err_status = 0, n, n1, n2, max_ent, max_writes, save_errno;
size_t size ;
jnl_buffer_ptr_t jb;
@@ -125,7 +123,7 @@ int4 wcs_wtstart(gd_region *region, int4 writes)
cache_rec_ptr_t cr, cr_lo, cr_hi;
static int4 error_message_loop_count = 0;
uint4 index;
- boolean_t is_mm;
+ boolean_t is_mm, was_crit;
uint4 curr_wbox_seq_num;
int try_sleep, rc;
gd_region *sav_cur_region;
@@ -147,12 +145,6 @@ int4 wcs_wtstart(gd_region *region, int4 writes)
csd = csa->hdr;
is_mm = (dba_mm == csd->acc_meth);
assert(is_mm || (dba_bg == csd->acc_meth));
-
- /* you don't enter this routine if this has been compiled with #define UNTARGETED_MSYNC and it is MM mode */
-# if defined(UNTARGETED_MSYNC)
- assert(!is_mm);
-# endif
-
BG_TRACE_ANY(csa, wrt_calls); /* Calls to wcs_wtstart */
/* If *this* process is already in wtstart, we won't interrupt it do it again */
if (csa->in_wtstart)
@@ -199,34 +191,34 @@ int4 wcs_wtstart(gd_region *region, int4 writes)
cr_hi = cr_lo + csd->n_bts;
} else
{
- ahead = &csa->acc_meth.mm.mmblk_state->mmblkq_active;
- if (cnl->mm_extender_pid == process_id)
- max_writes = max_ent; /* allow file extender or rundown to write everything out */
- DEBUG_ONLY(cr_lo = (cache_rec_ptr_t)(csa->acc_meth.mm.mmblk_state->mmblk_array + csd->bt_buckets));
- DEBUG_ONLY(cr_hi = (cache_rec_ptr_t)(csa->acc_meth.mm.mmblk_state->mmblk_array + csd->bt_buckets + csd->n_bts));
+ queue_empty = TRUE;
+ n1 = 1; /* set to a non-zero value so dbsync timer canceling (if needed) can happen */
+ goto writes_completed; /* to avoid unnecessary IF checks in the more common case (BG) */
}
assert(((sm_long_t)ahead & 7) == 0);
queue_empty = FALSE;
csa->wbuf_dqd++; /* Tell rundown we have an orphaned block in case of interrupt */
+ was_crit = csa->now_crit;
for (n1 = n2 = 0, csrfirst = NULL; (n1 < max_ent) && (n2 < max_writes) && !cnl->wc_blocked; ++n1)
- {
- csr = (cache_state_rec_ptr_t)REMQHI((que_head_ptr_t)ahead);
- if (INTERLOCK_FAIL == (INTPTR_T)csr)
+ { /* If not-crit, avoid REMQHI by peeking at the active queue and if it is found to have a 0 fl link, assume
+ * there is nothing to flush and break out of the loop. This avoids unnecessary interlock usage (GTM-7635).
+ * If holding crit, we cannot safely avoid the REMQHI so interlock usage is avoided only in the no-crit case.
+ */
+ if (!was_crit && (0 == ahead->fl))
+ csr = NULL;
+ else
{
- assert(FALSE);
- SET_TRACEABLE_VAR(cnl->wc_blocked, TRUE);
- BG_TRACE_PRO_ANY(csa, wcb_wtstart_lckfail1);
- break;
+ csr = (cache_state_rec_ptr_t)REMQHI((que_head_ptr_t)ahead);
+ if (INTERLOCK_FAIL == (INTPTR_T)csr)
+ {
+ assert(FALSE);
+ SET_TRACEABLE_VAR(cnl->wc_blocked, TRUE);
+ BG_TRACE_PRO_ANY(csa, wcb_wtstart_lckfail1);
+ break;
+ }
}
if (NULL == csr)
- {
- NO_MSYNC_ONLY(
- /* NO_MSYNC doesn't sync db, make sure it syncs the journal file */
- if (is_mm)
- queue_empty = TRUE;
- )
break; /* the queue is empty */
- }
if (csr == csrfirst)
{ /* completed a tour of the queue */
queue_empty = FALSE;
@@ -282,7 +274,7 @@ int4 wcs_wtstart(gd_region *region, int4 writes)
if (-1 == rc)
{
assert(FALSE);
- send_msg(VARLSTCNT(9) ERR_JNLFSYNCERR, 2, JNL_LEN_STR(csd),
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_JNLFSYNCERR, 2, JNL_LEN_STR(csd),
ERR_TEXT, 2, RTS_ERROR_TEXT("Error with fsync"), errno);
RELEASE_SWAPLOCK(&jb->fsync_in_prog_latch);
REINSERT_CR_AT_TAIL(csr, ahead, n, csa, csd, wcb_wtstart_lckfail3);
@@ -385,40 +377,9 @@ int4 wcs_wtstart(gd_region *region, int4 writes)
/* allow interrupts now that we are done using the reformat buffer */
ENABLE_INTERRUPTS(INTRPT_IN_REFORMAT_BUFFER_USE);
}
- } else
- {
-# if defined(TARGETED_MSYNC)
- bp = (blk_hdr_ptr_t)(csa->db_addrs[0] + (sm_off_t)csr->blk * MSYNC_ADDR_INCS);
- if ((sm_uc_ptr_t)bp > csa->db_addrs[1])
- save_errno = ERR_GBLOFLOW;
- else
- {
- size = MSYNC_ADDR_INCS;
- save_errno = 0; /* Assume all will work well */
- if (-1 == msync((caddr_t)bp, MSYNC_ADDR_INCS, MS_ASYNC))
- save_errno = errno;
- }
-# elif !defined(NO_MSYNC)
- bp = (blk_hdr_ptr_t)(csa->acc_meth.mm.base_addr + (sm_off_t)csr->blk * csd->blk_size);
- if ((sm_uc_ptr_t)bp > csa->db_addrs[1])
- save_errno = ERR_GBLOFLOW;
- else
- {
- size = bp->bsiz;
- if (csa->do_fullblockwrites)
- size = ROUND_UP(size, csa->fullblockwrite_len);
- assert(size <= csd->blk_size);
- offset = (off_t)((sm_uc_ptr_t)bp - (sm_uc_ptr_t)csd);
- INCR_DB_CSH_COUNTER(csa, n_dsk_writes, 1);
- /* Do db write without timer protect (not needed -- wtstart not reenterable in one task) */
- DB_LSEEKWRITE(csa, udi->fn, udi->fd, offset, bp, size, save_errno);
- }
-# endif
}
-# ifdef DEBUG
/* Trigger I/O error if white box test case is turned on */
GTM_WHITE_BOX_TEST(WBTEST_WCS_WTSTART_IOERR, save_errno, ENOENT);
-# endif
if (0 != save_errno)
{
assert(ERR_ENOSPCQIODEFER != save_errno || !csa->now_crit);
@@ -440,11 +401,12 @@ int4 wcs_wtstart(gd_region *region, int4 writes)
* (see mutex.c)
* Also, may be DBFILERR should be replaced with DBIOERR for specificity.
*/
- send_msg(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(region),
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(region),
ERR_TEXT, 2, RTS_ERROR_TEXT("Error during flush write"), save_errno);
if (!IS_GTM_IMAGE)
{
- gtm_putmsg(VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(region), ERR_TEXT, 2,
+ gtm_putmsg_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_DBFILERR, 2,
+ DB_LEN_STR(region), ERR_TEXT, 2,
RTS_ERROR_TEXT("Error during flush write"), save_errno);
}
save_dskspace_msg_counter = dskspace_msg_counter;
@@ -461,8 +423,8 @@ int4 wcs_wtstart(gd_region *region, int4 writes)
* processes issuing the below send_msg should be relatively small even if there
* are 1000s of processes.
*/
- send_msg(VARLSTCNT(7) ERR_DBIOERR, 4, REG_LEN_STR(region), DB_LEN_STR(region),
- save_errno);
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(7) ERR_DBIOERR, 4, REG_LEN_STR(region),
+ DB_LEN_STR(region), save_errno);
}
}
/* if (ERR_ENOSPCQIODEFER == save_errno): DB_LSEEKWRITE above encountered ENOSPC but couldn't
@@ -497,6 +459,7 @@ int4 wcs_wtstart(gd_region *region, int4 writes)
}
}
csa->wbuf_dqd--;
+writes_completed:
DEBUG_ONLY(
if (0 == n2)
BG_TRACE_ANY(csa, wrt_noblks_wrtn);
diff --git a/sr_unix/zlmov_lnames.c b/sr_unix/zlmov_lnames.c
index 4f9ff45..12e4ce0 100644
--- a/sr_unix/zlmov_lnames.c
+++ b/sr_unix/zlmov_lnames.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2007 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -10,7 +10,7 @@
****************************************************************/
#include "mdef.h"
-#include <string.h>
+#include "gtm_string.h"
#include <rtnhdr.h>
#ifdef USHBIN_SUPPORTED
@@ -31,11 +31,10 @@ void zlmov_lnames(rhdtyp *hdr)
size += lab_ent->lab_name.len;
}
lab_ptr = (char *)malloc(size);
- /* Store the pointer to malloc'd area in literal_text_adr so it can be accessable from the routine header.
- * Although we do not need this pointer, it is kept in literal_text_adr which otherwise anyway becomes
- * dangling after ptext_adr is released */
- hdr->literal_text_adr = (unsigned char *)lab_ptr;
- hdr->literal_text_len = size;
+ /* Previously, we would store the pointer to this malloc'd area in literal_text_adr so it could be accessable from the
+ * routine header. However, we never use the field (e.g., to free it), so there's no point in saving it. With dynamic
+ * literals, we still need literal_text_adr, so let's not do that.
+ */
for (lab_ent = lab_bot + 1; lab_ent < lab_top; lab_ent++)
{
memcpy(lab_ptr, lab_ent->lab_name.addr, lab_ent->lab_name.len);
diff --git a/sr_unix/zshow_devices.c b/sr_unix/zshow_devices.c
index e4dfc49..987a9c1 100644
--- a/sr_unix/zshow_devices.c
+++ b/sr_unix/zshow_devices.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -269,6 +269,8 @@ void zshow_devices(zshow_out *output)
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)
@@ -312,7 +314,13 @@ void zshow_devices(zshow_out *output)
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_PARM_SP(&v, zshow_follow);
+ }
+ }
else
{
ZS_STR_OUT(&v,pipe_text);
@@ -589,15 +597,22 @@ void zshow_devices(zshow_out *output)
} else
{
ZS_STR_OUT(&v, remote_text);
- v.str.addr = socketptr->remote.saddr_ip;
- v.str.len = STRLEN(socketptr->remote.saddr_ip);
+ 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);
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 (socketptr->local.saddr_ip[0])
+ if (NULL != socketptr->local.saddr_ip)
{
ZS_STR_OUT(&v, local_text);
v.str.addr = socketptr->local.saddr_ip;
diff --git a/sr_unix_cm/gtcm.h b/sr_unix_cm/gtcm.h
index a0f689d..26e8a81 100644
--- a/sr_unix_cm/gtcm.h
+++ b/sr_unix_cm/gtcm.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2005 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -52,7 +52,7 @@ int gtcm_dmpstat P((int));
void gtcm_rep_err P((char *, int));
int omi_srvc_xact P((omi_conn *));
int rc_srvc_xact P((omi_conn *, char *));
-char *gtcm_hname P((struct sockaddr_in *));
+char *gtcm_hname P((struct addrinfo *));
void gtcm_cpktdmp P((char *, int, char *));
void gtcm_pktdmp P((char *, int, char *));
void init_hist P((void));
diff --git a/sr_unix_cm/gtcm_bgn_net.c b/sr_unix_cm/gtcm_bgn_net.c
index ae0a05e..409e995 100644
--- a/sr_unix_cm/gtcm_bgn_net.c
+++ b/sr_unix_cm/gtcm_bgn_net.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -17,7 +17,8 @@
#include "gtm_stdlib.h"
#include "gtm_unistd.h" /* for close() used by CLOSEFILE_RESET */
-#include "gtm_time.h" /* for ctime() and time() */
+#include "gtm_time.h" /* for GTM_CTIME() and GTM_TIME() */
+#include "gtm_string.h"
#ifndef lint
static char rcsid[] = "$Header:$";
@@ -30,6 +31,9 @@ static char rcsid[] = "$Header:$";
#include "gtcm.h"
#include "gtmio.h"
+#include "gtm_socket.h"
+#include "gtm_netdb.h"
+#include "gtm_ipv6.h"
GBLREF char *omi_service;
GBLREF int rc_server_id;
@@ -39,6 +43,10 @@ GBLREF int psock;
GBLREF int ping_keepalive;
GBLREF int omi_pid;
+error_def(ERR_GETADDRINFO);
+error_def(ERR_GETNAMEINFO);
+error_def(ERR_TEXT);
+
int gtcm_bgn_net(omi_conn_ll *cll)
{
extern int4 omi_nxact, omi_nerrs, omi_brecv, omi_bsent;
@@ -49,10 +57,12 @@ int gtcm_bgn_net(omi_conn_ll *cll)
#ifdef NET_TCP
struct servent *se;
unsigned short port;
+ char port_buffer[NI_MAXSERV];
#endif /* defined(NET_TCP) */
#ifdef BSD_TCP
- struct sockaddr_in sin;
+ struct addrinfo *ai_ptr, hints;
const boolean_t reuseaddr = TRUE;
+ int errcode;
#else /* defined(BSD_TCP) */
#ifdef SYSV_TCP
struct t_bind *bind;
@@ -75,33 +85,43 @@ int gtcm_bgn_net(omi_conn_ll *cll)
if (!omi_service)
omi_service = SRVC_NAME;
#ifdef NET_TCP
-/* If not specified, we ask the system for any port */
- if (!omi_service)
- port = htons(0);
-/* Ask for a specific port */
- else
+ /* NET_TCP is defined only when BSD_TCP is defined or SYSV_TCP is defined, but SYSV_TCP is never defined (a bug?)
+ * so we move the code of obtaining port information from service down to #ifdef BSD_TCP
+ */
+#ifdef SYSV_TCP
+ GTMASSERT;
+#endif
+#endif /* defined(NET_TCP) */
+#ifdef BSD_TCP
+ /* Create a socket always tries IPv6 first */
+ SERVER_HINTS(hints, ((GTM_IPV6_SUPPORTED && !ipv4_only) ? AF_INET6 : AF_INET));
+ if ((fd = socket(hints.ai_family, SOCK_STREAM, 0)) < 0)
{
- if (ISDIGIT_ASCII(*omi_service))
- port = atoi(omi_service);
- else
+ if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
- se = getservbyname(omi_service, "tcp");
- endservent();
- if (!se)
- {
- OMI_DBG((omi_debug, "%s: Service \"%s\" not found in /etc/services.\n", SRVR_NAME, omi_service));
- return -1;
- }
- port = htons(se->s_port);
+ save_errno = errno;
+ return save_errno;
}
+ hints.ai_family = AF_INET;
}
-#endif /* defined(NET_TCP) */
-#ifdef BSD_TCP
- /* Create a socket */
- if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+ /* Bind an address to the socket */
+ if (0 != (errcode = getaddrinfo(NULL, omi_service, &hints, &ai_ptr)))
{
- save_errno = errno;
- return save_errno;
+ RTS_ERROR_ADDRINFO(NULL, ERR_GETADDRINFO, errcode);
+ return errcode;
+ }
+ if (ISDIGIT_ASCII(*omi_service))
+ port = atoi(omi_service);
+ else
+ {
+ if (0 != (errcode = getnameinfo(ai_ptr->ai_addr, ai_ptr->ai_addrlen, NULL, 0, port_buffer,
+ NI_MAXSERV, NI_NUMERICSERV)))
+ {
+ assert(FALSE);
+ RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode);
+ return errcode;
+ }
+ port = atoi(port_buffer);
}
/* Reuse a specified address */
if (port && setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&reuseaddr, SIZEOF(reuseaddr)) < 0)
@@ -110,11 +130,7 @@ int gtcm_bgn_net(omi_conn_ll *cll)
CLOSEFILE_RESET(fd, rc); /* resets "fd" to FD_INVALID */
return save_errno;
}
- /* Bind an address to the socket */
- sin.sin_family = AF_INET;
- sin.sin_addr.s_addr = INADDR_ANY;
- sin.sin_port = htons(port);
- if (bind(fd, (struct sockaddr *)&sin, SIZEOF(sin)) < 0)
+ if (bind(fd, ai_ptr->ai_addr, ai_ptr->ai_addrlen) < 0)
{
save_errno = errno;
CLOSEFILE_RESET(fd, rc); /* resets "fd" to FD_INVALID */
@@ -146,6 +162,7 @@ int gtcm_bgn_net(omi_conn_ll *cll)
return 0;
#else /* defined(BSD_TCP) */
#ifdef SYSV_TCP
+ GTMASSERT;
if ((fd = t_open(SYSV_TCP, O_RDWR, NULL)) < 0)
{
save_errno = errno;
diff --git a/sr_unix_cm/gtcm_cn_acpt.c b/sr_unix_cm/gtcm_cn_acpt.c
index 321741d..811aee3 100644
--- a/sr_unix_cm/gtcm_cn_acpt.c
+++ b/sr_unix_cm/gtcm_cn_acpt.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -21,13 +21,14 @@
#include "gtm_string.h"
#include "gtm_stdio.h"
#include "gtm_unistd.h" /* for close() used by CLOSEFILE_RESET */
-#include "gtm_time.h" /* for ctime() and time() */
+#include "gtm_time.h" /* for ctime and time */
#include "gtcm.h"
#include "rc_oflow.h"
#include "eintr_wrappers.h"
#include "gtm_socket.h"
#include "gtmio.h"
+#include "have_crit.h"
#ifdef BSD_TCP
#include "gtm_inet.h"
@@ -47,16 +48,17 @@ int gtcm_cn_acpt(omi_conn_ll *cll, int now) /* now --> current time in seconds
omi_conn *cptr;
omi_fd fd;
int rc;
+ char *tmp_time;
#ifdef BSD_TCP
- GTM_SOCKLEN_TYPE sln;
- struct sockaddr_in sin;
+ GTM_SOCKLEN_TYPE sln;
+ struct sockaddr_storage sas;
int optsize;
const boolean_t keepalive = TRUE;
/* Accept the connection from the network layer */
- sln = SIZEOF(sin);
- if ((fd = accept(cll->nve, (struct sockaddr *)&sin, (GTM_SOCKLEN_TYPE *)&sln)) < 0)
+ sln = SIZEOF(sas);
+ if ((fd = accept(cll->nve, (struct sockaddr *)&sas, (GTM_SOCKLEN_TYPE *)&sln)) < 0)
return -1;
#endif /* defined(BSD_TCP) */
@@ -84,7 +86,9 @@ int gtcm_cn_acpt(omi_conn_ll *cll, int now) /* now --> current time in seconds
memset(cptr->of, 0, SIZEOF(struct rc_oflow));
cptr->pklog = FD_INVALID;
/* Initialize the statistics */
- memcpy(&cptr->stats.sin,&sin,SIZEOF(sin));
+ memcpy(&cptr->stats.sas, &sas, sln);
+ cptr->stats.ai.ai_addr = (struct sockaddr *)&cptr->stats.sas;
+ cptr->stats.ai.ai_addrlen = sln;
cptr->stats.bytes_recv = 0;
cptr->stats.bytes_send = 0;
cptr->stats.start = time((time_t *)0);
@@ -100,7 +104,7 @@ int gtcm_cn_acpt(omi_conn_ll *cll, int now) /* now --> current time in seconds
for (prev = NULL, this = cll->head; this; prev = this, this = this->next)
{
- if (this->stats.sin.sin_addr.s_addr == sin.sin_addr.s_addr)
+ if (0 == memcmp((sockaddr_ptr)(&this->stats.sas), (sockaddr_ptr)&sas, sln))
{
if (cll->tail == this)
cll->tail = cptr;
@@ -111,7 +115,7 @@ int gtcm_cn_acpt(omi_conn_ll *cll, int now) /* now --> current time in seconds
cptr->next = this->next;
OMI_DBG_STMP;
OMI_DBG((omi_debug, "%s: dropping old connection to %s\n",
- SRVR_NAME, gtcm_hname(&cptr->stats.sin)));
+ SRVR_NAME, gtcm_hname(&cptr->stats.ai)));
gtcm_cn_disc(this, cll);
break;
}
@@ -154,8 +158,9 @@ int gtcm_cn_acpt(omi_conn_ll *cll, int now) /* now --> current time in seconds
}
}
)
+ GTM_CTIME(tmp_time, &cptr->stats.start);
OMI_DBG((omi_debug, "%s: connection %d from %s by user <%s> at %s", SRVR_NAME,
- cptr->stats.id, gtcm_hname(&cptr->stats.sin), cptr->ag_name, GTM_CTIME(&cptr->stats.start)));
+ cptr->stats.id, gtcm_hname(&cptr->stats.ai), cptr->ag_name, tmp_time));
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&keepalive, SIZEOF(keepalive)) < 0)
{
PERROR("setsockopt:");
diff --git a/sr_unix_cm/gtcm_cn_disc.c b/sr_unix_cm/gtcm_cn_disc.c
index 4b10b09..724c758 100644
--- a/sr_unix_cm/gtcm_cn_disc.c
+++ b/sr_unix_cm/gtcm_cn_disc.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -24,7 +24,7 @@ static char rcsid[] = "$Header:$";
#include "gtm_stdio.h"
#include "gtm_unistd.h" /* for close() used by CLOSEFILE_RESET */
-#include "gtm_time.h" /* for ctime() and time() */
+#include "gtm_time.h" /* for GTM_CTIME() and GTM_TIME() */
#include "gtcm.h"
#include "gtmio.h"
@@ -59,7 +59,7 @@ void gtcm_cn_disc(omi_conn *cptr, omi_conn_ll *cll)
cll->stats.clos++;
OMI_DBG_STMP;
OMI_DBG((omi_debug, "%s: connection %d to %s closed\n",
- SRVR_NAME, cptr->stats.id, gtcm_hname(&cptr->stats.sin)));
+ SRVR_NAME, cptr->stats.id, gtcm_hname(&cptr->stats.ai)));
OMI_DBG((omi_debug, "%s:\t%ld seconds connect time\n", SRVR_NAME, end - cptr->stats.start));
OMI_DBG((omi_debug, "%s:\t%d transactions\n", SRVR_NAME, nxact));
OMI_DBG((omi_debug, "%s:\t%d errors\n", SRVR_NAME, nerrs));
diff --git a/sr_unix_cm/gtcm_dmpstat.c b/sr_unix_cm/gtcm_dmpstat.c
index 26cd963..6ceb1d5 100644
--- a/sr_unix_cm/gtcm_dmpstat.c
+++ b/sr_unix_cm/gtcm_dmpstat.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -51,6 +51,7 @@ int gtcm_dmpstat(int sig)
time_t uptime, uphours, upmins, upsecs;
time_t itime, ihours, imins, isecs;
int status;
+ char *tmp_time;
#ifdef __MVS__
int tag_status;
@@ -70,8 +71,9 @@ int gtcm_dmpstat(int sig)
imins = (itime % 3600) / 60;
isecs = itime % 60;
- FPRINTF(fp, "%s", GTM_CTIME(&t));
- OMI_DBG((omi_debug, "%s", GTM_CTIME(&t)));
+ GTM_CTIME(tmp_time, &t);
+ FPRINTF(fp, "%s", tmp_time);
+ OMI_DBG((omi_debug, "%s", tmp_time));
FPRINTF(fp, "%d\n", omi_pid);
OMI_DBG((omi_debug, "%d\n", omi_pid));
FPRINTF(fp, "Up time: %ld:%.2ld:%.2ld\n",uphours,upmins,upsecs);
diff --git a/sr_unix_cm/gtcm_hist.c b/sr_unix_cm/gtcm_hist.c
index 0632ac3..c26e423 100644
--- a/sr_unix_cm/gtcm_hist.c
+++ b/sr_unix_cm/gtcm_hist.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -20,6 +20,7 @@
#include "gtm_string.h"
#include "gtm_stdio.h" /* for SPRINTF() atleast */
#include "gtm_time.h"
+#include "have_crit.h"
#include <signal.h>
#include "gtcm.h"
@@ -115,9 +116,10 @@ void save_rc_rsp(char *buff, int len)
void dump_omi_rq(void)
{
char msg[256];
- char *then = GTM_CTIME(&omi_hist[omi_hist_num].timestamp);
+ char *then;
omi_conn *temp;
+ GTM_CTIME(then, &omi_hist[omi_hist_num].timestamp);
then[24] = '\0';
if (omi_hist_num < 0) /* no history? */
return;
@@ -131,18 +133,19 @@ void dump_omi_rq(void)
void dump_rc_hist(void)
{
- int i;
+ int i;
+ char msg[256];
+ char *then;
if (rc_hist_num < 0) /* no history? */
return;
i = rc_hist_num;
do
{
- i = (i+1) % HISTORY;
+ i = (i + 1) % HISTORY;
if (rc_hist[i].timestamp)
{
- char msg[256];
- char *then = GTM_CTIME(&rc_hist[i].timestamp);
+ GTM_CTIME(then, &rc_hist[i].timestamp);
then[24] = '\0'; /* eliminate newline */
if (rc_hist[i].toobigflag)
{
diff --git a/sr_unix_cm/gtcm_loop.c b/sr_unix_cm/gtcm_loop.c
index 8666796..d21fc21 100644
--- a/sr_unix_cm/gtcm_loop.c
+++ b/sr_unix_cm/gtcm_loop.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -46,6 +46,8 @@
#include "error.h"
#include "gtmio.h"
#include "have_crit.h"
+#include "gtm_time.h"
+#include "fork_init.h"
#ifndef lint
static char rcsid[] = "$Header:$";
@@ -240,7 +242,7 @@ void gcore_server(void)
dump_rc_hist();
}
- pid=fork(); /* BYPASSOK: we are dumping a core, so no FORK_CLEAN needed */
+ FORK(pid); /* BYPASSOK: we are dumping a core, so no FORK_CLEAN needed */
if (pid < 0) /* fork error */
{
OMI_DBG((omi_debug,
diff --git a/sr_unix_cm/gtcm_ping.c b/sr_unix_cm/gtcm_ping.c
index 6a365fa..e92560a 100644
--- a/sr_unix_cm/gtcm_ping.c
+++ b/sr_unix_cm/gtcm_ping.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -25,11 +25,9 @@
#include "gtm_time.h"
#endif
#include <sys/types.h>
-#include "gtm_netdb.h"
#include "gtm_socket.h"
-#ifndef __MVS__
-#include <netinet/tcp.h>
-#endif
+#include "gtm_netdb.h"
+#include "gtm_ipv6.h"
#include "gtm_inet.h"
#ifndef __MVS__
@@ -72,6 +70,9 @@ struct icmp
#endif /* __CYGWIN__ || __MVS */
#ifdef __MVS__
+
+error_def(ERR_GETNAMEINFO);
+
struct ip
{
unsigned int ip_v:4; /* version */
@@ -124,8 +125,8 @@ int init_ping(void)
int icmp_ping(int conn)
{
fd_set fdmask;
- struct sockaddr_in paddr;
- GTM_SOCKLEN_TYPE paddr_len = SIZEOF(struct sockaddr_in);
+ struct sockaddr_storage paddr;
+ GTM_SOCKLEN_TYPE paddr_len = SIZEOF(struct sockaddr_storage);
struct icmp *icp;
struct ip *ip;
struct timeval timeout;
@@ -163,21 +164,14 @@ int icmp_ping(int conn)
}
#ifdef DEBUG_PING
{
- char *host;
+ char host[SA_MAXLEN];
struct hostent *he;
- char msg[64];
-#ifndef SUNOS
- host = inet_ntoa(paddr.sin_addr.s_addr);
- if ((he = gethostbyaddr(paddr.sin_addr.s_addr, SIZEOF(paddr.sin_addr.s_addr), 0)))
- host = he->h_name;
-#else
- SPRINTF(msg, "%d.%d.%d.%d",
- paddr.sin_addr.s_addr >> 24,
- paddr.sin_addr.s_addr >> 16 & 0xFF,
- paddr.sin_addr.s_addr >> 8 & 0xFF,
- paddr.sin_addr.s_addr & 0xFF);
- host = msg;
-#endif
+ if (0 != (errcode = getnameinfo((struct sockaddr *)&paddr, paddr_len, host, SA_MAXLEN, NULL, 0 0)))
+ {
+ assert(FALSE);
+ RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode);
+ return FALSE;
+ }
OMI_DBG((omi_debug, "ping: send to %s\n",host));
}
#endif
@@ -192,7 +186,7 @@ int icmp_ping(int conn)
*/
int get_ping_rsp(void)
{
- struct sockaddr_in from;
+ struct sockaddr_storage from;
register int cc;
GTM_SOCKLEN_TYPE fromlen;
struct icmp *icp;
@@ -203,6 +197,9 @@ int get_ping_rsp(void)
FPRINTF(stderr,"icmp_ping: no ping socket.\n");
exit(1);
}
+ /* SIZEOF() does not provide correct fromlen.
+ * fromlen in fact decided by recvfrom() below, so no need getaddrinfo() is needed to obtain the correct fromlen
+ */
fromlen = SIZEOF(from);
while ((cc = (int)(recvfrom(pingsock, (char *)pingrcv, IP_MAXPACKET, 0, (struct sockaddr *)&from,
(GTM_SOCKLEN_TYPE *)&fromlen))) < 0)
@@ -217,22 +214,14 @@ int get_ping_rsp(void)
/* xxxxxxx icp = (struct icmp *)(pingrcv + (ip->ip_hl << 2)); */
#ifdef DEBUG_PING
{
- char *host;
+ char host[SA_MAXLEN];
struct hostent *he;
- char msg[64];
-#ifndef SUNOS
- host = inet_ntoa(from.sin_addr.s_addr);
- if ((he = gethostbyaddr(from.sin_addr.s_addr,
- SIZEOF(from.sin_addr.s_addr), 0)))
- host = he->h_name;
-#else
- SPRINTF(msg, "%d.%d.%d.%d",
- from.sin_addr.s_addr >> 24,
- from.sin_addr.s_addr >> 16 & 0xFF,
- from.sin_addr.s_addr >> 8 & 0xFF,
- from.sin_addr.s_addr & 0xFF);
- host = msg;
-#endif
+ if (0 != (errcode = getnameinfo((struct sockaddr *)&from, fromlen, host, SA_MAXLEN, NULL, 0 0)))
+ {
+ assert(FALSE);
+ RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode);
+ return FALSE;
+ }
OMI_DBG((omi_debug, "ping: response from %s\n",host));
}
#endif
diff --git a/sr_unix_cm/gtcm_pktdmp.c b/sr_unix_cm/gtcm_pktdmp.c
index a7b74c9..1bb8954 100644
--- a/sr_unix_cm/gtcm_pktdmp.c
+++ b/sr_unix_cm/gtcm_pktdmp.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -31,38 +31,34 @@
GBLREF omi_conn *curr_conn;
GBLREF char *omi_service;
+error_def(ERR_GETADDRINFO);
+error_def(ERR_GETNAMEINFO);
+error_def(ERR_TEXT);
+
/* return in a static buffer the ASCII representation of a network address.
Returned as:
"hostid (nn.nn.nn.nn)" or "nn.nn.nn.nn" depending on whether or not
the host is listed in /etc/hosts.
*/
-char *gtcm_hname(struct sockaddr_in *sin)
+char *gtcm_hname(struct addrinfo *ai_ptr)
{
- struct hostent *he;
- static char name[256];
-
-#ifndef SUNOS
- if ((he = gethostbyaddr((void *)&sin->sin_addr.s_addr,
- SIZEOF(struct in_addr), AF_INET)))
- SPRINTF(name,"%s (%d.%d.%d.%d)",he->h_name,
- sin->sin_addr.s_addr >> 24,
- sin->sin_addr.s_addr >> 16 & 0xFF,
- sin->sin_addr.s_addr >> 8 & 0xFF,
- sin->sin_addr.s_addr & 0xFF);
- else
- SPRINTF(name,"%d.%d.%d.%d",
- sin->sin_addr.s_addr >> 24,
- sin->sin_addr.s_addr >> 16 & 0xFF,
- sin->sin_addr.s_addr >> 8 & 0xFF,
- sin->sin_addr.s_addr & 0xFF);
-#else
- SPRINTF(name,"%d.%d.%d.%d",
- sin->sin_addr.s_addr >> 24,
- sin->sin_addr.s_addr >> 16 & 0xFF,
- sin->sin_addr.s_addr >> 8 & 0xFF,
- sin->sin_addr.s_addr & 0xFF);
-#endif
- return name;
+ static char name[NI_MAXHOST + NI_MAXSERV + 4];
+ char ipname[NI_MAXSERV];
+ char host[NI_MAXHOST];
+ int errcode;
+
+ if(0 != (errcode = getnameinfo(ai_ptr->ai_addr, ai_ptr->ai_addrlen, ipname,
+ SIZEOF(ipname), NULL, 0, NI_NUMERICHOST)))
+ {
+ RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode);
+ return NULL;
+ }
+ if(0 == (errcode = getnameinfo(ai_ptr->ai_addr, ai_ptr->ai_addrlen, host, SIZEOF(host),
+ NULL, 0, NI_NAMEREQD)))
+ SPRINTF(name, "%s (%s)", host, ipname);
+ else
+ SPRINTF(name, "%s", ipname);
+ return name;
}
@@ -77,7 +73,7 @@ void gtcm_cpktdmp(char *ptr, int length, char *msg)
if (curr_conn && (512-strlen(msg)) > 25)
{
SPRINTF(newmsg,"Conn: %s - %s",
- gtcm_hname(&curr_conn->stats.sin), msg);
+ gtcm_hname(&curr_conn->stats.ai), msg);
gtcm_pktdmp(ptr, length, newmsg);
}
@@ -103,7 +99,7 @@ void gtcm_pktdmp(char *ptr, int length, char *msg)
char *gtm_dist;
ctim = time(0);
- ltime = localtime(&ctim);
+ GTM_LOCALTIME(ltime, &ctim);
SPRINTF(tbuf, "%02d%02d%02d%02d",ltime->tm_mon + 1,ltime->tm_mday,
ltime->tm_hour,ltime->tm_min);
diff --git a/sr_unix_cm/gtcm_rep_err.c b/sr_unix_cm/gtcm_rep_err.c
index 3ab6f20..a269d37 100644
--- a/sr_unix_cm/gtcm_rep_err.c
+++ b/sr_unix_cm/gtcm_rep_err.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -59,7 +59,7 @@ void gtcm_rep_err(char *msg, int errcode)
char outbuf[OUT_BUFF_SIZE];
time_t now;
int status, retval;
- char *gtm_dist, *filebuf;
+ char *gtm_dist, *filebuf, *tag_emsg, *tmp_time;
mstr tn;
MSTR_DEF(val, strlen(GTM_DIST_PATH), GTM_DIST_PATH); /* BYPASSOK */
@@ -87,7 +87,7 @@ void gtcm_rep_err(char *msg, int errcode)
# ifdef __MVS__
if (-1 != gtm_zos_create_tagged_file(fileName, TAG_EBCDIC))
{
- char *tag_emsg = STRERROR(errno);
+ tag_emsg = STRERROR(errno);
sgtm_putmsg(outbuf, VARLSTCNT(10) ERR_BADTAG, 4, LEN_AND_STR(fileName),
-1, TAG_EBCDIC, ERR_TEXT, 2, RTS_ERROR_STRING(tag_emsg));
}
@@ -95,7 +95,8 @@ void gtcm_rep_err(char *msg, int errcode)
if ((fp = Fopen(fileName, "a")))
{
now = time(0);
- FPRINTF(fp, "%s", GTM_CTIME(&now));
+ GTM_CTIME(tmp_time, &now);
+ FPRINTF(fp, "%s", tmp_time);
FPRINTF(fp, "server(%s) %s", omi_service, outbuf);
FCLOSE(fp, status);
}
diff --git a/sr_unix_cm/omi.h b/sr_unix_cm/omi.h
index 7be7a3f..567a1f0 100644
--- a/sr_unix_cm/omi.h
+++ b/sr_unix_cm/omi.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -57,23 +57,26 @@
{ \
extern FILE *omi_debug; \
time_t clock; \
+ char *time_ptr; \
+ \
if (omi_debug) \
{ \
clock = time((time_t *)0); \
- FPRINTF(omi_debug, "%s", ctime(&clock)); \
+ GTM_CTIME(time_ptr, &clock); \
+ FPRINTF(omi_debug, "%s", time_ptr); \
FFLUSH(omi_debug); \
} \
} while (0)
-#define OMI_DBG(X) \
- do \
- { \
- extern FILE *omi_debug; \
- if (omi_debug) \
- { \
- FPRINTF X ; \
- FFLUSH(omi_debug); \
- } \
+#define OMI_DBG(X) \
+ do \
+ { \
+ extern FILE *omi_debug; \
+ if (omi_debug) \
+ { \
+ FPRINTF X ; \
+ FFLUSH(omi_debug); \
+ } \
} while (0)
@@ -301,7 +304,8 @@ typedef struct omi_cn_stat
{
int id;
time_t start;
- struct sockaddr_in sin;
+ struct addrinfo ai;
+ struct sockaddr_storage sas;
int bytes_recv;
int bytes_send;
int xact[OMI_OP_MAX];
diff --git a/sr_unix_cm/omi_prc_conn.c b/sr_unix_cm/omi_prc_conn.c
index ffb8e99..944890f 100644
--- a/sr_unix_cm/omi_prc_conn.c
+++ b/sr_unix_cm/omi_prc_conn.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -150,7 +150,7 @@ int omi_prc_conn(omi_conn *cptr, char *xend, char *buff, char *bend)
{
OMI_DBG((omi_debug, "%s: memory allocation error (insufficient resources) while\n", SRVR_NAME));
OMI_DBG((omi_debug, "processing connect request from connection %d, %s.\n",
- cptr->stats.id, gtcm_hname(&cptr->stats.sin)));
+ cptr->stats.id, gtcm_hname(&cptr->stats.ai)));
return -OMI_ER_DB_UNRECOVER;
}
assert(ss_len.value < MAX_USER_NAME && ss_len.value > 0);
@@ -165,7 +165,7 @@ int omi_prc_conn(omi_conn *cptr, char *xend, char *buff, char *bend)
{
OMI_DBG((omi_debug, "%s: memory allocation error (insufficient resources) while\n", SRVR_NAME));
OMI_DBG((omi_debug, "processing connect request from connection %d, %s.\n",
- cptr->stats.id, gtcm_hname(&cptr->stats.sin)));
+ cptr->stats.id, gtcm_hname(&cptr->stats.ai)));
return -OMI_ER_DB_UNRECOVER;
}
diff --git a/sr_unix_cm/omi_srvc_xct.c b/sr_unix_cm/omi_srvc_xct.c
index 1bbc615..08bc399 100644
--- a/sr_unix_cm/omi_srvc_xct.c
+++ b/sr_unix_cm/omi_srvc_xct.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -99,18 +99,18 @@ int omi_srvc_xact (omi_conn *cptr)
if (errno == ETIMEDOUT)
{
OMI_DBG((omi_debug, "%s: connection %d to %s timed out.\n",
- SRVR_NAME, cptr->stats.id, gtcm_hname(&cptr->stats.sin)));
+ SRVR_NAME, cptr->stats.id, gtcm_hname(&cptr->stats.ai)));
}
else if (errno == ECONNRESET)
{
OMI_DBG((omi_debug, "%s: connection %d to %s closed by remote client.\n",
- SRVR_NAME, cptr->stats.id, gtcm_hname(&cptr->stats.sin)));
+ SRVR_NAME, cptr->stats.id, gtcm_hname(&cptr->stats.ai)));
}
else
{
char msg[256];
SPRINTF(msg, "Attempted read from connection %d to %s failed",
- cptr->stats.id, gtcm_hname(&cptr->stats.sin));
+ cptr->stats.id, gtcm_hname(&cptr->stats.ai));
gtcm_rep_err(msg, save_errno);
}
return -1;
@@ -426,17 +426,17 @@ int omi_srvc_xact (omi_conn *cptr)
if (errno == ETIMEDOUT)
{
OMI_DBG((omi_debug, "%s: connection %d to %s timed out.\n",
- SRVR_NAME, cptr->stats.id, gtcm_hname(&cptr->stats.sin)));
+ SRVR_NAME, cptr->stats.id, gtcm_hname(&cptr->stats.ai)));
}
else if (errno == ECONNRESET)
{
OMI_DBG((omi_debug, "%s: connection %d to %s closed by remote client.\n",
- SRVR_NAME, cptr->stats.id, gtcm_hname(&cptr->stats.sin)));
+ SRVR_NAME, cptr->stats.id, gtcm_hname(&cptr->stats.ai)));
}
else if (errno == EPIPE)
{
OMI_DBG((omi_debug, "%s: remote client no longer attached to connection %d, %s.\n",
- SRVR_NAME, cptr->stats.id, gtcm_hname(&cptr->stats.sin)));
+ SRVR_NAME, cptr->stats.id, gtcm_hname(&cptr->stats.ai)));
}
else if (errno == EINTR)
continue;
diff --git a/sr_unix_gnp/cmi_init.c b/sr_unix_gnp/cmi_init.c
index 6e74fb8..e41cadf 100644
--- a/sr_unix_gnp/cmi_init.c
+++ b/sr_unix_gnp/cmi_init.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -16,6 +16,7 @@
#include "gtm_netdb.h"
#include "gtm_socket.h"
#include "gtm_inet.h"
+#include "gtm_ipv6.h"
#include "cmidef.h"
#include "eintr_wrappers.h"
@@ -39,16 +40,17 @@ cmi_status_t cmi_init(cmi_descriptor *tnd, unsigned char tnr,
char *envvar;
struct protoent *p;
unsigned short myport;
- struct sockaddr_in in;
sigset_t oset;
int on = 1;
int rval, rc, save_errno;
+ struct addrinfo *ai_ptr, *local_ai_ptr;
+ boolean_t af;
status = cmj_netinit();
if (CMI_ERROR(status))
return status;
- status = cmj_getsockaddr(tnd, &in);
+ status = cmj_getsockaddr(NULL, tnd, &local_ai_ptr);
if (CMI_ERROR(status))
return status;
ntd_root->pool_size = pool_size;
@@ -61,9 +63,13 @@ cmi_status_t cmi_init(cmi_descriptor *tnd, unsigned char tnr,
return CMI_NETFAIL;
/* create the listening socket */
- ntd_root->listen_fd = socket(AF_INET, SOCK_STREAM, p->p_proto);
- if (FD_INVALID == ntd_root->listen_fd)
+ if ((GTM_IPV6_SUPPORTED && !ipv4_only)
+ && (FD_INVALID != (ntd_root->listen_fd = socket(AF_INET6, SOCK_STREAM, p->p_proto))))
+ af = AF_INET6;
+ else if (FD_INVALID == (ntd_root->listen_fd = socket(AF_INET, SOCK_STREAM, p->p_proto)))
return errno;
+ else
+ af = AF_INET;
/* make sure we can re-run quickly w/o reuse problems */
status = setsockopt(ntd_root->listen_fd, SOL_SOCKET, SO_REUSEADDR,
@@ -75,7 +81,19 @@ cmi_status_t cmi_init(cmi_descriptor *tnd, unsigned char tnr,
return save_errno;
}
- status = bind(ntd_root->listen_fd, (struct sockaddr*)&in, SIZEOF(in));
+ for(ai_ptr = local_ai_ptr; NULL != ai_ptr; ai_ptr = ai_ptr->ai_next)
+ if (af == ai_ptr->ai_family)
+ break;
+
+ if (NULL == ai_ptr)
+ {
+ CLOSEFILE_RESET(ntd_root->listen_fd, rc);
+ return CMI_NETFAIL;
+ }
+
+ status = bind(ntd_root->listen_fd, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
+ freeaddrinfo(ai_ptr);
+
if (-1 == status)
{
save_errno = errno;
diff --git a/sr_unix_gnp/cmi_open.c b/sr_unix_gnp/cmi_open.c
index 46ca6be..355ebf4 100644
--- a/sr_unix_gnp/cmi_open.c
+++ b/sr_unix_gnp/cmi_open.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -38,14 +38,13 @@ cmi_status_t cmi_open(struct CLB *lnk)
int rval;
unsigned char *cp;
char hn[MAX_HOST_NAME_LEN];
- struct sockaddr_in in;
- struct hostent *hp;
- struct protoent *p;
+ struct addrinfo *ai_ptr, *ai_head;
sigset_t oset;
int new_fd, rc, save_errno;
int sockerror;
GTM_SOCKLEN_TYPE sockerrorlen;
fd_set writefds;
+ int save_error;
if (!ntd_root)
{
@@ -55,14 +54,10 @@ cmi_status_t cmi_open(struct CLB *lnk)
}
lnk->ntd = ntd_root;
- status = cmj_resolve_nod_tnd(&lnk->nod, &lnk->tnd, &in);
+ status = cmj_getsockaddr(&lnk->nod, &lnk->tnd, &ai_head);
if (CMI_ERROR(status))
return status;
- p = getprotobyname(GTCM_SERVER_PROTOCOL);
- endprotoent();
- if (!p)
- return CMI_NETFAIL;
lnk->mun = -1;
memset((void *)&lnk->cqe, 0, SIZEOF(lnk->cqe));
@@ -74,11 +69,18 @@ cmi_status_t cmi_open(struct CLB *lnk)
lnk->sta = CM_CLB_DISCONNECT;
lnk->err = NULL;
lnk->ast = NULL;
- new_fd = socket(AF_INET, SOCK_STREAM, p->p_proto);
- if (FD_INVALID == new_fd)
+ for(ai_ptr = ai_head; NULL != ai_ptr; ai_ptr = ai_ptr->ai_next)
+ {
+ if (FD_INVALID != (new_fd = socket(ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol)))
+ break;
+ save_errno = errno;
+ }
+ if (NULL == ai_ptr)
+ {
+ freeaddrinfo(ai_head);
return errno;
-
- rval = connect(new_fd, (struct sockaddr *)&in, SIZEOF(in));
+ }
+ rval = connect(new_fd, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
if ((-1 == rval) && ((EINTR == errno) || (EINPROGRESS == errno)
#if (defined(__osf__) && defined(__alpha)) || defined(__sun) || defined(__vms)
|| (EWOULDBLOCK == errno)
@@ -126,12 +128,15 @@ cmi_status_t cmi_open(struct CLB *lnk)
if (new_fd > ntd_root->max_fd)
ntd_root->max_fd = new_fd;
lnk->mun = new_fd;
- lnk->peer = in;
+ memcpy((struct sockaddr *)(&lnk->peer_sas), ai_ptr->ai_addr, ai_ptr->ai_addrlen);
+ memcpy(&lnk->peer_ai, ai_ptr, SIZEOF(struct addrinfo));
+ lnk->peer_ai.ai_addr = (struct sockaddr *)(&lnk->peer_sas);
FD_SET(new_fd, &ntd_root->es);
lnk->sta = CM_CLB_IDLE;
} else
CLOSEFILE_RESET(new_fd, rc); /* resets "new_fd" to FD_INVALID */
}
SIGPROCMASK(SIG_SETMASK, &oset, NULL, rc);
+ freeaddrinfo(ai_head); /* prevent mem-leak */
return status;
}
diff --git a/sr_unix_gnp/cmi_peer_info.c b/sr_unix_gnp/cmi_peer_info.c
index 1943adb..f48eaae 100644
--- a/sr_unix_gnp/cmi_peer_info.c
+++ b/sr_unix_gnp/cmi_peer_info.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2002, 2009 Fidelity Information Services, Inc *
+ * Copyright 2002, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -13,35 +13,48 @@
#define _ISOC99_SOURCE
#endif
+#include <errno.h> /* for errno, used by RTS_ERROR_ADDRINFO */
+
#include "mdef.h"
#include "cmidef.h"
#include "gtm_netdb.h"
#include "gtm_socket.h"
#include "gtm_stdio.h"
+#include "iotcpdef.h"
+#include "gtm_string.h" /* for rts_error */
/* return in a the char * the ASCII representation of a network address.
Returned as:
"hostid (nn.nn.nn.nn)" or "nn.nn.nn.nn" depending on whether or not
the host is listed in /etc/hosts.
*/
+error_def(ERR_GETNAMEINFO);
+error_def(ERR_TEXT);
+
void cmi_peer_info(struct CLB *lnk, char *buf, size_t sz)
{
- struct sockaddr_in *sin = &lnk->peer;
-#ifndef SUNOSwhysmw
- struct hostent *he;
+ struct addrinfo *ai_ptr;
+ char hostname[SA_MAXLITLEN];
+ char ipname[SA_MAXLEN];
+ char port_str[NI_MAXSERV];
+ int errcode;
- if ((he = gethostbyaddr((char *)&sin->sin_addr.s_addr,
- SIZEOF(struct in_addr), AF_INET)))
- snprintf(buf, sz, "%s (%d.%d.%d.%d:%d)",he->h_name,
- sin->sin_addr.s_addr >> 24,
- sin->sin_addr.s_addr >> 16 & 0xFF,
- sin->sin_addr.s_addr >> 8 & 0xFF,
- sin->sin_addr.s_addr & 0xFF, (int)sin->sin_port);
- else
-#endif
- snprintf(buf, sz, "%d.%d.%d.%d:%d",
- sin->sin_addr.s_addr >> 24,
- sin->sin_addr.s_addr >> 16 & 0xFF,
- sin->sin_addr.s_addr >> 8 & 0xFF,
- sin->sin_addr.s_addr & 0xFF, (int)sin->sin_port);
+ ai_ptr = &lnk->peer_ai;
+ if (0 != (errcode = getnameinfo(ai_ptr->ai_addr, ai_ptr->ai_addrlen,
+ ipname, SA_MAXLEN,
+ port_str, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV)))
+ {
+ assert(0);
+ RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode);
+ return;
+ }
+ if (0 != (errcode = getnameinfo(ai_ptr->ai_addr, ai_ptr->ai_addrlen,
+ hostname, SA_MAXLITLEN,
+ NULL, 0, 0)))
+ {
+ assert(0);
+ RTS_ERROR_ADDRINFO(NULL, ERR_GETNAMEINFO, errcode);
+ return;
+ }
+ SNPRINTF(buf, sz, "%s (%s:%s)", hostname, ipname, port_str);
}
diff --git a/sr_unix_gnp/cmj_get_port.c b/sr_unix_gnp/cmj_get_port.c
index 4ab1026..47d4a36 100644
--- a/sr_unix_gnp/cmj_get_port.c
+++ b/sr_unix_gnp/cmj_get_port.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -14,7 +14,6 @@
#include "gtm_netdb.h"
#include "gtm_stdlib.h"
#include "gtm_string.h"
-#include <netinet/in.h>
#include "gtm_inet.h"
diff --git a/sr_unix_gnp/cmj_getsockaddr.c b/sr_unix_gnp/cmj_getsockaddr.c
index af31667..811c1ae 100644
--- a/sr_unix_gnp/cmj_getsockaddr.c
+++ b/sr_unix_gnp/cmj_getsockaddr.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -11,8 +11,9 @@
#include "mdef.h"
-#include "gtm_netdb.h"
#include "gtm_socket.h"
+#include "gtm_netdb.h"
+#include "gtm_ipv6.h"
#include "gtm_stdlib.h"
#include "gtm_string.h"
#include "gtm_inet.h"
@@ -23,75 +24,137 @@
#include "cmidef.h"
#include "eintr_wrappers.h"
+#define IPV6_SEPARATOR ']'
+#define IPV6_START '['
+
+error_def(CMI_BADIPADDRPORT);
+error_def(CMI_NOSERVENT);
+error_def(ERR_TEXT);
+error_def(CMI_NETFAIL);
+
/* writes into outport the TCP port cooresponding to tnd in NBO */
-cmi_status_t cmj_getsockaddr(cmi_descriptor *tnd, struct sockaddr_in *inp)
+cmi_status_t cmj_getsockaddr(cmi_descriptor *nod, cmi_descriptor *tnd, struct addrinfo **ai_ptr_ptr)
{
struct servent *s;
- char *tnd_str, *cp;
- char port_str[MAX_HOST_NAME_LEN];
- int tnd_len, ip_len;
-
- error_def(CMI_BADIPADDRPORT);
- error_def(CMI_NOSERVENT);
+ char *tnd_str, *cp, *addr_str_ptr;
+ char addr_end;
+ char port_str[MAX_HOST_NAME_LEN], *port_str_ptr;
+ char hn[MAX_HOST_NAME_LEN];
+ int loop_limit = MAX_GETHOST_TRIES;
+ int tnd_len, iplen, port_len;
+ struct addrinfo hints, *ai_ptr = NULL;
+ struct protoent *pe_ptr;
+ int errcode;
+ int port;
/*
* address/port number determination:
*
- * tnd := [IP address:]port
+ * tnd := IP address:port for IPv4
+ * tnd := [IP address]:port for IPv6
*
* If tnd is an empty string, get port number from services database
*
*/
tnd_str = CMI_DESC_POINTER(tnd);
tnd_len = CMI_DESC_LENGTH(tnd);
- if (tnd && 0 < tnd->len)
+ if (tnd && (0 < tnd->len))
{
- /* look for : */
- for (ip_len = 0, cp = tnd_str; cp < tnd_str + tnd_len; cp++)
+ /* look for symbol separted ip address and port in ipv6 */
+ if (IPV6_START == tnd_str[0])
{
- if (*cp != ':' && *cp != '.' && !ISDIGIT_ASCII(*cp))
+ if (NULL != (port_str_ptr = memchr(tnd_str, IPV6_SEPARATOR, tnd_len)))
+ {
+ if (0 == (iplen = (int)(port_str_ptr - &tnd_str[1])))
+ return CMI_BADIPADDRPORT;
+ if (iplen == tnd_len)
+ return CMI_BADIPADDRPORT;
+ } else
return CMI_BADIPADDRPORT;
- if (*cp == ':')
+ addr_str_ptr = &tnd_str[1]; /* skip the '[' */
+ iplen = port_str_ptr - addr_str_ptr;
+ port_str_ptr += 1; /* skip the ']' */
+ if (*port_str_ptr != ':')
+ return CMI_BADIPADDRPORT;
+ port_str_ptr += 1;
+ } else
+ {
+ /* look for : */
+ addr_str_ptr = port_str_ptr = tnd_str;
+ for (iplen = 0, cp = tnd_str; cp < tnd_str + tnd_len; cp++)
{
- if (0 == ip_len)
+ if (*cp != ':' && *cp != '.' && !ISDIGIT_ASCII(*cp))
+ return CMI_BADIPADDRPORT;
+ if (*cp == ':')
{
- if (0 == (ip_len = (int)(cp - tnd_str)))
+ if (0 == iplen)
+ {
+ if (0 == (iplen = (int)(cp - tnd_str)))
+ return CMI_BADIPADDRPORT;
+ port_str_ptr = (cp + 1);
+ } else
return CMI_BADIPADDRPORT;
- } else
- return CMI_BADIPADDRPORT;
+ }
}
+
}
- if (0 != ip_len)
- {
- *(tnd_str + ip_len) = '\0';
- inp->sin_addr.s_addr = INET_ADDR(tnd_str);
- *(tnd_str + ip_len) = ':';
- if ((in_addr_t)-1 == inp->sin_addr.s_addr)
+ port_len = (tnd_str + tnd_len) - port_str_ptr;
+ if (0 >= port_len)
+ return CMI_BADIPADDRPORT;
+ memcpy(port_str, port_str_ptr, port_len);
+ port_str[port_len] = '\0';
+
+ if (0 != iplen)
+ { /* specified host name and port */
+ addr_end = *(addr_str_ptr + iplen); /* the end can be ] or : */
+ *(addr_str_ptr + iplen) = '\0';
+ /* obtain ipv4/6 address for host tnd_str */
+ CLIENT_HINTS(hints);
+ if (0 != (errcode = getaddrinfo(addr_str_ptr, port_str, &hints, &ai_ptr)))
+ {
+ *(addr_str_ptr + iplen) = addr_end;
return CMI_BADIPADDRPORT;
+ }
+ *(addr_str_ptr + iplen) = addr_end;
} else
- {
- inp->sin_addr.s_addr = INADDR_ANY;
- ip_len = -1;
+ { /* only port is specified */
+ if (NULL != nod)
+ {
+ assert(CMI_DESC_LENGTH(nod) < (SIZEOF(hn)-1));
+ memcpy(hn, CMI_DESC_POINTER(nod), CMI_DESC_LENGTH(nod));
+ hn[CMI_DESC_LENGTH(nod)] = '\0';
+ CLIENT_HINTS(hints);
+
+ while ((EAI_AGAIN == (errcode = getaddrinfo(hn, port_str, &hints, &ai_ptr))) && (0 < loop_limit))
+ {
+ loop_limit--;
+ }
+ if (0 != errcode)
+ return CMI_NETFAIL;
+ *ai_ptr_ptr = ai_ptr;
+ return SS_NORMAL;
+ }
+
+ SERVER_HINTS(hints, (ipv4_only ? AF_INET : AF_UNSPEC));
+ if (0 != (errcode = getaddrinfo(NULL, port_str, &hints, &ai_ptr)))
+ {
+ return CMI_BADIPADDRPORT;
+ }
+ iplen = -1;
}
- if (tnd_len - ip_len > SIZEOF(port_str))
- return CMI_BADIPADDRPORT;
- memcpy(port_str, tnd_str + ip_len + 1, tnd_len - ip_len - 1);
- port_str[tnd_len - ip_len - 1] = '\0';
errno = 0;
- if (((0 == (inp->sin_port = ATOI(port_str))) && (0 != errno)) || (0 >= inp->sin_port))
+ port = ATOI(port_str);
+ if ((0 == port) && (0 != errno) || (0 >= port))
return CMI_BADIPADDRPORT;
- inp->sin_port = htons(inp->sin_port);
} else
- {
- inp->sin_addr.s_addr = INADDR_ANY;
+ { /* neither host nor port is specified */
/* use the services db */
- s = getservbyname(GTCM_SERVER_NAME, GTCM_SERVER_PROTOCOL);
- endservent();
- if (!s)
+ SERVER_HINTS(hints, (ipv4_only ? AF_INET : AF_UNSPEC));
+ if (0 != (errcode = getaddrinfo(NULL, GTCM_SERVER_NAME, &hints, &ai_ptr)))
+ {
return CMI_NOSERVENT;
- /* get port - netdb routine returns in NBO */
- inp->sin_port = s->s_port;
+ }
}
- inp->sin_family = AF_INET;
+ *ai_ptr_ptr = ai_ptr;
return SS_NORMAL;
}
diff --git a/sr_unix_gnp/cmj_incoming_call.c b/sr_unix_gnp/cmj_incoming_call.c
index 81f197a..3213880 100644
--- a/sr_unix_gnp/cmj_incoming_call.c
+++ b/sr_unix_gnp/cmj_incoming_call.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -20,16 +20,17 @@
#include <errno.h>
#include "gtmio.h"
#include "relqop.h"
+#include "gtm_string.h" /* for memcpy */
void cmj_incoming_call(struct NTD *tsk)
{
int rval, rc;
struct CLB *lnk;
- struct sockaddr_in in;
- GTM_SOCKLEN_TYPE sz = SIZEOF(in);
+ struct sockaddr_storage sas;
+ GTM_SOCKLEN_TYPE sz = SIZEOF(struct sockaddr);
cmi_status_t status;
- while ((-1 == (rval = ACCEPT(tsk->listen_fd, (struct sockaddr *)&in, (GTM_SOCKLEN_TYPE *)&sz))) && EINTR == errno)
+ while ((-1 == (rval = ACCEPT(tsk->listen_fd, (struct sockaddr *)&sas, (GTM_SOCKLEN_TYPE *)&sz))) && EINTR == errno)
;
while (rval >= 0)
{
@@ -59,14 +60,16 @@ void cmj_incoming_call(struct NTD *tsk)
tsk->max_fd = rval;
lnk->mun = rval;
lnk->sta = CM_CLB_IDLE;
- lnk->peer = in;
+ memcpy(&lnk->peer_sas, &sas, sz);
+ lnk->peer_ai.ai_addr = (struct sockaddr *)&lnk->peer_sas;
+ lnk->peer_ai.ai_addrlen = sz;
insqh(&lnk->cqe, &tsk->cqh);
lnk->ntd = tsk;
FD_SET(rval, &tsk->es);
/* setup for callback processing */
lnk->deferred_event = TRUE;
lnk->deferred_reason = CMI_REASON_CONNECT;
- while ((-1 == (rval = ACCEPT(tsk->listen_fd, (struct sockaddr *)&in, (GTM_SOCKLEN_TYPE *)&sz))) && EINTR == errno)
- ;
+ while ((-1 == (rval = ACCEPT(tsk->listen_fd, (struct sockaddr *)&sas, (GTM_SOCKLEN_TYPE *)&sz)))
+ && EINTR == errno);
}
}
diff --git a/sr_unix_gnp/cmj_resolve_nod_tnd.c b/sr_unix_gnp/cmj_resolve_nod_tnd.c
deleted file mode 100644
index 1ec7958..0000000
--- a/sr_unix_gnp/cmj_resolve_nod_tnd.c
+++ /dev/null
@@ -1,57 +0,0 @@
-/****************************************************************
- * *
- * Copyright 2001, 2009 Fidelity Information Services, Inc *
- * *
- * This source code contains the intellectual property *
- * of its copyright holder(s), and is made available *
- * under a license. If you do not know the terms of *
- * the license, please stop and do not read further. *
- * *
- ****************************************************************/
-
-#include "mdef.h"
-#include "cmidef.h"
-#include <netinet/in.h>
-#include "gtm_socket.h"
-#include "gtm_netdb.h"
-#include "gtm_inet.h"
-#include "gtm_string.h"
-#include <errno.h>
-#include "relqop.h"
-
-error_def(CMI_NETFAIL);
-
-cmi_status_t cmj_resolve_nod_tnd(cmi_descriptor *nod, cmi_descriptor *tnd, struct sockaddr_in *inp)
-{
- cmi_status_t status = SS_NORMAL;
- char hn[MAX_HOST_NAME_LEN];
- struct hostent *hp;
- int loop_limit = MAX_GETHOST_TRIES;
-
- /* tnd may contain host:port */
- status = cmj_getsockaddr(tnd, inp);
- if (CMI_ERROR(status))
- return status;
-
- if (inp->sin_addr.s_addr == INADDR_ANY)
- {
- /* use nod as a host name if tnd was just a port */
- assert(CMI_DESC_LENGTH(nod) < (SIZEOF(hn)-1));
- memcpy(hn, CMI_DESC_POINTER(nod), CMI_DESC_LENGTH(nod));
- hn[CMI_DESC_LENGTH(nod)] = '\0';
-
- /* test to see if nod is a dotted quad text string */
- inp->sin_addr.s_addr = INET_ADDR(hn);
- if (inp->sin_addr.s_addr == (in_addr_t)-1)
- {
- /* assume hn is a host and query netdb */
- for (; 0 < loop_limit && (NULL == (hp = GETHOSTBYNAME(hn))) && TRY_AGAIN == h_errno; loop_limit--)
- ;
- endhostent();
- if (!hp)
- return CMI_NETFAIL;
- inp->sin_addr = *(struct in_addr *)hp->h_addr;
- }
- }
- return status;
-}
diff --git a/sr_unix_gnp/cmj_setupfd.c b/sr_unix_gnp/cmj_setupfd.c
index d1c1c93..d5c3282 100644
--- a/sr_unix_gnp/cmj_setupfd.c
+++ b/sr_unix_gnp/cmj_setupfd.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -17,9 +17,6 @@
#endif
#include <sys/ioctl.h>
#include "gtm_inet.h"
-#ifndef __MVS__
-#include <netinet/tcp.h>
-#endif
#include <errno.h>
#include "eintr_wrappers.h"
diff --git a/sr_unix_gnp/cmu_getclb.c b/sr_unix_gnp/cmu_getclb.c
index b4931ed..df020c3 100644
--- a/sr_unix_gnp/cmu_getclb.c
+++ b/sr_unix_gnp/cmu_getclb.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -13,19 +13,25 @@
#include "cmidef.h"
#include "gtm_string.h"
#include "eintr_wrappers.h"
+#include "gtm_netdb.h"
+#include "gtm_socket.h"
+#include "iotcpdef.h"
GBLREF struct NTD *ntd_root;
+error_def(ERR_GETNAMEINFO);
+error_def(ERR_TEXT);
+
struct CLB *cmu_getclb(cmi_descriptor *node, cmi_descriptor *task)
{
cmi_status_t status;
struct CLB *p;
que_ent_ptr_t qp;
sigset_t oset;
- struct sockaddr_in in;
+ struct addrinfo *ai_ptr;
int rc;
- status = cmj_resolve_nod_tnd(node, task, &in);
+ status = cmj_getsockaddr(node, task, &ai_ptr);
if (CMI_ERROR(status))
return NULL;
@@ -36,9 +42,8 @@ struct CLB *cmu_getclb(cmi_descriptor *node, cmi_descriptor *task)
qp = RELQUE2PTR(p->cqe.fl))
{
p = QUEENT2CLB(qp, cqe);
- if (p->peer.sin_port == in.sin_port && 0 == memcmp(&p->peer.sin_addr, &in.sin_addr, SIZEOF(in.sin_addr)))
- { /* (port, address) pair is necessary and sufficient for uniqueness. There might be other fields in
- sockaddr_in that might be implementation dependent. So, compare only (port, address) pair. */
+ if (0 == memcpy(ai_ptr->ai_addr, (sockaddr_ptr)(&p->peer_sas), ai_ptr->ai_addrlen))
+ {
sigprocmask(SIG_SETMASK, &oset, NULL);
return p;
}
diff --git a/sr_unix_gnp/gtcm_gnp_pktdmp.c b/sr_unix_gnp/gtcm_gnp_pktdmp.c
index aa59741..b8d78e3 100644
--- a/sr_unix_gnp/gtcm_gnp_pktdmp.c
+++ b/sr_unix_gnp/gtcm_gnp_pktdmp.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -78,7 +78,7 @@ void gtcm_gnp_pktdmp(FILE *fp, struct CLB *lnk, int sta, unsigned char *buf, siz
}
chr = buf;
ctim = time(NULL);
- ltime = localtime(&ctim);
+ GTM_LOCALTIME(ltime, &ctim);
FPRINTF(fp, "%04d%02d%02d%02d%02d%02d (%s) %s length %d\n",
ltime->tm_year+1900, ltime->tm_mon + 1, ltime->tm_mday,
ltime->tm_hour,ltime->tm_min, ltime->tm_sec, op, msg, count);
diff --git a/sr_unix_gnp/gtcm_gnp_server.c b/sr_unix_gnp/gtcm_gnp_server.c
index 266e642..45f4c0f 100644
--- a/sr_unix_gnp/gtcm_gnp_server.c
+++ b/sr_unix_gnp/gtcm_gnp_server.c
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -88,6 +88,7 @@
# include "gtm_utf8.h"
#endif
#include "continue_handler.h"
+#include "have_crit.h"
#ifdef __osf__
# pragma pointer_size (save)
diff --git a/sr_unix_gnp/libcmisockettcp.list b/sr_unix_gnp/libcmisockettcp.list
index 23eab73..338a50b 100644
--- a/sr_unix_gnp/libcmisockettcp.list
+++ b/sr_unix_gnp/libcmisockettcp.list
@@ -24,7 +24,6 @@ cmj_init_clb
cmj_netinit
cmj_postevent
cmj_read
-cmj_resolve_nod_tnd
cmj_select
cmj_setupfd
cmj_unit2clb
diff --git a/sr_unix_nsb/opcode_def.h b/sr_unix_nsb/opcode_def.h
index 0e3a8ed..2265270 100644
--- a/sr_unix_nsb/opcode_def.h
+++ b/sr_unix_nsb/opcode_def.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -338,3 +338,6 @@ OPCODE_DEF(OC_RFRSHGVN, (OCT_NULL))
OPCODE_DEF(OC_INDFNNAME2, (OCT_MVAL | OCT_EXPRLEAF))
OPCODE_DEF(OC_INDGET2, (OCT_MVAL | OCT_EXPRLEAF))
OPCODE_DEF(OC_INDMERGE2, (OCT_NULL))
+OPCODE_DEF(OC_LITC, (OCT_MVAL | OCT_EXPRLEAF))
+OPCODE_DEF(OC_STOLITC, (OCT_NULL))
+OPCODE_DEF(OC_FNZPEEK, (OCT_MVAL | OCT_EXPRLEAF))
diff --git a/sr_unix_nsb/rtnhdr.h b/sr_unix_nsb/rtnhdr.h
index eceb80f..b341116 100644
--- a/sr_unix_nsb/rtnhdr.h
+++ b/sr_unix_nsb/rtnhdr.h
@@ -1,6 +1,6 @@
/****************************************************************
* *
- * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
* *
* This source code contains the intellectual property *
* of its copyright holder(s), and is made available *
@@ -129,6 +129,9 @@ typedef struct
#define CODE_BASE_ADDR(rtnhdr) ((unsigned char *)(rtnhdr))
#define CODE_OFFSET(rtnhdr, addr) ((char *)(addr) - (char *)(rtnhdr))
+#define DYNAMIC_LITERALS_ENABLED(rtnhdr) FALSE
+#define RW_REL_START_ADR(rtnhdr) ((char *)LITERAL_ADR(rtnhdr))
+
/* Flag values for get_src_line call */
#define VERIFY TRUE
#define NOVERIFY FALSE
diff --git a/sr_unix_nsb/ttt.txt b/sr_unix_nsb/ttt.txt
index 66a79af..a9d35e6 100644
--- a/sr_unix_nsb/ttt.txt
+++ b/sr_unix_nsb/ttt.txt
@@ -1,6 +1,6 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ;
-; Copyright 2001, 2012 Fidelity Information Services, Inc ;
+; Copyright 2001, 2013 Fidelity Information Services, Inc ;
; ;
; This source code contains the intellectual property ;
; of its copyright holder(s), and is made available ;
@@ -1008,3 +1008,9 @@ OC_INDGET2: pushab val.1
calls #2,xfer.xf_indget2
OC_INDMERGE2: pushab val.1
calls #1,xfer.xf_indmerge2
+OC_FNZPEEK: pushab val.0
+ pushab val.4
+ pushl val.3
+ pushl val.2
+ pushab val.1
+ calls #5,xfer.xf_fnzpeek
diff --git a/sr_vms_cm/gtcm_ch.c b/sr_vms_cm/gtcm_ch.c
new file mode 100644
index 0000000..51b41d0
--- /dev/null
+++ b/sr_vms_cm/gtcm_ch.c
@@ -0,0 +1,381 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "error.h"
+
+#include <descrip.h>
+#include <rms.h>
+#include <opcdef.h>
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "cmidef.h"
+#include "hashtab_mname.h" /* needed for cmmdef.h */
+#include "cmmdef.h"
+
+typedef struct {
+ char req_code;
+ char target[3];
+ int4 mess_code;
+ char text[255];
+}oper_msg_struct;
+
+#define MESSAGE_HDR_LEN 15
+
+error_def(ERR_GVUNDEF);
+error_def(ERR_SERVERERR);
+
+GBLDEF bool gtcm_errfile=FALSE;
+GBLDEF struct FAB gtcm_errfab;
+GBLDEF struct RAB gtcm_errrab;
+GBLDEF bool gtcm_firsterr=TRUE;
+
+GBLREF connection_struct *curr_entry;
+GBLREF bool undef_inhibit;
+
+CONDITION_HANDLER(gtcm_ch)
+{
+ bool first;
+ int prev_count,count;
+ uint4 stat;
+ int i;
+ oper_msg_struct oper_msg;
+ bool severe;
+ unsigned short faolen,severe_len;
+ char outadr[4];
+ char *ptr,*end, *tempptr, *buffptr;
+ uint4 flags, len, *argptr;
+ unsigned short msg_len;
+ uint4 *c;
+ char buff[512],buff1[512],buff2[512],tempbuf[2048];
+ cmi_descriptor *tempdesc,*tempdesc1;
+ void gtcm_write_ast(), preemptive_db_clnup(int);
+ char errout[259],errbuff[300];
+ char filename[]="SYS$MANAGER:CMERR.LOG";
+/* char filename[]="SYS$LOGIN:CMERR.LOG"; not defined by run/det */
+ $DESCRIPTOR(msg,buff);
+ $DESCRIPTOR(msg2,buff2);
+ $DESCRIPTOR(err1,errout);
+ $DESCRIPTOR(out,"");
+ $DESCRIPTOR(out1,"");
+
+ undef_inhibit = FALSE; /* reset undef_inhibit to the default value in case it got reset temporarily and there was an error.
+ * currently, only $INCREMENT temporarily resets this (in gtcmtr_increment.c)
+ */
+ severe = SEVERITY >= 4; /* a severe error */
+ preemptive_db_clnup(SEVERITY);
+ if (gtcm_firsterr) /* open error logging file */
+ { gtcm_errfab = cc$rms_fab;
+ gtcm_errrab = cc$rms_rab;
+ gtcm_errrab.rab$l_fab = >cm_errfab;
+ gtcm_errrab.rab$l_rop = RAB$M_WBH;
+ gtcm_errfab.fab$b_fns = SIZEOF(filename);
+ gtcm_errfab.fab$l_fna = filename;
+ gtcm_errfab.fab$b_shr = FAB$M_SHRGET | FAB$M_UPI;
+ gtcm_errfab.fab$l_fop = FAB$M_MXV | FAB$M_CBT;
+ gtcm_errfab.fab$b_fac = FAB$M_PUT;
+ gtcm_errfab.fab$b_rat = FAB$M_CR;
+ stat = sys$create(>cm_errfab);
+ if (stat & 1)
+ { stat = sys$connect(>cm_errrab);
+ if (stat == RMS$_NORMAL)
+ { gtcm_errfile = TRUE;
+ }
+ }
+ gtcm_firsterr = FALSE;
+ }
+ if (curr_entry)
+ { ptr = curr_entry->clb_ptr->mbf;
+ end = ptr + curr_entry->clb_ptr->mbl;
+ }else
+ { ptr = &tempbuf[0];
+ end = &tempbuf[2047];
+ }
+ argptr = &SIGNAL;
+ *ptr++ = CMMS_E_ERROR;
+ *ptr++ = 0;
+ *ptr++ = sig->chf$l_sig_args - 2; /* discount exception pc and psl */
+ flags = 15;
+ buffptr = &buff1[0];
+ prev_count = 0;
+ for (count = 0; count < sig->chf$l_sig_args - 2;)
+ { count++;
+ msg_len = 0;
+ msg.dsc$w_length = 512;
+ sys$getmsg(*argptr,&msg_len,&msg,flags,outadr);
+ if ((gtcm_errfile || severe) && *argptr != 0)
+ { msg.dsc$w_length = msg_len;
+ out.dsc$w_length = 255;
+ out.dsc$a_pointer = &oper_msg.text[MESSAGE_HDR_LEN];
+ c = argptr + 1;
+ faolen = 0;
+ if (sig->chf$l_sig_args > 3)
+ { switch(*c)
+ {
+ case 0:
+ sys$fao(&msg, &faolen, &out);
+ break;
+ case 1:
+ sys$fao(&msg, &faolen, &out, *(c+1));
+ break;
+ case 2:
+ sys$fao(&msg, &faolen, &out, *(c+1), *(c+2));
+ break;
+ case 3:
+ sys$fao(&msg, &faolen, &out, *(c+1),*(c+2),*(c+3));
+ break;
+ case 4:
+ sys$fao(&msg, &faolen, &out, *(c+1),*(c+2),*(c+3),*(c+4));
+ break;
+ case 5:
+ sys$fao(&msg, &faolen, &out, *(c+1),*(c+2),*(c+3),*(c+4),*(c+5));
+ break;
+ case 6:
+ sys$fao(&msg, &faolen, &out, *(c+1),*(c+2),*(c+3),*(c+4),*(c+5),*(c+6));
+ break;
+ }
+ }else
+ { sys$fao(&msg, &faolen, &out);
+ }
+ severe_len = faolen;
+ if (gtcm_errfile)
+ { memcpy(errout,"!%D ",4);
+ memcpy(errout + 4,&oper_msg.text[MESSAGE_HDR_LEN],faolen);
+ err1.dsc$w_length = faolen + 4;
+ out1.dsc$w_length = 300;
+ out1.dsc$a_pointer = &errbuff[0];
+ sys$fao(&err1, &faolen, &out1, 0);
+ gtcm_errrab.rab$w_rsz = faolen;
+ gtcm_errrab.rab$l_rbf = errbuff;
+ sys$put(>cm_errrab);
+ sys$flush(>cm_errrab);
+ }
+ /* Special case severe errors, because they will cause the GT.CM process to halt when they
+ are signalled if they are sent normally. Create ascii string of error and signal
+ with SERVERERR. Also signal severe errors to operators.
+ */
+
+ if (severe)
+ { memcpy(&oper_msg.text[0],"GT.CM SERVER: ",MESSAGE_HDR_LEN);
+ msg2.dsc$a_pointer = &oper_msg;
+ msg2.dsc$w_length = severe_len + 8 + MESSAGE_HDR_LEN;
+ oper_msg.req_code = OPC$_RQ_RQST;
+ *oper_msg.target = OPC$M_NM_CENTRL | OPC$M_NM_DEVICE | OPC$M_NM_DISKS;
+ sys$sndopr(&msg2,0);
+ ptr--;
+ *ptr++ = 4;
+ *ptr++ = 'L';
+ *(int4*)ptr = ERR_SERVERERR;
+ ptr += SIZEOF(int4);
+ *ptr++ = 'L';
+ *(int4*)ptr = 2;
+ ptr += SIZEOF(int4);
+ *ptr++ = 'L';
+ *(int4*)ptr = severe_len;
+ ptr += SIZEOF(int4);
+ *ptr++ = 'A';
+ *(short*)ptr = severe_len;
+ ptr += SIZEOF(short);
+ memcpy(ptr,&oper_msg.text[MESSAGE_HDR_LEN],severe_len);
+ ptr += faolen;
+ break; /* skip further processing for severe errors */
+ }
+ }
+
+ /* Mark this argument as the first argument after a signal. If there are fao parameters
+ in the message, then this argument will be count, otherwise, it will be the next signal.
+ */
+ first = TRUE;
+ if (end - ptr < SIZEOF(int4) + 1) /* need second buff, write out first one */
+ { if (curr_entry)
+ { curr_entry->clb_ptr->cbl = (unsigned char *)ptr - curr_entry->clb_ptr->mbf;
+ curr_entry->clb_ptr->ast = 0;
+ tempptr = curr_entry->clb_ptr->mbf + 1;
+ *tempptr++ = 1;
+ *tempptr = count - prev_count;
+ prev_count = count;
+ cmi_write(curr_entry->clb_ptr);
+ ptr = curr_entry->clb_ptr->mbf;
+ *ptr++ = CMMS_E_ERROR;
+ *ptr++ = 0;
+ *ptr++ = sig->chf$l_sig_args - 2 - count;
+ }else
+ { ptr = &tempbuf[0];
+ }
+ }
+ *ptr++ = 'L';
+ *(int4*)ptr = *argptr++;
+ ptr += SIZEOF(int4);
+ for (i = 0; i < msg_len;)
+ { if (buff[i++] == '!')
+ { if (buff[i] == 'A') /* ascii */
+ { if (first)
+ { first = FALSE; /* fao count */
+ if (end - ptr < SIZEOF(int4) + 1) /* need second buff, write out first one */
+ { if (curr_entry)
+ { curr_entry->clb_ptr->cbl = (unsigned char *)ptr
+ - curr_entry->clb_ptr->mbf;
+ curr_entry->clb_ptr->ast = 0;
+ tempptr = curr_entry->clb_ptr->mbf + 1;
+ *tempptr++ = 1;
+ *tempptr = count - prev_count;
+ prev_count = count;
+ cmi_write(curr_entry->clb_ptr);
+ ptr = curr_entry->clb_ptr->mbf;
+ *ptr++ = CMMS_E_ERROR;
+ *ptr++ = 0;
+ *ptr++ = sig->chf$l_sig_args - 2 - count;
+ }else
+ { ptr = &tempbuf[0];
+ }
+ }
+ *ptr++ = 'L';
+ count++;
+ *(int4*)ptr = *argptr++;
+ ptr += SIZEOF(int4);
+ }
+ if (buff[++i] == 'S') /* descriptor */
+ { *buffptr++ = 'D';
+ tempptr = buffptr;
+ buffptr += SIZEOF(short);
+ tempdesc = buffptr;
+ tempdesc1 = *argptr++;
+ *tempdesc = *tempdesc1;
+ tempdesc->dsc$a_pointer = 0;
+ buffptr += SIZEOF(cmi_descriptor);
+ memcpy(buffptr,tempdesc1->dsc$a_pointer, tempdesc1->dsc$w_length);
+ buffptr += tempdesc1->dsc$w_length;
+ *(short*)tempptr = buffptr - tempptr - 2;
+ }else if (buff[i] == 'D') /* string */
+ { if (end - ptr < SIZEOF(int4) + 1) /* need second buff, write out first one */
+ { if (curr_entry)
+ { curr_entry->clb_ptr->cbl = (unsigned char *)ptr
+ - curr_entry->clb_ptr->mbf;
+ curr_entry->clb_ptr->ast = 0;
+ tempptr = curr_entry->clb_ptr->mbf + 1;
+ *tempptr++ = 1;
+ *tempptr = count - prev_count;
+ prev_count = count;
+ cmi_write(curr_entry->clb_ptr);
+ ptr = curr_entry->clb_ptr->mbf;
+ *ptr++ = CMMS_E_ERROR;
+ *ptr++ = 0;
+ *ptr++ = sig->chf$l_sig_args - 2 - count;
+ }else
+ { ptr = &tempbuf[0];
+ }
+ }
+ *ptr++ = 'L';
+ len = *argptr++;
+ *(int4*)ptr = len;
+ ptr += SIZEOF(int4);
+ count++;
+ *buffptr++ = 'A';
+ *(short*)buffptr = len;
+ buffptr += 2;
+ tempptr = *argptr++;
+ memcpy(buffptr, tempptr, len);
+ buffptr += len;
+ }else if (buff[i] == 'C') /* counted string */
+ { *buffptr++ = 'C';
+ tempptr = *argptr++;
+ memcpy(buffptr,tempptr, *tempptr);
+ buffptr += *tempptr;
+ }
+ if (curr_entry && (end - ptr < buffptr - &buff1[0]))
+ {
+ curr_entry->clb_ptr->cbl = (unsigned char *)ptr - curr_entry->clb_ptr->mbf;
+ curr_entry->clb_ptr->ast = 0;
+ tempptr = curr_entry->clb_ptr->mbf + 1;
+ *tempptr++ = 1;
+ *tempptr = count - prev_count;
+ prev_count = count;
+ cmi_write(curr_entry->clb_ptr);
+ ptr = curr_entry->clb_ptr->mbf;
+ *ptr++ = CMMS_E_ERROR;
+ *ptr++ = 0;
+ *ptr++ = sig->chf$l_sig_args - 2 - count;
+ }
+ else if (NULL == curr_entry)
+ ptr = &tempbuf[0];
+ memcpy(ptr,&buff1[0],buffptr - &buff1[0]);
+ ptr += buffptr - &buff1[0];
+ buffptr = &buff1[0];
+ count++;
+ }else if (buff[i + 1] == 'L') /* a longword */
+ { if(buff[i] == 'U' || buff[i] == 'X' || buff[i] == 'S')
+ { if (first)
+ { first = FALSE;
+ if (end - ptr < SIZEOF(int4) + 1)/* need second buff, write out first one */
+ { if (curr_entry)
+ { curr_entry->clb_ptr->cbl = (unsigned char *)ptr
+ - curr_entry->clb_ptr->mbf;
+ curr_entry->clb_ptr->ast = 0;
+ tempptr = curr_entry->clb_ptr->mbf + 1;
+ *tempptr++ = 1;
+ *tempptr = count - prev_count;
+ prev_count = count;
+ cmi_write(curr_entry->clb_ptr);
+ ptr = curr_entry->clb_ptr->mbf;
+ *ptr++ = CMMS_E_ERROR;
+ *ptr++ = 0;
+ *ptr++ = sig->chf$l_sig_args - 2 - count;
+ }else
+ { ptr = &tempbuf[0];
+ }
+ }
+ *ptr++ = 'L';
+ count++;
+ *(int4*)ptr = *argptr++;
+ ptr += SIZEOF(int4);
+ }
+ if (end - ptr < SIZEOF(int4) + 1) /* need second buff, write out first one */
+ { if (curr_entry)
+ { curr_entry->clb_ptr->cbl = (unsigned char *)ptr
+ - curr_entry->clb_ptr->mbf;
+ curr_entry->clb_ptr->ast = 0;
+ tempptr = curr_entry->clb_ptr->mbf + 1;
+ *tempptr++ = 1;
+ *tempptr = count - prev_count;
+ prev_count = count;
+ cmi_write(curr_entry->clb_ptr);
+ ptr = curr_entry->clb_ptr->mbf;
+ *ptr++ = CMMS_E_ERROR;
+ *ptr++ = 0;
+ *ptr++ = sig->chf$l_sig_args - 2 - count;
+ }else
+ { ptr = &tempbuf[0];
+ }
+ }
+ *ptr++ = 'L';
+ count++;
+ *(int4*)ptr = *argptr++;
+ ptr += SIZEOF(int4);
+ }
+ }
+ }
+ }
+ }
+ if (curr_entry && (ptr > curr_entry->clb_ptr->mbf + 3)) /* unwritten message in buffer */
+ { curr_entry->clb_ptr->cbl = (unsigned char *)ptr - curr_entry->clb_ptr->mbf;
+ curr_entry->clb_ptr->ast = gtcm_write_ast;
+ cmi_write(curr_entry->clb_ptr);
+ }
+ if (severe)
+ lib$signal(SIGNAL);
+ mch->CHF_MCH_SAVR0 = CM_NOOP; /* return NOOP, so that nothing more is done */
+ if ((stat = sys$unwind(&mch->CHF_MCH_DEPTH, 0)) != SS$_NORMAL)
+ NEXTCH;
+}
diff --git a/sr_vms_cm/gtcm_exi_ch.c b/sr_vms_cm/gtcm_exi_ch.c
new file mode 100644
index 0000000..f38cad2
--- /dev/null
+++ b/sr_vms_cm/gtcm_exi_ch.c
@@ -0,0 +1,124 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <descrip.h>
+#include <rms.h>
+#include <opcdef.h>
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "cmidef.h"
+#include "hashtab_mname.h" /* needed for cmmdef.h */
+#include "cmmdef.h"
+#include "error.h"
+
+typedef struct {
+ char req_code;
+ char target[3];
+ int4 mess_code;
+ char text[255];
+}oper_msg_struct;
+
+#define MESSAGE_HDR_LEN 32 /* length of rundownerr string */
+
+GBLREF bool gtcm_errfile;
+GBLREF struct FAB gtcm_errfab;
+GBLREF struct RAB gtcm_errrab;
+GBLREF int4 gtcm_exi_condition;
+GBLREF int4 process_id;
+
+CONDITION_HANDLER(gtcm_exi_ch)
+{
+ static readonly char filename[] = "SYS$MANAGER:CMEXIT.LOG";
+ static readonly char rundownerr[] = "GTCM TERMINATION RUNDOWN ERROR :";
+ char buff[512], buff2[512], errout[259], errbuff[300], outadr[4];
+ unsigned short faolen, msg_len, severe_len;
+ uint4 *argptr, *a_ptr, flags = 0, stat;
+ oper_msg_struct oper_msg;
+
+ $DESCRIPTOR(msg, buff);
+ $DESCRIPTOR(msg2, buff2);
+ $DESCRIPTOR(err1, errout);
+ $DESCRIPTOR(out, "");
+ $DESCRIPTOR(out1, "");
+
+ if (!gtcm_errfile) /* open error logging file */
+ { gtcm_errfab = cc$rms_fab;
+ gtcm_errrab = cc$rms_rab;
+ gtcm_errrab.rab$l_fab = >cm_errfab;
+ gtcm_errrab.rab$l_rop = RAB$M_WBH;
+ gtcm_errfab.fab$b_fns = SIZEOF(filename);
+ gtcm_errfab.fab$l_fna = filename;
+ gtcm_errfab.fab$b_shr = FAB$M_SHRGET | FAB$M_UPI;
+ gtcm_errfab.fab$l_fop = FAB$M_MXV | FAB$M_CBT;
+ gtcm_errfab.fab$b_fac = FAB$M_PUT;
+ gtcm_errfab.fab$b_rat = FAB$M_CR;
+ stat = sys$create(>cm_errfab);
+ if (stat & 1)
+ { stat = sys$connect(>cm_errrab);
+ if (RMS$_NORMAL == stat)
+ gtcm_errfile = TRUE;
+ }
+ }
+ argptr = &SIGNAL;
+ sys$getmsg(*argptr, &msg_len, &msg, flags, outadr);
+ msg.dsc$w_length = msg_len;
+ out.dsc$w_length = SIZEOF(oper_msg.text) - MESSAGE_HDR_LEN;
+ out.dsc$a_pointer = &oper_msg.text[MESSAGE_HDR_LEN];
+ a_ptr = argptr + 1;
+ faolen = 0;
+ if (sig->chf$l_sig_args > 3)
+ { switch(*a_ptr)
+ {
+ case 0: sys$fao(&msg, &faolen, &out);
+ break;
+ case 1: sys$fao(&msg, &faolen, &out, *(a_ptr+1));
+ break;
+ case 2: sys$fao(&msg, &faolen, &out, *(a_ptr+1), *(a_ptr+2));
+ break;
+ case 3: sys$fao(&msg, &faolen, &out, *(a_ptr+1), *(a_ptr+2), *(a_ptr+3));
+ break;
+ case 4: sys$fao(&msg, &faolen, &out, *(a_ptr+1), *(a_ptr+2), *(a_ptr+3), *(a_ptr+4));
+ break;
+ case 5: sys$fao(&msg, &faolen, &out, *(a_ptr+1), *(a_ptr+2), *(a_ptr+3), *(a_ptr+4), *(a_ptr+5));
+ break;
+ case 6: sys$fao(&msg, &faolen, &out, *(a_ptr+1), *(a_ptr+2), *(a_ptr+3), *(a_ptr+4), *(a_ptr+5), *(a_ptr+6));
+ break;
+ }
+ } else
+ sys$fao(&msg, &faolen, &out);
+ severe_len = faolen;
+ if (gtcm_errfile)
+ { memcpy(errout, "!%D ", 4);
+ memcpy(errout + 4, &oper_msg.text[MESSAGE_HDR_LEN], faolen);
+ err1.dsc$w_length = faolen + 4;
+ out1.dsc$w_length = SIZEOF(errbuff);
+ out1.dsc$a_pointer = errbuff;
+ sys$fao(&err1, &faolen, &out1, 0);
+ gtcm_errrab.rab$w_rsz = faolen;
+ gtcm_errrab.rab$l_rbf = errbuff;
+ sys$put(>cm_errrab);
+ sys$flush(>cm_errrab);
+ }
+ memcpy(oper_msg.text, rundownerr, MESSAGE_HDR_LEN);
+ msg2.dsc$a_pointer = &oper_msg;
+ msg2.dsc$w_length = severe_len + 8 + MESSAGE_HDR_LEN;
+ oper_msg.req_code = OPC$_RQ_RQST;
+ *oper_msg.target = OPC$M_NM_CENTRL | OPC$M_NM_DEVICE | OPC$M_NM_DISKS;
+ sys$sndopr(&msg2, 0);
+ EXIT(gtcm_exi_condition);
+ NEXTCH;
+}
diff --git a/sr_vms_cm/gtcm_mbxread_ast.c b/sr_vms_cm/gtcm_mbxread_ast.c
new file mode 100644
index 0000000..7f72fcd
--- /dev/null
+++ b/sr_vms_cm/gtcm_mbxread_ast.c
@@ -0,0 +1,74 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2004 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "cmidef.h"
+#include "hashtab_mname.h" /* needed for cmmdef.h */
+#include "cmmdef.h"
+#include "msg.h"
+#include "gtcm_int_unpack.h"
+
+GBLREF relque action_que;
+GBLREF connection_struct *curr_entry;
+extern long gtcm_action_pending();
+
+gtcm_mbxread_ast(struct NTD *tsk)
+{
+
+ cm_mbx *mp;
+ unsigned char *msg;
+ unsigned short procnum;
+ struct CLB *tell;
+ connection_struct *cnx;
+ msgtype err;
+ unsigned char *transnum, *laflag;
+ error_def(CMERR_INVINTMSG);
+ struct CLB *gtcm_find_proc();
+ void gtcm_write_ast();
+
+ mp = tsk->mbx.dsc$a_pointer;
+ msg = &mp->text[0];
+ assert(*msg == CMMS_S_INTERRUPT);
+ msg++;
+ procnum = *((unsigned short *)msg)++;
+ tell = gtcm_find_proc(tsk,procnum);
+ assert (tell);
+
+ switch(*msg)
+ {
+ case CMMS_L_LKCANCEL:
+ laflag = transnum = msg + 1;
+ transnum++;
+ cnx = (connection_struct *) tell->usr;
+ if (curr_entry == cnx || gtcm_write_ast == tell->ast)
+ { /* store information till end of server loop or write done */
+ cnx->int_cancel.laflag = *laflag | 1; /* since laflag may be 0, x40, x80 */
+ cnx->int_cancel.transnum = *transnum;
+ }
+ else
+ { /* not curr_entry and not write pending */
+ cnx->lk_cancel = *transnum;
+ memcpy(tell->mbf,msg, S_HDRSIZE + S_LAFLAGSIZE + 1);
+ tell->cbl = S_HDRSIZE + S_LAFLAGSIZE + 1;
+ (void)gtcm_action_pending(cnx); /* checks if in queue already */
+ cnx->new_msg = FALSE;
+ sys$cantim(cnx,0);
+ }
+ break;
+ default:
+ err.arg_cnt = MID_MSG_SIZE;
+ err.new_opts = err.def_opts = 1;
+ err.msg_number = CMERR_INVINTMSG;
+ err.fp_cnt = 2;
+ sys$putmsg (&err, 0, 0, 0);
+ break;
+ }
+}
diff --git a/sr_vms_cm/gtcm_server.c b/sr_vms_cm/gtcm_server.c
new file mode 100644
index 0000000..d4aeaa7
--- /dev/null
+++ b/sr_vms_cm/gtcm_server.c
@@ -0,0 +1,369 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_limits.h"
+#include "gtm_inet.h"
+
+#include <descrip.h>
+#include <iodef.h>
+#include <ssdef.h>
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "mlkdef.h"
+#include "gdscc.h"
+#include "gt_timer.h"
+#include "cmidef.h"
+#include "hashtab_mname.h" /* needed for cmmdef.h */
+#include "cmmdef.h"
+#include "gtcmlkdef.h"
+#include "ladef.h"
+#include "stp_parms.h"
+#include "stringpool.h"
+#include "efn.h"
+#include "repl_msg.h"
+#include "gtmsource.h"
+#include "gtmimagename.h"
+#include "desblk.h" /* for desblk structure */
+#include "gtcmtr_protos.h"
+#include "trans_log_name.h"
+#include "get_page_size.h"
+#include "filestruct.h"
+#include "jnl.h"
+#include "gdskill.h"
+#include "buddy_list.h"
+#include "hashtab_int4.h" /* needed for tp.h */
+#include "tp.h"
+#include "init_secshr_addrs.h"
+#include "gtm_threadgbl_init.h"
+#include "gtm_env_init.h" /* for gtm_env_init() prototype */
+
+GBLDEF bool cm_timeout = FALSE;
+GBLDEF bool cm_shutdown = FALSE;
+GBLDEF unsigned short procnum;
+GBLDEF short gtcm_ast_avail;
+GBLDEF int gtcm_users = 0;
+GBLDEF int4 gtcm_exi_condition;
+GBLDEF connection_struct *curr_entry;
+GBLDEF relque ALIGN_QUAD action_que;
+GBLDEF desblk gtcm_exi_blk;
+GBLDEF struct CLB *proc_to_clb[USHRT_MAX + 1]; /* for index 0 */
+GBLDEF gd_region *action_que_dummy_reg;
+
+GBLREF short astq_dyn_avail;
+GBLREF bool licensed;
+GBLREF boolean_t run_time;
+GBLREF boolean_t gtcm_connection;
+GBLREF uint4 image_count;
+GBLREF int4 lkid, lid;
+GBLREF cm_lckblkreg *blkdlist;
+GBLREF gv_namehead *gv_target;
+GBLREF struct NTD *ntd_root;
+GBLREF spdesc rts_stringpool, stringpool;
+GBLREF boolean_t is_replicator;
+
+LITREF char cm_prd_name[];
+LITREF char cm_ver_name[];
+LITREF int4 cm_prd_len;
+LITREF int4 cm_ver_len;
+OS_PAGE_SIZE_DECLARE
+
+#define GTCM_AST_OVRHD 4 /* init ast, read/write overlap, mbx, safety */
+
+error_def(CMERR_CMINTQUE);
+error_def(CMERR_CMSYSSRV);
+error_def(ERR_BADGTMNETMSG);
+error_def(ERR_WILLEXPIRE);
+error_def(LP_NOCNFDB);
+error_def(LP_INVCSM);
+
+gtcm_server()
+{
+ static readonly int4 reptim[2] = {-100000, -1}; /* 10ms */
+ static readonly int4 wait[2] = {-1000000, -1}; /* 100ms */
+ void gtcm_ch(), gtcm_exi_handler(), gtcm_init_ast(), gtcm_int_unpack(), gtcm_mbxread_ast(),
+ gtcm_neterr(), gtcm_read_ast(), gtcm_remove_from_action_queue(), gtcm_shutdown_ast(), gtcm_write_ast(),
+ la_freedb();
+ bool gtcm_link_accept();
+ bool alid;
+ char buff[512];
+ char *h = NULL;
+ char *la_getdb();
+ char nbuff[256];
+ char *pak = NULL;
+ char reply;
+ unsigned short outlen;
+ int4 closewait[2] = {0, -1};
+ int4 inid = 0, mdl = 0, nid = 0, days = 0;
+ int4 lic_status;
+ int4 lic_x;
+ int4 lm_mdl_nid();
+ uint4 status;
+ int i, receive(), value;
+ mstr name1, name2;
+ gd_addr *get_next_gdr();
+ struct NTD *cmu_ntdroot();
+ connection_struct *prev_curr_entry;
+ struct dsc$descriptor_s dprd;
+ struct dsc$descriptor_s dver;
+ $DESCRIPTOR(node_name, nbuff);
+ $DESCRIPTOR(proc_name, "GTCM_SERVER");
+ $DESCRIPTOR(timout, buff);
+ DCL_THREADGBL_ACCESS;
+
+ GTM_THREADGBL_INIT;
+ assert(0 == EMPTY_QUEUE); /* check so dont need gdsfhead everywhere */
+ gtm_imagetype_init(GTCM_GNP_SERVER_IMAGE); /* Side-effect: Sets skip_dbtriggers to TRUE for non-trigger platforms */
+ gtm_env_init(); /* read in all environment variables */
+ get_page_size();
+ name1.addr = "GTCMSVRNAM";
+ name1.len = SIZEOF("GTCMSVRNAM") - 1;
+ status = trans_log_name(&name1, &name2, nbuff);
+ if (SS$_NORMAL == status)
+ {
+ proc_name.dsc$a_pointer = nbuff;
+ proc_name.dsc$w_length = node_name.dsc$w_length = name2.len;
+ } else if (SS$_NOLOGNAM == status)
+ {
+ MEMCPY_LIT(nbuff, "GTCMSVR");
+ node_name.dsc$w_length = SIZEOF("GTCMSVR") - 1;
+ } else
+ rts_error(VARLSTCNT(1) status);
+ sys$setprn(&proc_name);
+ status = lib$get_foreign(&timout, 0, &outlen, 0);
+ if ((status & 1) && (6 > outlen))
+ {
+ for (i = 0; i < outlen; i++)
+ {
+ value = value * 10;
+ if (buff[i] <= '9' && buff[i] >= '0')
+ value += buff[i] - 48;
+ else
+ break;
+ }
+ if (outlen && (i == outlen))
+ {
+ cm_timeout = TRUE;
+ closewait[0] = value * -10000000;
+ }
+ }
+ dprd.dsc$w_length = cm_prd_len;
+ dprd.dsc$b_dtype = DSC$K_DTYPE_T;
+ dprd.dsc$b_class = DSC$K_CLASS_S;
+ dprd.dsc$a_pointer= cm_prd_name;
+ dver.dsc$w_length = cm_ver_len;
+ dver.dsc$b_dtype = DSC$K_DTYPE_T;
+ dver.dsc$b_class = DSC$K_CLASS_S;
+ dver.dsc$a_pointer= cm_ver_name;
+ getjobnum();
+ ast_init();
+ licensed = TRUE;
+ lkid = 2;
+# ifdef NOLICENSE
+ lid = 1;
+# else
+ /* this code used to be scattered to discourage reverse engineering, but since it now disabled, that seems pointless */
+ lic_status = ((NULL == (h = la_getdb(LMDB))) ? LP_NOCNFDB : SS$_NORMAL);
+ lic_status = ((1 == (lic_status & 1)) ? lm_mdl_nid(&mdl, &nid, &inid) : lic_status);
+ lic_status = ((1 == (lic_status & 1)) ? lp_licensed(h, &dprd, &dver, mdl, nid, &lid, &lic_x, &days, pak) : lic_status);
+ if (LP_NOCNFDB != lic_status)
+ la_freedb(h);
+ if (1 == (lic_status & 1))
+ {
+ licensed = TRUE;
+ if (days < 14)
+ rts_error(VARLSTCNT(1) ERR_WILLEXPIRE);
+ } else
+ {
+ licensed = FALSE;
+ sys$exit(lic_status);
+ }
+# endif
+ gtcm_ast_avail = astq_dyn_avail - GTCM_AST_OVRHD;
+ stp_init(STP_INITSIZE);
+ rts_stringpool = stringpool;
+ cache_init();
+ procnum = 0;
+ get_proc_info(0, TADR(login_time), &image_count);
+ memset(proc_to_clb, 0, SIZEOF(proc_to_clb));
+ status = cmi_init(&node_name, 0, 0, gtcm_init_ast, gtcm_link_accept);
+ if (!(status & 1))
+ {
+ rts_error(VARLSTCNT(1) ((status ^ 3) | 4));
+ sys$exit(status);
+ }
+ ntd_root = cmu_ntdroot();
+ ntd_root->mbx_ast = gtcm_mbxread_ast;
+ ntd_root->err = gtcm_neterr;
+ gtcm_connection = FALSE;
+ lib$establish(gtcm_ch);
+ gtcm_exi_blk.exit_hand = >cm_exi_handler;
+ gtcm_exi_blk.arg_cnt = 1;
+ gtcm_exi_blk.cond_val = >cm_exi_condition;
+ sys$dclexh(>cm_exi_blk);
+ INVOKE_INIT_SECSHR_ADDRS;
+ initialize_pattern_table();
+ assert(run_time); /* Should have been set by gtm_imagetype_init */
+ while (!cm_shutdown)
+ {
+ if (blkdlist)
+ gtcml_chkreg();
+
+ assert(!lib$ast_in_prog());
+ status = sys$dclast(>cm_remove_from_action_queue, 0, 0);
+ if (SS$_NORMAL != status)
+ rts_error(VARLSTCNT(4) CMERR_CMSYSSRV, 0, status, 0);
+ if (INTERLOCK_FAIL == curr_entry)
+ rts_error(VARLSTCNT(1) CMERR_CMINTQUE);
+ if (EMPTY_QUEUE != curr_entry)
+ {
+ switch (*curr_entry->clb_ptr->mbf)
+ {
+ case CMMS_L_LKCANALL:
+ reply = gtcmtr_lkcanall();
+ break;
+ case CMMS_L_LKCANCEL:
+ reply = gtcmtr_lkcancel();
+ break;
+ case CMMS_L_LKREQIMMED:
+ reply = gtcmtr_lkreqimmed();
+ break;
+ case CMMS_L_LKREQNODE:
+ reply = gtcmtr_lkreqnode();
+ break;
+ case CMMS_L_LKREQUEST:
+ reply = gtcmtr_lkrequest();
+ break;
+ case CMMS_L_LKRESUME:
+ reply = gtcmtr_lkresume();
+ break;
+ case CMMS_L_LKACQUIRE:
+ reply = gtcmtr_lkacquire();
+ break;
+ case CMMS_L_LKSUSPEND:
+ reply = gtcmtr_lksuspend();
+ break;
+ case CMMS_L_LKDELETE:
+ reply = gtcmtr_lkdelete();
+ break;
+ case CMMS_Q_DATA:
+ reply = gtcmtr_data();
+ break;
+ case CMMS_Q_GET:
+ reply = gtcmtr_get();
+ break;
+ case CMMS_Q_KILL:
+ reply = gtcmtr_kill();
+ break;
+ case CMMS_Q_ORDER:
+ reply = gtcmtr_order();
+ break;
+ case CMMS_Q_PREV:
+ reply = gtcmtr_zprevious();
+ break;
+ case CMMS_Q_PUT:
+ reply = gtcmtr_put();
+ break;
+ case CMMS_Q_QUERY:
+ reply = gtcmtr_query();
+ break;
+ case CMMS_Q_ZWITHDRAW:
+ reply = gtcmtr_zwithdraw();
+ break;
+ case CMMS_S_INITPROC:
+ reply = gtcmtr_initproc();
+ break;
+ case CMMS_S_INITREG:
+ reply = gtcmtr_initreg();
+ break;
+ case CMMS_S_TERMINATE:
+ reply = gtcmtr_terminate(TRUE);
+ break;
+ case CMMS_E_TERMINATE:
+ reply = gtcmtr_terminate(FALSE);
+ break;
+ case CMMS_U_LKEDELETE:
+ reply = gtcmtr_lke_clearrep(curr_entry->clb_ptr, curr_entry->clb_ptr->mbf);
+ break;
+ case CMMS_U_LKESHOW:
+ reply = gtcmtr_lke_showrep(curr_entry->clb_ptr, curr_entry->clb_ptr->mbf);
+ break;
+ case CMMS_B_BUFRESIZE:
+ reply = CM_WRITE;
+ value = *(unsigned short *)(curr_entry->clb_ptr->mbf + 1);
+ if (value > curr_entry->clb_ptr->mbl)
+ {
+ free(curr_entry->clb_ptr->mbf);
+ curr_entry->clb_ptr->mbf = malloc(value);
+ }
+ *curr_entry->clb_ptr->mbf = CMMS_C_BUFRESIZE;
+ curr_entry->clb_ptr->mbl = value;
+ curr_entry->clb_ptr->cbl = 1;
+ break;
+ case CMMS_B_BUFFLUSH:
+ reply = gtcmtr_bufflush();
+ break;
+ case CMMS_Q_INCREMENT:
+ reply = gtcmtr_increment();
+ break;
+ default:
+ reply = FALSE;
+ if (SS$_NORMAL == status)
+ rts_error(VARLSTCNT(3) ERR_BADGTMNETMSG, 1, (int)*curr_entry->clb_ptr->mbf);
+ break;
+ }
+ if (curr_entry) /* curr_entry can be NULL if went through gtcmtr_terminate */
+ {
+ status = sys$gettim(&curr_entry->lastact[0]);
+ if (SS$_NORMAL != status)
+ rts_error(VARLSTCNT(1) status);
+ /* curr_entry is used by gtcm_mbxread_ast to determine if it needs to defer the interrupt message */
+ prev_curr_entry = curr_entry;
+ if (CM_WRITE == reply)
+ { /* if ast == gtcm_write_ast, let it worry */
+ curr_entry->clb_ptr->ast = gtcm_write_ast;
+ curr_entry = EMPTY_QUEUE;
+ cmi_write(prev_curr_entry->clb_ptr);
+ } else
+ {
+ curr_entry = EMPTY_QUEUE;
+ if (1 == (prev_curr_entry->int_cancel.laflag & 1))
+ { /* valid interrupt cancel msg, handle in gtcm_mbxread_ast */
+ status = sys$dclast(gtcm_int_unpack, prev_curr_entry, 0);
+ if (SS$_NORMAL != status)
+ rts_error(VARLSTCNT(1) status);
+ } else if (CM_READ == reply)
+ {
+ prev_curr_entry->clb_ptr->ast = gtcm_read_ast;
+ cmi_read(prev_curr_entry->clb_ptr);
+ }
+ }
+ }
+ } else if (1 < astq_dyn_avail)
+ {
+# ifdef GTCM_REPTIM
+ /* if reptim is not needed - and smw doesn't know why it would be - remove this */
+ status = sys$schdwk(0, 0, &wait[0], &reptim[0]);
+# else
+ status = sys$schdwk(0, 0, &wait[0], 0);
+# endif
+ sys$hiber();
+ sys$canwak(0, 0);
+ }
+ if (cm_timeout && (0 == gtcm_users))
+ sys$setimr(efn_ignore, closewait, gtcm_shutdown_ast, &cm_shutdown, 0);
+ }
+}
diff --git a/sr_vms_cm/gtcmd_ini_reg.c b/sr_vms_cm/gtcmd_ini_reg.c
new file mode 100644
index 0000000..a404b6e
--- /dev/null
+++ b/sr_vms_cm/gtcmd_ini_reg.c
@@ -0,0 +1,130 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <rms.h>
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "cmidef.h"
+#include "hashtab_mname.h" /* needed for cmmdef.h */
+#include "cmmdef.h"
+#include <syidef.h>
+#include <efndef.h>
+
+#include "vmsdtype.h"
+
+typedef struct {
+ item_list_3 ilist;
+ int4 terminator;
+} syistruct;
+
+GBLREF cm_region_head *reglist;
+
+cm_region_head *gtcmd_ini_reg(connection_struct *cnx)
+{
+ cm_region_head *rh, *ptr, *last;
+ struct FAB tst;
+ struct NAM name;
+ unsigned char *fname,dummy[MAX_FN_LEN];
+ unsigned short len;
+ uint4 status;
+ unsigned short retlen;
+ char node[15];
+ syistruct syi_list;
+ short iosb[4];
+ gds_file_id dbid;
+ gd_region *gv_match();
+ file_control *file_cntl;
+
+ error_def (ERR_DBOPNERR);
+
+ ptr = 0;
+ fname = cnx->clb_ptr->mbf;
+ fname++;
+ len = *((unsigned short *) fname)++;
+ if (len > MAX_FN_LEN)
+ rts_error(VARLSTCNT(4) ERR_DBOPNERR, 2, len, fname);
+ tst = cc$rms_fab;
+ tst.fab$l_nam = &name;
+ name = cc$rms_nam;
+ name.nam$b_ess = MAX_FN_LEN;
+ name.nam$l_esa = dummy;
+ tst.fab$l_fna = fname;
+ tst.fab$b_fns = len;
+ status = sys$parse(&tst);
+ if (status != RMS$_NORMAL)
+ rts_error(VARLSTCNT(6) ERR_DBOPNERR, 2, len, fname, status, tst.fab$l_stv);
+ status = sys$search(&tst);
+ if (status != RMS$_NORMAL)
+ rts_error(VARLSTCNT(6) ERR_DBOPNERR, 2, len, fname, status, tst.fab$l_stv);
+ memcpy(dbid.dvi, name.nam$t_dvi, SIZEOF(name.nam$t_dvi));
+ memcpy(dbid.did, name.nam$w_did, SIZEOF(name.nam$w_did));
+ memcpy(dbid.fid, name.nam$w_fid, SIZEOF(name.nam$w_fid));
+ last = reglist;
+ for (ptr = reglist; ptr; ptr = ptr->next)
+ {
+ file_cntl = ptr->reg->dyn.addr->file_cntl;
+ if ((NULL != file_cntl) && (NULL != file_cntl->file_info)
+ && is_gdid_gdid_identical(&dbid, &((vms_gds_info *)file_cntl->file_info)->file_id))
+ break;
+ last = ptr;
+ }
+ /* All open regions should be stored in a manner accessible to stop processing in case of the server being VMS stopped */
+ if (!ptr)
+ { /* open region */
+ ptr = malloc(SIZEOF(*ptr));
+ ptr->next = 0;
+ ptr->last = 0;
+ ptr->head.fl = ptr->head.bl = 0;
+ if (last)
+ {
+ last->next = ptr;
+ ptr->last = last;
+ } else
+ reglist = ptr;
+ ptr->reg = malloc(SIZEOF(struct gd_region_struct) + SIZEOF(struct gd_segment_struct));
+ memset(ptr->reg, 0,SIZEOF(struct gd_region_struct) + SIZEOF(struct gd_segment_struct));
+ ptr->refcnt = 0;
+ ptr->reg->open = FALSE;
+ ptr->reg->dyn.addr = (unsigned char *) ptr->reg + SIZEOF(struct gd_region_struct);
+ ptr->reg->dyn.addr->acc_meth = dba_bg;
+ memcpy(ptr->reg->dyn.addr->fname,fname,len);
+ ptr->reg->dyn.addr->fname_len = len;
+ ptr->reg_hash = malloc(SIZEOF(hash_table_mname));
+ syi_list.ilist.buffer_length = SIZEOF(node);
+ syi_list.ilist.item_code = SYI$_NODENAME;
+ syi_list.ilist.buffer_address = node;
+ syi_list.ilist.return_length_address = &retlen;
+ syi_list.terminator = 0;
+ status = sys$getsyiw(EFN$C_ENF, 0, 0, &syi_list, &iosb[0], 0, 0);
+ if ((status & 1) && (iosb[0] & 1))
+ {
+ memcpy(ptr->reg->rname, node, retlen);
+ if (retlen < SIZEOF(node))
+ {
+ ptr->reg->rname[retlen] = ':';
+ if (retlen < (SIZEOF(node) - 1))
+ ptr->reg->rname[retlen + 1] = ':';
+ }
+ }
+ }
+ if (!ptr->reg->open)
+ {
+ ptr->wakeup = 0; /* Init EACH time (re)open region */
+ gtcmd_cst_init(ptr);
+ }
+ return ptr;
+}
diff --git a/sr_vms_cm/gvcmz_errmsg.c b/sr_vms_cm/gvcmz_errmsg.c
new file mode 100644
index 0000000..8de3ba0
--- /dev/null
+++ b/sr_vms_cm/gvcmz_errmsg.c
@@ -0,0 +1,131 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "cmidef.h"
+#include "hashtab_mname.h" /* needed for cmmdef.h */
+#include "cmmdef.h"
+
+gvcmz_errmsg(c,close)
+struct CLB *c;
+bool close;
+{
+ char *buf1,*buf2,*buf3,*ptr;
+ int i,j,x,count1,count2,count3;
+ int4 *msgbuf,*msgptr;
+ uint4 status;
+ cmi_descriptor *desc;
+
+ buf1 = c->mbf;
+ buf2 = buf3 = 0;
+ count2 = count3 = 0;
+ ptr = buf1 + 1;
+ if (*ptr)
+ { buf2 = malloc(c->mbl);
+ c->mbf = buf2;
+ status = cmi_read(c);
+ if ((status & 1) == 0)
+ { buf2 = 0;
+ count2 = 1;
+ goto signal;
+ }
+ if (*c->mbf != CMMS_E_ERROR)
+ { buf2 = 0;
+ count2 = 1;
+ goto signal;
+ }
+ ptr = buf2 + 1;
+ if (*ptr)
+ { buf3 = malloc(c->mbl);
+ c->mbf = buf3;
+ status = cmi_read(c);
+ if ((status & 1) == 0)
+ { buf3 = 0;
+ count3 = 1;
+ goto signal;
+ }
+ if (*c->mbf != CMMS_E_ERROR)
+ { buf3 = 0;
+ count3 = 1;
+ goto signal;
+ }
+ }
+ }
+ ptr = buf1 + 2;
+ count1 = *ptr++;
+ if (buf2)
+ { ptr = buf2 + 2;
+ count2 = *ptr;
+ if (buf3)
+ { ptr = buf3 + 2;
+ count3 = *ptr;
+ }
+ ptr = buf1 + 3;
+ }
+signal:
+ msgbuf = malloc((count1 + count2 + count3 + 1) * SIZEOF(int4));
+ msgptr = msgbuf;
+ *msgptr++ = count1 + count2 + count3;
+ x = count1;
+ for ( j = 0; ; j++)
+ { for ( i = 0; i < x ; i++)
+ { if (*ptr == 'L')
+ { ptr++;
+ *msgptr++ = *(int4 *)ptr;
+ ptr += SIZEOF(int4);
+ }else if (*ptr == 'Q')
+ { ptr++;
+ *msgptr++ = ptr;
+ ptr += 4 * SIZEOF(int4);
+ }else if (*ptr == 'C')
+ { ptr++;
+ *msgptr++ = ptr + 1;
+ ptr += 2 + *(short*)ptr;
+ }else if (*ptr == 'A')
+ { ptr++;
+ *msgptr++ = ptr + 2;
+ ptr += 2 + *(short*)ptr;
+ }else if (*ptr == 'D')
+ { desc = ptr + 1;
+ desc->dsc$a_pointer = ptr + SIZEOF(cmi_descriptor) + 1;
+ *msgptr++ = desc;
+ ptr += 1 + SIZEOF(cmi_descriptor) + desc->dsc$w_length;
+ }else
+ { if (j == 0)
+ *msgbuf = i;
+ else if (j == 1)
+ *msgbuf = i + count1;
+ else
+ *msgbuf = i + count1 + count2;
+ j = 2;
+ break;
+ }
+ }
+ if (j == 0 && buf2)
+ { x = count2;
+ ptr = buf2 + 3;
+ }else if (j == 1 && buf3)
+ { x = count3;
+ ptr = buf3 + 3;
+ }else
+ { break;
+ }
+ }
+ if (buf2)
+ free(buf2);
+ if (buf3)
+ free(buf3);
+ c->mbf = buf1;
+ if (close)
+ { gvcmy_close(c);
+ }
+ callg_signal(msgbuf);
+}
diff --git a/sr_vvms/append_time_stamp.c b/sr_vvms/append_time_stamp.c
new file mode 100644
index 0000000..e2a4880
--- /dev/null
+++ b/sr_vvms/append_time_stamp.c
@@ -0,0 +1,79 @@
+/****************************************************************
+ * *
+ * Copyright 2003, 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+#include "gtm_fcntl.h"
+
+#include <ssdef.h>
+#include <rms.h>
+#include <devdef.h>
+#include <descrip.h>
+#include <libdtdef.h>
+#include <libdef.h>
+#include <starlet.h>
+
+#include "iosp.h"
+#include "gtm_file_stat.h"
+#include "gtm_rename.h"
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsfhead.h"
+#include "gdscc.h"
+#include "filestruct.h"
+#include "jnl.h"
+
+#define YR_DIGIT_SIZE 4
+#define TIME_DIGIT_SIZE 6
+
+/* Append the formatted timestamp to the file name (fn); *fn_len contains the current length of the filename and at exit from this
+ * function, it is updated to reflect the new length.
+ */
+uint4 append_time_stamp(char *fn, int *fn_len, jnl_tm_t now)
+{
+ uint4 status1;
+ gtm_uint64_t whole_time;
+ char es_buffer[MAX_FN_LEN], name_buffer[MAX_FN_LEN];
+ char yr_arr[MAX_FN_LEN], yr_time_arr[MAX_FN_LEN], time_arr[MAX_FN_LEN];
+ char format_arr[MAX_FN_LEN], output_arr[MAX_FN_LEN];
+ short yr_len;
+ unsigned long days, context = 0;
+ long yearflag = LIB$K_OUTPUT_FORMAT;
+ long daysflag = LIB$K_DAY_OF_YEAR;
+ $DESCRIPTOR(yr_time_format, JNLSWITCH_TM_FMT);
+ $DESCRIPTOR(yr_time_str, yr_time_arr);
+
+ JNL_WHOLE_FROM_SHORT_TIME(whole_time, now);
+ if (LIB$_NORMAL != (status1 = lib$cvt_from_internal_time(&daysflag, &days, &whole_time))) /* Get julian date */
+ return status1;
+ if (SS$_NORMAL != (status1 = lib$init_date_time_context(&context, &yearflag, &yr_time_format)))
+ return status1;
+ yr_len = MAX_FN_LEN;
+ if (SS$_NORMAL != (status1 = lib$format_date_time(&yr_time_str, &whole_time, &context, &yr_len, 0))) /* get the year */
+ {
+ lib$free_date_time_context(&context);
+ return status1;
+ }
+ if (SS$_NORMAL != (status1 = lib$free_date_time_context(&context)))
+ return status1;
+ yr_time_arr[yr_len]='\0';
+ memcpy(yr_arr, yr_time_arr, YR_DIGIT_SIZE);
+ yr_arr[YR_DIGIT_SIZE] = '\0';
+ memcpy(time_arr, &yr_time_arr[YR_DIGIT_SIZE + 1], TIME_DIGIT_SIZE);
+ time_arr[TIME_DIGIT_SIZE] = '\0';
+ SPRINTF(fn + *fn_len, "_%s%d%s", yr_arr, days, time_arr);
+ *fn_len = strlen(fn);
+ return SS_NORMAL;
+}
diff --git a/sr_vvms/ast.h b/sr_vvms/ast.h
new file mode 100644
index 0000000..8a0e6f9
--- /dev/null
+++ b/sr_vvms/ast.h
@@ -0,0 +1,16 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#define ENABLE 1
+#define DISABLE 0
+
+#define ENABLE_AST sys$setast(ENABLE);
+#define DISABLE_AST sys$setast(DISABLE);
diff --git a/sr_vvms/ast_get_static.c b/sr_vvms/ast_get_static.c
new file mode 100644
index 0000000..7552979
--- /dev/null
+++ b/sr_vvms/ast_get_static.c
@@ -0,0 +1,38 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "efn.h"
+#include "timers.h"
+#include <ssdef.h>
+
+GBLREF short astq_dyn_alloc;
+GBLREF short astq_dyn_avail;
+GBLREF short astq_dyn_min;
+
+bool ast_get_static(needed)
+int needed;
+{
+ int4 pause[2];
+
+ if ((astq_dyn_alloc - needed) < astq_dyn_min)
+ return FALSE;
+ astq_dyn_alloc -= needed;
+ astq_dyn_avail -= needed;
+ pause[0] = TIM_AST_WAIT;
+ pause[1] = -1;
+ while (astq_dyn_avail < 0 )
+ { if (sys$setimr(efn_immed_wait, &pause, 0, 0, 0) == SS$_NORMAL)
+ { sys$synch(efn_immed_wait, 0);
+ }
+ };
+ return TRUE;
+}
diff --git a/sr_vvms/ast_init.c b/sr_vvms/ast_init.c
new file mode 100644
index 0000000..d67e42d
--- /dev/null
+++ b/sr_vvms/ast_init.c
@@ -0,0 +1,31 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <jpidef.h>
+#include "ast_init.h"
+
+#define MIN_DYN_ASTS 4
+
+GBLDEF short astq_dyn_avail;
+GBLDEF short astq_dyn_alloc;
+GBLDEF short astq_dyn_min;
+
+void ast_init(void)
+{
+int4 item, outv;
+
+ item = JPI$_ASTLM;
+ lib$getjpi(&item, 0, 0, &outv, 0, 0);
+ astq_dyn_alloc = astq_dyn_avail = outv;
+ astq_dyn_min = MIN_DYN_ASTS;
+ sys$setrwm(0); /* set resource wait mode, so will not create error if exceeded I/O limit */
+}
diff --git a/sr_vvms/ast_init.h b/sr_vvms/ast_init.h
new file mode 100644
index 0000000..b4d3425
--- /dev/null
+++ b/sr_vvms/ast_init.h
@@ -0,0 +1,17 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef AST_INIT_INCLUDED
+#define AST_INIT_INCLUDED
+
+void ast_init(void);
+
+#endif /* AST_INIT_INCLUDED */
diff --git a/sr_vvms/backup_buffer_flush.c b/sr_vvms/backup_buffer_flush.c
new file mode 100644
index 0000000..3f0623e
--- /dev/null
+++ b/sr_vvms/backup_buffer_flush.c
@@ -0,0 +1,170 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <rms.h>
+#include <iodef.h>
+#include "gtm_string.h"
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "efn.h"
+#include "util.h"
+#include "memcoherency.h"
+#include "sleep_cnt.h"
+#include "wcs_sleep.h"
+#include "iormdef.h"
+#include "shmpool.h"
+#include "gtmimagename.h"
+#include "mupipbckup.h"
+#include "send_msg.h"
+
+GBLREF int process_id;
+
+error_def(ERR_BKUPTMPFILOPEN);
+error_def(ERR_BKUPTMPFILWRITE);
+
+/* Return true if flush attempted, false if lock not obtained or other error */
+boolean_t backup_buffer_flush(gd_region *reg)
+{
+ int4 status, write_size, write_len, lcnt;
+ sgmnt_addrs *csa;
+ shmpool_buff_hdr_ptr_t sbufh_p;
+ shmpool_blk_hdr_ptr_t sblkh_p, next_sblkh_p;
+ boolean_t multiple_writes;
+ sm_uc_ptr_t write_ptr;
+
+ struct FAB fab;
+ struct NAM nam;
+ struct RAB rab;
+ VMS_ONLY(int flush_cnt);
+
+ csa = &FILE_INFO(reg)->s_addrs;
+ sbufh_p = csa->shmpool_buffer;
+
+ if (!shmpool_lock_hdr_nowait(reg))
+ {
+#ifdef DEBUG
+ /* someone else is flushing it right now */
+ if (!IS_GTM_IMAGE)
+ util_out_print("Process !12UL has the shmpool lock preventing backup buffer flush.",
+ TRUE, sbufh_p->shmpool_crit_latch.u.parts.latch_pid);
+#endif
+ return FALSE;
+ }
+
+
+ if (0 != sbufh_p->backup_errno)
+ { /* Since this is signal/mupip initiated, the proper message will be (or already has been) output on exit. */
+ shmpool_unlock_hdr(reg);
+ return FALSE; /* Async error state change (perhaps mupip stop) -- nothing to do if backup is dying */
+ }
+
+ /* See if there are any buffers needing flushing. Note that we are holding the shmpool lock across
+ the IO we will be doing. This simplifies the backup logic substantialy. If we released and obtained
+ the lock for each buffer we dequeue (to allow other processes to proceed while we are doing IO) it
+ is likely that some of those other processes would get the idea to also run a buffer flush. Then we
+ would have to manage the task of doing multiple simultaneous IO to the temporary file potentially
+ resulting in gaps in the file which is something we definitely do not want to do. Besides, if a backup
+ is going on (and thus causing the flush) we are likely doing this in crit which is holding up all
+ other processes anyway so we aren't losing much if anything. This is also historically how this
+ has been done to assure the robustness of the temporary file. SE 1/2005.
+ */
+ if (0 < sbufh_p->backup_cnt)
+ { /* open the file, write to it at the address and close the file */
+ fab = cc$rms_fab;
+ fab.fab$b_fac = FAB$M_PUT;
+ fab.fab$l_fna = sbufh_p->tempfilename;
+ fab.fab$b_fns = strlen(sbufh_p->tempfilename);
+ rab = cc$rms_rab;
+ rab.rab$l_fab = &fab;
+ rab.rab$l_rop = RAB$M_WBH | RAB$M_EOF;
+
+ for (lcnt = 1; MAX_OPEN_RETRY >= lcnt; lcnt++)
+ {
+ if (RMS$_FLK != (status = sys$open(&fab, NULL, NULL)))
+ break;
+ wcs_sleep(lcnt);
+ }
+
+ if ((RMS$_NORMAL != status) || (RMS$_NORMAL != (status = sys$connect(&rab))))
+ { /* Unable to open temporary file */
+ sbufh_p->backup_errno = status;
+ sbufh_p->failed = process_id;
+ csa->nl->nbb = BACKUP_NOT_IN_PROGRESS;
+ send_msg(VARLSTCNT(5) ERR_BKUPTMPFILOPEN, 2, LEN_AND_STR(sbufh_p->tempfilename), sbufh_p->backup_errno);
+ shmpool_unlock_hdr(reg);
+ return FALSE;
+ }
+
+ DEBUG_ONLY(flush_cnt = 0);
+ for (sblkh_p = SBLKP_REL2ABS(&sbufh_p->que_backup, fl);
+ sblkh_p != (shmpool_blk_hdr_ptr_t)&sbufh_p->que_backup;
+ sblkh_p = next_sblkh_p)
+ { /* Loop through the queued backup blocks */
+ DEBUG_ONLY(++flush_cnt);
+ VERIFY_QUEUE((que_head_ptr_t)&sbufh_p->que_free);
+ VERIFY_QUEUE((que_head_ptr_t)&sbufh_p->que_backup);
+ next_sblkh_p = SBLKP_REL2ABS(sblkh_p, fl); /* Get next offset now in case remove entry */
+ /* Need read fence for checking if block has valid data or not since these
+ fields are not set under lock */
+ SHM_READ_MEMORY_BARRIER;
+ assert(SHMBLK_BACKUP == sblkh_p->blktype);
+ if (!sblkh_p->valid_data)
+ continue;
+ assert(sbufh_p->blk_size >= ((blk_hdr_ptr_t)(sblkh_p + 1))->bsiz); /* Still validly sized blk? */
+ /* This block has valid data. Flush it first, then dequeue it. It won't hurt if this
+ process fails between the time that it starts the IO and it dequeues the block. The
+ worst that would happen is the block would be in the temporary file twice which, while
+ a little annoying is not functionally incorrect. If we dequeue it first though, there is
+ a possibility that the IO could be lost and an invalid block written to the temporary file
+ or missed altogether.
+ */
+ write_size = SIZEOF(*sblkh_p) + sbufh_p->blk_size; /* Assume write hdr/data in one block */
+ write_ptr = (sm_uc_ptr_t)sblkh_p;
+ while (write_size)
+ { /* Our block + hdr would exceed the 32K max. Write it in two writes as necessary. Since this
+ is standard buffered IO, this is not as big a deal as it could be hence we don't go
+ crazy with our own buffering scheme.
+ */
+ write_len = MIN(MAX_RMS_RECORDSIZE, write_size);
+ rab.rab$l_rbf = write_ptr;
+ rab.rab$w_rsz = write_len;
+ if (RMS$_NORMAL != (status = sys$put(&rab)))
+ {
+ sbufh_p->backup_errno = status;
+ sbufh_p->failed = process_id;
+ csa->nl->nbb = BACKUP_NOT_IN_PROGRESS;
+ send_msg(VARLSTCNT(5) ERR_BKUPTMPFILWRITE, 2, LEN_AND_STR(sbufh_p->tempfilename),
+ sbufh_p->backup_errno);
+ break;
+ }
+ write_ptr += write_len;
+ write_size -= write_len;
+ }
+ if (sbufh_p->backup_errno)
+ break;
+ /* Update disk addr with record just written */
+ sbufh_p->dskaddr += (SIZEOF(*sblkh_p) + sbufh_p->blk_size);
+ /* Now we can deque this entry from the backup queue safely and release it */
+ shmpool_blk_free(reg, sblkh_p);
+ }
+ sys$close(&fab);
+ }
+ shmpool_unlock_hdr(reg);
+ return TRUE;
+}
diff --git a/sr_vvms/bin_load.c b/sr_vvms/bin_load.c
new file mode 100644
index 0000000..cb9154c
--- /dev/null
+++ b/sr_vvms/bin_load.c
@@ -0,0 +1,510 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+#include "gtm_ctype.h"
+#include "gtm_stdlib.h"
+
+#include "stringpool.h"
+#include <rms.h>
+#include "iormdef.h"
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "msg.h"
+#include "muextr.h"
+#include "outofband.h"
+#include "collseq.h"
+#include "copy.h"
+#include "util.h"
+#include "op.h"
+#include "gvsub2str.h"
+#include "error.h"
+#include "mu_load_stat.h"
+#include "load.h"
+#include "mvalconv.h"
+#include "mu_gvis.h"
+#include "gtmmsg.h"
+
+#define CR 13
+#define LF 10
+#define LCL_BUF_SIZE 512
+#define FILLFACTOR_EXPONENT 10
+#define V3_STDNULLCOLL "00000" /* V3 denotes binary extract header version number (not GT.M version number) */
+
+GBLREF bool mu_ctrlc_occurred;
+GBLREF bool mu_ctrly_occurred;
+GBLREF bool mupip_DB_full;
+GBLREF bool mupip_error_occurred;
+GBLREF spdesc stringpool;
+GBLREF gv_key *gv_altkey;
+GBLREF gv_key *gv_currkey;
+GBLREF gd_region *gv_cur_region;
+GBLREF gd_addr *gd_header;
+GBLREF int4 gv_keysize;
+GBLREF gv_namehead *gv_target;
+
+error_def(ERR_BEGINST);
+error_def(ERR_BINHDR);
+error_def(ERR_BLKCNT);
+error_def(ERR_COLLTYPVERSION);
+error_def(ERR_COLLATIONUNDEF);
+error_def(ERR_CORRUPT);
+error_def(ERR_GVIS);
+error_def(ERR_LDBINFMT);
+error_def(ERR_LOADABORT);
+error_def(ERR_LOADCTRLY);
+error_def(ERR_LOADEOF);
+error_def(ERR_MUNOACTION);
+error_def(ERR_OLDBINEXTRACT);
+error_def(ERR_PREMATEOF);
+error_def(ERR_TEXT);
+
+/***********************************************************************************************/
+/* Binary Format */
+/***********************************************************************************************/
+
+/* starting extract file format 3, we have an extra record for each gvn, that contains the
+ * collation information of the database at the time of extract. This record is transparent
+ * to the user, so the semantics of the command line options, 'begin' and 'end' to MUPIP LOAD
+ * will remain same. The collation header is identified in the binary extract by the fact
+ * that its size is 4 bytes and no valid data record can have length 4.
+ */
+
+void bin_load(uint4 begin, uint4 end, struct RAB *inrab, struct FAB *infab)
+{
+
+ boolean_t need_xlation, new_gvn;
+ char *buff, std_null_coll[BIN_HEADER_NUMSZ + 1];
+ coll_hdr db_collhdr, extr_collhdr;
+ collseq *db_collseq, *extr_collseq, *save_gv_target_collseq;
+ gv_key *tmp_gvkey = NULL; /* null-initialize at start, will be malloced later */
+ int current, last, len, max_blk_siz, max_key, other_rsz, status, subsc_len;
+ msgtype msg;
+ mval tmp_mval, v;
+ rec_hdr *next_rp, *rp;
+ uint4 extr_std_null_coll, global_key_count, key_count, max_data_len, max_subsc_len, rec_count;
+ unsigned char *btop, *cp1, *cp2, *end_buff, *gvkey_char_ptr, hdr_lvl ,*tmp_ptr, *tmp_key_ptr,
+ cmpc_str[MAX_KEY_SZ + 1], dest_buff[MAX_ZWR_KEY_SZ], dup_key_str[MAX_KEY_SZ + 1], src_buff[MAX_KEY_SZ + 1];
+ unsigned short next_cmpc, rec_len;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ assert(4 == SIZEOF(coll_hdr));
+ inrab->rab$l_ubf = malloc(LCL_BUF_SIZE);
+ inrab->rab$w_usz = LCL_BUF_SIZE - 1;
+ max_data_len = max_subsc_len = key_count = 0;
+ rec_count = 1;
+ status = sys$get(inrab);
+ if (RMS$_EOF == status)
+ rts_error(VARLSTCNT(1) ERR_PREMATEOF);
+ if (!(status & 1))
+ rts_error(VARLSTCNT(1) status);
+ len = inrab->rab$w_rsz;
+ buff = inrab->rab$l_rbf;
+ while ((0 < len) && ((LF == buff[len - 1]) || (CR == buff[len - 1])))
+ len--;
+ /* expect the level can be represented in a single character */
+ assert(' ' == *(buff + SIZEOF(BIN_HEADER_LABEL) - 3));
+ hdr_lvl = EXTR_HEADER_LEVEL(buff);
+ if (0 != memcmp(buff, BIN_HEADER_LABEL, SIZEOF(BIN_HEADER_LABEL) - 2) || '2' > hdr_lvl
+ || *(BIN_HEADER_VERSION) < hdr_lvl)
+ { /* ignore the level check */
+ rts_error(VARLSTCNT(1) ERR_LDBINFMT);
+ return;
+ }
+ if ('3' < hdr_lvl)
+ {
+ memcpy(std_null_coll, buff + BIN_HEADER_NULLCOLLOFFSET, BIN_HEADER_NUMSZ);
+ std_null_coll[BIN_HEADER_NUMSZ] = '\0';
+ extr_std_null_coll = STRTOUL(std_null_coll, NULL, 10);
+ if (0 != extr_std_null_coll && 1!= extr_std_null_coll)
+ {
+ rts_error(VARLSTCNT(5) ERR_TEXT, 2, RTS_ERROR_TEXT("Corrupted null collation field in header"),
+ ERR_LDBINFMT);
+ return;
+ }
+ } else
+ {
+ memcpy(std_null_coll, V3_STDNULLCOLL, BIN_HEADER_NUMSZ);
+ assert(BIN_HEADER_NUMSZ == STR_LIT_LEN(V3_STDNULLCOLL));
+ std_null_coll[BIN_HEADER_NUMSZ] = '\0';
+ extr_std_null_coll = 0;
+ }
+ msg.arg_cnt = 18;
+ msg.new_opts = msg.def_opts = 1;
+ msg.msg_number = ERR_BINHDR;
+ msg.fp_cnt = 16;
+ msg.fp[0].n = SIZEOF(BIN_HEADER_LABEL) - 1;
+ msg.fp[1].cp = buff;
+ msg.fp[2].n = SIZEOF("YEARMMDD") - 1;
+ msg.fp[3].cp = buff + SIZEOF(BIN_HEADER_LABEL) - 1;
+ msg.fp[4].n = SIZEOF(BIN_HEADER_DATEFMT) - SIZEOF("YEARMMDD");
+ msg.fp[5].cp = buff + SIZEOF("YEARMMDD") + SIZEOF(BIN_HEADER_LABEL) - 2;
+ msg.fp[6].n = BIN_HEADER_NUMSZ;
+ msg.fp[7].cp = buff + BIN_HEADER_BLKOFFSET;
+ msg.fp[8].n = BIN_HEADER_NUMSZ;
+ msg.fp[9].cp = buff + BIN_HEADER_RECOFFSET;
+ msg.fp[10].n = BIN_HEADER_NUMSZ;
+ msg.fp[11].cp = buff + BIN_HEADER_KEYOFFSET;
+ msg.fp[12].n = BIN_HEADER_NUMSZ;
+ msg.fp[13].cp = &std_null_coll[0];
+ if (hdr_lvl > '3')
+ {
+ msg.fp[14].n = BIN_HEADER_SZ - (BIN_HEADER_NULLCOLLOFFSET + BIN_HEADER_NUMSZ);
+ msg.fp[15].cp = buff + BIN_HEADER_NULLCOLLOFFSET + BIN_HEADER_NUMSZ;
+ } else
+ {
+ msg.fp[14].n = V3_BIN_HEADER_SZ - (BIN_HEADER_KEYOFFSET + BIN_HEADER_NUMSZ);
+ msg.fp[15].cp = buff + BIN_HEADER_KEYOFFSET + BIN_HEADER_NUMSZ;
+ }
+ sys$putmsg(&msg, 0, 0, 0);
+ v.mvtype = MV_STR;
+ v.str.len = BIN_HEADER_NUMSZ;
+ v.str.addr = buff + BIN_HEADER_BLKOFFSET;
+ s2n(&v);
+ stringpool.free = stringpool.base;
+ max_blk_siz = MV_FORCE_INTD(&v);
+ assert(max_blk_siz > LCL_BUF_SIZE - 1);
+ infab->fab$w_mrs = max_blk_siz;
+ /* Note the buffer size below is the same as the blocksize but the extract data will not contain the block header.
+ * But rather than reduce the buffer by that amount we just leave it (somewhat) larger. Reason is beginning with V5
+ * we also accept V4 extracts which had a smaller block header so the real size is indeterminate and since the
+ * difference is only a few bytes, we leave the buffer size at the full blocksize. SE 4/2005
+ */
+ inrab->rab$w_usz = max_blk_siz;
+ free(inrab->rab$l_ubf);
+ inrab->rab$l_ubf = malloc(inrab->rab$w_usz);
+ v.mvtype = MV_STR;
+ rec_count++;
+ new_gvn = FALSE;
+ if ('2' < hdr_lvl)
+ {
+ status = sys$get(inrab);
+ if (RMS$_EOF == status)
+ rts_error(VARLSTCNT(1) ERR_PREMATEOF);
+ if (!(status & 1))
+ rts_error(VARLSTCNT(1) status);
+ if (SIZEOF(coll_hdr) != inrab->rab$w_rsz)
+ {
+ rts_error(VARLSTCNT(5) ERR_TEXT, 2, RTS_ERROR_TEXT("Corrupt collation header"), ERR_LDBINFMT);
+ return;
+ }
+ extr_collhdr = *((coll_hdr *)(inrab->rab$l_rbf));
+ new_gvn = TRUE;
+ } else
+ gtm_putmsg(VARLSTCNT(3) ERR_OLDBINEXTRACT, 1, hdr_lvl - '0');
+ if (begin < 2)
+ begin = 2;
+ for ( ; rec_count < begin; )
+ {
+ status = sys$get(inrab);
+ if (RMS$_EOF == status)
+ {
+ sys$close(infab);
+ gtm_putmsg(VARLSTCNT(3) ERR_LOADEOF, 1, begin);
+ mupip_exit(ERR_MUNOACTION);
+ }
+ if (RMS$_NORMAL != status)
+ rts_error(VARLSTCNT(1) status);
+ if (SIZEOF(coll_hdr) == inrab->rab$w_rsz)
+ {
+ assert(hdr_lvl > '2');
+ continue;
+ }
+ rec_count++;
+ }
+ msg.msg_number = ERR_BEGINST;
+ msg.arg_cnt = 3;
+ msg.fp_cnt = 1;
+ msg.fp[0].n = rec_count;
+ sys$putmsg(&msg, 0, 0, 0);
+ ESTABLISH(mupip_load_ch);
+ extr_collseq = db_collseq = NULL;
+ need_xlation = FALSE;
+ rec_count = begin - 1;
+ other_rsz = 0;
+ assert(NULL == tmp_gvkey); /* GVKEY_INIT macro relies on this */
+ GVKEY_INIT(tmp_gvkey, DBKEYSIZE(MAX_KEY_SZ)); /* tmp_gvkey will point to malloced memory after this */
+ for ( ; !mupip_DB_full; )
+ {
+ if (++rec_count > end)
+ break;
+ next_cmpc = 0;
+ mupip_error_occurred = FALSE;
+ if (mu_ctrly_occurred)
+ break;
+ if (mu_ctrlc_occurred)
+ {
+ mu_load_stat(max_data_len, max_subsc_len, key_count, key_count ? (rec_count - 1) : 0, ERR_BLKCNT);
+ mu_gvis();
+ util_out_print(0, TRUE);
+ }
+ /* reset the stringpool for every record in order to avoid garbage collection */
+ stringpool.free = stringpool.base;
+ if (other_rsz)
+ { /* read an extra block when it wasn't a tail, but rather a new record */
+ inrab->rab$w_rsz = other_rsz;
+ rp = inrab->rab$l_ubf + MAX_BIN_WRT;
+ btop = rp + other_rsz;
+ other_rsz = 0;
+ } else
+ {
+ if (RMS$_EOF == (status = sys$get(inrab)))
+ break;
+ if (RMS$_NORMAL != status)
+ {
+ lib$signal(status);
+ mupip_error_occurred = TRUE;
+ break;
+ }
+ assert((max_blk_siz >= inrab->rab$w_rsz) && (MAX_BIN_WRT >= inrab->rab$w_rsz));
+ rp = inrab->rab$l_rbf;
+ btop = inrab->rab$l_rbf + inrab->rab$w_rsz;
+ if (MAX_BIN_WRT == inrab->rab$w_rsz)
+ { /* Most likely there's more, so do another read */
+ inrab->rab$l_ubf += MAX_BIN_WRT;
+ status = sys$get(inrab);
+ if ((RMS$_NORMAL != status) && ((end != rec_count) || (RMS$_EOF != status)))
+ {
+ lib$signal(status);
+ mupip_error_occurred = TRUE;
+ break;
+ }
+ other_rsz = inrab->rab$w_rsz;
+ inrab->rab$l_ubf = rp;
+ }
+ }
+ if (SIZEOF(coll_hdr) == inrab->rab$w_rsz)
+ {
+ extr_collhdr = *((coll_hdr *)(inrab->rab$l_rbf));
+ assert(hdr_lvl > '2');
+ new_gvn = TRUE; /* next record will contain a new gvn */
+ rec_count--; /* Decrement as this record does not count as a record for loading purposes */
+ continue;
+ }
+ cp1 = rp + 1;
+ v.str.addr = cp1;
+ while (*cp1++)
+ ;
+ v.str.len = cp1 - (unsigned char *)v.str.addr - 1;
+ if (hdr_lvl <= '2' || new_gvn)
+ {
+ GV_BIND_NAME_AND_ROOT_SEARCH(gd_header, &v.str);
+ max_key = gv_cur_region->max_key_size;
+ db_collhdr.act = gv_target->act;
+ db_collhdr.ver = gv_target->ver;
+ db_collhdr.nct = gv_target->nct;
+ }
+ if ((0 != rp->cmpc) || (v.str.len > rp->rsiz) || mupip_error_occurred)
+ {
+ rts_error(VARLSTCNT(4) ERR_CORRUPT, 2, rec_count, global_key_count);
+ mu_gvis();
+ util_out_print(0, TRUE);
+ continue;
+ }
+ if (new_gvn)
+ {
+ global_key_count = 1;
+ if ((db_collhdr.act != extr_collhdr.act || db_collhdr.ver != extr_collhdr.ver ||
+ db_collhdr.nct != extr_collhdr.nct || extr_std_null_coll != gv_cur_region->std_null_coll))
+ /* do we need to bother about 'ver' change ??? */
+ {
+ if (extr_collhdr.act)
+ {
+ if (extr_collseq = ready_collseq((int)extr_collhdr.act))
+ {
+ if (!do_verify(extr_collseq, extr_collhdr.act, extr_collhdr.ver))
+ {
+ rts_error(VARLSTCNT(8) ERR_COLLTYPVERSION, 2,
+ extr_collhdr.act, extr_collhdr.ver,
+ ERR_GVIS, 2, gv_altkey->end - 1, gv_altkey->base);
+ }
+ } else
+ {
+ rts_error(VARLSTCNT(7) ERR_COLLATIONUNDEF, 1, extr_collhdr.act,
+ ERR_GVIS, 2, gv_altkey->end - 1, gv_altkey->base);
+ }
+ }
+ if (db_collhdr.act)
+ {
+ if (db_collseq = ready_collseq((int)db_collhdr.act))
+ {
+ if (!do_verify(db_collseq, db_collhdr.act, db_collhdr.ver))
+ {
+ rts_error(VARLSTCNT(8) ERR_COLLTYPVERSION, 2, db_collhdr.act,
+ db_collhdr.ver,
+ ERR_GVIS, 2, gv_altkey->end - 1, gv_altkey->base);
+ }
+ } else
+ {
+ rts_error(VARLSTCNT(7) ERR_COLLATIONUNDEF, 1, db_collhdr.act,
+ ERR_GVIS, 2, gv_altkey->end - 1, gv_altkey->base);
+ }
+ }
+ need_xlation = TRUE;
+ } else
+ need_xlation = FALSE;
+ }
+ new_gvn = FALSE;
+ GET_USHORT(rec_len, &rp->rsiz);
+ for (; rp < btop; rp = (unsigned char *)rp + rec_len)
+ {
+ GET_USHORT(rec_len, &rp->rsiz);
+ if ((rec_len + (unsigned char *)rp > btop) && (other_rsz))
+ { /* if there was a second read try to use it */
+ btop += other_rsz;
+ other_rsz = 0;
+ }
+ if (rec_len + (unsigned char *)rp > btop)
+ {
+ rts_error(VARLSTCNT(4) ERR_CORRUPT, 2, rec_count, global_key_count);
+ mu_gvis();
+ util_out_print(0, TRUE);
+ break;
+ }
+ cp1 = rp + 1;
+ cp2 = &gv_currkey->base + rp->cmpc;
+ current = 1;
+ for (;;)
+ {
+ last = current;
+ current = *cp2++ = *cp1++;
+ if ((0 == last) && (0 == current))
+ break;
+ if ((cp1 > ((unsigned char *)rp + rec_len)) ||
+ (cp2 > ((unsigned char *)gv_currkey + gv_currkey->top)))
+ {
+ rts_error(VARLSTCNT(4) ERR_CORRUPT, 2, rec_count, global_key_count);
+ mu_gvis();
+ util_out_print(0, TRUE);
+ break;
+ }
+ }
+ if (mupip_error_occurred)
+ break;
+ gv_currkey->end = cp2 - (unsigned char *)&gv_currkey->base - 1;
+ if (max_subsc_len < (gv_currkey->end + 1))
+ max_subsc_len = gv_currkey->end + 1;
+ if (need_xlation)
+ { /* gv_currkey would have been modified/translated in the earlier put */
+ memcpy(gv_currkey->base, cmpc_str, next_cmpc);
+ next_rp = (rec_hdr *)((unsigned char*)rp + rec_len);
+ if ((unsigned char*)next_rp < btop)
+ {
+ next_cmpc = next_rp->cmpc;
+ assert(next_cmpc <= gv_currkey->end);
+ memcpy(cmpc_str, gv_currkey->base, next_cmpc);
+ } else
+ next_cmpc = 0;
+ assert(hdr_lvl >= '3');
+ assert(extr_collhdr.act || db_collhdr.act || extr_collhdr.nct || db_collhdr.nct ||
+ extr_std_null_coll != gv_cur_region->std_null_coll);
+ /* the length of the key might change (due to nct variation),
+ * so get a copy of the original key from the extract */
+ memcpy(dup_key_str, gv_currkey->base, gv_currkey->end + 1);
+ gvkey_char_ptr = dup_key_str;
+ while (*gvkey_char_ptr++)
+ ;
+ gv_currkey->end = gvkey_char_ptr - dup_key_str;
+ assert(gv_keysize <= tmp_gvkey->top);
+ while (*gvkey_char_ptr)
+ {
+ /* get next subscript (in GT.M internal subsc format) */
+ subsc_len = 0;
+ tmp_ptr = src_buff;
+ while (*gvkey_char_ptr)
+ *tmp_ptr++ = *gvkey_char_ptr++;
+ subsc_len = tmp_ptr - src_buff;
+ src_buff[subsc_len] = '\0';
+ if (extr_collseq)
+ {
+ /* undo the extract time collation */
+ TREF(transform) = TRUE;
+ save_gv_target_collseq = gv_target->collseq;
+ gv_target->collseq = extr_collseq;
+ } else
+ TREF(transform) = FALSE;
+ /* convert the subscript to string format */
+ end_buff = gvsub2str(src_buff, dest_buff, FALSE);
+ /* transform the string to the current subsc format */
+ TREF(transform) = TRUE;
+ tmp_mval.mvtype = MV_STR;
+ tmp_mval.str.addr = (char *)dest_buff;
+ tmp_mval.str.len = end_buff - dest_buff;
+ tmp_gvkey->prev = 0;
+ tmp_gvkey->end = 0;
+ if (extr_collseq)
+ gv_target->collseq = save_gv_target_collseq;
+ mval2subsc(&tmp_mval, tmp_gvkey);
+ /* we now have the correctly transformed subscript */
+ tmp_key_ptr = gv_currkey->base + gv_currkey->end;
+ memcpy(tmp_key_ptr, tmp_gvkey->base, tmp_gvkey->end + 1);
+ gv_currkey->prev = gv_currkey->end;
+ gv_currkey->end += tmp_gvkey->end;
+ gvkey_char_ptr++;
+ }
+ if ((gv_cur_region->std_null_coll != extr_std_null_coll) && gv_currkey->prev)
+ {
+ if (extr_std_null_coll == 0)
+ {
+ GTM2STDNULLCOLL(gv_currkey->base, gv_currkey->end);
+ } else
+ {
+ STD2GTMNULLCOLL(gv_currkey->base, gv_currkey->end);
+ }
+ }
+ }
+ if (gv_currkey->end >= max_key)
+ {
+ rts_error(VARLSTCNT(4) ERR_CORRUPT, 2, rec_count, global_key_count);
+ mu_gvis();
+ util_out_print(0, TRUE);
+ continue;
+ }
+ v.str.addr = cp1;
+ v.str.len = rec_len - (cp1 - (unsigned char *)rp);
+ if (max_data_len < v.str.len)
+ max_data_len = v.str.len;
+ op_gvput(&v);
+ if (mupip_error_occurred)
+ {
+ if (!mupip_DB_full)
+ {
+ rts_error(VARLSTCNT(4) ERR_CORRUPT, 2, rec_count, global_key_count);
+ util_out_print(0, TRUE);
+ }
+ break;
+ }
+ key_count++;
+ global_key_count++;
+ }
+ }
+ free(tmp_gvkey);
+ lib$revert();
+ status = sys$close(infab);
+ if (RMS$_NORMAL != status)
+ {
+ lib$signal(status);
+ mupip_error_occurred = TRUE;
+ }
+ mu_load_stat(max_data_len, max_subsc_len, key_count, key_count ? (rec_count - 1) : 0, ERR_BLKCNT);
+ if (mupip_error_occurred)
+ lib$signal(ERR_LOADABORT, 1, rec_count - 1);
+ if (mu_ctrly_occurred)
+ lib$signal(ERR_LOADCTRLY);
+ free(inrab->rab$l_ubf);
+}
diff --git a/sr_vvms/bt_que_refresh.c b/sr_vvms/bt_que_refresh.c
new file mode 100644
index 0000000..0bcdbb1
--- /dev/null
+++ b/sr_vvms/bt_que_refresh.c
@@ -0,0 +1,47 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "wcs_recover.h"
+
+void bt_que_refresh(gd_region *greg)
+{
+ sgmnt_addrs *cs;
+ bt_rec *que_base, *que_top, *p;
+ int i;
+
+ cs = &FILE_INFO(greg)->s_addrs;
+ i = 0;
+ for (que_base = cs->bt_header, que_top = que_base + cs->hdr->bt_buckets + 1; que_base < que_top ; que_base++)
+ {
+ assert(que_base->blk == BT_QUEHEAD);
+ for (p = (bt_rec *) ((char *) que_base + que_base->blkque.fl) ; p != que_base ;
+ p = (bt_rec *) ((char *) p + p->blkque.fl))
+ {
+ if (i++ > cs->hdr->n_bts)
+ { wcs_recover(greg);
+ return;
+ }
+ if ((int4)p & 3)
+ { wcs_recover(greg);
+ return;
+ }
+ p->cache_index = CR_NOTVALID;
+ }
+ }
+ return;
+}
diff --git a/sr_vvms/build_print_stage.com b/sr_vvms/build_print_stage.com
new file mode 100644
index 0000000..1d47c4a
--- /dev/null
+++ b/sr_vvms/build_print_stage.com
@@ -0,0 +1,20 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2003 Sanchez Computer Associates, Inc. !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$! build_print_stage.com - prints the current time and stage of the build with appropriate indentation
+$!
+$! p1 - string indicating the stage
+$! p2 - string indicating "begin" or "end" or "middle" (they get 0 2 and 4 spaces indentation respectively)
+$!
+$ time_stamp = f$time()
+$ if (p2 .eqs. "begin") then write sys$output " ''time_stamp' --> BEGIN ''p1'"
+$ if (p2 .eqs. "middle") then write sys$output " ''time_stamp' --> ''p1'"
+$! if (p2 .eqs. "end") then write sys$output " ''time_stamp' --> END ''p1'"
diff --git a/sr_vvms/buildaux.com b/sr_vvms/buildaux.com
new file mode 100644
index 0000000..1470215
--- /dev/null
+++ b/sr_vvms/buildaux.com
@@ -0,0 +1,425 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2005 Fidelity Information Services, Inc !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$! buildaux - build auxiliary utilities
+$! parameters:
+$! p1 = version number
+$! p2 = library (p, d, or b)
+$! p3 = target device and directory
+$! p4 = optional auxillary to build ("gde", "dse", "mupip", "lke", "lmu", "gtmstop",
+$! "cmi", "gtcm_server", "gtcm_stop", "ibi_xfm", "ddp", "dbcertify")
+$! (if none specified, will build all auxillaries)
+$!
+$ if p1 .eqs. ""
+$ then
+$ write sys$output "Must supply a version"
+$ exit
+$ endif
+$!
+$ lnkimg=f$locate(p2,"PBD")
+$ if (f$length(p2) .ne. 1) .or. (lnkimg .eq. 3)
+$ then
+$ write sys$output "Library must be P, B or D"
+$ exit
+$ endif
+$!
+$ if p3 .eqs. ""
+$ then
+$ write sys$output "Must specify a target directory for the .exe files"
+$ exit
+$ endif
+$!
+$ @gtm$tools:gtm_verify_symbols "set" ! sets the global symbols gtm_copy, gtm_delete, gtm_library, gtm_purge
+$ @gtm$tools:build_print_stage "buildaux" "begin"
+$!
+$! ---------- buildaux set linker options -----------
+$!
+$ lnkopt = f$element(lnkimg,",","/notrace,/debug,/debug")
+$ alpha = (f$getsyi("arch_name") .eqs. "Alpha")
+$ if alpha then lnkopt = lnkopt + "/section"
+$!
+$! ---------- buildaux determine set of auxillaries to build -----------
+$!
+$ if p4 .eqs. ""
+$ then
+$ buildaux_gde = "yes"
+$ buildaux_dse = "yes"
+$ buildaux_mupip = "yes"
+$ buildaux_lke = "yes"
+$ buildaux_lmu = "yes"
+$ buildaux_gtmstop = "yes"
+$ buildaux_cmi = "yes"
+$ buildaux_gtcm_server= "yes"
+$ buildaux_gtcm_stop = "yes"
+$ buildaux_ibi_xfm = "yes"
+$ buildaux_ddp = "yes"
+$ buildaux_dbcertify = "yes"
+$ else
+$ buildaux_gde = ""
+$ buildaux_dse = ""
+$ buildaux_mupip = ""
+$ buildaux_lke = ""
+$ buildaux_lmu = ""
+$ buildaux_gtmstop = ""
+$ buildaux_cmi = ""
+$ buildaux_gtcm_server= ""
+$ buildaux_gtcm_stop = ""
+$ buildaux_ibi_xfm = ""
+$ buildaux_ddp = ""
+$ buildaux_dbcertify = ""
+$ buildaux_'p4' = "yes"
+$ endif
+$!
+$! smw 2001/5/2 force no dsf debug files for now - later check axp and logical
+$ dsffiles = 0
+$!
+$ @gtm$tools:setactive_silent 'p1' 'p2'
+$ set def gtm$vrt
+$ set def gtm$exe
+$!
+$ set def [.obj]
+$ objdir = f$environment("default")
+$ set def 'p3'
+$ targdir = f$environment("default")
+$ set def [.map]
+$ mapfile = f$environment("default")
+$ set def [-]
+$!
+$! ---------- buildaux prepare options for the linker in .opt files -----------
+$!
+$ open/write relnam release_name.opt
+$ write relnam "ident=",p1
+$ close relnam
+$!
+$! Because the linker creates image sections on a per-cluster
+$! basis, create a cluster for all of the code Psect's (whose
+$! pages can be shared among processes) and collect all of the
+$! code Psect's into it so the pages corresponding to that image
+$! section can be shared. Note the MACRO/MIGRATION compiler
+$! names its code Psect "$CODE" (as do most of the VAX compilers),
+$! while the AXP C compiler and MACRO assembler name their code
+$! Psect's "$CODE$".
+$ open/write clusnam cluster.opt
+$ write clusnam "cluster = literal_clust"
+$ write clusnam "collect = literal_clust,GTM$LITERALS"
+$ write clusnam "cluster = code_clust"
+$ write clusnam "collect = code_clust,GTM$CODE,$CODE,$CODE$"
+$ close clusnam
+$!
+$ open/write secshrlink secshrlink.opt
+$ if ("" .eqs. f$trnlnm("gtm_no_secshr")) .or. (p2 .nes. "P")
+$ then
+$ write secshrlink "gtm$pro:gtmsecshr.exe/share"
+$ endif
+$ close secshrlink
+$!
+$! ---------- buildaux gde -----------
+$!
+$ if (buildaux_gde .nes. "")
+$ then
+$ @gtm$tools:build_print_stage "Building GDE" "middle"
+$!
+$! use production images to compile GDE*.M and other GT.M utilities
+$ @gtm$tools:setactive_silent 'p1' p
+$ set def [.obj]
+$!
+$ set command gtm$src:GTMCOMMANDS.CLDX ! define MUMPS command if .cldx file present
+$ mumps gtm$src:gde*.m
+$ gtm_library /replace mumps gde*.obj
+$ gtm_delete gde*.obj;*
+$!
+$ gtm_copy gtm$src:lclcol.mpt []_lclcol.m
+$ mumps _lclcol
+$ gtm_library /replace mumps _lclcol.obj
+$ gtm_delete _lclcol.m;,_lclcol.obj;
+$!
+$ gtm_copy gtm$src:patcode.mpt []_patcode.m
+$ mumps _patcode
+$ gtm_library /replace mumps _patcode.obj
+$ gtm_delete _patcode.m;,_patcode.obj;
+$!
+$ set def [-]
+$ @gtm$tools:setactive_silent 'p1' 'p2' ! revert back to currently building image
+$!
+$ xtra = "," + f$parse(f$search("gtm$src:gde*.msg"),,,"NAME")
+$ set noon
+$ search/nooutput gtm$src:gde.m patcode
+$ if $severity .eq. 1 then $ xtra = xtra + ",_patcode"
+$ define/user gdeobj 'objdir'mumps.olb
+$ define/user sys$error nl:
+$ define/user sys$output nl:
+$ gtm_library/extract=gdeoget/output=nl: 'objdir'mumps.olb
+$ if $severity .eq. 1 then $ xtra = xtra + ",gdeoget"
+$ set on
+$ gdedsf = ""
+$ if dsffiles then gdedsf = "/dsf=gde.dsf"
+$ define/user gdeobj 'objdir'mumps.olb
+$ define/user target 'targdir'
+$ link/map='mapfile'gde.map/full/exe='targdir'gde.exe'lnkopt' 'gdedsf' gdeobj/incl=(gde'xtra'),sys$input/opt,target:cluster.opt/opt,target:release_name.opt/opt
+gdeobj/incl=(_lclcol,gdeadd,gdechang,gdetempl,gdedelet,gdeexit,gdeget,gdemsgin)
+gdeobj/incl=(gdehelp,gdesetgd,gdeinit,gdelocks,gdelog,gdemap,gdeparse,gdeput,gdequit)
+gdeobj/incl=(gderenam,gdescan,gdeshow,gdespawn,gdeverif)
+SYMBOL=GTM$CTRLC_ENABLE,0
+name = GDE.EXE
+$ endif
+$!
+$! ---------- buildaux dse -----------
+$!
+$ if (buildaux_dse .nes. "")
+$ then
+$ @gtm$tools:build_print_stage "Building DSE" "middle"
+$ dsedsf = ""
+$ if dsffiles then dsedsf = "/dsf=dse.dsf"
+$ define/user dseobj 'objdir'mumps.olb
+$ define/user target 'targdir'
+$ link/map='mapfile'dse.map/full/cross/exe='targdir'dse.exe'lnkopt' 'dsedsf' dseobj/libr/incl=dse,target:secshrlink.opt/opt,target:cluster.opt/opt,sys$input/opt,target:release_name.opt/opt
+name = DSE.EXE
+$ endif
+$!
+$! ---------- buildaux mupip -----------
+$!
+$ if (buildaux_mupip .nes. "")
+$ then
+$ @gtm$tools:build_print_stage "Building MUPIP" "middle"
+$ mupipdsf = ""
+$ if dsffiles then mupipdsf = "/dsf=mupip.dsf"
+$ define/user mupipobj 'objdir'mumps.olb
+$ define/user target 'targdir'
+$ link/map='mapfile'mupip.map/full/cross/exe='targdir'mupip.exe'lnkopt' 'mupipdsf' mupipobj/libr/incl=mupip,target:secshrlink.opt/opt,target:cluster.opt/opt,sys$input/opt,target:release_name.opt/opt
+name = MUPIP.EXE
+$ endif
+$!
+$! ---------- buildaux dbcertify -----------
+$!
+$ if (buildaux_dbcertify .nes. "")
+$ then
+$ @gtm$tools:build_print_stage "Building DBCERTIFY" "middle"
+$ dbcertifydsf = ""
+$ if dsffiles then dbcertifydsf = "/dsf=dbcertify.dsf"
+$ define/user dbcertifyobj 'objdir'mumps.olb
+$ define/user target 'targdir'
+$ link/map='mapfile'dbcertify.map/full/cross/exe='targdir'dbcertify.exe'lnkopt' 'dbcertifydsf' dbcertifyobj/libr/incl=dbcertify,target:cluster.opt/opt,sys$input/opt,target:release_name.opt/opt
+name = DBCERTIFY.EXE
+$ endif
+$!
+$! ---------- buildaux lke -----------
+$!
+$ if (buildaux_lke .nes. "")
+$ then
+$ @gtm$tools:build_print_stage "Building LKE" "middle"
+$ lkedsf = ""
+$ if dsffiles then lkedsf = "/dsf=lke.dsf"
+$ define/user lkeobj 'objdir'mumps.olb
+$ define/user target 'targdir'
+$ link/map='mapfile'lke.map/full/exe='targdir'lke.exe'lnkopt' 'lkedsf' lkeobj/libr/incl=lke,target:secshrlink.opt/opt,target:cluster.opt/opt,sys$input/opt,target:release_name.opt/opt
+name = LKE.EXE
+$ endif
+$!
+$! ---------- buildaux lmu if not NOLICENSE in mdef.h -----------
+$!
+$ if (buildaux_lmu .nes. "")
+$ then
+$ search/nooutput gtm$src:mdef.h nolicense
+$ if $severity .ne. 1
+$ then
+$ @gtm$tools:build_print_stage "Building LMU" "middle"
+$ define/user lmuobj 'objdir'mumps.olb
+$ define/user target 'targdir'
+$ link/map='mapfile'lmu.map/full/exe='targdir'lmu.exe'lnkopt' lmuobj/libr/incl=lmu,target:secshrlink.opt/opt,target:cluster.opt/opt,sys$input/opt,target:release_name.opt/opt
+name = LMU.EXE
+$ endif
+$ endif
+$!
+$! ---------- skip gtmstop and cmi building for "minimal_build" -----------
+$!
+$ minimal = f$trnlnm("minimal_build")
+$ if (minimal .nes. "")
+$ then
+$ goto minimal_build_skip
+$ endif
+$!
+$! ---------- buildaux gtmstop -----------
+$!
+$ if (buildaux_gtmstop .nes. "")
+$ then
+$ @gtm$tools:build_print_stage "Building GTM$STOP" "middle"
+$!
+$! use production images to compile GTMSTOP.M
+$ @gtm$tools:setactive_silent 'p1' p
+$ set def [.obj]
+$ set command gtm$src:GTMCOMMANDS.CLDX ! define MUMPS command if .cldx file present
+$ mumps gtm$src:gtmstop.m
+$ gtm_library /replace mumps gtmstop.obj
+$ gtm_delete gtmstop.obj;
+$ set def [-]
+$ @gtm$tools:setactive_silent 'p1' 'p2' ! revert back to currently building image
+$!
+$ gtmstopdsf = ""
+$ if dsffiles then gtmstopdsf = "/dsf=gtm$stop.dsf"
+$ define/user gtmstopobj 'objdir'mumps.olb
+$ define/user target 'targdir'
+$ link/exe=gtm$stop.exe/map='mapfile'gtm$stop.map/full 'gtmstopdsf' gtmstopobj/incl=(gtmstop,gtmstopzc,merrors),sys$input/opt,target:cluster.opt/opt,target:release_name.opt/opt
+gtm$vrt:[pct]_dh.obj,_do.obj,_exp.obj,_st.obj
+name = GTM$STOP.EXE
+$ endif
+$!
+$! ---------- buildaux cmishr -----------
+$!
+$ if (buildaux_cmi .nes. "")
+$ then
+$ @gtm$tools:build_print_stage "Building CMISHR" "middle"
+$ @gtm$tools:cmicom 'p1' 'p2' 'objdir'
+$ xtra = f$element(alpha,",","/incl=cmivector,")
+$ cmilink = "cmilink." + f$element(alpha,",","vax,axp")
+$ cmidsf = ""
+$ if dsffiles then cmidsf = "/dsf=cmishr.dsf"
+$ define/user cmiobj 'objdir'cmi.olb
+$ define/user target 'targdir'
+$ link/map='mapfile'cmishr.map/full/share='targdir'cmishr.exe'lnkopt' 'cmidsf' cmiobj/libr'xtra',gtm$tools:'cmilink'/opt,sys$input/opt,target:release_name.opt/opt
+name = CMISHR.EXE
+$ set security/protect=(o:rwed,s:rwed,g:re,w:re) 'targdir'cmishr.exe
+$ if p2 .eqs. "P"
+$ then
+$ gtm_copy 'targdir'cmishr.exe 'targdir''p1'_cmishr.exe
+$ curpriv=f$setprv("sysprv")
+$ gtm_copy/protect=(o:rwed,s:rwed,g:re,w:re) 'targdir'cmishr.exe gtm$sec:'p1'_cmishr.exe
+$ curpriv=f$setprv(curpriv)
+$ set security/protect=(o:rwed,s:rwed,g:re,w:re) 'targdir''p1'_cmishr.exe
+$ endif
+$ endif
+$!
+$! ---------- buildaux gtcm_server -----------
+$!
+$ if (buildaux_gtcm_server .nes. "")
+$ then
+$ @gtm$tools:build_print_stage "Building GTCM_SERVER" "middle"
+$ gtcmsrvdsf = ""
+$ if dsffiles then gtcmsrvdsf = "/dsf=gtcm_server.dsf"
+$ define/user gtcmobj 'objdir'mumps.olb
+$ define/user target 'targdir'
+$ link/map='mapfile'gtcm_server.map/full/exe='targdir'gtcm_server.exe'lnkopt' 'gtcmsrvdsf' gtcmobj/libr/incl=gtcm_server,target:secshrlink.opt/opt,target:cluster.opt/opt,sys$input/opt,target:release_name.opt/opt
+name = GTCM_SERVER.EXE
+$ endif
+$!
+$! ---------- buildaux gtcm_stop -----------
+$!
+$ if (buildaux_gtcm_stop .nes. "")
+$ then
+$ @gtm$tools:build_print_stage "Building GTCM_STOP" "middle"
+$!
+$! use production images to compile GTCMSTOP.M
+$ @gtm$tools:setactive_silent 'p1' p
+$ set def [.obj]
+$ set command gtm$src:GTMCOMMANDS.CLDX ! define MUMPS command if .cldx file present
+$ mumps gtm$src:gtcmstop.m
+$ gtm_library /replace mumps gtcmstop.obj
+$ gtm_delete gtcmstop.obj;
+$ set def [-]
+$ @gtm$tools:setactive_silent 'p1' 'p2' ! revert back to currently building image
+$!
+$ gtcmstpdsf = ""
+$ if dsffiles then gtcmstpdsf = "/dsf=gtcm_stop.dsf"
+$ define/user gtcmstopobj 'objdir'mumps.olb
+$ define/user target 'targdir'
+$ link/map='mapfile'gtcm_stop.map/full/exe='targdir'gtcm_stop.exe gtcmstopobj/incl=(gtcmstop,gtmstopzc,merrors),target:cluster.opt/opt,sys$input/opt,target:release_name.opt/opt
+gtm$vrt:[pct]_dh.obj,_exp.obj
+name = GTCM_STOP.EXE
+$ endif
+$!
+$! ---------- buildaux ibi_xfm -----------
+$!
+$ if (buildaux_ibi_xfm .nes. "")
+$ then
+$ set noon
+$ define/user sys$error nl:
+$ define/user sys$output nl:
+$ gtm_library/extract=dsm_api_vector/output=nl: 'objdir'mumps.olb
+$ severity = $severity
+$ set on
+$ if severity .eq. 1
+$ then
+$ @gtm$tools:build_print_stage "Building IBI_XFM" "middle"
+$ define/user ibiobj 'objdir'mumps.olb
+$ define/user target 'targdir'
+$ link/share='targdir'ibi_xfm.exe/map='mapfile'ibi_xfm.map/full ibiobj/libr/incl=dsm_api_vector,sys$input/opt,target:cluster.opt/opt,target:release_name.opt/opt
+GTMSHR/SHARE
+GSMATCH=LEQ,4,0
+name=DSM$SHARE
+$ endif
+$ endif
+$!
+$! ---------- buildaux ddpserver, ddpgvusr and gtcmddpstop -----------
+$!
+$ if (buildaux_ddp .nes. "")
+$ then
+$ set noon
+$ define/user sys$error nl:
+$ define/user sys$output nl:
+$ gtm_library/extract=ddpserver/output=nl: 'objdir'mumps.olb
+$ severity = $severity
+$ set on
+$ if severity .eq. 1
+$ then
+$ @gtm$tools:build_print_stage "Building DDPSERVER" "middle"
+$ define/user ddpobj 'objdir'mumps.olb
+$ define/user target 'targdir'
+$ link/map='mapfile'ddpserver.map/full/exe='targdir'ddpserver.exe'lnkopt' ddpobj/libr/incl=ddpserver,sys$input/opt,target:cluster.opt/opt,target:release_name.opt/opt
+gtmshr/share
+gtmsecshr/share
+name = DDPSERVER.EXE
+$ @gtm$tools:build_print_stage "Building DDPGVUSR" "middle"
+$ ddplink ="ddplink." + f$element(alpha,",","vax,axp")
+$ define/user ddpobj 'objdir'mumps.olb
+$ define/user target 'targdir'
+$ link/share='targdir'ddpgvusr.exe'lnkopt'/map='mapfile'DDPGVUSR.MAP/full ddpobj/incl=(DDPGVUSR),gtm$tools:'ddplink'/opt,sys$input/opt,target:release_name.opt/opt
+name = DDPGVUSR.EXE
+$ if p2 .eqs. "P"
+$ then
+$ @gtm$tools:build_print_stage "Building GTCMDDPSTOP" "middle"
+$!
+$ set def [.obj]
+$ set command gtm$src:GTMCOMMANDS.CLDX ! define MUMPS command if .cldx file present
+$!
+$ mumps gtm$src:stpimg.m
+$ gtm_library /replace mumps stpimg.obj
+$ gtm_delete stpimg.obj;
+$!
+$ mumps gtm$src:pid.m
+$ gtm_library /replace mumps pid.obj
+$ gtm_delete pid.obj;
+$!
+$ set def [-]
+$!
+$ define/user ddpobj 'objdir'mumps.olb
+$ define/user target 'targdir'
+$ link/exe='targdir'gtcmddpstop.exe/map='mapfile'gtcmddpstop.map/full ddpobj/incl=(stpimg),sys$input/opt,target:cluster.opt/opt,target:release_name.opt/opt
+ddpobj/incl=(pid,gtmstopzc,merrors)
+gtm$vrt:[pct]_dh.obj,_exp.obj
+SYMBOL=GTM$CTRLC_ENABLE,0
+name = GTCMDDPSTOP.EXE
+$ endif
+$ endif
+$ endif
+$!
+$! ---------- buildaux end -----------
+$!
+$minimal_build_skip:
+$ gtm_delete cluster.opt;*,release_name.opt;*,secshrlink.opt;*
+$ if p4 .eqs. ""
+$ then
+$ gtm_purge
+$ gtm_purge [.map]*.*
+$ endif
+$ set security/protect=(o:rwed,s:rwed,g:re,w:re) *.exe
+$ @gtm$tools:build_print_stage "buildaux" "end"
+$!
+$ @gtm$tools:gtm_verify_symbols "unset" ! unsets the global symbols gtm_copy, gtm_delete gtm_library, gtm_purge
+$ exit
diff --git a/sr_vvms/buildbta.com b/sr_vvms/buildbta.com
new file mode 100644
index 0000000..d9ad026
--- /dev/null
+++ b/sr_vvms/buildbta.com
@@ -0,0 +1,47 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2004 Sanchez Computer Associates, Inc. !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$! buildbta.com - build bta images p1=version number; p2 = VMS version for libraries
+$!
+$ if p1 .eqs. ""
+$ then
+$ write sys$output "Must supply a version"
+$ exit
+$ endif
+$!
+$ old = 0
+$ vmsver = f$extract(1,3,f$getsyi("version")) - "."
+$ if (f$extract(0,1,p2) .eqs. "V") .and. (f$extract(1,2,p2) .nes. vmsver)
+$ then
+$ old = 1
+$ @gtm$tools:define-old-library-logicals 'p2'
+$ endif
+$ @gtm$tools:buildshr 'p1' b gtm$root:['p1'.bta]
+$ if f$search("gtm$vrt:[pct]_dh.obj") .eqs. "" then @gtm$tools:movempt 'p1'
+$ @gtm$tools:buildaux 'p1' b gtm$root:['p1'.bta]
+$!
+$ minimal = f$trnlnm("minimal_build")
+$ if (minimal .eqs. "")
+$ then
+$ @gtm$tools:buildtcx 'p1' b gtm$root:['p1'.bta]
+$ endif
+$ if (f$getsyi("arch_name") .eqs. "Alpha") then $ @gtm$tools:srm_check gtm$root:['p1'.bta]
+$!
+$ @gtm$tools:gtm_verify_symbols "set" ! sets the global symbols gtm_copy, gtm_delete, gtm_library, gtm_purge
+$!
+$! libr/out=gtm$vrt:[bta.obj]xref.lis/cross gtm$vrt:[bta.obj]mumps
+$ gtm_purge gtm$vrt:[bta.obj]
+$ set prot=w:re gtm$vrt:[bta]*.exe
+$ set prot=w:r gtm$vrt:[bta]*.olb
+$ if old then $ @gtm$tools:define-old-library-logicals remove
+$!
+$ @gtm$tools:gtm_verify_symbols "unset" ! unsets the global symbols gtm_copy, gtm_delete gtm_library, gtm_purge
+$ exit
diff --git a/sr_vvms/buildcm.com b/sr_vvms/buildcm.com
new file mode 100644
index 0000000..dff5145
--- /dev/null
+++ b/sr_vvms/buildcm.com
@@ -0,0 +1,20 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2003 Sanchez Computer Associates, Inc. !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$! buildcm - build gtcm_server, cmishr and gtcm_stop
+$! parameters:
+$! p1 = version number
+$! p2 = library (p, d, or b)
+$! p3 = target device and directory
+$!
+$ @gtm$tools:buildaux 'p1' 'p2' 'p3' "cmi"
+$ @gtm$tools:buildaux 'p1' 'p2' 'p3' "gtcm_server"
+$ @gtm$tools:buildaux 'p1' 'p2' 'p3' "gtcm_stop"
diff --git a/sr_vvms/buildcmi.com b/sr_vvms/buildcmi.com
new file mode 100644
index 0000000..511f31a
--- /dev/null
+++ b/sr_vvms/buildcmi.com
@@ -0,0 +1,18 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2003 Sanchez Computer Associates, Inc. !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$! buildcmi - build cmishr
+$! This uses an existing library and does not purge
+$! p1 = version number
+$! p2 = library (p, b, or d)
+$! p3 = target device and directory
+$!
+$ @gtm$tools:buildaux 'p1' 'p2' 'p3' cmi
diff --git a/sr_vvms/builddbcertify.com b/sr_vvms/builddbcertify.com
new file mode 100644
index 0000000..2061ca8
--- /dev/null
+++ b/sr_vvms/builddbcertify.com
@@ -0,0 +1,18 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2005 Fidelity Information Services, Inc !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$! builddbcertify - build a dbcertify
+$! parameters:
+$! p1 = version number
+$! p2 = library (p, d, or b)
+$! p3 = target device and directory
+$!
+$ @gtm$tools:buildaux 'p1' 'p2' 'p3' "dbcertify"
diff --git a/sr_vvms/builddbg.com b/sr_vvms/builddbg.com
new file mode 100644
index 0000000..8264766
--- /dev/null
+++ b/sr_vvms/builddbg.com
@@ -0,0 +1,32 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2004 Sanchez Computer Associates, Inc. !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$! builddbg.com build dbg images - p1 = version number; p2 = VMS version for libraries
+$!
+$ if p1 .eqs. "" then $exit
+$ old = 0
+$ vmsver = f$extract(1,3,f$getsyi("version")) - "."
+$ if (f$extract(0,1,p2) .eqs. "V") .and. (f$extract(1,2,p2) .nes. vmsver)
+$ then
+$ old = 1
+$ @gtm$tools:define-old-library-logicals 'p2'
+$ endif
+$ @gtm$tools:buildshr 'p1' d gtm$root:['p1'.dbg]
+$ @gtm$tools:buildaux 'p1' d gtm$root:['p1'.dbg]
+$!
+$ minimal = f$trnlnm("minimal_build")
+$ if (minimal .eqs. "")
+$ then
+$ @gtm$tools:buildtcx 'p1' d gtm$root:['p1'.dbg]
+$ endif
+$ if (f$getsyi("arch_name") .eqs. "Alpha") then $ @gtm$tools:srm_check gtm$root:['p1'.dbg]
+$ if old then $ @gtm$tools:define-old-library-logicals remove
+$ exit
diff --git a/sr_vvms/buildddp.com b/sr_vvms/buildddp.com
new file mode 100644
index 0000000..3eccd74
--- /dev/null
+++ b/sr_vvms/buildddp.com
@@ -0,0 +1,18 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2003 Sanchez Computer Associates, Inc. !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$! buildaux - build utilties
+$! parameters:
+$! p1 = version number
+$! p2 = library (p, d, or b)
+$! p3 = target device and directory
+$!
+$ @gtm$tools:buildaux 'p1' 'p2' 'p3' "ddp"
diff --git a/sr_vvms/builddse.com b/sr_vvms/builddse.com
new file mode 100644
index 0000000..d1c9aa3
--- /dev/null
+++ b/sr_vvms/builddse.com
@@ -0,0 +1,18 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2003 Sanchez Computer Associates, Inc. !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$! builddse - build dse
+$! parameters:
+$! p1 = version number
+$! p2 = library (p, d, or b)
+$! p3 = target device and directory
+$!
+$ @gtm$tools:buildaux 'p1' 'p2' 'p3' "dse"
diff --git a/sr_vvms/buildgde.com b/sr_vvms/buildgde.com
new file mode 100644
index 0000000..551ea01
--- /dev/null
+++ b/sr_vvms/buildgde.com
@@ -0,0 +1,18 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2003 Sanchez Computer Associates, Inc. !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$! buildgde - build gde
+$! parameters:
+$! p1 = version number
+$! p2 = library (p, d, or b)
+$! p3 = target device and directory
+$!
+$ @gtm$tools:buildaux 'p1' 'p2' 'p3' "gde"
diff --git a/sr_vvms/buildhlp.com b/sr_vvms/buildhlp.com
new file mode 100644
index 0000000..2b76318
--- /dev/null
+++ b/sr_vvms/buildhlp.com
@@ -0,0 +1,43 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2003 Sanchez Computer Associates, Inc. !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$! buildhlp.com - build help files
+$!
+$ if p1 .eqs. "" then $exit
+$ @gtm$tools:gtm_verify_symbols "set" ! sets the global symbols gtm_copy, gtm_delete, gtm_library, gtm_purge
+$ @gtm$tools:build_print_stage "buildhlp" "begin"
+$ @gtm$tools:setactive_silent 'p1' b
+$ set def gtm$help
+$!
+$ @gtm$tools:build_print_stage "Creating *.hlb files" "middle"
+$ gtm_library/create=(block:25,key:60)/help dse
+$ gtm_library/help dse gtm$src:dse
+$ gtm_library/create=(block:25,key:60)/help LKE
+$ gtm_library/help LKE gtm$src:LKE
+$ gtm_library/create=(block:25,key:60)/help mupip.hlb
+$ gtm_library/help mupip.hlb gtm$src:mupip
+$ gtm_library/create=(block:25,key:60)/help gde
+$ gtm_library/help gde gtm$src:gde
+$ gtm_library/create=(block:25,key:60)/help cce
+$ gtm_library/help cce gtm$src:cce
+$ gtm_library/create=(block:25,key:60)/help la
+$ gtm_library/help la gtm$src:la
+$ gtm_library/create=(block:25,key:60)/help lmu
+$ gtm_library/help lmu gtm$src:lmu
+$ gtm_library/create=(block:25,keysize:60)/help mumps
+$ gtm_library/help mumps gtm$src:mumps
+$ gtm_purge
+$ set prot=w:r *.hlb
+$ set def gtm$ver
+$!
+$ @gtm$tools:build_print_stage "buildhlp" "end"
+$ @gtm$tools:gtm_verify_symbols "unset" ! unsets the global symbols gtm_copy, gtm_delete gtm_library, gtm_purge
+$ exit
diff --git a/sr_vvms/buildlke.com b/sr_vvms/buildlke.com
new file mode 100644
index 0000000..ca7fd14
--- /dev/null
+++ b/sr_vvms/buildlke.com
@@ -0,0 +1,18 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2003 Sanchez Computer Associates, Inc. !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$! buildlke - build an lke
+$! parameters:
+$! p1 = version number
+$! p2 = library (p, d, or b)
+$! p3 = target device and directory
+$!
+$ @gtm$tools:buildaux 'p1' 'p2' 'p3' "lke"
diff --git a/sr_vvms/buildmapdb.com b/sr_vvms/buildmapdb.com
new file mode 100644
index 0000000..d3b50ed
--- /dev/null
+++ b/sr_vvms/buildmapdb.com
@@ -0,0 +1,78 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2003 Sanchez Computer Associates, Inc. !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$! -----------------------------------------------------------------------------------------------------------
+$! This utility builds a database out of each *.map file created in gtm$map.
+$! The database is named mapdb.dat with its global directory mapdb.gld both in gtm$map.
+$! -----------------------------------------------------------------------------------------------------------
+$ if (f$trnlnm("gtm$map") .eqs. "")
+$ then
+$ write sys$output "Logical gtm$map not defined. Exiting..."
+$ exit
+$ endif
+$!
+$ define sys$output nl:
+$ define sys$error nl:
+$ savegbldir = f$trnlnm("gtm$gbldir")
+$ savepwd = f$environment("default")
+$ set def gtm$map
+$ curpwd = f$environment("default")
+$ delete/log mapdb.gld.*
+$ delete/log mapdb.dat.*
+$ define gtm$gbldir gtm$map:mapdb.gld
+$!
+$ open/write outfile mapdbtmp.com
+$ write outfile "change /seg $DEFAULT /file=''curpwd'mapdb.dat"
+$ write outfile "change /seg $DEFAULT /allocation=200"
+$ close outfile
+$ gde
+ at mapdbtmp.com
+exit
+$ delete/log mapdbtmp.com.*
+$!
+$ mupip create
+$!
+$ delete/log mapdb.m.*
+$ delete/log mapdb.obj.*
+$maploop:
+$ mapfile = f$search("*.map")
+$ if (mapfile .eqs. "") then goto end_maploop
+$ imagename = f$parse(mapfile,,,"NAME")
+$ if (imagename .eqs. "IPCRM") then goto maploop
+$ if (imagename .eqs. "MCOMPILE") then goto maploop
+$ if (imagename .eqs. "GTM$DMOD") then goto maploop
+$ if (imagename .eqs. "GTM$STOP") then goto maploop
+$ if (imagename .eqs. "GTCM_STOP") then goto maploop
+$ if (imagename .eqs. "CRASHANDBURN") then goto maploop
+$ if (imagename .eqs. "GTCMDDPSTOP") then goto maploop
+$ if (imagename .eqs. "CCP") then goto maploop
+$ deassign sys$output
+$ write sys$output " --> Building in gtm$map:mapdb.dat : global ^''imagename'"
+$ define sys$output nl:
+$ gawk /input=gtm$tools:mapdb.awk /var=("image=''imagename'") 'mapfile' /out=mapdb.m
+$ gtm
+if $e($zv,6,9)]"V4.0" d ^mapdb quit
+; versions <= V4.0 complain mapdb.m has too many literals. so we xecute all contents of mapdb.m instead
+set file="mapdb.m" open file use file read str
+for quit:str="" xecute str read str
+$ mumps gtm$src:mapoff.m
+$ purge mapoff.obj
+$ delete/log gtm$obj:*.lis.*/excl=xref.lis
+$ delete/log mapdb.m.*
+$ delete/log mapdb.obj.*
+$ goto maploop
+$!
+$end_maploop:
+$ define gtm$gbldir 'savegbldir'
+$ deassign sys$output
+$ deassign sys$error
+$ set def 'savepwd'
+$!
diff --git a/sr_vvms/buildmupip.com b/sr_vvms/buildmupip.com
new file mode 100644
index 0000000..6e5d085
--- /dev/null
+++ b/sr_vvms/buildmupip.com
@@ -0,0 +1,18 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2003 Sanchez Computer Associates, Inc. !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$! buildmupip - build a mupip
+$! parameters:
+$! p1 = version number
+$! p2 = library (p, d, or b)
+$! p3 = target device and directory
+$!
+$ @gtm$tools:buildaux 'p1' 'p2' 'p3' "mupip"
diff --git a/sr_vvms/buildpro.com b/sr_vvms/buildpro.com
new file mode 100644
index 0000000..91ee3c4
--- /dev/null
+++ b/sr_vvms/buildpro.com
@@ -0,0 +1,64 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2004 Sanchez Computer Associates, Inc. !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$! buildpro.com - build pro images p1 = version number; p2 = VMS version for libraries
+$!
+$ if p1 .eqs. ""
+$ then
+$ write sys$output "Must supply a version"
+$ exit
+$ endif
+$!
+$ old = 0
+$ vmsver = f$extract(1,3,f$getsyi("version")) - "."
+$ if (f$extract(0,1,p2) .eqs. "V") .and. (f$extract(1,2,p2) .nes. vmsver)
+$ then
+$ old = 1
+$ @gtm$tools:define-old-library-logicals 'p2'
+$ endif
+$ @gtm$tools:buildsec 'p1' p gtm$root:['p1'.pro]
+$ @gtm$tools:buildshr 'p1' p gtm$root:['p1'.pro]
+$ @gtm$tools:movempt 'p1'
+$ @gtm$tools:buildaux 'p1' p gtm$root:['p1'.pro]
+$!
+$ minimal = f$trnlnm("minimal_build")
+$ if (minimal .eqs. "")
+$ then
+$ @gtm$tools:buildtcx 'p1' p gtm$root:['p1'.pro]
+$ endif
+$!
+$ @gtm$tools:gtm_verify_symbols "set" ! sets the global symbols gtm_copy, gtm_delete, gtm_library, gtm_purge
+$!
+$ if (f$getsyi("arch_name") .eqs. "Alpha") then $ @gtm$tools:srm_check gtm$root:['p1'.pro]
+$ dir/nohead/notrail/ver=1/out=gtm$root:['p1']src.txt gtm$src
+$ gtm_purge gtm$root:['p1']src.txt
+$ set def gtm$root:['p1'.pro]
+$ gtm_copy gtm$src:gtmcommands.cldx []gtmcommands.cld
+$ gtm_copy gtm$src:gtm$defaults.* gtm$vrt:[tls]
+$ gtm_purge gtm$vrt:[tls]
+$ gtm_library/create=(block:25)/macro gtmzcall
+$ gtm_library/macro gtmzcall gtm$src:gtmzcall.max
+$ set noon
+$ gtm_library/extract=mumps_binding/output=mumps_binding.max gtm$vrt:[pro.obj]maclib.mlb
+$ if $severity .eq. 1
+$ then
+$ gtm_library/macro gtmzcall mumps_binding.max
+$ gtm_delete mumps_binding.max.
+$ endif
+$ gtm_library/out=gtm$vrt:[pro.obj]xref.lis/cross gtm$vrt:[pro.obj]mumps
+$ set def gtm$pro
+$ gtm_purge gtm$root:['p1'.pro]
+$ set prot=w:re gtm$vrt:[pro]*.exe
+$ set prot=w:r gtm$vrt:[pro]*.olb
+$ if old then $ @gtm$tools:define-old-library-logicals remove
+$!
+$ @gtm$tools:gtm_verify_symbols "unset" ! unsets the global symbols gtm_copy, gtm_delete gtm_library, gtm_purge
+$ exit
diff --git a/sr_vvms/buildsec.com b/sr_vvms/buildsec.com
new file mode 100644
index 0000000..6f220ad
--- /dev/null
+++ b/sr_vvms/buildsec.com
@@ -0,0 +1,130 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2013 Fidelity Information Services, Inc !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$! buildsec - build gtmsecshr
+$! parameters:
+$! p1 = version number
+$! p2 = library (p, d, or b)
+$! p3 = target device and directory
+$!
+$ if p1 .eqs. ""
+$ then
+$ write sys$output "Must supply a version"
+$ exit
+$ endif
+$!
+$ lnkimg=f$locate(p2,"PBD")
+$ if (f$length(p2) .ne. 1) .or. (lnkimg .eq. 3)
+$ then
+$ write sys$output "Library must be P, B or D"
+$ exit
+$ endif
+$!
+$ if p3 .eqs. ""
+$ then
+$ write sys$output "Must specify a target directory for the .exe files"
+$ exit
+$ endif
+$!
+$ @gtm$tools:gtm_verify_symbols "set" ! sets the global symbols gtm_copy, gtm_delete, gtm_library, gtm_purge
+$ @gtm$tools:build_print_stage "buildsec" "begin"
+$!
+$! ---------- set linker options -----------
+$!
+$ lnkopt = ""
+$ alpha = (f$getsyi("arch_name") .eqs. "Alpha")
+$ if alpha then lnkopt = lnkopt + "/section"
+$!
+$! smw 2001/5/2 force no dsf files for now - later check axp and logical
+$ dsffiles = 0
+$!
+$ @gtm$tools:setactive_silent 'p1' 'p2'
+$ set def 'p3'
+$ targdir = f$parse("*.*",,,"device")+f$parse("*.*",,,"directory")
+$ set def gtm$vrt
+$ set def gtm$exe
+$ if f$search("gtmshr.olb") .eqs. "" then gtm_library/create gtmshr.olb
+$ if f$search("gtmlib.olb") .eqs. "" then gtm_library/create gtmlib.olb
+$ set def [.obj]
+$ objdir = f$parse("*.*",,,"device")+f$parse("*.*",,,"directory")
+$ define/nolog obd 'objdir'mumps.olb ! used by secshrlink.axp
+$ define/nolog urd 'objdir'user_rundown.obj
+$ gtm_library /extract=user_rundown /out=user_rundown mumps.olb
+$ set def 'targdir'
+$ set def [.map]
+$ mapfile = f$parse("*.*",,,"device")+f$parse("*.*",,,"directory")
+$ set def [-]
+$!
+$! ---------- prepare options for the linker in .opt files -----------
+$!
+$ open/write relnam release_name.opt
+$ write relnam "ident=",p1
+$ close relnam
+$!
+$! ---------- build gtmsecshr -----------
+$!
+$ @gtm$tools:build_print_stage "Building GTMSECSHR" "middle"
+$ secshrlink = "secshrlink." + f$element(alpha,",","vax,axp")
+$ gtmsecshrdsf = ""
+$ if dsffiles then gtmsecshrdsf = "/dsf=gtmsecshr.dsf"
+$ define/user target 'targdir'
+$ link /protect/notrace/share='targdir'gtmsecshr.exe 'gtmsecshrdsf' 'lnkopt' -
+ /map='mapfile'gtmsecshr.map/full gtm$tools:'secshrlink'/opt,sys$input/opt,target:release_name.opt/opt
+name = GTMSECSHR.EXE
+$ set prot=(o:rewd,s:rewd,g:re,w:re) 'targdir'gtmsecshr.exe
+$!
+$! ---------- build crashandburn -----------
+$!
+$ @gtm$tools:build_print_stage "Building CRASHANDBURN" "middle"
+$ ccopts := /standard=vaxc/share_globals/float=g_float/warn=disable=(signedknown,signedmember,questcompare,questcompare1)
+$ ccopts = ccopts + "/inc=(gtm$src:,tcpip$examples:)/assume=nowritable_string_literals/nolist/define=(TEST_REPL"
+$ if "P" .nes. f$edit(f$extract(0, 1, p2), "UPCASE") then $ ccopts = ccopts + ",DEBUG"
+$ ccopts = ccopts + ")"
+$ if "D" .eqs. f$edit(f$extract(0, 1, p2), "UPCASE") then $ ccopts = ccopts + "/nooptimize/debug"
+$ cc'ccopts'/object=urd gtm$src:USER_RUNDOWN.C
+$ define/user target 'targdir'
+$ link /protect/notrace/share='targdir'crashandburn.exe 'lnkopt' -
+ /map='mapfile'crashandburn.map/full gtm$tools:'secshrlink'/opt,sys$input/opt,target:release_name.opt/opt
+name = CRASHANDBURN.EXE
+$ if (f$parse(targdir,,,,"NO_CONCEAL") - "][") .eqs. (f$parse("GTM$ROOT:[" + P1 + ".PRO]",,,,"NO_CONCEAL") - "][")
+$ then
+$ newsec = p1 + "_gtmsecshr.exe"
+$ newburn = p1 + "_crashandburn.exe"
+$ gtm_copy gtmsecshr.exe 'newsec'
+$ gtm_copy crashandburn.exe 'newburn'
+$ if dsffiles
+$ then
+$ newdsf = p1 + "_gtmsecshr.dsf"
+$ gtm_copy gtmsecshr.dsf 'newdsf'
+$ endif
+$ curpriv=f$setprv("bypas")
+$ gtm_copy 'newsec' gtm$sec:
+$ curpriv=f$setprv(curpriv)
+$ curpriv=f$setprv("cmkrnl")
+$ install replace/header/share/protect/open gtm$sec:'newsec'
+$
+$! install remove older version 'p1'_crashandburn.exe in case it was previously installed
+$ define/user sys$output nl:
+$ define/user sys$error nl:
+$ install remove gtm$root:['p1'.pro]'newburn'
+$
+$ curpriv=f$setprv(curpriv)
+$ newsec = newsec + ","
+$ else
+$ newsec :=
+$ endif
+$ gtm_delete 'f$trnlnm("urd").
+$!
+$! pur/log 'targdir''newsec'gtmsecshr.exe,'mapfile'gtmsecshr.map
+$!
+$ @gtm$tools:build_print_stage "buildsec" "end"
+$ @gtm$tools:gtm_verify_symbols "unset" ! unsets the global symbols gtm_copy, gtm_delete gtm_library, gtm_purge
+$ exit
diff --git a/sr_vvms/buildshr.com b/sr_vvms/buildshr.com
new file mode 100644
index 0000000..17b25fd
--- /dev/null
+++ b/sr_vvms/buildshr.com
@@ -0,0 +1,208 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2012 Fidelity Information Services, Inc !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$! buildshr - build a shareable image
+$! parameters:
+$! p1 = version number
+$! p2 = library (p, d, or b)
+$! p3 = target device and directory
+$!
+$ if p1 .eqs. ""
+$ then
+$ write sys$output "Must supply a version"
+$ exit
+$ endif
+$!
+$ lnkimg=f$locate(p2,"PBD")
+$ if (f$length(p2) .ne. 1) .or. (lnkimg .eq. 3)
+$ then
+$ write sys$output "Library must be P, B or D"
+$ exit
+$ endif
+$!
+$ if p3 .eqs. ""
+$ then
+$ write sys$output "Must specify a target directory for the .exe files"
+$ exit
+$ endif
+$!
+$ @gtm$tools:gtm_verify_symbols "set" ! sets the global symbols gtm_copy, gtm_delete, gtm_library, gtm_purge
+$ @gtm$tools:build_print_stage "buildshr" "begin"
+$!
+$! ---------- buildshr set linker options -----------
+$!
+$ lnkopt = f$element(lnkimg,",","/notrace,/debug,/debug")
+$ alpha = (f$getsyi("arch_name") .eqs. "Alpha")
+$ if alpha then lnkopt = lnkopt + "/section"
+$!
+$! smw 2001/5/2 force no dsf files for now - later check axp and logical
+$ dsffiles = 0
+$!
+$ @gtm$tools:setactive_silent 'p1' 'p2'
+$ set def gtm$vrt
+$ set def gtm$exe
+$ if f$search("gtmshr.olb") .eqs. "" then gtm_library/create gtmshr.olb
+$ if f$search("gtmlib.olb") .eqs. "" then gtm_library/create gtmlib.olb
+$ set def 'p3'
+$ targdir = f$parse("*.*",,,"device")+f$parse("*.*",,,"directory")
+$ set def gtm$vrt
+$ set def gtm$exe
+$ set def [.obj]
+$ objdir = f$parse("*.*",,,"device")+f$parse("*.*",,,"directory")
+$ set def 'targdir'
+$ set def [.map]
+$ mapfile = f$parse("*.*",,,"device")+f$parse("*.*",,,"directory")
+$ set def [-]
+$!
+$! ---------- buildshr prepare options for the linker in .opt files -----------
+$!
+$ open/write relnam release_name.opt
+$ write relnam "ident=",p1
+$ close relnam
+$!
+$ open/write secshrlink secshrlink.opt
+$ if ("" .eqs. f$trnlnm("gtm_no_secshr")) .or. (p2 .nes. "P")
+$ then
+$ write secshrlink "gtm$pro:gtmsecshr.exe/share"
+$ endif
+$ close secshrlink
+$!
+$! ---------- buildshr gtmshr (after determining filler) -----------
+$!
+$ fillname = ""
+$!
+$ if (lnkimg .eq. 0) .and. ((f$extract(0,2,p1) .nes. "V9") .or. (p1 .eqs. "V999")) ! keep the pro image size stable
+$ then
+$ @gtm$tools:build_print_stage "Building template GTMSHR" "middle"
+$ @gtm$tools:linkshr 'targdir' 'objdir' 'lnkopt'/share=nl:/map=sizemap.tmp/brief ""
+$ search/out=temp.tmp sizemap.tmp "virtual memory allocated"
+$ if 1 .ne. $severity
+$ then
+$ write sys$output "%GTM-F-BUILDCHK, Check map (sizemap.tmp) format"
+$ @gtm$tools:gtm_verify_symbols "unset" ! unsets the global symbols gtm_copy, gtm_delete gtm_library, gtm_purge
+$ exit
+$ endif
+$ open/read temp temp.tmp
+$ read temp a
+$ close temp
+$ x = f$locate(",",a) + 1
+$ a = f$extract(x,99,a)
+$ image_size = f$extract(1,f$locate(".",a)-1,a)
+$ if 0 .eq. f$integer(image_size)
+$ then
+$ write sys$output "%GTM-F-BUILDCHK, Check map (sizemap.tmp) virtual memory pages"
+$ @gtm$tools:gtm_verify_symbols "unset" ! unsets the global symbols gtm_copy, gtm_delete gtm_library, gtm_purge
+$ exit
+$ endif
+$ gtm_delete temp.tmp;*,sizemap.tmp;*
+$ if alpha
+$ then
+$! Note: pages are 512 bytes
+$ page_target = 6000
+$ if f$extract(1,4,p1) .eqs. "60FT" .or. f$extract(1,4,p1) .eqs. "60BL"
+$ then
+$ if f$extract(5,2,p1) .lts. "09" then $ page_target = 5120
+$ endif
+$ if f$extract(1,5,p1) .les. "60000" then $ page_target = 5120
+$ if f$extract(1,2,p1) .lts. "43" then $ page_target = 4000
+$ else
+$ page_target = 2000
+$ if f$extract(0,3,p1) .eqs. "V42" then $ page_target = 1600
+$ if f$extract(0,3,p1) .eqs. "V40" then $ page_target = 1200
+$ if f$extract(0,3,p1) .eqs. "V32" then $ page_target = 1200
+$ if f$extract(0,3,p1) .eqs. "V31" then $ page_target = 1000
+$ if f$extract(0,2,p1) .eqs. "V2" then $ page_target = 950
+$ endif
+$ if image_size .lt. page_target
+$ then
+$ fillname = "gtmfiller." + f$element(alpha,",","mar,m64")
+$ create 'fillname'
+ .title gtmfiller - patch & expansion space
+ .psect gtmfiller,con,nord,noexe,nowrt,pic,shr,gbl
+$ open/append fill 'fillname'
+$ write fill "page_target = ",page_target
+$ write fill "actual_pages = ",image_size
+$ write fill " .blkb <page_target - actual_pages> * 512"
+$ write fill " .end"
+$ close fill
+$ if f$environment("VERIFY_PROCEDURE") then write sys$output "[BUILDSHR-I-IMAGESIZE Actual size ",image_size," pages]"
+$ qual = f$element(alpha,",",",/alpha")
+$ fillname := gtmfiller
+$ macro'qual'/nolist gtmfiller
+$ else
+$ write sys$output "%BUILDSHR-W-IMAGESIZE Image size (",image_size,") is greater than target size of ",page_target
+$ endif
+$ endif
+$!
+$ @gtm$tools:build_print_stage "Building real GTMSHR" "middle"
+$ gtmshrdsf = ""
+$ if dsffiles then gtmshrdsf = "/dsf=gtmshr.dsf"
+$ @gtm$tools:linkshr 'targdir' 'objdir' 'lnkopt'/symb='mapfile'gtmshr.stb/share=gtmshr.exe/map='mapfile'gtmshr.map/full'gtmshrdsf' 'fillname'
+$ if fillname .nes. "" then $ gtm_delete gtmfiller.obj;*,gtmfiller.m%%;*
+$!
+$! ---------- buildshr mcompile -----------
+$!
+$ @gtm$tools:build_print_stage "Building MCOMPILE" "middle"
+$ define/user objlib 'objdir'mumps.olb
+$ define/user target 'targdir'
+$ set def 'targdir'
+$ mcompdsf = ""
+$ if dsffiles then mcompdsf = "/dsf=mcompile.dsf"
+$ link/exe=mcompile.exe/map=[.map]mcompile.map/full'lnkopt' 'mcompdsf' objlib/incl=mcompile,sys$input/opt,target:release_name/opt
+stack = 256
+name = MCOMPILE.EXE
+target:gtmshr.exe/share
+$!
+$! ---------- buildshr create gtmshr.olb and gtmlib.olb -----------
+$!
+$ @gtm$tools:build_print_stage "Creating GTMSHR.OLB and GTMLIB.OLB" "middle"
+$ gtm_library/create=(block:5,hist:0,modu:3,glob:10)/share gtmshr.olb
+$ gtm_library gtmshr.olb gtmshr.exe
+$ gtm_library/create=(block:5,hist:0,modu:3,glob:10) gtmlib.olb
+$ gtm_library/extract=(gtm_main,gtm$defaults,gtmi$def)/out=gtm_main 'objdir'mumps
+$ gtm_library gtmlib.olb gtm_main.obj
+$ set noon
+$ gtm_library/extract=gtm_zc/out=gtm_zc 'objdir'mumps
+$ severity = $severity
+$ set on
+$ if severity .eq. 1
+$ then
+$ gtm_library gtmlib.olb gtm_zc
+$ gtm_delete gtm_zc.obj;*
+$ endif
+$!
+$! ---------- buildshr gtm$dmod -----------
+$!
+$ @gtm$tools:build_print_stage "Building GTM$DMOD" "middle"
+$!
+$! use production images to compile GTM$DMOD.M
+$ @gtm$tools:setactive_silent 'p1' p
+$ set def [.obj]
+$ set command gtm$src:GTMCOMMANDS.CLDX ! define MUMPS command if .cldx file present
+$ mumps gtm$src:gtm$dmod.m
+$ gtm_library /replace mumps gtm$dmod.obj
+$ gtm_delete gtm$dmod.obj;
+$ set def [-]
+$ @gtm$tools:setactive_silent 'p1' 'p2' ! revert back to currently building image
+$!
+$ dmoddsf = ""
+$ if dsffiles then dmoddsf = "/dsf=gtm$dmod.dsf"
+$ define/user target 'targdir'
+$ link/map=[.map]gtm$dmod.map/full/exe=gtm$dmod.exe'lnkopt' 'dmoddsf' 'objdir'mumps/includ=gtm$dmod,sys$input/opt,target:release_name/opt
+name = GTM$DMOD.EXE
+$!
+$! ---------- buildshr end -----------
+$!
+$ gtm_delete gtm_main.obj.*,release_name.opt;*,secshrlink.opt;*
+$ @gtm$tools:build_print_stage "buildshr" "end"
+$!
+$ @gtm$tools:gtm_verify_symbols "unset" ! unsets the global symbols gtm_copy, gtm_delete gtm_library, gtm_purge
+$ exit
diff --git a/sr_vvms/buildtcx.com b/sr_vvms/buildtcx.com
new file mode 100644
index 0000000..84f704c
--- /dev/null
+++ b/sr_vvms/buildtcx.com
@@ -0,0 +1,93 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2003 Sanchez Computer Associates, Inc. !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$! buildtcx - build gt.cx
+$! parameters:
+$! p1 = version number
+$! p2 = library (p, d, or b)
+$! p3 = target device and directory
+$!
+$ if p1 .eqs. ""
+$ then
+$ write sys$output "Must supply a version"
+$ exit
+$ endif
+$!
+$ lnkimg=f$locate(p2,"PBD")
+$ if (f$length(p2) .ne. 1) .or. (lnkimg .eq. 3)
+$ then
+$ write sys$output "Library must be P, B or D"
+$ exit
+$ endif
+$!
+$ if p3 .eqs. ""
+$ then
+$ write sys$output "Must specify a target directory for the .exe files"
+$ exit
+$ endif
+$!
+$ @gtm$tools:gtm_verify_symbols "set" ! sets the global symbols gtm_copy, gtm_delete, gtm_library, gtm_purge
+$ @gtm$tools:build_print_stage "buildtcx" "begin"
+$!
+$! ---------- buildtcx set linker options -----------
+$!
+$ lnkopt = f$element(lnkimg,",","/notrace,/debug,/debug")
+$ alpha = (f$getsyi("arch_name") .eqs. "Alpha")
+$ if alpha then lnkopt = lnkopt + "/section"
+$!
+$ @gtm$tools:setactive_silent 'p1' 'p2'
+$ set def 'p3'
+$ targdir = f$parse("*.*",,,"device")+f$parse("*.*",,,"directory")
+$ set def gtm$vrt
+$ set def gtm$exe
+$ set def [.obj]
+$ objdir = f$parse("*.*",,,"device")+f$parse("*.*",,,"directory")
+$ set def 'targdir'
+$ set def [.map]
+$ mapfile = f$parse("*.*",,,"device")+f$parse("*.*",,,"directory")
+$ set def [-]
+$!
+$! ---------- buildtcx prepare options for the linker in .opt files -----------
+$!
+$ open/write relnam release_name.opt
+$ write relnam "ident=",p1
+$ close relnam
+$!
+$ open/write secshrlink secshrlink.opt
+$ if ("" .eqs. f$trnlnm("gtm_no_secshr")) .or. (p2 .nes. "P")
+$ then
+$ write secshrlink "gtm$pro:gtmsecshr.exe/share"
+$ endif
+$ close secshrlink
+$!
+$! ---------- buildtcx ccp -----------
+$!
+$ @gtm$tools:build_print_stage "Building CCP" "middle"
+$ define/user target 'targdir'
+$ link/map='mapfile'CCP.map/exe='targdir'CCP.exe'lnkopt' 'objdir'mumps/lib/inc=CCP,sys$input/opt,target:secshrlink.opt/opt,target:release_name.opt/opt
+name = CCP.EXE
+$!
+$! ---------- buildtcx cce -----------
+$!
+$ @gtm$tools:build_print_stage "Building CCE" "middle"
+$ define/user target 'targdir'
+$ link/map='mapfile'CCE.map/exe='targdir'CCE.exe'lnkopt' 'objdir'mumps/lib/inc=CCE,sys$input/opt,target:secshrlink.opt/opt,target:release_name.opt/opt
+name = CCE.EXE
+$!
+$! ---------- buildtcx end -----------
+$!
+$ gtm_purge
+$ gtm_purge [.map]*.*
+$ gtm_delete release_name.opt;*,secshrlink.opt;*
+$!
+$ @gtm$tools:build_print_stage "buildtcx" "end"
+$ @gtm$tools:gtm_verify_symbols "unset" ! unsets the global symbols gtm_copy, gtm_delete gtm_library, gtm_purge
+$ exit
diff --git a/sr_vvms/cce.c b/sr_vvms/cce.c
new file mode 100644
index 0000000..c946352
--- /dev/null
+++ b/sr_vvms/cce.c
@@ -0,0 +1,88 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <climsgdef.h>
+#include <descrip.h>
+#include <rmsdef.h>
+
+#include "gdsroot.h"
+#include "ccp.h"
+#include "ccpact.h"
+#include "getjobnum.h"
+#include "dfntmpmbx.h"
+#include "get_page_size.h"
+#include "gtm_env_init.h" /* for gtm_env_init() prototype */
+#include "gtm_threadgbl_init.h"
+
+GBLDEF uint4 ret_status = 1;
+
+static bool cce_done;
+
+cce()
+{
+ $DESCRIPTOR(prompt,"CCE> ");
+ int status;
+ char buff[512];
+ $DESCRIPTOR(command,buff);
+ unsigned short outlen;
+ mstr lnm$group = {9, "LNM$GROUP"};
+ int CCE_CMD(), CLI$DCL_PARSE(), CLI$DISPATCH();
+ DCL_THREADGBL_ACCESS;
+
+ GTM_THREADGBL_INIT; /* This is the first C routine in the cce so do init here */
+ gtm_env_init(); /* read in all environment variables before any function call (particularly malloc) */
+ getjobnum();
+ get_page_size();
+ dfntmpmbx (lnm$group.len, lnm$group.addr);
+ status = lib$get_foreign(&command,0,&outlen,0);
+ if ((status & 1) && outlen > 0)
+ { command.dsc$w_length = outlen;
+ status = CLI$DCL_PARSE(&command ,&CCE_CMD, &lib$get_input, 0, 0);
+ if (status == CLI$_NORMAL)
+ CLI$DISPATCH();
+ }else
+ { while (!cce_done)
+ {
+ status = CLI$DCL_PARSE(0 ,&CCE_CMD, &lib$get_input
+ , &lib$get_input, &prompt);
+ if (status == RMS$_EOF)
+ cce_done = TRUE;
+ else if (status == CLI$_NORMAL)
+ {
+ ret_status = 1;
+ CLI$DISPATCH();
+ }
+ }
+ }
+ return ret_status;
+}
+
+void cce_stop()
+{
+
+ ccp_sendmsg(CCTR_STOP, 0);
+ return;
+}
+
+void cce_debug()
+{
+
+ ccp_sendmsg(CCTR_DEBUG, 0);
+ return;
+}
+
+void cce_exit()
+{
+ cce_done = TRUE;
+ return;
+}
diff --git a/sr_vvms/cce.hlp b/sr_vvms/cce.hlp
new file mode 100644
index 0000000..1c6b751
--- /dev/null
+++ b/sr_vvms/cce.hlp
@@ -0,0 +1,253 @@
+
+1 Overview
+ Overview
+ The principle components of GT.CX are the CCP and the utility
+ program, CCE. The CCE examines and changes conditions for
+ clustered operation. Use the CCE to:
+
+ o Change database files to and from clustered operation
+ o Control the time processes will wait without reporting an error
+ for access to clustered files
+ o Examine the status of files, locks and the CCP
+ o Stop the CCP
+
+2 Use of CCE
+ Use of CCE
+ CCE prompts for all required information. Use HELP to invoke
+ online information about CCE. SET FILE /CLUSTER to change a new or
+ previously non-clustered file to clustered operation. SET FILE
+ /NORESPONSE to make cluster access failures hang processes rather
+ than giving errors. STOP the CCP when terminating clustered
+ operation. When the CCE session is complete, EXIT.
+1 Commands
+ Commands
+ CCE commands can be entered at the CCE> prompt or as parameters to
+ the CCE command when CCE is defined as a foreign command.
+
+ Example:
+
+ $ CCE
+ CCE> STOP
+ CCE>
+
+ or
+
+ $ CCE STOP
+ $
+
+ CCE commands, command parameters and qualifiers may be abbreviated
+ using enough characters from the beginning of the command to
+ unambiguously identify the keyword. CCE keywords can always be
+ abbreviated to 4 characters or less. The description for each
+ command identifies the current minimum abbreviations by showing the
+ optional part of the keyword in square brackets ([]).
+1 EXIT
+ E[XIT]
+ The EXIT command terminates an CCE session. The syntax for the
+ EXIT command is:
+
+ E[XIT]
+
+ Example:
+
+ CCE> EXIT
+ $
+
+1 HELP
+ H[ELP]
+ The HELP command displays online information about CCE commands and
+ qualifiers, using the VMS help facility. HELP takes an optional
+ parameter which specifies a topic on which you desire help. Exit
+ from HELP by entering <RET> enough times to leave all nested levels
+ or by entering <CTRL Z>. The syntax for the HELP command is:
+
+ H[ELP] [topic]
+
+ Example:
+
+ CCE> HELP SET
+
+ This command would display help on the SET command.
+1 QUIT
+ Q[UIT]
+ The QUIT command is synonymous with the EXIT command and terminates
+ CCE. The syntax for the QUIT command is:
+
+ Q[UIT]
+
+1 SET
+ SE[T]
+ The SET command changes clustering characteristics. The syntax for
+ the SET command is:
+
+ SE[T] F[ILE] file-spec set-file-qualifier
+
+ SET FILE makes a file clustered or non-clustered and/or alters the
+ cluster timers. The set-file-qualifiers determine the exact SET
+ FILE action
+
+ Several set-file-qualifiers have time arguments which share the
+ following characteristics:
+ o they accept a VMS delta-time.
+ o the maximum time accepted is 00:59:59.99. Because the format
+ is hh:mm:ss, normally it is specified as 00:00:ss.
+ o if no argument is supplied, the default value is reestablished.
+
+2 /CLUSTER
+ /C[LUSTER]
+ The /CLUSTER qualifier controls whether a file is non-clustered or
+ clustered. The syntax for the CLUSTER qualifier is:
+
+ /[NO]C[LUSTER]
+
+ In order for SET FILE/[NO]CLUSTER to successfully switch a file
+ between modes of operation, the file must be quiescent, i.e. no
+ process may currently be accessing the file.
+
+ A clustered file is open to all members of the cluster which have
+ active CCPs. A non-clustered file is restricted to access by the
+ first node of the cluster to open the file. Only databases with BG
+ access method can be clustered. When files are created by MUPIP
+ CREATE they are non-clustered.
+2 /QUANTUM_INTERVAL
+ /QUANTUM_INTERVAL
+ The /QUANTUM_INTERVAL should only be changed on instructions from
+ Greystone. The syntax for the /QUANTUM_INTERVAL qualifier is:
+
+ /Q[UANTUM_INTERVAL]=delta-time
+
+2 /RESPONSE_INTERVAL
+ /RESPONSE_INTERVAL
+ The /RESPONSE_INTERVAL qualifier controls how long a GT.M process
+ will wait for a response from the CCP before reporting an error.
+ The syntax for the /RESPONSE_INTERVAL qualifier is:
+
+ /[NO]R[ESPONSE_INTERVAL]=delta-time
+
+ If a member of the cluster has a capacity problem seriously
+ affecting response time, increasing the RESPONSE_INTERVAL may
+ prevent database timeout errors.
+
+ If a database cannot be accessed within the RESPONSE_INTERVAL, the
+ default error handling strategy is to inform the application
+ program with an error. The application program may then notify the
+ user and/or operator and retry or halt. /NORESPONSE_INTERVAL or
+ RESPONSE_INTERVAL=0 permit the alternate approach of suspending the
+ application program until the problem is resolved by an operator.
+ In this case CCP operator messages or stalling of normal activity
+ are relied upon to signal the error.
+
+ The default RESPONSE_INTERVAL is 1 minute.
+2 /STALE_INTERVAL
+ /STALE_INTERVAL
+ The /STALE_INTERVAL qualifier controls how long a cluster member
+ not active in updating the file may operate before verifying any
+ local copies of database information. The syntax for the
+ /STALE_INTERVAL qualifier is:
+
+ /[NO]S[TALE_INTERVAL]=delta-time
+
+ Increasing the STALE_INTERVAL may slightly reduce system overhead.
+
+ A cluster member updating a file or LOCKing a name mapped to a file
+ is forced to constantly verify synchronization with that file. A
+ cluster member exclusively reading a file is allowed to have local
+ copies of database information which may not be current. The
+ STALE_INTERVAL controls how "out of date" local copies can be.
+
+ /NOSTALE_INTERVAL or /STALE_INTERVAL=0 turns off the staleness
+ timer. This is appropriate only if all cluster members constantly
+ mix reads and writes or if a cluster member exclusively reading can
+ function properly using perceptibly out of date information.
+
+ The default STALE_INTERVAL is 5 seconds.
+2 /TICK_INTERVAL
+ /TICK_INTERVAL
+ The /TICK_INTERVAL should only be changed on instructions from
+ Greystone. The syntax for the /TICK_INTERVAL qualifier is:
+
+ /T[ICK_INTERVAL]=delta-time
+
+2 Examples
+ Examples
+
+ CCE>SET FILE MUMPS.DAT/CLUSTER/STALE=00:00:10
+
+ This command would make the file MUMPS.DAT clustered and change the
+ STALE_TIMER to 10 seconds.
+
+ CCE>SET FILE TEMP.DAT/NOCLUSTER
+
+ This command would make the file TEMP.DAT non-clustered.
+1 SHOW
+ SH[OW]
+ The SHOW command displays information on locks, database files or
+ CCP activity. The syntax for the SHOW command is:
+
+ SH[OW] C[CP] | F[ILE] file-spec
+ | L[OCKS] | T[RANSACTIONS] [ /O[UT]=file-spec ]
+
+2 CCP
+ C[CP]
+ SHOW CCP displays the status of the CCP for the node in the
+ cluster. If a CCP is running and the CCE user has the SYSLCK
+ privilege, this command reports the PID of the CCP and how many
+ processes are accessing clustered databases.
+
+ Example:
+
+ CCE>SHOW CCP
+
+ %GTM-I-CCENOCCP, The cluster control program is not running on this
+ node
+
+2 FILE
+ F[ILE]
+ SHOW FILE displays the clustering status of a database file. The
+ status includes whether the file is clustered and the timer
+ intervals for that file.
+
+ Example:
+
+ CCE>SHOW FILE MUMPS.DAT
+
+ Database file MUMPS.DAT is a cluster database
+ STALE_INTERVAL 00:00:05.00
+ RESPONSE_INTERVAL 00:01:00.00
+ QUANTUM_INTERVAL 00:00:01.00
+ TICK_INTERVAL 00:00:00.10
+
+2 LOCKS
+ L[OCKS]
+ SHOW LOCKS displays the VMS locks used by GT.CX and GT.M on the
+ node. SHOW LOCKS does not display locks the CCE process does not
+ have privileges to examine. The meaning of the lock display is not
+ documented for the user and this command is intended for use only
+ under the direction of Greystone.
+2 TRANSACTIONS
+ T[RANSACTIONS]
+ SHOW TRANSACTIONS displays the 100 most recent CCP actions. The
+ meaning of the transaction display is not documented for the user
+ and this command is intended for use only under the direction of
+ Greystone.
+2 /OUT
+ /O[UT]
+ SHOW LOCKS and SHOW TRANSACTIONS accept the /OUT= qualifier for
+ directing the display to a file. By default the output is directed
+ to SYS$OUTPUT.
+1 STOP
+ ST[OP]
+ The STOP command terminates the Cluster Control Program and
+ therefore all access from this node to clustered databases. The
+ syntax for the STOP command is:
+
+ ST[OP]
+
+ If possible, use this command after application procedures cause
+ all processes to drop their interest in the clustered file(s).
+
+ Example:
+
+ CCE>STOP
+
+ This command would stop the CCP.
diff --git a/sr_vvms/cce_ccp.c b/sr_vvms/cce_ccp.c
new file mode 100644
index 0000000..7576491
--- /dev/null
+++ b/sr_vvms/cce_ccp.c
@@ -0,0 +1,118 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <prvdef.h>
+#include <ssdef.h>
+#include <descrip.h>
+#include <dvidef.h>
+#include <jpidef.h>
+#include <efndef.h>
+
+#include "vmsdtype.h"
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "ccp.h"
+#include "ccpact.h"
+
+GBLREF uint4 ret_status;
+
+cce_ccp()
+{
+ struct
+ {
+ item_list_3 item[2];
+ int4 terminator;
+ } item_list;
+ uint4 status;
+ char out_str[15];
+ $DESCRIPTOR(out_desc,out_str);
+ unsigned short out_len;
+ short dvisb[4];
+ int4 refnum, pid, pidadr;
+ short dummy;
+ int4 prvadr[2], prvprv[2];
+ int4 iosb[2];
+ short ccp_channel;
+ error_def(ERR_CCENOCCP);
+ error_def(ERR_CCECCPPID);
+ error_def(ERR_CCECLSTPRCS);
+ error_def(ERR_CCENOWORLD);
+ error_def(ERR_CCENOGROUP);
+
+ lib$establish(cce_ccp_ch);
+ ccp_channel = ccp_sendmsg(CCTR_NULL,0);
+ lib$revert();
+ if (!ccp_channel)
+ {
+ ret_status = ERR_CCENOCCP;
+ lib$signal(ERR_CCENOCCP);
+ return;
+ }
+ prvadr[0] = PRV$M_WORLD;
+ prvadr[1] = 0;
+ status = sys$setprv(TRUE, &prvadr[0], FALSE, &prvprv[0]);
+ if (status != SS$_NORMAL)
+ { lib$signal(ERR_CCENOWORLD);
+ prvadr[0] = PRV$M_GROUP;
+ prvadr[1] = 0;
+ status = sys$setprv(TRUE, &prvadr[0], FALSE, &prvprv[0]);
+ if (status != SS$_NORMAL)
+ { lib$signal(ERR_CCENOGROUP);
+ }
+ }
+ item_list.item[0].buffer_length = SIZEOF(pid);
+ item_list.item[0].buffer_address = &pid;
+ item_list.item[0].item_code = JPI$_PID;
+ item_list.item[0].return_length_address = &dummy;
+ item_list.item[1].buffer_length = 15;
+ item_list.item[1].buffer_address = out_str;
+ item_list.item[1].item_code = JPI$_PRCNAM;
+ item_list.item[1].return_length_address = &out_len;
+ item_list.terminator = 0;
+ pidadr = -1;
+ for (; ;)
+ { status = sys$getjpiw(EFN$C_ENF,&pidadr,0,&item_list,&iosb,0,0);
+ if (status == SS$_NORMAL && out_len == (SIZEOF(CCP_PRC_NAME) - 1)
+ && memcmp(&out_str[0],CCP_PRC_NAME,(SIZEOF(CCP_PRC_NAME) - 1)) == 0)
+ { lib$signal(ERR_CCECCPPID,1,pid);
+ break;
+ }
+ if (status == SS$_NOMOREPROC)
+ break;
+ }
+ refnum = 0;
+ memset(&item_list, 0, SIZEOF(item_list));
+ item_list.item[0].buffer_length = SIZEOF(refnum);
+ item_list.item[0].buffer_address = &refnum;
+ item_list.item[0].item_code = DVI$_REFCNT;
+ item_list.item[0].return_length_address = &dummy;
+ status = sys$getdviw (0, ccp_channel, 0, &item_list, &dvisb, 0, 0, 0);
+ if (status != SS$_NORMAL)
+ { lib$signal(status);
+ if (prvprv[0] & prvadr[0] == 0)
+ { sys$setprv(FALSE, &prvadr[0], FALSE, 0);
+ }
+ return;
+ }
+ if (pid)
+ { lib$signal(ERR_CCECLSTPRCS,1,refnum - 2);
+ }else
+ { lib$signal(ERR_CCECLSTPRCS,1,refnum - 1);
+ }
+ if (prvprv[0] & prvadr[0] == 0)
+ { sys$setprv(FALSE, &prvadr[0], FALSE, 0);
+ }
+ return;
+}
diff --git a/sr_vvms/cce_ccp_ch.c b/sr_vvms/cce_ccp_ch.c
new file mode 100644
index 0000000..a25a5c0
--- /dev/null
+++ b/sr_vvms/cce_ccp_ch.c
@@ -0,0 +1,15 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+void cce_ccp_ch()
+{
+return;
+}
diff --git a/sr_vvms/cce_ccpdmp.c b/sr_vvms/cce_ccpdmp.c
new file mode 100644
index 0000000..4ecf64d
--- /dev/null
+++ b/sr_vvms/cce_ccpdmp.c
@@ -0,0 +1,106 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <ssdef.h>
+#include <prvdef.h>
+#include "vmsdtype.h"
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "ccp.h"
+#include "ccpact.h"
+#include <jpidef.h>
+#include <efndef.h>
+
+#include "cli.h"
+
+void cce_ccpdmp(void)
+{
+
+ struct
+ {
+ item_list_3 item[2];
+ int4 terminator;
+ } item_list;
+ short ccp_channel, dummy, out_len, iosb[4];
+ int4 prvadr[2], prvprv[2], pid, pidadr, status;
+ char out_str[15];
+ uint4 dumpon,dumpnow;
+ int4 error;
+ error_def(ERR_CCEDUMPNOW);
+ error_def(ERR_CCEDUMPON);
+ error_def(ERR_CCEDUMPOFF);
+ error_def(ERR_CCENOCCP);
+ error_def(ERR_NOCCPPID);
+ error_def(ERR_CCEDMPQUALREQ);
+
+ if (cli_present("DB") == CLI_PRESENT)
+ { cce_dbdump();
+ return;
+ }
+ lib$establish(cce_ccp_ch);
+ ccp_channel = ccp_sendmsg(CCTR_NULL,0);
+ lib$revert();
+ if (!ccp_channel)
+ { rts_error(VARLSTCNT(1) ERR_CCENOCCP);
+ return;
+ }
+ dumpnow = cli_present("NOW");
+ if (dumpnow != CLI_PRESENT && ((dumpon = cli_present("ON")) != CLI_PRESENT) && (dumpon != CLI_NEGATED))
+ { rts_error(VARLSTCNT(1) ERR_CCEDMPQUALREQ);
+ return;
+ }
+ if (dumpon == CLI_NEGATED)
+ dumpon = FALSE;
+ prvadr[0] = PRV$M_WORLD;
+ prvadr[1] = 0;
+ status = sys$setprv(TRUE, &prvadr[0], FALSE, &prvprv[0]);
+ if (status != SS$_NORMAL)
+ { prvadr[0] = PRV$M_GROUP;
+ prvadr[1] = 0;
+ sys$setprv(TRUE, &prvadr[0], FALSE, &prvprv[0]);
+ }
+ item_list.item[0].buffer_length = SIZEOF(pid);
+ item_list.item[0].buffer_address = &pid;
+ item_list.item[0].item_code = JPI$_PID;
+ item_list.item[0].return_length_address = &dummy;
+ item_list.item[1].buffer_length = 15;
+ item_list.item[1].buffer_address = out_str;
+ item_list.item[1].item_code = JPI$_PRCNAM;
+ item_list.item[1].return_length_address = &out_len;
+ item_list.terminator = 0;
+ pidadr = -1;
+ for (; ;)
+ { status = sys$getjpiw(EFN$C_ENF,&pidadr,0,&item_list,&iosb,0,0);
+ if (status == SS$_NORMAL && out_len == (SIZEOF(CCP_PRC_NAME) - 1)
+ && memcmp(&out_str[0],CCP_PRC_NAME,(SIZEOF(CCP_PRC_NAME) - 1)) == 0)
+ break;
+ if (status == SS$_NOMOREPROC)
+ { rts_error(VARLSTCNT(1) ERR_NOCCPPID);
+ return;
+ }
+ }
+ if (dumpnow == CLI_PRESENT)
+ error = ERR_CCEDUMPNOW;
+ else if (dumpon == CLI_PRESENT)
+ error = ERR_CCEDUMPON;
+ else
+ error = ERR_CCEDUMPOFF;
+ status = sys$forcex(&pid,0,error);
+ if (status != SS$_NORMAL)
+ { rts_error(VARLSTCNT(1) status);
+ return;
+ }
+ return;
+}
diff --git a/sr_vvms/cce_cluster.c b/sr_vvms/cce_cluster.c
new file mode 100644
index 0000000..f74fcaa
--- /dev/null
+++ b/sr_vvms/cce_cluster.c
@@ -0,0 +1,170 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "gdsblk.h"
+#include <rmsdef.h>
+#include <fab.h>
+#include <xab.h>
+#include <ssdef.h>
+#include <iodef.h>
+#include <descrip.h>
+#include <climsgdef.h>
+#include <efndef.h>
+#include "cli.h"
+
+#include "filestruct.h"
+#include "util.h"
+#include "timers.h"
+#include "dbcx_ref.h"
+
+void cce_cluster(void )
+{
+ enum db_ver database;
+ char fn[256];
+ struct FAB ccpfab;
+ struct XABFHC xab;
+ sgmnt_data *old_data, *dummy_data;
+ short iosb[4];
+ unsigned short fn_len;
+ int4 status, size, cluster, space_needed;
+ error_def(ERR_CCERDERR);
+ error_def(ERR_CCEWRTERR);
+ error_def(ERR_CCEDBCL);
+ error_def(ERR_CCEDBNTCL);
+ error_def(ERR_CCEBADFN);
+ error_def(ERR_DBOPNERR);
+ error_def(ERR_DBNOTGDS);
+ error_def(ERR_BADDBVER);
+ error_def(ERR_CCEBGONLY);
+ $DESCRIPTOR(cluster_qualifier, "CLUSTER");
+
+ fn_len = SIZEOF(fn);
+ if (!cli_get_str("FILE",fn,&fn_len))
+ {
+ lib$signal(ERR_CCEBADFN);
+ return;
+ }
+ ccpfab = cc$rms_fab;
+ ccpfab.fab$l_fna = fn;
+ ccpfab.fab$b_fns = fn_len;
+ ccpfab.fab$b_fac = FAB$M_BIO | FAB$M_GET | FAB$M_PUT;
+ ccpfab.fab$l_fop = FAB$M_UFO;
+ xab = cc$rms_xabfhc;
+ ccpfab.fab$l_xab = &xab;
+ status = sys$open(&ccpfab);
+ if (status != RMS$_NORMAL)
+ {
+ lib$signal(ERR_DBOPNERR, 2, ccpfab.fab$b_fns, ccpfab.fab$l_fna, status);
+ return;
+ }
+ dummy_data = malloc(ROUND_UP(SIZEOF(sgmnt_data), OS_PAGELET_SIZE));
+ status = sys$qiow(EFN$C_ENF, ccpfab.fab$l_stv, IO$_READVBLK, iosb, 0, 0, dummy_data,
+ ROUND_UP(SIZEOF(sgmnt_data), OS_PAGELET_SIZE), 1,0,0,0);
+ if (status & 1)
+ status = iosb[0];
+ if ((status & 1) == 0)
+ {
+ lib$signal(ERR_CCERDERR, 2, ccpfab.fab$b_fns, ccpfab.fab$l_fna, status);
+ sys$dassgn(ccpfab.fab$l_stv);
+ free(dummy_data);
+ return;
+ }
+/*
+ Commented out as this is unused code and we are removing the old version database references
+ (SE - 4/2005 V5.0)
+ if (memcmp(&dummy_data->label[0], GDS_LABEL, GDS_LABEL_SZ))
+ { if (memcmp(&dummy_data->label[0], GDS_LABEL, GDS_LABEL_SZ - 3))
+ { lib$signal (ERR_DBNOTGDS, 2, ccpfab.fab$b_fns, ccpfab.fab$l_fna);
+ status = sys$dassgn(ccpfab.fab$l_stv);
+ assert(status & 1);
+ free(dummy_data);
+ return;
+ }else
+ {
+ if (!memcmp(&dummy_data->label[GDS_LABEL_SZ - 3],GDS_V23,2))
+ database = v23;
+ else if (!memcmp(&dummy_data->label[GDS_LABEL_SZ - 3],GDS_V24,2))
+ database = v24;
+ else if (!memcmp(&dummy_data->label[GDS_LABEL_SZ - 3],GDS_V25,2))
+ database = v25;
+ else if (!memcmp(&dummy_data->label[GDS_LABEL_SZ - 3],GDS_V254,2))
+ database = v254;
+ else
+ lib$signal (ERR_BADDBVER, 2, ccpfab.fab$b_fns, ccpfab.fab$l_fna);
+ }
+ }
+ else
+ database = v255;
+*/
+
+ if (dummy_data->acc_meth != dba_bg)
+ {
+ lib$signal(ERR_CCEBGONLY);
+ status = sys$dassgn(ccpfab.fab$l_stv);
+ assert(status & 1);
+ free(dummy_data);
+ return;
+ }
+ size = (LOCK_BLOCK(dummy_data) * DISK_BLOCK_SIZE) + LOCK_SPACE_SIZE(dummy_data);
+ old_data = malloc(size);
+ memcpy(old_data, dummy_data, SIZEOF(sgmnt_data));
+ cluster = cli$present(&cluster_qualifier);
+ if (cluster == CLI$_NEGATED)
+ old_data->clustered = FALSE;
+ else if (cluster == CLI$_PRESENT)
+ {
+ old_data->clustered = TRUE;
+ old_data->trans_hist.lock_sequence = 0;
+ }
+ change_fhead_timer("STALE_INTERVAL", old_data->staleness, -50000000, TRUE);
+ change_fhead_timer("RESPONSE_INTERVAL",old_data->ccp_response_interval, -600000000, TRUE);
+ change_fhead_timer("QUANTUM_INTERVAL", old_data->ccp_quantum_interval, -10000000, FALSE);
+ change_fhead_timer("TICK_INTERVAL", old_data->ccp_tick_interval, -1000000, FALSE);
+ if (old_data->unbacked_cache)
+ {
+ space_needed = (old_data->n_bts + getprime(old_data->n_bts) + 1) * SIZEOF(bt_rec);
+ if (space_needed > old_data->free_space)
+ {
+ old_data->n_bts = old_data->free_space/(2*SIZEOF(bt_rec));
+ for (;;)
+ {
+ space_needed = (old_data->n_bts + getprime(old_data->n_bts) + 1) * SIZEOF(bt_rec);
+ if (space_needed <= old_data->free_space)
+ {
+ old_data->bt_buckets = getprime(old_data->n_bts);
+ break;
+ }
+ old_data->n_bts--;
+ }
+ util_out_open(0);
+ util_out_print("Only have space for !UL cache records in clustered file !AD, adjusting file",TRUE,
+ old_data->n_bts, fn_len, fn);
+ }
+ old_data->free_space -= space_needed;
+ old_data->unbacked_cache = FALSE;
+ }
+ status = dbcx_ref(old_data, ccpfab.fab$l_stv);
+ if ((status & 1) == 0)
+ lib$signal(ERR_CCEWRTERR, 2, ccpfab.fab$b_fns, ccpfab.fab$l_fna, status);
+ if (cluster != CLI$_ABSENT)
+ lib$signal ((old_data->clustered) ? ERR_CCEDBCL : ERR_CCEDBNTCL, 2, ccpfab.fab$b_fns, ccpfab.fab$l_fna);
+ status = sys$dassgn(ccpfab.fab$l_stv);
+ assert(status & 1);
+ free(dummy_data);
+ free(old_data);
+ return;
+}
diff --git a/sr_vvms/cce_cmd.cld b/sr_vvms/cce_cmd.cld
new file mode 100644
index 0000000..9915c7a
--- /dev/null
+++ b/sr_vvms/cce_cmd.cld
@@ -0,0 +1,110 @@
+MODULE CCE_CMD
+
+DEFINE VERB DUMP
+ ROUTINE cce_ccpdmp
+ QUALIFIER ON
+ NEGATABLE
+ QUALIFIER NOW
+ NONNEGATABLE
+ QUALIFIER DB
+ NONNEGATABLE
+ DISALLOW ANY2(NOW,ON,DB)
+
+DEFINE VERB SET
+ PARAMETER P1
+ VALUE (TYPE = SET_ACTIONS)
+
+DEFINE TYPE SET_ACTIONS
+ KEYWORD FILE SYNTAX SET_FILE
+
+DEFINE SYNTAX SET_FILE
+ ROUTINE cce_cluster
+ PARAMETER P1
+ LABEL = SHOW_ACTIONS
+ VALUE(REQUIRED)
+ PARAMETER P2
+ LABEL = FILE
+ PROMPT = "File"
+ VALUE(TYPE=$FILE,REQUIRED)
+ QUALIFIER CLUSTER
+ QUALIFIER RESPONSE_INTERVAL
+ VALUE(TYPE = $DELTATIME)
+ NEGATABLE
+ QUALIFIER STALE_INTERVAL
+ VALUE(TYPE = $DELTATIME)
+ NEGATABLE
+ QUALIFIER QUANTUM_INTERVAL
+ VALUE(TYPE = $DELTATIME)
+ NONNEGATABLE
+ QUALIFIER TICK_INTERVAL
+ VALUE(TYPE = $DELTATIME)
+ NONNEGATABLE
+
+DEFINE VERB debug
+ ROUTINE cce_debug
+
+DEFINE VERB exit
+ ROUTINE cce_exit
+
+DEFINE VERB help
+ ROUTINE cce_help
+ PARAMETER P1, LABEL=QUERY
+
+DEFINE VERB quit
+ ROUTINE cce_exit
+
+DEFINE VERB SHOW
+ PARAMETER P1
+ VALUE (TYPE = SHOW_ACTIONS)
+
+DEFINE TYPE SHOW_ACTIONS
+ KEYWORD TRANSACTIONS SYNTAX = SHOW_TRANSACTIONS
+ KEYWORD LOCKS SYNTAX = SHOW_LOCKS
+ KEYWORD FILE SYNTAX = SHOW_FILE
+ KEYWORD CCP SYNTAX = SHOW_CCP
+
+DEFINE SYNTAX SHOW_LOCKS
+ ROUTINE cce_show_locks
+ PARAMETER P1
+ LABEL = SHOW_ACTIONS
+ VALUE(REQUIRED)
+ QUALIFIER ALL
+ NONNEGATABLE
+ QUALIFIER OUTPUT
+ VALUE (TYPE = $FILE)
+ NONNEGATABLE
+DEFINE SYNTAX SHOW_TRANSACTIONS
+ ROUTINE cce_dump
+ PARAMETER P1
+ LABEL = SHOW_ACTIONS
+ VALUE(REQUIRED)
+ QUALIFIER OUTPUT
+ VALUE (TYPE = $FILE)
+ NONNEGATABLE
+
+DEFINE SYNTAX SHOW_FILE
+ ROUTINE cce_show_file
+ PARAMETER P1
+ LABEL = SHOW_ACTIONS
+ VALUE(REQUIRED)
+ PARAMETER P2
+ LABEL = FILE
+ PROMPT = "File"
+ VALUE(TYPE=$FILE,REQUIRED)
+ QUALIFIER OUTPUT
+ VALUE (TYPE = $FILE)
+ NONNEGATABLE
+
+DEFINE SYNTAX SHOW_CCP
+ ROUTINE cce_ccp
+
+DEFINE VERB stop
+ ROUTINE cce_stop
+
+DEFINE VERB start
+ ROUTINE cce_start
+ QUALIFIER PRIORITY
+ VALUE (REQUIRED)
+ NONNEGATABLE
+
+
diff --git a/sr_vvms/cce_dbdump.c b/sr_vvms/cce_dbdump.c
new file mode 100644
index 0000000..eebf5ab
--- /dev/null
+++ b/sr_vvms/cce_dbdump.c
@@ -0,0 +1,190 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <clidef.h>
+#include <rms.h>
+#include <iodef.h>
+#include <psldef.h>
+#include <descrip.h>
+#include <ssdef.h>
+#include <secdef.h>
+
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "mlkdef.h"
+#include "util.h"
+#include "mem_list.h"
+#include "cce_sec_size.h"
+#include "init_sec.h"
+#include "fid_from_sec.h"
+
+OS_PAGE_SIZE_DECLARE
+#define RECORD_SIZE 1024
+#define EXTRA_SPACE 256
+
+typedef struct
+{ unsigned short status;
+ unsigned short char_ct;
+ uint4 pid;
+}m_iosb;
+
+void cce_dbdump(void)
+{
+ uint4 channel, status, flags, pid, real_size, req_size, size, addrs[2], sec_addrs[2];
+ int i, j, k, l;
+ gds_file_id file;
+ m_iosb stat_blk;
+ sgmnt_data *sd;
+ unsigned char mbuff[512], *c, *cptr, *ctop;
+ $DESCRIPTOR(d_sec,mbuff);
+ static readonly $DESCRIPTOR(d_cmd,"install lis/glo");
+ static readonly $DESCRIPTOR(d_mnam,"CCE$DBDUMPMBX");
+ static readonly $DESCRIPTOR(d_pnam,"CCE$DBDUMPPRC");
+ char filename[]="SYS$LOGIN:CCE_DBDUMP.DMP", buff[RECORD_SIZE], id_lab[]=" FILE ID:";
+ struct FAB fab;
+ struct RAB rab;
+ error_def(ERR_CCEDBDUMP);
+ error_def(ERR_CCEDBNODUMP);
+
+
+ util_out_open(0);
+ status = sys$crembx(0, &channel, 512, 0, 0, PSL$C_USER, &d_mnam);
+ if (status != SS$_NORMAL)
+ sys$exit(status);
+ flags = CLI$M_NOWAIT | CLI$M_NOLOGNAM;
+ status = lib$spawn(&d_cmd, 0, &d_mnam, &flags, &d_pnam, &pid);
+ if (status != SS$_NORMAL)
+ { if (status == SS$_DUPLNAM)
+ { util_out_print("Spawned process CCE$DBDUMPPRC already exists, cannot continue rundown",TRUE);
+ }
+ sys$exit(status);
+ }
+ /* the following guess at the dump file size is modeled on the calculation for a section */
+ size = DIVIDE_ROUND_UP((SIZEOF(sgmnt_data) + (WC_MAX_BUFFS + getprime(WC_MAX_BUFFS) + 1) * SIZEOF(bt_rec)
+ + (DEF_LOCK_SIZE / OS_PAGELET_SIZE)
+ + (WC_MAX_BUFFS + getprime(WC_MAX_BUFFS)) * SIZEOF(cache_rec) + SIZEOF(cache_que_heads)),
+ OS_PAGELET_SIZE);
+ size += EXTRA_SPACE;
+
+ fab = cc$rms_fab;
+ fab.fab$b_fac = FAB$M_PUT;
+ fab.fab$l_fop = FAB$M_CBT | FAB$M_MXV | FAB$M_TEF;
+ fab.fab$l_fna = filename;
+ fab.fab$b_fns = SIZEOF(filename);
+ fab.fab$b_rfm = FAB$C_FIX;
+ fab.fab$w_mrs = RECORD_SIZE;
+ fab.fab$w_deq = size;
+ fab.fab$l_alq = size;
+ switch (status = sys$create(&fab))
+ {
+ case RMS$_NORMAL:
+ case RMS$_CREATED:
+ case RMS$_SUPERSEDE:
+ case RMS$_FILEPURGED:
+ break;
+ default:
+ util_out_print("Error: Cannot create dump file !AD.",TRUE,fab.fab$b_fns,fab.fab$l_fna);
+ sys$exit(status);
+ }
+
+ rab = cc$rms_rab;
+ rab.rab$l_fab = &fab;
+ status = sys$connect(&rab);
+ if (status != RMS$_NORMAL)
+ { util_out_print("Error: Cannot connect to dump file !AD.",TRUE,fab.fab$b_fns,fab.fab$l_fna);
+ sys$exit(status);
+ }
+ rab.rab$w_rsz = SIZEOF(buff);
+
+ for (; ;)
+ { status = sys$qiow (0, channel,IO$_READVBLK ,&stat_blk, 0, 0, mbuff, 512,0,0,0,0);
+ if (status != SS$_NORMAL)
+ { sys$exit(status);
+ break;
+ }
+ if (stat_blk.status == SS$_ENDOFFILE)
+ break;
+ if (stat_blk.status != SS$_NORMAL)
+ { sys$exit(stat_blk.status);
+ break;
+ }
+ if (!memcmp("GT$S",mbuff,4))
+ { for ( c = mbuff; *c > 32 ; c++)
+ ;
+ d_sec.dsc$w_length = c - mbuff;
+ flags = SEC$M_GBL | SEC$M_WRT | SEC$M_SYSGBL | SEC$M_PAGFIL | SEC$M_DZRO | SEC$M_PERM;
+ addrs[0] = addrs[1] = 0;
+ fid_from_sec(&d_sec,&file);
+
+ real_size = cce_sec_size(&file);
+ if (real_size == 0)
+ real_size = size;
+ real_size += 1;
+
+ assert(OS_PAGE_SIZE % OS_PAGELET_SIZE == 0);
+
+ /* Request enough pagelets to ensure enough contiguous pages to contain desired number of pagelets. */
+ req_size = ROUND_UP(real_size, OS_PAGE_SIZE);
+ lib$get_vm_page(&req_size, &addrs[0]);
+
+ /* addrs will hold addresses of start and end of contiguous block of pagelets for use by $deltva. */
+ assert((addrs[0] + (req_size * OS_PAGELET_SIZE) - 1) == addrs[1]);
+
+ /* $get_vm_page returns pagelets; we must align to integral page boundary. */
+ /* sec_addrs will contain the starting and ending addresses of the mapped section. */
+ sec_addrs[0] = ROUND_UP(addrs[0], OS_PAGE_SIZE); /* align to first integral page boundary */
+ sec_addrs[1] = addrs[0] + (real_size * OS_PAGELET_SIZE);
+ sec_addrs[1] = ROUND_UP(addrs[1], OS_PAGE_SIZE) - 1; /* A(last byte of last page) */
+
+ status = init_sec(sec_addrs, &d_sec, 0, real_size, flags);
+ if (status & 1)
+ {
+ sd = sec_addrs[0];
+ memset(buff, 0, RECORD_SIZE);
+ memcpy(buff, d_sec.dsc$a_pointer, d_sec.dsc$w_length);
+ cptr = &buff[0] + d_sec.dsc$w_length;
+ memcpy(cptr,id_lab,SIZEOF(id_lab));
+ cptr += SIZEOF(id_lab);
+ memcpy(cptr,&file,SIZEOF(file));
+ rab.rab$l_rbf = buff;
+ status = sys$put(&rab);
+ if (status != RMS$_NORMAL)
+ { util_out_print("Error writing to dump file !AD.",TRUE,fab.fab$b_fns,fab.fab$l_fna);
+ util_out_print("Status code is !UL.",TRUE,status);
+ break;
+ }
+ for (c = sd, i = 0; (real_size + EXTRA_SPACE) >= i;
+ c += RECORD_SIZE, i += (RECORD_SIZE / DISK_BLOCK_SIZE))
+ {
+ rab.rab$l_rbf = c;
+ status = sys$put(&rab);
+ if (status != RMS$_NORMAL)
+ { util_out_print("Error writing to dump file !AD.",TRUE,fab.fab$b_fns,fab.fab$l_fna);
+ util_out_print("Status code is !UL.",TRUE,status);
+ break;
+ }
+ }
+ lib$signal(ERR_CCEDBDUMP,2,d_sec.dsc$w_length,d_sec.dsc$a_pointer);
+ }else
+ { lib$signal(ERR_CCEDBNODUMP,2,d_sec.dsc$w_length,d_sec.dsc$a_pointer,status,0);
+ }
+ gtm_deltva(&addrs[0],0,0);
+ lib$free_vm_page(&real_size,&addrs[0]);
+ }
+ }
+ sys$exit(SS$_NORMAL);
+}
diff --git a/sr_vvms/cce_dump.c b/sr_vvms/cce_dump.c
new file mode 100644
index 0000000..93c0a0b
--- /dev/null
+++ b/sr_vvms/cce_dump.c
@@ -0,0 +1,26 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "ccp.h"
+#include "ccpact.h"
+#include "cce_output.h"
+
+void cce_dump(void)
+{
+ ccp_action_aux_value mbxname;
+
+ cce_get_return_channel(&mbxname);
+ ccp_sendmsg(CCTR_QUEDUMP, &mbxname);
+ cce_read_return_channel();
+ return;
+}
diff --git a/sr_vvms/cce_get_return_channel.c b/sr_vvms/cce_get_return_channel.c
new file mode 100644
index 0000000..9b9a3b5
--- /dev/null
+++ b/sr_vvms/cce_get_return_channel.c
@@ -0,0 +1,47 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "ccp.h"
+#include <dvidef.h>
+#include <descrip.h>
+
+GBLDEF unsigned short cce_return_channel;
+static struct dsc$descriptor_s cce_return_channel_name;
+static unsigned char cce_return_channel_name_buffer[20];
+
+void cce_get_return_channel(p)
+ccp_action_aux_value *p;
+{
+ int status;
+ int4 namlen;
+
+ if (!cce_return_channel)
+ {
+ status = sys$crembx(0, &cce_return_channel, 0,0,0,0, 0);
+ if ((status & 1) == 0)
+ lib$signal(status);
+ cce_return_channel_name.dsc$w_length = SIZEOF(cce_return_channel_name_buffer);
+ cce_return_channel_name.dsc$b_dtype = DSC$K_DTYPE_T;
+ cce_return_channel_name.dsc$b_class = DSC$K_CLASS_S;
+ cce_return_channel_name.dsc$a_pointer = cce_return_channel_name_buffer;
+ status = lib$getdvi(&DVI$_FULLDEVNAM, &cce_return_channel,0,0,&cce_return_channel_name, &namlen);
+ if ((status & 1) == 0)
+ lib$signal(status);
+ if (cce_return_channel_name.dsc$w_length > SIZEOF(p->str.txt))
+ GTMASSERT;
+ cce_return_channel_name.dsc$w_length = namlen;
+ }
+ p->str.len = cce_return_channel_name.dsc$w_length;
+ memcpy(p->str.txt, cce_return_channel_name.dsc$a_pointer, p->str.len);
+ return;
+}
diff --git a/sr_vvms/cce_help.c b/sr_vvms/cce_help.c
new file mode 100644
index 0000000..50a31c8
--- /dev/null
+++ b/sr_vvms/cce_help.c
@@ -0,0 +1,35 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <ssdef.h>
+#include <climsgdef.h>
+#include <descrip.h>
+
+#define HLP$M_PROMPT 1
+#define HELP_LIBRARY "GTM$HELP:CCE"
+
+void cce_help(void)
+{
+
+ uint4 flags;
+ char buff[256];
+ $DESCRIPTOR(line, buff);
+ $DESCRIPTOR(libr, HELP_LIBRARY);
+ $DESCRIPTOR(ent, "QUERY");
+
+ if (CLI$PRESENT(&ent) != CLI$_PRESENT || CLI$GET_VALUE(&ent,&line) != SS$_NORMAL)
+ line.dsc$w_length = 0;
+ flags = HLP$M_PROMPT;
+ lbr$output_help(lib$put_output,0,&line,&libr,&flags,lib$get_input);
+ return;
+
+}
diff --git a/sr_vvms/cce_output.c b/sr_vvms/cce_output.c
new file mode 100644
index 0000000..4f57ee3
--- /dev/null
+++ b/sr_vvms/cce_output.c
@@ -0,0 +1,76 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <fab.h>
+#include <rab.h>
+#include <descrip.h>
+#include <climsgdef.h>
+#include "cce_output.h"
+
+static struct RAB *cce_output_rab = 0;
+static struct FAB *cce_output_fab = 0;
+
+void cce_out_open(void)
+{
+ uint4 status;
+ static readonly unsigned char sys_output_name[] = "SYS$OUTPUT";
+ $DESCRIPTOR(output_qualifier, "OUTPUT");
+ char output_name[255];
+ $DESCRIPTOR(output_name_desc, output_name);
+ short unsigned outnamlen;
+
+ status = cli$get_value(&output_qualifier, &output_name_desc, &outnamlen);
+ if (status != 1)
+ {
+ outnamlen = SIZEOF(sys_output_name) - 1;
+ output_name_desc.dsc$a_pointer = sys_output_name;
+ }
+ cce_output_fab = malloc(SIZEOF(*cce_output_fab));
+ cce_output_rab = malloc(SIZEOF(*cce_output_rab));
+ *cce_output_fab = cc$rms_fab;
+ *cce_output_rab = cc$rms_rab;
+ cce_output_rab->rab$l_fab = cce_output_fab;
+ cce_output_rab->rab$w_usz = 255;
+ cce_output_fab->fab$w_mrs = 255;
+ cce_output_fab->fab$b_fac = FAB$M_GET | FAB$M_PUT;
+ cce_output_fab->fab$b_rat = FAB$M_CR;
+ cce_output_fab->fab$l_fna = output_name_desc.dsc$a_pointer;
+ cce_output_fab->fab$b_fns = outnamlen;
+ status = sys$create(cce_output_fab, 0, 0);
+ if ((status & 1) == 0)
+ lib$signal(status);
+ status = sys$connect(cce_output_rab, 0, 0);
+ if ((status & 1) == 0)
+ lib$signal(status);
+}
+
+void cce_out_write( unsigned char *addr, unsigned int len)
+{
+ int status;
+
+ cce_output_rab->rab$l_rbf = addr;
+ cce_output_rab->rab$w_rsz = len;
+ status = sys$put(cce_output_rab,0 ,0);
+ if ((status & 1) == 0)
+ lib$signal(status);
+ return;
+}
+
+void cce_out_close(void)
+{
+ sys$close(cce_output_fab, 0, 0);
+ free(cce_output_fab);
+ free(cce_output_rab);
+ cce_output_fab = 0;
+ cce_output_rab = 0;
+ return;
+}
diff --git a/sr_vvms/cce_output.h b/sr_vvms/cce_output.h
new file mode 100644
index 0000000..e11bf79
--- /dev/null
+++ b/sr_vvms/cce_output.h
@@ -0,0 +1,20 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef __CCE_OUTPUT_H__
+#define __CCE_OUTPUT_H__
+
+void cce_out_open(void);
+void cce_out_write(unsigned char *addr, unsigned int len);
+void cce_out_close(void);
+void cce_read_return_channel(void);
+
+#endif
diff --git a/sr_vvms/cce_read_return_channel.c b/sr_vvms/cce_read_return_channel.c
new file mode 100644
index 0000000..93cf231
--- /dev/null
+++ b/sr_vvms/cce_read_return_channel.c
@@ -0,0 +1,59 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "ccp.h"
+#include <iodef.h>
+#include <ssdef.h>
+#include "efn.h"
+#include "cce_output.h"
+
+GBLREF unsigned short cce_return_channel;
+
+void cce_read_return_channel(void)
+{
+ unsigned short mbsb[4];
+ uint4 status;
+ unsigned char buff[255];
+ int4 efn_mask;
+ static uint4 time[2] = { -30000000, -1 }; /* 3 seconds */
+ error_def(ERR_CCERDTIMOUT);
+
+ cce_out_open();
+ for (;;)
+ {
+ efn_mask = (1 << efn_immed_wait | 1 << efn_timer);
+ status = sys$setimr(efn_timer,time,0,&cce_return_channel,0);
+ if ((status & 1) == 0)
+ lib$signal(status);
+ status = sys$qio(efn_immed_wait, cce_return_channel, IO$_READVBLK, &mbsb[0], 0, 0, &buff,
+ SIZEOF(buff), 0, 0, 0, 0);
+ if ((status & 1) == 0)
+ lib$signal(status);
+ if ((status = sys$wflor(efn_immed_wait,efn_mask)) != SS$_NORMAL)
+ lib$signal(status);
+ if ((status = sys$readef(efn_immed_wait, &efn_mask)) == SS$_WASSET)
+ { sys$cantim(&cce_return_channel,0);
+ status = mbsb[0];
+ if (status == SS$_ENDOFFILE)
+ break;
+ if ((status & 1) == 0)
+ lib$signal(status);
+ cce_out_write(buff, mbsb[1]);
+ }else
+ { lib$signal(ERR_CCERDTIMOUT);
+ break;
+ }
+ }
+ cce_out_close();
+ return;
+}
diff --git a/sr_vvms/cce_sec_size.c b/sr_vvms/cce_sec_size.c
new file mode 100644
index 0000000..99c6670
--- /dev/null
+++ b/sr_vvms/cce_sec_size.c
@@ -0,0 +1,61 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <rms.h>
+#include <iodef.h>
+#include <efndef.h>
+
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "jnl.h"
+#include "cce_sec_size.h"
+
+int cce_sec_size(gds_file_id *file)
+{
+ uint4 status;
+ int size;
+ short iosb[4];
+ sgmnt_data sd;
+ sgmnt_data_ptr_t csd = &sd;
+ char expanded_file_name[MAX_FN_LEN];
+ struct FAB fab;
+ struct NAM nam;
+ int buckets;
+
+ fab = cc$rms_fab;
+ fab.fab$l_fop = FAB$M_NAM | FAB$M_UFO;
+ fab.fab$b_fac = FAB$M_GET | FAB$M_PUT | FAB$M_BIO;
+ fab.fab$b_shr = FAB$M_SHRPUT | FAB$M_SHRGET | FAB$M_UPI;
+ fab.fab$l_nam = &nam;
+ nam = cc$rms_nam;
+ nam.nam$b_ess = MAX_FN_LEN;
+ nam.nam$l_esa = expanded_file_name;
+ memcpy(nam.nam$t_dvi, file->dvi,file->dvi[0] + 1);
+ memcpy(nam.nam$w_fid, file->fid, SIZEOF(file->fid));
+ status = sys$open(&fab, 0, 0);
+ if (!(status & 1))
+ return 0;
+ status = sys$qiow(EFN$C_ENF,fab.fab$l_stv, IO$_READVBLK, &iosb[0], 0,0, csd, SIZEOF(sgmnt_data), 1,0,0,0);
+ if (!(status & 1))
+ return 0;
+ buckets = getprime(sd.n_bts);
+ size = (LOCK_BLOCK(csd) * DISK_BLOCK_SIZE) + LOCK_SPACE_SIZE(csd) + CACHE_CONTROL_SIZE(csd) + NODE_LOCAL_SPACE(csd)
+ + JNL_SHARE_SIZE(csd);
+ sys$dassgn(fab.fab$l_stv);
+ return size / OS_PAGELET_SIZE;
+}
diff --git a/sr_vvms/cce_sec_size.h b/sr_vvms/cce_sec_size.h
new file mode 100644
index 0000000..3b5821a
--- /dev/null
+++ b/sr_vvms/cce_sec_size.h
@@ -0,0 +1,17 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef CCE_SEC_SIZE_INCLUDED
+#define CCE_SEC_SIZE_INCLUDED
+
+int cce_sec_size(gds_file_id *file);
+
+#endif /* CCE_SEC_SIZE_INCLUDED */
diff --git a/sr_vvms/cce_show_file.c b/sr_vvms/cce_show_file.c
new file mode 100644
index 0000000..7f93580
--- /dev/null
+++ b/sr_vvms/cce_show_file.c
@@ -0,0 +1,146 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "gdsblk.h"
+#include <rmsdef.h>
+#include <fab.h>
+#include <xab.h>
+#include <ssdef.h>
+#include <iodef.h>
+#include <descrip.h>
+#include <climsgdef.h>
+#include <efndef.h>
+
+#include "filestruct.h"
+#include "util.h"
+#include "cli.h"
+
+#define PUTTIM(L,T) (outbufidx = 0 , memset(outbuf, ' ', SIZEOF(outbuf)), \
+ PUTLIT(L), sys$asctim(&timlen, &time_desc, (T), 1), outbufidx = time_desc.dsc$w_length + timlen, \
+ util_out_write(outbuf, outbufidx))
+#define PUTSTR(A,L) (memcpy(&outbuf[outbufidx], (A), (L)), outbufidx += (L))
+#define PUTLIT(X) PUTSTR((X), SIZEOF(X) - 1)
+
+/* NOTE: WHY BOTH old_data and dummy_data? */
+cce_show_file()
+{
+ char fn[256];
+ struct FAB ccpfab;
+ struct XABFHC xab;
+ sgmnt_data *old_data, *dummy_data;
+ sgmnt_addrs *cs;
+ short iosb[4];
+ unsigned short fn_len;
+ short unsigned timlen;
+ struct dsc$descriptor_s time_desc;
+ int4 status, size, cluster;
+ unsigned char *c;
+ unsigned char outbuf[80];
+ int outbufidx;
+ $DESCRIPTOR(output_qualifier, "OUTPUT");
+ error_def(ERR_CCERDERR);
+ error_def(ERR_CCEBADFN);
+ error_def(ERR_DBOPNERR);
+ error_def(ERR_DBNOTGDS);
+ error_def(ERR_BADDBVER);
+ error_def(ERR_CCEBGONLY);
+
+ fn_len = SIZEOF(fn);
+ if (!cli_get_str("FILE",fn,&fn_len))
+ {
+ lib$signal(ERR_CCEBADFN);
+ return;
+ }
+ ccpfab = cc$rms_fab;
+ ccpfab.fab$l_fna = fn;
+ ccpfab.fab$b_fns = fn_len;
+ ccpfab.fab$b_fac = FAB$M_BIO | FAB$M_GET;
+ ccpfab.fab$b_shr = FAB$M_SHRPUT | FAB$M_SHRGET | FAB$M_UPI;
+ ccpfab.fab$l_fop = FAB$M_UFO;
+ xab = cc$rms_xabfhc;
+ ccpfab.fab$l_xab = &xab;
+ status = sys$open(&ccpfab);
+ if (status != RMS$_NORMAL)
+ {
+ lib$signal(ERR_DBOPNERR, 2, ccpfab.fab$b_fns, ccpfab.fab$l_fna, status);
+ return;
+ }
+ dummy_data = malloc(512);
+ status = sys$qiow(EFN$C_ENF, ccpfab.fab$l_stv, IO$_READVBLK, iosb, 0, 0, dummy_data, 512, 1, 0, 0, 0);
+ if (status & 1)
+ status = iosb[0];
+ if ((status & 1) == 0)
+ {
+ lib$signal(ERR_CCERDERR, 2, ccpfab.fab$b_fns, ccpfab.fab$l_fna, status);
+ sys$dassgn(ccpfab.fab$l_stv);
+ return;
+ }
+ if (memcmp(&dummy_data->label[0], GDS_LABEL, 12))
+ {
+ if (memcmp(&dummy_data->label[0], GDS_LABEL, 9))
+ lib$signal (ERR_DBNOTGDS, 2, ccpfab.fab$b_fns, ccpfab.fab$l_fna);
+ else
+ lib$signal (ERR_BADDBVER, 2, ccpfab.fab$b_fns, ccpfab.fab$l_fna);
+ status = sys$dassgn(ccpfab.fab$l_stv);
+ assert(status & 1);
+ return;
+ }
+ if (dummy_data->acc_meth != dba_bg)
+ {
+ lib$signal(ERR_CCEBGONLY);
+ status = sys$dassgn(ccpfab.fab$l_stv);
+ assert(status & 1);
+ return;
+ }
+ size = (((SIZEOF(sgmnt_data)) + 511)/512) * 512;
+ old_data = malloc(size);
+ status = sys$qiow(EFN$C_ENF, ccpfab.fab$l_stv, IO$_READVBLK, iosb, 0, 0, old_data, size, 1, 0, 0, 0);
+ if (status & 1)
+ status = iosb[0];
+ if ((status & 1) == 0)
+ {
+ lib$signal(ERR_CCERDERR, 2, ccpfab.fab$b_fns, ccpfab.fab$l_fna, status);
+ status = sys$dassgn(ccpfab.fab$l_stv);
+ assert(status & 1);
+ return;
+ }
+ outbufidx = 0;
+ util_out_open(&output_qualifier);
+ PUTLIT("Database file ");
+ PUTSTR(fn, fn_len);
+ PUTLIT(" is ");
+ if (!old_data->clustered)
+ {
+ PUTLIT(" NOT ");
+ }
+ PUTLIT(" a cluster database");
+ util_out_write(outbuf, outbufidx);
+ time_desc.dsc$b_dtype = DSC$K_DTYPE_T;
+ time_desc.dsc$b_class = DSC$K_CLASS_S;
+ time_desc.dsc$a_pointer = &outbuf[20];
+ time_desc.dsc$w_length = 40;
+ PUTTIM("STALE_INTERVAL", old_data->staleness);
+ PUTTIM("RESPONSE_INTERVAL",old_data->ccp_response_interval);
+ PUTTIM("QUANTUM_INTERVAL", old_data->ccp_quantum_interval);
+ PUTTIM("TICK_INTERVAL", old_data->ccp_tick_interval);
+ util_out_close();
+ status = sys$dassgn(ccpfab.fab$l_stv);
+ assert(status & 1);
+ free(dummy_data);
+ free(old_data);
+ return;
+}
diff --git a/sr_vvms/cce_show_locks.c b/sr_vvms/cce_show_locks.c
new file mode 100644
index 0000000..4adb843
--- /dev/null
+++ b/sr_vvms/cce_show_locks.c
@@ -0,0 +1,232 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "vmsdtype.h"
+#include <lckdef.h>
+#include <jpidef.h>
+#include <descrip.h>
+#include <lkidef.h>
+#include <climsgdef.h>
+#include <psldef.h>
+#include <prvdef.h>
+#include <ssdef.h>
+#include <efndef.h>
+#include "util.h"
+
+
+void display_lock_mode(int n, char *out);
+
+void cce_show_locks(void)
+{
+ struct
+ {
+ int4 length;
+ struct
+ {
+ unsigned int group:16, rmod:8, status: 7, sysnam:1;
+ } value;
+ } namespace;
+ struct
+ {
+ int4 length;
+ int4 value;
+ } lkidadr, remlkid, system, pid;
+
+ struct
+ {
+ int4 length;
+ char value[31];
+ } resnam;
+ struct
+ {
+ int4 length;
+ char value[3];
+ } state;
+
+#define ITEM_DEF(A, B) SIZEOF((B).value), A, &((B).value), &((B).length)
+
+ item_list_3 ilist[] = {
+ ITEM_DEF(LKI$_LOCKID, lkidadr),
+ ITEM_DEF(LKI$_PID, pid),
+ ITEM_DEF(LKI$_REMLKID, remlkid),
+ ITEM_DEF(LKI$_RESNAM, resnam),
+ ITEM_DEF(LKI$_STATE, state),
+ ITEM_DEF(LKI$_SYSTEM, system),
+ ITEM_DEF(LKI$_NAMSPACE, namespace),
+ 0, 0, 0, 0};
+ int4 in_id;
+ uint4 status;
+ bool show_all_locks;
+ struct
+ {
+ char lockid[8];
+ char sp0[1];
+ char remoteid[8];
+ char sp1[1];
+ char que[4];
+ char sp2[1];
+ char rq[2];
+ char sp2a[1];
+ char gn[2];
+ char sp3[1];
+ char systemid[8];
+ char sp4[1];
+ char owner[8];
+ char sp5[1];
+ char procname[15];
+ char sp6[1];
+ char group[8];
+ char sp7[1];
+ char rmod[4];
+ char sp8[1];
+ char sysnam[3];
+ char sp9[1];
+ char resourcename[31];
+ } print_line;
+ struct dsc$descriptor_s dsc_procname;
+ $DESCRIPTOR(all_qualifier, "ALL");
+ $DESCRIPTOR(output_qualifier, "OUTPUT");
+ unsigned char *cp, *ctop;
+ uint4 prvprv1[2], prvprv2[2], prvadr[2];
+ static readonly char heading_line[] =
+ "LOCK ID REMOTEID QUE RQ GN SYSTEMID OWNER PROCESS NAME GROUP MODE LVL RESOURCE NAME";
+ error_def(ERR_CCENOSYSLCK);
+ error_def(ERR_CCENOWORLD);
+ error_def(ERR_CCENOGROUP);
+
+ prvadr[1] = 0;
+ prvadr[0] = PRV$M_SYSLCK;
+ status = sys$setprv(TRUE, &prvadr[0], FALSE, &prvprv1[0]);
+ if (status != SS$_NORMAL)
+ lib$signal(ERR_CCENOSYSLCK);
+ prvadr[0] = PRV$M_WORLD;
+ status = sys$setprv(TRUE, &prvadr[0], FALSE, &prvprv2[0]);
+ if (status != SS$_NORMAL)
+ {
+ lib$signal(ERR_CCENOWORLD);
+ prvadr[0] = PRV$M_GROUP;
+ status = sys$setprv(TRUE, &prvadr[0], FALSE, &prvprv2[0]);
+ if (status != SS$_NORMAL)
+ lib$signal(ERR_CCENOGROUP);
+ }
+
+ status = cli$present(&all_qualifier);
+ show_all_locks = (status == CLI$_PRESENT);
+ dsc_procname.dsc$w_length = SIZEOF(print_line.procname);
+ dsc_procname.dsc$b_dtype = DSC$K_DTYPE_T;
+ dsc_procname.dsc$b_class = DSC$K_CLASS_S;
+ dsc_procname.dsc$a_pointer = print_line.procname;
+ util_out_open(&output_qualifier);
+ util_out_write(LIT_AND_LEN(heading_line));
+ util_out_write(heading_line, 0);
+ for (in_id = -1; ;)
+ {
+ status = sys$getlkiw(EFN$C_ENF, &in_id, &ilist, 0, 0, 0, 0);
+ if (status != 1)
+ break;
+ if (!show_all_locks && memcmp("GTM", &resnam.value, SIZEOF("GTM") - 2) != 0)
+ continue;
+ memset(&print_line, ' ', SIZEOF(print_line));
+ i2hex(lkidadr.value, print_line.lockid, SIZEOF(print_line.lockid));
+ i2hex(pid.value, print_line.owner, SIZEOF(print_line.owner));
+ i2hex(system.value, print_line.systemid, SIZEOF(print_line.systemid));
+ i2hex(remlkid.value, print_line.remoteid, SIZEOF(print_line.remoteid));
+ i2hex(namespace.value.group, print_line.group, SIZEOF(print_line.group));
+ display_lock_mode(state.value[0], &print_line.rq);
+ display_lock_mode(state.value[1], &print_line.gn);
+ memcpy(print_line.resourcename, resnam.value, resnam.length);
+ switch(state.value[2])
+ {
+ case LKI$C_GRANTED:
+ cp = "GRNT";
+ break;
+ case LKI$C_CONVERT:
+ cp = "CONV";
+ break;
+ case LKI$C_WAITING:
+ cp = "WAIT";
+ break;
+ default:
+ cp = "????";
+ break;
+ }
+ memcpy(print_line.que, cp, SIZEOF(print_line.que));
+ status = lib$getjpi(&JPI$_PRCNAM, &pid.value, 0, 0, &dsc_procname, 0);
+ switch(namespace.value.rmod)
+ {
+ case PSL$C_USER:
+ cp = "USER";
+ break;
+ case PSL$C_EXEC:
+ cp = "EXEC";
+ break;
+ case PSL$C_SUPER:
+ cp = "SUPR";
+ break;
+ case PSL$C_KERNEL:
+ cp = "KRNL";
+ break;
+ default:
+ cp = "????";
+ break;
+ }
+ memcpy(print_line.rmod, cp, SIZEOF(print_line.rmod));
+ cp = namespace.value.sysnam ? "SYS" : "GRP";
+ memcpy(print_line.sysnam, cp, SIZEOF(print_line.sysnam));
+ for (cp = print_line.resourcename, ctop = cp + SIZEOF(print_line.resourcename); cp < ctop; cp++)
+ if (*cp < 32 || *cp > 127)
+ *cp = '.';
+ for (cp = &print_line, ctop = cp + SIZEOF(print_line); cp < ctop && *(ctop - 1) == ' '; ctop--)
+ ;
+ util_out_write(&print_line, ctop - cp);
+ }
+ util_out_close();
+ if (prvprv2[0] & prvadr[0] == 0)
+ sys$setprv(FALSE, &prvadr[0], FALSE, 0);
+ prvadr[1] = 0;
+ prvadr[0] = PRV$M_SYSLCK;
+ if (prvprv1[0] & PRV$M_SYSLCK == 0)
+ sys$setprv(FALSE, &prvadr[0], FALSE, 0);
+ return;
+}
+
+void display_lock_mode(int n, char *out)
+{
+ char *cp;
+ switch (n)
+ {
+ case LCK$K_NLMODE:
+ cp = "NL";
+ break;
+ case LCK$K_CRMODE:
+ cp = "CR";
+ break;
+ case LCK$K_CWMODE:
+ cp = "CW";
+ break;
+ case LCK$K_PRMODE:
+ cp = "PR";
+ break;
+ case LCK$K_PWMODE:
+ cp = "PW";
+ break;
+ case LCK$K_EXMODE:
+ cp = "EX";
+ break;
+ default:
+ cp = "??";
+ break;
+ }
+ *out++ = *cp++;
+ *out = *cp;
+ return;
+}
diff --git a/sr_vvms/cce_start.c b/sr_vvms/cce_start.c
new file mode 100644
index 0000000..70fda5f
--- /dev/null
+++ b/sr_vvms/cce_start.c
@@ -0,0 +1,75 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <ssdef.h>
+#include <secdef.h>
+#include <descrip.h>
+#include <prvdef.h>
+#include <prcdef.h>
+#include <rms.h>
+#include "util.h"
+#include "cli.h"
+
+void cce_start(void)
+{
+ int4 status;
+ uint4 prvadr[2], prvprv[2];
+ static readonly $DESCRIPTOR(proc,"GT.CX_CONTROL");
+ static readonly $DESCRIPTOR(image,"GTM$DIST:CCP.EXE");
+ static readonly uic = 65540; /* uic = [1,4] */
+ $DESCRIPTOR(ccp,"");
+ unsigned char success[] = "GT.CX Cluster controller started with PID = ";
+ uint4 pid;
+ uint4 baspri;
+ struct FAB ccp_fab;
+ struct NAM ccp_nam;
+ unsigned char ccp_namebuf[63]; /* max image name allowable for creprc */
+
+ prvadr[1] = 0;
+ prvadr[0] = PRV$M_DETACH | PRV$M_OPER | PRV$M_SYSNAM | PRV$M_SYSLCK | PRV$M_TMPMBX;
+ status = sys$setprv(TRUE, &prvadr[0], FALSE, &prvprv[0]);
+ if (status == SS$_NORMAL)
+ {
+ baspri = 5;
+ cli_get_num("PRIORITY",&baspri);
+
+ ccp_fab = cc$rms_fab;
+ ccp_fab.fab$l_fna = image.dsc$a_pointer;
+ ccp_fab.fab$b_fns = image.dsc$w_length;
+ ccp_fab.fab$l_nam = &ccp_nam;
+ ccp_nam = cc$rms_nam;
+ ccp_nam.nam$l_esa = ccp_namebuf;
+ ccp_nam.nam$b_ess = SIZEOF(ccp_namebuf);
+ ccp_nam.nam$b_nop = NAM$M_SYNCHK;
+ status = sys$parse (&ccp_fab);
+ if (!(status & 1))
+ { lib$signal(status);
+ return;
+ }
+ ccp.dsc$a_pointer = ccp_namebuf;
+ ccp.dsc$w_length = ccp_nam.nam$b_esl;
+
+ status = sys$creprc(&pid, &ccp, 0, 0, 0, &prvadr, 0, &proc, baspri, uic, 0, PRC$M_DETACH);
+ sys$setprv(FALSE, &prvprv[0], FALSE, 0);
+ if (status != SS$_NORMAL)
+ { lib$signal(status);
+ return;
+ }
+ util_out_open(0);
+ i2hex(pid, &success[ SIZEOF(success) - 8], 8);
+ util_out_write(&success[0], SIZEOF(success));
+ util_out_close();
+ }
+ else
+ lib$signal(status);
+}
+
diff --git a/sr_vvms/ccp.c b/sr_vvms/ccp.c
new file mode 100644
index 0000000..4872f92
--- /dev/null
+++ b/sr_vvms/ccp.c
@@ -0,0 +1,60 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2004 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "error.h"
+#include "gdsroot.h"
+#include "ccp.h"
+#include "ccpact.h"
+#include "get_page_size.h"
+#include "gtm_env_init.h" /* for gtm_env_init() prototype */
+
+GBLDEF bool ccp_stop;
+GBLDEF int ccp_stop_ctr;
+GBLREF bool licensed ;
+int ccp(void)
+{
+ ccp_action_record *act;
+ error_def(ERR_CCPBADMSG);
+ error_def(ERR_OPRCCPSTOP);
+
+#define CCP_TABLE_ENTRY(A,B,C,D) void B();
+#include "ccpact_tab.h"
+#undef CCP_TABLE_ENTRY
+#define CCP_TABLE_ENTRY(A,B,C,D) B,
+ static readonly (*dispatch_table[])() =
+{
+#include "ccpact_tab.h"
+};
+#undef CCP_TABLE_ENTRY
+
+ licensed= TRUE ;
+ gtm_env_init(); /* read in all environment variables before any function call (particularly malloc) */
+ get_page_size();
+ ccp_init();
+ lib$establish(ccp_ch);
+ while (!ccp_stop || ccp_stop_ctr > 0)
+ {
+ act = ccp_act_select();
+ if (!act)
+ sys$hiber();
+ else
+ {
+ if (act->action < 0 || act->action >= CCPACTION_COUNT)
+ ccp_signal_cont(ERR_CCPBADMSG);
+ else
+ (*dispatch_table[act->action])(act);
+ ccp_act_complete();
+ }
+ }
+ ccp_exit();
+ return ERR_OPRCCPSTOP;
+}
diff --git a/sr_vvms/ccp_add_reg.c b/sr_vvms/ccp_add_reg.c
new file mode 100644
index 0000000..394bc2b
--- /dev/null
+++ b/sr_vvms/ccp_add_reg.c
@@ -0,0 +1,25 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "ccp.h"
+
+GBLREF ccp_db_header *ccp_reg_root;
+
+void ccp_add_reg(d)
+ccp_db_header *d;
+{
+ /* see note for ccp_get_reg...go ordered list for efficiency */
+ d->next = ccp_reg_root;
+ ccp_reg_root = d;
+ return;
+}
diff --git a/sr_vvms/ccp_bt_get.c b/sr_vvms/ccp_bt_get.c
new file mode 100644
index 0000000..f0dd075
--- /dev/null
+++ b/sr_vvms/ccp_bt_get.c
@@ -0,0 +1,40 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+
+
+bt_rec *ccp_bt_get(cs_addrs, block)
+/* this function returns a pointer to the bt_rec entry or 0 if not found */
+int4 block; /* block number to put */
+sgmnt_addrs *cs_addrs;
+{
+ register sgmnt_addrs *cs;
+ bt_rec *p;
+
+ cs = cs_addrs;
+ p = cs->bt_header + (block % cs->hdr->bt_buckets);
+ assert(p->blk == BT_QUEHEAD);
+ for (;;)
+ { p = (bt_rec *) ((char *) p + p->blkque.fl);
+ if (p->blk == block)
+ { return p;
+ }
+ if (p->blk == BT_QUEHEAD)
+ { return 0;
+ }
+ }
+}
diff --git a/sr_vvms/ccp_ch.c b/sr_vvms/ccp_ch.c
new file mode 100644
index 0000000..b31d585
--- /dev/null
+++ b/sr_vvms/ccp_ch.c
@@ -0,0 +1,141 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "error.h"
+#include "gdsroot.h"
+#include "ccp.h"
+#include <descrip.h>
+#include <lnmdef.h>
+#include <opcdef.h>
+
+GBLREF uint4 process_id;
+GBLREF bool ccp_dump_on;
+
+error_def(ERR_CCPSIGCONT);
+
+static unsigned char pid_msg[] = "GT.CX_CONTROL--PID: ",
+ pc_msg[] = "PC: ";
+
+static $DESCRIPTOR (lnm$dcl_logical, "LNM$DCL_LOGICAL");
+static $DESCRIPTOR (gtm$deadlock, "GTM$DEADLOCK");
+
+static int attr = LNM$M_CASE_BLIND;
+
+
+CONDITION_HANDLER(ccp_ch)
+{
+ struct
+ {
+ char type;
+ int target : 24;
+ int4 rqstid;
+ char text[255];
+ } oper_msg;
+
+ struct dsc$descriptor_s oper_msg_dsc, sig_msg_dsc, fao_out_dsc;
+ int4 *pc, count;
+ uint4 *c, status;
+ unsigned short sig_msg_len, fao_len, oper_text_len;
+ char *text_ptr, sig_msg_buffer[255];
+
+
+ c = &SIGNAL;
+
+ /* Don't report CANCEL, and don't report DEADLOCK unless logical name GTM$DEADLOCK is defined */
+ if (SIGNAL == ERR_CCPSIGCONT && sig->chf$l_sig_args > 2 &&
+ (*(c + 3) == SS$_CANCEL ||
+ *(c + 3) == SS$_DEADLOCK && sys$trnlnm(&attr, &lnm$dcl_logical, >m$deadlock, NULL, NULL) != SS$_NORMAL))
+ CONTINUE;
+
+ if (ccp_dump_on)
+ ccp_dump();
+
+
+ /* Initialize constant fields */
+
+ oper_msg_dsc.dsc$b_dtype = fao_out_dsc.dsc$b_dtype
+ = sig_msg_dsc.dsc$b_dtype
+ = DSC$K_DTYPE_T;
+
+ oper_msg_dsc.dsc$b_class = fao_out_dsc.dsc$b_class
+ = sig_msg_dsc.dsc$b_class
+ = DSC$K_CLASS_S;
+
+ oper_msg_dsc.dsc$a_pointer = &oper_msg;
+ sig_msg_dsc.dsc$a_pointer = sig_msg_buffer;
+
+ oper_msg.type = OPC$_RQ_RQST;
+ oper_msg.target = OPC$M_NM_CLUSTER; /***** This should be setable by CCE *****/
+ oper_msg.rqstid = 0;
+
+
+ /* Move PID text into message */
+ text_ptr = oper_msg.text;
+ memcpy(text_ptr, pid_msg, sizeof pid_msg - 1);
+ text_ptr += sizeof pid_msg - 1;
+ text_ptr += ojhex_to_str(process_id, text_ptr);
+ *text_ptr++ = ' ';
+
+ if (SIGNAL != ERR_CCPSIGCONT)
+ {
+ pc = (int4 *)sig + sig->chf$l_sig_args - 1;
+ memcpy(text_ptr, pc_msg, sizeof pc_msg - 1);
+ text_ptr += sizeof pc_msg - 1;
+ text_ptr += ojhex_to_str(*pc, text_ptr);
+ *text_ptr++ = ' ';
+ }
+
+ fao_out_dsc.dsc$w_length = sizeof oper_msg.text - (text_ptr - oper_msg.text);
+ count = sig->chf$l_sig_args - 2;
+
+ for (;;)
+ {
+ sig_msg_dsc.dsc$w_length = sizeof sig_msg_buffer;
+ sys$getmsg(*c++, &sig_msg_len, &sig_msg_dsc, 0, NULL);
+ sig_msg_dsc.dsc$w_length = sig_msg_len;
+
+ fao_out_dsc.dsc$a_pointer = text_ptr;
+ /* Allow max of 4 fao args, will ignore if not used */
+ sys$fao(&sig_msg_dsc, &fao_len, &fao_out_dsc, *(c+1), *(c+2), *(c+3), *(c+4));
+ text_ptr += fao_len;
+
+ if (--count != 0)
+ if (fao_len == sig_msg_len)
+ {
+ if (*c == 0)
+ {
+ c++;
+ count--;
+ }
+ }
+ else
+ {
+ count -= *c + 1;
+ c += *c + 1;
+ }
+
+ if (count == 0)
+ break;
+
+ *text_ptr++ = ' ';
+ fao_out_dsc.dsc$w_length -= fao_len + 1;
+ }
+
+ oper_msg_dsc.dsc$w_length = text_ptr - (char *)&oper_msg;
+ sys$sndopr(&oper_msg_dsc, 0);
+
+ /* Drop active entry, if any, and continue to operate */
+ if (SIGNAL == ERR_CCPSIGCONT)
+ CONTINUE;
+
+ NEXTCH;
+}
diff --git a/sr_vvms/ccp_close1.c b/sr_vvms/ccp_close1.c
new file mode 100644
index 0000000..ca7b7d1
--- /dev/null
+++ b/sr_vvms/ccp_close1.c
@@ -0,0 +1,237 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2003 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <fab.h>
+#include <lckdef.h>
+#include <secdef.h>
+#include <psldef.h>
+#include <descrip.h>
+#include <efndef.h>
+
+
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "ccp.h"
+#include "jnl.h"
+#include "locks.h"
+#include "del_sec.h"
+#include "mem_list.h"
+
+#define PRIORITY 2
+
+GBLREF ccp_relque *ccp_action_que;
+GBLREF ccp_db_header *ccp_reg_root;
+GBLREF bool ccp_stop;
+GBLREF int ccp_stop_ctr;
+GBLREF jnl_gbls_t jgbl;
+
+void ccp_close_timeout(); /* TODO: move to a header */
+
+static int4 delta_1_sec[2] = { -10000000, -1 };
+
+
+void ccp_close1(ccp_db_header *db)
+{
+ ccp_db_header *db0, *db1;
+ ccp_que_entry *que_ent;
+ ccp_relque *que_hd;
+ mem_list *ml_ptr, *ml_ptr_hold;
+ sgmnt_addrs *csa;
+ vms_gds_info *gds_info;
+ unsigned char section_name[GLO_NAME_MAXLEN];
+ uint4 retadr[2], status, outaddrs[2];
+ struct dsc$descriptor_s name_dsc;
+
+
+ if (ccp_stop)
+ ccp_stop_ctr--;
+
+ if (db->stale_in_progress)
+ sys$cantim(&db->stale_timer_id, PSL$C_USER);
+
+ ccp_quemin_adjust(CCP_CLOSE_REGION);
+
+ sys$cantim(&db->tick_timer_id, PSL$C_USER);
+ sys$cantim(&db->quantum_timer_id, PSL$C_USER);
+
+ db->segment->nl->ccp_state = CCST_CLOSED;
+ db->wmexit_requested = TRUE; /* ignore any blocking ASTs - already releasing */
+
+ gds_info = FILE_INFO(db->greg);
+
+ if (JNL_ENABLED(db->glob_sec))
+ {
+ if (db->segment->jnl != NULL && db->segment->jnl->channel != 0)
+ {
+ status = sys$setimr(0, delta_1_sec, ccp_close_timeout, &db->close_timer_id, 0);
+ if (status != SS$_NORMAL)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+ status = ccp_enqw(EFN$C_ENF, LCK$K_EXMODE, &db->wm_iosb, LCK$M_CONVERT | LCK$M_NOQUEUE, NULL, 0,
+ NULL, 0, NULL, PSL$C_USER, 0);
+ if (status == SS$_NOTQUEUED)
+ /* We're not the only node accessing the journal file */
+ jnl_file_close(db->greg, FALSE, FALSE);
+ else
+ {
+ /***** Check error status here? *****/
+ if (db->segment->jnl->jnl_buff->before_images &&
+ db->segment->ti->curr_tn > db->segment->jnl->jnl_buff->epoch_tn)
+ {
+ csa = db->segment;
+ JNL_SHORT_TIME(jgbl.gbl_jrec_time); /* needed for jnl_put_jrt_pini()
+ and jnl_write_epoch_rec() */
+ if (0 == csa->jnl->pini_addr)
+ jnl_put_jrt_pini(csa);
+ db->segment->jnl->jnl_buff->epoch_tn = db->segment->ti->curr_tn;
+ jnl_write_epoch_rec(db->segment);
+ }
+ jnl_file_close(db->greg, TRUE, FALSE);
+ }
+ sys$cantim(&db->close_timer_id, PSL$C_USER);
+ status = gtm_deq(gds_info->s_addrs.jnl->jnllsb->lockid, NULL, PSL$C_USER, 0);
+ if (status != SS$_NORMAL)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+ }
+ }
+
+ db->segment = NULL; /* Warn AST's that the segment has been deleted */
+
+ status = sys$deq(db->lock_iosb.lockid, NULL, PSL$C_USER, LCK$M_CANCEL);
+ if (status != SS$_NORMAL && status != SS$_CANCELGRANT)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+
+ status = sys$deq(db->refcnt_iosb.lockid, NULL, PSL$C_USER, LCK$M_CANCEL);
+ if (status != SS$_NORMAL && status != SS$_CANCELGRANT)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+
+ status = sys$deq(db->wm_iosb.lockid, NULL, PSL$C_USER, LCK$M_CANCEL);
+ if (status != SS$_NORMAL && status != SS$_CANCELGRANT)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+
+ status = sys$deq(db->flush_iosb.lockid, NULL, PSL$C_USER, LCK$M_CANCEL);
+ if (status != SS$_NORMAL && status != SS$_CANCELGRANT)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+
+ status = sys$cancel(gds_info->fab->fab$l_stv);
+ if (status != SS$_NORMAL)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+
+ status = sys$dassgn(gds_info->fab->fab$l_stv);
+ if (status != SS$_NORMAL)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+
+ csa = &gds_info->s_addrs;
+
+ outaddrs[0] = csa->db_addrs[0] - OS_PAGE_SIZE; /* header no access page */
+ outaddrs[1] = csa->db_addrs[1] + OS_PAGE_SIZE; /* trailer no access page */
+ if (FALSE == is_va_free(outaddrs[0]))
+ gtm_deltva(outaddrs, NULL, PSL$C_USER);
+ if (status != SS$_NORMAL)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+
+ status = sys$cretva(csa->db_addrs, retadr, PSL$C_USER);
+ if (status != SS$_NORMAL)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+ assert(retadr[0] == csa->db_addrs[0] && retadr[1] == csa->db_addrs[1]);
+
+ ml_ptr_hold=db->mem_ptr;
+
+ if (ml_ptr_hold->prev != NULL)
+ {
+ /* if prior segment is adjacent and free, coalesce the segments */
+ if (ml_ptr_hold->prev->free &&
+ ml_ptr_hold->addr == ml_ptr_hold->prev->addr + OS_PAGELET_SIZE * ml_ptr_hold->prev->pages)
+ {
+ ml_ptr = ml_ptr_hold->prev;
+ ml_ptr->next = ml_ptr_hold->next;
+ if (ml_ptr->next != NULL)
+ ml_ptr->next->prev = ml_ptr;
+ ml_ptr->pages += ml_ptr_hold->pages;
+ free(ml_ptr_hold);
+ ml_ptr_hold = ml_ptr;
+ }
+ }
+
+ if (ml_ptr_hold->next != NULL)
+ {
+ /* if next segment is adjacent and free, coalesce the segments */
+ if (ml_ptr_hold->next->free &&
+ ml_ptr_hold->next->addr == ml_ptr_hold->addr + OS_PAGELET_SIZE * ml_ptr_hold->pages)
+ {
+ ml_ptr = ml_ptr_hold->next;
+ ml_ptr_hold->next = ml_ptr->next;
+ if (ml_ptr_hold->next != NULL)
+ ml_ptr_hold->next->prev = ml_ptr_hold;
+ ml_ptr_hold->pages += ml_ptr->pages;
+ free(ml_ptr);
+ }
+ }
+
+ ml_ptr_hold->free = TRUE;
+
+ global_name("GT$S", &gds_info->file_id, section_name);
+ name_dsc.dsc$a_pointer = §ion_name[1];
+ name_dsc.dsc$w_length = section_name[0];
+ name_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
+ name_dsc.dsc$b_class = DSC$K_CLASS_S;
+ status = del_sec(SEC$M_SYSGBL, &name_dsc, NULL);
+ if (status != SS$_NORMAL)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+
+ /* Dequeue locks after delete section in ccp_close,
+ acquire lock before create section in gvcst_init,
+ release lock after delete section in gds_rundown */
+
+ status = gtm_deq(db->lock_iosb.lockid, NULL, PSL$C_USER, 0);
+ if (status != SS$_NORMAL)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+
+ status = gtm_deq(db->refcnt_iosb.lockid, NULL, PSL$C_USER, 0);
+ if (status != SS$_NORMAL)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+
+ status = gtm_deq(db->wm_iosb.lockid, NULL, PSL$C_USER, 0);
+ if (status != SS$_NORMAL)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+
+ status = gtm_deq(db->flush_iosb.lockid, NULL, PSL$C_USER, 0);
+ if (status != SS$_NORMAL)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+
+ que_hd = &ccp_action_que[PRIORITY];
+ for (que_ent = (char *)que_hd + que_hd->bl; que_ent != que_hd; que_ent = (char *)que_ent + que_ent->q.bl)
+ if (que_ent->value.v.h == db)
+ que_ent->value.v.h = 0;
+
+ free(gds_info->fab->fab$l_nam);
+ free(gds_info->fab);
+ free(db->greg->dyn.addr);
+ free(db->greg);
+
+ /* Remove db from list, this list should never be changed in an AST */
+ for (db0 = ccp_reg_root, db1 = NULL; db0 != db; db1 = db0, db0 = db0->next)
+ ;
+ if (db1 == NULL)
+ ccp_reg_root = db0->next;
+ else
+ db1->next = db0->next;
+
+ free(db);
+
+ return;
+}
diff --git a/sr_vvms/ccp_close_timeout.c b/sr_vvms/ccp_close_timeout.c
new file mode 100644
index 0000000..138a428
--- /dev/null
+++ b/sr_vvms/ccp_close_timeout.c
@@ -0,0 +1,39 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "ccp.h"
+#include "jnl.h"
+
+
+/* AST routine entered on expiration of timer set in ccp_close1 */
+
+void ccp_close_timeout(pdb)
+ccp_db_header **pdb;
+{
+ ccp_db_header *db;
+
+
+ assert(lib$ast_in_prog());
+
+ db = *pdb;
+ db->segment->jnl->jnl_buff->dskaddr = db->segment->jnl->jnl_buff->freeaddr;
+
+ sys$wake(NULL, NULL);
+
+ return;
+}
diff --git a/sr_vvms/ccp_closejnl_ast.c b/sr_vvms/ccp_closejnl_ast.c
new file mode 100644
index 0000000..e790462
--- /dev/null
+++ b/sr_vvms/ccp_closejnl_ast.c
@@ -0,0 +1,44 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <psldef.h>
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "ccp.h"
+#include "ccpact.h"
+
+
+static void ccp_closejnl_ast_user( gd_region *reg)
+{
+ ccp_action_record buffer;
+
+ buffer.action = CCTR_CLOSEJNL;
+ buffer.pid = 0;
+ buffer.v.reg = reg;
+ ccp_act_request(&buffer);
+}
+
+
+/* NOTE: Because this blocking AST routine is established via a call to gtm_enqw, it
+ executes in KERNEL mode; ccp_closejnl_ast_user, however, must execute in USER mode.
+ This is accomplished by using sys$dclast, explicitly specifying USER mode. */
+
+void ccp_closejnl_ast( gd_region *reg)
+{
+ assert(lib$ast_in_prog());
+
+ sys$dclast(ccp_closejnl_ast_user, reg, PSL$C_USER);
+}
diff --git a/sr_vvms/ccp_cluster_lock_wake.c b/sr_vvms/ccp_cluster_lock_wake.c
new file mode 100644
index 0000000..6e178c4
--- /dev/null
+++ b/sr_vvms/ccp_cluster_lock_wake.c
@@ -0,0 +1,27 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "ccp.h"
+#include "ccpact.h"
+#include "ccp_cluster_lock_wake.h"
+
+void ccp_cluster_lock_wake(gd_region *reg)
+{
+ ccp_sendmsg(CCTR_LKRQWAKE, &((vms_gds_info *)(reg->dyn.addr->file_cntl->file_info))->file_id);
+ return;
+}
diff --git a/sr_vvms/ccp_dump.c b/sr_vvms/ccp_dump.c
new file mode 100644
index 0000000..a4a717b
--- /dev/null
+++ b/sr_vvms/ccp_dump.c
@@ -0,0 +1,168 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <rms.h>
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "ccp.h"
+#include "jnl.h"
+#include <iodef.h>
+#include "probe.h"
+
+GBLREF ccp_db_header *ccp_reg_root;
+
+static const char header_label[] = "<ccp_db_header @ -------------->",
+#define header_offset 17 /* -----------------^ */
+ region_label[] = "<gd_region @ ------------------>",
+#define region_offset 13 /* -------------^ */
+ addrs_label[] = "<sgmnt_addrs @ ---------------->",
+#define addrs_offset 15 /* ---------------^ */
+ node_label[] = "<node_local @ ----------------->",
+#define node_offset 14 /* --------------^ */
+ jnl_label[] = "<jnl_private_control @ -------->",
+#define jnl_offset 23 /* -----------------------^ */
+ data_label1[] = "<sgmnt_data @ ",
+#define data_offset 14 /* --------------^ */
+ data_label2[] = " starts in next block>",
+ end_label[] = "<End of data>",
+ filename[] = "SYS$MANAGER:CCPDUMP.DMP";
+
+#define READ FALSE
+#define RECORD_SIZE 1024
+
+
+void ccp_dump(void)
+{
+ ccp_db_header *db;
+ sgmnt_data dummy;
+ struct FAB fab;
+ struct RAB rab;
+ char *c, buffer[RECORD_SIZE];
+ int i;
+
+
+ if (ccp_reg_root == NULL)
+ return;
+ fab = cc$rms_fab;
+ fab.fab$b_fns = SIZEOF(filename - 1);
+ fab.fab$l_fna = filename;
+ fab.fab$w_mrs = RECORD_SIZE;
+ fab.fab$b_rfm = FAB$C_FIX;
+ fab.fab$b_fac = FAB$M_PUT;
+ fab.fab$l_fop = FAB$M_CBT | FAB$M_MXV | FAB$M_TEF;
+ dummy.n_bts = WC_MAX_BUFFS;
+ dummy.bt_buckets = getprime(WC_MAX_BUFFS);
+ fab.fab$w_deq = fab.fab$l_alq
+ = LOCK_BLOCK(&dummy);
+ switch (sys$create(&fab))
+ {
+ case RMS$_NORMAL:
+ case RMS$_CREATED:
+ case RMS$_SUPERSEDE:
+ case RMS$_FILEPURGED:
+ break;
+ default:
+ return;
+ }
+ rab = cc$rms_rab;
+ rab.rab$w_rsz = RECORD_SIZE;
+ rab.rab$l_fab = &fab;
+ if (sys$connect(&rab) != RMS$_NORMAL)
+ return;
+ for (db = ccp_reg_root; db != NULL; db = db->next)
+ {
+ memset(buffer, 0, SIZEOF(buffer));
+ c = buffer;
+ if (probe(SIZEOF(ccp_db_header), db, READ))
+ {
+ memcpy(c, header_label, SIZEOF(header_label) - 1);
+ (void)i2hex_nofill(db, c + header_offset, SIZEOF(c) * 2);
+ c += SIZEOF(header_label) - 1;
+ /* ccp_db_header is defined in CCP.H */
+ memcpy(c, db, SIZEOF(ccp_db_header));
+ c += ROUND_UP(SIZEOF(ccp_db_header), 32);
+ }
+ if (probe(SIZEOF(gd_region), db->greg, READ))
+ {
+ memcpy(c, region_label, SIZEOF(region_label) - 1);
+ (void)i2hex_nofill(db->greg, c + region_offset, SIZEOF(c) * 2);
+ c += SIZEOF(region_label) - 1;
+ /* gd_region is defined in GDSFHEAD.H */
+ memcpy(c, db->greg, SIZEOF(gd_region));
+ c += ROUND_UP(SIZEOF(gd_region), 32);
+ }
+ if (probe(SIZEOF(sgmnt_addrs), db->segment, READ))
+ {
+ memcpy(c, addrs_label, SIZEOF(addrs_label) - 1);
+ (void)i2hex_nofill(db->segment, c + addrs_offset, SIZEOF(c) * 2);
+ c += SIZEOF(addrs_label) - 1;
+ /* sgmnt_addrs is defined in GDSFHEAD.H */
+ memcpy(c, db->segment, SIZEOF(sgmnt_addrs));
+ c += ROUND_UP(SIZEOF(sgmnt_addrs), 32);
+ if (probe(SIZEOF(node_local), db->segment->nl, READ))
+ {
+ memcpy(c, node_label, SIZEOF(node_label) - 1);
+ (void)i2hex_nofill(db->segment->nl, c + node_offset, SIZEOF(c) * 2);
+ c += SIZEOF(node_label) - 1;
+ /* node_local is defined in GDSBT.H */
+ memcpy(c, db->segment->nl, SIZEOF(node_local));
+ c += ROUND_UP(SIZEOF(node_local), 32);
+ }
+ if (db->segment->jnl != NULL && probe(SIZEOF(jnl_private_control), db->segment->jnl, READ))
+ {
+ memcpy(c, jnl_label, SIZEOF(jnl_label) - 1);
+ (void)i2hex_nofill(db->segment->jnl, c + jnl_offset, SIZEOF(c) * 2);
+ c += SIZEOF(jnl_label) - 1;
+ /* jnl_private_control is defined in JNL.H */
+ memcpy(c, db->segment->jnl, SIZEOF(jnl_private_control));
+ c += ROUND_UP(SIZEOF(jnl_private_control), 32);
+ }
+ }
+ memcpy(c, data_label1, SIZEOF(data_label1) - 1);
+ i = i2hex_nofill(db->glob_sec, c + data_offset, SIZEOF(c) * 2);
+ memcpy(c + SIZEOF(data_label1) - 1 + i, data_label2, SIZEOF(data_label2) - 1);
+ rab.rab$l_rbf = buffer;
+ if (sys$put(&rab) != RMS$_NORMAL)
+ {
+ sys$close(&fab);
+ return;
+ }
+ /* db->glob_sec points to sgmnt_data, defined in GDSFHEAD.H */
+ if (probe(RECORD_SIZE, db->glob_sec, READ))
+ {
+ i = DIVIDE_ROUND_UP((LOCK_BLOCK(db->glob_sec) * DISK_BLOCK_SIZE) + LOCK_SPACE_SIZE(db->glob_sec)
+ + CACHE_CONTROL_SIZE(db->glob_sec), OS_PAGELET_SIZE);
+ for (c = db->glob_sec; i > 0; c += RECORD_SIZE, i -= (RECORD_SIZE / OS_PAGELET_SIZE))
+ if (probe(RECORD_SIZE, c, READ))
+ {
+ rab.rab$l_rbf = c;
+ if (sys$put(&rab) != RMS$_NORMAL)
+ {
+ sys$close(&fab);
+ return;
+ }
+ } else
+ break;
+ }
+ }
+ memset(buffer, 0, RECORD_SIZE);
+ memcpy(buffer, end_label, SIZEOF(end_label) - 1);
+ rab.rab$l_rbf = buffer;
+ sys$put(&rab);
+ sys$close(&fab);
+ return;
+}
diff --git a/sr_vvms/ccp_enq.c b/sr_vvms/ccp_enq.c
new file mode 100644
index 0000000..ae9000d
--- /dev/null
+++ b/sr_vvms/ccp_enq.c
@@ -0,0 +1,42 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "error.h"
+#include "locks.h"
+
+/*
+ * ccp_enq is identical to sys$enq, except that it causes the CCPSIGCONT
+ * message to be issued to OPCOM if sys$enq returns an unsuccessful status.
+ */
+
+uint4 ccp_enq(
+ unsigned int efn,
+ unsigned int lkmode,
+ lock_sb *lksb,
+ unsigned int flags,
+ void *resnam,
+ unsigned int parid,
+ void *astadr,
+ unsigned int astprm,
+ void *blkast,
+ unsigned int acmode,
+ unsigned int nullarg)
+{
+ uint4 status;
+ error_def(ERR_CCPSIGCONT);
+
+ status = sys$enq(efn, lkmode, lksb, flags, resnam, parid, astadr, astprm, blkast, acmode, nullarg);
+ if ((ERROR | SEVERE) & status)
+ rts_error(VARLSTCNT(4) ERR_CCPSIGCONT, 1, caller_id(), status);
+ return status;
+}
diff --git a/sr_vvms/ccp_enqw.c b/sr_vvms/ccp_enqw.c
new file mode 100644
index 0000000..abd77c8
--- /dev/null
+++ b/sr_vvms/ccp_enqw.c
@@ -0,0 +1,44 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "error.h"
+#include "locks.h"
+
+/*
+ * ccp_enqw is identical to sys$enqw, except that it causes the CCPSIGCONT
+ * message to be issued to OPCOM if sys$enqw returns an unsuccessful status.
+ */
+
+uint4 ccp_enqw(
+ unsigned int efn,
+ unsigned int lkmode,
+ lock_sb *lksb,
+ unsigned int flags,
+ void *resnam,
+ unsigned int parid,
+ void *astadr,
+ unsigned int astprm,
+ void *blkast,
+ unsigned int acmode,
+ unsigned int nullarg)
+{
+ uint4 status;
+ error_def(ERR_CCPSIGCONT);
+
+ status = sys$enqw(efn, lkmode, lksb, flags, resnam, parid, astadr, astprm, blkast, acmode, nullarg);
+ if (SUCCESS & status)
+ status = (uint4)lksb->cond;
+ if ((ERROR | SEVERE) & status)
+ rts_error(VARLSTCNT(4) ERR_CCPSIGCONT, 1, caller_id(), status);
+ return status;
+}
diff --git a/sr_vvms/ccp_ewmwtbf_interrupt.c b/sr_vvms/ccp_ewmwtbf_interrupt.c
new file mode 100644
index 0000000..8a7577b
--- /dev/null
+++ b/sr_vvms/ccp_ewmwtbf_interrupt.c
@@ -0,0 +1,33 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "ccp.h"
+#include "ccpact.h"
+
+void ccp_ewmwtbf_interrupt( ccp_db_header **p)
+{
+ ccp_db_header *db;
+ ccp_action_record buff;
+
+ assert(lib$ast_in_prog());
+ db = *p;
+ buff.action = CCTR_EWMWTBF;
+ buff.pid = 0;
+ buff.v.h = db;
+ ccp_act_request(&buff);
+ return;
+}
diff --git a/sr_vvms/ccp_exi_ch.c b/sr_vvms/ccp_exi_ch.c
new file mode 100644
index 0000000..7567a2b
--- /dev/null
+++ b/sr_vvms/ccp_exi_ch.c
@@ -0,0 +1,26 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "error.h"
+
+
+#define UNWIND_LEVELS 3
+/* 0 unwinds CCP_EXI_CH, 1 unwinds CCP_RUNDOWN, 2,3 and 4 unwind the three VMS handlers,
+ thus returning to the pc when the exit condition was received. */
+
+static uint4 depth = UNWIND_LEVELS;
+
+CONDITION_HANDLER(ccp_exi_ch)
+{
+ START_CH;
+ UNWIND(&depth, 0);
+}
diff --git a/sr_vvms/ccp_exitwm1.c b/sr_vvms/ccp_exitwm1.c
new file mode 100644
index 0000000..2a8971d
--- /dev/null
+++ b/sr_vvms/ccp_exitwm1.c
@@ -0,0 +1,53 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <fab.h>
+#include <iodef.h>
+
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "ccp.h"
+
+
+/* AST routine entered on completion of sys$qio to write the master map, in ccp_tr_exitwm */
+
+void ccp_exitwm1( ccp_db_header *db)
+{
+ sgmnt_addrs *cs_addrs;
+ uint4 status;
+
+
+ assert(lib$ast_in_prog());
+
+ if ((db->qio_iosb.cond & 1) == 0)
+ ccp_signal_cont(db->qio_iosb.cond); /***** Is this reasonable? *****/
+
+ cs_addrs = db->segment;
+ if (db->last_lk_sequence < cs_addrs->ti->lock_sequence)
+ {
+ status = sys$qio(0, FILE_INFO(db->greg)->fab->fab$l_stv, IO$_WRITEVBLK, &db->qio_iosb, ccp_exitwm1a, db,
+ cs_addrs->lock_addrs[0], db->glob_sec->lock_space_size, LOCK_BLOCK(db->glob_sec) + 1, 0, 0, 0);
+ if ((status & 1) == 0)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+ db->last_lk_sequence = cs_addrs->ti->lock_sequence;
+ }
+ else
+ ccp_exitwm2(db);
+
+ return;
+}
diff --git a/sr_vvms/ccp_exitwm1a.c b/sr_vvms/ccp_exitwm1a.c
new file mode 100644
index 0000000..204a0c4
--- /dev/null
+++ b/sr_vvms/ccp_exitwm1a.c
@@ -0,0 +1,29 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "ccp.h"
+
+
+/* AST routine entered on completion of sys$qio to write the lock block, in ccp_tr_exitwm or ccp_exitwm1 */
+
+void ccp_exitwm1a( ccp_db_header *db)
+{
+ assert(lib$ast_in_prog());
+
+ if ((db->qio_iosb.cond & 1) == 0)
+ ccp_signal_cont(db->qio_iosb.cond); /***** Is this reasonable? *****/
+
+ ccp_exitwm2(db);
+
+ return;
+}
diff --git a/sr_vvms/ccp_exitwm2.c b/sr_vvms/ccp_exitwm2.c
new file mode 100644
index 0000000..b9a3044
--- /dev/null
+++ b/sr_vvms/ccp_exitwm2.c
@@ -0,0 +1,35 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <fab.h>
+#include <iodef.h>
+
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "ccp.h"
+
+
+/* If required, start to write header to disk */
+
+void ccp_exitwm2( ccp_db_header *db)
+{
+ uint4 status;
+
+ ccp_exitwm2a(db);
+ return;
+}
diff --git a/sr_vvms/ccp_exitwm2a.c b/sr_vvms/ccp_exitwm2a.c
new file mode 100644
index 0000000..dc3febf
--- /dev/null
+++ b/sr_vvms/ccp_exitwm2a.c
@@ -0,0 +1,42 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <fab.h>
+#include <iodef.h>
+
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "ccp.h"
+
+
+/* Start to write transaction history to disk */
+
+void ccp_exitwm2a(ccp_db_header *db)
+{
+ uint4 status;
+
+
+ assert(db->segment->ti->early_tn == db->segment->ti->curr_tn);
+
+ status = sys$qio(0, FILE_INFO(db->greg)->fab->fab$l_stv, IO$_WRITEVBLK, &db->qio_iosb, ccp_exitwm3, db,
+ &db->glob_sec->trans_hist, BT_SIZE(db->glob_sec) + SIZEOF(th_index), TH_BLOCK, 0, 0, 0);
+ if ((status & 1) == 0)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+
+ return;
+}
diff --git a/sr_vvms/ccp_exitwm3.c b/sr_vvms/ccp_exitwm3.c
new file mode 100644
index 0000000..f6e46f8
--- /dev/null
+++ b/sr_vvms/ccp_exitwm3.c
@@ -0,0 +1,90 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2003 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "ccp.h"
+#include "jnl.h"
+#include "locks.h"
+#include <lckdef.h>
+#include <psldef.h>
+#include <efndef.h>
+
+
+error_def(ERR_GTMCHECK);
+
+
+/* AST routine entered on completion of sys$qio to write transaction history to disk, in ccp_exitwm2a;
+ now we may drop write mode and start writing dirty buffers */
+
+void ccp_exitwm3( ccp_db_header *db)
+{
+ sgmnt_addrs *csa;
+ bt_rec *que_base, *que_top, *p;
+ ccp_action_record request;
+ uint4 status;
+
+
+ assert(lib$ast_in_prog());
+
+ csa = db->segment;
+ assert(csa->nl->ccp_state == CCST_WMXREQ);
+ assert(csa->ti->curr_tn == csa->ti->early_tn);
+
+ db->wm_iosb.valblk[CCP_VALBLK_TRANS_HIST] = csa->ti->curr_tn + csa->ti->lock_sequence;
+ if (JNL_ENABLED(csa->hdr) && csa->jnl != NULL)
+ {
+ assert(csa->jnl->channel != 0);
+ db->wm_iosb.valblk[CCP_VALBLK_JNL_ADDR] = csa->jnl->jnl_buff->freeaddr;
+ db->wm_iosb.valblk[CCP_VALBLK_EPOCH_TN] = csa->jnl->jnl_buff->epoch_tn;
+ /* lastaddr is no longer a field in jnl_buff
+ * db->wm_iosb.valblk[CCP_VALBLK_LST_ADDR] = csa->jnl->jnl_buff->lastaddr;
+ */
+ }
+
+ /* Convert Write-mode lock from Protected Write to Concurrent Read, writing the lock value block */
+ status = ccp_enqw(EFN$C_ENF, LCK$K_CRMODE, &db->wm_iosb, LCK$M_CONVERT | LCK$M_VALBLK, NULL, 0,
+ NULL, 0, NULL, PSL$C_USER, 0);
+ /***** Check error status here? *****/
+
+ for (que_base = csa->bt_header, que_top = que_base + csa->hdr->bt_buckets;
+ que_base < que_top;
+ ++que_base)
+ {
+ assert(que_base->blk == BT_QUEHEAD);
+
+ for (p = (bt_rec *)((char *)que_base + que_base->blkque.fl);
+ p != que_base;
+ p = (bt_rec *)((char *)p + p->blkque.fl))
+ {
+ if (((int4)p & 3) != 0)
+ ccp_signal_cont(ERR_GTMCHECK); /***** Is this reasonable? *****/
+ p->flushing = FALSE;
+ }
+ }
+
+ db->blocking_ast_received = FALSE;
+ db->wmexit_requested = FALSE;
+ csa->nl->ccp_state = CCST_WMXGNT;
+ db->wc_rover = 0;
+
+ request.action = CCTR_EWMWTBF;
+ request.pid = 0;
+ request.v.h = db;
+ ccp_act_request(&request);
+
+ return;
+}
diff --git a/sr_vvms/ccp_exitwm_attempt.c b/sr_vvms/ccp_exitwm_attempt.c
new file mode 100644
index 0000000..eeea4ee
--- /dev/null
+++ b/sr_vvms/ccp_exitwm_attempt.c
@@ -0,0 +1,177 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "ccp.h"
+#include <ssdef.h>
+
+
+/********************************************************************************
+* After any of the state transitions which might lead to exit write mode *
+* processing, this routine must be called to determine if all necessary *
+* criteria have been met. *
+* *
+* CAUTION: (1) To avoid race conditions this routine MUST only be called as *
+* an AST; *
+* (2) All bit fiddling with the db_header state bits MUST be done *
+* within an AST for the same reason. *
+********************************************************************************/
+
+void ccp_exitwm_attempt( ccp_db_header *db)
+{
+ ccp_action_record request;
+ int4 curr_time[2], result_time[2], ticks_left;
+ uint4 status;
+
+
+ assert(lib$ast_in_prog());
+
+ if (db->quantum_expired && db->wmexit_requested &&
+ db->segment != NULL && db->segment->nl->ccp_state == CCST_DRTGNT)
+ {
+ /* If first request is after quantum expired, one extra tick to try and get writes off */
+ if (db->drop_lvl == 0)
+ {
+ if (!db->extra_tick_started)
+ {
+ /* db->glob_sec->wcs_active_lvl -= db->glob_sec->n_bts / 2 - 7; */
+ db->extra_tick_started = TRUE;
+ status = sys$setimr(0, &db->glob_sec->ccp_tick_interval, ccp_extra_tick, &db->extra_tick_id, 0);
+ if (status == SS$_NORMAL)
+ return;
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+ }
+ else
+ if (!db->extra_tick_done)
+ return;
+ db->extra_tick_started = db->extra_tick_done
+ = FALSE;
+ }
+ assert(!db->tick_in_progress);
+ db->segment->nl->ccp_crit_blocked = TRUE;
+ if (db->segment->nl->in_crit == 0 && db->glob_sec->freeze == 0)
+ {
+ request.action = CCTR_EXITWM;
+ request.pid = 0;
+ request.v.exreq.fid = FILE_INFO(db->greg)->file_id;
+ request.v.exreq.cycle = db->segment->nl->ccp_cycle;
+ ccp_act_request(&request);
+ }
+ }
+ else
+ if (!db->quantum_expired && db->wmexit_requested && db->drop_lvl == 0)
+ {
+ /* Gradually drop active_lvl to reduce the number of dirty
+ buffers the CCP has to write upon releasing write mode */
+ sys$gettim(curr_time);
+ lib$sub_times(&db->start_wm_time, curr_time, result_time);
+ ticks_left = result_time[0] / db->glob_sec->ccp_tick_interval[0];
+ if (ticks_left >= 1)
+ db->drop_lvl = (db->glob_sec->n_bts / 2 - 7) / ticks_left;
+ }
+
+ return;
+}
+
+/***********************************************************************
+Write mode may not be exited while a GT.M process is processing in the critical
+section. In order to ensure this, the following scheme is used:
+
+THIS ROUTINE:
+ 1. crit_blocked <-- 1
+ 2. if crit is not owned then raise request for CCTR_EXITWM
+
+GRAB_CRIT:
+ 1. Get critical section
+ 2. If crit_blocked is set
+ A. Raise request for CCTR_EXITWM, wait for WMEXIT to complete
+ B. If not write mode, request write mode, wait to enter write mode
+
+REL_CRIT:
+ 1. Acquire cycle number
+ 1. Release critical section
+ 2. If crit_blocked is set
+ A. Raise request for CCTR_EXITWM for cycle number,
+ wait for WMEXIT to complete
+
+Requests for CCTR_EXITWM include the cycle number. If duplicates or 'obsolete'
+requests are received, they are ignored. For duplicate requests, i.e., the CCP
+is currently in the process of releasing write mode for the indicated cycle,
+the process id is stored to be issued a wake up when the exiting process is
+completed.
+
+The cycle must be acquired prior to releasing the critical section as the
+database could cycle between the time that crit is released and the ccp acts on
+the message, as during that time, either the ccp or another process that enters
+crit could initiate an WMEXIT.
+
+This routine will not enter a request to exit write mode in the queue if the
+critical section is owned as, having set the crit_blocked flag, it is
+guaranteed that a GT.M process will send such a request. This routine must set
+the flag and then check crit, and REL_CRIT must release crit and then check the
+flag in order to guarantee an exit write mode request being issued.
+
+An exit write mode request must be issued from REL_CRIT because it can not be
+guaranteed that another process will ever enter the critical section.
+
+This scheme leaves a small hole open because of the possible interaction of a
+second GT.M process. With the use of only two boolean flags (in crit and crit
+blocked) concurrency control cannot be guaranteed with the interaction of three
+processes. The hole is shown by the following sequence of events:
+
+ 1. GTM1 enters crit
+ 2. GTM1 releases crit
+ 3. GTM2 enters crit
+ 4. GTM2 checks ccp_crit_blocked, finds it clear and begins processing
+ 5. CCP sets crit blocked
+ 6. CCP checks in_crit, finds it non-zero and returns
+ 7. GTM1 checks crit_blocked, finds it set and issues an WMEXIT request
+ 8. CCP processes the WMEXIT request while GTM2 is processing in crit
+
+To remove this hole, another flag or the use of a state flag and state
+transistions rather than a boolean flag might be utilised. Currently, it is
+detected rather than prevented. This is done in CCP_TR_EXITWM by checking when
+the request has come from a GTM process to see if the critical section is
+owned. If it is and the process holding it is not the process that issued the
+WMEXIT request, then a second process has slipped through the hole. In this
+case, the WMEXIT request is ignored, as the second process will issue a request
+upon leaving the critical section. The process id is stored so that upon
+completion of the exiting process, the GTM process will be issued a wakeup.
+Should the check be done after the second process has already left the critical
+section, the CCP will continue exiting write mode. It will receive a second
+spurious request that will be ignored. (And possibly even a third request from
+a process entering the critical section which will also be ignored).
+
+Two optimizations have been conceived to reduce the chances of a process
+holding the critical section during the period that the database is not in read
+mode. The first of these is to have all GTM processes ensure that they are in
+write mode before they attempt to grab the critical section. The second is to
+have GTM processes wait until the ccp_crit_blocked flag is clear before
+attempting to grab the critical section. This second optimization is not
+currently implemented, because the use of CCP_USERWAIT requires that the
+process receive a wakeup from the CCP. To do this it must send a message and
+the only appropriate message is a request for write mode. Because the database
+is currently in write mode, waiting to exit it, this results in a stream of
+spurious messages being sent that clog the CCP's queues and mailbox. To
+implement this optimization will require a spin wait loop of some sort or the
+introduction of a new message type allowing a GTM process to wait on the
+clearing of the ccp_crit_blocked flag rather than on being in write mode.
+If this optimization is implemented, the call to CCP_USERWAIT could be
+eliminated from REL_CRIT.
+
+***********************************************************************/
diff --git a/sr_vvms/ccp_exitwm_blkast.c b/sr_vvms/ccp_exitwm_blkast.c
new file mode 100644
index 0000000..5a4dd17
--- /dev/null
+++ b/sr_vvms/ccp_exitwm_blkast.c
@@ -0,0 +1,40 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "ccp.h"
+
+
+/* Blocking AST routine entered when there is a Write-mode request from another machine */
+
+void ccp_exitwm_blkast(ccp_db_header **pdb)
+{
+ ccp_db_header *db;
+
+
+ db = *pdb;
+ db->blocking_ast_received = TRUE;
+
+ if (!db->wmexit_requested && CCP_SEGMENT_STATE(db->segment->nl, CCST_MASK_WRITE_MODE))
+ {
+ db->wmexit_requested = TRUE;
+ if (!db->quantum_expired && db->segment->nl->ccp_state == CCST_DRTGNT)
+ ccp_tick_start(db);
+ ccp_exitwm_attempt(db);
+ }
+
+ return;
+}
diff --git a/sr_vvms/ccp_extra_tick.c b/sr_vvms/ccp_extra_tick.c
new file mode 100644
index 0000000..3e43d1d
--- /dev/null
+++ b/sr_vvms/ccp_extra_tick.c
@@ -0,0 +1,29 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "ccp.h"
+
+void ccp_extra_tick(ccp_db_header **p)
+{
+ ccp_db_header *db;
+
+ assert(lib$ast_in_prog());
+ db = *p;
+ db->extra_tick_done = 1;
+ ccp_exitwm_attempt(db);
+ return;
+}
diff --git a/sr_vvms/ccp_format_querec.c b/sr_vvms/ccp_format_querec.c
new file mode 100644
index 0000000..5bb58ca
--- /dev/null
+++ b/sr_vvms/ccp_format_querec.c
@@ -0,0 +1,166 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "ccp.h"
+#include <descrip.h>
+#include "probe.h"
+
+
+unsigned char *ccp_format_time(
+date_time *tim,
+unsigned char *inaddr,
+unsigned short maxlen)
+{
+ globalvalue LIB$M_TIME_FIELDS;
+ struct dsc$descriptor_s dx;
+ short outlen;
+ unsigned int flags = LIB$M_TIME_FIELDS;
+
+ dx.dsc$w_length = maxlen;
+ dx.dsc$b_dtype = DSC$K_DTYPE_T;
+ dx.dsc$b_class = DSC$K_CLASS_S;
+ dx.dsc$a_pointer = inaddr;
+ lib$format_date_time(&dx, tim, 0, &outlen, &flags);
+ return inaddr + outlen;
+}
+
+
+unsigned char *ccp_fqstr(
+unsigned char *str,
+unsigned char *cp,
+unsigned int maxlen)
+{
+ int n;
+ for (n = 0 ; n < maxlen && *cp ; n++)
+ *str++ = *cp++;
+ return str;
+}
+
+
+#define CCP_TABLE_ENTRY(A,B,C,D) "A",
+static const unsigned char names[][16] =
+{
+#include "ccpact_tab.h"
+};
+#undef CCP_TABLE_ENTRY
+
+#define CCP_TABLE_ENTRY(A,B,C,D) C,
+static const unsigned char rectyp[] =
+{
+#include "ccpact_tab.h"
+};
+#undef CCP_TABLE_ENTRY
+
+
+unsigned char *ccp_format_querec(
+ccp_que_entry *inrec,
+unsigned char *outbuf,
+unsigned short outbuflen)
+{
+ unsigned char *out, *out1;
+ ccp_action_code act;
+ ccp_action_record *rec;
+ ccp_db_header *db;
+ int n;
+
+ rec = &inrec->value;
+ out = outbuf;
+ act = rec->action;
+ if (act < 0 || act >= CCPACTION_COUNT)
+ {
+ out = ccp_fqstr(out, "Action code not valid", outbuflen);
+ /* should add more info here */
+ return out;
+ }
+ out1 = out + 10;
+ out = ccp_fqstr(out, &names[act][5], SIZEOF(names[act]));
+ while (out < out1)
+ *out++ = ' ';
+ i2hex(rec->pid, out, SIZEOF(rec->pid) *2);
+ out += 8;
+ *out++ = ' ';
+ out = ccp_format_time(&inrec->request_time, out, outbuf + outbuflen - out);
+ *out++ = ' ';
+ out = ccp_format_time(&inrec->process_time, out, outbuf + outbuflen - out);
+ *out++ = ' ';
+ switch(rectyp[act])
+ {
+/* add info here */
+ case CCTVSTR:
+ out = ccp_fqstr(out, rec->v.str.txt, rec->v.str.len);
+ break;
+ case CCTVMBX:
+ break;
+ case CCTVFIL:
+ assert(rec->v.file_id.dvi[0] < SIZEOF(rec->v.file_id.dvi));
+ out = ccp_fqstr(out, &rec->v.file_id.dvi[1], rec->v.file_id.dvi[0]);
+ for (n = 0 ; n < SIZEOF(rec->v.file_id.did) / SIZEOF(rec->v.file_id.did[0]) ; n++)
+ {
+ *out++ = ' ';
+ i2hex(rec->v.file_id.did[n], out, SIZEOF(rec->v.file_id.did[n]) * 2);
+ out += SIZEOF(rec->v.file_id.did[n]) * 2;
+ /* note: wouldn't hurt tomodify i2hex to return end of string */
+ }
+ for (n = 0 ; n < SIZEOF(rec->v.file_id.fid) / SIZEOF(rec->v.file_id.fid[0]) ; n++)
+ {
+ *out++ = ' ';
+ i2hex(rec->v.file_id.fid[n], out, SIZEOF(rec->v.file_id.fid[n]) * 2);
+ out += SIZEOF(rec->v.file_id.fid[n]) * 2;
+ }
+ break;
+ case CCTVDBP:
+ db = rec->v.h;
+ if (probe(SIZEOF(*db),db,FALSE) && probe(SIZEOF(gd_region), db->greg, FALSE))
+ { if (probe(SIZEOF(sgmnt_data),db->glob_sec,FALSE) &&
+ !memcmp(db->glob_sec->label, GDS_LABEL,GDS_LABEL_SZ -1))
+ {
+ assert(((vms_gds_info *)(db->greg->dyn.addr->file_cntl->file_info))->file_id.dvi[0]
+ < SIZEOF(((vms_gds_info *)(db->greg->dyn.addr->file_cntl->file_info))->file_id.dvi));
+ out = ccp_fqstr(out, &((vms_gds_info *)(db->greg->dyn.addr->file_cntl->file_info))->file_id.dvi[1],
+ ((vms_gds_info *)(db->greg->dyn.addr->file_cntl->file_info))->file_id.dvi[0]);
+ for (n = 0 ; n <
+ SIZEOF(((vms_gds_info *)(db->greg->dyn.addr->file_cntl->file_info))->file_id.did)
+ / SIZEOF(((vms_gds_info *)(db->greg->dyn.addr->file_cntl->file_info))->file_id.did[0]) ;
+ n++)
+ {
+ *out++ = ' ';
+ i2hex(((vms_gds_info *)(db->greg->dyn.addr->file_cntl->file_info))->file_id.did[n], out,
+ SIZEOF(((vms_gds_info *)(db->greg->dyn.addr->file_cntl->file_info))->file_id.did[n]) * 2);
+ out +=
+ SIZEOF(((vms_gds_info *)(db->greg->dyn.addr->file_cntl->file_info))->file_id.did[n]) * 2;
+ /* note: wouldn't hurt tomodify i2hex to return end of string */
+ }
+ for (n = 0 ;
+ n <
+ SIZEOF(((vms_gds_info *)(db->greg->dyn.addr->file_cntl->file_info))->file_id.fid)
+ / SIZEOF(((vms_gds_info *)(db->greg->dyn.addr->file_cntl->file_info))->file_id.fid[0]) ;
+ n++)
+ {
+ *out++ = ' ';
+ i2hex(((vms_gds_info *)(db->greg->dyn.addr->file_cntl->file_info))->file_id.fid[n],
+ out,
+ SIZEOF(((vms_gds_info *)(db->greg->dyn.addr->file_cntl->file_info))->file_id.fid[n]) * 2);
+ out +=
+ SIZEOF(((vms_gds_info *)(db->greg->dyn.addr->file_cntl->file_info))->file_id.fid[n]) * 2;
+ }
+ }
+ }
+ break;
+ }
+ return out;
+}
diff --git a/sr_vvms/ccp_get_reg.c b/sr_vvms/ccp_get_reg.c
new file mode 100644
index 0000000..31e1564
--- /dev/null
+++ b/sr_vvms/ccp_get_reg.c
@@ -0,0 +1,36 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "ccp.h"
+
+GBLREF ccp_db_header *ccp_reg_root;
+
+ccp_db_header *ccp_get_reg(name)
+gds_file_id *name;
+{
+ ccp_db_header *ptr;
+
+ assert(!lib$ast_in_prog());
+ /* note: should use ordered list for more efficiency */
+ for ( ptr = ccp_reg_root ; ptr ; ptr = ptr->next)
+ { if (!memcmp(name, &((vms_gds_info *)(ptr->greg->dyn.addr->file_cntl->file_info))->file_id, SIZEOF(gds_file_id)))
+ break;
+ }
+ return ptr;
+}
diff --git a/sr_vvms/ccp_get_reg_by_fab.c b/sr_vvms/ccp_get_reg_by_fab.c
new file mode 100644
index 0000000..da2f2b2
--- /dev/null
+++ b/sr_vvms/ccp_get_reg_by_fab.c
@@ -0,0 +1,33 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "ccp.h"
+
+GBLREF ccp_db_header *ccp_reg_root;
+
+ccp_db_header *ccp_get_reg_by_fab(fb)
+struct FAB *fb;
+{
+ ccp_db_header *ptr;
+
+ assert(!lib$ast_in_prog());
+ for ( ptr = ccp_reg_root ; ptr && ((vms_gds_info *)(ptr->greg->dyn.addr->file_cntl->file_info))->fab != fb; ptr = ptr->next)
+ ;
+ return ptr;
+}
diff --git a/sr_vvms/ccp_gotdrt_tick.c b/sr_vvms/ccp_gotdrt_tick.c
new file mode 100644
index 0000000..209769c
--- /dev/null
+++ b/sr_vvms/ccp_gotdrt_tick.c
@@ -0,0 +1,23 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "ccp.h"
+
+void ccp_gotdrt_tick( ccp_db_header *db)
+{
+
+ if (!db->tick_in_progress && !db->quantum_expired)
+ { ccp_tick_start(db);
+ }
+ return;
+}
diff --git a/sr_vvms/ccp_init.c b/sr_vvms/ccp_init.c
new file mode 100644
index 0000000..ab87329
--- /dev/null
+++ b/sr_vvms/ccp_init.c
@@ -0,0 +1,178 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2007 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <descrip.h>
+#include <jpidef.h>
+#include <prvdef.h>
+#include <ssdef.h>
+#include "gtm_inet.h"
+
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "ccp.h"
+#include "ladef.h"
+#include "repl_msg.h"
+#include "gtmsource.h"
+#include "filestruct.h"
+#include "jnl.h"
+#include "gdscc.h"
+#include "locks.h"
+#include "gdskill.h"
+#include "buddy_list.h"
+#include "hashtab_int4.h" /* needed for tp.h */
+#include "tp.h"
+#include "getjobnum.h"
+#include "lmdef.h"
+#include "dfntmpmbx.h"
+#include "init_secshr_addrs.h"
+
+typedef struct{
+int4 link;
+int4 *exit_hand;
+int4 arg_cnt;
+int4 *cond_val;
+} desblk;
+
+GBLDEF int4 ccp_exi_condition;
+GBLDEF desblk ccp_exi_blk;
+GBLDEF unsigned short ccp_channel;
+GBLDEF ccp_db_header *ccp_reg_root = 0;
+
+GBLREF bool checkdb_timer;
+GBLREF bool ccp_dump_on;
+GBLREF bool licensed;
+GBLREF int4 lkid, lid;
+
+LITREF int4 ccp_prd_len;
+LITREF char ccp_prd_name[];
+LITREF char ccp_ver_name[];
+LITREF int4 ccp_ver_len;
+OS_PAGE_SIZE_DECLARE
+
+static unsigned char old_name_str[15];
+static uint4 name_status;
+static $DESCRIPTOR(old_proc_name, old_name_str);
+
+void
+ccp_init(void)
+{
+ uint4 status, grp_num, prvadr[2], prvprv[2];
+ mstr lnm$system = {10, "LNM$SYSTEM"};
+ unsigned short out_len;
+ $DESCRIPTOR(proc_name, CCP_PRC_NAME);
+ $DESCRIPTOR(desc, "GTM$CLSTLK");
+ $DESCRIPTOR(lognam, CCP_MBX_NAME);
+ error_def(ERR_CCPGRP);
+ error_def(ERR_CCPNAME);
+ error_def(ERR_CCPMBX);
+ error_def(ERR_WILLEXPIRE);
+ error_def(LP_NOCNFDB);
+ error_def(LP_INVCSM);
+ int4 lic_status; /* license status */
+ int4 inid = 0; /* initial node number */
+ int4 mdl = 0; /* hw. nodel */
+ int4 nid = 0; /* node number */
+ int4 days = 0; /* days to expiration */
+ int4 lic_x; /* license value */
+ char *h = NULL; /* license data base */
+ char *pak = NULL; /* license pak */
+ struct dsc$descriptor_s dprd;
+ struct dsc$descriptor_s dver;
+ int4 thirty_sec[2] = { -300000000 , -1};
+
+ ccp_dump_on = 1;
+ dprd.dsc$w_length = ccp_prd_len;
+ dprd.dsc$b_dtype = DSC$K_DTYPE_T;
+ dprd.dsc$b_class = DSC$K_CLASS_S;
+ dprd.dsc$a_pointer = ccp_prd_name;
+ dver.dsc$w_length = ccp_ver_len;
+ dver.dsc$b_dtype = DSC$K_DTYPE_T;
+ dver.dsc$b_class = DSC$K_CLASS_S;
+ dver.dsc$a_pointer = ccp_ver_name;
+ licensed = TRUE;
+ lic_status = SS$_NORMAL;
+ lkid = 2;
+#ifndef NOLICENSE
+ lic_status = ((NULL == (h = la_getdb(LMDB))) ? LP_NOCNFDB : SS$_NORMAL);
+#endif
+#ifndef DEBUG
+ status = lib$getjpi(&JPI$_GRP, 0, 0, &grp_num, 0, 0);
+ if (0 == (status & 1))
+ lib$signal(ERR_CCPGRP, 0, status);
+ if (1 != grp_num)
+ lib$signal(ERR_CCPGRP);
+#endif
+ name_status = lib$getjpi(&JPI$_PRCNAM, 0, 0, 0, &old_proc_name, &out_len);
+ old_proc_name.dsc$w_length = out_len;
+ status = sys$setprn(&proc_name);
+ if (0 == (status & 1))
+ lib$signal(ERR_CCPNAME, 0, status);
+#ifndef NOLICENSE
+ lic_status = ((1 == (lic_status & 1)) ? lm_mdl_nid(&mdl, &nid, &inid) : lic_status);
+#endif
+ getjobnum();
+ INVOKE_INIT_SECSHR_ADDRS;
+ prvadr[1] = 0;
+ prvadr[0] = PRV$M_SYSLCK | PRV$M_SYSNAM | PRV$M_OPER;
+ status = sys$setprv(TRUE, &prvadr[0], FALSE, &prvprv[0]);
+ if (0 == (status & 1))
+ lib$signal(status);
+#ifdef NOLICENSE
+ lid = 1;
+ lic_x = 32767;
+#else
+ lic_status = ((1 == (lic_status & 1)) ? lp_licensed(h, &dprd, &dver, mdl, nid, &lid, &lic_x, &days, pak) : lic_status);
+#endif
+ dfntmpmbx(lnm$system.len, lnm$system.addr);
+ status = sys$crembx(0, &ccp_channel, 0, 0, 0, 0, &lognam);
+ if (0 == (status & 1))
+ lib$signal(ERR_CCPMBX, 0, status);
+ ccp_act_init();
+#ifndef NOLICENSE
+ if (LP_NOCNFDB != lic_status)
+ la_freedb(h);
+ if (1 == (lic_status & 1))
+ {
+ licensed = TRUE;
+ if (days < 14)
+ rts_error(VARLSTCNT(1) ERR_WILLEXPIRE);
+ } else
+ {
+ licensed = FALSE;
+ /* if (LP_INVCSM != lic_status) */
+ rts_error(VARLSTCNT(1) lic_status);
+ }
+#endif
+ ccp_mbx_start();
+ ccp_exi_blk.exit_hand = &ccp_rundown;
+ ccp_exi_blk.arg_cnt = 1;
+ ccp_exi_blk.cond_val = &ccp_exi_condition;
+ sys$dclexh(&ccp_exi_blk);
+ sys$setimr(0, &thirty_sec[0], ccp_tr_checkdb, 0, 0);
+ checkdb_timer = TRUE;
+ return;
+}
+
+void
+ccp_exit(void)
+{
+ error_def(ERR_OPRCCPSTOP);
+
+ if (name_status & 1)
+ sys$setprn(&old_proc_name);
+ lib$signal(ERR_OPRCCPSTOP);
+}
diff --git a/sr_vvms/ccp_lkdowake_blkast.c b/sr_vvms/ccp_lkdowake_blkast.c
new file mode 100644
index 0000000..4a65c83
--- /dev/null
+++ b/sr_vvms/ccp_lkdowake_blkast.c
@@ -0,0 +1,25 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "ccp.h"
+#include "ccpact.h"
+
+/* blocking ast for lock wake up, request from another machine to do a lock wake up */
+
+void ccp_lkdowake_blkast(db)
+ccp_db_header *db;
+{
+ assert(lib$ast_in_prog());
+ db->remote_wakeup = TRUE;
+ return;
+}
diff --git a/sr_vvms/ccp_lkrqwake1.c b/sr_vvms/ccp_lkrqwake1.c
new file mode 100644
index 0000000..2af74b1
--- /dev/null
+++ b/sr_vvms/ccp_lkrqwake1.c
@@ -0,0 +1,45 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "ccp.h"
+#include "locks.h"
+#include <lckdef.h>
+#include <psldef.h>
+#include <ssdef.h>
+
+
+/* AST routine entered on completion of CR mode lock conversion request
+ in ccp_opendb3c, ccp_tr_lkrqwake, ccp_tr_writedb1, or here */
+
+void ccp_lkrqwake1( ccp_db_header *db)
+{
+ uint4 status;
+
+
+ assert(lib$ast_in_prog());
+
+ if (db->lock_iosb.cond == SS$_NORMAL)
+ return;
+
+ ccp_signal_cont(db->lock_iosb.cond); /***** Is this reasonable? *****/
+
+ if (db->lock_iosb.cond == SS$_DEADLOCK)
+ {
+ /* Just try again */
+ status = ccp_enq(0, LCK$K_CRMODE, &db->lock_iosb, LCK$M_CONVERT | LCK$M_SYNCSTS, NULL, 0,
+ ccp_lkrqwake1, db, ccp_lkdowake_blkast, PSL$C_USER, 0);
+ /***** Check error status here? *****/
+ }
+
+ return;
+}
diff --git a/sr_vvms/ccp_mbx_manager.c b/sr_vvms/ccp_mbx_manager.c
new file mode 100644
index 0000000..284f8cb
--- /dev/null
+++ b/sr_vvms/ccp_mbx_manager.c
@@ -0,0 +1,62 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "ccp.h"
+#include <iodef.h>
+#include <efndef.h>
+
+
+GBLREF unsigned short ccp_channel;
+static bool mailbox_running = FALSE;
+
+static void ccp_mbx_interrupt(void);
+
+void ccp_mbx_start(void)
+{
+ uint4 status;
+ error_def(ERR_CCPMBX);
+
+ if (mailbox_running)
+ return;
+ mailbox_running = TRUE;
+ status = sys$qio(0, ccp_channel, (IO$_SETMODE|IO$M_WRTATTN), 0,0,0, ccp_mbx_interrupt,0 ,0 ,0 ,0 ,0);
+ if ((status & 1) == 0)
+ lib$signal(ERR_CCPMBX, 0 , status);
+ return;
+}
+
+static void ccp_mbx_interrupt(void)
+{
+ ccp_action_record buff;
+ unsigned short mbsb[4];
+ bool more_room;
+ uint4 status;
+ error_def(ERR_CCPMBX);
+
+ mailbox_running = FALSE;
+ status = sys$qiow(EFN$C_ENF, ccp_channel, (IO$_READVBLK | IO$M_NOW), &mbsb[0], 0, 0, &buff,
+ SIZEOF(buff), 0, 0, 0, 0);
+ if (status & 1)
+ status = mbsb[0];
+ if ((status & 1) == 0)
+ lib$signal(ERR_CCPMBX, 0, status);
+ more_room = ccp_act_request(&buff);
+ if (more_room)
+ ccp_mbx_start();
+ return;
+}
diff --git a/sr_vvms/ccp_opendb.c b/sr_vvms/ccp_opendb.c
new file mode 100644
index 0000000..d823bed
--- /dev/null
+++ b/sr_vvms/ccp_opendb.c
@@ -0,0 +1,69 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "ccp.h"
+#include <fab.h>
+#include <nam.h>
+
+void ccp_opendb( ccp_action_record *rec)
+{
+ ccp_db_header *db;
+ struct NAM *ccp_nam;
+ struct FAB *ccp_fab;
+ uint4 status;
+ int size;
+
+ db = malloc(SIZEOF(*db));
+ memset(db, 0, SIZEOF(*db));
+ db->write_wait.last = &db->write_wait.first;
+ db->flu_wait.last = &db->flu_wait.first;
+ db->exitwm_wait.last = &db->exitwm_wait.first;
+ db->reopen_wait.last = &db->reopen_wait.first;
+ ccp_pndg_proc_add(&db->write_wait, rec->pid);
+ db->greg = malloc(SIZEOF(*db->greg));
+ memset(db->greg, 0, SIZEOF(*db->greg));
+ db->greg->dyn.addr = malloc(SIZEOF(gd_segment));
+ memset(db->greg->dyn.addr, 0, SIZEOF(gd_segment));
+ FILE_CNTL_INIT(db->greg->dyn.addr);
+ ccp_fab = ((vms_gds_info *)(db->greg->dyn.addr->file_cntl->file_info))->fab = malloc(SIZEOF(struct FAB));
+ *ccp_fab = cc$rms_fab;
+ ccp_nam = malloc(SIZEOF(*ccp_nam));
+ *ccp_nam = cc$rms_nam;
+ ccp_fab->fab$l_nam = ccp_nam;
+ db->greg->dyn.addr->acc_meth = dba_bg;
+ ((vms_gds_info *)(db->greg->dyn.addr->file_cntl->file_info))->file_id = rec->v.file_id;
+ db->segment = &((vms_gds_info *)(db->greg->dyn.addr->file_cntl->file_info))->s_addrs;
+/* Malloc a temporary local node struct so can mark the state, necessary for processing of CCP_TR_WRITEDB from other processes */
+ db->segment->nl = malloc(SIZEOF(node_local));
+ db->segment->nl->ccp_state = CCST_OPNREQ;
+ db->segment->now_crit = 0;
+ ccp_add_reg(db);
+ memcpy(ccp_nam->nam$t_dvi,rec->v.file_id.dvi,SIZEOF(rec->v.file_id.dvi));
+ memcpy(ccp_nam->nam$w_did,rec->v.file_id.did, SIZEOF(rec->v.file_id.did));
+ memcpy(ccp_nam->nam$w_fid,rec->v.file_id.fid, SIZEOF(rec->v.file_id.fid));
+ ccp_fab->fab$l_fop = (FAB$M_UFO | FAB$M_NAM | FAB$M_CBT);
+ ccp_fab->fab$b_fac = (FAB$M_PUT | FAB$M_GET | FAB$M_BIO);
+ ccp_fab->fab$b_rtv = WINDOW_ALL;
+ ccp_fab->fab$b_shr = (FAB$M_SHRPUT | FAB$M_SHRGET | FAB$M_UPI);
+ db->extra_tick_id = db->tick_timer_id = db->quantum_timer_id = db->exitwm_timer_id =
+ db->wmcrit_timer_id = db->close_timer_id = db;
+ sys$open(ccp_fab, ccp_opendb1e, ccp_opendb1a);
+ ccp_quemin_adjust(CCP_OPEN_REGION);
+ return;
+}
diff --git a/sr_vvms/ccp_opendb1.c b/sr_vvms/ccp_opendb1.c
new file mode 100644
index 0000000..00f2700
--- /dev/null
+++ b/sr_vvms/ccp_opendb1.c
@@ -0,0 +1,35 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "ccp.h"
+
+
+/* AST routine entered on completion of sys$qio to read database file header in ccp_tr_opendb1a */
+
+void ccp_opendb1( ccp_db_header *db)
+{
+ ccp_action_record request;
+
+
+ assert(lib$ast_in_prog());
+
+ if ((db->qio_iosb.cond & 1) == 0)
+ ccp_signal_cont(db->qio_iosb.cond); /***** Is this reasonable? *****/
+
+ request.action = CCTR_OPENDB1;
+ request.pid = 0;
+ request.v.h = db;
+ ccp_act_request(&request);
+
+ return;
+}
diff --git a/sr_vvms/ccp_opendb1a.c b/sr_vvms/ccp_opendb1a.c
new file mode 100644
index 0000000..e83dadd
--- /dev/null
+++ b/sr_vvms/ccp_opendb1a.c
@@ -0,0 +1,28 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "ccp.h"
+#include "ccpact.h"
+
+void ccp_opendb1a( struct FAB *fb)
+/* entered after sucessful sys$open from ccp_opendb */
+{
+ ccp_action_record buff;
+
+ buff.action = CCTR_OPENDB1A;
+ buff.pid = 0;
+ buff.v.fab = fb;
+ ccp_act_request(&buff);
+ return;
+}
+
diff --git a/sr_vvms/ccp_opendb1e.c b/sr_vvms/ccp_opendb1e.c
new file mode 100644
index 0000000..f40ff53
--- /dev/null
+++ b/sr_vvms/ccp_opendb1e.c
@@ -0,0 +1,28 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "ccp.h"
+#include "ccpact.h"
+
+void ccp_opendb1e( struct FAB *fb)
+/* entered after failure sys$open from ccp_opendb */
+{
+ ccp_action_record buff;
+
+ buff.action = CCTR_OPENDB1E;
+ buff.pid = 0;
+ buff.v.fab = fb;
+ ccp_act_request(&buff);
+ return;
+}
+
diff --git a/sr_vvms/ccp_opendb2.c b/sr_vvms/ccp_opendb2.c
new file mode 100644
index 0000000..a5a060e
--- /dev/null
+++ b/sr_vvms/ccp_opendb2.c
@@ -0,0 +1,131 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <fab.h>
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "ccp.h"
+#include "mlkdef.h"
+#include "jnl.h"
+#include "locks.h"
+#include <descrip.h>
+#include <iodef.h>
+#include <lckdef.h>
+#include <psldef.h>
+#include <secdef.h>
+#include <ssdef.h>
+#include "min_max.h"
+#include "mem_list.h"
+#include "init_sec.h"
+
+OS_PAGE_SIZE_DECLARE
+
+GBLREF mem_list *mem_list_head;
+
+
+/* AST routine entered on completion of PW mode lock conversion request
+ in ccp_tr_opendb1, ccp_tr_opendb1b, or here */
+
+void ccp_opendb2(ccp_db_header *db)
+{
+ uint4 status;
+ unsigned char section_name[GLO_NAME_MAXLEN];
+ struct dsc$descriptor_s name_dsc;
+ int4 size;
+ sgmnt_addrs *csa;
+ sgmnt_data *csd;
+ mem_list *ml_ptr;
+
+
+ assert(lib$ast_in_prog());
+
+ if (db->wm_iosb.cond != SS$_NORMAL && db->wm_iosb.cond != SS$_VALNOTVALID)
+ {
+ ccp_signal_cont(db->wm_iosb.cond); /***** Is this reasonable? *****/
+
+ if (db->wm_iosb.cond == SS$_DEADLOCK)
+ {
+ /* Just try again */
+ /* Convert Write-mode lock from Null to Protected Write, reading the lock value block */
+ status = ccp_enq(0, LCK$K_PWMODE, &db->wm_iosb, LCK$M_CONVERT | LCK$M_VALBLK, NULL, 0,
+ ccp_opendb2, db, NULL, PSL$C_USER, 0);
+ /***** Check error status here? *****/
+ return;
+ }
+ }
+
+ csa = db->segment;
+ if (csa->hdr->lock_space_size == 0)
+ if (csa->hdr->n_bts * csa->hdr->blk_size <= DEF_LOCK_SIZE)
+ csa->hdr->lock_space_size = csa->hdr->n_bts * csa->hdr->blk_size;
+ else
+ {
+ csa->hdr->lock_space_size = DEF_LOCK_SIZE;
+
+ /* REPLACE THIS WITH FREE_SPACE WHEN NEXT BASELINE MADE */
+ csa->hdr->free_space = csa->hdr->n_bts * csa->hdr->blk_size - DEF_LOCK_SIZE;
+ }
+
+ size = DIVIDE_ROUND_UP((LOCK_BLOCK(csa->hdr) * DISK_BLOCK_SIZE) + LOCK_SPACE_SIZE(csa->hdr) + CACHE_CONTROL_SIZE(csa->hdr)
+ + NODE_LOCAL_SPACE(csa->hdr) + JNL_SHARE_SIZE(csa->hdr), OS_PAGELET_SIZE);
+
+ status = gtm_expreg(size, csa->db_addrs, PSL$C_USER, 0);
+ if (status != SS$_NORMAL)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+
+ assert(csa->db_addrs[1] == csa->db_addrs[0] + OS_PAGELET_SIZE * size - 1);
+ csa->db_addrs[1] = csa->db_addrs[0] + OS_PAGELET_SIZE * (size - OS_PAGE_SIZE/OS_PAGELET_SIZE) - 1;
+
+ for (ml_ptr = mem_list_head; ml_ptr != NULL; ml_ptr = ml_ptr->next)
+ if (csa->db_addrs[0] == ml_ptr->addr)
+ break;
+ assert (ml_ptr);
+ db->mem_ptr = ml_ptr;
+ global_name("GT$S", &FILE_INFO(db->greg)->file_id, section_name);
+ name_dsc.dsc$a_pointer = §ion_name[1];
+ name_dsc.dsc$w_length = section_name[0];
+ name_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
+ name_dsc.dsc$b_class = DSC$K_CLASS_S;
+ status = init_sec(csa->db_addrs, &name_dsc, 0, size - OS_PAGE_SIZE/OS_PAGELET_SIZE,
+ SEC$M_GBL | SEC$M_DZRO | SEC$M_WRT | SEC$M_PAGFIL | SEC$M_SYSGBL | SEC$M_PERM);
+ if (status != SS$_NORMAL && status != SS$_CREATED)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+
+ memcpy(csa->db_addrs[0], csa->hdr, SIZEOF(sgmnt_data));
+ free (csa->hdr);
+ csa->hdr = csa->db_addrs[0];
+
+ csa->critical = csa->db_addrs[0] + (LOCK_BLOCK(csa->hdr) * DISK_BLOCK_SIZE) + LOCK_SPACE_SIZE(csa->hdr)
+ + CACHE_CONTROL_SIZE(csa->hdr);
+ assert((-(SIZEOF(int4) * 2) & (uint4)csa->critical) == (uint4)csa->critical); /* DB64 */
+ mutex_init(csa->critical, NUM_CRIT_ENTRY(csa->hdr), FALSE);
+
+ free(csa->nl);
+ csa->nl = (char *)csa->critical + CRIT_SPACE(NUM_CRIT_ENTRY(csa->hdr));
+ csa->nl->ccp_state = CCST_OPNREQ;
+
+ status = sys$qio(0, FILE_INFO(db->greg)->fab->fab$l_stv, IO$_READVBLK, &db->qio_iosb, ccp_opendb3, db,
+ &csa->hdr->trans_hist, BT_SIZE(csa->hdr) + SIZEOF(th_index), TH_BLOCK, 0, 0, 0);
+ if ((status & 1) == 0)
+ {
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+ ccp_close1(db);
+ }
+
+ return;
+}
diff --git a/sr_vvms/ccp_opendb3.c b/sr_vvms/ccp_opendb3.c
new file mode 100644
index 0000000..8eb2285
--- /dev/null
+++ b/sr_vvms/ccp_opendb3.c
@@ -0,0 +1,35 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "ccp.h"
+
+
+/* AST routine entered on completion of sys$qio to read transaction history in ccp_opendb2 */
+
+void ccp_opendb3( ccp_db_header *db)
+{
+ ccp_action_record request;
+
+
+ assert(lib$ast_in_prog());
+
+ if ((db->qio_iosb.cond & 1) == 0)
+ ccp_signal_cont(db->qio_iosb.cond); /***** Is this reasonable? *****/
+
+ request.action = CCTR_OPENDB3;
+ request.pid = 0;
+ request.v.h = db;
+ ccp_act_request(&request);
+
+ return;
+}
diff --git a/sr_vvms/ccp_opendb3a.c b/sr_vvms/ccp_opendb3a.c
new file mode 100644
index 0000000..4b7d565
--- /dev/null
+++ b/sr_vvms/ccp_opendb3a.c
@@ -0,0 +1,34 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "ccp.h"
+#include "ccpact.h"
+#include "ccp_opendb3a.h"
+
+void ccp_opendb3a( ccp_db_header *db)
+{
+ ccp_action_record buff;
+
+ if ((db->wm_iosb.cond & 1) == 0)
+ lib$signal(db->wm_iosb.cond);
+ buff.action = CCTR_OPENDB3A;
+ buff.pid = 0;
+ buff.v.h = db;
+ ccp_act_request(&buff);
+ return;
+}
diff --git a/sr_vvms/ccp_opendb3a.h b/sr_vvms/ccp_opendb3a.h
new file mode 100644
index 0000000..374ad40
--- /dev/null
+++ b/sr_vvms/ccp_opendb3a.h
@@ -0,0 +1,16 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+#ifndef __CCP_OPENDB3A_H__
+#define __CCP_OPENDB3A_H__
+
+void ccp_opendb3a(ccp_db_header *db);
+
+#endif
diff --git a/sr_vvms/ccp_opendb3b.c b/sr_vvms/ccp_opendb3b.c
new file mode 100644
index 0000000..95ba539
--- /dev/null
+++ b/sr_vvms/ccp_opendb3b.c
@@ -0,0 +1,43 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <fab.h>
+#include <iodef.h>
+
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "ccp.h"
+
+
+void ccp_opendb3b( ccp_db_header *db)
+{
+ uint4 status;
+
+
+ db->glob_sec->trans_hist.early_tn = db->glob_sec->trans_hist.curr_tn;
+
+ status = sys$qio(0, FILE_INFO(db->greg)->fab->fab$l_stv, IO$_WRITEVBLK, &db->qio_iosb, ccp_opendb3c, db,
+ db->segment->db_addrs[0], (MM_BLOCK + 1) * 512 + MASTER_MAP_SIZE_V4, 1, 0, 0, 0);
+ if ((status & 1) == 0)
+ {
+ ccp_close1(db);
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+ }
+
+ return;
+}
diff --git a/sr_vvms/ccp_opendb3c.c b/sr_vvms/ccp_opendb3c.c
new file mode 100644
index 0000000..011133a
--- /dev/null
+++ b/sr_vvms/ccp_opendb3c.c
@@ -0,0 +1,101 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <psldef.h>
+#include <lckdef.h>
+#include <efndef.h>
+
+
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "gdsblk.h"
+#include "ccp.h"
+#include "jnl.h"
+#include "locks.h"
+#include "mlk_shr_init.h"
+
+error_def(ERR_CCPJNLOPNERR);
+
+/* AST routine entered on completion of sys$qio to update header in ccp_opendb3b */
+void ccp_opendb3c(ccp_db_header *db)
+{
+ char *c;
+ sgmnt_addrs *csa;
+ sgmnt_data *csd;
+ unsigned int i;
+ uint4 status;
+
+ assert(lib$ast_in_prog());
+
+ csa = db->segment;
+ csd = csa->hdr;
+
+ if (JNL_ENABLED(csd))
+ if (db->wm_iosb.valblk[CCP_VALBLK_JNL_ADDR] == 0)
+ {
+ db->wm_iosb.valblk[CCP_VALBLK_JNL_ADDR] = csa->jnl->jnl_buff->freeaddr;
+ db->wm_iosb.valblk[CCP_VALBLK_EPOCH_TN] = csa->jnl->jnl_buff->epoch_tn;
+ /* lastaddr is no longer a field in jnl_buff
+ * db->wm_iosb.valblk[CCP_VALBLK_LST_ADDR] = csa->jnl->jnl_buff->lastaddr;
+ */
+ }
+ else
+ {
+ /* Open journal file, not first machine */
+ jnl_file_open(db->greg, FALSE, ccp_closejnl_ast);
+ if (csa->jnl->channel == 0)
+ {
+ ccp_close1(db);
+ ccp_signal_cont(ERR_CCPJNLOPNERR); /***** Is this reasonable? *****/
+ }
+ csa->jnl->jnl_buff->before_images = csd->ccp_jnl_before;
+ }
+
+ db->wm_iosb.valblk[CCP_VALBLK_TRANS_HIST] = csd->trans_hist.curr_tn + csd->trans_hist.lock_sequence;
+
+ /* Convert Write-mode lock from Protected Write to Concurrent Read, writing the lock value block */
+ status = ccp_enqw(EFN$C_ENF, LCK$K_CRMODE, &db->wm_iosb, LCK$M_CONVERT | LCK$M_VALBLK, NULL, 0,
+ NULL, 0, NULL, PSL$C_USER, 0);
+ /***** Check error status here? *****/
+
+ i = SIZEOF(sgmnt_data);
+ assert((-(SIZEOF(int4) * 2) & i) == i); /* check quadword alignment */
+ csa->nl->bt_header_off = i;
+ csa->nl->th_base_off = (i += csd->bt_buckets * SIZEOF(bt_rec));
+ csa->nl->th_base_off += SIZEOF(que_ent); /* Skip over links for hash table queue */
+ csa->nl->bt_base_off = i + SIZEOF(bt_rec); /* one unused rec to anchor TH queue */
+ bt_init(csa);
+ csa->nl->cache_off = -CACHE_CONTROL_SIZE(csd);
+ db_csh_ini(csa);
+ bt_que_refresh(db->greg);
+ db_csh_ref(csa, TRUE);
+ mlk_shr_init(csa->lock_addrs[0], csd->lock_space_size, csa, (FALSE == db->greg->read_only));
+ db->greg->open = TRUE;
+
+ /* Convert M-lock lock from Null to Concurrent Read, and establish a blocking AST routine */
+ status = ccp_enq(0, LCK$K_CRMODE, &db->lock_iosb, LCK$M_CONVERT | LCK$M_SYNCSTS, NULL, 0,
+ ccp_lkrqwake1, db, ccp_lkdowake_blkast, PSL$C_USER, 0);
+ /***** Check error status here? *****/
+
+/* csd->glob_sec_init = TRUE; this field is not used by vms or the ccp */
+ if (csd->staleness[0] != 0 || csd->staleness[1] != 0) /* if values are 0, no stale timer */
+ db->stale_timer_id = db;
+
+ ccp_request_write_mode(db);
+
+ return;
+}
diff --git a/sr_vvms/ccp_pndg_proc_add.c b/sr_vvms/ccp_pndg_proc_add.c
new file mode 100644
index 0000000..25b9a81
--- /dev/null
+++ b/sr_vvms/ccp_pndg_proc_add.c
@@ -0,0 +1,36 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "ccp.h"
+
+void ccp_pndg_proc_add(list, pid)
+ccp_wait_head *list;
+int4 pid;
+{
+ /* add a processes id to a ccp_wait list.
+ we add at the end of the list so that wakeup's
+ will be delivered to VMS in FIFO order
+ */
+ ccp_wait *e;
+
+ for (e = list->first; e; e = e->next)
+ { if (e->pid == pid)
+ return;
+ }
+ e = malloc(SIZEOF(*e));
+ e->pid = pid;
+ e->next = 0;
+ *(list->last) = &(e->next);
+ list->last = e;
+ return;
+}
diff --git a/sr_vvms/ccp_pndg_proc_wake.c b/sr_vvms/ccp_pndg_proc_wake.c
new file mode 100644
index 0000000..09dd379
--- /dev/null
+++ b/sr_vvms/ccp_pndg_proc_wake.c
@@ -0,0 +1,30 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "ccp.h"
+#include "crit_wake.h"
+
+void ccp_pndg_proc_wake( ccp_wait_head *list)
+{
+ ccp_wait *e, *ex;
+
+ for (e = list->first ; e ; e = ex)
+ {
+ crit_wake(&e->pid);
+ ex = e->next;
+ free(e);
+ }
+ list->first = 0;
+ list->last = &list->first;
+ return;
+}
diff --git a/sr_vvms/ccp_quantum_interrupt.c b/sr_vvms/ccp_quantum_interrupt.c
new file mode 100644
index 0000000..6dfc3d0
--- /dev/null
+++ b/sr_vvms/ccp_quantum_interrupt.c
@@ -0,0 +1,39 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "ccp.h"
+
+void ccp_quantum_interrupt( ccp_db_header **p)
+{
+
+ ccp_db_header *db;
+
+ db = *p;
+ assert(lib$ast_in_prog());
+ if (!db->quantum_expired)
+ {
+ assert(db->segment->nl->ccp_state != CCST_WMXREQ);
+ if (db->tick_in_progress)
+ {
+ db->tick_in_progress = FALSE;
+ sys$cantim(&db->tick_timer_id, 0);
+ }
+ db->quantum_expired = TRUE;
+ }
+ ccp_exitwm_attempt(db);
+ return;
+}
diff --git a/sr_vvms/ccp_queue_manager.c b/sr_vvms/ccp_queue_manager.c
new file mode 100644
index 0000000..3a6aa58
--- /dev/null
+++ b/sr_vvms/ccp_queue_manager.c
@@ -0,0 +1,250 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "ccp.h"
+#include "ccp_retchan_manager.h"
+#include "ast.h"
+#include <psldef.h>
+#include <ssdef.h>
+
+/* ccp_queue_manager - A package to manage ccp queue entries */
+
+#define NUM_QUE_SLOTS 100
+#define MIN_QUE_FREE 5
+#define QUE_EXTEND_SIZE (NUM_QUE_SLOTS / 2)
+#define MAX_QUE_SIZE 1000
+
+GBLDEF ccp_que_entry *current_item;
+GBLDEF ccp_relque *ccp_action_que;
+
+error_def(ERR_CCPINTQUE);
+
+static ccp_relque *ccp_free_que;
+static short int ccp_que_entry_count, ccp_que_free_count, ccp_que_free_minimum;
+
+#define CCP_MAX_PRIORITY 3
+#define CCPR_HI 2
+#define CCPR_NOR 1
+#define CCPR_LOW 0
+
+#define CCP_TABLE_ENTRY(A,B,C,D) D,
+static const unsigned char priority[] =
+{
+#include "ccpact_tab.h"
+};
+#undef CCP_TABLE_ENTRY
+
+/* Get the first action available to process; if NULL, queues were empty */
+
+ccp_action_record *ccp_act_select(void)
+{
+ ccp_relque *p;
+ ccp_que_entry *result;
+
+
+ assert(current_item == NULL);
+
+ for (p = &ccp_action_que[CCP_MAX_PRIORITY]; p > ccp_action_que;)
+ {
+ result = remqhi(--p);
+ if (result == -1)
+ lib$signal(ERR_CCPINTQUE);
+ else
+ if (result != NULL)
+ break;
+ }
+
+ if (result == NULL)
+ return NULL;
+
+ current_item = result;
+
+ return &result->value;
+}
+
+
+void ccp_act_complete(void)
+{
+ int4 status;
+
+
+ assert(current_item != NULL);
+ sys$gettim(¤t_item->process_time);
+ status = insqti(current_item, ccp_free_que);
+ if (status == -1)
+ lib$signal(ERR_CCPINTQUE);
+
+ current_item = NULL;
+ adawi(1, &ccp_que_free_count);
+
+ if (ccp_que_free_count == ccp_que_free_minimum + MIN_QUE_FREE)
+ {
+ status = sys$dclast(ccp_mbx_start, 0, PSL$C_USER);
+ if (status != SS$_NORMAL)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+ }
+
+ return;
+}
+
+bool ccp_act_request(ccp_action_record *rec)
+{
+ ccp_action_code act;
+ ccp_que_entry *ptr;
+ /* need to deal with starvation */
+
+
+ act = rec->action;
+
+ if (act == CCTR_NULL)
+ return (ccp_que_free_count > ccp_que_free_minimum);
+
+ if (act <= 0 || act >= CCPACTION_COUNT)
+ GTMASSERT;
+
+ ptr = remqhi(ccp_free_que);
+ if (ptr == -1)
+ lib$signal(ERR_CCPINTQUE);
+ if (ptr == 0)
+ GTMASSERT;
+
+ adawi(-1, &ccp_que_free_count);
+
+ sys$gettim(&ptr->request_time);
+ ptr->value = *rec;
+ insqti(ptr, &ccp_action_que[priority[act]]);
+
+ sys$wake(NULL, NULL);
+
+ return (ccp_que_free_count > ccp_que_free_minimum);
+}
+
+
+/* Places the request at the head of the high priority queue */
+
+bool ccp_priority_request(ccp_action_record *rec)
+{
+ ccp_action_code act;
+ ccp_que_entry *ptr;
+ /* need to deal with starvation */
+
+
+ act = rec->action;
+
+ if (act == CCTR_NULL)
+ return (ccp_que_free_count > ccp_que_free_minimum);
+
+ if (act <= 0 || act >= CCPACTION_COUNT)
+ GTMASSERT;
+
+ ptr = remqhi(ccp_free_que);
+ if (ptr == -1)
+ lib$signal(ERR_CCPINTQUE);
+ if (ptr == 0)
+ GTMASSERT;
+
+ adawi(-1, &ccp_que_free_count);
+
+ sys$gettim(&ptr->request_time);
+ ptr->value = *rec;
+ insqhi(ptr, &ccp_action_que[priority[act]]);
+
+ sys$wake(NULL, NULL);
+
+ return (ccp_que_free_count > ccp_que_free_minimum);
+}
+
+void ccp_act_init(void)
+{
+ unsigned char *ptr;
+ int n, siz;
+
+
+ ccp_free_que = malloc(SIZEOF(ccp_relque));
+ memset(ccp_free_que, 0, SIZEOF(ccp_relque));
+
+ ccp_action_que = malloc(SIZEOF(ccp_relque) * CCP_MAX_PRIORITY);
+ memset(ccp_action_que, 0, SIZEOF(ccp_relque) * CCP_MAX_PRIORITY);
+
+ ccp_que_free_count = ccp_que_entry_count = NUM_QUE_SLOTS;
+ ccp_que_free_minimum = MIN_QUE_FREE;
+
+ if (SIZEOF(ccp_que_entry) & 7)
+ siz = (SIZEOF(ccp_que_entry) & ~7) + 8;
+ else
+ siz = SIZEOF(ccp_que_entry) ;
+ ptr = malloc(siz * ccp_que_entry_count);
+ /* set buffer space to zero in order to distinguish history records from never used records */
+ memset(ptr, 0, siz * ccp_que_entry_count);
+
+ for (n = 0; n < ccp_que_entry_count; n++, ptr += siz)
+ {
+ insqti(ptr, ccp_free_que);
+ /* could check for success here */
+ }
+
+ return;
+}
+
+
+void ccp_quemin_adjust(char oper)
+{
+ if (oper == CCP_OPEN_REGION && ccp_que_free_minimum < ccp_que_entry_count / 2)
+ ccp_que_free_minimum += 3;
+ else
+ if (oper == CCP_CLOSE_REGION && ccp_que_free_minimum > MIN_QUE_FREE)
+ ccp_que_free_minimum -= 3;
+
+ return;
+}
+
+#define PUTLIT(X) ccp_retchan_text(context, LIT_AND_LEN(X));
+#define GETTAIL(X) (((unsigned char *) (X)) + (X)->bl)
+
+
+void ccp_quedump1(ccp_action_record *tr)
+{
+ unsigned char *endptr, *context, buffer[128];
+ ccp_que_entry *qe;
+
+
+ context = ccp_retchan_init(&tr->v);
+
+ PUTLIT("HISTORY QUEUE CONTENTS:");
+
+ for (qe = GETTAIL(ccp_free_que); qe != ccp_free_que; qe = GETTAIL(&(qe->q)))
+ if (qe->value.action != CCTR_NULL)
+ {
+ endptr = ccp_format_querec(qe, buffer, SIZEOF(buffer));
+ ccp_retchan_text(context, buffer, endptr - buffer);
+ }
+
+ ccp_retchan_fini(context);
+
+ return;
+}
+
+
+void ccp_tr_quedump(ccp_action_record *tr)
+{
+ uint4 status;
+
+ /* Note: should add other requests here, also syntax in ccp might be sho que/history */
+
+ /* ccp_quedump1 needs to be in an AST to prevent ccp_mbx_interrupt from changing the queue */
+ status = sys$dclast(ccp_quedump1, tr, PSL$C_USER);
+ if (status != SS$_NORMAL)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+
+ return;
+}
diff --git a/sr_vvms/ccp_release_name.c b/sr_vvms/ccp_release_name.c
new file mode 100644
index 0000000..fd79d71
--- /dev/null
+++ b/sr_vvms/ccp_release_name.c
@@ -0,0 +1,20 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* ccp_release_name.c : defines product name and version for licensing
+
+*/
+#include "mdef.h"
+
+LITDEF char ccp_prd_name[] = "GT.CX" ;
+LITDEF int4 ccp_prd_len = SIZEOF(ccp_prd_name) - 1 ;
+LITDEF char ccp_ver_name[] = "V120";
+LITDEF int4 ccp_ver_len = SIZEOF(ccp_ver_name) - 1 ;
diff --git a/sr_vvms/ccp_reqdrtbuf_interrupt.c b/sr_vvms/ccp_reqdrtbuf_interrupt.c
new file mode 100644
index 0000000..e703c13
--- /dev/null
+++ b/sr_vvms/ccp_reqdrtbuf_interrupt.c
@@ -0,0 +1,59 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "ccp.h"
+#include "locks.h"
+#include <lckdef.h>
+#include <psldef.h>
+#include <ssdef.h>
+
+
+/* AST routine entered on completion of EX mode lock conversion request
+ in ccp_tr_writedb1 (or here) granted (we hope) for got dirty buffers */
+
+void ccp_reqdrtbuf_interrupt( ccp_db_header *db)
+{
+ uint4 status;
+ ccp_action_record request;
+
+
+ assert(lib$ast_in_prog());
+
+ if (db->flush_iosb.cond == SS$_NORMAL)
+ {
+ request.action = CCTR_GOTDRT;
+ request.pid = 0;
+ request.v.h = db;
+ ccp_act_request(&request);
+ return;
+ }
+
+ ccp_signal_cont(db->flush_iosb.cond); /***** Is this reasonable? *****/
+
+ if (db->flush_iosb.cond == SS$_DEADLOCK)
+ {
+ /* Just try again */
+ status = ccp_enq(0, LCK$K_EXMODE, &db->flush_iosb, LCK$M_CONVERT | LCK$M_SYNCSTS, NULL, 0,
+ ccp_reqdrtbuf_interrupt, db, NULL, PSL$C_USER, 0);
+ if (status == SS$_SYNCH)
+ {
+ request.action = CCTR_GOTDRT;
+ request.pid = 0;
+ request.v.h = db;
+ ccp_act_request(&request);
+ }
+ /***** Check error status here? *****/
+ }
+
+ return;
+}
diff --git a/sr_vvms/ccp_request_write_mode.c b/sr_vvms/ccp_request_write_mode.c
new file mode 100644
index 0000000..0760f3e
--- /dev/null
+++ b/sr_vvms/ccp_request_write_mode.c
@@ -0,0 +1,44 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "ccp.h"
+#include "locks.h"
+#include <lckdef.h>
+#include <psldef.h>
+
+GBLREF bool ccp_stop;
+
+
+void ccp_request_write_mode( ccp_db_header *db)
+{
+ uint4 status;
+
+
+ if (ccp_stop)
+ return;
+
+ db->write_mode_requested = TRUE;
+
+ if (db->stale_in_progress)
+ {
+ sys$cantim(&db->stale_timer_id, PSL$C_USER);
+ db->stale_in_progress = FALSE;
+ }
+
+ /* Convert Write-mode lock from Concurrent Read to Protected Write, reading the lock value block */
+ status = ccp_enq(0, LCK$K_PWMODE, &db->wm_iosb, LCK$M_CONVERT | LCK$M_VALBLK, NULL, 0,
+ ccp_reqwm_interrupt, &db->wmcrit_timer_id, ccp_exitwm_blkast, PSL$C_USER, 0);
+ /***** Check error status here? *****/
+
+ return;
+}
diff --git a/sr_vvms/ccp_reqwm_interrupt.c b/sr_vvms/ccp_reqwm_interrupt.c
new file mode 100644
index 0000000..4081fef
--- /dev/null
+++ b/sr_vvms/ccp_reqwm_interrupt.c
@@ -0,0 +1,109 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <fab.h>
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "ccp.h"
+#include <iodef.h>
+#include <ssdef.h>
+#include "ccp_writedb2.h"
+
+GBLREF uint4 process_id;
+GBLREF sgmnt_addrs *vms_mutex_check_csa;
+
+
+static int4 delta_100_msec[2] = { -100000, -1 };
+
+
+/* AST routine entered on completion of PW mode lock conversion request in ccp_request_write_mode */
+
+void ccp_reqwm_interrupt(ccp_db_header **pdb)
+{
+ ccp_db_header *db;
+ sgmnt_addrs *csa;
+ uint4 status;
+
+
+ assert(lib$ast_in_prog());
+
+ db = *pdb;
+
+ csa = db->segment;
+ if (csa == NULL || csa->nl->ccp_state == CCST_CLOSED)
+ return;
+ vms_mutex_check_csa = csa;
+ switch (db->wm_iosb.cond)
+ {
+ case SS$_DEADLOCK:
+ ccp_signal_cont(SS$_DEADLOCK);
+ /* Just try again */
+ ccp_request_write_mode(db);
+ return;
+
+ case SS$_CANCEL:
+ /* Lock cancelled by close */
+ return;
+
+ case SS$_VALNOTVALID:
+ /* Force reads from disk */
+ db->wm_iosb.valblk[CCP_VALBLK_TRANS_HIST] = 0;
+ db->last_lk_sequence = db->master_map_start_tn
+ = 0;
+ /* Drop through ... */
+
+ case SS$_NORMAL:
+ if (db->wm_iosb.valblk[CCP_VALBLK_TRANS_HIST] == csa->ti->curr_tn + csa->ti->lock_sequence)
+ {
+ /* No change to current tn, do not need to update header */
+ if (csa->now_crit)
+ {
+ assert (csa->nl->in_crit == process_id);
+ csa->nl->in_crit = 0;
+ (void)mutex_unlockw(csa->critical, csa->critical->crashcnt, &csa->now_crit);
+ /***** Check error status here? *****/
+ }
+ ccp_writedb5(db);
+ }
+ else
+ {
+ if (csa->nl->in_crit == 0)
+ {
+ if (mutex_lockwim(csa->critical, csa->critical->crashcnt, &csa->now_crit) == cdb_sc_normal)
+ csa->nl->in_crit = process_id; /* now_crit was set by mutex_lockwim */
+ else
+ if (csa->nl->in_crit == 0) /***** Why is this re-tested? *****/
+ {
+ status = sys$setimr(0, delta_100_msec, ccp_reqwm_interrupt, &db->wmcrit_timer_id,
+ 0);
+ if (status != SS$_NORMAL)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+ return;
+ }
+ }
+ status = sys$qio(0, FILE_INFO(db->greg)->fab->fab$l_stv, IO$_READVBLK, &db->qio_iosb, ccp_writedb2, db,
+ &db->glob_sec->trans_hist, BT_SIZE(csa->hdr) + SIZEOF(th_index), TH_BLOCK, 0, 0, 0);
+ if (status != SS$_NORMAL)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+ }
+ return;
+
+ default:
+ ccp_signal_cont(db->wm_iosb.cond); /***** Is this reasonable? *****/
+ return;
+ }
+}
diff --git a/sr_vvms/ccp_retchan_manager.c b/sr_vvms/ccp_retchan_manager.c
new file mode 100644
index 0000000..6dac4a5
--- /dev/null
+++ b/sr_vvms/ccp_retchan_manager.c
@@ -0,0 +1,168 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "ccp.h"
+#include "ccp_retchan_manager.h"
+#include <descrip.h>
+#include <iodef.h>
+
+static void ccp_retchan_cl1(unsigned short chan);
+
+static short ccp_retchan_open(ccp_action_aux_value *v)
+{
+ struct dsc$descriptor mbxname;
+ short return_channel;
+ uint4 status;
+
+ mbxname.dsc$w_length = v->str.len;
+ mbxname.dsc$b_dtype = DSC$K_DTYPE_T;
+ mbxname.dsc$b_class = DSC$K_CLASS_S;
+ mbxname.dsc$a_pointer = v->str.txt;
+ status = sys$assign(&mbxname, &return_channel, 0, 0);
+ if ((status & 1) == 0)
+ return_channel = 0;
+ return return_channel;
+}
+
+
+static void ccp_retchan_close(unsigned short chan)
+{
+ sys$qio(0, chan, IO$_WRITEOF, 0, ccp_retchan_cl1, chan, 0, 0, 0, 0, 0, 0);
+ return;
+}
+
+static void ccp_retchan_cl1(unsigned short chan)
+{
+ uint4 status;
+
+ status = sys$dassgn(chan);
+ assert(status & 1);
+ return;
+}
+
+static uint4 ccp_retchan_write(
+unsigned short chan,
+unsigned char *addr,
+unsigned short len,
+void (*completion_addr)(),
+uint4 completion_arg)
+{
+ uint4 status;
+
+ status = sys$qio(0, chan, IO$_WRITEVBLK, 0, completion_addr, completion_arg, addr, len, 0, 0, 0, 0);
+ return status;
+}
+
+/***********************************************************************
+ The following routines are used to return a file of text records
+ to cce.
+
+ To start, call ccp_retchan_init(v), where v contains the return
+ mailbox name. This routine returns a pointer which is the
+ context for this suite and must be preserved until the
+ last call.
+
+ To send a text line, call ccp_retchan_text(p,addr,len), where
+ p is the context and addr and len define the text to be
+ sent.
+
+ To finish, call ccp_retchan_fini(p) with the context p.
+ Nothing is sent out and there are no I/O waits until
+ the last call. The last call operates through a chain
+ of completion ast's. Therefore, consistent queue contents
+ (for example) may be returned to the cce with these routines
+
+ Note: error status returns will cause a clean-up to commence and
+ processing to terminate on the assumption that the CCE
+ either exited or malfunctioned under this circumstance.
+***********************************************************************/
+
+struct retchan_header *ccp_retchan_init(ccp_action_aux_value *v)
+{
+ struct retchan_header *p;
+
+ p = malloc(SIZEOF(*p));
+ p->head = 0;
+ p->tail = p;
+ p->chan = 0;
+ p->mbxnam = *v;
+ return p;
+}
+
+void ccp_retchan_text(
+struct retchan_header *p,
+unsigned char *addr,
+unsigned short len)
+{
+ struct retchan_txt *v;
+ v = malloc(SIZEOF(*v) - 1 + len);
+ *(p->tail) = v;
+ p->tail = v;
+ v->next = 0;
+ v->len = len;
+ memcpy(v->txt, addr, len);
+}
+
+static void ccp_retchan_cleanup(struct retchan_header *p)
+{
+ struct retchan_txt *v, *w;
+
+ for (v = p->head ; v ; v = w)
+ {
+ w = v->next;
+ free(v);
+ }
+ if (p->chan)
+ ccp_retchan_close(p->chan);
+ free(p);
+ return;
+}
+
+static void ccp_retchan_fini1(struct retchan_header *p)
+{
+ struct retchan_txt *v, *w;
+ uint4 status;
+ assert(p->head);
+ v = p->head;
+ w = v->next;
+ free(v);
+ if (!w)
+ {
+ ccp_retchan_close(p->chan);
+ free(p);
+ } else
+ {
+ p->head = w;
+ status = ccp_retchan_write(p->chan, w->txt, w->len, ccp_retchan_fini1, p);
+ if ((status & 1) == 0)
+ ccp_retchan_cleanup(p);
+ }
+ return;
+}
+
+void ccp_retchan_fini(struct retchan_header *p)
+{
+ uint4 status;
+
+ if(p->head == 0)
+ return;
+ p->chan = ccp_retchan_open(&p->mbxnam.str);
+ if (p->chan)
+ {
+ status = ccp_retchan_write(p->chan, p->head->txt, p->head->len, ccp_retchan_fini1, p);
+ if (status & 1)
+ return;
+ }
+ ccp_retchan_cleanup(p);
+ return;
+}
diff --git a/sr_vvms/ccp_retchan_manager.h b/sr_vvms/ccp_retchan_manager.h
new file mode 100644
index 0000000..36d4f52
--- /dev/null
+++ b/sr_vvms/ccp_retchan_manager.h
@@ -0,0 +1,35 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef __CCP_RETCHAN_MANAGER_H__
+#define __CCP_RETCHAN_MANAGER_H__
+
+
+struct retchan_txt
+{
+ struct retchan_txt *next;
+ unsigned char len;
+ unsigned char txt[1];
+};
+
+struct retchan_header
+{
+ struct retchan_txt *head;
+ struct retchan_txt **tail;
+ uint4 chan;
+ ccp_action_aux_value mbxnam;
+};
+
+struct retchan_header *ccp_retchan_init(ccp_action_aux_value *v);
+void ccp_retchan_text(struct retchan_header *p,unsigned char *addr,unsigned short len);
+void ccp_retchan_fini(struct retchan_header *p);
+
+#endif
diff --git a/sr_vvms/ccp_rundown.c b/sr_vvms/ccp_rundown.c
new file mode 100644
index 0000000..0b6031d
--- /dev/null
+++ b/sr_vvms/ccp_rundown.c
@@ -0,0 +1,59 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "error.h"
+#include "gdsroot.h"
+#include "ccp.h"
+#include "ccpact.h"
+
+typedef struct{
+int4 link;
+int4 *exit_hand;
+int4 arg_cnt;
+int4 *cond_val;
+}desblk;
+
+GBLREF int4 ccp_exi_condition;
+GBLREF desblk ccp_exi_blk;
+GBLDEF bool ccp_dump_on;
+
+void ccp_rundown(void)
+{
+ error_def(ERR_CCEDUMPON);
+ error_def(ERR_CCEDUMPOFF);
+ error_def(ERR_CCEDUMPNOW);
+ error_def(ERR_FORCEDHALT);
+
+ ccp_action_record buff;
+
+ if (ccp_exi_condition == ERR_CCEDUMPNOW || ccp_exi_condition == ERR_CCEDUMPON ||
+ ccp_exi_condition == ERR_CCEDUMPOFF || ccp_exi_condition == ERR_FORCEDHALT)
+ { if (ccp_exi_condition == ERR_FORCEDHALT)
+ { buff.action = CCTR_STOP;
+ buff.pid=0;
+ ccp_priority_request(&buff);
+ }
+ else
+ { if (ccp_exi_condition == ERR_CCEDUMPNOW)
+ ccp_dump();
+ else
+ ccp_dump_on = (ccp_exi_condition == ERR_CCEDUMPON);
+ }
+ ccp_exi_blk.exit_hand = &ccp_rundown;
+ ccp_exi_blk.arg_cnt = 1;
+ ccp_exi_blk.cond_val = &ccp_exi_condition;
+ sys$dclexh(&ccp_exi_blk);
+ lib$establish(ccp_exi_ch);
+ lib$signal(ccp_exi_condition); /* signal an error so can unwind and continue processing */
+ }
+ lib$signal(ccp_exi_condition);
+}
diff --git a/sr_vvms/ccp_sendmsg.c b/sr_vvms/ccp_sendmsg.c
new file mode 100644
index 0000000..1c1075f
--- /dev/null
+++ b/sr_vvms/ccp_sendmsg.c
@@ -0,0 +1,55 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <ssdef.h>
+#include "gdsroot.h"
+#include "ccp.h"
+#include <iodef.h>
+#include <descrip.h>
+#include <psldef.h>
+
+error_def(ERR_CCPMBX);
+
+GBLREF uint4 process_id;
+
+static short channel;
+static ccp_iosb iosb;
+static $DESCRIPTOR (devnam, CCP_MBX_NAME);
+
+
+short ccp_sendmsg(action, aux_value)
+ccp_action_code action;
+ccp_action_aux_value *aux_value;
+{
+ ccp_action_record request;
+
+
+ if (channel == 0 && sys$assign(&devnam, &channel, PSL$C_USER, NULL) != SS$_NORMAL)
+ {
+ rts_error(ERR_CCPMBX);
+ return 0; /* Necessary for operation of cce_ccp */
+ }
+
+ request.action = action;
+ request.pid = process_id;
+ if (aux_value != NULL)
+ request.v = *aux_value;
+
+ if (sys$qio(0, channel, IO$_WRITEVBLK | IO$M_NOW, &iosb, NULL, 0, &request, sizeof request, 0, 0, 0, 0)
+ != SS$_NORMAL)
+ {
+ rts_error(ERR_CCPMBX);
+ return 0; /* Necessary for operation of cce_ccp */
+ }
+
+ return channel;
+}
diff --git a/sr_vvms/ccp_signal_cont.c b/sr_vvms/ccp_signal_cont.c
new file mode 100644
index 0000000..ac7855c
--- /dev/null
+++ b/sr_vvms/ccp_signal_cont.c
@@ -0,0 +1,56 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2005 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <stdarg.h>
+
+void ccp_signal_cont(uint4 arg1, ...)
+{
+ va_list var;
+ uint4 arg2, arg3, arg4, arg5;
+ int4 numargs, pc;
+
+ error_def(ERR_CCPSIGCONT);
+
+ pc = caller_id();
+ VAR_START(var, arg1);
+ va_count(numargs);
+ switch (numargs)
+ {
+ case 1:
+ lib$signal(ERR_CCPSIGCONT, 1, pc, arg1);
+ break;
+ case 2:
+ arg2 = va_arg(var, uint4);
+ lib$signal(ERR_CCPSIGCONT, 1, pc, arg1, arg2);
+ break;
+ case 3:
+ arg2 = va_arg(var, uint4);
+ arg3 = va_arg(var, uint4);
+ lib$signal(ERR_CCPSIGCONT, 1, pc, arg1, arg2, arg3);
+ break;
+ case 4:
+ arg2 = va_arg(var, uint4);
+ arg3 = va_arg(var, uint4);
+ arg4 = va_arg(var, uint4);
+ lib$signal(ERR_CCPSIGCONT, 1, pc, arg1, arg2, arg3, arg4);
+ break;
+ default:
+ arg2 = va_arg(var, uint4);
+ arg3 = va_arg(var, uint4);
+ arg4 = va_arg(var, uint4);
+ arg5 = va_arg(var, uint4);
+ lib$signal(ERR_CCPSIGCONT, 1, pc, arg1, arg2, arg3, arg4, arg5);
+ break;
+ }
+ va_end(var);
+}
diff --git a/sr_vvms/ccp_staleness.c b/sr_vvms/ccp_staleness.c
new file mode 100644
index 0000000..f34f894
--- /dev/null
+++ b/sr_vvms/ccp_staleness.c
@@ -0,0 +1,38 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "ccp.h"
+#include "ccpact.h"
+
+void ccp_staleness(ccp_db_header **p)
+{
+ ccp_db_header *db;
+ ccp_action_record buff;
+
+ db = *p;
+ db->stale_in_progress = FALSE;
+ if (!db->write_mode_requested)
+ { buff.action = CCTR_WRITEDB;
+ buff.pid = 0;
+ buff.v.exreq.fid = ((vms_gds_info *)(db->greg->dyn.addr->file_cntl->file_info))->file_id;
+ buff.v.exreq.cycle = db->segment->nl->ccp_cycle;
+ ccp_act_request(&buff);
+ }
+ return;
+}
diff --git a/sr_vvms/ccp_tick_interrupt.c b/sr_vvms/ccp_tick_interrupt.c
new file mode 100644
index 0000000..daf2790
--- /dev/null
+++ b/sr_vvms/ccp_tick_interrupt.c
@@ -0,0 +1,44 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "ccp.h"
+
+void ccp_tick_interrupt( ccp_db_header **p)
+{
+ ccp_db_header *db;
+
+ assert(lib$ast_in_prog());
+ db = *p;
+ if (!db->quantum_expired)
+ {
+ assert(db->wmexit_requested);
+ assert(db->segment == NULL || db->segment->nl->ccp_state != CCST_WMXREQ);
+ assert(db->tick_in_progress == TRUE);
+ /* db->glob_sec->wcs_active_lvl -= db->drop_lvl; */
+ if ((db->segment != NULL) && (db->tick_tn != db->segment->ti->curr_tn))
+ ccp_tick_start(db);
+ else
+ {
+ /* cancel quantum timer */
+ sys$cantim(&db->quantum_timer_id, 0);
+ db->tick_in_progress = FALSE;
+ db->quantum_expired = TRUE;
+ ccp_exitwm_attempt(db);
+ }
+ }
+ return;
+}
diff --git a/sr_vvms/ccp_tick_start.c b/sr_vvms/ccp_tick_start.c
new file mode 100644
index 0000000..0ac65a1
--- /dev/null
+++ b/sr_vvms/ccp_tick_start.c
@@ -0,0 +1,42 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "ccp.h"
+#include <ssdef.h>
+
+
+/* AST routine called from ccp_exitwm_blkast, ccp_gotdrt_tick, and ccp_tick_interrupt */
+
+void ccp_tick_start( ccp_db_header *db)
+{
+ uint4 status;
+
+
+ assert(lib$ast_in_prog());
+ assert(!db->quantum_expired);
+ assert(db->wmexit_requested);
+ assert(db->segment->nl->ccp_state != CCST_WMXREQ);
+
+ db->tick_in_progress = TRUE;
+ db->tick_tn = db->segment->ti->curr_tn;
+
+ status = sys$setimr(0, &db->glob_sec->ccp_tick_interval, ccp_tick_interrupt, &db->tick_timer_id, 0);
+ if (status != SS$_NORMAL)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+
+ return;
+}
diff --git a/sr_vvms/ccp_tr_checkdb.c b/sr_vvms/ccp_tr_checkdb.c
new file mode 100644
index 0000000..0222716
--- /dev/null
+++ b/sr_vvms/ccp_tr_checkdb.c
@@ -0,0 +1,60 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "ccp.h"
+#include <ssdef.h>
+
+GBLREF ccp_db_header *ccp_reg_root;
+GBLDEF bool checkdb_timer;
+
+static int4 delta_30_sec[2] = { -300000000, -1 };
+
+
+/* Check to see if any databases are still being accessed */
+
+void ccp_tr_checkdb(void)
+{
+ ccp_db_header *db;
+ ccp_action_record request;
+ uint4 status;
+
+
+ checkdb_timer = FALSE;
+
+ if (ccp_reg_root == NULL)
+ {
+ status = sys$setimr(0, delta_30_sec, ccp_tr_checkdb, 0, 0);
+ if (status == SS$_NORMAL)
+ checkdb_timer = TRUE;
+ else
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+ }
+ else
+ for (db = ccp_reg_root; db != NULL; db = db->next)
+ {
+ request.action = CCTR_CLOSE;
+ request.pid = 0;
+ request.v.file_id = FILE_INFO(db->greg)->file_id;
+ if (!ccp_act_request(&request))
+ break;
+ }
+ /* Let ccp_tr_close restart the timer so we don't build up redundant requests */
+
+ return;
+}
diff --git a/sr_vvms/ccp_tr_close.c b/sr_vvms/ccp_tr_close.c
new file mode 100644
index 0000000..3d3e93e
--- /dev/null
+++ b/sr_vvms/ccp_tr_close.c
@@ -0,0 +1,86 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "ccp.h"
+#include "locks.h"
+#include <psldef.h>
+#include <lckdef.h>
+#include <ssdef.h>
+#include <efndef.h>
+
+
+GBLREF bool ccp_stop, checkdb_timer;
+
+static int4 delta_30_sec[2] = { -300000000, -1 };
+
+
+/* Close the database; the process no longer has an interest in the region */
+
+void ccp_tr_close( ccp_action_record *rec)
+{
+ ccp_db_header *db;
+ uint4 status;
+
+
+ db = ccp_get_reg(&rec->v.file_id);
+
+ if (db != NULL && db->segment->nl->ccp_state != CCST_OPNREQ)
+ {
+ status = ccp_enqw(EFN$C_ENF, LCK$K_EXMODE, &db->refcnt_iosb, LCK$M_CONVERT | LCK$M_NOQUEUE, NULL, 0,
+ NULL, 0, NULL, PSL$C_USER, 0);
+ /***** Check error status here? *****/
+
+ if (status == SS$_NORMAL || ccp_stop)
+ if (db->segment->nl->ccp_state == CCST_RDMODE)
+ ccp_close1(db);
+ else
+ {
+ db->close_region = TRUE;
+ if (db->wmexit_requested)
+ status = sys$dclast(ccp_exitwm_attempt, db, PSL$C_USER);
+ else
+ status = sys$dclast(ccp_exitwm_blkast, &db->exitwm_timer_id, PSL$C_USER);
+ if (status != SS$_NORMAL)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+ }
+
+ /* NOTE: The following `else' clause is a temporary kludge. There appears to be a scenario in which
+ the CCP loses track of a request to relinquish write mode, causing GT.M processes to hang.
+ We piggyback on the checkdb timer processing here to guarantee that the hang doesn't persist,
+ by simulating the receipt of the blocking AST that initiates write mode exit processing. */
+ else
+ if (db->quantum_expired && CCP_SEGMENT_STATE(db->segment->nl, CCST_MASK_WRITE_MODE))
+ {
+ status = sys$dclast(ccp_exitwm_blkast, &db->exitwm_timer_id, PSL$C_USER);
+ if (status != SS$_NORMAL)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+ }
+ }
+
+ if (rec->pid == 0 && !checkdb_timer)
+ {
+ /* Request was from ccp_tr_checkdb */
+ status = sys$setimr(0, delta_30_sec, ccp_tr_checkdb, 0, 0);
+ if (status == SS$_NORMAL)
+ checkdb_timer = TRUE;
+ else
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+ }
+
+ return;
+}
diff --git a/sr_vvms/ccp_tr_closejnl.c b/sr_vvms/ccp_tr_closejnl.c
new file mode 100644
index 0000000..88d212e
--- /dev/null
+++ b/sr_vvms/ccp_tr_closejnl.c
@@ -0,0 +1,63 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2005 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "gdsbgtr.h"
+#include "ccp.h"
+#include <psldef.h>
+#include "jnl.h"
+#include "locks.h"
+
+
+void ccp_tr_closejnl( ccp_action_record *rec)
+{
+ ccp_db_header *db;
+ sgmnt_addrs *csa;
+ jnl_private_control *jpc;
+ uint4 status;
+
+
+ db = ccp_get_reg(&FILE_INFO(rec->v.reg)->file_id);
+
+ assert(db->segment->nl->ccp_state == CCST_WMXGNT);
+
+ csa = &FILE_INFO(db->greg)->s_addrs;
+
+ if (csa->hdr->jnl_state != jnl_closed)
+ return;
+
+ jpc = csa->jnl;
+
+ if (jpc->qio_active)
+ {
+ /* Just keep trying */
+ if ((status = sys$dclast(ccp_closejnl_ast, db, PSL$C_USER)) != SS$_NORMAL)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+
+ return;
+ }
+ assert(0 != jpc->jnllsb->lockid);
+ if ((status = gtm_deq(jpc->jnllsb->lockid, NULL, PSL$C_USER, 0)) != SS$_NORMAL)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+ jpc->jnllsb->lockid = 0;
+ if ((status = sys$dassgn(jpc->channel)) != SS$_NORMAL)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+
+ jpc->channel = 0;
+ jpc->pini_addr = 0;
+}
diff --git a/sr_vvms/ccp_tr_debug.c b/sr_vvms/ccp_tr_debug.c
new file mode 100644
index 0000000..f2f1716
--- /dev/null
+++ b/sr_vvms/ccp_tr_debug.c
@@ -0,0 +1,23 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "ccp.h"
+#include <ssdef.h>
+
+void ccp_tr_debug(r)
+ccp_action_record *r;
+{
+ /* could/should establish dbg$input and dbg$output */
+ lib$signal(SS$_DEBUG);
+ return;
+}
diff --git a/sr_vvms/ccp_tr_ewmwtbf.c b/sr_vvms/ccp_tr_ewmwtbf.c
new file mode 100644
index 0000000..fc2d431
--- /dev/null
+++ b/sr_vvms/ccp_tr_ewmwtbf.c
@@ -0,0 +1,79 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "gdsbgtr.h"
+#include "ccp.h"
+#include "locks.h"
+#include <lckdef.h>
+#include <psldef.h>
+#include <efndef.h>
+
+#include "jnl.h"
+
+
+static int4 delta_50_msec[2] = { -500000, -1 }; /**** PUT THIS IN THE DATA BASE HEADER !!! ***/
+
+
+/* Exit write mode and wait for buffers to be written out */
+
+void ccp_tr_ewmwtbf( ccp_action_record *rec)
+{
+ ccp_db_header *db;
+ gd_region *r;
+ sgmnt_addrs *csa;
+ cache_rec *w, *wtop;
+ uint4 status;
+
+
+ db = rec->v.h;
+ assert(db->segment->nl->ccp_state == CCST_WMXGNT);
+
+ r = db->greg;
+ wcs_wtfini(r);
+ sys$dclast(wcs_wtstart, r, 0);
+ csa = &FILE_INFO(r)->s_addrs;
+
+ w = &db->segment->acc_meth.bg.cache_state->cache_array;
+ w += db->segment->hdr->bt_buckets;
+ for (wtop = w + db->glob_sec->n_bts; (w < wtop) && (0 == w->dirty); ++w)
+ ;
+
+ if (w >= wtop && db->segment->acc_meth.bg.cache_state->cacheq_active.fl == 0 &&
+ (!JNL_ENABLED(csa->hdr) || csa->jnl == NULL || csa->jnl->jnl_buff->dskaddr == csa->jnl->jnl_buff->freeaddr))
+ {
+ /* All dirty buffers have now been flushed */
+ (void)ccp_enqw(EFN$C_ENF, LCK$K_NLMODE, &db->flush_iosb, LCK$M_CONVERT, NULL, 0, NULL, 0, NULL, PSL$C_USER, 0);
+ /***** Check error status here? *****/
+
+ db->segment->nl->ccp_state = CCST_RDMODE;
+ db->write_mode_requested = FALSE;
+
+ ccp_pndg_proc_wake(&db->exitwm_wait);
+
+ if (db->close_region)
+ ccp_close1(db);
+ else
+ if (db->write_wait.first != NULL || db->flu_wait.first != NULL)
+ ccp_request_write_mode(db);
+ }
+ else
+ if ((status = sys$setimr(0, delta_50_msec, ccp_ewmwtbf_interrupt, &db->exitwm_timer_id, 0)) != SS$_NORMAL)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+
+}
diff --git a/sr_vvms/ccp_tr_exitwm.c b/sr_vvms/ccp_tr_exitwm.c
new file mode 100644
index 0000000..010fed6
--- /dev/null
+++ b/sr_vvms/ccp_tr_exitwm.c
@@ -0,0 +1,147 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <fab.h>
+#include <iodef.h>
+
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "ccp.h"
+#include <ssdef.h>
+#include "wcs_recover.h"
+#include "crit_wake.h"
+
+
+/****************************************************************************************
+* The scheme for managing exit write mode is explained in CCP_EXITWM_ATTEMPT.C. *
+* Please do not update this code without updating the comments in that module. *
+****************************************************************************************/
+
+error_def(ERR_CCPSIGDMP);
+error_def(ERR_GTMASSERT);
+
+/* Request to relinquish write mode */
+
+void ccp_tr_exitwm( ccp_action_record *rec)
+{
+ ccp_db_header *db;
+ sgmnt_addrs *cs_addrs;
+ bt_rec *que_base, *que_top, *p;
+ int4 n, i;
+ uint4 status;
+
+ db = ccp_get_reg(&rec->v.exreq.fid);
+ if (db == NULL)
+ return;
+
+ cs_addrs = db->segment;
+
+ if (rec->v.exreq.cycle != db->segment->nl->ccp_cycle || db->segment->nl->ccp_state != CCST_DRTGNT)
+ {
+ if (rec->pid != 0)
+ if (db->segment->nl->ccp_state == CCST_WMXREQ)
+ ccp_pndg_proc_add(&db->exitwm_wait, rec->pid);
+ else
+ crit_wake(&rec->pid);
+ return;
+ }
+
+ if (rec->pid != 0)
+ ccp_pndg_proc_add(&db->exitwm_wait, rec->pid);
+
+ if (cs_addrs->nl->in_crit != 0 && cs_addrs->nl->in_crit != rec->pid)
+ return;
+
+ if (cs_addrs->nl->wc_blocked)
+ wcs_recover(db->greg);
+
+ assert(!db->tick_in_progress);
+ assert(db->quantum_expired);
+ assert(db->segment->nl->ccp_crit_blocked);
+ assert(db->segment->nl->ccp_state == CCST_DRTGNT);
+ assert(db->segment->ti->curr_tn == db->segment->ti->early_tn);
+
+ db->segment->nl->ccp_state = CCST_WMXREQ;
+
+ if (db->stale_timer_id != NULL)
+ {
+ status = sys$setimr(0, &db->glob_sec->staleness, ccp_staleness, &db->stale_timer_id, 0);
+ if (status != SS$_NORMAL)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+ db->stale_in_progress = TRUE;
+ }
+
+ db->last_write_tn = db->segment->ti->early_tn;
+
+ for (;;)
+ {
+ for (que_base = db->segment->bt_header, que_top = que_base + db->glob_sec->n_bts;
+ que_base < que_top;
+ que_base++)
+ {
+ assert(que_base->blk == BT_QUEHEAD);
+ i = 0;
+ for (p = (bt_rec *)((char *)que_base + que_base->blkque.fl);
+ p != que_base;
+ p = (bt_rec *)((char *)p + p->blkque.fl))
+ {
+ if (((int4)p & 3) != 0)
+ ccp_signal_cont(ERR_GTMASSERT); /***** Is this reasonable? *****/
+ n = p->cache_index;
+ p->flushing = (n == -1) ? FALSE : ((cache_rec *)((char *)db->glob_sec + n))->dirty;
+ if (i > db->glob_sec->n_bts)
+ break;
+ i++;
+ }
+ if (i > db->glob_sec->n_bts)
+ break;
+ }
+ if (i > db->glob_sec->n_bts)
+ {
+ lib$signal(ERR_CCPSIGDMP, 1);
+ wcs_recover(db->greg);
+ }
+ else
+ break;
+ }
+
+ /* Update the master map if it has changed. If the map is updated, then the master map ast completion
+ routine will start the transaction history update. Otherwise, we will start it here. */
+ if (db->master_map_start_tn < cs_addrs->ti->mm_tn)
+ {
+ status = sys$qio(0, FILE_INFO(db->greg)->fab->fab$l_stv, IO$_WRITEVBLK, &db->qio_iosb, ccp_exitwm1, db,
+ MM_ADDR(db->glob_sec), MASTER_MAP_SIZE(db->glob_sec), MM_BLOCK, 0, 0, 0);
+ if ((status & 1) == 0)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+ db->master_map_start_tn = cs_addrs->ti->mm_tn;
+ }
+ else
+ if (db->last_lk_sequence < cs_addrs->ti->lock_sequence)
+ {
+ status = sys$qio(0, FILE_INFO(db->greg)->fab->fab$l_stv, IO$_WRITEVBLK, &db->qio_iosb, ccp_exitwm1a, db,
+ cs_addrs->lock_addrs[0], db->glob_sec->lock_space_size, LOCK_BLOCK(db->glob_sec) + 1,
+ 0, 0, 0);
+ if ((status & 1) == 0)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+ db->last_lk_sequence = cs_addrs->ti->lock_sequence;
+ }
+ else
+ ccp_exitwm2(db);
+
+ return;
+}
diff --git a/sr_vvms/ccp_tr_exwmreq.c b/sr_vvms/ccp_tr_exwmreq.c
new file mode 100644
index 0000000..aa725e4
--- /dev/null
+++ b/sr_vvms/ccp_tr_exwmreq.c
@@ -0,0 +1,37 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "ccp.h"
+#include <psldef.h>
+#include <ssdef.h>
+
+
+/* Request to relinquish write mode, implying that there is a write mode request from another machine */
+
+void ccp_tr_exwmreq( ccp_action_record *rec)
+{
+ ccp_db_header *db;
+ uint4 status;
+
+
+ db = rec->v.h;
+
+ if (db != NULL && !db->wmexit_requested)
+ {
+ status = sys$dclast(ccp_exitwm_blkast, &db->exitwm_timer_id, PSL$C_USER);
+ if (status != SS$_NORMAL)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+ }
+
+ return;
+}
diff --git a/sr_vvms/ccp_tr_flushlk.c b/sr_vvms/ccp_tr_flushlk.c
new file mode 100644
index 0000000..b93e904
--- /dev/null
+++ b/sr_vvms/ccp_tr_flushlk.c
@@ -0,0 +1,39 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "ccp.h"
+#include "crit_wake.h"
+
+void ccp_tr_flushlk( ccp_action_record *rec)
+{
+ ccp_db_header *db;
+
+ db = ccp_get_reg(&rec->v.file_id);
+ assert(db);
+ {
+ /* file is open */
+ if (CCP_SEGMENT_STATE(db->segment->nl, CCST_MASK_HAVE_DIRTY_BUFFERS))
+ crit_wake(&rec->pid);
+ else
+ {
+ ccp_pndg_proc_add(&db->flu_wait, rec->pid);
+ if (!db->write_mode_requested)
+ ccp_request_write_mode(db);
+ }
+ }
+}
diff --git a/sr_vvms/ccp_tr_gotdrt.c b/sr_vvms/ccp_tr_gotdrt.c
new file mode 100644
index 0000000..0ed895e
--- /dev/null
+++ b/sr_vvms/ccp_tr_gotdrt.c
@@ -0,0 +1,54 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "ccp.h"
+#include <psldef.h>
+#include <ssdef.h>
+
+
+/* Dirty buffers acquired; entered after successful conversion of Flush-lock to Exclusive mode */
+
+void ccp_tr_gotdrt( ccp_action_record *rec)
+{
+ ccp_db_header *db;
+ uint4 status;
+ void ccp_exitwm_attempt(), ccp_gotdrt_tick();
+
+
+ db = rec->v.h;
+
+ assert(!db->dirty_buffers_acquired);
+ db->dirty_buffers_acquired = TRUE;
+
+ assert(db->segment->nl->ccp_state == CCST_WRTGNT);
+ db->segment->nl->ccp_state = CCST_DRTGNT;
+
+ if (db->blocking_ast_received && !db->tick_in_progress && !db->quantum_expired)
+ {
+ status = sys$dclast(ccp_gotdrt_tick, db, PSL$C_USER);
+ if (status != SS$_NORMAL)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+ }
+
+ ccp_pndg_proc_wake(&db->flu_wait);
+ status = sys$dclast(ccp_exitwm_attempt, db, PSL$C_USER);
+ if (status != SS$_NORMAL)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+
+ return;
+}
diff --git a/sr_vvms/ccp_tr_lkrqwake.c b/sr_vvms/ccp_tr_lkrqwake.c
new file mode 100644
index 0000000..7924d60
--- /dev/null
+++ b/sr_vvms/ccp_tr_lkrqwake.c
@@ -0,0 +1,54 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "ccp.h"
+#include "locks.h"
+#include <psldef.h>
+#include <lckdef.h>
+#include <ssdef.h>
+
+
+/* Request to wake up all cluster processes waiting for an M-lock */
+
+void ccp_tr_lkrqwake( ccp_action_record *rec)
+{
+ ccp_db_header *db;
+ uint4 status;
+
+
+ db = ccp_get_reg(&rec->v.file_id);
+ if (db != NULL)
+ {
+ /* Deliver blocking AST's to any CCP's running on other nodes */
+ status = ccp_enq(0, LCK$K_EXMODE, &db->lock_iosb, LCK$M_CONVERT, NULL, 0,
+ NULL, 0, NULL, PSL$C_USER, 0);
+ /***** Check error status here? *****/
+
+ /* Cancel the previous request; its only purpose was to deliver the blocking AST's */
+ status = sys$deq(db->lock_iosb.lockid, NULL, PSL$C_USER, LCK$M_CANCEL);
+ if (status != SS$_NORMAL && status != SS$_CANCELGRANT)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+
+ /* Reestablish our own blocking AST routine */
+ status = ccp_enq(0, LCK$K_CRMODE, &db->lock_iosb, LCK$M_CONVERT | LCK$M_SYNCSTS, NULL, 0,
+ ccp_lkrqwake1, db, ccp_lkdowake_blkast, PSL$C_USER, 0);
+ /***** Check error status here? *****/
+ }
+
+ return;
+}
diff --git a/sr_vvms/ccp_tr_null.c b/sr_vvms/ccp_tr_null.c
new file mode 100644
index 0000000..b0cacad
--- /dev/null
+++ b/sr_vvms/ccp_tr_null.c
@@ -0,0 +1,20 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "ccp.h"
+
+void ccp_tr_null(r)
+ccp_action_record *r;
+{
+ return;
+}
diff --git a/sr_vvms/ccp_tr_opendb1.c b/sr_vvms/ccp_tr_opendb1.c
new file mode 100644
index 0000000..b8e3419
--- /dev/null
+++ b/sr_vvms/ccp_tr_opendb1.c
@@ -0,0 +1,119 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "ccp.h"
+#include "vmsdtype.h"
+#include "locks.h"
+#include <descrip.h>
+#include <lckdef.h>
+#include <psldef.h>
+#include <ssdef.h>
+#include <syidef.h>
+#include <efndef.h>
+
+
+
+#define DEF_NODE 0xFFFF
+
+typedef struct
+ {
+ item_list_3 ilist;
+ int4 terminator;
+ } syistruct;
+
+
+/* Open database, second phase; entered after successful sys$open from ccp_opendb1 */
+
+void ccp_tr_opendb1( ccp_action_record *rec)
+{
+ ccp_action_record request;
+ ccp_db_header *db;
+ uint4 node, status, retlen;
+ unsigned short iosb[4];
+ unsigned char resnam_buffer[GLO_NAME_MAXLEN];
+ struct dsc$descriptor_s resnam;
+ syistruct syi_list;
+
+
+ if ((db = rec->v.h) == NULL)
+ return;
+
+ global_name("GT$F", &FILE_INFO(db->greg)->file_id, resnam_buffer);
+ resnam.dsc$a_pointer = &resnam_buffer[1];
+ resnam.dsc$w_length = resnam_buffer[0];
+ resnam.dsc$b_dtype = DSC$K_DTYPE_T;
+ resnam.dsc$b_class = DSC$K_CLASS_S;
+
+ status = ccp_enqw(EFN$C_ENF, LCK$K_NLMODE, &db->flush_iosb, LCK$M_SYSTEM, &resnam, 0, NULL, 0, NULL, PSL$C_USER, 0);
+ /***** Check error status here? *****/
+
+ resnam_buffer[4] = 'L';
+ status = ccp_enqw(EFN$C_ENF, LCK$K_NLMODE, &db->lock_iosb, LCK$M_SYSTEM, &resnam, 0, NULL, 0, NULL, PSL$C_USER, 0);
+ /***** Check error status here? *****/
+
+ memset(db->wm_iosb.valblk, 0, SIZEOF(db->wm_iosb.valblk));
+ resnam_buffer[4] = 'S';
+ status = ccp_enqw(EFN$C_ENF, LCK$K_NLMODE, &db->wm_iosb, LCK$M_SYSTEM, &resnam, 0, NULL, 0, NULL, PSL$C_USER, 0);
+ /***** Check error status here? *****/
+
+ if (db->wm_iosb.cond == SS$_NORMAL)
+ {
+ node = 0;
+ syi_list.ilist.item_code = SYI$_NODE_CSID;
+ syi_list.ilist.buffer_address = &node;
+ syi_list.ilist.buffer_length = SIZEOF(node);
+ syi_list.ilist.return_length_address = &retlen;
+ syi_list.terminator = 0;
+ status = sys$getsyiw(EFN$C_ENF, NULL, NULL, &syi_list, iosb, NULL, 0);
+ if (status != SS$_NORMAL || (status = iosb[0]) != SS$_NORMAL)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+ if (node == 0)
+ node = DEF_NODE;
+
+ memcpy(resnam_buffer, "GT$N_", 5);
+ i2hex(node, &resnam_buffer[5], 8);
+
+ resnam.dsc$a_pointer = resnam_buffer;
+ resnam.dsc$w_length = 13;
+ status = ccp_enqw(EFN$C_ENF, LCK$K_CRMODE, &db->refcnt_iosb, LCK$M_SYSTEM, &resnam, db->wm_iosb.lockid,
+ NULL, 0, NULL, PSL$C_USER, 0);
+ /***** Check error status here? *****/
+ }
+ else
+ /* Force a retry in ccp_tr_opendb1b (we set the low bit to distinguish this from a true deadlock) */
+ db->refcnt_iosb.cond = SS$_DEADLOCK | 1;
+
+ if (db->flush_iosb.cond == SS$_NORMAL && db->lock_iosb.cond == SS$_NORMAL &&
+ db->wm_iosb.cond == SS$_NORMAL && db->refcnt_iosb.cond == SS$_NORMAL)
+ {
+ /* Convert Write-mode lock from Null to Protected Write, reading the lock value block */
+ status = ccp_enq(0, LCK$K_PWMODE, &db->wm_iosb, LCK$M_CONVERT | LCK$M_VALBLK, NULL, 0,
+ ccp_opendb2, db, NULL, PSL$C_USER, 0);
+ /***** Check error status here? *****/
+ }
+ else
+ {
+ request.action = CCTR_OPENDB1B;
+ request.pid = 0;
+ request.v.h = db;
+ ccp_act_request(&request);
+ }
+
+ return;
+}
diff --git a/sr_vvms/ccp_tr_opendb1a.c b/sr_vvms/ccp_tr_opendb1a.c
new file mode 100644
index 0000000..44c1411
--- /dev/null
+++ b/sr_vvms/ccp_tr_opendb1a.c
@@ -0,0 +1,42 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <fab.h>
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "ccp.h"
+#include <iodef.h>
+
+
+/* Open database, first phase, step two; entered after successful completion
+ of sys$open in ccp_opendb (via ccp_opendb1a) */
+
+void ccp_tr_opendb1a( ccp_action_record *rec)
+{
+ ccp_db_header *db;
+ uint4 status;
+
+
+ db = ccp_get_reg_by_fab(rec->v.fab);
+ db->segment->hdr = malloc(SIZEOF(sgmnt_data));
+
+ status = sys$qio(0, rec->v.fab->fab$l_stv, IO$_READVBLK, &db->qio_iosb, ccp_opendb1, db,
+ db->segment->hdr, SIZEOF(sgmnt_data), 1, 0, 0, 0);
+ if ((status & 1) == 0)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+
+ return;
+}
diff --git a/sr_vvms/ccp_tr_opendb1b.c b/sr_vvms/ccp_tr_opendb1b.c
new file mode 100644
index 0000000..6d1b80d
--- /dev/null
+++ b/sr_vvms/ccp_tr_opendb1b.c
@@ -0,0 +1,154 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "ccp.h"
+#include "vmsdtype.h"
+#include "locks.h"
+#include <descrip.h>
+#include <lckdef.h>
+#include <psldef.h>
+#include <ssdef.h>
+#include <syidef.h>
+#include <efndef.h>
+
+
+
+#define DEF_NODE 0xFFFF
+
+typedef struct
+ {
+ item_list_3 ilist;
+ int4 terminator;
+ } syistruct;
+
+
+/* Entered after any failure to grant database locks in ccp_tr_opendb1; retry */
+
+void ccp_tr_opendb1b( ccp_action_record *rec)
+{
+ ccp_action_record request;
+ ccp_db_header *db;
+ uint4 node, status, retlen;
+ unsigned short iosb[4];
+ unsigned char resnam_buffer[GLO_NAME_MAXLEN];
+ struct dsc$descriptor_s resnam;
+ syistruct syi_list;
+
+
+ if ((db = rec->v.h) == NULL)
+ return;
+
+ global_name("GT$F", &FILE_INFO(db->greg)->file_id, resnam_buffer);
+ resnam.dsc$a_pointer = &resnam_buffer[1];
+ resnam.dsc$w_length = resnam_buffer[0];
+ resnam.dsc$b_dtype = DSC$K_DTYPE_T;
+ resnam.dsc$b_class = DSC$K_CLASS_S;
+
+ if (db->flush_iosb.cond != SS$_NORMAL)
+ {
+ ccp_signal_cont(db->flush_iosb.cond); /***** Is this reasonable? *****/
+
+ if (db->flush_iosb.cond == SS$_DEADLOCK)
+ {
+ /* Just try again */
+ status = ccp_enqw(EFN$C_ENF, LCK$K_NLMODE, &db->flush_iosb, LCK$M_SYSTEM, &resnam, 0,
+ NULL, 0, NULL, PSL$C_USER, 0);
+ /***** Check error status here? *****/
+ }
+ }
+
+ if (db->lock_iosb.cond != SS$_NORMAL)
+ {
+ ccp_signal_cont(db->lock_iosb.cond); /***** Is this reasonable? *****/
+
+ if (db->lock_iosb.cond == SS$_DEADLOCK)
+ {
+ resnam_buffer[4] = 'L';
+ /* Just try again */
+ status = ccp_enqw(EFN$C_ENF, LCK$K_NLMODE, &db->lock_iosb, LCK$M_SYSTEM, &resnam, 0,
+ NULL, 0, NULL, PSL$C_USER, 0);
+ /***** Check error status here? *****/
+ }
+ }
+
+ if (db->wm_iosb.cond != SS$_NORMAL)
+ {
+ ccp_signal_cont(db->wm_iosb.cond); /***** Is this reasonable? *****/
+
+ if (db->wm_iosb.cond == SS$_DEADLOCK)
+ {
+ memset(db->wm_iosb.valblk, 0, SIZEOF(db->wm_iosb.valblk));
+ resnam_buffer[4] = 'S';
+ /* Just try again */
+ status = ccp_enqw(EFN$C_ENF, LCK$K_NLMODE, &db->wm_iosb, LCK$M_SYSTEM, &resnam, 0,
+ NULL, 0, NULL, PSL$C_USER, 0);
+ /***** Check error status here? *****/
+ }
+ }
+
+ if (db->wm_iosb.cond == SS$_NORMAL && db->refcnt_iosb.cond != SS$_NORMAL)
+ if ((db->refcnt_iosb.cond & 0xFFFE) == SS$_DEADLOCK) /* Ignore low bit possibly set in ccp_tr_opendb1 */
+ {
+ if ((db->refcnt_iosb.cond & 1) == 0) /* Only report a true deadlock */
+ ccp_signal_cont(SS$_DEADLOCK);
+
+ node = 0;
+ syi_list.ilist.item_code = SYI$_NODE_CSID;
+ syi_list.ilist.buffer_address = &node;
+ syi_list.ilist.buffer_length = SIZEOF(node);
+ syi_list.ilist.return_length_address = &retlen;
+ syi_list.terminator = 0;
+ status = sys$getsyiw(EFN$C_ENF, NULL, NULL, &syi_list, iosb, NULL, 0);
+ if (status != SS$_NORMAL || (status = iosb[0]) != SS$_NORMAL)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+ if (node == 0)
+ node = DEF_NODE;
+
+ memcpy(resnam_buffer, "GT$N_", 5);
+ i2hex(node, &resnam_buffer[5], 8);
+
+ resnam.dsc$a_pointer = resnam_buffer;
+ resnam.dsc$w_length = 13;
+ /* Just try again */
+ status = ccp_enqw(EFN$C_ENF, LCK$K_CRMODE, &db->refcnt_iosb, LCK$M_SYSTEM, &resnam, db->wm_iosb.lockid,
+ NULL, 0, NULL, PSL$C_USER, 0);
+ /***** Check error status here? *****/
+ }
+ else
+ ccp_signal_cont(db->refcnt_iosb.cond); /***** Is this reasonable? *****/
+
+ if (db->flush_iosb.cond == SS$_NORMAL && db->lock_iosb.cond == SS$_NORMAL &&
+ db->wm_iosb.cond == SS$_NORMAL && db->refcnt_iosb.cond == SS$_NORMAL)
+ {
+ /* Convert Write-mode lock from Null to Protected Write, reading the lock value block */
+ status = ccp_enq(0, LCK$K_PWMODE, &db->wm_iosb, LCK$M_CONVERT | LCK$M_VALBLK, NULL, 0,
+ ccp_opendb2, db, NULL, PSL$C_USER, 0);
+ /***** Check error status here? *****/
+ }
+ else
+ {
+ /* Try again... */
+ request.action = CCTR_OPENDB1B;
+ request.pid = 0;
+ request.v.h = db;
+ ccp_act_request(&request);
+ }
+
+ return;
+}
diff --git a/sr_vvms/ccp_tr_opendb1e.c b/sr_vvms/ccp_tr_opendb1e.c
new file mode 100644
index 0000000..2a5d6aa
--- /dev/null
+++ b/sr_vvms/ccp_tr_opendb1e.c
@@ -0,0 +1,60 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <fab.h>
+
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "ccp.h"
+
+GBLREF ccp_db_header *ccp_reg_root;
+
+
+/* Entered after unsuccessful sys$open in ccp_opendb (via ccp_opendb1e) */
+
+void ccp_tr_opendb1e( ccp_action_record *rec)
+{
+ ccp_db_header *db, *db0, *db1;
+ uint4 status, status1;
+
+
+ db = ccp_get_reg_by_fab(rec->v.fab);
+ if (db == NULL)
+ return;
+
+ status = rec->v.fab->fab$l_sts;
+ status1 = rec->v.fab->fab$l_stv;
+
+ for (db0 = ccp_reg_root, db1 = NULL; db0 != db; db1 = db0, db0 = db0->next)
+ ;
+ if (db1 == NULL)
+ ccp_reg_root = db0->next;
+ else
+ db1->next = db0->next;
+
+ free(FILE_INFO(db->greg)->fab->fab$l_nam);
+ free(FILE_INFO(db->greg)->fab);
+ free(db->greg->dyn.addr);
+ free(db->greg);
+ free(db);
+
+ ccp_quemin_adjust(CCP_CLOSE_REGION);
+ ccp_signal_cont(status, 0, status1); /***** Is this reasonable? *****/
+
+ return;
+}
diff --git a/sr_vvms/ccp_tr_opendb3.c b/sr_vvms/ccp_tr_opendb3.c
new file mode 100644
index 0000000..e5c9f6b
--- /dev/null
+++ b/sr_vvms/ccp_tr_opendb3.c
@@ -0,0 +1,103 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <descrip.h>
+#include <fab.h>
+#include <iodef.h>
+#include <ssdef.h>
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "ccp.h"
+#include "jnl.h"
+#include "ccp_opendb3a.h"
+
+error_def(ERR_CCPJNLOPNERR);
+
+
+
+/* Open database, third phase; entered after completion of sys$qio
+ to read transaction history in ccp_opendb2 (via ccp_opendb3) */
+
+void ccp_tr_opendb3(ccp_action_record *rec)
+{
+ ccp_db_header *db;
+ sgmnt_addrs *csa;
+ sgmnt_data *csd;
+ jnl_private_control *jpc;
+ uint4 status;
+
+
+ db = rec->v.h;
+ db->master_map_start_tn = 0;
+
+ csa = db->segment;
+ csd = db->glob_sec
+ = csa->hdr
+ = csa->db_addrs[0];
+
+ adawi(1, &csa->nl->ref_cnt); /* GT.M process that sent open request */
+ csa->lock_addrs[0] = (unsigned char *)csd + (LOCK_BLOCK(csd) * DISK_BLOCK_SIZE);
+ csa->lock_addrs[1] = csa->lock_addrs[0] + csd->lock_space_size;
+
+ if (JNL_ENABLED(csd))
+ {
+ jpc = csa->jnl
+ = malloc(SIZEOF(jnl_private_control));
+ memset(jpc, 0, SIZEOF(jnl_private_control));
+
+ jpc->region = db->greg;
+ jpc->jnl_buff = csa->lock_addrs[1] + CACHE_CONTROL_SIZE(csd) + JNL_NAME_EXP_SIZE;
+
+ FILE_INFO(db->greg)->s_addrs.jnl->jnllsb->lockid = 0;
+
+ if (db->wm_iosb.valblk[CCP_VALBLK_JNL_ADDR] == 0)
+ {
+ /* Open jnl file based on data in file header, first machine to open */
+ jnl_file_open(db->greg, FALSE, ccp_closejnl_ast);
+ if (jpc->channel == 0)
+ {
+ /* Open failed */
+ ccp_close1(db);
+ ccp_signal_cont(ERR_CCPJNLOPNERR); /***** Is this reasonable? *****/
+ return;
+ }
+
+ /* Write out file id for other machines */
+ csd->trans_hist.ccp_jnl_filesize = jpc->jnl_buff->filesize;
+ csd->ccp_jnl_before = jpc->jnl_buff->before_images;
+
+ status = sys$qio(0, FILE_INFO(db->greg)->fab->fab$l_stv, IO$_WRITEVBLK, &db->qio_iosb, ccp_opendb3a, db,
+ csd, (MM_BLOCK - 1) * OS_PAGELET_SIZE, 1, 0, 0, 0);
+ }
+ else
+ {
+/* ??? --> */ /* Open jnl file based on id in header. Read in header to make sure get file id from first machine */
+
+ status = sys$qio(0, FILE_INFO(db->greg)->fab->fab$l_stv, IO$_READVBLK, &db->qio_iosb, ccp_opendb3a, db,
+ csd, (MM_BLOCK - 1) * OS_PAGELET_SIZE, 1, 0, 0, 0);
+ }
+
+ if (status != SS$_NORMAL)
+ {
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+ ccp_close1(db);
+ }
+ }
+ else
+ ccp_opendb3b(db);
+
+}
diff --git a/sr_vvms/ccp_tr_opendb3a.c b/sr_vvms/ccp_tr_opendb3a.c
new file mode 100644
index 0000000..8d635a8
--- /dev/null
+++ b/sr_vvms/ccp_tr_opendb3a.c
@@ -0,0 +1,28 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "ccp.h"
+
+void ccp_tr_opendb3a( ccp_action_record *rec)
+{
+ ccp_db_header *db;
+
+ db = rec->v.h;
+ ccp_opendb3b(db);
+ return;
+}
diff --git a/sr_vvms/ccp_tr_stop.c b/sr_vvms/ccp_tr_stop.c
new file mode 100644
index 0000000..7abc598
--- /dev/null
+++ b/sr_vvms/ccp_tr_stop.c
@@ -0,0 +1,43 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "ccp.h"
+#include "ccpact.h"
+
+GBLREF bool ccp_stop;
+GBLREF int ccp_stop_ctr;
+GBLREF ccp_db_header *ccp_reg_root;
+
+void ccp_tr_stop( ccp_action_record *r)
+{
+ ccp_db_header *ptr;
+ ccp_action_record buff;
+
+ if (ccp_stop)
+ return;
+ ccp_stop = TRUE;
+ for (ptr = ccp_reg_root; ptr; ptr = ptr->next)
+ { ccp_stop_ctr++;
+ buff.action = CCTR_CLOSE;
+ buff.pid = 0;
+ buff.v.file_id = ((vms_gds_info *)(ptr->greg->dyn.addr->file_cntl->file_info))->file_id;
+ ccp_act_request(&buff);
+ }
+ return;
+}
diff --git a/sr_vvms/ccp_tr_writedb.c b/sr_vvms/ccp_tr_writedb.c
new file mode 100644
index 0000000..7564b7f
--- /dev/null
+++ b/sr_vvms/ccp_tr_writedb.c
@@ -0,0 +1,53 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "ccp.h"
+#include "crit_wake.h"
+
+GBLREF bool ccp_stop;
+
+
+/* Request for write mode */
+
+void ccp_tr_writedb( ccp_action_record *rec)
+{
+ ccp_db_header *db;
+
+
+ db = ccp_get_reg(&rec->v.file_id);
+
+ if (db == NULL)
+ {
+ if (rec->pid != 0 && !ccp_stop)
+ ccp_opendb(rec);
+ }
+ else
+ /* File is open or in the process of being opened */
+ if (rec->pid != 0 && !db->segment->nl->ccp_crit_blocked &&
+ CCP_SEGMENT_STATE(db->segment->nl, CCST_MASK_WRITE_MODE))
+ crit_wake(&rec->pid);
+ else
+ {
+ if (rec->pid != 0)
+ ccp_pndg_proc_add(&db->write_wait, rec->pid);
+ if (!db->write_mode_requested && db->segment->nl->ccp_state != CCST_OPNREQ)
+ ccp_request_write_mode(db);
+ }
+
+ return;
+}
diff --git a/sr_vvms/ccp_tr_writedb1.c b/sr_vvms/ccp_tr_writedb1.c
new file mode 100644
index 0000000..976e5f2
--- /dev/null
+++ b/sr_vvms/ccp_tr_writedb1.c
@@ -0,0 +1,151 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "ccp.h"
+#include "mlkdef.h"
+#include "jnl.h"
+#include "locks.h"
+#include <lckdef.h>
+#include <psldef.h>
+#include <ssdef.h>
+#include "crit_wake.h"
+
+
+#define NODENUMBER 0xFFE00000
+
+GBLREF uint4 process_id;
+
+/* TODO: move to a header */
+void ccp_quantum_interrupt(), ccp_reqdrtbuf_interrupt();
+
+static int4 delta_100_msec[2] = { -1000000, -1 };
+
+
+/* Request for write mode; entered after successful conversion of Write-mode lock to Protected Write */
+
+void ccp_tr_writedb1(ccp_action_record *rec)
+{
+ ccp_action_record request;
+ ccp_db_header *db;
+ jnl_buffer *jb;
+ sgmnt_addrs *csa;
+ int4 curr_time[2];
+ uint4 status, *p1, *p2, *top;
+
+
+ if ((db = rec->v.h) == NULL)
+ return;
+
+ csa = db->segment;
+ assert(csa->nl->ccp_state == CCST_RDMODE || csa->nl->ccp_state == CCST_CLOSED || csa->nl->ccp_state == CCST_OPNREQ);
+
+ if (JNL_ENABLED(csa->hdr))
+ {
+ assert(csa->jnl->channel != 0);
+
+ jb = csa->jnl->jnl_buff;
+
+ if (jb->blocked != 0)
+ {
+ /* jnl writes from a previous write mode are not done yet; try again later */
+ if ((status = sys$setimr(0, delta_100_msec, ccp_writedb5, db, 0)) != SS$_NORMAL)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+ return;
+ }
+
+ jb->epoch_tn = db->wm_iosb.valblk[CCP_VALBLK_EPOCH_TN];
+ jb->freeaddr = jb->dskaddr
+ = ROUND_UP(db->wm_iosb.valblk[CCP_VALBLK_JNL_ADDR], DISK_BLOCK_SIZE);
+ /* lastaddr is no longer a field in jnl_buff
+ * jb->lastaddr = db->wm_iosb.valblk[CCP_VALBLK_LST_ADDR];
+ */
+ jb->free = jb->dsk
+ = 0;
+ }
+
+ /* Note: We must clear these flags prior to changing state or a set from ccp_exitwm_blkast may be missed */
+ db->quantum_expired = FALSE;
+ db->tick_in_progress = FALSE;
+
+ if (db->remote_wakeup)
+ {
+ for (p2 = NULL, p1 = csa->lock_addrs[0], top = p1 + SIZEOF(int4) * NUM_CLST_LCKS;
+ *p1 != 0 && p1 <= top;
+ ++p1)
+ {
+ if ((*p1 & NODENUMBER) == (process_id & NODENUMBER))
+ {
+ crit_wake(p1);
+ if (p2 == NULL)
+ p2 = p1;
+ *p1 = 0;
+ }
+ else
+ if (p2 != NULL)
+ {
+ *p2++ = *p1;
+ *p1 = 0;
+ }
+ }
+
+ db->remote_wakeup = FALSE;
+
+ status = ccp_enq(0, LCK$K_CRMODE, &db->lock_iosb, LCK$M_CONVERT | LCK$M_SYNCSTS, NULL, 0,
+ ccp_lkrqwake1, db, ccp_lkdowake_blkast, PSL$C_USER, 0);
+ /***** Check error status here? *****/
+ }
+
+ db->glob_sec->freeze = 0;
+ /* db->glob_sec->wcs_active_lvl = db->glob_sec->n_bts / 2; */
+ db->drop_lvl = 0;
+
+ sys$gettim(curr_time);
+ lib$add_times(curr_time, db->glob_sec->ccp_quantum_interval, &db->start_wm_time);
+
+ csa->nl->ccp_state = CCST_WRTGNT;
+
+ if (db->blocking_ast_received)
+ {
+ status = sys$dclast(ccp_exitwm_blkast, &db->exitwm_timer_id, PSL$C_USER);
+ if (status != SS$_NORMAL)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+ }
+
+ csa->nl->ccp_crit_blocked = FALSE;
+ ++csa->nl->ccp_cycle;
+
+ status = sys$setimr(0, &db->glob_sec->ccp_quantum_interval, ccp_quantum_interrupt, &db->quantum_timer_id, 0);
+ if (status != SS$_NORMAL)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+
+ db->dirty_buffers_acquired = FALSE;
+ ccp_pndg_proc_wake(&db->write_wait);
+
+ status = ccp_enq(0, LCK$K_EXMODE, &db->flush_iosb, LCK$M_CONVERT | LCK$M_SYNCSTS, NULL, 0,
+ ccp_reqdrtbuf_interrupt, db, NULL, PSL$C_USER, 0);
+ if (status == SS$_SYNCH)
+ {
+ request.action = CCTR_GOTDRT;
+ request.pid = 0;
+ request.v.h = db;
+ ccp_act_request(&request);
+ }
+ /***** Check error status here? *****/
+
+}
diff --git a/sr_vvms/ccp_userwait.c b/sr_vvms/ccp_userwait.c
new file mode 100644
index 0000000..3aaab96
--- /dev/null
+++ b/sr_vvms/ccp_userwait.c
@@ -0,0 +1,89 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <iodef.h>
+#include <fab.h>
+#include <efndef.h>
+
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "ccp.h"
+
+static bool ccp_communication_timeout;
+/***********************************************************************
+This routine is called to wait for a clustered data base to transition
+to a new state. If the "state" parameter is non-zero, then it is
+considered a bit mask, with state zero being the lsb, etc. (All of
+these masks are symbolically defined in ccp.h as CCST_MASK_nnnnn.)
+In this case we will return when the state is obtained. If the
+state is zero, we will return when the ccp_cycle count is bumped,
+indicating that we have transitioned into read mode. In any event
+we will return after the "next" cycle has passed, so that if we
+"miss" our window, we can try again.
+***********************************************************************/
+bool ccp_userwait(gd_region *reg, uint4 state, int4 *timadr, unsigned short cycle)
+ /* if timadr is non-zero, then the timeout quadword, else use the seg's timeout interval */
+{
+ int4 status;
+ static void ccp_nocomm();
+ bool timer_on;
+ sgmnt_data *seg;
+ sgmnt_addrs *csa;
+ int4 *timptr;
+ char buff[(MM_BLOCK - 1) * DISK_BLOCK_SIZE];
+ short iosb[4];
+ error_def(ERR_CCPNOTFND);
+
+ csa = &((vms_gds_info *)(reg->dyn.addr->file_cntl->file_info))->s_addrs;
+ seg = ((vms_gds_info *)(reg->dyn.addr->file_cntl->file_info))->s_addrs.hdr;
+ timptr = timadr ? timadr : (int4 *) &seg->ccp_response_interval;
+ timer_on = timptr[0] != 0 && timptr[1] != 0;
+ for (; ;)
+ { ccp_communication_timeout = FALSE;
+ if (timer_on)
+ {
+ status = sys$setimr(0, timptr, ccp_nocomm, ccp_nocomm, 0);
+ if ((status & 1) == 0)
+ rts_error(VARLSTCNT(1) status);
+ }
+ while (!CCP_SEGMENT_STATE(csa->nl, state) && csa->nl->ccp_cycle == cycle && !ccp_communication_timeout)
+ {
+ sys$hiber();
+ }
+
+ if (ccp_communication_timeout && !(CCP_SEGMENT_STATE(csa->nl, state) || csa->nl->ccp_cycle != cycle))
+ {
+ status = sys$qiow(EFN$C_ENF, ((vms_gds_info *)(reg->dyn.addr->file_cntl->file_info))->fab->fab$l_stv,
+ IO$_READVBLK, &iosb[0], 0, 0, buff, SIZEOF(buff), 1, 0, 0, 0);
+ if ((status & 1) && (iosb[0] & 1) && ((sgmnt_data *)buff)->freeze)
+ continue;
+ rts_error(VARLSTCNT(1) ERR_CCPNOTFND);
+ }else
+ break;
+ }
+ if (timer_on)
+ sys$cantim(ccp_nocomm,0);
+ return CCP_SEGMENT_STATE(csa->nl, state);
+}
+
+static void ccp_nocomm()
+{
+ ccp_communication_timeout = TRUE;
+ sys$wake(0,0);
+ return;
+}
diff --git a/sr_vvms/ccp_writedb2.c b/sr_vvms/ccp_writedb2.c
new file mode 100644
index 0000000..fead00d
--- /dev/null
+++ b/sr_vvms/ccp_writedb2.c
@@ -0,0 +1,192 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <fab.h>
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "ccp.h"
+#include "jnl.h"
+#include <iodef.h>
+#include <ssdef.h>
+#include "wcs_recover.h"
+#include "ccp_writedb2.h"
+#include "ccp_writedb3.h"
+
+
+error_def(ERR_CCPSIGDMP);
+
+GBLREF uint4 process_id;
+
+
+
+/* AST routine entered on completion of sys$qio to read transaction history in ccp_reqwm_interrupt */
+
+void ccp_writedb2(ccp_db_header *db)
+{
+ bt_rec *btr, *que_base, *que_top;
+ cache_rec *wtop, *w;
+ sgmnt_addrs *cs_addrs;
+ int i;
+ uint4 status;
+
+
+ assert(lib$ast_in_prog());
+
+ cs_addrs = db->segment;
+ if (cs_addrs == NULL || cs_addrs->nl->ccp_state == CCST_CLOSED)
+ return;
+
+ if ((db->qio_iosb.cond & 1) == 0)
+ ccp_signal_cont(db->qio_iosb.cond); /***** Is this reasonable? *****/
+
+ if (JNL_ENABLED(cs_addrs->hdr))
+ cs_addrs->jnl->jnl_buff->filesize = cs_addrs->ti->ccp_jnl_filesize;
+
+/******************************************************************************
+
+There are several possible threads of execution subsequent to the completion of
+this routine. If the master map needs to be re-read, then we inititate the qio
+read. The completions ast for this read, ccp_writedb4, checks the status and
+then either initiates a read to update the lock section if necessary or calls
+ccp_writedb5 which posts an action request to finish the job. On the other
+hand, if the master map is up to date, then we either read the lock section if
+necessary or call ccp_writedb5 at this time so that the next step will be
+effected upon completion of this routine. The completion ast for the lock read
+checks the status and then calls ccp_writedb5 to post an action request to
+finish the job. We post the reads first in order to overlap the I/O and
+processing. (Note: further improvement could be obtained by not waiting on
+completion of the master map read until some time later when a GT.M process
+required the master map. Would still need to update the total_blks field.)
+
+******************************************************************************/
+
+ assert (cs_addrs->ti->curr_tn == cs_addrs->ti->early_tn);
+
+ if (db->wm_iosb.valblk[CCP_VALBLK_TRANS_HIST] == 0)
+ {
+ status = sys$qio(0, FILE_INFO(db->greg)->fab->fab$l_stv, IO$_READVBLK, &db->qio_iosb, ccp_writedb3, db,
+ cs_addrs->db_addrs[0], (MM_BLOCK - 1) * 512, 1, 0, 0, 0);
+ if (status == SS$_IVCHAN)
+ /* database has been closed out, section deleted */
+ return;
+ if (status != SS$_NORMAL)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+ }
+ else
+ if (db->master_map_start_tn < cs_addrs->ti->mm_tn)
+ {
+ status = sys$qio(0, FILE_INFO(db->greg)->fab->fab$l_stv, IO$_READVBLK, &db->qio_iosb, ccp_writedb4, db,
+ MM_ADDR(db->glob_sec), MASTER_MAP_SIZE(db->glob_sec), MM_BLOCK, 0, 0, 0);
+ if (status == SS$_IVCHAN)
+ /* database has been closed out, section deleted */
+ return;
+ if (status != SS$_NORMAL)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+ db->master_map_start_tn = cs_addrs->ti->mm_tn;
+ }
+ else
+ if (db->last_lk_sequence < cs_addrs->ti->lock_sequence)
+ {
+ status = sys$qio(0, FILE_INFO(db->greg)->fab->fab$l_stv, IO$_READVBLK, &db->qio_iosb,
+ ccp_writedb4a, db, cs_addrs->lock_addrs[0], db->glob_sec->lock_space_size,
+ LOCK_BLOCK(db->glob_sec) + 1, 0, 0, 0);
+ if (status == SS$_IVCHAN)
+ /* database has been closed out, section deleted */
+ return;
+ if (status != SS$_NORMAL)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+ db->last_lk_sequence = cs_addrs->ti->lock_sequence;
+ }
+ else
+ ccp_writedb5(db);
+
+ w = &cs_addrs->acc_meth.bg.cache_state->cache_array;
+ w += cs_addrs->hdr->bt_buckets;
+ for (wtop = w + cs_addrs->hdr->n_bts; w < wtop; ++w)
+ {
+ if (w->blk != CR_BLKEMPTY)
+ if ((btr = ccp_bt_get(cs_addrs, w->blk)) == NULL)
+ {
+ if (w->tn <= OLDEST_HIST_TN(cs_addrs))
+ {
+ w->cycle++; /* increment cycle whenever blk number changes (tp_hist depends on this) */
+ w->blk = CR_BLKEMPTY;
+ }
+ w->bt_index = 0;
+ }
+ else
+ if (btr->tn < db->last_write_tn) /* not changed since dropped write mode */
+ {
+ w->bt_index = GDS_ABS2REL(btr);
+ btr->cache_index = GDS_ABS2REL(w);
+ }
+ else
+ {
+ assert(0 == w->dirty);
+ btr->cache_index = CR_NOTVALID;
+ w->cycle++; /* increment cycle whenever blk number changes (tp_hist depends on this) */
+ w->blk = CR_BLKEMPTY;
+ w->bt_index = 0;
+ }
+ assert(0 == w->dirty);
+ }
+
+ for (;;)
+ {
+ for (que_base = cs_addrs->bt_header, que_top = que_base + cs_addrs->hdr->bt_buckets;
+ que_base < que_top;
+ ++que_base)
+ {
+ assert(que_base->blk == BT_QUEHEAD);
+ i = 0;
+ for (btr = (bt_rec *)((char *)que_base + que_base->blkque.fl);
+ btr != que_base;
+ btr = (bt_rec *)((char *)btr + btr->blkque.fl))
+ {
+ if (btr->cache_index != CR_NOTVALID)
+ {
+ w = GDS_REL2ABS(btr->cache_index);
+ if (w->blk != btr->blk)
+ btr->cache_index = CR_NOTVALID;
+ }
+
+ if (i > cs_addrs->hdr->n_bts)
+ break;
+ ++i;
+ }
+
+ if (i > cs_addrs->hdr->n_bts)
+ break;
+ }
+
+ if (i > cs_addrs->hdr->n_bts)
+ {
+ lib$signal(ERR_CCPSIGDMP, 1);
+ wcs_recover(db->greg);
+ }
+ else
+ break;
+ }
+
+ if (cs_addrs->now_crit)
+ {
+ assert(cs_addrs->nl->in_crit == process_id);
+ cs_addrs->nl->in_crit = 0;
+ (void)mutex_unlockw(cs_addrs->critical, cs_addrs->critical->crashcnt, &cs_addrs->now_crit);
+ /***** Check error status here? *****/
+ }
+}
diff --git a/sr_vvms/ccp_writedb2.h b/sr_vvms/ccp_writedb2.h
new file mode 100644
index 0000000..0bb73b8
--- /dev/null
+++ b/sr_vvms/ccp_writedb2.h
@@ -0,0 +1,16 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+#ifndef __CCP_WRITEDB2_H__
+#define __CCP_WRITEDB2_H__
+
+void ccp_writedb2(ccp_db_header *db);
+
+#endif
diff --git a/sr_vvms/ccp_writedb3.c b/sr_vvms/ccp_writedb3.c
new file mode 100644
index 0000000..eba7e52
--- /dev/null
+++ b/sr_vvms/ccp_writedb3.c
@@ -0,0 +1,76 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2005 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <iodef.h>
+#include <rms.h>
+#include <ssdef.h>
+
+#include "gdsroot.h"
+#include "ccp.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "ccp_writedb3.h"
+
+
+/* AST routine entered on completion of sys$qio to read header in ccp_writedb2 */
+
+void ccp_writedb3(ccp_db_header *db)
+{
+ uint4 status;
+ sgmnt_addrs *cs_addrs;
+
+
+ assert(lib$ast_in_prog());
+
+ cs_addrs = db->segment;
+
+ if (cs_addrs == NULL || cs_addrs->nl->ccp_state == CCST_CLOSED)
+ return;
+
+ if ((db->qio_iosb.cond & 1) == 0)
+ ccp_signal_cont(db->qio_iosb.cond); /***** Is this reasonable? *****/
+
+ cs_addrs->nl->in_wtstart = 0;
+ cs_addrs->nl->wc_in_free = cs_addrs->hdr->n_bts;
+
+ if (db->master_map_start_tn < cs_addrs->ti->mm_tn)
+ {
+ status = sys$qio(0, FILE_INFO(db->greg)->fab->fab$l_stv, IO$_READVBLK, &db->qio_iosb, ccp_writedb4, db,
+ MM_ADDR(db->glob_sec), MASTER_MAP_SIZE(db->glob_sec), MM_BLOCK, 0, 0, 0);
+ if (status == SS$_IVCHAN) /* database has been closed out, section deleted */
+ return;
+ if ((status & 1) == 0)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+ db->master_map_start_tn = cs_addrs->ti->mm_tn;
+ }
+ else
+ if (db->last_lk_sequence < cs_addrs->ti->lock_sequence)
+ {
+ status = sys$qio(0, FILE_INFO(db->greg)->fab->fab$l_stv, IO$_READVBLK, &db->qio_iosb, ccp_writedb4a, db,
+ cs_addrs->lock_addrs[0], db->glob_sec->lock_space_size, LOCK_BLOCK(db->glob_sec) + 1,
+ 0, 0, 0);
+ if (status == SS$_IVCHAN) /* database has been closed out, section deleted */
+ return;
+ if ((status & 1) == 0)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+ db->last_lk_sequence = cs_addrs->ti->lock_sequence;
+ }
+ else
+ ccp_writedb5(db);
+
+ return;
+}
diff --git a/sr_vvms/ccp_writedb3.h b/sr_vvms/ccp_writedb3.h
new file mode 100644
index 0000000..82f8436
--- /dev/null
+++ b/sr_vvms/ccp_writedb3.h
@@ -0,0 +1,16 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+#ifndef __CCP_WRITEDB3_H__
+#define __CCP_WRITEDB3_H__
+
+void ccp_writedb3(ccp_db_header *db);
+
+#endif
diff --git a/sr_vvms/ccp_writedb4.c b/sr_vvms/ccp_writedb4.c
new file mode 100644
index 0000000..8ab5dfd
--- /dev/null
+++ b/sr_vvms/ccp_writedb4.c
@@ -0,0 +1,61 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <iodef.h>
+#include <rms.h>
+#include <ssdef.h>
+
+#include "gdsroot.h"
+#include "ccp.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+
+
+/* AST routine entered on completion of sys$qio to read the master map,
+ in ccp_writedb2 or ccp_writedb3 */
+
+void ccp_writedb4(ccp_db_header *db)
+{
+ sgmnt_addrs *cs_addrs;
+ uint4 status;
+
+
+ assert(lib$ast_in_prog());
+
+ cs_addrs = db->segment;
+
+ if (cs_addrs == NULL || cs_addrs->nl->ccp_state == CCST_CLOSED)
+ return;
+
+ if ((db->qio_iosb.cond & 1) == 0)
+ ccp_signal_cont(db->qio_iosb.cond); /***** Is this reasonable? *****/
+
+ if (db->last_lk_sequence < cs_addrs->ti->lock_sequence)
+ {
+ status = sys$qio(0, FILE_INFO(db->greg)->fab->fab$l_stv, IO$_READVBLK, &db->qio_iosb, ccp_writedb4a, db,
+ cs_addrs->lock_addrs[0], db->glob_sec->lock_space_size, LOCK_BLOCK(db->glob_sec) + 1, 0, 0, 0);
+ if (status == SS$_IVCHAN) /* database has been closed out, section deleted */
+ return;
+ if ((status & 1) == 0)
+ ccp_signal_cont(status); /***** Is this reasonable? *****/
+ db->last_lk_sequence = cs_addrs->ti->lock_sequence;
+ }
+ else
+ ccp_writedb5(db);
+
+ return;
+}
diff --git a/sr_vvms/ccp_writedb4a.c b/sr_vvms/ccp_writedb4a.c
new file mode 100644
index 0000000..9527a26
--- /dev/null
+++ b/sr_vvms/ccp_writedb4a.c
@@ -0,0 +1,39 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "ccp.h"
+#include <ssdef.h>
+
+
+/* AST routine entered on completion of sys$qio to read the lock block,
+ in ccp_writedb2, ccp_writedb3, or ccp_writedb4 */
+
+void ccp_writedb4a(ccp_db_header *db)
+{
+ assert(lib$ast_in_prog());
+
+ if (db->segment == NULL || db->segment->nl->ccp_state == CCST_CLOSED)
+ return;
+
+ if ((db->qio_iosb.cond & 1) == 0)
+ ccp_signal_cont(db->qio_iosb.cond); /***** Is this reasonable? *****/
+
+ ccp_writedb5(db);
+
+ return;
+}
diff --git a/sr_vvms/ccp_writedb5.c b/sr_vvms/ccp_writedb5.c
new file mode 100644
index 0000000..207ff49
--- /dev/null
+++ b/sr_vvms/ccp_writedb5.c
@@ -0,0 +1,26 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "ccp.h"
+#include "ccpact.h"
+
+void ccp_writedb5(ccp_db_header *db)
+{
+ ccp_action_record buff;
+
+ buff.action = CCTR_WRITEDB1;
+ buff.pid = 0;
+ buff.v.h = db;
+ ccp_act_request(&buff);
+ return;
+}
diff --git a/sr_vvms/ce_init.c b/sr_vvms/ce_init.c
new file mode 100644
index 0000000..04d22e1
--- /dev/null
+++ b/sr_vvms/ce_init.c
@@ -0,0 +1,56 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include <ssdef.h>
+#include <descrip.h>
+
+#include "mdef.h"
+#include "comp_esc.h"
+#include "io.h"
+#include "trans_log_name.h"
+
+
+GBLDEF bool ce_init_done = FALSE;
+GBLDEF struct ce_sentinel_desc *ce_def_list;
+
+
+int ce_init (void)
+{
+ $DESCRIPTOR(filename,"GTM$COMPILER_ESCAPE");
+ $DESCRIPTOR(entrypoint,"GTM$COMPILER_ESCAPE");
+
+ int4 (*compiler_escape_init)();
+ mstr filename_logical, filename_translation;
+ char buffer[256];
+
+ uint4 status;
+
+
+ status = SS$_NORMAL;
+ if (!ce_init_done)
+ {
+ ce_def_list = NULL;
+
+ /* Check for existence of logical name; if present, invoke corresponding entry point. */
+ filename_logical.addr = filename.dsc$a_pointer;
+ filename_logical.len = filename.dsc$w_length;
+
+ if (trans_log_name(&filename_logical, &filename_translation, buffer) == SS$_NORMAL)
+ {
+ if ((status = lib$find_image_symbol(&filename, &entrypoint, &compiler_escape_init)) == SS$_NORMAL)
+ compiler_escape_init();
+ }
+
+ ce_init_done = TRUE;
+ }
+
+ return status;
+}
diff --git a/sr_vvms/ce_substitute.c b/sr_vvms/ce_substitute.c
new file mode 100644
index 0000000..d7acc19
--- /dev/null
+++ b/sr_vvms/ce_substitute.c
@@ -0,0 +1,86 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <ssdef.h>
+#include <descrip.h>
+
+#include "compiler.h"
+#include "comp_esc.h"
+
+GBLREF unsigned char *source_buffer;
+GBLREF boolean_t run_time;
+GBLREF struct ce_sentinel_desc *ce_def_list;
+
+error_def(ERR_CEUSRERROR);
+error_def(ERR_CEBIGSKIP);
+error_def(ERR_CETOOLONG);
+
+void ce_substitute (struct ce_sentinel_desc *shp, int4 source_column, int4 *skip_count)
+{
+ unsigned char *cp, sub_buffer[MAX_SRCLINE];
+ int4 source_length, tail_length;
+ int4 lcl_src_col, sav_last_src_col, status;
+ boolean_t run_or_compile;
+ struct dsc$descriptor_s buffer, substitution;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ for (source_length = source_column;
+ source_buffer[source_length-1] != '\0' && source_length <= MAX_SRCLINE;
+ source_length++)
+ ;
+ buffer.dsc$a_pointer = source_buffer;
+ buffer.dsc$w_length = source_length;
+ substitution.dsc$a_pointer = sub_buffer;
+ substitution.dsc$w_length = MAX_SRCLINE;
+ /* Copy important values to locals to prevent inadvertent user modification. */
+ run_or_compile = run_time;
+ lcl_src_col = source_column;
+ status = shp->user_routine(&buffer, &lcl_src_col, run_or_compile, &substitution, skip_count);
+ if (status != SS$_NORMAL)
+ {
+ sav_last_src_col = TREF(last_source_column);
+ TREF(last_source_column) = source_column;
+ stx_error (ERR_CEUSRERROR, 1, status);
+ TREF(last_source_column) = sav_last_src_col;
+ return;
+ }
+ tail_length = source_length - (source_column + *skip_count) + 1;
+ if (0 > tail_length)
+ {
+ sav_last_src_col = TREF(last_source_column);
+ TREF(last_source_column) = source_column;
+ stx_error (ERR_CEBIGSKIP);
+ TREF(last_source_column) = sav_last_src_col;
+ return;
+ }
+ source_length = (source_column - 1) + substitution.dsc$w_length + tail_length;
+ if (source_length > MAX_SRCLINE - 2)
+ {
+ sav_last_src_col = TREF(last_source_column);
+ TREF(last_source_column) = source_column;
+ stx_error (ERR_CETOOLONG);
+ TREF(last_source_column) = sav_last_src_col;
+ return;
+ }
+ if (0 < tail_length)
+ {
+ memcpy (&source_buffer[(source_column-1) + substitution.dsc$w_length],
+ &source_buffer[(source_column-1) + *skip_count],
+ tail_length);
+ }
+ if (0 < substitution.dsc$w_length)
+ memcpy (&source_buffer[source_column-1], substitution.dsc$a_pointer, substitution.dsc$w_length);
+ source_buffer[source_length] = source_buffer[source_length+1] = '\0';
+ return;
+}
diff --git a/sr_vvms/change_fhead_timer.c b/sr_vvms/change_fhead_timer.c
new file mode 100644
index 0000000..f931424
--- /dev/null
+++ b/sr_vvms/change_fhead_timer.c
@@ -0,0 +1,75 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <climsgdef.h>
+#include <descrip.h>
+#include <ssdef.h>
+
+#include "timers.h"
+
+void change_fhead_timer(char *timer_name, sm_int_ptr_t timer_address, int default_time, bool zero_is_ok)
+/* default_time is in milliseconds */
+{
+ uint4 old_value[2];
+ int i;
+ short len;
+ int4 status;
+ char *cp;
+ unsigned char time_buff[63];
+ struct dsc$descriptor_s dsc, timd;
+
+ error_def(ERR_TIMRBADVAL);
+
+ timd.dsc$b_dtype = DSC$K_DTYPE_T;
+ timd.dsc$b_class = DSC$K_CLASS_S;
+ timd.dsc$a_pointer = time_buff;
+ timd.dsc$w_length = SIZEOF(time_buff);
+ dsc.dsc$b_dtype = DSC$K_DTYPE_T;
+ dsc.dsc$b_class = DSC$K_CLASS_S;
+ dsc.dsc$a_pointer = timer_name;
+ for (i = 0 , cp = timer_name ; *cp && i < SIZEOF(time_buff) ; cp++, i++)
+ ;
+ dsc.dsc$w_length = i;
+ status = cli$present(&dsc);
+ if (CLI$_NEGATED == status)
+ {
+ if (TRUE == zero_is_ok)
+ timer_address[0] = timer_address[1] = 0;
+ else
+ {
+ timer_address[0] = default_time * TIMER_SCALE;
+ timer_address[1] = -1;
+ }
+ } else if (CLI$_PRESENT == status)
+ {
+ status = cli$get_value(&dsc, &timd, &len);
+ if (SS$_NORMAL == status)
+ {
+ old_value[0] = timer_address[0];
+ old_value[1] = timer_address[1];
+ timd.dsc$w_length = len;
+ status = sys$bintim(&timd, timer_address);
+ if ((!zero_is_ok && timer_address[0] == 0) || timer_address[1] < -9 ||
+ (timer_address[1] == -9 && timer_address[0] < -1640161632)) /* < 1 hour */
+ {
+ timer_address[0] = old_value[0];
+ timer_address[1] = old_value[1];
+ rts_error(VARLSTCNT(1) ERR_TIMRBADVAL);
+ }
+ assert(status & 1);
+ }
+ else
+ rts_error(VARLSTCNT(1) ERR_TIMRBADVAL);
+ }
+ return;
+}
diff --git a/sr_vvms/cli.c b/sr_vvms/cli.c
new file mode 100644
index 0000000..6936c82
--- /dev/null
+++ b/sr_vvms/cli.c
@@ -0,0 +1,370 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2005 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <climsgdef.h>
+#include <descrip.h>
+#include "gtm_limits.h"
+
+#include "gtm_ctype.h"
+#include "gtm_stdlib.h"
+#include "gtm_string.h"
+
+#include "cli.h"
+#include "gtmmsg.h"
+#include "error.h"
+
+extern int4 CLI$GET_VALUE();
+extern int CLI$PRESENT();
+
+error_def(ERR_STRNOTVALID);
+
+CONDITION_HANDLER(clich)
+{
+ START_CH;
+ CONTINUE;
+}
+
+boolean_t cli_get_hex(char *e, uint4 *dst)
+{
+ uint4 status;
+ unsigned short retlength = 0;
+ char buf[MAX_LINE], *ptr;
+
+ $DESCRIPTOR(d_buf, buf);
+ $DESCRIPTOR(d_ent, " ");
+
+ d_ent.dsc$a_pointer = e;
+ d_ent.dsc$w_length = strlen(e);
+ assert(d_ent.dsc$w_length > 0);
+ if (CLI$_PRESENT == CLI$PRESENT(&d_ent))
+ {
+ if (SS$_NORMAL == (status = CLI$GET_VALUE(&d_ent, &d_buf, &retlength)))
+ {
+ ptr = &buf[0];
+ buf[retlength] = 0; /* for cli_str_to_hex */
+ if (!cli_str_to_hex(ptr, dst))
+ {
+ gtm_putmsg(VARLSTCNT(4) ERR_STRNOTVALID, 2, retlength, buf);
+ return (FALSE);
+ }
+ return (TRUE);
+ } else
+ gtm_putmsg(VARLSTCNT(5) ERR_STRNOTVALID, 2, retlength, buf, status);
+ }
+ return (FALSE);
+}
+
+boolean_t cli_get_hex64(char *e, gtm_uint64_t *dst)
+{
+ uint4 status;
+ unsigned short retlength = 0;
+ char buf[MAX_LINE], *ptr;
+
+ $DESCRIPTOR(d_buf, buf);
+ $DESCRIPTOR(d_ent, " ");
+
+ d_ent.dsc$a_pointer = e;
+ d_ent.dsc$w_length = strlen(e);
+ assert(d_ent.dsc$w_length > 0);
+ if (CLI$_PRESENT == CLI$PRESENT(&d_ent))
+ {
+ if (SS$_NORMAL == (status = CLI$GET_VALUE(&d_ent, &d_buf, &retlength)))
+ {
+ ptr = &buf[0];
+ buf[retlength] = 0; /* for cli_str_to_hex64 */
+ if (!cli_str_to_hex64(ptr, dst))
+ {
+ gtm_putmsg(VARLSTCNT(4) ERR_STRNOTVALID, 2, retlength, buf);
+ return (FALSE);
+ }
+ return (TRUE);
+ } else
+ gtm_putmsg(VARLSTCNT(5) ERR_STRNOTVALID, 2, retlength, buf, status);
+ }
+ return (FALSE);
+}
+
+boolean_t cli_get_uint64(char *e, gtm_uint64_t *dst)
+{
+ uint4 status;
+ unsigned short retlength = 0;
+ char buf[MAX_LINE], *ptr;
+
+ $DESCRIPTOR(d_buf, buf);
+ $DESCRIPTOR(d_ent, " ");
+
+ d_ent.dsc$a_pointer = e;
+ d_ent.dsc$w_length = strlen(e);
+ assert(d_ent.dsc$w_length > 0);
+ if (CLI$_PRESENT == CLI$PRESENT(&d_ent))
+ {
+ if (SS$_NORMAL == (status = CLI$GET_VALUE(&d_ent, &d_buf, &retlength)))
+ {
+ ptr = &buf[0];
+ buf[retlength] = 0; /* for cli_str_to_uint64 */
+ if (!cli_str_to_uint64(ptr, dst))
+ {
+ gtm_putmsg(VARLSTCNT(4) ERR_STRNOTVALID, 2, retlength, buf);
+ return (FALSE);
+ }
+ return (TRUE);
+ } else
+ gtm_putmsg(VARLSTCNT(5) ERR_STRNOTVALID, 2, retlength, buf, status);
+ }
+ return (FALSE);
+}
+
+boolean_t cli_get_int(char *e, int *dst) /* entity, destination */
+{
+ uint4 status;
+ unsigned short retlength = 0;
+ unsigned char buf[MAX_LINE], *bufpt;
+
+ $DESCRIPTOR(d_buf, buf);
+ $DESCRIPTOR(d_ent, " ");
+
+ d_ent.dsc$a_pointer = e;
+ d_ent.dsc$w_length = strlen(e);
+ assert(d_ent.dsc$w_length > 0);
+
+ if (CLI$_PRESENT == CLI$PRESENT(&d_ent))
+ {
+ if (SS$_NORMAL == (status = CLI$GET_VALUE(&d_ent, &d_buf, &retlength)))
+ {
+ bufpt = &buf[0];
+ buf[retlength] = 0; /* for cli_str_to_int */
+ if (!cli_str_to_int(bufpt, dst))
+ {
+ gtm_putmsg(VARLSTCNT(4) ERR_STRNOTVALID, 2, retlength, buf);
+ return FALSE;
+ } else
+ return TRUE;
+ } else
+ gtm_putmsg(VARLSTCNT(5) ERR_STRNOTVALID, 2, retlength, buf, status);
+ }
+ return FALSE;
+}
+
+boolean_t cli_get_int64(char *e, gtm_int64_t *dst) /* entity, destination */
+{
+ uint4 status;
+ unsigned short retlength = 0;
+ unsigned char buf[MAX_LINE], *bufpt;
+
+ $DESCRIPTOR(d_buf, buf);
+ $DESCRIPTOR(d_ent, " ");
+
+ d_ent.dsc$a_pointer = e;
+ d_ent.dsc$w_length = strlen(e);
+ assert(d_ent.dsc$w_length > 0);
+
+ if (CLI$_PRESENT == CLI$PRESENT(&d_ent))
+ {
+ if (SS$_NORMAL == (status = CLI$GET_VALUE(&d_ent, &d_buf, &retlength)))
+ {
+ bufpt = &buf[0];
+ buf[retlength] = 0; /* for cli_str_to_int64 */
+ if (!cli_str_to_int64(bufpt, dst))
+ {
+ gtm_putmsg(VARLSTCNT(4) ERR_STRNOTVALID, 2, retlength, buf);
+ return FALSE;
+ } else
+ return TRUE;
+ } else
+ gtm_putmsg(VARLSTCNT(5) ERR_STRNOTVALID, 2, retlength, buf, status);
+ }
+ return FALSE;
+}
+
+boolean_t cli_get_num(char *e, int *dst) /* entity, destination */
+{
+ uint4 status;
+ unsigned short retlength = 0;
+ unsigned char buf[MAX_LINE], *bufpt;
+
+ $DESCRIPTOR(d_buf, buf);
+ $DESCRIPTOR(d_ent, " ");
+
+ d_ent.dsc$a_pointer = e;
+ d_ent.dsc$w_length = strlen(e);
+ assert(d_ent.dsc$w_length > 0);
+
+ if (CLI$_PRESENT == CLI$PRESENT(&d_ent))
+ {
+ if (SS$_NORMAL == (status = CLI$GET_VALUE(&d_ent, &d_buf, &retlength)))
+ {
+ bufpt = &buf[0];
+ buf[retlength] = 0; /* for cli_str_to_num */
+ if (!cli_str_to_num(bufpt, dst))
+ {
+ gtm_putmsg(VARLSTCNT(4) ERR_STRNOTVALID, 2, retlength, buf);
+ return FALSE;
+ } else
+ return TRUE;
+ } else
+ gtm_putmsg(VARLSTCNT(5) ERR_STRNOTVALID, 2, retlength, buf, status);
+ }
+ return FALSE;
+}
+
+boolean_t cli_get_num64(char *e, gtm_int64_t *dst) /* entity, destination */
+{
+ uint4 status;
+ unsigned short retlength = 0;
+ unsigned char buf[MAX_LINE], *bufpt;
+
+ $DESCRIPTOR(d_buf, buf);
+ $DESCRIPTOR(d_ent, " ");
+
+ d_ent.dsc$a_pointer = e;
+ d_ent.dsc$w_length = strlen(e);
+ assert(d_ent.dsc$w_length > 0);
+
+ if (CLI$_PRESENT == CLI$PRESENT(&d_ent))
+ {
+ if (SS$_NORMAL == (status = CLI$GET_VALUE(&d_ent, &d_buf, &retlength)))
+ {
+ bufpt = &buf[0];
+ buf[retlength] = 0; /* for cli_str_to_num64 */
+ if (!cli_str_to_num64(bufpt, dst))
+ {
+ gtm_putmsg(VARLSTCNT(4) ERR_STRNOTVALID, 2, retlength, buf);
+ return FALSE;
+ } else
+ return TRUE;
+ } else
+ gtm_putmsg(VARLSTCNT(5) ERR_STRNOTVALID, 2, retlength, buf, status);
+ }
+ return FALSE;
+}
+
+boolean_t cli_get_str(char *e, char *dst, unsigned short *ml) /* entity, destination, max length */
+{
+ char buf[MAX_LINE];
+ $DESCRIPTOR(d_buf, buf);
+ $DESCRIPTOR(d_ent, " ");
+ unsigned short l=0;
+ int4 status;
+
+ assert(*ml > 0);
+ d_ent.dsc$a_pointer = e;
+ d_ent.dsc$w_length = strlen(e);
+ assert(d_ent.dsc$w_length > 0);
+
+ if (((CLI$_PRESENT == (status = CLI$PRESENT(&d_ent))) || (CLI$_LOCPRES == status))
+ && (CLI$_ABSENT != CLI$GET_VALUE(&d_ent, &d_buf, &l)))
+ {
+ if (l <= *ml)
+ {
+ memset(dst, 0, *ml);
+ memcpy(dst, buf, l);
+ *ml = l;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+boolean_t cli_negated(char *e) /* entity */
+{
+ $DESCRIPTOR(d_ent, " ");
+ int4 status;
+
+ d_ent.dsc$a_pointer = e;
+ d_ent.dsc$w_length = strlen(e);
+ assert(d_ent.dsc$w_length > 0);
+ status =CLI$PRESENT(&d_ent);
+ if ((CLI$_NEGATED == status) || (CLI$_LOCNEG == status))
+ return TRUE;
+ else
+ return FALSE;
+}
+
+int cli_present(char *e) /* entity */
+{
+ int4 status;
+ $DESCRIPTOR(d_ent, " ");
+
+ d_ent.dsc$a_pointer = e;
+ d_ent.dsc$w_length = strlen(e);
+ assert(d_ent.dsc$w_length > 0);
+ status = CLI$PRESENT(&d_ent);
+ if ((CLI$_PRESENT == status) || (CLI$_LOCPRES == status))
+ return CLI_PRESENT;
+ else if ((CLI$_NEGATED == status) || (CLI$_LOCNEG == status))
+ return CLI_NEGATED;
+ else if (CLI$_ABSENT == status)
+ return CLI_ABSENT;
+ else
+ return status;
+}
+
+int4 cli_t_f_n(char *e) /* entity */
+{ /* this function retrieves a CLI value of type TRUE_FALSE_NEITHER (for example, as seen in PATCH_CMD.CLD).
+ * It assumes the presence of the qualifier in question.
+ */
+ uint4 status;
+ char buf[MAX_LINE];
+ unsigned short retlength = 0;
+ $DESCRIPTOR(d_buf, buf);
+ $DESCRIPTOR(d_ent, " ");
+
+ d_ent.dsc$a_pointer = e;
+ d_ent.dsc$w_length = strlen(e);
+ assert(d_ent.dsc$w_length > 0);
+
+ if (SS$_NORMAL == (status = CLI$GET_VALUE(&d_ent, &d_buf, &retlength)))
+ {
+ if ('T' == buf[0])
+ return (1);
+ else if ('F' == buf[0])
+ return (0);
+ else
+ return (-1);
+ } else
+ {
+ gtm_putmsg(VARLSTCNT(5) ERR_STRNOTVALID, 2, retlength, buf, status);
+ return (-1);
+ }
+}
+
+int4 cli_n_a_e(char *e) /* entity */
+{ /* this function retrieves a CLI value of type TRUE_ALWAYS_FALSE_NEVER_EXISTING .
+ * It assumes the presence of the qualifier in question.
+ */
+ uint4 status;
+ char buf[MAX_LINE];
+ unsigned short retlength = 0;
+ $DESCRIPTOR(d_buf, buf);
+ $DESCRIPTOR(d_ent, " ");
+
+ d_ent.dsc$a_pointer = e;
+ d_ent.dsc$w_length = strlen(e);
+ assert(d_ent.dsc$w_length > 0);
+
+ if (SS$_NORMAL == (status = CLI$GET_VALUE(&d_ent, &d_buf, &retlength)))
+ {
+ if ('F' == buf[0] || 'N' == buf[0])
+ return (0);
+ else if ('T' == buf[0] || 'A' == buf[0])
+ return (1);
+ else if ('E' == buf[0])
+ return (2);
+ else
+ return (-1);
+ } else
+ {
+ gtm_putmsg(VARLSTCNT(5) ERR_STRNOTVALID, 2, retlength, buf, status);
+ return (-1);
+ }
+}
diff --git a/sr_vvms/cli.h b/sr_vvms/cli.h
new file mode 100644
index 0000000..5c0e332
--- /dev/null
+++ b/sr_vvms/cli.h
@@ -0,0 +1,27 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2003 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef CLI$_NEGATED
+#include <climsgdef.h>
+#endif
+
+#define CLI_NEGATED CLI$_NEGATED
+#define CLI_PRESENT CLI$_PRESENT
+#define CLI_ABSENT CLI$_ABSENT
+#define MAX_LINE 512
+#define CLI_GET_STR_ALL cli_get_str_all_piece
+
+/* include platform independent prototypes */
+
+#include "cliif.h"
+
+int cli_get_str_all_piece(unsigned char *cli_text, unsigned char *all_piece_buff,
+ int *all_piece_buff_len); /***type int added***/
diff --git a/sr_vvms/cli_get_str_all_piece.c b/sr_vvms/cli_get_str_all_piece.c
new file mode 100644
index 0000000..ec02825
--- /dev/null
+++ b/sr_vvms/cli_get_str_all_piece.c
@@ -0,0 +1,61 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "error.h"
+#include <climsgdef.h>
+#include <descrip.h>
+#include "gtm_string.h"
+#include "cli.h"
+
+extern int4 CLI$GET_VALUE();
+extern int CLI$PRESENT();
+/* This routine is written as a parallel module of UNIX cli_get_str(),
+ which always returns the concatenated string.
+ cli_get_str() of VVMS returns one piece at a time.
+ Note: cli_text must be a null terminated string below */
+cli_get_str_all_piece(unsigned char *cli_text, unsigned char *all_piece_buff, int *all_piece_buff_len)
+{
+ unsigned char map_pool[256], *ptr;
+ int status, s_len;
+ unsigned short n_len;
+
+ struct dsc$descriptor_s desc_cli_str;
+ $DESCRIPTOR(buffer, map_pool);
+ desc_cli_str.dsc$a_pointer = cli_text;
+ desc_cli_str.dsc$w_length = strlen(cli_text);
+ desc_cli_str.dsc$b_dtype = DSC$K_DTYPE_T;
+ desc_cli_str.dsc$b_class = DSC$K_CLASS_S;
+ *all_piece_buff_len = s_len = 0;
+ for (; ;)
+ {
+ status = CLI$GET_VALUE(&desc_cli_str, &buffer, &n_len);
+ if (SS$_NORMAL == status)
+ {
+ memcpy(all_piece_buff + s_len, buffer.dsc$a_pointer, n_len);
+ s_len += n_len;
+ all_piece_buff[s_len] = 0;
+ break;
+ }
+ if (CLI$_ABSENT == status)
+ return FALSE;
+ assert(CLI$_COMMA == status);
+ if (CLI$_COMMA == status)
+ {
+ memcpy(all_piece_buff + s_len, buffer.dsc$a_pointer, n_len);
+ s_len += n_len;
+ all_piece_buff[s_len]=',';
+ s_len++;
+ }
+ }
+ *all_piece_buff_len = s_len;
+ return TRUE;
+}
diff --git a/sr_vvms/cmicom.com b/sr_vvms/cmicom.com
new file mode 100644
index 0000000..688b7e6
--- /dev/null
+++ b/sr_vvms/cmicom.com
@@ -0,0 +1,73 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2003 Sanchez Computer Associates, Inc. !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$! cmicom - compile/assemble cmi modules and place them in cmi.olb
+$! p1 = version number
+$! p2 = library (p, d, or b)
+$! p3 = target device and directory
+$!
+$ if p1 .eqs. ""
+$ then
+$ write sys$output "Must supply a version"
+$ exit
+$ endif
+$ compopt=f$locate(p2,"PBD")
+$ if (f$length(p2) .ne. 1) .or. (compopt .eq. 3)
+$ then
+$ write sys$output "Library must be P, B or D"
+$ exit
+$ endif
+$ if p3 .eqs. ""
+$ then
+$ write sys$output "Must specify a target directory for the .olb file"
+$ exit
+$ endif
+$!
+$ alpha = (f$getsyi("arch_name") .eqs. "Alpha")
+$ decc = alpha .or. (f$integer(f$extract(1,2,p1)) .ge. 32)
+$ macopt = f$element(alpha,",",",/migration/flag=(hints)") + "/nolist" + f$element(compopt,",",",,/debug")
+$! 2000/2/3 smw optimized cmi loops so turn off for now - 2000/2/8 fixed DEC C 6.2 ECO 2
+$ compopt = "/include=gtm$src:/nolist" + f$element(compopt,",","/optimize,/optimize/define=debug,/nooptimize/define=debug/debug")
+$! compopt = "/include=gtm$src:/nolist" + f$element(compopt,",","/nooptimize,/nooptimize/define=debug,/nooptimize/define=debug/debug")
+$ compopt = "/standard=vaxc/assume=nowritable_string_literals" + compopt
+$ ctlb :=
+$ if alpha then ctlb = "+" + f$search("sys$library:sys$lib_c.tlb") + "/libr"
+$ @gtm$tools:setactive_silent 'p1' 'p2'
+$ calldir = f$environment("default")
+$ set def 'p3'
+$ x := message/nolist gtm$vrt:[cmi]cmierrors
+$ if f$environment("VERIFY_PROCEDURE") then write sys$output x
+$ x
+$ x = "macro" + macopt + " gtm$vrt:[cmi]cmj_util.mar+" + f$search("gtm$src:maclib.mlb") + "/lib"
+$ if f$environment("VERIFY_PROCEDURE") then write sys$output x
+$ x
+$ if .not. alpha
+$ then
+$ x := macro'macopt' gtm$vrt:[cmi]cmivector.mar
+$ if f$environment("VERIFY_PROCEDURE") then write sys$output x
+$ x
+$ endif
+$cloop:
+$ fil = f$search("gtm$vrt:[cmi]*.c")
+$ if fil .nes. ""
+$ then
+$ x = "cc"+compopt+" "+fil+ctlb
+$ if f$environment("VERIFY_PROCEDURE") then write sys$output x
+$ x
+$ goto cloop
+$ endif
+$ gtm_library/create cmi
+$ gtm_library cmi *
+$ gtm_delete *.obj;*
+$ gtm_purge cmi.olb
+$ set def 'calldir'
+$!
+$ exit
diff --git a/sr_vvms/cmidefsp.h b/sr_vvms/cmidefsp.h
new file mode 100644
index 0000000..31b58b0
--- /dev/null
+++ b/sr_vvms/cmidefsp.h
@@ -0,0 +1,168 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2005 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/*** The following typedef's will have to be changed if this is ported to UNIX (for DUX) at least */
+
+#ifndef CMIDEFSP_H_INCLUDED
+#define CMIDEFSP_H_INCLUDED
+
+#ifndef MDEFSP_included
+typedef long int4; /* 4-byte signed integer */
+typedef unsigned long uint4; /* 4 byte unsigned integer */
+#endif
+
+#define ALIGN_QUAD _align(quadword)
+
+#define CMM_MIN_PEER_LEVEL "010"
+
+enum nsn_type
+{ connect_op, discon_op, abort_op, exit_op, pathlost, protocol,
+ thirdparty, timeout, netshut, intmsg, reject, confirm,
+ nsn_type_count
+}; /* connect, discon, abort, exit were renamed connect_op, discon_op, abort_op, exit_op respectively to prevent name conflicts
+ * with system library routines */
+
+typedef struct
+{
+ unsigned short msg;
+ unsigned short unit;
+ unsigned char netnum;
+ unsigned char netnam[3];
+ unsigned char len;
+ unsigned char text[3];
+} cm_mbx;
+
+typedef struct
+{
+ unsigned short status;
+ unsigned short xfer_count;
+ uint4 dev_info;
+} qio_iosb;
+
+typedef struct
+{
+ unsigned short dsc$w_length;
+ unsigned char dsc$b_dtype;
+ unsigned char dsc$b_class;
+ char *dsc$a_pointer;
+} cmi_descriptor;
+
+typedef struct
+{
+ int4 fl;
+ int4 bl;
+} relque;
+
+struct NTD
+{
+ relque cqh;
+ qio_iosb mst;
+ cmi_descriptor mnm;
+ cmi_descriptor mbx;
+ unsigned short dch;
+ unsigned short mch;
+ int (*crq)();
+ void (*err)();
+ void (*sht)();
+ void (*dcn)();
+ void (*mbx_ast)();
+ bool (*acc)();
+ short unsigned stt[nsn_type_count];
+};
+
+typedef struct clb_stat_struct
+{
+ struct
+ {
+ uint4 msgs,errors,bytes,last_error;
+ } read,write;
+} clb_stat;
+
+struct CLB
+{
+ relque cqe;
+ cmi_descriptor nod;
+ cmi_descriptor tnd;
+ struct NTD *ntd;
+ unsigned short dch;
+ unsigned short mun;
+ uint4 usr;
+ void (*err)();
+ qio_iosb ios;
+ unsigned short cbl;
+ unsigned short mbl;
+ unsigned char *mbf;
+ void (*tra)();
+ unsigned char sta;
+ unsigned char unused1;
+ unsigned short tmo;
+ void (*ast)();
+ struct clb_stat_struct stt;
+};
+
+typedef struct CLB clb_struct;
+
+#include <ssdef.h>
+
+#define CMI_MUTEX_DECL long int was_setast
+#define CMI_MUTEX_BLOCK { \
+ was_setast = DISABLE_AST; /* save previous state */ \
+ assert(SS$_WASSET == was_setast); \
+ }
+#define CMI_MUTEX_RESTORE { \
+ if (SS$_WASSET == was_setast) /* don't enable if was disabled coming in */ \
+ ENABLE_AST; \
+ }
+
+#define ALIGN_QUAD _align(quadword)
+
+#define CM_URGDATA_OFFSET 0
+#define CM_URGDATA_LEN 6
+
+#define CMI_ERROR(s) (0 == ((s) & 1))
+#define CMI_CLB_IOSTATUS(c) ((c)->ios.status)
+#define CMI_CLB_ERROR(c) (CMI_ERROR(CMI_CLB_IOSTATUS(c)))
+#define CMI_MAKE_STATUS(s) (!CMI_ERROR(s) ? SS$_NORMAL : (s))
+
+typedef uint4 cmi_status_t;
+typedef uint4 cmi_reason_t;
+typedef int cmi_unit_t;
+
+#include <msgdef.h>
+
+#define CMI_REASON_INTMSG MSG$_INTMSG
+#define CMI_REASON_DISCON MSG$_DISCON
+#define CMI_REASON_ABORT MSG$_ABORT
+#define CMI_REASON_EXIT MSG$_EXIT
+#define CMI_REASON_PATHLOST MSG$_PATHLOST
+#define CMI_REASON_PROTOCOL MSG$_PROTOCOL
+#define CMI_REASON_THIRDPARTY MSG$_THIRDPARTY
+#define CMI_REASON_TIMEOUT MSG$_TIMEOUT
+#define CMI_REASON_NETSHUT MSG$_NETSHUT
+#define CMI_REASON_REJECT MSG$_REJECT
+#define CMI_REASON_CONFIRM MSG$_CONFIRM
+
+#define CMI_IDLE(milliseconds) hiber_start_wait_any((milliseconds))
+
+uint4 cmi_init(cmi_descriptor *tnd, unsigned char tnr, void (*err)(), void (*crq)(), bool (*acc)());
+
+#define cmi_realloc_mbf(clb, newsize) \
+ { \
+ if (clb->mbf) \
+ { \
+ clb->mbl = 0; \
+ free(clb->mbf); \
+ } \
+ clb->mbf = (unsigned char *)malloc(newsize); \
+ clb->mbl = newsize; \
+ }
+
+#endif /* CMIDEFSP_H_INCLUDED */
diff --git a/sr_vvms/cms_load.com b/sr_vvms/cms_load.com
new file mode 100644
index 0000000..451ece0
--- /dev/null
+++ b/sr_vvms/cms_load.com
@@ -0,0 +1,105 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2003 Sanchez Computer Associates, Inc. !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$! This DCL command file is a front end to launch a platform_CMS_LOAD, which in turn fetches
+$! files from CMS libraries and puts them into the appropriate source directory(ies) for the
+$! specified platform.
+$!
+$! p1 - target platform or CMS library specification from which the target can be determined
+$! p2 - "to version", version of GT.M to populate on target platform (including punctuation, e.g., class name)
+$! p3 - library's password (for Unix platforms)
+$! p4 - "from version", version of GT.M to fetch (defaults to p2)
+$!
+$ interact = (F$MODE() .eqs. "INTERACTIVE")
+$!
+$askplat:
+$!
+$! Determine platform.
+$! Since VMS DCL doesn't have an "elseif" command, the following are
+$! all single "if"'s to improve readability and maintainability by
+$! keeping down the number of nesting levels.
+$!
+$! check by specific platform name
+$!
+$ platform :=
+$ if ((p1 .eqs. "ALPHA2") .or. (p1 .eqs. "WIGLAF") .or (p1 .eqs. "ASGARD"))
+$ then
+$ cms_lib = "S_AVMS"
+$ dl_type = "VMS"
+$ platform = "''p1'"
+$ endif
+$!
+$ if ( p1 .eqs. "CETUS" )
+$ then
+$ cms_lib = "S_VMS"
+$ dl_type = "VMS"
+$ platform = "CETUS"
+$ endif
+$!
+$ if ( platform .eqs. "" )
+$ then
+$ if ( interact )
+$ then
+$ inquire p1 "Enter valid CMS library or target platform name"
+$ if ( p1 .eqs. "" )
+$ then
+$ write sys$output "%CMS_LOAD-E-BADPLATFORM, Invalid platform or CMS library specified"
+$ exit
+$ endif
+$ goto askplat ! verify platform or CMS library specification
+$ else
+$ write sys$output "%CMS_LOAD-E-BADPLATFORM, Invalid platform or CMS library specified"
+$ exit
+$ endif
+$ endif
+$!
+$! Verify CMS library.
+$ cms set library 'cms_lib'
+$ if ( $severity .ne. 1 )
+$ then
+$ write sys$output "%CMS_LOAD-E-BADCMSLIB, Invalid platform or CMS library specified for first argument"
+$ exit
+$ endif
+$!
+$! If we get to this point, we should have a valid platform and CMS library; now verify the "to" version.
+$! This is the version on the target platform to which the sources will be copied.
+$!
+$ to_version = p2
+$askver:
+$ if ( to_version .eqs. "" )
+$ then
+$ if ( interact )
+$ then
+$ write sys$output "%CMS_LOAD-I-NOTOVERSION, You have specified a null ""to version""; the default is V9.9-0"
+$ inquire to_version "Enter ""to version"" (with all punctuation) or enter <CR> to retain V9.9-0"
+$ endif
+$ if ( to_version .eqs. "" )
+$ then
+$ write sys$output "%CMS_LOAD-I-DEFAULTVER, Defaulting ""to version"" to V9.9-0"
+$ to_version = "V9.9-0"
+$ endif
+$ endif
+$!
+$ from_version == p4
+$!
+$ cmsver = to_version - "." - "-"
+$ toolsdir = "user:[library.''cmsver'.tools]"
+$ gtmverdir = "user:[library.''cmsver']"
+$ @'toolsdir'cms_load_verify_from_to_version 'to_version' 'from_version'
+$ if ( $status .ne. 1 )
+$ then
+$ exit
+$ endif
+$!
+$ when = f$trnlnm("test_run_time")
+$ if when .nes. "" then $ when = "/after=""" + when + """"
+$ submit/noprint/notify/queue='dl_type'_download_hiq/log='gtmverdir''platform'_cms_load.log 'toolsdir''dl_type'_cms_load.com -
+ 'when' /parameters=("''to_version'","''platform'","''cms_lib'","''p3'","''from_version'")
diff --git a/sr_vvms/cms_load_verify_from_to_version.com b/sr_vvms/cms_load_verify_from_to_version.com
new file mode 100644
index 0000000..790e55b
--- /dev/null
+++ b/sr_vvms/cms_load_verify_from_to_version.com
@@ -0,0 +1,99 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2003 Sanchez Computer Associates, Inc. !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$! This DCL command file verifies the validity of the "from version" and
+$! "to version" for a dowload from CMS to a target platform. The rules
+$! are:
+$!
+$! if "to version" is "V9.x-x" and not "V9.9-0", then "from version"
+$! can be any valid version ("V9.9-0" must always be the most
+$! recent on the main line of descent),
+$! otherwise, "from version" must match "to version"
+$!
+$! if "from version" is not specified and there is a choice, this
+$! script, if invoked interactively, will prompt for it. The default
+$! is to set "from version" to "to version".
+$!
+$!
+$! Input:
+$!
+$! p1 - "to version", the version of GT.M to populate on the target platform
+$! p2 - "from version", the version of GT.M to fetch from CMS
+$!
+$!
+$! Output:
+$!
+$! from_version - set to version of GT.M to fetch from CMS, compatible
+$! with requested "to version"
+$!
+$!
+$! Error:
+$!
+$! exit
+$!
+$ interact = (F$MODE() .eqs. "INTERACTIVE")
+$! set verify
+$!
+$! Determine whether the user wishes to fetch a different version (the "from version") that that being populated.
+$! This is only legal when the "to version" is a V9.9-x version other than V9.9-0 (which must always be the most
+$! recent on the main line of descent).
+$!
+$!
+$ to_version = p1
+$ from_version == p2
+$!
+$ if ( from_version .nes. "" .and. from_version .nes. to_version )
+$ then
+$ if ( f$extract(0,3,to_version) .nes. "V9." .and. f$extract(0,6,from_version) .nes. "NEXT32" )
+$ then
+$ write sys$output "%CMS_LOAD-I-MISMATCH, You cannot overwrite ''to_version' with any other version"
+$ exit 9
+$ else
+$ if ( to_version .eqs. "V9.9-0" )
+$ then
+$ write sys$output "%CMS_LOAD-I-ILLDEVELOP, V9.9-0 must always be the most recent version the main line of descent"
+$ exit 9
+$ endif
+$ endif
+$ endif
+$!
+$!
+$! If user didn't specify a different "from version", determine whether it's allowed;
+$! if so, and this is an interactive invocation, prompt the user for a "from version".
+$!
+$ if ( from_version .eqs. "" )
+$ then
+$ if ( f$extract(0,3,to_version) .nes. "V9." .or. to_version .eqs. "V9.9-0" )
+$ then
+$ from_version == to_version ! no comment needed about defaulting; there's no choice
+$ else
+$ if ( interact )
+$ then
+$ write sys$output "%CMS_LOAD-I-NOFROMVERSION, You have specified a null ""from version""; the default is ",to_version
+$ inquire spec_version "Enter ""from version"" (with all punctuation) or enter <CR> to retain ''from_version'"
+$ from_version == spec_version
+$ endif
+$ if ( from_version .eqs. "" )
+$ then
+$ write sys$output "%CMS_LOAD-I-DEFAULTVER, Defaulting ""from version"" to ",to_version
+$ from_version == to_version
+$ endif
+$ endif
+$ endif
+$!
+$ if ( F$EXTRACT(0,3,from_version) .eqs. "V9." )
+$ then
+$ write sys$output ""
+$ write sys$output "You have selected ",from_version," which contains the most recent versions in the main line of descent"
+$ write sys$output ""
+$ endif
+$!
+$ exit 1
diff --git a/sr_vvms/comall.m b/sr_vvms/comall.m
new file mode 100644
index 0000000..ab371fa
--- /dev/null
+++ b/sr_vvms/comall.m
@@ -0,0 +1,259 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ;
+; Copyright 2001, 2013 Fidelity Information Services, Inc ;
+; ;
+; This source code contains the intellectual property ;
+; of its copyright holder(s), and is made available ;
+; under a license. If you do not know the terms of ;
+; the license, please stop and do not read further. ;
+; ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+main ; by default go to prompt
+prompt ;
+ s lower="abcdefghijklmnopqrstuvwxyz",upper="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ For Read "V[AX] or A[XP]? ",vaxoraxp,! Do Quit:$Data(vaxoraxp)
+ . Set vaxoraxp=$Translate($Extract(vaxoraxp,1),lower,upper)
+ . If vaxoraxp="A" Set vaxoraxp="AXP"
+ . Else If vaxoraxp="V" Set vaxoraxp="VAX"
+ . Else Write " Should be VAX or AXP",! Kill vaxoraxp
+ If vaxoraxp="AXP" Do
+ . Set vaxc=0
+ . For i=0:1 Set x=$ztrnlnm("gtm$libsrc",,i) Quit:x="" Do
+ . . If x="T_VMS" Write "GTM$LIBSRC contains VAX directory for AXP platform, aborting list generation",! Halt
+ Else Do
+ . For i=0:1 Set x=$ztrnlnm("gtm$libsrc",,i) Quit:x="" Do
+ . . If x="T_AVMS" Write "GTM$LIBSRC contains AXP directory for VAX platform, aborting list generation",! Halt
+ . For Read "D[EC C] or V[AX C]? ",vaxc,! Do Quit:$Data(vaxc)
+ . . Set vaxc=$Translate($Extract(vaxc,1),lower,upper)
+ . . If vaxc="V" Set vaxc=1
+ . . Else If vaxc="D" Set vaxc=0
+ . . Else Write " Should be DECC or VAXC",! Kill vaxc
+ For Read "F[ull] or I[ncremental] Version? ",efori,! Do Quit:$d(efori)
+ . Set efori=$Translate($Extract(efori,1),lower,upper)
+ . If efori="F" Set efori=1
+ . Else If efori="I" Set efori=0
+ . Else Write " Should be F or I",! Kill efori
+ For Read "multiple compilations per line? [Y] ",mcpl,! Do Quit:$d(mcpl)
+ . Set mcpl=$tr($e(mcpl,1),lower,upper)
+ . If mcpl="Y"!'$l(mcpl) Set mcpl=1
+ . Else If mcpl="N" Set mcpl=0
+ . Else Write " Should be Y or N",! Kill mcpl
+ For Write "VMS version: [",$Select(vaxoraxp="AXP":"V7.2",1:"V7.2") Read "] ",vmsver,! Do Quit:$d(vmsver)
+ . If vmsver="" Set vmsver=$Select(vaxoraxp="AXP":"V72",1:"V72") Quit
+ . Set vmsver=$TRanslate(vmsver,lower_".",upper)
+ . If vmsver="V72" Quit
+ . If vaxoraxp="AXP",vmsver="V71"!(vmsver="V62")!(vmsver="V73") Quit
+ . If vaxoraxp="VAX",vmsver="V71"!(vmsver="V61")!(vmsver="V55") Quit
+ . Else Write " Should be V7.2 or ",$Select(vaxoraxp="AXP":"V7.3, V7.1 or V6.2",1:"V7.1, V6.1 or V5.5"),! Kill vmsver
+ do common
+ quit
+noprompt; with no input reads for the alpha
+ s lower="abcdefghijklmnopqrstuvwxyz",upper="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ set vaxoraxp="AXP"
+ set efori=1
+ set mcpl=1
+ set vmsver="V72"
+ set vaxc=0
+ do common
+ quit
+common ;
+ k ar,br
+ Set ofil=$zparse($ztrnlnm("gtm$libsrc"),"directory")
+ If $p(ofil,".")="[LIBRARY",$p(ofil,".",3)="SRC]" s tfil=$p(ofil,".",2)
+ Else If $extract(ofil,1,2)="[V",$piece(ofil,".",2)="SRC]" Set tfil=$extract($piece(ofil,".",1),2,$length(ofil))
+ Else Read "GT.M Version: ",tfil,!
+ If tfil="" Write !,"No version specified",! Quit
+ Set ofil=$zparse(vaxoraxp_"_gtm$gtmdev:[LIBRARY."_tfil_"]"_vaxoraxp_"_comlist.com")
+ if ofil="" w !,"No version structure for "_tfil,! quit
+ s (mtables,relname)=0
+ f s x=$zsearch("gtm$libsrc:*.*") q:x="" s ar($p($p(x,";",1),"]",2))=""
+ f s x=$o(ar(x)) q:x="" s br($p(x,".",2),$p(x,".",1))="" s:x["MTABLES.C" mtables=1 s:x["RELEASE_NAME.H" relname=1
+ i 'relname w !,"WARNING: No RELEASE_NAME.H"
+ e i 'mtables s br("C","MTABLES")="" w !,"Added MTABLES.C to the compile list"
+ ;
+ o ofil:newv u ofil
+ d proc
+ c ofil
+ q
+proc ;
+ s count=0
+ w "$! comlist.com : p1=macro params, p2=cc params, p3=gtm$xxx, p4 = version number, p5 = YES to build",!
+ w "$ set verify",!
+ w "$ show time",!
+ w "$!",!
+ Write "$! default to building development version",!
+ w "$ if p4 .eqs. """" then p4 = ""d""",!
+ w "$!",!
+ Write "$! use production images to compile MSG.M",!
+ w "$ @gtm$com:setactive 'p4' p",!
+ w "$ set noon",!
+ w "$ install list gtmsecshr",!
+ w "$ if $severity .ne. 1",!
+ w "$ then",!
+ w "$ pdir = ""gtm$root:["" + f$trnlnm(""gtm$curpro"") + "".pro]""",!
+ w "$ define gtmsecshr gtm$sec:'f$trnlnm(""gtm$curpro"")'_gtmsecshr.exe",!
+ w "$ define gtmshr 'pdir'gtmshr.exe",!
+ w "$ define mcompile 'pdir'mcompile.exe",!
+ w "$ endif",!
+ w "$ set default 'p3'",!
+ w "$ set default [.obj]",!
+ w "$!",!
+ ;
+ Set listopts="/nolist"
+ s srcdir="gtm$src:",srctail=""
+ Set maxlen=0,comend="",search="CLD",exclude="",command="$ set command/object"_listopts Do genlst
+ w "$",!
+ Set maxlen=0,search="MSG",exclude="",command="$ message/object"_listopts Do genlst
+ w "$",!
+ w "$! define MUMPS command if .cldx file present",!
+ s srcdir="gtm$src:",srctail=""
+ Set maxlen=0,comend="",search="CLDX",exclude="",command="$ set command" Do genlst
+ w "$",!
+ Set search="MSG"
+ Write "$ if f$extract(1,2,p4) .lt. 43 then $ goto skpmsg",!
+ Write "$ mumps 'f$search(""gtm$src:MSG.M"")'",!
+ Write "$ link msg",!
+ Write "$ gtm_process_msg == ""$"" + f$environment(""DEFAULT"") + ""msg.exe""",!
+ Set pname="",errctl=0
+ For Set pname=$Order(br(search,pname)) Quit:""=pname Do:pname["ERRORS"
+ . Write "$ gtm_process_msg ",srcdir,pname,".",search," VMS",!
+ . Set br("C",pname_"_CTL")="",errctl=1
+ . If "MERRORS"=pname Write "$ rename/log merrors_ansi.h gtm$src",!
+ If errctl Write "$ rename/log *errors_ctl.c gtm$src",!
+ Write "$ delete/log msg.obj;",!
+ Write "$ delete/log msg.exe;",!
+ Write "$ @gtm$tools:gen_gtm_threadgbl_deftypes",!
+ Write "$ if 1 .ne. $status",!
+ Write "$ then",!
+ Write "$ write sys$output ""Failed to build gtm_threadgbl_deftypes.h - aborting build""",!
+ Write "$ exit",!
+ Write "$ endif",!
+ Write "$",!
+ Write "$skpmsg:",!
+ If efori write "$!",!
+ Set srcdir="gtm$src:",srctail=""
+ s maxlen=0
+ i mcpl s maxlen=100
+ w "$ compiler = ""cc""",!
+ Set vaxcopts="/vaxc"
+ Set deccslit="/assume=nowritable_string_literals"
+ Set deccopts="/standard=vaxc/share_globals/float=g_float"
+ Set deccopts=deccopts_"/warn=disable=(signedknown,signedmember,questcompare,questcompare1)/inc=(gtm$src:,tcpip$examples:)"
+ If (vaxoraxp="VAX")&(vaxc=1) Set opts=vaxcopts
+ Else Set opts=deccopts_deccslit
+ Set opts=opts_listopts_"'p2'"
+ Write "$ opts = """_opts_"""",!
+ Set axpexcl="GTCM_NETERR,GTCM_SERVER," ; these sources need different options and header files on AXP VMS
+ Set deccexcl="MEMMOVE,SECSHR_DB_CLNUP,SEC_SHR_BLK_BUILD," ; these need to omit "DECC$" prefix from "MEMMOVE"
+ ; avoid compiling GTM_THREADGBL_DEFTYPES.C since it is used by gtm$tools:gen_gtm_threadgbl_deftypes.com to
+ ; build GTM_THREADGBL_DEFTYPES.H. It is not part of the GTM runtime. SE 11/10.
+ Set exclude="GTM_THREADGBL_DEFTYPES,"
+ If vaxoraxp="AXP" Set exclude=exclude_axpexcl; Do
+ . Set deccaxp="MUPIP_SET_FILE,",exclude=exclude_deccaxp
+ If vaxc=0 Set exclude=exclude_deccexcl
+ s comend="",search="C",command="$ 'compiler''opts'" d genlst
+ If vaxoraxp="AXP" Do
+ . ;Write "$ write sys$output ""DECC-E-NFG - REMOVE this nonsense when DECC can compile MUPIP_SET_FILE /optimize""",!
+ . ;Write "$ opts = """_deccopts_listopts_"'p2'/noopti""",!
+ . ;Write command_$p(deccaxp,",")_".C"_comend,!
+ . ; end of MUPIP_SET_FILE nonsense
+ . ; N.B. On AXP VMS V6.1 or later, <NBFDEF.H> has been moved to SYS$LIB_C.TLB; recompile source files that need it.
+ . Write "$ opts = """_deccopts_listopts_"'p2'""",! ; N.B. omit "/assume=nowritable_string_literals"
+ . Set comend="+sys$library:sys$lib_c.tlb/library",command="$ 'compiler''opts'"
+ . For i=1:1 Set pname=$Piece(axpexcl,",",i) Quit:pname="" Do
+ . . If $Data(br("C",pname)) Write command_" "_srcdir_pname_".C"_comend,!
+ If vaxc=0 Do
+ . w "$! Turn off prefix generation for the name memmove in order to generate references to local version.",!
+ . w "$! Then compile memmove and anything in gtmsecshr that refers to it in order to eliminate",!
+ . w "$! any outbound calls from gtmsecshr (other modules that refer to memmove should use the one",!
+ . w "$! in the DEC C shared executable because it's probably faster).",!
+ . Write "$ opts = """_deccopts_deccslit_listopts_"/prefix=except=(MEMMOVE)'p2'""",!
+ . s comend="",search="C",command="$ 'compiler''opts'"
+ . For i=1:1 Set pname=$Piece(deccexcl,",",i) Quit:pname="" Do
+ . . If $Data(br("C",pname)) Write command_" "_srcdir_pname_".C"_comend,!
+ If efori Write "$ library/macro/create/log maclib",! Set libopt="/insert"
+ Else Write "$ copy/log gtm$src:maclib.mlb []",! Set libopt=""
+ Set maxlen=0,comend="",search="MAX",exclude="",command="$ library/macro"_libopt_"/log maclib" Do genlst
+ Write "$ copy maclib.mlb gtm$src",!
+ Write "$ purge/log maclib.mlb,gtm$src:maclib.mlb",!
+ Write "$ library/macro/list gtm$src:maclib",!
+ ;
+ ; Native VAX MACRO dialect modules.
+ Write "$ compiler = ""macro""",!
+ If vaxoraxp="VAX" Write "$ opts = """_listopts_"'p1'""",!
+ Else Write "$ opts = ""/migration/flag=(hints)"_listopts_"'p1'""",!
+ Set maxlen=0,comend="+maclib/lib",search="MAR",exclude="",command="$ 'compiler''opts'" Do genlst
+ ;
+ ; Native AXP MACRO dialect modules.
+ If vaxoraxp="AXP" Do
+ . Write "$ compiler = ""macro""",!
+ . Write "$ opts = ""/alpha_axp"_listopts_"'p1'""",!
+ . Set maxlen=0,comend="+maclib/lib",search="M64",exclude="",command="$ 'compiler''opts'" Do genlst
+ If efori Do newolb
+ w "$!",!
+ If $Data(br("C","DDPGVUSR")) Do
+ . Write "$ library/log/noglobals mumps ddpgvusr.obj",!
+ . Write "$ delete/log ddpgvusr.*;*",!
+ w "$ dir *.obj;2",! ; look for duplicates (usually caused by both C and MACRO versions)
+ ; Macro64 V1.2-108 has a bug which leaves dummy symbols from bndsym
+ ; gtm_main.m64 does not use bndsym but library/list/name showed it
+ ; also generated dummy symbols incorrectly. See mails in C9E07-002614 folder
+ ; The problem in gtm_main.m64 is using the $call macro with an argument of type /A
+ ; This bug was fixed by -118 which we no longer have
+ For m64bug="CMI_SYMBOLS","DDPGVUSR_SYMBOLS","GTM_MAIN" Do
+ . If $Data(br("M64",m64bug)) Do
+ . . Write "$ library/log mumps "_m64bug_".obj",!
+ . . Write "$ library/list="_m64bug_".name/name/only="_m64bug_" mumps",!
+ . . Write "$ search/noout/nowarn "_m64bug_".name macro64$",!
+ . . Write "$ if $status .ne. %X08D78053 ! NOMATCHES",!
+ . . Write "$ then",!
+ . . Write "$ library/remove=macro64$* mumps",!
+ . . Write "$ endif",!
+ . . Write "$ delete/log "_m64bug_".obj;*,"_m64bug_".name;*",!
+ If 'efori Write "$ library/log mumps *.obj",!
+ If efori Write "$ library mumps *.obj",!
+ If efori write "$ library/compress/data=reduce mumps.olb",!
+ If efori Write "$ purge/log mumps.olb",!
+ write "$ delete *.obj;*",!
+ write "$ show time",!
+ write "$ if p5 .nes. ""YES"" then exit",!
+ write "$ if p3 .eqs. ""GTM$DBG"" then $@gtm$tools:builddbg 'p4' ",vmsver,!
+ write "$ if p3 .eqs. ""GTM$BTA"" then $@gtm$tools:buildbta 'p4' ",vmsver,!
+ write "$ if p3 .eqs. ""GTM$PRO"" then $@gtm$tools:buildpro 'p4' ",vmsver,!
+ write "$ show time",!
+ quit
+genlst s command=command_" "_srcdir,str=command,pname="",linecnt=0
+ f s pname=$o(br(search,pname)) q:pname="" d
+ . If '(exclude[(pname_",")) Do
+ . . s count=count+1,linecnt=linecnt+1
+ . . s x=pname_"."_search_comend
+ . . i maxlen,$l(x)+$l(str)>maxlen d flush s linecnt=1
+ . . s str=str_x_","
+ . . i 'maxlen d flush
+ d flush:(maxlen)&(linecnt)
+ q
+flush w $e(str,1,$l(str)-1)_srctail,!
+ s str=command,linecnt=0
+ q
+newolb ;
+ w "$",!
+ w "$ ! ----- create new mumps.olb -------",!
+ w "$",!
+ w "$ show status",!
+ w "$ set noverify",!
+ w "$ size = 0",!
+ w "$ count = 0",!
+ w "$ cntblk:",!
+ w "$ x = f$search(""*.obj"")",!
+ w "$ if x .nes. """"",!
+ w "$ then ",!
+ w "$ count = count + 1",!
+ w "$ size = size + f$file_attributes(x,""EOF"")",!
+ w "$ goto cntblk",!
+ w "$ endif",!
+ w "$ gblcnt = count + count / 10",!
+ w "$ size = size + size / 10",!
+ w "$ set verify",!
+ w "$ purge/log",!
+ w "$ library/create=(history:0,module:'count',global:'gblcnt',block:'size') mumps",!
+ q
diff --git a/sr_vvms/comimage.com b/sr_vvms/comimage.com
new file mode 100644
index 0000000..3ddda36
--- /dev/null
+++ b/sr_vvms/comimage.com
@@ -0,0 +1,110 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2003 Sanchez Computer Associates, Inc. !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$! This file submits either PRO, BTA or DBG image for build
+$! P1 is the target-version
+$! P2 is the target-image (bta, dbg, pro)
+$! P3 is the target-node (which determines the platform)
+$! P4 is an optional quoted list of submit qualifiers (e.g. "/queue=alpha1_hiq/after=time")
+$!
+$ interact = (f$mode() .eqs. "INTERACTIVE")
+$!
+$ if p1 .eqs. ""
+$ then
+$ write sys$output "Must specify a version"
+$ if interact then inquire p1 "Version"
+$ if p1 .eqs. ""
+$ then
+$ write sys$output "No action taken"
+$ exit
+$ endif
+$ endif
+$!
+$askimage:
+$ if f$locate(p2,"/BTA/DBG/PRO") .eq. f$length("/BTA/DBG/PRO")
+$ then
+$ write sys$output "Must specify an image"
+$ if interact
+$ then
+$ inquire p2 "Image (bta,dbg,pro)"
+$ if f$locate(p2,"/BTA/DBG/PRO") .eq. f$length("/BTA/DBG/PRO")
+$ then
+$ write sys$output "Check Spelling"
+$ goto askimage
+$ endif
+$ else
+$ write sys$output "No action taken"
+$ exit
+$ endif
+$ endif
+$!
+$ if p3 .eqs. "" then p3 = f$getsyi("nodename")
+$!
+$ if (p3 .eqs. "CETUS")
+$ then
+$ if interact
+$ then
+$ write sys$output " "
+$ inquire link "Do you want to link the ''p2' files? Y/N "
+$ if ((link .eqs. "Y") .or. (link .eqs. "y"))
+$ then
+$ linkopt := YES
+$ else
+$ linkopt := NO
+$ endif
+$ else
+$ linkopt := NO
+$ endif
+$ else
+$ linkopt := YES
+$ endif
+$!
+$ platform = f$getsyi("arch_name")
+$ if (platform .eqs. "Alpha")
+$ then
+$ platform := AXP
+$ endif
+$!
+$ @gtm$tools:build_print_stage "comimage ''p1' ''p2' on ''p3'" "begin"
+$!
+$ when = f$trnlnm("test_run_time")
+$ if when .nes. "" then $ when = "/after=""" + when + """"
+$ comlist = f$search("user:[library."+p1+"]"+platform+"_comlist.com",0)
+$ if ( comlist .eqs. "" )
+$ then
+$ write sys$output "%COMIMAGE-E-NOCOMLIST, no comlist for version"
+$ exit
+$ endif
+$ if (p2 .eqs. "PRO" .or. p2 .eqs. "P")
+$ then
+$ submit/noprint/name=buildpro/log=user:[library.'p1']buildpro.log -
+ /queue='p3'_hiq/parameters=("","",gtm$pro,'p1','linkopt') 'comlist''p4''when'
+$ comimage_entry == $entry
+$ exit
+$ endif
+$ if (p2 .eqs. "BTA" .or. p2 .eqs. "B")
+$ then
+$ submit/noprint/name=buildbta/log=user:[library.'p1']buildbta.log -
+ /queue='p3'_hiq/parameters=("/debug","/nooptimize/debug",gtm$bta,'p1','linkopt') -
+ 'comlist''p4''when'
+$ comimage_entry == $entry
+$ exit
+$ endif
+$ if (p2 .eqs. "DBG" .or. p2 .eqs. "D")
+$ then
+$ submit/noprint/name=builddbg/log=user:[library.'p1']builddbg.log -
+ /queue='p3'_hiq/parameters=("/debug","/nooptimize/debug/define=DEBUG",gtm$dbg,'p1','linkopt') -
+ 'comlist''p4''when'
+$ comimage_entry == $entry
+$ exit
+$ endif
+$ @gtm$tools:build_print_stage "comimage" "end"
+$ exit
diff --git a/sr_vvms/comp_lits.c b/sr_vvms/comp_lits.c
new file mode 100644
index 0000000..374c5e5
--- /dev/null
+++ b/sr_vvms/comp_lits.c
@@ -0,0 +1,48 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "compiler.h"
+#include <rtnhdr.h>
+#include "mdq.h"
+#include "stringpool.h"
+
+GBLREF mliteral literal_chain;
+GBLREF spdesc stringpool;
+GBLREF unsigned short source_name_len;
+GBLREF mident routine_name;
+
+GBLDEF uint4 lits_size;
+
+void comp_lits(rhead)
+rhdtyp *rhead;
+{
+ uint4 offset;
+ mliteral *p;
+
+ offset = stringpool.free - stringpool.base;
+ offset += PADLEN(offset, NATIVE_WSIZE);
+ rhead->src_full_name.len = source_name_len;
+ rhead->src_full_name.addr = (char *)offset;
+ offset += source_name_len;
+ offset += PADLEN(offset, NATIVE_WSIZE);
+ rhead->routine_name.len = routine_name.len;
+ rhead->routine_name.addr = (char *)offset;
+ offset += routine_name.len;
+ offset += PADLEN(offset, NATIVE_WSIZE);
+ dqloop(&literal_chain, que, p)
+ if (p->rt_addr < 0)
+ {
+ p->rt_addr = offset;
+ offset += SIZEOF(mval);
+ }
+ lits_size = offset;
+}
diff --git a/sr_vvms/comque.com b/sr_vvms/comque.com
new file mode 100644
index 0000000..dbbc77d
--- /dev/null
+++ b/sr_vvms/comque.com
@@ -0,0 +1,53 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2005 Fidelity Information Services, Inc !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$! p1 is the version to build
+$! p2 is the node on which to build; defaults to the node on which it is submitted
+$! p3 can be used to specify a quoted list of submit qualifiers like "/hold" or "/after=0-23:59"
+$!
+$ interact = (f$mode() .eqs. "INTERACTIVE")
+$!
+$ if p1 .eqs. "" then p1 = f$trnlnm("gtm$verno")
+$ if p2 .eqs. "" then p2 = f$getsyi("nodename")
+$!
+$ @gtm$com:setactive 'p1' p
+$ @gtm$tools:comimage 'p1' "PRO" 'p2' 'p3'
+$ comimage_pro_entry = comimage_entry
+$
+$ @gtm$tools:comimage 'p1' "DBG" 'p2' 'p3'
+$ comimage_dbg_entry = comimage_entry
+$
+$ @gtm$tools:buildhlp 'p1'
+$
+$ set entry /release 'comimage_pro_entry'
+$ sync /entry='comimage_pro_entry'
+$ set noverify
+$ search gtm$ver:buildpro.log "-W-","-E-","-F-" /out=gtm$ver:errorpro.log
+$ comimage_pro_status = $status
+$ set verify
+$ if (comimage_pro_status .eqs. "%X00000001") then goto error_handler
+$ if (((comimage_pro_status / 2) * 2) .eqs. comimage_pro_status) then goto error_handler
+$ delete/log gtm$ver:errorpro.log.
+$
+$ set entry /release 'comimage_dbg_entry'
+$ sync /entry='comimage_dbg_entry'
+$ set noverify
+$ search gtm$ver:builddbg.log "-W-","-E-","-F-" /out=gtm$ver:errordbg.log
+$ comimage_dbg_status = $status
+$ set verify
+$ if (comimage_dbg_status .eqs. "%X00000001") then goto error_handler
+$ if (((comimage_dbg_status / 2) * 2) .eqs. comimage_dbg_status) then goto error_handler
+$ delete/log gtm$ver:errordbg.log.
+$
+$ exit
+$
+$error_handler:
+$ exit
diff --git a/sr_vvms/cre_comlist.com b/sr_vvms/cre_comlist.com
new file mode 100644
index 0000000..9cc5a58
--- /dev/null
+++ b/sr_vvms/cre_comlist.com
@@ -0,0 +1,45 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2004 Sanchez Computer Associates, Inc. !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$! cre_comlist invokes commal to create a typ_comlist.com compile driver
+$!
+$ interact = (f$mode() .eqs. "INTERACTIVE")
+$!
+$ if f$search("gtm$libsrc:*.*.*",0) .eqs. ""
+$ then
+$ write sys$output "GTM$LIBSRC does not point to any sources"
+$ if interact
+$ then
+$ inquire libsrc "Compile directory list"
+$ define gtm$libsrc 'libsrc'
+$ endif
+$ if f$search("gtm$libsrc:*.*.*",0) .eqs. ""
+$ then
+$ write sys$output "No action taken"
+$ exit
+$ endif
+$ endif
+$ show log gtm$libsrc
+$ curver = f$element(1,".",f$trnlnm("gtm$vrt"))
+$ curimg = f$extract(0,1,f$element(1,"$",f$trnlnm("gtm$exe")))
+$! "expand" gtm$src, i.e. get all directories in the search list, if
+$! it is a search list
+$ src1 = f$trnlnm("gtm$src",,0)
+$ src2 = f$trnlnm("gtm$src",,1)
+$ define gtmsrc "''src1'"
+$ if "" .nes. src2 then define/nolog gtmsrc "''src1',''src2'"
+$ define gtm$routines "[]/src=(''f$trnlnm("gtmsrc")')"
+$ version p p
+$ gtm
+o "SYS$COMMAND" u "SYS$COMMAND" d ^comall
+$ version 'curver' 'curimg'
+$ delete comall.obj.
+$ exit
diff --git a/sr_vvms/cre_comlistxp.com b/sr_vvms/cre_comlistxp.com
new file mode 100644
index 0000000..d73ac14
--- /dev/null
+++ b/sr_vvms/cre_comlistxp.com
@@ -0,0 +1,32 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2004 Sanchez Computer Associates, Inc. !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$! cre_comlistxp invokes commalxp to create a typ_comlist.com compile driver
+$! --- assumes "version" command was executed before coming in here
+$!
+$ set def gtm$ver
+$ curver = f$element(1,".",f$trnlnm("gtm$vrt"))
+$ curimg = f$extract(0,1,f$element(1,"$",f$trnlnm("gtm$exe")))
+$ define gtm$libsrc axp_gtm$gtmdev:[library.'curver'.src]
+$ show log gtm$libsrc
+$! "expand" gtm$src, i.e. get all directories in the search list, if
+$! it is a search list
+$ src1 = f$trnlnm("gtm$src",,0)
+$ src2 = f$trnlnm("gtm$src",,1)
+$ define gtmsrc "''src1'"
+$ if "" .nes. src2 then define/nolog gtmsrc "''src1',''src2'"
+$ define gtm$routines "[]/src=(''f$trnlnm("gtmsrc")')"
+$ version p p
+$ gtm
+o "SYS$COMMAND" u "SYS$COMMAND" d noprompt^comall
+$ version 'curver' 'curimg'
+$ delete comall.obj.
+$ exit
diff --git a/sr_vvms/crit_wake.c b/sr_vvms/crit_wake.c
new file mode 100644
index 0000000..f6813c9
--- /dev/null
+++ b/sr_vvms/crit_wake.c
@@ -0,0 +1,32 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <ssdef.h>
+#include <prvdef.h>
+
+
+int crit_wake(uint4 *pid)
+{
+ uint4 status, prvprv[2],
+ prvadr[2] = { PRV$M_WORLD, 0 };
+
+
+ if ((status = sys$setprv(TRUE, prvadr, FALSE, prvprv)) == SS$_NORMAL)
+ {
+ status = sys$wake(pid, NULL);
+
+ if ((prvprv[0] & PRV$M_WORLD) == 0)
+ (void)sys$setprv(FALSE, prvadr, FALSE, NULL);
+ }
+
+ return (int)status;
+}
diff --git a/sr_vvms/ctrap_set.c b/sr_vvms/ctrap_set.c
new file mode 100644
index 0000000..c97650a
--- /dev/null
+++ b/sr_vvms/ctrap_set.c
@@ -0,0 +1,49 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2006 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "efn.h"
+#include <ssdef.h>
+#include "xfer_enum.h"
+#include "outofband.h"
+
+/* ------------------------------------------------------------------
+ * Set flags and transfer table for synchronous handling of ctrap.
+ * Should be called only from set_xfer_handlers.
+ * ------------------------------------------------------------------
+ */
+
+GBLREF volatile int4 ctrap_action_is;
+GBLREF int (* volatile xfer_table[])();
+GBLREF volatile int4 outofband;
+
+void ctrap_set(int4 ob_char)
+{
+ int4 status;
+ void op_fetchintrrpt(), op_startintrrpt(), op_forintrrpt();
+
+ if (!outofband)
+ {
+ status = sys$setef(efn_outofband);
+ assert(SS$_WASCLR == status);
+ if (status != SS$_WASCLR && status != SS$_WASSET)
+ GTMASSERT;
+ outofband = ctrap;
+ ctrap_action_is = ob_char;
+ xfer_table[xf_linefetch] = op_fetchintrrpt;
+ xfer_table[xf_linestart] = op_startintrrpt;
+ xfer_table[xf_zbfetch] = op_fetchintrrpt;
+ xfer_table[xf_zbstart] = op_startintrrpt;
+ xfer_table[xf_forchk1] = op_startintrrpt;
+ xfer_table[xf_forloop] = op_forintrrpt;
+ sys$wake(0,0);
+ }
+}
diff --git a/sr_vvms/ctrlc_set.c b/sr_vvms/ctrlc_set.c
new file mode 100644
index 0000000..7977960
--- /dev/null
+++ b/sr_vvms/ctrlc_set.c
@@ -0,0 +1,71 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "efn.h"
+#include <ssdef.h>
+
+#include "gtm_string.h"
+#include "xfer_enum.h"
+#include "outofband.h"
+#include "msg.h"
+#include "op.h"
+#include "gtmimagename.h"
+
+/* ------------------------------------------------------------------
+ * Set flags and transfer table for synchronous handling of cntl-C.
+ * Should be called only from set_xfer_handlers.
+ *
+ * Note: dummy parameter is for calling compatibility.
+ * ------------------------------------------------------------------
+ */
+
+GBLREF volatile char source_file_name[];
+GBLREF int (* volatile xfer_table[])();
+GBLREF volatile bool ctrlc_on;
+GBLREF volatile int4 ctrap_action_is, outofband;
+
+ctrlc_set(int4 dummy_param)
+{
+ int4 status;
+ msgtype message;
+ error_def(ERR_LASTFILCMPLD);
+
+ if (!IS_MCODE_RUNNING)
+ {
+ message.arg_cnt = 4;
+ message.def_opts = message.new_opts = 0;
+ message.msg_number = ERR_LASTFILCMPLD;
+ message.fp_cnt = 2;
+ message.fp[0].n = strlen(source_file_name);
+ message.fp[1].cp = source_file_name;
+ sys$putmsg(&message, 0, 0, 0);
+ } else if (!outofband)
+ {
+ if (ctrlc_on)
+ {
+ status = sys$setef(efn_outofband);
+ assert(SS$_WASCLR == status);
+ if (status != SS$_WASCLR && status != SS$_WASSET)
+ GTMASSERT;
+ ctrap_action_is = 0;
+ outofband = ctrlc;
+ xfer_table[xf_linefetch] = op_fetchintrrpt;
+ xfer_table[xf_linestart] = op_startintrrpt;
+ xfer_table[xf_zbfetch] = op_fetchintrrpt;
+ xfer_table[xf_zbstart] = op_startintrrpt;
+ xfer_table[xf_forchk1] = op_startintrrpt;
+ xfer_table[xf_forloop] = op_forintrrpt;
+ sys$wake(0,0);
+ }
+ }
+}
diff --git a/sr_vvms/ctrly_set.c b/sr_vvms/ctrly_set.c
new file mode 100644
index 0000000..b225b34
--- /dev/null
+++ b/sr_vvms/ctrly_set.c
@@ -0,0 +1,56 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "efn.h"
+#include <ssdef.h>
+#include "xfer_enum.h"
+#include "outofband.h"
+#include "op.h"
+#include "deferred_events.h"
+#include "gtmimagename.h"
+
+/* ------------------------------------------------------------------
+ * Set flags and transfer table for synchronous handling of cntl-Y.
+ * Should be called only from set_xfer_handlers.
+ *
+ * Note: dummy parameter is for calling compatibility.
+ * ------------------------------------------------------------------
+ */
+
+GBLREF int (* volatile xfer_table[])();
+GBLREF volatile int4 outofband, ctrap_action_is;
+
+void ctrly_set(int4 dummy_param)
+{
+ int4 status;
+
+ if (!IS_MCODE_RUNNING)
+ {
+ outofband = ctrly;
+ outofband_clear();
+ } else
+ {
+ status = sys$setef(efn_outofband);
+ assert(SS$_WASCLR == status);
+ if (status != SS$_WASCLR && status != SS$_WASSET)
+ GTMASSERT;
+ ctrap_action_is = 0;
+ outofband = ctrly;
+ xfer_table[xf_linefetch] = op_fetchintrrpt;
+ xfer_table[xf_linestart] = op_startintrrpt;
+ xfer_table[xf_zbfetch] = op_fetchintrrpt;
+ xfer_table[xf_zbstart] = op_startintrrpt;
+ xfer_table[xf_forchk1] = op_startintrrpt;
+ xfer_table[xf_forloop] = op_forintrrpt;
+ sys$wake(0,0);
+ }
+}
diff --git a/sr_vvms/curr_dev_outbndset.c b/sr_vvms/curr_dev_outbndset.c
new file mode 100644
index 0000000..25cdf98
--- /dev/null
+++ b/sr_vvms/curr_dev_outbndset.c
@@ -0,0 +1,30 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "outofband.h"
+#include "curr_dev_outbndset.h"
+#include "deferred_events.h"
+
+GBLREF bool std_dev_outbnd;
+
+void curr_dev_outbndset(int4 ob_char)
+{
+
+ if (ob_char > MAXOUTOFBAND)
+ {
+ GTMASSERT;
+ }
+ else
+ { std_dev_outbnd = FALSE;
+ ctrap_set(ob_char);
+ }
+}
diff --git a/sr_vvms/curr_dev_outbndset.h b/sr_vvms/curr_dev_outbndset.h
new file mode 100644
index 0000000..160fac3
--- /dev/null
+++ b/sr_vvms/curr_dev_outbndset.h
@@ -0,0 +1,17 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef CURR_DEV_OUTBNDSET_INCLUDED
+#define CURR_DEV_OUTBNDSET_INCLUDED
+
+void curr_dev_outbndset(int4 ob_char);
+
+#endif /* CURR_DEV_OUTBNDSET_INCLUDED */
diff --git a/sr_vvms/cvtprot.c b/sr_vvms/cvtprot.c
new file mode 100644
index 0000000..b4cad85
--- /dev/null
+++ b/sr_vvms/cvtprot.c
@@ -0,0 +1,51 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <xab.h>
+#include "cvtprot.h"
+
+int cvtprot(char *cp, short cnt)
+{
+ int mask;
+
+ /* a protection mask consists of 4 bits, R(ead), W(rite), E(xecute), and D(elete).
+ to deny access, the bit is one; to grant access, the
+ bit is set to zero.
+ */
+ mask = 0;
+ for (;cnt > 0 ; cnt--, cp++)
+ {
+ switch (*cp)
+ {
+ case 'R':
+ case 'r':
+ mask |= XAB$M_NOREAD;
+ break;
+ case 'W':
+ case 'w':
+ mask |= XAB$M_NOWRITE;
+ break;
+ case 'E':
+ case 'e':
+ mask |= XAB$M_NOEXE;
+ break;
+ case 'D':
+ case 'd':
+ mask |= XAB$M_NODEL;
+ break;
+ default:
+ return -1;
+ }
+ }
+ return mask;
+}
+
diff --git a/sr_vvms/cvttime.c b/sr_vvms/cvttime.c
new file mode 100644
index 0000000..978a7be
--- /dev/null
+++ b/sr_vvms/cvttime.c
@@ -0,0 +1,27 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <descrip.h>
+#include "cvttime.h"
+
+
+int4 cvttime(mval *src, int4 tim[2])
+{
+ $DESCRIPTOR (dsrc,src->str.addr) ;
+ int4 cnx= 0, fl= 127;
+ int4 status;
+
+ dsrc.dsc$w_length= src->str.len ;
+ status= lib$convert_date_string(&dsrc,tim,&cnx,&fl,0,0) ;
+ return status;
+}
+
diff --git a/sr_vvms/dbcertify_cmd.cld b/sr_vvms/dbcertify_cmd.cld
new file mode 100644
index 0000000..375d59d
--- /dev/null
+++ b/sr_vvms/dbcertify_cmd.cld
@@ -0,0 +1,20 @@
+MODULE DBCERTIFY_CMD
+
+DEFINE VERB SCAN
+ PARAMETER P1, LABEL=REGION, PROMPT="Region", VALUE(REQUIRED)
+ ROUTINE dbcertify_scan_phase
+ QUALIFIER BSU_KEYS NEGATABLE
+ QUALIFIER DEBUG NEGATABLE
+ QUALIFIER DETAIL NEGATABLE
+ QUALIFIER KEEP_TEMPS NEGATABLE
+ QUALIFIER OUTFILE NONNEGATABLE VALUE(TYPE = $FILE, REQUIRED)
+ QUALIFIER REPORT_ONLY NEGATABLE
+ QUALIFIER TEMPFILE_DIR NONNEGATABLE VALUE(TYPE = $FILE, REQUIRED)
+
+DEFINE VERB CERTIFY
+ PARAMETER P1, LABEL=P1OUTFILE, PROMPT="DBCERTIFY SCAN output filename", VALUE(TYPE = $FILE, REQUIRED)
+ ROUTINE dbcertify_certify_phase
+ QUALIFIER BLOCKS NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER DEBUG NEGATABLE
+ QUALIFIER KEEP_TEMPS NEGATABLE
+ QUALIFIER TEMPFILE_DIR NONNEGATABLE VALUE(TYPE = $FILE, REQUIRED)
diff --git a/sr_vvms/dbcertify_dbfilop.c b/sr_vvms/dbcertify_dbfilop.c
new file mode 100644
index 0000000..a65e228
--- /dev/null
+++ b/sr_vvms/dbcertify_dbfilop.c
@@ -0,0 +1,222 @@
+/****************************************************************
+ * *
+ * Copyright 2005, 2009 Fidelity Information Services, LLC. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+#include <descrip.h>
+#include <iodef.h>
+#include <psldef.h>
+#include <rms.h>
+#include <rmsdef.h>
+#include <ssdef.h>
+#include <syidef.h>
+#include <efndef.h>
+
+
+#include "gdsroot.h"
+#include "v15_gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "v15_gdsbt.h"
+#include "gdsfhead.h"
+#include "v15_gdsfhead.h"
+#include "gdsblk.h"
+#include "gdsblkops.h"
+#include "filestruct.h"
+#include "efn.h"
+#include "vmsdtype.h"
+#include "sleep_cnt.h"
+#include "error.h"
+#include "wcs_sleep.h"
+#include "gtm_file_stat.h"
+#include "iosb_disk.h"
+#include "iosp.h"
+#include "is_file_identical.h"
+#include "dbcertify.h"
+
+#define DEFDBEXT ".dat"
+#define MAX_NODE_NAME_LEN 16
+
+static int msgcodes[2] = {1 , 0}; /* allows for 1 parm for sys$putmsg() */
+
+void dbcertify_dbfilop(phase_static_area *psa)
+{
+ uint4 addrs[2], lcnt, node_area, node_number, status, hold_esa;
+ unsigned short retlen[4];
+ io_status_block_disk iosb;
+ char node_name[MAX_NODE_NAME_LEN], dnetid[MAX_NODE_NAME_LEN];
+ struct
+ {
+ item_list_3 ilist[3];
+ int4 terminator;
+ } syi_list;
+ vms_gds_info *gds_info;
+ $DESCRIPTOR (faodsc, dnetid);
+ static readonly $DESCRIPTOR (ctrstr, "!UL.!UL");
+
+ error_def(ERR_DBFILOPERR);
+ error_def(ERR_MUSTANDALONE);
+ error_def(ERR_NETDBOPNERR);
+ error_def(ERR_DBOPNERR);
+ error_def(ERR_SYSCALL);
+
+ gds_info = psa->fc->file_info;
+ switch(psa->fc->op)
+ {
+ case FC_READ:
+ assert(psa->fc->op_pos > 0); /* gt.m uses the vms convention of numbering the blocks from 1 */
+ status = sys$qiow(EFN$C_ENF, gds_info->fab->fab$l_stv, IO$_READVBLK, &iosb, NULL, 0,
+ psa->fc->op_buff, psa->fc->op_len, psa->fc->op_pos, 0, 0, 0);
+ if (SYSCALL_SUCCESS(status))
+ status = iosb.cond;
+ if (SYSCALL_ERROR(status))
+ rts_error(VARLSTCNT(5) ERR_DBFILOPERR, 2, gds_info->fab->fab$b_fns, gds_info->fab->fab$l_fna,
+ status);
+ break;
+ case FC_WRITE:
+ status = sys$qiow(EFN$C_ENF, gds_info->fab->fab$l_stv, IO$_WRITEVBLK,
+ &iosb, NULL, 0, psa->fc->op_buff, psa->fc->op_len, psa->fc->op_pos, 0, 0, 0);
+ if (SYSCALL_SUCCESS(status))
+ status = iosb.cond;
+ if (SYSCALL_ERROR(status))
+ rts_error(VARLSTCNT(5) ERR_DBFILOPERR, 2, gds_info->fab->fab$b_fns,
+ gds_info->fab->fab$l_fna, status);
+ break;
+ case FC_OPEN:
+ if (NULL == gds_info->fab)
+ gds_info->fab = malloc(SIZEOF(*gds_info->fab));
+
+ *gds_info->fab = cc$rms_fab;
+ gds_info->fab->fab$l_fna = psa->dbc_gv_cur_region->dyn.addr->fname;
+ gds_info->fab->fab$b_fns = psa->dbc_gv_cur_region->dyn.addr->fname_len;
+ gds_info->fab->fab$b_fac = FAB$M_BIO | FAB$M_GET | FAB$M_PUT;
+ gds_info->fab->fab$l_fop = FAB$M_UFO;
+ if (psa->phase_one)
+ { /* We need shared access for phase-1 but not phase-2 which must run standalone */
+ gds_info->fab->fab$b_rtv = WINDOW_ALL;
+ gds_info->fab->fab$b_shr = FAB$M_SHRPUT | FAB$M_SHRGET | FAB$M_UPI;
+ } else
+ gds_info->fab->fab$b_shr = FAB$M_NIL;
+ gds_info->fab->fab$l_dna = DEFDBEXT;
+ gds_info->fab->fab$b_dns = SIZEOF(DEFDBEXT) - 1;
+ if (NULL == gds_info->nam)
+ {
+ gds_info->nam = malloc(SIZEOF(*gds_info->nam));
+ *gds_info->nam = cc$rms_nam;
+ gds_info->nam->nam$l_esa = malloc(MAX_FN_LEN + 1);
+ }
+ gds_info->nam->nam$b_ess = MAX_FN_LEN;
+ gds_info->fab->fab$l_nam = gds_info->nam;
+ if (NULL == gds_info->xabfhc)
+ gds_info->xabfhc = malloc(SIZEOF(*gds_info->xabfhc));
+ *gds_info->xabfhc = cc$rms_xabfhc;
+ gds_info->fab->fab$l_xab = gds_info->xabfhc;
+ if (NULL == gds_info->xabpro)
+ gds_info->xabpro = malloc(SIZEOF(*gds_info->xabpro));
+ *gds_info->xabpro = cc$rms_xabpro;
+ gds_info->xabfhc->xab$l_nxt = gds_info->xabpro;
+
+ psa->dbc_gv_cur_region->read_only = FALSE; /* maintain csa->read_write simultaneously */
+ gds_info->s_addrs.read_write = TRUE; /* maintain reg->read_only simultaneously */
+ if (0 == gds_info->fab->fab$b_fns)
+ {
+ memcpy(gds_info->nam->nam$t_dvi, gds_info->file_id.dvi, SIZEOF(gds_info->nam->nam$t_dvi));
+ memcpy(gds_info->nam->nam$w_did, gds_info->file_id.did, SIZEOF(gds_info->nam->nam$w_did));
+ memcpy(gds_info->nam->nam$w_fid, gds_info->file_id.fid, SIZEOF(gds_info->nam->nam$w_fid));
+ gds_info->fab->fab$l_fop |= FAB$M_NAM;
+ } else
+ {
+ gds_info->nam->nam$b_nop = NAM$M_NOCONCEAL;
+ if (0 == (1 & (status = sys$parse(gds_info->fab, NULL, NULL))))
+ rts_error(VARLSTCNT(9) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("sys$parse"),
+ CALLFROM, status, gds_info->fab->fab$l_stv);
+ if (gds_info->nam->nam$b_node)
+ {
+ syi_list.ilist[0].item_code = SYI$_NODENAME;
+ syi_list.ilist[0].buffer_address = &node_name;
+ syi_list.ilist[0].buffer_length = SIZEOF(node_name);
+ syi_list.ilist[0].return_length_address = &retlen[0];
+ syi_list.ilist[1].item_code = SYI$_NODE_AREA;
+ syi_list.ilist[1].buffer_address = &node_area;
+ syi_list.ilist[1].buffer_length = SIZEOF(node_area);
+ syi_list.ilist[1].return_length_address = &retlen[1];
+ syi_list.ilist[2].item_code = SYI$_NODE_NUMBER;
+ syi_list.ilist[2].buffer_address = &node_number;
+ syi_list.ilist[2].buffer_length = SIZEOF(node_number);
+ syi_list.ilist[2].return_length_address = &retlen[2];
+ syi_list.terminator = 0;
+ status = sys$getsyiw(EFN$C_ENF, NULL, NULL, &syi_list, &iosb, NULL, 0);
+ if (SYSCALL_SUCCESS(status))
+ status = sys$fao(&ctrstr, &retlen[3], &faodsc, node_area, node_number);
+ if (SYSCALL_ERROR(status))
+ rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("sys$getsyiw()"),
+ CALLFROM, status);
+ if (((gds_info->nam->nam$b_node - 2 != retlen[0])
+ || (0 != memcmp(gds_info->nam->nam$l_esa, node_name, retlen[0])))
+ && ((gds_info->nam->nam$b_node - 2 != retlen[3])
+ || (0 != memcmp(gds_info->nam->nam$l_esa, dnetid, retlen[3]))))
+ {
+ rts_error(VARLSTCNT(1) ERR_NETDBOPNERR);
+ }
+ gds_info->fab->fab$l_fna = gds_info->nam->nam$l_esa + gds_info->nam->nam$b_node;
+ gds_info->fab->fab$b_fns = gds_info->nam->nam$b_esl - gds_info->nam->nam$b_node;
+ }
+ }
+ for (lcnt = 1; 15 >= lcnt; lcnt++)
+ { /* Try for 15 seconds */
+ if (RMS$_FLK != (status = sys$open(gds_info->fab, NULL, NULL)))
+ break;
+ sleep(1);
+ }
+ if (SYSCALL_ERROR(status))
+ {
+ if (RMS$_PRV == status)
+ {
+ gds_info->fab->fab$b_fac = FAB$M_BIO | FAB$M_GET;
+ psa->dbc_gv_cur_region->read_only = TRUE; /* maintain csa->read_write simultaneously */
+ gds_info->s_addrs.read_write = FALSE; /* maintain reg->read_only simultaneously */
+ gds_info->fab->fab$l_fna = gds_info->nam->nam$l_esa;
+ gds_info->fab->fab$b_fns = gds_info->nam->nam$b_esl;
+ status = sys$open(gds_info->fab);
+ }
+ if (RMS$_NORMAL != status)
+ {
+ if (RMS$_FLK == status)
+ rts_error(VARLSTCNT(4) MAKE_MSG_TYPE(ERR_MUSTANDALONE, ERROR),
+ 2, gds_info->fab->fab$b_fns, gds_info->fab->fab$l_fna);
+ else
+ rts_error(VARLSTCNT(6) ERR_DBOPNERR, 2, gds_info->fab->fab$b_fns,
+ gds_info->fab->fab$l_fna, status, gds_info->fab->fab$l_stv);
+ }
+ }
+ memcpy(gds_info->file_id.dvi, gds_info->nam->nam$t_dvi, SIZEOF(gds_info->nam->nam$t_dvi));
+ memcpy(gds_info->file_id.did, gds_info->nam->nam$w_did, SIZEOF(gds_info->nam->nam$w_did));
+ memcpy(gds_info->file_id.fid, gds_info->nam->nam$w_fid, SIZEOF(gds_info->nam->nam$w_fid));
+ /* Copy after removing the version number from file name */
+ fncpy_nover(gds_info->nam->nam$l_esa, gds_info->nam->nam$b_esl,
+ psa->dbc_gv_cur_region->dyn.addr->fname, psa->dbc_gv_cur_region->dyn.addr->fname_len);
+ gds_info->nam->nam$b_esl = gds_info->fab->fab$b_fns = psa->dbc_gv_cur_region->dyn.addr->fname_len;
+ strcpy(gds_info->fab->fab$l_fna, psa->dbc_gv_cur_region->dyn.addr->fname);
+ gds_info->fab->fab$l_xab = NULL;
+ gds_info->fab->fab$l_nam = NULL;
+ gds_info->xabfhc->xab$l_nxt = NULL;
+ break;
+ case FC_CLOSE:
+ status = sys$dassgn(gds_info->fab->fab$l_stv);
+ if (!(status & 1))
+ gtm_putmsg(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("sys$dassgn"), CALLFROM, status);
+ break;
+ default:
+ GTMASSERT;
+ }
+}
diff --git a/sr_vvms/dbcertify_exit_handler.c b/sr_vvms/dbcertify_exit_handler.c
new file mode 100644
index 0000000..ebc8ef4
--- /dev/null
+++ b/sr_vvms/dbcertify_exit_handler.c
@@ -0,0 +1,124 @@
+/****************************************************************
+ * *
+ * Copyright 2005, 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <ssdef.h>
+#include <psldef.h>
+#include <descrip.h>
+#include <signal.h> /* for VSIG_ATOMIC_T type */
+
+#include "gtm_inet.h"
+#include "gtm_stdio.h" /* for FILE structure etc. */
+#include "gtm_time.h"
+
+#include "ast.h"
+#include "gdsroot.h"
+#include "v15_gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "v15_gdsbt.h"
+#include "gdsfhead.h"
+#include "v15_gdsfhead.h"
+#include "filestruct.h"
+#include "v15_filestruct.h"
+#include "error.h"
+#include "iotimer.h"
+#include "jnl.h"
+#include "locklits.h"
+#include "gtmrecv.h" /* for recvpool etc. */
+#include "io.h"
+#include "iosp.h"
+#include "sleep_cnt.h"
+#include "repl_msg.h"
+#include "gtmsource.h"
+#include "repl_sem.h"
+#include "repl_shm.h"
+#include "desblk.h"
+#include "gtmimagename.h"
+#include "util.h"
+#include "op.h"
+#include "repl_log.h"
+#include "generic_exit_handler.h"
+#include "gv_rundown.h"
+#include "have_crit.h"
+#include "print_exit_stats.h"
+#include "setzdir.h"
+#include "buddy_list.h"
+#include "hashtab_mname.h" /* needed for muprec.h */
+#include "hashtab_int4.h" /* needed for muprec.h */
+#include "hashtab_int8.h" /* needed for muprec.h */
+#include "muprec.h"
+#include "gtmmsg.h"
+#include "secshr_db_clnup.h"
+#include "gdsblk.h"
+#include "gdsblkops.h"
+#include "dbcertify.h"
+
+GBLREF int4 exi_condition;
+GBLREF desblk exi_blk;
+GBLREF enum gtmImageTypes image_type;
+GBLREF uint4 process_id;
+GBLREF phase_static_area *psa_gbl;
+
+error_def(ERR_ACK);
+error_def(ERR_FORCEDHALT);
+error_def(ERR_UNKNOWNFOREX);
+
+void dbcertify_exit_handler(void)
+{
+ void (*signal_routine)();
+ int4 lcnt;
+
+ sys$setast(ENABLE); /* safer and doesn't hurt much */
+ sys$cantim(0,0); /* cancel all outstanding timers. prevents unwelcome surprises */
+
+ /* We can defer exit-handling if it was a forced-halt and we are in an AST or have crit in any region.
+ * If we are in an AST when a fatal exception occurs we can neither defer exiting nor do normal exit-handling,
+ * so we return immediately with the hope that the privileged exit-handler in GTMSECSHR,
+ * secshr_db_clnup(ABNORMAL_TERMINATION) will do the necessary cleanup.
+ * Note that even if we hold crit in any region when a non-deferrable exception occurs, we can still go ahead with
+ * normal exit-handling chores. secshr_db_clnup(NORMAL_TERMINATION) (invoked below) will cleanup the crits for us.
+ */
+ if (ERR_FORCEDHALT == exi_condition || 0 == exi_condition)
+ {
+ if (lib$ast_in_prog()) /* The rest of this assumes that it may use AST's */
+ {
+ EXIT_HANDLER(&exi_blk); /* reestablish the exit handler */
+ sys$forcex(&process_id); /* make the forcex come back as an AST */
+ ESTABLISH(exi_ch); /* set a condition handler to unwind exit handler levels */
+ rts_error_csa(CSA_ARG(NULL) ERR_ACK); /* and signal success */
+ }
+ assert(!lib$ast_in_prog());
+ /* We defer exiting only if we are in commit phase in any region as opposed to holding crit in that region.
+ * The danger of deferring if we are holding crit in a region is that we may do infinite defers in processes
+ * that have no intention of releasing crit.
+ * 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)
+ {
+ EXIT_HANDLER(&exi_blk);
+ ESTABLISH(exi_ch);
+ rts_error_csa(CSA_ARG(NULL) exi_condition ? exi_condition : ERR_FORCEDHALT);
+ }
+ } else if (lib$ast_in_prog())
+ rts_error_csa(CSA_ARG(NULL) exi_condition); /* this shouldn't return */
+ SET_FORCED_EXIT_STATE_ALREADY_EXITING;
+ 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();
+}
diff --git a/sr_vvms/dbcertify_parse_and_dispatch.c b/sr_vvms/dbcertify_parse_and_dispatch.c
new file mode 100644
index 0000000..b7f0687
--- /dev/null
+++ b/sr_vvms/dbcertify_parse_and_dispatch.c
@@ -0,0 +1,62 @@
+/****************************************************************
+ * *
+ * Copyright 2005 Fidelity Information Services, LLC. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <rmsdef.h>
+#include <descrip.h>
+#include <climsgdef.h>
+#include <ssdef.h>
+
+#include "cli.h"
+#include "gdsroot.h"
+#include "v15_gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "v15_gdsbt.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "v15_gdsfhead.h"
+#include "gdsblkops.h"
+#include "error.h"
+#include "mupip_exit.h" /* Wrong name but does what we want */
+#include "dbcertify.h"
+
+GBLREF phase_static_area *psa_gbl;
+
+extern int DBCERTIFY_CMD(), CLI$DCL_PARSE(), CLI$DISPATCH();
+
+void dbcertify_parse_and_dispatch(int argc, char **argv)
+{
+ char buff[512];
+ int status;
+ unsigned short outlen;
+ $DESCRIPTOR(command, buff);
+ error_def(ERR_CLIERR);
+
+ status = lib$get_foreign(&command, 0, &outlen, 0);
+ if (status & 1)
+ {
+ if (0 < outlen)
+ {
+ command.dsc$w_length = outlen;
+ status = CLI$DCL_PARSE(&command, &DBCERTIFY_CMD, &lib$get_input, 0, 0);
+ if (status == CLI$_NORMAL)
+ { /* Before we dispatch the function, process one common parameter we need immediately */
+ psa_gbl->dbc_debug = (CLI_PRESENT == cli_present("DEBUG"));
+ CLI$DISPATCH();
+ }
+ } else
+ rts_error(VARLSTCNT(4) ERR_CLIERR, 2, RTS_ERROR_LITERAL("No parameters specified"));
+ }
+ mupip_exit(status);
+}
diff --git a/sr_vvms/dbcx_ref.c b/sr_vvms/dbcx_ref.c
new file mode 100644
index 0000000..6e7f2c9
--- /dev/null
+++ b/sr_vvms/dbcx_ref.c
@@ -0,0 +1,54 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* This routine takes a pointer to a sgmnt_data struct with space for the BTs and
+ locks attached. The BTs and the lock space are initialized and then written
+ to disk to the file specified by channel.
+*/
+
+#include "mdef.h"
+#include <rms.h>
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include <ssdef.h>
+#include <iodef.h>
+#include <efndef.h>
+#include "mlk_shr_init.h"
+#include "dbcx_ref.h"
+
+
+int dbcx_ref(sgmnt_data *sd, int chan)
+{
+ char *qio_ptr, *qio_top;
+ short iosb[4];
+ int block, status;
+ sgmnt_addrs sa;
+
+
+ sa.hdr = sd;
+ bt_malloc(&sa);
+ mlk_shr_init((char *)sd + (LOCK_BLOCK(sd) * DISK_BLOCK_SIZE), sd->lock_space_size, &sa, TRUE);
+ qio_ptr = (char *)sd;
+ qio_top = qio_ptr + (LOCK_BLOCK(sd) * DISK_BLOCK_SIZE) + LOCK_SPACE_SIZE(sd);
+ for ( block = 1; qio_ptr < qio_top; block++, qio_ptr += DISK_BLOCK_SIZE)
+ {
+ if (SS$_NORMAL != (status = sys$qiow(EFN$C_ENF, chan, IO$_WRITEVBLK, iosb,
+ 0, 0, qio_ptr, DISK_BLOCK_SIZE, block, 0, 0, 0)))
+ return status;
+ if (!(iosb[0] & 1))
+ return iosb[0];
+ }
+ return SS$_NORMAL;
+}
diff --git a/sr_vvms/dbcx_ref.h b/sr_vvms/dbcx_ref.h
new file mode 100644
index 0000000..470c4be
--- /dev/null
+++ b/sr_vvms/dbcx_ref.h
@@ -0,0 +1,17 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef DBCX_REF_INCLUDED
+#define DBCX_REF_INCLUDED
+
+int dbcx_ref(sgmnt_data *sd, int chan);
+
+#endif /* DBCX_REF_INCLUDED */
diff --git a/sr_vvms/dbfilop.c b/sr_vvms/dbfilop.c
new file mode 100644
index 0000000..f01a30e
--- /dev/null
+++ b/sr_vvms/dbfilop.c
@@ -0,0 +1,241 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include <descrip.h>
+#include <iodef.h>
+#include <psldef.h>
+#include <rms.h>
+#include <rmsdef.h>
+#include <ssdef.h>
+#include <syidef.h>
+#include <efndef.h>
+
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "efn.h"
+#include "vmsdtype.h"
+#include "sleep_cnt.h"
+#include "dbfilop.h"
+#include "wcs_sleep.h"
+#include "gtm_file_stat.h"
+#include "gtm_malloc.h" /* for CHECK_CHANNEL_STATUS macro */
+#include "iosb_disk.h"
+#include "iosp.h"
+
+#define DEFDBEXT ".dat"
+#define MAX_NODE_NAME_LEN 16
+
+GBLREF gd_region *gv_cur_region;
+
+uint4 dbfilop(file_control *fc)
+{
+ uint4 addrs[2], lcnt, node_area, node_number, status;
+ unsigned short retlen[4];
+ io_status_block_disk iosb;
+ char node_name[MAX_NODE_NAME_LEN], dnetid[MAX_NODE_NAME_LEN];
+ struct {
+ item_list_3 ilist[3];
+ int4 terminator;
+ } syi_list;
+ vms_gds_info *gds_info;
+ uint4 channel_id;
+
+ $DESCRIPTOR (faodsc, dnetid);
+ static readonly $DESCRIPTOR (ctrstr, "!UL.!UL");
+
+ error_def(ERR_DBFILOPERR);
+ error_def(ERR_DBNOTGDS);
+ error_def(ERR_NETDBOPNERR);
+ error_def(ERR_SYSCALL);
+
+ assert((dba_mm == fc->file_type) || (dba_bg == fc->file_type));
+ gds_info = fc->file_info;
+ switch(fc->op)
+ {
+ case FC_READ:
+ assert(fc->op_pos > 0); /* gt.m uses the vms convention of numbering the blocks from 1 */
+ channel_id = gds_info->fab->fab$l_stv;
+ status = sys$qiow(EFN$C_ENF, channel_id, IO$_READVBLK, &iosb, NULL, 0,
+ fc->op_buff, fc->op_len, fc->op_pos, 0, 0, 0);
+ if (SYSCALL_SUCCESS(status))
+ status = iosb.cond;
+ if (SYSCALL_ERROR(status))
+ {
+ CHECK_CHANNEL_STATUS(status, channel_id);
+ rts_error(VARLSTCNT(5) ERR_DBFILOPERR, 2, gds_info->fab->fab$b_fns, gds_info->fab->fab$l_fna,
+ status);
+ }
+ if ((1 == fc->op_pos) && (0 != memcmp(fc->op_buff, GDS_LABEL, GDS_LABEL_SZ - 3)))
+ rts_error(VARLSTCNT(4) ERR_DBNOTGDS, 2, gds_info->fab->fab$b_fns, gds_info->fab->fab$l_fna);
+ break;
+ case FC_WRITE:
+ if ((1 == fc->op_pos) && (0 != memcmp(fc->op_buff, GDS_LABEL, GDS_LABEL_SZ - 1)
+ || (0 == ((sgmnt_data_ptr_t)fc->op_buff)->acc_meth)))
+ GTMASSERT;
+ assert((1 != fc->op_pos) || fc->op_len <= SIZEOF_FILE_HDR(fc->op_buff));
+ switch(fc->file_type)
+ {
+ case dba_bg:
+ channel_id = gds_info->fab->fab$l_stv;
+ status = sys$qiow(EFN$C_ENF, channel_id, IO$_WRITEVBLK,
+ &iosb, NULL, 0, fc->op_buff, fc->op_len, fc->op_pos, 0, 0, 0);
+ if (SYSCALL_SUCCESS(status))
+ status = iosb.cond;
+ else
+ CHECK_CHANNEL_STATUS(status, channel_id);
+ break;
+ case dba_mm:
+ addrs[0] = fc->op_buff;
+ addrs[1] = addrs[0] + fc->op_len - 1;
+ status = sys$updsec(addrs, NULL, PSL$C_USER, 0, efn_immed_wait, &iosb, NULL, 0);
+ if (SYSCALL_SUCCESS(status))
+ {
+ status = sys$synch(efn_immed_wait, &iosb);
+ if (SS$_NORMAL == status)
+ status = iosb.cond;
+ } else if (SS$_NOTMODIFIED == status)
+ status = SS$_NORMAL;
+ break;
+ default:
+ GTMASSERT;
+ }
+ if (SYSCALL_ERROR(status))
+ rts_error(VARLSTCNT(5) ERR_DBFILOPERR, 2, gds_info->fab->fab$b_fns,
+ gds_info->fab->fab$l_fna, status);
+ break;
+ case FC_OPEN:
+ if (NULL == gds_info->fab)
+ gds_info->fab = malloc(SIZEOF(*gds_info->fab));
+
+ *gds_info->fab = cc$rms_fab;
+ gds_info->fab->fab$l_fna = gv_cur_region->dyn.addr->fname;
+ gds_info->fab->fab$b_fns = gv_cur_region->dyn.addr->fname_len;
+ gds_info->fab->fab$b_rtv = WINDOW_ALL;
+ gds_info->fab->fab$b_fac = FAB$M_BIO | FAB$M_GET | FAB$M_PUT;
+ gds_info->fab->fab$l_fop = FAB$M_UFO;
+ gds_info->fab->fab$b_shr = FAB$M_SHRPUT | FAB$M_SHRGET | FAB$M_UPI;
+ gds_info->fab->fab$l_dna = DEFDBEXT;
+ gds_info->fab->fab$b_dns = SIZEOF(DEFDBEXT) - 1;
+ if (NULL == gds_info->nam)
+ {
+ gds_info->nam = malloc(SIZEOF(*gds_info->nam));
+ *gds_info->nam = cc$rms_nam;
+ gds_info->nam->nam$l_esa = malloc(MAX_FN_LEN);
+ }
+ gds_info->nam->nam$b_ess = MAX_FN_LEN;
+ gds_info->fab->fab$l_nam = gds_info->nam;
+ if (NULL == gds_info->xabfhc)
+ gds_info->xabfhc = malloc(SIZEOF(*gds_info->xabfhc));
+ *gds_info->xabfhc = cc$rms_xabfhc;
+ gds_info->fab->fab$l_xab = gds_info->xabfhc;
+ if (NULL == gds_info->xabpro)
+ gds_info->xabpro = malloc(SIZEOF(*gds_info->xabpro));
+ *gds_info->xabpro = cc$rms_xabpro;
+ gds_info->xabfhc->xab$l_nxt = gds_info->xabpro;
+
+ gv_cur_region->read_only = FALSE; /* maintain csa->read_write simultaneously */
+ gds_info->s_addrs.read_write = TRUE; /* maintain reg->read_only simultaneously */
+ if (0 == gds_info->fab->fab$b_fns)
+ {
+ memcpy(gds_info->nam->nam$t_dvi, gds_info->file_id.dvi, SIZEOF(gds_info->nam->nam$t_dvi));
+ memcpy(gds_info->nam->nam$w_did, gds_info->file_id.did, SIZEOF(gds_info->nam->nam$w_did));
+ memcpy(gds_info->nam->nam$w_fid, gds_info->file_id.fid, SIZEOF(gds_info->nam->nam$w_fid));
+ gds_info->fab->fab$l_fop |= FAB$M_NAM;
+ } else
+ {
+ gds_info->nam->nam$b_nop = NAM$M_NOCONCEAL;
+ if (0 == (1 & (status = sys$parse(gds_info->fab, NULL, NULL))))
+ return status;
+ if (gds_info->nam->nam$b_node)
+ {
+ syi_list.ilist[0].item_code = SYI$_NODENAME;
+ syi_list.ilist[0].buffer_address = &node_name;
+ syi_list.ilist[0].buffer_length = SIZEOF(node_name);
+ syi_list.ilist[0].return_length_address = &retlen[0];
+ syi_list.ilist[1].item_code = SYI$_NODE_AREA;
+ syi_list.ilist[1].buffer_address = &node_area;
+ syi_list.ilist[1].buffer_length = SIZEOF(node_area);
+ syi_list.ilist[1].return_length_address = &retlen[1];
+ syi_list.ilist[2].item_code = SYI$_NODE_NUMBER;
+ syi_list.ilist[2].buffer_address = &node_number;
+ syi_list.ilist[2].buffer_length = SIZEOF(node_number);
+ syi_list.ilist[2].return_length_address = &retlen[2];
+ syi_list.terminator = 0;
+ status = sys$getsyiw(EFN$C_ENF, NULL, NULL, &syi_list, &iosb, NULL, 0);
+ if (SYSCALL_SUCCESS(status))
+ status = sys$fao(&ctrstr, &retlen[3], &faodsc, node_area, node_number);
+ if (SYSCALL_ERROR(status))
+ return status;
+ if (((gds_info->nam->nam$b_node - 2 != retlen[0])
+ || (0 != memcmp(gds_info->nam->nam$l_esa, node_name, retlen[0])))
+ && ((gds_info->nam->nam$b_node - 2 != retlen[3])
+ || (0 != memcmp(gds_info->nam->nam$l_esa, dnetid, retlen[3]))))
+ return ERR_NETDBOPNERR;
+
+ gds_info->fab->fab$l_fna = gds_info->nam->nam$l_esa + gds_info->nam->nam$b_node;
+ gds_info->fab->fab$b_fns = gds_info->nam->nam$b_esl - gds_info->nam->nam$b_node;
+ }
+ }
+ for (lcnt = 1; MAX_OPEN_RETRY >= lcnt; lcnt++)
+ {
+ if (RMS$_FLK != (status = sys$open(gds_info->fab, NULL, NULL)))
+ break;
+ wcs_sleep(lcnt);
+ }
+ if (SYSCALL_ERROR(status))
+ {
+ if (RMS$_PRV == status)
+ {
+ gds_info->fab->fab$b_fac = FAB$M_BIO | FAB$M_GET;
+ gv_cur_region->read_only = TRUE; /* maintain csa->read_write simultaneously */
+ gds_info->s_addrs.read_write = FALSE; /* maintain reg->read_only simultaneously */
+ gds_info->fab->fab$l_fna = gds_info->nam->nam$l_esa;
+ gds_info->fab->fab$b_fns = gds_info->nam->nam$b_esl;
+ status = sys$open(gds_info->fab);
+ }
+ if (RMS$_NORMAL != status)
+ {
+ if (RMS$_ACC == status)
+ status = gds_info->fab->fab$l_stv;
+ return status;
+ }
+ }
+ memcpy(gds_info->file_id.dvi, gds_info->nam->nam$t_dvi, SIZEOF(gds_info->nam->nam$t_dvi));
+ memcpy(gds_info->file_id.did, gds_info->nam->nam$w_did, SIZEOF(gds_info->nam->nam$w_did));
+ memcpy(gds_info->file_id.fid, gds_info->nam->nam$w_fid, SIZEOF(gds_info->nam->nam$w_fid));
+ /* Copy after removing the version number from file name */
+ fncpy_nover(gds_info->nam->nam$l_esa, gds_info->nam->nam$b_esl,
+ gv_cur_region->dyn.addr->fname, gv_cur_region->dyn.addr->fname_len);
+ gds_info->nam->nam$b_esl = gds_info->fab->fab$b_fns = gv_cur_region->dyn.addr->fname_len;
+ memcpy(gds_info->fab->fab$l_fna, gv_cur_region->dyn.addr->fname, gds_info->fab->fab$b_fns);
+ gds_info->fab->fab$l_xab = NULL;
+ gds_info->fab->fab$l_nam = NULL;
+ gds_info->xabfhc->xab$l_nxt = NULL;
+ break;
+ case FC_CLOSE:
+ status = sys$dassgn(gds_info->fab->fab$l_stv);
+ if (!(status & 1))
+ gtm_putmsg(VARLSTCNT(8) ERR_SYSCALL, 5, RTS_ERROR_LITERAL("sys$dassgn"), CALLFROM, status);
+ break;
+ default:
+ GTMASSERT;
+ }
+ return SS$_NORMAL;
+}
diff --git a/sr_vvms/dbgflip.com b/sr_vvms/dbgflip.com
new file mode 100644
index 0000000..343c696
--- /dev/null
+++ b/sr_vvms/dbgflip.com
@@ -0,0 +1,38 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2003, 2008 Fidelity Information Services, Inc !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$! dbgflip.com - turn "off" or "on" debug bit in gtm$dbg:*.exe and gtm$bta.exe (if it exists). Default is to turn "off"
+$!
+$ if p1 .eqs. ""
+$ then
+$ off_or_on = "off"
+$ else
+$ off_or_on = "''p1'"
+$ endif
+$!
+$ nodebugi := $gtm$bin:flipdebug.exe
+$!
+$bta_loop:
+$ exename = f$search("gtm$bta:*.exe")
+$ if (exename .eqs. "") then goto end_bta_loop
+$ write sys$output "nodebugi ''exename' ''off_or_on' alpha"
+$ nodebugi 'exename' 'off_or_on' alpha
+$ goto bta_loop
+$end_bta_loop:
+$
+$dbg_loop:
+$ exename = f$search("gtm$dbg:*.exe")
+$ if (exename .eqs. "") then goto end_dbg_loop
+$ write sys$output "nodebugi ''exename' ''off_or_on' alpha"
+$ nodebugi 'exename' 'off_or_on' alpha
+$ goto dbg_loop
+$end_dbg_loop:
+$
diff --git a/sr_vvms/dbinit_ch.c b/sr_vvms/dbinit_ch.c
new file mode 100644
index 0000000..53f25d2
--- /dev/null
+++ b/sr_vvms/dbinit_ch.c
@@ -0,0 +1,240 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <descrip.h>
+#include <fab.h>
+#include <iodef.h>
+#include <lckdef.h>
+#include <lkidef.h>
+#include <psldef.h>
+#include <prvdef.h>
+#include <secdef.h>
+#include <efndef.h>
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "jnl.h"
+#include "vmsdtype.h"
+#include "error.h"
+#include "locks.h"
+#include "del_sec.h"
+#include "mem_list.h"
+#include "repl_sp.h" /* for F_CLOSE (used by JNL_FD_CLOSE) */
+#include "iosp.h" /* for SS_NORMAL used by JNL_FD_CLOSE */
+#include "shmpool.h" /* needed for shmpool structures */
+#include "have_crit.h"
+
+error_def(ERR_REQRUNDOWN);
+
+GBLREF gd_region *db_init_region;
+
+CONDITION_HANDLER(dbinit_ch)
+{
+ char name_buff[GLO_NAME_MAXLEN];
+ short iosb[4];
+ uint4 last_one_status, outaddrs[2], status, lk_status;
+ int4 lock_addrs_end;
+ vms_gds_info *gds_info;
+ sgmnt_addrs *csa;
+ boolean_t read_write, is_bg;
+ vms_lock_sb *file_lksb;
+ struct
+ {
+ int4 length;
+ char value[3];
+ } state;
+ item_list_3 ilist[2];
+ uint4 prvprv1[2], prvprv2[2], prvadr[2];
+ $DESCRIPTOR(desc, name_buff);
+
+ START_CH;
+ if (SUCCESS == SEVERITY || INFO == SEVERITY)
+ {
+ PRN_ERROR;
+ CONTINUE;
+ }
+ last_one_status = 0;
+ lock_addrs_end = 0;
+ gds_info = NULL;
+ if (NULL != db_init_region->dyn.addr->file_cntl)
+ gds_info = FILE_INFO(db_init_region);
+ if (NULL != gds_info)
+ {
+ gds_info = FILE_INFO(db_init_region);
+ file_lksb = &gds_info->file_cntl_lsb;
+ csa = &gds_info->s_addrs;
+ read_write = (FALSE == db_init_region->read_only);
+ is_bg = (dba_bg == db_init_region->dyn.addr->acc_meth);
+
+ if ((NULL != csa->hdr) && (0 != csa->hdr->label[0]) && (JNL_ENABLED(csa->hdr)) && (NULL != csa->jnl))
+ {
+ if (NOJNL != csa->jnl->channel)
+ JNL_FD_CLOSE(csa->jnl->channel, status); /* sets csa->jnl->channel to NOJNL */
+ if ((NULL != csa->jnl->jnllsb) && (0 != csa->jnl->jnllsb->lockid))
+ {
+ status = gtm_deq(csa->jnl->jnllsb->lockid, NULL, PSL$C_USER, 0);
+ assert(SS$_NORMAL == status);
+ csa->jnl->jnllsb->lockid = 0;
+ }
+ }
+
+ if (0 != file_lksb->lockid)
+ {
+ /* Emulate rundown code - see if we are the last one before deleting the section */
+ /* examine which lock state we are in at first */
+ prvadr[1] = 0;
+ prvadr[0] = PRV$M_SYSLCK;
+ status = sys$setprv(TRUE, &prvadr[0], FALSE, &prvprv1[0]);
+ if (SS$_NORMAL == status)
+ {
+ prvadr[0] = PRV$M_WORLD;
+ status = sys$setprv(TRUE, &prvadr[0], FALSE, &prvprv2[0]);
+ }
+ if (SS$_NORMAL == status)
+ {
+ memset(&ilist, 0, SIZEOF(ilist));
+ ilist[0].item_code = LKI$_STATE;
+ ilist[0].buffer_length = SIZEOF(state.value);
+ ilist[0].buffer_address = &(state.value[0]);
+ ilist[0].return_length_address = &(state.length);
+ status = sys$getlkiw(EFN$C_ENF, &(file_lksb->lockid), &ilist, 0, 0, 0, 0);
+ }
+ if (SS$_NORMAL != status)
+ {
+ state.value[1] = LCK$K_NLMODE;
+ status = SS$_NORMAL;
+ }
+ if (0 == (prvprv2[0] & PRV$M_WORLD))
+ sys$setprv(FALSE, &prvadr[0], FALSE, 0);
+ prvadr[0] = PRV$M_SYSLCK;
+ if (0 == (prvprv1[0] & PRV$M_SYSLCK))
+ sys$setprv(FALSE, &prvadr[0], FALSE, 0);
+ switch (state.value[1])
+ {
+ case LCK$K_NLMODE:
+ case LCK$K_CRMODE:
+ case LCK$K_CWMODE:
+ case LCK$K_PRMODE:
+ status = gtm_enqw(EFN$C_ENF, LCK$K_PWMODE, file_lksb, LCK$M_CONVERT | LCK$M_NODLCKBLK,
+ NULL, 0, NULL, 0, NULL, PSL$C_USER, 0);
+ if (SS$_NORMAL == status)
+ status = file_lksb->cond;
+ case LCK$K_PWMODE:
+ if (SS$_NORMAL == status)
+ {
+ last_one_status = gtm_enqw(EFN$C_ENF, LCK$K_EXMODE, file_lksb,
+ LCK$M_CONVERT | LCK$M_NOQUEUE | LCK$M_NODLCKWT,
+ NULL, 0, NULL, 0, NULL, PSL$C_USER, 0);
+ if (SS$_NORMAL == last_one_status)
+ status =
+ last_one_status = file_lksb->cond;
+ }
+ }
+ if (csa->nl)
+ {
+ if ((1 == csa->nl->ref_cnt) && (ERR_REQRUNDOWN != SIGNAL) && (csa->read_write)
+ && (NULL != csa->hdr) && (FALSE == csa->hdr->clustered))
+ {
+ /* last writer and applicable to clean up the stamp in database */
+ csa->hdr->owner_node = 0;
+ memset(csa->hdr->now_running, 0, SIZEOF(csa->hdr->now_running));
+ if (0 != csa->hdr->label[0])
+ sys$qiow(EFN$C_ENF, gds_info->fab->fab$l_stv, IO$_WRITEVBLK, iosb,
+ NULL, 0, csa->hdr, SIZEOF(sgmnt_data), 1, 0, 0, 0);
+ }
+ if (!is_bg)
+ {
+ assert(csa->db_addrs[0]);
+ if (!csa->hdr)
+ csa->hdr = csa->db_addrs[0];
+ lock_addrs_end = (sm_uc_ptr_t)(csa->nl) + ROUND_UP(LOCK_SPACE_SIZE(csa->hdr)
+ + NODE_LOCAL_SPACE(csa->hdr) + JNL_SHARE_SIZE(csa->hdr)
+ + SHMPOOL_BUFFER_SIZE, OS_PAGE_SIZE) - 1;
+ }
+ if (SS$_NORMAL == last_one_status)
+ { /* Do not remove shared memory if we did not create it. */
+ if (TREF(new_dbinit_ipc))
+ {
+ global_name("GT$S", &gds_info->file_id, name_buff);
+ desc.dsc$a_pointer = &name_buff[1];
+ desc.dsc$w_length = name_buff[0];
+ desc.dsc$b_dtype = DSC$K_DTYPE_T;
+ desc.dsc$b_class = DSC$K_CLASS_S;
+ del_sec(SEC$M_SYSGBL, &desc, NULL);
+ if (!is_bg)
+ {
+ name_buff[4] = 'L';
+ del_sec(SEC$M_SYSGBL, &desc, NULL);
+ }
+ }
+ gds_info->file_cntl_lsb.valblk[0] = 0;
+ gtm_enqw(EFN$C_ENF, LCK$K_PWMODE, &gds_info->file_cntl_lsb, LCK$M_CONVERT | LCK$M_VALBLK,
+ NULL, 0, NULL, 0, NULL, PSL$C_USER, 0);
+ } else if (csa->ref_cnt)
+ { /* we incremented csa->nl->ref_cnt; so decrement it now.
+ * decrement private ref_cnt before shared ref_cnt decrement. currently journaling
+ * logic in gds_rundown() in VMS relies on this order to detect last writer
+ */
+ csa->ref_cnt--;
+ assert(!csa->ref_cnt);
+ adawi(-1, &csa->nl->ref_cnt);
+ }
+ }
+ }
+ if (NULL != csa->db_addrs[0])
+ { /* Unmap the section used by the database */
+ outaddrs[0] = csa->db_addrs[0] - OS_PAGE_SIZE; /* header no access page */
+ outaddrs[1] = csa->db_addrs[1] + OS_PAGE_SIZE; /* trailer no access page */
+ gtm_deltva(outaddrs, NULL, PSL$C_USER);
+ if ((!is_bg) && (csa->nl))
+ {
+ csa->lock_addrs[0] = (sm_uc_ptr_t)(csa->nl);
+ csa->lock_addrs[1] = lock_addrs_end;
+ assert(csa->lock_addrs[1] > csa->lock_addrs[0]);
+ gtm_deltva(csa->lock_addrs, NULL, PSL$C_USER);
+ }
+ }
+ if (0 != gds_info->file_cntl_lsb.lockid)
+ {
+ if (0 != gds_info->cx_cntl_lsb.lockid)
+ { /* if they have been granted, release the sub-locks too */
+ status = gtm_deq(gds_info->cx_cntl_lsb.lockid, NULL, PSL$C_USER, 0);
+ assert(SS$_NORMAL == status);
+ gds_info->cx_cntl_lsb.lockid = 0;
+ }
+ status = gtm_deq(gds_info->file_cntl_lsb.lockid, NULL, PSL$C_USER, 0);
+ assert(SS$_NORMAL == status);
+ gds_info->file_cntl_lsb.lockid = 0;
+ }
+ csa->hdr = NULL;
+ csa->nl = NULL;
+ if (NULL != csa->jnl)
+ {
+ free(csa->jnl);
+ csa->jnl = NULL;
+ }
+ sys$dassgn(gds_info->fab->fab$l_stv);
+ }
+ /* Reset intrpt_ok_state to OK_TO_INTERRUPT in case we got called (due to an rts_error) with intrpt_ok_state
+ * being set to INTRPT_IN_GVCST_INIT.
+ * We should actually be calling RESTORE_INTRPT_OK_STATE macro but since we don't have access to local variable
+ * save_intrpt_ok_state, set intrpt_ok_state directly.
+ */
+ assert((INTRPT_OK_TO_INTERRUPT == intrpt_ok_state) || (INTRPT_IN_GVCST_INIT == intrpt_ok_state));
+ intrpt_ok_state = INTRPT_OK_TO_INTERRUPT;
+ NEXTCH;
+}
diff --git a/sr_vvms/dcp_a2c.c b/sr_vvms/dcp_a2c.c
new file mode 100644
index 0000000..f16dfd1
--- /dev/null
+++ b/sr_vvms/dcp_a2c.c
@@ -0,0 +1,198 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <descrip.h>
+#include <secdef.h>
+#include <jpidef.h>
+#include <ssdef.h>
+#include <stddef.h>
+
+#include "ddphdr.h"
+#include "ddpcom.h"
+#include "decddp.h"
+#include "longset.h"
+#include "dcp_a2c.h"
+#include "crit_wake.h"
+#include "is_proc_alive.h"
+
+GBLDEF com_hdr_t *com_area = NULL;
+GBLDEF com_slot_t *com_ptr = NULL;
+GBLDEF int4 ddp_slot_size;
+
+GBLREF mstr my_circuit_name;
+GBLREF int4 ddp_max_rec_size;
+
+static int4 queue_retry_count = 20000;
+static boolean_t transmit_timer_expired;
+
+static condition_code init_section(boolean_t agent);
+static condition_code get_pid(int4 *pid);
+static void transmit_timer_ast(void);
+static void set_transmit_timer(void);
+
+static condition_code init_section(boolean_t agent)
+{
+ condition_code status;
+ int4 inadr[2], retadr[2], flags, com_pagcnt, nproc;
+ com_slot_t *nthslot;
+ struct dsc$descriptor section_name;
+ char section_name_buffer[] = DDP_AGENT_BUFF_NAME;
+
+ /* Global section layout ****
+ *
+ * COM_HDR <- com_area
+ * MAXIMUM_PROCESSES * COM_SLOT (slot 0 thru MAXIMUM_PROCESSES - 1) <- com_area->slot array
+ */
+ INIT_DESCRIP(section_name, section_name_buffer);
+ section_name.dsc$w_length = STR_LIT_LEN(section_name_buffer);
+ assert(DDP_CIRCUIT_NAME_LEN < section_name.dsc$w_length);
+ memcpy(§ion_name.dsc$a_pointer[section_name.dsc$w_length - DDP_CIRCUIT_NAME_LEN],
+ my_circuit_name.addr, my_circuit_name.len);
+ inadr[0] = inadr[1] = 0; /* indicates that data is to be mapped into p0 space. Does not specify starting address, as
+ * SEC$M_EXPREG is set in the flags */
+ ddp_slot_size = ROUND_UP(offsetof(com_slot_t, text[0]) + DDP_MSG_HDRLEN + ddp_max_rec_size, OS_PAGELET_SIZE);
+ assert(0 == (ddp_slot_size & 1)); /* even slot size for padding odd length outbound message */
+ com_pagcnt = DIVIDE_ROUND_UP(SIZEOF(com_hdr_t) + MAXIMUM_PROCESSES * ddp_slot_size, OS_PAGELET_SIZE);
+ flags = SEC$M_GBL | SEC$M_SYSGBL | SEC$M_WRT | SEC$M_PAGFIL | SEC$M_EXPREG | SEC$M_DZRO;
+ status = sys$crmpsc(inadr, retadr, 0, flags, §ion_name, 0, 0, 0, com_pagcnt, 0, 0, 0);
+ if (0 == (status & 1))
+ return status;
+ com_area = retadr[0];
+ if (agent && 0 == com_area->server_pid)
+ {
+ for (nproc = 0; MAXIMUM_PROCESSES > nproc; nproc++)
+ {
+ nthslot = (com_slot_t *)((unsigned char *)com_area->slot + (nproc * ddp_slot_size));
+ lib$insqti(&(nthslot->q), &(com_area->unused_slots), &queue_retry_count);
+ }
+ }
+ return status;
+}
+
+static condition_code get_pid(int4 *pid)
+{
+ condition_code status;
+ int4 item_code;
+
+ item_code = JPI$_PID;
+ status = lib$getjpi(&item_code, 0, 0, pid, 0, 0);
+ return status;
+}
+
+/* Initialize shared memory: agent's version */
+condition_code dcpa_shm_init(void)
+{
+ condition_code status;
+
+ status = init_section(TRUE);
+ if (0 == (status & 1))
+ return status;
+ status = get_pid(&(com_area->server_pid));
+ return status;
+}
+
+/* routine to get message from client...0 means there is none*/
+com_slot_t *dcpa_read(void)
+{
+ com_slot_t *p;
+
+ lib$remqhi(&(com_area->outbound_pending), &p, &queue_retry_count);
+ return (p == &(com_area->outbound_pending)) ? 0 : p;
+}
+
+void dcpa_send(com_slot_t *p)
+{
+ p->state = 0;
+ crit_wake(&(p->pid));
+ return;
+}
+
+void dcpa_free_user(com_slot_t *user)
+{
+ user->pid = 0;
+ lib$insqti(&(user->q), &(com_area->unused_slots), &queue_retry_count);
+}
+
+/* Initialize shared memory: client's version */
+condition_code dcpc_shm_init(boolean_t init_shm)
+{
+ condition_code status;
+ uint4 server;
+ error_def(ERR_DDPTOOMANYPROCS);
+ error_def(ERR_DDPNOSERVER);
+
+ if (FALSE != init_shm)
+ {
+ status = init_section(FALSE);
+ if (0 == (status & 1))
+ return status;
+ }
+ if (0 == (server = com_area->server_pid) /* server not running, client had enough privs. to create shm memory */
+ || !is_proc_alive(server, 0))
+ return ERR_DDPNOSERVER;
+ lib$remqhi(&(com_area->unused_slots), &com_ptr, &queue_retry_count);
+ if (com_ptr == &com_area->unused_slots)
+ {
+ com_ptr = NULL;
+ return ERR_DDPTOOMANYPROCS;
+ }
+ status = get_pid(&(com_ptr->pid));
+ return status;
+}
+
+/* Client routine to send-to-agent */
+void dcpc_send2agent(void)
+{
+ com_ptr->state = 1;
+ lib$insqti(&(com_ptr->q), &(com_area->outbound_pending), &queue_retry_count);
+ crit_wake(&(com_area->server_pid));
+ return;
+}
+
+static void transmit_timer_ast()
+{
+ transmit_timer_expired = TRUE;
+ sys$wake(0, 0);
+}
+
+static void set_transmit_timer(void)
+{
+ static readonly int4 timeout[2] = {-50000000, -1}; /* 5 s */
+
+ transmit_timer_expired = FALSE;
+ sys$setimr(0, timeout, transmit_timer_ast, &transmit_timer_expired, 0);
+}
+
+/* Client routine to receive from agent */
+/* Returns 1 if timed out, 0 if got some data */
+int dcpc_rcv_from_agent(void)
+{
+ set_transmit_timer();
+ while (com_ptr->state == 1)
+ {
+ sys$hiber();
+ if (transmit_timer_expired)
+ {
+ com_ptr->state = 0;
+ return 1;
+ }
+ }
+ sys$cantim(&transmit_timer_expired, 0);
+ return 0;
+}
+
+void dcpc_shm_rundown(void)
+{
+ com_ptr->pid = 0;
+ lib$insqti(&(com_ptr->q), &(com_area->unused_slots), &queue_retry_count);
+}
diff --git a/sr_vvms/dcp_a2c.h b/sr_vvms/dcp_a2c.h
new file mode 100644
index 0000000..e4f81de
--- /dev/null
+++ b/sr_vvms/dcp_a2c.h
@@ -0,0 +1,24 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2002 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef DCP_A2C_H_INCLUDED
+#define DCP_A2C_H_INCLUDED
+
+condition_code dcpa_shm_init(void);
+com_slot_t *dcpa_read(void);
+void dcpa_send(struct com_slot *p);
+void dcpa_free_user(struct com_slot *user);
+condition_code dcpc_shm_init(boolean_t init_shm);
+void dcpc_send2agent(void);
+int dcpc_rcv_from_agent(void);
+void dcpc_shm_rundown(void);
+
+#endif /* DCP_A2C_H_INCLUDED */
diff --git a/sr_vvms/dcp_get_circuit.c b/sr_vvms/dcp_get_circuit.c
new file mode 100644
index 0000000..1fd2539
--- /dev/null
+++ b/sr_vvms/dcp_get_circuit.c
@@ -0,0 +1,44 @@
+/****************************************************************
+ * *
+ * Copyright 2002 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <ssdef.h>
+#include <lnmdef.h>
+
+#include "ddphdr.h"
+#include "ddpcom.h"
+#include "decddp.h"
+#include "trans_log_name.h"
+#include "getzprocess.h"
+#include "five_bit.h"
+#include "is_five_bit.h"
+
+GBLDEF unsigned short my_circuit = 0;
+GBLDEF mstr my_circuit_name;
+static unsigned char cktnam_buff[MAX_TRANS_NAME_LEN];
+
+condition_code dcp_get_circuit(mval *logical)
+{
+ condition_code status;
+
+ error_def(ERR_DDPINVCKT);
+
+ status = trans_log_name(&logical->str, &my_circuit_name, cktnam_buff);
+ if (SS$_NORMAL == status)
+ {
+ if (DDP_CIRCUIT_NAME_LEN == my_circuit_name.len && is_five_bit(my_circuit_name.addr))
+ my_circuit = five_bit(my_circuit_name.addr);
+ else
+ status = ERR_DDPINVCKT;
+ }
+ return status;
+}
diff --git a/sr_vvms/dcp_get_groups.c b/sr_vvms/dcp_get_groups.c
new file mode 100644
index 0000000..e982ad3
--- /dev/null
+++ b/sr_vvms/dcp_get_groups.c
@@ -0,0 +1,73 @@
+/****************************************************************
+ * *
+ * Copyright 2002 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_ctype.h"
+
+#include <ssdef.h>
+#include <lnmdef.h>
+
+#include "ddphdr.h"
+#include "ddpcom.h"
+#include "decddp.h"
+#include "trans_log_name.h"
+
+GBLREF unsigned short my_group_mask;
+GBLREF mstr my_circuit_name;
+
+condition_code dcp_get_groups(void)
+{
+ char *grpp, *grpp_top, digit;
+ char group_list_buffer[MAX_TRANS_NAME_LEN], group_logical_buffer[MAX_TRANS_NAME_LEN];
+ mstr group_list, group_logical;
+ condition_code status;
+ int group;
+ unsigned short group_mask;
+
+ assert(DDP_DEFAULT_GROUP_MASK == my_group_mask); /* this function should be called only once, this is a crude check */
+ group_logical.addr = group_logical_buffer;
+ memcpy(group_logical.addr, DDP_GROUP_LOGICAL_PREFIX, STR_LIT_LEN(DDP_GROUP_LOGICAL_PREFIX));
+ memcpy(&group_logical.addr[STR_LIT_LEN(DDP_GROUP_LOGICAL_PREFIX)], my_circuit_name.addr, my_circuit_name.len);
+ group_logical.len = STR_LIT_LEN(DDP_GROUP_LOGICAL_PREFIX) + my_circuit_name.len;
+ if (SS$_NORMAL != (status = trans_log_name(&group_logical, &group_list, group_list_buffer)))
+ {
+ if (SS$_NOLOGNAM == status)
+ status = SS$_NORMAL;
+ return status;
+ }
+ for (group = 0, group_mask = 0, grpp = group_list.addr, grpp_top = group_list.addr + group_list.len;
+ grpp < grpp_top;
+ grpp++, group = 0)
+ {
+ if (',' == *grpp)
+ continue;
+ do
+ {
+ digit = *grpp;
+ if (ISDIGIT(digit))
+ group = (group * 10 + digit - '0');
+ else
+ break;
+ } while (++grpp < grpp_top);
+ if (',' == digit || grpp == grpp_top)
+ {
+ if (DDP_MAX_GROUP > group)
+ group_mask |= (1 << group);
+ } else
+ { /* skip to the next group */
+ while (++grpp < grpp_top && ',' != *grpp)
+ ;
+ }
+ }
+ my_group_mask = group_mask;
+ return SS$_NORMAL;
+}
diff --git a/sr_vvms/dcp_get_maxrecsize.c b/sr_vvms/dcp_get_maxrecsize.c
new file mode 100644
index 0000000..face3ea
--- /dev/null
+++ b/sr_vvms/dcp_get_maxrecsize.c
@@ -0,0 +1,50 @@
+/****************************************************************
+ * *
+ * Copyright 2002 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <ssdef.h>
+#include <lnmdef.h>
+#include <stddef.h>
+
+#include "ddphdr.h"
+#include "ddpcom.h"
+#include "decddp.h"
+#include "trans_log_name.h"
+#include "getzprocess.h"
+#include "five_bit.h"
+#include "is_five_bit.h"
+
+GBLDEF int4 ddp_max_rec_size;
+GBLREF mstr my_circuit_name;
+
+condition_code dcp_get_maxrecsize(void)
+{
+ mstr recsize, recsize_logical;
+ char recbuff[MAX_TRANS_NAME_LEN], recsize_logical_buffer[MAX_TRANS_NAME_LEN];
+ condition_code status;
+ error_def(ERR_DDPRECSIZNOTNUM);
+
+ recsize_logical.addr = recsize_logical_buffer;
+ memcpy(recsize_logical.addr, DDP_MAXRECSIZE_PREFIX, STR_LIT_LEN(DDP_MAXRECSIZE_PREFIX));
+ memcpy(&recsize_logical.addr[STR_LIT_LEN(DDP_MAXRECSIZE_PREFIX)], my_circuit_name.addr, my_circuit_name.len);
+ recsize_logical.len = STR_LIT_LEN(DDP_MAXRECSIZE_PREFIX) + my_circuit_name.len;
+ if (SS$_NORMAL == (status = trans_log_name(&recsize_logical, &recsize, recbuff)))
+ {
+ if (-1 != (ddp_max_rec_size = asc2i(recbuff, recsize.len)))
+ {
+ if (DDP_MIN_RECSIZE > ddp_max_rec_size)
+ ddp_max_rec_size = DDP_MIN_RECSIZE;
+ } else
+ status = ERR_DDPRECSIZNOTNUM;
+ }
+ return status;
+}
diff --git a/sr_vvms/dcp_get_volsets.c b/sr_vvms/dcp_get_volsets.c
new file mode 100644
index 0000000..ee4be7b
--- /dev/null
+++ b/sr_vvms/dcp_get_volsets.c
@@ -0,0 +1,163 @@
+/****************************************************************
+ * *
+ * Copyright 2002, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_stdio.h"
+#include "gtm_string.h"
+
+#include <ssdef.h>
+#include <lnmdef.h>
+#include <descrip.h>
+#include <fab.h>
+#include <rms.h>
+#include <iodef.h>
+#include <errno.h>
+
+#include "ddphdr.h"
+#include "ddpcom.h"
+#include "five_bit.h"
+#include "is_five_bit.h"
+#include "eintr_wrappers.h"
+
+GBLREF mstr my_circuit_name;
+static int vug_parse(char *line, unsigned short *vol, unsigned short *uci, mstr *gld);
+
+static int vug_parse(char *line, unsigned short *vol, unsigned short *uci, mstr *gld)
+{
+ char *begin, esa[MAX_FN_LEN];
+ struct FAB fab;
+ struct NAM nam;
+
+ error_def(ERR_DDPCONFGOOD);
+ error_def(ERR_DDPCONFIGNORE);
+ error_def(ERR_DDPCONFINCOMPL);
+ error_def(ERR_DDPCONFBADVOL);
+ error_def(ERR_DDPCONFBADUCI);
+ error_def(ERR_DDPCONFBADGLD);
+
+ for (; '\0' != *line && ISSPACE(*line); line++) /* skip over leading spaces */
+ ;
+ if ('\0' == *line || VUG_CONFIG_COMMENT_CHAR == *line) /* ignore empty or comment line */
+ return ERR_DDPCONFIGNORE;
+ for (begin = line++; '\0' != *line && !ISSPACE(*line); line++) /* look for beginning of volume */
+ ;
+ if ('\0' == *line) /* end of line when volume expected */
+ return ERR_DDPCONFINCOMPL;
+ if (DDP_VOLUME_NAME_LEN != line - begin || !is_five_bit(begin)) /* valid volume spec? */
+ return ERR_DDPCONFBADVOL;
+ *vol = five_bit(begin);
+ for (line++; '\0' != *line && ISSPACE(*line); line++) /* skip over spaces; look for uci */
+ ;
+ if ('\0' == *line) /* end of line when uci expected */
+ return ERR_DDPCONFINCOMPL;
+ for (begin = line++; '\0' != *line && !ISSPACE(*line); line++) /* find end of uci spec */
+ ;
+ if ('\0' == *line) /* line ends with uci, gld not in the configuration */
+ return ERR_DDPCONFINCOMPL;
+ if (DDP_UCI_NAME_LEN != line - begin || !is_five_bit(begin)) /* valid uci spec? */
+ return ERR_DDPCONFBADUCI;
+ *uci = five_bit(begin);
+ for (line++; '\0' != *line && ISSPACE(*line); line++) /* skip over spaces, find beginning of gld */
+ ;
+ if ('\0' == *line) /* end of line when gld expected */
+ return ERR_DDPCONFINCOMPL;
+ for (begin = line++; '\0' != *line && !ISSPACE(*line); line++) /* find end of gld */
+ ;
+ gld->addr = begin;
+ gld->len = line - begin;
+ /* valid file specified for gld? */
+ fab = cc$rms_fab;
+ nam = cc$rms_nam;
+ nam.nam$b_nop = NAM$M_SYNCHK;
+ fab.fab$l_nam = &nam;
+ fab.fab$l_fop = FAB$M_NAM;
+ fab.fab$l_fna = gld->addr;
+ fab.fab$b_fns = gld->len;
+ nam.nam$l_esa = esa;
+ nam.nam$b_ess = SIZEOF(esa);
+ if (RMS$_NORMAL != sys$parse(&fab, 0, 0))
+ return ERR_DDPCONFBADGLD;
+ return ERR_DDPCONFGOOD;
+}
+
+condition_code dcp_get_volsets(void)
+{
+ char vug_conf_buffer[MAX_TRANS_NAME_LEN], vug_logical_buffer[MAX_TRANS_NAME_LEN];
+ mstr vug_conf, vug_logical;
+ condition_code status;
+ int volset_count, line_no, parse_status;
+ unsigned short vol, uci;
+ char *line_p;
+ char line[BUFSIZ];
+ FILE *vol_fp;
+ mstr gld;
+ char err_str[1024];
+
+ error_def(ERR_DDPVOLSETCONFIG);
+ error_def(ERR_DDPCONFGOOD);
+ error_def(ERR_DDPCONFIGNORE);
+
+ vug_logical.addr = vug_logical_buffer;
+ memcpy(vug_logical.addr, DDP_VOLSET_CONF_LOGICAL_PREFIX, STR_LIT_LEN(DDP_VOLSET_CONF_LOGICAL_PREFIX));
+ memcpy(&vug_logical.addr[STR_LIT_LEN(DDP_VOLSET_CONF_LOGICAL_PREFIX)], my_circuit_name.addr, my_circuit_name.len);
+ vug_logical.len = STR_LIT_LEN(DDP_VOLSET_CONF_LOGICAL_PREFIX) + my_circuit_name.len;
+ if (SS$_NORMAL != (status = trans_log_name(&vug_logical, &vug_conf, vug_conf_buffer)))
+ {
+ decddp_log_error(status, "Volume Set Configuration File logical translation failed", 0, 0);
+ return status;
+ }
+ vug_conf.addr[vug_conf.len] = '\0';
+ if (NULL == (vol_fp = Fopen(vug_conf.addr, "r")))
+ {
+ SNPRINTF(err_str, SIZEOF(err_str), "Volume Set Configuration File %s open error : %s", vug_conf.addr,
+ strerror(errno));
+ decddp_log_error(ERR_DDPVOLSETCONFIG, err_str, 0, 0);
+ return ERR_DDPVOLSETCONFIG;
+ }
+ /* Read lines from the configuration file and set up volset_table */
+ for (line_no = 1, volset_count = 0; DDP_MAX_VOLSETS > volset_count; line_no++)
+ {
+ FGETS_FILE(line, BUFSIZ, vol_fp, line_p);
+ if (NULL != line_p)
+ {
+ if (ERR_DDPCONFGOOD == (parse_status = vug_parse(line_p, &vol, &uci, &gld)))
+ {
+ if (FALSE != enter_vug(vol, uci, &gld))
+ volset_count++;
+ } else if (ERR_DDPCONFIGNORE != parse_status)
+ {
+ SNPRINTF(err_str, SIZEOF(err_str),
+ "Incomplete or invalid configuration entry at line %d of file %s", line_no,
+ vug_conf.addr);
+ decddp_log_error(parse_status, err_str, 0, 0);
+ }
+ } else if (feof(vol_fp))
+ break;
+ else /* ferror(vol_fp) */
+ {
+ SNPRINTF(err_str, SIZEOF(err_str), "Volume Set Configuration File %s read error : %s", vug_conf.addr,
+ strerror(errno));
+ decddp_log_error(ERR_DDPVOLSETCONFIG, err_str, 0, 0);
+ fclose(vol_fp);
+ return ERR_DDPVOLSETCONFIG;
+ }
+ }
+ fclose(vol_fp);
+ if (0 == volset_count)
+ {
+ SNPRINTF(err_str, SIZEOF(err_str), "Volume Set Configuration File %s does not contain any valid VOL UCI GLD triple",
+ vug_conf.addr);
+ decddp_log_error(ERR_DDPVOLSETCONFIG, err_str, 0, 0);
+ return ERR_DDPVOLSETCONFIG;
+ }
+ return SS$_NORMAL;
+}
diff --git a/sr_vvms/dcpsubs.c b/sr_vvms/dcpsubs.c
new file mode 100644
index 0000000..c5fd9ad
--- /dev/null
+++ b/sr_vvms/dcpsubs.c
@@ -0,0 +1,180 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2004 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_limits.h"
+
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+
+#include "ddphdr.h"
+#include "ddpcom.h"
+#include "dcpsubs.h"
+
+#define SUBS_OUT(X) (is_negative ? ('9' - (X)) : ((X) + '0'))
+
+
+/********************************************
+* DCPSUBS.C
+*
+* Convert GT.M global reference to DSM global reference
+********************************************/
+
+boolean_t dcp_g2d(unsigned char **inptradr, unsigned char **outptradr, int outbuflen, unsigned char *naked_size_p)
+/*
+unsigned char **inptradr; Address of pointer to GT.M global reference to be converted
+unsigned char **outptradr; Address of pointer to DSM global reference buffer
+unsigned char *naked_size_p; Address where to store naked_size
+*/
+
+/* Upon return: the pointers pointed to by inptradr and outptradr are updated.
+ If the return value is true then the conversion was completely successful.
+ If false, then the conversion was completed to the extend possible. However,
+ there was a non-convertable character, such as an embedded null.
+*/
+{
+ unsigned char *ipt, *opt, *start_out, *opt_top;
+ unsigned char ch;
+ boolean_t succeeded;
+ int expval, outexp, digit;
+ boolean_t is_negative;
+ error_def(ERR_DDPSUBSNUL);
+ error_def(ERR_GVSUBOFLOW);
+
+ /* Work with local copies of the pointers, as there are otherwise two
+ levels of de-referencing involved
+ */
+ ipt = *inptradr;
+ opt = start_out = *outptradr;
+ opt_top = opt + outbuflen;
+ /* The 'succeeded' flag indicates whether the conversion was performed
+ with complete success. It is initialized to 'TRUE'. If at any time,
+ the program detects that the conversion will not be 100% accurate, the
+ variable will be set to 'FALSE'.
+ */
+ succeeded = TRUE;
+ /* The variable 'ch' will always contain the current character that we are
+ working on.
+ */
+ /* Do global name in 7-bit format first */
+ while (KEY_DELIMITER != (ch = *ipt++) && opt < opt_top)
+ *opt++ = (ch << 1) + 1;
+ if (KEY_DELIMITER == ch)
+ *(opt - 1) &= ~1; /* the last byte of the global has bit 0 cleared, all others have bit 0 set */
+ else
+ rts_error(VARLSTCNT(1) ERR_GVSUBOFLOW);
+ while (KEY_DELIMITER != (ch = *ipt++) && opt < opt_top)
+ {
+ if (UCHAR_MAX < opt - start_out)
+ rts_error(VARLSTCNT(1) ERR_GVSUBOFLOW);
+ *naked_size_p = opt - start_out;
+ if (STR_SUB_PREFIX == ch || (SUBSCRIPT_STDCOL_NULL == ch && KEY_DELIMITER == *ipt))
+ { /* GT.M subscript is a string subscript */
+ ch = *ipt++;
+ if (KEY_DELIMITER == ch) /* If input subscript is null, make output subscript null */
+ *opt++ = 1; /* 1 is special indicator for null string */
+ else
+ { /* Non-null string is here */
+ assert(STR_SUB_PREFIX == *(ipt -2));
+ *opt++ = 0xFE; /* FE is indication that non-null string follows */
+ for ( ; 0 != ch && opt < opt_top; ch = *ipt++)
+ {
+ if (1 == ch)
+ { /* Decode GT.M style control characters */
+ if (0 == (ch = (*ipt++ - 1)))
+ rts_error(VARLSTCNT(1) ERR_DDPSUBSNUL);
+ }
+ *opt++ = ch;
+ }
+ if (0 != ch)
+ rts_error(VARLSTCNT(1) ERR_GVSUBOFLOW);
+ }
+ } else
+ { /* GT.M subscript is a numeric subscript */
+ if (0x80 == ch)
+ { /* Special case: input value is zero */
+ if (opt + 1 < opt_top) /* need two bytes */
+ {
+ *opt++ = 0x80;
+ *opt++ = '0';
+ ipt++;
+ } else
+ rts_error(VARLSTCNT(1) ERR_GVSUBOFLOW);
+ } else
+ {
+ is_negative = (0 == (ch & 0x80));
+ if (is_negative)
+ ch = ~ch;
+ expval = (ch & 0x7f);
+ expval -= 0x3F; /* Remove bias */
+ /* For DSM, all negative exponents are = 0x81 */
+ if (-1 > expval)
+ outexp = -1;
+ else
+ outexp = expval;
+ /* 1 collation byte + 1 decimal point + expval zeros + max 18 digits + trailer if negative */
+ if ((1 + 1 + (0 > expval ? -expval : expval) + 2 * (MAX_NUM_SUBSC_LEN - 1) + (is_negative ? 1 : 0))
+ > opt_top - opt) /* stricter check than necessary, the number might not be all of 18 digits */
+ rts_error(VARLSTCNT(1) ERR_GVSUBOFLOW);
+ *opt++ = is_negative ? (0x7e - outexp) : outexp + 0x82;
+ if (-1 > expval) /* Leading decimal point? */
+ { /* Yes, output decimal point and leading zeros */
+ *opt++ = '.';
+ for (digit = expval; 0 > ++digit; )
+ *opt++ = SUBS_OUT(0);
+ }
+ while (0 != (ch = *ipt++) && STR_SUB_PREFIX != ch)
+ { /* Output mantissa */
+ if (is_negative)
+ ch = ~ch;
+ ch--;
+ if (-1 == expval--)
+ *opt++ = '.';
+ digit = (ch >> 4); /* upper nibble */
+ *opt++ = SUBS_OUT(digit);
+ if (-1 == expval--)
+ *opt++ = '.';
+ digit = (ch & 0xF); /* lower nibble */
+ *opt++ = SUBS_OUT(digit);
+ }
+ if (STR_SUB_PREFIX == ch && KEY_DELIMITER == *ipt) /* at end of negative subscript */
+ ipt++; /* increment past trailing zero byte */
+ if (expval < -1)
+ { /* Trim possible trailing zero and possible "." */
+ if (*(opt - 1) == SUBS_OUT(0))
+ opt--;
+ if ('.' == *(opt - 1))
+ opt--;
+ } else
+ { /* Output trailing zeroes, if any */
+ for ( ; 0 <= expval; expval--)
+ *opt++ = SUBS_OUT(0);
+ }
+ /* negative subscripts have a FE trailer */
+ if (is_negative)
+ *opt++ = 0xFE;
+ }
+ }
+ if (opt < opt_top)
+ *opt++ = 0;
+ else
+ rts_error(VARLSTCNT(1) ERR_GVSUBOFLOW);
+ }
+ /* Operation completed, clean-up and return */
+ *outptradr = opt;
+ *inptradr = ipt;
+ return succeeded;
+}
diff --git a/sr_vvms/dcpsubs.h b/sr_vvms/dcpsubs.h
new file mode 100644
index 0000000..59792df
--- /dev/null
+++ b/sr_vvms/dcpsubs.h
@@ -0,0 +1,17 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2002 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef DCPSUBS_H_INCLUDED
+#define DCPSUBS_H_INCLUDED
+
+boolean_t dcp_g2d(unsigned char **inptradr, unsigned char **outptradr, int outbuflen, unsigned char *naked_size_p);
+
+#endif /* DCPSUBS_H_INCLUDED */
diff --git a/sr_vvms/ddp_db_op.c b/sr_vvms/ddp_db_op.c
new file mode 100644
index 0000000..6068617
--- /dev/null
+++ b/sr_vvms/ddp_db_op.c
@@ -0,0 +1,348 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2002 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_ctype.h"
+#include "gtm_time.h"
+
+#include <descrip.h>
+
+#include "ddphdr.h"
+#include "ddpcom.h"
+#include "decddp.h"
+#include "route_table.h"
+#include "subscript.h"
+#include "seven_2_ascii.h"
+
+#define DDP_LOG_ZSTATUS \
+{ \
+ gtm$zstatus(&ddp_result); \
+ DDP_LOG_ERROR(ddp_result.dsc$w_length, ddp_result.dsc$a_pointer); \
+}
+
+GBLDEF int4 subscript_count;
+GBLDEF struct dsc$descriptor ddp_result;
+GBLDEF struct dsc$descriptor subscript_array[1 + 1 + 1 + MAX_GVSUBSCRIPTS]; /* worst case (SET operation) -
+ * 1 - input data (for SET)
+ * 1 - global directory
+ * 1 - global name
+ * MAX_GVSUBSCRIPTS - max # subscripts
+ */
+GBLREF bool dec_nofac;
+error_def(ERR_ZGBLDIRACC);
+error_def(ERR_DBOPNERR);
+error_def(ERR_GVUNDEF);
+error_def(ERR_REC2BIG);
+error_def(ERR_LCKSTIMOUT);
+error_def(ERR_DDPOUTMSG2BIG);
+error_def(ERR_DDPLOGERR);
+
+void gtm$zstatus(struct dsc$descriptor *zstatus);
+
+static unsigned char spool[MAX_ETHER_DATA_SIZE];
+
+char *ddp_db_op(
+ struct in_buffer_struct *bp,
+ condition_code (*func)(), /* function to dispatch to*/
+ unsigned char *addr, /* if == 0, then receive the result in 'ddp_result'
+ if == 1, then there is no result
+ if > 1, set the first descriptor to be equal to the data pointed to at addr */
+ int len) /* if addr > 1, then this is the length of the data to set-up */
+{
+ ddp_hdr_t *dp; /* pointer to input buffer */
+ unsigned char *cp, *inkeyptr, *keytop, *extref;
+ int ch, index, length, jobno, subscript_type, bufavail, gtm_prefix_len;
+ condition_code status;
+ routing_tab *remote_node;
+ mstr *gld;
+ ddp_global_request_t *gp;
+
+ dp = &bp->dh;
+ gp = dp->txt;
+ jobno = dp->source_job_number;
+ assert((2 <= jobno) && (0 == (jobno & 1)));
+ jobno >>= 1;
+ jobno -= 1;
+ assert(0 <= jobno && MAX_USERS_PER_NODE >= jobno);
+ if (NULL == (remote_node = find_route(dp->source_circuit_name))) /* couldn't find sender in our tables */
+ return "";
+ if (dp->message_number > remote_node->incoming_users[jobno] + 1) /* sequencing error, incoming message number is too big */
+ return "";
+ remote_node->incoming_users[jobno] = dp->message_number;
+ /* Vinaya, 07/11/02 - Based on ether traces, we noticed that the field global_type is always 0x02. Since we don't know
+ * what 0x02 really means, we don't want to sanity check the incoming message for the value of this field in the
+ * incoming message. Hence the disabling of the check. Note, the check had been disabled before the DDP revamp
+ * exercise in 2002. */
+/*** temorarily noop this
+* if (DDP_GLOBAL_TYPE != gp->global_type)
+* return "<FORMT>";
+*****/
+ cp = spool;
+ subscript_count = 0; /* incremented after every add of a subscript to subscript_array.
+ * this is usually done with the INIT_DESCRIP and DESCRIP_LENGTH usage */
+ if (addr > (char *)1)
+ { /* set-up pointer to input data */
+ INIT_DESCRIP(subscript_array[subscript_count], addr);
+ subscript_array[subscript_count].dsc$w_length = len;
+ subscript_count++;
+ }
+ /* set-up global directory */
+ INIT_DESCRIP(subscript_array[subscript_count], cp);
+ if (NULL != (gld = find_gld(gp->vol, gp->uci)))
+ {
+ memcpy(cp, gld->addr, gld->len);
+ cp += gld->len;
+ } else
+ return "<NOUCI>";
+ DESCRIP_LENGTH(subscript_array[subscript_count], cp);
+ subscript_count++;
+ inkeyptr = gp->global;
+ keytop = inkeyptr + (int)gp->global_len;
+ if (keytop > (char *)dp + dp->message_length) /* check to see that key length doesnt send us off the end of the record */
+ return "<FORMT>";
+ /* set-up global name */
+ INIT_DESCRIP(subscript_array[subscript_count], cp);
+ length = seven_2_ascii(inkeyptr, cp);
+ cp += length;
+ inkeyptr += length;
+ if (inkeyptr > keytop)
+ return "<FORMT>";
+ DESCRIP_LENGTH(subscript_array[subscript_count], cp);
+ subscript_count++;
+ /* set-up subscripts */
+ /* our subscript format takes less space than DSM's subscript format; so we don't have to check for buffer overflow */
+ for ( ; inkeyptr < keytop; )
+ {
+ subscript_type = *inkeyptr++;
+ if (1 < subscript_type && 0x80 > subscript_type)
+ {
+ subscript_type = 0x7F - subscript_type;
+ *--inkeyptr = '-';
+ INIT_DESCRIP(subscript_array[subscript_count], inkeyptr);
+ inkeyptr++;
+ while(subscript_type--)
+ {
+ ch = *inkeyptr;
+ ch = 0x69 - ch;
+ assert(ISDIGIT(ch));
+ *inkeyptr++ = ch;
+ }
+ assert('.' == *inkeyptr || 0xFE == *inkeyptr);
+ if ('.' == *inkeyptr)
+ inkeyptr++;
+ while (0xFE != (ch = *inkeyptr))
+ {
+ ch = 0x69 - ch;
+ assert(ISDIGIT(ch));
+ *inkeyptr++ = ch;
+ }
+ inkeyptr++;
+ DESCRIP_LENGTH(subscript_array[subscript_count], inkeyptr - 1);
+ subscript_count++;
+ assert('\0' != *inkeyptr);
+ inkeyptr++;
+ } else
+ {
+ INIT_DESCRIP(subscript_array[subscript_count], inkeyptr);
+ while ('\0' != *inkeyptr++)
+ ;
+ DESCRIP_LENGTH(subscript_array[subscript_count], inkeyptr - 1);
+ subscript_count++;
+ }
+ if (inkeyptr > keytop)
+ return "<FORMT>";
+ }
+ /* perform operation */
+ status = ddp_dal_dispatch(func, (addr == 0) ? &ddp_result : NULL);
+ if (0 == (status & 1))
+ {
+ DDP_LOG_ZSTATUS;
+ if (status == ERR_GVUNDEF)
+ return "<UNDEF>";
+ if (status == ERR_ZGBLDIRACC)
+ return "<NOUCI>";
+ if (status == ERR_DBOPNERR)
+ return "<DKHER>";
+/****** This is displayed as a SYNTX error
+ if (status == ERR_REC2BIG)
+ return "<MXSTR>";
+********/
+ /*default:*/
+ decddp_log_error(status, "Undecoded status message, returned as <DBDGD>", &bp->dh.source_circuit_name,
+ &bp->dh.source_job_number);
+ return "<DBDGD>";
+ }
+ /* This is the message received from the client, so reply to the source of this message */
+ decddp_shdr(DDPTR_RESPONSE, 1, dp->source_circuit_name, dp->source_job_number, dp->message_number, bp->fh.source_address);
+ if (NULL == addr && 0 < ddp_result.dsc$w_length)
+ { /* note, input buffer and output buffer are different and so we can test the incoming message header fields */
+ bufavail = decddp_bufavail();
+ if (DDPTR_QUERY != dp->trancode && bufavail > ddp_result.dsc$w_length)
+ decddp_s8bit_counted(ddp_result.dsc$a_pointer, ddp_result.dsc$w_length);
+ else if (DDPTR_QUERY == dp->trancode &&
+ bufavail > DSM_EXTREF_FORM_LEN + ddp_result.dsc$w_length -
+ (gtm_prefix_len = STR_LIT_LEN(GTM_EXTREF_PREFIX) + gld->len + STR_LIT_LEN(GTM_EXTREF_SUFFIX)))
+ { /* form of extref is ^|"globaldirectory"|global */
+ /* form of extref should be ^["UCI","VOL"]global */
+ extref = ddp_result.dsc$a_pointer;
+ assert(0 == memcmp(extref, GTM_EXTREF_PREFIX, STR_LIT_LEN(GTM_EXTREF_PREFIX)));
+ assert(0 == memcmp(&extref[STR_LIT_LEN(GTM_EXTREF_PREFIX)], gld->addr, gld->len));
+ assert(0 == memcmp(&extref[STR_LIT_LEN(GTM_EXTREF_PREFIX) + gld->len], GTM_EXTREF_SUFFIX,
+ STR_LIT_LEN(GTM_EXTREF_SUFFIX)));
+ decddp_s8bit_counted(LIT_AND_LEN(DSM_EXTREF_PREFIX));
+ decddp_s5asc(gp->uci);
+ decddp_s8bit_counted(LIT_AND_LEN(DSM_UCI_VOL_SEPARATOR));
+ decddp_s5asc(gp->vol);
+ decddp_s8bit_counted(LIT_AND_LEN(DSM_EXTREF_SUFFIX));
+ decddp_s8bit_counted(&extref[gtm_prefix_len], ddp_result.dsc$w_length - gtm_prefix_len);
+ } else /* result is larger than our outbound buffer size */
+ {
+ decddp_log_error(ERR_DDPOUTMSG2BIG, "Undecoded status message, returned as <DBDGD>",
+ &bp->dh.source_circuit_name, &bp->dh.source_job_number);
+ return "<DBDGD>";
+ }
+ }
+ decddp_putbyte(DDP_MSG_TERMINATOR);
+ return NULL;
+}
+
+char *ddp_lock_op(
+ struct in_buffer_struct *bptr,
+ condition_code (*func)(), /* function to dispatch to*/
+ int unlock_code) /* if =1, then this is an unlock */
+{
+ ddp_hdr_t *dp; /* pointer to input buffer */
+ unsigned char *bp, *btop, *uci_p, *vol_p;
+ unsigned char *cp;
+ int ch, jobno;
+ condition_code status;
+ boolean_t success;
+ routing_tab *remote_node;
+ auxvalue aux;
+ mstr *gld;
+
+ dp = &bptr->dh;
+ jobno = dp->source_job_number;
+ assert((2 <= jobno) && (0 == (jobno & 1)));
+ jobno >>= 1;
+ jobno -= 1;
+ assert(0 <= jobno && MAX_USERS_PER_NODE >= jobno);
+ if (NULL == (remote_node = find_route(dp->source_circuit_name))) /* couldn't find sender in our tables */
+ return "";
+ if (dp->message_number > remote_node->incoming_users[jobno] + 1) /* sequencing error, incoming message number is too big */
+ return "";
+ remote_node->incoming_users[jobno] = dp->message_number;
+ bp = dp->txt;
+ btop = (char *)dp + dp->message_length - 1;
+ if ('^' != *bp++ || '[' != *bp++ || '\"' != *bp++)
+ return "<FORMT>";
+ subscript_count = 0; /* incremented after every add of a subscript to subscript_array.
+ * this is usually done with the INIT_DESCRIP and DESCRIP_LENGTH usage */
+ cp = spool;
+ /* set-up global directory */
+ INIT_DESCRIP(subscript_array[subscript_count], cp);
+ uci_p = bp;
+ bp += DDP_UCI_NAME_LEN;
+ if (*bp++ != '\"' || *bp++ != ',' || *bp++ != '\"')
+ return "<FORMT>";
+ vol_p = bp;
+ bp += DDP_VOLUME_NAME_LEN;
+ if (*bp++ != '\"' || *bp++ != ']')
+ return "<FORMT>";
+ if (NULL != (gld = find_gld(five_bit(vol_p), five_bit(uci_p))))
+ {
+ memcpy(cp, gld->addr, gld->len);
+ cp += gld->len;
+ } else
+ return "<NOUCI>";
+ DESCRIP_LENGTH(subscript_array[subscript_count], cp);
+ subscript_count++;
+ /* Load global name */
+ if (bp > btop)
+ return "<FORMT>";
+ INIT_DESCRIP(subscript_array[subscript_count], bp);
+ for (; '(' != *bp && bp < btop; bp++)
+ ;
+ DESCRIP_LENGTH(subscript_array[subscript_count], bp);
+ subscript_count++;
+ if (bp < btop && '(' != *bp++)
+ return "<FORMT>";
+ for ( ; bp < btop; )
+ {
+ ch = *bp++;
+ if (')' == ch)
+ break;
+ if ('\"' != ch)
+ {
+ INIT_DESCRIP(subscript_array[subscript_count], bp - 1);
+ if ('-' == ch)
+ ch = *bp++;
+ for (; ;)
+ {
+ ch = *bp++;
+ if (bp > btop)
+ break;
+ if (ISDIGIT(ch) || ch == '.')
+ continue;
+ break;
+ }
+ DESCRIP_LENGTH(subscript_array[subscript_count], bp - 1);
+ subscript_count++;
+ } else
+ {
+ INIT_DESCRIP(subscript_array[subscript_count], bp);
+ for (; ;)
+ {
+ ch = *bp++;
+ if ('\"' == ch)
+ { /* CAUTION: MUST REMOVE DOUBLE QUOTES */
+ ch = *bp++;
+ if ('\"' != ch)
+ break;
+ }
+ }
+ DESCRIP_LENGTH(subscript_array[subscript_count], bp - 2);
+ subscript_count++;
+ }
+ if (')' == ch)
+ break;
+ if (',' != ch || ch >= btop)
+ return "<FORMT>";
+ }
+ success = TRUE;
+ aux.as.circuit = dp->source_circuit_name;
+ aux.as.job = jobno;
+ status = ddp_lock_dispatch(func, unlock_code, aux.auxid);
+ if (0 == (status & 1))
+ {
+ if (status == ERR_LCKSTIMOUT)
+ success = FALSE;
+ else
+ {
+ DDP_LOG_ZSTATUS;
+ if (ERR_ZGBLDIRACC == status)
+ return "<NOUCI>";
+ if (ERR_DBOPNERR == status)
+ return "<DKHER>";
+ /*default:*/
+ decddp_log_error(status, "Undecoded status message, returned as <DBDGD>", &bptr->dh.source_circuit_name,
+ &bptr->dh.source_job_number);
+ return "<DBDGD>";
+ }
+ }
+ /* This is the message received from the client, so reply to the source of this message */
+ decddp_shdr(DDPTR_RESPONSE, 1, dp->source_circuit_name, dp->source_job_number, dp->message_number, bptr->fh.source_address);
+ if (!unlock_code)
+ decddp_putbyte(success ? 'S' : 'F');
+ decddp_putbyte(DDP_MSG_TERMINATOR);
+ return NULL;
+}
diff --git a/sr_vvms/ddp_spkitbld.dat b/sr_vvms/ddp_spkitbld.dat
new file mode 100644
index 0000000..21005b1
--- /dev/null
+++ b/sr_vvms/ddp_spkitbld.dat
@@ -0,0 +1,6 @@
+SPKITBLD$KITNAME := GTCD60002
+SPKITBLD$REWIND_TAPE := N
+SPKITBLD$AUTOINIT_TAPE := 'GTM_INIT_TAPE'
+SPKITBLD$SKIP_FIRST_TAPE_READY_PROMPT := Y
+SPKITBLD$SKIP_FIRST_DISK_READY_PROMPT := Y
+SPKITBLD$SAVESET_A := GTM$VRT:[TDP]KITINSTAL.COM;,DDPKITHLP.COM;,GTM$VRT:[PRO]DDPSERVER.EXE;,GTM$VRT:[PRO]DDPGVUSR.EXE;,GTM$VRT:[PRO]GTCMDDPSTOP.EXE;
diff --git a/sr_vvms/ddp_trace_output.c b/sr_vvms/ddp_trace_output.c
new file mode 100644
index 0000000..ec03155
--- /dev/null
+++ b/sr_vvms/ddp_trace_output.c
@@ -0,0 +1,52 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2002 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gtm_string.h"
+
+#define D2HEX(X) (((X) < 10) ? (X) + '0' : (X) - 10 + 'A')
+#define BYTES_PER_LINE 32
+
+char *ddp_trace_prefix[] =
+{
+ "-> ", /* DDP_SEND */
+ "<- " /* DDP_RECV */
+};
+
+void ddp_trace_output(unsigned char *cp, int len, int code)
+{
+ unsigned char outbuf[BYTES_PER_LINE * 4]; /* space before and after each byte */
+ unsigned char *cin, *cout, *ctop;
+ int n, m, p, prefix_len;
+
+ prefix_len = strlen(ddp_trace_prefix[code]);
+ assert(BYTES_PER_LINE > prefix_len);
+ strcpy(outbuf, ddp_trace_prefix[code]);
+ for (cin = cp, ctop = cin + len , cout = outbuf + prefix_len, n = 0; cin < ctop; n++)
+ {
+ if (n >= BYTES_PER_LINE)
+ {
+ cce_out_write(outbuf, cout - outbuf);
+ strcpy(outbuf, ddp_trace_prefix[code]);
+ cout = outbuf + prefix_len;
+ n = 0;
+ }
+ m = *cin++;
+ p = (m >> 4);
+ *cout++ = D2HEX(p);
+ p = (m & 0x0F);
+ *cout++ = D2HEX(p);
+ *cout++ = ' ';
+ }
+ if (n)
+ cce_out_write(outbuf, cout - outbuf);
+ return;
+}
diff --git a/sr_vvms/ddp_trace_output.h b/sr_vvms/ddp_trace_output.h
new file mode 100644
index 0000000..220de80
--- /dev/null
+++ b/sr_vvms/ddp_trace_output.h
@@ -0,0 +1,25 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef DDP_TRACE_OUTPUT_INCLUDED
+#define DDP_TRACE_OUTPUT_INCLUDED
+
+#define DDP_TRACE_ENV "GTMDDP$TRACE"
+
+enum
+{
+ DDP_SEND = 0,
+ DDP_RECV = 1
+};
+
+int ddp_trace_output(unsigned char *cp, int len, int code);
+
+#endif /* DDP_TRACE_OUTPUT_INCLUDED */
diff --git a/sr_vvms/ddpcom.h b/sr_vvms/ddpcom.h
new file mode 100644
index 0000000..e6cb172
--- /dev/null
+++ b/sr_vvms/ddpcom.h
@@ -0,0 +1,102 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2002 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef DDPCOM_H_INCLUDED
+#define DDPCOM_H_INCLUDED
+
+struct iosb_struct
+{
+ unsigned short status;
+ unsigned short length;
+ uint4 devinfo;
+};
+
+struct queue_entry
+{
+ int4 fl;
+ int4 bl;
+};
+
+typedef struct com_slot
+{
+ struct queue_entry q;
+ struct iosb_struct iosb;
+ uint4 pid;
+ short len;
+ short state; /* 1 means no message for client, 0 means message is ready for client */
+ char text[1]; /* actually, ddp_slot_size bytes */
+} com_slot_t;
+
+/* The state flag is actually used to mean that the client may proceed to reuse the message space.
+ Once the client places a message in the slot, the flag remains 1 until the server has returned
+ a reply. It is necessary to check that the server has replied as there is no mutex protecting the
+ message slot. If the client aborts prior to the server replying, and were to then start a new
+ transaction, placing a new message in the slot, the server's reply to the previous request could
+ overlay the new message.
+*/
+
+typedef struct com_hdr
+{
+ struct queue_entry unused_slots;
+ struct queue_entry outbound_pending;
+ uint4 server_pid;
+ int4 filler; /* we must be quad-word aligned */
+ com_slot_t slot[1];
+} com_hdr_t;
+
+#define MAXIMUM_CIRCUITS 32
+#define MAX_USERS_PER_NODE MAXIMUM_PROCESSES /* Only MAXIMUM_PROCESSES supported at this time */
+
+typedef struct
+{
+ unsigned short circuit_name;
+ char ether_addr[ETHERADDR_LENGTH];
+ unsigned char incoming_users[MAX_USERS_PER_NODE];
+ unsigned char outgoing_users[MAX_USERS_PER_NODE];
+} routing_tab;
+
+typedef struct
+{
+ unsigned short volset_name;
+ unsigned short circuit_name;
+} circuit_tab;
+
+typedef struct uci_gld_pair_struct
+{
+ unsigned short uci;
+ mstr gld;
+ struct uci_gld_pair_struct *next;
+} uci_gld_pair;
+
+typedef struct
+{
+ unsigned short vol;
+ uci_gld_pair *ug;
+} volset_tab;
+
+#define VUG_CONFIG_COMMENT_CHAR '#'
+
+typedef union
+{
+ uint4 auxid;
+ struct
+ {
+ short circuit;
+ short job;
+ }as;
+} auxvalue;
+
+#define DDP_XMIT_FAIL "<DDP_ETHER_IO_FAIL>"
+#define DDP_MSG2BIG "<DDP_MSG2BIG>"
+#define DDP_AGENT_BUFF_NAME "GTMDDP$AGENTBUFF$XXX" /* XXX - DDP_CIRCUIT_NAME_LEN characters that will be filled in
+ * by init_section */
+
+#endif /* DDPCOM_H_INCLUDED */
diff --git a/sr_vvms/ddpgvusr.c b/sr_vvms/ddpgvusr.c
new file mode 100644
index 0000000..cb51ef2
--- /dev/null
+++ b/sr_vvms/ddpgvusr.c
@@ -0,0 +1,772 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_ctype.h"
+#include "gtm_limits.h"
+#include <ssdef.h>
+#include <stddef.h>
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "ddphdr.h"
+#include "ddpcom.h"
+#include "send_msg.h"
+#include "dcpsubs.h"
+#include "dcp_a2c.h"
+#include "five_bit.h"
+#include "is_five_bit.h"
+#include "five_2_ascii.h"
+#include "subscript.h"
+#include "str2gvkey.h"
+#include "gvusr.h"
+#include "min_max.h"
+#include "is_proc_alive.h"
+
+/* Retry count should be user parameter */
+#define RETRYCNT 5
+
+/* list of machines that this client is speaking to. The message number
+ is unique per client, per machine. Since multiple database files
+ can reside on a given machine, the message number can not be associated
+ with a region structure. Since the number must be in synch for each
+ machine, it can't be in the client structure. Hence the appropriate
+ sequence number for each machine for this client must be kept separately.
+*/
+
+error_def(ERR_GVDATAFAIL);
+error_def(ERR_GVGETFAIL);
+error_def(ERR_GVKILLFAIL);
+error_def(ERR_GVORDERFAIL);
+error_def(ERR_GVPUTFAIL);
+error_def(ERR_GVQUERYFAIL);
+error_def(ERR_GVSUBOFLOW);
+error_def(ERR_GVZPREVFAIL);
+error_def(ERR_NETDBOPNERR);
+error_def(ERR_NETFAIL);
+error_def(ERR_NETLCKFAIL);
+error_def(ERR_TEXT);
+error_def(ERR_UNIMPLOP);
+error_def(ERR_DDPBADRESPONSE);
+error_def(ERR_DDPCONGEST);
+error_def(ERR_DDPNOCONNECT);
+error_def(ERR_DDPSHUTDOWN);
+error_def(ERR_DDPTOOMANYPROCS);
+error_def(ERR_DDPNOSERVER);
+error_def(ERR_REC2BIG);
+
+GBLREF gd_region *gv_cur_region;
+GBLREF gv_key *gv_altkey;
+GBLREF gv_key *gv_currkey;
+
+GBLREF struct com_slot *com_ptr;
+GBLREF struct com_hdr *com_area;
+
+GBLREF int4 ddp_max_rec_size;
+GBLREF int4 ddp_slot_size;
+
+static unsigned short my_jobno;
+static ddp_info *ddp_values;
+static gv_key **ckey_adr;
+static gv_key **akey_adr;
+static gd_region **creg_adr;
+static unsigned char *bufptr;
+
+static condition_code send_to_agent();
+static int gvusr_o2(char trancode);
+
+static void setup_global_pointers(char trancode)
+{
+ char *inpt;
+ unsigned char *ptr, *lastsubstart;
+ ddp_hdr_t *dp;
+ ddp_global_request_t *gp;
+
+ gv_currkey = *ckey_adr;
+ gv_altkey = *akey_adr;
+ gv_cur_region = *creg_adr;
+ inpt = gv_currkey->base;
+ ddp_values = &FILE_INFO(gv_cur_region)->file_id;
+ dp = com_ptr->text;
+ dp->trancode = trancode;
+ dp->proto = DDP_PROTO_VERSION;
+ /* source_circuit_name filled in by agent */
+ dp->source_job_number = my_jobno;
+ dp->remote_circuit_name = ddp_values->volset; /* Actually the volset name. Translated by the agent */
+ dp->remote_job_number = 0;
+ dp->filler1 = 0;
+ dp->hdrlen = DDP_MSG_HDRLEN;
+ gp = dp->txt;
+ gp->naked_size = 0;
+ gp->uci = ddp_values->uci;
+ gp->vol = ddp_values->volset;
+ gp->global_type = DDP_GLOBAL_TYPE;
+ bufptr = gp->global;
+ dcp_g2d(&inpt, &bufptr, (unsigned char *)com_ptr + ddp_slot_size - bufptr, &gp->naked_size);
+ if (UCHAR_MAX >= bufptr - gp->global)
+ gp->global_len = bufptr - gp->global;
+ else
+ rts_error(VARLSTCNT(1) ERR_GVSUBOFLOW);
+ return;
+}
+
+static condition_code send_to_agent(void)
+{
+ uint4 server;
+
+ com_ptr->len = bufptr - (unsigned char *)com_ptr->text;
+ dcpc_send2agent();
+ if (0 == dcpc_rcv_from_agent())
+ return SS$_NORMAL;
+ return (0 == (server = com_area->server_pid) || !is_proc_alive(server, 0)) ? ERR_DDPNOSERVER : ERR_NETFAIL;
+}
+
+void gvusr_init(gd_region *reg, gd_region **creg, gv_key **ckey, gv_key **akey)
+/* 2nd argument is a pointer to gv_cur_region in gtmshr */
+/* 3rd argument is a pointer to gv_currkey in gtmshr */
+/* 4th argument is a pointer to gv_altkey in gtmshr */
+{
+ char *cp;
+ condition_code status;
+ gd_segment *seg;
+ mval cktnam_logi = DEFINE_MVAL_STRING(MV_STR, 0, 0, STR_LIT_LEN(DDP_CLIENT_CKTNAM_LOGI), DDP_CLIENT_CKTNAM_LOGI, 0, 0);
+ static boolean_t shm_inited = FALSE;
+
+ ckey_adr = ckey;
+ akey_adr = akey;
+ creg_adr = creg;
+ gv_cur_region = reg;
+ seg = reg->dyn.addr;
+ /* NOTE: In a clean and better world, these structures shouldn't have to
+ be set up this way for a dba_usr database. Users should be able
+ to define their own structures to put in seg->file_cntl. But this
+ is the real world, and GV_MATCH will get sick if we don't toe the
+ line, and make a usr database look like a bg or mm database at
+ this structure level. No one is using the usr funcitionality except
+ our implementation of DEC DDP, I believe, so it shouldn't be too
+ embarrassing.
+ */
+ FILE_CNTL_INIT_IF_NULL(seg);
+ ddp_values = &FILE_INFO(reg)->file_id;
+ if (0 == ddp_values->uci)
+ { /* Calculate UCI and Volume set names */
+ cp = ®->dyn.addr->fname;
+ if (!is_five_bit(cp))
+ rts_error(VARLSTCNT(6) ERR_NETDBOPNERR, 0, ERR_TEXT, 2, LEN_AND_LIT("Invalid VOLUME specification"));
+ ddp_values->volset = five_bit(cp);
+ cp += DDP_VOLUME_NAME_LEN;
+ if (':' != *cp++ || ':' != *cp++)
+ rts_error(VARLSTCNT(6) ERR_NETDBOPNERR, 0, ERR_TEXT, 2,
+ LEN_AND_LIT("Invalid separator between volume and uci"));
+ if (!is_five_bit(cp))
+ rts_error(VARLSTCNT(6) ERR_NETDBOPNERR, 0, ERR_TEXT, 2, LEN_AND_LIT("Invalid UCI specification"));
+ ddp_values->uci = five_bit(cp);
+ }
+ if (NULL != com_ptr)
+ { /* Have already established communications with the agent */
+ reg->open = TRUE;
+ return;
+ }
+ if (NULL == com_area)
+ {
+ status = dcp_get_circuit(&cktnam_logi);
+ if (0 == (status & 1))
+ rts_error(VARLSTCNT(7) ERR_NETDBOPNERR, 0, ERR_TEXT, 2,
+ LEN_AND_LIT("Could not find circuit name to use"), status);
+ status = dcp_get_maxrecsize();
+ if (0 == (status & 1))
+ rts_error(VARLSTCNT(7) ERR_NETDBOPNERR, 0, ERR_TEXT, 2,
+ LEN_AND_LIT("Could not find maximum record size"), status);
+ }
+ status = dcpc_shm_init(NULL == com_area);
+ if (0 == (status & 1))
+ {
+ if (ERR_DDPTOOMANYPROCS == status)
+ rts_error(VARLSTCNT(5) ERR_NETDBOPNERR, 0, ERR_DDPTOOMANYPROCS, 1, MAXIMUM_PROCESSES);
+ else
+ rts_error(VARLSTCNT(3) ERR_NETDBOPNERR, 0, status);
+ }
+ my_jobno = ((((unsigned char *)com_ptr - (unsigned char *)com_area->slot) / ddp_slot_size) + 1) << 1;
+ /* Note: no slot zero...slot 1 is for server/agent; normal users use $J*2 */
+ reg->open = TRUE;
+ return;
+}
+
+void gvusr_rundown(void)
+{
+ ddp_hdr_t *dp;
+ ddp_global_request_t *gp;
+
+ if (NULL == com_ptr)
+ return;
+ dp = com_ptr->text;
+ dp->trancode = DDPTR_USEREXIT;
+ dp->source_job_number = my_jobno;
+ gp = dp->txt;
+ com_ptr->len = gp->global - (unsigned char *)com_ptr->text;
+ dcpc_send2agent();
+ /* Deal with LOCK rundowns */
+ com_ptr = NULL;
+ return;
+}
+
+int gvusr_data(void)
+{
+ ddp_hdr_t *msg;
+ char *cp, *cp_top;
+ int msglen;
+ int retval;
+ condition_code status;
+ int retry_count;
+
+ for (retry_count = 0; ; retry_count++)
+ {
+ setup_global_pointers(DDPTR_DEFINE);
+ status = send_to_agent();
+ if (0 != (status & 1))
+ break;
+ if (RETRYCNT <= retry_count)
+ rts_error(VARLSTCNT(1) status);
+ }
+ msg = com_ptr->text;
+ msglen = msg->message_length - msg->hdrlen - 1; /* -1 to strip the terminator byte */
+ if (0 > msglen)
+ msglen = 0;
+ switch(msg->trancode)
+ {
+ case DDPTR_RESPONSE:
+ /* Result can be at most two digits, each digit being the ASCII value of char '0' or '1' */
+ /* Possible valid results : "0", "1", "00", "01", "10", or "11" - without the quotes, quotes shown here only
+ * to indicate that the result is a string */
+ for (retval = 0, cp = msg->txt, cp_top = cp + MIN(2, msglen); cp < cp_top; cp++)
+ { /* only 2 digits for $D result */
+ retval *= 10;
+ if ('1' == *cp)
+ retval++;
+ else if ('0' != *cp)
+ { /* Note: perhaps this should be retry */
+ send_msg(VARLSTCNT(8) ERR_GVDATAFAIL, 2, LEN_AND_LIT("DDP_FORMAT"), ERR_TEXT, 2, msglen, msg->txt);
+ rts_error(VARLSTCNT(8) ERR_GVDATAFAIL, 2, LEN_AND_LIT("DDP_FORMAT"), ERR_TEXT, 2, msglen, msg->txt);
+ }
+ }
+ return retval;
+ case DDPTR_ERRESPONSE:
+ rts_error(VARLSTCNT(4) ERR_GVDATAFAIL, 2, msglen, msg->txt);
+ return 0;
+ case DDPTRX_CONGESTION:
+ rts_error(VARLSTCNT(1) ERR_DDPCONGEST);
+ return 0;
+ case DDPTRX_SHUTDOWN:
+ rts_error(VARLSTCNT(1) ERR_DDPSHUTDOWN);
+ return 0;
+ case DDPTRX_NOCONNECT:
+ rts_error(VARLSTCNT(4) ERR_DDPNOCONNECT, 2, DB_LEN_STR(gv_cur_region));
+ return 0;
+ default:
+ send_msg(VARLSTCNT(11) ERR_GVDATAFAIL, 2, LEN_AND_LIT("DDP_NET_FAIL"),
+ ERR_DDPBADRESPONSE, 1, (long)msg->trancode, ERR_TEXT, 2, msglen, msg->txt);
+ rts_error(VARLSTCNT(11) ERR_GVDATAFAIL, 2, LEN_AND_LIT("DDP_NET_FAIL"),
+ ERR_DDPBADRESPONSE, 1, (long)msg->trancode, ERR_TEXT, 2, msglen, msg->txt);
+ return 0;
+ }
+ return 0;
+}
+
+static int gvusr_o2(char trancode)
+{
+ ddp_hdr_t *msg;
+ int msglen;
+ mval tv;
+ condition_code status;
+ int retry_count;
+
+ for (retry_count = 0; ; retry_count++)
+ {
+ setup_global_pointers(trancode);
+ if (0 == gv_currkey->prev) /* Name level dollar orders are not supported */
+ rts_error(VARLSTCNT(6) ERR_UNIMPLOP, 0, ERR_TEXT, 2, LEN_AND_LIT("Name level $ORDER"));
+ status = send_to_agent();
+ if (0 != (status & 1))
+ break;
+ if (RETRYCNT <= retry_count)
+ rts_error(VARLSTCNT(1) status);
+ }
+ msg = com_ptr->text;
+ msglen = msg->message_length - msg->hdrlen - 1; /* -1 to strip the terminator byte */
+ if (0 > msglen)
+ msglen = 0;
+ switch(msg->trancode)
+ {
+ case DDPTR_RESPONSE:
+ tv.mvtype = MV_STR;
+ tv.str.addr = msg->txt;
+ tv.str.len = msglen;
+ memcpy(gv_altkey, gv_currkey, SIZEOF(*gv_currkey) + gv_currkey->prev);
+ gv_altkey->end = gv_altkey->prev;
+ gtm$mval2subsc(&tv, gv_altkey);
+ return (0 != msglen) ? 1 : 0;
+ case DDPTR_ERRESPONSE:
+ rts_error(VARLSTCNT(4) ERR_GVORDERFAIL, 2, msglen, msg->txt);
+ return 0;
+ case DDPTRX_CONGESTION:
+ rts_error(VARLSTCNT(1) ERR_DDPCONGEST);
+ return 0;
+ case DDPTRX_SHUTDOWN:
+ rts_error(VARLSTCNT(1) ERR_DDPSHUTDOWN);
+ return 0;
+ case DDPTRX_NOCONNECT:
+ rts_error(VARLSTCNT(4) ERR_DDPNOCONNECT, 2, DB_LEN_STR(gv_cur_region));
+ return 0;
+ default:
+ send_msg(VARLSTCNT(11) ERR_GVORDERFAIL, 2, LEN_AND_LIT("DDP_NET_FAIL"),
+ ERR_DDPBADRESPONSE, 1, (long)msg->trancode, ERR_TEXT, 2, msglen, msg->txt);
+ rts_error(VARLSTCNT(11) ERR_GVORDERFAIL, 2, LEN_AND_LIT("DDP_NET_FAIL"),
+ ERR_DDPBADRESPONSE, 1, (long)msg->trancode, ERR_TEXT, 2, msglen, msg->txt);
+ return 0;
+ }
+ return 0;
+}
+
+int gvusr_order(void)
+{
+ return(gvusr_o2(DDPTR_ORDER));
+}
+
+int gvusr_query(mval *v)
+{
+ ddp_hdr_t *msg;
+ int msglen, retval;
+ condition_code status;
+ int retry_count;
+
+ for (retry_count = 0; ; retry_count++)
+ {
+ setup_global_pointers(DDPTR_QUERY);
+ status = send_to_agent();
+ if (0 != (status & 1))
+ break;
+ if (RETRYCNT <= retry_count)
+ rts_error(VARLSTCNT(1) status);
+ }
+ msg = com_ptr->text;
+ msglen = msg->message_length - msg->hdrlen - 1; /* -1 to strip the terminator byte */
+ if (0 > msglen)
+ msglen = 0;
+ switch(msg->trancode)
+ {
+ case DDPTR_RESPONSE:
+ if (0 != msglen)
+ {
+ v->mvtype = MV_STR;
+ v->str.len = msglen;
+ v->str.addr = msg->txt;
+ return 1;
+ }
+ return 0;
+ case DDPTR_ERRESPONSE:
+ if (0 != memcmp(msg->txt, "<UNDEF>", STR_LIT_LEN("<UNDEF>")))
+ rts_error(VARLSTCNT(4) ERR_GVQUERYFAIL, 2, msglen, msg->txt);
+ return 0;
+ case DDPTRX_CONGESTION:
+ rts_error(VARLSTCNT(1) ERR_DDPCONGEST);
+ return 0;
+ case DDPTRX_SHUTDOWN:
+ rts_error(VARLSTCNT(1) ERR_DDPSHUTDOWN);
+ return 0;
+ case DDPTRX_NOCONNECT:
+ rts_error(VARLSTCNT(4) ERR_DDPNOCONNECT, 2, DB_LEN_STR(gv_cur_region));
+ return 0;
+ default:
+ send_msg(VARLSTCNT(11) ERR_GVQUERYFAIL, 2, LEN_AND_LIT("DDP_NET_FAIL"),
+ ERR_DDPBADRESPONSE, 1, (long)msg->trancode, ERR_TEXT, 2, msglen, msg->txt);
+ rts_error(VARLSTCNT(11) ERR_GVQUERYFAIL, 2, LEN_AND_LIT("DDP_NET_FAIL"),
+ ERR_DDPBADRESPONSE, 1, (long)msg->trancode, ERR_TEXT, 2, msglen, msg->txt);
+ return 0;
+ }
+ return 0;
+}
+
+int gvusr_zprevious(void)
+{
+ return(gvusr_o2(DDPTR_PREVIOUS));
+}
+
+int gvusr_get(mval *v)
+{
+ ddp_hdr_t *msg;
+ int msglen;
+ int retval;
+ condition_code status;
+ int retry_count;
+
+ for (retry_count = 0; ; retry_count++)
+ {
+ setup_global_pointers(DDPTR_GET);
+ status = send_to_agent();
+ if (0 != (status & 1))
+ break;
+ if (RETRYCNT <= retry_count)
+ rts_error(VARLSTCNT(1) status);
+ }
+ msg = com_ptr->text;
+ msglen = msg->message_length - msg->hdrlen - 1; /* -1 to strip the terminator byte */
+ if (0 > msglen)
+ msglen = 0;
+ switch(msg->trancode)
+ {
+ case DDPTR_RESPONSE:
+ v->mvtype = MV_STR;
+ v->str.len = msglen;
+ v->str.addr = msg->txt;
+ return 1;
+ case DDPTR_ERRESPONSE:
+ if (0 != memcmp(msg->txt, "<UNDEF>", STR_LIT_LEN("<UNDEF>")))
+ rts_error(VARLSTCNT(4) ERR_GVGETFAIL, 2, msglen, msg->txt);
+ return 0;
+ case DDPTRX_CONGESTION:
+ rts_error(VARLSTCNT(1) ERR_DDPCONGEST);
+ return 0;
+ case DDPTRX_SHUTDOWN:
+ rts_error(VARLSTCNT(1) ERR_DDPSHUTDOWN);
+ return 0;
+ case DDPTRX_NOCONNECT:
+ rts_error(VARLSTCNT(4) ERR_DDPNOCONNECT, 2, DB_LEN_STR(gv_cur_region));
+ return 0;
+ default:
+ send_msg(VARLSTCNT(11) ERR_GVGETFAIL, 2, LEN_AND_LIT("DDP_NET_FAIL"),
+ ERR_DDPBADRESPONSE, 1, (long)msg->trancode, ERR_TEXT, 2, msglen, msg->txt);
+ rts_error(VARLSTCNT(11) ERR_GVGETFAIL, 2, LEN_AND_LIT("DDP_NET_FAIL"),
+ ERR_DDPBADRESPONSE, 1, (long)msg->trancode, ERR_TEXT, 2, msglen, msg->txt);
+ return 0;
+ }
+ return 0;
+}
+
+void gvusr_kill(bool do_subtree)
+{
+ ddp_hdr_t *msg;
+ int msglen;
+ condition_code status;
+ int retry_count;
+
+ if (!do_subtree)
+ rts_error(VARLSTCNT(1) ERR_UNIMPLOP);
+ for (retry_count = 0; ; retry_count++)
+ {
+ setup_global_pointers(DDPTR_KILL);
+ status = send_to_agent();
+ if (0 != (status & 1))
+ break;
+ if (RETRYCNT <= retry_count)
+ rts_error(VARLSTCNT(1) status);
+ }
+ msg = com_ptr->text;
+ msglen = msg->message_length - msg->hdrlen - 1; /* -1 to strip the terminator byte */
+ if (0 > msglen)
+ msglen = 0;
+ switch(msg->trancode)
+ {
+ case DDPTR_RESPONSE:
+ assert(0 == msglen);
+ return;
+ case DDPTR_ERRESPONSE:
+ rts_error(VARLSTCNT(4) ERR_GVKILLFAIL, 2, msglen, msg->txt);
+ return;
+ case DDPTRX_CONGESTION:
+ rts_error(VARLSTCNT(1) ERR_DDPCONGEST);
+ return;
+ case DDPTRX_SHUTDOWN:
+ rts_error(VARLSTCNT(1) ERR_DDPSHUTDOWN);
+ return;
+ case DDPTRX_NOCONNECT:
+ rts_error(VARLSTCNT(4) ERR_DDPNOCONNECT, 2, DB_LEN_STR(gv_cur_region));
+ return;
+ default:
+ send_msg(VARLSTCNT(11) ERR_GVKILLFAIL, 2, LEN_AND_LIT("DDP_NET_FAIL"),
+ ERR_DDPBADRESPONSE, 1, (long)msg->trancode, ERR_TEXT, 2, msglen, msg->txt);
+ rts_error(VARLSTCNT(11) ERR_GVKILLFAIL, 2, LEN_AND_LIT("DDP_NET_FAIL"),
+ ERR_DDPBADRESPONSE, 1, (long)msg->trancode, ERR_TEXT, 2, msglen, msg->txt);
+ return;
+ }
+ return;
+}
+
+void gvusr_put(mval *v)
+{
+ int buff_remaining;
+ condition_code status;
+ ddp_hdr_t *msg;
+ int msglen;
+ int retry_count;
+
+ msg = com_ptr->text;
+ for (retry_count = 0; ; retry_count++)
+ {
+ setup_global_pointers(DDPTR_PUT);
+ buff_remaining = (unsigned char *)com_ptr + ddp_slot_size - bufptr;
+ assert(0 <= buff_remaining); /* we shouldn't have trashed someone else's slot */
+ if (v->str.len + 1 > buff_remaining) /* + 1 for the mysterious last byte that the protocol seems to want */
+ rts_error(VARLSTCNT(6) ERR_REC2BIG, 4, ((ddp_global_request_t *)(msg->txt))->global_len + v->str.len,
+ ddp_slot_size - offsetof(com_slot_t, text[0]) - DDP_MSG_HDRLEN
+ - offsetof(ddp_global_request_t, global[0]), REG_LEN_STR(gv_cur_region));
+ memcpy(bufptr, v->str.addr, v->str.len);
+ bufptr += v->str.len;
+ bufptr++; /* Not sure why the extra byte is here, but the protocol seems to have it */
+ status = send_to_agent();
+ if (0 != (status & 1))
+ break;
+ if (RETRYCNT <= retry_count)
+ rts_error(VARLSTCNT(1) status);
+ }
+ msglen = msg->message_length - msg->hdrlen - 1; /* -1 to strip the terminator byte */
+ if (0 > msglen)
+ msglen = 0;
+ switch(msg->trancode)
+ {
+ case DDPTR_RESPONSE:
+ assert(0 == msglen);
+ return;
+ case DDPTR_ERRESPONSE:
+ rts_error(VARLSTCNT(4) ERR_GVPUTFAIL, 2, msglen, msg->txt);
+ return;
+ case DDPTRX_CONGESTION:
+ rts_error(VARLSTCNT(1) ERR_DDPCONGEST);
+ return;
+ case DDPTRX_SHUTDOWN:
+ rts_error(VARLSTCNT(1) ERR_DDPSHUTDOWN);
+ return;
+ case DDPTRX_NOCONNECT:
+ rts_error(VARLSTCNT(4) ERR_DDPNOCONNECT, 2, DB_LEN_STR(gv_cur_region));
+ return;
+ default:
+ send_msg(VARLSTCNT(11) ERR_GVPUTFAIL, 2, LEN_AND_LIT("DDP_NET_FAIL"),
+ ERR_DDPBADRESPONSE, 1, (long)msg->trancode, ERR_TEXT, 2, msglen, msg->txt);
+ rts_error(VARLSTCNT(11) ERR_GVPUTFAIL, 2, LEN_AND_LIT("DDP_NET_FAIL"),
+ ERR_DDPBADRESPONSE, 1, (long)msg->trancode, ERR_TEXT, 2, msglen, msg->txt);
+ return;
+ }
+ return;
+}
+
+static void setup_lock_message(char trancode, uint4 lock_len, unsigned char *lock_key, gd_region *creg)
+{
+ unsigned char sub_len, *lock_top, *lptr, *lptr_top, sep, ch, *cptr, *buftop;
+ ddp_info *reg_values;
+ ddp_hdr_t *dp;
+ boolean_t is_string, seen_dot, timed_out;
+ int tries;
+
+ sep = '(';
+ lock_top = lock_key + lock_len;
+ sub_len = *lock_key++;
+ reg_values = &FILE_INFO(creg)->file_id;
+ dp = (ddp_hdr_t *)com_ptr->text;
+ memset(dp, 0, SIZEOF(*dp));
+ dp->trancode = trancode;
+ dp->proto = DDP_PROTO_VERSION;
+ dp->source_job_number = my_jobno;
+ dp->remote_circuit_name = reg_values->volset; /* Actually the volset name. Translated by the agent */
+ dp->remote_job_number = 0;
+ dp->filler1 = 0;
+ dp->hdrlen = DDP_MSG_HDRLEN;
+ bufptr = dp->txt; /* beginning of the nref */
+ if ('^' == *lock_key)
+ {
+ *bufptr++ = *lock_key++;
+ sub_len--;
+ }
+ /* put a ["UCI","VOL"] in the buffer in front of the lock namespace */
+ cptr = DSM_EXTREF_PREFIX;
+ cptr++; /* go past the ^ */
+ memcpy(bufptr, cptr, STR_LIT_LEN(DSM_EXTREF_PREFIX) - 1); /* -1 bcoz ^ has already been accounted for */
+ bufptr += (STR_LIT_LEN(DSM_EXTREF_PREFIX) - 1);
+ bufptr = five_2_ascii(®_values->uci, bufptr);
+ memcpy(bufptr, DSM_UCI_VOL_SEPARATOR, STR_LIT_LEN(DSM_UCI_VOL_SEPARATOR));
+ bufptr += STR_LIT_LEN(DSM_UCI_VOL_SEPARATOR);
+ bufptr = five_2_ascii(®_values->volset, bufptr);
+ memcpy(bufptr, DSM_EXTREF_SUFFIX, STR_LIT_LEN(DSM_EXTREF_SUFFIX));
+ bufptr += STR_LIT_LEN(DSM_EXTREF_SUFFIX);
+ buftop = (unsigned char *)com_ptr + ddp_slot_size;
+ if (bufptr + sub_len + 2 >= buftop)
+ rts_error(VARLSTCNT(1) ERR_GVSUBOFLOW);
+ memcpy(bufptr, lock_key, sub_len);
+ bufptr += sub_len;
+ lock_key += sub_len;
+ if (lock_key < lock_top)
+ {
+ while (lock_key < lock_top)
+ {
+ *bufptr++ = sep;
+ sub_len = *lock_key++;
+ lptr = lock_key;
+ lptr_top = lptr + sub_len;
+ seen_dot = is_string = FALSE;
+ if (0 != sub_len && '-' == *lptr)
+ *lptr++;
+ for ( ; lptr < lptr_top; )
+ {
+ ch = *lptr++;
+ if ('.' == ch)
+ {
+ if (seen_dot)
+ {
+ is_string = TRUE;
+ break;
+ } else
+ {
+ seen_dot = TRUE;
+ continue;
+ }
+ }
+ if (!ISDIGIT(ch))
+ {
+ is_string = TRUE;
+ break;
+ }
+ }
+ if (is_string)
+ {
+ if (bufptr >= buftop)
+ rts_error(VARLSTCNT(1) ERR_GVSUBOFLOW);
+ *bufptr++ = '\"';
+ }
+ lptr = lock_key;
+ lptr_top = lptr + sub_len;
+ for ( ; lptr < lptr_top; )
+ {
+ if (bufptr >= buftop)
+ rts_error(VARLSTCNT(1) ERR_GVSUBOFLOW);
+ ch = *lptr++;
+ *bufptr++ = ch;
+ if ('\"' != ch)
+ continue;
+ else
+ {
+ if (bufptr >= buftop)
+ rts_error(VARLSTCNT(1) ERR_GVSUBOFLOW);
+ *bufptr++ = ch; /* double the quotes to make a legal reference */
+ }
+ }
+ if (is_string)
+ {
+ if (bufptr >= buftop)
+ rts_error(VARLSTCNT(1) ERR_GVSUBOFLOW);
+ *bufptr++ = '\"';
+ }
+ lock_key += sub_len;
+ sep = ',';
+ }
+ if (bufptr >= buftop)
+ rts_error(VARLSTCNT(1) ERR_GVSUBOFLOW);
+ *bufptr++ = ')';
+ }
+ *bufptr++ = DDP_MSG_TERMINATOR;
+ return;
+}
+
+int gvusr_lock(uint4 lock_len, unsigned char *lock_key, gd_region *creg)
+{
+ ddp_hdr_t *msg;
+ int msglen;
+ int retval;
+ condition_code status;
+ int retry_count;
+
+ for (retry_count = 0; ; retry_count++)
+ {
+ setup_lock_message(DDPTR_ZALLOC, lock_len, lock_key, creg);
+ status = send_to_agent();
+ if (0 != (status & 1))
+ break;
+ if (RETRYCNT <= retry_count)
+ rts_error(VARLSTCNT(1) status);
+ }
+ msg = com_ptr->text;
+ msglen = msg->message_length - msg->hdrlen - 1; /* -1 to strip the terminator byte */
+ if (0 > msglen)
+ msglen = 0;
+ switch(msg->trancode)
+ {
+ case DDPTR_RESPONSE:
+ assert(0 != msglen);
+ if ('S' == msg->txt[0])
+ return 0; /* 0 is a successful lock */
+ assert('F' == msg->txt[0]);
+ return 1;
+ case DDPTR_ERRESPONSE:
+ rts_error(VARLSTCNT(1) ERR_NETLCKFAIL);
+ return 1;
+ case DDPTRX_CONGESTION:
+ rts_error(VARLSTCNT(1) ERR_DDPCONGEST);
+ return 1;
+ case DDPTRX_SHUTDOWN:
+ rts_error(VARLSTCNT(1) ERR_DDPSHUTDOWN);
+ return 1;
+ case DDPTRX_NOCONNECT:
+ rts_error(VARLSTCNT(4) ERR_DDPNOCONNECT, 2, DB_LEN_STR(gv_cur_region));
+ return 1;
+ default:
+ send_msg(VARLSTCNT(9) ERR_NETLCKFAIL, 0, ERR_DDPBADRESPONSE, 1, (long)msg->trancode, ERR_TEXT, 2, msglen, msg->txt);
+ rts_error(VARLSTCNT(9) ERR_NETLCKFAIL, 0, ERR_DDPBADRESPONSE, 1, (long)msg->trancode, ERR_TEXT, 2, msglen,msg->txt);
+ return 1;
+ }
+ return 1;
+}
+
+void gvusr_unlock(uint4 lock_len, unsigned char *lock_key, gd_region *creg)
+{
+ ddp_hdr_t *msg;
+ int msglen;
+ condition_code status;
+ int retry_count;
+
+ for (retry_count = 0; ; retry_count++)
+ {
+ setup_lock_message(DDPTR_ZDEALLOC, lock_len, lock_key, creg);
+ status = send_to_agent();
+ if (0 != (status & 1))
+ break;
+ if (RETRYCNT <= retry_count)
+ rts_error(VARLSTCNT(1) status);
+ }
+ msg = com_ptr->text;
+ msglen = msg->message_length - msg->hdrlen - 1; /* -1 to strip the terminator byte */
+ if (0 > msglen)
+ msglen = 0;
+ switch(msg->trancode)
+ {
+ case DDPTR_RESPONSE:
+ assert(0 == msglen);
+ return;
+ case DDPTR_ERRESPONSE:
+ rts_error(VARLSTCNT(1) ERR_NETLCKFAIL);
+ return;
+ case DDPTRX_CONGESTION:
+ rts_error(VARLSTCNT(1) ERR_DDPCONGEST);
+ return;
+ case DDPTRX_SHUTDOWN:
+ rts_error(VARLSTCNT(1) ERR_DDPSHUTDOWN);
+ return;
+ case DDPTRX_NOCONNECT:
+ rts_error(VARLSTCNT(4) ERR_DDPNOCONNECT, 2, DB_LEN_STR(gv_cur_region));
+ return;
+ default:
+ send_msg(VARLSTCNT(9) ERR_NETLCKFAIL, 0, ERR_DDPBADRESPONSE, 1, (long)msg->trancode, ERR_TEXT, 2, msglen, msg->txt);
+ rts_error(VARLSTCNT(9) ERR_NETLCKFAIL, 0, ERR_DDPBADRESPONSE, 1, (long)msg->trancode, ERR_TEXT, 2, msglen,msg->txt);
+ return;
+ }
+ return;
+}
diff --git a/sr_vvms/ddpkithlp.com b/sr_vvms/ddpkithlp.com
new file mode 100644
index 0000000..44c9213
--- /dev/null
+++ b/sr_vvms/ddpkithlp.com
@@ -0,0 +1,157 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! Copyright 2001, 2003 Sanchez Computer Associates, Inc. !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$ IF F$EXTRACT(0,5,P1) .EQS. "HELP_" THEN GOTO 'P1'
+$ EXIT VMI$_UNSUPPORTED
+$HELP_PURGE:
+$ TYPE SYS$INPUT
+
+ If GT.CM DDP is previously installed, there is no reason to keep older
+ versions of the software online, unless you wish to test before purging.
+
+$ EXIT
+$HELP_NDB_CNT:
+$ TYPE SYS$INPUT
+ The installation inserts this value as the default for controlling the
+ DDP Server quotas established in GTCMDDPSTART.COM. If you provide a value
+ less than 1, the value will be set to 1. This value can be easily changed
+ later.
+
+$ EXIT
+$HELP_RC_CNT:
+$ TYPE SYS$INPUT
+ The installation inserts this value as the default for controlling the
+ DDP Server quotas established in GTCMDDPSTART.COM. If you provide a value
+ less than 1, the value will be set to 1. This value can be easily changed
+ later.
+
+$ EXIT
+$HELP_SRV_UIC:
+$ TYPE SYS$INPUT
+ The DDP Server usually must have broad file access so running under the
+ SYSTEM UIC may make sense. The recommended alternative is to use a
+ distinguished UIC which has appropriate UIC or ACL based access to served
+ files.
+
+$ EXIT
+$HELP_STD_CNF:
+$ TYPE SYS$INPUT
+ The standard configuration performs the following:
+
+ * Places files in SYS$COMMON:[GTM_DIST] with SYSTEM as owner
+ * Gives the DDP server a "UCI" of DDP, and a "VOLUME SET" of GTM
+ * Gives the DDP server a global directory of GTM$DIST:DDP_SERVER.GLD
+ * Creates a volume configuration file DDP_VOLCONF.LIS and copies it to GTM$DIST
+ * Copies the GT.CM DDP command procedures to SYS$MANAGER
+ * Adds GTCMDDPSTART.COM to the system startup database
+ * Starts GT.CM DDP at the end of the installation
+
+ If the SYSTEM id is not set up, the installation will use [1,4].
+ If you answer YES, no more questions will be asked.
+
+$ EXIT
+$HELP_DST_OWN:
+$ TYPE SYS$INPUT
+ Provide a UIC, normally SYSTEM, to own the files in the GT.M distribution.
+ The UIC can be a name, a group name and a user name separated by a comma,
+ or a pair of octal codes separated by a comma which specify group and user.
+
+$ EXIT
+$HELP_SYS_DST:
+$ TYPE SYS$INPUT
+ Usual practice is to place a system component such as GT.CM DDP on the
+ system disk. If you have severe space constraints, you may need to use
+ another volume.
+
+$ EXIT
+$HELP_SYS_DIR:
+$ TYPE SYS$INPUT
+ This directory becomes be a sub-directory of SYS$COMMON and holds the
+ distribution. If it does not exist, the installation creates it with
+ WORLD=RE access. If you are not concerned with mixing software from
+ different vendors, you may wish to use SYSLIB.
+
+$ EXIT
+$HELP_DST_DEV:
+$ TYPE SYS$INPUT
+ The disk must be mounted, on-line and have adequate space to hold the GT.CM
+ DDP distribution. The disk name may be physical or logical.
+
+$ EXIT
+$HELP_DST_DIR:
+$ TYPE SYS$INPUT
+ This directory holds the distribution. If it does not exist, the
+ installation creates it with WORLD=RE access.
+
+$ EXIT
+$HELP_VOLCONF:
+$ TYPE SYS$INPUT
+ The GT.CM DDP Server requires one or more Global Directories in order to
+ find the appropriate database files. Each Global Directory is associated
+ with a "UCI" "Volume-set" pair by an entry in the volume configuration
+ file in the form of
+
+ VOL UCI GlobalDirectory
+
+ where VOL and UCI are each 3 characters long. The name of the volume
+ configuration file is parameter P1 to the script GTCMDDPSTART.COM.
+ The file you specify now will be generated and used as the default if P1 is
+ not specified for GTCMDDPSTART. The installation creates the configuration
+ file with one entry using the "Volume-Set", "UCI", "Global Directory" you
+ specify in response to the following questions.
+
+$ EXIT
+$HELP_VOL_NAME:
+$ TYPE SYS$INPUT
+ The GT.CM DDP Server requires one or more Global Directories in order to
+ find the appropriate database files. Each Global Directory is associated
+ with a "UCI" "Volume-set" pair by an entry in the volume configuration
+ file. Specify the "Volume-set" name that you wish to enter in the
+ configuration file.
+
+$ EXIT
+$HELP_UCI_NAME:
+$ TYPE SYS$INPUT
+ The GT.CM DDP Server requires one or more Global Directories in order to
+ find the appropriate database files. Each Global Directory is associated
+ with a "UCI" "Volume-set" pair by an entry in the volume configuration
+ file. Specify the "UCI" name for the "Volume-set" name you specified
+ before.
+
+$ EXIT
+$HELP_GBLDIR:
+$ TYPE SYS$INPUT
+ The GT.CM DDP Server requires one or more Global Directories in order to
+ find the appropriate database files. Each Global Directory is associated
+ with a "UCI" "Volume-set" pair by an entry in the volume configuration
+ file. Specify the "Global Directory" file name for the "Volume-set"
+ "UCI" pair you specified before.
+
+$ EXIT
+$HELP_STARTDB:
+$ TYPE SYS$INPUT
+ Answering yes causes the installation to place GTCMDDPSTART.COM in the
+ startup database so the system startup automatically sets up the GT.CM
+ DDP server whenever the system boots.
+
+$ EXIT
+$HELP_RUN_IVP:
+$ TYPE SYS$INPUT
+ This installation kit contains an installation verification procedure (IVP)
+ which you can run as part of the installation to verify the correctness of
+ the software. Note that if you choose this option, the GT.M images must
+ already be installed.
+
+$ EXIT
+$HELP_START_CM:
+$ TYPE SYS$INPUT
+ Answering yes causes the installation to start GT.CM DDP Server.
+
+$ EXIT
diff --git a/sr_vvms/ddpkitinstal.com b/sr_vvms/ddpkitinstal.com
new file mode 100644
index 0000000..fd663d3
--- /dev/null
+++ b/sr_vvms/ddpkitinstal.com
@@ -0,0 +1,557 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2003 Sanchez Computer Associates, Inc. !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$!
+$! KITINSTAL.COM PROCEDURE FOR THE GT.CM DDP PRODUCT
+$!
+$ ON CONTROL_Y THEN VMI$CALLBACK CONTROL_Y
+$! ON WARNING THEN EXIT $STATUS !! allow warning on install replace
+$ IF P1 .EQS. "VMI$_INSTALL" THEN GOTO INSTALL
+$ IF P1 .EQS. "VMI$_POSTINSTALL" THEN GOTO POSTINSTALL
+$ IF P1 .EQS. "VMI$_IVP" THEN GOTO IVP
+$ EXIT VMI$_UNSUPPORTED
+$!
+$INSTALL:
+$ TYPE SYS$INPUT
+
+ GT.CM DDP (c) COPYRIGHT 1988, 2002 by Sanchez Computer Associates, Inc
+ ALL RIGHTS RESERVED
+
+$! the following 2 lines must be maintained
+$ GTCM$VMS_VERSION :== 072 ! Minimum VMS version required
+$ GTCM$DISK_SPACE == 1600 ! Minumum disk space on system disk required for install (2x result)
+$ IF F$ELEMENT(0,",",VMI$VMS_VERSION) .EQS. "RELEASED"
+$ THEN
+$ GTCM$VMS_IS == F$ELEMENT(1,",",VMI$VMS_VERSION)
+$ IF GTCM$VMS_IS .LTS. GTCM$VMS_VERSION
+$ THEN
+$ VMI$CALLBACK MESSAGE E VMSMISMATCH "This GT.CM DDP kit requires an existing VMS''GTCM$VMS_VERSION' system."
+$ EXIT VMI$_FAILURE
+$ ENDIF
+$ ELSE
+$ GTCM$VMS_IS :==
+$ WRITE SYS$OUTPUT " No VMS version checking performed for field test versions."
+$ ENDIF
+$ IF (GTCM$VMS_IS .GES. "052") THEN T1 = F$VERIFY(VMI$KIT_DEBUG)
+$ VMI$CALLBACK CHECK_NET_UTILIZATION GTCM$ROOM 'GTCM$DISK_SPACE'
+$ IF .NOT. GTCM$ROOM
+$ THEN
+$ VMI$CALLBACK MESSAGE E NOSPACE "There is not enough disk space -- GT.CM DDP needs ''GTCM$DISK_SPACE' blocks."
+$ EXIT VMI$_FAILURE
+$ ENDIF
+$! setup default answers
+$ GTCM$DOPURGE :== YES
+$ GTCM$RUN_IVP == 0 !! should be "YES", but no IVP yet
+$ GTCM$NDB_CNT == 12
+$ GTCM$RC_CNT == 16
+$ GTCM$STD_CNF :== YES
+$ GTCM$DST_OWN :== SYSTEM
+$ IF F$IDENTIFIER(GTCM$DST_OWN,"NAME_TO_NUMBER") .EQ. 0 THEN GTCM$DST_OWN :== 1,4
+$ GTCM$SRV_UIC :==
+$ GTCM$SYS_DST :== YES
+$ GTCM$DST_DIR :== GTM_DIST
+$ GTCM$DST_CRE == GTCM$DST_DIR
+$ GTCM$DST_DEV :==
+$ GTCM$STARTDB :== YES
+$ GTCM$UCI_NAME :== DDP
+$ GTCM$VOL_NAME :== GTM
+$ GTCM$VOLCONF == "DDP_VOLCONF.LIS"
+$ GTCM$START_SRV :== YES
+$!
+$ VMI$CALLBACK ASK GTCM$DOPURGE "Do you want to purge files replaced by this installation" 'GTCM$DOPURGE' B -
+ "@VMI$KWD:DDPKITHLP HELP_PURGE"
+$ IF .NOT. GTCM$DOPURGE THEN VMI$CALLBACK SET PURGE NO
+$ VMI$CALLBACK ASK GTCM$NDB_CNT "How many networked databases will this node serve" 'GTCM$NDB_CNT' I -
+ "@VMI$KWD:DDPKITHLP HELP_NDB_CNT"
+$ IF GTCM$NDB_CNT .LT. 1
+$ THEN
+$ GTCM$NDB_CNT == 1
+$ WRITE SYS$OUTPUT " The installation set this value to 1 as 0 or negative values are not useful."
+$ ENDIF
+$ VMI$CALLBACK ASK GTCM$RC_CNT "How many client links will this node serve" 'GTCM$RC_CNT' I -
+ "@VMI$KWD:DDPKITHLP HELP_RC_CNT"
+$ IF GTCM$RC_CNT .LT. 1
+$ THEN
+$ GTCM$RC_CNT == 1
+$ WRITE SYS$OUTPUT " The installation set this value to 1 as 0 or negative values are not useful."
+$ ENDIF
+$ VMI$CALLBACK ASK GTCM$SRV_UIC "Under what UIC should the Server operate" "''GTCM$SRV_UIC'" S -
+ "@VMI$KWD:DDPKITHLP HELP_SRV_UIC"
+$ GTCM$SRV_UIC == GTCM$SRV_UIC - "[" - "]"
+$ IF GTCM$SRV_UIC - "," .NES. GTCM$SRV_UIC THEN GTCM$SRV_UIC :== ['GTCM$SRV_UIC']
+$ VMI$CALLBACK ASK GTCM$STD_CNF "Do you want the standard GT.CM DDP configuration" 'GTCM$STD_CNF' B -
+ "@VMI$KWD:DDPKITHLP HELP_STD_CNF"
+$ IF GTCM$STD_CNF
+$ THEN
+$ GTCM$SYS_DST == 1
+$ GTCM$STARTDB == 1
+$ GTCM$START_CM == 1
+$ GTCM$DST_LOG :== SYS$COMMON:['GTCM$DST_DIR']
+$ GTCM$DIR_TYPE :== COMMON
+$ GTCM$GBLDIR == "DDP_SERVER.GLD"
+$ GTCM$RUN_IVP == 0 !! no IVP yet
+$ ELSE ! not standard configuration
+$ VMI$CALLBACK ASK GTCM$DST_OWN "What UIC should own the GT.CM DDP distribution" 'GTCM$DST_OWN' S -
+$ "@VMI$KWD:DDPKITHLP HELP_DST_OWN"
+$ GTCM$DST_OWN == GTCM$DST_OWN - "[" - "]"
+$ VMI$CALLBACK ASK GTCM$SYS_DST "Do you want the GT.CM DDP distribution to go into a System Directory" 'GTCM$SYS_DST' B -
+ "@VMI$KWD:DDPKITHLP HELP_SYS_DST"
+$ IF GTCM$SYS_DST
+$ THEN
+$ VMI$CALLBACK ASK GTCM$DST_DIR "In what System Directory do you want to place GT.CM DDP" 'GTCM$DST_DIR' S -
+ "@VMI$KWD:DDPKITHLP HELP_SYS_DIR"
+$ GTCM$DST_DIR == GTCM$DST_DIR - "[" - "]"
+$ GTCM$DST_CRE == GTCM$DST_DIR
+$ GTCM$DST_LOG :== SYS$COMMON:['GTCM$DST_DIR']
+$ GTCM$DIR_TYPE :== COMMON
+$ ELSE ! not system disk
+$ VMI$CALLBACK ASK GTCM$DST_DEV "On which device do you want to place GT.CM DDP" "''GTCM$DST_DEV'" S -
+ "@VMI$KWD:DDPKITHLP HELP_DST_DEV"
+$ VMI$CALLBACK ASK GTCM$DST_DIR "In what directory on that device do you want to place GT.CM DDP" 'GTCM$DST_DIR' S -
+ "@VMI$KWD:DDPKITHLP HELP_DST_DIR"
+$ GTCM$DST_DEV == GTCM$DST_DEV - ":"
+$ GTCM$DST_DIR == GTCM$DST_DIR - "[" - "]"
+$ GTCM$DST_LOG :== 'GTCM$DST_DEV':['GTCM$DST_DIR']
+$ GTCM$DST_CRE == GTCM$DST_LOG
+$ GTCM$DIR_TYPE :== USER
+$ ENDIF ! system disk
+$ GTCM$GBLDIR == "DDP_SERVER.GLD"
+$ VMI$CALLBACK ASK GTCM$VOLCONF "What file do you want as volume-set configuration file for the DDP Server" 'GTCM$VOLCONF' S -
+ "@VMI$KWD:DDPKITHLP HELP_VOLCONF"
+$ VMI$CALLBACK ASK GTCM$VOL_NAME "What ""VOLSET"" do you want to assign to the GT.CM DDP Server" 'GTCM$VOL_NAME' S -
+ "@VMI$KWD:DDPKITHLP HELP_VOL_NAME"
+$ VMI$CALLBACK ASK GTCM$UCI_NAME "What ""UCI"" do you want to assign to the GT.CM DDP Server" 'GTCM$UCI_NAME' S -
+ "@VMI$KWD:DDPKITHLP HELP_UCI_NAME"
+$ VMI$CALLBACK ASK GTCM$GBLDIR "What file do you want as the global directory for the GT.CM DDP Server" 'GTCM$GBLDIR' S -
+ "@VMI$KWD:DDPKITHLP HELP_GBLDIR"
+$ VMI$CALLBACK ASK GTCM$STARTDB "Do you want GTCMDDPSTART.COM in the startup database" 'GTCM$STARTDB' B -
+ "@VMI$KWD:DDPKITHLP HELP_STARTDB"
+$!! no IVP yet
+$ IF 0 THEN VMI$CALLBACK ASK GTCM$RUN_IVP "Do you want to run the IVP (requires GT.M)" 'GTCM$RUN_IVP' B -
+ "@VMI$KWD:DDPKITHLP HELP_RUN_IVP"
+$ IF GTCM$RUN_IVP
+$ THEN
+$ GTCM$START_CCP == 1
+$ ELSE
+$ VMI$CALLBACK ASK GTCM$START_CM "Do you want to start GT.CM DDP now" 'GTCM$START_SRV' B "@VMI$KWD:DDPKITHLP HELP_START_CM"
+$ ENDIF
+$ ENDIF ! standard configuration
+$ TYPE SYS$INPUT
+
+ The following files are created and copied to appropriate destination
+
+ GTCMDDPSTART.COM copied to SYS$MANAGER:
+ GTCMDDPSTOP.COM copied to SYS$MANAGER:
+$ WRITE SYS$OUTPUT " ''GTCM$VOLCONF' copied to ''GTCM$DST_LOG'"
+$ TYPE SYS$INPUT
+
+ Each file contains its own user documentation.
+
+ All the questions have been asked. Installation now proceeds without your
+ manual intervention for about 5-10 minutes.
+$ IF GTCM$RUN_IVP THEN WRITE SYS$OUTPUT " Finally the installation verification procedure tests the installation."
+$ WRITE SYS$OUTPUT ""
+$ VMI$CALLBACK CREATE_DIRECTORY 'GTCM$DIR_TYPE' 'GTCM$DST_CRE' "/OWNER_UIC=[''GTCM$DST_OWN'] /PROTECTION=(WO:RE)"
+$ VMI$CALLBACK MESSAGE I CRECOM "Creating command files."
+$! Create GTCMDDPSTART.COM
+$ OPEN /WRITE OUFILE VMI$KWD:GTCMDDPSTART.COM
+$ WRITE OUFILE "$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
+$ WRITE OUFILE "$! !"
+$ WRITE OUFILE "$! Copyright 1988, 2003 Sanchez Computer Associates, Inc. !"
+$ WRITE OUFILE "$! !"
+$ WRITE OUFILE "$! This source code contains the intellectual property !"
+$ WRITE OUFILE "$! of its copyright holder(s), and is made available !"
+$ WRITE OUFILE "$! under a license. If you do not know the terms of !"
+$ WRITE OUFILE "$! the license, please stop and do not read further. !"
+$ WRITE OUFILE "$! !"
+$ WRITE OUFILE "$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! The invoking user requires the following privileges:"
+$ WRITE OUFILE "$! CMKRNL, DETATCH, OPER, NETMBX, PSWAPM, SYSNAM, SYSGBL and TMPMBX."
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! The parameters are:"
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! P1 = VOLSET_CONFIGURATION_FILE"
+$ WRITE OUFILE "$! if not specified, or specifed as """", defaults to"
+$ WRITE OUFILE "$! what is specified during the installation. For"
+$ WRITE OUFILE "$! standard installation, GT.CM sets the default to"
+$ WRITE OUFILE "$! GTM$DIST:DDP_VOLCONF.LIS"
+$ WRITE OUFILE "$! P2 = CIRCUIT_NAME"
+$ WRITE OUFILE "$! if not specified, or specified as """", defaults to"
+$ WRITE OUFILE "$! NOD, where NOD is the first three characters of the"
+$ WRITE OUFILE "$! node name"
+$ WRITE OUFILE "$! Note, only the first three characters of CIRCUIT_NAME"
+$ WRITE OUFILE "$! are used. If the specification is less than 3 characters in length,"
+$ WRITE OUFILE "$! the specification is suffixed with the appropriate number of"
+$ WRITE OUFILE "$! _ (underbar) characters."
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! P3 = ETHERNET_DEVICE"
+$ WRITE OUFILE "$! no default"
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! P4 = GROUPS (comma separated group numbers 0-15)"
+$ WRITE OUFILE "$! if not specified, or specified as """", defaults to 0"
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! P5 = comma separated list of GT.CM DDP tunable parameters"
+$ WRITE OUFILE "$! Note, the delimiter is comma alone and not comma-space."
+$ WRITE OUFILE "$! To omit specifying a parameter, specify the empty string """", or omit"
+$ WRITE OUFILE "$! everything (including double-quotes) in the appropriate"
+$ WRITE OUFILE "$! comma-delimited position"
+$ WRITE OUFILE "$! P5 = P5A,P5B,P5C"
+$ WRITE OUFILE "$! where"
+$ WRITE OUFILE "$! P5A = MAX RECORD SIZE"
+$ WRITE OUFILE "$! if not specified, or specified as """", defaults to MINRECSIZE"
+$ WRITE OUFILE "$! MINRECSIZE is 1024 bytes"
+$ WRITE OUFILE "$! GT.CM rounds up (MAX RECORD SIZE + 39) to the nearest 512 byte"
+$ WRITE OUFILE "$! value and uses that for outbound/incoming buffer space. 39"
+$ WRITE OUFILE "$! is the overhead needed by GT.CM and the DDP protocol."
+$ WRITE OUFILE "$! Considering that ethernet messages cannot exceed 1500 bytes"
+$ WRITE OUFILE "$! and that the DDP protocol doesn't appear to support message"
+$ WRITE OUFILE "$! fragmenting, the value MINRECSIZE is sufficient to support all"
+$ WRITE OUFILE "$! database operations (buffer space is 1536 for record size 1024)."
+$ WRITE OUFILE "$! If we account for the overhead for a database request and"
+$ WRITE OUFILE "$! response, the maximum outbound request size (SET operation)"
+$ WRITE OUFILE "$! is 1478, and the maximum incoming result size is 1484."
+$ WRITE OUFILE "$! Keep this in mind while loading data into files that are"
+$ WRITE OUFILE "$! served DDP servers. Note, GT.CM imposes a limit of 255 for the"
+$ WRITE OUFILE "$! key length (maximum combined length of subscripts) and so"
+$ WRITE OUFILE "$! does the DDP protocol. In some cases, although GT.CM's format"
+$ WRITE OUFILE "$! for keys is shorter than this maximum, the format required"
+$ WRITE OUFILE "$! by DDP might be longer and hence might cause"
+$ WRITE OUFILE "$! GVSUBOFLOW/REC2BIG errors"
+$ WRITE OUFILE "$! P5B = ETHERNET RECEIVE BUFFER COUNT"
+$ WRITE OUFILE "$! if not specified, or specified as """", defaults to 64."
+$ WRITE OUFILE "$! GT.CM pre-allocates this many Ethernet Receive Buffers."
+$ WRITE OUFILE "$! P5C = MAXIMUM REQUEST CREDITS"
+$ WRITE OUFILE "$! if not specified, or specified as """", defaults to 4."
+$ WRITE OUFILE "$! GT.CM sends this value for the request credits in the protocol"
+$ WRITE OUFILE "$! handshake exchange (WI, II announce) messages. This value"
+$ WRITE OUFILE "$! is used for flow control between client and server nodes."
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! The name of the server will be"
+$ WRITE OUFILE "$! GTMDDP_SERV_<CIRCUIT_NAME>"
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! Following logicals are defined in the system table by the startup script"
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! <Process-name-of-server> = <CIRCUIT_NAME>"
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! DDPGVUSR = GTM$DIST:DDPGVUSR.EXE"
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! GTMDDP_VOLCONF_<CIRCUIT_NAME> = P1"
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! If P3 is specifed and not """","
+$ WRITE OUFILE "$! GTMDDP_CONTROLLER_<CIRCUIT_NAME> = <ETHERNET_DEVICE>"
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! If P3 is not specified (or specifed as """"), or the DDP server fails to"
+$ WRITE OUFILE "$! open the specified <ETHERNET_DEVICE>, then the server attempts to open"
+$ WRITE OUFILE "$! the following devices in the order specified, and uses the first device"
+$ WRITE OUFILE "$! successfully opened."
+$ WRITE OUFILE "$! ECA0, ESA0, ETA0, EWA0, EXA0, EZA0, XEA0, XQA0"
+$ WRITE OUFILE "$! If the server fails to open all devices, it exits with an error."
+$ WRITE OUFILE "$! One can use SHOW PROC/ID=<DDP Server PID> to find the ethernet device"
+$ WRITE OUFILE "$! being used by the DDP server."
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! GTMDDP_GROUPS_<CIRCUIT_NAME> = P4"
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! GTMDDP_MAXRECSIZE_<CIRCUIT_NAME> = P5A"
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! GTMDDP_ETHRCVBUFCNT_<CIRCUIT_NAME> = P5B"
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! GTMDDP_MAXREQCREDITS_<CIRCUIT_NAME> = P5C"
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! In the below discussion, the units for quotas and limits are as per VMS"
+$ WRITE OUFILE "$! documentation."
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! P6 = comma seprated list of process quotas for the DDP server"
+$ WRITE OUFILE "$! Note, the delimiter is comma alone and not comma-space."
+$ WRITE OUFILE "$! To omit specifying a quota, specify the empty string """", or omit"
+$ WRITE OUFILE "$! everything (including double-quotes) in the appropriate"
+$ WRITE OUFILE "$! comma-delimited position"
+$ WRITE OUFILE "$! P6 = P6A,P6B,P6C,P6D,P6E"
+$ WRITE OUFILE "$! where"
+$ WRITE OUFILE "$! P6A is the maximum number of database files served to the network."
+$ WRITE OUFILE "$! if not specifed, or specified as """", defaults to value"
+$ WRITE OUFILE "$! specified during installation. For standard installation,"
+$ WRITE OUFILE "$! GT.CM sets the default to 12."
+$ WRITE OUFILE "$! This parameter is used to compute the following parameters"
+$ WRITE OUFILE "$! for the server"
+$ WRITE OUFILE "$! AST_LIMIT, ENQUEUE_LIMIT, FILE_LIMIT, IO_DIRECT, QUEUE_LIMIT,"
+$ WRITE OUFILE "$! PAGE_FILE "
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! P6B is the maximum number of remote clients served."
+$ WRITE OUFILE "$! if not specified, or specified as """", defaults to value"
+$ WRITE OUFILE "$! specified during installation. For standard installation,"
+$ WRITE OUFILE "$! GT.CM sets the default to 16."
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! P6C is the default working set size"
+$ WRITE OUFILE "$! if not specified, or specified as """", defaults to"
+$ WRITE OUFILE "$! FILE_LIMIT * 200 (see how FILE_LIMIT is computed below)"
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! P6D is the priority and should be at an appropriate priority"
+$ WRITE OUFILE "$! to balance network response with local load"
+$ WRITE OUFILE "$! if not specified, or specified as """", defaults to 5"
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! P6E is the byte limit and should be greater than or equal to 30000"
+$ WRITE OUFILE "$! if not specified, or specified as """", defaults to 30000"
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! The server is run with UIC specified during installation. For standard"
+$ WRITE OUFILE "$! installation, GT.CM sets the UIC to [1,4]"
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! Server errors are logged to SYS$MANAGER:DDP_CME.LOG"
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! The server has DUMP enabled, and is run with option to inhibit SWAPPING while"
+$ WRITE OUFILE "$! in wait state."
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! Based on GT.CM requirements, each quota or limit is computed as"
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! AST_LIMIT = (P6A + 1) * 3 + P6B"
+$ WRITE OUFILE "$! ENQUEUE_LIMIT = (P6A + 1) * 3"
+$ WRITE OUFILE "$! FILE_LIMIT = P6A + P6B + 3"
+$ WRITE OUFILE "$! IO_BUFFERED = (P6B + 3) * 1024"
+$ WRITE OUFILE "$! IO_DIRECT = P6A * 7"
+$ WRITE OUFILE "$! QUEUE_LIMIT = (P6A + 1) * 2"
+$ WRITE OUFILE "$! PRIORITY = P6D"
+$ WRITE OUFILE "$! WORKING_SET = P6C"
+$ WRITE OUFILE "$! MAXIMUM_WORKING_SET = WORKING_SET + 200 "
+$ WRITE OUFILE "$! BUFFER_LIMIT = P6E"
+$ WRITE OUFILE "$! PAGE_FILE = P6A * 10000"
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$ CURPRV = F$SETPRV(""TMPMBX"")"
+$ WRITE OUFILE "$ ON CONTROL_C THEN GOTO ERROR"
+$ WRITE OUFILE "$ ON ERROR THEN GOTO ERROR"
+$ WRITE OUFILE "$ CURPRV=F$SETPRV(""CMKRNL,DETACH,NETMBX,OPER,PSWAPM,SYSNAM,SYSGBL,TMPMBX"")+"",""+CURPRV"
+$ WRITE OUFILE "$ IF F$PRIVILEGE(""CMKRNL,DETACH,NETMBX,OPER,PSWAPM,SYSNAM,SYSGBL,TMPMBX"")"
+$ WRITE OUFILE "$ THEN"
+$ WRITE OUFILE "$ DEFINE /SYSTEM DDPGVUSR GTM$DIST:DDPGVUSR.EXE"
+$ WRITE OUFILE "$ NODE = F$GETSYI(""SCSNODE"")"
+$ WRITE OUFILE "$ NOD = F$EDIT(F$EXTRACT(0,3,NODE),""TRIM"")"
+$ WRITE OUFILE "$ IF F$LENGTH(NOD) .LT. 3 THEN NOD = NOD + F$EXTRACT(0,3-F$LENGTH(NOD),""___"")"
+$ WRITE OUFILE "$ P2 = F$EDIT(P2,""COLLAPSE"")"
+$ WRITE OUFILE "$ IF P2 .EQS. """""
+$ WRITE OUFILE "$ THEN"
+$ WRITE OUFILE "$ P2 = NOD"
+$ WRITE OUFILE "$ ELSE"
+$ WRITE OUFILE "$ P2 = F$EDIT(F$EXTRACT(0,3,P2),""TRIM"")"
+$ WRITE OUFILE "$ IF F$LENGTH(P2) .LT. 3 THEN P2 = P2 + F$EXTRACT(0,3-F$LENGTH(P2),""___"")"
+$ WRITE OUFILE "$ ENDIF"
+$ WRITE OUFILE "$ P1 = F$EDIT(P1,""COLLAPSE"")"
+$ WRITE OUFILE "$ IF P1 .EQS. """" THEN P1 = ""GTM$DIST:''GTCM$VOLCONF'"""
+$ WRITE OUFILE "$ DEFINE /SYSTEM GTMDDP_VOLCONF_'P2' 'P1'"
+$ WRITE OUFILE "$ IF P3 .NES. """""
+$ WRITE OUFILE "$ THEN"
+$ WRITE OUFILE "$ DEFINE /SYSTEM GTMDDP_CONTROLLER_'P2' 'P3'"
+$ WRITE OUFILE "$ ELSE"
+$ WRITE OUFILE "$ IF F$TRNLNM(""GTMDDP_CONTROLLER_'","'P2'"",""LNM$SYSTEM_TABLE"") .NES. """""
+$ WRITE OUFILE "$ THEN"
+$ WRITE OUFILE "$ DEASSIGN /SYSTEM GTMDDP_CONTROLLER_'P2'"
+$ WRITE OUFILE "$ ENDIF"
+$ WRITE OUFILE "$ ENDIF"
+$ WRITE OUFILE "$ IF P4 .EQS. """" THEN P4 = ""0"""
+$ WRITE OUFILE "$ DEFINE /SYSTEM GTMDDP_GROUPS_'P2' ""'","'P4'"""
+$ WRITE OUFILE "$ P5A = F$ELEMENT(0,"","",P5)"
+$ WRITE OUFILE "$ IF P5A .EQS. "," THEN P5A :="
+$ WRITE OUFILE "$ P5B = F$ELEMENT(1,"","",P5)"
+$ WRITE OUFILE "$ IF P5B .EQS. "," THEN P5B :="
+$ WRITE OUFILE "$ P5C = F$ELEMENT(2,"","",P5)"
+$ WRITE OUFILE "$ IF P5C .EQS. "," THEN P5C :="
+$ WRITE OUFILE "$ MINRECSIZE = 1024"
+$ WRITE OUFILE "$ IF P5A .LT. MINRECSIZE THEN P5A = MINRECSIZE"
+$ WRITE OUFILE "$ DEFINE /SYSTEM GTMDDP_MAXRECSIZE_'P2' 'P5A'"
+$ WRITE OUFILE "$ IF P5B .NES. """""
+$ WRITE OUFILE "$ THEN"
+$ WRITE OUFILE "$ DEFINE /SYSTEM GTMDDP_ETHRCVBUFCNT_'P2' 'P5B'"
+$ WRITE OUFILE "$ ELSE"
+$ WRITE OUFILE "$ IF F$TRNLNM(""GTMDDP_ETHRCVBUFCNT_'","'P2'"",""LNM$SYSTEM_TABLE"") .NES. """""
+$ WRITE OUFILE "$ THEN"
+$ WRITE OUFILE "$ DEASSIGN /SYSTEM GTMDDP_ETHRCVBUFCNT_'P2'"
+$ WRITE OUFILE "$ ENDIF"
+$ WRITE OUFILE "$ ENDIF"
+$ WRITE OUFILE "$ IF P5C .NES. """""
+$ WRITE OUFILE "$ THEN"
+$ WRITE OUFILE "$ DEFINE /SYSTEM GTMDDP_MAXREQCREDITS_'P2' 'P5C'"
+$ WRITE OUFILE "$ ELSE"
+$ WRITE OUFILE "$ IF F$TRNLNM(""GTMDDP_MAXREQCREDITS_'","'P2'"",""LNM$SYSTEM_TABLE"") .NES. """""
+$ WRITE OUFILE "$ THEN"
+$ WRITE OUFILE "$ DEASSIGN /SYSTEM GTMDDP_MAXREQCREDITS_'P2'"
+$ WRITE OUFILE "$ ENDIF"
+$ WRITE OUFILE "$ ENDIF"
+$ WRITE OUFILE "$ PROCNAME := GTMDDP_SERV_'P2'"
+$ WRITE OUFILE "$ WRITE SYS$OUTPUT ""Starting the GT.CM DDP Server as process "",PROCNAME"
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! Note, all logicals are keyed by the <CIRCUIT_NAME>, but to pass the"
+$ WRITE OUFILE "$! the circuit name to the server, we use a logical <server-process-name>,"
+$ WRITE OUFILE "$! the value of which will be set to the CIRCUIT_NAME by this script."
+$ WRITE OUFILE "$! Server will find its circuit name by translating the logical"
+$ WRITE OUFILE "$! <server-process-name>"
+$ WRITE OUFILE "$ DEFINE /SYSTEM 'PROCNAME' 'P2'"
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$ P6A = F$ELEMENT(0,"","",P6)"
+$ WRITE OUFILE "$ IF P6A .EQS. "","" then P6A :="
+$ WRITE OUFILE "$ P6B = F$ELEMENT(1,"","",P6)"
+$ WRITE OUFILE "$ IF P6B .EQS. "","" THEN P6B :="
+$ WRITE OUFILE "$ P6C = F$ELEMENT(2,"","",P6)"
+$ WRITE OUFILE "$ IF P6C .EQS. "","" THEN P6C :="
+$ WRITE OUFILE "$ P6D = F$ELEMENT(3,"","",P6)"
+$ WRITE OUFILE "$ IF P6D .EQS. "","" THEN P6D :="
+$ WRITE OUFILE "$ P6E = F$ELEMENT(4,"","",P6)"
+$ WRITE OUFILE "$ IF P6E .EQS. "","" THEN P6E :="
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$ IF P6A .EQS. """" THEN P6A = ''GTCM$NDB_CNT'"
+$ WRITE OUFILE "$ IF P6B .EQS. """" THEN P6B = ''GTCM$RC_CNT'"
+$ WRITE OUFILE "$ AL = ((P6A + 1) * 3) + P6B"
+$ WRITE OUFILE "$ BL = (P6B + 3) * 1024"
+$ WRITE OUFILE "$ EL = (P6A + 1) * 3"
+$ WRITE OUFILE "$ FL = P6A + 3 + PP7"
+$ WRITE OUFILE "$ DL = P6A * 7"
+$ WRITE OUFILE "$ TQ = (P6A + 1) * 2"
+$ WRITE OUFILE "$ IF P6C .EQS. """" THEN P6C = FL * 200"
+$ WRITE OUFILE "$ WSE = P6C + 200"
+$ WRITE OUFILE "$ IF P6D .EQS. """" THEN P6D = 5"
+$ WRITE OUFILE "$ IF P6E .EQS. """" THEN P6E = 30000"
+$ WRITE OUFILE "$ PF = P6A * 10000"
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$ RUN /DETACHED /PROCESS='PROCNAME' /PRIV=(SYSNAM) -"
+$ WRITE OUFILE " /ERROR=SYS$MANAGER:DDP_CME.LOG -"
+$ WRITE OUFILE " /DUMP /NOSWAPPING /UIC=''GTCM$SRV_UIC' /AST_LIMIT='AL' /ENQUEUE_LIMIT='EL' -"
+$ WRITE OUFILE " /FILE_LIMIT='FL' /IO_BUFFERED='BL' /IO_DIRECT='DL' /QUEUE_LIMIT='TQ' -"
+$ WRITE OUFILE " /PRIORITY='P6D' /WORKING_SET='P6C' /MAXIMUM_WORKING_SET='WSE' -"
+$ WRITE OUFILE " /BUFFER_LIMIT='P6E' /PAGE_FILE='PF' GTM$DIST:DDPSERVER"
+$ WRITE OUFILE "$ ELSE"
+$ WRITE OUFILE "$ WRITE SYS$OUTPUT ""NOT starting GT.CM DDP Server because of inadequate privileges"""
+$ WRITE OUFILE "$ ENDIF"
+$ WRITE OUFILE "$ERROR:"
+$ WRITE OUFILE "$ CURPRV = F$SETPRV(CURPRV)"
+$ WRITE OUFILE "$ EXIT"
+$ CLOSE OUFILE
+$! Create GTCMDDPSTOP.COM
+$ OPEN /WRITE OUFILE VMI$KWD:GTCMDDPSTOP.COM
+$ WRITE OUFILE "$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
+$ WRITE OUFILE "$! !"
+$ WRITE OUFILE "$! Copyright 1988, 2003 Sanchez Computer Associates, Inc. !"
+$ WRITE OUFILE "$! !"
+$ WRITE OUFILE "$! This source code contains the intellectual property !"
+$ WRITE OUFILE "$! of its copyright holder(s), and is made available !"
+$ WRITE OUFILE "$! under a license. If you do not know the terms of !"
+$ WRITE OUFILE "$! the license, please stop and do not read further. !"
+$ WRITE OUFILE "$! !"
+$ WRITE OUFILE "$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! GTCMDDPSTOP.COM stops the GT.CM DDP Server for a node."
+$ WRITE OUFILE "$! Place an invocation or copy of this procedure in the site specific"
+$ WRITE OUFILE "$! shutdown: SYS$MANAGER:SYSHUTDWN to ensure all GT.M databases are"
+$ WRITE OUFILE "$! properly closed before VMS terminates. GTCMDDPSTOP should precede"
+$ WRITE OUFILE "$! GTCXSTOP, if used, and GTMSTOP, in any case."
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$ STOPIMAGE := $GTM$DIST:GTCMDDPSTOP.EXE"
+$ WRITE OUFILE "$ STOPIMAGE DDPSERVER"
+$ WRITE OUFILE "$ EXIT"
+$ CLOSE OUFILE
+$! Create the volume configuration file
+$ OPEN /WRITE OUFILE VMI$KWD:'GTCM$VOLCONF'
+$ WRITE OUFILE "#################################################################"
+$ WRITE OUFILE "# #"
+$ WRITE OUFILE "# Copyright 2002, 2003 Sanchez Computer Associates, Inc. #"
+$ WRITE OUFILE "# #"
+$ WRITE OUFILE "# This source code contains the intellectual property #"
+$ WRITE OUFILE "# of its copyright holder(s), and is made available #"
+$ WRITE OUFILE "# under a license. If you do not know the terms of #"
+$ WRITE OUFILE "# the license, please stop and do not read further. #"
+$ WRITE OUFILE "# #"
+$ WRITE OUFILE "#################################################################"
+$ WRITE OUFILE ""
+$ WRITE OUFILE "# The first argument to the GT.M DDP startup script (GTCMDDPSTART.COM)"
+$ WRITE OUFILE "# is the name of the configuration file listing the VOLUMEs and UCIs"
+$ WRITE OUFILE "# that the server serves. If the first argument is not specified,"
+$ WRITE OUFILE "# this file is used."
+$ WRITE OUFILE ""
+$ WRITE OUFILE "# Empty lines and those beginning with # are ignored by the server."
+$ WRITE OUFILE ""
+$ WRITE OUFILE "# One VOLUME, UCI, GLD triple can be specified on a line as"
+$ WRITE OUFILE "# VOL UCI GLD"
+$ WRITE OUFILE "# VOL and UCI must be three characters long and consist of only"
+$ WRITE OUFILE "# uppercase letters."
+$ WRITE OUFILE ""
+$ WRITE OUFILE "# There can be any number of white space characters between the VOLUME"
+$ WRITE OUFILE "# and UCI, and UCI and GLD. All characters after the first white space"
+$ WRITE OUFILE "# after GLD are ignored."
+$ WRITE OUFILE ""
+$ WRITE OUFILE "# There must be at least one valid entry for the server to start"
+$ WRITE OUFILE "# succesfully. No more than 16 entries are accepted by the server."
+$ WRITE OUFILE "# If multiple entries exist for the same VOLUME, UCI pair, the last"
+$ WRITE OUFILE "# entry is accepted and all previous entries are ignored."
+$ WRITE OUFILE ""
+$ WRITE OUFILE "''GTCM$VOL_NAME' ''GTCM$UCI_NAME' GTM$DIST:''GTCM$GBLDIR'"
+$ CLOSE OUFILE
+$!
+$ VMI$CALLBACK MESSAGE I PREINS "Preparing files for installation."
+$! GTCMFILES.KIT must be maintained as kit contents change
+$ OPEN /WRITE OUFILE VMI$KWD:GTCMFILES.KIT
+$ WRITE OUFILE "GTCM$ GTCMDDPSTART.COM VMI$ROOT:[SYSMGR] C"
+$ WRITE OUFILE "GTCM$ GTCMDDPSTOP.COM VMI$ROOT:[SYSMGR] C"
+$ WRITE OUFILE "GTCM$ GTCMDDPSTART.COM ''GTCM$DST_LOG'"
+$ WRITE OUFILE "GTCM$ GTCMDDPSTOP.COM ''GTCM$DST_LOG'"
+$ WRITE OUFILE "GTCM$ ''GTCM$VOLCONF' ''GTCM$DST_LOG'"
+$ CLOSE OUFILE
+$! GTCMIMAGES.KIT must be maintained as kit contents change
+$ OPEN /WRITE OUFILE VMI$KWD:GTCMIMAGES.KIT
+$ WRITE OUFILE "GTCM$ DDPGVUSR.EXE ''GTCM$DST_LOG'"
+$ WRITE OUFILE "GTCM$ DDPSERVER.EXE ''GTCM$DST_LOG'"
+$ WRITE OUFILE "GTCM$ GTCMDDPSTOP.EXE ''GTCM$DST_LOG'"
+$ CLOSE OUFILE
+$! Provide the command procedures and configuration file(s)
+$ VMI$CALLBACK PROVIDE_FILE "" VMI$KWD:GTCMFILES.KIT "" T
+$! Make sure the owner is who the installer asked for
+$ VMI$CALLBACK SECURE_FILE 'GTCM$DST_LOG'GTCMDDPSTART.COM ['GTCM$DST_OWN']
+$ VMI$CALLBACK SECURE_FILE 'GTCM$DST_LOG'GTCMDDPSTOP.COM ['GTCM$DST_OWN']
+$ VMI$CALLBACK SECURE_FILE 'GTCM$DST_LOG''GTCM$VOLCONF' ['GTCM$DST_OWN']
+$!
+$! Provide the images
+$ VMI$CALLBACK PROVIDE_IMAGE "" VMI$KWD:GTCMIMAGES.KIT "" T
+$! Make sure the owner is who the installer asked for
+$ VMI$CALLBACK SECURE_FILE 'GTCM$DST_LOG'DDPGVUSR.EXE ['GTCM$DST_OWN']
+$ VMI$CALLBACK SECURE_FILE 'GTCM$DST_LOG'DDPSERVER.EXE ['GTCM$DST_OWN']
+$ VMI$CALLBACK SECURE_FILE 'GTCM$DST_LOG'GTCMDDPSTOP.EXE ['GTCM$DST_OWN']
+$!
+$ VMI$CALLBACK MESSAGE I FININS "Finalizing the installation."
+$ IF GTCM$START_CM THEN VMI$CALLBACK SET POSTINSTALL YES
+$ IF GTCM$RUN_IVP THEN VMI$CALLBACK SET IVP YES
+$ IF GTCM$STARTDB THEN VMI$CALLBACK MODIFY_STARTUP_DB ADD GTCMDDPSTART.COM END
+$ EXIT VMI$_SUCCESS
+$!
+$POSTINSTALL:
+$!
+$ @'GTCM$DST_LOG'GTMLOGIN
+$ SET NOON
+$ DEFINE /USER_MODE SYS$ERROR NL:
+$ DEFINE /USER_MODE SYS$OUTPUT NL:
+$ IF GTCM$MGR_COM
+$ THEN
+$ T1 := SYS$MANAGER:
+$ ELSE
+$ T1 = GTCM$DST_LOG
+$ ENDIF
+$ @'T1'GTCMDDPSTOP
+$ SET ON
+$ @'T1'GTCMDDPSTART
+$ EXIT VMI$_SUCCESS
+$!
+$IVP:
+$! The real Installation Verification Procedure.
+$ TYPE SYS$INPUT
+
+ GT.CM DDP Installation Verification Procedure
+
+$! Extract the IVP .COM file from the text library.
+$ LIBRARIAN /EXTRACT=GTCMDDP$IVP /OUTPUT=GTCMDDP$IVP.COM GTCMDDP$IVP.TLB
+$ @GTCMDDP$IVP
+$ EXIT $STATUS
diff --git a/sr_vvms/ddpserver.c b/sr_vvms/ddpserver.c
new file mode 100644
index 0000000..309c5d4
--- /dev/null
+++ b/sr_vvms/ddpserver.c
@@ -0,0 +1,466 @@
+#/****************************************************************
+ * *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_stdio.h"
+#include "gtm_string.h"
+#include "gtm_time.h"
+
+#include <stddef.h>
+#include <ssdef.h>
+#include <lnmdef.h>
+#include <descrip.h>
+#include <fab.h>
+#include <rms.h>
+#include <iodef.h>
+#include <errno.h>
+
+#include "ddphdr.h"
+#include "ddpcom.h"
+#include "vmsdtype.h" /* for trans_log_name */
+#include "io.h"
+#include "dcpsubs.h"
+#include "decddp.h"
+#include "dcp_a2c.h"
+#include "route_table.h"
+#include "ddp_trace_output.h"
+#include "cce_output.h"
+#include "trans_log_name.h"
+#include "logical_truth_value.h"
+#include "gtm_ctype.h"
+#include "cli.h"
+#include "eintr_wrappers.h"
+#include "gtm_env_init.h" /* for gtm_env_init() prototype */
+
+GBLDEF boolean_t ddp_trace;
+GBLDEF unsigned short my_group_mask = DDP_DEFAULT_GROUP_MASK;
+GBLDEF volset_tab volset_table[DDP_MAX_VOLSETS];
+
+GBLREF unsigned short my_circuit;
+GBLREF com_hdr_t *com_area;
+GBLREF struct dsc$descriptor ddp_result;
+GBLREF unsigned char decddp_multicast_addr[ETHERADDR_LENGTH];
+GBLREF mval dollar_zproc;
+GBLREF int4 ddp_slot_size;
+
+error_def(ERR_DDPOUTMSG2BIG);
+
+static char ddp_input_buffer[offsetof(struct in_buffer_struct, dh) + MAX_ETHER_DATA_SIZE];
+static struct
+{
+ int4 link;
+ void (*exit_hand)();
+ int4 arg_cnt;
+ int4 *cond_val;
+} exi_desblk;
+static int4 exi_condition;
+
+static void self_wake(void);
+
+void ddp_return_error(struct in_buffer_struct *bp, char *msg);
+void reply_to_client(int chn, char *buff, int bufflen);
+void declare_client_error(int chn, char m);
+void declare_err_msg(ddp_hdr_t *ddptr_client, ddp_hdr_t *ddptr_server, char *error);
+void ddp_exi_rundown(void);
+
+mainx()
+{
+ /* server automatic declarations */
+ condition_code gtm$gbldata();
+ condition_code gtm$gblget();
+ condition_code gtm$gblkill();
+ condition_code gtm$gblorder();
+ condition_code gtm$gblprevious();
+ condition_code gtm$gblput();
+ condition_code gtm$gblquery();
+ condition_code gtm$lock2();
+ condition_code gtm$zdealloc2();
+ condition_code status;
+ int ckt;
+ boolean_t sendit, input_pending, circuit_entered;
+ mstr trace_logical = {LEN_AND_LIT(DDP_TRACE_ENV)};
+ char *addr, *topaddr, *errmsg;
+ ddp_hdr_t *ddptr;
+ routing_tab *remote_node;
+ struct frame_hdr *frame;
+ struct in_buffer_struct *bufptr = (struct in_buffer_struct *)ddp_input_buffer;
+ ddp_announce_msg_t *ap;
+ ddp_global_request_t *gp;
+ char errstr[1024];
+ DCL_THREADGBL_ACCESS;
+
+ /* Agent automatic declarations */
+ unsigned char *buff;
+ short len;
+ int4 jobno;
+ com_slot_t *cptr;
+
+ GTM_THREADGBL_INIT;
+ gtm_env_init(); /* read in all environment variables before any function call (particularly malloc) */
+ if (ddp_trace = logical_truth_value(&trace_logical, FALSE, NULL))
+ cce_out_open();
+
+ getzprocess();
+ status = dcp_get_circuit(&dollar_zproc);
+ if (0 == (status & 1))
+ {
+ decddp_log_error(status, "Circuit Name initialization failed", 0, 0);
+ return status;
+ }
+ status = dcp_get_volsets();
+ if (0 == (status & 1))
+ {
+ decddp_log_error(status, "Volume Set initialization failed", 0, 0);
+ return status;
+ }
+
+ status = dcp_get_groups();
+ if (0 == (status & 1))
+ {
+ decddp_log_error(status, "Group mask initialization failed", 0, 0);
+ return status;
+ }
+
+ status = dcp_get_maxrecsize();
+ if (0 == (status & 1))
+ {
+ decddp_log_error(status, "Max record size could not be found", 0, 0);
+ return status;
+ }
+
+ ddp_result.dsc$b_dtype = DSC$K_DTYPE_T;
+ ddp_result.dsc$b_class = DSC$K_CLASS_D;
+ ddp_result.dsc$w_length = 0;
+
+ gtm$init();
+
+ status = decddp_init();
+ if (0 == (status & 1))
+ {
+ decddp_log_error(status, "Ethernet controller initialization failed", 0, 0);
+ return status;
+ }
+ decddp_shdr(DDPTR_ANNOUNCE, 1, 1, 0, 0, decddp_multicast_addr);
+ decddp_sinit("WI");
+ status = decddp_send();
+ if (0 == (status & 1))
+ {
+ decddp_log_error(status, "Network connection failed", 0, 0);
+ return status;
+ }
+ decddp_log_error(0, "Server has connected to network", 0, 0);
+
+ /* Establish exit handler */
+ exi_desblk.exit_hand = ddp_exi_rundown;
+ exi_desblk.arg_cnt = 1;
+ exi_desblk.cond_val = &exi_condition;
+ sys$dclexh(&exi_desblk);
+
+ status = dcpa_shm_init();
+ if (0 == (status & 1))
+ {
+ decddp_log_error(status, "Agent buffer initialization failed", 0, 0);
+ return status;
+ }
+
+/**************
+ self_wake();
+*/
+ for (;;)
+ {
+ /* The input + output loop is structured in this way in order to make input and output 'fair' */
+ input_pending = dcp_get_input_buffer(bufptr, SIZEOF(ddp_input_buffer));
+ if (NULL != (cptr = dcpa_read()))
+ { /* Service local client request */
+ len = cptr->len;
+ jobno = ((unsigned char *)cptr - (unsigned char *)com_area->slot) / ddp_slot_size;
+ ddptr = buff = cptr->text;
+ assert((jobno + 1) == (ddptr->source_job_number >> 1));
+ if (DDPTR_USEREXIT != ddptr->trancode)
+ {
+ ddptr->source_circuit_name = my_circuit;
+ /* client gives us the name of the volume set. we translate it to the node supporting it */
+ if (0 == (ckt = find_circuit(ddptr->remote_circuit_name)))
+ {
+ declare_client_error(jobno, DDPTRX_NOCONNECT);
+ continue;
+ }
+ ddptr->remote_circuit_name = ckt;
+ remote_node = find_route(ckt);
+ if (!remote_node)
+ {
+ declare_client_error(jobno, DDPTRX_NOCONNECT);
+ continue;
+ }
+ ddptr->message_number = remote_node->outgoing_users[jobno];
+ decddp_set_etheraddr(remote_node->ether_addr);
+ status = dcp_send_message(buff, len, &cptr->iosb);
+ if (0 == (status & 1))
+ {
+ decddp_log_error(status, "Server transmission failed", &ckt, 0);
+ if (0 != cptr->state)
+ {
+ declare_err_msg(ddptr, ddptr, DDP_XMIT_FAIL);
+ dcpa_send(cptr);
+ }
+ }
+ } else
+ {
+ reset_user_count(jobno);
+ dcpa_free_user(cptr);
+ }
+ } else
+ {
+ if (!input_pending)
+ sys$hiber();
+ }
+ if (input_pending)
+ { /* Service remote request */
+ sendit = TRUE;
+ errmsg = NULL;
+ frame = &bufptr->fh;
+ ddptr = &bufptr->dh;
+ switch (ddptr->trancode)
+ {
+ case DDPTR_GET:
+ errmsg = ddp_db_op(bufptr, gtm$gblget, NULL, 0);
+ break;
+ case DDPTR_PUT:
+ gp = ddptr->txt;
+ addr = gp->global + gp->global_len;
+ topaddr = ((char *)ddptr) + ddptr->message_length;
+ if (addr > topaddr)
+ {
+ errmsg = "<FORMT>";
+ break;
+ }
+ errmsg = ddp_db_op(bufptr, gtm$gblput, addr, topaddr - addr - 1); /* -1 to get rid of the mysterious
+ * last byte in PUT message */
+ break;
+ case DDPTR_KILL:
+ errmsg = ddp_db_op(bufptr, gtm$gblkill,(char *)1 ,0);
+ break;
+ case DDPTR_ORDER:
+ errmsg = ddp_db_op(bufptr, gtm$gblorder, NULL, 0);
+ break;
+ case DDPTR_PREVIOUS:
+ errmsg = ddp_db_op(bufptr, gtm$gblprevious, NULL, 0);
+ break;
+ case DDPTR_DEFINE:
+ errmsg = ddp_db_op(bufptr, gtm$gbldata, NULL, 0);
+ break;
+ case DDPTR_QUERY:
+ errmsg = ddp_db_op(bufptr, gtm$gblquery, NULL, 0);
+ break;
+ case DDPTR_ZALLOC:
+ errmsg = ddp_lock_op(bufptr, gtm$lock2, 0);
+ break;
+ case DDPTR_ZDEALLOC:
+ errmsg = ddp_lock_op(bufptr, gtm$zdealloc2, 1);
+ break;
+ case DDPTR_ANNOUNCE:
+ ap = ddptr->txt;
+ if ('W' != ap->code[0] || 'I' != ap->code[1])
+ {
+ sendit = FALSE;
+ if ('I' == ap->code[0] && 'S' == ap->code[1])
+ {
+ remove_circuits(ddptr);
+ enter_circuits(ddptr);
+ decddp_log_error(0, "Volume set configuration has changed",
+ &bufptr->dh.source_circuit_name, &bufptr->dh.source_job_number);
+ } else if ('I' == ap->code[0] && 'D' == ap->code[1])
+ {
+ remove_circuits(ddptr);
+ decddp_log_error(0, "Circuit has shut-down",
+ &bufptr->dh.source_circuit_name, &bufptr->dh.source_job_number);
+ } else if (('I' == ap->code[0] && 'I' == ap->code[1]) ||
+ ('W' == ap->code[0] && 'A' == ap->code[1]))
+ {
+ if (FALSE != (circuit_entered = enter_circuits(ddptr))
+ && ('W' != ap->code[0] || 'A' != ap->code[1]))
+ decddp_log_error(0,"System connected in response to our connection request",
+ &bufptr->dh.source_circuit_name, &bufptr->dh.source_job_number);
+ }
+ } else if (FALSE != (sendit = enter_circuits(ddptr)))
+ { /* code == WI and we belong to some group that the announcer also belongs to */
+ decddp_log_error(0, "System is now connected",
+ &bufptr->dh.source_circuit_name, &bufptr->dh.source_job_number);
+ decddp_shdr(DDPTR_ANNOUNCE, 1, 1, 0, 0, frame->source_address);
+ decddp_sinit("II");
+ }
+ break;
+ case DDPTR_RESPONSE:
+ case DDPTR_ERRESPONSE:
+ sendit = FALSE;
+ errmsg = NULL;
+ jobno = (ddptr->remote_job_number >> 1);
+ jobno -= 1;
+ assert(jobno >= 0 && jobno < MAX_USERS_PER_NODE);
+ remote_node = find_route(ddptr->source_circuit_name);
+ /* ignore if we can't match the message sequence numbers */
+ if (remote_node && remote_node->outgoing_users[jobno] == ddptr->message_number)
+ {
+ remote_node->outgoing_users[jobno]++;
+ reply_to_client(jobno, ddptr, ddptr->message_length);
+ }
+ break;
+ default:
+ SNPRINTF(errstr, SIZEOF(errstr), "Unknown transaction code type: %d", ddptr->trancode);
+ decddp_log_error(0, errstr, &bufptr->dh.source_circuit_name, &bufptr->dh.source_job_number);
+ errmsg = "<FORMT>"; /* Let the server know that this was a badly formatted message */
+ break;/* throw away unkown transaction types */
+ }
+ if (NULL != errmsg)
+ {
+ if ('\0' != *errmsg)
+ ddp_return_error(bufptr, errmsg);
+ else
+ { /* a null error msg indicates a sequencing error - the message is ignored */
+ SNPRINTF(errstr, SIZEOF(errstr),
+ "Sequencing error - expected: %d, got: %d", remote_node->incoming_users[jobno] + 1,
+ bufptr->dh.message_number);
+ decddp_log_error(0, errstr,
+ &bufptr->dh.source_circuit_name, &bufptr->dh.source_job_number);
+ }
+ } else if (sendit)
+ {
+ status = decddp_send();
+ if (0 == (status & 1))
+ {
+ decddp_log_error(status, "Server response transmission failed",
+ &bufptr->dh.source_circuit_name, &bufptr->dh.source_job_number);
+ if (ERR_DDPOUTMSG2BIG == status)
+ ddp_return_error(bufptr, "<DBDGD>"); /* should ideally be something like
+ * "<MSG2BIG>", but we don't yet know the
+ * code DSM uses - Vinaya 06/28/02 */
+ }
+ }
+ }
+ }
+}
+
+/* Client subroutines */
+void ddp_return_error(struct in_buffer_struct *bp, char *msg)
+{
+ condition_code status;
+
+ decddp_shdr(DDPTR_ERRESPONSE, 1, bp->dh.source_circuit_name, bp->dh.source_job_number,
+ bp->dh.message_number, bp->fh.source_address);
+ (void)decddp_s8bit(msg);
+ decddp_putbyte(DDP_MSG_TERMINATOR);
+ status = decddp_send();
+ if (0 == (status & 1))
+ {
+ assert(ERR_DDPOUTMSG2BIG != status);
+ decddp_log_error(status, "Server error response transmission failed",
+ &bp->dh.source_circuit_name, &bp->dh.source_job_number);
+ }
+}
+
+static void self_wake(void)
+{
+ static readonly int4 timeout[2] = {-50000000, -1}; /* 5 seconds */
+ sys$wake(0, 0);
+ sys$setimr(0, timeout, self_wake, 0, 0);
+}
+
+/* Agent subroutines */
+
+void reply_to_client(int chn, char *buff, int bufflen)
+{
+ com_slot_t *cp;
+ ddp_hdr_t *ddptr_r, *ddptr_s;
+ DEBUG_ONLY(unsigned char *extref;)
+ DEBUG_ONLY(ddp_global_request_t *gp;)
+
+ cp = (com_slot_t *)((unsigned char *)com_area->slot + chn * ddp_slot_size);
+ assert(0 != cp->pid);
+ /* Only reply once. If state is zero, then there is alreay a message
+ in the buffer or a time out. Don't overlay message.
+ State may also be zero because we have timed out, in which case we
+ don't want to overlay the retry message */
+ if (0 == cp->state)
+ return;
+ ddptr_r = (ddp_hdr_t *)buff;
+ ddptr_s = (ddp_hdr_t *)cp->text; /* until we overwrite this com slot, the slot contains the message we sent */
+ if ((DDPTR_QUERY != ddptr_s->trancode) || 1 == bufflen || (1 == (ddptr_r->message_length - ddptr_r->hdrlen)))
+ { /* non QUERY operation, OR,
+ * came here from declare_client_error, OR
+ * "" result from QUERY (message contains 0xFF, just one byte) */
+ if (ddp_slot_size - offsetof(com_slot_t, text[0]) >= bufflen)
+ {
+ cp->len = bufflen;
+ memcpy(ddptr_s, ddptr_r, bufflen);
+ } else
+ { /* we don't want to trash someone else's slot; declare error instead */
+ assert(1 != bufflen); /* if we came into this function from declare_client_error, we should have sufficient
+ space in slot. Also, calling declare_err_msg is not good when there is no message
+ that has been formatted in the buffer. */
+ declare_err_msg(ddptr_s, ddptr_r, DDP_MSG2BIG);
+ }
+ } else
+ { /* remove the extended reference from the response */
+ assert(DSM_EXTREF_FORM_LEN < ddptr_r->message_length - ddptr_r->hdrlen);
+ DEBUG_ONLY(extref = ddptr_r->txt);
+ DEBUG_ONLY(gp = ddptr_s->txt);
+ assert(0 == memcmp(extref, DSM_EXTREF_PREFIX, STR_LIT_LEN(DSM_EXTREF_PREFIX)));
+ assert(gp->uci == five_bit(&extref[STR_LIT_LEN(DSM_EXTREF_PREFIX)]));
+ assert(0 == memcmp(&extref[STR_LIT_LEN(DSM_EXTREF_PREFIX) + DDP_UCI_NAME_LEN],
+ DSM_UCI_VOL_SEPARATOR, STR_LIT_LEN(DSM_UCI_VOL_SEPARATOR)));
+ assert(gp->vol ==
+ five_bit(&extref[STR_LIT_LEN(DSM_EXTREF_PREFIX) + DDP_UCI_NAME_LEN + STR_LIT_LEN(DSM_UCI_VOL_SEPARATOR)]));
+ assert(0 == memcmp(&extref[STR_LIT_LEN(DSM_EXTREF_PREFIX) + DDP_UCI_NAME_LEN +
+ STR_LIT_LEN(DSM_UCI_VOL_SEPARATOR) + DDP_VOLUME_NAME_LEN],
+ DSM_EXTREF_SUFFIX, STR_LIT_LEN(DSM_EXTREF_SUFFIX)));
+ assert(DDP_MSG_TERMINATOR == ddptr_r->txt[ddptr_r->message_length - ddptr_r->hdrlen - 1]);
+ if (ddp_slot_size - ddptr_r->message_length >= offsetof(com_slot_t, text[0]) - (DSM_EXTREF_FORM_LEN - 1))
+ { /* we don't want to trash someone else's slot; declare error instead */
+ memcpy((char *)ddptr_s, (char *)ddptr_r, ddptr_r->hdrlen); /* copy the header */
+ ddptr_s->message_length -= (DSM_EXTREF_FORM_LEN - 1); /* adjust for the removal of the extref prefix */
+ /* -1 because we want to retain ^ */
+ ddptr_s->txt[0] = '^'; /* global indicator */
+ memcpy(&ddptr_s->txt[1],
+ &ddptr_r->txt[DSM_EXTREF_FORM_LEN], /* global without the extref prefix */
+ ddptr_r->message_length - ddptr_r->hdrlen - DSM_EXTREF_FORM_LEN);
+ } else
+ declare_err_msg(ddptr_s, ddptr_r, DDP_MSG2BIG);
+ }
+ dcpa_send(cp);
+ return;
+}
+
+void declare_client_error(int chn, char m)
+{
+ reply_to_client(chn, &m, SIZEOF(m));
+ return;
+}
+
+void declare_err_msg(ddp_hdr_t *ddptr_client, ddp_hdr_t *ddptr_server, char *error)
+{ /* error should be '\0' terminated */
+ int error_len;
+
+ error_len = strlen(error) + 1; /* we want the terminating null to be copied due to the way we compute the message length
+ * for response messages in ddpgvusr */
+ memcpy((char *)ddptr_client, (char *)ddptr_server, ddptr_server->hdrlen); /* copy the header */
+ memcpy(ddptr_client->txt, error, error_len); /* Change the message text */
+ ddptr_client->message_length = ddptr_client->hdrlen + error_len;
+ ddptr_client->trancode = DDPTR_ERRESPONSE;
+}
+
+void ddp_exi_rundown(void)
+{
+
+ decddp_shdr(DDPTR_ANNOUNCE, 1, 1, 0, 0, decddp_multicast_addr);
+ decddp_sinit("ID");
+ decddp_send();
+}
diff --git a/sr_vvms/dec_err.c b/sr_vvms/dec_err.c
new file mode 100644
index 0000000..00548a5
--- /dev/null
+++ b/sr_vvms/dec_err.c
@@ -0,0 +1,42 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2005 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "msg.h"
+#include <stdarg.h>
+
+GBLREF bool dec_nofac;
+
+void dec_err(int4 msgnum, ...)
+{
+ va_list var;
+ uint4 i, count, argcnt;
+ msgtype msg;
+
+ VAR_START(var, msgnum);
+ va_count(argcnt);
+ msg.msg_number = msgnum;
+ argcnt--;
+ if (argcnt)
+ { count = va_arg(var, int4);
+ assert (count <= argcnt);
+ } else
+ count = 0;
+
+ count = (count > DEF_MSG_ARGS ? DEF_MSG_ARGS : count);
+ msg.new_opts = msg.def_opts = dec_nofac;
+ msg.arg_cnt = 2 + count; /* count + overhead */
+ msg.fp_cnt = count;
+ for (i = 0; i < count; i++)
+ msg.fp[i].n = va_arg(var, int4);
+ sys$putmsg(&msg,0,0,0);
+ va_end(var);
+}
diff --git a/sr_vvms/decddp.c b/sr_vvms/decddp.c
new file mode 100644
index 0000000..9117eaa
--- /dev/null
+++ b/sr_vvms/decddp.c
@@ -0,0 +1,393 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <descrip.h>
+#include <iodef.h>
+#include <ssdef.h>
+#include <efndef.h>
+#include <lnmdef.h> /* for trans_log_name */
+#include <stddef.h>
+
+#include "ddphdr.h"
+#include "ddpcom.h"
+#include "vmsdtype.h" /* for trans_log_name */
+#include "nmadef.h"
+#include "dcpsubs.h"
+#include "decddp.h"
+#include "ddp_trace_output.h"
+#include "trans_log_name.h"
+#include "five_bit.h"
+#include "five_2_ascii.h"
+
+/* Ethernet controller information. */
+
+#define XMTBUFLEN MAX_ETHER_DATA_SIZE /* size of a transmit buffer */
+#define RETRY_LIMIT 3 /* number of attempts to get past an error (as of this writing used by send) */
+
+GBLDEF unsigned char decddp_multicast_addr[ETHERADDR_LENGTH] = {9, 0, 0x2b, 0, 0, 1};
+
+GBLREF unsigned short my_circuit;
+GBLREF unsigned short my_group_mask; /* filled in dcp_get_group_mask */
+GBLREF boolean_t ddp_trace;
+GBLREF volset_tab volset_table[];
+GBLREF mstr my_circuit_name;
+
+typedef struct
+{
+ int4 buflen;
+ unsigned char *bufptr;
+} quad_desc;
+
+#ifdef __ALPHA
+# pragma member_alignment save
+# pragma nomember_alignment
+#endif
+
+static struct
+{
+ short parm_id;
+ int4 parm_val;
+} setparm[] =
+{ /* Keep NMA$C_PCLI_BFN as the first element */
+ {NMA$C_PCLI_BFN, ETH_RCV_BUFCNT}, /* GT.CM default # of receive buffers to preallocate */
+ {NMA$C_PCLI_FMT, NMA$C_LINFM_ETH}, /* packet format = ethernet packet format */
+ {NMA$C_PCLI_PTY, DDP_ETH_PROTO_TYPE}, /* protocol type = Distributed Data Processing (DDP) protocol */
+ {NMA$C_PCLI_PAD, NMA$C_STATE_OFF}, /* padding = no size field */
+ {NMA$C_PCLI_MLT, NMA$C_STATE_ON}, /* multicast address state = accecpt all multicast addresses */
+ {NMA$C_PCLI_BUS, ETHERNET_HEADER_SIZE + MAX_ETHER_DATA_SIZE} /* maximum allowable port receive data size */
+};
+
+#ifdef __ALPHA
+# pragma member_alignment restore
+#endif
+
+static quad_desc setparmdsc = {SIZEOF(setparm), setparm};
+static unsigned char sensebuf[250]; /* recommeded size for attributes buffer, see LAN Device Drivers in I/O manual */
+static quad_desc sensedsc = {SIZEOF(sensebuf), sensebuf};
+static unsigned char xmtbuf[XMTBUFLEN], *xmtbufptr = NULL;
+static struct iosb_struct read_iosb, write_iosb;
+static uint4 ethchan; /* returned ethernet channel # (only low-order word used) */
+static unsigned char destination_address[ETHERADDR_LENGTH];
+static unsigned char my_ether_addr[ETHERADDR_LENGTH];
+static boolean_t input_pending = FALSE;
+static unsigned char max_ddp_request_credits = DDP_MAX_REQUEST_CREDITS;
+/* End of ethernet control information. */
+
+static struct dsc$descriptor_s ethdsc[] =
+{
+ {STR_LIT_LEN("ECA0"), DSC$K_DTYPE_T, DSC$K_CLASS_S, "ECA0"},
+ {STR_LIT_LEN("ESA0"), DSC$K_DTYPE_T, DSC$K_CLASS_S, "ESA0"},
+ {STR_LIT_LEN("ETA0"), DSC$K_DTYPE_T, DSC$K_CLASS_S, "ETA0"},
+ {STR_LIT_LEN("EWA0"), DSC$K_DTYPE_T, DSC$K_CLASS_S, "EWA0"},
+ {STR_LIT_LEN("EXA0"), DSC$K_DTYPE_T, DSC$K_CLASS_S, "EXA0"},
+ {STR_LIT_LEN("EZA0"), DSC$K_DTYPE_T, DSC$K_CLASS_S, "EZA0"},
+ {STR_LIT_LEN("XEA0"), DSC$K_DTYPE_T, DSC$K_CLASS_S, "XEA0"},
+ {STR_LIT_LEN("XQA0"), DSC$K_DTYPE_T, DSC$K_CLASS_S, "XQA0"}
+};
+
+condition_code decddp_init(void)
+{
+ condition_code status;
+ char *sbp, logical_buffer[MAX_TRANS_NAME_LEN], translation_buffer[MAX_TRANS_NAME_LEN];
+ mstr logical, translation;
+ int4 eth_recv_bufcnt, credits;
+ struct dsc$descriptor_s ethdsc1;
+ int eth_index;
+
+ assert(0 == (SIZEOF(xmtbuf) & 1)); /* even buffer size for padding odd length outbound message */
+ logical.addr = logical_buffer;
+ memcpy(logical.addr, DDP_ETHER_DEV_PREFIX, STR_LIT_LEN(DDP_ETHER_DEV_PREFIX));
+ memcpy(&logical.addr[STR_LIT_LEN(DDP_ETHER_DEV_PREFIX)], my_circuit_name.addr, my_circuit_name.len);
+ logical.len = STR_LIT_LEN(DDP_ETHER_DEV_PREFIX) + my_circuit_name.len;
+ if (SS$_NORMAL == trans_log_name(&logical, &translation, translation_buffer))
+ {
+ ethdsc1.dsc$w_length = translation.len;
+ ethdsc1.dsc$b_dtype = DSC$K_DTYPE_T;
+ ethdsc1.dsc$b_class = DSC$K_CLASS_S;
+ ethdsc1.dsc$a_pointer = translation.addr;
+ status = SYS$ASSIGN(ðdsc1, ðchan, 0, 0);
+ } else
+ status = SS$_NOSUCHDEV;
+
+ for (eth_index = 0;
+ (SS$_NOSUCHDEV == status) && (SIZEOF(ethdsc) / SIZEOF(struct dsc$descriptor_s) > eth_index);
+ status = SYS$ASSIGN(ðdsc[eth_index++], ðchan, 0, 0));
+ if (0 != (status & 1)) /* if any of the SYS$ASSIGN's succeeded */
+ {
+ logical.addr = logical_buffer;
+ memcpy(logical.addr, DDP_ETH_RCV_BUFCNT_PREFIX, STR_LIT_LEN(DDP_ETH_RCV_BUFCNT_PREFIX));
+ memcpy(&logical.addr[STR_LIT_LEN(DDP_ETH_RCV_BUFCNT_PREFIX)], my_circuit_name.addr, my_circuit_name.len);
+ logical.len = STR_LIT_LEN(DDP_ETH_RCV_BUFCNT_PREFIX) + my_circuit_name.len;
+ if (SS$_NORMAL == trans_log_name(&logical, &translation, translation_buffer) && 0 < translation.len)
+ {
+ eth_recv_bufcnt = asc2i((uchar_ptr_t)translation_buffer, translation.len);
+ if (MIN_ETH_RECV_BUFCNT > eth_recv_bufcnt || MAX_ETH_RECV_BUFCNT < eth_recv_bufcnt)
+ eth_recv_bufcnt = ETH_RCV_BUFCNT;
+ assert(NMA$C_PCLI_BFN == setparm[0].parm_id);
+ setparm[0].parm_val = eth_recv_bufcnt; /* OK to overwrite static since once per run */
+ }
+ status = SYS$QIOW(EFN$C_ENF, ethchan, (IO$_SETMODE | IO$M_CTRL | IO$M_STARTUP), &write_iosb, 0, 0,
+ 0, &setparmdsc, 0, 0, 0, 0);
+ if (0 != (status & 1))
+ status = write_iosb.status;
+ if (0 != (status & 1))
+ {
+ status = SYS$QIOW(EFN$C_ENF, ethchan, (IO$_SENSEMODE | IO$M_CTRL), &write_iosb, 0, 0, 0, &sensedsc,
+ 0, 0, 0, 0);
+ if (0 != (status & 1))
+ status = write_iosb.status;
+ if (0 != (status & 1))
+ {
+ /* Locate the PHA parameter. */
+ status = SS$_NOSUCHDEV; /* default in case we don't find PHA parameter */
+ for (sbp = sensebuf; sbp < sensebuf + SIZEOF(sensebuf);)
+ {
+ if (0 == (*(short *)sbp & 0x1000)) /* if not string parameter, must be longword */
+ sbp += SIZEOF(short) + SIZEOF(int4); /* skip longword parameter */
+ else if (NMA$C_PCLI_PHA != (*(short *)sbp & 0x0fff)) /* compare without flag bits */
+ {
+ sbp += SIZEOF(short); /* skip to string count */
+ sbp += SIZEOF(short) + *(short *)sbp; /* skip over string count and string */
+ } else /* must be NMA$C_PCLI_PHA */
+ {
+ sbp += 2 * SIZEOF(short); /* skip over parameter ID and string count */
+ memcpy(my_ether_addr, sbp, ETHERADDR_LENGTH); /* get ethernet address */
+ sbp += ETHERADDR_LENGTH;
+ status = decddp_start_ast();
+ break;
+ }
+ }
+ logical.addr = logical_buffer;
+ memcpy(logical.addr, DDP_MAXREQCREDITS_PREFIX, STR_LIT_LEN(DDP_MAXREQCREDITS_PREFIX));
+ memcpy(&logical.addr[STR_LIT_LEN(DDP_MAXREQCREDITS_PREFIX)], my_circuit_name.addr,
+ my_circuit_name.len);
+ logical.len = STR_LIT_LEN(DDP_MAXREQCREDITS_PREFIX) + my_circuit_name.len;
+ if (SS$_NORMAL == trans_log_name(&logical, &translation, translation_buffer)
+ && 0 < translation.len)
+ {
+ credits = asc2i((uchar_ptr_t)translation_buffer, translation.len);
+ if (DDP_LEAST_MAXREQCREDITS <= credits && DDP_LARGEST_MAXREQCREDITS >= credits)
+ max_ddp_request_credits = (unsigned char)credits;
+ }
+ }
+ }
+ }
+ return status;
+}
+
+condition_code decddp_start_ast(void)
+{ /* Enable attention AST. */
+ return SYS$QIOW(EFN$C_ENF, ethchan, (IO$_SETMODE | IO$M_ATTNAST), &read_iosb, 0, 0, decddp_ast_handler, 0, 0, 0, 0, 0);
+}
+
+
+void decddp_ast_handler(void)
+{
+ input_pending = TRUE;
+ SYS$WAKE(0, 0);
+ return;
+}
+
+boolean_t dcp_get_input_buffer(struct in_buffer_struct *input_buffer, size_t inbufsiz)
+{
+ bool retval;
+ condition_code status;
+
+ if (FALSE == input_pending)
+ status = 0;
+ else
+ {
+ input_pending = FALSE;
+ status = SYS$QIOW(EFN$C_ENF, ethchan, IO$_READVBLK, &read_iosb, 0, 0, &input_buffer->dh,
+ inbufsiz - offsetof(struct in_buffer_struct, dh), 0, 0, input_buffer->fh.destination_address, 0);
+ input_buffer->fh.frame_length = read_iosb.length;
+ /* At this point, input_buffer should point to:
+ 2 bytes containing the number of bytes read (in_buffer_struct.len)
+ 14 bytes of Ethernet packet header information (in_buffer_struct.fh)
+ data starting at byte 16 (in_buffer_struct.dh followed by ddp message contents)
+ */
+ if (ddp_trace)
+ ddp_trace_output(&input_buffer->dh, input_buffer->fh.frame_length, DDP_RECV);
+ status = decddp_start_ast();
+ }
+ return (0 != (status & 1));
+}
+
+/* decddp_shdr - initialize transmit buffer with DDP packet header */
+void decddp_shdr(unsigned char trancode, short jobno, unsigned short remote_circuit, short return_jobno, unsigned char msgno,
+ unsigned char *etheraddr)
+/* trancode is DDP transaction code */
+/* jobno is job number */
+/* remote_circuit is 5-bit format of remote circuit name. However, a 0001 if this is a multicast announcement. */
+/* return_jobno is for response, job number of client; for request, 0 */
+/* msgno is message number */
+/* etheraddr is pointer to destination ethernet address (6 bytes) */
+{
+ ddp_hdr_t *dp;
+
+ assert(SIZEOF(xmtbuf) - 1 > DDP_MSG_HDRLEN); /* buffer overflow check; - 1 to accommodate terminator byte */
+ dp = (ddp_hdr_t *)xmtbuf;
+ dp->trancode = trancode; /* transaction code */
+ dp->proto = DDP_PROTO_VERSION;
+ dp->source_circuit_name = my_circuit; /* 5-bit format of local circuit name */
+ dp->source_job_number = jobno; /* job number << 1 */
+ dp->remote_circuit_name = remote_circuit; /* 5-bit format of remote circuit name */
+ dp->remote_job_number = return_jobno; /* response: $J; request: 0 */
+ dp->message_number = msgno; /* sequence number; must be in order */
+ dp->filler1 = 0x00; /* literal 00 */
+ /* leave message_length unset; filled later */
+ dp->hdrlen = DDP_MSG_HDRLEN; /* DDP header length */
+
+ xmtbufptr = &xmtbuf[DDP_MSG_HDRLEN]; /* first free position in buffer */
+ memcpy(destination_address, etheraddr, ETHERADDR_LENGTH);
+ return;
+}
+
+void decddp_set_etheraddr(unsigned char *adr)
+{ /* set up Ethernet address */
+ memcpy(destination_address, adr, ETHERADDR_LENGTH);
+ return;
+}
+
+unsigned char *decddp_s5bit(unsigned char *cp)
+{ /* convert 3 bytes to '5-bit format' and store in the transmit buffer; return pointer to next free transmit buffer location */
+ *((unsigned short *)xmtbufptr)++ = five_bit(cp);
+ return xmtbufptr;
+}
+
+unsigned char *decddp_s5asc(unsigned short fivebit)
+{ /* convert 5-bit format number to ASCII and store in the transmit buffer; return pointer to next free transmit buffer location */
+ xmtbufptr = five_2_ascii(&fivebit, xmtbufptr);
+ return xmtbufptr;
+}
+
+unsigned char *decddp_s7bit(unsigned char *cp)
+{ /* convert zero terminated string to '7-bit format' and store in the transmit buffer;
+ return pointer to next free transmit buffer location
+ */
+ unsigned char *mycp;
+
+ if ('\0' != *cp)
+ { /* Copy characters, shifting low-order 7 bits to high-order 7 bits and set low-order bit. */
+ for (mycp = cp; '\0' != *mycp; mycp++)
+ *xmtbufptr++ = ((*mycp << 1) & 0xff) | 0x01;
+ *(xmtbufptr - 1) &= 0xfe; /* clear low order bit of last byte signifying end of string */
+ /* N.B., shortest allowable string is zero bytes with no terminator */
+ }
+ return xmtbufptr;
+}
+
+
+unsigned char *decddp_s8bit(unsigned char *cp)
+{ /* transcribe zero terminated string to the transmit buffer; return pointer to next free transmit buffer location */
+ unsigned char *mycp;
+
+ mycp = cp;
+ do /* just copy the bytes, including terminating zero byte; shortest string is 1 byte (terminator) */
+ *xmtbufptr++ = *mycp++;
+ while ('\0' != *mycp);
+
+ return xmtbufptr;
+}
+
+void decddp_s8bit_counted(char *cp, int len)
+{
+ if (len)
+ memcpy(xmtbufptr, cp, len);
+ xmtbufptr += len;
+ return;
+}
+
+void decddp_putbyte(unsigned char ch) /* note the VAX MACRO version declared this of type (char *), but never set r0! */
+{ /* copy single character to transmit buffer */
+
+ *xmtbufptr++ = ch;
+ return;
+}
+
+condition_code decddp_send(void)
+{ /* transmit message */
+
+ return(dcp_send_message(xmtbuf, (xmtbufptr - xmtbuf), &write_iosb));
+}
+
+condition_code dcp_send_message(unsigned char *buffer, int length, struct iosb_struct *iosbp)
+{
+ int buflen, retry;
+ condition_code status;
+ error_def(ERR_DDPOUTMSG2BIG);
+
+ ((ddp_hdr_t *)buffer)->message_length = buflen = length;
+ if (0 != (buflen & 1))
+ buffer[buflen++] = 0xff; /* pad to even number of bytes with 0xff */
+ if (buflen < DDP_MIN_MSG_LEN)
+ buflen = DDP_MIN_MSG_LEN; /* pad to min len */
+ if (ddp_trace)
+ ddp_trace_output(buffer, buflen, DDP_SEND);
+ if (MAX_ETHER_DATA_SIZE < buflen)
+ return ERR_DDPOUTMSG2BIG;
+ for (retry = 0, status = 0; (0 == (status & 1)) && (RETRY_LIMIT > retry); retry++)
+ {
+ status = SYS$QIOW(EFN$C_ENF, ethchan, IO$_WRITEVBLK, iosbp, 0, 0, buffer, buflen, 0, 0, &destination_address, 0);
+ if (0 != (status & 1))
+ status = iosbp->status;
+ }
+ return status;
+}
+
+void decddp_sinit(unsigned char *response_code)
+{ /* DDP session initialization message (must have called decddp_shdr() first) */
+ ddp_announce_msg_t *ap;
+ int volset_index;
+
+ assert(DDP_ANNOUNCE_MSG_LEN <= SIZEOF(xmtbuf) - (xmtbufptr - xmtbuf)); /* buffer overflow check */
+ ap = (ddp_announce_msg_t *)xmtbufptr; /* xmtbufptr points to the byte past the header */
+
+ ap->filler0 = 0;
+ ap->code[0] = response_code[0];
+ ap->code[1] = response_code[1];
+ memcpy(ap->ether_addr, my_ether_addr, ETHERADDR_LENGTH);
+ ap->circuit_name = my_circuit;
+ ap->filler1 = 0;
+ ap->filler2 = 0;
+ ap->max_job_no = MAX_USERS_PER_NODE;
+ ap->group_mask = my_group_mask;
+ ap->advertise_interval = DDP_ADVERTISE_INTERVAL;
+ ap->max_request_credits = max_ddp_request_credits; /* used for flow control */
+ ap->cpu_type = DDP_CPU_TYPE;
+ ap->version = DDP_SOFTWARE_VERSION;
+ ap->cpu_load_rating = DDP_CPU_LOAD_RATING;
+ ap->proto_version = DDP_PROTO_VERSION;
+ ap->node_status = DDP_NODE_STATUS_ALL_CLEAR;
+ ap->autoconfigure_version = DDP_AUTOCONFIGURE_VERSION;
+ for (volset_index = 0; volset_index < DDP_MAX_VOLSETS; volset_index++) /* copy volset names to the buffer */
+ ap->volset[volset_index] = volset_table[volset_index].vol;
+ /*********************** BEGIN STUFF THAT IS YET TO BE UNDERSTOOD ************************/
+ memset(ap->filler3, 0, SIZEOF(ap->filler3));
+ *((uint4 *)&ap->filler3[32]) = DDP_ANNOUNCE_FILLER3_LITERAL;
+ /*********************** END STUFF THAT IS YET TO BE UNDERSTOOD ************************/
+ ap->terminator = DDP_MSG_TERMINATOR;
+
+ xmtbufptr += DDP_ANNOUNCE_MSG_LEN;
+ return;
+}
+
+unsigned char *decddp_xmtbuf(void)
+{
+ return xmtbuf;
+}
+
+int decddp_bufavail(void)
+{
+ return SIZEOF(xmtbuf) - (xmtbufptr - xmtbuf);
+}
diff --git a/sr_vvms/decddp.h b/sr_vvms/decddp.h
new file mode 100644
index 0000000..e99668f
--- /dev/null
+++ b/sr_vvms/decddp.h
@@ -0,0 +1,44 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2002 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef DECDDP_H_INCLUDED
+#define DECDDP_H_INCLUDED
+
+#define INIT_DESCRIP(X,A) ((X).dsc$a_pointer = (A), (X).dsc$b_dtype = DSC$K_DTYPE_T, (X).dsc$b_class = DSC$K_CLASS_S)
+#define DESCRIP_LENGTH(X,A) ((X).dsc$w_length = (char *)(A) - (X).dsc$a_pointer)
+
+condition_code decddp_init(void);
+condition_code decddp_start_ast(void);
+void decddp_ast_handler(void);
+boolean_t dcp_get_input_buffer(struct in_buffer_struct *input_buffer, size_t inbuflen);
+void decddp_shdr(unsigned char trancode, short jobno, unsigned short remote_circuit, short return_jobno,
+ unsigned char msgno, unsigned char *etheraddr);
+void decddp_set_etheraddr(unsigned char *adr);
+unsigned char *decddp_s5bit(unsigned char *cp);
+unsigned char *decddp_s5asc(unsigned short fivebit);
+unsigned char *decddp_s7bit(unsigned char *cp);
+unsigned char *decddp_s8bit(unsigned char *cp);
+void decddp_putbyte(unsigned char ch);
+condition_code decddp_send(void);
+condition_code dcp_send_message(unsigned char *buffer, int length, struct iosb_struct *iosbp);
+void decddp_sinit(unsigned char *response_code);
+void decddp_log_error(condition_code status, char *message_text, unsigned short *source_circuit,
+ unsigned short *source_job);
+void decddp_s8bit_counted(char *cp, int len);
+char *ddp_db_op(struct in_buffer_struct *bp, condition_code (*f)(), unsigned char *addr, int len);
+char *ddp_lock_op(struct in_buffer_struct *bptr, condition_code (*f)(), int unlock_code);
+condition_code dcp_get_circuit(mval *logical);
+condition_code dcp_get_volsets(void);
+condition_code dcp_get_groups(void);
+condition_code dcp_get_maxrecsize(void);
+unsigned char *decddp_xmtbuf(void);
+
+#endif /* DECDDP_H_INCLUDED */
diff --git a/sr_vvms/decddp_log_error.c b/sr_vvms/decddp_log_error.c
new file mode 100644
index 0000000..8034fdb
--- /dev/null
+++ b/sr_vvms/decddp_log_error.c
@@ -0,0 +1,86 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_time.h"
+
+#include <descrip.h>
+#include <opcdef.h>
+#include <ssdef.h>
+
+#include "ddphdr.h"
+#include "ddpcom.h"
+#include "dcpsubs.h"
+#include "decddp.h"
+#include "five_2_ascii.h"
+#include "util.h"
+
+#define PUTINBUFFER(X) (memcpy(bufptr, (X), SIZEOF(X)), bufptr += SIZEOF(X) - 1)
+#define NEWLINE (*bufptr++ = '\r' , *bufptr++ = '\n')
+#define MAX_MSG_LEN 512
+
+GBLREF bool dec_nofac;
+
+void decddp_log_error(condition_code status, char *message_text, unsigned short *source_circuit, unsigned short *source_job)
+{
+ int4 jobno, index;
+ short res_length;
+ char *bufptr;
+ oper_msg_struct oper;
+ mstr errmsg;
+ $DESCRIPTOR(opmsg, "");
+ error_def(ERR_SYSCALL);
+ error_def(ERR_DDPLOGERR);
+
+ bufptr = oper.text;
+ PUTINBUFFER("GTM.DDP Server Status");
+ if (NULL != source_circuit)
+ {
+ PUTINBUFFER(" Source circuit=");
+ bufptr = five_2_ascii(source_circuit, bufptr);
+ }
+ if (NULL != source_job)
+ {
+ PUTINBUFFER(" Source job=");
+ jobno = *source_job;
+ bufptr += 5;
+ for (index = 1; index <= 5; index++)
+ {
+ *(bufptr - index) = (jobno % 10) + '0';
+ jobno /= 10;
+ }
+ }
+ NEWLINE;
+ if (NULL != message_text)
+ {
+ while (*bufptr++ = *message_text++)
+ ;
+ bufptr--; /* remove the <NUL> terminator */
+ NEWLINE;
+ }
+ if (0 != status)
+ {
+ assert(SIZEOF(oper.text) - MAX_MSG_LEN >= bufptr - oper.text);
+ errmsg.addr = bufptr;
+ errmsg.len = MAX_MSG_LEN;
+ gtm_getmsg(status, &errmsg);
+ bufptr += errmsg.len;
+ }
+ oper.req_code = OPC$_RQ_RQST;
+ oper.target = OPC$M_NM_OPER1;
+ opmsg.dsc$a_pointer = &oper;
+ opmsg.dsc$w_length = SIZEOF(oper) - SIZEOF(oper.text) + (bufptr - oper.text);
+ if (SS$_NORMAL != (status = sys$sndopr(&opmsg, 0))) /* to the operator log */
+ dec_err(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("SYS$SNDOPR"), CALLFROM, status); /* record sndopr error in log */
+ DDP_LOG_ERROR(bufptr - oper.text, oper.text); /* also to the error log */
+ return;
+}
diff --git a/sr_vvms/define-old-library-logicals.com b/sr_vvms/define-old-library-logicals.com
new file mode 100644
index 0000000..8b4e830
--- /dev/null
+++ b/sr_vvms/define-old-library-logicals.com
@@ -0,0 +1,137 @@
+$ set noon
+$! Define old library logicals to support linking against older versions of
+$! VMS.
+$! John Francini 17 Apr 1997
+$! Roger Partridge 15 Dec 1999
+$! Xianguan Li 05 Jan 2000
+$! Sam Weiner 11 Jul 2004
+$!
+$! If on a AXP, call with P1 = "V62" to define for V6.2 libraries.
+$! If on a AXP, call with P1 = "V71" to define for V7.1 libraries.
+$! Default on AXP is V7.2-1.
+$!
+$! If on a VAX, call with P1 = "V55" to define for V5.5-2 libraries.
+$! P1 = "V61 for V6.1 libraries
+$! Default on VAX is V7.1.
+$!
+$! If called with P1 = "CHECK", a display of the current state of the libraries
+$! is given.
+$!
+$! If called with P1 = "REMOVE", then the logicals are deleted.
+$!
+$! These last two options may be abbrieviated to a single letter.
+$!
+$! All logicals are defined in the PROCESS logical name table.
+$ say := write sys$output
+$ myarch = f$getsyi("arch_type")
+$ on_vax := false
+$ on_alpha := false
+$ nosys := false
+$ dpn := define/process/nolog
+$ if myarch .eq. 1
+$ then
+$ on_vax := true
+$ arch_str := "VAX"
+$ endif
+$ if myarch .eq. 2
+$ then
+$ on_alpha := true
+$ arch_str := "Alpha"
+$ node = f$edit(f$getsyi("nodename"),"upcase")
+$ if node .eqs. "YETI" then nosys := true
+$ if node .eqs. "BGFOOT" then nosys := true
+$ endif
+$ if f$extract(0,1,p1) .eqs. "C" then goto check_logicals
+$ if f$extract(0,1,p1) .eqs. "R" then goto undefine_logicals
+$!
+$! Here to define the logicals
+$!
+$ if on_alpha
+$ then
+$ axplib := V721LIB
+$ verstr := V7.2-1
+$ if p1 .eqs. "V62"
+$ then
+$ axplib := V62LIB
+$ verstr := V6.2
+$ endif
+$ if p1 .eqs. "V71"
+$ then
+$ axplib := V71LIB
+$ verstr := V7.1
+$ endif
+$ say "[Defining old library logicals for OpenVMS Alpha ''verstr']"
+$ if nosys
+$ then
+$ dpn alpha$library gtm$root:[alpha$'axplib'.sys$library]
+$ dpn sys$library gtm$root:[alpha$'axplib'.sys$library]
+$ dpn alpha$loadable_images gtm$root:[alpha$'axplib'.sys$ldr]
+$ dpn sys$loadable_images gtm$root:[alpha$'axplib'.sys$ldr]
+$ else
+$ dpn alpha$library disk$launch-box:[alpha$'axplib'.sys$library]
+$ dpn sys$library disk$launch-box:[alpha$'axplib'.sys$library]
+$ dpn alpha$loadable_images disk$launch-box:[alpha$'axplib'.sys$ldr]
+$ dpn sys$loadable_images disk$launch-box:[alpha$'axplib'.sys$ldr]
+$ endif
+$ dpn old_library_logicals 'verstr'
+$ endif
+$ if on_vax
+$ then
+$ vaxlib := V71LIB
+$ verstr := V7.1
+$ if p1 .eqs. "V61"
+$ then
+$ vaxlib := V61LIB
+$ verstr := V6.1
+$ endif
+$ if p1 .eqs. "V55"
+$ then
+$ vaxlib := V55LIB
+$ verstr := V5.5-2
+$ endif
+$ say "[Defining old library logicals for OpenVMS VAX ''verstr']"
+$ dpn sys$library disk$cetus:[vax$'vaxlib'.sys$library]
+$ dpn vax$library disk$cetus:[vax$'vaxlib'.sys$library]
+$ dpn sys$loadable_images disk$cetus:[vax$'vaxlib'.sys$ldr]
+$ dpn vax$loadable_images disk$cetus:[vax$'vaxlib'.sys$ldr]
+$ dpn mthrtl disk$cetus:[vax$'vaxlib'.sys$library]uvmthrtl.exe
+$ dpn uvmthrtl disk$cetus:[vax$'vaxlib'.sys$library]uvmthrtl.exe
+$ dpn librtl2 disk$cetus:[vax$'vaxlib'.sys$library]librtl2.exe
+$ dpn old_library_logicals 'verstr'
+$ endif
+$ exit
+$!
+$! Here to check to see if the logicals are defined...
+$!
+$check_logicals:
+$ verstr = f$trnlnm("OLD_LIBRARY_LOGICALS","LNM$PROCESS")
+$ if verstr .eqs. ""
+$ then
+$ say "[No old library logicals are defined]"
+$ else
+$ say "[Currently using old library logicals for OpenVMS ''arch_str' ''verstr]"
+$ endif
+$ exit
+$!
+$! Here to undefine the old library logicals...
+$!
+$undefine_logicals:
+$ call undefiner sys$library
+$ call undefiner vax$library
+$ call undefiner sys$loadable_images
+$ call undefiner vax$loadable_images
+$ call undefiner mthrtl
+$ call undefiner uvmthrtl
+$ call undefiner librtl2
+$ call undefiner alpha$library
+$ call undefiner alpha$loadable_images
+$ call undefiner old_library_logicals
+$ say "[Old library logicals have been removed from your process table]"
+$ exit
+$!
+$! Subroutine to undefine a logical only if it exists in the PROCESS logical
+$! name table...
+$undefiner: SUBROUTINE
+$ if f$trnlnm(P1,"LNM$PROCESS") .NES. "" THEN DEASSIGN/PROCESS 'P1'
+$ exit
+$ endsubroutine
diff --git a/sr_vvms/del_sec.c b/sr_vvms/del_sec.c
new file mode 100644
index 0000000..4869466
--- /dev/null
+++ b/sr_vvms/del_sec.c
@@ -0,0 +1,37 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <ssdef.h>
+#include <psldef.h>
+#include <secdef.h>
+#include <descrip.h>
+#include <prvdef.h>
+#include "del_sec.h"
+
+int del_sec(uint4 flags,struct dsc$descriptor *gdsnam,char *ident)
+{
+int4 status;
+uint4 prvadr[2], prvprv[2];
+
+prvadr[1] = 0;
+prvadr[0] = PRV$M_SYSGBL | PRV$M_PRMGBL;
+status = sys$setprv(TRUE, &prvadr[0], FALSE, &prvprv[0]);
+if (status == SS$_NORMAL)
+{ status = sys$dgblsc(flags,gdsnam,ident);
+}
+if (~prvprv[0] & (PRV$M_SYSGBL | PRV$M_PRMGBL))
+{ prvprv[0] = ~prvprv[0];
+ prvprv[1] = ~prvprv[1];
+ sys$setprv(FALSE, &prvprv[0], FALSE, 0);
+}
+return status;
+}
diff --git a/sr_vvms/del_sec.h b/sr_vvms/del_sec.h
new file mode 100644
index 0000000..c6297e9
--- /dev/null
+++ b/sr_vvms/del_sec.h
@@ -0,0 +1,17 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef DEL_SEC_INCLUDED
+#define DEL_SEC_INCLUDED
+
+int del_sec(uint4 flags, struct dsc$descriptor *gdsnam, char *ident);
+
+#endif /* DEL_SEC_INCLUDED */
diff --git a/sr_vvms/desblk.h b/sr_vvms/desblk.h
new file mode 100644
index 0000000..b642c9b
--- /dev/null
+++ b/sr_vvms/desblk.h
@@ -0,0 +1,25 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+typedef struct {
+ int4 link;
+ int4 *exit_hand;
+ int4 arg_cnt;
+ int4 *cond_val;
+} desblk;
+
+#define SET_EXIT_HANDLER(exi_blk, exit_handler, exit_condition) \
+{ \
+ exi_blk.exit_hand = &exit_handler; \
+ exi_blk.arg_cnt = 1; \
+ exi_blk.cond_val = &exit_condition; \
+ EXIT_HANDLER(&exi_blk); \
+}
diff --git a/sr_vvms/desc2mval.c b/sr_vvms/desc2mval.c
new file mode 100644
index 0000000..8de9094
--- /dev/null
+++ b/sr_vvms/desc2mval.c
@@ -0,0 +1,162 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "stringpool.h"
+#include <descrip.h>
+#include "desc2mval.h"
+#include "mvalconv.h"
+
+GBLREF spdesc stringpool;
+
+error_def(ERR_ERRCALL);
+error_def(ERR_MAXSTRLEN);
+error_def(ERR_UNSDCLASS);
+error_def(ERR_UNSDDTYPE);
+
+void desc2mval (struct dsc$descriptor *src, mval *v)
+{
+ if ($is_desc64(src))
+ desc2mval_64((struct dsc64$descriptor *)src, v);
+ else
+ desc2mval_32(src, v);
+}
+
+void desc2mval_32(struct dsc$descriptor *src, mval *v)
+{
+ int4 status;
+ struct dsc$descriptor dst;
+ double dstnm;
+
+ switch(src->dsc$b_class)
+ {
+ case DSC$K_CLASS_S: /* scalar or string descriptor */
+ case DSC$K_CLASS_D: /* dynamic descriptor is same as _S for input */
+ v->mvtype = MV_STR;
+ switch(src->dsc$b_dtype)
+ {
+ case DSC$K_DTYPE_G:
+ double2s(src->dsc$a_pointer, v);
+ break;
+ case DSC$K_DTYPE_B:
+ MV_FORCE_MVAL(v, *(char *)src->dsc$a_pointer);
+ break;
+ case DSC$K_DTYPE_BU:
+ MV_FORCE_MVAL(v, *(unsigned char *)src->dsc$a_pointer);
+ break;
+ case DSC$K_DTYPE_W:
+ MV_FORCE_MVAL(v, *(short *)src->dsc$a_pointer);
+ break;
+ case DSC$K_DTYPE_WU:
+ MV_FORCE_MVAL(v, *(unsigned short *)src->dsc$a_pointer);
+ break;
+ case DSC$K_DTYPE_L:
+ MV_FORCE_MVAL(v, *(int4 *)src->dsc$a_pointer);
+ break;
+ case DSC$K_DTYPE_LU:
+ case DSC$K_DTYPE_Q:
+ case DSC$K_DTYPE_QU:
+ case DSC$K_DTYPE_D:
+ case DSC$K_DTYPE_F:
+ case DSC$K_DTYPE_H:
+ dst.dsc$w_length = SIZEOF(double);
+ dst.dsc$b_dtype = DSC$K_DTYPE_G;
+ dst.dsc$b_class = DSC$K_CLASS_S;
+ dst.dsc$a_pointer = &dstnm;
+ status = lib$cvt_dx_dx(src, &dst);
+ if (!(status & 1))
+ rts_error(VARLSTCNT(1) status);
+ double2s(&dstnm, v);
+ break;
+ case DSC$K_DTYPE_T:
+ ENSURE_STP_FREE_SPACE(src->dsc$w_length);
+ assert(stringpool.free >= stringpool.base);
+ v->str.addr = stringpool.free;
+ stringpool.free += v->str.len = src->dsc$w_length;
+ assert(stringpool.free <= stringpool.top);
+ memcpy(v->str.addr, src->dsc$a_pointer, v->str.len);
+ break;
+ default:
+ rts_error(VARLSTCNT(1) ERR_UNSDDTYPE);
+ }
+ break;
+ default:
+ rts_error(VARLSTCNT(7) ERR_UNSDCLASS, 5, ERR_ERRCALL, 3, CALLFROM);
+ }
+}
+
+void desc2mval_64 (struct dsc64$descriptor *src, mval *v)
+{
+ int4 status;
+ struct dsc64$descriptor dst;
+ double dstnm;
+
+ switch(src->dsc64$b_class)
+ {
+ case DSC64$K_CLASS_S: /* scalar or string descriptor */
+ case DSC64$K_CLASS_D: /* dynamic descriptor is same as _S for input */
+ v->mvtype = MV_STR;
+ switch(src->dsc64$b_dtype)
+ {
+ case DSC64$K_DTYPE_G:
+ double2s((double *)src->dsc64$pq_pointer, v);
+ break;
+ case DSC64$K_DTYPE_B:
+ MV_FORCE_MVAL(v, *(char *)src->dsc64$pq_pointer);
+ break;
+ case DSC64$K_DTYPE_BU:
+ MV_FORCE_MVAL(v, *(unsigned char *)src->dsc64$pq_pointer);
+ break;
+ case DSC64$K_DTYPE_W:
+ MV_FORCE_MVAL(v, *(short *)src->dsc64$pq_pointer);
+ break;
+ case DSC64$K_DTYPE_WU:
+ MV_FORCE_MVAL(v, *(unsigned short *)src->dsc64$pq_pointer);
+ break;
+ case DSC64$K_DTYPE_L:
+ MV_FORCE_MVAL(v, *(int4 *)src->dsc64$pq_pointer);
+ break;
+ case DSC64$K_DTYPE_LU:
+ case DSC64$K_DTYPE_Q:
+ case DSC64$K_DTYPE_QU:
+ case DSC64$K_DTYPE_FS:
+ case DSC64$K_DTYPE_F:
+ case DSC64$K_DTYPE_D:
+ case DSC64$K_DTYPE_H:
+ dst.dsc64$w_mbo = 1;
+ dst.dsc64$l_mbmo = -1;
+ dst.dsc64$q_length = SIZEOF(double);
+ dst.dsc64$b_dtype = DSC64$K_DTYPE_G;
+ dst.dsc64$b_class = DSC64$K_CLASS_S;
+ dst.dsc64$pq_pointer = (char *)&dstnm;
+ status = lib$cvt_dx_dx(src, &dst);
+ if (!(status & 1))
+ rts_error(VARLSTCNT(1) status);
+ double2s(&dstnm, v);
+ break;
+ case DSC64$K_DTYPE_T:
+ if(MAX_STRLEN < src->dsc64$q_length)
+ rts_error(VARLSTCNT(1) ERR_MAXSTRLEN);
+ ENSURE_STP_FREE_SPACE(src->dsc64$q_length);
+ assert(stringpool.free >= stringpool.base);
+ v->str.addr = stringpool.free;
+ stringpool.free += v->str.len = src->dsc64$q_length;
+ assert(stringpool.free <= stringpool.top);
+ memcpy(v->str.addr, src->dsc64$pq_pointer, v->str.len);
+ break;
+ default:
+ rts_error(VARLSTCNT(1) ERR_UNSDDTYPE);
+ }
+ break;
+ default:
+ rts_error(VARLSTCNT(7) ERR_UNSDCLASS, 5, ERR_ERRCALL, 3, CALLFROM);
+ }
+}
diff --git a/sr_vvms/desc2mval.h b/sr_vvms/desc2mval.h
new file mode 100644
index 0000000..26b377c
--- /dev/null
+++ b/sr_vvms/desc2mval.h
@@ -0,0 +1,19 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2004 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef DESC2MVAL_INCLUDED
+#define DESC2MVAL_INCLUDED
+
+void desc2mval(struct dsc$descriptor *src, mval *v);
+void desc2mval_32(struct dsc$descriptor *src, mval *v);
+void desc2mval_64(struct dsc64$descriptor *src, mval *v);
+
+#endif /* DESC2MVAL_INCLUDED */
diff --git a/sr_vvms/dfntmpmbx.c b/sr_vvms/dfntmpmbx.c
new file mode 100644
index 0000000..62dc5ec
--- /dev/null
+++ b/sr_vvms/dfntmpmbx.c
@@ -0,0 +1,39 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <descrip.h>
+#include <lnmdef.h>
+#include "vmsdtype.h"
+
+int4 dfntmpmbx (len, addr)
+short len;
+char *addr;
+{
+ int4 status;
+ int4 ret;
+ $DESCRIPTOR (proc_dir, "LNM$PROCESS_DIRECTORY");
+ $DESCRIPTOR (lnm$tmpmbx, "LNM$TEMPORARY_MAILBOX");
+ struct
+ {
+ item_list_3 le[1];
+ int4 terminator;
+ } item_list;
+
+ item_list.le[0].buffer_length = len;
+ item_list.le[0].item_code = LNM$_STRING;
+ item_list.le[0].buffer_address = addr;
+ item_list.le[0].return_length_address = &ret;
+ item_list.terminator = 0;
+
+ status = sys$crelnm (0, &proc_dir, &lnm$tmpmbx, 0, &item_list);
+ return status;
+}
diff --git a/sr_vvms/dfntmpmbx.h b/sr_vvms/dfntmpmbx.h
new file mode 100644
index 0000000..c693e75
--- /dev/null
+++ b/sr_vvms/dfntmpmbx.h
@@ -0,0 +1,17 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef DFNTMPMBX_INCLUDED
+#define DFNTMPMBX_INCLUDED
+
+int4 dfntmpmbx(short len, char *addr);
+
+#endif /* DFNTMPMBX_INCLUDED */
diff --git a/sr_vvms/disable_ctrl.c b/sr_vvms/disable_ctrl.c
new file mode 100644
index 0000000..aeebeec
--- /dev/null
+++ b/sr_vvms/disable_ctrl.c
@@ -0,0 +1,20 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+void disable_ctrl(mask_addr, ctrl_mask)
+ uint4 *mask_addr;
+ int4 *ctrl_mask;
+
+ {
+ lib$disable_ctrl(mask_addr, ctrl_mask);
+ }
diff --git a/sr_vvms/disk_block_available.c b/sr_vvms/disk_block_available.c
new file mode 100644
index 0000000..8fbf916
--- /dev/null
+++ b/sr_vvms/disk_block_available.c
@@ -0,0 +1,55 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* disk_block_available(int fd, uint4 *free_blocks)
+ * parameter:
+ * fd: file descriptor of the file that is located
+ * on the disk being examined
+ * free_blocks:
+ * address to an uint4 where the number of
+ * free blocks will be returned to
+ * return:
+ * the status of the system service sys$getdviw()
+ * if status is normal, then free_blocks is the correct value
+ * otherwise, free_blocks is undetermined
+ */
+#include "mdef.h"
+
+#include <dvidef.h>
+#include <ssdef.h>
+#include <efndef.h>
+
+
+#include "vmsdtype.h"
+#include "disk_block_available.h"
+
+int4 disk_block_available(int fd, uint4 *free_blocks)
+{
+ unsigned short retlen;
+ struct
+ {
+ item_list_3 item;
+ int4 terminator;
+ } item_list;
+ short iosb[4];
+ int4 status;
+
+ item_list.item.buffer_length = 4;
+ item_list.item.item_code = DVI$_FREEBLOCKS;
+ item_list.item.buffer_address = free_blocks;
+ item_list.item.return_length_address = &retlen;
+ item_list.terminator = 0;
+ status = sys$getdviw(EFN$C_ENF, fd, NULL, &item_list, iosb, NULL, 0, 0);
+ if (SS$_NORMAL == status)
+ status = iosb[0];
+
+ return status;
+}
diff --git a/sr_vvms/disk_block_available.h b/sr_vvms/disk_block_available.h
new file mode 100644
index 0000000..366a114
--- /dev/null
+++ b/sr_vvms/disk_block_available.h
@@ -0,0 +1,17 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef DISK_BLOCK_AVAILABLE_INCLUDED
+#define DISK_BLOCK_AVAILABLE_INCLUDED
+
+int4 disk_block_available(int fd, uint4 *free_blocks);
+
+#endif /* DISK_BLOCK_AVAILABLE_INCLUDED */
diff --git a/sr_vvms/dm_read.c b/sr_vvms/dm_read.c
new file mode 100644
index 0000000..63e243f
--- /dev/null
+++ b/sr_vvms/dm_read.c
@@ -0,0 +1,263 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <iodef.h>
+#include <ssdef.h>
+#include <trmdef.h>
+#include <ttdef.h>
+#include <tt2def.h>
+#include <efndef.h>
+
+
+#include "comline.h"
+#include "io.h"
+#include "iotimer.h"
+#include "iottdef.h"
+#include "stringpool.h"
+#include "op.h"
+#include "outofband.h"
+#include "m_recall.h"
+#include "dm_read.h"
+
+GBLDEF int comline_index;
+
+GBLREF mstr *comline_base;
+GBLREF io_pair io_curr_device;
+GBLREF io_pair io_std_device;
+GBLREF bool prin_in_dev_failure;
+GBLREF int4 outofband;
+GBLREF bool ctrlu_occurred;
+GBLREF spdesc stringpool;
+GBLREF io_desc *active_device;
+
+#define CCPROMPT 0x00010000
+#define CCRECALL 0x008D0000
+
+void dm_read(mval *v)
+{
+ boolean_t done;
+ unsigned short iosb[4];
+ int cl, index;
+ uint4 max_width, save_modifiers, save_term_msk, status;
+ read_iosb stat_blk;
+ io_desc *io_ptr;
+ t_cap s_mode;
+ d_tt_struct *tt_ptr;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ if (tt == io_curr_device.out->type)
+ iott_flush(io_curr_device.out);
+ if (!comline_base)
+ {
+ comline_base = malloc(MAX_RECALL * SIZEOF(mstr));
+ memset(comline_base, 0, (MAX_RECALL * SIZEOF(mstr)));
+ }
+ io_ptr = io_curr_device.in;
+ assert(tt == io_ptr->type);
+ assert(dev_open == io_ptr->state);
+ if (io_ptr->dollar.zeof)
+ op_halt();
+ if (outofband)
+ {
+ outofband_action(FALSE);
+ assert(FALSE);
+ }
+ tt_ptr = (d_tt_struct *)io_ptr->dev_sp;
+ max_width = (io_ptr->width > tt_ptr->in_buf_sz) ? io_ptr->width : tt_ptr->in_buf_sz;
+ assert(stringpool.free >= stringpool.base);
+ assert(stringpool.free <= stringpool.top);
+ ENSURE_STP_FREE_SPACE(max_width);
+ active_device = io_ptr;
+ index = 0;
+ /* the following section of code puts the terminal in "easy of use" mode */
+ status = sys$qiow(EFN$C_ENF, tt_ptr->channel, IO$_SENSEMODE,
+ &stat_blk, 0, 0, &s_mode, 12, 0, 0, 0, 0);
+ if (SS$_NORMAL == status)
+ status = stat_blk.status;
+ if (SS$_NORMAL != status)
+ rts_error(VARLSTCNT(1) status);
+ if ((s_mode.ext_cap & TT2$M_PASTHRU) ||
+ !(s_mode.ext_cap & TT2$M_EDITING) ||
+ !(s_mode.term_char & TT$M_ESCAPE) ||
+ !(s_mode.term_char & TT$M_TTSYNC))
+ {
+ s_mode.ext_cap &= (~TT2$M_PASTHRU);
+ s_mode.ext_cap |= TT2$M_EDITING;
+ s_mode.term_char |= (TT$M_ESCAPE | TT$M_TTSYNC);
+ status = sys$qiow(EFN$C_ENF, tt_ptr->channel,
+ IO$_SETMODE, &stat_blk, 0, 0, &s_mode, 12, 0, 0, 0, 0);
+ if (SS$_NORMAL == status)
+ status = stat_blk.status;
+ if (SS$_NORMAL != status)
+ /* The following error is probably going to cause the terminal state to get mucked up */
+ rts_error(VARLSTCNT(1) status);
+ /* the following flag is normally used by iott_rdone, iott_readfl and iott_use but dm_read resets it when done */
+ tt_ptr->term_chars_twisted = TRUE;
+ }
+ save_modifiers = (unsigned)tt_ptr->item_list[0].addr;
+ tt_ptr->item_list[0].addr = (unsigned)tt_ptr->item_list[0].addr | TRM$M_TM_NORECALL & (~TRM$M_TM_NOECHO);
+ tt_ptr->item_list[1].addr = NO_M_TIMEOUT; /* reset key click timeout */
+ save_term_msk = ((io_termmask *)tt_ptr->item_list[2].addr)->mask[0];
+ ((io_termmask *)tt_ptr->item_list[2].addr)->mask[0] = TERM_MSK | (SHFT_MSK << CTRL_B) | (SHFT_MSK << CTRL_Z);
+ tt_ptr->item_list[4].buf_len = (TREF(gtmprompt)).len;
+ do
+ {
+ done = TRUE;
+ assert(0 <= index && index <= MAX_RECALL + 1);
+ cl = clmod(comline_index - index);
+ if ((0 == index) || (MAX_RECALL + 1 == index))
+ tt_ptr->item_list[5].buf_len = 0;
+ else
+ {
+ tt_ptr->item_list[5].buf_len = comline_base[cl].len;
+ tt_ptr->item_list[5].addr = comline_base[cl].addr;
+ }
+ status = sys$qiow(EFN$C_ENF, tt_ptr->channel, tt_ptr->read_mask, &stat_blk, 0, 0,
+ stringpool.free, tt_ptr->in_buf_sz, 0, 0, tt_ptr->item_list, 6 * SIZEOF(item_list_struct));
+ if (outofband)
+ break;
+ if (SS$_NORMAL != status)
+ {
+ if (io_curr_device.in == io_std_device.in && io_curr_device.out == io_std_device.out)
+ {
+ if (prin_in_dev_failure)
+ sys$exit(status);
+ else
+ prin_in_dev_failure = TRUE;
+ }
+ break;
+ }
+ if (stat_blk.term_length > ESC_LEN - 1)
+ {
+ stat_blk.term_length = ESC_LEN - 1;
+ if (SS$_NORMAL == stat_blk.status)
+ stat_blk.status = SS$_PARTESCAPE;
+ }
+ if (SS$_NORMAL != stat_blk.status)
+ {
+ if (ctrlu_occurred)
+ {
+ index = 0;
+ done = FALSE;
+ ctrlu_occurred = FALSE;
+ iott_wtctrlu(stat_blk.char_ct + (TREF(gtmprompt)).len, io_ptr);
+ } else
+ {
+ status = stat_blk.status;
+ break;
+ }
+ } else
+ {
+ if ((CTRL_B == stat_blk.term_char) ||
+ (stat_blk.term_length == tt_ptr->key_up_arrow.len &&
+ !memcmp(tt_ptr->key_up_arrow.addr, stringpool.free + stat_blk.char_ct,
+ tt_ptr->key_up_arrow.len)))
+ {
+ done = FALSE;
+ if ((MAX_RECALL + 1 != index) && (comline_base[cl].len || !index))
+ index++;
+ } else
+ {
+ if (stat_blk.term_length == tt_ptr->key_down_arrow.len &&
+ !memcmp(tt_ptr->key_down_arrow.addr, stringpool.free + stat_blk.char_ct,
+ tt_ptr->key_down_arrow.len))
+ {
+ done = FALSE;
+ if (index)
+ --index;
+ }
+ }
+ if (!done)
+ {
+ status = sys$qiow(EFN$C_ENF, tt_ptr->channel,
+ IO$_WRITEVBLK, &iosb, NULL, 0,
+ tt_ptr->erase_to_end_line.addr, tt_ptr->erase_to_end_line.len,
+ 0, CCRECALL, 0, 0);
+ } else
+ {
+ if (stat_blk.char_ct > 0
+ && (('R' == *stringpool.free) || ('r' == *stringpool.free)) &&
+ (TRUE == m_recall(stat_blk.char_ct, stringpool.free, &index, tt_ptr->channel)))
+ {
+ assert(-1 <= index && index <= MAX_RECALL);
+ done = FALSE;
+ flush_pio();
+ status = sys$qiow(EFN$C_ENF, tt_ptr->channel,
+ IO$_WRITEVBLK, &iosb, NULL, 0,
+ 0, 0, 0, CCPROMPT, 0, 0);
+ if ((-1 == index) || (CTRL_Z == stat_blk.term_char))
+ index = 0;
+ }
+ }
+ if (!done)
+ {
+ if (SS$_NORMAL == status)
+ status = iosb[0];
+ if (SS$_NORMAL != status)
+ break;
+ } else
+ {
+ if (CTRL_Z == stat_blk.term_char)
+ io_curr_device.in->dollar.zeof = TRUE;
+ }
+ }
+ } while (!done);
+ /* put the terminal back the way the user had it set up */
+ tt_ptr->item_list[0].addr = save_modifiers;
+ ((io_termmask *)tt_ptr->item_list[2].addr)->mask[0] = save_term_msk;
+ if (tt_ptr->term_chars_twisted)
+ {
+ s_mode.ext_cap &= (~TT2$M_PASTHRU & ~TT2$M_EDITING);
+ s_mode.ext_cap |= (tt_ptr->ext_cap & (TT2$M_PASTHRU | TT2$M_EDITING));
+ s_mode.term_char &= (~TT$M_ESCAPE);
+ s_mode.term_char |= (tt_ptr->term_char & TT$M_ESCAPE);
+ status = sys$qiow(EFN$C_ENF, tt_ptr->channel,
+ IO$_SETMODE, iosb, 0, 0, &s_mode, 12, 0, 0, 0, 0);
+ if (SS$_NORMAL == status)
+ status = iosb[0];
+ tt_ptr->term_chars_twisted = FALSE;
+ }
+ if (SS$_NORMAL != status)
+ rts_error(VARLSTCNT(1) status);
+ if (outofband)
+ {
+ /* outofband not going to help more than a error so it's checked 2nd */
+ outofband_action(FALSE);
+ assert(FALSE);
+ }
+ v->mvtype = MV_STR;
+ v->str.len = stat_blk.char_ct;
+ v->str.addr = stringpool.free;
+ if (stat_blk.char_ct)
+ {
+ cl = clmod(comline_index - 1);
+ if (stat_blk.char_ct != comline_base[cl].len || memcmp(comline_base[cl].addr, stringpool.free, stat_blk.char_ct))
+ {
+ comline_base[comline_index] = v->str;
+ comline_index = clmod(comline_index + 1);
+ }
+ stringpool.free += stat_blk.char_ct;
+ }
+ assert(stringpool.free <= stringpool.top);
+ if ((io_ptr->dollar.x += stat_blk.char_ct) > io_ptr->width && io_ptr->wrap)
+ {
+ /* dm_read doesn't maintain the other io status isv's,
+ but it does $x and $y so the user can find out where they wound up */
+ io_ptr->dollar.y += io_ptr->dollar.x / io_ptr->width;
+ if (io_ptr->length)
+ io_ptr->dollar.y %= io_ptr->length;
+ io_ptr->dollar.x %= io_ptr->width;
+ }
+ active_device = 0;
+}
diff --git a/sr_vvms/do_verify.c b/sr_vvms/do_verify.c
new file mode 100644
index 0000000..0aa33e9
--- /dev/null
+++ b/sr_vvms/do_verify.c
@@ -0,0 +1,24 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* do_verify.c VMS - call user-supplied collation type and version
+ * verification routine.
+ */
+
+#include "mdef.h"
+#include "collseq.h"
+
+int4 do_verify(csp, type, ver)
+ collseq *csp;
+ unsigned char type, ver;
+{
+ return (*csp->verify)(type,ver);
+}
diff --git a/sr_vvms/do_xform.c b/sr_vvms/do_xform.c
new file mode 100644
index 0000000..ac45b7b
--- /dev/null
+++ b/sr_vvms/do_xform.c
@@ -0,0 +1,80 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <descrip.h>
+
+#include "collseq.h"
+#include "do_xform.h"
+
+#define MAX_INPUT_LEN 65535
+
+void do_xform(collseq *csp, int fc_type, mstr *input, mstr *output, int *length)
+{
+ struct dsc64$descriptor outbuff1, insub1;
+ struct dsc$descriptor outbuff, insub;
+ int4 status;
+
+ error_def(ERR_COLLARGLONG);
+
+ DO_XFORM_RETURN_IF_NULL_STRING(input, output, length);
+ assert (0 == csp->argtype || 1 == csp->argtype);
+ assert(XFORM == fc_type || XBACK == fc_type);
+ if (0 == csp->argtype)
+ {
+ if (MAX_INPUT_LEN < input->len)
+ rts_error(VARLSTCNT(3) ERR_COLLARGLONG, 1, csp->act);
+ insub.dsc$b_dtype = DSC$K_DTYPE_T;
+ insub.dsc$b_class = DSC$K_CLASS_S;
+ insub.dsc$w_length = input->len;
+ insub.dsc$a_pointer = input->addr;
+
+ outbuff.dsc$b_dtype = DSC$K_DTYPE_T;
+ outbuff.dsc$b_class = DSC$K_CLASS_S;
+ outbuff.dsc$w_length = output->len;
+ outbuff.dsc$a_pointer = output->addr;
+
+ if (XFORM == fc_type)
+ status = (csp->xform)(&insub, 1, &outbuff, length);
+ else
+ status = (csp->xback)(&insub, 1, &outbuff, length);
+ /* If collation routine has changed outbuff1.val, it stores the transformed value in the
+ * externally allocated buffer. In this case, update output->addr before returning. */
+ if (outbuff.dsc$a_pointer != output->addr)
+ output->addr = outbuff.dsc$a_pointer;
+ } else
+ {
+ insub1.dsc64$b_dtype = DSC64$K_DTYPE_T;
+ insub1.dsc64$b_class = DSC64$K_CLASS_S;
+ insub1.dsc64$q_length = input->len;
+ insub1.dsc64$pq_pointer = input->addr;
+
+ outbuff1.dsc64$b_dtype = DSC64$K_DTYPE_T;
+ outbuff1.dsc64$b_class = DSC64$K_CLASS_S;
+ outbuff1.dsc64$q_length = output->len;
+ outbuff1.dsc64$pq_pointer = output->addr;
+
+ if (XFORM == fc_type)
+ status = (csp->xform)(&insub1, 1, &outbuff1, length);
+ else
+ status = (csp->xback)(&insub1, 1, &outbuff1, length);
+ /* If collation routine has changed outbuff1.val, it stores the transformed value in the
+ * externally allocated buffer. In this case, update output->addr before returning. */
+ if (outbuff1.dsc64$pq_pointer != output->addr)
+ {
+ output->addr = (char*)(outbuff1.dsc64$pq_pointer);
+ assert(output->addr == outbuff1.dsc64$pq_pointer); /* ensure 32-bit address */
+ }
+ }
+ if (!(status & 1))
+ rts_error(VARLSTCNT(1) status);
+}
diff --git a/sr_vvms/do_zcall.c b/sr_vvms/do_zcall.c
new file mode 100644
index 0000000..5463476
--- /dev/null
+++ b/sr_vvms/do_zcall.c
@@ -0,0 +1,567 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <ssdef.h>
+#include <descrip.h>
+#include <inttypes.h>
+#include <libdef.h>
+#include "stringpool.h"
+#include "zcall.h"
+#include "zcdef.h"
+#include "io.h"
+#include "mval2desc.h"
+#include "desc2mval.h"
+#include "setterm.h"
+#include "gtmdbglvl.h" /* for VERIFY_STORAGE_CHAINS macro */
+#include "gtm_malloc.h" /* for VERIFY_STORAGE_CHAINS macro */
+
+typedef struct lclarg_type
+{
+ unsigned char skip;
+ unsigned char initted;
+ unsigned char filler[2];
+ unsigned char *zctab;
+ struct dsc64$descriptor dsc;
+ unsigned char data[16];
+} lclarg;
+
+#define VAL_NONE 0
+#define VAL_INPUTMVAL 1
+#define VAL_ZCTABVAL 2
+#define N_DSIZES 32
+/* memset(dsizes, 0, N_DSIZES * SIZEOF(dsizes[0]));
+ dsizes[ZC$DTYPE_STRING] = -1;
+ dsizes[ZC$DTYPE_BYTE] = 1;
+ dsizes[ZC$DTYPE_WORD] = 2;
+ dsizes[ZC$DTYPE_LONG] = 4;
+ dsizes[ZC$DTYPE_QUAD] = 8;
+ dsizes[ZC$DTYPE_FLOATING] = 4;
+ dsizes[ZC$DTYPE_DOUBLE] = 8;
+ dsizes[ZC$DTYPE_G_FLOATING] = 8;
+ dsizes[ZC$DTYPE_H_FLOATING] = 16;
+*/
+#define INIT_64BITDESC \
+{ \
+ is_a_desc64 = TRUE; \
+ dsc64 = &lclp->dsc; \
+ dsc64->dsc64$w_mbo = 1; \
+ dsc64->dsc64$l_mbmo = -1; \
+ type = &dsc64->dsc64$b_dtype; \
+ class = &dsc64->dsc64$b_class; \
+}
+
+#define INIT_32BITDESC \
+{ \
+ is_a_desc64 = FALSE; \
+ dsc = (struct dsc$descriptor *)&lclp->dsc; \
+ type = &dsc->dsc$b_dtype; \
+ class = &dsc->dsc$b_class; \
+}
+
+static readonly short dsizes[N_DSIZES] = {
+ 0, 0, 1, 2, 4, 0, 1, 2, 4, 8, 4, 8,
+ 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 8, 16, 0, 0, 0
+};
+
+GBLREF spdesc stringpool;
+GBLREF io_pair io_std_device;
+
+error_def(ERR_MAXSTRLEN);
+error_def(ERR_VMSMEMORY2);
+error_def(ERR_ZCALLTABLE);
+error_def(ERR_ZCCONMSMTCH);
+error_def(ERR_ZCCONVERT);
+error_def(ERR_ZCINPUTREQ);
+error_def(ERR_ZCOPT0);
+error_def(ERR_ZCPOSOVR);
+error_def(ERR_ZCUNKMECH);
+error_def(ERR_ZCUNKQUAL);
+error_def(ERR_ZCUNKTYPE);
+error_def(ERR_ZCWRONGDESC);
+
+void do_zcall(mval *dst,
+ int mask,
+ mval **mvallist, mval **mvallistend,
+ zctabrtn *zcrtn,
+ lclarg *lcllist, lclarg *lcllistend)
+{
+ zctabret *zcret;
+ zctabinput *firstin;
+ zctaboutput *firstout, *lastout;
+ int4 status, alloclen;
+ zctabinput *inp;
+ zctaboutput *outp;
+ mval **mvpp;
+ lclarg *lclp;
+ struct dsc64$descriptor *dsc64;
+ struct dsc$descriptor *dsc, *valdsc;
+ unsigned char *type;
+ unsigned char *class;
+ boolean_t is_a_desc64;
+ unsigned char use_value;
+ union
+ {
+ double f0;
+ int r0;
+ } save_ret;
+ uint4 dstlen, indx, byref;
+ struct dsc$descriptor tmpdsc;
+ mval tmpmval;
+ uint64_t val_qw;
+ unsigned short val_us;
+
+ zcret = (zctabret *)((char *)zcrtn + SIZEOF(zctabrtn) - 1 + zcrtn->callnamelen);
+ firstin = (zctabinput *)ROUND_UP((int) zcret + SIZEOF(zctabret), SIZEOF(int4));
+ firstout = firstin + zcrtn->n_inputs;
+ lastout = firstout + zcrtn->n_outputs;
+ for (lclp = lcllist; lclp < lcllistend; lclp++)
+ lclp->initted = FALSE;
+ is_a_desc64 = FALSE;
+ for (inp = firstin, mvpp = mvallist; inp < (zctabinput *)firstout; inp++)
+ {
+ switch (inp->type) /* guard type */
+ {
+ case ZC$DTYPE_STRING:
+ case ZC$DTYPE_BYTE:
+ case ZC$DTYPE_BYTEU:
+ case ZC$DTYPE_WORD:
+ case ZC$DTYPE_WORDU:
+ case ZC$DTYPE_LONG:
+ case ZC$DTYPE_LONGU:
+ case ZC$DTYPE_QUAD:
+ case ZC$DTYPE_FLOATING:
+ case ZC$DTYPE_DOUBLE:
+ case ZC$DTYPE_H_FLOATING:
+ break;
+ default:
+ rts_error(VARLSTCNT(1) ERR_ZCUNKTYPE);
+ }
+ switch (inp->mechanism) /* guard mechanism */
+ {
+ case ZC$MECH_VALUE:
+ case ZC$MECH_REFERENCE:
+ case ZC$MECH_DESCRIPTOR:
+ case ZC$MECH_DESCRIPTOR64:
+ break;
+ default:
+ rts_error(VARLSTCNT(1) ERR_ZCUNKMECH);
+ }
+ assertpro(mvpp <= mvallistend);
+ lclp = lcllist + inp->position - 1;
+ if (lclp->initted)
+ rts_error(VARLSTCNT(5) ERR_ZCALLTABLE, 0, ERR_ZCPOSOVR, 1, inp->position);
+ lclp->skip = FALSE;
+ lclp->zctab = inp;
+ if (ZC$MECH_DESCRIPTOR64 == inp->mechanism)
+ {
+ INIT_64BITDESC;
+ } else
+ {
+ INIT_32BITDESC;
+ }
+ use_value = VAL_NONE;
+ switch (inp->qualifier)
+ {
+ case ZC$IQUAL_CONSTANT:
+ use_value = VAL_ZCTABVAL;
+ break;
+ case ZC$IQUAL_OPTIONAL:
+ if (mvpp == mvallistend)
+ lclp->skip = TRUE;
+ else if (!MV_DEFINED(*mvpp) && (*mvpp)->str.addr == (*mvpp))
+ {
+ lclp->skip = TRUE;
+ mvpp++;
+ } else
+ use_value = VAL_INPUTMVAL;
+ break;
+ case ZC$IQUAL_OPTIONAL_0:
+ if (mvpp == mvallistend || (!MV_DEFINED(*mvpp) && (*mvpp)->str.addr == (*mvpp)))
+ {
+ if (!(ZC$MECH_REFERENCE == inp->mechanism ||
+ ZC$MECH_DESCRIPTOR == inp->mechanism || ZC$MECH_DESCRIPTOR64 == inp->mechanism))
+ rts_error(VARLSTCNT(3) ERR_ZCALLTABLE, 0, ERR_ZCOPT0);
+ lclp->skip = TRUE;
+ if (is_a_desc64)
+ dsc64->dsc64$pq_pointer = 0;
+ else
+ dsc->dsc$a_pointer = 0;
+ if (mvpp < mvallistend)
+ mvpp++;
+ } else
+ use_value = VAL_INPUTMVAL;
+ break;
+ case ZC$IQUAL_DEFAULT:
+ if (mvpp == mvallistend)
+ use_value = VAL_ZCTABVAL;
+ else if (!MV_DEFINED(*mvpp) && (*mvpp)->str.addr == (*mvpp))
+ {
+ use_value = VAL_ZCTABVAL;
+ mvpp++;
+ } else
+ use_value = VAL_INPUTMVAL;
+ break;
+ case ZC$IQUAL_REQUIRED:
+ if (mvpp == mvallistend || (!MV_DEFINED(*mvpp) && (*mvpp)->str.addr == (*mvpp)))
+ rts_error(VARLSTCNT(1) ERR_ZCINPUTREQ);
+ use_value = VAL_INPUTMVAL;
+ break;
+ default:
+ rts_error(VARLSTCNT(3) ERR_ZCALLTABLE, 0, ERR_ZCUNKQUAL);
+ }
+ switch (use_value)
+ {
+ case VAL_INPUTMVAL:
+ if (!is_a_desc64)
+ dsc->dsc$w_length = 0;
+ else
+ dsc64->dsc64$q_length = 0;
+ *class = DSC$K_CLASS_S;
+ *type = inp->type;
+ if (ZC$DTYPE_STRING == inp->type)
+ {
+ MV_FORCE_STR(*mvpp);
+ if (!is_a_desc64)
+ {
+ if (65535 < (*mvpp)->str.len)
+ rts_error(VARLSTCNT(1) ERR_ZCWRONGDESC);
+ dsc->dsc$w_length =(*mvpp)->str.len ;
+ dsc->dsc$a_pointer = (*mvpp)->str.addr;
+ } else
+ {
+ dsc64->dsc64$q_length = (*mvpp)->str.len;
+ dsc64->dsc64$pq_pointer = (*mvpp)->str.addr;
+ }
+ } else
+ {
+ if (!is_a_desc64)
+ {
+ dsc->dsc$w_length = dsizes[inp->type];
+ dsc->dsc$a_pointer = &lclp->data;
+ } else
+ {
+ dsc64->dsc64$q_length = dsizes[inp->type];
+ dsc64->dsc64$pq_pointer = (char *)&lclp->data;
+ }
+ assert(is_a_desc64 ? dsc64->dsc64$q_length : dsc->dsc$w_length);
+ mval2desc(*mvpp, &lclp->dsc);
+ }
+ mvpp++;
+ break;
+ case VAL_ZCTABVAL:
+ if (ZC$DTYPE_STRING == inp->type)
+ {
+ /*
+ for this case inp->value cannot be a 64-bit descriptor, inp->value is the descriptor
+ created by putval macro in gtmzcall.max. putval creates a descriptor for each input
+ string value by using the directive .ascid. So for descriptor64, we only copy the
+ 32-bit contents to dsc64.
+ */
+ if (is_a_desc64)
+ {
+ valdsc = (struct dsc$descriptor *)inp->value;
+ dsc64->dsc64$w_mbo = 1;
+ dsc64->dsc64$b_dtype = valdsc->dsc$b_dtype;
+ dsc64->dsc64$b_class = valdsc->dsc$b_class;
+ dsc64->dsc64$l_mbmo = -1;
+ dsc64->dsc64$q_length = valdsc->dsc$w_length;
+ dsc64->dsc64$pq_pointer = valdsc->dsc$a_pointer;
+ }
+ else
+ *dsc = *(struct dsc$descriptor *)inp->value;
+ } else
+ {
+ *type = inp->type;
+ *class = DSC$K_CLASS_S;
+ if (!is_a_desc64)
+ {
+ dsc->dsc$w_length = dsizes[inp->type];
+ dsc->dsc$a_pointer = &lclp->data;
+ memcpy(dsc->dsc$a_pointer, inp->value, dsizes[inp->type]);
+ } else
+ {
+ dsc64->dsc64$q_length = dsizes[inp->type];
+ dsc64->dsc64$pq_pointer = (char *)&lclp->data;
+ memcpy(dsc64->dsc64$pq_pointer, inp->value, dsizes[inp->type]);
+ }
+ }
+ break;
+ case VAL_NONE:
+ break;
+ default:
+ GTMASSERT;
+ break; /* though not necessary, keep compiler on some platforms happy */
+ }
+ lclp->initted = TRUE;
+ }
+ assert(inp == (zctabinput *)firstout);
+ if (mvpp < mvallistend) rts_error(VARLSTCNT(1) ERR_ZCCONMSMTCH);
+ assert(mvpp == mvallistend);
+ is_a_desc64 = FALSE;
+ for (outp = firstout; outp < lastout; outp++)
+ {
+ switch (outp->type) /* guard type */
+ {
+ case ZC$DTYPE_STRING:
+ case ZC$DTYPE_BYTE:
+ case ZC$DTYPE_BYTEU:
+ case ZC$DTYPE_WORD:
+ case ZC$DTYPE_WORDU:
+ case ZC$DTYPE_LONG:
+ case ZC$DTYPE_LONGU:
+ case ZC$DTYPE_QUAD:
+ case ZC$DTYPE_FLOATING:
+ case ZC$DTYPE_DOUBLE:
+ case ZC$DTYPE_H_FLOATING:
+ break;
+ default:
+ rts_error(VARLSTCNT(1) ERR_ZCUNKTYPE);
+ }
+ switch (outp->mechanism) /* guard mechanism */
+ {
+ case ZC$MECH_VALUE:
+ case ZC$MECH_REFERENCE:
+ case ZC$MECH_DESCRIPTOR:
+ case ZC$MECH_DESCRIPTOR64:
+ break;
+ default:
+ rts_error(VARLSTCNT(1) ERR_ZCUNKMECH);
+ }
+ switch (outp->qualifier) /* guard qualifier */
+ {
+ case ZC$OQUAL_REQUIRED:
+ case ZC$OQUAL_DUMMY:
+ case ZC$OQUAL_PREALLOCATE:
+ break;
+ default:
+ rts_error(VARLSTCNT(3) ERR_ZCALLTABLE, 0, ERR_ZCUNKQUAL);
+ }
+ lclp = lcllist + outp->position - 1;
+ if (lclp->initted)
+ {
+ inp = lclp->zctab;
+ if (lclp->skip || outp->type != inp->type || outp->mechanism != inp->mechanism ||
+ inp->type == ZC$DTYPE_STRING || outp->qualifier == ZC$OQUAL_PREALLOCATE)
+ rts_error(VARLSTCNT(5) ERR_ZCALLTABLE, 0, ERR_ZCPOSOVR, 1, outp->position);
+ } else
+ {
+ lclp->skip = FALSE;
+ lclp->zctab = outp;
+ if (ZC$MECH_DESCRIPTOR64 == outp->mechanism)
+ {
+ INIT_64BITDESC;
+ } else
+ {
+ INIT_32BITDESC;
+ }
+ *class = DSC$K_CLASS_S;
+ *type = outp->type;
+ if (outp->type == ZC$DTYPE_STRING)
+ {
+ assert(ZC$MECH_DESCRIPTOR == outp->mechanism || ZC$MECH_DESCRIPTOR64 == outp->mechanism );
+ if (!is_a_desc64)
+ {
+ dsc->dsc$w_length = 0;
+ dsc->dsc$a_pointer = 0;
+ } else
+ {
+ dsc64->dsc64$q_length = 0;
+ dsc64->dsc64$pq_pointer = 0;
+ }
+ if (ZC$OQUAL_PREALLOCATE == outp->qualifier && dst)
+ { /* if no output string, ignore this, else allocate space for the output string */
+ assert((0 < outp->value) && (outp->value <= MAX_STRLEN));
+ alloclen = outp->value;
+ if (is_a_desc64)
+ {
+ val_qw = alloclen;
+ status = lib$sget1_dd_64(&val_qw, dsc64);
+ } else
+ {
+ val_us = alloclen;
+ status = lib$sget1_dd(&val_us, dsc);
+ }
+ if (!(status & 1))
+ {
+ if (LIB$_INSVIRMEM == status)
+ rts_error(VARLSTCNT(3) ERR_VMSMEMORY2, 1, alloclen);
+ else
+ {
+ assert(LIB$_FATERRLIB == status);
+ GTMASSERT; /* Only other return code is fatal internal error */
+ }
+ }
+ } else
+ {
+ assert(0 == outp->value);
+ *class = DSC$K_CLASS_D;
+ }
+ } else
+ {
+ if (!is_a_desc64)
+ {
+ dsc->dsc$w_length = dsizes[inp->type];
+ dsc->dsc$a_pointer = &lclp->data;
+ } else
+ {
+ dsc64->dsc64$q_length = dsizes[inp->type];
+ dsc64->dsc64$pq_pointer = (char *)&lclp->data;
+ }
+ assert(is_a_desc64 ? dsc64->dsc64$q_length : dsc->dsc$w_length);
+ }
+ }
+ }
+ assert(outp == lastout);
+ if (zcrtn->outbnd_reset) /* if indicated, disable our outofband handling */
+ {
+ if (io_std_device.in->type == tt)
+ resetterm(io_std_device.in);
+ zc_call(zcrtn, zcret, lcllist, lcllistend, &save_ret);
+ if (io_std_device.in->type == tt)
+ setterm(io_std_device.in);
+ } else
+ zc_call(zcrtn, zcret, lcllist, lcllistend, &save_ret);
+ VERIFY_STORAGE_CHAINS;
+ if (mask)
+ {
+ for (indx = 0;; indx++)
+ {
+ if (!mask)
+ break;
+ byref = mask & 1;
+ mask >>= 1;
+ if (!byref)
+ continue;
+ inp = firstin + indx;
+ lclp = lcllist + inp->position - 1;
+ if (!lclp->skip)
+ {
+ desc2mval(&lclp->dsc, &tmpmval);
+ mvpp = mvallist + indx;
+ **mvpp = tmpmval;
+ }
+ }
+ }
+ if (dst != NULL) /* if a return value expected */
+ { /* Allocate space in stringpool for destination mval */
+ dst->mvtype = 0;
+ dstlen = 0;
+ if (ZC$RETC_VALUE == zcret->class)
+ dstlen += MAXNUMLEN;
+ for (outp = firstout; outp < lastout; outp++)
+ {
+ if (ZC$OQUAL_DUMMY != outp->qualifier)
+ {
+ if (dstlen)
+ dstlen += 1;
+ lclp = lcllist + outp->position - 1;
+ if ($is_desc64(&lclp->dsc))
+ {
+ INIT_64BITDESC;
+ } else
+ {
+ INIT_32BITDESC;
+ }
+ if (DSC$K_DTYPE_T != *type)
+ dstlen += MAXNUMLEN;
+ else
+ {
+ if (!is_a_desc64)
+ dstlen += dsc->dsc$w_length;
+ else {
+ if (MAX_STRLEN < dsc64->dsc64$q_length)
+ rts_error(VARLSTCNT(1) ERR_MAXSTRLEN);
+ dstlen += dsc64->dsc64$q_length;
+ }
+ }
+ }
+ }
+ if (MAX_STRLEN < dstlen)
+ rts_error(VARLSTCNT(1) ERR_MAXSTRLEN);
+ ENSURE_STP_FREE_SPACE(dstlen);
+ /* Construct destination mval */
+ dst->str.addr = stringpool.free;
+ dstlen = 0;
+ if (ZC$RETC_VALUE == zcret->class)
+ {
+ tmpdsc.dsc$b_dtype = zcret->type;
+ tmpdsc.dsc$b_class = DSC$K_CLASS_S;
+ tmpdsc.dsc$a_pointer = &save_ret;
+ desc2mval(&tmpdsc, &tmpmval);
+ MV_FORCE_STRD(&tmpmval);
+ dstlen += tmpmval.str.len;
+ *stringpool.free++ = ',';
+ dstlen++;
+ }
+ for (outp = firstout; outp < lastout; outp++)
+ {
+ if (ZC$OQUAL_DUMMY != outp->qualifier)
+ {
+ lclp = lcllist + outp->position - 1;
+ if ($is_desc64(&lclp->dsc))
+ {
+ INIT_64BITDESC;
+ } else
+ {
+ INIT_32BITDESC;
+ }
+ if (DSC64$K_DTYPE_T == *type)
+ {
+ if (!is_a_desc64)
+ {
+ memcpy(stringpool.free, dsc->dsc$a_pointer, dsc->dsc$w_length);
+ stringpool.free += dsc->dsc$w_length;
+ dstlen += dsc->dsc$w_length;
+ } else
+ {
+ memcpy(stringpool.free, dsc64->dsc64$pq_pointer, dsc64->dsc64$q_length);
+ stringpool.free += dsc64->dsc64$q_length;
+ dstlen += dsc64->dsc64$q_length;
+ }
+ if (DSC64$K_CLASS_S == *class && ZC$OQUAL_PREALLOCATE == outp->qualifier)
+ {
+ if (!is_a_desc64)
+ dsc->dsc$w_length = outp->value;
+ else
+ dsc64->dsc64$q_length = outp->value;
+ if ((status = lib$sfree1_dd(&lclp->dsc)) != SS$_NORMAL)
+ rts_error(VARLSTCNT(3) ERR_ZCCONVERT, 0, status);
+ } else if (DSC64$K_CLASS_D == *class && (dsc->dsc$a_pointer || dsc64->dsc64$pq_pointer))
+ {
+ if ((status = lib$sfree1_dd(&lclp->dsc)) != SS$_NORMAL)
+ rts_error(VARLSTCNT(3) ERR_ZCCONVERT, 0, status);
+ }
+ } else
+ {
+ desc2mval(&lclp->dsc, &tmpmval);
+ MV_FORCE_STRD(&tmpmval);
+ dstlen += tmpmval.str.len;
+ }
+ *stringpool.free++ = ',';
+ dstlen++;
+ }
+ }
+ dst->mvtype = MV_STR;
+ if (dstlen == 0)
+ {
+ assert(stringpool.free == dst->str.addr);
+ dst->str.len = 0;
+ } else
+ {
+ stringpool.free--; /* take off trailing , */
+ dst->str.len = stringpool.free - (unsigned char *)dst->str.addr;
+ assert(dst->str.len == dstlen - 1);
+ }
+ }
+ return;
+}
diff --git a/sr_vvms/dpgbldir_sysops.c b/sr_vvms/dpgbldir_sysops.c
new file mode 100644
index 0000000..0f42b7b
--- /dev/null
+++ b/sr_vvms/dpgbldir_sysops.c
@@ -0,0 +1,162 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include <fab.h>
+#include <iodef.h>
+#include <nam.h>
+#include <rmsdef.h>
+#include <ssdef.h>
+#include <efndef.h>
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "gbldirnam.h"
+#include "filestruct.h"
+#include "io.h"
+#include "stringpool.h"
+#include "dpgbldir.h"
+#include "dpgbldir_sysops.h"
+#include "trans_log_name.h"
+#include "gtm_logicals.h"
+
+GBLREF mval dollar_zgbldir;
+
+char LITDEF gde_labels[GDE_LABEL_NUM][GDE_LABEL_SIZE] =
+{
+ GDE_LABEL_LITERAL
+};
+
+/************************THESE ROUTINES ARE OS SPECIFIC AND SO WILL HAVE TO RESIDE IN ANOTHER MODULE*********************/
+
+#define DVI_LEN (SIZEOF(cc$rms_nam.nam$t_dvi))
+#define DID_LEN (SIZEOF(cc$rms_nam.nam$w_did))
+#define FID_LEN (SIZEOF(cc$rms_nam.nam$w_fid))
+
+bool comp_gd_addr(gd_addr *gd_ptr, struct FAB *file_ptr)
+{
+ if ((memcmp(&file_ptr->fab$l_nam->nam$w_fid, gd_ptr->id->fid, FID_LEN) == 0) &&
+ (memcmp(&file_ptr->fab$l_nam->nam$t_dvi, gd_ptr->id->dvi, DVI_LEN) == 0))
+
+ return TRUE;
+ return FALSE;
+}
+
+void fill_gd_addr_id(gd_addr *gd_ptr, struct FAB *file_ptr)
+{
+ gd_ptr->id = malloc(SIZEOF(*gd_ptr->id));
+ memcpy(&gd_ptr->id->dvi, &file_ptr->fab$l_nam->nam$t_dvi, DVI_LEN);
+ memcpy(&gd_ptr->id->did, &file_ptr->fab$l_nam->nam$w_did, DID_LEN);
+ memcpy(&gd_ptr->id->fid, &file_ptr->fab$l_nam->nam$w_fid, FID_LEN);
+
+ return;
+}
+/********************************THESE ROUTINES ARE STUBS PROVIDED FOR TESTING PURPOSES************************************/
+#define DOTGLD ".GLD"
+void *open_gd_file(mstr *v)
+{
+ struct FAB *fab;
+ int4 status;
+
+ error_def(ERR_ZGBLDIRACC);
+
+ fab = malloc(SIZEOF(struct FAB));
+ *fab = cc$rms_fab;
+ fab->fab$l_fna = v->addr;
+ fab->fab$b_fns = v->len;
+ fab->fab$l_fop = FAB$M_UFO ;
+ fab->fab$b_fac = FAB$M_GET | FAB$M_BIO;
+ fab->fab$l_nam = malloc(SIZEOF(struct NAM));
+ fab->fab$l_dna = DOTGLD;
+ fab->fab$b_dns = SIZEOF(DOTGLD) - 1;
+ *fab->fab$l_nam = cc$rms_nam;
+ status = sys$open(fab);
+ if (status != RMS$_NORMAL)
+ {
+ if (!dollar_zgbldir.str.len || ((dollar_zgbldir.str.len == v->len)
+ && !memcmp(dollar_zgbldir.str.addr, v->addr, v->len)))
+ {
+ rts_error(VARLSTCNT(9) ERR_ZGBLDIRACC, 6, v->len, v->addr,
+ LEN_AND_LIT(". Cannot continue"), LEN_AND_LIT(""), status);
+ assert(FALSE);
+ }
+ rts_error(VARLSTCNT(9) ERR_ZGBLDIRACC, 6, v->len, v->addr, LEN_AND_LIT(". Retaining "),
+ dollar_zgbldir.str.len, dollar_zgbldir.str.addr, status);
+ }
+ return fab;
+}
+
+void file_read(struct FAB *file_ptr, int4 size, char *buff, int4 pos)
+{
+ int4 status;
+ short iosb[4];
+
+ error_def(ERR_ZGBLDIRACC);
+
+ status = sys$qiow(EFN$C_ENF,file_ptr->fab$l_stv, IO$_READVBLK, &iosb[0], 0, 0, buff, size, pos, 0, 0, 0);
+ if (status == SS$_NORMAL)
+ status = iosb[0];
+ if (status != SS$_NORMAL)
+ rts_error(VARLSTCNT(9) ERR_ZGBLDIRACC, 6, file_ptr->fab$b_fns,file_ptr->fab$l_fna,
+ LEN_AND_LIT(""), LEN_AND_LIT(""), status);
+ return;
+}
+
+void close_gd_file(struct FAB *file_ptr)
+{
+ sys$dassgn(file_ptr->fab$l_stv);
+ if (file_ptr->fab$l_nam)
+ free(file_ptr->fab$l_nam);
+ free(file_ptr);
+ return;
+}
+
+
+void dpzgbini(void)
+{
+ mstr temp_mstr;
+ char temp_buff[MAX_TRANS_NAME_LEN];
+
+ dollar_zgbldir.mvtype = MV_STR;
+ dollar_zgbldir.str.addr = GTM_GBLDIR;
+ dollar_zgbldir.str.len = SIZEOF(GTM_GBLDIR) - 1;
+ if (SS$_NORMAL == trans_log_name(&dollar_zgbldir.str, &temp_mstr, &temp_buff[0]))
+ {
+ dollar_zgbldir.str.len = temp_mstr.len;
+ dollar_zgbldir.str.addr = temp_mstr.addr;
+ }
+ s2pool(&dollar_zgbldir.str);
+}
+
+mstr *get_name(mstr *ms)
+{
+ int4 status;
+ char c[MAX_TRANS_NAME_LEN];
+ mstr ms1, *new;
+
+ error_def(ERR_ZGBLDIRACC);
+
+ if ((status = trans_log_name(ms,&ms1,&c[0])) == SS$_NORMAL)
+ ms = &ms1;
+ else if (status != SS$_NOLOGNAM)
+ rts_error(VARLSTCNT(9) ERR_ZGBLDIRACC, 6, ms->len, ms->addr, LEN_AND_LIT(""), LEN_AND_LIT(""), status);
+ new = malloc(SIZEOF(mstr));
+ new->len = ms->len;
+ new->addr = malloc(ms->len);
+ memcpy(new->addr,ms->addr,ms->len);
+ return new;
+}
diff --git a/sr_vvms/dpgbldir_sysops.h b/sr_vvms/dpgbldir_sysops.h
new file mode 100644
index 0000000..d6cf868
--- /dev/null
+++ b/sr_vvms/dpgbldir_sysops.h
@@ -0,0 +1,22 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef __DPGBLDIR_SYSOPS_H__
+#define __DPGBLDIR_SYSOPS_H__
+
+bool comp_gd_addr(gd_addr *gd_ptr, struct FAB *file_ptr);
+void fill_gd_addr_id(gd_addr *gd_ptr, struct FAB *file_ptr);
+void file_read(struct FAB *file_ptr, int4 size, char *buff, int4 pos);
+void close_gd_file(struct FAB *file_ptr);
+void dpzgbini(void);
+mstr *get_name(mstr *ms);
+
+#endif
diff --git a/sr_vvms/dse.c b/sr_vvms/dse.c
new file mode 100644
index 0000000..5009428
--- /dev/null
+++ b/sr_vvms/dse.c
@@ -0,0 +1,177 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <efndef.h>
+#include <signal.h>
+#include <iodef.h>
+#include <rmsdef.h>
+#include <ssdef.h>
+#include <descrip.h>
+#include <climsgdef.h>
+
+#include "gtm_inet.h"
+
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "gdscc.h"
+#include "gdskill.h"
+#include "filestruct.h"
+#include "cli.h"
+#include "error.h"
+#include "min_max.h" /* needed for init_root_gv.h */
+#include "init_root_gv.h"
+#include "io.h"
+#include "iottdef.h"
+#include "jnl.h"
+#include "buddy_list.h" /* needed for tp.h */
+#include "hashtab_int4.h" /* needed for tp.h */
+#include "tp.h"
+#include "stp_parms.h"
+#include "stringpool.h"
+#include "repl_msg.h"
+#include "gtmsource.h"
+#include "gtmimagename.h"
+#include "desblk.h" /* for desblk structure */
+#include "util.h"
+#include "dse.h"
+#include "getjobnum.h"
+#include "patcode.h"
+#include "generic_exit_handler.h"
+#include "dfntmpmbx.h"
+#include "ladef.h"
+#include "ast_init.h"
+#include "get_page_size.h"
+#include "init_secshr_addrs.h"
+#include "dse_exit.h"
+#include "gtm_env_init.h" /* for gtm_env_init() prototype */
+#include "gtm_imagetype_init.h"
+#include "gtm_threadgbl_init.h"
+
+GBLDEF block_id patch_curr_blk;
+
+GBLREF VSIG_ATOMIC_T util_interrupt;
+GBLREF desblk exi_blk;
+GBLREF int4 exi_condition;
+GBLREF int4 lkid;
+GBLREF boolean_t dse_running;
+GBLREF gv_namehead *gv_target;
+GBLREF mval curr_gbl_root;
+GBLREF gd_region *gv_cur_region;
+GBLREF gd_binding *gd_map;
+GBLREF gd_binding *gd_map_top;
+GBLREF gd_addr *gd_header;
+GBLREF gd_addr *original_header;
+GBLREF sgmnt_addrs *cs_addrs;
+GBLREF short crash_count;
+GBLREF bool wide_out;
+GBLREF spdesc rts_stringpool, stringpool;
+GBLREF boolean_t write_after_image;
+
+error_def(ERR_CTRLC);
+
+OS_PAGE_SIZE_DECLARE
+
+extern int DSE_CMD();
+extern int CLI$DCL_PARSE();
+extern int CLI$DISPATCH();
+
+$DESCRIPTOR (prompt, "DSE> ");
+
+static readonly mstr lnm$group = {9, "LNM$GROUP"};
+static void dse_process(void);
+
+void dse(void)
+{
+ $DESCRIPTOR (desc, "SYS$OUTPUT");
+ char buff[MAX_LINE];
+ $DESCRIPTOR (command, buff);
+ unsigned short outlen;
+ uint4 status;
+ int4 sysout_channel;
+ t_cap t_mode;
+ DCL_THREADGBL_ACCESS;
+
+ GTM_THREADGBL_INIT;
+ gtm_imagetype_init(DSE_IMAGE);
+ gtm_env_init(); /* read in all environment variables */
+ TREF(transform) = TRUE;
+ util_out_open(0);
+ SET_EXIT_HANDLER(exi_blk, generic_exit_handler, exi_condition); /* Establish exit handler */
+ ESTABLISH(util_base_ch);
+ status =lp_id(&lkid);
+ if (SS$_NORMAL != status)
+ rts_error(VARLSTCNT(1) status);
+ get_page_size();
+ getjobnum();
+ INVOKE_INIT_SECSHR_ADDRS;
+ dfntmpmbx(lnm$group.len, lnm$group.addr);
+ ast_init();
+ stp_init(STP_INITSIZE);
+ rts_stringpool = stringpool;
+ initialize_pattern_table();
+ gvinit();
+ region_init(FALSE);
+ INIT_GBL_ROOT();
+ sys$assign(&desc, &sysout_channel, 0, 0);
+ if (sysout_channel)
+ {
+ sys$qiow(EFN$C_ENF, sysout_channel, IO$_SENSEMODE, 0, 0, 0, &t_mode, 12, 0, 0, 0, 0);
+ if (t_mode.pg_width >= 132)
+ wide_out = TRUE;
+ else
+ wide_out = FALSE;
+ } else
+ wide_out = FALSE;
+ if (cs_addrs)
+ crash_count = cs_addrs->critical->crashcnt;
+ patch_curr_blk = get_dir_root();
+ REVERT;
+ util_out_print("!/File !_!AD", TRUE, DB_LEN_STR(gv_cur_region));
+ util_out_print("Region!_!AD!/", TRUE, REG_LEN_STR(gv_cur_region));
+ dse_ctrlc_setup();
+ CREATE_DUMMY_GBLDIR(gd_header, original_header, gv_cur_region, gd_map, gd_map_top);
+ status = lib$get_foreign(&command, 0, &outlen, 0);
+ if ((status & 1) && outlen > 0)
+ {
+ command.dsc$w_length = outlen;
+ status = CLI$DCL_PARSE(&command, &DSE_CMD, &lib$get_input, 0, 0);
+ if (RMS$_EOF == status)
+ dse_exit();
+ else if (CLI$_NORMAL == status)
+ {
+ ESTABLISH(util_ch);
+ CLI$DISPATCH();
+ REVERT;
+ }
+ }
+ for (;;)
+ dse_process();
+}
+
+static void dse_process(void)
+{
+ uint4 status;
+
+ ESTABLISH(util_ch);
+ status = CLI$DCL_PARSE(0, &DSE_CMD, &lib$get_input, &lib$get_input, &prompt);
+ if (RMS$_EOF == status)
+ dse_exit();
+ else if (CLI$_NORMAL == status)
+ CLI$DISPATCH();
+ if (util_interrupt)
+ rts_error(VARLSTCNT(1) ERR_CTRLC);
+}
diff --git a/sr_vvms/dse.hlp b/sr_vvms/dse.hlp
new file mode 100644
index 0000000..354817c
--- /dev/null
+++ b/sr_vvms/dse.hlp
@@ -0,0 +1,1158 @@
+
+1 Overview
+ Overview
+ The GT.M Database Structure Editor, DSE, examines and repairs
+ Greystone Technology Database Structure (GDS) database(s). GT.M uses
+ Buffered Global (BG) and Mapped Memory (MM) access methods for GDS
+ files. For more information on GDS, refer to the "Greystone Database
+ Structure" chapter in the GT.M Administration and Operations Guide.
+ MUPIP INTEG provides comprehensive error checking, which serves to
+ verify the results of repairs undertaken with DSE. For more
+ information on MUPIP INTEG, refer to the "MUMPS Peripheral Interchange
+ Program" chapter in the GT.M Administration and Operations Guide. For
+ more information on the use of DSE, refer to the "Maintaining Database
+ Integrity" chapter in the GT.M Administration and Operations Guide.
+
+1 DSE_Functions
+ Functions of DSE
+ DSE is primarily a database repair utility.
+
+ Use DSE to:
+
+ o Dump parts of the database for troubleshooting database errors
+
+ o Add or delete a record in a block
+
+ o Update file, block or record header information
+
+ o Update bit maps
+
+ o Save copies of database fragments for analysis, audit or
+ restoration.
+
+ When GT.CX is installed, DSE may report DSEBLKRDFAIL, Failed attempt
+ to read block. Use the command CRITICAL /SEIZE followed by CRITICAL
+ /RELEASE to clear this error.
+
+ Use the DSE EXIT command to leave DSE.
+
+1 Command_Syntax
+ Command Syntax
+ The format for DSE commands is:
+
+ Command qualifier
+
+ DSE interprets all numeric input as hexadecimal, except for time
+ values, the /BLK_SIZE=, /KEY_MAX_SIZE=, /RECORD_MAX_SIZE=,
+ /REFERENCE_COUNT=, /TIMERS_PENDING= and /WRITES_PER_FLUSH= on CHANGE
+ /FILEHEADER, and /VERSION= on the REMOVE and RESTORE commands. This
+ convention corresponds to the displays provided by DSE and by MUPIP
+ INTEG.
+
+1 ADD
+ AD[D]
+ The ADD command adds a record to a block.
+
+ The format of the ADD command is:
+
+ AD[D] [/B[LOCK]=block]
+
+ For greater than level 0 blocks add:
+
+ /STAR /POINTER=block
+
+ or
+
+ /OFFSET=offset|/RECORD=record /KEY=key /POINTER=block
+
+ For level 0 blocks add:
+
+ /OFFSET=offset|/RECORD=record /KEY=key /D[ATA]=string
+
+ The ADD command requires either the /OFFSET or /RECORD qualifier to
+ position the record in the block and either the /KEY or the /STAR
+ qualifier to define the key for the block.
+
+ The /STAR qualifier is not valid at level 0 (i.e., for a data block).
+ The ADD command requires the /DATA qualifier at level 0 or the
+ /POINTER qualifier at any other level to provide the content of the
+ record.
+
+2 Qualifiers
+/BLOCK
+ /B[LOCK]=block_number
+ Specifies the block to receive the new record.
+
+ On commands with no /BLOCK= qualifier, DSE uses the last block
+ handled by a DSE operation. In this case, when no block has been
+ accessed, .i.e., on the first block oriented command, DSE uses
+ block one (1).
+
+/DATA
+ /D[ATA]=string
+ Specifies the data field for records added to a data block. Use
+ quotes around string and escape codes of the form \a or \ab,
+ where a and b are hexadecimal digits representing non-printing
+ characters. \\ translates to a single backslash. The /DATA
+ qualifier only applies at level 0 and is incompatible with the
+ /STAR and /POINTER qualifiers.
+
+/KEY
+ /K[EY]=key
+ Specifies the key of the new record. Enclose MUMPS-style global
+ references in quotes (""). The /KEY qualifier is incompatible
+ with the /STAR qualifier.
+
+/OFFSET
+ /O[FFSET]=offset
+ Adds the new record at the next record boundary after the
+ specified offset. The /OFFSET qualifier is incompatible with the
+ /RECORD and /STAR qualifiers.
+
+/POINTER
+ /P[OINTER]=pointer
+ Specifies the block pointer field for records added to an index
+ block. The /POINTER qualifier is incompatible with the /DATA
+ qualifier and cannot be used at level 0.
+
+/RECORD
+ /R[ECORD]=record_number
+ Specifies a record number of the new record. The /RECORD
+ qualifier is incompatible with the /OFFSET and /STAR qualifiers.
+
+/STAR
+ /S[TAR]
+ Adds a star record (i.e., a record that identifies the last
+ record in an indexed block) at the end of the specified block.
+ The /STAR qualifier is incompatible with all qualifiers except
+ /BLOCK and /POINTER and cannot be used at level 0.
+
+1 ALL
+ AL[L]
+ The ALL command applies action(s) specified by a qualifier to all GDS
+ regions defined by the current Global Directory. This is a very
+ powerful command; use caution. Be especially careful if you have an
+ overlapping database structure (e.g., overlapping regions accessed
+ from separate application global directories).
+
+2 Qualifiers
+/BUFFER_FLUSH
+ /B[UFFER_FLUSH]
+ Flushes to disk buffers all regions specified by the current
+ Global Directory. The /BUFFER_FLUSH qualifier is incompatible
+ with the /RENEW qualifier.
+
+/CRITINIT
+ /C[RITINIT]
+ Initializes critical sections for all regions specified by the
+ current Global Directory. The /CRITINIT qualifier is
+ incompatible with the /RENEW, /RELEASE and /SEIZE qualifiers.
+
+/FREEZE
+ /[NO]F[REEZE]
+ Prevents updates to all GDS regions specified by the current
+ Global Directory. The /NOFREEZE allows updates to all GDS
+ regions specified by the current Global Directory. The /FREEZE
+ qualifier is incompatible with the /RENEW qualifier.
+
+ DSE releases /FREEZE when it EXITs. To hold all databases, enter
+ ALL /FREEZE=TRUE and then SPAWN to perform other operations.
+
+/REFERENCE
+ /REF[ERENCE]
+ Resets reference counts to 1 for all regions specified by the
+ current Global Directory. The /REFERENCE qualifier is
+ incompatible with the /RENEW qualifier.
+
+/RELEASE
+ /REL[EASE]
+ Releases critical sections for all regions specified by the
+ current Global Directory. The /RELEASE qualifier is incompatible
+ with the /CRITINIT, /RENEW and /SEIZE qualifiers.
+
+/RENEW
+ /REN[EW]
+ Reinitializes critical sections (/CRITICAL) and buffers
+ (/WCINIT), resets reference counts to 1 (/REFERENCE_COUNT) and
+ clears freeze flags for all regions specified by the current
+ Global Directory (/NOFREEZE). /RENEW requires confirmation. The
+ /RENEW qualifier is incompatible with all other qualifiers.
+
+/SEIZE
+ /S[EIZE]
+ Seizes the critical section for all regions specified by the
+ current Global Directory. The /SEIZE qualifier is incompatible
+ with the /CRITINIT, /RELEASE and /RENEW qualifiers.
+
+ The SEIZE qualifier can be useful when you encounter a
+ DSEBLKRDFAIL error, generated when DSE is unable to read a block
+ from the database. If you encounter this error when accessing
+ data on a cluster using GT.CX, SEIZE and RELEASE the critical
+ section; this may solve the problem.
+
+/WCINIT
+ /W[CINIT]
+ Reinitializes buffers for all regions specified by the current
+ Global Directory. /WCINIT requires confirmation. The /WCINIT
+ qualifier is incompatible with the /RENEW qualifier.
+
+1 BUFFER_FLUSH
+ B[UFFER_FLUSH]
+ The BUFFER_FLUSH command flushes the current region's buffers to disk.
+
+
+ The format of the BUFFER_FLUSH command is:
+
+ B[UFFER_FLUSH]
+
+ The BUFFER_FLUSH command has no qualifiers.
+
+1 CHANGE
+ CH[ANGE]
+ The CHANGE command changes fields of a file, block, or record header
+ and the bit map.
+
+ The CHANGE command either has a /FILEHEADER qualifier or an implicit
+ or explicit /BLOCK qualifier plus one or more of their associated
+ qualifiers to define the target of the change.
+
+2 Block_qualifiers
+/BLOCK
+ /BL[OCK]=block_number
+ Specifies the block to modify. The /BLOCK qualifier is
+ incompatible with the /FILEHEADER qualifier and all qualifiers
+ related to /FILEHEADER.
+
+ /BLOCK is the default qualifier. On commands with neither a
+ /BLOCK nor a /FILEHEADER qualifier, DSE uses the last block
+ handled by a DSE operation. In this case, when no block has been
+ accessed, that is, on the first block-oriented command, DSE uses
+ block one (1).
+
+/BSIZ
+ /BS[IZ]=block_size
+ Changes the block size field of the specified block. Decreasing
+ the block size can result in loss of existing data. The /BSIZ
+ qualifier is incompatible with all qualifiers except /BLOCK,
+ /LEVEL and /TN.
+
+/LEVEL
+ /L[EVEL]=level
+ Changes the level field for the specified block. The /LEVEL
+ qualifier is incompatible with all qualifiers except /BLOCK,
+ /BSIZ and /TN.
+
+/TN
+ /TN[=transaction_number]
+ Changes the transaction number for the current block. When a
+ CHANGE command does not include a /TN=, DSE sets the transaction
+ number to the current transaction number. Manipulation of the
+ block transaction number affects MUPIP BACKUP /INCREMENTAL. The
+ /TN qualifier is incompatible with all qualifiers except /BLOCK,
+ /BSIZ and /LEVEL.
+
+/OFFSET
+ /OF[FSET]=offset
+ Specifies the offset within the block of the target record. The
+ /OFFSET qualifier is incompatible with all qualifiers except
+ /BLOCK, /CMPC and /RSIZ.
+
+/RECORD
+ /RE[CORD]=record_number
+ Specifies the record number of the target record. The /RECORD
+ qualifier is incompatible with all qualifiers except /BLOCK,
+ /CMPC and /RSIZ.
+
+/CMPC
+ /CM[PC]=compression_count
+ Changes the compression count field of the specified record. The
+ /CMPC qualifier is incompatible with all qualifiers except
+ /BLOCK, /OFFSET, and /RECORD.
+
+/RSIZ
+ /RS[IZ]=record_size
+ Changes the record size field of the specified record. The /RSIZ
+ qualifier is incompatible with all qualifiers except /OFFSET and
+ /RECORD.
+
+2 File_header_qualifiers
+/FILEHEADER
+ /FI[LEHEADER]
+ Enables modification of specific fields in the file header. The
+ /FILEHEADER qualifier is incompatible with the /BLOCK and all
+ qualifiers related to /BLOCK (i.e., /BSIZ, /CMPC, /LEVEL,
+ /OFFSET, /RECORD, /RSIZ and /TN qualifiers).
+
+/BLK_SIZE
+ /BLK[_SIZE]=block_size
+ Changes the decimal block size field of the current file. Use
+ the /BLK_SIZE qualifier only in conjunction with the /FILEHEADER
+ qualifier. Do not use this CHANGE qualifier except on
+ instructions from Greystone.
+
+/BLOCKS_FREE
+ /BLO[CKS_FREE]=free blocks
+ Changes the free blocks field of the current file. Use the
+ /BLOCK_FREE qualifier only in conjunction with the /FILEHEADER
+ qualifier. Database operations maintain this field for the
+ user's convenience. The field does not control any database
+ operations.
+
+/B_COMPREHENSIVE
+ /B_C[OMPREHENSIVE]=transaction_number
+ Changes the transaction number in the fileheader of the last
+ comprehensive backup to the value specified. Use this qualifier
+ only in conjunction with the /FILEHEADER qualifier.
+
+/B_INCREMENTAL
+ /B_I[NCREMENTAL]=transaction_number
+ Changes the transaction number in the fileheader of the last
+ incremental backup to the value specified. Use this qualifier
+ only in conjunction with the /FILEHEADER qualifier.
+
+/B_RECORD
+ /B_R[ECORD]=transaction_number
+ Changes the transaction number in the fileheader of the last
+ /RECORD backup to the value specified. Use this qualifier only
+ in conjunction with the /FILEHEADER qualifier.
+
+/CORRUPT_FILE
+ /CO[RRUPT_FILE]=value
+ Sets the file_corrupt field in the file header. Possible values
+ are: TRUE, FALSE and NOCHANGE. Use the /CORRUPT_FILE qualifier
+ only in conjunction with the /FILEHEADER qualifier.
+
+ WARNING: when DSE EXITs after a CHANGE /FILEHEADER /CORRUPT=TRUE
+ without a matching CHANGE /FILEHEADER /CORRUPT=FALSE, the file
+ becomes unavailable to all future access.
+
+/CURRENT_TN
+ /CU[RRENT_TN]=transaction_number
+ Changes the current transaction number for the current region.
+ Use the /CURRENT_TN qualifier only in conjunction with the
+ /FILEHEADER qualifier. This qualifier has implications only for
+ MUPIP BACKUP /INCREMENTAL. Raising the /CURRENT_TN corrects
+ block transaction number too large errors.
+
+/FLUSH_TIME
+ /FL[USH_TIME][=delta_time]
+ Changes the flush_time default interval (in delta_time). The
+ time entered must be between 0 and 1 hour.
+
+ Use the /FLUSH_TIME qualifier only in conjunction with the
+ /FILEHEADER qualifier. Do not use this CHANGE qualifier except
+ on instructions from Greystone. A /FLUSH_TIME with no value
+ resets the /FLUSH_TIME to the default value. Input is
+ interpreted as decimal.
+
+/FREEZE
+ /FR[EEZE]=value
+ Sets availability of the region for update. Possible values are:
+ TRUE, FALSE and NOCHANGE. Use to "freeze" (disable database
+ writes) or "unfreeze" the database. Use the /FREEZE qualifier
+ only in conjunction with the /FILEHEADER qualifier.
+
+ DSE releases /FREEZE when it EXITs. To hold the database(s),
+ CHANGE /FILEHEADER /FREEZE=TRUE and then SPAWN to perform other
+ operations.
+
+/KEY_MAX_SIZE
+ /K[EY_MAX_SIZE]=key_max_size
+ Changes the decimal value for the maximum allowable key size.
+ Use the /KEY_MAX_SIZE qualifier only in conjunction with the
+ /FILEHEADER qualifier. Reducing KEY_MAX_SIZE can restrict access
+ to existing data and cause GT.M-generated errors. Do not create
+ incompatible key and record sizes. If you make a permanent
+ change to the key size using DSE, use GDE to check that the
+ appropriate Global Directory contains the same key size for the
+ region. For more information on key and record sizes, refer to
+ the "Global Directory Editor" chapter in the GT.M Administration
+ and Operations Guide.
+
+/NULL_SUBSCRIPTS
+ /N[ULL_SUBSCRIPTS]=value
+ Sets the acceptability of null subscripts in database keys.
+ Possible values are: TRUE, FALSE and NOCHANGE. Use the
+ /NULL_SUBSCRIPTS qualifier only in conjunction with the
+ /FILEHEADER qualifier. Prohibiting null-subscripts can restrict
+ access to existing data and cause GT.M generated errors.
+
+/QUANTUM_INTERVAL
+ /Q[UANTUM_INTERVAL][=delta_time]
+ Changes the amount of time a single system holds control of
+ writes to the database file. The time entered must be between 0
+ and 1 hour.
+
+ Use the /QUANTUM_INTERVAL qualifier only in conjunction with the
+ /FILEHEADER qualifier. This field applies only to clustered
+ databases. Do not use this CHANGE qualifier except on
+ instructions from Greystone. A /QUANTUM_INTERVAL with no value
+ resets the /QUANTUM_INTERVAL to the default value. Input is
+ interpreted as decimal.
+
+/RECORD_MAX_SIZE
+ /REC[ORD_MAX_SIZE]=record_max_size
+ Changes the decimal value for the maximum allowable record size.
+ Use the /RECORD_MAX_SIZE qualifier only in conjunction with the
+ /FILEHEADER qualifier. Reducing the RECORD_MAX_SIZE can restrict
+ access to existing data and cause GT.M-generated errors. Do not
+ create incompatible key and record sizes. If you make a
+ permanent change to the record size using DSE, make sure GDE
+ contains the same record size for the appropriate Global
+ Directory. For more information on key and record sizes, refer
+ to "Global Directory Editor" chapter in GT.M Administration and
+ Operations Guide.
+
+/REFERENCE_COUNT
+ /REF[ERENCE_COUNT]=reference_count
+ Sets a field that tracks how many processes are accessing the
+ database from the current node. MUPIP INTEG and DSE use decimal
+ numbers for /REFERENCE_COUNT. Use the /REFERENCE_COUNT qualifier
+ only in conjunction with the /FILEHEADER qualifier. Restrict
+ CHANGE /FILEHEADER /REFERENCE_COUNT to the case where the
+ process running DSE has exclusive (stand-alone) access to the
+ database file. When DSE has sole access to a database file the
+ /REFERENCE_COUNT should be 1. This is an informational field and
+ does not have any effect on processing.
+
+/RESPONSE_INTERVAL
+ /[NO]RES[PONSE_INTERVAL][=delta_time]
+ Changes the time that processes trying to access the clustered
+ database wait before returning an error. /NORESPONSE_INTERVAL
+ prevents the system from reporting cluster access timeouts as
+ errors. The time entered must be between 0 and 1 hour.
+
+ A large /RESPONSE_INTERVAL or /NORESPONSE_INTERVAL effectively
+ hangs processes when a cluster problem occurs. When an operator
+ action clears the problem, processing resumes. A small
+ /RESPONSE_INTERVAL causes GT.M processes to generate an error
+ when a cluster problem occurs. The /RESPONSE_INTERVAL should be
+ set to at least the /QUANTUM_INTERVAL times twice the number of
+ systems in the cluster running GT.CX.
+
+ Use the /RESPONSE_INTERVAL qualifier only in conjunction with
+ the /FILEHEADER qualifier. This field applies only to clustered
+ databases. Do not use this CHANGE qualifier except on
+ instructions from Greystone. A /RESPONSE_INTERVAL with no value
+ resets the /RESPONSE_INTERVAL to the default value. Input is
+ interpreted as decimal.
+
+/STALENESS_TIMER
+ /[NO]S[TALENESS_TIMER][=delta_time]
+ Changes the amount of time a system reading the database allows
+ to pass before resynchronizing with the database.
+ /NOSTALENESS_TIMER prevents the system from enforcing this type
+ of synchronization. The time entered must be between 0 and 1
+ hour.
+
+ {/\-}~STALENESS_TIMER limits how long old blocks can be in cache
+ memory before they are refreshed. A node synchronizes
+ automatically when it writes or when it reads a new block from
+ disk that shows synchronization is required. The
+ /STALENESS_TIMER should be set to at least the
+ /QUANTUM_INTERVAL times twice the number of systems.
+ Use the /STALENESS_TIMER qualifier only in conjunction with the
+ /FILEHEADER qualifier. This field applies only to clustered
+ databases. Do not use this CHANGE qualifier except on
+ instructions from Greystone. A /STALENESS_TIMER with no value
+ resets the /STALENESS_TIMER to the default value. Input is
+ interpreted as decimal.
+
+/TICK_INTERVAL
+ /TIC[K_INTERVAL][=delta_time]
+ Changes the time a system controlling writes continues its
+ /QUANTUM_INTERVAL when it has no writes to perform and other
+ systems have writes pending. The time entered must be between 0
+ and 1 hour.
+
+ If /TICK_INTERVAL is equal to or larger than /QUANTUM_INTERVAL,
+ it is effectively disabled. For the best performance,
+ /TICK_INTERVAL should generally be small.
+
+ Use the /TICK_INTERVAL qualifier only in conjunction with the
+ /FILEHEADER qualifier. This field applies only to clustered
+ databases. Do not use this CHANGE qualifier except on
+ instructions from Greystone. A /TICK_INTERVAL with no value
+ resets the /TICK_INTERVAL to the default value. Input is
+ interpreted as decimal.
+
+/TIMERS_PENDING
+ /TI[MERS_PENDING]=timers_pending
+ Sets field that tracks the number of processes considering a
+ timed flush. Use the /TIMERS_PENDING qualifier only in
+ conjunction with the /FILEHEADER qualifier. Proper values are 0,
+ 1, and 2. Do not use this CHANGE qualifier except on
+ instructions from Greystone.
+
+/TOTAL_BLKS
+ /TO[TAL_BLKS]=total_blocks
+ Changes the total blocks field of the current file. Use the
+ /TOTAL_BLKS qualifier only in conjunction with the /FILEHEADER
+ qualifier.
+
+ WARNING: The total blocks field should always reflect the actual
+ size of the database. Change this field only if it no longer
+ reflects the size of the database.
+
+/TRIGGER_FLUSH
+ /TR[IGGER_FLUSH]=trigger_flush
+ Sets the decimal value for the triggering threshold, in buffers,
+ for flushing the cache modified queue. Use the /TRIGGER_FLUSH
+ qualifier only in conjunction with the /FILEHEADER qualifier. Do
+ not use this CHANGE qualifier except on instructions from
+ Greystone.
+
+/WRITES_PER_FLUSH
+ /WR[ITES_PER_FLUSH]=writes_per_flush
+ Sets the decimal number of blocks to write in each flush. Use
+ the /WRITES_PER_FLUSH qualifier only in conjunction with the
+ /FILEHEADER qualifier. Do not use this CHANGE qualifier except
+ on instructions from Greystone.
+
+1 CLOSE
+ CL[OSE]
+ The CLOSE command closes the currently open output file. Use to close
+ the opened dump file.
+
+ The format of the CLOSE command is:
+
+ CL[OSE]
+
+ The CLOSE command has no qualifiers.
+
+1 CRITICAL
+ CR[ITICAL]
+ The CRITICAL command along with its qualifiers displays and/or
+ modifies the status and contents of the critical section for the
+ current region. The critical section provides a control mechanism.
+ This field identifies, by its PID, the process presently managing
+ updates to database.
+
+ The format of the CRITICAL command is:
+
+ CR[ITICAL] /I[NIT]
+ /O[WNER]
+ /REL[EASE]
+ /REM[OVE]
+ /RES[ET]
+ /S[EIZE]
+
+ By default, the CRITICAL command assumes the /OWNER qualifier, which
+ displays the status of the critical section.
+
+2 Qualifiers
+/INIT
+ /I[NIT]
+ Reinitializes the critical section. The /RESET qualifier causes
+ all processes actively accessing that database file to signal an
+ error. Do not use /INIT without the /RESET parameter when other
+ processes are accessing the region.
+
+ CAUTION: Using CRITICAL /INIT when the write owner of a critical
+ section is an active GT.M process may cause structural database
+ damage.
+
+/OWNER
+ /O[WNER]
+ Displays the ID of the process at the head of the critical
+ section, the ID of the process running DSE and the count of
+ critical read owners. When the current process owns the critical
+ section, DSE displays a warning message. The /OWNER qualifier is
+ incompatible with other qualifiers.
+
+ Example:
+
+ DSE> critical/owner
+
+ Write critical section is currently unowned
+
+/RELEASE
+ /REL[EASE]
+ Releases the critical section if the process running DSE owns
+ the section. The /RELEASE qualifier is incompatible with other
+ qualifiers.
+
+/REMOVE
+ /REM[OVE]
+ Terminates any write ownership of the critical section. Use this
+ when the critical section is owned by a process that is
+ nonexistent or is known to no longer be running a GT.M image.
+ The /REMOVE qualifier is incompatible with other qualifiers.
+
+ CAUTION: Using CRITICAL/REMOVE when the write owner of a
+ critical section is an active GT.M process may cause structural
+ database damage.
+
+/RESET
+ /RES[ET]
+ Displays the number of times the critical section has been
+ through an online reinitialization.
+
+ /RESET when used with /INIT causes an error for processes that
+ are attempting to get the critical section of the region. Use
+ /RESET normally or if the write ownership belongs to an active
+ GT.M process that does not respond to a MUPIP STOP. The /RESET
+ qualifier is only compatible with the /INIT qualifier.
+
+/SEIZE
+ /S[EIZE]
+ Seizes the critical section if the section is available. The
+ /SEIZE qualifier is incompatible with other qualifiers.
+
+1 DUMP
+ D[UMP]
+ The DUMP command displays blocks, records or file headers. DUMP serves
+ as one of the primary DSE examination commands. Use the error messages
+ reported by MUPIP INTEG to determine what to DUMP and examine from the
+ database. DUMP also transfers records to a sequential file for future
+ study and/or for input to MUPIP LOAD.
+
+ The DUMP command requires specification of either /BLOCK, /HEADER,
+ /RECORD or /FILEHEADER.
+
+2 Qualifiers
+/BLOCK
+ /B[LOCK]=block_number
+ Specifies the starting block of the dump. The /BLOCK qualifier
+ is incompatible with the /FILEHEADER qualifier.
+
+ On commands with no /BLOCK= qualifier, DSE uses the last block
+ handled by a DSE operation. In this case, when no block has been
+ accessed, .i.e., on the first block oriented command, DSE uses
+ block one (1).
+
+ Example:
+
+ DSE> dump/block=2
+
+ Block 2 Size 1B Level 0 TN 2
+ Rec:1 Blk 2 Off 7 Size A Cmpc 0 Ptr 8 Key ^a
+ 7 : | A 0 0 61 0 0 8 0 0 0
+ | . . . a . . . . . .
+
+ Rec:2 Blk 2 Off 11 Size A Cmpc 0 Ptr B Key ^b
+ 11 : | A 0 0 62 0 0 B 0 0 0
+ | . . . b . . . . . .
+
+
+/COUNT
+ /C[OUNT]=count
+ Specifies the number of block headers or records to DUMP. The
+ /COUNT qualifier is incompatible with the /FILEHEADER qualifier.
+
+/FILEHEADER
+ /F[ILEHEADER]
+ Dumps file header information. The /FILEHEADER qualifier is
+ incompatible with all other qualifiers.
+
+/GLO
+ /G[LO]
+ Dumps the specified record or blocks into the current output
+ file in Global Output (GO) format. The /GLO qualifier is
+ incompatible with the /HEADER and /FILEHEADER qualifiers.
+
+/HEADER
+ /[NO]H[EADER]
+ Specifies whether the dump of the specified blocks or records is
+ restricted to, or excludes, headers. The /HEADER qualifier is
+ incompatible with the /GLO and /FILEHEADER qualifiers.
+
+ By default, DUMP displays all information in a block or record.
+
+/OFFSET
+ /O[FFSET]=offset
+ Specifies the offset of the starting record for the dump. If the
+ offset does not point to the beginning of a record, DSE rounds
+ down to the last valid record start (e.g., DUMP/OFF=10 starts at
+ /OFF=A if that was the last record). The /OFFSET qualifier is
+ incompatible with the /RECORD and /FILEHEADER qualifiers.
+
+/RECORD
+ /R[ECORD]=record_number
+ Specifies the record number of the starting record of the dump.
+ The /RECORD qualifier is incompatible with the /OFFSET and
+ /FILEHEADER qualifiers.
+
+1 EVALUATE
+ EV[ALUATE]
+ The EVALUATE command displays a number in both hexadecimal and
+ decimal. Use it to translate a hexadecimal number to decimal and vice
+ versa. The /DECIMAL and /HEXADECIMAL qualifiers specify the input base
+ for the number.
+
+ The format of the EVALUATE command is:
+
+ EV[ALUATE] /D[ECIMAL]
+ /H[EXADECIMAL]
+ /N[UMBER]=number
+
+ The /NUMBER qualifier is required.
+
+ By default, EVALUATE treats the number as having a hexadecimal base.
+
+2 Qualifiers
+/DECIMAL
+ /D[ECIMAL]
+ Specifies that the input number has a decimal base. The /DECIMAL
+ qualifier is incompatible with the /HEXADECIMAL qualifier
+
+/HEXADECIMAL
+ /H[EXADECIMAL]
+ Specifies that the input number has a hexadecimal base. The
+ /HEXADECIMAL qualifier is incompatible with the /DECIMAL
+ qualifier.
+
+/NUMBER
+ /N[UMBER]=number
+ Specifies the number to evaluate. This qualifier is required.
+
+ Example:
+
+ DSE> evaluate/number=61
+
+ Hex: 61 Dec: 97
+
+
+1 EXIT
+ EX[IT]
+ The EXIT command ends a DSE session.
+
+ The format of the EXIT command is:
+
+ EX[IT]
+
+ The EXIT command has no qualifiers.
+
+1 FIND
+ F[IND]
+ The FIND command directs DSE to a given block or region. At the
+ beginning of a DSE session, use the FIND /REGION command to select the
+ target region.
+
+ The FIND command, except with the /FREEBLOCK and /REGION qualifiers,
+ uses the index tree to locate blocks. FIND can locate blocks only
+ within the index tree structure. If you need to locate keys
+ independent of their attachment to the tree, use the RANGE command.
+
+2 Qualifiers
+/BLOCK
+ /B[LOCK]=block_number
+ Specifies the block to find. The /BLOCK qualifier is
+ incompatible with the /KEY and /REGION qualifiers.
+
+ On commands with no /BLOCK= qualifier, DSE uses the last block
+ handled by a DSE operation. In this case, when no block has been
+ accessed, .i.e., on the first block oriented command, DSE uses
+ block one (1).
+
+/EXHAUSTIVE
+ /E[XHAUSTIVE]
+ Instructs DSE to search the entire index structure for the
+ desired path or siblings. FIND /EXHAUSTIVE is useful in locating
+ blocks that are in the tree but not indexed correctly. The
+ /EXHAUSTIVE qualifier is incompatible with the /FREEBLOCK, /KEY
+ and /REGION qualifiers.
+
+/FREEBLOCK
+ /F[REEBLOCK]
+ Finds the nearest free block to the block specified by /HINT.
+ The /FREEBLOCK qualifier is incompatible with all other
+ qualifiers except /BLOCK and /HINT. The /HINT qualifier is
+ required with the /FREEBLOCK qualifier.
+
+/HINT
+ /H[INT]=block_number
+ Designates the starting point of a /FREEBLOCK search. The /HINT
+ qualifier can be used only in conjunction with the /FREEBLOCK
+ qualifier.
+
+/KEY
+ /K[EY]=key
+ Searches the database for the block containing the specified
+ key. Enclose a MUMPS style key in quotes (""). The /KEY
+ qualifier is incompatible with all other qualifiers.
+
+/REGION
+ /R[EGION][=region]
+ Switches to the named Global Directory region. The /REGION
+ qualifier is incompatible with all other qualifiers.
+
+ /REGION without a specified region, or /REGION=*, displays all
+ existing regions in the database.
+
+/SIBLINGS
+ /S[IBLINGS]
+ Displays the block numbers of the logical siblings of the
+ specified block. The logical siblings are the blocks that
+ logically exist to the right and left of the given block in the
+ database tree structure. The /SIBLINGS qualifier is incompatible
+ with the /FREEBLOCK, /KEY and /REGION qualifiers.
+
+1 HELP
+ H[ELP]
+ The HELP command explains DSE commands. The HELP command uses similar
+ conventions to the VAX/VMS help facility.
+
+ The format of the HELP command is:
+
+ H[ELP] [item]
+
+ Item tells HELP which information to display. Enter the DSE command
+ (item) after the HELP command or at the Topic prompt. Use <RETURN> or
+ <CTRL Z> to return to the DSE prompt.
+
+1 INTEGRIT
+ I[NTEGRIT]
+ The INTEGRIT command checks the internal consistency of a non-bitmap
+ block. INTEG reports errors in hexadecimal notation.
+
+ The format of the INTEGRIT command is:
+
+ I[NTEGRIT] /B[LOCK]=block_number
+
+2 Qualifiers
+/BLOCK
+ /B[LOCK]=block_number
+ Specifies the block for DSE to check.
+
+ On commands with no /BLOCK= qualifier, DSE uses the last block
+ handled by a DSE operation. In this case, when no block has been
+ accessed, .i.e., on the first block oriented command, DSE uses
+ block one (1).
+
+1 MAPS
+ M[APS]
+ The MAPS command examines or updates bit maps.
+
+ MAPS forces blocks either /BUSY or /FREE. The /MASTER qualifier
+ reflects the current status of a local bit map back into the master
+ map. The /RESTORE qualifier rebuilds all maps and should be used with
+ a great deal of caution as it can destroy important information.
+
+ By default, MAPS shows the status of the bit map for the specified
+ block.
+
+2 Qualifiers
+/BLOCK
+ /BL[OCK]=block_number
+ Specifies the target block for MAPS. The /BLOCK qualifier is
+ incompatible with the /RESTORE_ALL qualifier.
+
+ On commands with no /BLOCK= qualifier, DSE uses the last block
+ handled by a DSE operation. In this case, when no block has been
+ accessed, .i.e., on the first block-oriented command, DSE uses
+ block one (1).
+
+/BUSY
+ /BU[SY]
+ Marks the current block busy in the block's local map and
+ appropriately updates the master bit map. The /BUSY qualifier is
+ incompatible with all qualifiers except /BLOCK.
+
+/FREE
+ /F[REE]
+ Marks the current block free in the block's local map and
+ appropriately updates the master bit map. The /FREE qualifier is
+ incompatible with all qualifiers except /BLOCK.
+
+/MASTER
+ /M[ASTER]
+ Sets the master bit map bit associated with the current block's
+ local map according to whether that local map is full or not.
+ The /MASTER qualifier is incompatible with all qualifiers except
+ /BLOCK.
+
+/RESTORE_ALL
+ /R[ESTORE_ALL]
+ Sets all local bit maps and the master bit map to reflect the
+ blocks used in the database file. Use RESTORE_ALL only if the
+ database contents are known to be correct, but a large number of
+ the bit maps require correction. The /RESTORE_ALL qualifier is
+ incompatible with all other qualifiers.
+
+1 OPEN
+ OP[EN]
+ The OPEN command opens a file for sequential output of global variable
+ data. OPEN a file to which you want to "dump" information.
+
+ The format of the OPEN command is:
+
+ OP[EN] /F[ILE]=file
+
+ If an OPEN command does not have a /FILE qualifier, DSE reports the
+ name of the current output file.
+
+2 Qualifiers
+/F[ILE]
+ /F[ILE]=file
+ Specifies the file to open.
+
+1 OVERWRITE
+ OV[ERWRITE]
+ The OVERWRITE command overwrites the specified string onto the given
+ offset in the current block. Use extreme caution when using this
+ command.
+
+ The format of the OVERWRITE command is:
+
+ OV[ERWRITE] /D[ATA]=string
+ /O[FFSET]=offset
+
+2 Qualifiers
+/D[ATA]
+ /D[ATA]=string
+ Specifies the data to be written. Use quotes around string and
+ escape codes of the form \a or \ab, where a and b are
+ hexadecimal digits, for non-printing characters. \\ translates
+ to a single backslash.
+
+/O[FFSET]
+ /O[FFSET]=offset
+ Specifies the offset in the current block where the overwrite
+ should begin.
+
+1 PAGE
+ P[AGE]
+ The PAGE command sends one form feed to the output device. Use PAGE to
+ add form feeds to a dump file, making the hardcopy file easier to
+ read. If you plan to use the dump file with MUPIP LOAD, do not use
+ PAGE.
+
+ The format of the PAGE command is:
+
+ P[AGE]
+
+ The PAGE command has no qualifiers.
+
+1 RANGE
+ RA[NGE]
+ The RANGE command finds all blocks in the database whose first key
+ falls in the specified range of keys. The RANGE command may take a
+ very long time unless the range specified by /FROM and /TO is close
+ together. Use FIND /KEY first to determine whether the key appears in
+ the tree.
+
+ The format of the RANGE command is:
+
+ RA[NGE] /F[ROM]=block
+ /T[O]=block
+ /L[OWER]=key
+ /U[PPER]=key
+
+2 Qualifiers
+/FROM
+ /F[ROM]=block_number
+ Specifies a starting block number for the range search.
+
+ By default, RANGE starts processing at the beginning of the
+ file.
+
+/TO
+ /T[O]=block_number
+ Specifies an ending block number for the range search.
+
+ By default, RANGE stops processing at the end of the file.
+
+/LOWER
+ /L[OWER]=key
+ Specifies the lower bound for the key range.
+
+/UPPER
+ /U[PPER]=key
+ Specifies the upper bound for the key range.
+
+1 REMOVE
+ REM[OVE]
+ The REMOVE command removes one or more records or a save buffer.
+
+ The format of the REMOVE command is:
+
+ REM[OVE] /B[LOCK]=block_number
+ /C[OUNT]=count
+ /O[FFSET]
+ /R[ECORD]=record_number
+ /V[ERSION]=version_number
+
+ The version number is specified in decimal.
+
+2 Qualifiers
+/BLOCK
+ /B[LOCK]=block_number
+ Specifies the block associated with the record or buffer being
+ deleted.
+
+ On commands with no /BLOCK= qualifier, DSE uses the last block
+ handled by a DSE operation. In this case, when no block has been
+ accessed, .i.e., on the first block oriented command, DSE uses
+ block one (1).
+
+/COUNT
+ /C[OUNT]=count
+ Specifies the number of records to remove. The /COUNT qualifier
+ is incompatible with the /VERSION qualifier.
+
+ By default, REMOVE deletes a single record.
+
+/OFFSET
+ /O[FFSET]=offset
+ Specifies the offset of the record to remove. The /OFFSET
+ qualifier is incompatible with the /RECORD and /VERSION
+ qualifiers.
+
+/RECORD
+ /R[ECORD]=record_number
+ Specifies the record number of the record to remove. The /RECORD
+ qualifier is incompatible with the /OFFSET and /VERSION
+ qualifiers.
+
+/VERSION
+ /V[ERSION]=version_number
+ Specifies the decimal version number in decimal of the save
+ buffer to remove. /VERSION is required to REMOVE a SAVE buffer.
+ /VERSION is incompatible with all qualifiers except /BLOCK.
+
+1 RESTORE
+ RES[TORE]
+ The RESTORE command restores saved versions of blocks.
+
+ The format of the RESTORE command is:
+
+ RES[TORE] /B[LOCK]=block_number
+ /F[ROM]=from
+ /R[EGION]=region
+ /V[ERSION]=version_number
+
+ The version number is specified in decimal.
+
+2 Qualifiers
+/BLOCK
+ /B[LOCK]=block_number
+ Specifies the block to restore.
+
+ On commands with no /BLOCK= qualifier, DSE uses the last block
+ handled by a DSE operation. In this case, when no block has been
+ accessed, .i.e., on the first block oriented command, DSE uses
+ block one (1).
+
+/FROM
+ /F[ROM]=block_number
+ Specifies the block number of the save buffer to restore.
+
+ By default, RESTORE uses the target block number as the SAVE
+ block number.
+
+/REGION
+ /R[EGION]=region_number
+ Specifies the region of the saved buffer to restore.
+
+ By default, RESTORE uses SAVE buffers from the current region.
+
+/VERSION
+ /V[ERSION]=version_number
+ Specifies the decimal version number of the block to restore.
+ The version number is required.
+
+1 SAVE
+ SA[VE]
+ The SAVE command saves versions of blocks or displays a listing of
+ saved versions. Saved information is lost when DSE EXITs. Use with the
+ RESTORE command to move blocks. As a safety feature, use SAVE to
+ retain fallback copies of database blocks before changing them.
+
+ The format of the SAVE command is:
+
+ SA[VE] /B[LOCK]=block_number
+ /C[OMMENT]=string
+ /L[IST]
+
+2 Qualifiers
+/BLOCK
+ /B[LOCK]=block_number
+ Specifies the block to save.
+
+ On commands with no /BLOCK= qualifier, DSE uses the last block
+ handled by a DSE operation. In this case, when no block has been
+ accessed, .i.e., on the first block-oriented command, DSE uses
+ block one (1).
+
+/COMMENT
+ /C[OMMENT]=string
+ Specifies a comment to save with the block. Enclose the comment
+ in quotes (""). The /COMMENT qualifier is incompatible with the
+ /LIST qualifier.
+
+/LIST
+ /L[IST]
+ Lists saved versions of specified blocks. The /LIST qualifier is
+ incompatible with the /COMMENT qualifier.
+
+ By default, SAVE /LIST provides a directory of all SAVEd blocks.
+
+1 SHIFT
+ SH[IFT]
+ The SHIFT command shifts data in a block, filling the block with zeros
+ or shortening the block. The format of the SHIFT command is:
+
+ SH[IFT] /B[ACKWARD]=shift
+ /F[ORWARD]=shift
+ /O[FFSET]=offset
+
+2 Qualifiers
+/BACKWARD
+ /B[ACKWARD]=shift
+ Specifies the extent to which DSE should shift data backwards
+ towards the block header. The /BACKWARD qualifier is
+ incompatible with the /FORWARD qualifier.
+
+/FORWARD
+ /F[ORWARD]=shift
+ Specifies the extent to which DSE should shift data forward
+ towards the end of the block. The /FORWARD qualifier is
+ incompatible with the /BACKWARD qualifier.
+
+/OFFSET
+ /O[FFSET]=offset
+ Specifies the starting offset of the portion of the block to
+ shift.
+
+1 SPAWN
+ SP[AWN]
+ The SPAWN command creates a subprocess for access to the VMS Command
+ Language Interpreter (CLI), usually DCL, without terminating the
+ current DSE environment. Use the SPAWN command to suspend a session
+ and issue DCL commands such as MUPIP INTEG /REGION or GDE. The SPAWN
+ command spawns a subprocess with an optional command string. A SPAWN
+ with no command string parameter leaves your terminal at the input
+ prompt of the CLI of the spawned process.
+
+ The format of the SPAWN command is:
+
+ SP[AWN] [command]
+
+ The SPAWN command has no qualifiers.
+
+1 WCINIT
+ W[CINIT]
+ The WCINIT command reinitializes the global buffers of the current
+ region. Because it cleans out the cache, WCINIT is a very dangerous
+ command and therefore should not be used except under Greystone
+ supervision.
+
+ WARNING: A WCINIT command issued while normal database operations are
+ in progress can cause catastrophic damage to the database.
+
+ The format of the WCINIT command is:
+
+ W[CINIT]
+
+ The WCINIT command has no qualifiers.
+
+ When you issue the WCINIT command, DSE issues the CONFIRMATION:
+ prompt. You must verify the WCINIT command by responding with a "YES."
+
+ If you do not confirm the WCINIT, DSE issues the message:
+
+ No action taken, enter yes at the CONFIRMATION prompt to initialize
+ global buffers.
+
+
diff --git a/sr_vvms/dse_cmd.cld b/sr_vvms/dse_cmd.cld
new file mode 100644
index 0000000..0a45c36
--- /dev/null
+++ b/sr_vvms/dse_cmd.cld
@@ -0,0 +1,353 @@
+MODULE DSE_CMD
+
+DEFINE VERB add
+ ROUTINE dse_adrec
+ QUALIFIER block NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER data NONNEGATABLE VALUE(TYPE=$QUOTED_STRING,REQUIRED)
+ QUALIFIER key NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER offset NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER pointer NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER record NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER star SYNTAX=AD_STAR_SYN NONNEGATABLE
+
+ DISALLOW STAR AND (DATA OR KEY OR RECORD OR OFFSET) OR DATA AND POINTER OR RECORD AND OFFSET
+
+DEFINE SYNTAX AD_STAR_SYN
+ ROUTINE dse_adstar
+
+DEFINE VERB all
+ ROUTINE dse_all
+ QUALIFIER all NONNEGATABLE
+ QUALIFIER buffer_flush NONNEGATABLE
+ QUALIFIER critinit NONNEGATABLE
+ QUALIFIER dump NONNEGATABLE
+ QUALIFIER freeze NEGATABLE
+ QUALIFIER override NONNEGATABLE
+ QUALIFIER reference NONNEGATABLE
+ QUALIFIER release NONNEGATABLE
+ QUALIFIER renew SYNTAX = ALL_CONFIRM_SYNTAX NONNEGATABLE
+ QUALIFIER seize NONNEGATABLE
+ QUALIFIER wcinit SYNTAX = ALL_CONFIRM_SYNTAX NONNEGATABLE
+
+ DISALLOW (WCINIT AND BUFFER_FLUSH)
+ DISALLOW (RENEW AND (FREEZE OR SEIZE OR RELEASE OR CRITINIT OR BUFFER_FLUSH OR REFERENCE OR WCINIT OR OVERRIDE))
+ DISALLOW (SEIZE AND RELEASE) OR (CRITINIT AND (SEIZE OR RELEASE))
+ DISALLOW (DUMP AND (BUFFER_FLUSH OR CRITINIT OR FREEZE OR OVERRIDE OR REFERENCE OR RELEASE OR RENEW OR SEIZE OR WCINIT ))
+ DISALLOW ALL AND NOT DUMP
+
+DEFINE SYNTAX ALL_CONFIRM_SYNTAX
+ ROUTINE dse_all
+ PARAMETER P1, LABEL=CONFIRMATION, VALUE(REQUIRED)
+
+DEFINE VERB buffer_flush
+ ROUTINE dse_flush
+
+DEFINE VERB cache
+ ROUTINE dse_cache
+ QUALIFIER all NONNEGATABLE
+ QUALIFIER change NONNEGATABLE
+ QUALIFIER crit NEGATABLE
+ QUALIFIER offset NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER recover NONNEGATABLE
+ QUALIFIER show NONNEGATABLE
+ QUALIFIER size NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER value NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER verify NONNEGATABLE
+
+ DISALLOW NOT (CHANGE OR RECOVER OR SHOW OR VERIFY)
+ DISALLOW ANY2(CHANGE,RECOVER,SHOW,VERIFY)
+ DISALLOW ALL AND CHANGE
+ DISALLOW NOT (CHANGE OR SHOW) AND (OFFSET OR SIZE OR VALUE)
+ DISALLOW SHOW AND VALUE
+ DISALLOW CHANGE AND NOT OFFSET
+ DISALLOW OFFSET AND NOT SIZE
+ DISALLOW SIZE AND NOT OFFSET
+ DISALLOW VALUE AND NOT OFFSET
+ DISALLOW NEG CRIT AND (CHANGE OR RECOVER OR VERIFY)
+
+DEFINE VERB change
+ QUALIFIER fileheader SYNTAX = CHANGE_FH_SYNTAX
+ QUALIFIER block NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER bsiz SYNTAX=CHANGE_BH_SYN NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER cmpc SYNTAX=CHANGE_RH_SYN NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER level SYNTAX=CHANGE_BH_SYN NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER offset SYNTAX=CHANGE_RH_SYN NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER record SYNTAX=CHANGE_RH_SYN NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER rsiz SYNTAX=CHANGE_RH_SYN NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER tn SYNTAX=CHANGE_BH_SYN NONNEGATABLE VALUE(DEFAULT = "FFFFFFFFFFFFFFFF")
+
+ DISALLOW (fileheader AND (BLOCK OR LEVEL OR BSIZ OR RECORD OR OFFSET OR CMPC OR RSIZ OR TN)) OR
+ ((LEVEL OR BSIZ OR TN) AND (RECORD OR OFFSET OR CMPC OR RSIZ)) OR
+ (RECORD AND OFFSET)
+
+DEFINE SYNTAX CHANGE_FH_SYNTAX
+ ROUTINE dse_chng_fhead
+ QUALIFIER abandoned_kills NONNEGATABLE VALUE(TYPE = $NUMBER, REQUIRED)
+ QUALIFIER avg_blks_read NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER blks_to_upgrade NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER blk_size NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER b_bytestream NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER b_comprehensive NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER b_database NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER b_incremental NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER b_record NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER blocks_free NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER cert_db_ver NONNEGATABLE VALUE(REQUIRED,TYPE=DB_VERS)
+ QUALIFIER corrupt_file VALUE(TYPE=TRUE_FALSE_NOCHANGE), DEFAULT
+ QUALIFIER crit NEGATABLE
+ QUALIFIER current_tn NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER db_write_fmt NONNEGATABLE VALUE(REQUIRED,TYPE=DB_VERS)
+ QUALIFIER declocation NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER decvalue NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER def_collation NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER flush_time NONNEGATABLE VALUE(TYPE = $DELTATIME)
+ QUALIFIER freeze VALUE(TYPE=TRUE_FALSE_NOCHANGE), DEFAULT
+ QUALIFIER fully_upgraded NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER got2v5once NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER gvstatsreset NONNEGATABLE
+ QUALIFIER hard_spin_count NONNEGATABLE VALUE(TYPE = $NUMBER, REQUIRED)
+ QUALIFIER hexlocation NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER hexvalue NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER inhibit_kills NONNEGATABLE VALUE(TYPE = $NUMBER, REQUIRED)
+ QUALIFIER interrupted_recov VALUE(TYPE=TRUE_FALSE_NOCHANGE), DEFAULT
+ QUALIFIER jnl_cache VALUE(TYPE=TRUE_FALSE_NOCHANGE), DEFAULT
+ QUALIFIER key_max_size NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER kill_in_prog NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER location NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER machine_name NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER max_tn NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER mbm_size NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER null_subscripts VALUE(TYPE=NEVER_ALWAYS_ALLOWEXISTING), DEFAULT
+ QUALIFIER online_nbb NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER override NONNEGATABLE
+ QUALIFIER pre_read_trigger_factor NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER quantum_interval NONNEGATABLE VALUE(TYPE = $DELTATIME)
+ QUALIFIER rc_srv_count NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER record_max_size NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER reference_count NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER reg_seqno NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER reserved_bytes NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER resync_seqno NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER resync_tn NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER response_interval NEGATABLE VALUE(TYPE = $DELTATIME)
+ QUALIFIER size NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER sleep_spin_count NONNEGATABLE VALUE(TYPE = $NUMBER, REQUIRED)
+ QUALIFIER spin_sleep_time NONNEGATABLE VALUE(TYPE = $NUMBER, REQUIRED)
+ QUALIFIER staleness_timer NEGATABLE VALUE(TYPE = $DELTATIME)
+ QUALIFIER stdnullcoll VALUE(TYPE=TRUE_FALSE_NOCHANGE), DEFAULT
+ QUALIFIER tick_interval NONNEGATABLE VALUE(TYPE = $DELTATIME)
+ QUALIFIER timers_pending NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER total_blks NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER trigger_flush NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER upd_reserved_area NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER upd_writer_trigger_factor NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER value NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER wait_disk NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER warn_max_tn NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER writes_per_flush NONNEGATABLE VALUE(REQUIRED)
+
+DEFINE TYPE DB_VERS
+ KEYWORD V4
+ KEYWORD V6
+
+DEFINE TYPE TRUE_FALSE_NOCHANGE
+ KEYWORD TRUE
+ KEYWORD FALSE
+ KEYWORD NOCHANGE, DEFAULT
+
+DEFINE TYPE NEVER_ALWAYS_ALLOWEXISTING
+ KEYWORD ALWAYS
+ KEYWORD EXISTING
+ KEYWORD FALSE
+ KEYWORD NEVER
+ KEYWORD TRUE
+ KEYWORD NOCHANGE, DEFAULT
+
+DEFINE SYNTAX CHANGE_BH_SYN
+ ROUTINE dse_chng_bhead
+
+DEFINE SYNTAX CHANGE_RH_SYN
+ ROUTINE dse_chng_rhead
+
+DEFINE VERB close
+ ROUTINE dse_close
+
+DEFINE VERB critical
+ ROUTINE dse_crit
+ QUALIFIER all NONNEGATABLE
+ QUALIFIER crash NONNEGATABLE
+ QUALIFIER cycle NONNEGATABLE
+ QUALIFIER init NONNEGATABLE
+ QUALIFIER owner NONNEGATABLE
+ QUALIFIER release NONNEGATABLE
+ QUALIFIER remove NONNEGATABLE
+ QUALIFIER reset NONNEGATABLE
+ QUALIFIER seize NONNEGATABLE
+
+ DISALLOW ANY2(INIT,OWNER,SEIZE,RELEASE,REMOVE)
+ DISALLOW CRASH AND (SEIZE OR RELEASE OR OWNER OR RESET)
+ DISALLOW RESET AND (SEIZE OR RELEASE OR OWNER)
+ DISALLOW CYCLE AND (INIT OR REMOVE OR SEIZE OR RELEASE OR RESET)
+ DISALLOW ALL AND (CRASH OR CYCLE OR INIT OR OWNER OR RELEASE OR REMOVE OR RESET OR SEIZE)
+
+DEFINE VERB dump
+ ROUTINE dse_dmp
+ QUALIFIER block NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER count VALUE(REQUIRED)
+ QUALIFIER crit NEGATABLE
+ QUALIFIER fileheader SYNTAX=FILE_HEAD_SYN NONNEGATABLE
+ QUALIFIER glo NONNEGATABLE
+ QUALIFIER header NEGATABLE
+ QUALIFIER offset NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER record NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER zwr NONNEGATABLE
+
+ DISALLOW ANY2(RECORD,OFFSET,FILEHEADER) OR FILEHEADER AND (BLOCK OR HEADER OR COUNT OR GLO OR ZWR) OR GLO AND ZWR
+ OR GLO AND HEADER OR ZWR AND HEADER OR COUNT AND NOT HEADER AND NOT (RECORD OR OFFSET) AND NOT BLOCK
+
+DEFINE SYNTAX FILE_HEAD_SYN
+ ROUTINE dse_dmp_fhead
+ QUALIFIER all NONNEGATABLE
+ QUALIFIER backup NEGATABLE
+ QUALIFIER basic NEGATABLE
+ QUALIFIER bg_trc NEGATABLE
+ QUALIFIER db_csh NEGATABLE
+ QUALIFIER environment NEGATABLE
+ QUALIFIER gvstats NEGATABLE
+ QUALIFIER journal NEGATABLE
+ QUALIFIER mixedmode NEGATABLE
+ QUALIFIER retries NEGATABLE
+ QUALIFIER tpblkmod NEGATABLE
+ QUALIFIER tpretries NEGATABLE
+ QUALIFIER updproc NEGATABLE
+
+DEFINE VERB evaluate
+ ROUTINE dse_eval
+ QUALIFIER decimal NONNEGATABLE
+ QUALIFIER hexadecimal NONNEGATABLE
+ QUALIFIER number NONNEGATABLE VALUE(REQUIRED)
+
+DEFINE VERB exit
+ ROUTINE dse_exit
+
+DEFINE VERB find
+ ROUTINE dse_f_blk
+ QUALIFIER block NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER crit NEGATABLE
+ QUALIFIER exhaustive NONNEGATABLE
+ QUALIFIER freeblock SYNTAX=FIND_FREE_SYN NONNEGATABLE
+ QUALIFIER hint NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER key SYNTAX=FIND_KEY_SYN NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER region SYNTAX=FIND_REG_SYN NONNEGATABLE VALUE(DEFAULT="*")
+ QUALIFIER siblings NONNEGATABLE
+
+ DISALLOW ANY2(BLOCK,FREEBLOCK,KEY,REGION)
+ DISALLOW (EXHAUSTIVE OR SIBLINGS) AND (FREEBLOCK OR KEY OR REGION)
+ DISALLOW HINT AND NOT FREEBLOCK
+ DISALLOW FREEBLOCK AND NOT HINT
+
+DEFINE SYNTAX FIND_KEY_SYN
+ ROUTINE dse_f_key
+
+DEFINE SYNTAX FIND_FREE_SYN
+ ROUTINE dse_f_free
+
+DEFINE SYNTAX FIND_REG_SYN
+ ROUTINE dse_f_reg
+
+DEFINE VERB help
+ ROUTINE dse_help
+ PARAMETER P1, LABEL=QUERY
+
+DEFINE VERB integrit
+ ROUTINE dse_integ
+ QUALIFIER block NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER crit NEGATABLE
+
+DEFINE VERB maps
+ ROUTINE dse_maps
+ QUALIFIER block NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER busy NONNEGATABLE
+ QUALIFIER free NONNEGATABLE
+ QUALIFIER master NONNEGATABLE
+ QUALIFIER restore_all NONNEGATABLE
+
+ DISALLOW ANY2(FREE,BUSY,MASTER,RESTORE_ALL) OR (BLOCK AND RESTORE_ALL)
+
+DEFINE VERB open
+ ROUTINE dse_open
+ QUALIFIER file NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER ochset NONNEGATABLE VALUE(TYPE=$QUOTED_STRING,REQUIRED)
+
+DEFINE VERB overwrite
+ ROUTINE dse_over
+ QUALIFIER block NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER data NONNEGATABLE VALUE(TYPE=$QUOTED_STRING,REQUIRED)
+ QUALIFIER offset NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER ochset NONNEGATABLE VALUE(REQUIRED, TYPE=$NUMBER)
+
+DEFINE VERB page
+ ROUTINE dse_page
+
+DEFINE VERB quit
+ ROUTINE dse_exit
+
+DEFINE VERB range
+ ROUTINE dse_range
+ QUALIFIER busy NEGATABLE
+ QUALIFIER crit NEGATABLE
+ QUALIFIER from NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER index NONNEGATABLE
+ QUALIFIER lost NONNEGATABLE
+ QUALIFIER lower NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER star NONNEGATABLE
+ QUALIFIER to NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER upper NONNEGATABLE VALUE(REQUIRED)
+
+DEFINE VERB remove
+ ROUTINE dse_rmsb
+ QUALIFIER block NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER count VALUE(REQUIRED)
+ QUALIFIER offset SYNTAX=REC_REMO_SYN NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER record SYNTAX=REC_REMO_SYN NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER version NONNEGATABLE VALUE(REQUIRED)
+
+ DISALLOW ANY2(RECORD,OFFSET,VERSION) OR VERSION AND COUNT
+
+DEFINE SYNTAX REC_REMO_SYN
+ ROUTINE dse_rmrec
+
+DEFINE VERB restore
+ ROUTINE dse_rest
+ QUALIFIER block NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER from NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER region NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER version NONNEGATABLE VALUE(REQUIRED)
+
+DEFINE VERB save
+ ROUTINE dse_save
+ QUALIFIER block NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER comment NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER crit NEGATABLE
+ QUALIFIER list NONNEGATABLE
+
+ DISALLOW LIST AND COMMENT
+
+DEFINE VERB shift
+ ROUTINE dse_shift
+ QUALIFIER backward NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER forward NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER offset NONNEGATABLE VALUE(REQUIRED)
+
+ DISALLOW FORWARD AND BACKWARD
+
+DEFINE VERB spawn
+ ROUTINE util_spawn
+ PARAMETER P1, LABEL=COMMAND, VALUE(DEFAULT="")
+
+DEFINE VERB version
+ ROUTINE dse_version
+
+DEFINE VERB wcinit
+ ROUTINE dse_wcreinit
+ PARAMETER P1, LABEL=CONFIRMATION, VALUE(REQUIRED)
diff --git a/sr_vvms/dse_ctrlc_setup.c b/sr_vvms/dse_ctrlc_setup.c
new file mode 100644
index 0000000..28200ef
--- /dev/null
+++ b/sr_vvms/dse_ctrlc_setup.c
@@ -0,0 +1,65 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* chtest.c
+/*
+ */
+
+#include "mdef.h"
+#include "io.h"
+#include "iottdef.h"
+#include <iodef.h>
+#include <dvidef.h>
+#include <dcdef.h>
+#include <ssdef.h>
+#include <descrip.h>
+#include <chfdef.h>
+#include <efndef.h>
+#include <signal.h>
+
+GBLREF VSIG_ATOMIC_T util_interrupt;
+
+#define OUTOFBAND_MSK 0x02000008
+
+void intr_handler(void)
+{
+ util_interrupt = 1;
+}
+
+void dse_ctrlc_setup(void)
+{ int4 status, channel, item_code, event;
+ uint4 devclass;
+ io_terminator outofband_msk;
+ $DESCRIPTOR(sys_input,"SYS$INPUT");
+
+ if ((status = sys$assign(&sys_input,&channel,0,0)) != SS$_NORMAL)
+ lib$signal(status);
+ item_code = DVI$_DEVCLASS;
+ lib$getdvi(&item_code, &channel, 0, &devclass, 0, 0);
+ if (devclass == DC$_TERM)
+ {
+ outofband_msk.x = 0;
+ outofband_msk.mask = OUTOFBAND_MSK;
+ if ((status = sys$qiow(EFN$C_ENF,channel
+ ,(IO$_SETMODE | IO$M_OUTBAND | IO$M_TT_ABORT)
+ ,0 ,0 ,0
+ ,intr_handler
+ ,&outofband_msk
+ ,0 ,0 ,0 ,0 )) != SS$_NORMAL)
+ { lib$signal(status);
+ }
+ }
+ util_interrupt = 0;
+ return;
+}
+
+
+
diff --git a/sr_vvms/dse_help.c b/sr_vvms/dse_help.c
new file mode 100644
index 0000000..8d7e0fa
--- /dev/null
+++ b/sr_vvms/dse_help.c
@@ -0,0 +1,66 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "release_name.h"
+#include <ssdef.h>
+#include <climsgdef.h>
+#include <descrip.h>
+#include "util.h"
+#include "dse.h"
+
+#define HLP$M_PROMPT 1
+#define HELP_LIBRARY "GTM$HELP:DSE"
+
+void dse_help(void)
+{
+
+ uint4 flags;
+ char buff[256];
+ $DESCRIPTOR(line, buff);
+ $DESCRIPTOR(libr, HELP_LIBRARY);
+ $DESCRIPTOR(ent, "QUERY");
+
+ if (CLI$PRESENT(&ent) != CLI$_PRESENT || CLI$GET_VALUE(&ent,&line) != SS$_NORMAL)
+ line.dsc$w_length = 0;
+ flags = HLP$M_PROMPT;
+ lbr$output_help(lib$put_output,0,&line,&libr,&flags,lib$get_input);
+ return;
+
+}
+
+void dse_version(void)
+{
+ /*
+ * The following assumptions have been made in this function
+ * 1. GTM_RELEASE_NAME is of the form "GTM_PRODUCT VERSION THEREST"
+ * (Refer file release_name.h)
+ * 2. A single blank separates GTM_PRODUCT and VERSION
+ * 3. If THEREST exists, it is separated from VERSION by atleast
+ * one blank
+ */
+ char gtm_rel_name[] = GTM_RELEASE_NAME;
+ char dse_rel_name[SIZEOF(GTM_RELEASE_NAME) - SIZEOF(GTM_PRODUCT)];
+ int dse_rel_name_len;
+ char *cptr;
+
+ for (cptr = gtm_rel_name + SIZEOF(GTM_PRODUCT), dse_rel_name_len = 0;
+ *cptr != ' ' && *cptr != '\0';
+ dse_rel_name[dse_rel_name_len++] = *cptr++);
+ dse_rel_name[dse_rel_name_len] = '\0';
+ util_out_print("!AD", TRUE, dse_rel_name_len, dse_rel_name);
+ return;
+}
diff --git a/sr_vvms/dse_open.c b/sr_vvms/dse_open.c
new file mode 100644
index 0000000..417ed73
--- /dev/null
+++ b/sr_vvms/dse_open.c
@@ -0,0 +1,184 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include <rms.h>
+#include <ssdef.h>
+#include <descrip.h>
+#include <climsgdef.h>
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "gdsblk.h"
+#include "cli.h"
+#include "dse.h"
+#include "util.h"
+
+#define NO_P_MSG_SIZE (SIZEOF(msg) / SIZEOF(int4) - 5)
+
+static struct FAB patch_fab;
+static struct RAB patch_rab;
+static char patch_ofile[256];
+
+GBLREF enum dse_fmt dse_dmp_format;
+
+void dse_open(void)
+{
+ $DESCRIPTOR(d_buff, patch_ofile);
+ $DESCRIPTOR(d_ent, "FILE");
+ int4 status,i;
+ struct {
+ short int arg_cnt;
+ short int def_opt;
+ int4 msg_number;
+ short int fp_cnt;
+ short new_opts;
+ int4 fp_n[4];
+ } msg;
+
+ if (cli_present("FILE") == CLI_PRESENT)
+ {
+ if (CLOSED_FMT != dse_dmp_format)
+ {
+ util_out_print("Error: output file already open.",TRUE);
+ util_out_print("Current output file: !AD", TRUE, strlen(patch_ofile), &patch_ofile[0]);
+ return;
+ }
+ if (CLI$GET_VALUE(&d_ent,&d_buff) != SS$_NORMAL)
+ return;
+ for(i = 254; patch_ofile[i] == ' ' ;i--)
+ if (i == 0)
+ {
+ util_out_print("Error: must specify a file name.",TRUE);
+ return;
+ }
+ i++;
+ patch_ofile[i] = 0;
+ patch_fab = cc$rms_fab;
+ patch_fab.fab$b_rat = FAB$M_CR;
+ patch_fab.fab$l_fna = patch_ofile;
+ patch_fab.fab$b_fns = i;
+ status = sys$create(&patch_fab);
+ switch (status )
+ {
+ case RMS$_NORMAL:
+ case RMS$_CREATED:
+ case RMS$_SUPERSEDE:
+ case RMS$_FILEPURGED:
+ break;
+ default:
+ msg.arg_cnt = NO_P_MSG_SIZE;
+ msg.new_opts = msg.def_opt = 1;
+ msg.msg_number = status;
+ msg.fp_cnt = 0;
+ sys$putmsg(&msg,0,0,0);
+ return;
+ }
+ patch_rab = cc$rms_rab;
+ patch_rab.rab$l_fab = &patch_fab;
+ status = sys$connect(&patch_rab);
+ if (status != RMS$_NORMAL)
+ {
+ msg.arg_cnt = NO_P_MSG_SIZE;
+ msg.new_opts = msg.def_opt = 1;
+ msg.msg_number = status;
+ msg.fp_cnt = 0;
+ sys$putmsg(&msg,0,0,0);
+ return;
+ }
+ dse_dmp_format = OPEN_FMT;
+ } else
+ {
+ if (CLOSED_FMT != dse_dmp_format)
+ util_out_print("Current output file: !AD", TRUE, strlen(patch_ofile), &patch_ofile[0]);
+ else
+ util_out_print("No current output file.",TRUE);
+ }
+ return;
+
+}
+
+boolean_t dse_fdmp_output(void *addr, int4 len)
+{
+ int4 status;
+ static char *buffer = NULL;
+ static int bufsiz = 0;
+
+ struct {
+ short int arg_cnt;
+ short int def_opt;
+ int4 msg_number;
+ short int fp_cnt;
+ short new_opts;
+ int4 fp_n[4];
+ } msg;
+ assert(len >= 0);
+ if (len + 1 > bufsiz)
+ {
+ if (buffer)
+ free(buffer);
+ bufsiz = len + 1;
+ buffer = (char *)malloc(bufsiz);
+ }
+ if (len)
+ {
+ memcpy(buffer, addr, len);
+ buffer[len] = 0;
+ }
+ patch_rab.rab$l_rbf = buffer;
+ patch_rab.rab$w_rsz = len;
+ status = sys$put(&patch_rab);
+ if (status != RMS$_NORMAL)
+ {
+ rts_error(VARLSTCNT(1) status);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+void dse_close(void)
+{
+ int4 status;
+ struct {
+ short int arg_cnt;
+ short int def_opt;
+ int4 msg_number;
+ short int fp_cnt;
+ short new_opts;
+ int4 fp_n[4];
+ } msg;
+
+ if (CLOSED_FMT != dse_dmp_format)
+ {
+ util_out_print("Closing output file: !AD",TRUE,LEN_AND_STR(patch_ofile));
+ status = sys$close(&patch_fab);
+ if (status != RMS$_NORMAL)
+ {
+ msg.arg_cnt = NO_P_MSG_SIZE;
+ msg.new_opts = msg.def_opt = 1;
+ msg.msg_number = status;
+ msg.fp_cnt = 0;
+ sys$putmsg(&msg,0,0,0);
+ return;
+ }
+ dse_dmp_format = CLOSED_FMT;
+ }
+ else
+ util_out_print("Error: no current output file.",TRUE);
+ return;
+}
diff --git a/sr_vvms/dse_puttime.c b/sr_vvms/dse_puttime.c
new file mode 100644
index 0000000..4012104
--- /dev/null
+++ b/sr_vvms/dse_puttime.c
@@ -0,0 +1,26 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <descrip.h>
+#include "util.h"
+#include "dse_puttime.h"
+
+void dse_puttime(int_ptr_t time, char *c, bool flush)
+{ unsigned char outbuf[12];
+ short unsigned timelen;
+ $DESCRIPTOR(time_desc,outbuf);
+
+ memset(outbuf, 0, SIZEOF(outbuf));
+ sys$asctim(&timelen, &time_desc, time, 1);
+ util_out_print(c,flush,timelen,outbuf);
+ return;
+}
diff --git a/sr_vvms/dsk_read.c b/sr_vvms/dsk_read.c
new file mode 100644
index 0000000..3fa7d74
--- /dev/null
+++ b/sr_vvms/dsk_read.c
@@ -0,0 +1,173 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <descrip.h>
+#include <iodef.h>
+#include <rms.h>
+#include <ssdef.h>
+#include "gtm_string.h"
+#ifdef DEBUG
+#include "gtm_stdio.h"
+#endif
+
+#include "cdb_sc.h"
+#include "efn.h"
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "gtm_malloc.h" /* for CHECK_CHANNEL_STATUS macro */
+#include "iosb_disk.h"
+#include "iosp.h"
+#include "gds_blk_upgrade.h"
+#include "gdsbml.h"
+#include "gtmimagename.h"
+
+GBLREF gd_region *gv_cur_region;
+GBLREF sgmnt_addrs *cs_addrs;
+GBLREF sgmnt_data_ptr_t cs_data;
+GBLREF uint4 update_trans;
+GBLREF volatile int4 fast_lock_count;
+GBLREF boolean_t dse_running;
+
+error_def(ERR_DYNUPGRDFAIL);
+
+int4 dsk_read(block_id blk, sm_uc_ptr_t buff, enum db_ver *ondsk_blkver, boolean_t blk_free)
+{
+ int4 status, size;
+ io_status_block_disk iosb;
+ enum db_ver tmp_ondskblkver;
+ sm_uc_ptr_t save_buff = NULL;
+ uint4 channel_id;
+ boolean_t fully_upgraded;
+ DEBUG_ONLY(
+ blk_hdr_ptr_t blk_hdr;
+ static int in_dsk_read;
+ )
+ /* It is possible that the block that we read in from disk is a V4 format block. The database block scanning routines
+ * (gvcst_*search*.c) that might be concurrently running currently assume all global buffers (particularly the block
+ * headers) are V5 format. They are not robust enough to handle a V4 format block. Therefore we do not want to
+ * risk reading a potential V4 format block directly into the cache and then upgrading it. Instead we read it into
+ * a private buffer, upgrade it there and then copy it over to the cache in V5 format. This is the static variable
+ * read_reformat_buffer. We could have as well used the global variable "reformat_buffer" for this purpose. But
+ * that would then prevent dsk_reads and concurrent dsk_writes from proceeding. We dont want that loss of asynchronocity.
+ * Hence we keep them separate. Note that while "reformat_buffer" is used by a lot of routines, "read_reformat_buffer"
+ * is used only by this routine and hence is a static instead of a GBLDEF.
+ */
+ static sm_uc_ptr_t read_reformat_buffer;
+ static int read_reformat_buffer_len;
+
+ assert(!blk_free); /* VMS should never try to read a FREE block from the disk */
+ assert(0 == in_dsk_read); /* dsk_read should never be nested. the read_reformat_buffer logic below relies on this */
+ DEBUG_ONLY(in_dsk_read++;)
+ assert(cs_addrs->hdr == cs_data);
+ size = cs_data->blk_size;
+ assert(cs_data->acc_meth == dba_bg);
+ /* Since cs_data->fully_upgraded is referenced more than once in this module (once explicitly and once in
+ * GDS_BLK_UPGRADE_IF_NEEDED macro used below), take a copy of it and use that so all usages see the same value.
+ * Not doing this, for example, can cause us to see the database as fully upgraded in the first check causing us
+ * not to allocate save_buff (a temporary buffer to hold a V4 format block) at all but later in the macro
+ * we might see the database as NOT fully upgraded so we might choose to call the function gds_blk_upgrade which
+ * does expect a temporary buffer to have been pre-allocated. It is ok if the value of cs_data->fully_upgraded
+ * changes after we took a copy of it since we have a buffer locked for this particular block (at least in BG)
+ * so no concurrent process could be changing the format of this block. For MM there might be an issue.
+ */
+ fully_upgraded = cs_data->fully_upgraded;
+ if (!fully_upgraded)
+ {
+ save_buff = buff;
+ if (size > read_reformat_buffer_len)
+ { /* do the same for the reformat_buffer used by dsk_read */
+ assert(0 == fast_lock_count); /* this is mainline (non-interrupt) code */
+ ++fast_lock_count; /* No interrupts in free/malloc across this change */
+ if (NULL != read_reformat_buffer)
+ free(read_reformat_buffer);
+ read_reformat_buffer = malloc(size);
+ read_reformat_buffer_len = size;
+ --fast_lock_count;
+ }
+ buff = read_reformat_buffer;
+ }
+ if (NULL != cs_addrs->nl) /* could be NULL in case of MUPIP CREATE */
+ INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_dsk_read, 1);
+ channel_id = ((vms_gds_info*)(gv_cur_region->dyn.addr->file_cntl->file_info))->fab->fab$l_stv;
+ status = sys$qiow(efn_bg_qio_read, channel_id, IO$_READVBLK, &iosb, 0, 0,
+ buff, size, (size / DISK_BLOCK_SIZE) * blk + cs_data->start_vbn, 0, 0, 0);
+ if (SS$_NORMAL != status)
+ {
+ DEBUG_ONLY(in_dsk_read--;)
+ assert(FALSE);
+ CHECK_CHANNEL_STATUS(status, channel_id);
+ return status;
+ }
+ status = iosb.cond;
+ if (SS$_NORMAL != status)
+ {
+ DEBUG_ONLY(in_dsk_read--;)
+ assert(FALSE);
+ return status;
+ }
+ assert(0 == (long)buff % 2);
+ /* GDSV4 (0) version uses "buff->bver" as a block length so should always be > 0 when M code is running.
+ * The only exception is if the block has not been initialized (possible if it is BLK_FREE status in the
+ * bitmap). This is possible due to concurrency issues while traversing down the tree. But if we have
+ * crit on this region, we should not see these either. Assert accordingly.
+ */
+ assert(!IS_MCODE_RUNNING || !cs_addrs->now_crit || ((blk_hdr_ptr_t)buff)->bver);
+ /* Block must be converted to current version (if necessary) for use by internals.
+ * By definition, all blocks are converted from/to their on-disk version at the IO point.
+ */
+ GDS_BLK_UPGRADE_IF_NEEDED(blk, buff, save_buff, cs_data, &tmp_ondskblkver, status, fully_upgraded);
+ DEBUG_DYNGRD_ONLY(
+ if (GDSVCURR != tmp_ondskblkver)
+ PRINTF("DSK_READ: Block %d being dynamically upgraded on read\n", blk);
+ )
+ assert((GDSV6 == tmp_ondskblkver) || (NULL != save_buff)); /* never read a V4 block directly into cache */
+ if (NULL != ondsk_blkver)
+ *ondsk_blkver = tmp_ondskblkver;
+ /* a bitmap block should never be short of space for a dynamic upgrade. assert that. */
+ assert((NULL == ondsk_blkver) || !IS_BITMAP_BLK(blk) || (ERR_DYNUPGRDFAIL != status));
+ /* If we didn't run gds_blk_upgrade which would move the block into the cache, we need to do
+ * it ourselves. Note that buff will be cleared by the GDS_BLK_UPGRADE_IF_NEEDED macro if
+ * buff and save_buff are different and gds_blk_upgrade was called.
+ */
+ if ((NULL != save_buff) && (NULL != buff)) /* Buffer not moved by upgrade, we must move */
+ memcpy(save_buff, buff, size);
+ DEBUG_ONLY(
+ in_dsk_read--;
+ if (cs_addrs->now_crit && !dse_running)
+ { /* 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.
+ */
+ blk_hdr = (NULL != save_buff) ? (blk_hdr_ptr_t)save_buff : (blk_hdr_ptr_t)buff;
+ GDS_BLK_HDR_CHECK(cs_data, blk_hdr, fully_upgraded);
+ }
+ )
+ if (cs_data->clustered && !cs_addrs->now_crit && ((blk_hdr_ptr_t)buff)->tn > cs_addrs->ti->curr_tn)
+ { /* a future read */
+ /* Note !! This clustering code is currently dead as no clustering product currently exists. Should
+ it be resurrected, the test above needs some work as "buff" can be zeroed at this point (even though
+ it is unlikely we would ever support the headache of auto-upgrade in a clustered environment).
+ */
+ assert(FALSE); /* update_trans is relied upon by t_end/tp_tend currently and it is not clear
+ * if setting it to TRUE here is ok. since this is clustering code and is not
+ * currently supported, an assert is added to revisit this once clustering is enabled.
+ */
+ update_trans = UPDTRNS_DB_UPDATED_MASK;
+ return FUTURE_READ;
+ }
+ return status;
+}
diff --git a/sr_vvms/dsk_write.c b/sr_vvms/dsk_write.c
new file mode 100644
index 0000000..6c8001e
--- /dev/null
+++ b/sr_vvms/dsk_write.c
@@ -0,0 +1,184 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <rms.h>
+#ifdef DEBUG
+#include "gtm_stdio.h"
+#endif
+
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsbgtr.h"
+#include "gdsfhead.h"
+#include <iodef.h>
+#include "efn.h"
+#include <ssdef.h>
+#include "iosb_disk.h"
+#include "iosp.h"
+#include "shmpool.h"
+#include "filestruct.h"
+#include "gtm_malloc.h" /* for CHECK_CHANNEL_STATUS macro */
+#include "memcoherency.h"
+#include "gds_blk_downgrade.h"
+#include "gdsbml.h"
+
+/***********************************************************************************
+ * WARNING: This routine does not manage the number of outstanding AST available.
+ * The calling routine is responsible for that.
+ ***********************************************************************************/
+
+GBLREF sm_uc_ptr_t reformat_buffer;
+GBLREF int reformat_buffer_len;
+GBLREF volatile int reformat_buffer_in_use; /* used only in DEBUG mode */
+GBLREF volatile int4 fast_lock_count;
+GBLREF boolean_t dse_running;
+
+int4 dsk_write(gd_region *reg, block_id blk, cache_rec_ptr_t cr, void (*ast_rtn)(), int4 ast_param, io_status_block_disk *iosb)
+{
+ int4 size, status;
+ sgmnt_addrs *csa;
+ sgmnt_data_ptr_t csd;
+ shmpool_blk_hdr_ptr_t sblkh_p;
+ boolean_t asyncIO;
+ sm_uc_ptr_t buff;
+ uint4 channel_id;
+ DEBUG_ONLY(
+ boolean_t reformat;
+ blk_hdr_ptr_t blk_hdr;
+ )
+
+ csa = &((vms_gds_info*)(reg->dyn.addr->file_cntl->file_info))->s_addrs;
+ csd = csa->hdr;
+ assert(NULL != csd);
+ assert(cr);
+ assert(cr->buffaddr);
+ assert(blk == cr->blk);
+ buff = GDS_ANY_REL2ABS(csa, cr->buffaddr);
+ DEBUG_ONLY(
+ /* Check GDS block that is about to be written. Dont do this for DSE as it may intentionally create bad blocks */
+ if (!dse_running)
+ {
+ blk_hdr = (blk_hdr_ptr_t)buff;
+ assert((unsigned)GDSVLAST > (unsigned)blk_hdr->bver);
+ assert((LCL_MAP_LEVL == blk_hdr->levl) || ((unsigned)MAX_BT_DEPTH > (unsigned)blk_hdr->levl));
+ assert((unsigned)csd->blk_size >= (unsigned)blk_hdr->bsiz);
+ assert(csd->trans_hist.curr_tn >= blk_hdr->tn);
+ }
+ )
+ assert(((blk_hdr_ptr_t)buff)->bver); /* GDSV4 (0) version uses this field as a block length so should always be > 0 */
+ asyncIO = TRUE;
+ DEBUG_ONLY(reformat = FALSE);
+ if (IS_GDS_BLK_DOWNGRADE_NEEDED(cr->ondsk_blkver))
+ { /* Need to downgrade/reformat this block back to a previous format.
+ * Ask for a buffer from our shared memory pool buffer manager.
+ */
+ DEBUG_ONLY(reformat = TRUE);
+ sblkh_p = shmpool_blk_alloc(reg, SHMBLK_REFORMAT);
+ if ((shmpool_blk_hdr_ptr_t)-1 == sblkh_p)
+ { /* We weren't able to get a reformat block from the pool for async IO
+ use so we will have to make do with a static buffer and a synchronous IO.
+ */
+ DEBUG_DYNGRD_ONLY(PRINTF("DSK_WRITE: Block %d being dynamically downgraded on write (syncIO)\n", blk));
+ asyncIO = FALSE;
+ assert(0 <= fast_lock_count);
+ ++fast_lock_count; /* Prevents interrupt from using reformat buffer while we have it */
+ /* reformat_buffer_in_use should always be incremented only AFTER incrementing fast_lock_count
+ * as it is the latter that prevents interrupts from using the reformat buffer. Similarly
+ * the decrement of fast_lock_count should be done AFTER decrementing reformat_buffer_in_use.
+ */
+ assert(0 == reformat_buffer_in_use);
+ DEBUG_ONLY(reformat_buffer_in_use++;)
+ if (csd->blk_size > reformat_buffer_len)
+ { /* Buffer not big enough (or does not exist) .. get a new one releasing old if it exists */
+ if (reformat_buffer)
+ free(reformat_buffer);
+ reformat_buffer = malloc(csd->blk_size);
+ reformat_buffer_len = csd->blk_size;
+ }
+ gds_blk_downgrade((v15_blk_hdr_ptr_t)reformat_buffer, (blk_hdr_ptr_t)buff);
+ buff = reformat_buffer;
+ BG_TRACE_PRO_ANY(csa, dwngrd_refmts_syncio);
+ } else
+ { /* We have a reformat buffer. Make the necessary attachments, and mark it valid */
+ DEBUG_DYNGRD_ONLY(PRINTF("DSK_WRITE: Block %d being dynamically downgraded on write (asyncIO)\n", blk));
+ /* note (sblkh_p + 1) is shorthand to address data portion of blk following header */
+ gds_blk_downgrade((v15_blk_hdr_ptr_t)(sblkh_p + 1), (blk_hdr_ptr_t)buff);
+ buff = (v15_blk_hdr_ptr_t)(sblkh_p + 1);
+ sblkh_p->use.rfrmt.cr_off = GDS_ANY_ABS2REL(csa, cr);
+ sblkh_p->use.rfrmt.cycle = cr->cycle;
+ sblkh_p->blkid = blk;
+ /* Note that this is updating this offset field in the cache record outside of crit but since this
+ field is not govered by crit, this should not be an issue as the updates to the block are always
+ well sequenced (here and in wcs_wtfini()). Also the subsequent write barriers will make sure to
+ broadcast this change to all processors.
+ */
+ cr->shmpool_blk_off = GDS_ANY_ABS2REL(csa, sblkh_p);
+ /* Need a write coherency fence here as we want to make sure the above info is stored and
+ reflected to other processors before we mark the block valid.
+ */
+ SHM_WRITE_MEMORY_BARRIER;
+ sblkh_p->valid_data = TRUE;
+ BG_TRACE_PRO_ANY(csa, dwngrd_refmts_asyncio);
+ }
+ size = ((v15_blk_hdr_ptr_t)buff)->bsiz;
+ assert(size <= csd->blk_size - SIZEOF(blk_hdr) + SIZEOF(v15_blk_hdr));
+ size = (size + 1) & ~1;
+ assert(SIZEOF(v15_blk_hdr) <= size);
+ } else DEBUG_ONLY(if (GDSV6 == cr->ondsk_blkver))
+ {
+ size = (((blk_hdr_ptr_t)buff)->bsiz + 1) & ~1;
+ assert(SIZEOF(blk_hdr) <= size);
+ }
+ DEBUG_ONLY(else GTMASSERT);
+ if (csa->do_fullblockwrites)
+ /* round size up to next full logical filesys block. */
+ size = ROUND_UP(size, csa->fullblockwrite_len);
+ assert(size <= csd->blk_size);
+ assert(FALSE == reg->read_only);
+ assert(dba_bg == reg->dyn.addr->acc_meth);
+ assert((size / 2 * 2) == size);
+ assert(0 == (((uint4) buff) & 7)); /* some disk controllers require quadword aligned xfers */
+ assert(!csa->acc_meth.bg.cache_state->cache_array || buff != csd);
+ /* if doing a reformat, the buffer is not in cache so points to a local reformat buffer so the check below is superfluous */
+ assert(reformat || !csa->acc_meth.bg.cache_state->cache_array
+ || (buff >= (unsigned char *)csa->acc_meth.bg.cache_state->cache_array
+ + (SIZEOF(cache_rec) * (csd->bt_buckets + csd->n_bts))));
+ assert(buff < (sm_uc_ptr_t)csd || reformat); /* assumes hdr follows immediately after the buffer pool in shared memory */
+ assert(size <= csd->blk_size);
+ channel_id = ((vms_gds_info*)(reg->dyn.addr->file_cntl->file_info))->fab->fab$l_stv;
+ if (asyncIO)
+ {
+ status = sys$qio(efn_bg_qio_write, channel_id, IO$_WRITEVBLK, iosb ,ast_rtn, ast_param, buff, size,
+ (csd->blk_size / DISK_BLOCK_SIZE) * blk + csd->start_vbn, 0, 0, 0);
+ CHECK_CHANNEL_STATUS(status, channel_id);
+ } else
+ {
+ status = sys$qiow(efn_bg_qio_write, channel_id, IO$_WRITEVBLK, iosb ,ast_rtn, ast_param, buff, size,
+ (csd->blk_size / DISK_BLOCK_SIZE) * blk + csd->start_vbn, 0, 0, 0);
+ CHECK_CHANNEL_STATUS(status, channel_id);
+ DEBUG_ONLY(reformat_buffer_in_use--;)
+ assert(0 == reformat_buffer_in_use);
+ --fast_lock_count;
+ assert(0 <= fast_lock_count);
+ /* Since we are doing synchroous IO here, if we also happen to already hold crit, then
+ invoke wcs_wtfini() to handle completion of that IO. Else it will have to be handled
+ elsewhere as grabbing crit here could create a deadlock situation.
+ */
+ if (csa->now_crit)
+ wcs_wtfini(reg);
+ }
+ return status;
+}
diff --git a/sr_vvms/dsk_write_nocache.c b/sr_vvms/dsk_write_nocache.c
new file mode 100644
index 0000000..4428878
--- /dev/null
+++ b/sr_vvms/dsk_write_nocache.c
@@ -0,0 +1,111 @@
+/****************************************************************
+ * *
+ * Copyright 2005, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <rms.h>
+#include "gtm_stdio.h"
+
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include <iodef.h>
+#include "efn.h"
+#include <ssdef.h>
+#include "iosb_disk.h"
+#include "iosp.h"
+#include "filestruct.h"
+#include "gtm_malloc.h" /* for CHECK_CHANNEL_STATUS macro */
+#include "gds_blk_downgrade.h"
+
+/***********************************************************************************
+ * WARNING: This routine does not manage the number of outstanding AST available.
+ * The calling routine is responsible for that.
+ ***********************************************************************************/
+
+GBLREF sm_uc_ptr_t reformat_buffer;
+GBLREF int reformat_buffer_len;
+GBLREF volatile int reformat_buffer_in_use; /* used only in DEBUG mode */
+GBLREF volatile int4 fast_lock_count;
+
+int4 dsk_write_nocache(gd_region *reg, block_id blk, sm_uc_ptr_t buff, enum db_ver ondsk_blkver,
+ void (*ast_rtn)(), int4 ast_param, io_status_block_disk *iosb)
+{
+ int4 size, status;
+ sgmnt_addrs *csa;
+ sgmnt_data_ptr_t csd;
+ boolean_t reformat;
+ uint4 channel_id;
+
+ csa = &((vms_gds_info*)(reg->dyn.addr->file_cntl->file_info))->s_addrs;
+ size = (((blk_hdr_ptr_t)buff)->bsiz + 1) & ~1;
+ csd = csa->hdr;
+ assert(NULL != csd);
+ assert(((blk_hdr_ptr_t)buff)->bver); /* GDSV4 (0) version uses this field as a block length so should always be > 0 */
+ reformat = FALSE;
+ if (IS_GDS_BLK_DOWNGRADE_NEEDED(ondsk_blkver))
+ { /* Need to downgrade/reformat this block back to a previous format */
+ assert(0 == fast_lock_count); /* since this is mainline (non-interrupt) code */
+ ++fast_lock_count; /* Prevents interrupt from using reformat buffer while we have it */
+ DEBUG_DYNGRD_ONLY(PRINTF("DSK_WRITE_NOCACHE: Block %d being dynamically downgraded on write\n", blk));
+ reformat = TRUE;
+ /* reformat_buffer_in_use should always be incremented only AFTER incrementing fast_lock_count
+ * as it is the latter that prevents interrupts from using the reformat buffer. Similarly
+ * the decrement of fast_lock_count should be done AFTER decrementing reformat_buffer_in_use.
+ */
+ assert(0 == reformat_buffer_in_use);
+ DEBUG_ONLY(reformat_buffer_in_use++;)
+ if (csd->blk_size > reformat_buffer_len)
+ { /* Buffer not big enough (or does not exist) .. get a new one releasing old if it exists */
+ if (reformat_buffer)
+ free(reformat_buffer);
+ reformat_buffer = malloc(csd->blk_size);
+ reformat_buffer_len = csd->blk_size;
+ }
+ gds_blk_downgrade((v15_blk_hdr_ptr_t)reformat_buffer, (blk_hdr_ptr_t)buff);
+ buff = reformat_buffer;
+ size = (((v15_blk_hdr_ptr_t)buff)->bsiz + 1) & ~1;
+ assert(SIZEOF(v15_blk_hdr) <= size);
+ /* Represents a state change from V5 -> V4 format */
+ INCR_BLKS_TO_UPGRD(csa, csd, 1);
+ } else DEBUG_ONLY(if (GDSV6 == ondsk_blkver))
+ {
+ size = (((blk_hdr_ptr_t)buff)->bsiz + 1) & ~1;
+ assert(SIZEOF(blk_hdr) <= size);
+ /* no adjustment to blks_to_upgrd counter is needed since the format we are going to write is GDSVCURR */
+ }
+ DEBUG_ONLY(else GTMASSERT);
+ if (csa->do_fullblockwrites)
+ size = ROUND_UP(size, csa->fullblockwrite_len); /* round size up to next full logical filesys block. */
+ assert(size <= csd->blk_size);
+ assert(FALSE == reg->read_only);
+ assert((size / 2 * 2) == size);
+ assert(0 == (((uint4) buff) & 7)); /* some disk controllers require quadword aligned xfers */
+ assert(!csa->acc_meth.bg.cache_state->cache_array || buff != csd);
+ assert(size <= csd->blk_size);
+ channel_id = ((vms_gds_info*)(reg->dyn.addr->file_cntl->file_info))->fab->fab$l_stv;
+ status = sys$qiow(efn_bg_qio_write, channel_id, IO$_WRITEVBLK, iosb ,ast_rtn, ast_param, buff, size,
+ (csd->blk_size / DISK_BLOCK_SIZE) * blk + csd->start_vbn, 0, 0, 0);
+ if (reformat)
+ {
+ DEBUG_ONLY(
+ reformat_buffer_in_use--;
+ assert(0 == reformat_buffer_in_use);
+ )
+ --fast_lock_count;
+ assert(0 == fast_lock_count);
+ }
+ CHECK_CHANNEL_STATUS(status, channel_id);
+ return status;
+}
diff --git a/sr_vvms/dsm_api.c b/sr_vvms/dsm_api.c
new file mode 100644
index 0000000..55cf2b6
--- /dev/null
+++ b/sr_vvms/dsm_api.c
@@ -0,0 +1,895 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <descrip.h>
+#include <fab.h>
+#include <rab.h>
+
+#include "gtmidef.h"
+
+#ifdef __ALPHA
+#include <builtins.h>
+#else
+#pragma builtins
+#endif
+
+#define memcpy(DST,SRC,LEN) _MOVC3((unsigned short) (LEN), (char *) (SRC), (char *) (DST))
+#define memset(DST, VALUE, LEN) _MOVC5(0, (char *)0, VALUE, LEN, (char *)(DST))
+
+typedef int4 condition_code;
+#ifdef TRACE_API
+/*******debug only*****/
+#define TRACE(X) dsmapi_out_write(X, SIZEOF(X) - 1)
+#define TRACE_NUM(X) dsmapi_out_hex(X)
+#define TRACE_DESC(X) (TRACE("Descriptor Length/Value:"), \
+ TRACE_NUM((X).dsc$w_length), \
+ dsmapi_out_write((X).dsc$a_pointer, (X).dsc$w_length))
+/*****debug above this ****/
+#else
+#define TRACE(X)
+#define TRACE_NUM(X)
+#define TRACE_DESC(X)
+#endif
+void dsmapi_out_write();
+
+#define CHECK_ARGUMENT_COUNT(ARG_CNT, FIRST_ARG, MIN, MAX) \
+ (ARG_CNT) = *(((int *) (&FIRST_ARG)) - 1); \
+ if ((ARG_CNT) > (MAX) || (ARG_CNT) < (MIN)) \
+ return DSM$_CI_ARGCNT
+#define CHECK_SDB(SDB) if ((SDB)->sdb_size != DSM$K_SDB_SIZE) return DSM$_CI_SDB
+#define CHECK_GDB(GDB) if ((GDB)->gdb_size != DSM$K_GDB_SIZE) return DSM$_CI_GDB
+#define CHECK_STATUS(STAT) if (((STAT) & 1) == 0) return (STAT)
+#define CHECK_GTM_STATUS(STAT) if (((STAT) & 1) == 0)\
+ {\
+ if (STAT == ERR_UNDEF || STAT == ERR_GVUNDEF)\
+ STAT = DSM$_UNDEF;\
+ else if (STAT == ERR_MAXNRSUBSCRIPTS || STAT == ERR_GVSUBOFLOW)\
+ STAT = DSM$_INVSUBSCR;\
+ else if (STAT == ERR_GVNAKED || STAT == ERR_GVNAKEDEXTNM)\
+ STAT = DSM$_NAKEDERR;\
+ else if (STAT == ERR_LVNULLSUBS || STAT == ERR_NULSUBSC)\
+ STAT = DSM$_NULLSUBSCR;\
+ else if (STAT == ERR_IFNOTINIT)\
+ STAT = DSM$_CI_NOTINIT;\
+ else if (STAT == ERR_VAREXPECTED)\
+ STAT = DSM$_NAME;\
+ return STAT;\
+ }
+#define GBLDIR_PREFIX "GTMAPI$"
+#define DSM$DK_NAME_LENGTH 8
+globalvalue DSM$K_NAME_LENGTH = DSM$DK_NAME_LENGTH; /* Max length of global/local name*/
+#define DSM$DK_NUMBER_SUBSCRIPT 25
+globalvalue DSM$K_NUMBER_SUBSCRIPT = DSM$DK_NUMBER_SUBSCRIPT; /* Max # of subscripts */
+globalvalue DSM$K_STRING_LENGTH = 512; /* Max string length */
+globalvalue DSM$K_SUBSCRIPT_LENGTH = 245; /* Max length of a subscript */
+globalvalue DSM$K_UCI_NAME_LENGTH = 3; /* UCI name length */
+#define DSM$DK_VOLSET_NAME_LENGTH 3
+globalvalue DSM$K_VOLSET_NAME_LENGTH = DSM$DK_VOLSET_NAME_LENGTH; /* Volume set name length */
+
+#define DSM$M_SIBLING 1
+#define DSM$M_PREVIOUS 2
+
+/* Return status indicators from the callable routines */
+/* Theirs */
+globalvalue DSM$_ALLOC = 0x007F800A;
+globalvalue DSM$_CI_GDB = 0x007F8092;
+globalvalue DSM$_ARGERR = 0x007F8012;
+globalvalue DSM$_CI_ITEMBUFLEN = 0x007F809A;
+globalvalue DSM$_CI_ITEMINSUF = 0x007F80A2;
+globalvalue DSM$_CI_ITEMTYPE = 0x007F80AA;
+globalvalue DSM$_CI_LOCKMODE = 0x007F80B2;
+globalvalue DSM$_CI_NOSIBLING = 0x007F80B8;
+globalvalue DSM$_CI_NOTINIT = 0x007F80C2;
+globalvalue DSM$_CI_SDB = 0x007F80CA;
+globalvalue DSM$_CI_SUBPOS = 0x007F80D2;
+globalvalue DSM$_CI_ACTIVE = 0x007F8082;
+globalvalue DSM$_CI_ARGCNT = 0x007F808A;
+globalvalue DSM$_INVSUBSCR = 0x007F8542;
+globalvalue DSM$_FORCEXIT = 0x007F82A4;
+globalvalue DSM$_NAKEDERR = 0x007F862A;
+globalvalue DSM$_NAME = 0x007F863A;
+globalvalue DSM$_NOSUCHUCI = 0x007F86A2;
+globalvalue DSM$_NOSUCHVOLSET = 0x007F86AA;
+globalvalue DSM$_NOTRUN = 0x007F86C2;
+globalvalue DSM$_STRLEN = 0x007F885A;
+globalvalue DSM$_SUCCESS = 0x007F8861;
+globalvalue DSM$_NULLSUBSCR = 0x007F86DA;
+globalvalue DSM$_SYNTAX = 0x007F886A;
+globalvalue DSM$_TIMEOUT = 0x007F889A;
+globalvalue DSM$_TPABORT = 0x007F88A2;
+globalvalue DSM$_TPNORU = 0x007F88C2;
+globalvalue DSM$_TPNOTCONF = 0x007F88CA;
+globalvalue DSM$_TPROTRAN = 0x007F88FA;
+globalvalue DSM$_PROT = 0x007F8772;
+globalvalue DSM$_UNDEF = 0x007F890A;
+globalvalue DSM$_RULEVEL = 0x007F87C2;
+globalvalue DSM$_RUNDOWN = 0x007F87D0;
+
+/* Ours */
+#define error_def(x) globalvalue x
+error_def(ERR_UNIMPLOP);
+error_def(ERR_GVUNDEF);
+error_def(ERR_UNDEF);
+error_def(ERR_IFNOTINIT);
+error_def(ERR_VAREXPECTED);
+error_def(ERR_LVNULLSUBS);
+error_def(ERR_NULSUBSC);
+error_def(ERR_GVNAKED);
+error_def(ERR_GVNAKEDEXTNM);
+error_def(ERR_MAXNRSUBSCRIPTS);
+error_def(ERR_GVSUBOFLOW);
+
+/* Global Data Block definition */
+struct gdb
+{
+ int4 gdb_size; /* length of gdb in longwords */
+ int4 name_length; /* length of global name */
+ /* If zero, this is a global reference */
+ char global_name[DSM$DK_NAME_LENGTH]; /* global name */
+ char uci_nlen;
+ char uci_name[DSM$DK_NAME_LENGTH]; /* uci name */
+ char volset_nlen;
+ char volset_name[DSM$DK_VOLSET_NAME_LENGTH]; /* volume set name */
+};
+
+globalvalue DSM$K_GDB_SIZE = 11; /* Number of longwords in a GDB */
+
+/* SDB data block definition */
+struct sdb
+{
+ int4 sdb_size; /* length of sdb in longwords */
+ int4 sdb_count; /* subscript count */
+ struct dsc$descriptor_s subscripts[DSM$DK_NUMBER_SUBSCRIPT]; /* array of subscripts */
+};
+
+globalvalue DSM$K_SDB_SIZE = 90; /* number of longwords in a SDB */
+
+static struct dsc$descriptor_s return_string = {0, DSC$K_DTYPE_T, DSC$K_CLASS_D, 0 };
+static struct dsc$descriptor_s global_name_desc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};
+static char global_directory_buffer[24];
+static struct dsc$descriptor_s global_directory_desc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, global_directory_buffer };
+
+extern condition_code gtm$gblget(), gtm$get(), gtm$gblorder(), gtm$gbldata(), gtm$init(),
+ gtm$kill(), gtm$put(), gtm$xecute();
+
+struct dsc$descriptor_s *setup_gname(global_data_block)
+struct gdb *global_data_block;
+{
+ if (global_data_block->name_length == 0)
+ return 0;
+ global_name_desc.dsc$w_length = global_data_block->name_length;
+ global_name_desc.dsc$a_pointer = global_data_block->global_name;
+ return &global_name_desc;
+}
+
+struct dsc$descriptor_s *setup_gdir(global_data_block)
+struct gdb *global_data_block;
+{
+ char *cp;
+
+ if (global_data_block->uci_nlen != 3 || global_data_block->volset_nlen != 3)
+ return 0;
+ memcpy(global_directory_buffer, GBLDIR_PREFIX, SIZEOF(GBLDIR_PREFIX) - 1);
+ cp = global_directory_buffer + SIZEOF(GBLDIR_PREFIX) - 1;
+ memcpy(cp, global_data_block->uci_name, SIZEOF(global_data_block->uci_name));
+ cp += SIZEOF(global_data_block->uci_name);
+ *cp++ = '$';
+ memcpy(cp, global_data_block->volset_name, SIZEOF(global_data_block->volset_name));
+ cp += SIZEOF(global_data_block->volset_name);
+ global_directory_desc.dsc$w_length = cp - global_directory_buffer;
+ return &global_directory_desc;
+}
+
+condition_code check_3_alphas(cp)
+char *cp;
+{
+ int i, ch;
+
+ for (i = 0 ; i < 3 ; i++)
+ {
+ ch = *cp++;
+ if (ch < 'A' || ch > 'Z')
+ return DSM$_NOSUCHUCI;
+ }
+ return DSM$_SUCCESS;
+}
+
+condition_code dsm$dsm(command_line)
+struct dsc$descriptor_s *command_line;
+{
+ int arg_cnt;
+
+ CHECK_ARGUMENT_COUNT(arg_cnt, command_line, 1, 1);
+TRACE("at DSM$DSM");
+ return ERR_UNIMPLOP;
+}
+
+condition_code dsm$gdb_clear(global_data_block)
+struct gdb *global_data_block;
+{
+ int arg_cnt;
+
+TRACE("condition_code dsm$gdb_clear(global_data_block)");
+ CHECK_ARGUMENT_COUNT(arg_cnt, global_data_block, 1, 1);
+ CHECK_GDB(global_data_block);
+ global_data_block->name_length = 0;
+ global_data_block->uci_nlen = 0;
+ global_data_block->volset_nlen = 0;
+ return DSM$_SUCCESS;
+}
+
+condition_code dsm$gdb_create(gdb_address)
+struct gdb **gdb_address;
+{
+ struct gdb *global_data_block;
+ condition_code status;
+ int arg_cnt;
+
+TRACE("condition_code dsm$gdb_create(gdb_address)");
+ CHECK_ARGUMENT_COUNT(arg_cnt, gdb_address, 1, 1);
+ status = lib$get_vm(&SIZEOF(*global_data_block), &global_data_block, 0);
+ CHECK_STATUS(status);
+ *gdb_address = global_data_block;
+ memset(global_data_block, 0, SIZEOF(*global_data_block));
+ global_data_block->gdb_size = DSM$K_GDB_SIZE;
+ return DSM$_SUCCESS;
+}
+
+condition_code dsm$gdb_initialize(gdbsiz, global_data_block)
+uint4 *gdbsiz;
+struct gdb *global_data_block;
+{
+ int arg_cnt;
+
+TRACE("condition_code dsm$gdb_initialize(gdbsiz, global_data_block)");
+ CHECK_ARGUMENT_COUNT(arg_cnt, gdbsiz, 2, 2);
+ if (*gdbsiz != DSM$K_GDB_SIZE)
+ lib$signal(DSM$_CI_GDB);
+ memset(global_data_block, 0, SIZEOF(*global_data_block));
+ global_data_block->gdb_size = DSM$K_GDB_SIZE;
+ return DSM$_SUCCESS;
+}
+
+condition_code dsm$gdb_extract(global_data_block, global_name, global_name_length, uci_name, volume_set_name)
+struct gdb *global_data_block;
+struct dsc$descriptor_s *global_name;
+unsigned short *global_name_length;
+struct dsc$descriptor_s *uci_name;
+struct dsc$descriptor_s *volume_set_name;
+{
+ int arg_cnt;
+ struct dsc$descriptor_s auto_string;
+ condition_code status;
+
+TRACE("condition_code dsm$gdb_extract(global_data_block, ...");
+ CHECK_ARGUMENT_COUNT(arg_cnt, global_data_block, 2, 5);
+ CHECK_GDB(global_data_block);
+ auto_string.dsc$w_length = global_data_block->name_length;
+ auto_string.dsc$b_dtype = DSC$K_DTYPE_T;
+ auto_string.dsc$b_class = DSC$K_CLASS_S;
+ auto_string.dsc$a_pointer = global_data_block->global_name;
+ status = lib$scopy_dxdx(&auto_string, global_name);
+ CHECK_STATUS(status);
+ if (arg_cnt > 2)
+ {
+ if (global_name_length)
+ *global_name_length = global_data_block->name_length;
+ if (arg_cnt > 3)
+ {
+ if (uci_name)
+ {
+ auto_string.dsc$w_length = global_data_block->uci_nlen;
+ auto_string.dsc$a_pointer = global_data_block->uci_name;
+ status = lib$scopy_dxdx(&auto_string, uci_name);
+ CHECK_STATUS(status);
+ }
+ if (arg_cnt > 4)
+ {
+ if (volume_set_name)
+ {
+ auto_string.dsc$w_length = global_data_block->volset_nlen;
+ auto_string.dsc$a_pointer = global_data_block->volset_name;
+ status = lib$scopy_dxdx(&auto_string, volume_set_name);
+ CHECK_STATUS(status);
+ }
+ }
+ }
+ }
+ return DSM$_SUCCESS;
+}
+
+condition_code dsm$gdb_insert(global_name, global_data_block, uci_name, volume_set_name)
+struct dsc$descriptor_s *global_name;
+struct gdb *global_data_block;
+struct dsc$descriptor_s *uci_name;
+struct dsc$descriptor_s *volume_set_name;
+{
+ int arg_cnt;
+ condition_code status;
+ int n;
+ char *cin, *cout;
+
+TRACE("condition_code dsm$gdb_insert(global_name, ...");
+ CHECK_ARGUMENT_COUNT(arg_cnt, global_name, 2, 4);
+ CHECK_GDB(global_data_block);
+ n = global_name->dsc$w_length;
+ if (n < 1 || n > DSM$K_NAME_LENGTH)
+ return DSM$_NAME;
+ global_data_block->name_length = n;
+ for (cin = global_name->dsc$a_pointer, cout = global_data_block->global_name ; n-- > 0 ; )
+ *cout++ = *cin++;
+ if (arg_cnt > 2 && uci_name)
+ {
+ status = check_3_alphas(uci_name);
+ if ((status & 1) == 0)
+ return DSM$_NOSUCHUCI;
+ for (cin = uci_name->dsc$a_pointer, cout = global_data_block->uci_name , n = SIZEOF(global_data_block->uci_name);
+ n-- > 0 ; )
+ *cout++ = *cin++;
+ }
+ if (arg_cnt > 3 && volume_set_name)
+ {
+ status = check_3_alphas(volume_set_name);
+ if ((status & 1) == 0)
+ return DSM$_NOSUCHVOLSET;
+ for (cin = volume_set_name->dsc$a_pointer,
+ cout = global_data_block->volset_name , n = SIZEOF(global_data_block->volset_name);
+ n-- > 0 ; )
+ *cout++ = *cin++;
+ }
+ return DSM$_SUCCESS;
+}
+
+condition_code dsm$gdb_free(global_data_block)
+struct gdb *global_data_block;
+{
+ int arg_cnt;
+ condition_code status;
+
+TRACE("condition_code dsm$gdb_free(global_data_block)");
+ CHECK_ARGUMENT_COUNT(arg_cnt, global_data_block, 1, 1);
+ CHECK_GDB(global_data_block);
+ status = lib$free_vm(&SIZEOF(*global_data_block), &global_data_block, 0);
+ CHECK_STATUS(status);
+ return DSM$_SUCCESS;
+}
+
+condition_code dsm$global_$data(global_data_block, subscript_data_block, dvalue)
+struct gdb *global_data_block;
+struct sdb *subscript_data_block;
+uint4 *dvalue;
+{
+ int arg_cnt;
+ condition_code status;
+ struct dsc$descriptor *gname_desc;
+ struct dsc$descriptor *gdir_desc;
+ struct dsc$descriptor return_data_value;
+/***************DEBUG **************/
+#ifdef TRACE_API
+int4 *ip, nnn;
+ip = subscript_data_block;
+TRACE("SDB HEADER VALUE: ");
+TRACE_NUM(ip);
+TRACE_NUM(*ip);
+for (nnn = 0 ; nnn < subscript_data_block->sdb_count ; nnn++)
+ TRACE_DESC(subscript_data_block->subscripts[nnn]);
+/************END DEBUG **********/
+TRACE("condition_code dsm$global_$data(global_data_block, ...");
+#endif
+ CHECK_ARGUMENT_COUNT(arg_cnt, global_data_block, 3, 3);
+ CHECK_GDB(global_data_block);
+ CHECK_SDB(subscript_data_block);
+ gname_desc = setup_gname(global_data_block);
+ gdir_desc = setup_gdir(global_data_block);
+ return_data_value.dsc$w_length = SIZEOF(int4);
+ return_data_value.dsc$b_dtype = DSC$K_DTYPE_L;
+ return_data_value.dsc$b_class = DSC$K_CLASS_S;
+ return_data_value.dsc$a_pointer = dvalue;
+ status = dsm_api_dispatch(gtm$gbldata, &return_data_value, gdir_desc, gname_desc, subscript_data_block->sdb_count,
+ subscript_data_block->subscripts);
+ CHECK_GTM_STATUS(status)
+#ifdef TRACE_GLOBALS
+display_global_ref("$D", global_data_block, subscript_data_block);
+display_int(*dvalue);
+#endif
+TRACE_DESC(return_data_value);
+ return DSM$_SUCCESS;
+}
+
+condition_code dsm$global_$order(global_data_block, subscript_data_block,
+ option_mask, sibling, sibling_length)
+struct gdb *global_data_block;
+struct sdb *subscript_data_block;
+uint4 *option_mask;
+struct dsc$descriptor_s *sibling;
+unsigned short *sibling_length;
+{
+ int arg_cnt;
+ condition_code status;
+ struct dsc$descriptor *gname_desc;
+ struct dsc$descriptor *gdir_desc;
+
+TRACE("condition_code dsm$global_$order(global_data_block, ");
+ CHECK_ARGUMENT_COUNT(arg_cnt, global_data_block, 3, 5);
+ CHECK_GDB(global_data_block);
+ CHECK_SDB(subscript_data_block);
+ if (subscript_data_block->sdb_count < 1)
+ return DSM$_NAKEDERR;
+ if (*option_mask & 2) /* Should be $ZPREVIOUS */
+ {
+TRACE("At $ZPREVIOUS");
+ lib$signal(ERR_UNIMPLOP);
+ }
+ gname_desc = setup_gname(global_data_block);
+ gdir_desc = setup_gdir(global_data_block);
+ status = dsm_api_dispatch(gtm$gblorder, &return_string, gdir_desc, gname_desc, subscript_data_block->sdb_count,
+ subscript_data_block->subscripts);
+ CHECK_GTM_STATUS(status)
+ if (return_string.dsc$w_length == 0)
+ {
+ status = DSM$_CI_NOSIBLING;
+TRACE("Found NOSIBLING");
+ if (*option_mask & 1)
+ subscript_data_block->sdb_count--;
+#ifdef TRACE_GLOBALS
+display_global_ref("$O", global_data_block, subscript_data_block);
+display_str("=<null>");
+#endif
+ }
+ else
+ {
+ status = DSM$_SUCCESS;
+ if (*option_mask & 1)
+TRACE_DESC(return_string);
+ {
+TRACE("option_mask is odd, performining scopy_dxdxto subscript_data_block");
+ lib$scopy_dxdx(&return_string, &subscript_data_block->subscripts[subscript_data_block->sdb_count - 1]);
+ }
+ if (arg_cnt > 3 && sibling)
+ {
+ lib$scopy_dxdx(&return_string, sibling);
+ if (arg_cnt > 4 && sibling_length)
+ {
+ *sibling_length = (return_string.dsc$w_length < sibling->dsc$w_length)
+ ? return_string.dsc$w_length : sibling->dsc$w_length;
+ }
+ }
+#ifdef TRACE_GLOBALS
+display_global_ref("$O", global_data_block, subscript_data_block);
+display_descript(&return_string, return_string.dsc$w_length);
+#endif
+ }
+ lib$sfree1_dd(&return_string);
+ return status;
+}
+
+condition_code dsm$global_get_t(global_data_block, subscript_data_block, get_value, get_value_length)
+struct gdb *global_data_block;
+struct sdb *subscript_data_block;
+struct dsc$descriptor_s *get_value;
+unsigned short *get_value_length;
+{
+ int arg_cnt;
+ condition_code status;
+ struct dsc$descriptor *gname_desc;
+ struct dsc$descriptor *gdir_desc;
+
+TRACE("condition_code dsm$global_get_t(global_data_block, ...");
+ CHECK_ARGUMENT_COUNT(arg_cnt, global_data_block, 3, 4);
+ CHECK_GDB(global_data_block);
+ CHECK_SDB(subscript_data_block);
+ gname_desc = setup_gname(global_data_block);
+ gdir_desc = setup_gdir(global_data_block);
+ status = dsm_api_dispatch(gtm$gblget, &return_string, gdir_desc, gname_desc, subscript_data_block->sdb_count,
+ subscript_data_block->subscripts);
+ CHECK_GTM_STATUS(status)
+#ifdef TRACE_GLOBALS
+display_global_ref("G ", global_data_block, subscript_data_block);
+display_descript(&return_string, return_string.dsc$w_length);
+#endif
+ TRACE_DESC(return_string);
+ if (arg_cnt > 3 && get_value_length)
+ {
+ *get_value_length = (return_string.dsc$w_length < get_value->dsc$w_length)
+ ? return_string.dsc$w_length : get_value->dsc$w_length;
+ }
+ lib$scopy_dxdx(&return_string, get_value);
+ lib$sfree1_dd(&return_string);
+ return DSM$_SUCCESS;
+}
+
+condition_code dsm$initialize(command_line)
+struct dsc$descriptor_s *command_line;
+{
+ int arg_cnt;
+ condition_code status;
+
+TRACE("condition_code dsm$initialize(command_line)");
+ CHECK_ARGUMENT_COUNT(arg_cnt, command_line, 0, 1);
+ if (arg_cnt > 0 && command_line != 0 && command_line->dsc$w_length != 0)
+ {
+TRACE("AT DSM$INITIALIZE");
+ dsmapi_out_write(command_line->dsc$a_pointer, command_line->dsc$w_length);
+ return ERR_UNIMPLOP;
+ }
+ status = gtm$init();
+ CHECK_GTM_STATUS(status)
+ return DSM$_SUCCESS;
+}
+
+condition_code dsm$sdb_clear(subscript_data_block)
+struct sdb *subscript_data_block;
+{
+ int arg_cnt;
+
+TRACE("condition_code dsm$sdb_clear(subscript_data_block)");
+ CHECK_ARGUMENT_COUNT(arg_cnt, subscript_data_block, 1, 1);
+ CHECK_SDB(subscript_data_block);
+ subscript_data_block->sdb_count = 0;
+ return DSM$_SUCCESS;
+}
+
+condition_code dsm$sdb_count(subscript_data_block, count)
+struct sdb *subscript_data_block;
+uint4 *count;
+{
+ int arg_cnt;
+
+TRACE("condition_code dsm$sdb_count(subscript_data_block, count)");
+ CHECK_ARGUMENT_COUNT(arg_cnt, subscript_data_block, 2, 2);
+ CHECK_SDB(subscript_data_block);
+ *count = subscript_data_block->sdb_count;
+ return DSM$_SUCCESS;
+}
+
+condition_code dsm$sdb_create(sdb_address)
+struct sdb **sdb_address;
+{
+ struct sdb *subscript_data_block;
+ condition_code status;
+ int arg_cnt, dsm_sdb_size;
+
+TRACE("condition_code dsm$sdb_create(sdb_address)");
+ CHECK_ARGUMENT_COUNT(arg_cnt, sdb_address, 1, 1);
+ status = lib$get_vm(&SIZEOF(*subscript_data_block), &subscript_data_block, 0);
+ CHECK_STATUS(status);
+ *sdb_address = subscript_data_block;
+ memset(subscript_data_block, 0, SIZEOF(*subscript_data_block));
+ dsm_sdb_size = DSM$K_SDB_SIZE;
+ status = dsm$sdb_initialize(&dsm_sdb_size, subscript_data_block);
+ CHECK_STATUS(status);
+ return DSM$_SUCCESS;
+}
+
+condition_code dsm$sdb_extract_one_t(subscript_data_block, position, sub_value, sub_value_length)
+struct sdb *subscript_data_block;
+uint4 *position;
+struct dsc$descriptor_s *sub_value;
+unsigned short *sub_value_length;
+{
+ int arg_cnt;
+ condition_code status;
+ int pos;
+
+TRACE("condition_code dsm$sdb_extract_one_t(subscript_data_block, ...");
+ CHECK_ARGUMENT_COUNT(arg_cnt, subscript_data_block, 3, 4);
+ CHECK_SDB(subscript_data_block);
+ pos = *position - 1;
+ if (pos < 0 || pos > subscript_data_block->sdb_count + 1)
+ return DSM$_CI_SUBPOS;
+ status = lib$scopy_dxdx(&subscript_data_block->subscripts[pos], sub_value);
+ CHECK_STATUS(status);
+ if (arg_cnt > 3 && sub_value_length)
+ *sub_value_length = subscript_data_block->subscripts[pos].dsc$w_length;
+ return DSM$_SUCCESS;
+}
+
+condition_code dsm$sdb_free(subscript_data_block)
+struct sdb *subscript_data_block;
+{
+ int arg_cnt, dsm_number_subscript;
+ condition_code status;
+
+TRACE("condition_code dsm$sdb_free(subscript_data_block)");
+ CHECK_ARGUMENT_COUNT(arg_cnt, subscript_data_block, 1, 1);
+ CHECK_SDB(subscript_data_block);
+ dsm_number_subscript = DSM$K_NUMBER_SUBSCRIPT;
+ status = lib$sfreen_dd(&dsm_number_subscript, subscript_data_block->subscripts);
+ CHECK_STATUS(status);
+ status = lib$free_vm(&SIZEOF(*subscript_data_block), &subscript_data_block, 0);
+ CHECK_STATUS(status);
+ return DSM$_SUCCESS;
+}
+
+condition_code dsm$sdb_initialize(sdbsize, subscript_data_block)
+int4 *sdbsize;
+struct sdb *subscript_data_block;
+{
+ int arg_cnt;
+ condition_code status;
+ int n;
+
+TRACE("condition_code dsm$sdb_initialize(sdbsize, subscript_data_block)");
+ CHECK_ARGUMENT_COUNT(arg_cnt, sdbsize, 2, 2);
+ if (*sdbsize != DSM$K_SDB_SIZE)
+ return DSM$_CI_SDB;
+ subscript_data_block->sdb_size = DSM$K_SDB_SIZE;
+ subscript_data_block->sdb_count = 0;
+ for (n = 0 ; n < DSM$K_NUMBER_SUBSCRIPT ; n++)
+ {
+ subscript_data_block->subscripts[n].dsc$w_length = 0;
+ subscript_data_block->subscripts[n].dsc$b_dtype = DSC$K_DTYPE_T;
+ subscript_data_block->subscripts[n].dsc$b_class = DSC$K_CLASS_D;
+ subscript_data_block->subscripts[n].dsc$a_pointer = 0;
+ }
+ return DSM$_SUCCESS;
+}
+
+condition_code dsm$sdb_insert_null(position, subscript_data_block)
+uint4 *position;
+struct sdb *subscript_data_block;
+{
+ int arg_cnt;
+ condition_code status;
+ int pos;
+
+TRACE("condition_code dsm$sdb_insert_null(position, subscript_data_block)");
+TRACE("Null inserted at position");
+TRACE_NUM(*position);
+ CHECK_ARGUMENT_COUNT(arg_cnt, position, 2, 2);
+ CHECK_SDB(subscript_data_block);
+ pos = *position - 1;
+ if (pos < 0 || pos > subscript_data_block->sdb_count + 1)
+ return DSM$_CI_SUBPOS;
+ subscript_data_block->subscripts[pos].dsc$w_length = 0;
+ subscript_data_block->sdb_count = pos + 1;
+ return DSM$_SUCCESS;
+}
+
+condition_code dsm$sdb_insert_one_t(position, sub_value, subscript_data_block)
+uint4 *position;
+struct dsc$descriptor_s *sub_value;
+struct sdb *subscript_data_block;
+{
+ int arg_cnt;
+ condition_code status;
+ int pos;
+
+TRACE("condition_code dsm$sdb_insert_one_t(position, ...");
+TRACE("Position/Value");
+TRACE_NUM(*position);
+TRACE_DESC(*sub_value);
+ CHECK_ARGUMENT_COUNT(arg_cnt, position, 3, 3);
+ CHECK_SDB(subscript_data_block);
+ pos = *position - 1;
+ if (pos < 0 || pos > subscript_data_block->sdb_count + 1)
+ return DSM$_CI_SUBPOS;
+ status = lib$scopy_dxdx(sub_value, &subscript_data_block->subscripts[pos]);
+ CHECK_STATUS(status);
+ if (pos >= subscript_data_block->sdb_count)
+ subscript_data_block->sdb_count = pos + 1;
+ /* Note check here for maximum depth! */
+ return DSM$_SUCCESS;
+}
+
+condition_code dsm$xecute(mumps_code)
+struct dsc$descriptor_s *mumps_code;
+{
+ int arg_cnt;
+ condition_code status;
+
+ CHECK_ARGUMENT_COUNT(arg_cnt, mumps_code, 1, 1);
+ status = gtm$xecute(mumps_code);
+ CHECK_GTM_STATUS(status)
+ return DSM$_SUCCESS;
+}
+
+condition_code dsm$rundown()
+{
+TRACE("condition_code dsm$rundown()");
+ return DSM$_SUCCESS;
+}
+
+condition_code dsm$local_get(local_name, get_value, get_value_length)
+struct dsc$descriptor_s *local_name;
+struct dsc$descriptor_s *get_value;
+unsigned short *get_value_length;
+{
+ int arg_cnt;
+ condition_code status;
+
+TRACE("condition_code dsm$local_get(local_name, ...");
+ CHECK_ARGUMENT_COUNT(arg_cnt, local_name, 2, 3);
+ status = gtm$get(GTMI$_LOCAL, &return_string, local_name);
+ CHECK_GTM_STATUS(status)
+#ifdef TRACE_GLOBALS
+display_descript(&local_name, local_name.dsc$w_length);
+display_descript(&return_string, return_string.dsc$w_length);
+#endif
+ TRACE_DESC(return_string);
+ if (arg_cnt > 2 && get_value_length)
+ {
+ *get_value_length = (return_string.dsc$w_length < get_value->dsc$w_length)
+ ? return_string.dsc$w_length : get_value->dsc$w_length;
+ }
+ lib$scopy_dxdx(&return_string, get_value);
+ lib$sfree1_dd(&return_string);
+ return DSM$_SUCCESS;
+}
+
+condition_code dsm$local_set(local_name, set_value)
+struct dsc$descriptor_s *local_name;
+struct dsc$descriptor_s *set_value;
+{
+ int arg_cnt;
+ condition_code status;
+
+TRACE("condition_code dsm$local_set(local_name, ...");
+ CHECK_ARGUMENT_COUNT(arg_cnt, local_name, 2, 2);
+ status = gtm$put(GTMI$_LOCAL, set_value, local_name);
+ CHECK_GTM_STATUS(status)
+ return DSM$_SUCCESS;
+}
+
+condition_code dsm$local_kill(local_name)
+struct dsc$descriptor_s *local_name;
+{
+ int arg_cnt;
+ condition_code status;
+
+TRACE("condition_code dsm$local_set(local_name, ...");
+ CHECK_ARGUMENT_COUNT(arg_cnt, local_name, 1, 1);
+ status = gtm$kill(GTMI$_LOCAL, local_name);
+ CHECK_GTM_STATUS(status)
+ return DSM$_SUCCESS;
+}
+
+#ifdef TRACE_GLOBALS
+static unsigned char tg_buffer[132];
+static unsigned char *tgb;
+
+display_global_ref(typ, g, s)
+unsigned char *typ;
+struct gdb *g;
+struct sdb *s;
+{
+ int i, j;
+ unsigned char *cp;
+
+ tgb = tg_buffer;
+ while (*typ)
+ *tgb++ = *typ++;
+ *tgb++ = ':';
+ *tgb++ = '^';
+ cp = g->global_name;
+ for (i = 0 ; i < g->name_length ; i++)
+ *tgb++ = *cp++;
+ if (s->sdb_count == 0)
+ return;
+ *tgb++ = '(';
+ for (i = 0 ; i < s->sdb_count ; i++)
+ {
+ *tgb++ = '"';
+ for (cp = s->subscripts[i].dsc$a_pointer, j = s->subscripts[i].dsc$w_length ; j-- > 0 ; )
+ *tgb++ = *cp++;
+ *tgb++ = '"';
+ *tgb++ = ',';
+ }
+ *(tgb - 1) = ')';
+ return;
+}
+
+display_int(n)
+int n;
+{
+ *tgb++ = '=';
+ if (n > 9)
+ *tgb++ = '0' + ((n / 10) % 10);
+ *tgb++ = '0' + (n % 10);
+ display_dump();
+}
+
+display_descript(d, len)
+struct dsc$descriptor_s *d;
+int len;
+{
+ char *cp;
+ int n;
+
+ *tgb++ = '=';
+ for (n = 0 , cp = d->dsc$a_pointer ; n++ < len; )
+ *tgb++ = *cp++;
+ display_dump();
+}
+display_dump()
+{
+ dsmapi_out_write(tg_buffer, tgb - tg_buffer);
+}
+
+display_str(s)
+char *s;
+{
+ while (*tgb++ = *s++)
+ ;
+ dsmapi_out_write(tg_buffer, tgb - tg_buffer);
+}
+
+#endif
+
+static struct RAB *dsmapi_output_rab = 0;
+static struct FAB *dsmapi_output_fab = 0;
+
+static void dsmapi_out_open()
+{
+ uint4 status;
+
+ dsmapi_output_fab = malloc(SIZEOF(*dsmapi_output_fab));
+ dsmapi_output_rab = malloc(SIZEOF(*dsmapi_output_rab));
+ *dsmapi_output_fab = cc$rms_fab;
+ *dsmapi_output_rab = cc$rms_rab;
+ dsmapi_output_rab->rab$l_fab = dsmapi_output_fab;
+ dsmapi_output_rab->rab$w_usz = 255;
+ dsmapi_output_fab->fab$w_mrs = 255;
+ dsmapi_output_fab->fab$b_fac = FAB$M_GET | FAB$M_PUT;
+ dsmapi_output_fab->fab$b_rat = FAB$M_CR;
+ dsmapi_output_fab->fab$l_fna = "SYS$OUTPUT";
+ dsmapi_output_fab->fab$b_fns = SIZEOF("SYS$OUTPUT") - 1;
+ status = sys$create(dsmapi_output_fab, 0, 0);
+ if ((status & 1) == 0)
+ lib$signal(status);
+ status = sys$connect(dsmapi_output_rab, 0, 0);
+ if ((status & 1) == 0)
+ lib$signal(status);
+}
+
+static void dsmapi_out_write(addr, len)
+unsigned char *addr;
+unsigned int len;
+{
+ if (!dsmapi_output_fab)
+ dsmapi_out_open();
+ dsmapi_output_rab->rab$l_rbf = addr;
+ dsmapi_output_rab->rab$w_rsz = len;
+ sys$put(dsmapi_output_rab,0 ,0);
+ return;
+}
+
+static void dsmapi_out_hex(val)
+int4 val;
+{
+ register char *cp;
+ register unsigned int n;
+ char x;
+ char dest[8];
+
+ n = val;
+ cp = &dest[8];
+ while (cp > dest)
+ {
+ x = n & 0xF;
+ n >>= 4;
+ *--cp = x + ((x > 9) ? 'A' - 10 : '0');
+ }
+ dsmapi_out_write(dest, SIZEOF(dest));
+ return;
+}
+
+static void dsmapi_out_close()
+{
+ sys$close(dsmapi_output_fab, 0, 0);
+ free(dsmapi_output_fab);
+ free(dsmapi_output_rab);
+ dsmapi_output_fab = 0;
+ dsmapi_output_rab = 0;
+ return;
+}
diff --git a/sr_vvms/dtgbldir.c b/sr_vvms/dtgbldir.c
new file mode 100644
index 0000000..c299276
--- /dev/null
+++ b/sr_vvms/dtgbldir.c
@@ -0,0 +1,225 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* dtgbldir.c - test global directory functions */
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+#include "gtm_stdio.h"
+#include "gtm_stdlib.h"
+#include <fab.h>
+#include <rmsdef.h>
+#include <iodef.h>
+#include <ssdef.h>
+#include <descrip.h>
+#include <psldef.h>
+#include <lnmdef.h>
+#include <efndef.h>
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "gbldirnam.h"
+#include "dpgbldir.h"
+
+main()
+{
+ struct FAB fab;
+ header_struct *header;
+ gd_addr *addr, *addr1, *addr2, *addr3;
+ gd_region *region;
+ gd_segment *segment;
+ int4 *long_ptr, ret_addr;
+ short iosb[4];
+ mval v;
+ char file_name1[] = "dtgbld01.gld", file_name2[] = "dtgbld02.gld", file_name3[] = "dtgbld03.gld";
+ char label[] = GDE_LABEL_LITERAL;
+ char file_name4[]="dtlog1";
+ uint4 status, size;
+ $DESCRIPTOR(proc_tab, "LNM$PROCESS");
+ $DESCRIPTOR(gbldir, "GTM$GBLDIR");
+ $DESCRIPTOR(dtlog, "DTLOG1");
+ typedef struct
+ { short buf_len;
+ short item;
+ int4 buf_addr;
+ int4 ret_addr;
+ int4 term;
+ }item_list;
+ item_list ilist;
+ char acmo=PSL$C_USER;
+
+/************************* Create logical names for tests **********************************************************/
+ ilist.item = LNM$_STRING;
+ ilist.buf_len = SIZEOF(file_name1) - 1;
+ ilist.buf_addr = file_name1;
+ ilist.term = 0;
+ ilist.ret_addr = &ret_addr;
+ status = sys$crelnm(0, &proc_tab, &gbldir, &acmo, &ilist);
+ if (!(status & 1))
+ rts_error(VARLSTCNT(1) status);
+ ilist.buf_len = SIZEOF(file_name2) - 1;
+ ilist.buf_addr = file_name2;
+ status = sys$crelnm(0, &proc_tab, &dtlog, &acmo, &ilist);
+ if (!(status & 1))
+ rts_error(VARLSTCNT(1) status);
+
+/************************* Create global directory files for tests *************************************************/
+ fab = cc$rms_fab;
+ fab.fab$l_alq = 5;
+ fab.fab$l_fna = file_name1;
+ fab.fab$b_fns = SIZEOF(file_name1) - 1;
+ fab.fab$l_fop = (FAB$M_UFO | FAB$M_CBT);
+ fab.fab$b_fac = (FAB$M_PUT | FAB$M_GET | FAB$M_BIO);
+ fab.fab$b_shr = (FAB$M_SHRPUT | FAB$M_SHRGET | FAB$M_UPI);
+ status = sys$create(&fab);
+ if (status != RMS$_CREATED && status != RMS$_FILEPURGED && status != RMS$_NORMAL)
+ sys$exit(status);
+ size = SIZEOF(header_struct) + SIZEOF(gd_addr) + 3 * SIZEOF(gd_binding) + SIZEOF(gd_region) + SIZEOF(gd_segment);
+ header = malloc(((size + 511) / 512) * 512);
+ header->filesize = size;
+ size = ((size + 511) / 512) * 512;
+ memcpy(header->label, label, SIZEOF(label)-1);
+ addr = (char*)header + SIZEOF(header_struct);
+ addr->maps = SIZEOF(gd_addr);
+ addr->n_maps = 3;
+ addr->regions = (int4)(addr->maps) + 3 * SIZEOF(gd_binding);
+ addr->n_regions = 1;
+ addr->segments = (int4)(addr->regions) + SIZEOF(gd_region);
+ addr->n_segments = 1;
+ addr->link = addr->tab_ptr = addr->id = addr->local_locks = 0;
+ addr->max_rec_size = 100;
+ addr->end = addr->segments + SIZEOF(gd_segment);
+ long_ptr = (char*)addr + (int4)(addr->maps);
+ *long_ptr++ = 0xFFFF2F23;
+ *long_ptr++ = 0xFFFFFFFF;
+ *long_ptr++ = addr->regions;
+ *long_ptr++ = 0xFFFFFF24;
+ *long_ptr++ = 0xFFFFFFFF;
+ *long_ptr++ = addr->regions;
+ *long_ptr++ = 0xFFFFFFFF;
+ *long_ptr++ = 0xFFFFFFFF;
+ *long_ptr++ = addr->regions;
+ region = (char*)addr + (int4)(addr->regions);
+ segment = (char*)addr + (int4)(addr->segments);
+ memset(region, 0, SIZEOF(gd_region));
+ region->rname_len = 5;
+ memcpy(region->rname,"TEMP1",5);
+ region->dyn.offset = addr->segments;
+ region->max_rec_size = 100;
+ region->max_key_size = 64;
+ segment->sname_len = 5;
+ memcpy(segment->sname, "TEMP1", 5);
+ memcpy(segment->fname, "MUMPS1.DAT", 10);
+ segment->fname_len = 10;
+ segment->blk_size = 2 * DISK_BLOCK_SIZE;
+ segment->allocation = 100;
+ segment->ext_blk_count = 100;
+ segment->cm_blk = 0;
+ segment->lock_space = 20;
+ memcpy(segment->defext, ".DAT", 4);
+ segment->global_buffers = 64;
+ segment->buckets = 0;
+ segment->windows = 0;
+ segment->acc_meth = dba_bg;
+ segment->defer_time = 0;
+ segment->file_cntl = 0;
+ status = sys$qiow(EFN$C_ENF, fab.fab$l_stv, IO$_WRITEVBLK, &iosb[0], 0, 0, header, size, 1, 0, 0, 0);
+ if (!(status & 1))
+ rts_error(VARLSTCNT(1) status);
+ if (!(iosb[0] & 1))
+ rts_error(VARLSTCNT(1) status);
+ sys$dassgn(fab.fab$l_stv);
+ region->rname_len = 5;
+ memcpy(region->rname,"TEMP2",5);
+ segment->sname_len = 5;
+ memcpy(segment->sname,"TEMP2",5);
+ memcpy(segment->fname,"MUMPS2.DAT",10);
+ segment->fname_len = 10;
+ fab.fab$l_fna = file_name2;
+ fab.fab$b_fns = SIZEOF(file_name3) - 1;
+ status = sys$create(&fab);
+ if (status != RMS$_CREATED && status != RMS$_FILEPURGED && status != RMS$_NORMAL)
+ sys$exit(status);
+ status = sys$qiow(EFN$C_ENF, fab.fab$l_stv, IO$_WRITEVBLK, &iosb[0], 0, 0, header, size, 1, 0, 0, 0);
+ if (!(status & 1))
+ rts_error(VARLSTCNT(1) status);
+ if (!(iosb[0] & 1))
+ rts_error(VARLSTCNT(1) status);
+ sys$dassgn(fab.fab$l_stv);
+ region->rname_len = 5;
+ memcpy(region->rname, "TEMP3", 5);
+ segment->sname_len = 5;
+ memcpy(segment->sname, "TEMP3", 5);
+ memcpy(segment->fname, "MUMPS3.DAT", 10);
+ segment->fname_len = 10;
+ fab.fab$l_fna = file_name3;
+ fab.fab$b_fns = SIZEOF(file_name3) - 1;
+ status = sys$create(&fab);
+ if (status != RMS$_CREATED && status != RMS$_FILEPURGED && status != RMS$_NORMAL)
+ sys$exit(status);
+ status = sys$qiow(EFN$C_ENF, fab.fab$l_stv, IO$_WRITEVBLK, &iosb[0], 0, 0, header, size, 1, 0, 0, 0);
+ if (!(status & 1))
+ rts_error(VARLSTCNT(1) status);
+ if (!(iosb[0] & 1))
+ rts_error(VARLSTCNT(1) status);
+ sys$dassgn(fab.fab$l_stv);
+
+/*************************** Run tests********************************************/
+ v.str.len = SIZEOF(file_name1) - 1;
+ v.str.addr = file_name1;
+ PRINTF("Open first global directory: dtgbld01.gld\n");
+ addr1 = zgbldir(&v);
+ PRINTF("Region name is %s, expected TEMP1\n", addr1->regions->rname);
+ PRINTF("Segment name is %s, expected TEMP1\n", addr1->regions->dyn.addr->sname);
+ PRINTF("File name is %s, expected MUMPS1.DAT\n", addr1->regions->dyn.addr->fname);
+ v.str.len = SIZEOF(file_name2) - 1;
+ v.str.addr = file_name2;
+ PRINTF("Open second global directory: dtgbld02.gld\n");
+ addr2 = zgbldir(&v);
+ PRINTF("Region name is %s, expected TEMP2\n", addr2->regions->rname);
+ PRINTF("Segment name is %s, expected TEMP2\n", addr2->regions->dyn.addr->sname);
+ PRINTF("File name is %s, expected MUMPS2.DAT\n", addr2->regions->dyn.addr->fname);
+ v.str.len = SIZEOF(file_name3) - 1;
+ v.str.addr = file_name3;
+ PRINTF("Open third global directory: dtgbld03.gld\n");
+ addr3 = zgbldir(&v);
+ PRINTF("Region name is %s, expected TEMP3\n", addr3->regions->rname);
+ PRINTF("Segment name is %s, expected TEMP3\n", addr3->regions->dyn.addr->sname);
+ PRINTF("File name is %s, expected MUMPS3.DAT\n", addr3->regions->dyn.addr->fname);
+ PRINTF("Open null string global directory: dtgbld01.gld\n");
+ v.str.len = 0;
+ addr = zgbldir(&v);
+ if (addr != addr1)
+ PRINTF("Expected pointer to previous struct, got new structure\n");
+ else
+ PRINTF("Got same pointer as expected.\n");
+ PRINTF("Open dtlog1 global directory: dtgbld02.gld\n");
+ v.str.len = SIZEOF(file_name4) - 1;
+ v.str.addr = file_name4;
+ addr = zgbldir(&v);
+ if (addr != addr2)
+ PRINTF("Expected pointer to previous struct, got new structure\n");
+ else
+ PRINTF("Got same pointer as expected.\n");
+ v.str.len = SIZEOF(file_name3) - 1;
+ v.str.addr = file_name3;
+ PRINTF("Reopen third global directory: dtgbld03.gld\n");
+ addr = zgbldir(&v);
+ if (addr != addr3)
+ PRINTF("Expected pointer to previous struct, got new structure\n");
+ else
+ PRINTF("Got same pointer as expected.\n");
+ return;
+}
diff --git a/sr_vvms/edrelbta.m b/sr_vvms/edrelbta.m
new file mode 100644
index 0000000..0c51e1b
--- /dev/null
+++ b/sr_vvms/edrelbta.m
@@ -0,0 +1,37 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ;
+; Copyright 2001, 2003 Sanchez Computer Associates, Inc. ;
+; ;
+; This source code contains the intellectual property ;
+; of its copyright holder(s), and is made available ;
+; under a license. If you do not know the terms of ;
+; the license, please stop and do not read further. ;
+; ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+edrelnam ; ; ; verify a proposed release name and update release_name.h
+ ;
+ set $zro="[]/src=([],gtm$vrt:[pct])"
+ Write "$ztrnlnm(""gtm_new_ver_id"") = """,$ztrnlnm("gtm_new_ver_id"),"""",!
+ set relnam=$$FUNC^%UCASE($ztrnlnm("gtm_new_ver_id")),suffix=$piece(relnam,"-",2)
+ if $p(relnam,"-")'?1"V"1.2N1"."1.2N&'((suffix?1.2N.1A)!(suffix?1"BL"1.2N)!(suffix?1"FT"1.2N)) do
+ . write !,"The parameter """,relnam,""" (gtm_new_ver_id) is not a valid format",!
+ . set $ztrap="" zmessage 2
+ set file="release_name.h",new="temp.tmp"
+ open file:(read:exception="goto noopen"),new:newversion
+ ;
+ Use file:exception="goto eof"
+ For Read line Do
+ . Use new
+ . If line["GTM_RELEASE_NAME" Do
+ . . Write $Piece(line,"V"),relnam,"-beta ",$Piece($Piece(line,"V",2,999)," ",2,99),!
+ . Else Do
+ . . If line["GTM_VERSION" Write $Piece(line,"V",1,2),$Piece(relnam,"-"),"""",!
+ . . Else Write line,!
+ . Use file:exception="goto eof"
+ Quit
+ ;
+eof close file,new:rename=file
+ quit
+ ;
+noopen write !,"Unable to open release_name.h",!
+ set $ztrap="" zmessage 2
diff --git a/sr_vvms/edrelnam.m b/sr_vvms/edrelnam.m
new file mode 100644
index 0000000..bc6f503
--- /dev/null
+++ b/sr_vvms/edrelnam.m
@@ -0,0 +1,37 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ;
+; Copyright 2001, 2003 Sanchez Computer Associates, Inc. ;
+; ;
+; This source code contains the intellectual property ;
+; of its copyright holder(s), and is made available ;
+; under a license. If you do not know the terms of ;
+; the license, please stop and do not read further. ;
+; ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+edrelnam ; ; ; verify a proposed release name and update release_name.h
+ ;
+ set $zro="[]/src=([],gtm$vrt:[pct])"
+ Write "$ztrnlnm(""gtm_new_ver_id"") = """,$ztrnlnm("gtm_new_ver_id"),"""",!
+ set relnam=$$FUNC^%UCASE($ztrnlnm("gtm_new_ver_id")),suffix=$piece(relnam,"-",2)
+ if $p(relnam,"-")'?1"V"1.2N1"."1.2N&'((suffix?1.2N.1A)!(suffix?1"BL"1.2N)!(suffix?1"FT"1.2N)) do
+ . write !,"The parameter """,relnam,""" (gtm_new_ver_id) is not a valid format",!
+ . set $ztrap="" zmessage 2
+ set file="release_name.h",new="temp.tmp"
+ open file:(read:exception="goto noopen"),new:newversion
+ ;
+ Use file:exception="goto eof"
+ For Read line Do
+ . Use new
+ . If line["GTM_RELEASE_NAME" Do
+ . . Write $Piece(line,"V"),relnam," ",$Piece($Piece(line,"V",2,999)," ",2,99),!
+ . Else Do
+ . . If line["GTM_VERSION" Write $Piece(line,"V",1,2),$Piece(relnam,"-"),"""",!
+ . . Else Write line,!
+ . Use file:exception="goto eof"
+ Quit
+ ;
+eof close file,new:rename=file
+ quit
+ ;
+noopen write !,"Unable to open release_name.h",!
+ set $ztrap="" zmessage 2
diff --git a/sr_vvms/efn.h b/sr_vvms/efn.h
new file mode 100644
index 0000000..a3f1d35
--- /dev/null
+++ b/sr_vvms/efn.h
@@ -0,0 +1,39 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2005 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include <efndef.h>
+
+enum efn_names
+{
+ efn_bg_qio_read = 3, /* According to the Programming Concepts Manual section on "Using Event Flags",
+ * event flag 0 is the default flag used by system routines.
+ * event flag 1 to 23 may be used in system routines.
+ * event flag 24 to 31 is reserved for Compaq/HP use only.
+ * event flags in cluster #1 i.e. flag # 32 to 63 are Local and Available for general use.
+ * However, we have not (yet) noticed any issues with our event flag usage. We'll stick with
+ * cluster 0 usage until we've had a chance to cleanup event flag usage
+ */
+ efn_bg_qio_write,
+ efn_ignore_obsolete,
+ efn_immed_wait, /* to be used whenever we are NOT in an AST and are going to WAIT */
+ efn_op_job,
+ efn_outofband,
+ efn_timer,
+ efn_sys_wait,
+ efn_2timer, /* used by gt.cm cmi */
+ efn_jnl,
+ efn_iott_write,
+ efn_cmi_immed_wait,
+ efn_cmi_mbx,
+ efn_timer_ast, /* to be used whenever we are in an AST and are going to WAIT */
+ efn_hiber_start, /* used by hiber_start when not in an AST */
+ efn_ignore = EFN$C_ENF
+};
diff --git a/sr_vvms/error_return.c b/sr_vvms/error_return.c
new file mode 100644
index 0000000..095396d
--- /dev/null
+++ b/sr_vvms/error_return.c
@@ -0,0 +1,97 @@
+/****************************************************************
+ * *
+ * Copyright 2010, 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_stdlib.h"
+#include "gtm_stdio.h"
+
+#include "error.h"
+#include "error_trap.h"
+#include "dollar_zlevel.h"
+#include <rtnhdr.h>
+#include "stack_frame.h"
+#include "golevel.h"
+#include "io.h"
+
+#define BASE_FRAME(fp) ((fp->type & SFT_DM))
+
+GBLREF stack_frame *frame_pointer;
+GBLREF unsigned short proc_act_type;
+GBLREF dollar_ecode_type dollar_ecode; /* structure containing $ECODE related information */
+GBLREF int mumps_status;
+GBLREF stack_frame *error_frame;
+GBLREF io_desc *gtm_err_dev;
+
+error_def(ERR_REPEATERROR);
+
+void error_return(void)
+{
+ int parent_level;
+ stack_frame *curframe, *cur_counted_frame, *parent_counted_frame;
+ boolean_t rethrow_needed = FALSE, dev_act_err;
+
+ DBGEHND((stderr, "error_return: Entered\n"));
+ assert((frame_pointer->flags & SFF_ETRAP_ERR) || (error_frame == frame_pointer));
+ /* Determine counted frame at the current $zlevel */
+ for (curframe = frame_pointer; (NULL != curframe) && !(curframe->type & SFT_COUNT) && !BASE_FRAME(curframe);
+ curframe = curframe->old_frame_pointer)
+ ;
+ cur_counted_frame = curframe;
+ NULLIFY_ERROR_FRAME; /* reset error_frame */
+ dev_act_err = ((NULL != cur_counted_frame) && (cur_counted_frame->flags & SFF_ETRAP_ERR)
+ && (cur_counted_frame->flags & SFF_DEV_ACT_ERR));
+ /* If the top level error is a device exception error, we do not want to unwind upto the parent frame but instead
+ * rethrow the error at the current level and use $ztrap/$etrap exception handling. In case even that fails,
+ * we will come again to error_return at which point, we will do the unwind upto the parent frame.
+ */
+ if (!dev_act_err && (NULL != curframe)) /* Determine counted frame at the parent $zlevel */
+ for (curframe = curframe->old_frame_pointer;
+ (NULL != curframe) && !(curframe->type & SFT_COUNT) && !BASE_FRAME(curframe);
+ curframe = curframe->old_frame_pointer)
+ ;
+ parent_counted_frame = curframe;
+ /* Exit if we are at the bottom of the stack */
+ parent_level = dollar_zlevel() - 1;
+ if ((NULL == parent_counted_frame) || (1 > parent_level))
+ EXIT(dollar_ecode.error_last_ecode);
+ assert(parent_level > 0);
+ if (dev_act_err || (!BASE_FRAME(parent_counted_frame) && dollar_ecode.index))
+ rethrow_needed = TRUE;
+ DBGEHND((stderr, "error_return: rethrow_needed: %d dev_act_err: %d\n", rethrow_needed, dev_act_err));
+ if (!dev_act_err)
+ {
+ if (parent_counted_frame->type & SFT_DM)
+ { /* hack to retain SFT_DM frame from being unwound by golevel */
+ parent_counted_frame->type |= SFT_COUNT;
+ GOLEVEL(parent_level + 1, FALSE);
+ parent_counted_frame->type &= ~SFT_COUNT;
+ assert(parent_counted_frame->type & SFT_DM);
+ } else
+ GOLEVEL(parent_level, FALSE);
+ /* Check that we have unwound exactly upto the parent counted frame. */
+ assert(parent_counted_frame == frame_pointer);
+ } else
+ {
+ GOLEVEL(parent_level + 1, FALSE);
+ /* Check that we have unwound exactly upto the current counted frame. */
+ assert(cur_counted_frame == frame_pointer);
+ }
+ assert(!proc_act_type);
+ if (rethrow_needed)
+ {
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_REPEATERROR);
+ assert(FALSE); /* the previous rts_error() should not return */
+ }
+ /* zero the error device just to be safe */
+ assert(NULL == gtm_err_dev);
+ gtm_err_dev = NULL;
+}
diff --git a/sr_vvms/errorsp.h b/sr_vvms/errorsp.h
new file mode 100644
index 0000000..262c89f
--- /dev/null
+++ b/sr_vvms/errorsp.h
@@ -0,0 +1,170 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef __ERRORSP_H__
+#define __ERRORSP_H__
+
+#include <ssdef.h>
+#include <errnodef.h>
+#include <chfdef.h>
+
+typedef unsigned int ch_ret_type;
+GBLREF int4 error_condition;
+
+#define CONDITION_HANDLER(name) \
+ ch_ret_type name(struct chf$signal_array *sig, struct chf$mech_array *mch)
+
+#define WARNING 0x00000000
+#define SUCCESS 0x00000001
+#define ERROR 0x00000002
+#define INFO 0x00000003
+#define SEVERE 0x00000004
+#define SEV_MSK 0x00000007
+
+#define SIGNAL sig->chf$l_sig_name
+#define SEVERITY (SIGNAL & SEV_MSK)
+
+#define FAC_MSK 0x08010000
+#define MSGCC_MASK 0x00FFFFF8
+#define NOT_EXC 4
+#define FACILITY_MASK (0x0FFF0000)
+#define GTM_FACILITY (0x08F60000)
+#define RMS_FACILITY (RMS$_FACILITY << 16)
+#define SYSTEM_FACILITY (SYSTEM$_FACILITY << 16)
+#define IS_GTM_ERROR(X) ((X & FACILITY_MASK) == GTM_FACILITY)
+#define IS_RMS_ERROR(X) ((X & FACILITY_MASK) == RMS_FACILITY)
+#define IS_SYSTEM_ERROR(X) ((X & FACILITY_MASK) == SYSTEM_FACILITY)
+/* Count of arguments the TPRETRY error will make available for tp_restart to use */
+#define TPRESTART_ARG_CNT 10 /* see comment in INVOKE_RESTART macro in tp.h */
+
+/* ***** If the system error was a hardware trap or a hardware fault the ***** */
+/* ***** PC and PSL are necessary for message output. In all other cases ***** */
+/* ***** the PC and PSL are removed from the signal argument list by ***** */
+/* ***** subtracting two from the argument count in sig->chf$l_sig_args. ***** */
+/* ***** If the severity code held in the first 3 bits of the argument ***** */
+/* ***** sig->chf$l_sig_name is 5, 6, or 7 (reserved for digital) it is ***** */
+/* ***** a fault or trap. ***** */
+
+#define ERROR_RTN error_return_vms
+
+#define TRAP (!(SIGNAL & FAC_MSK) && (SIGNAL & SEV_MSK) > NOT_EXC)
+
+#define PRN_ERROR { \
+ if (!(TRAP)) \
+ sig->chf$l_sig_args -= 2; \
+ if (0 < sig->chf$l_sig_args) \
+ sys$putmsg(sig, 0); \
+ }
+/* MUM_TSTART unwinds the current C-stack and restarts executing generated code from the top of the current M-stack */
+#define MUM_TSTART UNWIND(&mch->CHF_MCH_DEPTH, CODE_ADDRESS(mum_tstart))
+
+#define ESTABLISH_NOJMP(x) lib$establish(x)
+#define ESTABLISH_NOUNWIND(x) lib$establish(x)
+#define ESTABLISH_RET(x,ret) lib$establish(x)
+#define ESTABLISH(x) lib$establish(x)
+
+#define REVERT lib$revert()
+#define CONTINUE return SS$_CONTINUE
+#define NEXTCH return SS$_RESIGNAL
+#define UNWIND(X, Y) { \
+ int stat; \
+ stat = sys$unwind((X), (Y)); \
+ if ((SS$_NORMAL != stat) && (SS$_UNWINDING != stat)) \
+ EXIT(stat); \
+ return SS$_NORMAL; \
+ }
+
+#define START_CH error_def(ERR_TPRETRY); \
+ DCL_THREADGBL_ACCESS; \
+ \
+ SETUP_THREADGBL_ACCESS; \
+ if (SIGNAL != ERR_TPRETRY) \
+ { \
+ if (SIGNAL == SS$_UNWIND) \
+ return SS$_NORMAL; \
+ if (SIGNAL == SS$_DEBUG) \
+ return SS$_RESIGNAL; \
+ if ((SIGNAL & MSGCC_MASK) == (C$_SIGUSR1 & MSGCC_MASK)) \
+ { /* Ignore signal if no handler. Call handler as AST */ \
+ /* because deferred_events() needs it that way. */ \
+ /* Ignore errors 'cause we can't handle them now anyway */ \
+ if (NULL != RFPTR(gtm_sigusr1_handler)) \
+ if (lib$ast_in_prog()) \
+ IVFPTR(gtm_sigusr1_handler); \
+ else \
+ sys$dclast(RFPTR(gtm_sigusr1_handler), 0, 0); \
+ return SS$_CONTINUE; \
+ } \
+ error_condition = SIGNAL; \
+ }
+
+#define MDB_START { \
+ ESTABLISH(terminate_ch); \
+ if (cs_addrs && cs_addrs->hdr && cs_addrs->hdr->clustered) \
+ sys$cantim(&cs_addrs->hdr->clustered, 0); \
+ }
+
+#define TERMINATE { \
+ lib$sig_to_stop(sig, mch); \
+ return SS$_RESIGNAL; \
+ }
+
+#define SUPPRESS_DUMP (FALSE)
+#define DUMP_CORE TERMINATE
+
+#define MUMPS_EXIT { \
+ mumps_status = SIGNAL; \
+ GOLEVEL(0, FALSE); \
+ MUM_TSTART; \
+ }
+#define PROCDIE(x) EXIT(x)
+#define EXIT(x) sys$exit(x)
+
+#define DUMP ( SIGNAL == SS$_ACCVIO \
+ || SIGNAL == SS$_ASTFLT \
+ || SIGNAL == SS$_OPCCUS \
+ || SIGNAL == SS$_OPCDEC \
+ || SIGNAL == SS$_PAGRDERR \
+ || SIGNAL == SS$_RADRMOD \
+ || SIGNAL == SS$_ROPRAND \
+ || SIGNAL == ERR_ASSERT \
+ || SIGNAL == ERR_GTMASSERT \
+ || SIGNAL == ERR_GTMASSERT2 \
+ || SIGNAL == ERR_GTMCHECK /* BYPASSOK */ \
+ || SIGNAL == ERR_VMSMEMORY \
+ || SIGNAL == ERR_STACKOFLOW )
+
+/* true if one of above or SEVERE and GTM error or SYSTEM error */
+#define DUMPABLE ( DUMP || (SEVERITY == SEVERE && \
+ ( IS_GTM_ERROR(SIGNAL))))
+
+unsigned char *set_zstatus(mstr *src, struct chf$signal_array *sig, unsigned char **ctxtp, boolean_t need_rtsloc);
+
+#define SET_ZSTATUS(ctxt) set_zstatus(&src_line_d, sig, ctxt, TRUE)
+#define MSG_OUTPUT !(SIGNAL & 0xF0000000)
+
+
+#define EXIT_HANDLER(x) sys$dclexh(x)
+
+#define SEND_CALLERID(callee) send_msg_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_CALLERID, 3, LEN_AND_STR((callee)), caller_id());
+#define PRINT_CALLERID util_out_print(" -- generated from 0x!XL.", NOFLUSH, caller_id());
+#define MAKE_MSG_WARNING(x) ((x) & ~SEV_MSK | WARNING)
+#define MAKE_MSG_SUCCESS(x) ((x) & ~SEV_MSK | SUCCESS)
+#define MAKE_MSG_ERROR(x) ((x) & ~SEV_MSK | ERROR)
+#define MAKE_MSG_INFO(x) ((x) & ~SEV_MSK | INFO)
+#define MAKE_MSG_SEVERE(x) ((x) & ~SEV_MSK | SEVERE)
+#define MAX_MSG_SIZE 256
+
+CONDITION_HANDLER(ccp_ch);
+CONDITION_HANDLER(ccp_exi_ch);
+CONDITION_HANDLER(ojch);
+
+#endif
diff --git a/sr_vvms/ether_trace.c b/sr_vvms/ether_trace.c
new file mode 100644
index 0000000..fed5cd8
--- /dev/null
+++ b/sr_vvms/ether_trace.c
@@ -0,0 +1,100 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "nmadef.h"
+#include "ddphdr.h"
+#include <descrip.h>
+#include <iodef.h>
+#include <efndef.h>
+#include "util.h"
+#include "ddp_trace_output.h"
+
+
+unsigned char packet_header[20];
+unsigned char local_buffer[1000];
+char *buffer_top = local_buffer;
+
+#define CHECK_STATUS if ((status & 1) == 0) lib$signal(status);
+#define CHECK_IOSB if ((status & 1) != 0) status = ether_iosb.result ; CHECK_STATUS;
+int ether_trace(void)
+{
+ int4 status;
+ char ether_string[] = "ESA0";
+ $DESCRIPTOR(ether_name, ether_string);
+ $DESCRIPTOR(output_qual, "OUTPUT");
+ int4 ether_channel = 0;
+ int i;
+ struct
+ {
+ unsigned short result;
+ short length;
+ int4 devspec;
+ } ether_iosb;
+ struct
+ {
+ short param_id;
+ int4 param_value;
+ } set_parm_array[] =
+ {
+ {
+ NMA$C_PCLI_PRM, NMA$C_STATE_ON
+ }
+ };
+ struct dsc$descriptor_s set_parm;
+
+ util_out_open(&output_qual);
+ set_parm.dsc$w_length = SIZEOF(set_parm_array);
+ set_parm.dsc$a_pointer = set_parm_array;
+ set_parm.dsc$b_dtype = 0;
+ set_parm.dsc$b_class = 0;
+ status = sys$assign (
+ ðer_name,
+ ðer_channel,
+ 0,
+ 0);
+ CHECK_STATUS;
+ status = sys$qiow (
+ 0,
+ ether_channel,
+ IO$_SETMODE | IO$M_CTRL | IO$M_STARTUP,
+ ðer_iosb,
+ 0,
+ 0,
+ 0,
+ &set_parm,
+ 0,
+ 0,
+ 0,
+ 0);
+ CHECK_IOSB;
+ for (i = 0 ; i < 2000 ; i++)
+ {
+retry:
+ status = sys$qiow(EFN$C_ENF,
+ ether_channel,
+ IO$_READPBLK,
+ ðer_iosb,
+ 0,
+ 0,
+ buffer_top, 1500, 0, 0, packet_header, 0);
+ CHECK_IOSB;
+ if (packet_header[0] != 0xAA && packet_header[6] != 0xAA)
+ goto retry;
+/* util_out_write("Packet", SIZEOF("Packet"));
+ ddp_trace_output(packet_header, SIZEOF(packet_header));
+ ddp_trace_output(buffer_top, ether_iosb.length);
+*/
+ ddp_trace_output(buffer_top, 30, DDP_RECV);
+ }
+ util_out_close();
+ return 1;
+}
diff --git a/sr_vvms/exi_ch.c b/sr_vvms/exi_ch.c
new file mode 100644
index 0000000..193b021
--- /dev/null
+++ b/sr_vvms/exi_ch.c
@@ -0,0 +1,31 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <signal.h> /* for VSIG_ATOMIC_T type */
+
+#include "error.h"
+#include "have_crit.h"
+
+
+#define UNWIND_LEVELS 4
+/* 0 unwinds EXI_CH, 1 unwinds EXI_RUNDOWN, 2,3 and 4 unwind the three VMS handlers,
+ thus returning to pc was at when the exit condition was received. */
+
+static int depth = UNWIND_LEVELS;
+
+CONDITION_HANDLER(exi_ch)
+{
+ START_CH;
+ SET_FORCED_EXIT_STATE;
+ UNWIND(&depth, NULL);
+}
diff --git a/sr_vvms/exttime.c b/sr_vvms/exttime.c
new file mode 100644
index 0000000..7d24a89
--- /dev/null
+++ b/sr_vvms/exttime.c
@@ -0,0 +1,37 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2002 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "jnl.h"
+
+int exttime(uint4 short_time, char *buffer, int extract_len)
+{
+ char *p;
+ jnl_proc_time VMS_time;
+ uint4 days, h_seconds;
+
+ JNL_WHOLE_FROM_SHORT_TIME(VMS_time, short_time);
+ /* Convert the VMS time to the number of days since the system
+ zero date, and the number of hundredths of a second since midnight */
+ lib$day(&days, &VMS_time, &h_seconds);
+ /* Convert days and h_seconds to $Horolog format */
+ p = i2asc((unsigned char *)(buffer + extract_len), days + DAYS);
+ *p++ = ',';
+ p = i2asc(p, h_seconds / CENTISECONDS);
+ *p++ = '\\';
+ return p - buffer;
+}
diff --git a/sr_vvms/f_piece.c b/sr_vvms/f_piece.c
new file mode 100644
index 0000000..91239dc
--- /dev/null
+++ b/sr_vvms/f_piece.c
@@ -0,0 +1,88 @@
+/****************************************************************
+ * *
+ * Copyright 2006, 2011 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include "compiler.h"
+#include "opcode.h"
+#include "toktyp.h"
+#include "advancewindow.h"
+#include "fnpc.h"
+
+error_def(ERR_COMMA);
+
+int f_piece(oprtype *a, opctype op)
+{
+ delimfmt unichar;
+ mval *delim_mval;
+ oprtype x;
+ triple *delimiter, *first, *last, *r, *srcislit;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ r = maketriple(op);
+ if (EXPR_FAIL == expr(&(r->operand[0]), MUMPS_STR))
+ return FALSE;
+ if (TK_COMMA != TREF(window_token))
+ {
+ stx_error(ERR_COMMA);
+ return FALSE;
+ }
+ advancewindow();
+ delimiter = newtriple(OC_PARAMETER);
+ r->operand[1] = put_tref(delimiter);
+ first = newtriple(OC_PARAMETER);
+ delimiter->operand[1] = put_tref(first);
+ if (EXPR_FAIL == expr(&x, MUMPS_STR))
+ return FALSE;
+ if (TK_COMMA != TREF(window_token))
+ first->operand[0] = put_ilit(1);
+ else
+ {
+ advancewindow();
+ if (EXPR_FAIL == expr(&(first->operand[0]), MUMPS_INT))
+ return FALSE;
+ }
+ assert(TRIP_REF == x.oprclass);
+ if ((TK_COMMA != TREF(window_token)) && (OC_LIT == x.oprval.tref->opcode)
+ && (1 == x.oprval.tref->operand[0].oprval.mlit->v.str.len))
+ { /* Single char delimiter */
+ delim_mval = &x.oprval.tref->operand[0].oprval.mlit->v;
+ unichar.unichar_val = 0;
+ r->opcode = OC_FNP1;
+ unichar.unibytes_val[0] = *delim_mval->str.addr;
+ delimiter->operand[0] = put_ilit(unichar.unichar_val);
+ srcislit = newtriple(OC_PARAMETER);
+ first->operand[1] = put_tref(srcislit);
+ } else
+ {
+ delimiter->operand[0] = x;
+ last = newtriple(OC_PARAMETER);
+ first->operand[1] = put_tref(last);
+ if (TK_COMMA != TREF(window_token))
+ last->operand[0] = first->operand[0];
+ else
+ {
+ advancewindow();
+ if (EXPR_FAIL == expr(&(last->operand[0]), MUMPS_INT))
+ return FALSE;
+ }
+ srcislit = newtriple(OC_PARAMETER);
+ last->operand[1] = put_tref(srcislit);
+ }
+ /* Pass value 1 (TRUE) if src string is a literal, else 0 (FALSE) */
+ srcislit->operand[0] = put_ilit((OC_LIT == r->operand[0].oprval.tref->opcode) ? TRUE : FALSE);
+ ins_triple(r);
+ *a = put_tref(r);
+ return TRUE;
+}
diff --git a/sr_vvms/fetch_cms_version.com b/sr_vvms/fetch_cms_version.com
new file mode 100644
index 0000000..20b4925
--- /dev/null
+++ b/sr_vvms/fetch_cms_version.com
@@ -0,0 +1,90 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2003 Sanchez Computer Associates, Inc. !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$! fetch_cms_version.com - fetch CMS elements for a specific version (class)
+$!
+$! p1 - "from version" class name (version name with punctuation; e.g. "V3.2-015")
+$! p2 - CMS library list (e.g., S_SUN or S_UNIX_CM)
+$!
+$! This command file fetches the elements from CMS libraries; depending on
+$! its arguments, it will fetch either the most recent generations on the main line
+$! of descent or the generations corresponding to any release for which we have
+$! created a CMS class. Its complexity is due to the requirement to handle elements
+$! present in old releases that have subsequently been NIX'ed.
+$!
+$ if (f$extract(0,4,p1) .eqs. "V9.9" .or. p1 .eqs. "NEXT" )
+$ then
+$ write sys$output ""
+$ write sys$output "MOST RECENT GENERATIONS IN THE MAIN LINE OF DESCENT ARE BEING DOWNLOADED ..."
+$ write sys$output "Fetching version ", p1
+$!
+$! Get the most recent generation on the main line of descent of all source files:
+$ cms set library 'p2'
+$ cms fetch *.* ""
+$!
+$! If release_name.h is present, modify the release number to target_version.
+$ if (f$search("release_name.h") .nes. "")
+$ then
+$ if f$search("edrelnam.obj") .nes. ""
+$ then
+$ delete edrelnam.obj;* ! in case it's for the wrong CPU
+$ endif
+$ version p p ! production version should always be present and working
+$ define/user gtm_new_ver_id 'p1'
+$ gtm ! Set to correct version
+set $zroutines="[]/src=([],gtm$src,gtm$vrt:[pct])"
+d ^edrelnam
+$ delete release_name.h;1
+$ delete edrelnam.obj;*
+$ rename release_name.h;2 release_name.h;1
+$ endif
+$!
+$! Don't bother processing NIX'ed files; they don't belong in "most recent" version.
+$ directory *.*nix
+$ if f$search("*.*nix;*") .nes. "" then delete/log *.*nix;*
+$ else
+$ write sys$output "Fetching version ", p1
+$!
+$! Because this is a configured version and not just the most recent on the
+$! main line of descent, it's possible some of the elements in this version
+$! have been NIX'ed since the version was created. For this reason, we need
+$! to go through each component CMS source library, one at a time, and change
+$! any NIX'ed files back to their original names. This is necessary in order
+$! to preserve proper occlusion behavior.
+$!
+$ lib_ind = 0
+$ lib_cnt = f$trnlnm(p2,,,,,"MAX_INDEX")
+$lib_loop:
+$ lib = f$trnlnm(p2,,lib_ind)
+$ cms set library 'lib'
+$ cms fetch *.*/gen='p1' ""
+$ show symbol $status
+$nix_loop:
+$ nixname = f$search("*.*NIX")
+$ if (nixname .eqs. "") then goto end_nixloop
+$ nixname = nixname - f$parse(nixname,,,"VERSION")
+$ basename = nixname - "NIX"
+$ rename/log 'nixname' 'basename'
+$ goto nix_loop
+$end_nixloop:
+$ lib_ind = lib_ind + 1
+$ if (lib_ind .le. lib_cnt) then goto lib_loop
+$!
+$ endif
+$ directory
+$!
+$! Delete duplicates that should have been superseded by previous versions:
+$ if f$search("*.*;4") .nes. "" then delete/log *.*;4
+$ if f$search("*.*;3") .nes. "" then delete/log *.*;3
+$ if f$search("*.*;2") .nes. "" then delete/log *.*;2
+$!
+$ccfini:
+$ directory
diff --git a/sr_vvms/fgn_parms.c b/sr_vvms/fgn_parms.c
new file mode 100644
index 0000000..65fc51c
--- /dev/null
+++ b/sr_vvms/fgn_parms.c
@@ -0,0 +1,50 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "compiler.h"
+#include <descrip.h>
+#include "desc2mval.h"
+
+static readonly mval empty_mv;
+static mval ret_mv;
+
+int fgn_parms(
+int output,
+mval *margs[],
+int maxargs,
+int *fgnargs)
+{
+ int i,argcnt, *fparms;
+ mval **v;
+ error_def(ERR_MAXACTARG);
+
+ v = margs;
+ fparms = fgnargs;
+ argcnt = *fparms++;
+ if (output)
+ { argcnt--;
+ fparms++;
+ margs[maxargs] = &ret_mv; /* extra slot on the end just to take return value */
+
+ }
+ else
+ margs[maxargs] = 0;
+
+ if (argcnt > MAX_ACTUALS)
+ rts_error(VARLSTCNT(1) ERR_MAXACTARG);
+
+ for (i = 0; i < argcnt; i++)
+ { *v = push_mval(&empty_mv);
+ desc2mval(*fparms++, *v++);
+ }
+ return argcnt;
+}
diff --git a/sr_vvms/fgn_resolve_lab.c b/sr_vvms/fgn_resolve_lab.c
new file mode 100644
index 0000000..5b09c17
--- /dev/null
+++ b/sr_vvms/fgn_resolve_lab.c
@@ -0,0 +1,22 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <rtnhdr.h>
+
+GBLDEF mval fgn_label = DEFINE_MVAL_STRING(MV_STR, 0, 0, 0, NULL, 0, 0);
+
+USHBIN_ONLY(lnr_tabent **) NON_USHBIN_ONLY(lnr_tabent *) fgn_resolve_lab(rhdtyp *rtn, int lab_len, char* lab_name)
+{
+ fgn_label.str.len = lab_len;
+ fgn_label.str.addr = lab_name;
+ return op_labaddr(rtn, &fgn_label, 0);
+}
diff --git a/sr_vvms/fgncal_ch.c b/sr_vvms/fgncal_ch.c
new file mode 100644
index 0000000..9f5d22a
--- /dev/null
+++ b/sr_vvms/fgncal_ch.c
@@ -0,0 +1,61 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "lv_val.h"
+#include "error.h"
+#include "op.h"
+#include "io.h"
+#include "fgncal.h"
+
+GBLREF lv_val *active_lv;
+GBLREF sgmnt_addrs *cs_addrs;
+GBLREF int mumps_status;
+
+error_def(ERR_ASSERT);
+error_def(ERR_GTMASSERT);
+error_def(ERR_GTMASSERT2);
+error_def(ERR_GTMCHECK);
+error_def(ERR_STACKOFLOW);
+error_def(ERR_VMSMEMORY);
+
+CONDITION_HANDLER(fgncal_ch)
+{
+ int4 status;
+
+ START_CH;
+ if (DUMP)
+ {
+ gtm_dump();
+ NEXTCH;
+ }
+ MDB_START;
+ if (active_lv)
+ {
+ if (!LV_IS_VAL_DEFINED(active_lv) && !LV_HAS_CHILD(active_lv))
+ op_kill(active_lv);
+ active_lv = (lv_val *)0;
+ }
+ set_zstatus(NULL, sig, NULL, FALSE);
+ if (SEVERITY == SEVERE)
+ EXIT(SIGNAL);
+ fgncal_unwind();
+ mumps_status = SIGNAL;
+ mch->CHF_MCH_SAVR0 = mumps_status;
+ UNWIND(NULL, NULL);
+}
diff --git a/sr_vvms/fgncal_rundown.c b/sr_vvms/fgncal_rundown.c
new file mode 100644
index 0000000..814f1ef
--- /dev/null
+++ b/sr_vvms/fgncal_rundown.c
@@ -0,0 +1,60 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <psldef.h>
+#include <descrip.h>
+#include "gtm_inet.h"
+
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "iotimer.h"
+#include "repl_msg.h" /* needed by gtmsource.h */
+#include "gtmsource.h" /* needed for jnlpool_addrs and etc. */
+#include "repl_shm.h" /* needed for DETACH_FROM_JNLPOOL macro */
+#include "op.h"
+#include <rtnhdr.h>
+#include "lv_val.h" /* needed for "fgncal.h" */
+#include "fgncal.h"
+#include "gv_rundown.h"
+#include "filestruct.h"
+#include "jnl.h"
+#include "dpgbldir.h"
+
+GBLREF gv_key *gv_currkey;
+GBLREF boolean_t pool_init;
+GBLREF jnlpool_addrs jnlpool;
+GBLREF jnlpool_ctl_ptr_t jnlpool_ctl;
+GBLREF uint4 dollar_tlevel;
+
+void fgncal_rundown(void)
+{
+ sys$cantim(0,0); /* cancel all outstanding timers. prevents unwelcome surprises */
+ if (gv_currkey != NULL)
+ {
+ gv_currkey->end = 0; /* key no longer valid, since all databases are closed */
+ gv_currkey->base[0] = 0;
+ }
+ finish_active_jnl_qio();
+ DETACH_FROM_JNLPOOL(pool_init, jnlpool, jnlpool_ctl);
+ if (dollar_tlevel)
+ OP_TROLLBACK(0);
+ op_lkinit();
+ op_unlock();
+ op_zdeallocate(NO_M_TIMEOUT);
+ gv_rundown(); /* run down all databases */
+ gd_rundown();
+}
diff --git a/sr_vvms/fgncal_zlinit.c b/sr_vvms/fgncal_zlinit.c
new file mode 100644
index 0000000..c6173b3
--- /dev/null
+++ b/sr_vvms/fgncal_zlinit.c
@@ -0,0 +1,23 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+void fgncal_zlinit (void)
+{
+ void fgncal_rtn(), gtm$fgncall();
+ bool dummy;
+
+ dummy = zlput_rname(CODE_ADDRESS(fgncal_rtn));
+ assert(TRUE == dummy);
+ dummy = zlput_rname(CODE_ADDRESS(gtm$fgncall));
+ assert(TRUE == dummy);
+}
diff --git a/sr_vvms/fgncalsp.h b/sr_vvms/fgncalsp.h
new file mode 100644
index 0000000..93d876a
--- /dev/null
+++ b/sr_vvms/fgncalsp.h
@@ -0,0 +1,17 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef __FGNCALSP_H__
+#define __FGNCALSP_H__
+
+void fgncal_zlinit (void);
+
+#endif
diff --git a/sr_vvms/fid_from_sec.c b/sr_vvms/fid_from_sec.c
new file mode 100644
index 0000000..8ddb2d4
--- /dev/null
+++ b/sr_vvms/fid_from_sec.c
@@ -0,0 +1,43 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include <descrip.h>
+
+#define PREFIX_SIZE 4
+
+fid_from_sec(section,file)
+struct dsc$descriptor *section;
+gds_file_id *file;
+{
+ int i, j, k, l = 0;
+ char *cptr, *ctop;
+
+ /* See the routine GLOBAL_NAME for the encoding algorithm. Keep these two routines in tandom */
+
+ for (cptr = ctop = section->dsc$a_pointer + section->dsc$w_length - 1; *cptr != '$'; cptr--)
+ ;
+ file->dvi[0] = (cptr - section->dsc$a_pointer) - PREFIX_SIZE;
+ memcpy (&file->dvi[1], (char *)section->dsc$a_pointer + 4, file->dvi[0]);
+ for ( i = (SIZEOF(file->fid) / SIZEOF(file->fid[0])) - 1; i >= 0 ; i--)
+ { for ( j = 0; j < SIZEOF(file->fid[0]) * 2 ; j++, ctop--)
+ { k = *ctop - (*ctop > '9' ? 55 : 48);
+ l = (l << 4) + k;
+ }
+ file->fid[i] = l;
+ }
+ return;
+}
diff --git a/sr_vvms/fid_from_sec.h b/sr_vvms/fid_from_sec.h
new file mode 100644
index 0000000..084140e
--- /dev/null
+++ b/sr_vvms/fid_from_sec.h
@@ -0,0 +1,17 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef FID_FROM_SEC_INCLUDED
+#define FID_FROM_SEC_INCLUDED
+
+int fid_from_sec(struct dsc$descriptor *section, gds_file_id *file); /***type int added***/
+
+#endif /* FID_FROM_SEC_INCLUDED */
diff --git a/sr_vvms/file_head_read.c b/sr_vvms/file_head_read.c
new file mode 100644
index 0000000..c87fade
--- /dev/null
+++ b/sr_vvms/file_head_read.c
@@ -0,0 +1,97 @@
+/****************************************************************
+ * *
+ * Copyright 2003, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+#include <descrip.h>
+#include <rms.h>
+#include <climsgdef.h>
+#include <iodef.h>
+#include <efndef.h>
+#include <ssdef.h>
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "gtmio.h"
+#include "gtmmsg.h"
+#include "iosb_disk.h"
+#include "iosp.h"
+/*
+ * This is a plain way to read file header.
+ * User needs to take care of concurrency issue etc.
+ * Parameters :
+ * fn : full name of a database file.
+ * header: Pointer to database file header structure (may not be in shared memory)
+ * len: size of header (may be just SGMNT_HDR_LEN or SIZEOF_FILE_HDR_MAX)
+ */
+boolean_t file_head_read(char *fn, sgmnt_data_ptr_t header, int4 len)
+{
+ int header_size;
+ int4 status1;
+ uint4 status2;
+ io_status_block_disk iosb;
+ struct FAB fab;
+ struct XABFHC xabfhc;
+
+ error_def(ERR_DBOPNERR);
+ error_def(ERR_DBFILOPERR);
+ error_def(ERR_DBNOTGDS);
+
+ header_size = SIZEOF(sgmnt_data);
+ fab = cc$rms_fab;
+ fab.fab$l_fna = fn;
+ fab.fab$b_fns = strlen(fn);
+ fab.fab$b_fac = FAB$M_GET;
+ fab.fab$l_fop = FAB$M_UFO;
+ fab.fab$b_shr = FAB$M_SHRPUT | FAB$M_SHRGET | FAB$M_UPI;
+ xabfhc = cc$rms_xabfhc;
+ fab.fab$l_xab = &xabfhc;
+ status1 = sys$open(&fab);
+ if ((status1 & 1) == 0)
+ {
+ gtm_putmsg(VARLSTCNT(6) ERR_DBOPNERR, 2, LEN_AND_STR(fn), status1, fab.fab$l_stv);
+ return FALSE;
+ }
+ status2 = SS_NORMAL;
+ DO_FILE_READ(fab.fab$l_stv, 0, header, header_size, status1, status2);
+ if (!(status1 & 1))
+ {
+ sys$dassgn(fab.fab$l_stv);
+ gtm_putmsg(VARLSTCNT(5) ERR_DBFILOPERR, 2, LEN_AND_STR(fn), status1);
+ return FALSE;
+ }
+ if (memcmp(header->label, GDS_LABEL, GDS_LABEL_SZ - 1))
+ {
+ sys$dassgn(fab.fab$l_stv);
+ gtm_putmsg(VARLSTCNT(4) ERR_DBNOTGDS, 2, LEN_AND_STR(fn));
+ return FALSE;
+ }
+ assert(MASTER_MAP_SIZE_MAX >= MASTER_MAP_SIZE(header));
+ assert(SGMNT_HDR_LEN == len || SIZEOF_FILE_HDR(header) <= len);
+ if (SIZEOF_FILE_HDR(header) <= len)
+ {
+ status2 = SS_NORMAL;
+ DO_FILE_READ(fab.fab$l_stv, ROUND_UP(SGMNT_HDR_LEN + 1, DISK_BLOCK_SIZE), MM_ADDR(header),
+ MASTER_MAP_SIZE(header), status1, status2);
+ if (!(status1 & 1))
+ {
+ sys$dassgn(fab.fab$l_stv);
+ gtm_putmsg(VARLSTCNT(5) ERR_DBFILOPERR, 2, LEN_AND_STR(fn), status1);
+ return FALSE;
+ }
+ }
+ sys$dassgn(fab.fab$l_stv); /* use sys$dassgn (not sys$close) since FAB$M_UFO was specified in fab$l_fop in open */
+ return TRUE;
+}
diff --git a/sr_vvms/file_head_write.c b/sr_vvms/file_head_write.c
new file mode 100644
index 0000000..ff17f14
--- /dev/null
+++ b/sr_vvms/file_head_write.c
@@ -0,0 +1,80 @@
+/****************************************************************
+ * *
+ * Copyright 2003, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+#include <descrip.h>
+#include <rms.h>
+#include <climsgdef.h>
+#include <iodef.h>
+#include <efndef.h>
+#include <ssdef.h>
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "gtmio.h"
+#include "gtmmsg.h"
+#include "iosb_disk.h"
+#include "iosp.h"
+
+error_def(ERR_DBFILOPERR);
+error_def(ERR_DBNOTGDS);
+error_def(ERR_DBOPNERR);
+
+/*
+ * This is a plain way to write file header.
+ * User needs to take care of concurrency issue etc.
+ * Parameters :
+ * fn : full name of a database file.
+ * header: Pointer to database file header structure (may not be in shared memory)
+ * len: length of header to write (should be either SGMNT_HDR_LEN or SIZEOF_FILE_HDR(header))
+ */
+boolean_t file_head_write(char *fn, sgmnt_data_ptr_t header, int4 len)
+{
+ int header_size;
+ int4 status1;
+ uint4 status2;
+ io_status_block_disk iosb;
+ struct FAB fab;
+ struct XABFHC xabfhc;
+
+ header_size = SIZEOF_FILE_HDR(header);
+ assert(SGMNT_HDR_LEN == len || header_size == len);
+ fab = cc$rms_fab;
+ fab.fab$l_fna = fn;
+ fab.fab$b_fns = strlen(fn);
+ fab.fab$b_shr = FAB$M_SHRPUT | FAB$M_SHRGET | FAB$M_UPI;
+ fab.fab$b_fac = FAB$M_GET | FAB$M_PUT | FAB$M_UPD ;
+ fab.fab$l_fop = FAB$M_UFO;
+ xabfhc = cc$rms_xabfhc;
+ fab.fab$l_xab = &xabfhc;
+ status1 = sys$open(&fab);
+ if ((status1 & 1) == 0)
+ {
+ gtm_putmsg(VARLSTCNT(6) ERR_DBOPNERR, 2, LEN_AND_STR(fn), status1, fab.fab$l_stv);
+ return FALSE;
+ }
+ status2 = SS_NORMAL;
+ DB_DO_FILE_WRITE(fab.fab$l_stv, 0, header, len, status1, status2);
+ if (!(status1 & 1))
+ {
+ sys$dassgn(fab.fab$l_stv); /* use sys$dassgn (not sys$close) since FAB$M_UFO was specified
+ in fab$l_fop in open */
+ gtm_putmsg(VARLSTCNT(5) ERR_DBFILOPERR, 2, LEN_AND_STR(fn), status1);
+ return FALSE;
+ }
+ sys$dassgn(fab.fab$l_stv);
+ return TRUE;
+}
diff --git a/sr_vvms/filestruct.h b/sr_vvms/filestruct.h
new file mode 100644
index 0000000..4c2e3e1
--- /dev/null
+++ b/sr_vvms/filestruct.h
@@ -0,0 +1,54 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* filestruct.h */
+
+#include "gdsdbver.h"
+
+#define GDS_LABEL_GENERIC "GDSDYNSEG"
+#define GDS_LABEL GDS_LABEL_GENERIC GDS_CURR /* This string must be of length GDS_LABEL_SZ */
+#define GDS_RPL_LABEL "GDSRPLUNX03" /* This string must be of length GDS_LABEL_SZ */
+
+typedef struct vms_gds_info_struct /* BG and MM databases */
+{
+ struct FAB *fab;
+ struct NAM *nam;
+ struct XABFHC *xabfhc;
+ sgmnt_addrs s_addrs;
+ gds_file_id file_id;
+ vms_lock_sb file_cntl_lsb; /* replaces gd_region lsb */
+ vms_lock_sb cx_cntl_lsb; /* replaces gd_region ref_lsb */
+ struct XABPRO *xabpro;
+} vms_gds_info;
+
+typedef struct vms_gd_info_struct /* Global Directories */
+{
+ struct FAB *fab;
+ struct NAM *nam;
+} vms_gd_info;
+
+typedef struct vms_file_info_struct /* sequential files used by MUPIP */
+{
+ struct FAB *fab;
+ struct NAM *nam;
+ struct RAB *rab;
+} vms_file_info;
+
+#define FILE_INFO(reg) ((vms_gds_info *)(reg)->dyn.addr->file_cntl->file_info)
+#define FILE_ID(reg) ((vms_gds_info *)(reg)->dyn.addr->file_cntl->file_info)->file_id
+#define GDS_INFO vms_gds_info
+#define FI_FN(file_info) ((vms_file_info *)file_info)->fab->fab$b_fns
+#define FI_FN_LEN(file_info) ((vms_file_info *)file_info)->fab->fab$l_fna
+
+#define REG_EQUAL(fileinfo,reg) (memcmp(&(fileinfo)->file_id, &FILE_INFO(reg)->file_id, SIZEOF(gds_file_id)) == 0)
+#define WINDOW_ALL 255
+#define WRT_STRT_PNDNG (unsigned short)65534 /* the code assumes this is non-zero, even,
+ and that VMS never uses its value for iosb.cond */
diff --git a/sr_vvms/finish_active_jnl_qio.c b/sr_vvms/finish_active_jnl_qio.c
new file mode 100644
index 0000000..b03b049
--- /dev/null
+++ b/sr_vvms/finish_active_jnl_qio.c
@@ -0,0 +1,57 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "jnl.h"
+#include "send_msg.h"
+#include "sleep_cnt.h"
+#include "dpgbldir.h"
+#include "wcs_sleep.h"
+
+void finish_active_jnl_qio(void)
+{
+ gd_addr *addr_ptr;
+ gd_region *reg, *r_top;
+ int4 lcnt;
+ sgmnt_addrs *csa;
+ jnl_private_control *jpc;
+
+ error_def(ERR_JNLFLUSH);
+
+ for (addr_ptr = get_next_gdr(NULL); addr_ptr; addr_ptr = get_next_gdr(addr_ptr))
+ {
+ for (reg = addr_ptr->regions, r_top = reg + addr_ptr->n_regions; reg < r_top; reg++)
+ {
+ if (reg->open && !reg->was_open && (NULL != (csa = &FILE_INFO(reg)->s_addrs)) && (NULL != csa->hdr)
+ && (JNL_ENABLED(csa->hdr) && (NULL != (jpc = csa->jnl)) && (NULL != jpc->jnl_buff)))
+ {
+ for (lcnt = 1; (FALSE != jpc->qio_active) && (0 == jpc->jnl_buff->iosb.cond); lcnt++)
+ {
+ if (lcnt <= JNL_MAX_FLUSH_TRIES)
+ wcs_sleep(lcnt);
+ else
+ {
+ jnl_send_oper(jpc, ERR_JNLFLUSH);
+ assert(FALSE);
+ break;
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/sr_vvms/fix_pages.c b/sr_vvms/fix_pages.c
new file mode 100644
index 0000000..a9428e3
--- /dev/null
+++ b/sr_vvms/fix_pages.c
@@ -0,0 +1,66 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <prtdef.h>
+#include <psldef.h>
+#include <ssdef.h>
+
+#include "stringpool.h"
+#include "fix_pages.h"
+
+#define CHUNK_SIZE 16384 /* should be the largest OS_PAGE_SIZE, or a multiple thereof, and not an unfair strain on stp */
+
+GBLREF spdesc stringpool;
+OS_PAGE_SIZE_DECLARE
+
+void fix_pages(unsigned char *inbot, unsigned char *intop)
+{
+ register unsigned char *bot, *top;
+ unsigned char *buff, *range[2];
+ uint4 chunk, size, status;
+
+ bot = ((uint4)inbot) & ~(OS_PAGE_SIZE - 1);
+ top = ((uint4)intop) & ~(OS_PAGE_SIZE - 1);
+ top += OS_PAGE_SIZE;
+ range[0] = bot;
+ range[1] = top - 1;
+ status = sys$setprt(range, NULL, (uint4)PSL$C_USER, (uint4)PRT$C_UW, NULL);
+ if (status != SS$_NORMAL) /* can't update shared readonly memory */
+ {
+ chunk = top - bot; /* already a multiple of OS_PAGE_SIZE due to rounding of bot and top */
+ chunk = chunk < CHUNK_SIZE ? chunk : CHUNK_SIZE;
+ ENSURE_STP_FREE_SPACE(chunk); /* ensure temp space in the stringpool */
+ buff = stringpool.free;
+ assert(buff >= stringpool.base);
+ assert(buff <= stringpool.top);
+ chunk = (stringpool.top - buff) & ~(OS_PAGE_SIZE - 1); /* use as much as there is */
+ for (; bot < top; bot += size)
+ {
+ size = top - bot;
+ if (size > chunk)
+ size = chunk;
+ assert(0 == (size & (OS_PAGE_SIZE - 1)));
+ memcpy(buff, bot, size); /* save the content of a chunk */
+ range[0] = bot;
+ range[1] = bot + size - 1;
+ status = sys$cretva(range, 0, PSL$C_USER); /* replace an address range with empty pages */
+ if (status != SS$_NORMAL)
+ {
+ rts_error(VARLSTCNT(1) status);
+ break; /* hygenic; should never be reached */
+ }
+ memcpy(bot, buff, size); /* restore content to the new overlay */
+ }
+ }
+ return;
+}
diff --git a/sr_vvms/gbldirnam.h b/sr_vvms/gbldirnam.h
new file mode 100644
index 0000000..f014131
--- /dev/null
+++ b/sr_vvms/gbldirnam.h
@@ -0,0 +1,15 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2008 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#define GDE_LABEL_SIZE 13
+#define GDE_LABEL_NUM 1
+/* Note, GDE_LABEL_LITERAL must be maintained in gdeinit.m if changes are made here */
+#define GDE_LABEL_LITERAL "GTCGBLDIR009"
diff --git a/sr_vvms/gde.hlp b/sr_vvms/gde.hlp
new file mode 100644
index 0000000..959967c
--- /dev/null
+++ b/sr_vvms/gde.hlp
@@ -0,0 +1,887 @@
+
+1 Overview
+ GDE Overview
+ The GT.M Global Directory Editor, GDE, is a tool for creating,
+ examining, and modifying Global Directories (GDs). A Global Directory
+ is a file that identifies:
+
+ o What global variables go to what database files
+
+ o The size limits for names and values of global variables
+
+ o Other database characteristics
+
+ o If and what type of journaling should take place
+
+ All MUMPS programs that use the same Global Directory share all the
+ same global variables, unless the Global Directory uses logical names
+ for which users have varying definitions. The local variables are
+ accessible only among programs executed within a single process scope.
+
+
+2 Functions
+ GDE Functions
+ The main functions of the Global Directory Editor are to:
+
+ o Define the mapping of global variables to database files
+
+ o Define the character limitations of global variable names and
+ records
+
+ o Provide the MUMPS Peripheral Interchange Program (MUPIP) with
+ characteristics (e.g., /ALLOCATION size) used in creating and
+ extending a database file
+
+ o Define whether a database file should be journaled and how
+
+ o Define the /ACCESS_METHOD used to access the database files and
+ other database characteristics
+
+2 Mapping
+ Mapping
+ Defining a "map," i.e., where GT.M stores a global variable,
+ requires defining, not only the NAME of the global variable and the
+ database FILE in the Global Directory, but also the REGION and
+ SEGMENT.
+
+ A REGION is a logical structure that holds information such as key-
+ and record-size about a portion of a database. GT.M and the
+ operating system handle data stored in a REGION together by storing
+ it in the same place or places, backing it up as a unit, etc. A
+ REGION must map to a SEGMENT.
+
+ A SEGMENT defines additional database storage characteristics not
+ required for RMS files. A SEGMENT must map to a FILE. The SEGMENT
+ exists primarily for future design considerations, when a
+ one-to-one correspondence between the REGION and SEGMENT will no
+ longer be required.
+
+ The connection in the map between a name and a file is very
+ important and is used by the run-time system and most GT.M
+ utilities. Specifying a map requires entering (a) NAME(S) with a
+ connection to a REGION, a REGION with a connection to a SEGMENT,
+ and a SEGMENT with a connection to a database file. The commands
+ may be issued in any order, but the final result must be a complete
+ logical path from name to file.
+
+ NAME(s) ---> REGION ---> SEGMENT ---> FILE
+
+2 Default_GD
+ Creating a Default Global Directory
+ The Global Directory Editor creates a quick default Global
+ Directory for purposes such as development and testing work. A
+ default Global Directory also serves as a starting point or shell
+ for a custom Global Directory.
+
+ To create a default Global Directory structure, invoke and
+ immediately EXIT GDE. GDE creates a Global Directory mapping of all
+ NAMEs to the REGION $DEFAULT, the default REGION to the SEGMENT
+ $DEFAULT and the default SEGMENT to the default file-specification
+ MUMPS with the default file extension of .DAT.
+
+2 Custom_GD
+ Creating a Custom Global Directory
+ When a default Global Directory does not meet your needs, you need
+ to customize a Global Directory. Usually you customize the Global
+ Directory when you define your production database file. This
+ enables you to optimize the sharing and location of your data.
+
+ To create a custom Global Directory, invoke GDE and issue the
+ commands necessary to build the desired Global Directory. For more
+ information about mapping, refer to the "How to Map Global
+ Variables" section.
+
+2 GTM$GBLDIR
+ Defining the GTM$GBLDIR Logical Name
+ GT.M identifies the current Global Directory by the logical name
+ GTM$GBLDIR. GDE, MUPIP, LKE, DSE and the GT.M run-time system use
+ this logical name to identify the file used as the Global
+ Directory. The run-time system normally uses this logical name, but
+ may also access a Global Directory by setting $ZGBLDIR or the
+ extended global reference ([]) syntax.
+
+ If you maintain multiple Global Directories, define GTM$GBLDIR to
+ the Global Directory you currently want to use. The system manager
+ normally defines GTM$GBLDIR in a GROUP or SYSTEM table. The default
+ installation procedure creates a startup command procedure, which
+ assigns GTM$GBLDIR the name MUMPS.GLD. You may want to define
+ GTM$GBLDIR in your LOGIN.COM file.
+
+ Example
+
+ $ DEFINE GTM$GBLDIR PROD.GLD
+
+ For more information on defining logical names in LOGIN.COM, refer
+ to the VAX/VMS Guide to Using VMS.
+
+1 Command_syntax
+ Command Syntax
+ The general format for GDE commands is:
+
+ command [/object-type] [object-name] [/qualifier...]
+ ex: /NAME Name-space /region-qualifier...
+ /REGION Region-name /region-qualifier...
+ /SEGMENT Segment-name /segment-qualifier...
+
+ where:
+
+ Object-type Indicates whether the command operates on a /N[AME],
+ /R[EGION] or /S[EGMENT].
+
+ Object-name Specifies the name of a N[AME] space, R[EGION] or
+ S[EGMENT]. Object-names of different types may have the
+ same name.
+
+ Name-space Specifies a name or name prefix that maps to a REGION.
+ Names may include the wildcard operator * as a suffix.
+
+ Region-name Specifies a REGION name.
+
+ Segment-name Specifies a SEGMENT name.
+
+ Qualifier Indicates a command or object qualifier.
+
+ The format for each command specifies required qualifiers for the
+ command.
+
+ The @, EXIT, HELP, LOG, QUIT and SPAWN commands do not use this
+ general format. For the applicable format, refer to the section
+ explaining each of these commands.
+
+ Comments on the command line may be delimited by an exclamation mark
+ (!). An exclamation mark not enclosed in quotes (") causes GDE to
+ ignore the rest of the input line.
+
+1 at-sign
+ @
+ The @ command executes a GDE command file. Use the @ command to run
+ stored GDE command sequences from an interactive session.
+
+ The format of the @ command is:
+
+ @ file-specification
+
+ The file-specification specifies the command file to execute. GDE
+ provides the default file extension ".COM" in creating the
+ file-specification.
+
+ GDE executes each line of the command file as if the line had been
+ typed at the terminal.
+
+ Example
+
+ GDE> @standard
+
+ This command transfers the GDE input to STANDARD.COM in the current
+ default directory. STANDARD.COM should contain GDE commands; any
+ comments should start with an exclamation mark (!).
+
+1 ADD
+ A[DD]
+ The ADD command inserts a new NAME, REGION, or SEGMENT into the Global
+ Directory.
+
+ The format of the ADD command is:
+
+ A[DD]/N[AME] name-space /R[EGION]=region-name
+ A[DD]/R[EGION] region-name /D[YNAMIC]=segment-name [/region-qual...]
+ A[DD]/S[EGMENT] segment-name /F[ILE_NAME]=file-spec [/segment-qual...]
+
+ The ADD command requires specification of an object-type and
+ object-name. GDE supplies default values for qualifiers not supplied.
+
+ Name-spaces are case-sensitive while other objects are not.
+
+1 CHANGE
+ C[HANGE]
+ The CHANGE command alters the NAME to REGION or REGION to SEGMENT
+ mapping and the environment for a REGION or SEGMENT.
+
+ The format of the CHANGE command is:
+
+ C[HANGE]/N[AME] name-space /R[EGION]=new-region
+ C[HANGE]/R[EGION] region-name [/region-qualifier...]
+ C[HANGE]/S[EGMENT] segment-name [/segment-qualifier...]
+
+ The CHANGE command requires specification of an object-type and
+ object-name.
+
+ Changes to the database environment characteristics take effect the
+ next time you create a new file with the MUPIP CREATE command. Mapping
+ changes take effect for subsequent image activation, for example
+ following the next RUN or MUMPS/DIRECT command.
+
+1 DELETE
+ D[ELETE]
+ The DELETE command removes a NAME, REGION, or SEGMENT from the Global
+ Directory. The DELETE command does not delete the actual data from the
+ database but can make the data inaccessible to MUMPS images using the
+ resulting directory.
+
+ The format of the DELETE command is:
+
+ D[ELETE]/N[AME] name-space
+ D[ELETE]/R[EGION] region-name
+ D[ELETE]/S[EGMENT] segment-name
+
+ The DELETE command requires specification of an object-type and
+ object-name.
+
+ Deleting a NAME removes the NAME to REGION mapping. Deleting a REGION
+ unmaps all NAMES mapped to the REGION. Deleting a SEGMENT unmaps the
+ REGION mapped to the SEGMENT.
+
+ Map the deleted names to another REGION or the deleted REGION to
+ another SEGMENT using the CHANGE command.
+ The default name-space (*) can not be deleted.
+
+1 EXIT
+ E[XIT]
+ The EXIT command writes all changes made in the current GDE editing
+ session to the Global Directory.
+
+ The format of the EXIT command is:
+
+ E[XIT]
+
+ GDE performs a full verification test (VERIFY) on the data. If the
+ verification succeeds, GDE writes the new Global Directory to disk and
+ issues a verification message.
+
+ If the verification fails, GDE displays a listing of all unverifiable
+ mappings and waits for corrections. Make appropriate corrections or
+ leave the Global Directory in its original, unedited state by using
+ the QUIT command.
+
+ If you have not made any changes to the Global Directory, GDE does not
+ create a new Global Directory.
+
+1 HELP
+ H[ELP]
+ The HELP command explains the GDE commands. The HELP command uses
+ similar conventions to the VAX/VMS help facility.
+
+ The format of the HELP command is:
+
+ HE[LP] [keyword...]
+
+ Specify the GDE command for which you want information at the Topic
+ prompt. The help facility also provides an "Overview."
+
+ Use <RETURN> or <CTRL Z> to return to the GDE prompt.
+
+1 LOCKS
+ LOC[KS]
+ The LOCKS command specifies the REGION into which GT.M maps locks on
+ names not starting with ^. GDE maps locks on global names (starting
+ with ^) to the region of the database specified for that name.
+
+ The format of the LOCKS command is:
+
+ LOC[KS] /R[EGION]=region-name
+
+ The LOCK /REGION= qualifier allows specification of a region for local
+ locks. By default, GDE maps local locks to the default region
+ $DEFAULT.
+
+ Example
+
+ GDE> LOCK/REGION=MAIN
+
+ This command maps all locks on resource names that don't start with
+ "^" to region MAIN.
+
+1 LOG
+ LOG
+ The LOG command creates a log file of all GDE commands and displays
+ for the current editing session. Because the system places an
+ exclamation point (i.e., the comment symbol) before all display lines
+ in the log, a log can be used with the @ sign as a command procedure.
+
+ The format of the LOG command is:
+
+ LOG
+ LOG /ON[=file-spec]
+ LOG /OF[F]
+
+ The LOG command without a qualifier reports the current status of GDE
+ logging. The LOG command displays a message showing whether logging is
+ in effect and the specification of the current log file for the GDE
+ session.
+
+ The log facility can be turned on and off using the /ON or /OFF
+ qualifiers any time during a GDE session. However, GDE closes the log
+ files only when the GDE session ends.
+
+ The /ON qualifier has an optional argument of a file-specification,
+ which must identify a legal RMS file. GDE uses the default file
+ extension ".LOG". If LOG /ON has no file-specification argument, GDE
+ uses the previous log file for the editing session. If no log file has
+ previously been specified during this editing session, GDE uses the
+ default log file GDELOG.LOG.
+
+1 QUIT
+ Q[UIT]
+ The QUIT command ends the current editing session without saving any
+ changes to the Global Directory. GDE does not create an updated Global
+ Directory file.
+
+ The format of the QUIT command is:
+
+ Q[UIT]
+
+ If the session made changes to the Global Directory, GDE issues a
+ message warning that the Global Directory has not been updated.
+
+1 RENAME
+ R[ENAME]
+ The RENAME command allows changes of a NAME, the name of a REGION or
+ the name of a SEGMENT.
+
+ The format of the RENAME command is:
+
+ R[ENAME]/N[AME] old-name new-name
+ R[ENAME]/R[EGION] old-reg-name new-reg-name
+ R[ENAME]/S[EGMENT] old-seg-name new-seg-name
+
+ The RENAME command requires specification of an object-type and two
+ object-names.
+
+ When renaming a REGION, GDE transfers all NAME mappings to the new
+ REGION. When renaming a SEGMENT, GDE transfers the REGION mappings to
+ the new SEGMENT.
+
+1 SETGD
+ SE[TGD]
+ The SETGD command closes out edits on one Global Directory and opens
+ edits on another.
+
+ The format of the SETGD command is:
+
+ SE[TGD] /F[ILE]=file-specification [/Q[UIT]]
+
+ The /FILE=file-specification qualifier identifies the new Global
+ Directory. When you provide a partial file-specification, GDE uses the
+ current default directory and defaults the type to .GLD.
+
+ The /QUIT qualifier specifies that any changes that have been made to
+ the current Global Directory are not written, i.e., are lost, during
+ the change of Global Directory.
+
+ A SETGD changes the Global Directory on which the GDE edits act. If
+ the current Global Directory has not been modified or the /QUIT
+ qualifier appears in the command, the change simply occurs. However,
+ if the current Global Directory has been modified, GDE verifies the
+ Global Directory, and if the verification is successful, writes that
+ Global Directory. If the verification is not successful, the SETGD
+ fails.
+
+1 SHOW
+ SH[OW]
+ The SHOW command displays information about NAMEs, REGIONs and
+ SEGMENTs.
+
+ The format of the SHOW command is:
+
+ SH[OW] /N[AME] [name-space]
+ SH[OW] /R[EGION] [region-name]
+ SH[OW] /S[EGMENT] [segment-name]
+ SH[OW] /M[AP] [R[EGION]=region-name]
+ SH[OW] /T[EMPLATE]
+ SH[OW] /A[LL]
+
+ The object-type is optional. /MAP, /TEMPLATE, and /ALL are special
+ qualifiers used as follows:
+
+ o /MAP - displays the mapping of all NAMES, REGIONs, SEGMENTs, and
+ files
+
+ o /TEMPLATE - displays the current REGION and SEGMENT templates
+
+ o /ALL - displays all templates, the map, and information about each
+ defined NAME, REGION, and SEGMENT
+
+ By default, SHOW displays /ALL.
+
+
+1 SPAWN
+ SP[AWN]
+ The SPAWN command creates a subprocess for access to VMS CLI (usually
+ DCL) without terminating the current GDE environment. Use the SPAWN
+ command to suspend a session and issue DCL commands such as DIRECTORY
+ or SHOW LOGICAL. The SPAWN command spawns a subprocess with an
+ optional command string. If SPAWN has no command string parameter, the
+ GDE command leaves the terminal at the prompt for the CLI (usually
+ DCL) of the spawned process.
+
+ The format of the SPAWN command is:
+
+ SP[AWN] [DCL command]
+
+ Example
+
+ GDE> SPAWN "DIR *.DAT"
+
+ This command invokes a VMS directory listing of all files in the
+ current default directory with a .DAT extension.
+
+1 TEMPLATE
+ T[EMPLATE]
+ The TEMPLATE command maintains a set of REGION and SEGMENT qualifier
+ values for use as templates when ADDing regions and segments. When an
+ ADD command omits qualifiers, GDE uses the template values as
+ defaults. GDE maintains a separate set of SEGMENT qualifier values for
+ each ACCESS_METHOD. When GDE modifies the ACCESS_METHOD, it activates
+ the appropriate set of TEMPLATEs and sets all unspecified qualifiers
+ to the template defaults for the new ACCESS_METHOD. Use the GDE SHOW
+ command to display qualifier values for all ACCESS_METHODs.
+
+ The format of the TEMPLATE command is:
+
+ T[EMPLATE]/R[EGION] [/region-qualifier...]
+ T[EMPLATE]/S[EGMENT] [/segment-qualifier...]
+
+ The TEMPLATE command requires specification of an object-type.
+
+1 VERIFY
+ V[ERIFY]
+ The VERIFY command checks the NAME to REGION mappings to insure all
+ NAMES map to a REGION. The VERIFY command checks REGION to SEGMENT
+ mappings to insure each REGION maps to a SEGMENT, each SEGMENT maps to
+ only one REGION and the SEGMENT maps to an RMS file. The EXIT command
+ implicitly performs a VERIFY /ALL.
+
+ The format of the VERIFY command is:
+
+ V[ERIFY]
+ V[ERIFY] /N[AME] [name-space]
+ V[ERIFY] /R[EGION] [region-name]
+ V[ERIFY] /S[EGMENT] [segment-name]
+ V[ERIFY] /M[AP]
+ V[ERIFY] /T[EMPLATE]
+ V[ERIFY] /A[LL]
+
+ The object-type is optional. /MAP, /TEMPLATE, and /ALL are special
+ qualifiers used as follows:
+
+ o /MAP - checks that all NAMES map to a REGION, all REGIONs map to a
+ SEGMENT, and all SEGMENTs map to a FILE
+
+ o /TEMPLATE - checks that all templates currently are consistent and
+ useable
+
+ o /ALL - checks all map and template data
+
+ VERIFY with no qualifier, VERIFY /MAP and VERIFY /ALL each check all
+ current information.
+
+1 Qualifiers
+ GDE Command Qualifiers
+ The /NAME, /REGION, and /SEGMENT qualifiers each have additional
+ qualifiers used to further define or specify characteristics of a
+ NAME, REGION, or SEGMENT. This section discusses these additional
+ qualifiers.
+
+2 Name_Qualifiers
+ Name Qualifiers
+ The only /NAME qualifier, used with the commands ADD or CHANGE, is
+ the /REGION qualifier.
+
+3 /REGION
+ /R[EGION]=region-name
+ Specifies the name of a REGION.
+
+ The maximum length is 16 alphanumeric characters.
+
+ Example
+
+ GDE> add/Name a*/Region=areg
+
+ This command creates the name "a," if it does not exist and maps
+ it to the region "areg."
+
+
+2 Region_Qualifiers
+ Region Qualifiers
+ The following /REGION qualifiers can be used with the ADD, CHANGE
+ or TEMPLATE commands.
+
+3 /DYNAMIC_SEGMENT
+ /D[YNAMIC_SEGMENT]=segment-name
+ Specifies the name of a dynamic SEGMENT. A dynamic segment
+ allows read-write access.
+
+ The minimum length is 1 alpha character.
+
+ The maximum length is 16 alphanumeric characters.
+
+3 /KEY_SIZE
+ /K[EY_SIZE]=size in bytes
+ Specifies the maximum size of keys, in bytes, which can be
+ stored in the region.
+
+ CAUTION: The key size must be less than the record size. GDE
+ rejects the command if the key size is greater than the record
+ size.
+
+ The minimum key size is 3 bytes.
+
+ The maximum key size is 255 bytes.
+
+ By default, GDE uses a key size of 64 bytes.
+
+3 /RECORD_SIZE
+ /R[ECORD_SIZE]=size in bytes
+ Specifies the maximum record size, in bytes, which can be stored
+ in the region.
+
+ CAUTION: The key size must be less than the record size. GDE
+ rejects the command if the key size exceeds the record size.
+
+ The record size must be less than half the block size of the
+ segment to which the region maps. If the record size is not less
+ than half the block size minus 7 bytes, GDE issues an error
+ message. To VERIFY or EXIT, you must change the record size.
+
+ The minimum record size is 7 bytes.
+
+ The maximum record size is 32,508 bytes.
+
+ By default, GDE uses a record size of 256 bytes.
+
+3 /NULL_SUBSCRIPTS
+ /[NO]N[ULL_SUBSCRIPTS]
+ Indicates whether GT.M allows null subscripts for global
+ variables stored in the region, i.e., whether GT.M permits
+ reference such as ^aaa("",1).
+
+ By default, REGIONS have /NONULL_SUBSCRIPTS.
+
+3 /JOURNAL
+ /[NO]J[OURNAL][=journal-option-list]
+ Specifies whether the database file allows journaling and, if it
+ does, establishes characteristics for the journal file.
+
+ /NOJOURNAL specifies that the database file does not allow
+ journaling. /NOJOURNAL does not accept an argument assignment.
+
+ /JOURNAL specifies that journaling is allowed. /JOURNAL takes
+ one or more arguments in a journal-option-list. The
+ journal-option-list contains keywords separated with commas (,)
+ enclosed in parentheses (). When the list contains only one
+ keyword, the parentheses are optional.
+
+ For more information about journaling, refer to the GT.M
+ Journaling chapter of the GT.M Administration and Operations
+ Guide.
+
+4 BEFORE_IMAGE
+ [NO]BE[FORE_IMAGE]
+ [NO]BEFORE_IMAGE controls whether the journal should capture
+ before images of information that an update is about to
+ modify.
+
+ A BEFORE_IMAGE journal permits the possibility of performing
+ "roll-back" recovery (i.e., Backward Recovery) of the
+ associated database file. BEFORE_IMAGE increases the load on
+ I/O and CPU resources and therefore may affect performance.
+
+4 FILE_NAME
+ F[ILE_NAME]=file-specification
+ FILE_NAME=file-specification specifies the name of the
+ journal file.
+
+ Journal file-specifications are limited to 255 characters.
+
+ By default, GDE derives the file-specification from the
+ database file name.
+
+ By default, GDE uses a journal file type of .MJL.
+
+4 ALLOCATION
+ A[LLOCATION]=blocks
+ ALLOCATION=blocks specifies the initial size of the journal
+ file in RMSblocks. Because frequent journal file extensions
+ degrade run-time performance, make journal file allocation
+ ample for a production database file.
+
+ When you change the ALLOCATION and do not also specify
+ EXTENSION, the EXTENSION automatically changes to equal the
+ ALLOCATION.
+
+ The minimum allocation is 10 blocks.
+
+ The maximum allocation is 16777216 blocks.
+
+ By default, GDE uses an allocation of 100 blocks.
+
+4 EXTENSION
+ E[XTENSION]=blocks
+ EXTENSION=blocks specifies the size by which a journal file
+ extends when it becomes full. EXTENSION=0 prevents automatic
+ journal file extension. Because frequent journal file
+ extensions degrade run-time performance, make the journal
+ file extension ample for a production database file.
+
+ When you change the ALLOCATION and do not also specify
+ EXTENSION, the EXTENSION automatically changes to equal the
+ ALLOCATION.
+
+ The minimum EXTENSION is 0 blocks.
+
+ The maximum EXTENSION is 65536 blocks.
+
+ By default, GDE uses an EXTENSION of 100 blocks.
+
+4 BUFFER_SIZE
+ BU[FFER_SIZE]=pages
+ BUFFER_SIZE=pages specifies the amount of memory used to
+ buffer journal file output. A larger BUFFER_SIZE usually
+ smooths and improves run-time performance.
+
+ A larger BUFFER_SIZE requires more memory resources, which
+ may be scarce. A larger BUFFER_SIZE provides more room for
+ journal records in memory on their way to the disk and
+ therefore increases the number of update records that may be
+ lost in a system failure.
+
+ The minimum BUFFER_SIZE is enough 512-byte pages to hold 2
+ GDS database blocks.
+
+ The maximum BUFFER_SIZE is 2000 pages.
+
+ By default, GDE uses a BUFFER_SIZE of 128 pages.
+
+2 Segment_Qualifiers
+ Segment Qualifiers
+ The following /SEGMENT qualifiers can be used with the ADD, CHANGE,
+ or TEMPLATE commands.
+
+3 /FILE_NAME
+ /F[ILE_NAME]=file-spec
+ Specifies the file name for a SEGMENT. GT.M allows full
+ file-specifications and logical names. Note that if the file-
+ specification is a search list, the first file in the list is
+ used and all others are ignored.
+
+ The maximum file-specification length is 255 characters.
+
+ By default, GDE uses a file name of MUMPS.
+
+ By default, GDE uses a file extension of .DAT.
+
+3 /ACCESS_METHOD
+ /AC[CESS_METHOD]=code
+ Specifies the access method GT.M uses to store and retrieve data
+ from the global database file. The two methods are Buffered
+ Global (BG) and Mapped Memory (MM).
+
+ GDE maintains a separate set of SEGMENT qualifier values for
+ each ACCESS_METHOD. When GDE modifies the ACCESS_METHOD, it
+ activates the appropriate set of TEMPLATEs and sets all
+ unspecified qualifiers to the template defaults for the new
+ ACCESS_METHOD.
+
+ By default, GDE uses an access method of BG.
+
+
+3 /BLOCK_SIZE
+ /BL[OCK_SIZE]=size
+ Specifies the size, in bytes, of each database block on disk.
+ The block-size must be a multiple of 512 (the RMS block-size).
+ If the block-size is not a multiple of 512, GDE rounds off the
+ block-size to the next highest multiple of 512 and issues a
+ warning message.
+
+ If the specified block-size is less than the minimum, GDE uses
+ the minimum block-size. If the specified block-size is greater
+ than the maximum, GDE issues an error message.
+
+ A 1024 byte or 2048 byte block-size serves well for most
+ applications.
+
+
+ The minimum block-size is 512 bytes.
+
+ The maximum block-size is 65,024 bytes.
+
+ By default, GDE uses a block-size of 1024 bytes for BG and MM
+ files.
+
+3 /ALLOCATION
+ /AL[LOCATION]=size
+ Specifies the number of blocks GT.M allocates to a disk file
+ when MUPIP creates the file. For GDS files, the number of bytes
+ allocated is ALLOCATION size times the BLOCK_SIZE.
+
+ The default allocation was chosen for small development
+ projects. Use larger allocations for production files and large
+ projects. Because file fragmentation impairs performance, make
+ the initial allocation large enough to hold the anticipated
+ contents of the file for a length of time consistent with your
+ RMS file reorganization schedule.
+
+ The minimum ALLOCATION is 10 blocks.
+
+ The maximum ALLOCATION is 16777216 blocks.
+
+ By default, GDE uses an ALLOCATION of 100 blocks.
+
+3 /EXTENSION_COUNT
+ /E[XTENSION_COUNT]=size
+ Specifies the number of extra GDS blocks of disk space by which
+ the file should extend. The extend amount is interpreted as the
+ number of usable GDS blocks to create with the extension. To
+ calculate the number of host operating system blocks added with
+ each extension, multiply the number of GDS blocks added by (GDS
+ block size/host block size); to this amount, add one local bit
+ map block for each 512-byte block added in each extension, plus
+ one for any remaining bytes.
+
+ The default extension amount was chosen for small development
+ projects. Use larger extensions for larger files. Because many
+ file extensions adversely affect performance, set up extensions
+ appropriate to the file allocation.
+
+ BG files may extend automatically when the file is full. A zero
+ extension size prevents a BG file from automatically extending.
+
+ BG files may be, and MM files must be, extended with MUPIP
+ EXTEND. When a MUPIP EXTEND command does not include a /BLOCKS=
+ qualifier, EXTEND uses the extension size in the database
+ header. The extension amount may be changed with the MUPIP SET
+ command. To require explicit expansion for BG files with MUPIP
+ EXTEND, set /EXTENSION_COUNT to zero.
+
+ The minimum EXTENSION is 0 blocks.
+
+ The maximum EXTENSION is 65,535 blocks.
+
+ By default, GDE uses an EXTENSION of 100 blocks.
+
+3 /GLOBAL_BUFFER_COUNT
+ /G[LOBAL_BUFFER_COUNT]=size
+ Specifies the number of global buffers for a file. Global
+ buffers serve as part of the database caching mechanisms.
+
+ Avoid inadequate settings of this factor. However, if your
+ system is memory constrained and the database file traffic is
+ not heavy enough to hold the cache in memory, increasing
+ GLOBAL_BUFFER_COUNT may induce VMS paging. Therefore, do not
+ increase this factor to a large value without careful
+ observation.
+
+ The proper number of GLOBAL_BUFFERs depends on the application
+ and the amount of primary memory available on the system. Most
+ production databases exhibit a direct relationship between the
+ number of GLOBAL_BUFFERs and performance. However, the
+ relationship is not linear, but rather more parabolic, so that
+ increases past some point have progressively less benefit. This
+ point of diminishing returns depends on the application. For
+ most applications, Greystone expects the optimum number of
+ GLOBAL_BUFFERs to be between 512 and 2048.
+
+ Generally, you should increase the number of GLOBAL_BUFFERs for
+ production GDS databases. This is because GT.M uses the shared
+ memory database cache associated with each GDS file for the vast
+ majority of caching.
+
+ The minimum for BG is 64 blocks.
+
+ The maximum for BG is 4096 blocks.
+
+ By default, GDE uses a GLOBAL_BUFFER_COUNT of 128 blocks.
+
+3 /DEFER
+ /[NO]D[EFER]
+ Instructs GT.M whether or not to store updates on the disk
+ immediately.
+
+ DEFER has a significant performance benefit for heavily updated
+ database files. However, DEFER should only be used for files,
+ such as those containing temporary storage for reports, which
+ can be recreated if the system crashes.
+
+ By default, GDE makes MM database files /DEFER.
+
+3 /LOCK_SPACE
+ /LOC[K_SPACE]=size
+ Specifies the number of pages of space to use for the lock
+ database stored with this segment. If GT.M runs out of space to
+ store locks, the system becomes slightly less efficient. The
+ default amount is generous for most MUMPS applications.
+
+ The minimum LOCK_SPACE is 10 pages.
+
+ The maximum LOCK_SPACE is 1000 pages.
+
+ By default, GDE uses a LOCK_SPACE of 20 pages.
+
+1 Guidelines
+ Mapping Guidelines
+ Global Directory maps consist of a hierarchy of NAMEs, REGIONs,
+ SEGMENTs and FILEs. The following section provides guidelines for
+ defining and using these mapping components.
+
+2 Names
+ NAME Guidelines
+ GT.M uses a NAME to place global variables in a physical database
+ file.
+ A NAME:
+
+ o Maps to only one REGION in the Global Directory
+
+ o Can be a discrete "global" name, e.g., aaa is a discrete global
+
+ o Can be a partial name ending with a wild card ("*")
+
+ o Must begin with an alphabetic character or a % sign
+
+ o Can be 1 to 8 alphanumeric characters
+
+ o Is case sensitive
+
+ A wild card defines all names starting with the characters of the
+ partial name. For example, abc*, defines the range of all global
+ names beginning with the three characters "abc."
+
+2 Regions
+ REGION Guidelines
+ GT.M uses a REGION to logically define a portion of the database
+ with the same characteristics, such as key and record-size. A
+ REGION maps to a SEGMENT. More than one NAME may map to a REGION. A
+ Global Directory must have at least one REGION.
+
+ A region-name:
+
+ o Must begin with an alphabetic character, except for $DEFAULT
+
+ o Can include alphanumerics, a dollar sign and an underscore
+
+ o Can be 1 to 15 characters
+
+ GDE automatically converts region-names to upper-case.
+
+ By default, GDE uses $DEFAULT for the default region-name.
+
+2 Segments
+ SEGMENT Guidelines
+ GT.M uses a SEGMENT to define a physical file and access method for
+ the database stored in that file. A SEGMENT maps to only one RMS
+ file. A SEGMENT can be mapped by only one REGION.
+
+ A segment-name:
+
+ o Must begin with an alphabetic character, except for $DEFAULT
+
+ o Can include alphanumerics, a dollar sign and an underscore
+
+ o Can be 1 to 15 characters
+
+ GDE automatically converts segment-names to upper-case.
+
+ By default, GDE uses the file name MUMPS for the $DEFAULT default
+ segment. By default, GDE uses the file extension .DAT for database
+ files.
+
+
diff --git a/sr_vvms/gdeget.m b/sr_vvms/gdeget.m
new file mode 100644
index 0000000..e618779
--- /dev/null
+++ b/sr_vvms/gdeget.m
@@ -0,0 +1,334 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ;
+; Copyright 2006 Fidelity Information Services, Inc ;
+; ;
+; This source code contains the intellectual property ;
+; of its copyright holder(s), and is made available ;
+; under a license. If you do not know the terms of ;
+; the license, please stop and do not read further. ;
+; ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+gdeget: ;read in an existing GD or create a default
+LOAD
+ n abs,contents,rel,xregs,xsegs,reglist,map,$et
+ i debug s $et="b"
+ e s $et="g ABORT^GDE:($p($p($zs,"","",3),""-"")'=""%GDE"") u io w !,$p($zs,"","",3,999),! h"
+ s abs=1,update=0,chset=$SELECT($ZV["OS390":"ISO8859-1",1:"")
+ o file:(exc="g badfile":rewind:recordsize=SIZEOF("dsk_blk"):readonly:fixed:blocksize=SIZEOF("dsk_blk"):ichset=chset)
+ u file r rec
+ i debug u @useio
+; header
+ s label=$e(rec,1,12)
+ set v5ft1=0
+ i (label="GTCGBLDIR008")!(label="GTCGBDUNX004") s label=hdrlab,v5ft1=1,update=1 ;autoconvert
+ i v5ft1=1 n SIZEOF d v5ft1init
+ set v44=0
+ i (label="GTCGBLDIR007")!(label="GTCGBDUNX003") s label=hdrlab,v44=1,update=1 ;autoconvert
+ i v44=1 n MAXNAMLN,MAXSEGLN,MAXREGLN,SIZEOF d v44init
+ s v30=0
+ i (label="GTCGBLDIR006")!(label="GTCGBDUNX002") s label=hdrlab,v30=4,update=1 ;autoconvert
+ i label'=hdrlab d cretmps,CONVERT^GDEOGET,verify s update=1 q ;autoconvert
+ s filesize=$$bin2num($e(rec,13,16))
+ s abs=abs+SIZEOF("gd_header")
+; contents
+ i $e(rec,abs,abs+3)'=$c(0,0,0,0) zm gdeerr("INPINTEG") ; filler
+ s abs=abs+4
+ s contents("maxrecsize")=$$bin2num($e(rec,abs,abs+3)),abs=abs+4
+ s contents("mapcnt")=$$bin2num($e(rec,abs,abs+1)),abs=abs+2
+ s contents("regioncnt")=$$bin2num($e(rec,abs,abs+1)),abs=abs+2
+ s contents("segmentcnt")=$$bin2num($e(rec,abs,abs+1)),abs=abs+2
+ i $e(rec,abs,abs+1)'=$tr($j("",2)," ",ZERO) zm gdeerr("INPINTEG") ; filler
+ s abs=abs+2
+ s contents("maps")=$$bin2num($e(rec,abs,abs+3)),abs=abs+4
+ s contents("regions")=$$bin2num($e(rec,abs,abs+3)),abs=abs+4
+ s contents("segments")=$$bin2num($e(rec,abs,abs+3)),abs=abs+4
+ s abs=abs+12 ;skip link, tab_ptr and id pointers
+ s contents("end")=$$bin2num($e(rec,abs,abs+3)),abs=abs+4
+ i contents("regioncnt")'=contents("segmentcnt") zm gdeerr("INPINTEG")
+ i contents("regioncnt")-1>contents("mapcnt") zm gdeerr("INPINTEG")
+; verify offsets
+ i abs'=(SIZEOF("gd_header")+SIZEOF("gd_contents")+1) zm gdeerr("INPINTEG")
+ s x=contents("maps")
+ i x+1'=(abs-SIZEOF("gd_header")) zm gdeerr("INPINTEG")
+ s x=x+(contents("mapcnt")*SIZEOF("gd_map"))
+ i x'=contents("regions") zm gdeerr("INPINTEG")
+ s x=x+(contents("regioncnt")*SIZEOF("gd_region"))
+ i x'=contents("segments") zm gdeerr("INPINTEG")
+ s x=x+(contents("segmentcnt")*(SIZEOF("gd_segment")-v30))
+ i x'=contents("end") zm gdeerr("INPINTEG")
+ s rel=abs
+; maps - verify that mapped regions and regions are 1-to-1
+ k reglist
+ f i=1:1:contents("mapcnt") d map
+ zm:'$$MAP2NAM^GDEMAP(.map) gdeerr("INPINTEG")
+ s s=""
+ f i=1:1:contents("regioncnt") s s=$o(reglist(s))
+ i $l($o(reglist(s))) zm gdeerr("INPINTEG")
+; regions
+ k regs,xregs s regs=0
+ f i=1:1:contents("regioncnt") d region
+ i regs'=contents("regioncnt") zm gdeerr("INPINTEG")
+; segments
+ k segs,xsegs s segs=0
+ f i=1:1:contents("segmentcnt") d segment
+ i segs'=contents("segmentcnt") zm gdeerr("INPINTEG")
+; template access method
+ s tmpacc=$$gderead(4)
+ i accmeth'[("\"_tmpacc) zm gdeerr("INPINTEG")
+; templates
+ k tmpreg,tmpseg
+ d cretmps
+ f s="ALLOCATION","BEFORE_IMAGE","BUFFER_SIZE" d tmpreg(s)
+ i 'v30 d tmpreg("COLLATION_DEFAULT")
+ f s="EXTENSION","FILE_NAME" d tmpreg(s)
+ f s="JOURNAL","KEY_SIZE","NULL_SUBSCRIPTS","RECORD_SIZE" d tmpreg(s) ;,"STOP_ENABLE"
+ ; need to handle versioning
+ i 'v44&'v30 d tmpreg("STDNULLCOLL")
+ f i=2:1:$l(accmeth,"\") s am=$p(accmeth,"\",i) d
+ . i am="MM" d:$l(rec)-(rel-1)<3 nextrec i +$e(rec,rel,rel+2)'=2 d tmpmm q
+ . f s="ACCESS_METHOD","ALLOCATION","BLOCK_SIZE","BUCKET_SIZE","DEFER","EXTENSION_COUNT","FILE_TYPE" d tmpseg(am,s)
+ . f s="GLOBAL_BUFFER_COUNT","LOCK_SPACE" d tmpseg(am,s)
+ . i 'v30 d tmpseg(am,"RESERVED_BYTES") ;autoconvert, can be condensed someday
+ . d tmpseg(am,"WINDOW_SIZE")
+ c file
+; resolve
+ s s=""
+ f s s=$o(nams(s)) q:'$l(s) zm:'$d(xregs(nams(s))) gdeerr("INPINTEG") s nams(s)=xregs(nams(s))
+ f s s=$o(regs(s)) q:'$l(s) zm:'$d(xsegs(regs(s,"DYNAMIC_SEGMENT"))) gdeerr("INPINTEG") d
+ . s regs(s,"DYNAMIC_SEGMENT")=xsegs(regs(s,"DYNAMIC_SEGMENT"))
+ f s s=$o(segs(s)) q:'$l(s) s am=segs(s,"ACCESS_METHOD") d
+ . s x="" f s x=$o(segs(s,x)) q:x="" i x'="FILE_NAME",'$l(tmpseg(am,x)) zm:segs(s,x) gdeerr("INPINTEG") s segs(s,x)=""
+ ; fall through !
+verify: s x=$$ALL^GDEVERIF
+ i 'x zm gdeerr("INPINTEG")
+ q
+
+;----------------------------------------------------------------------------------------------------------------------------------
+
+badfile ;file access failed
+ s:'debug $et="" u file:exc="" s abortzs=$zs zm gdeerr("GDREADERR"):file,+abortzs
+ h
+ ;
+bin2num:(bin) ; binary number -> number
+ n num,i
+ s num=0
+ i endian=TRUE f i=$l(bin):-1:1 s num=$a(bin,i)*HEX($l(bin)-i*2)+num
+ e f i=1:1:$l(bin) s num=$a(bin,i)*HEX(i-1*2)+num
+ q num
+ ;
+
+;----------------------------------------------------------------------------------------------------------------------------------
+map:
+ i $l(rec)-(rel-1)<SIZEOF("gd_map") d nextrec
+ s s=$e(rec,rel,rel+SIZEOF("mident")-1),rel=rel+SIZEOF("mident")
+ s x=$f(s,$c(0))-2 i x=-2 s x=SIZEOF("mident")
+ s s=$e(s,1,x)
+ s x=$$bin2num($e(rec,rel,rel+3)),rel=rel+4
+ s map(s)=x
+ s reglist(x)="",x=x-contents("regions")
+ i x#SIZEOF("gd_region") zm gdeerr("INPINTEG")
+ i x\SIZEOF("gd_region")'<contents("regioncnt") zm gdeerr("INPINTEG")
+ s abs=abs+SIZEOF("gd_map")
+ q
+region:
+ i $l(rec)-(rel-1)<SIZEOF("gd_region") d nextrec
+ s regs=regs+1
+ s l=$$bin2num($e(rec,rel,rel+1)),rel=rel+2
+ s s=$e(rec,rel,rel+l-1),rel=rel+MAXREGLN,xregs(abs-1-SIZEOF("gd_header"))=s
+ s regs(s,"KEY_SIZE")=$$bin2num($e(rec,rel,rel+1)),rel=rel+2
+ s regs(s,"RECORD_SIZE")=$$bin2num($e(rec,rel,rel+3)),rel=rel+4
+ s regs(s,"DYNAMIC_SEGMENT")=$$bin2num($e(rec,rel,rel+3)),rel=rel+4
+ s x=regs(s,"DYNAMIC_SEGMENT")-contents("segments")
+ i x#(SIZEOF("gd_segment")-v30) zm gdeerr("INPINTEG") ; autoconvert
+ i x\(SIZEOF("gd_segment")-v30)'<contents("segmentcnt") zm gdeerr("INPINTEG") ; autoconvert
+ i $e(rec,rel,rel+3)'=$c(0,0,0,0) zm gdeerr("INPINTEG") ; static segment
+ s rel=rel+4
+ i $e(rec,rel)'=ZERO zm gdeerr("INPINTEG") ; OPEN state
+ s rel=rel+1
+ i $e(rec,rel)'=ZERO zm gdeerr("INPINTEG") ; lock_write
+ s rel=rel+1
+ s regs(s,"NULL_SUBSCRIPTS")=$$bin2num($e(rec,rel)),rel=rel+1
+ s regs(s,"JOURNAL")=$$bin2num($e(rec,rel)),rel=rel+1
+ s regs(s,"ALLOCATION")=$$bin2num($e(rec,rel,rel+3)),rel=rel+4 ; journal options
+ s regs(s,"EXTENSION")=$$bin2num($e(rec,rel,rel+1)),rel=rel+2
+ s regs(s,"BUFFER_SIZE")=$$bin2num($e(rec,rel,rel+1)),rel=rel+2
+ s regs(s,"BEFORE_IMAGE")=$$bin2num($e(rec,rel)),rel=rel+1
+ i $e(rec,rel,rel+3)'=$tr($j("",4)," ",ZERO) zm gdeerr("INPINTEG") ; 4 chars
+ s rel=rel+4
+ s regs(s,"COLLATION_DEFAULT")=$$bin2num($e(rec,rel)),rel=rel+1 ; default collating type
+ ; stdnullcoll is applicable from V5
+ i 'v44&'v30 s regs(s,"STDNULLCOLL")=$$bin2num($e(rec,rel))
+ e d
+ . i $e(rec,rel)'=$tr($j("",1)," ",ZERO) zm gdeerr("INPINTEG") ; 1 chars
+ . s regs(s,"STDNULLCOLL")=0
+ s rel=rel+1
+ s l=$$bin2num($e(rec,rel)),rel=rel+1 ;jnl_file_len
+ s regs(s,"FILE_NAME")=$e(rec,rel,rel+l-1),rel=rel+SIZEOF("file_spec")
+ i $e(rec,rel,rel+7)'=$tr($j("",8)," ",ZERO) zm gdeerr("INPINTEG") ; reserved
+ s rel=rel+8
+ s abs=abs+SIZEOF("gd_region")
+ q
+segment:
+ i $l(rec)-(rel-1)<(SIZEOF("gd_segment")-v30) d nextrec ; autoconvert
+ s segs=segs+1
+ s x=$$bin2num($e(rec,rel+SIZEOF("am_offset")-v30,rel+SIZEOF("am_offset")-v30+3)) ; autoconvert
+ s am=$s(x=1:"BG",x=2:"MM",x=4:"USER",1:"ERROR")
+ i am="ERROR" zm gdeerr("INPINTEG")
+ s l=$$bin2num($e(rec,rel,rel+1)),rel=rel+2
+ s s=$e(rec,rel,rel+l-1),rel=rel+MAXSEGLN,xsegs(abs-1-SIZEOF("gd_header"))=s
+ s segs(s,"ACCESS_METHOD")=am
+ s l=$$bin2num($e(rec,rel,rel+1)),rel=rel+2
+ s segs(s,"FILE_NAME")=$e(rec,rel,rel+l-1),rel=rel+SIZEOF("file_spec")
+ s segs(s,"BLOCK_SIZE")=$$bin2num($e(rec,rel,rel+1)),rel=rel+2
+ s segs(s,"EXTENSION_COUNT")=$$bin2num($e(rec,rel,rel+1)),rel=rel+2
+ s segs(s,"ALLOCATION")=$$bin2num($e(rec,rel,rel+3)),rel=rel+4
+ i $e(rec,rel,rel+3)'=$tr($j("",4)," ",ZERO) zm gdeerr("INPINTEG") ; reserved for clb
+ s rel=rel+4
+ i $e(rec,rel,rel+3)'=".DAT" zm gdeerr("INPINTEG")
+ s rel=rel+4
+ s segs(s,"DEFER")=$$bin2num($e(rec,rel))
+ s rel=rel+1
+ s x=$$bin2num($e(rec,rel)),rel=rel+1
+ s segs(s,"FILE_TYPE")=$s(x=0:"DYNAMIC",1:"ERROR")
+ i segs(s,"FILE_TYPE")="ERROR" zm gdeerr("INPINTEG")
+ s segs(s,"BUCKET_SIZE")=$$bin2num($e(rec,rel))
+ s rel=rel+1
+ s segs(s,"WINDOW_SIZE")=$$bin2num($e(rec,rel))
+ s rel=rel+1
+ s segs(s,"LOCK_SPACE")=$$bin2num($e(rec,rel,rel+3)),rel=rel+4
+ s segs(s,"GLOBAL_BUFFER_COUNT")=$$bin2num($e(rec,rel,rel+3)),rel=rel+4
+ i 'v30 s segs(s,"RESERVED_BYTES")=$$bin2num($e(rec,rel,rel+3)),rel=rel+4 ;autoconvert
+ e s segs(s,"RESERVED_BYTES")=0
+ s rel=rel+4 ; access method already processed
+ i $e(rec,rel,rel+3)'=$tr($j("",4)," ",ZERO) zm gdeerr("INPINTEG") ; file_cntl pointer
+ s rel=rel+4
+ i $e(rec,rel,rel+3)'=$tr($j("",4)," ",ZERO) zm gdeerr("INPINTEG") ; repl_list pointer
+ s rel=rel+4
+ s abs=abs+SIZEOF("gd_segment")-v30
+ q
+gderead:(max)
+ n s
+ i $l(rec)-(rel-1)<3 d nextrec
+ s l=$e(rec,rel,rel+2),rel=rel+3,abs=abs+3
+ i l>max zm gdeerr("INPINTEG")
+ i $l(rec)-(rel-1)<l d nextrec
+ s s=$e(rec,rel,rel+l-1),rel=rel+l,abs=abs+l
+ q s
+ ;
+tmpreg:(s)
+ i $l(rec)-(rel-1)<3 d nextrec
+ s l=$e(rec,rel,rel+2),rel=rel+3,abs=abs+3
+ i $l(rec)-(rel-1)<l d nextrec
+ s tmpreg(s)=$e(rec,rel,rel+l-1),rel=rel+l,abs=abs+l
+ q
+tmpseg:(a,s)
+ i $l(rec)-(rel-1)<3 d nextrec
+ s l=$e(rec,rel,rel+2),rel=rel+3,abs=abs+3
+ i $l(rec)-(rel-1)<l d nextrec
+ s tmpseg(a,s)=$s($l(tmpseg(a,s)):$e(rec,rel,rel+l-1),1:"") s rel=rel+l,abs=abs+l
+ q
+nextrec:
+ n nextrec
+ u file r nextrec
+ i debug u @useio
+ s rec=$e(rec,rel,$l(rec))_nextrec,rel=1
+ q
+;----------------------------------------------------------------------------------------------------------------------------------
+
+CREATE
+ k contents,nams,regs,segs,tmpreg,tmpseg
+ s update=1
+ s header=$tr($j("",SIZEOF("gd_header")-16)," ",ZERO)
+ s nams=2,(nams("*"),nams("#"))=defreg
+ s regs=1,regs(defreg,"DYNAMIC_SEGMENT")=defseg,reg="regs(defreg)"
+ d cretmps
+ s x=""
+ f s x=$o(tmpreg(x)) q:'$l(x) s @reg@(x)=tmpreg(x)
+ s segs=1
+ s am=tmpacc d maktseg
+ q
+cretmps:
+ s tmpreg("ALLOCATION")=100
+ s tmpreg("BEFORE_IMAGE")=1
+ s tmpreg("BUFFER_SIZE")=128
+ s tmpreg("COLLATION_DEFAULT")=0
+ s tmpreg("EXTENSION")=100
+ s tmpreg("FILE_NAME")=""
+ s tmpreg("JOURNAL")=0
+ s tmpreg("KEY_SIZE")=64
+ s tmpreg("NULL_SUBSCRIPTS")=0
+ s tmpreg("RECORD_SIZE")=256
+ s tmpreg("STDNULLCOLL")=0
+ ;s tmpreg("STOP_ENABLED")=1
+ s tmpseg("BG","ACCESS_METHOD")="BG"
+ s tmpseg("BG","ALLOCATION")=100
+ s tmpseg("BG","BLOCK_SIZE")=1024
+ s tmpseg("BG","BUCKET_SIZE")=""
+ s tmpseg("BG","DEFER")=""
+ s tmpseg("BG","EXTENSION_COUNT")=100
+ s tmpseg("BG","FILE_TYPE")="DYNAMIC"
+ s tmpseg("BG","GLOBAL_BUFFER_COUNT")=defglo
+ s tmpseg("BG","RESERVED_BYTES")=0
+ s tmpseg("BG","LOCK_SPACE")=40
+ s tmpseg("BG","WINDOW_SIZE")=""
+ d tmpmm
+ s tmpseg("USER","ACCESS_METHOD")="USER"
+ s tmpseg("USER","ALLOCATION")=""
+ s tmpseg("USER","BLOCK_SIZE")=""
+ s tmpseg("USER","BUCKET_SIZE")=""
+ s tmpseg("USER","DEFER")=""
+ s tmpseg("USER","EXTENSION_COUNT")=""
+ s tmpseg("USER","FILE_TYPE")="DYNAMIC"
+ s tmpseg("USER","GLOBAL_BUFFER_COUNT")=""
+ s tmpseg("USER","RESERVED_BYTES")=0
+ s tmpseg("USER","LOCK_SPACE")=""
+ s tmpseg("USER","WINDOW_SIZE")=""
+ s tmpacc="BG"
+ q
+tmpmm: s tmpseg("MM","ACCESS_METHOD")="MM"
+ s tmpseg("MM","ALLOCATION")=100
+ s tmpseg("MM","BLOCK_SIZE")=1024
+ s tmpseg("MM","BUCKET_SIZE")=""
+ s tmpseg("MM","DEFER")=1
+ s tmpseg("MM","EXTENSION_COUNT")=100
+ s tmpseg("MM","FILE_TYPE")="DYNAMIC"
+ s tmpseg("MM","GLOBAL_BUFFER_COUNT")=1024
+ s tmpseg("MM","RESERVED_BYTES")=0
+ s tmpseg("MM","LOCK_SPACE")=40
+ s tmpseg("MM","WINDOW_SIZE")=""
+ q
+maktseg: s segs(defseg,"FILE_NAME")=defdb
+ s seg="segs(defseg)",x=""
+ f s x=$o(tmpseg(am,x)) q:'$l(x) s @seg@(x)=tmpseg(am,x)
+ q
+v44init:
+ s SIZEOF("am_offset")=308
+ s SIZEOF("file_spec")=256
+ s SIZEOF("gd_header")=16
+ s SIZEOF("gd_contents")=44
+ s SIZEOF("gd_map")=12
+ s SIZEOF("gd_region")=316
+ s SIZEOF("gd_segment")=320
+ s SIZEOF("mident")=8
+ s SIZEOF("rec_hdr")=3
+ s SIZEOF("dsk_blk")=512
+ s SIZEOF("max_str")=32767
+ s MAXNAMLN=SIZEOF("mident"),MAXREGLN=16,MAXSEGLN=16
+ i ver'="VMS" s SIZEOF("blk_hdr")=8
+ e s SIZEOF("blk_hdr")=7
+ q
+v5ft1init:
+ s SIZEOF("am_offset")=324
+ s SIZEOF("file_spec")=256
+ s SIZEOF("gd_header")=16
+ s SIZEOF("gd_contents")=44
+ s SIZEOF("gd_map")=36
+ s SIZEOF("gd_region")=332
+ s SIZEOF("gd_segment")=336
+ s SIZEOF("mident")=32
+ s SIZEOF("rec_hdr")=3
+ s SIZEOF("dsk_blk")=512
+ s SIZEOF("max_str")=32767
+ i ver'="VMS" s SIZEOF("blk_hdr")=8
+ e s SIZEOF("blk_hdr")=7
+ q
diff --git a/sr_vvms/gdeoget.m b/sr_vvms/gdeoget.m
new file mode 100644
index 0000000..963b016
--- /dev/null
+++ b/sr_vvms/gdeoget.m
@@ -0,0 +1,436 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ;
+; Copyright 2006 Fidelity Information Services, Inc ;
+; ;
+; This source code contains the intellectual property ;
+; of its copyright holder(s), and is made available ;
+; under a license. If you do not know the terms of ;
+; the license, please stop and do not read further. ;
+; ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+gdeget: ;read in an existing GD or create a default
+CONVERT n accmeth,hdrlab,MAXSEGLN,MAXREGLN,SIZEOF,RMS,csegs,cregs,contents d gdeinit
+ ;s label=$e(rec,1,12)
+ s (v23,v24,v25)=0 ; to allow autoconvert
+ i label="GTCGBLDIR001" s label=hdrlab,(v23,v24)=1,update=1 ; to allow autoconvert
+ i label="GTCGBLDIR002" s label=hdrlab,v24=1,update=1 ; to allow autoconvert
+ i label="GTCGBLDIR003" s label=hdrlab,v25=1,update=1 ; to allow autoconvert
+ i label'=hdrlab zm gdeerr("GDUNKNFMT"):file,gdeerr("INPINTEG")
+ s filesize=$$bin2num($e(rec,13,16))
+ s header=$e(rec,17,SIZEOF("gd_header")),abs=abs+SIZEOF("gd_header")
+; contents
+ i $e(rec,abs,abs+3)'=$c(0,0,0,0) zm gdeerr("INPINTEG") ; filler
+ s abs=abs+4
+ s contents("maxrecsize")=$$bin2num($e(rec,abs,abs+3)),abs=abs+4
+ s contents("mapcnt")=$$bin2num($e(rec,abs,abs+1)),abs=abs+2
+ s contents("maps")=$$bin2num($e(rec,abs,abs+3)),abs=abs+4
+ s contents("regioncnt")=$$bin2num($e(rec,abs,abs+1)),abs=abs+2
+ s contents("regions")=$$bin2num($e(rec,abs,abs+3)),abs=abs+4
+ s contents("segmentcnt")=$$bin2num($e(rec,abs,abs+1)),abs=abs+2
+ s contents("segments")=$$bin2num($e(rec,abs,abs+3)),abs=abs+4
+ s contents("gdscnt")=$$bin2num($e(rec,abs,abs+1)),abs=abs+2
+ s contents("gdsfiledata")=$$bin2num($e(rec,abs,abs+3)),abs=abs+4
+ s contents("rmscnt")=$$bin2num($e(rec,abs,abs+1)),abs=abs+2
+ s contents("rmsfiledata")=$$bin2num($e(rec,abs,abs+3)),abs=abs+4
+ s contents("end")=$$bin2num($e(rec,abs,abs+3)),abs=abs+4
+ s abs=abs+22
+ i contents("regioncnt")'=contents("segmentcnt") zm gdeerr("INPINTEG")
+ i contents("regioncnt")-1>contents("mapcnt") zm gdeerr("INPINTEG")
+; verify offsets
+ i abs'=(SIZEOF("gd_header")+SIZEOF("gd_contents")+1) zm gdeerr("INPINTEG")
+ s x=contents("maps")
+ i x+1'=(abs-SIZEOF("gd_header")) zm gdeerr("INPINTEG")
+ s x=x+(contents("mapcnt")*SIZEOF("gd_map"))
+ i x'=contents("regions") zm gdeerr("INPINTEG")
+ s x=x+(contents("regioncnt")*SIZEOF("gd_region"))
+ i x'=contents("segments") zm gdeerr("INPINTEG")
+ s x=x+(contents("segmentcnt")*SIZEOF("gd_segment"))
+ i x'=contents("gdsfiledata") zm gdeerr("INPINTEG")
+ s x=x+(contents("gdscnt")*SIZEOF("gds_filedata"))
+ i x'=contents("rmsfiledata") zm gdeerr("INPINTEG")
+ s x=x+(contents("rmscnt")*SIZEOF("rms_filedata"))
+ i x'=contents("end") zm gdeerr("INPINTEG")
+ s rel=abs
+; maps - verify that mapped regions and regions are 1-to-1
+ k reglist
+ f i=1:1:contents("mapcnt") d map
+ s s=""
+ f i=1:1:contents("regioncnt") s s=$o(reglist(s))
+ i $l($o(reglist(s))) zm gdeerr("INPINTEG")
+; regions
+ k cregs,xregs s cregs=0
+ f i=1:1:contents("regioncnt") d region
+ i cregs'=contents("regioncnt") zm gdeerr("INPINTEG")
+; segments
+ k csegs,xsegs s csegs=0
+ f i=1:1:contents("segmentcnt") d segment
+ i csegs'=contents("segmentcnt") zm gdeerr("INPINTEG")
+; gdsfiledata
+ f i=1:1:contents("gdscnt") d fabdata(SIZEOF("gds_filedata"),0)
+; rmsfiledata
+ f i=1:1:contents("rmscnt") d fabdata(SIZEOF("rms_filedata"),SIZEOF("struct RAB"))
+; names
+ k nams s nams=0
+ i $l(rec)-(rel-1)<3 d nextrec
+ s nams=$e(rec,rel,rel+2),rel=rel+3,abs=abs+3
+ f i=1:1:nams d name
+; regions
+ k regs s regs=0
+ i $l(rec)-(rel-1)<3 d nextrec
+ s regs=$e(rec,rel,rel+2),rel=rel+3,abs=abs+3
+ i regs<contents("regioncnt") zm gdeerr("INPINTEG")
+ f i=1:1:regs d gdereg
+; template access method
+ s tmpacc=$$gderead(4)
+ i accmeth'[("\"_tmpacc) zm gdeerr("INPINTEG")
+; segments
+ k segs s segs=0
+ i $l(rec)-(rel-1)<3 d nextrec
+ s segs=$e(rec,rel,rel+2),rel=rel+3,abs=abs+3
+ i segs<contents("segmentcnt") zm gdeerr("INPINTEG")
+ f i=1:1:segs d gdeseg
+; templates
+ ;k tmpreg,tmpseg
+ f s="ALLOCATION","BEFORE_IMAGE","BUFFER_SIZE","EXTENSION","FILE_NAME" d tmpreg(s)
+ i v24 d tmpreg(s) s tmpreg("ALLOCATION")=100,tmpreg("BEFORE_IMAGE")=1 ; to allow autoconvert
+ i v24 s tmpreg("BUFFER_SIZE")=128,tmpreg("EXTENSION")=100,tmpreg("FILE_NAME")="" ; to allow autoconvert
+ ; ;,tmpreg("STOP_ENABLE")=0
+ f s="JOURNAL","KEY_SIZE","LOCK_WRITE","NULL_SUBSCRIPTS","RECORD_SIZE" d tmpreg(s) ;,"STOP_ENABLE"
+ f s="ACCESS_METHOD","ALLOCATION","BLOCK_SIZE" d tmpseg("BG",s)
+ f s="EXTENSION_COUNT","FILE_TYPE","GLOBAL_BUFFER_COUNT" d tmpseg("BG",s)
+ i v23 s tmpseg("BG","LOCK_SPACE")=20 ; to allow autoconvert
+ e s s="LOCK_SPACE" d tmpseg("BG",s) ; remove else
+ f s="ACCESS_METHOD","ALLOCATION","BLOCK_SIZE","DEFER","EXTENSION_COUNT","FILE_TYPE" d tmpseg("MM",s)
+ i v23 s tmpseg("MM","LOCK_SPACE")=20 ; to allow autoconvert
+ e s s="LOCK_SPACE" d tmpseg("MM",s) ; remove else
+ f s="ACCESS_METHOD","ALLOCATION","BLOCK_SIZE","BUCKET_SIZE","EXTENSION_COUNT" d tmpseg("RMS",s)
+ f s="FILE_TYPE","GLOBAL_BUFFER_COUNT","WINDOW_SIZE" d tmpseg("RMS",s)
+ i v25 s tmpseg("USER","ACCESS_METHOD")="USER",tmpseg("USER","FILE_TYPE")="DYNAMIC" ; to allow autoconvert
+ e f s="ACCESS_METHOD","FILE_TYPE" d tmpseg("USER",s) ; remove else
+; resolve
+ s s=""
+ f s s=$o(cregs(s)) q:'$l(s) i '$d(regs(s)) zm gdeerr("INPINTEG")
+ f s s=$o(csegs(s)) q:'$l(s) i '$d(segs(s)) zm gdeerr("INPINTEG")
+ f s s=$o(cregs(s)) q:'$l(s) i '$d(xsegs(cregs(s,"DYNAMIC_SEGMENT"))) zm gdeerr("INPINTEG")
+ f s s=$o(regs(s)) q:'$l(s) i '$d(segs(regs(s,"DYNAMIC_SEGMENT"))) zm gdeerr("INPINTEG")
+ c file
+ d tmpres
+ f s s=$o(regs(s)) q:'$l(s) k regs(s,"LOCK_WRITE") d regres f x=$o(regs(s,x)) q:'$l(x) d
+ . s:$d(minreg(x))&(regs(s,x)<minreg(x)) regs(s,x)=minreg(x)
+ . s:$d(maxreg(x))&(regs(s,x)>maxreg(x)) regs(s,x)=maxreg(x)
+ f s s=$o(segs(s)) q:'$l(s) s am=segs(s,"ACCESS_METHOD"),x="" s:am="RMS" am="BG" d
+ . d segres f s x=$o(segs(s,am,x)) q:x="" s segs(s,x)=segs(s,am,x) k segs(s,am,x) d
+ . . s:$d(minseg(am,x))&(segs(s,x)<minseg(am,x)) segs(s,x)=minseg(am,x)
+ . . s:$d(maxseg(am,x))&(segs(s,x)>maxseg(am,x)) segs(s,x)=maxseg(am,x)
+ . f i=1:1:$l(accmeth,"\") s x=$p(accmeth,"\",i) i am'=x k segs(s,x)
+ k minseg("RMS"),maxseg("RMS"),tmpseg("RMS")
+ i tmpacc="RMS" s tmpacc="BG"
+ q
+
+tmpres: k tmpreg("LOCK_WRITE")
+ s x="" s x=$o(tmpreg(x)) q:x="" d
+ . s:$d(minreg(x))&(tmpreg(x)<minreg(x)) tmpreg(x)=minreg(x)
+ . s:$d(maxreg(x))&(tmpreg(x)>maxreg(x)) tmpreg(x)=maxreg(x)
+ s am="" f s am=$o(tmpseq(am)) q:am="" s x="" f s x=$o(tmpseq(am,x)) q:x="" d
+ . s:$d(minseg(am,x))&(tmpseg(am,x)<minseg(am,x)) tmpseg(am,x)=minseg(am,x)
+ . s:$d(maxseg(am,x))&(tmpseg(am,x)>maxseg(am,x)) tmpseg(am,x)=maxseg(am,x)
+ q
+
+regres: s x="" f s x=$o(tmpreg(x)) q:x="" s:'$d(regs(s,x)) regs(s,x)=tmpreg(x)
+ q
+
+segres: s x="" f s x=$o(tmpseg(am,x)) q:x="" s:'$d(segs(s,am,x)) segs(s,am,x)=tmpseg(am,x)
+ q
+
+; verify
+ s x=$$ALL^GDEVERIF
+ i 'x zm gdeerr("INPINTEG")
+ q
+
+;----------------------------------------------------------------------------------------------------------------------------------
+
+badfile ;file access failed
+ s:'debug $et="" s abortzs=$zs zm gdeerr("GDREADERR"):file,+abortzs
+ h
+ ;
+bin2num:(bin) ; binary number -> number
+ n num,i
+ s num=0
+ f i=1:1:$l(bin) s num=$a(bin,i)*HEX(i-1*2)+num
+ q num
+ ;
+str2hex:(in)
+ n i,j,out
+ s out=""
+ f i=1:1 s j=$a(in,i) q:j=-1 f k=j\16,j#16 s out=out_$s(k<10:k,1:$c(k+55))
+ q out
+ ;
+num2long:(num)
+ i num<0 zm gdeerr("INPINTEG")
+ i num'<TWO(32) zm gdeerr("INPINTEG")
+ q $c(num/TWO(24),num/TWO(16)#256,num/256#256,num#256)
+ ;
+num2shrt:(num)
+ i num<0 zm gdeerr("INPINTEG")
+ i num'<TWO(16) zm gdeerr("INPINTEG")
+ q $c(num\256,num#256)
+ ;
+dec2hex:(in)
+ q $$str2hex($$num2long(in))
+
+;----------------------------------------------------------------------------------------------------------------------------------
+
+map:
+ i $l(rec)-(rel-1)<SIZEOF("gd_map") d nextrec
+ s x=$$bin2num($e(rec,rel+SIZEOF("mident"),rel+SIZEOF("gd_map")-1))
+ s reglist(x)="",x=x-contents("regions")
+ i x#SIZEOF("gd_region") zm gdeerr("INPINTEG")
+ i x\SIZEOF("gd_region")'<contents("regioncnt") zm gdeerr("INPINTEG")
+ s rel=rel+SIZEOF("gd_map")
+ s abs=abs+SIZEOF("gd_map")
+ q
+region:
+ i $l(rec)-(rel-1)<SIZEOF("gd_region") d nextrec
+ s cregs=cregs+1
+ s l=$$bin2num($e(rec,rel,rel+1)),rel=rel+2
+ s s=$e(rec,rel,rel+l-1),rel=rel+MAXSEGLN,xregs(abs-1-SIZEOF("gd_header"))=s
+ s cregs(s,"DYNAMIC_SEGMENT")=$$bin2num($e(rec,rel,rel+3)),rel=rel+4
+ s x=cregs(s,"DYNAMIC_SEGMENT")-contents("segments")
+ i x#SIZEOF("gd_segment") zm gdeerr("INPINTEG")
+ i x\SIZEOF("gd_segment")'<contents("segmentcnt") zm gdeerr("INPINTEG")
+ i $e(rec,rel,rel+3)'=$c(0,0,0,0) zm gdeerr("INPINTEG") ; static segment
+ s rel=rel+4
+ s cregs(s,"RECORD_SIZE")=$$bin2num($e(rec,rel,rel+3)),rel=rel+4
+ s cregs(s,"KEY_SIZE")=$$bin2num($e(rec,rel,rel+1)),rel=rel+2
+ i $e(rec,rel)'=ZERO zm gdeerr("INPINTEG") ; OPEN state
+ s rel=rel+1
+ s cregs(s,"LOCK_WRITE")=$$bin2num($e(rec,rel)),rel=rel+1
+ s cregs(s,"NULL_SUBSCRIPTS")=$$bin2num($e(rec,rel)),rel=rel+1
+ s cregs(s,"JOURNAL")=$$bin2num($e(rec,rel)),rel=rel+1
+ i $e(rec,rel,rel+7)'=$tr($j("",8)," ",ZERO) zm gdeerr("INPINTEG") ; gbl_lk_root, lcl_lk_root
+ s rel=rel+8
+ s cregs(s,"ALLOCATION")=$$bin2num($e(rec,rel,rel+3)),rel=rel+4 ; journal options
+ s cregs(s,"EXTENSION")=$$bin2num($e(rec,rel,rel+1)),rel=rel+2
+ s cregs(s,"BUFFER_SIZE")=$$bin2num($e(rec,rel,rel+1)),rel=rel+2
+ s cregs(s,"BEFORE_IMAGE")=$$bin2num($e(rec,rel)),rel=rel+1
+ i 'v23,'v24,$e(rec,rel,rel+10)'=$tr($j("",11)," ",ZERO) zm gdeerr("INPINTEG") ; 7 filler + 4 for jnllsb
+ s rel=rel+11
+ s l=$$bin2num($e(rec,rel)),rel=rel+1
+ s cregs(s,"FILE_NAME")=$e(rec,rel,rel+l-1),rel=rel+SIZEOF("jnl_filename")
+ i $e(rec,rel,rel+46)'=$tr($j("",47)," ",ZERO) zm gdeerr("INPINTEG") ; reserved
+ s rel=rel+47
+ s abs=abs+SIZEOF("gd_region")
+ q
+segment:
+ i $l(rec)-(rel-1)<SIZEOF("gd_segment") d nextrec
+ s csegs=csegs+1
+ s x=$$bin2num($e(rec,rel+SIZEOF("am_offset"),rel+SIZEOF("am_offset")+3))
+ s am=$s(x=0:"RMS",x=1:"BG",x=2:"MM",x=4:"USER",1:"ERROR")
+ i am="ERROR" zm gdeerr("INPINTEG")
+ s l=$$bin2num($e(rec,rel,rel+1)),rel=rel+2
+ s s=$e(rec,rel,rel+l-1),rel=rel+MAXSEGLN,xsegs(abs-1-SIZEOF("gd_header"))=s
+ s (csegs(s,"ACCESS_METHOD"),csegs(s,am,"ACCESS_METHOD"))=am
+ s l=$$bin2num($e(rec,rel,rel+1)),rel=rel+2
+ s csegs(s,am,"FILE_NAME")=$e(rec,rel,rel+l-1),rel=rel+SIZEOF("file_spec")
+ s x=$$bin2num($e(rec,rel)),rel=rel+1
+ s csegs(s,am,"FILE_TYPE")=$s(x=0:"DYNAMIC",1:"ERROR")
+ i csegs(s,am,"FILE_TYPE")="ERROR" zm gdeerr("INPINTEG")
+ i "USER"=am s rel=rel+8
+ e s csegs(s,am,"BLOCK_SIZE")=$$bin2num($e(rec,rel,rel+1)),rel=rel+2
+ e s csegs(s,am,"ALLOCATION")=$$bin2num($e(rec,rel,rel+3)),rel=rel+4
+ e s csegs(s,am,"EXTENSION_COUNT")=$$bin2num($e(rec,rel,rel+1)),rel=rel+2
+ i $e(rec,rel,rel+3)'=$tr($j("",4)," ",ZERO) zm gdeerr("INPINTEG") ; reserved for clb
+ s rel=rel+4
+ i "BG|MM"[am s csegs(s,am,"LOCK_SPACE")=$s(v23:20,1:$$bin2num($e(rec,rel))) ; allow autoconv
+ s rel=rel+1
+ i 'v24 i $e(rec,rel,rel+3)'=".DAT" zm gdeerr("INPINTEG") ; if to allow autoconv
+ s rel=rel+4
+ i $e(rec,rel,rel+3)'=$tr($j("",4)," ",ZERO) zm gdeerr("INPINTEG") ; filler
+ s rel=rel+4
+ s rel=rel+4 ; access method already processed
+ s xfile(s)=$$bin2num($e(rec,rel,rel+3)),rel=rel+4
+ i "MM"=am s csegs(s,am,"DEFER")=$$bin2num($e(rec,rel+36))
+ s rel=rel+96
+ s abs=abs+SIZEOF("gd_segment")
+ q
+fabdata:(datasize,offset)
+ n fna,x,y
+ i $l(rec)-(rel-1)<datasize d nextrec
+ s x=$e(rec,rel+1+offset,rel+datasize-1)
+ s fna=$$bin2num($e(x,RMS("FAB$L_FNA"),RMS("FAB$L_FNA")+3))
+ s y=fna-contents("segments")
+ i y#SIZEOF("gd_segment")'=SIZEOF("fna_offset") zm gdeerr("INPINTEG")
+ i y\SIZEOF("gd_segment")'<contents("segmentcnt") zm gdeerr("INPINTEG")
+ s y=fna-SIZEOF("fna_offset")
+ i '$d(xsegs(y)) zm gdeerr("INPINTEG")
+ s s=xsegs(y)
+ i '$d(csegs(s,"ACCESS_METHOD")) zm gdeerr("INPINTEG")
+ s am=csegs(s,"ACCESS_METHOD")
+ i csegs(s,am,"ALLOCATION")'=$$bin2num($e(x,RMS("FAB$L_ALQ"),RMS("FAB$L_ALQ")+3)) zm gdeerr("INPINTEG")
+ i csegs(s,am,"EXTENSION_COUNT")'=$$bin2num($e(x,RMS("FAB$W_DEQ"),RMS("FAB$W_DEQ")+1)) zm gdeerr("INPINTEG")
+ i "RMS"=am s csegs(s,am,"WINDOW_SIZE")=$$bin2num($e(x,RMS("FAB$B_RTV")))
+ s y=$$bin2num($e(x,RMS("FAB$L_DNA"),RMS("FAB$L_DNA")+3))-contents("segments")
+ i 'v24 i y#SIZEOF("gd_segment")'=SIZEOF("dna_offset") zm gde("INPINTEG") ; if to allow autoconvert
+ i $l(csegs(s,am,"FILE_NAME"))'=$$bin2num($e(x,RMS("FAB$B_FNS"))) zm gdeerr("INPINTEG")
+ i 'v24 i $$bin2num($e(x,RMS("FAB$B_DNS")))'=4 ; if to allow autoconvert
+ i csegs(s,am,"BLOCK_SIZE")'=$$bin2num($e(x,RMS("FAB$W_BLS"),RMS("FAB$W_BLS")+1)) zm gdeerr("INPINTEG")
+ i "RMS"=am s csegs(s,am,"BUCKET_SIZE")=$$bin2num($e(x,RMS("FAB$B_BKS")))
+ i "BG|RMS"[am s csegs(s,am,"GLOBAL_BUFFER_COUNT")=$$bin2num($e(x,RMS("FAB$W_GBC"),RMS("FAB$W_GBC")+1))
+ s rel=rel+datasize,abs=abs+datasize
+ q
+name:
+ i $l(rec)-(rel-1)<3 d nextrec
+ s l=$e(rec,rel,rel+2),rel=rel+3,abs=abs+3
+ i l>SIZEOF("mident") zm gdeerr("INPINTEG")
+ i $l(rec)-(rel-1)<l d nextrec
+ s s=$e(rec,rel,rel+l-1),rel=rel+l,abs=abs+l
+ i $l(rec)-(rel-1)<3 d nextrec
+ s l=$e(rec,rel,rel+2),rel=rel+3,abs=abs+3
+ i l>MAXREGLN zm gdeerr("INPINTEG")
+ i $l(rec)-(rel-1)<l d nextrec
+ s nams(s)=$e(rec,rel,rel+l-1),rel=rel+l,abs=abs+l
+ q
+gdereg:
+ s s=$$gderead(MAXREGLN)
+ s regs(s,"DYNAMIC_SEGMENT")=$$gderead(MAXSEGLN)
+ s regs(s,"ALLOCATION")=$$gderead(10)
+ s regs(s,"EXTENSION")=$$gderead($l(maxreg("EXTENSION")))
+ s regs(s,"FILE_NAME")=$$gderead(SIZEOF("jnl_filename"))
+ s regs(s,"BUFFER_SIZE")=$$gderead(5)
+ i v24 s regs(s,"ALLOCATION")=100,regs(s,"EXTENSION")=100,regs(s,"FILE_NAME")="" ; to allow autoconvert
+ i s regs(s,"BUFFER_SIZE")=128,regs(s,"BEFORE_IMAGE")=1 ;,regs(s,"STOP_ENABLE")=0 ; to allow autoconvert
+ i s x=$$gderead(5),x=$$gderead(5) ; to allow autoconvert
+ e s regs(s,"BEFORE_IMAGE")=$$gderead(1) ;s regs(s,""STOP_ENABLE")=$$gderead(1) ; remove else
+ s regs(s,"JOURNAL")=$$gderead(1)
+ s regs(s,"KEY_SIZE")=$$gderead(5)
+ s regs(s,"LOCK_WRITE")=$$gderead(1)
+ s regs(s,"NULL_SUBSCRIPTS")=$$gderead(1)
+ s regs(s,"RECORD_SIZE")=$$gderead(5)
+ q
+gdeseg:
+ s s=$$gderead(MAXSEGLN)
+ s segs(s,"ACCESS_METHOD")=$$gderead(4)
+ s segs(s,"BG","ACCESS_METHOD")=$$gderead(4)
+ s segs(s,"BG","ALLOCATION")=$$gderead(10)
+ s segs(s,"BG","BLOCK_SIZE")=$$gderead($l(maxseg("BG","BLOCK_SIZE")))
+ s segs(s,"BG","EXTENSION_COUNT")=$$gderead($l(maxseg("BG","EXTENSION_COUNT")))
+ s segs(s,"BG","FILE_NAME")=$$gderead(SIZEOF("file_spec"))
+ s segs(s,"BG","FILE_TYPE")=$$gderead(7)
+ s segs(s,"BG","GLOBAL_BUFFER_COUNT")=$$gderead(5)
+ s segs(s,"BG","LOCK_SPACE")=$s(v23:20,1:$$gderead(3)) ; to allow autoconvert
+ s segs(s,"MM","ACCESS_METHOD")=$$gderead(4)
+ s segs(s,"MM","ALLOCATION")=$$gderead(10)
+ s segs(s,"MM","BLOCK_SIZE")=$$gderead($l(maxseg("MM","BLOCK_SIZE")))
+ s segs(s,"MM","DEFER")=$$gderead(1)
+ s segs(s,"MM","EXTENSION_COUNT")=$$gderead($l(maxseg("MM","EXTENSION_COUNT")))
+ s segs(s,"MM","FILE_NAME")=$$gderead(SIZEOF("file_spec"))
+ s segs(s,"MM","FILE_TYPE")=$$gderead(7)
+ s segs(s,"MM","LOCK_SPACE")=$s(v23:20,1:$$gderead(3)) ; to allow autoconvert
+ s segs(s,"RMS","ACCESS_METHOD")=$$gderead(4)
+ s segs(s,"RMS","ALLOCATION")=$$gderead(10)
+ s segs(s,"RMS","BLOCK_SIZE")=$$gderead(5)
+ s segs(s,"RMS","BUCKET_SIZE")=$$gderead(5)
+ s segs(s,"RMS","EXTENSION_COUNT")=$$gderead($l(maxseg("RMS","EXTENSION_COUNT")))
+ s segs(s,"RMS","FILE_NAME")=$$gderead(SIZEOF("file_spec"))
+ s segs(s,"RMS","FILE_TYPE")=$$gderead(7)
+ s segs(s,"RMS","GLOBAL_BUFFER_COUNT")=$$gderead(5)
+ s segs(s,"RMS","WINDOW_SIZE")=$$gderead(5)
+ s segs(s,"USER","ACCESS_METHOD")=$s(v25:"USER",1:$$gderead(4)) ; to allow autoconvert
+ s segs(s,"USER","FILE_NAME")=$s(v25:"MUMPS",1:$$gderead(SIZEOF("file_spec"))) ; to allow autoconvert
+ s segs(s,"USER","FILE_TYPE")=$s(v25:"DYNAMIC",1:$$gderead(7)) ; to allow autoconvert
+ q
+gderead:(max)
+ n s
+ i $l(rec)-(rel-1)<3 d nextrec
+ s l=$e(rec,rel,rel+2),rel=rel+3,abs=abs+3
+ i l>max zm gdeerr("INPINTEG")
+ i $l(rec)-(rel-1)<l d nextrec
+ s s=$e(rec,rel,rel+l-1),rel=rel+l,abs=abs+l
+ q s
+ ;
+tmpreg:(s)
+ i $l(rec)-(rel-1)<3 d nextrec
+ s l=$e(rec,rel,rel+2),rel=rel+3,abs=abs+3
+ i $l(rec)-(rel-1)<l d nextrec
+ s tmpreg(s)=$e(rec,rel,rel+l-1),rel=rel+l,abs=abs+l
+ q
+tmpseg:(a,s)
+ i $l(rec)-(rel-1)<3 d nextrec
+ s l=$e(rec,rel,rel+2),rel=rel+3,abs=abs+3
+ i $l(rec)-(rel-1)<l d nextrec
+ s tmpseg(a,s)=$e(rec,rel,rel+l-1),rel=rel+l,abs=abs+l
+ q
+nextrec:
+ n nextrec
+ u file r nextrec
+ i debug u @useio
+ s rec=$e(rec,rel,$l(rec))_nextrec,rel=1
+ q
+
+;----------------------------------------------------------------------------------------------------------------------------------
+
+gdeinit:
+ s accmeth="\BG\MM\RMS\USER"
+ s hdrlab="GTCGBLDIR004"
+ s SIZEOF("am_offset")=296
+ s SIZEOF("blk_hdr")=7
+ s SIZEOF("dna_offset")=288
+ s SIZEOF("file_spec")=255
+ s SIZEOF("fna_offset")=19
+ s SIZEOF("gd_header")=288
+ s SIZEOF("gd_contents")=64
+ s SIZEOF("gd_map")=12
+ s SIZEOF("gd_region")=160
+ s SIZEOF("gd_segment")=400
+ s SIZEOF("gds_filedata")=80
+ s SIZEOF("jnl_filename")=49
+ s SIZEOF("mident")=8
+ s SIZEOF("rec_hdr")=3
+ s SIZEOF("dsk_blk")=512
+ s SIZEOF("rms_filedata")=224
+ s SIZEOF("struct FAB")=80,SIZEOF("struct RAB")=68
+;
+ s MAXNAMLN=SIZEOF("mident"),MAXREGLN=15,MAXSEGLN=15
+;define offsets into rms structures
+ ;fab
+ ;s RMS("FAB$B_BID")=0
+ s RMS("FAB$B_BLN")=1
+ ;s RMS("FAB$W_IFI")=2
+ s RMS("FAB$L_FOP")=4
+ ;s RMS("FAB$L_STS")=8
+ s RMS("FAB$L_STV")=12
+ s RMS("FAB$L_ALQ")=16
+ s RMS("FAB$W_DEQ")=20
+ s RMS("FAB$B_FAC")=22
+ ;s RMS("FAB$B_SHR")=23
+ ;s RMS("FAB$L_CTX")=24
+ s RMS("FAB$B_RTV")=28
+ ;s RMS("FAB$B_ORG")=29
+ ;s RMS("FAB$B_RAT")=30
+ ;s RMS("FAB$B_RFM")=31
+ ;s RMS("FAB$L_JNL")=32
+ s RMS("FAB$L_XAB")=36
+ ;s RMS("FAB$L_NAM")=40
+ s RMS("FAB$L_FNA")=44
+ s RMS("FAB$L_DNA")=48
+ s RMS("FAB$B_FNS")=52
+ s RMS("FAB$B_DNS")=53
+ ;s RMS("FAB$W_MRS")=54
+ ;s RMS("FAB$L_MRN")=56
+ s RMS("FAB$W_BLS")=60
+ s RMS("FAB$B_BKS")=62
+ s RMS("FAB$B_FSZ")=63
+ ;s RMS("FAB$L_DEV")=64
+ ;s RMS("FAB$L_SDC")=68
+ s RMS("FAB$W_GBC")=72
+ ;s RMS("FAB$B_ACMODES")=74
+ ;s RMS("FAB$B_RCF")=75
+ ;rab
+ s RMS("RAB$L_FAB")=60
+ s RMS("RAB$L_XAB")=64
+; rms
+ s minseg("RMS","ALLOCATION")=10,minseg("RMS","BLOCK_SIZE")=SIZEOF("dsk_blk"),minseg("RMS","BUCKET_SIZE")=0
+ s minseg("RMS","EXTENSION_COUNT")=0,minseg("RMS","GLOBAL_BUFFER_COUNT")=0,minseg("RMS","WINDOW_SIZE")=0
+ s maxseg("RMS","ALLOCATION")=TWO(24),maxseg("RMS","BLOCK_SIZE")=HEX(4)-SIZEOF("dsk_blk"),maxseg("RMS","BUCKET_SIZE")=63
+ s maxseg("RMS","EXTENSION_COUNT")=HEX(4)-1,maxseg("RMS","GLOBAL_BUFFER_COUNT")=32767,maxseg("RMS","WINDOW_SIZE")=255
+ q
diff --git a/sr_vvms/gdeput.m b/sr_vvms/gdeput.m
new file mode 100644
index 0000000..4e870a8
--- /dev/null
+++ b/sr_vvms/gdeput.m
@@ -0,0 +1,176 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ;
+; Copyright 2006 Fidelity Information Services, Inc ;
+; ;
+; This source code contains the intellectual property ;
+; of its copyright holder(s), and is made available ;
+; under a license. If you do not know the terms of ;
+; the license, please stop and do not read further. ;
+; ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+gdeput: ;output the result of the session to the global directory file
+GDEPUT()
+ n rec,gds,cregs,csegs,cregcnt,csegcnt,maxrecsize,mapcnt,map
+ d PUTMAKE^GDEMAP
+ s s="",gdeputzs=""
+ f mapcnt=0:1 s s=$o(map(s)) q:'$l(s) s cregs(map(s))=""
+ s maxrecsize=0
+ f cregcnt=0:1 s s=$o(cregs(s)) q:'$l(s) d
+ . s csegs(regs(s,"DYNAMIC_SEGMENT"))=s i maxrecsize<regs(s,"RECORD_SIZE") s maxrecsize=regs(s,"RECORD_SIZE")
+ f csegcnt=0:1 s s=$o(csegs(s)) q:'$l(s) d fdatum
+ i cregcnt'=csegcnt d error1
+ s x=SIZEOF("gd_contents")+(mapcnt*SIZEOF("gd_map")),s=""
+ f i=0:1 s s=$o(cregs(s)) q:'$l(s) s cregs(s,"offset")=i*SIZEOF("gd_region")+x
+ s x=x+(cregcnt*SIZEOF("gd_region"))
+ f i=0:1 s s=$o(csegs(s)) q:'$l(s) s csegs(s,"offset")=i*SIZEOF("gd_segment")+x
+ s x=x+(csegcnt*SIZEOF("gd_segment"))
+ s rec=""
+; contents
+ s rec=rec_$c(0,0,0,0) ; not used
+ s rec=rec_$$num2bin(4,maxrecsize) ; max rec size
+ s filesize=SIZEOF("gd_contents")
+ s rec=rec_$$num2bin(2,mapcnt)_$$num2bin(2,cregcnt)_$$num2bin(2,csegcnt)_$$num2bin(2,0) ; maps,regs,segs,filler
+ s rec=rec_$$num2bin(4,filesize) ; mapptr
+ s filesize=filesize+(mapcnt*SIZEOF("gd_map"))
+ s rec=rec_$$num2bin(4,filesize) ; regionptr
+ s filesize=filesize+(cregcnt*SIZEOF("gd_region"))
+ s rec=rec_$$num2bin(4,filesize) ; segmentptr
+ s filesize=filesize+(csegcnt*SIZEOF("gd_segment")),base=filesize
+ s rec=rec_$tr($j("",12)," ",ZERO) ; reserved
+ s rec=rec_$$num2bin(4,filesize) ; end
+ s rec=hdrlab_$$num2bin(4,$l(hdrlab)+4+filesize)_rec
+ i create zm gdeerr("GDCREATE"):file
+ e s:$ZVersion["VMS" $p(file,";",2)=$p(file,";",2)+1 zm gdeerr("GDUPDATE"):file
+ s gdexcept="s gdeputzs=$zs zgoto "_$zl_":writeerr^GDEPUT"
+ i $ZVersion["VMS" s tempfile=$p(file,";",1)_"inprogress"
+ e s tempfile=file_"inprogress"
+ s chset=$SELECT($ZV["OS390":"ISO8859-1",1:"")
+ o tempfile:(rewind:noreadonly:newversion:recordsize=512:fixed:blocksize=512:exception=gdexcept:ochset=chset)
+; maps
+ s s=""
+ f s s=$o(map(s)) q:'$l(s) d map
+; cregs
+ f s s=$o(cregs(s)) q:'$l(s) d cregion
+; csegs
+ f s s=$o(csegs(s)) q:'$l(s) d csegment
+; template access method
+ i accmeth'[("\"_tmpacc) d error1
+ s rec=rec_$tr($j($l(tmpacc),3)," ",0)
+ s rec=rec_tmpacc
+; templates
+ f s s=$o(tmpreg(s)) q:'$l(s) s rec=rec_$tr($j($l(tmpreg(s)),3)," ",0) s rec=rec_tmpreg(s)
+ f i=2:1:$l(accmeth,"\") s am=$p(accmeth,"\",i) s s="" d
+ . f s s=$o(tmpseg(am,s)) q:'$l(s) s rec=rec_$tr($j($l(tmpseg(am,s)),3)," ",0),rec=rec_tmpseg(am,s)
+ u tempfile
+ f s record=$e(rec,1,512),rec=$e(rec,513,9999) q:'$l(record) w record,!
+ u @useio
+ i $ZV'["VMS" o file c file:delete
+ c tempfile:rename=file
+ q 1
+
+;-----------------------------------------------------------------------------------------------------------------------------------
+
+fdatum:
+ s x=segs(s,"ACCESS_METHOD")
+ s filetype=$s((x="BG")!(x="MM"):"GDS",x="USER":"USER",1:"ERROR")
+ i filetype="ERROR" d error1
+ q
+map:
+ d writerec
+ i $l(s)'=SIZEOF("mident") d error1
+ s rec=rec_s_$$num2bin(4,cregs(map(s),"offset"))
+ q
+cregion:
+ d writerec
+ s rec=rec_$$num2bin(2,$l(s))
+ s rec=rec_s_$tr($j("",MAXREGLN-$l(s))," ",ZERO)
+ s rec=rec_$$num2bin(2,regs(s,"KEY_SIZE"))
+ s rec=rec_$$num2bin(4,regs(s,"RECORD_SIZE"))
+ s rec=rec_$$num2bin(4,csegs(regs(s,"DYNAMIC_SEGMENT"),"offset"))
+ s rec=rec_$$num2bin(4,0)
+ s rec=rec_ZERO ; OPEN state
+ s rec=rec_ZERO ; LOCK_WRITE
+ s rec=rec_$c(regs(s,"NULL_SUBSCRIPTS"))
+ s rec=rec_$c(regs(s,"JOURNAL"))
+ s rec=rec_$$num2bin(4,regs(s,"ALLOCATION"))
+ s rec=rec_$$num2bin(2,regs(s,"EXTENSION"))
+ s rec=rec_$$num2bin(2,regs(s,"BUFFER_SIZE"))
+ s rec=rec_$c(regs(s,"BEFORE_IMAGE"))
+ s rec=rec_$tr($j("",4)," ",ZERO) ;filler
+ s rec=rec_$$num2bin(1,regs(s,"COLLATION_DEFAULT"))
+ s rec=rec_$$num2bin(1,regs(s,"STDNULLCOLL"))
+ s rec=rec_$$num2bin(1,$l(regs(s,"FILE_NAME")))
+ s rec=rec_regs(s,"FILE_NAME")_$tr($j("",SIZEOF("file_spec")-$l(regs(s,"FILE_NAME")))," ",ZERO)
+ s rec=rec_$tr($j("",8)," ",ZERO) ; reserved
+ q
+csegment:
+ d writerec
+ s ref=$l(rec)
+ s am=segs(s,"ACCESS_METHOD")
+ s rec=rec_$$num2bin(2,$l(s))
+ s rec=rec_s_$tr($j("",MAXSEGLN-$l(s))," ",ZERO)
+ s rec=rec_$$num2bin(2,$l(segs(s,"FILE_NAME")))
+ s rec=rec_segs(s,"FILE_NAME")_$tr($j("",SIZEOF("file_spec")-$l(segs(s,"FILE_NAME")))," ",ZERO)
+ s rec=rec_$$num2bin(2,segs(s,"BLOCK_SIZE"))
+ s rec=rec_$$num2bin(2,segs(s,"EXTENSION_COUNT"))
+ s rec=rec_$$num2bin(4,segs(s,"ALLOCATION"))
+ s rec=rec_$tr($j("",4)," ",ZERO) ;reserved for clb
+ s rec=rec_".DAT"
+ s rec=rec_$c(+segs(s,"DEFER"))
+ s rec=rec_ZERO ;DYNAMIC segment
+ s rec=rec_$$num2bin(1,segs(s,"BUCKET_SIZE"))
+ s rec=rec_$$num2bin(1,segs(s,"WINDOW_SIZE"))
+ s rec=rec_$$num2bin(4,segs(s,"LOCK_SPACE"))
+ s rec=rec_$$num2bin(4,segs(s,"GLOBAL_BUFFER_COUNT"))
+ s rec=rec_$$num2bin(4,segs(s,"RESERVED_BYTES"))
+ s x=$s(am="BG":1,am="MM":2,am="USER":4,1:-1)
+ i x=-1 d error1
+ s rec=rec_$$num2bin(4,x)
+ s rec=rec_$$num2bin(4,0) ; file_cntl ptr
+ s rec=rec_$$num2bin(4,0) ; repl_list ptr
+ q
+
+;-----------------------------------------------------------------------------------------------------------------------------------
+
+num2bin:(l,n)
+ q $s(l=1:$$num2tiny(+n),l=2:$$num2shrt(+n),l=4:$$num2long(+n),1:$$num2error)
+ ;
+num2tiny:(num)
+ i (num<0)!(num'<256) d error1
+ q $c(num)
+ ;
+num2shrt:(num)
+ i (num<0)!(num'<TWO(16)) d error1
+ i endian=TRUE q $c(num\256,num#256)
+ e q $c(num#256,num\256)
+ ;
+num2long:(num)
+ i (num<0)!(num'<TWO(32)) d error1
+ i endian=TRUE q $c(num/16777216,num/65536#256,num/256#256,num#256)
+ e q $c(num#256,num/256#256,num/65536#256,num/16777216)
+
+num2error:()
+ d error1
+ q 0
+
+;----------------------------------------------------------------------------------------------------------------------------------
+
+fatal:(msgno)
+ q msgno\8*8+4
+ ;
+error1:
+ s $et="d ABORT^GDE"
+ c tempfile:delete
+ zm $$fatal(gdeerr("VERIFY")):"FAILED"
+ ;
+writerec:
+ i $l(rec)<512 q
+ s record=$e(rec,1,512),rec=$e(rec,513,9999)
+ u tempfile w record,! u @useio
+ q
+ ;
+writeerr
+ u @useio
+ c tempfile:delete
+ zm gdeerr("WRITEERROR"):gdeputzs
+ q 0
diff --git a/sr_vvms/gdeverif.m b/sr_vvms/gdeverif.m
new file mode 100644
index 0000000..f336854
--- /dev/null
+++ b/sr_vvms/gdeverif.m
@@ -0,0 +1,196 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ;
+; Copyright 2006, 2012 Fidelity Information Services, Inc ;
+; ;
+; This source code contains the intellectual property ;
+; of its copyright holder(s), and is made available ;
+; under a license. If you do not know the terms of ;
+; the license, please stop and do not read further. ;
+; ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+verify: ;implement the verb: VERIFY, also invoked from show and GDEGET
+ALL() ;external
+ n verified,gqual s verified=1
+ s gqual="NAME" d ALLNAM
+ s gqual="REGION" d ALLREG,usereg
+ s gqual="SEGMENT" d ALLSEG,useseg
+ d ALLTEM
+ zm gdeerr("VERIFY"):$s(verified:"OK",1:"FAILED") w !
+ q verified
+
+;-----------------------------------------------------------------------------------------------------------------------------------
+; called from GDEPARSE.M
+
+ALLNAM
+ n NAME s NAME=""
+ f s NAME=$o(nams(NAME)) q:'$l(NAME) d name1
+ q
+ALLREG
+ n REGION s REGION=""
+ f s REGION=$o(regs(REGION)) q:'$l(REGION) d region1
+ q
+ALLSEG
+ n SEGMENT s SEGMENT=""
+ f s SEGMENT=$o(segs(SEGMENT)) q:'$l(SEGMENT) d seg1
+; No duplicate region->segment mappings
+ n refdyns s s=""
+ f s s=$o(regs(s)) q:'$l(s) d:$d(refdyns(regs(s,"DYNAMIC_SEGMENT"))) dupseg s refdyns(regs(s,"DYNAMIC_SEGMENT"),s)=""
+; No duplicate segment->file mappings
+ n reffils
+ f s s=$o(segs(s)) q:'$l(s) d:$d(reffils(segs(s,"FILE_NAME"))) dupfile s reffils(segs(s,"FILE_NAME"),s)=""
+ q
+NAME
+ i '$d(nams(NAME)) k verified zm $$info(gdeerr("OBJNOTFND")):"Name":$s(NAME'="#":NAME,1:"Local Locks") q
+name1: i '$d(regs(nams(NAME))) s verified=0 zm gdeerr("MAPBAD"):"Region":nams(NAME):"Name":$s(NAME'="#":NAME,1:"Local Locks")
+ q
+REGION
+ i '$d(regs(REGION)) k verified zm $$info(gdeerr("OBJNOTFND")):"Region":REGION q
+region1: i '$d(segs(regs(REGION,"DYNAMIC_SEGMENT"))) s verified=0
+ i zm gdeerr("MAPBAD"):"Dynamic segment":regs(REGION,"DYNAMIC_SEGMENT"):"Region":REGION q
+ n rquals s s=""
+ f s s=$o(regs(REGION,s)) q:'$l(s) s rquals(s)=regs(REGION,s)
+ f s s=$o(minreg(s)) q:'$l(s) i '$d(rquals(s)) s verified=0 zm $$info(gdeerr("QUALREQD")):s,gdeerr("REGIS"):REGION
+ f s s=$o(maxreg(s)) q:'$l(s) i '$d(rquals(s)) s verified=0 zm $$info(gdeerr("QUALREQD")):s,gdeerr("REGIS"):REGION
+ s x=$$RQUALS(.rquals)
+ q
+SEGMENT
+ i '$d(segs(SEGMENT)) k verified zm $$info(gdeerr("OBJNOTFND")):"Segment":SEGMENT q
+seg1: i '$d(segs(SEGMENT,"ACCESS_METHOD")) s verified=0 zm $$info(gdeerr("QUALREQD")):"Access method",gdeerr("SEGIS"):"":SEGMENT q
+ s am=segs(SEGMENT,"ACCESS_METHOD")
+ n squals s s=""
+ f s s=$o(segs(SEGMENT,s)) q:'$l(s) s squals(s)=segs(SEGMENT,s)
+ f s s=$o(minseg(am,s)) q:'$l(s) i '$d(squals(s)) s verified=0 zm $$info(gdeerr("QUALREQD")):s,gdeerr("SEGIS"):am:SEGMENT
+ f s s=$o(maxseg(am,s)) q:'$l(s) i '$d(squals(s)) s verified=0 zm $$info(gdeerr("QUALREQD")):s,gdeerr("SEGIS"):am:SEGMENT
+ s x=$$SQUALS(am,.squals)
+ q
+usereg: n REGION,NAME s REGION=""
+ f s REGION=$o(regs(REGION)) q:'$l(REGION) d usereg1
+ q
+usereg1: s NAME=""
+ f s NAME=$o(nams(NAME)) q:$g(nams(NAME))=REGION!'$l(NAME)
+ i '$l(NAME) s verified=0 zm gdeerr("MAPBAD"):"A":"NAME":"REGION":REGION
+ q
+useseg: n SEGMENT,REGION s SEGMENT=""
+ f s SEGMENT=$o(segs(SEGMENT)) q:'$l(SEGMENT) d useseg1
+ q
+useseg1: s REGION=""
+ f s REGION=$o(regs(REGION)) q:$g(regs(REGION,"DYNAMIC_SEGMENT"))=SEGMENT!'$l(REGION)
+ i '$l(REGION) s verified=0 zm gdeerr("MAPBAD"):"A":"REGION":"SEGMENT":SEGMENT
+ q
+;-----------------------------------------------------------------------------------------------------------------------------------
+; routine services
+
+info:(mesno)
+ q mesno\8*8+3
+ ;
+dupseg: s verified=0
+ zm gdeerr("MAPDUP"):"Regions":$o(refdyns(regs(s,"DYNAMIC_SEGMENT"),"")):s:"Dynamic segment":regs(s,"DYNAMIC_SEGMENT")
+ q
+dupfile: s verified=0
+ zm gdeerr("MAPDUP"):"Dynamic segments":$o(reffils(segs(s,"FILE_NAME"),"")):s:"File":segs(s,"FILE_NAME")
+ q
+ALLTEM
+ s x=$$TRQUALS(.tmpreg)
+ ; The change is for TR C9E02-002518, any template command updates only active segment
+ ; so verify only that segment with template region, not all segments
+ d tmpseg
+ q
+tmpseg: n squals s s=""
+ f s s=$o(tmpseg(am,s)) q:'$l(s) s squals(s)=tmpseg(am,s)
+ s x=$$TSQUALS(am,.squals)
+ q
+regelm: i s'="DYNAMIC_SEGMENT",'$d(tmpreg(s)) zm $$info(gdeerr("QUALBAD")):s
+ e i $d(minreg(s)),minreg(s)>rquals(s) zm gdeerr("VALTOOSMALL"):rquals(s):minreg(s):s
+ e i $d(maxreg(s)),maxreg(s)<rquals(s) zm gdeerr("VALTOOBIG"):rquals(s):maxreg(s):s
+ i s verified=0 zm gdeerr("REGIS"):REGION
+ q
+segelm: i s'="FILE_NAME",'$l(tmpseg(am,s)) zm $$info(gdeerr("QUALBAD")):s
+ e i $d(minseg(am,s)),minseg(am,s)>squals(s) zm gdeerr("VALTOOSMALL"):squals(s):minseg(am,s):s
+ e i $d(maxseg(am,s)),maxseg(am,s)<squals(s) zm gdeerr("VALTOOBIG"):squals(s):maxseg(am,s):s
+ i s verified=0 zm gdeerr("SEGIS"):am:SEGMENT
+ q
+rec2blk: s y=s-f-SIZEOF("blk_hdr")
+ i x>y s verified=0 zm gdeerr("RECSIZIS"):x,gdeerr("REGIS"):REGION,gdeerr("RECTOOBIG"):s:f:y,gdeerr("SEGIS"):am:SEGMENT
+ q
+buf2blk: i REGION="TEMPLATE","USER"[am,am'=tmpacc q
+ i "USER"[am s verified=0 zm gdeerr("NOJNL"):am,gdeerr("REGIS"):REGION,gdeerr("SEGIS"):am:SEGMENT
+ s y=s/256
+ i y>x s verified=0 zm gdeerr("BUFSIZIS"):x,gdeerr("REGIS"):REGION,gdeerr("BUFTOOSMALL"):s:y,gdeerr("SEGIS"):am:SEGMENT
+ q
+mmbichk: i REGION="TEMPLATE",am="MM",tmpacc'="MM" q
+ i am="MM" s verified=0 zm gdeerr("MMNOBEFORIMG"),gdeerr("REGIS"):REGION,gdeerr("SEGIS"):am:SEGMENT
+ q
+prefix(str1,str2) ;check whether str1 is a prefix of str2
+ n len1,len2
+ s len1=$l(str1),len2=$l(str2)
+ q:(len1>len2)!'len1 0
+ i ($e(str2,1,len1)=str1) q 1
+ q 0
+
+;-----------------------------------------------------------------------------------------------------------------------------------
+; called from GDEADD.M and GDECHANG.M
+
+RQUALS(rquals)
+ i '$d(verified) n verified s verified=1
+ s s=""
+ f s s=$o(rquals(s)) q:'$l(s) d regelm
+ i $d(rquals("FILE_NAME")),$l(rquals("FILE_NAME"))>(SIZEOF("file_spec")-1) s verified=0
+ i zm $$info(gdeerr("VALTOOLONG")):rquals("FILE_NAME"):SIZEOF("file_spec")-1:"Journal filename",gdeerr("REGIS"):REGION
+ s s="KEY_SIZE",s=$s($d(rquals(s)):rquals(s),$d(regs(REGION,s)):regs(REGION,s),1:tmpreg(s))
+ s x="RECORD_SIZE",x=$s($d(rquals(x)):rquals(x),$d(regs(REGION,x)):regs(REGION,x),1:tmpreg(x))
+ i s+4>x s verified=0 zm gdeerr("KEYSIZIS"):s,gdeerr("KEYTOOBIG"):x:x-4,gdeerr("REGIS"):REGION
+ i REGION="TEMPLATE" s s=tmpseg(tmpacc,"BLOCK_SIZE"),f=tmpseg(tmpacc,"RESERVED_BYTES")
+ e s s="DYNAMIC_SEGMENT",s=$s($d(rquals(s)):rquals(s),$d(regs(REGION,s)):regs(REGION,s),1:0)
+ e q:'$d(segs(s)) verified n SEGMENT,am d
+ . s SEGMENT=s,am=segs(s,"ACCESS_METHOD"),s=$g(segs(s,"BLOCK_SIZE")),f=$g(segs(s,"RESERVED_BYTES"))
+ i am'="USER" d rec2blk
+ s x="JOURNAL"
+ i '$s('$d(rquals(x)):tmpreg(x),1:rquals(x)) q verified
+ s x="BUFFER_SIZE",x=$s($d(rquals(x)):rquals(x),$d(regs(REGION,x)):regs(REGION,x),1:tmpreg(x)) d buf2blk
+ i nommbi s x="BEFORE_IMAGE" i $s('$d(rquals(x)):tmpreg(x),1:rquals(x)) d mmbichk
+ q verified
+ ;
+SQUALS(am,squals)
+ i '$d(verified) n verified s verified=1
+ n s s s=""
+ f s s=$o(squals(s)) q:'$l(s) i $l(squals(s)) d segelm
+ s s="BLOCK_SIZE"
+ i $d(squals(s)),squals(s)#512 s x=squals(s),squals(s)=x\512+1*512
+ i zm gdeerr("BLKSIZ512"):x:squals(s),gdeerr("SEGIS"):am:SEGMENT
+ s s="WINDOW_SIZE"
+ i SEGMENT="TEMPLATE" s x=tmpreg("RECORD_SIZE") d segreg q verified
+ n REGION s REGION=""
+ f s REGION=$o(regs(REGION)) q:'$l(REGION) i regs(REGION,"DYNAMIC_SEGMENT")=SEGMENT s s=regs(REGION,"RECORD_SIZE") d segreg
+ q verified
+segreg:
+ i am'="USER" d
+ . s s="BLOCK_SIZE",s=$s($d(squals(s)):squals(s),$d(segs(SEGMENT,s)):segs(SEGMENT,s),1:tmpseg(am,s))
+ . s f="RESERVED_BYTES",f=$s($d(squals(f)):squals(f),$d(segs(SEGMENT,s)):seg(SEGMENT,f),1:tmpseg(am,f))
+ . s x="RECORD_SIZE",x=$s($d(regs(REGION,x)):regs(REGION,x),1:tmpreg(x))
+ . d rec2blk
+ i '$s(SEGMENT="TEMPLATE":tmpreg("JOURNAL"),1:regs(REGION,"JOURNAL")) q
+ s x=$s(SEGMENT="TEMPLATE":tmpreg("BUFFER_SIZE"),1:regs(REGION,"BUFFER_SIZE")) d buf2blk
+ i nommbi,$s(SEGMENT="TEMPLATE":tmpreg("BEFORE_IMAGE"),1:regs(REGION,"BEFORE_IMAGE")) d mmbichk
+ q
+
+;-----------------------------------------------------------------------------------------------------------------------------------
+; called from GDETEMPL.M
+
+TRQUALS(rquals)
+ n REGION,SEGMENT,am s (REGION,SEGMENT)="TEMPLATE",am=tmpacc
+ q $$RQUALS(.rquals)
+ ;
+TSQUALS(am,squals)
+ n REGION,SEGMENT s (REGION,SEGMENT)="TEMPLATE"
+ q $$SQUALS(am,.squals)
+
+;-----------------------------------------------------------------------------------------------------------------------------------
+; called from GDEADD.M, GDECHANG.M and GDETEMPL.M, [GTM-7184]
+NQUALS(rquals)
+ n nullsub s nullsub=rquals("NULL_SUBSCRIPTS")
+ i ($$prefix(nullsub,"NEVER")!$$prefix(nullsub,"FALSE")) s rquals("NULL_SUBSCRIPTS")=0
+ e d
+ . i ($$prefix(nullsub,"ALWAYS")!$$prefix(nullsub,"TRUE")) s rquals("NULL_SUBSCRIPTS")=1
+ . e d
+ . . i ($$prefix(nullsub,"EXISTING")) s rquals("NULL_SUBSCRIPTS")=2
+ q
diff --git a/sr_vvms/gds_file_size.c b/sr_vvms/gds_file_size.c
new file mode 100644
index 0000000..48f95aa
--- /dev/null
+++ b/sr_vvms/gds_file_size.c
@@ -0,0 +1,59 @@
+/****************************************************************
+ * *
+ * Copyright 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include <rms.h>
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "gtmmsg.h"
+
+error_def(ERR_DBFILOPERR);
+
+/* If a routine other than mupip integ uses this module, the interface and error reporting may need to change. */
+gtm_uint64_t gds_file_size(file_control *fc)
+{
+ vms_gds_info *gds_info;
+ uint4 status;
+ unsigned int ret_size;
+ struct FAB fab;
+ struct XABFHC xab;
+
+ gds_info = (vms_gds_info *)fc->file_info;
+ if (gds_info->xabfhc)
+ { /* if sys$open fails, we will be returning xab$l_ebk that was prior existing and printing an error message. */
+ ret_size = gds_info->xabfhc->xab$l_ebk;
+
+ fab = cc$rms_fab;
+ xab = cc$rms_xabfhc;
+ fab.fab$l_xab = &xab;
+ fab.fab$l_fna = gds_info->fab->fab$l_fna;
+ fab.fab$b_fns = gds_info->fab->fab$b_fns;
+ fab.fab$b_fac = FAB$M_GET;
+ fab.fab$b_shr = FAB$M_SHRPUT | FAB$M_SHRGET;
+ if (RMS$_NORMAL == (status = sys$open(&fab)))
+ {
+ ret_size = xab.xab$l_ebk;
+ status = sys$close(&fab);
+ }
+ if (RMS$_NORMAL != status)
+ gtm_putmsg(VARLSTCNT(8) ERR_DBFILOPERR, 2, FAB_LEN_STR(&fab), 0, status);
+ } else
+ ret_size = 0;
+ return (gtm_uint64_t)ret_size;
+}
diff --git a/sr_vvms/gds_rundown.c b/sr_vvms/gds_rundown.c
new file mode 100644
index 0000000..a2886f8
--- /dev/null
+++ b/sr_vvms/gds_rundown.c
@@ -0,0 +1,583 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <descrip.h>
+#include <fab.h>
+#include <lckdef.h>
+#include <iodef.h>
+#include <psldef.h>
+#include <secdef.h>
+#include <ssdef.h>
+#include <efndef.h>
+
+#include "gtm_time.h"
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "ast.h"
+#include "ccp.h"
+#include "ccpact.h"
+#include "cdb_sc.h"
+#include "efn.h"
+#include "jnl.h"
+#include "timers.h"
+#include "error.h"
+#include "iosp.h"
+#include "locks.h"
+#include "util.h"
+#include "send_msg.h"
+#include "change_reg.h"
+#include "is_proc_alive.h"
+#include "del_sec.h"
+#include "mem_list.h"
+#include "gvusr.h"
+#include "gtmmsg.h"
+#include "wcs_recover.h"
+#include "wcs_flu.h"
+#include "gtmimagename.h"
+#include "iosb_disk.h"
+#include "wbox_test_init.h"
+#include "shmpool.h" /* needed for shmpool structures */
+
+GBLREF gd_region *gv_cur_region;
+GBLREF sgmnt_addrs *cs_addrs;
+GBLREF sgmnt_data_ptr_t cs_data;
+GBLREF int4 exi_condition;
+GBLREF uint4 image_count, process_id;
+GBLREF short crash_count, astq_dyn_avail;
+GBLREF boolean_t is_src_server;
+GBLREF boolean_t is_rcvr_server;
+GBLREF boolean_t is_updproc;
+GBLREF boolean_t mupip_jnl_recover;
+GBLREF jnl_process_vector *originator_prc_vec;
+GBLREF jnl_process_vector *prc_vec;
+GBLREF jnl_gbls_t jgbl;
+GBLREF boolean_t mu_rndwn_process;
+GBLREF boolean_t dse_running;
+#ifdef DEBUG
+GBLREF boolean_t in_mu_rndwn_file;
+#endif
+
+LITREF char gtm_release_name[];
+LITREF int4 gtm_release_name_len;
+
+static const unsigned short zero_fid[3];
+
+error_def(ERR_ASSERT);
+error_def(ERR_CRITRESET);
+error_def(ERR_DBRNDWN);
+error_def(ERR_DBRNDWNWRN);
+error_def(ERR_GTMASSERT);
+error_def(ERR_GTMASSERT2);
+error_def(ERR_GTMCHECK);
+error_def(ERR_IPCNOTDEL);
+error_def(ERR_JNLFLUSH);
+error_def(ERR_OUTOFSPACE);
+error_def(ERR_STACKOFLOW);
+error_def(ERR_TEXT);
+error_def(ERR_VMSMEMORY);
+
+CONDITION_HANDLER(gds_rundown_ch)
+{
+ vms_gds_info *gds_info;
+ jnl_private_control *jpc = NULL;
+ uint4 outaddrs[2], retadr[2], status;
+ boolean_t nonclst_bg;
+
+ START_CH;
+
+ if (PRO_ONLY(mu_rndwn_process &&) DUMPABLE && !SUPPRESS_DUMP)
+ TERMINATE;
+ /* deq all the locks, so it wont affect other processes */
+ gds_info = gv_cur_region->dyn.addr->file_cntl->file_info;
+ cs_addrs = &gds_info->s_addrs;
+ DEBUG_ONLY(in_mu_rndwn_file = FALSE);
+ TREF(donot_write_inctn_in_wcs_recover) = FALSE; /* might have been set to TRUE in mu_rndwn_file(). */
+ if (cs_addrs)
+ {
+ if (cs_addrs->now_crit)
+ rel_crit(gv_cur_region);
+ jpc = cs_addrs->jnl;
+ }
+ if (jpc && jpc->jnllsb && 0 != jpc->jnllsb->lockid)
+ {
+ status = gtm_deq(jpc->jnllsb->lockid, NULL, PSL$C_USER, 0);
+ assert(SS$_NORMAL == status);
+ jpc->jnllsb->lockid = 0;
+ }
+ if (0 != gds_info->cx_cntl_lsb.lockid)
+ {
+ status = gtm_deq(gds_info->cx_cntl_lsb.lockid, NULL, PSL$C_USER, 0);
+ assert(SS$_NORMAL == status);
+ gds_info->cx_cntl_lsb.lockid = 0;
+ }
+ if (0 != gds_info->file_cntl_lsb.lockid)
+ {
+ status = gtm_deq(gds_info->file_cntl_lsb.lockid, NULL, PSL$C_USER, 0);
+ assert(SS$_NORMAL == status);
+ gds_info->file_cntl_lsb.lockid = 0;
+ }
+
+ /* -------------------------- take care of address space ------------------------- */
+ if (cs_addrs)
+ {
+ if (cs_addrs->hdr)
+ {
+ nonclst_bg = (dba_bg == cs_addrs->hdr->acc_meth);
+ if (FALSE == nonclst_bg)
+ {
+ cs_addrs->lock_addrs[1] = (sm_uc_ptr_t)(cs_addrs->nl) + ROUND_UP(LOCK_SPACE_SIZE(cs_addrs->hdr)
+ + NODE_LOCAL_SPACE(cs_addrs->hdr) + JNL_SHARE_SIZE(cs_addrs->hdr)
+ + SHMPOOL_BUFFER_SIZE + 1, OS_PAGE_SIZE) + 1;
+ cs_addrs->lock_addrs[0] = (sm_uc_ptr_t)(cs_addrs->nl);
+ if (FALSE == is_va_free(cs_addrs->lock_addrs[0]))
+ gtm_deltva(cs_addrs->lock_addrs, retadr, PSL$C_USER);
+ }
+ }
+ outaddrs[0] = cs_addrs->db_addrs[0] - OS_PAGE_SIZE; /* header no access page */
+ outaddrs[1] = cs_addrs->db_addrs[1] + OS_PAGE_SIZE; /* trailer no access page */
+ if (FALSE == is_va_free(outaddrs[0]))
+ gtm_deltva(outaddrs, retadr, PSL$C_USER);
+ }
+
+ sys$dassgn(gds_info->fab->fab$l_stv);
+ gv_cur_region->open = FALSE;
+ if (cs_addrs)
+ {
+ cs_addrs->hdr = NULL;
+ cs_addrs->nl = NULL;
+ REMOVE_CSA_FROM_CSADDRSLIST(cs_addrs); /* remove "cs_addrs" from list of open regions (cs_addrs_list) */
+ cs_addrs->db_addrs[0] = NULL;
+ cs_addrs->lock_addrs[0] = NULL;
+ }
+ PRN_ERROR;
+ gtm_putmsg(VARLSTCNT(4) ERR_DBRNDWN, 2, REG_LEN_STR(gv_cur_region));
+ UNWIND(NULL, NULL);
+}
+
+void gds_rundown(void)
+{
+ bool nonclst_bg, clustered, read_write;
+ char name_buff[GLO_NAME_MAXLEN];
+ io_status_block_disk iosb;
+ uint4 jnl_status, last_one_status, outaddrs[2], retadr[2], status, we_are_last_writer;
+ vms_gds_info *gds_info;
+ boolean_t ipc_deleted, remove_shm, cancelled_timer, cancelled_dbsync_timer, vermismatch;
+ now_t now; /* for GET_CUR_TIME macro*/
+ char *time_ptr, time_str[CTIME_BEFORE_NL + 2]; /* for GET_CUR_TIME macro*/
+ jnl_private_control *jpc;
+ jnl_buffer_ptr_t jbp;
+ $DESCRIPTOR(desc, name_buff);
+
+ jnl_status = 0;
+ if (!gv_cur_region->open)
+ return;
+ if (dba_usr == gv_cur_region->dyn.addr->acc_meth)
+ {
+ change_reg();
+ gvusr_rundown();
+ return;
+ }
+ if ((dba_bg != gv_cur_region->dyn.addr->acc_meth) && (dba_mm != gv_cur_region->dyn.addr->acc_meth))
+ return;
+ ESTABLISH(gds_rundown_ch);
+ gds_info = gv_cur_region->dyn.addr->file_cntl->file_info;
+ cs_addrs = &gds_info->s_addrs;
+ assert(cs_data == cs_addrs->hdr);
+ clustered = cs_addrs->hdr->clustered;
+ crash_count = cs_addrs->critical->crashcnt;
+ last_one_status = we_are_last_writer = FALSE;
+ nonclst_bg = (dba_bg == cs_addrs->hdr->acc_meth);
+ read_write = (FALSE == gv_cur_region->read_only);
+ if (!cs_addrs->persistent_freeze)
+ region_freeze(gv_cur_region, FALSE, FALSE, FALSE);
+ if (ERR_CRITRESET != exi_condition)
+ rel_crit(gv_cur_region);
+ sys$cantim(gv_cur_region, PSL$C_USER); /* cancel all database write timers and jnl_mm_timer()s for this region */
+ cancelled_timer = FALSE;
+ if (cs_addrs->timer)
+ {
+ adawi(-1, &cs_addrs->nl->wcs_timers);
+ cs_addrs->timer = FALSE;
+ cancelled_timer = TRUE;
+ ++astq_dyn_avail;
+ }
+ /* The order of resetting cs_addrs->dbsync_timer and the sys$cantim(cs_addrs) following it is important.
+ * This is because once dbsync_timer is set to FALSE, both wcs_clean_dbsync_timer_ast and wcs_clean_dbsync_ast
+ * know not to proceed with the dbsync any further.
+ * If we cancelled the timer first, then it is possible that before resetting dbsync_timer to FALSE, we
+ * got interrupted by wcs_clean_dbsync_timer_ast which might then set off a timer to drive
+ * wcs_clean_dbsync_ast only to have dbsync_timer reset to FALSE by the next statement in gds_rundown()
+ * effectively ending up in a situation where we will have an orphaned wcs_clean_dbsync_ast timer pop
+ * much later after the region has been rundown which we don't want.
+ */
+ cancelled_dbsync_timer = FALSE;
+ if (cs_addrs->dbsync_timer)
+ {
+ cs_addrs->dbsync_timer = FALSE;
+ cancelled_dbsync_timer = TRUE;
+ ++astq_dyn_avail;
+ }
+ sys$cantim(cs_addrs, PSL$C_USER); /* cancel all epoch-timers for this region */
+ jpc = cs_addrs->jnl;
+ if (JNL_ENABLED(cs_addrs->hdr) && IS_GTCM_GNP_SERVER_IMAGE);
+ originator_prc_vec = NULL;
+ if (memcmp(cs_addrs->nl->now_running, gtm_release_name, gtm_release_name_len + 1))
+ { /* VERMISMATCH condition. Possible only if DSE */
+ assert(dse_running);
+ vermismatch = TRUE;
+ } else
+ vermismatch = FALSE;
+ if (TRUE == clustered)
+ {
+ nonclst_bg = FALSE;
+ if (JNL_ENABLED(cs_addrs->hdr) && (NULL != jpc) && (NOJNL != jpc->channel)
+ && (0 != memcmp(cs_addrs->nl->jnl_file.jnl_file_id.fid, zero_fid, SIZEOF(zero_fid))))
+ {
+ if (0 != jpc->pini_addr)
+ {
+ grab_crit(gv_cur_region);
+ if (JNL_ENABLED(cs_addrs->hdr))
+ {
+ jnl_status = jnl_ensure_open();
+ if (jnl_status == 0)
+ {
+ jnl_put_jrt_pfin(cs_addrs);
+ if (SS_NORMAL != (jnl_status = jnl_flush(gv_cur_region)))
+ {
+ send_msg(VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(cs_data),
+ ERR_TEXT, 2,
+ RTS_ERROR_TEXT("Error with journal flush in gds_rundown1"),
+ jnl_status);
+ assert(NOJNL == jpc->channel);/* jnl file lost has been triggered */
+ /* In this routine, all code that follows from here on does not
+ * assume anything about the journaling characteristics of this
+ * database so it is safe to continue execution even though
+ * journaling got closed in the middle.
+ */
+ }
+ }
+ }
+ rel_crit(gv_cur_region);
+ }
+ if (!is_src_server)
+ {
+ assert(0 != jpc->jnllsb->lockid);
+ status = gtm_deq(jpc->jnllsb->lockid, NULL, PSL$C_USER, 0);
+ assert(SS$_NORMAL == status);
+ jpc->jnllsb->lockid = 0;
+ }
+ sys$dassgn(jpc->channel);
+ }
+ } else
+ { /* ----------------------------- acquire startup/shutdown lock ---------------------------------- */
+ /* Acquire PW mode to ensure that this is the only process in this section of the rundown code.
+ * Then attempt to get EX mode; if granted, then this process is the only process accessing the
+ * database, and cache rundown and header flushing should occur. Use the NOQUEUE flag so that
+ * we don't have to wait for the lock.
+ */
+ status = gtm_enqw(EFN$C_ENF, LCK$K_PWMODE, &gds_info->file_cntl_lsb, LCK$M_CONVERT | LCK$M_NODLCKBLK,
+ NULL, 0, NULL, 0, NULL, PSL$C_USER, 0);
+ if (SS$_NORMAL == status)
+ status = gds_info->file_cntl_lsb.cond;
+ if (SS$_NORMAL == status)
+ {
+ status = gtm_enqw(EFN$C_ENF, LCK$K_EXMODE, &gds_info->file_cntl_lsb,
+ LCK$M_CONVERT | LCK$M_NOQUEUE | LCK$M_NODLCKWT,
+ NULL, 0, NULL, 0, NULL, PSL$C_USER, 0);
+ if ((SS$_NORMAL == status) && !vermismatch)
+ last_one_status = status = gds_info->file_cntl_lsb.cond;
+ }
+ if (read_write)
+ {
+ assert(cs_addrs->nl->ref_cnt > 0);
+ assert(cs_addrs->ref_cnt);
+ /* The primary purpose of the shared ref_cnt flag is to indicate whether we are the last writer.
+ * The private ref_cnt and shared ref_cnt should always be updated in the following order.
+ * While incrementing, shared ref_cnt should be updated first
+ * While decrementing, shared ref_cnt should be updated last
+ * This way, it is guaranteed that whenever the private ref_cnt is TRUE, this process
+ * definitely has incremented the shared ref_cnt.
+ * The only issue with this is that it is possible that the shared ref_cnt has been incremented
+ * although the private ref_cnt has not been (due to STOP/ID or kill -9) or when the private
+ * ref_cnt has been decremented, while the shared ref_cnt has not been.
+ * In this case, the actual last writer might conclude he is not actually the last writer and
+ * hence might not do the necessary cleanup (like writing an EOF record in the journal file etc.)
+ * although a later MUPIP RUNDOWN will take care of doing the necessary stuff.
+ * If the ordering of updates of the shared and private ref_cnt were reversed, we have the issue of
+ * some process incorrectly concluding itself as the last writer and doing cleanup when it
+ * should not be doing so. That is dangerous and can cause damage to the database/journal.
+ */
+ if (cs_addrs->ref_cnt)
+ {
+ cs_addrs->ref_cnt--;
+ assert(!cs_addrs->ref_cnt);
+ adawi(-1, &cs_addrs->nl->ref_cnt);
+ }
+ }
+ /* ------------------------------ flush if applicable ------------------------------------------
+ * If cs_addrs->nl->donotflush_dbjnl is set, it means mupip recover/rollback was interrupted and therefore we
+ * should not flush shared memory contents to disk as they might be in an inconsistent state.
+ * In this case, we will go ahead and remove shared memory (without flushing the contents) in this routine.
+ * A reissue of the recover/rollback command will restore the database to a consistent state.
+ */
+ if (read_write && !cs_addrs->nl->donotflush_dbjnl && !vermismatch)
+ {
+ if (cs_addrs->nl->ref_cnt < 1)
+ { /* since csa->nl->ref_cnt is not an accurate indicator of whether we are the last writer or not,
+ * we need to be careful before modifying any shared memory fields below, hence the grab_crit */
+ grab_crit(gv_cur_region);
+ cs_addrs->nl->ref_cnt = 0; /* just in case for pro */
+ we_are_last_writer = TRUE;
+ /* ========================= laster writer in this region ================= */
+ if (nonclst_bg)
+ { /* Note WCSFLU_SYNC_EPOCH ensures the epoch is synced to the journal and indirectly
+ * also ensures that the db is fsynced. We don't want to use it in the calls to
+ * wcs_flu() from t_end() and tp_tend() since we can defer it to out-of-crit there.
+ * In this case, since we are running down, we don't have any such option.
+ */
+ cs_addrs->nl->remove_shm =
+ wcs_flu(WCSFLU_FLUSH_HDR | WCSFLU_WRITE_EPOCH | WCSFLU_SYNC_EPOCH);
+ }
+ assert(0 == memcmp(cs_addrs->hdr->label, GDS_LABEL, GDS_LABEL_SZ - 1));
+ cs_addrs->hdr->owner_node = 0;
+ memset(cs_addrs->hdr->now_running, 0, SIZEOF(cs_addrs->hdr->now_running));
+ if (nonclst_bg)
+ {
+ sys$qiow(EFN$C_ENF, gds_info->fab->fab$l_stv, IO$_WRITEVBLK, &iosb, NULL, 0,
+ cs_addrs->hdr, SIZEOF(sgmnt_data), 1, 0, 0, 0);
+ } else
+ {
+ if (SS$_NORMAL == sys$updsec(cs_addrs->db_addrs, NULL, PSL$C_USER, 0,
+ efn_immed_wait, &iosb, NULL, 0))
+ {
+ cs_addrs->nl->remove_shm = TRUE;
+ sys$synch(efn_immed_wait, &iosb);
+ }
+ }
+ rel_crit(gv_cur_region);
+ } else if ((cancelled_timer && (0 > cs_addrs->nl->wcs_timers)) || cancelled_dbsync_timer)
+ { /* cancelled pending db or jnl flush timers - flush database and journal buffers to disk */
+ grab_crit(gv_cur_region);
+ /* we need to sync the epoch as the fact that there is no active pending flush timer implies
+ * there will be noone else who will flush the dirty buffers and EPOCH to disk in a timely fashion
+ */
+ wcs_flu(WCSFLU_FLUSH_HDR | WCSFLU_WRITE_EPOCH | WCSFLU_SYNC_EPOCH);
+ rel_crit(gv_cur_region);
+ }
+ if (JNL_ENABLED(cs_addrs->hdr)
+ && ((NOJNL != jpc->channel) && !JNL_FILE_SWITCHED(jpc)
+ || (we_are_last_writer
+ && (0 != memcmp(cs_addrs->nl->jnl_file.jnl_file_id.fid, zero_fid, SIZEOF(zero_fid))))))
+ { /* We need to close the journal file cleanly if we have the latest generation journal file open
+ * or if we are the last writer and the journal file is open in shared memory (not necessarily
+ * by ourselves e.g. the only process that opened the journal got shot abnormally)
+ * Note: we should not rely on the shared memory value of csa->nl->jnl_file.jnl_file_id
+ * if we are not the last writer as it can be concurrently updated.
+ */
+ grab_crit(gv_cur_region);
+ if (JNL_ENABLED(cs_addrs->hdr))
+ {
+ /* jnl_ensure_open/set_jnl/jnl_file_close/jnl_put_jrt_pini/pfin need it */
+ SET_GBL_JREC_TIME;
+ /* Before writing to jnlfile, adjust jgbl.gbl_jrec_time if needed to maintain time order
+ * of jnl records. This needs to be done BEFORE the jnl_ensure_open as that could write
+ * journal records (if it decides to switch to a new journal file).
+ */
+ jbp = jpc->jnl_buff;
+ ADJUST_GBL_JREC_TIME(jgbl, jbp);
+ if (!we_are_last_writer || is_src_server)
+ { /* last writer of this database should actually execute the "else" part which calls
+ * set_jnl_file_close(), but if it happens to be the source server, then we should
+ * not go there because set_jnl_file_close() does gtm_enq and gtm_deq on jpc->jnllsb
+ * and the source-server is the only one that bypasses getting those locks in
+ * jnl_file_open. instead we call jnl_file_close() to just write an EOF record for
+ * us.
+ */
+ jnl_status = jnl_ensure_open();
+ if (0 == jnl_status)
+ {
+ if (!jgbl.mur_extract)
+ {
+ if (we_are_last_writer && (0 == jpc->pini_addr))
+ jnl_put_jrt_pini(cs_addrs);
+ if (0 != jpc->pini_addr)
+ jnl_put_jrt_pfin(cs_addrs);
+ }
+ if (FALSE == nonclst_bg)
+ { /* in the case of MM, the above jnl_put_jrt_{pini,pfin}() calls
+ * would have started timers to do jnl-qio through the call to
+ * jnl_mm_timer() from jnl_write(). we do not want the timer routine
+ * jnl_mm_timer_write() to pop and try dereferencing csa->jnl or
+ * csa->nl after we have closed the journal or have detached from
+ * this region's shared memory. cancel those timers here. Unix does
+ * not suffer from this issue since over there, jnl_mm_timer_write()
+ * is not region-based and hence does the proper checks on each
+ * region before trying to dereference csa->jnl or csa->nl.
+ */
+ sys$cantim(gv_cur_region, PSL$C_USER);
+ }
+ /* if not the last writer and no pending flush timer left,
+ * do jnl flush now.
+ */
+ if (!we_are_last_writer && (0 > cs_addrs->nl->wcs_timers))
+ {
+ if (SS_NORMAL != (jnl_status = jnl_flush(gv_cur_region)))
+ {
+ send_msg(VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(cs_data),
+ ERR_TEXT, 2,
+ RTS_ERROR_TEXT( \
+ "Error with journal flush in gds_rundown2"),
+ jnl_status);
+ /* jnl file lost has been triggered */
+ assert(NOJNL == jpc->channel);
+ /* In this routine, all code that follows from here on does
+ * not assume anything about the journaling characteristics
+ * of this database so it is safe to continue execution
+ * even though journaling got closed in the middle.
+ */
+ }
+ }
+ jnl_file_close(gv_cur_region, we_are_last_writer, FALSE);
+ }
+ } else
+ { /* since csa->nl->ref_cnt is not a reliable indicator of last writer status, we
+ * want to make sure any other process having this journal file open relinquishes
+ * control of it even though "we_are_last_writer" is TRUE. hence the call to
+ * set_jnl_file_close(). We do not check the return value below as it is not clear
+ * what to do in case of error.
+ */
+ status = set_jnl_file_close(SET_JNL_FILE_CLOSE_RUNDOWN);
+ assert(SS$_NORMAL == status);
+ }
+ assert(jpc->jnllsb->lockid || is_src_server || (NOJNL == jpc->channel));
+ }
+ rel_crit(gv_cur_region);
+ }
+ }
+ /* release the journal file lock if we have a non-zero jnllsb->lockid */
+ if ((NULL != jpc) && (0 != jpc->jnllsb->lockid))
+ {
+ assert(read_write);
+ status = gtm_deq(jpc->jnllsb->lockid, NULL, PSL$C_USER, 0);
+ assert((SS$_NORMAL == status)
+ || (SS$_IVLOCKID == status)
+ && gtm_white_box_test_case_enabled);
+ jpc->jnllsb->lockid = 0;
+ }
+ }
+ /* Get the remove_shm status from node_local before deleting address space of global section.
+ * If cs_addrs->nl->donotflush_dbjnl is TRUE, it means we can safely remove shared memory without compromising data
+ * integrity as a reissue of recover will restore the database to a consistent state.
+ */
+ remove_shm = !vermismatch && (cs_addrs->nl->remove_shm || cs_addrs->nl->donotflush_dbjnl);
+ /* -------------------------- take care of address space ------------------------- */
+ if (FALSE == nonclst_bg)
+ {
+ cs_addrs->lock_addrs[1] = (sm_uc_ptr_t)(cs_addrs->nl) + ROUND_UP(LOCK_SPACE_SIZE(cs_addrs->hdr)
+ + NODE_LOCAL_SPACE(cs_addrs->hdr) + JNL_SHARE_SIZE(cs_addrs->hdr)
+ + SHMPOOL_BUFFER_SIZE + 1, OS_PAGE_SIZE) + 1;
+ cs_addrs->lock_addrs[0] = (sm_uc_ptr_t)(cs_addrs->nl);
+ gtm_deltva(cs_addrs->lock_addrs, retadr, PSL$C_USER);
+ }
+ outaddrs[0] = cs_addrs->db_addrs[0] - OS_PAGE_SIZE; /* header no access page */
+ outaddrs[1] = cs_addrs->db_addrs[1] + OS_PAGE_SIZE; /* trailer no access page */
+ gtm_deltva(outaddrs, retadr, PSL$C_USER);
+ /* -------------------------- take care of global section ------------------------- */
+ assert (!is_rcvr_server);
+ ipc_deleted = FALSE;
+ /* Don't dismantle global section if last writer didn't succeed in flushing the cache out */
+ if (SS$_NORMAL == last_one_status)
+ {
+ if (remove_shm)
+ {
+ global_name("GT$S", &FILE_INFO(gv_cur_region)->file_id, name_buff);
+ desc.dsc$w_length = name_buff[0];
+ desc.dsc$b_dtype = DSC$K_DTYPE_T;
+ desc.dsc$b_class = DSC$K_CLASS_S;
+ desc.dsc$a_pointer = &name_buff[1];
+ assert(!vermismatch);
+ del_sec(SEC$M_SYSGBL, &desc, NULL);
+ if (FALSE == nonclst_bg)
+ {
+ name_buff[4] = 'L';
+ del_sec(SEC$M_SYSGBL, &desc, NULL);
+ }
+ ipc_deleted = TRUE;
+ } else if (is_src_server || is_updproc)
+ {
+ gtm_putmsg(VARLSTCNT(6) ERR_DBRNDWNWRN, 4, DB_LEN_STR(gv_cur_region), process_id, process_id);
+ send_msg(VARLSTCNT(6) ERR_DBRNDWNWRN, 4, DB_LEN_STR(gv_cur_region), process_id, process_id);
+ } else
+ send_msg(VARLSTCNT(6) ERR_DBRNDWNWRN, 4, DB_LEN_STR(gv_cur_region), process_id, process_id);
+ }
+ /* ------------------------- take care of locks ------------------------------------ */
+ if (TRUE == clustered)
+ {
+ /* Dequeue locks after delete section in ccp_close,
+ acquire lock before create section in gvcst_init,
+ release lock after delete section in gds_rundown */
+ status = gtm_deq(gds_info->cx_cntl_lsb.lockid, NULL, PSL$C_USER, 0);
+ assert(SS$_NORMAL == status);
+ gds_info->cx_cntl_lsb.lockid = 0;
+ status = gtm_deq(gds_info->file_cntl_lsb.lockid, NULL, PSL$C_USER, 0);
+ assert(SS$_NORMAL == status);
+ gds_info->file_cntl_lsb.lockid = 0;
+ ccp_sendmsg(CCTR_CLOSE, &FILE_INFO(gv_cur_region)->file_id);
+ } else
+ {
+ if (SS$_NORMAL == last_one_status)
+ {
+ gds_info->file_cntl_lsb.valblk[0] = 0;
+ gtm_enqw(EFN$C_ENF, LCK$K_NLMODE, &gds_info->file_cntl_lsb, LCK$M_CONVERT | LCK$M_VALBLK,
+ NULL, 0, NULL, 0, NULL, PSL$C_USER, 0);
+ }
+ status = gtm_deq(gds_info->cx_cntl_lsb.lockid, NULL, PSL$C_USER, 0);
+ assert(SS$_NORMAL == status);
+ gds_info->cx_cntl_lsb.lockid = 0;
+ status = gtm_deq(gds_info->file_cntl_lsb.lockid, NULL, PSL$C_USER, 0);
+ assert(SS$_NORMAL == status);
+ gds_info->file_cntl_lsb.lockid = 0;
+ }
+ if (!ipc_deleted)
+ {
+ GET_CUR_TIME;
+ if (is_src_server)
+ gtm_putmsg(VARLSTCNT(8) ERR_IPCNOTDEL, 6, CTIME_BEFORE_NL, time_ptr,
+ LEN_AND_LIT("Source server"), REG_LEN_STR(gv_cur_region));
+ if (is_updproc)
+ gtm_putmsg(VARLSTCNT(8) ERR_IPCNOTDEL, 6, CTIME_BEFORE_NL, time_ptr,
+ LEN_AND_LIT("Update process"), REG_LEN_STR(gv_cur_region));
+ if (mupip_jnl_recover)
+ {
+ gtm_putmsg(VARLSTCNT(8) ERR_IPCNOTDEL, 6, CTIME_BEFORE_NL, time_ptr,
+ LEN_AND_LIT("Mupip journal process"), REG_LEN_STR(gv_cur_region));
+ send_msg(VARLSTCNT(8) ERR_IPCNOTDEL, 6, CTIME_BEFORE_NL, time_ptr,
+ LEN_AND_LIT("Mupip journal process"), REG_LEN_STR(gv_cur_region));
+ }
+ }
+ REVERT;
+ /* -------------------------- nullify pointers ------------------------------------- */
+ sys$dassgn(gds_info->fab->fab$l_stv);
+ gv_cur_region->open = FALSE;
+ cs_addrs->hdr = NULL;
+ cs_addrs->nl = NULL;
+ REMOVE_CSA_FROM_CSADDRSLIST(cs_addrs); /* remove "cs_addrs" from list of open regions (cs_addrs_list) */
+ cs_addrs->db_addrs[0] = NULL;
+ cs_addrs->lock_addrs[0] = NULL;
+}
diff --git a/sr_vvms/gdsfheadsp.h b/sr_vvms/gdsfheadsp.h
new file mode 100644
index 0000000..3eafeb3
--- /dev/null
+++ b/sr_vvms/gdsfheadsp.h
@@ -0,0 +1,22 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2005 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef __GDSFHEADSP_H__
+#define __GDSFHEADSP_H__
+
+int4 dsk_write(gd_region *r, block_id blk, cache_rec_ptr_t cr,
+ void (*ast_rtn)(), int4 ast_param, io_status_block_disk *iosb);
+int4 dsk_write_nocache(gd_region *r, block_id blk, sm_uc_ptr_t buff, enum db_ver ondsk_blkver,
+ void (*ast_rtn)(), int4 ast_param, io_status_block_disk *iosb);
+void wcs_clean_dbsync_ast(sgmnt_addrs *csa);
+void wcs_clean_dbsync_timer_ast(sgmnt_addrs *csa);
+
+#endif
diff --git a/sr_vvms/gdsfilext.c b/sr_vvms/gdsfilext.c
new file mode 100644
index 0000000..4b23161
--- /dev/null
+++ b/sr_vvms/gdsfilext.c
@@ -0,0 +1,387 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include <iodef.h>
+#include <lckdef.h>
+#include <psldef.h>
+#include <dvidef.h>
+#include <rms.h>
+#include <ssdef.h>
+#include <efndef.h>
+
+#include "ast.h"
+#include "buddy_list.h"
+#include "gdsroot.h"
+#include "gdskill.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbml.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "gdscc.h"
+#include "filestruct.h"
+#include "jnl.h"
+#include "iosp.h"
+#include "hashtab_int4.h" /* needed for tp.h */
+#include "tp.h"
+#include "vmsdtype.h"
+#include "locks.h"
+#include "send_msg.h"
+#include "bit_set.h"
+#include "gt_timer.h"
+#include "dbfilop.h"
+#include "disk_block_available.h"
+#include "gtmmsg.h"
+#include "gdsfilext.h"
+#include "bm_getfree.h"
+#include "gdsblk.h" /* needed for gds_blk_downgrade.h */
+#include "gds_blk_downgrade.h" /* for IS_GDS_BLK_DOWNGRADE_NEEDED macro */
+#include "gtmimagename.h"
+
+GBLREF sgmnt_addrs *cs_addrs;
+GBLREF sgmnt_data_ptr_t cs_data;
+GBLREF unsigned char cw_set_depth;
+GBLREF uint4 dollar_tlevel;
+GBLREF gd_region *gv_cur_region;
+GBLREF boolean_t mu_reorg_process;
+GBLREF inctn_opcode_t inctn_opcode;
+GBLREF sgm_info *sgm_info_ptr;
+GBLREF unsigned int t_tries;
+GBLREF jnl_gbls_t jgbl;
+GBLREF inctn_detail_t inctn_detail; /* holds detail to fill in to inctn jnl record */
+GBLREF boolean_t gtm_dbfilext_syslog_disable; /* control whether db file extension message is logged or not */
+
+error_def(ERR_DBFILERR);
+error_def(ERR_DBFILEXT);
+error_def(ERR_DBOPNERR);
+error_def(ERR_DSKSPACEFLOW);
+error_def(ERR_ERRCALL);
+error_def(ERR_GBLOFLOW);
+error_def(ERR_JNLFILOPN);
+error_def(ERR_JNLFLUSH);
+error_def(ERR_MUSTANDALONE);
+error_def(ERR_TEXT);
+error_def(ERR_TOTALBLKMAX);
+
+#define ERROR_CLEANUP \
+ sys$close(&fcb); \
+ if (FALSE == was_crit) \
+ rel_crit(gv_cur_region);
+
+uint4 gdsfilext(uint4 blocks, uint4 filesize)
+{
+ bool was_crit;
+ char *buff;
+ unsigned char *mastermap[2], *retadr[2];
+ short iosb[4];
+ uint4 alloc_blocks, avail_blocks, new_bit_maps, blocks_needed, block_factor,
+ bplmap, jnl_status, map, new_blocks, new_total,
+ save_inctn_opcode, save_stv, status;
+ struct FAB fcb;
+ struct RAB rab;
+ file_control *fc;
+ vms_gds_info *gds_info;
+ trans_num curr_tn;
+ int4 prev_extend_blks_to_upgrd;
+ jnl_private_control *jpc;
+ jnl_buffer_ptr_t jbp;
+
+ /* Both blocks and total blocks are unsigned ints so make sure we aren't asking for huge numbers that will
+ overflow and end up doing silly things.
+ */
+ assert(blocks <= (MAXTOTALBLKS(cs_data) - cs_data->trans_hist.total_blks));
+
+ if (0 == blocks)
+ return (NO_FREE_SPACE); /* should this be changed to show extension not enabled ? */
+ gds_info = gv_cur_region->dyn.addr->file_cntl->file_info;
+ assert(cs_data == cs_addrs->hdr); /* because following line used to check cs_addrs->hdr (instead of cs_data) */
+ if (dba_mm == cs_data->acc_meth)
+ { /* mm only works MUPIP standalone, but calling this keeps the logic in one place */
+ status = gtm_enqw(EFN$C_ENF, LCK$K_EXMODE, &gds_info->file_cntl_lsb,
+ LCK$M_CONVERT | LCK$M_NOQUEUE | LCK$M_NODLCKWT,
+ NULL, 0, NULL, 0, NULL, PSL$C_USER, 0);
+ if (SS$_NORMAL == status)
+ status = gds_info->file_cntl_lsb.cond;
+ if (SS$_NORMAL != status)
+ {
+ gtm_putmsg(VARLSTCNT(5) ERR_MUSTANDALONE, 2, FAB_LEN_STR(&fcb), status);
+ return (NO_FREE_SPACE); /* should this be changed to show extention not enabled ? */
+ }
+ }
+ was_crit = cs_addrs->now_crit;
+ /* If we are coming from mupip_extend (which gets crit itself) we better have waited for any unfreezes to occur.
+ * If we are coming from online rollback (when that feature is available), we will come in holding crit and in
+ * the final retry. In that case too, we expect to have waited for unfreezes to occur in the caller itself.
+ * Therefore if we are coming in holding crit from MUPIP, we expect the db to be unfrozen so no need to wait for
+ * freeze.
+ * If we are coming from GT.M and final retry (in which case we come in holding crit) we expect to have waited
+ * for any unfreezes (by invoking tp_crit_all_regions) to occur (TP or non-TP) before coming into this
+ * function. However, there is one exception. In the final retry, if tp_crit_all_regions notices that
+ * at least one of the participating regions did ONLY READs, it will not wait for any freeze on THAT region
+ * to complete before grabbing crit. Later, in the final retry, if THAT region did an update which caused
+ * op_tcommit to invoke bm_getfree->gdsfilext, then we would have come here with a frozen region on which
+ * we hold crit.
+ */
+ assert(!was_crit || !cs_data->freeze || (dollar_tlevel && (CDB_STAGNATE <= t_tries)));
+ /*
+ * If we are in the final retry and already hold crit, it is possible that csa->nl->wc_blocked is also set to
+ * TRUE (by a concurrent process in phase2 which encountered an error in the midst of commit and secshr_db_clnup
+ * finished the job for it). In this case we do NOT want to invoke wcs_recover as that will update the "bt"
+ * transaction numbers without correspondingly updating the history transaction numbers (effectively causing
+ * a cdb_sc_blkmod type of restart). Therefore do NOT call grab_crit (which unconditionally invokes wcs_recover)
+ * if we already hold crit.
+ */
+ if (!was_crit)
+ {
+ for ( ; ; )
+ {
+ grab_crit(gv_cur_region);
+ if (!cs_data->freeze)
+ break;
+ rel_crit(gv_cur_region);
+ while (cs_data->freeze)
+ hiber_start(1000);
+ }
+ } else if (cs_data->freeze && dollar_tlevel)
+ { /* We don't want to continue with file extension as explained above. Hence return with an error code which
+ * op_tcommit will recognize (as a cdb_sc_needcrit type of restart) and restart accordingly.
+ */
+ assert(CDB_STAGNATE <= t_tries);
+ return (uint4)(FINAL_RETRY_FREEZE_PROG);
+ }
+ assert(cs_addrs->ti->total_blks == cs_data->trans_hist.total_blks);
+ if (cs_data->trans_hist.total_blks != filesize)
+ {
+ if (FALSE == was_crit)
+ rel_crit(gv_cur_region);
+ return (SS$_NORMAL);
+ }
+ if (IS_GTM_IMAGE && (2 * (dollar_tlevel ? sgm_info_ptr->cw_set_depth : cw_set_depth) < cs_addrs->ti->free_blocks))
+ {
+ if (FALSE == was_crit)
+ {
+ rel_crit(gv_cur_region);
+ return (EXTEND_SUSPECT);
+ }
+ /* If free_blocks counter is not ok, then correct it. Do the check again. If still fails, then GTMASSERT. */
+ if (is_free_blks_ctr_ok() ||
+ (2 * (dollar_tlevel ? sgm_info_ptr->cw_set_depth : cw_set_depth) < cs_addrs->ti->free_blocks))
+ GTMASSERT; /* held crit through bm_getfree into gdsfilext and still didn't get it right */
+ }
+ CHECK_TN(cs_addrs, cs_data, cs_data->trans_hist.curr_tn); /* can issue rts_error TNTOOLARGE */
+ bplmap = cs_data->bplmap;
+ fcb = cc$rms_fab;
+ fcb.fab$b_shr = gds_info->fab->fab$b_shr;
+ fcb.fab$l_fna = &(gv_cur_region->dyn.addr->fname);
+ fcb.fab$b_fns = gv_cur_region->dyn.addr->fname_len;
+ fcb.fab$b_fac = FAB$M_BIO | FAB$M_GET | FAB$M_PUT;
+ fcb.fab$l_fop = FAB$M_CBT;
+ if (RMS$_NORMAL == (status = sys$open(&fcb)))
+ {
+ block_factor = cs_data->blk_size / DISK_BLOCK_SIZE;
+ if (SS$_NORMAL == (status = disk_block_available(gds_info->fab->fab$l_stv, &avail_blocks)))
+ {
+ avail_blocks /= block_factor;
+ if ((blocks * EXTEND_WARNING_FACTOR) > avail_blocks)
+ {
+ if (blocks > avail_blocks)
+ {
+ send_msg(VARLSTCNT(11) ERR_GBLOFLOW, 0, ERR_DBFILERR, 2, FAB_LEN_STR(&fcb),
+ ERR_ERRCALL, 3, CALLFROM);
+ ERROR_CLEANUP;
+ return (NO_FREE_SPACE);
+ }
+ send_msg(VARLSTCNT(10) ERR_DSKSPACEFLOW, 3, FAB_LEN_STR(&fcb), avail_blocks * block_factor,
+ ERR_ERRCALL, 3, CALLFROM);
+ }
+ } else
+ {
+ send_msg(VARLSTCNT(13) ERR_GBLOFLOW, 0, ERR_DBFILERR, 2, FAB_LEN_STR(&fcb), status, 0,
+ ERR_ERRCALL, 3, CALLFROM);
+ ERROR_CLEANUP;
+ return (NO_FREE_SPACE);
+ }
+ } else
+ {
+ if (FALSE == was_crit)
+ rel_crit(gv_cur_region);
+ send_msg(VARLSTCNT(15) ERR_GBLOFLOW, 0, ERR_DBOPNERR, 2, FAB_LEN_STR(&fcb), status, 0, fcb.fab$l_stv, 0,
+ ERR_ERRCALL, 3, CALLFROM);
+ return (NO_FREE_SPACE);
+ }
+ /* new total of non-bitmap blocks will be number of current, non-bitmap blocks, plus new blocks desired
+ * There are (bplmap - 1) non-bitmap blocks per bitmap, so add (bplmap - 2) to number of non-bitmap blocks
+ * and divide by (bplmap - 1) to get total number of bitmaps for expanded database. (must round up in this
+ * manner as every non-bitmap block must have an associated bitmap)
+ * Current number of bitmaps is (total number of current blocks + bplmap - 1) / bplmap.
+ * Subtract current number of bitmaps from number needed for expanded database to get number of new bitmaps needed.
+ */
+ new_bit_maps = DIVIDE_ROUND_UP(cs_data->trans_hist.total_blks
+ - DIVIDE_ROUND_UP(cs_data->trans_hist.total_blks, bplmap) + blocks, bplmap - 1)
+ - DIVIDE_ROUND_UP(cs_data->trans_hist.total_blks, bplmap);
+ new_blocks = blocks + new_bit_maps;
+ assert(0 < (int)new_blocks);
+ new_total = cs_data->trans_hist.total_blks + new_blocks;
+ if (new_total > MAXTOTALBLKS(cs_data))
+ {
+ send_msg(VARLSTCNT(7) ERR_TOTALBLKMAX, 0, ERR_ERRCALL, 3, CALLFROM);
+ ERROR_CLEANUP;
+ return (NO_FREE_SPACE);
+ }
+ if (JNL_ENABLED(cs_data))
+ {
+ if (!jgbl.dont_reset_gbl_jrec_time)
+ SET_GBL_JREC_TIME; /* needed before jnl_ensure_open as that can write jnl records */
+ jpc = cs_addrs->jnl;
+ jbp = jpc->jnl_buff;
+ /* Before writing to jnlfile, adjust jgbl.gbl_jrec_time if needed to maintain time order
+ * of jnl records. This needs to be done BEFORE the jnl_ensure_open as that could write
+ * journal records (if it decides to switch to a new journal file).
+ */
+ ADJUST_GBL_JREC_TIME(jgbl, jbp);
+ jnl_status = jnl_ensure_open();
+ if (jnl_status)
+ {
+ send_msg(VARLSTCNT(11) jnl_status, 4, JNL_LEN_STR(cs_data), DB_LEN_STR(gv_cur_region),
+ ERR_ERRCALL, 3, CALLFROM);
+ ERROR_CLEANUP;
+ return (NO_FREE_SPACE); /* should have better return status */
+ }
+ }
+ buff = malloc(cs_data->blk_size);
+ memset(buff, 0, cs_data->blk_size);
+ rab = cc$rms_rab;
+ rab.rab$l_fab = &fcb;
+ rab.rab$l_rbf = buff;
+ rab.rab$w_rsz = cs_data->blk_size;
+ rab.rab$l_rop |= RAB$M_EOF;
+ if (RMS$_NORMAL != (status = sys$connect(&rab)))
+ {
+ save_stv = fcb.fab$l_stv;
+ free(buff);
+ send_msg(VARLSTCNT(15) ERR_GBLOFLOW, 0, ERR_DBFILERR, 2, FAB_LEN_STR(&fcb), status, 0, save_stv, 0,
+ ERR_ERRCALL, 3, CALLFROM);
+ ERROR_CLEANUP;
+ return (NO_FREE_SPACE);
+ }
+ /* get last block needed, position write to be (block_size/512-1) blocks before so that will end at desired block */
+ rab.rab$l_bkt = cs_data->start_vbn + (block_factor * new_total) - block_factor;
+ status = sys$write(&rab);
+ free(buff);
+ if (RMS$_NORMAL != status)
+ {
+ save_stv = fcb.fab$l_stv;
+ send_msg(VARLSTCNT(15) ERR_GBLOFLOW, 0, ERR_DBFILERR, 2, FAB_LEN_STR(&fcb), status, 0, save_stv, 0,
+ ERR_ERRCALL, 3, CALLFROM);
+ ERROR_CLEANUP;
+ return (NO_FREE_SPACE);
+ }
+
+ if (RMS$_NORMAL != (status = sys$close(&fcb)))
+ {
+ if (FALSE == was_crit)
+ rel_crit(gv_cur_region);
+ send_msg(VARLSTCNT(15) ERR_GBLOFLOW, 0, ERR_DBFILERR, 2, FAB_LEN_STR(&fcb), status, 0, fcb.fab$l_stv, 0,
+ ERR_ERRCALL, 3, CALLFROM);
+ return (NO_FREE_SPACE);
+ }
+ DEBUG_ONLY(prev_extend_blks_to_upgrd = cs_data->blks_to_upgrd;)
+ /* inctn_detail.blks_to_upgrd_delta holds the increase in "csd->blks_to_upgrd" due to the file extension */
+ inctn_detail.blks2upgrd_struct.blks_to_upgrd_delta
+ = (IS_GDS_BLK_DOWNGRADE_NEEDED(cs_data->desired_db_format) ? new_bit_maps : 0);
+ if (JNL_ENABLED(cs_data))
+ {
+ save_inctn_opcode = inctn_opcode;
+ if (mu_reorg_process)
+ inctn_opcode = inctn_gdsfilext_mu_reorg;
+ else
+ inctn_opcode = inctn_gdsfilext_gtm;
+ if (0 == jpc->pini_addr)
+ jnl_put_jrt_pini(cs_addrs);
+ jnl_write_inctn_rec(cs_addrs);
+ inctn_opcode = save_inctn_opcode;
+ /* Harden INCTN to disk before updating/flushing database. This will ensure that any positive adjustment to the
+ * blks_to_upgrd counter (stored in the inctn record) is seen by recovery before a V4 format bitmap block is.
+ */
+ jnl_status = jnl_flush(gv_cur_region);
+ if (SS_NORMAL != jnl_status)
+ {
+ send_msg(VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(cs_data),
+ ERR_TEXT, 2, RTS_ERROR_TEXT("Error with journal flush during gdsfilext"),
+ jnl_status);
+ assert(NOJNL == jpc->channel); /* jnl file lost has been triggered */
+ /* In this routine, all code that follows from here on does not assume anything about the
+ * journaling characteristics of this database so it is safe to continue execution even though
+ * journaling got closed in the middle. Let the caller deal with this situation.
+ */
+ }
+ }
+ if (new_bit_maps)
+ {
+ for (map = ROUND_UP(cs_data->trans_hist.total_blks, bplmap); map < new_total; map += bplmap)
+ {
+ DEBUG_ONLY(new_bit_maps--;)
+ if (SS$_NORMAL != (status = bml_init(map)))
+ {
+ if (FALSE == was_crit)
+ rel_crit(gv_cur_region);
+ send_msg(VARLSTCNT(13) ERR_GBLOFLOW, 0, ERR_DBFILERR, 2, FAB_LEN_STR(&fcb), status, 0,
+ ERR_ERRCALL, 3, CALLFROM);
+ return (NO_FREE_SPACE);
+ }
+ }
+ assert(0 == new_bit_maps);
+ }
+ assert(cs_data->blks_to_upgrd == (inctn_detail.blks2upgrd_struct.blks_to_upgrd_delta + prev_extend_blks_to_upgrd));
+ assert(0 < (int)blocks);
+ assert(0 < (int)(cs_data->trans_hist.free_blocks + blocks));
+ cs_data->trans_hist.free_blocks += blocks;
+ blocks = cs_data->trans_hist.total_blks;
+ cs_data->trans_hist.total_blks = new_total;
+ if (blocks / bplmap * bplmap != blocks)
+ {
+ bit_set( blocks / bplmap, MM_ADDR(cs_data)); /* Mark old last local map as having space */
+ if ((int4)blocks > cs_addrs->nl->highest_lbm_blk_changed)
+ cs_addrs->nl->highest_lbm_blk_changed = blocks;
+ }
+ cs_addrs->ti->mm_tn++;
+ curr_tn = cs_addrs->ti->curr_tn;
+ assert(cs_addrs->ti->early_tn == cs_addrs->ti->curr_tn);
+ /* do not increment transaction number for forward recovery */
+ if (!jgbl.forw_phase_recovery || JNL_ENABLED(cs_data))
+ {
+ cs_data->trans_hist.early_tn = cs_data->trans_hist.curr_tn + 1;
+ INCREMENT_CURR_TN(cs_data);
+ }
+ fc = gv_cur_region->dyn.addr->file_cntl;
+ fc->file_type = cs_addrs->hdr->acc_meth;
+ fc->op = FC_WRITE;
+ fc->op_buff = (sm_uc_ptr_t)cs_addrs->hdr;
+ fc->op_len = SIZEOF_FILE_HDR(cs_data);
+ fc->op_pos = 1; /* write from the start of the file-header */
+ /* Note: (for bg) if machine crashes after update is done, BT queues could malformed from partial write. */
+ status = dbfilop(fc);
+ if (FALSE == was_crit)
+ rel_crit(gv_cur_region);
+ if (SS$_NORMAL != status)
+ {
+ send_msg(VARLSTCNT(13) ERR_GBLOFLOW, 0, ERR_DBFILERR, 2, FAB_LEN_STR(&fcb), status, 0, ERR_ERRCALL, 3, CALLFROM);
+ return (NO_FREE_SPACE);
+ }
+ INCR_GVSTATS_COUNTER(cs_addrs, cs_addrs->nl, n_db_extends, 1);
+ if (!gtm_dbfilext_syslog_disable)
+ send_msg(VARLSTCNT(7) ERR_DBFILEXT, 5, FAB_LEN_STR(&fcb), blocks, new_total, &curr_tn);
+ return (SS$_NORMAL);
+}
diff --git a/sr_vvms/gen_gtm_threadgbl_deftypes.com b/sr_vvms/gen_gtm_threadgbl_deftypes.com
new file mode 100644
index 0000000..16daae0
--- /dev/null
+++ b/sr_vvms/gen_gtm_threadgbl_deftypes.com
@@ -0,0 +1,159 @@
+$!#################################################################
+$!# #
+$!# Copyright 2010, 2012 Fidelity Information Services, Inc #
+$!# #
+$!# This source code contains the intellectual property #
+$!# of its copyright holder(s), and is made available #
+$!# under a license. If you do not know the terms of #
+$!# the license, please stop and do not read further. #
+$!# #
+$!#################################################################
+$!
+$ set noon
+$ savedir = f$environment("DEFAULT")
+$!
+$! Generate gtm_threadgbl_deftypes.h from gtm_threadgbl_deftypes.c. The result is a list of
+$! #defines for the (real) types of the neutral-typed vars in the gtm_threadgbl structure. The
+$! vars are neutral so not all types have to be defined in all modules. This mechanism allows
+$! us to type only the vars used in the module.
+$!
+$! First setup the compile options and commands we need
+$!
+$ common_options := /standard=vaxc/share/assume=nowrit/float=g_float/inc=(here:,gtm$src:)/warn=disable=(signedknown,signedmember,questcompare,questcompare1)
+$ ccdbg :== cc'common_options'/define=(debug,nolicense)/debug/nooptimize
+$ ccpro :== cc'common_options'
+$!
+$! We need to build this table twice - once for pro and once for dbg because the elements in the
+$! table could be different sizes. So setup the necessary #ifdefs so the proper set is selected
+$! when the module is built. One complication is that gtm_malloc_src.h gets built both as PRO and
+$! DBG in the same module for a pro build. The DEBUG flag is overridden and the PRO build is
+$! selected is PRO_BUILD is defined (set by gtm_malloc_dbg.c).
+$!
+$ set def gtm$obj
+$ if $severity .ne. 1
+$ then
+$ write sys$output "gen_gtm_threadgbl_deftypes.com-E-: Unable to switch to gtm$obj - ERROR"
+$ set def 'savedir'
+$ exit 2
+$ endif
+$ if f$search("gtm_threadgbl_deftypes.h") .nes. "" then delete/nolog gtm_threadgbl_deftypes.h.*
+$ if f$search("gtm_threadgbl_deftypes.h") .nes. ""
+$ then
+$ write sys$output "gen_gtm_threadgbl_deftypes.com-E-: Unable to delete old gtm$obj:gtm_threadgbl_deftypes.h - ERROR"
+$ set def 'savedir'
+$ exit 2
+$ endif
+$!
+$! Create gtm_threadgbl_deftypes.h file - create in gtm$obj first so we don't replace the gtm$src version
+$! until/unless we know it is replaceable.
+$!
+$ year = f$extract(7, 4, f$time())
+$ open/share/write ofile gtm_threadgbl_deftypes.h
+$ write ofile "/******************************************************************"
+$ write ofile " * *"
+$ write ofile " * Copyright 2010, ''year' Fidelity Information Services, Inc *"
+$ write ofile " * *"
+$ write ofile " * This source code contains the intellectual property *"
+$ write ofile " * of its copyright holder(s), and is made available *"
+$ write ofile " * under a license. If you do not know the terms of *"
+$ write ofile " * the license, please stop and do not read further. *"
+$ write ofile " * *"
+$ write ofile " ******************************************************************/"
+$ write ofile " "
+$ write ofile "#ifndef GTM_THREADGBL_DEFTYPES_INCLUDED"
+$ write ofile "#define GTM_THREADGBL_DEFTYPES_INCLUDED"
+$ gtmvrt = f$trnlmn("gtm$vrt")
+$ gtmtools = f$extract(0,f$length(gtmvrt)-1,gtmvrt)
+$ write ofile "/* Generated by ''gtmtools'TOOLS]gen_gtm_threadgbl_deftypes.com */"
+$!
+$! Output selection criteria for PRO build
+$!
+$ write ofile " "
+$ write ofile "#if !defined(DEBUG) || defined(PRO_BUILD)"
+$!
+$! Now do pro build/run
+$!
+$ ccpro gtm$src:gtm_threadgbl_deftypes.c
+$ if 1 .ne. $severity
+$ then
+$ write sys$output "gen_gtm_threadgbl_deftypes.com-E-: pro build of gtm$obj:gtm_threadgbl_deftypes failed - ERROR"
+$ set def 'savedir'
+$ exit 2
+$ endif
+$ link/map=gtm_threadgbl_deftypes.map/full/exe=gtm_threadgbl_deftypes gtm_threadgbl_deftypes.obj
+$ if 1 .ne. $severity
+$ then
+$ write sys$output "gen_gtm_threadgbl_deftypes.com-E-: pro build link of gtm$obj/gtm_threadgbl_deftypes failed. See gtm$obj:gtm_threadgbl_deftypes.map - ERROR"
+$ set def 'savedir'
+$ exit 2
+$ endif
+$ define/user/nolog sys$output ofile
+$ run gtm_threadgbl_deftypes
+$ if 1 .ne. $severity
+$ then
+$ write sys$output "gen_gtm_threadgbl_deftypes.com-E-: generating pro output failed - ERROR"
+$ set def 'savedir'
+$ exit 2
+$ endif
+$ write ofile "#else"
+$!
+$! Do debug build
+$!
+$ ccdbg gtm$src:gtm_threadgbl_deftypes.c
+$ if 1 .ne. $severity
+$ then
+$ write sys$output "gen_gtm_threadgbl_deftypes.com-E-: dbg build of gtm$obj:gtm_threadgbl_deftypes failed - ERROR"
+$ set def 'savedir'
+$ exit 2
+$ endif
+$ link/map=gtm_threadgbl_deftypes.map/full/exe=gtm_threadgbl_deftypes gtm_threadgbl_deftypes.obj
+$ if 1 .ne. $severity
+$ then
+$ write "gen_gtm_threadgbl_deftypes.com-E-: dbg build link of gtm$obj/gtm_threadgbl_deftypes failed. See gtm$obj:gtm_threadgbl_deftypes.map - ERROR"
+$ set def 'savedir'
+$ exit 2
+$ endif
+$ define/user/nolog sys$output ofile
+$ run gtm_threadgbl_deftypes
+$ if 1 .ne. $severity
+$ then
+$ write sys$output "gen_gtm_threadgbl_deftypes.com-E-: generating dbg output failed - ERROR"
+$ set def 'savedir'
+$ exit 2
+$ endif
+$ write ofile "#endif"
+$ write ofile "#endif"
+$ close ofile
+$!
+$! Make sure it is there
+$!
+$ if f$search("gtm_threadgbl_deftypes.h") .eqs. ""
+$ then
+$ write sys$output "gen_gtm_threadgbl_deftypes.com-E-: Unable to generate new gtm$obj:gtm_threadgbl_deftypes.h - ERROR"
+$ set def 'savedir'
+$ exit 2
+$ endif
+$!
+$! See if it is different from the one in gtm$src (or if the gtm$src one is not there). Only move it there if
+$! needed to prevent unneeded re-compiles of the world.
+$!
+$ keepold = 0
+$ if f$search("gtm$src:gtm_threadgbl_deftypes.h") .nes. ""
+$ then
+$ diff/output=gtm_threadgbl_deftypes.diff gtm$src:gtm_threadgbl_deftypes.h gtm$obj:gtm_threadgbl_deftypes.h
+$ if $severity .eq. 1 then keepold = 1
+$ endif
+$ if keepold .eq. 0 then copy /nolog gtm_threadgbl_deftypes.h gtm$src:
+$ if 1 .ne. $severity
+$ then
+$ write sys$output "gen_gtm_threadgbl_deftypes.com-E-: Unable to copy/replace gtm$src:gtm_threadgbl_deftypes.h - ERROR"
+$ set def 'savedir'
+$ exit 2
+$ endif
+$!
+$ if f$search("gtm_threadgbl_deftypes.exe") .nes. "" then delete/nolog gtm_threadgbl_deftypes.exe.*
+$ if f$search("gtm_threadgbl_deftypes.obj") .nes. "" then delete/nolog gtm_threadgbl_deftypes.obj.*
+$ if f$search("gtm_threadgbl_deftypes.map") .nes. "" then delete/nolog gtm_threadgbl_deftypes.map.*
+$ if f$search("gtm_threadgbl_deftypes.diff") .nes. "" then delete/nolog gtm_threadgbl_deftypes.diff.*
+$ set def 'savedir'
+$ exit 1
diff --git a/sr_vvms/generic_exit_handler.c b/sr_vvms/generic_exit_handler.c
new file mode 100644
index 0000000..f3e2255
--- /dev/null
+++ b/sr_vvms/generic_exit_handler.c
@@ -0,0 +1,218 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <ssdef.h>
+#include "gtm_inet.h"
+#include <psldef.h>
+#include <descrip.h>
+#include <signal.h> /* for VSIG_ATOMIC_T type */
+
+#include "gtm_stdio.h" /* for FILE structure etc. */
+#include "gtm_time.h"
+
+#include "ast.h"
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "error.h"
+#include "iotimer.h"
+#include "jnl.h"
+#include "locklits.h"
+#include "gtmrecv.h" /* for recvpool etc. */
+#include "io.h"
+#include "iosp.h"
+#include "sleep_cnt.h"
+#include "repl_msg.h"
+#include "gtmsource.h"
+#include "repl_sem.h"
+#include "repl_shm.h"
+#include "desblk.h"
+#include "gtmimagename.h"
+#include "util.h"
+#include "op.h"
+#include "repl_log.h"
+#include "generic_exit_handler.h"
+#include "gv_rundown.h"
+#include "have_crit.h"
+#include "print_exit_stats.h"
+#include "setzdir.h"
+#include "buddy_list.h"
+#include "hashtab_mname.h" /* needed for muprec.h */
+#include "hashtab_int4.h" /* needed for muprec.h */
+#include "hashtab_int8.h" /* needed for muprec.h */
+#include "muprec.h"
+#include "gtmmsg.h"
+#include "secshr_db_clnup.h"
+#include "repl_shutdcode.h"
+
+GBLREF void (*call_on_signal)();
+GBLREF uint4 dollar_tlevel;
+GBLREF int4 exi_condition;
+GBLREF desblk exi_blk;
+GBLREF int gtmsource_srv_count, gtmrecv_srv_count;
+GBLREF FILE *gtmsource_log_fp, *gtmrecv_log_fp;
+GBLREF boolean_t is_src_server, is_rcvr_server, is_tracing_on, is_updproc, is_updhelper;
+GBLREF jnlpool_addrs jnlpool;
+GBLREF jnlpool_ctl_ptr_t jnlpool_ctl;
+GBLREF boolean_t pool_init;
+GBLREF uint4 process_id;
+GBLREF recvpool_addrs recvpool;
+GBLREF FILE *updproc_log_fp;
+GBLREF mval original_cwd;
+GBLREF jnl_gbls_t jgbl;
+GBLREF upd_helper_entry_ptr_t helper_entry;
+GBLREF volatile boolean_t in_wcs_recover; /* TRUE if in "wcs_recover" */
+GBLREF boolean_t exit_handler_active;
+GBLREF int process_exiting;
+
+error_def(ERR_ACK);
+error_def(ERR_CRITRESET);
+error_def(ERR_FORCEDHALT);
+error_def(ERR_MUJNLSTAT);
+error_def(ERR_UNKNOWNFOREX);
+
+void generic_exit_handler(void)
+{
+ void (*signal_routine)();
+ boolean_t is_mupip, is_gtm;
+ int4 lcnt;
+ gd_addr *addr_ptr;
+ gd_region *reg, *r_top;
+ sgmnt_addrs *csa;
+ static int invoke_cnt = 0; /* how many times generic_exit_handler was invoked in the lifetime of this process */
+
+ is_gtm = IS_GTM_IMAGE;
+ is_mupip = IS_MUPIP_IMAGE;
+ exit_handler_active = TRUE;
+ sys$setast(ENABLE); /* safer and doesn't hurt much */
+ if (is_tracing_on)
+ turn_tracing_off(NULL);
+ /* We expect generic_exit_handler to be invoked at most twice. Once by MUPIP STOP at which time we might have decided
+ * to defer exiting (because of holding crit etc.) but after all those resources which prevented us from exiting have
+ * been released, we should reinvoke generic_exit_handler once more and that invocation SHOULD EXIT. Assert this.
+ */
+ assert(invoke_cnt < 2);
+ DEBUG_ONLY(invoke_cnt++;)
+ /* We can defer exit-handling if it was a forced-halt and we are in an AST or have crit in any region.
+ * If we are in an AST when a fatal exception occurs we can neither defer exiting nor do normal exit-handling,
+ * so we return immediately with the hope that the privileged exit-handler in GTMSECSHR,
+ * secshr_db_clnup(ABNORMAL_TERMINATION) will do the necessary cleanup.
+ * Note that even if we hold crit in any region when a non-deferrable exception occurs, we can still go ahead with
+ * normal exit-handling chores. secshr_db_clnup(NORMAL_TERMINATION) (invoked below) will cleanup the crits for us.
+ */
+ if (ERR_FORCEDHALT == exi_condition || 0 == exi_condition)
+ {
+ if (lib$ast_in_prog()) /* The rest of this assumes that it may use AST's */
+ {
+ assert(!process_exiting);
+ EXIT_HANDLER(&exi_blk); /* reestablish the exit handler */
+ sys$forcex(&process_id); /* make the forcex come back as an AST */
+ ESTABLISH(exi_ch); /* set a condition handler to unwind exit handler levels */
+ rts_error_csa(CSA_ARG(NULL) ERR_ACK); /* and signal success */
+ }
+ assert(!lib$ast_in_prog());
+ /* There are at least three cases where we definitely want to defer exiting as abnormally terminating could
+ * potentially cause database damage. They are
+ * a) Commit phase (beginning from when early_tn is curr_tn + 1 to when they become equal)
+ * b) Cache recovery phase (if we are in "wcs_recover" recovering the cache). In that case too
+ * early_tn is set to curr_tn + 1 (just like (a)) so no special processing is needed.
+ * c) When the intrpt_ok_state is flagged
+ */
+ if ((0 != have_crit(CRIT_HAVE_ANY_REG | CRIT_IN_COMMIT)) || (INTRPT_OK_TO_INTERRUPT != intrpt_ok_state))
+ {
+ assert(!process_exiting);
+ EXIT_HANDLER(&exi_blk);
+ ESTABLISH(exi_ch);
+ rts_error_csa(CSA_ARG(NULL) exi_condition ? exi_condition : ERR_FORCEDHALT);
+ }
+ assert(!in_wcs_recover); /* case (b) above should have been handled by have_crit(CRIT_IN_COMMIT) itself */
+ } else if (lib$ast_in_prog())
+ rts_error_csa(CSA_ARG(NULL) exi_condition); /* this shouldn't return */
+ process_exiting = TRUE;
+ sys$cantim(0,0); /* cancel all outstanding timers. prevents unwelcome surprises...DO this only after AFTER we decide NOT
+ * to defer exit-handling as otherwise we might cause a deadlock due to cancelling a timer that the
+ * mainline code holding CRIT is waiting for */
+ SET_FORCED_EXIT_STATE_ALREADY_EXITING;
+ ESTABLISH(lastchance1);
+ /* call_on_signal is currently used only by certain mupip commands, but it will be NULL if unused */
+ if ((SS$_NORMAL != exi_condition) && call_on_signal && (!(IS_GTM_ERROR(exi_condition)) || ERR_FORCEDHALT == exi_condition))
+ {
+ assert(!lib$ast_in_prog());
+ signal_routine = call_on_signal;
+ call_on_signal = NULL;
+ (*signal_routine)();
+ }
+ finish_active_jnl_qio();
+ if (jgbl.mupip_journal)
+ mur_close_files(); /* Will it increase gtm image size pulling mur*.c ??? */
+ DETACH_FROM_JNLPOOL(pool_init, jnlpool, jnlpool_ctl);
+ secshr_db_clnup(NORMAL_TERMINATION);
+ if (dollar_tlevel)
+ OP_TROLLBACK(0);
+ if (is_gtm) /* do lock rundown only for GT.M (though it probably is harmless if invoked by the others) */
+ {
+ op_lkinit(); /* seems to be GT.CM client specific */
+ op_unlock();
+ op_zdeallocate(NO_M_TIMEOUT);
+ }
+ REVERT;
+ ESTABLISH(lastchance2);
+ gv_rundown();
+ REVERT;
+ ESTABLISH(lastchance3);
+ print_exit_stats();
+ io_rundown(NORMAL_RUNDOWN);
+ if (0 == exi_condition)
+ exi_condition = ERR_UNKNOWNFOREX;
+ if (is_mupip) /* do mupip-specific replication processing */
+ {
+ assert(!lib$ast_in_prog());
+ if (is_updhelper && NULL != helper_entry) /* haven't had a chance to cleanup, must be an abnormal exit */
+ {
+ helper_entry->helper_shutdown = ABNORMAL_SHUTDOWN;
+ helper_entry->helper_pid = 0; /* vacate my slot */
+ helper_entry = NULL;
+ }
+ if (recvpool.recvpool_ctl)
+ {
+ detach_shm(recvpool.shm_range);
+ signoff_from_gsec(recvpool.shm_lockid);
+ memset(&recvpool, 0, SIZEOF(recvpool));
+ }
+ if (is_src_server && sem_set_exists(SOURCE) && gtmsource_srv_count && (0 != rel_sem(SOURCE, SRC_SERV_COUNT_SEM)))
+ repl_log(gtmsource_log_fp, TRUE, TRUE, "Error releasing the source server count semaphore : %s\n",
+ REPL_SEM_ERROR);
+ if (is_rcvr_server && sem_set_exists(RECV) && gtmrecv_srv_count && (0 != rel_sem(RECV, RECV_SERV_COUNT_SEM)))
+ repl_log(gtmrecv_log_fp, TRUE, TRUE, "Error releasing the receiver server count semaphore : %s\n",
+ REPL_SEM_ERROR);
+ if (is_updproc && sem_set_exists(RECV) && (0 != rel_sem(RECV, UPD_PROC_COUNT_SEM)))
+ repl_log(updproc_log_fp, TRUE, TRUE, "Error releasing the update process count semaphore : %s\n",
+ REPL_SEM_ERROR);
+ /* log the exit of replication servers */
+ if (is_src_server)
+ repl_log(gtmsource_log_fp, TRUE, TRUE, "Source server exiting...\n");
+ else if (is_rcvr_server)
+ repl_log(gtmrecv_log_fp, TRUE, TRUE, "Receiver server exiting...\n");
+ else if (is_updproc)
+ repl_log(updproc_log_fp, TRUE, TRUE, "Update process exiting...\n");
+ else if (is_updhelper)
+ repl_log(updproc_log_fp, TRUE, TRUE, "Helper exiting...\n");
+ util_out_close();
+ }
+ if (is_gtm)
+ setzdir(&original_cwd, NULL); /* Restore the image startup cwd. This is done here 'cos VMS chdir() doesn't behave
+ * as documented. See comments in setzdir(). */
+}
diff --git a/sr_vvms/generic_exit_handler.h b/sr_vvms/generic_exit_handler.h
new file mode 100644
index 0000000..723c29d
--- /dev/null
+++ b/sr_vvms/generic_exit_handler.h
@@ -0,0 +1,18 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef GENERIC_EXIT_HANDLER_INCLUDED
+#define GENERIC_EXIT_HANDLER_INCLUDED
+
+void generic_exit_handler(void);
+
+
+#endif /* GENERIC_EXIT_HANDLER_INCLUDED */
diff --git a/sr_vvms/get_command_line.c b/sr_vvms/get_command_line.c
new file mode 100644
index 0000000..8e48dcb
--- /dev/null
+++ b/sr_vvms/get_command_line.c
@@ -0,0 +1,46 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include "stringpool.h"
+#include <descrip.h>
+#include "get_command_line.h"
+
+#define MAX_COMMAND_LINE_LENGTH 255
+
+GBLREF spdesc stringpool;
+
+void get_command_line(mval *v, boolean_t zcmd_line)
+{
+ struct dsc$descriptor_s cmd_desc;
+
+ /* zcmd_line is currently unused in VMS */
+ ENSURE_STP_FREE_SPACE(MAX_COMMAND_LINE_LENGTH);
+ v->mvtype = MV_STR;
+ cmd_desc.dsc$w_length = MAX_COMMAND_LINE_LENGTH;
+ cmd_desc.dsc$b_dtype = DSC$K_DTYPE_T;
+ cmd_desc.dsc$b_class = DSC$K_CLASS_S;
+ cmd_desc.dsc$a_pointer = stringpool.free;
+ /* initialize the 4-byte int v->str.len to 0 before calling lib$get_foreign() with &v->str.len as the function
+ * expects a pointer to a short (rather than an int) and hence will reset only the lower-order 2-bytes in v->str.len
+ */
+ v->str.len = 0;
+ if ((lib$get_foreign (&cmd_desc, 0, &v->str.len) & 1) == 0)
+ v->str.len = 0;
+ v->str.addr = stringpool.free;
+ stringpool.free += v->str.len;
+ assert(stringpool.free >= stringpool.base);
+ assert(stringpool.free < stringpool.top);
+ return;
+}
diff --git a/sr_vvms/get_full_path.c b/sr_vvms/get_full_path.c
new file mode 100644
index 0000000..3972e64
--- /dev/null
+++ b/sr_vvms/get_full_path.c
@@ -0,0 +1,70 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <errno.h>
+#include <rms.h>
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "jnl.h"
+#include <iodef.h>
+#include "gtmmsg.h"
+#include "gtm_file_stat.h"
+
+
+/* Gets expanded path of a file.
+ * NOTE: Since gtm_file_stat now expands a file name with full path, consider nixing this routine : Layek 5/10/2
+ * Output Parameter
+ * uint4 *status : error number
+ * Returns:
+ * TRUE: if file path is expanded
+ * FALSE: if file path cannot be expanded
+ */
+boolean_t get_full_path(char *name, unsigned int len, char *exp_file_name,
+ unsigned int *exp_name_len, int max_len, uint4 *status)
+{
+ struct FAB fab;
+ struct NAM nam;
+ char es_buffer[MAX_FN_LEN], name_buffer[MAX_FN_LEN];
+ char *src, *srctop, *dest, *destmax;
+ error_def(ERR_FILENAMETOOLONG);
+
+ nam = cc$rms_nam;
+ /* Note From Documentation :
+ * The nam$l_esa and nam$b_ess fields must be specified (nonzero) for wildcard character processing.
+ * nam$l_rsa required for wildcard character processing */
+ nam.nam$l_rsa = name_buffer; /* Resultant string area address: specifies name, type,
+ * and version of last file found */
+ nam.nam$b_rss = SIZEOF(name_buffer); /* Resultant String Area size. */
+ nam.nam$l_esa = es_buffer; /* Expanded String area address: specifies file name, type,
+ * and version of file. */
+ nam.nam$b_ess = SIZEOF(es_buffer); /* Size of Expanded String area */
+ nam.nam$b_nop = NAM$M_NOCONCEAL; /* indicates that when a concealed device logical name is present,
+ * the concealed device logical name is to be replaced by the
+ * actual physical device name in the expanded string. */
+ fab = cc$rms_fab;
+ fab.fab$l_nam = &nam;
+ fab.fab$l_fop = FAB$M_NAM;
+ fab.fab$l_fna = name; /* File specification string address. */
+ fab.fab$b_fns = len; /* File specification string size. */
+ if ((*status = sys$parse(&fab, 0, 0)) != RMS$_NORMAL)
+ return FALSE;
+ *status = sys$search(&fab, 0, 0);
+ if (*status != RMS$_NORMAL && *status != RMS$_NMF && *status != RMS$_FNF)
+ return FALSE;
+ /* For returned length eliminate version info */
+ fncpy_nover(nam.nam$l_rsa, nam.nam$b_rsl, exp_file_name, *exp_name_len);
+ return TRUE;
+}
diff --git a/sr_vvms/get_page_size.c b/sr_vvms/get_page_size.c
new file mode 100644
index 0000000..0138253
--- /dev/null
+++ b/sr_vvms/get_page_size.c
@@ -0,0 +1,26 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <syidef.h>
+#include "get_page_size.h"
+
+GBLDEF int4 gtm_os_page_size;
+
+void get_page_size(void)
+{
+ int4 status;
+
+ status = lib$getsyi(&SYI$_PAGE_SIZE, >m_os_page_size, 0, 0, 0, 0);
+ if ((status & 1) == 0)
+ rts_error(status);
+ return;
+}
diff --git a/sr_vvms/get_proc_info.c b/sr_vvms/get_proc_info.c
new file mode 100644
index 0000000..4975d42
--- /dev/null
+++ b/sr_vvms/get_proc_info.c
@@ -0,0 +1,60 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <jpidef.h>
+#include <prvdef.h>
+#include <ssdef.h>
+#include <efndef.h>
+
+#include "efn.h"
+#include "gtmsecshr.h"
+#include "vmsdtype.h"
+#include "repl_sp.h"
+
+uint4 get_proc_info(uint4 pid, uint4 *time, uint4 *icount)
+{
+ struct
+ {
+ item_list_3 item[2];
+ int4 terminator;
+ } item_list;
+ unsigned short iosb[4], retlen, retlen1;
+ uint4 status;
+ uint4 prvadr[2], prvprv[2];
+
+ GTMSECSHR_SET_PRIV(PRV$M_WORLD, status);
+ if (SS$_NORMAL == status)
+ {
+ item_list.item[0].buffer_length = SIZEOF(*icount);
+ item_list.item[0].item_code = JPI$_IMAGECOUNT;
+ item_list.item[0].buffer_address = icount;
+ item_list.item[0].return_length_address = &retlen1;
+ if (NULL != time)
+ {
+ item_list.item[1].buffer_length = SIZEOF(uint4) * 2;
+ item_list.item[1].item_code = JPI$_LOGINTIM;
+ item_list.item[1].buffer_address = time;
+ item_list.item[1].return_length_address = &retlen;
+ } else /* from is_proc_alive, no need for LOGINTIM which may require an INSWAP */
+ { /* each of these is a short */
+ item_list.item[1].buffer_length = 0;
+ item_list.item[1].item_code = 0;
+ }
+ item_list.terminator = 0;
+ status = sys$getjpiw(EFN$C_ENF, &pid, NULL, &item_list, iosb, NULL, 0);
+ if (SS$_NORMAL == status)
+ status = iosb[0];
+ GTMSECSHR_REL_PRIV;
+ }
+ return status;
+}
diff --git a/sr_vvms/get_src_line.c b/sr_vvms/get_src_line.c
new file mode 100644
index 0000000..328b720
--- /dev/null
+++ b/sr_vvms/get_src_line.c
@@ -0,0 +1,217 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include <fab.h>
+#include <rab.h>
+#include <rmsdef.h>
+
+#include "compiler.h"
+#include <rtnhdr.h>
+#include "srcline.h"
+#include "zroutines.h"
+#include "op.h"
+#include "gt_timer.h"
+#include "zbreak.h"
+#include "hashtab_mname.h"
+
+#define RT_TBL_SZ 20
+
+int get_src_line(mval *routine, mval *label, int offset, mstr **srcret, boolean_t verifytrig)
+{
+ struct FAB fab;
+ struct RAB rab;
+ struct NAM nam;
+ bool added;
+ unsigned char buff[MAX_SRCLINE], *cp1, *cp2, *cp3, *chkcalc;
+ unsigned char es[255], srcnamebuf[SIZEOF(mident_fixed) + STR_LIT_LEN(DOTM)];
+ boolean_t badfmt, found;
+ int *lt_ptr, tmp_int, status;
+ uint4 checksum, lcnt, srcint, srcstat, *src_tbl;
+ mstr src;
+ rhdtyp *rtn_vector;
+ zro_ent *srcdir;
+ mstr *base, *current, *top;
+ ht_ent_mname *tabent;
+ var_tabent rtnent;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ srcstat = 0;
+ *srcret = NULL;
+ if (NULL == (TREF(rt_name_tbl)).base)
+ init_hashtab_mname(TADR(rt_name_tbl), RT_TBL_SZ, HASHTAB_NO_COMPACT, HASHTAB_NO_SPARE_TABLE);
+ assert(routine->mvtype & MV_STR);
+ if (NULL == (rtn_vector = find_rtn_hdr(&routine->str))) /* Note assignment */
+ {
+ op_zlink(routine, NULL);
+ rtn_vector = find_rtn_hdr(&routine->str);
+ if (!rtn_vector)
+ return OBJMODMISS;
+ }
+ if (!rtn_vector->src_full_name.len)
+ return SRCNOTAVAIL;
+ rtnent.var_name = rtn_vector->routine_name;
+ COMPUTE_HASH_MNAME(&rtnent);
+ added = add_hashtab_mname(TADR(rt_name_tbl), &rtnent, NULL, &tabent);
+ src_tbl = (uint4 *)tabent->value;
+ if (added || 0 == tabent->value)
+ {
+ fab = cc$rms_fab;
+ fab.fab$l_fna = rtn_vector->src_full_name.addr;
+ fab.fab$b_fns = rtn_vector->src_full_name.len;
+ fab.fab$l_nam = &nam;
+ nam = cc$rms_nam;
+ nam.nam$l_esa = es;
+ nam.nam$b_ess = SIZEOF(es);
+ status = sys$parse(&fab);
+ if (!(status & 1))
+ found = FALSE;
+ else
+ {
+ status = sys$search(&fab);
+ if (!(status & 1))
+ found = FALSE;
+ else
+ found = TRUE;
+ }
+ if (!found)
+ {
+ tmp_int = rtn_vector->routine_name.len;
+ memcpy (srcnamebuf, rtn_vector->routine_name.addr, tmp_int);
+ if ('%' == srcnamebuf[0]) /* percents are translated to _ on filenames */
+ srcnamebuf[0] = '_';
+ MEMCPY_LIT(&srcnamebuf[tmp_int], DOTM);
+ src.addr = srcnamebuf;
+ src.len = tmp_int + STR_LIT_LEN(DOTM);
+ zro_search(0, 0, &src, &srcdir);
+ if (srcdir)
+ {
+ fab.fab$l_fna = srcnamebuf;
+ fab.fab$b_fns = tmp_int + 2;
+ fab.fab$l_dna = srcdir->str.addr;
+ fab.fab$b_dns = srcdir->str.len;
+ found = TRUE;
+ }
+ }
+ if (!found)
+ srcstat |= SRCNOTFND;
+ else
+ {
+ fab.fab$b_fac = FAB$M_GET;
+ fab.fab$b_shr = FAB$M_SHRGET;
+ for (lcnt = 0; lcnt < MAX_FILE_OPEN_TRIES; lcnt++)
+ {
+ status = sys$open(&fab);
+ if (RMS$_FLK != status)
+ break;
+ hiber_start(WAIT_FOR_FILE_TIME);
+ }
+ if (RMS$_NORMAL != status)
+ rts_error(VARLSTCNT(1) status);
+ rab = cc$rms_rab;
+ rab.rab$l_fab = &fab;
+ rab.rab$l_ubf = buff;
+ rab.rab$w_usz = SIZEOF(buff);
+ if (RMS$_NORMAL != (status = sys$connect(&rab)))
+ rts_error(VARLSTCNT(1) status);
+ }
+
+ tmp_int = found ? rtn_vector->lnrtab_len : 0;
+ assert((found && tmp_int >= 1) || (0 == tmp_int));
+ /* first two words are the status code and the number of entries */
+ src_tbl = (uint4 *)malloc(tmp_int * SIZEOF(mstr) + SIZEOF(uint4) * 2);
+ base = (mstr *)(src_tbl + 2);
+ *(src_tbl + 1) = tmp_int; /* So zlput_rname knows how big we are */
+ badfmt = FALSE;
+ checksum = 0;
+ for (current = base + 1, top = base + tmp_int; current < top; current++)
+ {
+ status = sys$get(&rab);
+ if (RMS$_EOF == status)
+ {
+ badfmt = TRUE;
+ break;
+ } else if (RMS$_NORMAL != status)
+ {
+ free(src_tbl);
+ rts_error(VARLSTCNT(1) status);
+ }
+ if (rab.rab$w_rsz)
+ {
+ /* set cp1 = to start of line separator */
+ for (cp1 = buff , cp2 = cp1 + rab.rab$w_rsz;
+ cp1 < cp2 && (' ' != *cp1) && ('\t' != *cp1); cp1++)
+ ;
+ /* calculate checksum */
+ for (chkcalc = buff; chkcalc < cp2;)
+ {
+ srcint = 0;
+ if (cp2 - chkcalc < SIZEOF(int4))
+ {
+ memcpy(&srcint, chkcalc, cp2 - chkcalc);
+ chkcalc = cp2;
+ } else
+ {
+ srcint = *(int4 *)chkcalc;
+ chkcalc += SIZEOF(int4);
+ }
+ checksum ^= srcint;
+ checksum >>= 1;
+ }
+ current->len = rab.rab$w_rsz;
+ current->addr = malloc(rab.rab$w_rsz);
+ memcpy(current->addr, buff, rab.rab$w_rsz);
+ } else
+ {
+ current->addr = malloc(1);
+ current->addr[0] = ' ';
+ current->len = 1;
+ }
+ }
+ if (found)
+ {
+ *base = *(base + 1);
+ if (!badfmt)
+ {
+ status = sys$get(&rab);
+ if ((RMS$_EOF != status) || checksum != rtn_vector->checksum)
+ badfmt = TRUE;
+ }
+ sys$close(&fab);
+ if (badfmt)
+ srcstat |= CHECKSUMFAIL;
+ }
+ *src_tbl = srcstat;
+ tabent->value = (char *)src_tbl;
+ }
+ srcstat |= *src_tbl;
+ lt_ptr = find_line_addr(rtn_vector, &label->str, 0, NULL);
+ if (!lt_ptr)
+ srcstat |= LABELNOTFOUND;
+ else if (!(srcstat & (SRCNOTFND | SRCNOTAVAIL)))
+ {
+ tmp_int = (int)(lt_ptr - (int *)LNRTAB_ADR(rtn_vector));
+ tmp_int += offset;
+ if (0 == tmp_int)
+ srcstat |= ZEROLINE;
+ else if (tmp_int < 0)
+ srcstat |= NEGATIVELINE;
+ else if (tmp_int >= rtn_vector->lnrtab_len)
+ srcstat |= AFTERLASTLINE;
+ else /* successfully located line */
+ *srcret = ((mstr *)(src_tbl + 2)) + tmp_int;
+ }
+ return srcstat;
+}
diff --git a/sr_vvms/get_tpu_addr.c b/sr_vvms/get_tpu_addr.c
new file mode 100644
index 0000000..8b4285a
--- /dev/null
+++ b/sr_vvms/get_tpu_addr.c
@@ -0,0 +1,26 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <descrip.h>
+
+unsigned char *get_tpu_addr()
+{
+ int4 status;
+ unsigned char *fcn;
+ static readonly $DESCRIPTOR(filename,"TPUSHR");
+ static readonly $DESCRIPTOR(symnam,"TPU$TPU");
+
+ status = lib$find_image_symbol(&filename,&symnam,&fcn);
+ if ((status & 1) == 0)
+ rts_error(VARLSTCNT(1) status);
+ return fcn;
+}
diff --git a/sr_vvms/get_tpu_addr.h b/sr_vvms/get_tpu_addr.h
new file mode 100644
index 0000000..8614b53
--- /dev/null
+++ b/sr_vvms/get_tpu_addr.h
@@ -0,0 +1,17 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef GET_TPU_ADDR_INCLUDED
+#define GET_TPU_ADDR_INCLUDED
+
+unsigned char *get_tpu_addr(void);
+
+#endif /* GET_TPU_ADDR_INCLUDED */
diff --git a/sr_vvms/getjobnum.c b/sr_vvms/getjobnum.c
new file mode 100644
index 0000000..46db7cd
--- /dev/null
+++ b/sr_vvms/getjobnum.c
@@ -0,0 +1,34 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <jpidef.h>
+#include <ssdef.h>
+
+#include "repl_sp.h"
+#include "getjobnum.h"
+
+GBLREF uint4 process_id;
+GBLREF uint4 image_count;
+
+void getjobnum(void)
+{
+ uint4 status;
+ int4 item_code;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ item_code = JPI$_PID;
+ if (SS$_NORMAL !=(status = lib$getjpi(&item_code, 0, 0, &process_id, 0, 0)))
+ rts_error(VARLSTCNT(1) status);
+ get_proc_info(process_id, TADR(login_time), &image_count);
+}
diff --git a/sr_vvms/getline.com b/sr_vvms/getline.com
new file mode 100644
index 0000000..85aa12a
--- /dev/null
+++ b/sr_vvms/getline.com
@@ -0,0 +1,66 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2003 Sanchez Computer Associates, Inc. !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$!
+$! p1 - "image+offset"
+$!
+$ if (p1 .eqs. "")
+$ then
+$ write sys$output ""
+$ write sys$output "Syntax : @gtm$tools:getline image+offset"
+$ write sys$output ""
+$ write sys$output " e.g. @gtm$tools:getline ""GTMSHR+0001FC"""
+$ write sys$output ""
+$ exit
+$ endif
+$!
+$ define sys$output nl:
+$ define sys$error nl:
+$!
+$ savegtmgbldir = f$trnlnm("gtm$gbldir","LNM$PROCESS_TABLE")
+$ savegtmroutines = f$trnlnm("gtm$routines","LNM$PROCESS_TABLE")
+$!
+$ define /process gtm$gbldir "gtm$map:mapdb.gld"
+$ define /process gtm$routines "gtm$vrt:[pct]/nosrc,gtm$map/src=(gtm$map,gtm$src,gtm$vrt:[pct])"
+$!
+$ define /process getlineinput "''p1'"
+$!
+$ deassign sys$output
+$ deassign sys$error
+$!
+$ curpriv=f$setprv("bypas") ! for writing in gtm$obj:*.lis and gtm$map:mapdb.dat
+$ gtm
+d ^mapoff($ztrnlnm("getlineinput"))
+$!
+$ curpriv=f$setprv(curpriv)
+$!
+$ define sys$output nl:
+$ define sys$error nl:
+$!
+$ deassign /process getlineinput
+$!
+$ if (savegtmgbldir .eqs. "")
+$ then
+$ deassign /process gtm$gbldir
+$ else
+$ define /process gtm$gbldir "''savegtmgbldir'"
+$ endif
+$!
+$ if (savegtmroutines .eqs. "")
+$ then
+$ deassign /process gtm$routines
+$ else
+$ define /process gtm$routines "''savegtmroutines'"
+$ endif
+$!
+$ deassign sys$output
+$ deassign sys$error
+$!
diff --git a/sr_vvms/getstorage.c b/sr_vvms/getstorage.c
new file mode 100644
index 0000000..e1ee826
--- /dev/null
+++ b/sr_vvms/getstorage.c
@@ -0,0 +1,24 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <jpidef.h>
+#include "getstorage.h"
+
+int4 getstorage(void)
+{
+ int4 status;
+ uint4 page_count;
+ status = lib$getjpi(&JPI$_FREPTECNT,0,0,&page_count,0,0);
+ if ((status & 1) == 0)
+ rts_error(status);
+ return (int4)(page_count < (MAXPOSINT4 / OS_PAGELET_SIZE) ? (page_count * OS_PAGELET_SIZE) : MAXPOSINT4);
+}
diff --git a/sr_vvms/getzmode.c b/sr_vvms/getzmode.c
new file mode 100644
index 0000000..e74e1f9
--- /dev/null
+++ b/sr_vvms/getzmode.c
@@ -0,0 +1,38 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <jpidef.h>
+#include <ssdef.h>
+#include <descrip.h>
+#include "getzmode.h"
+
+#define MAX_MODE_LEN 15
+
+void getzmode(void)
+{
+ static unsigned char mode_buf[MAX_MODE_LEN];
+ static readonly int4 jpi_code = JPI$_MODE;
+ $DESCRIPTOR(out_string,"");
+ short int out_len;
+ uint4 status;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ out_string.dsc$a_pointer = mode_buf;
+ out_string.dsc$w_length = MAX_MODE_LEN;
+ if (SS$_NORMAL != (status = lib$getjpi(&jpi_code ,0 ,0, 0, &out_string, &out_len))) /* Intentional assignment */
+ rts_error(VARLSTCNT(1) status);
+ (TREF(dollar_zmode)).str.addr = &mode_buf[0];
+ (TREF(dollar_zmode)).mvtype = MV_STR;
+ (TREF(dollar_zmode)).str.len = out_len;
+ return;
+}
diff --git a/sr_vvms/getzprocess.c b/sr_vvms/getzprocess.c
new file mode 100644
index 0000000..76b4dbe
--- /dev/null
+++ b/sr_vvms/getzprocess.c
@@ -0,0 +1,43 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2002 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <jpidef.h>
+#include <ssdef.h>
+#include <descrip.h>
+#include "job.h" /* for MAX_PRCNAM_LEN in jobsp.h */
+#include "getzprocess.h"
+
+GBLDEF mval dollar_zproc;
+static unsigned char proc_buf[MAX_PRCNAM_LEN + 1];
+
+void getzprocess(void)
+{
+ int4 jpi_code, status;
+ short int out_len;
+ $DESCRIPTOR(out_string, proc_buf);
+ error_def(ERR_SYSCALL);
+
+ jpi_code = JPI$_PRCNAM;
+ dollar_zproc.str.addr = proc_buf;
+ dollar_zproc.mvtype = MV_STR;
+ if ((status = lib$getjpi( &jpi_code
+ ,0
+ ,0
+ ,0
+ ,&out_string
+ ,&out_len )) != SS$_NORMAL)
+ {
+ rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("LIB$GETJPI"), CALLFROM, status);
+ }
+ dollar_zproc.str.len = out_len;
+ return;
+}
diff --git a/sr_vvms/global_name.c b/sr_vvms/global_name.c
new file mode 100644
index 0000000..79ebed3
--- /dev/null
+++ b/sr_vvms/global_name.c
@@ -0,0 +1,47 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <descrip.h>
+
+#include "gdsroot.h"
+
+
+void global_name (prefix, fil, buff)
+unsigned char prefix[4];
+gds_file_id *fil;
+unsigned char *buff;
+{
+ unsigned char *cp;
+ int i, j, k, n;
+
+ /* The routine MU_SEC_CLEAN decodes this algorithm. Keep the two routines in tandem. */
+
+ cp = buff + 1;
+ memcpy(cp, prefix, SIZEOF(prefix));
+ cp += SIZEOF(prefix);
+ i = fil->dvi[0];
+ memcpy(cp, &fil->dvi[1], i);
+ cp += i;
+ *cp++ = '$';
+ for (i = 0 ; i < SIZEOF(fil->fid) / SIZEOF(fil->fid[0]) ; i++)
+ {
+ for (k = fil->fid[i], j = 0 ; j < SIZEOF(fil->fid[0]) * 2; j++, k = k >> 4)
+ {
+ n = k & 0xf;
+ *cp++ = n + (n < 10 ? 48 : 55);
+ }
+ }
+ assert(cp - buff <= GLO_NAME_MAXLEN);
+ *buff = cp - buff - 1;
+ return;
+}
diff --git a/sr_vvms/go_load.c b/sr_vvms/go_load.c
new file mode 100644
index 0000000..03ecaeb
--- /dev/null
+++ b/sr_vvms/go_load.c
@@ -0,0 +1,344 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <rms.h>
+
+#include "stringpool.h"
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "error.h"
+#include "msg.h"
+#include "muextr.h"
+#include "util.h"
+#include "mupip_exit.h"
+#include "mlkdef.h"
+#include "zshow.h"
+#include "mu_load_stat.h"
+#include "load.h"
+#include "mu_gvis.h"
+#include "mupip_put_gvdata.h"
+#include "str2gvkey.h"
+#include "gtmmsg.h"
+#include "iottdefsp.h"
+
+#define DEFAULT_MAX_REC_SIZE 3072
+
+GBLREF bool mupip_error_occurred;
+GBLREF bool mu_ctrly_occurred;
+GBLREF bool mu_ctrlc_occurred;
+GBLREF gd_addr *gd_header;
+GBLREF spdesc stringpool;
+GBLREF gv_key *gv_currkey;
+GBLREF gd_region *gv_cur_region;
+
+error_def(ERR_RECCNT);
+error_def(ERR_MUPIPINFO);
+error_def(ERR_PREMATEOF);
+error_def(ERR_LOADABORT);
+error_def(ERR_LOADCTRLY);
+error_def(ERR_LOADEOF);
+error_def(ERR_BEGINST);
+error_def(ERR_LOADFILERR);
+error_def(ERR_MUNOACTION);
+error_def(ERR_MUNOFINISH);
+error_def(ERR_SYSCALL);
+
+/***********************************************************************************************/
+/* GT.M Go Format or ZWR Format */
+/***********************************************************************************************/
+void go_load(uint4 begin, uint4 end, struct RAB *inrab, struct FAB *infab)
+{
+ uint4 max_data_len, max_subsc_len, max_record_size, status;
+ uint4 key_count, rec_count;
+ msgtype msg;
+ char *ptr;
+ int len, keylength, keystate, fmt = MU_FMT_ZWR;
+ mstr src, des;
+ boolean_t keepgoing, format_error = FALSE;
+ unsigned char *rec_buff, ch;
+
+ msg.new_opts = msg.def_opts = 1;
+ inrab->rab$w_usz = ZWR_EXP_RATIO(gd_header->max_rec_size);
+ inrab->rab$l_ubf = malloc(inrab->rab$w_usz + 8);
+ inrab->rab$l_ubf = (((int4)(inrab->rab$l_ubf) + 7) & -8);
+ max_data_len = 0;
+ max_subsc_len = 0;
+ key_count = 0;
+ rec_count = 1;
+ max_record_size = DEFAULT_MAX_REC_SIZE;
+ rec_buff = (unsigned char *)malloc(max_record_size);
+ for (; 3 > rec_count; rec_count++)
+ {
+ status = sys$get(inrab); /* scan off header */
+ if (RMS$_EOF == status)
+ {
+ sys$close(infab);
+ mupip_exit(ERR_PREMATEOF);
+ }
+ if (RMS$_NORMAL != status)
+ {
+ gtm_putmsg(VARLSTCNT(14) ERR_LOADFILERR, 2, infab->fab$b_fns, infab->fab$l_fna,
+ ERR_SYSCALL, 5, LEN_AND_LIT("SYS$GET"), CALLFROM, status, 0, inrab->rab$l_stv);
+ sys$close(infab);
+ mupip_exit(ERR_MUNOACTION);
+ }
+ len = inrab->rab$w_rsz;
+ ptr = inrab->rab$l_rbf;
+ while (0 < len && ((ASCII_LF == *(ptr + len - 1)) || (ASCII_CR == *(ptr + len - 1))))
+ len--;
+ if (2 == rec_count) /* the format flag appears only in the second record. */
+ fmt = (0 == memcmp(ptr + len - STR_LIT_LEN("ZWR"), "ZWR", STR_LIT_LEN("ZWR"))) ?
+ MU_FMT_ZWR : MU_FMT_GO;
+ msg.msg_number = ERR_MUPIPINFO;
+ msg.arg_cnt = 6;
+ msg.fp_cnt = 4;
+ msg.fp[0].n = len;
+ msg.fp[1].cp = ptr;
+ sys$putmsg(&msg, 0, 0, 0);
+ }
+ if (begin < 3)
+ begin = 3;
+ assert(3 == rec_count);
+ for (; rec_count < begin; rec_count++) /* scan to begin */
+ {
+ status = sys$get(inrab);
+ if (RMS$_EOF == status)
+ {
+ sys$close(infab);
+ gtm_putmsg(VARLSTCNT(3) ERR_LOADEOF, 1, begin);
+ mupip_exit(ERR_MUNOACTION);
+ }
+ if (RMS$_NORMAL != status)
+ {
+ gtm_putmsg(VARLSTCNT(14) ERR_LOADFILERR, 2, infab->fab$b_fns, infab->fab$l_fna,
+ ERR_SYSCALL, 5, LEN_AND_LIT("SYS$GET"), CALLFROM, status, 0, inrab->rab$l_stv);
+ sys$close(infab);
+ mupip_exit(ERR_MUNOACTION);
+ }
+ }
+ msg.msg_number = ERR_BEGINST;
+ msg.arg_cnt = 4;
+ msg.fp_cnt = 2;
+ msg.fp[0].n = rec_count;
+ sys$putmsg(&msg, 0, 0, 0);
+
+ ESTABLISH(mupip_load_ch);
+ for (; ; rec_count++)
+ {
+ if (mu_ctrly_occurred || mupip_error_occurred)
+ break;
+ if (mu_ctrlc_occurred)
+ {
+ mu_load_stat(max_data_len, max_subsc_len, key_count, key_count ? (rec_count - 1) : 0, ERR_RECCNT);
+ mu_gvis();
+ util_out_print("", TRUE);
+ }
+ /* reset the stringpool for every record in order to avoid garbage collection */
+ stringpool.free = stringpool.base;
+ if (rec_count > end)
+ break;
+ if (RMS$_EOF == (status = sys$get(inrab)))
+ break;
+ if (RMS$_NORMAL != status)
+ {
+ rts_error(VARLSTCNT(14) ERR_LOADFILERR, 2, infab->fab$b_fns, infab->fab$l_fna,
+ ERR_SYSCALL, 5, LEN_AND_LIT("SYS$GET"), CALLFROM, status, 0, inrab->rab$l_stv);
+ mupip_error_occurred = TRUE;
+ break;
+ }
+ len = inrab->rab$w_rsz;
+ ptr = inrab->rab$l_rbf;
+ while (0 < len && ((ASCII_LF == *(ptr + len - 1)) || (ASCII_CR == *(ptr + len - 1))))
+ len--;
+ if (0 == len)
+ continue;
+ if (MU_FMT_ZWR == fmt)
+ {
+ keylength = 0;
+ keystate = 0;
+ keepgoing = TRUE;
+ while((keylength < len - 1) && keepgoing) /* 1 == SIZEOF(=), since ZWR allows '^x(1,2)='*/
+ {
+ ch = *(ptr + keylength);
+ keylength++;
+ switch (keystate)
+ {
+ case 0: /* in global name */
+ if ('=' == ch) /* end of key */
+ {
+ keylength--;
+ keepgoing = FALSE;
+ }
+ else if ('(' == ch) /* start of subscripts */
+ keystate = 1;
+ break;
+ case 1: /* in subscripts area, but out of quotes or $C() */
+ switch (ch)
+ {
+ case ')': /* end of subscripts ==> end of key */
+ assert('=' == *(ptr + keylength));
+ keepgoing = FALSE;
+ break;
+ case '"': /* step into "..." */
+ keystate = 2;
+ break;
+ case '$': /* step into $C(...) */
+ assert(('C' == *(ptr + keylength)) || ('c' == *(ptr + keylength)));
+ assert('(' == *(ptr + keylength + 1));
+ keylength += 2;
+ keystate = 3;
+ break;
+ }
+ break;
+ case 2: /* in "..." */
+ if ('"' == ch)
+ {
+ switch (*(ptr + keylength))
+ {
+ case '"': /* "" */
+ keylength++;
+ break;
+ case '_': /* _$C(...) */
+ assert('$' == *(ptr + keylength + 1));
+ assert(('c' == *(ptr + keylength + 2)) || ('C' == *(ptr + keylength + 2)));
+ assert('(' == *(ptr + keylength + 3));
+ keylength += 4;
+ keystate = 3;
+ break;
+ default: /* step out of "..." */
+ keystate = 1;
+ }
+ }
+ break;
+ case 3: /* in $C(...) */
+ if (')' == ch)
+ {
+ if ('_' == *(ptr + keylength)) /* step into "..." */
+ {
+ assert('"' == *(ptr + keylength + 1));
+ keylength += 2;
+ keystate = 2;
+ break;
+ }
+ else
+ keystate = 1; /* step out of $C(...) */
+ }
+ break;
+ default:
+ assert(FALSE);
+ break;
+ }
+ }
+ gv_currkey->end = 0;
+ str2gvkey_gvfunc(ptr, keylength);
+ if (mupip_error_occurred)
+ {
+ mu_gvis();
+ break;
+ }
+ assert(keylength < len - 1);
+ if (max_subsc_len < (gv_currkey->end + 1))
+ max_subsc_len = gv_currkey->end + 1;
+ src.len = len - keylength - 1;
+ src.addr = (char *)(ptr + keylength + 1);
+ des.len = 0;
+ if (src.len > max_record_size)
+ {
+ max_record_size = src.len;
+ free(rec_buff);
+ rec_buff = (unsigned char *)malloc(max_record_size);
+ }
+ des.addr = (char *)rec_buff;
+ if (FALSE == zwr2format(&src, &des))
+ {
+ util_out_print("Format error in record !8UL: !/!AD", TRUE, rec_count, src.len, src.addr);
+ format_error = TRUE;
+ continue;
+ }
+ if (max_data_len < des.len)
+ max_data_len = des.len;
+ mupip_put_gvdata(rec_buff, des.len);
+ if (mupip_error_occurred)
+ {
+ mu_gvis();
+ break;
+ }
+ key_count++;
+ } else
+ {
+ gv_currkey->end = 0;
+ str2gvkey_gvfunc(ptr, len);
+ if (mupip_error_occurred)
+ {
+ mu_gvis();
+ break;
+ }
+ if (max_subsc_len < (gv_currkey->end + 1))
+ max_subsc_len = gv_currkey->end + 1;
+ rec_count++;
+ if (rec_count > end)
+ {
+ rec_count--; /* Decrement as didn't load key */
+ break;
+ }
+ if (RMS$_EOF == (status = sys$get(inrab)))
+ break;
+ if (RMS$_NORMAL != status)
+ {
+ mupip_error_occurred = TRUE;
+ mu_gvis();
+ rts_error(VARLSTCNT(14) ERR_LOADFILERR, 2, infab->fab$b_fns, infab->fab$l_fna,
+ ERR_SYSCALL, 5, LEN_AND_LIT("SYS$GET"), CALLFROM, status, 0, inrab->rab$l_stv);
+ break;
+ }
+ len = inrab->rab$w_rsz;
+ ptr = inrab->rab$l_rbf;
+ while (0 < len && ((ASCII_LF == *(ptr + len - 1)) || (ASCII_CR == *(ptr + len - 1))))
+ len--;
+ if (max_data_len < len)
+ max_data_len = len;
+ mupip_put_gvdata(ptr, len);
+ if (mupip_error_occurred)
+ {
+ mu_gvis();
+ break;
+ }
+ key_count++;
+ }
+ }
+ gv_cur_region = NULL;
+ REVERT;
+ status = sys$close(infab);
+ if (RMS$_NORMAL != status)
+ {
+ gtm_putmsg(VARLSTCNT(14) ERR_LOADFILERR, 2, infab->fab$b_fns, infab->fab$l_fna,
+ ERR_SYSCALL, 5, LEN_AND_LIT("SYS$CLOSE"), CALLFROM, status, 0, inrab->rab$l_stv);
+ mupip_error_occurred = TRUE;
+ }
+ if (mupip_error_occurred)
+ {
+ gtm_putmsg(VARLSTCNT(3) ERR_LOADABORT, 1, rec_count);
+ mupip_exit( ERR_MUNOACTION );
+ }
+ if (mu_ctrly_occurred)
+ rts_error(VARLSTCNT(1) ERR_LOADCTRLY);
+ mu_load_stat(max_data_len, max_subsc_len, key_count, key_count ? (rec_count - 1) : 0, ERR_RECCNT);
+ free(inrab->rab$l_ubf);
+ free(rec_buff);
+ if (format_error)
+ mupip_exit(ERR_MUNOFINISH);
+}
diff --git a/sr_vvms/golevel.c b/sr_vvms/golevel.c
new file mode 100644
index 0000000..0a45965
--- /dev/null
+++ b/sr_vvms/golevel.c
@@ -0,0 +1,53 @@
+/****************************************************************
+ * *
+ * Copyright 2010, 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_stdio.h"
+
+#include <rtnhdr.h>
+#include "stack_frame.h"
+#include "tp_frame.h"
+#include "golevel.h"
+#include "error.h"
+#include "dollar_zlevel.h"
+
+GBLREF stack_frame *frame_pointer;
+
+error_def(ERR_ZGOTOTOOBIG);
+error_def(ERR_ZGOTOLTZERO);
+
+void golevel(int4 level)
+{
+ stack_frame *fp;
+ int4 unwind, zlevel, prevlvl;
+
+ if (0 > level)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZGOTOLTZERO);
+ for (zlevel = 0, fp = frame_pointer; fp->old_frame_pointer; fp = fp->old_frame_pointer)
+ {
+ if (fp->type & SFT_COUNT)
+ zlevel++;
+ }
+ if (level > zlevel)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_ZGOTOTOOBIG);
+ for (unwind = 0, fp = frame_pointer; fp->old_frame_pointer; fp = fp->old_frame_pointer)
+ {
+ if ((fp->type & SFT_COUNT) && (level == zlevel--))
+ break;
+ unwind++;
+ }
+ DBGEHND_ONLY(prevlvl = dollar_zlevel());
+ GOFRAMES(unwind, FALSE, FALSE);
+ DBGEHND((stderr, "golevel: Unwound from level %d to level %d which is %d frames ending in stackframe 0x"lvaddr" with"
+ " type 0x%04lx\n", prevlvl, level, unwind, frame_pointer, (frame_pointer ? frame_pointer->type : 0xffff)));
+ return;
+}
diff --git a/sr_vvms/goq_load.c b/sr_vvms/goq_load.c
new file mode 100644
index 0000000..1e92fe7
--- /dev/null
+++ b/sr_vvms/goq_load.c
@@ -0,0 +1,193 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <iodef.h>
+#include <rms.h>
+#include <ssdef.h>
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "efn.h"
+#include "msg.h"
+#include "mupip_exit.h"
+#include "load.h"
+
+#define MVX_BLK_SIZE 2048
+#define M11_BLK_SIZE 1024
+
+GBLREF gd_region *gv_cur_region;
+
+/***********************************************************************************************/
+/* M/VX GOQ Format */
+/***********************************************************************************************/
+void goq_load(uint4 begin, uint4 end, struct FAB *infab)
+{
+ int status;
+ msgtype msg;
+ unsigned char *in_buff, *b;
+ unsigned int n;
+ bool is_begin;
+ uint4 rec_count;
+ unsigned short goq_blk_size;
+ short iosb[4];
+
+ error_def(ERR_INVMVXSZ);
+ error_def(ERR_MUPIPINFO);
+ error_def(ERR_PREMATEOF);
+ error_def(ERR_LDGOQFMT);
+ error_def(ERR_BEGINST);
+
+ rec_count = 0;
+ if (begin > 0)
+ is_begin = TRUE;
+ else
+ is_begin = FALSE;
+ goq_blk_size = MVX_BLK_SIZE;
+ infab->fab$w_mrs = goq_blk_size;
+ in_buff = malloc(goq_blk_size + 8);
+ if (is_begin)
+ {
+ status = sys$qio(efn_bg_qio_read, infab->fab$l_stv, IO$_READVBLK, &iosb[0],
+ 0, 0, in_buff, goq_blk_size,
+ (rec_count * goq_blk_size / 512) + 1, 0, 0, 0);
+ if (SS$_NORMAL != status) /* get header block */
+ rts_error(VARLSTCNT(1) status);
+ sys$synch(efn_bg_qio_read, &iosb[0]);
+ if (SS$_NORMAL != iosb[0])
+ rts_error(VARLSTCNT(1) iosb[0]);
+ if (iosb[1] != goq_blk_size)
+ {
+ if (M11_BLK_SIZE != iosb[1])
+ rts_error(VARLSTCNT(1) ERR_INVMVXSZ);
+ goq_blk_size = M11_BLK_SIZE;
+ }
+ while ((SS$_ENDOFFILE != iosb[0]) && (rec_count < begin))
+ {
+ rec_count++;
+ status = sys$qio(efn_bg_qio_read, infab->fab$l_stv, IO$_READVBLK, &iosb[0],
+ 0, 0, in_buff, goq_blk_size,
+ (rec_count * goq_blk_size / 512) + 1, 0, 0, 0);
+ if (SS$_NORMAL != status)
+ rts_error(VARLSTCNT(1) status);
+ sys$synch(efn_bg_qio_read, &iosb[0]);
+ if ((SS$_NORMAL != iosb[0]) && (SS$_ENDOFFILE != iosb[0]))
+ {
+ rts_error(VARLSTCNT(1) iosb[0]);
+ mupip_exit(iosb[0]);
+ }
+ }
+ for (;rec_count < begin;)
+ {
+ status = sys$qio(efn_bg_qio_read, infab->fab$l_stv, IO$_READVBLK, &iosb[0],
+ 0, 0, in_buff, goq_blk_size,
+ (rec_count * goq_blk_size / 512) + 1, 0, 0, 0);
+ if (SS$_NORMAL != status)
+ rts_error(VARLSTCNT(1) status);
+ sys$synch(efn_bg_qio_read, &iosb[0]);
+ if (SS$_ENDOFFILE == iosb[0])
+ rts_error(VARLSTCNT(1) ERR_PREMATEOF);
+ if (SS$_NORMAL != iosb[0])
+ rts_error(VARLSTCNT(1) iosb[0]);
+ rec_count++;
+ }
+ msg.msg_number = ERR_BEGINST;
+ msg.arg_cnt = 3;
+ msg.new_opts = msg.def_opts = 1;
+ msg.fp_cnt = 1;
+ msg.fp[0].n = rec_count;
+ sys$putmsg(&msg, 0, 0, 0);
+ } else
+ {
+ status = sys$qio(efn_bg_qio_read, infab->fab$l_stv, IO$_READVBLK, &iosb[0],
+ 0, 0, in_buff, goq_blk_size,
+ (rec_count * goq_blk_size / 512) + 1, 0, 0, 0);
+ if (SS$_NORMAL != status)
+ rts_error(VARLSTCNT(1) status);
+ sys$synch(efn_bg_qio_read, &iosb[0]);
+ if (SS$_NORMAL != iosb[0])
+ {
+ rts_error(VARLSTCNT(1) iosb[0]);
+ mupip_exit(iosb[0]);
+ }
+ if (iosb[1] != goq_blk_size)
+ {
+ if (M11_BLK_SIZE != iosb[1])
+ rts_error(VARLSTCNT(1) ERR_INVMVXSZ);
+ goq_blk_size = M11_BLK_SIZE;
+ }
+ b = in_buff;
+ while ((13 != *b++) && (b - in_buff < goq_blk_size - 28))
+ ;
+ if (memcmp(b - SIZEOF("~%GOQ"), LIT_AND_LEN("~%GOQ")) || (10 != *b))
+ {
+ rts_error(VARLSTCNT(1) ERR_LDGOQFMT);
+ mupip_exit(ERR_LDGOQFMT);
+ }
+ for (n = 0; n < 3; n++)
+ {
+ while ((13 != *b++) && b - in_buff < goq_blk_size)
+ ;
+ if (10 != *b++)
+ {
+ rts_error(VARLSTCNT(1) ERR_LDGOQFMT);
+ mupip_exit(ERR_LDGOQFMT);
+ }
+ }
+ msg.msg_number = ERR_MUPIPINFO;
+ msg.arg_cnt = 4;
+ msg.new_opts = msg.def_opts = 1;
+ msg.fp_cnt = 2;
+ msg.fp[0].n = b - in_buff - 1;
+ msg.fp[1].cp = in_buff;
+ sys$putmsg(&msg, 0, 0, 0);
+ while (SS$_ENDOFFILE != iosb[0])
+ {
+ rec_count++;
+ status = sys$qio(efn_bg_qio_read, infab->fab$l_stv, IO$_READVBLK, &iosb[0],
+ 0, 0, in_buff, goq_blk_size,
+ (rec_count * goq_blk_size / 512) + 1, 0, 0, 0);
+ if (SS$_NORMAL != status)
+ {
+ rts_error(VARLSTCNT(1) status);
+ mupip_exit(status);
+ }
+ sys$synch(efn_bg_qio_read, &iosb[0]);
+ if ((SS$_NORMAL != iosb[0]) && (SS$_ENDOFFILE != iosb[0]))
+ {
+ rts_error(VARLSTCNT(1) iosb[0]);
+ mupip_exit(iosb[0]);
+ }
+ }
+ }
+ if (MVX_BLK_SIZE == goq_blk_size)
+ goq_mvx_load(infab, in_buff, rec_count, end);
+ else
+ goq_m11_load(infab, in_buff, rec_count, end);
+ /***********************************************************************************************/
+ /* Shut Down */
+ /***********************************************************************************************/
+CLOSE:
+ free(in_buff);
+ gv_cur_region = NULL;
+ status = sys$dassgn(infab->fab$l_stv);
+ if (SS$_NORMAL != status)
+ {
+ rts_error(VARLSTCNT(1) status);
+ mupip_exit(status);
+ }
+ return;
+}
diff --git a/sr_vvms/goq_m11_load.c b/sr_vvms/goq_m11_load.c
new file mode 100644
index 0000000..9513df2
--- /dev/null
+++ b/sr_vvms/goq_m11_load.c
@@ -0,0 +1,437 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <rms.h>
+#include "efn.h"
+#include <ssdef.h>
+#include <iodef.h>
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "msg.h"
+#include "muextr.h"
+#include "stringpool.h"
+#include "util.h"
+#include "op.h"
+#include "error.h"
+#include "mu_load_stat.h"
+#include "mvalconv.h"
+#include "mu_gvis.h"
+#include "quad2asc.h"
+
+#define ODD 1
+#define NEGORZRO 1
+#define M11_ZRO 96
+#define M11_EXP 64
+#define M11_NEG 128
+#define GTM_PREC 15
+
+#define MVX_BLK_SIZE 2048
+#define M11_BLK_SIZE 1024
+
+GBLREF bool mupip_error_occurred;
+GBLREF bool mupip_DB_full;
+GBLREF bool mu_ctrly_occurred;
+GBLREF bool mu_ctrlc_occurred;
+GBLREF gd_addr *gd_header;
+GBLREF gv_key *gv_currkey;
+GBLREF spdesc stringpool;
+
+#define US 0
+#define THEM 1
+#define GOQ_MAX_KSIZ 512
+#define LCL_BUF_SIZE 256
+
+error_def(ERR_BLKCNT);
+error_def(ERR_CORRUPT);
+error_def(ERR_GOQPREC);
+error_def(ERR_LOADABORT);
+error_def(ERR_LOADCTRLY);
+
+void goq_m11_load(struct FAB *infab, char *in_buff, uint4 rec_count, uint4 end)
+{
+ uint4 max_data_len, max_subsc_len, key_count, global_key_count;
+ int status;
+ msgtype msg;
+ char digit,exp, k_buff[LCL_BUF_SIZE];
+ unsigned char *cp1, *cp2, *cp3, *dp1, *b, *btop;
+ boolean_t mupip_precision_error, is_dec, is_end;
+ unsigned int len, n, order;
+ unsigned short goq_blk_size;
+ short iosb[4];
+ struct {
+ unsigned char cmpc;
+ unsigned char subsc_len;
+ unsigned char subsc[1];
+ } *goq_rp;
+ short int *goq_blk_used;
+ gv_key *goq_currkey;
+ int goq_key_sub, goq_subsc_map[2][129];
+ mval v, exist;
+
+ if (end > 0)
+ is_end = TRUE;
+ else is_end = FALSE;
+
+ max_data_len = max_subsc_len = key_count = 0;
+ goq_subsc_map[0][0] = goq_subsc_map[1][0] = 0;
+
+ goq_blk_size = M11_BLK_SIZE;
+ goq_currkey = malloc (SIZEOF(gv_key) + GOQ_MAX_KSIZ - 1);
+ goq_currkey->top = GOQ_MAX_KSIZ;
+ goq_blk_used = in_buff + goq_blk_size - SIZEOF(short int);
+ gv_currkey = malloc (SIZEOF(gv_key) + GOQ_MAX_KSIZ - 1 + MAX_GVKEY_PADDING_LEN);
+ gv_currkey->top = GOQ_MAX_KSIZ;
+
+
+ lib$establish(mupip_load_ch);
+
+ for (; !mupip_DB_full ;)
+ {
+ mupip_precision_error = FALSE;
+ mupip_error_occurred = FALSE;
+ if (mu_ctrly_occurred)
+ { break;
+ }
+ if (mu_ctrlc_occurred)
+ {
+ mu_load_stat(max_data_len, max_subsc_len, key_count, rec_count, ERR_BLKCNT);
+ mu_gvis();
+ util_out_print(0,TRUE);
+ }
+ /* reset the stringpool for every record in order to avoid garbage collection */
+ stringpool.free = stringpool.base;
+ if (is_end && (rec_count >= end))
+ break;
+ len = 0;
+ /*****************************************************************************************/
+ while (len == 0)
+ {
+ status = sys$qio(efn_bg_qio_read, infab->fab$l_stv ,IO$_READVBLK , &iosb[0],
+ 0,0,in_buff,goq_blk_size,
+ (rec_count * goq_blk_size / 512) + 1,0,0,0);
+
+ if (status != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+
+ sys$synch(efn_bg_qio_read, &iosb[0]);
+ if (iosb[0] == SS$_ENDOFFILE)
+ break;
+
+ if (iosb[0] != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) iosb[0]);
+ rec_count++;
+ len = *goq_blk_used;
+ }
+ /*****************************************************************************************/
+ if ((is_end && rec_count >= end) || iosb[0] == SS$_ENDOFFILE)
+ break;
+ if (len >= goq_blk_size)
+ { rts_error(VARLSTCNT(4) ERR_CORRUPT,2,rec_count,0);
+ continue;
+ }
+ goq_rp = in_buff;
+
+ btop = in_buff + len;
+ global_key_count = 1;
+ goq_key_sub = 0;
+
+ b = v.str.addr = &k_buff[0];
+ cp1 = &goq_rp->subsc[0];
+ cp2 = &goq_rp->subsc[0] + goq_rp->subsc_len;
+ cp3 = &goq_currkey->base[0];
+
+ while (*cp1 & ODD)
+ {
+ *b++ = *cp1 /2;
+ *cp3++ = *cp1++;
+ }
+ *b++ = *cp1 /2;
+ *cp3++ = *cp1++;
+ v.str.len = b - (unsigned char *) v.str.addr;
+
+ if (goq_rp->cmpc != 0 || v.str.len > goq_currkey->top)
+ {
+ rts_error(VARLSTCNT(4) ERR_CORRUPT,2,rec_count,global_key_count);
+ continue;
+ }
+ GV_BIND_NAME_AND_ROOT_SEARCH (gd_header, &v.str);
+ if (mupip_error_occurred)
+ {
+ rts_error(VARLSTCNT(4) ERR_CORRUPT,2,rec_count,global_key_count);
+ mu_gvis();
+ util_out_print(0,TRUE);
+ continue;
+ }
+ goq_key_sub++;
+ goq_subsc_map [US][goq_key_sub] = gv_currkey->end;
+ goq_subsc_map [THEM][goq_key_sub] = goq_currkey->end = v.str.len;
+
+ while (cp1 < cp2)
+ {
+ *cp3++ = *cp1++;
+ }
+ cp3 = &goq_currkey->base[0];
+ cp1 = cp3 + goq_currkey->end;
+ cp2 = cp3 + goq_rp->subsc_len;
+ for (;; )
+ {
+ dp1 = &goq_rp->subsc[ goq_rp->subsc_len ];
+ n = *dp1 + SIZEOF(char); /* size of data */
+
+ n += goq_rp->subsc_len + 2 * SIZEOF(char); /* size of key */
+ if ((unsigned char *) goq_rp + n > btop)
+ {
+ rts_error(VARLSTCNT(4) ERR_CORRUPT,2,rec_count,global_key_count);
+ mu_gvis();
+ util_out_print(0,TRUE);
+ break;
+ }
+ while (cp1 < cp2)
+ {
+ if (*cp1 == NEGORZRO)
+ {
+ cp1++;
+ exp = *cp1++;
+ if (exp < M11_EXP)
+ {
+ v.mvtype = MV_STR;
+ b = v.str.addr = &k_buff;
+ *b++ = '-';
+ *b++ = '.';
+ exp /= 2;
+ exp = M11_EXP/2 - exp - 1;
+ assert (exp < M11_EXP/2);
+
+ while (*cp1 != M11_NEG && cp1 < cp2 && !mupip_error_occurred)
+ {
+ digit = *cp1++;
+ digit /= 2;
+ switch (digit)
+ {
+ case '0': *b++ = '9';
+ break;
+ case '1': *b++ = '8';
+ break;
+ case '2': *b++ = '7';
+ break;
+ case '3': *b++ = '6';
+ break;
+ case '4': *b++ = '5';
+ break;
+ case '5': *b++ = '4';
+ break;
+ case '6': *b++ = '3';
+ break;
+ case '7': *b++ = '2';
+ break;
+ case '8': *b++ = '1';
+ break;
+ case '9': *b++ = '0';
+ break;
+ default:
+ rts_error(VARLSTCNT(4) ERR_CORRUPT,2,rec_count,
+ global_key_count);
+ mu_gvis();
+ util_out_print(0,TRUE);
+ }
+ }
+ if (!mupip_error_occurred)
+ {
+ if (*cp1++ != M11_NEG)
+ { rts_error(VARLSTCNT(4) ERR_CORRUPT,2,rec_count,global_key_count);
+ mu_gvis();
+ util_out_print(0,TRUE);
+ break;
+ }
+ if (b - (unsigned char *) v.str.addr > GTM_PREC + 2)
+ {
+ mupip_precision_error = TRUE;
+ }
+ *b++ = 'E';
+ if (order = exp/10)
+ *b++ = order + 48;
+ *b++ = exp - order*10 + 48;
+ v.str.len = b - (unsigned char *) v.str.addr;
+ s2n(&v);
+ if (mupip_error_occurred)
+ { rts_error(VARLSTCNT(4) ERR_CORRUPT,2,rec_count,global_key_count);
+ mu_gvis();
+ util_out_print(0,TRUE);
+ break;
+ }
+ else
+ v.mvtype = MV_NM;
+ }
+ }
+ else if (exp == M11_ZRO)
+ {
+ v.mvtype = MV_NM;
+ v.m[1] = 0;
+ }
+ else
+ { rts_error(VARLSTCNT(4) ERR_CORRUPT,2,rec_count,global_key_count);
+ mu_gvis();
+ util_out_print(0,TRUE);
+ break;
+ }
+ }
+ else if (*cp1 > NEGORZRO && *cp1 < M11_EXP)
+ {
+ cp1++;
+ is_dec = 0;
+ v.mvtype = MV_STR;
+ b = v.str.addr = &k_buff;
+ while (*cp1 & ODD)
+ {
+ *b = *cp1++ / 2;
+
+ if (*b++ == '.')
+ is_dec = 1;
+ }
+ *b++ = *cp1++ / 2;
+ v.str.len = b - (unsigned char *) v.str.addr;
+ if (cp1 > cp2)
+ {
+ rts_error(VARLSTCNT(4) ERR_CORRUPT,2,rec_count,global_key_count);
+ mu_gvis();
+ util_out_print(0,TRUE);
+ break;
+ }
+ if (v.str.len > GTM_PREC + is_dec)
+ {
+ mupip_precision_error = TRUE;
+ }
+ s2n(&v);
+ if (mupip_error_occurred)
+ { rts_error(VARLSTCNT(4) ERR_CORRUPT,2,rec_count,global_key_count);
+ mu_gvis();
+ util_out_print(0,TRUE);
+ break;
+ }
+ else
+ v.mvtype = MV_NM;
+ }
+ else
+ {
+ v.mvtype = MV_STR;
+ b = v.str.addr = &k_buff[0];
+ while (*cp1 & ODD)
+ {
+ *b++ = *cp1++ / 2;
+ }
+ *b++ = *cp1++ /2;
+ v.str.len = b - (unsigned char *) v.str.addr;
+ if (cp1 > cp2)
+ {
+ rts_error(VARLSTCNT(4) ERR_CORRUPT,2,rec_count,global_key_count);
+ mu_gvis();
+ util_out_print(0,TRUE);
+ break;
+ }
+ }
+ mval2subsc(&v,gv_currkey);
+ gv_currkey->prev = 0;
+ if (mupip_error_occurred)
+ {
+ rts_error(VARLSTCNT(4) ERR_CORRUPT,2,rec_count,global_key_count);
+ mu_gvis();
+ util_out_print(0,TRUE);
+ break;
+ }
+ goq_key_sub++;
+ goq_subsc_map[US][goq_key_sub] = gv_currkey->end;
+ goq_subsc_map[THEM][goq_key_sub] = goq_currkey->end = cp1 - cp3;
+ }
+
+ if (mupip_error_occurred)
+ break;
+
+ v.mvtype = MV_STR; /* mval for datum */
+ v.str.len = *dp1++;
+ v.str.addr = dp1;
+
+ if (mupip_precision_error)
+ {
+ op_gvdata(&exist);
+ if (exist.m[1] != 0)
+ {
+ msg.arg_cnt = 4;
+ msg.new_opts = msg.def_opts = 1;
+ msg.msg_number = ERR_GOQPREC;
+ msg.fp_cnt = 2;
+ msg.fp[0].n = rec_count;
+ msg.fp[1].n = global_key_count;
+ sys$putmsg(&msg,0,0,0);
+ mu_gvis();
+ util_out_print(0,TRUE);
+ }
+ else
+ op_gvput(&v);
+ mupip_precision_error = FALSE;
+ }
+ else
+ op_gvput (&v);
+ if (mupip_error_occurred)
+ {
+ if (!mupip_DB_full)
+ {
+ rts_error(VARLSTCNT(4) ERR_CORRUPT,2,rec_count,global_key_count);
+ util_out_print(0,TRUE);
+ }
+ break;
+ }
+ if (max_data_len < v.str.len)
+ max_data_len = v.str.len;
+ if (max_subsc_len < (gv_currkey->end + 1))
+ max_subsc_len = gv_currkey->end + 1;
+ key_count++;
+
+ (char *) goq_rp += n;
+ if (goq_rp < btop)
+ {
+ if (goq_rp->cmpc > goq_currkey->end)
+ {
+ rts_error(VARLSTCNT(4) ERR_CORRUPT,2,rec_count,global_key_count);
+ break;
+ }
+ cp1 = &goq_rp->subsc[0];
+ cp2 = &goq_currkey->base[0] + goq_rp->cmpc;
+ for ( n = 0; n < goq_rp->subsc_len; n++)
+ *cp2++ = *cp1++;
+ n = goq_key_sub;
+ for (; goq_subsc_map[THEM][n] > goq_rp->cmpc; n--)
+ ;
+ goq_key_sub = n;
+ cp1 = cp3 + goq_subsc_map[THEM][goq_key_sub];
+ gv_currkey->end = goq_subsc_map[US][goq_key_sub];
+ global_key_count++;
+ }
+ else
+ break;
+ }
+ }
+
+ if (mu_ctrly_occurred)
+ lib$signal(ERR_LOADCTRLY);
+
+ if (mupip_error_occurred)
+ lib$signal(ERR_LOADABORT,1,rec_count);
+ else
+ mu_load_stat(max_data_len, max_subsc_len, key_count, rec_count, ERR_BLKCNT);
+
+ free (goq_currkey);
+ free (gv_currkey);
+}
diff --git a/sr_vvms/goq_mvx_load.c b/sr_vvms/goq_mvx_load.c
new file mode 100644
index 0000000..1ac0873
--- /dev/null
+++ b/sr_vvms/goq_mvx_load.c
@@ -0,0 +1,520 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <rms.h>
+#include <ssdef.h>
+#include <iodef.h>
+
+#include "efn.h"
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "msg.h"
+#include "muextr.h"
+#include "stringpool.h"
+#include "util.h"
+#include "op.h"
+#include "error.h"
+#include "mu_load_stat.h"
+#include "mvalconv.h"
+#include "mu_gvis.h"
+#include "quad2asc.h"
+
+#define NEGORZRO 1
+#define MVX_ZRO 48
+#define MVX_EXP 32
+#define MVX_NEG 255
+#define GTM_PREC 15
+
+#define MVX_BLK_SIZE 2048
+#define M11_BLK_SIZE 1024
+
+GBLREF bool mupip_error_occurred;
+GBLREF bool mupip_DB_full;
+GBLREF bool mu_ctrly_occurred;
+GBLREF bool mu_ctrlc_occurred;
+GBLREF gd_addr *gd_header;
+
+GBLREF gv_key *gv_currkey;
+GBLREF spdesc stringpool;
+
+#define US 0
+#define THEM 1
+#define GOQ_MAX_KSIZ 512
+#define LCL_BUF_SIZE 256
+
+error_def(ERR_BLKCNT);
+error_def(ERR_CORRUPT);
+error_def(ERR_GOQPREC);
+error_def(ERR_LOADABORT);
+error_def(ERR_LOADCTRLY);
+
+void goq_mvx_load(struct FAB *infab, char *in_buff, uint4 rec_count, uint4 end)
+{
+ uint4 max_data_len, max_subsc_len, key_count, global_key_count;
+ int status;
+
+ static readonly unsigned char goq_gbl_blk_hdr[] = { 0, 1, 32, 0, 0 };
+ msgtype msg;
+ char exp, k_buff[LCL_BUF_SIZE];
+ unsigned char *cp1, *cp2, *cp3, *dp1, *b, *btop;
+ bool mupip_precision_error, is_dec, is_end;
+ unsigned int len, n, order;
+ unsigned short goq_blk_size;
+ short iosb[4];
+ struct {
+ unsigned char cmpc; /* number of initial characters in common with previous key */
+ unsigned char subsc_len; /* number of characters in subsc to append to those we can
+ use from beginning of previous key */
+ unsigned char subsc[1]; /* characters (usually representing subscripts) to be appended
+ to characters we can use from beginning of previous key */
+ } *goq_rp;
+ short int *goq_blk_used;
+ gv_key *goq_currkey;
+
+ /* goq_key_sub = number of discrete items in key to convert (i.e., global name and subscripts)
+ goq_subsc_map = array of positions separating discrete items in key:
+ goq_subsc_map[*][0] = start of key (start of global name)
+ goq_subsc_map[*][1] = end of global name/start of first subscript
+ goq_subsc_map[*][n] = end of subscript n-1/start of subscript n
+ goq_subsc_map[US] [*] = position in gv_currkey->base
+ goq_subsc_map[THEM][*] = position in goq_currkey->base
+ */
+ int goq_key_sub, goq_subsc_map[2][129];
+
+ mval v, exist;
+
+ if (end > 0) is_end = TRUE;
+ else is_end = FALSE;
+
+ max_data_len = max_subsc_len = key_count = 0;
+ goq_subsc_map[0][0] = goq_subsc_map[1][0] = 0;
+
+ goq_blk_size = MVX_BLK_SIZE;
+ goq_currkey = malloc (SIZEOF(gv_key) + GOQ_MAX_KSIZ - 1);
+ goq_currkey->top = GOQ_MAX_KSIZ;
+ goq_blk_used = in_buff + goq_blk_size - SIZEOF(short int);
+ gv_currkey = malloc (SIZEOF(gv_key) + GOQ_MAX_KSIZ - 1 + MAX_GVKEY_PADDING_LEN);
+ gv_currkey->top = GOQ_MAX_KSIZ;
+
+ lib$establish(mupip_load_ch);
+
+ for (; !mupip_DB_full ;)
+ {
+ mupip_precision_error = FALSE;
+ mupip_error_occurred = FALSE;
+ if (mu_ctrly_occurred)
+ { break;
+ }
+ if (mu_ctrlc_occurred)
+ {
+ mu_load_stat(max_data_len, max_subsc_len, key_count, rec_count, ERR_BLKCNT);
+ mu_gvis();
+ util_out_print(0,TRUE);
+ }
+ /* reset the stringpool for every record in order to avoid garbage collection */
+ stringpool.free = stringpool.base;
+ if (is_end && (rec_count > end))
+ break;
+ len = 0;
+ /*****************************************************************************************/
+ while (len == 0)
+ {
+ status = sys$qio(efn_bg_qio_read, infab->fab$l_stv ,IO$_READVBLK , &iosb[0],
+ 0,0,in_buff,goq_blk_size,
+ (rec_count * goq_blk_size / 512) + 1,0,0,0);
+
+ if (status != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+
+ sys$synch(efn_bg_qio_read, &iosb[0]);
+ if (iosb[0] == SS$_ENDOFFILE)
+ break;
+
+ if (iosb[0] != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) iosb[0]);
+ rec_count++;
+ len = *goq_blk_used;
+ }
+ /*****************************************************************************************/
+ if ((is_end && rec_count > end) || iosb[0] == SS$_ENDOFFILE)
+ break;
+ if (len >= goq_blk_size)
+ { rts_error(VARLSTCNT(4) ERR_CORRUPT,2,rec_count,0);
+ continue;
+ }
+ goq_rp = in_buff;
+ if (!memcmp(goq_rp,&goq_gbl_blk_hdr,SIZEOF(goq_gbl_blk_hdr)))
+ (char *) goq_rp += SIZEOF(goq_gbl_blk_hdr);
+
+ btop = in_buff + len;
+ global_key_count = 1;
+ goq_key_sub = 0;
+
+ cp1 = &goq_rp->subsc[0];
+ cp2 = &goq_rp->subsc[0] + goq_rp->subsc_len;
+ cp3 = &goq_currkey->base[0];
+ v.str.addr = cp1;
+
+ while (cp1 < cp2 && *cp1)
+ {
+ *cp3++ = *cp1++;
+ }
+ v.str.len = cp1 - (unsigned char *) v.str.addr;
+ if (cp1 < cp2 && !*cp1)
+ { *cp3++ = *cp1++;
+ }
+
+ if (goq_rp->cmpc != 0 || v.str.len > goq_currkey->top)
+ {
+ rts_error(VARLSTCNT(4) ERR_CORRUPT,2,rec_count,global_key_count);
+ continue;
+ }
+ GV_BIND_NAME_AND_ROOT_SEARCH (gd_header, &v.str);
+ if (mupip_error_occurred)
+ {
+ rts_error(VARLSTCNT(4) ERR_CORRUPT,2,rec_count,global_key_count);
+ mu_gvis();
+ util_out_print(0,TRUE);
+ continue;
+ }
+ goq_key_sub++;
+ goq_subsc_map [US][goq_key_sub] = gv_currkey->end;
+ goq_subsc_map [THEM][goq_key_sub] = goq_currkey->end = cp1 - (unsigned char *) v.str.addr;
+
+ while (cp1 < cp2)
+ {
+ *cp3++ = *cp1++;
+ }
+ cp3 = &goq_currkey->base[0];
+ cp1 = cp3 + goq_currkey->end;
+ cp2 = cp3 + goq_rp->subsc_len;
+ for (;; )
+ {
+ dp1 = &goq_rp->subsc[ goq_rp->subsc_len ];
+ n = *((unsigned short int *) dp1);
+
+ if (n == 65535)
+ n = 6;
+ else if (n > 32767)
+ n = 10;
+ else n += SIZEOF(short int);
+
+ n += goq_rp->subsc_len + 2 * SIZEOF(char);
+ if ((unsigned char *) goq_rp + n > btop)
+ {
+ rts_error(VARLSTCNT(4) ERR_CORRUPT,2,rec_count,global_key_count);
+ mu_gvis();
+ util_out_print(0,TRUE);
+ break;
+ }
+ while (cp1 < cp2)
+ {
+ if (*cp1 == NEGORZRO)
+ {
+ cp1++;
+ exp = *cp1++;
+ if (exp < MVX_EXP)
+ {
+ v.mvtype = MV_STR;
+ b = v.str.addr = &k_buff;
+ *b++ = '-';
+ *b++ = '.';
+ exp = -exp; /* get exponent's two's complement */
+ exp -= 224; /* for first 5 bits. */
+ exp -= 1;
+ assert (exp <= 31);
+
+ while (*cp1 != MVX_NEG && cp1 < cp2 && !mupip_error_occurred)
+ {
+ switch (*cp1++)
+ {
+ case '0': *b++ = '9';
+ break;
+ case '1': *b++ = '8';
+ break;
+ case '2': *b++ = '7';
+ break;
+ case '3': *b++ = '6';
+ break;
+ case '4': *b++ = '5';
+ break;
+ case '5': *b++ = '4';
+ break;
+ case '6': *b++ = '3';
+ break;
+ case '7': *b++ = '2';
+ break;
+ case '8': *b++ = '1';
+ break;
+ case '9': *b++ = '0';
+ break;
+ default:
+ rts_error(VARLSTCNT(4) ERR_CORRUPT,2,rec_count,
+ global_key_count);
+ mu_gvis();
+ util_out_print(0,TRUE);
+ }
+ }
+ if (!mupip_error_occurred)
+ {
+ if (cp1 >= cp2)
+ { rts_error(VARLSTCNT(4) ERR_CORRUPT,2,rec_count,global_key_count);
+ mu_gvis();
+ util_out_print(0,TRUE);
+ break;
+ }
+ else if (*cp1++ == MVX_NEG)
+ {
+ if (cp1 < cp2)
+ {
+ if (*cp1)
+ { rts_error(VARLSTCNT(4) ERR_CORRUPT,2,rec_count,
+ global_key_count);
+ mu_gvis();
+ util_out_print(0,TRUE);
+ break;
+ }
+ else
+ { cp1++;
+ }
+ }
+ }
+ else
+ { rts_error(VARLSTCNT(4) ERR_CORRUPT,2,rec_count,global_key_count);
+ mu_gvis();
+ util_out_print(0,TRUE);
+ break;
+ }
+ if (b - (unsigned char *) v.str.addr > GTM_PREC + 2)
+ {
+ mupip_precision_error = TRUE;
+ }
+ *b++ = 'E';
+ if (order = exp/10)
+ *b++ = order + 48;
+ *b++ = exp - order*10 + 48;
+ v.str.len = b - (unsigned char *) v.str.addr;
+ s2n(&v);
+ if (mupip_error_occurred)
+ { rts_error(VARLSTCNT(4) ERR_CORRUPT,2,rec_count,global_key_count);
+ mu_gvis();
+ util_out_print(0,TRUE);
+ break;
+ }
+ }
+ }
+ else if (exp == MVX_ZRO)
+ {
+ MV_FORCE_MVAL(&v,0) ;
+ if (cp1 < cp2)
+ {
+ if (!*cp1)
+ { cp1++;
+ }
+ else
+ { rts_error(VARLSTCNT(4) ERR_CORRUPT,2,rec_count,global_key_count);
+ mu_gvis();
+ util_out_print(0,TRUE);
+ break;
+ }
+ }
+ }
+ else
+ { rts_error(VARLSTCNT(4) ERR_CORRUPT,2,rec_count,global_key_count);
+ mu_gvis();
+ util_out_print(0,TRUE);
+ break;
+ }
+ }
+ else if (*cp1 > NEGORZRO && *cp1 < MVX_EXP)
+ {
+ cp1++;
+ is_dec = 0;
+ v.mvtype = MV_STR;
+ v.str.addr = cp1;
+ while (cp1 < cp2 && *cp1)
+ {
+ if (*cp1 == '.')
+ is_dec = 1;
+ cp1++;
+ }
+ v.str.len = cp1 - (unsigned char *) v.str.addr;
+ if (cp1 < cp2)
+ {
+ if (!*cp1)
+ { cp1++;
+ }
+ else
+ { rts_error(VARLSTCNT(4) ERR_CORRUPT,2,rec_count,global_key_count);
+ mu_gvis();
+ util_out_print(0,TRUE);
+ break;
+ }
+ }
+ if (v.str.len > GTM_PREC + is_dec)
+ {
+ mupip_precision_error = TRUE;
+ }
+ s2n(&v);
+ if (mupip_error_occurred)
+ { rts_error(VARLSTCNT(4) ERR_CORRUPT,2,rec_count,global_key_count);
+ mu_gvis();
+ util_out_print(0,TRUE);
+ break;
+ }
+ }
+ else
+ {
+ v.mvtype = MV_STR;
+ v.str.addr = cp1;
+ while (cp1 < cp2 && *cp1)
+ {
+ cp1++;
+ }
+ v.str.len = cp1 - (unsigned char *) v.str.addr;
+ if (cp1 < cp2)
+ {
+ if (!*cp1)
+ { cp1++;
+ }
+ else
+ { rts_error(VARLSTCNT(4) ERR_CORRUPT,2,rec_count,global_key_count);
+ mu_gvis();
+ util_out_print(0,TRUE);
+ break;
+ }
+ }
+ }
+ mval2subsc(&v,gv_currkey);
+ gv_currkey->prev = 0;
+ if (mupip_error_occurred)
+ {
+ rts_error(VARLSTCNT(4) ERR_CORRUPT,2,rec_count,global_key_count);
+ mu_gvis();
+ util_out_print(0,TRUE);
+ break;
+ }
+ goq_key_sub++;
+ goq_subsc_map[US][goq_key_sub] = gv_currkey->end;
+ goq_subsc_map[THEM][goq_key_sub] = goq_currkey->end = cp1 - cp3;
+ }
+
+ if (mupip_error_occurred)
+ break;
+
+ if (*((unsigned short int *) dp1) > 32767)
+ {
+ cp2 = dp1 + SIZEOF(short int);
+ if (*((unsigned short int *) dp1) == 65535)
+ {
+ MV_FORCE_MVAL(&v,*((int4 *) cp2)) ;
+ }
+ else
+ {
+ v.mvtype = MV_STR;
+ v.str.addr = &k_buff;
+ exp = *dp1;
+ status = quad2asc(cp2,exp,&k_buff,SIZEOF(k_buff),&v.str.len);
+ if (mupip_error_occurred)
+ break;
+ }
+ }
+ else
+ {
+ v.mvtype = MV_STR;
+ v.str.len = *((short int *) dp1)++;
+ v.str.addr = dp1;
+ }
+ if (mupip_precision_error)
+ {
+ op_gvdata(&exist);
+ if (exist.m[1] != 0)
+ {
+ msg.arg_cnt = 4;
+ msg.new_opts = msg.def_opts = 1;
+ msg.msg_number = ERR_GOQPREC;
+ msg.fp_cnt = 2;
+ msg.fp[0].n = rec_count;
+ msg.fp[1].n = global_key_count;
+ sys$putmsg(&msg,0,0,0);
+ mu_gvis();
+ util_out_print(0,TRUE);
+ }
+ else
+ op_gvput(&v);
+ mupip_precision_error = FALSE;
+ }
+ else
+ op_gvput (&v);
+ if (mupip_error_occurred)
+ {
+ if (!mupip_DB_full)
+ {
+ rts_error(VARLSTCNT(4) ERR_CORRUPT,2,rec_count,global_key_count);
+ util_out_print(0,TRUE);
+ }
+ break;
+ }
+ if (max_data_len < v.str.len)
+ max_data_len = v.str.len;
+ if (max_subsc_len < (gv_currkey->end + 1))
+ max_subsc_len = gv_currkey->end + 1;
+ key_count++;
+
+ (char *) goq_rp += n;
+ if (goq_rp < btop)
+ {
+ if (goq_rp->cmpc > goq_currkey->end)
+ {
+ rts_error(VARLSTCNT(4) ERR_CORRUPT,2,rec_count,global_key_count);
+ break;
+ }
+ cp1 = &goq_rp->subsc[0];
+ cp2 = &goq_currkey->base[0] + goq_rp->cmpc;
+ for ( n = 0; n < goq_rp->subsc_len; n++)
+ *cp2++ = *cp1++;
+ n = goq_key_sub;
+ for (; goq_subsc_map[THEM][n] > goq_rp->cmpc; n--)
+ ;
+ if (n == goq_key_sub && goq_subsc_map[THEM][n] == goq_rp->cmpc)
+ {
+ if (!goq_currkey->base[ goq_subsc_map[THEM][goq_key_sub] ])
+ goq_subsc_map[THEM][goq_key_sub]++;
+ else
+ n--;
+ }
+ goq_key_sub = n;
+ cp1 = cp3 + goq_subsc_map[THEM][goq_key_sub];
+ gv_currkey->end = goq_subsc_map[US][goq_key_sub];
+ global_key_count++;
+ }
+ else
+ break;
+ }
+ }
+
+ if (mu_ctrly_occurred)
+ lib$signal(ERR_LOADCTRLY);
+
+ if (mupip_error_occurred)
+ lib$signal(ERR_LOADABORT,1,rec_count);
+ else
+ mu_load_stat(max_data_len, max_subsc_len, key_count, rec_count, ERR_BLKCNT);
+
+ free (goq_currkey);
+ free (gv_currkey);
+}
diff --git a/sr_vvms/grab_crit.c b/sr_vvms/grab_crit.c
new file mode 100644
index 0000000..480a57e
--- /dev/null
+++ b/sr_vvms/grab_crit.c
@@ -0,0 +1,111 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <signal.h> /* for VSIG_ATOMIC_T type */
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "ccp.h"
+#include "ccpact.h"
+#include "error.h"
+#include "filestruct.h"
+#include "wcs_recover.h"
+
+GBLREF short crash_count;
+GBLREF volatile int4 crit_count;
+GBLREF int4 exi_condition;
+GBLREF uint4 process_id;
+GBLREF sgmnt_addrs *vms_mutex_check_csa;
+
+error_def(ERR_CRITRESET);
+error_def(ERR_DBCCERR);
+
+void grab_crit(gd_region *reg)
+{
+ unsigned short cycle_count, cycle;
+ ccp_action_aux_value msg;
+ sgmnt_addrs *csa;
+ sgmnt_data_ptr_t csd;
+ node_local_ptr_t cnl;
+ enum cdb_sc status;
+
+ csa = &FILE_INFO(reg)->s_addrs;
+ csd = csa->hdr;
+ cnl = csa->nl;
+
+ vms_mutex_check_csa = csa;
+ assert(!lib$ast_in_prog());
+ if (!csa->now_crit)
+ {
+ assert(0 == crit_count);
+ crit_count++;
+ if (csd->clustered)
+ {
+ /* For an explanation of the code dealing with clusters, see CCP_EXITWM_ATTEMPT.C.
+ Please do not change this code without updating the comments in that file. */
+ cycle = cnl->ccp_cycle;
+ while (!CCP_SEGMENT_STATE(cnl, CCST_MASK_WRITE_MODE))
+ {
+ (void)ccp_sendmsg(CCTR_WRITEDB, &FILE_INFO(reg)->file_id);
+ (void)ccp_userwait(reg, CCST_MASK_WRITE_MODE, 0, cycle);
+ cycle = cnl->ccp_cycle;
+ }
+ }
+
+ if (cdb_sc_normal !=
+ (status = MUTEX_LOCKW(csa->critical, crash_count, &csa->now_crit, &csd->mutex_spin_parms)))
+ {
+ crit_count = 0;
+ switch (status)
+ {
+ case cdb_sc_critreset:
+ rts_error_csa(CSA_ARG(NULL) ERR_CRITRESET, 2, REG_LEN_STR(reg));
+ case cdb_sc_dbccerr:
+ rts_error_csa(CSA_ARG(NULL) ERR_DBCCERR, 2, REG_LEN_STR(reg));
+ default:
+ GTMASSERT;
+ }
+ return;
+ }
+
+ assert(cnl->in_crit == 0);
+ cnl->in_crit = process_id;
+
+ CRIT_TRACE(crit_ops_gw); /* see gdsbt.h for comment on placement */
+
+ if (csd->clustered)
+ {
+ cycle = cnl->ccp_cycle;
+ if (cnl->ccp_crit_blocked)
+ {
+ msg.exreq.fid = FILE_INFO(reg)->file_id;
+ msg.exreq.cycle = cycle;
+ (void)ccp_sendmsg(CCTR_EXITWM, &msg);
+ (void)ccp_userwait(reg, ~(CCST_MASK_WRITE_MODE), 0, msg.exreq.cycle);
+ while (cnl->ccp_crit_blocked && cnl->ccp_cycle == msg.exreq.cycle ||
+ !CCP_SEGMENT_STATE(cnl, CCST_MASK_WRITE_MODE))
+ {
+ cycle = cnl->ccp_cycle;
+ (void)ccp_sendmsg(CCTR_WRITEDB, &FILE_INFO(reg)->file_id);
+ (void)ccp_userwait(reg, CCST_MASK_WRITE_MODE, 0, cycle);
+ }
+ }
+ }
+ crit_count = 0;
+ }
+ if (cnl->wc_blocked)
+ wcs_recover(reg);
+}
diff --git a/sr_vvms/grab_crit_immediate.c b/sr_vvms/grab_crit_immediate.c
new file mode 100644
index 0000000..4157532
--- /dev/null
+++ b/sr_vvms/grab_crit_immediate.c
@@ -0,0 +1,109 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <signal.h> /* for VSIG_ATOMIC_T type */
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "ccp.h"
+#include "ccpact.h"
+#include "error.h"
+#include "filestruct.h"
+#include "wcs_recover.h"
+
+error_def(ERR_CRITRESET);
+error_def(ERR_DBCCERR);
+
+GBLREF short crash_count;
+GBLREF volatile int4 crit_count;
+GBLREF int4 exi_condition;
+GBLREF VSIG_ATOMIC_T forced_exit;
+GBLREF uint4 process_id;
+GBLREF sgmnt_addrs *vms_mutex_check_csa;
+
+/* One try to grab crit; no waiting because of possible deadlock. Used by TP */
+
+boolean_t grab_crit_immediate(gd_region *reg)
+{
+ unsigned short cycle_count, cycle;
+ ccp_action_aux_value msg;
+ sgmnt_addrs *csa;
+ enum cdb_sc status;
+ node_local_ptr_t cnl;
+
+ csa = &FILE_INFO(reg)->s_addrs;
+ vms_mutex_check_csa = csa;
+ cnl = csa->nl;
+ if (!csa->now_crit)
+ {
+ assert(0 == crit_count);
+ crit_count++;
+ if (csa->hdr->clustered)
+ {
+ /* For an explanation of the code dealing with clusters, see CCP_EXITWM_ATTEMPT.C.
+ Please do not change this code without updating the comments in that file. */
+ cycle = cnl->ccp_cycle;
+ if (!CCP_SEGMENT_STATE(cnl, CCST_MASK_WRITE_MODE))
+ return FALSE;
+ }
+ if ((status = mutex_lockwim(csa->critical, crash_count, &csa->now_crit)) != cdb_sc_normal)
+ {
+ crit_count = 0;
+ switch (status)
+ {
+ case cdb_sc_nolock:
+ return FALSE;
+ case cdb_sc_critreset:
+ rts_error_csa(CSA_ARG(NULL) ERR_CRITRESET, 2, REG_LEN_STR(reg));
+ case cdb_sc_dbccerr:
+ rts_error_csa(CSA_ARG(NULL) ERR_DBCCERR, 2, REG_LEN_STR(reg));
+ default:
+ if (forced_exit)
+ EXIT(exi_condition);
+ GTMASSERT;
+ }
+ return FALSE;
+ }
+ assert(cnl->in_crit == 0);
+ cnl->in_crit = process_id;
+ if (csa->hdr->clustered)
+ {
+ cycle = cnl->ccp_cycle;
+ if (cnl->ccp_crit_blocked)
+ {
+ msg.exreq.fid = FILE_INFO(reg)->file_id;
+ msg.exreq.cycle = cycle;
+ (void)ccp_sendmsg(CCTR_EXITWM, &msg);
+ (void)ccp_userwait(reg, ~(CCST_MASK_WRITE_MODE), 0, cycle);
+ if (cnl->ccp_crit_blocked && (cnl->ccp_cycle == cycle) ||
+ !CCP_SEGMENT_STATE(cnl, CCST_MASK_WRITE_MODE))
+ {
+ crit_count = 0;
+ rel_crit(reg);
+ return FALSE;
+ }
+ }
+ }
+ crit_count = 0;
+ }
+ /* We can be in an AST if we are called wcs_wipchk_ast(). In that case don't do wcs_recover since it can
+ * cause deadlocks. Let the next guy obtaining crit do it. Note also the order of the statements in the
+ * if. wc_blocked is very rarely TRUE and hence is placed ahead of the lib$ast_in_prog check.
+ */
+ if (cnl->wc_blocked && !lib$ast_in_prog())
+ wcs_recover(reg);
+ return TRUE;
+}
diff --git a/sr_vvms/grab_lock.c b/sr_vvms/grab_lock.c
new file mode 100644
index 0000000..8097657
--- /dev/null
+++ b/sr_vvms/grab_lock.c
@@ -0,0 +1,67 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <signal.h> /* for VSIG_ATOMIC_T type */
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "cdb_sc.h"
+
+error_def(ERR_CRITRESET);
+error_def(ERR_DBCCERR);
+
+GBLREF volatile int4 crit_count;
+GBLREF uint4 exi_condition;
+GBLREF uint4 process_id;
+GBLREF sgmnt_addrs *vms_mutex_check_csa;
+
+boolean_t grab_lock(gd_region *reg, boolean_t dummy1, uint4 dummy2)
+{
+ enum cdb_sc status;
+ sgmnt_addrs *csa;
+
+ csa = &FILE_INFO(reg)->s_addrs;
+ vms_mutex_check_csa = csa;
+ assert(!lib$ast_in_prog());
+
+ if (!csa->now_crit)
+ {
+ assert(0 == crit_count);
+ crit_count++;
+ if (cdb_sc_normal !=
+ (status = MUTEX_LOCKW(csa->critical, 0, &csa->now_crit,
+ (mutex_spin_parms_ptr_t)((sm_uc_ptr_t)csa->critical + JNLPOOL_CRIT_SPACE))))
+ { /* mutex spin parms structure resides at csa->critical + JNLPOOL_CRIT_SPACE, see gtmsource.h for jnlpool layout */
+ crit_count = 0;
+ switch (status)
+ {
+ case cdb_sc_critreset:
+ rts_error_csa(CSA_ARG(NULL) ERR_CRITRESET, 2, REG_LEN_STR(reg));
+ case cdb_sc_dbccerr:
+ rts_error_csa(CSA_ARG(NULL) ERR_DBCCERR, 2, REG_LEN_STR(reg));
+ default:
+ GTMASSERT;
+ }
+ return TRUE;
+ }
+ assert(csa->nl->in_crit == 0);
+ csa->nl->in_crit = process_id;
+ CRIT_TRACE(crit_ops_gw); /* see gdsbt.h for comment on placement */
+ crit_count = 0;
+ }
+ return TRUE;
+}
diff --git a/sr_vvms/gse.mpt b/sr_vvms/gse.mpt
new file mode 100644
index 0000000..e6b29c4
--- /dev/null
+++ b/sr_vvms/gse.mpt
@@ -0,0 +1,77 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ;
+; Copyright 2006 Fidelity Information Services, Inc ;
+; ;
+; This source code contains the intellectual property ;
+; of its copyright holder(s), and is made available ;
+; under a license. If you do not know the terms of ;
+; the license, please stop and do not read further. ;
+; ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%GSE ;GT.M %GSE utility - global search
+ ;
+ n c,i,g,gn,gtmvt,m,n,p,rl,s,sl,sx,tics,x,%ZD,%ZG
+ i '$d(%zdebug) n $et s $et="zg "_$zl_":ERR^%GSE" u $p:(ctrap=$c(3):exc="zg "_$zl_":LOOP^%GSE")
+ w !,"Global Search for Every Occurrence",!
+ d base
+ q
+base f d q:$l(%ZD)
+ . r !,"Output device: <terminal>: ",%ZD,!
+ . i '$l(%ZD) s %ZD=$p q
+ . i %ZD="^" q
+ . i %ZD="?" d q
+ . . w !!,"Select the device you want for output"
+ . . w !,"If you wish to exit enter a carat (^)",!
+ . . s %ZD=""
+ . i $zparse(%ZD)="" w " no such device" s %ZD="" q
+ . o %ZD:(newversion:block=2048:record=2044:exception="g noopen"):0
+ . i '$t w !,%ZD," is not available" s %ZD="" q
+ . q
+noopen . w !,$p($ZS,",",2,999),! c %ZD s %ZD=""
+ q:%ZD="^"
+ i %ZD'=$p u %ZD w $zd($h,"DD-MON-YEAR 24:60:SS"),!,"Global Search for Every occurrence",! u $p
+ f d main q:'%ZG
+ c:%ZD'=$p %ZD u $p:(ctrap="":exc="")
+ q
+main k %ZG d CALL^%GSEL i '%ZG q
+ s gn=""
+ r "Find string: ",s,!!
+ i s="" w !,"No string to find - no search done.",! s %ZG=0 q
+ i s?.E1C.E w !,"The Find string contains control characters"
+ u %ZD s gtmvt=$$GTMVT
+ i gtmvt s sx=$c(27)_"[7m"_s_$c(27)_"[0m"
+ e s sx=s,sl=$l(s),tics=$tr($j("",sl)," ","^")
+ f s gn=$o(%ZG(gn)) q:gn="" d search
+ q
+search u %ZD w:$x>70 ! w gn,?$x\10+1*10
+ s g=gn,(m,n)=0
+ i ($d(@g)#10=1) s n=1 d:@g[s show
+ f s g=$q(@g) q:g="" s n=n+1 d:@g[s show
+ i m w !!,"Total ",m," matches found in ",n," nodes.",!
+ e w !,"No matches found in ",n," nodes.",!
+ u $p
+ q
+show s x=@g,c=$l(x,s),m=m+c-1,rl=$j("",16)
+ w !,g,?16 f i=1:1:c-1 s p=$tr($p(x,s,i),$c(9)," ") w p,sx i 'gtmvt s rl=rl_$j(tics,$l(p)+sl)
+ w $p(@g,s,c)
+ i 'gtmvt w !,rl
+ q
+ ;
+GTMVT() ; true if a video
+ i $zver'["VMS" n d d q +d ;if should be more precise
+ . s d=""
+ . i $i'=$p q
+ . zsh "d":d
+ . f s d=$o(d("D",d)) q:d="" i $p(d("D",d)," ")=$p s d=$p(d("D",d)," ",3) q
+ . i d["TERMINAL" s d=$tr($ztrnlnm("TERM"),"ANSIVT","ansivt") i $l(d),d["ansi"!(d["vt") s d=1
+ i @"$zgetdvi($zparse($zio,""DEVICE""),""TRM"")",@"$zgetdvi($zio,""DECCRT"")"
+ q $t
+ ;
+ERR i $d(%ZD),%ZD'=$p c %ZD
+ u $p w !,$p($zs,",",2,99),!
+ u $p:(ctrap="":exc="")
+ s $ec=""
+ q
+LOOP i $d(%ZD),%ZD'=$p c %ZD
+ d base
+ q
diff --git a/sr_vvms/gt_timer.h b/sr_vvms/gt_timer.h
new file mode 100644
index 0000000..4f0bc80
--- /dev/null
+++ b/sr_vvms/gt_timer.h
@@ -0,0 +1,72 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef __GT_TIMER_H__
+#define __GT_TIMER_H__
+
+/*
+ * -----------------------------------------------------
+ * System dependent include file for gtm timer package
+ * -----------------------------------------------------
+ */
+
+typedef int4 TID; /* Timer ID type */
+
+#define sighold(x)
+#define sigrelse(x)
+
+/*
+ * -----------------------------------------------------
+ * Gtm timer package uses ABS_TIME structure to carry
+ * the time information irrelevantly of operating system
+ * specifics. The time in this structure is stored as
+ * absolute time - elapsed time since some major historic
+ * event, or some fixed date in the past. Different
+ * operating systems have different time reference points.
+ * The time is converted from the OS time format to
+ * a format, given in this file, and from then on, all
+ * timer related calls reffer to this time.
+ * -----------------------------------------------------
+ */
+typedef struct tag_abs_time {
+ int4 at_sec; /* seconds */
+ int4 at_usec; /* and microseconds */
+} ABS_TIME;
+
+typedef long gtm_tv_usec_t;
+
+/*
+ * -----------------------------------------------------
+ * All timer request are placed into a linked list, or
+ * a queue of * pending requests in a time order.
+ * The first timer in this queue is currently the
+ * active timer, and expires first.
+ * -----------------------------------------------------
+ */
+typedef struct tag_ts {
+ TID tid; /* Timer id */
+ ABS_TIME expir_time; /* Absolute Time when timer expires */
+ void (*handler)(); /* Pointer to handler routine */
+ struct tag_ts *next; /* Pointer to next */
+} GT_TIMER;
+
+#define GT_WAKE sys$wake(0,0)
+#define hiber_start_wait_any hiber_start
+
+int4 abs_time_comp(ABS_TIME *atp1, ABS_TIME *atp2);
+void add_int_to_abs_time(ABS_TIME *atps, int4 ival, ABS_TIME *atpd);
+void cancel_timer(TID tid);
+void hiber_start(uint4 hiber);
+void start_timer(TID tid, int4 time_to_expir, void(* handler)(), int4 data_length, void *handler_data);
+ABS_TIME sub_abs_time(ABS_TIME *atp1, ABS_TIME *atp2);
+void sys_get_curr_time(ABS_TIME *atp);
+
+#endif
diff --git a/sr_vvms/gt_timers.c b/sr_vvms/gt_timers.c
new file mode 100644
index 0000000..42b4963
--- /dev/null
+++ b/sr_vvms/gt_timers.c
@@ -0,0 +1,155 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2007 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/*
+ * --------------------------------------------------------------
+ * Following routines are top level, user callable
+ * routines of this package:
+ *
+ * void sys_get_cur_time(ABS_TIME atp)
+ * fetch absolute time into stucture
+ *
+ * void hiber_start(uint4 hiber)
+ * used to sleep for hiber milliseconds
+ *
+ * void start_timer(TID tid, int4 time_to_expir, void (*handler)(), int4 dummy_hdata_len, char *dummy_hdata)
+ * Used to start a new timer.
+ *
+ * void cancel_timer(TID tid)
+ * Cancel an existing timer.
+ * Cancelling timer with tid = 0, cancells all timers.
+ * --------------------------------------------------------------
+ */
+#include "mdef.h"
+
+#include <ssdef.h>
+
+#include "efn.h"
+#include "gt_timer.h"
+#include "timedef.h"
+#include "wake.h"
+
+#define MAX_INT 4294967295.0
+
+GBLREF int process_exiting;
+
+/*
+ * ----------------------------------------------------
+ * Get current clock time in milliseconds
+ * Fill-in the structure with the absolute time
+ * of system clock.
+ *
+ * Arguments:
+ * atp - pointer to structure of absolute time
+ * ----------------------------------------------------
+ */
+void sys_get_curr_time(ABS_TIME *atp)
+{
+ uint4 status, systim[2];
+
+ status = sys$gettim(systim);
+ if (status & 1)
+ {
+ atp->at_usec = (systim[0] / 10) % 1000000;
+ atp->at_sec = (uint4)(((((double)systim[1]) * MAX_INT) + (double)systim[0]) / 10000000.0);
+ return;
+ }
+ rts_error(VARLSTCNT(1) status);
+}
+
+static void hiber_start_ast(void)
+{ /* Only purpose of this function is to provide a unique identifier for hiber_start timr driven while in an AST */
+ return;
+}
+
+/*
+ * ------------------------------------------------------
+ * Start hibernating by starting a timer using hiber_time
+ * (in msecs) and doing a pause
+ * ------------------------------------------------------
+ */
+void hiber_start(uint4 hiber)
+{
+ int4 hiber_time[2]; /* don't have static since can be interrupted by an AST */
+ int status_timr, status_wait, ast_in_prog;
+
+ if (0 == hiber)
+ return; /* in PRO code return */
+
+ hiber_time[0] = -time_low_ms((int4)hiber);
+ hiber_time[1] = -time_high_ms((int4)hiber);
+ if (hiber_time[1] == 0)
+ hiber_time[1] -= 1;
+
+ if (0 != (ast_in_prog = lib$ast_in_prog()))
+ { /* sleep sounder but less permanently;
+ * note that an AST may cause an inappropriate time to be used for another hiber_start in progress,
+ * but that risk should be statistically small, and the consequences (as far as known) are not important
+ */
+ status_timr = sys$setimr(efn_timer_ast, hiber_time, 0, hiber_start_ast, 0);
+ assert(SS$_NORMAL == status_timr);
+ if (SS$_NORMAL == status_timr)
+ {
+ status_wait = sys$waitfr(efn_timer_ast);
+ assert(SS$_NORMAL == status_wait);
+ }
+ } else
+ { /* timr->hiber should not be changed to timr->waitfr. The former waits for a wakeup or outofband event; whichever
+ * happens sooner will stop the hiber while the latter does not recognize outofband events (like tp timeouts)
+ */
+ status_timr = sys$setimr(efn_hiber_start, hiber_time, wake, hiber_start, 0);
+ assert(SS$_NORMAL == status_timr);
+ if (SS$_NORMAL == status_timr)
+ {
+ sys$hiber();
+ sys$cantim(hiber_start, 0);
+ }
+ }
+}
+
+/*
+ * ----------------------------------------------------
+ * System call to set timer.
+ * Time is given im msecs.
+ *
+ * Arguments:
+ * tid - timer id
+ * time_to_expir - time to expiration.
+ * handler - address of handler routine
+ * ----------------------------------------------------
+ */
+void start_timer(TID tid, int4 time_to_expir, void (*handler)(), int4 dummy_hdata_len, void *dummy_hdata)
+{
+ int4 time[2];
+ int status;
+
+ time[1] = -time_high_ms(time_to_expir) - 1;
+ time[0] = -time_low_ms(time_to_expir);
+ status = sys$setimr(efn_timer, time, handler, tid, 0);
+ assert(SS$_NORMAL == status);
+}
+
+
+/*
+ * ---------------------------------------------
+ * System call to cancel timer.
+ * ---------------------------------------------
+ */
+void cancel_timer(TID tid)
+{
+ /* An interrupt should never cancel a timer that has been started in the mainline code.
+ * Or else it is possible the mainline code might hibernate for ever.
+ * In VMS, interrupt is equivalent to being in an AST. Hence assert we are never in an AST if we are here.
+ * The only exception is if we are exiting in which case we are not going to be hibernating so it is ok.
+ */
+ assert(!lib$ast_in_prog() || process_exiting);
+ sys$cantim(tid, 0);
+}
diff --git a/sr_vvms/gtcm_spkitbld.dat b/sr_vvms/gtcm_spkitbld.dat
new file mode 100644
index 0000000..02b5451
--- /dev/null
+++ b/sr_vvms/gtcm_spkitbld.dat
@@ -0,0 +1,6 @@
+SPKITBLD$KITNAME := GTCM60002
+SPKITBLD$REWIND_TAPE := N
+SPKITBLD$AUTOINIT_TAPE := 'GTM_INIT_TAPE'
+SPKITBLD$SKIP_FIRST_TAPE_READY_PROMPT := Y
+SPKITBLD$SKIP_FIRST_DISK_READY_PROMPT := Y
+SPKITBLD$SAVESET_A := GTM$VRT:[TCM]KITINSTAL.COM;,GTCMKITHLP.COM;,GTM$VRT:[PRO]GTCM_SERVER.EXE;,GTCM_STOP.EXE;,CMISHR.EXE;
diff --git a/sr_vvms/gtcmkithlp.com b/sr_vvms/gtcmkithlp.com
new file mode 100644
index 0000000..66db9ab
--- /dev/null
+++ b/sr_vvms/gtcmkithlp.com
@@ -0,0 +1,146 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2003 Sanchez Computer Associates, Inc. !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$!
+$! HELP TEXT PROCESSING FOR GT.CM KITINSTAL.COM
+$! COPYRIGHT 1989 - 2000 Sanchez Computer Associates
+$ IF F$EXTRACT(0,5,P1) .EQS. "HELP_" THEN GOTO 'P1'
+$ EXIT VMI$_UNSUPPORTED
+$HELP_PURGE:
+$ TYPE SYS$INPUT
+ If GT.CM is previously installed, there is no reason to keep older versions
+ of the software online, unless you wish to test before purging.
+
+$ EXIT
+$HELP_NDB_CNT:
+$ TYPE SYS$INPUT
+ The installation inserts this value as the default for controlling the
+ GT.CM Server quotas established in GTCMSERVER.COM. If you provide a value
+ less than 1, the value will be set to 1. This value can be easily changed
+ later.
+
+$ EXIT
+$HELP_RC_CNT:
+$ TYPE SYS$INPUT
+ The installation inserts this value as the default for controlling the
+ GT.CM Server quotas established in GTCMSERVER.COM. If you provide a value
+ less than 1, the value will be set to 1. This value can be easily changed
+ later.
+
+$ EXIT
+$HELP_SRV_UIC:
+$ TYPE SYS$INPUT
+ The GT.CM Server usually must have broad file access so running under the
+ SYSTEM UIC may make sense. The recommended alternative is to use a
+ distinguished UIC which has appropriate UIC or ACL based access to clustered
+ files.
+
+$ EXIT
+$HELP_STD_CNF:
+$ TYPE SYS$INPUT
+ The standard configuration performs the following:
+
+ * Places files in SYS$COMMON:[GTM_DIST] with SYSTEM as owner
+ * Copies the GT.CM command procedures, except GTCMAUTOSRV, to SYS$MANAGER
+ * Adds GTCMSTART.COM to the system startup database
+ * Sets up GTCMSTART.COM to start the GT.CM Server
+ * Enables auto-start and disables auto-stop of the GT.CM Server
+ * Starts GT.CM at the end of the installation
+
+ If the SYSTEM id is not set up, the installation will use [1,4].
+
+$ EXIT
+$HELP_DST_OWN:
+$ TYPE SYS$INPUT
+ Provide a UIC, normally SYSTEM, to own the files in the GT.M distribution.
+ The UIC can be a name, a group name and a user name separated by a comma,
+ or a pair of octal codes separated by a comma which specify group and user.
+
+$ EXIT
+$HELP_SYS_DST:
+$ TYPE SYS$INPUT
+ Usual practice is to place a system component such as GT.CM on the system
+ disk. If you have severe space constraints, you may need to use another
+ volume.
+
+$ EXIT
+$HELP_SYS_DIR:
+$ TYPE SYS$INPUT
+ This directory becomes be a sub-directory of SYS$COMMON and holds the
+ distribution. If it does not exist, the installation creates it with
+ WORLD=RE access. If you are not concerned with mixing software from
+ different vendors, you may wish to use SYSLIB.
+
+$ EXIT
+$HELP_DST_DEV:
+$ TYPE SYS$INPUT
+ The disk must be mounted, on-line and have adequate space to hold the GT.CM
+ distribution. The disk name may be physical or logical.
+
+$ EXIT
+$HELP_DST_DIR:
+$ TYPE SYS$INPUT
+ This directory holds the distribution. If it does not exist, the
+ installation creates it with WORLD=RE access.
+
+$ EXIT
+$HELP_STD_SRV:
+$ TYPE SYS$INPUT
+ Answering Yes causes the installation make GTCMSTART.COM so it starts a
+ GT.CM Server. Having the GT.CM Server running at all times makes for more
+ uniform response to network database access. However, if network access is
+ sporadic the Server may spend much time as an idle task.
+
+$ EXIT
+$HELP_AUTO_SRV:
+ Answering Yes causes an incoming network request to start a GT.CM Server if
+ none is currently running. When combined with the standard start this
+ provides resiliency for network operations.
+
+$ TYPE SYS$INPUT
+$ EXIT
+$HELP_TIMEOUT:
+ The timeout specifies the number of minutes an auto-started GT.CM Server
+ waits between incoming database access requests before shutting itself down.
+ A value of 0 inhibits auto-stops.
+
+$ TYPE SYS$INPUT
+$ EXIT
+$HELP_STARTDB:
+$ TYPE SYS$INPUT
+ Answering yes causes the installation to place GTCMSTART.COM in the startup
+ database so the system startup automatically sets up the GT.CM environment
+ whenever the system boots.
+
+$ EXIT
+$HELP_MGR_COM:
+$ TYPE SYS$INPUT
+ You may prevent the installation from moving the .COM files to SYS$MANAGER.
+ Copying the command procedures to SYS$MANAGER allows system startup to
+ access them through the VMS startup database and generally simplifies
+ operations. However, if you wish to have multiple versions of GT.M on your
+ system at the same time, you would not have multiple copies of the command
+ procedures in SYS$MANAGER.
+
+$ EXIT
+$HELP_RUN_IVP:
+$ TYPE SYS$INPUT
+ This installation kit contains an installation verification procedure (IVP)
+ which you can run as part of the installation to verify the correctness of
+ the software. Note that if you choose this option, the GT.M images must
+ already be installed before or during this installation.
+
+$ EXIT
+$HELP_START_CM:
+$ TYPE SYS$INPUT
+ Answering yes causes the installation to start GT.CM.
+
+$ EXIT
diff --git a/sr_vvms/gtcmkitinstal.com b/sr_vvms/gtcmkitinstal.com
new file mode 100644
index 0000000..cc425d8
--- /dev/null
+++ b/sr_vvms/gtcmkitinstal.com
@@ -0,0 +1,363 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2003 Sanchez Computer Associates, Inc. !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$!
+$! KITINSTAL.COM PROCEDURE FOR THE GT.CM PRODUCT
+$!
+$ ON CONTROL_Y THEN VMI$CALLBACK CONTROL_Y
+$! ON WARNING THEN EXIT $STATUS !! allow warning on install replace
+$ IF P1 .EQS. "VMI$_INSTALL" THEN GOTO INSTALL
+$ IF P1 .EQS. "VMI$_POSTINSTALL" THEN GOTO POSTINSTALL
+$ IF P1 .EQS. "VMI$_IVP" THEN GOTO IVP
+$ EXIT VMI$_UNSUPPORTED
+$!
+$INSTALL:
+$ TYPE SYS$INPUT
+
+ GT.CM (c) COPYRIGHT 1988, 2000 by Sanchez Computer Associates, Inc.
+ ALL RIGHTS RESERVED
+
+$! the following 2 lines must be maintained
+$ GTCM$VMS_VERSION :== 072 ! Minimum VMS version required
+$ GTCM$DISK_SPACE == 2000 ! Minumum disk space on system disk required for install (2x result)
+$ IF F$ELEMENT(0,",",VMI$VMS_VERSION) .EQS. "RELEASED"
+$ THEN
+$ GTCM$VMS_IS == F$ELEMENT(1,",",VMI$VMS_VERSION)
+$ IF GTCM$VMS_IS .LTS. GTCM$VMS_VERSION
+$ THEN
+$ VMI$CALLBACK MESSAGE E VMSMISMATCH "This GT.CM kit requires an existing VMS''GTCM$VMS_VERSION' system."
+$ EXIT VMI$_FAILURE
+$ ENDIF
+$ ELSE
+$ GTCM$VMS_IS :==
+$ WRITE SYS$OUTPUT " No VMS version checking performed for field test versions."
+$ ENDIF
+$ IF (GTCM$VMS_IS .GES. "052") THEN T1 = F$VERIFY(VMI$KIT_DEBUG)
+$ VMI$CALLBACK CHECK_NET_UTILIZATION GTCM$ROOM 'GTCM$DISK_SPACE'
+$ IF .NOT. GTCM$ROOM
+$ THEN
+$ VMI$CALLBACK MESSAGE E NOSPACE "There is not enough disk space -- GT.CM needs ''GTCM$DISK_SPACE' blocks."
+$ EXIT VMI$_FAILURE
+$ ENDIF
+$! setup default answers
+$ GTCM$DOPURGE :== YES
+$ GTCM$RUN_IVP == 0 !! should be "YES", but no IVP yet
+$ GTCM$NDB_CNT == 12
+$ GTCM$RC_CNT == 30
+$ GTCM$STD_CNF :== YES
+$ GTCM$DST_OWN :== SYSTEM
+$ IF F$IDENTIFIER(GTCM$DST_OWN,"NAME_TO_NUMBER") .EQ. 0 THEN GTCM$DST_OWN :== 1,4
+$ GTCM$SRV_UIC :==
+$ GTCM$SYS_DST :== YES
+$ GTCM$DST_DIR :== GTM_DIST
+$ GTCM$DST_CRE == GTCM$DST_DIR
+$ GTCM$DST_DEV :==
+$ GTCM$STD_SRV :== YES
+$ GTCM$AUTO_SRV :== YES
+$ GTCM$TIMEOUT == 0
+$ GTCM$STARTDB :== YES
+$ GTCM$MGR_COM :== YES
+$ GTCM$START_SRV :== YES
+$!
+$ VMI$CALLBACK ASK GTCM$DOPURGE "Do you want to purge files replaced by this installation" 'GTCM$DOPURGE' B -
+ "@VMI$KWD:GTCMKITHLP HELP_PURGE"
+$ IF .NOT. GTCM$DOPURGE THEN VMI$CALLBACK SET PURGE NO
+$ VMI$CALLBACK ASK GTCM$NDB_CNT "How many networked databases will this node serve" 'GTCM$NDB_CNT' I -
+ "@VMI$KWD:GTCMKITHLP HELP_NDB_CNT"
+$ IF GTCM$NDB_CNT .LT. 1
+$ THEN
+$ GTCM$NDB_CNT == 1
+$ WRITE SYS$OUTPUT " The installation set this value to 1 as 0 or negative values are not useful."
+$ ENDIF
+$ VMI$CALLBACK ASK GTCM$RC_CNT "How many client links will this node serve" 'GTCM$RC_CNT' I -
+ "@VMI$KWD:GTCMKITHLP HELP_RC_CNT"
+$ IF GTCM$RC_CNT .LT. 1
+$ THEN
+$ GTCM$RC_CNT == 1
+$ WRITE SYS$OUTPUT " The installation set this value to 1 as 0 or negative values are not useful."
+$ ENDIF
+$ VMI$CALLBACK ASK GTCM$SRV_UIC "Under what UIC should the Server operate" "''GTCM$SRV_UIC'" S -
+ "@VMI$KWD:GTCMKITHLP HELP_SRV_UIC"
+$ GTCM$SRV_UIC == GTCM$SRV_UIC - "[" - "]"
+$ IF GTCM$SRV_UIC - "," .NES. GTCM$SRV_UIC THEN GTCM$SRV_UIC :== ['GTCM$SRV_UIC']
+$ VMI$CALLBACK ASK GTCM$STD_CNF "Do you want the standard GT.CM configuration" 'GTCM$STD_CNF' B -
+ "@VMI$KWD:GTCMKITHLP HELP_STD_CNF"
+$ IF GTCM$STD_CNF
+$ THEN
+$ GTCM$SYS_DST == 1
+$ GTCM$STD_SRV :== 1
+$ GTCM$AUTO_SRV :== 1
+$ GTCM$STARTDB == 1
+$ GTCM$MGR_COM == 1
+$ GTCM$START_CM == 1
+$ GTCM$DST_LOG :== SYS$COMMON:['GTCM$DST_DIR']
+$ GTCM$DIR_TYPE :== COMMON
+$ GTCM$RUN_IVP == 0 !! no IVP yet
+$ ELSE ! not standard configuration
+$ VMI$CALLBACK ASK GTCM$DST_OWN "What UIC should own the GT.CM distribution" 'GTCM$DST_OWN' S "@VMI$KWD:GTCMKITHLP HELP_DST_OWN"
+$ GTCM$DST_OWN == GTCM$DST_OWN - "[" - "]"
+$ VMI$CALLBACK ASK GTCM$SYS_DST "Do you want the GT.CM distribution to go into a System Directory" 'GTCM$SYS_DST' B -
+ "@VMI$KWD:GTCMKITHLP HELP_SYS_DST"
+$ IF GTCM$SYS_DST
+$ THEN
+$ VMI$CALLBACK ASK GTCM$DST_DIR "In what System Directory do you want to place GT.CM" 'GTCM$DST_DIR' S -
+ "@VMI$KWD:GTCMKITHLP HELP_SYS_DIR"
+$ GTCM$DST_DIR == GTCM$DST_DIR - "[" - "]"
+$ GTCM$DST_CRE == GTCM$DST_DIR
+$ GTCM$DST_LOG :== SYS$COMMON:['GTCM$DST_DIR']
+$ GTCM$DIR_TYPE :== COMMON
+$ ELSE ! not system disk
+$ VMI$CALLBACK ASK GTCM$DST_DEV "On which device do you want to place GT.CM" "''GTCM$DST_DEV'" S -
+ "@VMI$KWD:GTCMKITHLP HELP_DST_DEV"
+$ VMI$CALLBACK ASK GTCM$DST_DIR "In what directory on that device do you want to place GT.CM" 'GTCM$DST_DIR' S -
+ "@VMI$KWD:GTCMKITHLP HELP_DST_DIR"
+$ GTCM$DST_DEV == GTCM$DST_DEV - ":"
+$ GTCM$DST_DIR == GTCM$DST_DIR - "[" - "]"
+$ GTCM$DST_LOG :== 'GTCM$DST_DEV':['GTCM$DST_DIR']
+$ GTCM$DST_CRE == GTCM$DST_LOG
+$ GTCM$DIR_TYPE :== USER
+$ ENDIF ! system disk
+$ VMI$CALLBACK ASK GTCM$STD_SRV "Do you want GTCMSTART.COM to start the GT.CM Server" 'GTCM$STD_SRV' S -
+ "@VMI$KWD:GTCMKITHLP HELP_STD_SRV"
+$ VMI$CALLBACK ASK GTCM$AUTO_SRV "Do you want network requests to automatically start the GT.CM server" 'GTCM$AUTO_SRV S -
+ "@VMI$KWD:GTCMKITHLP HELP_AUTO_SRV"
+$ IF GTCM$AUTO_SRV
+$ THEN
+$ VMI$CALLBACK ASK GTCM$TIMEOUT "How many quiet minutes before the server terminates (0=>never)" 'GTCM$TIMEOUT' I -
+ "@VMI$KWD:GTCMKITHLP HELP_TIMEOUT"
+$ IF GTCM$TIMEOUT .LT. 0
+$ THEN
+$ GTCM$TIMEOUT == 0
+$ WRITE SYS$OUTPUT " The installation set this value to 0 as negative values are not useful."
+$ ENDIF
+$ ENDIF
+$ VMI$CALLBACK ASK GTCM$STARTDB "Do you want GTCMSTART.COM in the startup database" 'GTCM$STARTDB' B -
+ "@VMI$KWD:GTCMKITHLP HELP_STARTDB"
+$ IF .NOT. GTCM$STARTDB
+$ THEN
+$ VMI$CALLBACK ASK GTCM$MGR_COM "Do you want the GT.M .COM files in SYS$MANAGER" 'GTCM$MGR_COM' B -
+ "@VMI$KWD:GTCMKITHLP HELP_MGR_COM"
+$ ENDIF
+$!! no IVP yet
+$ IF 0 THEN VMI$CALLBACK ASK GTCM$RUN_IVP "Do you want to run the IVP (requires GT.M)" 'GTCM$RUN_IVP' B -
+ "@VMI$KWD:GTCMKITHLP HELP_RUN_IVP"
+$ IF GTCM$RUN_IVP
+$ THEN
+$ GTCM$START_CCP == 1
+$ ELSE
+$ VMI$CALLBACK ASK GTCM$START_CM "Do you want to start GT.CM now" 'GTCM$START_SRV' B "@VMI$KWD:GTCMKITHLP HELP_START_CM"
+$ ENDIF
+$ ENDIF ! standard configuration
+$ IF GTCM$MGR_COM
+$ THEN
+$ WRITE SYS$OUTPUT " The following command files are created, except for GTCMAUTOSVR,"
+$ WRITE SYS$OUTPUT "and copied to SYS$MANAGER:"
+$ ELSE
+$ WRITE SYS$OUTPUT " The following command files are created:"
+$ ENDIF
+$ TYPE SYS$INPUT
+
+ GTCMAUTOSVR.COM
+ GTCMSERVER.COM
+ GTCMSTART.COM
+ GTCMSTOP.COM
+
+ Each file contains its own user documentation.
+
+ All the questions have been asked. Installation now proceeds without your
+ manual intervention for about 5-10 minutes.
+$ IF GTCM$RUN_IVP THEN WRITE SYS$OUTPUT " Finally the installation verification procedure tests the installation."
+$ WRITE SYS$OUTPUT ""
+$ VMI$CALLBACK CREATE_DIRECTORY 'GTCM$DIR_TYPE' 'GTCM$DST_CRE' "/OWNER_UIC=[''GTCM$DST_OWN'] /PROTECTION=(WO:RE)"
+$ VMI$CALLBACK MESSAGE I CRECOM "Creating command files."
+$! Create GTCMAUTOSVR.COM
+$ OPEN /WRITE OUFILE VMI$KWD:GTCMAUTOSVR.COM
+$ WRITE OUFILE "$! GTCMAUTOSVR.COM acts as a network object"
+$ WRITE OUFILE "$! for auto-starting a GT.CM Server with an optional timeout."
+$ WRITE OUFILE "$! P1 is the timeout"
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$ IF P1 .EQS. """" THEN P1 = ''GTCM$TIMEOUT'"
+$ WRITE OUFILE "$ SERVER := $''GTCM$DST_LOG'GTCM_SERVER"
+$ WRITE OUFILE "$ SERVER 'P1'"
+$ WRITE OUFILE "$ EXIT"
+$ CLOSE OUFILE
+$! Create GTCMSERVER.COM
+$ OPEN /WRITE OUFILE VMI$KWD:GTCMSERVER.COM
+$ WRITE OUFILE "$! GTCMSERVER.COM starts the GT.CM server with no timeout."
+$ WRITE OUFILE "$! The invoking user requires the following privileges:"
+$ WRITE OUFILE "$! DETATCH, NETMBX, PSWAPM, SYSNAM and TMPMBX"
+$ WRITE OUFILE "$! P1 is the maximum number of databases served to the network."
+$ WRITE OUFILE "$! P2 is the maximum number of remote clients served."
+$ WRITE OUFILE "$! P3 is the default working set size."
+$ WRITE OUFILE "$! P4 is the priority and should be at an appropriate priority"
+$ WRITE OUFILE "$! to balance network response with local load"
+$ WRITE OUFILE "$! P5 is the pagefile quota and should be large enough to"
+$ WRITE OUFILE "$! accommodate the global buffers for all BG database files."
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$ CURPRV = F$SETPRV(""TMPMBX"")"
+$ WRITE OUFILE "$ ON CONTROL_C THEN GOTO ERROR"
+$ WRITE OUFILE "$ ON ERROR THEN GOTO ERROR"
+$ WRITE OUFILE "$ CURPRV = F$SETPRV(""DETACH,NETMBX,PSWAPM,SYSNAM,TMPMBX"") + "","" + CURPRV"
+$ WRITE OUFILE "$ IF F$PRIVILEGE(""DETACH,NETMBX,PSWAPM,SYSNAM,TMPMBX"")"
+$ WRITE OUFILE "$ THEN"
+$ WRITE OUFILE "$ IF P6 .EQS. """""
+$ WRITE OUFILE "$ THEN"
+$ WRITE OUFILE "$ P6 := GTCM_SERVER"
+$ WRITE OUFILE "$ IF F$TRNLNM(""GTCMSVRNAM"",""LNM$SYSTEM_TABLE"") .NES. """""
+$ WRITE OUFILE "$ THEN"
+$ WRITE OUFILE "$ DEASSIGN /SYSTEM GTCMSVRNAM"
+$ WRITE OUFILE "$ ENDIF"
+$ WRITE OUFILE "$ ELSE"
+$ WRITE OUFILE "$ DEFINE /SYSTEM GTCMSVRNAM 'P6'"
+$ WRITE OUFILE "$ ENDIF"
+$ WRITE OUFILE "$ WRITE SYS$OUTPUT ""Starting the GT.CM Server as process "" + P6"
+$ WRITE OUFILE "$ IF P1 .EQS. """" THEN P1 = ''GTCM$NDB_CNT'"
+$ WRITE OUFILE "$ IF P2 .EQS. """" THEN P2 = ''GTCM$RC_CNT'"
+$ WRITE OUFILE "$ AL = ((P1 + 1) * 3) + P2"
+$ WRITE OUFILE "$ BL = (P2 + 3) * 1024"
+$ WRITE OUFILE "$ EL = (P1 + 1) * 3"
+$ WRITE OUFILE "$ FL = P1 + 3 + P2"
+$ WRITE OUFILE "$ DL = P1 * 7"
+$ WRITE OUFILE "$ TQ = (P1 + 1) * 2"
+$ WRITE OUFILE "$ IF P3 .EQS. """" THEN P3 = FL * 200"
+$ WRITE OUFILE "$ WSE = P3 + 200"
+$ WRITE OUFILE "$ IF P4 .EQS. """" THEN P4 = 5"
+$ WRITE OUFILE "$ IF P5 .EQS. """" THEN P5 = P1 * 10000"
+$ WRITE OUFILE "$ RUN/DETACHED /PROCESS='P6' /PRIV=(SYSNAM) /ERROR=SYS$MANAGER:CME.LOG -"
+$ WRITE OUFILE " /DUMP /NOSWAPPING /UIC=''GTCM$SRV_UIC' /AST_LIMIT='AL' /ENQUEUE_LIMIT='EL' -"
+$ WRITE OUFILE " /FILE_LIMIT='FL'/IO_BUFFERED='BL' /IO_DIRECT='DL' /QUEUE_LIMIT='TQ' -"
+$ WRITE OUFILE " /PRIORITY='P4' /WORKING_SET='P3' /MAXIMUM_WORKING_SET='WSE' -"
+$ WRITE OUFILE " /PAGE_FILE='P5' ''GTCM$DST_LOG'GTCM_SERVER"
+$ WRITE OUFILE "$ ELSE"
+$ WRITE OUFILE "$ WRITE SYS$OUTPUT ""NOT starting GT.CM Server because of inadequate privileges"""
+$ WRITE OUFILE "$ ENDIF"
+$ WRITE OUFILE "$ERROR:"
+$ WRITE OUFILE "$ CURPRV = F$SETPRV(CURPRV)"
+$ WRITE OUFILE "$ EXIT"
+$ CLOSE OUFILE
+$! Create GTCMSTART.COM
+$ OPEN /WRITE OUFILE VMI$KWD:GTCMSTART.COM
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! GTCMSTART.COM should be placed in the VMS startup database."
+$ WRITE OUFILE "$! P1, P2, P3, P4 and P5 are passed on to GTCMSERVER."
+$ WRITE OUFILE "$! It defines the CMISHR logical name, installs GT.CM images,"
+$ WRITE OUFILE "$! optionally sets up the autostart network object,"
+$ WRITE OUFILE "$! and optionally starts the GT.CM Server for a node."
+$ WRITE OUFILE "$! It defines the GTM$DIST and GTMSECSHR logical names,"
+$ WRITE OUFILE "$! to ensure they are /SYSTEM /EXEC, which doesn't work"
+$ WRITE OUFILE "$! if they exist /SYSTEM /SUPER."
+$ WRITE OUFILE "$! In that case modify the GT.M .COM files or invocation"
+$ WRITE OUFILE "$! or add DEASSIGNs in this file before the DEFINEs."
+$ WRITE OUFILE "$! If GT.M and GT.CM are stored in different places,"
+$ WRITE OUFILE "$! delete these DEFINEs and make sure the GT.M .COM files are OK."
+$ WRITE OUFILE "$! The invoking user requires the following privileges:"
+$ WRITE OUFILE "$! CMKRNL, DETATCH, OPER, NETMBX, PSWAPM, SYSNAM and TMPMBX"
+$ WRITE OUFILE "$! GTCM_SERVER is installed with privilege SYSNAM."
+$ WRITE OUFILE "$! CMISHR is the network interface and is installed for performance."
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$ CURPRV = F$SETPRV(""TMPMBX"")"
+$ WRITE OUFILE "$ ON CONTROL_C THEN GOTO ERROR"
+$ WRITE OUFILE "$ ON ERROR THEN GOTO ERROR"
+$ WRITE OUFILE "$ MUPI*P := $''GTCM$DST_LOG'MUPIP.EXE"
+$ WRITE OUFILE "$ MUPIP RUNDOWN ! Prepare a clean start"
+$ WRITE OUFILE "$ CURPRV = F$SETPRV(""CMKRNL,OPER,NETMBX,SYSNAM"") + "","" + CURPRV"
+$ WRITE OUFILE "$ IF F$PRIVILEGE(""CMKRNL,OPER,NETMBX,SYSNAM"")"
+$ WRITE OUFILE "$ THEN"
+$ WRITE OUFILE "$ DEFINE /SYSTEM/EXEC CMISHR ''GTCM$DST_LOG'CMISHR.EXE"
+$ WRITE OUFILE "$ DEFINE /SYSTEM/EXEC GTM$DIST ''GTCM$DST_LOG'"
+$ WRITE OUFILE "$ DEFINE /SYSTEM/EXEC GTMSECSHR ''GTCM$DST_LOG'GTMSECSHR.EXE"
+$ WRITE OUFILE "$ INSTALL"
+$ WRITE OUFILE " REPLACE /OPEN/HEADER/PRIV=SYSNAM ''GTCM$DST_LOG'GTCM_SERVER"
+$ WRITE OUFILE " REPLACE /OPEN/SHARED/HEADER CMISHR"
+$ T1 = "!"
+$ IF GTCM$AUTO_SRV THEN T1 :=
+$ WRITE OUFILE "$''T1' NCP :== $SYS$SYSTEM:NCP"
+$ WRITE OUFILE "$''T1' NCP SET OBJECT GTCMSVR NUMBER 0 FILE ''GTCM$DST_LOG'GTCMAUTOSVR.COM PROXY INCOMING USER ''GTCM$SRV_UIC'"
+$ T1 = "!"
+$ IF GTCM$STD_SRV THEN T1 :=
+$ WRITE OUFILE "$''T1' @''GTCM$DST_LOG'GTCMSERVER """"'P1' """"'P2' """"'P3' """"'P4' """"'P5' 'P6'"
+$ WRITE OUFILE "$ ELSE"
+$ WRITE OUFILE "$ WRITE SYS$OUTPUT ""NOT starting GT.CM because of inadequate privileges"""
+$ WRITE OUFILE "$ ENDIF"
+$ WRITE OUFILE "$ERROR:"
+$ WRITE OUFILE "$ CURPRV = F$SETPRV(CURPRV)"
+$ WRITE OUFILE "$ EXIT"
+$ CLOSE OUFILE
+$! Create GTCMSTOP.COM
+$ OPEN /WRITE OUFILE VMI$KWD:GTCMSTOP.COM
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! GTCMSTOP.COM stops the GT.CM Server for a node and does MUPIP RUNDOWN"
+$ WRITE OUFILE "$! Place an invocation or copy of this procedure in the site specific"
+$ WRITE OUFILE "$! shutdown: SYS$MANAGER:SYSHUTDWN to ensure all GT.M databases are"
+$ WRITE OUFILE "$! properly closed before VMS terminates. GTCMSTOP should precede"
+$ WRITE OUFILE "$! GTCXSTOP, if used, and GTMSTOP, in any case."
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$ MUPIP := $''GTCM$DST_LOG'MUPIP.EXE"
+$ WRITE OUFILE "$ RUN ''GTCM$DST_LOG'GTCM_STOP.EXE"
+$ WRITE OUFILE "$ MUPIP RUNDOWN"
+$ WRITE OUFILE "$ EXIT"
+$ CLOSE OUFILE
+$ VMI$CALLBACK MESSAGE I PREINS "Preparing files for installation."
+$! GTCMFILES.KIT must be maintained as kit contents change
+$ OPEN /WRITE OUFILE VMI$KWD:GTCMFILES.KIT
+$ IF GTCM$MGR_COM
+$ THEN
+$ WRITE OUFILE "GTCM$ GTCMSERVER.COM VMI$ROOT:[SYSMGR] C"
+$ WRITE OUFILE "GTCM$ GTCMSTART.COM VMI$ROOT:[SYSMGR] C"
+$ WRITE OUFILE "GTCM$ GTCMSTOP.COM VMI$ROOT:[SYSMGR] C"
+$ ENDIF
+$ WRITE OUFILE "GTCM$ GTCMAUTOSVR.COM ''GTCM$DST_LOG'"
+$ WRITE OUFILE "GTCM$ GTCMSERVER.COM ''GTCM$DST_LOG'"
+$ WRITE OUFILE "GTCM$ GTCMSTART.COM ''GTCM$DST_LOG'"
+$ WRITE OUFILE "GTCM$ GTCMSTOP.COM ''GTCM$DST_LOG'"
+$ CLOSE OUFILE
+$! GTCMIMAGES.KIT must be maintained as kit contents change
+$ OPEN /WRITE OUFILE VMI$KWD:GTCMIMAGES.KIT
+$ WRITE OUFILE "GTCM$ CMISHR.EXE ''GTCM$DST_LOG'"
+$ WRITE OUFILE "GTCM$ GTCM_SERVER.EXE ''GTCM$DST_LOG'"
+$ WRITE OUFILE "GTCM$ GTCM_STOP.EXE ''GTCM$DST_LOG'"
+$ CLOSE OUFILE
+$! Provide with file.KITs
+$ VMI$CALLBACK PROVIDE_FILE "" VMI$KWD:GTCMFILES.KIT "" T
+$ VMI$CALLBACK PROVIDE_IMAGE "" VMI$KWD:GTCMIMAGES.KIT "" T
+$ VMI$CALLBACK MESSAGE I FININS "Finalizing the installation."
+$ IF GTCM$START_CM THEN VMI$CALLBACK SET POSTINSTALL YES
+$ IF GTCM$RUN_IVP THEN VMI$CALLBACK SET IVP YES
+$ IF GTCM$STARTDB THEN VMI$CALLBACK MODIFY_STARTUP_DB ADD GTCMSTART.COM END
+$ EXIT VMI$_SUCCESS
+$!
+$POSTINSTALL:
+$!
+$ @'GTCM$DST_LOG'GTMLOGIN
+$ SET NOON
+$ DEFINE /USER_MODE SYS$ERROR NL:
+$ DEFINE /USER_MODE SYS$OUTPUT NL:
+$ IF GTCM$MGR_COM
+$ THEN
+$ T1 := SYS$MANAGER:
+$ ELSE
+$ T1 = GTCM$DST_LOG
+$ ENDIF
+$ @'T1'GTCMSTOP
+$ SET ON
+$ @'T1'GTCMSTART
+$ EXIT VMI$_SUCCESS
+$!
+$IVP:
+$! The real Installation Verification Procedure.
+$ TYPE SYS$INPUT
+
+ GT.CM Installation Verification Procedure
+
+$! Extract the IVP .COM file from the text library.
+$ LIBRARIAN /EXTRACT=GTCM$IVP /OUTPUT=GTCM$IVP.COM GTCM$IVP.TLB
+$ @GTCM$IVP
+$ EXIT $STATUS
diff --git a/sr_vvms/gtcmstop.m b/sr_vvms/gtcmstop.m
new file mode 100644
index 0000000..6b71a53
--- /dev/null
+++ b/sr_vvms/gtcmstop.m
@@ -0,0 +1,58 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ;
+; Copyright 1990, 2002 Sanchez Computer Associates, Inc. ;
+; ;
+; This source code contains the intellectual property ;
+; of its copyright holder(s), and is made available ;
+; under a license. If you do not know the terms of ;
+; the license, please stop and do not read further. ;
+; ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+GTCMSTOP ;GT.CM STOP utility - stops the GT.CM Server
+ ; If a logical GTCMSVRNAM is defined, only the process pointed by
+ ; it will be stopped (note: it is not checked whether that is a
+ ; GTCM_SERVER process). If the logical GTCMSVRNAM is not defined,
+ ; all processes with image name GTCM_SERVER are stopped.
+ ; All processes that are being stopped will be listed.
+ ;
+ n i,op,expriv,nopriv,pid,zt,$zt
+ s $zt="zg "_$zl_":ERR^GTCMSTOP" u $p:ctrap=$c(3) w !!
+ s op=$zsetprv("GROUP,WORLD"),(expriv,nopriv)=0,zt="d blindpid"
+ f i=1:1:10 d getipid(.pid) q:'pid d
+ . i i<10 d stopem(.pid) h 2 q
+ . d killem(.pid)
+ i expriv w !,"Insufficient privileges to examine ",expriv,"process",$s(expriv>1:"es.",1:"."),!
+ i nopriv w !,"Insufficient privileges to stop ",nopriv," process",$s(nopriv>1:"es.",1:"."),!
+ s op=$zsetprv(op) u $p:ctrap=""
+ q
+getipid(t);
+ n p,$zt,found,iorp k t s $zt=zt,t=0
+ s p=$zpid(0),logname=$ztrnlnm("GTCMSVRNAM") q:'p
+ f d s p=$zpid(1) q:'p d
+ . q:'p s iname=$zparse($zgetjpi(p,"IMAGNAME"),"NAME"),pname=$zgetjpi(p,"PRCNAM"),found=0,iorp=0
+ . i logname'="" s iorp=1
+ . i iorp,pname=logname s found=1
+ . i 'iorp,iname="GTCM_SERVER" s found=1
+ . i found s t(p)=$$FUNC^%DH(p,8),t=t+1
+ q
+blindpid
+ i $zs["NOPRIV" s expriv=expriv+1
+ e w !,$$FUNC^%DH(p,8)," ",$p($zs,",",2,99),!
+ s p=0
+ q
+stopem(t);
+ n p s p=""
+ f s p=$o(t(p)) q:p="" zsystem "show system /full /id="_t(p) d msg($&FORCEX(p),t(p),"Stopping process ")
+ q
+killem(t);
+ n p s p=""
+ f s p=$o(t(p)) q:p="" zsystem "show system /full /id="_t(p) d msg($&DELPRC(p),t(p),"Deleting process ")
+ q
+msg(stat,prc,defmsg)
+ i stat=1 w defmsg,prc,! q
+ s stat=$zm(stat)
+ i stat["NOPRIV" s:'$d(nopriv(prc)) nopriv(prc)=1,nopriv=nopriv+1 q
+ w "Error for ",prc," : ",stat,!
+ q
+ERR w !,$p($zs,",",2,99),! u $p:ctrap="" s:$d(op) op=$zsetprv(op)
+ q
diff --git a/sr_vvms/gtcx_spkitbld.dat b/sr_vvms/gtcx_spkitbld.dat
new file mode 100644
index 0000000..c59d92a
--- /dev/null
+++ b/sr_vvms/gtcx_spkitbld.dat
@@ -0,0 +1,6 @@
+SPKITBLD$KITNAME := GTCX60002
+SPKITBLD$REWIND_TAPE := N
+SPKITBLD$AUTOINIT_TAPE := 'GTM_INIT_TAPE'
+SPKITBLD$SKIP_FIRST_TAPE_READY_PROMPT := Y
+SPKITBLD$SKIP_FIRST_DISK_READY_PROMPT := Y
+SPKITBLD$SAVESET_A := GTM$VRT:[TCX]KITINSTAL.COM;,GTCXKITHLP.COM;,GTM$VRT:[PRO]CCE.EXE;,CCP.EXE;,GTM$VRT:[HLP]CCE.HLB;
diff --git a/sr_vvms/gtcxkithlp.com b/sr_vvms/gtcxkithlp.com
new file mode 100644
index 0000000..c098292
--- /dev/null
+++ b/sr_vvms/gtcxkithlp.com
@@ -0,0 +1,126 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2003 Sanchez Computer Associates, Inc. !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$!
+$! HELP TEXT PROCESSING FOR GT.CX KITINSTAL.COM
+$! COPYRIGHT 1989 - 2000 Sanchez Computer Associates
+$ IF F$EXTRACT(0,5,P1) .EQS. "HELP_" THEN GOTO 'P1'
+$ EXIT VMI$_UNSUPPORTED
+$HELP_READY:
+$ TYPE SYS$INPUT
+ If GT.CX is installed, it should not be active during an installation.
+
+$ EXIT
+$HELP_PURGE:
+$ TYPE SYS$INPUT
+ If GT.CX is previously installed, there is no reason to keep older versions
+ of the software online, unless you wish to test before purging.
+
+$ EXIT
+$HELP_CDB_CNT:
+$ TYPE SYS$INPUT
+ The installation inserts this value as the default for controlling the CCP
+ quotas established in GTCXSTART.COM. If you provide a value less than 1,
+ the value will be set to 1. This value can be easily changed later.
+
+$ EXIT
+$HELP_STD_CNF:
+$ TYPE SYS$INPUT
+ The standard configuration performs the following:
+
+ * Places files in SYS$COMMON:[GTM_DIST] with SYSTEM as owner
+ * Copies the GT.CX command procedures to SYS$MANAGER
+ * Adds GTCXSTART.COM to the system startup database
+ * Leaves GT.CX help files in GTM$DIST (does not move them to SYS$HELP)
+ * Sets up GTCXSTART.COM to start the CCP under the SYSTEM UIC
+ * Starts the GT.CX CCP at the end of the installation
+
+ If the SYSTEM id is not set up, the installation will use [1,4].
+
+$ EXIT
+$HELP_DST_OWN:
+$ TYPE SYS$INPUT
+ Provide a UIC, normally SYSTEM, to own the files in the GT.M distribution.
+ The UIC can be a name, a group name and a user name separated by a comma,
+ or a pair of octal codes separated by a comma which specify group and user.
+
+$ EXIT
+$HELP_SYS_DST:
+$ TYPE SYS$INPUT
+ Usual practice is to place a system component such as GT.CX on the system
+ disk. If you have severe space constraints, you may need to use another
+ volume.
+
+$ EXIT
+$HELP_SYS_DIR:
+$ TYPE SYS$INPUT
+ This directory becomes be a sub-directory of SYS$COMMON and holds the
+ distribution. If it does not exist, the installation creates it with
+ WORLD=RE access. If you are not concerned with mixing software from
+ different vendors, you may wish to use SYSLIB.
+
+$ EXIT
+$HELP_DST_DEV:
+$ TYPE SYS$INPUT
+ The disk must be mounted, on-line and have adequate space to hold the GT.CX
+ distribution. The disk name may be physical or logical.
+
+$ EXIT
+$HELP_DST_DIR:
+$ TYPE SYS$INPUT
+ This directory holds the distribution. If it does not exist, the
+ installation creates it with WORLD=RE access.
+
+$ EXIT
+$HELP_CCP_OWN:
+$ TYPE SYS$INPUT
+ The CCP usually must have broad file access so running under the SYSTEM UIC
+ may make sense. Alternatives involve using a distinguished UIC which has
+ appropriate UIC or ACL based access to clustered files. This UIC MUST be in
+ Group 1.
+
+$ EXIT
+$HELP_STARTDB:
+$ TYPE SYS$INPUT
+ Answering yes causes the installation to place GTCXSTART.COM in the startup
+ database so the system startup automatically sets up the GT.CX environment
+ whenever the system boots.
+
+$ EXIT
+$HELP_MGR_COM:
+$ TYPE SYS$INPUT
+ You may prevent the installation from moving the .COM files to SYS$MANAGER.
+ Copying the command procedures to SYS$MANAGER allows system startup to
+ access them through the VMS startup database and generally simplifies
+ operations. However, if you wish to have multiple versions of GT.M on your
+ system at the same time, you would not have multiple copies of the command
+ procedures in SYS$MANAGER.
+
+$ EXIT
+$HELP_HLP_DIR:
+$ TYPE SYS$INPUT
+ You may place the GT.CX help files in SYS$HELP or leave them with the rest
+ of the distribution.
+
+$ EXIT
+$HELP_RUN_IVP:
+$ TYPE SYS$INPUT
+ This installation kit contains an installation verification procedure (IVP)
+ which you can run as part of the installation to verify the correctness of
+ the software. Note that if you choose this option, the GT.M images must
+ already be installed.
+
+$ EXIT
+$HELP_START_CCP:
+$ TYPE SYS$INPUT
+ Answering yes causes the installation to start the CCP.
+
+$ EXIT
diff --git a/sr_vvms/gtcxkitinstal.com b/sr_vvms/gtcxkitinstal.com
new file mode 100644
index 0000000..502f0c1
--- /dev/null
+++ b/sr_vvms/gtcxkitinstal.com
@@ -0,0 +1,302 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2003 Sanchez Computer Associates, Inc. !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$!
+$! KITINSTAL.COM PROCEDURE FOR THE GT.CX PRODUCT
+$!
+$ ON CONTROL_Y THEN VMI$CALLBACK CONTROL_Y
+$ ON WARNING THEN EXIT $STATUS
+$ IF P1 .EQS. "VMI$_INSTALL" THEN GOTO INSTALL
+$ IF P1 .EQS. "VMI$_POSTINSTALL" THEN GOTO POSTINSTALL
+$ IF P1 .EQS. "VMI$_IVP" THEN GOTO IVP
+$ EXIT VMI$_UNSUPPORTED
+$!
+$INSTALL:
+$ TYPE SYS$INPUT
+
+ GT.CX (c) COPYRIGHT 1987 - 2000 by Sanchez Computer Associates
+ ALL RIGHTS RESERVED
+
+
+$! the following 2 lines must be maintained
+$ GTCX$VMS_VERSION :== 072 ! Minimum VMS version required
+$ GTCX$DISK_SPACE == 3000 ! Minumum disk space on system disk required for install (2x result)
+$!
+$ IF F$ELEMENT(0,",",VMI$VMS_VERSION) .EQS. "RELEASED"
+$ THEN
+$ GTCX$VMS_IS == F$ELEMENT(1,",",VMI$VMS_VERSION)
+$ IF GTCX$VMS_IS .LTS. GTCX$VMS_VERSION
+$ THEN
+$ VMI$CALLBACK MESSAGE E VMSMISMATCH "This GT.CX kit requires an existing VMS''GTCX$VMS_VERSION' system."
+$ EXIT VMI$_FAILURE
+$ ENDIF
+$ ELSE
+$ GTCX$VMS_IS :==
+$ WRITE SYS$OUTPUT " No VMS version checking performed for field test versions."
+$ ENDIF
+$ IF (GTCX$VMS_IS .GES. "052") THEN T1 = F$VERIFY(VMI$KIT_DEBUG)
+$ VMI$CALLBACK CHECK_NET_UTILIZATION GTCX$ROOM 'GTCX$DISK_SPACE'
+$ IF .NOT. GTCX$ROOM
+$ THEN
+$ VMI$CALLBACK MESSAGE E NOSPACE "There is not enough disk space -- GT.CX needs ''GTCX$DISK_SPACE' blocks."
+$ EXIT VMI$_FAILURE
+$ ENDIF
+$! check for running users
+$ SET NOON
+$ DEFINE SYS$ERROR NL:
+$ DEFINE SYS$OUTPUT NL:
+$ @SYS$COMMON:[GTM_DIST]:GTMLOGIN
+$ CCE :== $GTM$DIST:CCE
+$ CCE SHO CCP
+$ T1 = $SEVERITY
+$ DEASSIGN SYS$OUTPUT
+$ DEASSIGN SYS$ERROR
+$ IF T1 .EQ. 1 THEN CCE SHO CCP
+$ SET ON
+$ DELETE /SYMBOL/GLOBAL CCE
+$ VMI$CALLBACK ASK GTCX$READY "Have you verified there are no current GT.CX users" "NO" B "@VMI$KWD:GTCXKITHLP HELP_READY"
+$ IF .NOT. GTCX$READY THEN EXIT VMI$_FAILURE
+$! setup default answers
+$ GTCX$DOPURGE :== YES
+$ GTCX$RUN_IVP == 0 !! should be "YES", but no IVP yet
+$ GTCX$CDB_CNT == 12
+$ GTCX$STD_CNF :== YES
+$ GTCX$DST_OWN :== SYSTEM
+$ IF F$IDENTIFIER(GTCX$DST_OWN,"NAME_TO_NUMBER") .EQ. 0 THEN GTCX$DST_OWN :== 1,4
+$ GTCX$CCP_UIC == GTCX$DST_OWN
+$ GTCX$SYS_DST :== YES
+$ GTCX$DST_DIR :== GTM_DIST
+$ GTCX$DST_CRE == GTCX$DST_DIR
+$ GTCX$DST_DEV :==
+$ GTCX$STARTDB :== YES
+$ GTCX$MGR_COM :== YES
+$ GTCX$HLP_DIR :== NO
+$ GTCX$START_CCP :== YES
+$!
+$ VMI$CALLBACK ASK GTCX$DOPURGE "Do you want to purge files replaced by this installation" 'GTCX$DOPURGE' B -
+ "@VMI$KWD:GTCXKITHLP HELP_PURGE"
+$ IF .NOT. GTCX$DOPURGE THEN VMI$CALLBACK SET PURGE NO
+$ VMI$CALLBACK ASK GTCX$CDB_CNT "How many clustered databases will this node access" 'GTCX$CDB_CNT' I -
+ "@VMI$KWD:GTCXKITHLP HELP_CDB_CNT"
+$ IF GTCX$CDB_CNT .LT. 1
+$ THEN
+$ GTCX$CDB_CNT == 1
+$ WRITE SYS$OUTPUT " The installation set this value to 1 as 0 or negative values are not useful."
+$ ENDIF
+$ VMI$CALLBACK ASK GTCX$STD_CNF "Do you want the standard GT.CX configuration" 'GTCX$STD_CNF' B -
+ "@VMI$KWD:GTCXKITHLP HELP_STD_CNF"
+$ IF GTCX$STD_CNF
+$ THEN
+$ GTCX$SYS_DST == 1
+$ GTCX$STARTDB == 1
+$ GTCX$MGR_COM == 1
+$ GTCX$HLP_DIR == 0
+$ GTCX$START_CCP == 1
+$ GTCX$DST_LOG :== SYS$COMMON:['GTCX$DST_DIR']
+$ GTCX$DIR_TYPE :== COMMON
+$ GTCX$RUN_IVP == 0 !! "YES" no IVP yet
+$ ELSE ! not standard configuration
+$ VMI$CALLBACK ASK GTCX$DST_OWN "What UIC should own the GT.CX distribution" 'GTCX$DST_OWN' S "@VMI$KWD:GTCXKITHLP HELP_DST_OWN"
+$ GTCX$DST_OWN == GTCX$DST_OWN - "[" - "]"
+$ VMI$CALLBACK ASK GTCX$SYS_DST "Do you want the GT.CX distribution to go into a System Directory" 'GTCX$SYS_DST' B -
+ "@VMI$KWD:GTCXKITHLP HELP_SYS_DST"
+$ IF GTCX$SYS_DST
+$ THEN
+$ VMI$CALLBACK ASK GTCX$DST_DIR "In what System Directory do you want to place GT.CX" 'GTCX$DST_DIR' S -
+ "@VMI$KWD:GTCXKITHLP HELP_SYS_DIR"
+$ GTCX$DST_DIR == GTCX$DST_DIR - "[" - "]"
+$ GTCX$DST_CRE == GTCX$DST_DIR
+$ GTCX$DST_LOG :== SYS$COMMON:['GTCX$DST_DIR']
+$ GTCX$DIR_TYPE :== COMMON
+$ ELSE ! not system disk
+$ VMI$CALLBACK ASK GTCX$DST_DEV "On which device do you want to place GT.CX" "''GTCX$DST_DEV'" S -
+ "@VMI$KWD:GTCXKITHLP HELP_DST_DEV"
+$ VMI$CALLBACK ASK GTCX$DST_DIR "In what directory on that device do you want to place GT.CX" 'GTCX$DST_DIR' S -
+ "@VMI$KWD:GTCXKITHLP HELP_DST_DIR"
+$ GTCX$DST_DEV == GTCX$DST_DEV - ":"
+$ GTCX$DST_DIR == GTCX$DST_DIR - "[" - "]"
+$ GTCX$DST_LOG :== 'GTCX$DST_DEV':['GTCX$DST_DIR']
+$ GTCX$DST_CRE == GTCX$DST_LOG
+$ GTCX$DIR_TYPE :== USER
+$ ENDIF ! system disk
+$ VMI$CALLBACK ASK GTCX$CCP_UIC "Under what UIC should the CCP operate (must be Group 1)" 'GTCX$CCP_UIC' S -
+ "@VMI$KWD:GTCXKITHLP HELP_CCP_OWN"
+$ GTCX$CCP_UIC == GTCX$CCP_UIC - "[" - "]"
+$ IF F$ELEMENT(0,",",GTCX$CCP_UIC) .NE. 1
+$ THEN
+$ T1 = F$FAO("!%U",'F$IDENTIFIER(GTCX$CCP_UIC,"NAME_TO_NUMBER")')' -"["-"]"
+$ IF F$ELEMENT(0,",",T1) .NE. 1
+$ THEN
+$ GTCX$CCP_UIC :== SYSTEM
+$ IF F$IDENTIFIER(GTCX$CCP_UIC,"NAME_TO_NUMBER") .EQ. 0 THEN GTCX$CCP_UIC :== 1,4
+$ WRITE SYS$OUTPUT " The installation is using the default because the Group must be 1."
+$ ENDIF
+$ ENDIF
+$ VMI$CALLBACK ASK GTCX$STARTDB "Do you want GTCXSTART.COM in the startup database" 'GTCX$STARTDB' B -
+ "@VMI$KWD:GTCXKITHLP HELP_STARTDB"
+$ IF .NOT. GTCX$STARTDB
+$ THEN
+$ VMI$CALLBACK ASK GTCX$MGR_COM "Do you want the GT.M .COM files in SYS$MANAGER" 'GTCX$MGR_COM' B -
+ "@VMI$KWD:GTCXKITHLP HELP_MGR_COM"
+$ ENDIF
+$ VMI$CALLBACK ASK GTCX$HLP_DIR "Do you want the GT.CX help files in SYS$HELP" 'GTCX$HLP_DIR' B "@VMI$KWD:GTCXKITHLP HELP_HLP_DIR"
+$!! no IVP yet
+$ IF 0 THEN VMI$CALLBACK ASK GTCX$RUN_IVP "Do you want to run the IVP (requires GT.M)" 'GTCX$RUN_IVP' B -
+ "@VMI$KWD:GTCXKITHLP HELP_RUN_IVP"
+$ IF GTCX$RUN_IVP
+$ THEN
+$ GTCX$START_CCP == 1
+$ ELSE
+$ VMI$CALLBACK ASK GTCX$START_CCP "Do you want to start a GT.CX CCP now" 'GTCX$START_CCP' B "@VMI$KWD:GTCXKITHLP HELP_START_CCP"
+$ ENDIF
+$ ENDIF ! standard configuration
+$ IF GTCX$MGR_COM
+$ THEN
+$ WRITE SYS$OUTPUT " The following command files are created and copied to SYS$MANAGER:"
+$ ELSE
+$ WRITE SYS$OUTPUT " The following command files are created:"
+$ ENDIF
+$ TYPE SYS$INPUT
+
+ GTCXSTART.COM
+ GTCXSTOP.COM
+
+ Each file contains its own user documentation.
+
+ All the questions have been asked. Installation now proceeds without your
+ manual intervention for about 5-10 minutes.
+$ IF GTCX$RUN_IVP THEN WRITE SYS$OUTPUT " Finally the installation verification procedure tests the installation."
+$ WRITE SYS$OUTPUT ""
+$ VMI$CALLBACK CREATE_DIRECTORY 'GTCX$DIR_TYPE' 'GTCX$DST_CRE' "/OWNER_UIC=[''GTCX$DST_OWN'] /PROTECTION=(WO:RE)"
+$ VMI$CALLBACK MESSAGE I CRECOM "Creating command files."
+$! Create GTCXSTART.COM
+$ OPEN /WRITE OUFILE VMI$KWD:GTCXSTART.COM
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! GTCXSTART.COM should be placed in the VMS startup database."
+$ WRITE OUFILE "$! It starts the GT.CX Cluster Controller Program (CCP) for a node."
+$ WRITE OUFILE "$! The invoking user requires the following privileges:"
+$ WRITE OUFILE "$! ALTPRI, DETATCH, OPER, PSWAPM, SYSLCK, SYSNAM and TMPMBX"
+$ WRITE OUFILE "$! P1 is the number of clustered databases."
+$ WRITE OUFILE "$! P2 is the priority and should be at or just above the highest priority"
+$ WRITE OUFILE "$! used by a any GT.M process which accesses clustered database files."
+$ WRITE OUFILE "$! P3 is the default working set size."
+$ WRITE OUFILE "$! P4 is the Page File Quota, which should be the sum for all"
+$ WRITE OUFILE "$! clustered databases of (GLOBAL_BUFFERS*BLOCKSIZE/512+LOCKSPACE+50),"
+$ WRITE OUFILE "$! and which this procedure approximates by defaulting to P1 * 10000."
+$ WRITE OUFILE "$ CURPRV = F$SETPRV(""TMPMBX"")"
+$ WRITE OUFILE "$ ON CONTROL_C THEN GOTO ERROR"
+$ WRITE OUFILE "$ ON ERROR THEN GOTO ERROR"
+$ WRITE OUFILE "$ CCE := $''GTCX$DST_LOG'CCE.EXE"
+$ WRITE OUFILE "$ MUPI*P := $''GTCX$DST_LOG'MUPIP.EXE"
+$ WRITE OUFILE "$ MUPIP RUNDOWN ! Prepare a clean start"
+$ WRITE OUFILE "$ CURPRV = F$SETPRV(""ALTPRI,DETACH,OPER,PSWAPM,SYSLCK,SYSNAM,TMPMBX"") + - "
+$ WRITE OUFILE " "","" + CURPRV"
+$ WRITE OUFILE "$ IF F$PRIVILEGE(""ALTPRI,DETACH,OPER,PSWAPM,SYSLCK,SYSNAM,TMPMBX"")"
+$ WRITE OUFILE "$ THEN"
+$ WRITE OUFILE "$ WRITE SYS$OUTPUT ""Starting the CCP as process GT.CX_CONTROL"""
+$ WRITE OUFILE "$ IF P1 .EQS. """" THEN P1 = ''GTCX$CDB_CNT'"
+$ WRITE OUFILE "$ FL = P1 + 3"
+$ WRITE OUFILE "$ AL = FL * 4"
+$ WRITE OUFILE "$ EL = FL * 5"
+$ WRITE OUFILE "$ DL = FL * 10"
+$ WRITE OUFILE "$ TQ = FL * 3"
+$ WRITE OUFILE "$ IF P2 .EQS. """" THEN P2 = 5"
+$ WRITE OUFILE "$ IF P3 .EQS. """" THEN P3 = FL * 200"
+$ WRITE OUFILE "$ WSE = P3 + 200"
+$ WRITE OUFILE "$ IF P4 .EQS. """" THEN P4 = P1 * 10000"
+$ WRITE OUFILE "$ RUN/DETACHED/PROC=""GT.CX_CONTROL""/PRIV=(OPER,SYSLCK,SYSNAM,TMPMBX) -"
+$ WRITE OUFILE " /ERROR=SYS$MANAGER:CCPERR.LOG /PAGE_FILE='P4' -"
+$ WRITE OUFILE " /DUMP/NOSWAPPING/UIC=''GTCX$CCP_UIC'/AST_LIMIT='AL'/ENQUEUE_LIMIT='EL' -"
+$ WRITE OUFILE " /FILE_LIMIT='FL'/IO_DIRECT='DL'/QUEUE_LIMIT='TQ'/PRIORITY='P2' -"
+$ WRITE OUFILE " /WORKING_SET='P3'/MAXIMUM_WORKING_SET='WSE' ''GTCX$DST_LOG'CCP.EXE"
+$ WRITE OUFILE "$ ELSE"
+$ WRITE OUFILE "$ WRITE SYS$OUTPUT ""NOT starting the CCP because of inadequate privileges"""
+$ WRITE OUFILE "$ ENDIF"
+$ WRITE OUFILE "$ERROR:"
+$ WRITE OUFILE "$ CURPRV = F$SETPRV(CURPRV)"
+$ WRITE OUFILE "$ EXIT"
+$ CLOSE OUFILE
+$! Create GTCXSTOP.COM
+$ OPEN /WRITE OUFILE VMI$KWD:GTCXSTOP.COM
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! GTCXSTOP.COM stops the GT.CX CCP for a node and does MUPIP RUNDOWN"
+$ WRITE OUFILE "$! Place an invocation or copy of this procedure in the site specific"
+$ WRITE OUFILE "$! shutdown: SYS$MANAGER:SYSHUTDWN to ensure all GT.M databases are"
+$ WRITE OUFILE "$! properly closed before VMS terminates. GTCXSTOP should follow"
+$ WRITE OUFILE "$! GTCMSTOP, if used and GTMSTOP, in any case."
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$ CCE := $''GTCX$DST_LOG'CCE.EXE"
+$ WRITE OUFILE "$ MUPIP := $''GTCX$DST_LOG'MUPIP.EXE"
+$ WRITE OUFILE "$ CCE STOP"
+$ WRITE OUFILE "$ MUPIP RUNDOWN"
+$ WRITE OUFILE "$ EXIT"
+$ CLOSE OUFILE
+$ VMI$CALLBACK MESSAGE I PREINS "Preparing files for installation."
+$! GTCXFILES.KIT must be maintained as kit contents change
+$ OPEN /WRITE OUFILE VMI$KWD:GTCXFILES.KIT
+$ IF GTCX$MGR_COM
+$ THEN
+$ WRITE OUFILE "GTCX$ GTCXSTART.COM VMI$ROOT:[SYSMGR] C"
+$ WRITE OUFILE "GTCX$ GTCXSTOP.COM VMI$ROOT:[SYSMGR] C"
+$ ENDIF
+$ WRITE OUFILE "GTCX$ GTCXSTART.COM ''GTCX$DST_LOG'"
+$ WRITE OUFILE "GTCX$ GTCXSTOP.COM ''GTCX$DST_LOG'"
+$ CLOSE OUFILE
+$! GTCXIMAGES.KIT must be maintained as kit contents change
+$ OPEN /WRITE OUFILE VMI$KWD:GTCXIMAGES.KIT
+$ WRITE OUFILE "GTCX$ CCE.EXE ''GTCX$DST_LOG'"
+$ WRITE OUFILE "GTCX$ CCP.EXE ''GTCX$DST_LOG'"
+$ CLOSE OUFILE
+$! Create GTCXHLB.KIT - don't know why this requires a separate file.
+$ GTCX$HLP_LOG == GTCX$DST_LOG
+$ IF GTCX$HLP_DIR THEN GTCX$HLP_LOG :== VMI$ROOT:[SYSHLP]
+$ OPEN /WRITE OUFILE VMI$KWD:GTCXHLB.KIT
+$ WRITE OUFILE "GTCX$ CCE.HLB ''GTCX$HLP_LOG'"
+$ CLOSE OUFILE
+$! Provide with file.KITs
+$ VMI$CALLBACK PROVIDE_FILE "" VMI$KWD:GTCXFILES.KIT "" T
+$ VMI$CALLBACK PROVIDE_IMAGE "" VMI$KWD:GTCXIMAGES.KIT "" T
+$ VMI$CALLBACK PROVIDE_FILE "" VMI$KWD:GTCXHLB.KIT "" T
+$ VMI$CALLBACK MESSAGE I FININS "Finalizing the installation."
+$ IF GTCX$START_CCP THEN VMI$CALLBACK SET POSTINSTALL YES
+$ IF GTCX$RUN_IVP THEN VMI$CALLBACK SET IVP YES
+$ IF GTCX$STARTDB THEN VMI$CALLBACK MODIFY_STARTUP_DB ADD GTCXSTART.COM END
+$ EXIT VMI$_SUCCESS
+$!
+$POSTINSTALL:
+$!
+$! do a gtmlogin
+$ @'GTCX$DST_LOG'GTMLOGIN
+$ CCE := $GTM$DIST:CCE.EXE
+$ SET NOON
+$ DEFINE /USER_MODE SYS$ERROR NL:
+$ DEFINE /USER_MODE SYS$OUTPUT NL:
+$ CCE STOP
+$ SET ON
+$ IF GTCX$MGR_COM
+$ THEN
+$ T1 := SYS$MANAGER:
+$ ELSE
+$ T1 = GTM$DST_LOG
+$ ENDIF
+$ @'T1'GTCXSTART
+$ EXIT VMI$_SUCCESS
+$!
+$IVP:
+$! The real Installation Verification Procedure.
+$ TYPE SYS$INPUT
+
+ GT.CX Installation Verification Procedure
+
+$! Extract the IVP .COM file from the text library.
+$ LIBRARIAN /EXTRACT=GTCX$IVP /OUTPUT=GTCX$IVP.COM GTCX$IVP.TLB
+$ @GTCX$IVP
+$ EXIT $STATUS
diff --git a/sr_vvms/gtm$ce.h b/sr_vvms/gtm$ce.h
new file mode 100644
index 0000000..4e6a5d3
--- /dev/null
+++ b/sr_vvms/gtm$ce.h
@@ -0,0 +1,28 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+enum GTM$INFO_CODE
+{
+ GTCE$K_SFN,
+ GTCE$K_RTN,
+ GTCE$K_INDIR,
+ GTCE$K_ZROU,
+ GTCE$K_ZCOM,
+ GTCE$K_CMDLIN,
+ GTCE$K_P1,
+ GTCE$K_P2,
+ GTCE$K_P3,
+ GTCE$K_P4,
+ GTCE$K_P5,
+ GTCE$K_P6,
+ GTCE$K_P7,
+ GTCE$K_P8
+} ;
diff --git a/sr_vvms/gtm$ce_establish.c b/sr_vvms/gtm$ce_establish.c
new file mode 100644
index 0000000..bf82633
--- /dev/null
+++ b/sr_vvms/gtm$ce_establish.c
@@ -0,0 +1,58 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include <ssdef.h>
+#include <descrip.h>
+
+#include "mdef.h"
+#include "comp_esc.h"
+
+GBLREF struct ce_sentinel_desc *ce_def_list;
+
+
+int4 GTM$CE_ESTABLISH (user_action_routine, sentinel)
+int4 (*user_action_routine)();
+struct dsc$descriptor_s sentinel;
+{
+ struct ce_sentinel_desc *shp, *shp_last;
+
+
+ shp = shp_last = ce_def_list;
+ while (shp != NULL)
+ {
+ shp_last = shp;
+ shp = shp->next;
+ }
+
+ /* Create new node. */
+ shp = malloc(SIZEOF(struct ce_sentinel_desc));
+
+ shp->escape_sentinel = malloc(sentinel.dsc$w_length);
+ memcpy (shp->escape_sentinel, sentinel.dsc$a_pointer, sentinel.dsc$w_length);
+ shp->escape_length = sentinel.dsc$w_length;
+ shp->user_routine = user_action_routine;
+ shp->next = NULL;
+
+ /* Add to list. */
+ if (shp_last == NULL)
+ {
+ /* First sentinel handler, it is the list. */
+ ce_def_list = shp;
+ }
+ else
+ {
+ /* Add to end of list. */
+ shp_last->next = shp;
+ }
+
+
+ return SS$_NORMAL;
+}
diff --git a/sr_vvms/gtm$ce_getinfo.c b/sr_vvms/gtm$ce_getinfo.c
new file mode 100644
index 0000000..5ac2c02
--- /dev/null
+++ b/sr_vvms/gtm$ce_getinfo.c
@@ -0,0 +1,136 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2004 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include <ssdef.h>
+#include <descrip.h>
+
+#include "mdef.h"
+#include "svnames.h"
+#include "gtm_ce.h"
+#include "op.h"
+
+
+GBLREF unsigned short source_name_len;
+GBLREF char source_file_name[];
+GBLREF mident routine_name;
+
+
+int4 GTM$CE_GETINFO(uint4 item_code, int4 *resultant_value, struct dsc$descriptor_s resultant_string, uint4 *resultant_length)
+{
+ mval v;
+ char *item_start, *item_string;
+ int4 copy_len, i, pc, pn;
+
+ error_def(ERR_CENOINDIR);
+ error_def(ERR_UNIMPLOP);
+
+
+ switch ((enum GTM$INFO_CODE)item_code)
+ {
+ case GTCE$K_SFN:
+ copy_len = source_name_len;
+ if (copy_len > resultant_string.dsc$w_length)
+ copy_len = resultant_string.dsc$w_length;
+ memcpy (resultant_string.dsc$a_pointer, source_file_name, copy_len);
+ *resultant_length = copy_len;
+ break;
+
+ case GTCE$K_RTN:
+ copy_len = routine_name.len;
+ if (copy_len > resultant_string.dsc$w_length)
+ copy_len = resultant_string.dsc$w_length;
+ memcpy(resultant_string.dsc$a_pointer, routine_name.addr, copy_len);
+ *resultant_length = copy_len;
+ break;
+
+ case GTCE$K_INDIR:
+ stx_error(ERR_CENOINDIR);
+ *resultant_value = 0;
+ break;
+
+ case GTCE$K_ZROU:
+ op_svget (SV_ZROUTINES, &v);
+ copy_len = v.str.len;
+ if (copy_len > resultant_string.dsc$w_length)
+ copy_len = resultant_string.dsc$w_length;
+ memcpy (resultant_string.dsc$a_pointer, v.str.addr, copy_len);
+ *resultant_length = copy_len;
+ break;
+
+ case GTCE$K_ZCOM:
+ op_svget (SV_ZCOMPILE, &v);
+ copy_len = v.str.len;
+ if (copy_len > resultant_string.dsc$w_length)
+ copy_len = resultant_string.dsc$w_length;
+ memcpy (resultant_string.dsc$a_pointer, v.str.addr, copy_len);
+ *resultant_length = copy_len;
+ break;
+
+ case GTCE$K_P1:
+ case GTCE$K_P2:
+ case GTCE$K_P3:
+ case GTCE$K_P4:
+ case GTCE$K_P5:
+ case GTCE$K_P6:
+ case GTCE$K_P7:
+ case GTCE$K_P8:
+ case GTCE$K_CMDLIN:
+ op_svget (SV_ZCMDLINE, &v);
+
+ switch ((enum GTM$INFO_CODE)item_code)
+ {
+ case GTCE$K_CMDLIN: pn = 0; break;
+ case GTCE$K_P1: pn = 1; break;
+ case GTCE$K_P2: pn = 2; break;
+ case GTCE$K_P3: pn = 3; break;
+ case GTCE$K_P4: pn = 4; break;
+ case GTCE$K_P5: pn = 5; break;
+ case GTCE$K_P6: pn = 6; break;
+ case GTCE$K_P7: pn = 7; break;
+ case GTCE$K_P8: pn = 8; break;
+ }
+ item_string = v.str.addr;
+ if (pn == 0)
+ {
+ copy_len = v.str.len;
+ item_start = item_string;
+ }
+ else
+ {
+ pc = pn - 1;
+ i = 0;
+ while (pc > 0 && i++ < v.str.len && *item_string++)
+ {
+ if (*item_string == ',')
+ {
+ pc--;
+ item_string++;
+ i++;
+ }
+ }
+ item_start = item_string;
+ for (copy_len = 0; *item_string++ != ',' && i++ < v.str.len; copy_len++) ;
+ }
+
+ if (copy_len > resultant_string.dsc$w_length)
+ copy_len = resultant_string.dsc$w_length;
+ if (copy_len > 0)
+ memcpy (resultant_string.dsc$a_pointer, item_start, copy_len);
+ *resultant_length = copy_len;
+ break;
+
+ default:
+ rts_error (VARLSTCNT(1) ERR_UNIMPLOP);
+ break;
+ }
+
+ return SS$_NORMAL;
+}
diff --git a/sr_vvms/gtm$compile.c b/sr_vvms/gtm$compile.c
new file mode 100644
index 0000000..bcc53f1
--- /dev/null
+++ b/sr_vvms/gtm$compile.c
@@ -0,0 +1,162 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <ssdef.h>
+#include <descrip.h>
+
+#include "gtm_inet.h"
+
+#include "stp_parms.h"
+#include "stringpool.h"
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "gdscc.h"
+#include "gdskill.h"
+#include "filestruct.h"
+#include "jnl.h"
+#include "buddy_list.h" /* needed for tp.h */
+#include "hashtab_int4.h" /* needed for tp.h */
+#include "tp.h"
+#include "cmd_qlf.h"
+#include "cryptdef.h"
+#include "ladef.h"
+#include "iosp.h"
+#include "repl_msg.h"
+#include "gtmsource.h"
+#include "cli.h"
+#include "op.h"
+#include "io.h"
+#include "source_file.h"
+#include "lmdef.h"
+#include "getjobnum.h"
+#include "ast_init.h"
+#include "comp_esc.h"
+#include "get_page_size.h"
+#include "init_secshr_addrs.h"
+#include "print_exit_stats.h"
+#include "gtm_env_init.h" /* for gtm_env_init() prototype */
+#include "gtm_threadgbl_init.h"
+#include "gtmimagename.h"
+#include "gtm_imagetype_init.h"
+
+GBLREF int (*op_open_ptr)(mval *v, mval *p, int t, mval *mspace);
+GBLREF boolean_t run_time;
+GBLREF command_qualifier glb_cmd_qlf, cmd_qlf;
+GBLREF bool licensed;
+GBLREF int4 lkid, lid;
+GBLREF spdesc rts_stringpool, stringpool;
+
+error_def (LP_NOCNFDB);
+error_def (ERR_WILLEXPIRE);
+
+OS_PAGE_SIZE_DECLARE
+
+LITREF char gtm_product[PROD];
+LITREF int4 gtm_product_len;
+LITREF char gtm_version[VERS];
+LITREF int4 gtm_version_len;
+
+#define FILE_NAME_SIZE 255
+
+int gtm$compile(void)
+{
+ unsigned short len;
+ char source_file_string[FILE_NAME_SIZE + 1],
+ obj_file[FILE_NAME_SIZE + 1],
+ list_file[FILE_NAME_SIZE + 1],
+ ceprep_file[FILE_NAME_SIZE + 1];
+ int4 status;
+ int4 inid = 0;
+ int4 nid = 0; /* node number */
+ int4 days = 128; /* days to expiration */
+ int4 lic_x = 0; /* license value */
+ char *h = NULL; /* license data base */
+ char *pak = NULL; /* pak record */
+ int4 mdl = 0; /* hardw. model type */
+ $DESCRIPTOR (dprd, gtm_product);
+ $DESCRIPTOR (dver, gtm_version);
+ DCL_THREADGBL_ACCESS;
+
+ GTM_THREADGBL_INIT; /* This is the first C routine in the VMS compiler so do init here */
+ gtm_env_init(); /* read in all environment variables before any function call (particularly malloc) */
+ gtm_imagetype_init(GTM_IMAGE); /* While compile-only, pretending GTM_IMAGE is sufficient */
+ op_open_ptr = op_open;
+ licensed = TRUE;
+# ifdef NOLICENSE
+ status = SS$_NORMAL;
+ lid = 1;
+ lic_x = 32767;
+# else
+ if (NULL == (h = la_getdb(LMDB))) /* license db in mem */
+ status = LP_NOCNFDB;
+ else
+ status = SS$_NORMAL;
+ if (1 == (status & 1)) /* licensing: node + system */
+ status = lm_mdl_nid(&mdl, &nid, &inid);
+ if (1 == (status & 1)) /* licensing: license */
+ {
+ dprd.dsc$w_length = gtm_product_len;
+ dver.dsc$w_length = gtm_version_len;
+ status = lp_licensed(h, &dprd, &dver, mdl, nid, &lid, &lic_x, &days, pak);
+ }
+# endif
+ get_page_size();
+ getjobnum();
+ INVOKE_INIT_SECSHR_ADDRS;
+ if (1 == (status & 1)) /* licensing: license units */
+ status = LP_ACQUIRE(pak, lic_x, lid, &lkid);
+ ast_init();
+ io_init(TRUE);
+ stp_init(STP_INITSIZE);
+ rts_stringpool = stringpool;
+ run_time = FALSE;
+ TREF(compile_time) = TRUE;
+# ifdef NOLICENSE
+ status = SS$_NORMAL;
+# else
+ if (LP_NOCNFDB != status)
+ la_freedb(h);
+ if (1 == (status & 1)) /* licensing */
+ {
+ if (days < 14)
+ lm_putmsgu(ERR_WILLEXPIRE, 0, 0);
+ } else
+ {
+ licensed = FALSE;
+ rts_error(VARLSTCNT(1) status);
+ }
+# endif
+ glb_cmd_qlf.object_file.str.addr = obj_file;
+ glb_cmd_qlf.object_file.str.len = FILE_NAME_SIZE;
+ glb_cmd_qlf.list_file.str.addr = list_file;
+ glb_cmd_qlf.list_file.str.len = FILE_NAME_SIZE;
+ glb_cmd_qlf.ceprep_file.str.addr = ceprep_file;
+ glb_cmd_qlf.ceprep_file.str.len = FILE_NAME_SIZE;
+ get_cmd_qlf(&glb_cmd_qlf);
+ ce_init(); /* initialize compiler escape processing */
+ TREF(dollar_zcstatus) = SS$_NORMAL;
+ len = FILE_NAME_SIZE;
+ for (status = cli_get_str("INFILE", source_file_string, &len);
+ status;
+ status = cli_get_str("INFILE", source_file_string, &len))
+ {
+ compile_source_file(len, source_file_string, TRUE);
+ len = FILE_NAME_SIZE;
+ }
+ print_exit_stats();
+ io_rundown(NORMAL_RUNDOWN);
+ return TREF(dollar_zcstatus);
+}
diff --git a/sr_vvms/gtm$dmod.m b/sr_vvms/gtm$dmod.m
new file mode 100644
index 0000000..76181c6
--- /dev/null
+++ b/sr_vvms/gtm$dmod.m
@@ -0,0 +1 @@
+ F B
diff --git a/sr_vvms/gtm$interrupt.c b/sr_vvms/gtm$interrupt.c
new file mode 100644
index 0000000..a9d8291
--- /dev/null
+++ b/sr_vvms/gtm$interrupt.c
@@ -0,0 +1,42 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "io.h"
+#include "iottdef.h"
+#include "outofband.h"
+#include "deferred_events.h"
+
+GBLREF io_pair io_std_device;
+GBLREF bool std_dev_outbnd;
+
+void gtm$interrupt(int4 ob_char)
+{
+ uint4 mask;
+ d_tt_struct *tt_ptr;
+
+ if (io_std_device.in->type != tt || ob_char > MAXOUTOFBAND)
+ return;
+
+ tt_ptr = (d_tt_struct *) io_std_device.in->dev_sp;
+ std_dev_outbnd = TRUE;
+ mask = 1 << ob_char;
+ if (mask & tt_ptr->enbld_outofbands.mask)
+ { ctrap_set(ob_char);
+ }
+ else if (mask & CTRLC_MSK)
+ { ctrlc_set(0);
+ }
+ else if (mask & CTRLY_MSK)
+ { ctrly_set(0);
+ }
+ return;
+}
diff --git a/sr_vvms/gtm$ivp.tlb b/sr_vvms/gtm$ivp.tlb
new file mode 100644
index 0000000..e0b2c5a
Binary files /dev/null and b/sr_vvms/gtm$ivp.tlb differ
diff --git a/sr_vvms/gtm$startup.c b/sr_vvms/gtm$startup.c
new file mode 100644
index 0000000..f71b5cd
--- /dev/null
+++ b/sr_vvms/gtm$startup.c
@@ -0,0 +1,452 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <efndef.h>
+#include <descrip.h>
+#include <jpidef.h>
+#include <prvdef.h>
+#include <ssdef.h>
+#include <starlet.h>
+#include <stsdef.h>
+
+#include "gtm_limits.h"
+#include "gtm_inet.h"
+#include "gtm_string.h"
+
+#include "gdsroot.h"
+#include <rtnhdr.h>
+#include "stack_frame.h"
+#include "stringpool.h"
+#include "stp_parms.h"
+#include "zcall.h"
+#include "cryptdef.h"
+#include "mv_stent.h"
+#include "startup.h"
+#include "ladef.h"
+#include "io.h"
+#include "iottdef.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "gdscc.h"
+#include "cmd_qlf.h"
+#include "gdskill.h"
+#include "filestruct.h"
+#include "error.h" /* for EXIT_HANDLER macro used in SET_EXIT_HANDLER macro */
+#include "jnl.h"
+#include "buddy_list.h" /* needed for tp.h */
+#include "hashtab_int4.h" /* needed for tp.h */
+#include "tp.h"
+#include "collseq.h"
+#ifndef __vax
+# include "fnpc.h"
+#endif
+#include "desblk.h"
+#include "repl_msg.h"
+#include "gtmsource.h"
+#include "gtmimagename.h"
+#include "cache.h"
+#include "op.h"
+#include "patcode.h"
+#include "dpgbldir_sysops.h" /* for dpzgbini prototype */
+#include "dfntmpmbx.h"
+#include "ast_init.h"
+#include "comp_esc.h"
+#include "repl_sp.h"
+#include "mprof.h"
+#include "init_secshr_addrs.h"
+#include "getzmode.h"
+#include "getzprocess.h"
+#include "gtmmsg.h"
+#include "tp_timeout.h"
+#include "getjobname.h"
+#include "error_trap.h" /* for ecode_init() prototype */
+#include "zyerror_init.h"
+#include "generic_exit_handler.h"
+#include "ztrap_form_init.h"
+#include "zdate_form_init.h"
+#include "dollar_system_init.h"
+#include "gtm_env_xlate_init.h"
+#include "zco_init.h"
+#include "svnames.h"
+#include "getzdir.h"
+#include "jobinterrupt_init.h"
+#include "gtm_env_init.h" /* for gtm_env_init() prototype */
+#include "gtm_logicals.h" /* for DISABLE_ALIGN_STRINGS */
+#include "logical_truth_value.h"
+#include "zwrite.h"
+#include "gtm_imagetype_init.h"
+#include "gtm_threadgbl_init.h"
+
+#define FREE_RTNTBL_SPACE 17
+#define MIN_INDIRECTION_NESTING 32
+#define MAX_INDIRECTION_NESTING 256
+#define MAX_IO_TIMER 60000000
+#define MIN_IO_TIMER 1000000
+
+GBLDEF zctabrtn *zctab, *zctab_end;
+GBLDEF zcpackage *zcpack_start, *zcpack_end;
+GBLDEF unsigned char *gtm_main_address; /* Save the address of gtm_main, for use by tir */
+GBLDEF bool init_done = FALSE;
+GBLDEF uint4 trust = 0;
+GBLDEF mval original_cwd;
+GBLDEF unsigned char original_cwd_buff[PATH_MAX + PATH_MAX]; /* device + directory */
+
+GBLREF desblk exi_blk;
+GBLREF void (*tp_timeout_start_timer_ptr)(int4 tmout_sec);
+GBLREF void (*tp_timeout_clear_ptr)(void);
+GBLREF void (*tp_timeout_action_ptr)(void);
+GBLREF int (*op_open_ptr)(mval *v, mval *p, int t, mval *mspace);
+GBLREF void (*unw_prof_frame_ptr)(void);
+GBLREF rtn_tabent *rtn_fst_table, *rtn_names, *rtn_names_top, *rtn_names_end;
+GBLREF int4 break_message_mask;
+GBLREF int4 exi_condition;
+GBLREF int4 write_filter;
+GBLREF int4 spc_inp_prc;
+GBLREF uint4 image_count;
+GBLREF stack_frame *frame_pointer;
+GBLREF unsigned char *stackbase, *stacktop, *stackwarn, *msp;
+GBLREF mv_stent *mv_chain;
+GBLREF bool undef_inhibit;
+GBLREF uint4 iott_write_delay[2];
+GBLREF int (* volatile xfer_table[])();
+GBLREF mval dollar_ztrap;
+GBLREF mval dollar_zstatus;
+GBLREF mval dollar_zdir;
+GBLREF spdesc stringpool;
+GBLREF spdesc rts_stringpool;
+GBLREF command_qualifier glb_cmd_qlf, cmd_qlf;
+GBLREF int4 zdir_form;
+GBLREF int mumps_status;
+GBLREF boolean_t is_replicator;
+GBLREF int dollar_truth;
+GBLREF boolean_t mstr_native_align;
+GBLREF void (*cache_table_relobjs)(void); /* Function pointer to call cache_table_rebuild() */
+GBLREF symval *curr_symval;
+GBLREF boolean_t skip_dbtriggers;
+OS_PAGE_SIZE_DECLARE
+
+error_def(ERR_LINKVERSION);
+error_def(ERR_WILLEXPIRE);
+error_def(LP_NOCNFDB); /* No license data base */
+error_def(ERR_COLLATIONUNDEF);
+
+static readonly mstr lnm$group = {9, "LNM$GROUP"};
+
+/* Licensing */
+GBLREF bool licensed;
+GBLREF int4 lkid, lid;
+
+LITREF char gtm_product[PROD];
+LITREF int4 gtm_product_len;
+LITREF char gtm_version[VERS];
+LITREF int4 gtm_version_len;
+/* End of Licensing */
+
+error_def(ERR_COLLATIONUNDEF);
+error_def(ERR_LINKVERSION);
+error_def(ERR_WILLEXPIRE);
+error_def(LP_NOCNFDB); /* No license data base */
+
+void gtm$startup(struct startup_vector *svec, boolean_t is_dal)
+/* Note: various references to data copied from *svec could profitably be referenced directly */
+{
+ char *mstack_ptr;
+ unsigned char *base_address, *transfer_address;
+ void dfnlnm$tmpmbx();
+ static readonly unsigned char init_break[1] = {'B'};
+ int4 lct;
+ int i;
+ mstr log_name;
+ mstr val;
+ boolean_t ret, is_defined;
+ char buff[MAX_FN_LEN];
+ DCL_THREADGBL_ACCESS;
+
+ uint4 imagpriv, trust_status;
+ typedef struct {
+ short buflen;
+ short itmcode;
+ void *buffer;
+ void *retlen;
+ } ITMLST;
+ ITMLST item_list[2] = {
+ { 4, JPI$_IMAGPRIV, &imagpriv, 0},
+ { 0, 0, 0, 0} };
+
+ /* Licensing */
+ int4 status;
+ int4 inid;
+ int4 nid; /* node number */
+ int4 days; /* days to expiration */
+ int4 lic_x; /* license value */
+ char *h; /* license data base */
+ char *pak; /* pak record */
+ int4 mdl; /* hardw. model type */
+ struct dsc$descriptor_s dprd, dver;
+ /* End of Licensing */
+
+ /* While normally gtm$startup is only called once per process, when the invocation method is through
+ * call-ins, it is invoked on every call-in so we need to be able to handle the case that we are already
+ * initialized. The main "flag" for this is the init_done global variable but since that flag may one day
+ * move into the gtm_threadgbl framework (even though VMS will never be threaded), we instead test the
+ * threadgbl base variable to see if it is initialized or not and bypass threadgbl initialization if so.
+ */
+ if (NULL == gtm_threadgbl)
+ {
+ GTM_THREADGBL_INIT; /* This is the first C routine in VMS so do init here */
+ }
+ cache_table_relobjs = &cache_table_rebuild;
+ /* If we get any errors signalled during initialization, don't let the process
+ * continue under any circumstances. This condition handler enforces that.
+ */
+ lib$establish(lib$sig_to_stop);
+ assert(BITS_PER_UCHAR == 8);
+ /* When items are added to svec, but recompilation of a new release is not
+ * required, appropriate "if (svec->argcnt < ?)" statements should be
+ * added here to establish defaults. The computed defaults may all be removed
+ * for each release where recompilation is required.
+ */
+ tp_timeout_start_timer_ptr = tp_start_timer;
+ tp_timeout_clear_ptr = tp_clear_timeout;
+ tp_timeout_action_ptr = tp_timeout_action;
+ op_open_ptr = op_open;
+ unw_prof_frame_ptr = unw_prof_frame;
+ if (SIZEOF(*svec) != svec->argcnt)
+ rts_error(VARLSTCNT(1) ERR_LINKVERSION);
+ if (!init_done)
+ {
+ gtm_imagetype_init(GTM_IMAGE);
+ gtm_env_init(); /* read in all environment variables */
+ if ((!is_dal) && 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);
+ licensed = TRUE;
+ pak = NULL;
+# ifdef NOLICENSE
+ status = SS$_NORMAL;
+ h = NULL;
+# else
+ if (NULL == (h = la_getdb(LMDB))) /* license db in mem */
+ status = LP_NOCNFDB;
+ else
+ status = SS$_NORMAL;
+# endif
+ get_page_size();
+ /* note: for upward compatibility, missing values in the startup vector can be set to defaults */
+ get_proc_info(0, TADR(login_time), &image_count);
+ gtm_main_address = svec->gtm_main_inaddr;
+ ast_init();
+ rtn_fst_table = rtn_names = (rtn_tabent *)svec->rtn_start;
+ rtn_names_end = (rtn_tabent *)svec->rtn_end - 1;
+ rtn_names_top = (rtn_tabent *)svec->rtn_end + FREE_RTNTBL_SPACE - 1;
+ rtn_tbl_sort(rtn_names, rtn_names_end);
+ fgncal_zlinit();
+ zctab = (zctabrtn *)svec->zctable_start;
+ zctab_end = (zctabrtn *)svec->zctable_end;
+ zcpack_start = (zcpackage *)svec->zcpackage_begin;
+ zcpack_end = (zcpackage *)svec->zcpackage_end;
+ svec->xf_tab = &xfer_table[0];
+ svec->dlr_truth = &dollar_truth;
+ 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);
+ else if (imagpriv & PRV$M_CMEXEC)
+ trust = svec->user_spawn_flag;
+ }
+ if (svec->user_stack_size < 4096)
+ svec->user_stack_size = 4096;
+ if (svec->user_stack_size > 8388608)
+ svec->user_stack_size = 8388608;
+ mstack_ptr = malloc(svec->user_stack_size);
+ msp = stackbase = mstack_ptr + svec->user_stack_size - mvs_size[MVST_STORIG];
+ mv_chain = (mv_stent *)msp;
+ mv_chain->mv_st_type = MVST_STORIG; /* Initialize first (anchor) mv_stent so doesn't do anything */
+ mv_chain->mv_st_next = 0;
+ mv_chain->mv_st_cont.mvs_storig = 0;
+ stacktop = mstack_ptr + 2 * mvs_size[MVST_NTAB];
+ stackwarn = stacktop + 1024;
+ if (!svec->labels)
+ glb_cmd_qlf.qlf &= ~CQ_LOWER_LABELS;
+ cmd_qlf.qlf = glb_cmd_qlf.qlf;
+ break_message_mask = svec->break_message_mask;
+ undef_inhibit = svec->undef_inhib;
+ TREF(lv_null_subs) = svec->lvnullsubs;
+ zdir_form = svec->zdir_form;
+ if (!IS_VALID_ZDIR_FORM(zdir_form))
+ zdir_form = ZDIR_FORM_FULLPATH;
+ write_filter = 0;
+ if (svec->user_write_filter & CHAR_FILTER)
+ write_filter |= CHAR_FILTER;
+ if (svec->user_write_filter & ESC1)
+ write_filter |= ESC1;
+ spc_inp_prc = svec->special_input;
+ if (svec->user_strpl_size < STP_INITSIZE)
+ svec->user_strpl_size = STP_INITSIZE;
+ else if (svec->user_strpl_size > STP_MAXINITSIZE)
+ svec->user_strpl_size = STP_MAXINITSIZE;
+ stp_init(svec->user_strpl_size);
+ if ((svec->user_io_timer < MAX_IO_TIMER) && (svec->user_io_timer > MIN_IO_TIMER))
+ iott_write_delay[0] = -svec->user_io_timer;
+ rts_stringpool = stringpool;
+ TREF(compile_time) = FALSE;
+ assert(run_time); /* Should have been set by gtm_imagetype_init */
+ /* Initialize alignment requirement for the runtime stringpool */
+ log_name.addr = DISABLE_ALIGN_STRINGS;
+ log_name.len = STR_LIT_LEN(DISABLE_ALIGN_STRINGS);
+ /* mstr_native_align = logical_truth_value(&log_name, FALSE, NULL) ? FALSE : TRUE; */
+ mstr_native_align = FALSE; /* TODO: remove this line and uncomment the above line */
+ getjobname();
+ DEBUG_ONLY(util_out_open(0));
+ INVOKE_INIT_SECSHR_ADDRS;
+# ifdef NOLICENSE
+ status = SS$_NORMAL;
+ mdl = nid = inid = 0;
+# else
+ if (1 == (status & 1)) /* licensing: node+ system */
+ {
+ mdl = nid = inid = 0;
+ status = lm_mdl_nid(&mdl, &nid, &inid);
+ }
+# endif
+ dfntmpmbx(lnm$group.len, lnm$group.addr);
+ if (svec->base_addr)
+ base_address = svec->base_addr - SIZEOF(frame_pointer->rvector->jsb);
+# ifdef NOLICENSE
+ status = SS$_NORMAL;
+ lid = 1;
+ lic_x = 32767;
+ days = 128;
+# else
+ if (1 == (status & 1)) /* licensing: license */
+ {
+ dprd.dsc$w_length = gtm_product_len;
+ dprd.dsc$a_pointer = gtm_product;
+ dver.dsc$w_length = gtm_version_len;
+ dver.dsc$a_pointer = gtm_version;
+ status = lp_licensed(h, &dprd, &dver, mdl, nid, &lid, &lic_x, &days, pak);
+ }
+# endif
+ if (1 == (status & 1)) /* licensing: license units */
+ status = LP_ACQUIRE(pak, lic_x, lid, &lkid); /* def in cryptdef */
+# ifdef NOLICENSE
+ status = SS$_NORMAL;
+# else
+ if (LP_NOCNFDB != status)
+ la_freedb(h);
+ if (1 == (status & 1)) /* licensing */
+ {
+ licensed = TRUE;
+ if (days < 14)
+ la_putmsgu(ERR_WILLEXPIRE, 0, 0);
+ } else
+ {
+ licensed = FALSE;
+ rts_error(VARLSTCNT(1) status);
+ }
+# endif
+ jobinterrupt_init();
+ getzprocess();
+ getzmode();
+ /* Now that we let users change cwd (set $zdir), we want to save cwd so that we can restore cwd at exit. */
+ /* We save cwd at startup to workaround bug (?) documented in setzdir() regarding chdir() */
+ /* We don't want to place original_cwd in the stringpool 'cos it doesn't change over the life of a process. */
+ /* By placing original_cwd in a pre-allocated buffer, we avoid making original_cwd a part of gcol passes. */
+ getzdir(); /* get current working directory at startup */
+ original_cwd = dollar_zdir;
+ original_cwd.str.addr = original_cwd_buff;
+ memcpy(original_cwd_buff, dollar_zdir.str.addr, dollar_zdir.str.len);
+ cache_init();
+ zco_init();
+ frame_pointer = msp -= SIZEOF(stack_frame) + SIZEOF(rhdtyp);
+ memset(frame_pointer, 0, SIZEOF(stack_frame) + SIZEOF(rhdtyp));
+ frame_pointer->type = SFT_COUNT;
+ frame_pointer->rvector = (rhdtyp *)((char *)frame_pointer + SIZEOF(stack_frame));
+ symbinit();
+ if (svec->base_addr)
+ {
+ base_frame(base_address);
+ jobchild_init(base_address);
+ }
+ dpzgbini();
+ svec->frm_ptr = frame_pointer;
+ io_init(svec->ctrlc_enable);
+ dollar_ztrap.mvtype = MV_STR;
+ dollar_ztrap.str.len = SIZEOF(init_break);
+ dollar_ztrap.str.addr = init_break;
+ dollar_zstatus.mvtype = MV_STR;
+ dollar_zstatus.str.len = 0;
+ dollar_zstatus.str.addr = NULL;
+ ecode_init();
+ zyerror_init();
+ ztrap_form_init();
+ zdate_form_init(svec);
+ dollar_system_init(svec);
+ gtm_env_xlate_init();
+ initialize_pattern_table();
+ /* Initialize compiler escape feature */
+ ce_init();
+ /* Initialize local collating sequence */
+ TREF(transform) = TRUE;
+ lct = find_local_colltype();
+ if (0 != lct)
+ {
+ TREF(local_collseq) = ready_collseq(lct);
+ if (!TREF(local_collseq))
+ {
+ exi_condition = ERR_COLLATIONUNDEF;
+ gtm_putmsg(VARLSTCNT(3) ERR_COLLATIONUNDEF, 1, lct);
+ op_halt();
+ }
+ } else
+ TREF(local_collseq) = NULL;
+ /* Initialize zwrite subsystem. Better to do it now when we have storage to allocate than
+ * if we fail and storage allocation may not be possible. To that end, pretend we have
+ * seen alias acitivity so those structures are initialized as well.
+ */
+ assert(FALSE == curr_symval->alias_activity);
+ curr_symval->alias_activity = TRUE;
+ lvzwr_init(0, (mval *)NULL);
+ 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++)
+ {
+ (TREF(fnpca)).fnpcs[i].pcoffmax = &(TREF(fnpca)).fnpcs[i].pstart[FNPC_ELEM_MAX];
+ (TREF(fnpca)).fnpcs[i].indx = i;
+ }
+ (TREF(fnpca)).fnpcsteal = &(TREF(fnpca)).fnpcs[0]; /* Starting place to look for cache reuse */
+ (TREF(fnpca)).fnpcmax = &(TREF(fnpca)).fnpcs[FNPC_MAX - 1]; /* The last element */
+ /* until this point all signals run down the process. That sounds reasonable since we're not executing any
+ * of the customers code and we wouldn't know how to cope anyway. Now we can cope so establish
+ * the mdb_condition_handler.
+ */
+ *svec->fp = mdb_condition_handler;
+ SET_EXIT_HANDLER(exi_blk, generic_exit_handler, exi_condition); /* Establish exit handler */
+ init_done = TRUE;
+ } else
+ {
+ if (svec->base_addr)
+ { base_address = svec->base_addr - SIZEOF(frame_pointer->rvector->jsb);
+ transfer_address = base_address + SIZEOF(rhdtyp);
+ svec->xf_tab = &xfer_table[0];
+ base_frame(base_address);
+ new_stack_frame(base_address, transfer_address, transfer_address);
+ svec->frm_ptr = frame_pointer;
+ *svec->fp = mdb_condition_handler;
+ mumps_status = SS$_NORMAL;
+ }
+ }
+ lib$revert(); /* from lib$sig_to_stop establish */
+ return;
+}
diff --git a/sr_vvms/gtm_bintim.c b/sr_vvms/gtm_bintim.c
new file mode 100644
index 0000000..15143ac
--- /dev/null
+++ b/sr_vvms/gtm_bintim.c
@@ -0,0 +1,65 @@
+/****************************************************************
+ * *
+ * Copyright 2003 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+
+#include "mdef.h"
+
+#include <ssdef.h>
+#include <descrip.h>
+#include <climsgdef.h>
+#include <jpidef.h>
+#include <fab.h>
+#include <rab.h>
+#include <nam.h>
+#include <rmsdef.h>
+#include <math.h> /* for SECOND2EPOCH_SECOND macro */
+
+#include "gtm_string.h"
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "jnl.h" /* jnl_proc_time needs this. jnl.h needs some of the above */
+#include "gtm_bintim.h"
+
+int gtm_bintim(char *toscan, jnl_proc_time *timep)
+{
+ uint4 status;
+ $DESCRIPTOR (qual_dsc, toscan);
+ int len = strlen(toscan);
+ jnl_proc_time jptime;
+
+ jptime = *timep;
+ /* remove quotes */
+ while (toscan[len - 1] == '"')
+ --len;
+ while ('"' == *qual_dsc.dsc$a_pointer)
+ {
+ --len;
+ ++qual_dsc.dsc$a_pointer;
+ }
+ qual_dsc.dsc$w_length = len;
+ status = sys$bintim(&qual_dsc,&jptime);
+ if (0 > jptime)
+ { /* delta time will be a negative value */
+ jptime = MID_TIME(-(jptime)); /* convert to JNL_SHORT_TIME format */
+ jptime = -(jptime);
+ } else
+ jptime = MID_TIME(jptime); /* convert to JNL_SHORT_TIME format */
+
+ *timep = jptime;
+ if (SS$_NORMAL == status)
+ return 0;
+ else
+ return -1;
+}
diff --git a/sr_vvms/gtm_blkast.c b/sr_vvms/gtm_blkast.c
new file mode 100644
index 0000000..5a3c94c
--- /dev/null
+++ b/sr_vvms/gtm_blkast.c
@@ -0,0 +1,41 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <lckdef.h>
+#include <psldef.h>
+#include <efndef.h>
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "locks.h"
+
+void gtm_blkast(gd_region *region)
+{
+ vms_gds_info *vbi;
+
+ if (region != NULL)
+ {
+ vbi = FILE_INFO(region);
+ gtm_deq(vbi->file_cntl_lsb.lockid, NULL, PSL$C_USER, LCK$M_CANCEL);
+ gtm_enqw(EFN$C_ENF, LCK$K_PWMODE, &vbi->file_cntl_lsb, LCK$M_CONVERT, NULL, 0,
+ NULL, 0, NULL, PSL$C_USER, 0);
+ /* Update the lock value block and reestablish the blocking AST */
+ vbi->file_cntl_lsb.valblk[0] = region->node;
+ gtm_enq(0, LCK$K_CRMODE, &vbi->file_cntl_lsb, LCK$M_CONVERT | LCK$M_VALBLK, NULL, 0,
+ NULL, region, gtm_blkast, PSL$C_USER, 0);
+ }
+}
diff --git a/sr_vvms/gtm_ce.h b/sr_vvms/gtm_ce.h
new file mode 100644
index 0000000..4e6a5d3
--- /dev/null
+++ b/sr_vvms/gtm_ce.h
@@ -0,0 +1,28 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+enum GTM$INFO_CODE
+{
+ GTCE$K_SFN,
+ GTCE$K_RTN,
+ GTCE$K_INDIR,
+ GTCE$K_ZROU,
+ GTCE$K_ZCOM,
+ GTCE$K_CMDLIN,
+ GTCE$K_P1,
+ GTCE$K_P2,
+ GTCE$K_P3,
+ GTCE$K_P4,
+ GTCE$K_P5,
+ GTCE$K_P6,
+ GTCE$K_P7,
+ GTCE$K_P8
+} ;
diff --git a/sr_vvms/gtm_conv.c b/sr_vvms/gtm_conv.c
new file mode 100644
index 0000000..a0b5c80
--- /dev/null
+++ b/sr_vvms/gtm_conv.c
@@ -0,0 +1,38 @@
+/****************************************************************
+ * *
+ * Copyright 2006 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_conv.h"
+
+/* These are dummy routines to allow code to compile/link on VMS. These routines are not
+ used but elimination of them from the code is detremental to the clarify of the UNIX
+ codebase and since Alpha/VMS is a dead platform, these dummy routines also have a
+ limited lifespan.. 9/2006 SE
+*/
+
+LITDEF mstr chset_names[CHSET_MAX_IDX];
+GBLDEF UConverter *chset_desc[CHSET_MAX_IDX];
+
+UConverter* get_chset_desc(const mstr *chset)
+{
+ GTMASSERT;
+}
+
+int gtm_conv(UConverter* from, UConverter* to, mstr* src, char* dstbuff, int* bufflen)
+{
+ GTMASSERT;
+}
+
+int verify_chset(const mstr *parm)
+{
+ GTMASSERT;
+}
diff --git a/sr_vvms/gtm_conv.h b/sr_vvms/gtm_conv.h
new file mode 100644
index 0000000..a28d6a3
--- /dev/null
+++ b/sr_vvms/gtm_conv.h
@@ -0,0 +1,27 @@
+/****************************************************************
+ * *
+ * Copyright 2006 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef GTM_CONV_H
+#define GTM_CONV_H
+
+/* Define types for use by compilation in VMS in code paths that will never be
+ used. This was the preferred method of making the Unicode modified UNIX code
+ work in VMS rather than butchering it with ifdefs making maintenance more
+ difficult. 9/2006 SE
+*/
+
+typedef int UConverter;
+
+UConverter* get_chset_desc(const mstr *chset);
+int gtm_conv(UConverter* from, UConverter* to, mstr* src, char* dstbuff, int* bufflen);
+int verify_chset(const mstr *parm);
+
+#endif /* GTM_CONV_H */
diff --git a/sr_vvms/gtm_deq.c b/sr_vvms/gtm_deq.c
new file mode 100644
index 0000000..7077af7
--- /dev/null
+++ b/sr_vvms/gtm_deq.c
@@ -0,0 +1,67 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <lkidef.h>
+#include <lckdef.h>
+#include <prvdef.h>
+#include <ssdef.h>
+#include <efndef.h>
+
+#include "gtmsecshr.h"
+#include "locks.h"
+#include "vmsdtype.h"
+
+GBLREF uint4 rundown_process_id;
+GBLREF lock_sb vms_lock_list[MAX_VMS_LOCKS + 1];
+GBLREF int vms_lock_tail;
+
+uint4 gtm_deq(unsigned int lkid, void *valblk, unsigned int acmode, unsigned int flags)
+{
+ struct
+ {
+ item_list_3 item[1];
+ int4 terminator;
+ } item_list;
+ unsigned short iosb[4];
+ int index;
+ uint4 lk_pid = 0, retlen, status;
+ uint4 prvadr[2], prvprv[2];
+
+ item_list.item[0].buffer_length = SIZEOF(lk_pid);
+ item_list.item[0].item_code = LKI$_PID;
+ item_list.item[0].buffer_address = &lk_pid;
+ item_list.item[0].return_length_address = &retlen;
+ item_list.terminator = 0;
+ if ((SS$_NORMAL == (status = sys$getlkiw(EFN$C_ENF, &lkid, &item_list, iosb, NULL, 0, 0)))
+ && (lk_pid == rundown_process_id))
+ {
+ GTMSECSHR_SET_DBG_PRIV(PRV$M_SYSLCK, status);
+ if (SS$_NORMAL == status)
+ {
+ status = sys$deq(lkid, valblk, acmode, flags);
+ if ((status & 1) && !(flags & LCK$M_CANCEL))
+ {
+ for (index = 0; index < vms_lock_tail; index++)
+ {
+ if (vms_lock_list[index].lockid == lkid)
+ {
+ vms_lock_list[index].lockid = 0;
+ break;
+ }
+ }
+ }
+ GTMSECSHR_REL_DBG_PRIV;
+ }
+ }
+ return status;
+}
diff --git a/sr_vvms/gtm_enq.c b/sr_vvms/gtm_enq.c
new file mode 100644
index 0000000..a3ae073
--- /dev/null
+++ b/sr_vvms/gtm_enq.c
@@ -0,0 +1,53 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <lckdef.h>
+#include <prvdef.h>
+#include <ssdef.h>
+
+#include "gtmsecshr.h"
+#include "locks.h"
+
+/* while this has the same interface as sys$enq, it is intended only for conversions
+ * in order to record the lock in the list of locks to deq at image termination,
+ * the lock must first be taken out (generally in NL mode with gtm_enqw() */
+uint4 gtm_enq(
+ unsigned int efn,
+ unsigned int lkmode,
+ lock_sb *lsb,
+ unsigned int flags,
+ void *resnam,
+ unsigned int parid,
+ void *astadr,
+ unsigned int astprm,
+ void *blkast,
+ unsigned int acmode,
+ unsigned int nullarg)
+{
+ uint4 status;
+ uint4 prvadr[2], prvprv[2];
+
+ GTMSECSHR_SET_DBG_PRIV(PRV$M_SYSLCK, status);
+ if (SS$_NORMAL == status)
+ {
+ if ((flags & LCK$M_CONVERT) && lsb->lockid)
+ status = sys$enq(efn, lkmode, lsb, flags, resnam, parid, astadr, astprm, blkast, acmode, nullarg);
+ else
+ status = SS$_CVTUNGRANT;
+ /* the above is an indication to the caller that the lock was not first established in NL mode
+ * with gtm_enqw, so that it is registered in vms_lock_list in case of process termination
+ * if circumstances turn nasty, that condition can lead to a hang so don't permit it */
+ GTMSECSHR_REL_DBG_PRIV;
+ }
+ return status;
+}
diff --git a/sr_vvms/gtm_enqw.c b/sr_vvms/gtm_enqw.c
new file mode 100644
index 0000000..1dc3284
--- /dev/null
+++ b/sr_vvms/gtm_enqw.c
@@ -0,0 +1,88 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <lckdef.h>
+#include <prvdef.h>
+#include <ssdef.h>
+
+#include "gtmsecshr.h"
+#include "locks.h"
+#include "probe.h"
+
+GBLDEF lock_sb vms_lock_list[MAX_VMS_LOCKS + 1];
+GBLDEF int vms_lock_tail;
+
+/* see also gtm_enq */
+uint4 gtm_enqw(
+ unsigned int efn,
+ unsigned int lkmode,
+ lock_sb *lsb,
+ unsigned int flags,
+ void *resnam,
+ unsigned int parid,
+ void *astadr,
+ unsigned int astprm,
+ void *blkast,
+ unsigned int acmode,
+ unsigned int nullarg)
+{
+ int index;
+ uint4 status;
+ uint4 prvadr[2], prvprv[2];
+
+ GTMSECSHR_SET_DBG_PRIV(PRV$M_SYSLCK, status);
+ if (SS$_NORMAL == status)
+ {
+ /* send the vms_lock_list element in place of the lsb
+ * to ensure that the list is up to date in case of a sudden loss of cabin pressure */
+ if (!GTM_PROBE(SIZEOF(*lsb), (unsigned char *)lsb, READ))
+ return SS$_ACCVIO;
+ vms_lock_list[vms_lock_tail] = *lsb;
+ status = sys$enqw(efn, lkmode, &vms_lock_list[vms_lock_tail], flags, resnam, parid,
+ astadr, astprm, blkast, acmode, nullarg);
+ *lsb = vms_lock_list[vms_lock_tail];
+ if (SS$_NORMAL == status)
+ status = lsb->cond;
+ if (SS$_NORMAL == status)
+ {
+ if (!(flags & LCK$M_CONVERT))
+ {
+ if (vms_lock_tail < MAX_VMS_LOCKS)
+ vms_lock_tail++;
+ else /* vms_lock_tail basically sticks at MAX_VMS_LOCKS once it hits it */
+ { /* the following looks for open slots to reuse */
+ for (index = 0; index < vms_lock_tail; index++)
+ {
+ if (0 == vms_lock_list[index].lockid)
+ {
+ vms_lock_list[index] = *lsb;
+ vms_lock_list[vms_lock_tail].lockid = 0;
+ break;
+ }
+ }
+ if (index >= vms_lock_tail)
+ { /* if no open slots, release the lock */
+ (void)sys$deq(vms_lock_list[vms_lock_tail].lockid, 0, acmode, flags);
+ /* the following should be interpretted by the caller as too many database files;
+ * borrowing the condition code avoids merrors, and "should" never happen,
+ * as GT.M only nests sub-locks to a depth of 1 */
+ status = SS$_EXDEPTH;
+ }
+ }
+ }
+ } else
+ vms_lock_list[vms_lock_tail].lockid = 0;
+ GTMSECSHR_REL_DBG_PRIV;
+ }
+ return status;
+}
diff --git a/sr_vvms/gtm_env_init_sp.c b/sr_vvms/gtm_env_init_sp.c
new file mode 100644
index 0000000..1dc8e98
--- /dev/null
+++ b/sr_vvms/gtm_env_init_sp.c
@@ -0,0 +1,54 @@
+/****************************************************************
+ * *
+ * Copyright 2004 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <prtdef.h>
+#include <psldef.h> /* for PSL$C_USER */
+#include <ssdef.h>
+
+#include "iosp.h" /* for SS_NORMAL */
+#include "gtm_logicals.h"
+#include "trans_log_name.h" /* for trans_log_name() prototype */
+#include "gtm_env_init.h" /* for gtm_env_init_sp() prototype */
+#include "gtm_stdlib.h" /* for STRTOL macro */
+#include "gtm_string.h" /* for strlen() */
+
+GBLREF uint4 gtm_memory_noaccess_defined; /* count of the number of GTM_MEMORY_NOACCESS_ADDR logicals which are defined */
+GBLREF uint4 gtm_memory_noaccess[GTM_MEMORY_NOACCESS_COUNT];
+
+void gtm_env_init_sp(void)
+{
+ mstr val, tn;
+ char buf[1024], lognamebuf[1024];
+ uint4 mem_start, status, count;
+
+ /* Check if the logical GTM_MEMORY_NOACCESS_ADDR0 is defined. If so note the value down.
+ * Continue to do this for as many environment variables as are defined with a max. limit of
+ * GTM_MEMORY_NOACCESS_COUNT (currently 8) (i.e. stop at GTM_MEMORY_NOACCESS_ADDR3)
+ * gtm_expreg() will later look at these values before expanding the virtual address space.
+ */
+ for (count = 0; count < GTM_MEMORY_NOACCESS_COUNT; count++)
+ {
+ assert(0 == gtm_memory_noaccess[count]);
+ mem_start = 0;
+ SPRINTF(lognamebuf, "%s%d", GTM_MEMORY_NOACCESS_ADDR, count);
+ val.addr = lognamebuf;
+ val.len = (int)strlen(lognamebuf);
+ if (SS_NORMAL == (status = trans_log_name(&val, &tn, buf)))
+ mem_start = STRTOL(buf, NULL, 16);
+ if (!mem_start)
+ break; /* break if the environment variable is not defined properly */
+ gtm_memory_noaccess[count] = mem_start;
+ }
+ gtm_memory_noaccess_defined = count;
+ assert(GTM_MEMORY_NOACCESS_COUNT >= gtm_memory_noaccess_defined);
+}
diff --git a/sr_vvms/gtm_env_translate.c b/sr_vvms/gtm_env_translate.c
new file mode 100644
index 0000000..4cf068f
--- /dev/null
+++ b/sr_vvms/gtm_env_translate.c
@@ -0,0 +1,110 @@
+/****************************************************************
+ * *
+ * Copyright 2006, 2011 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <descrip.h>
+#include <stddef.h>
+#include <ssdef.h>
+#include "error.h"
+#include "gtm_env_xlate_init.h"
+
+GBLREF mstr env_gtm_env_xlate;
+GBLREF mval dollar_zdir;
+
+error_def(ERR_ASSERT);
+error_def(ERR_GTMASSERT);
+error_def(ERR_GTMASSERT2);
+error_def(ERR_GTMCHECK);
+error_def(ERR_STACKOFLOW);
+error_def(ERR_TEXT);
+error_def(ERR_VMSMEMORY);
+error_def(ERR_XTRNRETSTR);
+error_def(ERR_XTRNRETVAL);
+error_def(ERR_XTRNTRANSDLL);
+error_def(ERR_XTRNTRANSDLL);
+error_def(ERR_XTRNTRANSERR);
+
+/* This condition handler is necessary since execution does not return to
+ * gtm_env_translate if there is an error in lib$find_image_symbol otherwise */
+CONDITION_HANDLER(gtm_env_xlate_ch)
+{
+ int4 status;
+
+ START_CH;
+ PRN_ERROR;
+ if (DUMP)
+ NEXTCH;
+ mch->CHF_MCH_SAVR0 = SIGNAL; /* return status from lib$find_image_symbol to op_gvextnam or mlk_pvtblk_create*/
+ if ((status = sys$unwind(&mch->CHF_MCH_DEPTH, 0)) != SS$_NORMAL)
+ NEXTCH;
+}
+
+mval* gtm_env_translate(mval* val1, mval* val2, mval* val_xlated)
+{
+ int ret_gtm_env_xlate;
+ int4 status;
+ struct dsc$descriptor filename;
+ struct dsc$descriptor entry_point;
+ MSTR_CONST(routine_name, GTM_ENV_XLATE_ROUTINE_NAME);
+ /* The env xlate routines expect parameters of type xc_string_t* which
+ * is not defined on VMS. On VMS, xc_string_t is assumed to be same as
+ * mstr. Following code is to ensure any future mstr changes are caught
+ * sooner than later */
+ typedef struct
+ {
+ unsigned int length;
+ char* address;
+ } xc_string_t; /* A replica of what mstr ought to be */
+ xc_string_t* dummy_ptr;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ assert(offsetof(xc_string_t, length) == offsetof(mstr, len) && SIZEOF(dummy_ptr->length) == SIZEOF(val1->str.len));
+ assert(offsetof(xc_string_t, address) == offsetof(mstr, addr) && SIZEOF(dummy_ptr->address) == SIZEOF(val1->str.addr));
+ if (0 != env_gtm_env_xlate.len)
+ {
+ MV_FORCE_STR(val2);
+ if (NULL == RFPTR(gtm_env_xlate_entry))
+ {
+ entry_point.dsc$b_dtype = DSC$K_DTYPE_T;
+ entry_point.dsc$b_class = DSC$K_CLASS_S;
+ entry_point.dsc$w_length = routine_name.len;
+ entry_point.dsc$a_pointer = routine_name.addr;
+ filename.dsc$b_dtype = DSC$K_DTYPE_T;
+ filename.dsc$b_class = DSC$K_CLASS_S;
+ filename.dsc$w_length = env_gtm_env_xlate.len;
+ filename.dsc$a_pointer = env_gtm_env_xlate.addr;
+
+ ESTABLISH(gtm_env_xlate_ch);
+ status = lib$find_image_symbol(&filename, &entry_point, &RFPTR(gtm_env_xlate_entry), 0);
+ REVERT;
+ if (0 == (status & 1))
+ rts_error(VARLSTCNT(1) ERR_XTRNTRANSDLL);
+ }
+ val_xlated->str.addr = NULL;
+ ret_gtm_env_xlate = IVFPTR(gtm_env_xlate_entry)(&val1->str, &val2->str, &dollar_zdir.str, &val_xlated->str);
+ if (MAX_DBSTRLEN < val_xlated->str.len)
+ rts_error(VARLSTCNT(4) ERR_XTRNRETVAL, 2, val_xlated->str.len, MAX_DBSTRLEN);
+ if (0 != ret_gtm_env_xlate)
+ {
+ if ((val_xlated->str.len) && (val_xlated->str.addr))
+ rts_error(VARLSTCNT(6) ERR_XTRNTRANSERR, 0, ERR_TEXT, 2,
+ val_xlated->str.len, val_xlated->str.addr);
+ else
+ rts_error(VARLSTCNT(1) ERR_XTRNTRANSERR);
+ }
+ if ((NULL == val_xlated->str.addr) && (0 != val_xlated->str.len)) \
+ rts_error(VARLSTCNT(1) ERR_XTRNRETSTR);
+ val_xlated->mvtype = MV_STR;
+ val1 = val_xlated;
+ }
+ return val1;
+}
diff --git a/sr_vvms/gtm_event_log.c b/sr_vvms/gtm_event_log.c
new file mode 100644
index 0000000..9d2026f
--- /dev/null
+++ b/sr_vvms/gtm_event_log.c
@@ -0,0 +1,22 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+int gtm_event_log_init()
+{
+return 0;}
+
+int gtm_event_log_close()
+{
+return 0;}
+
+int gtm_event_log(int argc, char *category, char *code, char *msg)
+{
+return 0;}
diff --git a/sr_vvms/gtm_file_remove.c b/sr_vvms/gtm_file_remove.c
new file mode 100644
index 0000000..7e34fe8
--- /dev/null
+++ b/sr_vvms/gtm_file_remove.c
@@ -0,0 +1,55 @@
+/****************************************************************
+ * *
+ * Copyright 2003, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+#include "gtm_fcntl.h"
+
+#include <ssdef.h>
+#include <rms.h>
+#include <devdef.h>
+#include <descrip.h>
+#include <libdtdef.h>
+#include <libdef.h>
+#include <starlet.h>
+
+#include "gtm_file_remove.h"
+#include "iosp.h"
+
+int4 gtm_file_remove(char *fn, int fn_len, uint4 *ustatus)
+{
+ unsigned char es_buffer[MAX_FN_LEN], name_buffer[MAX_FN_LEN];
+ struct FAB fab;
+ struct NAM nam;
+ uint4 status;
+
+ *ustatus = SS_NORMAL;
+ nam = cc$rms_nam;
+ nam.nam$l_rsa = name_buffer;
+ nam.nam$b_rss = SIZEOF(name_buffer);
+ nam.nam$l_esa = es_buffer;
+ nam.nam$b_ess = SIZEOF(es_buffer);
+ nam.nam$b_nop = NAM$M_NOCONCEAL;
+ fab = cc$rms_fab;
+ fab.fab$l_nam = &nam;
+ fab.fab$l_fop = FAB$M_NAM;
+ fab.fab$l_fna = fn;
+ fab.fab$b_fns = fn_len;
+ status = sys$erase(&fab);
+ if (!(status & 1))
+ {
+ *ustatus = fab.fab$l_stv;
+ return status;
+ }
+ *ustatus = status;
+ return SS_NORMAL;
+}
diff --git a/sr_vvms/gtm_file_stat.c b/sr_vvms/gtm_file_stat.c
new file mode 100644
index 0000000..78ce48d
--- /dev/null
+++ b/sr_vvms/gtm_file_stat.c
@@ -0,0 +1,110 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <rms.h>
+#include <devdef.h>
+#include <ssdef.h>
+#include "util.h"
+#include "gtmmsg.h"
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_file_stat.h"
+
+GBLREF bool incremental;
+GBLREF bool in_backup;
+
+/* Checks the status of a file.
+ * Output Parameter
+ * uint4 *status : error number
+ * Returns:
+ * FILE_NOT_FOUND: if file is not presnt
+ * FILE_PRESENT: if file is present
+ * FILE_READONLY|FILE_PRESENT: if file is readonly
+ * FILE_STAT_ERROR: if error happens during this module.
+ * Side Effect: Except for FILE_STAT_ERROR passed "ret" will have expanded file name with path.
+ * Note: This routine now removes version info in "ret". In case caller need that we need to change this module.
+ */
+int gtm_file_stat(mstr *file, mstr *def, mstr *ret, boolean_t check_prv, uint4 *status)
+{
+ char *ptr;
+ unsigned char es_buffer[MAX_FN_LEN], name_buffer[MAX_FN_LEN];
+ int retstat;
+ struct FAB fab;
+ struct NAM nam;
+
+ nam = cc$rms_nam;
+ /* Note From Documentation :
+ * The nam$l_esa and nam$b_ess fields must be specified (nonzero) for wildcard character processing.
+ * nam$l_rsa required for wildcard character processing */
+ nam.nam$l_rsa = name_buffer; /* Resultant string area address: specifies name, type,
+ * and version of last file found */
+ nam.nam$b_rss = SIZEOF(name_buffer); /* Buffer size for l_rsa: For sys$search */
+ nam.nam$l_esa = es_buffer; /* Expanded String area address: specifies file name, type,
+ * and version of file */
+ nam.nam$b_ess = SIZEOF(es_buffer); /* Size of Expanded String area */
+ nam.nam$b_nop = NAM$M_NOCONCEAL; /* Indicates that when a concealed device logical name is present,
+ * the concealed device logical name is to be replaced by the
+ * actual physical device name in the expanded string. */
+ fab = cc$rms_fab;
+ fab.fab$l_nam = &nam;
+ fab.fab$l_fop = FAB$M_NAM;
+ fab.fab$l_fna = file->addr; /* File specification string address. */
+ fab.fab$b_fns = file->len; /* File specification string size. */
+ if (NULL != def)
+ {
+ fab.fab$l_dna = def->addr; /* Default file specification string. */
+ fab.fab$b_dns = def->len; /* Default file specification string size. */
+ }
+ /* sys$parse is done in order to initialize the NAM or NAML block appropriately */
+ if ((*status = sys$parse(&fab, 0, 0)) != RMS$_NORMAL)
+ return FILE_STAT_ERROR;
+ if (in_backup && !incremental && (fab.fab$l_dev & DEV$M_SQD))
+ {
+ util_out_print("MUPIP cannot backup to a magnetic tape",TRUE);
+ return FILE_NOT_FOUND;
+ }
+ *status = sys$search(&fab, 0, 0);
+ switch(*status)
+ {
+ case RMS$_NORMAL:
+ retstat = FILE_PRESENT;
+ break;
+ case RMS$_NMF:
+ case RMS$_FNF:
+ retstat = FILE_NOT_FOUND;
+ break;
+ case RMS$_PRV:
+ if (check_prv)
+ {
+ retstat = (FILE_PRESENT | FILE_READONLY);
+ break;
+ }
+ default:
+ return FILE_STAT_ERROR;
+ }
+ if (NULL != ret)
+ /* For returned length eliminate version info */
+ fncpy_nover(nam.nam$l_rsa, nam.nam$b_rsl, ret->addr, ret->len);
+ if (!check_prv || FILE_PRESENT != retstat)
+ return retstat;
+ fab.fab$b_shr = FAB$M_SHRPUT | FAB$M_SHRGET | FAB$M_UPI;
+ fab.fab$b_fac = FAB$M_GET | FAB$M_PUT | FAB$M_UPD ;
+ fab.fab$l_fop = FAB$M_UFO;
+ *status = sys$open(&fab);
+ if (RMS$_PRV == *status)
+ retstat = retstat | FILE_READONLY;
+ if ((*status) & 1) /* if successful open */
+ sys$dassgn(fab.fab$l_stv);
+ else if (RMS$_PRV != *status)
+ return FILE_STAT_ERROR;
+ return retstat;
+}
diff --git a/sr_vvms/gtm_getlkiw.c b/sr_vvms/gtm_getlkiw.c
new file mode 100644
index 0000000..67f4428
--- /dev/null
+++ b/sr_vvms/gtm_getlkiw.c
@@ -0,0 +1,31 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <prvdef.h>
+#include <ssdef.h>
+
+#include "gtmsecshr.h"
+
+uint4 gtm_getlkiw(uint4 efn, uint4 *lkid, void *itmlst, void *iosb, void *astadr, uint4 astprm, uint4 dummy)
+{
+ uint4 status;
+ uint4 prvadr[2], prvprv[2];
+
+ GTMSECSHR_SET_DBG_PRIV(PRV$M_SYSLCK, status);
+ if (status == SS$_NORMAL)
+ {
+ status = sys$getlkiw(efn, lkid, itmlst, iosb, astadr, astprm, dummy);
+ GTMSECSHR_REL_DBG_PRIV;
+ }
+ return status;
+}
diff --git a/sr_vvms/gtm_getlkiw.h b/sr_vvms/gtm_getlkiw.h
new file mode 100644
index 0000000..71e61a5
--- /dev/null
+++ b/sr_vvms/gtm_getlkiw.h
@@ -0,0 +1,17 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef GTM_GETLKIW_INCLUDED
+#define GTM_GETLKIW_INCLUDED
+
+uint4 gtm_getlkiw(uint4 efn, uint4 *lkid, void *itmlst, void *iosb, void *astadr, uint4 astprm, uint4 dummy);
+
+#endif /* GTM_GETLKIW_INCLUDED */
diff --git a/sr_vvms/gtm_getmsg.c b/sr_vvms/gtm_getmsg.c
new file mode 100644
index 0000000..88c432c
--- /dev/null
+++ b/sr_vvms/gtm_getmsg.c
@@ -0,0 +1,36 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <descrip.h>
+#include <ssdef.h>
+
+void gtm_getmsg(msgnum, msgbuf)
+uint4 msgnum;
+mstr *msgbuf;
+{
+ int4 status;
+ unsigned short m_len;
+ $DESCRIPTOR(d_sp,"");
+
+ d_sp.dsc$a_pointer = msgbuf->addr;
+ d_sp.dsc$w_length = --msgbuf->len; /* reserve a byte for a <NUL> terminator */
+
+ status = sys$getmsg(msgnum, &m_len, &d_sp, 0, 0);
+ if (status == SS$_NORMAL || status == SS$_BUFFEROVF)
+ {
+ assert(m_len <= msgbuf->len);
+ msgbuf->len = m_len;
+ }
+ else
+ msgbuf->len = 0;
+ *(char *)(msgbuf->addr + msgbuf->len) = 0; /* add a null terminator */
+}
diff --git a/sr_vvms/gtm_logicals.h b/sr_vvms/gtm_logicals.h
new file mode 100644
index 0000000..1964332
--- /dev/null
+++ b/sr_vvms/gtm_logicals.h
@@ -0,0 +1,86 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* gtm_logicals.h - Logical names used by GT.M. */
+/* within each group, the entries are in alpha order of the third column */
+/* -------------------------- Common to Unix and VMS -------------------------- */
+
+#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_GVDUPSETNOOP "GTM_GVDUPSETNOOP"
+#define GTM_GVUNDEF_FATAL "GTM_GVUNDEF_FATAL"
+#define GTM_TP_ALLOCATION_CLUE "GTM_TP_ALLOCATION_CLUE"
+#define GTM_TPNOTACIDTIME "GTM_TPNOTACIDTIME"
+#define GTM_TPRESTART_LOG_DELTA "GTM_TPRESTART_LOG_DELTA"
+#define GTM_TPRESTART_LOG_LIMIT "GTM_TPRESTART_LOG_FIRST"
+#define GTM_ZMAXTPTIME "GTM_ZMAXTPTIME"
+
+/* White-box testing */
+#define GTM_WHITE_BOX_TEST_CASE_COUNT "GTM_WHITE_BOX_TEST_CASE_COUNT"
+#define GTM_WHITE_BOX_TEST_CASE_ENABLE "GTM_WHITE_BOX_TEST_CASE_ENABLE"
+#define GTM_WHITE_BOX_TEST_CASE_NUMBER "GTM_WHITE_BOX_TEST_CASE_NUMBER"
+
+/* Indirection-cache */
+#define GTM_MAX_INDRCACHE_COUNT "GTM_MAX_INDRCACHE_COUNT"
+#define GTM_MAX_INDRCACHE_MEMORY "GTM_MAX_INDRCACHE_MEMORY"
+
+/* MUPIP BACKUP */
+# define GTM_BAK_TEMPDIR_LOG_NAME "GTM_BAKTMPDIR"
+
+/* Pattern match operator */
+#define PAT_FILE "GTM_PATTERN_FILE"
+#define PAT_TABLE "GTM_PATTERN_TABLE"
+
+/* Alternative Collation */
+#define CT_PREFIX "GTM_COLLATE_"
+#define LCT_PREFIX "GTM_LOCAL_COLLATE"
+#define LCT_STDNULL "GTM_LCT_STDNULL"
+
+/* GTM processing versus M standard */
+/* (see gtm_local_collate above) */
+#define GTM_STDXKILL "GTM_STDXKILL"
+
+/* Miscellaneous */
+#define ZCOMPILE "GTM$COMPILE"
+#define GTM_DEBUG_LEVEL_ENVLOG "GTMDBGLVL"
+#define GTM_ZROUTINES "GTM$ROUTINES"
+#define GTM_BOOLEAN "GTM_BOOLEAN"
+#define DISABLE_ALIGN_STRINGS "GTM_DISABLE_ALIGNSTR"
+#define GTM_MAX_SOCKETS "GTM_MAX_SOCKETS"
+#define GTM_MEMORY_RESERVE "GTM_MEMORY_RESERVE"
+#define GTM_NOUNDEF "GTM_NOUNDEF"
+#define GTM_PRINCIPAL "GTM$PRINCIPAL"
+#define GTM_PROMPT "GTM_PROMPT"
+#define GTM_SIDE_EFFECT "GTM_SIDE_EFFECTS"
+#define SYSID "GTM_SYSID"
+#define GTM_MPROF_TESTING "GTM_TRACE_GBL_NAME"
+#define GTM_TRACE_GROUPS "GTM_TRACE_GROUPS"
+#define GTM_TRACE_TABLE_SIZE "GTM_TRACE_TABLE_SIZE"
+#define ZDATE_FORM "GTM_ZDATE_FORM"
+#define GTM_ZINTERRUPT "GTM_ZINTERRUPT"
+#define GTM_ZQUIT_ANYWAY "GTM_ZQUIT_ANYWAY"
+#define ZTRAP_FORM "GTM_ZTRAP_FORM"
+#define ZTRAP_NEW "GTM_ZTRAP_NEW"
+#define ZYERROR "GTM_ZYERROR"
+#define GTM_MAX_STORALLOC "GTM_MAX_STORALLOC"
+/* -------------------------- VMS only -------------------------- */
+
+/* Miscellaneous */
+#define GTM_MEMORY_NOACCESS_ADDR "GTM_MEMORY_NOACCESS_ADDR"
+#define GTM_MEMORY_NOACCESS_COUNT 8 /* count of the above logicals which are parsed */
+
diff --git a/sr_vvms/gtm_mtio.h b/sr_vvms/gtm_mtio.h
new file mode 100644
index 0000000..0d9e8a5
--- /dev/null
+++ b/sr_vvms/gtm_mtio.h
@@ -0,0 +1,15 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* gtm_mtio.h VMS - include appropriate OS files for mag tape operations */
+
+
+/* not presently used */
diff --git a/sr_vvms/gtm_putmsg.c b/sr_vvms/gtm_putmsg.c
new file mode 100644
index 0000000..3dfcc95
--- /dev/null
+++ b/sr_vvms/gtm_putmsg.c
@@ -0,0 +1,42 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2005 Fidelity Information Servcies, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <stdarg.h>
+#include "msg.h"
+
+#define MAX_ERR_ARGS 64
+
+static int4 msgv[MAX_ERR_ARGS + 1];
+
+void gtm_putmsg(int4 msgid, ...)
+{
+ va_list var;
+ short int *sptr;
+ int4 argcnt, *lptr;
+
+ VAR_START(var, msgid);
+ va_count(argcnt);
+ if (MAX_ERR_ARGS < argcnt)
+ argcnt = MAX_ERR_ARGS;
+ sptr = (short int *)msgv;
+ *sptr= argcnt;
+ sptr++;
+ *sptr= 0;
+ assert(0 < argcnt);
+ msgv[1] = msgid;
+ argcnt--;
+ for (lptr = &msgv[2]; argcnt; *lptr++ = va_arg(var, int4), argcnt--)
+ ;
+ va_end(var);
+ sys$putmsg(msgv, 0, 0, 0);
+ return;
+}
diff --git a/sr_vvms/gtm_rename.c b/sr_vvms/gtm_rename.c
new file mode 100644
index 0000000..1ac89f0
--- /dev/null
+++ b/sr_vvms/gtm_rename.c
@@ -0,0 +1,64 @@
+/****************************************************************
+ * *
+ * Copyright 2003, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_rename.h"
+#include "iosp.h"
+
+#include <ssdef.h>
+#include <rms.h>
+#include <devdef.h>
+#include <descrip.h>
+#include <libdtdef.h>
+#include <libdef.h>
+#include <starlet.h>
+
+
+uint4 gtm_rename(char *org_fn, int org_fn_len, char *rename_fn, int rename_len, uint4 *ustatus)
+{
+ char es1_buffer[MAX_FN_LEN], name1_buffer[MAX_FN_LEN];
+ char es2_buffer[MAX_FN_LEN], name2_buffer[MAX_FN_LEN];
+ struct FAB fab1, fab2;
+ struct NAM nam1, nam2;
+ uint4 status;
+
+ *ustatus = SS_NORMAL;
+ nam1 = cc$rms_nam;
+ nam1.nam$l_rsa = name1_buffer;
+ nam1.nam$b_rss = SIZEOF(name1_buffer);
+ nam1.nam$l_esa = es1_buffer;
+ nam1.nam$b_ess = SIZEOF(es1_buffer);
+ fab1 = cc$rms_fab;
+ fab1.fab$l_nam = &nam1;
+ fab1.fab$b_shr = FAB$M_SHRPUT | FAB$M_SHRGET | FAB$M_SHRDEL | FAB$M_SHRUPD;
+ fab1.fab$l_fna = org_fn;
+ fab1.fab$b_fns = org_fn_len;
+
+ nam2 = cc$rms_nam;
+ nam2.nam$l_rsa = name2_buffer;
+ nam2.nam$b_rss = SIZEOF(name2_buffer);
+ nam2.nam$l_esa = es2_buffer;
+ nam2.nam$b_ess = SIZEOF(es2_buffer);
+ fab2 = cc$rms_fab;
+ fab2.fab$l_nam = &nam2;
+ fab2.fab$b_shr = FAB$M_SHRPUT | FAB$M_SHRGET | FAB$M_SHRDEL | FAB$M_SHRUPD;
+ fab2.fab$l_fna = rename_fn;
+ fab2.fab$b_fns = rename_len;
+ status = sys$rename(&fab1, 0, 0, &fab2); /* Rename the file */
+ if (!(status & 1))
+ {
+ *ustatus = fab1.fab$l_stv;
+ return status;
+ }
+ *ustatus = status;
+ return SS_NORMAL;
+}
diff --git a/sr_vvms/gtm_snprintf.c b/sr_vvms/gtm_snprintf.c
new file mode 100644
index 0000000..c211881
--- /dev/null
+++ b/sr_vvms/gtm_snprintf.c
@@ -0,0 +1,29 @@
+/****************************************************************
+ * *
+ * Copyright 2002, 2010 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_stdio.h"
+
+#include <stdarg.h>
+
+int gtm_snprintf(char *str, size_t size, const char *format, ...)
+{ /* hack for VMS, ignore size argument and call sprintf. When snprintf becomes available on VMS, nix this file and define SNPRINTF
+ * in gtm_stdio.h to snprintf */
+
+ va_list printargs;
+ int retval, rc;
+
+ va_start(printargs, format);
+ retval = VSPRINTF(str, format, printargs, rc);
+ va_end(printargs);
+ return retval;
+}
diff --git a/sr_vvms/gtm_spkitbld.dat b/sr_vvms/gtm_spkitbld.dat
new file mode 100644
index 0000000..7ee270c
--- /dev/null
+++ b/sr_vvms/gtm_spkitbld.dat
@@ -0,0 +1,11 @@
+SPKITBLD$KITNAME := GTM60002
+SPKITBLD$REWIND_TAPE := Y
+SPKITBLD$AUTOINIT_TAPE := 'GTM_INIT_TAPE'
+SPKITBLD$SKIP_FIRST_TAPE_READY_PROMPT := Y
+SPKITBLD$SKIP_FIRST_DISK_READY_PROMPT := Y
+SPKITBLD$SAVESET_A := GTM$VRT:[TLS]KITINSTAL.COM;,GTMKITHLP.COM;,GTMCOLLECT.OPT;,GTM$VRT:[HLP]DSE.HLB;,GDE.HLB;,LKE.HLB;,MUMPS.HLB;,MUPIP.HLB;
+SPKITBLD$NEW_MEDIA_FOR_SAVESET_A := N
+SPKITBLD$SAVESET_B := GTM$VRT:[PRO]GTMSECSHR.EXE;,GTMSHR.EXE;,DSE.EXE;,GDE.EXE;,GTM$DMOD.EXE;,LKE.EXE;,MCOMPILE.EXE;,MUPIP.EXE;,GTM$STOP.EXE;
+SPKITBLD$NEW_MEDIA_FOR_SAVESET_B := N
+SPKITBLD$SAVESET_C := GTM$VRT:[PRO]GTMCOMMANDS.CLD;,GTMZCALL.MLB;,GTMLIB.OLB;,GTMSHR.OLB;,GTM$VRT:[PCT]*.M;,GTM$VRT:[TLS]GTM$DEFAULTS.M64;,GTM$CE.H;,GTM$IVP.TLB;
+SPKITBLD$NEW_MEDIA_FOR_SAVESET_C := N
diff --git a/sr_vvms/gtm_stdio.h b/sr_vvms/gtm_stdio.h
new file mode 100644
index 0000000..5c5ff07
--- /dev/null
+++ b/sr_vvms/gtm_stdio.h
@@ -0,0 +1,50 @@
+/****************************************************************
+ * *
+ * 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. *
+ * *
+ ****************************************************************/
+
+/* gtm_stdio.h - gtm interface to stdio.h */
+
+#ifndef GTM_STDIOH
+#define GTM_STDIOH
+
+/* This header is split between sr_unix and sr_vvms because there are several test system and standalone modules
+ * that do not #define UNIX or VMS for us to know which defines to proceed with. So now this split makes
+ * that determination unnecessary.
+ */
+
+#include <stdio.h>
+
+#define FDOPEN fdopen
+#define FGETS(strg, n, strm, fgets_res) (fgets_res = fgets(strg,n,strm))
+#define Fopen fopen
+#define GETS(buffer, gets_res) syntax error
+#define PERROR perror
+#define POPEN popen
+#define TEMPNAM tempnam
+
+#define DEFAULT_GTM_TMP P_tmpdir
+#define RENAME rename
+#define SETVBUF setvbuf
+
+#define FPRINTF fprintf
+#define PRINTF printf
+#define SCANF scanf
+#define SSCANF sscanf
+#define SNPRINTF gtm_snprintf /* hack for VMS, ignore size argument and call sprintf */
+#define VPRINTF(STRING, FORMAT, VALUE, RC) vsprintf(STRING, FORMAT, VALUE)
+#define VFPRINTF(STREAM, FORMAT, VALUE, RC) vfprintf(STREAM, FORMAT, VALUE)
+#define VSPRINTF(STRING, FORMAT, VALUE, RC) vsprintf(STRING, FORMAT, VALUE)
+#define VSNPRINTF(STRING, SIZE, FORMAT, VALUE, RC) vsnprintf(STRING, SIZE, FORMAT, VALUE)
+#define VSCANF(FORMAT, POINTER, RC) vscanf(FORMAT, POINTER)
+#define VSSCANF(STRING, FORMAT, POINTER, RC) vsscanf(STRING, FORMAT, POINTER)
+#define VFSCANF(STREAM, FORMAT, POINTER, RC) vfscanf(STREAM, FORMAT, POINTER)
+int gtm_snprintf(char *str, size_t size, const char *format, ...);
+
+#endif
diff --git a/sr_vvms/gtm_utf8.c b/sr_vvms/gtm_utf8.c
new file mode 100644
index 0000000..9533261
--- /dev/null
+++ b/sr_vvms/gtm_utf8.c
@@ -0,0 +1,28 @@
+/****************************************************************
+ * *
+ * Copyright 2006 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+/* These are dummy routines to allow code to compile/link on VMS. These routines are not
+ used but elimination of them from the code is detremental to the clarify of the UNIX
+ codebase and since Alpha/VMS is a dead platform, these dummy routines also have a
+ limited lifespan.. 9/2006 SE
+*/
+
+int utf8_len_strict(unsigned char* ptr, int len)
+{
+ GTMASSERT;
+}
+
+void utf8_badchar(int len, unsigned char* str, unsigned char *strtop, int chset_len, unsigned char* chset)
+{
+ GTMASSERT;
+}
diff --git a/sr_vvms/gtm_utf8.h b/sr_vvms/gtm_utf8.h
new file mode 100644
index 0000000..84c9e77
--- /dev/null
+++ b/sr_vvms/gtm_utf8.h
@@ -0,0 +1,46 @@
+/****************************************************************
+ * *
+ * Copyright 2006 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef GTM_UTF8_H
+#define GTM_UTF8_H
+
+/* Define types for use by compilation in VMS in code paths that will never be
+ used. This was the preferred method of making the Unicode modified UNIX code
+ work in VMS rather than butchering it with ifdefs making maintenance more
+ difficult. 9/2006 SE
+*/
+
+#define UTF8_VALID(mbptr, ptrend, bytelen) (bytelen = -1, FALSE)
+#define UTF16BE_VALID(mbptr, ptrend, bytelen) (bytelen = -1, FALSE)
+#define UTF16LE_VALID(mbptr, ptrend, bytelen) (bytelen = -1, FALSE)
+#define UTF8_MBFOLLOW(mbptr) (-1)
+#define UTF16BE_MBFOLLOW(mbptr, ptrend) (-1)
+#define UTF16LE_MBFOLLOW(mbptr, ptrend) (-1)
+#define UTF8_WCTOMB(codepoint, mbptr) mbptr
+#define UTF16BE_WCTOMB(codepoint, mbptr) mbptr
+#define UTF16LE_WCTOMB(codepoint, mbptr) mbptr
+#define UTF8_MBTOWC(mbptr, ptrend, codepoint) (-1)
+#define UTF16BE_MBTOWC(mbptr, ptrend, codepoint) (-1)
+#define UTF16LE_MBTOWC(mbptr, ptrend, codepoint) (-1)
+#define U_VALID_CODE(codepoint) (FALSE)
+#define UTF16BE_BOM '\0'
+#define UTF16BE_BOM_LEN 1
+#define UTF16LE_BOM '\0'
+#define UTF16LE_BOM_LEN 1
+#define UTF8_BOM '\0'
+#define UTF8_BOM_LEN 1
+
+#define GTM_MB_LEN_MAX 1 /* VMS does not support unicode so no multiple byte chars */
+
+int utf8_len_strict(unsigned char* ptr, int len);
+void utf8_badchar(int len, unsigned char* str, unsigned char *strtop, int chset_len, unsigned char* chset);
+
+#endif /* GTM_UTF8_H */
diff --git a/sr_vvms/gtm_verify_symbols.com b/sr_vvms/gtm_verify_symbols.com
new file mode 100644
index 0000000..8023f17
--- /dev/null
+++ b/sr_vvms/gtm_verify_symbols.com
@@ -0,0 +1,38 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2003 Sanchez Computer Associates, Inc. !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$! full build comes through axp_comlist.com which would have done set verify where the more output the merrier
+$! but for incremental invocations of this script, we do not want lots of output spewed so avoid logging in that case.
+$! since we cannot pass a local symbol to the caller, we set a global symbol.
+$!
+$! p1 - "set" or "unset"
+$!
+$ if (p1 .eqs. "set")
+$ then
+$ if f$environment("VERIFY_PROCEDURE")
+$ then
+$ gtm_copy :== copy/log
+$ gtm_delete :== delete/log
+$ gtm_library :== library/log
+$ gtm_purge :== purge/log
+$ else
+$ gtm_copy :== copy/nolog
+$ gtm_delete :== delete/nolog
+$ gtm_library :== library/nolog
+$ gtm_purge :== purge/nolog
+$ endif
+$ else
+$ gtm_del = "delete" ! in case someone has redefined "delete"
+$ gtm_del /symb/glob gtm_copy
+$ gtm_del /symb/glob gtm_delete
+$ gtm_del /symb/glob gtm_library
+$ gtm_del /symb/glob gtm_purge
+$ endif
diff --git a/sr_vvms/gtm_wake.c b/sr_vvms/gtm_wake.c
new file mode 100644
index 0000000..77efeb0
--- /dev/null
+++ b/sr_vvms/gtm_wake.c
@@ -0,0 +1,19 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gtm_wake.h"
+
+void gtm_wake(int4 *pidadr,char *prcnam)
+{
+ sys$wake(pidadr, prcnam);
+ return;
+}
diff --git a/sr_vvms/gtmcollect.opt b/sr_vvms/gtmcollect.opt
new file mode 100644
index 0000000..edbf856
--- /dev/null
+++ b/sr_vvms/gtmcollect.opt
@@ -0,0 +1,41 @@
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+! !
+! Copyright 2002 Sanchez Computer Associates, Inc. !
+! !
+! This source code contains the intellectual property !
+! of its copyright holder(s), and is made available !
+! under a license. If you do not know the terms of !
+! the license, please stop and do not read further. !
+! !
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!
+! gtmcollect.opt
+!
+! This is a linker options file which contains cluster commands
+! that set the pfc (page fault cluster size) to 12 for the code
+! section and 20 for the literal constants section.
+!
+! The page fault cluster size is the number of pages which are
+! transferred to memory as the result of a page fault.
+! Normally it is controlled is by a SYSGEN parameter
+! (PFCDEFAULT) for all image sections which do not otherwise
+! specify a PFC. The default is generally set to 64 pages by
+! AUTOGEN. 64 seems to be a good size for DEC utilities but
+! it is generally significantly larger than optimal for MUMPS
+! programs in GT.M. You may wish to experiment to find the
+! best size for you image(s).
+!
+! Exact spelling of "gtm$code" and "gtm$literals" is essential
+! as any psect name will be accepted without error.
+!
+! If you wish to use your own options just include the cluster
+! options at the FIRST appropriate opportunity, in your file,
+! and the collect options near the end.
+! Otherwise you may use this as your options file and specify
+! "gtmcollect/option" in the list of files for your link command.
+!
+cluster=code,,12,
+cluster=lits,,20,
+collect=code,gtm$code
+collect=lits,gtm$literals
+!
diff --git a/sr_vvms/gtmcommands.cldx b/sr_vvms/gtmcommands.cldx
new file mode 100644
index 0000000..3bee5db
--- /dev/null
+++ b/sr_vvms/gtmcommands.cldx
@@ -0,0 +1,28 @@
+DEFINE VERB MUMPS
+ IMAGE "MCOMPILE"
+ QUALIFIER DIRECT_MODE, SYNTAX=DIRECT_MODE
+ QUALIFIER CROSS_REFERENCE PLACEMENT=POSITIONAL
+ QUALIFIER DEBUG PLACEMENT=POSITIONAL
+ QUALIFIER LIST VALUE(TYPE=$FILE)
+ PLACEMENT=POSITIONAL
+ QUALIFIER MACHINE_CODE PLACEMENT=POSITIONAL
+ QUALIFIER IGNORE PLACEMENT=POSITIONAL
+ QUALIFIER LENGTH VALUE(REQUIRED,TYPE=$NUMBER)
+ PLACEMENT=POSITIONAL
+ QUALIFIER SPACE VALUE(REQUIRED,TYPE=$NUMBER)
+ PLACEMENT=POSITIONAL
+ QUALIFIER OBJECT VALUE(TYPE=$FILE)
+ PLACEMENT=POSITIONAL
+ QUALIFIER WARNINGS PLACEMENT=POSITIONAL
+ QUALIFIER LABELS VALUE(REQUIRED)
+ PLACEMENT=POSITIONAL
+ QUALIFIER LINE_ENTRY PLACEMENT=POSITIONAL
+ QUALIFIER INLINE_LITERALS PLACEMENT=POSITIONAL
+ QUALIFIER ALIGN_STRINGS PLACEMENT=POSITIONAL
+ QUALIFIER CE_PREPROCESS VALUE(TYPE=$FILE)
+ PLACEMENT=POSITIONAL
+ PARAMETER P1, LABEL=INFILE,PROMPT="FILE",VALUE(REQUIRED,LIST,TYPE=$FILE)
+DEFINE SYNTAX DIRECT_MODE
+ IMAGE "GTM$DMOD"
+ NOQUALIFIERS
+ NOPARAMETERS
diff --git a/sr_vvms/gtmdc_spkitbld.dat b/sr_vvms/gtmdc_spkitbld.dat
new file mode 100644
index 0000000..1d1f433
--- /dev/null
+++ b/sr_vvms/gtmdc_spkitbld.dat
@@ -0,0 +1,6 @@
+SPKITBLD$KITNAME := GTDC60002
+SPKITBLD$REWIND_TAPE := N
+SPKITBLD$AUTOINIT_TAPE := 'GTM_INIT_TAPE'
+SPKITBLD$SKIP_FIRST_TAPE_READY_PROMPT := Y
+SPKITBLD$SKIP_FIRST_DISK_READY_PROMPT := Y
+SPKITBLD$SAVESET_A :=GTM$VRT:[TDC]KITINSTAL.COM;,GTMDCKITHLP.COM;,GTM$VRT:[PRO]DBCERTIFY.EXE;,GTM$VRT:[SRC]V5CBSU.M;
diff --git a/sr_vvms/gtmdckithlp.com b/sr_vvms/gtmdckithlp.com
new file mode 100644
index 0000000..eff0f6d
--- /dev/null
+++ b/sr_vvms/gtmdckithlp.com
@@ -0,0 +1,94 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2005 Fidelity Information Services, Inc !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$!
+$! HELP TEXT PROCESSING FOR GT.M DBCERTIFY utility KITINSTAL.COM
+$ IF F$EXTRACT(0,5,P1) .EQS. "HELP_" THEN GOTO 'P1'
+$ EXIT VMI$_UNSUPPORTED
+$HELP_PURGE:
+$ TYPE SYS$INPUT
+
+ If the GT.M DBCERTIFY utility is previously installed, there is no reason to
+ keep older versions of the software online, unless you wish to test before
+ purging.
+
+$ EXIT
+$HELP_STD_CNF:
+$ TYPE SYS$INPUT
+ The standard configuration performs the following:
+
+ * Places files in SYS$COMMON:[GTMDBCERTIFY] with SYSTEM as owner.
+ * Copies two GT.M DBCERTIFY utility command procedures to the
+ above directory and SYS$MANAGER:.
+ * Uses the existing GT.M distribution from GTM$DIST:.
+ * Builds V5CBSU.EXE using the GT.M from GTM$DIST:.
+
+ If the SYSTEM id is not set up, the installation will use [1,4].
+
+$ EXIT
+$HELP_DST_OWN:
+$ TYPE SYS$INPUT
+ Provide a UIC, normally SYSTEM, to own the files in the GT.M DBCERTIFY utility
+ distribution. The UIC can be a name, a group name and a user name separated
+ by a comma, or a pair of octal codes separated by a comma which specify
+ group and user.
+
+$ EXIT
+$HELP_SYS_DST:
+$ TYPE SYS$INPUT
+ Usual practice is to place a system component such as the GT.M DBCERTIFY
+ utility on the system disk. If you have severe space constraints, you may
+ need to use another volume.
+
+$ EXIT
+$HELP_SYS_DIR:
+$ TYPE SYS$INPUT
+ This directory becomes a sub-directory of SYS$COMMON and holds the
+ distribution. If it does not exist, the installation creates it with
+ WORLD=RE access. If you are not concerned with mixing software from
+ different vendors, you may wish to use SYSLIB.
+
+$ EXIT
+$HELP_DST_DEV:
+$ TYPE SYS$INPUT
+ The disk must be mounted, on-line and have adequate space to hold the
+ GT.M DBCERTIFY utility distribution. The disk name may be physical or logical.
+
+$ EXIT
+$HELP_DST_DIR:
+$ TYPE SYS$INPUT
+ This directory holds the distribution. If it does not exist, the
+ installation creates it with WORLD=RE access.
+
+$ EXIT
+$HELP_GTM_LOG:
+$ TYPE SYS$INPUT
+ The GT.M DBCERTIFY utility invokes utilities from the existing GT.M
+ distribution. The location of the distribution may be specified as
+ a logical name or as device:[directory]. GTM$DIST is the default.
+
+$ EXIT
+$HELP_RUN_IVP:
+$ TYPE SYS$INPUT
+ This installation kit does not contain an installation verification
+ procedure (IVP) which you can run as part of the installation to
+ verify the correctness of the software.
+
+$ EXIT
+$HELP_BLD_EXE:
+$ TYPE SYS$INPUT
+ The executable for V5CBSU must be built before the existing databases
+ can be prepared for upgrade for use with the new GT.M version. This is
+ done using the GTMDCBUILD.COM procedure created by this installation.
+ Answering yes to this question will invoke this procedure at the end
+ of this installation.
+
+$ EXIT
diff --git a/sr_vvms/gtmdckitinstal.com b/sr_vvms/gtmdckitinstal.com
new file mode 100644
index 0000000..c640519
--- /dev/null
+++ b/sr_vvms/gtmdckitinstal.com
@@ -0,0 +1,229 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2005, 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. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$!
+$! KITINSTAL.COM PROCEDURE FOR THE GT.M DBCERTIFY UTILITY
+$!
+$ ON CONTROL_Y THEN VMI$CALLBACK CONTROL_Y
+$! ON WARNING THEN EXIT $STATUS !! allow warning on install replace
+$ IF P1 .EQS. "VMI$_INSTALL" THEN GOTO INSTALL
+$ IF P1 .EQS. "VMI$_POSTINSTALL" THEN GOTO POSTINSTALL
+$ IF P1 .EQS. "VMI$_IVP" THEN GOTO IVP
+$ EXIT VMI$_UNSUPPORTED
+$!
+$INSTALL:
+$ TYPE SYS$INPUT
+
+GT.M DBCERTIFY (c) COPYRIGHT 2005 by Fidelity Information Services, Inc
+ ALL RIGHTS RESERVED
+
+$! the following 2 lines must be maintained
+$ GTMDC$VMS_VERSION :== 072 ! Minimum VMS version required
+$ GTMDC$DISK_SPACE == 840 ! Minumum disk space on system disk required for install (2x result)
+$ IF F$ELEMENT(0,",",VMI$VMS_VERSION) .EQS. "RELEASED"
+$ THEN
+$ GTMDC$VMS_IS == F$ELEMENT(1,",",VMI$VMS_VERSION)
+$ IF GTMDC$VMS_IS .LTS. GTMDC$VMS_VERSION
+$ THEN
+$ VMI$CALLBACK MESSAGE E VMSMISMATCH "This GT.M DBCERTIFY utility kit requires an existing VMS''GTMDC$VMS_VERSION' system."
+$ EXIT VMI$_FAILURE
+$ ENDIF
+$ ELSE
+$ GTMDC$VMS_IS :==
+$ WRITE SYS$OUTPUT " No VMS version checking performed for field test versions."
+$ ENDIF
+$ IF (GTMDC$VMS_IS .GES. "052") THEN T1 = F$VERIFY(VMI$KIT_DEBUG)
+$ VMI$CALLBACK CHECK_NET_UTILIZATION GTMDC$ROOM 'GTMDC$DISK_SPACE'
+$ IF .NOT. GTMDC$ROOM
+$ THEN
+$ VMI$CALLBACK MESSAGE E NOSPACE "There is not enough disk space -- GT.M DBCERTIFY utility kit needs ''GTMDC$DISK_SPACE' blocks."
+$ EXIT VMI$_FAILURE
+$ ENDIF
+$! setup default answers
+$ GTMDC$DOPURGE :== YES
+$ GTMDC$RUN_IVP == 0 !! should be "YES", but no IVP yet
+$ GTMDC$BLD_EXE :== YES !! build V5CBSU.EXE in postinstall
+$ GTMDC$STD_CNF :== YES
+$ GTMDC$DST_OWN :== SYSTEM
+$ IF F$IDENTIFIER(GTMDC$DST_OWN,"NAME_TO_NUMBER") .EQ. 0 THEN GTMDC$DST_OWN :== 1,4
+$ GTMDC$SYS_DST :== YES
+$ GTMDC$DST_DIR :== GTMDBCERTIFY
+$ GTMDC$DST_CRE == GTMDC$DST_DIR
+$ GTMDC$DST_DEV :==
+$ GTMDC$MGR_COM :== YES
+$ GTMDC$GTM_LOG :== GTM$DIST:
+$!
+$ VMI$CALLBACK ASK GTMDC$DOPURGE "Do you want to purge files replaced by this installation" 'GTMDC$DOPURGE' B -
+ "@VMI$KWD:GTMDCKITHLP HELP_PURGE"
+$ IF .NOT. GTMDC$DOPURGE THEN VMI$CALLBACK SET PURGE NO
+$ VMI$CALLBACK ASK GTMDC$STD_CNF "Do you want the standard GT.M DBCERTIFY utility configuration" 'GTMDC$STD_CNF' B -
+ "@VMI$KWD:GTMDCKITHLP HELP_STD_CNF"
+$ IF GTMDC$STD_CNF
+$ THEN
+$ GTMDC$SYS_DST == 1
+$ GTMDC$MGR_COM == 1
+$ GTMDC$DST_LOG :== SYS$COMMON:['GTMDC$DST_DIR']
+$ GTMDC$DIR_TYPE :== COMMON
+$ GTMDC$GTM_LOG :== GTM$DIST:
+$ GTMDC$RUN_IVP == 0 !! no IVP yet
+$ ELSE ! not standard configuration
+$ VMI$CALLBACK ASK GTMDC$DST_OWN "What UIC should own the GT.M DBCERTIFY utility distribution" 'GTMDC$DST_OWN' S -
+ "@VMI$KWD:GTMDCKITHLP HELP_DST_OWN"
+$ GTMDC$DST_OWN == GTMDC$DST_OWN - "[" - "]"
+$ VMI$CALLBACK ASK GTMDC$SYS_DST "Do you want the GT.M DBCERTIFY utility distribution to go into a System Directory" -
+ 'GTMDC$SYS_DST' B "@VMI$KWD:GTMDCKITHLP HELP_SYS_DST"
+$ IF GTMDC$SYS_DST
+$ THEN
+$ VMI$CALLBACK ASK GTMDC$DST_DIR "In what System Directory do you want to place GT.M DBCERTIFY utility" 'GTMDC$DST_DIR' S -
+ "@VMI$KWD:GTMDCKITHLP HELP_SYS_DIR"
+$ GTMDC$DST_DIR == GTMDC$DST_DIR - "[" - "]"
+$ GTMDC$DST_CRE == GTMDC$DST_DIR
+$ GTMDC$DST_LOG :== SYS$COMMON:['GTMDC$DST_DIR']
+$ GTMDC$DIR_TYPE :== COMMON
+$ ELSE ! not system disk
+$ GTMDC$MGR_COM == 0
+$ VMI$CALLBACK ASK GTMDC$DST_DEV "On which device do you want to place the GT.M DBCERTIFY utility" "" S -
+ "@VMI$KWD:GTMDCKITHLP HELP_DST_DEV"
+$ VMI$CALLBACK ASK GTMDC$DST_DIR "In what directory on that device do you want to place the GT.M DBCERTIFY utility" -
+ 'GTMDC$DST_DIR' S "@VMI$KWD:GTMDCKITHLP HELP_DST_DIR"
+$ GTMDC$DST_DEV == GTMDC$DST_DEV - ":"
+$ GTMDC$DST_DIR == GTMDC$DST_DIR - "[" - "]"
+$ GTMDC$DST_LOG :== 'GTMDC$DST_DEV':['GTMDC$DST_DIR']
+$ GTMDC$DST_CRE == GTMDC$DST_LOG
+$ GTMDC$DIR_TYPE :== USER
+$ VMI$CALLBACK ASK GTMDC$GTM_LOG "Where is the existing GT.M distribution located" -
+ 'GTMDC$GTM_LOG' S "@VMI$KWD:GTMDCKITHLP HELP_GTM_LOG"
+$ IF F$LOCATE(":", GTMDC$GTM_LOG) .NE. F$LENGTH(GTMDC$GTM_LOG) .AND. -
+ F$LOCATE("]", GTMDC$GTM_LOG) .NE. F$LENGTH(GTMDC$GTM_LOG)
+$ THEN
+$ GTMDC$GTM_LOG :== 'GTMDC$GTM_LOG':
+$ ENDIF
+$ ENDIF ! system disk
+$ VMI$CALLBACK ASK GTMDC$BLD_EXE "Do you want to build V5CBSU.EXE now" 'GTMDC$BLD_EXE' B -
+ "@VMI$KWD:GTMDCKITHLP HELP_BLD_EXE"
+$!! no IVP yet
+$ IF FALSE THEN VMI$CALLBACK ASK GTMDC$RUN_IVP "Do you want to run the IVP (requires GT.M)" 'GTMDC$RUN_IVP' B -
+ "@VMI$KWD:GTMDCKITHLP HELP_RUN_IVP"
+$ ENDIF ! standard configuration
+$ IF GTMDC$MGR_COM
+$ THEN
+$ WRITE SYS$OUTPUT " The following command files are created and copied to SYS$MANAGER:"
+$ ELSE
+$ WRITE SYS$OUTPUT " The following command files are created:"
+$ ENDIF
+$ TYPE SYS$INPUT
+
+ GTMDCBUILD.COM
+ GTMDCDEFINE.COM
+
+ Each file contains its own user documentation.
+
+ All the questions have been asked. Installation now proceeds without your
+ manual intervention for about 5-10 minutes.
+$ WRITE SYS$OUTPUT ""
+$ VMI$CALLBACK CREATE_DIRECTORY 'GTMDC$DIR_TYPE' 'GTMDC$DST_CRE' "/OWNER_UIC=[''GTMDC$DST_OWN'] /PROTECTION=(WO:RE)"
+$ VMI$CALLBACK MESSAGE I CRECOM "Creating command files."
+$! Create GTMDCBUILD.COM
+$ OPEN /WRITE OUFILE VMI$KWD:GTMDCBUILD.COM
+$ WRITE OUFILE "$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
+$ WRITE OUFILE "$! !"
+$ WRITE OUFILE "$! Copyright 2005, 2010 Fidelity Information Services, Inc !"
+$ WRITE OUFILE "$! !"
+$ WRITE OUFILE "$! This source code contains the intellectual property !"
+$ WRITE OUFILE "$! of its copyright holder(s), and is made available !"
+$ WRITE OUFILE "$! under a license. If you do not know the terms of !"
+$ WRITE OUFILE "$! the license, please stop and do not read further. !"
+$ WRITE OUFILE "$! !"
+$ WRITE OUFILE "$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! GTMDCBUILD.COM builds V5CBSU.EXE from V5CBSU.M."
+$ WRITE OUFILE "$! It calls GTMLOGIN.COM to setup the existing GT.M environment"
+$ WRITE OUFILE "$! then compiles and links V5CBSU."
+$ WRITE OUFILE "$! "
+$ WRITE OUFILE "$ @''GTMDC$GTM_LOG'GTMLOGIN"
+$ WRITE OUFILE "$ SET DEFAULT ''GTMDC$DST_LOG'"
+$ WRITE OUFILE "$ SET NOON"
+$ WRITE OUFILE "$ MUMPS V5CBSU"
+$ WRITE OUFILE "$ IF $STATUS THEN LINK V5CBSU,''GTMDC$GTM_LOG'_DH,''GTMDC$GTM_LOG'_EXP,''GTMDC$GTM_LOG'_UCASE"
+$ WRITE OUFILE "$! "
+$ WRITE OUFILE "$ EXIT"
+$ CLOSE OUFILE
+$! Create GTMDCDEFINE.COM
+$ OPEN /WRITE OUFILE VMI$KWD:GTMDCDEFINE.COM
+$ WRITE OUFILE "$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
+$ WRITE OUFILE "$! !"
+$ WRITE OUFILE "$! Copyright 2005, 2010 Fidelity Information Services, Inc !"
+$ WRITE OUFILE "$! !"
+$ WRITE OUFILE "$! This source code contains the intellectual property !"
+$ WRITE OUFILE "$! of its copyright holder(s), and is made available !"
+$ WRITE OUFILE "$! under a license. If you do not know the terms of !"
+$ WRITE OUFILE "$! the license, please stop and do not read further. !"
+$ WRITE OUFILE "$! !"
+$ WRITE OUFILE "$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! GTMDCDEFINE.COM defines symbols for DBCERTIFY.EXE and V5CBSU.EXE."
+$ WRITE OUFILE "$! It calls GTMLOGIN.COM to setup the existing GT.M environment"
+$ WRITE OUFILE "$! then defines the symbols."
+$ WRITE OUFILE "$! "
+$ WRITE OUFILE "$ @''GTMDC$GTM_LOG'GTMLOGIN"
+$ WRITE OUFILE "$ DBCERTIFY:==$''GTMDC$DST_LOG'DBCERTIFY.EXE"
+$ WRITE OUFILE "$ V5CBSU:==$''GTMDC$DST_LOG'V5CBSU.EXE"
+$ WRITE OUFILE "$! "
+$ WRITE OUFILE "$ EXIT"
+$ CLOSE OUFILE
+$ VMI$CALLBACK MESSAGE I PREINS "Preparing files for installation."
+$! GTMDCFILES.KIT must be maintained as kit contents change
+$ OPEN /WRITE OUFILE VMI$KWD:GTMDCFILES.KIT
+$ IF GTMDC$MGR_COM
+$ THEN
+$ WRITE OUFILE "GTMDC$ GTMDCBUILD.COM VMI$ROOT:[SYSMGR] C"
+$ WRITE OUFILE "GTMDC$ GTMDCDEFINE.COM VMI$ROOT:[SYSMGR] C"
+$ ENDIF
+$ WRITE OUFILE "GTMDC$ GTMDCBUILD.COM ''GTMDC$DST_LOG'"
+$ WRITE OUFILE "GTMDC$ GTMDCDEFINE.COM ''GTMDC$DST_LOG'"
+$ WRITE OUFILE "GTMDC$ V5CBSU.M ''GTMDC$DST_LOG'"
+$ CLOSE OUFILE
+$! GTMDCIMAGES.KIT must be maintained as kit contents change
+$ OPEN /WRITE OUFILE VMI$KWD:GTMDCIMAGES.KIT
+$ WRITE OUFILE "GTMDC$ DBCERTIFY.EXE ''GTMDC$DST_LOG'"
+$ CLOSE OUFILE
+$! Provide with file.KITs
+$ VMI$CALLBACK PROVIDE_FILE "" VMI$KWD:GTMDCFILES.KIT "" T
+$ VMI$CALLBACK PROVIDE_IMAGE "" VMI$KWD:GTMDCIMAGES.KIT "" T
+$ VMI$CALLBACK MESSAGE I FININS "Finalizing the installation."
+$ IF GTMDC$BLD_EXE THEN VMI$CALLBACK SET POSTINSTALL YES
+$ EXIT VMI$_SUCCESS
+$!
+$POSTINSTALL:
+$!
+$ TYPE SYS$INPUT
+
+ Building V5CBSU.EXE
+
+$ SET ON
+$ ON CONTROL_Y THEN EXIT VMI$_FAILURE
+$ IF GTMDC$MGR_COM
+$ THEN
+$ T1 := SYS$MANAGER:
+$ ELSE
+$ T1 = GTMDC$DST_LOG
+$ ENDIF
+$ @'T1'GTMDCBUILD
+$ ON CONTROL_Y THEN EXIT VMI$_FAILURE
+$ EXIT VMI$_SUCCESS
+$!
+$IVP:
+$! The real Installation Verification Procedure.
+$ TYPE SYS$INPUT
+
+ There is no GT.M DBCERTIFY utility Installation Verification Procedure
+
+$ EXIT $STATUS
diff --git a/sr_vvms/gtmfi_spkitbld.dat b/sr_vvms/gtmfi_spkitbld.dat
new file mode 100644
index 0000000..bc0d068
--- /dev/null
+++ b/sr_vvms/gtmfi_spkitbld.dat
@@ -0,0 +1,6 @@
+SPKITBLD$KITNAME := GTFI60002
+SPKITBLD$REWIND_TAPE := N
+SPKITBLD$AUTOINIT_TAPE := 'GTM_INIT_TAPE'
+SPKITBLD$SKIP_FIRST_TAPE_READY_PROMPT := Y
+SPKITBLD$SKIP_FIRST_DISK_READY_PROMPT := Y
+SPKITBLD$SAVESET_A :=GTM$VRT:[TFI]KITINSTAL.COM;,GTMFIKITHLP.COM;,GTM$VRT:[PRO]IBI_XFM.EXE;
diff --git a/sr_vvms/gtmfikithlp.com b/sr_vvms/gtmfikithlp.com
new file mode 100644
index 0000000..b7d1875
--- /dev/null
+++ b/sr_vvms/gtmfikithlp.com
@@ -0,0 +1,131 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2003 Sanchez Computer Associates, Inc. !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$!
+$! HELP TEXT PROCESSING FOR GT.M FOCUS INTERFACE KITINSTAL.COM
+$! COPYRIGHT 1989 - 2000 Sanchez Computer Associates
+$ IF F$EXTRACT(0,5,P1) .EQS. "HELP_" THEN GOTO 'P1'
+$ EXIT VMI$_UNSUPPORTED
+$HELP_PURGE:
+$ TYPE SYS$INPUT
+
+ If the GT.M FOCUS interface is previously installed, there is no reason to
+ keep older versions of the software online, unless you wish to test before
+ purging.
+
+$ EXIT
+$HELP_STD_CNF:
+$ TYPE SYS$INPUT
+ The standard configuration performs the following:
+
+ * Places files in SYS$COMMON:[GTM_DIST] with SYSTEM as owner.
+ * Defines the DSM_API logical name.
+ * Defines the logical name GTMAPI$FCS$nod to GTM$DIST:FOCUS.GLD, where nod
+ is the first three characters of the node name. This makes a connection
+ between a UCI of FCS and a volumeset of nod and the FOCUS.GLD.
+ * Copies the GT.M FOCUS interface command procedure to SYS$MANAGER.
+ * Adds GTMFISTART.COM to the system startup database.
+ * Sets up the GT.M FOCUS interface at the end of the installation.
+
+ If the SYSTEM id is not set up, the installation will use [1,4].
+
+$ EXIT
+$HELP_DST_OWN:
+$ TYPE SYS$INPUT
+ Provide a UIC, normally SYSTEM, to own the files in the GT.M FOCUS interface
+ distribution. The UIC can be a name, a group name and a user name separated
+ by a comma, or a pair of octal codes separated by a comma which specify
+ group and user.
+
+$ EXIT
+$HELP_SYS_DST:
+$ TYPE SYS$INPUT
+ Usual practice is to place a system component such as the GT.M FOCUS
+ interface on the system disk. If you have severe space constraints, you may
+ need to use another volume.
+
+$ EXIT
+$HELP_SYS_DIR:
+$ TYPE SYS$INPUT
+ This directory becomes be a sub-directory of SYS$COMMON and holds the
+ distribution. If it does not exist, the installation creates it with
+ WORLD=RE access. If you are not concerned with mixing software from
+ different vendors, you may wish to use SYSLIB.
+
+$ EXIT
+$HELP_DST_DEV:
+$ TYPE SYS$INPUT
+ The disk must be mounted, on-line and have adequate space to hold the
+ GT.M FOCUS interface distribution. The disk name may be physical or logical.
+
+$ EXIT
+$HELP_DST_DIR:
+$ TYPE SYS$INPUT
+ This directory holds the distribution. If it does not exist, the
+ installation creates it with WORLD=RE access.
+
+$ EXIT
+$HELP_GBLDIR:
+$ TYPE SYS$INPUT
+ The GT.M FOCUS interface requires one or more Global Directories in order to
+ find the appropriate database files. Each Global Directory is associated
+ with a "UCI" "Volume-set" pair by a logical name in the form of
+ GTMAPI$uci$vol where uci and vol are each 3 characters long. GTMFISTART
+ will define these logical names for you if you provide it with a list in the
+ form uci*vol*global-directory as P1. GTMFISTART defaults this list to a
+ single element where vol is the first three characters of the node-name, and
+ the uci and global directory are selected during the installation. Remember
+ that if the global directory file-specification contains a logical name,
+ the logical must be accessible to a detached process.
+
+$ EXIT
+$HELP_UCI_NAME:
+$ TYPE SYS$INPUT
+ The GT.M FOCUS interface requires one or more Global Directories in order to
+ find the appropriate database files. Each Global Directory is associated
+ with a "UCI" "Volume-set" pair by a logical name in the form of
+ GTMAPI$uci$vol where uci and vol are each 3 characters long. GTMFISTART
+ will define these logical names for you if you provide it with a list in the
+ form uci*vol*global-directory as P1. GTMFISTART defaults this list to a
+ single element where vol is the first three characters of the node-name, and
+ the uci and global directory are selected during the installation.
+
+$ EXIT
+$HELP_STARTDB:
+$ TYPE SYS$INPUT
+ Answering yes causes the installation to place GTMFISTART.COM in the
+ startup database so the system startup automatically sets up the GT.M FOCUS
+ interface whenever the system boots.
+
+$ EXIT
+$HELP_MGR_COM:
+$ TYPE SYS$INPUT
+ You may prevent the installation from moving the .COM files to SYS$MANAGER.
+ Copying the command procedures to SYS$MANAGER allows system startup to
+ access them through the VMS startup database and generally simplifies
+ operations. However, if you wish to have multiple versions of GT.M on your
+ system at the same time, you would not have multiple copies of the command
+ procedures in SYS$MANAGER.
+
+$ EXIT
+$HELP_RUN_IVP:
+$ TYPE SYS$INPUT
+ This installation kit contains an installation verification procedure (IVP)
+ which you can run as part of the installation to verify the correctness of
+ the software. Note that if you choose this option, the GT.M images must
+ already be installed.
+
+$ EXIT
+$HELP_START_GTMFI:
+$ TYPE SYS$INPUT
+ Answering yes causes the installation to set up the GT.M FOCUS interface.
+
+$ EXIT
diff --git a/sr_vvms/gtmfikitinstal.com b/sr_vvms/gtmfikitinstal.com
new file mode 100644
index 0000000..de07201
--- /dev/null
+++ b/sr_vvms/gtmfikitinstal.com
@@ -0,0 +1,239 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2003 Sanchez Computer Associates, Inc. !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$!
+$! KITINSTAL.COM PROCEDURE FOR THE GT.M FOCUS INTERFACE
+$!
+$ ON CONTROL_Y THEN VMI$CALLBACK CONTROL_Y
+$! ON WARNING THEN EXIT $STATUS !! allow warning on install replace
+$ IF P1 .EQS. "VMI$_INSTALL" THEN GOTO INSTALL
+$ IF P1 .EQS. "VMI$_POSTINSTALL" THEN GOTO POSTINSTALL
+$ IF P1 .EQS. "VMI$_IVP" THEN GOTO IVP
+$ EXIT VMI$_UNSUPPORTED
+$!
+$INSTALL:
+$ TYPE SYS$INPUT
+
+GT.M FOCUS INTERFACE (c) COPYRIGHT 1991-2000 by Sanchez Computer Associates
+ ALL RIGHTS RESERVED
+
+$! the following 2 lines must be maintained
+$ GTMFI$VMS_VERSION :== 072 ! Minimum VMS version required
+$ GTMFI$DISK_SPACE == 400 ! Minumum disk space on system disk required for install (2x result)
+$ IF F$ELEMENT(0,",",VMI$VMS_VERSION) .EQS. "RELEASED"
+$ THEN
+$ GTMFI$VMS_IS == F$ELEMENT(1,",",VMI$VMS_VERSION)
+$ IF GTMFI$VMS_IS .LTS. GTMFI$VMS_VERSION
+$ THEN
+$ VMI$CALLBACK MESSAGE E VMSMISMATCH "This GT.M FOCUS interface kit requires an existing VMS''GTMFI$VMS_VERSION' system."
+$ EXIT VMI$_FAILURE
+$ ENDIF
+$ ELSE
+$ GTMFI$VMS_IS :==
+$ WRITE SYS$OUTPUT " No VMS version checking performed for field test versions."
+$ ENDIF
+$ IF (GTMFI$VMS_IS .GES. "052") THEN T1 = F$VERIFY(VMI$KIT_DEBUG)
+$ VMI$CALLBACK CHECK_NET_UTILIZATION GTMFI$ROOM 'GTMFI$DISK_SPACE'
+$ IF .NOT. GTMFI$ROOM
+$ THEN
+$ VMI$CALLBACK MESSAGE E NOSPACE "There is not enough disk space -- GT.M FOCUS interface needs ''GTMFI$DISK_SPACE' blocks."
+$ EXIT VMI$_FAILURE
+$ ENDIF
+$! setup default answers
+$ GTMFI$DOPURGE :== YES
+$ GTMFI$RUN_IVP == 0 !! should be "YES", but no IVP yet
+$ GTMFI$STD_CNF :== YES
+$ GTMFI$DST_OWN :== SYSTEM
+$ IF F$IDENTIFIER(GTMFI$DST_OWN,"NAME_TO_NUMBER") .EQ. 0 THEN GTMFI$DST_OWN :== 1,4
+$ GTMFI$SYS_DST :== YES
+$ GTMFI$DST_DIR :== GTM_DIST
+$ GTMFI$DST_CRE == GTMFI$DST_DIR
+$ GTMFI$DST_DEV :==
+$ GTMFI$STARTDB :== YES
+$ GTMFI$MGR_COM :== YES
+$ GTMFI$START_GTMFI :== YES
+$ GTMFI$UCI_NAME :== FCS
+$!
+$ VMI$CALLBACK ASK GTMFI$DOPURGE "Do you want to purge files replaced by this installation" 'GTMFI$DOPURGE' B -
+ "@VMI$KWD:GTMFIKITHLP HELP_PURGE"
+$ IF .NOT. GTMFI$DOPURGE THEN VMI$CALLBACK SET PURGE NO
+$ VMI$CALLBACK ASK GTMFI$STD_CNF "Do you want the standard GT.M FOCUS interface configuration" 'GTMFI$STD_CNF' B -
+ "@VMI$KWD:GTMFIKITHLP HELP_STD_CNF"
+$ IF GTMFI$STD_CNF
+$ THEN
+$ GTMFI$SYS_DST == 1
+$ GTMFI$STARTDB == 1
+$ GTMFI$MGR_COM == 1
+$ GTMFI$START_GTMFI == 1
+$ GTMFI$DST_LOG :== SYS$COMMON:['GTMFI$DST_DIR']
+$ GTMFI$DIR_TYPE :== SYSTEM
+$ GTMFI$GBLDIR == GTMFI$DST_LOG + "FOCUS.GLD"
+$ GTMFI$RUN_IVP == 0 !! no IVP yet
+$ ELSE ! not standard configuration
+$ VMI$CALLBACK ASK GTMFI$DST_OWN "What UIC should own the GT.M FOCUS interface distribution" 'GTMFI$DST_OWN' S -
+ "@VMI$KWD:GTMFIKITHLP HELP_DST_OWN"
+$ GTMFI$DST_OWN == GTMFI$DST_OWN - "[" - "]"
+$ VMI$CALLBACK ASK GTMFI$SYS_DST "Do you want the GT.M FOCUS interface distribution to go into a System Directory" -
+ 'GTMFI$SYS_DST' B "@VMI$KWD:GTMFIKITHLP HELP_SYS_DST"
+$ IF GTMFI$SYS_DST
+$ THEN
+$ VMI$CALLBACK ASK GTMFI$DST_DIR "In what System Directory do you want to place GT.M FOCUS interface" 'GTMFI$DST_DIR' S -
+ "@VMI$KWD:GTMFIKITHLP HELP_SYS_DIR"
+$ GTMFI$DST_DIR == GTMFI$DST_DIR - "[" - "]"
+$ GTMFI$DST_CRE == GTMFI$DST_DIR
+$ GTMFI$DST_LOG :== SYS$COMMON:['GTMFI$DST_DIR']
+$ GTMFI$DIR_TYPE :== SYSTEM
+$ GTMFI$GBLDIR == GTMFI$DST_LOG + "FOCUS.GLD"
+$ ELSE ! not system disk
+$ VMI$CALLBACK ASK GTMFI$DST_DEV "On which device do you want to place the GT.M FOCUS interface" "''GTMFI$DST_DEV'" S -
+ "@VMI$KWD:GTMFIKITHLP HELP_DST_DEV"
+$ VMI$CALLBACK ASK GTMFI$DST_DIR "In what directory on that device do you want to place the GT.M FOCUS interface" -
+ 'GTMFI$DST_DIR' S "@VMI$KWD:GTMFIKITHLP HELP_DST_DIR"
+$ GTMFI$DST_DEV == GTMFI$DST_DEV - ":"
+$ GTMFI$DST_DIR == GTMFI$DST_DIR - "[" - "]"
+$ GTMFI$DST_LOG :== 'GTMFI$DST_DEV':['GTMFI$DST_DIR']
+$ GTMFI$DST_CRE == GTMFI$DST_LOG
+$ GTMFI$DIR_TYPE :== USER
+$ GTMFI$GBLDIR == GTMFI$DST_LOG + "FOCUS.GLD"
+$ ENDIF ! system disk
+$ VMI$CALLBACK ASK GTMFI$LM_FILE "What do you want to call the configuration database file" 'GTMFI$LM_FILE' S -
+ "@VMI$KWD:GTMFIKITHLP HELP_LM_FILE"
+$ VMI$CALLBACK ASK GTMFI$GBLDIR "What file do you want as the global directory for the GT.M FOCUS interface" 'GTMFI$GBLDIR' S -
+ "@VMI$KWD:GTMFIKITHLP HELP_GBLDIR"
+$ VMI$CALLBACK ASK GTMFI$UCI_NAME "What ""UCI"" do you want to assign to the GT.M FOCUS interface" 'GTMFI$UCI_NAME' S -
+ "@VMI$KWD:GTMFIKITHLP HELP_UCI_NAME"
+$ VMI$CALLBACK ASK GTMFI$STARTDB "Do you want GTMFISTART.COM in the startup database" 'GTMFI$STARTDB' B -
+ "@VMI$KWD:GTMFIKITHLP HELP_STARTDB"
+$ IF .NOT. GTMFI$STARTDB
+$ THEN
+$ VMI$CALLBACK ASK GTMFI$MGR_COM "Do you want the GTMFISTART.COM file in SYS$MANAGER" 'GTMFI$MGR_COM' B -
+ "@VMI$KWD:GTMFIKITHLP HELP_MGR_COM"
+$ ENDIF
+$!! no IVP yet
+$ IF FALSE THEN VMI$CALLBACK ASK GTMFI$RUN_IVP "Do you want to run the IVP (requires GT.M)" 'GTMFI$RUN_IVP' B -
+ "@VMI$KWD:GTMFIKITHLP HELP_RUN_IVP"
+$ IF GTMFI$RUN_IVP
+$ THEN
+$ GTMFI$START_GTMFI == 1
+$ ELSE
+$ VMI$CALLBACK ASK GTMFI$START_GTMFI "Do you want to set up the GT.M FOCUS interface now" 'GTMFI$START_GTMFI' B -
+ "@VMI$KWD:GTMFIKITHLP HELP_START_GTMFI"
+$ ENDIF
+$ ENDIF ! standard configuration
+$ IF GTMFI$MGR_COM
+$ THEN
+$ WRITE SYS$OUTPUT " The following command file is created and copied to SYS$MANAGER:"
+$ ELSE
+$ WRITE SYS$OUTPUT " The following command file is created:"
+$ ENDIF
+$ TYPE SYS$INPUT
+
+ GTMFISTART.COM
+
+ The file contains its own user documentation.
+
+ All the questions have been asked. Installation now proceeds without your
+ manual intervention for about 5-10 minutes.
+$ IF GTMFI$RUN_IVP THEN WRITE SYS$OUTPUT " Finally the installation verification procedure tests the installation."
+$ WRITE SYS$OUTPUT ""
+$!! When VMS 5.2 is required, the following line should be removed in favor of changing all GTMFI$DIR_TYPE :== SYSTEM to :== COMMON
+$ IF (GTMFI$VMS_IS .GES. "052") .AND. (GTMFI$DIR_TYPE .EQS. "SYSTEM") THEN GTMFI$DIR_TYPE :== COMMON
+$ VMI$CALLBACK CREATE_DIRECTORY 'GTMFI$DIR_TYPE' 'GTMFI$DST_CRE' "/OWNER_UIC=[''GTMFI$DST_OWN'] /PROTECTION=(WO:RE)"
+$ VMI$CALLBACK MESSAGE I CRECOM "Creating command files."
+$! Create GTMFISTART.COM
+$ OPEN /WRITE OUFILE VMI$KWD:GTMFISTART.COM
+$ WRITE OUFILE "$! GTMFISTART.COM provides GT.M FOCUS interface for a node."
+$ WRITE OUFILE "$! It defines the IBI_XFM logical name, and the logical names"
+$ WRITE OUFILE "$! relating UCIs and Volumesets to global directories the interface."
+$ WRITE OUFILE "$! The invoking user requires the SYSNAM privilege."
+$ WRITE OUFILE "$! P1 is a list of volume-set, UCI, file-specification triples, where "
+$ WRITE OUFILE "$! the 3 parts are separated by asterisks (*) and the list is separated "
+$ WRITE OUFILE "$! by commas. The volume-set and UCI must be 3 character names, and "
+$ WRITE OUFILE "$! the file-specification may be a logical name. This defaults to a "
+$ WRITE OUFILE "$! single triple consisting of the 1st 3 characters of the node name,"
+$ WRITE OUFILE "$! the literal FCS and GTM$DIST:FOCUS.GLD. e.g., if P1 is"
+$ WRITE OUFILE "$! null for node MIKE - MIK*FCS*GTM$DIST:FOCUS.GLD."
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$ CURPRV = F$SETPRV(""TMPMBX"")"
+$ WRITE OUFILE "$ ON CONTROL_C THEN GOTO ERROR"
+$ WRITE OUFILE "$ ON ERROR THEN GOTO ERROR"
+$ WRITE OUFILE "$ CURPRV=F$SETPRV(""SYSNAM"")+"",""+CURPRV"
+$ WRITE OUFILE "$ IF F$PRIVILEGE(""SYSNAM"")"
+$ WRITE OUFILE "$ THEN"
+$ WRITE OUFILE "$ DEFINE /SYSTEM IBI_XFM ''GTMFI$DST_LOG'IBI_XFM.EXE"
+$ WRITE OUFILE "$ P1 = F$EDIT(P1,""COLLAPSE"")"
+$ WRITE OUFILE "$ IF P1 .EQS. """" "
+$ WRITE OUFILE "$ THEN"
+$ WRITE OUFILE "$ P1=F$EXTRACT(0,3,F$EDIT(F$GETSYI(""SCSNODE""),""TRIM"") + ""___"") + ""*''GTMFI$UCI_NAME'*''GTMFI$GBLDIR'"""
+$ WRITE OUFILE "$ ENDIF"
+$ WRITE OUFILE "$ N = 0"
+$ WRITE OUFILE "$ GOSUB UCI"
+$ WRITE OUFILE "$ ENDIF"
+$ WRITE OUFILE "$ERROR:"
+$ WRITE OUFILE "$ CURPRV = F$SETPRV(CURPRV)"
+$ WRITE OUFILE "$ EXIT"
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$UCI:"
+$ WRITE OUFILE "$ T1 = F$ELEMENT(N,"","",P1)"
+$ WRITE OUFILE "$ IF T1 .EQS. "","" THEN RETURN"
+$ WRITE OUFILE "$ VLS = F$EXTRACT(0,3,F$ELEMENT(0,""*"",T1)+""___"")"
+$ WRITE OUFILE "$ UCI = F$EXTRACT(0,3,F$ELEMENT(1,""*"",T1)+""___"")"
+$ WRITE OUFILE "$ GLD = F$ELEMENT(2,""*"",T1)"
+$ WRITE OUFILE "$ DEFINE /SYSTEM GTMAPI$'UCI'$'VLS' 'GLD'"
+$ WRITE OUFILE "$ N = N + 1"
+$ WRITE OUFILE "$ GOTO UCI"
+$ CLOSE OUFILE
+$ VMI$CALLBACK MESSAGE I PREINS "Preparing files for installation."
+$! GTMFIFILES.KIT must be maintained as kit contents change
+$ OPEN /WRITE OUFILE VMI$KWD:GTMFIFILES.KIT
+$ IF GTMFI$MGR_COM
+$ THEN
+$ WRITE OUFILE "GTMFI$ GTMFISTART.COM VMI$ROOT:[SYSMGR] C"
+$ ENDIF
+$ WRITE OUFILE "GTMFI$ GTMFISTART.COM ''GTMFI$DST_LOG'"
+$ CLOSE OUFILE
+$! GTMFIIMAGES.KIT must be maintained as kit contents change
+$ OPEN /WRITE OUFILE VMI$KWD:GTMFIIMAGES.KIT
+$ WRITE OUFILE "GTMFI$ IBI_XFM.EXE ''GTMFI$DST_LOG'"
+$ CLOSE OUFILE
+$! Provide with file.KITs
+$ VMI$CALLBACK PROVIDE_FILE "" VMI$KWD:GTMFIFILES.KIT "" T
+$ VMI$CALLBACK PROVIDE_IMAGE "" VMI$KWD:GTMFIIMAGES.KIT "" T
+$ VMI$CALLBACK MESSAGE I FININS "Finalizing the installation."
+$ IF GTMFI$START_GTMFI THEN VMI$CALLBACK SET POSTINSTALL YES
+$ IF GTMFI$RUN_IVP THEN VMI$CALLBACK SET IVP YES
+$ IF GTMFI$STARTDB THEN VMI$CALLBACK MODIFY_STARTUP_DB ADD GTMFISTART.COM END
+$ EXIT VMI$_SUCCESS
+$!
+$POSTINSTALL:
+$!
+$ SET ON
+$! do a gtmlogin
+$ @'GTMFI$DST_LOG'GTMLOGIN
+$ IF GTMFI$MGR_COM
+$ THEN
+$ T1 := SYS$MANAGER:
+$ ELSE
+$ T1 = GTMFI$DST_LOG
+$ ENDIF
+$ @'T1'GTMFISTART
+$ EXIT VMI$_SUCCESS
+$!
+$IVP:
+$! The real Installation Verification Procedure.
+$ TYPE SYS$INPUT
+
+ GT.M FOCUS interface Installation Verification Procedure
+
+$! Extract the IVP .COM file from the text library.
+$ LIBRARIAN /EXTRACT=GTMFI$IVP /OUTPUT=GTMFI$IVP.COM GTMFI$IVP.TLB
+$ @GTMFI$IVP
+$ EXIT $STATUS
diff --git a/sr_vvms/gtmidef.h b/sr_vvms/gtmidef.h
new file mode 100644
index 0000000..d881367
--- /dev/null
+++ b/sr_vvms/gtmidef.h
@@ -0,0 +1,26 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/*
+ gtmidef.h : counterpart to the gtmi$def.mar
+
+*/
+#define GTMI$_GLOBAL 1
+#define GTMI$_NAKED 2
+#define GTMI$_EXTGBL 3
+#define GTMI$_LOCAL 4
+#define GTMI$_EXTLCL 5
+#define GTMI$_LOCK 6
+#define GTMI$_ZALLOC 7
+#define GTMI$_ZDEALLOC 8
+#define GTMI$_INCLOCK 9
+#define GTMI$_DECLOCK 10
+#define GTMI$_UNLOCK 11
diff --git a/sr_vvms/gtmio.h b/sr_vvms/gtmio.h
new file mode 100644
index 0000000..a7dce21
--- /dev/null
+++ b/sr_vvms/gtmio.h
@@ -0,0 +1,104 @@
+/****************************************************************
+ * *
+ * Copyright 2003, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+#ifndef GTMIO_Included
+#define GTMIO_Included
+
+/* Include necessary files for system calls
+ * CHANNEL : The channel to read
+ * OFFSET : Disk offset in bytes. Should be divisible by DISK_BLOCK_SIZE.
+ * BUFF : Buffer to read data.
+ * LEN : Length in bytes to read.
+ * STATUS1 : Status of system call
+ * STATUS2 : Secondary status of system call
+ */
+#define DO_FILE_READ(CHANNEL, OFFSET, READBUFF, LEN, STATUS1, STATUS2) \
+{ \
+ off_jnl_t start; \
+ io_status_block_disk iosb; \
+ \
+ STATUS2 = SS_NORMAL; \
+ assert(0 == (OFFSET) % DISK_BLOCK_SIZE); \
+ start = OFFSET >> LOG2_DISK_BLOCK_SIZE; \
+ STATUS1 = sys$qiow(EFN$C_ENF, CHANNEL, IO$_READVBLK, &iosb, NULL, 0, \
+ (uchar_ptr_t)(READBUFF), LEN, start + 1, 0, 0, 0); \
+ if (1 & STATUS1) \
+ STATUS1 = iosb.cond; \
+}
+
+#define DB_DO_FILE_WRITE(CHANNEL, OFFSET, WRITEBUFF, LEN, STATUS1, STATUS2) \
+ DO_FILE_WRITE(CHANNEL, OFFSET, WRITEBUFF, LEN, STATUS1, STATUS2)
+
+#define JNL_DO_FILE_WRITE(CSA, JNL_FN, CHANNEL, OFFSET, WRITEBUFF, LEN, STATUS1, STATUS2) \
+ DO_FILE_WRITE(CHANNEL, OFFSET, WRITEBUFF, LEN, STATUS1, STATUS2)
+
+#define DO_FILE_WRITE(CHANNEL, OFFSET, WRITEBUFF, LEN, STATUS1, STATUS2) \
+{ \
+ off_jnl_t start; \
+ io_status_block_disk iosb; \
+ \
+ STATUS2 = SS_NORMAL; \
+ assert(0 == (OFFSET) % DISK_BLOCK_SIZE); \
+ start = OFFSET >> LOG2_DISK_BLOCK_SIZE; \
+ STATUS1 = sys$qiow(EFN$C_ENF, CHANNEL, IO$_WRITEVBLK, &iosb, NULL, 0, \
+ (uchar_ptr_t)(WRITEBUFF), LEN, start + 1, 0, 0, 0); \
+ if (1 & STATUS1) \
+ STATUS1 = iosb.cond; \
+}
+
+#define DOREADRC(FDESC, FBUFF, FBUFF_LEN, RC) \
+{ \
+ ssize_t gtmioStatus; \
+ size_t gtmioBuffLen; \
+ sm_uc_ptr_t gtmioBuff; \
+ gtmioBuffLen = FBUFF_LEN; \
+ gtmioBuff = (sm_uc_ptr_t)(FBUFF); \
+ for (;;) \
+ { \
+ if (-1 != (gtmioStatus = read(FDESC, gtmioBuff, gtmioBuffLen))) \
+ { \
+ gtmioBuffLen -= gtmioStatus; \
+ if (0 == gtmioBuffLen || 0 == gtmioStatus) \
+ break; \
+ gtmioBuff += gtmioStatus; \
+ } \
+ else if (EINTR != errno) \
+ break; \
+ } \
+ if (-1 == gtmioStatus) /* Had legitimate error - return it */ \
+ RC = errno; \
+ else if (0 == gtmioBuffLen) \
+ RC = 0; \
+ else \
+ RC = -1; /* Something kept us from reading what we wanted */ \
+}
+
+/* Use CLOSEFILE for those files (or sockets) that are opened using UNIX (POSIX) system calls */
+#define CLOSEFILE(FDESC, RC) \
+{ \
+ do \
+ { \
+ RC = close(FDESC); \
+ } while(-1 == RC && EINTR == errno); \
+ if (-1 == RC) /* Had legitimate error - return it */ \
+ RC = errno; \
+}
+
+/* CLOSEFILE_RESET
+ * Loop until close succeeds for fails with other than EINTR.
+ * At end reset channel to FD_INVALID unconditionally (even if close was not successful).
+ */
+#define CLOSEFILE_RESET(FDESC, RC) \
+{ \
+ CLOSEFILE(FDESC, RC); \
+ FDESC = FD_INVALID; \
+}
+
+#endif
diff --git a/sr_vvms/gtmkithlp.com b/sr_vvms/gtmkithlp.com
new file mode 100644
index 0000000..b8ea2c5
--- /dev/null
+++ b/sr_vvms/gtmkithlp.com
@@ -0,0 +1,172 @@
+$!
+$! HELP TEXT PROCESSING FOR GT.M KITINSTAL.COM
+$! COPYRIGHT 1989 - 2000 Sanchez Computer Associates
+$ IF F$EXTRACT(0,5,P1) .EQS. "HELP_" THEN GOTO 'P1'
+$ EXIT VMI$_UNSUPPORTED
+$HELP_PURGE:
+$ TYPE SYS$INPUT
+ If GT.M is previously installed, there is no reason to keep older versions
+ of the software online, unless you wish to test before purging.
+
+$ EXIT
+$HELP_STD_CNF:
+$ TYPE SYS$INPUT
+ The standard configuration performs the following:
+
+ * Places files in SYS$COMMON:[GTM_DIST] with SYSTEM as owner
+ * Copies the GT.M command procedures to SYS$MANAGER
+ * Adds GTMSTART.COM to the system startup database
+ * Leaves GT.M help files in GTM$DIST (does not move them to SYS$HELP)
+ * Defines DCL commands for GT.M in the system command table
+ * Defines logical names, including LNK$LIBRARY*, in the system table
+ * INSTALLs all the appropriate GT.M images during the installation
+ * Defines the default global directory as MUMPS.GLD
+ * Defines the default routine search list as "[],GTM$DIST:"
+ * Compiles the MUMPS percent routines
+
+ If the SYSTEM id is not set up, the installation will use [1,4].
+ If you answer YES, there are no other questions.
+
+$ EXIT
+$HELP_DST_OWN:
+$ TYPE SYS$INPUT
+ Provide a UIC, normally SYSTEM, to own the files in the GT.M distribution.
+ The UIC can be a name, a group name and a user name separated by a comma,
+ or a pair of octal codes separated by a comma which specify group and user.
+
+$ EXIT
+$HELP_SYS_DST:
+$ TYPE SYS$INPUT
+ Usual practice is to place a language processor, such as GT.M, on the system
+ disk. If you have severe space constraints, you may need to use another
+ volume.
+
+$ EXIT
+$HELP_SYS_DIR:
+$ TYPE SYS$INPUT
+ This directory becomes a sub-directory of SYS$COMMON, and holds the
+ distribution. If it does not exist, the installation creates it with
+ WORLD=RE access. If you are not concerned with mixing software from
+ different vendors, you may wish to use SYSLIB.
+
+$ EXIT
+$HELP_DST_DEV:
+$ TYPE SYS$INPUT
+ The disk must be mounted, on-line, and have adequate space to hold the GT.M
+ distribution. The disk name may be physical or logical.
+
+$ EXIT
+$HELP_DST_DIR:
+$ TYPE SYS$INPUT
+ This directory holds the distribution. If it does not exist, the
+ installation creates it with WORLD=RE access.
+
+$ EXIT
+$HELP_STARTDB:
+$ TYPE SYS$INPUT
+ Answering yes causes the installation to place GTMSTART.COM in the startup
+ database so the system startup automatically sets up the GT.M environment
+ whenever the system boots.
+
+$ EXIT
+$HELP_MGR_COM:
+$ TYPE SYS$INPUT
+ You may prevent the installation from moving the .COM files to SYS$MANAGER.
+ Copying the command procedures to SYS$MANAGER allows system startup to
+ access them through the VMS startup database and generally simplifies
+ operations. However, if you wish to have multiple versions of GT.M on your
+ system at the same time, multiple copies of the command procedures in
+ SYS$MANAGER would require intervention to provide alternative naming.
+
+$ EXIT
+$HELP_HLP_DIR:
+$ TYPE SYS$INPUT
+ You may place the GT.M help files in SYS$HELP or leave them with the rest of
+ the distribution.
+
+$ EXIT
+$HELP_DEF_DCL:
+$ TYPE SYS$INPUT
+ Common practice is (YES) to define commands in the system command tables
+ (SYS$LIBRARY:DCLTABLES.EXE). A less efficient, but sometimes more flexible,
+ alternative, has each process define them as it starts. Another alternative
+ uses alternate command tables. GT.M uses the MUMPS command.
+
+$ EXIT
+$HELP_DEF_SYS:
+$ TYPE SYS$INPUT
+ Common practice is (YES) to define widely used logical names in the SYSTEM
+ logical name table. A less efficient but sometimes more flexible
+ alternative has each process define them as it starts. Other alternatives
+ use definitions in one or more GROUP logical name tables, or in a logical
+ name table other than those supplied with VMS.
+
+$ EXIT
+$HELP_LNK_LOG:
+$ TYPE SYS$INPUT
+ LNK$LIBRARYn logical names point to libraries included by default when
+ performing an image LINK under VMS. GT.M links require an object library,
+ GTMLIB.OLB, and a shareable image library, GTMSHR.OLB. Adding these
+ libraries to your list of LNK$LIBRARY logical names simplifies your LINK
+ commands for GT.M. If you answer YES, then the installation procedure finds
+ the next two available LNK$LIBRARYn logical names FOR THIS PROCESS, and
+ defines them so they point to the appropriate GT.M libraries.
+
+$ EXIT
+$HELP_RUN_IVP:
+$ TYPE SYS$INPUT
+ This installation kit contains an installation verification procedure (IVP)
+ which you can run as part of the installation to verify the correctness of
+ the software. Note that if you choose this option, the GT.M images are
+ automatically INSTALLed.
+
+$ EXIT
+$HELP_PCT_RTN:
+$ TYPE SYS$INPUT
+ The GT.M Mumps System is distributed with a set of programmer tools,
+ so-called percent (%) routines. If you answer YES to this question, the
+ installation compiles these routines. Note that if you choose this option,
+ the GT.M images are automatically INSTALLed.
+
+$ EXIT
+$HELP_INSTALL:
+$ TYPE SYS$INPUT
+ In order to run GT.M, certain images must be INSTALLed in your system with
+ the INSTALL utility. If you answer YES, then these images are INSTALLed
+ during this installation procedure. You may wish to defer this for
+ operational reasons, or until you have completed a brief evaluation.
+
+$ EXIT
+$HELP_DEF_RTN:
+$ TYPE SYS$INPUT
+ GTM$ROUTINES is a logical name for your MUMPS routine search list. If you
+ answer YES, the installation adds a default definition for this search list
+ to GTMLOGICALS.COM.
+
+$ EXIT
+$HELP_RTN_DIR:
+$ TYPE SYS$INPUT
+ The installation uses this string as the definition for the GTM$ROUTINES
+ search list. The directories specified do not need to exist at this time.
+ This definition can be easily changed later. Because GTM$ROUTINES provides
+ a string to GT.M and does not act as a VMS search list, you should enclose
+ the items in the list with quotes (") when the list has more than one item.
+
+
+$ EXIT
+$HELP_DEF_GLD:
+$ TYPE SYS$INPUT
+ GTM$GBLDIR is a logical name for your global directory. If you answer YES,
+ the installation adds a default definition for the global directory to
+ GTMLOGICALS.COM.
+
+$ EXIT
+$HELP_GBL_DIR:
+$ TYPE SYS$INPUT
+ The installation uses this string as the definition for the GTM$GBLDIR
+ global directory name. This file specification may be a partial or complete
+ file specification. The file does not need to exist at this time. A partial
+ file specification is usually used for development, and a complete one for
+ production. This definition can be easily changed later.
+
+$ EXIT
diff --git a/sr_vvms/gtmkitinstal.com b/sr_vvms/gtmkitinstal.com
new file mode 100644
index 0000000..b4701ff
--- /dev/null
+++ b/sr_vvms/gtmkitinstal.com
@@ -0,0 +1,443 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2011 Fidelity Information Services, Inc !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$!
+$! KITINSTAL.COM PROCEDURE FOR THE GT.M PRODUCT
+$!
+$ ON CONTROL_Y THEN VMI$CALLBACK CONTROL_Y
+$! ON WARNING THEN EXIT $STATUS !! allow warning errors for INSTALL REPLACE
+$ IF P1 .EQS. "VMI$_INSTALL" THEN GOTO INSTALL
+$ IF P1 .EQS. "VMI$_POSTINSTALL" THEN GOTO POSTINSTALL
+$ IF P1 .EQS. "VMI$_IVP" THEN GOTO IVP
+$ EXIT VMI$_UNSUPPORTED
+$!
+$INSTALL:
+$ TYPE SYS$INPUT
+
+ GT.M (c) COPYRIGHT 1985 - 2000 by Sanchez Computer Associates
+ ALL RIGHTS RESERVED
+
+$! the following 2 lines must be maintained
+$ GTM$VMS_VERSION :== 072 ! Minimum VMS version required
+$ ALPHA = (f$getsyi("arch_name") .eqs. "Alpha")
+$ IF ALPHA
+$ THEN
+$ GTM$DISK_SPACE == 28000 ! Minumum disk space on system disk required
+$ ELSE
+$ GTM$DISK_SPACE == 16000 ! Minumum disk space on system disk required
+$ ENDIF
+$ IF F$ELEMENT(0,",",VMI$VMS_VERSION) .EQS. "RELEASED"
+$ THEN
+$ GTM$VMS_IS == F$ELEMENT(1,",",VMI$VMS_VERSION)
+$ IF GTM$VMS_IS .LTS. GTM$VMS_VERSION
+$ THEN
+$ VMI$CALLBACK MESSAGE E VMSMISMATCH "This GT.M kit requires an existing VMS''GTM$VMS_VERSION' system."
+$ EXIT VMI$_FAILURE
+$ ENDIF
+$ ELSE
+$ GTM$VMS_IS :==
+$ WRITE SYS$OUTPUT " No VMS version checking performed for field test versions."
+$ ENDIF
+$ IF (GTM$VMS_IS .GES. "052") THEN T1 = F$VERIFY(VMI$KIT_DEBUG)
+$ VMI$CALLBACK CHECK_NET_UTILIZATION GTM$ROOM 'GTM$DISK_SPACE'
+$ IF .NOT. GTM$ROOM
+$ THEN
+$ VMI$CALLBACK MESSAGE E NOSPACE "There is not enough disk space -- GT.M needs ''GTM$DISK_SPACE' blocks."
+$ EXIT VMI$_FAILURE
+$ ENDIF
+$! setup default answers
+$ GTM$DOPURGE :== YES
+$ GTM$RUN_IVP :== YES
+$ GTM$STD_CNF :== YES
+$ GTM$DST_OWN :== SYSTEM
+$ IF F$IDENTIFIER(GTM$DST_OWN,"NAME_TO_NUMBER") .EQ. 0 THEN GTM$DST_OWN :== 1,4
+$ GTM$SYS_DST :== YES
+$ GTM$DST_DIR :== GTM_DIST
+$ GTM$DST_CRE == GTM$DST_DIR
+$ GTM$DST_DEV :==
+$ GTM$STARTDB :== YES
+$ GTM$MGR_COM :== YES
+$ GTM$HLP_DIR :== NO
+$ GTM$DEF_DCL :== YES
+$ GTM$DEF_SYS :== YES
+$ GTM$LNK_LOG :== YES
+$ GTM$INSTALL :== YES
+$ GTM$DEF_GLD :== YES
+$ GTM$GBL_DIR :== MUMPS.GLD
+$ GTM$DEF_RTN :== YES
+$ GTM$RTN_DIR :== [],GTM$DIST:
+$ GTM$PCT_RTN :== YES
+$ VMI$CALLBACK ASK GTM$DOPURGE "Do you want to purge files replaced by this installation" 'GTM$DOPURGE' B -
+ "@VMI$KWD:GTMKITHLP HELP_PURGE"
+$ IF .NOT. GTM$DOPURGE THEN VMI$CALLBACK SET PURGE NO
+$ VMI$CALLBACK ASK GTM$STD_CNF "Do you want the standard GT.M configuration (performs INSTALL)" 'GTM$STD_CNF' B -
+ "@VMI$KWD:GTMKITHLP HELP_STD_CNF"
+$ IF GTM$STD_CNF
+$ THEN
+$ GTM$SYS_DST == 1
+$ GTM$STARTDB == 1
+$ GTM$MGR_COM == 1
+$ GTM$HLP_DIR == 0
+$ GTM$DEF_DCL == 1
+$ GTM$DEF_SYS == 1
+$ GTM$INSTALL == 1
+$ GTM$LNK_LOG == 1
+$ GTM$INSTALL == 1
+$ GTM$DEF_GLD == 1
+$ GTM$DEF_RTN == 1
+$ GTM$PCT_RTN == 1
+$ GTM$DST_LOG :== SYS$COMMON:['GTM$DST_DIR']
+$ GTM$DIR_TYPE :== COMMON
+$ ELSE ! Not standard configuration
+$ VMI$CALLBACK ASK GTM$DST_OWN "What UIC should own the GT.M distribution" 'GTM$DST_OWN' S "@VMI$KWD:GTMKITHLP HELP_DST_OWN"
+$ GTM$DST_OWN == GTM$DST_OWN - "[" - "]"
+$ VMI$CALLBACK ASK GTM$SYS_DST "Do you want the GT.M distribution to go into a System Directory" 'GTM$SYS_DST' B -
+ "@VMI$KWD:GTMKITHLP HELP_SYS_DST"
+$ IF GTM$SYS_DST
+$ THEN
+$ VMI$CALLBACK ASK GTM$DST_DIR "In what System Directory do you want to place GT.M" 'GTM$DST_DIR' S -
+ "@VMI$KWD:GTMKITHLP HELP_SYS_DIR"
+$ GTM$DST_DIR == GTM$DST_DIR - "[" - "]"
+$ GTM$DST_CRE == GTM$DST_DIR
+$ GTM$DST_LOG :== SYS$COMMON:['GTM$DST_DIR']
+$ GTM$DIR_TYPE :== COMMON
+$ ELSE ! Not system disk
+$ VMI$CALLBACK ASK GTM$DST_DEV "On which device do you want to place GT.M" "''GTM$DST_DEV'" S "@VMI$KWD:GTMKITHLP HELP_DST_DEV"
+$ VMI$CALLBACK ASK GTM$DST_DIR "In what directory on that device do you want to place GT.M" 'GTM$DST_DIR' S -
+ "@VMI$KWD:GTMKITHLP HELP_DST_DIR"
+$ GTM$DST_DEV == GTM$DST_DEV - ":"
+$ GTM$DST_DIR == GTM$DST_DIR - "[" - "]"
+$ GTM$DST_LOG :== 'GTM$DST_DEV':['GTM$DST_DIR']
+$ GTM$DST_CRE == GTM$DST_LOG
+$ GTM$DIR_TYPE :== USER
+$ ENDIF ! system disk
+$ VMI$CALLBACK ASK GTM$STARTDB "Do you want GTMSTART.COM in the startup database" 'GTM$STARTDB' B -
+ "@VMI$KWD:GTMKITHLP HELP_STARTDB"
+$ IF .NOT. GTM$STARTDB
+$ THEN
+$ VMI$CALLBACK ASK GTM$MGR_COM "Do you want the GT.M .COM files in SYS$MANAGER" 'GTM$MGR_COM' B -
+ "@VMI$KWD:GTMKITHLP HELP_MGR_COM"
+$ ENDIF
+$ VMI$CALLBACK ASK GTM$HLP_DIR "Do you want the GT.M help files in SYS$HELP" 'GTM$HLP_DIR' B "@VMI$KWD:GTMKITHLP HELP_HLP_DIR"
+$ VMI$CALLBACK ASK GTM$DEF_DCL "Do you want to define GT.M commands to the system" 'GTM$DEF_DCL' B -
+ "@VMI$KWD:GTMKITHLP HELP_DEF_DCL"
+$ VMI$CALLBACK ASK GTM$DEF_SYS "Do you want to define GT.M logical names in the System Table" 'GTM$DEF_SYS' B -
+ "@VMI$KWD:GTMKITHLP HELP_DEF_SYS"
+$ VMI$CALLBACK ASK GTM$LNK_LOG "Do you want to define the LNK$LIBRARY logical names" 'GTM$LNK_LOG' B -
+ "@VMI$KWD:GTMKITHLP HELP_LNK_LOG"
+$ VMI$CALLBACK ASK GTM$RUN_IVP "Do you want to run the IVP (performs INSTALL)" 'GTM$RUN_IVP' B -
+ "@VMI$KWD:GTMKITHLP HELP_RUN_IVP"
+$ IF GTM$RUN_IVP
+$ THEN
+$ GTM$PCT_RTN == 1
+$ ELSE
+$ VMI$CALLBACK ASK GTM$PCT_RTN "Do you want to compile the GT.M percent routines (performs INSTALL)" 'GTM$PCT_RTN' B -
+ "@VMI$KWD:GTMKITHLP HELP_PCT_RTN"
+$ ENDIF
+$ IF (GTM$RUN_IVP .OR. GTM$PCT_RTN)
+$ THEN
+$ GTM$INSTALL == 1
+$ ELSE
+$ VMI$CALLBACK ASK GTM$INSTALL "Do you want to INSTALL the GT.M shareable images now" 'GTM$INSTALL' B -
+ "@VMI$KWD:GTMKITHLP HELP_INSTALL"
+$ ENDIF
+$ VMI$CALLBACK ASK GTM$DEF_RTN "Do you want to have a default definition for GTM$ROUTINES" 'GTM$DEF_RTN' B -
+ "@VMI$KWD:GTMKITHLP HELP_DEF_RTN"
+$ IF GTM$DEF_RTN
+$ THEN
+$ VMI$CALLBACK ASK GTM$RTN_DIR "What is the search specification for GTM$ROUTINES" 'GTM$RTN_DIR' S -
+ "@VMI$KWD:GTMKITHLP HELP_RTN_DIR"
+$ ENDIF
+$ VMI$CALLBACK ASK GTM$DEF_GLD "Do you want to have a default definition for GTM$GBLDIR" 'GTM$DEF_GLD' B -
+ "@VMI$KWD:GTMKITHLP HELP_DEF_GLD"
+$ IF GTM$DEF_GLD
+$ THEN
+$ VMI$CALLBACK ASK GTM$GBL_DIR "What is the file specification for GTM$GBLDIR" 'GTM$GBL_DIR' S -
+ "@VMI$KWD:GTMKITHLP HELP_GBL_DIR"
+$ ENDIF
+$ ENDIF ! standard configuration
+$! tell them what's happening
+$ IF GTM$MGR_COM
+$ THEN
+$ WRITE SYS$OUTPUT " The following command files are created and copied to SYS$MANAGER:"
+$ ELSE
+$ WRITE SYS$OUTPUT " The following command files are created:"
+$ ENDIF
+$ TYPE SYS$INPUT
+
+ GTMINSTALL.COM
+ GTMLOGICALS.COM
+ GTMLOGIN.COM
+ GTMSTART.COM
+ GTMSTOP.COM
+
+ Each file contains its own user documentation.
+
+ All the questions have been asked. Installation now proceeds without your
+ manual intervention for about 10-15 minutes.
+$ IF GTM$RUN_IVP THEN WRITE SYS$OUTPUT " Finally the Installation Verification Procedure tests the installation."
+$ WRITE SYS$OUTPUT ""
+$ VMI$CALLBACK CREATE_DIRECTORY 'GTM$DIR_TYPE' 'GTM$DST_CRE' "/OWNER_UIC=[''GTM$DST_OWN'] /PROTECTION=(WO:RE)"
+$ VMI$CALLBACK RESTORE_SAVESET B
+$ VMI$CALLBACK RESTORE_SAVESET C
+$ WRITE SYS$OUTPUT ""
+$ VMI$CALLBACK MESSAGE I CRECOM "Creating command files."
+$! Create GTMINSTALL.COM
+$ OPEN /WRITE OUFILE VMI$KWD:GTMINSTALL.COM
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! GTMINSTALL.COM installs GTMSECSHR and other GT.M images."
+$ WRITE OUFILE "$! GTMSECSHR is a small protected image and must be installed."
+$ WRITE OUFILE "$! GTMSHR is the run-time library and is installed for performance."
+$ WRITE OUFILE "$! GTM$DMOD and MCOMPILE are small images frequently used in development."
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$ INSTALL"
+$ WRITE OUFILE "REPLACE /OPEN/SHARED/HEADER/PROTECTED GTMSECSHR"
+$ WRITE OUFILE "REPLACE /OPEN/SHARED/HEADER GTMSHR"
+$ WRITE OUFILE "REPLACE /OPEN/SHARED/HEADER GTM$DMOD"
+$ WRITE OUFILE "REPLACE /OPEN/SHARED/HEADER MCOMPILE"
+$ WRITE OUFILE "$ EXIT"
+$ CLOSE OUFILE
+$! Create GTMLOGICALS.COM
+$ GTM$HLP_LOG :== GTM$DIST
+$ IF GTM$HLP_DIR THEN GTM$HLP_LOG :== SYS$HELP
+$ OPEN /WRITE OUFILE VMI$KWD:GTMLOGICALS.COM
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! GTMLOGICALS.COM defines the logical names required to use GT.M."
+$ WRITE OUFILE "$! By default the definitions are placed in the PROCESS table."
+$ WRITE OUFILE "$! Parameter 1, if supplied should be the name of a logical name table"
+$ WRITE OUFILE "$! and/or the mode of definition."
+$ WRITE OUFILE "$! Assignments in a ""permanent"" table reduce GT.M activation time."
+$ WRITE OUFILE "$!"
+$ IF GTM$LNK_LOG THEN WRITE OUFILE "$! The LNK$LIBRARY names many require adjustment to your environment."
+$ IF GTM$DEF_GLD THEN WRITE OUFILE "$! GTM$GBLDIR is defined to provide default access to a global directory."
+$ IF GTM$DEF_RTN THEN WRITE OUFILE "$! GTM$ROUTINES is defined to provide access to the GT.M utilities."
+$ IF GTM$DEF_RTN THEN WRITE OUFILE "$! You may wish to define a different structure for $ZROUTINES."
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$ IF (P1 .NES. """") .AND. (F$EXTRACT(0,1,P1) .NES. ""/"") THEN P1 := /'P1"
+$ WRITE OUFILE "$ DEFINE 'P1' GTM$DIST ''GTM$DST_LOG'"
+$ IF GTM$DEF_GLD THEN WRITE OUFILE "$ DEFINE 'P1' GTM$GBLDIR ''GTM$GBL_DIR'"
+$ IF GTM$DEF_RTN THEN WRITE OUFILE "$ DEFINE 'P1' GTM$ROUTINES ""''GTM$RTN_DIR'"""
+$ WRITE OUFILE "$ DEFINE 'P1' GTM$HELP ''GTM$HLP_LOG'"
+$ WRITE OUFILE "$ DEFINE 'P1' GTMSHR GTM$DIST:GTMSHR.EXE"
+$ WRITE OUFILE "$ DEFINE 'P1' GTMSECSHR GTM$DIST:GTMSECSHR.EXE"
+$ WRITE OUFILE "$ DEFINE 'P1' GTM$DMOD GTM$DIST:GTM$DMOD.EXE"
+$ WRITE OUFILE "$ DEFINE 'P1' MCOMPILE GTM$DIST:MCOMPILE.EXE"
+$ IF GTM$LNK_LOG
+$ THEN
+$ N1 = 0
+$ DN = 0
+$ T1 = F$TRNLNM("LNK$LIBRARY")
+$ IF (T1 .EQS. "") .OR. (F$LOCATE("GTMLIB",T1) .NE. F$LENGTH(T1)) .OR. (F$LOCATE("GTMSHR",T1) .NE. F$LENGTH(T1))
+$ THEN
+$ WRITE OUFILE "$ DEFINE 'P1' LNK$LIBRARY GTM$DIST:GTMLIB.OLB"
+$ DN = 1
+$ ELSE ! lnk$library is in use
+$LNK_LOOP:
+$ N1 = N1 + 1
+$ T1 = F$TRNLNM("LNK$LIBRARY_''N1'")
+$ IF (T1 .EQS. "") .OR. (F$LOCATE("GTMLIB",T1) .NE. F$LENGTH(T1)) .OR. (F$LOCATE("GTMSHR",T1) .NE. F$LENGTH(T1))
+$ THEN
+$ WRITE OUFILE "$ DEFINE 'P1' LNK$LIBRARY_''N1' GTM$DIST:GTMLIB.OLB"
+$ DN = 1
+$ ENDIF
+$ IF (.NOT. DN) .AND. (N1 .LT. 998) THEN GOTO LNK_LOOP
+$ ENDIF ! gtmlib handling
+$ IF DN ! placed gtmlib
+$ THEN
+$ N1 = N1 + 1
+$ WRITE OUFILE "$ DEFINE 'P1' LNK$LIBRARY_''N1' GTM$DIST:GTMSHR.OLB"
+$ ELSE
+$ VMI$CALLBACK MESSAGE I NOLNKLOG "No LNK$LIBRARY logical names available"
+$ ENDIF
+$ ENDIF ! setting up LNK$LIBRARYs
+$ WRITE OUFILE "$ EXIT"
+$ CLOSE OUFILE
+$! Create GTMLOGIN.COM
+$ OPEN /WRITE OUFILE VMI$KWD:GTMLOGIN.COM
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! GTMLOGIN.COM performs process specific setup for GT.M."
+$ WRITE OUFILE "$! It calls GTMLOGICALS.COM if the logical names are not"
+$ WRITE OUFILE "$! in the SYSTEM table."
+$ WRITE OUFILE "$! It defines symbols to access GT.M images."
+$ WRITE OUFILE "$! It defines GT.M commands locally if they are not defined to the system."
+$ WRITE OUFILE "$! When the command and logical names are not defined on a process level,"
+$ WRITE OUFILE "$! a production user may save start-up time by not using GTMLOGIN."
+$ WRITE OUFILE "$! CCE is infrequently used, but may be defined as a foreign command."
+$ WRITE OUFILE "$!"
+$ IF .NOT. GTM$DEF_SYS
+$ THEN
+$ WRITE OUFILE "$ dir = F$ENVIRONMENT(""PROCEDURE"")"
+$ WRITE OUFILE "$ dir = F$PARSE(dir,,,""DEVICE"") + F$PARSE(dir,,,""DIRECTORY"")"
+$ WRITE OUFILE "$ @'dir'GTMLOGICALS.COM"
+$ ENDIF
+$ IF .NOT. GTM$DEF_DCL THEN WRITE OUFILE "$ SET COMMAND GTM$DIST:GTMCOMMANDS.CLD"
+$ WRITE OUFILE "$ DSE :== $GTM$DIST:DSE.EXE ! Database System Editor"
+$ WRITE OUFILE "$ GDE :== $GTM$DIST:GDE.EXE ! Global Directory Editor"
+$ WRITE OUFILE "$ GTM :== MUMPS/DIRECT ! Direct Mode MUMPS"
+$ WRITE OUFILE "$ LKE :== $GTM$DIST:LKE.EXE ! Lock Editor"
+$ WRITE OUFILE "$ MUPI*P :== $GTM$DIST:MUPIP.EXE ! MUMPS Peripheral Interchange Program"
+$ WRITE OUFILE "$ EXIT"
+$ WRITE OUFILE "$ CCE :== $GTM$DIST:CCE.EXE ! GT.CX Operator Interface Program"
+$ WRITE OUFILE "$ EXIT"
+$ CLOSE OUFILE
+$! Create GTMSTART.COM
+$ OPEN /WRITE OUFILE VMI$KWD:GTMSTART.COM
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! GTMSTART.COM should be placed in the VMS startup database."
+$ WRITE OUFILE "$! It invokes GTMLOGICALS.COM and GTMINSTALL.COM."
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$ dir = F$ENVIRONMENT(""PROCEDURE"")"
+$ WRITE OUFILE "$ dir = F$PARSE(dir,,,""DEVICE"") + F$PARSE(dir,,,""DIRECTORY"")"
+$ IF GTM$DEF_SYS THEN WRITE OUFILE "$ IF P1 .EQS. """" .OR. (P1 .EQS. ""FULL"") THEN P1 := SYSTEM/EXEC"
+$ WRITE OUFILE "$ @'dir'GTMLOGICALS 'P1'"
+$ WRITE OUFILE "$ @'dir'GTMINSTALL"
+$ WRITE OUFILE "$ EXIT"
+$ CLOSE OUFILE
+$! Create GTMSTOP.COM
+$ OPEN /WRITE OUFILE VMI$KWD:GTMSTOP.COM
+$ WRITE OUFILE "$!"
+$ WRITE OUFILE "$! GTMSTOP.COM stops all the active GT.M processes and does a RUNDOWN."
+$ WRITE OUFILE "$! Place an invocation or copy of this procedure in the site specific"
+$ WRITE OUFILE "$! shutdown: SYS$MANAGER:SYSHUTDWN to ensure all GT.M databases are"
+$ WRITE OUFILE "$! properly closed before VMS terminates. GTMSTOP should follow"
+$ WRITE OUFILE "$! GTCMSTOP and precede GTCXSTOP, if they are used."
+$ WRITE OUFILE "$! If GTMSTOP is not intended to disable subsequent use of GT.M,"
+$ WRITE OUFILE "$! add a comment (!) before the INSTALL REMOVE GTMSECSHR."
+$ WRITE OUFILE "$!"
+$ IF .NOT. GTM$DEF_SYS
+$ THEN
+$ WRITE OUFILE "$ dir = F$ENVIRONMENT(""PROCEDURE"")"
+$ WRITE OUFILE "$ dir = F$PARSE(dir,,,""DEVICE"") + F$PARSE(dir,,,""DIRECTORY"")"
+$ WRITE OUFILE "$ @'dir'GTMLOGICALS.COM"
+$ ENDIF
+$ WRITE OUFILE "$ MUPIP := $GTM$DIST:MUPIP.EXE"
+$ WRITE OUFILE "$ STOP := $GTM$DIST:GTM$STOP"
+$ WRITE OUFILE "$ STOP 'P1'"
+$ WRITE OUFILE "$ MUPIP RUNDOWN"
+$ WRITE OUFILE "$ INSTALL REMOVE GTMSECSHR"
+$ WRITE OUFILE "$ EXIT"
+$ IF GTM$DEF_SYS THEN WRITE OUFILE "$ IF P2 .EQS. """" THEN P2 := /SYSTEM/EXEC"
+$ WRITE OUFILE "$ DEASSIGN 'P2' GTMSECSHR"
+$ CLOSE OUFILE
+$ VMI$CALLBACK MESSAGE I PREINS "Preparing files for installation."
+$! GTMFILES.KIT must be maintained as kit contents change
+$ GTM$HLP_LOG == GTM$DST_LOG
+$ IF GTM$HLP_DIR THEN GTM$HLP_LOG :== VMI$ROOT:[SYSHLP]
+$ OPEN /WRITE OUFILE VMI$KWD:GTMFILES.KIT
+$ IF GTM$MGR_COM
+$ THEN
+$ WRITE OUFILE "GTM$ GTMINSTALL.COM VMI$ROOT:[SYSMGR] C"
+$ WRITE OUFILE "GTM$ GTMLOGICALS.COM VMI$ROOT:[SYSMGR] C"
+$ WRITE OUFILE "GTM$ GTMLOGIN.COM VMI$ROOT:[SYSMGR] C"
+$ WRITE OUFILE "GTM$ GTMSTART.COM VMI$ROOT:[SYSMGR] C"
+$ WRITE OUFILE "GTM$ GTMSTOP.COM VMI$ROOT:[SYSMGR] C"
+$ ENDIF
+$ WRITE OUFILE "GTM$ GTMINSTALL.COM ''GTM$DST_LOG'"
+$ WRITE OUFILE "GTM$ GTMLOGICALS.COM ''GTM$DST_LOG'"
+$ WRITE OUFILE "GTM$ GTMLOGIN.COM ''GTM$DST_LOG'"
+$ WRITE OUFILE "GTM$ GTMSTART.COM ''GTM$DST_LOG'"
+$ WRITE OUFILE "GTM$ GTMSTOP.COM ''GTM$DST_LOG'"
+$ WRITE OUFILE "GTM$ DSE.HLB ''GTM$HLP_LOG'"
+$ WRITE OUFILE "GTM$ GDE.HLB ''GTM$HLP_LOG'"
+$ WRITE OUFILE "GTM$ LKE.HLB ''GTM$HLP_LOG'"
+$ WRITE OUFILE "GTM$ MUMPS.HLB ''GTM$HLP_LOG'"
+$ WRITE OUFILE "GTM$ MUPIP.HLB ''GTM$HLP_LOG'"
+$ WRITE OUFILE "GTM$ GTMLIB.OLB ''GTM$DST_LOG'"
+$ WRITE OUFILE "GTM$ GTMSHR.OLB ''GTM$DST_LOG'"
+$ WRITE OUFILE "GTM$ GTMZCALL.MLB ''GTM$DST_LOG'"
+$ IF ALPHA
+$ THEN
+$ WRITE OUFILE "GTM$ GTM$DEFAULTS.M64 ''GTM$DST_LOG'"
+$ ELSE
+$ WRITE OUFILE "GTM$ GTM$DEFAULTS.MAR ''GTM$DST_LOG'"
+$ ENDIF
+$ WRITE OUFILE "GTM$ GTM$CE.H ''GTM$DST_LOG'"
+$ WRITE OUFILE "GTM$ GTMCOLLECT.OPT ''GTM$DST_LOG'"
+$ WRITE OUFILE "GTM$ GTMCOMMANDS.CLD ''GTM$DST_LOG' C"
+$ WRITE OUFILE "GTM$ *.M ''GTM$DST_LOG'"
+$ CLOSE OUFILE
+$! GTMIMAGES.KIT must be maintained as kit contents change
+$ OPEN /WRITE OUFILE VMI$KWD:GTMIMAGES.KIT
+$ WRITE OUFILE "GTM$ GTMSECSHR.EXE ''GTM$DST_LOG'"
+$ WRITE OUFILE "GTM$ GTMSHR.EXE ''GTM$DST_LOG'"
+$ WRITE OUFILE "GTM$ DSE.EXE ''GTM$DST_LOG'"
+$ WRITE OUFILE "GTM$ GDE.EXE ''GTM$DST_LOG'"
+$ WRITE OUFILE "GTM$ GTM$DMOD.EXE ''GTM$DST_LOG'"
+$ WRITE OUFILE "GTM$ LKE.EXE ''GTM$DST_LOG'"
+$ WRITE OUFILE "GTM$ MCOMPILE.EXE ''GTM$DST_LOG'"
+$ WRITE OUFILE "GTM$ MUPIP.EXE ''GTM$DST_LOG'"
+$ WRITE OUFILE "GTM$ GTM$STOP.EXE ''GTM$DST_LOG'"
+$ CLOSE OUFILE
+$! Provide with file.KITs
+$ VMI$CALLBACK PROVIDE_FILE "" VMI$KWD:GTMFILES.KIT "" T
+$ VMI$CALLBACK PROVIDE_IMAGE "" VMI$KWD:GTMIMAGES.KIT "" T
+$ VMI$CALLBACK MESSAGE I FININS "Finalizing the installation."
+$ IF GTM$DEF_DCL THEN VMI$CALLBACK PROVIDE_DCL_COMMAND GTMCOMMANDS.CLD
+$ IF GTM$STARTDB THEN VMI$CALLBACK MODIFY_STARTUP_DB ADD GTMSTART.COM LPMAIN
+$! GTM$INSTALL is TRUE if GTM$RUN_IVP or GTM$PCT_RTN
+$ IF GTM$INSTALL THEN VMI$CALLBACK SET POSTINSTALL YES
+$ IF GTM$RUN_IVP THEN VMI$CALLBACK SET IVP YES
+$ EXIT VMI$_SUCCESS
+$!
+$POSTINSTALL:
+$ ON CONTROL_Y THEN EXIT VMI$_FAILURE
+$! remove MUPIP from command tables for change from V2.4 to V2.5
+$ SET NOON
+$ DEFINE /USER_MODE SYS$OUTPUT NL:
+$ DEFINE /USER_MODE SYS$ERROR NL:
+$ SET COMMAND /TABLE=SYS$COMMON:[SYSLIB]DCLTABLES /OUTPUT=SYS$COMMON:[SYSLIB]DCLTABLES /DELETE=MUPIP
+$ DEFINE /USER_MODE SYS$OUTPUT NL:
+$ DEFINE /USER_MODE SYS$ERROR NL:
+$ SET COMMAND /DELETE=MUPIP
+$ SET ON
+$ IF GTM$MGR_COM
+$ THEN
+$ T1 := SYS$MANAGER:
+$ ELSE
+$ T1 = GTM$DST_LOG
+$ ENDIF
+$ @'T1'GTMSTART
+$ @'T1'GTMLOGIN
+$ ON CONTROL_Y THEN EXIT VMI$_FAILURE
+$ SET DEFAULT GTM$DIST
+$ T2 = F$ENVIRONMENT("PROTECTION")
+$ SET PROTECTION=(S=REWD,O=REWD,G=REWD,W=RE)/DEFAULT
+$ MUMPS GTM$DMOD.M
+$ IF GTM$LNK_LOG
+$ THEN
+$ T1 :=
+$ ELSE
+$ T1 :=,GTMLIB.OLB/LIB,GTMSHR.OLB/LIB
+$ ENDIF
+$ LINK GTM$DMOD.OBJ/NOTRACE'T1
+$ IF GTM$PCT_RTN
+$ THEN
+$ TYPE SYS$INPUT
+
+ Compiling the GT.M percent (%) routines.
+$ MUMPS *
+$ IF GTM$DOPURGE THEN PURGE *.*
+$ SET DEFAULT VMI$KWD
+$ ENDIF ! percent routines
+$ SET PROTECTION=('T2')/DEFAULT
+$ EXIT VMI$_SUCCESS
+$!
+$IVP:
+$! The real Installation Verification Procedure.
+$ TYPE SYS$INPUT
+
+ GT.M Installation Verification Procedure
+
+$! Extract the IVP .COM file from the text library.
+$ LIBRARIAN /EXTRACT=GTM$IVP /OUTPUT=GTM$IVP.COM GTM$IVP.TLB
+$ @GTM$IVP
+$ EXIT $STATUS
+$!
diff --git a/sr_vvms/gtmrecv.c b/sr_vvms/gtmrecv.c
new file mode 100644
index 0000000..15a9b4c
--- /dev/null
+++ b/sr_vvms/gtmrecv.c
@@ -0,0 +1,334 @@
+/****************************************************************
+ * *
+ * Copyright 2006, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_unistd.h"
+#include "gtm_fcntl.h"
+#include "gtm_inet.h"
+#ifdef UNIX
+#include "gtm_ipc.h"
+#include <sys/wait.h>
+#include "repl_instance.h"
+#elif defined(VMS)
+#include <ssdef.h>
+#include <descrip.h> /* Required for gtmrecv.h */
+#endif
+#include <errno.h>
+
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "iosp.h"
+#include "repl_shutdcode.h"
+#include "gtmrecv.h"
+#include "repl_log.h"
+#include "repl_dbg.h"
+#include "gtm_stdio.h"
+#include "gtm_string.h"
+#include "repl_errno.h"
+#include "gtm_event_log.h"
+#include "repl_sem.h"
+#include "repl_sp.h"
+#include "cli.h"
+#include "jnl.h"
+#include "repl_filter.h"
+#include "error.h"
+#include "eintr_wrappers.h"
+#include "util.h"
+#include "is_proc_alive.h"
+#include "repl_msg.h"
+#include "gtmsource.h"
+#include "gtmmsg.h"
+#include "sgtm_putmsg.h"
+#include "gt_timer.h"
+#ifdef UNIX
+#include "ftok_sems.h"
+#endif
+
+GBLDEF boolean_t gtmrecv_fetchreysnc;
+GBLDEF boolean_t gtmrecv_logstats = FALSE;
+GBLDEF int gtmrecv_filter = NO_FILTER;
+GBLDEF seq_num gtmrecv_resync_seqno;
+GBLREF void (*call_on_signal)();
+
+GBLREF uint4 process_id;
+GBLREF recvpool_addrs recvpool;
+GBLREF int recvpool_shmid;
+GBLREF gtmrecv_options_t gtmrecv_options;
+GBLREF int gtmrecv_log_fd;
+GBLREF FILE *gtmrecv_log_fp;
+GBLREF boolean_t is_rcvr_server;
+GBLREF int gtmrecv_srv_count;
+GBLREF uint4 log_interval;
+
+int gtmrecv(void)
+{
+ recvpool_ctl_ptr_t recvpool_ctl;
+ upd_proc_local_ptr_t upd_proc_local;
+ gtmrecv_local_ptr_t gtmrecv_local;
+ upd_helper_ctl_ptr_t upd_helper_ctl;
+ uint4 gtmrecv_pid, channel;
+ int semval, status, save_upd_status, upd_start_status, upd_start_attempts;
+ char print_msg[1024];
+ recvpool_user pool_user = GTMRECV;
+#ifdef UNIX
+ pid_t pid, procgp;
+ int exit_status, waitpid_res;
+ int log_init_status;
+#elif defined(VMS)
+ uint4 pid;
+ char proc_name[PROC_NAME_MAXLEN + 1];
+ $DESCRIPTOR(proc_name_desc, proc_name);
+#endif
+
+ error_def(ERR_RECVPOOLSETUP);
+ error_def(ERR_MUPCLIERR);
+ error_def(ERR_TEXT);
+ error_def(ERR_REPLERR);
+
+ call_on_signal = gtmrecv_sigstop;
+ ESTABLISH_RET(gtmrecv_ch, SS_NORMAL);
+
+#ifdef VMS
+ pool_user = (CLI_PRESENT == cli_present("DUMMY_START")) ? GTMRECV_CHILD : GTMRECV;
+#endif
+ memset((uchar_ptr_t)&recvpool, 0, SIZEOF(recvpool));
+ if (-1 == gtmrecv_get_opt())
+ rts_error(VARLSTCNT(1) ERR_MUPCLIERR);
+ recvpool_init(pool_user, gtmrecv_options.start && 0 != gtmrecv_options.listen_port, gtmrecv_options.start);
+ /*
+ * When gtmrecv_options.start is TRUE, shm field recvpool.recvpool_ctl->fresh_start is updated in recvpool_init()
+ * recvpool.recvpool_ctl->fresh_start == TRUE ==> fresh start, and
+ * recvpool.recvpool_ctl->fresh_start == FALSE ==> start after a crash
+ */
+ recvpool_ctl = recvpool.recvpool_ctl;
+ upd_proc_local = recvpool.upd_proc_local;
+ gtmrecv_local = recvpool.gtmrecv_local;
+ upd_helper_ctl = recvpool.upd_helper_ctl;
+ if (GTMRECV == pool_user)
+ {
+ if (gtmrecv_options.start)
+ {
+ if (0 == gtmrecv_options.listen_port /* implies (updateonly || helpers only) */
+ || !recvpool_ctl->fresh_start)
+ {
+ if (SRV_ALIVE == (status = is_recv_srv_alive()) && 0 != gtmrecv_options.listen_port)
+ {
+ rel_sem(RECV, RECV_SERV_OPTIONS_SEM);
+ rts_error(VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Receiver Server already exists"));
+ } else if (SRV_DEAD == status && 0 == gtmrecv_options.listen_port)
+ {
+ rel_sem(RECV, RECV_SERV_OPTIONS_SEM);
+ rts_error(VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Receiver server does not exist. Start it first"));
+ } else if (SRV_ERR == status)
+ {
+ status = errno;
+ rel_sem(RECV, RECV_SERV_OPTIONS_SEM);
+ rts_error(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Receiver server semaphore error"), status);
+ }
+ if (gtmrecv_options.updateonly)
+ {
+ status = gtmrecv_start_updonly() - UPDPROC_STARTED;
+ rel_sem(RECV, RECV_SERV_OPTIONS_SEM);
+ gtmrecv_exit(status);
+ }
+ if (gtmrecv_options.helpers && 0 == gtmrecv_options.listen_port)
+ { /* start helpers only */
+ status = gtmrecv_start_helpers(gtmrecv_options.n_readers, gtmrecv_options.n_writers);
+ rel_sem(RECV, RECV_SERV_OPTIONS_SEM);
+ gtmrecv_exit(status - NORMAL_SHUTDOWN);
+ }
+ }
+#ifndef REPL_DEBUG_NOBACKGROUND
+ if (SS_NORMAL == (status = repl_fork_rcvr_server(&pid, &channel)) && pid)
+ {
+ REPL_DPRINT2("Waiting for receiver child process %d to startup\n", pid);
+ while (0 == (semval = get_sem_info(RECV, RECV_SERV_COUNT_SEM, SEM_INFO_VAL)) &&
+ is_proc_alive(pid, 0))
+ {
+ /* To take care of reassignment of PIDs, the while condition should be && with the
+ * condition (PPID of pid == process_id)
+ */
+ REPL_DPRINT2("Waiting for receiver child process %d to startup\n", pid);
+ SHORT_SLEEP(GTMRECV_WAIT_FOR_SRV_START);
+#ifdef UNIX
+ WAITPID(pid, &exit_status, WNOHANG, waitpid_res); /* Release defunct child if dead */
+#endif
+ }
+#ifdef VMS
+ /* Deassign the cmd mailbox channel */
+ if (SS_NORMAL != (status = sys$dassgn(channel)))
+ {
+ gtm_putmsg(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Unable to close send-cmd mbox channel"), status);
+ gtmrecv_exit(ABNORMAL_SHUTDOWN);
+ }
+#endif
+ if (0 <= semval)
+ rel_sem(RECV, RECV_SERV_OPTIONS_SEM);
+ gtmrecv_exit(1 == semval ? SRV_ALIVE : SRV_DEAD);
+ } else if (SS_NORMAL != status)
+ {
+#ifdef UNIX
+ status = errno;
+#endif
+ rts_error(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Unable to fork"), status);
+ }
+#endif
+ } else if (gtmrecv_options.shut_down)
+ {
+ if (gtmrecv_options.updateonly)
+ gtmrecv_exit(gtmrecv_endupd() - NORMAL_SHUTDOWN);
+ if (gtmrecv_options.helpers)
+ gtmrecv_exit(gtmrecv_end_helpers(FALSE) - NORMAL_SHUTDOWN);
+ gtmrecv_exit(gtmrecv_shutdown(FALSE, NORMAL_SHUTDOWN) - NORMAL_SHUTDOWN);
+ } else if (gtmrecv_options.changelog)
+ {
+ gtmrecv_exit(gtmrecv_changelog() - NORMAL_SHUTDOWN);
+ } else if (gtmrecv_options.checkhealth)
+ {
+ gtmrecv_exit(gtmrecv_checkhealth() - NORMAL_SHUTDOWN);
+ } else if (gtmrecv_options.showbacklog)
+ {
+ gtmrecv_exit(gtmrecv_showbacklog() - NORMAL_SHUTDOWN);
+ } else
+ {
+ gtmrecv_exit(gtmrecv_statslog() - NORMAL_SHUTDOWN);
+ }
+ } /* (pool_user != GTMRECV) */
+ is_rcvr_server = TRUE;
+ process_id = getpid();
+ strcpy(gtmrecv_local->log_file, gtmrecv_options.log_file);
+ gtmrecv_local->log_interval = log_interval = gtmrecv_options.rcvr_log_interval;
+ upd_proc_local->log_interval = gtmrecv_options.upd_log_interval;
+ upd_helper_ctl->start_helpers = FALSE;
+ upd_helper_ctl->start_n_readers = upd_helper_ctl->start_n_writers = 0;
+#ifdef UNIX
+ log_init_status = repl_log_init(REPL_GENERAL_LOG, >mrecv_log_fd, NULL, gtmrecv_options.log_file, NULL);
+ assert(SS_NORMAL == log_init_status);
+ repl_log_fd2fp(>mrecv_log_fp, gtmrecv_log_fd);
+ if (-1 == (procgp = setsid()))
+ rts_error(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Receiver server error in setsid"), errno);
+#elif defined(VMS)
+ util_log_open(STR_AND_LEN(gtmrecv_options.log_file));
+ /* Get a meaningful process name */
+ proc_name_desc.dsc$w_length = get_proc_name(LIT_AND_LEN("GTMRCV"), process_id, proc_name);
+ if (SS$_NORMAL != (status = sys$setprn(&proc_name_desc)))
+ {
+ gtm_putmsg(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Unable to change receiver server process name"), status);
+ gtmrecv_exit(ABNORMAL_SHUTDOWN);
+ }
+#else
+#error Unsupported platform
+#endif
+ gtm_event_log_init();
+ gtmrecv_local->recv_serv_pid = process_id;
+ gtmrecv_local->listen_port = gtmrecv_options.listen_port;
+ if (recvpool_ctl->fresh_start)
+ QWASSIGNDW(recvpool_ctl->jnl_seqno, 0); /* Update process will initialize this to a non-zero value */
+ else
+ { /* Coming up after a crash, reset Update process read. This is done by setting gtmrecv_local->restart.
+ * This will trigger update process to reset recvpool_ctl->jnl_seqno too.
+ */
+ gtmrecv_local->restart = GTMRECV_RCVR_RESTARTED;
+ }
+ save_upd_status = upd_proc_local->upd_proc_shutdown;
+ for (upd_start_attempts = 0;
+ UPDPROC_START_ERR == (upd_start_status = gtmrecv_upd_proc_init(recvpool_ctl->fresh_start)) &&
+ GTMRECV_MAX_UPDSTART_ATTEMPTS > upd_start_attempts;
+ upd_start_attempts++)
+ {
+ if (EREPL_UPDSTART_SEMCTL == repl_errno || EREPL_UPDSTART_BADPATH == repl_errno)
+ {
+ gtmrecv_autoshutdown();
+ } else if (EREPL_UPDSTART_FORK == repl_errno)
+ {
+ /* Couldn't start up update now, can try later */
+ LONG_SLEEP(GTMRECV_WAIT_FOR_PROC_SLOTS);
+ continue;
+ } else if (EREPL_UPDSTART_EXEC == repl_errno)
+ {
+ /* In forked child, could not exec, should exit */
+ upd_proc_local->upd_proc_shutdown = save_upd_status;
+ gtmrecv_exit(ABNORMAL_SHUTDOWN);
+ }
+ }
+ if ((UPDPROC_EXISTS == upd_start_status && recvpool_ctl->fresh_start) ||
+ (UPDPROC_START_ERR == upd_start_status && GTMRECV_MAX_UPDSTART_ATTEMPTS <= upd_start_attempts))
+ {
+ sgtm_putmsg(print_msg, VARLSTCNT(4) ERR_REPLERR, RTS_ERROR_LITERAL((UPDPROC_EXISTS == upd_start_status) ?
+ "Runaway Update Process. Aborting..." :
+ "Too many failed attempts to fork Update Process. Aborting..."));
+ repl_log(gtmrecv_log_fp, TRUE, TRUE, print_msg);
+ gtm_event_log(GTM_EVENT_LOG_ARGC, "MUPIP", "REPLERR", print_msg);
+ gtmrecv_autoshutdown();
+ }
+ upd_proc_local->start_upd = UPDPROC_STARTED;
+ if (!recvpool_ctl->fresh_start)
+ {
+ while ((GTMRECV_RCVR_RESTARTED == gtmrecv_local->restart) && (SRV_ALIVE == is_updproc_alive()))
+ {
+ REPL_DPRINT1("Rcvr waiting for update to restart\n");
+ SHORT_SLEEP(GTMRECV_WAIT_FOR_SRV_START);
+ }
+ upd_proc_local->bad_trans = FALSE;
+ recvpool_ctl->write_wrap = recvpool_ctl->recvpool_size;
+ recvpool_ctl->write = 0;
+ recvpool_ctl->wrapped = FALSE;
+ upd_proc_local->changelog = TRUE;
+ gtmrecv_local->restart = GTMRECV_NO_RESTART; /* release the update process wait */
+ }
+ if (gtmrecv_options.helpers)
+ gtmrecv_helpers_init(gtmrecv_options.n_readers, gtmrecv_options.n_writers);
+#ifdef UNIX
+ /*
+ * Child needs to increment receivpool lock couner semaphore.
+ * Since we can have ftok collisions with someone else, we cannot gaurantee that current count is one.
+ * So just increment semaphore number 1 after grabbing semaphore number 0. Then release semaphore 0.
+ */
+ if (!ftok_sem_get(recvpool.recvpool_dummy_reg, TRUE, REPLPOOL_ID, FALSE))
+ rts_error(VARLSTCNT(1) ERR_RECVPOOLSETUP);
+ if (!ftok_sem_release(recvpool.recvpool_dummy_reg, FALSE, FALSE))
+ rts_error(VARLSTCNT(1) ERR_RECVPOOLSETUP);
+#endif
+ /* Lock the receiver server count semaphore. Its value should be atmost 1. */
+ if (0 > grab_sem_immediate(RECV, RECV_SERV_COUNT_SEM))
+ rts_error(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("Receive pool semop failure"),
+ REPL_SEM_ERRNO);
+#ifdef REPL_DEBUG_NOBACKGROUND
+ rel_sem(RECV, RECV_SERV_OPTIONS_SEM);
+#endif
+ gtmrecv_srv_count++;
+ gtmrecv_filter = NO_FILTER;
+ if ('\0' != gtmrecv_local->filter_cmd[0])
+ {
+ if (SS_NORMAL == (status = repl_filter_init(gtmrecv_local->filter_cmd)))
+ gtmrecv_filter |= EXTERNAL_FILTER;
+ else
+ {
+ if (EREPL_FILTERSTART_EXEC == repl_errno)
+ gtmrecv_exit(ABNORMAL_SHUTDOWN);
+ }
+ }
+ gtmrecv_process(!recvpool_ctl->fresh_start);
+ return (SS_NORMAL);
+}
diff --git a/sr_vvms/gtmrecv.h b/sr_vvms/gtmrecv.h
new file mode 100644
index 0000000..e77315c
--- /dev/null
+++ b/sr_vvms/gtmrecv.h
@@ -0,0 +1,330 @@
+/****************************************************************
+ * *
+ * Copyright 2006, 2013 Fidelity Information Services, Inc.*
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef GTMRECV_H
+#define GTMRECV_H
+
+/* Needs mdef.h, gdsfhead.h and its dependencies, and iosp.h */
+
+#define DEFAULT_RECVPOOL_SIZE (64 * 1024 * 1024) /* bytes */
+#define DEFAULT_SHUTDOWN_TIMEOUT 30 /* seconds */
+#define MAX_FILTER_CMD_LEN 512 /* characters */
+#define UPD_HELPERS_DELIM ','
+#define MAX_UPD_HELPERS 128 /* Max helper process (incl. readers and writers) one instance can support */
+#define MIN_UPD_HELPERS 1 /* Minimum number of helper processes, one for reading or writing */
+
+#define DEFAULT_UPD_HELPERS 8 /* If value for -HELPERS is not specified, start these many helpers. Change
+ * DEFAULT_UPD_HELPERS_STR if you change DEFAULT_UPD_HELPERS */
+#define DEFAULT_UPD_HELP_READERS 5 /* If -HELPERS is not specified, or specified as -HELPERS=,n start these many
+ * readers. Change DEFAULT_UPD_HELPERS_STR if you change DEFAULT_UPD_HELP_READERS */
+#define DEFAULT_UPD_HELPERS_STR "8,5" /* Built as "DEFAULT_UPD_HELPERS,DEFAULT_UPD_HELP_READERS". Maintain DEFAULT for
+ * /helpers in vvms:mupip_cmd.cld in sync with DEFAULT_UPD_HELPERS_STR */
+
+#ifdef VMS
+#define MAX_GSEC_KEY_LEN 32 /* 31 is allowed + 1 for NULL terminator */
+#endif
+
+typedef enum
+{
+ GTMRECV_DUMMY_STATE = 0,
+ GTMRECV_START,
+ GTMRECV_WAITING_FOR_CONNECTION,
+ GTMRECV_RECEIVING_MSGS,
+ GTMRECV_WAITING_FOR_UPD_CRASH_RESTART,
+ GTMRECV_WAITING_FOR_UPD_SHUT_RESTART
+} gtmrecv_state_t;
+
+enum
+{
+ UPDPROC_STARTED,
+ UPDPROC_START,
+ UPDPROC_EXISTS,
+ UPDPROC_START_ERR
+};
+
+enum
+{
+ GTMRECV_NO_RESTART,
+ GTMRECV_RCVR_RESTARTED,
+ GTMRECV_UPD_RESTARTED
+};
+
+enum
+{
+ HELPER_REAP_NONE = 0,
+ HELPER_REAP_NOWAIT,
+ HELPER_REAP_WAIT
+};
+
+#define GTMRECV_WAIT_FOR_PROC_SLOTS 1 /* s */
+#define GTMRECV_WAIT_FOR_UPDSTART (1000 - 1) /* ms */
+#define GTMRECV_WAIT_FOR_UPD_SHUTDOWN 10 /* ms */
+#define GTMRECV_MAX_UPDSTART_ATTEMPTS 16
+#define GTMRECV_WAIT_FOR_RECVSTART (1000 - 1) /* ms */
+#define GTMRECV_WAIT_FOR_SRV_START 10 /* ms */
+#define GTMRECV_REAP_HELPERS_INTERVAL 300 /* s */
+
+
+#define SRV_ALIVE 0x0
+#define SRV_DEAD 0x1
+#define SRV_ERR 0x2
+
+/* The exit status of checkhealth is BIT-OR of the Receiver status and the
+ * Update status */
+#define RECEIVER_SRV_ALIVE 0x00
+#define RECEIVER_SRV_DEAD 0x01
+#define RECEIVER_CHECKHEALTH_ERR 0x02
+#define UPDATE_PROC_ALIVE 0x00
+#define UPDATE_PROC_DEAD 0x04
+#define UPDATE_CHECKHEALTH_ERR 0x08
+#define RECVPOOL_SEGMENT 'R'
+#define MIN_RECVPOOL_SIZE (1024 * 1024)
+
+#define GTMRECV_MIN_TCP_SEND_BUFSIZE (512) /* anything less than this, issue a warning */
+#define GTMRECV_TCP_SEND_BUFSIZE (1024) /* not much outbound traffic, we can live with a low limit */
+#define GTMRECV_MIN_TCP_RECV_BUFSIZE (16 * 1024) /* anything less than this, issue a warning */
+#define GTMRECV_TCP_RECV_BUFSIZE_INCR (32 * 1024) /* attempt to get a larger buffer with this increment */
+#define GTMRECV_TCP_RECV_BUFSIZE (1024 * 1024) /* desirable to set the buffer size to be able to receive large chunks */
+
+/* Note: fields shared between the receiver and update processes
+ really need to have memory barriers or other appropriate
+ synchronization constructs to ensure changes by one
+ process are actually seen by the other process. Cache
+ line spacing should also be taken into account.
+ Adding volatile is only a start at this.
+*/
+
+typedef struct
+{
+ replpool_identifier recvpool_id; /* Shared memory identification */
+ volatile seq_num start_jnl_seqno;/* The sequence number with which operations started. Initialized by recvr srvr */
+ volatile seq_num jnl_seqno; /* Sequence number of the next transaction expected to be received from source
+ * server. Updated by Receiver Server */
+ seq_num old_jnl_seqno; /* Stores the value of jnl_seqno before it is set to 0 when upd crash/shut */
+ boolean_t std_null_coll; /* Null collation setting for secondary, set by update process, used by recv srvr */
+ uint4 recvdata_base_off; /* Receive pool offset from where journal data starts */
+ uint4 recvpool_size; /* Available space for journal data in bytes */
+ volatile uint4 write; /* Relative offset from recvdata_base_off for for the next journal record to be
+ * written. Updated by Receiver Server */
+ volatile uint4 write_wrap; /* Relative offset from recvdata_base_off where write was wrapped by recvr srvr */
+ volatile uint4 wrapped; /* Boolean, set by Receiver Server when it wraps. Reset by Update Process when it
+ * wraps. Used for detecting space used in the receive pool */
+ uint4 initialized; /* Boolean, has receive pool been initialized? */
+ uint4 fresh_start; /* Boolean, fresh_start or crash_start? */
+} recvpool_ctl_struct;
+
+/*
+ * The following structure contains Update Process related data items.
+ * Maintaining this structure in the Receive pool provides for
+ * persistence across instantiations of the Update Process (across crashes,
+ * the receive pool is preserved)
+ */
+
+typedef struct
+{
+ uint4 upd_proc_pid; /* Process identification of update server */
+ uint4 upd_proc_pid_prev; /* Save for reporting old pid if we fail */
+ volatile seq_num read_jnl_seqno; /* Next jnl_seqno to be read; keep aligned at 8 byte boundary for performance */
+ volatile uint4 read; /* Relative offset from recvdata_base_off of the next journal record to be
+ * read from the receive pool */
+ volatile uint4 upd_proc_shutdown; /* Used to communicate shutdown related values between Receiver and Update */
+ volatile int4 upd_proc_shutdown_time; /* Time allowed for update process to shut down */
+ volatile uint4 bad_trans; /* Boolean, set by Update Process that it received a bad transaction record */
+ volatile uint4 changelog; /* Boolean - change the log file */
+ int4 start_upd; /* Used to communicate upd only startup values */
+ boolean_t updateresync; /* Same as gtmrecv_options update resync */
+ volatile uint4 log_interval; /* Interval (in seqnos) at which update process logs its progress */
+ char log_file[MAX_FN_LEN + 1];
+} upd_proc_local_struct;
+
+/*
+ * The following structure contains data items local to the Receiver Server,
+ * but are in the Receive Pool to provide for persistence across instantiations
+ * of the Receiver Server (across Receiver Server crashes, the Receive
+ * Pool is preserved).
+ */
+typedef struct
+{
+ uint4 recv_serv_pid; /* Process identification of receiver server */
+ int4 lastrecvd_time; /* unused */
+ /* Data items used in communicating action qualifiers (show statistics, shutdown) and
+ * qualifier values (log file, shutdown time, etc). */
+ volatile uint4 statslog; /* Boolean - detailed log on/off? */
+ volatile uint4 shutdown; /* Used to communicate shutdown related values between process initiating shutdown
+ * and Receiver Server */
+ int4 shutdown_time; /* Time allowed for shutdown in seconds */
+ int4 listen_port; /* Port at which the Receiver Server is listening */
+ volatile uint4 restart; /* Used by receiver server to coordinate crash restart with update process */
+ volatile uint4 changelog; /* Boolean - change the log file */
+ volatile uint4 log_interval; /* Interval (in seqnos) at which receiver logs its progress */
+ char filter_cmd[MAX_FILTER_CMD_LEN]; /* Receiver filters incoming records using this process */
+ char log_file[MAX_FN_LEN + 1]; /* File to log receiver progress */
+ char statslog_file[MAX_FN_LEN + 1]; /* File to log statistics */
+} gtmrecv_local_struct;
+
+#ifdef VMS
+typedef struct
+{
+ char name[MAX_GSEC_KEY_LEN];
+ struct dsc$descriptor_s desc;
+ char filler[3];
+} vms_shm_key;
+#endif
+
+/*
+ * The following structure contains data items local to the Update Helpers,
+ * but are in the Receive Pool to provide for persistence across instantiations
+ * of the Helpers (the Receive Pool is preserved across helper crashes).
+ */
+
+typedef struct
+{
+ uint4 helper_pid; /* Owner of this entry. Non-zero indicates entry occupied */
+ uint4 helper_pid_prev;/* Copy of helper_pid, used to recognize helpers that are now gone and salvage entries */
+ uint4 helper_type; /* READER or WRITER */
+ volatile uint4 helper_shutdown;/* used to communicate to the helpers to shut down */
+} upd_helper_entry_struct;
+
+typedef struct
+{
+ global_latch_t pre_read_lock; /* operated by pre-readers. Used to control access to next_read_offset */
+ volatile uint4 pre_read_offset; /* updated by updproc, read-only by pre-readers */
+ volatile boolean_t first_done; /* pre-readers use this to elect ONE that computes where to begin/resume */
+ volatile uint4 next_read_offset; /* offset in recvpool of the next record to be pre-read by pre-readers */
+ uint4 start_helpers; /* TRUE: receiver to start helpers, FALSE: receiver finished helper start */
+ uint4 start_n_readers; /* start/started these many readers */
+ uint4 start_n_writers; /* start/started these many writers */
+ uint4 reap_helpers; /* receiver to salvage slots vacated by dead helpers */
+ upd_helper_entry_struct helper_list[MAX_UPD_HELPERS]; /* helper information */
+} upd_helper_ctl_struct;
+
+/*
+ * Receive pool shared memory layout -
+ *
+ * recvpool_ctl_struct
+ * upd_proc_local_struct
+ * gtmrecv_local_struct
+ * upd_helper_ctl_struct
+ * zero or more journal records
+ */
+
+#define RECVPOOL_CTL_SIZE ROUND_UP(SIZEOF(recvpool_ctl_struct), CACHELINE_SIZE)
+#define UPD_PROC_LOCAL_SIZE ROUND_UP(SIZEOF(upd_proc_local_struct), CACHELINE_SIZE)
+#define GTMRECV_LOCAL_SIZE ROUND_UP(SIZEOF(gtmrecv_local_struct), CACHELINE_SIZE)
+#define UPD_HELPER_CTL_SIZE ROUND_UP(SIZEOF(upd_helper_ctl_struct), CACHELINE_SIZE)
+
+#define RECVDATA_BASE_OFF ROUND_UP(RECVPOOL_CTL_SIZE + UPD_HELPER_CTL_SIZE + GTMRECV_LOCAL_SIZE + UPD_HELPER_CTL_SIZE, \
+ JNL_REC_START_BNDRY)
+
+#if defined(__osf__) && defined(__alpha)
+# pragma pointer_size(save)
+# pragma pointer_size(long)
+#endif
+
+typedef recvpool_ctl_struct *recvpool_ctl_ptr_t;
+typedef upd_proc_local_struct *upd_proc_local_ptr_t;
+typedef gtmrecv_local_struct *gtmrecv_local_ptr_t;
+typedef upd_helper_entry_struct *upd_helper_entry_ptr_t;
+typedef upd_helper_ctl_struct *upd_helper_ctl_ptr_t;
+
+#if defined(__osf__) && defined(__alpha)
+# pragma pointer_size(restore)
+#endif
+
+typedef struct
+{
+ recvpool_ctl_ptr_t recvpool_ctl;
+ upd_proc_local_ptr_t upd_proc_local;
+ gtmrecv_local_ptr_t gtmrecv_local;
+ upd_helper_ctl_ptr_t upd_helper_ctl;
+ sm_uc_ptr_t recvdata_base;
+#ifdef UNIX
+ gd_region *recvpool_dummy_reg;
+#elif VMS
+ int4 shm_range[2];
+ int4 shm_lockid;
+ vms_shm_key vms_recvpool_key;
+#endif
+} recvpool_addrs;
+
+typedef enum
+{
+ UPDPROC,
+ UPD_HELPER_READER,
+ UPD_HELPER_WRITER,
+ GTMRECV
+#ifdef VMS
+ , GTMRECV_CHILD
+#endif
+} recvpool_user;
+
+typedef struct
+{
+ boolean_t start;
+ boolean_t shut_down;
+ boolean_t checkhealth;
+ boolean_t statslog;
+ boolean_t showbacklog;
+ boolean_t updateonly;
+ boolean_t stopsourcefilter;
+ boolean_t changelog;
+ int4 buffsize;
+ int4 shutdown_time;
+ int4 listen_port;
+ boolean_t updateresync;
+ uint4 rcvr_log_interval;
+ uint4 upd_log_interval;
+ boolean_t helpers;
+ int4 n_readers;
+ int4 n_writers;
+ char log_file[MAX_FN_LEN + 1];
+ char filter_cmd[MAX_FILTER_CMD_LEN];
+} gtmrecv_options_t;
+
+#include "gtm_inet.h"
+
+/********** Receiver server function prototypes **********/
+int gtmrecv(void);
+int gtmrecv_changelog(void);
+int gtmrecv_checkhealth(void);
+int gtmrecv_comm_init(in_port_t port);
+int gtmrecv_end1(boolean_t auto_shutdown);
+int gtmrecv_endupd(void);
+void gtmrecv_end(void);
+int gtmrecv_get_opt(void);
+int gtmrecv_poll_actions1(int *pending_data_len, int *buff_unprocessed, unsigned char *buffp);
+int gtmrecv_poll_actions(int pending_data_len, int buff_unprocessed, unsigned char *buffp);
+void gtmrecv_process(boolean_t crash_restart);
+int gtmrecv_showbacklog(void);
+int gtmrecv_shutdown(boolean_t auto_shutdown, int exit_status);
+void gtmrecv_sigstop(void);
+void gtmrecv_autoshutdown(void);
+int gtmrecv_statslog(void);
+int gtmrecv_ipc_cleanup(boolean_t auto_shutdown, int *exit_status);
+int gtmrecv_start_updonly(void);
+int gtmrecv_upd_proc_init(boolean_t fresh_start);
+int gtmrecv_wait_for_detach(void);
+void gtmrecv_exit(int exit_status);
+int gtmrecv_alloc_msgbuff(void);
+void gtmrecv_free_msgbuff(void);
+int gtmrecv_alloc_filter_buff(int bufsiz);
+void gtmrecv_free_filter_buff(void);
+int is_updproc_alive(void);
+int is_srv_alive(int srv_type);
+int is_recv_srv_alive(void);
+void recvpool_init(recvpool_user pool_user, boolean_t gtmrecv_startup, boolean_t lock_opt_sem);
+void gtmrecv_reinit_logseqno(void);
+int gtmrecv_helpers_init(int n_readers, int n_writers);
+int gtmrecv_start_helpers(int n_readers, int n_writers);
+void gtmrecv_reap_helpers(boolean_t wait);
+int gtmrecv_end_helpers(boolean_t is_rcvr_srvr);
+
+#endif
diff --git a/sr_vvms/gtmrecv_end.c b/sr_vvms/gtmrecv_end.c
new file mode 100644
index 0000000..d943386
--- /dev/null
+++ b/sr_vvms/gtmrecv_end.c
@@ -0,0 +1,167 @@
+/****************************************************************
+ * *
+ * Copyright 2006, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_unistd.h" /* for close() */
+#include "gtm_string.h"
+
+#ifdef UNIX
+#include "gtm_ipc.h"
+#include <sys/shm.h>
+#include <sys/sem.h>
+#include <sys/wait.h>
+#elif defined(VMS)
+#include <ssdef.h>
+#include <psldef.h>
+#include <descrip.h> /* Required for gtmrecv.h */
+#else
+#error Unsupported platform
+#endif
+#include <errno.h>
+#include "gtm_inet.h"
+
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "iosp.h"
+#include "repl_shutdcode.h"
+#include "gtmrecv.h"
+#include "repl_dbg.h"
+#include "gtm_stdio.h"
+#include "gtm_event_log.h"
+#include "eintr_wrappers.h"
+#include "jnl.h"
+#include "repl_filter.h"
+#include "repl_msg.h"
+#include "repl_sem.h"
+#ifdef VMS
+#include "repl_shm.h"
+#endif
+#include "repl_log.h"
+#include "is_proc_alive.h"
+
+GBLREF uint4 process_id;
+GBLREF recvpool_addrs recvpool;
+GBLREF int gtmrecv_filter;
+GBLREF boolean_t gtmrecv_logstats;
+GBLREF int gtmrecv_listen_sock_fd;
+GBLREF int gtmrecv_sock_fd;
+GBLREF int gtmrecv_log_fd;
+GBLREF FILE *gtmrecv_log_fp;
+GBLREF qw_num repl_recv_data_recvd;
+GBLREF qw_num repl_recv_data_processed;
+GBLREF repl_msg_ptr_t gtmrecv_msgp;
+GBLREF uchar_ptr_t repl_filter_buff;
+
+int gtmrecv_endupd(void)
+{
+ VMS_ONLY(uint4 savepid;) UNIX_ONLY(pid_t savepid;)
+ int exit_status;
+ UNIX_ONLY(pid_t waitpid_res;)
+
+ repl_log(stdout, TRUE, TRUE, "Initiating shut down of Update Process\n");
+ recvpool.upd_proc_local->upd_proc_shutdown = SHUTDOWN;
+ /* Wait for update process to shut down */
+ while(recvpool.upd_proc_local->upd_proc_shutdown == SHUTDOWN &&
+ (savepid = UNIX_ONLY((pid_t))recvpool.upd_proc_local->upd_proc_pid) > 0 &&
+ is_proc_alive(savepid, 0))
+ {
+ SHORT_SLEEP(GTMRECV_WAIT_FOR_UPD_SHUTDOWN);
+ UNIX_ONLY(WAITPID(savepid, &exit_status, WNOHANG, waitpid_res);) /* Release defunct update process if dead */
+ }
+ exit_status = recvpool.upd_proc_local->upd_proc_shutdown;
+ if (SHUTDOWN == exit_status)
+ {
+ if (0 == savepid) /* No Update Process */
+ exit_status = NORMAL_SHUTDOWN;
+ else /* Update Process Crashed */
+ {
+ repl_log(stderr, TRUE, TRUE, "Update Process exited abnormally, INTEGRITY CHECK might be warranted\n");
+ exit_status = ABNORMAL_SHUTDOWN;
+ }
+ }
+ /* Wait for the Update Process to detach */
+ if (0 == grab_sem(RECV, UPD_PROC_COUNT_SEM))
+ {
+ if(0 != (errno = rel_sem(RECV, UPD_PROC_COUNT_SEM)))
+ repl_log(stderr, TRUE, TRUE, "Error releasing the Update Process Count semaphore : %s\n", REPL_SEM_ERROR);
+ repl_log(stdout, TRUE, TRUE, "Update Process exited\n");
+ } else
+ {
+ repl_log(stderr, TRUE, TRUE, "Error in update proc count semaphore : %s\n", REPL_SEM_ERROR);
+ exit_status = ABNORMAL_SHUTDOWN;
+ }
+ return (exit_status);
+}
+
+int gtmrecv_end1(boolean_t auto_shutdown)
+{
+ uint4 savepid;
+ int exit_status;
+ seq_num log_seqno, log_seqno1;
+ int fclose_res;
+#ifdef VMS
+ int4 status;
+#endif
+
+ exit_status = gtmrecv_end_helpers(TRUE);
+ exit_status = gtmrecv_endupd();
+ QWASSIGN(log_seqno, recvpool.recvpool_ctl->jnl_seqno);
+ QWASSIGN(log_seqno1, recvpool.upd_proc_local->read_jnl_seqno);
+ /* Detach from receive pool */
+ recvpool.gtmrecv_local->shutdown = exit_status;
+ recvpool.gtmrecv_local->recv_serv_pid = 0;
+ UNIX_ONLY(
+ if (recvpool.recvpool_ctl && 0 > SHMDT(recvpool.recvpool_ctl))
+ repl_log(stderr, TRUE, TRUE, "Error detaching from Receive Pool : %s\n", REPL_STR_ERROR);
+ )
+ VMS_ONLY(
+ if (recvpool.recvpool_ctl)
+ {
+ if (SS$_NORMAL != (status = detach_shm(recvpool.shm_range)))
+ repl_log(stderr, TRUE, TRUE, "Error detaching from recvpool : %s\n", REPL_STR_ERROR);
+ recvpool.recvpool_ctl = NULL;
+ if (!auto_shutdown && (SS$_NORMAL != (status = signoff_from_gsec(recvpool.shm_lockid))))
+ repl_log(stderr, TRUE, TRUE, "Error dequeueing lock on recvpool global section : %s\n",
+ REPL_STR_ERROR);
+ }
+ )
+ gtmrecv_free_msgbuff();
+ gtmrecv_free_filter_buff();
+ recvpool.recvpool_ctl = NULL;
+ /* Close the connection with the Receiver */
+ if (FD_INVALID != gtmrecv_listen_sock_fd)
+ close(gtmrecv_listen_sock_fd);
+ if (FD_INVALID != gtmrecv_sock_fd)
+ close(gtmrecv_sock_fd);
+ QWDECRBYDW(log_seqno, 1);
+ QWDECRBYDW(log_seqno1, 1);
+ repl_log(gtmrecv_log_fp, TRUE, TRUE, "REPL INFO - Last Recvd Seqno : %llu Jnl Total : %llu Msg Total : %llu\n",
+ log_seqno, repl_recv_data_processed, repl_recv_data_recvd);
+ repl_log(gtmrecv_log_fp, TRUE, TRUE, "REPL INFO - Last Seqno processed by update process : %llu\n", log_seqno1);
+ gtm_event_log_close();
+ if (gtmrecv_filter & EXTERNAL_FILTER)
+ repl_stop_filter();
+ if (auto_shutdown)
+ return (exit_status);
+ else
+ gtmrecv_exit(exit_status - NORMAL_SHUTDOWN);
+}
+
+void gtmrecv_end(void)
+{
+ gtmrecv_end1(FALSE);
+}
diff --git a/sr_vvms/gtmrecv_fetchresync.c b/sr_vvms/gtmrecv_fetchresync.c
new file mode 100644
index 0000000..a176df5
--- /dev/null
+++ b/sr_vvms/gtmrecv_fetchresync.c
@@ -0,0 +1,290 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc.*
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_stdio.h"
+#include "gtm_socket.h"
+#include "gtm_netdb.h"
+#include "gtm_inet.h"
+#include "gtm_time.h" /* needed for difftime() definition */
+#include "gtm_fcntl.h"
+#include "gtm_unistd.h"
+#include "gtm_string.h"
+#include <errno.h>
+#include <descrip.h> /* Required for gtmsource.h */
+
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "jnl.h"
+#include "buddy_list.h"
+#include "hashtab_mname.h" /* needed for muprec.h */
+#include "hashtab_int4.h" /* needed for muprec.h */
+#include "hashtab_int8.h" /* needed for muprec.h */
+#include "muprec.h"
+#include "error.h"
+#include "iosp.h"
+#include "gtmrecv.h"
+#include "repl_comm.h"
+#include "repl_msg.h"
+#include "repl_errno.h"
+#include "repl_dbg.h"
+#include "gtm_logicals.h"
+#include "eintr_wrappers.h"
+#include "repl_sem.h"
+#include "repl_sp.h"
+#include "repl_log.h"
+#include "io.h"
+#include "is_file_identical.h"
+#include "trans_log_name.h"
+
+#define MAX_ATTEMPTS_FOR_FETCH_RESYNC 60 /* max-wait in seconds for source server response after connection is established */
+#define MAX_WAIT_FOR_FETCHRESYNC_CONN 60 /* max-wait in seconds to establish connection with the source server */
+#define FETCHRESYNC_PRIMARY_POLL (MICROSEC_IN_SEC - 1) /* micro seconds, almost 1 second */
+#define GRAB_SEM_ERR_OUT rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0,\
+ ERR_TEXT, 2,\
+ LEN_AND_LIT("Error with receive pool semaphores. Receiver Server possibly exists"))
+
+GBLREF uint4 process_id;
+GBLREF int gtmrecv_listen_sock_fd, gtmrecv_sock_fd;
+GBLREF struct addrinfo primary_ai;
+GBLREF struct sockaddr_storage primary_sas;
+GBLREF seq_num seq_num_zero;
+GBLREF jnl_gbls_t jgbl;
+GBLREF int repl_max_send_buffsize, repl_max_recv_buffsize;
+
+error_def(ERR_RECVPOOLSETUP);
+error_def(ERR_REPLCOMM);
+error_def(ERR_TEXT);
+
+CONDITION_HANDLER(gtmrecv_fetchresync_ch)
+{
+ START_CH;
+ /* Remove semaphores created */
+ remove_sem_set(RECV);
+ repl_close(>mrecv_listen_sock_fd);
+ repl_close(>mrecv_sock_fd);
+ PRN_ERROR;
+ NEXTCH;
+}
+
+int gtmrecv_fetchresync(int port, seq_num *resync_seqno)
+{
+ mstr log_nam, trans_log_nam;
+ char trans_buff[MAX_FN_LEN+1];
+ key_t recvpool_key;
+ repl_msg_t msg;
+ unsigned char *msg_ptr; /* needed for REPL_{SEND,RECV}_LOOP */
+ int tosend_len, sent_len, sent_this_iter; /* needed for REPL_SEND_LOOP */
+ int torecv_len, recvd_len, recvd_this_iter; /* needed for REPL_RECV_LOOP */
+ int status; /* needed for REPL_{SEND,RECV}_LOOP */
+ fd_set input_fds;
+ int wait_count;
+ char seq_num_str[32], *seq_num_ptr, err_string[1024];
+ pid_t rollback_pid;
+ int rollback_status;
+ int wait_status;
+ gd_id file_id;
+ struct dsc$descriptor_s name_dsc;
+ char res_name[MAX_NAME_LEN + 2]; /* +1 for the terminator and another +1 for the length stored in [0]
+ by global_name() */
+ mstr res_name_str;
+ time_t t1, t2;
+ struct timeval gtmrecv_fetchresync_max_wait;
+
+ recvpool_key = -1;
+ ESTABLISH(gtmrecv_fetchresync_ch);
+ QWASSIGN(*resync_seqno, seq_num_zero);
+ /* Verify that a receiver server is not already running */
+ log_nam.addr = GTM_GBLDIR;
+ log_nam.len = SIZEOF(GTM_GBLDIR) - 1;
+ if (trans_log_name(&log_nam, &trans_log_nam, trans_buff) != SS_NORMAL)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ LEN_AND_LIT("gtmgbldir not defined"));
+ trans_buff[trans_log_nam.len] = '\0';
+ gtmrecv_fetchresync_max_wait.tv_sec = MAX_WAIT_FOR_FETCHRESYNC_CONN;
+ gtmrecv_fetchresync_max_wait.tv_usec = 0;
+ /* Get Recv. Pool Resource Name : name_dsc holds the resource name */
+ set_gdid_from_file((gd_id_ptr_t)&file_id, trans_buff, trans_log_nam.len);
+ global_name("GT$R", &file_id, res_name); /* R - Stands for Receiver Pool */
+ name_dsc.dsc$a_pointer = &res_name[1];
+ name_dsc.dsc$w_length = res_name[0];
+ name_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
+ name_dsc.dsc$b_class = DSC$K_CLASS_S;
+ name_dsc.dsc$a_pointer[name_dsc.dsc$w_length] = '\0';
+ if (0 != init_sem_set_recvr(&name_dsc))
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_RECVPOOLSETUP, 0,
+ ERR_TEXT, 2, LEN_AND_LIT("Error with receiver pool sem init."), REPL_SEM_ERRNO);
+ /* Lock all access to receive pool */
+ status = grab_sem_immediate(RECV, RECV_POOL_ACCESS_SEM);
+ if (0 == status)
+ status = grab_sem_immediate(RECV, RECV_SERV_COUNT_SEM);
+ else
+ GRAB_SEM_ERR_OUT;
+ if (0 == status)
+ status = grab_sem_immediate(RECV, UPD_PROC_COUNT_SEM);
+ else
+ {
+ rel_sem(RECV, RECV_POOL_ACCESS_SEM);
+ GRAB_SEM_ERR_OUT;
+ }
+ if (0 == status)
+ status = grab_sem_immediate(RECV, RECV_SERV_OPTIONS_SEM);
+ else
+ {
+ rel_sem(RECV, RECV_POOL_ACCESS_SEM);
+ rel_sem(RECV, RECV_SERV_COUNT_SEM);
+ GRAB_SEM_ERR_OUT;
+ }
+ if (0 != status)
+ {
+ rel_sem(RECV, RECV_POOL_ACCESS_SEM);
+ rel_sem(RECV, RECV_SERV_COUNT_SEM);
+ rel_sem(RECV, UPD_PROC_COUNT_SEM);
+ GRAB_SEM_ERR_OUT;
+ }
+ /* Global section shouldn't already exist */
+ if (shm_exists(RECV, &name_dsc))
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_RECVPOOLSETUP, 0,
+ ERR_TEXT, 2, LEN_AND_LIT("Receive pool exists. Receiver Server possibly exists already!"));
+ gtmrecv_comm_init(port);
+ primary_ai.ai_addr = (sockaddr_ptr)&primary_sas;
+ primary_ai.ai_addrlen = SIZEOF(primary_sas);
+ repl_log(stdout, TRUE, TRUE, "Waiting for a connection...\n");
+ FD_ZERO(&input_fds);
+ FD_SET(gtmrecv_listen_sock_fd, &input_fds);
+ t1 = time(NULL);
+ while ((status = select(gtmrecv_listen_sock_fd + 1, &input_fds, NULL, NULL, >mrecv_fetchresync_max_wait)) < 0)
+ {
+ if (errno == EINTR || errno == EAGAIN)
+ {
+ t2 = time(NULL);
+ if (0 >= (int)(gtmrecv_fetchresync_max_wait.tv_sec =
+ (MAX_WAIT_FOR_FETCHRESYNC_CONN - (int)difftime(t2, t1))))
+ {
+ status = 0;
+ break;
+ }
+ gtmrecv_fetchresync_max_wait.tv_usec = 0;
+ FD_SET(gtmrecv_listen_sock_fd, &input_fds);
+ continue;
+ } else
+ {
+ status = ERRNO;
+ SNPRINTF(err_string, SIZEOF(err_string), "Error in select on listen socket : %s", STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(err_string));
+ }
+ }
+ if (status == 0)
+ {
+ repl_log(stdout, TRUE, TRUE, "Waited about %d seconds for connection from primary source server\n",
+ MAX_WAIT_FOR_FETCHRESYNC_CONN);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_LIT("Waited too long to get a connection request. Check if primary is alive."));
+ }
+
+ ACCEPT_SOCKET(gtmrecv_listen_sock_fd, primary_ai.ai_addr, (sssize_t *)&primary_ai.ai_addrlen, gtmrecv_sock_fd);
+ if (gtmrecv_sock_fd < 0)
+ {
+ status = ERRNO;
+ SNPRINTF(err_string, SIZEOF(err_string), "Error accepting connection from Source Server : %s", STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(err_string));
+ }
+ repl_log(stdout, TRUE, TRUE, "Connection established\n");
+ repl_close(>mrecv_listen_sock_fd);
+ if (0 != (status = get_send_sock_buff_size(gtmrecv_sock_fd, &repl_max_send_buffsize))
+ || 0 != (status = get_recv_sock_buff_size(gtmrecv_sock_fd, &repl_max_recv_buffsize)))
+ {
+ SNPRINTF(err_string, SIZEOF(err_string), "Error getting socket send/recv bufsizes : %s", STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(err_string));
+ return ERR_REPLCOMM;
+ }
+ msg.type = REPL_FETCH_RESYNC;
+ memset(&msg.msg[0], 0, MIN_REPL_MSGLEN - REPL_MSG_HDRLEN);
+ QWASSIGN(*(seq_num *)&msg.msg[0], jgbl.max_resync_seqno);
+ msg.len = MIN_REPL_MSGLEN;
+ REPL_SEND_LOOP(gtmrecv_sock_fd, &msg, msg.len, REPL_POLL_NOWAIT);
+ ; /* Empty Body */
+ if (status != SS_NORMAL)
+ {
+ if (repl_errno == EREPL_SEND)
+ {
+ SNPRINTF(err_string, SIZEOF(err_string), "Error sending FETCH RESYNC message. Error in send : %s",
+ STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(err_string));
+ }
+ if (repl_errno == EREPL_SELECT)
+ {
+ SNPRINTF(err_string, SIZEOF(err_string), "Error sending FETCH RESYNC message. Error in select : %s",
+ STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(err_string));
+ }
+ }
+ wait_count = MAX_ATTEMPTS_FOR_FETCH_RESYNC;
+ REPL_RECV_LOOP(gtmrecv_sock_fd, &msg, MIN_REPL_MSGLEN, REPL_POLL_WAIT)
+ {
+ if (0 >= wait_count)
+ break;
+ repl_log(stdout, TRUE, TRUE, "Waiting for FETCH RESYNC\n");
+ wait_count--;
+ }
+ if (status != SS_NORMAL)
+ {
+ if (repl_errno == EREPL_RECV)
+ {
+ SNPRINTF(err_string, SIZEOF(err_string), "Error receiving RESYNC JNLSEQNO. Error in recv : %s",
+ STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(err_string));
+ }
+ if (repl_errno == EREPL_SELECT)
+ {
+ SNPRINTF(err_string, SIZEOF(err_string), "Error receiving RESYNC JNLSEQNO. Error in select : %s",
+ STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(err_string));
+ }
+ }
+ if (wait_count <= 0)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_LIT("Waited too long to get fetch resync message from primary. Check if primary is alive."));
+ REVERT;
+ QWASSIGN(*resync_seqno, *(seq_num *)&msg.msg[0]);
+ repl_log(stdout, TRUE, TRUE, "Received RESYNC SEQNO is "INT8_FMT"\n", INT8_PRINT(*resync_seqno));
+ /* Fork a child which will do the rest of the roll-back. The parent
+ * waits till the Source server signals completion of its task on
+ * receiving FETCH_RESYNC -- To be done on VMS. As of now it is sequential on VMS.
+ * The functionality doesn't get affected while the performance may
+ * suffer
+ */
+ rel_sem_immediate(RECV, RECV_SERV_COUNT_SEM);
+ /* Wait till connection is broken or REPL_CONN_CLOSE is received */
+ REPL_RECV_LOOP(gtmrecv_sock_fd, &msg, MIN_REPL_MSGLEN, REPL_POLL_WAIT)
+ {
+ REPL_DPRINT1("FETCH_RESYNC : Waiting for source to send CLOSE_CONN or connection breakage\n");
+ }
+ repl_close(>mrecv_sock_fd);
+ remove_sem_set(RECV);
+ return(SS_NORMAL);
+}
+
+int gtmrecv_wait_for_detach(void)
+{ /* Wait till parent detaches from all regions and releases receiver server count lock.
+ * Release the semaphore to protect against hang if this function is re-entered.
+ * Releasing is ok since this semaphore has no use once the parent has detached from the regions
+ */
+ if (0 == grab_sem(RECV, RECV_SERV_COUNT_SEM) && 0 == rel_sem(RECV, RECV_SERV_COUNT_SEM))
+ return(SS_NORMAL);
+ return(REPL_SEM_ERRNO);
+}
diff --git a/sr_vvms/gtmrecv_poll_actions.c b/sr_vvms/gtmrecv_poll_actions.c
new file mode 100644
index 0000000..e84484f
--- /dev/null
+++ b/sr_vvms/gtmrecv_poll_actions.c
@@ -0,0 +1,446 @@
+/****************************************************************
+ * *
+ * Copyright 2008, 2013 Fidelity Information Services, Inc.*
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_stdio.h"
+#include "gtm_string.h"
+#include "gtm_unistd.h"
+#include "gtm_time.h"
+#include <sys/wait.h>
+#include <errno.h>
+#include "gtm_inet.h"
+#include <descrip.h> /* Required for gtmrecv.h */
+
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "repl_shutdcode.h"
+
+#include "gtmrecv.h"
+#include "repl_comm.h"
+#include "repl_msg.h"
+#include "repl_dbg.h"
+#include "repl_log.h"
+#include "repl_errno.h"
+#include "iosp.h"
+#include "eintr_wrappers.h"
+#include "gt_timer.h"
+#include "gtmio.h"
+
+#include "util.h"
+#include "tp_change_reg.h"
+
+GBLREF repl_msg_ptr_t gtmrecv_msgp;
+GBLREF int gtmrecv_max_repl_msglen;
+GBLREF int gtmrecv_listen_sock_fd;
+GBLREF int gtmrecv_sock_fd;
+GBLREF boolean_t repl_connection_reset;
+GBLREF recvpool_addrs recvpool;
+GBLREF int gtmrecv_log_fd;
+GBLREF FILE *gtmrecv_log_fp;
+GBLREF boolean_t gtmrecv_logstats;
+GBLREF boolean_t gtmrecv_wait_for_jnl_seqno;
+GBLREF boolean_t gtmrecv_bad_trans_sent;
+GBLREF pid_t updproc_pid;
+GBLREF uint4 log_interval;
+GBLREF volatile time_t gtmrecv_now;
+
+error_def(ERR_REPLCOMM);
+error_def(ERR_RECVPOOLSETUP);
+error_def(ERR_TEXT);
+
+#ifdef INT8_SUPPORTED
+static seq_num last_ack_seqno = 0;
+#else
+static seq_num last_ack_seqno = {0, 0};
+#endif
+
+#define GTMRECV_NEXT_REPORT_FACTOR 2
+
+enum
+{
+ CONTINUE_POLL,
+ STOP_POLL
+};
+
+int gtmrecv_poll_actions1(int *pending_data_len, int *buff_unprocessed, unsigned char *buffp)
+{
+ static int report_cnt = 1;
+ static int next_report_at = 1;
+ static boolean_t send_xoff = FALSE;
+ static boolean_t xoff_sent = FALSE;
+ static boolean_t log_draining_msg = FALSE;
+ static boolean_t send_badtrans = FALSE;
+ static boolean_t upd_shut_too_early_logged = FALSE;
+ static repl_msg_t xoff_msg, bad_trans_msg;
+ static time_t last_reap_time = 0;
+
+ boolean_t alert = FALSE, info = FALSE;
+ int return_status;
+ gd_region *region_top;
+ unsigned char *msg_ptr; /* needed for REPL_{SEND,RECV}_LOOP */
+ int tosend_len, sent_len, sent_this_iter; /* needed for REPL_SEND_LOOP */
+ int torecv_len, recvd_len, recvd_this_iter; /* needed for REPL_RECV_LOOP */
+ int status; /* needed for REPL_{SEND,RECV}_LOOP */
+ int temp_len, pending_msg_size;
+ int upd_start_status, upd_start_attempts;
+ int buffered_data_len;
+ int upd_exit_status;
+ boolean_t bad_trans_detected = FALSE;
+ uint4 jnl_status;
+ recvpool_ctl_ptr_t recvpool_ctl;
+ upd_proc_local_ptr_t upd_proc_local;
+ gtmrecv_local_ptr_t gtmrecv_local;
+ upd_helper_ctl_ptr_t upd_helper_ctl;
+
+ recvpool_ctl = recvpool.recvpool_ctl;
+ upd_proc_local = recvpool.upd_proc_local;
+ gtmrecv_local = recvpool.gtmrecv_local;
+ upd_helper_ctl = recvpool.upd_helper_ctl;
+ jnl_status = 0;
+ if (SHUTDOWN == gtmrecv_local->shutdown)
+ {
+ repl_log(gtmrecv_log_fp, TRUE, TRUE, "Shutdown signalled\n");
+ gtmrecv_end(); /* Won't return */
+ }
+ /* Reset report_cnt and next_report_at to 1 when a new upd proc is forked */
+ if (1 == report_cnt || report_cnt == next_report_at)
+ {
+ if ((alert =
+ (NO_SHUTDOWN == upd_proc_local->upd_proc_shutdown
+ && SRV_DEAD == is_updproc_alive() &&
+ NO_SHUTDOWN == upd_proc_local->upd_proc_shutdown)) ||
+ (info = ((NORMAL_SHUTDOWN == upd_proc_local->upd_proc_shutdown ||
+ ABNORMAL_SHUTDOWN == upd_proc_local->upd_proc_shutdown)) &&
+ SRV_DEAD == is_updproc_alive()))
+ {
+ if (alert)
+ repl_log(gtmrecv_log_fp, TRUE, TRUE,
+ "ALERT : Receiver Server detected that Update Process is not ALIVE\n");
+ else
+ repl_log(gtmrecv_log_fp, TRUE, TRUE,
+ "INFO : Update process not running. User initiated Update Process shutdown was done\n");
+ if (1 == report_cnt)
+ {
+ send_xoff = TRUE;
+ QWASSIGN(recvpool_ctl->old_jnl_seqno, recvpool_ctl->jnl_seqno);
+ QWASSIGNDW(recvpool_ctl->jnl_seqno, 0);
+ upd_proc_local->bad_trans = FALSE; /* No point in doing bad transaction processing */
+ }
+ gtmrecv_wait_for_jnl_seqno = TRUE;
+ REPL_DPRINT1(
+ "gtmrecv_poll_actions : Setting gtmrecv_wait_for_jnl_seqno to TRUE because of upd crash/shutdown\n");
+ next_report_at *= GTMRECV_NEXT_REPORT_FACTOR;
+ report_cnt++;
+ }
+ } else
+ report_cnt++;
+
+ if (upd_proc_local->bad_trans && !send_badtrans)
+ {
+ send_xoff = TRUE;
+ send_badtrans = TRUE;
+ bad_trans_detected = TRUE;
+ } else if (!upd_proc_local->bad_trans && send_badtrans && 1 != report_cnt)
+ {
+ send_badtrans = FALSE;
+ bad_trans_detected = FALSE;
+ }
+ if (send_xoff && !xoff_sent && (FD_INVALID != gtmrecv_sock_fd))
+ {
+ /* Send XOFF */
+ xoff_msg.type = REPL_XOFF_ACK_ME;
+ memcpy((uchar_ptr_t)&xoff_msg.msg[0], (uchar_ptr_t)&upd_proc_local->read_jnl_seqno, SIZEOF(seq_num));
+ xoff_msg.len = MIN_REPL_MSGLEN;
+ REPL_SEND_LOOP(gtmrecv_sock_fd, &xoff_msg, xoff_msg.len, REPL_POLL_NOWAIT)
+ ; /* Empty Body */
+ if (SS_NORMAL != status)
+ {
+ if (REPL_CONN_RESET(status) && EREPL_SEND == repl_errno)
+ {
+ repl_log(gtmrecv_log_fp, TRUE, TRUE, "Connection reset while sending XOFF_ACK_ME. "
+ "Status = %d ; %s\n", status, STRERROR(status));
+ repl_close(>mrecv_sock_fd);
+ repl_connection_reset = TRUE;
+ xoff_sent = FALSE;
+ send_badtrans = FALSE;
+ } else if (EREPL_SEND == repl_errno)
+ rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_LIT("Error sending XOFF msg due to BAD_TRANS or UPD crash/shutdown. "
+ "Error in send"), status);
+ else if (EREPL_SELECT == repl_errno)
+ rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_LIT("Error sending XOFF msg due to BAD_TRANS or UPD crash/shutdown. "
+ "Error in select"), status);
+ } else
+ {
+ xoff_sent = TRUE;
+ log_draining_msg = TRUE;
+ }
+ repl_log(gtmrecv_log_fp, TRUE, TRUE, "REPL_XOFF_ACK_ME sent due to upd shutdown/crash or bad trans\n");
+ send_xoff = FALSE;
+ } else if (send_xoff && !xoff_sent && repl_connection_reset)
+ {
+ send_xoff = FALSE; /* connection has been lost, no point sending XOFF */
+ send_badtrans = FALSE;
+ }
+ /* Drain pipe */
+ if (xoff_sent)
+ {
+ if (log_draining_msg)
+ { /* avoid multiple logs per instance */
+ repl_log(gtmrecv_log_fp, TRUE, TRUE, "REPL INFO - Draining replication pipe due to %s\n",
+ send_badtrans ? "BAD_TRANS" : "UPD shutdown/crash");
+ log_draining_msg = FALSE;
+ }
+ if (0 != *buff_unprocessed)
+ {
+ /* Throw away the current contents of the buffer */
+ buffered_data_len = ((*pending_data_len <= *buff_unprocessed) ? *pending_data_len : *buff_unprocessed);
+ *buff_unprocessed -= buffered_data_len;
+ buffp += buffered_data_len;
+ *pending_data_len -= buffered_data_len;
+ REPL_DPRINT2("gtmrecv_poll_actions : (1) Throwing away %d bytes from old buffer while draining\n",
+ buffered_data_len);
+ while (REPL_MSG_HDRLEN <= *buff_unprocessed)
+ {
+ assert(0 == ((unsigned long)buffp & (SIZEOF(((repl_msg_ptr_t)buffp)->type) - 1)));
+ *pending_data_len = ((repl_msg_ptr_t)buffp)->len;
+ buffered_data_len = ((*pending_data_len <= *buff_unprocessed) ?
+ *pending_data_len : *buff_unprocessed);
+ *buff_unprocessed -= buffered_data_len;
+ buffp += buffered_data_len;
+ *pending_data_len -= buffered_data_len;
+ REPL_DPRINT2("gtmrecv_poll_actions : (2) Throwing away %d bytes from old buffer while draining\n",
+ buffered_data_len);
+ }
+ if (0 < *buff_unprocessed)
+ {
+ memmove((unsigned char *)gtmrecv_msgp, buffp, *buff_unprocessed);
+ REPL_DPRINT2("gtmrecv_poll_actions : Incomplete header of length %d while draining\n",
+ *buff_unprocessed);
+ }
+ }
+ status = SS_NORMAL;
+ if (0 != *buff_unprocessed || 0 == *pending_data_len)
+ {
+ /* Receive the header of a message */
+ REPL_RECV_LOOP(gtmrecv_sock_fd, ((unsigned char *)gtmrecv_msgp) + *buff_unprocessed,
+ (REPL_MSG_HDRLEN - *buff_unprocessed), REPL_POLL_WAIT)
+ ; /* Empty Body */
+
+ REPL_DPRINT3("gtmrecv_poll_actions : Received %d type of message of length %d while draining\n",
+ ((repl_msg_ptr_t)gtmrecv_msgp)->type, ((repl_msg_ptr_t)gtmrecv_msgp)->len);
+ }
+ if (SS_NORMAL == status &&
+ (0 != *buff_unprocessed || 0 == *pending_data_len) && REPL_XOFF_ACK == gtmrecv_msgp->type)
+ {
+ /* The rest of the XOFF_ACK msg */
+ REPL_RECV_LOOP(gtmrecv_sock_fd, gtmrecv_msgp, (MIN_REPL_MSGLEN - REPL_MSG_HDRLEN), REPL_POLL_WAIT)
+ ; /* Empty Body */
+ if (SS_NORMAL == status)
+ {
+ repl_log(gtmrecv_log_fp, TRUE, TRUE,
+ "REPL INFO - XOFF_ACK received. Drained replication pipe completely\n");
+ upd_shut_too_early_logged = FALSE;
+ xoff_sent = FALSE;
+ return_status = STOP_POLL;
+ }
+ } else if (SS_NORMAL == status)
+ {
+ /* Drain the rest of the message */
+ pending_msg_size = ((*pending_data_len > 0) ? *pending_data_len : gtmrecv_msgp->len - REPL_MSG_HDRLEN);
+ REPL_DPRINT2("gtmrecv_poll_actions : Throwing away %d bytes from pipe\n", pending_msg_size);
+ for (; SS_NORMAL == status && 0 < pending_msg_size;
+ pending_msg_size -= gtmrecv_max_repl_msglen)
+ {
+ temp_len = (pending_msg_size < gtmrecv_max_repl_msglen)? pending_msg_size : gtmrecv_max_repl_msglen;
+ REPL_RECV_LOOP(gtmrecv_sock_fd, gtmrecv_msgp, temp_len, REPL_POLL_WAIT)
+ ; /* Empty Body */
+ }
+ *buff_unprocessed = 0; *pending_data_len = 0;
+ if (SS_NORMAL == status && info && !upd_shut_too_early_logged)
+ {
+ repl_log(gtmrecv_log_fp, TRUE, TRUE, "ALERT : User initiated shutdown of Update Process done "
+ "when there was data in the replication pipe\n");
+ upd_shut_too_early_logged = TRUE;
+ }
+ return_status = CONTINUE_POLL;
+ }
+ if (SS_NORMAL != status)
+ {
+ if (EREPL_RECV == repl_errno)
+ {
+ if (REPL_CONN_RESET(status))
+ {
+ repl_log(gtmrecv_log_fp, TRUE, TRUE, "Connection reset while receiving XOFF_ACK. "
+ "Status = %d ; %s\n", status, STRERROR(status));
+ repl_close(>mrecv_sock_fd);
+ repl_connection_reset = TRUE;
+ xoff_sent = FALSE;
+ send_badtrans = FALSE;
+ return_status = STOP_POLL;
+ } else
+ rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_LIT("Error while draining replication pipe. Error in recv"), status);
+ } else if (EREPL_SELECT == repl_errno)
+ {
+ rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_LIT("Error while draining replication pipe. Error in select"), status);
+ }
+ }
+ } else
+ return_status = STOP_POLL;
+
+ if (STOP_POLL == return_status && send_badtrans && (FD_INVALID != gtmrecv_sock_fd))
+ {
+ /* Send BAD_TRANS */
+ bad_trans_msg.type = REPL_BADTRANS;
+ memcpy((uchar_ptr_t)&bad_trans_msg.msg[0], (uchar_ptr_t)&upd_proc_local->read_jnl_seqno, SIZEOF(seq_num));
+ bad_trans_msg.len = MIN_REPL_MSGLEN;
+ REPL_SEND_LOOP(gtmrecv_sock_fd, &bad_trans_msg, bad_trans_msg.len, REPL_POLL_NOWAIT)
+ ; /* Empty Body */
+ if (SS_NORMAL == status)
+ {
+ repl_log(gtmrecv_log_fp, TRUE, TRUE,
+ "REPL_BADTRANS sent with seqno %llu\n", upd_proc_local->read_jnl_seqno);
+ } else
+ {
+ if (REPL_CONN_RESET(status) && EREPL_SEND == repl_errno)
+ {
+ repl_log(gtmrecv_log_fp, TRUE, TRUE, "Connection reset while sending REPL_BADTRANS. "
+ "Status = %d ; %s\n", status, STRERROR(status));
+ repl_close(>mrecv_sock_fd);
+ repl_connection_reset = TRUE;
+ return_status = STOP_POLL;
+ } else if (EREPL_SEND == repl_errno)
+ rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_LIT("Error sending BAD_TRANS. Error in send"), status);
+ else if (EREPL_SELECT == repl_errno)
+ rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_LIT("Error sending BAD_TRANS. Error in select"), status);
+ }
+ send_badtrans = FALSE;
+ }
+ if (upd_proc_local->bad_trans && bad_trans_detected ||
+ UPDPROC_START == upd_proc_local->start_upd && 1 != report_cnt)
+ {
+ if (UPDPROC_START == upd_proc_local->start_upd)
+ {
+ assert(is_updproc_alive() != SRV_ALIVE);
+ upd_proc_local->upd_proc_shutdown = NO_SHUTDOWN;
+ }
+ recvpool_ctl->wrapped = FALSE;
+ recvpool_ctl->write_wrap = recvpool_ctl->recvpool_size;
+ recvpool_ctl->write = 0;
+ if (UPDPROC_START == upd_proc_local->start_upd)
+ {
+ /* Attempt starting the update process */
+ for (upd_start_attempts = 0;
+ UPDPROC_START_ERR == (upd_start_status = gtmrecv_upd_proc_init(FALSE)) &&
+ GTMRECV_MAX_UPDSTART_ATTEMPTS > upd_start_attempts;
+ upd_start_attempts++)
+ {
+ if (EREPL_UPDSTART_SEMCTL == repl_errno || EREPL_UPDSTART_BADPATH == repl_errno)
+ {
+ gtmrecv_autoshutdown();
+ } else if (EREPL_UPDSTART_FORK == repl_errno)
+ {
+ /* Couldn't start up update now, can try later */
+ LONG_SLEEP(GTMRECV_WAIT_FOR_PROC_SLOTS);
+ continue;
+ } else if (EREPL_UPDSTART_EXEC == repl_errno)
+ {
+ /* In forked child, could not exec, should exit */
+ gtmrecv_exit(ABNORMAL_SHUTDOWN);
+ }
+ }
+ if (UPDPROC_STARTED == (upd_proc_local->start_upd = upd_start_status))
+ {
+ REPL_DPRINT1("gtmrecv_poll_actions : Setting gtmrecv_wait_for_jnl_seqno to TRUE because of "
+ "upd restart\n");
+ gtmrecv_wait_for_jnl_seqno = TRUE;
+ report_cnt = next_report_at = 1;
+ if (send_xoff && (FD_INVALID == gtmrecv_sock_fd))
+ {
+ /* Update start command was issued before connection was established,
+ * no point in sending XOFF. */
+ send_xoff = FALSE;
+ }
+ } else
+ {
+ repl_log(gtmrecv_log_fp, TRUE, TRUE, "%d failed attempts to fork update process. Try later\n",
+ upd_start_attempts);
+ }
+ } else
+ {
+ REPL_DPRINT1("gtmrecv_poll_actions : Setting gtmrecv_wait_for_jnl_seqno to TRUE because bad trans sent\n");
+ gtmrecv_wait_for_jnl_seqno = TRUE;/* set this to TRUE to break out and go back to a fresh "do_main_loop" */
+ gtmrecv_bad_trans_sent = TRUE;
+ QWASSIGN(recvpool_ctl->jnl_seqno, upd_proc_local->read_jnl_seqno); /* This was the bad transaction */
+ upd_proc_local->bad_trans = FALSE;
+ }
+ }
+ if (0 == *pending_data_len && 0 != gtmrecv_local->changelog)
+ {
+ if (gtmrecv_local->changelog & REPLIC_CHANGE_LOGINTERVAL)
+ {
+ repl_log(gtmrecv_log_fp, TRUE, TRUE, "Changing log interval from %u to %u\n",
+ log_interval, gtmrecv_local->log_interval);
+ log_interval = gtmrecv_local->log_interval;
+ gtmrecv_reinit_logseqno(); /* will force a LOG on the first recv following the interval change */
+ }
+ if (gtmrecv_local->changelog & REPLIC_CHANGE_LOGFILE)
+ {
+ repl_log(gtmrecv_log_fp, TRUE, TRUE, "Changing log file to %s\n", gtmrecv_local->log_file);
+ util_log_open(STR_AND_LEN(gtmrecv_local->log_file));
+ repl_log(gtmrecv_log_fp, TRUE, TRUE, "Change log to %s successful\n",gtmrecv_local->log_file);
+ }
+ upd_proc_local->changelog = gtmrecv_local->changelog; /* Ask the update process to changelog request */
+ /* NOTE: update process and receiver each ignore any setting specific to the other (REPLIC_CHANGE_UPD_LOGINTERVAL,
+ * REPLIC_CHANGE_LOGINTERVAL) */
+ gtmrecv_local->changelog = 0;
+ }
+ if (0 == *pending_data_len && !gtmrecv_logstats && gtmrecv_local->statslog)
+ {
+ repl_log(gtmrecv_log_fp, TRUE, TRUE, "Stats logging not supported on VMS\n");
+ } else if (0 == *pending_data_len && gtmrecv_logstats && !gtmrecv_local->statslog)
+ {
+ gtmrecv_logstats = FALSE;
+ repl_log(gtmrecv_log_fp, TRUE, TRUE, "End statistics logging\n");
+ }
+ if (0 == *pending_data_len)
+ {
+ if (upd_helper_ctl->start_helpers)
+ {
+ gtmrecv_helpers_init(upd_helper_ctl->start_n_readers, upd_helper_ctl->start_n_writers);
+ upd_helper_ctl->start_helpers = FALSE;
+ }
+ if (HELPER_REAP_NONE != (status = upd_helper_ctl->reap_helpers) ||
+ (double)GTMRECV_REAP_HELPERS_INTERVAL <= difftime(gtmrecv_now, last_reap_time))
+ {
+ gtmrecv_reap_helpers(HELPER_REAP_WAIT == status);
+ last_reap_time = gtmrecv_now;
+ }
+ }
+ return (return_status);
+}
+
+int gtmrecv_poll_actions(int pending_data_len, int buff_unprocessed, unsigned char *buffp)
+{
+ while (CONTINUE_POLL == gtmrecv_poll_actions1(&pending_data_len, &buff_unprocessed, buffp));
+ return (SS_NORMAL);
+}
diff --git a/sr_vvms/gtmrecv_process.c b/sr_vvms/gtmrecv_process.c
new file mode 100644
index 0000000..2ffecdc
--- /dev/null
+++ b/sr_vvms/gtmrecv_process.c
@@ -0,0 +1,1113 @@
+/****************************************************************
+ * *
+ * Copyright 2006, 2013 Fidelity Information Services, Inc.*
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_socket.h"
+#include "gtm_inet.h"
+#include "gtm_time.h"
+#include "gtm_fcntl.h"
+#include "gtm_unistd.h"
+#include "gtm_string.h"
+#include "gtm_stdio.h"
+
+#include <sys/time.h>
+#include <errno.h>
+#ifdef VMS
+#include <descrip.h> /* Required for gtmrecv.h */
+#endif
+
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "gtmrecv.h"
+#include "repl_comm.h"
+#include "repl_msg.h"
+#include "repl_dbg.h"
+#include "repl_errno.h"
+#include "iosp.h"
+#include "gtm_event_log.h"
+#include "eintr_wrappers.h"
+#include "jnl.h"
+#include "repl_sp.h"
+#include "repl_filter.h"
+#include "repl_log.h"
+#include "gtmsource.h"
+#include "gtm_netdb.h"
+#include "sgtm_putmsg.h"
+#include "gt_timer.h"
+#include "min_max.h"
+#include "error.h"
+#include "copy.h"
+#include "memcoherency.h"
+#include "replgbl.h"
+
+#define RECVBUFF_REPLMSGLEN_FACTOR 8
+
+#define GTMRECV_WAIT_FOR_STARTJNLSEQNO 100 /* ms */
+
+#define GTMRECV_WAIT_FOR_UPD_PROGRESS 100 /* ms */
+#define GTMRECV_WAIT_FOR_UPD_PROGRESS_US (GTMRECV_WAIT_FOR_UPD_PROGRESS * 1000) /* micro sec */
+
+/* By having different high and low watermarks, we can reduce the # of XOFF/XON exchanges */
+#define RECVPOOL_HIGH_WATERMARK_PCTG 90 /* Send XOFF when %age of receive pool space occupied goes beyond this */
+#define RECVPOOL_LOW_WATERMARK_PCTG 80 /* Send XON when %age of receive pool space occupied falls below this */
+#define RECVPOOL_XON_TRIGGER_SIZE (1 * 1024 * 1024) /* Keep the low water mark within this amount of high water mark
+ * so that we don't wait too long to send XON */
+
+#define GTMRECV_XOFF_LOG_CNT 100
+
+#define GTMRECV_HEARTBEAT_PERIOD 10 /* seconds, timer that goes off every this period is the time keeper for
+ * receiver server; used to reduce calls to time related systemc calls */
+
+GBLDEF repl_msg_ptr_t gtmrecv_msgp;
+GBLDEF int gtmrecv_max_repl_msglen;
+GBLDEF int gtmrecv_sock_fd = FD_INVALID;
+GBLDEF boolean_t repl_connection_reset = FALSE;
+GBLDEF boolean_t gtmrecv_wait_for_jnl_seqno = FALSE;
+GBLDEF boolean_t gtmrecv_bad_trans_sent = FALSE;
+GBLDEF struct addrinfo primary_ai;
+GBLDEF struct sockaddr_storage primary_sas;
+
+GBLDEF qw_num repl_recv_data_recvd = 0;
+GBLDEF qw_num repl_recv_data_processed = 0;
+GBLDEF qw_num repl_recv_prefltr_data_procd = 0;
+GBLDEF qw_num repl_recv_lastlog_data_recvd = 0;
+GBLDEF qw_num repl_recv_lastlog_data_procd = 0;
+
+GBLDEF time_t repl_recv_prev_log_time;
+GBLDEF time_t repl_recv_this_log_time;
+GBLDEF volatile time_t gtmrecv_now = 0;
+
+GBLREF gtmrecv_options_t gtmrecv_options;
+GBLREF int gtmrecv_listen_sock_fd;
+GBLREF recvpool_addrs recvpool;
+GBLREF boolean_t gtmrecv_logstats;
+GBLREF int gtmrecv_filter;
+GBLREF int gtmrecv_log_fd;
+GBLREF FILE *gtmrecv_log_fp;
+GBLREF seq_num seq_num_zero, seq_num_one, seq_num_minus_one;
+GBLREF unsigned char jnl_ver, remote_jnl_ver;
+GBLREF unsigned char *repl_filter_buff;
+GBLREF int repl_filter_bufsiz;
+GBLREF unsigned int jnl_source_datalen, jnl_dest_maxdatalen;
+GBLREF unsigned char jnl_source_rectype, jnl_dest_maxrectype;
+GBLREF int repl_max_send_buffsize, repl_max_recv_buffsize;
+GBLREF boolean_t primary_side_std_null_coll;
+GBLREF boolean_t primary_side_trigger_support;
+GBLREF boolean_t secondary_side_std_null_coll;
+GBLREF boolean_t secondary_side_trigger_support;
+GBLREF seq_num lastlog_seqno;
+GBLREF uint4 log_interval;
+GBLREF qw_num trans_recvd_cnt, last_log_tr_recvd_cnt;
+
+error_def(ERR_JNLNEWREC);
+error_def(ERR_JNLRECFMT);
+error_def(ERR_JNLSETDATA2LONG);
+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);
+
+static unsigned char *buffp, *buff_start, *msgbuff, *filterbuff;
+static int buff_unprocessed;
+static int buffered_data_len;
+static int max_recv_bufsiz;
+static int data_len;
+static boolean_t xoff_sent;
+static repl_msg_t xon_msg, xoff_msg;
+static int xoff_msg_log_cnt = 0;
+static long recvpool_high_watermark, recvpool_low_watermark;
+static uint4 write_loc, write_wrap;
+static uint4 write_len, write_off,
+ pre_filter_write_len, pre_filter_write, pre_intlfilter_datalen;
+static double time_elapsed;
+static int recvpool_size;
+static int heartbeat_period;
+
+static void do_flow_control(uint4 write_pos)
+{
+ /* Check for overflow before writing */
+
+ recvpool_ctl_ptr_t recvpool_ctl;
+ upd_proc_local_ptr_t upd_proc_local;
+ gtmrecv_local_ptr_t gtmrecv_local;
+ long space_used;
+ unsigned char *msg_ptr; /* needed for REPL_{SEND,RECV}_LOOP */
+ int tosend_len, sent_len, sent_this_iter; /* needed for REPL_SEND_LOOP */
+ int torecv_len, recvd_len, recvd_this_iter; /* needed for REPL_RECV_LOOP */
+ int status; /* needed for REPL_{SEND,RECV}_LOOP */
+ int read_pos;
+ char print_msg[1024];
+
+ recvpool_ctl = recvpool.recvpool_ctl;
+ upd_proc_local = recvpool.upd_proc_local;
+ gtmrecv_local = recvpool.gtmrecv_local;
+ space_used = 0;
+ if (recvpool_ctl->wrapped)
+ space_used = write_pos + recvpool_size - (read_pos = upd_proc_local->read);
+ if (!recvpool_ctl->wrapped || space_used > recvpool_size)
+ space_used = write_pos - (read_pos = upd_proc_local->read);
+ if (space_used >= recvpool_high_watermark && !xoff_sent)
+ {
+ /* Send XOFF message */
+ xoff_msg.type = REPL_XOFF;
+ memcpy((uchar_ptr_t)&xoff_msg.msg[0], (uchar_ptr_t)&upd_proc_local->read_jnl_seqno, SIZEOF(seq_num));
+ xoff_msg.len = MIN_REPL_MSGLEN;
+ REPL_SEND_LOOP(gtmrecv_sock_fd, &xoff_msg, xoff_msg.len, REPL_POLL_NOWAIT)
+ {
+ gtmrecv_poll_actions(data_len, buff_unprocessed, buffp);
+ if (repl_connection_reset || gtmrecv_wait_for_jnl_seqno)
+ return;
+ }
+ if (SS_NORMAL != status)
+ {
+ if (REPL_CONN_RESET(status) && EREPL_SEND == repl_errno)
+ {
+ repl_connection_reset = TRUE;
+ return;
+ }
+ if (EREPL_SEND == repl_errno)
+ {
+ SNPRINTF(print_msg, SIZEOF(print_msg), "Error sending XOFF msg. Error in send : %s",
+ STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(print_msg));
+ }
+ if (EREPL_SELECT == repl_errno)
+ {
+ SNPRINTF(print_msg, SIZEOF(print_msg), "Error sending XOFF msg. Error in select : %s",
+ STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(print_msg));
+ }
+ }
+ if (gtmrecv_logstats)
+ repl_log(gtmrecv_log_fp, TRUE, TRUE, "Space used = %ld, High water mark = %d Low water mark = %d, "
+ "Updproc Read = %d, Recv Write = %d, Sent XOFF\n", space_used, recvpool_high_watermark,
+ recvpool_low_watermark, read_pos, write_pos);
+ repl_log(gtmrecv_log_fp, TRUE, TRUE, "REPL_XOFF sent as receive pool has %ld bytes transaction data yet to be "
+ "processed\n", space_used);
+ xoff_sent = TRUE;
+ xoff_msg_log_cnt = 1;
+ } else if (space_used < recvpool_low_watermark && xoff_sent)
+ {
+ xon_msg.type = REPL_XON;
+ memcpy((uchar_ptr_t)&xon_msg.msg[0], (uchar_ptr_t)&upd_proc_local->read_jnl_seqno, SIZEOF(seq_num));
+ xon_msg.len = MIN_REPL_MSGLEN;
+ REPL_SEND_LOOP(gtmrecv_sock_fd, &xon_msg, xon_msg.len, REPL_POLL_NOWAIT)
+ {
+ gtmrecv_poll_actions(data_len, buff_unprocessed, buffp);
+ if (repl_connection_reset || gtmrecv_wait_for_jnl_seqno)
+ return;
+ }
+ if (SS_NORMAL != status)
+ {
+ if (REPL_CONN_RESET(status) && EREPL_SEND == repl_errno)
+ {
+ repl_connection_reset = TRUE;
+ return;
+ }
+ if (EREPL_SEND == repl_errno)
+ {
+ SNPRINTF(print_msg, SIZEOF(print_msg), "Error sending XON msg. Error in send : %s",
+ STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(print_msg));
+ }
+ if (EREPL_SELECT == repl_errno)
+ {
+ SNPRINTF(print_msg, SIZEOF(print_msg), "Error sending XON msg. Error in select : %s",
+ STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(print_msg));
+ }
+ }
+ if (gtmrecv_logstats)
+ repl_log(gtmrecv_log_fp, TRUE, TRUE, "Space used now = %ld, High water mark = %d, "
+ "Low water mark = %d, Updproc Read = %d, Recv Write = %d, Sent XON\n", space_used,
+ recvpool_high_watermark, recvpool_low_watermark, read_pos, write_pos);
+ repl_log(gtmrecv_log_fp, TRUE, TRUE, "REPL_XON sent as receive pool has %ld bytes free space to buffer transaction "
+ "data\n", recvpool_size - space_used);
+ xoff_sent = FALSE;
+ xoff_msg_log_cnt = 0;
+ }
+ return;
+}
+
+static int gtmrecv_est_conn(void)
+{
+ recvpool_ctl_ptr_t recvpool_ctl;
+ upd_proc_local_ptr_t upd_proc_local;
+ gtmrecv_local_ptr_t gtmrecv_local;
+ fd_set input_fds;
+ int status;
+ const int disable_keepalive = 0;
+ struct linger disable_linger = {0, 0};
+ struct timeval poll_interval;
+ char print_msg[1024];
+ int send_buffsize, recv_buffsize, tcp_r_bufsize;
+
+ /*
+ * Wait for a connection from a Source Server.
+ * The Receiver Server is an iterative server.
+ */
+
+ recvpool_ctl = recvpool.recvpool_ctl;
+ upd_proc_local = recvpool.upd_proc_local;
+ gtmrecv_local = recvpool.gtmrecv_local;
+ primary_ai.ai_addr = (sockaddr_ptr)&primary_sas;
+
+ gtmrecv_comm_init((in_port_t)gtmrecv_local->listen_port);
+ primary_ai.ai_addrlen = SIZEOF(primary_sas);
+ repl_log(gtmrecv_log_fp, TRUE, TRUE, "Waiting for a connection...\n");
+ FD_ZERO(&input_fds);
+ FD_SET(gtmrecv_listen_sock_fd, &input_fds);
+ /*
+ * Note - the following while loop checks for EINTR on the select. The
+ * SELECT macro is not used because the FD_SET is redone before the new
+ * call to select (after the continue).
+ */
+ poll_interval.tv_sec = 0;
+ poll_interval.tv_usec = REPL_POLL_WAIT;
+ while (0 >= (status = select(gtmrecv_listen_sock_fd + 1, &input_fds, NULL, NULL, &poll_interval)))
+ {
+ assert(0 == poll_interval.tv_sec);
+ poll_interval.tv_usec = REPL_POLL_WAIT;
+ FD_SET(gtmrecv_listen_sock_fd, &input_fds);
+ if (0 == status)
+ gtmrecv_poll_actions(0, 0, NULL);
+ else if (EINTR == errno || EAGAIN == errno)
+ continue;
+ else
+ {
+ status = ERRNO;
+ SNPRINTF(print_msg, SIZEOF(print_msg), "Error in select on listen socket : %s", STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(print_msg));
+ }
+ }
+ ACCEPT_SOCKET(gtmrecv_listen_sock_fd, primary_ai.ai_addr, (sssize_t *)&primary_ai.ai_addrlen, gtmrecv_sock_fd);
+ if (FD_INVALID == gtmrecv_sock_fd)
+ {
+ status = ERRNO;
+ SNPRINTF(print_msg, SIZEOF(print_msg), "Error accepting connection from Source Server : %s", STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(print_msg));
+ }
+ /* Connection established */
+ repl_close(>mrecv_listen_sock_fd); /* Close the listener socket */
+ repl_connection_reset = FALSE;
+ repl_log(gtmrecv_log_fp, TRUE, TRUE, "Connection accepted. Connection socket created.\n");
+ if (-1 == setsockopt(gtmrecv_sock_fd, SOL_SOCKET, SO_LINGER, (const void *)&disable_linger, SIZEOF(disable_linger)))
+ {
+ status = ERRNO;
+ SNPRINTF(print_msg, SIZEOF(print_msg), "Error with receiver server socket disable linger : %s", STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(print_msg));
+ }
+
+#ifdef REPL_DISABLE_KEEPALIVE
+ if (-1 == setsockopt(gtmrecv_sock_fd, SOL_SOCKET, SO_KEEPALIVE, (const void *)&disable_keepalive,
+ SIZEOF(disable_keepalive)))
+ { /* Till SIGPIPE is handled properly */
+ status = ERRNO;
+ SNPRINTF(print_msg, SIZEOF(print_msg), "Error with receiver server socket disable keepalive : %s",
+ STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(print_msg));
+ }
+#endif
+ if (0 != (status = get_send_sock_buff_size(gtmrecv_sock_fd, &send_buffsize)))
+ {
+ SNPRINTF(print_msg, SIZEOF(print_msg), "Error getting socket send buffsize : %s", STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(print_msg));
+ }
+ if (send_buffsize < GTMRECV_TCP_SEND_BUFSIZE)
+ {
+ if (0 != (status = set_send_sock_buff_size(gtmrecv_sock_fd, GTMRECV_TCP_SEND_BUFSIZE)))
+ {
+ if (send_buffsize < GTMRECV_MIN_TCP_SEND_BUFSIZE)
+ {
+ SNPRINTF(print_msg, SIZEOF(print_msg), "Could not set TCP send buffer size to %d : %s",
+ GTMRECV_MIN_TCP_SEND_BUFSIZE, STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) MAKE_MSG_INFO(ERR_REPLCOMM), 0, ERR_TEXT, 2,
+ LEN_AND_STR(print_msg));
+ }
+ }
+ }
+ if (0 != (status = get_send_sock_buff_size(gtmrecv_sock_fd, &repl_max_send_buffsize))) /* may have changed */
+ {
+ SNPRINTF(print_msg, SIZEOF(print_msg), "Error getting socket send buffsize : %s", STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(print_msg));
+ }
+ if (0 != (status = get_recv_sock_buff_size(gtmrecv_sock_fd, &recv_buffsize)))
+ {
+ SNPRINTF(print_msg, SIZEOF(print_msg), "Error getting socket recv buffsize : %s", STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(print_msg));
+ }
+ if (recv_buffsize < GTMRECV_TCP_RECV_BUFSIZE)
+ {
+ for (tcp_r_bufsize = GTMRECV_TCP_RECV_BUFSIZE;
+ tcp_r_bufsize >= MAX(recv_buffsize, GTMRECV_MIN_TCP_RECV_BUFSIZE)
+ && 0 != (status = set_recv_sock_buff_size(gtmrecv_sock_fd, tcp_r_bufsize));
+ tcp_r_bufsize -= GTMRECV_TCP_RECV_BUFSIZE_INCR)
+ ;
+ if (tcp_r_bufsize < GTMRECV_MIN_TCP_RECV_BUFSIZE)
+ {
+ SNPRINTF(print_msg, SIZEOF(print_msg), "Could not set TCP receive buffer size in range [%d, %d], last "
+ "known error : %s", GTMRECV_MIN_TCP_RECV_BUFSIZE, GTMRECV_TCP_RECV_BUFSIZE,
+ STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) MAKE_MSG_INFO(ERR_REPLCOMM), 0, ERR_TEXT, 2,
+ LEN_AND_STR(print_msg));
+ }
+ }
+ if (0 != (status = get_recv_sock_buff_size(gtmrecv_sock_fd, &repl_max_recv_buffsize))) /* may have changed */
+ {
+ SNPRINTF(print_msg, SIZEOF(print_msg), "Error getting socket recv buffsize : %s", STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(print_msg));
+ }
+ repl_log(gtmrecv_log_fp, TRUE, TRUE, "Connection established, using TCP send buffer size %d receive buffer size %d\n",
+ repl_max_send_buffsize, repl_max_recv_buffsize);
+ return (SS_NORMAL);
+}
+
+int gtmrecv_alloc_filter_buff(int bufsiz)
+{
+ unsigned char *old_filter_buff, *free_filter_buff;
+
+ bufsiz = ROUND_UP2(bufsiz, OS_PAGE_SIZE);
+ if (NO_FILTER != gtmrecv_filter && repl_filter_bufsiz < bufsiz)
+ {
+ REPL_DPRINT3("Expanding filter buff from %d to %d\n", repl_filter_bufsiz, bufsiz);
+ free_filter_buff = filterbuff;
+ old_filter_buff = repl_filter_buff;
+ filterbuff = (unsigned char *)malloc(bufsiz + OS_PAGE_SIZE);
+ repl_filter_buff = (uchar_ptr_t)ROUND_UP2((unsigned long)filterbuff, OS_PAGE_SIZE);
+ if (NULL != free_filter_buff)
+ {
+ assert(NULL != old_filter_buff);
+ memcpy(repl_filter_buff, old_filter_buff, repl_filter_bufsiz);
+ free(free_filter_buff);
+ }
+ repl_filter_bufsiz = bufsiz;
+ }
+ return (SS_NORMAL);
+}
+
+void gtmrecv_free_filter_buff(void)
+{
+ if (NULL != filterbuff)
+ {
+ assert(NULL != repl_filter_buff);
+ free(filterbuff);
+ filterbuff = repl_filter_buff = NULL;
+ repl_filter_bufsiz = 0;
+ }
+}
+
+int gtmrecv_alloc_msgbuff(void)
+{
+ gtmrecv_max_repl_msglen = MAX_REPL_MSGLEN + SIZEOF(gtmrecv_msgp->type); /* add SIZEOF(...) for alignment */
+ assert(NULL == gtmrecv_msgp); /* first time initialization. The receiver server doesn't need to re-allocate */
+ msgbuff = (unsigned char *)malloc(gtmrecv_max_repl_msglen + OS_PAGE_SIZE);
+ gtmrecv_msgp = (repl_msg_ptr_t)ROUND_UP2((unsigned long)msgbuff, OS_PAGE_SIZE);
+ gtmrecv_alloc_filter_buff(gtmrecv_max_repl_msglen);
+ return (SS_NORMAL);
+}
+
+void gtmrecv_free_msgbuff(void)
+{
+ if (NULL != msgbuff)
+ {
+ assert(NULL != gtmrecv_msgp);
+ free(msgbuff);
+ msgbuff = NULL;
+ gtmrecv_msgp = NULL;
+ }
+}
+
+static void process_tr_buff(void)
+{
+ recvpool_ctl_ptr_t recvpool_ctl;
+ upd_proc_local_ptr_t upd_proc_local;
+ gtmrecv_local_ptr_t gtmrecv_local;
+ seq_num log_seqno, upd_seqno, diff_seqno;
+ uint4 future_write, in_size, out_size, out_bufsiz, tot_out_size, save_buff_unprocessed,
+ save_buffered_data_len, upd_read;
+ boolean_t filter_pass = FALSE;
+ uchar_ptr_t save_buffp, save_filter_buff, in_buff, out_buff;
+ int status;
+ qw_num msg_total;
+
+ recvpool_ctl = recvpool.recvpool_ctl;
+ upd_proc_local = recvpool.upd_proc_local;
+ gtmrecv_local = recvpool.gtmrecv_local;
+ do
+ {
+ if (write_loc + data_len > recvpool_size)
+ {
+# ifdef REPL_DEBUG
+ if (recvpool_ctl->wrapped)
+ REPL_DPRINT1("Update Process too slow. Waiting for it to free up space and wrap\n");
+# endif
+ while (recvpool_ctl->wrapped)
+ {
+ /* Wait till the updproc wraps */
+ SHORT_SLEEP(GTMRECV_WAIT_FOR_UPD_PROGRESS);
+ gtmrecv_poll_actions(data_len, buff_unprocessed, buffp);
+ if (repl_connection_reset || gtmrecv_wait_for_jnl_seqno)
+ return;
+ }
+ assert(recvpool_ctl->wrapped == FALSE);
+ REPL_DPRINT3("Write wrapped%sat : %d\n", (NO_FILTER != gtmrecv_filter && !filter_pass) ?
+ " prior to filtering " : (NO_FILTER != gtmrecv_filter) ? " after filtering " : " ", write_loc);
+ recvpool_ctl->write_wrap = write_wrap = write_loc;
+ /* The update process reads (a) "recvpool_ctl->write" first. If "write" is not equal to
+ * "upd_proc_local->read", it then reads (b) "recvpool_ctl->write_wrap" and assumes that "write_wrap"
+ * holds a non-stale value. This is in turn used to compare "temp_read" and "write_wrap" to determine
+ * how much of unprocessed data there is in the receive pool. If it so happens that the receiver server
+ * sets "write_wrap" in the above line to a value that is lesser than its previous value (possible if
+ * in the previous wrap of the pool, transactions used more portions of the pool than in the current wrap),
+ * it is important that the update process sees the updated value of "write_wrap" as long as it sees the
+ * corresponding update to "write". This is because it will otherwise end up processing the tail section
+ * of the receive pool (starting from the uptodate value of "write" to the stale value of "write_wrap")
+ * that does not contain valid journal data. For this read order dependency to hold good, the receiver
+ * server needs to do a write memory barrier after updating "write_wrap" but before updating "write".
+ * The update process will do a read memory barrier after reading "wrapped" but before reading "write".
+ */
+ SHM_WRITE_MEMORY_BARRIER;
+ /* The update process looks at "recvpool_ctl->write" first and then reads (a) "recvpool_ctl->write_wrap"
+ * AND (b) all journal data in the receive pool upto this offset. It assumes that (a) and (b) will never
+ * hold stale values corresponding to a previous state of "recvpool_ctl->write". In order for this
+ * assumption to hold good, the receiver server needs to do a write memory barrier after updating the
+ * receive pool data and "write_wrap" but before updating "write". The update process will do a read
+ * memory barrier after reading "write" but before reading "write_wrap" or the receive pool data. Not
+ * enforcing the read order will result in the update process attempting to read/process invalid data
+ * from the receive pool (which could end up in db out of sync situation between primary and secondary).
+ */
+ recvpool_ctl->write = write_loc = 0;
+ SHM_WRITE_MEMORY_BARRIER;
+ recvpool_ctl->wrapped = TRUE;
+ }
+ assert(buffered_data_len <= recvpool_size);
+ do_flow_control(write_loc);
+ if (repl_connection_reset)
+ {
+ repl_log(gtmrecv_log_fp, TRUE, TRUE, "Connection reset\n");
+ repl_close(>mrecv_sock_fd);
+ return;
+ }
+ if (gtmrecv_wait_for_jnl_seqno)
+ return;
+ future_write = write_loc + buffered_data_len;
+ upd_read = upd_proc_local->read;
+# ifdef REPL_DEBUG
+ if (recvpool_ctl->wrapped && (write_loc <= upd_read) && (upd_read <= future_write))
+ REPL_DPRINT1("Update Process too slow. Waiting for it to free up space\n");
+# endif
+ while (recvpool_ctl->wrapped && (write_loc <= upd_read) && (upd_read <= future_write))
+ { /* Write will cause overflow. Wait till there is more space available */
+ SHORT_SLEEP(GTMRECV_WAIT_FOR_UPD_PROGRESS);
+ gtmrecv_poll_actions(data_len, buff_unprocessed, buffp);
+ if (repl_connection_reset || gtmrecv_wait_for_jnl_seqno)
+ return;
+ upd_read = upd_proc_local->read;
+ }
+ memcpy(recvpool.recvdata_base + write_loc, buffp, buffered_data_len);
+ write_loc = future_write;
+ if (write_loc > write_wrap)
+ write_wrap = write_loc;
+
+ repl_recv_data_processed += (qw_num)buffered_data_len;
+ buffp += buffered_data_len;
+ buff_unprocessed -= buffered_data_len;
+ data_len -= buffered_data_len;
+
+ if (0 == data_len)
+ {
+ write_len = ((recvpool_ctl->write != write_wrap) ?
+ (write_loc - recvpool_ctl->write) : write_loc);
+ write_off = ((recvpool_ctl->write != write_wrap) ? recvpool_ctl->write : 0);
+ if ((recvpool_ctl->jnl_seqno - lastlog_seqno >= log_interval)
+ && (NO_FILTER == gtmrecv_filter || filter_pass))
+ {
+ log_seqno = recvpool_ctl->jnl_seqno;
+ upd_seqno = recvpool.upd_proc_local->read_jnl_seqno;
+ assert(log_seqno >= upd_seqno);
+ diff_seqno = (log_seqno - upd_seqno);
+ trans_recvd_cnt += (log_seqno - lastlog_seqno);
+ msg_total = repl_recv_data_recvd - buff_unprocessed;
+ /* Don't include data not yet processed, we'll include that count in a later log */
+ if (NO_FILTER == gtmrecv_filter)
+ {
+ repl_log(gtmrecv_log_fp, TRUE, TRUE, "REPL INFO - Seqno : "INT8_FMT" "INT8_FMTX
+ " Jnl Total : "INT8_FMT" "INT8_FMTX" Msg Total : "INT8_FMT" "INT8_FMTX
+ " Current backlog : "INT8_FMT" "INT8_FMTX"\n",
+ log_seqno, log_seqno, repl_recv_data_processed, repl_recv_data_processed,
+ msg_total, msg_total, diff_seqno, diff_seqno);
+ } else
+ {
+ repl_log(gtmrecv_log_fp, TRUE, TRUE, "REPL INFO - Seqno : "INT8_FMT" "INT8_FMTX
+ " Pre filter total : "INT8_FMT" "INT8_FMTX" Post filter total : "
+ INT8_FMT" "INT8_FMTX" Msg Total : "INT8_FMT" "INT8_FMTX
+ " Current backlog : "INT8_FMT" "INT8_FMTX"\n",
+ log_seqno, log_seqno, repl_recv_prefltr_data_procd, repl_recv_prefltr_data_procd,
+ repl_recv_data_processed, repl_recv_data_processed,
+ msg_total, msg_total, diff_seqno, diff_seqno);
+ }
+ /* Approximate time with an error not more than GTMRECV_HEARTBEAT_PERIOD. We use this instead of
+ * calling time(), and expensive system call, especially on VMS. The consequence of this choice
+ * is that we may defer logging when we may have logged. We can live with that. Currently, the
+ * logging interval is not changeable by users. When/if we provide means of choosing log interval,
+ * this code may have to be re-examined.
+ * Vinaya 2003, Sep 08
+ */
+ assert(0 != gtmrecv_now);
+ repl_recv_this_log_time = gtmrecv_now;
+ assert(repl_recv_this_log_time >= repl_recv_prev_log_time);
+ time_elapsed = difftime(repl_recv_this_log_time, repl_recv_prev_log_time);
+ if ((double)GTMRECV_LOGSTATS_INTERVAL <= time_elapsed)
+ {
+ repl_log(gtmrecv_log_fp, TRUE, TRUE, "REPL INFO since last log : Time elapsed : %00.f "
+ "Tr recvd : "INT8_FMT" Tr bytes : "INT8_FMT" Msg bytes : "INT8_FMT"\n",
+ time_elapsed, trans_recvd_cnt - last_log_tr_recvd_cnt,
+ repl_recv_data_processed - repl_recv_lastlog_data_procd,
+ msg_total - repl_recv_lastlog_data_recvd);
+ repl_log(gtmrecv_log_fp, TRUE, TRUE, "REPL INFO since last log : Time elapsed : %00.f "
+ "Tr recvd/s : %f Tr bytes/s : %f Msg bytes/s : %f\n", time_elapsed,
+ (float)(trans_recvd_cnt - last_log_tr_recvd_cnt)/time_elapsed,
+ (float)(repl_recv_data_processed - repl_recv_lastlog_data_procd)/time_elapsed,
+ (float)(msg_total - repl_recv_lastlog_data_recvd)/time_elapsed);
+ repl_recv_lastlog_data_procd = repl_recv_data_processed;
+ repl_recv_lastlog_data_recvd = msg_total;
+ last_log_tr_recvd_cnt = trans_recvd_cnt;
+ repl_recv_prev_log_time = repl_recv_this_log_time;
+ }
+ lastlog_seqno = log_seqno;
+ }
+ if (gtmrecv_logstats && (NO_FILTER == gtmrecv_filter || filter_pass))
+ {
+ if (NO_FILTER == gtmrecv_filter)
+ repl_log(gtmrecv_log_fp, FALSE, FALSE, "Tr : "INT8_FMT" Size : %d Write : %d "
+ "Total : "INT8_FMT"\n", recvpool_ctl->jnl_seqno, write_len,
+ write_off, repl_recv_data_processed);
+ else
+ repl_log(gtmrecv_log_fp, FALSE, FALSE, "Tr : "INT8_FMT" Pre filter Size : %d "
+ "Post filter Size : %d Pre filter Write : %d Post filter Write : %d "
+ "Pre filter Total : "INT8_FMT" Post filter Total : "INT8_FMT"\n",
+ recvpool_ctl->jnl_seqno, pre_filter_write_len, write_len,
+ pre_filter_write, write_off, repl_recv_prefltr_data_procd,
+ repl_recv_data_processed);
+ }
+ if ((NO_FILTER == gtmrecv_filter) || filter_pass)
+ {
+ recvpool_ctl->write_wrap = write_wrap;
+ QWINCRBYDW(recvpool_ctl->jnl_seqno, 1);
+ /* The update process looks at "recvpool_ctl->write" first and then reads
+ * (a) "recvpool_ctl->write_wrap" AND (b) all journal data in the receive pool upto this offset.
+ * It assumes that (a) and (b) will never hold stale values that reflect a corresponding previous
+ * state of "recvpool_ctl->write". In order for this assumption to hold good, the receiver server
+ * needs to do a write memory barrier after updating the receive pool data and "write_wrap" but
+ * before updating "write". The update process will do a read memory barrier after reading
+ * "write" but before reading "write_wrap" or the receive pool data. Not enforcing the read order
+ * will result in the update process attempting to read/process invalid data from the receive pool.
+ */
+ SHM_WRITE_MEMORY_BARRIER;
+ recvpool_ctl->write = write_loc;
+ if (filter_pass)
+ { /* Switch buffers back */
+ buffp = save_buffp;
+ buff_unprocessed = save_buff_unprocessed;
+ buffered_data_len = save_buffered_data_len;
+ filter_pass = FALSE;
+ }
+ } else
+ {
+ pre_filter_write = write_off;
+ pre_filter_write_len = write_len;
+ repl_recv_prefltr_data_procd += (qw_num)pre_filter_write_len;
+ if (gtmrecv_filter & INTERNAL_FILTER)
+ {
+ pre_intlfilter_datalen = write_len;
+ in_buff = recvpool.recvdata_base + write_off;
+ in_size = pre_intlfilter_datalen;
+ out_buff = repl_filter_buff;
+ out_bufsiz = repl_filter_bufsiz;
+ tot_out_size = 0;
+ while (SS_NORMAL != (status =
+ repl_filter_old2cur[remote_jnl_ver - JNL_VER_EARLIEST_REPL](
+ in_buff, &in_size, out_buff, &out_size, out_bufsiz)) &&
+ EREPL_INTLFILTER_NOSPC == repl_errno)
+ {
+ save_filter_buff = repl_filter_buff;
+ gtmrecv_alloc_filter_buff(repl_filter_bufsiz + (repl_filter_bufsiz >> 1));
+ in_buff += in_size;
+ in_size = pre_filter_write_len - (in_buff - recvpool.recvdata_base - write_off);
+ out_bufsiz = repl_filter_bufsiz - (out_buff - save_filter_buff) - out_size;
+ out_buff = repl_filter_buff + (out_buff - save_filter_buff) + out_size;
+ tot_out_size += out_size;
+ }
+ if (SS_NORMAL == status)
+ write_len = tot_out_size + out_size;
+ else
+ {
+ if (EREPL_INTLFILTER_BADREC == repl_errno)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_JNLRECFMT);
+ else 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) */
+ GTMASSERT;
+ }
+ } else
+ {
+ if (write_len > repl_filter_bufsiz)
+ gtmrecv_alloc_filter_buff(write_len);
+ memcpy(repl_filter_buff, recvpool.recvdata_base + write_off, write_len);
+ }
+ assert(write_len <= repl_filter_bufsiz);
+ if ((gtmrecv_filter & EXTERNAL_FILTER) &&
+ (SS_NORMAL != (status = repl_filter(recvpool_ctl->jnl_seqno, repl_filter_buff, (int*)&write_len,
+ repl_filter_bufsiz))))
+ repl_filter_error(recvpool_ctl->jnl_seqno, status);
+ assert(write_len <= repl_filter_bufsiz);
+ if (write_len > recvpool_size)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(11) ERR_REPLTRANS2BIG, 5, &recvpool_ctl->jnl_seqno,
+ write_len, 0, LEN_AND_LIT("Receive"), ERR_TEXT, 2,
+ LEN_AND_LIT("Post filter tr len larger than receive pool size"));
+
+ /* Switch buffers */
+ save_buffp = buffp;
+ save_buff_unprocessed = buff_unprocessed;
+ save_buffered_data_len = buffered_data_len;
+
+ data_len = buff_unprocessed = buffered_data_len = write_len;
+ buffp = repl_filter_buff;
+ write_loc = write_off;
+ repl_recv_data_processed -= (qw_num)pre_filter_write_len;
+ filter_pass = TRUE;
+ }
+ } else
+ filter_pass = FALSE;
+ } while (NO_FILTER != gtmrecv_filter && filter_pass);
+ return;
+}
+
+static void do_main_loop(boolean_t crash_restart)
+{
+ /* The work-horse of the Receiver Server */
+
+ void do_flow_control();
+
+ recvpool_ctl_ptr_t recvpool_ctl;
+ upd_proc_local_ptr_t upd_proc_local;
+ gtmrecv_local_ptr_t gtmrecv_local;
+ seq_num request_from, recvd_jnl_seqno;
+ int skip_for_alignment, msg_type, msg_len;
+ unsigned char *msg_ptr; /* needed for REPL_{SEND,RECV}_LOOP */
+ int tosend_len, sent_len, sent_this_iter; /* needed for REPL_SEND_LOOP */
+ int torecv_len, recvd_len, recvd_this_iter; /* needed for REPL_RECV_LOOP */
+ int status; /* needed for REPL_{SEND,RECV}_LOOP */
+ char print_msg[1024];
+ repl_heartbeat_msg_t heartbeat;
+ repl_start_reply_msg_t *start_msg;
+ uint4 recvd_start_flags;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ recvpool_ctl = recvpool.recvpool_ctl;
+ upd_proc_local = recvpool.upd_proc_local;
+ gtmrecv_local = recvpool.gtmrecv_local;
+ gtmrecv_wait_for_jnl_seqno = FALSE;
+
+ if (!gtmrecv_bad_trans_sent)
+ {
+ /* Wait for the Update Process to write start_jnl_seqno */
+ repl_log(gtmrecv_log_fp, FALSE, FALSE, "Waiting for Update Process to write jnl_seqno\n");
+ while (QWEQ(recvpool_ctl->jnl_seqno, seq_num_zero))
+ {
+ SHORT_SLEEP(GTMRECV_WAIT_FOR_STARTJNLSEQNO);
+ gtmrecv_poll_actions(0, 0, NULL);
+ if (repl_connection_reset)
+ return;
+ }
+ secondary_side_std_null_coll = recvpool_ctl->std_null_coll;
+ secondary_side_trigger_support = FALSE;
+ gtmrecv_wait_for_jnl_seqno = FALSE;
+ if (QWEQ(recvpool_ctl->start_jnl_seqno, seq_num_zero))
+ QWASSIGN(recvpool_ctl->start_jnl_seqno, recvpool_ctl->jnl_seqno);
+ repl_log(gtmrecv_log_fp, FALSE, TRUE, "Requesting transactions from JNL_SEQNO "INT8_FMT"\n",
+ recvpool_ctl->jnl_seqno);
+ QWASSIGN(request_from, recvpool_ctl->jnl_seqno);
+ /* Send (re)start JNL_SEQNO to Source Server */
+ gtmrecv_msgp->type = REPL_START_JNL_SEQNO;
+ ((repl_start_msg_ptr_t)gtmrecv_msgp)->start_flags = START_FLAG_NONE;
+ ((repl_start_msg_ptr_t)gtmrecv_msgp)->start_flags |=
+ (gtmrecv_options.stopsourcefilter ? START_FLAG_STOPSRCFILTER : 0);
+ ((repl_start_msg_ptr_t)gtmrecv_msgp)->start_flags |= (gtmrecv_options.updateresync ? START_FLAG_UPDATERESYNC : 0);
+ ((repl_start_msg_ptr_t)gtmrecv_msgp)->start_flags |= START_FLAG_HASINFO;
+ if (secondary_side_std_null_coll)
+ ((repl_start_msg_ptr_t)gtmrecv_msgp)->start_flags |= START_FLAG_COLL_M;
+ ((repl_start_msg_ptr_t)gtmrecv_msgp)->jnl_ver = jnl_ver;
+ QWASSIGN(*(seq_num *)&((repl_start_msg_ptr_t)gtmrecv_msgp)->start_seqno[0], request_from);
+ gtmrecv_msgp->len = MIN_REPL_MSGLEN;
+ REPL_SEND_LOOP(gtmrecv_sock_fd, gtmrecv_msgp, gtmrecv_msgp->len, REPL_POLL_NOWAIT)
+ {
+ gtmrecv_poll_actions(0, 0, NULL);
+ if (repl_connection_reset || gtmrecv_wait_for_jnl_seqno)
+ return;
+ }
+ if (SS_NORMAL != status)
+ {
+ if (REPL_CONN_RESET(status) && EREPL_SEND == repl_errno)
+ {
+ repl_close(>mrecv_sock_fd);
+ repl_connection_reset = TRUE;
+ sgtm_putmsg(print_msg, VARLSTCNT(4) ERR_REPLWARN, 2, LEN_AND_LIT("Connection closed"));
+ repl_log(gtmrecv_log_fp, TRUE, TRUE, print_msg);
+ gtm_event_log(GTM_EVENT_LOG_ARGC, "MUPIP", "ERR_REPLWARN", print_msg);
+ return;
+ }
+ if (EREPL_SEND == repl_errno)
+ {
+ SNPRINTF(print_msg, SIZEOF(print_msg), "Error sending (re)start jnlseqno. Error in send : %s",
+ STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(print_msg));
+ }
+ if (EREPL_SELECT == repl_errno)
+ {
+ SNPRINTF(print_msg, SIZEOF(print_msg), "Error sending (re)start jnlseqno. Error in select : %s",
+ STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(print_msg));
+ }
+ }
+ }
+ gtmrecv_bad_trans_sent = FALSE;
+ request_from = recvpool_ctl->jnl_seqno;
+ assert(request_from >= seq_num_one);
+ gtmrecv_reinit_logseqno();
+
+ repl_log(gtmrecv_log_fp, FALSE, TRUE, "Waiting for WILL_START or ROLL_BACK_FIRST message\n");
+
+ /* Receive journal data and place it in the Receive Pool */
+ buff_start = (unsigned char *)gtmrecv_msgp;
+ buffp = buff_start;
+ buff_unprocessed = 0;
+ data_len = 0;
+ skip_for_alignment = 0;
+ write_loc = recvpool_ctl->write;
+ write_wrap = recvpool_ctl->write_wrap;
+
+ repl_recv_data_recvd = 0;
+ repl_recv_data_processed = 0;
+ repl_recv_prefltr_data_procd = 0;
+ repl_recv_lastlog_data_recvd = 0;
+ repl_recv_lastlog_data_procd = 0;
+
+ while (TRUE)
+ {
+ recvd_len = gtmrecv_max_repl_msglen - buff_unprocessed - skip_for_alignment;
+ while ((status = repl_recv(gtmrecv_sock_fd, (buffp + buff_unprocessed), &recvd_len, REPL_POLL_WAIT))
+ == SS_NORMAL && recvd_len == 0)
+ {
+ recvd_len = gtmrecv_max_repl_msglen - buff_unprocessed - skip_for_alignment;
+ if (xoff_sent)
+ do_flow_control(write_loc);
+ if (xoff_sent && GTMRECV_XOFF_LOG_CNT <= xoff_msg_log_cnt)
+ {
+ /* update process is still running slow, gtmrecv_poll_interval is now 0.
+ * Force wait before logging any message.
+ */
+ SHORT_SLEEP(REPL_POLL_WAIT >> 10); /* approximate in ms */
+ REPL_DPRINT1("Waiting for Update Process to clear recvpool space\n");
+ xoff_msg_log_cnt = 0;
+ } else if (xoff_sent)
+ xoff_msg_log_cnt++;
+
+ if (repl_connection_reset)
+ {
+ repl_log(gtmrecv_log_fp, TRUE, TRUE, "Connection reset\n");
+ repl_close(>mrecv_sock_fd);
+ return;
+ }
+ if (gtmrecv_wait_for_jnl_seqno)
+ return;
+ gtmrecv_poll_actions(data_len, buff_unprocessed, buffp);
+ if (repl_connection_reset || gtmrecv_wait_for_jnl_seqno)
+ return;
+ }
+
+ if (SS_NORMAL != status)
+ {
+ if (EREPL_RECV == repl_errno)
+ {
+ if (REPL_CONN_RESET(status))
+ {
+ repl_log(gtmrecv_log_fp, TRUE, TRUE, "Connection reset. Status = %d ; %s\n",
+ status, STRERROR(status));
+ repl_connection_reset = TRUE;
+ repl_close(>mrecv_sock_fd);
+ return;
+ } else
+ {
+ SNPRINTF(print_msg, SIZEOF(print_msg), "Error in receiving from source. "
+ "Error in recv : %s", STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_STR(print_msg));
+ }
+ } else if (EREPL_SELECT == repl_errno)
+ {
+ SNPRINTF(print_msg, SIZEOF(print_msg), "Error in receiving from source. Error in select : %s",
+ STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(print_msg));
+ }
+ }
+
+ if (repl_connection_reset)
+ return;
+
+ /* Something on the replication pipe - read it */
+
+ REPL_DPRINT3("Pending data len : %d Prev buff unprocessed : %d\n", data_len, buff_unprocessed);
+
+ buff_unprocessed += recvd_len;
+ repl_recv_data_recvd += (qw_num)recvd_len;
+
+ if (gtmrecv_logstats)
+ repl_log(gtmrecv_log_fp, FALSE, FALSE, "Recvd : %d Total : %d\n", recvd_len, repl_recv_data_recvd);
+
+ while (REPL_MSG_HDRLEN <= buff_unprocessed)
+ {
+ if (0 == data_len)
+ {
+ assert(0 == ((unsigned long)buffp & (SIZEOF(((repl_msg_ptr_t)buffp)->type) - 1)));
+ msg_type = ((repl_msg_ptr_t)buffp)->type;
+ msg_len = data_len = ((repl_msg_ptr_t)buffp)->len - REPL_MSG_HDRLEN;
+ assert(0 == (msg_len & ((SIZEOF(((repl_msg_ptr_t)buffp)->type)) - 1)));
+ buffp += REPL_MSG_HDRLEN;
+ buff_unprocessed -= REPL_MSG_HDRLEN;
+
+ if (data_len > recvpool_size)
+ {
+ /* Too large a transaction to be
+ * accommodated in the Receive Pool */
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLTRANS2BIG, 5, &recvpool_ctl->jnl_seqno,
+ data_len, 0, LEN_AND_LIT("Receive"));
+ }
+ }
+ buffered_data_len = ((data_len <= buff_unprocessed) ? data_len : buff_unprocessed);
+ switch(msg_type)
+ {
+ case REPL_TR_JNL_RECS:
+ process_tr_buff();
+ if (repl_connection_reset || gtmrecv_wait_for_jnl_seqno)
+ return;
+ break;
+
+ case REPL_HEARTBEAT:
+ buffp += buffered_data_len;
+ buff_unprocessed -= buffered_data_len;
+ data_len -= buffered_data_len;
+ if (0 == data_len)
+ {
+ /* Heartbeat msg contents start from buffp - msg_len */
+ memcpy(heartbeat.ack_seqno, buffp - msg_len, msg_len);
+ REPL_DPRINT4("HEARTBEAT received with time %ld SEQNO "INT8_FMT" at %ld\n",
+ *(time_t *)&heartbeat.ack_time[0],
+ (*(seq_num *)&heartbeat.ack_seqno[0]), time(NULL));
+ heartbeat.type = REPL_HEARTBEAT;
+ heartbeat.len = MIN_REPL_MSGLEN;
+ QWASSIGN(*(seq_num *)&heartbeat.ack_seqno[0], upd_proc_local->read_jnl_seqno);
+ REPL_SEND_LOOP(gtmrecv_sock_fd, &heartbeat, heartbeat.len, REPL_POLL_NOWAIT)
+ {
+ gtmrecv_poll_actions(data_len, buff_unprocessed, buffp);
+ if (repl_connection_reset || gtmrecv_wait_for_jnl_seqno)
+ return;
+ }
+ /* Error handling for the above send_loop is not required as it'll be caught
+ * in the next recv_loop of the receiver server */
+ REPL_DPRINT4("HEARTBEAT sent with time %ld SEQNO "INT8_FMT" at %ld\n",
+ *(time_t *)&heartbeat.ack_time[0],
+ (*(seq_num *)&heartbeat.ack_seqno[0]), time(NULL));
+ }
+ break;
+
+ case REPL_WILL_RESTART_WITH_INFO:
+ case REPL_ROLLBACK_FIRST:
+ buffp += buffered_data_len;
+ buff_unprocessed -= buffered_data_len;
+ data_len -= buffered_data_len;
+ if (0 == data_len)
+ {
+ assert(msg_len == MIN_REPL_MSGLEN - REPL_MSG_HDRLEN);
+ start_msg = (repl_start_reply_msg_t *)(buffp - msg_len - REPL_MSG_HDRLEN);
+ assert((unsigned long)start_msg % SIZEOF(seq_num) == 0); /* alignment check */
+ QWASSIGN(recvd_jnl_seqno, *(seq_num *)start_msg->start_seqno);
+ if (REPL_WILL_RESTART_WITH_INFO == msg_type)
+ {
+ repl_log(gtmrecv_log_fp, TRUE, TRUE, "Received WILL_START message. "
+ "Primary acked the restart point\n");
+ remote_jnl_ver = start_msg->jnl_ver;
+ REPL_DPRINT3("Local jnl ver is octal %o, remote jnl ver is octal %o\n",
+ jnl_ver, remote_jnl_ver);
+ repl_check_jnlver_compat();
+ /* older versions zero filler that was in place of start_msg->start_flags,
+ * so we are okay fetching start_msg->start_flags unconditionally.
+ */
+ GET_ULONG(recvd_start_flags, start_msg->start_flags);
+ assert(remote_jnl_ver > V15_JNL_VER || 0 == recvd_start_flags);
+ if (remote_jnl_ver <= V15_JNL_VER) /* safety in pro */
+ recvd_start_flags = 0;
+ primary_side_std_null_coll = (recvd_start_flags & START_FLAG_COLL_M) ?
+ TRUE : FALSE;
+ if (FALSE != ((TREF(replgbl)).null_subs_xform =
+ ((primary_side_std_null_coll &&
+ !secondary_side_std_null_coll)
+ || (secondary_side_std_null_coll &&
+ !primary_side_std_null_coll))))
+ (TREF(replgbl)).null_subs_xform = (primary_side_std_null_coll ?
+ STDNULL_TO_GTMNULL_COLL : GTMNULL_TO_STDNULL_COLL);
+ /* this sets null_subs_xform regardless of remote_jnl_ver */
+ primary_side_trigger_support
+ = (recvd_start_flags & START_FLAG_TRIGGER_SUPPORT) ? TRUE : FALSE;
+ if ((jnl_ver > remote_jnl_ver)
+ && (IF_NONE != repl_filter_old2cur[remote_jnl_ver
+ - JNL_VER_EARLIEST_REPL]))
+ {
+ assert(IF_INVALID !=
+ repl_filter_old2cur[remote_jnl_ver - JNL_VER_EARLIEST_REPL]);
+ /* reverse transformation should exist */
+ 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;
+ gtmrecv_alloc_filter_buff(gtmrecv_max_repl_msglen);
+ } else
+ {
+ gtmrecv_filter &= ~INTERNAL_FILTER;
+ if (NO_FILTER == gtmrecv_filter)
+ gtmrecv_free_filter_buff();
+ }
+ /* Don't send any more stopsourcefilter message */
+ gtmrecv_options.stopsourcefilter = FALSE;
+ assert(QWEQ(recvd_jnl_seqno, request_from));
+ break;
+ }
+ repl_log(gtmrecv_log_fp, TRUE, FALSE, "ROLLBACK_FIRST message received. Secondary "
+ "ahead of primary. Secondary at "INT8_FMT, request_from);
+ repl_log(gtmrecv_log_fp, FALSE, TRUE, ", primary at "INT8_FMT". "
+ "Do ROLLBACK FIRST\n", recvd_jnl_seqno);
+ gtmrecv_autoshutdown();
+ }
+ break;
+
+ default:
+ /* Discard the message */
+ repl_log(gtmrecv_log_fp, TRUE, TRUE, "Message of unknown type (%d) received\n", msg_type);
+ assert(FALSE);
+ buffp += buffered_data_len;
+ buff_unprocessed -= buffered_data_len;
+ data_len -= buffered_data_len;
+ break;
+ }
+ if (repl_connection_reset)
+ return;
+ }
+ skip_for_alignment = (int)((unsigned long)buffp & (SIZEOF(((repl_msg_ptr_t)buffp)->type) - 1));
+ if (0 != buff_unprocessed)
+ {
+ REPL_DPRINT4("Incmpl msg hdr, moving %d bytes from %lx to %lx\n", buff_unprocessed, (caddr_t)buffp,
+ (caddr_t)buff_start + skip_for_alignment);
+ memmove(buff_start + skip_for_alignment, buffp, buff_unprocessed);
+ }
+ buffp = buff_start + skip_for_alignment;
+
+ gtmrecv_poll_actions(data_len, buff_unprocessed, buffp);
+ if (repl_connection_reset || gtmrecv_wait_for_jnl_seqno)
+ return;
+ }
+}
+
+static void gtmrecv_heartbeat_timer(TID tid, int4 interval_len, int *interval_ptr)
+{
+ assert(0 != gtmrecv_now);
+ UNIX_ONLY(assert(*interval_ptr == heartbeat_period);) /* interval_len and interval_ptr are dummies on VMS */
+ gtmrecv_now += heartbeat_period;
+ REPL_DPRINT2("Starting heartbeat timer with %d s\n", heartbeat_period);
+ start_timer((TID)gtmrecv_heartbeat_timer, heartbeat_period * 1000, gtmrecv_heartbeat_timer, SIZEOF(heartbeat_period),
+ &heartbeat_period); /* start_timer expects time interval in milli seconds, heartbeat_period is in seconds */
+}
+
+static void gtmrecv_main_loop(boolean_t crash_restart)
+{
+ assert(FD_INVALID == gtmrecv_sock_fd);
+ gtmrecv_poll_actions(0, 0, NULL); /* Clear any pending bad trans */
+ gtmrecv_est_conn();
+ gtmrecv_bad_trans_sent = FALSE; /* this assignment should be after gtmrecv_est_conn since gtmrecv_est_conn can
+ * potentially call gtmrecv_poll_actions. If the timing is right,
+ * gtmrecv_poll_actions might set this variable to TRUE if the update process sets
+ * bad_trans in the recvpool. When we are (re)establishing connection with the
+ * source server, there is no point in doing bad trans processing. Also, we have
+ * to send START_JNL_SEQNO message to the source server. If not, there will be a
+ * deadlock with the source and receiver servers waiting for each other to send
+ * a message. */
+ repl_recv_prev_log_time = gtmrecv_now;
+ while (!repl_connection_reset)
+ do_main_loop(crash_restart);
+ return;
+}
+
+void gtmrecv_process(boolean_t crash_restart)
+{
+ recvpool_ctl_ptr_t recvpool_ctl;
+ upd_proc_local_ptr_t upd_proc_local;
+ gtmrecv_local_ptr_t gtmrecv_local;
+ void gtmrecv_heartbeat_timer();
+
+ recvpool_ctl = recvpool.recvpool_ctl;
+ upd_proc_local = recvpool.upd_proc_local;
+ gtmrecv_local = recvpool.gtmrecv_local;
+
+ jnl_ver = JNL_VER_THIS;
+ assert(REPL_POLL_WAIT < MILLISECS_IN_SEC);
+ recvpool_size = recvpool_ctl->recvpool_size;
+ recvpool_high_watermark = (long)((float)RECVPOOL_HIGH_WATERMARK_PCTG / 100 * recvpool_size);
+ recvpool_low_watermark = (long)((float)RECVPOOL_LOW_WATERMARK_PCTG / 100 * recvpool_size);
+ if ((long)((float)(RECVPOOL_HIGH_WATERMARK_PCTG - RECVPOOL_LOW_WATERMARK_PCTG) / 100 * recvpool_size) >=
+ RECVPOOL_XON_TRIGGER_SIZE)
+ { /* for large receive pools, the difference between high and low watermarks as computed above may be too large that
+ * we may not send XON quickly enough. Limit the difference to RECVPOOL_XON_TRIGGER_SIZE */
+ recvpool_low_watermark = recvpool_high_watermark - RECVPOOL_XON_TRIGGER_SIZE;
+ }
+ REPL_DPRINT4("RECVPOOL HIGH WATERMARK is %ld, LOW WATERMARK is %ld, Receive pool size is %ld\n",
+ recvpool_high_watermark, recvpool_low_watermark, recvpool_size);
+ gtmrecv_alloc_msgbuff();
+ gtmrecv_now = time(NULL);
+ heartbeat_period = GTMRECV_HEARTBEAT_PERIOD; /* time keeper, well sorta */
+ start_timer((TID)gtmrecv_heartbeat_timer, heartbeat_period * 1000, gtmrecv_heartbeat_timer, SIZEOF(heartbeat_period),
+ &heartbeat_period); /* start_timer expects time interval in milli seconds, heartbeat_period is in seconds */
+ do
+ {
+ gtmrecv_main_loop(crash_restart);
+ } while (repl_connection_reset);
+ GTMASSERT; /* shouldn't reach here */
+ return;
+}
diff --git a/sr_vvms/gtmrecv_shutdown.c b/sr_vvms/gtmrecv_shutdown.c
new file mode 100644
index 0000000..ef8c47d
--- /dev/null
+++ b/sr_vvms/gtmrecv_shutdown.c
@@ -0,0 +1,150 @@
+/****************************************************************
+ * *
+ * Copyright 2006, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_socket.h"
+#include <sys/time.h>
+#include <errno.h>
+#include "gtm_fcntl.h"
+#include "gtm_unistd.h"
+#include "gtm_inet.h"
+#include "gtm_string.h"
+#include <descrip.h> /* Required for gtmrecv.h */
+
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "iosp.h"
+#include "gtmrecv.h"
+#include "repl_dbg.h"
+#include "gtm_stdio.h"
+#include "repl_shutdcode.h"
+#include "repl_sem.h"
+#include "is_proc_alive.h"
+#include "repl_log.h"
+#include "gt_timer.h"
+
+#define GTMRECV_WAIT_FOR_SHUTDOWN (1000 - 1) /* ms, almost 1s */
+
+GBLREF uint4 process_id;
+GBLREF recvpool_addrs recvpool;
+GBLREF int recvpool_shmid;
+GBLREF gtmrecv_options_t gtmrecv_options;
+GBLREF boolean_t is_rcvr_server;
+GBLREF int gtmrecv_srv_count;
+GBLREF void (*call_on_signal)();
+
+int gtmrecv_shutdown(boolean_t auto_shutdown, int exit_status)
+{
+
+ uint4 savepid;
+ boolean_t shut_upd_too;
+ int status;
+
+ repl_log(stdout, TRUE, TRUE, "Initiating shut down\n");
+ call_on_signal = NULL; /* So we don't reenter on error */
+ /* Grab the receive pool access control and receive pool option write lock */
+ status = grab_sem(RECV, RECV_POOL_ACCESS_SEM);
+ if (0 == status && (!auto_shutdown || gtmrecv_srv_count))
+ {
+ if((status = grab_sem(RECV, RECV_SERV_OPTIONS_SEM)) < 0)
+ rel_sem(RECV, RECV_POOL_ACCESS_SEM);
+ } /* else if autoshutdown, parent still holds RECV_SERV_OPTIONS_SEM and the child is exiting at startup */
+ if (0 > status)
+ {
+ repl_log(stderr, TRUE, TRUE,
+ "Error grabbing receive pool control/recvpool option write lock : %s. Shutdown not complete\n",
+ REPL_SEM_ERROR);
+ return (ABNORMAL_SHUTDOWN);
+ }
+
+ shut_upd_too = FALSE;
+
+ if (!auto_shutdown)
+ {
+ /* Wait till shutdown time nears */
+ if (0 < gtmrecv_options.shutdown_time)
+ {
+ repl_log(stdout, FALSE, TRUE, "Waiting for %d seconds before signalling shutdown\n",
+ gtmrecv_options.shutdown_time);
+ LONG_SLEEP(gtmrecv_options.shutdown_time);
+ } else
+ repl_log(stdout, FALSE, TRUE, "Signalling immediate shutdown\n");
+ recvpool.gtmrecv_local->shutdown = SHUTDOWN;
+
+ /* Wait for receiver server to shut down */
+ while(recvpool.gtmrecv_local->shutdown == SHUTDOWN &&
+ 0 < (savepid = recvpool.gtmrecv_local->recv_serv_pid) &&
+ is_proc_alive(savepid, 0))
+ SHORT_SLEEP(GTMRECV_WAIT_FOR_SHUTDOWN);
+
+ exit_status = recvpool.gtmrecv_local->shutdown;
+ if (SHUTDOWN == exit_status)
+ {
+ if (0 == savepid) /* No Receiver Process */
+ exit_status = NORMAL_SHUTDOWN;
+ else /* Receiver Server Crashed */
+ {
+ repl_log(stderr, FALSE, TRUE, "Receiver Server exited abnormally\n");
+ exit_status = ABNORMAL_SHUTDOWN;
+ shut_upd_too = TRUE;
+ }
+ }
+ }
+
+ if (shut_upd_too)
+ gtmrecv_endupd();
+
+ /*
+ * gtmrecv_ipc_cleanup will not be successful unless receiver server has completely exited.
+ * It relies on RECV_SERV_COUNT_SEM value.
+ */
+ if (FALSE == gtmrecv_ipc_cleanup(auto_shutdown, &exit_status))
+ {
+ /* Release all semaphores */
+ if (!auto_shutdown)
+ {
+ rel_sem_immediate( RECV, UPD_PROC_COUNT_SEM);
+ rel_sem_immediate( RECV, RECV_SERV_COUNT_SEM);
+ }
+ rel_sem_immediate( RECV, RECV_SERV_OPTIONS_SEM);
+ rel_sem_immediate( RECV, RECV_POOL_ACCESS_SEM);
+ }
+ return (exit_status);
+}
+
+static void gtmrecv_stop(boolean_t exit)
+{
+ int status;
+
+ status = gtmrecv_shutdown(TRUE, gtmrecv_end1(TRUE)) - NORMAL_SHUTDOWN;
+ if (exit)
+ gtmrecv_exit(status);
+ return;
+}
+
+void gtmrecv_sigstop(void)
+{
+ if (is_rcvr_server)
+ gtmrecv_stop(FALSE);
+ return;
+}
+
+void gtmrecv_autoshutdown(void)
+{
+ gtmrecv_stop(TRUE);
+ return;
+}
diff --git a/sr_vvms/gtmsecshr.h b/sr_vvms/gtmsecshr.h
new file mode 100644
index 0000000..e1d1b89
--- /dev/null
+++ b/sr_vvms/gtmsecshr.h
@@ -0,0 +1,34 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2004 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#if defined(__alpha) && defined(__vms)
+#define memmove gtm_memmove
+#endif
+#define GTMSECSHR_SET_PRIV(X, Y) \
+{ \
+ prvadr[1] = 0; \
+ prvadr[0] = (X); \
+ Y = sys$setprv(TRUE, prvadr, FALSE, prvprv); \
+}
+#define GTMSECSHR_REL_PRIV \
+if (0 != (prvadr[0] &= ~prvprv[0])) \
+{ \
+ sys$setprv(FALSE, prvadr, FALSE, NULL); \
+}
+#ifdef DEBUG
+#define GTMSECSHR_SET_DBG_PRIV(X, Y) GTMSECSHR_SET_PRIV((X), (Y))
+#define GTMSECSHR_REL_DBG_PRIV GTMSECSHR_REL_PRIV
+#else
+/* in kernel mode - can do whatever anyway */
+#define GTMSECSHR_SET_DBG_PRIV(X, Y) Y = TRUE
+#define GTMSECSHR_REL_DBG_PRIV
+#endif
+
diff --git a/sr_vvms/gtmsource.c b/sr_vvms/gtmsource.c
new file mode 100644
index 0000000..e188682
--- /dev/null
+++ b/sr_vvms/gtmsource.c
@@ -0,0 +1,556 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc.*
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <efndef.h>
+#include "gtm_inet.h"
+#include <sys/mman.h>
+#include "gtm_fcntl.h"
+#include "gtm_unistd.h"
+#include <errno.h>
+#include "gtm_string.h"
+
+#include <ssdef.h>
+#include <prtdef.h>
+#include <prcdef.h>
+#include <secdef.h>
+#include <psldef.h>
+#include <descrip.h>
+#include <iodef.h>
+#include <prvdef.h>
+#include <lnmdef.h>
+
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "jnl.h"
+#include "repl_msg.h"
+#include "gtmsource.h"
+#include "repl_dbg.h"
+#include "error.h"
+#include "gtm_stdio.h"
+#include "cli.h"
+#include "iosp.h"
+#include "repl_log.h"
+#include "repl_errno.h"
+#include "gtm_event_log.h"
+#include "repl_shutdcode.h"
+#include "repl_sem.h"
+#include "repl_sp.h"
+#include "efn.h"
+#include "vmsdtype.h"
+#include "gtm_logicals.h"
+#include "repl_filter.h"
+#include "util.h"
+#include "io.h"
+#include "is_proc_alive.h"
+#include "is_file_identical.h"
+#include "dfntmpmbx.h"
+#include "gtmmsg.h"
+#include "sgtm_putmsg.h"
+#include "trans_log_name.h"
+#include "repl_comm.h"
+
+GBLDEF boolean_t gtmsource_logstats = FALSE, gtmsource_pool2file_transition = FALSE;
+GBLDEF int gtmsource_filter = NO_FILTER;
+GBLDEF boolean_t update_disable = FALSE;
+
+GBLREF gtmsource_options_t gtmsource_options;
+GBLREF gtmsource_state_t gtmsource_state;
+GBLREF jnlpool_addrs jnlpool;
+GBLREF uint4 process_id;
+GBLREF int gtmsource_sock_fd;
+GBLREF int gtmsource_log_fd;
+GBLREF FILE *gtmsource_log_fp;
+GBLREF gd_addr *gd_header;
+GBLREF void (*call_on_signal)();
+GBLREF boolean_t is_src_server;
+GBLREF seq_num gtmsource_save_read_jnl_seqno, seq_num_zero;
+GBLREF gd_region *gv_cur_region;
+GBLREF sgmnt_addrs *cs_addrs;
+GBLREF sgmnt_data_ptr_t cs_data;
+GBLREF repl_msg_ptr_t gtmsource_msgp;
+GBLREF int gtmsource_msgbufsiz;
+GBLREF unsigned char *gtmsource_tcombuff_start;
+GBLREF uchar_ptr_t repl_filter_buff;
+GBLREF int repl_filter_bufsiz;
+GBLREF int gtmsource_srv_count;
+GBLREF boolean_t primary_side_std_null_coll;
+GBLREF boolean_t primary_side_trigger_support;
+GBLREF uint4 log_interval;
+GBLREF unsigned char jnl_ver;
+
+error_def(ERR_JNLPOOLSETUP);
+error_def(ERR_MUPCLIERR);
+error_def(ERR_NOTALLDBOPN);
+error_def(ERR_NULLCOLLDIFF);
+error_def(ERR_REPLCOMM);
+error_def(ERR_REPLINFO);
+error_def(ERR_REPLOFFJNLON);
+error_def(ERR_TEXT);
+
+int gtmsource()
+{
+ gd_region *reg, *region_top;
+ sgmnt_addrs *csa;
+ boolean_t jnlpool_inited, srv_alive, all_files_open;
+ uint4 gtmsource_pid;
+ int status, ef_status, retval=0, len;
+ char print_msg[1024];
+ uint4 prvadr[2], prvprv[2];
+ mstr log_nam, trans_log_nam;
+ char proc_name[PROC_NAME_MAXLEN + 1];
+ char cmd_str[MAX_COMMAND_LINE_LENGTH], sigmbx_name[MAX_NAME_LEN + 1], trans_buff[MAX_FN_LEN];
+ uint4 signal_channel, cmd_channel;
+ unsigned short mbsb[4], cmd_len;
+ uint4 buff, server_pid, clus_flags_stat;
+ gds_file_id file_id;
+ seq_num resync_seqno;
+ char exp_log_file_name[MAX_FN_LEN], log_file_name[MAX_FN_LEN];
+ unsigned short log_file_len;
+ int exp_log_file_name_len, connect_parms_index;
+ char *ptr, qwstring[100];
+
+ $DESCRIPTOR(proc_name_desc, proc_name);
+ $DESCRIPTOR(d_signal_mbox, sigmbx_name);
+ $DESCRIPTOR(cmd_desc, cmd_str);
+
+ memset((uchar_ptr_t)&jnlpool, 0, SIZEOF(jnlpool));
+ call_on_signal = gtmsource_sigstop;
+ ESTABLISH_RET(gtmsource_ch, SS_NORMAL);
+ if (-1 == gtmsource_get_opt())
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MUPCLIERR);
+
+ if (CLI_PRESENT == cli_present("START"))
+ { /* Generate a unique name for the signal_mbx using global_name(gbldir) and "GTMX" as prefix */
+ log_nam.addr = GTM_GBLDIR;
+ log_nam.len = STR_LIT_LEN(GTM_GBLDIR);
+ if (SS_NORMAL != (status = trans_log_name(&log_nam, &trans_log_nam, trans_buff)))
+ {
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("gtm$gbldir not defined"), status);
+ gtmsource_exit(ABNORMAL_SHUTDOWN);
+ }
+ set_gdid_from_file((gd_id_ptr_t)&file_id, trans_buff, trans_log_nam.len);
+ global_name("GTMX", &file_id, sigmbx_name);
+ STR_OF_DSC(d_signal_mbox)++;
+ LEN_OF_DSC(d_signal_mbox) = sigmbx_name[0];
+ if (CLI_PRESENT != cli_present("DUMMY_START"))
+ { /* Get the cmd line */
+ if (0 == ((status = lib$get_foreign(&cmd_desc, 0, &cmd_len, 0)) & 1))
+ {
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Unable to read the cmd-line into a string"), status);
+ gtmsource_exit(ABNORMAL_SHUTDOWN);
+ }
+ if (0 == cmd_len)
+ { /* Command issued on the MUPIP command line, we have to build the argument string to pass to child */
+ MEMCPY_LIT(&cmd_str[cmd_len], SOURCE_PROMPT_START_QUAL);
+ cmd_len += STR_LIT_LEN(SOURCE_PROMPT_START_QUAL);
+ if (CLI_PRESENT == cli_present("BUFFSIZE"))
+ {
+ MEMCPY_LIT(&cmd_str[cmd_len], BUFF_QUAL);
+ cmd_len += STR_LIT_LEN(BUFF_QUAL);
+ ptr = i2asc(qwstring, gtmsource_options.buffsize);
+ memcpy(&cmd_str[cmd_len], qwstring, ptr - qwstring);
+ cmd_len += ptr - qwstring;
+ }
+ if (CLI_PRESENT == cli_present("CONNECTPARAMS"))
+ {
+ MEMCPY_LIT(&cmd_str[cmd_len], CONNECT_QUAL);
+ cmd_len += STR_LIT_LEN(CONNECT_QUAL);
+ cmd_str[cmd_len++] = '"'; /* begin quote */
+ for (connect_parms_index = GTMSOURCE_CONN_HARD_TRIES_COUNT;
+ connect_parms_index < GTMSOURCE_CONN_PARMS_COUNT; connect_parms_index++)
+ {
+ ptr = i2asc(qwstring, gtmsource_options.connect_parms[connect_parms_index]);
+ memcpy(&cmd_str[cmd_len], qwstring, ptr - qwstring);
+ cmd_len += ptr - qwstring;
+ cmd_str[cmd_len++] = ','; /* delimiter */
+ }
+ cmd_str[cmd_len - 1] = '"'; /* end quote, overwrite last comma */
+ }
+ if (CLI_PRESENT == cli_present("FILTER"))
+ {
+ MEMCPY_LIT(&cmd_str[cmd_len], FILTER_QUAL);
+ cmd_len += STR_LIT_LEN(FILTER_QUAL);
+ len = strlen(gtmsource_options.filter_cmd);
+ memcpy(&cmd_str[cmd_len], gtmsource_options.filter_cmd, len);
+ cmd_len += len;
+ }
+ if (CLI_PRESENT == cli_present("LOG"))
+ {
+ MEMCPY_LIT(&cmd_str[cmd_len], LOG_QUAL);
+ cmd_len += STR_LIT_LEN(LOG_QUAL);
+ len = strlen(gtmsource_options.log_file);
+ memcpy(&cmd_str[cmd_len], gtmsource_options.log_file, len);
+ cmd_len += len;
+ }
+ if (CLI_PRESENT == cli_present("LOG_INTERVAL"))
+ {
+ MEMCPY_LIT(&cmd_str[cmd_len], LOGINTERVAL_QUAL);
+ cmd_len += STR_LIT_LEN(LOGINTERVAL_QUAL);
+ ptr = i2asc(qwstring, gtmsource_options.src_log_interval);
+ memcpy(&cmd_str[cmd_len], qwstring, ptr - qwstring);
+ cmd_len += ptr - qwstring;
+ }
+ if (CLI_PRESENT == cli_present("PASSIVE"))
+ {
+ MEMCPY_LIT(&cmd_str[cmd_len], PASSIVE_QUAL);
+ cmd_len += STR_LIT_LEN(PASSIVE_QUAL);
+ }
+ if (CLI_PRESENT == cli_present("SECONDARY"))
+ {
+ MEMCPY_LIT(&cmd_str[cmd_len], SECONDARY_QUAL);
+ cmd_len += STR_LIT_LEN(SECONDARY_QUAL);
+ len = strlen(gtmsource_options.secondary_host);
+ memcpy(&cmd_str[cmd_len], gtmsource_options.secondary_host, len);
+ cmd_len += len;
+ MEMCPY_LIT(&cmd_str[cmd_len], ":");
+ cmd_len += 1;
+ ptr = i2asc(qwstring, gtmsource_options.secondary_port);
+ memcpy(&cmd_str[cmd_len], qwstring, ptr - qwstring);
+ cmd_len += ptr - qwstring;
+ }
+ }
+ /* Append a dummy qualifier */
+ MEMCPY_LIT(&cmd_str[cmd_len], DUMMY_START_QUAL);
+ cmd_desc.dsc$w_length = cmd_len + STR_LIT_LEN(DUMMY_START_QUAL);
+ /* Create a mailbox to wait for the source server, tobe spawned off, to get initialized */
+ status = dfntmpmbx(LEN_AND_LIT("LNM$GROUP"));
+ if (SS$_NORMAL != status && SS$_SUPERSEDE != status)
+ {
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Unable to redefine LNM$TEMPORARY_MAILBOX"), status);
+ gtmsource_exit(ABNORMAL_SHUTDOWN);
+ }
+ SET_PRIV((PRV$M_GRPNAM), status);
+ if (SS$_NORMAL != status)
+ {
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Unable to get GRPNAM privilege"), status);
+ gtmsource_exit(ABNORMAL_SHUTDOWN);
+ }
+ status = sys$crembx(0, &signal_channel, 4, 4, 0, PSL$C_USER, &d_signal_mbox);
+ REL_PRIV;
+ if (SS$_NORMAL != status)
+ {
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Unable to create source server init-wait mailbox"), status);
+ gtmsource_exit(ABNORMAL_SHUTDOWN);
+ }
+ status = dfntmpmbx(LEN_AND_LIT("LNM$JOB"));
+ if (SS$_NORMAL != status && SS$_SUPERSEDE != status)
+ {
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Unable to redefine LNM$TEMPORARY_MAILBOX"), status);
+ gtmsource_exit(ABNORMAL_SHUTDOWN);
+ }
+ /* Create detached server and write startup commands to it */
+ if (SS$_NORMAL != repl_create_server(&cmd_desc, "GTMS", "", &cmd_channel, &server_pid, ERR_JNLPOOLSETUP))
+ gtmsource_exit(ABNORMAL_SHUTDOWN);
+ /* Async. read on the mailbox, just borrowing the event flag efn_op_job */
+ status = sys$qio(efn_op_job, signal_channel, IO$_READVBLK, &mbsb[0], 0, 0,
+ &buff, SIZEOF(buff), 0, 0, 0, 0);
+ if (SS$_NORMAL != status)
+ {
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0,
+ ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to read from signal-mbx"), status);
+ retval = ABNORMAL_SHUTDOWN;
+ }
+ /* wait until (server process is alive AND qio-event-flag not set) */
+ while (!retval && (srv_alive = is_proc_alive(server_pid, 0)) &&
+ (SS$_WASCLR == (ef_status = sys$readef(efn_op_job, &clus_flags_stat))))
+ SHORT_SLEEP(GTMSOURCE_WAIT_FOR_SRV_START);
+ if (!retval && !srv_alive)
+ {
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Source server died while startup"));
+ retval = ABNORMAL_SHUTDOWN;
+ }
+ if (!retval && (SS$_WASSET != ef_status))
+ {
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Source server startup completion signalling problem"), ef_status);
+ retval = ABNORMAL_SHUTDOWN;
+ }
+ /* Verify the content read from mailbox */
+ if (!retval && (SERVER_UP != buff))
+ {
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Invalid message read from signalling mbox"));
+ retval = ABNORMAL_SHUTDOWN;
+ }
+ /* Deassign the send-cmd mailbox channel */
+ if (SS$_NORMAL != (status = sys$dassgn(cmd_channel)))
+ {
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Unable to close send-cmd mbox channel"), status);
+ retval = ABNORMAL_SHUTDOWN;
+ }
+ /* Deassign the signalling mailbox channel */
+ if (SS$_NORMAL != (status = sys$dassgn(signal_channel)))
+ {
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Unable to close source server startup mbox channel"), status);
+ retval = ABNORMAL_SHUTDOWN;
+ }
+ gtmsource_exit(retval);
+ }
+ process_id = getpid(); /* pid of the source server */
+ /* Get a meaningful process name */
+ proc_name_desc.dsc$w_length = get_proc_name(LIT_AND_LEN("GTMSRC"), process_id, proc_name);
+ if (SS$_NORMAL != (status = sys$setprn(&proc_name_desc)))
+ {
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Unable to change source server process name"), status);
+ gtmsource_exit(ABNORMAL_SHUTDOWN);
+ }
+ }
+ jnlpool_init(GTMSOURCE, gtmsource_options.start, &jnlpool_inited);
+ /* When gtmsource_options.start is TRUE,
+ * jnlpool_inited == TRUE ==> fresh start, and
+ * jnlpool_inited == FALSE ==> start after a crash
+ */
+ if (!gtmsource_options.start)
+ {
+ if (gtmsource_options.shut_down)
+ gtmsource_exit(gtmsource_shutdown(FALSE, NORMAL_SHUTDOWN) - NORMAL_SHUTDOWN);
+ else if (gtmsource_options.activate)
+ gtmsource_exit(gtmsource_mode_change(GTMSOURCE_MODE_ACTIVE_REQUESTED) - NORMAL_SHUTDOWN);
+ else if (gtmsource_options.deactivate)
+ gtmsource_exit(gtmsource_mode_change(GTMSOURCE_MODE_PASSIVE_REQUESTED) - NORMAL_SHUTDOWN);
+ else if (gtmsource_options.checkhealth)
+ gtmsource_exit(gtmsource_checkhealth() - NORMAL_SHUTDOWN);
+ else if (gtmsource_options.changelog)
+ gtmsource_exit(gtmsource_changelog() - NORMAL_SHUTDOWN);
+ else if (gtmsource_options.showbacklog)
+ gtmsource_exit(gtmsource_showbacklog() - NORMAL_SHUTDOWN);
+ else if (gtmsource_options.stopsourcefilter)
+ gtmsource_exit(gtmsource_stopfilter() - NORMAL_SHUTDOWN);
+ else if (gtmsource_options.update)
+ gtmsource_exit(gtmsource_secnd_update(FALSE) - NORMAL_SHUTDOWN);
+ else
+ gtmsource_exit(gtmsource_statslog() - NORMAL_SHUTDOWN);
+ }
+ assert(gtmsource_options.start);
+ is_src_server = TRUE;
+ strcpy(jnlpool.gtmsource_local->log_file, gtmsource_options.log_file);
+ jnlpool.gtmsource_local->log_interval = log_interval = gtmsource_options.src_log_interval;
+ jnlpool.gtmsource_local->mode = gtmsource_options.mode;
+ if (GTMSOURCE_MODE_ACTIVE == gtmsource_options.mode)
+ {
+ jnlpool.gtmsource_local->connect_parms[GTMSOURCE_CONN_HARD_TRIES_COUNT] =
+ gtmsource_options.connect_parms[GTMSOURCE_CONN_HARD_TRIES_COUNT];
+ jnlpool.gtmsource_local->connect_parms[GTMSOURCE_CONN_HARD_TRIES_PERIOD] =
+ gtmsource_options.connect_parms[GTMSOURCE_CONN_HARD_TRIES_PERIOD];
+ jnlpool.gtmsource_local->connect_parms[GTMSOURCE_CONN_SOFT_TRIES_PERIOD] =
+ gtmsource_options.connect_parms[GTMSOURCE_CONN_SOFT_TRIES_PERIOD];
+ jnlpool.gtmsource_local->connect_parms[GTMSOURCE_CONN_ALERT_PERIOD] =
+ gtmsource_options.connect_parms[GTMSOURCE_CONN_ALERT_PERIOD];
+ jnlpool.gtmsource_local->connect_parms[GTMSOURCE_CONN_HEARTBEAT_PERIOD] =
+ gtmsource_options.connect_parms[GTMSOURCE_CONN_HEARTBEAT_PERIOD];
+ jnlpool.gtmsource_local->connect_parms[GTMSOURCE_CONN_HEARTBEAT_MAX_WAIT] =
+ gtmsource_options.connect_parms[GTMSOURCE_CONN_HEARTBEAT_MAX_WAIT];
+ }
+ util_log_open(STR_AND_LEN(gtmsource_options.log_file));
+ /* If previous shutdown did not complete successfully and jnlpool was left lying around, do not proceed */
+ if (!jnlpool_inited && NO_SHUTDOWN != jnlpool.gtmsource_local->shutdown)
+ {
+ sgtm_putmsg(print_msg, VARLSTCNT(4) ERR_REPLINFO, 2,
+ RTS_ERROR_LITERAL("Previous source server did not complete shutdown. Resetting shutdown related fields\n"));
+ repl_log(gtmsource_log_fp, TRUE, TRUE, print_msg);
+ jnlpool.gtmsource_local->shutdown = NO_SHUTDOWN;
+ }
+ REPL_DPRINT1("Setting up regions\n");
+ gvinit();
+
+ /* We use the same code dse uses to open all regions but we must make sure
+ * they are all open before proceeding.
+ */
+ all_files_open = region_init(FALSE);
+ if (!all_files_open)
+ {
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOTALLDBOPN);
+ gtmsource_autoshutdown();
+ }
+ /* Determine primary side null subscripts collation order */
+ /* Also check whether all regions have same null collation order */
+ primary_side_std_null_coll = -1;
+ for (reg = gd_header->regions, region_top = gd_header->regions + gd_header->n_regions; reg < region_top; reg++)
+ {
+ csa = &FILE_INFO(reg)->s_addrs;
+ if (primary_side_std_null_coll != csa->hdr->std_null_coll)
+ {
+ if (-1 == primary_side_std_null_coll)
+ primary_side_std_null_coll = csa->hdr->std_null_coll;
+ else
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NULLCOLLDIFF);
+ }
+ }
+ primary_side_trigger_support = FALSE;
+ EXIT_IF_REPLOFF_JNLON(gd_header);
+ if (jnlpool_inited)
+ gtmsource_seqno_init();
+ jnlpool.gtmsource_local->gtmsource_pid = process_id;
+ rel_sem_immediate(SOURCE, SRC_SERV_OPTIONS_SEM);
+ rel_sem_immediate(SOURCE, JNL_POOL_ACCESS_SEM);
+ /* Indicate the start up completion to the parent mupip process through a mail box */
+ status = dfntmpmbx(LEN_AND_LIT("LNM$GROUP"));
+ if (SS$_NORMAL != status && SS$_SUPERSEDE != status)
+ {
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Unable to redefine LNM$TEMPORARY_MAILBOX"), status);
+ gtmsource_exit(ABNORMAL_SHUTDOWN);
+ }
+ SET_PRIV((PRV$M_GRPNAM), status);
+ status = sys$crembx(0, &signal_channel, 4, 4, 0, PSL$C_USER, &d_signal_mbox);
+ REL_PRIV;
+ if (SS$_NORMAL != status)
+ {
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Unable to create source server init-wait mailbox"), status);
+ gtmsource_exit(ABNORMAL_SHUTDOWN);
+ }
+ status = dfntmpmbx(LEN_AND_LIT("LNM$JOB"));
+ if (SS$_NORMAL != status && SS$_SUPERSEDE != status)
+ {
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Unable to redefine LNM$TEMPORARY_MAILBOX"), status);
+ gtmsource_exit(ABNORMAL_SHUTDOWN);
+ }
+ buff = SERVER_UP;
+ status = sys$qiow(EFN$C_ENF, signal_channel, IO$_WRITEVBLK | IO$M_NOW, &mbsb[0], 0, 0, &buff, SIZEOF(buff), 0, 0, 0, 0);
+ if (SS$_NORMAL != status)
+ {
+ if (SS$_NORMAL != (status = sys$dassgn(signal_channel)))
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Unable to close source server startup mbox channel (child)"), status);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Unable to write start-up completion in the source server startup mbox (child)"),
+ status);
+ gtmsource_exit(ABNORMAL_SHUTDOWN);
+ }
+ if (SS$_NORMAL != (status = sys$dassgn(signal_channel)))
+ {
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Unable to close source server startup mbox channel (child)"), status);
+ gtmsource_exit(ABNORMAL_SHUTDOWN);
+ }
+ gtmsource_srv_count++;
+ gtmsource_secnd_update(TRUE);
+ region_top = gd_header->regions + gd_header->n_regions;
+ for (reg = gd_header->regions; reg < region_top; reg++)
+ {
+ if (reg->read_only && REPL_ALLOWED(&FILE_INFO(reg)->s_addrs))
+ {
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Source Server does not have write permissions to one or "
+ "more database files that are replicated"));
+ gtmsource_autoshutdown();
+ }
+ }
+ gtm_event_log_init();
+ if (jnlpool_inited)
+ sgtm_putmsg(print_msg, VARLSTCNT(4) ERR_REPLINFO, 2,
+ RTS_ERROR_LITERAL("GTM Replication Source Server : Fresh Start"));
+ else
+ sgtm_putmsg(print_msg, VARLSTCNT(4) ERR_REPLINFO, 2,
+ RTS_ERROR_LITERAL("GTM Replication Source Server : Crash Restart"));
+ repl_log(gtmsource_log_fp, TRUE, TRUE, print_msg);
+ gtm_event_log(GTM_EVENT_LOG_ARGC, "MUPIP", "REPLINFO", print_msg);
+ jnl_ver = JNL_VER_THIS;
+ 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_START;
+ while (jnlpool.gtmsource_local->mode == GTMSOURCE_MODE_PASSIVE
+ && jnlpool.gtmsource_local->shutdown == NO_SHUTDOWN)
+ SHORT_SLEEP(GTMSOURCE_WAIT_FOR_MODE_CHANGE)
+ ;
+ if (GTMSOURCE_MODE_PASSIVE == jnlpool.gtmsource_local->mode)
+ { /* Shutdown initiated */
+ assert(jnlpool.gtmsource_local->shutdown == SHUTDOWN);
+ sgtm_putmsg(print_msg, VARLSTCNT(4) ERR_REPLINFO, 2,
+ RTS_ERROR_LITERAL("GTM Replication Source Server Shutdown signalled"));
+ repl_log(gtmsource_log_fp, TRUE, TRUE, print_msg);
+ gtm_event_log(GTM_EVENT_LOG_ARGC, "MUPIP", "REPLINFO", print_msg);
+ break;
+ }
+ gtmsource_poll_actions(FALSE);
+ if (GTMSOURCE_CHANGING_MODE == gtmsource_state)
+ continue;
+ if (GTMSOURCE_MODE_ACTIVE_REQUESTED == jnlpool.gtmsource_local->mode)
+ jnlpool.gtmsource_local->mode = GTMSOURCE_MODE_ACTIVE;
+ sgtm_putmsg(print_msg, VARLSTCNT(4) ERR_REPLINFO, 2,
+ RTS_ERROR_LITERAL("GTM Replication Source Server now in ACTIVE mode"));
+ repl_log(gtmsource_log_fp, TRUE, TRUE, print_msg);
+ gtm_event_log(GTM_EVENT_LOG_ARGC, "MUPIP", "REPLINFO", print_msg);
+ if (SS_NORMAL != (status = gtmsource_alloc_tcombuff()))
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Error allocating initial tcom buffer space. Malloc error"), status);
+ gtmsource_filter = NO_FILTER;
+ if ('\0' != jnlpool.gtmsource_local->filter_cmd[0])
+ {
+ if (SS_NORMAL == (status = repl_filter_init(jnlpool.gtmsource_local->filter_cmd)))
+ gtmsource_filter |= EXTERNAL_FILTER;
+ else
+ {
+ if (EREPL_FILTERSTART_EXEC == repl_errno)
+ gtmsource_exit(ABNORMAL_SHUTDOWN);
+ }
+ }
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK);
+ QWASSIGN(resync_seqno, seq_num_zero);
+ for (reg = gd_header->regions, region_top = gd_header->regions + gd_header->n_regions; reg < region_top; reg++)
+ {
+ assert(reg->open);
+ csa = &FILE_INFO(reg)->s_addrs;
+ if (REPL_ALLOWED(csa->hdr))
+ {
+ if (QWLT(resync_seqno, csa->hdr->resync_seqno))
+ QWASSIGN(resync_seqno, csa->hdr->resync_seqno);
+ }
+ }
+ if (QWGT(jnlpool.gtmsource_local->read_jnl_seqno, resync_seqno)) /* source server terminated before it */
+ QWASSIGN(resync_seqno, jnlpool.gtmsource_local->read_jnl_seqno); /* set resync_seqno in the file headers */
+ QWASSIGN(jnlpool.gtmsource_local->read_jnl_seqno, resync_seqno);
+ QWASSIGN(jnlpool.gtmsource_local->read_addr, jnlpool.jnlpool_ctl->write_addr);
+ jnlpool.gtmsource_local->read = jnlpool.jnlpool_ctl->write;
+ jnlpool.gtmsource_local->read_state = READ_POOL;
+ if (QWLT(jnlpool.gtmsource_local->read_jnl_seqno, jnlpool.jnlpool_ctl->jnl_seqno))
+ {
+ jnlpool.gtmsource_local->read_state = READ_FILE;
+ QWASSIGN(gtmsource_save_read_jnl_seqno, jnlpool.jnlpool_ctl->jnl_seqno);
+ gtmsource_pool2file_transition = TRUE; /* so that we read the latest gener jnl files */
+ }
+ rel_lock(jnlpool.jnlpool_dummy_reg);
+ gtmsource_process();
+ /* gtmsource_process returns only when mode needs to be changed to PASSIVE */
+ assert(gtmsource_state == GTMSOURCE_CHANGING_MODE);
+ gtmsource_ctl_close();
+ gtmsource_free_msgbuff();
+ gtmsource_free_tcombuff();
+ gtmsource_free_filter_buff();
+ gtmsource_stop_heartbeat();
+ if (FD_INVALID != gtmsource_sock_fd)
+ repl_close(>msource_sock_fd);
+ if (gtmsource_filter & EXTERNAL_FILTER)
+ repl_stop_filter();
+ } while (TRUE);
+ gtmsource_end();
+ return(SS_NORMAL);
+}
diff --git a/sr_vvms/gtmsource.h b/sr_vvms/gtmsource.h
new file mode 100644
index 0000000..c96f5ba
--- /dev/null
+++ b/sr_vvms/gtmsource.h
@@ -0,0 +1,410 @@
+/****************************************************************
+ * *
+ * Copyright 2006, 2013 Fidelity Information Services, Inc.*
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef GTMSOURCE_H
+#define GTMSOURCE_H
+
+/* for in_addr_t typedef on Linux */
+#include "gtm_inet.h"
+#include "gtm_ipv6.h"
+#include <gtm_socket.h>
+
+/* Needs mdef.h, gdsfhead.h and its dependencies */
+#define JNLPOOL_DUMMY_REG_NAME "JNLPOOL_REG"
+#define MAX_FILTER_CMD_LEN 512
+#define MIN_JNLPOOL_SIZE (1 * 1024 * 1024)
+
+#ifdef VMS
+#define MAX_GSEC_KEY_LEN 32 /* 31 is allowed + 1 for NULL terminator */
+#endif
+
+enum
+{
+ READ_POOL,
+ READ_FILE
+};
+
+enum
+{
+ GTMSOURCE_MODE_PASSIVE,
+ GTMSOURCE_MODE_ACTIVE,
+ GTMSOURCE_MODE_PASSIVE_REQUESTED,
+ GTMSOURCE_MODE_ACTIVE_REQUESTED
+};
+
+#define SRV_ALIVE 0x0
+#define SRV_DEAD 0x1
+#define SRV_ERR 0x2
+
+typedef enum
+{
+ GTMSOURCE_DUMMY_STATE = 0,
+ GTMSOURCE_START,
+ GTMSOURCE_WAITING_FOR_CONNECTION,
+ GTMSOURCE_WAITING_FOR_RESTART,
+ GTMSOURCE_SEARCHING_FOR_RESTART,
+ GTMSOURCE_SENDING_JNLRECS,
+ GTMSOURCE_WAITING_FOR_XON,
+ GTMSOURCE_CHANGING_MODE
+} gtmsource_state_t;
+
+#define GTMSOURCE_WAIT_FOR_RECEIVER_TO_QUIT 5 /* seconds */
+#define GTMSOURCE_WAIT_FOR_RECEIVER_CLOSE_CONN (1000 - 1) /* ms */
+#define GTMSOURCE_WAIT_FOR_JNLOPEN 10 /* ms */
+#define GTMSOURCE_WAIT_FOR_JNL_RECS 1 /* ms */
+#define GTMSOURCE_WAIT_FOR_SRV_START 10 /* ms */
+#define GTMSOURCE_WAIT_FOR_MODE_CHANGE (1000 - 1) /* ms, almost 1 s */
+#define GTMSOURCE_WAIT_FOR_SHUTDOWN (1000 - 1) /* ms, almost 1 s */
+#define GTMSOURCE_WAIT_FOR_SOURCESTART (1000 - 1) /* ms */
+
+#define GTMSOURCE_SHUTDOWN_PAD_TIME 5 /* seconds */
+
+#define GTMSOURCE_SENT_THRESHOLD_FOR_RECV (1 * 1024 * 1024)
+#define BACKLOG_BYTES_THRESHOLD (1 * 1024 * 1024)
+#define BACKLOG_COUNT_THRESHOLD (10 * 1024)
+
+#define GTMSOURCE_MIN_TCP_SEND_BUFSIZE (16 * 1024) /* anything less than this, issue a warning */
+#define GTMSOURCE_TCP_SEND_BUFSIZE_INCR (32 * 1024) /* attempt to get a larger buffer with this increment */
+#define GTMSOURCE_TCP_SEND_BUFSIZE (1024 * 1024) /* desirable to set the buffer size to be able to send large chunks */
+#define GTMSOURCE_MIN_TCP_RECV_BUFSIZE (512) /* anything less than this, issue a warning */
+#define GTMSOURCE_TCP_RECV_BUFSIZE (1024) /* not much inbound traffic, we can live with a low limit */
+
+#define GTMSOURCE_FH_FLUSH_INTERVAL 60 /* seconds, if required, flush file header(s) every these many seconds */
+
+typedef struct
+{ /* IMPORTANT : all fields that are used by the source server reading from pool logic must be defined VOLATILE to avoid compiler
+ * optimization, forcing fresh load on every access */
+ replpool_identifier jnlpool_id;
+ seq_num start_jnl_seqno; /* The sequence number with which operations started */
+ volatile seq_num jnl_seqno; /* Sequence number for transactions. Updated by GTM process */
+ uint4 jnldata_base_off; /* Journal pool offset from where journal data starts */
+ uint4 jnlpool_size; /* Available space for journal data in bytes */
+ uint4 write; /* Relative offset from jnldata_base_off for the next journal record to
+ * be written. Updated by GTM process. */
+ volatile uint4 lastwrite_len; /* The length of the last transaction written into the journal pool.
+ * Copied to jnldata_hdr.prev_jnldata_len before writing into the pool.
+ * Updated by GTM process. */
+ volatile qw_off_t early_write_addr; /* Virtual address assuming the to-be-written jnl records are already
+ * written into the journal pool. Is equal to write_addr except in the
+ * window when the actual write takes place. */
+ volatile qw_off_t write_addr; /* Virtual address of the next journal record to be written in the merged
+ * journal file. Note that the merged journal may not exist.
+ * Updated by GTM process */
+ boolean_t upd_disabled; /* Identify whether updates are disabled or not on the secondary */
+ volatile jnl_tm_t prev_jnlseqno_time; /* To ensure that time never decreases across successive jnl records
+ * across ALL replicated regions attached to this journal pool.
+ */
+} jnlpool_ctl_struct;
+
+#if defined(__osf__) && defined(__alpha)
+# pragma pointer_size(save)
+# pragma pointer_size(long)
+#endif
+
+typedef jnlpool_ctl_struct *jnlpool_ctl_ptr_t;
+
+#if defined(__osf__) && defined(__alpha)
+# pragma pointer_size(restore)
+#endif
+
+/*
+ * When a GTM process writes journal data into the journal pool, it uses the
+ * following layout at location write
+ *
+ * struct jnlpool_trans_struct
+ * {
+ * jnldata_hdr_struct jnldata_hdr; - jnldata_hdr.jnldata_len
+ * is the length of journal
+ * data of a transaction
+ * uchar jnldata[jnldata_len]; - transaction journal
+ * data
+ * };
+ */
+
+/********************** VERY IMPORTANT ********************************
+ * Keep SIZEOF(jnldata_hdr_struct) == ~JNL_WRT_END_MASK + 1 and
+ * jnlpool_size should be a multiple of (~JNL_WRT_END_MASK + 1).
+ * This is to avoid jnldata_hdr_struct from wrapping, so that fields
+ * remain contiguous.
+ **********************************************************************/
+typedef struct
+{
+ uint4 jnldata_len; /* length of the journal data of a
+ * a transaction in bytes */
+ uint4 prev_jnldata_len; /* length of the journal data of
+ * the previous transaction in the
+ * journal pool (in bytes) */
+} jnldata_hdr_struct;
+
+#if defined(__osf__) && defined(__alpha)
+# pragma pointer_size(save)
+# pragma pointer_size(long)
+#endif
+
+typedef jnldata_hdr_struct *jnldata_hdr_ptr_t;
+
+#if defined(__osf__) && defined(__alpha)
+# pragma pointer_size(restore)
+#endif
+
+#define REPL_CONN_HARD_TRIES_COUNT 5 /* Default number of connection hard tries */
+#define REPL_CONN_HARD_TRIES_PERIOD 500 /* msec Default connection hard try period */
+#define REPL_CONN_SOFT_TRIES_PERIOD 5 /* sec Default connection soft try period*/
+#define REPL_CONN_ALERT_ALERT_PERIOD 30 /* sec Default alert period*/
+#define REPL_CONN_HEARTBEAT_PERIOD 15 /* sec Default heartbeat period */
+#define REPL_CONN_HEARTBEAT_MAX_WAIT 60 /* sec Default heartbeat maximum waiting period */
+#define REPL_MAX_CONN_HARD_TRIES_PERIOD 1000 /* ms */
+
+#define REPL_MAX_LOG_PERIOD 150 /*sec Maximum logging period */
+
+enum
+{
+ GTMSOURCE_CONN_HARD_TRIES_COUNT = 0,
+ GTMSOURCE_CONN_HARD_TRIES_PERIOD,
+ GTMSOURCE_CONN_SOFT_TRIES_PERIOD,
+ GTMSOURCE_CONN_ALERT_PERIOD,
+ GTMSOURCE_CONN_HEARTBEAT_PERIOD,
+ GTMSOURCE_CONN_HEARTBEAT_MAX_WAIT,
+ GTMSOURCE_CONN_PARMS_COUNT
+};
+
+#define GTMSOURCE_CONN_PARMS_DELIM ","
+#define JNLPOOL_SEGMENT 'J'
+
+/*
+ * The following structure contains data items local to the Source Server.
+ * It is maintained in the journal pool to provide for persistence across
+ * instantiations of the Source Server (due to crashes).
+ */
+typedef struct
+{
+ uint4 gtmsource_pid; /* Process identification of source server */
+ int4 filler1; /* Keep read_addr 8-byte aligned */
+
+ /* Control fields */
+ qw_off_t read_addr; /* Virtual address of the next journal record in the merged journal file to read */
+ seq_num read_jnl_seqno; /* Next jnl_seqno to be read */
+ uint4 read; /* Offset relative to jnldata_base_off of the next journal record from the journal pool */
+ int4 read_state; /* From where to read - pool or the file(s)? */
+ int4 mode; /* Active, or Passive */
+ int4 lastsent_time; /* Currently unused, Vinaya 2005/02/08 */
+ seq_num lastsent_jnl_seqno; /* Currently unsued, Vinaya 2005/02/08 */
+
+ /* Data items used in communicating action qualifiers (show statistics, shutdown, etc) and qualifier values
+ * (log file, shutdown time, the identity of the secondary system, etc).
+ */
+
+ uint4 statslog; /* Boolean - detailed log on/off? */
+ uint4 shutdown; /* Use to communicate shutdown related values */
+ int4 shutdown_time; /* Time allowed for shutdown in seconds */
+ uint4 filler4; /* Keep secondary_inet_addr aligned */
+ union gtm_sockaddr_in46 secondary_inet_addr; /* IP address of the secondary */
+ int secondary_af; /* address family of the seconary */
+ int secondary_addrlen; /* length of the secondary address */
+ uint4 secondary_port; /* Port at which Receiver is listening */
+ uint4 changelog; /* change the log file or log interval */
+ uint4 log_interval; /* seqno count interval at which source server prints messages about replic traffic */
+ uint4 filler2; /* make gtmsource_local_struct size multiple of 8 bytes */
+ int4 connect_parms[GTMSOURCE_CONN_PARMS_COUNT]; /* Connect failure tries parms. Add fillers (if necessary)
+ * based on GTMSOURCE_CONN_PARMS_COUNT */
+ uint4 filler3; /* extra space after connect_parms */
+ char secondary_host[MAX_HOST_NAME_LEN];
+ char filter_cmd[MAX_FILTER_CMD_LEN];
+ char log_file[MAX_FN_LEN + 1];
+ char statslog_file[MAX_FN_LEN + 1];
+} gtmsource_local_struct;
+
+#if defined(__osf__) && defined(__alpha)
+# pragma pointer_size(save)
+# pragma pointer_size(long)
+#endif
+
+typedef gtmsource_local_struct *gtmsource_local_ptr_t;
+
+#if defined(__osf__) && defined(__alpha)
+# pragma pointer_size(restore)
+#endif
+
+/*
+ * Journal pool shared memory layout -
+ *
+ * jnlpool_ctl_struct
+ * mutex structure (mutex_struct) [JNLPOOL lock control]
+ * NUM_CRIT_ENTRY * mutex_que_entry [JNLPOOL lock control]
+ * mutex spin parms structure (mutex_spin_parms_struct) [JNLPOOL lock control]
+ * node local structure (node_local) [JNLPOOL lock control]
+ * gtmsource_local_struct
+ * zero or more jnlpool_trans_struct
+ */
+
+/*
+ * Push the jnldata_base_off to be aligned
+ * to (~JNL_WRT_END_MASK + 1)-byte boundary
+ */
+
+#define JNLPOOL_CTL_SIZE ROUND_UP(SIZEOF(jnlpool_ctl_struct), CACHELINE_SIZE) /* align crit semaphore at cache line */
+#define JNLDATA_BASE_OFF ((JNLPOOL_CTL_SIZE +\
+ JNLPOOL_CRIT_SPACE +\
+ SIZEOF(mutex_spin_parms_struct) +\
+ SIZEOF(node_local) +\
+ SIZEOF(gtmsource_local_struct) +\
+ ~JNL_WRT_END_MASK) & JNL_WRT_END_MASK)
+#ifdef VMS
+typedef struct
+{
+ char name[MAX_GSEC_KEY_LEN];
+ struct dsc$descriptor_s desc;
+} t_vms_shm_key;
+#endif
+
+typedef struct
+{
+ jnlpool_ctl_ptr_t jnlpool_ctl;
+ gd_region *jnlpool_dummy_reg; /* some functions need gd_region */
+ gtmsource_local_ptr_t gtmsource_local;
+ sm_uc_ptr_t jnldata_base;
+#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)
+# pragma pointer_size(save)
+# pragma pointer_size(long)
+#endif
+
+typedef jnlpool_addrs *jnlpool_addrs_ptr_t;
+
+#if defined(__osf__) && defined(__alpha)
+# pragma pointer_size(restore)
+#endif
+
+typedef enum
+{
+ GTMPROC,
+ GTMSOURCE
+} jnlpool_user;
+
+typedef struct
+{
+ boolean_t start;
+ boolean_t shut_down;
+ boolean_t activate;
+ boolean_t deactivate;
+ boolean_t checkhealth;
+ boolean_t statslog;
+ boolean_t showbacklog;
+ boolean_t changelog;
+ boolean_t stopsourcefilter;
+ boolean_t update; /* A new qualifier for updates on secondary */
+ int4 shutdown_time;
+ int4 buffsize;
+ int4 mode;
+ int4 secondary_port;
+ uint4 src_log_interval;
+ int4 connect_parms[GTMSOURCE_CONN_PARMS_COUNT];
+ char filter_cmd[MAX_FILTER_CMD_LEN];
+ char secondary_host[MAX_HOST_NAME_LEN];
+ char log_file[MAX_FN_LEN + 1];
+} gtmsource_options_t;
+
+#define EXIT_IF_REPLOFF_JNLON(gd_header) \
+ region_top = gd_header->regions + gd_header->n_regions; \
+ for (reg = gd_header->regions; reg < region_top; reg++) \
+ { \
+ csa = &FILE_INFO(reg)->s_addrs; \
+ if (!REPL_ALLOWED(csa) && JNL_ALLOWED(csa)) \
+ { \
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_REPLOFFJNLON, 2, DB_LEN_STR(reg)); \
+ gtmsource_autoshutdown(); \
+ } \
+ }
+
+#define UPDATE_RESYNC_SEQNO(REGION, pre_update, post_update) \
+{ /* modifies csa, was_crit; uses pre_update, post_update */ \
+ csa = &FILE_INFO(REGION)->s_addrs; \
+ if (REPL_ALLOWED(csa->hdr)) \
+ { /* Although csa->hdr->resync_seqno is only modified by the source \
+ * server and never concurrently, it is accessed by fileheader_sync() which \
+ * does it while in crit. To avoid the latter from reading an inconsistent \
+ * value (i.e. neither the pre-update nor the post-update value), which is \
+ * possible if the 8-byte operation is not atomic but a sequence of two \
+ * 4-byte operations AND if the pre-update and post-update value differ in \
+ * their most significant 4-bytes, we grab crit. \
+ * \
+ * For native INT8 platforms, we expect the compiler to optimize the "if" away. \
+ * \
+ * Note: the ordering of operands in the below if check is the way it is because \
+ * a. the more frequent case is QWCHANGE_IS_READER_CONSISTENT returning TRUE. \
+ * b. source server does not hold crit coming here (but we are covering the case \
+ * when it may) \
+ */ \
+ if (!QWCHANGE_IS_READER_CONSISTENT(pre_update, post_update) \
+ && FALSE == (was_crit = csa->now_crit)) \
+ grab_crit(REGION); \
+ FILE_INFO(REGION)->s_addrs.hdr->resync_seqno = post_update; \
+ if (!QWCHANGE_IS_READER_CONSISTENT(pre_update, post_update) \
+ && FALSE == was_crit) \
+ rel_crit(REGION); \
+ } \
+}
+
+/********** Source server function prototypes **********/
+int gtmsource(void);
+boolean_t gtmsource_is_heartbeat_overdue(time_t *now, repl_heartbeat_msg_t *overdue_heartbeat);
+int gtmsource_alloc_filter_buff(int bufsiz);
+int gtmsource_alloc_msgbuff(int maxbuffsize);
+int gtmsource_alloc_tcombuff(void);
+void gtmsource_free_filter_buff(void);
+void gtmsource_free_msgbuff(void);
+void gtmsource_free_tcombuff(void);
+int gtmsource_changelog(void);
+int gtmsource_checkhealth(void);
+int gtmsource_comm_init(void);
+int gtmsource_ctl_close(void);
+int gtmsource_ctl_init(void);
+int gtmsource_end1(boolean_t auto_shutdown);
+int gtmsource_est_conn(void);
+int gtmsource_get_jnlrecs(uchar_ptr_t buff, int *data_len, int maxbufflen, boolean_t read_multiple);
+int gtmsource_get_opt(void);
+int gtmsource_ipc_cleanup(boolean_t auto_shutdown, int *exit_status);
+int gtmsource_mode_change(int to_mode);
+int gtmsource_poll_actions(boolean_t poll_secondary);
+int gtmsource_process(void);
+int gtmsource_readfiles(uchar_ptr_t buff, int *data_len, int maxbufflen, boolean_t read_multiple);
+int gtmsource_readpool(uchar_ptr_t buff, int *data_len, int maxbufflen, boolean_t read_multiple, qw_num stop_read_at);
+int gtmsource_recv_restart(seq_num *recvd_jnl_seqno, int *msg_type, int *start_flags);
+int gtmsource_secnd_update(boolean_t print_message);
+int gtmsource_set_lookback(void);
+int gtmsource_showbacklog(void);
+int gtmsource_shutdown(boolean_t auto_shutdown, int exit_status);
+int gtmsource_srch_restart(seq_num recvd_jnl_seqno, int recvd_start_flags);
+int gtmsource_statslog(void);
+int gtmsource_stopfilter(void);
+int gtmsource_update_resync_tn(seq_num resync_seqno);
+void gtmsource_autoshutdown(void);
+void gtmsource_end(void);
+void gtmsource_exit(int exit_status);
+void gtmsource_seqno_init(void);
+void gtmsource_sigstop(void);
+boolean_t jnlpool_hasnt_overflowed(jnlpool_ctl_ptr_t jctl, uint4 jnlpool_size, qw_num read_addr);
+void jnlpool_detach(void);
+void jnlpool_init(jnlpool_user pool_user, boolean_t gtmsource_startup, boolean_t *jnlpool_initialized);
+int gtmsource_init_heartbeat(void);
+int gtmsource_process_heartbeat(repl_heartbeat_msg_t *heartbeat_msg);
+int gtmsource_send_heartbeat(time_t *now);
+int gtmsource_stop_heartbeat(void);
+void gtmsource_flush_fh(seq_num resync_seqno);
+void gtmsource_reinit_logseqno(void);
+
+#endif /* GTMSOURCE_H */
diff --git a/sr_vvms/gtmsource_changelog.c b/sr_vvms/gtmsource_changelog.c
new file mode 100644
index 0000000..7858d0f
--- /dev/null
+++ b/sr_vvms/gtmsource_changelog.c
@@ -0,0 +1,85 @@
+/****************************************************************
+ * *
+ * Copyright 2006 Fidelity Information Services, Inc.*
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_time.h"
+#include "gtm_string.h"
+#include "gtm_inet.h" /* Required for gtmsource.h */
+#include <errno.h>
+#ifdef VMS
+#include <descrip.h> /* Required for gtmsource.h */
+#endif
+
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "repl_shutdcode.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "repl_msg.h"
+#include "gtmsource.h"
+#include "repl_dbg.h"
+#include "repl_sem.h"
+#include "util.h"
+#include "repl_log.h"
+
+GBLREF jnlpool_addrs jnlpool;
+GBLREF gtmsource_options_t gtmsource_options;
+
+int gtmsource_changelog(void)
+{
+ uint4 changelog_desired = 0, changelog_accepted = 0;
+
+ if (0 > grab_sem(SOURCE, SRC_SERV_OPTIONS_SEM))
+ {
+ util_out_print("Error grabbing jnlpool option write lock. Could not initiate change log", TRUE);
+ return (ABNORMAL_SHUTDOWN);
+ }
+ if (0 != jnlpool.gtmsource_local->changelog)
+ {
+ util_out_print("Change log is already in progress. Not initiating change in log file or log interval", TRUE);
+ rel_sem(SOURCE, SRC_SERV_OPTIONS_SEM);
+ return (ABNORMAL_SHUTDOWN);
+ }
+ if ('\0' != gtmsource_options.log_file[0]) /* trigger change in log file */
+ {
+ changelog_desired |= REPLIC_CHANGE_LOGFILE;
+ if (0 != strcmp(jnlpool.gtmsource_local->log_file, gtmsource_options.log_file))
+ {
+ changelog_accepted |= REPLIC_CHANGE_LOGFILE;
+ strcpy(jnlpool.gtmsource_local->log_file, gtmsource_options.log_file);
+ util_out_print("Change log initiated with file !AD", TRUE, LEN_AND_STR(gtmsource_options.log_file));
+ } else
+ util_out_print("Log file is already !AD. Not initiating change in log file", TRUE,
+ LEN_AND_STR(gtmsource_options.log_file));
+ }
+ if (0 != gtmsource_options.src_log_interval) /* trigger change in log interval */
+ {
+ changelog_desired |= REPLIC_CHANGE_LOGINTERVAL;
+ if (gtmsource_options.src_log_interval != jnlpool.gtmsource_local->log_interval)
+ {
+ changelog_accepted |= REPLIC_CHANGE_LOGINTERVAL;
+ jnlpool.gtmsource_local->log_interval = gtmsource_options.src_log_interval;
+ util_out_print("Change log initiated with interval !UL", TRUE, gtmsource_options.src_log_interval);
+ } else
+ util_out_print("Log interval is already !UL. Not initiating change in log interval", TRUE,
+ gtmsource_options.src_log_interval);
+ }
+ if (0 != changelog_accepted)
+ jnlpool.gtmsource_local->changelog = changelog_accepted;
+ else
+ util_out_print("No change to log file or log interval", TRUE);
+ rel_sem(SOURCE, SRC_SERV_OPTIONS_SEM);
+ return ((0 != changelog_accepted && changelog_accepted == changelog_desired) ? NORMAL_SHUTDOWN : ABNORMAL_SHUTDOWN);
+}
diff --git a/sr_vvms/gtmsource_checkhealth.c b/sr_vvms/gtmsource_checkhealth.c
new file mode 100644
index 0000000..5a801d8
--- /dev/null
+++ b/sr_vvms/gtmsource_checkhealth.c
@@ -0,0 +1,134 @@
+/****************************************************************
+ * *
+ * Copyright 2006, 2007 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <sys/time.h>
+#include <errno.h>
+#include "gtm_inet.h" /* Required for gtmsource.h */
+#include "gtm_string.h"
+#ifdef UNIX
+#include <sys/sem.h>
+#endif
+#ifdef VMS
+#include <descrip.h> /* Required for gtmsource.h */
+#endif
+
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "jnl.h"
+#include "repl_msg.h"
+#include "gtmsource.h"
+#include "repl_dbg.h"
+#include "gtm_stdio.h"
+#include "repl_shutdcode.h"
+#include "repl_sem.h"
+#include "repl_sp.h"
+#include "repl_log.h"
+#include "is_proc_alive.h"
+#include "gtmmsg.h"
+#include "sgtm_putmsg.h"
+#include "util.h"
+
+GBLREF jnlpool_addrs jnlpool;
+GBLREF gtmsource_options_t gtmsource_options;
+GBLREF gd_addr *gd_header;
+
+int gtmsource_checkhealth(void)
+{
+ uint4 gtmsource_pid;
+ int status, semval;
+ boolean_t srv_alive, all_files_open;
+ seq_num reg_seqno, jnlseqno;
+ gd_region *reg, *region_top;
+ sgmnt_addrs *csa;
+ sgmnt_data_ptr_t csd;
+ char errtxt[OUT_BUFF_SIZE];
+
+ error_def(ERR_NOTALLDBOPN);
+ error_def(ERR_REPLJNLCLOSED);
+
+ REPL_DPRINT1("Checking health of Source Server\n");
+
+ /* Grab the jnlpool option write lock */
+ if (0 > grab_sem(SOURCE, SRC_SERV_OPTIONS_SEM))
+ {
+ repl_log(stderr, FALSE, TRUE,
+ "Error grabbing jnlpool option write lock : %s. Could not check health of Source Server\n",
+ REPL_SEM_ERROR);
+ return (SRV_ERR + NORMAL_SHUTDOWN);
+ }
+
+ gtmsource_pid = jnlpool.gtmsource_local->gtmsource_pid;
+ if (0 < gtmsource_pid)
+ {
+ if (srv_alive = is_proc_alive(gtmsource_pid, 0))
+ semval = get_sem_info(SOURCE, SRC_SERV_COUNT_SEM, SEM_INFO_VAL);
+ if (srv_alive && 1 == semval)
+ {
+ repl_log(stderr, FALSE, TRUE, FORMAT_STR, gtmsource_pid, "Source server", "");
+ status = SRV_ALIVE;
+ } else if (!srv_alive || 0 == semval)
+ {
+ repl_log(stderr, FALSE, TRUE, FORMAT_STR, gtmsource_pid, "Source server", " NOT");
+ if (srv_alive)
+ repl_log(stderr, FALSE, TRUE, "Another process exists with same pid");
+ status = SRV_DEAD;
+ } else
+ {
+ repl_log(stderr, FALSE, TRUE,
+ "Error in source server semval : %s. Could not check health of Source Server\n", REPL_SEM_ERROR);
+ status = SRV_ERR;
+ }
+ } else
+ {
+ if (NO_SHUTDOWN == jnlpool.gtmsource_local->shutdown)
+ repl_log(stderr, FALSE, TRUE, "Source Server crashed during journal pool initialization\n");
+ else
+ repl_log(stderr, FALSE, TRUE, "Source server crashed during shutdown\n");
+ status = SRV_DEAD;
+ }
+ rel_sem(SOURCE, SRC_SERV_OPTIONS_SEM);
+ /* Check that there are no regions with replication state = WAS_ON (i.e. repl_was_open). If so report that.
+ * But to determine that, we need to attach to all the database regions.
+ */
+ gvinit();
+ /* We use the same code dse uses to open all regions but we must make sure they are all open before proceeding. */
+ all_files_open = region_init(FALSE);
+ if (!all_files_open)
+ {
+ gtm_putmsg(VARLSTCNT(1) ERR_NOTALLDBOPN);
+ status |= SRV_ERR;
+ } else
+ {
+ for (reg = gd_header->regions, region_top = gd_header->regions + gd_header->n_regions; reg < region_top; reg++)
+ {
+ csa = &FILE_INFO(reg)->s_addrs;
+ csd = csa->hdr;
+ if (REPL_WAS_ENABLED(csd))
+ {
+ assert(!JNL_ENABLED(csd) || REPL_ENABLED(csd)); /* || is for turning replication on concurrently */
+ reg_seqno = csd->reg_seqno;
+ jnlseqno = (NULL != jnlpool.jnlpool_ctl) ? jnlpool.jnlpool_ctl->jnl_seqno : MAX_SEQNO;
+ sgtm_putmsg(errtxt, VARLSTCNT(8) ERR_REPLJNLCLOSED, 6, DB_LEN_STR(reg),
+ ®_seqno, ®_seqno, &jnlseqno, &jnlseqno);
+ repl_log(stderr, FALSE, TRUE, errtxt);
+ status |= SRV_ERR;
+ }
+ }
+ }
+ return (status + NORMAL_SHUTDOWN);
+}
diff --git a/sr_vvms/gtmsource_end.c b/sr_vvms/gtmsource_end.c
new file mode 100644
index 0000000..46cb74b
--- /dev/null
+++ b/sr_vvms/gtmsource_end.c
@@ -0,0 +1,138 @@
+/****************************************************************
+ * *
+ * Copyright 2006, 2011 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_unistd.h" /* for close() */
+
+#ifdef UNIX
+#include "gtm_ipc.h"
+#include <sys/shm.h>
+#include <sys/sem.h>
+#elif defined(VMS)
+#include <ssdef.h>
+#include <psldef.h>
+#include <descrip.h> /* Required for gtmsource.h */
+#else
+#error Unsupported platform
+#endif
+#include <errno.h>
+#include "gtm_inet.h"
+#include "gtm_string.h"
+
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "repl_msg.h"
+#include "gtmsource.h"
+#include "repl_dbg.h"
+#include "gtm_stdio.h"
+#include "gtm_event_log.h"
+#include "repl_shutdcode.h"
+#include "eintr_wrappers.h"
+#include "jnl.h"
+#include "repl_filter.h"
+#include "repl_sem.h"
+#ifdef VMS
+#include "repl_shm.h"
+#endif
+#ifdef UNIX
+#include "mutex.h"
+#endif
+#include "repl_log.h"
+#include "repl_comm.h"
+
+GBLREF jnlpool_addrs jnlpool;
+GBLREF jnlpool_ctl_ptr_t jnlpool_ctl;
+GBLREF uint4 process_id;
+GBLREF int gtmsource_sock_fd;
+GBLREF int gtmsource_log_fd;
+GBLREF FILE *gtmsource_log_fp;
+GBLREF int gtmsource_filter;
+GBLREF boolean_t gtmsource_logstats;
+GBLREF int gtmsource_statslog_fd;
+GBLREF FILE *gtmsource_statslog_fp;
+GBLREF unsigned char *gtmsource_tcombuff_start;
+GBLREF qw_num repl_source_data_sent;
+GBLREF qw_num repl_source_msg_sent;
+GBLREF seq_num seq_num_zero;
+GBLREF repl_msg_ptr_t gtmsource_msgp;
+GBLREF uchar_ptr_t repl_filter_buff;
+GBLREF boolean_t pool_init;
+
+int gtmsource_end1(boolean_t auto_shutdown)
+{
+ int exit_status;
+ seq_num log_seqno, log_seqno1, diff_seqno;
+ int fclose_res;
+#ifdef VMS
+ int4 status;
+#endif
+
+ gtmsource_ctl_close();
+ rel_lock(jnlpool.jnlpool_dummy_reg);
+ UNIX_ONLY(mutex_cleanup(jnlpool.jnlpool_dummy_reg);)
+ exit_status = NORMAL_SHUTDOWN;
+ if (!auto_shutdown)
+ jnlpool.gtmsource_local->shutdown = NORMAL_SHUTDOWN;
+ QWASSIGN(log_seqno, jnlpool.gtmsource_local->read_jnl_seqno);
+ QWASSIGN(log_seqno1, jnlpool.jnlpool_ctl->jnl_seqno);
+ jnlpool.gtmsource_local->gtmsource_pid = 0;
+ /* Detach from journal pool */
+ UNIX_ONLY(
+ if (jnlpool.jnlpool_ctl && 0 > SHMDT(jnlpool.jnlpool_ctl))
+ repl_log(gtmsource_log_fp, FALSE, TRUE, "Error detaching from journal pool : %s\n", REPL_STR_ERROR);
+ )
+ VMS_ONLY(
+ if (jnlpool.jnlpool_ctl)
+ {
+ if (SS$_NORMAL != (status = detach_shm(jnlpool.shm_range)))
+ repl_log(stderr, TRUE, TRUE, "Error detaching from jnlpool : %s\n", REPL_STR_ERROR);
+ jnlpool.jnlpool_ctl = NULL;
+ if (!auto_shutdown && (SS$_NORMAL != (status = signoff_from_gsec(jnlpool.shm_lockid))))
+ repl_log(stderr, TRUE, TRUE, "Error dequeueing lock on jnlpool global section : %s\n",
+ REPL_STR_ERROR);
+ }
+ )
+ jnlpool.jnlpool_ctl = jnlpool_ctl = NULL;
+ pool_init = FALSE;
+ gtmsource_free_msgbuff();
+ gtmsource_free_tcombuff();
+ gtmsource_free_filter_buff();
+ gtmsource_stop_heartbeat();
+ repl_close(>msource_sock_fd);
+ if (QWNE(log_seqno, seq_num_zero))
+ QWDECRBYDW(log_seqno, 1);
+ if (QWNE(log_seqno1, seq_num_zero))
+ QWDECRBYDW(log_seqno1, 1);
+ QWSUB(diff_seqno, log_seqno1, log_seqno);
+ repl_log(gtmsource_log_fp, TRUE, FALSE, "REPL INFO - Last Seqno written in jnlpool : %llu", log_seqno1);
+ repl_log(gtmsource_log_fp, FALSE, FALSE, " Last sent seqno : %llu", log_seqno);
+ repl_log(gtmsource_log_fp, FALSE, TRUE, " Number of unsent seqno : %llu\n", diff_seqno);
+ repl_log(gtmsource_log_fp, TRUE, TRUE, "REPL INFO - Jnl Total : %llu Msg Total : %llu\n",
+ repl_source_data_sent, repl_source_msg_sent);
+ if (gtmsource_filter & EXTERNAL_FILTER)
+ repl_stop_filter();
+ gtm_event_log_close();
+ if (auto_shutdown)
+ return (exit_status);
+ else
+ gtmsource_exit(exit_status - NORMAL_SHUTDOWN);
+}
+
+void gtmsource_end(void)
+{
+ gtmsource_end1(FALSE);
+}
diff --git a/sr_vvms/gtmsource_flush_fh.c b/sr_vvms/gtmsource_flush_fh.c
new file mode 100644
index 0000000..71cf079
--- /dev/null
+++ b/sr_vvms/gtmsource_flush_fh.c
@@ -0,0 +1,102 @@
+/****************************************************************
+ * *
+ * Copyright 2006 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#ifdef VMS
+#include <descrip.h> /* Required for gtmsource.h */
+#endif
+
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "repl_msg.h"
+#include "gtmsource.h"
+#include "jnl.h"
+#include "repl_dbg.h"
+
+GBLREF gd_region *gtmsource_mru_reg;
+GBLREF gd_addr *gd_header;
+GBLREF seq_num gtmsource_last_flush_reg_seq, gtmsource_last_flush_resync_seq;
+
+void gtmsource_flush_fh(seq_num resync_seqno)
+{ /* Update all replicated regions' file header resync_seqno to given number
+ * Flush at least one region's file header to disk if there has been no updates since the last time we flushed. We do this to
+ * keep the system's last exchanged seqno as current as we can. In case the system crashes, the difference between
+ * the two systems' seqno shouldn't be too large to cause large backlog and so long resynchronization. On a system that
+ * is contantly updated, there is a good chance that a GTM process flushes file header hence recording replication progress,
+ * in which case the source server doesn't have to flush.
+ * We choose the most recently updated region to flush
+ */
+ seq_num max_reg_seqno, pre_update_seqno;
+ gd_region *reg, *region_top, *mru_reg;
+ sgmnt_addrs *csa, *mru_reg_csa;
+ boolean_t was_crit;
+ REPL_DEBUG_ONLY(
+ char reg_name[MAX_RN_LEN + 1]; /* + 1 for trailing '\0' */
+ )
+
+ assert(gtmsource_last_flush_resync_seq <= resync_seqno);
+ if (gtmsource_last_flush_resync_seq == resync_seqno) /* already flushed */
+ {
+ REPL_EXTRA_DPRINT1("flush_fh: no action, returning\n");
+ return;
+ }
+ max_reg_seqno = 0;
+ for (reg = gd_header->regions, region_top = gd_header->regions + gd_header->n_regions; reg < region_top; reg++)
+ {
+ csa = &FILE_INFO(reg)->s_addrs;
+ if (REPL_ALLOWED(csa->hdr))
+ {
+ assert(csa->hdr->resync_seqno <= resync_seqno); /* don't want to go back */
+ pre_update_seqno = csa->hdr->resync_seqno;
+ UPDATE_RESYNC_SEQNO(reg, pre_update_seqno, resync_seqno); /* updates csa (no change though) and now_crit */
+ assert(csa->hdr->resync_seqno == resync_seqno);
+ if (csa->hdr->reg_seqno > max_reg_seqno)
+ { /* there could be multiple regions with the same max_reg_seqno; we choose the first in the list */
+ max_reg_seqno = csa->hdr->reg_seqno; /* where is the system at? */
+ mru_reg_csa = csa;
+ mru_reg = reg;
+ }
+ }
+ }
+ if (0 == max_reg_seqno) /* we are in trouble, no replicated region found */
+ GTMASSERT;
+ assert(resync_seqno <= max_reg_seqno);
+ assert(max_reg_seqno >= gtmsource_last_flush_reg_seq);
+ assert(max_reg_seqno >= gtmsource_last_flush_resync_seq);
+ if (max_reg_seqno == gtmsource_last_flush_reg_seq) /* no updates to the system */
+ {
+ if (FALSE == (was_crit = mru_reg_csa->now_crit))
+ grab_crit(mru_reg);
+ fileheader_sync(mru_reg);
+ if (!was_crit)
+ rel_crit(mru_reg);
+ gtmsource_last_flush_resync_seq = resync_seqno;
+ } /* else, GTM process will flush file header */
+ REPL_DEBUG_ONLY(
+ memcpy(reg_name, mru_reg->rname, mru_reg->rname_len);
+ reg_name[mru_reg->rname_len] = '\0';
+ if (max_reg_seqno == gtmsource_last_flush_reg_seq)
+ REPL_DPRINT2("flush_fh: flushed file header of %s\n", reg_name);
+ REPL_DPRINT4("flush_fh: set mru_reg to %s, last_flush_reg_seqno to %llu, last_flush_resync_seqno to %llu\n",
+ reg_name, max_reg_seqno, resync_seqno);
+ )
+ gtmsource_mru_reg = mru_reg;
+ gtmsource_last_flush_reg_seq = max_reg_seqno;
+ return;
+}
diff --git a/sr_vvms/gtmsource_get_opt.c b/sr_vvms/gtmsource_get_opt.c
new file mode 100644
index 0000000..30a5361
--- /dev/null
+++ b/sr_vvms/gtmsource_get_opt.c
@@ -0,0 +1,349 @@
+/****************************************************************
+ * *
+ * Copyright 2006, 2013 Fidelity Information Services, Inc.*
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_stdlib.h"
+#include "gtm_netdb.h"
+#include "gtm_socket.h"
+#include "gtm_inet.h"
+#include "gtm_string.h"
+#include "gtm_ctype.h"
+#if !defined(__MVS__) && !defined(VMS)
+#include <sys/socketvar.h>
+#endif
+#ifdef VMS
+#include <descrip.h> /* Required for gtmsource.h */
+#endif
+#include <errno.h>
+
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "repl_msg.h"
+#include "jnl.h"
+#include "gtmsource.h"
+#include "cli.h"
+#include "gtm_stdio.h"
+#include "util.h"
+#include "repl_log.h"
+
+#define MAX_SECONDARY_LEN (MAX_HOST_NAME_LEN + 11) /* +11 for ':' and
+ * port number */
+
+#define DEFAULT_JNLPOOL_SIZE (64 * 1024 * 1024)
+
+#define DEFAULT_SHUTDOWN_TIMEOUT 30
+
+#define GTMSOURCE_CONN_PARMS_LEN ((10 + 1) * GTMSOURCE_CONN_PARMS_COUNT - 1)
+
+GBLREF gtmsource_options_t gtmsource_options;
+GBLREF boolean_t update_disable;
+
+error_def(ERR_GETADDRINFO);
+error_def(ERR_GETNAMEINFO);
+error_def(ERR_TEXT);
+
+int gtmsource_get_opt(void)
+{
+ boolean_t secondary, dotted_notation;
+ int tries, index = 0;
+ unsigned short secondary_len;
+ char secondary_sys[MAX_SECONDARY_LEN], *c;
+ struct hostent *sec_hostentry;
+ struct addrinfo *ai_ptr;
+ int errcode;
+ char *ip_end;
+ int port_len;
+
+ boolean_t log, log_interval_specified;
+ unsigned short log_file_len;
+
+ boolean_t buffsize_status;
+
+ boolean_t filter;
+ unsigned short filter_cmd_len;
+
+ int timeout_status;
+
+ unsigned short statslog_val_len;
+ char statslog_val[4]; /* "ON" or "OFF" */
+
+ unsigned short update_val_len;
+ char update_val[SIZEOF("DISABLE")]; /* "ENABLE" or "DISABLE" */
+
+ unsigned short connect_parms_str_len;
+ char *connect_parms_str, tmp_connect_parms_str[GTMSOURCE_CONN_PARMS_LEN + 1];
+ char *connect_parm_token_str, *connect_parm;
+ int connect_parms_index;
+ boolean_t connect_parms_badval;
+
+ memset((char *)>msource_options, 0, SIZEOF(gtmsource_options));
+
+ gtmsource_options.start = (cli_present("START") == CLI_PRESENT);
+ gtmsource_options.shut_down = (cli_present("SHUTDOWN") == CLI_PRESENT);
+ gtmsource_options.activate = (cli_present("ACTIVATE") == CLI_PRESENT);
+ gtmsource_options.deactivate = (cli_present("DEACTIVATE") == CLI_PRESENT);
+ gtmsource_options.checkhealth = (cli_present("CHECKHEALTH") == CLI_PRESENT);
+ gtmsource_options.statslog = (cli_present("STATSLOG") == CLI_PRESENT);
+ gtmsource_options.showbacklog = (cli_present("SHOWBACKLOG") == CLI_PRESENT);
+ gtmsource_options.changelog = (cli_present("CHANGELOG") == CLI_PRESENT);
+ gtmsource_options.stopsourcefilter = (cli_present("STOPSOURCEFILTER") == CLI_PRESENT);
+ gtmsource_options.update = (cli_present("UPDATE") == CLI_PRESENT);
+
+ if (gtmsource_options.start || gtmsource_options.activate)
+ {
+ if (secondary = (CLI_PRESENT == cli_present("SECONDARY")))
+ {
+ secondary_len = MAX_SECONDARY_LEN;
+ if (!cli_get_str("SECONDARY", secondary_sys, &secondary_len))
+ {
+ util_out_print("Error parsing SECONDARY qualifier", TRUE);
+ return(-1);
+ }
+ /* Parse secondary_sys into secondary_host
+ * and secondary_port */
+ c = secondary_sys;
+ dotted_notation = TRUE;
+ if ('[' == *c)
+ {
+ ip_end = strchr(++c, ']');
+ if (NULL == ip_end || 0 == (index = ip_end - c))
+ {
+ util_out_print("Invalid IP address !AD", TRUE,
+ LEN_AND_STR(secondary_sys));
+ return(-1);
+ }
+ memcpy(gtmsource_options.secondary_host, c, index);
+ gtmsource_options.secondary_host[index] = '\0';
+ c = ip_end + 1;
+ } else
+ {
+ while(*c && *c != ':')
+ gtmsource_options.secondary_host[index++] = *c++;
+ gtmsource_options.secondary_host[index] = '\0';
+ }
+ if (':' != *c)
+ {
+ util_out_print("Secondary port number should be specified", TRUE);
+ return(-1);
+ }
+ port_len = strlen(++c);
+ errno = 0;
+ if (((0 == (gtmsource_options.secondary_port = ATOI(c))) && (0 != errno))
+ || (0 >= gtmsource_options.secondary_port))
+ {
+ util_out_print("Error parsing secondary port number !AD", TRUE, LEN_AND_STR(c));
+ return(-1);
+ }
+ assert(NI_MAXSERV > port_len);
+ }
+ if (CLI_PRESENT == cli_present("CONNECTPARAMS"))
+ {
+ connect_parms_str_len = GTMSOURCE_CONN_PARMS_LEN + 1;
+ if (!cli_get_str("CONNECTPARAMS", tmp_connect_parms_str, &connect_parms_str_len))
+ {
+ util_out_print("Error parsing CONNECTPARAMS qualifier", TRUE);
+ return(-1);
+ }
+#ifdef VMS
+ /* strip the quotes around the string. (DCL doesn't do it) */
+ assert('"' == tmp_connect_parms_str[0]);
+ assert('"' == tmp_connect_parms_str[connect_parms_str_len - 1]);
+ connect_parms_str = &tmp_connect_parms_str[1];
+ tmp_connect_parms_str[connect_parms_str_len - 1] = '\0';
+#else
+ connect_parms_str = &tmp_connect_parms_str[0];
+#endif
+ for (connect_parms_index =
+ GTMSOURCE_CONN_HARD_TRIES_COUNT,
+ connect_parms_badval = FALSE,
+ connect_parm_token_str = connect_parms_str;
+ !connect_parms_badval &&
+ connect_parms_index < GTMSOURCE_CONN_PARMS_COUNT &&
+ (connect_parm = strtok(connect_parm_token_str,
+ GTMSOURCE_CONN_PARMS_DELIM))
+ != NULL;
+ connect_parms_index++,
+ connect_parm_token_str = NULL)
+
+ {
+ errno = 0;
+ if ((0 == (gtmsource_options.connect_parms[connect_parms_index] = ATOI(connect_parm))
+ && 0 != errno) || 0 >= gtmsource_options.connect_parms[connect_parms_index])
+ connect_parms_badval = TRUE;
+ }
+ if (connect_parms_badval)
+ {
+ util_out_print("Error parsing or invalid value parameter in CONNECTPARAMS", TRUE);
+ return(-1);
+ }
+ if (GTMSOURCE_CONN_PARMS_COUNT != connect_parms_index)
+ {
+ util_out_print(
+ "All CONNECTPARAMS - HARD TRIES, HARD TRIES PERIOD, "
+ "SOFT TRIES PERIOD, "
+ "ALERT TIME, HEARTBEAT INTERVAL, "
+ "MAX HEARBEAT WAIT should be specified", TRUE);
+ return(-1);
+ }
+ } else
+ {
+ gtmsource_options.connect_parms[GTMSOURCE_CONN_HARD_TRIES_COUNT] = REPL_CONN_HARD_TRIES_COUNT;
+ gtmsource_options.connect_parms[GTMSOURCE_CONN_HARD_TRIES_PERIOD] = REPL_CONN_HARD_TRIES_PERIOD;
+ gtmsource_options.connect_parms[GTMSOURCE_CONN_SOFT_TRIES_PERIOD] = REPL_CONN_SOFT_TRIES_PERIOD;
+ gtmsource_options.connect_parms[GTMSOURCE_CONN_ALERT_PERIOD] = REPL_CONN_ALERT_ALERT_PERIOD;
+ gtmsource_options.connect_parms[GTMSOURCE_CONN_HEARTBEAT_PERIOD] = REPL_CONN_HEARTBEAT_PERIOD;
+ gtmsource_options.connect_parms[GTMSOURCE_CONN_HEARTBEAT_MAX_WAIT] = REPL_CONN_HEARTBEAT_MAX_WAIT;
+ }
+ if (gtmsource_options.connect_parms[GTMSOURCE_CONN_ALERT_PERIOD]<
+ gtmsource_options.connect_parms[GTMSOURCE_CONN_SOFT_TRIES_PERIOD])
+ gtmsource_options.connect_parms[GTMSOURCE_CONN_ALERT_PERIOD] =
+ gtmsource_options.connect_parms[GTMSOURCE_CONN_SOFT_TRIES_PERIOD];
+ if (gtmsource_options.connect_parms[GTMSOURCE_CONN_HEARTBEAT_MAX_WAIT] <
+ gtmsource_options.connect_parms[GTMSOURCE_CONN_HEARTBEAT_PERIOD])
+ gtmsource_options.connect_parms[GTMSOURCE_CONN_HEARTBEAT_MAX_WAIT] =
+ gtmsource_options.connect_parms[GTMSOURCE_CONN_HEARTBEAT_PERIOD];
+ }
+
+ if (gtmsource_options.start || gtmsource_options.statslog || gtmsource_options.changelog || gtmsource_options.activate ||
+ gtmsource_options.deactivate)
+ {
+ log = (cli_present("LOG") == CLI_PRESENT);
+ log_interval_specified = (CLI_PRESENT == cli_present("LOG_INTERVAL"));
+ if (log)
+ {
+ log_file_len = MAX_FN_LEN + 1;
+ if (!cli_get_str("LOG", gtmsource_options.log_file, &log_file_len))
+ {
+ util_out_print("Error parsing LOG qualifier", TRUE);
+ return(-1);
+ }
+ } else
+ gtmsource_options.log_file[0] = '\0';
+ gtmsource_options.src_log_interval = 0;
+ if (log_interval_specified)
+ {
+ if (!cli_get_num("LOG_INTERVAL", (int4 *)>msource_options.src_log_interval))
+ {
+ util_out_print("Error parsing LOG_INTERVAL qualifier", TRUE);
+ return (-1);
+ }
+ }
+ if (gtmsource_options.start && 0 == gtmsource_options.src_log_interval)
+ gtmsource_options.src_log_interval = LOGTRNUM_INTERVAL;
+ /* For changelog/activate/deactivate, interval == 0 implies don't change log interval already established */
+ /* We ignore interval specification for statslog, Vinaya 2005/02/07 */
+ }
+
+ if (gtmsource_options.start)
+ {
+ assert(secondary || CLI_PRESENT == cli_present("PASSIVE"));
+ gtmsource_options.mode = ((secondary) ? GTMSOURCE_MODE_ACTIVE : GTMSOURCE_MODE_PASSIVE);
+ if (buffsize_status = (CLI_PRESENT == cli_present("BUFFSIZE")))
+ {
+ if (!cli_get_int("BUFFSIZE", >msource_options.buffsize))
+ {
+ util_out_print("Error parsing BUFFSIZE qualifier", TRUE);
+ return(-1);
+ }
+ if (MIN_JNLPOOL_SIZE > gtmsource_options.buffsize)
+ gtmsource_options.buffsize = MIN_JNLPOOL_SIZE;
+ } else
+ gtmsource_options.buffsize = DEFAULT_JNLPOOL_SIZE;
+ /* Round up buffsize to the nearest (~JNL_WRT_END_MASK + 1) multiple */
+ gtmsource_options.buffsize = ((gtmsource_options.buffsize + ~JNL_WRT_END_MASK) & JNL_WRT_END_MASK);
+ if (filter = (CLI_PRESENT == cli_present("FILTER")))
+ {
+ filter_cmd_len = MAX_FILTER_CMD_LEN;
+ if (!cli_get_str("FILTER", gtmsource_options.filter_cmd, &filter_cmd_len))
+ {
+ util_out_print("Error parsing FILTER qualifier", TRUE);
+ return(-1);
+ }
+ } else
+ gtmsource_options.filter_cmd[0] = '\0';
+ }
+
+ if (gtmsource_options.shut_down)
+ {
+ if ((timeout_status = cli_present("TIMEOUT")) == CLI_PRESENT)
+ {
+ if (!cli_get_int("TIMEOUT", >msource_options.shutdown_time))
+ {
+ util_out_print("Error parsing TIMEOUT qualifier", TRUE);
+ return(-1);
+ }
+ if (DEFAULT_SHUTDOWN_TIMEOUT < gtmsource_options.shutdown_time || 0 > gtmsource_options.shutdown_time)
+ {
+ gtmsource_options.shutdown_time = DEFAULT_SHUTDOWN_TIMEOUT;
+ util_out_print("shutdown TIMEOUT changed to !UL", TRUE, gtmsource_options.shutdown_time);
+ }
+ } else if (CLI_NEGATED == timeout_status)
+ gtmsource_options.shutdown_time = -1;
+ else /* TIMEOUT not specified */
+ gtmsource_options.shutdown_time = DEFAULT_SHUTDOWN_TIMEOUT;
+ }
+
+ if (gtmsource_options.statslog)
+ {
+ statslog_val_len = 4; /* max(strlen("ON"), strlen("OFF")) + 1 */
+ if (!cli_get_str("STATSLOG", statslog_val, &statslog_val_len))
+ {
+ util_out_print("Error parsing STATSLOG qualifier", TRUE);
+ return(-1);
+ }
+ UNIX_ONLY(cli_strupper(statslog_val);)
+ if (0 == strcmp(statslog_val, "ON"))
+ gtmsource_options.statslog = TRUE;
+ else if (0 == strcmp(statslog_val, "OFF"))
+ gtmsource_options.statslog = FALSE;
+ else
+ {
+ util_out_print("Invalid value for STATSLOG qualifier, should be either ON or OFF", TRUE);
+ return(-1);
+ }
+ }
+
+ if (gtmsource_options.activate)
+ update_disable = FALSE;
+ if (gtmsource_options.deactivate || (gtmsource_options.start && GTMSOURCE_MODE_PASSIVE == gtmsource_options.mode))
+ update_disable = TRUE;
+
+ if (gtmsource_options.update)
+ {
+ update_val_len = SIZEOF(update_val);
+ if (!cli_get_str("UPDATE", update_val, &update_val_len))
+ {
+ util_out_print("Error parsing UPDATE qualifier", TRUE);
+ return(-1);
+ }
+ UNIX_ONLY(cli_strupper(update_val);)
+ if (strcmp(update_val, "ENABLE") == 0)
+ {
+ util_out_print("Update are now enabled", TRUE);
+ update_disable = FALSE;
+ } else if (strcmp(update_val, "DISABLE") == 0)
+ {
+ util_out_print("Update are now disabled", TRUE);
+ update_disable = TRUE;
+ } else
+ {
+ util_out_print("Invalid value for UPDATE qualifier, should be either ENABLE or DISABLE", TRUE);
+ return(-1);
+ }
+ }
+ return(0);
+}
diff --git a/sr_vvms/gtmsource_heartbeat.c b/sr_vvms/gtmsource_heartbeat.c
new file mode 100644
index 0000000..9df5ec6
--- /dev/null
+++ b/sr_vvms/gtmsource_heartbeat.c
@@ -0,0 +1,248 @@
+/****************************************************************
+ * *
+ * Copyright 2006, 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+#include "gtm_stdio.h"
+
+#include "gtm_time.h"
+#include <sys/time.h>
+#include <errno.h>
+#include "gtm_inet.h" /* Required for gtmsource.h */
+#ifdef VMS
+#include <descrip.h> /* Required for gtmsource.h */
+#endif
+
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "jnl.h"
+#include "repl_msg.h"
+#include "gtmsource.h"
+#include "repl_comm.h"
+#include "repl_dbg.h"
+#include "repl_log.h"
+#include "repl_errno.h"
+#include "iosp.h"
+#include "gt_timer.h"
+#include "gtmsource_heartbeat.h"
+#include "relqop.h"
+
+GBLREF jnlpool_addrs jnlpool;
+GBLREF int gtmsource_sock_fd;
+GBLREF boolean_t gtmsource_logstats;
+GBLREF int gtmsource_log_fd;
+GBLREF FILE *gtmsource_log_fp;
+GBLREF gtmsource_state_t gtmsource_state;
+GBLREF gd_addr *gd_header;
+
+GBLDEF boolean_t heartbeat_stalled = TRUE;
+GBLDEF repl_heartbeat_que_entry_t *repl_heartbeat_que_head = NULL;
+GBLDEF repl_heartbeat_que_entry_t *repl_heartbeat_free_head = NULL;
+GBLDEF volatile time_t gtmsource_now;
+GBLDEF time_t last_sent_time, earliest_sent_time;
+
+error_def(ERR_REPLCOMM);
+error_def(ERR_TEXT);
+
+static int heartbeat_period, heartbeat_max_wait;
+
+void gtmsource_heartbeat_timer(TID tid, int4 interval_len, int *interval_ptr)
+{
+ assert(0 != gtmsource_now);
+ UNIX_ONLY(assert(*interval_ptr == heartbeat_period);) /* interval_len and interval_ptr are dummies on VMS */
+ gtmsource_now += heartbeat_period; /* cannot use *interval_ptr on VMS */
+ REPL_DPRINT2("Starting heartbeat timer with %d s\n", heartbeat_period);
+ start_timer((TID)gtmsource_heartbeat_timer, heartbeat_period * 1000, gtmsource_heartbeat_timer, SIZEOF(heartbeat_period),
+ &heartbeat_period); /* start_timer expects time interval in milli seconds, heartbeat_period is in seconds */
+}
+
+int gtmsource_init_heartbeat(void)
+{
+ int num_q_entries;
+ repl_heartbeat_que_entry_t *heartbeat_element;
+
+ assert(NULL == repl_heartbeat_que_head);
+
+ heartbeat_period = jnlpool.gtmsource_local->connect_parms[GTMSOURCE_CONN_HEARTBEAT_PERIOD];
+ heartbeat_max_wait = jnlpool.gtmsource_local->connect_parms[GTMSOURCE_CONN_HEARTBEAT_MAX_WAIT];
+ num_q_entries = DIVIDE_ROUND_UP(heartbeat_max_wait, heartbeat_period) + 2;
+ REPL_DPRINT4("Initialized heartbeat, heartbeat_period = %d s, heartbeat_max_wait = %d s, num_q_entries = %d\n",
+ heartbeat_period, heartbeat_max_wait, num_q_entries);
+ if (!(repl_heartbeat_que_head = (repl_heartbeat_que_entry_t *)malloc(num_q_entries * SIZEOF(repl_heartbeat_que_entry_t))))
+ rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_LIT("Error in allocating heartbeat queue"), errno);
+
+ memset(repl_heartbeat_que_head, 0, num_q_entries * SIZEOF(repl_heartbeat_que_entry_t));
+ repl_heartbeat_free_head = repl_heartbeat_que_head + 1;
+ *(time_t *)&repl_heartbeat_que_head->heartbeat.ack_time[0] = 0;
+ *(time_t *)&repl_heartbeat_free_head->heartbeat.ack_time[0] = 0;
+ for (heartbeat_element = repl_heartbeat_free_head + 1, num_q_entries -= 2;
+ num_q_entries > 0;
+ num_q_entries--, heartbeat_element++)
+ {
+ insqt((que_ent_ptr_t)heartbeat_element, (que_ent_ptr_t)repl_heartbeat_free_head);
+ }
+ last_sent_time = gtmsource_now = time(NULL);
+ /* Ideally, we should use the Greatest Common Factor of heartbeat_period and GTMSOURCE_LOGSTATS_INTERVAL as the time keeper
+ * interval. As it stands now, we may not honor GTMSOURCE_LOGSTATS_INTERVAL if user specifies a heartbeat value
+ * larger than GTMSOURCE_LOGSTATS_INTERVAL. When we make GTMSOURCE_LOGSTATS_INTERVAL a user configurable parameter,
+ * this code may have to be revisited. Also, modify the check in gtmsource_process (prev_now != (save_now = gtmsource_now))
+ * to be something like (hearbeat_period < difftime((save_now = gtmsource_now), prev_now)). Vinaya 2003, Sep 08
+ */
+ start_timer((TID)gtmsource_heartbeat_timer, heartbeat_period * 1000, gtmsource_heartbeat_timer, SIZEOF(heartbeat_period),
+ &heartbeat_period); /* start_timer expects time interval in milli seconds, heartbeat_period is in seconds */
+ heartbeat_stalled = FALSE;
+ earliest_sent_time = 0;
+ return (SS_NORMAL);
+}
+
+int gtmsource_stop_heartbeat(void)
+{
+ cancel_timer((TID)gtmsource_heartbeat_timer);
+ if (NULL != repl_heartbeat_que_head)
+ free(repl_heartbeat_que_head);
+ repl_heartbeat_que_head = NULL;
+ repl_heartbeat_free_head = NULL;
+ last_sent_time = 0;
+ earliest_sent_time = 0;
+ gtmsource_now = 0;
+ heartbeat_stalled = TRUE;
+ REPL_DPRINT1("Stopped heartbeat\n");
+ return (SS_NORMAL);
+}
+
+boolean_t gtmsource_is_heartbeat_overdue(time_t *now, repl_heartbeat_msg_t *overdue_heartbeat)
+{
+
+ repl_heartbeat_que_entry_t *heartbeat_element;
+ double time_elapsed;
+ unsigned char seq_num_str[32], *seq_num_ptr;
+
+#ifndef REPL_DISABLE_HEARTBEAT
+ if (0 == earliest_sent_time ||
+ (time_elapsed = difftime(*now, earliest_sent_time)) <= (double)heartbeat_max_wait)
+ return (FALSE);
+
+ heartbeat_element = (repl_heartbeat_que_entry_t *)remqh((que_ent_ptr_t)repl_heartbeat_que_head);
+ if (NULL == heartbeat_element)
+ {
+ assert(FALSE);
+ return (FALSE);
+ }
+
+ memcpy(overdue_heartbeat, &heartbeat_element->heartbeat, SIZEOF(repl_heartbeat_msg_t));
+
+ REPL_DPRINT5("Overdue heartbeat - SEQNO : "INT8_FMT" time : %ld now : %ld difftime : %00.f\n",
+ INT8_PRINT(*(seq_num *)&overdue_heartbeat->ack_seqno[0]), *(time_t *)&overdue_heartbeat->ack_time[0], *now,
+ time_elapsed);
+
+ insqt((que_ent_ptr_t)heartbeat_element, (que_ent_ptr_t)repl_heartbeat_free_head);
+
+ return (TRUE);
+#else
+ return (FALSE);
+#endif
+}
+
+int gtmsource_send_heartbeat(time_t *now)
+{
+ repl_heartbeat_que_entry_t *heartbeat_element;
+ unsigned char *msg_ptr; /* needed for REPL_{SEND,RECV}_LOOP */
+ int tosend_len, sent_len, sent_this_iter; /* needed for REPL_SEND_LOOP */
+ int status; /* needed for REPL_{SEND,RECV}_LOOP */
+ unsigned char seq_num_str[32], *seq_num_ptr;
+
+
+ heartbeat_element = (repl_heartbeat_que_entry_t *)remqh((que_ent_ptr_t)repl_heartbeat_free_head);
+ if (NULL == heartbeat_element) /* Too many pending heartbeats, send later */
+ return (SS_NORMAL);
+
+ QWASSIGN(*(seq_num *)&heartbeat_element->heartbeat.ack_seqno[0], jnlpool.jnlpool_ctl->jnl_seqno);
+ *(time_t *)&heartbeat_element->heartbeat.ack_time[0] = *now;
+
+ heartbeat_element->heartbeat.type = REPL_HEARTBEAT;
+ heartbeat_element->heartbeat.len = MIN_REPL_MSGLEN;
+ REPL_SEND_LOOP(gtmsource_sock_fd, &heartbeat_element->heartbeat, MIN_REPL_MSGLEN, REPL_POLL_NOWAIT)
+ {
+ gtmsource_poll_actions(FALSE); /* Recursive call */
+ if (GTMSOURCE_WAITING_FOR_CONNECTION == gtmsource_state ||
+ GTMSOURCE_CHANGING_MODE == gtmsource_state)
+ return (SS_NORMAL);
+ }
+
+ if (SS_NORMAL == status)
+ {
+ insqt((que_ent_ptr_t)heartbeat_element, (que_ent_ptr_t)repl_heartbeat_que_head);
+ last_sent_time = *now;
+ if (0 == earliest_sent_time)
+ earliest_sent_time = last_sent_time;
+
+ REPL_DPRINT4("HEARTBEAT sent with time %ld SEQNO "INT8_FMT" at %ld\n",
+ *(time_t *)&heartbeat_element->heartbeat.ack_time[0],
+ INT8_PRINT(*(seq_num *)&heartbeat_element->heartbeat.ack_seqno[0]), time(NULL));
+
+ return (SS_NORMAL);
+ }
+
+ if (EREPL_SEND == repl_errno && REPL_CONN_RESET(status))
+ {
+ repl_log(gtmsource_log_fp, TRUE, TRUE, "Connection reset while attempting to send heartbeat. Status = %d ; %s\n",
+ status, STRERROR(status));
+ repl_close(>msource_sock_fd);
+ gtmsource_state = GTMSOURCE_WAITING_FOR_CONNECTION;
+ return (SS_NORMAL);
+ }
+ if (EREPL_SEND == repl_errno)
+ rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_LIT("Error sending HEARTBEAT message. Error in send"), status);
+
+ if (EREPL_SELECT == repl_errno)
+ rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_LIT("Error sending HEARTBEAT message. Error in select"), status);
+
+ GTMASSERT;
+}
+
+int gtmsource_process_heartbeat(repl_heartbeat_msg_t *heartbeat_msg)
+{
+ repl_heartbeat_que_entry_t *heartbeat_element;
+ seq_num ack_seqno;
+ gd_region *reg, *region_top;
+ sgmnt_addrs *csa;
+ unsigned char seq_num_str[32], *seq_num_ptr;
+
+ QWASSIGN(ack_seqno, *(seq_num *)&heartbeat_msg->ack_seqno[0]);
+
+ REPL_DPRINT4("HEARTBEAT received with time %ld SEQNO "INT8_FMT" at %ld\n",
+ *(time_t *)&heartbeat_msg->ack_time[0], INT8_PRINT(ack_seqno), time(NULL));
+
+ for (heartbeat_element = (repl_heartbeat_que_entry_t *)remqh((que_ent_ptr_t)repl_heartbeat_que_head);
+ NULL != heartbeat_element&&
+ *(time_t *)&heartbeat_msg->ack_time[0] >= earliest_sent_time;
+ heartbeat_element = (repl_heartbeat_que_entry_t *)remqh((que_ent_ptr_t)repl_heartbeat_que_head))
+ {
+ insqt((que_ent_ptr_t)heartbeat_element, (que_ent_ptr_t)repl_heartbeat_free_head);
+ earliest_sent_time =
+ *(time_t *)&((repl_heartbeat_que_entry_t *)
+ ((unsigned char *)repl_heartbeat_que_head + repl_heartbeat_que_head->que.fl))->heartbeat.ack_time[0];
+ }
+
+ if (NULL != heartbeat_element)
+ insqh((que_ent_ptr_t)heartbeat_element, (que_ent_ptr_t)repl_heartbeat_que_head);
+
+ return (SS_NORMAL);
+}
diff --git a/sr_vvms/gtmsource_mode_change.c b/sr_vvms/gtmsource_mode_change.c
new file mode 100644
index 0000000..85f79f9
--- /dev/null
+++ b/sr_vvms/gtmsource_mode_change.c
@@ -0,0 +1,116 @@
+/****************************************************************
+ * *
+ * Copyright 2006, 2013 Fidelity Information Services, Inc.*
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_time.h"
+#include "gtm_fcntl.h"
+#include "gtm_unistd.h"
+#include "gtm_inet.h"
+#include "gtm_string.h"
+#include <errno.h>
+#include <descrip.h> /* Required for gtmsource.h */
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "repl_msg.h"
+#include "gtmsource.h"
+#include "repl_dbg.h"
+#include "gtm_stdio.h"
+#include "repl_shutdcode.h"
+#include "repl_sem.h"
+#include "repl_log.h"
+
+GBLREF jnlpool_addrs jnlpool;
+GBLREF gtmsource_options_t gtmsource_options;
+GBLREF boolean_t update_disable;
+
+int gtmsource_mode_change(int to_mode)
+{
+ uint4 savepid;
+ int exit_status;
+ int status, detach_status, remove_status;
+
+ /* Grab the jnlpool jnlpool option write lock */
+ if (0 > grab_sem(SOURCE, SRC_SERV_OPTIONS_SEM))
+ {
+ repl_log(stderr, FALSE, TRUE,
+ "Error grabbing jnlpool access control/jnlpool option write lock : %s. Could not change mode\n", REPL_SEM_ERROR);
+ return (ABNORMAL_SHUTDOWN);
+ }
+
+ if ((jnlpool.gtmsource_local->mode == GTMSOURCE_MODE_ACTIVE_REQUESTED)
+ || (jnlpool.gtmsource_local->mode == GTMSOURCE_MODE_PASSIVE_REQUESTED))
+ {
+ repl_log(stderr, FALSE, TRUE, "Source Server %s already requested, not changing mode\n",
+ (to_mode == GTMSOURCE_MODE_ACTIVE_REQUESTED) ? "ACTIVATE" : "DEACTIVATE");
+ rel_sem(SOURCE, SRC_SERV_OPTIONS_SEM);
+ return (ABNORMAL_SHUTDOWN);
+ }
+ if (((GTMSOURCE_MODE_ACTIVE == jnlpool.gtmsource_local->mode) && (GTMSOURCE_MODE_ACTIVE_REQUESTED == to_mode))
+ || ((GTMSOURCE_MODE_PASSIVE == jnlpool.gtmsource_local->mode) && (GTMSOURCE_MODE_PASSIVE_REQUESTED == to_mode)))
+ {
+ repl_log(stderr, FALSE, TRUE, "Source Server already %s, not changing mode\n",
+ (to_mode == GTMSOURCE_MODE_ACTIVE_REQUESTED) ? "ACTIVE" : "PASSIVE");
+ rel_sem(SOURCE, SRC_SERV_OPTIONS_SEM);
+ return (ABNORMAL_SHUTDOWN);
+ }
+
+ repl_log(stdout, FALSE, FALSE, "Initiating change of mode from %s to %s\n", (GTMSOURCE_MODE_ACTIVE_REQUESTED == to_mode) ?
+ "PASSIVE" : "ACTIVE", (GTMSOURCE_MODE_ACTIVE_REQUESTED == to_mode) ? "ACTIVE" : "PASSIVE");
+
+ if (GTMSOURCE_MODE_ACTIVE_REQUESTED == to_mode)
+ {
+ jnlpool.gtmsource_local->secondary_port = gtmsource_options.secondary_port;
+ strcpy(jnlpool.gtmsource_local->secondary_host, gtmsource_options.secondary_host);
+ jnlpool.gtmsource_local->secondary_port = gtmsource_options.secondary_port;
+ memcpy(&jnlpool.gtmsource_local->connect_parms[0], >msource_options.connect_parms[0],
+ SIZEOF(gtmsource_options.connect_parms));
+ }
+ if ('\0' != gtmsource_options.log_file[0] && 0 != strcmp(jnlpool.gtmsource_local->log_file, gtmsource_options.log_file))
+ {
+ repl_log(stdout, FALSE, TRUE, "Signaling change in log file from %s to %s\n",
+ jnlpool.gtmsource_local->log_file, gtmsource_options.log_file);
+ strcpy(jnlpool.gtmsource_local->log_file, gtmsource_options.log_file);
+ jnlpool.gtmsource_local->changelog |= REPLIC_CHANGE_LOGFILE;
+ }
+ if (0 != gtmsource_options.src_log_interval && jnlpool.gtmsource_local->log_interval != gtmsource_options.src_log_interval)
+ {
+ repl_log(stdout, FALSE, TRUE, "Signaling change in log interval from %u to %u\n",
+ jnlpool.gtmsource_local->log_interval, gtmsource_options.src_log_interval);
+ jnlpool.gtmsource_local->log_interval = gtmsource_options.src_log_interval;
+ jnlpool.gtmsource_local->changelog |= REPLIC_CHANGE_LOGINTERVAL;
+ }
+
+ jnlpool.gtmsource_local->mode = to_mode;
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK);
+ if (update_disable)
+ {
+ jnlpool.jnlpool_ctl->upd_disabled = TRUE;
+ repl_log(stdout, FALSE, TRUE, "Updates are disabled now \n");
+ }
+ else
+ {
+ jnlpool.jnlpool_ctl->upd_disabled = FALSE;
+ repl_log(stdout, FALSE, TRUE, "Updates are allowed now \n");
+ }
+ rel_lock(jnlpool.jnlpool_dummy_reg);
+
+ rel_sem(SOURCE, SRC_SERV_OPTIONS_SEM);
+
+ REPL_DPRINT1("Change mode signalled\n");
+
+ return (NORMAL_SHUTDOWN);
+}
diff --git a/sr_vvms/gtmsource_process.c b/sr_vvms/gtmsource_process.c
new file mode 100644
index 0000000..7bf4f24
--- /dev/null
+++ b/sr_vvms/gtmsource_process.c
@@ -0,0 +1,841 @@
+/****************************************************************
+ * *
+ * Copyright 2006, 2013 Fidelity Information Services, Inc.*
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+#include "gtm_stdio.h"
+#include "gtm_socket.h"
+#include "gtm_inet.h"
+#include "gtm_fcntl.h"
+#include "gtm_unistd.h"
+#include "gtm_time.h"
+#include "gtm_stat.h"
+
+#include <errno.h>
+#include <signal.h>
+#include <descrip.h> /* Required for gtmsource.h */
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "repl_msg.h"
+#include "gtmsource.h"
+#include "repl_comm.h"
+#include "jnl.h"
+#include "hashtab_mname.h" /* needed for muprec.h */
+#include "hashtab_int4.h" /* needed for muprec.h */
+#include "hashtab_int8.h" /* needed for muprec.h */
+#include "buddy_list.h"
+#include "muprec.h"
+#include "repl_ctl.h"
+#include "repl_errno.h"
+#include "repl_dbg.h"
+#include "iosp.h"
+#include "gt_timer.h"
+#include "gtmsource_heartbeat.h"
+#include "repl_filter.h"
+#include "repl_log.h"
+#include "min_max.h"
+#include "rel_quant.h"
+#include "copy.h"
+#include "repl_sort_tr_buff.h"
+#include "replgbl.h"
+
+#define MAX_HEXDUMP_CHARS_PER_LINE 26 /* 2 characters per byte + space, 80 column assumed */
+
+GBLDEF seq_num gtmsource_save_read_jnl_seqno;
+GBLDEF gtmsource_state_t gtmsource_state = GTMSOURCE_DUMMY_STATE;
+GBLDEF repl_msg_ptr_t gtmsource_msgp = NULL;
+GBLDEF int gtmsource_msgbufsiz = 0;
+GBLREF uchar_ptr_t repl_filter_buff;
+GBLREF int repl_filter_bufsiz;
+
+GBLDEF qw_num repl_source_data_sent = 0;
+GBLDEF qw_num repl_source_msg_sent = 0;
+GBLDEF qw_num repl_source_lastlog_data_sent = 0;
+GBLDEF qw_num repl_source_lastlog_msg_sent = 0;
+GBLDEF time_t repl_source_prev_log_time;
+GBLDEF time_t repl_source_this_log_time;
+GBLDEF gd_region *gtmsource_mru_reg;
+GBLDEF time_t gtmsource_last_flush_time;
+GBLDEF seq_num gtmsource_last_flush_reg_seq, gtmsource_last_flush_resync_seq;
+
+GBLREF volatile time_t gtmsource_now;
+GBLREF int gtmsource_sock_fd;
+GBLREF jnlpool_addrs jnlpool;
+GBLREF gd_addr *gd_header;
+GBLREF sgmnt_addrs *cs_addrs;
+GBLREF sgmnt_data_ptr_t cs_data;
+GBLREF gd_region *gv_cur_region;
+GBLREF repl_ctl_element *repl_ctl_list;
+GBLREF gtmsource_options_t gtmsource_options;
+
+GBLREF int gtmsource_log_fd;
+GBLREF FILE *gtmsource_log_fp;
+GBLREF boolean_t gtmsource_logstats;
+GBLREF int gtmsource_filter;
+GBLREF gd_addr *gd_header;
+GBLREF seq_num seq_num_zero, seq_num_minus_one, seq_num_one;
+GBLREF unsigned char jnl_ver, remote_jnl_ver;
+GBLREF unsigned int jnl_source_datalen, jnl_dest_maxdatalen;
+GBLREF unsigned char jnl_source_rectype, jnl_dest_maxrectype;
+GBLREF int repl_max_send_buffsize, repl_max_recv_buffsize;
+GBLREF boolean_t primary_side_std_null_coll;
+GBLREF boolean_t secondary_side_std_null_coll;
+GBLREF seq_num lastlog_seqno;
+GBLREF uint4 log_interval;
+GBLREF qw_num trans_sent_cnt, last_log_tr_sent_cnt;
+
+error_def(ERR_REPLCOMM);
+error_def(ERR_TEXT);
+error_def(ERR_REPLRECFMT);
+error_def(ERR_JNLSETDATA2LONG);
+error_def(ERR_JNLNEWREC);
+error_def(ERR_REPLGBL2LONG);
+error_def(ERR_SECNODZTRIGINTP);
+
+int gtmsource_process(void)
+{
+ /* The work-horse of the Source Server */
+
+ gtmsource_local_ptr_t gtmsource_local;
+ jnlpool_ctl_ptr_t jctl;
+ seq_num recvd_seqno, sav_read_jnl_seqno;
+ seq_num recvd_jnl_seqno, tmp_read_jnl_seqno;
+ int data_len, srch_status, poll_time;
+ unsigned char *msg_ptr; /* needed for REPL_{SEND,RECV}_LOOP */
+ int tosend_len, sent_len, sent_this_iter; /* needed for REPL_SEND_LOOP */
+ int torecv_len, recvd_len, recvd_this_iter; /* needed for REPL_RECV_LOOP */
+ int status; /* needed for REPL_{SEND,RECV}_LOOP */
+ int tot_tr_len, send_tr_len, remaining_len;
+ int recvd_msg_type, recvd_start_flags;
+ repl_msg_t xoff_ack;
+ repl_msg_ptr_t send_msgp;
+ uchar_ptr_t in_buff, out_buff, out_buffmsg;
+ uint4 in_buflen, in_size, out_size, tot_out_size, pre_intlfilter_datalen;
+ seq_num log_seqno, diff_seqno, pre_read_jnl_seqno, post_read_jnl_seqno, jnl_seqno;
+ char err_string[1024];
+ boolean_t xon_wait_logged;
+ double time_elapsed;
+ seq_num resync_seqno, old_resync_seqno, curr_seqno, filter_seqno;
+ gd_region *reg, *region_top, *gtmsource_upd_reg, *old_upd_reg;
+ sgmnt_addrs *csa;
+ boolean_t was_crit;
+ uint4 temp_dw, out_bufsiz, out_buflen;
+ qw_num backlog_bytes, backlog_count;
+ long prev_msg_sent = 0;
+ time_t prev_now = 0, save_now;
+ int index;
+ uint4 temp_ulong;
+ DEBUG_ONLY(uchar_ptr_t save_inbuff;)
+ DEBUG_ONLY(uchar_ptr_t save_outbuff;)
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ assert(REPL_MSG_HDRLEN == SIZEOF(jnldata_hdr_struct)); /* necessary for reading multiple transactions from jnlpool in
+ * a single attempt */
+ jctl = jnlpool.jnlpool_ctl;
+ gtmsource_local = jnlpool.gtmsource_local;
+ gtmsource_msgp = NULL;
+ gtmsource_msgbufsiz = MAX_REPL_MSGLEN;
+
+ assert(REPL_POLL_WAIT < MILLISECS_IN_SEC);
+ assert(GTMSOURCE_IDLE_POLL_WAIT < REPL_POLL_WAIT);
+
+ gtmsource_state = GTMSOURCE_WAITING_FOR_CONNECTION;
+ while (TRUE)
+ {
+ gtmsource_stop_heartbeat();
+ gtmsource_reinit_logseqno();
+ if (GTMSOURCE_WAITING_FOR_CONNECTION == gtmsource_state)
+ {
+ gtmsource_est_conn();
+ if (GTMSOURCE_CHANGING_MODE == gtmsource_state)
+ return (SS_NORMAL);
+ repl_log(gtmsource_log_fp, TRUE, TRUE, "Connected to secondary, using TCP send buffer size %d "
+ "receive buffer size %d\n", repl_max_send_buffsize, repl_max_recv_buffsize);
+ repl_source_data_sent = repl_source_msg_sent = 0;
+ repl_source_lastlog_data_sent = 0;
+ repl_source_lastlog_msg_sent = 0;
+
+ gtmsource_alloc_msgbuff(MAX_REPL_MSGLEN);
+ gtmsource_state = GTMSOURCE_WAITING_FOR_RESTART;
+ repl_source_prev_log_time = time(NULL);
+ }
+ if (GTMSOURCE_WAITING_FOR_RESTART == gtmsource_state &&
+ SS_NORMAL != (status = gtmsource_recv_restart(&recvd_seqno, &recvd_msg_type, &recvd_start_flags)))
+ {
+ if (EREPL_RECV == repl_errno)
+ {
+ if (REPL_CONN_RESET(status))
+ {
+ /* Connection reset */
+ repl_log(gtmsource_log_fp, TRUE, TRUE,
+ "Connection reset while receiving restart SEQNO. Status = %d ; %s\n",
+ status, STRERROR(status));
+ repl_close(>msource_sock_fd);
+ SHORT_SLEEP(GTMSOURCE_WAIT_FOR_RECEIVER_CLOSE_CONN);
+ gtmsource_state = GTMSOURCE_WAITING_FOR_CONNECTION;
+ continue;
+ } else
+ {
+ SNPRINTF(err_string, SIZEOF(err_string),
+ "Error receiving RESTART SEQNO. Error in recv : %s", STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_STR(err_string));
+ }
+ } else if (EREPL_SEND == repl_errno)
+ {
+ if (REPL_CONN_RESET(status))
+ {
+ repl_log(gtmsource_log_fp, TRUE, TRUE,
+ "Connection reset while sending XOFF_ACK due to possible update process shutdown. "
+ "Status = %d ; %s\n", status, STRERROR(status));
+ repl_close(>msource_sock_fd);
+ SHORT_SLEEP(GTMSOURCE_WAIT_FOR_RECEIVER_CLOSE_CONN);
+ gtmsource_state = GTMSOURCE_WAITING_FOR_CONNECTION;
+ continue;
+ }
+ SNPRINTF(err_string, SIZEOF(err_string), "Error sending XOFF_ACK_ME message. Error in send : %s",
+ STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_STR(err_string));
+ } else if (EREPL_SELECT == repl_errno)
+ {
+ SNPRINTF(err_string, SIZEOF(err_string), "Error receiving RESTART SEQNO/sending XOFF_ACK_ME. "
+ "Error in select : %s", STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_STR(err_string));
+ }
+ }
+ if (GTMSOURCE_CHANGING_MODE == gtmsource_state)
+ return (SS_NORMAL);
+
+ QWASSIGN(sav_read_jnl_seqno, gtmsource_local->read_jnl_seqno);
+ if (GTMSOURCE_SEARCHING_FOR_RESTART == gtmsource_state || REPL_START_JNL_SEQNO == recvd_msg_type)
+ {
+ assert(gtmsource_state == GTMSOURCE_SEARCHING_FOR_RESTART ||
+ gtmsource_state == GTMSOURCE_WAITING_FOR_RESTART);
+ gtmsource_state = GTMSOURCE_SEARCHING_FOR_RESTART;
+ if (SS_NORMAL == (srch_status = gtmsource_srch_restart(recvd_seqno, recvd_start_flags)))
+ {
+ repl_log(gtmsource_log_fp, TRUE, TRUE, "Sending REPL_WILL_RESTART\n");
+ memset(gtmsource_msgp, 0, MIN_REPL_MSGLEN); /* to idenitify older releases in the future */
+ gtmsource_msgp->type = REPL_WILL_RESTART_WITH_INFO;
+ ((repl_start_reply_msg_ptr_t)gtmsource_msgp)->jnl_ver = jnl_ver;
+ temp_ulong = (0 == primary_side_std_null_coll) ? START_FLAG_NONE : START_FLAG_COLL_M;
+ temp_ulong |= START_FLAG_SRCSRV_IS_VMS;
+ PUT_ULONG(((repl_start_reply_msg_ptr_t)gtmsource_msgp)->start_flags, temp_ulong);
+ recvd_start_flags = START_FLAG_NONE;
+ } else /* srch_restart returned EREPL_SEC_AHEAD */
+ {
+ assert(EREPL_SEC_AHEAD == srch_status);
+ gtmsource_msgp->type = REPL_ROLLBACK_FIRST;
+ repl_log(gtmsource_log_fp, TRUE, TRUE, "Sending REPL_ROLLBACK_FIRST\n");
+ }
+ } else
+ {
+ /* REPL_FETCH_RESYNC received and state is WAITING_FOR_RESTART */
+ assert(GTMSOURCE_WAITING_FOR_RESTART == gtmsource_state && REPL_FETCH_RESYNC == recvd_msg_type);
+ gtmsource_msgp->type = REPL_RESYNC_SEQNO;
+ }
+
+ QWASSIGN(*(seq_num *)&((repl_start_reply_msg_ptr_t)gtmsource_msgp)->start_seqno[0],
+ gtmsource_local->read_jnl_seqno);
+ gtmsource_msgp->len = MIN_REPL_MSGLEN;
+ REPL_SEND_LOOP(gtmsource_sock_fd, gtmsource_msgp, gtmsource_msgp->len, REPL_POLL_NOWAIT)
+ {
+ gtmsource_poll_actions(FALSE);
+ if (GTMSOURCE_CHANGING_MODE == gtmsource_state)
+ return (SS_NORMAL);
+ }
+ if (SS_NORMAL != status)
+ {
+ if (REPL_CONN_RESET(status) && EREPL_SEND == repl_errno)
+ {
+ repl_log(gtmsource_log_fp, TRUE, TRUE,
+ "Connection reset while sending REPL_WILL_RESTART/RESYNC_SEQNO. "
+ "Status = %d ; %s\n", status, STRERROR(status));
+ repl_close(>msource_sock_fd);
+ SHORT_SLEEP(GTMSOURCE_WAIT_FOR_RECEIVER_CLOSE_CONN);
+ gtmsource_state = GTMSOURCE_WAITING_FOR_CONNECTION;
+ continue;
+ }
+ if (EREPL_SEND == repl_errno)
+ {
+ SNPRINTF(err_string, SIZEOF(err_string), "Error sending ROLLBACK FIRST message. Error in send : %s",
+ STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_STR(err_string));
+ }
+ if (EREPL_SELECT == repl_errno)
+ {
+ SNPRINTF(err_string, SIZEOF(err_string), "Error sending ROLLBACK FIRST message. "
+ "Error in select : %s", STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_STR(err_string));
+ }
+ }
+ if (REPL_WILL_RESTART_WITH_INFO != gtmsource_msgp->type)
+ {
+ assert(gtmsource_msgp->type == REPL_RESYNC_SEQNO || gtmsource_msgp->type == REPL_ROLLBACK_FIRST);
+ if (REPL_RESYNC_SEQNO == gtmsource_msgp->type)
+ {
+ repl_log(gtmsource_log_fp, TRUE, TRUE, "RESYNC_SEQNO msg sent with SEQNO "INT8_FMT"\n",
+ (*(seq_num *)>msource_msgp->msg[0]));
+ QWASSIGN(resync_seqno, recvd_seqno);
+ if (QWLE(gtmsource_local->read_jnl_seqno, resync_seqno))
+ QWASSIGN(resync_seqno, gtmsource_local->read_jnl_seqno);
+ QWASSIGN(old_resync_seqno, seq_num_zero);
+ QWASSIGN(curr_seqno, seq_num_zero);
+ region_top = gd_header->regions + gd_header->n_regions;
+ for (reg = gd_header->regions; reg < region_top; reg++)
+ {
+ csa = &FILE_INFO(reg)->s_addrs;
+ if (REPL_ALLOWED(csa->hdr))
+ {
+ if (QWLT(old_resync_seqno, csa->hdr->old_resync_seqno))
+ QWASSIGN(old_resync_seqno, csa->hdr->old_resync_seqno);
+ if (QWLT(curr_seqno, csa->hdr->reg_seqno))
+ QWASSIGN(curr_seqno, csa->hdr->reg_seqno);
+ }
+ }
+ assert(QWNE(old_resync_seqno, seq_num_zero));
+ REPL_DPRINT2("BEFORE FINDING RESYNC - old_resync_seqno is "INT8_FMT, old_resync_seqno);
+ REPL_DPRINT2(", curr_seqno is "INT8_FMT"\n", curr_seqno);
+ if (QWNE(old_resync_seqno, resync_seqno))
+ {
+ assert(QWGE(curr_seqno, gtmsource_local->read_jnl_seqno));
+ QWDECRBY(resync_seqno, seq_num_one);
+ gtmsource_update_resync_tn(resync_seqno);
+ region_top = gd_header->regions + gd_header->n_regions;
+ for (reg = gd_header->regions; reg < region_top; reg++)
+ {
+ csa = &FILE_INFO(reg)->s_addrs;
+ if (REPL_ALLOWED(csa->hdr))
+ {
+ REPL_DPRINT4("Assigning "INT8_FMT" to old_resyc_seqno of %s. Prev value "
+ INT8_FMT"\n", resync_seqno, reg->rname, csa->hdr->old_resync_seqno);
+ /* Although csa->hdr->old_resync_seqno is only modified by the source
+ * server and never concurremntly, it is read by fileheader_sync() which
+ * does it while in crit. To avoid the latter from reading an inconsistent
+ * value (i.e. neither the pre-update nor the post-update value, which is
+ * possible if the 8-byte operation is not atomic but a sequence of two
+ * 4-byte operations AND if the pre-update and post-update value differ in
+ * their most significant 4-bytes) we grab crit. We could have used the
+ * QWCHANGE_IS_READER_CONSISTENT macro (which checks for most significant
+ * 4-byte differences) instead to determine if it is really necessary to
+ * grab crit. But since the update to old_resync_seqno is a rare operation,
+ * we decide to play it safe.
+ */
+ if (FALSE == (was_crit = csa->now_crit))
+ grab_crit(reg);
+ QWASSIGN(csa->hdr->old_resync_seqno, resync_seqno);
+ if (FALSE == was_crit)
+ rel_crit(reg);
+ }
+ }
+ }
+ }
+
+ /* Could send a REPL_CLOSE_CONN message here */
+
+ /*
+ * It is expected that on receiving this msg, the
+ * Receiver Server will break the connection and exit.
+ */
+
+ repl_close(>msource_sock_fd);
+ LONG_SLEEP(GTMSOURCE_WAIT_FOR_RECEIVER_TO_QUIT); /* may not be needed after REPL_CLOSE_CONN is sent */
+ gtmsource_state = GTMSOURCE_WAITING_FOR_CONNECTION;
+ continue;
+ }
+
+ if (QWLT(gtmsource_local->read_jnl_seqno, sav_read_jnl_seqno) && NULL != repl_ctl_list)
+ {
+ /* The journal files may have been positioned ahead of
+ * the read_jnl_seqno for the next read. Indicate that
+ * they have to be repositioned into the past.
+ */
+ assert(READ_FILE == gtmsource_local->read_state);
+ gtmsource_set_lookback();
+ }
+
+ /* The variable poll_time indicates if we should wait for the receive pipe to be I/O ready and should be set to
+ * a non-zero value ONLY if the source server has nothing to send. At this point we have data to send and so
+ * set poll_time to no-wait.
+ */
+ poll_time = REPL_POLL_NOWAIT;
+ gtmsource_state = GTMSOURCE_SENDING_JNLRECS;
+ gtmsource_init_heartbeat();
+
+ if ((jnl_ver >= remote_jnl_ver) && (IF_NONE != repl_filter_cur2old[remote_jnl_ver - JNL_VER_EARLIEST_REPL]))
+ {
+ assert(IF_INVALID != repl_filter_cur2old[remote_jnl_ver - JNL_VER_EARLIEST_REPL]);
+ assert(IF_INVALID != repl_filter_old2cur[remote_jnl_ver - JNL_VER_EARLIEST_REPL]);
+ /* reverse transformation should exist */
+ assert(IF_NONE != repl_filter_old2cur[remote_jnl_ver - JNL_VER_EARLIEST_REPL]);
+ if (FALSE != ((TREF(replgbl)).null_subs_xform = (primary_side_std_null_coll &&
+ !secondary_side_std_null_coll || secondary_side_std_null_coll &&
+ !primary_side_std_null_coll)))
+ (TREF(replgbl)).null_subs_xform = (primary_side_std_null_coll ?
+ STDNULL_TO_GTMNULL_COLL : GTMNULL_TO_STDNULL_COLL);
+ /* note that if jnl_ver == remote_jnl_ver and jnl_ver > V15_JNL_VER, the two sides may be running
+ * different null collation. However, we leave the overhead of null collation transformation to
+ * the receiver as source server is generally more loaded than the receiver
+ */
+ gtmsource_filter |= INTERNAL_FILTER;
+ gtmsource_alloc_filter_buff(gtmsource_msgbufsiz);
+ } else
+ {
+ gtmsource_filter &= ~INTERNAL_FILTER;
+ if (NO_FILTER == gtmsource_filter)
+ gtmsource_free_filter_buff();
+ }
+ xon_wait_logged = FALSE;
+ gtmsource_upd_reg = gtmsource_mru_reg = NULL;
+ for (reg = gd_header->regions, region_top = gd_header->regions + gd_header->n_regions; reg < region_top; reg++)
+ {
+ csa = &FILE_INFO(reg)->s_addrs;
+ if (REPL_ALLOWED(csa->hdr))
+ {
+ if (NULL == gtmsource_upd_reg)
+ gtmsource_upd_reg = gtmsource_mru_reg = reg;
+ else if (csa->hdr->reg_seqno > FILE_INFO(gtmsource_mru_reg)->s_addrs.hdr->reg_seqno)
+ gtmsource_mru_reg = reg;
+ }
+ }
+ /* source server startup and change of mode flush all regions, so we are okay to consider the current state
+ * as completely flushed */
+ gtmsource_last_flush_time = gtmsource_now;
+ gtmsource_last_flush_reg_seq = jctl->jnl_seqno;
+ gtmsource_last_flush_resync_seq = gtmsource_local->read_jnl_seqno;
+ prev_now = gtmsource_now;
+ while (TRUE)
+ {
+ gtmsource_poll_actions(TRUE);
+ if (GTMSOURCE_CHANGING_MODE == gtmsource_state)
+ return (SS_NORMAL);
+ if (GTMSOURCE_WAITING_FOR_CONNECTION == gtmsource_state)
+ break;
+ if (prev_now != gtmsource_now)
+ {
+ prev_now = gtmsource_now;
+ if (gtmsource_msgbufsiz - MAX_REPL_MSGLEN > 2 * OS_PAGE_SIZE)
+ { /* We have expanded the buffer by too much (could have been avoided had we sent one
+ * transaction at a time while reading from journal files); let's revert back to our
+ * initial buffer size. If we don't reduce our buffer, it is possible that the buffer keeps
+ * growing (while reading * from journal file) thus making the size of sends while reading
+ * from journal pool very large (> 1 MB).
+ */
+ gtmsource_free_filter_buff();
+ gtmsource_free_msgbuff();
+ gtmsource_alloc_msgbuff(MAX_REPL_MSGLEN); /* will also allocate filter buffer */
+ }
+ }
+ /* Check if receiver sent us any control message. Typically, the traffic from receiver to source is very
+ * low compared to traffic in the other direction. More often than not, there will be nothing on the pipe
+ * to receive. Ideally, we should let TCP notify us when there is data on the pipe (async I/O on Unix and
+ * VMS). But, we are not there yet. Since we do a select() before a recv(), we won't block if there is
+ * nothing in the pipe. So, it shouldn't be an expensive operation even if done before every send. Also,
+ * in doing so, we react to an XOFF sooner than later.
+ */
+ /* Make sure we don't sleep for a longer duration if there is something to be sent across */
+ assert((GTMSOURCE_SENDING_JNLRECS != gtmsource_state)
+ || ((0 == poll_time) || (GTMSOURCE_IDLE_POLL_WAIT == poll_time)));
+ REPL_RECV_LOOP(gtmsource_sock_fd, gtmsource_msgp, MIN_REPL_MSGLEN, poll_time)
+ {
+ if (0 == recvd_len) /* nothing received in the first attempt, let's try again later */
+ break;
+ gtmsource_poll_actions(TRUE);
+ if (GTMSOURCE_CHANGING_MODE == gtmsource_state)
+ return (SS_NORMAL);
+ if (GTMSOURCE_WAITING_FOR_CONNECTION == gtmsource_state)
+ break;
+ }
+ if ((SS_NORMAL == status) && (0 != recvd_len))
+ { /* Process the received control message */
+ switch(gtmsource_msgp->type)
+ {
+ case REPL_XOFF:
+ case REPL_XOFF_ACK_ME:
+ gtmsource_state = GTMSOURCE_WAITING_FOR_XON;
+ poll_time = REPL_POLL_WAIT; /* because we are waiting for a REPL_XON */
+ repl_log(gtmsource_log_fp, TRUE, TRUE,
+ "REPL_XOFF/REPL_XOFF_ACK_ME received. Send stalled...\n");
+ xon_wait_logged = FALSE;
+ if (REPL_XOFF_ACK_ME == gtmsource_msgp->type)
+ {
+ xoff_ack.type = REPL_XOFF_ACK;
+ QWASSIGN(*(seq_num *)&xoff_ack.msg[0], *(seq_num *)>msource_msgp->msg[0]);
+ xoff_ack.len = MIN_REPL_MSGLEN;
+ REPL_SEND_LOOP(gtmsource_sock_fd, &xoff_ack, xoff_ack.len, REPL_POLL_NOWAIT)
+ {
+ gtmsource_poll_actions(FALSE);
+ if (GTMSOURCE_CHANGING_MODE == gtmsource_state)
+ return (SS_NORMAL);
+ }
+ if (SS_NORMAL == status)
+ {
+ repl_log(gtmsource_log_fp, TRUE, TRUE, "REPL_XOFF_ACK sent...\n");
+ } else
+ {
+ if (REPL_CONN_RESET(status) && EREPL_SEND == repl_errno)
+ {
+ repl_log(gtmsource_log_fp, TRUE, TRUE,
+ "Connection reset while sending REPL_XOFF_ACK. "
+ "Status = %d ; %s\n", status, STRERROR(status));
+ repl_close(>msource_sock_fd);
+ gtmsource_state = GTMSOURCE_WAITING_FOR_CONNECTION;
+ break;
+ }
+ if (EREPL_SEND == repl_errno)
+ {
+ SNPRINTF(err_string, SIZEOF(err_string),
+ "Error sending REPL_XOFF_ACK_ME. "
+ "Error in send : %s",
+ STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0,
+ ERR_TEXT, 2,
+ LEN_AND_STR(err_string));
+ }
+ if (EREPL_SELECT == repl_errno)
+ {
+ SNPRINTF(err_string, SIZEOF(err_string),
+ "Error sending REPL_XOFF_ACK_ME. "
+ "Error in select : %s",
+ STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0,
+ ERR_TEXT, 2, LEN_AND_STR(err_string));
+ }
+ }
+ }
+ break;
+
+ case REPL_XON:
+ gtmsource_state = GTMSOURCE_SENDING_JNLRECS;
+ poll_time = REPL_POLL_NOWAIT; /* because we received XON and data ready for send */
+ repl_log(gtmsource_log_fp, TRUE, TRUE, "REPL_XON received\n");
+ heartbeat_stalled = FALSE;
+ REPL_DPRINT1("Restarting HEARTBEAT\n");
+ break;
+
+ case REPL_BADTRANS:
+ case REPL_START_JNL_SEQNO:
+ QWASSIGN(recvd_seqno, *(seq_num *)>msource_msgp->msg[0]);
+ gtmsource_state = GTMSOURCE_SEARCHING_FOR_RESTART;
+ if (REPL_BADTRANS == gtmsource_msgp->type)
+ {
+ repl_log(gtmsource_log_fp, TRUE, TRUE,
+ "REPL_BADTRANS received with SEQNO "INT8_FMT"\n", recvd_seqno);
+ } else
+ {
+ recvd_start_flags = ((repl_start_msg_ptr_t)gtmsource_msgp)->start_flags;
+ repl_log(gtmsource_log_fp, TRUE, TRUE,
+ "REPL_START_JNL_SEQNO received with SEQNO "INT8_FMT". Possible "
+ "crash of recvr/update process\n", recvd_seqno);
+ }
+ break;
+
+ case REPL_HEARTBEAT:
+ gtmsource_process_heartbeat((repl_heartbeat_msg_t *)gtmsource_msgp);
+ break;
+ default:
+ repl_log(gtmsource_log_fp, TRUE, TRUE, "Message of unknown type %d length %d"
+ "received, hex dump follows\n", gtmsource_msgp->type, recvd_len);
+ for (index = 0; index < MIN(recvd_len, gtmsource_msgbufsiz - REPL_MSG_HDRLEN); )
+ {
+ repl_log(gtmsource_log_fp, FALSE, FALSE, "%.2x ",
+ gtmsource_msgp->msg[index]);
+ if ((++index) % MAX_HEXDUMP_CHARS_PER_LINE == 0)
+ repl_log(gtmsource_log_fp, FALSE, FALSE, "\n");
+ }
+ assert(FALSE);
+ break;
+ }
+ } else if (SS_NORMAL != status)
+ {
+ if (EREPL_RECV == repl_errno)
+ {
+ if (REPL_CONN_RESET(status))
+ {
+ /* Connection reset */
+ repl_log(gtmsource_log_fp, TRUE, TRUE,
+ "Connection reset while attempting to receive from secondary. "
+ "Status = %d ; %s\n", status, STRERROR(status));
+ repl_close(>msource_sock_fd);
+ SHORT_SLEEP(GTMSOURCE_WAIT_FOR_RECEIVER_CLOSE_CONN);
+ gtmsource_state = GTMSOURCE_WAITING_FOR_CONNECTION;
+ break;
+ } else
+ {
+ SNPRINTF(err_string, SIZEOF(err_string),
+ "Error receiving Control message from Receiver. Error in recv : %s",
+ STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_STR(err_string));
+ }
+ } else if (EREPL_SELECT == repl_errno)
+ {
+ SNPRINTF(err_string, SIZEOF(err_string),
+ "Error receiving Control message from Receiver. Error in select : %s",
+ STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_STR(err_string));
+ }
+ }
+ if (GTMSOURCE_WAITING_FOR_XON == gtmsource_state)
+ {
+ if (!xon_wait_logged)
+ {
+ repl_log(gtmsource_log_fp, TRUE, TRUE, "Waiting to receive XON\n");
+ heartbeat_stalled = TRUE;
+ REPL_DPRINT1("Stalling HEARTBEAT\n");
+ xon_wait_logged = TRUE;
+ }
+ continue;
+ }
+ if (GTMSOURCE_SEARCHING_FOR_RESTART == gtmsource_state ||
+ GTMSOURCE_WAITING_FOR_CONNECTION == gtmsource_state)
+ break;
+ assert(gtmsource_state == GTMSOURCE_SENDING_JNLRECS);
+ pre_read_jnl_seqno = gtmsource_local->read_jnl_seqno;
+ tot_tr_len = gtmsource_get_jnlrecs(>msource_msgp->msg[0], &data_len,
+ gtmsource_msgbufsiz - REPL_MSG_HDRLEN,
+ !(gtmsource_filter & EXTERNAL_FILTER));
+ post_read_jnl_seqno = gtmsource_local->read_jnl_seqno;
+ if (GTMSOURCE_CHANGING_MODE == gtmsource_state)
+ return (SS_NORMAL);
+ if (GTMSOURCE_WAITING_FOR_CONNECTION == gtmsource_state)
+ break;
+ if (0 <= tot_tr_len)
+ {
+ if (0 < data_len)
+ {
+ APPLY_EXT_FILTER_IF_NEEDED(gtmsource_filter, gtmsource_msgp, data_len, tot_tr_len);
+ gtmsource_msgp->type = REPL_TR_JNL_RECS;
+ gtmsource_msgp->len = data_len + REPL_MSG_HDRLEN;
+ send_msgp = gtmsource_msgp;
+ send_tr_len = tot_tr_len;
+ if (gtmsource_filter & INTERNAL_FILTER)
+ {
+ in_buff = gtmsource_msgp->msg;
+ in_buflen = data_len; /* size of the first journal record in the converted buffer */
+ out_buffmsg = repl_filter_buff;
+ out_buff = out_buffmsg + REPL_MSG_HDRLEN;
+ out_bufsiz = repl_filter_bufsiz - REPL_MSG_HDRLEN;
+ remaining_len = tot_tr_len;
+ while (JREC_PREFIX_SIZE <= remaining_len)
+ {
+ filter_seqno = ((struct_jrec_null *)(in_buff))->jnl_seqno;
+ DEBUG_ONLY(
+ save_inbuff = in_buff;
+ save_outbuff = out_buff;
+ )
+ APPLY_INT_FILTER(in_buff, in_buflen, out_buff, out_buflen,
+ out_bufsiz, status);
+ /* Internal filters should not modify the incoming pointers. Assert that. */
+ assert((save_inbuff == in_buff) && (save_outbuff == out_buff));
+ if (SS_NORMAL == status)
+ { /* adjust various pointers and book-keeping values to move to next
+ * record.
+ */
+ ((repl_msg_ptr_t)(out_buffmsg))->type = REPL_TR_JNL_RECS;
+ ((repl_msg_ptr_t)(out_buffmsg))->len = out_buflen + REPL_MSG_HDRLEN;
+ out_buffmsg = (out_buff + out_buflen);
+ remaining_len -= (in_buflen + REPL_MSG_HDRLEN);
+ assert(0 <= remaining_len);
+ if (0 >= remaining_len)
+ break;
+ in_buff += in_buflen;
+ in_buflen = ((repl_msg_ptr_t)(in_buff))->len - REPL_MSG_HDRLEN;
+ in_buff += REPL_MSG_HDRLEN;
+ out_buff = (out_buffmsg + REPL_MSG_HDRLEN);
+ out_bufsiz -= (out_buflen + REPL_MSG_HDRLEN);
+ assert(0 <= (int)out_bufsiz);
+ } else if (EREPL_INTLFILTER_NOSPC == repl_errno)
+ {
+ REALLOCATE_INT_FILTER_BUFF(out_buff, out_buffmsg, out_bufsiz);
+ /* note that in_buff and in_buflen is not changed so that we can
+ * start from where we left
+ */
+ } else
+ {
+ INT_FILTER_RTS_ERROR(filter_seqno);
+ }
+ }
+ assert(0 == remaining_len);
+ send_msgp = (repl_msg_ptr_t)repl_filter_buff;
+ send_tr_len = out_buffmsg - repl_filter_buff;
+ }
+ /* ensure that the head of the buffer has the correct type and len */
+ assert(REPL_TR_JNL_RECS == send_msgp->type);
+ assert(0 == (send_msgp->len % JNL_REC_START_BNDRY));
+ assert(send_tr_len && (0 == (send_tr_len % REPL_MSG_HDRLEN)));
+ /* The following loop tries to send multiple seqnos in one shot. resync_seqno gets
+ * updated once the send is completely successful. If an error occurs in the middle
+ * of the send, it is possible that we successfully sent a few seqnos to the other side.
+ * In this case resync_seqno should be updated to reflect those seqnos. Not doing so
+ * might cause the secondary to get ahead of the primary in terms of resync_seqno.
+ * Although it is possible to determine the exact seqno where the send partially failed,
+ * we update resync_seqno as if all seqnos were successfully sent (It is ok for the
+ * resync_seqno on the primary side to be a little more than the actual value as long as
+ * the secondary side has an accurate value of resync_seqno. This is because the
+ * resync_seqno of the system is the minimum of the resync_seqno of both primary
+ * and secondary). This is done by the call to gtmsource_flush_fh() done within the
+ * REPL_SEND_LOOP macro as well as in the (SS_NORMAL != status) if condition below.
+ */
+ REPL_SEND_LOOP(gtmsource_sock_fd, send_msgp, send_tr_len, REPL_POLL_WAIT)
+ {
+ gtmsource_poll_actions(FALSE);
+ if (GTMSOURCE_CHANGING_MODE == gtmsource_state)
+ {
+ gtmsource_flush_fh(post_read_jnl_seqno);
+ return (SS_NORMAL);
+ }
+ }
+ if (SS_NORMAL != status)
+ {
+ gtmsource_flush_fh(post_read_jnl_seqno);
+ if (REPL_CONN_RESET(status) && EREPL_SEND == repl_errno)
+ {
+ repl_log(gtmsource_log_fp, TRUE, TRUE,
+ "Connection reset while sending transaction data from "
+ INT8_FMT" to "INT8_FMT". Status = %d ; %s\n", pre_read_jnl_seqno,
+ post_read_jnl_seqno, status, STRERROR(status));
+ repl_close(>msource_sock_fd);
+ SHORT_SLEEP(GTMSOURCE_WAIT_FOR_RECEIVER_CLOSE_CONN);
+ gtmsource_state = GTMSOURCE_WAITING_FOR_CONNECTION;
+ break;
+ }
+ if (EREPL_SEND == repl_errno)
+ {
+ SNPRINTF(err_string, SIZEOF(err_string),
+ "Error sending DATA. Error in send : %s", STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_STR(err_string));
+ }
+ if (EREPL_SELECT == repl_errno)
+ {
+ SNPRINTF(err_string, SIZEOF(err_string),
+ "Error sending DATA. Error in select : %s", STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_STR(err_string));
+ }
+ }
+ /* Record the "last sent seqno" in file header of most recently updated region and one
+ * region picked in round robin order. Updating one region is sufficient since the
+ * system's resync_seqno is computed to be the maximum of file header resync_seqno
+ * across all regions. We choose to update multiple regions to increase the odds of
+ * not losing information in case of a system crash
+ */
+ UPDATE_RESYNC_SEQNO(gtmsource_mru_reg, pre_read_jnl_seqno, post_read_jnl_seqno);
+ if (gtmsource_mru_reg != gtmsource_upd_reg)
+ UPDATE_RESYNC_SEQNO(gtmsource_upd_reg, pre_read_jnl_seqno, post_read_jnl_seqno);
+ old_upd_reg = gtmsource_upd_reg;
+ do
+ { /* select next region in round robin order */
+ gtmsource_upd_reg++;
+ if (gtmsource_upd_reg >= gd_header->regions + gd_header->n_regions)
+ gtmsource_upd_reg = gd_header->regions; /* wrap back to first region */
+ } while (gtmsource_upd_reg != old_upd_reg && /* back to the original region? */
+ !REPL_ALLOWED(FILE_INFO(gtmsource_upd_reg)->s_addrs.hdr));
+ save_now = gtmsource_now;
+ if (GTMSOURCE_FH_FLUSH_INTERVAL <= difftime(save_now, gtmsource_last_flush_time))
+ {
+ gtmsource_flush_fh(post_read_jnl_seqno);
+ gtmsource_last_flush_time = save_now;
+ }
+
+ repl_source_msg_sent += (qw_num)send_tr_len;
+ repl_source_data_sent += (qw_num)(send_tr_len) -
+ (post_read_jnl_seqno - pre_read_jnl_seqno) * REPL_MSG_HDRLEN;
+ log_seqno = post_read_jnl_seqno - 1; /* post_read_jnl_seqno is the "next" seqno to be sent,
+ * not the last one we sent */
+ if (log_seqno - lastlog_seqno >= log_interval || gtmsource_logstats)
+ { /* print always when STATSLOG is ON, or when the log interval has passed */
+ trans_sent_cnt += (log_seqno - lastlog_seqno);
+ /* jctl->jnl_seqno >= post_read_jnl_seqno is the most common case;
+ * see gtmsource_readpool() for when the rare case can occur */
+ jnl_seqno = jctl->jnl_seqno;
+ assert(jnl_seqno >= post_read_jnl_seqno - 1);
+ diff_seqno = (jnl_seqno >= post_read_jnl_seqno) ?
+ (jnl_seqno - post_read_jnl_seqno) : 0;
+ repl_log(gtmsource_log_fp, TRUE, FALSE, "REPL INFO - Seqno : "INT8_FMT, log_seqno);
+ repl_log(gtmsource_log_fp, FALSE, FALSE, " Jnl Total : "INT8_FMT" Msg Total : "
+ INT8_FMT" ", repl_source_data_sent, repl_source_msg_sent);
+ repl_log(gtmsource_log_fp, FALSE, TRUE, "Current backlog : "INT8_FMT"\n",
+ diff_seqno);
+ /* gtmsource_now is updated by the heartbeat protocol every heartbeat
+ * interval. To cut down on calls to time(), we use gtmsource_now as the
+ * time to figure out if we have to log statistics. This works well as the
+ * logging interval generally is larger than the heartbeat interval, and that
+ * the heartbeat protocol is running when we are sending data. The consequence
+ * although is that we may defer logging when we would have logged. We can live
+ * with that given the benefit of not calling time related system calls.
+ * Currently, the logging interval is not changeable by users. When/if we provide
+ * means of choosing log interval, this code may have to be re-examined.
+ * Vinaya 2003, Sep 08
+ */
+ assert(0 != gtmsource_now); /* must hold if we are sending data */
+ repl_source_this_log_time = gtmsource_now; /* approximate time, in the worst case,
+ * behind by heartbeat interval */
+ assert(repl_source_this_log_time >= repl_source_prev_log_time);
+ time_elapsed = difftime(repl_source_this_log_time, repl_source_prev_log_time);
+ if ((double)GTMSOURCE_LOGSTATS_INTERVAL <= time_elapsed)
+ {
+ repl_log(gtmsource_log_fp, TRUE, TRUE, "REPL INFO since last log : "
+ "Time elapsed : %00.f Tr sent : "INT8_FMT" Tr bytes : "
+ INT8_FMT" Msg bytes : "INT8_FMT"\n",
+ time_elapsed, trans_sent_cnt - last_log_tr_sent_cnt,
+ repl_source_data_sent - repl_source_lastlog_data_sent,
+ repl_source_msg_sent - repl_source_lastlog_msg_sent);
+ repl_log(gtmsource_log_fp, TRUE, TRUE, "REPL INFO since last log : "
+ "Time elapsed : %00.f Tr sent/s : %f Tr bytes/s : %f "
+ "Msg bytes/s : %f\n", time_elapsed,
+ (float)(trans_sent_cnt - last_log_tr_sent_cnt)/time_elapsed,
+ (float)(repl_source_data_sent - repl_source_lastlog_data_sent) /
+ time_elapsed,
+ (float)(repl_source_msg_sent - repl_source_lastlog_msg_sent) /
+ time_elapsed);
+ repl_source_lastlog_data_sent = repl_source_data_sent;
+ repl_source_lastlog_msg_sent = repl_source_msg_sent;
+ last_log_tr_sent_cnt = trans_sent_cnt;
+ repl_source_prev_log_time = repl_source_this_log_time;
+ }
+ lastlog_seqno = log_seqno;
+ }
+ /* Because we sent data to the other side and there might be more to be sent across, don't
+ * wait for the receive pipe to be ready.
+ */
+ poll_time = REPL_POLL_NOWAIT;
+ } else /* data_len == 0 */
+ { /* nothing to send */
+ gtmsource_flush_fh(post_read_jnl_seqno);
+ /* Sleep for a while (as part of the next REPL_RECV_LOOP) to avoid spinning when there is no
+ * data to be sent
+ */
+ poll_time = GTMSOURCE_IDLE_POLL_WAIT;
+ }
+ } else /* else tot_tr_len < 0, error */
+ {
+ if (0 < data_len) /* Insufficient buffer space, increase the buffer space */
+ gtmsource_alloc_msgbuff(data_len + REPL_MSG_HDRLEN);
+ else
+ GTMASSERT; /* Major problems */
+ }
+ }
+ }
+}
diff --git a/sr_vvms/gtmsource_process_ops.c b/sr_vvms/gtmsource_process_ops.c
new file mode 100644
index 0000000..852abf2
--- /dev/null
+++ b/sr_vvms/gtmsource_process_ops.c
@@ -0,0 +1,740 @@
+/****************************************************************
+ * *
+ * Copyright 2006, 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_socket.h"
+#include "gtm_inet.h"
+#include "gtm_netdb.h"
+#include <sys/time.h>
+#include <errno.h>
+#include "gtm_fcntl.h"
+#include "gtm_unistd.h"
+#include "gtm_stat.h"
+#include "gtm_string.h"
+#include "gtm_stdio.h"
+#include <descrip.h> /* Required for gtmsource.h */
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "repl_msg.h"
+#include "gtmsource.h"
+#include "repl_comm.h"
+#include "jnl.h"
+#include "hashtab_mname.h" /* needed for muprec.h */
+#include "hashtab_int4.h" /* needed for muprec.h */
+#include "hashtab_int8.h" /* needed for muprec.h */
+#include "buddy_list.h"
+#include "muprec.h"
+#include "repl_ctl.h"
+#include "repl_errno.h"
+#include "repl_dbg.h"
+#include "iosp.h"
+#include "gtm_event_log.h"
+#include "gt_timer.h"
+#include "eintr_wrappers.h"
+#include "repl_sp.h"
+#include "repl_filter.h"
+#include "repl_log.h"
+#include "sgtm_putmsg.h"
+#include "min_max.h"
+#include "error.h"
+
+GBLREF gd_addr *gd_header;
+GBLREF jnlpool_addrs jnlpool;
+GBLREF int gtmsource_sock_fd;
+GBLREF seq_num gtmsource_save_read_jnl_seqno;
+GBLREF gtmsource_state_t gtmsource_state;
+GBLREF repl_msg_ptr_t gtmsource_msgp;
+GBLREF int gtmsource_msgbufsiz;
+GBLREF unsigned char *gtmsource_tcombuff_start;
+GBLREF unsigned char *gtmsource_tcombuffp;
+GBLREF int gtmsource_log_fd;
+GBLREF FILE *gtmsource_log_fp;
+GBLREF boolean_t gtmsource_logstats;
+GBLREF int gtmsource_filter;
+GBLREF seq_num seq_num_zero;
+GBLREF unsigned char jnl_ver, remote_jnl_ver;
+GBLREF uchar_ptr_t repl_filter_buff;
+GBLREF int repl_filter_bufsiz;
+GBLREF boolean_t gtmsource_pool2file_transition;
+GBLREF repl_ctl_element *repl_ctl_list;
+GBLREF int repl_max_send_buffsize, repl_max_recv_buffsize;
+GBLREF boolean_t secondary_side_std_null_coll;
+GBLREF boolean_t secondary_side_trigger_support;
+
+error_def(ERR_REPLCOMM);
+error_def(ERR_REPLWARN);
+error_def(ERR_TEXT);
+error_def(ERR_UNIMPLOP);
+
+static unsigned char *tcombuff, *msgbuff, *filterbuff;
+
+int gtmsource_est_conn()
+{
+ int connection_attempts, alert_attempts, save_errno, status;
+ char print_msg[1024], msg_str[1024];
+ gtmsource_local_ptr_t gtmsource_local;
+ int send_buffsize, recv_buffsize, tcp_s_bufsize;
+ int logging_period, logging_interval; /* logging period = soft_tries_period*logging_interval */
+ int logging_attempts;
+ sockaddr_ptr secondary_sa;
+ int secondary_addrlen;
+
+ gtmsource_local = jnlpool.gtmsource_local;
+ /* Connect to the secondary - use hard tries, soft tries ... */
+ connection_attempts = 0;
+ gtmsource_comm_init(); /* set up gtmsource_loal.secondary_ai */
+ secondary_sa = (sockaddr_ptr)(>msource_local->secondary_inet_addr);
+ secondary_addrlen = gtmsource_local->secondary_addrlen;
+ repl_log(gtmsource_log_fp, TRUE, TRUE, "Connect hard tries count = %d, Connect hard tries period = %d\n",
+ gtmsource_local->connect_parms[GTMSOURCE_CONN_HARD_TRIES_COUNT],
+ gtmsource_local->connect_parms[GTMSOURCE_CONN_HARD_TRIES_PERIOD]);
+ do
+ {
+ status = gtm_connect(gtmsource_sock_fd, secondary_sa, secondary_addrlen);
+ if (0 == status)
+ break;
+ repl_log(gtmsource_log_fp, FALSE, FALSE, "%d hard connection attempt failed : %s\n", connection_attempts + 1,
+ STRERROR(ERRNO));
+ repl_close(>msource_sock_fd);
+ if (REPL_MAX_CONN_HARD_TRIES_PERIOD > jnlpool.gtmsource_local->connect_parms[GTMSOURCE_CONN_HARD_TRIES_PERIOD])
+ SHORT_SLEEP(gtmsource_local->connect_parms[GTMSOURCE_CONN_HARD_TRIES_PERIOD])
+ else
+ LONG_SLEEP(gtmsource_local->connect_parms[GTMSOURCE_CONN_HARD_TRIES_PERIOD] % MILLISECS_IN_SEC);
+ gtmsource_poll_actions(FALSE);
+ if (GTMSOURCE_CHANGING_MODE == gtmsource_state)
+ return (SS_NORMAL);
+ gtmsource_comm_init();
+ } while (++connection_attempts < gtmsource_local->connect_parms[GTMSOURCE_CONN_HARD_TRIES_COUNT]);
+
+ gtmsource_poll_actions(FALSE);
+ if (GTMSOURCE_CHANGING_MODE == gtmsource_state)
+ return (SS_NORMAL);
+
+ if (gtmsource_local->connect_parms[GTMSOURCE_CONN_HARD_TRIES_COUNT] <= connection_attempts)
+ { /*Initialize logging period related variables*/
+ logging_period = gtmsource_local->connect_parms[GTMSOURCE_CONN_SOFT_TRIES_PERIOD];
+ logging_interval = 1;
+ logging_attempts = 0;
+
+ alert_attempts = DIVIDE_ROUND_DOWN(gtmsource_local->connect_parms[GTMSOURCE_CONN_ALERT_PERIOD],
+ gtmsource_local->connect_parms[GTMSOURCE_CONN_SOFT_TRIES_PERIOD]);
+ repl_log(gtmsource_log_fp, TRUE, TRUE, "Soft tries period = %d, Alert period = %d\n",
+ gtmsource_local->connect_parms[GTMSOURCE_CONN_SOFT_TRIES_PERIOD],
+ alert_attempts * gtmsource_local->connect_parms[GTMSOURCE_CONN_SOFT_TRIES_PERIOD]);
+ connection_attempts = 0;
+ do
+ {
+ status = gtm_connect(gtmsource_sock_fd, secondary_sa, secondary_addrlen);
+ if (0 == status)
+ break;
+ repl_close(>msource_sock_fd);
+ if (0 == (connection_attempts + 1) % logging_interval)
+ {
+ repl_log(gtmsource_log_fp, TRUE, TRUE, "%d soft connection attempt failed : %s\n",
+ connection_attempts + 1, STRERROR(ERRNO));
+ logging_attempts++;
+ }
+ LONG_SLEEP(gtmsource_local->connect_parms[GTMSOURCE_CONN_SOFT_TRIES_PERIOD]);
+ gtmsource_poll_actions(FALSE);
+ if (GTMSOURCE_CHANGING_MODE == gtmsource_state)
+ return (SS_NORMAL);
+ gtmsource_comm_init();
+ connection_attempts++;
+ if (0 == (connection_attempts % logging_interval) && 0 == (logging_attempts % alert_attempts))
+ { /* Log ALERT message */
+ SNPRINTF(msg_str, SIZEOF(msg_str),
+ "GTM Replication Source Server : Could not connect to secondary in %d seconds\n",
+ connection_attempts *
+ gtmsource_local->connect_parms[GTMSOURCE_CONN_SOFT_TRIES_PERIOD]);
+ sgtm_putmsg(print_msg, VARLSTCNT(4) ERR_REPLWARN, 2, LEN_AND_STR(msg_str));
+ repl_log(gtmsource_log_fp, TRUE, TRUE, print_msg);
+ gtm_event_log(GTM_EVENT_LOG_ARGC, "MUPIP", "REPLWARN", print_msg);
+ }
+ if (logging_period <= REPL_MAX_LOG_PERIOD)
+ { /*the maximum real_period can reach 2*REPL_MAX_LOG_PERIOD)*/
+ if (0 == connection_attempts % logging_interval)
+ { /* Double the logging period after every logging attempt*/
+ logging_interval = logging_interval << 1;
+ logging_period = logging_period << 1;
+ }
+ }
+ } while (TRUE);
+ }
+ if (0 != (status = get_send_sock_buff_size(gtmsource_sock_fd, &send_buffsize)))
+ {
+ SNPRINTF(msg_str, SIZEOF(msg_str), "Error getting socket send buffsize : %s", STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(msg_str));
+ }
+ if (send_buffsize < GTMSOURCE_TCP_SEND_BUFSIZE)
+ {
+ for (tcp_s_bufsize = GTMSOURCE_TCP_SEND_BUFSIZE;
+ tcp_s_bufsize >= MAX(send_buffsize, GTMSOURCE_MIN_TCP_SEND_BUFSIZE)
+ && 0 != (status = set_send_sock_buff_size(gtmsource_sock_fd, tcp_s_bufsize));
+ tcp_s_bufsize -= GTMSOURCE_TCP_SEND_BUFSIZE_INCR)
+ ;
+ if (tcp_s_bufsize < GTMSOURCE_MIN_TCP_SEND_BUFSIZE)
+ {
+ SNPRINTF(msg_str, SIZEOF(msg_str), "Could not set TCP send buffer size in range [%d, %d], last "
+ "known error : %s", GTMSOURCE_MIN_TCP_SEND_BUFSIZE, GTMSOURCE_TCP_SEND_BUFSIZE,
+ STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) MAKE_MSG_INFO(ERR_REPLCOMM), 0, ERR_TEXT, 2, LEN_AND_STR(msg_str));
+ }
+ }
+ if (0 != (status = get_send_sock_buff_size(gtmsource_sock_fd, &repl_max_send_buffsize))) /* may have changed */
+ {
+ SNPRINTF(msg_str, SIZEOF(msg_str), "Error getting socket send buffsize : %s", STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(msg_str));
+ }
+ if (0 != (status = get_recv_sock_buff_size(gtmsource_sock_fd, &recv_buffsize)))
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_LIT("Error getting socket recv buffsize"),
+ ERR_TEXT, 2, LEN_AND_STR(STRERROR(status)));
+ if (recv_buffsize < GTMSOURCE_TCP_RECV_BUFSIZE)
+ {
+ if (0 != (status = set_recv_sock_buff_size(gtmsource_sock_fd, GTMSOURCE_TCP_RECV_BUFSIZE)))
+ {
+ if (recv_buffsize < GTMSOURCE_MIN_TCP_RECV_BUFSIZE)
+ {
+ SNPRINTF(msg_str, SIZEOF(msg_str), "Could not set TCP recv buffer size to %d : %s",
+ GTMSOURCE_MIN_TCP_RECV_BUFSIZE, STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) MAKE_MSG_INFO(ERR_REPLCOMM), 0, ERR_TEXT, 2,
+ LEN_AND_STR(msg_str));
+ }
+ }
+ }
+ if (0 != (status = get_recv_sock_buff_size(gtmsource_sock_fd, &repl_max_recv_buffsize))) /* may have changed */
+ {
+ SNPRINTF(msg_str, SIZEOF(msg_str), "Error getting socket recv buffsize : %s", STRERROR(status));
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_REPLCOMM, 0, ERR_TEXT, 2, LEN_AND_STR(msg_str));
+ }
+ return (SS_NORMAL);
+}
+
+int gtmsource_alloc_tcombuff(void)
+{ /* Allocate buffer for TCOM, ZTCOM records */
+
+ if (NULL == tcombuff)
+ {
+ assert(NULL == gtmsource_tcombuff_start);
+ tcombuff = (unsigned char *)malloc(gd_header->n_regions * TCOM_RECLEN + OS_PAGE_SIZE);
+ gtmsource_tcombuff_start = (unsigned char *)ROUND_UP2((unsigned long)tcombuff, OS_PAGE_SIZE);
+ }
+ return (SS_NORMAL);
+}
+
+void gtmsource_free_tcombuff(void)
+{
+ if (NULL != tcombuff)
+ {
+ free(tcombuff);
+ tcombuff = gtmsource_tcombuff_start = NULL;
+ }
+ return;
+}
+
+int gtmsource_alloc_filter_buff(int bufsiz)
+{
+ unsigned char *old_filter_buff, *free_filter_buff;
+
+ bufsiz = ROUND_UP2(bufsiz, OS_PAGE_SIZE);
+ if (gtmsource_filter != NO_FILTER && bufsiz > repl_filter_bufsiz)
+ {
+ REPL_DPRINT3("Expanding filter buff from %d to %d\n", repl_filter_bufsiz, bufsiz);
+ free_filter_buff = filterbuff;
+ old_filter_buff = repl_filter_buff;
+ filterbuff = (unsigned char *)malloc(bufsiz + OS_PAGE_SIZE);
+ repl_filter_buff = (unsigned char *)ROUND_UP2((unsigned long)filterbuff, OS_PAGE_SIZE);
+ if (NULL != free_filter_buff)
+ {
+ assert(NULL != old_filter_buff);
+ memcpy(repl_filter_buff, old_filter_buff, repl_filter_bufsiz);
+ free(free_filter_buff);
+ }
+ repl_filter_bufsiz = bufsiz;
+ }
+ return (SS_NORMAL);
+}
+
+void gtmsource_free_filter_buff(void)
+{
+ if (NULL != filterbuff)
+ {
+ assert(NULL != repl_filter_buff);
+ free(filterbuff);
+ filterbuff = repl_filter_buff = NULL;
+ repl_filter_bufsiz = 0;
+ }
+}
+
+int gtmsource_alloc_msgbuff(int maxbuffsize)
+{ /* Allocate message buffer */
+
+ repl_msg_ptr_t oldmsgp;
+ unsigned char *free_msgp;
+
+ assert(MIN_REPL_MSGLEN < maxbuffsize);
+ maxbuffsize = ROUND_UP2(maxbuffsize, OS_PAGE_SIZE);
+ if (maxbuffsize > gtmsource_msgbufsiz || NULL == gtmsource_msgp)
+ {
+ REPL_DPRINT3("Expanding message buff from %d to %d\n", gtmsource_msgbufsiz, maxbuffsize);
+ free_msgp = msgbuff;
+ oldmsgp = gtmsource_msgp;
+ msgbuff = (unsigned char *)malloc(maxbuffsize + OS_PAGE_SIZE);
+ gtmsource_msgp = (repl_msg_ptr_t)ROUND_UP2((unsigned long)msgbuff, OS_PAGE_SIZE);
+ if (NULL != free_msgp)
+ { /* Copy existing data */
+ assert(NULL != oldmsgp);
+ memcpy((unsigned char *)gtmsource_msgp, (unsigned char *)oldmsgp, gtmsource_msgbufsiz);
+ free(free_msgp);
+ }
+ gtmsource_msgbufsiz = maxbuffsize;
+ gtmsource_alloc_filter_buff(gtmsource_msgbufsiz);
+ }
+ return (SS_NORMAL);
+}
+
+void gtmsource_free_msgbuff(void)
+{
+ if (NULL != msgbuff)
+ {
+ assert(NULL != gtmsource_msgp);
+ free(msgbuff);
+ msgbuff = NULL;
+ gtmsource_msgp = NULL;
+ gtmsource_msgbufsiz = 0;
+ }
+}
+
+int gtmsource_recv_restart(seq_num *recvd_jnl_seqno, int *msg_type, int *start_flags)
+{
+ /* Receive jnl_seqno for (re)starting transmission */
+
+ fd_set input_fds;
+ repl_msg_t msg;
+ unsigned char *msg_ptr; /* needed for REPL_{SEND,RECV}_LOOP */
+ int tosend_len, sent_len, sent_this_iter; /* needed for REPL_SEND_LOOP */
+ int torecv_len, recvd_len, recvd_this_iter; /* needed for REPL_RECV_LOOP */
+ int status; /* needed for REPL_{SEND,RECV}_LOOP */
+ unsigned char seq_num_str[32], *seq_num_ptr;
+ repl_msg_t xoff_ack;
+ boolean_t rcv_node_same_endianness = FALSE;
+
+ status = SS_NORMAL;
+ for (; SS_NORMAL == status;)
+ {
+ repl_log(gtmsource_log_fp, FALSE, FALSE, "Waiting for (re)start JNL_SEQNO/FETCH RESYSNC msg\n");
+ REPL_RECV_LOOP(gtmsource_sock_fd, &msg, MIN_REPL_MSGLEN, REPL_POLL_WAIT)
+ {
+ gtmsource_poll_actions(FALSE);
+ if (GTMSOURCE_CHANGING_MODE == gtmsource_state)
+ return (SS_NORMAL);
+ }
+ if (SS_NORMAL == status)
+ {
+ /* Determine endianness of other system by seeing if the msg.len is greater than
+ * expected. If it is, convert it and see if it is now what we expect. If it is,
+ * then the other system is of opposite endianness.
+ * Note: We would normally use msg.type since is is effectively an enum and we
+ * control by adding new messages. But, REPL_START_JNL_SEQNO is lucky number zero
+ * which means it is identical on systems of either endianness.
+ */
+ if (((unsigned)MIN_REPL_MSGLEN < (unsigned)msg.len)
+ && ((unsigned)MIN_REPL_MSGLEN == GTM_BYTESWAP_32((unsigned)msg.len)))
+ rcv_node_same_endianness = FALSE;
+ else
+ rcv_node_same_endianness = TRUE;
+ if (!rcv_node_same_endianness)
+ {
+ msg.type = GTM_BYTESWAP_32(msg.type);
+ msg.len = GTM_BYTESWAP_32(msg.len);
+ }
+ assert(msg.type == REPL_START_JNL_SEQNO || msg.type == REPL_FETCH_RESYNC || msg.type == REPL_XOFF_ACK_ME);
+ assert(msg.len == MIN_REPL_MSGLEN);
+ *msg_type = msg.type;
+ *start_flags = START_FLAG_NONE;
+ QWASSIGN(*recvd_jnl_seqno, *(seq_num *)&msg.msg[0]);
+ if (REPL_START_JNL_SEQNO == msg.type)
+ {
+ if (!rcv_node_same_endianness)
+ *recvd_jnl_seqno = GTM_BYTESWAP_64(*recvd_jnl_seqno);
+ repl_log(gtmsource_log_fp, FALSE, FALSE, "Received (re)start JNL_SEQNO msg %d bytes. seq no "
+ INT8_FMT"\n", recvd_len, INT8_PRINT(*recvd_jnl_seqno));
+ if (!rcv_node_same_endianness)
+ ((repl_start_msg_ptr_t)&msg)->start_flags =
+ GTM_BYTESWAP_32(((repl_start_msg_ptr_t)&msg)->start_flags);
+ *start_flags = ((repl_start_msg_ptr_t)&msg)->start_flags;
+ if (*start_flags & START_FLAG_STOPSRCFILTER)
+ {
+ repl_log(gtmsource_log_fp, FALSE, FALSE,
+ "Start JNL_SEQNO msg tagged with STOP SOURCE FILTER\n");
+ if (gtmsource_filter & EXTERNAL_FILTER)
+ {
+ repl_stop_filter();
+ gtmsource_filter &= ~EXTERNAL_FILTER;
+ } else
+ repl_log(gtmsource_log_fp, FALSE, FALSE,
+ "Filter is not active, ignoring STOP SOURCE FILTER msg\n");
+ *msg_type = REPL_START_JNL_SEQNO;
+ }
+ assert(*start_flags & START_FLAG_HASINFO); /* V4.2+ versions have jnl ver in the start msg */
+ remote_jnl_ver = ((repl_start_msg_ptr_t)&msg)->jnl_ver;
+ REPL_DPRINT3("Local jnl ver is octal %o, remote jnl ver is octal %o\n", jnl_ver, remote_jnl_ver);
+ repl_check_jnlver_compat();
+ assert(remote_jnl_ver > V15_JNL_VER || 0 == (*start_flags & START_FLAG_COLL_M));
+ if (remote_jnl_ver <= V15_JNL_VER)
+ *start_flags &= ~START_FLAG_COLL_M; /* zap it for pro, just in case */
+ secondary_side_std_null_coll = (*start_flags & START_FLAG_COLL_M) ? TRUE : FALSE;
+ assert((remote_jnl_ver >= V19_JNL_VER) || (0 == (*start_flags & START_FLAG_TRIGGER_SUPPORT)));
+ if (remote_jnl_ver < V19_JNL_VER)
+ *start_flags &= ~START_FLAG_TRIGGER_SUPPORT; /* zap it for pro, just in case */
+ secondary_side_trigger_support = (*start_flags & START_FLAG_TRIGGER_SUPPORT) ? TRUE : FALSE;
+ return (SS_NORMAL);
+ } else if (REPL_FETCH_RESYNC == msg.type)
+ {
+ if (!rcv_node_same_endianness)
+ *recvd_jnl_seqno = GTM_BYTESWAP_64(*recvd_jnl_seqno);
+ repl_log(gtmsource_log_fp, TRUE, TRUE, "FETCH RESYNC msg received with SEQNO "INT8_FMT"\n",
+ INT8_PRINT(*(seq_num *)&msg.msg[0]));
+ return (SS_NORMAL);
+ } else if (REPL_XOFF_ACK_ME == msg.type)
+ {
+ repl_log(gtmsource_log_fp, FALSE, FALSE, "XOFF received when waiting for (re)start JNL_SEQNO/FETCH "
+ "RESYSNC msg. Possible crash/shutdown of update process\n");
+ /* Send XOFF_ACK */
+ xoff_ack.type = REPL_XOFF_ACK;
+ if (!rcv_node_same_endianness)
+ *recvd_jnl_seqno = GTM_BYTESWAP_64(*recvd_jnl_seqno);
+ QWASSIGN(*(seq_num *)&xoff_ack.msg[0], *recvd_jnl_seqno);
+ xoff_ack.len = MIN_REPL_MSGLEN;
+ REPL_SEND_LOOP(gtmsource_sock_fd, &xoff_ack, xoff_ack.len, REPL_POLL_NOWAIT)
+ {
+ gtmsource_poll_actions(FALSE);
+ if (GTMSOURCE_CHANGING_MODE == gtmsource_state)
+ return (SS_NORMAL);
+ }
+ if (SS_NORMAL == status)
+ {
+ repl_log(gtmsource_log_fp, TRUE, TRUE, "REPL_XOFF_ACK sent...\n");
+ }
+ } else
+ {
+ repl_log(gtmsource_log_fp, FALSE, FALSE, "UNKNOWN msg received when waiting for (re)start "
+ "JNL_SEQNO/FETCH RESYSNC msg. Ignoring msg\n");
+ GTMASSERT;
+ }
+ }
+ }
+ return (status);
+}
+
+int gtmsource_srch_restart(seq_num recvd_jnl_seqno, int recvd_start_flags)
+{
+ seq_num tmp_read_jnl_seqno;
+ qw_off_t tmp_read_addr;
+ uint4 tmp_read, prev_tmp_read, prev_tr_size, jnlpool_size;
+ int save_lastwrite_len;
+ unsigned char seq_num_str[32], *seq_num_ptr;
+ gd_region *reg, *region_top;
+ sgmnt_addrs *csa;
+ jnlpool_ctl_ptr_t jctl;
+ gtmsource_local_ptr_t gtmsource_local;
+
+ jctl = jnlpool.jnlpool_ctl;
+ jnlpool_size = jctl->jnlpool_size;
+ gtmsource_local = jnlpool.gtmsource_local;
+ if (recvd_start_flags & START_FLAG_UPDATERESYNC)
+ {
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK);
+ QWASSIGN(gtmsource_local->read_jnl_seqno, jctl->jnl_seqno);
+ QWASSIGN(gtmsource_local->read_addr, jctl->write_addr);
+ gtmsource_local->read = jctl->write;
+ rel_lock(jnlpool.jnlpool_dummy_reg);
+ gtmsource_local->read_state = READ_POOL;
+ repl_log(gtmsource_log_fp, TRUE, TRUE, "Update resync received, source server now reading from journal pool\n");
+ gtmsource_ctl_close();
+ REPL_DPRINT1("Received START_FLAG_UPDATERESYNC\n");
+ }
+
+ if (QWGT(recvd_jnl_seqno, gtmsource_local->read_jnl_seqno))
+ {
+ /*
+ * The Receiver is ahead of me though I haven't yet
+ * sent the transactions read_jnl_seqno thru
+ * recvd_jnl_seqno across.
+ */
+ /* Log Warning Message */
+ repl_log(gtmsource_log_fp, TRUE, FALSE, "Receiver ahead of Source. Source at JNL_SEQNO "INT8_FMT,
+ INT8_PRINT(gtmsource_local->read_jnl_seqno));
+ repl_log(gtmsource_log_fp, FALSE, TRUE, ", receiver at "INT8_FMT"\n", INT8_PRINT(recvd_jnl_seqno));
+ return (EREPL_SEC_AHEAD);
+ }
+
+ QWASSIGN(tmp_read_jnl_seqno, gtmsource_local->read_jnl_seqno);
+
+ if (READ_POOL == gtmsource_local->read_state)
+ {
+ /* Follow the back-chain in the Journal Pool to find whether
+ * or not recvd_jnl_seqno is in the Pool */
+
+ /* The implementation for searching through the back chain has several inefficiences. We are deferring addressing
+ * them to keep code changes for V4.4-003 to a minimum. We should address these in an upcoming release.
+ * Vinaya 2003, Oct 02 */
+
+ QWASSIGN(tmp_read_addr, gtmsource_local->read_addr);
+ QWASSIGN(tmp_read_jnl_seqno, gtmsource_local->read_jnl_seqno);
+ tmp_read = gtmsource_local->read;
+
+ if (jnlpool_hasnt_overflowed(jctl, jnlpool_size, tmp_read_addr) &&
+ QWGT(tmp_read_jnl_seqno, recvd_jnl_seqno) &&
+ QWGT(tmp_read_jnl_seqno, jctl->start_jnl_seqno))
+ {
+ if (QWGE(jctl->early_write_addr, tmp_read_addr))
+ {
+ /* If there is no more input to be read, the previous transaction size should not be read from the
+ * journal pool since the read pointers point to the next read. In such a case, we can find the
+ * size of the transcation tmp_read_jnl_seqno from jctl->lastwrite_len. We should access
+ * lastwrite_len after a memory barrier to avoid reading a stale value. We rely on the memory
+ * barrier done in jnlpool_hasnt_overflowed */
+ save_lastwrite_len = jctl->lastwrite_len;
+ if (QWEQ(jctl->early_write_addr, tmp_read_addr))
+ { /* GT.M is not writing any transaction, safe to rely on jctl->lastwrite_len. Note, GT.M could not
+ * have been writing transaction tmp_read_jnl_seqno if we are here. Also, lastwrite_len cannot be
+ * in the future w.r.t early_write_addr because of the memory barriers we do in t{p}_{t}end.c
+ * It can be behind by atmost one transaction (tmp_read_jnl_seqno). Well, we want the length of
+ * transaction tmp_read_jnl_seqno, not tmp_read_jnl_seqno + 1. */
+ QWDECRBYDW(tmp_read_addr, save_lastwrite_len);
+ QWDECRBYDW(tmp_read_jnl_seqno, 1);
+ prev_tmp_read = tmp_read;
+ tmp_read -= save_lastwrite_len;
+ if (tmp_read >= prev_tmp_read)
+ tmp_read += jnlpool_size;
+ assert(tmp_read == QWMODDW(tmp_read_addr, jnlpool_size));
+ REPL_DPRINT2("Srch restart : No more input in jnlpool, backing off to read_jnl_seqno : "
+ INT8_FMT, INT8_PRINT(tmp_read_jnl_seqno));
+ REPL_DPRINT3(" read_addr : "INT8_FMT" read : %d\n", INT8_PRINT(tmp_read_addr), tmp_read);
+ }
+ }
+ if (QWEQ(tmp_read_addr, jctl->write_addr))
+ { /* we caught a GTM process writing tmp_read_jnl_seqno + 1, we cannot rely on lastwrite_len as it
+ * may or may not have changed. Wait until the GTM process finishes writing this transaction */
+ repl_log(gtmsource_log_fp, TRUE, TRUE, "SEARCHING RESYNC POINT IN POOL : Waiting for GTM process "
+ "to finish writing journal records to the pool\n");
+ while (QWEQ(tmp_read_addr, jctl->write_addr))
+ {
+ SHORT_SLEEP(GTMSOURCE_WAIT_FOR_JNL_RECS);
+ gtmsource_poll_actions(FALSE);
+ }
+ repl_log(gtmsource_log_fp, TRUE, TRUE, "SEARCHING RESYNC POINT IN POOL : GTM process finished "
+ "writing journal records to the pool\n");
+ }
+ }
+
+ while (jnlpool_hasnt_overflowed(jctl, jnlpool_size, tmp_read_addr) &&
+ QWGT(tmp_read_jnl_seqno, recvd_jnl_seqno) &&
+ QWGT(tmp_read_jnl_seqno, jctl->start_jnl_seqno))
+ {
+ assert(tmp_read + SIZEOF(jnldata_hdr_struct) <= jnlpool_size);
+ prev_tr_size = ((jnldata_hdr_ptr_t)(jnlpool.jnldata_base + tmp_read))->prev_jnldata_len;
+ if ((prev_tr_size <= tmp_read_addr) &&
+ jnlpool_hasnt_overflowed(jctl, jnlpool_size, tmp_read_addr - prev_tr_size))
+ {
+ QWDECRBYDW(tmp_read_addr, prev_tr_size);
+ prev_tmp_read = tmp_read;
+ tmp_read -= prev_tr_size;
+ if (tmp_read >= prev_tmp_read)
+ tmp_read += jnlpool_size;
+ assert(tmp_read == QWMODDW(tmp_read_addr, jnlpool_size));
+ QWDECRBYDW(tmp_read_jnl_seqno, 1);
+ REPL_DPRINT2("Srch restart : No overflow yet, backing off to read_jnl_seqno : "INT8_FMT,
+ INT8_PRINT(tmp_read_jnl_seqno));
+ REPL_DPRINT3(" read_addr : "INT8_FMT" read : %d\n", INT8_PRINT(tmp_read_addr), tmp_read);
+ continue;
+ }
+ break;
+ }
+
+ QWASSIGN(gtmsource_local->read_addr, tmp_read_addr);
+ gtmsource_local->read = tmp_read;
+
+ if (jnlpool_hasnt_overflowed(jctl, jnlpool_size, tmp_read_addr) &&
+ QWEQ(tmp_read_jnl_seqno, recvd_jnl_seqno) &&
+ QWGE(tmp_read_jnl_seqno, jctl->start_jnl_seqno))
+ {
+ REPL_DPRINT2("Srch restart : Now in READ_POOL state read_jnl_seqno : "INT8_FMT,
+ INT8_PRINT(tmp_read_jnl_seqno));
+ REPL_DPRINT3(" read_addr : "INT8_FMT" read : %d\n",INT8_PRINT(tmp_read_addr), tmp_read);
+ } else
+ {
+ /* Overflow, or requested seqno too far back to be in pool */
+ REPL_DPRINT2("Srch restart : Now in READ_FILE state. Changing sync point to read_jnl_seqno : "INT8_FMT,
+ INT8_PRINT(tmp_read_jnl_seqno));
+ REPL_DPRINT3(" read_addr : "INT8_FMT" read : %d ", INT8_PRINT(tmp_read_addr), tmp_read);
+ REPL_DPRINT2("save_read_jnl_seqno : "INT8_FMT"\n", INT8_PRINT(gtmsource_save_read_jnl_seqno));
+
+ QWASSIGN(gtmsource_save_read_jnl_seqno, tmp_read_jnl_seqno);
+ if (QWLT(gtmsource_save_read_jnl_seqno, jctl->start_jnl_seqno))
+ {
+ QWASSIGN(gtmsource_save_read_jnl_seqno, jctl->start_jnl_seqno);
+ assert(QWEQ(gtmsource_local->read_addr, seq_num_zero));
+ assert(gtmsource_local->read == 0);
+ /* For pro version, force zero assignment */
+ QWASSIGN(gtmsource_local->read_addr, seq_num_zero);
+ gtmsource_local->read = 0;
+ REPL_DPRINT2("Srch restart : Sync point "INT8_FMT, INT8_PRINT(gtmsource_save_read_jnl_seqno));
+ REPL_DPRINT2(" beyond start_seqno : "INT8_FMT, INT8_PRINT(jctl->start_jnl_seqno));
+ REPL_DPRINT3(", sync point set to read_addr : "INT8_FMT" read : %d\n",
+ INT8_PRINT(gtmsource_local->read_addr), gtmsource_local->read);
+ }
+ gtmsource_local->read_state = READ_FILE;
+
+ repl_log(gtmsource_log_fp, TRUE, TRUE, "Source server now reading from journal files; journal pool "
+ "does not contain transaction %llu\n", recvd_jnl_seqno);
+ gtmsource_pool2file_transition = TRUE;
+ }
+ } else /* read_state is READ_FILE and requesting a sequence number
+ * less than or equal to read_jnl_seqno */
+ {
+ if (QWGT(tmp_read_jnl_seqno, gtmsource_save_read_jnl_seqno))
+ QWASSIGN(gtmsource_save_read_jnl_seqno, tmp_read_jnl_seqno);
+ REPL_DPRINT2("Srch restart : Continuing in READ_FILE state. Retaining sync point for read_jnl_seqno : "INT8_FMT,
+ INT8_PRINT(tmp_read_jnl_seqno));
+ REPL_DPRINT2(" at read_addr : "INT8_FMT, INT8_PRINT(gtmsource_local->read_addr));
+ REPL_DPRINT3(" read : %d corresponding to save_read_jnl_seqno : "INT8_FMT"\n", gtmsource_local->read,
+ INT8_PRINT(gtmsource_save_read_jnl_seqno));
+ repl_log(gtmsource_log_fp, TRUE, TRUE, "Source server continuing to read from journal files at transaction %llu\n",
+ recvd_jnl_seqno);
+ }
+
+ QWASSIGN(gtmsource_local->read_jnl_seqno, recvd_jnl_seqno);
+
+ region_top = gd_header->regions + gd_header->n_regions;
+ for (reg = gd_header->regions; reg < region_top; reg++)
+ {
+ csa = &FILE_INFO(reg)->s_addrs;
+ if (REPL_ALLOWED(csa->hdr))
+ {
+#ifndef INT8_SUPPORTED
+ grab_crit(reg); /* File-header sync is done in crit, and so grab_crit here */
+#endif
+ QWASSIGN(FILE_INFO(reg)->s_addrs.hdr->resync_seqno, recvd_jnl_seqno);
+ REPL_DPRINT3("Setting resync_seqno of %s to "INT8_FMT"\n", reg->rname, INT8_PRINT(recvd_jnl_seqno));
+#ifndef INT8_SUPPORTED
+ rel_crit(reg);
+#endif
+ }
+ }
+
+ return (SS_NORMAL);
+}
+
+int gtmsource_get_jnlrecs(uchar_ptr_t buff, int *data_len, int maxbufflen, boolean_t read_multpile)
+{
+ int total_tr_len;
+ unsigned char seq_num_str[32], *seq_num_ptr;
+ jnlpool_ctl_ptr_t jctl;
+ gtmsource_local_ptr_t gtmsource_local;
+ seq_num jnl_seqno, read_jnl_seqno;
+ qw_num write_addr, read_addr;
+
+ jctl = jnlpool.jnlpool_ctl;
+ gtmsource_local = jnlpool.gtmsource_local;
+ write_addr = jctl->write_addr;
+ jnl_seqno = jctl->jnl_seqno;
+ read_jnl_seqno = gtmsource_local->read_jnl_seqno;
+ read_addr = gtmsource_local->read_addr;
+ assert(read_addr <= write_addr);
+ assert((0 != write_addr) || (read_jnl_seqno <= jctl->start_jnl_seqno));
+
+#ifdef GTMSOURCE_ALWAYS_READ_FILES
+ gtmsource_local->read_state = READ_FILE;
+#endif
+ switch(gtmsource_local->read_state)
+ {
+ case READ_POOL:
+#ifndef GTMSOURCE_ALWAYS_READ_FILES_STRESS
+ if (read_addr == write_addr)
+ {/* Nothing to read. While reading pool, the comparison of read_addr against write_addr is the only
+ * reliable indicator if there are any transactions to be read. This is due to the placement of
+ * memory barriers in t_end/tp_tend.c. Also, since we do not issue memory barrier here, we may be reading
+ * a stale value of write_addr in which case we may conclude that there is nothing to read. But, this will
+ * not continue forever as the source server eventually (decided by architecture's implementation) will see
+ * the change to write_addr.
+ */
+ *data_len = 0;
+ return (0);
+ }
+ if (0 < (total_tr_len = gtmsource_readpool(buff, data_len, maxbufflen, read_multpile, write_addr)))
+ return (total_tr_len);
+ if (0 < *data_len)
+ return (-1);
+#endif /* for GTMSOURCE_ALWAYS_READ_FILES_STRESS, we let the source server switch back and forth between pool read and file read */
+ /* Overflow, switch to READ_FILE */
+ gtmsource_local->read_state = READ_FILE;
+ QWASSIGN(gtmsource_save_read_jnl_seqno, read_jnl_seqno);
+ gtmsource_pool2file_transition = TRUE; /* so that we read the latest gener jnl files */
+ repl_log(gtmsource_log_fp, TRUE, TRUE, "Source server now reading from journal files; journal pool "
+ "overflow detected at transaction %llu\n", gtmsource_save_read_jnl_seqno);
+
+ /* CAUTION : FALL THROUGH */
+
+ case READ_FILE:
+ if (read_jnl_seqno >= jnl_seqno)
+ { /* Nothing to read. While reading from files, source server does not use write_addr to decide
+ * how much to read. Also, it is possible that read_addr and write_addr are the same if the
+ * source server came up after a crash and syncs with the latest state in jnlpool (see
+ * gtmsource()). These reasons preclude the comparison of read_addr and write_addr (as we did for
+ * READ_POOL case) to decide whether there are any unsent transactions. We use jnl_seqno instead.
+ * Note though, the source server's view of jnl_seqno may be stale, and we may conclude that
+ * we don't have anything to read as we do not do memory barrier here to fetch the latest
+ * value of jnl_seqno. But, this will not continue forever as the source server eventually
+ * (decided by architecture's implementation) will see the change to jnl_seqno.
+ *
+ * On systems that allow unordered memory access, it is possible that the value of jnl_seqno
+ * as seen by source server is in the past compared to read_jnl_seqno - source server in
+ * keeping up with updaters reads (from pool) and sends upto write_addr, the last transaction
+ * of which could be jnl_seqno + 1. To cover the case, we use >= in the above comparison.
+ * Given this, we may return with "nothing to read" even though we fell through from the READ_POOL case.
+ */
+ *data_len = 0;
+ return 0;
+ }
+ if (gtmsource_pool2file_transition /* read_pool -> read_file transition */
+ || NULL == repl_ctl_list) /* files not opened */
+ {
+ /* Close all the file read related structures
+ * and start afresh. The idea here is that
+ * most of the file read info might be stale
+ * 'cos there is usually a long gap between
+ * pool to file read transitions (in
+ * production environments). So, start afresh
+ * with the latest generation journal files.
+ * This will also prevent opening previous
+ * generations that may not be required.
+ */
+ REPL_DPRINT1("Pool to File read transition. Closing all the stale file read info and starting "
+ "afresh\n");
+ gtmsource_ctl_close();
+ gtmsource_ctl_init();
+ gtmsource_pool2file_transition = FALSE;
+ }
+ if (0 < (total_tr_len = gtmsource_readfiles(buff, data_len, maxbufflen, read_multpile)))
+ return (total_tr_len);
+ if (0 < *data_len)
+ return (-1);
+ GTMASSERT;
+ }
+}
diff --git a/sr_vvms/gtmsource_readfiles.c b/sr_vvms/gtmsource_readfiles.c
new file mode 100644
index 0000000..f15712f
--- /dev/null
+++ b/sr_vvms/gtmsource_readfiles.c
@@ -0,0 +1,1704 @@
+/****************************************************************
+ * *
+ * Copyright 2006, 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include <stddef.h> /* for offsetof macro */
+#include "gtm_socket.h"
+#include "gtm_inet.h"
+#include <sys/time.h>
+#include <errno.h>
+#include "gtm_fcntl.h"
+#include "gtm_unistd.h"
+#include <ssdef.h>
+#include <rms.h>
+#include <devdef.h>
+#include <fab.h>
+#include <iodef.h>
+#include <nam.h>
+#include <rmsdef.h>
+#include <descrip.h> /* Required for gtmsource.h */
+#include <efndef.h>
+#include <secdef.h>
+#include "iosb_disk.h"
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "repl_msg.h"
+#include "gtmsource.h"
+#include "jnl.h"
+#include "buddy_list.h"
+#include "hashtab_mname.h" /* needed for muprec.h */
+#include "hashtab_int4.h" /* needed for muprec.h */
+#include "hashtab_int8.h" /* needed for muprec.h */
+#include "muprec.h"
+#include "repl_ctl.h"
+#include "repl_errno.h"
+#include "repl_dbg.h"
+#include "iosp.h"
+#include "gtm_stdio.h"
+#include "copy.h"
+#include "eintr_wrappers.h"
+#include "repl_sp.h"
+#include "is_file_identical.h"
+#include "repl_log.h"
+#include "min_max.h"
+#include "error.h"
+#include "repl_tr_good.h"
+
+#define LOG_WAIT_FOR_JNL_RECS_PERIOD (10 * 1000) /* ms */
+#define LOG_WAIT_FOR_JNLOPEN_PERIOD (10 * 1000) /* ms */
+
+#define LSEEK_ERR_STR "Error in lseek"
+#define READ_ERR_STR "Error in read"
+#define UNKNOWN_ERR_STR "Error unknown"
+
+GBLREF unsigned char *gtmsource_tcombuff_start;
+GBLREF jnlpool_addrs jnlpool;
+GBLREF repl_ctl_element *repl_ctl_list;
+GBLREF seq_num gtmsource_save_read_jnl_seqno;
+GBLREF repl_msg_ptr_t gtmsource_msgp;
+GBLREF int gtmsource_msgbufsiz;
+GBLREF seq_num seq_num_zero, seq_num_one;
+GBLREF gd_region *gv_cur_region;
+GBLREF FILE *gtmsource_log_fp;
+
+error_def(ERR_JNLBADRECFMT);
+error_def(ERR_NOPREVLINK);
+error_def(ERR_REPLBRKNTRANS);
+error_def(ERR_REPLCOMM);
+error_def(ERR_REPLFILIOERR);
+error_def(ERR_TEXT);
+
+static int4 num_tcom = -1;
+static boolean_t trans_read = FALSE;
+static int tot_tcom_len = 0;
+static int total_wait_for_jnl_recs = 0;
+static int total_wait_for_jnlopen = 0;
+static unsigned char *tcombuffp = NULL;
+
+static int adjust_buff_leaving_hdr(repl_buff_t *rb);
+static tr_search_state_t position_read(repl_ctl_element*, seq_num);
+static int read_regions(
+ unsigned char **buff, int *buff_avail,
+ boolean_t attempt_open_oldnew,
+ boolean_t *brkn_trans,
+ seq_num read_jnl_seqno);
+
+static int first_read(repl_ctl_element*);
+static int update_max_seqno_info(repl_ctl_element *ctl);
+static int scavenge_closed_jnl_files(seq_num ack_seqno);
+static int update_eof_addr(repl_ctl_element *ctl, int *eof_change);
+
+static int repl_read_file(repl_buff_t *rb)
+{
+ repl_buff_desc *b;
+ repl_file_control_t *fc;
+ int nb;
+ sgmnt_addrs *csa;
+ uint4 dskaddr;
+ uint4 read_less, status;
+ int eof_change;
+ VMS_ONLY(
+ io_status_block_disk iosb;
+ uint4 read_off;
+ uint4 extra_bytes;
+ sm_uc_ptr_t read_buff;
+ DEBUG_ONLY(unsigned char verify_buff[DISK_BLOCK_SIZE];)
+ )
+
+ fc = rb->fc;
+ b = &rb->buff[rb->buffindex];
+ csa = &FILE_INFO(rb->backctl->reg)->s_addrs;
+ read_less = 0;
+ assert(b->readaddr >= b->recaddr);
+ assert(0 < b->buffremaining);
+ dskaddr = csa->jnl->jnl_buff->dskaddr;
+ if (!is_gdid_gdid_identical(&fc->id, JNL_GDID_PTR(csa)))
+ {
+ if (!rb->backctl->eof_addr_final)
+ update_eof_addr(rb->backctl, &eof_change); /* update possible change in end_of_data, re-read file header */
+ assert(!fc->jfh->crash);
+ dskaddr = fc->jfh->end_of_data;
+ if (0 == fc->jfh->prev_recov_end_of_data) /* file not virtually truncated by recover/rollback */
+ dskaddr += EOF_RECLEN;
+ }
+ /* Make sure we do not read beyond end of data in the journal file */
+ /* Note : This logic is always needed when journal file is pre-allocated.
+ * With no pre-allocation, this logic is needed only when repl_read_file is called from
+ * update_max_seqno_info -> repl_next. Specifically, this logic is needed till the existing
+ * JRT_EOF record is completely overwritten and the file grows beyond its existing size.
+ */
+ assert(b->readaddr <= dskaddr);
+ if (b->buffremaining > (dskaddr - b->readaddr)) /* note the ordering of the operands to take care of 4G overflow */
+ {
+ if (b->readaddr == dskaddr)
+ {
+ REPL_DPRINT3("READ FILE : Jnl file %s yet to grow from (or ends at) offset %u\n",
+ rb->backctl->jnl_fn, b->readaddr);
+ return (SS_NORMAL);
+ }
+ read_less = b->buffremaining - (dskaddr - b->readaddr); /* explicit ordering to take care of 4G overflow */
+ REPL_DPRINT5("READ FILE : Racing with jnl file %s avoided. Read size reduced from %u to %u at offset %u\n",
+ rb->backctl->jnl_fn, b->buffremaining, b->buffremaining - read_less, b->readaddr);
+ }
+#ifdef UNIX
+ if (lseek(fc->fd, (off_t)b->readaddr, SEEK_SET) == (off_t)-1)
+ {
+ repl_errno = EREPL_JNLFILESEEK;
+ return (ERRNO);
+ }
+ READ_FILE(fc->fd, b->base + REPL_BLKSIZE(rb) - b->buffremaining, b->buffremaining - read_less, nb);
+ status = ERRNO;
+#elif defined(VMS)
+ nb = b->buffremaining - read_less; /* to be read */
+ read_off = ROUND_DOWN2(b->readaddr, DISK_BLOCK_SIZE); /* since read has to start at a disk block boundary */
+ extra_bytes = b->readaddr - read_off;
+ read_buff = b->base + REPL_BLKSIZE(rb) - b->buffremaining - extra_bytes;
+ DEBUG_ONLY(
+ if (0 != extra_bytes)
+ memcpy(verify_buff, read_buff, extra_bytes);
+ else;
+ )
+ assert(read_buff >= b->base);
+ status = sys$qiow(EFN$C_ENF, fc->fd, IO$_READVBLK, &iosb, 0, 0, read_buff, nb + extra_bytes,
+ DIVIDE_ROUND_DOWN(read_off, DISK_BLOCK_SIZE) + 1, 0, 0, 0);
+ if (SYSCALL_SUCCESS(status) && ((SYSCALL_SUCCESS(status = iosb.cond)) || SS$_ENDOFFILE == status))
+ {
+ nb = iosb.length; /* num bytes actually read */
+ nb -= extra_bytes; /* that we are interested in */
+ if ((SS$_NORMAL == status && nb < b->buffremaining - read_less) || (0 >= nb))
+ GTMASSERT; /* we thought VMS wouldn't return less than what we requested for */
+ DEBUG_ONLY((0 != extra_bytes) ? assert(0 == memcmp(verify_buff, read_buff, extra_bytes)) : 0;)
+ status = SS$_NORMAL;
+ } else
+ nb = -1;
+#else
+#error Unsupported platform
+#endif
+ if (nb >= 0)
+ {
+ b->buffremaining -= nb;
+ b->readaddr += nb;
+ return (SS_NORMAL);
+ }
+ repl_errno = EREPL_JNLFILEREAD;
+ return (status);
+}
+
+static int repl_next(repl_buff_t *rb)
+{
+ repl_buff_desc *b;
+ int4 reclen;
+ jrec_suffix *suffix;
+ uint4 maxreclen;
+ int status, sav_buffremaining;
+ char err_string[BUFSIZ];
+
+
+ b = &rb->buff[rb->buffindex];
+ b->recbuff += b->reclen; /* The next record */
+ b->recaddr += b->reclen;
+ if (b->recaddr == b->readaddr && b->buffremaining == 0)
+ {
+ /* Everything in this buffer processed */
+ b->recbuff = b->base;
+ b->reclen = 0;
+ b->buffremaining = REPL_BLKSIZE(rb);
+ }
+ if (b->recaddr == b->readaddr || b->reclen == 0)
+ {
+ sav_buffremaining = b->buffremaining;
+ if ((status = repl_read_file(rb)) == SS_NORMAL)
+ {
+ if (sav_buffremaining == b->buffremaining)
+ {
+ b->reclen = 0;
+ repl_errno = EREPL_JNLRECINCMPL;
+ return (repl_errno);
+ }
+ } else
+ {
+ if (repl_errno == EREPL_JNLFILESEEK)
+ MEMCPY_LIT(err_string, LSEEK_ERR_STR);
+ else if (repl_errno == EREPL_JNLFILEREAD)
+ MEMCPY_LIT(err_string, READ_ERR_STR);
+ else
+ MEMCPY_LIT(err_string, UNKNOWN_ERR_STR);
+ rts_error(VARLSTCNT(9) ERR_REPLFILIOERR, 2, rb->backctl->jnl_fn_len, rb->backctl->jnl_fn,
+ ERR_TEXT, 2, LEN_AND_STR(err_string), status);
+ }
+ }
+ maxreclen = ((b->base + REPL_BLKSIZE(rb)) - b->recbuff) - b->buffremaining;
+ assert(maxreclen > 0);
+ if (maxreclen > JREC_PREFIX_UPTO_LEN_SIZE &&
+ (reclen = ((jrec_prefix *)b->recbuff)->forwptr) <= maxreclen &&
+ IS_VALID_JNLREC((jnl_record *)b->recbuff, rb->fc->jfh))
+ {
+ b->reclen = reclen;
+ return SS_NORMAL;
+ }
+ repl_errno = (maxreclen > JREC_PREFIX_SIZE && reclen <= maxreclen) ? EREPL_JNLRECFMT : EREPL_JNLRECINCMPL;
+ b->reclen = 0;
+ return repl_errno;
+}
+
+static int open_prev_gener(repl_ctl_element **old_ctl, repl_ctl_element *ctl, seq_num read_seqno)
+{
+
+ if (0 == ctl->repl_buff->fc->jfh->prev_jnl_file_name_length ||
+ QWLE(ctl->repl_buff->fc->jfh->start_seqno, read_seqno))
+ {
+ /* No need to open previous generation, or no previous
+ * generation */
+ REPL_DPRINT2("No need to open prev gener of %s or no prev gener\n", ctl->jnl_fn);
+ return (0);
+ }
+ repl_ctl_create(old_ctl, ctl->reg, ctl->repl_buff->fc->jfh->prev_jnl_file_name_length,
+ (char *)ctl->repl_buff->fc->jfh->prev_jnl_file_name, FALSE);
+ REPL_DPRINT2("Prev gener file %s opened\n", ctl->repl_buff->fc->jfh->prev_jnl_file_name);
+ (*old_ctl)->prev = ctl->prev;
+ (*old_ctl)->next = ctl;
+ (*old_ctl)->prev->next = *old_ctl;
+ (*old_ctl)->next->prev = *old_ctl;
+ first_read(*old_ctl);
+ if ((*old_ctl)->file_state == JNL_FILE_OPEN)
+ {
+ (*old_ctl)->file_state = JNL_FILE_CLOSED;
+ REPL_DPRINT2("open_prev_gener : %s jnl file marked closed\n", (*old_ctl)->jnl_fn);
+ } else if ((*old_ctl)->file_state == JNL_FILE_UNREAD)
+ {
+ (*old_ctl)->file_state = JNL_FILE_EMPTY;
+ REPL_DPRINT2("open_prev_gener : %s jnl file marked empty\n", (*old_ctl)->jnl_fn);
+ } else
+ GTMASSERT;
+ return (1);
+}
+
+static int open_newer_gener_jnlfiles(gd_region *reg, repl_ctl_element *reg_ctl_end)
+{
+ sgmnt_addrs *csa;
+ repl_ctl_element *new_ctl, *ctl;
+ ino_t save_jnl_inode;
+ int jnl_fn_len;
+ char jnl_fn[JNL_NAME_SIZE];
+ int nopen, n;
+ int status;
+ gd_region *r_save;
+ uint4 jnl_status;
+ boolean_t do_jnl_ensure_open;
+ gd_id_ptr_t reg_ctl_end_id;
+
+ /* Attempt to open newer generation journal files. Return the number of new files opened. Create new
+ * ctl element(s) for each newer generation and attach at reg_ctl_end. Work backwards from the current journal file.
+ */
+ jnl_status = 0;
+ nopen = 0;
+ csa = &FILE_INFO(reg)->s_addrs;
+ reg_ctl_end_id = ®_ctl_end->repl_buff->fc->id;
+ /* Note that at this point, journaling might have been turned OFF (e.g. REPL_WAS_ON state) in which case
+ * JNL_GDID_PTR(csa) would have been nullified by jnl_file_lost. Therefore comparing with that is not a good idea
+ * to use the "id" to check if the journal file remains same (this was done previously). Instead use the ID of
+ * the current reg_ctl_end and the NAME of the newly opened journal file. Because we dont have crit, we cannot
+ * safely read the journal file name from the file header therefore we invoke repl_ctl_create unconditionally
+ * (that has safety protections for crit) and use the new_ctl that it returns to access the journal file name
+ * returned and use that for the ID to NAME comparison.
+ */
+ jnl_fn_len = 0; jnl_fn[0] = '\0';
+ for (do_jnl_ensure_open = TRUE; ; do_jnl_ensure_open = FALSE)
+ {
+ repl_ctl_create(&new_ctl, reg, jnl_fn_len, jnl_fn, do_jnl_ensure_open);
+ if (do_jnl_ensure_open && is_gdid_file_identical(reg_ctl_end_id, new_ctl->jnl_fn, new_ctl->jnl_fn_len))
+ { /* Current journal file in db file header has been ALREADY opened by source server. Return right away */
+ assert(0 == nopen);
+ repl_ctl_close(new_ctl);
+ return (nopen);
+ }
+ nopen++;
+ REPL_DPRINT2("Newer generation file %s opened\n", new_ctl->jnl_fn);
+ new_ctl->prev = reg_ctl_end;
+ new_ctl->next = reg_ctl_end->next;
+ if (new_ctl->next)
+ new_ctl->next->prev = new_ctl;
+ new_ctl->prev->next = new_ctl;
+ jnl_fn_len = new_ctl->repl_buff->fc->jfh->prev_jnl_file_name_length;
+ memcpy(jnl_fn, new_ctl->repl_buff->fc->jfh->prev_jnl_file_name, jnl_fn_len);
+ jnl_fn[jnl_fn_len] = '\0';
+ if ('\0' == jnl_fn[0])
+ { /* prev link has been cut, can't follow path back from latest generation jnlfile to the latest we had opened */
+ rts_error(VARLSTCNT(4) ERR_NOPREVLINK, 2, new_ctl->jnl_fn_len, new_ctl->jnl_fn);
+ }
+ if (is_gdid_file_identical(®_ctl_end->repl_buff->fc->id, jnl_fn, jnl_fn_len))
+ break;
+ }
+ /* Name of the journal file corresponding to reg_ctl_end might have changed. Update the name.
+ * Since inode info doesn't change when a file is renamed, it is not necessary to close and reopen the file.
+ */
+ reg_ctl_end->jnl_fn[reg_ctl_end->jnl_fn_len] = '\0'; /* For safety */
+ jnl_fn[jnl_fn_len] = '\0';
+ if (strcmp(reg_ctl_end->jnl_fn, jnl_fn) != 0) /* Name has changed */
+ {
+ REPL_DPRINT3("Detected name change of %s to %s\n", reg_ctl_end->jnl_fn, jnl_fn);
+ reg_ctl_end->jnl_fn_len = reg_ctl_end->reg->jnl_file_len = jnl_fn_len;
+ memcpy(reg_ctl_end->jnl_fn, jnl_fn, jnl_fn_len);
+ memcpy(reg_ctl_end->reg->jnl_file_name, jnl_fn, jnl_fn_len);
+ }
+ /* Except the latest generation, mark the newly opened future generations CLOSED, or EMPTY.
+ * We assume that when a new file is opened, the previous generation has been flushed to disk fully.
+ */
+ for (ctl = reg_ctl_end, n = nopen; n; n--, ctl = ctl->next)
+ {
+ if (ctl->file_state == JNL_FILE_UNREAD)
+ first_read(ctl);
+ else if (ctl->file_state == JNL_FILE_OPEN)
+ {
+ if (update_max_seqno_info(ctl) != SS_NORMAL)
+ {
+ assert(repl_errno == EREPL_JNLEARLYEOF);
+ GTMASSERT; /* Program bug */
+ }
+ } else
+ GTMASSERT;
+ if (ctl->file_state == JNL_FILE_UNREAD)
+ {
+ ctl->file_state = JNL_FILE_EMPTY;
+ REPL_DPRINT2("Open_newer_gener_files : %s marked empty\n", ctl->jnl_fn);
+ } else
+ {
+ assert(ctl->file_state == JNL_FILE_OPEN);
+ ctl->file_state = JNL_FILE_CLOSED;
+ REPL_DPRINT2("Open_newer_gener_files : %s marked closed\n", ctl->jnl_fn);
+ }
+ }
+ return (nopen);
+}
+
+static int update_eof_addr(repl_ctl_element *ctl, int *eof_change)
+{
+ repl_file_control_t *fc;
+ uint4 prev_eof_addr, new_eof_addr;
+ int status;
+ sgmnt_addrs *csa;
+#ifdef VMS
+ short iosb[4];
+#endif
+ repl_buff_t *rb;
+
+ assert(!ctl->eof_addr_final); /* The caller should invoke us ONLY if ctl->eof_addr_final is FALSE */
+ csa = &FILE_INFO(ctl->reg)->s_addrs;
+ rb = ctl->repl_buff;
+ fc = rb->fc;
+ prev_eof_addr = fc->eof_addr;
+ *eof_change = 0;
+ if (is_gdid_gdid_identical(&fc->id, JNL_GDID_PTR(csa)))
+ {
+ new_eof_addr = csa->jnl->jnl_buff->dskaddr;
+ REPL_DPRINT3("Update EOF : New EOF addr from SHM for %s is %u\n", ctl->jnl_fn, new_eof_addr);
+ } else
+ {
+ REPL_DPRINT2("Update EOF : New EOF addr will be found from jnl file hdr for %s\n", ctl->jnl_fn);
+ UNIX_ONLY(
+ REPL_DPRINT4("Update EOF : FC ID IS %u %d %u\n", fc->id.inode, fc->id.device, fc->id.st_gen);
+ REPL_DPRINT4("Update EOF : csa->nl->jnl_file.u (unreliable) is %u %d %u\n", csa->nl->jnl_file.u.inode,
+ csa->nl->jnl_file.u.device, csa->nl->jnl_file.u.st_gen);
+ )
+ if (!ctl->eof_addr_final)
+ {
+ F_READ_BLK_ALIGNED(fc->fd, 0, fc->jfh, REAL_JNL_HDR_LEN, status);
+ if (SS_NORMAL != status)
+ rts_error(VARLSTCNT(9) ERR_REPLFILIOERR, 2, ctl->jnl_fn_len, ctl->jnl_fn,
+ ERR_TEXT, 2, RTS_ERROR_LITERAL("Error in reading jfh in update_eof_addr"), status);
+ REPL_DPRINT2("Update EOF : Jnl file hdr refreshed from file for %s\n", ctl->jnl_fn);
+ ctl->eof_addr_final = TRUE; /* No more updates to fc->eof_addr for this journal file */
+ }
+ new_eof_addr = fc->jfh->end_of_data + EOF_RECLEN;
+ REPL_DPRINT3("Update EOF : New EOF addr from jfh for %s is %u\n", ctl->jnl_fn, new_eof_addr);
+ }
+ /* ensure that new_eof_addr is not less than prev_eof_addr.
+ * the only scenario where this need not be TRUE is the following case
+ * (i) if new_eof_addr == (journal file header's end_of_data + size of eof record) and
+ * (ii) if prev_eof_addr == the next REPL_BLKSIZE boundary (since source server reads in chunks of REPL_BLKSIZE)
+ * in the above case, source server's read of REPL_BLKSIZE bytes while trying to read at offset end_of_data would
+ * have succeeded since the whole REPL_BLKSIZE block has been allocated in the journal file both in Unix and VMS.
+ * but only the first EOF_RECLEN bytes of that block is valid data.
+ * For the case new_eof_addr < prev_eof_addr, the assert could have been
+ * DIVIDE_ROUND_UP(prev_eof_addr, REPL_BLKSIZE(rb)) == DIVIDE_ROUND_UP(new_eof_addr, REPL_BLKSIZE(rb)), but we use
+ * DIVIDE_ROUND_DOWN and account for prev_eof_addr being an exact multiple of REPL_BLKSIZE(rb) to avoid 4G overflow
+ */
+ assert((new_eof_addr >= prev_eof_addr)
+ || (DIVIDE_ROUND_DOWN(prev_eof_addr, REPL_BLKSIZE(rb)) - ((0 == prev_eof_addr % REPL_BLKSIZE(rb)) ? 1 : 0)
+ == DIVIDE_ROUND_DOWN(new_eof_addr, REPL_BLKSIZE(rb))));
+ fc->eof_addr = new_eof_addr;
+ /* eof_change calculated below is not used anywhere. In case it needs to be used, the below calculation
+ * has to be reexamined in light of the above assert involving new_eof_addr and prev_eof_addr
+ * although the code below is dead for now, it can be used for future performance enhancements.
+ */
+ *eof_change = new_eof_addr > prev_eof_addr ? (int4)(new_eof_addr - prev_eof_addr) : -(int4)(prev_eof_addr - new_eof_addr);
+ /* Above computation done that way because the variables involved are unsigned */
+ return (SS_NORMAL);
+}
+
+static int force_file_read(repl_ctl_element *ctl)
+{ /* The journal file may have grown since we last read it. A previously read EOF record may have been over-written on disk.
+ * Reposition read pointers so that a file read is forced if the current read pointers are positioned at a EOF record.
+ */
+ repl_buff_t *rb;
+ repl_buff_desc *b;
+ repl_file_control_t *fc;
+ enum jnl_record_type rectype;
+
+ rb = ctl->repl_buff;
+ b = &rb->buff[REPL_MAINBUFF];
+ fc = rb->fc;
+ if (b->reclen == 0 || b->recaddr == b->readaddr || b->buffremaining == 0 || b->buffremaining == REPL_BLKSIZE(rb))
+ { /* A file read will be forced anyway */
+ return (SS_NORMAL);
+ }
+ /* b->recbuff points to valid record */
+ rectype = ((jrec_prefix *)b->recbuff)->jrec_type;
+ assert(rectype > JRT_BAD && rectype <= JRT_RECTYPES);
+ if (rectype != JRT_EOF) /* Can't be stale */
+ return (SS_NORMAL);
+ assert(b->reclen == EOF_RECLEN);
+ assert(b->readaddr - b->recaddr >= EOF_RECLEN);
+ b->buffremaining += (b->readaddr - b->recaddr);
+ b->readaddr = b->recaddr;
+ b->reclen = 0;
+ return (SS_NORMAL);
+}
+
+static int update_max_seqno_info(repl_ctl_element *ctl)
+{ /* The information in ctl is outdated. The journal file has grown. Update max_seqno and its dskaddr */
+ int eof_change;
+ repl_buff_t *rb;
+ repl_buff_desc *b;
+ repl_file_control_t *fc;
+ uint4 dskread, stop_at;
+ boolean_t max_seqno_found;
+ uint4 max_seqno_addr;
+ seq_num max_seqno, reg_seqno;
+ int status;
+ enum jnl_record_type rectype;
+ gd_region *reg;
+ sgmnt_addrs *csa;
+
+ assert(ctl->file_state == JNL_FILE_OPEN);
+
+ rb = ctl->repl_buff;
+ fc = rb->fc;
+ reg = ctl->reg;
+ csa = &FILE_INFO(reg)->s_addrs;
+ if (!ctl->eof_addr_final)
+ update_eof_addr(ctl, &eof_change);
+# ifdef GTMSOURCE_SKIP_DSKREAD_WHEN_NO_EOF_CHANGE
+ /* This piece of code needs some more testing - Vinaya 03/11/98 */
+ if ((0 == eof_change) && ctl->first_read_done)
+ {
+ REPL_DPRINT2("UPDATE MAX SEQNO INFO: No change in EOF addr. Skipping disk read for %s\n", ctl->jnl_fn);
+ return (SS_NORMAL);
+ }
+# endif
+ if (fc->eof_addr == JNL_FILE_FIRST_RECORD)
+ {
+ repl_errno = EREPL_JNLEARLYEOF;
+ return (repl_errno);
+ }
+ QWASSIGN(reg_seqno, csa->hdr->reg_seqno);
+ QWDECRBYDW(reg_seqno, 1);
+ assert(!ctl->max_seqno_final || ctl->eof_addr_final);
+ if (QWGE(ctl->max_seqno, reg_seqno) || (ctl->max_seqno_final && ctl->first_read_done))
+ { /* have searched already */
+ REPL_DPRINT4("UPDATE MAX SEQNO INFO : not reading file %s; max_seqno = "INT8_FMT", reg_seqno = "INT8_FMT"\n",
+ ctl->jnl_fn, INT8_PRINT(ctl->max_seqno), INT8_PRINT(reg_seqno));
+ return (SS_NORMAL);
+ }
+ rb->buffindex = REPL_SCRATCHBUFF; /* temporarily set to scratch buffer */
+ b = &rb->buff[rb->buffindex];
+ dskread = ROUND_DOWN(fc->eof_addr, REPL_BLKSIZE(rb));
+ if (dskread == fc->eof_addr)
+ dskread -= REPL_BLKSIZE(rb);
+ QWASSIGN(max_seqno, seq_num_zero);
+ max_seqno_addr = 0;
+ max_seqno_found = FALSE;
+ do
+ {
+ /* Ignore the existing contents of scratch buffer */
+ b->buffremaining = REPL_BLKSIZE(rb);
+ b->recbuff = b->base;
+ b->reclen = 0;
+ b->readaddr = b->recaddr = JNL_BLK_DSKADDR(dskread, REPL_BLKSIZE(rb));
+ if (b->readaddr == JNL_FILE_FIRST_RECORD && adjust_buff_leaving_hdr(rb) != SS_NORMAL)
+ {
+ assert(repl_errno == EREPL_BUFFNOTFRESH);
+ GTMASSERT; /* Program bug */
+ }
+ stop_at = dskread + MIN(REPL_BLKSIZE(rb), fc->eof_addr - dskread); /* Limit search to this block */
+ /* If we don't limit the search, we may end up re-reading blocks that follow this block. The consequence of
+ * limiting the search is that we may not find the maximum close to the current state, but some time in the past
+ * for a file that is growing. We can live with that as we will redo the max search if necessary */
+ assert(stop_at > dskread);
+ while (b->reclen < stop_at - b->recaddr)
+ {
+ if ((status = repl_next(rb)) == SS_NORMAL)
+ {
+ rectype = ((jrec_prefix *)b->recbuff)->jrec_type;
+ if (IS_REPLICATED(rectype))
+ {
+ QWASSIGN(max_seqno, GET_JNL_SEQNO(b->recbuff));
+ max_seqno_addr = b->recaddr;
+ } else if (rectype == JRT_EOF)
+ break;
+ } else if (status == EREPL_JNLRECINCMPL)
+ { /* it is possible to get this return value if jb->dskaddr is in the middle of a journal record */
+ break;
+ } else
+ {
+ if (status == EREPL_JNLRECFMT)
+ rts_error(VARLSTCNT(5) ERR_JNLBADRECFMT, 3, ctl->jnl_fn_len, ctl->jnl_fn, b->recaddr);
+ else
+ GTMASSERT;
+ }
+ }
+ if ((max_seqno_found = (0 != max_seqno)) || (0 == dskread))
+ break;
+ dskread -= REPL_BLKSIZE(rb);
+ } while (TRUE);
+ rb->buffindex = REPL_MAINBUFF; /* reset back to the main buffer */
+ if (max_seqno_found)
+ {
+ QWASSIGN(ctl->max_seqno, max_seqno);
+ ctl->max_seqno_dskaddr = max_seqno_addr;
+ if (ctl->eof_addr_final)
+ ctl->max_seqno_final = TRUE; /* No more max_seqno updates as this journal file has switched */
+ return (SS_NORMAL);
+ }
+ /* dskread == 0 */
+ repl_errno = EREPL_JNLEARLYEOF;
+ return (repl_errno);
+}
+
+static int adjust_buff_leaving_hdr(repl_buff_t *rb)
+{ /* The first alignsize bytes to be read from jnl file. Adjust fields in rb->buff[rb->buffindex] to skip jnl file header */
+ repl_buff_desc *b;
+
+ if (REPL_BLKSIZE(rb) <= JNL_FILE_FIRST_RECORD)
+ return (SS_NORMAL);
+ b = &rb->buff[rb->buffindex];
+ if (b->buffremaining < REPL_BLKSIZE(rb))
+ {
+ repl_errno = EREPL_BUFFNOTFRESH;
+ return (repl_errno);
+ }
+ memset(b->base, 0, JNL_FILE_FIRST_RECORD);
+ b->recbuff = b->base + JNL_FILE_FIRST_RECORD;
+ b->reclen = 0;
+ b->recaddr = b->readaddr = JNL_FILE_FIRST_RECORD;
+ b->buffremaining -= JNL_FILE_FIRST_RECORD;
+ return (SS_NORMAL);
+}
+
+static int first_read(repl_ctl_element *ctl)
+{ /* The first read from this generation of the journal file. Find the min_seqno, max_seqno.
+ * If EOF is found while searching for min_seqno, or, nothing could be read from this file,
+ * this is an empty journal file, probably will be written to later.
+ * Position the next read at min_seqno. Update the max_seqno_info.
+ */
+
+ int status, eof_change;
+ enum jnl_record_type rectype;
+ repl_buff_t *rb;
+ repl_buff_desc *b;
+ repl_file_control_t *fc;
+ boolean_t min_seqno_found;
+ unsigned char seq_num_str[32], *seq_num_ptr; /* INT8_PRINT */
+
+ rb = ctl->repl_buff;
+ assert(rb->buffindex == REPL_MAINBUFF);
+ b = &rb->buff[rb->buffindex];
+ fc = rb->fc;
+ /* Ignore the existing contents of the buffer */
+ b->buffremaining = REPL_BLKSIZE(rb);
+ b->recbuff = b->base;
+ b->reclen = 0;
+ b->readaddr = JNL_FILE_FIRST_RECORD;
+ b->recaddr = JNL_FILE_FIRST_RECORD;
+ if (adjust_buff_leaving_hdr(rb) != SS_NORMAL)
+ {
+ assert(repl_errno == EREPL_BUFFNOTFRESH);
+ GTMASSERT; /* Program bug */
+ }
+ min_seqno_found = FALSE;
+ while (!min_seqno_found)
+ {
+ if ((status = repl_next(rb)) == SS_NORMAL)
+ {
+ rectype = ((jrec_prefix *)b->recbuff)->jrec_type;
+ if (IS_REPLICATED(rectype))
+ {
+ QWASSIGN(ctl->min_seqno, GET_JNL_SEQNO(b->recbuff));
+ QWASSIGN(ctl->seqno, ctl->min_seqno);
+ ctl->tn = ((jrec_prefix *)b->recbuff)->tn;
+ QWASSIGN(ctl->max_seqno, ctl->min_seqno);
+ ctl->min_seqno_dskaddr = ctl->max_seqno_dskaddr = b->recaddr;
+ ctl->file_state = JNL_FILE_OPEN;
+ min_seqno_found = TRUE;
+ } else if (rectype == JRT_EOF)
+ {
+ ctl->first_read_done = TRUE;
+ REPL_DPRINT2("JRT_EOF read when looking for first replication record. Empty file %s\n",
+ ctl->jnl_fn);
+ return (SS_NORMAL);
+ }
+ } else if (status == EREPL_JNLRECINCMPL) /* Nothing read */
+ {
+ ctl->first_read_done = TRUE;
+ REPL_DPRINT2("Nothing read when looking for first replication record. Empty file %s\n", ctl->jnl_fn);
+ return (SS_NORMAL);
+ } else
+ {
+ if (status == EREPL_JNLRECFMT)
+ rts_error(VARLSTCNT(5) ERR_JNLBADRECFMT, 3, ctl->jnl_fn_len, ctl->jnl_fn, b->recaddr);
+ }
+ }
+ REPL_DPRINT5("FIRST READ of %s - Min seqno "INT8_FMT" min_seqno_dskaddr %u EOF addr %u\n",
+ ctl->jnl_fn, INT8_PRINT(ctl->min_seqno), ctl->min_seqno_dskaddr, ctl->repl_buff->fc->eof_addr);
+ if (update_max_seqno_info(ctl) != SS_NORMAL)
+ {
+ assert(repl_errno == EREPL_JNLEARLYEOF);
+ GTMASSERT; /* Program bug */
+ }
+ REPL_DPRINT5("FIRST READ of %s - Max seqno "INT8_FMT" max_seqno_dskaddr %u EOF addr %d\n",
+ ctl->jnl_fn, INT8_PRINT(ctl->max_seqno), ctl->max_seqno_dskaddr, ctl->repl_buff->fc->eof_addr);
+ ctl->first_read_done = TRUE;
+ return (SS_NORMAL);
+}
+
+static void increase_buffer(unsigned char **buff, int *buflen, int buffer_needed)
+{
+ int newbuffsize, alloc_status;
+ unsigned char *old_msgp;
+
+ /* The tr size is not known apriori. Hence, a good guess of 1.5 times the current buffer space is used */
+ newbuffsize = gtmsource_msgbufsiz + (gtmsource_msgbufsiz >> 1);
+ if (buffer_needed > newbuffsize)
+ newbuffsize = buffer_needed;
+ REPL_DPRINT3("Buff space shortage. Attempting to increase buff space. Curr buff space %d. Attempt increase to atleast %d\n",
+ gtmsource_msgbufsiz, newbuffsize);
+ old_msgp = (unsigned char *)gtmsource_msgp;
+ if ((alloc_status = gtmsource_alloc_msgbuff(newbuffsize)) != SS_NORMAL)
+ {
+ rts_error(VARLSTCNT(7) ERR_REPLCOMM, 0, ERR_TEXT, 2,
+ LEN_AND_LIT("Error extending buffer space while reading files. Malloc error"), alloc_status);
+ }
+ *buff = (unsigned char *)gtmsource_msgp + (*buff - old_msgp);
+ *buflen = gtmsource_msgbufsiz - (*buff - (unsigned char *)gtmsource_msgp);
+ return;
+}
+
+static int read_transaction(repl_ctl_element *ctl, unsigned char **buff, int *bufsiz, seq_num read_jnl_seqno)
+{ /* Read the transaction ctl->seqno into buff. Position the next read at the next seqno in the journal file.
+ * Update max_seqno if necessary. If read of the next seqno blocks, leave the read buffers as is.
+ * The next time when this journal file is accessed the read will move forward.
+ */
+ repl_buff_t *rb;
+ repl_buff_desc *b;
+ repl_file_control_t *fc;
+ int readlen;
+ seq_num rec_jnl_seqno;
+ enum jnl_record_type rectype;
+ int status;
+ seq_num read_seqno;
+ unsigned char *seq_num_ptr, seq_num_str[32]; /* INT8_PRINT */
+
+ rb = ctl->repl_buff;
+ assert(rb->buffindex == REPL_MAINBUFF);
+ b = &rb->buff[rb->buffindex];
+ fc = rb->fc;
+ ctl->read_complete = FALSE;
+ readlen = 0;
+ assert(0 != b->reclen);
+ if (b->reclen > *bufsiz)
+ increase_buffer(buff, bufsiz, b->reclen);
+ assert(b->reclen <= *bufsiz);
+ memcpy(*buff, b->recbuff, b->reclen);
+ *buff += b->reclen;
+ readlen += b->reclen;
+ *bufsiz -= b->reclen;
+ rectype = ((jrec_prefix *)b->recbuff)->jrec_type;
+ assert(IS_REPLICATED(rectype));
+ rec_jnl_seqno = GET_REPL_JNL_SEQNO(b->recbuff);
+ assert(QWEQ(rec_jnl_seqno, ctl->seqno));
+ if (QWGT(rec_jnl_seqno, ctl->max_seqno))
+ {
+ QWASSIGN(ctl->max_seqno, rec_jnl_seqno);
+ ctl->max_seqno_dskaddr = b->recaddr;
+ }
+ ctl->tn = ((jrec_prefix *)b->recbuff)->tn;
+ if (!IS_FENCED(rectype) || JRT_NULL == rectype)
+ { /* Entire transaction done */
+ ctl->read_complete = TRUE;
+ trans_read = TRUE;
+ } else
+ {
+ assert(IS_TUPD(rectype) || IS_FUPD(rectype)); /* The first record should be the beginning of a transaction */
+ }
+ /* Suggested optimisation : Instead of waiting for all records pertaining to this transaction to
+ * be written to the journal file, read those available, mark this file BLOCKED, read other journal
+ * files, and come back to this journal file later.
+ */
+ while (!ctl->read_complete) /* Read the rest of the transaction */
+ {
+ if ((status = repl_next(rb)) == SS_NORMAL)
+ {
+ rectype = ((jrec_prefix *)b->recbuff)->jrec_type;
+ if (IS_REPLICATED(rectype))
+ {
+ if (b->reclen > *bufsiz)
+ increase_buffer(buff, bufsiz, b->reclen);
+ assert(b->reclen <= *bufsiz);
+ if (rectype != JRT_TCOM && rectype != JRT_ZTCOM)
+ {
+ memcpy(*buff, b->recbuff, b->reclen);
+ *buff += b->reclen;
+ readlen += b->reclen;
+ } else
+ {
+ memcpy(tcombuffp, b->recbuff, b->reclen);
+ tcombuffp += b->reclen;
+ tot_tcom_len += b->reclen;
+ /* End of transaction in this file */
+ ctl->read_complete = TRUE;
+ if (num_tcom == -1)
+ num_tcom = ((jnl_record *)b->recbuff)->jrec_tcom.num_participants;
+ num_tcom--;
+ if (num_tcom == 0) /* Read the whole trans */
+ trans_read = TRUE;
+ }
+ *bufsiz -= b->reclen;
+ QWASSIGN(rec_jnl_seqno, GET_JNL_SEQNO(b->recbuff));
+ assert(QWEQ(rec_jnl_seqno, ctl->seqno));
+ if (QWGT(rec_jnl_seqno, ctl->max_seqno))
+ {
+ QWASSIGN(ctl->max_seqno, rec_jnl_seqno);
+ ctl->max_seqno_dskaddr = b->recaddr;
+ }
+ ctl->tn = ((jrec_prefix *)b->recbuff)->tn;
+ } else if (rectype == JRT_EOF)
+ {
+ assert(FALSE);
+ rts_error(VARLSTCNT(7) ERR_REPLBRKNTRANS, 1, &read_jnl_seqno,
+ ERR_TEXT, 2, RTS_ERROR_LITERAL("Early EOF found"));
+ }
+ } else if (status == EREPL_JNLRECINCMPL)
+ { /* Log warning message for every certain number of attempts. There might have been a crash
+ * and the file might have been corrupted. The file possibly might never grow.
+ * Such cases have to be detected and attempt to read such files aborted.
+ */
+ gtmsource_poll_actions(TRUE);
+ SHORT_SLEEP(GTMSOURCE_WAIT_FOR_JNL_RECS);
+ if ((total_wait_for_jnl_recs += GTMSOURCE_WAIT_FOR_JNL_RECS) % LOG_WAIT_FOR_JNL_RECS_PERIOD == 0)
+ {
+ repl_log(gtmsource_log_fp, TRUE, TRUE, "REPL_WARN : Source server waited %dms for journal record(s)"
+ " to be written to journal file %s while attempting to read transaction "INT8_FMT". "
+ "Check for problems with journaling\n", total_wait_for_jnl_recs, ctl->jnl_fn,
+ INT8_PRINT(ctl->seqno));
+ }
+ } else
+ {
+ if (status == EREPL_JNLRECFMT)
+ rts_error(VARLSTCNT(5) ERR_JNLBADRECFMT, 3, ctl->jnl_fn_len, ctl->jnl_fn, b->recaddr);
+ else
+ GTMASSERT;
+ }
+ }
+ /* Try positioning next read to the next seqno. Leave it as is if operation blocks (has to wait for records) */
+ QWADD(read_seqno, ctl->seqno, seq_num_one);
+ position_read(ctl, read_seqno);
+ return (readlen);
+}
+
+static tr_search_state_t do_linear_search(repl_ctl_element *ctl, uint4 lo_addr, uint4 max_readaddr, seq_num read_seqno,
+ tr_search_status_t *srch_status)
+{
+ repl_buff_t *rb;
+ repl_buff_desc *b;
+ seq_num rec_jnl_seqno;
+ enum jnl_record_type rectype;
+ tr_search_state_t found;
+ int status;
+
+ REPL_DPRINT5("do_linear_search: file : %s lo_addr : %u max_readaddr : %u read_seqno : %llu\n",
+ ctl->jnl_fn, lo_addr, max_readaddr, read_seqno);
+ assert(lo_addr < max_readaddr);
+ rb = ctl->repl_buff;
+ assert(rb->buffindex == REPL_MAINBUFF);
+ b = &rb->buff[rb->buffindex];
+ if (lo_addr != b->recaddr)
+ { /* Initiate a fresh read */
+ lo_addr = ROUND_DOWN(lo_addr, REPL_BLKSIZE(rb));
+ b->recaddr = b->readaddr = JNL_BLK_DSKADDR(lo_addr, REPL_BLKSIZE(rb));
+ b->recbuff = b->base;
+ b->reclen = 0;
+ b->buffremaining = REPL_BLKSIZE(rb);
+ if (b->readaddr == JNL_FILE_FIRST_RECORD && adjust_buff_leaving_hdr(rb) != SS_NORMAL)
+ {
+ assert(repl_errno == EREPL_BUFFNOTFRESH);
+ GTMASSERT; /* Program bug */
+ }
+ REPL_DPRINT1("do_linear_search: initiating fresh read\n");
+ } else
+ { /* use what has been read already */
+ assert(read_seqno != ctl->seqno); /* if not, we'll skip to the next transaction and declare read_seqno not found */
+ }
+ found = TR_NOT_FOUND;
+ srch_status->prev_seqno = srch_status->seqno = 0;
+ while (found == TR_NOT_FOUND && b->reclen < max_readaddr - b->recaddr)
+ {
+ if ((status = repl_next(rb)) == SS_NORMAL)
+ {
+ rectype = ((jrec_prefix *)b->recbuff)->jrec_type;
+ if (IS_REPLICATED(rectype))
+ {
+ rec_jnl_seqno = GET_JNL_SEQNO(b->recbuff);
+ if (srch_status->seqno == 0 || srch_status->seqno != rec_jnl_seqno)
+ { /* change srch_status only when records of different transactions are encountered */
+ srch_status->prev_seqno = srch_status->seqno;
+ srch_status->seqno = rec_jnl_seqno;
+ }
+ if (QWLT(ctl->max_seqno, rec_jnl_seqno))
+ {
+ QWASSIGN(ctl->max_seqno, rec_jnl_seqno);
+ ctl->max_seqno_dskaddr = b->recaddr;
+ }
+ QWASSIGN(ctl->seqno, rec_jnl_seqno);
+ ctl->tn = ((jrec_prefix *)b->recbuff)->tn;
+ if (QWEQ(rec_jnl_seqno, read_seqno))
+ found = TR_FOUND;
+ else if (QWGT(rec_jnl_seqno, read_seqno))
+ found = TR_WILL_NOT_BE_FOUND;
+ } else if (rectype == JRT_EOF)
+ found = TR_WILL_NOT_BE_FOUND;
+ } else if (status == EREPL_JNLRECINCMPL)
+ found = TR_FIND_WOULD_BLOCK;
+ else if (status == EREPL_JNLRECFMT)
+ rts_error(VARLSTCNT(5) ERR_JNLBADRECFMT, 3, ctl->jnl_fn_len, ctl->jnl_fn, b->recaddr);
+ }
+ REPL_DPRINT2("do_linear_search: returning %s\n", (found == TR_NOT_FOUND) ? "TR_NOT_FOUND" :
+ (found == TR_FOUND) ? "TR_FOUND" :
+ (found == TR_WILL_NOT_BE_FOUND) ? "TR_WILL_NOT_BE_FOUND" :
+ (found == TR_FIND_WOULD_BLOCK) ? "TR_FIND_WOULD_BLOCK" :
+ "*UNKNOWN RETURN CODE*");
+ return (found);
+}
+
+static tr_search_state_t do_binary_search(repl_ctl_element *ctl, uint4 lo_addr, uint4 hi_addr, seq_num read_seqno,
+ tr_search_status_t *srch_status)
+{
+ repl_buff_t *rb;
+ repl_buff_desc *b;
+ repl_file_control_t *fc;
+ tr_search_state_t found;
+ uint4 low, high, mid, new_mid, mid_further, stop_at;
+ uint4 srch_half_lo_addr, srch_half_hi_addr, othr_half_lo_addr, othr_half_hi_addr;
+ uint4 hi_addr_mod, hi_addr_diff, mid_mod, mid_diff;
+ uint4 willnotbefound_addr = 0, willnotbefound_stop_at = 0;
+ int iter, max_iter;
+ enum jnl_record_type rectype;
+ boolean_t search_complete = FALSE;
+
+ REPL_DPRINT5("do_binary_search: file : %s lo_addr : %u hi_addr : %u read_seqno : %llu\n",
+ ctl->jnl_fn, lo_addr, hi_addr, read_seqno);
+ if (lo_addr > hi_addr)
+ {
+ REPL_DPRINT1("do_binary_search: lower limit is larger than upper limit, search not initiated\n");
+ return TR_NOT_FOUND;
+ }
+ rb = ctl->repl_buff;
+ assert(rb->buffindex == REPL_MAINBUFF);
+ b = &rb->buff[rb->buffindex];
+ fc = rb->fc;
+ assert(lo_addr < fc->eof_addr);
+ assert(hi_addr <= fc->eof_addr);
+ assert(lo_addr <= hi_addr);
+ low = ROUND_DOWN(lo_addr, REPL_BLKSIZE(rb));
+ if (0 == (hi_addr_mod = hi_addr % REPL_BLKSIZE(rb)))
+ hi_addr_mod = REPL_BLKSIZE(rb); /* avoid including additional block if already aligned */
+ hi_addr_diff = fc->eof_addr - hi_addr;
+ high = hi_addr + MIN(REPL_BLKSIZE(rb) - hi_addr_mod, hi_addr_diff);
+ for (found = TR_NOT_FOUND, mid = ROUND_DOWN((low >> 1) + (high >> 1), REPL_BLKSIZE(rb)); ; )
+ {
+ mid_mod = mid % REPL_BLKSIZE(rb);
+ mid_diff = fc->eof_addr - mid;
+ assert(0 != mid_diff);
+ stop_at = mid + MIN(REPL_BLKSIZE(rb) - mid_mod, mid_diff);
+ /* Note that for high values of journal-alignsize (which is what REPL_BLKSIZE macro expands to), it is
+ * possible that stop_at is GREATER than high. Since it is not necessary to search any further than high,
+ * limit it accordingly before calling the linear search.
+ */
+ found = do_linear_search(ctl, mid, MIN(stop_at, high), read_seqno, srch_status);
+ assert(srch_status->seqno == 0 || srch_status->seqno == ctl->seqno);
+ switch (found)
+ {
+ case TR_FOUND:
+ rectype = ((jrec_prefix *)b->recbuff)->jrec_type;
+ if (!IS_FENCED(rectype) || IS_TUPD(rectype) || IS_FUPD(rectype) || JRT_NULL == rectype)
+ {
+ REPL_DPRINT4("do_binary_search: found %llu at %u in %s\n", read_seqno, b->recaddr,
+ ctl->jnl_fn);
+ return found;
+ }
+ assert(b->recaddr >= REPL_BLKSIZE(rb)); /* cannot have trailing records of a tr in first block */
+ low = ((b->recaddr > REPL_BLKSIZE(rb)) ?
+ ROUND_DOWN(b->recaddr - REPL_BLKSIZE(rb), REPL_BLKSIZE(rb)) : 0);
+ high = ROUND_DOWN(b->recaddr, REPL_BLKSIZE(rb));
+ REPL_DPRINT5("do_binary_search: found record of type %d with seqno %llu at %u in %s\n",
+ rectype, read_seqno, b->recaddr, ctl->jnl_fn);
+ REPL_DPRINT3("do_binary_search: will back off and search for beginning of transaction, changing "
+ "low to %u high to %u\n", low, high);
+ break;
+ case TR_NOT_FOUND:
+ assert(b->readaddr == stop_at);
+ if (srch_status->seqno != 0)
+ { /* at least one replicated record found in block */
+ assert(read_seqno > srch_status->seqno);
+ low = stop_at; /* search in the upper half */
+ REPL_DPRINT5("do_binary_search: could not find %llu in block %u, last seen replicated "
+ "record has seqno %llu changing low to %u\n", read_seqno, mid,
+ srch_status->seqno, low);
+ } else
+ { /* no replicated record found in block */
+ assert(srch_status->prev_seqno == 0); /* must hold if no replicated record found */
+ REPL_DPRINT3("do_binary_search: could not find %llu, no replicated record in block %u, "
+ "searching lower half", read_seqno, mid);
+ if (low < mid) /* seach lower half recursively */
+ found = do_binary_search(ctl, low, mid, read_seqno, srch_status);
+ else
+ {
+ REPL_DPRINT4("do_binary_search: all blocks searched in lower half search, "
+ "seqno %llu not found, low %u high %u\n", read_seqno, low, mid);
+ }
+ if (found == TR_NOT_FOUND && stop_at < high) /* search upper half recursively */
+ found = do_binary_search(ctl, stop_at, high, read_seqno, srch_status);
+ else
+ {
+ REPL_DEBUG_ONLY(
+ if (found == TR_NOT_FOUND)
+ {
+ REPL_DPRINT4("do_binary_search: all blocks searched in upper half"
+ " search, seqno %llu not found, low %u high %u\n",
+ read_seqno, stop_at, high);
+ }
+ )
+ }
+ if (found != TR_NOT_FOUND)
+ return found;
+ search_complete = TRUE;
+ }
+ break;
+
+ case TR_WILL_NOT_BE_FOUND:
+ if (srch_status->seqno != 0 && read_seqno < srch_status->seqno)
+ {
+ if (srch_status->prev_seqno == 0)
+ { /* first replicated record in block has larger seqno than read_seqno */
+ REPL_DPRINT5("do_binary_search: will not find %llu, first replicated record in "
+ "block %u has seqno %llu, changing high to %u\n", read_seqno, mid,
+ srch_status->seqno, mid);
+ willnotbefound_addr = mid;
+ willnotbefound_stop_at = stop_at;
+ high = mid; /* search in the lower half */
+ } else
+ { /* at least two replicated records found, and the read_seqno is between the seqno
+ * numbers of two records */
+ REPL_DPRINT5("do_binary_search: will not find %llu in block %u, last two seqnos are"
+ " %llu and %llu, return WILL_NOT_BE_FOUND\n", read_seqno, mid,
+ srch_status->prev_seqno, srch_status->seqno);
+ assert(srch_status->prev_seqno < read_seqno);
+ return found; /* read_seqno is not in this journal file */
+ }
+ } else
+ { /* found EOF record, read_seqno is not in this journal file */
+ REPL_DPRINT3("do_binary_search: will not find %llu in block %u, EOF found\n", read_seqno,
+ mid);
+ return found;
+ }
+ break;
+
+ case TR_FIND_WOULD_BLOCK:
+ assert(mid == ROUND_DOWN(high, REPL_BLKSIZE(rb))); /* must be the last block for this retval */
+ assert(ctl->file_state == JNL_FILE_OPEN || /* file that is yet to grow, or truncated file */
+ ctl->file_state == JNL_FILE_CLOSED && 0 != fc->jfh->prev_recov_end_of_data);
+ if (srch_status->seqno != 0)
+ { /* journal flush yet to be done, or truncated file's end_of_data reached, can't locate seqno */
+ assert(read_seqno > srch_status->seqno);
+ REPL_DPRINT4("do_binary_search: find of %llu would block, last seqno %llu found in block "
+ "%u\n", read_seqno, srch_status->seqno, mid);
+ return (ctl->file_state == JNL_FILE_OPEN ? found : TR_WILL_NOT_BE_FOUND);
+ }
+ /* no replicated record found in the block, search in previous block(s) */
+ high = (high > REPL_BLKSIZE(rb)) ? high - REPL_BLKSIZE(rb) : 0;
+ REPL_DPRINT4("do_binary_search: find of %llu would block, no seqno found in block %u, "
+ "change high to %u\n", read_seqno, mid, high);
+ break;
+
+ default: /* Why didn't we cover all cases? */
+ GTMASSERT;
+ } /* end switch */
+ if (!search_complete && low < high)
+ {
+ new_mid = ROUND_DOWN((low >> 1) + (high >> 1), REPL_BLKSIZE(rb));
+ mid_further = (new_mid != mid) ? 0 : REPL_BLKSIZE(rb); /* if necessary, move further to avoid repeat */
+ if (high - new_mid > mid_further)
+ {
+ mid = new_mid + mid_further;
+ continue;
+ }
+ }
+ REPL_DPRINT6("do_binary_search: all blocks searched, seqno %llu not found, low %u high %u mid %u mid_further %u\n",
+ read_seqno, low, high, mid, mid_further);
+ assert(found != TR_FOUND);
+ /* done searching all blocks between lo_addr and hi_addr */
+ if (found == TR_NOT_FOUND && 0 != willnotbefound_addr)
+ { /* There is a block that contains a seqno larger than read_seqno; leave ctl positioned at that seqno.
+ * If we don't do this, we may repeat binary search (wastefully) for all seqnos between read_seqno and
+ * the least seqno larger than read_seqno in this file.
+ */
+ found = do_linear_search(ctl, willnotbefound_addr, willnotbefound_stop_at, read_seqno, srch_status);
+ REPL_DPRINT4("do_binary_search: position at seqno %llu in block [%u, %u)\n", srch_status->seqno,
+ willnotbefound_addr, willnotbefound_stop_at);
+ assert(found == TR_WILL_NOT_BE_FOUND);
+ assert(read_seqno < ctl->seqno);
+ }
+ return found;
+ } /* end for */
+}
+
+static tr_search_state_t position_read(repl_ctl_element *ctl, seq_num read_seqno)
+{
+ repl_buff_t *rb;
+ repl_buff_desc *b;
+ uint4 lo_addr, hi_addr;
+ tr_search_state_t found, (*srch_func)();
+ tr_search_status_t srch_status;
+ uint4 willnotbefound_addr = 0, willnotbefound_stop_at = 0;
+ int eof_change;
+ DEBUG_ONLY(jnl_record *jrec;)
+ DEBUG_ONLY(enum jnl_record_type rectype;)
+
+ /* Position read pointers so that the next read should get the first journal record with JNL_SEQNO atleast read_seqno.
+ * Do a search between min_seqno and seqno if read_seqno < ctl->seqno; else search from ctl->seqno onwards.
+ * If ctl->seqno > ctl->max_seqno update max_seqno as you move, else search between ctl->seqno and ctl->max_seqno.
+ * We want to do a binary search here.
+ */
+
+ /* If the receiver disconnects while we were previously in the read-file mode and later reconnects requesting a
+ * particular sequence number, it is possible that we can have an out-of-date fc->eof_addr as fc->eof_addr is not
+ * frequently updated. But, now that we will be searching for the sequence number (either with binary or linear
+ * search) update the fc->eof_addr unconditionally. This is considered okay since the update_eof_addr function
+ * is a almost always a light weight function (with the only exception being the case when the jnl file source
+ * server is interested in is not the latest generation file then it could end up reading the journal file header
+ * from disk but that too it does only once per older generation journal file so it is okay)
+ */
+ if (!ctl->eof_addr_final)
+ update_eof_addr(ctl, &eof_change);
+ /* Validate the range; if called from read_transaction(), it is possible that we are looking out of range, but
+ * we clearly can identify such a case */
+ assert(ctl->min_seqno <= read_seqno);
+ assert(read_seqno <= ctl->max_seqno || read_seqno == ctl->seqno + 1);
+ rb = ctl->repl_buff;
+ assert(REPL_MAINBUFF == rb->buffindex);
+ b = &rb->buff[rb->buffindex];
+ /* looking up something we read already? */
+ assert(read_seqno != ctl->seqno || read_seqno == ctl->min_seqno || read_seqno == ctl->max_seqno || ctl->lookback);
+ srch_func = do_binary_search;
+ if (read_seqno > ctl->seqno)
+ {
+ if (read_seqno == ctl->seqno + 1)
+ { /* trying to position to next seqno or the max, better to do linear search */
+ srch_func = do_linear_search;
+ lo_addr = b->recaddr;
+ hi_addr = MAXUINT4;
+ } else if (read_seqno < ctl->max_seqno)
+ {
+ lo_addr = b->recaddr;
+ hi_addr = ctl->max_seqno_dskaddr;
+ /* Since we know that read_seqno is LESSER than ctl->max_seqno, we know for sure we should not return
+ * this function with found = TR_NOT_FOUND. If ever the binary/linear search invocation at the end of
+ * this function returns with TR_NOT_FOUND, we have to change that to TR_WILL_NOT_BE_FOUND and also
+ * adjust ctl->seqno to point to ctl->max_seqno that way we dont repeat binary search (wastefully) for
+ * all seqnos between read_seqno and the least seqno larger than read_seqno in this file.
+ */
+ willnotbefound_addr = hi_addr;
+ assert(ctl->max_seqno_dskaddr < rb->fc->eof_addr);
+ willnotbefound_stop_at = rb->fc->eof_addr;
+ } else if (read_seqno == ctl->max_seqno)
+ { /* For read_seqno == ctl->max_seqno, do not use linear search. Remember, max_seqno_dskaddr may be the
+ * the address of the TCOM record of a transaction, and this TCOM record may be in a different block
+ * than the block containing the first record of the transcation. To get it right, we may have to
+ * back off to previous blocks. Well, do_binary_search() handles this condition. So, better we use binary
+ * search. */
+ lo_addr = b->recaddr;
+ assert(ctl->max_seqno_dskaddr < rb->fc->eof_addr);
+ hi_addr = rb->fc->eof_addr;
+ } else /* read_seqno > ctl->max_seqno */
+ {
+ lo_addr = ctl->max_seqno_dskaddr;
+ hi_addr = rb->fc->eof_addr;
+ }
+ } else /* (read_seqno <= ctl->seqno) */
+ {
+ if (read_seqno != ctl->min_seqno)
+ {
+ lo_addr = ctl->min_seqno_dskaddr;
+ hi_addr = b->recaddr + b->reclen;
+ } else
+ { /* trying to locate min, better to do linear search */
+ srch_func = do_linear_search;
+ lo_addr = ctl->min_seqno_dskaddr;
+ hi_addr = MAXUINT4;
+ if (read_seqno == ctl->seqno) /* we are positioned where we want to be, no need for read */
+ {
+ assert(lo_addr == b->recaddr);
+ assert(MIN_JNLREC_SIZE <= b->reclen);
+ DEBUG_ONLY(jrec = (jnl_record *)b->recbuff;)
+ DEBUG_ONLY(rectype = jrec->prefix.jrec_type;)
+ assert(b->reclen == jrec->prefix.forwptr);
+ assert(IS_VALID_JNLREC(jrec, rb->fc->jfh));
+ assert(IS_REPLICATED(rectype));
+ assert(!IS_FENCED(rectype) || IS_TUPD(rectype) || IS_FUPD(rectype) || JRT_NULL == rectype);
+ REPL_DPRINT3("position_read: special case, read %llu is same as min in %s, returning TR_FOUND\n",
+ read_seqno, ctl->jnl_fn);
+ return TR_FOUND;
+ }
+ }
+ }
+#if defined(GTMSOURCE_READFILES_LINEAR_SEARCH_TEST)
+ srch_func = do_linear_search;
+ hi_addr = MAXUINT4;
+#elif defined(GTMSOURCE_READFILES_BINARY_SEARCH_TEST)
+ srch_func = do_binary_search;
+ hi_addr = rb->fc->eof_addr;
+#endif
+ REPL_DPRINT6("position_read: Using %s search to locate %llu in %s between %u and %u\n",
+ (srch_func == do_linear_search) ? "linear" : "binary", read_seqno, ctl->jnl_fn, lo_addr, hi_addr);
+ found = srch_func(ctl, lo_addr, hi_addr, read_seqno, &srch_status);
+ if ((TR_NOT_FOUND == found) && (0 != willnotbefound_addr))
+ { /* There is a block that contains a seqno larger than read_seqno; leave ctl positioned at this higher seqno.
+ * If we don't do this, we could end up in an infinite loop if the caller of this function is "read_regions".
+ * That caller redoes the "position_read" function call assuming there would have been some progress in the
+ * previous call to the same function. So not resetting ctl->seqno here will result in an infinite loop.
+ */
+ found = do_linear_search(ctl, willnotbefound_addr, willnotbefound_stop_at, read_seqno, &srch_status);
+ REPL_DPRINT4("do_binary_search: position at seqno %llu in block [%u, %u)\n", srch_status.seqno,
+ willnotbefound_addr, willnotbefound_stop_at);
+ assert(found == TR_WILL_NOT_BE_FOUND);
+ assert(read_seqno < ctl->seqno);
+ }
+ assert(found != TR_NOT_FOUND);
+ return (found);
+}
+
+static int read_and_merge(unsigned char *buff, int maxbufflen, seq_num read_jnl_seqno)
+{
+ int buff_avail, total_read, read_len, pass;
+ boolean_t brkn_trans;
+ unsigned char *seq_num_ptr, seq_num_str[32]; /* INT8_PRINT */
+ repl_ctl_element *ctl;
+
+ trans_read = FALSE;
+ num_tcom = -1;
+ tot_tcom_len = 0;
+ total_read = 0;
+ total_wait_for_jnl_recs = 0;
+ total_wait_for_jnlopen = 0;
+ tcombuffp = gtmsource_tcombuff_start;
+ buff_avail = maxbufflen;
+ for (ctl = repl_ctl_list->next; ctl != NULL; ctl = ctl->next)
+ ctl->read_complete = FALSE;
+ for (pass = 1; !trans_read; pass++)
+ {
+ if (pass > 1)
+ {
+ gtmsource_poll_actions(TRUE);
+ SHORT_SLEEP(GTMSOURCE_WAIT_FOR_JNLOPEN);
+ if ((total_wait_for_jnlopen += GTMSOURCE_WAIT_FOR_JNLOPEN) % LOG_WAIT_FOR_JNLOPEN_PERIOD == 0)
+ repl_log(gtmsource_log_fp, TRUE, TRUE, "REPL_WARN : Source server waited %dms for journal file(s) "
+ "to be opened, or updated while attempting to read transaction "INT8_FMT". Check for "
+ "problems with journaling\n", total_wait_for_jnlopen, INT8_PRINT(read_jnl_seqno));
+ }
+ read_len = read_regions(&buff, &buff_avail, pass > 1, &brkn_trans, read_jnl_seqno);
+ if (brkn_trans)
+ rts_error(VARLSTCNT(3) ERR_REPLBRKNTRANS, 1, &read_jnl_seqno);
+ total_read += read_len;
+ }
+ if (tot_tcom_len > 0)
+ { /* Copy all the TCOM records to the end of the buffer */
+ assert(tot_tcom_len <= ((unsigned char *)gtmsource_msgp + gtmsource_msgbufsiz - buff));
+ memcpy(buff, gtmsource_tcombuff_start, tot_tcom_len);
+ total_read += tot_tcom_len;
+ }
+ return (total_read);
+}
+
+static int read_regions(unsigned char **buff, int *buff_avail,
+ boolean_t attempt_open_oldnew, boolean_t *brkn_trans, seq_num read_jnl_seqno)
+{
+ repl_ctl_element *ctl, *prev_ctl, *old_ctl;
+ gd_region *region;
+ tr_search_state_t found;
+ int read_len, cumul_read;
+ int nopen;
+ unsigned char seq_num_str[32], *seq_num_ptr; /* INT8_PRINT */
+ DEBUG_ONLY(static int loopcnt;)
+ sgmnt_addrs *csa;
+ jnlpool_ctl_ptr_t jctl;
+ uint4 freeaddr;
+
+ cumul_read = 0;
+ *brkn_trans = TRUE;
+ assert(repl_ctl_list->next != NULL);
+ jctl = jnlpool.jnlpool_ctl;
+ /* For each region */
+ for (ctl = repl_ctl_list->next, prev_ctl = repl_ctl_list; ctl != NULL && !trans_read; prev_ctl = ctl, ctl = ctl->next)
+ {
+ found = TR_NOT_FOUND;
+ region = ctl->reg;
+ DEBUG_ONLY(loopcnt = 0;)
+ while (found == TR_NOT_FOUND)
+ { /* Find the generation of the journal file which has read_jnl_seqno */
+ for ( ; ctl != NULL && ctl->reg == region &&
+ ((ctl->file_state == JNL_FILE_CLOSED && QWGT(read_jnl_seqno, ctl->max_seqno))
+ || (ctl->file_state == JNL_FILE_EMPTY
+ && QWGE(read_jnl_seqno, ctl->repl_buff->fc->jfh->start_seqno)));
+ prev_ctl = ctl, ctl = ctl->next)
+ ;
+ if (ctl == NULL || ctl->reg != region)
+ { /* Hit the end of generation list for journal file */
+ if (!attempt_open_oldnew)
+ { /* Reposition to skip prev_ctl */
+ REPL_DPRINT2("First pass...not opening newer gener file...skipping %s\n", prev_ctl->jnl_fn);
+ ctl = prev_ctl;
+ prev_ctl = ctl->prev;
+ found = TR_FIND_WOULD_BLOCK;
+ continue;
+ }
+ nopen = open_newer_gener_jnlfiles(region, prev_ctl);
+ if (nopen > 0) /* Newer gener files opened */
+ {
+ if (prev_ctl->file_state == JNL_FILE_CLOSED)
+ { /* Recently updated journal file, search this */
+ ctl = prev_ctl;
+ prev_ctl = ctl->prev;
+ REPL_DPRINT3("Attempt search in %s. Next gener is %s\n",
+ ctl->jnl_fn, ctl->next->jnl_fn);
+ } else
+ { /* Search next gener onwards */
+ ctl = prev_ctl->next;
+ prev_ctl = ctl->prev;
+ REPL_DPRINT3("Skipping empty gener %s. Moving to gener %s\n",
+ prev_ctl->jnl_fn, ctl->jnl_fn);
+ }
+ } else if (nopen == 0)
+ { /* None opened, the journal file hasn't been written into.
+ * Reposition to skip the prev_ctl.
+ */
+ ctl = prev_ctl;
+ prev_ctl = ctl->prev;
+ if (QWLT(read_jnl_seqno, jctl->jnl_seqno))
+ {
+ csa = &FILE_INFO(ctl->reg)->s_addrs;
+ freeaddr = csa->jnl->jnl_buff->freeaddr;
+ if ((ctl->repl_buff->fc->eof_addr == freeaddr) || (!JNL_ENABLED(csa->hdr)))
+ { /* No more pending updates in the journal file. Next update to the
+ * journal file will take the seqno jctl->jnl_seqno which will be
+ * greater than read_jnl_seqno
+ */
+ found = TR_WILL_NOT_BE_FOUND;
+ continue;
+ }
+ }
+ found = TR_FIND_WOULD_BLOCK;
+ }
+ } else if (ctl->file_state == JNL_FILE_UNREAD)
+ {
+ if (!ctl->first_read_done || attempt_open_oldnew)
+ first_read(ctl);
+ if (ctl->file_state == JNL_FILE_UNREAD)
+ {
+ REPL_DPRINT2("First read of %s. Nothing yet written to this file\n", ctl->jnl_fn);
+ if (ctl->prev->reg == ctl->reg &&
+ QWGT(ctl->repl_buff->fc->jfh->start_seqno, read_jnl_seqno))
+ { /* Prev gener opened already. Looking for read_jnl_seqno in this gener,
+ * but the first possible seqno in this gener is > read_jnl_seqno.
+ */
+ found = TR_WILL_NOT_BE_FOUND;
+ continue;
+ }
+ if (ctl->prev->reg == ctl->reg)
+ { /* Nothing yet written to the file. Attempt opening next gener. */
+ assert(QWLE(ctl->prev->repl_buff->fc->jfh->start_seqno,
+ ctl->repl_buff->fc->jfh->start_seqno));
+ prev_ctl = ctl;
+ ctl = ctl->next;
+ } else if (attempt_open_oldnew)
+ {
+ if (open_prev_gener(&old_ctl, ctl, read_jnl_seqno) == 0)
+ {
+ if (QWGT(ctl->repl_buff->fc->jfh->start_seqno, read_jnl_seqno))
+ {
+ found = TR_WILL_NOT_BE_FOUND;
+ continue;
+ }
+ /* Nothing yet written to this file. Attempt opening next gener */
+ prev_ctl = ctl;
+ ctl = ctl->next;
+ } else
+ {
+ assert(old_ctl->file_state == JNL_FILE_CLOSED ||
+ old_ctl->file_state == JNL_FILE_EMPTY);
+ if (old_ctl->file_state == JNL_FILE_EMPTY ||
+ QWGT(old_ctl->min_seqno, read_jnl_seqno))
+ { /* Give the other regions a chance to
+ * open their previous generations.
+ */
+ REPL_DPRINT2("Skipping to other regions. Not reading from "
+ "previous generation file %s\n", old_ctl->jnl_fn);
+ found = TR_FIND_WOULD_BLOCK;
+ continue;
+ }
+ /* Search the prev gener and backwards */
+ ctl = old_ctl;
+ prev_ctl = old_ctl->prev;
+ REPL_DPRINT2("Attempt searching in %s and backwards\n", ctl->jnl_fn);
+ }
+ } else
+ {
+ REPL_DPRINT2("First pass...skipping UNREAD file %s\n", ctl->jnl_fn);
+ found = TR_FIND_WOULD_BLOCK;
+ continue;
+ }
+ }
+ } else if (ctl->file_state == JNL_FILE_EMPTY || QWGT(ctl->min_seqno, read_jnl_seqno))
+ { /* May be in prev gener */
+ if (ctl->prev->reg == ctl->reg && ctl->file_state != JNL_FILE_EMPTY)
+ { /* If prev gener is already open, and we come here, we are looking for
+ * a seqno between prev gener's max_seqno and this gener's min_seqno.
+ * This region is not part of the transaction. Skip to the next region.
+ */
+ REPL_DPRINT3("Gap between %s (max seqno "INT8_FMT,
+ ctl->prev->jnl_fn, INT8_PRINT(ctl->prev->max_seqno));
+ REPL_DPRINT3(") and %s (min seqno "INT8_FMT, ctl->jnl_fn, INT8_PRINT(ctl->min_seqno));
+ REPL_DPRINT2(") found while looking for "INT8_FMT"\n", INT8_PRINT(read_jnl_seqno));
+ assert(ctl->prev->file_state == JNL_FILE_CLOSED &&
+ QWLT(ctl->prev->max_seqno, read_jnl_seqno) ||
+ ctl->prev->file_state == JNL_FILE_EMPTY);
+ found = TR_WILL_NOT_BE_FOUND;
+ continue;
+ }
+ if (ctl->prev->reg == ctl->reg)
+ { /* Skip the empty gener */
+ REPL_DPRINT2("Skipping empty journal file %s\n", ctl->jnl_fn);
+ prev_ctl = ctl;
+ ctl = ctl->next;
+ continue;
+ }
+ if (!attempt_open_oldnew)
+ {
+ REPL_DPRINT2("First pass...not opening prev gener file...skipping %s\n", ctl->jnl_fn);
+ found = TR_FIND_WOULD_BLOCK;
+ continue;
+ }
+ /* Need to open prev gener */
+ if (open_prev_gener(&old_ctl, ctl, read_jnl_seqno) == 0)
+ {
+ if (ctl->file_state != JNL_FILE_EMPTY)
+ found = TR_WILL_NOT_BE_FOUND;
+ else
+ { /* Skip the empty generation */
+ REPL_DPRINT2("Skipping empty journal file %s\n", ctl->jnl_fn);
+ prev_ctl = ctl;
+ ctl = ctl->next;
+ }
+ continue;
+ }
+ assert(old_ctl->file_state == JNL_FILE_CLOSED || old_ctl->file_state == JNL_FILE_EMPTY);
+ if (old_ctl->file_state == JNL_FILE_EMPTY || QWGT(old_ctl->min_seqno, read_jnl_seqno))
+ { /* Give the other regions a chance to open their previous generations */
+ found = TR_FIND_WOULD_BLOCK;
+ REPL_DPRINT2("Skipping to other regions. Not reading from previous generation file %s\n",
+ old_ctl->jnl_fn);
+ continue;
+ }
+ /* Search the prev gener and backwards */
+ ctl = old_ctl;
+ prev_ctl = old_ctl->prev;
+ REPL_DPRINT2("Attempt searching in %s and backwards\n", ctl->jnl_fn);
+ } else
+ {
+ assert((ctl->file_state == JNL_FILE_OPEN || read_jnl_seqno <= ctl->max_seqno)
+ && ctl->min_seqno <= read_jnl_seqno);
+ if (ctl->lookback)
+ {
+ assert(QWLE(read_jnl_seqno, ctl->seqno));
+ assert(ctl->file_state == JNL_FILE_OPEN || ctl->file_state == JNL_FILE_CLOSED);
+ REPL_DPRINT4("Looking back and attempting to position read for %s at "
+ INT8_FMT". File state is %s\n", ctl->jnl_fn, INT8_PRINT(read_jnl_seqno),
+ (ctl->file_state == JNL_FILE_OPEN) ? "OPEN" : "CLOSED");
+ position_read(ctl, read_jnl_seqno);
+ ctl->lookback = FALSE;
+ }
+ if (QWEQ(read_jnl_seqno, ctl->seqno))
+ { /* Found it */
+ if (!ctl->read_complete)
+ {
+ if ((read_len = read_transaction(ctl, buff, buff_avail, read_jnl_seqno)) < 0)
+ assert(repl_errno == EREPL_JNLEARLYEOF);
+ cumul_read += read_len;
+ }
+ found = TR_FOUND;
+ } else if (QWLT(read_jnl_seqno, ctl->seqno))
+ { /* This region is not involved in transaction read_jnl_seqno */
+ found = TR_WILL_NOT_BE_FOUND;
+ } else /* QWGT(read_jnl_seqno, ctl->seqno) */
+ {
+ /* Detect infinite loop of calls to position_read() by limiting # of calls to 1024 in dbg */
+ DEBUG_ONLY(loopcnt++;)
+ assert(1024 > loopcnt);
+ if (ctl->file_state == JNL_FILE_OPEN)
+ { /* State change from READ_FILE->READ_POOL-> READ_FILE might cause this.
+ * The journal files have grown since the transition from READ_FILE to READ_POOL
+ * was made. Update ctl info.
+ */
+ if (update_max_seqno_info(ctl) != SS_NORMAL)
+ {
+ assert(repl_errno == EREPL_JNLEARLYEOF);
+ GTMASSERT; /* Program bug */
+ }
+ if (QWLE(read_jnl_seqno, ctl->max_seqno))
+ { /* May be found in this journal file,
+ * attempt to position next read to read_jnl_seqno
+ */
+ force_file_read(ctl); /* Buffer might be stale with an EOF record */
+ position_read(ctl, read_jnl_seqno);
+ } else
+ { /* Will possibly be found in next gener */
+ prev_ctl = ctl;
+ ctl = ctl->next;
+ }
+ } else if (ctl->file_state == JNL_FILE_CLOSED)
+ { /* May be found in this jnl file, attempt to position next read to read_jnl_seqno */
+ position_read(ctl, read_jnl_seqno);
+ } else
+ { /* Program bug - ctl->seqno should never be greater than ctl->max_seqno */
+ GTMASSERT;
+ }
+ }
+ }
+ }
+ /* Move to the next region, now that the tr has been found or will not be found */
+ *brkn_trans = (*brkn_trans && found == TR_WILL_NOT_BE_FOUND);
+ for ( ; ctl->next != NULL && ctl->next->reg == region; prev_ctl = ctl, ctl = ctl->next)
+ ;
+ }
+ assert(!*brkn_trans);
+ return (cumul_read);
+}
+
+int gtmsource_readfiles(unsigned char *buff, int *data_len, int maxbufflen, boolean_t read_multiple)
+{
+
+ int4 read_size, read_state, first_tr_len, tot_tr_len;
+ unsigned char seq_num_str[32], *seq_num_ptr; /* INT8_PRINT */
+ jnlpool_ctl_ptr_t jctl;
+ gtmsource_local_ptr_t gtmsource_local;
+ seq_num read_jnl_seqno, jnl_seqno;
+ qw_num read_addr;
+ uint4 jnlpool_size;
+ static int4 max_tr_size = MAX_TR_BUFFSIZE; /* Will generally be less than initial gtmsource_msgbufsiz;
+ * allows for space to accommodate the last transaction */
+
+ jctl = jnlpool.jnlpool_ctl;
+ gtmsource_local = jnlpool.gtmsource_local;
+ jnlpool_size = jctl->jnlpool_size;
+ jnl_seqno = jctl->jnl_seqno;
+ read_jnl_seqno = gtmsource_local->read_jnl_seqno;
+ read_state = gtmsource_local->read_state;
+ assert(buff == (unsigned char *)gtmsource_msgp + REPL_MSG_HDRLEN); /* else increasing buffer space will not work */
+ assert(maxbufflen == gtmsource_msgbufsiz - REPL_MSG_HDRLEN);
+ tot_tr_len = 0;
+ assert(REPL_MSG_HDRLEN == SIZEOF(jnldata_hdr_struct));
+ read_addr = gtmsource_local->read_addr;
+ first_tr_len = read_size = read_and_merge(buff, maxbufflen, read_jnl_seqno++) + REPL_MSG_HDRLEN;
+ max_tr_size = MAX(max_tr_size, read_size);
+ do
+ {
+ tot_tr_len += read_size;
+ REPL_DPRINT5("File read seqno : %llu Tr len : %d Total tr len : %d Maxbufflen : %d\n", read_jnl_seqno - 1,
+ read_size - REPL_MSG_HDRLEN, tot_tr_len, maxbufflen);
+ if (gtmsource_save_read_jnl_seqno < read_jnl_seqno)
+ {
+ read_addr += read_size;
+ if (jnlpool_size >= (jctl->early_write_addr - read_addr)) /* No more overflow, switch to READ_POOL */
+ { /* To avoid the expense of memory barrier in jnlpool_hasnt_overflowed(), we use a possibly stale
+ * value of early_write_addr to check if we can switch back to pool. The consequence
+ * is that we may switch back and forth between file and pool read if we are in a situation wherein a
+ * GTM process races with source server, writing transactions into the pool right when the source server
+ * concludes that it can read from pool. We think this condition is rare enough that the expense
+ * of re-opening the files (due to the transition) and re-positioning read pointers is considered
+ * living with when compared with the cost of a memory barrier. We can reduce the expense by
+ * not clearing the file information for every transition back to pool. We can wait for a certain
+ * period of time (say 15 minutes) before we close all files. */
+ gtmsource_local->read = read_addr % jnlpool_size;
+ gtmsource_local->read_state = read_state = READ_POOL;
+ break;
+ }
+ REPL_DPRINT3("Readfiles : after sync with pool read_seqno: %llu read_addr: %llu\n", read_jnl_seqno,
+ read_addr);
+ }
+ if (read_multiple)
+ {
+ if (tot_tr_len < max_tr_size && read_jnl_seqno < jnl_seqno)
+ { /* Limit the read by the buffer length, or until there is no more to be read. If not limited by the
+ * buffer length, the buffer will keep growing due to logic that expands the buffer when needed */
+ /* recompute buff and maxbufflen as buffer may have expanded during read_and_merge */
+ buff = (unsigned char *)gtmsource_msgp + tot_tr_len + REPL_MSG_HDRLEN;
+ maxbufflen = gtmsource_msgbufsiz - tot_tr_len - REPL_MSG_HDRLEN;
+ read_size = read_and_merge(buff, maxbufflen, read_jnl_seqno++) + REPL_MSG_HDRLEN;
+ max_tr_size = MAX(max_tr_size, read_size);
+ /* don't use buff to assign type and len as buffer may have expanded, use gtmsource_msgp instead */
+ ((repl_msg_ptr_t)((unsigned char *)gtmsource_msgp + tot_tr_len))->type = REPL_TR_JNL_RECS;
+ ((repl_msg_ptr_t)((unsigned char *)gtmsource_msgp + tot_tr_len))->len = read_size;
+ continue;
+ }
+ REPL_DPRINT6("Readfiles : tot_tr_len %d max_tr_size %d read_jnl_seqno %llu jnl_seqno %llu "
+ "gtmsource_msgbufsize : %d; stop multiple reads\n", tot_tr_len, max_tr_size, read_jnl_seqno,
+ jnl_seqno, gtmsource_msgbufsiz);
+ }
+ break;
+ } while (TRUE);
+ gtmsource_local->read_addr = read_addr;
+ gtmsource_local->read_jnl_seqno = read_jnl_seqno;
+#ifdef GTMSOURCE_ALWAYS_READ_FILES
+ gtmsource_local->read_state = read_state = READ_FILE;
+#endif
+ if (read_state == READ_POOL)
+ {
+ gtmsource_ctl_close(); /* no need to keep files open now that we are going to read from pool */
+ repl_log(gtmsource_log_fp, TRUE, TRUE, "Source server now reading from journal pool at transaction %llu\n",
+ read_jnl_seqno);
+ REPL_DPRINT3("Readfiles : after switch to pool, read_addr : "INT8_FMT" read : %u\n",
+ INT8_PRINT(read_addr), gtmsource_local->read);
+ }
+ *data_len = (first_tr_len - REPL_MSG_HDRLEN);
+ return (tot_tr_len);
+}
+
+static int scavenge_closed_jnl_files(seq_num ack_seqno) /* currently not used */
+{ /* Run thru the repl_ctl_list and scavenge for those journal files which are no longer required for
+ * replication (the receiver side has acknowledged that it has successfully processed journal recs upto
+ * and including those with JNL_SEQNO ack_seqno). Close these journal files and report to the operator
+ * that these files are no longer needed for replication so that the operator can take these files off-line.
+ */
+ boolean_t scavenge;
+ repl_ctl_element *ctl, *prev_ctl;
+
+ for (prev_ctl = repl_ctl_list, ctl = repl_ctl_list->next; ctl != NULL; prev_ctl = ctl, ctl = ctl->next)
+ {
+ if (!ctl->next || ctl->next->reg != ctl->reg)
+ open_newer_gener_jnlfiles(ctl->reg, ctl);
+ /* following two switche blocks cannot be merged as file_state could change in the first switch block */
+ switch(ctl->file_state)
+ {
+ case JNL_FILE_CLOSED :
+ case JNL_FILE_EMPTY :
+ break;
+ case JNL_FILE_OPEN :
+ if (update_max_seqno_info(ctl) != SS_NORMAL)
+ {
+ assert(repl_errno == EREPL_JNLEARLYEOF);
+ GTMASSERT; /* Program bug */
+ }
+ break;
+ case JNL_FILE_UNREAD :
+ first_read(ctl);
+ break;
+ }
+ switch(ctl->file_state)
+ {
+ case JNL_FILE_CLOSED :
+ scavenge = (QWGE(ack_seqno, ctl->max_seqno) && ctl->next && ctl->next->reg == ctl->reg);
+ /* There should exist a next generation */
+ break;
+ case JNL_FILE_EMPTY :
+ /* Previous generation should have been scavenged and the
+ * ack_seqno should be in one of the next generations.
+ */
+ scavenge = (ctl->prev->reg != ctl->reg && ctl->next && ctl->next->reg == ctl->reg
+ && (ctl->next->file_state == JNL_FILE_OPEN
+ || ctl->next->file_state == JNL_FILE_CLOSED)
+ && QWGE(ctl->next->min_seqno, ack_seqno));
+ break;
+ default :
+ scavenge = FALSE;
+ break;
+ }
+ if (scavenge)
+ {
+ ctl->prev->next = ctl->next;
+ ctl->next->prev = ctl->prev;
+ REPL_DPRINT2("Journal file %s no longer needed for replication\n", ctl->jnl_fn);
+ repl_ctl_close(ctl);
+ }
+ }
+ return 0;
+}
+
+int gtmsource_update_resync_tn(seq_num resync_seqno)
+{
+ repl_ctl_element *ctl, *prev_ctl;
+ gd_region *region;
+ sgmnt_addrs *csa;
+ int read_size;
+ unsigned char seq_num_str[32], *seq_num_ptr; /* INT8_PRINT */
+
+ REPL_DPRINT2("UPDATING RESYNC TN with seqno "INT8_FMT"\n", INT8_PRINT(resync_seqno));
+ gtmsource_ctl_close();
+ gtmsource_ctl_init();
+ read_size = read_and_merge((unsigned char *)>msource_msgp->msg[0], gtmsource_msgbufsiz - REPL_MSG_HDRLEN, resync_seqno);
+ for (ctl = repl_ctl_list->next, prev_ctl = repl_ctl_list; ctl != NULL; )
+ {
+ for (region = ctl->reg;
+ ctl != NULL && ctl->reg == region && (ctl->file_state == JNL_FILE_OPEN || ctl->file_state == JNL_FILE_CLOSED);
+ prev_ctl = ctl, ctl = ctl->next)
+ ;
+ if (ctl == NULL || ctl->reg != region || prev_ctl->reg == region)
+ {
+ csa = &FILE_INFO(region)->s_addrs;
+ csa->hdr->resync_tn = prev_ctl->tn;
+ REPL_DPRINT3("RESYNC TN for %s is %d\n", prev_ctl->jnl_fn, prev_ctl->tn);
+ } else
+ { /* The only ctl entry for this region is empty or unread */
+ assert(FILE_INFO(region)->s_addrs.hdr->resync_tn == 1);
+ }
+ /* Move to the next region */
+ for (; ctl != NULL && ctl->reg == region;
+ prev_ctl = ctl, ctl = ctl->next);
+ }
+ gtmsource_ctl_close(); /* close all structures now that we are done; if we have to read from journal files; we'll open
+ * the structures again */
+ return (SS_NORMAL);
+}
diff --git a/sr_vvms/gtmsource_readpool.c b/sr_vvms/gtmsource_readpool.c
new file mode 100644
index 0000000..73acb0b
--- /dev/null
+++ b/sr_vvms/gtmsource_readpool.c
@@ -0,0 +1,201 @@
+/****************************************************************
+ * *
+ * Copyright 2006, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include "gtm_socket.h"
+#include "gtm_inet.h"
+#include <sys/time.h>
+#include <errno.h>
+#include "gtm_fcntl.h"
+#include "gtm_unistd.h"
+#include "gtm_stat.h"
+#ifdef VMS
+#include <descrip.h> /* Required for gtmsource.h */
+#endif
+
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "repl_msg.h"
+#include "gtmsource.h"
+#include "jnl.h"
+#include "buddy_list.h"
+#include "hashtab_mname.h" /* needed for muprec.h */
+#include "hashtab_int4.h" /* needed for muprec.h */
+#include "hashtab_int8.h" /* needed for muprec.h */
+#include "muprec.h"
+#include "repl_ctl.h"
+#include "repl_errno.h"
+#include "repl_dbg.h"
+#include "memcoherency.h"
+#include "repl_tr_good.h"
+#include "min_max.h"
+
+GBLREF jnlpool_addrs jnlpool;
+
+int gtmsource_readpool(uchar_ptr_t buff, int *data_len, int maxbufflen, boolean_t read_multiple, qw_num stop_read_at)
+{
+
+ uint4 jnldata_len, read_size, read, jnlpool_size, avail_data;
+ uint4 first_tr_len, num_tr_read, tr_len;
+ int4 wrap_size;
+ unsigned char seq_num_str[32], *seq_num_ptr;
+ uchar_ptr_t buf_top, tr_p;
+ jnlpool_ctl_ptr_t jctl;
+ gtmsource_local_ptr_t gtmsource_local;
+ sm_uc_ptr_t jnldata_base;
+ jnldata_hdr_ptr_t jnl_header;
+ qw_num read_addr, avail_data_qw;
+ repl_msg_ptr_t msgp;
+ seq_num read_jnl_seqno, jnl_seqno;
+
+ jctl = jnlpool.jnlpool_ctl;
+ jnlpool_size = jctl->jnlpool_size;
+ DEBUG_ONLY(jnl_seqno = jctl->jnl_seqno;) /* jnl_seqno is used in an assert below. jnl_seqno is a local variable for
+ * debugging purposes since shared memory can change from the time the assert
+ * fails to the time the core gets created
+ */
+ jnldata_base = jnlpool.jnldata_base;
+ gtmsource_local = jnlpool.gtmsource_local;
+ read = gtmsource_local->read;
+ read_addr = gtmsource_local->read_addr;
+ read_jnl_seqno = gtmsource_local->read_jnl_seqno;
+ assert(stop_read_at > read_addr); /* there should be data to be read, if not how did we end up here? */
+ if (jnlpool_hasnt_overflowed(jctl, jnlpool_size, read_addr))
+ { /* No overflow yet. Before we read the content (including the jnldata_len read below), we have to ensure we read
+ * up-to-date content. We rely on the memory barrier done in jnlpool_hasnt_overflowed for this. */
+ assert(read + SIZEOF(jnldata_hdr_struct) <= jnlpool_size);
+ jnl_header = (jnldata_hdr_ptr_t)(jnldata_base + read);
+ first_tr_len = jnldata_len = jnl_header->jnldata_len;
+ if (read_multiple)
+ {
+ assert(stop_read_at >= read_addr);
+ avail_data_qw = stop_read_at - read_addr;
+ assert(maxbufflen <= MAXPOSINT4); /* to catch the case of change in type of maxbufflen */
+ avail_data = (uint4)MIN(avail_data_qw, (qw_num)maxbufflen);
+ read_multiple = (first_tr_len < avail_data);
+ if (read_multiple)
+ jnldata_len = avail_data;
+ }
+ if (SIZEOF(jnldata_hdr_struct) < jnldata_len && jnldata_len <= jnlpool_size)
+ {
+ read_size = jnldata_len - SIZEOF(jnldata_hdr_struct);
+ if (0 < read_size && read_size <= maxbufflen)
+ {
+ if (0 < (wrap_size = (int4)(read - (jnlpool_size - jnldata_len))))
+ read_size -= wrap_size;
+ memcpy(buff, (sm_uc_ptr_t)jnl_header + SIZEOF(jnldata_hdr_struct), read_size);
+ if (0 < wrap_size)
+ memcpy(buff + read_size, jnldata_base, wrap_size);
+ /* Now that we have read the content, we have to ensure that we haven't read content that may been
+ * overwritten. We rely on the memory barrier done in jnlpool_hasnt_overflowed for this */
+ if (jnlpool_hasnt_overflowed(jctl, jnlpool_size, read_addr))
+ { /* No overflow */
+ REPL_DEBUG_ONLY(
+ assert(repl_tr_good(buff, first_tr_len - SIZEOF(jnldata_hdr_struct),
+ read_jnl_seqno));
+ )
+ num_tr_read = 1;
+ if (read_multiple)
+ { /* although stop_read_at - read_addr contains no partial transaction, it is possible that
+ * stop_read_at - read_addr is more than maxbufflen, and hence we read fewer bytes
+ * than stop_read_at - read_addr; scan what we read to figure out if the tail is an
+ * incomplete transaction */
+ assert(first_tr_len < jnldata_len); /* must hold if multiple transactions read */
+ tr_p = buff + first_tr_len - SIZEOF(jnldata_hdr_struct);
+ buf_top = buff + jnldata_len - SIZEOF(jnldata_hdr_struct);
+ while (SIZEOF(jnldata_hdr_struct) < (buf_top - tr_p)) /* more than hdr available */
+ {
+ tr_len = ((jnldata_hdr_ptr_t)tr_p)->jnldata_len;
+ assert(0 < tr_len);
+ assert(tr_len <= jnlpool_size);
+ if (tr_len <= (buf_top - tr_p)) /* transaction completely read */
+ { /* the message type and len assignments are a violation of layering;
+ * ideally, this should be done in gtmsource_process(), but we choose
+ * to do it here for performance reasons. If we have to do it in
+ * gtmsource_process(), we have to scan the buffer again. */
+ ((repl_msg_ptr_t)tr_p)->type = REPL_TR_JNL_RECS;
+ ((repl_msg_ptr_t)tr_p)->len = tr_len;
+ REPL_DEBUG_ONLY(
+ assert(repl_tr_good(tr_p + REPL_MSG_HDRLEN,
+ tr_len - REPL_MSG_HDRLEN,
+ read_jnl_seqno + num_tr_read));
+ )
+ num_tr_read++;
+ tr_p += tr_len;
+ } else
+ {
+ REPL_DPRINT5("Partial transaction read since jnldata_len %llu "
+ "larger than maxbufflen %d, tr_len %d, remaining "
+ "buffer %d\n", avail_data_qw, maxbufflen,
+ tr_len, buf_top - tr_p);
+ break;
+ }
+ }
+ REPL_DEBUG_ONLY(
+ if (0 != (buf_top - tr_p))
+ {
+ REPL_DPRINT4("Partial tr header read since jnldata_len %llu "
+ "larger than maxbufflen %d, incomplete header length %d\n",
+ avail_data_qw, maxbufflen, buf_top - tr_p);
+ } else ;
+ )
+ jnldata_len = (tr_p - buff) + SIZEOF(jnldata_hdr_struct);
+ wrap_size = (int4)(read - (jnlpool_size - jnldata_len));
+ }
+ REPL_DPRINT4("Pool read seqno : "INT8_FMT" Num Tr read : %d Total Tr len : %d\n",
+ INT8_PRINT(read_jnl_seqno), num_tr_read, jnldata_len);
+ REPL_DPRINT4("Read %u : Next read : %u : %s\n", read,
+ (0 > wrap_size) ? read + jnldata_len : wrap_size,
+ (0 > wrap_size) ? "" : " READ WRAPPED");
+ read = ((0 > wrap_size) ? read + jnldata_len : wrap_size);
+ read_addr += jnldata_len;
+ read_jnl_seqno += num_tr_read;
+ assert(stop_read_at >= read_addr);
+ assert(jnl_seqno >= read_jnl_seqno - 1);
+ /* In the rare case when we read the transaction read_jnl_seqno just as it becomes
+ * available and before the GTM process that wrote it updates jctl->jnl_seqno
+ * in t_end/tp_tend, we may return from this function with read_jnl_seqno one more than
+ * jctl->jnl_seqno. This is such a rare case that we don't want to add a wait loop for
+ * jctl->jnl_seqno to become equal to read_jnl_seqno. We expect that by the time we send
+ * the just read transaction(s) using socket I/O, jctl->jnl_seqno would have been updated.
+ * In any case, we prevent ourselves from misinterpreting this condition when
+ * read_jnl_seqno is compared against jctl->jnl_seqno in gtmsource_process(),
+ * gtmsource_get_jnlrecs() and gtmsource_showbacklog()
+ */
+ assert(read == read_addr % jnlpool_size);
+ gtmsource_local->read = read;
+ gtmsource_local->read_addr = read_addr;
+ gtmsource_local->read_jnl_seqno = read_jnl_seqno;
+ *data_len = first_tr_len - SIZEOF(jnldata_hdr_struct);
+ return (jnldata_len);
+ } /* else overflow happened, or about to happen */
+ } else if (0 < read_size && jnlpool_hasnt_overflowed(jctl, jnlpool_size, read_addr))
+ { /* Buffer cannot accommodate data */
+ *data_len = read_size;
+ return (-1);
+ } /* else
+ * We read a corrupt (overwritten) large value, or read_size == 0, both of which imply overflow.
+ * read_size == 0 => overflow because every transaction generates non-zero bytes of jnl data */
+ } /* else
+ * We read a corrupt (overwritten) large value, or read 0, both of which imply overflow.
+ * jnldata_len == 0 => overflow because every transaction generates non-zero bytes of jnl data */
+ } /* else overflow happened, or about to happen */
+ *data_len = -1;
+ return (-1); /* Error indication */
+}
diff --git a/sr_vvms/gtmsource_secnd_update.c b/sr_vvms/gtmsource_secnd_update.c
new file mode 100644
index 0000000..c475127
--- /dev/null
+++ b/sr_vvms/gtmsource_secnd_update.c
@@ -0,0 +1,61 @@
+/****************************************************************
+ * *
+ * Copyright 2006, 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#if !defined(__MVS__) && !defined(VMS)
+#include <sys/param.h>
+#endif
+#include <sys/time.h>
+#include <errno.h>
+#include "gtm_string.h"
+#include "gtm_inet.h" /* Required for gtmsource.h */
+#ifdef UNIX
+#include <sys/sem.h>
+#endif
+#ifdef VMS
+#include <descrip.h> /* Required for gtmsource.h */
+#endif
+
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "repl_msg.h"
+#include "gtmsource.h"
+#include "repl_dbg.h"
+#include "error.h"
+#include "gtm_stdio.h"
+#include "repl_shutdcode.h"
+#include "repl_sem.h"
+#include "util.h"
+
+GBLREF jnlpool_addrs jnlpool;
+GBLREF boolean_t update_disable;
+
+int gtmsource_secnd_update(boolean_t print_message)
+{
+ if (grab_sem(SOURCE, SRC_SERV_OPTIONS_SEM) < 0)
+ {
+ util_out_print("Error grabbing jnlpool option write lock. Could not initiate change log", TRUE);
+ return(ABNORMAL_SHUTDOWN);
+ }
+ grab_lock(jnlpool.jnlpool_dummy_reg, TRUE, ASSERT_NO_ONLINE_ROLLBACK);
+ jnlpool.jnlpool_ctl->upd_disabled = update_disable;
+ rel_lock(jnlpool.jnlpool_dummy_reg);
+ rel_sem(SOURCE, SRC_SERV_OPTIONS_SEM);
+ if (print_message)
+ util_out_print("Updates are now !AZ", TRUE, update_disable ? "disabled" : "enabled");
+ return(NORMAL_SHUTDOWN);
+}
diff --git a/sr_vvms/gtmsource_seqno_init.c b/sr_vvms/gtmsource_seqno_init.c
new file mode 100644
index 0000000..0350db0
--- /dev/null
+++ b/sr_vvms/gtmsource_seqno_init.c
@@ -0,0 +1,82 @@
+/****************************************************************
+ * *
+ * Copyright 2006, 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+#include "gtm_inet.h"
+#include "gtm_fcntl.h"
+#include <descrip.h> /* Required for gtmsource.h */
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "error.h"
+#include "repl_msg.h"
+#include "gtmsource.h"
+#include "jnl.h"
+#include "gtmmsg.h"
+
+GBLREF gd_addr *gd_header;
+GBLREF gd_region *gv_cur_region;
+GBLREF gtmsource_options_t gtmsource_options;
+GBLREF jnlpool_addrs jnlpool;
+GBLREF seq_num seq_num_one, seq_num_zero;
+
+error_def(ERR_NOREPLCTDREG);
+
+void gtmsource_seqno_init(void)
+{
+ /* Find the start_jnl_seqno */
+
+ gd_region *reg, *region_top;
+ seq_num local_read_jsn, local_jsn;
+ sgmnt_addrs *csa;
+ sgmnt_data_ptr_t csd;
+ sm_uc_ptr_t gld_fn;
+
+ /* Unix and VMS have different field names for now, but will both be soon changed to instname instead of gtmgbldir */
+ gld_fn = (sm_uc_ptr_t)jnlpool.jnlpool_ctl->jnlpool_id.gtmgbldir;
+ QWASSIGN(jnlpool.jnlpool_ctl->start_jnl_seqno, seq_num_zero);
+ QWASSIGN(local_read_jsn, seq_num_zero);
+ QWASSIGN(local_jsn, seq_num_zero);
+ region_top = gd_header->regions + gd_header->n_regions;
+ for (reg = gd_header->regions; reg < region_top; reg++)
+ {
+ assert(reg->open);
+ csa = &FILE_INFO(reg)->s_addrs;
+ csd = csa->hdr;
+ if (REPL_ALLOWED(csd))
+ {
+ if (QWLT(local_read_jsn, csd->resync_seqno))
+ QWASSIGN(local_read_jsn, csd->resync_seqno);
+ if (QWLT(local_jsn, csd->reg_seqno))
+ QWASSIGN(local_jsn, csd->reg_seqno);
+ /* Copy gtmgbldir into the database shared memory.
+ * Used later to avoid updates from a different gtmgbldir to this database.
+ */
+ assert(SIZEOF(csa->nl->replinstfilename) == SIZEOF(jnlpool.jnlpool_ctl->jnlpool_id.gtmgbldir));
+ memcpy(csa->nl->replinstfilename, gld_fn, SIZEOF(csa->nl->replinstfilename));
+ }
+ }
+ if (QWEQ(local_jsn, seq_num_zero))
+ {
+ /* No replicated region, or databases created with older version of GTM */
+ gtm_putmsg(VARLSTCNT(5) ERR_NOREPLCTDREG, 3, LEN_AND_LIT("global directory"), gld_fn);
+ /* Error, has to shutdown all regions 'cos mupip needs exclusive access to turn replication on */
+ gtmsource_autoshutdown();
+ }
+ QWASSIGN(jnlpool.jnlpool_ctl->start_jnl_seqno, local_jsn);
+ QWASSIGN(jnlpool.jnlpool_ctl->jnl_seqno, local_jsn);
+ QWASSIGN(jnlpool.gtmsource_local->read_jnl_seqno, local_read_jsn);
+}
diff --git a/sr_vvms/gtmsource_showbacklog.c b/sr_vvms/gtmsource_showbacklog.c
new file mode 100644
index 0000000..44d4513
--- /dev/null
+++ b/sr_vvms/gtmsource_showbacklog.c
@@ -0,0 +1,65 @@
+/****************************************************************
+ * *
+ * Copyright 2006, 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#if !defined(__MVS__) && !defined(VMS)
+#include <sys/param.h>
+#endif
+#include <sys/time.h>
+#include "gtm_inet.h"
+#include <errno.h>
+#include "gtm_string.h"
+#ifdef VMS
+#include <descrip.h> /* Required for gtmsource.h */
+#endif
+
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "repl_msg.h"
+#include "gtmsource.h"
+#include "repl_dbg.h"
+#include "repl_shutdcode.h"
+#include "util.h"
+
+GBLREF jnlpool_addrs jnlpool;
+GBLREF gtmsource_options_t gtmsource_options;
+GBLREF seq_num seq_num_zero;
+GBLREF seq_num seq_num_one;
+
+int gtmsource_showbacklog(void)
+{
+ seq_num seq_num, jnl_seqno, read_jnl_seqno;
+
+ QWASSIGN(read_jnl_seqno, jnlpool.gtmsource_local->read_jnl_seqno);
+ QWASSIGN(jnl_seqno, jnlpool.jnlpool_ctl->jnl_seqno);
+ /* jnl_seqno >= read_jnl_seqno is the most common case; see gtmsource_readpool() for when the rare case can occur */
+ seq_num = (jnl_seqno >= read_jnl_seqno) ? jnl_seqno - read_jnl_seqno : 0;
+ util_out_print("!@UQ : backlog number of transactions written to journal pool and "
+ "yet to be sent by the source server", TRUE, &seq_num);
+ QWASSIGN(seq_num, jnl_seqno);
+ if (QWNE(seq_num, seq_num_zero))
+ QWDECRBY(seq_num, seq_num_one);
+ util_out_print("!@UQ : sequence number of last transaction written to journal pool", TRUE, &seq_num);
+ QWASSIGN(seq_num, read_jnl_seqno);
+ if (QWNE(seq_num, seq_num_zero))
+ QWDECRBY(seq_num, seq_num_one);
+ util_out_print("!@UQ : sequence number of last transaction sent by source server", TRUE, &seq_num);
+ if ((jnlpool.gtmsource_local->mode == GTMSOURCE_MODE_PASSIVE)
+ || ( jnlpool.gtmsource_local->mode == GTMSOURCE_MODE_ACTIVE_REQUESTED))
+ util_out_print("WARNING - Source Server is in passive mode, transactions are not being replicated", TRUE);
+ return (NORMAL_SHUTDOWN);
+}
diff --git a/sr_vvms/gtmsource_shutdown.c b/sr_vvms/gtmsource_shutdown.c
new file mode 100644
index 0000000..9c28972
--- /dev/null
+++ b/sr_vvms/gtmsource_shutdown.c
@@ -0,0 +1,185 @@
+/****************************************************************
+ * *
+ * Copyright 2006, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <sys/mman.h>
+#if !(defined(__MVS__)) && !(defined(VMS))
+#include <sys/param.h>
+#endif
+#include "gtm_socket.h"
+#include <sys/time.h>
+#include <errno.h>
+#include "gtm_fcntl.h"
+#include "gtm_unistd.h"
+#include "gtm_inet.h" /* Required for gtmsource.h */
+#include "gtm_string.h"
+#include <descrip.h> /* Required for gtmsource.h */
+
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "repl_msg.h"
+#include "gtmsource.h"
+#include "repl_dbg.h"
+#include "gt_timer.h"
+#include "gtm_stdio.h"
+#include "repl_shutdcode.h"
+#include "repl_sem.h"
+#include "is_proc_alive.h"
+#include "repl_comm.h"
+#include "repl_log.h"
+
+#define GTMSOURCE_WAIT_FOR_SHUTDOWN (1000 - 1) /* ms, almost 1 s */
+
+GBLREF jnlpool_addrs jnlpool;
+GBLREF jnlpool_ctl_ptr_t jnlpool_ctl;
+GBLREF uint4 process_id;
+GBLREF int gtmsource_srv_count;
+GBLREF gtmsource_options_t gtmsource_options;
+GBLREF int4 jnlpool_shmid;
+GBLREF boolean_t is_src_server;
+GBLREF void (*call_on_signal)();
+
+int gtmsource_shutdown(boolean_t auto_shutdown, int exit_status)
+{
+ uint4 savepid;
+ int status;
+
+ /*
+ * Significance of shutdown field in gtmsource_local:
+ * This field is initially set to NO_SHUTDOWN. When a command to shut
+ * down the source server is issued, the process initiating the
+ * shutdown sets this field to SHUTDOWN. The Source Server on sensing
+ * that it has to shut down (reads SHUTDOWN in the shutdown field),
+ * flushes the database regions, writes (NORMAL_SHUTDOWN + its exit
+ * value) into this field and exits. On seeing a non SHUTDOWN value
+ * in this field, the process which initiated the shutdown removes the
+ * ipcs and exits with the exit value which is a combination of
+ * gtmsource_local->shutdown and its own exit value.
+ *
+ * Note : Exit values should be positive for error indication,
+ * zero for normal exit.
+ */
+ repl_log(stdout, TRUE, TRUE, "Initiating shut down\n");
+ call_on_signal = NULL; /* Don't reenter on error */
+ /* Grab the jnlpool access control lock and jnlpool option write lock */
+ if (!auto_shutdown || gtmsource_srv_count)
+ {
+ status = grab_sem(SOURCE, JNL_POOL_ACCESS_SEM);
+ if (0 == status)
+ if (0 > (status = grab_sem(SOURCE, SRC_SERV_OPTIONS_SEM)))
+ rel_sem(SOURCE, JNL_POOL_ACCESS_SEM);
+ } else /* else if autoshutdown, parent is still holding the control lock, and the option lock,
+ * and the child is exiting at startup */
+ status = 0;
+
+ if (0 > status)
+ {
+ repl_log(stderr, TRUE, TRUE,
+ "Error grabbing jnlpool access control/jnlpool option write lock : %s. Shutdown not complete\n",
+ REPL_SEM_ERROR);
+ return (ABNORMAL_SHUTDOWN);
+ }
+
+ if (!auto_shutdown)
+ {
+ /* Wait till shutdown time nears */
+ if (0 < gtmsource_options.shutdown_time)
+ {
+ repl_log(stdout, FALSE, TRUE, "Waiting for %d seconds before signalling shutdown\n",
+ gtmsource_options.shutdown_time);
+ LONG_SLEEP(gtmsource_options.shutdown_time);
+ } else
+ repl_log(stdout, FALSE, TRUE, "Signalling shutdown immediate\n");
+
+ jnlpool.gtmsource_local->shutdown = SHUTDOWN;
+
+ /* Wait for source server(s) to die. But release jnlpool access control and src serv options semaphore before
+ * waiting as the concurrently running source server(s) might need these (e.g. if it is in the process of
+ * starting up and invoking the function "gtmsource_secnd_update").
+ */
+ if (0 != (status = rel_sem(SOURCE, SRC_SERV_OPTIONS_SEM)))
+ repl_log(stderr, TRUE, TRUE, "Error releasing the Source Server Options semaphore : %s\n", REPL_SEM_ERROR);
+ if (0 != (status = rel_sem(SOURCE, JNL_POOL_ACCESS_SEM)))
+ repl_log(stderr, TRUE, TRUE, "Error releasing the Journal Pool Access semaphore : %s\n", REPL_SEM_ERROR);
+
+ while ((SHUTDOWN == jnlpool.gtmsource_local->shutdown)
+ && (0 < (savepid = jnlpool.gtmsource_local->gtmsource_pid))
+ && is_proc_alive(savepid, 0))
+ SHORT_SLEEP(GTMSOURCE_WAIT_FOR_SHUTDOWN);
+
+ if (0 != (status = grab_sem(SOURCE, JNL_POOL_ACCESS_SEM)))
+ {
+ repl_log(stderr, TRUE, TRUE, "Error re-grabbing the Journal Pool Access semaphore : %s\n", REPL_SEM_ERROR);
+ return (ABNORMAL_SHUTDOWN);
+ }
+ if (0 != (status = grab_sem(SOURCE, SRC_SERV_OPTIONS_SEM)))
+ {
+ rel_sem(SOURCE, JNL_POOL_ACCESS_SEM);
+ repl_log(stderr, TRUE, TRUE, "Error re-grabbing the Source Server Options semaphore : %s\n",
+ REPL_SEM_ERROR);
+ return (ABNORMAL_SHUTDOWN);
+ }
+ exit_status = jnlpool.gtmsource_local->shutdown;
+ if (SHUTDOWN == exit_status)
+ {
+ if (0 == savepid) /* No source server */
+ exit_status = NORMAL_SHUTDOWN;
+ else /* Source Server crashed */
+ {
+ repl_log(stderr, FALSE, TRUE,"Source Server exited abnormally. MUPIP RUNDOWN might be warranted\n");
+ exit_status = ABNORMAL_SHUTDOWN;
+ }
+ }
+ }
+
+ /*
+ * gtmsource_ipc_cleanup will not be successful unless source server has completely exited.
+ * It relies on SRC_SERV_COUNT_SEM value.
+ */
+ if (FALSE == gtmsource_ipc_cleanup(auto_shutdown, &exit_status))
+ {
+ /* Release rundown, count, and option semaphores */
+ if (!auto_shutdown)
+ rel_sem_immediate(SOURCE, SRC_SERV_COUNT_SEM);
+ rel_sem_immediate(SOURCE, SRC_SERV_OPTIONS_SEM);
+ rel_sem_immediate(SOURCE, JNL_POOL_ACCESS_SEM);
+ }
+ return (exit_status);
+}
+
+static void gtmsource_stop(boolean_t exit)
+{
+ int status;
+
+ status = gtmsource_shutdown(TRUE, gtmsource_end1(TRUE)) - NORMAL_SHUTDOWN;
+ if (exit)
+ gtmsource_exit(status);
+ return;
+}
+
+void gtmsource_sigstop(void)
+{
+ if (is_src_server)
+ gtmsource_stop(FALSE);
+ return;
+}
+
+void gtmsource_autoshutdown(void)
+{
+ gtmsource_stop(TRUE);
+ return;
+}
diff --git a/sr_vvms/gtmsource_statslog.c b/sr_vvms/gtmsource_statslog.c
new file mode 100644
index 0000000..837271b
--- /dev/null
+++ b/sr_vvms/gtmsource_statslog.c
@@ -0,0 +1,83 @@
+/****************************************************************
+ * *
+ * Copyright 2006, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#if !defined(__MVS__) && !defined(VMS)
+#include <sys/param.h>
+#endif
+#include <sys/time.h>
+#include <errno.h>
+#include "gtm_string.h"
+#include "gtm_inet.h" /* Required for gtmsource.h */
+#ifdef UNIX
+#include <sys/sem.h>
+#endif
+#ifdef VMS
+#include <descrip.h> /* Required for gtmsource.h */
+#endif
+
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "repl_msg.h"
+#include "gtmsource.h"
+#include "repl_dbg.h"
+#include "repl_shutdcode.h"
+#include "repl_sem.h"
+#include "util.h"
+
+GBLREF jnlpool_addrs jnlpool;
+GBLREF gtmsource_options_t gtmsource_options;
+
+#ifdef VMS
+error_def(ERR_UNIMPLOP);
+error_def(ERR_TEXT);
+#endif
+
+int gtmsource_statslog(void)
+{
+#ifdef VMS
+ rts_error(VARLSTCNT(6) ERR_UNIMPLOP, 0, ERR_TEXT, 2, LEN_AND_LIT("Statistics logging not supported on VMS"));
+#endif
+ /* Grab the jnlpool jnlpool option write lock */
+ if (0 > grab_sem(SOURCE, SRC_SERV_OPTIONS_SEM))
+ {
+ util_out_print("Error grabbing jnlpool option write lock. Could not initiate stats log", TRUE);
+ return (ABNORMAL_SHUTDOWN);
+ }
+
+ if (gtmsource_options.statslog == jnlpool.gtmsource_local->statslog)
+ {
+ util_out_print("STATSLOG is already !AD. Not initiating change in stats log", TRUE, gtmsource_options.statslog ?
+ strlen("ON") : strlen("OFF"), gtmsource_options.statslog ? "ON" : "OFF");
+ rel_sem_immediate(SOURCE, SRC_SERV_OPTIONS_SEM);
+ return (ABNORMAL_SHUTDOWN);
+ }
+
+ if (!gtmsource_options.statslog)
+ {
+ jnlpool.gtmsource_local->statslog = FALSE;
+ jnlpool.gtmsource_local->statslog_file[0] = '\0';
+ util_out_print("STATSLOG turned OFF", TRUE);
+ rel_sem_immediate(SOURCE, SRC_SERV_OPTIONS_SEM);
+ return (NORMAL_SHUTDOWN);
+ }
+
+ jnlpool.gtmsource_local->statslog = TRUE;
+ util_out_print("Stats log turned on", TRUE);
+ rel_sem_immediate(SOURCE, SRC_SERV_OPTIONS_SEM);
+ return (NORMAL_SHUTDOWN);
+}
diff --git a/sr_vvms/gtmsource_stopfilter.c b/sr_vvms/gtmsource_stopfilter.c
new file mode 100644
index 0000000..e22ff50
--- /dev/null
+++ b/sr_vvms/gtmsource_stopfilter.c
@@ -0,0 +1,68 @@
+/****************************************************************
+ * *
+ * Copyright 2006 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#if !defined(__MVS__) && !defined(VMS)
+#include <sys/param.h>
+#endif
+#include <sys/time.h>
+#include <errno.h>
+#include "gtm_string.h"
+#include "gtm_inet.h" /* Required for gtmsource.h */
+#ifdef UNIX
+#include <sys/sem.h>
+#endif
+#ifdef VMS
+#include <descrip.h> /* Required for gtmsource.h */
+#endif
+
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "repl_msg.h"
+#include "gtmsource.h"
+#include "repl_dbg.h"
+#include "repl_shutdcode.h"
+#include "repl_sem.h"
+#include "util.h"
+
+GBLREF jnlpool_addrs jnlpool;
+GBLREF gtmsource_options_t gtmsource_options;
+
+int gtmsource_stopfilter(void)
+{
+ /* Grab the jnlpool jnlpool option write lock */
+ if (0 > grab_sem(SOURCE, SRC_SERV_OPTIONS_SEM))
+ {
+ util_out_print("Error grabbing jnlpool option write lock. Could not stop filter", TRUE);
+ return (ABNORMAL_SHUTDOWN);
+ }
+
+ if ('\0' == jnlpool.gtmsource_local->filter_cmd[0])
+ {
+ util_out_print("No filter currently active", TRUE);
+ rel_sem_immediate(SOURCE, SRC_SERV_OPTIONS_SEM);
+ return (ABNORMAL_SHUTDOWN);
+ }
+
+ jnlpool.gtmsource_local->filter_cmd[0] = '\0';
+
+ util_out_print("Stop filter initiated", TRUE);
+
+ rel_sem_immediate(SOURCE, SRC_SERV_OPTIONS_SEM);
+
+ return (NORMAL_SHUTDOWN);
+}
diff --git a/sr_vvms/gtmstop.m b/sr_vvms/gtmstop.m
new file mode 100644
index 0000000..3d8d6dd
--- /dev/null
+++ b/sr_vvms/gtmstop.m
@@ -0,0 +1,47 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ;
+; Copyright 1989, 2002 Sanchez Computer Associates, Inc. ;
+; ;
+; This source code contains the intellectual property ;
+; of its copyright holder(s), and is made available ;
+; under a license. If you do not know the terms of ;
+; the license, please stop and do not read further. ;
+; ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+GTMSTOP ;GT.M STOP utility - stop all GT.M processes
+ ;
+ d ^%ST
+ n i,op,nopriv,pid,$zt
+ s $zt="zg "_$zl_":ERR^GTMSTOP" u $p:ctrap=$c(3) w !!
+ s op=$zsetprv("SYSLCK,GROUP,WORLD"),nopriv=0
+ i '$zpriv("SYSLCK") w !,"You need SYSLCK privilege to run this program.",!
+ e f i=1:1:10 d getpid(.pid) q:'pid d
+ . i i<10 d stopem(.pid) h 2 q
+ . d killem(.pid)
+ i nopriv w !,"Insufficient privileges to stop ",nopriv," process",$s(nopriv>1:"es.",1:"."),!
+ s op=$zsetprv(op) u $p:ctrap=""
+ q
+getpid(t);
+ n l,p k t s t=0
+ s l=$zlkid(0)
+ i l d f s l=$zlkid(1) q:'l d
+ . i $extract($zgetlki(l,"RESNAM"),1,6)="GTM$LM" s p=$zgetlki(l,"PID"),t(p)=$$FUNC^%DH(p,8),t=t+1
+ s p=$zgetjpi(0,"pid")
+ i $d(t(p)) s t=t-1 k t(p)
+ q
+stopem(t);
+ n p s p=""
+ f s p=$o(t(p)) q:p="" d msg($&FORCEX(p),t(p),"Stopping process ")
+ q
+killem(t);
+ n p s p=""
+ f s p=$o(t(p)) q:p="" d msg($&DELPRC(p),t(p),"Deleting process ")
+ q
+msg(stat,prc,defmsg)
+ i stat=1 w defmsg,prc,! q
+ s stat=$zm(stat)
+ i stat["NOPRIV" s:'$d(nopriv(prc)) nopriv(prc)=1,nopriv=nopriv+1 q
+ i $l(stat) w "Error for ",prc," : ",stat,!
+ q
+ERR w !,$p($zs,",",2,99),! u $p:ctrap="" s:$d(op) op=$ZSETPRV(op)
+ q
diff --git a/sr_vvms/gvcmy_open.h b/sr_vvms/gvcmy_open.h
new file mode 100644
index 0000000..d68570b
--- /dev/null
+++ b/sr_vvms/gvcmy_open.h
@@ -0,0 +1,17 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef __GVCMY_OPEN_H__
+#define __GVCMY_OPEN_H__
+
+void gvcmy_open(gd_region *reg, struct NAM *nb);
+
+#endif
diff --git a/sr_vvms/gvcst_init_sysops.c b/sr_vvms/gvcst_init_sysops.c
new file mode 100644
index 0000000..80d2ce8
--- /dev/null
+++ b/sr_vvms/gvcst_init_sysops.c
@@ -0,0 +1,902 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <descrip.h>
+#include <dvidef.h>
+#include <fab.h>
+#include <iodef.h>
+#include <lckdef.h>
+#include <lkidef.h>
+#include <nam.h>
+#include <psldef.h>
+#include <prvdef.h>
+#include <rmsdef.h>
+#include <secdef.h>
+#include <ssdef.h>
+#include <syidef.h>
+#include <xabfhcdef.h>
+#include <efndef.h>
+#include "gtm_string.h"
+#include "gtm_stdio.h"
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "gdsblk.h"
+#include "gdscc.h"
+#include "gdsblkops.h"
+#include "filestruct.h"
+#include "ccp.h"
+#include "cryptdef.h"
+#include "del_sec.h"
+#include "efn.h"
+#include "io.h"
+#include "error.h"
+#include "iottdef.h"
+#include "jnl.h"
+#include "locks.h"
+#include "min_max.h"
+#include "mlkdef.h"
+#include "vmsdtype.h"
+#include "gt_timer.h"
+#include "util.h"
+#include "mlk_shr_init.h"
+#include "dbfilop.h"
+#include "gvcst_protos.h" /* for gvcst_init_sysops prototype */
+#include "mem_list.h"
+#include "gv_match.h"
+#include "init_sec.h"
+#include "gvcmy_open.h"
+#include "semwt2long_handler.h"
+#include "gtmmsg.h"
+#include "shmpool.h"
+#include "send_msg.h"
+#include "gtmimagename.h"
+#include "have_crit.h"
+
+#define DEF_NODE 0xFFFF
+#define MAX_SEM_WT (1000 * 30) /* 30 second wait before DSE errors out for access control lock */
+#define PRT$C_NA 0
+
+typedef struct {
+ item_list_3 ilist;
+ int4 terminator;
+} syistruct;
+
+OS_PAGE_SIZE_DECLARE
+
+GBLREF boolean_t dse_running;
+GBLREF gd_region *gv_cur_region;
+GBLREF short crash_count;
+GBLREF boolean_t gtm_fullblockwrites; /* Do full (not partial) database block writes T/F */
+GBLREF uint4 process_id;
+
+LITREF char gtm_release_name[];
+LITREF int4 gtm_release_name_len;
+
+/* The following set of macros works around the fact that older VMS compilers do not support
+ * macros with variable number of parameters (a.k.a. variadic macros) that we use to
+ * implement the UNIX counterpart of PRINT_CRASH_MESSAGE in gvcst_ini_sysops.c.
+ */
+#define PRINT_CRASH_MESSAGE_2_ARGS(ARG1, ARG2) \
+ PRINT_CRASH_MESSAGE(2, ARG1, ARG2, NULL, NULL, NULL, NULL, NULL, NULL)
+
+#define PRINT_CRASH_MESSAGE_6_ARGS(ARG1, ARG2, ARG3, ARG4, ARG5, ARG6) \
+ PRINT_CRASH_MESSAGE(6, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, NULL, NULL)
+
+#define PRINT_CRASH_MESSAGE_8_ARGS(ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8) \
+ PRINT_CRASH_MESSAGE(8, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8)
+
+#define VARIADIC_RTS_ERROR(CNT, ERROR, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8) \
+{ \
+ if (2 == CNT) \
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(6) ERROR, 4, DB_LEN_STR(reg), \
+ ARG1, ARG2); \
+ else if (6 == CNT) \
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(10) ERROR, 4, DB_LEN_STR(reg), \
+ ARG1, ARG2, ARG3, ARG4, ARG5, ARG6); \
+ else if (8 == CNT) \
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(12) ERROR, 4, DB_LEN_STR(reg), \
+ ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8); \
+}
+
+/* Depending on whether journaling and/or replication was enabled at the time of the crash,
+ * print REQRUNDOWN, REQRECOV, or REQROLLBACK error message.
+ */
+#define PRINT_CRASH_MESSAGE(CNT, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8) \
+{ \
+ if (JNL_ENABLED(tsd)) \
+ { \
+ if (REPL_ENABLED(tsd) && tsd->jnl_before_image) \
+ { \
+ VARIADIC_RTS_ERROR(CNT, ERR_REQROLLBACK, \
+ ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8); \
+ } else \
+ { \
+ VARIADIC_RTS_ERROR(CNT, ERR_REQRECOV, \
+ ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8); \
+ } \
+ } else \
+ { \
+ VARIADIC_RTS_ERROR(CNT, ERR_REQRUNDOWN, \
+ ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7, ARG8); \
+ } \
+}
+
+error_def(ERR_BADGBLSECVER);
+error_def(ERR_CLSTCONFLICT);
+error_def(ERR_CRITSEMFAIL);
+error_def(ERR_DBFILERR);
+error_def(ERR_DBOPNERR);
+error_def(ERR_FILEIDGBLSEC);
+error_def(ERR_GBLSECNOTGDS);
+error_def(ERR_JNLBUFFREGUPD);
+error_def(ERR_MUPRECFLLCK);
+error_def(ERR_NETDBOPNERR);
+error_def(ERR_NLMISMATCHCALC);
+error_def(ERR_REQRECOV);
+error_def(ERR_REQROLLBACK);
+error_def(ERR_REQRUNDOWN);
+error_def(ERR_SEMWT2LONG);
+error_def(ERR_SYSCALL);
+error_def(ERR_TEXT);
+error_def(ERR_VERMISMATCH);
+
+gd_region *dbfilopn(gd_region *reg)
+{
+ gd_region *prev_reg, *sav_reg;
+ gd_segment *seg;
+ file_control *fc;
+ uint4 status, sub_status;
+ vms_gds_info *gds_info;
+
+ sav_reg = gv_cur_region;
+ gv_cur_region = reg;
+ seg = reg->dyn.addr;
+ assert((dba_bg == seg->acc_meth) || (dba_mm == seg->acc_meth));
+ FILE_CNTL_INIT_IF_NULL(seg);
+ gds_info = seg->file_cntl->file_info;
+ fc = seg->file_cntl;
+ fc->file_type = seg->acc_meth;
+ fc->op = FC_OPEN;
+ if (ERR_NETDBOPNERR == (status = dbfilop(fc)))
+ {
+ gv_cur_region = sav_reg;
+ gvcmy_open(reg, gds_info->nam);
+ return -1;
+ }
+ if (SS$_NORMAL != status)
+ {
+ sub_status = gds_info->fab->fab$l_stv;
+ free(gds_info->fab);
+ free(gds_info->nam->nam$l_esa);
+ free(gds_info->nam);
+ free(gds_info->xabfhc);
+ free(gds_info->xabpro);
+ free(seg->file_cntl->file_info);
+ free(seg->file_cntl);
+ seg->file_cntl = NULL;
+ gv_cur_region = sav_reg;
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_DBOPNERR, 2, DB_LEN_STR(reg), status, sub_status);
+ GTMASSERT;
+ }
+ if (NULL != (prev_reg = gv_match(reg)))
+ {
+ sys$dassgn(gds_info->fab->fab$l_stv);
+ free(gds_info->fab);
+ free(gds_info->nam->nam$l_esa);
+ free(gds_info->nam);
+ free(gds_info->xabfhc);
+ free(gds_info->xabpro);
+ free(seg->file_cntl->file_info);
+ free(seg->file_cntl);
+ seg->file_cntl = NULL;
+ reg = prev_reg;
+ }
+ gv_cur_region = sav_reg;
+ return reg;
+}
+
+void dbsecspc(gd_region *reg, sgmnt_data *sd, gtm_uint64_t *sec_size)
+{
+ int section_size;
+ int4 inadr[2], inadr1[2];
+ uint4 status;
+ vms_gds_info *gds_info;
+
+ gds_info = FILE_INFO(reg);
+ switch (reg->dyn.addr->acc_meth)
+ {
+ case dba_mm:
+ *sec_size = gds_info->xabfhc->xab$l_ebk;
+ break;
+
+ case dba_bg:
+ *sec_size = DIVIDE_ROUND_UP((LOCK_BLOCK_SIZE(sd) * OS_PAGE_SIZE) + LOCK_SPACE_SIZE(sd) + CACHE_CONTROL_SIZE(sd)
+ + NODE_LOCAL_SPACE(sd) + JNL_SHARE_SIZE(sd) + SHMPOOL_BUFFER_SIZE, OS_PAGELET_SIZE);
+ break;
+ default:
+ GTMASSERT;
+ }
+ /* sys$expreg's first argument is expressed in pages on VAX VMS (512 bytes each), but in "pagelets" on
+ Alpha VMS (also 512 bytes each). Since the region will be expanded by an integral number of pages,
+ round up sec_size to a multiple of the page size, then add two full pages for protection. */
+ section_size = ROUND_UP(*sec_size, OS_PAGE_SIZE / OS_PAGELET_SIZE);
+ status = gtm_expreg(section_size + 2 * OS_PAGE_SIZE / OS_PAGELET_SIZE, inadr, PSL$C_USER, 0);
+ if (SS$_NORMAL != status)
+ {
+ sys$dassgn(gds_info->fab->fab$l_stv);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_DBFILERR, 2,
+ gds_info->fab->fab$b_fns, gds_info->fab->fab$l_fna, status);
+ }
+ gds_info->s_addrs.db_addrs[0] = inadr[0] + OS_PAGE_SIZE;
+ gds_info->s_addrs.db_addrs[1] = inadr[1] - OS_PAGE_SIZE;
+ assert(gds_info->s_addrs.db_addrs[1] == gds_info->s_addrs.db_addrs[0] + section_size * OS_PAGELET_SIZE - 1);
+ /* GUARD THE BEGINNING OF THE DATA BASE SEGMENT WITH ONE NOACCESS PAGE */
+ inadr1[0] = inadr1[1]
+ = inadr[0];
+ status = sys$setprt(inadr1, NULL, 0, PRT$C_NA, 0);
+ if (SS$_NORMAL == status)
+ {
+ /* GUARD THE END OF THE DATA BASE SEGMENT WITH ONE NOACCESS PAGE */
+ inadr1[0] = inadr1[1]
+ = gds_info->s_addrs.db_addrs[1] + 1;
+ status = sys$setprt(inadr1, NULL, PSL$C_USER, PRT$C_NA, NULL);
+ }
+ if (SS$_NORMAL != status)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_DBFILERR, 2,
+ gds_info->fab->fab$b_fns, gds_info->fab->fab$l_fna, status);
+ return;
+}
+
+void db_init(gd_region *reg, sgmnt_data *tsd)
+{
+ boolean_t clustered, cluster_member, mupip_jnl_recover, read_write, is_bg, lock_released = FALSE;
+ char name_buff[GLO_NAME_MAXLEN], node_buff[14], nodename_buff[16], local_nodename_buff[16];
+ sgmnt_addrs *csa;
+ sgmnt_data *nsd;
+ file_control *fc;
+ struct dsc$descriptor_s name_dsc, node_dsc;
+ syistruct syi_list;
+ int index, dblksize, fbwsize, item_code;
+ uint4 efn_mask, flags, i, init_status, node, size, status;
+ uint4 lk_pid = 0;
+ unsigned short iosb[4], retlen, local_nodename_len;
+ vms_gds_info *gds_info;
+ vms_lock_sb *file_lksb;
+ uint4 get_lkpid(struct dsc$descriptor_s *, int, uint4);
+ struct
+ {
+ item_list_3 ilist[2];
+ int4 terminator;
+ } syi_list_2;
+ struct
+ {
+ item_list_3 item[1];
+ int4 terminator;
+ } lk_pid_list;
+ char now_running[MAX_REL_NAME];
+ gtm_uint64_t sec_size;
+ int jnl_buffer_size;
+ char s[JNLBUFFUPDAPNDX_SIZE]; /* JNLBUFFUPDAPNDX_SIZE is defined in jnl.h */
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ ESTABLISH(dbinit_ch);
+ assert(INTRPT_IN_GVCST_INIT == intrpt_ok_state); /* we better be called from gvcst_init */
+ TREF(new_dbinit_ipc) = FALSE; /* we did not create a new ipc resource */
+ /* ------------------------------------- gather information --------------------------------------- */
+ assert((dba_bg == tsd->acc_meth) || (dba_mm == tsd->acc_meth));
+ is_bg = (dba_bg == tsd->acc_meth);
+ clustered = (dba_bg == tsd->clustered && tsd->acc_meth); /* ??? */
+ read_write = (FALSE == reg->read_only);
+ node = 0;
+ syi_list_2.ilist[0].item_code = SYI$_NODE_CSID;
+ syi_list_2.ilist[0].buffer_address = &node;
+ syi_list_2.ilist[0].buffer_length = SIZEOF(node);
+ syi_list_2.ilist[0].return_length_address = &retlen;
+ syi_list_2.ilist[1].item_code = SYI$_NODENAME;
+ syi_list_2.ilist[1].buffer_address = local_nodename_buff;
+ syi_list_2.ilist[1].buffer_length = SIZEOF(local_nodename_buff) - 1;
+ syi_list_2.ilist[1].return_length_address = &local_nodename_len;
+ syi_list_2.terminator = 0;
+ status = sys$getsyiw(EFN$C_ENF, NULL, NULL, &syi_list_2, iosb, NULL, 0);
+ if (SS$_NORMAL == status)
+ status = iosb[0];
+ if (SS$_NORMAL != status)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_CLSTCONFLICT, 4, DB_LEN_STR(reg),
+ 0, local_nodename_buff, status);
+ if (0 == node)
+ node = DEF_NODE;
+ if (-1 != reg->node) /* -1 is a flag indicating that a MUPIP JOURNAL /RECOVER is in progress */
+ reg->node = node; /* Leave it so that it goes into the value block */
+
+ /* --------------------------- grab the startup/rundown lock on file --------------------------- */
+ gds_info = FILE_INFO(reg);
+ file_lksb = &gds_info->file_cntl_lsb;
+ global_name("GT$S", &gds_info->file_id, name_buff);
+ name_dsc.dsc$a_pointer = &name_buff[1];
+ name_dsc.dsc$w_length = name_buff[0];
+ name_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
+ name_dsc.dsc$b_class = DSC$K_CLASS_S;
+ /* These locks must be taken out before mapping the file to a section, and released after unmapping the section
+ * Note: Rather than simply taking out this lock at PW mode, we take it out at NL mode and then convert to PW.
+ * Lock requests in the conversion queue are serviced before locks in the waiting queue; heavy GT.CX activity
+ * on a given database can potentially keep the conversion queue busy enough to keep new lock requests (especially
+ * at higher lock modes like PW) bottled up on the waiting queue indefinitely. Since NL mode lock requests are
+ * compatible with all other lock modes, and since they don't go to the waiting queue if LCK$M_EXPEDITE is specified;
+ * they are always granted. Then the subsequent conversion request will rapidly move to the head of the conversion
+ * queue and ultimately be granted.
+ */
+ assert((0 == file_lksb->lockid) || (!IS_GTM_IMAGE));
+ if (0 == file_lksb->lockid)
+ {
+ mupip_jnl_recover = FALSE;
+ /* NL mode lock is granted immediately only if LCK$M_EXPEDITE is specified. If there is a waiting queue
+ * for this lock and LCK$M_EXPEDITE is not specified, we might not be granted this NL mode lock immediately.
+ */
+ status = gtm_enqw(EFN$C_ENF, LCK$K_NLMODE, file_lksb, LCK$M_SYSTEM | LCK$M_EXPEDITE,
+ &name_dsc, 0, NULL, 0, NULL, PSL$C_USER, 0);
+ if (SS$_NORMAL == status)
+ {
+ if (dse_running)
+ {
+ /* try to acquire the lock synchronously without waiting */
+ status = gtm_enqw(EFN$C_ENF, LCK$K_PWMODE, file_lksb, LCK$M_VALBLK | LCK$M_CONVERT |
+ LCK$M_NODLCKBLK | LCK$M_NOQUEUE, NULL, 0, NULL, 0, NULL, PSL$C_USER, 0);
+ if (SS$_NORMAL == status)
+ status = file_lksb->cond;
+ else if (SS$_NOTQUEUED == status)
+ { /* someone else is holding the lock */
+ assert(0 != file_lksb->lockid && -1 != file_lksb->lockid);
+ status = get_lkpid(&name_dsc, LCK$K_PWMODE, &lk_pid);
+ if (SS$_NORMAL != status)
+ {
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Failed to get lock pid"),
+ ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), status);
+ } /* no 'else' needed, since the process wont come down after the rts_error */
+ if (lk_pid)
+ util_out_print("Access control lock for region !AD held by pid, !UL. "
+ "An attempt will be made in the next 30 seconds to grab it.",
+ TRUE, DB_LEN_STR(reg), lk_pid);
+ TREF(semwait2long) = FALSE;
+ start_timer(semwt2long_handler, MAX_SEM_WT, semwt2long_handler, 0, NULL);
+ /* do an asynchronous enq and then wait using wflor() */
+ status = gtm_enq(efn_immed_wait, LCK$K_PWMODE, file_lksb, LCK$M_VALBLK |
+ LCK$M_CONVERT | LCK$M_NODLCKBLK, NULL, 0, NULL, 0, NULL, PSL$C_USER, 0);
+ if (SS$_NORMAL != status)
+ {
+ cancel_timer(semwt2long_handler);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Failed to register an asynchronous enq"),
+ ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg), status);
+ }
+ /* wait for the timer to expire or for the above enq() to finish */
+ efn_mask = ((SHFT_MSK << efn_timer) | (SHFT_MSK << efn_immed_wait));
+ status = sys$wflor(efn_immed_wait, efn_mask);
+ if (SS$_NORMAL != status)
+ {
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Wait-for-logical-or failed"), ERR_CRITSEMFAIL,
+ 2, DB_LEN_STR(reg), status);
+ }
+ if (SS$_NORMAL != file_lksb->cond)
+ {
+ if (TREF(semwait2long))
+ {
+ status = get_lkpid(&name_dsc, LCK$K_PWMODE, &lk_pid);
+ if (SS$_NORMAL != status)
+ {
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Failed to get lock pid"), ERR_CRITSEMFAIL, 2,
+ DB_LEN_STR(reg), status);
+ }
+ if (0 != lk_pid)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_SEMWT2LONG, 7,
+ process_id, (MAX_SEM_WT / 1000),
+ LEN_AND_LIT("access control"), DB_LEN_STR(reg), lk_pid);
+ else
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4)
+ ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg));
+ } else
+ {
+ cancel_timer(semwt2long_handler);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4)
+ ERR_CRITSEMFAIL, 2, DB_LEN_STR(reg));
+ }
+ } else
+ {
+ status = file_lksb->cond;
+ if (!TREF(semwait2long))
+ cancel_timer(semwt2long_handler);
+ }
+ }
+ } else
+ {
+ status = gtm_enqw(EFN$C_ENF, LCK$K_PWMODE, file_lksb,
+ LCK$M_VALBLK | LCK$M_CONVERT | LCK$M_NODLCKBLK, NULL, 0, NULL, 0, NULL, PSL$C_USER, 0);
+ if (SS$_NORMAL == status)
+ status = file_lksb->cond;
+ }
+ }
+ if ((SS$_NORMAL != status) && (SS$_VALNOTVALID != status))
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), status);
+ if ((SS$_NORMAL == status) && (0 != file_lksb->valblk[0]) && (-1 != reg->node))
+ {
+ if (file_lksb->valblk[0] != node)
+ {
+ if (-1 == file_lksb->valblk[0])
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_MUPRECFLLCK, 2, DB_LEN_STR(reg));
+ if (FALSE == clustered)
+ {
+ syi_list.ilist.item_code = SYI$_NODENAME;
+ syi_list.ilist.buffer_address = nodename_buff;
+ syi_list.ilist.buffer_length = SIZEOF(nodename_buff) - 1;
+ syi_list.ilist.return_length_address = &retlen;
+ syi_list.terminator = 0;
+ status = sys$getsyiw(EFN$C_ENF, file_lksb->valblk, NULL, &syi_list, iosb, NULL, 0);
+ if (SS$_NORMAL == status)
+ status = iosb[0];
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_CLSTCONFLICT, 4, DB_LEN_STR(reg),
+ (SS$_NORMAL == status) ? strlen(nodename_buff) : 0, nodename_buff);
+ }
+ }
+ } else
+ file_lksb->valblk[0] = 0;
+ } else if (IS_MUPIP_IMAGE)
+ mupip_jnl_recover = TRUE;
+
+ /* ------------------------------------ GT.CX: grab the lock on node --------------------------------------- */
+ memcpy(node_buff, "GT$N_", 5);
+ i2hex(node, &node_buff[5], 8);
+ if (TRUE == clustered)
+ node_dsc.dsc$w_length = 13;
+ else
+ {
+ node_buff[13] = read_write ? 'W' : 'R';
+ node_dsc.dsc$w_length = 14;
+ }
+ node_dsc.dsc$a_pointer = node_buff;
+ node_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
+ node_dsc.dsc$b_class = DSC$K_CLASS_S;
+ status = gtm_enqw(EFN$C_ENF, LCK$K_NLMODE, &gds_info->cx_cntl_lsb, LCK$M_SYSTEM | LCK$M_EXPEDITE,
+ &node_dsc, file_lksb->lockid, NULL, 0, NULL, PSL$C_USER, 0);
+ if (SS$_NORMAL == status)
+ {
+ status = gtm_enqw(EFN$C_ENF, LCK$K_CRMODE, &gds_info->cx_cntl_lsb, LCK$M_CONVERT,
+ &node_dsc, file_lksb->lockid, NULL, 0, NULL, PSL$C_USER, 0);
+ if (SS$_NORMAL == status)
+ status = gds_info->cx_cntl_lsb.cond;
+ }
+ if (SS$_NORMAL != status)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), status);
+
+ /* --------------------------- Re-read the fileheader inside the lock -------------------------------- */
+ fc = reg->dyn.addr->file_cntl;
+ fc->file_type = reg->dyn.addr->acc_meth;
+ fc->op = FC_READ;
+ fc->op_buff = (sm_uc_ptr_t)tsd;
+ fc->op_len = SIZEOF(*tsd);
+ fc->op_pos = 1;
+ status = dbfilop(fc);
+ if (SS$_NORMAL != status)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_DBFILERR, 2, DB_LEN_STR(reg), status,
+ gds_info->fab->fab$l_stv);
+
+ /* ----------------------------- init sections and establish pointers in csa --------------------- */
+ /* Since we are about to allocate new shared memory, if necessary, adjust the journal buffer size right now.
+ * Note that if the process setting up shared memory is a read-only process, then we might not flush updated
+ * jnl_buffer_size to the file header, which is fine because the value in shared memory is what all processes
+ * are looking at. If necessary, the next process to initialize shared memory will repeat the process of
+ * adjusting the jnl_buffer_size value.
+ */
+ jnl_buffer_size = tsd->jnl_buffer_size;
+ if ((0 != jnl_buffer_size) && (jnl_buffer_size < (tsd->blk_size / DISK_BLOCK_SIZE + 1)))
+ {
+ ROUND_UP_MIN_JNL_BUFF_SIZE(tsd->jnl_buffer_size, tsd);
+ SNPRINTF(s, JNLBUFFUPDAPNDX_SIZE, JNLBUFFUPDAPNDX, JNL_BUFF_PORT_MIN(tsd), JNL_BUFFER_MAX);
+ send_msg_csa(CSA_ARG(NULL) VARLSTCNT(10) ERR_JNLBUFFREGUPD, 4, REG_LEN_STR(reg),
+ jnl_buffer_size, tsd->jnl_buffer_size, ERR_TEXT, 2, LEN_AND_STR(s));
+ }
+ /* The layout of shared memory depends on the number of mutex queue entries specified in the file header. Thus in
+ * order to set, for example, csa->critical or csa->shmpool_buffer, we need to know this number. However, this
+ * number can be zero if we have not yet done db_auto_upgrade. So go ahead and upgrade to the value that will
+ * eventually be used, which is DEFAULT_NUM_CRIT_ENTRY.
+ */
+ if (0 == NUM_CRIT_ENTRY(tsd))
+ NUM_CRIT_ENTRY(tsd) = DEFAULT_NUM_CRIT_ENTRY;
+ dbsecspc(reg, tsd, &sec_size); /* calculate section size (filesize for MM) */
+ csa = &gds_info->s_addrs;
+ flags = SEC$M_GBL | SEC$M_SYSGBL;
+ if (is_bg)
+ flags |= SEC$M_WRT | SEC$M_PAGFIL | SEC$M_PERM;
+ else if (read_write)
+ flags |= SEC$M_WRT;
+ init_status = init_sec(csa->db_addrs, &name_dsc, gds_info->fab->fab$l_stv, sec_size, flags);
+ if ((SS$_NORMAL != init_status)
+ && ((SS$_CREATED != init_status) || ((0 != file_lksb->valblk[0]) && (FALSE == clustered))))
+ {
+ if (SS$_CREATED == init_status)
+ {
+ del_sec(SEC$M_SYSGBL, &name_dsc, NULL);
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_DBFILERR, 2, DB_LEN_STR(reg),
+ ERR_TEXT, 2, LEN_AND_LIT("Check for 'delete pending' sections - stop all accessors"));
+ } else
+ {
+ assert(FALSE);
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg),
+ ERR_TEXT, 2, LEN_AND_LIT("Error initializing shared memory"), init_status);
+ }
+ }
+ if (is_bg)
+ csa->nl = csa->db_addrs[0];
+ else
+ {
+ size = ROUND_UP(LOCK_SPACE_SIZE(tsd) + NODE_LOCAL_SPACE(tsd) + JNL_SHARE_SIZE(tsd) + SHMPOOL_BUFFER_SIZE,
+ OS_PAGE_SIZE) / OS_PAGELET_SIZE;
+ status = gtm_expreg(size, csa->lock_addrs, PSL$C_USER, 0);
+ if (SS$_NORMAL != status)
+ {
+ csa->lock_addrs[0] = NULL;
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), status);
+ }
+ assert(csa->lock_addrs[0] + size * OS_PAGELET_SIZE - 1 == csa->lock_addrs[1]);
+ name_buff[4] = 'L';
+ status = init_sec(csa->lock_addrs, &name_dsc, 0, size, SEC$M_PAGFIL | SEC$M_GBL | SEC$M_WRT | SEC$M_SYSGBL);
+ if ((SS$_NORMAL != status) && ((SS$_CREATED != status) || (SS$_NORMAL == init_status)))
+ {
+ if (SS$_CREATED == status)
+ {
+ del_sec(SEC$M_SYSGBL, &name_dsc, NULL);
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_DBFILERR, 2, DB_LEN_STR(reg),
+ ERR_TEXT, 2, LEN_AND_LIT("Check for 'delete pending' sections - stop all accessors"));
+ } else
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(9) ERR_DBFILERR, 2, DB_LEN_STR(reg),
+ ERR_TEXT, 2, LEN_AND_LIT("Error initializing MM non-file shared memory"), status);
+ }
+ csa->nl = csa->lock_addrs[0];
+ }
+ /* If shared memory is already initialized, do VERMISMATCH check BEFORE referencing any other fields in shared memory. */
+ if (SS$_CREATED == init_status)
+ TREF(new_dbinit_ipc) = TRUE;
+ else if (memcmp(csa->nl->now_running, gtm_release_name, gtm_release_name_len + 1))
+ { /* Copy csa->nl->now_running into a local variable before passing to rts_error() due to the following issue.
+ * In VMS, a call to rts_error copies only the error message and its arguments (as pointers) and
+ * transfers control to the topmost condition handler which is dbinit_ch() in this case. dbinit_ch()
+ * does a PRN_ERROR only for SUCCESS/INFO (VERMISMATCH is neither of them) and in addition
+ * nullifies csa->nl as part of its condition handling. It then transfers control to the next level condition
+ * handler which does a PRN_ERROR but at that point in time, the parameter csa->nl->now_running is no longer
+ * accessible and hence no parameter substitution occurs (i.e. the error message gets displayed with plain !ADs).
+ * In UNIX, this is not an issue since the first call to rts_error() does the error message
+ * construction before handing control to the topmost condition handler. But it does not hurt to do the copy.
+ */
+ assert(strlen(csa->nl->now_running) < SIZEOF(now_running));
+ memcpy(now_running, csa->nl->now_running, SIZEOF(now_running));
+ now_running[SIZEOF(now_running) - 1] = '\0'; /* protection against bad values of csa->nl->now_running */
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_VERMISMATCH, 6, DB_LEN_STR(reg), gtm_release_name_len, gtm_release_name,
+ LEN_AND_STR(now_running));
+ }
+ /* Neither the creator, nor the first-writer ==> Done with mod to shared memory ==> release the lock */
+ if ((0 != file_lksb->valblk[0]) && ((!read_write) || (csa->nl->ref_cnt > 0)))
+ {
+ if (read_write)
+ {
+ adawi(1, &csa->nl->ref_cnt);
+ assert(!csa->ref_cnt); /* Increment shared ref_cnt before private ref_cnt increment. */
+ csa->ref_cnt++; /* Currently journaling logic in gds_rundown() in VMS relies
+ * on this order to detect last writer */
+ assert(csa->read_write);
+ }
+ if (FALSE == clustered)
+ status = gtm_enqw(EFN$C_ENF, LCK$K_CRMODE, file_lksb, LCK$M_CONVERT | LCK$M_NODLCKBLK,
+ NULL, 0, NULL, 0, NULL, PSL$C_USER, 0);
+ else
+ status = gtm_enqw(EFN$C_ENF, LCK$K_NLMODE, file_lksb, LCK$M_CONVERT,
+ NULL, 0, NULL, 0, NULL, PSL$C_USER, 0);
+ lock_released = TRUE;
+ if (SS$_NORMAL == status)
+ status = file_lksb->cond;
+ if (SS$_NORMAL != status)
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), status);
+ }
+ csa->critical = (sm_uc_ptr_t)(csa->nl) + NODE_LOCAL_SIZE;
+ crash_count = csa->critical->crashcnt; /* done in gvcst_init(), but needed before that for call to grab_crit() below */
+ /* Note: Here we check jnl_sate from database file and its value cannot change without standalone access.
+ * The jnl_buff buffer should be initialized irrespective of read/write process */
+ JNL_INIT(csa, reg, tsd);
+ csa->shmpool_buffer = (shmpool_buff_hdr_ptr_t)((sm_uc_ptr_t)(csa->nl) + NODE_LOCAL_SPACE(tsd) + JNL_SHARE_SIZE(tsd));
+ csa->lock_addrs[0] = (sm_uc_ptr_t)(csa->shmpool_buffer) + SHMPOOL_BUFFER_SIZE;
+ csa->lock_addrs[1] = csa->lock_addrs[0] + LOCK_SPACE_SIZE(tsd) - 1;
+ if (is_bg)
+ {
+ nsd = csa->hdr = csa->lock_addrs[1] + 1 + CACHE_CONTROL_SIZE(tsd);
+ if (SS$_CREATED == init_status)
+ {
+ memcpy((uchar_ptr_t)nsd, (uchar_ptr_t)tsd, SIZEOF(sgmnt_data));
+ fc->file_type = dba_bg;
+ fc->op = FC_READ;
+ fc->op_buff = MM_ADDR(nsd);
+ fc->op_len = MASTER_MAP_SIZE(nsd);
+ fc->op_pos = MM_BLOCK;
+ status = dbfilop(fc);
+ if (SS$_NORMAL != status)
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(6) ERR_DBFILERR, 2, DB_LEN_STR(reg), status,
+ gds_info->fab->fab$l_stv);
+ if (nsd->owner_node)
+ { /* Crash occurred. */
+ PRINT_CRASH_MESSAGE_2_ARGS(strlen((char *)local_nodename_buff), local_nodename_buff);
+ }
+ }
+ } else
+ {
+ nsd = csa->hdr = csa->db_addrs[0];
+ SET_MM_BASE_ADDR(csa, nsd);
+ }
+ csa->total_blks = nsd->trans_hist.total_blks;
+
+ /* ensure correct alignment */
+ assert((-(SIZEOF(int4) * 2) & (int)csa->critical) == csa->critical);
+ assert(0 == ((OS_PAGE_SIZE - 1) & (int)csa->critical));
+ assert(0 == ((OS_PAGE_SIZE - 1) & (int)csa->nl));
+ assert((!(JNL_ALLOWED(csa))) ||
+ (0 == ((OS_PAGE_SIZE - 1) & (int)((sm_uc_ptr_t)(csa->jnl->jnl_buff) - JNL_NAME_EXP_SIZE))));
+ assert(0 == ((OS_PAGE_SIZE - 1) & (int)csa->shmpool_buffer));
+ assert(0 == ((OS_PAGE_SIZE - 1) & (int)csa->lock_addrs[0]));
+ assert(0 == ((OS_PAGE_SIZE - 1) & (int)(csa->lock_addrs[1] + 1)));
+ assert(0 == ((OS_PAGE_SIZE - 1) & (int)csa->hdr));
+
+ /* ----------------------------- setup shared memory if needed -------------------------- */
+ if (SS$_CREATED == init_status)
+ { /* initialize if new */
+ if (!clustered)
+ memset(csa->nl, 0, SIZEOF(*csa->nl));
+ if (JNL_ALLOWED(csa))
+ { /* initialize jb->cycle to a value different from initial value of jpc->cycle (0). although this is not
+ * necessary right now, in the future, the plan is to change jnl_ensure_open() to only do a cycle mismatch
+ * check in order to determine whether to call jnl_file_open() or not. this is in preparation for that.
+ */
+ csa->jnl->jnl_buff->cycle = 1;
+ }
+ memcpy(csa->nl->label, GDS_LABEL, GDS_LABEL_SZ - 1); /* Database label */
+ assert(MAX_REL_NAME > gtm_release_name_len);
+ memcpy(csa->nl->now_running, gtm_release_name, gtm_release_name_len + 1); /* GT.M version */
+ assert(MAX_FN_LEN > reg->dyn.addr->fname_len);
+ memcpy(csa->nl->fname, reg->dyn.addr->fname, reg->dyn.addr->fname_len); /* file name */
+ memcpy(&csa->nl->unique_id.file_id[0], &(gds_info->file_id), SIZEOF(gds_file_id)); /* file id */
+ assert(MAX_MCNAMELEN > local_nodename_len);
+ memcpy(csa->nl->machine_name, local_nodename_buff, local_nodename_len); /* node name */
+ csa->nl->owner_node = node; /* node id */
+ csa->nl->wcs_staleness = -1;
+ csa->nl->wcs_timers = -1;
+ csa->nl->highest_lbm_blk_changed = -1;
+ csa->nl->nbb = BACKUP_NOT_IN_PROGRESS;
+ shmpool_buff_init(reg);
+ csa->nl->sec_size = sec_size; /* Set the shared memory size */
+
+ /* save pointers in csa to access shared memory */
+ csa->nl->critical = (sm_off_t)((sm_uc_ptr_t)csa->critical - (sm_uc_ptr_t)csa->nl);
+ if (JNL_ALLOWED(csa))
+ csa->nl->jnl_buff = (sm_off_t)((sm_uc_ptr_t)csa->jnl->jnl_buff - (sm_uc_ptr_t)csa->nl);
+ csa->nl->shmpool_buffer = (sm_off_t)((sm_uc_ptr_t)csa->shmpool_buffer - (sm_uc_ptr_t)csa->nl);
+ if (is_bg)
+ /* In MM mode, it is possible that (eventually) shared mem and mapped mem could be > 4G apart */
+ csa->nl->hdr = (sm_off_t)((sm_uc_ptr_t)csa->hdr - (sm_uc_ptr_t)csa->nl);
+ csa->nl->lock_addrs = (sm_off_t)((sm_uc_ptr_t)csa->lock_addrs[0] - (sm_uc_ptr_t)csa->nl);
+
+ mlk_shr_init(csa->lock_addrs[0], nsd->lock_space_size, csa, read_write);
+
+ /* At this point, nsd->owner_node may indicate improper shutdown; see if it's safe to continue */
+ if ((0 != nsd->owner_node) && (nsd->owner_node != node))
+ {
+ syi_list_2.ilist[0].item_code = SYI$_CLUSTER_MEMBER;
+ syi_list_2.ilist[0].buffer_address = &cluster_member;
+ syi_list_2.ilist[0].buffer_length = SIZEOF(cluster_member);
+ syi_list_2.ilist[0].return_length_address = &i; /* dummy - not used */
+ syi_list_2.ilist[1].item_code = SYI$_NODENAME;
+ syi_list_2.ilist[1].buffer_address = nodename_buff;
+ syi_list_2.ilist[1].buffer_length = SIZEOF(nodename_buff) - 1;
+ syi_list_2.ilist[1].return_length_address = &retlen;
+ syi_list_2.terminator = 0;
+ status = sys$getsyiw(EFN$C_ENF, &nsd->owner_node, NULL, &syi_list_2, iosb, NULL, 0);
+ if (SS$_NORMAL == status)
+ status = iosb[0];
+ if ((SS$_NORMAL != status) && (SS$_NOSUCHNODE != status))
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(7) ERR_CLSTCONFLICT, 4,
+ DB_LEN_STR(reg), LEN_AND_STR(nodename_buff), status);
+ /*** Temporarily add `&& !clustered' to the following condition, ****
+ **** until a more specific solution to this problem is made, probably in ccp_close1 ***/
+ if ((SS$_NORMAL == status) && (TRUE == cluster_member) && (FALSE == clustered))
+ { /* DB was improperly shutdown on another node in the cluster,
+ * and that node is still running; force user to rundown.
+ */
+ PRINT_CRASH_MESSAGE_2_ARGS(retlen, nodename_buff);
+ }
+ if (read_write)
+ {
+ CHECK_TN(csa, nsd, nsd->trans_hist.curr_tn + HEADER_UPDATE_COUNT); /* can issue TNTOOLARGE error */
+ nsd->trans_hist.curr_tn += HEADER_UPDATE_COUNT;
+ }
+ }
+ if (is_bg)
+ {
+ csa->nl->cache_off = -CACHE_CONTROL_SIZE(nsd);
+ db_csh_ini(csa);
+ bt_malloc(csa);
+ db_csh_ref(csa, TRUE);
+ if (0 == nsd->flush_trigger)
+ nsd->flush_trigger = FLUSH_FACTOR(nsd->n_bts);
+ }
+ if (!read_write)
+ csa->nl->remove_shm = TRUE; /* gds_rundown can remove gblsec if first process has read-only access */
+ csa->nl->glob_sec_init = TRUE;
+ if (read_write || is_bg)
+ { /* add current db_csh counters into the cumulative counters and reset the current counters */
+# define TAB_DB_CSH_ACCT_REC(COUNTER, DUMMY1, DUMMY2) \
+ csa->hdr->COUNTER.cumul_count += csa->hdr->COUNTER.curr_count; \
+ csa->hdr->COUNTER.curr_count = 0;
+# include "tab_db_csh_acct_rec.h"
+# undef TAB_DB_CSH_ACCT_REC
+ }
+ gvstats_rec_csd2cnl(csa); /* should be called before "db_auto_upgrade" */
+ db_auto_upgrade(reg); /* should be called before "gtm_mutex_init" to ensure NUM_CRIT_ENTRY is nonzero */
+ mutex_init(csa->critical, NUM_CRIT_ENTRY(csa->hdr), FALSE);
+ } else
+ {
+ if (memcmp(csa->nl->label, GDS_LABEL, GDS_LABEL_SZ - 1))
+ {
+ name_buff[4] = 'S';
+ if (memcmp(csa->nl->label, GDS_LABEL, GDS_LABEL_SZ - 3))
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_GBLSECNOTGDS, 2, name_buff[0], &name_buff[1]);
+ else
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_BADGBLSECVER, 2, name_buff[0], &name_buff[1]);
+ }
+ if (memcmp(&csa->nl->unique_id.file_id[0], (char *)(&(gds_info->file_id)), SIZEOF(gds_file_id)))
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(4) ERR_FILEIDGBLSEC, 2, DB_LEN_STR(reg));
+ if (csa->nl->donotflush_dbjnl)
+ {
+ assert(FALSE);
+ PRINT_CRASH_MESSAGE_6_ARGS(strlen((char *)csa->nl->machine_name), csa->nl->machine_name, ERR_TEXT, 2,
+ SIZEOF("mupip recover/rollback created shared memory. Needs MUPIP RUNDOWN") - 1,
+ "mupip recover/rollback created shared memory. Needs MUPIP RUNDOWN");
+ }
+ /* verify pointers from our calculation vs. the copy in shared memory */
+ if (csa->nl->critical != (sm_off_t)((sm_uc_ptr_t)csa->critical - (sm_uc_ptr_t)csa->nl))
+ {
+ PRINT_CRASH_MESSAGE_8_ARGS(strlen((char *)csa->nl->machine_name), csa->nl->machine_name,
+ ERR_NLMISMATCHCALC, 4, SIZEOF("critical") - 1, "critical",
+ (uint4)((sm_uc_ptr_t)csa->critical - (sm_uc_ptr_t)csa->nl), (uint4)csa->nl->critical);
+ }
+ if ((JNL_ALLOWED(csa)) &&
+ (csa->nl->jnl_buff != (sm_off_t)((sm_uc_ptr_t)csa->jnl->jnl_buff - (sm_uc_ptr_t)csa->nl)))
+ {
+ PRINT_CRASH_MESSAGE_8_ARGS(strlen((char *)csa->nl->machine_name), csa->nl->machine_name,
+ ERR_NLMISMATCHCALC, 4, SIZEOF("journal buffer") - 1, "journal buffer",
+ (uint4)((sm_uc_ptr_t)csa->jnl->jnl_buff - (sm_uc_ptr_t)csa->nl), (uint4)csa->nl->jnl_buff);
+ }
+ if (csa->nl->shmpool_buffer != (sm_off_t)((sm_uc_ptr_t)csa->shmpool_buffer - (sm_uc_ptr_t)csa->nl))
+ {
+ PRINT_CRASH_MESSAGE_8_ARGS(strlen((char *)csa->nl->machine_name), csa->nl->machine_name,
+ ERR_NLMISMATCHCALC, 4, SIZEOF("backup buffer") - 1, "backup buffer",
+ (uint4)((sm_uc_ptr_t)csa->shmpool_buffer - (sm_uc_ptr_t)csa->nl), (uint4)csa->nl->shmpool_buffer);
+ }
+ if ((is_bg) && (csa->nl->hdr != (sm_off_t)((sm_uc_ptr_t)csa->hdr - (sm_uc_ptr_t)csa->nl)))
+ {
+ PRINT_CRASH_MESSAGE_8_ARGS(strlen((char *)csa->nl->machine_name), csa->nl->machine_name,
+ ERR_NLMISMATCHCALC, 4, SIZEOF("file header") - 1, "file header",
+ (uint4)((sm_uc_ptr_t)csa->hdr - (sm_uc_ptr_t)csa->nl), (uint4)csa->nl->hdr);
+ }
+ if (csa->nl->lock_addrs != (sm_off_t)((sm_uc_ptr_t)csa->lock_addrs[0] - (sm_uc_ptr_t)csa->nl))
+ {
+ PRINT_CRASH_MESSAGE_8_ARGS(strlen((char *)csa->nl->machine_name), csa->nl->machine_name,
+ ERR_NLMISMATCHCALC, 4, SIZEOF("lock address") - 1, "lock address",
+ (uint4)((sm_uc_ptr_t)csa->lock_addrs[0] - (sm_uc_ptr_t)csa->nl), (uint4)csa->nl->lock_addrs);
+ }
+ /* now_running is checked in gvcst_init, since they are portable */
+ if (is_bg)
+ db_csh_ini(csa);
+ }
+ if (gtm_fullblockwrites)
+ { /* We have been asked to do FULL BLOCK WRITES for this database. Unlike *NIX, on VMS, we can get the
+ underlying filsystem block/buffersize with a call to $GETDVI. This allows a full write of a block
+ without the OS having to fetch the old block for a read/update operation. We will round the IOs
+ (only from dsk_write() to the next filesystem blocksize if the following criteria are met:
+
+ 1) Database blocksize must be a whole multiple of the filesystem blocksize for the above
+ mentioned reason.
+
+ 2) Filesystem blocksize must be a factor of the location of the first data block
+ given by start_vbn.
+
+ The saved length (if the feature is enabled) will be the filesystem blocksize and will be the
+ length that a database IO is rounded up to prior to initiation of the IO.
+ */
+ item_code = DVI$_DEVBUFSIZ;
+ status = lib$getdvi(&item_code, &gds_info->fab->fab$l_stv, NULL, &fbwsize, NULL, NULL);
+ if (SS$_NORMAL == status)
+ {
+ dblksize = csa->hdr->blk_size;
+ if (0 != fbwsize && (0 == dblksize % fbwsize) &&
+ (0 == ((csa->hdr->start_vbn - 1) * DISK_BLOCK_SIZE) % fbwsize))
+ csa->do_fullblockwrites = TRUE; /* This region is fullblockwrite enabled */
+ /* Report this length in DSE even if not enabled */
+ csa->fullblockwrite_len = fbwsize; /* Length for rounding fullblockwrite */
+ } /* else if lib$getdvi fails.. do non-fullblockwrites */
+ else
+ send_msg_csa(CSA_ARG(csa) VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("getdvi DEVBUFSIZ"), CALLFROM, status);
+ }
+ if (!lock_released)
+ {
+ if (read_write)
+ { /* ========= first writer =========== */
+ /* since lock_released was set based on csa->nl->ref_cnt and since the latter is not an accurate
+ * indicator of whether we are the last writer or not, we need to be careful before modifying any
+ * shared memory fields below, hence the grab_crit */
+ if (!csa->nl->wc_blocked)
+ { /* if wc_blocked is TRUE and if journaling is enabled, grab_crit below will end up doing
+ * wcs_recover which will try to open the journal file but will fail because cs_addrs
+ * will be NULL since we have not yet opened this region (reg->open is still FALSE).
+ * in that case we want to be safe and avoid doing the grab_crit().
+ * this will be fixed as part of C9E01-002490.
+ */
+ bt_init(csa); /* needed to initialize csa->ti, csa->bt_header, csa->bt_base, csa->th_base */
+ /* used by grab_crit() and routines it invokes which are wcs_verify/wcs_recover */
+ grab_crit(reg);
+ }
+ csa->nl->remove_shm = FALSE;
+ assert(0 == csa->nl->ref_cnt); /* ensure no other writer has incremented ref_cnt until now */
+ adawi(1, &csa->nl->ref_cnt);
+ assert(!csa->ref_cnt); /* Increment shared ref_cnt before private ref_cnt increment. */
+ csa->ref_cnt++; /* Currently journaling logic in gds_rundown() in VMS relies
+ * on this order to detect last writer */
+ assert(csa->read_write);
+ memcpy(csa->hdr->now_running, gtm_release_name, gtm_release_name_len + 1);
+ csa->hdr->owner_node = node;
+ nsd->trans_hist.early_tn = nsd->trans_hist.curr_tn;
+ nsd->max_update_array_size = nsd->max_non_bm_update_array_size
+ = ROUND_UP2(MAX_NON_BITMAP_UPDATE_ARRAY_SIZE(nsd), UPDATE_ARRAY_ALIGN_SIZE);
+ nsd->max_update_array_size += ROUND_UP2(MAX_BITMAP_UPDATE_ARRAY_SIZE, UPDATE_ARRAY_ALIGN_SIZE);
+ assert(0 == memcmp(nsd, GDS_LABEL, GDS_LABEL_SZ - 1));
+ status = sys$qiow(EFN$C_ENF, gds_info->fab->fab$l_stv, IO$_WRITEVBLK, iosb, NULL, 0,
+ nsd, ROUND_UP(SIZEOF(sgmnt_data), DISK_BLOCK_SIZE), 1, 0, 0, 0);
+ if (SS$_NORMAL == status)
+ status = iosb[0];
+ if (csa->now_crit)
+ rel_crit(reg);
+ if (SS$_NORMAL != status)
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), status);
+ }
+ /* releasing the startup/shutdown lock */
+ file_lksb->valblk[0] = mupip_jnl_recover ? -1 : reg->node;
+ if ((FALSE == clustered) || (TRUE == mupip_jnl_recover))
+ status = gtm_enqw(EFN$C_ENF, mupip_jnl_recover ? LCK$K_EXMODE : LCK$K_CRMODE, file_lksb,
+ LCK$M_VALBLK | LCK$M_CONVERT | LCK$M_NODLCKBLK, NULL, 0, NULL, 0, NULL, PSL$C_USER, 0);
+ else
+ status = gtm_enqw(EFN$C_ENF, LCK$K_NLMODE, file_lksb, LCK$M_VALBLK | LCK$M_CONVERT,
+ NULL, 0, NULL, 0, NULL, PSL$C_USER, 0);
+ if (SS$_NORMAL == status)
+ status = file_lksb->cond;
+ if (SS$_NORMAL != status)
+ rts_error_csa(CSA_ARG(csa) VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(reg), status);
+ }
+ reg->node = node; /* In case MUPIP JOURNAL /RECOVER */
+ if ((TRUE == clustered) && (FALSE == CCP_SEGMENT_STATE(csa->nl, CCST_MASK_OPEN)))
+ {
+ ccp_sendmsg(CCTR_WRITEDB, &gds_info->file_id);
+ ccp_userwait(reg, CCST_MASK_OPEN, &nsd->ccp_response_interval, csa->nl->ccp_cycle);
+ }
+ REVERT;
+ return;
+}
diff --git a/sr_vvms/gvusr_queryget.c b/sr_vvms/gvusr_queryget.c
new file mode 100644
index 0000000..92c723d
--- /dev/null
+++ b/sr_vvms/gvusr_queryget.c
@@ -0,0 +1,47 @@
+/****************************************************************
+ * *
+ * Copyright 2002 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "str2gvkey.h"
+#include "gvusr.h"
+#include "gvusr_queryget.h"
+#include "stringpool.h"
+
+GBLREF gv_key *gv_currkey;
+GBLREF gv_key *gv_altkey;
+
+boolean_t gvusr_queryget(mval *v)
+{ /* this function logically should be in DDPGVUSR, but is now in GTMSHR because the tree of functions called from
+ * str2gvkey_nogvfunc use globals that are currently not setup in DDPGVUSR, and the number of globals makes for nasty problems
+ * in the link */
+
+ /* $Q and $G as separate steps, if $G returns "", loop until $Q returns "" or $Q and $G return non "" */
+
+ for (; ;)
+ {
+ if (gvusr_query(v))
+ {
+ str2gvkey_nogvfunc(v->str.addr, v->str.len, gv_currkey); /* setup gv_currkey from return of query */
+ if (gvusr_get(v))
+ {
+ s2pool(&v->str);
+ return TRUE;
+ }
+ } else
+ return FALSE;
+ }
+}
diff --git a/sr_vvms/ident.h b/sr_vvms/ident.h
new file mode 100644
index 0000000..3b32ff9
--- /dev/null
+++ b/sr_vvms/ident.h
@@ -0,0 +1,12 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#define CONVERT_IDENT(to, from, len) lower_to_upper(to, from, len)
diff --git a/sr_vvms/incr_link.h b/sr_vvms/incr_link.h
new file mode 100644
index 0000000..50d4fc8
--- /dev/null
+++ b/sr_vvms/incr_link.h
@@ -0,0 +1,17 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef INCR_LINK_INCLUDED
+#define INCR_LINK_INCLUDED
+
+bool incr_link(unsigned char *fab, bool libr);
+
+#endif /* INCR_LINK_INCLUDED */
diff --git a/sr_vvms/init_sec.c b/sr_vvms/init_sec.c
new file mode 100644
index 0000000..9f9cdd0
--- /dev/null
+++ b/sr_vvms/init_sec.c
@@ -0,0 +1,38 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <descrip.h>
+#include <prvdef.h>
+#include <psldef.h>
+#include <secdef.h>
+#include <ssdef.h>
+
+#include "gtmsecshr.h"
+
+uint4 init_sec(uint4 *retadr, struct dsc$descriptor_s *gsdnam, uint4 chan, uint4 pagcnt, uint4 flags)
+{
+ uint4 inadr[2], status;
+ uint4 prvadr[2], prvprv[2];
+
+ GTMSECSHR_SET_PRIV((PRV$M_SYSGBL | PRV$M_PRMGBL), status);
+ if (SS$_NORMAL == status)
+ {
+ inadr[0] = retadr[0];
+ inadr[1] = retadr[1];
+ status = sys$crmpsc(inadr, retadr, PSL$C_USER, flags, gsdnam, NULL, 0,
+ flags & SEC$M_PAGFIL ? 0 : chan,
+ pagcnt, 0, 0, 0);
+ GTMSECSHR_REL_PRIV;
+ }
+ return status;
+}
diff --git a/sr_vvms/init_sec.h b/sr_vvms/init_sec.h
new file mode 100644
index 0000000..8885b67
--- /dev/null
+++ b/sr_vvms/init_sec.h
@@ -0,0 +1,17 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef INIT_SEC_INCLUDED
+#define INIT_SEC_INCLUDED
+
+uint4 init_sec(uint4 *retadr, struct dsc$descriptor_s *gsdnam, uint4 chan, uint4 pagcnt, uint4 flags);
+
+#endif /* INIT_SEC_INCLUDED */
diff --git a/sr_vvms/interlock.h b/sr_vvms/interlock.h
new file mode 100644
index 0000000..0934333
--- /dev/null
+++ b/sr_vvms/interlock.h
@@ -0,0 +1,58 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef INTERLOCK_H_INCLUDED
+#define INTERLOCK_H_INCLUDED
+
+#include "lockconst.h"
+#include "compswap.h"
+#include "aswp.h"
+
+/* LATCH_{CLEAR,SET,CONFLICT} need to be in ascending order. wcs_* routines on this ordering for detecting out-of-range values */
+#define LATCH_CLEAR -1
+#define LATCH_SET 0
+#define LATCH_CONFLICT 1
+#define WRITE_LATCH_VAL(cr) (cr)->interlock.semaphore /* this can take either of the above 3 LATCH_* values */
+
+#define INTERLOCK_INIT(X) ((X)->interlock.semaphore = LATCH_CLEAR, (X)->read_in_progress = -1)
+
+#define INTERLOCK_INIT_MM(X) ((X)->interlock.semaphore = LATCH_CLEAR)
+
+#define LOCK_NEW_BUFF_FOR_UPDATE(X) ((X)->interlock.semaphore = LATCH_SET)
+#define LOCK_BUFF_FOR_UPDATE(X, Y, Z) (Y = adawi(1, &(X)->interlock.semaphore))
+#define RELEASE_BUFF_UPDATE_LOCK(X, Y, Z) (Y = adawi(-1, &(X)->interlock.semaphore))
+#define LOCK_BUFF_FOR_WRITE(X, Y) (Y = adawi(1, &(X)->interlock.semaphore))
+#define CLEAR_BUFF_UPDATE_LOCK(X) (adawi(-1, &(X)->interlock.semaphore))
+
+#define LOCK_BUFF_FOR_READ(X, Y) (Y = adawi(1, &(X)->read_in_progress))
+#define RELEASE_BUFF_READ_LOCK(X) (adawi(-1, &(X)->read_in_progress))
+
+#define WRITER_BLOCKED_BY_PROC(X) ((X) >= LATCH_SET)
+#define WRITER_OWNS_BUFF(X) ((X) > LATCH_SET)
+#define WRITER_STILL_OWNS_BUFF(X, Y) (Y = adawi(-1, &(X)->interlock.semaphore), (Y > LATCH_CLEAR))
+#define OWN_BUFF(X) ((X) < LATCH_CONFLICT)
+
+#define ADD_ENT_TO_ACTIVE_QUE_CNT(X, Y) (adawi(1, (X)))
+#define SUB_ENT_FROM_ACTIVE_QUE_CNT(X, Y) (adawi(-1, (X)))
+
+#define INCR_CNT(X, Y) (adawi(1, (X)))
+#define DECR_CNT(X, Y) (adawi(-1, (X)))
+
+#define GET_SWAPLOCK(X) (COMPSWAP_LOCK((X), LOCK_AVAILABLE, 0, process_id, image_count))
+/* 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).
+ */
+#define RELEASE_SWAPLOCK(X) ((COMPSWAP_UNLOCK((X), process_id, image_count, LOCK_AVAILABLE, 0)) ? 1 : (GTMASSERT, 0))
+
+#endif /* INTERLOCK_H_INCLUDED */
diff --git a/sr_vvms/io_get_fgn_driver.c b/sr_vvms/io_get_fgn_driver.c
new file mode 100644
index 0000000..5351b55
--- /dev/null
+++ b/sr_vvms/io_get_fgn_driver.c
@@ -0,0 +1,76 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "io.h"
+#include <descrip.h>
+#include "gtm_caseconv.h"
+
+#define MAX_DRIVER_NAME_LEN 8
+#define PROLOG "GTM$DRIVER$"
+
+struct fgn_driver_list_struct
+{
+ unsigned char name[MAX_DRIVER_NAME_LEN];
+ struct fgn_driver_list_struct *next;
+ dev_dispatch_struct disp_table;
+};
+
+static struct fgn_driver_list_struct *fgn_driver_root = 0;
+
+dev_dispatch_struct *io_get_fgn_driver(mstr *s)
+{
+ struct fgn_driver_list_struct *ptr;
+ unsigned char in_name[MAX_DRIVER_NAME_LEN], *cp;
+ unsigned char image_name[MAX_DRIVER_NAME_LEN + SIZEOF(PROLOG)];
+ int n, nmax;
+ uint4 status;
+ struct dsc$descriptor_s image_name_desc;
+ int4 (*callback)();
+
+ nmax = s->len;
+ if (nmax > MAX_DRIVER_NAME_LEN)
+ nmax = MAX_DRIVER_NAME_LEN;
+ lower_to_upper(in_name, s->addr, nmax);
+ for (n = nmax, cp = &in_name[nmax] ; n < MAX_DRIVER_NAME_LEN ; n++)
+ *cp++ = 0;
+ for (ptr = fgn_driver_root ; ptr ; ptr = ptr->next)
+ {
+ if (memcmp(in_name, ptr->name, SIZEOF(ptr->name)) == 0)
+ return &(ptr->disp_table);
+ }
+ memcpy(image_name, PROLOG, SIZEOF(PROLOG) - 1);
+ memcpy(&image_name[SIZEOF(PROLOG) - 1], in_name, nmax);
+ image_name_desc.dsc$w_length = nmax + SIZEOF(PROLOG) - 1;
+ assert(image_name_desc.dsc$w_length < SIZEOF(image_name));
+ image_name_desc.dsc$b_dtype = DSC$K_DTYPE_T;
+ image_name_desc.dsc$b_class = DSC$K_CLASS_S;
+ image_name_desc.dsc$a_pointer = image_name;
+ status = lib$find_image_symbol(&image_name_desc, & image_name_desc, &callback);
+ if ((status & 1) == 0)
+ {
+ rts_error(VARLSTCNT(1) status);
+ return 0;
+ }
+ ptr = malloc(SIZEOF(*ptr));
+ /* NOTE: SHOULD PROTECT THIS WITH CONDITION HANDLER */
+ status = (*callback)(&(ptr->disp_table));
+ if ((status & 1) == 0)
+ {
+ free(ptr);
+ rts_error(VARLSTCNT(1) status);
+ return 0;
+ }
+ memcpy(ptr->name, in_name, SIZEOF(ptr->name));
+ ptr->next = fgn_driver_root;
+ fgn_driver_root = ptr;
+ return &ptr->disp_table;
+}
diff --git a/sr_vvms/io_init_name.c b/sr_vvms/io_init_name.c
new file mode 100644
index 0000000..9351a56
--- /dev/null
+++ b/sr_vvms/io_init_name.c
@@ -0,0 +1,37 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include "outofband.h"
+#include "io.h"
+#include "gtm_logicals.h"
+
+#define mstr_set_str(x,y) ((x)->addr = (y), (x)->len = SIZEOF(y) - 1)
+
+GBLDEF uint4 std_dev_outofband_msk;
+GBLDEF mstr sys_input;
+GBLDEF mstr sys_output;
+GBLDEF mstr gtm_principal;
+
+void io_init_name(void)
+{
+ uint4 disable_mask;
+
+ disable_mask = CTRLY_MSK ;
+ lib$disable_ctrl(&disable_mask, &std_dev_outofband_msk);
+ std_dev_outofband_msk &= CTRLY_MSK;
+ mstr_set_str(>m_principal, GTM_PRINCIPAL);
+ mstr_set_str(&sys_input,"SYS$INPUT");
+ mstr_set_str(&sys_output ,"SYS$OUTPUT");
+}
diff --git a/sr_vvms/io_is_rm.c b/sr_vvms/io_is_rm.c
new file mode 100644
index 0000000..b0393c1
--- /dev/null
+++ b/sr_vvms/io_is_rm.c
@@ -0,0 +1,23 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include "io.h"
+
+
+bool io_is_rm(mstr *name)
+
+{
+ return(io_type(name) == rm);
+}
diff --git a/sr_vvms/io_is_sn.c b/sr_vvms/io_is_sn.c
new file mode 100644
index 0000000..f5ad0a3
--- /dev/null
+++ b/sr_vvms/io_is_sn.c
@@ -0,0 +1,44 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <ssdef.h>
+#include <dcdef.h>
+#include <devdef.h>
+#include <dvidef.h>
+#include <descrip.h>
+#include "io.h"
+
+/* This module determines whether a vms device is NONLOCAL and therefore a network device, generally sys$net.
+In UNIX, it always returns false. */
+bool io_is_sn(mstr *tn)
+{
+ uint4 devclass; /* device classification information */
+ uint4 devtype; /* device type information */
+ int4 item_code;
+ uint4 stat;
+
+ $DESCRIPTOR(buf_desc,"");
+
+ item_code = DVI$_DEVCLASS;
+
+ buf_desc.dsc$a_pointer = tn->addr;
+ buf_desc.dsc$w_length = tn->len;
+ stat = lib$getdvi(&item_code
+ ,0
+ ,&buf_desc
+ ,&devclass
+ ,0 , 0);
+ if (stat == SS$_NONLOCAL)
+ return TRUE;
+ else
+ return FALSE;
+}
diff --git a/sr_vvms/io_open_try.c b/sr_vvms/io_open_try.c
new file mode 100644
index 0000000..f4cf697
--- /dev/null
+++ b/sr_vvms/io_open_try.c
@@ -0,0 +1,154 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include "gt_timer.h"
+#include "io.h"
+#include "iotimer.h"
+#include "io_params.h"
+#include "io_dev_dispatch.h"
+#include "gtm_caseconv.h"
+#include "outofband.h"
+#include "gtmimagename.h"
+
+LITREF dev_dispatch_struct io_dev_dispatch[];
+LITREF unsigned char io_params_size[];
+GBLREF int4 outofband;
+GBLREF int4 write_filter;
+GBLREF io_desc *active_device;
+
+bool io_open_try(io_log_name *naml, io_log_name *tl, mval *pp, int4 timeout, mval *mspace)
+{
+ char buf1[MAX_TRANS_NAME_LEN]; /* buffer to hold translated name */
+ char dev_type[MAX_DEV_TYPE_LEN];
+ int n;
+ mstr tn; /* translated name */
+ uint4 stat; /* status */
+ int p_offset;
+ unsigned char ch;
+ ABS_TIME cur_time, end_time;
+ bool out_of_time = FALSE;
+
+ if (0 == naml->iod)
+ {
+ if (0 == tl->iod)
+ {
+ tl->iod = (io_desc *)malloc(SIZEOF(io_desc));
+ memset((char*)tl->iod, 0, SIZEOF(io_desc));
+ tl->iod->pair.in = tl->iod;
+ tl->iod->pair.out = tl->iod;
+ tl->iod->trans_name = tl;
+ p_offset = 0;
+ while (iop_eol != *(pp->str.addr + p_offset))
+ {
+ if ((iop_tmpmbx == (ch = *(pp->str.addr + p_offset++))) || (iop_prmmbx == ch))
+ tl->iod->type = mb;
+ else if (iop_nl == ch)
+ tl->iod->type = nl;
+ p_offset += ((IOP_VAR_SIZE == io_params_size[ch]) ?
+ (unsigned char)*(pp->str.addr + p_offset) + 1 : io_params_size[ch]);
+ }
+ if (!tl->iod->type && mspace && mspace->str.len)
+ {
+ lower_to_upper(dev_type, mspace->str.addr, mspace->str.len);
+ if (((SIZEOF("TCP") - 1) == mspace->str.len)
+ && (0 == memcmp(dev_type, LIT_AND_LEN("TCP"))))
+ tl->iod->type = tcp;
+ else if (((SIZEOF("SOCKET") - 1) == mspace->str.len)
+ && (0 == memcmp(dev_type, LIT_AND_LEN("SOCKET"))))
+ tl->iod->type = gtmsocket;
+ else
+ tl->iod->type = us;
+ }
+ if (!tl->iod->type)
+ {
+ tn.len = tl->len;
+ tn.addr = &tl->dollar_io;
+ tl->iod->type = io_type(&tn);
+ }
+ }
+ naml->iod = tl->iod;
+ }
+ tl->iod->disp_ptr = &io_dev_dispatch[tl->iod->type];
+ assert(0 != naml->iod);
+ active_device = naml->iod;
+ if (dev_never_opened == naml->iod->state)
+ {
+ naml->iod->wrap = DEFAULT_IOD_WRAP;
+ naml->iod->width = DEFAULT_IOD_WIDTH;
+ naml->iod->length = DEFAULT_IOD_LENGTH;
+ naml->iod->write_filter = write_filter;
+ }
+ if (dev_open != naml->iod->state)
+ {
+ naml->iod->dollar.x = 0;
+ naml->iod->dollar.y = 0;
+ naml->iod->dollar.za = 0;
+ naml->iod->dollar.zb[0] = 0;
+ naml->iod->dollar.zeof = FALSE;
+ }
+ if (0 == timeout)
+ stat = (naml->iod->disp_ptr->open)(naml, pp, -1, mspace, timeout); /* ZY: add a parameter timeout */
+ else if (NO_M_TIMEOUT == timeout)
+ {
+ while (FALSE == (stat = (naml->iod->disp_ptr->open)(naml, pp, -1, mspace, timeout))) /* ZY: add timeout */
+ {
+ hiber_start(1000); /* 1 second */
+ if (outofband)
+ outofband_action(FALSE);
+ }
+ } else
+ {
+ sys_get_curr_time(&cur_time);
+ add_int_to_abs_time(&cur_time, timeout * 1000, &end_time);
+ while (FALSE == (stat = (naml->iod->disp_ptr->open)(naml, pp, -1, mspace, timeout)) /* ZY: add timeout */
+ && (!out_of_time))
+ {
+ hiber_start(1000); /* 1 second */
+ if (outofband)
+ outofband_action(FALSE);
+ sys_get_curr_time(&cur_time);
+ if (abs_time_comp(&end_time, &cur_time) <= 0)
+ out_of_time = TRUE;
+ }
+ }
+ if (TRUE == stat)
+ {
+ naml->iod->state = dev_open;
+ if (27 == naml->iod->trans_name->dollar_io[0])
+ {
+ tn.addr = &naml->iod->trans_name->dollar_io[4];
+ n = naml->iod->trans_name->len - 4;
+ if (n < 0)
+ n = 0;
+ tn.len = n;
+ naml->iod->trans_name = get_log_name(&tn, INSERT);
+ naml->iod->trans_name->iod = naml->iod;
+ }
+ }
+ else
+ {
+ if (dev_open == naml->iod->state && (gtmsocket != naml->iod->type))
+ naml->iod->state = dev_closed;
+ else if ((gtmsocket == naml->iod->type) && naml->iod->newly_created)
+ {
+ assert(naml->iod->state != dev_open);
+ iosocket_destroy(naml->iod);
+ }
+ }
+ active_device = 0;
+ if ((NO_M_TIMEOUT != timeout) && IS_MCODE_RUNNING)
+ return (stat);
+ return FALSE;
+}
diff --git a/sr_vvms/io_type.c b/sr_vvms/io_type.c
new file mode 100644
index 0000000..83f920f
--- /dev/null
+++ b/sr_vvms/io_type.c
@@ -0,0 +1,98 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2004 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <ssdef.h>
+#include <dcdef.h>
+#include <devdef.h>
+#include <dvidef.h>
+#include "gtm_limits.h"
+#include "io.h"
+#include <descrip.h>
+
+enum io_dev_type io_type(mstr *tn)
+{
+ enum io_dev_type type;
+ uint4 devchar; /* device characteristics information */
+ uint4 devclass; /* device classification information */
+ uint4 devtype; /* device type information */
+ int4 item_code;
+ uint4 stat;
+ error_def(ERR_INVSTRLEN);
+
+ $DESCRIPTOR(buf_desc,"");
+
+ if (SHRT_MAX < tn->len)
+ rts_error(VARLSTCNT(4) ERR_INVSTRLEN, 2, tn->len, SHRT_MAX);
+ item_code = DVI$_DEVCLASS;
+ buf_desc.dsc$a_pointer = tn->addr;
+ buf_desc.dsc$w_length = tn->len;
+ stat = lib$getdvi(&item_code
+ ,0
+ ,&buf_desc
+ ,&devclass
+ ,0 , 0);
+ if (stat == SS$_NOSUCHDEV || stat == SS$_IVDEVNAM)
+ { type = rm;
+ }
+ else if (stat == SS$_NORMAL)
+ {
+ item_code = DVI$_DEVCHAR;
+ stat = lib$getdvi(&item_code
+ ,0
+ ,&buf_desc
+ ,&devchar
+ ,0 , 0);
+ if (stat != SS$_NORMAL && stat != SS$_NONLOCAL)
+ { rts_error(VARLSTCNT(1) stat );
+ }
+ switch(devclass)
+ {
+ case DC$_TAPE:
+ if (devchar & DEV$M_FOR)
+ { type = mt;
+ }
+ else
+ { type = rm;
+ }
+ break;
+ case DC$_TERM:
+ type = tt;
+ break;
+ case DC$_MAILBOX:
+ item_code = DVI$_DEVTYPE;
+ stat = lib$getdvi(&item_code
+ ,0
+ ,&buf_desc
+ ,&devtype
+ ,0 , 0);
+ if (stat != SS$_NORMAL)
+ { rts_error(VARLSTCNT(1) stat );
+ }
+ if (devtype == DT$_NULL)
+ type = nl;
+ else
+ type = mb;
+ break;
+ case DC$_DISK:
+ default:
+ type = rm;
+ break;
+ }
+ }
+ else if (stat == SS$_NONLOCAL)
+ {
+ type = rm;
+ }else
+ { rts_error(VARLSTCNT(1) stat);
+ }
+ return type;
+}
diff --git a/sr_vvms/ioff_open.c b/sr_vvms/ioff_open.c
new file mode 100644
index 0000000..d76e8ed
--- /dev/null
+++ b/sr_vvms/ioff_open.c
@@ -0,0 +1,19 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+/* STUB file for VMS */
+
+void ioff_open()
+{
+ return;
+}
diff --git a/sr_vvms/iomb_cancel_read.c b/sr_vvms/iomb_cancel_read.c
new file mode 100644
index 0000000..f990671
--- /dev/null
+++ b/sr_vvms/iomb_cancel_read.c
@@ -0,0 +1,34 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <ssdef.h>
+#include "efn.h"
+#include "io.h"
+#include "iombdef.h"
+
+void iomb_cancel_read(mb_ptr)
+d_mb_struct *mb_ptr;
+{
+ uint4 status;
+
+ if (!mb_ptr->stat_blk.status)
+ {
+#ifdef DEBUG
+/* this is for an assert that verifies a reliance on VMS IOSB maintenance */
+ mb_ptr->timer_on = FALSE;
+#endif
+ status = sys$cancel(mb_ptr->channel);
+ if (status != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+ }
+ return;
+}
diff --git a/sr_vvms/iomb_close.c b/sr_vvms/iomb_close.c
new file mode 100644
index 0000000..2474557
--- /dev/null
+++ b/sr_vvms/iomb_close.c
@@ -0,0 +1,55 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <ssdef.h>
+#include "io.h"
+#include "iombdef.h"
+#include "io_params.h"
+#include "stringpool.h"
+
+LITREF unsigned char io_params_size[];
+
+void iomb_close(io_desc *device, mval *pp)
+{
+ unsigned char ch;
+ uint4 status;
+ d_mb_struct *mb_ptr;
+ int p_offset;
+
+ if (device->state == dev_open)
+ {
+ p_offset = 0;
+ mb_ptr = (d_mb_struct *)device->dev_sp;
+ while ((ch = *(pp->str.addr + p_offset++)) != iop_eol)
+ {
+ if (ch == iop_delete)
+ {
+ if ((status = sys$delmbx(mb_ptr->channel)) != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+ }
+ if (ch == iop_exception)
+ {
+ device->error_handler.len = *(pp->str.addr + p_offset);
+ device->error_handler.addr = (char *)(pp->str.addr + p_offset + 1);
+ s2pool(&device->error_handler);
+ }
+ p_offset += ((IOP_VAR_SIZE == io_params_size[ch]) ?
+ (unsigned char)*(pp->str.addr + p_offset) + 1 : io_params_size[ch]);
+ }
+ if (status = sys$dassgn(mb_ptr->channel) != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+ device->state = dev_closed;
+ if (mb_ptr->inbuf != 0)
+ free(mb_ptr->inbuf);
+ }
+ return;
+}
diff --git a/sr_vvms/iomb_dataread.c b/sr_vvms/iomb_dataread.c
new file mode 100644
index 0000000..860b27a
--- /dev/null
+++ b/sr_vvms/iomb_dataread.c
@@ -0,0 +1,134 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <iodef.h>
+#include <ssdef.h>
+
+#include "efn.h"
+#include "io.h"
+#include "iombdef.h"
+#include "iotimer.h"
+#include "timedef.h"
+#include "outofband.h"
+
+#define SHFT_MSK 0x00000001
+#define TIMER_FLAGS 0
+
+GBLREF io_pair io_curr_device;
+GBLREF int4 outofband;
+
+int iomb_dataread(int4 timeout)
+{
+ bool timed;
+ uint4 efn_mask, status, temp_read_mask, time[2];
+ io_desc *io_ptr;
+ d_mb_struct *mb_ptr;
+
+ error_def(ERR_MBXWRTONLY);
+ error_def(ERR_IOEOF);
+
+ io_ptr = io_curr_device.in;
+ assert(dev_open == io_ptr->state);
+ io_ptr->dollar.zeof = FALSE;
+ mb_ptr = (d_mb_struct *)io_ptr->dev_sp;
+ if (IO_SEQ_WRT == mb_ptr->promsk)
+ rts_error(VARLSTCNT(1) ERR_MBXWRTONLY);
+ mb_ptr->in_pos = mb_ptr->in_top = mb_ptr->inbuf;
+ temp_read_mask = mb_ptr->read_mask;
+#ifdef DEBUG
+/* this is for an assert that verifies a reliance on VMS IOSB maintenance */
+ mb_ptr->timer_on = TRUE;
+#endif
+ mb_ptr->stat_blk.status = 0;
+ efn_mask = (SHFT_MSK << efn_immed_wait | SHFT_MSK << efn_outofband);
+ if ((NO_M_TIMEOUT == timeout) || !timeout)
+ {
+ timed = FALSE;
+ if (!timeout)
+ temp_read_mask |= IO$M_NOW;
+ } else
+ {
+ timed = TRUE;
+ time[0] = -time_low(timeout);
+ time[1] = -time_high(timeout) - 1;
+ efn_mask |= SHFT_MSK << efn_timer;
+ status = sys$setimr(efn_timer, &time, iomb_cancel_read, mb_ptr, TIMER_FLAGS);
+ if (SS$_NORMAL != status)
+ rts_error(VARLSTCNT(1) status);
+ }
+ status = sys$qio(efn_immed_wait, mb_ptr->channel
+ ,temp_read_mask, &mb_ptr->stat_blk
+ ,NULL, 0
+ ,mb_ptr->inbuf, mb_ptr->maxmsg
+ ,0, 0, 0, 0);
+ if (SS$_NORMAL != status)
+ rts_error(VARLSTCNT(1) status);
+ status = sys$wflor(efn_immed_wait, efn_mask);
+ if (SS$_NORMAL != status)
+ rts_error(VARLSTCNT(1) status);
+ if (timed)
+ {
+ status = sys$cantim(mb_ptr, 0);
+ if (SS$_NORMAL != status)
+ rts_error(VARLSTCNT(1) status);
+ }
+ if (!mb_ptr->stat_blk.status)
+ {
+ if (outofband)
+ {
+ status = sys$dclast(iomb_cancel_read, mb_ptr, 0);
+ if (SS$_NORMAL != status)
+ rts_error(VARLSTCNT(1) status);
+ }
+ status = sys$synch(efn_immed_wait, &mb_ptr->stat_blk);
+ if (SS$_NORMAL != status)
+ rts_error(VARLSTCNT(1) status);
+ }
+ if (outofband)
+ {
+ outofband_action(FALSE);
+ assert(FALSE);
+ }
+ io_ptr->dollar.za = 0;
+ switch(mb_ptr->stat_blk.status)
+ {
+ case SS$_BUFFEROVF:
+ /* io_ptr->dollar.za = 1; * data mangled * this error information is currently discarded */
+ case SS$_NORMAL:
+ assert(mb_ptr->stat_blk.char_ct <= mb_ptr->maxmsg);
+ if ((0 == timeout) && !mb_ptr->stat_blk.char_ct)
+ return FALSE;
+ mb_ptr->in_top = mb_ptr->inbuf + mb_ptr->stat_blk.char_ct;
+ io_ptr->dollar.za = (short)mb_ptr->stat_blk.pid; /* $za is too small to hold the full VMS pid */
+ return TRUE;
+ break;
+ case SS$_ABORT:
+ case SS$_CANCEL:
+ assert(!mb_ptr->timer_on);
+ return FALSE;
+ break;
+ case SS$_ENDOFFILE:
+ io_ptr->dollar.za = (short)mb_ptr->stat_blk.pid; /* $za is too small to hold the full VMS pid */
+ if (!io_ptr->dollar.za)
+ return FALSE;
+ io_ptr->dollar.zeof = TRUE;
+ if (io_ptr->error_handler.len > 0)
+ rts_error(VARLSTCNT(1) ERR_IOEOF);
+ return TRUE;
+ break;
+ default: /* NOREADER and NOWRITER are currently unsolicited */
+ if (!mb_ptr->stat_blk.status)
+ GTMASSERT;
+ rts_error(VARLSTCNT(1) mb_ptr->stat_blk.status);
+ }
+}
diff --git a/sr_vvms/iomb_dummy.c b/sr_vvms/iomb_dummy.c
new file mode 100644
index 0000000..334e611
--- /dev/null
+++ b/sr_vvms/iomb_dummy.c
@@ -0,0 +1,18 @@
+/****************************************************************
+ * *
+ * Copyright 2011 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "io.h"
+
+short iomb_dummy(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 timeout)
+{
+ return 0;
+}
diff --git a/sr_vvms/iomb_flush.c b/sr_vvms/iomb_flush.c
new file mode 100644
index 0000000..f756204
--- /dev/null
+++ b/sr_vvms/iomb_flush.c
@@ -0,0 +1,18 @@
+/****************************************************************
+ * *
+ * Copyright 2011 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "io.h"
+
+void iomb_flush(io_desc *iod)
+{
+ return;
+}
diff --git a/sr_vvms/iomb_open.c b/sr_vvms/iomb_open.c
new file mode 100644
index 0000000..09e2c04
--- /dev/null
+++ b/sr_vvms/iomb_open.c
@@ -0,0 +1,188 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include <descrip.h>
+#include <dcdef.h>
+#include <dvidef.h>
+#include <iodef.h>
+#include <jpidef.h>
+#include <ssdef.h>
+#include <efndef.h>
+
+
+#include "io.h"
+#include "io_params.h"
+#include "iombdef.h"
+#include "vmsdtype.h"
+#include "stringpool.h"
+#include "trans_log_name.h"
+#include "copy.h"
+
+#define MBX_FUNC_R (IO$_READVBLK)
+#define MBX_FUNC_W (IO$_WRITEVBLK | IO$M_NOW)
+#define TERM_READ_MIN_BCOUNT 1037
+#define MBX_BCOUNT 1200
+#define UCB$V_PRMMBX 0 /* from $UCBDEF macro */
+
+LITREF unsigned char io_params_size[];
+
+short iomb_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 timeout)
+{
+ bool create;
+ unsigned char buf1[MAX_TRANS_NAME_LEN];
+ short buf_ret, cls_ret, return_length, sts_ret;
+ int4 byte_count, blocksize;
+ uint4 devbuf, devclass, devsts, status;
+ int p_offset;
+ d_mb_struct *mb_ptr;
+ io_desc *ioptr;
+ io_log_name *tl;
+ mstr v, tn;
+ params ch;
+ struct dsc$descriptor lognam;
+ struct {
+ item_list_3 item;
+ int4 terminator;
+ } getjpi_item_list = {4, JPI$_BYTCNT, &byte_count, &return_length, 0};
+ struct {
+ item_list_3 item[3];
+ int4 terminator;
+ } getdvi_item_list = {4, DVI$_DEVSTS, &devsts, &sts_ret,
+ 4, DVI$_DEVCLASS, &devclass, &cls_ret,
+ 4, DVI$_DEVBUFSIZ, &devbuf, &buf_ret,
+ 0};
+
+ error_def(ERR_INSFFBCNT);
+ error_def(ERR_DEVPARMNEG);
+
+ p_offset = 0;
+ ioptr = dev_name->iod;
+ if (ioptr->state == dev_never_opened)
+ {
+ ioptr->dev_sp = (d_mb_struct *)(malloc(SIZEOF(d_mb_struct)));
+ mb_ptr = (d_mb_struct *)ioptr->dev_sp;
+ mb_ptr->maxmsg = DEF_MB_MAXMSG;
+ mb_ptr->promsk = 0;
+ mb_ptr->del_on_close = FALSE;
+ mb_ptr->prmflg = 0;
+ mb_ptr->read_mask = MBX_FUNC_R;
+ mb_ptr->write_mask = MBX_FUNC_W;
+ ioptr->state = dev_closed;
+ }
+ mb_ptr = (d_mb_struct *)ioptr->dev_sp;
+ if (ioptr->state != dev_open)
+ {
+ status = sys$getjpiw(EFN$C_ENF, 0, 0, &getjpi_item_list, 0, 0, 0);
+ if (status != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+ if (byte_count < TERM_READ_MIN_BCOUNT + MBX_BCOUNT)
+ rts_error(VARLSTCNT(1) ERR_INSFFBCNT);
+ lognam.dsc$w_length = (unsigned short)dev_name->len;
+ lognam.dsc$b_dtype = DSC$K_DTYPE_T;
+ lognam.dsc$b_class = DSC$K_CLASS_S;
+ lognam.dsc$a_pointer = dev_name->dollar_io;
+ create = TRUE;
+ status = sys$getdviw(EFN$C_ENF, 0, &lognam, &getdvi_item_list,
+ 0, 0, 0, 0);
+ if ((status == SS$_NORMAL) && (devclass == DC$_MAILBOX))
+ create = FALSE;
+ while ((ch = *(pp->str.addr + p_offset++)) != iop_eol)
+ {
+ switch(ch)
+ {
+ case iop_blocksize:
+ GET_LONG(blocksize, pp->str.addr + p_offset);
+ if (blocksize < 0)
+ rts_error(VARLSTCNT(1) ERR_DEVPARMNEG);
+ mb_ptr->maxmsg = blocksize;
+ break;
+ case iop_delete:
+ mb_ptr->del_on_close = TRUE;
+ break;
+ case iop_readonly:
+ mb_ptr->promsk = IO_RD_ONLY;
+ break;
+ case iop_noreadonly:
+ mb_ptr->promsk &= ~IO_RD_ONLY;
+ break;
+ case iop_writeonly:
+ mb_ptr->promsk = IO_SEQ_WRT;
+ break;
+ case iop_nowriteonly:
+ mb_ptr->promsk &= ~IO_SEQ_WRT;
+ break;
+ case iop_prmmbx:
+ mb_ptr->prmflg = 1;
+ break;
+ case iop_tmpmbx:
+ mb_ptr->prmflg = 0;
+ break;
+ case iop_exception:
+ ioptr->error_handler.len = *(pp->str.addr + p_offset);
+ ioptr->error_handler.addr = pp->str.addr + p_offset + 1;
+ s2pool(&ioptr->error_handler);
+ break;
+ default:
+ break;
+ }
+ p_offset += ((IOP_VAR_SIZE == io_params_size[ch]) ?
+ (unsigned char)*(pp->str.addr + p_offset) + 1 : io_params_size[ch]);
+ }
+ if (create)
+ status = sys$crembx(mb_ptr->prmflg
+ ,&(mb_ptr->channel)
+ ,mb_ptr->maxmsg
+ ,mb_ptr->maxmsg
+ ,mb_ptr->promsk
+ ,0
+ ,&lognam);
+ else
+ {
+ status = sys$assign(&lognam, &(mb_ptr->channel), 0, 0);
+ mb_ptr->maxmsg = devbuf;
+ mb_ptr->prmflg = (devsts >> UCB$V_PRMMBX) & 1;
+ }
+ switch(status)
+ {
+ case SS$_NORMAL:
+ v.addr = lognam.dsc$a_pointer;
+ v.len = lognam.dsc$w_length;
+ if ((status = trans_log_name(&v, &tn, buf1)) != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+ tl = get_log_name(&tn, INSERT);
+ tl->iod = dev_name->iod;
+ tl->iod->trans_name = tl;
+ break;
+ case SS$_EXBYTLM:
+ case SS$_EXPORTQUOTA:
+ case SS$_INSFMEM:
+ case SS$_INTERLOCK:
+ case SS$_NOIOCHAN:
+ return FALSE;
+ default:
+ rts_error(VARLSTCNT(1) status);
+ }
+ ioptr->width = mb_ptr->maxmsg;
+ if (mb_ptr->prmflg && mb_ptr->del_on_close)
+ {
+ if ((status = sys$delmbx(mb_ptr->channel)) != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+ }
+ mb_ptr->in_pos = mb_ptr->in_top = mb_ptr->inbuf = malloc(ioptr->width);
+ ioptr->length = DEF_MB_LENGTH;
+ ioptr->state = dev_open;
+ }
+ return TRUE;
+}
diff --git a/sr_vvms/iomb_rdone.c b/sr_vvms/iomb_rdone.c
new file mode 100644
index 0000000..ff25d78
--- /dev/null
+++ b/sr_vvms/iomb_rdone.c
@@ -0,0 +1,55 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2006 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <iodef.h>
+#include "io.h"
+#include "iombdef.h"
+
+GBLREF io_pair io_curr_device;
+
+int iomb_rdone(mint *v,int4 t)
+{
+ short not_timed_out;
+ io_desc *io_ptr;
+ d_mb_struct *mb_ptr;
+
+ io_ptr = io_curr_device.in;
+ assert (io_ptr->state == dev_open);
+ mb_ptr = (d_mb_struct *) io_ptr->dev_sp;
+
+ if (mb_ptr->in_top == mb_ptr->in_pos)
+ not_timed_out = iomb_dataread(t);
+ else
+ not_timed_out = TRUE;
+
+ if (not_timed_out && (mb_ptr->in_top != mb_ptr->in_pos))
+ {
+ *v = *mb_ptr->in_pos++;
+ if ((++io_ptr->dollar.x > io_ptr->width) && io_ptr->wrap)
+ {
+ io_ptr->dollar.y += (io_ptr->dollar.x / io_ptr->width);
+ if(io_ptr->length)
+ io_ptr->dollar.y %= io_ptr->length;
+ io_ptr->dollar.x %= io_ptr->width;
+ }
+ } else
+ {
+ *v = -1;
+ if (io_ptr->dollar.zeof)
+ {
+ io_ptr->dollar.x = 0;
+ io_ptr->dollar.y++;
+ }
+ }
+
+ return not_timed_out;
+}
diff --git a/sr_vvms/iomb_read.c b/sr_vvms/iomb_read.c
new file mode 100644
index 0000000..81e45fa
--- /dev/null
+++ b/sr_vvms/iomb_read.c
@@ -0,0 +1,57 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include <iodef.h>
+#include "io.h"
+#include "iombdef.h"
+#include "stringpool.h"
+
+GBLREF io_pair io_curr_device;
+GBLREF spdesc stringpool;
+
+int iomb_read(mval *v, int4 t)
+{
+ short not_timed_out;
+ io_desc *io_ptr;
+ d_mb_struct *mb_ptr;
+
+ io_ptr = io_curr_device.in;
+ assert (io_ptr->state == dev_open);
+ mb_ptr = (d_mb_struct *) io_ptr->dev_sp;
+
+ assert(stringpool.free >= stringpool.base);
+ assert(stringpool.free <= stringpool.top);
+ ENSURE_STP_FREE_SPACE(mb_ptr->maxmsg);
+ v->str.addr = stringpool.free;
+
+ if (mb_ptr->in_top == mb_ptr->in_pos)
+ not_timed_out = iomb_dataread(t);
+ else
+ not_timed_out = TRUE;
+
+ memcpy(v->str.addr,mb_ptr->in_pos,(v->str.len = mb_ptr->in_top - mb_ptr->in_pos));
+ mb_ptr->in_pos = mb_ptr->in_top = mb_ptr->inbuf;
+
+ if (io_ptr->wrap && ((io_ptr->dollar.x += v->str.len) > io_ptr->width))
+ {
+ io_ptr->dollar.y += (io_ptr->dollar.x / io_ptr->width);
+ if(io_ptr->length)
+ io_ptr->dollar.y %= io_ptr->length;
+ io_ptr->dollar.x %= io_ptr->width;
+ }
+ io_ptr->dollar.x = 0;
+ io_ptr->dollar.y++;
+ return not_timed_out;
+}
diff --git a/sr_vvms/iomb_readfl.c b/sr_vvms/iomb_readfl.c
new file mode 100644
index 0000000..39c6043
--- /dev/null
+++ b/sr_vvms/iomb_readfl.c
@@ -0,0 +1,59 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2006 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include <iodef.h>
+#include "io.h"
+#include "iombdef.h"
+
+GBLREF io_pair io_curr_device;
+
+int iomb_readfl(mval *v,int4 length,int4 t)
+{
+ int not_timed_out;
+ int len;
+ io_desc *io_ptr;
+ d_mb_struct *mb_ptr;
+
+ io_ptr = io_curr_device.in;
+ assert (io_ptr->state == dev_open);
+ mb_ptr = (d_mb_struct *) io_ptr->dev_sp;
+
+ if (mb_ptr->in_top == mb_ptr->in_pos)
+ not_timed_out = iomb_dataread(t);
+ else
+ not_timed_out = TRUE;
+
+ if ((len = mb_ptr->in_top - mb_ptr->in_pos) > length)
+ len = length;
+
+ memcpy(v->str.addr,mb_ptr->in_pos,len);
+ v->str.len = len;
+ mb_ptr->in_pos += len;
+ if (io_ptr->dollar.zeof)
+ {
+ io_ptr->dollar.x = 0;
+ io_ptr->dollar.y++;
+ }else
+ {
+ if ((io_ptr->dollar.x += len) > io_ptr->width && io_ptr->wrap)
+ {
+ io_ptr->dollar.y += (io_ptr->dollar.x / io_ptr->width);
+ if(io_ptr->length)
+ io_ptr->dollar.y %= io_ptr->length;
+ io_ptr->dollar.x %= io_ptr->width;
+ }
+ }
+ return not_timed_out;
+}
diff --git a/sr_vvms/iomb_use.c b/sr_vvms/iomb_use.c
new file mode 100644
index 0000000..6d68499
--- /dev/null
+++ b/sr_vvms/iomb_use.c
@@ -0,0 +1,104 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2004 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include <iodef.h>
+#include <ssdef.h>
+#include <efndef.h>
+
+#include "io.h"
+#include "io_params.h"
+#include "iombdef.h"
+#include "compiler.h"
+#include "stringpool.h"
+#include "copy.h"
+
+LITREF unsigned char io_params_size[];
+
+void iomb_use(io_desc *iod, mval *pp)
+{
+ int4 length, width;
+ uint4 status;
+ d_mb_struct *mb_ptr;
+ params ch;
+ int p_offset;
+
+ error_def(ERR_DEVPARMNEG);
+
+ p_offset = 0;
+ iomb_flush(iod);
+ mb_ptr = (d_mb_struct *)iod->dev_sp;
+ while ((ch = *(pp->str.addr + p_offset++)) != iop_eol)
+ {
+ switch (ch)
+ {
+ case iop_writeof:
+ status = sys$qiow(EFN$C_ENF, mb_ptr->channel
+ ,IO$_WRITEOF | IO$M_NOW, &mb_ptr->stat_blk
+ ,NULL, 0
+ ,0 ,0, 0, 0, 0, 0);
+ if (status != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+ break;
+ case iop_delete:
+ if (mb_ptr->prmflg && mb_ptr->del_on_close)
+ {
+ if ((status = sys$delmbx(mb_ptr->channel)) != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+ }
+ break;
+ case iop_exception:
+ iod->error_handler.len = *(pp->str.addr + p_offset);
+ iod->error_handler.addr = pp->str.addr + p_offset + 1;
+ s2pool(&iod->error_handler);
+ break;
+ case iop_length:
+ GET_LONG(length, pp->str.addr + p_offset);
+ if (length < 0)
+ rts_error(VARLSTCNT(1) ERR_DEVPARMNEG);
+ iod->length = length;
+ break;
+ case iop_wait:
+ mb_ptr->write_mask &= ~IO$M_NOW;
+ break;
+ case iop_nowait:
+ mb_ptr->write_mask |= IO$M_NOW;
+ break;
+ case iop_width:
+ GET_LONG(width, pp->str.addr + p_offset);
+ if (width < 0)
+ rts_error(VARLSTCNT(1) ERR_DEVPARMNEG);
+ if (width == 0)
+ {
+ iod->wrap = FALSE;
+ iod->width = mb_ptr->maxmsg;
+ } else
+ {
+ iod->width = width;
+ iod->wrap = TRUE;
+ }
+ break;
+ case iop_wrap:
+ iod->wrap = TRUE;
+ break;
+ case iop_nowrap:
+ iod->wrap = FALSE;
+ break;
+ default:
+ break;
+ }
+ p_offset += ((IOP_VAR_SIZE == io_params_size[ch]) ?
+ (unsigned char)*(pp->str.addr + p_offset) + 1 : io_params_size[ch]);
+ }
+}
diff --git a/sr_vvms/iomb_write.c b/sr_vvms/iomb_write.c
new file mode 100644
index 0000000..4365db0
--- /dev/null
+++ b/sr_vvms/iomb_write.c
@@ -0,0 +1,82 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2004 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <ssdef.h>
+#include <iodef.h>
+#include "efn.h"
+#include "io.h"
+#include "iombdef.h"
+#include "outofband.h"
+
+#define SHFT_MSK 0x00000001
+
+GBLREF int4 outofband;
+GBLREF io_pair io_curr_device;
+
+void iomb_write(mstr *v)
+{
+ unsigned char *ch;
+ int len, out_len;
+ uint4 status, efn_mask;
+ d_mb_struct *mb_ptr;
+ mb_iosb stat_blk;
+ error_def(ERR_MBXRDONLY);
+
+ mb_ptr = (d_mb_struct *)io_curr_device.out->dev_sp;
+ if (mb_ptr->promsk == IO_RD_ONLY)
+ rts_error(VARLSTCNT(1) ERR_MBXRDONLY);
+
+ efn_mask = (SHFT_MSK << efn_immed_wait | SHFT_MSK << efn_outofband);
+ for (ch = v->addr, len = v->len ; ; )
+ { if (len > mb_ptr->maxmsg)
+ out_len = mb_ptr->maxmsg;
+ else
+ out_len = len;
+ status = sys$qio(efn_immed_wait ,mb_ptr->channel
+ ,mb_ptr->write_mask ,&stat_blk
+ ,NULL,0
+ ,ch ,out_len ,0 ,0 ,0 ,0);
+ if (status != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+
+ status = sys$wflor(efn_immed_wait,efn_mask);
+ if (status != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+
+ if (outofband)
+ {
+ status = sys$cancel(mb_ptr->channel);
+ if (status != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+ status = sys$synch(efn_immed_wait, &stat_blk);
+ if (status != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+ assert(stat_blk.status == SS$_CANCEL || stat_blk.status == SS$_ABORT);
+ outofband_action(FALSE);
+ assert(FALSE);
+ }
+
+ if (stat_blk.status != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+
+ if ((len -= out_len) == 0)
+ break;
+ ch += out_len;
+ }
+ if ((io_curr_device.out->dollar.x += v->len) > io_curr_device.out->width && io_curr_device.out->wrap)
+ {
+ io_curr_device.out->dollar.y += (io_curr_device.out->dollar.x / io_curr_device.out->width);
+ if (io_curr_device.out->length)
+ io_curr_device.out->dollar.y %= io_curr_device.out->length;
+ io_curr_device.out->dollar.x %= io_curr_device.out->width;
+ }
+}
diff --git a/sr_vvms/iomb_wteol.c b/sr_vvms/iomb_wteol.c
new file mode 100644
index 0000000..cc80657
--- /dev/null
+++ b/sr_vvms/iomb_wteol.c
@@ -0,0 +1,35 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2004 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "io.h"
+
+void iomb_wteol(int4 v, io_desc *iod)
+{
+ mstr temp;
+ int4 s;
+ char ptr[2];
+
+ temp.len = 2;
+ ptr[0] = '\15';
+ ptr[1] = '\12';
+ temp.addr = ptr;
+ for (s = 0; s++ < v ; )
+ {
+ iod->dollar.x -= 2;
+ iomb_write(&temp);
+ }
+ iod->dollar.x = 0;
+ iod->dollar.y += v;
+ if(iod->length)
+ iod->dollar.y %= iod->length;
+ return;
+}
diff --git a/sr_vvms/iomb_wtff.c b/sr_vvms/iomb_wtff.c
new file mode 100644
index 0000000..d8b1077
--- /dev/null
+++ b/sr_vvms/iomb_wtff.c
@@ -0,0 +1,29 @@
+/****************************************************************
+ * *
+ * Copyright 2011 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "io.h"
+
+GBLREF io_pair io_curr_device;
+
+void iomb_wtff(void)
+{
+ mstr temp;
+ char p[1];
+
+ p[0] = '\14';
+ temp.len = 1;
+ temp.addr = p;
+ iomb_write(&temp);
+ io_curr_device.out->dollar.x = 0;
+ io_curr_device.out->dollar.y = 0;
+ return;
+}
diff --git a/sr_vvms/iomb_wtone.c b/sr_vvms/iomb_wtone.c
new file mode 100644
index 0000000..57baf98
--- /dev/null
+++ b/sr_vvms/iomb_wtone.c
@@ -0,0 +1,25 @@
+/****************************************************************
+ * *
+ * Copyright 2011 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "io.h"
+
+void iomb_wtone(int v)
+{
+ mstr temp;
+ char p[1];
+
+ p[0] = (char)v;
+ temp.len = 1;
+ temp.addr = p;
+ iomb_write(&temp);
+ return;
+}
diff --git a/sr_vvms/iombdef.h b/sr_vvms/iombdef.h
new file mode 100644
index 0000000..d47e13c
--- /dev/null
+++ b/sr_vvms/iombdef.h
@@ -0,0 +1,45 @@
+/****************************************************************
+ * *
+ * Copyright 2011 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+#ifndef __IOMBDEF_H
+#define __IOMBDEF_H
+
+#define DEF_MB_MAXMSG 255
+#define DEF_MB_LENGTH 66
+
+/* *************************************************************** */
+/* *********** structure for the mailbox driver *************** */
+/* *************************************************************** */
+
+typedef struct
+{ unsigned short status;
+ unsigned short char_ct;
+ uint4 pid;
+} mb_iosb;
+
+typedef struct
+{
+ unsigned short channel;
+ uint4 maxmsg;
+ uint4 promsk;
+ unsigned char del_on_close;
+ bool timer_on;
+ unsigned char prmflg;
+ uint4 read_mask;
+ uint4 write_mask;
+ unsigned char *inbuf;
+ unsigned char *in_pos;
+ unsigned char *in_top;
+ mb_iosb stat_blk;
+} d_mb_struct;
+
+void iomb_cancel_read(d_mb_struct *mb_ptr);
+
+#endif
diff --git a/sr_vvms/iomt_closesp.c b/sr_vvms/iomt_closesp.c
new file mode 100644
index 0000000..492e730
--- /dev/null
+++ b/sr_vvms/iomt_closesp.c
@@ -0,0 +1,19 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "io.h"
+
+void iomt_closesp(int4 channel)
+{
+ sys$dassgn(channel);
+ return;
+}
diff --git a/sr_vvms/iomt_open.c b/sr_vvms/iomt_open.c
new file mode 100644
index 0000000..9ef91d9
--- /dev/null
+++ b/sr_vvms/iomt_open.c
@@ -0,0 +1,338 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include "io.h"
+#include "iosp.h"
+#include "iottdef.h"
+#include "iomtdef.h"
+#include "io_params.h"
+#include "nametabtyp.h"
+#include "toktyp.h"
+#include "stringpool.h"
+#include "namelook.h"
+#include "copy.h"
+
+LITDEF unsigned char LIB_AB_ASC_EBC[256] =
+{
+ 0, 1, 2, 3, 55, 45, 46, 47, 22, 5, 37, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 60, 61, 50, 38, 24, 25, 63, 39, 28, 29, 30,
+ 31, 64, 79, 127, 123, 91, 108, 80, 125, 77, 93, 92, 78, 107, 96, 75,
+ 97, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 122, 94, 76, 126, 110,
+ 111, 124, 193, 194, 195, 196, 197, 198, 199, 200, 201, 209, 210, 211, 212, 213,
+ 214, 215, 216, 217, 226, 227, 228, 229, 230, 231, 232, 233, 74, 224, 90, 95,
+ 109, 121, 129, 130, 131, 132, 133, 134, 135, 136, 137, 145, 146, 147, 148, 149,
+ 150, 151, 152, 153, 162, 163, 164, 165, 166, 167, 168, 169, 192, 106, 208, 161,
+ 7, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 255
+};
+LITDEF unsigned char LIB_AB_EBC_ASC[256] =
+{
+ 0, 1, 2, 3, 92, 9, 92, 127, 92, 92, 92, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 92, 92, 8, 92, 24, 25, 92, 92, 28, 29, 30,
+ 31, 92, 92, 92, 92, 92, 10, 23, 27, 92, 92, 92, 92, 92, 5, 6,
+ 7, 92, 92, 22, 92, 92, 92, 92, 4, 92, 92, 92, 92, 20, 21, 92,
+ 26, 32, 92, 92, 92, 92, 92, 92, 92, 92, 92, 91, 46, 60, 40, 43,
+ 33, 38, 92, 92, 92, 92, 92, 92, 92, 92, 92, 93, 36, 42, 41, 59,
+ 94, 45, 47, 92, 92, 92, 92, 92, 92, 92, 92, 124, 44, 37, 95, 62,
+ 63, 92, 92, 92, 92, 92, 92, 92, 92, 92, 96, 58, 35, 64, 39, 61,
+ 34, 92, 97, 98, 99, 100, 101, 102, 103, 104, 105, 92, 92, 92, 92, 92,
+ 92, 92, 106, 107, 108, 109, 110, 111, 112, 113, 114, 92, 92, 92, 92, 92,
+ 92, 92, 126, 115, 116, 117, 118, 119, 120, 121, 122, 92, 92, 92, 92, 92,
+ 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92,
+ 92, 123, 65, 66, 67, 68, 69, 70, 71, 72, 73, 92, 92, 92, 92, 92,
+ 92, 125, 74, 75, 76, 77, 78, 79, 80, 81, 82, 92, 92, 92, 92, 92,
+ 92, 92, 92, 83, 84, 85, 86, 87, 88, 89, 90, 92, 92, 92, 92, 92,
+ 92, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 92, 92, 92, 92, 92, 255
+};
+LITREF unsigned char io_params_size[];
+
+static readonly nametabent mtlab_names[] =
+{
+ {3, "ANS"}, {4,"ANSI"}, { 3, "DOS"}, { 5, "DOS11"}
+};
+static readonly unsigned char mtlab_index[27] =
+{
+ 0, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4
+ ,4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
+ ,4, 4, 4
+};
+static readonly char mtlab_type[]={ MTLAB_ANSI, MTLAB_ANSI, MTLAB_DOS11, MTLAB_DOS11 };
+
+error_def(ERR_DEVPARMNEG);
+error_def(ERR_MTRECTOOBIG);
+error_def(ERR_MTRECGTRBLK);
+error_def(ERR_MTBLKTOOBIG);
+error_def(ERR_MTBLKTOOSM);
+error_def(ERR_MTFIXRECSZ);
+error_def(ERR_MTRECTOOSM);
+error_def(ERR_MTINVLAB);
+error_def(ERR_MTDOSFOR);
+error_def(ERR_MTANSIFOR);
+error_def(ERR_MTIS);
+error_def(ERR_VARRECBLKSZ);
+
+#define VREC_HDR_LEN 4
+
+short iomt_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 timeout)
+{
+ bool do_rewind, do_erase;
+ int lab_type;
+ unsigned char *buff, ch, len;
+ int4 length, blocksize, recordsize;
+ uint4 status;
+ d_mt_struct *mt, newmt;
+ iosb io_status_blk;
+ io_desc *ioptr;
+ char *tab;
+ int p_offset;
+
+ ioptr = dev_name->iod;
+ buff = 0;
+ memset(&newmt, 0, SIZEOF(newmt)); /* zero structure to start */
+ if (ioptr->state == dev_never_opened)
+ ioptr->dev_sp =(void *)(malloc(SIZEOF(d_mt_struct)));
+ mt = (d_mt_struct *)dev_name->iod->dev_sp;
+ if (ioptr->state == dev_open && mt->buffer)
+ {
+ if (mt->bufftoggle < 0)
+ buff = (mt->buffer + mt->bufftoggle);
+ else
+ buff = (mt->buffer);
+ }
+ do_rewind = do_erase = FALSE;
+ if (ioptr->state == dev_never_opened)
+ {
+ length = DEF_MT_LENGTH;
+ newmt.read_mask = IO_READLBLK;
+ newmt.write_mask = IO_WRITELBLK;
+ newmt.block_sz = MTDEF_BUF_SZ;
+ newmt.record_sz = MTDEF_REC_SZ;
+ newmt.ebcdic = FALSE;
+ newmt.labeled = FALSE;
+ newmt.fixed = FALSE;
+ newmt.stream = FALSE;
+ newmt.read_only = FALSE;
+ newmt.newversion = FALSE;
+ newmt.last_op = mt_null;
+ newmt.wrap = TRUE;
+ }
+ else
+ {
+ length = ioptr->length;
+ newmt = *mt;
+ }
+ p_offset = 0;
+ while (*(pp->str.addr + p_offset) != iop_eol)
+ {
+ switch (ch = *(pp->str.addr + p_offset++))
+ {
+ case iop_blocksize:
+ GET_LONG(blocksize, pp->str.addr + p_offset);
+ if (blocksize < 0)
+ rts_error(VARLSTCNT(1) ERR_DEVPARMNEG);
+ else if (blocksize > MAX_BLK_SZ)
+ rts_error(VARLSTCNT(1) ERR_MTBLKTOOBIG);
+ else if (blocksize < MIN_BLK_SZ)
+ rts_error(VARLSTCNT(3) ERR_MTBLKTOOSM, 1, MIN_BLK_SZ);
+ newmt.block_sz = blocksize;
+ break;
+ case iop_recordsize:
+ GET_LONG(recordsize, (pp->str.addr + p_offset));
+ if (recordsize < 0)
+ rts_error(VARLSTCNT(1) ERR_DEVPARMNEG);
+ if (recordsize > MAX_REC_SZ)
+ rts_error(VARLSTCNT(1) ERR_MTRECTOOBIG);
+ newmt.record_sz = recordsize;
+
+ break;
+ case iop_rewind:
+ do_rewind = TRUE;
+ break;
+ case iop_erasetape:
+ do_erase = TRUE;
+ break;
+ case iop_newversion:
+ newmt.newversion = TRUE;
+ break;
+ case iop_readonly:
+ newmt.read_only = TRUE;
+ break;
+ case iop_noreadonly:
+ newmt.read_only = FALSE;
+ break;
+ case iop_ebcdic:
+ newmt.ebcdic = TRUE;
+ break;
+ case iop_noebcdic:
+ newmt.ebcdic = FALSE;
+ break;
+ case iop_nolabel:
+ newmt.labeled = FALSE;
+ break;
+ case iop_label:
+ len = *(pp->str.addr + p_offset);
+ tab = pp->str.addr + p_offset + 1;
+ if ((lab_type = namelook(mtlab_index, mtlab_names, tab, len)) < 0)
+ {
+ rts_error(VARLSTCNT(1) ERR_MTINVLAB);
+ return FALSE;
+ }
+ newmt.labeled = mtlab_type[lab_type];
+ break;
+ case iop_fixed:
+ newmt.fixed = TRUE;
+ break;
+ case iop_nofixed:
+ newmt.fixed = FALSE;
+ break;
+ case iop_rdcheckdata:
+ newmt.read_mask |= IO_M_DATACHECK;
+ break;
+ case iop_nordcheckdata:
+ newmt.read_mask &= (~(IO_M_DATACHECK));
+ break;
+ case iop_wtcheckdata:
+ newmt.write_mask |= IO_M_DATACHECK;
+ break;
+ case iop_nowtcheckdata:
+ newmt.write_mask &= (~(IO_M_DATACHECK));
+ break;
+ case iop_inhretry:
+ newmt.write_mask |= IO_M_INHRETRY;
+ newmt.read_mask |= IO_M_INHRETRY;
+ break;
+ case iop_retry:
+ newmt.write_mask &= ~IO_M_INHRETRY;
+ newmt.read_mask &= ~IO_M_INHRETRY;
+ break;
+ case iop_inhextgap:
+ newmt.write_mask |= IO_M_INHEXTGAP;
+ break;
+ case iop_extgap:
+ newmt.write_mask &= ~IO_M_INHEXTGAP;
+ break;
+ case iop_stream:
+ newmt.stream = TRUE;
+ break;
+ case iop_nostream:
+ newmt.stream = FALSE;
+ break;
+ case iop_wrap:
+ newmt.wrap = TRUE;
+ break;
+ case iop_nowrap:
+ newmt.wrap = FALSE;
+ break;
+ case iop_length:
+ GET_LONG(length, pp->str.addr + p_offset);
+ if (length < 0)
+ rts_error(VARLSTCNT(1) ERR_DEVPARMNEG);
+ break;
+ case iop_exception:
+ ioptr->error_handler.len = *(pp->str.addr + p_offset);
+ ioptr->error_handler.addr = pp->str.addr + p_offset + 1;
+ s2pool(&ioptr->error_handler);
+ break;
+ default:
+ break;
+ }
+ p_offset += ((IOP_VAR_SIZE == io_params_size[ch]) ?
+ (unsigned char)*(pp->str.addr + p_offset) + 1 : io_params_size[ch]);
+ }
+ if (newmt.labeled == MTLAB_DOS11)
+ if (!newmt.stream)
+ {
+ rts_error(VARLSTCNT(6) ERR_MTDOSFOR, 0 ,ERR_MTIS, 2,
+ ioptr->trans_name->len, ioptr->trans_name->dollar_io);
+ }
+
+ if (newmt.labeled == MTLAB_ANSI)
+ if (newmt.stream)
+ { rts_error(VARLSTCNT(6) ERR_MTANSIFOR, 0 ,ERR_MTIS, 2,
+ ioptr->trans_name->len, ioptr->trans_name->dollar_io);
+ }
+ if (newmt.stream)
+ { newmt.wrap = TRUE;
+ newmt.fixed = FALSE;
+ }
+ if (newmt.fixed)
+ {
+ if (newmt.record_sz < MIN_FIXREC_SZ)
+ rts_error(VARLSTCNT(1) ERR_MTRECTOOSM);
+ if (newmt.block_sz / newmt.record_sz * newmt.record_sz != newmt.block_sz)
+ rts_error(VARLSTCNT(4) ERR_MTFIXRECSZ, 2, newmt.block_sz, newmt.record_sz);
+ }
+ else
+ { if (newmt.record_sz > MAX_VARREC_SZ)
+ rts_error(VARLSTCNT(1) ERR_MTRECTOOBIG);
+ if (newmt.record_sz < MIN_VARREC_SZ)
+ rts_error(VARLSTCNT(1) ERR_MTRECTOOSM);
+ if (newmt.block_sz < newmt.record_sz + (newmt.stream ? 2 : VREC_HDR_LEN))
+ rts_error(VARLSTCNT(1) ERR_VARRECBLKSZ);
+ }
+ if (newmt.record_sz > newmt.block_sz)
+ rts_error(VARLSTCNT(1) ERR_MTRECGTRBLK);
+ if (ioptr->state != dev_open)
+ {
+ status = iomt_opensp(dev_name, &newmt);
+ if (status == MT_BUSY)
+ return FALSE;
+ if (status == MT_TAPERROR)
+ rts_error(VARLSTCNT(1) newmt.access_id);
+ }
+ if (newmt.fixed)
+ {
+ newmt.buffer = (unsigned char *)malloc(newmt.block_sz);
+ newmt.bufftoggle = 0;
+ } else
+ {
+ newmt.buffer = (unsigned char *)malloc(newmt.block_sz * 2);
+ newmt.bufftoggle = newmt.block_sz;
+ }
+ if (buff)
+ free(buff);
+ newmt.bufftop = newmt.buffptr = newmt.buffer;
+ newmt.last_op = mt_null;
+ ioptr->state = dev_open;
+ *mt = newmt;
+ ioptr->width = newmt.record_sz;
+ ioptr->length = length;
+ ioptr->dollar.zeof = FALSE;
+ ioptr->dollar.x = 0;
+ ioptr->dollar.y = 0;
+ if (do_erase)
+ iomt_erase(ioptr);
+ if (do_rewind)
+ iomt_rewind(ioptr);
+ if (mt->labeled)
+ {
+ status = iomt_sense(mt, &io_status_blk);
+ if (status != SS_NORMAL)
+ {
+ ioptr->dollar.za = 9;
+ rts_error(VARLSTCNT(5) status,
+ ERR_MTIS, 2, ioptr->trans_name->len, ioptr->trans_name->dollar_io);
+ }
+ if (io_status_blk.dev_dep_info & MT_M_BOT)
+ mt->last_op = mt_rewind;
+ }
+ return TRUE;
+}
diff --git a/sr_vvms/iomt_opensp.c b/sr_vvms/iomt_opensp.c
new file mode 100644
index 0000000..9c2cf71
--- /dev/null
+++ b/sr_vvms/iomt_opensp.c
@@ -0,0 +1,40 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "io.h"
+#include "iottdef.h"
+#include "iomtdef.h"
+#include <descrip.h>
+#include <ssdef.h>
+
+uint4 iomt_opensp(
+io_log_name *dev_name,
+d_mt_struct *mtdef)
+{
+ uint4 status, channel;
+ $DESCRIPTOR(file_name,"");
+
+ file_name.dsc$a_pointer = dev_name->dollar_io;
+ file_name.dsc$w_length = (unsigned short) dev_name->len;
+ if ((status = sys$assign(&file_name,&channel,0,0)) == SS$_DEVALLOC
+ || status == SS$_INSFMEM || status == SS$_NOIOCHAN)
+ { status = MT_BUSY;
+ }
+ else if (status != SS$_NORMAL)
+ { mtdef->access_id = status;
+ status = MT_TAPERROR;
+ }
+ else
+ mtdef->access_id = channel;
+ return status;
+}
+
diff --git a/sr_vvms/iomt_qio.c b/sr_vvms/iomt_qio.c
new file mode 100644
index 0000000..fbecb3b
--- /dev/null
+++ b/sr_vvms/iomt_qio.c
@@ -0,0 +1,44 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "io.h"
+#include "iottdef.h"
+#include "iomtdef.h"
+#include <iodef.h>
+#include <ssdef.h>
+#include <efndef.h>
+
+
+void iomt_qio(io_desc *iod, uint4 mask, uint4 parm)
+{
+ uint4 status, status1;
+ iosb io_status_blk;
+ d_mt_struct *mt_ptr;
+ error_def (ERR_MTIS);
+
+ io_status_blk.status = 0;
+ mt_ptr = (d_mt_struct *) iod->dev_sp;
+ status = sys$qiow(EFN$C_ENF,mt_ptr->access_id, mask, &io_status_blk, 0,0,parm, 0,0,0,0,0);
+
+ if ((status1 = io_status_blk.status) != SS$_NORMAL)
+ {
+ if (SS$_ENDOFTAPE == status1)
+ iod->dollar.za = 1;
+ else
+ {
+ iod->dollar.za = 9;
+ rts_error(VARLSTCNT(4) ERR_MTIS, 2, iod->trans_name->len, iod->trans_name->dollar_io);
+ }
+ } else
+ iod->dollar.za = 0;
+ return;
+}
diff --git a/sr_vvms/iomt_rdlblk.c b/sr_vvms/iomt_rdlblk.c
new file mode 100644
index 0000000..be488d3
--- /dev/null
+++ b/sr_vvms/iomt_rdlblk.c
@@ -0,0 +1,36 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "io.h"
+#include "iottdef.h"
+#include "iomtdef.h"
+#include <iodef.h>
+#include <ssdef.h>
+#include <efndef.h>
+
+
+uint4 iomt_rdlblk(
+ d_mt_struct *mt_ptr,
+ uint4 mask,
+ iosb *stat_blk,
+ void *buff,
+ int size)
+
+{
+ uint4 status;
+
+ mask |= IO$_READLBLK;
+ status = sys$qiow(EFN$C_ENF,mt_ptr->access_id,mask,stat_blk,0,0,
+ buff,size,0,0,0,0);
+ return status;
+}
+
diff --git a/sr_vvms/iomt_sense.c b/sr_vvms/iomt_sense.c
new file mode 100644
index 0000000..f27e2ee
--- /dev/null
+++ b/sr_vvms/iomt_sense.c
@@ -0,0 +1,29 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2004 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "io.h"
+#include "iottdef.h"
+#include "iomtdef.h"
+#include <ssdef.h>
+#include <iodef.h>
+#include <efndef.h>
+
+
+uint4 iomt_sense(d_mt_struct *mt, iosb *io_status_blk)
+{
+ uint4 status;
+
+ status = sys$qiow(EFN$C_ENF,mt->access_id, IO$_SENSEMODE, io_status_blk,0,0,0,0,0,0,0,0);
+ if (status == SS$_NORMAL)
+ status = io_status_blk->status;
+ return status;
+}
diff --git a/sr_vvms/iomt_tm.c b/sr_vvms/iomt_tm.c
new file mode 100644
index 0000000..9ff5841
--- /dev/null
+++ b/sr_vvms/iomt_tm.c
@@ -0,0 +1,30 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "io.h"
+#include "iottdef.h"
+#include "iomtdef.h"
+#include "io_params.h"
+#include <iodef.h>
+#include <ssdef.h>
+
+void iomt_tm( io_desc *dev)
+{
+ d_mt_struct *mt_ptr;
+
+ iomt_flush(dev);
+ iomt_qio(dev, IO$_WRITEMARK, 0); /* writes eof without ext gap */
+ mt_ptr = (d_mt_struct *) dev->dev_sp;
+ mt_ptr->last_op = ((mt_ptr->last_op == mt_tm || mt_ptr->last_op == mt_tm2)
+ ? mt_tm2 : mt_tm);
+ return;
+}
diff --git a/sr_vvms/iomt_wtlblk.c b/sr_vvms/iomt_wtlblk.c
new file mode 100644
index 0000000..78062c7
--- /dev/null
+++ b/sr_vvms/iomt_wtlblk.c
@@ -0,0 +1,22 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "io.h"
+#include "iottdef.h"
+#include <iodef.h>
+#include <efndef.h>
+
+
+uint4 iomt_wtlblk(uint4 channel, uint4 mask, iosb *stat_blk, void *buff, int size)
+{
+ return sys$qiow(EFN$C_ENF, channel, mask | IO$_WRITELBLK,stat_blk, 0,0, (char*)buff,size, 0,0,0,0 );
+}
diff --git a/sr_vvms/iomtdef.h b/sr_vvms/iomtdef.h
new file mode 100644
index 0000000..e505a4c
--- /dev/null
+++ b/sr_vvms/iomtdef.h
@@ -0,0 +1,106 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2004 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef __IOMTDEF_H__
+#define __IOMTDEF_H__
+
+/* iomtdef.h VMS - mag tape header file */
+
+#define MAX_VARREC_SZ 9995
+#define MAX_FIXREC_SZ 65535
+#define MAX_REC_SZ 65535 /* maximum value that can be specified for the RECORDSIZE device parameter */
+#define MAX_BLK_SZ 65535
+#define MIN_BLK_SZ 14
+#define MIN_VARREC_SZ 5
+#define MIN_FIXREC_SZ 1
+
+enum mt_op
+{
+ mt_null, mt_write, mt_read, mt_eof, mt_eof2, mt_rewind, mt_tm, mt_tm2
+};
+
+#define MTDEF_BUF_SZ 1024
+#define MTDEF_REC_SZ 1020
+#define MTDEF_PG_WIDTH 255
+#define DEF_MT_LENGTH 66
+
+#define MT_RECHDRSIZ 4
+
+#define MTLAB_DOS11 (1 << 0)
+#define MTLAB_ANSI (1 << 1)
+
+#define MTL_VOL1 (1 << 0)
+#define MTL_HDR1 (1 << 1)
+#define MTL_HDR2 (1 << 2)
+#define MTL_EOF1 (1 << 3)
+#define MTL_EOF2 (1 << 4)
+
+#define ANSI_LAB_LENGTH 80
+/* THESE DEFINITIONS ARE TAKEN FROM VMS SYS$LIBRARY IODEF.H */
+
+/* */
+/* *** START LOGICAL I/O FUNCTION CODES *** */
+/* */
+#define IO_WRITEMARK 28 /*WRITE TAPE MARK */
+#define IO_WRITELBLK 32 /*WRITE LOGICAL BLOCK */
+#define IO_READLBLK 33 /*READ LOGICAL BLOCK */
+#define IO_WRITEOF 40 /*WRITE END OF FILE */
+#define IO_REWIND 36 /*REWIND TAPE */
+#define IO_SKIPFILE 37 /*SKIP FILES */
+#define IO_SKIPRECORD 38 /*SKIP RECORDS */
+
+/* */
+/* FUNCTION MODIFIER BIT DEFINITIONS */
+/* */
+
+#define IO_M_DATACHECK 16384
+#define IO_M_INHRETRY 32768
+#define IO_M_INHEXTGAP 4096
+#define IO_M_ERASE 1024
+
+/* THESE DEFINITIONS ARE TAKEN FROM VMS SYS$LIBRARY MTDEF.H */
+
+#define MT_M_BOT 65536
+#define MT_TAPERROR 666
+#define MT_BUSY 333
+
+/* *************************************************************** */
+/* ************* structure for the magtape ********************** */
+/* *************************************************************** */
+
+typedef struct
+{
+ int4 access_id; /* channel to access magtape */
+ uint4 read_mask;
+ uint4 write_mask;
+ uint4 record_sz;
+ uint4 block_sz;
+ unsigned char *buffer;
+ unsigned char *bufftop;
+ unsigned char *buffptr;
+ int bufftoggle;
+ bool ebcdic;
+ unsigned char labeled;
+ mstr rec;
+ bool last_op;
+ bool newversion;
+ bool read_only;
+ bool wrap;
+ bool fixed;
+ bool stream;
+}d_mt_struct;
+
+uint4 iomt_rdlblk(d_mt_struct *mt_ptr, uint4 mask, iosb *stat_blk, void *buff, int size);
+uint4 iomt_wtlblk(uint4 channel, uint4 mask, iosb *stat_blk, void *buff, int size);
+uint4 iomt_sense(d_mt_struct *mt, iosb *io_status_blk);
+uint4 iomt_opensp(io_log_name *dev_name, d_mt_struct *mtdef);
+
+#endif
diff --git a/sr_vvms/iorm_close.c b/sr_vvms/iorm_close.c
new file mode 100644
index 0000000..c24d0a3
--- /dev/null
+++ b/sr_vvms/iorm_close.c
@@ -0,0 +1,128 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include <rms.h>
+#include "mdef.h"
+#include "io.h"
+#include "iormdef.h"
+#include <ssdef.h>
+#include <iodef.h>
+#include <devdef.h>
+#include "io_params.h"
+
+LITREF unsigned char io_params_size[];
+
+void iorm_close(io_desc *iod, mval *pp)
+{
+int4 status;
+unsigned char c;
+int p_offset;
+d_rm_struct *rm_ptr;
+mstr bque= {9,"SYS$BATCH"} ; /* default submit queue */
+mstr pque= {9,"SYS$PRINT"} ; /* default spool queue */
+bool rename, submit, spool, delete;
+boolean_t rm_destroy = TRUE;
+boolean_t rm_rundown = FALSE;
+
+unsigned short promask;
+struct FAB fab;
+struct NAM nam;
+struct XABPRO xab;
+
+assert(iod != 0);
+assert((pp->str.addr) != 0);
+rm_ptr = (d_rm_struct *) iod->dev_sp;
+if (iod->state == dev_open)
+{
+ promask = rm_ptr->promask;
+ iorm_use(iod, pp);
+ if ((rm_ptr->f.fab$b_fac == FAB$M_GET) == 0 && rm_ptr->r.rab$l_ctx == FAB$M_PUT &&
+ rm_ptr->outbuf_pos != rm_ptr->outbuf && !iod->dollar.za)
+ { iorm_flush(iod);
+ }
+ p_offset = 0;
+ delete = ((rm_ptr->f.fab$l_fop & FAB$M_DLT) == FAB$M_DLT) ;
+ rename = submit = spool = FALSE ;
+ if (rm_ptr->f.fab$l_dev & DEV$M_FOD)
+ {
+ while (*(pp->str.addr + p_offset) != iop_eol)
+ {
+ switch (c = *(pp->str.addr + p_offset++))
+ {
+ case iop_rename:
+ fab = rm_ptr->f;
+ fab.fab$b_fns = *(pp->str.addr + p_offset);
+ fab.fab$l_fna = (pp->str.addr + p_offset+ 1);
+ rename= TRUE ;
+ break;
+ case iop_submit:
+ rm_ptr->f.fab$l_fop &= ~FAB$M_SCF & ~FAB$M_DLT ;
+ submit= TRUE ;
+ break;
+ case iop_spool:
+ rm_ptr->f.fab$l_fop &= ~FAB$M_SPL & ~FAB$M_DLT ;
+ spool= TRUE ;
+ break;
+ case iop_destroy:
+ rm_destroy = TRUE;
+ break;
+ case iop_nodestroy:
+ rm_destroy = FALSE;
+ break;
+ case iop_rundown:
+ rm_rundown = TRUE;
+ break;
+ default:
+ break;
+ }
+ p_offset += ((IOP_VAR_SIZE == io_params_size[c]) ?
+ (unsigned char)*(pp->str.addr + p_offset) + 1 : io_params_size[c]);
+ }
+ }
+ if (promask != rm_ptr->promask)
+ { xab = cc$rms_xabpro;
+ xab.xab$w_pro = rm_ptr->promask;
+ rm_ptr->f.fab$l_xab = &xab;
+ }
+ nam = *(rm_ptr->f.fab$l_nam) ;
+ status = sys$close(&rm_ptr->f);
+ rm_ptr->f.fab$l_xab = 0;
+ if (!rm_ptr->f.fab$w_ifi)
+ iod->state = dev_closed;
+ if (status != RMS$_NORMAL)
+ rts_error(VARLSTCNT(2) status, rm_ptr->f.fab$l_stv);
+ if (rename)
+ {
+ if ((status = sys$rename(&(rm_ptr->f), 0, 0, &fab)) != RMS$_NORMAL)
+ rts_error(VARLSTCNT(2) status, rm_ptr->f.fab$l_stv);
+ }
+ if (spool)
+ {
+ status= iorm_jbc(&nam, pp, &pque, delete) ;
+ if ((status & 1)==0)
+ {
+ rts_error(VARLSTCNT(1) status) ;
+ }
+ }
+ if (submit)
+ {
+ status= iorm_jbc(&nam, pp, &bque, delete) ;
+ if ((status & 1)==0)
+ {
+ rts_error(VARLSTCNT(1) status) ;
+ }
+ }
+}
+rm_ptr->r.rab$l_ctx = FAB$M_GET;
+if (rm_destroy && !rm_rundown)
+ remove_rms(iod);
+return;
+}
diff --git a/sr_vvms/iorm_flush.c b/sr_vvms/iorm_flush.c
new file mode 100644
index 0000000..b01c873
--- /dev/null
+++ b/sr_vvms/iorm_flush.c
@@ -0,0 +1,28 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+
+#include "mdef.h"
+#include <rms.h>
+#include "io.h"
+#include "iormdef.h"
+
+void iorm_flush(io_desc *iod)
+{
+ d_rm_struct *rm_ptr;
+
+ rm_ptr = (d_rm_struct *) iod->dev_sp;
+ if (rm_ptr->outbuf < rm_ptr->outbuf_pos)
+ { iorm_wteol(1,iod);
+ }
+ return;
+}
+
diff --git a/sr_vvms/iorm_get.c b/sr_vvms/iorm_get.c
new file mode 100644
index 0000000..ae4d65d
--- /dev/null
+++ b/sr_vvms/iorm_get.c
@@ -0,0 +1,105 @@
+/****************************************************************
+ * *
+ * Copyright 2004, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/****************************************************************
+ * *
+ * iorm_get is a wrapper around the RMS sys$get routine to *
+ * implement the GT.M BIGRECORD file format. *
+ * *
+ * Arguments: *
+ * iod io_desc structure *
+ * timeout timeout value from M OPEN *
+ * *
+ * Return: RMS$_NORMAL or RMS error status *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <rms.h>
+
+#include "io.h"
+#include "iormdef.h"
+#include "iotimer.h"
+
+int iorm_get(io_desc *iod, int4 timeout)
+{
+ d_rm_struct *rm_ptr;
+ struct RAB *rab;
+ int4 stat;
+ int len, reclen, toread, expected_reclen, extra_bytes;
+ unsigned long save_ubf;
+
+ assert(0 <= timeout);
+ rm_ptr = (d_rm_struct *)iod->dev_sp;
+ rab = &rm_ptr->r;
+ reclen = 0; /* set to bytes read total */
+ save_ubf = rab->rab$l_ubf;
+ if (rm_ptr->largerecord)
+ {
+ if (FAB$C_FIX == rm_ptr->b_rfm)
+ {
+ if (iod->width < rm_ptr->l_mrs)
+ {
+ rab->rab$l_stv = rm_ptr->l_mrs;
+ return RMS$_RTB;
+ }
+ expected_reclen = toread = rm_ptr->l_mrs;
+ } else if (FAB$C_VAR == rm_ptr->b_rfm)
+ {
+ rab->rab$w_usz = SIZEOF(uint4);
+ rab->rab$l_ubf = &toread;
+ toread = 0;
+ rab->rab$b_tmo = (timeout <= 255) ? timeout : 255;
+ stat = sys$get(rab);
+ rab->rab$l_ubf = save_ubf;
+ if (RMS$_NORMAL != stat)
+ return stat;
+ expected_reclen = toread;
+ } else
+ GTMASSERT;
+ toread = ROUND_UP2(toread, SIZEOF(uint4));
+ extra_bytes = toread - expected_reclen;
+ rab->rab$w_usz = (unsigned short)(MAX_RMS_UDF_RECORD < toread ? MAX_RMS_UDF_RECORD : toread);
+ } else
+ {
+ rab->rab$w_usz = toread = (unsigned short)rm_ptr->l_usz;
+ extra_bytes = 0;
+ }
+ do
+ {
+ do
+ {
+ rab->rab$b_tmo = (timeout <= 255) ? timeout : 255;
+ stat = sys$get(rab);
+ if (RMS$_TMO == stat && NO_M_TIMEOUT != timeout)
+ (timeout > 255) ? (timeout -= 255) : (timeout = 0);
+ } while ((RMS$_TMO == stat) && (timeout > 0));
+ reclen += (unsigned int)rab->rab$w_rsz;
+ if (!rm_ptr->largerecord)
+ break;
+ toread -= (unsigned int)rab->rab$w_rsz;
+ rab->rab$l_ubf += (unsigned int)rab->rab$w_rsz;
+ rab->rab$w_usz = (unsigned short)(MAX_RMS_UDF_RECORD < toread ? MAX_RMS_UDF_RECORD : toread);
+ } while (RMS$_NORMAL == stat && 0 < toread);
+ rab->rab$l_ubf = save_ubf;
+ switch (stat)
+ {
+ case RMS$_NORMAL:
+ assert(!rm_ptr->largerecord || (0 == toread && reclen - expected_reclen == extra_bytes));
+ rm_ptr->l_rsz = reclen - extra_bytes;
+ break;
+ case RMS$_EOF:
+ rm_ptr->l_rsz = reclen;
+ break;
+ }
+ return stat;
+}
diff --git a/sr_vvms/iorm_jbc.c b/sr_vvms/iorm_jbc.c
new file mode 100644
index 0000000..0cfd9b0
--- /dev/null
+++ b/sr_vvms/iorm_jbc.c
@@ -0,0 +1,206 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* iorm_jbc.c
+ used in: iorm_close.c
+*/
+#include <rms.h>
+#include "mdef.h"
+#include "io.h"
+#include <ssdef.h>
+#include <sjcdef.h>
+#include <iodef.h>
+#include <efndef.h>
+
+#include "io_params.h"
+#define IDENDIM 28
+LITREF unsigned char io_params_size[];
+
+int4 iorm_jbc(struct NAM *nam, mval *pp, mstr *que, bool delete)
+/* *p : parameter list */
+/* *que : default que */
+/* delete : delete file */
+{
+ int4 sys$sndjbc(), sys$parse(), sys$search() ;
+ int4 status ;
+ int4 iosb[2] ;
+ int4 temp ;
+ int p_offset ;
+ int k ;
+ unsigned char c ;
+ struct { short bln ; short cod ; char *buf ; int4 rln ;} itm[64] ;
+
+ itm[0].bln= IDENDIM ;
+ itm[0].cod= SJC$_FILE_IDENTIFICATION ;
+ itm[0].buf= &(nam->nam$t_dvi) ;
+ itm[0].rln= 0 ;
+
+ itm[1].bln= que->len ;
+ itm[1].cod= SJC$_QUEUE;
+ itm[1].buf= que->addr ;
+ itm[1].rln= 0 ;
+
+ p_offset = 0 ; k= 2 ; c = *(pp->str.addr + p_offset++) ;
+ while (c != iop_eol)
+ {
+ if (io_params_size[c]==IOP_VAR_SIZE)
+ {
+ itm[k].bln= (short) *(pp->str.addr + p_offset) ;
+ itm[k].buf= (pp->str.addr + p_offset + 1) ;
+ p_offset += (*(pp->str.addr + p_offset) + 1);
+ }
+ else
+ {
+ itm[k].bln= io_params_size[c] ;
+ itm[k].buf= pp->str.addr + p_offset;
+ p_offset += io_params_size[c];
+ }
+ itm[k].rln= 0 ;
+ switch (c)
+ {
+ case iop_after: itm[k].cod= SJC$_AFTER_TIME ;
+ break ;
+ case iop_burst: itm[k].cod= SJC$_FILE_BURST ;
+ break ;
+ case iop_characteristic:
+ itm[k].cod= SJC$_CHARACTERISTIC_NUMBER ;
+ break ;
+ case iop_cli: itm[k].cod= SJC$_CLI ;
+ break ;
+ case iop_copies: itm[k].cod= SJC$_FILE_COPIES ;
+ break ;
+ case iop_cpulimit: itm[k].cod= SJC$_CPU_LIMIT ;
+ break ;
+ case iop_doublespace: itm[k].cod= SJC$_DOUBLE_SPACE ;
+ break ;
+ case iop_firstpage: itm[k].cod= SJC$_FIRST_PAGE ;
+ break ;
+ case iop_flag: itm[k].cod= SJC$_FILE_FLAG ;
+ break ;
+ case iop_form: itm[k].cod= SJC$_FORM_NUMBER ;
+ break ;
+ case iop_header: itm[k].cod= SJC$_PAGE_HEADER ;
+ break ;
+ case iop_hold: itm[k].cod= SJC$_HOLD ;
+ break ;
+ case iop_lastpage: itm[k].cod= SJC$_LAST_PAGE ;
+ break ;
+ case iop_logfile: itm[k].cod= SJC$_LOG_SPECIFICATION ;
+ break ;
+ case iop_logqueue: itm[k].cod= SJC$_LOG_QUEUE ;
+ break ;
+ case iop_lowercase: itm[k].cod= SJC$_LOWERCASE ;
+ break ;
+ case iop_name: itm[k].cod= SJC$_JOB_NAME ;
+ break ;
+ case iop_noburst: itm[k].cod= SJC$_NO_FILE_BURST ;
+ break ;
+ case iop_nodoublespace: itm[k].cod= SJC$_NO_DOUBLE_SPACE ;
+ break ;
+ case iop_noflag: itm[k].cod= SJC$_NO_FILE_FLAG ;
+ break ;
+ case iop_noheader: itm[k].cod= SJC$_NO_PAGE_HEADER ;
+ break ;
+ case iop_nohold: itm[k].cod= SJC$_NO_HOLD ;
+ break ;
+ case iop_nolowercase: itm[k].cod= SJC$_NO_LOWERCASE ;
+ break ;
+ case iop_nonotify: itm[k].cod= SJC$_NO_NOTIFY ;
+ break ;
+ case iop_nopage: itm[k].cod= SJC$_NO_PAGINATE ;
+ break ;
+ case iop_nopassall: itm[k].cod= SJC$_NO_PASSALL ;
+ break ;
+ case iop_noprint: itm[k].cod= SJC$_NO_LOG_SPOOL ;
+ k++ ;
+ itm[k].bln= 0 ;
+ itm[k].cod= SJC$_LOG_DELETE ;
+ itm[k].buf= 0 ;
+ itm[k].rln= 0 ;
+ break ;
+ case iop_norestart: itm[k].cod= SJC$_NO_RESTART ;
+ break ;
+ case iop_note: itm[k].cod= SJC$_NOTE ;
+ break ;
+ case iop_notify: itm[k].cod= SJC$_NOTIFY ;
+ break ;
+ case iop_notrailer: itm[k].cod= SJC$_NO_FILE_TRAILER ;
+ break ;
+ case iop_operator: itm[k].cod= SJC$_OPERATOR_REQUEST ;
+ break ;
+ case iop_p1: itm[k].cod=SJC$_PARAMETER_1 ;
+ break ;
+ case iop_p2: itm[k].cod=SJC$_PARAMETER_2 ;
+ break ;
+ case iop_p3: itm[k].cod=SJC$_PARAMETER_3 ;
+ break ;
+ case iop_p4: itm[k].cod=SJC$_PARAMETER_4 ;
+ break ;
+ case iop_p5: itm[k].cod=SJC$_PARAMETER_5 ;
+ break ;
+ case iop_p6: itm[k].cod=SJC$_PARAMETER_6 ;
+ break ;
+ case iop_p7: itm[k].cod=SJC$_PARAMETER_7 ;
+ break ;
+ case iop_p8: itm[k].cod=SJC$_PARAMETER_8 ;
+ break ;
+ case iop_page: itm[k].cod= SJC$_PAGINATE ;
+ break ;
+ case iop_passall: itm[k].cod= SJC$_PASSALL ;
+ break ;
+ case iop_print: itm[k].cod= SJC$_LOG_SPOOL ;
+ k++ ;
+ itm[k].bln= 0 ;
+ itm[k].cod= SJC$_NO_LOG_DELETE ;
+ itm[k].buf= 0 ;
+ itm[k].rln= 0 ;
+ break ;
+ case iop_priority: itm[k].cod= SJC$_PRIORITY ;
+ break ;
+ case iop_queue: itm[1].bln= itm[k].bln ;
+ itm[1].buf= itm[k].buf ;
+ --k ;
+ break ;
+ case iop_remote: itm[k].cod= SJC$_SCSNODE_NAME ;
+ break ;
+ case iop_restart: itm[k].cod= SJC$_RESTART ;
+ break ;
+ case iop_setup: itm[k].cod= SJC$_FILE_SETUP_MODULES ;
+ break ;
+ case iop_trailer: itm[k].cod= SJC$_FILE_TRAILER ;
+ break ;
+ case iop_uic: itm[k].cod= SJC$_UIC ;
+ break ;
+ case iop_user: itm[k].cod= SJC$_USERNAME ;
+ break ;
+ default: --k ;
+ break ;
+ }
+ k++ ;
+ c= *(pp->str.addr + p_offset++) ;
+ }
+ if (delete)
+ {
+ itm[k].bln= 0 ;
+ itm[k].cod= SJC$_DELETE_FILE ;
+ itm[k].buf= 0 ;
+ itm[k].rln= 0 ;
+ k++ ;
+ }
+ itm[k].bln = itm[k].cod = 0;
+ itm[k].buf = itm[k].rln = 0 ;
+ status= sys$sndjbcw(EFN$C_ENF,SJC$_ENTER_FILE,0,itm,iosb,0,0) ;
+ if ((status & 1)==1)
+ {
+ status= iosb[0] ;
+ }
+ return status ;
+}
diff --git a/sr_vvms/iorm_open.c b/sr_vvms/iorm_open.c
new file mode 100644
index 0000000..e363071
--- /dev/null
+++ b/sr_vvms/iorm_open.c
@@ -0,0 +1,405 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <starlet.h>
+#include <efn.h>
+#include <descrip.h>
+#include <rms.h>
+#include <dcdef.h>
+#include <devdef.h>
+#include <dvidef.h>
+#include <acedef.h>
+#include <ssdef.h>
+#include <stddef.h>
+#include "gtm_string.h"
+
+#include "vmsdtype.h"
+#include "io.h"
+#include "iormdef.h"
+#include "io_params.h"
+#include "min_max.h"
+
+#define ESC 27
+#define DFLT_FILE_EXT ".DAT"
+#define VREC_HDR_LEN 4
+#define VFC_MAX_RECLEN (32767 - 2) /* have to leave two bytes for the fixed control */
+
+error_def(ERR_RMWIDTHTOOBIG);
+error_def(ERR_TEXT);
+error_def(ERR_BIGNOACL);
+error_def(ERR_DEVOPENFAIL);
+error_def(ERR_VARRECBLKSZ);
+
+short iorm_open(io_log_name *iol, mval *pp, int fd, mval *mspace, int4 timeout)
+{
+ int4 status;
+ io_desc *iod; /* local pointer to io_curr_device */
+ d_rm_struct *d_rm;
+ struct XABFHC xabfhc;
+ struct XABPRO xabpro;
+ struct RAB *r;
+ struct FAB *f;
+ struct NAM *nam;
+ mstr newtln;
+ struct dsc$descriptor_s devname, outname;
+ uint4 width;
+ uint4 acebin[128]; /* needs to be big enough for any other ACLs on file */
+ uint4 *acebinptr;
+ struct acedef *aceptr;
+ char *acetop;
+ boolean_t acefound = FALSE, created = FALSE, isdisk = FALSE, noacl = FALSE;
+ unsigned int devclass, devchar, devchar2, devtype, dvistat, iosb[2];
+ short devclassret, devcharret, devchar2ret, devtyperet;
+ struct
+ {
+ item_list_3 item[4];
+ int terminator;
+ } item_list;
+ unsigned char resultant_name[255];
+ unsigned char tmpfdns;
+ /** unsigned char resultant_name[MAX_TRANS_NAME_LEN]; THIS WOULD BE RIGHT BUT MAX_TRANS_NAME_LEN MUST BE <= 255 **/
+
+ /* while sr_unix/iorm_open.c prefixes errors with ERR_DEVOPENFAIL and it might be nice to be consistent */
+ /* changing VMS after all this time could break user programs */
+ /* An exception is being made for the extremely unlikely problem creating a GTM ACE so it stands out */
+ iod = iol->iod;
+ assert(*(pp->str.addr) < n_iops);
+ assert(iod);
+ assert(iod->state >= 0 && iod->state < n_io_dev_states);
+ assert(rm == iod->type);
+ if (dev_never_opened == iod->state)
+ {
+ iod->dev_sp = (d_rm_struct *)(malloc(SIZEOF(d_rm_struct)));
+ d_rm = (d_rm_struct *)iod->dev_sp;
+ memset(d_rm, 0, SIZEOF(*d_rm));
+ iod->width = DEF_RM_WIDTH;
+ iod->length = DEF_RM_LENGTH;
+ r = &d_rm->r;
+ f = &d_rm->f;
+ *r = cc$rms_rab;
+ *f = cc$rms_fab;
+ r->rab$l_fab = f;
+ r->rab$w_usz = d_rm->l_usz = DEF_RM_WIDTH;
+ f->fab$w_mrs = d_rm->l_mrs = DEF_RM_WIDTH;
+ f->fab$b_rfm = d_rm->b_rfm = FAB$C_VAR; /* default is variable record format */
+ f->fab$l_fop = FAB$M_CIF | FAB$M_SQO | FAB$M_CBT | FAB$M_NAM;
+ f->fab$b_fac = FAB$M_GET | FAB$M_PUT | FAB$M_TRN; /* TRN allows truncate option to be specified in RAB later */
+ f->fab$b_rat = FAB$M_CR;
+
+ f->fab$l_dna = DFLT_FILE_EXT;
+ f->fab$b_dns = SIZEOF(DFLT_FILE_EXT) - 1;
+ d_rm->f.fab$l_nam = nam = malloc(SIZEOF(*nam));
+ *nam = cc$rms_nam;
+ nam->nam$l_esa = resultant_name;
+ nam->nam$b_ess = SIZEOF(resultant_name);
+ nam->nam$b_nop = NAM$M_NOCONCEAL;
+
+ r->rab$l_rop = RAB$M_TMO | RAB$M_WBH | RAB$M_RAH;
+ d_rm->promask = 0xFFFF;
+ } else
+ {
+ d_rm = (d_rm_struct *)iod->dev_sp;
+ if (dev_closed == iod->state)
+ d_rm->f.fab$w_bls = 0; /* Reset the block size to pass the block-record check below.
+ * The FAB initialization sets the block size later so it's OK to zero it here.
+ */
+ nam = d_rm->f.fab$l_nam;
+ nam->nam$l_esa = 0;
+ nam->nam$b_ess = 0;
+ nam->nam$b_esl = 0;
+ }
+ iorm_use(iod, pp);
+ if (dev_open != iod->state)
+ {
+ if (!d_rm->largerecord && (d_rm->f.fab$w_bls > 0) && (FAB$C_FIX != d_rm->f.fab$b_rfm)
+ && (d_rm->f.fab$w_bls < (d_rm->r.rab$w_usz + VREC_HDR_LEN)))
+ rts_error(VARLSTCNT(1) ERR_VARRECBLKSZ);
+ d_rm->r.rab$l_ctx = FAB$M_GET;
+ d_rm->f.fab$l_fna = iol->dollar_io;
+ d_rm->f.fab$b_fns = iol->len;
+/* smw next overrides any xab set by iorm_use */
+ xabpro = cc$rms_xabpro;
+ d_rm->f.fab$l_xab = &xabpro;
+ memset(acebin, 0, SIZEOF(acebin));
+ status = sys$parse(&d_rm->f); /* to get device for getdvi */
+ if ((1 & status))
+ {
+ devname.dsc$w_length = nam->nam$b_dev;
+ devname.dsc$a_pointer = nam->nam$l_dev;
+ devname.dsc$b_dtype = DSC$K_DTYPE_T;
+ devname.dsc$b_class = DSC$K_CLASS_S;
+ item_list.item[0].item_code = DVI$_DEVCLASS;
+ item_list.item[0].buffer_length = SIZEOF(devclass);
+ item_list.item[0].buffer_address = &devclass;
+ item_list.item[0].return_length_address = &devclassret;
+ item_list.item[1].item_code = DVI$_DEVCHAR;
+ item_list.item[1].buffer_length = SIZEOF(devchar);
+ item_list.item[1].buffer_address = &devchar;
+ item_list.item[1].return_length_address = &devcharret;
+ item_list.item[2].item_code = DVI$_DEVCHAR2;
+ item_list.item[2].buffer_length = SIZEOF(devchar2);
+ item_list.item[2].buffer_address = &devchar2;
+ item_list.item[2].return_length_address = &devchar2ret;
+ item_list.item[3].item_code = DVI$_DEVTYPE;
+ item_list.item[3].buffer_length = SIZEOF(devtype);
+ item_list.item[3].buffer_address = &devtype;
+ item_list.item[3].return_length_address = &devtyperet;
+ item_list.terminator = 0;
+ dvistat = sys$getdviw(EFN$C_ENF, NULL, &devname, &item_list, iosb, NULL, 0, 0);
+ if (SS$_NORMAL == dvistat)
+ dvistat = iosb[0];
+ if (SS$_NONLOCAL == dvistat || (SS$_NORMAL == dvistat &&
+ ((DC$_DISK != devclass || (DEV$M_NET & devchar) ||
+ (DEV$M_DAP | DEV$M_DFS) & devchar2) || /* UCX NFS sets DFS */
+ (DT$_FD1 <= devtype && DT$_FD8 >= devtype) ))) /* but not tcpware so check foreign disk */
+ { /* if not disk, dfs/nfs, or non local, create gets BADATTRIB in stv if acl buf and siz set */
+ noacl = TRUE;
+ }
+ } else /* let create/open report the problem */
+ noacl = TRUE;
+ if (DEV$M_NET & d_rm->f.fab$l_dev)
+ { /* need to release sys$parse channel if DECnet */
+ tmpfdns = d_rm->f.fab$b_dns;
+ d_rm->f.fab$b_dns = 0;
+ assert(0 == nam->nam$l_rlf);
+ nam->nam$l_rlf = 0;
+ nam->nam$b_nop |= NAM$M_SYNCHK;
+ status = sys$parse(&d_rm->f); /* give up channel */
+ d_rm->f.fab$b_dns = tmpfdns; /* restore */
+ nam->nam$b_nop &= ~NAM$M_SYNCHK;
+ }
+ if (noacl)
+ {
+ if (d_rm->largerecord && MAX_RMS_RECORDSIZE < d_rm->l_mrs)
+ rts_error(VARLSTCNT(1) ERR_RMWIDTHTOOBIG);
+ d_rm->largerecord = FALSE;
+ }
+ if (d_rm->largerecord && FAB$M_GET != d_rm->f.fab$b_fac)
+ { /* if readonly use format from existing file */
+ aceptr = acebin;
+ aceptr->ace$b_size = GTM_ACE_SIZE * SIZEOF(uint4);
+ aceptr->ace$b_type = ACE$C_INFO;
+ /* without NOPROPAGATE, new versions will get ACE,
+ PROTECTED prevents set acl /dele unless =all */
+ aceptr->ace$w_flags = ACE$M_NOPROPAGATE | ACE$M_PROTECTED;
+/* if HIDDEN, dir/sec does not display which may make it harder to check if problems
+ aceptr->ace$w_flags |= ACE$M_HIDDEN;
+*/
+ aceptr->ace$v_info_type = ACE$C_CUST; /* must be after flags */
+ aceptr->ace$w_application_facility = GTM_ACE_FAC; /* GTM error fac */
+ aceptr->ace$w_application_flags = GTM_ACE_BIGREC;
+ assert(SIZEOF(uint4) * GTM_ACE_LAB_OFF == (&aceptr->ace$t_info_start - (char *)aceptr));
+ acebin[GTM_ACE_LAB_OFF] = GTM_ACE_LABEL;
+ acebin[GTM_ACE_RFM_OFF] = d_rm->b_rfm;
+ acebin[GTM_ACE_MRS_OFF] = d_rm->l_mrs;
+ acebin[GTM_ACE_SIZE] = 0; /* terminate */
+ d_rm->f.fab$b_rfm = FAB$C_UDF;
+ d_rm->f.fab$w_mrs = 0;
+ }
+ if (!noacl)
+ { /* tape gets BADATTRIB in stv if acl buf and siz set */
+ xabpro.xab$l_aclbuf = acebin;
+ xabpro.xab$w_aclsiz = SIZEOF(acebin);
+ }
+ if (FAB$M_GET == d_rm->f.fab$b_fac)
+ {
+ xabfhc = cc$rms_xabfhc;
+ xabpro.xab$l_nxt = &xabfhc;
+ status = sys$open(&d_rm->f);
+ } else
+ {
+ xabpro.xab$w_pro = d_rm->promask;
+ status = sys$create(&d_rm->f);
+ }
+ nam->nam$l_esa = 0;
+ nam->nam$b_ess = 0;
+ nam->nam$b_esl = 0;
+ d_rm->f.fab$l_xab = 0;
+ switch (status)
+ {
+ case RMS$_NORMAL:
+ if (d_rm->f.fab$l_fop & FAB$M_MXV)
+ created = iod->dollar.zeof = TRUE;
+ break;
+
+ case RMS$_CRE_STM:
+ case RMS$_CREATED:
+ case RMS$_SUPERSEDE:
+ case RMS$_FILEPURGED:
+ if (d_rm->f.fab$l_dev & DEV$M_FOD)
+ created = iod->dollar.zeof = TRUE;
+ break;
+
+ case RMS$_ACT:
+ case RMS$_FLK:
+ return(FALSE);
+
+ default:
+ rts_error(VARLSTCNT(2) status, d_rm->f.fab$l_stv);
+ }
+ if (!noacl && (DEV$M_RND & d_rm->f.fab$l_dev) && !(DEV$M_NET & d_rm->f.fab$l_dev))
+ isdisk = TRUE; /* local disk */
+ else if (created && d_rm->largerecord && MAX_RMS_RECORDSIZE < d_rm->l_mrs)
+ rts_error(VARLSTCNT(1) ERR_RMWIDTHTOOBIG);
+ /* $create does not return the ACE: if a new file is created aclsts is IVACL */
+ /* if CIF and existing file has no acl aclsts ACLEMPTY */
+ /* if CIF and existing file has acl aclsts is NORMAL */
+ if (isdisk && ((created && SS$_IVACL == xabpro.xab$l_aclsts) || (0 != xabpro.xab$l_aclsts &&
+ (FAB$M_GET != d_rm->f.fab$b_fac && ((1 & xabpro.xab$l_aclsts) || SS$_ACLEMPTY != xabpro.xab$l_aclsts)))))
+ {
+ xabpro.xab$l_aclctx = 0; /* reset context */
+ d_rm->f.fab$l_xab = &xabpro;
+ status = sys$display(&d_rm->f);
+ d_rm->f.fab$l_xab = 0; /* prevent close error */
+ if (!(1 & status))
+ rts_error(VARLSTCNT(2) status, d_rm->f.fab$l_stv);
+ if (0 != xabpro.xab$l_aclsts && !(1 & xabpro.xab$l_aclsts) && SS$_ACLEMPTY != xabpro.xab$l_aclsts)
+ rts_error(VARLSTCNT(1) xabpro.xab$l_aclsts);
+ }
+ if (isdisk && (1 & status) && 0 != xabpro.xab$l_aclsts && !(1 & xabpro.xab$l_aclsts) &&
+ SS$_ACLEMPTY != xabpro.xab$l_aclsts)
+ rts_error(VARLSTCNT(1) xabpro.xab$l_aclsts);
+ if (isdisk && 0 != xabpro.xab$w_acllen && (1 & status)) /* acl and success */
+ {
+ if (SIZEOF(acebin) < xabpro.xab$w_acllen)
+ { /* get a new buffer big enough */
+ xabpro.xab$l_aclbuf = malloc(xabpro.xab$w_acllen);
+ xabpro.xab$w_aclsiz = xabpro.xab$w_acllen;
+ xabpro.xab$l_aclctx = 0; /* reset context */
+ d_rm->f.fab$l_xab = &xabpro;
+ status = sys$display(&d_rm->f);
+ d_rm->f.fab$l_xab = 0;
+ if (!(1 & status))
+ rts_error(VARLSTCNT(2) status, d_rm->f.fab$l_stv);
+ if (!(1 & xabpro.xab$l_aclsts))
+ rts_error(VARLSTCNT(1) xabpro.xab$l_aclsts);
+ }
+ acetop = (char *)xabpro.xab$l_aclbuf + xabpro.xab$w_acllen;
+ for (aceptr = xabpro.xab$l_aclbuf; aceptr < acetop; aceptr = (char *)aceptr + aceptr->ace$b_size)
+ {
+ if (0 == aceptr->ace$b_size)
+ break;
+ if (ACE$C_INFO == aceptr->ace$b_type && ACE$C_CUST == aceptr->ace$v_info_type
+ && GTM_ACE_FAC == aceptr->ace$w_application_facility
+ && GTM_ACE_BIGREC == aceptr->ace$w_application_flags)
+ { /* info for large records */
+ acebinptr = aceptr;
+ assert(GTM_ACE_LABEL == acebinptr[GTM_ACE_LAB_OFF]);
+ d_rm->largerecord = TRUE;
+ d_rm->b_rfm = (unsigned char)acebinptr[GTM_ACE_RFM_OFF];
+ d_rm->l_mrs = acebinptr[GTM_ACE_MRS_OFF];
+ acefound = TRUE;
+ break;
+ }
+ }
+ if (acebin != xabpro.xab$l_aclbuf)
+ { /* free larger buffer now */
+ free(xabpro.xab$l_aclbuf);
+ xabpro.xab$l_aclbuf = acebin;
+ xabpro.xab$w_aclsiz = SIZEOF(acebin);
+ }
+ }
+ if (!acefound)
+ {
+ if (!created)
+ { /* copy from exisiting file */
+ if (isdisk && d_rm->largerecord && FAB$C_UDF == d_rm->f.fab$b_rfm)
+ rts_error(VARLSTCNT(1) ERR_BIGNOACL); /* maybe lost in copy */
+ d_rm->b_rfm = d_rm->f.fab$b_rfm;
+ d_rm->l_mrs = d_rm->f.fab$w_mrs;
+ } else if (isdisk && d_rm->largerecord)
+ rts_error(VARLSTCNT(8) ERR_DEVOPENFAIL, 2, iol->len, iol->dollar_io,
+ ERR_TEXT, 2, LEN_AND_LIT("GTM ACE on new file disappeared - possible VMS problem"));
+ d_rm->largerecord = FALSE;
+ }
+/* smw does next overwriting of mrs make sense to RMS */
+ /* if not largerecord, read only, sequential, not magtape ... */
+ if (!d_rm->largerecord && (FAB$M_GET == d_rm->f.fab$b_fac) && (0 == d_rm->f.fab$w_mrs) && xabfhc.xab$w_lrl)
+ d_rm->l_mrs = d_rm->l_usz = d_rm->r.rab$w_usz = d_rm->f.fab$w_mrs = xabfhc.xab$w_lrl;
+
+ if (d_rm->largerecord)
+ { /* guess at a good blocks per IO */
+ uint4 blocksperrec;
+ blocksperrec = DIVIDE_ROUND_UP(d_rm->l_mrs, RMS_DISK_BLOCK);
+ if (RMS_MAX_MBC <= blocksperrec * 2)
+ d_rm->r.rab$b_mbc = RMS_MAX_MBC;
+ else if (RMS_DEF_MBC < blocksperrec * 2)
+ d_rm->r.rab$b_mbc = blocksperrec * 2;
+ }
+ status = sys$connect(&d_rm->r);
+ if (RMS$_NORMAL != status)
+ rts_error(VARLSTCNT(2) status, d_rm->r.rab$l_stv);
+ if (d_rm->r.rab$l_rop & RAB$M_EOF)
+ iod->dollar.zeof = TRUE;
+ if (ESC == iod->trans_name->dollar_io[0])
+ {
+ /* process permanent file...get real name */
+ status = sys$display(&d_rm->f);
+ if (status & 1)
+ {
+ devname.dsc$w_length = nam->nam$t_dvi[0];
+ devname.dsc$b_dtype = DSC$K_DTYPE_T;
+ devname.dsc$b_class = DSC$K_CLASS_S;
+ devname.dsc$a_pointer = &nam->nam$t_dvi[1];
+ outname.dsc$w_length = SIZEOF(resultant_name);
+ outname.dsc$b_dtype = DSC$K_DTYPE_T;
+ outname.dsc$b_class = DSC$K_CLASS_S;
+ outname.dsc$a_pointer = resultant_name;
+ status = lib$fid_to_name(&devname, &nam->nam$w_fid, & outname, &newtln.len, 0, 0);
+ if ((status & 1) && (0 != newtln.len))
+ {
+ newtln.addr = resultant_name;
+ iod->trans_name = get_log_name(&newtln, INSERT);
+ iod->trans_name->iod = iod;
+ }
+ }
+ } else
+ { /* smw since esl zeroed above this is dead code since early days */
+ if (nam->nam$b_esl && (iod->trans_name->len != nam->nam$b_esl ||
+ memcmp(&iod->trans_name->dollar_io[0], resultant_name, nam->nam$b_esl)))
+ {
+ newtln.addr = resultant_name;
+ newtln.len = nam->nam$b_esl;
+ iod->trans_name = get_log_name(&newtln, INSERT);
+ iod->trans_name->iod = iod;
+ }
+ }
+ if (0 == d_rm->l_mrs)
+ d_rm->l_mrs = iod->width;
+ iod->width = d_rm->l_usz = d_rm->l_mrs;
+ if (!d_rm->largerecord)
+ {
+ d_rm->r.rab$w_usz = d_rm->f.fab$w_mrs = d_rm->l_mrs;
+ if (FAB$C_VFC == d_rm->f.fab$b_rfm) /* have to leave two bytes for the fixed control */
+ iod->width = MIN(iod->width, VFC_MAX_RECLEN);
+ }
+ width = iod->width;
+ if (d_rm->largerecord)
+ {
+ width = ROUND_UP(width, SIZEOF(uint4));
+ if (FAB$C_VAR == d_rm->b_rfm)
+ width += SIZEOF(uint4); /* for count */
+ }
+ d_rm->bufsize = width + 1;
+ d_rm->inbuf = (char*)malloc(width + 1);
+ d_rm->outbuf_start = (char*)malloc(width + 1);
+ d_rm->inbuf_pos = d_rm->inbuf;
+ d_rm->inbuf_top = d_rm->inbuf + iod->width;
+ d_rm->outbuf_pos = d_rm->outbuf = d_rm->outbuf_start + (d_rm->largerecord && FAB$C_VAR == d_rm->b_rfm
+ ? SIZEOF(uint4) : 0);
+ d_rm->outbuf_top = d_rm->outbuf + iod->width;
+ d_rm->promask = xabpro.xab$w_pro;
+ iod->state = dev_open;
+ }
+ return TRUE;
+}
diff --git a/sr_vvms/iorm_put.c b/sr_vvms/iorm_put.c
new file mode 100644
index 0000000..659daea
--- /dev/null
+++ b/sr_vvms/iorm_put.c
@@ -0,0 +1,72 @@
+/****************************************************************
+ * *
+ * Copyright 2004, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/****************************************************************
+ * *
+ * iorm_put is a wrapper around the RMS sys$put routine to *
+ * implement the GT.M BIGRECORD file format. *
+ * *
+ * Argument: *
+ * iod io_desc structure *
+ * *
+ * Return: RMS$_NORMAL or RMS error status *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <rms.h>
+#include <devdef.h>
+#include "gtm_string.h"
+#include "io.h"
+#include "iormdef.h"
+
+int iorm_put(io_desc *iod)
+{
+ int4 stat;
+ unsigned int reclen;
+ d_rm_struct *rm_ptr;
+
+ rm_ptr = iod->dev_sp;
+ if (rm_ptr->f.fab$b_fac == FAB$M_GET)
+ return RMS$_FAC;
+ assert(rm_ptr->outbuf == rm_ptr->r.rab$l_rbf);
+ if (!rm_ptr->largerecord)
+ {
+ rm_ptr->r.rab$w_rsz = rm_ptr->l_rsz;
+ stat = sys$put(&rm_ptr->r);
+ } else
+ {
+ if (FAB$C_VAR == rm_ptr->b_rfm)
+ {
+ rm_ptr->r.rab$l_rbf -= SIZEOF(uint4); /* recordsize */
+ assert(rm_ptr->r.rab$l_rbf >= rm_ptr->outbuf_start);
+ *(uint4 *)rm_ptr->r.rab$l_rbf = rm_ptr->l_rsz;
+ rm_ptr->l_rsz += SIZEOF(uint4);
+ }
+ reclen = ROUND_UP2(rm_ptr->l_rsz, SIZEOF(uint4)); /* fix and var records on longword boundary */
+ if (reclen > rm_ptr->l_rsz)
+ {
+ assert((rm_ptr->r.rab$l_rbf + reclen) <= ROUND_UP((unsigned long)rm_ptr->outbuf_top, SIZEOF(uint4)));
+ memset(&rm_ptr->r.rab$l_rbf[rm_ptr->l_rsz], 0, reclen - rm_ptr->l_rsz); /* null pad */
+ }
+ do
+ {
+ rm_ptr->r.rab$w_rsz = (unsigned short)(MAX_RMS_UDF_RECORD < reclen
+ ? MAX_RMS_UDF_RECORD : reclen);
+ stat = sys$put(&rm_ptr->r);
+ if (RMS$_NORMAL != stat)
+ return stat;
+ rm_ptr->r.rab$l_rbf += rm_ptr->r.rab$w_rsz;
+ reclen -= (unsigned int)rm_ptr->r.rab$w_rsz;
+ } while (0 < reclen);
+ }
+ return stat;
+}
diff --git a/sr_vvms/iorm_rdone.c b/sr_vvms/iorm_rdone.c
new file mode 100644
index 0000000..4d5d4d7
--- /dev/null
+++ b/sr_vvms/iorm_rdone.c
@@ -0,0 +1,93 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2006 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <rms.h>
+
+#include "io.h"
+#include "iormdef.h"
+#include "iotimer.h"
+#include "stringpool.h"
+
+GBLREF io_pair io_curr_device;
+#define CR 13
+
+int iorm_rdone(mint *x, int4 timeout)
+{
+ io_desc *iod;
+ d_rm_struct *d_rm;
+ struct RAB *rab;
+ int4 stat;
+ int ret;
+
+ error_def(ERR_IOEOF);
+
+ assert(timeout >= 0);
+ iod = io_curr_device.in;
+ d_rm = (d_rm_struct *)io_curr_device.in->dev_sp;
+ assert(d_rm->inbuf_pos >= d_rm->inbuf);
+ assert(d_rm->inbuf_pos <= d_rm->inbuf_top);
+ /* if write buffer not empty, and there was no error */
+ if ((FAB$M_PUT == d_rm->r.rab$l_ctx) && d_rm->outbuf != d_rm->outbuf_pos
+ && !iod->dollar.za)
+ iorm_wteol(1, iod);
+ d_rm->r.rab$l_ctx = FAB$M_GET;
+ rab = &d_rm->r;
+ ret = TRUE;
+ if (d_rm->inbuf_pos == d_rm->inbuf_top || d_rm->inbuf_pos == d_rm->inbuf)
+ { /* no buffered input left */
+ rab->rab$l_ubf = d_rm->inbuf;
+ d_rm->l_usz = iod->width;
+ stat = iorm_get(iod, timeout);
+ switch (stat)
+ {
+ case RMS$_NORMAL:
+ d_rm->inbuf_top = d_rm->inbuf + d_rm->l_rsz;
+ *d_rm->inbuf_top++ = CR;
+ d_rm->inbuf_pos = d_rm->inbuf;
+ *x = (mint)*(unsigned char *)d_rm->inbuf_pos++;
+ iod->dollar.x = 1;
+ iod->dollar.y++;
+ iod->dollar.za = 0;
+ break;
+ case RMS$_TMO:
+ *x = (mint)-1;
+ iod->dollar.za = 9;
+ ret = FALSE;
+ break;
+ case RMS$_EOF:
+ *x = (mint)0;
+ if (iod->dollar.zeof)
+ {
+ iod->dollar.za = 9;
+ rts_error(VARLSTCNT(1) ERR_IOEOF);
+ }
+ iod->dollar.x = 0;
+ iod->dollar.y++;
+ iod->dollar.za = 0;
+ iod->dollar.zeof = TRUE;
+ if (iod->error_handler.len > 0)
+ rts_error(VARLSTCNT(1) ERR_IOEOF);
+ break;
+ default:
+ d_rm->inbuf_pos = d_rm->inbuf;
+ iod->dollar.za = 9;
+ rts_error(VARLSTCNT(2) stat, rab->rab$l_stv);
+ }
+ } else
+ {
+ *x = (mint)*(unsigned char *)d_rm->inbuf_pos++;
+ iod->dollar.x++;
+ iod->dollar.za = 0;
+ }
+ return ret;
+}
diff --git a/sr_vvms/iorm_read.c b/sr_vvms/iorm_read.c
new file mode 100644
index 0000000..51649fd
--- /dev/null
+++ b/sr_vvms/iorm_read.c
@@ -0,0 +1,100 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <rms.h>
+#include "gtm_string.h"
+
+#include "io.h"
+#include "iormdef.h"
+#include "iotimer.h"
+#include "stringpool.h"
+
+GBLREF spdesc stringpool;
+GBLREF io_pair io_curr_device;
+
+int iorm_read(mval *v, int4 timeout)
+{
+ io_desc *iod;
+ d_rm_struct *rm_ptr;
+ struct RAB *rab;
+ int4 stat;
+ int len;
+
+ error_def(ERR_IOEOF);
+
+ assert(stringpool.free >= stringpool.base);
+ assert(stringpool.free <= stringpool.top);
+ assert(timeout >= 0);
+ iod = io_curr_device.in;
+ rm_ptr = (d_rm_struct *)iod->dev_sp;
+ /* if write buffer not empty, and there was no error */
+ if ((FAB$M_PUT == rm_ptr->r.rab$l_ctx) && (rm_ptr->outbuf != rm_ptr->outbuf_pos) && !iod->dollar.za)
+ iorm_wteol(1, iod);
+
+ v->mvtype = MV_STR;
+ rm_ptr->r.rab$l_ctx = FAB$M_GET;
+
+ if (rm_ptr->inbuf != rm_ptr->inbuf_pos
+ && (0 != (len = rm_ptr->inbuf_top - rm_ptr->inbuf_pos)))
+ {
+ assert(len > 0);
+ ENSURE_STP_FREE_SPACE(len);
+ v->str.addr = stringpool.free;
+ memcpy(v->str.addr, rm_ptr->inbuf_pos, len);
+ rm_ptr->inbuf_pos = rm_ptr->inbuf;
+ v->str.len = len;
+ iod->dollar.x = 0;
+ iod->dollar.y++;
+ } else
+ {
+ /* ensure extra space for pad if not longword aligned */
+ ENSURE_STP_FREE_SPACE(iod->width + (rm_ptr->largerecord ? SIZEOF(uint4) : 0));
+ /* need to set usz and make sure width == mrs for fix */
+ rab = &rm_ptr->r;
+ rab->rab$l_ubf = stringpool.free;
+ stat = iorm_get(iod, timeout);
+ switch (stat)
+ {
+ case RMS$_NORMAL:
+ v->str.addr = stringpool.free;
+ v->str.len = rm_ptr->l_rsz;
+ iod->dollar.x = 0;
+ iod->dollar.y++;
+ iod->dollar.za = 0;
+ break;
+ case RMS$_TMO:
+ v->str.len = 0;
+ iod->dollar.za = 9;
+ return FALSE;
+ case RMS$_EOF:
+ v->str.len = 0;
+ if (iod->dollar.zeof)
+ {
+ iod->dollar.za = 9;
+ rts_error(VARLSTCNT(1) ERR_IOEOF);
+ }
+ iod->dollar.x = 0;
+ iod->dollar.za = 0;
+ iod->dollar.y++;
+ iod->dollar.zeof = TRUE;
+ if (iod->error_handler.len > 0)
+ rts_error(VARLSTCNT(1) ERR_IOEOF);
+ break;
+ default:
+ v->str.len = 0;
+ iod->dollar.za = 9;
+ rts_error(VARLSTCNT(2) stat, rab->rab$l_stv);
+ }
+ }
+ return TRUE;
+}
diff --git a/sr_vvms/iorm_readfl.c b/sr_vvms/iorm_readfl.c
new file mode 100644
index 0000000..c52d884
--- /dev/null
+++ b/sr_vvms/iorm_readfl.c
@@ -0,0 +1,107 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2006 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <rms.h>
+#include "gtm_string.h"
+
+#include "io.h"
+#include "iormdef.h"
+#include "iotimer.h"
+#include "stringpool.h"
+
+GBLREF io_pair io_curr_device;
+
+#define fl_copy(a, b) (a > b ? b : a)
+
+int iorm_readfl(mval *v, int4 length, int4 timeout)
+{
+ io_desc *iod;
+ d_rm_struct *d_rm;
+ struct RAB *rab;
+ int4 stat;
+ uint4 len, cp_len;
+
+ error_def(ERR_IOEOF);
+
+ assert(timeout >= 0);
+ v->mvtype = MV_STR;
+ iod = io_curr_device.in;
+
+ d_rm = (d_rm_struct *)io_curr_device.in->dev_sp;
+ /* if write buffer not empty, and there was no error */
+ if ((FAB$M_PUT == d_rm->r.rab$l_ctx) && d_rm->outbuf != d_rm->outbuf_pos
+ && !iod->dollar.za)
+ iorm_wteol(1, iod);
+ d_rm->r.rab$l_ctx = FAB$M_GET;
+ len = d_rm->inbuf_top - d_rm->inbuf_pos;
+ if ((d_rm->inbuf != d_rm->inbuf_pos) && (0 != len))
+ {
+ cp_len = fl_copy(length, len);
+ memcpy(v->str.addr, d_rm->inbuf_pos, cp_len);
+ if((d_rm->inbuf_pos += cp_len) >= d_rm->inbuf_top)
+ {
+ d_rm->inbuf_pos = d_rm->inbuf;
+ iod->dollar.y++;
+ iod->dollar.x = 0;
+ } else
+ iod->dollar.x += cp_len;
+ v->str.len = cp_len;
+ } else
+ {
+ rab = &d_rm->r;
+ rab->rab$l_ubf = d_rm->inbuf;
+ d_rm->l_usz = iod->width;
+ stat = iorm_get(iod, timeout);
+ switch (stat)
+ {
+ case RMS$_NORMAL:
+ d_rm->inbuf_top = d_rm->inbuf + d_rm->l_rsz;
+ if (length > d_rm->l_rsz)
+ length = d_rm->l_rsz;
+ v->str.len = length;
+ memcpy(v->str.addr, d_rm->inbuf, length);
+ if ((d_rm->inbuf_pos += length) >= d_rm->inbuf_top)
+ {
+ d_rm->inbuf_pos = d_rm->inbuf;
+ iod->dollar.y++;
+ iod->dollar.x = 0;
+ } else
+ iod->dollar.x += length;
+ iod->dollar.za = 0;
+ break;
+ case RMS$_TMO:
+ v->str.len = 0;
+ iod->dollar.za = 9;
+ return FALSE;
+ case RMS$_EOF:
+ v->str.len = 0;
+ if (iod->dollar.zeof)
+ {
+ iod->dollar.za = 9;
+ rts_error(VARLSTCNT(1) ERR_IOEOF);
+ }
+ iod->dollar.x = 0;
+ iod->dollar.y++;
+ iod->dollar.za = 0;
+ iod->dollar.zeof = TRUE;
+ if (iod->error_handler.len > 0)
+ rts_error(VARLSTCNT(1) ERR_IOEOF);
+ break;
+ default:
+ v->str.len = 0;
+ iod->dollar.za = 9;
+ rts_error(VARLSTCNT(2) stat, rab->rab$l_stv);
+ }
+ }
+ return TRUE;
+}
diff --git a/sr_vvms/iorm_use.c b/sr_vvms/iorm_use.c
new file mode 100644
index 0000000..ffb80d2
--- /dev/null
+++ b/sr_vvms/iorm_use.c
@@ -0,0 +1,280 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include <devdef.h>
+#include <rms.h>
+
+#include "io.h"
+#include "iormdef.h"
+#include "io_params.h"
+#include "stringpool.h"
+#include "copy.h"
+
+typedef struct
+{
+ unsigned short mem;
+ unsigned short grp;
+} uic_struct;
+
+LITREF unsigned char io_params_size[];
+
+void iorm_use(io_desc *iod, mval *pp)
+{
+ unsigned char c;
+ int4 width, length, blocksize;
+ int4 status;
+ d_rm_struct *rm_ptr;
+ struct RAB *r;
+ struct FAB *f;
+ int p_offset;
+ boolean_t shared_seen = FALSE;
+
+ error_def(ERR_DEVPARMNEG);
+ error_def(ERR_RMWIDTHPOS);
+ error_def(ERR_RMWIDTHTOOBIG);
+ error_def(ERR_RMNOBIGRECORD);
+ error_def(ERR_RMBIGSHARE);
+ error_def(ERR_MTBLKTOOBIG);
+ error_def(ERR_MTBLKTOOSM);
+
+ p_offset = 0;
+ rm_ptr = (d_rm_struct *)iod->dev_sp;
+ r = &rm_ptr->r;
+ f = &rm_ptr->f;
+ assert(r->rab$l_fab == f);
+ while (*(pp->str.addr + p_offset) != iop_eol)
+ {
+ assert(*(pp->str.addr + p_offset) < n_iops);
+ switch ((c = *(pp->str.addr + p_offset++)))
+ {
+ case iop_allocation:
+ if (iod->state != dev_open)
+ f->fab$l_alq = *(int4*)(pp->str.addr + p_offset);
+ break;
+ case iop_append:
+ if (iod->state != dev_open)
+ r->rab$l_rop |= RAB$M_EOF;
+ break;
+ case iop_blocksize:
+ if (iod->state != dev_open)
+ {
+ GET_LONG(blocksize, pp->str.addr + p_offset);
+ if (MAX_RMS_ANSI_BLOCK < blocksize)
+ rts_error(VARLSTCNT(1) ERR_MTBLKTOOBIG);
+ else if (MIN_RMS_ANSI_BLOCK > blocksize)
+ rts_error(VARLSTCNT(3) ERR_MTBLKTOOSM, 1, MIN_RMS_ANSI_BLOCK);
+ else
+ f->fab$w_bls = (unsigned short)blocksize;
+ }
+ break;
+ case iop_contiguous:
+ if (iod->state != dev_open)
+ {
+ f->fab$l_fop &= ~FAB$M_CBT;
+ f->fab$l_fop |= FAB$M_CTG;
+ }
+ break;
+ case iop_delete:
+ f->fab$l_fop |= FAB$M_DLT;
+ break;
+ case iop_extension:
+ GET_USHORT(f->fab$w_deq, pp->str.addr + p_offset);
+ break;
+ case iop_exception:
+ iod->error_handler.len = *(pp->str.addr + p_offset);
+ iod->error_handler.addr = pp->str.addr + p_offset + 1;
+ s2pool(&iod->error_handler);
+ break;
+ case iop_fixed:
+ if (iod->state != dev_open)
+ rm_ptr->f.fab$b_rfm = rm_ptr->b_rfm = FAB$C_FIX;
+ break;
+ case iop_length:
+ GET_LONG(length, pp->str.addr + p_offset);
+ if (length < 0)
+ rts_error(VARLSTCNT(1) ERR_DEVPARMNEG);
+ iod->length = length;
+ break;
+ case iop_newversion:
+ if (iod->state != dev_open)
+ {
+ f->fab$l_fop |= FAB$M_MXV;
+ f->fab$l_fop &= ~(FAB$M_CIF | FAB$M_SUP);
+ }
+ break;
+ case iop_nosequential:
+ break;
+ case iop_s_protection:
+ rm_ptr->promask &= ~(0x0F << XAB$V_SYS);
+ rm_ptr->promask |= ((~(unsigned char)*(pp->str.addr + p_offset) & 0x0000000F) << XAB$V_SYS);
+ break;
+ case iop_w_protection:
+ rm_ptr->promask &= ~(0x0F << XAB$V_WLD);
+ rm_ptr->promask |= ((~(unsigned char)*(pp->str.addr + p_offset) & 0x0000000F) << XAB$V_WLD);
+ break;
+ case iop_g_protection:
+ rm_ptr->promask &= ~(0x0F << XAB$V_GRP);
+ rm_ptr->promask |= ((~(unsigned char)*(pp->str.addr + p_offset) & 0x0000000F) << XAB$V_GRP);
+ break;
+ case iop_o_protection:
+ rm_ptr->promask &= ~(0x0F << XAB$V_OWN);
+ rm_ptr->promask |= ((~(unsigned char)*(pp->str.addr + p_offset) & 0x0000000F) << XAB$V_OWN);
+ break;
+ case iop_readonly:
+ if (iod->state != dev_open)
+ f->fab$b_fac = FAB$M_GET;
+ break;
+ case iop_noreadonly:
+ if (iod->state != dev_open)
+ f->fab$b_fac = FAB$M_GET | FAB$M_PUT | FAB$M_TRN;
+ break;
+ case iop_recordsize:
+ if (iod->state != dev_open)
+ {
+ GET_LONG(width, pp->str.addr + p_offset);
+ if (width <= 0)
+ rts_error(VARLSTCNT(1) ERR_RMWIDTHPOS);
+ iod->width = width;
+ if (MAX_RMS_RECORDSIZE >= width)
+ r->rab$w_usz = f->fab$w_mrs = (unsigned short)width;
+ else if (MAX_STRLEN < width)
+ rts_error(VARLSTCNT(1) ERR_RMWIDTHTOOBIG);
+ else if (!rm_ptr->largerecord)
+ rts_error(VARLSTCNT(1) ERR_RMNOBIGRECORD);
+ rm_ptr->l_usz = rm_ptr->l_mrs = width;
+ }
+ break;
+ case iop_shared:
+ if (iod->state != dev_open)
+ shared_seen = TRUE;
+ break;
+ case iop_spool:
+ f->fab$l_fop |= FAB$M_SPL;
+ break;
+ case iop_submit:
+ f->fab$l_fop |= FAB$M_SCF;
+ break;
+ case iop_rfa:
+ break;
+ case iop_space:
+ if (iod->state == dev_open && f->fab$l_dev & DEV$M_SQD)
+ {
+ GET_LONG(r->rab$l_bkt, pp->str.addr + p_offset);
+ if ((status = sys$space(r, 0, 0)) != RMS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+ r->rab$l_bkt = 0;
+ }
+ break;
+ case iop_uic:
+ {
+ unsigned char *ch, ct, *end;
+ uic_struct uic;
+ struct XABPRO *xabpro;
+
+ ch = pp->str.addr + p_offset;
+ ct = *ch++;
+ end = ch + ct;
+ uic.grp = uic.mem = 0;
+ xabpro = malloc(SIZEOF(struct XABPRO));
+ *xabpro = cc$rms_xabpro;
+/* g,m are octal - no matter currently since iorm_open overwrites fab xab */
+ while (*ch != ',' && ch < end)
+ uic.grp = (10 * uic.grp) + (*ch++ - '0');
+ if (*ch == ',')
+ {
+ while (++ch < end)
+ uic.mem = (10 * uic.mem) + (*ch - '0');
+ }
+ xabpro->xab$l_uic = *((int4 *)&uic);
+ f->fab$l_xab = xabpro;
+ break;
+ }
+ case iop_width:
+ if (iod->state == dev_open)
+ {
+ GET_LONG(width, pp->str.addr + p_offset);
+ if (width <= 0)
+ rts_error(VARLSTCNT(1) ERR_RMWIDTHPOS);
+ else if (width <= rm_ptr->l_mrs)
+ {
+ iorm_flush(iod);
+ rm_ptr->l_usz = iod->width = width;
+ if (!rm_ptr->largerecord)
+ r->rab$w_usz = (short)width;
+ iod->wrap = TRUE;
+ }
+ }
+ break;
+ case iop_wrap:
+ iod->wrap = TRUE;
+ break;
+ case iop_nowrap:
+ iod->wrap = FALSE;
+ break;
+ case iop_convert:
+ r->rab$l_rop |= RAB$M_CVT;
+ break;
+ case iop_rewind:
+ if (iod->state == dev_open && rm_ptr->f.fab$l_dev & DEV$M_FOD)
+ {
+ if (iod->dollar.zeof && rm_ptr->outbuf_pos > rm_ptr->outbuf)
+ iorm_wteol(1, iod);
+ sys$rewind(r);
+ iod->dollar.zeof = FALSE;
+ iod->dollar.y = 0;
+ iod->dollar.x = 0;
+ rm_ptr->outbuf_pos = rm_ptr->outbuf;
+ rm_ptr->r.rab$l_ctx = FAB$M_GET;
+ }
+ break;
+ case iop_truncate:
+ r->rab$l_rop |= RAB$M_TPT;
+ break;
+ case iop_notruncate:
+ r->rab$l_rop &= ~RAB$M_TPT;
+ break;
+ case iop_bigrecord:
+ if (iod->state != dev_open)
+ rm_ptr->largerecord = TRUE;
+ break;
+ case iop_nobigrecord:
+ if (iod->state != dev_open)
+ {
+ if (MAX_RMS_RECORDSIZE < rm_ptr->l_mrs)
+ rts_error(ERR_RMNOBIGRECORD);
+ rm_ptr->largerecord = FALSE;
+ }
+ break;
+ case iop_rfm:
+ break;
+ default:
+ break;
+ }
+ p_offset += ((IOP_VAR_SIZE == io_params_size[c]) ?
+ (unsigned char)*(pp->str.addr + p_offset) + 1 : io_params_size[c]);
+ }
+ if (shared_seen)
+ {
+ f->fab$b_shr = FAB$M_SHRGET;
+ if (rm_ptr->largerecord)
+ {
+ if (f->fab$b_fac & FAB$M_PUT)
+ {
+ rts_error(VARLSTCNT(1) ERR_RMBIGSHARE);
+ }
+ } else if ((f->fab$b_fac & FAB$M_PUT) == FALSE)
+ f->fab$b_shr |= FAB$M_SHRPUT;
+ }
+}/* eor */
diff --git a/sr_vvms/iorm_write.c b/sr_vvms/iorm_write.c
new file mode 100644
index 0000000..b2830a8
--- /dev/null
+++ b/sr_vvms/iorm_write.c
@@ -0,0 +1,63 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include <rms.h>
+#include "io.h"
+#include "iormdef.h"
+#include <devdef.h>
+
+GBLREF io_pair io_curr_device;
+error_def(ERR_NOTTOEOFONPUT);
+error_def(ERR_DEVICEREADONLY);
+
+void iorm_write(mstr *v)
+{
+ unsigned char *inpt;
+ io_desc *iod;
+ int inlen, outlen, n;
+ d_rm_struct *rm_ptr;
+
+ iod = io_curr_device.out;
+ rm_ptr = (d_rm_struct *) iod->dev_sp;
+ if (rm_ptr->f.fab$b_fac == FAB$M_GET)
+ rts_error(VARLSTCNT(1) ERR_DEVICEREADONLY);
+
+ rm_ptr->r.rab$l_ctx = FAB$M_PUT;
+ if (!iod->dollar.zeof && rm_ptr->f.fab$l_dev & DEV$M_FOD
+ && !(rm_ptr->r.rab$l_rop & RAB$M_TPT))
+ {
+ iod->dollar.za = 9;
+ rts_error(VARLSTCNT(1) ERR_NOTTOEOFONPUT);
+ }
+ inlen = v->len;
+ outlen = iod->width - (rm_ptr->outbuf_pos - rm_ptr->outbuf);
+ if ( ! iod->wrap && inlen > outlen)
+ inlen = outlen;
+ if (!inlen)
+ return;
+ for (inpt = v->addr ; ; inpt += n)
+ {
+ n = (inlen > outlen) ? outlen : inlen;
+ memcpy(rm_ptr->outbuf_pos, inpt, n);
+ iod->dollar.x += n;
+ rm_ptr->outbuf_pos +=n;
+ if ((inlen -= n) <= 0)
+ break;
+ iorm_wteol(1, iod);
+ outlen = iod->width - (rm_ptr->outbuf_pos - rm_ptr->outbuf);
+ }
+ iod->dollar.za = 0;
+ return;
+}
diff --git a/sr_vvms/iorm_wteol.c b/sr_vvms/iorm_wteol.c
new file mode 100644
index 0000000..426a9d7
--- /dev/null
+++ b/sr_vvms/iorm_wteol.c
@@ -0,0 +1,73 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <rms.h>
+#include <devdef.h>
+#include "gtm_string.h"
+#include "io.h"
+#include "iormdef.h"
+error_def(ERR_NOTTOEOFONPUT);
+error_def(ERR_DEVICEREADONLY);
+
+void iorm_wteol(int4 n_eol, io_desc *iod)
+{
+ struct RAB *r;
+ int4 stat;
+ int reclen;
+ int4 i;
+ d_rm_struct *rm_ptr;
+
+ rm_ptr = iod->dev_sp;
+ if (rm_ptr->f.fab$b_fac == FAB$M_GET)
+ rts_error(VARLSTCNT(1) ERR_DEVICEREADONLY);
+ r = &rm_ptr->r;
+ r->rab$l_rbf = rm_ptr->outbuf;
+ r->rab$l_ctx = FAB$M_PUT;
+ if (!iod->dollar.zeof && rm_ptr->f.fab$l_dev & DEV$M_FOD
+ && !(rm_ptr->r.rab$l_rop & RAB$M_TPT))
+ {
+ iod->dollar.za = 9;
+ rts_error(VARLSTCNT(1) ERR_NOTTOEOFONPUT);
+ }
+
+ for (i = 0; i < n_eol; i++)
+ {
+ reclen = rm_ptr->outbuf_pos - rm_ptr->outbuf;
+ if (rm_ptr->b_rfm != FAB$C_FIX)
+ rm_ptr->l_rsz = reclen;
+ else
+ {
+ reclen = rm_ptr->l_mrs - reclen;
+ rm_ptr->l_rsz = rm_ptr->l_mrs;
+ if (reclen > 0)
+ memset(rm_ptr->outbuf_pos, SP, reclen);
+ }
+ stat = iorm_put(iod);
+ switch (stat)
+ {
+ case RMS$_NORMAL:
+ break;
+ default:
+ rm_ptr->outbuf_pos = rm_ptr->outbuf;
+ iod->dollar.za = 9;
+ rts_error(VARLSTCNT(2) stat, r->rab$l_stv);
+ }
+ rm_ptr->outbuf_pos = rm_ptr->outbuf;
+ }
+
+ iod->dollar.za = 0;
+ iod->dollar.x = 0;
+ iod->dollar.y += n_eol;
+ if (iod->length)
+ iod->dollar.y %= iod->length;
+ return;
+}
diff --git a/sr_vvms/iormdef.h b/sr_vvms/iormdef.h
new file mode 100644
index 0000000..cea0ed9
--- /dev/null
+++ b/sr_vvms/iormdef.h
@@ -0,0 +1,55 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2004 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#define DEF_RM_WIDTH 32767
+#define DEF_RM_LENGTH 66
+#define MAX_RMS_RECORDSIZE 32767
+#define MAX_RMS_UDF_RECORD 65535
+#define MAX_RMS_ANSI_BLOCK 65635
+#define MIN_RMS_ANSI_BLOCK 14
+#define RMS_DISK_BLOCK 512
+#define RMS_DEF_MBC 16
+#define RMS_MAX_MBC 127
+
+#define GTM_ACE_BIGREC 1 /* application flag */
+#define GTM_ACE_FAC 0xF6 /* application facility */
+#define GTM_ACE_LABEL 'GTMB'
+#define GTM_ACE_LAB_OFF 2 /* ACE$K_LENGTH / sizeof uint4 */
+#define GTM_ACE_RFM_OFF 3
+#define GTM_ACE_MRS_OFF 4
+#define GTM_ACE_SIZE 5
+
+/* ***************************************************** */
+/* *********** structure for RMS driver **************** */
+/* ***************************************************** */
+
+typedef struct
+{
+ struct RAB r;
+ struct FAB f;
+ unsigned int l_mrs; /* fab mrs */
+ unsigned int l_rsz; /* rab rsz */
+ unsigned int l_usz; /* rab usz */
+ boolean_t largerecord;
+ unsigned short promask;
+ char b_rfm; /* logical fab rfm */
+ uint4 bufsize; /* size of buffers */
+ char *outbuf_start; /* always real start of outbuf */
+ char *outbuf;
+ char *outbuf_pos;
+ char *outbuf_top; /* smw 20031119 not used */
+ char *inbuf;
+ char *inbuf_pos;
+ char *inbuf_top;
+ char *block_buffer; /* used for large records */
+}d_rm_struct; /* rms */
+
+int4 iorm_jbc(struct NAM *nam, mval *pp, mstr *que, bool delete);
diff --git a/sr_vvms/iosb_disk.h b/sr_vvms/iosb_disk.h
new file mode 100644
index 0000000..8c51a3b
--- /dev/null
+++ b/sr_vvms/iosb_disk.h
@@ -0,0 +1,26 @@
+/****************************************************************
+ * *
+ * Copyright 2003 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+#ifndef IOSB_DISK_H_INCLUDED
+#define IOSB_DISK_H_INCLUDED
+
+#pragma member_alignment save
+#pragma nomember_alignment
+
+typedef struct io_status_block_disk_struct
+{
+ unsigned short cond;
+ unsigned int length;
+ unsigned short devdepend;
+} io_status_block_disk;
+
+#pragma member_alignment restore
+
+#endif /* IOSB_DISK_H_INCLUDED */
diff --git a/sr_vvms/iosize.h b/sr_vvms/iosize.h
new file mode 100644
index 0000000..8599400
--- /dev/null
+++ b/sr_vvms/iosize.h
@@ -0,0 +1,12 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#define LEGAL_IO_SIZE(X) ((((int4)X) + 7) & -8)
diff --git a/sr_vvms/iosp.h b/sr_vvms/iosp.h
new file mode 100644
index 0000000..478625a
--- /dev/null
+++ b/sr_vvms/iosp.h
@@ -0,0 +1,25 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2003 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+
+#define TRL_OFF 4
+
+#define SS_NORMAL 1
+#define SS_NOLOGNAM 444
+#define SS_ENDOFFILE 2160
+#define SS_ENDOFTAPE 2168
+
+/* parameters for io_rundown() */
+#define NORMAL_RUNDOWN 0
+#define RUNDOWN_EXCEPT_STD 1
+
+#define SYSCALL_SUCCESS(STATUS) (1 & (STATUS))
+#define SYSCALL_ERROR(STATUS) (!(1 & (STATUS)))
diff --git a/sr_vvms/iotcp_select.h b/sr_vvms/iotcp_select.h
new file mode 100644
index 0000000..d4253fa
--- /dev/null
+++ b/sr_vvms/iotcp_select.h
@@ -0,0 +1,49 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef FD_SET
+/*
+ * from BSD 4.3 (could grab a copy from CCKIM for 4.2)
+ *
+ *
+ */
+
+#ifndef NBBY
+#define NBBY 8 /* number of bits in a byte */
+#endif
+/*
+ * Select uses bit masks of file descriptors in longs.
+ * These macros manipulate such bit fields (the filesystem macros use chars).
+ * FD_SETSIZE may be defined by the user, but the default here
+ * should be >= NOFILE (param.h).
+ */
+#ifndef FD_SETSIZE
+#define FD_SETSIZE 256
+#endif
+
+typedef uint4 fd_mask;
+#define NFDBITS (SIZEOF(fd_mask) * NBBY) /* bits per mask */
+#ifndef howmany
+#define howmany(x, y) (((x)+((y)-1))/(y))
+#endif
+
+#ifndef fd_set
+typedef struct fd_set {
+ fd_mask fds_bits[howmany(FD_SETSIZE, NFDBITS)];
+} fd_set;
+#endif
+
+#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
+#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
+#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
+#define FD_ZERO(p) memset((char *)(p), '\0', SIZEOF(*(p)))
+#undef NEED_FD_SET
+#endif /* ifndef(FD_SET) */
diff --git a/sr_vvms/iotcp_string.c b/sr_vvms/iotcp_string.c
new file mode 100644
index 0000000..65a6ea2
--- /dev/null
+++ b/sr_vvms/iotcp_string.c
@@ -0,0 +1,107 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* ZY: self-defined string operation routines
+ * since string routines cause multiply-defined problem on VMS
+ */
+
+#include "mdef.h" /* 96/12/30 smw for memcmp */
+
+char *vmssp_strcpy(char *s1, char *s2)
+{
+ char *p, *q;
+ p = s1;
+ q = s2;
+ for (; *q; ++q)
+ *p++ = *q;
+ *p = '\0';
+ return(s1);
+}
+
+
+char *vmssp_strcat(char *s1, char *s2)
+{
+ char *p, *q;
+ for (p=s1; *p; ++p);
+ for (q=s2; *q; ++q)
+ *p++ = *q;
+ *p = '\0';
+ return(s1);
+}
+
+
+int vmssp_sprintf(char *s1, char *format, char *sour, unsigned short num)
+{
+ char correct_format[10];
+ char *str, *p, q[10];
+ int t, i, j;
+
+ vmssp_strcpy(correct_format, "%s,%d");
+ if (memcmp(format, correct_format, 6))
+ /* How to print error by GTM staff?
+ printf("Error: sprintf format is not correct!\n");
+ */
+ return(-1);
+
+ str = s1;
+ for (p=sour,i=0; *p; p++,i++)
+ *str++ = *p;
+ *str++ = ',';
+ i++;
+ for(t=num,j=0; t>9; )
+ {
+ q[j++] = (t % 10) + '0';
+ t = (int)t/10;
+ }
+ q[j] = t + '0';
+ for (; j>=0 ; --j, ++i)
+ *str++ = q[j];
+ *str = '\0';
+ return(i);
+}
+
+
+int vmssp_sscanf(char *str, char *format, char *rel, short *num)
+{
+ char correct_format[10];
+ char *p;
+ int t;
+
+ if (!(*str)) /* empty string, unix returns EOF */
+ return(-1);
+
+ vmssp_strcpy(correct_format, "%[^,],%hu");
+ if (memcmp(format, correct_format, 10))
+ /* How to print error by GTM staff?
+ printf("Error: sscanf format is not correct!\n");
+ */
+ return(-1);
+
+ for (p=str; *p && *p!=','; p++)
+ *rel++ = *p;
+ *rel = '\0';
+ if (!(*p))
+ /* no , match */
+ return(-1);
+ else
+ {
+ for (p++, *num=0; *p; p++)
+ {
+ t = *p - '0';
+ *num = *num * 10 + t;
+ }
+ if (*str == ',')
+ return(1);
+ else
+ return(2);
+ }
+}
+
diff --git a/sr_vvms/iott_cancel_read.c b/sr_vvms/iott_cancel_read.c
new file mode 100644
index 0000000..e25d656
--- /dev/null
+++ b/sr_vvms/iott_cancel_read.c
@@ -0,0 +1,39 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <iodef.h>
+#include <ssdef.h>
+#include "io.h"
+#include "iottdef.h"
+#include "efn.h"
+
+void iott_cancel_read(io_ptr)
+io_desc *io_ptr;
+
+/* This routine should always be followed by an iott_resetast, which
+includes a qiow that we would prefer not to do within the AST */
+{
+ uint4 status;
+ d_tt_struct *tt_ptr;
+
+ tt_ptr = (d_tt_struct*)(io_ptr->dev_sp);
+ if (!tt_ptr->stat_blk.status)
+ {
+#ifdef DEBUG
+/* this is for an assert that verifies a reliance on VMS IOSB maintenance */
+ tt_ptr->read_timer = FALSE;
+#endif
+ if ((status = sys$cancel(tt_ptr->channel)) != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+ }
+ return;
+}
diff --git a/sr_vvms/iott_clockfini.c b/sr_vvms/iott_clockfini.c
new file mode 100644
index 0000000..75c7d29
--- /dev/null
+++ b/sr_vvms/iott_clockfini.c
@@ -0,0 +1,21 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "io.h"
+#include "iottdef.h"
+
+void iott_clockfini( d_tt_struct *tt_ptr)
+{
+ tt_ptr->clock_on = FALSE;
+ iott_wtstart(tt_ptr);
+ return;
+}
diff --git a/sr_vvms/iott_close.c b/sr_vvms/iott_close.c
new file mode 100644
index 0000000..35af912
--- /dev/null
+++ b/sr_vvms/iott_close.c
@@ -0,0 +1,111 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <iodef.h>
+#include <ssdef.h>
+#include <trmdef.h>
+#include <ttdef.h>
+#include <tt2def.h>
+#include <efndef.h>
+
+
+#include "efn.h"
+#include "io.h"
+#include "iottdef.h"
+#include "io_params.h"
+#include "outofband.h"
+#include "stringpool.h"
+
+GBLREF short astq_dyn_alloc;
+GBLREF short astq_dyn_avail;
+GBLREF io_pair io_std_device;
+GBLREF uint4 std_dev_outofband_msk;
+LITREF unsigned char io_params_size[];
+
+void iott_close(io_desc *v, mval *pp) /* exception is the only deviceparameter allowed */
+{
+ unsigned short iosb[4];
+ uint4 dummy_msk, enable_msk, status;
+ d_tt_struct *tt_ptr;
+ t_cap s_mode;
+ params ch;
+ int p_offset;
+
+ assert(v->type == tt);
+ if (v->state != dev_open)
+ return;
+
+ assert((v->pair.in == v) || (v->pair.out == v));
+ tt_ptr = (d_tt_struct *)(v->dev_sp);
+
+ if (v->pair.out == v)
+ {
+ status = sys$dclast(iott_wtclose, tt_ptr, 0);
+ if (status != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+ }
+
+ if (v->pair.in == v && tt_ptr->term_chars_twisted)
+ {
+ status = sys$qiow(EFN$C_ENF, tt_ptr->channel, IO$_SENSEMODE,
+ iosb, 0, 0, &s_mode, 12, 0, 0, 0, 0);
+ if (status == SS$_NORMAL)
+ status = iosb[0];
+ if (status != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+ s_mode.ext_cap &= (~TT2$M_PASTHRU & ~TT2$M_EDITING);
+ s_mode.ext_cap |= (tt_ptr->ext_cap & (TT2$M_PASTHRU | TT2$M_EDITING));
+ s_mode.term_char &= (~TT$M_ESCAPE);
+ s_mode.term_char |= (tt_ptr->term_char & TT$M_ESCAPE);
+ status = sys$qiow(EFN$C_ENF, tt_ptr->channel, IO$_SETMODE,
+ iosb, 0, 0, &s_mode, 12, 0, 0, 0, 0);
+ if (status == SS$_NORMAL)
+ status = iosb[0];
+ if (status != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+ }
+
+ if (v->pair.in == io_std_device.in)
+ {
+ enable_msk = std_dev_outofband_msk & CTRLY_MSK;
+ if (enable_msk == CTRLY_MSK)
+ status = lib$enable_ctrl(&enable_msk, &dummy_msk);
+ if (status != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+ }
+
+ status = sys$dassgn(tt_ptr->channel);
+ if (status != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+
+ p_offset = 0;
+ while (*(pp->str.addr + p_offset) != iop_eol)
+ {
+ if ((ch = *(pp->str.addr + p_offset++)) == iop_exception)
+ {
+ v->error_handler.len = *(pp->str.addr + p_offset);
+ v->error_handler.addr = pp->str.addr + p_offset + 1;
+ s2pool(&v->error_handler);
+ }
+ p_offset += ((IOP_VAR_SIZE == io_params_size[ch]) ?
+ (unsigned char)*(pp->str.addr + p_offset) + 1 : io_params_size[ch]);
+ }
+
+ v->state = dev_closed;
+ astq_dyn_alloc += TERMINAL_STATIC_ASTS;
+ astq_dyn_avail += TERMINAL_STATIC_ASTS;
+ free(tt_ptr->sb_buffer);
+ free(tt_ptr->io_buffer);
+
+ return;
+}
diff --git a/sr_vvms/iott_flush.c b/sr_vvms/iott_flush.c
new file mode 100644
index 0000000..5a0ec37
--- /dev/null
+++ b/sr_vvms/iott_flush.c
@@ -0,0 +1,73 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <iodef.h>
+#include <ssdef.h>
+#include <efndef.h>
+
+#include "io.h"
+#include "iottdef.h"
+#include "xfer_enum.h"
+#include "deferred_events.h"
+
+GBLREF io_pair io_curr_device;
+GBLREF io_pair io_std_device;
+GBLREF bool prin_out_dev_failure;
+GBLREF int (*xfer_table[])();
+
+void iott_flush(io_desc *ioptr)
+{
+ void op_fetchintrrpt(), op_startintrrpt(), op_forintrrpt();
+ char *c_ptr;
+ short iosb[4], length;
+ uint4 status;
+ d_tt_struct *tt_ptr;
+
+ tt_ptr = (d_tt_struct*)ioptr->dev_sp;
+ sys$cantim(tt_ptr, 0);
+ tt_ptr->clock_on = FALSE;
+ if (tt_ptr->io_free != tt_ptr->io_inuse)
+ {
+ c_ptr = tt_ptr->io_inuse;
+ if (tt_ptr->io_free < tt_ptr->io_inuse)
+ {
+ length = tt_ptr->io_buftop - tt_ptr->io_inuse;
+ tt_ptr->io_inuse = tt_ptr->io_buffer;
+ } else
+ {
+ length = tt_ptr->io_free - tt_ptr->io_inuse;
+ tt_ptr->io_inuse = tt_ptr->io_free;
+ }
+ tt_ptr->io_pending = c_ptr + length;
+ if (tt_ptr->io_pending == tt_ptr->io_buftop)
+ tt_ptr->io_pending = tt_ptr->io_buffer;
+ status = sys$qiow(EFN$C_ENF, tt_ptr->channel, tt_ptr->write_mask, iosb, 0, 0, c_ptr, length, 0, 0, 0, 0);
+ if (status & 1)
+ status = iosb[0];
+ if (status & 1)
+ prin_out_dev_failure = FALSE;
+ else
+ {
+ if (io_curr_device.out == io_std_device.out)
+ {
+ if (prin_out_dev_failure)
+ sys$exit(status);
+ else
+ prin_out_dev_failure = TRUE;
+ }
+ xfer_set_handlers(tt_write_error_event, tt_write_error_set, status);
+ }
+ } else
+ while (tt_ptr->sb_free != tt_ptr->sb_pending)
+ sys$hiber();
+}
diff --git a/sr_vvms/iott_open.c b/sr_vvms/iott_open.c
new file mode 100644
index 0000000..b5ab494
--- /dev/null
+++ b/sr_vvms/iott_open.c
@@ -0,0 +1,254 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <dcdef.h>
+#include <descrip.h>
+#include <dvidef.h>
+#include <iodef.h>
+#include <smgtrmptr.h>
+#include <ssdef.h>
+#include <trmdef.h>
+#include <ttdef.h>
+#include <tt2def.h>
+#include <efndef.h>
+
+#include "io.h"
+#include "iotimer.h"
+#include "io_params.h"
+#include "iottdef.h"
+#include "vmsdtype.h"
+#include "stringpool.h"
+
+GBLREF short astq_dyn_avail;
+GBLREF short astq_dyn_alloc;
+GBLREF int4 spc_inp_prc;
+GBLREF io_log_name *io_root_log_name;
+GBLREF io_pair io_std_device;
+
+LITREF unsigned char io_params_size[];
+
+error_def(ERR_TERMASTQUOTA);
+
+short iott_open(io_log_name *dev_name, mval *pp, int fd, mval *mspace, int4 timeout)
+{
+ bool ast_get_static(int); /* TODO; move to a header */
+ unsigned char buf[256], ch, sensemode[8];
+ short dummy;
+ int4 bufsz, devtype, buflen;
+ uint4 status;
+ unsigned int req_code;
+ d_tt_struct *tt_ptr;
+ io_desc *ioptr;
+ iosb dvisb;
+ t_cap t_mode;
+ int p_offset;
+ struct
+ {
+ item_list_3 item[1];
+ int4 terminator;
+ } item_list;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ ioptr = dev_name->iod;
+ if (dev_never_opened == ioptr->state)
+ ioptr->dev_sp = (d_tt_struct *)(malloc(SIZEOF(d_tt_struct)));
+ tt_ptr = (d_tt_struct *)ioptr->dev_sp;
+ if (dev_open != ioptr->state)
+ {
+ short channel;
+ $DESCRIPTOR(file_name, "");
+ if (FALSE == ast_get_static(TERMINAL_STATIC_ASTS))
+ rts_error(VARLSTCNT(1) ERR_TERMASTQUOTA);
+ file_name.dsc$a_pointer = dev_name->dollar_io;
+ file_name.dsc$w_length = (unsigned short)dev_name->len;
+ if (SS$_DEVALLOC == (status = sys$assign(&file_name, &channel, 0, 0))
+ || (SS$_INSFMEM == status) || (SS$_NOIOCHAN == status))
+ {
+ astq_dyn_avail += TERMINAL_STATIC_ASTS;
+ astq_dyn_alloc += TERMINAL_STATIC_ASTS;
+ return FALSE;
+ }
+ if ((SS$_NORMAL != status) && (SS$_REMOTE != status))
+ {
+ astq_dyn_avail += TERMINAL_STATIC_ASTS;
+ rts_error(VARLSTCNT(1) status);
+ }
+ tt_ptr->channel = (int4)channel;
+ tt_ptr->io_pending = tt_ptr->io_inuse =
+ tt_ptr->io_free = tt_ptr->io_buffer = malloc(RING_BUF_SZ);
+ tt_ptr->io_buftop = tt_ptr->io_buffer + RING_BUF_SZ;
+ tt_ptr->sb_pending = tt_ptr->sb_free = tt_ptr->sb_buffer =
+ malloc(IOSB_BUF_SZ * SIZEOF(iosb_struct));
+ tt_ptr->sb_buftop = tt_ptr->sb_buffer + IOSB_BUF_SZ;
+ }
+ if (dev_never_opened == ioptr->state)
+ {
+ status = sys$qiow(EFN$C_ENF, tt_ptr->channel, IO$_SENSEMODE,
+ &tt_ptr->stat_blk, 0, 0, &t_mode, 12, 0, 0, 0, 0);
+ if (SS$_NORMAL == status)
+ status = tt_ptr->stat_blk.status;
+ if (SS$_NORMAL != status)
+ {
+ astq_dyn_avail += TERMINAL_STATIC_ASTS;
+ rts_error(VARLSTCNT(1) status);
+ }
+ tt_ptr->read_mask = IO_FUNC_R;
+ tt_ptr->write_mask = IO_FUNC_W;
+ tt_ptr->clock_on = FALSE;
+ tt_ptr->term_char = t_mode.term_char;
+ tt_ptr->ext_cap = t_mode.ext_cap;
+ ioptr->width = t_mode.pg_width;
+ ioptr->length = t_mode.pg_length;
+ tt_ptr->in_buf_sz = TTDEF_BUF_SZ;
+ tt_ptr->term_chars_twisted = FALSE;
+ tt_ptr->enbld_outofbands.x = 0;
+ if ((spc_inp_prc & (SHFT_MSK << CTRL_U)) && (tt_ptr->term_char & TT$M_SCOPE)
+ && !(tt_ptr->ext_cap & TT2$M_PASTHRU))
+ tt_ptr->ctrlu_msk = (SHFT_MSK << CTRL_U);
+ else
+ tt_ptr->ctrlu_msk = 0;
+ if (io_std_device.in)
+ /* if this is the principal device, io_std_device.in is not yet set up, therefore
+ the resetast is done later in term_setup so that it can pick the correct handler */
+ iott_resetast(ioptr);
+ status = sys$qiow(EFN$C_ENF, tt_ptr->channel
+ ,IO$_SENSEMODE|IO$M_RD_MODEM
+ ,&tt_ptr->stat_blk, 0, 0
+ ,sensemode
+ ,0, 0, 0, 0, 0);
+ /* The first time this code is called is to open the principal device
+ * and io_root_log_name->iod will be == 0, when that is true we do
+ * not want to do the lat connect even if it is a lat device */
+ if ((SS$_NORMAL == status) && (SS$_NORMAL == tt_ptr->stat_blk.status) &&
+ (DT$_LAT == sensemode[0]) && (0 != io_root_log_name->iod))
+ {
+ status = sys$qiow(EFN$C_ENF, tt_ptr->channel,
+ IO$_TTY_PORT|IO$M_LT_CONNECT,
+ &tt_ptr->stat_blk, 0, 0, 0, 0, 0, 0, 0, 0);
+ /* If we try to open the principal device with a statement like
+ * open "LTA66:" we will come through here and will get the
+ * illegal io function error...just ignore it */
+ if (SS$_NORMAL == status)
+ status = tt_ptr->stat_blk.status;
+ if ((SS$_NORMAL != status) && (SS$_ILLIOFUNC != status))
+ {
+ astq_dyn_avail += TERMINAL_STATIC_ASTS;
+ rts_error(VARLSTCNT(1) status);
+ }
+ }
+ item_list.item[0].buffer_length = SIZEOF(devtype);
+ item_list.item[0].item_code = DVI$_DEVTYPE;
+ item_list.item[0].buffer_address = &devtype;
+ item_list.item[0].return_length_address = &dummy;
+ item_list.terminator = 0;
+ status = sys$getdviw(EFN$C_ENF, tt_ptr->channel, 0, &item_list, &dvisb, 0, 0, 0);
+ if (SS$_NORMAL == status)
+ status = dvisb.status;
+ if (SS$_NORMAL != status)
+ rts_error(VARLSTCNT(1) status);
+ status = smg$init_term_table_by_type(&devtype, &tt_ptr->term_tab_entry, 0);
+ if (!(status & 1))
+ {
+ tt_ptr->erase_to_end_line.len = 0;
+ tt_ptr->key_up_arrow.len = 0;
+ tt_ptr->key_down_arrow.len = 0;
+ tt_ptr->clearscreen.len = 0;
+ } else
+ {
+ bufsz = SIZEOF(buf);
+ req_code = SMG$K_ERASE_TO_END_LINE;
+ status = smg$get_term_data(&tt_ptr->term_tab_entry, &req_code, &bufsz, &buflen, buf, 0);
+ if (status & 1)
+ {
+ tt_ptr->erase_to_end_line.len = buflen;
+ tt_ptr->erase_to_end_line.addr = malloc(tt_ptr->erase_to_end_line.len);
+ memcpy(tt_ptr->erase_to_end_line.addr, buf, buflen);
+ } else
+ tt_ptr->erase_to_end_line.len = 0;
+ req_code = SMG$K_KEY_UP_ARROW;
+ status = smg$get_term_data(&tt_ptr->term_tab_entry, &req_code, &bufsz, &buflen, buf, 0);
+ if (status & 1)
+ {
+ tt_ptr->key_up_arrow.len = buflen;
+ tt_ptr->key_up_arrow.addr = malloc(tt_ptr->key_up_arrow.len);
+ memcpy(tt_ptr->key_up_arrow.addr, buf, buflen);
+ } else
+ tt_ptr->key_up_arrow.len = 0;
+ req_code = SMG$K_KEY_DOWN_ARROW;
+ status = smg$get_term_data(&tt_ptr->term_tab_entry, &req_code, &bufsz, &buflen, buf, 0);
+ if (status & 1)
+ {
+ tt_ptr->key_down_arrow.len = buflen;
+ tt_ptr->key_down_arrow.addr = malloc(tt_ptr->key_down_arrow.len);
+ memcpy(tt_ptr->key_down_arrow.addr, buf, buflen);
+ } else
+ tt_ptr->key_down_arrow.len = 0;
+ req_code = SMG$K_ERASE_TO_END_DISPLAY;
+ status = smg$get_term_data(&tt_ptr->term_tab_entry, &req_code, &bufsz, &buflen, buf, 0);
+ if (status & 1)
+ {
+ tt_ptr->clearscreen.len = buflen;
+ tt_ptr->clearscreen.addr = malloc(tt_ptr->clearscreen.len);
+ memcpy(tt_ptr->clearscreen.addr, buf, buflen);
+ } else
+ tt_ptr->clearscreen.len = 0;
+ }
+ tt_ptr->item_len = 3 * SIZEOF(item_list_struct);
+ tt_ptr->item_list[0].buf_len = 0;
+ tt_ptr->item_list[0].item_code = TRM$_MODIFIERS;
+ tt_ptr->item_list[0].addr = TRM$M_TM_TRMNOECHO;
+ tt_ptr->item_list[0].ret_addr = 0;
+ tt_ptr->item_list[1].buf_len = 0;
+ tt_ptr->item_list[1].item_code = TRM$_TIMEOUT;
+ tt_ptr->item_list[1].addr = NO_M_TIMEOUT;
+ tt_ptr->item_list[1].ret_addr = 0;
+ tt_ptr->item_list[2].buf_len = SIZEOF(io_termmask);
+ tt_ptr->item_list[2].item_code = TRM$_TERM;
+ tt_ptr->item_list[2].addr = malloc(SIZEOF(io_termmask));
+ memset(tt_ptr->item_list[2].addr, 0, SIZEOF(io_termmask));
+ ((io_termmask *)tt_ptr->item_list[2].addr)->mask[0] =
+ (spc_inp_prc & (SHFT_MSK << CTRL_Z)) ? (TERM_MSK | (SHFT_MSK << CTRL_Z)) : TERM_MSK;
+ tt_ptr->item_list[2].ret_addr = 0;
+ tt_ptr->item_list[3].buf_len = 0;
+ tt_ptr->item_list[3].item_code = TRM$_ESCTRMOVR;
+ tt_ptr->item_list[3].addr = ESC_LEN - 1;
+ tt_ptr->item_list[3].ret_addr = 0;
+ tt_ptr->item_list[4].buf_len = (TREF(gtmprompt)).len;
+ tt_ptr->item_list[4].item_code = TRM$_PROMPT;
+ tt_ptr->item_list[4].addr = (TREF(gtmprompt)).addr;
+ tt_ptr->item_list[4].ret_addr = 0;
+ tt_ptr->item_list[5].buf_len = 0;
+ tt_ptr->item_list[5].item_code = TRM$_INISTRNG;
+ tt_ptr->item_list[5].addr = 0;
+ tt_ptr->item_list[5].ret_addr = 0;
+
+ if (0 != (t_mode.term_char & TT$M_WRAP))
+ ioptr->wrap = TRUE;
+ }
+ ioptr->state = dev_open;
+ p_offset = 0;
+ while (iop_eol != *(pp->str.addr + p_offset))
+ {
+ if (iop_exception == (ch = *(pp->str.addr + p_offset++)))
+ {
+ ioptr->error_handler.len = *(pp->str.addr + p_offset);
+ ioptr->error_handler.addr = pp->str.addr + p_offset + 1;
+ s2pool(&ioptr->error_handler);
+ break;
+ }
+ p_offset += ((IOP_VAR_SIZE == io_params_size[ch]) ?
+ (unsigned char)*(pp->str.addr + p_offset) + 1 : io_params_size[ch]);
+ }
+ return TRUE;
+}
diff --git a/sr_vvms/iott_rdone.c b/sr_vvms/iott_rdone.c
new file mode 100644
index 0000000..71130bd
--- /dev/null
+++ b/sr_vvms/iott_rdone.c
@@ -0,0 +1,320 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <iodef.h>
+#include <trmdef.h>
+#include <ttdef.h>
+#include <tt2def.h>
+#include <ssdef.h>
+#include <efndef.h>
+
+#include "efn.h"
+#include "io.h"
+#include "iottdef.h"
+#include "outofband.h"
+#include "curr_dev_outbndset.h"
+#include "std_dev_outbndset.h"
+
+#define ONE_CHAR 1
+#define ALL_CTRL 0x0ffffffff
+
+GBLREF io_pair io_curr_device;
+GBLREF io_pair io_std_device;
+GBLREF bool prin_in_dev_failure;
+GBLREF bool ctrlu_occurred;
+GBLREF uint4 std_dev_outofband_msk;
+GBLREF int4 outofband;
+GBLREF int4 spc_inp_prc;
+
+int iott_rdone( mint *v, int4 t)
+{
+ boolean_t timed_out;
+ unsigned char ch[ESC_LEN];
+ uint4 buff_len, char_msk, efn_mask, len, mask_in1, save_term_msk, status;
+ iosb stat_blk;
+ io_desc *io_ptr;
+ t_cap s_mode;
+ d_tt_struct *tt_ptr;
+
+ error_def(ERR_IOEOF);
+
+ io_ptr = io_curr_device.in;
+ assert (io_ptr->state == dev_open);
+ tt_ptr = (d_tt_struct*) io_ptr->dev_sp;
+ if (io_curr_device.out == io_ptr)
+ iott_flush(io_curr_device.out);
+
+ if (!(tt_ptr->ext_cap & TT2$M_PASTHRU))
+ {
+ /* in order to access all characters, except <CTRL-Q> and <CTRL-S>, we go into pasthru */
+
+ status = sys$qiow(EFN$C_ENF,tt_ptr->channel,IO$_SENSEMODE,
+ &stat_blk,0,0,&s_mode,12,0,0,0,0);
+ if (status == SS$_NORMAL)
+ status = stat_blk.status;
+ if (status != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+ s_mode.ext_cap |= TT2$M_PASTHRU;
+ status = sys$qiow(EFN$C_ENF,tt_ptr->channel,IO$_SETMODE,
+ &stat_blk,0,0,&s_mode,12,0,0,0,0);
+ if (status == SS$_NORMAL)
+ status = stat_blk.status;
+ if (status != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+ tt_ptr->term_chars_twisted = TRUE;
+ }
+
+ if (tt_ptr->term_char & TT$M_ESCAPE)
+ {
+ len = 4 * (SIZEOF(item_list_struct));
+ buff_len = ESC_LEN;
+ }else
+ {
+ len = 3 * (SIZEOF(item_list_struct));
+ buff_len = ONE_CHAR;
+ }
+
+ efn_mask = (SHFT_MSK << efn_immed_wait | SHFT_MSK << efn_outofband);
+ tt_ptr->item_list[1].addr = t;
+ ch[0] = 0;
+ timed_out = FALSE;
+
+ save_term_msk = ((io_termmask *)tt_ptr->item_list[2].addr)->mask[0];
+ ((io_termmask *)tt_ptr->item_list[2].addr)->mask[0] = ALL_CTRL;
+ /* the above prevents echoing of control characters, which preserves established behavior */
+
+ status = sys$qio(efn_immed_wait,tt_ptr->channel
+ ,tt_ptr->read_mask ,&tt_ptr->stat_blk
+ ,NULL ,0
+ ,&ch[0] ,buff_len
+ ,0 ,0 ,&(tt_ptr->item_list[0]) ,len);
+ if (status != SS$_NORMAL)
+ {
+ if (io_curr_device.in == io_std_device.in && io_curr_device.out == io_std_device.out)
+ {
+ if (prin_in_dev_failure)
+ {
+ ((io_termmask *)tt_ptr->item_list[2].addr)->mask[0] = save_term_msk;
+ sys$exit(status);
+ }else
+ prin_in_dev_failure = TRUE;
+ }
+ rts_error(VARLSTCNT(1) status);
+ }
+
+ status = sys$wflor(efn_immed_wait,efn_mask);
+ if (status != SS$_NORMAL)
+ {
+ ((io_termmask *)tt_ptr->item_list[2].addr)->mask[0] = save_term_msk;
+ rts_error(VARLSTCNT(1) status);
+ }
+
+ if (!tt_ptr->stat_blk.status)
+ {
+ if (outofband)
+ {
+ status = sys$dclast(iott_cancel_read, io_ptr, 0);
+ if (status != SS$_NORMAL)
+ {
+ ((io_termmask *)tt_ptr->item_list[2].addr)->mask[0] = save_term_msk;
+ rts_error(VARLSTCNT(1) status);
+ }
+ iott_resetast(io_ptr); /*reset ast after cancel */
+ }
+ status = sys$synch(efn_immed_wait ,&tt_ptr->stat_blk);
+ if (status != SS$_NORMAL)
+ {
+ ((io_termmask *)tt_ptr->item_list[2].addr)->mask[0] = save_term_msk;
+ rts_error(VARLSTCNT(1) status);
+ }
+ }
+
+ assert(tt_ptr->stat_blk.status);
+ /* can't put this back until the read is definately finished, which is why it's repeated above for error exits */
+ ((io_termmask *)tt_ptr->item_list[2].addr)->mask[0] = save_term_msk;
+
+ if (outofband)
+ {
+ outofband_action(FALSE);
+ assert(FALSE);
+ }
+
+ if (ctrlu_occurred)
+ {
+ ctrlu_occurred = FALSE;
+ ch[0] = CTRL_U;
+ }
+
+ if (tt_ptr->stat_blk.term_length > ESC_LEN - 1)
+ {
+ tt_ptr->stat_blk.term_length = ESC_LEN - 1;
+ /* this error may be overridden by an error in the iosb */
+ io_ptr->dollar.za = 2;
+ }else
+ io_ptr->dollar.za = 0;
+
+ switch(tt_ptr->stat_blk.status)
+ {
+ case SS$_CONTROLC:
+ case SS$_CONTROLY:
+ case SS$_NORMAL:
+ break;
+ case SS$_ABORT:
+ case SS$_CANCEL:
+ assert(FALSE); /* not planning on this, even though it should be ok */
+ iott_resetast(io_ptr); /* reset ast after cancel */
+ case SS$_TIMEOUT: /* CAUTION: fallthrough */
+ if (ch[0] == 0) /* if the buffer holds a non-null character, accept it */
+ {
+ *v = -1;
+ io_ptr->dollar.za = 0;
+ io_ptr->dollar.zb[0] = '\0';
+ timed_out = TRUE;
+ }
+ break;
+ case SS$_DATACHECK:
+ case SS$_DATAOVERUN:
+ case SS$_PARITY:
+ io_ptr->dollar.za = 1; /* data mangled */
+ break;
+ case SS$_BADESCAPE:
+ case SS$_PARTESCAPE:
+ io_ptr->dollar.za = 2; /* escape mangled */
+ break;
+ case SS$_CHANINTLK:
+ case SS$_COMMHARD:
+ case SS$_CTRLERR:
+ case SS$_DEVACTIVE:
+ case SS$_DEVALLOC:
+ case SS$_DEVINACT:
+ case SS$_DEVOFFLINE:
+ case SS$_DEVREQERR:
+ case SS$_DISCONNECT:
+ case SS$_MEDOFL:
+ case SS$_OPINCOMPL:
+ case SS$_TOOMUCHDATA:
+ io_ptr->dollar.za = 3; /* hardware contention or failure */
+ break;
+ case SS$_DUPUNIT:
+ case SS$_INSFMEM:
+ case SS$_INSFMAPREG:
+ case SS$_INCOMPAT:
+ io_ptr->dollar.za = 4; /* system configuration */
+ break;
+ case SS$_EXQUOTA:
+ case SS$_NOPRIV:
+ io_ptr->dollar.za = 5; /* process limits */
+ break;
+ default:
+ io_ptr->dollar.za = 9; /* if list above is maintained, indicates an iott_ programming defect */
+ }
+
+ if (tt_ptr->term_chars_twisted)
+ {
+ if (!(tt_ptr->ext_cap & TT2$M_PASTHRU))
+ s_mode.ext_cap &= (~TT2$M_PASTHRU);
+ status = sys$qiow(EFN$C_ENF,tt_ptr->channel,
+ IO$_SETMODE,&stat_blk,0,0,&s_mode,12,0,0,0,0);
+ if (status == SS$_NORMAL)
+ status = stat_blk.status;
+ if (status != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+ tt_ptr->term_chars_twisted = FALSE;
+ }
+
+ if (timed_out)
+ return FALSE;
+
+ if (ch[0] < 32)
+ {
+ char_msk = SHFT_MSK << ch[0];
+ if (!(tt_ptr->ext_cap & TT2$M_PASTHRU))
+ {
+ if ((tt_ptr->enbld_outofbands.mask & char_msk)
+ || ((io_ptr == io_std_device.in) && (std_dev_outofband_msk & char_msk & CTRLC_MSK)))
+ /* if and when <CTRL-C> and <CTRL-Y> handling is normalized the
+ CTRLC_MSK above should probably be removed; nonetheless, currently
+ <CTRL-Y> just gives gt.m a seizure and restarts the current operation - why waste the character */
+ {
+ /* pass on the outofband that was grabbed by the special pasthru */
+ status = sys$dclast(((io_ptr == io_std_device.in) ? std_dev_outbndset : curr_dev_outbndset),
+ (int4*)ch[0], 0);
+ if (status != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+ outofband_action(FALSE);
+ assert(FALSE);
+ }
+
+ if (spc_inp_prc & (SHFT_MSK << CTRL_Z))
+ {
+ if ((tt_ptr->stat_blk.term_char == CTRL_Z) && (save_term_msk & char_msk))
+ io_ptr->dollar.zeof = TRUE;
+ else
+ io_ptr->dollar.zeof = FALSE;
+ }
+ }
+
+ if (tt_ptr->stat_blk.term_length && !(save_term_msk & char_msk) &&
+ ((buff_len == ONE_CHAR) /* this is a proxy for !TT$M_ESCAPE */
+ || (ch[0] != ESC)))
+ {
+ /* demote control character terminators unless they are really enabled by the application */
+ tt_ptr->stat_blk.char_ct++;
+ tt_ptr->stat_blk.term_length--;
+ }
+ }
+ assert(tt_ptr->stat_blk.term_length < ESC_LEN);
+ *v = ch[0];
+ memcpy(io_ptr->dollar.zb, &ch[0], tt_ptr->stat_blk.term_length);
+ io_ptr->dollar.zb[tt_ptr->stat_blk.term_length] = '\0';
+
+ /* The three lines above used to be implemented by the
+ following code:
+
+ if (buff_len == ONE_CHAR)
+ { *v = ch[0];
+ io_ptr->dollar.zb[0] = '\0';
+ }
+ else
+ { *v = (ch[0] == ESC) ? 0 : ch[0];
+ if (tt_ptr->stat_blk.term_length > SIZEOF(io_ptr->dollar.zb) - 1)
+ { tt_ptr->stat_blk.term_length = SIZEOF(io_ptr->dollar.zb) - 1;
+ io_ptr->dollar.za = 2;
+ }
+ memcpy(io_ptr->dollar.zb,&ch[0],tt_ptr->stat_blk.term_length);
+ io_ptr->dollar.zb[tt_ptr->stat_blk.term_length] = '\0';
+ }
+
+ This caused $zb to always be null if NOESCAPE
+ ($ZB normally contains the terminator) and
+ the value to be 0 if ESCAPE and an escape sequence arrived.
+ The new behavior is to ALWAYS report the (1st) arriving
+ character and ALWAYS maintain $ZB. Note that $x is/was not
+ increased if the (1st) arriving character is a terminator.
+ The old code has been left in case we wish to quickly return
+ to the old behavior.
+ */
+
+ if (!((int)tt_ptr->item_list[0].addr & TRM$M_TM_NOECHO))
+ {
+ if ((io_ptr->dollar.x += tt_ptr->stat_blk.char_ct) > io_ptr->width && io_ptr->wrap)
+ {
+ io_ptr->dollar.y = ++(io_ptr->dollar.y);
+ if(io_ptr->length)
+ io_ptr->dollar.y %= io_ptr->length;
+ io_ptr->dollar.x = 0;
+ }
+ }
+ if (io_ptr->dollar.zeof && (io_ptr->error_handler.len > 0))
+ rts_error(VARLSTCNT(1) ERR_IOEOF);
+ return TRUE;
+}
diff --git a/sr_vvms/iott_read.c b/sr_vvms/iott_read.c
new file mode 100644
index 0000000..4eca049
--- /dev/null
+++ b/sr_vvms/iott_read.c
@@ -0,0 +1,30 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "io.h"
+#include "iottdef.h"
+#include "stringpool.h"
+
+GBLREF io_pair io_curr_device;
+GBLREF spdesc stringpool;
+
+int iott_read( mval *v, int4 t)
+{
+ int4 length;
+
+ assert(stringpool.free >= stringpool.base);
+ assert(stringpool.free <= stringpool.top);
+ length = ((d_tt_struct*)(io_curr_device.in->dev_sp))->in_buf_sz;
+ ENSURE_STP_FREE_SPACE(length + ESC_LEN);
+ v->str.addr = stringpool.free;
+ return iott_readfl(v,length,t);
+}
diff --git a/sr_vvms/iott_readfl.c b/sr_vvms/iott_readfl.c
new file mode 100644
index 0000000..f77bbf7
--- /dev/null
+++ b/sr_vvms/iott_readfl.c
@@ -0,0 +1,223 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <iodef.h>
+#include <ssdef.h>
+#include <trmdef.h>
+#include <ttdef.h>
+#include <tt2def.h>
+
+#include "efn.h"
+#include "io.h"
+#include "iottdef.h"
+#include "iotimer.h"
+#include "outofband.h"
+#include "timedef.h"
+
+#define TIMER_FLAGS 0
+
+GBLREF io_pair io_curr_device;
+GBLREF io_pair io_std_device;
+GBLREF bool prin_in_dev_failure;
+GBLREF int4 outofband;
+GBLDEF bool ctrlu_occurred;
+GBLDEF int4 spc_inp_prc;
+
+int iott_readfl(mval *v, int4 length, int4 timeout)
+{
+ int not_timed_out;
+ boolean_t timed;
+ uint4 efn_mask, status, time[2];
+ iosb stat_blk;
+ io_desc *io_ptr;
+ t_cap s_mode;
+ d_tt_struct *tt_ptr;
+ io_termmask save_term_msk;
+
+ error_def(ERR_IOEOF);
+
+ io_ptr = io_curr_device.in;
+ assert(dev_open == io_ptr->state);
+ tt_ptr = (d_tt_struct *)io_ptr->dev_sp;
+ if (io_curr_device.out == io_ptr)
+ iott_flush(io_curr_device.out);
+ memset(&tt_ptr->stat_blk, 0, SIZEOF(read_iosb));
+ efn_mask = (SHFT_MSK << efn_immed_wait | SHFT_MSK << efn_outofband);
+ not_timed_out = TRUE;
+#ifdef DEBUG
+/* this is for an assert that verifies a reliance on VMS IOSB maintenance */
+ tt_ptr->read_timer = FALSE;
+#endif
+ tt_ptr->item_list[1].addr = timeout;
+ if ((NO_M_TIMEOUT == timeout) || !timeout)
+ timed = FALSE;
+ else
+ {
+ timed = TRUE;
+ time[0] = -time_low(timeout);
+ time[1] = -time_high(timeout) - 1;
+ efn_mask |= SHFT_MSK << efn_timer;
+ status = sys$setimr(efn_timer, &time, iott_cancel_read, io_ptr ,TIMER_FLAGS);
+ if (SS$_NORMAL != status)
+ rts_error(VARLSTCNT(1) status);
+ }
+ for (;;)
+ {
+ status = sys$qio(efn_immed_wait ,tt_ptr->channel
+ ,tt_ptr->read_mask, &tt_ptr->stat_blk
+ ,NULL, 0
+ ,v->str.addr, length + ESC_LEN - 1
+ ,0, 0, &(tt_ptr->item_list[0]), 4 * (SIZEOF(item_list_struct)));
+ if (SS$_NORMAL != status)
+ {
+ if ((io_curr_device.in == io_std_device.in) && (io_curr_device.out == io_std_device.out))
+ {
+ if (prin_in_dev_failure)
+ sys$exit(status);
+ else
+ prin_in_dev_failure = TRUE;
+ }
+ break;
+ }
+ status = sys$wflor(efn_immed_wait, efn_mask);
+ if (SS$_NORMAL != status)
+ break;
+ if (timed)
+ {
+ status = sys$cantim(io_ptr, 0);
+ if (SS$_NORMAL != status)
+ break;
+ }
+ if (!tt_ptr->stat_blk.status)
+ {
+ if (outofband)
+ {
+ status = sys$dclast(iott_cancel_read, io_ptr, 0);
+ if (SS$_NORMAL != status)
+ break;
+ iott_resetast(io_ptr); /* reset ast after cancel */
+ }
+ status = sys$synch(efn_immed_wait, &tt_ptr->stat_blk);
+ if (SS$_NORMAL != status)
+ break;
+ }
+ if (outofband)
+ {
+ outofband_action(FALSE);
+ assert(FALSE);
+ }
+ if (ctrlu_occurred)
+ {
+ ctrlu_occurred = FALSE;
+ iott_wtctrlu(tt_ptr->stat_blk.char_ct, io_ptr);
+ if (timed)
+ {
+ /* strictly speaking a <CTRL-U> shouldn't buy you more time, but practically, it works better */
+ status = sys$setimr(efn_timer, &time, iott_cancel_read, io_ptr, TIMER_FLAGS);
+ if (SS$_NORMAL != status)
+ break;
+ }
+ continue;
+ }
+ break;
+ }
+ if (SS$_NORMAL != status)
+ rts_error(VARLSTCNT(1) status);
+ if (tt_ptr->stat_blk.term_length > ESC_LEN - 1)
+ {
+ tt_ptr->stat_blk.term_length = ESC_LEN - 1;
+ /* this error may be overridden by an error in the iosb */
+ io_ptr->dollar.za = 2;
+ } else
+ io_ptr->dollar.za = 0;
+ v->str.len = tt_ptr->stat_blk.char_ct;
+ memcpy(io_ptr->dollar.zb, v->str.addr + tt_ptr->stat_blk.char_ct, tt_ptr->stat_blk.term_length);
+ io_ptr->dollar.zb[tt_ptr->stat_blk.term_length] = '\0';
+ switch (tt_ptr->stat_blk.status)
+ {
+ case SS$_CONTROLC:
+ case SS$_CONTROLY:
+ assert(0 == tt_ptr->stat_blk.term_length);
+ io_ptr->dollar.zb[0] = (SS$_CONTROLC == tt_ptr->stat_blk.status) ? CTRLC : CTRLY;
+ if (((io_termmask *)tt_ptr->item_list[2].addr)->mask[0] & (SHFT_MSK << io_ptr->dollar.zb[0]))
+ io_ptr->dollar.zb[1] = '\0';
+ else
+ io_ptr->dollar.zb[0] = '\0';
+ break;
+ case SS$_NORMAL:
+ break;
+ case SS$_ABORT:
+ case SS$_CANCEL:
+ assert(!tt_ptr->read_timer);
+ iott_resetast(io_ptr); /* reset ast after cancel */
+ case SS$_TIMEOUT: /* CAUTION: fallthrough */
+ not_timed_out = FALSE;
+ break;
+ case SS$_DATACHECK:
+ case SS$_DATAOVERUN:
+ case SS$_PARITY:
+ io_ptr->dollar.za = 1; /* data mangled */
+ break;
+ case SS$_BADESCAPE:
+ case SS$_PARTESCAPE:
+ io_ptr->dollar.za = 2; /* escape mangled */
+ break;
+ case SS$_CHANINTLK:
+ case SS$_COMMHARD:
+ case SS$_CTRLERR:
+ case SS$_DEVACTIVE:
+ case SS$_DEVALLOC:
+ case SS$_DEVINACT:
+ case SS$_DEVOFFLINE:
+ case SS$_DEVREQERR:
+ case SS$_DISCONNECT:
+ case SS$_MEDOFL:
+ case SS$_OPINCOMPL:
+ case SS$_TOOMUCHDATA:
+ io_ptr->dollar.za = 3; /* hardware contention or failure */
+ break;
+ case SS$_DUPUNIT:
+ case SS$_INSFMEM:
+ case SS$_INSFMAPREG:
+ case SS$_INCOMPAT:
+ io_ptr->dollar.za = 4; /* system configuration */
+ break;
+ case SS$_EXQUOTA:
+ case SS$_NOPRIV:
+ io_ptr->dollar.za = 5; /* process limits */
+ break;
+ default:
+ io_ptr->dollar.za = 9; /* if list above is maintained, indicates an iott_ programming defect */
+ }
+ if (!((int)tt_ptr->item_list[0].addr & TRM$M_TM_NOECHO))
+ {
+ if ((io_ptr->dollar.x += v->str.len) > io_ptr->width && io_ptr->wrap)
+ {
+ io_ptr->dollar.y += (io_ptr->dollar.x / io_ptr->width);
+ if(io_ptr->length)
+ io_ptr->dollar.y %= io_ptr->length;
+ io_ptr->dollar.x %= io_ptr->width;
+ }
+ }
+ if (spc_inp_prc & (SHFT_MSK << CTRL_Z))
+ {
+ if ((CTRL_Z == tt_ptr->stat_blk.term_char) && !(tt_ptr->ext_cap & TT2$M_PASTHRU))
+ {
+ io_ptr->dollar.zeof = TRUE;
+ if (io_ptr->error_handler.len > 0)
+ rts_error(VARLSTCNT(1) ERR_IOEOF);
+ } else
+ io_ptr->dollar.zeof = FALSE;
+ }
+ return not_timed_out;
+}
diff --git a/sr_vvms/iott_resetast.c b/sr_vvms/iott_resetast.c
new file mode 100644
index 0000000..2694044
--- /dev/null
+++ b/sr_vvms/iott_resetast.c
@@ -0,0 +1,58 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <ssdef.h>
+#include <iodef.h>
+#include <efndef.h>
+
+#include "io.h"
+#include "iottdef.h"
+#include "outofband.h"
+#include "curr_dev_outbndset.h"
+#include "std_dev_outbndset.h"
+
+GBLREF io_pair io_std_device;
+GBLREF uint4 std_dev_outofband_msk;
+
+void iott_resetast( io_desc *io_ptr)
+{
+ void std_dev_outbndset(), curr_dev_outbndset(), (*ast_routine)();
+ short iosb[4];
+ uint4 status;
+ d_tt_struct *tt_ptr;
+ io_terminator outofbands;
+
+ tt_ptr = (d_tt_struct*) io_ptr->dev_sp;
+ outofbands.x = 0;
+ outofbands.mask = tt_ptr->enbld_outofbands.mask | tt_ptr->ctrlu_msk;
+
+ if (io_ptr == io_std_device.in)
+ {
+ /* <CTRL-Y> doesn't do anything unless it's in the enabled_outofbands.mask,
+ but we're using the std_dev_outofband_msk to hold the inital state of the CONTROL=Y;
+ this probably deserves more attention, but for now, if we mask it out,
+ the user at least gets to see evidence of disturbance e.g. that input was lost*/
+ outofbands.mask |= (std_dev_outofband_msk & (~CTRLY_MSK));
+ ast_routine = std_dev_outbndset;
+ }
+ else
+ ast_routine = curr_dev_outbndset;
+
+ status = sys$qiow(EFN$C_ENF, tt_ptr->channel
+ ,(IO$_SETMODE | IO$M_OUTBAND | IO$M_TT_ABORT) ,iosb
+ ,NULL ,0
+ ,ast_routine ,&outofbands ,0 ,0 ,0 ,0 );
+ if (status == SS$_NORMAL)
+ status = iosb[0];
+ if (status != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+}
diff --git a/sr_vvms/iott_use.c b/sr_vvms/iott_use.c
new file mode 100644
index 0000000..8352e9e
--- /dev/null
+++ b/sr_vvms/iott_use.c
@@ -0,0 +1,495 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <iodef.h>
+#include <smgtrmptr.h>
+#include <ssdef.h>
+#include <trmdef.h>
+#include <ttdef.h>
+#include <tt2def.h>
+#include <efndef.h>
+
+#include "io.h"
+#include "io_params.h"
+#include "iottdef.h"
+#include "nametabtyp.h"
+#include "outofband.h"
+#include "stringpool.h"
+#include "namelook.h"
+#include "copy.h"
+
+LITDEF nametabent filter_names[] =
+{
+ { 4, "CHAR*"},
+ { 3, "ESC*"},
+ { 6, "NOCHAR*"},
+ { 5, "NOESC*"}
+};
+LITDEF unsigned char filter_index[27] =
+{
+ 0, 0, 0, 1, 1, 2, 2, 2, 2, 2, 2, 2
+ ,2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4
+ ,4, 4, 4
+};
+
+GBLREF bool ctrlc_on;
+GBLREF uint4 std_dev_outofband_msk;
+GBLREF uint4 spc_inp_prc;
+GBLREF io_pair io_std_device;
+LITREF unsigned char io_params_size[];
+
+void iott_use(io_desc *iod, mval *pp)
+{
+ bool flush_input;
+ char buf[512];
+ int fil_type;
+ unsigned char ch, len;
+ short field;
+ int4 width, length;
+ uint4 mask_in, status;
+ unsigned int bufsz, buflen;
+ unsigned int req_code, args[4];
+ d_tt_struct *out_ttptr, *in_ttptr, *tt_ptr;
+ io_desc *d_in, *d_out;
+ io_termmask mask_term;
+ iosb stat_blk;
+ char *tab;
+ t_cap s_mode;
+ int p_offset;
+
+ error_def(ERR_DEVPARMNEG);
+ error_def(ERR_TTINVFILTER);
+ error_def(ERR_TTWIDTHTOOBIG);
+ error_def(ERR_TTLENGTHTOOBIG);
+
+ assert(iod->state == dev_open);
+ assert(iod->type == tt);
+ assert(iod->pair.in == iod || iod->pair.out == iod);
+ iott_flush(iod);
+ p_offset = 0;
+ if (*(pp->str.addr + p_offset) != iop_eol)
+ {
+ tt_ptr = (d_tt_struct *)iod->dev_sp;
+ bufsz = SIZEOF(buf);
+ flush_input = FALSE;
+ /* WARNING - the inclusion of an IOSB on this qio is NOT spurious! Values in the IOSB
+ are used, nay, required on the subsequent SETMODE call. RTPAD will fail the
+ SETMODE on certain circumstances when the IOSB is not present.
+ */
+ status = sys$qiow(EFN$C_ENF, tt_ptr->channel,
+ IO$_SENSEMODE, &stat_blk, 0, 0, &s_mode, 12, 0, 0, 0, 0);
+ if (status == SS$_NORMAL)
+ status = stat_blk.status;
+ if (status != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+ /* although it is only for safety, the following covers for
+ read * (iott_rdone) and dm_read use of pasthru et al */
+ s_mode.ext_cap &= (~TT2$M_PASTHRU);
+ s_mode.ext_cap |= (tt_ptr->ext_cap & TT2$M_PASTHRU);
+ s_mode.ext_cap &= (~TT2$M_EDITING);
+ s_mode.ext_cap |= (tt_ptr->ext_cap & TT2$M_EDITING);
+ s_mode.term_char &= (~TT$M_ESCAPE);
+ s_mode.term_char |= (tt_ptr->term_char & TT$M_ESCAPE);
+ s_mode.term_char &= (~TT$M_TTSYNC);
+ s_mode.term_char |= (tt_ptr->term_char & TT$M_TTSYNC);
+ d_in = iod->pair.in;
+ d_out = iod->pair.out;
+ in_ttptr = d_in->type == tt ? (d_tt_struct *)d_in->dev_sp : (d_tt_struct *)0;
+ out_ttptr = d_out->type == tt ? (d_tt_struct *)d_out->dev_sp : (d_tt_struct *)0;
+ if (in_ttptr)
+ {
+ in_ttptr->term_chars_twisted = FALSE; /* they were normalized above */
+ mask_in = in_ttptr->item_list[0].addr;
+ memcpy(&mask_term, in_ttptr->item_list[2].addr, SIZEOF(io_termmask));
+ }
+ while (*(pp->str.addr + p_offset) != iop_eol)
+ {
+ switch (ch = *(pp->str.addr + p_offset++))
+ {
+ case iop_canctlo:
+ if (out_ttptr)
+ out_ttptr->write_mask |= IO$M_CANCTRLO;
+ break;
+ case iop_cenable:
+ if (iod == io_std_device.in && !ctrlc_on)
+ {
+ ctrlc_on = TRUE;
+ std_dev_outofband_msk |= CTRLC_MSK;
+ iott_resetast(iod);
+ }
+ break;
+ case iop_nocenable:
+ if (iod == io_std_device.in && ctrlc_on)
+ {
+ ctrlc_on = FALSE;
+ std_dev_outofband_msk &= (~CTRLC_MSK);
+ iott_resetast(iod);
+ }
+ break;
+ case iop_clearscreen:
+ if (out_ttptr)
+ {
+ status = sys$qiow(EFN$C_ENF, out_ttptr->channel, IO$_WRITEVBLK,
+ &stat_blk, NULL, 0,
+ out_ttptr->clearscreen.addr, out_ttptr->clearscreen.len,
+ 0, 0, 0, 0);
+ if (status == SS$_NORMAL)
+ status = stat_blk.status;
+ if (status != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+ }
+ break;
+ case iop_convert:
+ mask_in |= TRM$M_TM_CVTLOW;
+ break;
+ case iop_noconvert:
+ mask_in &= (~TRM$M_TM_CVTLOW);
+ break;
+ case iop_ctrap:
+ if (in_ttptr)
+ {
+ in_ttptr->enbld_outofbands.mask = *((uint4 *)(pp->str.addr + p_offset));
+ iott_resetast(iod);
+ }
+ break;
+ case iop_downscroll:
+ if (out_ttptr && out_ttptr->term_tab_entry)
+ {
+ args[0] = 2;
+ args[1] = d_out->dollar.y;
+ args[2] = 1;
+ req_code = SMG$K_SET_CURSOR_ABS;
+ status = smg$get_term_data (&out_ttptr->term_tab_entry,
+ &req_code, &bufsz, &buflen, buf, args);
+ if (!(status & 1))
+ rts_error(VARLSTCNT(1) status);
+ status = sys$qiow(EFN$C_ENF, out_ttptr->channel, IO$_WRITEVBLK,
+ &stat_blk, NULL, 0, buf, buflen, 0, 0, 0, 0);
+ if (status == SS$_NORMAL)
+ status = stat_blk.status;
+ if (status != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+
+ if (d_out->dollar.y > 0)
+ {
+ d_out->dollar.y --;
+ if (d_out->length)
+ d_out->dollar.y %= d_out->length;
+ }
+ d_out->dollar.x = 0;
+ }
+ break;
+ case iop_echo:
+ if (in_ttptr)
+ s_mode.term_char &= (~TT$M_NOECHO);
+ break;
+ case iop_noecho:
+ if (in_ttptr)
+ s_mode.term_char |= TT$M_NOECHO;
+ break;
+ case iop_editing:
+ if (in_ttptr)
+ s_mode.ext_cap |= TT2$M_EDITING;
+ break;
+ case iop_noediting:
+ if (in_ttptr)
+ s_mode.ext_cap &= (~TT2$M_EDITING);
+ break;
+ case iop_escape:
+ if (in_ttptr)
+ s_mode.term_char |= TT$M_ESCAPE;
+ break;
+ case iop_noescape:
+ if (in_ttptr)
+ s_mode.term_char &= (~TT$M_ESCAPE);
+ default:
+ break;
+ case iop_eraseline:
+ if (out_ttptr)
+ {
+ status = sys$qiow(EFN$C_ENF, out_ttptr->channel, IO$_WRITEVBLK,
+ &stat_blk, NULL, 0,
+ out_ttptr->erase_to_end_line.addr, out_ttptr->erase_to_end_line.len,
+ 0, 0, 0, 0);
+ if (status == SS$_NORMAL)
+ status = stat_blk.status;
+ if (status != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+ }
+ break;
+ case iop_exception:
+ iod->error_handler.len = *(pp->str.addr + p_offset);
+ iod->error_handler.addr = pp->str.addr + p_offset + 1;
+ s2pool(&iod->error_handler);
+ break;
+ case iop_filter:
+ len = *(pp->str.addr + p_offset);
+ tab = pp->str.addr + p_offset + 1;
+ if ((fil_type = namelook(filter_index, filter_names, tab, len)) < 0)
+ {
+ rts_error(VARLSTCNT(1) ERR_TTINVFILTER);
+ return;
+ }
+ switch (fil_type)
+ {
+ case 0:
+ iod->write_filter |= CHAR_FILTER;
+ break;
+ case 1:
+ iod->write_filter |= ESC1;
+ break;
+ case 2:
+ iod->write_filter &= ~CHAR_FILTER;
+ break;
+ case 3:
+ iod->write_filter &= ~ESC1;
+ break;
+ }
+ break;
+ case iop_nofilter:
+ iod->write_filter = 0;
+ break;
+ case iop_field:
+ GET_SHORT(field, pp->str.addr + p_offset);
+ if (field < 0)
+ rts_error(VARLSTCNT(1) ERR_DEVPARMNEG);
+ if (in_ttptr)
+ if (field == 0)
+ in_ttptr->in_buf_sz = TTDEF_BUF_SZ;
+ else
+ in_ttptr->in_buf_sz = field;
+ break;
+ case iop_flush:
+ flush_input = TRUE;
+ break;
+ case iop_hostsync:
+ if (in_ttptr)
+ s_mode.term_char |= TT$M_HOSTSYNC;
+ break;
+ case iop_nohostsync:
+ if (in_ttptr)
+ s_mode.term_char &= (~TT$M_HOSTSYNC);
+ break;
+ case iop_insert:
+ if (in_ttptr)
+ s_mode.ext_cap |= TT2$M_INSERT;
+ break;
+ case iop_noinsert:
+ if (in_ttptr)
+ s_mode.ext_cap &= (~TT2$M_INSERT);
+ break;
+ case iop_length:
+ GET_LONG(length, pp->str.addr + p_offset);
+ if (length < 0)
+ rts_error(VARLSTCNT(1) ERR_DEVPARMNEG);
+ if (length > TTMAX_PG_LENGTH)
+ rts_error(VARLSTCNT(1) ERR_TTLENGTHTOOBIG);
+ s_mode.pg_length = length;
+ d_out->length = length;
+ break;
+ case iop_pasthru:
+ if (in_ttptr)
+ {
+ s_mode.ext_cap |= TT2$M_PASTHRU;
+ if ((spc_inp_prc & (SHFT_MSK << CTRL_U)) && (s_mode.term_char & TT$M_SCOPE))
+ {
+ in_ttptr->ctrlu_msk =0;
+ iott_resetast(iod);
+ }
+ }
+ break;
+ case iop_nopasthru:
+ if (in_ttptr)
+ {
+ s_mode.ext_cap &= (~TT2$M_PASTHRU);
+ if ((spc_inp_prc & (SHFT_MSK << CTRL_U)) && (s_mode.term_char & TT$M_SCOPE))
+ {
+ in_ttptr->ctrlu_msk = (SHFT_MSK << CTRL_U);
+ iott_resetast(iod);
+ }
+ }
+ break;
+ case iop_readsync:
+ if (in_ttptr)
+ s_mode.term_char |= TT$M_READSYNC;
+ break;
+ case iop_noreadsync:
+ if (in_ttptr)
+ s_mode.term_char &= (~TT$M_READSYNC);
+ break;
+ case iop_terminator:
+ memcpy(&mask_term.mask[0], (pp->str.addr + p_offset), SIZEOF(io_termmask));
+ if (mask_term.mask[0] == NUL &&
+ mask_term.mask[1] == NUL &&
+ mask_term.mask[2] == NUL &&
+ mask_term.mask[3] == NUL &&
+ mask_term.mask[4] == NUL &&
+ mask_term.mask[5] == NUL &&
+ mask_term.mask[6] == NUL &&
+ mask_term.mask[7] == NUL)
+ mask_term.mask[0] = TERM_MSK;
+ break;
+ case iop_noterminator:
+ memset(&mask_term.mask[0], 0, SIZEOF(io_termmask));
+ break;
+ case iop_ttsync:
+ s_mode.term_char |= TT$M_TTSYNC;
+ break;
+ case iop_nottsync:
+ s_mode.term_char &= (~TT$M_TTSYNC);
+ break;
+ case iop_typeahead:
+ if (in_ttptr)
+ s_mode.term_char &= (~TT$M_NOTYPEAHD);
+ break;
+ case iop_notypeahead:
+ if (in_ttptr)
+ s_mode.term_char |= TT$M_NOTYPEAHD;
+ break;
+ case iop_upscroll:
+ if (out_ttptr && out_ttptr->term_tab_entry)
+ {
+ args[0] = 2;
+ args[1] = d_out->dollar.y + 2;
+ args[2] = 1;
+ req_code = SMG$K_SET_CURSOR_ABS;
+ status = smg$get_term_data (&out_ttptr->term_tab_entry, &req_code,
+ &bufsz, &buflen, buf, args);
+ if (!(status & 1))
+ rts_error(VARLSTCNT(1) status);
+ status = sys$qiow(EFN$C_ENF, out_ttptr->channel, IO$_WRITEVBLK,
+ &stat_blk, NULL, 0, buf, buflen, 0, 0, 0, 0);
+ if (status == SS$_NORMAL)
+ status = stat_blk.status;
+ if (status != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+
+ d_out->dollar.y++;
+ if (d_out->length)
+ d_out->dollar.y %= d_out->length;
+ d_out->dollar.x = 0;
+ }
+ break;
+ case iop_width:
+ GET_LONG(width, pp->str.addr + p_offset);
+ if (width < 0)
+ rts_error(VARLSTCNT(1) ERR_DEVPARMNEG);
+ if (width > TTMAX_PG_WIDTH)
+ rts_error(VARLSTCNT(1) ERR_TTWIDTHTOOBIG);
+ if (width == 0)
+ {
+ s_mode.term_char &= (~TT$M_WRAP);
+ d_out->wrap = FALSE;
+ s_mode.pg_width = TTDEF_PG_WIDTH;
+ d_out->width = TTDEF_PG_WIDTH;
+ } else
+ {
+ /* ******** later with a ring buffer this will change to indicate ******** */
+ /* ******** location of a carriage return on an extended write ******** */
+ s_mode.pg_width = width;
+ d_out->width = width;
+ s_mode.term_char |= TT$M_WRAP;
+ d_out->wrap = TRUE;
+ }
+ break;
+ case iop_wrap:
+ s_mode.term_char |= TT$M_WRAP;
+ d_out->wrap = TRUE;
+ break;
+ case iop_nowrap:
+ s_mode.term_char &= (~TT$M_WRAP);
+ d_out->wrap = FALSE;
+ break;
+ case iop_x:
+ if (out_ttptr && out_ttptr->term_tab_entry)
+ {
+ GET_LONG(d_out->dollar.x, pp->str.addr + p_offset);
+ if (d_out->dollar.x < 0)
+ d_out->dollar.x = 0;
+ if (d_out->dollar.x > d_out->width && d_out->wrap)
+ {
+ d_out->dollar.y += (d_out->dollar.x / d_out->width);
+ if (d_out->length)
+ d_out->dollar.y %= d_out->length;
+ d_out->dollar.x %= d_out->width;
+ }
+ args[0] = 2;
+ args[1] = d_out->dollar.y + 1;
+ args[2] = d_out->dollar.x + 1;
+ req_code = SMG$K_SET_CURSOR_ABS;
+ status = smg$get_term_data (&out_ttptr->term_tab_entry,
+ &req_code, &bufsz, &buflen, buf, args);
+ if (!(status & 1))
+ rts_error(VARLSTCNT(1) status);
+ status = sys$qiow(EFN$C_ENF, out_ttptr->channel, IO$_WRITEVBLK,
+ &stat_blk, NULL, 0, buf, buflen, 0, 0, 0, 0);
+ if (status == SS$_NORMAL)
+ status = stat_blk.status;
+ if (status != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+ }
+ break;
+ case iop_y:
+ if (out_ttptr && out_ttptr->term_tab_entry)
+ {
+ GET_LONG(d_out->dollar.y, pp->str.addr + p_offset);
+ if (d_out->dollar.y < 0)
+ d_out->dollar.y = 0;
+ if (d_out->length)
+ d_out->dollar.y %= d_out->length;
+ args[0] = 2;
+ args[1] = d_out->dollar.y + 1;
+ args[2] = d_out->dollar.x + 1;
+ req_code = SMG$K_SET_CURSOR_ABS;
+ status = smg$get_term_data (&out_ttptr->term_tab_entry,
+ &req_code, &bufsz, &buflen, buf, args);
+ if (!(status & 1))
+ rts_error(VARLSTCNT(1) status);
+ status = sys$qiow(EFN$C_ENF, out_ttptr->channel, IO$_WRITEVBLK,
+ &stat_blk, NULL, 0, buf, buflen, 0, 0, 0, 0);
+ if (status == SS$_NORMAL)
+ status = stat_blk.status;
+ if (status != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+ }
+ break;
+ }
+ p_offset += ((IOP_VAR_SIZE == io_params_size[ch]) ?
+ (unsigned char)*(pp->str.addr + p_offset) + 1 : io_params_size[ch]);
+ }
+ status = sys$qiow(EFN$C_ENF, tt_ptr->channel, IO$_SETMODE,
+ &stat_blk, NULL, 0, &s_mode, 12, 0, 0, 0, 0);
+ if (status == SS$_NORMAL)
+ status = stat_blk.status;
+ if (status != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+ if (in_ttptr)
+ {
+ in_ttptr->item_list[0].addr = mask_in;
+ in_ttptr->term_char = s_mode.term_char;
+ in_ttptr->ext_cap = s_mode.ext_cap;
+ memcpy(in_ttptr->item_list[2].addr, &mask_term, SIZEOF(io_termmask));
+ if (flush_input)
+ {
+ status = sys$qiow(EFN$C_ENF, in_ttptr->channel,
+ IO$_READVBLK | IO$M_PURGE | IO$M_TIMED | IO$M_NOECHO,
+ &stat_blk, NULL, 0, &flush_input, 1, 0, 0, 0, 0);
+ if (status == SS$_NORMAL)
+ status = stat_blk.status;
+ if ((status != SS$_NORMAL) && (status != SS$_TIMEOUT))
+ rts_error(VARLSTCNT(1) status);
+ }
+ }
+ }
+ return;
+}
diff --git a/sr_vvms/iott_write.c b/sr_vvms/iott_write.c
new file mode 100644
index 0000000..f8965e7
--- /dev/null
+++ b/sr_vvms/iott_write.c
@@ -0,0 +1,96 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <iodef.h>
+#include <ssdef.h>
+
+#include "efn.h"
+#include "io.h"
+#include "iottdef.h"
+#include "timedef.h"
+#include "dollarx.h"
+
+GBLDEF uint4 iott_write_delay[2] =
+ {
+ (~(3300000) + 1),
+ 0xffffffff
+ };
+GBLREF io_pair io_curr_device;
+
+void iott_write(mstr *mstr_ptr)
+{
+ d_tt_struct *tt_ptr;
+ char *iop, *io_in, *str;
+ uint4 status;
+ int cpy_len, str_len, t_len;
+ io_desc *io_ptr;
+ iosb_struct *sb[2];
+
+ io_ptr = io_curr_device.out;
+ tt_ptr = (d_tt_struct *)io_curr_device.out->dev_sp;
+ /* pending must follow free - must be able to get pair uninterrupted with movq */
+ assert(&tt_ptr->sb_free + 1 == &tt_ptr->sb_pending);
+ str = mstr_ptr->addr;
+ str_len = mstr_ptr->len;
+ while (0 != str_len)
+ {
+ for (; ;)
+ {
+ movq(&tt_ptr->sb_free, sb);
+ if (sb_dist(sb[0], sb[1]) < MIN_IOSB_SP)
+ sys$hiber();
+ else
+ break;
+ }
+ for (; ;)
+ {
+ iop = tt_ptr->io_pending;
+ if (io_space(tt_ptr->io_free, (unsigned char *)iop) < MIN_RINGBUF_SP)
+ sys$hiber();
+ else
+ break;
+ }
+ assert(tt_ptr->io_free < tt_ptr->io_buftop);
+ if (tt_ptr->io_free < (iop = tt_ptr->io_pending))
+ cpy_len = ((t_len = (unsigned char *)iop - tt_ptr->io_free) <= str_len ?
+ (t_len > MAX_MEMCPY ? MAX_MEMCPY : t_len) :
+ (str_len > MAX_MEMCPY ? MAX_MEMCPY : str_len));
+ else
+ cpy_len = ((t_len = tt_ptr->io_buftop - tt_ptr->io_free) <= str_len ?
+ (t_len > MAX_MEMCPY ? MAX_MEMCPY : t_len) :
+ (str_len > MAX_MEMCPY ? MAX_MEMCPY : str_len));
+ assert(tt_ptr->io_free + cpy_len <= tt_ptr->io_buftop);
+ memcpy(tt_ptr->io_free, str, cpy_len);
+ str += cpy_len;
+ str_len -= cpy_len;
+ if ((tt_ptr->io_free += cpy_len) == tt_ptr->io_buftop)
+ tt_ptr->io_free = tt_ptr->io_buffer;
+ if (tt_ptr->io_free < tt_ptr->io_inuse)
+ {
+ if (SS$_NORMAL != (status = sys$dclast(iott_wtstart, tt_ptr, 0)))
+ rts_error(VARLSTCNT(1) status);
+ } else if (tt_ptr->io_free - tt_ptr->io_inuse >= SPACE_INUSE)
+ {
+ if (SS$_NORMAL != (status = sys$dclast(iott_wtstart, tt_ptr, 0)))
+ rts_error(VARLSTCNT(1) status);
+ } else if (FALSE == tt_ptr->clock_on)
+ {
+ tt_ptr->clock_on = TRUE;
+ if (SS$_NORMAL != (status = sys$setimr(efn_ignore, iott_write_delay, iott_clockfini ,tt_ptr, 0)))
+ rts_error(VARLSTCNT(1) status);
+ }
+ }
+ dollarx(io_ptr, (uchar_ptr_t)mstr_ptr->addr, (uchar_ptr_t)mstr_ptr->addr + mstr_ptr->len);
+ tt_ptr->write_mask &= (~IO$M_CANCTRLO);
+ return;
+}
diff --git a/sr_vvms/iott_wtclose.c b/sr_vvms/iott_wtclose.c
new file mode 100644
index 0000000..53e36f0
--- /dev/null
+++ b/sr_vvms/iott_wtclose.c
@@ -0,0 +1,57 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <dcdef.h>
+#include <iodef.h>
+#include <ssdef.h>
+#include <efndef.h>
+
+#include "io.h"
+#include "iottdef.h"
+
+GBLREF io_pair io_std_device;
+
+void iott_wtclose(d_tt_struct *tt_ptr)
+{
+ uint4 status;
+ short length;
+ unsigned char sensemode[8];
+
+ if (tt_ptr->clock_on)
+ {
+ if (SS$_NORMAL != (status = sys$cantim(tt_ptr, 0)))
+ rts_error(VARLSTCNT(1) status);
+ }
+ if (tt_ptr->io_free < tt_ptr->io_inuse)
+ length = tt_ptr->io_buftop - tt_ptr->io_inuse;
+ else
+ length = tt_ptr->io_free - tt_ptr->io_inuse;
+ tt_ptr->sb_free->start_addr = tt_ptr->io_inuse;
+ if (SS$_NORMAL != (status = sys$qiow(EFN$C_ENF, tt_ptr->channel, tt_ptr->write_mask, &(tt_ptr->sb_free->iosb_val),
+ iott_wtfini, tt_ptr, tt_ptr->io_inuse, length, 0, 0, 0, 0)))
+ rts_error(VARLSTCNT(1) status);
+ status = sys$qiow(EFN$C_ENF, tt_ptr->channel, IO$_SENSEMODE | IO$M_RD_MODEM, &tt_ptr->sb_free->iosb_val, 0, 0,
+ sensemode, 0 ,0, 0, 0, 0);
+ if ((io_std_device.in->dev_sp != tt_ptr) &&
+ (io_std_device.out->dev_sp != tt_ptr) &&
+ (SS$_NORMAL == status) && (DT$_LAT == sensemode[0]))
+ {
+ if (SS$_NORMAL != (status = sys$qiow(EFN$C_ENF, tt_ptr->channel, IO$_TTY_PORT | IO$M_LT_DISCON,
+ &tt_ptr->sb_free->iosb_val, 0, 0, 0, 0, 0, 0, 0, 0)))
+ rts_error(VARLSTCNT(1) status);
+ }
+ tt_ptr->io_inuse = tt_ptr->io_free;
+ tt_ptr->sb_free++;
+ tt_ptr->sb_free = new_sbfree(tt_ptr);
+ return;
+}
diff --git a/sr_vvms/iott_wtctrlu.c b/sr_vvms/iott_wtctrlu.c
new file mode 100644
index 0000000..9ff3c2a
--- /dev/null
+++ b/sr_vvms/iott_wtctrlu.c
@@ -0,0 +1,63 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2004 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "io.h"
+
+#define BS 8
+
+GBLREF io_pair io_curr_device;
+
+#define ERASE_BUF_SZ 64
+static readonly unsigned char eraser[ERASE_BUF_SZ * 3] =
+{
+ BS,SP,BS, BS,SP,BS, BS,SP,BS, BS,SP,BS, BS,SP,BS, BS,SP,BS, BS,SP,BS, BS,SP,BS,
+ BS,SP,BS, BS,SP,BS, BS,SP,BS, BS,SP,BS, BS,SP,BS, BS,SP,BS, BS,SP,BS, BS,SP,BS,
+ BS,SP,BS, BS,SP,BS, BS,SP,BS, BS,SP,BS, BS,SP,BS, BS,SP,BS, BS,SP,BS, BS,SP,BS,
+ BS,SP,BS, BS,SP,BS, BS,SP,BS, BS,SP,BS, BS,SP,BS, BS,SP,BS, BS,SP,BS, BS,SP,BS,
+ BS,SP,BS, BS,SP,BS, BS,SP,BS, BS,SP,BS, BS,SP,BS, BS,SP,BS, BS,SP,BS, BS,SP,BS,
+ BS,SP,BS, BS,SP,BS, BS,SP,BS, BS,SP,BS, BS,SP,BS, BS,SP,BS, BS,SP,BS, BS,SP,BS,
+ BS,SP,BS, BS,SP,BS, BS,SP,BS, BS,SP,BS, BS,SP,BS, BS,SP,BS, BS,SP,BS, BS,SP,BS,
+ BS,SP,BS, BS,SP,BS, BS,SP,BS, BS,SP,BS, BS,SP,BS, BS,SP,BS, BS,SP,BS, BS,SP,BS
+};
+
+void iott_wtctrlu( short v, io_desc *iod)
+{
+mstr temp;
+int x, y;
+short s;
+
+ temp.addr = &eraser[0];
+ x = iod->dollar.x;
+ y = iod->dollar.y;
+ if (iod->wrap)
+ v %= iod->width;
+
+ if ((s = v / ERASE_BUF_SZ) != 0)
+ {
+ temp.len = ERASE_BUF_SZ * 3;
+ while (s-- != 0)
+ {
+ iott_write(&temp);
+ iod->dollar.x = x;
+ iod->dollar.y = y;
+ }
+ }
+ if ((s = v % ERASE_BUF_SZ) != 0)
+ {
+ temp.len = s * 3;
+ iott_write(&temp);
+ iod->dollar.x = x;
+ iod->dollar.y = y;
+ }
+ iott_flush(io_curr_device.out);
+ return;
+}
diff --git a/sr_vvms/iott_wtfini.c b/sr_vvms/iott_wtfini.c
new file mode 100644
index 0000000..341451f
--- /dev/null
+++ b/sr_vvms/iott_wtfini.c
@@ -0,0 +1,29 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "io.h"
+#include "iottdef.h"
+#include "gtm_wake.h"
+
+void iott_wtfini(d_tt_struct *tt_ptr)
+{
+ tt_ptr->io_pending = tt_ptr->sb_pending->start_addr +
+ tt_ptr->sb_pending->iosb_val.char_ct;
+ if (tt_ptr->io_pending == tt_ptr->io_buftop)
+ tt_ptr->io_pending = tt_ptr->io_buffer;
+ tt_ptr->sb_pending++;
+ if (tt_ptr->sb_pending == tt_ptr->sb_buftop)
+ tt_ptr->sb_pending = tt_ptr->sb_buffer;
+ gtm_wake(0,0);
+ return;
+}
+
diff --git a/sr_vvms/iott_wtstart.c b/sr_vvms/iott_wtstart.c
new file mode 100644
index 0000000..710fddf
--- /dev/null
+++ b/sr_vvms/iott_wtstart.c
@@ -0,0 +1,76 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2004 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <ssdef.h>
+
+#include "efn.h"
+#include "io.h"
+#include "iottdef.h"
+#include "xfer_enum.h"
+#include "op.h"
+#include "deferred_events.h"
+
+GBLREF io_pair io_curr_device;
+GBLREF io_pair io_std_device;
+GBLREF bool prin_out_dev_failure;
+GBLREF int (*xfer_table[])();
+
+void iott_wtstart(d_tt_struct *tt_ptr)
+{
+ int length;
+ uint4 status;
+
+ if (tt_ptr->io_free != tt_ptr->io_inuse)
+ {
+ tt_ptr->sb_free->start_addr = tt_ptr->io_inuse;
+ if (tt_ptr->io_free < tt_ptr->io_inuse)
+ {
+ length = tt_ptr->io_buftop - tt_ptr->io_inuse;
+ tt_ptr->io_inuse = tt_ptr->io_buffer;
+ } else
+ {
+ length = tt_ptr->io_free - tt_ptr->io_inuse;
+ tt_ptr->io_inuse = tt_ptr->io_free;
+ }
+ if (SS$_NORMAL == (status = sys$qio(
+ efn_iott_write
+ ,tt_ptr->channel
+ ,tt_ptr->write_mask
+ ,&(tt_ptr->sb_free->iosb_val)
+ ,iott_wtfini
+ ,tt_ptr
+ ,tt_ptr->sb_free->start_addr
+ ,length
+ ,0
+ ,0
+ ,0
+ ,0)))
+ {
+ prin_out_dev_failure = FALSE;
+ tt_ptr->sb_free++;
+ if (tt_ptr->sb_free == tt_ptr->sb_buftop)
+ tt_ptr->sb_free = tt_ptr->sb_buffer;
+ } else
+ {
+ if (io_curr_device.out == io_std_device.out)
+ {
+ if (prin_out_dev_failure)
+ sys$exit(status);
+ else
+ prin_out_dev_failure = TRUE;
+ }
+ xfer_set_handlers(tt_write_error_event, tt_write_error_set, status);
+ }
+ }
+ return;
+}
diff --git a/sr_vvms/iottdef.h b/sr_vvms/iottdef.h
new file mode 100644
index 0000000..5294f8e
--- /dev/null
+++ b/sr_vvms/iottdef.h
@@ -0,0 +1,147 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2004 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef __IOTTDEF_H__
+#define __IOTTDEF_H__
+
+#define IO_FUNC_R (IO$_READVBLK | IO$M_EXTEND)
+#define IO_FUNC_W IO$_WRITEVBLK
+#define TERM_MSK 0x00002000 /* <RET> */
+
+#define SHFT_MSK 0x00000001
+#define CTRL_B 2
+#define CTRL_U 21
+#define CTRL_Z 26
+
+#include "iottdefsp.h"
+
+#define ESC 27
+
+#define TTMAX_PG_LENGTH 255
+#define TTMAX_PG_WIDTH 511
+#define TTDEF_PG_WIDTH 255
+#define TTDEF_BUF_SZ 1024
+
+#define TTEOL "\015\012"
+#define TERMINAL_STATIC_ASTS 2
+#define IOSB_BUF_SZ 20
+#define RING_BUF_SZ 2048
+#define MIN_RINGBUF_SP 128
+#define MIN_IOSB_SP 3
+#define SPACE_INUSE 768
+#define MAX_MEMCPY 512
+
+#define io_space(x,y) (x >= y ? RING_BUF_SZ - (x - y) : (y - x))
+
+#define sb_dist(x,y) (x >= y ? IOSB_BUF_SZ - (x - y) : (y - x))
+
+#define new_sbfree(a) ((a)->sb_buffer + (((a)->sb_free - (a)->sb_buffer) % IOSB_BUF_SZ))
+
+/* ***************************************************** */
+/* *********** structure for terminal driver *********** */
+/* ***************************************************** */
+
+typedef struct
+{ unsigned short status;
+ unsigned short char_ct;
+ unsigned char term_char;
+ unsigned char reserved;
+ unsigned char term_length;
+ unsigned char cur_pos_eol;
+}read_iosb;
+
+
+typedef struct
+{ unsigned short status;
+ unsigned short char_ct;
+ uint4 dev_dep_info;
+}iosb;
+
+
+typedef struct
+{
+ read_iosb iosb_val;
+ char *start_addr;
+}iosb_struct;
+
+typedef struct
+{ uint4 mask[8];
+} io_termmask;
+
+typedef struct
+{ uint4 x;
+ uint4 mask;
+}io_terminator;
+
+typedef struct
+{
+ unsigned short buf_len;
+ unsigned short item_code;
+ char *addr;
+ char *ret_addr;
+}item_list_struct;
+
+typedef struct
+{
+
+ short channel; /* channel for access to terminal */
+ unsigned char clock_on; /* flag for clock running or off */
+ uint4 read_mask; /* arg mask used in sys$qio read */
+ uint4 write_mask; /* arg mask for sys$qio write */
+ uint4 in_buf_sz; /* size of read buffer */
+ /* unsigned short pg_width; width of output page */
+ uint4 term_char;
+ uint4 ext_cap;
+ uint4 term_tab_entry; /* SMG index for terminal type */
+ io_terminator enbld_outofbands; /*enabled out-of-band chars*/
+ unsigned char read_timer;
+ item_list_struct item_list[6];
+ uint4 item_len;
+ unsigned char *io_inuse; /* output buffer pointer to area */
+ /* in use but not qio'd */
+ unsigned char *io_free; /* pointer to free space in buff */
+ unsigned char *io_pending; /* pointer to data already queued */
+ unsigned char *io_buftop;
+ unsigned char *io_buffer; /* the write ring buffer */
+ /* pending must follow free - must be able to get pair uninterrupted with movq */
+ iosb_struct *sb_free; /* first free position in buffer */
+ iosb_struct *sb_pending; /* pointer to first iosb that */
+ /* return data after qio is done */
+
+ iosb_struct *sb_buftop;
+ iosb_struct *sb_buffer; /* the iosb ring buffer */
+ mstr erase_to_end_line;
+ mstr key_up_arrow;
+ mstr key_down_arrow;
+ mstr clearscreen;
+ read_iosb stat_blk;
+ bool term_chars_twisted;
+ uint4 ctrlu_msk;
+}d_tt_struct;
+
+typedef struct
+{ unsigned char class;
+ unsigned char type;
+ unsigned short pg_width;
+ unsigned int term_char : 24;
+ unsigned int pg_length : 8;
+ uint4 ext_cap; /* extended terminal characteristics */
+}t_cap; /* terminal capabilites */
+
+void iott_cancel_read(io_desc *io_ptr);
+void iott_clockfini(d_tt_struct *tt_ptr);
+void iott_resetast(io_desc *io_ptr);
+void iott_wtclose(d_tt_struct *tt_ptr);
+void iott_wtctrlu(short v, io_desc *iod);
+void iott_wtstart(d_tt_struct *tt_ptr);
+void iott_wtfini(d_tt_struct *tt_ptr);
+
+#endif
diff --git a/sr_vvms/iottdefsp.h b/sr_vvms/iottdefsp.h
new file mode 100644
index 0000000..0f0cc6b
--- /dev/null
+++ b/sr_vvms/iottdefsp.h
@@ -0,0 +1,34 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#define ASCII_ESC 27 /* this ASCII value is needed on any platform */
+#define EBCDIC_ESC 39
+#define ASCII_CR 13
+#define EBCDIC_CR 13
+#define ASCII_LF 10
+#define EBCDIC_LF 37
+#define ASCII_FF 12
+#define EBCDIC_FF 12
+#define ASCII_BS 8
+#define EBCDIC_BS 22
+#define VT 11
+
+#define ASCII_TTEOL "\015\012"
+#define EBCDIC_TTEOL "\025"
+
+#define ESC ASCII_ESC
+#define NATIVE_ESC ASCII_ESC
+#define NATIVE_CR ASCII_CR
+#define NATIVE_LF ASCII_LF
+#define NATIVE_FF ASCII_FF
+#define NATIVE_BS ASCII_BS
+#define NATIVE_TTEOL ((ascii != io_ptr->out_code_set) ? EBCDIC_TTEOL : ASCII_TTEOL)
+#define NATIVE_VT VT
diff --git a/sr_vvms/ious_iocontrol.c b/sr_vvms/ious_iocontrol.c
new file mode 100644
index 0000000..2abbafc
--- /dev/null
+++ b/sr_vvms/ious_iocontrol.c
@@ -0,0 +1,58 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2004 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "io.h"
+#include "iousdef.h"
+#include <descrip.h>
+
+GBLREF io_pair io_curr_device;
+
+void ious_iocontrol(mstr *d)
+{
+ struct dsc$descriptor val;
+
+ val.dsc$w_length = d->len;
+ val.dsc$b_dtype = DSC$K_DTYPE_T;
+ val.dsc$b_class = DSC$K_CLASS_S;
+ val.dsc$a_pointer = d->addr;
+
+ (((d_us_struct*)(io_curr_device.out->dev_sp))->disp->iocontrol)(&val);
+ return;
+}
+
+void ious_dlr_device(mstr *d)
+{
+ struct dsc$descriptor val;
+
+ val.dsc$w_length = d->len;
+ val.dsc$b_dtype = DSC$K_DTYPE_T;
+ val.dsc$b_class = DSC$K_CLASS_S;
+ val.dsc$a_pointer = d->addr;
+
+ (((d_us_struct*)(io_curr_device.out->dev_sp))->disp->dlr_device)(&val);
+ d->len = val.dsc$w_length;
+ return;
+}
+
+void ious_dlr_key(mstr *d)
+{
+ struct dsc$descriptor val;
+
+ val.dsc$w_length = d->len;
+ val.dsc$b_dtype = DSC$K_DTYPE_T;
+ val.dsc$b_class = DSC$K_CLASS_S;
+ val.dsc$a_pointer = d->addr;
+
+ (((d_us_struct*)(io_curr_device.out->dev_sp))->disp->dlr_key)(&val);
+ d->len = val.dsc$w_length;
+ return;
+}
diff --git a/sr_vvms/ious_open.c b/sr_vvms/ious_open.c
new file mode 100644
index 0000000..715ef5e
--- /dev/null
+++ b/sr_vvms/ious_open.c
@@ -0,0 +1,49 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include "io.h"
+#include "iousdef.h"
+
+/*file_des is a dummy parameter */
+short ious_open(io_log_name *dev, mval *pp, int file_des, mval *mspace, int4 timeout)
+{
+ io_desc *iod;
+ dev_dispatch_struct *fgn_driver;
+ error_def(ERR_USRIOINIT);
+
+ iod = dev->iod;
+ if (iod->state == dev_never_opened)
+ {
+ iod->dev_sp = (void *)malloc(SIZEOF(d_us_struct));
+ memset(iod->dev_sp, 0, SIZEOF(d_us_struct));
+ iod->state = dev_closed;
+ }
+
+ if (iod->state != dev_open)
+ {
+ if (mspace && mspace->str.len)
+ { fgn_driver = io_get_fgn_driver(&mspace->str);
+ ((d_us_struct*)(iod->dev_sp))->disp = fgn_driver;
+ }
+ else if (!(((d_us_struct*)(iod->dev_sp))->disp->open))
+ { rts_error(VARLSTCNT(1) ERR_USRIOINIT);
+ return FALSE;
+ }
+
+ ((void(*)())(((d_us_struct*)(iod->dev_sp))->disp->open))();
+ iod->state = dev_open;
+ }
+ return TRUE;
+}
diff --git a/sr_vvms/ious_rdone.c b/sr_vvms/ious_rdone.c
new file mode 100644
index 0000000..583a2e5
--- /dev/null
+++ b/sr_vvms/ious_rdone.c
@@ -0,0 +1,32 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2006 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "io.h"
+#include "iousdef.h"
+#include <descrip.h>
+
+GBLREF io_pair io_curr_device;
+
+int ious_rdone(mint *v, int4 t)
+{
+ struct dsc$descriptor dsc;
+ unsigned char p;
+
+ p = 0;
+ dsc.dsc$w_length = 1;
+ dsc.dsc$b_dtype = DSC$K_DTYPE_T;
+ dsc.dsc$b_class = DSC$K_CLASS_S;
+ dsc.dsc$a_pointer = &p;
+ ((void(*)())(((d_us_struct*)(io_curr_device.in->dev_sp))->disp->rdone))(&dsc);
+ *v = p;
+ return TRUE;
+}
diff --git a/sr_vvms/ious_read.c b/sr_vvms/ious_read.c
new file mode 100644
index 0000000..2fe6030
--- /dev/null
+++ b/sr_vvms/ious_read.c
@@ -0,0 +1,34 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "io.h"
+#include "iousdef.h"
+#include "stringpool.h"
+#include <descrip.h>
+
+GBLREF spdesc stringpool;
+GBLREF io_pair io_curr_device;
+
+int ious_read(mval *v, int4 t)
+{
+ struct dsc$descriptor dsc;
+
+ ENSURE_STP_FREE_SPACE(MAX_US_READ);
+ dsc.dsc$w_length = MAX_US_READ;
+ dsc.dsc$b_dtype = DSC$K_DTYPE_T;
+ dsc.dsc$b_class = DSC$K_CLASS_S;
+ dsc.dsc$a_pointer = stringpool.free;
+ ((void(*)())(((d_us_struct*)(io_curr_device.in->dev_sp))->disp->read))(&dsc);
+ v->str.len = dsc.dsc$w_length;
+ v->str.addr = stringpool.free;
+ return TRUE;
+}
diff --git a/sr_vvms/ious_readfl.c b/sr_vvms/ious_readfl.c
new file mode 100644
index 0000000..5d8eb03
--- /dev/null
+++ b/sr_vvms/ious_readfl.c
@@ -0,0 +1,36 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "io.h"
+#include "iousdef.h"
+#include "stringpool.h"
+#include <descrip.h>
+
+GBLREF spdesc stringpool;
+GBLREF io_pair io_curr_device;
+
+int ious_readfl( mval *v, int4 length, int4 t)
+{
+ struct dsc$descriptor dsc;
+
+ if (length > MAX_US_READ)
+ length = MAX_US_READ;
+ ENSURE_STP_FREE_SPACE(length);
+ dsc.dsc$w_length = length;
+ dsc.dsc$b_dtype = DSC$K_DTYPE_T;
+ dsc.dsc$b_class = DSC$K_CLASS_S;
+ dsc.dsc$a_pointer = stringpool.free;
+ ((void(*)())(((d_us_struct*)(io_curr_device.in->dev_sp))->disp->readfl))(&dsc);
+ v->str.len = dsc.dsc$w_length;
+ v->str.addr = stringpool.free;
+ return TRUE;
+}
diff --git a/sr_vvms/ious_write.c b/sr_vvms/ious_write.c
new file mode 100644
index 0000000..b117119
--- /dev/null
+++ b/sr_vvms/ious_write.c
@@ -0,0 +1,28 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "io.h"
+#include "iousdef.h"
+#include <descrip.h>
+
+GBLREF io_pair io_curr_device;
+
+void ious_write(mstr *v)
+{
+ struct dsc$descriptor dsc;
+
+ dsc.dsc$w_length = v->len;
+ dsc.dsc$b_dtype = DSC$K_DTYPE_T;
+ dsc.dsc$b_class = DSC$K_CLASS_S;
+ dsc.dsc$a_pointer = v->addr;
+ ((void(*)())(((d_us_struct*)(io_curr_device.out->dev_sp))->disp->write))(&dsc);
+}
diff --git a/sr_vvms/ious_wtone.c b/sr_vvms/ious_wtone.c
new file mode 100644
index 0000000..7dbea40
--- /dev/null
+++ b/sr_vvms/ious_wtone.c
@@ -0,0 +1,28 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2006 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "io.h"
+#include "iousdef.h"
+#include <descrip.h>
+
+GBLREF io_pair io_curr_device;
+
+void ious_wtone(int v)
+{
+ struct dsc$descriptor dsc;
+
+ dsc.dsc$w_length = 4;
+ dsc.dsc$b_dtype = DSC$K_DTYPE_T;
+ dsc.dsc$b_class = DSC$K_CLASS_S;
+ dsc.dsc$a_pointer = &v;
+ ((void(*)())(((d_us_struct*)(io_curr_device.out->dev_sp))->disp->wtone))(&dsc);
+}
diff --git a/sr_vvms/is_file_identical.c b/sr_vvms/is_file_identical.c
new file mode 100644
index 0000000..9be3af5
--- /dev/null
+++ b/sr_vvms/is_file_identical.c
@@ -0,0 +1,140 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <rms.h>
+#include <devdef.h>
+#include <ssdef.h>
+#include "gtm_string.h"
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "is_file_identical.h"
+
+bool is_gdid_file_identical(gd_id_ptr_t fid, char *filename, int4 filelen)
+{
+ uint4 status;
+ struct FAB fab;
+ struct NAM nam;
+ char es[MAX_FN_LEN + 1];
+ error_def (ERR_FILEPARSE);
+
+ fab = cc$rms_fab;
+ nam = cc$rms_nam;
+ fab.fab$l_nam = &(nam);
+ fab.fab$l_fop = FAB$M_NAM;
+ fab.fab$l_fna = filename;
+ fab.fab$b_fns = filelen;
+ nam.nam$b_nop = NAM$M_NOCONCEAL;
+ nam.nam$l_esa = es;
+ nam.nam$b_ess = MAX_FN_LEN;
+ if (RMS$_NORMAL == (status = sys$parse(&fab,0,0)))
+ status = sys$search(&fab,0,0);
+ if (RMS$_NORMAL != status)
+ {
+ rts_error(VARLSTCNT(6) ERR_FILEPARSE, 2, filelen, filename, status, fab.fab$l_stv);
+ return FALSE;
+ }
+
+ return !(memcmp(&fid->dvi, &nam.nam$t_dvi, SIZEOF(fid->dvi)) || memcmp(&fid->fid, &nam.nam$w_fid, SIZEOF(fid->fid)));
+}
+
+/* is_file_identical()
+ * returns TRUE if the two files are identical,
+ * returns FALSE if either one of the files specified doesn't exist, or if they are different files.
+ */
+
+bool is_file_identical(char *filename1, char *filename2)
+{
+ uint4 status, filelen1, filelen2;
+ struct FAB fab1, fab2;
+ struct NAM nam1, nam2;
+ char es1[MAX_FN_LEN + 1], es2[MAX_FN_LEN + 1];
+ error_def (ERR_FILEPARSE);
+
+ fab1 = cc$rms_fab;
+ nam1 = cc$rms_nam;
+ fab1.fab$l_nam = &(nam1);
+ fab1.fab$l_fop = FAB$M_NAM;
+ fab1.fab$l_fna = filename1;
+ fab1.fab$b_fns = filelen1 = strlen(filename1);
+ nam1.nam$b_nop = NAM$M_NOCONCEAL;
+ nam1.nam$l_esa = es1;
+ nam1.nam$b_ess = MAX_FN_LEN;
+ if (RMS$_NORMAL == (status = sys$parse(&fab1,0,0)))
+ status = sys$search(&fab1,0,0);
+ if (RMS$_NORMAL != status)
+ {
+ if (RMS$_FNF != status) /* do not error out if one of these files do not exist */
+ rts_error(VARLSTCNT(6) ERR_FILEPARSE, 2, filelen1, filename1, status, fab1.fab$l_stv);
+ return FALSE;
+ }
+ fab2 = cc$rms_fab;
+ nam2 = cc$rms_nam;
+ fab2.fab$l_nam = &(nam2);
+ fab2.fab$l_fop = FAB$M_NAM;
+ fab2.fab$l_fna = filename2;
+ fab2.fab$b_fns = filelen2 = strlen(filename2);
+ nam2.nam$b_nop = NAM$M_NOCONCEAL;
+ nam2.nam$l_esa = es2;
+ nam2.nam$b_ess = MAX_FN_LEN;
+ if (RMS$_NORMAL == (status = sys$parse(&fab2,0,0)))
+ status = sys$search(&fab2,0,0);
+ if (RMS$_NORMAL != status)
+ {
+ if (RMS$_FNF != status) /* do not error out if one of these files do not exist */
+ rts_error(VARLSTCNT(6) ERR_FILEPARSE, 2, filelen2, filename2, status, fab2.fab$l_stv);
+ return FALSE;
+ }
+
+ return !(memcmp(&nam1.nam$t_dvi, &nam2.nam$t_dvi, SIZEOF(nam1.nam$t_dvi)) ||
+ memcmp(&nam1.nam$w_fid, &nam2.nam$w_fid, SIZEOF(nam1.nam$w_fid)));
+}
+
+bool is_gdid_gdid_identical(gd_id_ptr_t fid_1, gd_id_ptr_t fid_2)
+{ /* the file id (fid) is unique within a device (dvi), so the directory id (did) is redundant for uniqueness check */
+ return !(memcmp(&fid_1->dvi, &fid_2->dvi, SIZEOF(fid_1->dvi)) || memcmp(&fid_1->fid, &fid_2->fid, SIZEOF(fid_1->fid)));
+}
+
+void set_gdid_from_file(gd_id_ptr_t fileid, char *filename, int4 filelen)
+{
+ uint4 status;
+ struct FAB fab;
+ struct NAM nam;
+ char es[MAX_FN_LEN + 1];
+ error_def (ERR_FILEPARSE);
+
+ fab = cc$rms_fab;
+ nam = cc$rms_nam;
+ fab.fab$l_nam = &(nam);
+ fab.fab$l_fop = FAB$M_NAM;
+ fab.fab$l_fna = filename;
+ fab.fab$b_fns = filelen;
+ nam.nam$b_nop = NAM$M_NOCONCEAL;
+ nam.nam$l_esa = es;
+ nam.nam$b_ess = MAX_FN_LEN;
+ if (RMS$_NORMAL == (status = sys$parse(&fab,0,0)))
+ status = sys$search(&fab,0,0);
+ if (RMS$_NORMAL == status)
+ {
+ memcpy(&fileid->dvi, &nam.nam$t_dvi, SIZEOF(fileid->dvi));
+ memcpy(&fileid->did, &nam.nam$w_did, SIZEOF(fileid->did));
+ memcpy(&fileid->fid, &nam.nam$w_fid, SIZEOF(fileid->fid));
+ }
+ else
+ rts_error(VARLSTCNT(6) ERR_FILEPARSE, 2, filelen, filename, status, fab.fab$l_stv);
+}
diff --git a/sr_vvms/is_five_bit.c b/sr_vvms/is_five_bit.c
new file mode 100644
index 0000000..b4128a9
--- /dev/null
+++ b/sr_vvms/is_five_bit.c
@@ -0,0 +1,27 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "is_five_bit.h"
+
+int is_five_bit(unsigned char *cp)
+{
+ unsigned char ch;
+ int i;
+
+ for (i = 0 ; i < 3 ; i++)
+ {
+ ch = *cp++;
+ if (ch > 'Z' || ch < 'A')
+ return FALSE;
+ }
+ return TRUE;
+}
diff --git a/sr_vvms/is_five_bit.h b/sr_vvms/is_five_bit.h
new file mode 100644
index 0000000..f37ce55
--- /dev/null
+++ b/sr_vvms/is_five_bit.h
@@ -0,0 +1,17 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef IS_FIVE_BIT_INCLUDED
+#define IS_FIVE_BIT_INCLUDED
+
+int is_five_bit(unsigned char *cp); /***type int added***/
+
+#endif /* IS_FIVE_BIT_INCLUDED */
diff --git a/sr_vvms/is_proc_alive.c b/sr_vvms/is_proc_alive.c
new file mode 100644
index 0000000..4a01028
--- /dev/null
+++ b/sr_vvms/is_proc_alive.c
@@ -0,0 +1,31 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* is_proc_alive(pid, imagecnt) - VMS version.
+ *
+ * Checks to see if a process exists. Returns TRUE (non-zero) or FALSE (zero)
+ * accordingly.
+ */
+#include "mdef.h"
+
+#include <ssdef.h>
+#include "repl_sp.h"
+#include "is_proc_alive.h"
+
+bool is_proc_alive(uint4 pid, uint4 imagecnt)
+{
+ uint4 icount;
+
+ if ((get_proc_info(pid, NULL, &icount) == SS$_NONEXPR) || (imagecnt && (imagecnt != icount)))
+ return FALSE;
+ return TRUE;
+}
+
diff --git a/sr_vvms/jnl_file_extend.c b/sr_vvms/jnl_file_extend.c
new file mode 100644
index 0000000..8ebdfac
--- /dev/null
+++ b/sr_vvms/jnl_file_extend.c
@@ -0,0 +1,386 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <ssdef.h>
+#include <iodef.h>
+#include <psldef.h>
+#include <lckdef.h>
+#include <dvidef.h>
+#include <rms.h>
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "ccp.h"
+#include "efn.h"
+#include "jnl.h"
+#include "iosp.h"
+#include "vmsdtype.h"
+#include "send_msg.h"
+#include "dbfilop.h"
+#include "disk_block_available.h"
+#include "gtmmsg.h"
+#include "iosb_disk.h"
+#include "gtmio.h"
+#include "error.h"
+
+#define BLKS_PER_WRITE 64
+
+GBLREF gd_region *gv_cur_region;
+GBLREF sgmnt_addrs *cs_addrs;
+GBLREF sgmnt_data_ptr_t cs_data;
+GBLREF jnl_gbls_t jgbl;
+GBLREF boolean_t in_jnl_file_autoswitch;
+
+error_def(ERR_DBFILERR);
+error_def(ERR_DSKSPACEFLOW);
+error_def(ERR_JNLNOCREATE);
+error_def(ERR_JNLEXTEND);
+error_def(ERR_JNLREADEOF);
+error_def(ERR_JNLSPACELOW);
+error_def(ERR_NEWJNLFILECREAT);
+error_def(ERR_NOSPACEEXT);
+error_def(ERR_JNLFILEXTERR);
+error_def(ERR_JNLWRERR);
+error_def(ERR_JNLRDERR);
+
+static const unsigned short zero_fid[3];
+
+uint4 jnl_file_extend(jnl_private_control *jpc, uint4 total_jnl_rec_size)
+{
+ struct FAB fab;
+ struct XABFHC xabfhc;
+ struct NAM nam;
+ struct RAB rab;
+ sgmnt_addrs *csa;
+ sgmnt_data_ptr_t csd;
+ node_local_ptr_t cnl;
+ GDS_INFO *gds_info;
+ jnl_create_info jnl_info;
+ jnl_file_header header;
+ file_control *fc;
+ boolean_t need_extend;
+ char *buff, jnl_file_name[JNL_NAME_SIZE], prev_jnl_fn[MAX_FN_LEN];
+ int new_blocks, avail_blocks;
+ uint4 new_alq, status;
+ uint4 jnl_status = 0;
+ unsigned short fn_len;
+ jnl_buffer_ptr_t jb;
+ uint4 aligned_tot_jrec_size, count;
+ io_status_block_disk iosb;
+
+ switch(jpc->region->dyn.addr->acc_meth)
+ {
+ case dba_mm:
+ case dba_bg:
+ csa = &FILE_INFO(jpc->region)->s_addrs;
+ break;
+ default:
+ GTMASSERT;
+ }
+ csd = csa->hdr;
+ cnl = csa->nl;
+ assert(csa == cs_addrs && csd == cs_data);
+ assert(0 != memcmp(cnl->jnl_file.jnl_file_id.fid, zero_fid, SIZEOF(zero_fid)));
+ assert(csa->now_crit || (csd->clustered && (CCST_CLOSED == cnl->ccp_state)));
+ assert(&FILE_INFO(jpc->region)->s_addrs == csa);
+ if (!JNL_ENABLED(csa) || (NOJNL == jpc->channel) || (JNL_FILE_SWITCHED(jpc)))
+ GTMASSERT; /* crit and messing with the journal file - how could it have vanished? */
+ if (!csd->jnl_deq)
+ {
+ assert(DIVIDE_ROUND_UP(total_jnl_rec_size, DISK_BLOCK_SIZE) <= csd->jnl_alq);
+ assert(csd->jnl_alq == csd->autoswitchlimit);
+ new_blocks = csd->jnl_alq;
+ } else
+ /* May cause extension of csd->jnl_deq * n blocks where n > 0 */
+ new_blocks = ROUND_UP(DIVIDE_ROUND_UP(total_jnl_rec_size, DISK_BLOCK_SIZE), csd->jnl_deq);
+ jb = jpc->jnl_buff;
+ jpc->status = SS_NORMAL;
+ DEBUG_ONLY(count = 0);
+ for (need_extend = (0 != new_blocks); need_extend; )
+ {
+ DEBUG_ONLY(count++);
+ /* usually we will do the loop just once where we do the file extension.
+ * rarely we might need to do an autoswitch instead after which again rarely
+ * we might need to do an extension on the new journal to fit in the transaction's journal requirements.
+ * therefore we should do this loop a maximum of twice. hence the assert below.
+ */
+ assert(count <= 2);
+ need_extend = FALSE;
+ xabfhc = cc$rms_xabfhc;
+ nam = cc$rms_nam;
+ fab = cc$rms_fab;
+ fab.fab$b_shr = FAB$M_SHRPUT | FAB$M_SHRGET | FAB$M_UPI;
+ fab.fab$b_fac = FAB$M_BIO | FAB$M_GET | FAB$M_PUT;
+ fab.fab$l_fop = FAB$M_CBT | FAB$M_NAM;
+ fab.fab$l_xab = &xabfhc;
+ fab.fab$l_nam = &nam;
+ /* Get the file id from the header and open the journal file */
+ memcpy(&nam.nam$t_dvi, cnl->jnl_file.jnl_file_id.dvi, SIZEOF(cnl->jnl_file.jnl_file_id.dvi));
+ memcpy(&nam.nam$w_did, cnl->jnl_file.jnl_file_id.did, SIZEOF(cnl->jnl_file.jnl_file_id.did));
+ memcpy(&nam.nam$w_fid, cnl->jnl_file.jnl_file_id.fid, SIZEOF(cnl->jnl_file.jnl_file_id.fid));
+ if (SYSCALL_SUCCESS(jpc->status = sys$open(&fab)))
+ {
+ if (SYSCALL_SUCCESS((status = disk_block_available(jpc->channel, &avail_blocks))))
+ {
+ avail_blocks += xabfhc.xab$l_hbk - xabfhc.xab$l_ebk;
+ if ((new_blocks * EXTEND_WARNING_FACTOR) > avail_blocks)
+ {
+ if (new_blocks > avail_blocks)
+ { /* if we cannot satisfy the requst, it is an error */
+ send_msg(VARLSTCNT(6) ERR_NOSPACEEXT, 4, JNL_LEN_STR(csd),
+ new_blocks, avail_blocks);
+ new_blocks = 0;
+ jpc->status = SS_NORMAL;
+ } else
+ send_msg(VARLSTCNT(5) ERR_DSKSPACEFLOW, 3, JNL_LEN_STR(csd),
+ (avail_blocks - new_blocks));
+ }
+ } else
+ send_msg(VARLSTCNT(5) ERR_JNLFILEXTERR, 2, JNL_LEN_STR(csd), status);
+ fab.fab$w_deq = new_blocks;
+ rab = cc$rms_rab;
+ rab.rab$l_fab = &fab;
+ rab.rab$b_mbc = BLKS_PER_WRITE;
+ rab.rab$l_rop |= RAB$M_EOF;
+ /* ensure current journal file size is well within autoswitchlimit */
+ assert(csd->autoswitchlimit >= jb->filesize);
+ if (new_blocks && (SYSCALL_SUCCESS(jpc->status = sys$connect(&rab))))
+ {
+ new_alq = jb->filesize + new_blocks;
+ if (csd->autoswitchlimit < ((new_blocks * EXTEND_WARNING_FACTOR) + jb->filesize))
+ send_msg(VARLSTCNT(5) ERR_JNLSPACELOW, 3, JNL_LEN_STR(csd),
+ csd->autoswitchlimit - jb->filesize);
+ /* switch journal file if the request cannot be satisfied */
+ if (csd->autoswitchlimit < new_alq)
+ { /* Reached max, need to autoswitch */
+ /* Ensure new journal file can hold the entire current
+ transaction's journal record requirements */
+ assert(csd->autoswitchlimit >= MAX_REQD_JNL_FILE_SIZE(total_jnl_rec_size));
+ memset(&jnl_info, 0, SIZEOF(jnl_info));
+ jnl_info.prev_jnl = &prev_jnl_fn[0];
+ set_jnl_info(gv_cur_region, &jnl_info);
+ assert(!jgbl.forw_phase_recovery || (NULL != jgbl.mur_pini_addr_reset_fnptr));
+ assert(jgbl.forw_phase_recovery || (NULL == jgbl.mur_pini_addr_reset_fnptr));
+ if (NULL != jgbl.mur_pini_addr_reset_fnptr)
+ (*jgbl.mur_pini_addr_reset_fnptr)(csa);
+ jnl_status = jnl_ensure_open();
+ if (0 == jnl_status)
+ { /* flush the cache and jnl-buffer-contents to current journal file before
+ * switching to a new journal. Set a global variable in_jnl_file_autoswitch
+ * so jnl_write can know not to do the padding check. But because this is a global
+ * variable, we also need to make sure it is reset in case of errors during the
+ * autoswitch (or else calls to jnl_write after we are out of the autoswitch logic
+ * will continue to incorrectly not do the padding check. Hence a condition handler.
+ */
+ in_jnl_file_autoswitch = TRUE;
+ /* Also make sure time is not changed. This way if "jnl_write" as part of writing a
+ * journal record invokes jnl_file_extend, when the autoswitch is done and writing
+ * of the parent jnl_write resumes, we want it to continue with the same timestamp
+ * and not have to reset its time (non-trivial task) to reflect any changes since.
+ */
+ assert(!jgbl.save_dont_reset_gbl_jrec_time);
+ jgbl.save_dont_reset_gbl_jrec_time = jgbl.dont_reset_gbl_jrec_time;
+ jgbl.dont_reset_gbl_jrec_time = TRUE;
+ /* Establish a condition handler so we reset a few global variables that have
+ * temporarily been modified in case of errors inside wcs_flu/jnl_file_close.
+ */
+ ESTABLISH_RET(jnl_file_autoswitch_ch, EXIT_ERR);
+ /* It is possible we still have not written a PINI record in this journal file
+ * (e.g. mupip extend saw the need to do jnl_file_extend inside jnl_write while
+ * trying to write a PINI record). Write a PINI record in that case before closing
+ * the journal file that way the EOF record will have a non-zero pini_addr.
+ */
+ if (0 == jpc->pini_addr)
+ jnl_put_jrt_pini(csa);
+ wcs_flu(WCSFLU_FLUSH_HDR | WCSFLU_WRITE_EPOCH);
+ jnl_file_close(gv_cur_region, TRUE, TRUE);
+ REVERT;
+ in_jnl_file_autoswitch = FALSE;
+ jgbl.dont_reset_gbl_jrec_time = jgbl.save_dont_reset_gbl_jrec_time;
+ DEBUG_ONLY(jgbl.save_dont_reset_gbl_jrec_time = FALSE);
+ gds_info = FILE_INFO(gv_cur_region);
+ assert(jnl_info.fn_len == gds_info->fab->fab$b_fns);
+ assert(0 == memcmp(jnl_info.fn, gds_info->fab->fab$l_fna, jnl_info.fn_len));
+ assert(!jnl_info.no_rename);
+ assert(!jnl_info.no_prev_link);
+ if (EXIT_NRM == cre_jnl_file(&jnl_info))
+ {
+ assert(!memcmp(csd->jnl_file_name, jnl_info.jnl, jnl_info.jnl_len));
+ assert(csd->jnl_file_name[jnl_info.jnl_len] == '\0');
+ assert(csd->jnl_file_len == jnl_info.jnl_len);
+ assert(csd->jnl_buffer_size == jnl_info.buffer);
+ assert(csd->jnl_alq == jnl_info.alloc);
+ assert(csd->jnl_deq == jnl_info.extend);
+ assert(csd->jnl_before_image == jnl_info.before_images);
+ csd->jnl_checksum = jnl_info.checksum;
+ csd->jnl_eovtn = csd->trans_hist.curr_tn;
+ fc = gv_cur_region->dyn.addr->file_cntl;
+ fc->op = FC_WRITE; /* write needed for successful jnl_file_open() */
+ fc->op_buff = (sm_uc_ptr_t)csd;
+ fc->op_len = SGMNT_HDR_LEN;
+ fc->op_pos = 1;
+ send_msg(VARLSTCNT(4) ERR_NEWJNLFILECREAT, 2, JNL_LEN_STR(csd));
+ /* Dequeue the journal lock on the current jnl generation */
+ jpc->status = gtm_deq(jpc->jnllsb->lockid, NULL, PSL$C_USER, 0);
+ assert(SS$_NORMAL == jpc->status);
+ jpc->jnllsb->lockid = 0;
+ if ((SS_NORMAL != (status = set_jnl_file_close(SET_JNL_FILE_CLOSE_EXTEND)))
+ || (SS_NORMAL != (status = dbfilop(fc))))
+ {
+ send_msg(VARLSTCNT(7) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region),
+ status, 0, gds_info->fab->fab$l_stv);
+ jpc->status = ERR_JNLNOCREATE;
+ } else
+ {
+ /* set_jnl_file_close() would have opened and closed
+ * the new journal. we therefore have to reopen it now.
+ * this code should be removed in V4.4. see comment
+ * in sr_vvms/set_jnl_file_close.c for details
+ * --- nars -- 2002/04/18
+ */
+ jnl_status = jnl_ensure_open(); /* sets jpc->status */
+ if (jnl_status != 0)
+ {
+ if (SS_NORMAL != jpc->status2)
+ {
+ if (!(IS_RMS_ERROR(jpc->status2) ||
+ IS_SYSTEM_ERROR(jpc->status2)))
+ rts_error(VARLSTCNT(9) jnl_status, 4,
+ JNL_LEN_STR(csd),
+ DB_LEN_STR(gv_cur_region),
+ jpc->status, 0, jpc->status2);
+ else
+ rts_error(VARLSTCNT(8) jnl_status, 4,
+ JNL_LEN_STR(csd),
+ DB_LEN_STR(gv_cur_region),
+ jpc->status, jpc->status2);
+ }
+ else
+ rts_error(VARLSTCNT(7) jnl_status, 4,
+ JNL_LEN_STR(csd), DB_LEN_STR(gv_cur_region),
+ jpc->status);
+ }
+ assert(jb->filesize == csd->jnl_alq);
+ aligned_tot_jrec_size =
+ ALIGNED_ROUND_UP(MAX_REQD_JNL_FILE_SIZE(total_jnl_rec_size),
+ csd->jnl_alq, csd->jnl_deq);
+ if (aligned_tot_jrec_size > csd->jnl_alq)
+ { /* need to extend more than initial allocation
+ * in the new journal file to accommodate the
+ * current transaction.
+ */
+ new_blocks = aligned_tot_jrec_size - csd->jnl_alq;
+ assert(new_blocks);
+ assert(0 == new_blocks % csd->jnl_deq);
+ need_extend = TRUE;
+ }
+ }
+ } else
+ {
+ send_msg(VARLSTCNT(4) ERR_JNLNOCREATE, 2, JNL_LEN_STR(csd));
+ jpc->status = ERR_JNLNOCREATE;
+ }
+ } else
+ {
+ assert(FALSE);
+ rts_error(VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(gv_cur_region));
+ }
+ } else
+ { /* nullify extension jnl blocks */
+ buff = malloc(DISK_BLOCK_SIZE * BLKS_PER_WRITE);
+ memset(buff, 0, DISK_BLOCK_SIZE * BLKS_PER_WRITE);
+ rab.rab$w_rsz = DISK_BLOCK_SIZE * BLKS_PER_WRITE;
+ rab.rab$l_rbf = buff;
+ for (rab.rab$l_bkt = xabfhc.xab$l_ebk;
+ (SYSCALL_SUCCESS(jpc->status)) && (rab.rab$l_bkt <= new_alq);
+ rab.rab$l_bkt += BLKS_PER_WRITE)
+ {
+ if (rab.rab$l_bkt + BLKS_PER_WRITE > new_alq)
+ rab.rab$w_rsz = (new_alq + 1 - rab.rab$l_bkt) * DISK_BLOCK_SIZE;
+ jpc->status = sys$write(&rab);
+ if (SYSCALL_ERROR(jpc->status))
+ {
+ assert(FALSE);
+ rts_error(VARLSTCNT(6) ERR_JNLWRERR, 2, JNL_LEN_STR(csd), jpc->status,
+ rab.rab$l_stv);
+ }
+ }
+ jb->filesize = new_alq; /* Actually this is virtual file size blocks */
+ DO_FILE_READ(jpc->channel, 0, &header, REAL_JNL_HDR_LEN, jpc->status, jpc->status2);
+ if (SYSCALL_ERROR(jpc->status))
+ {
+ assert(FALSE);
+ rts_error(VARLSTCNT(5) ERR_JNLRDERR, 2, JNL_LEN_STR(csd), jpc->status);
+ }
+ assert((header.virtual_size + new_blocks) == new_alq);
+ header.virtual_size = new_alq;
+ JNL_DO_FILE_WRITE(NULL, NULL, jpc->channel, 0,
+ &header, REAL_JNL_HDR_LEN, jpc->status, jpc->status2);
+ if (SYSCALL_ERROR(jpc->status))
+ {
+ assert(FALSE);
+ rts_error(VARLSTCNT(5) ERR_JNLWRERR, 2, JNL_LEN_STR(csd), jpc->status);
+ }
+ assert(!need_extend); /* ensure we won't go through the for loop again */
+ free(buff);
+ }
+ } else if (new_blocks)
+ {
+ assert(FALSE);
+ jpc->status2 = rab.rab$l_stv;
+ }
+ if ((SYSCALL_ERROR(status = sys$close(&fab))) && new_blocks && (SYSCALL_SUCCESS(jpc->status)))
+ {
+ assert(FALSE);
+ jpc->status = status;
+ }
+ } else
+ {
+ assert(FALSE);
+ assert(SYSCALL_ERROR(jpc->status)); /* ensure we will follow the call to jnl_file_lost() below */
+ jpc->status2 = fab.fab$l_stv;
+ }
+ if (SYSCALL_ERROR(jpc->status))
+ break; /* break on error */
+ }
+ if (0 >= new_blocks)
+ {
+ assert(FALSE);
+ new_blocks = -1;
+ jpc->status = ERR_JNLREADEOF;
+ }
+ if ((SYSCALL_SUCCESS(jpc->status)) && (new_blocks > 0))
+ {
+ if (csd->clustered)
+ csa->ti->ccp_jnl_filesize = jb->filesize; /* Need to pass new filesize to other machines */
+ INCR_GVSTATS_COUNTER(csa, cnl, n_jnl_extends, 1);
+ return EXIT_NRM;
+ }
+ /* Notify operator and terminate journalling */
+ jnl_file_lost(jpc, ERR_JNLEXTEND);
+ return EXIT_ERR;
+}
+
+CONDITION_HANDLER(jnl_file_autoswitch_ch)
+{
+ START_CH;
+ assert(in_jnl_file_autoswitch);
+ in_jnl_file_autoswitch = FALSE;
+ jgbl.dont_reset_gbl_jrec_time = jgbl.save_dont_reset_gbl_jrec_time;
+ DEBUG_ONLY(jgbl.save_dont_reset_gbl_jrec_time = FALSE);
+ NEXTCH;
+}
diff --git a/sr_vvms/jnl_file_open.c b/sr_vvms/jnl_file_open.c
new file mode 100644
index 0000000..3fd18a8
--- /dev/null
+++ b/sr_vvms/jnl_file_open.c
@@ -0,0 +1,300 @@
+/***************************************************************
+ * *
+ * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <descrip.h>
+#include <fab.h>
+#include <iodef.h>
+#include <lckdef.h>
+#include <nam.h>
+#include <psldef.h>
+#include <rmsdef.h>
+#include <ssdef.h>
+#include <xab.h>
+#include "gtm_inet.h"
+#include <efndef.h>
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "jnl.h"
+#include "probe.h"
+#include "repl_msg.h"
+#include "gtmsource.h"
+#include "locks.h"
+#include "gtmmsg.h"
+#include "send_msg.h"
+#include "iosp.h" /* for SS_NORMAL */
+#include "gtmimagename.h"
+#include "gtmrecv.h"
+#include "repl_sp.h" /* for F_CLOSE (used by JNL_FD_CLOSE) */
+
+#include "wbox_test_init.h"
+
+GBLREF jnlpool_ctl_ptr_t jnlpool_ctl;
+GBLREF boolean_t pool_init;
+GBLREF boolean_t is_src_server;
+GBLREF boolean_t is_updproc;
+GBLREF boolean_t is_updhelper;
+GBLREF upd_helper_entry_ptr_t helper_entry;
+GBLREF jnl_process_vector *prc_vec;
+GBLREF boolean_t forw_phase_recovery;
+
+error_def(ERR_CLSTCONFLICT);
+error_def(ERR_JNLFILOPN);
+error_def(ERR_JNLOPNERR);
+
+static const unsigned short zero_fid[3];
+
+/* Called from the blocking AST routine entered to release the journal file, as a result of a MUPIP SET command */
+
+void jnl_oper_user_ast(gd_region *reg)
+{
+ jnl_private_control *jpc;
+ uint4 status;
+ int close_res;
+
+ if (reg && reg->open)
+ {
+ jpc = FILE_INFO(reg)->s_addrs.jnl;
+ if (SS_NORMAL != jpc->status)
+ {
+ assert(0 != jpc->jnllsb->lockid);
+ status = gtm_deq(jpc->jnllsb->lockid, NULL, PSL$C_USER, 0);
+ assert(SS$_NORMAL == status);
+ jnl_send_oper(jpc, status);
+
+ }
+ if ((FALSE == jpc->qio_active) && (NOJNL != jpc->old_channel))
+ {
+ JNL_FD_CLOSE(jpc->old_channel, close_res); /* sets csa->jnl->channel to NOJNL */
+ jpc->pini_addr = 0;
+ jpc->jnllsb->lockid = 0;
+ }
+ }
+}
+
+/* NOTE: Because the blocking AST routine is established via a call to gtm_enqw,
+ it executes in KERNEL mode; jnl_oper_user_ast, however, must execute in USER mode.
+ This is accomplished by using sys$dclast, explicitly specifying USER mode. */
+
+static void jnl_oper_krnl_ast(gd_region *reg)
+{
+ jnl_private_control *jpc;
+
+ if (!GTM_PROBE(SIZEOF(gd_region), reg, READ) || !reg->open)
+ return;
+ if (!GTM_PROBE(SIZEOF(gd_segment), reg->dyn.addr, READ))
+ return;
+ if (dba_bg != reg->dyn.addr->acc_meth && dba_mm != reg->dyn.addr->acc_meth)
+ return;
+ if (!GTM_PROBE(SIZEOF(file_control), reg->dyn.addr->file_cntl, READ))
+ return;
+ if (!GTM_PROBE(SIZEOF(vms_gd_info), reg->dyn.addr->file_cntl->file_info, READ))
+ return;
+
+ jpc = FILE_INFO(reg)->s_addrs.jnl; /* since *cs_addrs is a part of vms_gds_info, no additional probe
+ for sgmnt_addrs is needed */
+ if (!GTM_PROBE(SIZEOF(jnl_private_control), jpc, WRITE))
+ return;
+ if ((FALSE == jpc->qio_active) && (NOJNL != jpc->channel))
+ {
+ jpc->old_channel = jpc->channel;
+ jpc->channel = NOJNL;
+ if (!GTM_PROBE(SIZEOF(vms_lock_sb), jpc->jnllsb, WRITE))
+ return;
+ jpc->status = gtm_deq(jpc->jnllsb->lockid, NULL, PSL$C_USER, 0);
+ sys$dclast(jnl_oper_user_ast, reg, PSL$C_USER); /* if it fails, jnl_ensure_open should cleanup */
+ }
+}
+
+uint4 jnl_file_open(gd_region *reg, bool init, void oper_ast())
+{
+ sgmnt_addrs *csa;
+ sgmnt_data *csd;
+ node_local_ptr_t cnl;
+ struct FAB fab; /* same name as other modules help to compare code */
+ struct NAM nam;
+ struct XABFHC xabfhc;
+ struct XABITM xabitm;
+ struct xab_caching_options_flags xabitemcacheopt;
+ struct {
+ short len,
+ cod;
+ void *address;
+ int *retlen;
+ } xabitemlist[2];
+ jnl_private_control *jpc;
+ jnl_buffer *jb;
+ jnl_file_header header;
+ uint4 status, sts;
+ char name_buffer[GLO_NAME_MAXLEN], es_buffer[MAX_FN_LEN];
+ boolean_t retry;
+ $DESCRIPTOR(desc, name_buffer);
+
+ if ((dba_bg != reg->dyn.addr->acc_meth) && (dba_mm != reg->dyn.addr->acc_meth))
+ GTMASSERT;
+ if (NULL == oper_ast)
+ oper_ast = jnl_oper_krnl_ast;
+ csa = &FILE_INFO(reg)->s_addrs;
+ csd = csa->hdr;
+ cnl = csa->nl;
+ jpc = csa->jnl;
+ jb = jpc->jnl_buff;
+ assert(NOJNL == jpc->channel);
+ sts = 0;
+ jpc->status = jpc->status2 = SS_NORMAL; /* caution : SS_NORMAL not equal to 0 in VMS */
+ xabfhc = cc$rms_xabfhc;
+ nam = cc$rms_nam;
+ fab = cc$rms_fab;
+ fab.fab$l_fop = FILE_INFO(reg)->fab->fab$l_fop;
+ fab.fab$b_shr = FILE_INFO(reg)->fab->fab$b_shr;
+ fab.fab$b_fac = FILE_INFO(reg)->fab->fab$b_fac;
+ fab.fab$l_xab = &xabfhc;
+ if (csd->jnl_sync_io && (IS_GTM_IMAGE || is_updproc || (is_updhelper && helper_entry &&
+ (UPD_HELPER_WRITER == helper_entry->helper_type))))
+ { /* setup xabitm and link in */
+ xabitemcacheopt.xab$v_file_attributes = 0;
+ xabitemcacheopt.xab$v_file_contents = XAB$K_NOCACHING;
+ xabitemcacheopt.xab$v_flush_on_close = XAB$K_FLUSH;
+ xabitemcacheopt.xab$v_cachectl_mbz = 0;
+ memset(&xabitemlist, 0, SIZEOF(xabitemlist));
+ xabitemlist[0].len = SIZEOF(struct xab_caching_options_flags);
+ xabitemlist[0].cod = XAB$_CACHING_OPTIONS;
+ xabitemlist[0].address = &xabitemcacheopt;
+ memset(&xabitm, 0, SIZEOF(xabitm));
+ xabitm.xab$b_bln = XAB$C_ITMLEN;
+ xabitm.xab$b_cod = XAB$C_ITM;
+ xabitm.xab$l_itemlist = xabitemlist;
+ xabitm.xab$b_mode = XAB$K_SETMODE;
+ xabfhc.xab$l_nxt = &xabitm;
+ }
+ fab.fab$l_nam = &nam;
+ if (init)
+ {
+ cre_jnl_file_intrpt_rename(((int)csd->jnl_file_len), csd->jnl_file_name);
+ nam.nam$l_esa = es_buffer; /* Though conclealed name is not possible, we use it */
+ nam.nam$b_ess = SIZEOF(es_buffer);
+ fab.fab$l_fna = csd->jnl_file_name;
+ fab.fab$b_fns = csd->jnl_file_len;
+ /* although jnl_file_close() would have memset cnl->jnl_file.jnl_file_id to 0 and incremented cycle, it
+ * might have got shot in the middle of executing those instructions. we redo it here just to be safe.
+ */
+ memset(&cnl->jnl_file.jnl_file_id, 0, SIZEOF(cnl->jnl_file.jnl_file_id));
+ jb->cycle++; /* increment shared cycle so all future callers of jnl_ensure_open recognize journal switch */
+ for (retry = TRUE; ;)
+ {
+ status = sys$open(&fab);
+ if (0 == (status & 1))
+ {
+ jpc->status = status;
+ jpc->status2 = fab.fab$l_stv;
+ sts = ERR_JNLFILOPN;
+ if (RMS$_PRV == status)
+ break;
+ } else
+ {
+ jpc->channel = fab.fab$l_stv;
+ sts = jnl_file_open_common(reg, DISK_BLOCK_SIZE * (xabfhc.xab$l_ebk - 1));
+ }
+ if ((0 != sts) && retry)
+ {
+ assert(!is_src_server); /* source server should only read journal files so must never reach
+ * a situation where it has to switch journal files.
+ */
+ sts = jnl_file_open_switch(reg, sts);
+ retry = FALSE; /* Do not switch more than once, even if error occurs */
+ if (0 == sts)
+ continue;
+ }
+ break;
+ }
+ } else
+ {
+ ASSERT_JNLFILEID_NOT_NULL(csa);
+ /* use the file id in node-local shared memory to open the journal file */
+ memcpy(&nam.nam$t_dvi, &cnl->jnl_file.jnl_file_id.dvi, SIZEOF(cnl->jnl_file.jnl_file_id.dvi));
+ memcpy(&nam.nam$w_did, &cnl->jnl_file.jnl_file_id.did, SIZEOF(cnl->jnl_file.jnl_file_id.did));
+ memcpy(&nam.nam$w_fid, &cnl->jnl_file.jnl_file_id.fid, SIZEOF(cnl->jnl_file.jnl_file_id.fid));
+ fab.fab$l_fop |= FAB$M_NAM;
+ status = sys$open(&fab);
+ if (!(status & 1))
+ {
+ jpc->status = status;
+ jpc->status2 = fab.fab$l_stv;
+ sts = ERR_JNLFILOPN;
+ } else if (csd->clustered && (0 == jb->size))
+ {
+ /* CCP -- not first to open */
+ jb->size = csd->jnl_buffer_size * DISK_BLOCK_SIZE;
+ jb->filesize = xabfhc.xab$l_ebk; /* Why not virtual file size ??? */
+ jb->min_write_size = JNL_MIN_WRITE;
+ jb->max_write_size = JNL_MAX_WRITE;
+ }
+ }
+ /* Clear out any previous out-of-sync values that new_dskaddr/new_dsk might have (from previous journal files) */
+ jpc->new_dskaddr = jpc->new_dsk = 0;
+ /* Also clear out the field that controls whether the above two fields are used in secshr_db_clnup */
+ jpc->dsk_update_inprog = FALSE;
+ if (0 == sts)
+ {
+ if (!is_src_server)
+ {
+ global_name("GT$J", &FILE_INFO(reg)->file_id, name_buffer);
+ desc.dsc$w_length = name_buffer[0];
+ desc.dsc$a_pointer = &name_buffer[1];
+ desc.dsc$b_dtype = DSC$K_DTYPE_T;
+ desc.dsc$b_class = DSC$K_CLASS_S;
+ memset(jpc->jnllsb, 0, SIZEOF(vms_lock_sb));
+ status = gtm_enqw(EFN$C_ENF, LCK$K_NLMODE, jpc->jnllsb, LCK$M_SYSTEM | LCK$M_EXPEDITE, &desc, 0, NULL,
+ 0, NULL, PSL$C_USER, 0);
+ if (SS_NORMAL == status)
+ status = jpc->jnllsb->cond;
+ if (SS_NORMAL == status)
+ {
+ status = gtm_enqw(EFN$C_ENF, LCK$K_CRMODE, jpc->jnllsb, LCK$M_CONVERT | LCK$M_NODLCKBLK,
+ NULL, 0, NULL, reg, oper_ast, PSL$C_USER, 0);
+ if (SS_NORMAL == status)
+ status = jpc->jnllsb->cond;
+ }
+ if (SS_NORMAL != status)
+ {
+ sys$dassgn(fab.fab$l_stv);
+ jpc->status = status;
+ sts = ERR_CLSTCONFLICT;
+ }
+ }
+ if (is_src_server || SS_NORMAL == status)
+ {
+ if (init)
+ { /* deferred to ensure that the lock works - stash the file id in node-local for subsequent users */
+ memcpy(&cnl->jnl_file.jnl_file_id.dvi, &nam.nam$t_dvi, SIZEOF(cnl->jnl_file.jnl_file_id.dvi));
+ memcpy(&cnl->jnl_file.jnl_file_id.did, &nam.nam$w_did, SIZEOF(cnl->jnl_file.jnl_file_id.did));
+ memcpy(&cnl->jnl_file.jnl_file_id.fid, &nam.nam$w_fid, SIZEOF(cnl->jnl_file.jnl_file_id.fid));
+ }
+ jpc->channel = fab.fab$l_stv;
+ jpc->cycle = jb->cycle; /* make private cycle and shared cycle in sync */
+ jpc->sync_io = csd->jnl_sync_io;
+ }
+ }
+ GTM_WHITE_BOX_TEST(WBTEST_JNL_FILE_OPEN_FAIL, sts, ERR_JNLFILOPN);
+ if (0 != sts)
+ {
+ jpc->channel = NOJNL;
+ jnl_send_oper(jpc, sts);
+ }
+ assert((0 != sts) || (NOJNL != jpc->channel));
+ return sts;
+}
diff --git a/sr_vvms/jnl_output_sp.c b/sr_vvms/jnl_output_sp.c
new file mode 100644
index 0000000..55b5222
--- /dev/null
+++ b/sr_vvms/jnl_output_sp.c
@@ -0,0 +1,298 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <iodef.h>
+#include <psldef.h>
+#include <efndef.h>
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "jnl.h"
+#include "efn.h"
+#include "locks.h"
+#include "crit_wake.h"
+#include "memcoherency.h"
+#include "wbox_test_init.h"
+
+GBLREF short astq_dyn_avail;
+GBLREF uint4 image_count;
+GBLREF uint4 process_id;
+
+error_def(ERR_JNLACCESS);
+error_def(ERR_JNLACCESS);
+error_def(ERR_JNLWRTDEFER);
+error_def(ERR_JNLWRTNOWWRTR);
+
+uint4 jnl_qio_start(jnl_private_control *jpc)
+{
+ uint4 new_dskaddr, status;
+
+ assert(!lib$ast_in_prog());
+ /* mainline entry can't go to the ast directly to avoid being recursed upon by wcs_wtstart */
+ if (!jpc->qio_active)
+ { /* only try the ast if this process doesn't have a write in progress */
+ new_dskaddr = jpc->new_dskaddr;
+ status = jnl_permit_ast(jpc);
+ if (SS$_NORMAL != status)
+ jnl_send_oper(jpc, ERR_JNLACCESS);
+ else if (!jpc->qio_active && jpc->jnl_buff->io_in_prog)
+ status = ERR_JNLWRTDEFER;
+ } else
+ status = ERR_JNLWRTNOWWRTR;
+ return (status);
+}
+
+uint4 jnl_permit_ast(jnl_private_control *jpc)
+{
+
+ /* this extra level exists to provide a return that may permit the ast to process, thus making status info available */
+ assert(!lib$ast_in_prog());
+ return (sys$dclast(jnl_start_ast, jpc, PSL$C_USER));
+}
+
+void jnl_start_ast(jnl_private_control *jpc)
+{
+ void jnl_qio_end();
+ bool bsi(), bci();
+ int tsz;
+ int4 free;
+ uint4 status;
+ sm_uc_ptr_t base;
+ jnl_buffer_ptr_t jb;
+
+ assert(lib$ast_in_prog());
+ if (!jpc->qio_active && (NOJNL != jpc->channel))
+ { /* no jnl io inprogress by this process and haven't lost the file through an operator close */
+ jb = jpc->jnl_buff;
+ if (FALSE == bsi(&jb->io_in_prog)) /* jnl writes are single threaded */
+ { /* got jb write exclusive ownership */
+ if (jb->blocked && jb->blocked != process_id)
+ { /* Blocking requires special handling to prevent deadlocks since ASTs can't be
+ * nested. The process that is currently blocked knows to issue the right jnl-qio
+ * commands (taking care that the qio gets cleaned up without deadlocking). But
+ * if non-blocked processes are allowed to take up io_in_prog ownership, deadlocks
+ * can occur. e.g. P1 takes up io_in_prog of region R1 and enters into a
+ * wcs_wipchk_ast() for region R2. P2 in the meantime takes up io_in_prog for
+ * region R2 and enters into wcs_wipchk_ast() for region R1.
+ */
+ bci(&jb->io_in_prog);
+ return;
+ }
+ if (JNL_FILE_SWITCHED(jpc))
+ { /* don't know how we can have an old journal file open if we have dirty data in the journal buffer,
+ * but it is safer to handle this case by not doing the qio (D9C12-002266) so we do not corrupt
+ * both old (because we overwrite) and current journal file (because we miss out on writing some
+ * data). if we do not have any data left in the journal buffer to write, it is possible that we
+ * come here if we get interrupted in jnl_file_close() (by wcs_stale() which results in a call to
+ * jnl_qio_start()) after the increment of jb->cycle but before jpc->channel got set to NOJNL. In
+ * this case, doing nothing is the right thing to do as all jnl data flushing has already happened.
+ */
+ assert((jb->dskaddr == jb->freeaddr)
+ || (gtm_white_box_test_case_enabled
+ && (WBTEST_JNL_FILE_LOST_DSKADDR == gtm_white_box_test_case_number)));
+ jpc->fd_mismatch = TRUE;
+ bci(&jb->io_in_prog); /* release lock and return */
+ return;
+ } else
+ jpc->fd_mismatch = FALSE;
+ /* Take a copy of the shared dsk* fields while holding the io_in_prog lock. This is used by
+ * jnl_write_attempt to determine if there is a JNLCNTRL error with dskaddr/dsk.
+ */
+ jpc->new_dskaddr = jb->dskaddr;
+ jpc->new_dsk = jb->dsk;
+ if ((jb->dskaddr % jb->size) != jb->dsk)
+ { /* This is a JNLCNTRL error but since we are inside an AST we cannot return any non-zero value.
+ * We expect caller (jnl_write_attempt) to detect this from the copy of new_dskaddr/new_dsk.
+ */
+ bci(&jb->io_in_prog); /* release lock and return */
+ return;
+ }
+ /* Start jnl qio */
+ jpc->qio_active = TRUE;
+ jb->image_count = image_count;
+ jb->now_writer = process_id;
+ free = jb->free;
+ /* The following barrier is to make sure that for the value of "free" that we extract (which may be
+ slightly stale but that is not a correctness issue) we make sure we dont write out a stale version of
+ the journal buffer contents. While it is possible that we see journal buffer contents that are more
+ uptodate than "free", this would only mean writing out a less than optimal number of bytes but again,
+ not a correctness issue. Secondary effect is that it also enforces a corresponding non-stale value of
+ freeaddr is read and this is relied upon by asserts below.
+ */
+ SHM_READ_MEMORY_BARRIER;
+ tsz = (free < jb->dsk ? jb->size : free) - jb->dsk;
+ assert(0 <= tsz);
+ assert(jb->dskaddr + tsz <= jb->freeaddr);
+ if (tsz)
+ { /* ensure that dsk and free are never equal and we have left space for JNL_WRT_START_MASK */
+ assert((free > jb->dsk) || (free < (jb->dsk & JNL_WRT_START_MASK(jb)))
+ || (jb->dsk != (jb->dsk & JNL_WRT_START_MASK(jb))));
+ assert(DISK_BLOCKS_SUM(jb->dskaddr, tsz) <= jb->filesize);
+ jb->qiocnt++;
+ jb->wrtsize = tsz;
+ tsz += (jb->dsk - (jb->dsk & JNL_WRT_START_MASK(jb))); /* back up to block boundary */
+ assert(0 == jb->buff_off); /* buff_off should have been set to 0 in jnl_file_open_common.c */
+ base = &jb->buff[jb->dsk & JNL_WRT_START_MASK(jb)];
+ assert(tsz >= jb->wrtsize);
+ assert(base >= jb->buff);
+ assert(base < (jb->buff + jb->size));
+ tsz = (tsz + ~JNL_WRT_END_MASK) & JNL_WRT_END_MASK; /* round-up to quad-word boundary */
+ if (tsz > jb->max_write_size)
+ {
+ tsz = jb->max_write_size;
+ jb->wrtsize = tsz - ((jb->buff + jb->dsk) - base);
+ }
+ assert((base + tsz) <= (jb->buff + jb->size));
+ if (jb->blocked != process_id)
+ {
+ status = sys$qio(efn_jnl, jpc->channel, IO$_WRITEVBLK, &jb->iosb, jnl_qio_end, jpc,
+ base, tsz, jb->dskaddr/DISK_BLOCK_SIZE + 1, 0, 0, 0);/* 1st block is designated 1 */
+ if (0 == (status & 1))
+ { /*modify iosb so that qio_end will process the error*/
+ assert(FALSE);
+ jb->iosb.cond = status;
+ jb->iosb.length = 0;
+ jb->iosb.dev_specific = 0;
+ jnl_qio_end(jpc);
+ }
+ } else
+ { /* Do qiow */
+ status = sys$qiow(EFN$C_ENF, jpc->channel, IO$_WRITEVBLK, &jb->iosb, NULL, 0,
+ base, tsz, jb->dskaddr/DISK_BLOCK_SIZE + 1, 0, 0, 0);
+ if (0 == (status & 1))
+ {
+ assert(FALSE);
+ jb->iosb.cond = status;
+ jb->iosb.length = 0;
+ jb->iosb.dev_specific = 0;
+ }
+ jnl_qio_end(jpc);
+ }
+ } else
+ { /* nothing left to write */
+ jb->wrtsize = 0;
+ jb->iosb.cond = 1;
+ jnl_qio_end(jpc); /* qio_active semaphore prevents need for dclast */
+ }
+ } /* if got jb write exclusive ownersip */
+ } /* if no io in progress and have a channel */
+ return;
+}
+
+void jnl_qio_end(jnl_private_control *jpc)
+{
+ bool bci();
+ uint4 wake_pid;
+ jnl_buffer *jb;
+ sgmnt_addrs *csa;
+ node_local_ptr_t cnl;
+
+ if (FALSE == jpc->qio_active)
+ return; /* during exi_rundown, secshr_db_clnup may have effectively "cancelled" the io */
+ jb = jpc->jnl_buff;
+ assert(jb->io_in_prog);
+ csa = &FILE_INFO(jpc->region)->s_addrs;
+ if (0 == (jb->iosb.cond & 1))
+ {
+ jb->errcnt++;
+ jnl_send_oper(jpc, ERR_JNLACCESS);
+ } else
+ {
+ assert(jb->dsk <= jb->size);
+ assert(jb->freeaddr >= jb->dskaddr);
+ jpc->new_dsk = jb->dsk + jb->wrtsize;
+ if (jpc->new_dsk >= jb->size)
+ jpc->new_dsk = 0;
+ jpc->new_dskaddr = jb->dskaddr + jb->wrtsize;
+ assert(jb->freeaddr >= jpc->new_dskaddr);
+ jpc->dsk_update_inprog = TRUE;
+ jb->dsk = jpc->new_dsk;
+ jb->dskaddr = jpc->new_dskaddr;
+ jpc->dsk_update_inprog = FALSE;
+ assert(jb->freeaddr >= jb->dskaddr);
+ cnl = csa->nl;
+ INCR_GVSTATS_COUNTER(csa, cnl, n_jfile_bytes, jb->wrtsize);
+ INCR_GVSTATS_COUNTER(csa, cnl, n_jfile_writes, 1);
+ }
+ jb->iosb.cond = -2; /* don't leave success set */
+ jb->now_writer = 0; /* NOTE: The order of these lines is necessary for concurrency control */
+ jpc->qio_active = FALSE;
+ bci(&jb->io_in_prog);
+ wake_pid = jb->blocked;
+ if (0 != wake_pid)
+ crit_wake(&wake_pid);
+ /* If we dont have crit and journaling state has been turned to OFF concurrently, need to free up our journal
+ * resources for the crit holding process (currently either switching journals or turning journaling OFF) to
+ * proceed. If we hold crit though and free up the journal resources as part of this interrupt routine (jnl_qio_end),
+ * it is possible that mainline code (one that is switching journals or turning journaling OFF e.g. jnl_file_lost)
+ * will be confused about whether to do the journal resource free up depending on where in the execution flow
+ * the jnl_qio_end AST got delivered. Therefore do not do any freeup while holding crit and in interrupt code.
+ */
+ if (!csa->now_crit && (jnl_closed == csa->hdr->jnl_state))
+ { /* operator close that this process needs to recognize */
+ jpc->old_channel = jpc->channel;
+ jpc->channel = NOJNL;
+ jpc->status = gtm_deq(jpc->jnllsb->lockid, NULL, PSL$C_USER, 0);
+ assert(SS$_NORMAL == jpc->status);
+ if (SS$_NORMAL == jpc->status)
+ jpc->jnllsb->lockid = 0;
+ jnl_oper_user_ast(jpc->region); /* which should deq the lock */
+ }
+ return;
+}
+
+void jnl_mm_timer_write(gd_region *reg)
+{
+ sgmnt_addrs *csa;
+
+ assert(lib$ast_in_prog());
+ assert(reg->open); /* gds_rundown() should have cancelled timers for this region before setting reg->open to FALSE */
+ if (!reg->open)
+ return;
+ csa = &FILE_INFO(reg)->s_addrs;
+ if (csa->jnl) /* cover trip during rundown */
+ jnl_start_ast(csa->jnl);
+ adawi(-1, &csa->nl->wcs_timers);
+ csa->timer = FALSE;
+ astq_dyn_avail++;
+ return;
+}
+
+void jnl_mm_timer(sgmnt_addrs *csa, gd_region *reg)
+{
+ uint4 status;
+
+ assert(reg->open);
+ if (!csa->timer && csa->nl->wcs_timers < 1)
+ {
+ if (astq_dyn_avail > 0)
+ {
+ astq_dyn_avail--;
+ csa->timer = TRUE;
+ adawi(1, &csa->nl->wcs_timers);
+ status = sys$setimr(efn_ignore, &csa->hdr->flush_time[0], jnl_mm_timer_write, reg, 0);
+ if (0 == (status & 1))
+ {
+ adawi(-1, &csa->nl->wcs_timers);
+ csa->timer = FALSE;
+ astq_dyn_avail++;
+ }
+ }
+ }
+ return;
+}
diff --git a/sr_vvms/jnl_prc_vector.c b/sr_vvms/jnl_prc_vector.c
new file mode 100644
index 0000000..9df495c
--- /dev/null
+++ b/sr_vvms/jnl_prc_vector.c
@@ -0,0 +1,99 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <jpidef.h>
+#include <syidef.h>
+#include <ssdef.h>
+#include <efndef.h>
+
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "jnl.h"
+#include "vmsdtype.h"
+
+
+void jnl_prc_vector(pv)
+jnl_process_vector *pv;
+{
+ struct
+ {
+ item_list_3 item[7];
+ int4 terminator;
+ } item_list;
+ unsigned short iosb[4];
+ uint4 mode, status, dummy;
+
+
+ memset(pv, 0, SIZEOF(jnl_process_vector));
+
+ sys$gettim(&pv->jpv_time);
+
+ item_list.item[0].buffer_length = SIZEOF(pv->jpv_pid);
+ item_list.item[0].item_code = JPI$_PID;
+ item_list.item[0].buffer_address = &pv->jpv_pid;
+ item_list.item[0].return_length_address = &dummy;
+
+ item_list.item[1].buffer_length = SIZEOF(pv->jpv_login_time);
+ item_list.item[1].item_code = JPI$_LOGINTIM;
+ item_list.item[1].buffer_address = &pv->jpv_login_time;
+ item_list.item[1].return_length_address = &dummy;
+
+ item_list.item[2].buffer_length = SIZEOF(pv->jpv_image_count);
+ item_list.item[2].item_code = JPI$_IMAGECOUNT;
+ item_list.item[2].buffer_address = &pv->jpv_image_count;
+ item_list.item[2].return_length_address = &dummy;
+
+ item_list.item[3].buffer_length = SIZEOF(mode);
+ item_list.item[3].item_code = JPI$_JOBTYPE;
+ item_list.item[3].buffer_address = &mode; /* jpv_mode set below */
+ item_list.item[3].return_length_address = &dummy;
+
+ item_list.item[4].buffer_length = SIZEOF(pv->jpv_user);
+ item_list.item[4].item_code = JPI$_USERNAME;
+ item_list.item[4].buffer_address = pv->jpv_user;
+ item_list.item[4].return_length_address = &dummy;
+
+ item_list.item[5].buffer_length = SIZEOF(pv->jpv_prcnam);
+ item_list.item[5].item_code = JPI$_PRCNAM;
+ item_list.item[5].buffer_address = pv->jpv_prcnam;
+ item_list.item[5].return_length_address = &dummy;
+
+ item_list.item[6].buffer_length = SIZEOF(pv->jpv_terminal);
+ item_list.item[6].item_code = JPI$_TERMINAL;
+ item_list.item[6].buffer_address = pv->jpv_terminal;
+ item_list.item[6].return_length_address = &dummy;
+
+ item_list.terminator = 0;
+
+ if ((status = sys$getjpiw(EFN$C_ENF, NULL, NULL, &item_list, iosb, NULL, 0)) != SS$_NORMAL ||
+ (status = iosb[0]) != SS$_NORMAL)
+ rts_error(status);
+
+ pv->jpv_mode = mode;
+
+
+ item_list.item[0].buffer_length = SIZEOF(pv->jpv_node);
+ item_list.item[0].item_code = SYI$_NODENAME;
+ item_list.item[0].buffer_address = pv->jpv_node;
+ item_list.item[0].return_length_address = &dummy;
+
+ *((int4 *)&item_list.item[1]) = 0; /* terminator */
+
+ if ((status = sys$getsyiw(EFN$C_ENF, NULL, NULL, &item_list, iosb, NULL, 0)) != SS$_NORMAL ||
+ (status = iosb[0]) != SS$_NORMAL)
+ rts_error(status);
+
+}
diff --git a/sr_vvms/jnlext_write.c b/sr_vvms/jnlext_write.c
new file mode 100644
index 0000000..32df40b
--- /dev/null
+++ b/sr_vvms/jnlext_write.c
@@ -0,0 +1,42 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2004 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <fab.h>
+#include <rab.h>
+#include <rmsdef.h>
+
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "jnl.h"
+#include "buddy_list.h"
+#include "hashtab_mname.h" /* needed for muprec.h */
+#include "hashtab_int4.h" /* needed for muprec.h */
+#include "hashtab_int8.h" /* needed for muprec.h */
+#include "muprec.h"
+
+void jnlext_write(fi_type *file_info, char *buffer, int length)
+{
+ uint4 status;
+
+ error_def (ERR_JNLEXTR);
+
+ file_info->rab->rab$w_rsz = length - 1;
+ file_info->rab->rab$l_rbf = buffer;
+ status = sys$put(file_info->rab);
+ if (status != RMS$_NORMAL)
+ rts_error(VARLSTCNT(5) ERR_JNLEXTR, 2, file_info->fab->fab$b_fns, file_info->fab->fab$l_fna, status);
+}
diff --git a/sr_vvms/jnlpool_init.c b/sr_vvms/jnlpool_init.c
new file mode 100644
index 0000000..5964869
--- /dev/null
+++ b/sr_vvms/jnlpool_init.c
@@ -0,0 +1,384 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <ssdef.h>
+#include <prtdef.h>
+#include <secdef.h>
+#include <psldef.h>
+#include <descrip.h>
+#include <stddef.h>
+
+#include <errno.h>
+#include "gtm_inet.h" /* Required for gtmsource.h */
+#include "gtm_fcntl.h"
+#include "gtm_unistd.h"
+#include "gtm_stdlib.h"
+#include "gtm_string.h"
+
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "repl_sem.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "iosp.h"
+#include "repl_msg.h"
+#include "gtmsource.h"
+#include "gtm_logicals.h"
+#include "jnl.h"
+#include "repl_shm.h"
+#include "io.h"
+#include "is_file_identical.h"
+#include "trans_log_name.h"
+#include "error.h"
+#include "mutex.h"
+
+GBLREF jnlpool_addrs jnlpool;
+GBLREF jnlpool_ctl_ptr_t jnlpool_ctl;
+GBLREF sm_uc_ptr_t jnldata_base;
+GBLREF int4 jnlpool_shmid;
+GBLREF uint4 process_id;
+GBLREF gd_region *gv_cur_region;
+GBLREF jnlpool_ctl_ptr_t temp_jnlpool_ctl;
+GBLREF gtmsource_options_t gtmsource_options;
+GBLREF boolean_t pool_init;
+GBLREF uint4 process_id;
+
+GBLREF seq_num seq_num_zero;
+LITREF char gtm_release_name[];
+LITREF int4 gtm_release_name_len;
+
+static gd_region jnlpool_dummy_reg;
+static gd_segment jnlpool_dummy_seg;
+static file_control jnlpool_dummy_fc;
+static vms_gds_info jnlpool_dummy_vdi;
+static sgmnt_addrs *jnlpool_dummy_sa;
+
+/* Keep track of which resources we have so we can release them if necessary in
+ our condition handler.
+*/
+static VSIG_ATOMIC_T have_source_access_sem;
+static VSIG_ATOMIC_T have_source_options_sem;
+static VSIG_ATOMIC_T have_source_count_sem;
+static VSIG_ATOMIC_T gsec_is_registered;
+
+#define MAX_RES_TRIES 620 /* Also defined in gvcst_init_sysops.c */
+
+error_def(ERR_ASSERT);
+error_def(ERR_GTMASSERT);
+error_def(ERR_GTMASSERT2);
+error_def(ERR_GTMCHECK);
+error_def(ERR_JNLPOOLSETUP);
+error_def(ERR_REPLERR);
+error_def(ERR_REPLWARN);
+error_def(ERR_STACKOFLOW);
+error_def(ERR_TEXT);
+error_def(ERR_VMSMEMORY);
+
+CONDITION_HANDLER(jnlpool_init_ch)
+{
+ START_CH;
+ if (!(IS_GTM_ERROR(SIGNAL)) || DUMPABLE || SEVERITY == ERROR)
+ { /* Release resources we have aquired */
+ if (gsec_is_registered)
+ {
+ gsec_is_registered = FALSE;
+ signoff_from_gsec(jnlpool.shm_lockid);
+ }
+ if (have_source_count_sem)
+ {
+ have_source_count_sem = FALSE;
+ rel_sem_immediate(SOURCE, SRC_SERV_COUNT_SEM);
+ }
+ if (have_source_options_sem)
+ {
+ have_source_options_sem = FALSE;
+ rel_sem_immediate(SOURCE, SRC_SERV_OPTIONS_SEM);
+ }
+ if (have_source_access_sem)
+ {
+ have_source_access_sem = FALSE;
+ rel_sem_immediate(SOURCE, JNL_POOL_ACCESS_SEM);
+ }
+ NEXTCH;
+ }
+ /* warning, info, or success */
+ CONTINUE;
+}
+
+void jnlpool_init(jnlpool_user pool_user,
+ boolean_t gtmsource_startup,
+ boolean_t *jnlpool_initialized)
+{
+ mstr log_nam, trans_log_nam;
+ char trans_buff[MAX_FN_LEN+1];
+ int4 status;
+ uint4 ustatus;
+ unsigned int full_len;
+ boolean_t shm_created;
+ struct dsc$descriptor_s name_dsc;
+ char res_name[MAX_NAME_LEN + 2]; /* +1 for the terminator and another +1 for the length stored in [0] by
+ global_name() */
+ gds_file_id file_id;
+ mutex_spin_parms_ptr_t jnlpool_mutex_spin_parms;
+
+ have_source_access_sem = FALSE;
+ have_source_options_sem = FALSE;
+ have_source_count_sem = FALSE;
+ gsec_is_registered = FALSE;
+ ESTABLISH(jnlpool_init_ch);
+ memset((uchar_ptr_t)&jnlpool, 0, SIZEOF(jnlpool_addrs));
+ memset((uchar_ptr_t)&jnlpool_dummy_reg, 0, SIZEOF(gd_region));
+ memset((uchar_ptr_t)&jnlpool_dummy_seg, 0, SIZEOF(gd_segment));
+ memset((uchar_ptr_t)&jnlpool_dummy_fc, 0, SIZEOF(file_control));
+ memset((uchar_ptr_t)&jnlpool_dummy_vdi, 0, SIZEOF(vms_gds_info));
+
+ jnlpool.jnlpool_dummy_reg = &jnlpool_dummy_reg;
+ MEMCPY_LIT(jnlpool_dummy_reg.rname, JNLPOOL_DUMMY_REG_NAME);
+ jnlpool_dummy_reg.rname_len = STR_LIT_LEN(JNLPOOL_DUMMY_REG_NAME);
+ jnlpool_dummy_reg.dyn.addr = &jnlpool_dummy_seg;
+ jnlpool_dummy_reg.dyn.addr->acc_meth = dba_bg; /* To keep tp_change_reg happy */
+ jnlpool_dummy_seg.file_cntl = &jnlpool_dummy_fc;
+ jnlpool_dummy_fc.file_info = &jnlpool_dummy_vdi;
+ jnlpool_dummy_sa = &jnlpool_dummy_vdi.s_addrs;
+
+ log_nam.addr = GTM_GBLDIR;
+ log_nam.len = SIZEOF(GTM_GBLDIR) - 1;
+
+ if (SS_NORMAL != trans_log_name(&log_nam, &trans_log_nam, trans_buff))
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("gtm$gbldir not defined"));
+ trans_buff[trans_log_nam.len] = '\0';
+ full_len = trans_log_nam.len;
+ if (!get_full_path(&trans_buff, trans_log_nam.len, &trans_buff, &full_len, SIZEOF(trans_buff), &ustatus))
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Failed to get full path for gtm$gbldir"), ustatus);
+ trans_log_nam.len = full_len; /* since on vax, mstr.len is a 'short' */
+ memcpy(jnlpool_dummy_seg.fname, trans_buff, trans_log_nam.len);
+ jnlpool_dummy_seg.fname_len = trans_log_nam.len;
+ jnlpool_dummy_seg.fname[jnlpool_dummy_seg.fname_len] = '\0';
+
+ /* Get Journal Pool Resource Name : name_dsc holds the resource name */
+ set_gdid_from_file((gd_id *)&file_id, trans_buff, trans_log_nam.len);
+ global_name("GT$P", &file_id, res_name); /* P - Stands for Journal Pool */
+ name_dsc.dsc$a_pointer = &res_name[1];
+ name_dsc.dsc$w_length = res_name[0];
+ name_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
+ name_dsc.dsc$b_class = DSC$K_CLASS_S;
+ name_dsc.dsc$a_pointer[name_dsc.dsc$w_length] = '\0';
+
+ /*
+ * We need to do some journal pool locking. The lock
+ * to obtain is the journal pool access control lock
+ * which is also used as the rundown lock. When one has this, no
+ * new attaches to the journal pool are allowed. Also, a
+ * rundown cannot occur. We will get this lock,
+ * then initialize the fields (if not already initialized)
+ * before we release the access control lock.
+ * Refer to repl_sem.h for an enumeration of semaphores in the sem-set
+ */
+
+ assert(NUM_SRC_SEMS == NUM_RECV_SEMS);
+ if (0 != init_sem_set_source(&name_dsc))
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Error with journal pool sem init."), REPL_SEM_ERRNO);
+ if (0 != grab_sem(SOURCE, JNL_POOL_ACCESS_SEM))
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Error with journal pool access semaphore"), REPL_SEM_ERRNO);
+ have_source_access_sem = TRUE;
+ if (GTMSOURCE == pool_user && gtmsource_startup)
+ {
+ /* Get the option semaphore */
+ if (0 != grab_sem(SOURCE, SRC_SERV_OPTIONS_SEM))
+ {
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0,
+ ERR_TEXT, 2, RTS_ERROR_LITERAL("Error with journal pool option semaphore"), REPL_SEM_ERRNO);
+ }
+ have_source_options_sem = TRUE;
+ /* Get the server count semaphore, to make sure that somebody else hasn't created one already */
+ if (0 != grab_sem_immediate(SOURCE, SRC_SERV_COUNT_SEM))
+ {
+ if (REPL_SEM_NOT_GRABBED)
+ {
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JNLPOOLSETUP, 0,
+ ERR_TEXT, 2, RTS_ERROR_LITERAL("Source Server already exists"));
+ } else
+ {
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Error with journal pool server count semaphore"), REPL_SEM_ERRNO);
+ }
+ }
+ have_source_count_sem = TRUE;
+ }
+
+ /* At this point, if (Source-serve AND Startup) all the 3 sems have been grabbed
+ else JNL_POOL_ACCESS_SEM alone has been grabbed
+ */
+
+ /* Store the jnlpool key */
+ memcpy(jnlpool.vms_jnlpool_key.name, name_dsc.dsc$a_pointer, name_dsc.dsc$w_length);
+ jnlpool.vms_jnlpool_key.desc.dsc$a_pointer = jnlpool.vms_jnlpool_key.name;
+ jnlpool.vms_jnlpool_key.desc.dsc$w_length = name_dsc.dsc$w_length;
+ jnlpool.vms_jnlpool_key.desc.dsc$b_dtype = DSC$K_DTYPE_T;
+ jnlpool.vms_jnlpool_key.desc.dsc$b_class = DSC$K_CLASS_S;
+
+ /* Registering with the global section involves grabbing a lock on the jnlpool global section
+ * in the ConcurrentRead mode (CR). This lock will be used when deleting the jnlpool (in signoff_from_gsec())
+ * to make sure that nobody else is attached to the jnlpool global section when detaching from it*/
+
+ if (SS$_NORMAL != (status = register_with_gsec(&jnlpool.vms_jnlpool_key.desc, &jnlpool.shm_lockid)))
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Unable to get lock on jnlpool"), status);
+ gsec_is_registered = TRUE;
+
+ if (GTMSOURCE != pool_user || !gtmsource_startup)
+ { /* Global section should already exist */
+ if (SS$_NORMAL != (status = map_shm(SOURCE, &name_dsc, jnlpool.shm_range)))
+ {
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Journal pool does not exist"), status);
+ }
+ shm_created = FALSE;
+ } else
+ {
+ status = create_and_map_shm(SOURCE, &name_dsc, gtmsource_options.buffsize, jnlpool.shm_range);
+ if (SS$_CREATED == status)
+ shm_created = TRUE;
+ else if (SS$_NORMAL == status)
+ shm_created = FALSE;
+ else
+ {
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_JNLPOOLSETUP, 0,
+ ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to create or map to jnlpool global section"), status);
+ }
+ }
+
+
+ jnlpool_shmid = 1; /* A value > 0, as an indication of the existance of recvpool gsec */
+
+ /* Initialize journal pool pointers to point to appropriate shared memory locations */
+
+ jnlpool.jnlpool_ctl = ROUND_UP((unsigned long)jnlpool.shm_range[0], (2*BITS_PER_UCHAR));
+ jnlpool_dummy_sa->critical = (mutex_struct_ptr_t)((sm_uc_ptr_t)jnlpool.jnlpool_ctl + JNLPOOL_CTL_SIZE); /* secshr_db_clnup
+ * uses this
+ * relationship */
+ jnlpool_mutex_spin_parms = (mutex_spin_parms_ptr_t)((sm_uc_ptr_t)jnlpool_dummy_sa->critical + JNLPOOL_CRIT_SPACE);
+ jnlpool_dummy_sa->nl = (node_local_ptr_t)((sm_uc_ptr_t)jnlpool_mutex_spin_parms + SIZEOF(mutex_spin_parms_struct));
+ if (shm_created)
+ memset(jnlpool_dummy_sa->nl, 0, SIZEOF(node_local)); /* Make jnlpool_dummy_sa->nl->glob_sec_init FALSE */
+ jnlpool_dummy_sa->now_crit = FALSE;
+ jnlpool.gtmsource_local = (gtmsource_local_ptr_t)((sm_uc_ptr_t)jnlpool_dummy_sa->nl + SIZEOF(node_local));
+ jnldata_base = jnlpool.jnldata_base = (sm_uc_ptr_t)jnlpool.jnlpool_ctl + JNLDATA_BASE_OFF;
+ jnlpool_ctl = jnlpool.jnlpool_ctl;
+
+ if (GTMSOURCE == pool_user && gtmsource_startup)
+ {
+ jnlpool.gtmsource_local->gtmsource_pid = 0;
+ *jnlpool_initialized = FALSE;
+ }
+
+ if (!jnlpool_dummy_sa->nl->glob_sec_init) /* Shared memory is created by this process */
+ {
+ if (GTMSOURCE != pool_user || !gtmsource_startup)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(6) ERR_JNLPOOLSETUP, 0,
+ ERR_TEXT, 2, RTS_ERROR_LITERAL("Journal pool has not been initialized"));
+
+ /* Initialize the shared memory fields */
+
+ /*
+ * start_jnl_seqno (and jnl_seqno, read_jnl_seqno) need
+ * region shared mem to be setup.
+ */
+
+ jnlpool_ctl->jnldata_base_off = JNLDATA_BASE_OFF;
+ jnlpool_ctl->jnlpool_size = gtmsource_options.buffsize - jnlpool_ctl->jnldata_base_off;
+ assert((jnlpool_ctl->jnlpool_size & ~JNL_WRT_END_MASK) == 0);
+ assert(!(SIZEOF(replpool_identifier) % BITS_PER_UCHAR));
+ jnlpool_ctl->write = 0;
+ jnlpool_ctl->lastwrite_len = 0;
+ QWASSIGNDW(jnlpool_ctl->early_write_addr, 0);
+ QWASSIGNDW(jnlpool_ctl->write_addr, 0);
+ strcpy(jnlpool_ctl->jnlpool_id.repl_pool_key, name_dsc.dsc$a_pointer);
+ memcpy(jnlpool_ctl->jnlpool_id.gtmgbldir, jnlpool_dummy_seg.fname, jnlpool_dummy_seg.fname_len);
+ jnlpool_ctl->jnlpool_id.gtmgbldir[jnlpool_dummy_seg.fname_len] = '\0';
+ memcpy(jnlpool_ctl->jnlpool_id.label, GDS_RPL_LABEL, GDS_LABEL_SZ); /* why -1 heree ???? */
+ memcpy(jnlpool_ctl->jnlpool_id.now_running, gtm_release_name, gtm_release_name_len + 1);
+ assert(0 == (offsetof(jnlpool_ctl_struct, start_jnl_seqno) % BITS_PER_UCHAR));
+ /* ensure that start_jnl_seqno starts at an 8 byte boundary */
+ assert(0 == offsetof(jnlpool_ctl_struct, jnlpool_id));
+ /* ensure that the pool identifier is at the top of the pool */
+ jnlpool_ctl->jnlpool_id.pool_type = JNLPOOL_SEGMENT;
+ mutex_init(jnlpool_dummy_sa->critical, DEFAULT_NUM_CRIT_ENTRY, FALSE);
+ jnlpool_mutex_spin_parms->mutex_hard_spin_count = MUTEX_HARD_SPIN_COUNT;
+ jnlpool_mutex_spin_parms->mutex_sleep_spin_count = MUTEX_SLEEP_SPIN_COUNT;
+ jnlpool_mutex_spin_parms->mutex_spin_sleep_mask = MUTEX_SPIN_SLEEP_MASK;
+ jnlpool_mutex_spin_parms->mutex_que_entry_space_size = DEFAULT_NUM_CRIT_ENTRY;
+ QWASSIGNDW(jnlpool.gtmsource_local->read_addr, 0);
+ jnlpool.gtmsource_local->read = 0;
+ jnlpool.gtmsource_local->read_state = READ_POOL;
+ jnlpool.gtmsource_local->mode = gtmsource_options.mode;
+ QWASSIGN(jnlpool.gtmsource_local->lastsent_jnl_seqno, seq_num_zero); /* 0 indicates nothing has been sent yet */
+ jnlpool.gtmsource_local->lastsent_time = -1;
+
+ jnlpool.gtmsource_local->statslog = FALSE;
+ jnlpool.gtmsource_local->shutdown = FALSE;
+ jnlpool.gtmsource_local->shutdown_time = -1;
+ jnlpool.gtmsource_local->secondary_port = gtmsource_options.secondary_port;
+ strcpy(jnlpool.gtmsource_local->secondary_host, gtmsource_options.secondary_host);
+ strcpy(jnlpool.gtmsource_local->filter_cmd, gtmsource_options.filter_cmd);
+ strcpy(jnlpool.gtmsource_local->log_file, gtmsource_options.log_file);
+ jnlpool.gtmsource_local->statslog_file[0] = '\0';
+
+ jnlpool_dummy_sa->nl->glob_sec_init = TRUE;
+ *jnlpool_initialized = TRUE;
+ }
+
+ temp_jnlpool_ctl->jnlpool_size = jnlpool_ctl->jnlpool_size;
+
+ /* Release control lockout now that it is initialized.
+ * Source Server will release the control lockout only after
+ * other fields shared with GTM processes are initialized */
+ if (GTMSOURCE != pool_user || !gtmsource_startup)
+ {
+ have_source_access_sem = FALSE;
+ rel_sem(SOURCE, JNL_POOL_ACCESS_SEM);
+ }
+ pool_init = TRUE; /* This is done for properly setting the updata_disable flag by active/passive
+ source server in jnl_file_open */
+ jnlpool_dummy_reg.open = TRUE; /* this is used by t_commit_cleanup/tp_restart/mutex_deadlock_check */
+ jnlpool_dummy_reg.read_only = FALSE; /* maintain csa->read_write simultaneously */
+ jnlpool_dummy_sa->read_write = TRUE; /* maintain reg->read_only simultaneously */
+ REVERT;
+ return;
+}
+
+void jnlpool_detach(void)
+{
+ int4 status;
+
+ if (TRUE == pool_init)
+ {
+ /* Delete expanded virtual address space */
+ if (SS$_NORMAL != (status = detach_shm(jnlpool.shm_range)))
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_REPLWARN, 2,
+ RTS_ERROR_LITERAL("Could not detach from journal pool"), status);
+ if (SS$_NORMAL != (status = signoff_from_gsec(jnlpool.shm_lockid)))
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_REPLERR, 0,
+ ERR_TEXT, 2, RTS_ERROR_LITERAL("Error dequeueing lock on jnlpool global section"), status);
+ jnlpool_ctl = NULL;
+ memset(&jnlpool, 0, SIZEOF(jnlpool));
+ pool_init = FALSE;
+ }
+}
diff --git a/sr_vvms/jnlsp.h b/sr_vvms/jnlsp.h
new file mode 100644
index 0000000..ad2507a
--- /dev/null
+++ b/sr_vvms/jnlsp.h
@@ -0,0 +1,133 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+#ifndef JNLSP_H_INCLUDED
+#define JNLSP_H_INCLUDED
+
+/* Start jnlsp.h - platform-specific journaling definitions. */
+
+#ifndef SS$_NORMAL
+#include <ssdef.h>
+#endif
+
+typedef short fd_type;
+typedef vms_file_info fi_type;
+
+/* in disk blocks but jnl file addresses are kept by byte so limited by uint4 for now */
+#define JNL_ALLOC_MAX 8388607
+#define JNL_BUFFER_DEF 128
+#define NOJNL FD_INVALID_NONPOSIX
+/*
+ * In VMS, time is a 64-bit quantity whose unit is in 100 nanoseconds.
+ * To convert it to a unit of time that has more relevance to the user (the most desirable would be a second)
+ * and not lose many CPU cycles in the process, we extract bits 23 thru 55 (0 is lsb, 63 is msb), a total of
+ * 33 bits. This gives us a unit (which we now refer to as an epoch-second) which is 0.8388608 of a second.
+ * Since we want to store the extracted bits in a uint4 and since bit 55 is 1 until sometime in year 2087,
+ * we ignore bit 55 and assume 1 in that position while maintaining whole (64 bit) time quantities.
+ * Bit 55 toggles approximately every 41700 days (114 years). System time on VMS has crossed this
+ * period once. So, bit 55 is 1 now. Bits 56 thru 63 are 0 now.
+ */
+
+/* we'll zap 9 higher order bits and 23 lower order bits of 64 bit time */
+
+#define JNL_MIDTIME_ZEROBITS 7 /* 23 - SIZEOF(low_time) */
+#define JNL_HITIME_MASK (short)0x007F /* (short)((1 << (JNL_MIDTIME_ZEROBITS)) - 1) */
+#define JNL_HITIME_ADJUST_MASK (short)(JNL_HITIME_MASK + 1)
+#define JNL_MIDTIME_MASK (uint4)0xFFFFFF80 /* (unsigned int)(~JNL_HITIME_MASK) */
+#define JNL_LOWTIME_MASK (unsigned short)0x0000 /* (unsigned short)(0) */
+#define JNL_HITIME_WARN_THRESHOLD (short)0x00FD /* warn 980 days before our algorithm breaks */
+#define JNL_LOTIME_ADJUST_MASK (uint4)(1 << 22) /* instead of filling in 0 lowtime, fill in mean value */
+
+#ifdef INT8_SUPPORTED
+
+typedef gtm_int64_t jnl_proc_time;
+
+#define JNL_SHORTTIME_MASK 0x007FFFFFFF800000ll
+ /* ((JNL_HITIME_MASK << SIZEOF(midtime)) | JNL_MIDTIME_MASK) << SIZEOF(lowtime) */
+#define MID_TIME(W) (uint4)(((W) & JNL_SHORTTIME_MASK) >> 23) /* (masked W) >> (JNL_MIDTIME_ZEROBITS + 16) */
+#define JNL_WHOLE_FROM_SHORT_TIME(W, S) W = (((jnl_proc_time)(S) << 23) \
+ | ((jnl_proc_time)(JNL_HITIME_ADJUST_MASK) << 48))
+#define JNL_FULL_HI_TIME(W) (short)((W) >> 48) /* whole_time >> (SIZEOF(mid_time) + SIZEOF(low_time)) */
+
+#else /* ! INT8_SUPPORTED */
+
+#ifdef __ALPHA /* We know that ALPHA is a 64 bit chip (INT8_SUPPORTED) and so is covered by the if case, but */
+# pragma member_alignment save /* we are keeping the alignment pragma to serve as an indicator for any future platforms */
+# pragma nomember_alignment /* As of today, only VAX is not INT8_SUPPORTED and VAX anyway guarantees nomember_alignment for */
+#endif /* jnl_proc_time structure. Vinaya Feb 28, 2002 */
+
+typedef struct
+{
+ unsigned short low_time;
+ uint4 mid_time;
+ short hi_time;
+} jnl_proc_time;
+
+#ifdef __ALPHA
+# pragma member_alignment restore
+#endif
+
+#define MID_TIME(W) (((uint4)((W).hi_time & JNL_HITIME_MASK) << (32 - JNL_MIDTIME_ZEROBITS)) | \
+ ((uint4)((W).mid_time & JNL_MIDTIME_MASK) >> JNL_MIDTIME_ZEROBITS) | \
+ ((uint4)((W).low_time & JNL_LOWTIME_MASK))) /* to make the definition complete; compiler is
+ * hopefully smart enough that this sub-expression
+ * is not evaluated */
+#define JNL_WHOLE_FROM_SHORT_TIME(W, S) \
+{ \
+ (W).hi_time = (short)((S) >> (32 - JNL_MIDTIME_ZEROBITS)) | JNL_HITIME_ADJUST_MASK; \
+ (W).mid_time = (uint4)((S) << JNL_MIDTIME_ZEROBITS); \
+ (W).low_time = (unsigned short)((S) & JNL_LOWTIME_MASK); \
+}
+#define JNL_FULL_HI_TIME(W) ((W).hi_time)
+
+#endif /* INT8_SUPPORTED */
+
+#define JNL_SHORT_TIME(S) \
+{ \
+ jnl_proc_time quad_time; \
+ int4 status; \
+ \
+ status = sys$gettim(&quad_time); \
+ assert(status & 1); \
+ S = MID_TIME(quad_time); \
+}
+
+#define JNL_WHOLE_TIME(W) \
+{ \
+ int4 status; \
+ \
+ status = sys$gettim(&(W)); \
+ assert(status & 1); \
+}
+
+/* Note that the user interface for epoch-interval is in seconds both in terms of input and output. Only the internal
+ * representation is different.
+ */
+#define SECONDS_PER_EPOCH_SECOND 0.8388608 /* 2**64BIT_TIME_23_LSB_IGNORED * 100 ns = (2**23) * (100 * 10**-9) */
+/* the following macros need #include <math.h> for the prototypes as otherwise it will give arbitrary results */
+#define SECOND2EPOCH_SECOND(s) (uint4)floor((double)(s) / SECONDS_PER_EPOCH_SECOND) /* int approximation will always be less than
+ * exact, so we might write epochs more
+ * frequently than user specified. */
+#define EPOCH_SECOND2SECOND(e) (uint4)ceil((double)(e) * SECONDS_PER_EPOCH_SECOND) /* for values from 1 thru 32K-1, we've noticed
+ * that conversion from seconds to epoch seconds
+ * and back does not lose precision
+ */
+#define JNL_EXT_DEF ".MJL"
+#define DEF_DB_EXT_NAME "DAT"
+#define DEF_JNL_EXT_NAME JNL_EXT_DEF
+
+#define EXTTIMEVMS(T) EXTTIME(T)
+#define EXTINTVMS(I) EXTINT(I)
+#define EXTTXTVMS(T,L) EXTTXT(T,L)
+
+uint4 jnl_file_open(gd_region *reg, bool init, void oper_ast());
+void jnl_mm_timer_write(gd_region *reg);
+
+#endif /* JNLSP_H_INCLUDED */
diff --git a/sr_vvms/jobchild_init.c b/sr_vvms/jobchild_init.c
new file mode 100644
index 0000000..afb1c1a
--- /dev/null
+++ b/sr_vvms/jobchild_init.c
@@ -0,0 +1,298 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include "error.h"
+#include <ssdef.h>
+#include <descrip.h>
+#include <iodef.h>
+#include <lnmdef.h>
+#include <dvidef.h>
+#include <jpidef.h>
+#include <stsdef.h>
+#include "vmsdtype.h"
+#include <rtnhdr.h>
+#include "stack_frame.h"
+#include "stringpool.h"
+#include "job.h"
+#include "efn.h"
+#include "op.h"
+#include "zbreak.h"
+#include "jobchild_init.h"
+#include "cmd_qlf.h"
+#include "lv_val.h" /* needed for "callg.h" */
+#include "callg.h"
+
+#define FATAL(error) (error & STS$M_COND_ID | STS$K_SEVERE)
+
+GBLDEF unsigned short pchan;
+
+GBLREF spdesc stringpool;
+GBLREF stack_frame *frame_pointer;
+
+error_def(ERR_ACK);
+error_def(ERR_ENQ);
+error_def(ERR_FMLLSTMISSING);
+error_def(ERR_JOBFAIL);
+error_def(ERR_JOBLABOFF);
+error_def(ERR_STRINGOFLOW);
+
+void jobchild_init(unsigned char *base_addr_ptr)
+{
+ unsigned status;
+ mbx_iosb iosb;
+ struct
+ {
+ item_list_3 item[1];
+ int4 terminator;
+ } item_list;
+ short dummy;
+ $DESCRIPTOR (tabnam, "LNM$PROCESS");
+ $DESCRIPTOR (lognam, "GTM$JOB$");
+ mval ppid;
+ char ppidstr[MAX_PIDSTR_LEN];
+ short ppidstrlen;
+ short cchan;
+ int4 punit, cunit;
+ char pmbxnam[32];
+ $DESCRIPTOR (pmbx, &pmbxnam[0]);
+
+/* Parameters ... */
+ mstr input, output, error, gbldir;
+
+/* Messages */
+ int4 cmaxmsg;
+ mstr stsdsc;
+ pmsg_type stsmsg;
+ mstr isddsc;
+ isd_type isd;
+ mstr argstr;
+ int4 argcnt, i;
+ mval *arglst;
+ mval rt;
+
+ struct {
+ int4 callargs;
+ int4 truth;
+ int4 retval;
+ int4 mask;
+ int4 argcnt;
+ mval *argval[1];
+ } *gcall_arg;
+/* Transfer data */
+ rhdtyp *rt_hdr;
+ mstr label, rtn;
+ int4 *lp;
+ DCL_THREADGBL_ACCESS;
+
+ LITDEF $DESCRIPTOR (sys$input, "SYS$INPUT");
+ LITDEF $DESCRIPTOR (sys$output, "SYS$OUTPUT");
+ LITDEF $DESCRIPTOR (sys$error, "SYS$ERROR");
+ LITDEF $DESCRIPTOR (gtm$gbldir, "GTM$GBLDIR");
+
+ SETUP_THREADGBL_ACCESS;
+ item_list.item[0].buffer_length = MAX_PIDSTR_LEN;
+ item_list.item[0].item_code = LNM$_STRING;
+ item_list.item[0].buffer_address = &ppidstr[0];
+ item_list.item[0].return_length_address = &ppidstrlen;
+ item_list.terminator = 0;
+ status = sys$trnlnm(0, &tabnam, &lognam, 0, &item_list);
+ if (SS$_NOLOGNAM == status)
+ {
+ new_stack_frame(base_addr_ptr, base_addr_ptr + SIZEOF(rhdtyp), base_addr_ptr + SIZEOF(rhdtyp));
+ return;
+ }
+ if (SS$_NORMAL != status)
+ rts_error(VARLSTCNT(1) FATAL(status));
+ if (MAX_PIDSTR_LEN < ppidstrlen)
+ rts_error(VARLSTCNT(1) FATAL(ERR_JOBFAIL));
+ ppid.mvtype = MV_STR;
+ ppid.str.len = ppidstrlen;
+ ppid.str.addr = &ppidstr[0];
+ s2n(&ppid);
+ status = sys$assign(&sys$input, &cchan, 0, 0);
+ if (!(status & 1))
+ rts_error(VARLSTCNT(1) FATAL(status));
+ item_list.item[0].buffer_length = SIZEOF(cmaxmsg);
+ item_list.item[0].item_code = DVI$_DEVBUFSIZ;
+ item_list.item[0].buffer_address = &cmaxmsg;
+ item_list.item[0].return_length_address = &dummy;
+ item_list.terminator = 0;
+ status = sys$getdvi(efn_immed_wait, cchan, 0, &item_list, &iosb, 0, 0, 0);
+ if (SS$_NORMAL != status)
+ rts_error(VARLSTCNT(1) FATAL(status));
+ sys$synch(efn_immed_wait, &iosb);
+ if (SS$_NORMAL != iosb.status)
+ rts_error(VARLSTCNT(1) FATAL(iosb.status));
+ item_list.item[0].buffer_length = SIZEOF(punit);
+ item_list.item[0].item_code = JPI$_TMBU;
+ item_list.item[0].buffer_address = &punit;
+ item_list.item[0].return_length_address = &dummy;
+ item_list.terminator = 0;
+ status = sys$getjpi(efn_immed_wait, 0, 0, &item_list, &iosb, 0, 0);
+ if (SS$_NORMAL != status)
+ rts_error(VARLSTCNT(1) FATAL(status));
+ sys$synch(efn_immed_wait, &iosb);
+ if (SS$_NORMAL != iosb.status)
+ rts_error(VARLSTCNT(1) FATAL(iosb.status));
+ pmbx.dsc$w_length = ojunit_to_mba(&pmbxnam[0], punit);
+ status = sys$assign(&pmbx, &pchan, 0, 0);
+ if (!(status & 1))
+ rts_error(VARLSTCNT(1) FATAL(status));
+ lib$establish(ojch); /* now we have the mailbox, use the condition handler to send status and exit */
+ stsmsg.unused = 0;
+ stsmsg.finalsts = ERR_ENQ;
+ stsdsc.addr = &stsmsg;
+ stsdsc.len = SIZEOF(stsmsg);
+ ojmbxio(IO$_WRITEVBLK, pchan, &stsdsc, &iosb, TRUE);
+ if (!IS_STP_SPACE_AVAILABLE(cmaxmsg))
+ rts_error(VARLSTCNT(1) ERR_STRINGOFLOW);
+ input.len = cmaxmsg;
+ input.addr = stringpool.free;
+ ojmbxio(IO$_READVBLK, cchan, &input, &iosb, FALSE);
+ input.len = iosb.byte_count;
+ stringpool.free += input.len;
+ assert(iosb.pid == (int4)MV_FORCE_INTD(&ppid));
+ if (!IS_STP_SPACE_AVAILABLE(cmaxmsg))
+ rts_error(VARLSTCNT(1) ERR_STRINGOFLOW);
+ output.len = cmaxmsg;
+ output.addr = stringpool.free;
+ ojmbxio(IO$_READVBLK, cchan, &output, &iosb, FALSE);
+ output.len = iosb.byte_count;
+ stringpool.free += output.len;
+ assert(iosb.pid == (int4)MV_FORCE_INTD(&ppid));
+ if (!IS_STP_SPACE_AVAILABLE(cmaxmsg))
+ rts_error(VARLSTCNT(1) ERR_STRINGOFLOW);
+ error.len = cmaxmsg;
+ error.addr = stringpool.free;
+ ojmbxio(IO$_READVBLK, cchan, &error, &iosb, FALSE);
+ error.len = iosb.byte_count;
+ stringpool.free += error.len;
+ assert(iosb.pid == (int4)MV_FORCE_INTD(&ppid));
+ if (!IS_STP_SPACE_AVAILABLE(cmaxmsg))
+ rts_error(VARLSTCNT(1) ERR_STRINGOFLOW);
+ gbldir.len = cmaxmsg;
+ gbldir.addr = stringpool.free;
+ ojmbxio(IO$_READVBLK, cchan, &gbldir, &iosb, FALSE);
+ gbldir.len = iosb.byte_count;
+ stringpool.free += gbldir.len;
+ assert(iosb.pid == (int4)MV_FORCE_INTD(&ppid));
+ if (!IS_STP_SPACE_AVAILABLE(cmaxmsg))
+ rts_error(VARLSTCNT(1) ERR_STRINGOFLOW);
+ isddsc.len = SIZEOF(isd);
+ isddsc.addr = &isd;
+ ojmbxio(IO$_READVBLK, cchan, &isddsc, &iosb, FALSE);
+ assert(SIZEOF(isd) == iosb.byte_count);
+ assert(iosb.pid == (int4)MV_FORCE_INTD(&ppid));
+ if (!IS_STP_SPACE_AVAILABLE(cmaxmsg))
+ rts_error(VARLSTCNT(1) ERR_STRINGOFLOW);
+ argstr.len = SIZEOF(argcnt);
+ argstr.addr = &argcnt;
+ ojmbxio(IO$_READVBLK, cchan, &argstr, &iosb, FALSE);
+ assert(SIZEOF(argcnt) == iosb.byte_count);
+ assert(iosb.pid == (int4)MV_FORCE_INTD(&ppid));
+ if (argcnt)
+ { /* process incoming parameters list */
+ arglst = malloc(argcnt * SIZEOF(mval));
+ gcall_arg = malloc(SIZEOF(*gcall_arg) + (argcnt - 1) * SIZEOF(mval *));
+ gcall_arg->callargs = argcnt + 4;
+ gcall_arg->truth = 1;
+ gcall_arg->retval = 0;
+ gcall_arg->mask = 0;
+ gcall_arg->argcnt = argcnt;
+ for (i = 0; i < argcnt; i++)
+ {
+ if (!IS_STP_SPACE_AVAILABLE(cmaxmsg))
+ rts_error(VARLSTCNT(1) ERR_STRINGOFLOW);
+ argstr.len = cmaxmsg;
+ argstr.addr = stringpool.free;
+ ojmbxio(IO$_READVBLK, cchan, &argstr, &iosb, FALSE);
+ assert(iosb.pid == (int4)MV_FORCE_INTD(&ppid));
+ argstr.len = iosb.byte_count;
+ stringpool.free += argstr.len;
+ arglst[i].mvtype = MV_STR;
+ arglst[i].str = argstr;
+ gcall_arg->argval[i] = &arglst[i];
+ }
+ }
+ status = sys$dassgn(cchan);
+ if (SS$_NORMAL != status)
+ rts_error(VARLSTCNT(1) status);
+ stsmsg.unused = 0;
+ stsdsc.addr = &stsmsg;
+ stsdsc.len = SIZEOF(stsmsg);
+ rtn.addr = &isd.routine.c[0];
+ rtn.len = mid_len(&isd.routine);
+ if (0 == (rt_hdr = find_rtn_hdr(&rtn)))
+ {
+ rt.mvtype = MV_STR;
+ rt.str = rtn;
+ op_zlink(&rt, 0);
+ if (0 == (rt_hdr = find_rtn_hdr(&rtn)))
+ GTMASSERT;
+ }
+ base_addr_ptr = (char *)rt_hdr;
+ label.addr = &isd.label.c[0];
+ label.len = mid_len(&isd.label);
+ lp = NULL;
+ if ((rt_hdr->compiler_qlf & CQ_LINE_ENTRY) || (0 == isd.offset))
+ /* label offset with routine compiled with NOLINE_ENTRY should cause error */
+ lp = find_line_addr(rt_hdr, &label, isd.offset, NULL);
+ if (!lp)
+ rts_error(VARLSTCNT(1) ERR_JOBLABOFF);
+ if (argcnt && !(TREF(lab_proxy)).has_parms) /* Label has no formallist, but is passed an actuallist. */
+ rts_error(VARLSTCNT(1) ERR_FMLLSTMISSING);
+ item_list.item[0].item_code = LNM$_STRING;
+ item_list.item[0].return_length_address = &dummy;
+ item_list.terminator = 0;
+ item_list.item[0].buffer_length = input.len;
+ item_list.item[0].buffer_address = input.addr;
+ status = sys$crelnm(0, &tabnam, &sys$input, 0, &item_list);
+ if (!(status & 1))
+ rts_error(VARLSTCNT(1) status);
+ item_list.item[0].buffer_length = output.len;
+ item_list.item[0].buffer_address = output.addr;
+ status = sys$crelnm(0, &tabnam, &sys$output, 0, &item_list);
+ if (!(status & 1))
+ rts_error(VARLSTCNT(1) status);
+ item_list.item[0].buffer_length = error.len;
+ item_list.item[0].buffer_address = error.addr;
+ status = sys$crelnm(0, &tabnam, &sys$error, 0, &item_list);
+ if (!(status & 1))
+ rts_error(VARLSTCNT(1) status);
+ if (0 != gbldir.len)
+ {
+ item_list.item[0].buffer_length = gbldir.len;
+ item_list.item[0].buffer_address = gbldir.addr;
+ status = sys$crelnm(0, &tabnam, >m$gbldir, 0, &item_list);
+ if (!(status & 1))
+ rts_error(VARLSTCNT(1) status);
+ }
+ stsmsg.finalsts = ERR_ACK;
+ ojmbxio(IO$_WRITEVBLK, pchan, &stsdsc, &iosb, TRUE);
+ status = sys$dassgn(pchan);
+ if (SS$_NORMAL != status)
+ rts_error(VARLSTCNT(1) status);
+ if ((0 != isd.schedule.lo) || (0 != isd.schedule.hi))
+ {
+ status = sys$schdwk(0, 0, &isd.schedule, 0);
+ if (SS$_NORMAL != status)
+ rts_error(VARLSTCNT(1) status);
+ sys$hiber();
+ }
+ new_stack_frame(base_addr_ptr, LINE_NUMBER_ADDR(rt_hdr, lp), LINE_NUMBER_ADDR(rt_hdr, lp));
+ if (argcnt)
+ callg(push_parm, (gparam_list *)gcall_arg);
+ lib$revert();
+}
diff --git a/sr_vvms/jobchild_init.h b/sr_vvms/jobchild_init.h
new file mode 100644
index 0000000..f7dfbb2
--- /dev/null
+++ b/sr_vvms/jobchild_init.h
@@ -0,0 +1,17 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef __JOBCHILD_INIT_H__
+#define __JOBCHILD_INIT_H__
+
+void jobchild_init(unsigned char *base_addr_ptr);
+
+#endif
diff --git a/sr_vvms/jobsp.h b/sr_vvms/jobsp.h
new file mode 100644
index 0000000..c699706
--- /dev/null
+++ b/sr_vvms/jobsp.h
@@ -0,0 +1,86 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef JOBSP_H_INCLUDED
+#define JOBSP_H_INCLUDED
+
+#define MAX_JOBPAR_LEN 255
+#define MAX_FILSPC_LEN 255
+#define MAX_PIDSTR_LEN 10
+#define MAX_MBXNAM_LEN 16
+#define MAX_PRCNAM_LEN 15
+
+#define JP_NO_BASPRI -1
+
+typedef struct
+ {
+ int4 lo;
+ int4 hi;
+ } quadword; /* date_time; */
+
+typedef struct
+ {
+ unsigned unused;
+ unsigned finalsts;
+ } pmsg_type;
+
+typedef struct
+ {
+ mident_fixed label;
+ int4 offset;
+ mident_fixed routine;
+ quadword schedule;
+ } isd_type;
+
+typedef struct
+ {
+ unsigned short status;
+ unsigned short byte_count;
+ uint4 pid;
+ } mbx_iosb;
+
+typedef enum
+{
+ jpdt_nul,
+ jpdt_num,
+ jpdt_str
+} jp_datatype;
+
+#define JPDEF(a,b) a
+typedef enum
+{
+#include "jobparams.h"
+} jp_type;
+
+#include <descrip.h>
+
+void ojmbxio(int4 func, short chan, mstr *msg, short *iosb, bool now);
+unsigned short ojunit_to_mba(char *targ, uint4 n);
+uint4 ojmba_to_unit(char *src);
+void ojerrcleanup(void);
+void ojastread (int expected);
+bool ojchkbytcnt(int4 cmaxmsg);
+void ojcleanup(void);
+bool ojcrembxs(uint4 *punit, struct dsc$descriptor_s *cmbx, int4 cmaxmsg, bool timed);
+void ojparams(unsigned char *p, mval *routine, bool *defprcnam, int4 *cmaxmsg, mstr *image,
+ mstr *input, mstr *output, mstr *error, struct dsc$descriptor_s *prcnam, int4 *baspri,
+ int4 *stsflg, mstr *gbldir, mstr *startup, struct dsc$descriptor_s *logfile, mstr *deffs,
+ quadword *schedule);
+void ojsetattn(int msg);
+void ojtmrinit(int4 *timeout);
+void ojdefbaspri(int4 *baspri);
+void ojdefdeffs(mstr *deffs);
+void ojdefimage(mstr *image);
+void ojdefprcnam(struct dsc$descriptor_s *prcnam);
+void ojtmrrtn(void);
+unsigned short ojhex_to_str(uint4 s, char *t);
+
+#endif /* JOBSP_H_INCLUDED */
diff --git a/sr_vvms/jpv_v10to12.c b/sr_vvms/jpv_v10to12.c
new file mode 100644
index 0000000..9007952
--- /dev/null
+++ b/sr_vvms/jpv_v10to12.c
@@ -0,0 +1,39 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "jnl.h"
+#include "jpv_v10to12.h"
+
+void jpv_v10to12(char *old_jpv_ptr, jnl_process_vector *new_jpv)
+{
+ jnl_process_vector temp_jpv;
+ v10_jnl_process_vector *old_jpv;
+
+ memset(&temp_jpv, 0, SIZEOF(jnl_process_vector));
+ old_jpv = (v10_jnl_process_vector *) old_jpv_ptr;
+ temp_jpv.jpv_pid = old_jpv->jpv_pid;
+ temp_jpv.jpv_time = old_jpv->jpv_time;
+ temp_jpv.jpv_login_time = old_jpv->jpv_login_time;
+ temp_jpv.jpv_image_count = old_jpv->jpv_image_count;
+ temp_jpv.jpv_mode = old_jpv->jpv_mode;
+ memcpy(&temp_jpv.jpv_node, old_jpv->jpv_node, V10_JPV_LEN_NODE);
+ memcpy(&temp_jpv.jpv_user, old_jpv->jpv_user, V10_JPV_LEN_USER);
+ memcpy(&temp_jpv.jpv_prcnam, old_jpv->jpv_prcnam, V10_JPV_LEN_PRCNAM);
+ memcpy(&temp_jpv.jpv_terminal, old_jpv->jpv_terminal, V10_JPV_LEN_TERMINAL);
+ memcpy(new_jpv, &temp_jpv, SIZEOF(jnl_process_vector));
+}
diff --git a/sr_vvms/jpv_v10to12.h b/sr_vvms/jpv_v10to12.h
new file mode 100644
index 0000000..051b5ce
--- /dev/null
+++ b/sr_vvms/jpv_v10to12.h
@@ -0,0 +1,37 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef JPV_V10TOV12
+#define JPV_V10TOV12
+
+#define V10_JPV_LEN_NODE 15
+#define V10_JPV_LEN_USER 12
+#define V10_JPV_LEN_PRCNAM 15
+#define V10_JPV_LEN_TERMINAL 8
+
+typedef struct v10_jnl_process_vector_struct
+{
+ uint4 jpv_pid; /* Process id */
+ jnl_proc_time jpv_time, /* Journal record timestamp; also used for process termination time */
+ jpv_login_time; /* Process login time; also used for process initialization time */
+ int4 jpv_image_count; /* Image activations [VMS only] */
+ unsigned char jpv_mode; /* a la JPI$_MODE [VMS only] */
+ char jpv_node[V10_JPV_LEN_NODE], /* Node name */
+ jpv_user[V10_JPV_LEN_USER], /* User name */
+ jpv_prcnam[V10_JPV_LEN_PRCNAM], /* Process name */
+ jpv_terminal[V10_JPV_LEN_TERMINAL]; /* Login terminal */
+ /* SIZEOF(jnl_process_vector) must be a multiple of SIZEOF(int4) */
+ char jpv_padding;
+} v10_jnl_process_vector;
+
+void jpv_v10to12(char *old_jpv_ptr, jnl_process_vector *new_jpv);
+
+#endif /* JPV_V10TOV12 */
diff --git a/sr_vvms/kitprepare.com b/sr_vvms/kitprepare.com
new file mode 100644
index 0000000..932e67b
--- /dev/null
+++ b/sr_vvms/kitprepare.com
@@ -0,0 +1,73 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2013 Fidelity Information Services, Inc !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! The purpose of this script is to generate save the full directory
+$! information to dir_full.txt and record the checksum for each file.
+$
+$! p1 - version to get kits for (e.g. V50000D)
+$
+$ if (p1 .eqs. "")
+$ then
+$ write sys$output ""
+$ write sys$output "With yeti or bgfoot as the build system of record"
+$ write sys$output "Syntax : @gtm$tools:kitprepare <version>"
+$ write sys$output " e.g. @gtm$tools:kitprepare V60002"
+$ write sys$output ""
+$ exit
+$ endif
+$
+$! Check if the kits we expect to see are present in GTM$VRT:[DIST]
+$ gtmverno = p1
+$ distdir = "gtm$root:[" + gtmverno + ".dist]"
+$
+$ set def gtm$root:['gtmverno]
+$ set def [.dist]
+$ purge/log *.*
+$ if (f$search("dir_full.txt") .nes. "")
+$ then
+$ delete/log dir_full.txt;
+$ endif
+$ dir/full /out=dir_full.txt
+$
+$ open/append dirlist dir_full.txt
+$
+$! the following list has to be maintained in sync with "distrib_kits_vms" defined in $cms_tools/server_list
+$ kitlist = "GTCDxxxxx.A,GTCMxxxxx.A,GTDCxxxxx.A,GTMxxxxx.A,GTMxxxxx.B,GTMxxxxx.C"
+$!
+$ numkits = f$length(kitlist)
+$ partial_list = "''kitlist'"
+$ verlength = f$length(gtmverno)
+$ kitver = f$extract(1, 5, gtmverno)
+$kitcheckloop:
+$ index = f$locate(",",partial_list)
+$ curkit = f$extract(0, index, partial_list)
+$ partial_list = f$extract(index + 1, numkits, partial_list)
+$ if (curkit .eqs. "") then goto endkitcheckloop
+$ length = f$length(curkit)
+$ xxindex = f$locate("xxxxx",curkit)
+$ kitprefix = f$extract(0, xxindex, curkit)
+$ kitsuffix = f$extract(xxindex+5, length, curkit)
+$ kitfile = distdir + kitprefix + kitver + kitsuffix
+$ if (f$search(kitfile) .eqs. "")
+$ then
+$ msg = "''kitfile' does not exist. First run @gtm$com:kitstart all ''gtmverno' user:[library.''gtmverno'.dist]"
+$ write sys$output "KITPREP-E-NOKITS : ''msg'"
+$ write dirlist "KITPREP-E-NOKITS : ''msg'"
+$ exit 0 ! to signal error
+$ endif
+$ checksum 'kitfile
+$ filename = f$parse(kitfile,,,"NAME") + f$parse(kitfile,,,"TYPE")
+$ write sys$output "KITPREP-I-CHECKSUM : ''filename' : checksum = [''checksum$checksum'] "
+$ write dirlist "KITPREP-I-CHECKSUM : ''filename' : checksum = [''checksum$checksum'] "
+$ goto kitcheckloop
+$endkitcheckloop:
+$
+$ write sys$output "KITPREP-S-SUCCESS : KITPREP completed successfully"
+$ write dirlist "KITPREP-S-SUCCESS : KITPREP completed successfully"
diff --git a/sr_vvms/kitstart.com b/sr_vvms/kitstart.com
new file mode 100644
index 0000000..94fdebc
--- /dev/null
+++ b/sr_vvms/kitstart.com
@@ -0,0 +1,153 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2013 Fidelity Information Services Inc !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$! kitstart.com p1=product p2=version, p3=destination
+$!
+$ alpha = (f$getsyi("arch_name") .eqs. "Alpha")
+$ if alpha
+$ then
+$ prodlist = "GT.M\GT.CM\GT.CX\GT.DDP\GT.DC\ALL\"
+$ else
+$ prodlist = "GT.M\GT.CM\GT.CX\GTM.FI\GT.DDP\ALL\"
+$ endif
+$ pllen = f$length(prodlist)
+$ gtm_init_tape :== y
+$ say = "write sys$output"
+$ ask = "inquire"
+$ say "GT.M Distribution Kit Build"
+$ on error then goto badkit
+$ on severe then goto badkit
+$ on control_y then goto badkit
+$ prd = p1
+$ p1 = ""
+$ vno = p2
+$ p2 = ""
+$ dst = p3
+$ p3 = ""
+$ gosub getprod
+$ gosub getver
+$ gosub getdst
+$ ver 'vno' p
+$ savpriv = f$setprv("bypas,cmkrnl,log_io,sysnam,volpro,oper")
+$ if f$getdvi(outdev,"devclass") .eq. 2
+$ then
+$ init/over=(accessibility,expiration,owner)/density=1600 'outdev' gtc
+$ endif
+$! Fix the Version #s in "gtm$vrt:[t%%]*_spkitbld.dat"
+$ @gtm$tools:spkitupdate.com 'vno'
+$!
+$ if (f$locate("GT.M",prd) + f$locate("ALL",prd)) .ne. prdlen2
+$ then
+$ @sys$update:spkitbld "" 'dst' "" gtm$vrt:[tls]gtm_spkitbld.dat
+$ if $severity .ne. 1 then goto badkit
+$ prot_obj_files="(S:RE,O:RWED,G:RE,W:RE)"
+$ f="GTM$VRT:[PCT]*.obj"
+$ write sys$output " Resetting protection on all obj files to ''prot_obj_files' ..."
+$ set security/class=file/protection='prot_obj_files' 'f'
+$ gtm_init_tape :== n
+$ endif
+$ if (f$locate("GT.CM",prd) + f$locate("ALL",prd)) .ne. prdlen2
+$ then
+$ @sys$update:spkitbld "" 'dst' "" gtm$vrt:[tcm]gtcm_spkitbld.dat
+$ if $severity .ne. 1 then goto badkit
+$ gtm_init_tape :== n
+$ endif
+$!1999/1/3 smw CX not supported if (f$locate("GT.CX",prd) + f$locate("ALL",prd)) .ne. prdlen2
+$ if (f$locate("GT.CX",prd)) .ne. f$length(prd)
+$ then
+$ @sys$update:spkitbld "" 'dst' "" gtm$vrt:[tcx]gtcx_spkitbld.dat
+$ if $severity .ne. 1 then goto badkit
+$ gtm_init_tape :== n
+$ endif
+$ if .NOT. alpha .AND. (f$locate("GTM.FI",prd) + f$locate("ALL",prd)) .ne. prdlen2
+$ then
+$ @sys$update:spkitbld "" 'dst' "" gtm$vrt:[tfi]gtmfi_spkitbld.dat
+$ if $severity .ne. 1 then goto badkit
+$ gtm_init_tape :== n
+$ endif
+$ if (f$locate("GT.DDP",prd) + f$locate("ALL",prd)) .ne. prdlen2
+$ then
+$ @sys$update:spkitbld "" 'dst' "" gtm$vrt:[tdp]ddp_spkitbld.dat
+$ if $severity .ne. 1 then goto badkit
+$ gtm_init_tape :== n
+$ endif
+$ if (f$locate("GT.DC",prd) + f$locate("ALL",prd)) .ne. prdlen2
+$ then
+$ @sys$update:spkitbld "" 'dst' "" gtm$vrt:[tdc]gtmdc_spkitbld.dat
+$ if $severity .ne. 1 then goto badkit
+$ gtm_init_tape :== n
+$ endif
+$ if f$getdvi(outdev,"DEVCLASS") .eq. 2
+$ then
+$ if .not. f$getdvi(outdev,"MNT") then mount/foreign/noassist 'outdev'
+$ dismount/unload 'outdev'
+$ endif
+$ @gtm$tools:kitprepare.com 'vno'
+$goodbye:
+$ savpriv = f$setprv(savpriv)
+$ exit
+$!
+$badkit:
+$type sys$input:
+
+ +---------------------+
+ | |
+ | THIS IS A BAD KIT |
+ | |
+ +---------------------+
+
+$ goto goodbye
+$!
+$getprod:
+$ prdlen2 = f$length(prd) * 2
+$ if prdlen2 .eq. 0
+$ then
+$ ask prd "Product"
+$ if f$extract(0,1,prd) .eqs. "Q" then exit
+$ goto getprod
+$ endif
+$ n = 0
+$prodloop:
+$ t1 = f$element(n,",",prd)
+$ if t1 .eqs. "," then return
+$ t1 = f$locate(t1,prodlist)
+$ if t1 .eq. pllen
+$ then
+$ say "Product not available"
+$ prd = ""
+$ goto getprod
+$ endif
+$ n = n + 1
+$ goto prodloop
+$!
+$getver:
+$ if f$search("gtm$root:["+vno+".pro]gtmshr.exe") .nes. "" then return
+$ if vno .nes. "" then say "Version Number not available"
+$ ask vno "Version Number"
+$ if f$extract(0,1,vno) .eqs. "Q" then exit
+$ goto getver
+$!
+$getdst:
+$ on warning then goto nodst
+$ outdev = f$parse(dst,,,"device")
+$ dst = f$parse(dst,"[F-O-O]",,"directory")
+$ if dst .eqs. "[F-O-O]"
+$ then
+$ dst = outdev
+$ else
+$ dst = outdev + dst
+$ endif
+$ on warning then continue
+$ return
+$nodst:
+$ ask dst "Destination"
+$ if f$extract(0,1,dst) .eqs. "Q" then exit
+$ goto getdst
diff --git a/sr_vvms/la.hlp b/sr_vvms/la.hlp
new file mode 100644
index 0000000..9800d73
--- /dev/null
+++ b/sr_vvms/la.hlp
@@ -0,0 +1,170 @@
+1 OVERVIEW
+ O[VERVIEW]
+ The License Administration (LA) issues the Product
+ Authorization Keys (PAKs) that are delivered to License
+ Management systems at customer sites. The LA is invoked by
+ typing:
+ LA command [/qualifier=value... [parameter...]
+ The LA is terminated by the command EXIT.
+1 INITIALIZE
+ I[NITIALIZE] file name
+ The INITIALIZE command creates a new, empty License
+ Administration data base file. The command creates a new
+ version of the file when the file already exists. The file
+ name has to be assigned the logical name GTM$LADB.
+1 CREATE
+ C[REATE]
+ The CREATE command enters new, valid PAKs in the LA data base.
+ The command does not accept any qualifiers, all the input data
+ is prompted for. The invalid entry fields may be edited until
+ the field data is valid.
+1 PRINT
+ P[RINT]
+ The PRINT command creates the files PRODAUTHKEY.LIS in the
+ default directory. The files contain the PAK data in the
+ format for mailing PAKs to customers. There is one version of
+ the file above for each PAK matching the restrictions given by
+ the PRINT command qualifiers.
+ The syntax for the PRINT command is:
+ P[RINT] [/qualifier=value]
+2 /PRODUCT
+ /P[RODUCT]=pattern
+ Selects all PAKs with the product name matching the pattern.
+2 /VERSION
+ /VE[RSION]=pattern
+ Selects all PAKs with the product version name matching the
+ pattern.
+2 /VALUE
+ /V[ALUE]=dec.num
+ Selects all PAKs with the license value of "dec.num".
+2 /LICENSE_ID
+ /L[ICENSE_ID]=dec.num
+ Selects all PAKs with the license ID of "dec.num".
+2 /SYSTEM_ID
+ /S[YSTEM_ID]=hex.num
+ Selects all PAKs with the system ID "hex.num". For PAKs with
+ more than one system ID only the first one in the list is
+ matched.
+2 /NUM_SYS
+ /N[UM_SYS]=dec.num
+ Selects all PAKs with "dec.num" system IDs.
+2 /AVAILABLE
+ /A[VAILABLE]=date
+ Selects all PAKs available exactly at "date".
+2 /EXPIRES
+ /EX[PIRES]=date
+ Selects all PAKs expiring exactly at "date".
+2 /CREATED
+ /CR[EATED]=date
+ Selects all PAKs created exactly at "date".
+2 /ENCRYPTION
+ /EN[CRYPTION]=dec.num
+ Selects all PAKs with the checksum computed by the
+ "dec.num"-th encryption function.
+2 /CHECKSUM
+ /CH[ECKSUM]=pattern
+ Selects all PAKs with the checksum matching the pattern. The
+ pattern is a sequence of characters, without dashes between
+ groups of four characters and without the leading digit.
+2 /OPERATOR
+ /O[PERATOR]=pattern
+ Selects all PAKs created by the operator matching the pattern.
+1 LIST
+ L[IST]
+ The LIST command lists all PAKs matching the restrictions
+ given by the qualifiers to the terminal.
+ The syntax for the LIST command is:
+ L[IST] [/qualifier=value]
+2 /PRODUCT
+ /P[RODUCT]=pattern
+ Selects all PAKs with the product name matching the pattern.
+2 /VERSION
+ /VE[RSION]=pattern
+ Selects all PAKs with the product version name matching the
+ pattern.
+2 /VALUE
+ /V[ALUE]=dec.num
+ Selects all PAKs with the license value of "dec.num".
+2 /LICENSE_ID
+ /L[ICENSE_ID]=dec.num
+ Selects all PAKs with the license ID of "dec.num".
+2 /SYSTEM_ID
+ /S[YSTEM_ID]=hex.num
+ Selects all PAKs with the system ID "hex.num". For PAKs with
+ more than one system ID only the first one in the list is
+ matched.
+2 /NUM_SYS
+ /N[UM_SYS]=dec.num
+ Selects all PAKs with "dec.num" system IDs.
+2 /AVAILABLE
+ /A[VAILABLE]=date
+ Selects all PAKs available exactly at "date".
+2 /EXPIRES
+ /EX[PIRES]=date
+ Selects all PAKs expiring exactly at "date".
+2 /CREATED
+ /CR[EATED]=date
+ Selects all PAKs created exactly at "date".
+2 /ENCRYPTION
+ /EN[CRYPTION]=dec.num
+ Selects all PAKs with the checksum computed by the
+ "dec.num"-th encryption function.
+2 /CHECKSUM
+ /CH[ECKSUM]=pattern
+ Selects all PAKs with the checksum matching the pattern. The
+ pattern is a sequence of characters, without dashes between
+ groups of four characters and without the leading digit.
+2 /OPERATOR
+ /O[PERATOR]=pattern
+ Selects all PAKs created by the operator matching the pattern.
+1 VOID
+ V[OID]
+ The VOID command marks all qualified PAKs void. The PAK is
+ void when its check sum is replaced with the
+ n-0000-0000-0000-0000 string. The encryption function number
+ is kept. The command invalidates PAKs created by mistake. It
+ should not be used for valid PAKs.
+ The syntax for the VOID command is:
+ V[OID] [/qualifier=value]
+2 /PRODUCT
+ /P[RODUCT]=pattern
+ Selects all PAKs with the product name matching the pattern.
+2 /VERSION
+ /VE[RSION]=pattern
+ Selects all PAKs with the product version name matching the
+ pattern.
+2 /VALUE
+ /V[ALUE]=dec.num
+ Selects all PAKs with the license value of "dec.num".
+2 /LICENSE_ID
+ /L[ICENSE_ID]=dec.num
+ Selects all PAKs with the license ID of "dec.num".
+2 /SYSTEM_ID
+ /S[YSTEM_ID]=hex.num
+ Selects all PAKs with the system ID "hex.num". For PAKs with
+ more than one system ID only the first one in the list is
+ matched.
+2 /NUM_SYS
+ /N[UM_SYS]=dec.num
+ Selects all PAKs with "dec.num" system IDs.
+2 /AVAILABLE
+ /A[VAILABLE]=date
+ Selects all PAKs available exactly at "date".
+2 /EXPIRES
+ /EX[PIRES]=date
+ Selects all PAKs expiring exactly at "date".
+2 /CREATED
+ /CR[EATED]=date
+ Selects all PAKs created exactly at "date".
+2 /ENCRYPTION
+ /EN[CRYPTION]=dec.num
+ Selects all PAKs with the checksum computed by the
+ "dec.num"-th encryption function.
+2 /CHECKSUM
+ /CH[ECKSUM]=pattern
+ Selects all PAKs with the checksum matching the pattern. The
+ pattern is a sequence of characters, without dashes between
+ groups of four characters and without the leading digit.
+2 /OPERATOR
+ /O[PERATOR]=pattern
+ Selects all PAKs created by the operator matching the pattern.
diff --git a/sr_vvms/la_cmnd.cld b/sr_vvms/la_cmnd.cld
new file mode 100644
index 0000000..5de72f5
--- /dev/null
+++ b/sr_vvms/la_cmnd.cld
@@ -0,0 +1,114 @@
+MODULE LA_CMND
+
+DEFINE VERB exit
+ ROUTINE la_exit
+ NOQUALIFIERS
+
+DEFINE VERB help
+ ROUTINE la_help
+ PARAMETER P1 ,LABEL=topic
+ NOQUALIFIERS
+
+DEFINE VERB initialize
+ ROUTINE la_initial
+ NOQUALIFIERS
+
+DEFINE VERB create
+ ROUTINE la_create
+ NOPARAMETERS
+ QUALIFIER input, LABEL=io, VALUE (TYPE = $FILE,REQUIRED)
+
+DEFINE VERB void
+ ROUTINE la_maint
+ NOPARAMETERS
+ QUALIFIER checksum, LABEL=cs, VALUE (REQUIRED)
+ QUALIFIER num_sys, LABEL=L, VALUE (TYPE = $NUMBER,REQUIRED)
+ QUALIFIER product, LABEL=nam, VALUE (REQUIRED)
+ QUALIFIER version, LABEL=ver, VALUE (REQUIRED)
+ QUALIFIER value, LABEL=x, VALUE (TYPE = $NUMBER,REQUIRED)
+ QUALIFIER activation, LABEL=t0, VALUE (TYPE = $DATETIME,REQUIRED)
+ QUALIFIER expiration, LABEL=t1, VALUE (TYPE = $DATETIME,REQUIRED)
+ QUALIFIER configuration_id, LABEL=lid, VALUE (TYPE = $NUMBER,REQUIRED)
+ QUALIFIER hardware_model, LABEL=sid, VALUE (REQUIRED)
+ QUALIFIER node_num, LABEL=nid, VALUE (REQUIRED)
+ QUALIFIER creation, LABEL=std, VALUE (TYPE = $DATETIME,REQUIRED)
+ QUALIFIER operator, LABEL=oid, VALUE (REQUIRED)
+ QUALIFIER customer, LABEL=adr, VALUE (LIST,REQUIRED)
+ QUALIFIER comment, LABEL=com, VALUE (REQUIRED)
+ QUALIFIER output, LABEL=io, VALUE (DEFAULT=LICENSE.LIS,TYPE = $FILE)
+
+DEFINE VERB list
+ ROUTINE la_maint
+ NOPARAMETERS
+ QUALIFIER checksum, LABEL=cs, VALUE (REQUIRED)
+ QUALIFIER num_sys, LABEL=L, VALUE (TYPE = $NUMBER,REQUIRED)
+ QUALIFIER product, LABEL=nam, VALUE (REQUIRED)
+ QUALIFIER version, LABEL=ver, VALUE (REQUIRED)
+ QUALIFIER value, LABEL=x, VALUE (TYPE = $NUMBER,REQUIRED)
+ QUALIFIER activation, LABEL=t0, VALUE (TYPE = $DATETIME,REQUIRED)
+ QUALIFIER expiration, LABEL=t1, VALUE (TYPE = $DATETIME,REQUIRED)
+ QUALIFIER configuration_id, LABEL=lid, VALUE (TYPE = $NUMBER,REQUIRED)
+ QUALIFIER hardware_model, LABEL=sid, VALUE (REQUIRED)
+ QUALIFIER node_num, LABEL=nid, VALUE (REQUIRED)
+ QUALIFIER creation, LABEL=std, VALUE (TYPE = $DATETIME,REQUIRED)
+ QUALIFIER operator, LABEL=oid, VALUE (REQUIRED)
+ QUALIFIER customer, LABEL=adr, VALUE (LIST,REQUIRED)
+ QUALIFIER comment, LABEL=com, VALUE (REQUIRED)
+ QUALIFIER output, LABEL=io, VALUE (DEFAULT=LICENSE.LIS,TYPE = $FILE)
+
+DEFINE VERB print
+ ROUTINE la_maint
+ NOPARAMETERS
+ QUALIFIER checksum, LABEL=cs, VALUE (REQUIRED)
+ QUALIFIER num_sys, LABEL=L, VALUE (TYPE = $NUMBER,REQUIRED)
+ QUALIFIER product, LABEL=nam, VALUE (REQUIRED)
+ QUALIFIER version, LABEL=ver, VALUE (REQUIRED)
+ QUALIFIER value, LABEL=x, VALUE (TYPE = $NUMBER,REQUIRED)
+ QUALIFIER activation, LABEL=t0, VALUE (TYPE = $DATETIME,REQUIRED)
+ QUALIFIER expiration, LABEL=t1, VALUE (TYPE = $DATETIME,REQUIRED)
+ QUALIFIER configuration_id, LABEL=lid, VALUE (TYPE = $NUMBER,REQUIRED)
+ QUALIFIER hardware_model, LABEL=sid, VALUE (REQUIRED)
+ QUALIFIER node_num, LABEL=nid, VALUE (REQUIRED)
+ QUALIFIER creation, LABEL=std, VALUE (TYPE = $DATETIME,REQUIRED)
+ QUALIFIER operator, LABEL=oid, VALUE (REQUIRED)
+ QUALIFIER customer, LABEL=adr, VALUE (LIST,REQUIRED)
+ QUALIFIER comment, LABEL=com, VALUE (REQUIRED)
+ QUALIFIER output, LABEL=io, VALUE (TYPE= $FILE,REQUIRED)
+
+DEFINE VERB show
+ ROUTINE la_maint
+ NOPARAMETERS
+ QUALIFIER checksum, LABEL=cs, VALUE (REQUIRED)
+ QUALIFIER num_sys, LABEL=L, VALUE (TYPE = $NUMBER,REQUIRED)
+ QUALIFIER product, LABEL=nam, VALUE (REQUIRED)
+ QUALIFIER version, LABEL=ver, VALUE (REQUIRED)
+ QUALIFIER value, LABEL=x, VALUE (TYPE = $NUMBER,REQUIRED)
+ QUALIFIER activation, LABEL=t0, VALUE (TYPE = $DATETIME,REQUIRED)
+ QUALIFIER expiration, LABEL=t1, VALUE (TYPE = $DATETIME,REQUIRED)
+ QUALIFIER configuration_id, LABEL=lid, VALUE (TYPE = $NUMBER,REQUIRED)
+ QUALIFIER hardware_model, LABEL=sid, VALUE (REQUIRED)
+ QUALIFIER node_num, LABEL=nid, VALUE (REQUIRED)
+ QUALIFIER creation, LABEL=std, VALUE (TYPE = $DATETIME,REQUIRED)
+ QUALIFIER operator, LABEL=oid, VALUE (REQUIRED)
+ QUALIFIER customer, LABEL=adr, VALUE (LIST,REQUIRED)
+ QUALIFIER comment, LABEL=com, VALUE (REQUIRED)
+ QUALIFIER output, LABEL=io, VALUE (DEFAULT=LICENSE.LIS,TYPE = $FILE)
+
+DEFINE VERB store
+ ROUTINE la_store
+ NOPARAMETERS
+ QUALIFIER checksum, LABEL=cs, VALUE (REQUIRED)
+ QUALIFIER num_sys, LABEL=L, VALUE (TYPE = $NUMBER,REQUIRED)
+ QUALIFIER product, LABEL=nam, VALUE (REQUIRED)
+ QUALIFIER version, LABEL=ver, VALUE (REQUIRED)
+ QUALIFIER value, LABEL=x, VALUE (TYPE = $NUMBER,REQUIRED)
+ QUALIFIER activation, LABEL=t0, VALUE (TYPE = $DATETIME,REQUIRED)
+ QUALIFIER expiration, LABEL=t1, VALUE (TYPE = $DATETIME,REQUIRED)
+ QUALIFIER configuration_id, LABEL=lid, VALUE (TYPE = $NUMBER,REQUIRED)
+ QUALIFIER hardware_model, LABEL=sid, VALUE (REQUIRED)
+ QUALIFIER node_num, LABEL=nid, VALUE (REQUIRED)
+ QUALIFIER creation, LABEL=std, VALUE (TYPE = $DATETIME,REQUIRED)
+ QUALIFIER operator, LABEL=oid, VALUE (REQUIRED)
+ QUALIFIER customer, LABEL=adr, VALUE (LIST,REQUIRED)
+ QUALIFIER comment, LABEL=com, VALUE (REQUIRED)
+ QUALIFIER output, LABEL=io, VALUE (DEFAULT=LICENSE.LIS,TYPE = $FILE)
diff --git a/sr_vvms/la_convert.c b/sr_vvms/la_convert.c
new file mode 100644
index 0000000..ec38ea1
--- /dev/null
+++ b/sr_vvms/la_convert.c
@@ -0,0 +1,42 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* la_convert.c : translates sequence of bits in bcs[2] to sequence of A - P char
+ used in : la_create.c
+*/
+#include "mdef.h"
+#include "ladef.h"
+
+#define conv(byte,even) ((even ? lo(byte):hi(byte)) + 'A')
+#define lo(x) (x & mask)
+#define hi(x) (x>>4)
+#define mask 15
+
+void la_convert (
+int4 bcs[] ,
+char *cs ) /* result, check sum A - P form */
+{
+ unsigned char *h ; /* bcs scaled in char */
+ int k,j ;
+ bool even ;
+
+ h= (char *)bcs ;
+ even= TRUE ;
+ k= j= 0 ;
+ while (j!=8)
+ {
+ cs[k]= conv(h[j],even) ;
+ even= !even ;
+ cs[k+1]= conv(h[j],even) ;
+ even= !even ;
+ k += 2 ; j++ ;
+ }
+}
diff --git a/sr_vvms/la_create.c b/sr_vvms/la_create.c
new file mode 100644
index 0000000..7a52461
--- /dev/null
+++ b/sr_vvms/la_create.c
@@ -0,0 +1,103 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* la_create.c : License Administration function for creating new licenses
+ used in : license_adm.c
+*/
+
+#include <ssdef.h>
+#include "mdef.h"
+#include <climsgdef.h>
+#include <descrip.h>
+#include "ladef.h"
+#include "lmdef.h"
+#define SAVE (rp[0]=='S' || rp[0]=='Y' )
+#define DISP (rp[0]=='D' || rp[0]==0 )
+#define QUIT (rp[0]=='Q')
+#define EDIT (rp[0]=='E')
+
+int la_create (void)
+{
+ int smg$create_virtual_keyboard(), toupper();
+
+ error_def(LA_NOCNFDB); /* No license created */
+ error_def(LA_NOCNF) ; /* No license created */
+ error_def(LA_NEWCNF) ; /* New license created */
+ error_def(LA_SAVE) ; /* Save Y/N ? */
+ error_def(LA_EMPTY) ;
+ error_def(LA_BADENCR) ;
+
+ char *h ; /* db in main store */
+ la_prolog *prol ; /* db file prolog */
+ pak *p ; /* pak record */
+
+ char rp[32] ; /* operator reply */
+ int4 status ;
+ unsigned char recall= 16 ;
+ unsigned short w ;
+ uint4 kid ; /* virt. keyboard ID */
+ uint4 bcs[3]= {0,0,0} ;
+
+ if ((h= la_getdb(LADB))==NULL) /* db in main storage */
+ {
+ lib$signal(LA_NOCNFDB) ;
+ }
+ prol= h ;
+ p= (char *)h + prol->len ; /* place for new pak */
+
+ status= smg$create_virtual_keyboard(&kid,0,0,0,&recall)
+ ;if (status!=SS$_NORMAL)
+ {
+ lib$signal(status) ;
+ }
+ la_initpak(prol->lastid,p) ; /* pak initialized */
+ rp[0]= 'E' ;
+ while (!SAVE && !QUIT)
+ {
+ if EDIT
+ {
+ la_edit(kid,h,p) ;
+ la_puthead(p) ;
+ la_putfldr(&(p->pf)) ;
+ if(!la_encrypt(p->ph.n,&(p->pd),(p->ph.l[4] - p->ph.l[2]),bcs))
+ {
+ lib$signal(LA_BADENCR) ;
+ }
+ else
+ {
+ la_convert(p->ph.cs,bcs) ;
+ }
+ }
+ else if DISP
+ {
+ la_listpak(p) ;
+ }
+ la_putmsgu(LA_EMPTY,0,0) ;
+ rp[0]= 0 ;
+ la_getstr(kid,LA_SAVE,rp,0,1) ;
+ la_putmsgu(LA_EMPTY,0,0) ;
+ rp[0]= ( rp[0]>='a' ? rp[0]-32 : rp[0] ) ;
+ }
+ if (SAVE)
+ {
+ (prol->N)++ ; /* count of paks ++ */
+ prol->len += p->ph.l[0] ; /* db file size ++ */
+ prol->lastid = p->pd.lid ; /* new last license ID */
+ la_putdb (LADB,h) ; /* db back to file */
+ lm_putmsgu (LA_NEWCNF,0,0) ;
+ }
+ else if (QUIT) /* abort without saving */
+ {
+ lm_putmsgu(LA_NOCNF,0,0) ;
+ }
+ la_freedb(h) ;
+ return(status) ;
+}
diff --git a/sr_vvms/la_edit.c b/sr_vvms/la_edit.c
new file mode 100644
index 0000000..59d2929
--- /dev/null
+++ b/sr_vvms/la_edit.c
@@ -0,0 +1,150 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* la_edit.c: new license entered, inteactively with fields editting
+ used in : la_create.c
+*/
+
+#include "mdef.h"
+#include <ssdef.h>
+#include <descrip.h>
+#include "ladef.h"
+#define MINT 0x0FFFFFFF
+#define MUNS 0xFFFFFFFF
+#define MSHO 32767
+#define B (e==SS$_NORMAL)
+#define cop(a,b) { char *y= a ;while (*b!=0) *(y++)= *(b++) ; *y= 0 ;}
+
+void la_edit (uint4 kid,char *h,pak *p)
+/*
+uint4 kid ; virt. keyboard ID
+char *h ; data base
+pak *p ; buf. for new pak rec
+*/
+{
+ int str$upcase() ;
+ int k,e,u,w ;
+ int4 n ;
+ bool valid ;
+ char buf[9*ADDR] ; /* temporary */
+ int4 sid[NSYS] ; /* temp hardw. model */
+ int4 mdl ; /* hardware model */
+
+ int4 *psid ; /* pak SIDs */
+ char *padr ; /* pak address */
+ char *pcom ; /* pak comment */
+ char *badr ; /* pointer to buf */
+ char *top ;
+
+ error_def(LA_PNAM) ;
+ error_def(LA_PVER) ;
+ error_def(LA_PX) ;
+ error_def(LA_PT0) ;
+ error_def(LA_PT1) ;
+ error_def(LA_PLID) ;
+ error_def(LA_PL) ;
+ error_def(LA_PSID) ;
+ error_def(LA_PCUST) ;
+ error_def(LA_PADR1) ;
+ error_def(LA_PADR2) ;
+ error_def(LA_PADR3) ;
+ error_def(LA_PADR4) ;
+ error_def(LA_PCOM) ;
+ error_def(LA_PENC) ;
+ error_def(LA_VALNAM) ;
+ error_def(LA_VALVER) ;
+ error_def(LA_INVAL) ;
+ uint4 ladr[5]= {LA_PCUST,LA_PADR1,LA_PADR2,LA_PADR3,LA_PADR4} ;
+
+ $DESCRIPTOR(dnam,p->pd.nam) ;
+ $DESCRIPTOR(dver,p->pd.ver) ;
+ $DESCRIPTOR(dbuf,buf) ;
+
+ valid= FALSE ;
+ while (!valid)
+ {
+ w= la_getstr(kid,LA_PNAM,p->pd.nam,1,PROD) ;
+ dnam.dsc$w_length= w ;
+ e= str$upcase(&dnam,&dnam) ; if (!B) lib$signal(e) ;
+ valid= la_validate(LA_VALNAM,p->pd.nam) ;
+ }
+ valid= FALSE ;
+ while (!valid)
+ {
+ w= la_getstr(kid,LA_PVER,p->pd.ver,0,VERS) ;
+ dver.dsc$w_length= w ;
+ e= str$upcase(&dver,&dver) ; if (!B) lib$signal(e) ;
+ valid= la_validate(LA_VALVER,p->pd.ver) ;
+ }
+ n= p->pd.x ;
+ la_getnum(kid,LA_PX,&n,0,MSHO) ; p->pd.x= n ;
+ la_getdat(kid,LA_PT0,&(p->pd.t0),0,MUNS) ;
+ la_getdat(kid,LA_PT1,&(p->pd.t1),p->pd.t0[1],MUNS) ;
+ valid= FALSE ;
+ while (!valid)
+ {
+ la_getnum(kid,LA_PLID,&(p->pd.lid),1,MINT) ;
+ valid= la_uniqlid(h,p->pd.lid) ;
+ }
+ n= p->pd.L ;
+ psid= (char *)p + SIZEOF(pak) ;
+ padr= psid + 2*n ;
+ for (k= 0;k!=n;k++)
+ {
+ sid[k]= psid[k] ;
+ }
+ for (k= n;k!=NSYS;k++)
+ {
+ sid[k]= 0 ;
+ }
+ la_getnum(kid,LA_PL,&n,1,NSYS) ; p->pd.L= n ;
+ for (k= 0;k!=n;k++)
+ {
+ w= la_mdl2nam(buf,sid[k]) ;
+ buf[w]= 0 ;
+ valid= FALSE ;
+ while (!valid)
+ {
+ w= la_getstr(kid,LA_PSID,buf,0,HWLEN) ;
+ dbuf.dsc$w_length= w ;
+ e= str$upcase(&dbuf,&dbuf) ; if (!B) lib$signal(e) ;
+ valid= la_nam2mdl(&mdl,w,buf) ;
+ if (!valid)
+ {
+ la_putmsgu(LA_INVAL,0,0) ;
+ }
+ }
+ sid[k]= mdl ;
+ }
+ badr= buf ;
+ for (k= 0;k!=5;k++)
+ {
+ cop(badr,padr) ;
+ w= la_getstr(kid,ladr[k],badr,0,ADDR) ;
+ padr++ ;
+ badr += w + 1 ;
+ }
+ cop(badr,padr) ;
+ w= la_getstr(kid,LA_PCOM,badr,0,4*ADDR) ;
+ top= badr + w + 1 ;
+ for (k= 0;k!=n;k++)
+ {
+ psid[k]= sid[k] ;
+ }
+ padr= psid + 2*n ;
+ badr= buf ;
+ while (badr!=top)
+ {
+ *(padr++)= *(badr++) ;
+ }
+ n= p->ph.n ;
+ la_getnum(kid,LA_PENC,&n,0,NCRY) ; p->ph.n= n ;
+}
diff --git a/sr_vvms/la_encrypt.c b/sr_vvms/la_encrypt.c
new file mode 100644
index 0000000..9b97dc5
--- /dev/null
+++ b/sr_vvms/la_encrypt.c
@@ -0,0 +1,51 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* la_encrypt.c : for given encryption function number, and an input sequence of bytes,
+ the program computes the checksum of the sequence.
+ used in : la_create.c,lp_licensed.c,lm_verify
+*/
+#include "mdef.h"
+#include <ssdef.h>
+#include "ladef.h"
+#include <descrip.h>
+#include "la_encrypt.h"
+
+bool la_encrypt (
+short n , /* encryption function number */
+char *q , /* input sequence */
+int len, /* sequence length */
+uint4 bcs[]) /* result, binary form */
+{
+ uint4 poly0[10] = { 0xEDB88320,0xA001A001,0x00008408,0x00000000,0xA001A001,1,1,1,1,1} ;
+ int4 init0[10] = { 0xFFFFFFFF,0x00000000,0x0000FFFF,0xFFFFFFFF,0x00000000,0,0,0,0,0} ;
+ uint4 poly1[10] = { 0xA001A001,0x00008408,0xEDB88320,0xEDB88320,0x0000A001,1,1,1,1,1} ;
+ int4 init1[10] = { 0x00000000,0x0000FFFF,0xFFFFFFFF,0xFFFFFFFF,0x00000000,0,0,0,0,0} ;
+ bool status ;
+ int4 crctbl[16] ;
+ $DESCRIPTOR (dq,q) ;
+
+ dq.dsc$w_length = len ;
+ if (n>=5)
+ {
+ status = FALSE;
+ }
+ else
+ {
+ lib$crc_table(poly0+n,crctbl) ;
+ bcs[0] = lib$crc(crctbl,init0+n,&dq) ;
+
+ lib$crc_table(poly1+n,crctbl) ;
+ bcs[1] = lib$crc(crctbl,init1+n,&dq) ;
+ status = TRUE ;
+ }
+ return status ;
+}
diff --git a/sr_vvms/la_exit.c b/sr_vvms/la_exit.c
new file mode 100644
index 0000000..59b7bcd
--- /dev/null
+++ b/sr_vvms/la_exit.c
@@ -0,0 +1,21 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* la_exit.c : returns RMS$_EOF to terminate license adm or license man
+ used in : license_adm.c license_man.c
+ */
+
+#include "mdef.h"
+#include <rmsdef.h>
+int la_exit()
+{
+ return(RMS$_EOF) ;
+}
diff --git a/sr_vvms/la_fputmsgu.c b/sr_vvms/la_fputmsgu.c
new file mode 100644
index 0000000..4f08452
--- /dev/null
+++ b/sr_vvms/la_fputmsgu.c
@@ -0,0 +1,48 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* la_fputmsgu.c : outputs and formats message for user message code
+ and user FAO arguments to a file.
+ */
+#include "mdef.h"
+
+#include <ssdef.h>
+#include <rms.h>
+#include <descrip.h>
+#include "ladef.h"
+#include "la_putline.h"
+#include "la_fputmsgu.h"
+
+#define B (e==SS$_NORMAL)
+
+ void la_fputmsgu (struct RAB *rab,int4 c,int4 fao[],short n)
+ {
+ int k,e;
+ struct { short argc ; /* structure longword count */
+ short opt ; /* message display options */
+ int4 code ; /* message code */
+ short count ; /* FAO count */
+ short newopt; /* new options */
+ int4 fao[16]; /* fao arguments */
+ } msgvec ;
+
+ msgvec.argc= n+2 ;
+ msgvec.opt= 0x0001 ;
+ msgvec.code= c ;
+ msgvec.count= n ;
+ msgvec.newopt= 0x0001 ;
+
+ for (k= 0;k!=n;k++) msgvec.fao[k]= fao[k] ;
+
+ e= sys$putmsg(&msgvec,&la_putline,0,rab) ;
+ if (!B) lib$signal(e) ;
+
+}
diff --git a/sr_vvms/la_fputmsgu.h b/sr_vvms/la_fputmsgu.h
new file mode 100644
index 0000000..2e31cbe
--- /dev/null
+++ b/sr_vvms/la_fputmsgu.h
@@ -0,0 +1,16 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+#ifndef __LA_FPUTMSGU_H__
+#define __LA_FPUTMSGU_H__
+
+void la_fputmsgu (struct RAB *rab,int4 c,int4 fao[],short n);
+
+#endif
diff --git a/sr_vvms/la_getcli.c b/sr_vvms/la_getcli.c
new file mode 100644
index 0000000..4a8190d
--- /dev/null
+++ b/sr_vvms/la_getcli.c
@@ -0,0 +1,138 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <ssdef.h>
+#include <descrip.h>
+#include <climsgdef.h>
+
+#include "ladef.h"
+/* la_getcli.c: retrieves values from the parsed string and fills the pak
+ pattern in. Fills the array of qualified variables.
+ used in : la_maint.c
+*/
+
+#define MAXLNG 0xFFFFFFFF
+#define CONST static readonly
+
+bool la_getcli(int v_arr[], pak *pak_ptr)
+/* v_arr - qualified variables */
+/* pak_ptr - buff for pak pattern */
+{
+ bool cli, valid;
+ char *cptr, ret[ADDR], *vptr[16]; /* pointers to pak variables */
+ short t_short; /* return string length */
+ int cnt0, cnt1;
+ int4 cli$present(), cli$getvalue();
+ int4 result;
+ uint4 cli_status, status;
+ varid var; /* variable identifier (enum type) */
+ CONST char *iden[16] = { "n", "cs", "l" , "std", "oid", "L" , "nam", "ver",
+ "x", "t0", "t1", "lid", "sid", "nid", "adr", "com" };
+ CONST short len[16] = { 1, 2, 1, 3, 3, 1, 3, 3,
+ 1, 2, 2, 3, 3, 3, 3, 3};
+ CONST vtyp type[16] = { sho, csm, sho, dat, str, sho, str, str,
+ sho, dat, dat, lon, mdl, lon, list, str };
+ $DESCRIPTOR (dent, iden); /* CLI entity descriptor */
+ $DESCRIPTOR (dret, ret); /* CLI return value descrip */
+
+ dret.dsc$w_length = ADDR;
+ vptr[v_n] = &(pak_ptr->ph.n);
+ vptr[v_cs] = pak_ptr->ph.cs;
+ vptr[v_l] = pak_ptr->ph.l;
+ vptr[v_std] = pak_ptr->pf.std;
+ vptr[v_oid] = pak_ptr->pf.oid;
+ vptr[v_L] = &(pak_ptr->pd.L);
+ vptr[v_nam] = pak_ptr->pd.nam;
+ vptr[v_ver] = pak_ptr->pd.ver;
+ vptr[v_x] = &(pak_ptr->pd.x);
+ vptr[v_t0] = pak_ptr->pd.t0;
+ vptr[v_t1] = pak_ptr->pd.t1;
+ vptr[v_lid] = &(pak_ptr->pd.lid);
+ vptr[v_sid] = (char *)pak_ptr + SIZEOF(pak);
+ vptr[v_nid] = vptr[v_sid] + SIZEOF(int4);
+ cptr = vptr[v_adr] = vptr[v_nid] + SIZEOF(int4);
+ vptr[v_com] = vptr[v_adr] + 4 * ADDR + 4;
+ for (cnt0 = 0; 4 != cnt0; cnt0++)
+ *(cptr++) = 0;
+ cli = FALSE;
+ for (var = v_cs; var != eovar; var++)
+ {
+ dent.dsc$a_pointer= iden[var];
+ dent.dsc$w_length = len[var];
+ cli_status = cli$present(&dent);
+ if (CLI$_PRESENT == cli_status)
+ {
+ cli = TRUE;
+ status = SS$_NORMAL;
+ dret.dsc$w_length = ADDR;
+ cli_status = cli$get_value(&dent, &dret, &t_short);
+ dret.dsc$w_length = t_short;
+ ret[t_short] = 0;
+ switch (type[var])
+ {
+ case str: memcpy(vptr[var], ret, t_short + 1);
+ break;
+ case list: memcpy(vptr[var], ret, t_short + 1);
+ for (cptr = vptr[var] + t_short + 1, cnt0 = 1; (CLI$_COMMA == cli_status) && (5 != cnt0);
+ cptr += t_short + 1, cnt0++)
+ {
+ dret.dsc$w_length = ADDR;
+ cli_status = cli$get_value(&dent, &dret, &t_short);
+ dret.dsc$w_length = t_short;
+ ret[t_short] = 0;
+ memcpy(cptr, ret, t_short + 1);
+ }
+ for (; cnt0 < 5; cnt0++)
+ *(cptr++) = 0;
+ break;
+ case sho: status = lib$cvt_dtb((int4)t_short, ret, &result);
+ *((short *)vptr[var]) = result;
+ break;
+ case lon: status = lib$cvt_dtb((int4)t_short, ret, vptr[var]);
+ break;
+ case hex: status = lib$cvt_htb((int4)t_short, ret, vptr[var]);
+ break;
+ case dat: status = lib$convert_date_string(&dret, (date *)vptr[var]);
+ break;
+ case mdl: valid = la_nam2mdl(vptr[var], t_short, ret);
+ if (!valid)
+ *((int4 *)vptr[var]) = MAXLNG;
+ break;
+ case csm: if (('0' <= ret[0]) && ('9' >= ret[0]))
+ {
+ status = lib$cvt_dtb(1, ret, &result);
+ *((short *)vptr[v_n]) = result;
+ cnt0 = v_arr[v_n] = 1;
+ } else
+ cnt0 = 0;
+ for (cnt1 = 0; (16 != cnt1) && (cnt0 != t_short); cnt0++)
+ {
+ if ('-' != ret[cnt0])
+ {
+ *(vptr[var] + cnt1) = ret[cnt0];
+ cnt1++;
+ }
+ }
+ *(vptr[var] + cnt1) = 0;
+ break;
+ otherwise: break;
+ }
+ if (SS$_NORMAL != status)
+ la_putmsgs(status);
+ v_arr[var] = 1;
+ } else
+ v_arr[var] = 0;
+ }
+ pak_ptr->pd.L = 1; /* only one system allowed for matching */
+ return cli;
+}
diff --git a/sr_vvms/la_getdat.c b/sr_vvms/la_getdat.c
new file mode 100644
index 0000000..2f631be
--- /dev/null
+++ b/sr_vvms/la_getdat.c
@@ -0,0 +1,81 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <ssdef.h>
+#include <descrip.h>
+
+#include "ladef.h"
+
+/* la_getdat.c: Prompts for a date string until correct and within range
+ used in : la_interact.c
+*/
+
+void la_getdat(uint4 kid, int4 code, date *date_ptr, uint4 lo, uint4 hi)
+/* kid - virt. keyb. ID */
+/* code - promt msg code */
+/* date_ptr - date/time returned */
+/* lo - min value of date */
+/* hi - max value of date */
+{
+ int status;
+ bool valid;
+ char pro[64], res[64];
+ unsigned short length; /* res. string length */
+ int4 mlen = 32; /* max length of result */
+ int smg$read_string(), sys$getmsg();
+ int sys$asctim();
+ $DESCRIPTOR(dini, res); /* initial string */
+ $DESCRIPTOR(dres, res); /* resuting string */
+ $DESCRIPTOR(dprm, pro); /* prompt string */
+ error_def(LA_INVAL);
+
+ dprm.dsc$w_length = 64;
+ status = sys$getmsg(code, &length, &dprm, 1, 0);
+ if (SS$_NORMAL != status)
+ lib$signal(status);
+ dprm.dsc$w_length = length;
+ dres.dsc$w_length = 12;
+ if (0 == (*date_ptr)[1])
+ { /* no initial date */
+ res[0] = 0;
+ length = 0;
+ } else
+ {
+ status = sys$asctim(&length, &dres, date_ptr, 0);
+ if (SS$_NORMAL != status)
+ lib$signal(status);
+ }
+ dres.dsc$w_length = 64;
+ valid = FALSE;
+ while ((SS$_NORMAL != status) || !valid)
+ {
+ res[length] = ' ';
+ dini.dsc$w_length = length;
+ status = smg$read_string(&kid, &dres, &dprm, &mlen, 0, 0, 0, &length, 0, 0, &dini);
+ if (SS$_NORMAL != status)
+ lib$signal(status);
+ else if (0 == length)
+ { /* no datstatus/time */
+ (*date_ptr)[0] = (*date_ptr)[1] = lo = 0;
+ hi = 1;
+ } else if (0 != length)
+ { /* date/time entered */
+ status = lib$convert_date_string(&dres, date_ptr);
+ if (SS$_NORMAL != status)
+ la_putmsgs(status);
+ }
+ valid = ((*date_ptr)[1] >= lo || (*date_ptr)[1] < hi);
+ if (!valid)
+ la_putmsgu(LA_INVAL, 0, 0);
+ }
+}
diff --git a/sr_vvms/la_getdb.c b/sr_vvms/la_getdb.c
new file mode 100644
index 0000000..1a625ae
--- /dev/null
+++ b/sr_vvms/la_getdb.c
@@ -0,0 +1,85 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* la_getdb : entire license data base in memory
+ or file read error
+ or not enough memory allocated
+ or bad db file identifier
+ la_freedb : frees the store allocated for the data base
+ */
+#include "mdef.h"
+#include <ssdef.h>
+#include <rms.h>
+#include "ladef.h"
+#include "la_io.h"
+
+GBLREF bool licensed;
+GBLREF int4 lkid, lid;
+
+ char * la_getdb (char *fn)
+/*
+ char *fn ; data base file name
+*/
+{
+ struct FAB f ; /* file access block */
+ struct RAB r ; /* record access block */
+ struct XABFHC x ; /* file header */
+ struct NAM n; /* added nam block to capture file id (js) */
+
+ int4 status ;
+ int4 size ;
+ int k ;
+ char *h= NULL ; /* db in main store */
+ char *p ; /* current read buffer */
+ la_prolog *prol ; /* db file prolog */
+
+ n = cc$rms_nam;
+ status= bopen(fn,&f,&r,&x,&n);
+ if (status==SS$_NORMAL)
+ {
+ size= 512 * x.xab$l_ebk + PBUF ;
+ if ((h= (char *)malloc(size))!=NULL)
+ {
+ p= h ;
+ while (status==SS$_NORMAL && p<h+size)
+ {
+ status= bread(&r,p,BLKS) ; p += BLKS ;
+ }
+ if (status!=RMS$_EOF)
+ {
+ h= NULL ;
+ }
+ else
+ {
+ prol= h ;
+ if (prol->id!=DBID) /* invalid file ID */
+ {
+ h= NULL ;
+ }
+ }
+ }
+ bclose(&f) ;
+ }
+ else
+ {
+ h= NULL ;
+ }
+ return(h) ;
+}
+
+ void la_freedb (h)
+ char *h ; /* data base in memory */
+{
+ if (h!=NULL)
+ {
+ free(h) ;
+ }
+}
diff --git a/sr_vvms/la_getnum.c b/sr_vvms/la_getnum.c
new file mode 100644
index 0000000..37ffb09
--- /dev/null
+++ b/sr_vvms/la_getnum.c
@@ -0,0 +1,77 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <ssdef.h>
+#include <descrip.h>
+
+#include "ladef.h"
+#include "min_max.h"
+
+/* la_getnum.c: Prompts for a decimal input until valid. Provides an initial value.
+ used in : la_interact.c
+*/
+
+#define MAXLEN 16
+#define MAXDECLEN 12 /* max length of a num in decimal digits */
+
+void la_getnum (uint4 kid, int4 code, int4 *num_ptr, int4 lo, int4 hi)
+/* kid - virt. keyb. ID */
+/* code - prompt code */
+/* num_ptr - result returned */
+/* lo - min value of result */
+/* hi - max value of result */
+{
+ bool valid;
+ char buf[32], *ini = NULL, pro[64], *res = NULL;
+ unsigned short length; /* res. string length */
+ int4 smg$read_string(), sys$getmsg();
+ int4 bin, status;
+ int4 mlen = MAXLEN; /* max length of res */
+ int cnt0;
+ $DESCRIPTOR (dini, ini); /* initial string */
+ $DESCRIPTOR (dres, res); /* resulting string */
+ $DESCRIPTOR (dprm, pro); /* prompt string */
+ error_def (LA_INVAL);
+
+ bin = *num_ptr;
+ cnt0 = MAXLEN;
+ while (0 != bin)
+ {
+ cnt0--;
+ buf[cnt0] = bin % 10 + '0';
+ bin = bin / 10;
+ }
+ res = buf + cnt0;
+ dres.dsc$a_pointer = dini.dsc$a_pointer = res;
+ dres.dsc$w_length = MAXLEN;
+ dprm.dsc$w_length = SIZEOF(pro);
+ status = sys$getmsg(code, &length, &dprm, 1, 0);
+ dprm.dsc$w_length = length;
+ length = MAXLEN - cnt0;
+ valid = FALSE;
+ while ((status & 1) && !valid)
+ {
+ memset(res + length, ' ', cnt0);
+ dini.dsc$w_length = MIN(length, MAXDECLEN);
+ status = smg$read_string(&kid, &dres, &dprm, &mlen, 0, 0, 0, &length, 0, 0, &dini);
+ if (status & 1)
+ {
+ status = lib$cvt_dtb((int4)length, res, num_ptr);
+ valid = ((*num_ptr >= lo) && (*num_ptr < hi) && (SS$_NORMAL == status));
+ if (!valid)
+ la_putmsgu(LA_INVAL, 0, 0);
+ }
+ }
+ if (!(status & 1))
+ lib$signal(status);
+}
diff --git a/sr_vvms/la_getstr.c b/sr_vvms/la_getstr.c
new file mode 100644
index 0000000..b4828eb
--- /dev/null
+++ b/sr_vvms/la_getstr.c
@@ -0,0 +1,71 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <ssdef.h>
+#include <descrip.h>
+
+#include "ladef.h"
+#include "min_max.h"
+
+/* la_getstr.c: Prompts for string input until correct; provides initial
+ string
+ used in : la_interact.c
+*/
+
+short la_getstr(uint4 kid, int4 code, char *res, int lo, int hi)
+/* kid - virt. keyb. ID */
+/* code - prompt message code */
+/* res - result returned */
+/* lo - min length of result */
+/* hi - max length of result */
+{
+ boolean_t valid;
+ char buf[4 * ADDR], pro[80];
+ char *ini = NULL;
+ unsigned short w_short; /* res. string length */
+ int cnt;
+ int4 status;
+ int4 smg$read_string(), sys$getmsg();
+ $DESCRIPTOR (dini, ini); /* initial string */
+ $DESCRIPTOR (dbuf, buf); /* resuting string */
+ $DESCRIPTOR (dpro, pro); /* prompt string */
+ error_def (LA_INVAL);
+
+ dpro.dsc$w_length = 80;
+ status = sys$getmsg(code, &w_short, &dpro, 1, 0);
+ if (SS$_NORMAL != status)
+ lib$signal(status);
+ dpro.dsc$w_length = w_short;
+ for (w_short = 0; !w_short || ((0 != res[w_short]) && (hi > w_short)); w_short++)
+ buf[w_short] = res[w_short];
+ dini.dsc$a_pointer = buf;
+ dbuf.dsc$w_length = hi;
+ valid = FALSE;
+ while ((SS$_NORMAL != status) || !valid)
+ {
+ buf[w_short] = ' ';
+ dini.dsc$w_length = w_short;
+ status = smg$read_string(&kid, &dbuf, &dpro, &hi, 0, 0, 0, &w_short, 0, 0, &dini);
+ if (SS$_NORMAL != status)
+ lib$stop(status);
+ valid = ((w_short >= lo) && (w_short < hi)) || ((1 == w_short) && (1 == hi));
+ if (!valid)
+ {
+ w_short = MIN(w_short, hi - 1);
+ la_putmsgu(LA_INVAL, 0, 0);
+ }
+ }
+ for (cnt = 0; cnt < hi; cnt++)
+ res[cnt] = (cnt < w_short) ? buf[cnt] : 0;
+ return w_short;
+}
diff --git a/sr_vvms/la_help.c b/sr_vvms/la_help.c
new file mode 100644
index 0000000..b256a05
--- /dev/null
+++ b/sr_vvms/la_help.c
@@ -0,0 +1,42 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* la_help.c: displays the help file
+ used in : la_cmnd.cld
+*/
+
+#include "mdef.h"
+#include <ssdef.h>
+#include <descrip.h>
+#include <climsgdef.h>
+#include "ladef.h"
+
+int la_help ()
+{
+ int cli$get_getvalue();
+ int lbr$output_help() ;
+ int e ;
+ int4 fl= 1 ;
+ short w ;
+ char buf[256] ;
+ $DESCRIPTOR (dent,"topic");
+ $DESCRIPTOR (dbuf,buf) ;
+ $DESCRIPTOR (dlib,LAHP) ;
+
+ e = cli$get_value(&dent,&dbuf,&w) ;
+ if (e!=SS$_NORMAL)
+ {
+ dbuf.dsc$w_length= 0 ;
+ }
+ lbr$output_help(lib$put_output,0,&dbuf,&dlib,&fl,lib$get_input) ;
+
+ return e ;
+}
diff --git a/sr_vvms/la_initial.c b/sr_vvms/la_initial.c
new file mode 100644
index 0000000..8ef968b
--- /dev/null
+++ b/sr_vvms/la_initial.c
@@ -0,0 +1,111 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* la_initial.c: == data base file initialized
+ */
+
+#include "mdef.h"
+#include <climsgdef.h>
+#include <ssdef.h>
+#include <psldef.h>
+#include <rms.h>
+#include <lnmdef.h>
+#include <descrip.h>
+#include "gtm_string.h"
+#include "ladef.h"
+#include "lmdef.h"
+#include "la_io.h"
+
+int la_initial (char *ln[])
+/*
+char *ln[] ; db logical name
+*/
+{
+ int4 cli$get_getvalue(),sys$trnlnm();
+ error_def (LA_DBINIT) ; /* License db init. */
+ error_def (LA_DBEXIS) ; /* Lic. db exists allready */
+ la_prolog *h ; /* data base prolog */
+ int4 status ; /* status */
+ int4 fao[2] ;
+ char res[128] ; /* resulting file name */
+ char exp[255]; /* expanded file name */
+ int4 expl; /* ... length */
+ char buf[BLKS] ;
+ $DESCRIPTOR (dtbp,"LNM$JOB") ;
+ $DESCRIPTOR (dtbs,"LNM$FILE_DEV") ;
+ $DESCRIPTOR (dlnm,ln[0]) ;
+ $DESCRIPTOR (dres,res) ;
+ struct FAB fab ;
+ struct RAB rab ;
+ struct NAM nam;
+ struct XABPRO xab;
+ int4 ctx= 0 ;
+ int4 iosb ;
+ char acmo= PSL$C_USER ;
+ short w ;
+ struct
+ {
+ short bln;
+ short cod;
+ int4 bdr;
+ int4 rln;
+ } itm[3] ;
+
+ dlnm.dsc$w_length= strlen(ln[0]) ;
+ status= sys$trnlnm(0,&dtbs,&dlnm,0,0) ;
+ if (status==SS$_NOLOGNAM)
+ {
+ itm[0].bln= strlen(ln[1]) ; itm[1].bln= 0 ;
+ itm[0].cod= LNM$_STRING ; itm[1].cod= 0 ;
+ itm[0].bdr= ln[1] ; itm[1].bdr= 0 ;
+ itm[0].rln= &w ; itm[1].rln= 0 ;
+ status= sys$crelnm(0,&dtbp,&dlnm,&acmo,itm) ;
+ }
+ if (status==SS$_NORMAL)
+ {
+ status= lib$find_file(&dlnm,&dres,&ctx,0,0,&iosb,0) ;
+ if (status==RMS$_NMF || status==RMS$_FNF)
+ {
+ status= SS$_NORMAL ;
+ }
+ else if (status==SS$_NORMAL || status==RMS$_NORMAL)
+ {
+ status= LA_DBEXIS ;
+ }
+ }
+ if (status==SS$_NORMAL) /* file name received in f */
+ {
+ h= buf ; /* prolog positioned in buf */
+ h->id= DBID ; /* db file assigned its ID */
+ h->N= 0 ;
+ h->len= SIZEOF(la_prolog) ; /* prolog data filled in */
+ nam = cc$rms_nam;
+ nam.nam$l_esa = &exp;
+ nam.nam$b_ess = SIZEOF(exp);
+ status= bcreat(ln[0],&fab,&rab,&nam,&xab,ALOC) ;
+ if (status==SS$_NORMAL)
+ {
+ status= bwrite(&rab,buf,BLKS) ;
+ }
+ bclose(&fab) ;
+ }
+ if (status==SS$_NORMAL)
+ {
+/* fao[0]= strlen(ln[0]) ; fao[1]= ln[0] ; */
+ fao[0]= nam.nam$b_esl; fao[1]= &exp;
+ lm_putmsgu(LA_DBINIT,fao,2) ;
+ }
+ else
+ {
+ lib$signal(status) ;
+ }
+ return status ;
+}
diff --git a/sr_vvms/la_initpak.c b/sr_vvms/la_initpak.c
new file mode 100644
index 0000000..7cfa2cb
--- /dev/null
+++ b/sr_vvms/la_initpak.c
@@ -0,0 +1,45 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* la_initpak.c: initializes the pak record
+ used in : la_create.c
+ */
+
+#include "mdef.h"
+#include <ssdef.h>
+#include <descrip.h>
+#include "ladef.h"
+
+void la_initpak (llid,p)
+int4 llid ; /* last license ID */
+pak *p ; /* buff. for the pak rec*/
+{
+ int k ;
+ char *q ;
+
+ q= (char *)p ;
+ for (k= 0;k!=PBUF;k++)
+ {
+ *(q++) = 0 ;
+ }
+
+ p->ph.n= 0 ;
+ p->ph.cs[0]= 0 ;
+
+ p->pd.nam[0]= 0 ;
+ p->pd.ver[0]= 0 ;
+ p->pd.x= 0 ;
+ p->pd.t0[1]= 0 ;
+ p->pd.t1[1]= 0 ;
+ p->pd.lid= llid + 1 ;
+ p->pd.L= 0 ;
+
+}
diff --git a/sr_vvms/la_io.c b/sr_vvms/la_io.c
new file mode 100644
index 0000000..758db25
--- /dev/null
+++ b/sr_vvms/la_io.c
@@ -0,0 +1,201 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* License Adiministration I/O system */
+#include "mdef.h"
+
+#include "gtm_string.h"
+#include <ssdef.h>
+#include <rms.h>
+#include "ladef.h"
+#include "la_io.h"
+#define T RMS$_NORMAL
+
+ void bclose (struct FAB *f)
+{
+ sys$close(f) ;
+}
+
+ void bdelete (struct FAB *f,struct XABPRO *x)
+{
+ int e;
+
+ *x = cc$rms_xabpro;
+ x->xab$w_pro = 0x0000; /* (sy:rwed,ow:rwed,gr:rwed,wo:rwed) */
+ f->fab$l_xab = x;
+
+ e = sys$close(f);
+
+ f->fab$l_fop = f->fab$l_fop | FAB$M_NAM; /* Allow name block input */
+ f->fab$l_fna = 0;
+ f->fab$b_fns = 0; /* Disable hard file name */
+
+ e = sys$erase(f);
+}
+
+ int bcreat (
+ char *fn ,
+ struct FAB *f ,
+ struct RAB *r ,
+ struct NAM *nam,
+ struct XABPRO *xab,
+ int n ) /* file allocation */
+{
+ int e ;
+
+ *f= cc$rms_fab ;
+ f->fab$l_alq= n ;
+ f->fab$w_deq= n/4 ;
+ f->fab$b_fac= FAB$M_PUT ;
+ f->fab$l_fna= fn ;
+ f->fab$b_fns= strlen(fn) ;
+ f->fab$l_mrn= 0 ;
+ f->fab$l_fop= FAB$M_CBT ;
+ f->fab$w_mrs= BLKS ;
+ f->fab$b_org= FAB$C_SEQ ;
+ f->fab$b_rfm= FAB$C_FIX ;
+ f->fab$b_shr= FAB$M_NIL ;
+
+ *xab = cc$rms_xabpro;
+ xab->xab$w_pro = 0xEE88; /* /protection=(sy:rwe,ow:rwe,gr:r,wo:r) */
+ f->fab$l_xab = xab;
+
+ f->fab$l_nam = nam;
+
+ e= sys$create(f) ;
+ if (e==T)
+ {
+ *r= cc$rms_rab ;
+ r->rab$l_fab= f ;
+ r->rab$b_mbc= 4;
+ e= sys$connect(r) ;
+ }
+ if (e==T) e= SS$_NORMAL ;
+ return (e) ;
+}
+
+ int vcreat (
+ char *fn ,
+ struct FAB *f ,
+ struct RAB *r ,
+ int n ) /* file allocation */
+{
+ int e ;
+ *f= cc$rms_fab ;
+ f->fab$b_fac= FAB$M_PUT ;
+ f->fab$l_fna= fn ;
+ f->fab$b_fns= strlen(fn) ;
+ f->fab$l_mrn= 0 ;
+ f->fab$b_org= FAB$C_SEQ ;
+ f->fab$b_rfm= FAB$C_VAR ;
+ f->fab$b_rat= FAB$M_CR ;
+ f->fab$b_shr= FAB$M_NIL ;
+
+ e= sys$create(f) ;
+ if (e==T)
+ {
+ *r= cc$rms_rab ;
+ r->rab$l_fab= f ;
+ r->rab$b_mbc= 4;
+ e= sys$connect(r) ;
+ }
+ if (e==T) e= SS$_NORMAL ;
+ return (e) ;
+}
+
+ int bopen(
+ char *fn ,
+ struct FAB *f ,
+ struct RAB *r ,
+ struct XABFHC *x ,
+ struct NAM *nam)
+{
+ int e ;
+ *f= cc$rms_fab ;
+ f->fab$b_fac= FAB$M_GET;
+ f->fab$l_fna= fn ;
+ f->fab$b_fns= strlen(fn) ;
+ f->fab$b_shr= FAB$M_SHRGET ;
+ f->fab$l_xab= x ;
+
+ *x= cc$rms_xabfhc ;
+ f->fab$l_nam = nam;
+
+ e= sys$open(f) ;
+ if (e==T)
+ {
+ *r= cc$rms_rab ;
+ r->rab$l_fab= f ;
+ r->rab$b_mbc= 4 ;
+ r->rab$b_rac= RAB$C_SEQ ;
+ r->rab$l_rop= RAB$M_RAH ;
+ e= sys$connect(r) ;
+ }
+ if (e==T) e= SS$_NORMAL ;
+ return (e) ;
+}
+
+ int breopen(
+ char *fn ,
+ struct FAB *f ,
+ struct RAB *r ,
+ struct XABFHC *x ,
+ struct NAM *nam)
+{
+ int e ;
+ *f= cc$rms_fab ;
+ f->fab$b_fac= FAB$M_GET | FAB$M_DEL ; /* Allow also delete access */
+ f->fab$l_fna= fn ;
+ f->fab$b_fns= strlen(fn) ;
+/* f->fab$b_shr= FAB$M_SHRGET ; */ /* No shared get */
+ f->fab$l_xab= x ;
+
+ *x= cc$rms_xabfhc ;
+ f->fab$l_nam = nam;
+
+ e= sys$open(f) ;
+ if (e==T)
+ {
+ *r= cc$rms_rab ;
+ r->rab$l_fab= f ;
+ r->rab$b_mbc= 4 ;
+ r->rab$b_rac= RAB$C_SEQ ;
+ r->rab$l_rop= RAB$M_RAH ;
+ e= sys$connect(r) ;
+ }
+ if (e==T) e= SS$_NORMAL ;
+ return (e) ;
+}
+
+ int bread (
+ struct RAB *r ,
+ char *p , /* user buffer address */
+ unsigned short w ) /* user buffer length in bytes */
+{
+ int e ;
+ r->rab$l_ubf= p ;
+ r->rab$w_usz= w ;
+ e= sys$get(r) ;
+ if (e==T) e= SS$_NORMAL ;
+ return(e) ;
+}
+
+ int bwrite (
+ struct RAB *r ,
+ char *p ,
+ unsigned short w )
+{
+ int e ;
+ r->rab$l_rbf= p ;
+ r->rab$w_rsz= w ;
+ if ((e= sys$put(r))==T) e= SS$_NORMAL ;
+ return(e) ;
+}
diff --git a/sr_vvms/la_io.h b/sr_vvms/la_io.h
new file mode 100644
index 0000000..2f5f27d
--- /dev/null
+++ b/sr_vvms/la_io.h
@@ -0,0 +1,61 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef __LA_IO_H__
+#define __LA_IO_H__
+
+#include <rms.h>
+
+ void bclose (struct FAB *f);
+
+ void bdelete (struct FAB *f,struct XABPRO *x);
+
+ int bcreat (
+ char *fn ,
+ struct FAB *f ,
+ struct RAB *r ,
+ struct NAM *nam,
+ struct XABPRO *xab,
+ int n );
+
+ int vcreat (
+ char *fn ,
+ struct FAB *f ,
+ struct RAB *r ,
+ int n );
+
+ int bopen(
+ char *fn ,
+ struct FAB *f ,
+ struct RAB *r ,
+ struct XABFHC *x ,
+ struct NAM *nam);
+
+ int breopen(
+ char *fn ,
+ struct FAB *f ,
+ struct RAB *r ,
+ struct XABFHC *x ,
+ struct NAM *nam);
+
+ int bread (
+ struct RAB *r ,
+ char *p , /* user buffer address */
+ unsigned short w ); /* user buffer length in bytes */
+
+ int bwrite (
+ struct RAB *r ,
+ char *p ,
+ unsigned short w );
+
+int vcreat(char *fn, struct FAB *f, struct RAB *r, int n);
+
+#endif
diff --git a/sr_vvms/la_listpak.c b/sr_vvms/la_listpak.c
new file mode 100644
index 0000000..55ec84e
--- /dev/null
+++ b/sr_vvms/la_listpak.c
@@ -0,0 +1,132 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* la_listpak.c: lists one pak record to stdout
+ used in : la_create.c
+ */
+#include "mdef.h"
+#include <ssdef.h>
+#include <descrip.h>
+#include "gtm_string.h"
+#include "ladef.h"
+
+void la_listpak (char *q)
+/* q - buffer with the pak record */
+{
+
+ pak *p ; /* pak record */
+ int4 *psid ; /* pak SIDs */
+ int4 *pnid ; /* pak NIDs */
+ char *padr ; /* pak address */
+ char *pcom ; /* pak comment */
+
+ int4 fao[16] ; /* fao arguments */
+ int k ;
+ char buf[32] ; /* model name buffer */
+ short w ; /* model name length */
+
+ error_def(LA_HEAD) ; /* Listing header */
+ error_def(LA_NAM) ; /* Product */
+ error_def(LA_VER) ; /* Version */
+ error_def(LA_X) ; /* License value */
+ error_def(LA_UNLX) ; /* Unlimited license */
+ error_def(LA_T0) ; /* Date available */
+ error_def(LA_T1) ; /* Date expires */
+ error_def(LA_UNLT0) ; /* Date unlimited */
+ error_def(LA_UNLT1) ; /* Date unlimited */
+ error_def(LA_LID) ; /* License ID */
+ error_def(LA_L) ; /* Number of systems */
+ error_def(LA_SID) ; /* Hardware model */
+ error_def(LA_UNSID) ; /* Hardware no limit.*/
+ error_def(LA_CUST) ; /* Customer name */
+ error_def(LA_ADR) ; /* Address line !SL */
+ error_def(LA_COM) ; /* Comment */
+ error_def(LA_CS) ; /* Check sum */
+ error_def(LA_STD) ; /* Creation date */
+ error_def(LA_OID) ; /* Operator ID */
+
+ p= q ;
+ psid= q + p->ph.l[3] ;
+ pnid= q + p->ph.l[4] ;
+ padr= q + p->ph.l[5] ;
+ pcom= q + p->ph.l[6] ;
+
+ la_putmsgu(LA_HEAD,0,0) ;
+
+ fao[0]= strlen(p->pd.nam) ; fao[1]= (p->pd.nam) ;
+ la_putmsgu(LA_NAM,fao,2) ;
+ fao[0]= strlen(p->pd.ver) ; fao[1]= (p->pd.ver) ;
+ la_putmsgu(LA_VER,fao,2) ;
+ if (p->pd.x!=0) /* job limited license */
+ {
+ la_putmsgu(LA_X,&(p->pd.x),1) ;
+ }
+ else /* unlimited license */
+ {
+ la_putmsgu(LA_UNLX,0,0) ;
+ }
+ if (p->pd.t0[1]!=0) /* available date given */
+ {
+ fao[0]= &(p->pd.t0) ;
+ la_putmsgu(LA_T0,fao,1) ;
+ }
+ else /* date not given */
+ {
+ la_putmsgu(LA_UNLT0,0,0) ;
+ }
+ if (p->pd.t1[1]!=0) /* available date given */
+ {
+ fao[0]= &(p->pd.t1) ;
+ la_putmsgu(LA_T1,fao,1) ;
+ }
+ else /* date not given */
+ {
+ la_putmsgu(LA_UNLT1,0,0) ;
+ }
+ la_putmsgu(LA_LID,&(p->pd.lid),1) ;
+ la_putmsgu(LA_L,&(p->pd.L),1) ;
+ for (k= 0;k!=(p->pd.L);k++)
+ {
+ if (psid[k]==0)
+ {
+ fao[0]= k ;
+ la_putmsgu(LA_UNSID,fao,1) ;
+ }
+ else
+ {
+ w= la_mdl2nam(buf,psid[k]) ;
+ fao[0]= k ; fao[1]= w ; fao[2]= buf ;
+ la_putmsgu(LA_SID,fao,3) ;
+ }
+ }
+ fao[0]= strlen(padr) ; fao[1]= padr ;
+ la_putmsgu(LA_CUST,fao,2) ;
+ for (k= 1;k!=5;k++)
+ {
+ padr= padr + strlen(padr) + 1 ;
+ fao[0]= k ;
+ fao[1]= strlen(padr) ; fao[2]= padr ;
+ la_putmsgu(LA_ADR,fao,3) ;
+ }
+ fao[0]= strlen(pcom) ; fao[1]= pcom ;
+ la_putmsgu(LA_COM,fao,2) ;
+ fao[0]= p->ph.n ;
+ fao[1]= fao[3]= fao[5]= fao[7]= 4 ;
+ fao[2]= p->ph.cs ;
+ fao[4]= p->ph.cs + 4 ;
+ fao[6]= p->ph.cs + 8 ;
+ fao[8]= p->ph.cs + 12 ;
+ la_putmsgu(LA_CS,fao,9) ;
+ fao[0]= &(p->pf.std) ;
+ la_putmsgu(LA_STD,fao,1) ;
+ fao[0]= strlen(p->pf.oid) ; fao[1]= (p->pf.oid) ;
+ la_putmsgu(LA_OID,fao,2) ;
+}
diff --git a/sr_vvms/la_maint.c b/sr_vvms/la_maint.c
new file mode 100644
index 0000000..91da55f
--- /dev/null
+++ b/sr_vvms/la_maint.c
@@ -0,0 +1,126 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* la_maint.c : License Adm. function completing maintenance commands */
+
+#include "mdef.h"
+#include <climsgdef.h>
+#include <ssdef.h>
+#include <descrip.h>
+#include <rms.h>
+#include "ladef.h"
+#include "la_io.h"
+#include "la_writepak.h"
+
+#define B (e==CLI$_NORMAL||e==SS$_NORMAL)
+#define OK (rep[0]=='Y' || rep[0]=='T' || rep[0]=='1')
+#define QUIT (rep[0]=='Q')
+
+int la_maint (void)
+{
+ int4 cli$get_getvalue();
+
+ error_def(LA_NOCNFDB) ;
+ error_def(LA_VOID) ;
+ error_def(LA_VOIDED) ;
+ error_def(LA_EMPTY) ;
+ int e ;
+ unsigned short w ;
+ bool voi,cli; /* a license voided */
+ char com[64] ; /* command */
+ char io[64]= "PAK.LIS" ; /* io file name */
+ char rep[64] ; /* reply */
+
+ $DESCRIPTOR (dentv,"$VERB");
+ $DESCRIPTOR (dcom,com);
+ $DESCRIPTOR (denti,"io");
+ $DESCRIPTOR (dio,io);
+
+ uint4 kid ; /* virt. keyb. ID */
+
+ la_prolog *prol; /* db prolog */
+ char *h ; /* data base */
+ pak *p ; /* pak record */
+ pak q[PBUF] ; /* pak pattern */
+ int v[32] ; /* qualif. variables */
+ int n,k ; /* pak rec count */
+ struct FAB f ;
+ struct RAB r ;
+
+ e= smg$create_virtual_keyboard(&kid) ; if (!B) lib$signal(e) ;
+ e= cli$get_value(&dentv,&dcom,&w) ; if (!B) lib$signal(e) ;
+ com[w]= 0;
+
+ cli = la_getcli(v,q) ;
+ denti.dsc$w_length= 2 ;
+ e= cli$present(&denti) ;
+ if B
+ {
+ e= cli$get_value(&denti,&dio,&w);
+ io[w]= 0;
+ }
+ la_puthead(q) ; /* pak pattern filled in */
+ if ((h= la_getdb(LADB))==NULL)
+ {
+ lib$signal(LA_NOCNFDB) ;
+ }
+ prol= h ;
+ p= h + SIZEOF(la_prolog) ;
+
+ if ((com[0]=='S')||(com[0]=='s')) {
+ $DESCRIPTOR (head1, "PAK # Product Created on Created by Customer name");
+ $DESCRIPTOR (head2, "----- ------- ----------- ------------ -------------------------------------");
+ lib$put_output (&head1);
+ lib$put_output (&head2);
+ }
+
+ n= 0 ;
+ voi= FALSE ;
+ rep[0]= 0 ;
+ while (n != prol->N && !QUIT)
+ {
+ if ((!cli && n==prol->N-1) || (cli && la_match(p,q,v)))
+ {
+ switch ((com[0]>='a' ? com[0]-32 : com[0]))
+ {
+ case 'L' : la_listpak(p) ;
+ break ;
+ case 'P' : e= vcreat(io,&f,&r,0) ; if (!B) lib$signal(e) ;
+ la_writepak(&r,p) ;
+ bclose(&f) ;
+ break ;
+ case 'S' : la_showpak(p);
+ break;
+ case 'V' : la_listpak(p) ;
+ la_putmsgu(LA_EMPTY, 0, 0);
+ rep[0]= 0 ;
+ la_getstr(kid,LA_VOID,rep,0,32) ;
+ rep[0]= (rep[0]>='a' ? rep[0]-32 : rep[0]) ;
+ if (OK)
+ {
+ for (k= 0;k!=16;k++) p->ph.cs[k]= '0' ;
+ la_putmsgu(LA_VOIDED,0,0) ;
+ voi= TRUE ;
+ }
+ break ;
+ otherwise: ;
+ }
+ }
+ n++ ;
+ p = (char *)p + p->ph.l[0] ;
+ }
+ if (voi)
+ {
+ la_putdb(LADB,h) ;
+ }
+ la_freedb(h) ;
+ return e ;
+}
diff --git a/sr_vvms/la_match.c b/sr_vvms/la_match.c
new file mode 100644
index 0000000..5da0ae3
--- /dev/null
+++ b/sr_vvms/la_match.c
@@ -0,0 +1,92 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <ssdef.h>
+#include <strdef.h>
+#include <descrip.h>
+
+#include "gtm_string.h"
+#include "ladef.h"
+#include "gtm_caseconv.h"
+
+/* la_match.c: for two paks pak_ptr0, pak_ptr1 and array of qualified variables computes
+ true of "pak pak_ptr0 matches the pattern pak_ptr1" on qualified variables
+ used in : la_maint.c
+*/
+#define point(a, b) { a[v_n] = &(b->ph.n); a[v_cs] = b->ph.cs; a[v_l] = b->ph.l;\
+ a[v_std] = &(b->pf.std[1]); a[v_oid] = b->pf.oid; a[v_L] = &(b->pd.L);\
+ a[v_nam] = b->pd.nam; a[v_ver] = b->pd.ver; a[v_x] = &(b->pd.x);\
+ a[v_t0] = &(b->pd.t0[1]); a[v_t1] = &(b->pd.t1[1]); a[v_lid] = &(b->pd.lid);\
+ a[v_sid] = (char *)b + b->ph.l[3]; \
+ a[v_nid] = (char *)b + b->ph.l[4]; \
+ a[v_adr] = (char *)b + b->ph.l[5]; \
+ a[v_com] = (char *)b + b->ph.l[6]; }
+
+bool la_match(pak *pak_ptr0, pak *pak_ptr1, int v_arr[])
+/* pak_ptr0 - pak */
+/* pak_ptr1 - pak pattern */
+/* v_arr - qualified variables */
+{
+ bool match;
+ char *padr; /* address lines */
+ char *ppt[16]; /* pointers to pak variables */
+ char *qpt[16]; /* pointers to pattern var */
+ char *can; /* string to match */
+ char *pat = NULL; /* match pattern */
+ char buf[128];
+ short cnt;
+ int4 str$match_wild();
+ int4 status;
+ varid var; /* variable ident (enum type) */
+ VARTYP (type); /* variable type - ladef */
+ $DESCRIPTOR(dpat, pat);
+ $DESCRIPTOR(dbuf, buf);
+
+ point(ppt, pak_ptr0);
+ point(qpt, pak_ptr1);
+ var = v_n;
+ match = ('0' != pak_ptr0->ph.cs[0]) || (1 == v_arr[v_cs]);
+ while ((var != eovar) && match)
+ {
+ if (1 == v_arr[var])
+ {
+ switch (type[var])
+ {
+ case str: dpat.dsc$a_pointer = qpt[var];
+ dpat.dsc$w_length = (short)strlen(qpt[var]);
+ dbuf.dsc$w_length = cnt = strlen(ppt[var]);
+ lower_to_upper(buf, ppt[var], cnt);
+ match = STR$_MATCH == str$match_wild(&dbuf, &dpat);
+ break;
+ case sho: match = *(short *)ppt[var] == *(short *)qpt[var];
+ break;
+ case lon: match = *(int4 *)ppt[var] == *(int4 *)qpt[var];
+ break;
+ case hex: match = *(int4 *)ppt[var] == *(int4 *)qpt[var];
+ break;
+ case dat: match = *(uint4 *)ppt[var] >= *(uint4 *)qpt[var] || (0 == *(int4 *)ppt[var]);
+ break;
+ case lst: match = FALSE;
+ for (cnt = 0; !match && (cnt < pak_ptr0->pd.L); cnt++)
+ {
+ match = *(int4 *)ppt[var] == *(int4 *)qpt[var];
+ ppt[var] += SIZEOF(int4);
+ }
+ break;
+ otherwise: break;
+ }
+ }
+ var++;
+ }
+ return match;
+}
diff --git a/sr_vvms/la_mdl2nam.c b/sr_vvms/la_mdl2nam.c
new file mode 100644
index 0000000..fb645da
--- /dev/null
+++ b/sr_vvms/la_mdl2nam.c
@@ -0,0 +1,75 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* la_mdl2nam.c : hardware model converted to hardware name
+ used in : la_edit.c, lm_edit.c, la_listpak.c, lm_listpak.c
+*/
+#include "mdef.h"
+#include "ladef.h"
+
+#define HWSIZ 185
+typedef struct
+{
+ char nam[HWLEN];
+} hw_model;
+
+readonly hw_model hw_name[HWSIZ] =
+ { "\0", "V780", "V782", "V750", "V730", "V785", "VUV1", "VWS1", "VUV2", "VWS2", "VWSD", "V8600", "V8650", "V8200", "V8300",
+ "V8530", "V8550", "V8700", "V8800", "VWS2000", "VUV2000", "VWSD2000", "V009", "V8250", "V8350", "V3600", "V3600W",
+ "V3600D", "V6210", "V3820", "V3520L", "V8840", "V9RR", "VUV2_S", "VUV2_J", "VWS2_T", "VWS2_J", "VWSD_T", "VWSD_J",
+ "VUV2000_S", "VUV2000_J", "VWS2000_T", "VWS2000_J", "VWSD2000_T", "VWSD2000_J", "V3600_S", "V3600_J", "V3600W_T",
+ "V3600W_J", "V3600D_T", "V3600D_J", "V3820_S", "V3820_J", "V3820L_T", "V3520L_J", "V8250L", "V8250L_J", "VCV", "VCVWS",
+ "VCVWSD", "VCV_S", "VCV_J", "VCVWS_T", "VCVWS_J", "VCVWSD_T", "VCVWSD_J", "V8500", "V8370", "V8650P", "V6220", "V6230",
+ "V6240", "V6250", "V6260", "V6270", "V6280", "V6215", "V6225", "V6235", "V6245", "V6255", "V6265", "V6275", "V6285",
+ "V8810", "V8820", "V8830", "V3400", "V3400W", "V3400D", "V3400_S", "V3400_J", "V3400W_T", "V3400W_J", "V3400D_T",
+ "V3400D_J", "VUV2000_O", "VWS2000_O", "VWSD2000_O", "VWSK2000", "V6210_S", "V6220_S", "V6230_S", "V6240_S", "V6250_S",
+ "V6260_S", "V6270_S", "V6280_S", "V6310_S", "V6320_S", "V6330_S", "V6340_S", "V6350_S", "V6360_S", "V6370_S", "V6380_S",
+ "V6200_J", "V6300_J", "V3900", "V3900_S", "V3900D", "V3900D_T", "V3900_J", "V3900D_J", "V2000A", "V2000A_S", "V2000AW",
+ "V2000AD", "V2000AW_T", "V2000AD_T", "V2000A_J", "V2000AW_J", "V2000AD_J", "V3840", "V3840_S", "V3540L", "V3840L_T",
+ "V3860", "V3860_S", "V3560L", "V3860L_T", "V3880", "V3880_S", "V3580L", "V3880L_T", "V38A0", "V38A0_S", "VPV", "VPVWS",
+ "VPVWSD", "VPV_S", "VPV_J", "VPVWS_T", "VPVWS_J", "VPVWSD_T", "VPVWSD_J", "VTM", "VTM_S", "VTM_J", "V9RR10_T", "V9RR20_T",
+ "V9RR30_T", "V9RR40_T", "V9RR50_T", "V9RR60_T", "V9RR70_T", "V9RR80_T", "V9RR10_S", "V9RR20_S", "V9RR30_S", "V9RR40_S",
+ "V9RR50_S", "V9RR60_S", "V9RR70_S", "V9RR80_S", "V9RR10_J", "Vxxx10", "Vxxx20", "Vyyy10", "Vyyy20", "Vyyy30", "Vyyy40",
+ "V6305E_T", "V6305E_S", "V6305E_J" };
+
+short la_mdl2nam (nam,mdl)
+char nam[] ; /* returns - hw. name */
+int4 mdl ; /* hw. model */
+{
+ int k ;
+ short w ;
+ static readonly char x[17] = "0123456789ABCDEF" ;
+
+ if (mdl>=HWSIZ)
+ {
+ nam[0] = '0' ; nam[1] = 'x' ;
+ k = 8 ;
+ while (k!=0)
+ {
+ k-- ;
+ nam[k+2] = x[mdl%16] ;
+ mdl = mdl>>4 ;
+ }
+ w = 10 ;
+ }
+ else
+ {
+ k = mdl;
+ w = 0 ;
+ while (hw_name[k].nam[w]!=0)
+ {
+ nam[w] = hw_name[k].nam[w] ;
+ w++ ;
+ }
+ }
+ nam[w] = 0 ;
+ return w ;
+}
diff --git a/sr_vvms/la_nam2mdl.c b/sr_vvms/la_nam2mdl.c
new file mode 100644
index 0000000..802d8a7
--- /dev/null
+++ b/sr_vvms/la_nam2mdl.c
@@ -0,0 +1,98 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* la_nam2mdl.c : hardware name converted to hardware model
+ used in : la_edit.c, lm_edit.c
+*/
+#include "mdef.h"
+#include "ladef.h"
+
+#define HWSIZ 212
+typedef struct
+{
+ char nam[HWLEN] ; /* model name */
+ short mdl ; /* hardware model */
+} hw_model ;
+readonly hw_model hw[HWSIZ]=
+ {{"\0",0},
+ {"V780", 1}, {"V782", 2}, {"V750", 3}, {"V730", 4}, {"V785", 5},
+ {"VUV1", 6}, {"VWS1", 7}, {"VUV2", 8}, {"VWS2", 9}, {"VWSD", 10},
+ {"V8600", 11}, {"V8650", 12}, {"V8200", 13}, {"V8300", 14}, {"V8530", 15},
+ {"V8550", 16}, {"V8700", 17}, {"V8800", 18}, {"VWS2000", 19}, {"VUV2000", 20},
+ {"VWSD2000", 21}, {"V009", 22}, {"V8250", 23}, {"V8350", 24}, {"V3600", 25},
+ {"V3600W", 26}, {"V3600D", 27}, {"V9CC", 28}, {"V6210_T", 28}, {"V6210", 28},
+ {"V3820", 29}, {"V3520L", 30}, {"V8PS", 31}, {"V8840", 31}, {"V9RR", 32},
+ {"VUV2_S", 33}, {"VUV2_J", 34}, {"VWS2_T", 35}, {"VWS2_J", 36}, {"VWSD_T", 37},
+ {"VWSD_J", 38}, {"VUV2000_S", 39}, {"VUV2000_J", 40}, {"VWS2000_T", 41}, {"VWS2000_J", 42},
+ {"VWSD2000_T", 43}, {"VWSD2000_J", 44}, {"V3600_S", 45}, {"V3600_J", 46}, {"V3600W_T", 47},
+ {"V3600W_J", 48}, {"V3600D_T", 49}, {"V3600D_J", 50}, {"V3820_S", 51}, {"V3820_J", 52},
+ {"V3820L_T", 53}, {"V3520L_J", 54}, {"V8250L", 55}, {"V8250L_J", 56}, {"VCV", 57},
+ {"VCVWS", 58}, {"VCVWSD", 59}, {"VCV_S", 60}, {"VCV_J", 61}, {"VCVWS_T", 62},
+ {"VCVWS_J", 63}, {"VCVWSD_T", 64}, {"VCVWSD_J", 65}, {"V8500", 66}, {"V8370", 67},
+ {"V8650P", 68}, {"V6220_T", 69}, {"V6220", 69}, {"V6230_T", 70}, {"V6230", 70},
+ {"V6240_T", 71}, {"V6240", 71}, {"V6250_T", 72}, {"V6250", 72}, {"V6260_T", 73},
+ {"V6260", 73}, {"V6270_T", 74}, {"V6270", 74}, {"V6280_T", 75}, {"V6280", 75},
+ {"V6310_T", 76}, {"V6215", 76}, {"V6320_T", 77}, {"V6225", 77}, {"V6330_T", 78},
+ {"V6235", 78}, {"V6340_T", 79}, {"V6245", 79}, {"V6350_T", 80}, {"V6255", 80},
+ {"V6360_T", 81}, {"V6265", 81}, {"V6370_T", 82}, {"V6275", 82}, {"V6380_T", 83},
+ {"V6285", 83}, {"V8810", 84}, {"V8820", 85}, {"V8830", 86}, {"V3400", 87},
+ {"V3400W", 88}, {"V3400D", 89}, {"V3400_S", 90}, {"V3400_J", 91}, {"V3400W_T", 92},
+ {"V3400W_J", 93}, {"V3400D_T", 94}, {"V3400D_J", 95}, {"VUV2000_O", 96}, {"VWS2000_O", 97},
+ {"VWSD2000_O", 98}, {"VWSK2000", 99}, {"V6210_S", 100}, {"V6220_S", 101}, {"V6230_S", 102},
+ {"V6240_S", 103}, {"V6250_S", 104}, {"V6260_S", 105}, {"V6270_S", 106}, {"V6280_S", 107},
+ {"V6310_S", 108}, {"V6215_S", 108}, {"V6320_S", 109}, {"V6225_S", 109}, {"V6330_S", 110},
+ {"V6235_S", 110}, {"V6340_S", 111}, {"V6245_S", 111}, {"V6350_S", 112}, {"V6255_S", 112},
+ {"V6360_S", 113}, {"V6265_S", 113}, {"V6370_S", 114}, {"V6275_S", 114}, {"V6380_S", 115},
+ {"V6285_S", 115}, {"V6200_J", 116}, {"V6300_J", 117}, {"V6205_J", 117}, {"V3900", 118},
+ {"V3900_S", 119}, {"V3900D", 120}, {"V3900D_T", 121}, {"V3900_J", 122}, {"V3900D_J", 123},
+ {"V2000A", 124}, {"V2000A_S", 125}, {"V2000AW", 126}, {"V2000AD", 127}, {"V2000AW_T", 128},
+ {"V2000AD_T", 129}, {"V2000A_J", 130}, {"V2000AW_J", 131}, {"V2000AD_J", 132}, {"V3840", 133},
+ {"V3840_S", 134}, {"V3540L", 135}, {"V3840L_T", 136}, {"V3860", 137}, {"V3860_S", 138},
+ {"V3560L", 139}, {"V3860L_T", 140}, {"V3880", 141}, {"V3880_S", 142}, {"V3580L", 143},
+ {"V3880L_T", 144}, {"V38A0", 145}, {"V38A0_S", 146}, {"VPV", 147}, {"VPVWS", 148},
+ {"VPVWSD", 149}, {"VPV_S", 150}, {"VPV_J", 151}, {"VPVWS_T", 152}, {"VPVWS_J", 153},
+ {"VPVWSD_T", 154}, {"VPVWSD_J", 155}, {"VTM", 156}, {"VTM_S", 157}, {"VTM_J", 158},
+ {"V9RR10_T", 159}, {"V9RR20_T", 160}, {"V9RR30_T", 161}, {"V9RR40_T", 162}, {"V9RR50_T", 163},
+ {"V9RR60_T", 164}, {"V9RR70_T", 165}, {"V9RR80_T", 166}, {"V9RR10_S", 167}, {"V9RR20_S", 168},
+ {"V9RR30_S", 169}, {"V9RR40_S", 170}, {"V9RR50_S", 171}, {"V9RR60_S", 172}, {"V9RR70_S", 173},
+ {"V9RR80_S", 174}, {"V9RR10_J", 175}, {"Vxxx10", 176}, {"Vxxx20", 177}, {"Vyyy10", 178},
+ {"Vyyy20", 179}, {"Vyyy30", 180}, {"Vyyy40", 181}, {"V6305E_T", 182}, {"V6305E_S", 183},
+ {"V6305E_J", 184}};
+
+bool la_nam2mdl (
+int4 *mdl , /* returns - hw. model */
+short w , /* nam length */
+char nam[] ) /* hardware name */
+{
+ int k,j ;
+ bool match ;
+
+ if (w>=2 && nam[0]=='0' && nam[1]=='X' ) /* name is hex number */
+ {
+ match = lib$cvt_htb((int4)(w-2),nam+2,mdl) ;
+ }
+ else /* name is string V... */
+ {
+ match = (w==0) ; k = 1 ;
+ while (!match && k!=HWSIZ)
+ {
+ j = 0 ;
+ while (j!=w && hw[k].nam[j]==nam[j])
+ {
+ j++ ;
+ }
+ match = ((j==w) && (hw[k].nam[w]==0)) ;
+ k++ ;
+ }
+ *mdl = hw[k-1].mdl ;
+ }
+ return match ;
+}
diff --git a/sr_vvms/la_putdb.c b/sr_vvms/la_putdb.c
new file mode 100644
index 0000000..18ae687
--- /dev/null
+++ b/sr_vvms/la_putdb.c
@@ -0,0 +1,71 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* la_putdb : stores entire license data base from the main store back in db file */
+
+#include "mdef.h"
+#include <ssdef.h>
+#include <descrip.h>
+#include <rms.h>
+#include "ladef.h"
+#include "la_io.h"
+
+#define B (e==SS$_NORMAL || e==RMS$_NORMAL)
+
+ void la_putdb (char *fn,char *h)
+/* fn - data base file name */
+/* h - data base */
+{
+ struct FAB f,fd ; /* file access block */
+ struct RAB r,rd ; /* record access block */
+ struct XABFHC x ; /* file header */
+ struct NAM nam, nam2;
+ struct XABPRO xab, xab2;
+
+ int sys$erase() ;
+
+ int e,len ;
+ la_prolog *prol ; /* data base prolog */
+ char *p ;
+
+ nam2 = cc$rms_nam;
+ breopen(fn,&fd,&rd,&x,&nam2); /* this should actually be "reopen" */
+ nam = cc$rms_nam;
+ e= bcreat(fn,&f,&r,&nam,&xab,ALOC) ; if (!B) lib$signal(e) ;
+ if B
+ {
+ p= prol= h ;
+ len= prol->len ; /* file length in bytes */
+ while (B && len>0 )
+ {
+ e = bwrite(&r,p,BLKS) ;
+ p += BLKS ;
+ len -= BLKS ;
+ }
+ bclose(&f) ;
+ if (!B)
+ {
+ lib$signal(e) ;
+ }
+ else
+ {
+#if 0
+ bdelete(&fd,&xab2,&nam2); /* delete old config file */
+#else
+ bdelete(&fd,&xab2); /* delete old config file */
+#endif
+ }
+ }
+ else
+ {
+ lib$signal(e) ;
+ }
+}
diff --git a/sr_vvms/la_putfldr.c b/sr_vvms/la_putfldr.c
new file mode 100644
index 0000000..1f0be92
--- /dev/null
+++ b/sr_vvms/la_putfldr.c
@@ -0,0 +1,38 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* la_putfldr.c : fills the pak folder in
+ used in : la_create.c
+*/
+
+#include <ssdef.h>
+#include "mdef.h"
+#include <jpidef.h>
+#include "ladef.h"
+#include <descrip.h>
+#define B (e==SS$_NORMAL)
+
+void la_putfldr ( pfldr *pf )
+{
+ $DESCRIPTOR(doid,&(pf->oid)) ;
+ int sys$gettim();
+ int e ;
+ short w ;
+ int4 item= JPI$_USERNAME ;
+
+ e= sys$gettim(&(pf->std)) ;
+ if (!B) lib$signal(e) ;
+
+ doid.dsc$w_length= 16 ;
+ e= lib$getjpi(&item,0,0,0,&doid,&w) ;
+ if B (pf->oid)[w]= 0 ;
+ else lib$signal(e) ;
+}
diff --git a/sr_vvms/la_puthead.c b/sr_vvms/la_puthead.c
new file mode 100644
index 0000000..563e076
--- /dev/null
+++ b/sr_vvms/la_puthead.c
@@ -0,0 +1,41 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* la_puthead.c : fills pak header in
+ used in : la_create.c
+*/
+#include "mdef.h"
+#include "gtm_string.h"
+#include "ladef.h"
+
+void la_puthead (p)
+pak *p ; /* pak data */
+{
+ int k,u,w ;
+ char *padr ;
+
+ p->ph.l[1]= SIZEOF(phead) ; /* offset to pfldr */
+ p->ph.l[2]= p->ph.l[1] + SIZEOF(pfldr) ; /* offset to pdata */
+ p->ph.l[3]= p->ph.l[2] + SIZEOF(pdata) ; /* offset to psid */
+ p->ph.l[4]= p->ph.l[3] + SIZEOF(int4)*(p->pd.L);/* offset to pnid */
+ p->ph.l[5]= p->ph.l[4] + SIZEOF(int4)*(p->pd.L);/* offset to padr */
+
+ padr= (char*)p + p->ph.l[5] ;
+ w= u= 0 ;
+ for (k= 0;k!=5;k++)
+ {
+ u= strlen(padr) ;
+ padr += u + 1 ;
+ w += u + 1 ;
+ }
+ p->ph.l[6]= p->ph.l[5] + w ; /* offset to pcom */
+ p->ph.l[0]= p->ph.l[6] + strlen(padr) ; /* offset to next */
+}
diff --git a/sr_vvms/la_putline.c b/sr_vvms/la_putline.c
new file mode 100644
index 0000000..a3e035d
--- /dev/null
+++ b/sr_vvms/la_putline.c
@@ -0,0 +1,32 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* la_putline : writes message supplied by sys$putmsg to file given by its RAB
+ used in : la_fputmsgu.c
+ */
+
+#include "mdef.h"
+#include <rms.h>
+#include <descrip.h>
+#include "la_io.h"
+
+int la_putline (
+ struct dsc$descriptor *line ,
+ struct RAB *rab )
+{
+ int4 status ;
+ status= bwrite(rab,line->dsc$a_pointer,line->dsc$w_length) ;
+ if ((status & 1)==0)
+ {
+ lib$signal(status) ;
+ }
+ return 0 ;
+}
diff --git a/sr_vvms/la_putline.h b/sr_vvms/la_putline.h
new file mode 100644
index 0000000..83ecfc6
--- /dev/null
+++ b/sr_vvms/la_putline.h
@@ -0,0 +1,16 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+#ifndef __LA_PUTLINE_H__
+#define __LA_PUTLINE_H__
+
+int la_putline ( struct dsc$descriptor *line , struct RAB *rab );
+
+#endif
diff --git a/sr_vvms/la_putmsgs.c b/sr_vvms/la_putmsgs.c
new file mode 100644
index 0000000..a3400e5
--- /dev/null
+++ b/sr_vvms/la_putmsgs.c
@@ -0,0 +1,27 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "msg.h"
+
+/* la_putmsgs.c : outputs the message for the system status code */
+
+ void la_putmsgs(c)
+ int c ;
+ {
+ int k,e ;
+ msgtype msgvec;
+
+ msgvec.arg_cnt = 1;
+ msgvec.def_opts = 0x000F;
+ msgvec.msg_number = c;
+ msgvec.fp_cnt = msgvec.new_opts = 0;
+ sys$putmsg(&msgvec) ;
+ }
diff --git a/sr_vvms/la_putmsgu.c b/sr_vvms/la_putmsgu.c
new file mode 100644
index 0000000..7dd7b79
--- /dev/null
+++ b/sr_vvms/la_putmsgu.c
@@ -0,0 +1,48 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* la_putmsgu.c : outputs and formats message for user message code
+ and user FAO arguments
+ */
+#include "mdef.h"
+
+#include <ssdef.h>
+
+void la_putmsgu (c, fao, n)
+int4 c ; /* message code */
+int4 fao[] ; /* fao arguments */
+short n ; /* number of fao args */
+{
+ int k, local_n;
+ struct { short argc; /* structure longword count */
+ short opt; /* message display options */
+ int4 code; /* message code */
+ short count; /* FAO count */
+ short newopt; /* new options */
+ int4 fao[16]; /* fao arguments */
+ } msgvec ;
+
+ local_n = n;
+ if (local_n < 0)
+ local_n = 0;
+ if (local_n > 15)
+ local_n = 15;
+
+ msgvec.argc = local_n + 2; /* number of longwords (excluding argc, opt) */
+ msgvec.opt = 0x0001; /* include message text; do not include mnemonic name, severity level, or facility prefix */
+ msgvec.code = c;
+ msgvec.count = local_n;
+ msgvec.newopt = msgvec.opt; /* no change */
+
+ for (k = 0; k < local_n; k++)
+ msgvec.fao[k] = fao[k];
+ sys$putmsg(&msgvec) ;
+}
diff --git a/sr_vvms/la_showpak.c b/sr_vvms/la_showpak.c
new file mode 100644
index 0000000..681b046
--- /dev/null
+++ b/sr_vvms/la_showpak.c
@@ -0,0 +1,55 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* la_showpak.c: shows pak summary to stdout
+ js / 20-sep-1989
+ */
+#include "mdef.h"
+#include <ssdef.h>
+#include <descrip.h>
+#include "gtm_string.h"
+#include "ladef.h"
+
+void la_showpak (q)
+char *q ; /* buffer with the pak record */
+{
+ pak *p ; /* pak record */
+ char *padr ; /* pak address */
+ $DESCRIPTOR(faoctl, "!5SL!AS !8AD !11%D !12AD !37AD");
+ char line[256];
+ int4 length;
+ char status[2] = " ";
+ $DESCRIPTOR(linedesc, line);
+ $DESCRIPTOR(dstatus, status);
+ int4 today, exday;
+
+ p= q ;
+ padr= q + p->ph.l[5] ;
+
+ if (p->pd.t1[1]!=0) {
+ lib$day (&today, 0);
+ lib$day (&exday, p->pd.t1);
+ if (today > exday) status[0] = '+';
+ }
+
+ if (p->ph.cs[0]=='0')
+ if (status[0]=='+')
+ status[0] = '%';
+ else
+ status[0] = '*';
+
+ sys$fao (&faoctl, &length, &linedesc, p->pd.lid, &dstatus, LEN_AND_STR(p->pd.nam), &(p->pf.std),
+ LEN_AND_STR(p->pf.oid), LEN_AND_STR(padr));
+ linedesc.dsc$w_length = length;
+ lib$put_output (&linedesc);
+
+ return;
+}
diff --git a/sr_vvms/la_store.c b/sr_vvms/la_store.c
new file mode 100644
index 0000000..45a8941
--- /dev/null
+++ b/sr_vvms/la_store.c
@@ -0,0 +1,61 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "ladef.h"
+#include "lmdef.h"
+
+#include <ssdef.h>
+#include <climsgdef.h>
+#include <descrip.h>
+
+/* la_store.c : License Administration function for creating new licenses
+ from DCL command procedures
+ used in : license_adm.c
+*/
+
+int la_store(void)
+{
+ char rp[32]; /* operator reply */
+ char *c_ptr; /* db in main store */
+ int4 status;
+ uint4 bcs[3] = {0, 0, 0};
+ int v_arr[32];
+ int toupper();
+ pak *pak_ptr; /* pak record */
+ la_prolog *prol; /* db file prolog */
+
+ error_def(LA_NOCNFDB); /* No license created */
+ error_def(LA_NEWCNF); /* New license created */
+ error_def(LA_BADENCR);
+
+ if (NULL == (c_ptr = la_getdb(LADB))) /* db in main storage */
+ lib$signal(LA_NOCNFDB);
+ prol = c_ptr;
+ pak_ptr = (char *)c_ptr + prol->len; /* place for new pak */
+ la_initpak(prol->lastid, pak_ptr); /* pak initialized */
+ la_getcli(v_arr, pak_ptr);
+ la_puthead(pak_ptr);
+ la_putfldr(&(pak_ptr->pf));
+ if (!la_encryt(pak_ptr->ph.n, &(pak_ptr->pd), (pak_ptr->ph.l[4] - pak_ptr->ph.l[2]), bcs))
+ lib$signal(LA_BADENCR);
+ else
+ la_convert(pak_ptr->ph.cs, bcs);
+ la_listpak(pak_ptr);
+ (prol->N)++; /* count of paks++ */
+ prol->len += pak_ptr->ph.l[0]; /* db file size++ */
+ prol->lastid = pak_ptr->pd.lid; /* new last license ID */
+ la_putdb(LADB, c_ptr); /* db back to file */
+ lm_putmsgu(LA_NEWCNF, 0, 0);
+ la_freedb(c_ptr);
+ return (SS$_NORMAL);
+}
diff --git a/sr_vvms/la_uniqlid.c b/sr_vvms/la_uniqlid.c
new file mode 100644
index 0000000..17f6813
--- /dev/null
+++ b/sr_vvms/la_uniqlid.c
@@ -0,0 +1,48 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* la_uniqlid.c : uniqlid == license ID is unique in the data base
+ used : la_create.c
+*/
+
+#include "mdef.h"
+#include "ladef.h"
+
+bool la_uniqlid (char *h,int4 lid)
+/*
+h - data base
+id -license ID
+*/
+{
+
+ error_def(LA_NOTUNIQ) ;
+ bool unique ;
+ int n ;
+ la_prolog *prol; /* db prolog */
+ pak *p ; /* pak record */
+
+ prol= h ;
+ p= h + SIZEOF(la_prolog) ;
+
+ n= 0 ;
+ unique= TRUE ;
+ while (unique && n!=prol->N)
+ {
+ unique= (p->pd.lid!=lid) ;
+ n++ ;
+ p = (char *)p + p->ph.l[0] ;
+ }
+ if (!unique)
+ {
+ la_putmsgu(LA_NOTUNIQ,0,0) ;
+ }
+ return(unique);
+}
diff --git a/sr_vvms/la_validate.c b/sr_vvms/la_validate.c
new file mode 100644
index 0000000..cdf3c35
--- /dev/null
+++ b/sr_vvms/la_validate.c
@@ -0,0 +1,65 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* la_validate.c: valid == 'val is in the message string given by code'
+ used in : la_edit.c
+*/
+
+#include "mdef.h"
+#include <ssdef.h>
+#include "ladef.h"
+#include <descrip.h>
+#include "gtm_string.h"
+#define B (e==SS$_NORMAL)
+
+bool la_validate (int4 code,char *val)
+/*
+int4 code ; mes. code for validation str
+char *val ; validated value
+*/
+{
+ int sys$getmsg() ;
+
+ error_def(LA_CHOOSE) ; /* Choose a value from the list */
+ char buf[256] ; /* list of valid values */
+ $DESCRIPTOR(dbuf,buf) ;
+
+ unsigned short w ; /* res. string length */
+ int e,k,n,len ;
+ bool valid,prop ;
+
+ dbuf.dsc$w_length= 256 ;
+ e= sys$getmsg(code,&w,&dbuf,1,0) ; if (!B) lib$signal(e) ;
+
+ len= strlen(val) ;
+ n= 0 ; prop= TRUE ; valid= (n==len) ;
+ while(!valid && n<w)
+ {
+ if (prop)
+ {
+ k= 0 ; valid= TRUE ;
+ while(valid && n!=w && buf[n]!=',')
+ {
+ valid= (buf[n]==val[k]) ;
+ n++ ; k++ ;
+ }
+ valid= (valid && k==len) ;
+ }
+ prop= (buf[n]==',') ;
+ n++ ;
+ }
+ if (!valid)
+ {
+ la_putmsgu(LA_CHOOSE,0,0) ;
+ la_putmsgu(code,0,0) ;
+ }
+ return(valid) ;
+}
diff --git a/sr_vvms/la_writepak.c b/sr_vvms/la_writepak.c
new file mode 100644
index 0000000..354f8a2
--- /dev/null
+++ b/sr_vvms/la_writepak.c
@@ -0,0 +1,153 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* la_writepak.c: writes a pak record to a file
+ used in : la_maint.c
+ */
+
+#include "mdef.h"
+#include <rms.h>
+#include "gtm_string.h"
+#include "ladef.h"
+#include "la_fputmsgu.h"
+#include "la_writepak.h"
+
+void la_writepak (struct FAB *f,pak *p)
+/*
+struct FAB *f ; output file
+pak *p ; pak record
+*/
+{
+
+ int4 *psid ; /* pak SIDs */
+ int4 *pnid ; /* pak NIDs */
+ char *padr ; /* pak address */
+ char *pcom ; /* pak comment */
+
+ int4 fao[16] ; /* fao arguments */
+ int4 mdl ;
+ int k, j ;
+ short w ;
+ char buf[32] ;
+ char hex[8] ; /* hex version of hw. mdl */
+ static readonly char x[17] = "0123456789ABCDEF" ;
+
+ error_def(LA_NAM) ; /* Product */
+ error_def(LA_VER) ; /* Version */
+ error_def(LA_X) ; /* License value */
+ error_def(LA_PX) ; /* Unlimited license */
+ error_def(LA_T0) ; /* Date available */
+ error_def(LA_T1) ; /* Date expires */
+ error_def(LA_PT0) ; /* Date available */
+ error_def(LA_PT1) ; /* Date expires */
+ error_def(LA_LID) ; /* License ID */
+ error_def(LA_L) ; /* Number of systems */
+ error_def(LA_SIDX) ; /* Hw mdl, with hex */
+ error_def(LA_PSID) ; /* Hw mdl. unlimited */
+ error_def(LA_CS) ; /* Check sum */
+
+ error_def(LA_PAKHD) ; /* PAK header */
+ error_def(LA_ISSUR) ; /* Issuer name, addr */
+ error_def(LA_ISSUE) ; /* headings */
+ error_def(LA_ISSDT) ; /* Issue date */
+ error_def(LA_ISADR) ; /* Customer name,adr */
+ error_def(LA_DELIM) ; /* page delimiter */
+ error_def(LA_EMPTY) ; /* empty line */
+
+ psid= (char *)p + p->ph.l[3] ;
+ pnid= (char *)p + p->ph.l[4] ;
+ padr= (char *)p + p->ph.l[5] ;
+
+ la_fputmsgu(f,LA_PAKHD,0,0) ;
+ la_fputmsgu(f,LA_ISSUR,0,0) ;
+ la_fputmsgu(f,LA_ISSUE,0,0) ;
+ fao[0]= 0 ; /* outputs current time */
+ fao[0] = &(p->pf.std);
+ la_fputmsgu(f,LA_ISSDT,fao,1) ;
+
+ for (k= 0;k!=5;k++)
+ {
+ fao[0]= strlen(padr) ; fao[1]= padr ;
+ la_fputmsgu(f,LA_ISADR,fao,3) ;
+ padr= padr + strlen(padr) + 1 ;
+ }
+ la_fputmsgu(f,LA_DELIM,0,0) ;
+
+ fao[0]= strlen(p->pd.nam) ; fao[1]= (p->pd.nam) ;
+ la_fputmsgu(f,LA_NAM,fao,2) ;
+ la_fputmsgu(f,LA_EMPTY,0,0) ;
+ fao[0]= strlen(p->pd.ver) ; fao[1]= (p->pd.ver) ;
+ la_fputmsgu(f,LA_VER,fao,2) ;
+ la_fputmsgu(f,LA_EMPTY,0,0) ;
+ if (p->pd.x!=0) /* job limited license */
+ {
+ la_fputmsgu(f,LA_X,&(p->pd.x),1) ;
+ }
+ else /* unlimited license */
+ {
+ la_fputmsgu(f,LA_PX,0,0) ;
+ }
+ la_fputmsgu(f,LA_EMPTY,0,0) ;
+ if (p->pd.t0[1]!=0) /* available date given */
+ {
+ fao[0]= &(p->pd.t0) ;
+ la_fputmsgu(f,LA_T0,fao,1) ;
+ }
+ else /* date not given */
+ {
+ la_fputmsgu(f,LA_PT0,0,0) ;
+ }
+ la_fputmsgu(f,LA_EMPTY,0,0) ;
+ if (p->pd.t1[1]!=0) /* available date given */
+ {
+ fao[0]= &(p->pd.t1) ;
+ la_fputmsgu(f,LA_T1,fao,1) ;
+ }
+ else /* date not given */
+ {
+ la_fputmsgu(f,LA_PT1,0,0) ;
+ }
+ la_fputmsgu(f,LA_EMPTY,0,0) ;
+ la_fputmsgu(f,LA_LID,&(p->pd.lid),1) ;
+ la_fputmsgu(f,LA_EMPTY,0,0) ;
+ la_fputmsgu(f,LA_L,&(p->pd.L),1) ;
+ la_fputmsgu(f,LA_EMPTY,0,0) ;
+ for (k= 0;k!=(p->pd.L);k++)
+ {
+ if (psid[k]==0)
+ {
+ fao[0] = k ;
+ la_fputmsgu(f,LA_PSID,fao,1) ;
+ }
+ else
+ { mdl = psid[k] ;
+ w = la_mdl2nam(buf,mdl) ;
+ j = 8 ;
+ while (mdl!=0)
+ {
+ hex[--j] = x[mdl%16] ;
+ mdl >>=4 ;
+ }
+ fao[0] = k ;
+ fao[1] = w ; fao[2] = buf ;
+ fao[3] = 8 - j ; fao[4] = hex+j ;
+ la_fputmsgu(f,LA_SIDX,fao,5) ;
+ }
+ }
+ la_fputmsgu(f,LA_EMPTY,0,0) ;
+ fao[0]= p->ph.n ;
+ fao[1]= fao[3]= fao[5]= fao[7]= 4 ;
+ fao[2]= p->ph.cs ;
+ fao[4]= p->ph.cs + 4 ;
+ fao[6]= p->ph.cs + 8 ;
+ fao[8]= p->ph.cs + 12 ;
+ la_fputmsgu(f,LA_CS,fao,9) ;
+}
diff --git a/sr_vvms/la_writepak.h b/sr_vvms/la_writepak.h
new file mode 100644
index 0000000..6a6f47b
--- /dev/null
+++ b/sr_vvms/la_writepak.h
@@ -0,0 +1,16 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+#ifndef __LA_WRITEPAK_H__
+#define __LA_WRITEPAK_H__
+
+void la_writepak (struct FAB *f,pak *p);
+
+#endif
diff --git a/sr_vvms/ladef.h b/sr_vvms/ladef.h
new file mode 100644
index 0000000..78c85d2
--- /dev/null
+++ b/sr_vvms/ladef.h
@@ -0,0 +1,133 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* ladef.h - license administration structures */
+#include "mdef.h"
+#include <rms.h>
+
+#define DBID 0x0000FFFF /* data base file ID */
+#define LADB "GTM$LADB" /* license adm. data base name */
+#define LMDB "GTM$CNFDB" /* license man. data base name */
+#define LAHP "GTM$HELP:LA" /* license adm. help file */
+#define LMHP "GTM$HELP:LMU" /* license man. help file */
+#define LMLK "GTM$LM" /* license n. lock resource */
+#define LAFILE "GTM$ROOT:[CUS]LA.DAT" /* default adm. db file */
+#define LMFILE "GTM$DIST:GTC.CNF" /* default man. db file */
+#define BLKS 512 /* db file record size */
+#define ALOC 32 /* initial allocation in blocks */
+
+#define HWLEN 11 /* moved here from obsolete vaxmodel.h */
+
+#define FNAM 64 /* max file name size */
+#define PROD 16 /* max lenght of product */
+#define VERS 16 /* max length of version */
+#define ADDR 64 /* max addr line length */
+#define NSYS 32 /* max number of systems */
+#define NCRY 10 /* ecrypt. func.# < NCRY */
+#define CSLN 21 /* expanded checksum length */
+#define PBUF (SIZEOF(pak)+8*NSYS+9*ADDR) /* max size of pak */
+
+typedef int4 date[2] ; /* date/time quadword */
+
+typedef struct
+{
+ int4 id ; /* id == DBID */
+ int4 N ; /* number of paks in the file */
+ int4 len ; /* file length in bytes */
+ int4 lastid ; /* last license ID
+ int4 unused[12] ; /* not used */
+} la_prolog ; /* prolog to license adm file */
+
+typedef struct
+{
+ short n ; /* encryption function number */
+ char cs[18] ; /* check sum */
+ short l[14] ; /* offsets within pak */
+} phead ;
+
+typedef struct
+{
+ date std ; /* data/time pak created */
+ char oid[16] ; /* operator "USERNAME" */
+} pfldr ;
+
+typedef struct
+{
+ short L ; /* number of systems */
+ char nam[PROD] ; /* product name */
+ char ver[VERS] ; /* version name */
+ short x ; /* license value */
+ date t0 ; /* date available */
+ date t1 ; /* date expires */
+ int4 lid ; /* license ID */
+} pdata ;
+
+typedef struct
+{
+ phead ph ; /* pak header */
+ pfldr pf ; /* pak folder */
+ pdata pd ; /* license data */
+} pak ; /* pak structure is followed */
+ /* by variable length arrays */
+ /* sid,nid,adr,com */
+
+
+typedef enum /* variable type */
+{
+ str,sho,lon,hex,dat,lst,csm,mdl,list,emp
+} vtyp ;
+
+typedef enum /* variables identification */
+{
+ v_n,v_cs,v_l,v_std,v_oid,v_L,v_nam,v_ver,v_x,v_t0,v_t1,v_lid,v_sid,v_nid,v_adr,v_com,eovar
+} varid ;
+
+#define VARTYP(t) vtyp const t[17]= \
+{ sho,str ,sho,dat ,str ,sho,str ,str ,sho,dat ,dat ,lon ,lst ,lst ,str ,str ,emp }
+
+bool la_getcli(int v_arr[], pak *pak_ptr);
+bool la_match(pak *pak_ptr0, pak *pak_ptr1, int v_arr[]);
+bool la_nam2mdl(int4 *mdl, short w, char nam[]);
+bool la_uniqlid(char *h, int4 lid);
+bool la_validate(int4 code, char *val);
+char * la_getdb(char *fn);
+char *la_getdb(char *fn);
+short la_getstr(uint4 kid, int4 code, char *res, int lo, int hi);
+short la_mdl2nam(char nam[], int4 mdl);
+void la_convert(int4 bcs[], char *cs);
+void la_edit(uint4 kid, char *h, pak *p);
+void la_freedb(char *h);
+void la_getdat(uint4 kid, int4 code, date *date_ptr, uint4 lo, uint4 hi);
+void la_getnum(uint4 kid, int4 code, int4 *num_ptr, int4 lo, int4 hi);
+void la_initpak(int4 llid, pak *p);
+void la_listpak(char *q);
+void la_putdb(char *fn, char *h);
+void la_putfldr(pfldr *pf);
+void la_puthead(pak *p);
+ void la_putmsgs(int c);
+void la_putmsgs(int c);
+void la_putmsgu(int4 c, int4 fao[], short n);
+void la_showpak(char *q);
+void la_writepak(struct FAB *f, pak *p);
+int la_create (void);
+int la_maint (void);
+int la_store(void);
+
+#include <descrip.h>
+
+int4 lp_acquire(pak *p, int4 lval, int4 lid, int4 *lkid);
+int4 lp_confirm(int4 lid, uint4 lkid);
+int4 lp_licensed(char *h, struct dsc$descriptor *prd, struct dsc$descriptor *ver,
+ int4 mdl, int4 nid,int4 *lid, int4 *x, int4 *days, pak *p);
+int4 lp_licensed(char *h, struct dsc$descriptor *prd, struct dsc$descriptor *ver, int4 mdl, int4 nid,
+ int4 *lid, int4 *x, int4 *days, pak *p);
+uint4 lp_id(uint4 *lkid);
+
diff --git a/sr_vvms/laerrors.msg b/sr_vvms/laerrors.msg
new file mode 100644
index 0000000..103160b
--- /dev/null
+++ b/sr_vvms/laerrors.msg
@@ -0,0 +1,89 @@
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+! !
+! Copyright 2001 Sanchez Computer Associates, Inc. !
+! !
+! This source code contains the intellectual property !
+! of its copyright holder(s), and is made available !
+! under a license. If you do not know the terms of !
+! the license, please stop and do not read further. !
+! !
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ .FACILITY LMU,240/PREFIX=LA_
+ .TITLE LAERRORS Messages for LMU, VMS EDITION
+DBEXIS <The configuration database already exists>/fao=1/warning
+NOCNFDB <Invalid or missing configuration database>/fao=0/fatal
+DBINIT <Configuration database !AD successfully created>/fao=1/success
+INVAL < ^ Invalid value, reenter>/fao=0/warning
+NOTUNIQ < ^ Configuration ID not unique>/fao=0/warning
+NOSYS <Node !AD not available, Please enter the node number - if known>/fao=1/info
+HEAD <!/*** Product Authorization Key ***!/>/fao=0/info
+NOCNF <No configuration created>/fao=0/info
+BADENCR <Bad check sum number>/fao=0/error
+BADCS <The configuration data is not correct>/fao=0/error
+
+NAM <* Product :!AD>/fao=1/info
+VER <* Version :!AD>/fao=1/info
+X <* Configuration value :!SW>/fao=1/info
+UNLX <* Configuration value :Unlimited jobs>/fao=0/info
+T0 <* Activation date :!11%D>/fao=1/info
+T1 <* Expiration date :!11%D>/fao=1/info
+UNLT0 <* Activation date :Not limited>/fao=1/info
+UNLT1 <* Expiration date :Not limited>/fao=1/info
+LID <* Configuration ID :!SL>/fao=1/info
+NID <* Node number !SL :!SL>/fao=2/info
+L <* Number of systems :!SW>/fao=1/info
+SID <* Hardware model !SL :!AD>/fao=2/info
+SIDX <* Hardware model !SL :!AD!2(_)(0x!AD)>/fao=5/info
+UNSID <* Hardware model !SL :Not limited >/fao=1/info
+CUST <* Customer name :!AD>/fao=1/info
+ADR <* Address line !SL :!AD>/fao=2/info
+COM <* Comment :!AD>/fao=1/info
+CS <* Check sum :!SL-!AD-!AD-!AD-!AD>/fao=5/info
+STD <* Creation date :!17%D>/fao=1/info
+OID <* Operator ID :!AD>/fao=1/info
+
+PNAM <* Product :>/fao=0/info
+PVER <* Version :>/fao=0/info
+PX <* Configuration value :>/fao=0/info
+PT0 <* Activation date :>/fao=0/info
+PT1 <* Expiration date :>/fao=0/info
+PLID <* Configuration ID :>/fao=0/info
+PNID <* Node number [dec]:>/fao=0/info
+PL <* Number of systems :>/fao=0/info
+PSID <* Hardware model :>/fao=0/info
+PCUST <* Customer name :>/fao=0/info
+PADR1 <* Address line 1 :>/fao=0/info
+PADR2 <* Address line 2 :>/fao=0/info
+PADR3 <* Address line 3 :>/fao=0/info
+PADR4 <* Address line 4 :>/fao=0/info
+PCOM <* Comment :>/fao=0/info
+PENC <* Security function # :>/fao=0/info
+PCS <* Check sum :>/fao=0/info
+
+SAVE <Do you want to save, display again, edit or quit S/D/E/Q [D] ?:>/fao=0/info
+MODCNF <Configuration modified>/fao=0/success
+NEWCNF <New configuration stored in database>/fao=0/success
+VOID <Do you want to void Y/N , or quit Q [N] ?:>/fao=0/info
+VOIDED <Configuration voided>/fao=0/success
+PAKHD <!1(/)!3(_)GT.M PRODUCT AUTHORIZATION KEY!2(/)>/fao=0/info
+ISSUR <Sanchez Computer Associates!/Malvern, PA 19355>/fao=0/info
+ISSUE <!2(/)Issued to:!7(_)Issue Date:!/>/fao=0/info
+ISSDT <!8(_)!11%D>/fao=1/info
+ISADR <!_!AD>/fao=1/info
+DELIM <!3(/)!75**!/>/fao=0/info
+EMPTY <!_ >/fao=0/info
+
+CHOOSE <Choose a value from the list:>/fao=0/info
+VALNAM <GT.M,GT.CM,GT.CX,TEST>/fao=0/info
+VALVER <V1.0,V1.2,V2.3,V2.4,V2.5,V3.0>/fao=0/info
+
+DESTR <Delete, Next or Quit D/N/Q [N] ?:>/fao=0/info
+MOD <Modify, Next or Quit M/N/Q [M] ?:>/fao=0/info
+DELETE <Configuration deleted>/fao=0/success
+
+CNFOK <Configuration !SL is valid for local node>/fao=1/success
+
+HEADCL <Node name!2(_)Node number!2(_) Hardware model>/fao=0/info
+DELICL <---------!2(_)-----------!2(_) -------------->/fao=0/info
+SHOWCL "!15<!AD!>!3(_)!UL!2(_) !15<!AD!>"/fao=3/info
+ .END
diff --git a/sr_vvms/lbrdef.h b/sr_vvms/lbrdef.h
new file mode 100644
index 0000000..bc3e100
--- /dev/null
+++ b/sr_vvms/lbrdef.h
@@ -0,0 +1,143 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#define LBR$C_CTLTBLID 203
+#define LBR$M_LOCATE 1
+#define LBR$M_OPEN 2
+#define LBR$K_LENGTH 30
+#define LBR$C_LENGTH 30
+#define LBR$S_LBRCTLTBL 30
+#define LBR$B_ID 0
+#define LBR$B_TBLSIZ 1
+#define LBR$B_TYPE 2
+#define LBR$B_FUNC 3
+#define LBR$R_USRFLG_OVERLAY 6
+#define LBR$L_USRFLG 6
+#define LBR$R_USRFLG_BITS 6
+#define LBR$V_LOCATE 0
+#define LBR$V_OPEN 1
+#define LBR$L_HDRPTR 10
+#define LBR$L_CTXPTR 14
+#define LBR$L_CURIDX 18
+#define LBR$L_USRNAM 22
+#define LBR$L_OLDHDRPTR 26
+#define LBR$C_TYP_UNK 0
+#define LBR$C_TYP_OBJ 1
+#define LBR$C_TYP_MLB 2
+#define LBR$C_TYP_HLP 3
+#define LBR$C_TYP_TXT 4
+#define LBR$C_TYP_SHSTB 5
+#define LBR$C_TYP_DECMX 5
+#define LBR$C_TYP_RDEC 127
+#define LBR$C_TYP_USRLW 128
+#define LBR$C_TYP_USRHI 255
+#define LBR$C_FLUSHDATA 1
+#define LBR$C_FLUSHALL 0
+#define LBR$C_MAXRECSIZ 2048
+#define LBR$C_PAGESIZE 512
+#define LBR$C_HASHSIZE 512
+#define LBR$C_TEXTPAGE 508
+#define LBR$C_DEXTQ 50
+#define LBR$C_MAXCTL 16
+#define LBR$C_MAXHDRSIZ 128
+#define LBR$C_DEFENTALL 300
+#define LBR$C_RETRYOPEN 30
+#define LBR$C_RETRYWAIT 1
+#define LBR$C_MINREAD 2
+#define LBR$C_MAXREAD 50
+#define LBR$C_MEMXTRA 50
+#define LBR$C_PUTBUFSIZ 30
+#define LBR$C_FLSHBFSIZ 1
+#define LBR$C_MAXIDXRD 20
+#define LBR$C_MAXKEYLEN 128
+#define LBR$C_MAXLUHREC 32768
+#define LBR$C_CREATE 0
+#define LBR$C_READ 1
+#define LBR$C_UPDATE 2
+#define LBR$C_MAXFUNC 2
+#define LBR$S_LBRDEF 16
+#define LBR$L_IC_CTLTBL 4
+#define LBR$L_IC_FUNC 8
+#define LBR$L_IC_TYPE 12
+#define LBR$S_LBRDEF1 32
+#define LBR$L_OP_CTLTBL 4
+#define LBR$L_OP_FNS 8
+#define LBR$L_OP_CREOPT 12
+#define LBR$L_OP_DNS 16
+#define LBR$L_OP_RLFNA 20
+#define LBR$L_OP_RNS 24
+#define LBR$L_OP_RNSLEN 28
+#define LBR$S_LBRDEF2 8
+#define LBR$L_CL_CTLTBL 4
+#define LBR$S_LBRDEF3 12
+#define LBR$L_GH_CTLTBL 4
+#define LBR$L_GH_RETARY 8
+#define LBR$S_LBRDEF4 12
+#define LBR$L_SI_CTLTBL 4
+#define LBR$L_SI_IDXNUM 8
+#define LBR$S_LBRDEF5 16
+#define LBR$L_LK_CTLTBL 4
+#define LBR$L_LK_KEYNAM 8
+#define LBR$L_LK_TXTRFA 12
+#define LBR$S_LBRDEF6 16
+#define LBR$L_IK_CTLTBL 4
+#define LBR$L_IK_KEYNAM 8
+#define LBR$L_IK_TXTRFA 12
+#define LBR$S_LBRDEF7 20
+#define LBR$L_RK_CTLTBL 4
+#define LBR$L_RK_KEYNAM 8
+#define LBR$L_RK_OLDRFA 12
+#define LBR$L_RK_NEWRFA 16
+#define LBR$S_LBRDEF8 12
+#define LBR$L_DK_CTLTBL 4
+#define LBR$L_DK_KEYNAM 8
+#define LBR$S_LBRDEF9 12
+#define LBR$L_DD_CTLTBL 4
+#define LBR$L_DD_TXTRFA 8
+#define LBR$S_LBRDEF10 16
+#define LBR$L_GR_CTLTBL 4
+#define LBR$L_GR_BUFDES 8
+#define LBR$L_GR_BUFLEN 12
+#define LBR$S_LBRDEF11 16
+#define LBR$L_PR_CTLTBL 4
+#define LBR$L_PR_BUFDES 8
+#define LBR$L_PR_TXTRFA 12
+#define LBR$S_LBRDEF12 8
+#define LBR$L_PE_CTLTBL 4
+#define LBR$S_LBRDEF13 20
+#define LBR$L_SR_CTLTBL 4
+#define LBR$L_SR_IDXNUM 8
+#define LBR$L_SR_RFA 12
+#define LBR$L_SR_USRTN 16
+#define LBR$S_LBRDEF14 12
+#define LBR$L_SU_KEYDES 4
+#define LBR$L_SU_TXTRFA 8
+#define LBR$S_LBRDEF15 16
+#define LBR$L_GI_CTLTBL 4
+#define LBR$L_GI_IDXNUM 8
+#define LBR$L_GI_USRTN 12
+#define LBR$S_LBRDEF16 12
+#define LBR$L_GU_KEYADR 4
+#define LBR$L_GU_TXTRFA 8
+#define LBR$C_ADDMOD 1
+#define LBR$C_DELMOD 2
+#define LBR$C_REPMOD 3
+#define LBR$S_LBRDEF17 16
+#define LBR$L_AU_CTLTBL 4
+#define LBR$L_AU_FLAGS 8
+#define LBR$L_AU_KEYNAM 12
+#define LBR$S_LBRDEF18 12
+#define LBR$L_GU_CTLTBL 4
+#define LBR$L_GU_USRTN 8
+#define LBR$S_LBRDEF19 8
+#define LBR$L_UU_UPDESC 4
+
+#define LBR$_HDRTRUNC 0x00268800
diff --git a/sr_vvms/license_adm.c b/sr_vvms/license_adm.c
new file mode 100644
index 0000000..0904cbc
--- /dev/null
+++ b/sr_vvms/license_adm.c
@@ -0,0 +1,45 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* license_adm.c : License Administration main program */
+
+#include "mdef.h"
+#include <climsgdef.h>
+#include <descrip.h>
+#include <ssdef.h>
+#include <rmsdef.h>
+#include "ladef.h"
+extern int la_cmnd() ; /* CLD command definition table */
+
+license_adm()
+{
+ int cli$dispatch() ;
+ int4 stat0 ;
+ int4 stat1 ;
+ int4 fl= 0 ;
+ char *ln[2]= { LADB,LAFILE } ;
+ char buf[256] ;
+ unsigned short len ;
+ bool rep;
+ $DESCRIPTOR (prompt,"LMA> ") ;
+ $DESCRIPTOR (dbuf,buf) ;
+
+ stat0= lib$get_foreign(&dbuf,0,&len,&fl);
+ rep = (len==0);
+ do {
+ stat1= cli$dcl_parse(&dbuf,&la_cmnd,&lib$get_input,&lib$get_input,&prompt);
+ if (stat1==CLI$_NORMAL)
+ stat0= cli$dispatch(ln);
+ if (stat0!=RMS$_EOF && rep)
+ stat0= lib$get_foreign(&dbuf,&prompt,&len,&fl);
+ } while (stat0!=RMS$_EOF && rep);
+ return SS$_NORMAL;
+}
diff --git a/sr_vvms/linkshr.com b/sr_vvms/linkshr.com
new file mode 100644
index 0000000..ffa3dd1
--- /dev/null
+++ b/sr_vvms/linkshr.com
@@ -0,0 +1,28 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2003 Sanchez Computer Associates, Inc. !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$! linkshr - link a shareable image
+$! parameters:
+$! p1 = target directory
+$! p2 = object library directory
+$! p3 = link options
+$! P4 = link command suffix
+$!
+$ set def 'p1'
+$ if p4 .nes. "" then $ p4 = ","+p4
+$ alpha = (f$getsyi("arch_name") .eqs. "Alpha")
+$ xtra :=
+$ if .not. alpha then $ xtra := objlib/include=gtmvector,
+$ define/user objlib 'p2'mumps.olb
+$ define/user target 'p1'
+$ gtmshrlink = "gtmshrlink." + f$element(alpha,",","vax,axp")
+$ link 'p3' 'xtra' objlib/include=(cmerrors,cmierrors),gtm$tools:'gtmshrlink'/opt,sys$input/opt,target:secshrlink.opt/opt,target:release_name.opt/opt 'p4'
+name = GTMSHR.EXE
diff --git a/sr_vvms/list_file.c b/sr_vvms/list_file.c
new file mode 100644
index 0000000..85e0cc6
--- /dev/null
+++ b/sr_vvms/list_file.c
@@ -0,0 +1,279 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include <ssdef.h>
+#include <descrip.h>
+#include <rms.h>
+
+#include "io.h"
+#include "io_params.h"
+#include "cmd_qlf.h"
+#include "list_file.h"
+#include "op.h"
+
+#define LISTEXT ".LIS"
+
+GBLREF int (*op_open_ptr)(mval *v, mval *p, int t, mval *mspace);
+GBLREF command_qualifier cmd_qlf;
+GBLREF mident module_name;
+GBLREF io_pair io_curr_device;
+GBLREF list_params lst_param;
+
+static char print_time_buf[20];
+static io_pair dev_in_use;
+
+void open_list_file(void)
+{
+ char charspace;
+ uint4 status;
+ unsigned char list_name[MAX_MIDENT_LEN + STR_LIT_LEN(LISTEXT)], fname[255];
+ struct FAB fab;
+ struct NAM nam;
+
+#ifdef __ALPHA
+# pragma member_alignment save
+# pragma nomember_alignment
+#endif
+ static readonly struct{
+ unsigned char newversion;
+ unsigned char wrap;
+ unsigned char width;
+ int4 v_width;
+ unsigned char eol;
+ }open_params_list = {
+ (unsigned char)iop_newversion, (unsigned char)iop_wrap,
+ (unsigned char)iop_recordsize, (int4)132,
+ (unsigned char)iop_eol
+ };
+#ifdef __ALPHA
+# pragma member_alignment restore
+#endif
+
+ mval params;
+ mval file;
+ struct dsc$descriptor_s print_time_d
+ = { SIZEOF(print_time_buf), DSC$K_DTYPE_T, DSC$K_CLASS_S, print_time_buf };
+
+ lst_param.list_line = 1;
+ lst_param.page = 0;
+
+ fab = cc$rms_fab;
+ nam = cc$rms_nam;
+ fab.fab$l_dna = &list_name[0];
+ assert(module_name.len <= MAX_MIDENT_LEN);
+ fab.fab$b_dns = module_name.len;
+ memcpy(&list_name[0], module_name.addr, fab.fab$b_dns);
+ MEMCPY_LIT(&list_name[fab.fab$b_dns], LISTEXT);
+ fab.fab$b_dns += STR_LIT_LEN(LISTEXT);
+ if (MV_DEFINED(&cmd_qlf.list_file))
+ {
+ fab.fab$b_fns = cmd_qlf.list_file.str.len;
+ fab.fab$l_fna = cmd_qlf.list_file.str.addr;
+ }
+ nam.nam$l_esa = &fname[0];
+ nam.nam$b_ess = SIZEOF(fname);
+ nam.nam$b_nop = (NAM$M_SYNCHK);
+ fab.fab$l_nam = &nam;
+ fab.fab$l_fop = FAB$M_NAM;
+ if ((status = sys$parse(&fab,0,0)) != RMS$_NORMAL)
+ { rts_error(VARLSTCNT(1) status);
+ }
+
+ file.mvtype = params.mvtype = MV_STR;
+ file.str.len = nam.nam$b_esl;
+ file.str.addr = &fname[0];
+ params.str.len = SIZEOF(open_params_list);
+ params.str.addr = &open_params_list;
+ (*op_open_ptr)(&file, ¶ms, 30, 0);
+ params.str.len = 1;
+ charspace = (char) iop_eol;
+ params.str.addr = &charspace;
+ dev_in_use = io_curr_device;
+ op_use(&file,¶ms);
+ lib$date_time(&print_time_d);
+ list_head(0);
+ return;
+}
+
+void close_list_file(void)
+{
+ mval param,list_file;
+ unsigned char charspace;
+
+ param.str.len = 1;
+ charspace = (char) iop_eol;
+ param.str.addr = &charspace;
+ list_file.mvtype = param.mvtype = MV_STR;
+ list_file.str.len = io_curr_device.in->trans_name->len;
+ list_file.str.addr = &io_curr_device.in->trans_name->dollar_io[0];
+ op_close(&list_file, ¶m);
+ io_curr_device = dev_in_use;
+}
+
+
+void list_cmd(void)
+{
+ unsigned short cmd_len;
+ unsigned char cmd_line[256];
+ static readonly unsigned char command_line[] = "COMMAND LINE";
+ static readonly unsigned char command_line_under[] = "-----------------";
+ $DESCRIPTOR(d_cmd,cmd_line);
+
+ if (lib$get_foreign(&d_cmd, 0, &cmd_len) == SS$_NORMAL)
+ {
+ list_line(command_line);
+ list_line(command_line_under);
+ cmd_line[cmd_len]='\0';
+ list_line(cmd_line);
+ }
+}
+
+
+LITREF char gtm_release_name[];
+LITREF int4 gtm_release_name_len;
+
+GBLREF char source_file_name[];
+GBLREF unsigned short source_name_len;
+GBLREF char rev_time_buf[];
+
+void list_head(bool newpage)
+{
+ short col_2 = 70;
+ static readonly unsigned char page_lit[] = "page ";
+ unsigned char page_no_buf[10];
+ mval head;
+
+ if (newpage)
+ op_wtff();
+
+ head.mvtype = MV_STR;
+ head.str.addr = >m_release_name[0];
+ head.str.len = gtm_release_name_len;
+ op_write (&head);
+
+ op_wttab(col_2);
+ head.str.addr = print_time_buf;
+ head.str.len = 20;
+ op_write(&head);
+
+ op_wttab(100);
+ lst_param.page++;
+ head.str.addr = page_lit;
+ head.str.len = SIZEOF(page_lit) - 1;
+ op_write(&head);
+
+ head.str.addr = page_no_buf;
+ head.str.len = i2asc(page_no_buf, lst_param.page) - page_no_buf;
+ op_write(&head);
+ op_wteol(1);
+
+ head.str.addr = source_file_name;
+ head.str.len = source_name_len;
+ op_write(&head);
+ if (source_name_len >= col_2)
+ op_wteol(1);
+ op_wttab(col_2);
+ head.str.addr = rev_time_buf;
+ head.str.len = 20;
+ op_write(&head);
+ op_wteol(3);
+}
+
+
+#define BIG_PG 32
+#define BIG_PG_BOT_SP 10
+#define SMALL_PG_BOT_SP 3
+
+void list_line(char *c)
+{
+ short n, c_len, space_avail;
+ mval out;
+
+ if (io_curr_device.out->dollar.y >= lst_param.lines_per_page -
+ ((lst_param.lines_per_page < BIG_PG) ? SMALL_PG_BOT_SP : BIG_PG_BOT_SP))
+ list_head(1);
+
+ out.mvtype = MV_STR;
+ c_len = (short)strlen(c);
+
+ while(c_len > 0)
+ {
+ if (c_len < (space_avail = PG_WID - io_curr_device.out->dollar.x))
+ space_avail = c_len;
+ out.str.len = space_avail;
+ out.str.addr = c;
+ op_write(&out);
+ c_len -= space_avail;
+ c += space_avail;
+ if (c_len > 0)
+ {
+ assert(io_curr_device.out->dollar.x != 0);
+ op_wteol(1);
+ }
+ }
+
+ if ((n = lst_param.lines_per_page - io_curr_device.out->dollar.y) <
+ lst_param.space)
+ {
+ assert(n > 0);
+ op_wteol(n);
+ }
+ else
+ op_wteol(lst_param.space);
+}
+
+void list_line_number(void)
+{
+ void op_write();
+ unsigned char buf[8];
+ int n,m, i, q;
+ unsigned char *pt;
+ mval out;
+
+ assert(cmd_qlf.qlf & CQ_LIST);
+ if (io_curr_device.out->dollar.y >= lst_param.lines_per_page -
+ ((lst_param.lines_per_page < BIG_PG) ? SMALL_PG_BOT_SP : BIG_PG_BOT_SP))
+ list_head(1);
+
+ n = lst_param.list_line++;
+ pt = &buf[5];
+ memset(&buf[0],SP,SIZEOF(buf));
+ do
+ {
+ i = n / 10;
+ q = n - (i * 10);
+ *--pt = q + '0';
+ n = i;
+ } while(i > 0);
+ out.mvtype = MV_STR;
+ out.str.addr = buf;
+ out.str.len = SIZEOF(buf);
+ op_write(&out);
+}
+
+
+void list_chkpage(void)
+{
+ if (io_curr_device.out->dollar.y >= lst_param.lines_per_page -
+ ((lst_param.lines_per_page < BIG_PG) ? SMALL_PG_BOT_SP : BIG_PG_BOT_SP))
+ list_head(1);
+}
+
+
+void list_tab(void)
+{
+ op_wttab(LISTTAB);
+ return;
+}
diff --git a/sr_vvms/lke.c b/sr_vvms/lke.c
new file mode 100644
index 0000000..32da79f
--- /dev/null
+++ b/sr_vvms/lke.c
@@ -0,0 +1,132 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <rmsdef.h>
+#include <ssdef.h>
+#include <descrip.h>
+#include <climsgdef.h>
+
+#include "gtm_inet.h"
+
+#include "mlkdef.h"
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsfhead.h"
+#include "gdscc.h"
+#include "gdskill.h"
+#include "filestruct.h"
+#include "error.h" /* for EXIT_HANDLER macro used in SET_EXIT_HANDLER macro */
+#include "cli.h"
+#include "jnl.h"
+#include "stp_parms.h"
+#include "buddy_list.h" /* needed for tp.h */
+#include "hashtab_int4.h" /* needed for tp.h */
+#include "tp.h"
+#include "stringpool.h"
+#include "repl_msg.h"
+#include "gtmsource.h"
+#include "gtmimagename.h"
+#include "desblk.h" /* for desblk structure */
+#include "util.h"
+#include "lke.h"
+#include "getjobname.h"
+#include "getjobnum.h"
+#include "generic_exit_handler.h"
+#include "ladef.h"
+#include "ast_init.h"
+#include "get_page_size.h"
+#include "init_secshr_addrs.h"
+#include "gtm_env_init.h" /* for gtm_env_init() prototype */
+#include "patcode.h"
+#include "gtm_imagetype_init.h"
+#include "gtm_threadgbl_init.h"
+
+GBLREF desblk exi_blk;
+GBLREF int4 lkid;
+GBLREF int4 exi_condition;
+GBLREF spdesc rts_stringpool, stringpool;
+
+OS_PAGE_SIZE_DECLARE
+
+extern int lke_cmd();
+extern int CLI$DCL_PARSE();
+extern int CLI$DISPATCH();
+
+$DESCRIPTOR (output_qualifier, "OUTPUT");
+
+static void lke_process(void);
+
+void lke(void)
+{
+ char buff[MAX_LINE];
+ $DESCRIPTOR (command, buff);
+ uint4 status;
+ short len;
+ bool dcl;
+ DCL_THREADGBL_ACCESS;
+
+ GTM_THREADGBL_INIT;
+ gtm_imagetype_init(LKE_IMAGE);
+ gtm_env_init(); /* read in all environment variables */
+ util_out_open(0);
+ SET_EXIT_HANDLER(exi_blk, generic_exit_handler, exi_condition); /* Establish exit handler */
+ ESTABLISH(util_base_ch);
+ status =lp_id(&lkid);
+ if (SS$_NORMAL != status)
+ rts_error(VARLSTCNT(1) status);
+ get_page_size();
+ stp_init(STP_INITSIZE);
+ rts_stringpool = stringpool;
+ getjobname();
+ INVOKE_INIT_SECSHR_ADDRS;
+ ast_init();
+ initialize_pattern_table();
+ gvinit();
+ region_init(TRUE);
+ getjobnum();
+ status = lib$get_foreign(&command, 0, &len, 0);
+ if ((status & 1) && len > 0)
+ {
+ command.dsc$w_length = len;
+ status = CLI$DCL_PARSE(&command, &lke_cmd, &lib$get_input, 0, 0);
+ if (CLI$_NORMAL == status)
+ {
+ util_out_open(&output_qualifier);
+ CLI$DISPATCH();
+ util_out_close();
+ }
+ lke_exit();
+ }
+ for (;;)
+ lke_process();
+}
+
+static void lke_process(void)
+{
+ uint4 status;
+ $DESCRIPTOR (prompt, "LKE> ");
+
+ ESTABLISH(util_ch);
+ status = CLI$DCL_PARSE(0, &lke_cmd, &lib$get_input, &lib$get_input, &prompt);
+ if (RMS$_EOF == status)
+ lke_exit();
+ else if (CLI$_NORMAL == status)
+ {
+ util_out_open(&output_qualifier);
+ CLI$DISPATCH();
+ util_out_close();
+ }
+}
diff --git a/sr_vvms/lke.hlp b/sr_vvms/lke.hlp
new file mode 100644
index 0000000..80ef13f
--- /dev/null
+++ b/sr_vvms/lke.hlp
@@ -0,0 +1,305 @@
+
+1 Overview
+ The MUMPS LOCK Utility
+ The GT.M LOCK Utility, LKE, provides a tool for examining and changing
+ the GT.M LOCK environment. In MUMPS, the LOCK command reserves one or
+ more resource names. Only one process at a time can reserve a resource
+ name. No other process sharing the same environment can successfully
+ LOCK that resource name at the same time. MUMPS code commonly uses
+ LOCKs as flags controlling access to global data. Generally a LOCK
+ specifies the same as the name of the global variable that requires
+ protected access. However, this is only a convention. A LOCK argument
+ may contain any subscripted or unsubscripted MUMPS name including a
+ name with no preceding caret (^). Because they have the appearance of
+ local variable names, resource names with no preceding caret (^) are
+ commonly referred to as "local LOCKs."
+
+ The ZALLOCATE and ZDEALLOCATE commands provide an alternative,
+ non-standard, mechanism for managing LOCKs.
+
+2 Functions
+ Functions
+ The two primary functions of the MUMPS LOCK Utility (LKE) are:
+
+ o SHOW all or specified LOCKs currently active on the system
+
+ o CLEAR all or specified LOCKs currently active on the system
+
+ When debugging a MUMPS application, you may use LKE to identify and
+ clear a possible deadlock situation, i.e., two or more processes
+ have LOCKs and are waiting to add resource names LOCKed by the
+ other(s).
+
+ When used with GT.CX and/or GT.CM, LKE may display and change
+ information on other nodes of a distributed database system.
+
+2 LOCK_database
+ MUMPS LOCKs and Global Directories
+ GT.M distributes the LOCK database among the database files
+ identified by the Global Directory (GD). The Global Directory
+ Editor (GDE) creates and maintains Global Directories.
+
+ GT.M maps LOCKs of resource names starting with a caret (^) to the
+ database file used to map variables with the same name. If the
+ Global Directory maps the name A to file A.DAT, GT.M maps all LOCKs
+ on resource name ^A to file A.DAT.
+
+ GT.M maps LOCKs on names not starting with a caret (^) to the
+ region of the database specified with the GDE command LOCK /REGION.
+ By default, GDE creates Global Directories mapping local LOCKs to
+ the region $DEFAULT.
+
+ These two factors result in the following:
+
+ o ^ LOCKs automatically intersect for all users of the same data
+ in any database file, because GT.M stores the ^ LOCKs in the
+ same file as the data
+
+ o "local" LOCKs intersect dependent on the Global Directory,
+ because users may access the database through different Global
+ Directories.
+
+2 Global_Directories
+ Establishing a Global Directory
+ GDE and LKE use the logical name GTM$GBLDIR to identify which file
+ to use for the Global Directory. Define GTM$GBLDIR using the DCL
+ command DEFINE. The system manager may define GTM$GBLDIR in a GROUP
+ or SYSTEM logical name table, allowing many users access to the
+ logical name. Individual users define GTM$GBLDIR in their LOGIN.COM
+ or other command files.
+
+ Example
+
+ $ DEFINE GTM$GBLDIR PROD.GLD
+
+ When a process invokes a GT.M image, GT.M identifies the current
+ Global Directory by the logical name GTM$GBLDIR. Within MUMPS, SET
+ $ZGBLDIR=expr changes the Global Directory. $ZGBLDIR is an
+ intrinsic special variable. An individual LOCK, ZALLOCATE or
+ ZDEALLOCATE argument may specify a Global Directory with the
+ extended global syntax.
+
+1 CLEAR
+ C[LEAR]
+ The CLEAR command removes active LOCKs. The format of the CLEAR
+ command is:
+
+ C[LEAR] [/qualifier...]
+
+ The optional CLEAR command qualifiers are:
+
+ /A[LL]
+ /I[NTERACTIVE]
+ /O[UTPUT]=file-spec
+ /P[ID]=pid
+ /R[EGION]=region-name
+
+ By default, CLEAR operates interactively (/INTERACTIVE).
+
+2 Qualifiers
+/ALL
+ /A[LL]
+ Specifies the removal of all current LOCKs. If used with the
+ /REGION qualifier /ALL removes all LOCKs in the region. Issue a
+ CLEAR /ALL only when there are no active GT.M processes using
+ LOCKs or when you can predict the effect on the application.
+
+ The /ALL qualifier is incompatible with the /INTERACTIVE
+ qualifier.
+
+/INTERACTIVE
+ /I[NTERACTIVE]
+ Clears one LOCK at a time interactively. LKE displays each
+ current LOCK with the PID of the owner process and prompts for
+ verification that the LOCK should be cleared. LKE retains the
+ LOCK for any response other than Y[ES].
+
+ The /INTERACTIVE qualifier is incompatible with the /ALL
+ qualifier.
+
+ By default, CLEAR operates interactively (/INTERACTIVE).
+
+/OUTPUT
+ /OUTPUT=file-spec
+ Directs the reporting of all cleared LOCKs. If you specify an
+ existing file, LKE creates a new version of that file.
+
+ The /OUTPUT qualifier is compatible with all other qualifiers.
+
+ By default, CLEAR sends its messages to SYS$OUTPUT.
+
+/PID
+ /P[ID]=pid
+ Clears all LOCKs associated with the specified process
+ identification number. LKE interprets the PID as a hexadecimal
+ number. This command provides a means for directing CLEAR to
+ LOCKs held by a process that is behaving abnormally.
+
+ The /PID qualifier is compatible with all other qualifiers.
+
+/REGION
+ /R[EGION]=region-name
+ Clears LOCKs mapped by the current Global Directory to a region
+ specified by the region-name.
+
+ The /REGION qualifier is compatible with all other qualifiers.
+
+ By default, CLEAR /REGION= operates interactively
+ (/INTERACTIVE).
+
+1 EXIT
+ E[XIT]
+ The EXIT command ends an LKE session. The format of the EXIT command
+ is:
+
+ E[XIT]
+
+1 HELP
+ H[ELP]
+ The HELP command explains LKE commands. The format of the HELP command
+ is:
+
+ H[ELP] [options...]
+
+ The HELP command uses similar conventions to the VAX/VMS help
+ facility. Enter the LKE command for which you want information at the
+ Topic prompt(s). Use <RETURN> or <CTRL Z> to return to the LKE prompt.
+
+ Example
+
+ LKE> HELP SHOW
+
+ This command displays help for the SHOW command.
+
+
+1 SHOW
+ SH[OW]
+ The SHOW command provides a status report on the LOCK mechanism and
+ the LOCK database. The format of the SHOW command is:
+
+ SH[OW] [/qualifier...]
+
+ By default, SHOW displays /ALL.
+
+ The SHOW command reports active LOCKs. Information displayed about
+ specific LOCKs includes the LOCK resource name and the process
+ identification (PID) of the LOCK owner. The VMS privileges of the LKE
+ process determine whether LKE can display the state of any other
+ process. The results of a SHOW may be immediately "outdated" by MUMPS
+ LOCK activity.
+
+ When LKE encounters a LOCK held by a process on another node in a
+ VAXcluster, it displays a message identifying the name of the node,
+ however it does not display the process state. When LKE displays the
+ message identifying the LOCK as belonging to a process on a node with
+ no name, it means a process abandoned the LOCK due to an abnormal
+ termination, and the node that held that process no longer holds
+ active membership in the VAXcluster or has been assigned a new node
+ identifier during a reboot.
+
+2 Qualifiers
+/ALL
+ /A[LL]
+ Specifies a display of all current LOCKs in all regions and
+ information about the state of processes owning these LOCKs. The
+ /ALL qualifier is compatible with all other qualifiers. SHOW
+ /ALL /WAIT displays both /ALL and /WAIT information.
+
+ By default, SHOW displays /ALL.
+
+/OUTPUT
+ /OUTPUT=file-spec
+ Directs the reporting of the current LOCKs. When you specify a
+ file, LKE overwrites that file.
+
+ The /OUTPUT qualifier is compatible with all other qualifiers.
+
+ By default, SHOW directs all messages to SYS$OUTPUT.
+
+/PID
+ /P[ID]=process-identification
+ Displays all LOCKs owned by the specified PID.
+
+ The /PID qualifier is compatible with all other qualifiers.
+
+ By default, SHOW displays the LOCKs for all PIDs.
+
+/REGION
+ /R[EGION]=region-name
+ Displays LOCKs for the specified region.
+
+ The /REGION qualifier is compatible with all other qualifiers.
+
+ By default, SHOW displays the LOCKs for all regions.
+
+/WAIT
+ /W[AIT]
+ Displays the LOCK resource name and the process state
+ information of all processes waiting for the LOCK to be granted.
+ LKE does not display the owner of the LOCK. SHOW /ALL /WAIT
+ displays both /ALL and /WAIT information.
+
+2 process_status
+ Some VMS Process Status Codes
+ When you use the SHOW command to display all LOCKs on the system,
+ LKE also displays the status of the process that owns the LOCK.
+ The common VMS process status codes and their meanings are as
+ follows:
+
+ CUR - VMS process status indicating that the LOCK is held by a
+ "current" process.
+
+ COM - VMS process status indicating that the LOCK is held by a
+ process ready to use the processor.
+
+ HIB - VMS process status indicating that the LOCK is held by a
+ process in "hibernation" (i.e., waiting for time to pass). Such a
+ process may be waiting to LOCK a resource name presently LOCKed by
+ another process.
+
+ LEF - VMS process status indicating that the LOCK is held by a
+ process waiting for an asynchronous event ("local event flag"). A
+ process waiting for terminal input waits in a LEF state.
+
+ A nonexistent process - the process that set the LOCK no longer
+ exists.
+
+ A process on a remote node - the LOCK exists on a remote node so
+ the system is unable to determine its exact status.
+
+ A process on a cluster node - the LOCK exists on another node in
+ the VAXcluster so the system is unable to determine its exact
+ status.
+
+ A GT.CM server - the LOCK was set on behalf of a process on another
+ node via the GT.CM software.
+
+ No privilege - you do not have the appropriate VMS privilege
+ required to view the status.
+
+ For additional information on these and other VMS process status
+ categories, refer to the VMS Monitor Utility Manual.
+
+1 SPAWN
+ SP[AWN]
+ The SPAWN command creates a sub-process for access to VMS CLI (usually
+ DCL) without terminating the current LKE environment. Use the SPAWN
+ command to suspend a session and issue DCL commands such as DIRECTORY
+ or SHOW LOGICAL. The SPAWN command accepts an optional command string
+ for execution by the spawned sub-process. If the SPAWN has command
+ string parameter, the created sub-process prompts and accepts any
+ legal CLI command. To terminate the sub-process use the LOGOUT DCL
+ command.
+
+ The format of the SPAWN command is:
+
+ SP[AWN] [DCL command]
+
+ Example
+
+ LKE> SPAWN "DIR *.DAT"
+
+ This command invokes a VMS directory listing of all files in the
+ current default directory with a .DAT extension. The sub-process
+ terminates when the directory listing completes.
+
diff --git a/sr_vvms/lke_cmd.cld b/sr_vvms/lke_cmd.cld
new file mode 100644
index 0000000..664e9ae
--- /dev/null
+++ b/sr_vvms/lke_cmd.cld
@@ -0,0 +1,46 @@
+MODULE LKE_CMD
+
+DEFINE VERB spawn
+ ROUTINE util_spawn
+ PARAMETER P1, LABEL=COMMAND, VALUE(DEFAULT="")
+ QUALIFIER output NONNEGATABLE VALUE(REQUIRED,TYPE=$FILE)
+
+DEFINE VERB exit
+ ROUTINE lke_exit
+ QUALIFIER output NONNEGATABLE VALUE(REQUIRED,TYPE=$FILE)
+
+DEFINE VERB help
+ ROUTINE lke_help
+ PARAMETER P1, LABEL=QUERY
+ QUALIFIER output NONNEGATABLE VALUE(REQUIRED,TYPE=$FILE)
+
+DEFINE VERB _setgld
+ ROUTINE lke_setgdr
+ PARAMETER P1, LABEL=GLD, VALUE(REQUIRED)
+ QUALIFIER output NONNEGATABLE VALUE(REQUIRED,TYPE=$FILE)
+
+DEFINE VERB show
+ ROUTINE lke_show
+ QUALIFIER all NONNEGATABLE
+ QUALIFIER crit NEGATABLE
+ QUALIFIER lock NONNEGATABLE VALUE(REQUIRED,TYPE=$QUOTED_STRING)
+ QUALIFIER memory NONNEGATABLE
+ QUALIFIER node NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER output NONNEGATABLE VALUE(REQUIRED,TYPE=$FILE)
+ QUALIFIER pid NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER region NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER wait NONNEGATABLE
+
+DEFINE VERB clear
+ ROUTINE lke_clear
+ QUALIFIER all NONNEGATABLE
+ QUALIFIER exact NEGATABLE
+ QUALIFIER interactive NEGATABLE
+ QUALIFIER lock NONNEGATABLE VALUE(REQUIRED,TYPE=$QUOTED_STRING)
+ QUALIFIER node NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER output NONNEGATABLE VALUE(REQUIRED,TYPE=$FILE)
+ QUALIFIER pid NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER region NONNEGATABLE VALUE(REQUIRED)
+
+ DISALLOW ANY2(INTERACTIVE,ALL)
+ DISALLOW EXACT AND NOT LOCK
diff --git a/sr_vvms/lke_getansw.c b/sr_vvms/lke_getansw.c
new file mode 100644
index 0000000..07d39c9
--- /dev/null
+++ b/sr_vvms/lke_getansw.c
@@ -0,0 +1,53 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <descrip.h>
+
+#include "gtm_ctype.h"
+#include "gtm_stdio.h"
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "iosp.h"
+#include "mlkdef.h"
+#include "lke.h"
+
+/*
+ * -----------------------------------------------
+ * Read terminal input, displaying a prompt string
+ *
+ * Return:
+ * TRUE - the answer was 'Y'
+ * FALSE - answer is 'N'
+ * -----------------------------------------------
+ */
+bool lke_get_answ(char *prompt)
+{
+ char res[8] ;
+ $DESCRIPTOR (dres,res) ;
+ short unsigned int len;
+ struct dsc$descriptor_s dprm;
+
+ dprm.dsc$b_dtype = DSC$K_DTYPE_T;
+ dprm.dsc$b_class = DSC$K_CLASS_S;
+ dprm.dsc$a_pointer = prompt;
+ for (dprm.dsc$w_length = 0 ; *prompt++ ; dprm.dsc$w_length++)
+ ;
+ lib$get_input(&dres,&dprm,&len);
+ if (len < 1)
+ return FALSE;
+ else
+ return ((res[0]=='y' || res[0]=='Y'));
+}
+
diff --git a/sr_vvms/lke_help.c b/sr_vvms/lke_help.c
new file mode 100644
index 0000000..beb7b76
--- /dev/null
+++ b/sr_vvms/lke_help.c
@@ -0,0 +1,44 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <ssdef.h>
+#include <climsgdef.h>
+#include <descrip.h>
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "iosp.h"
+#include "mlkdef.h"
+#include "lke.h"
+
+#define HLP$M_PROMPT 1
+#define HELP_LIBRARY "GTM$HELP:LKE"
+
+void lke_help(void)
+{
+
+ uint4 flags;
+ char buff[256];
+ $DESCRIPTOR(line, buff);
+ $DESCRIPTOR(libr, HELP_LIBRARY);
+ $DESCRIPTOR(ent, "QUERY");
+
+ if (CLI$PRESENT(&ent) != CLI$_PRESENT || CLI$GET_VALUE(&ent,&line) != SS$_NORMAL)
+ line.dsc$w_length = 0;
+ flags = HLP$M_PROMPT;
+ lbr$output_help(lib$put_output,0,&line,&libr,&flags,lib$get_input);
+ return;
+
+}
diff --git a/sr_vvms/lke_setgdr.c b/sr_vvms/lke_setgdr.c
new file mode 100644
index 0000000..11ca7ab
--- /dev/null
+++ b/sr_vvms/lke_setgdr.c
@@ -0,0 +1,74 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include <descrip.h>
+#include <climsgdef.h>
+
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "gds_rundown.h"
+#include "dpgbldir.h"
+#include "gvcmy_rundown.h"
+#include "mlkdef.h"
+#include "lke.h"
+#include "tp_change_reg.h"
+
+GBLREF gd_region *gv_cur_region;
+GBLREF sgmnt_data *cs_data;
+GBLREF sgmnt_addrs *cs_addrs;
+GBLREF gd_addr *gd_header;
+
+void lke_setgdr(void)
+{
+ int4 cli$present(), cli$get_value();
+ gd_region *r_top;
+ mval reset;
+ bool def;
+ short len;
+ char buf[256];
+ $DESCRIPTOR (dbuf,buf);
+ static readonly $DESCRIPTOR(dent,"GLD");
+ static readonly unsigned char init_gdr[] = "GTM$GBLDIR";
+
+ gvcmy_rundown();
+ for (gv_cur_region = gd_header->regions, r_top = gv_cur_region + gd_header->n_regions; gv_cur_region < r_top;
+ gv_cur_region++)
+ {
+ tp_change_reg();
+ gds_rundown();
+ }
+ if (cli$present(&dent)==CLI$_PRESENT)
+ {
+ cli$get_value(&dent,&dbuf,&len);
+ def = FALSE;
+ reset.mvtype = MV_STR;
+ reset.str.len = len;
+ reset.str.addr = &buf;
+ }
+ else
+ {
+ reset.mvtype = MV_STR;
+ reset.str.len = sizeof (init_gdr) - 1;
+ reset.str.addr = &init_gdr;
+ }
+ zgbldir(&reset);
+ cs_addrs = 0;
+ cs_data = 0;
+ region_init(TRUE) ;
+}
diff --git a/sr_vvms/lm_cmnd.cld b/sr_vvms/lm_cmnd.cld
new file mode 100644
index 0000000..24c2d01
--- /dev/null
+++ b/sr_vvms/lm_cmnd.cld
@@ -0,0 +1,82 @@
+MODULE LM_CMND
+DEFINE TYPE subj KEYWORD system
+
+DEFINE VERB exit
+ ROUTINE la_exit
+ NOQUALIFIERS
+
+DEFINE VERB help
+ ROUTINE lm_help
+ PARAMETER P1 ,LABEL=topic
+ NOQUALIFIERS
+
+DEFINE VERB show
+ ROUTINE lm_showcl
+ PARAMETER P1 ,LABEL=subject, VALUE(REQUIRED, TYPE=subj)
+ NOQUALIFIERS
+
+DEFINE VERB initialize
+ ROUTINE la_initial
+ NOQUALIFIERS
+
+DEFINE VERB register
+ ROUTINE lm_register
+ NOPARAMETERS
+ QUALIFIER input, LABEL=io, VALUE (TYPE = $FILE,REQUIRED)
+
+DEFINE VERB delete
+ ROUTINE lm_maint
+ NOPARAMETERS
+ QUALIFIER checksum, LABEL=cs, VALUE (REQUIRED)
+ QUALIFIER num_sys, LABEL=L, VALUE (TYPE = $NUMBER,REQUIRED)
+ QUALIFIER product, LABEL=nam, VALUE (REQUIRED)
+ QUALIFIER version, LABEL=ver, VALUE (REQUIRED)
+ QUALIFIER value, LABEL=x, VALUE (TYPE = $NUMBER,REQUIRED)
+ QUALIFIER activation, LABEL=t0, VALUE (TYPE = $DATETIME,REQUIRED)
+ QUALIFIER expiration, LABEL=t1, VALUE (TYPE = $DATETIME,REQUIRED)
+ QUALIFIER configuration_id, LABEL=lid, VALUE (TYPE = $NUMBER,REQUIRED)
+ QUALIFIER hardware_model, LABEL=sid, VALUE (REQUIRED)
+ QUALIFIER node_num, LABEL=nid, VALUE (REQUIRED)
+ QUALIFIER creation, LABEL=std, VALUE (TYPE = $DATETIME,REQUIRED)
+ QUALIFIER customer, LABEL=adr, VALUE (REQUIRED)
+ QUALIFIER comment, LABEL=com, VALUE (REQUIRED)
+ QUALIFIER operator, LABEL=oid, VALUE (REQUIRED)
+ QUALIFIER output, LABEL=io, VALUE (DEFAULT=LICENSE.LIS,TYPE = $FILE)
+
+DEFINE VERB modify
+ ROUTINE lm_maint
+ NOPARAMETERS
+ QUALIFIER checksum, LABEL=cs, VALUE (REQUIRED)
+ QUALIFIER num_sys, LABEL=L, VALUE (TYPE = $NUMBER,REQUIRED)
+ QUALIFIER product, LABEL=nam, VALUE (REQUIRED)
+ QUALIFIER version, LABEL=ver, VALUE (REQUIRED)
+ QUALIFIER value, LABEL=x, VALUE (TYPE = $NUMBER,REQUIRED)
+ QUALIFIER activation, LABEL=t0, VALUE (TYPE = $DATETIME,REQUIRED)
+ QUALIFIER expiration, LABEL=t1, VALUE (TYPE = $DATETIME,REQUIRED)
+ QUALIFIER configuration_id, LABEL=lid, VALUE (TYPE = $NUMBER,REQUIRED)
+ QUALIFIER hardware_model,LABEL=sid, VALUE (REQUIRED)
+ QUALIFIER node_num, LABEL=nid, VALUE (REQUIRED)
+ QUALIFIER creation, LABEL=std, VALUE (TYPE = $DATETIME,REQUIRED)
+ QUALIFIER customer, LABEL=adr, VALUE (REQUIRED)
+ QUALIFIER comment, LABEL=com, VALUE (REQUIRED)
+ QUALIFIER operator, LABEL=oid, VALUE (REQUIRED)
+ QUALIFIER output, LABEL=io, VALUE (DEFAULT=LICENSE.LIS,TYPE = $FILE)
+
+DEFINE VERB list
+ ROUTINE lm_maint
+ NOPARAMETERS
+ QUALIFIER checksum, LABEL=cs, VALUE (REQUIRED)
+ QUALIFIER num_sys, LABEL=L, VALUE (TYPE = $NUMBER,REQUIRED)
+ QUALIFIER product, LABEL=nam, VALUE (REQUIRED)
+ QUALIFIER version, LABEL=ver, VALUE (REQUIRED)
+ QUALIFIER value, LABEL=x, VALUE (TYPE = $NUMBER,REQUIRED)
+ QUALIFIER activation, LABEL=t0, VALUE (TYPE = $DATETIME,REQUIRED)
+ QUALIFIER expiration, LABEL=t1, VALUE (TYPE = $DATETIME,REQUIRED)
+ QUALIFIER configuration_id, LABEL=lid, VALUE (TYPE = $NUMBER,REQUIRED)
+ QUALIFIER hardware_model,LABEL=sid, VALUE (REQUIRED)
+ QUALIFIER node_num, LABEL=nid, VALUE (REQUIRED)
+ QUALIFIER creation, LABEL=std, VALUE (TYPE = $DATETIME,REQUIRED)
+ QUALIFIER operator, LABEL=oid, VALUE (REQUIRED)
+ QUALIFIER customer, LABEL=adr, VALUE (REQUIRED)
+ QUALIFIER comment, LABEL=com, VALUE (REQUIRED)
+ QUALIFIER output, LABEL=io, VALUE (DEFAULT=LICENSE.LIS,TYPE = $FILE)
diff --git a/sr_vvms/lm_convert.c b/sr_vvms/lm_convert.c
new file mode 100644
index 0000000..d41def2
--- /dev/null
+++ b/sr_vvms/lm_convert.c
@@ -0,0 +1,36 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* lm_convert.c : translates a sequence of A - P char to sequence of bits
+ used in : lm_verify, lp_licensed
+*/
+#include "mdef.h"
+
+#define lo(x) (x & mask)
+#define hi(x) (x<<4)
+#define mask 15
+
+void lm_convert (cs,bcs)
+int4 bcs[] ; /* result - binary form */
+char *cs ; /* check sum A - P form */
+{
+ unsigned char *h ; /* bcs scaled in char */
+ int k ;
+
+ h= (char *)bcs ;
+ k= 0 ;
+ while (k!=8)
+ {
+ h[k] = lo(*(cs++)-'A') ;
+ h[k] |= hi(*(cs++)-'A') ;
+ k++ ;
+ }
+}
diff --git a/sr_vvms/lm_edit.c b/sr_vvms/lm_edit.c
new file mode 100644
index 0000000..fc0009a
--- /dev/null
+++ b/sr_vvms/lm_edit.c
@@ -0,0 +1,115 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* lm_edit.c: new license entered interactively, with editing
+ used in : lm_register.c ,lm_maint.c
+*/
+
+#include "mdef.h"
+#include <ssdef.h>
+#include <descrip.h>
+#include "ladef.h"
+#include "lmdef.h"
+#define MINT 0x0FFFFFFF
+#define MUNS 0xFFFFFFFF
+#define MSHO 32767
+#define B (e==SS$_NORMAL)
+
+void lm_edit (int4 kid,char *h,pak *p,int4 lo,int4 hi)
+/*
+int4 kid ; virt. keyboard ID
+char *h ; data base
+pak *p ; returns - pak record
+int4 lo ; min num. of systems
+int4 hi ; max num. of systems
+*/
+{
+ int4 str$upcase() ;
+ int k,e,w ;
+ char buf[32] ;
+ int4 n ;
+ bool valid ;
+
+ int4 *psid ; /* pak SIDs */
+ int4 *pnid ; /* pak NIDs */
+ char mbuf[HWLEN+1] ; /* buf for hardw. model */
+ int4 mdl ; /* hardware model */
+
+ error_def(LA_PNAM) ;
+ error_def(LA_PVER) ;
+ error_def(LA_PX) ;
+ error_def(LA_PT0) ;
+ error_def(LA_PT1) ;
+ error_def(LA_PLID) ;
+ error_def(LA_PL) ;
+ error_def(LA_PSID) ;
+ error_def(LA_PCS) ;
+ error_def(LA_INVAL);
+
+ $DESCRIPTOR(dnam,p->pd.nam) ;
+ $DESCRIPTOR(dver,p->pd.ver) ;
+ $DESCRIPTOR(dcsm,p->ph.cs) ;
+ $DESCRIPTOR(dbuf,mbuf) ;
+
+ dnam.dsc$w_length= la_getstr(kid,LA_PNAM,p->pd.nam,1,PROD) ;
+ dver.dsc$w_length= la_getstr(kid,LA_PVER,p->pd.ver,0,VERS) ;
+ e= str$upcase(&dnam,&dnam) ; if (!B) lib$signal(e) ;
+ e= str$upcase(&dver,&dver) ; if (!B) lib$signal(e) ;
+
+ n= p->pd.x ;
+ la_getnum(kid,LA_PX,&n,0,MSHO) ; p->pd.x= n ;
+ la_getdat(kid,LA_PT0,&(p->pd.t0),0,MUNS) ;
+ la_getdat(kid,LA_PT1,&(p->pd.t1),p->pd.t0[1],MUNS) ;
+ la_getnum(kid,LA_PLID,&(p->pd.lid),1,MINT) ;
+
+ n= p->pd.L ;
+ la_getnum(kid,LA_PL,&n,lo,hi) ; p->pd.L= n ;
+ psid= (char *)p + SIZEOF(pak) ;
+ for (k= 0;k!=n;k++)
+ {
+ w= la_mdl2nam(mbuf,psid[k]) ;
+ mbuf[w]= 0 ;
+ valid= FALSE ;
+ while (!valid)
+ {
+ w= la_getstr(kid,LA_PSID,mbuf,0,HWLEN) ;
+ dbuf.dsc$w_length= w ;
+ e= str$upcase(&dbuf,&dbuf) ; if (!B) lib$signal(e) ;
+ valid= la_nam2mdl(&mdl,w,mbuf) ;
+ if (!valid)
+ {
+ la_putmsgu(LA_INVAL,0,0) ;
+ }
+ }
+ psid[k]= mdl ;
+ }
+ pnid= psid + n ;
+ lm_getnid(kid,pnid,psid,n) ;
+ buf[0]= p->ph.n+'0' ; buf[1]= '-' ;
+ for (k=0;k!=4;k++)
+ {
+ buf[k+2]= p->ph.cs[k] ; buf[6]= '-' ;
+ buf[k+7]= p->ph.cs[k+4] ; buf[11]= '-';
+ buf[k+12]= p->ph.cs[k+8] ; buf[16]= '-';
+ buf[k+17]= p->ph.cs[k+12];
+ }
+ buf[CSLN]= 0 ;
+ la_getstr(kid,LA_PCS,buf,CSLN,CSLN+1) ;
+ p->ph.n= buf[0]-'0' ;
+ for (k=0;k!=4;k++)
+ {
+ p->ph.cs[k]= buf[k+2] ;
+ p->ph.cs[k+4]= buf[k+7] ;
+ p->ph.cs[k+8]= buf[k+12] ;
+ p->ph.cs[k+12]= buf[k+17] ;
+ }
+ e= str$upcase(&dcsm,&dcsm) ; if (!B) lib$signal(e) ;
+}
diff --git a/sr_vvms/lm_getnid.c b/sr_vvms/lm_getnid.c
new file mode 100644
index 0000000..39abe24
--- /dev/null
+++ b/sr_vvms/lm_getnid.c
@@ -0,0 +1,107 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* lm_getnid.c: assigns a unique node IDs for each hardware model in the list.
+ The nodes are selected to match the hardware models.
+ The computed value can be overwritten interactively.
+ For standalone machines nid[k]==0
+ used in : lm_edit.c
+*/
+#include "mdef.h"
+#include <ssdef.h>
+#include <syidef.h>
+#include <efndef.h>
+
+#include "ladef.h"
+#include "lmdef.h"
+#define MINT 0x0FFFFFFF
+#define LAST (status==SS$_NOMORENODE)
+#define PROPER(e) if (e!=SS$_NORMAL && !LAST) { la_putmsgs(e) ; }
+
+void lm_getnid (uint4 kid,int4 nid[],int4 sid[],int4 n)
+/*
+uint4 kid ; virt. keyb. ID
+int4 nid[] ; array of node IDs
+int4 sid[] ; array of hw. models
+int4 n ; array size
+*/
+{
+ int4 sys$getsyiw() ;
+ error_def(LA_PNID) ;
+ error_def(LA_NOSYS) ;
+ int4 mdl= 0 ; /* hw. model */
+ int4 nd= 0 ; /* node ID */
+ int4 inid ; /* initial node id */
+ int i,k ;
+ int4 iosb[2],status ;
+ bool valid ;
+ char buf[32] ;
+ int4 fao[2] ;
+ int4 tmp[16] ;
+ short w ;
+ unsigned char cmem ;
+ struct
+ { short blen ; /* buffer length */
+ short code ; /* item code */
+ char *buf ; /* return buffer */
+ short *len ; /* return length */
+ } itm[4] ;
+
+ itm[0].blen= 1 ; itm[1].blen= 0 ;
+ itm[0].code= SYI$_CLUSTER_MEMBER ; itm[1].code= 0 ;
+ itm[0].buf = &cmem ; itm[1].buf = 0 ;
+ itm[0].len = &w ; itm[1].len = 0 ;
+
+ status= sys$getsyiw(EFN$C_ENF,0,0,itm,iosb,0,0) ;
+ if (( cmem & 1 )==0)
+ {
+ inid = 0 ;
+ status= lm_mdl_nid(&mdl,&nd,&inid) ;
+ inid = -1 ;
+ }
+ else
+ {
+ inid= -1 ;
+ status= lm_mdl_nid(&mdl,&nd,&inid) ;
+ }
+ for ( k = 0 ; k!=n ; k++ )
+ {
+ tmp[k] = nid[k] ; nid[k] = 0 ;
+ }
+ k= 0 ;
+ while ( k!=n && status!=SS$_NOMORENODE )
+ {
+ i = 0 ;
+ while (((sid[i]!=mdl && sid[i]!=0) || nid[i]!=0) && i!=n) i++ ;
+ if (i!=n)
+ {
+ nid[i] = nd ;
+ }
+ status= lm_mdl_nid(&mdl,&nd,&inid) ;
+ PROPER(status) ;
+ k++ ;
+ }
+ k = 0 ;
+ while (k!=n)
+ {
+ if (nid[k]==0 && tmp[k]==0)
+ {
+ fao[0]= la_mdl2nam(buf,sid[k]) ; fao[1]= buf ;
+ lm_putmsgu(LA_NOSYS,fao,2) ;
+ }
+ else if (nid[k]==0)
+ {
+ nid[k] = tmp[k] ;
+ }
+ la_getnum(kid,LA_PNID,(nid+k),0,MINT) ;
+ k++ ;
+ }
+}
diff --git a/sr_vvms/lm_help.c b/sr_vvms/lm_help.c
new file mode 100644
index 0000000..a2dc164
--- /dev/null
+++ b/sr_vvms/lm_help.c
@@ -0,0 +1,42 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* lm_help.c: displays the help file
+ used in : lm_cmnd.cld
+*/
+
+#include "mdef.h"
+#include <ssdef.h>
+#include <descrip.h>
+#include <climsgdef.h>
+#include "ladef.h"
+
+int lm_help ()
+{
+ int cli$get_getvalue();
+ int lbr$output_help() ;
+ int4 status ;
+ int4 fl= 1 ;
+ short w ;
+ char buf[256] ;
+ $DESCRIPTOR (dent,"topic");
+ $DESCRIPTOR (dbuf,buf) ;
+ $DESCRIPTOR (dlib,LMHP) ;
+
+ status= cli$get_value(&dent,&dbuf,&w) ;
+ if (status!=SS$_NORMAL)
+ {
+ dbuf.dsc$w_length= 0 ;
+ }
+ lbr$output_help(lib$put_output,0,&dbuf,&dlib,&fl,lib$get_input) ;
+
+ return status ;
+}
diff --git a/sr_vvms/lm_listpak.c b/sr_vvms/lm_listpak.c
new file mode 100644
index 0000000..3cb62f4
--- /dev/null
+++ b/sr_vvms/lm_listpak.c
@@ -0,0 +1,123 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* lm_listpak.c: lists one pak record to stdout
+ used in : lm_register.c,lm_maint.c
+ */
+
+#include "mdef.h"
+#include <ssdef.h>
+#include <descrip.h>
+#include "gtm_string.h"
+#include "ladef.h"
+#include "lmdef.h"
+
+void lm_listpak (pak *p)
+/*
+pak *p ; buffer with the pak record
+*/
+{
+
+ int4 *psid ; /* pak SIDs */
+ int4 *pnid ; /* pak NIDs */
+
+ int4 fao[16] ; /* fao arguments */
+ char buf[32] ;
+ int k ;
+ short w ;
+
+ error_def(LA_HEAD) ; /* Listing header */
+ error_def(LA_NAM) ; /* Product */
+ error_def(LA_VER) ; /* Version */
+ error_def(LA_X) ; /* License value */
+ error_def(LA_UNLX) ; /* Unlimited license */
+ error_def(LA_T0) ; /* Date available */
+ error_def(LA_T1) ; /* Date expires */
+ error_def(LA_UNLT0) ; /* Date unlimited */
+ error_def(LA_UNLT1) ; /* Date unlimited */
+ error_def(LA_LID) ; /* License ID */
+ error_def(LA_L) ; /* Number of systems */
+ error_def(LA_SID) ; /* Hardware model */
+ error_def(LA_UNSID) ; /* Unlimited hw. */
+ error_def(LA_NID) ; /* Node ID */
+ error_def(LA_CS) ; /* Check sum */
+ error_def(LA_STD) ; /* Creation date */
+ error_def(LA_OID) ; /* Operator ID */
+
+ psid= (char*)p + p->ph.l[3] ;
+ pnid= (char*)p + p->ph.l[4] ;
+
+ la_putmsgu(LA_HEAD,0,0) ;
+
+ fao[0]= strlen(p->pd.nam) ; fao[1]= (p->pd.nam) ;
+ la_putmsgu(LA_NAM,fao,2) ;
+ fao[0]= strlen(p->pd.ver) ; fao[1]= (p->pd.ver) ;
+ la_putmsgu(LA_VER,fao,2) ;
+ if (p->pd.x!=0) /* job limited license */
+ {
+ la_putmsgu(LA_X,&(p->pd.x),1) ;
+ }
+ else /* unlimited license */
+ {
+ la_putmsgu(LA_UNLX,0,0) ;
+ }
+ if (p->pd.t0[1]!=0) /* available date given */
+ {
+ fao[0]= &(p->pd.t0) ;
+ la_putmsgu(LA_T0,fao,1) ;
+ }
+ else /* date not given */
+ {
+ la_putmsgu(LA_UNLT0,0,0) ;
+ }
+ if (p->pd.t1[1]!=0) /* available date given */
+ {
+ fao[0]= &(p->pd.t1) ;
+ la_putmsgu(LA_T1,fao,1) ;
+ }
+ else /* date not given */
+ {
+ la_putmsgu(LA_UNLT1,0,0) ;
+ }
+ la_putmsgu(LA_LID,&(p->pd.lid),1) ;
+ la_putmsgu(LA_L,&(p->pd.L),1) ;
+ for (k= 0;k!=(p->pd.L);k++)
+ {
+ if (psid[k]==0)
+ {
+ fao[0]= k ;
+ la_putmsgu(LA_UNSID,fao,1) ;
+ }
+ else
+ {
+ w= la_mdl2nam(buf,psid[k]) ;
+ fao[0]= k ; fao[1]= w ; fao[2]= buf ;
+ la_putmsgu(LA_SID,fao,3) ;
+ }
+ }
+ for (k= 0;k!=(p->pd.L);k++)
+ {
+ fao[0]= k ; fao[1]= pnid[k] ;
+ la_putmsgu(LA_NID,fao,2) ;
+ }
+
+ fao[0]= p->ph.n ;
+ fao[1]= fao[3]= fao[5]= fao[7]= 4 ;
+ fao[2]= p->ph.cs ;
+ fao[4]= p->ph.cs + 4 ;
+ fao[6]= p->ph.cs + 8 ;
+ fao[8]= p->ph.cs + 12 ;
+ la_putmsgu(LA_CS,fao,9) ;
+ fao[0]= &(p->pf.std) ;
+ la_putmsgu(LA_STD,fao,1) ;
+ fao[0]= strlen(p->pf.oid) ; fao[1]= (p->pf.oid) ;
+ la_putmsgu(LA_OID,fao,2) ;
+}
diff --git a/sr_vvms/lm_maint.c b/sr_vvms/lm_maint.c
new file mode 100644
index 0000000..8e85ca4
--- /dev/null
+++ b/sr_vvms/lm_maint.c
@@ -0,0 +1,138 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* lm_maint.c : License Man. function completing maintenance commands */
+
+#include "mdef.h"
+#include <climsgdef.h>
+#include <ssdef.h>
+#include <descrip.h>
+#include <rms.h>
+#include "ladef.h"
+#include "lmdef.h"
+#include "la_io.h"
+#define DELETE (rp[0]=='D' || rp[0]=='Y' )
+#define MODIFY (rp[0]=='M' || rp[0]=='Y' || rp[0]==0 )
+#define QUIT (rp[0]=='Q')
+#define PROPER(status) { if ((status & 1)==0) lib$signal(status) ;}
+
+int lm_maint (void)
+{
+ int cli$get_getvalue();
+
+ error_def (LA_NOCNFDB);
+ error_def (LA_DESTR) ;
+ error_def (LA_DELETE) ;
+ error_def (LA_EMPTY) ;
+ error_def (LA_MOD) ;
+ error_def (LA_MODCNF) ;
+ int4 status ;
+ unsigned short w ;
+ char com[64] ; /* command */
+ char rp[32] ; /* reply */
+ $DESCRIPTOR (dentv,"$VERB");
+ $DESCRIPTOR (dcom,com);
+ uint4 kid ; /* virt. keyb. ID */
+ la_prolog *prol; /* db prolog */
+ char *h ; /* data base */
+ pak *p ; /* pak record */
+ pak q[PBUF] ; /* pak pattern */
+ int v[32] ; /* qualif. variables */
+ int n,k ; /* pak rec count */
+ char *x,*y,*z ; /* temp pointers for */
+ bool update,next ;
+ int4 fao[1] ;
+ struct FAB f ;
+ struct RAB r ;
+
+ status= smg$create_virtual_keyboard(&kid) ;
+ PROPER(status) ;
+ status= cli$get_value(&dentv,&dcom,&w) ;
+ PROPER(status) ;
+ com[0]= (com[0]>='a' ? com[0]-32 : com[0]) ; com[w]= 0 ;
+
+ la_getcli(v,q) ;
+ la_puthead(q) ; /* pak pattern filled in */
+ h= la_getdb(LMDB) ;
+ if (h==NULL)
+ {
+ lib$signal(LA_NOCNFDB) ;
+ }
+ prol= h ;
+ p= h + SIZEOF(la_prolog) ;
+ n= 0 ;
+ update= FALSE ;
+ rp[0]= 0 ;
+ while (n != prol->N && !QUIT)
+ {
+ next= TRUE ;
+ if (la_match(p,q,v))
+ {
+ switch (com[0])
+ {
+ case 'L' : lm_listpak(p) ;
+ break ;
+ case 'D' : lm_listpak(p) ;
+ la_putmsgu(LA_EMPTY, 0, 0);
+ rp[0]= 0 ;
+ la_getstr(kid,LA_DESTR,rp,0,1) ;
+ rp[0]= (rp[0]>='a' ? rp[0]-32 : rp[0]) ;
+ if DELETE
+ {
+ prol->N-- ;
+ prol->len -= p->ph.l[0] ;
+ x= p ; y= (char *)p + p->ph.l[0] ; z= h + prol->len ;
+ while (x!=z)
+ {
+ *(x++) = *(y++) ;
+ }
+ lm_putmsgu(LA_DELETE,0,0) ;
+ next= FALSE;
+ update= TRUE ;
+ }
+ break ;
+ case 'M' : lm_listpak(p) ;
+ la_putmsgu(LA_EMPTY, 0, 0);
+ rp[0]= 0 ;
+ la_getstr(kid,LA_MOD,rp,0,1) ;
+ rp[0]= (rp[0]>='a' ? rp[0]-32 : rp[0]) ;
+ if MODIFY
+ {
+ la_putmsgu(LA_EMPTY, 0, 0);
+ lm_edit(kid,h,p,p->pd.L,p->pd.L+1) ;
+ la_putfldr(&(p->pf)) ;
+ update= TRUE ;
+ lm_putmsgu (LA_MODCNF,0,0) ;
+ }
+ break ;
+#ifdef VERIFY
+ case 'V' : status= lm_verify(p) ;
+ fao[0]= p->pd.lid ;
+ lm_putmsgu(status,fao,1) ;
+ break ;
+#endif
+ otherwise: break ;
+ }
+ }
+ if (next)
+ {
+ n++ ;
+ p = (char *)p + p->ph.l[0] ;
+ }
+ }
+ la_putmsgu(LA_EMPTY, 0, 0);
+ if (update)
+ {
+ la_putdb(LMDB,h) ;
+ }
+ la_freedb(h) ;
+ return status ;
+}
diff --git a/sr_vvms/lm_mdl_nid.c b/sr_vvms/lm_mdl_nid.c
new file mode 100644
index 0000000..5a860e9
--- /dev/null
+++ b/sr_vvms/lm_mdl_nid.c
@@ -0,0 +1,51 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* lm_mdl_nid.c: given is csid.
+ csid>0 mdl,nid are returned for specific csid.
+ csid==-1, mdl,nid are returned for all systems
+ in the cluster - one pair per call
+ csid==0 mdl,nid are returned for local system
+ when the system is standalone nid==0
+ used in : lm_getnid.c
+*/
+#include "mdef.h"
+#include <ssdef.h>
+#include <syidef.h>
+#include <efndef.h>
+
+#include "ladef.h"
+
+int4 lm_mdl_nid (mdl,nid,csid)
+int4 *mdl ; /* returns - hardware model */
+int4 *nid ; /* returns - node number */
+int4 *csid ; /* cluster system ID */
+{
+ int4 sys$getsyiw() ;
+ struct
+ {
+ short blen ; /* buffer length */
+ short code ; /* item code */
+ char *buf ; /* return buffer */
+ short *len ; /* return length */
+ } itm[4] ;
+
+ int4 iosb[2],status ;
+ short w,u ;
+
+ itm[0].blen= 2 ; itm[1].blen= 4 ; itm[2].blen= 0 ;
+ itm[0].code= SYI$_HW_MODEL; itm[1].code= SYI$_NODE_NUMBER ; itm[2].code= 0 ;
+ itm[0].buf = mdl ; itm[1].buf= nid ; itm[2].buf = 0 ;
+ itm[0].len = &w ; itm[1].len= &u ; itm[2].len = 0 ;
+
+ status= sys$getsyiw(EFN$C_ENF,csid,0,itm,iosb,0,0) ;
+ return status ;
+}
diff --git a/sr_vvms/lm_putmsgu.c b/sr_vvms/lm_putmsgu.c
new file mode 100644
index 0000000..c38c244
--- /dev/null
+++ b/sr_vvms/lm_putmsgu.c
@@ -0,0 +1,41 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* lm_putmsgu.c : outputs and formats message for user message code
+ and user FAO arguments; includes all prefixes.
+ */
+#include "mdef.h"
+
+#include <ssdef.h>
+
+ void lm_putmsgu (c,fao,n)
+ int4 c ; /* message code */
+ int4 fao[] ; /* fao arguments */
+ short n ; /* number of fao arg.s */
+ {
+ int k;
+ struct { short argc ; /* structure longword count */
+ short opt ; /* message display options */
+ int4 code ; /* message code */
+ short count ; /* FAO count */
+ short newopt; /* new options */
+ int4 fao[16]; /* fao arguments */
+ } msgvec ;
+
+ msgvec.argc= n+2 ;
+ msgvec.opt= 0x0001 ;
+ msgvec.code= c ;
+ msgvec.count= n ;
+ msgvec.newopt= 0x000F ;
+
+ for (k= 0;k!=n;k++) msgvec.fao[k]= fao[k] ;
+ sys$putmsg(&msgvec) ;
+}
diff --git a/sr_vvms/lm_register.c b/sr_vvms/lm_register.c
new file mode 100644
index 0000000..d46824f
--- /dev/null
+++ b/sr_vvms/lm_register.c
@@ -0,0 +1,99 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* lm_register.c : == new license registered
+ used in : license_man.c
+*/
+
+#include <ssdef.h>
+#include "mdef.h"
+#include <descrip.h>
+#include "ladef.h"
+#include "lmdef.h"
+
+#define TOUPPER(C) ((C) >= 'b' && (C) <='z' ? ((C) - ('a' - 'A')) : (C))
+#define SAVE (rp[0]=='S' || rp[0]=='Y' )
+#define DISP (rp[0]=='D' || w==0 )
+#define QUIT (rp[0]=='Q')
+#define EDIT (rp[0]=='E')
+
+int lm_register (void)
+{
+ int4 smg$create_virtual_keyboard() ;
+ error_def (LA_NOCNF) ; /* No license created */
+ error_def (LA_NOCNFDB); /* No license created */
+ error_def (LA_NEWCNF) ; /* New license created */
+ error_def (LA_SAVE) ; /* Save Y/N ? */
+ error_def (LA_EMPTY) ;
+
+ la_prolog *prol ; /* db file prolog */
+ char *h ; /* db in main store */
+ pak *p ; /* pak record */
+
+ char rp[8] ; /* operator reply */
+ char buf[32] ; /* buffer for checksum */
+ int4 status ;
+ int k ;
+ unsigned char recall= 16 ;
+ unsigned short w ;
+ uint4 kid ; /* virt. keyboard ID */
+ bool valid ;
+ int4 fao[1];
+ int4 stat ;
+
+ if ((h= la_getdb(LMDB))==NULL) /* db in main storage */
+ {
+ lib$signal(LA_NOCNFDB) ;
+ }
+ prol= h ;
+ p= (char *)h + prol->len ; /* place for new pak */
+
+ status= smg$create_virtual_keyboard(&kid,0,0,0,&recall) ;
+ if ((status & 1)==0)
+ {
+ la_freedb(h) ;
+ lib$signal(status) ;
+ }
+ la_initpak(-1,p) ; /* pak initialized */
+ rp[0]= 'E' ;
+ valid= FALSE ;
+ while (!SAVE && !QUIT)
+ {
+ if EDIT
+ {
+ lm_edit(kid,h,p,1,NSYS) ;
+ la_puthead(p) ;
+ la_putfldr(&(p->pf)) ;
+ }
+ else if DISP
+ {
+ lm_listpak(p) ;
+ }
+ la_putmsgu(LA_EMPTY,0,0) ;
+ rp[0]= 0 ;
+ w= la_getstr(kid,LA_SAVE,rp,0,1) ;
+ la_putmsgu(LA_EMPTY,0,0) ;
+ rp[0]= (char)TOUPPER(rp[0]) ;
+ }
+ if (SAVE)
+ {
+ (prol->N)++ ; /* count of paks ++ */
+ prol->len += p->ph.l[0] ; /* db file size ++ */
+ la_putdb (LMDB,h) ; /* db back to file */
+ lm_putmsgu (LA_NEWCNF,0,0) ;
+ }
+ else if (QUIT) /* abort without saving */
+ {
+ lm_putmsgu(LA_NOCNF,0,0) ;
+ }
+ la_freedb(h) ;
+ return status ;
+}
diff --git a/sr_vvms/lm_showcl.c b/sr_vvms/lm_showcl.c
new file mode 100644
index 0000000..59753c0
--- /dev/null
+++ b/sr_vvms/lm_showcl.c
@@ -0,0 +1,92 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* lm_showcl : displays node name, node number and hw. model for all systems
+ in the cluster
+ used in : lmu
+*/
+#include "mdef.h"
+#include <ssdef.h>
+#include <syidef.h>
+#include <efndef.h>
+
+#include "ladef.h"
+#include "lmdef.h"
+#define NAML 15
+
+int4 lm_showcl(void)
+{
+ int sys$getsyiw() ;
+ error_def(LA_SHOWCL) ;
+ error_def(LA_HEADCL) ;
+ error_def(LA_DELICL) ;
+ char nam[32] ;
+ char buf[15] ;
+ short mdl = 0 ;
+ int4 nid ;
+ int4 csid ;
+ char snam[] = "Standalone" ;
+ struct
+ {
+ short blen ; /* buffer length */
+ short code ; /* item code */
+ char *buf ; /* return buffer */
+ short *len ; /* return length */
+ } itm[4] ;
+
+ int4 iosb[2],status ;
+ int4 fao[5] ;
+ short w0,w1,w2 ;
+ unsigned char cmem = 0 ;
+
+ la_putmsgu(LA_HEADCL,0,0) ;
+ la_putmsgu(LA_DELICL,0,0) ;
+
+ itm[0].blen= 2 ; itm[1].blen= 1 ; itm[2].blen= 0 ;
+ itm[0].code= SYI$_HW_MODEL ; itm[1].code= SYI$_CLUSTER_MEMBER;itm[2].code= 0 ;
+ itm[0].buf = &mdl ; itm[1].buf= &cmem ; itm[2].buf = 0 ;
+ itm[0].len = &w0 ; itm[1].len= &w1 ; itm[2].len = 0 ;
+
+ status= sys$getsyiw(EFN$C_ENF,0,0,itm,iosb,0,0) ;
+ if (status==SS$_NORMAL && (cmem & 1)==0)
+ {
+ itm[0].blen= 4 ; itm[1].blen= 0 ;
+ itm[0].code= SYI$_NODE_NUMBER ; itm[1].code= 0 ;
+ itm[0].buf= &nid ; itm[1].buf= 0 ;
+ itm[0].len= &w1 ; itm[1].len= 0 ;
+ status= sys$getsyiw(EFN$C_ENF,0,0,itm,iosb,0,0) ;
+ if (status!=SS$_NORMAL)
+ {
+ nid= 0 ;
+ status= SS$_NORMAL ;
+ }
+ w0= la_mdl2nam(buf,(int4)mdl) ;
+ fao[0]= SIZEOF(snam)-1 ; fao[1]= snam ; fao[2]= nid ; fao[3]= w0 ; fao[4]= buf ;
+ la_putmsgu(LA_SHOWCL,fao,5) ;
+ }
+ else if ((cmem & 1)==1)
+ {
+ itm[1].blen= 4 ; itm[2].blen= 15 ; itm[3].blen= 0 ;
+ itm[1].code= SYI$_NODE_NUMBER ; itm[2].code= SYI$_NODENAME ; itm[3].code= 0 ;
+ itm[1].buf= &nid ; itm[2].buf= nam ; itm[3].buf = 0 ;
+ itm[1].len= &w1 ; itm[2].len= &w2 ; itm[3].len = 0 ;
+ csid= -1 ;
+ status= sys$getsyiw(EFN$C_ENF,&csid,0,itm,iosb,0,0) ;
+ while (status==SS$_NORMAL)
+ {
+ w0= la_mdl2nam(buf,(int4)mdl) ;
+ fao[0]= w2 ; fao[1]= nam ; fao[2]= nid ; fao[3]= w0 ; fao[4]= buf ;
+ la_putmsgu(LA_SHOWCL,fao,5) ;
+ status= sys$getsyiw(EFN$C_ENF,&csid,0,itm,iosb,0,0) ;
+ }
+ }
+ return ( status==SS$_NOMORENODE ? SS$_NORMAL : status ) ;
+}
diff --git a/sr_vvms/lmdef.h b/sr_vvms/lmdef.h
new file mode 100644
index 0000000..482015b
--- /dev/null
+++ b/sr_vvms/lmdef.h
@@ -0,0 +1,24 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef __LMDEF_H__
+#define __LMDEF_H__
+
+int4 lm_mdl_nid(int4 *mdl, int4 *nid, int4 *csid);
+void lm_edit(int4 kid, char *h, pak *p, int4 lo, int4 hi);
+void lm_getnid(uint4 kid, int4 nid[], int4 sid[], int4 n);
+void lm_listpak(pak *p);
+void lm_putmsgu(int4 c, int4 fao[], short n);
+int lm_maint (void);
+int lm_register (void);
+int lm_showcl (void);
+
+#endif
diff --git a/sr_vvms/lmu.c b/sr_vvms/lmu.c
new file mode 100644
index 0000000..b560b8a
--- /dev/null
+++ b/sr_vvms/lmu.c
@@ -0,0 +1,49 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* lmu : License Management main program */
+
+#include "mdef.h"
+#include <climsgdef.h>
+#include <descrip.h>
+#include <ssdef.h>
+#include <rmsdef.h>
+#include "ladef.h"
+extern int lm_cmnd() ;
+
+lmu ()
+{
+ int cli$dispatch() ;
+ int4 stat0 ;
+ int4 stat1 ;
+ int4 fl= 0 ;
+ char buf[256] ;
+ char *ln[2]= { LMDB,LMFILE } ;
+ short len ;
+ bool rep ;
+ $DESCRIPTOR (prompt,"LMU> ") ;
+ $DESCRIPTOR (dbuf,buf) ;
+
+ stat0= lib$get_foreign(&dbuf,0,&len,&fl) ;
+ rep = (len==0) ;
+ do {
+ stat1= cli$dcl_parse(&dbuf,&lm_cmnd,&lib$get_input,&lib$get_input,&prompt) ;
+ if (stat1==CLI$_NORMAL)
+ {
+ stat0= cli$dispatch(ln) ;
+ }
+ if (stat0!=RMS$_EOF && rep)
+ {
+ stat0= lib$get_foreign(&dbuf,&prompt,&len,&fl) ;
+ }
+ } while (stat0!=RMS$_EOF && rep) ;
+ return (stat0==RMS$_EOF ? SS$_NORMAL : stat0) ;
+}
diff --git a/sr_vvms/lmu.hlp b/sr_vvms/lmu.hlp
new file mode 100644
index 0000000..a124a9a
--- /dev/null
+++ b/sr_vvms/lmu.hlp
@@ -0,0 +1,589 @@
+
+1 Overview
+ LMU Overview
+ Greystone products are sold under license. A license permits the legal
+ operation of a Greystone product on one or more machines. When
+ entering into a software license agreement with Greystone you receive
+ an installation kit containing the software and a unique set of
+ information called a Product Authorization Key (PAK). Although the
+ software license gives you the legal right to use the software, it is
+ the PAK which mechanically enables you to use the software. You must
+ enter this PAK information into your system before you can actually
+ use the licensed software. The License Management Utility (LMU)
+ provides the commands needed to enter and maintain this PAK
+ information. LMU is supplied with all Greystone products which require
+ a PAK.
+
+2 Acquiring_PAKs
+ Acquiring your Product Authorization Key (PAK)
+ A Product Authorization Key (PAK) is a set of information provided
+ by Greystone which identifies and authorizes your licensed
+ configuration. The PAK includes those configuration details which
+ are required by LMU to permit normal operation of the product. PAKs
+ may be communicated in hardcopy, orally or via electronic mail.
+ Handle your PAK information with care. Inappropriate disclosure of
+ PAKs could place your organization in violation of your Greystone
+ license agreement(s).
+
+ If you have just received new PAK information you need to enter
+ this information into your system using LMU and the REGISTER
+ command.
+
+2 PAK_Info
+ PAK Information
+ When REGISTERing a PAK be sure to enter the information on the PAK
+ exactly. PAKs contain the following fields of information. If a PAK
+ field is left blank the default listed appears when you display the
+ PAK information again.
+
+3 Product
+ Product
+ o Product - the name, for example GT.M
+
+3 Version
+ Version
+ o Version - if not specified the configuration is not
+ restricted to a particular version. Version identifiers are
+ in the format Vm.n-p where m is a major release, n is a
+ maintenance release, and p is a patch level. The default is
+ blank.
+
+3 Configuration
+ Configuration
+ o Configuration value - identifies the type of license (user-
+ based or machine-based) and if user-based, how many users. If
+ no value is specified the configuration does not restrict the
+ number of users, indicating a machine-based license. A value
+ corresponds numerically to the maximum number of concurrent
+ users licensed for the product (user-based license). The
+ default is "Unlimited jobs."
+
+3 Activation
+ Activation
+ o Activation date - if no time is specified the configuration
+ is already valid. Times are specified in [d]d-mon-[yy]yy
+ format. The default is "Not limited."
+
+3 Expiration
+ Expiration
+ o Expiration date - if no value is specified the configuration
+ does not expire. If a PAK has no expiration date, that PAK
+ can continue in use until some event such as an operator
+ action or a CPU change makes the PAK obsolete. The default is
+ "Not limited."
+
+3 Configuration_ID
+ Configuration_ID
+ o Configuration ID - an integer which uniquely identifies the
+ configuration. This field is required.
+
+3 Number-of-systems
+ Number-of-systems
+ o Number of Systems - how many separate computers share in the
+ configuration. Multiprocessor machines such as a VAX 6420 are
+ considered a single computer. This field is required.
+
+3 Hardware_Model
+ Hardware_Model
+ o Hardware Model(s) - a mnemonic or hexadecimal identifier for
+ the computers covered by the configuration. Hardware models
+ are included even in PAKs for user-based licenses. Hardware
+ model identifications may be examined using the SHOW SYSTEM
+ command.
+
+3 Check_Sum
+ Check_Sum
+ o Checksum - a 1 digit integer field followed by 4 fields each
+ of 4 alpha characters with dashes between fields, for
+ example: 0-AFFF-CEDC-EDCF-BDDD. The checksum is used to
+ validate that the fixed portions of the configuration have
+ been correctly entered. This field is required.
+
+3 Creation
+ Creation
+ o Creation date - the system date and time when this PAK was
+ entered. This is automatically generated and filled in by the
+ system.
+
+3 Operator_ID
+ Operator_ID
+ o Operator ID - the Username of the account used when the PAK
+ information was entered. This is automatically generated and
+ filled in by the system.
+
+2 Configuration_files
+ Configuration Database Files
+ LMU stores the PAK information in one or more files which are
+ referred to as the configuration database. Because an LMU session
+ deals with a single file, user configuration activities are
+ generally simplified and minimized when a single file holds all
+ licenses in a system. This is particularly true in a VAXcluster
+ when multiple licenses for the same product may exist for different
+ cluster members. However, you may use multiple files to manage
+ configurations.
+
+ Note: The system automatically sets up the configuration database
+ if you use the standard installation procedures. If you do not, the
+ following provides information you may need.
+
+ Products access the configuration database through the logical name
+ GTM$CNFDB. The default specification for a configuration file is
+ GTM$DIST:GTC.CNF.
+
+2 VMS_Locks
+ VMS Locks Used by the Configuration Facility
+ Greystone products use VMS locks to verify a properly configured
+ operation. Each process actively using one or more Greystone
+ configured product(s) requires three locks per product. For
+ example, if there are 5 programmers using the GT.M product, they
+ are accessing 15 locks.
+
+ Make sure your system can accommodate the number of locks required
+ for your new software. Systems with large numbers of processes may
+ require adjustments to the LOCKIDTBL and the LOCKIDTBL_MAX SYSGEN
+ parameters.
+
+2 License_types
+ License Types
+ To prepare the appropriate PAK for your installation you must
+ determine which type of license you need. Licenses are either
+ machine-based or user-based.
+
+3 Machine-based
+ Machine-based Licenses
+ A machine-based license permits any number of processes to
+ concurrently use a Greystone product on a particular machine.
+ Machine-based licenses are usually purchased when a computer has
+ a potentially large number of concurrent users. The advantages
+ of machine-based licenses are:
+
+ o They reward an efficient time-sharing environment. If your
+ application(s) supports many users per VAX Unit of Processing
+ (VUP), you are not penalized for your efficiency.
+
+ o They are frequently appropriate for the dedicated MUMPS
+ environment.
+
+ o They may reduce administrative costs in a growing
+ environment. As the number of users increases no action is
+ required. There is a single justification cycle rather than
+ multiple cycles.
+
+3 User-based
+ User-based Licenses
+
+ A user-based license places a maximum limit on the number of
+ processes in a system which can concurrently use a product. All
+ types of jobs count toward the user limit including:
+ interactive, batch, detached, spawned and remote processes.
+ User-based licenses are generally purchased when the number of
+ concurrent users is small relative to the capacity of the
+ system. A user-based license can be converted to a machine-based
+ license.
+
+ The advantages of user-based licenses are:
+
+ o They reward the environment where jobs tend to be massive
+ rather than distributed.
+
+ o They permit the use of a few MUMPS processes in a large
+ general purpose system.
+
+ o They permit a "pay-as-you-go" approach to the introduction of
+ MUMPS. Additional users may be added to a user-based license
+ in increments of 4.
+
+
+1 DELETE
+ D[ELETE]
+ The DELETE command removes one or more PAKs from the configuration
+ database.
+
+ The format of the DELETE command is:
+
+ D[ELETE] [/qualifier=value]
+
+ Qualifiers to the DELETE command select the PAKs on which the command
+ operates. If multiple qualifiers are used on a DELETE, only PAKs which
+ satisfy the values for all qualifiers are presented for deletion.
+ After the PAK is presented, LMU presents the prompt:
+
+ Delete, Next or Quit D/N/Q [N]:
+
+ Example
+
+ LMU> DELETE/CON=135975
+
+
+1 EXIT
+ E[XIT]
+ The EXIT command terminates an LMU session.
+
+ The format of the EXIT command is:
+
+ E[XIT]
+
+ Example
+
+ LMU> EXIT
+ $
+
+1 HELP
+ H[ELP]
+ The HELP command displays online information about LMU commands and
+ qualifiers, using the VMS help facility. HELP takes an optional
+ parameter which specifies a topic on which you desire help. Exit from
+ HELP by entering <RET> enough times to leave all nested levels or by
+ entering <CTRL Z>.
+
+ The format of the HELP command is:
+
+ H[ELP] [topic]
+
+ Example
+
+ LMU> HELP MODIFY
+
+ This command displays help on the MODIFY command.
+
+1 INITIALIZE
+ I[NITIALIZE]
+ The INITIALIZE command creates and formats a new configuration file.
+ If the file previously exists, INITIALIZE displays a warning and does
+ not create the file. If you need to replace an existing configuration
+ file, use the DCL DELETE command to remove the existing copy of the
+ file before initiating the LMU session.
+
+ The format of the INITIALIZE command is:
+
+ I[NITIALIZE]
+
+ Example
+
+ LMU> INITIALIZE
+
+ Caution: If you have a cluster which should have a common
+ configuration database, define GTM$CNFDB to GTC.CNF or some other
+ appropriate file in a common directory before invoking LMU to perform
+ an INITIALIZE.
+
+1 LIST
+ L[IST]
+ The LIST command displays one or more PAKs from the configuration
+ database.
+
+ The format of the LIST command is:
+
+ L[IST] [/qualifier=value]
+
+ Qualifiers to the LIST command select the PAKs on which the command
+ operates. If you use multiple qualifiers on a LIST, only PAKs which
+ satisfy the values for all the qualifiers display.
+
+ For more detailed information and examples, refer to the LMU
+ qualifiers description.
+
+ Example
+
+ LMU> LIST
+
+ This command LISTs the entire contents of the current configuration
+ file.
+
+1 MODIFY
+ M[ODIFY]
+ The MODIFY command changes one or more PAKs in the configuration
+ database. Use the MODIFY command to reflect any changes in the node
+ specific information, or to correct discrepancies between the
+ information entered with a prior REGISTER or MODIFY and the PAK
+ information.
+
+ If your current configuration does not contain all the nodes specified
+ in the PAK, LMU is not able to fill in the node information
+ automatically. In this case, enter the information if it is available.
+ Otherwise, leave it blank and MODIFY the configuration again when the
+ node becomes available.
+
+ The format of the MODIFY command is:
+
+ M[ODIFY] [/qualifier=value]
+
+ Qualifiers to the MODIFY command select the PAKs on which the command
+ operates. If you use multiple qualifiers on a MODIFY, only PAKs which
+ satisfy the values for all the qualifiers are presented for
+ modification.
+
+1 REGISTER
+ R[EGISTER]
+ The REGISTER command inserts the PAK information describing a
+ configuration into a configuration file. Once you accurately REGISTER
+ an appropriate PAK, the system configures the product for full normal
+ operation.
+
+ The format of the REGISTER command is:
+
+ R[EGISTER]
+
+ REGISTER prompts for all fields. REGISTER does not verify the accuracy
+ of the configuration. However, the configuration is verified whenever
+ a process uses the product. Be sure to enter all information
+ accurately and exactly, as an incomplete or incorrect PAK cannot
+ provide normal product operation.
+
+ Warning: when LMU prompts to save the license, it acts on the first
+ character of the response and does not wait for a <RET>.
+
+ If your current configuration does not contain all the nodes specified
+ in the PAK, LMU is not able to fill in the node information
+ automatically. In this case, enter the information if it is available.
+ Otherwise, leave it blank and MODIFY the configuration when the node
+ becomes available.
+
+1 SHOW
+ S[HOW] S[YSTEM]
+ The SHOW SYSTEM command presents the details required to complement
+ the information supplied by the PAK to REGISTER a configuration.
+
+ The format of the SHOW SYSTEM command is:
+
+ S[HOW] S[YSTEM]
+
+ The SHOW SYSTEM command displays the following information:
+
+ o Node name
+
+ o Node id
+
+ o Hardware Model mnemonic or hexadecimal identifier
+
+ In a VAXcluster, the display shows a line for each machine. In an
+ unclustered system, SHOW SYSTEM displays the node name as
+ "stand-alone." The model mnemonic displays if it is known, otherwise
+ the hexadecimal id displays.
+
+1 Qualifiers
+ Qualifiers
+ LMU qualifiers are used with LMU commands to direct the system to a
+ specific license or PAK.
+
+ The INITIALIZE, REGISTER and SHOW SYSTEM commands do not accept
+ qualifiers. The LIST, MODIFY and DELETE commands may act on more than
+ one PAK and take the same selecting qualifiers. If multiple qualifiers
+ are specified, only PAKs which satisfy the values for all qualifiers
+ are treated as objects of the command. In other words, the effect of
+ multiple qualifiers on the same command works as if there were ANDs.
+
+ LMU qualifiers may be abbreviated using enough characters from the
+ beginning of the qualifier to unambiguously identify the qualifier.
+ LMU qualifiers can always be abbreviated to four characters or less.
+ Greystone recommends using four characters or more in command
+ procedure files so commands introduced in future versions do not
+ necessitate coding changes. The description for each qualifier
+ identifies the current minimum abbreviation by showing the optional
+ part of the qualifier in square brackets ([]).
+
+ All of the LMU qualifiers take arguments. The qualifier is delimited
+ by an equal sign (=) which is followed by the argument.
+
+2 /ACTIVATION
+ /A[CTIVATION]
+ The /ACTIVATION qualifier selects PAKs which activate on a
+ particular date.
+
+ The format for the ACTIVATION qualifier is:
+
+ A[CTIVATION]=date
+
+ The date is of the form [d]d-mon-[yy]yy and cannot contain
+ wildcards. The keywords YESTERDAY, TODAY and TOMORROW are also
+ accepted.
+
+ Example
+
+ LMU> LIST/ACTIV=31-oct-1985
+
+ This command LISTs all PAKs with an availability date matching the
+ 31st of October, 1985.
+
+2 /CHECKSUM
+ /CH[ECKSUM]
+ The /CHECKSUM qualifier selects all PAKs with checksums which match
+ the specified pattern.
+
+ The format for the CHECKSUM qualifier is:
+
+ /CH[ECKSUM]=pattern
+
+ Example
+
+ LMU> MODIFY/CHECKSUM=0-FDCI-AL*
+
+ This command selects any PAKs with checksums starting with
+ 0-FDCI-AL for modification.
+
+2 /CONFIGURATION_ID
+ /CO[NFIGURATION_ID]
+ The /CONFIGURATION_ID qualifier selects a particular PAK based on
+ its identifier.
+
+ The format for the CONFIGURATION_ID qualifier is:
+
+ /CO[NFIGURATION_ID]=integer
+
+ Example
+
+ LMU> LIST/CONFIG=1345
+
+ This command LISTs the PAK with the ID 1345.
+
+2 /CREATION
+ /CR[EATION]
+ The /CREATION qualifier selects PAKs which were REGISTERed on a
+ particular date.
+
+ The format for the CREATION qualifier is:
+
+ /CR[EATION]=date
+
+ The date is of the form [d]d-mon-[yy]yy and cannot contain
+ wildcards. The keywords YESTERDAY, TODAY and TOMORROW are also
+ accepted.
+
+ Example
+
+ LMU> MODIFY/CREATION=today
+
+ This command presents for modification all PAKs created today.
+
+2 /EXPIRATION
+ /E[XPIRATION]
+ The /EXPIRATION qualifier selects PAKs which have a particular
+ EXPIRATION date.
+
+ The format for the EXPIRATION qualifier is:
+
+ /E[XPIRATION]=date
+
+ The date is of the form [d]d-mon-[yy]yy and cannot contain
+ wildcards. The keywords YESTERDAY, TODAY and TOMORROW are also
+ accepted.
+
+ Example
+
+ LMU> DELETE/EXPIR=yesterday
+
+ This command presents for deletion all PAKs which expired
+ yesterday.
+
+2 /HARDWARE_MODEL
+ /H[ARDWARE_MODEL]
+ The /HARDWARE_MODEL qualifier selects PAKs which configure a
+ computer of a particular model.
+
+ The format for the HARDWARE_MODEL qualifier is:
+
+ /H[ARDWARE_MODEL]=hexadecimal-integer or mnemonic
+
+ Example
+
+ LMU> DELETE/HARDWARE=VUV2
+
+ or
+
+ LMU> DELETE/HARDWARE=0x8
+
+ These commands display for possible deletion all PAKs which cover a
+ MicroVAX II.
+
+2 /NODE_NUM
+ /NO[DE_NUM]
+ The /NODE_NUM qualifier selects PAKs for a computer based on the
+ node number.
+
+ The format for the NODE_NUM qualifier is:
+
+ /NO[DE_NUM]=integer
+
+ Example
+
+ LMU> LIST/NODE=57
+
+ This command LISTs all PAKs which configure node 57.
+
+2 /NUM_SYS
+ /NU[M_SYS]
+ The /NUM_SYS qualifier selects PAKs which cover a particular number
+ of computers.
+
+ The format for the NUM_SYS qualifier is:
+
+ /NU[M_SYS]=integer
+
+ Example
+
+ DELETE/NUM_SYS=2
+
+ This command presents for deletion all PAKs for configurations
+ which cover two computers.
+
+2 /OPERATOR
+ /O[PERATOR]
+ The /OPERATOR qualifier selects PAKs which were REGISTERed by VMS
+ user account(s) which match a pattern.
+
+ The format for the OPERATOR qualifier is:
+
+ /O[PERATOR]=pattern
+
+ Example
+
+ LMU> LIST/OPER=SMITH_C
+
+ This command LISTs all PAKs which had been REGISTERed by SMITH_C.
+
+2 /PRODUCT
+ /P[RODUCT]
+ The /PRODUCT qualifier selects PAKs which configure products which
+ match a pattern.
+
+ The format for the PRODUCT qualifier is:
+
+ /P[RODUCT]=pattern
+
+ Example
+
+ LMU> MODIFY/PROD=GT.CX
+
+ This command presents for modification all PAKs for the GT.CX
+ product.
+
+2 /VALUE
+ /VA[LUE]
+ The /VALUE qualifier selects PAKs which authorize a particular
+ number of concurrent processes.
+
+ The format for the VALUE qualifier is:
+
+ /VA[LUE]=integer
+
+ Example
+
+ LMU> LIST/VALUE=20
+
+ This command LISTs all PAKs which configure 20 users.
+
+2 /VERSION
+ /VE[RSION]
+ The /VERSION qualifier selects PAKs which authorize product
+ versions which match a pattern.
+
+ The format for the VERSION qualifier is:
+
+ /VE[RSION]=pattern
+
+ Example
+
+ LMU> MODIFY/VERSION=V2*
+
+ This command presents for modification all PAKs with a version
+ starting with V2.
diff --git a/sr_vvms/load.h b/sr_vvms/load.h
new file mode 100644
index 0000000..22dad5e
--- /dev/null
+++ b/sr_vvms/load.h
@@ -0,0 +1,21 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2006 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef LOAD_INCLUDED
+#define LOAD_INCLUDED
+
+void bin_load(uint4 begin, uint4 end, struct RAB *inrab, struct FAB *infab);
+void go_load(uint4 begin, uint4 end, struct RAB *inrab, struct FAB *infab);
+void goq_load(uint4 begin, uint4 end, struct FAB *infab);
+void goq_m11_load(struct FAB *infab, char *in_buff, uint4 rec_count, uint4 end);
+void goq_mvx_load(struct FAB *infab, char *in_buff, uint4 rec_count, uint4 end);
+
+#endif /* LOAD_INCLUDED */
diff --git a/sr_vvms/lockdefs.h b/sr_vvms/lockdefs.h
new file mode 100644
index 0000000..9ed3211
--- /dev/null
+++ b/sr_vvms/lockdefs.h
@@ -0,0 +1,17 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#define MLK_LOGIN(x) ( x->login_time = TAREF1(login_time, 0), x->image_count = image_count)
+#define BLOCKING_PROC_ALIVE(w,x,y,z) (z = get_proc_info(w->blocked->owner,x,&y), ((z == SS$_NONEXPR) || \
+ ((z == SS$_NORMAL) && ((x[0] != w->blocked->login_time) || (y != w->blocked->image_count)))))
+#define PROC_ALIVE(w,x,y,z) (z = get_proc_info(w->owner,x,&y), ((z == SS$_NONEXPR) || \
+ ((z == SS$_NORMAL) && ((x[0] != w->login_time) || (y != w->image_count)))))
+#define PENDING_PROC_ALIVE(w,x,y,z) (z = get_proc_info(w->process_id,x,&y), (z == SS$_NONEXPR))
diff --git a/sr_vvms/locks.h b/sr_vvms/locks.h
new file mode 100644
index 0000000..a234a94
--- /dev/null
+++ b/sr_vvms/locks.h
@@ -0,0 +1,35 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2002 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* Lock status block declaration. */
+/* WARNING: be certain any changes in this structure declaration are reflected in gtm_enq and gtm_enqw. */
+typedef struct {
+ short cond;
+ short reserved;
+ uint4 lockid;
+ uint4 valblk[4];
+} lock_sb;
+
+#define MAX_VMS_LOCKS 1024
+
+uint4 gtm_deq(unsigned int lkid, void *valblk, unsigned int acmode, unsigned int flags);
+uint4 gtm_enq(unsigned int efn, unsigned int lkmode, lock_sb *lsb, unsigned int flags,
+ void *resnam, unsigned int parid, void *astadr, unsigned int astprm,
+ void *blkast, unsigned int acmode, unsigned int nullarg);
+uint4 gtm_enqw(unsigned int efn, unsigned int lkmode, lock_sb *lsb, unsigned int flags,
+ void *resnam, unsigned int parid, void *astadr, unsigned int astprm, void *blkast,
+ unsigned int acmode, unsigned int nullarg);
+uint4 ccp_enq(unsigned int efn, unsigned int lkmode, lock_sb *lksb, unsigned int flags,
+ void *resnam, unsigned int parid, void *astadr, unsigned int astprm,
+ void *blkast, unsigned int acmode, unsigned int nullarg);
+uint4 ccp_enqw(unsigned int efn, unsigned int lkmode, lock_sb *lksb, unsigned int flags,
+ void *resnam, unsigned int parid, void *astadr, unsigned int astprm,
+ void *blkast, unsigned int acmode, unsigned int nullarg);
diff --git a/sr_vvms/lp_acquire.c b/sr_vvms/lp_acquire.c
new file mode 100644
index 0000000..f81ab2b
--- /dev/null
+++ b/sr_vvms/lp_acquire.c
@@ -0,0 +1,95 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <descrip.h>
+#include <lckdef.h>
+#include <lkidef.h>
+#include <psldef.h>
+#include <ssdef.h>
+#include <efndef.h>
+
+#include "gdsroot.h"
+#include "ladef.h"
+#include "vmsdtype.h"
+#include "locks.h"
+#include "gtm_getlkiw.h"
+
+/*
+ lp_acquire.c : lp_acquire = SS$_NORMAL && (lkid, lid) already acquired
+ lp_acquire = SS$_NORMAL && 0 != lkid && units available
+ lp_acquire = LP_JOBLIM && 0 == lkid && no units available
+ lp_acquire = system call error
+ used in : Licensed products
+ */
+
+GBLREF int4 process_id;
+
+error_def (LP_JOBLIM); /* Job limit exceeded */
+
+
+static const int4 mode[] = { LCK$K_CWMODE, LCK$K_CWMODE, LCK$K_EXMODE };
+
+int4 lp_acquire(pak *p, int4 lval, int4 lid, int4 *lkid)
+ /* *p => pak record [NOTE: not used!] */
+ /* lval => license value */
+ /* lid -> license ID */
+ /* returns: lkid => lock ID */
+{
+ unsigned short iosb[4];
+ uint4 status;
+ int4 i, rsbrefcnt, retlen;
+ vms_lock_sb lksb[3];
+ struct dsc$descriptor_s dres[] =
+ {
+ { SIZEOF(LMLK) - 1, DSC$K_DTYPE_T, DSC$K_CLASS_S, LMLK },
+ { SIZEOF(int4), DSC$K_DTYPE_T, DSC$K_CLASS_S, &lid },
+ { SIZEOF(int4), DSC$K_DTYPE_T, DSC$K_CLASS_S, &process_id }
+ };
+ struct
+ {
+ item_list_3 ilist;
+ int4 terminator;
+ } item_list =
+ {
+ { SIZEOF(int4), LKI$_RSBREFCNT, &rsbrefcnt, &retlen },
+ 0
+ };
+
+
+ status = lp_confirm(lid, *lkid);
+ if (SS$_NORMAL != status)
+ {
+ *lkid = 0;
+ if (0 == lid)
+ return LP_JOBLIM;
+
+ for (i = 0; i < 3; ++i)
+ {
+ status = gtm_enqw(EFN$C_ENF, mode[i], &lksb[i], LCK$M_SYSTEM, &dres[i], *lkid,
+ NULL, 0, NULL, PSL$C_USER, 0);
+ if (SS$_NORMAL == status)
+ status = lksb[i].cond;
+ if (SS$_NORMAL != status)
+ return status;
+ *lkid = lksb[i].lockid;
+ }
+
+ status = gtm_getlkiw(EFN$C_ENF, &lksb[1].lockid, &item_list, iosb, NULL, 0, 0);
+ if (SS$_NORMAL == status)
+ status = iosb[0];
+ if ((SS$_NORMAL == status) && (rsbrefcnt > lval))
+ status = LP_JOBLIM;
+ }
+
+ return status;
+}
diff --git a/sr_vvms/lp_confirm.c b/sr_vvms/lp_confirm.c
new file mode 100644
index 0000000..1d78f4f
--- /dev/null
+++ b/sr_vvms/lp_confirm.c
@@ -0,0 +1,64 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* lp_confirm.c : lp_confirm == SS$_NORMAL when the product acquired license
+ units
+ used in : Licensed products
+ */
+#include "mdef.h"
+#include <ssdef.h>
+#include <lkidef.h>
+#include <efndef.h>
+#include "ladef.h"
+
+#define PROPER(stat) { if (stat==SS$_IVLOCKID) return LP_NOTACQ ;\
+ else if ((stat & 1)==0) return stat ;}
+
+GBLREF int4 process_id ;
+
+int4 lp_confirm (int4 lid, uint4 lkid)
+/*
+int4 lid ; license ID
+uint4 lkid ; lock ID
+*/
+{
+ error_def (LP_NOTACQ) ;
+ struct { short bln ; short cod ; char *buf ; int4 *rln ;} itm[3] ;
+ int4 status ;
+ int4 iosb[2] ;
+ int4 parid,len,len1 ;
+ int4 res ; /* parent lock resource name */
+
+ itm[0].bln= 4 ; itm[0].cod= LKI$_PARENT ; itm[0].buf= &parid ; itm[0].rln= &len ;
+ itm[1].bln= 4 ; itm[1].cod= LKI$_RESNAM ; itm[1].buf= &res ; itm[1].rln= &len1 ;
+ itm[2].bln = itm[2].cod = 0; itm[2].buf = itm[2].rln = 0;
+
+ if (lkid!=0 && lid!=0)
+ {
+ status= gtm_getlkiw(EFN$C_ENF,&lkid,itm,iosb,0,0,0) ;
+ PROPER(status) ;
+ if (parid!=0 && process_id==res)
+ {
+ status= gtm_getlkiw(EFN$C_ENF,&parid,&itm[1],iosb,0,0,0) ;
+ PROPER(status) ;
+ status= ( lid==res ? SS$_NORMAL : LP_NOTACQ ) ;
+ }
+ else
+ {
+ status= LP_NOTACQ ;
+ }
+ }
+ else
+ {
+ status= LP_NOTACQ ;
+ }
+ return status ;
+}
diff --git a/sr_vvms/lp_id.c b/sr_vvms/lp_id.c
new file mode 100644
index 0000000..02d39d2
--- /dev/null
+++ b/sr_vvms/lp_id.c
@@ -0,0 +1,64 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <ssdef.h>
+#include <descrip.h>
+#include <psldef.h>
+#include <syidef.h>
+#include <lckdef.h>
+#include <efndef.h>
+
+#include "gdsroot.h"
+#include "ladef.h"
+#include "vmsdtype.h"
+#include "locks.h"
+
+uint4 lp_id(uint4 *lkid)
+{
+ struct
+ {
+ item_list_3 ilist[1];
+ int4 terminator;
+ } syi_list_1;
+ struct dsc$descriptor_s node_dsc;
+ vms_lock_sb lksb;
+ uint4 node, status;
+ unsigned short iosb[4], retlen, local_nodename_len;
+ char node_buff[SIZEOF(LMLK) + 2 * SIZEOF(long)];
+
+ node = 0;
+ syi_list_1.ilist[0].item_code = SYI$_NODE_CSID;
+ syi_list_1.ilist[0].buffer_address = &node;
+ syi_list_1.ilist[0].buffer_length = SIZEOF(node);
+ syi_list_1.ilist[0].return_length_address = &retlen;
+ syi_list_1.terminator = 0;
+ status = sys$getsyiw(EFN$C_ENF, NULL, NULL, &syi_list_1, iosb, NULL, 0);
+ if (SS$_NORMAL == status)
+ status = iosb[0];
+ if (SS$_NORMAL == status)
+ {
+ memcpy(node_buff, LMLK, SIZEOF(LMLK) - 1);
+ node_buff[SIZEOF(LMLK) - 1] = '_';
+ i2hex(node, &node_buff[SIZEOF(LMLK)], 2 * SIZEOF(long));
+ node_dsc.dsc$w_length = SIZEOF(LMLK) + 2 * SIZEOF(long);
+ node_dsc.dsc$a_pointer = node_buff;
+ node_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
+ node_dsc.dsc$b_class = DSC$K_CLASS_S;
+ status = gtm_enqw(EFN$C_ENF, LCK$K_NLMODE, &lksb, LCK$M_SYSTEM, &node_dsc, *lkid, NULL, 0, NULL, PSL$C_USER, 0);
+ if (SS$_NORMAL == status)
+ status = lksb.cond;
+ if (SS$_NORMAL == status)
+ *lkid = lksb.lockid;
+ }
+ return status;
+}
diff --git a/sr_vvms/lp_licensed.c b/sr_vvms/lp_licensed.c
new file mode 100644
index 0000000..7fb404b
--- /dev/null
+++ b/sr_vvms/lp_licensed.c
@@ -0,0 +1,118 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* lp_licensed.c = SS$_NORMAL : product is licensed
+ = LP_LEXPIR : license has expired
+ = LP_NOAVAL : license not yet available
+ = LP_INVCSM : invalid checksum
+ used in : licensed products
+*/
+#include "mdef.h"
+#include "ladef.h"
+#include <ssdef.h>
+#include <descrip.h>
+#include "la_encrypt.h"
+#define MAXSHO 32767
+
+int4 lp_licensed(char *h, struct dsc$descriptor *prd, struct dsc$descriptor *ver, int4 mdl, int4 nid,
+ int4 *lid, int4 *x, int4 *days, pak *p)
+/* h is a pointer to the data base */
+/* prd is a pointer to a descriptor that in turn points to the product name */
+/* ver is a pointer to a descriptor that in turn points to the version */
+/* mdl is a hardware model id */
+/* nid is a cluster node ID */
+/* lid is a pointer to a license ID (returned) */
+/* x is a pointer to a license value (returned) */
+/* days is a pointer to a number of days until expiration (returned) */
+/* p is a pointer to a pak record (returned) */
+{
+ int4 memcmp() ;
+ void lm_convert() ;
+ error_def(LP_LEXPIR) ;
+ error_def(LP_NOAVAL) ;
+ error_def(LP_NOCONF) ;
+ error_def(LP_INVCSM) ;
+ la_prolog *prol; /* db prolog */
+ int4 *psid ;
+ int4 *pnid ;
+ int k,j ;
+ int4 status;
+ short offset ;
+ int4 d0,dd,d1;
+ bool match,pmat,vmat,nmat,valid ;
+ int4 bcs[3]= {0,0,0} ;
+ int4 pcs[3]= {0,0,0} ;
+
+ *lid= *x= *days= 0 ;
+ prol= h ;
+ p= h ;
+ offset= SIZEOF(la_prolog) ;
+ match= FALSE ;
+ j= 0 ;
+ while (!match && j != prol->N)
+ {
+ p = (char *)p + offset ;
+ pmat = (p->pd.nam[prd->dsc$w_length]==0) && (memcmp(prd->dsc$a_pointer,p->pd.nam,prd->dsc$w_length)==0) ;
+ vmat = (p->pd.ver[0]==0) || (memcmp(ver->dsc$a_pointer,p->pd.ver,ver->dsc$w_length)==0) ;
+ if (pmat && vmat)
+ {
+ psid= (char *)p + p->ph.l[3] ;
+ pnid= (char *)p + p->ph.l[4] ;
+ pcs[0]= pcs[1]= 0 ;
+ lm_convert(p->ph.cs,pcs) ;
+ k= 0 ;
+ nmat= FALSE ;
+ while (!nmat && k!=p->pd.L)
+ {
+ nmat= (nid==pnid[k] && (mdl==psid[k] || psid[k]==0));
+ k++ ;
+ }
+ }
+ match= pmat && vmat && nmat ;
+ offset= p->ph.l[0] ;
+ j++ ;
+ }
+ if (match)
+ {
+ *lid= p->pd.lid ;
+ *x= (p->pd.x==0 ? MAXSHO : p->pd.x) ;
+ valid= la_encrypt(p->ph.n,&(p->pd),(p->ph.l[4] - p->ph.l[2]),bcs) ;
+ valid= valid && (bcs[0]==pcs[0]) && (bcs[1]==pcs[1]) ;
+ if (valid)
+ {
+ if (p->pd.t1[1]==0) /* Unlimited License */
+ {
+ *days= MAXSHO ;
+ status= SS$_NORMAL ;
+ }
+ else
+ {
+ lib$day(&dd,0) ; /* Current days */
+ lib$day(&d1,p->pd.t1) ; /* Expiration days */
+ if (p->pd.t0[1]) /* Available days */
+ lib$day(&d0, p->pd.t0) ;
+ else
+ d0 = 0;
+ *days= d1 - dd ;
+ status = ( dd<d0 ? LP_NOAVAL : ( dd<d1 ? SS$_NORMAL : LP_LEXPIR )) ;
+ }
+ }
+ else
+ {
+ status= LP_INVCSM ;
+ }
+ }
+ else
+ {
+ status= LP_NOCONF ;
+ }
+ return status;
+}
diff --git a/sr_vvms/lperrors.msg b/sr_vvms/lperrors.msg
new file mode 100644
index 0000000..1c573fc
--- /dev/null
+++ b/sr_vvms/lperrors.msg
@@ -0,0 +1,22 @@
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+! !
+! Copyright 2001 Sanchez Computer Associates, Inc. !
+! !
+! This source code contains the intellectual property !
+! of its copyright holder(s), and is made available !
+! under a license. If you do not know the terms of !
+! the license, please stop and do not read further. !
+! !
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ .FACILITY GTLP,240/PREFIX=LP_
+ .TITLE LPERRORS Messages for GTLP, VMS EDITION
+NOCNFDB <No configuration data base>/fao=0/fatal
+NOCONF <No configuration for the product>/fao=1/fatal
+NOVERS <No configuration for the product version>/fao=0/fatal
+LEXPIR <The configuration has expired>/fao=0/fatal
+NOAVAL <The configuration is not yet available>/fao=0/fatal
+INVCSM <Invalid configuration>/fao=0/fatal
+NOTACQ <No configuration units acquired>/fao=0/fatal
+BADRES <Bad resource>/fao=0/fatal
+JOBLIM <Job limit exceeded>/fao=0/fatal
+ .END
diff --git a/sr_vvms/m_recall.c b/sr_vvms/m_recall.c
new file mode 100644
index 0000000..a2a482d
--- /dev/null
+++ b/sr_vvms/m_recall.c
@@ -0,0 +1,133 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <descrip.h>
+#include <iodef.h>
+#include <ssdef.h>
+#include <efndef.h>
+
+#include "comline.h"
+#include "gtm_caseconv.h"
+#include "m_recall.h"
+
+#define DEF_BUF_SZ 1024 /* from IOTT_OPEN.C */
+#define CCPROMPT 0x00010000
+#define ERR_RECBADNUM "Recall error: bad numeric argument format"
+#define ERR_RECNOTFND "Recall error: command not found"
+#define ERR_RECOUTOFRANGE "Recall error: numeric argument out of range"
+
+GBLREF mstr *comline_base;
+GBLREF int comline_index;
+
+int m_recall (short len, char *addr, int4 *index, short tt_channel)
+{
+ unsigned char *cp, *cp_top;
+ unsigned char recbuf[8];
+ unsigned char faobuf[DEF_BUF_SZ];
+ unsigned short reclen, arglen, iosb[4];
+ unsigned short faolen;
+ unsigned int n, cl;
+ $DESCRIPTOR (faodsc, faobuf);
+ static readonly $DESCRIPTOR (ctrstr, "!2SL !AD");
+
+ cp = addr; cp_top = cp + len;
+ while (cp < cp_top && *cp != SP && *cp != '\t')
+ cp++;
+ reclen = (char *) cp - addr;
+ if (reclen != 3 && reclen != 6)
+ return FALSE;
+
+ lower_to_upper (recbuf, addr, reclen);
+ if (memcmp (recbuf, "RECALL", reclen))
+ return FALSE;
+
+ while (cp < cp_top && (*cp == SP || *cp == '\t'))
+ cp++;
+ if (cp == cp_top)
+ {
+ flush_pio ();
+ cl = comline_index;
+ n = 1;
+ do
+ {
+ cl = clmod (cl - 1);
+ if (!comline_base[cl].len)
+ break;
+ sys$fao(&ctrstr, &faolen, &faodsc, n++, comline_base[cl].len, comline_base[cl].addr);
+
+ /* don't do status on terminal qiow'w in this module,
+ as errors should be unlikely and would cause messy exit from dm_read
+ if you don't like it revise the interface between the routines */
+
+ sys$qiow(EFN$C_ENF, tt_channel, IO$_WRITEVBLK, &iosb, 0, 0, faobuf, faolen, 0, CCPROMPT, 0, 0);
+ } while (cl != comline_index);
+ assert (!comline_base[cl].len || (n == MAX_RECALL + 1 && cl == comline_index));
+ *index = 0;
+ return TRUE;
+ }
+ /* cp now points to beginning of arg */
+
+ /* throw away trailing whitespace */
+ while (*--cp_top == SP || *cp_top == '\t')
+ assert(cp < cp_top);
+ cp_top++;
+ arglen = cp_top - cp;
+
+ if ('0' <= *cp && *cp <= '9') /* numeric argument */
+ {
+ n = 0;
+ while (cp < cp_top && *cp != SP && *cp != '\t')
+ {
+ n *= 10;
+ if ('0' <= *cp && *cp <= '9')
+ n += (*cp++ - '0');
+ else
+ {
+ sys$qiow(EFN$C_ENF, tt_channel, IO$_WRITEVBLK, &iosb, 0, 0,
+ ERR_RECBADNUM, sizeof ERR_RECBADNUM - 1, 0, CCPROMPT, 0, 0);
+ *index = -1;
+ return TRUE;
+ }
+ }
+ if (n <= 0 || n > MAX_RECALL)
+ {
+ sys$qiow(EFN$C_ENF, tt_channel, IO$_WRITEVBLK, &iosb, 0, 0,
+ ERR_RECOUTOFRANGE, sizeof ERR_RECOUTOFRANGE - 1, 0, CCPROMPT, 0, 0);
+ *index = -1;
+ return TRUE;
+ }
+ assert (arglen == 1 || arglen == 2);
+ }
+ else /* string argument */
+ {
+ cl = comline_index;
+ n = 1;
+ do
+ {
+ cl = clmod (cl - 1);
+ if (!comline_base[cl].len) break;
+ if (!memcmp (comline_base[cl].addr, cp, arglen))
+ break;
+ n++;
+ } while (cl != comline_index);
+ if (!comline_base[cl].len || cl == comline_index)
+ {
+ sys$qiow(EFN$C_ENF, tt_channel, IO$_WRITEVBLK, &iosb, 0, 0,
+ ERR_RECNOTFND, sizeof ERR_RECNOTFND - 1, 0, CCPROMPT, 0, 0);
+ *index = -1;
+ return TRUE;
+ }
+ }
+ assert (0 < n && n <= MAX_RECALL);
+ *index = n;
+ return TRUE;
+}
diff --git a/sr_vvms/m_recall.h b/sr_vvms/m_recall.h
new file mode 100644
index 0000000..f55205a
--- /dev/null
+++ b/sr_vvms/m_recall.h
@@ -0,0 +1,17 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef M_RECALL_INCLUDED
+#define M_RECALL_INCLUDED
+
+int m_recall(short len, char *addr, int4 *index, short tt_channel);
+
+#endif /* M_RECALL_INCLUDED */
diff --git a/sr_vvms/map_sym.c b/sr_vvms/map_sym.c
new file mode 100644
index 0000000..7b46824
--- /dev/null
+++ b/sr_vvms/map_sym.c
@@ -0,0 +1,137 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* map_sym.c VMS - load function from shared library for various collation symbols */
+/* Return TRUE/FALSE based on mapping success */
+
+#include <descrip.h>
+#include <ssdef.h>
+
+#include "mdef.h"
+#include "error.h"
+#include "collseq.h"
+#include "gtmmsg.h"
+
+#define CHECK_ERR_STAT \
+{ \
+ REVERT; \
+ return FALSE; \
+}
+
+STATICFNDCL CONDITION_HANDLER(map_sym_ch);
+
+error_def(ERR_ASSERT);
+error_def(ERR_COLLFNMISSING);
+error_def(ERR_GTMASSERT);
+error_def(ERR_GTMASSERT2);
+error_def(ERR_GTMCHECK);
+error_def(ERR_STACKOFLOW);
+error_def(ERR_VMSMEMORY);
+
+boolean_t map_collseq(mstr *fspec, collseq *ret_collseq)
+{
+ struct dsc$descriptor fspec_desc;
+ struct dsc$descriptor symbol_desc;
+ int status;
+ boolean_t coll_lib_found = FALSE;
+ ch_ret_type map_sym_ch();
+ static MSTR_CONST(xform_sym_1, "gtm_ac_xform_1");
+ static MSTR_CONST(xback_sym_1, "gtm_ac_xback_1");
+ static MSTR_CONST(xform_sym, "gtm_ac_xform");
+ static MSTR_CONST(xback_sym, "gtm_ac_xback");
+ static MSTR_CONST(verify_sym, "gtm_ac_verify");
+ static MSTR_CONST(version_sym, "gtm_ac_version");
+
+ ESTABLISH(map_sym_ch);
+ fspec_desc.dsc$w_length = fspec->len;
+ fspec_desc.dsc$b_dtype = DSC$K_DTYPE_T;
+ fspec_desc.dsc$b_class = DSC$K_CLASS_S;
+ fspec_desc.dsc$a_pointer = fspec->addr;
+ symbol_desc.dsc$w_length = xform_sym_1.len;
+ symbol_desc.dsc$b_dtype = DSC$K_DTYPE_T;
+ symbol_desc.dsc$b_class = DSC$K_CLASS_S;
+ symbol_desc.dsc$a_pointer = xform_sym_1.addr;
+ status = lib$find_image_symbol(&fspec_desc, &symbol_desc, &(ret_collseq->xform), 0);
+ if (status & 1)
+ {
+ symbol_desc.dsc$w_length = xback_sym_1.len;
+ symbol_desc.dsc$b_dtype = DSC$K_DTYPE_T;
+ symbol_desc.dsc$b_class = DSC$K_CLASS_S;
+ symbol_desc.dsc$a_pointer = xback_sym_1.addr;
+ status = lib$find_image_symbol(&fspec_desc, &symbol_desc, &(ret_collseq->xback), 0);
+ if (status & 1)
+ {
+ coll_lib_found = TRUE;
+ ret_collseq->argtype = 1;
+ } else
+ {
+ gtm_putmsg(VARLSTCNT(5) ERR_COLLFNMISSING, 3, LEN_AND_LIT("gtm_ac_xback_1()"), ret_collseq->act );
+ CHECK_ERR_STAT;
+ }
+ }
+ if (FALSE == coll_lib_found)
+ {
+ symbol_desc.dsc$w_length = xform_sym.len;
+ symbol_desc.dsc$b_dtype = DSC$K_DTYPE_T;
+ symbol_desc.dsc$b_class = DSC$K_CLASS_S;
+ symbol_desc.dsc$a_pointer = xform_sym.addr;
+ status = lib$find_image_symbol(&fspec_desc, &symbol_desc, &(ret_collseq->xform), 0);
+ if (status & 1)
+ {
+ symbol_desc.dsc$w_length = xback_sym.len;
+ symbol_desc.dsc$b_dtype = DSC$K_DTYPE_T;
+ symbol_desc.dsc$b_class = DSC$K_CLASS_S;
+ symbol_desc.dsc$a_pointer = xback_sym.addr;
+ status = lib$find_image_symbol(&fspec_desc, &symbol_desc, &(ret_collseq->xback), 0);
+ if (status & 1)
+ {
+ coll_lib_found = TRUE;
+ ret_collseq->argtype = 0;
+ } else
+ {
+ gtm_putmsg(VARLSTCNT(5) ERR_COLLFNMISSING, 3, LEN_AND_LIT("gtm_ac_xback()"), ret_collseq->act );
+ CHECK_ERR_STAT;
+ }
+ } else /* Neither xform_1 or xform is found */
+ CHECK_ERR_STAT;
+ }
+ assert(TRUE == coll_lib_found);
+ symbol_desc.dsc$w_length = verify_sym.len;
+ symbol_desc.dsc$b_dtype = DSC$K_DTYPE_T;
+ symbol_desc.dsc$b_class = DSC$K_CLASS_S;
+ symbol_desc.dsc$a_pointer = verify_sym.addr;
+ status = lib$find_image_symbol(&fspec_desc, &symbol_desc, &(ret_collseq->verify), 0);
+ if (!(status & 1))
+ CHECK_ERR_STAT;
+
+ symbol_desc.dsc$w_length = version_sym.len;
+ symbol_desc.dsc$b_dtype = DSC$K_DTYPE_T;
+ symbol_desc.dsc$b_class = DSC$K_CLASS_S;
+ symbol_desc.dsc$a_pointer = version_sym.addr;
+ status = lib$find_image_symbol(&fspec_desc, &symbol_desc, &(ret_collseq->version), 0);
+ if (!(status & 1))
+ CHECK_ERR_STAT;
+ REVERT;
+ return TRUE;
+}
+
+STATICFNDEF CONDITION_HANDLER(map_sym_ch)
+{
+ int4 status;
+
+ START_CH;
+
+ if (DUMP)
+ NEXTCH;
+ mch->CHF_MCH_SAVR0 = SIGNAL; /* return status from lib$find_image_symbol to map_sym */
+ if ((status = sys$unwind(&mch->CHF_MCH_DEPTH, 0)) != SS$_NORMAL)
+ NEXTCH;
+}
diff --git a/sr_vvms/mapdb.awk b/sr_vvms/mapdb.awk
new file mode 100644
index 0000000..dacde4b
--- /dev/null
+++ b/sr_vvms/mapdb.awk
@@ -0,0 +1,74 @@
+BEGIN {
+ dontprint = 0;
+ start = 0;
+ module = ""
+ endoffset = "";
+ }
+$4 == "Synopsis" { synopsis_section = $2; dontprint += 3; }
+$1 == "
" { dontprint = 6; }
+$1 == "$CODE$" { dontprint = 1; }
+dontprint { dontprint--; next; }
+synopsis_section == "Object" {
+ if ($2 == "")
+ {
+ module = $1;
+ next;
+ } else if (module == "")
+ {
+ module = $1;
+ precreator = $6;
+ creator = $7;
+ } else
+ {
+ precreator = $5;
+ creator = $6;
+ }
+ if (creator == "Message")
+ filext[module] = ".MSG";
+ else if (precreator == "MACRO-64")
+ filext[module] = ".M64";
+ else if (creator == "AMAC")
+ filext[module] = ".MAR";
+ else
+ filext[module] = ".C";
+ module = "";
+ next;
+ }
+$1 == "$CODE" { start = 1; }
+$1 == "$BSS$" { start = 0; }
+$1 == "$DATA$" { start = 0; }
+$1 == "$LITERAL$" { start = 0; }
+$1 == "$READONLY$" { start = 0; }
+$1 == "$READONLY_ADDR$" { start = 0; }
+$NF == "MOD" { next; } # e.g. lines starting with $LINKAGE, $SYMVECT, _AMAC$LINKAGE, etc.
+start {
+ if ($1 != "" && $2 == "")
+ {
+ module = $1;
+ } else
+ {
+ if (module == "")
+ {
+ module = $1;
+ begin = $2;
+ end = $3;
+ octa_field = $7;
+ } else
+ {
+ begin = $1;
+ end = $2;
+ octa_field = $6;
+ }
+ if (octa_field == "OCTA")
+ {
+ gsub("_", "", image);
+ printf "\tset ^%s(\"%s\")=\"%s%s\"\n", image, begin, module, filext[module];
+ endoffset = end;
+ }
+ module = "";
+ }
+ }
+END {
+ if (endoffset != "")
+ printf "\tset ^%s(\"%s\")=\"%s%s\"\n", image, endoffset, "IMAGE", ".END";
+ }
diff --git a/sr_vvms/mapoff.m b/sr_vvms/mapoff.m
new file mode 100644
index 0000000..eae2505
--- /dev/null
+++ b/sr_vvms/mapoff.m
@@ -0,0 +1,115 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ;
+; Copyright 2001, 2013 Fidelity Information Services, Inc ;
+; ;
+; This source code contains the intellectual property ;
+; of its copyright holder(s), and is made available ;
+; under a license. If you do not know the terms of ;
+; the license, please stop and do not read further. ;
+; ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+mapoff(imgoff); get module corresponding to img+offset and print it out
+ ;
+ ; ---------- print null string and return if input is null ---------------
+ i imgoff="" write "" quit
+ ;
+ ; ---------- get image and offset ------------
+ set image=$piece(imgoff,"+",1)
+ if (image'=imgoff) set offset=$piece(imgoff,"+",2)
+ else set offset=""
+ set image=$tr(image," ","") ; remove blank space
+ ;
+ ; ---------- find out if image is part of standard image list -------------
+ set imagelst="CMISHR|CRASHANDBURN|DDPGVUSR|DDPSERVER|DSE|GDE|GTCMDDPSTOP|GTCM_SERVER|GTCM_STOP|GTMSECSHR|GTMSHR|LKE|MUPIP"
+ set index=0
+ for i=1:1:$length(imagelst,"|") quit:index'=0 do
+ . if $piece(imagelst,"|",i)=image set index=i
+ ;
+ ; ---------- print imgoff as it was input if image could not be found in imagelst -------
+ if index=0 write imgoff quit
+ ;
+ ; ---------- extract module from image map database and print it out ----------
+ set image=$tr(image,"_","")
+ set str="^"_image
+ if (0=$d(str)) write "Error : gtm$map:mapdb.dat not built. Run @gtm$tools:buildmapdb.com first. Exiting...",! quit
+ set offset=$j(offset,8)
+ set offset=$tr(offset,"abcdefghijklmnopqrstuvwxyz ","ABCDEFGHIJKLMNOPQRSTUVWXYZ0")
+ ;
+ s endoffset=$order(@str@(""),-1)
+ s dendoffset=$$FUNC^%HD(endoffset)
+ set doffset=$$FUNC^%HD(offset)
+ if doffset>dendoffset write imgoff,! quit ;
+ if (0'=$d(@str@(offset))) set boffset=offset
+ else set boffset=$order(@str@(offset),-1)
+ if boffset="" write imgoff,! quit ;
+ set bdoffset=$$FUNC^%HD(boffset)
+ set deltaoff=doffset-bdoffset
+ set delta=$$FUNC^%DH(deltaoff)
+ set delta=$j(delta,8)
+ set delta=$tr(delta,"abcdefghijklmnopqrstuvwxyz ","ABCDEFGHIJKLMNOPQRSTUVWXYZ0")
+ set module=@str@(boffset)
+ set modulestr=$j(module,20)
+ set extension=$piece(module,".",2)
+ set extension=$tr(extension,"abcdefghijklmnopqrstuvwxyz ","ABCDEFGHIJKLMNOPQRSTUVWXYZ0")
+ if extension'="C" write imgoff,modulestr,! quit
+ if $d(^offset(module))=0 d initoff(module)
+ if $d(^offset(module))=0 write "Error creating ^offset(",module,") using initoff^mapoff(",module,")",! quit
+ set origdelta=$extract(delta,5,8)
+ if (0=$d(^offset(module,delta))) set delta=$order(^offset(module,delta),-1)
+ s sdelta=$extract(delta,5,8)
+ write imgoff,modulestr," : line ",$j(^offset(module,delta,0),3)," : ",boffset,"+",origdelta
+ write " [listline ",$j(^offset(module,delta,1),4)," : ",boffset,"+",sdelta,"]",!
+ q
+ ;
+initoff(module)
+ set dev="nl:"
+ open dev
+ use dev
+ set head=$piece(module,".")
+ set name="m"_$e($j,$length($j)-6,$length($j))
+ set outfile="gtm$map:"_name_".com"
+ open outfile:newversion
+ use outfile
+ ; It is important that NO warnings are issued by the compiler as otherwise this tool's line# mapping scheme fails.
+ ; Hence the /nowarn below.
+ write "$ common_options := /standard=vaxc/share/assume=nowrit/"
+ write "float=g_float/inc=(here:,gtm$src:,decw$include,tcpip$examples:)/nowarn",!
+ write "$ ccdbg := cc'common_options'/define=(debug,nolicense)/debug/nooptimize",!
+ write "$ ccpro := cc'common_options'",!
+ write "$ ",!
+ write "$ image = f$trnlnm(""gtm$exe"")",!
+ write "$ if ((image .nes. ""GTM$PRO"") .and. (image .nes. ""GTM$DBG""))",!
+ write "$ then",!
+ write "$ write sys$output ""gtm$exe should be either gtm$pro or gtm$dbg. Exiting...""",!
+ write "$ exit",!
+ write "$ endif ",!
+ write "$ set def gtm$obj",!
+ write "$ if (image .eqs. ""GTM$PRO"")",!
+ write "$ then",!
+ write "$ ccpro/machine/list/noobj gtm$src:"_module,!
+ write "$ endif ",!
+ write "$ if (image .eqs. ""GTM$DBG"")",!
+ write "$ then",!
+ write "$ ccdbg/machine/list/noobj gtm$src:"_module,!
+ write "$ endif ",!
+ write "$",!
+ write "$ gawk -v module="""_module_""" -f gtm$tools:mapoffset.awk gtm$obj:"_head_".lis >gtm$map:"_name_".m",!
+ write "$ gtm",!
+ write "if $e($zv,6,9)]""V4.0"" d ^"_name_" quit",!
+ write "; versions <= V4.0 complain mapdb.m has too many literals. so we xecute all contents of mapdb.m instead",!
+ write "set file=""gtm$map:"_name_".m"" open file use file read str",!
+ write "for quit:str="""" xecute str read str",!
+ write "$ ",!
+ close outfile
+ use $principal
+ set zsystr="zsy ""@gtm$map:"_name_""""
+ ;write zsystr,!
+ xecute zsystr
+ zsy "delete/nolog gtm$map:"_name_".com.,"_name_".m."
+ if $e($zv,6,9)]"V4.0" zsy "delete/nolog gtm$map:"_name_".obj."
+ ;
+ ;write $j(module,24)," ",offset," ",boffset," ",delta,!
+ ;
+ use $p
+ close dev
+ quit
diff --git a/sr_vvms/mapoffset.awk b/sr_vvms/mapoffset.awk
new file mode 100644
index 0000000..08658ab
--- /dev/null
+++ b/sr_vvms/mapoffset.awk
@@ -0,0 +1,32 @@
+BEGIN {
+ dontprint = 0; insrclist = 1; cursrcline = 1; listline = 0;
+ }
+$1 == "" { dontprint = 1; }
+$1 == "
" { dontprint = 1; }
+$1 == "Routine" && $2 == "Size:" { dontprint = 1; }
+$1 == "Source" && $2 == "Listing" { dontprint = 3; }
+$1 == "Machine" && $2 == "Code" && $3 == "Listing" { dontprint = 3; }
+$1 == ".PSECT" && $2 == "$LINK$," { exit; }
+$1 == ".PSECT" { insrclist = 0; next; }
+dontprint { dontprint--; next; }
+insrclist {
+ sub("^[ 0-9][ 0-9][ 0-9][ 0-9][ 0-9][ 0-9][ 0-9][X\t]","",$0);
+ if (srcline[$1] == "")
+ srcline[$1] = cursrcline++;
+ next;
+ }
+!insrclist {
+ sub("^\t"," ",$0); # replace tabs with spaces at the beginning
+ offset = substr($0, 10, 8);
+ gsub(" ", "0", offset);
+ lastbutone = NF - 1;
+ # do not consider usages like "; R28" as a listing line number
+ if (($lastbutone == ";") && (substr($NF, 1, 1) != "R"))
+ {
+ listline = +$NF; # the "+" is to typecast $NF into a number (instead of a string)
+ printf "\tset ^offset(\"%s\",\"%s\",0)=%d\n", module, offset, srcline[listline];
+ printf "\tset ^offset(\"%s\",\"%s\",1)=%d\n", module, offset, listline;
+ }
+ }
+END {
+ }
diff --git a/sr_vvms/mcompile.c b/sr_vvms/mcompile.c
new file mode 100644
index 0000000..cb37ac5
--- /dev/null
+++ b/sr_vvms/mcompile.c
@@ -0,0 +1,18 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* DO NOT INCLUDE MDEF, IN ORDER TO AVOID UNDEF ERR_ASSERT */
+mcompile()
+{
+ void gtm$compile();
+
+ gtm$compile();
+}
diff --git a/sr_vvms/mdefsa.h b/sr_vvms/mdefsa.h
new file mode 100644
index 0000000..4cdf71c
--- /dev/null
+++ b/sr_vvms/mdefsa.h
@@ -0,0 +1,82 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef MDEFSA_included
+#define MDEFSA_included
+#include "iosb_disk.h"
+
+/* # define SHORT_SLEEP(x) hiber_start(x); */
+/* Macros on struct dsc$descriptor_s */
+#define LEN_STR_OF_DSC(d) ((d).dsc$w_length), ((d).dsc$a_pointer)
+#define STR_LEN_OF_DSC(d) ((d).dsc$a_pointer), ((d).dsc$w_length)
+#define STR_OF_DSC(d) ((d).dsc$a_pointer)
+#define LEN_OF_DSC(d) ((d).dsc$w_length)
+#define DSC_CPY(to, from) memcpy(STR_OF_DSC(to), STR_OF_DSC(from), LEN_OF_DSC(from)); \
+ LEN_OF_DSC(to) = LEN_OF_DSC(from)
+#define DSC_APND_LIT(d, lit) memcpy(STR_OF_DSC(d) + LEN_OF_DSC(d), lit, SIZEOF(lit) - 1); \
+ LEN_OF_DSC(d) += SIZEOF(lit) - 1
+#define DSC_APND_STR(d, str) memcpy(STR_OF_DSC(d) + LEN_OF_DSC(d), str, strlen(str)); \
+ LEN_OF_DSC(d) += strlen(str)
+#define DSC_APND_DSC(d, dsc) memcpy(STR_OF_DSC(d) + LEN_OF_DSC(d), STR_OF_DSC(dsc), LEN_OF_DSC(dsc)); \
+ LEN_OF_DSC(d) += LEN_OF_DSC(dsc)
+#define MVAL_TO_DSC(v, d) (d).dsc$a_pointer = (v)->str.addr, (d).dsc$w_length = (v)->str.len
+#define DSC_TO_MVAL(d, v) (v)->str.addr = (d).dsc$a_pointer, (v)->str.len = (d).dsc$w_length
+
+/* DSK_WRITE macro needs "efn.h" to be included. Use this flavor if
+ writing from the cache. Note that it is possible that the sys$synch()
+ call follows a sys$qiow in dsk_write if in compabitility mode and
+ no reformat buffers were available (SE 04/2005 V5.0)
+*/
+#define DSK_WRITE(reg, blk, cr, status) \
+{ \
+ io_status_block_disk iosb; \
+ \
+ status = dsk_write(reg, blk, cr, 0, 0, &iosb); \
+ if (status & 1) \
+ { \
+ status = sys$synch(efn_bg_qio_write, &iosb); \
+ if (SS$_NORMAL == status) \
+ status = iosb.cond; \
+ } \
+}
+/* Use this flavor if writing direct from storage (not cache buffer).
+ Note that dsk_write_nocache() always does a synchronous write.
+*/
+#define DSK_WRITE_NOCACHE(reg, blk, ptr, odv, status) \
+{ \
+ io_status_block_disk iosb; \
+ \
+ status = dsk_write_nocache(reg, blk, ptr, odv, 0, 0, &iosb); \
+ if (status & 1) \
+ status = iosb.cond; \
+}
+
+#define CHECK_CHANNEL_STATUS(stat, chan_id) \
+{ \
+ GBLREF uint4 gtmDebugLevel; \
+ GBLREF uint4 check_channel_status; \
+ GBLREF uint4 check_channel_id; \
+ \
+ if ((SS$_IVCHAN == stat) || (SS$_IVIDENT == stat)) \
+ { \
+ check_channel_status = stat; \
+ check_channel_id = chan_id; \
+ if (gtmDebugLevel) \
+ verifyAllocatedStorage(); \
+ GTMASSERT; \
+ } \
+}
+
+#define DOTM ".M"
+#define DOTOBJ ".OBJ"
+#define GTM_DIST "GTM$DIST"
+
+#endif /* MDEFSA_included */
diff --git a/sr_vvms/mem_access.c b/sr_vvms/mem_access.c
new file mode 100644
index 0000000..216849e
--- /dev/null
+++ b/sr_vvms/mem_access.c
@@ -0,0 +1,45 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "mem_access.h"
+
+#define PRT$C_NA 0
+
+/* Set a region of memory to be inaccessable */
+void set_noaccess(unsigned char *na_page[2], unsigned char *prvprt)
+/*
+unsigned char *na_page[2]; array of addresses: the low and high addresses to be protected
+unsigned char *prvprt; A place to save the previous protection, should the caller later
+ wish to restore the protection
+*/
+{
+ unsigned status;
+ status = sys$setprt (na_page, 0, 0, PRT$C_NA, prvprt);
+ if (!(status & 1))
+ rts_error(VARLSTCNT(1) status);
+ return;
+}
+
+/* Return memory protection to the state of affairs which existed prior to a call to set_noaccess */
+void reset_access(unsigned char *na_page[2], unsigned char oldprt)
+/*
+unsigned char *na_page[2]; array of addresses: the low and high addresses to be protected
+unsigned char oldprt; A place to save the previous protection, should the caller later
+ wish to restore the protection
+*/
+{
+ unsigned status;
+ status = sys$setprt (na_page, 0, 0, oldprt, 0);
+ if (!(status & 1))
+ rts_error(VARLSTCNT(1) status);
+ return;
+}
diff --git a/sr_vvms/mem_list.c b/sr_vvms/mem_list.c
new file mode 100644
index 0000000..f1696d7
--- /dev/null
+++ b/sr_vvms/mem_list.c
@@ -0,0 +1,328 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <ssdef.h> /* for SS$_NORMAL */
+#include <jpidef.h>
+#include <psldef.h> /* for PSL$C_USER */
+#include <prtdef.h> /* for PRT$C_NA */
+#include <efndef.h>
+
+#include "gdsroot.h"
+#include "ccp.h"
+#include "vmsdtype.h"
+#include "mem_list.h"
+#include "gtm_logicals.h"
+
+GBLREF mem_list *mem_list_head;
+GBLREF uint4 process_id;
+GBLREF uint4 gtm_memory_noaccess_defined; /* count of the number of GTM_MEMORY_NOACCESS_ADDR logicals which are defined */
+GBLREF uint4 gtm_memory_noaccess[GTM_MEMORY_NOACCESS_COUNT]; /* see VMS gtm_env_init_sp.c */
+
+OS_PAGE_SIZE_DECLARE
+
+error_def(ERR_SHRMEMEXHAUSTED);
+
+/* forward declarations */
+
+mem_list *coalesce_prev(mem_list *ml_ptr);
+void coalesce_next(mem_list *ml_ptr);
+mem_list *check_avail(int4 req_pages);
+
+/*-----------------------------------------------------------------------
+ coalesce this block with the previous block if it is free and adjacent
+ to the current block's address space.
+ Return the pointer to the previous link, if it got coalesced
+ ----------------------------------------------------------------------*/
+
+mem_list *coalesce_prev(mem_list *ml_ptr)
+{
+ mem_list *ml_prev = ml_ptr->prev;
+
+ assert(ml_ptr->free);
+ if (NULL != ml_prev && ml_prev->free &&
+ (ml_prev->addr == ml_ptr->addr - (ml_prev->pages * OS_PAGELET_SIZE)))
+ {
+ ml_prev->next = ml_ptr->next;
+ if (ml_prev->next)
+ ml_prev->next->prev = ml_prev;
+ ml_prev->pages += ml_ptr->pages;
+ free(ml_ptr);
+ return ml_prev;
+ }
+ return ml_ptr;
+}
+
+/*-----------------------------------------------------------------------
+ coalesce next block with this block if it is free and adjacent to the
+ current block's address space.
+ ----------------------------------------------------------------------*/
+
+void coalesce_next(mem_list *ml_ptr)
+{
+ mem_list *ml_next = ml_ptr->next;
+ if (NULL != ml_next && ml_next->free &&
+ (ml_next->addr == ml_ptr->addr + (ml_ptr->pages * OS_PAGELET_SIZE)))
+ {
+ ml_ptr->next = ml_next->next;
+ if(ml_ptr->next)
+ ml_ptr->next->prev = ml_ptr;
+ ml_ptr->pages += ml_next->pages;
+ free(ml_next);
+ }
+}
+
+/*-----------------------------------------------------------------------
+ add a link at the end of doubly linked list,
+ ----------------------------------------------------------------------*/
+
+void add_link(int4 size, int4 inadr)
+{
+ mem_list *ml_ptr, *ml_prev;
+
+ for (ml_prev = NULL, ml_ptr = mem_list_head;
+ ml_ptr != NULL;
+ ml_prev = ml_ptr, ml_ptr = ml_ptr->next)
+ ;
+
+ ml_ptr = (mem_list *)malloc(SIZEOF(mem_list));
+ ml_ptr->prev = ml_prev;
+ ml_ptr->next = NULL;
+ if (mem_list_head)
+ ml_prev->next = ml_ptr;
+ else
+ mem_list_head = ml_ptr;
+ ml_ptr->pages = size;
+ ml_ptr->free = FALSE;
+ ml_ptr->addr = inadr;
+
+}
+
+/*-----------------------------------------------------------------------
+ check mem_list, to see if an exact sized chunk is available.
+ Return pointer to the appropriate link if space is available, or NULL
+ ----------------------------------------------------------------------*/
+
+mem_list *check_avail(int4 req_pages)
+{
+ mem_list *ml_ptr;
+
+ for (ml_ptr = mem_list_head; ml_ptr != NULL; ml_ptr = ml_ptr->next)
+ {
+ if (ml_ptr->free && ml_ptr->pages == req_pages)
+ break;
+ }
+ return ml_ptr;
+}
+
+/*-----------------------------------------------------------------------
+ check the state of a particular chunk of va. If the required chunk is
+ in the list and it is free, it returns TRUE and FALSE otherwise.
+ ----------------------------------------------------------------------*/
+
+boolean_t is_va_free(uint4 outaddrs)
+{
+ mem_list *ml_ptr;
+
+ for (ml_ptr = mem_list_head; ml_ptr; ml_ptr = ml_ptr->next)
+ if (outaddrs == ml_ptr->addr)
+ break;
+ return(NULL != ml_ptr && TRUE == ml_ptr->free);
+}
+
+/*-----------------------------------------------------------------------
+ expand the address space. If an exactly enough free chunk is already available
+ from previous activities, reuse it,
+ ----------------------------------------------------------------------*/
+
+uint4 gtm_expreg(uint4 size, uint4 *inadr, uint4 acmode, uint4 region)
+{
+ uint4 status;
+ mem_list *ml_ptr;
+
+ ml_ptr = check_avail(size);
+ if (ml_ptr == NULL) /* not enough free space found or the list is empty */
+ {
+ status = gtm_expreg_noaccess_check(size, inadr, acmode, region);
+ if (status == SS$_NORMAL)
+ add_link(size, inadr[0]);
+ else if ((SS$_ILLPAGCNT == status) && ((signed int)size > 0))
+ status = ERR_SHRMEMEXHAUSTED;
+ return status;
+ }else
+ {
+ assert (size == ml_ptr->pages);
+ ml_ptr->free = FALSE;
+ inadr[0] = ml_ptr->addr;
+ inadr[1] = ml_ptr->addr + ml_ptr->pages * OS_PAGELET_SIZE - 1;
+ }
+ return SS$_NORMAL;
+}
+
+uint4 gtm_expreg_noaccess_check(uint4 size, uint4 *inadr, uint4 acmode, uint4 region)
+{
+ uint4 status, count, retadr[2];
+ DEBUG_ONLY(static uint4 numiters = 0;)
+
+ do
+ { /* allocate memory using sys$expreg, but after that check if the memory range falls within the
+ * noaccess memory specified by gtm_memory_noaccess. if so, we need to do extra processing.
+ */
+ status = sys$expreg(size, inadr, acmode, region);
+ if ((SS$_NORMAL != status) || !gtm_memory_noaccess_defined)
+ return status;
+ /* check if allocated memory range intersects with the noaccess range */
+ for (count = 0; count < gtm_memory_noaccess_defined; count++)
+ {
+ if ((inadr[0] <= gtm_memory_noaccess[count]) && (inadr[1] > gtm_memory_noaccess[count]))
+ break; /* found an intersecting memory address */
+ }
+ if (count == gtm_memory_noaccess_defined) /* could not find any intersections */
+ return status; /* return right away */
+ /* free the memory allocated just now using sys$deltva and allocate memory specifically at the noaccess
+ * address using sys$cretva, set its protection to be no-access using sys$setprt and then redo the sys$expreg.
+ * this way we will create a small inaccessible hole in the virtual address space. if some function tries
+ * to access this address we will ACCVIO and hopefully find the culprit causing the corruption.
+ */
+ status = sys$deltva(inadr, retadr, PSL$C_USER);
+ assert(SS$_NORMAL == status);
+ /* now create virtual pages at fixed address using sys$cretva
+ *
+ * there are two system calls that allocate memory for a process' virtual address space in VMS.
+ * one is SYS$EXPREG and another is SYS$CRETVA. The former satisfies a request for n-bytes at an
+ * arbitrary address while the latter does it at a fixed address. It is the former that is used
+ * throughout GT.M code (for e.g. attaching to database shared memory). The latter is not advisable
+ * unless there is a real reason. in this case we want to protect a particular memory location
+ * from any access to identify if anything is trying to read/write to that location. hence the cretva.
+ *
+ * the virtual address space of a process in VMS has 4 parts, P0, P1, P2, P3. The last two are
+ * system space and not user accessible. P0 is the user's heap and P1 is the user's stack space.
+ * Given a total of 4Gb of addressible space (2**32), P0 and P1 are each 1Gb. Any memory allocation
+ * occurs in the P0 region. sys$expreg maintains a notion of the current end of the P0 region's
+ * virtual address space. all requests for memory are given from the current end and the current end
+ * is updated accordingly. any frees (using sys$deltva) that occur in the middle of the allocated
+ * space do not decrease the current end. only freeup of memory just before the current end also
+ * update the current end. for example, let us say current end is 0. if two allocations of 4M each
+ * is done, the current end becomes 8M. If the first allocation is freed, the current end stays at 8M.
+ * but when the second allocation is freed, the current end is taken back to 0 (not 4M). this is
+ * because the free logic will coalesce as many of the free address space as possible and decrease
+ * the current end by that amount.
+ *
+ * some problems with doing sys$cretva at a specific address is that sys$expreg will consider
+ * this to be the current end of the process virtual address space. all future sys$expreg()
+ * calls will get virtual addresses higher than the return from the sys$cretva call. it is quite
+ * possible that we will get a virtual-address-space-full (VASFULL) error when we would not have got
+ * it if we had not done the sys$cretva. This is because although the sys$cretva creates only one
+ * inaccessible OS_PAGE_SIZE hole, the virtual address space between the current end (before the sys$cretva)
+ * and the specific address (that we allocated using sys$cretva) is effectively a hole because of the
+ * inherent limitation of sys$expreg call (because of its simple approach of maintaining only the current
+ * end instead of some fancy data structure) to not recognize that space as usable anymore.
+ */
+ inadr[0] = gtm_memory_noaccess[count] & ~(OS_PAGE_SIZE - 1);
+ inadr[1] = inadr[0] + OS_PAGE_SIZE - 1;
+ status = sys$cretva(inadr, NULL, PSL$C_USER);
+ assert(SS$_NORMAL == status);
+ /* GUARD the above created page for no access using sys$setprt */
+ status = sys$setprt(inadr, NULL, (uint4)PSL$C_USER, (uint4)PRT$C_NA, NULL);
+ /* at the maximum, we might need to do one iteration for each noaccess memory address. there are at most
+ * gtm_memory_noaccess_defined such addresses. ensure we do not perform more than that number of iterations.
+ */
+ DEBUG_ONLY(numiters++;)
+ assert(gtm_memory_noaccess_defined >= numiters);
+ } while (TRUE);
+}
+
+/*-----------------------------------------------------------------------
+ Delete the chunk if it is at the end of virtual address space.
+ While doing so, coalesce with any other previous adjacent free blocks
+ of address space.
+ If the given address space is not at the end of the address space,
+ just mark it free and do NOT coalesce with any other previous/next
+ adjacent free blocks, since we might get into trouble setting protection
+ on reuse of coalesced blocks.
+ ----------------------------------------------------------------------*/
+
+uint4 gtm_deltva(uint4 *outaddrs, uint4 *retadr, uint4 acmode)
+{
+ mem_list *ml_ptr, *ml_ptr_new;
+ uint4 next_free_va, status;
+ unsigned short retlen;
+ unsigned short iosb[4];
+ struct
+ {
+ item_list_3 item;
+ int4 terminator;
+ } item_list;
+
+ for (ml_ptr = mem_list_head; ml_ptr; ml_ptr = ml_ptr->next)
+ if (outaddrs[0] == ml_ptr->addr)
+ break;
+
+ /* assert(ml_ptr);
+ some regions may be deleted using gtm_deltva() that are
+ not allocated by gtm_expreg(), so may not be present in the
+ list. For example, in mu_cre_file(), we allocate using
+ sys$crmpsc() which wont make into this list but deleted
+ using gtm_deltva() */
+
+ if (NULL == ml_ptr) /* "not in list" case, delete it */
+ {
+#ifdef DEBUG
+ /* To catch the callers supplying incorrect arguments */
+ for (ml_ptr = mem_list_head; ml_ptr; ml_ptr = ml_ptr->next)
+ if ((outaddrs[0] - OS_PAGE_SIZE) == ml_ptr->addr)
+ break;
+ if (ml_ptr)
+ assert(FALSE);
+#endif
+ status = sys$deltva(outaddrs, retadr, acmode);
+ return status;
+ }
+
+ assert (FALSE == ml_ptr->free);
+
+ if (ml_ptr->next == NULL)
+ {
+ /* check if the chunk is at the end of va, so we can delete it */
+ item_list.item.buffer_length = 4;
+ item_list.item.item_code = JPI$_FREP0VA;
+ item_list.item.buffer_address = &next_free_va;
+ item_list.item.return_length_address = &retlen;
+ item_list.terminator = 0;
+ status = sys$getjpiw(EFN$C_ENF, &process_id, NULL, &item_list, iosb, NULL, 0);
+
+ if (SS$_NORMAL == status && next_free_va == outaddrs[1] + 1)
+ {
+ ml_ptr->free = TRUE;
+ for (;;) /* coalesce all the adjacent free blocks */
+ {
+ ml_ptr_new = coalesce_prev(ml_ptr);
+ if (ml_ptr == ml_ptr_new)
+ break;
+ else
+ ml_ptr = ml_ptr_new;
+ }
+ outaddrs[0] = ml_ptr_new->addr;
+
+ if (ml_ptr_new->prev == NULL)
+ mem_list_head = NULL;
+ else
+ ml_ptr_new->prev->next = NULL;
+ free(ml_ptr_new);
+
+ status = sys$deltva(outaddrs, retadr, acmode);
+ return status;
+ }
+ }
+ ml_ptr->free = TRUE;
+ return SS$_NORMAL;
+}
diff --git a/sr_vvms/mem_list.h b/sr_vvms/mem_list.h
new file mode 100644
index 0000000..cb5e6b7
--- /dev/null
+++ b/sr_vvms/mem_list.h
@@ -0,0 +1,21 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2004 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef __MEM_LIST_H__
+#define __MEM_LIST_H__
+
+void add_link(int4 size, int4 inadr);
+boolean_t is_va_free(uint4 outaddrs);
+uint4 gtm_expreg(uint4 size, uint4 *inadr, uint4 acmode, uint4 region);
+uint4 gtm_expreg_noaccess_check(uint4 size, uint4 *inadr, uint4 acmode, uint4 region);
+uint4 gtm_deltva(uint4 *outaddrs, uint4 *retadr, uint4 acmode);
+
+#endif
diff --git a/sr_vvms/movempt.com b/sr_vvms/movempt.com
new file mode 100644
index 0000000..4f639b2
--- /dev/null
+++ b/sr_vvms/movempt.com
@@ -0,0 +1,63 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2004 Sanchez Computer Associates, Inc. !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$! movempt.com - Move .mpt files from gtm$src to gtm$pct with a _ prefix
+$!
+$ if p1 .eqs. ""
+$ then
+$ write sys$output "Must supply a version"
+$ exit
+$ endif
+$!
+$ @gtm$tools:gtm_verify_symbols "set" ! sets the global symbols gtm_copy, gtm_delete, gtm_library, gtm_purge
+$ @gtm$tools:build_print_stage "movempt" "begin"
+$!
+$ @gtm$tools:setactive_silent 'p1'
+$ @gtm$tools:build_print_stage "Copying .mpt files to gtm$pct" "middle"
+$
+$ define/nolog gtm$pct gtm$root:['p1'.pct]
+$ x = f$search("gtm$src:*.mpt")
+$ if x .eqs. "" then $ goto nompt
+$
+$ set noon
+$ gtm_delete gtm$pct:_*.m.*
+$ set on
+$
+$ loop:
+$ gtm_copy/prot=(s=re,o=rwed,g=re,w=re) 'x' gtm$pct:_'f$parse(x,,,"NAME")'.m
+$ x = f$search("gtm$src:*.mpt")
+$ if x .nes. "" then $ goto loop
+$
+$nompt:
+$ if f$search("gtm$src:gtm$dmod.m") .nes. ""
+$ then
+$ gtm_copy/prot=(s=re,o=rwed,g=re,w=re) gtm$src:gtm$dmod.m gtm$pct:
+$ gtm_purge gtm$pct:gtm$dmod.m
+$ endif
+$
+$ if f$search("gtm$pct:*.obj") .nes. ""
+$ then
+$ set noon
+$ set file/prot=(w=rwed) gtm$pct:*.obj
+$ set on
+$ endif
+$
+$ set command gtm$src:GTMCOMMANDS.CLDX ! define MUMPS command if .cldx file present
+$ mumps/obj=gtm$pct: gtm$pct:*.m
+$ gtm_purge gtm$pct:*.*
+$
+$ set noon
+$ set file/prot=(s=re,w=re) gtm$pct:*.obj
+$ set on
+$!
+$ @gtm$tools:build_print_stage "movempt" "end"
+$ @gtm$tools:gtm_verify_symbols "unset" ! unsets the global symbols gtm_copy, gtm_delete gtm_library, gtm_purge
+$ exit
diff --git a/sr_vvms/msg.h b/sr_vvms/msg.h
new file mode 100644
index 0000000..8750b6b
--- /dev/null
+++ b/sr_vvms/msg.h
@@ -0,0 +1,45 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#define DEF_MSG_ARGS 16
+
+typedef struct msgstruct
+{
+ unsigned short arg_cnt; /* argument count (# longwords) */
+ unsigned short def_opts; /* default message options */
+ unsigned msg_number; /* message number */
+ unsigned short fp_cnt; /* number of fao parameters */
+ unsigned short new_opts; /* new message options */
+ union
+ {
+ unsigned char *cp;
+ unsigned n;
+ } fp[DEF_MSG_ARGS]; /* fao parameter */
+} msgtype;
+
+#define SHORT_MSG_SIZE (SIZEOF(msgtype) / SIZEOF(int4) - 5)
+#define LONG_MSG_SIZE (SIZEOF(msgtype) / SIZEOF(int4) - 1)
+#define MID_MSG_SIZE (SIZEOF(msgtype) / SIZEOF(int4) - 3)
+#define FAO_ARG SIZEOF(int4)
+#define MSG_PRINT(ARG_CNT, OPTS, NUM, FP_CNT, FP2, FP3, FP4, FP5) \
+{ \
+ msg->arg_cnt = (ARG_CNT); \
+ msg->new_opts = msg->def_opts = (OPTS); \
+ msg->msg_number = (NUM); \
+ msg->fp_cnt = (FP_CNT); \
+ msg->fp[0].n = SIZEOF(gt_lit) - 1; \
+ msg->fp[1].cp = gt_lit; \
+ msg->fp[2].n = (FP2); \
+ msg->fp[3].n = (FP3); \
+ msg->fp[4].n = (FP4); \
+ msg->fp[5].n = (FP5); \
+ sys$putmsg(msg, 0, 0, 0); \
+}
diff --git a/sr_vvms/mu_cre_file.c b/sr_vvms/mu_cre_file.c
new file mode 100644
index 0000000..e06c2a9
--- /dev/null
+++ b/sr_vvms/mu_cre_file.c
@@ -0,0 +1,308 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <fab.h>
+#include <rab.h>
+#include <nam.h>
+#include <rmsdef.h>
+#include <ssdef.h>
+#include <descrip.h>
+#include <psldef.h>
+#include <secdef.h>
+#include <syidef.h>
+#include <efndef.h>
+#include "gtm_string.h"
+
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "mlkdef.h"
+#include "efn.h"
+#include "sleep_cnt.h"
+#include "util.h"
+#include "send_msg.h"
+#include "del_sec.h"
+#include "mem_list.h"
+#include "disk_block_available.h"
+#include "init_sec.h"
+#include "mucregini.h"
+#include "mu_cre_file.h"
+#include "mu_cre_vms_structs.h"
+#include "gtmmsg.h"
+#include "wcs_sleep.h"
+#include "iosb_disk.h"
+#include "iosp.h"
+#include "iormdef.h"
+#include "shmpool.h" /* Needed for the shmpool structures */
+
+GBLREF gd_region *gv_cur_region;
+GBLREF sgmnt_data_ptr_t cs_data;
+GBLREF sgmnt_addrs *cs_addrs;
+
+#define MAX_GBL_NAME_LEN 15
+#define BLK_SIZE (((gd_segment*)gv_cur_region->dyn.addr)->blk_size)
+
+error_def(ERR_BADACCMTHD);
+error_def(ERR_DBFILERR);
+error_def(ERR_MUNOSTRMBKUP);
+error_def(ERR_LOWSPACECRE);
+
+unsigned char mu_cre_file(void)
+{
+ unsigned char *inadr[2], *c, exit_stat;
+ enum db_acc_method temp_acc_meth;
+ uint4 lcnt, retadr[2];
+ int4 blk_init_size, initial_alq, free_blocks;
+ gtm_uint64_t free_blocks_ll, blocks_for_extension;
+ char buff[GLO_NAME_MAXLEN], fn_buff[MAX_FN_LEN];
+ unsigned int status;
+ int free_space;
+ struct FAB *fcb;
+ struct NAM nam;
+ gds_file_id new_id;
+ io_status_block_disk iosb;
+ char node[16];
+ short len;
+ struct {
+ short blen;
+ short code;
+ char *buf;
+ short *len;
+ int4 terminator;
+ } item = {15, SYI$_NODENAME, &node, &len, 0};
+ $DESCRIPTOR(desc, buff);
+
+ exit_stat = EXIT_NRM;
+/* The following calculations should duplicate the BT_SIZE macro from GDSBT and the LOCK_BLOCK macro from GDSFHEAD.H,
+ * but without using a sgmnt_data which is not yet set up at this point
+ */
+
+#ifdef GT_CX_DEF
+ /* This section needs serious chnages for the fileheader changes in V5 if it is ever resurrected */
+ over_head = DIVIDE_ROUND_UP(SIZEOF_FILE_HDR_DFLT
+ + (WC_MAX_BUFFS + getprime(WC_MAX_BUFFS) + 1) * SIZEOF(bt_rec), DISK_BLOCK_SIZE);
+ if (gv_cur_region->dyn.addr->acc_meth == dba_bg)
+ {
+ free_space = over_head - DIVIDE_ROUND_UP(SIZEOF_FILE_HDR_DFLT
+ + (gv_cur_region->dyn.addr->global_buffers + getprime(gv_cur_region->dyn.addr->global_buffers) + 1)
+ * SIZEOF(bt_rec), DISK_BLOCK_SIZE);
+ over_head += gv_cur_region->dyn.addr->lock_space ? gv_cur_region->dyn.addr->lock_space
+ : DEF_LOCK_SIZE / OS_PAGELET_SIZE;
+ } else if (gv_cur_region->dyn.addr->acc_meth == dba_mm)
+ {
+ free_space = over_head - DIVIDE_ROUND_UP(SIZEOF_FILE_HDR_DFLT, DISK_BLOCK_SIZE);
+ if (gv_cur_region->dyn.addr->lock_space)
+ {
+ over_head += gv_cur_region->dyn.addr->lock_space;
+ free_space += gv_cur_region->dyn.addr->lock_space;
+ } else
+ {
+ over_head += DEF_LOCK_SIZE / OS_PAGELET_SIZE;
+ free_space += DEF_LOCK_SIZE / OS_PAGELET_SIZE;
+ }
+ }
+ free_space *= DISK_BLOCK_SIZE;
+#else
+ assert(START_VBN_CURRENT > DIVIDE_ROUND_UP(SIZEOF_FILE_HDR_DFLT, DISK_BLOCK_SIZE));
+ free_space = ((START_VBN_CURRENT - 1) * DISK_BLOCK_SIZE) - SIZEOF_FILE_HDR_DFLT;
+#endif
+ switch (gv_cur_region->dyn.addr->acc_meth)
+ {
+ case dba_bg:
+ case dba_mm:
+ mu_cre_vms_structs(gv_cur_region);
+ fcb = ((vms_gds_info *)(gv_cur_region->dyn.addr->file_cntl->file_info))->fab;
+ cs_addrs = &((vms_gds_info *)(gv_cur_region->dyn.addr->file_cntl->file_info))->s_addrs;
+
+ fcb->fab$b_shr &= FAB$M_NIL; /* No access to this file while it is created */
+ fcb->fab$l_nam = &nam;
+ nam = cc$rms_nam;
+ /* There are (bplmap - 1) non-bitmap blocks per bitmap, so add (bplmap - 2) to number of non-bitmap blocks
+ * and divide by (bplmap - 1) to get total number of bitmaps for expanded database. (must round up in this
+ * manner as every non-bitmap block must have an associated bitmap)
+ */
+ fcb->fab$l_alq += DIVIDE_ROUND_UP(fcb->fab$l_alq, BLKS_PER_LMAP - 1); /* Bitmaps */
+ blk_init_size = fcb->fab$l_alq;
+ fcb->fab$l_alq *= BLK_SIZE / DISK_BLOCK_SIZE;
+ fcb->fab$l_alq += START_VBN_CURRENT - 1;
+ initial_alq = fcb->fab$l_alq;
+ fcb->fab$w_mrs = 512; /* no longer a relevent field to us */
+ break;
+ case dba_usr:
+ util_out_print("Database file for region !AD not created; access method is not GDS.", TRUE,
+ REG_LEN_STR(gv_cur_region));
+ return EXIT_WRN;
+ default:
+ gtm_putmsg(VARLSTCNT(1) ERR_BADACCMTHD);
+ return EXIT_ERR;
+ }
+ nam.nam$b_ess = SIZEOF(fn_buff);
+ nam.nam$l_esa = fn_buff;
+ nam.nam$b_nop |= NAM$M_SYNCHK;
+ status = sys$parse(fcb, 0, 0);
+ if (RMS$_NORMAL != status)
+ {
+ gtm_putmsg(VARLSTCNT(8) ERR_DBFILERR, 2, fcb->fab$b_fns, fcb->fab$l_fna, status, 0, fcb->fab$l_stv, 0);
+ return EXIT_ERR;
+ }
+ if (nam.nam$b_node != 0)
+ {
+ status = sys$getsyiw(EFN$C_ENF, 0, 0, &item, &iosb, 0, 0);
+ if (SS$_NORMAL == status)
+ status = iosb.cond;
+ if (SS$_NORMAL == status)
+ {
+ if (len == nam.nam$b_node-2 && !memcmp(nam.nam$l_esa, node, len))
+ {
+ fcb->fab$l_fna = nam.nam$l_esa + nam.nam$b_node;
+ fcb->fab$b_fns = nam.nam$b_esl - nam.nam$b_node;
+ }
+ } else
+ {
+ util_out_print("Could not get node for !AD.", TRUE, REG_LEN_STR(gv_cur_region));
+ exit_stat = EXIT_WRN;
+ }
+ }
+ assert(gv_cur_region->dyn.addr->acc_meth == dba_bg || gv_cur_region->dyn.addr->acc_meth == dba_mm);
+ nam.nam$l_esa = NULL;
+ nam.nam$b_esl = 0;
+ status = sys$create(fcb);
+ if (status != RMS$_CREATED && status != RMS$_FILEPURGED)
+ {
+ switch(status)
+ {
+ case RMS$_FLK:
+ util_out_print("Database file for region !AD not created; currently locked by another user.", TRUE,
+ REG_LEN_STR(gv_cur_region));
+ exit_stat = EXIT_INF;
+ break;
+ case RMS$_NORMAL:
+ util_out_print("Database file for region !AD not created; already exists.", TRUE,
+ REG_LEN_STR(gv_cur_region));
+ exit_stat = EXIT_INF;
+ break;
+ case RMS$_SUPPORT:
+ util_out_print("Database file for region !AD not created; cannot create across network.", TRUE,
+ REG_LEN_STR(gv_cur_region));
+ exit_stat = EXIT_WRN;
+ break;
+ case RMS$_FUL:
+ send_msg(VARLSTCNT(8) ERR_DBFILERR, 2, fcb->fab$b_fns, fcb->fab$l_fna,
+ status, 0, fcb->fab$l_stv, 0);
+ /* intentionally falling through */
+ default:
+ gtm_putmsg(VARLSTCNT(8) ERR_DBFILERR, 2, fcb->fab$b_fns, fcb->fab$l_fna,
+ status, 0, fcb->fab$l_stv, 0);
+ exit_stat = EXIT_ERR;
+ }
+ sys$dassgn(fcb->fab$l_stv);
+ return exit_stat;
+ }
+
+ memcpy(new_id.dvi, nam.nam$t_dvi, SIZEOF(nam.nam$t_dvi));
+ memcpy(new_id.did, nam.nam$w_did, SIZEOF(nam.nam$w_did));
+ memcpy(new_id.fid, nam.nam$w_fid, SIZEOF(nam.nam$w_fid));
+ global_name("GT$S", &new_id, buff); /* 2nd parm is actually a gds_file_id * in global_name */
+ desc.dsc$w_length = buff[0]; /* By definition, a gds_file_id is dvi,fid,did from nam */
+ desc.dsc$a_pointer = &buff[1];
+ cs_addrs->db_addrs[0] = cs_addrs->db_addrs[1] = inadr[0] = inadr[1] = inadr; /* used to determine p0 or p1 allocation */
+ status = init_sec(cs_addrs->db_addrs, &desc, fcb->fab$l_stv, (START_VBN_CURRENT - 1),
+ SEC$M_DZRO|SEC$M_GBL|SEC$M_WRT|SEC$M_EXPREG);
+ if ((SS$_CREATED != status) && (SS$_NORMAL != status))
+ {
+ gtm_putmsg(VARLSTCNT(8) ERR_DBFILERR, 2, fcb->fab$b_fns, fcb->fab$l_fna, status, 0, fcb->fab$l_stv, 0);
+ sys$dassgn(fcb->fab$l_stv);
+ return EXIT_ERR;
+ }
+ cs_data = (sgmnt_data *)cs_addrs->db_addrs[0];
+ memset(cs_data, 0, SIZEOF_FILE_HDR_DFLT);
+ cs_data->createinprogress = TRUE;
+ cs_data->trans_hist.total_blks = (initial_alq - (START_VBN_CURRENT - 1)) / (BLK_SIZE / DISK_BLOCK_SIZE);
+ /* assert that total_blks stored in file-header = non-bitmap blocks (initial allocation) + bitmap blocks */
+ assert(cs_data->trans_hist.total_blks == gv_cur_region->dyn.addr->allocation +
+ DIVIDE_ROUND_UP(gv_cur_region->dyn.addr->allocation, BLKS_PER_LMAP - 1));
+ cs_data->start_vbn = START_VBN_CURRENT;
+ temp_acc_meth = gv_cur_region->dyn.addr->acc_meth;
+ cs_data->acc_meth = gv_cur_region->dyn.addr->acc_meth = dba_bg;
+ cs_data->extension_size = gv_cur_region->dyn.addr->ext_blk_count;
+ mucregini(blk_init_size);
+ cs_addrs->hdr->free_space = free_space;
+#ifndef GT_CX_DEF
+ cs_addrs->hdr->unbacked_cache = TRUE;
+#endif
+ cs_data->acc_meth = gv_cur_region->dyn.addr->acc_meth = temp_acc_meth;
+ cs_data->createinprogress = FALSE;
+ if (SS$_NORMAL == (status = disk_block_available(fcb->fab$l_stv, &free_blocks)))
+ {
+ blocks_for_extension = (cs_data->blk_size / DISK_BLOCK_SIZE *
+ (DIVIDE_ROUND_UP(EXTEND_WARNING_FACTOR * (gtm_uint64_t)cs_data->extension_size, BLKS_PER_LMAP - 1)
+ + EXTEND_WARNING_FACTOR * (gtm_uint64_t)cs_data->extension_size));
+ if ((gtm_uint64_t)free_blocks < blocks_for_extension)
+ {
+ free_blocks_ll = (gtm_uint64_t)free_blocks;
+ gtm_putmsg(VARLSTCNT(8) ERR_LOWSPACECRE, 6, fcb->fab$b_fns, fcb->fab$l_fna, EXTEND_WARNING_FACTOR,
+ &blocks_for_extension, DISK_BLOCK_SIZE, &free_blocks_ll);
+ send_msg(VARLSTCNT(8) ERR_LOWSPACECRE, 6, fcb->fab$b_fns, fcb->fab$l_fna, EXTEND_WARNING_FACTOR,
+ &blocks_for_extension, DISK_BLOCK_SIZE, &free_blocks_ll);
+ }
+ }
+ if (SS$_NORMAL == (status = sys$updsec(((vms_gds_info *)(gv_cur_region->dyn.addr->file_cntl->file_info))->s_addrs.db_addrs,
+ NULL, PSL$C_USER, 0, efn_immed_wait, &iosb, NULL, 0)))
+ {
+ status = sys$synch(efn_immed_wait, &iosb);
+ if (SS$_NORMAL == status)
+ status = iosb.cond;
+ } else if (SS$_NOTMODIFIED == status)
+ status = SS$_NORMAL;
+ if (SS$_NORMAL == status)
+ status = del_sec(SEC$M_GBL, &desc, 0);
+ if (SS$_NORMAL == status)
+ status = sys$deltva(cs_addrs->db_addrs, retadr, PSL$C_USER);
+ if (SS$_NORMAL == status)
+ status = sys$dassgn(fcb->fab$l_stv);
+ if (SS$_NORMAL == status)
+ {
+ util_out_print("Database file for region !AD created.", TRUE, REG_LEN_STR(gv_cur_region));
+ /* the open and close are an attempt to ensure that the file is available, not under the control of an ACP,
+ * before MUPIP exits */
+ fcb->fab$b_shr = FAB$M_SHRPUT | FAB$M_SHRGET | FAB$M_UPI;
+ fcb->fab$l_fop = 0;
+ for (lcnt = 1; (60 * MAX_OPEN_RETRY) >= lcnt; lcnt++)
+ { /* per VMS engineering a delay is expected. We will wait up to an hour as a
+ * Delete Global Section operation is essentially and inherently asynchronous in nature
+ * and could take an arbitrary amount of time.
+ */
+ if (RMS$_FLK != (status = sys$open(fcb, NULL, NULL)))
+ break;
+ wcs_sleep(lcnt);
+ }
+ assert(RMS$_NORMAL == status);
+ if (RMS$_NORMAL == status)
+ {
+ status = sys$close(fcb);
+ assert(RMS$_NORMAL == status);
+ }
+ if (RMS$_NORMAL != status)
+ exit_stat = EXIT_WRN;
+ } else
+ exit_stat = EXIT_ERR;
+ if (RMS$_NORMAL != status)
+ gtm_putmsg(VARLSTCNT(8) ERR_DBFILERR, 2, fcb->fab$b_fns, fcb->fab$l_fna, status, 0, fcb->fab$l_stv, 0);
+ if ((MAX_RMS_RECORDSIZE - SIZEOF(shmpool_blk_hdr)) < cs_data->blk_size)
+ gtm_putmsg(VARLSTCNT(5) ERR_MUNOSTRMBKUP, 3, fcb->fab$b_fns, fcb->fab$l_fna, 32 * 1024 - DISK_BLOCK_SIZE);
+ return exit_stat;
+}
diff --git a/sr_vvms/mu_cre_vms_structs.c b/sr_vvms/mu_cre_vms_structs.c
new file mode 100644
index 0000000..5401172
--- /dev/null
+++ b/sr_vvms/mu_cre_vms_structs.c
@@ -0,0 +1,60 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include <rmsdef.h>
+#include <fab.h>
+#include <nam.h>
+#include "filestruct.h"
+#include "mu_cre_vms_structs.h"
+
+void mu_cre_vms_structs(gd_region *reg)
+{
+ vms_gds_info *mm_info;
+ gd_segment *seg;
+
+ assert(reg->dyn.addr->acc_meth == dba_bg || reg->dyn.addr->acc_meth == dba_mm);
+ seg = reg->dyn.addr;
+ seg->file_cntl = malloc(SIZEOF(file_control));
+ switch (reg->dyn.addr->acc_meth)
+ {
+ case dba_mm:
+ case dba_bg:
+ seg->file_cntl->file_info = malloc(SIZEOF(vms_gds_info));
+ memset(seg->file_cntl->file_info,0,SIZEOF(vms_gds_info));
+ mm_info = seg->file_cntl->file_info;
+ mm_info->fab = malloc(SIZEOF(struct FAB));
+ mm_info->nam = malloc(SIZEOF(struct NAM));
+ *mm_info->fab = cc$rms_fab;
+ *mm_info->nam = cc$rms_nam;
+ mm_info->fab->fab$l_nam = mm_info->nam;
+ mm_info->fab->fab$l_alq = seg->allocation;
+ mm_info->fab->fab$l_fna = seg->fname;
+ mm_info->fab->fab$l_dna = seg->defext;
+ mm_info->fab->fab$b_fns = seg->fname_len;
+ mm_info->fab->fab$b_dns = SIZEOF(seg->defext);
+ mm_info->fab->fab$w_mrs = reg->max_rec_size;
+ mm_info->fab->fab$w_bls = reg->max_rec_size;
+ mm_info->fab->fab$w_deq = seg->ext_blk_count;
+ mm_info->fab->fab$b_org = FAB$C_SEQ;
+ mm_info->fab->fab$b_rfm = FAB$C_FIX;
+ mm_info->fab->fab$l_fop = FAB$M_UFO | FAB$M_CIF | FAB$M_CBT;
+ mm_info->fab->fab$b_fac = FAB$M_GET | FAB$M_PUT | FAB$M_BIO;
+ mm_info->fab->fab$b_shr = FAB$M_SHRPUT | FAB$M_SHRGET | FAB$M_UPI;
+ break;
+ }
+ return;
+}
diff --git a/sr_vvms/mu_cre_vms_structs.h b/sr_vvms/mu_cre_vms_structs.h
new file mode 100644
index 0000000..f46a128
--- /dev/null
+++ b/sr_vvms/mu_cre_vms_structs.h
@@ -0,0 +1,17 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef MU_CRE_VMS_STRUCTS_INCLUDED
+#define MU_CRE_VMS_STRUCTS_INCLUDED
+
+void mu_cre_vms_structs(gd_region *reg);
+
+#endif /* MU_CRE_VMS_STRUCTS_INCLUDED */
diff --git a/sr_vvms/mu_extract.c b/sr_vvms/mu_extract.c
new file mode 100644
index 0000000..1ae671c
--- /dev/null
+++ b/sr_vvms/mu_extract.c
@@ -0,0 +1,392 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <rms.h>
+#include <descrip.h>
+#include <ssdef.h>
+#include <devdef.h>
+#include <dvidef.h>
+#include <climsgdef.h>
+
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "muextr.h"
+#include "stp_parms.h"
+#include "stringpool.h"
+#include "cli.h"
+#include "util.h"
+#include "op.h"
+#include "mupip_exit.h"
+#include "gv_select.h"
+#include "mu_outofband_setup.h"
+#include "gtmmsg.h"
+#include "mvalconv.h"
+
+error_def(ERR_DBRDONLY);
+error_def(ERR_EXTRACTCTRLY);
+error_def(ERR_EXTRACTFILERR);
+error_def(ERR_EXTRCLOSEERR);
+error_def(ERR_EXTRFMT);
+error_def(ERR_EXTRIOERR);
+error_def(ERR_FREEZE);
+error_def(ERR_GTMASSERT);
+error_def(ERR_MUNOACTION);
+error_def(ERR_MUNOFINISH);
+error_def(ERR_MUPCLIERR);
+error_def(ERR_NOSELECT);
+error_def(ERR_NULLCOLLDIFF);
+error_def(ERR_RECORDSTAT);
+error_def(ERR_SELECTSYNTAX);
+
+GBLREF bool mu_ctrlc_occurred;
+GBLREF bool mu_ctrly_occurred;
+GBLREF spdesc stringpool;
+GBLREF gd_region *gv_cur_region;
+GBLREF sgmnt_data *cs_data;
+GBLREF sgmnt_addrs *cs_addrs;
+GBLREF gd_addr *gd_header;
+GBLREF gv_namehead *gv_target;
+
+#define RMS_MAX_RECORD_SIZE ((1 << 16) - 1)
+
+#define WRITE_NUMERIC(nmfield) \
+{ \
+ MV_FORCE_MVAL(&val, nmfield); \
+ stringpool.free = stringpool.base; \
+ n2s(&val); \
+ if (val.mvtype & MV_NUM_APPROX) \
+ GTMASSERT; \
+ if (val.str.len > BIN_HEADER_NUMSZ) \
+ GTMASSERT; \
+ for (iter = val.str.len; iter < BIN_HEADER_NUMSZ; iter++) \
+ *outptr++ = '0'; \
+ memcpy(outptr, val.str.addr, val.str.len); \
+ outptr += val.str.len; \
+}
+
+LITDEF mval mu_bin_datefmt = DEFINE_MVAL_LITERAL(MV_STR, 0, 0, SIZEOF(BIN_HEADER_DATEFMT) - 1, BIN_HEADER_DATEFMT, 0, 0);
+GBLDEF struct FAB mu_outfab;
+GBLDEF struct RAB mu_outrab;
+
+void mu_extract(void)
+{
+ int reg_max_rec, reg_max_key, reg_max_blk, max_extract_rec_len, status,len, i, format;
+ int reg_std_null_coll, iter;
+ unsigned char cli_buff[MAX_LINE];
+ boolean_t logqualifier, freeze = FALSE, success;
+ mval val;
+ char format_buffer[FORMAT_STR_MAX_SIZE];
+ char gbl_name_buff[MAX_MIDENT_LEN + 2]; /* 2 for null and '^' */
+ glist gl_head, *gl_ptr;
+ gd_region *reg, *region_top;
+ mu_extr_stats global_total,grand_total;
+ uint4 item_code, devbufsiz, maxfield;
+ unsigned char outfilename[256];
+ unsigned short label_len, n_len;
+ static readonly unsigned char datefmt_txt[] = "DD-MON-YEAR 24:60:SS";
+ static readonly unsigned char label_text[] = "LABEL";
+ static readonly unsigned char select_text[] = "SELECT";
+ static readonly unsigned char log_text[] = "LOG";
+ static readonly mval datefmt = DEFINE_MVAL_LITERAL(MV_STR, 0, 0, SIZEOF(datefmt_txt) - 1,
+ (char *)datefmt_txt, 0, 0);
+ static readonly mval null_str = DEFINE_MVAL_LITERAL(MV_STR, 0, 0, 0, 0, 0, 0);
+ unsigned char *outbuf, *outptr;
+ static readonly $DESCRIPTOR(label_str,label_text);
+ static readonly $DESCRIPTOR(log_str,log_text);
+ struct dsc$descriptor_s label_buff;
+ $DESCRIPTOR(dir, "");
+ coll_hdr extr_collhdr;
+
+ mu_outofband_setup();
+
+ logqualifier = (CLI$PRESENT(&log_str) != CLI$_NEGATED);
+ if (cli_present("FREEZE") == CLI_PRESENT)
+ freeze = TRUE;
+ n_len = SIZEOF(format_buffer);
+ if (cli_get_str("FORMAT", format_buffer, &n_len) == FALSE)
+ {
+ n_len = SIZEOF("ZWR") - 1;
+ MEMCPY_LIT(format_buffer, "ZWR");
+ }
+ if (memcmp(format_buffer, "ZWR", n_len) == 0)
+ format = MU_FMT_ZWR;
+ else if (memcmp(format_buffer, "GO", n_len) == 0)
+ format = MU_FMT_GO;
+ else if (memcmp(format_buffer, "BINARY", n_len) == 0)
+ format = MU_FMT_BINARY;
+ else
+ {
+ util_out_print("Extract error: bad format type",TRUE);
+ mupip_exit (ERR_EXTRFMT);
+ }
+
+ n_len = 0;
+ memset(cli_buff, 0, SIZEOF(cli_buff));
+ if (FALSE == CLI_GET_STR_ALL(select_text, cli_buff, &n_len))
+ {
+ cli_buff[0] = '*';
+ n_len = 1;
+ }
+ grand_total.recknt = grand_total.reclen = grand_total.keylen = grand_total.datalen = 0;
+ global_total.recknt = global_total.reclen = global_total.keylen = global_total.datalen = 0;
+ /* gv_select will select globals */
+ gv_select(cli_buff, n_len, freeze, select_text, &gl_head, ®_max_rec, ®_max_key, ®_max_blk, FALSE);
+ if (!gl_head.next)
+ {
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NOSELECT);
+ mupip_exit(ERR_MUNOACTION);
+ }
+ /* For binary format, check whether all regions have same null collation order */
+ if (MU_FMT_BINARY == format)
+ {
+ for (reg = gd_header->regions, region_top = gd_header->regions + gd_header->n_regions, reg_std_null_coll = -1;
+ reg < region_top ; reg++)
+ {
+ if (reg->open)
+ {
+ if (reg_std_null_coll != reg->std_null_coll)
+ {
+ if (reg_std_null_coll == -1)
+ reg_std_null_coll = reg->std_null_coll;
+ else
+ {
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_NULLCOLLDIFF);
+ mupip_exit(ERR_NULLCOLLDIFF);
+ }
+ }
+ }
+ }
+ assert(-1 != reg_std_null_coll);
+ }
+ n_len = SIZEOF(outfilename);
+ mu_outfab = cc$rms_fab;
+ mu_outrab = cc$rms_rab;
+ mu_outrab.rab$l_fab = &mu_outfab;
+ mu_outrab.rab$l_rop = RAB$M_WBH;
+ mu_outfab.fab$l_fna = &outfilename;
+ if (cli_get_str("FILE", outfilename, &n_len) == FALSE) /* should be gtmassert */
+ {
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_MUPCLIERR);
+ mupip_exit(ERR_MUNOACTION);
+ }
+ if (format == MU_FMT_BINARY)
+ max_extract_rec_len = reg_max_blk;
+ else
+ max_extract_rec_len = ZWR_EXP_RATIO(reg_max_rec);
+ if (max_extract_rec_len > RMS_MAX_RECORD_SIZE)
+ max_extract_rec_len = RMS_MAX_RECORD_SIZE;
+ mu_outfab.fab$w_mrs = max_extract_rec_len;
+ mu_outfab.fab$b_fns = n_len;
+ mu_outfab.fab$b_rat = FAB$M_CR;
+ mu_outfab.fab$l_fop = FAB$M_CBT | FAB$M_MXV | FAB$M_TEF; /* contig best try - max version - trunc at close */
+ mu_outfab.fab$b_fac = FAB$M_PUT;
+ mu_outfab.fab$l_alq = 1000; /* initial allocation */
+ mu_outfab.fab$w_deq = 1000; /* def extend quant */
+
+ status = sys$create(&mu_outfab);
+ switch (status)
+ {
+ case RMS$_NORMAL:
+ case RMS$_CRE_STM:
+ case RMS$_CREATED:
+ case RMS$_SUPERSEDE:
+ case RMS$_FILEPURGED:
+ break;
+ default:
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_EXTRACTFILERR, 2, mu_outfab.fab$b_fns, mu_outfab.fab$l_fna,
+ status, 0, mu_outfab.fab$l_stv, 0);
+ mupip_exit(ERR_MUNOACTION);
+ }
+ status = sys$connect(&mu_outrab);
+ if (status != RMS$_NORMAL)
+ {
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_EXTRACTFILERR, 2, mu_outfab.fab$b_fns, mu_outfab.fab$l_fna,
+ status, 0, mu_outfab.fab$l_stv, 0);
+ mupip_exit(ERR_MUNOACTION);
+ }
+ if (mu_outfab.fab$l_dev & DEV$M_SQD)
+ {
+ if (format == MU_FMT_BINARY)
+ maxfield = reg_max_blk;
+ else if (format == MU_FMT_ZWR)
+ maxfield = reg_max_rec*7 + reg_max_key + 1;
+ else
+ maxfield = reg_max_rec > reg_max_key ? reg_max_rec : reg_max_key;
+ item_code = DVI$_DEVBUFSIZ;
+ dir.dsc$a_pointer = mu_outfab.fab$l_fna;
+ dir.dsc$w_length = n_len;
+ devbufsiz = 0;
+ lib$getdvi(&item_code, 0, &dir, &devbufsiz, 0, 0);
+ if (devbufsiz < maxfield + 8)
+ {
+ util_out_print("!/Buffer size !UL may not accomodate maximum field size of !UL.",
+ FALSE, devbufsiz, maxfield);
+ util_out_print("!/8 bytes/tape block overhead required for device.",
+ TRUE);
+ sys$close(&mu_outfab);
+ mupip_exit(ERR_MUNOACTION);
+ }
+ }
+ label_buff.dsc$a_pointer = malloc(128);
+ label_buff.dsc$w_length = 128;
+ label_buff.dsc$b_dtype = DSC$K_DTYPE_T;
+ label_buff.dsc$b_class = DSC$K_CLASS_S;
+ if (format == MU_FMT_BINARY)
+ {
+ /* binary header label format:
+ * fixed length text, fixed length date & time,
+ * fixed length max blk size, fixed length max rec size, fixed length max key size,
+ * fixed length reg_std_null_coll,
+ * 32-byte padded user-supplied string
+ */
+ outbuf = malloc(SIZEOF(BIN_HEADER_LABEL) - 1 + SIZEOF(BIN_HEADER_DATEFMT) - 1 + 4 * BIN_HEADER_NUMSZ
+ + BIN_HEADER_LABELSZ);
+ outptr = outbuf;
+ MEMCPY_LIT(outptr, BIN_HEADER_LABEL);
+ outptr += SIZEOF(BIN_HEADER_LABEL) - 1;
+ stringpool.free = stringpool.base;
+ op_horolog (&val);
+ stringpool.free = stringpool.base;
+ op_fnzdate (&val, &mu_bin_datefmt, &null_str, &null_str, &val);
+ memcpy (outptr, val.str.addr, val.str.len);
+ outptr += val.str.len;
+
+ WRITE_NUMERIC(reg_max_blk);
+ WRITE_NUMERIC(reg_max_rec);
+ WRITE_NUMERIC(reg_max_key);
+ WRITE_NUMERIC(reg_std_null_coll);
+
+ CLI$GET_VALUE (&label_str, &label_buff, &label_len);
+ memcpy (outptr, label_buff.dsc$a_pointer, BIN_HEADER_LABELSZ);
+ if (label_len < BIN_HEADER_LABELSZ)
+ {
+ outptr += label_len;
+ for (i = label_len; i < BIN_HEADER_LABELSZ; i++)
+ *outptr++ = ' ';
+ }
+ else
+ outptr += BIN_HEADER_LABELSZ;
+
+ mu_outrab.rab$w_rsz = outptr - outbuf;
+ mu_outrab.rab$l_rbf = outbuf;
+ status = sys$put (&mu_outrab);
+ if (RMS$_NORMAL != status)
+ {
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_EXTRIOERR, 2, mu_outfab.fab$b_fns, mu_outfab.fab$l_fna,
+ status, 0, mu_outrab.rab$l_stv, 0);
+ mupip_exit(ERR_MUNOACTION);
+ }
+ }
+ else
+ {
+ assert ((MU_FMT_GO == format) || (MU_FMT_ZWR == format));
+ CLI$GET_VALUE(&label_str, &label_buff, &mu_outrab.rab$w_rsz);
+ mu_outrab.rab$l_rbf = label_buff.dsc$a_pointer;
+ status = sys$put(&mu_outrab);
+ if (RMS$_NORMAL != status)
+ {
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_EXTRIOERR, 2, mu_outfab.fab$b_fns, mu_outfab.fab$l_fna,
+ status, 0, mu_outrab.rab$l_stv, 0);
+ mupip_exit(ERR_MUNOACTION);
+ }
+ stringpool.free = stringpool.base;
+ op_horolog(&val);
+ stringpool.free = stringpool.base;
+ op_fnzdate(&val, &datefmt, &null_str, &null_str, &val);
+ if (MU_FMT_ZWR == format)
+ {
+ memcpy(val.str.addr + val.str.len, " ZWR", 4);
+ val.str.len += 4;
+ }
+ mu_outrab.rab$l_rbf = val.str.addr;
+ mu_outrab.rab$w_rsz = val.str.len;
+ status = sys$put(&mu_outrab);
+ if (RMS$_NORMAL != status)
+ {
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_EXTRIOERR, 2, mu_outfab.fab$b_fns, mu_outfab.fab$l_fna,
+ status, 0, mu_outrab.rab$l_stv, 0);
+ mupip_exit(ERR_MUNOACTION);
+ }
+ }
+ success = TRUE;
+ for (gl_ptr = gl_head.next; gl_ptr; gl_ptr = gl_ptr->next)
+ {
+ if (mu_ctrly_occurred)
+ break;
+ if (mu_ctrlc_occurred)
+ {
+ gbl_name_buff[0]='^';
+ memcpy(&gbl_name_buff[1], gl_ptr->name.str.addr, gl_ptr->name.str.len);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_RECORDSTAT, 6, gl_ptr->name.str.len + 1, gbl_name_buff,
+ global_total.recknt, global_total.keylen, global_total.datalen, global_total.reclen);
+ mu_ctrlc_occurred = FALSE;
+ }
+ GV_BIND_NAME_AND_ROOT_SEARCH(gd_header,&gl_ptr->name.str);
+ if (MU_FMT_BINARY == format)
+ {
+ extr_collhdr.act = gv_target->act;
+ extr_collhdr.nct = gv_target->nct;
+ extr_collhdr.ver = gv_target->ver;
+ mu_outrab.rab$l_rbf = (char *)(&extr_collhdr);
+ mu_outrab.rab$w_rsz = SIZEOF(extr_collhdr);
+ status = sys$put(&mu_outrab);
+ if (RMS$_NORMAL != status)
+ {
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_EXTRIOERR, 2,
+ mu_outfab.fab$b_fns, mu_outfab.fab$l_fna, status,
+ 0, mu_outrab.rab$l_stv, 0);
+ mupip_exit(ERR_MUNOACTION);
+ }
+ }
+ /* Note: Do not change the order of the expression below.
+ * Otherwise if success is FALSE, mu_extr_gblout() will not be called at all.
+ * We want mu_extr_gblout() to be called irrespective of the value of success */
+ success = mu_extr_gblout(&gl_ptr->name, &mu_outrab, &global_total, format) && success;
+ if (logqualifier)
+ {
+ gbl_name_buff[0]='^';
+ memcpy(&gbl_name_buff[1], gl_ptr->name.str.addr, gl_ptr->name.str.len);
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_RECORDSTAT, 6, gl_ptr->name.str.len + 1, gbl_name_buff,
+ global_total.recknt, global_total.keylen, global_total.datalen, global_total.reclen);
+ mu_ctrlc_occurred = FALSE;
+ }
+ grand_total.recknt += global_total.recknt;
+ if (grand_total.reclen < global_total.reclen)
+ grand_total.reclen = global_total.reclen;
+ if (grand_total.keylen < global_total.keylen)
+ grand_total.keylen = global_total.keylen;
+ if (grand_total.datalen < global_total.datalen)
+ grand_total.datalen = global_total.datalen;
+
+ }
+ status = sys$close(&mu_outfab);
+ if (status != RMS$_NORMAL)
+ {
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_EXTRCLOSEERR, 2,
+ mu_outfab.fab$b_fns, mu_outfab.fab$l_fna, status,
+ 0, mu_outfab.fab$l_stv, 0);
+ mupip_exit(ERR_MUNOACTION);
+ }
+ if (mu_ctrly_occurred)
+ {
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_EXTRACTCTRLY);
+ mupip_exit(ERR_MUNOFINISH);
+ }
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_RECORDSTAT, 6, LEN_AND_LIT("TOTAL"),
+ grand_total.recknt, grand_total.keylen, grand_total.datalen, grand_total.reclen);
+ mupip_exit(success ? SS$_NORMAL : ERR_MUNOFINISH);
+}
diff --git a/sr_vvms/mu_getlst.c b/sr_vvms/mu_getlst.c
new file mode 100644
index 0000000..add8c7f
--- /dev/null
+++ b/sr_vvms/mu_getlst.c
@@ -0,0 +1,144 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/*
+ * mu_getlst.c
+ *
+ * Description: constructs the list that is specified by "name" from cli, size of each item
+ * of the list is "size", if anything wrong happened, set error_mupip.
+ * If we are in backup, we also parse the file spec for the list.
+ *
+ * Input: char *name -- specifies cli value to get
+ * int4 size -- specifies the size of a list item
+ * bool in_backup -- specifies whether we need to parse file specs for the list.
+ * Output: tp_region *grlist -- head of the list constructed
+ * error_mupip -- set, if something wrong happened
+ */
+#include "mdef.h"
+
+#include "gtm_string.h"
+#include "gtm_limits.h"
+
+#include <descrip.h>
+#include <climsgdef.h>
+#include <strdef.h>
+#include <rms.h>
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "mupipbckup.h"
+#include "gdscc.h"
+#include "gdskill.h"
+#include "jnl.h"
+#include "buddy_list.h" /* needed for tp.h */
+#include "hashtab_int4.h" /* needed for tp.h */
+#include "tp.h"
+#include "util.h"
+#include "mu_getlst.h"
+#include "gtmmsg.h"
+
+GBLREF bool error_mupip;
+GBLREF bool in_backup;
+GBLREF bool is_directory;
+GBLREF tp_region *grlist;
+GBLREF gd_addr *gd_header;
+GBLREF boolean_t mu_star_specified;
+
+void mu_getlst(char *name, int4 size)
+{
+ unsigned char regspec_buffer[GTM_PATH_MAX], filspec_buffer[GTM_PATH_MAX];
+ unsigned short ret_len, ct;
+ gd_region *reg;
+ tp_region *list;
+ uint4 status;
+ boolean_t matched;
+
+ $DESCRIPTOR(regspec, regspec_buffer);
+ $DESCRIPTOR(filspec, filspec_buffer);
+ $DESCRIPTOR(cand_str, "");
+ $DESCRIPTOR(fili,"DIRECTORY");
+ $DESCRIPTOR(regi, "");
+ error_def(ERR_FILEPARSE);
+ error_def(ERR_TEXT);
+
+ regi.dsc$a_pointer = name;
+ regi.dsc$w_length = strlen(name);
+
+ assert(size > 0);
+ mu_star_specified = FALSE;
+
+ is_directory = FALSE;
+ for (; CLI$_ABSENT != CLI$GET_VALUE(®i, ®spec, &ret_len); regspec.dsc$w_length = MAX_FN_LEN + 1)
+ {
+ if ((1 == ret_len) && ('*' == *regspec.dsc$a_pointer))
+ mu_star_specified = TRUE;
+ regspec.dsc$w_length = ret_len;
+ reg = (gd_region *)gd_header->regions;
+ for (matched = FALSE, ct = 0 ; ct < gd_header->n_regions ; reg++, ct++)
+ {
+ cand_str.dsc$a_pointer = &(reg->rname[0]);
+ cand_str.dsc$w_length = strlen(reg->rname);
+ if(STR$_MATCH == str$match_wild(&cand_str, ®spec))
+ {
+ matched = TRUE;
+ if (NULL == (list = insert_region(reg, &(grlist), NULL, size)))
+ {
+ error_mupip = TRUE;
+ rts_error(VARLSTCNT(4) ERR_TEXT, 2, RTS_ERROR_STRING("Region not found"));
+ continue;
+ }
+ if ((FALSE == in_backup) || (0 != ((backup_reg_list *)list)->backup_file.len))
+ continue;
+ if (TRUE == is_directory)
+ {
+ assert(NULL != grlist->fPtr);
+ mubexpfilnam((backup_reg_list *)list);
+ if (error_mupip)
+ return;
+ }
+ else
+ {
+ /* get a file spec for this reg spec */
+ status = CLI$GET_VALUE(&fili, &filspec, &ret_len);
+ if ((SS$_NORMAL != status) && (CLI$_COMMA != status))
+ {
+ gtm_putmsg(VARLSTCNT(1) status);
+ error_mupip = TRUE;
+ return;
+ }
+ if (FALSE == mubgetfil((backup_reg_list *)list,
+ filspec.dsc$a_pointer,
+ ret_len))
+ {
+ gtm_putmsg(VARLSTCNT(4) ERR_FILEPARSE, 2,
+ ret_len, filspec.dsc$a_pointer);
+ error_mupip = TRUE;
+ return;
+ }
+ if ((FALSE == is_directory) && (SS$_NORMAL == status))
+ break;
+ }
+ }
+ } /* foreach region in gd_header */
+ if (FALSE == matched)
+ {
+ util_out_print("Region !AD not found.", TRUE, regspec.dsc$w_length, regspec.dsc$a_pointer);
+ error_mupip = TRUE;
+ return;
+ }
+ } /* foreach reg spec */
+
+ return;
+}
diff --git a/sr_vvms/mu_gvis.c b/sr_vvms/mu_gvis.c
new file mode 100644
index 0000000..f43337e
--- /dev/null
+++ b/sr_vvms/mu_gvis.c
@@ -0,0 +1,45 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2006 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "msg.h"
+#include "format_targ_key.h"
+#include "mu_gvis.h"
+
+GBLREF gv_key *gv_currkey;
+
+void mu_gvis(void)
+{
+ char key_buff[MAX_ZWR_KEY_SZ], *key_end;
+ msgtype msg;
+
+ error_def(ERR_GVIS);
+
+ msg.arg_cnt = 4;
+ msg.new_opts = msg.def_opts = 1;
+ msg.msg_number = ERR_GVIS;
+ msg.fp_cnt = 2;
+ if (gv_currkey->end)
+ {
+ if ((key_end = format_targ_key(&key_buff[0], MAX_ZWR_KEY_SZ, gv_currkey, TRUE)) == 0)
+ key_end = &key_buff[MAX_ZWR_KEY_SZ - 1];
+ } else
+ key_end = &key_buff[0];
+ msg.fp[0].n = key_end - key_buff;
+ msg.fp[1].cp = &key_buff[0];
+ sys$putmsg(&msg,0,0,0);
+}
diff --git a/sr_vvms/mu_load_stat.c b/sr_vvms/mu_load_stat.c
new file mode 100644
index 0000000..9e4736e
--- /dev/null
+++ b/sr_vvms/mu_load_stat.c
@@ -0,0 +1,50 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "msg.h"
+#include "mu_load_stat.h"
+
+GBLREF bool mu_ctrlc_occurred;
+
+mu_load_stat(uint4 max_data_len, uint4 max_subsc_len, uint4 key_count, uint4 rec_count, uint4 stat_type)
+{
+ static readonly unsigned char gt_lit[] = "LOAD TOTAL";
+ msgtype *msg;
+ error_def(ERR_STATCNT);
+
+ msg = malloc(SIZEOF(msgtype) + FAO_ARG);
+ msg->arg_cnt = 7;
+ msg->new_opts = msg->def_opts = 1;
+ msg->msg_number = ERR_STATCNT;
+ msg->fp_cnt = 5;
+ msg->fp[0].n = SIZEOF(gt_lit) - 1;
+ msg->fp[1].cp = gt_lit;
+ msg->fp[2].n = key_count;
+ msg->fp[3].n = max_subsc_len;
+ msg->fp[4].n = max_data_len;
+ sys$putmsg(msg,0,0,0);
+
+ msg->msg_number = stat_type;
+ msg->arg_cnt = 3;
+ msg->fp_cnt = 1;
+ msg->fp[0].n = rec_count;
+ sys$putmsg(msg,0,0,0);
+
+ mu_ctrlc_occurred = FALSE;
+ free (msg);
+}
diff --git a/sr_vvms/mu_load_stat.h b/sr_vvms/mu_load_stat.h
new file mode 100644
index 0000000..a958f7f
--- /dev/null
+++ b/sr_vvms/mu_load_stat.h
@@ -0,0 +1,18 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef MU_LOAD_STAT_INCLUDED
+#define MU_LOAD_STAT_INCLUDED
+
+int mu_load_stat(uint4 max_data_len, uint4 max_subsc_len, uint4 key_count, uint4 rec_count,
+ uint4 stat_type);
+
+#endif /* MU_LOAD_STAT_INCLUDED */
diff --git a/sr_vvms/mu_outofband_setup.c b/sr_vvms/mu_outofband_setup.c
new file mode 100644
index 0000000..9ada142
--- /dev/null
+++ b/sr_vvms/mu_outofband_setup.c
@@ -0,0 +1,61 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "efn.h"
+#include "io.h"
+#include "iottdef.h"
+#include <iodef.h>
+#include <dvidef.h>
+#include <dcdef.h>
+#include <ssdef.h>
+#include <descrip.h>
+#include <efndef.h>
+#include "mupip_ctrl.h"
+
+
+#define OUTOFBAND_MSK 0x02000008
+
+GBLREF bool mu_ctrly_occurred;
+GBLREF bool mu_ctrlc_occurred;
+
+void mu_outofband_setup(void)
+{ int4 status, channel, item_code, event;
+ uint4 devclass;
+ io_terminator mu_outofband_msk;
+ $DESCRIPTOR(sys_input,"SYS$INPUT");
+
+ if ((status = sys$assign(&sys_input,&channel,0,0)) != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+ item_code = DVI$_DEVCLASS;
+ lib$getdvi(&item_code, &channel, 0, &devclass, 0, 0);
+ if (devclass == DC$_TERM)
+ {
+ mu_outofband_msk.x = 0;
+ mu_outofband_msk.mask = OUTOFBAND_MSK;
+ if ((status = sys$qiow(EFN$C_ENF,channel
+ ,(IO$_SETMODE | IO$M_OUTBAND | IO$M_TT_ABORT)
+ ,0 ,0 ,0
+ ,mupip_ctrl
+ ,&mu_outofband_msk
+ ,0 ,0 ,0 ,0 )) != SS$_NORMAL)
+ { rts_error(VARLSTCNT(1) status);
+ }
+ event = efn_outofband;
+ status = sys$clref(event);
+ if (status != SS$_WASSET && status != SS$_WASCLR)
+ {
+ GTMASSERT;
+ }
+ }
+ mu_ctrly_occurred = mu_ctrlc_occurred = FALSE;
+ return;
+}
diff --git a/sr_vvms/mu_rndwn_file.c b/sr_vvms/mu_rndwn_file.c
new file mode 100644
index 0000000..b9b7daf
--- /dev/null
+++ b/sr_vvms/mu_rndwn_file.c
@@ -0,0 +1,607 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <efndef.h>
+#include <descrip.h>
+#include <fab.h>
+#include <iodef.h>
+#include <lckdef.h>
+#include <nam.h>
+#include <psldef.h>
+#include <rmsdef.h>
+#include <secdef.h>
+#include <ssdef.h>
+#include <syidef.h>
+
+#include "gtm_string.h"
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "efn.h"
+#include "error.h"
+#include "jnl.h"
+#include "timedef.h"
+#include "vmsdtype.h"
+#include "sleep_cnt.h"
+#include "locks.h"
+#include "mlk_shr_init.h"
+#include "mu_rndwn_file.h"
+#include "dbfilop.h"
+#include "gvcst_protos.h" /* for gvcst_init_sysops prototype */
+#include "del_sec.h"
+#include "mem_list.h"
+#include "gds_rundown.h"
+#include "init_sec.h"
+#include "gtmmsg.h"
+#include "wcs_sleep.h"
+#include "wcs_flu.h"
+#include "shmpool.h" /* Needed for the shmpool structures */
+
+#define DEF_NODE 0xFFFF
+
+GBLREF sgmnt_addrs *cs_addrs;
+GBLREF sgmnt_data *cs_data;
+GBLREF gd_region *gv_cur_region;
+GBLREF jnl_gbls_t jgbl;
+#ifdef DEBUG
+GBLREF boolean_t in_mu_rndwn_file;
+#endif
+
+LITREF char gtm_release_name[];
+LITREF int4 gtm_release_name_len;
+
+error_def(ERR_BADDBVER);
+error_def(ERR_BADGBLSECVER);
+error_def(ERR_CLSTCONFLICT);
+error_def(ERR_DBFILERR);
+error_def(ERR_DBNOTGDS);
+error_def(ERR_FILEIDGBLSEC);
+error_def(ERR_GBLSECNOTGDS);
+error_def(ERR_TEXT);
+error_def(ERR_VERMISMATCH);
+
+OS_PAGE_SIZE_DECLARE
+
+int mu_rndwn_file(bool standalone) /* operates on gv_cur_region */
+{
+ sgmnt_data *temp_cs_data;
+ jnl_private_control *jpc;
+ vms_gds_info *gds_info;
+ vms_lock_sb *file_lksb;
+ file_control *fc;
+ struct dsc$descriptor_s section;
+ uint4 flags, lcnt, size, status, dbfop_status, owner_node, node, init_status, outaddrs[2];
+ boolean_t clustered, read_write, is_bg;
+ char name_buff[GLO_NAME_MAXLEN], now_running[MAX_REL_NAME], node_buff[9];
+ typedef struct
+ {
+ item_list_3 ilist;
+ int4 terminator;
+ } syistruct;
+ syistruct syi_list;
+ unsigned short retlen, iosb[4];
+ boolean_t mu_rndwn_status;
+ node_local_ptr_t cnl;
+ gtm_uint64_t sec_size;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ mu_rndwn_status = FALSE;
+ node = 0;
+ fc = gv_cur_region->dyn.addr->file_cntl;
+ fc->op = FC_OPEN;
+ fc->file_type = dba_bg; /* note that the file_type here does not imply the access method of the database (csd->acc_meth).
+ * instead this is just an indication that database file I/O is done through sys$qiow() calls
+ * and not sys$updsec() calls to dbfilop() which in turn require a fc->file_type of dba_bg
+ * later if gvcst_init() is attempted on the same database, this gets reset appropriately.
+ */
+ dbfop_status = dbfilop(fc);
+ if (SS$_NORMAL != dbfop_status)
+ {
+ gtm_putmsg(VARLSTCNT(4) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region));
+ gtm_putmsg(VARLSTCNT(1) dbfop_status);
+ return mu_rndwn_status;
+ }
+ gds_info = FILE_INFO(gv_cur_region);
+ read_write = (FALSE == gv_cur_region->read_only);
+ syi_list.ilist.item_code = SYI$_NODE_CSID;
+ syi_list.ilist.buffer_address = &node;
+ syi_list.ilist.buffer_length = SIZEOF(node);
+ syi_list.ilist.return_length_address = &retlen;
+ syi_list.terminator = 0;
+ status = sys$getsyiw(EFN$C_ENF, NULL, NULL, &syi_list, iosb, NULL, 0);
+ if (SS$_NORMAL == status)
+ status = iosb[0];
+ if (SS$_NORMAL != status)
+ {
+ gtm_putmsg(VARLSTCNT(1) status);
+ sys$dassgn(gds_info->fab->fab$l_stv);
+ return mu_rndwn_status;
+ }
+ if (0 == node)
+ node = DEF_NODE;
+ gv_cur_region->node = node; /* Leave it so that it goes into the value block */
+ cs_addrs = &gds_info->s_addrs;
+ cs_addrs->hdr = NULL;
+ cs_addrs->nl = NULL;
+ cs_addrs->jnl = NULL;
+ cs_addrs->db_addrs[0] = cs_addrs->db_addrs[1] = NULL;
+ cs_addrs->lock_addrs[0] = cs_addrs->lock_addrs[1] = NULL;
+ ESTABLISH_RET(gds_rundown_ch, FALSE);
+ global_name("GT$S", &gds_info->file_id, name_buff);
+ section.dsc$a_pointer = &name_buff[1];
+ section.dsc$w_length = name_buff[0];
+ section.dsc$b_dtype = DSC$K_DTYPE_T;
+ section.dsc$b_class = DSC$K_CLASS_S;
+ file_lksb = &gds_info->file_cntl_lsb;
+ file_lksb->valblk[0] = gv_cur_region->node;
+ /* These locks must be taken out before mapping the file to a section, and released after unmapping the section */
+ /* Note: Rather than simply taking out this lock at PW mode, we take it out at NL mode and then convert to EX.
+ * Lock requests in the conversion queue are serviced before locks in the waiting queue; heavy GT.CX activity
+ * on a given database can potentially keep the conversion queue busy enough to keep new lock requests (especially
+ * at higher lock modes like EX) bottled up on the waiting queue indefinitely. Since NL mode lock requests are
+ * compatible with all other lock modes, they don't go on the waiting queue; they are always granted. Then the
+ * compatible with all other lock modes, and since they don't go to the waiting queue if LCK$M_EXPEDITE is specified;
+ * they are always granted. Then the subsequent conversion request will rapidly move to the head of the conversion
+ * queue and ultimately be granted.
+ */
+ status = gtm_enqw(EFN$C_ENF, LCK$K_NLMODE, file_lksb, LCK$M_SYSTEM | LCK$M_EXPEDITE,
+ §ion, 0, NULL, 0, NULL, PSL$C_USER, 0);
+ if (SS$_NORMAL == status)
+ status = file_lksb->cond;
+ if (SS$_NORMAL != status)
+ {
+ gtm_putmsg(VARLSTCNT(4) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region));
+ gtm_putmsg(VARLSTCNT(1) status);
+ sys$dassgn(gds_info->fab->fab$l_stv);
+ return mu_rndwn_status;
+ }
+ for (lcnt = 1; lcnt <= MAX_LCK_TRIES; lcnt++)
+ { /* until the following lock is available, there's a transition going on */
+ status = gtm_enq(efn_immed_wait, LCK$K_PWMODE, file_lksb, LCK$M_CONVERT | LCK$M_NOQUEUE | LCK$M_NODLCKWT,
+ NULL, 0, NULL, 0, NULL, PSL$C_USER, 0);
+ if (SS$_NORMAL == status)
+ status = file_lksb->cond;
+ if (SS$_NOTQUEUED != status)
+ break;
+ wcs_sleep(lcnt);
+ }
+ assert(MAX_LCK_TRIES > lcnt);
+ if (SS$_NORMAL == status)
+ {
+ status = gtm_enqw(EFN$C_ENF, LCK$K_EXMODE, file_lksb,
+ LCK$M_CONVERT | LCK$M_NOQUEUE | LCK$M_NODLCKWT, NULL, 0, NULL, 0, NULL, PSL$C_USER, 0);
+ if (SS$_NORMAL == status)
+ status = file_lksb->cond;
+ }
+ if (SS$_NORMAL == status)
+ { /* convert the lock from EX to PW in order to update the value of the lsb */
+ status = gtm_enqw(EFN$C_ENF, LCK$K_PWMODE, file_lksb, LCK$M_VALBLK | LCK$M_CONVERT | LCK$M_NODLCKBLK,
+ NULL, 0, NULL, 0, NULL, PSL$C_USER, 0);
+ if (SS$_NORMAL == status)
+ status = file_lksb->cond;
+ }
+ if (SS$_NORMAL != status)
+ {
+ if (SS$_NOTQUEUED == status)
+ status = RMS$_FLK;
+ gtm_putmsg(VARLSTCNT(4) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region));
+ gtm_putmsg(VARLSTCNT(1) status);
+ status = gtm_deq(file_lksb->lockid, NULL, PSL$C_USER, 0);
+ assert(SS$_NORMAL == status);
+ file_lksb->lockid = 0;
+ sys$dassgn(gds_info->fab->fab$l_stv);
+ return mu_rndwn_status;
+ }
+ /* -------------- From this point on, I should have standalone access db_init() might be pending ----------------- */
+ /* Allocate temporary storage for the database file header and read it in */
+ /* We only need to read SIZEOF(sgmnt_data) here */
+ temp_cs_data = malloc(ROUND_UP(SIZEOF(sgmnt_data), DISK_BLOCK_SIZE));
+ fc->op = FC_READ;
+ fc->op_buff = temp_cs_data;
+ fc->op_len = SGMNT_HDR_LEN;
+ fc->op_pos = 1;
+ dbfop_status = dbfilop(fc);
+ if (SS$_NORMAL != dbfop_status)
+ {
+ gtm_putmsg(VARLSTCNT(4) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region));
+ gtm_putmsg(VARLSTCNT(1) dbfop_status);
+ status = gtm_deq(file_lksb->lockid, NULL, PSL$C_USER, 0);
+ assert(SS$_NORMAL == status);
+ file_lksb->lockid = 0;
+ sys$dassgn(gds_info->fab->fab$l_stv);
+ return mu_rndwn_status;
+ }
+ if ((gv_cur_region->dyn.addr->acc_meth != temp_cs_data->acc_meth)
+ && ((dba_mm == temp_cs_data->acc_meth) || (dba_bg == temp_cs_data->acc_meth)))
+ { /* Note that it is possible that temp_cs_data->acc_meth is not MM or BG and yet is a valid global section.
+ * This is possible if that global section was created by a version of GT.M with a different database format.
+ * We will issue BADDBVER error for such sections later but until then let us work with BG access method.
+ */
+ assert(dba_cm != gv_cur_region->dyn.addr->acc_meth);
+ gv_cur_region->dyn.addr->acc_meth = temp_cs_data->acc_meth;
+ }
+ dbsecspc(gv_cur_region, temp_cs_data, &sec_size);
+ flags = SEC$M_GBL | SEC$M_SYSGBL;
+ if (is_bg = (dba_bg == temp_cs_data->acc_meth))
+ flags |= SEC$M_WRT | SEC$M_PAGFIL | SEC$M_PERM;
+ else if (read_write)
+ flags |= SEC$M_WRT;
+ status = init_status = init_sec(cs_addrs->db_addrs, §ion, gds_info->fab->fab$l_stv, sec_size, flags);
+ if ((SS$_NORMAL == init_status) || (SS$_CREATED == init_status))
+ {
+ if (!gv_cur_region->dyn.addr->fname_len)
+ { /* coming in from MUPIP RUNDOWN with no arguments. fill in filename from the global section */
+ assert(SS$_NORMAL == init_status);
+ cnl = cs_addrs->db_addrs[0];
+ assert(SIZEOF(cnl->fname) <= SIZEOF(gv_cur_region->dyn.addr->fname));
+ memcpy(gv_cur_region->dyn.addr->fname, cnl->fname, SIZEOF(cnl->fname));
+ gv_cur_region->dyn.addr->fname[SIZEOF(cnl->fname) - 1] = '\0';
+ gv_cur_region->dyn.addr->fname_len = strlen(gv_cur_region->dyn.addr->fname);
+ }
+ if (memcmp(temp_cs_data->label, GDS_LABEL, GDS_LABEL_SZ - 3))
+ status = ERR_DBNOTGDS;
+ else if (MEMCMP_LIT(temp_cs_data->label, GDS_LABEL))
+ status = ERR_BADDBVER;
+ /* the following conditions should also be reported
+ * else if (temp_cs_data->createinprogress)
+ * else if (temp_cs_data->trans_hist.curr_tn > cs_data->trans_hist.curr_tn)
+ */
+ if (SS$_NORMAL == status)
+ {
+ memcpy(now_running, temp_cs_data->now_running, MAX_REL_NAME);
+ /* issue VERMISMATCH error if now_running in node_local does not match that of the file-header.
+ * there is one exception and that is to see if now_running in the file-header is the NULL string.
+ * (this is currently possible if the last process to detach from global section had read-only
+ * access to the database and was abnormally terminated leaving the global section orphaned).
+ * in this case, we do not want to issue a VERMISMATCH error.
+ */
+ if (memcmp(now_running, gtm_release_name, gtm_release_name_len + 1) && (now_running[0]))
+ status = ERR_VERMISMATCH;
+ }
+ /* similar to the VERMISMATCH error exception above, we need to except the case owner_node is ZERO.
+ * this needs to be reworked in a much better way for V4.3-001D --- nars -- 2002/09/11
+ */
+ if ((init_status == status) && (owner_node = temp_cs_data->owner_node))
+ {
+ if ((SS$_NORMAL == status) && (node != owner_node))
+ {
+ status = ERR_CLSTCONFLICT;
+ i2hex(owner_node, node_buff, 8);
+ } else if ((SS$_CREATED == status) && read_write)
+ {
+ memset(temp_cs_data->machine_name, 0, MAX_MCNAMELEN);
+ temp_cs_data->owner_node = 0;
+ temp_cs_data->freeze = 0;
+ fc->op = FC_WRITE;
+ fc->op_len = SGMNT_HDR_LEN;
+ fc->op_pos = 1;
+ dbfop_status = dbfilop(fc);
+ if (SS$_NORMAL != dbfop_status)
+ {
+ gtm_putmsg(VARLSTCNT(4) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region));
+ gtm_putmsg(VARLSTCNT(1) dbfop_status);
+ status = gtm_deq(file_lksb->lockid, NULL, PSL$C_USER, 0);
+ assert(SS$_NORMAL == status);
+ file_lksb->lockid = 0;
+ sys$dassgn(gds_info->fab->fab$l_stv);
+ free(temp_cs_data);
+ return mu_rndwn_status;
+ }
+ }
+ }
+ }
+ if (SS$_NORMAL != status)
+ { /* Note: this includes the successful condition SS$_CREATED */
+ REVERT;
+ outaddrs[0] = cs_addrs->db_addrs[0] - OS_PAGE_SIZE; /* header no access page */
+ outaddrs[1] = cs_addrs->db_addrs[1] + OS_PAGE_SIZE; /* trailer no access page */
+ if (FALSE == is_va_free(outaddrs[0]))
+ gtm_deltva(outaddrs, NULL, PSL$C_USER);
+ /* Don't delete the global section if VERMISMATCH/CLSTCONFLICT/DBNOTGDS/BADDBVER error on an existing section */
+ if (ERR_CLSTCONFLICT != status && ERR_VERMISMATCH != status && ERR_DBNOTGDS != status && ERR_BADDBVER != status)
+ del_sec(SEC$M_SYSGBL, §ion, NULL);
+ free(temp_cs_data);
+ if ((FALSE == standalone) || (SS$_CREATED != status))
+ {
+ gtm_deq(file_lksb->lockid, NULL, PSL$C_USER, 0);
+ file_lksb->lockid = 0;
+ }
+ if (SS$_CREATED == status)
+ {
+ mu_rndwn_status = TRUE;
+ file_lksb->valblk[0] = 0; /* reset to 0 since section has been deleted */
+ sys$dassgn(gds_info->fab->fab$l_stv);
+ return mu_rndwn_status;
+ }
+ if (ERR_VERMISMATCH == status)
+ gtm_putmsg(VARLSTCNT(8) ERR_VERMISMATCH, 6, DB_LEN_STR(gv_cur_region),
+ gtm_release_name_len, gtm_release_name, LEN_AND_STR(now_running));
+ else if (ERR_CLSTCONFLICT == status)
+ gtm_putmsg(VARLSTCNT(6) ERR_CLSTCONFLICT, 4, DB_LEN_STR(gv_cur_region), SIZEOF(node_buff), node_buff);
+ else if ((ERR_DBNOTGDS == status) || (ERR_BADDBVER == status))
+ {
+ gtm_putmsg(VARLSTCNT(4) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region));
+ gtm_putmsg(VARLSTCNT(4) status, 2, GDS_LABEL_SZ - 1, GDS_LABEL);
+ } else
+ {
+ gtm_putmsg(VARLSTCNT(4) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region));
+ gtm_putmsg(VARLSTCNT(1) status);
+ }
+ sys$dassgn(gds_info->fab->fab$l_stv);
+ return mu_rndwn_status;
+ }
+ /* The database file is valid and up-to-date with respect to the file header;
+ * map global sections and establish pointers to shared memory
+ */
+ if (is_bg)
+ cs_addrs->nl = cs_addrs->db_addrs[0];
+ else
+ {
+ name_buff[4] = 'L';
+ size = ROUND_UP(LOCK_SPACE_SIZE(temp_cs_data) + NODE_LOCAL_SPACE(temp_cs_data) + JNL_SHARE_SIZE(temp_cs_data)
+ + SHMPOOL_BUFFER_SIZE, OS_PAGE_SIZE) / OS_PAGELET_SIZE;
+ status = gtm_expreg(size, cs_addrs->lock_addrs, PSL$C_USER, 0);
+ assert(cs_addrs->lock_addrs[0] + size * OS_PAGELET_SIZE - 1 == cs_addrs->lock_addrs[1]);
+ if (SS$_NORMAL == status)
+ status = init_sec(cs_addrs->lock_addrs, §ion, 0, size,
+ SEC$M_PAGFIL | SEC$M_GBL | SEC$M_WRT | SEC$M_SYSGBL);
+ if ((SS$_NORMAL != status) && (SS$_CREATED != status))
+ {
+ cs_addrs->lock_addrs[0] = NULL;
+ gtm_deq(file_lksb->lockid, NULL, PSL$C_USER, 0);
+ file_lksb->lockid = 0;
+ gtm_putmsg(VARLSTCNT(4) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region));
+ gtm_putmsg(VARLSTCNT(1) status);
+ sys$dassgn(gds_info->fab->fab$l_stv);
+ free(temp_cs_data);
+ return mu_rndwn_status;
+ }
+ cs_addrs->nl = cs_addrs->lock_addrs[0];
+ }
+ /* The handling of shared memory rundown differs between Unix and VMS in the following areas. The VMS checks above
+ * for GDS_LABEL and now_running are using the file header, whereas Unix uses shared memory. In VMS, running down
+ * an older version's partially initialized shared memory will not issue a VERMISMATCH error since now_running[0]
+ * would be 0 -- it is treated the same as the case where the last process to detach had read-only access to the
+ * database. In both cases, the Unix approach seems better.
+ */
+ if (cs_addrs->nl->glob_sec_init)
+ {
+ cs_addrs->critical = (sm_uc_ptr_t)(cs_addrs->nl) + NODE_LOCAL_SIZE;
+ /* Note: Here we check jnl_sate from database file and
+ * its value cannot change without standalone access.
+ * In other words it is not necessary to read shared memory for the test (jnl_state != jnl_notallowed)
+ * The jnl_buff buffer should be initialized irrespective of read/write process */
+ JNL_INIT(cs_addrs, gv_cur_region, temp_cs_data);
+ cs_addrs->shmpool_buffer = (shmpool_buff_hdr_ptr_t)((sm_uc_ptr_t)(cs_addrs->nl) + NODE_LOCAL_SPACE(temp_cs_data)
+ + JNL_SHARE_SIZE(temp_cs_data));
+ cs_addrs->lock_addrs[0] = (sm_uc_ptr_t)(cs_addrs->shmpool_buffer) + SHMPOOL_BUFFER_SIZE;
+ cs_addrs->lock_addrs[1] = cs_addrs->lock_addrs[0] + LOCK_SPACE_SIZE(temp_cs_data) - 1;
+ cs_data = cs_addrs->hdr = is_bg ? (cs_addrs->lock_addrs[1] + 1 + CACHE_CONTROL_SIZE(temp_cs_data))
+ : cs_addrs->db_addrs[0];
+ assert(cs_data->acc_meth == temp_cs_data->acc_meth);
+ assert((-(SIZEOF(uint4) * 2) & (uint4)cs_addrs->critical) == (uint4)cs_addrs->critical);
+ assert(0 == ((OS_PAGE_SIZE - 1) & (int)cs_addrs->critical));
+ assert(0 == ((OS_PAGE_SIZE - 1) & (int)cs_addrs->nl));
+ assert((!(JNL_ALLOWED(cs_data)))
+ || (0 == ((OS_PAGE_SIZE - 1) & (int)((char_ptr_t)cs_addrs->jnl->jnl_buff - JNL_NAME_EXP_SIZE))));
+ assert(0 == ((OS_PAGE_SIZE - 1) & (int)cs_addrs->shmpool_buffer));
+ assert(0 == ((OS_PAGE_SIZE - 1) & (int)cs_addrs->lock_addrs[0]));
+ assert(0 == ((OS_PAGE_SIZE - 1) & (int)(cs_addrs->lock_addrs[1] + 1)));
+ assert(0 == ((OS_PAGE_SIZE - 1) & (int)cs_addrs->hdr));
+ /* -------- verify pointers from our calculation vs. the copy in shared memory ---------- */
+ assert((sm_off_t)((sm_uc_ptr_t)cs_addrs->critical - (sm_uc_ptr_t)cs_addrs->nl) == cs_addrs->nl->critical);
+ assert((!(JNL_ALLOWED(cs_data))) ||
+ ((sm_off_t)((sm_uc_ptr_t)cs_addrs->jnl->jnl_buff - (sm_uc_ptr_t)cs_addrs->nl)) == cs_addrs->nl->jnl_buff);
+ assert((sm_off_t)((sm_uc_ptr_t)cs_addrs->shmpool_buffer - (sm_uc_ptr_t)cs_addrs->nl)
+ == cs_addrs->nl->shmpool_buffer);
+ assert(!is_bg || (sm_off_t)((sm_uc_ptr_t)cs_addrs->hdr - (sm_uc_ptr_t)cs_addrs->nl) == cs_addrs->nl->hdr);
+ assert((sm_off_t)((sm_uc_ptr_t)cs_addrs->lock_addrs[0] - (sm_uc_ptr_t)cs_addrs->nl) == cs_addrs->nl->lock_addrs);
+ status = SS$_NORMAL;
+ if (memcmp(cs_addrs->nl->label, GDS_LABEL, GDS_LABEL_SZ - 1))
+ {
+ name_buff[4] = 'S';
+ if (memcmp(cs_addrs->nl->label, GDS_LABEL, GDS_LABEL_SZ - 3))
+ status = ERR_GBLSECNOTGDS;
+ else
+ status = ERR_BADGBLSECVER;
+ }
+ if (SS$_NORMAL == status)
+ { /* missing the file_id.did since it came from fid_from_sec, and it's not needed for uniqueness anyway */
+ memcpy(gds_info->file_id.did, &cs_addrs->nl->unique_id.file_id[SIZEOF(gds_info->file_id.dvi)],
+ SIZEOF(gds_info->file_id.did));
+ if (memcmp(&cs_addrs->nl->unique_id.file_id[0], (char *)(&(gds_info->file_id)), SIZEOF(gds_file_id)))
+ status = ERR_FILEIDGBLSEC;
+ }
+ if (SS$_NORMAL != status)
+ {
+ cs_addrs->lock_addrs[0] = NULL;
+ gtm_deq(file_lksb->lockid, NULL, PSL$C_USER, 0);
+ file_lksb->lockid = 0;
+ if (ERR_FILEIDGBLSEC == status)
+ gtm_putmsg(VARLSTCNT(4) ERR_FILEIDGBLSEC, 2, DB_LEN_STR(gv_cur_region));
+ else
+ gtm_putmsg(VARLSTCNT(4) status, 2, name_buff[0], &name_buff[1]);
+ sys$dassgn(gds_info->fab->fab$l_stv);
+ free(temp_cs_data);
+ return mu_rndwn_status;
+ }
+ /* Check to see that the fileheader in the shared segment is valid, so we won't endup flushing garbage to db file */
+ if (memcmp(cs_data->label, GDS_LABEL, GDS_LABEL_SZ - 1))
+ {
+ cs_addrs->lock_addrs[0] = NULL;
+ gtm_deq(file_lksb->lockid, NULL, PSL$C_USER, 0);
+ file_lksb->lockid = 0;
+ if (memcmp(cs_data->label, GDS_LABEL, GDS_LABEL_SZ - 3))
+ {
+ status = ERR_DBNOTGDS;
+ outaddrs[0] = cs_addrs->db_addrs[0] - OS_PAGE_SIZE; /* header no access page */
+ outaddrs[1] = cs_addrs->db_addrs[1] + OS_PAGE_SIZE; /* trailer no access page */
+ if (FALSE == is_va_free(outaddrs[0]))
+ gtm_deltva(outaddrs, NULL, PSL$C_USER);
+ del_sec(SEC$M_SYSGBL, §ion, NULL);
+ } else
+ status = ERR_BADDBVER;
+ gtm_putmsg(VARLSTCNT(8) status, 2, DB_LEN_STR(gv_cur_region),
+ ERR_TEXT, 2, RTS_ERROR_LITERAL("File header in the shared segment seems corrupt"));
+ sys$dassgn(gds_info->fab->fab$l_stv);
+ free(temp_cs_data);
+ return mu_rndwn_status;
+ }
+ /* ------------------------- shared memory is OK --------------------------------- */
+ assert(JNL_ALLOWED(cs_data) == JNL_ALLOWED(temp_cs_data));
+ free(temp_cs_data);
+ if (is_bg)
+ db_csh_ini(cs_addrs);
+ else
+ SET_MM_BASE_ADDR(cs_addrs, cs_data);
+ cs_addrs->nl->in_crit = 0;
+ clustered = cs_data->clustered;
+ cs_data->clustered = FALSE;
+ db_common_init(gv_cur_region, cs_addrs, cs_data); /* do initialization common to db_init() and mu_rndwn_file() */
+ mlk_shr_init(cs_addrs->lock_addrs[0], cs_data->lock_space_size, cs_addrs, read_write);
+ mutex_init(cs_addrs->critical, NUM_CRIT_ENTRY(cs_data), FALSE);
+ gv_cur_region->open = TRUE;
+ DEBUG_ONLY(in_mu_rndwn_file = TRUE);
+ TREF(donot_write_inctn_in_wcs_recover) = TRUE;
+ /* If csa->nl->donotflush_dbjnl is set, it means mupip recover/rollback was interrupted and therefore we should
+ * not flush shared memory contents to disk as they might be in an inconsistent state.
+ * In this case, we will go ahead and remove shared memory (without flushing the contents) in this routine.
+ * A reissue of the recover/rollback command will restore the database to a consistent state.
+ */
+ if (!cs_addrs->nl->donotflush_dbjnl)
+ {
+ /* At this point we are holding standalone access and are about to invoke wcs_flu/wcs_recover. If
+ * one or more GT.M processes were at the midst of phase 2 commit, wcs_recover/wcs_flu invokes
+ * wcs_phase2_commit_wait to wait for the processes to complete the phase 2 commit. But, if we have
+ * standalone access, there is NO point waiting for the phase 2 commits to complete as the processes
+ * might have been killed. So, set wcs_phase2_commit_pidcnt to 0 so wcs_recover/wcs_flu skips
+ * invoking wcs_phase2_commit_wait
+ */
+ cs_addrs->nl->wcs_phase2_commit_pidcnt = 0;
+ if (is_bg)
+ { /* No WCSFLU_*_EPOCH is passed here, as we aren't sure of the state, so no EPOCHs are written.
+ * If we write an EPOCH record, recover may get confused
+ * Note that for journaling we do not call jnl_file_close() with TRUE for second parameter.
+ * As a result journal file might not have an EOF record.
+ * So, a new process will switch the journal file and cut the journal file link,
+ * though it might be a good journal without an EOF
+ */
+ wcs_flu(read_write ? WCSFLU_FLUSH_HDR : WCSFLU_NONE);
+ }
+ jpc = cs_addrs->jnl;
+ if (NULL != jpc)
+ {
+ grab_crit(gv_cur_region);
+ if (NOJNL != jpc->channel)
+ jnl_file_close(gv_cur_region, FALSE, FALSE);
+ /* release the journal file lock if we have a non-zero jnllsb->lockid */
+ if (0 != jpc->jnllsb->lockid)
+ {
+ status = gtm_deq(jpc->jnllsb->lockid, NULL, PSL$C_USER, 0);
+ assert(SS$_NORMAL == status);
+ jpc->jnllsb->lockid = 0;
+ }
+ if (NULL != jpc->jnllsb)
+ free(jpc->jnllsb);
+ free(jpc);
+ cs_addrs->jnl = NULL;
+ rel_crit(gv_cur_region);
+ }
+ }
+ DEBUG_ONLY(in_mu_rndwn_file = FALSE);
+ TREF(donot_write_inctn_in_wcs_recover) = FALSE;
+ gv_cur_region->open = FALSE;
+ if (read_write)
+ {
+ memset(cs_data->now_running, 0, SIZEOF(cs_data->now_running));
+ cs_data->owner_node = 0;
+ cs_data->freeze = 0;
+ fc->op = FC_WRITE;
+ fc->op_buff = cs_data;
+ fc->op_len = SIZEOF_FILE_HDR(cs_data); /* include master map */
+ fc->op_pos = 1;
+ dbfop_status = dbfilop(fc);
+ if (SS$_NORMAL != dbfop_status)
+ {
+ gtm_putmsg(VARLSTCNT(4) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region));
+ gtm_putmsg(VARLSTCNT(1) dbfop_status);
+ status = gtm_deq(file_lksb->lockid, NULL, PSL$C_USER, 0);
+ assert(SS$_NORMAL == status);
+ file_lksb->lockid = 0;
+ sys$dassgn(gds_info->fab->fab$l_stv);
+ return mu_rndwn_status;
+ }
+ }
+ if (cs_data->clustered = clustered) /* Note embedded assignment */
+ {
+ fc->op = FC_WRITE;
+ fc->op_buff = cs_addrs->lock_addrs[0];
+ fc->op_len = cs_data->lock_space_size;
+ fc->op_pos = LOCK_BLOCK(cs_data) + 1;
+ dbfop_status = dbfilop(fc);
+ if (SS$_NORMAL != dbfop_status)
+ {
+ gtm_putmsg(VARLSTCNT(4) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region));
+ gtm_putmsg(VARLSTCNT(1) dbfop_status);
+ status = gtm_deq(file_lksb->lockid, NULL, PSL$C_USER, 0);
+ assert(SS$_NORMAL == status);
+ file_lksb->lockid = 0;
+ sys$dassgn(gds_info->fab->fab$l_stv);
+ return mu_rndwn_status;
+ }
+ }
+ } else
+ free(temp_cs_data);
+
+ REVERT;
+ if (!is_bg)
+ {
+ cs_addrs->lock_addrs[0] = (sm_uc_ptr_t)cs_addrs->nl;
+ cs_addrs->lock_addrs[1] = cs_addrs->lock_addrs[0] + ROUND_UP(LOCK_SPACE_SIZE(cs_data) + NODE_LOCAL_SPACE(cs_data)
+ + JNL_SHARE_SIZE(cs_data) + SHMPOOL_BUFFER_SIZE, OS_PAGE_SIZE) - 1;
+ gtm_deltva(cs_addrs->lock_addrs, NULL, PSL$C_USER);
+ name_buff[4] = 'L';
+ status = del_sec(SEC$M_SYSGBL, §ion, NULL);
+ }
+ if (SS$_NORMAL == status)
+ {
+ outaddrs[0] = cs_addrs->db_addrs[0] - OS_PAGE_SIZE; /* header no access page */
+ outaddrs[1] = cs_addrs->db_addrs[1] + OS_PAGE_SIZE; /* trailer no access page */
+ if (FALSE == is_va_free(outaddrs[0]))
+ gtm_deltva(outaddrs, NULL, PSL$C_USER);
+ name_buff[4] = 'S';
+ status = del_sec(SEC$M_SYSGBL, §ion, NULL);
+ }
+ if (SS$_NORMAL != status)
+ {
+ gtm_deq(file_lksb->lockid, NULL, PSL$C_USER, 0);
+ file_lksb->lockid = 0;
+ gtm_putmsg(VARLSTCNT(4) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region));
+ gtm_putmsg(VARLSTCNT(1) status);
+ sys$dassgn(gds_info->fab->fab$l_stv);
+ return mu_rndwn_status;
+ }
+ if (FALSE == standalone)
+ {
+ gtm_deq(file_lksb->lockid, NULL, PSL$C_USER, 0);
+ file_lksb->lockid = 0;
+ } else
+ file_lksb->valblk[0] = 0; /* reset to 0 since section has been deleted */
+ mu_rndwn_status = TRUE;
+ sys$dassgn(gds_info->fab->fab$l_stv);
+ return mu_rndwn_status;
+}
diff --git a/sr_vvms/mu_rndwn_file.h b/sr_vvms/mu_rndwn_file.h
new file mode 100644
index 0000000..2f673e5
--- /dev/null
+++ b/sr_vvms/mu_rndwn_file.h
@@ -0,0 +1,17 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2002 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef MU_RNDWN_FILE_INCLUDED
+#define MU_RNDWN_FILE_INCLUDED
+
+int mu_rndwn_file(bool standalone);
+
+#endif /* MU_RNDWN_FILE_INCLUDED */
diff --git a/sr_vvms/mu_rndwn_replpool.c b/sr_vvms/mu_rndwn_replpool.c
new file mode 100644
index 0000000..a8de3ea
--- /dev/null
+++ b/sr_vvms/mu_rndwn_replpool.c
@@ -0,0 +1,148 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <ssdef.h>
+#include <prtdef.h>
+#include <secdef.h>
+#include <psldef.h>
+#include <descrip.h>
+#include <errno.h>
+#include "gtm_fcntl.h"
+#include "gtm_unistd.h"
+#include "gtm_inet.h" /* Required for gtmsource.h */
+#include <stddef.h>
+#include "gtm_stdlib.h"
+#include "gtm_string.h"
+
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "repl_sem.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "iosp.h"
+#include "repl_msg.h"
+#include "gtmsource.h"
+#include "gtmrecv.h"
+#include "gtm_logicals.h"
+#include "jnl.h"
+#include "repl_shm.h"
+#include "mu_rndwn_replpool.h"
+#include "gtmmsg.h"
+
+LITREF char gtm_release_name[];
+LITREF int4 gtm_release_name_len;
+
+error_def(ERR_VERMISMATCH);
+error_def(ERR_MUREPLPOOL);
+error_def(ERR_TEXT);
+
+#define MU_RNDWN_REPLPOOL_RETURN(RETVAL) \
+{ \
+ detach_shm(shm_range); \
+ signoff_from_gsec(shm_lockid); \
+ return RETVAL; \
+}
+
+/* runsdown the shared segment identified by replpool_id */
+
+boolean_t mu_rndwn_replpool(replpool_identifier *replpool_id, boolean_t rndwn_all, boolean_t *segment_found)
+{
+ int which_pool;
+ int4 status;
+ int4 shm_lockid;
+ sm_uc_ptr_t shm_range[2];
+ replpool_id_ptr_t rp_id_ptr;
+ struct dsc$descriptor_s name_dsc;
+
+ /* name_dsc holds the resource name */
+ *segment_found = FALSE;
+ name_dsc.dsc$a_pointer = replpool_id->repl_pool_key;
+ name_dsc.dsc$w_length = strlen(replpool_id->repl_pool_key);
+ name_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
+ name_dsc.dsc$b_class = DSC$K_CLASS_S;
+ name_dsc.dsc$a_pointer[name_dsc.dsc$w_length] = '\0';
+
+ assert(JNLPOOL_SEGMENT == replpool_id->pool_type || RECVPOOL_SEGMENT == replpool_id->pool_type);
+ which_pool = (JNLPOOL_SEGMENT == replpool_id->pool_type)? SOURCE : RECV;
+
+ if (!shm_exists(which_pool, &name_dsc))
+ return TRUE;
+ *segment_found = TRUE;
+ if (SS$_NORMAL != (status = register_with_gsec(&name_dsc, &shm_lockid)))
+ {
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_MUREPLPOOL, 2, name_dsc.dsc$w_length, name_dsc.dsc$a_pointer,
+ ERR_TEXT, 2, RTS_ERROR_LITERAL("Failed to register with replpool"), status);
+ return FALSE;
+ }
+ status = map_shm(which_pool, &name_dsc, shm_range);
+ if (SS$_NORMAL != status)
+ {
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_MUREPLPOOL, 2, name_dsc.dsc$w_length, name_dsc.dsc$a_pointer,
+ ERR_TEXT, 2, RTS_ERROR_LITERAL("Failed to map replpool segment"), status);
+ signoff_from_gsec(shm_lockid);
+ return FALSE;
+ }
+ /* assert that the replpool identifier is at the top of replpool control structure */
+ assert(0 == offsetof(jnlpool_ctl_struct, jnlpool_id));
+ assert(0 == offsetof(recvpool_ctl_struct, recvpool_id));
+
+ rp_id_ptr = (replpool_identifier *)shm_range[0];
+ if (memcmp(rp_id_ptr->label, GDS_RPL_LABEL, GDS_LABEL_SZ - 1))
+ {
+ if (!memcmp(rp_id_ptr->label, GDS_RPL_LABEL, GDS_LABEL_SZ - 3))
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_MUREPLPOOL, 2, name_dsc.dsc$w_length, name_dsc.dsc$a_pointer,
+ ERR_TEXT, 2, RTS_ERROR_LITERAL("Incorrect version for the replpool segment."));
+ else
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_MUREPLPOOL, 2, name_dsc.dsc$w_length, name_dsc.dsc$a_pointer,
+ ERR_TEXT, 2, RTS_ERROR_LITERAL("Incorrect replpool format for the segment."));
+ MU_RNDWN_REPLPOOL_RETURN(FALSE);
+ }
+ if (memcmp(rp_id_ptr->now_running, gtm_release_name, gtm_release_name_len + 1))
+ {
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(12) ERR_MUREPLPOOL, 2, name_dsc.dsc$w_length, name_dsc.dsc$a_pointer,
+ ERR_VERMISMATCH, 6, name_dsc.dsc$w_length, name_dsc.dsc$a_pointer,
+ gtm_release_name_len, gtm_release_name, LEN_AND_STR(rp_id_ptr->now_running));
+ MU_RNDWN_REPLPOOL_RETURN(FALSE);
+ }
+ if (rndwn_all)
+ memcpy(replpool_id->gtmgbldir, rp_id_ptr->gtmgbldir, MAX_FN_LEN + 1);
+ else if (strcmp(replpool_id->gtmgbldir, rp_id_ptr->gtmgbldir))
+ {
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_MUREPLPOOL, 2, name_dsc.dsc$w_length, name_dsc.dsc$a_pointer,
+ ERR_TEXT, 2, RTS_ERROR_LITERAL("Global directory name does not match that in the replpool segment."));
+ MU_RNDWN_REPLPOOL_RETURN(FALSE);
+ }
+ if (SS$_NORMAL != (status = lastuser_of_gsec(shm_lockid)))
+ {
+ if (SS$_NOTQUEUED == status)
+ {
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(8) ERR_MUREPLPOOL, 2, name_dsc.dsc$w_length, name_dsc.dsc$a_pointer,
+ ERR_TEXT, 2, RTS_ERROR_LITERAL("Replpool segment is in use by another process."));
+ } else
+ {
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_MUREPLPOOL, 2, name_dsc.dsc$w_length, name_dsc.dsc$a_pointer,
+ ERR_TEXT, 2, RTS_ERROR_LITERAL("Failed to get last_user status for replpool segment."), status);
+ }
+ MU_RNDWN_REPLPOOL_RETURN(FALSE);
+ }
+ if (SS$_NORMAL != (status = delete_shm(&name_dsc)))
+ {
+ gtm_putmsg_csa(CSA_ARG(NULL) VARLSTCNT(9) ERR_MUREPLPOOL, 2, name_dsc.dsc$w_length, name_dsc.dsc$a_pointer,
+ ERR_TEXT, 2, RTS_ERROR_LITERAL("Failed to delete replpool segment."), status);
+ MU_RNDWN_REPLPOOL_RETURN(FALSE);
+ }
+ return TRUE;
+}
diff --git a/sr_vvms/mu_rndwn_replpool.h b/sr_vvms/mu_rndwn_replpool.h
new file mode 100644
index 0000000..4e6f918
--- /dev/null
+++ b/sr_vvms/mu_rndwn_replpool.h
@@ -0,0 +1,18 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef MU_RNDWN_REPLPOOL_INCLUDED
+#define MU_RNDWN_REPLPOOL_INCLUDED
+
+boolean_t mu_rndwn_replpool(replpool_identifier *replpool_id, boolean_t rndwn_all,
+ boolean_t *segment_found);
+
+#endif /* MU_RNDWN_REPLPOOL_INCLUDED */
diff --git a/sr_vvms/mu_signal_process.c b/sr_vvms/mu_signal_process.c
new file mode 100644
index 0000000..177d88a
--- /dev/null
+++ b/sr_vvms/mu_signal_process.c
@@ -0,0 +1,118 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <descrip.h>
+#include <climsgdef.h>
+#include <ssdef.h>
+#include <jpidef.h>
+#include <signal.h>
+#include "gtm_string.h"
+#include "cli.h"
+#include "util.h"
+#include "mu_signal_process.h"
+#include "send_msg.h"
+
+static int send_signal(int, int);
+GBLREF uint4 process_id;
+
+#define SENDMSG_OUTPUT(mpname, mpid) \
+{ \
+ error_def(ERR_MUPIPSIG); \
+ if (!MEMCMP_LIT(command, STOP_STR)) \
+ send_msg(VARLSTCNT(9) ERR_MUPIPSIG, 7, LEN_AND_STR(command), signal, process_id, \
+ process_id, mpid, mpid); \
+ util_out_print("!AD issued to process !AD: (PID=!XL)", FLUSH, LEN_AND_STR(command), \
+ LEN_AND_STR(mpname), mpid); \
+}
+
+static int send_signal(int pid, int signal)
+{
+ int status;
+
+ if (SIGUSR1 == signal)
+ { /* Currently only type of posix signal used */
+ status = kill(pid, signal);
+ if (-1 == status)
+ {
+ perror("Job Interrupt request failed: ");
+ status = SS$_BADPARAM;
+ } else
+ status = SS$_NORMAL;
+ } else
+ { /* Default signal but only ERR_FORCEDHALT currently sent */
+ status = sys$forcex(&pid, 0, signal);
+ if (status != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+ }
+ return status;
+}
+
+void mu_signal_process(char *command, int signal)
+{
+ boolean_t pid_present, name_present;
+ int4 pid, length, status, item, outv;
+ char prc_nam[20];
+ unsigned short name_len;
+ $DESCRIPTOR(d_prc_nam,"");
+
+ memset(prc_nam, 0, SIZEOF(prc_nam));
+ pid_present = name_present = FALSE;
+ if (cli_present("id") == CLI_PRESENT)
+ {
+ if(!cli_get_hex("id", &pid))
+ return;
+ pid_present = TRUE;
+ }
+ if (cli_present("name") == CLI_PRESENT)
+ {
+ name_len = 20;
+ if (!cli_get_str("name", prc_nam, &name_len))
+ return;
+ if (prc_nam[name_len-1] == '"')
+ name_len--;
+ if (prc_nam[0] == '"')
+ {
+ d_prc_nam.dsc$a_pointer = &prc_nam[1];
+ name_len--;
+ } else
+ d_prc_nam.dsc$a_pointer = &prc_nam;
+ d_prc_nam.dsc$w_length = name_len;
+ name_present = TRUE;
+ }
+ if (!name_present)
+ {
+ if (SS$_NORMAL == send_signal(pid, signal))
+ SENDMSG_OUTPUT("", pid);
+ return;
+ }
+ item = JPI$_PID;
+ status = lib$getjpi(&item, 0, &d_prc_nam, &outv, 0, 0);
+ if (SS$_NORMAL != status)
+ {
+ rts_error(VARLSTCNT(1) status);
+ return;
+ }
+ if (!pid_present)
+ {
+ if (SS$_NORMAL == send_signal(outv, signal))
+ SENDMSG_OUTPUT(&prc_nam, outv);
+ return;
+ }
+ if (outv != pid)
+ {
+ util_out_print("ID !XL and NAME !AD are not the same process", FLUSH, pid, LEN_AND_STR(&prc_nam));
+ return;
+ }
+ if (SS$_NORMAL == send_signal(pid, signal))
+ SENDMSG_OUTPUT(&prc_nam, pid);
+ return;
+}
diff --git a/sr_vvms/mu_upgrd_outofband.c b/sr_vvms/mu_upgrd_outofband.c
new file mode 100644
index 0000000..9eea0ff
--- /dev/null
+++ b/sr_vvms/mu_upgrd_outofband.c
@@ -0,0 +1,58 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "efn.h"
+#include "io.h"
+#include "iottdef.h"
+#include <iodef.h>
+#include <dvidef.h>
+#include <dcdef.h>
+#include <ssdef.h>
+#include <descrip.h>
+#include <efndef.h>
+#include "mupip_ctrl.h"
+
+
+#define OUTOFBAND_MSK 0x02000008
+
+
+void mu_upgrd_outofband(void)
+{ int4 status, channel, item_code, event;
+ uint4 devclass;
+ io_terminator mu_outofband_msk;
+ $DESCRIPTOR(sys_input,"SYS$INPUT");
+
+ if ((status = sys$assign(&sys_input,&channel,0,0)) != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+ item_code = DVI$_DEVCLASS;
+ lib$getdvi(&item_code, &channel, 0, &devclass, 0, 0);
+ if (devclass == DC$_TERM)
+ {
+ mu_outofband_msk.x = 0;
+ mu_outofband_msk.mask = OUTOFBAND_MSK;
+ if ((status = sys$qiow(EFN$C_ENF,channel
+ ,(IO$_SETMODE | IO$M_OUTBAND)
+ ,0 ,0 ,0
+ ,mupip_ctrl
+ ,&mu_outofband_msk
+ ,0 ,0 ,0 ,0 )) != SS$_NORMAL)
+ { rts_error(VARLSTCNT(1) status);
+ }
+ event = efn_outofband;
+ status = sys$clref(event);
+ if (status != SS$_WASSET && status != SS$_WASCLR)
+ { rts_error(VARLSTCNT(1) );
+ }
+ }
+ return;
+}
+
diff --git a/sr_vvms/mubchkfs.c b/sr_vvms/mubchkfs.c
new file mode 100644
index 0000000..9808400
--- /dev/null
+++ b/sr_vvms/mubchkfs.c
@@ -0,0 +1,82 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <rms.h>
+#include <ssdef.h>
+#include <descrip>
+#include <dvidef>
+#include <dcdef>
+#include "util.h"
+#include "gtmmsg.h"
+
+#define DOTINC ".INC"
+#define DOTDAT ".DAT"
+
+GBLREF bool incremental;
+GBLDEF bool mubtomag=FALSE;
+
+mstr *mubchkfs (mstr *file)
+{
+ unsigned char esa[MAX_FN_LEN];
+ uint4 status, devclass;
+ struct FAB fab;
+ struct NAM nam;
+ mstr *ret;
+ $DESCRIPTOR(dir,"");
+ int4 item_code;
+
+ fab = cc$rms_fab;
+ nam = cc$rms_nam;
+ fab.fab$l_nam = &(nam);
+ fab.fab$l_fop = FAB$M_NAM;
+ fab.fab$l_fna = file->addr;
+ fab.fab$b_fns = file->len;
+ if (incremental)
+ { fab.fab$l_dna = DOTINC;
+ fab.fab$b_dns = SIZEOF(DOTINC) - 1;
+ }else
+ { fab.fab$l_dna = DOTDAT;
+ fab.fab$b_dns = SIZEOF(DOTDAT) - 1;
+ }
+ nam.nam$l_esa = esa;
+ nam.nam$b_ess = MAX_FN_LEN;
+ nam.nam$b_nop = NAM$M_SYNCHK;
+ if ((status = sys$parse(&fab,0,0)) != RMS$_NORMAL)
+ { gtm_putmsg(VARLSTCNT(1) status);
+ return NULL;
+ }else
+ { item_code = DVI$_DEVCLASS;
+ dir.dsc$a_pointer = nam.nam$l_esa;
+ dir.dsc$w_length = nam.nam$b_esl;
+ if ((status = lib$getdvi(&item_code, 0, &dir, &devclass, 0, 0)) != SS$_NORMAL)
+ { gtm_putmsg(status);
+ return NULL;
+ }
+ if (devclass == DC$_TAPE)
+ { if (!incremental)
+ { util_out_print("MUPIP cannot backup to a magnetic tape",TRUE);
+ return NULL;
+ }else
+ { mubtomag = TRUE;
+ }
+ }
+ ret = malloc(SIZEOF(mstr));
+ if (nam.nam$b_name != 0)
+ ret->len = nam.nam$b_esl;
+ else
+ ret->len = nam.nam$b_esl - nam.nam$b_type - nam.nam$b_ver;
+ ret->addr = malloc(ret->len + 1);
+ memcpy(ret->addr,nam.nam$l_esa,ret->len);
+ *(ret->addr + ret->len) = 0;
+ }
+ return ret;
+}
diff --git a/sr_vvms/mubexpfilnam.c b/sr_vvms/mubexpfilnam.c
new file mode 100644
index 0000000..015beca
--- /dev/null
+++ b/sr_vvms/mubexpfilnam.c
@@ -0,0 +1,76 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/*
+ * mubexpfilnam.c
+ *
+ * Description: expand the filename with the global mstr directory, save the result in list->backup_file
+ * and set list->backup_to to backup_to_file.
+ *
+ * Input: directory -- where directory name is kept.
+ * list->reg -- used in the call to mupfndfil() to get the filename
+ * is_directory -- must have already been set, don't even bother to check
+ * Output: list->backup_to -- should be set to backup_to_file
+ * list->backup_file -- should have directory + name of the database file
+ */
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include <rms.h>
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "mupipbckup.h"
+
+GBLREF mstr directory;
+GBLREF bool error_mupip;
+
+void mubexpfilnam (backup_reg_list *list)
+{
+ int status, len;
+ struct FAB fab;
+ struct NAM nam;
+ unsigned char es[MAX_FN_LEN];
+ mstr file;
+ char *ptr, filename[MAX_FN_LEN];
+
+ file.len = MAX_FN_LEN;
+ file.addr = filename;
+ if (!mupfndfil(list->reg, &file)) /* mupfndfil prints the error message for non-runtime */
+ {
+ error_mupip = TRUE;
+ return;
+ }
+ *(file.addr + file.len) = ';';
+ file.len++;
+ fab = cc$rms_fab;
+ nam = cc$rms_nam;
+ fab.fab$l_nam = &nam;
+ fab.fab$l_fna = file.addr;
+ fab.fab$b_fns = file.len;
+ nam.nam$b_nop = NAM$M_SYNCHK;
+ nam.nam$l_esa = es;
+ nam.nam$b_ess = SIZEOF(es);
+ status = sys$parse(&fab);
+ if (!(status & 1))
+ rts_error(VARLSTCNT(1) status);
+ list->backup_to = backup_to_file;
+ len = nam.nam$l_ver + 1 - nam.nam$l_name;
+ list->backup_file.len = directory.len + len;
+ list->backup_file.addr = malloc(list->backup_file.len+1);
+ memcpy (list->backup_file.addr, directory.addr, directory.len);
+ memcpy (list->backup_file.addr + directory.len, nam.nam$l_name, len);
+ return;
+}
diff --git a/sr_vvms/mubfilcpy.c b/sr_vvms/mubfilcpy.c
new file mode 100644
index 0000000..ec16585
--- /dev/null
+++ b/sr_vvms/mubfilcpy.c
@@ -0,0 +1,492 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <rms.h>
+#include <ssdef.h>
+#include <climsgdef.h>
+#include <iodef.h>
+#include <descrip.h>
+#include <errno.h>
+#include <errnodef.h>
+#include <efndef.h>
+#include "gtm_stdio.h"
+#include "gtm_string.h"
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "mupipbckup.h"
+#include "sleep_cnt.h"
+#include "util.h"
+#include "setfileprot.h"
+#include "gtmmsg.h"
+#include "wcs_sleep.h"
+#include "gtm_tempnam.h"
+#include "gds_blk_downgrade.h"
+#include "shmpool.h"
+#include "min_max.h"
+#include "iormdef.h"
+#include "wcs_phase2_commit_wait.h"
+
+#define MAX_TEMPFILE_TRY 16
+#define BACKUP_E_OPENOUT 0x10A38012
+#define BACKUP_W_ACCONFLICT 0x10A38410
+
+#define DELETE_BAD_BACKUP(A) \
+{ \
+ if (SS$_NORMAL == (status = sys$dassgn((A).fab$l_stv))) \
+ status = sys$erase(&(A)); \
+ if (RMS$_NORMAL != status) \
+ { \
+ gtm_putmsg(VARLSTCNT(1) status); \
+ util_out_print("Cannot delete the unsuccessful backup file !AD", TRUE, (A).fab$b_fns, (A).fab$l_fna); \
+ } \
+}
+
+GBLREF bool online;
+GBLREF bool record;
+GBLREF bool file_backed_up;
+GBLREF bool mu_ctrly_occurred;
+GBLREF bool mu_ctrlc_occurred;
+GBLREF boolean_t debug_mupip;
+GBLREF gd_region *gv_cur_region;
+GBLREF sgmnt_addrs *cs_addrs;
+GBLREF sgmnt_data_ptr_t cs_data;
+GBLREF unsigned char *mubbuf;
+GBLREF uint4 process_id;
+
+bool mubfilcpy(backup_reg_list *list)
+{
+ mstr *file;
+ char *errptr, *temp_ptr, tempfilename[MAX_FN_LEN + 1], tempdir[MAX_FN_LEN], prefix[MAX_FN_LEN];
+ char backup_ign[] = "BACKUP/IGNORE=INTERLOCK ", rename[] = "RENAME ";
+ char command_buff[SIZEOF(backup_ign)+2*MAX_FN_LEN+1]; /*= SIZEOF(backup_ign)-1+2(filenames)+2(spaces)*/
+ unsigned short wt_iosb[4];
+ uint4 status, lcnt, backup_status, vbn;
+ int4 size, tempfilelen, command_len, errlen, read_size, read_len;
+ off_t filesize_tobe, filesize_curr;
+ struct FAB *fcb, fab, temp_fab;
+ struct RAB temp_rab;
+ unsigned short old_perm;
+ sgmnt_addrs *csa;
+ sgmnt_data *header;
+ struct XABFHC xabfhc;
+ shmpool_blk_hdr_ptr_t sblkh_p;
+ sm_uc_ptr_t read_ptr, inbuf;
+ block_id blk_num;
+
+ $DESCRIPTOR(command, command_buff);
+ $DESCRIPTOR(nl, "nl:");
+
+ error_def(ERR_BACKUPCTRL);
+ error_def(ERR_BCKUPBUFLUSH);
+ error_def(ERR_COMMITWAITSTUCK);
+ error_def(ERR_DBCCERR);
+ error_def(ERR_ERRCALL);
+ error_def(ERR_TEXT);
+ error_def(ERR_TRUNCATEFAIL);
+
+ /* ============================================ initialization =================================================== */
+ file = &(list->backup_file);
+ header = list->backup_hdr;
+ fcb = ((vms_gds_info *)(gv_cur_region->dyn.addr->file_cntl->file_info))->fab;
+
+ /* ======= construct temporary filename in destination directory with region name and process id as prefix ======= */
+ temp_ptr = file->addr + file->len - 1;
+ while ((']' != *temp_ptr) && (temp_ptr > file->addr))
+ temp_ptr--;
+ if (temp_ptr > file->addr)
+ {
+ memcpy(tempdir, file->addr, temp_ptr - file->addr + 1);
+ tempdir[temp_ptr - file->addr + 1] = '\0';
+ } else
+ {
+ assert(FALSE);
+ tempdir[0] = '\0';
+ }
+ memset(prefix, 0, MAX_FN_LEN);
+ memcpy(prefix, gv_cur_region->rname, gv_cur_region->rname_len);
+ SPRINTF(&prefix[gv_cur_region->rname_len], "_%x", process_id);
+ gtm_tempnam(tempdir, prefix, tempfilename);
+ tempfilelen = strlen(tempfilename);
+
+ /* ================= construct the command to backup the database to the temporary file ========================== */
+ MEMCPY_LIT(command_buff, backup_ign);
+ command_len = SIZEOF(backup_ign) - 1;
+ memcpy(&command_buff[command_len], fcb->fab$l_fna, fcb->fab$b_fns);
+ command_len += fcb->fab$b_fns;
+ command_buff[command_len++] = ' ';
+ memcpy(&command_buff[command_len], tempfilename, tempfilelen);
+ command_len += tempfilelen;
+ command_buff[command_len] = '\0';
+ command.dsc$w_length = command_len;
+
+ /* ============================ Issue the command and check the return status ==================================== */
+ lcnt = 0;
+ do
+ {
+ if (debug_mupip)
+ util_out_print("!/MUPIP INFO: !AD", TRUE, command_len, command_buff);
+ if (SS$_NORMAL != (status = lib$spawn(&command, 0, &nl, 0, 0, 0, &backup_status, 0, 0, 0, 0, 0, 0)))
+ {
+ gtm_putmsg(VARLSTCNT(1) status);
+ util_out_print("Unable to spawn the command: !AD", TRUE, command_len, command_buff);
+ return FALSE;
+ }
+ if ((backup_status & 1) || (BACKUP_W_ACCONFLICT == backup_status))
+ break;
+ else if ((BACKUP_E_OPENOUT == backup_status) && (lcnt++ < MAX_TEMPFILE_TRY))
+ {
+ command_len -= tempfilelen;
+ gtm_tempnam(tempdir, prefix, tempfilename);
+ tempfilelen = strlen(tempfilename);
+ memcpy(&command_buff[command_len], tempfilename, tempfilelen);
+ command_len += tempfilelen;
+ command_buff[command_len] = '\0';
+ command.dsc$w_length = command_len;
+ }
+ else
+ {
+ gtm_putmsg(VARLSTCNT(1) backup_status);
+ util_out_print("Execution of command: !AD failed.", TRUE, command_len, command_buff);
+ assert(FALSE);
+ return FALSE;
+ }
+ } while (TRUE);
+
+ /* ==================== we need to apply header and for online backup, tempfile then rename =================== */
+ if (online)
+ cs_addrs->nl->nbb = BACKUP_NOT_IN_PROGRESS; /* stop everyone from writing to tempfile */
+
+ /* -------------------------- open the temp copy of the backup file ---------------------- */
+ fab = cc$rms_fab;
+ xabfhc = cc$rms_xabfhc;
+ fab.fab$b_fac = FAB$M_BIO | FAB$M_PUT;
+ fab.fab$l_fop = FAB$M_UFO;
+ fab.fab$l_fna = tempfilename;
+ fab.fab$b_fns = tempfilelen;
+ fab.fab$l_xab = &xabfhc; /* to obtain the filesize info */
+ if (!(1 & (status = sys$open(&fab))))
+ {
+ gtm_putmsg(VARLSTCNT(1) status);
+ util_out_print("ERROR: Cannot open temporary backup file !AD.", TRUE,
+ fab.fab$b_fns, fab.fab$l_fna);
+ util_out_print("Please delete it manually.", TRUE);
+ return FALSE;
+ }
+
+ if (online)
+ {
+ /* ---------------------- calculate the to-be filesize ----------------------------------- */
+ filesize_tobe = header->start_vbn +
+ (off_t)header->blk_size / DISK_BLOCK_SIZE * header->trans_hist.total_blks;
+ filesize_curr = xabfhc.xab$l_ebk;
+ /* By getting crit here, we ensure that there is no process still in transaction logic that sees
+ (nbb != BACKUP_NOT_IN_PRORESS). After rel_crit(), any process that enters transaction logic will
+ see (nbb == BACKUP_NOT_IN_PRORESS) because we just set it to that value. At this point, backup
+ buffer is complete and there will not be any more new entries in the backup buffer until the next
+ backup.
+ */
+ grab_crit(gv_cur_region);
+ assert(cs_data == cs_addrs->hdr);
+ if (dba_bg == cs_data->acc_meth)
+ { /* Now that we have crit, wait for any pending phase2 updates to finish. Since phase2 updates happen
+ * outside of crit, we dont want them to keep writing to the backup temporary file even after the
+ * backup is complete and the temporary file has been deleted.
+ */
+ if (cs_addrs->nl->wcs_phase2_commit_pidcnt && !wcs_phase2_commit_wait(cs_addrs, NULL))
+ {
+ gtm_putmsg(VARLSTCNT(7) ERR_COMMITWAITSTUCK, 5, process_id, 1,
+ cs_addrs->nl->wcs_phase2_commit_pidcnt, DB_LEN_STR(gv_cur_region));
+ rel_crit(gv_cur_region);
+ DELETE_BAD_BACKUP(fab);
+ return FALSE;
+ }
+ }
+ if (debug_mupip)
+ {
+ util_out_print("MUPIP INFO: Current Transaction # at end of backup is 0x!16 at XQ", TRUE,
+ &cs_data->trans_hist.curr_tn);
+ }
+ rel_crit(gv_cur_region);
+ /* ------------------------------- write saved blocks ------------------------------------ */
+ lcnt = 0;
+ while ((0 != cs_addrs->shmpool_buffer->backup_cnt) && (0 == cs_addrs->shmpool_buffer->failed))
+ {
+ if (0 != cs_addrs->shmpool_buffer->failed)
+ break;
+ backup_buffer_flush(gv_cur_region);
+ if (++lcnt > MAX_BACKUP_FLUSH_TRY)
+ {
+ gtm_putmsg(VARLSTCNT(1) ERR_BCKUPBUFLUSH);
+ DELETE_BAD_BACKUP(fab);
+ return FALSE;
+ }
+ if (lcnt & 0xF)
+ wcs_sleep(lcnt);
+ else
+ { /* Force recovery every few retries - this should not be happening */
+ if (FALSE == shmpool_lock_hdr(gv_cur_region))
+ {
+ assert(FALSE);
+ gtm_putmsg(VARLSTCNT(9) ERR_DBCCERR, 2, REG_LEN_STR(gv_cur_region),
+ ERR_ERRCALL, 3, CALLFROM);
+ DELETE_BAD_BACKUP(fab);
+ return FALSE;
+ }
+ shmpool_abandoned_blk_chk(gv_cur_region, TRUE);
+ shmpool_unlock_hdr(gv_cur_region);
+ }
+ }
+
+ /* --- Verify that no errors from M processes during the backup --- */
+ if (0 != cs_addrs->shmpool_buffer->failed)
+ {
+ util_out_print("Process !XL encountered the following error.", TRUE,
+ cs_addrs->shmpool_buffer->failed);
+ if (0 != cs_addrs->shmpool_buffer->backup_errno)
+ gtm_putmsg(VARLSTCNT(1) cs_addrs->shmpool_buffer->backup_errno);
+ DELETE_BAD_BACKUP(fab);
+ return FALSE;
+ }
+
+ /* --- Open the temporary file (identical to mubinccpy.c) --- */
+ temp_fab = cc$rms_fab;
+ temp_fab.fab$b_fac = FAB$M_GET;
+ temp_fab.fab$l_fna = list->backup_tempfile;
+ temp_fab.fab$b_fns = strlen(list->backup_tempfile); /* double check here */
+ temp_rab = cc$rms_rab;
+ temp_rab.rab$l_fab = &temp_fab;
+
+ for (lcnt = 1; MAX_OPEN_RETRY >= lcnt; lcnt++)
+ {
+ if (RMS$_FLK != (status = sys$open(&temp_fab, NULL, NULL)))
+ break;
+ wcs_sleep(lcnt);
+ }
+ if ((RMS$_NORMAL != status) || (RMS$_NORMAL != (status = sys$connect(&temp_rab))))
+ {
+ gtm_putmsg(VARLSTCNT(1) status);
+ util_out_print("WARNING: DB file !AD backup aborted.", TRUE, fcb->fab$b_fns, fcb->fab$l_fna);
+ DELETE_BAD_BACKUP(fab);
+ return FALSE;
+ }
+
+ /* --- read and write every record in the temporary file (different from mubinccpy.c) --- */
+ sblkh_p = (shmpool_blk_hdr_ptr_t)mubbuf;
+ inbuf = (sm_uc_ptr_t)(sblkh_p + 1);
+ while (TRUE)
+ { /* Due to RMS restrictions we may have to do more than one read to pull in entire record/blk */
+ read_size = SIZEOF(*sblkh_p) + header->blk_size;
+ read_ptr = mubbuf;
+ while (read_size)
+ {
+ read_len = MIN(MAX_RMS_RECORDSIZE, read_size);
+ temp_rab.rab$w_usz = read_len;
+ temp_rab.rab$l_ubf = read_ptr;
+ status = sys$get(&temp_rab);
+ if (RMS$_NORMAL != status)
+ {
+ if (RMS$_EOF == status)
+ break;
+ else
+ {
+ gtm_putmsg(VARLSTCNT(1) status);
+ util_out_print("WARNING: DB file !AD backup aborted.", TRUE,
+ fcb->fab$b_fns, fcb->fab$l_fna);
+ DELETE_BAD_BACKUP(fab);
+ return FALSE;
+ }
+ }
+ read_ptr += read_len;
+ read_size -= read_len;
+ }
+ if (RMS$_EOF == status)
+ break;
+ /* Update block in database backup if it exists */
+ blk_num = sblkh_p->blkid;
+ if (header->trans_hist.total_blks <= blk_num)
+ /* Ignore block outside of db range at time of backup initiation */
+ continue;
+ if (debug_mupip)
+ util_out_print("MUPIP INFO: Restoring block 0x!XL from temporary file.",
+ TRUE, blk_num);
+ vbn = header->start_vbn + blk_num * (header->blk_size / DISK_BLOCK_SIZE);
+ /* If the incoming block has an ondisk version of V4, convert it back to that
+ version before writing it out so it is the same as the block in the original
+ database.
+ */
+ if (GDSV4 == sblkh_p->use.bkup.ondsk_blkver)
+ { /* Need to downgrade this block back to a previous format. Downgrade in place. */
+ gds_blk_downgrade((v15_blk_hdr_ptr_t)inbuf, (blk_hdr_ptr_t)inbuf);
+ size = (((v15_blk_hdr_ptr_t)inbuf)->bsiz + 1) & ~1;
+ } else
+ size = (((blk_hdr_ptr_t)inbuf)->bsiz + 1) & ~1;
+
+ if (cs_addrs->do_fullblockwrites)
+ size = ROUND_UP(size, cs_addrs->fullblockwrite_len);
+ assert(cs_addrs->hdr->blk_size >= size);
+ if (SS$_NORMAL != (status = sys$qiow(EFN$C_ENF, fab.fab$l_stv, IO$_WRITEVBLK, &wt_iosb[0], 0, 0,
+ inbuf, size, vbn,0,0,0))
+ || SS$_NORMAL != (status = wt_iosb[0]))
+ {
+ gtm_putmsg(VARLSTCNT(1) status);
+ util_out_print("ERROR: Failed writing data to backup file !AD.", TRUE,
+ fab.fab$b_fns, fab.fab$l_fna);
+ DELETE_BAD_BACKUP(fab);
+ return FALSE;
+ }
+ if (wt_iosb[1] != size)
+ {
+ util_out_print("ERROR: !UL bytes, instead of !UL bytes, were written to !AD.", TRUE,
+ wt_iosb[1], size, fab.fab$b_fns, fab.fab$l_fna);
+ DELETE_BAD_BACKUP(fab);
+ return FALSE;
+ }
+ if (mu_ctrly_occurred || mu_ctrlc_occurred)
+ {
+ gtm_putmsg(VARLSTCNT(1) ERR_BACKUPCTRL);
+ util_out_print("WARNING: DB file !AD backup aborted.", TRUE,
+ fcb->fab$b_fns, fcb->fab$l_fna);
+ DELETE_BAD_BACKUP(fab);
+ return FALSE;
+ }
+ }
+
+ /* --- close the temporary file (identical to mubinccpy.c) --- */
+ if (RMS$_NORMAL != (status = sys$close(&temp_fab)))
+ {
+ gtm_putmsg(VARLSTCNT(1) status);
+ util_out_print("WARNING: DB file !AD backup aborted.", TRUE, fcb->fab$b_fns, fcb->fab$l_fna);
+ DELETE_BAD_BACKUP(fab);
+ return FALSE;
+ }
+ } /* if (online) */
+
+ /* -------------------------------- write header ----------------------------------------- */
+ size = ROUND_UP(SIZEOF_FILE_HDR(header), DISK_BLOCK_SIZE);
+ assert(size <= 64 * 1024); /* Max we can write testing "short" iosb fields */
+ status = sys$qiow(EFN$C_ENF, fab.fab$l_stv, IO$_WRITEVBLK, &wt_iosb[0], 0, 0, header, size, 1, 0, 0, 0);
+ if (SS$_NORMAL != status || SS$_NORMAL != (status = wt_iosb[0]))
+ {
+ gtm_putmsg(VARLSTCNT(1) status);
+ util_out_print("ERROR: Failed writing database header to backup file !AD.", TRUE,
+ fab.fab$b_fns, fab.fab$l_fna);
+ DELETE_BAD_BACKUP(fab);
+ return FALSE;
+ }
+ if (wt_iosb[1] != size)
+ {
+ util_out_print("ERROR: !UL bytes, instead of !UL bytes, were written to !AD.", TRUE,
+ wt_iosb[1], size, fab.fab$b_fns, fab.fab$l_fna);
+ DELETE_BAD_BACKUP(fab);
+ return FALSE;
+ }
+ if (mu_ctrly_occurred || mu_ctrlc_occurred)
+ {
+ gtm_putmsg(VARLSTCNT(1) ERR_BACKUPCTRL);
+ util_out_print("WARNING: DB file !AD backup aborted.", TRUE, fcb->fab$b_fns, fcb->fab$l_fna);
+ DELETE_BAD_BACKUP(fab);
+ return FALSE;
+ }
+
+ /* --------------- close the temp copy of the backup file ---------------------------------------------- */
+ if (SS$_NORMAL != (status = sys$dassgn(fab.fab$l_stv)))
+ {
+ gtm_putmsg(VARLSTCNT(1) status);
+ util_out_print("ERROR: System Service SYS$DASSGN() failed.", TRUE);
+ return FALSE;
+ }
+
+ /* ---------- if file has extended since backup started, truncate it ------------------------------------ */
+ if (online && (filesize_tobe != filesize_curr))
+ {
+ /* truncate it */
+ assert(filesize_tobe < filesize_curr);
+ if (0 != truncate(tempfilename, (off_t)(filesize_tobe - 1) * DISK_BLOCK_SIZE))
+ {
+ errptr = (char *)strerror(errno);
+ errlen = strlen(errptr);
+ gtm_putmsg(VARLSTCNT(6) ERR_TRUNCATEFAIL, 4, tempfilelen, tempfilename,
+ filesize_curr, filesize_tobe - 1);
+ gtm_putmsg(VARLSTCNT(4) ERR_TEXT, 2, errlen, errptr);
+ return FALSE;
+ }
+ }
+
+ /* ======================= rename the tempfilename to the real backup filename ========================== */
+
+ /* --- if we don't have delete permission on the temporary file, give it --- */
+ old_perm = ((vms_gds_info *)(gv_cur_region->dyn.addr->file_cntl->file_info))->xabpro->xab$w_pro;
+ if (0x0080 & old_perm)
+ {
+ if (FALSE == setfileprot(tempfilename, tempfilelen,
+ (old_perm & (~((XAB$M_NODEL << XAB$V_SYS) | (XAB$M_NODEL << XAB$V_OWN))))))
+ {
+ util_out_print("Failed to set protection mask of !AD, to 0x!4XW", TRUE, tempfilelen, tempfilename,
+ (~((XAB$M_NODEL << XAB$V_SYS) | (XAB$M_NODEL << XAB$V_OWN))) & old_perm);
+ return FALSE;
+ }
+ }
+
+ /* --- construct and issue the command to rename the temporary file to backup file --- */
+ MEMCPY_LIT(command_buff, rename);
+ command_len = SIZEOF(rename) - 1;
+ memcpy(&command_buff[command_len], tempfilename, tempfilelen);
+ command_len += tempfilelen;
+ command_buff[command_len++] = ' ';
+ memcpy(&command_buff[command_len], file->addr, file->len);
+ command_len += file->len;
+ command_buff[command_len] = '\0';
+ command.dsc$w_length = command_len;
+
+ if (debug_mupip)
+ util_out_print("MUPIP INFO: !AD", TRUE, command_len, command_buff);
+ if ((SS$_NORMAL != (status = lib$spawn(&command, 0, &nl, 0, 0, 0, &backup_status, 0, 0, 0, 0, 0, 0)))
+ || (!((status = backup_status) & 1)))
+ {
+ gtm_putmsg(VARLSTCNT(1) status);
+ util_out_print("Command: !AD not executed successfully.", TRUE, command_len, command_buff);
+ return FALSE;
+ }
+
+ /* --- if the original database doesn't have delete permission, neither should the backup copy --- */
+ if (0x0080 & old_perm)
+ {
+ if (FALSE == setfileprot(file->addr, file->len, old_perm))
+ {
+ util_out_print("Failed to set protection mask of !AD, to 0x!4XW", TRUE,
+ file->addr, file->len, old_perm);
+ return FALSE;
+ }
+ }
+
+ /* =============================== Output Information =================================================== */
+ util_out_print("DB file !AD backed up in file !AD", TRUE,
+ fcb->fab$b_fns, fcb->fab$l_fna, file->len, file->addr);
+ util_out_print("Transactions up to 0x!16 at XQ are backed up.", TRUE, &header->trans_hist.curr_tn);
+ cs_addrs->hdr->last_com_backup = header->trans_hist.curr_tn;
+ cs_addrs->hdr->last_com_bkup_last_blk = header->trans_hist.total_blks;
+ if (record)
+ {
+ cs_addrs->hdr->last_rec_backup = header->trans_hist.curr_tn;
+ cs_addrs->hdr->last_rec_bkup_last_blk = header->trans_hist.total_blks;
+ }
+ file_backed_up = TRUE;
+
+ return TRUE;
+}
diff --git a/sr_vvms/mubgetfil.c b/sr_vvms/mubgetfil.c
new file mode 100644
index 0000000..c2acdeb
--- /dev/null
+++ b/sr_vvms/mubgetfil.c
@@ -0,0 +1,104 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/*
+ * mubgetfil.c
+ *
+ * Description: parse the file spec and determines whether it is backup to file, exec or tcpip.
+ * if it is to file, then determines whether it is a directory and sets "directory"
+ * and "is_directory" correspondingly.
+ *
+ * Input: char *name -- specifies the file spec
+ * ushort len -- specifies the file spec
+ * Output: backup_reg_list *list -- parsing result will be put to the backup_to and backup_file fields of list
+ * directory -- if backup to file and it is a directory, this will be set
+ * is_directory -- if backup to file, this will be set to reflect whether it is a directory.
+ */
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include <rms.h>
+#include <ssdef.h>
+#include <descrip.h>
+#include <climsgdef.h>
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "mupipbckup.h"
+#include "gtm_caseconv.h"
+
+GBLDEF mstr directory;
+GBLDEF bool is_directory;
+
+bool mubgetfil(backup_reg_list *list, char *name, unsigned short len)
+{
+ mstr *mubchkfs(), *temp, file;
+ uint4 status;
+ char tcp[5];
+
+ if (0 == len)
+ return FALSE;
+
+ if ('|' == *name)
+ {
+ len -= 1;
+ list->backup_to = backup_to_exec;
+ list->backup_file.len = len;
+ list->backup_file.addr = (char *)malloc(len + 1);
+ memcpy(list->backup_file.addr, name + 1, len);
+ return TRUE;
+ }
+
+ if (len > 5)
+ {
+ lower_to_upper(tcp, name, 5);
+ if (0 == memcmp(tcp, "TCP:/", 5))
+ {
+ list->backup_to = backup_to_tcp;
+ len -= 5;
+ name += 5;
+ while ('/' == *name)
+ {
+ len--;
+ name++;
+ }
+ list->backup_file.len = len;
+ list->backup_file.addr = (char *)malloc(len + 1);
+ memcpy(list->backup_file.addr, name, len);
+ *(list->backup_file.addr + len) = 0;
+ return TRUE;
+ }
+ }
+
+ file.addr = name;
+ file.len = len;
+ if (NULL == (temp = mubchkfs(&file))) /* mubchkfs is responsible for error message if NULL, and allocate space otherwise */
+ return FALSE;
+
+ if (']' == *(temp->addr + temp->len - 1))
+ {
+ is_directory = TRUE;
+ directory = *temp;
+ mubexpfilnam(list);
+ }
+ else
+ {
+ is_directory = FALSE;
+ list->backup_file = *temp;
+ }
+
+ return TRUE;
+}
diff --git a/sr_vvms/mubinccpy.c b/sr_vvms/mubinccpy.c
new file mode 100644
index 0000000..7c056ac
--- /dev/null
+++ b/sr_vvms/mubinccpy.c
@@ -0,0 +1,747 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gtm_string.h"
+#include "gtm_stdio.h"
+
+#include <rms.h>
+#include <ssdef.h>
+#include <iodef.h>
+#include <errno.h>
+#include "gtm_socket.h"
+#include "gtm_inet.h"
+#include <efndef.h>
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "gdsblk.h"
+#include "gdsbml.h"
+#include "stringpool.h"
+#include "muextr.h"
+#include "murest.h"
+#include "mupipbckup.h"
+#include "iotcproutine.h"
+#include "iotcpdef.h"
+#include "sleep_cnt.h"
+#include "util.h"
+#include "cli.h"
+#include "op.h"
+#include "io.h"
+#include "gtmmsg.h"
+#include "wcs_sleep.h"
+#include "gds_blk_upgrade.h"
+#include "shmpool.h"
+#include "iormdef.h"
+#include "iosp.h"
+#include "min_max.h"
+#include "gvcst_lbm_check.h"
+#include "wcs_phase2_commit_wait.h"
+
+#define MAX_TCP_SEND_RETRY 5
+
+GBLREF bool record;
+GBLREF bool online;
+GBLREF bool incremental;
+GBLREF bool file_backed_up;
+GBLREF bool error_mupip;
+GBLREF bool mu_ctrly_occurred;
+GBLREF bool mu_ctrlc_occurred;
+GBLREF bool mubtomag;
+GBLREF int4 mubmaxblk;
+GBLREF spdesc stringpool;
+GBLREF gd_region *gv_cur_region;
+GBLREF sgmnt_addrs *cs_addrs;
+GBLREF sgmnt_data_ptr_t cs_data;
+GBLREF unsigned char *mubbuf;
+GBLREF tcp_library_struct tcp_routines;
+GBLREF int4 backup_write_errno;
+GBLREF int4 backup_close_errno;
+GBLREF boolean_t debug_mupip;
+GBLREF uint4 process_id;
+
+#define COMMON_CLOSE(A) { \
+ (*common_close)(A); \
+ if (0 != backup_close_errno) \
+ return FALSE; \
+ }
+
+#define COMMON_WRITE(A, B, C) { \
+ (*common_write)(A, B, C); \
+ if (0 != backup_write_errno) \
+ return FALSE; \
+ }
+
+LITREF mval mu_bin_datefmt;
+
+/* forward declarations */
+static void file_write(char *temp, char *buf, int nbytes);
+static void file_close(char *temp);
+static void tcp_write(char *temp, char *buf, int nbytes);
+static void tcp_close(char *temp);
+
+bool mubinccpy(backup_reg_list *list)
+{
+ static readonly mval null_str = {MV_STR, 0, 0 , 0 , 0, 0};
+
+ int backup_socket;
+ int4 size, size1, bsize, bm_num, hint, lmsize, save_blks, rsize, match, timeout, outsize;
+ uint4 status, total_blks, bplmap, gds_ratio, blks_per_buff, counter, i, lcnt, read_size;
+ uchar_ptr_t bm_blk_buff, ptr1, ptr1_top, ptr, ptr_top;
+ char_ptr_t outptr, data_ptr;
+ unsigned short rd_iosb[4], port;
+ enum db_acc_method access;
+ blk_hdr *bp, *bptr;
+ struct FAB *fcb, temp_fab, mubincfab;
+ struct RAB temp_rab, mubincrab;
+ inc_header *outbuf;
+ mval val;
+ mstr *file;
+ sgmnt_data_ptr_t header;
+ char *common, addr[SA_MAXLEN + 1];
+ void (*common_write)();
+ void (*common_close)();
+ muinc_blk_hdr_ptr_t sblkh_p;
+ trans_num blk_tn;
+ block_id blk_num_base, blk_num;
+ boolean_t is_bitmap_blk, backup_this_blk;
+ enum db_ver dummy_odbv;
+ int4 blk_bsiz;
+
+ error_def(ERR_BCKUPBUFLUSH);
+ error_def(ERR_COMMITWAITSTUCK);
+ error_def(ERR_DBCCERR);
+ error_def(ERR_ERRCALL);
+
+ assert(list->reg == gv_cur_region);
+ assert(incremental);
+ /* Make sure inc_header can be same size on all platforms. Some platforms pad 8 byte aligned structures
+ that end on a 4 byte boundary and some do not. It is critical that this structure is the same size on
+ all platforms as it is sent across TCP connections when doing TCP backup.
+ */
+ assert(0 == (SIZEOF(inc_header) % 8));
+
+ /* ================= Initialization and some checks ======================== */
+
+ header = list->backup_hdr;
+ file = &(list->backup_file);
+
+ if (!mubtomag)
+ mubmaxblk = BACKUP_TEMPFILE_BUFF_SIZE;
+ fcb = ((vms_gds_info *)(gv_cur_region->dyn.addr->file_cntl->file_info))->fab;
+ if (list->tn >= header->trans_hist.curr_tn)
+ {
+ util_out_print("!/TRANSACTION number is greater than or equal to current transaction,", TRUE);
+ util_out_print("No blocks backed up from database !AD", TRUE, fcb->fab$b_fns, fcb->fab$l_fna);
+ return TRUE;
+ }
+
+ /* =========== open backup destination and define common_write ================= */
+ backup_write_errno = 0;
+ backup_close_errno = 0;
+ switch(list->backup_to)
+ {
+ case backup_to_file:
+ /* open the file and define the common_write function */
+ mubincfab = cc$rms_fab;
+ mubincfab.fab$b_fac = FAB$M_PUT;
+ mubincfab.fab$l_fop = FAB$M_CBT | FAB$M_MXV | FAB$M_TEF | FAB$M_POS & (~FAB$M_RWC) & (~FAB$M_RWO);
+ mubincfab.fab$l_fna = file->addr;
+ mubincfab.fab$b_fns = file->len;
+ mubincfab.fab$l_alq = cs_addrs->hdr->start_vbn +
+ STARTING_BLOCKS * cs_addrs->hdr->blk_size / DISK_BLOCK_SIZE;
+ mubincfab.fab$w_mrs = mubmaxblk;
+ mubincfab.fab$w_deq = EXTEND_SIZE;
+ switch (status = sys$create(&mubincfab))
+ {
+ case RMS$_NORMAL:
+ case RMS$_CREATED:
+ case RMS$_SUPERSEDE:
+ case RMS$_FILEPURGED:
+ break;
+ default:
+ gtm_putmsg(status, 0, mubincfab.fab$l_stv);
+ util_out_print("Error: Cannot create backup file !AD.",
+ TRUE, mubincfab.fab$b_fns, mubincfab.fab$l_fna);
+ return FALSE;
+ }
+
+ mubincrab = cc$rms_rab;
+ mubincrab.rab$l_fab = &mubincfab;
+ mubincrab.rab$l_rop = RAB$M_WBH;
+ if (RMS$_NORMAL != (status = sys$connect(&mubincrab)))
+ {
+ gtm_putmsg(status, 0, mubincrab.rab$l_stv);
+ util_out_print("Error: Cannot connect to backup file !AD.",
+ TRUE, mubincfab.fab$b_fns, mubincfab.fab$l_fna);
+ mubincfab.fab$l_fop |= FAB$M_DLT;
+ sys$close(&mubincfab);
+ return FALSE;
+ }
+ common = (char *)(&mubincrab);
+ common_write = file_write;
+ common_close = file_close;
+ break;
+ case backup_to_exec:
+ util_out_print("Error: Backup to pipe is yet to be implemented.", TRUE);
+ util_out_print("Error: Your request to backup database !AD to !AD is currently not valid.", TRUE,
+ fcb->fab$b_fns, fcb->fab$l_fna, file->len, file->addr);
+ return FALSE;
+ case backup_to_tcp:
+ iotcp_fillroutine();
+ /* parse it first */
+ switch (match = SSCANF(file->addr, "%[^:]:%hu", addr, &port))
+ {
+ case 1 :
+ port = DEFAULT_BKRS_PORT;
+ case 2 :
+ break;
+ default :
+ util_out_print("ERROR: A hostname has to be specified to backup through a TCP connection.",
+ TRUE);
+ return FALSE;
+ }
+ if ((0 == cli_get_int("NETTIMEOUT", &timeout)) || (0 > timeout))
+ timeout = DEFAULT_BKRS_TIMEOUT;
+ if (0 > (backup_socket = tcp_open(addr, port, timeout, FALSE)))
+ {
+ util_out_print("ERROR: Cannot open tcp connection due to the above error.", TRUE);
+ return FALSE;
+ }
+ common_write = tcp_write;
+ common_close = tcp_close;
+ common = (char *)(&backup_socket);
+ break;
+ default :
+ util_out_print("ERROR: Backup format !UL not supported.", TRUE, list->backup_to);
+ util_out_print("Error: Your request to backup database !AD to !AD is not valid.", TRUE,
+ fcb->fab$b_fns, fcb->fab$l_fna, file->len, file->addr);
+ return FALSE;
+ }
+
+ /* ============================= write inc_header =========================================== */
+
+ outptr = malloc(SIZEOF(inc_header));
+ outbuf = (inc_header *)outptr;
+ MEMCPY_LIT(&outbuf->label[0], INC_HEADER_LABEL);
+ stringpool.free = stringpool.base;
+ op_horolog(&val);
+ stringpool.free = stringpool.base;
+ op_fnzdate(&val, &mu_bin_datefmt, &null_str, &null_str, &val);
+ memcpy(&outbuf->date[0], val.str.addr, val.str.len);
+ memcpy(&outbuf->reg[0], gv_cur_region->rname, MAX_RN_LEN);
+ outbuf->start_tn = list->tn;
+ outbuf->end_tn = header->trans_hist.curr_tn;
+ outbuf->db_total_blks = header->trans_hist.total_blks;
+ outbuf->blk_size = header->blk_size;
+ outbuf->blks_to_upgrd = header->blks_to_upgrd;
+ COMMON_WRITE(common, outptr, SIZEOF(inc_header));
+ free(outptr);
+
+ if (mu_ctrly_occurred || mu_ctrlc_occurred)
+ {
+ error_mupip = TRUE;
+ COMMON_CLOSE(common);
+ util_out_print("WARNING: DB file !AD backup aborted.", TRUE, fcb->fab$b_fns, fcb->fab$l_fna);
+ return FALSE;
+ }
+
+ /* ============================ read/write appropriate blocks =============================== */
+
+ bsize = header->blk_size;
+ gds_ratio = bsize / DISK_BLOCK_SIZE;
+ blks_per_buff = BACKUP_READ_SIZE / bsize;
+ read_size = blks_per_buff * bsize;
+ outsize = SIZEOF(muinc_blk_hdr) + bsize;
+ outptr = (char_ptr_t)malloc(MAX(outsize, mubmaxblk));
+ sblkh_p = (muinc_blk_hdr_ptr_t)outptr;
+ data_ptr = (char_ptr_t)(sblkh_p + 1);
+ bp = (blk_hdr_ptr_t)mubbuf;
+ bm_blk_buff = (uchar_ptr_t)malloc(SIZEOF(blk_hdr) + (BLKS_PER_LMAP * BML_BITS_PER_BLK / BITS_PER_UCHAR));
+ mubincrab.rab$l_rbf = outptr;
+ save_blks = 0;
+ access = header->acc_meth;
+ memset(sblkh_p, 0, SIZEOF(*sblkh_p));
+
+ if (access == dba_bg)
+ bp = mubbuf;
+ else
+ {
+ ptr = cs_addrs->db_addrs[0] + (cs_addrs->hdr->start_vbn - 1) * DISK_BLOCK_SIZE;
+ ptr_top = cs_addrs->db_addrs[1] + 1;
+ }
+
+ sblkh_p->use.bkup.ondsk_blkver = GDSNOVER;
+ for (blk_num_base = 0; blk_num_base < header->trans_hist.total_blks; blk_num_base += blks_per_buff)
+ {
+ if (online && (0 != cs_addrs->shmpool_buffer->failed))
+ break;
+ if (header->trans_hist.total_blks - blk_num_base < blks_per_buff)
+ {
+ blks_per_buff = header->trans_hist.total_blks - blk_num_base;
+ read_size = blks_per_buff * bsize;
+ }
+
+ if (access == dba_bg)
+ {
+ if ((SS$_NORMAL != (status = sys$qiow(EFN$C_ENF, fcb->fab$l_stv, IO$_READVBLK, &rd_iosb, 0, 0, bp,
+ read_size, cs_addrs->hdr->start_vbn + (gds_ratio * blk_num_base),
+ 0, 0, 0)))
+ || (SS$_NORMAL != (status = rd_iosb[0])))
+ {
+ gtm_putmsg(VARLSTCNT(1) status);
+ util_out_print("Error reading data from database !AD.", TRUE,
+ fcb->fab$b_fns, fcb->fab$l_fna);
+ free(outptr);
+ free(bm_blk_buff);
+ error_mupip = TRUE;
+ COMMON_CLOSE(common);
+ return FALSE;
+ }
+ } else
+ {
+ assert(dba_mm == access);
+ bp = ptr + blk_num_base * bsize;
+ }
+
+ bptr = (blk_hdr *)bp;
+ /* The blocks we back up will be whatever version they are. There is no implicit conversion in this
+ part of the backup/restore. Since we aren't even looking at the blocks (and indeed some of these blocks
+ could potentially contain unintialized garbage data), we set the block version to GDSNOVER to signal
+ that the block version is unknown. The above applies to "regular" blocks but not to bitmap blocks which
+ we know are initialized. Because we have to read the bitmap blocks, they will be converted as necessary.
+ */
+ for (i = 0;
+ i < blks_per_buff && ((blk_num_base + i) < header->trans_hist.total_blks);
+ i++, bptr = (blk_hdr *)((char *)bptr + bsize))
+ {
+ blk_num = blk_num_base + i;
+ if (mu_ctrly_occurred || mu_ctrlc_occurred)
+ {
+ free(outptr);
+ free(bm_blk_buff);
+ error_mupip = TRUE;
+ COMMON_CLOSE(common);
+ util_out_print("WARNING: DB file !AD backup aborted.", TRUE, fcb->fab$b_fns, fcb->fab$l_fna);
+ return FALSE;
+ }
+ /* Before we check if this block needs backing up, check if this is a new bitmap block or not. If it is,
+ we can fall through and back it up as normal. But if this is NOT a bitmap block, use the
+ existing bitmap to determine if this block has ever been allocated or not. If not, we don't want to
+ even look at this block. It could be uninitialized which will just make things run slower if we
+ go to read it and back it up.
+ */
+ if (0 != ((BLKS_PER_LMAP - 1) & blk_num))
+ { /* Not a local bitmap block */
+ if (!gvcst_blk_ever_allocated(bm_blk_buff + SIZEOF(blk_hdr),
+ ((blk_num * BML_BITS_PER_BLK)
+ % (BLKS_PER_LMAP * BML_BITS_PER_BLK))))
+ continue; /* Bypass never-set blocks to avoid conversion problems */
+ is_bitmap_blk = FALSE;
+ if (SIZEOF(v15_blk_hdr) <= (blk_bsiz = ((v15_blk_hdr_ptr_t)bptr)->bsiz))
+ { /* We have either a V4 block or uninitialized garbage */
+ if (blk_bsiz > bsize)
+ /* This is not a valid V4 block so ignore it */
+ continue;
+ blk_tn = ((v15_blk_hdr_ptr_t)bptr)->tn;
+ } else
+ { /* Assume V5 block */
+ if ((blk_bsiz = bptr->bsiz) > bsize)
+ /* Not a valid V5 block either */
+ continue;
+ blk_tn = bptr->tn;
+ }
+ } else
+ { /* This is a bitmap block so save it into our bitmap block buffer. It is used as the
+ basis of whether or not we have to process a given block or not. We process allocated and
+ recycled blocks leaving free (never used) blocks alone as they have no data worth saving.
+ But after saving it, upgrade it to the current format if necessary.
+ */
+ is_bitmap_blk = TRUE;
+ memcpy(bm_blk_buff, bptr, BM_SIZE(header->bplmap));
+ if (SIZEOF(v15_blk_hdr) <= ((v15_blk_hdr_ptr_t)bm_blk_buff)->bsiz)
+ { /* This is a V4 format block -- needs upgrading */
+ status = gds_blk_upgrade(bm_blk_buff, bm_blk_buff, bsize, &dummy_odbv);
+ if (SS_NORMAL != status)
+ {
+ free(outptr);
+ free(bm_blk_buff);
+ error_mupip = TRUE;
+ COMMON_CLOSE(common);
+ util_out_print("Error: Block 0x!XL is too large for automatic upgrade", TRUE,
+ sblkh_p->blkid);
+ return FALSE;
+ }
+ }
+ assert(BM_SIZE(header->bplmap) == ((blk_hdr_ptr_t)bm_blk_buff)->bsiz);
+ assert(LCL_MAP_LEVL == ((blk_hdr_ptr_t)bm_blk_buff)->levl);
+ assert(gvcst_blk_is_allocated(bm_blk_buff + SIZEOF(blk_hdr),
+ ((blk_num * BML_BITS_PER_BLK)
+ % (BLKS_PER_LMAP * BML_BITS_PER_BLK))));
+ blk_bsiz = BM_SIZE(header->bplmap);
+ blk_tn = ((blk_hdr_ptr_t)bm_blk_buff)->tn;
+ }
+ /* The conditions for backing up a block or ignoring it (in order of evaluation):
+
+ 1) If blk is larger than size of db at time backup was initiated, we ignore the block.
+ 2) Always backup blocks 0, 1, and 2 as these are the only blocks that can contain data
+ and still have a transaction number of 0.
+ 3) For bitmap blocks, if blks_to_upgrd != 0 and the TN is 0 and the block number >=
+ last_blk_at_last_bkup, then backup the block. This way we get the correct version of
+ the bitmap block in the restore (otherwise have no clue what version to create them in
+ as bitmaps are created with a TN of 0 when before image journaling is enabled).
+ 4) If the block TN is below our TN threshold, ignore the block.
+ 5) Else if none of the above conditions, backup the block.
+ */
+ if (online && (header->trans_hist.curr_tn <= blk_tn))
+ backup_this_blk = FALSE;
+ else if (3 > blk_num || (is_bitmap_blk && 0 != header->blks_to_upgrd && (trans_num)0 == blk_tn
+ && blk_num >= list->last_blk_at_last_bkup))
+ backup_this_blk = TRUE;
+ else if ((blk_tn < list->tn))
+ backup_this_blk = FALSE;
+ else
+ backup_this_blk = TRUE;
+ if (!backup_this_blk)
+ {
+ if (online)
+ cs_addrs->nl->nbb = blk_num;
+ continue; /* not applicable */
+ }
+ sblkh_p->blkid = blk_num;
+ memcpy(data_ptr, bptr, blk_bsiz);
+ sblkh_p->valid_data = TRUE; /* Validation marker */
+ COMMON_WRITE(common, outptr, outsize);
+ if (online)
+ {
+ if (0 != cs_addrs->shmpool_buffer->failed)
+ break;
+ cs_addrs->nl->nbb = blk_num;
+ }
+ save_blks++;
+ }
+ }
+
+ /* ============================= write saved information for online backup ========================== */
+
+ if (online && (0 == cs_addrs->shmpool_buffer->failed))
+ {
+ /* -------- make sure everyone involved finishes -------- */
+ cs_addrs->nl->nbb = BACKUP_NOT_IN_PROGRESS;
+ /* By getting crit here, we ensure that there is no process still in transaction logic that sees
+ (nbb != BACKUP_NOT_IN_PRORESS). After rel_crit(), any process that enters transaction logic will
+ see (nbb == BACKUP_NOT_IN_PRORESS) because we just set it to that value. At this point, backup
+ buffer is complete and there will not be any more new entries in the backup buffer until the next
+ backup.
+ */
+ grab_crit(gv_cur_region);
+ assert(cs_data == cs_addrs->hdr);
+ if (dba_bg == cs_data->acc_meth)
+ { /* Now that we have crit, wait for any pending phase2 updates to finish. Since phase2 updates happen
+ * outside of crit, we dont want them to keep writing to the backup temporary file even after the
+ * backup is complete and the temporary file has been deleted.
+ */
+ if (cs_addrs->nl->wcs_phase2_commit_pidcnt && !wcs_phase2_commit_wait(cs_addrs, NULL))
+ {
+ gtm_putmsg(VARLSTCNT(7) ERR_COMMITWAITSTUCK, 5, process_id, 1,
+ cs_addrs->nl->wcs_phase2_commit_pidcnt, DB_LEN_STR(gv_cur_region));
+ rel_crit(gv_cur_region);
+ free(outptr);
+ free(bm_blk_buff);
+ error_mupip = TRUE;
+ COMMON_CLOSE(common);
+ return FALSE;
+ }
+ }
+ if (debug_mupip)
+ {
+ util_out_print("MUPIP INFO: Current Transaction # at end of backup is 0x!16 at XQ", TRUE,
+ &cs_data->trans_hist.curr_tn);
+ }
+ rel_crit(gv_cur_region);
+ counter = 0;
+ while (0 != cs_addrs->shmpool_buffer->backup_cnt)
+ {
+ if (0 != cs_addrs->shmpool_buffer->failed)
+ {
+ util_out_print("Process !UL encountered the following error.", TRUE,
+ cs_addrs->shmpool_buffer->failed);
+ if (0 != cs_addrs->shmpool_buffer->backup_errno)
+ gtm_putmsg(VARLSTCNT(1) cs_addrs->shmpool_buffer->backup_errno);
+ free(outptr);
+ free(bm_blk_buff);
+ error_mupip = TRUE;
+ COMMON_CLOSE(common);
+ return FALSE;
+ }
+ backup_buffer_flush(gv_cur_region);
+ if (++counter > MAX_BACKUP_FLUSH_TRY)
+ {
+ gtm_putmsg(VARLSTCNT(1) ERR_BCKUPBUFLUSH);
+ free(outptr);
+ free(bm_blk_buff);
+ error_mupip = TRUE;
+ COMMON_CLOSE(common);
+ return FALSE;
+ }
+ if (counter & 0xF)
+ wcs_sleep(counter);
+ else
+ { /* Force shmpool recovery to see if it can find the lost blocks */
+ if (!shmpool_lock_hdr(gv_cur_region))
+ {
+ gtm_putmsg(VARLSTCNT(9) ERR_DBCCERR, 2, REG_LEN_STR(gv_cur_region),
+ ERR_ERRCALL, 3, CALLFROM);
+ free(outptr);
+ free(bm_blk_buff);
+ error_mupip = TRUE;
+ COMMON_CLOSE(common);
+ assert(FALSE);
+ return FALSE;;
+ }
+ shmpool_abandoned_blk_chk(gv_cur_region, TRUE);
+ shmpool_unlock_hdr(gv_cur_region);
+ }
+ }
+
+ /* -------- Open the temporary file -------- */
+ temp_fab = cc$rms_fab;
+ temp_fab.fab$b_fac = FAB$M_GET;
+ temp_fab.fab$l_fna = list->backup_tempfile;
+ temp_fab.fab$b_fns = strlen(list->backup_tempfile);
+ temp_rab = cc$rms_rab;
+ temp_rab.rab$l_fab = &temp_fab;
+
+ for (lcnt = 1; MAX_OPEN_RETRY >= lcnt; lcnt++)
+ {
+ if (RMS$_FLK != (status = sys$open(&temp_fab, NULL, NULL)))
+ break;
+ wcs_sleep(lcnt);
+ }
+
+ if (RMS$_NORMAL != status)
+ {
+ gtm_putmsg(status, 0, temp_fab.fab$l_stv);
+ util_out_print("WARNING: DB file !AD backup aborted.", TRUE, fcb->fab$b_fns, fcb->fab$l_fna);
+ free(outptr);
+ free(bm_blk_buff);
+ error_mupip = TRUE;
+ COMMON_CLOSE(common);
+ return FALSE;
+ }
+
+ if (RMS$_NORMAL != (status = sys$connect(&temp_rab)))
+ {
+ gtm_putmsg(status, 0, temp_rab.rab$l_stv);
+ util_out_print("WARNING: DB file !AD backup aborted.", TRUE, fcb->fab$b_fns, fcb->fab$l_fna);
+ free(outptr);
+ free(bm_blk_buff);
+ error_mupip = TRUE;
+ COMMON_CLOSE(common);
+ return FALSE;
+ }
+
+ /* -------- read and write every record in the temporary file -------- */
+ while (1)
+ {
+ temp_rab.rab$w_usz = outsize;
+ temp_rab.rab$l_ubf = outptr;
+ status = sys$get(&temp_rab);
+ if (RMS$_NORMAL != status)
+ {
+ if (RMS$_EOF == status)
+ status = RMS$_NORMAL;
+ break;
+ }
+ assert(outsize == temp_rab.rab$w_rsz);
+ /* Still validly sized blk? */
+ assert((outsize - SIZEOF(shmpool_blk_hdr)) >= ((blk_hdr_ptr_t)(outptr + SIZEOF(shmpool_blk_hdr)))->bsiz);
+ COMMON_WRITE(common, outptr, temp_rab.rab$w_rsz);
+ }
+
+ if (RMS$_NORMAL != status)
+ {
+ gtm_putmsg(status, 0, temp_rab.rab$l_stv);
+ util_out_print("WARNING: DB file !AD backup aborted.", TRUE, fcb->fab$b_fns, fcb->fab$l_fna);
+ free(outptr);
+ free(bm_blk_buff);
+ error_mupip = TRUE;
+ COMMON_CLOSE(common);
+ return FALSE;
+ }
+
+ /* ---------------- Close the temporary file ----------------------- */
+ if (RMS$_NORMAL != (status = sys$close(&temp_fab)))
+ {
+ gtm_putmsg(status, 0, temp_fab.fab$l_stv);
+ util_out_print("WARNING: DB file !AD backup aborted.", TRUE, fcb->fab$b_fns, fcb->fab$l_fna);
+ free(outptr);
+ free(bm_blk_buff);
+ error_mupip = TRUE;
+ COMMON_CLOSE(common);
+ return FALSE;
+ }
+ }
+
+ /* ============================= write end_msg and fileheader ======================================= */
+
+ if ((!online) || (0 == cs_addrs->shmpool_buffer->failed))
+ {
+ MEMCPY_LIT(outptr, END_MSG);
+ /* Although the write only need be of length SIZEOF(END_MSG) - 1 for file IO, if the write is going
+ to TCP we have to write all these records with common length so just write the "regular" sized
+ buffer. The extra garbage left over from the last write will be ignored as we key only on the
+ this end text.
+ */
+ COMMON_WRITE(common, outptr, outsize);
+
+ ptr1 = header;
+ size1 = ROUND_UP(SIZEOF(sgmnt_data), DISK_BLOCK_SIZE);
+ ptr1_top = ptr1 + size1;
+ for (;ptr1 < ptr1_top ; ptr1 += size1)
+ {
+ if ((size1 = ptr1_top - ptr1) > mubmaxblk)
+ size1 = (mubmaxblk / DISK_BLOCK_SIZE) * DISK_BLOCK_SIZE;
+ COMMON_WRITE(common, ptr1, size1);
+ }
+
+ MEMCPY_LIT(outptr, HDR_MSG);
+ COMMON_WRITE(common, outptr, SIZEOF(HDR_MSG));
+ ptr1 = MM_ADDR(header);
+ size1 = ROUND_UP(MASTER_MAP_SIZE(header), DISK_BLOCK_SIZE);
+ ptr1_top = ptr1 + size1;
+ for (;ptr1 < ptr1_top ; ptr1 += size1)
+ {
+ if ((size1 = ptr1_top - ptr1) > mubmaxblk)
+ size1 = (mubmaxblk / DISK_BLOCK_SIZE) * DISK_BLOCK_SIZE;
+ COMMON_WRITE(common, ptr1, size1);
+ }
+
+ MEMCPY_LIT(outptr, MAP_MSG);
+ COMMON_WRITE(common, outptr, SIZEOF(MAP_MSG));
+ }
+
+
+ /* ================== close backup destination, output and return ================================== */
+
+ if (online && (0 != cs_addrs->shmpool_buffer->failed))
+ {
+ util_out_print("Process !UL encountered the following error.", TRUE,
+ cs_addrs->shmpool_buffer->failed);
+ if (0 != cs_addrs->shmpool_buffer->backup_errno)
+ gtm_putmsg(VARLSTCNT(1) cs_addrs->shmpool_buffer->backup_errno);
+ free(outptr);
+ free(bm_blk_buff);
+ error_mupip = TRUE;
+ COMMON_CLOSE(common);
+ return FALSE;
+ }
+
+ COMMON_CLOSE(common);
+ free(outptr);
+ free(bm_blk_buff);
+
+ util_out_print("DB file !AD incrementally backed up in !AD", TRUE,
+ fcb->fab$b_fns, fcb->fab$l_fna, file->len, file->addr);
+ util_out_print("!UL blocks saved.", TRUE, save_blks);
+ util_out_print("Transactions from 0x!16 at XQ to 0x!16 at XQ are backed up.", TRUE,
+ &cs_addrs->shmpool_buffer->inc_backup_tn, &header->trans_hist.curr_tn);
+ cs_addrs->hdr->last_inc_backup = header->trans_hist.curr_tn;
+ if (record)
+ cs_addrs->hdr->last_rec_backup = header->trans_hist.curr_tn;
+ file_backed_up = TRUE;
+ return TRUE;
+}
+
+static void tcp_write(char *temp, char *buf, int nbytes)
+{
+ int socket, nwritten, iostatus, send_retry;
+
+ socket = *(int *)(temp);
+
+ nwritten = 0;
+ send_retry = MAX_TCP_SEND_RETRY;
+
+ do
+ {
+ if (-1 != (iostatus = tcp_routines.aa_send(socket, buf + nwritten, nbytes - nwritten, 0)))
+ {
+ nwritten += iostatus;
+ if (nwritten == nbytes)
+ break;
+ } else if (EINTR != errno)
+ break;
+ } while (0 < send_retry--);
+
+ if ((nwritten != nbytes) && (-1 == iostatus))
+ {
+ gtm_putmsg(VARLSTCNT(1) errno);
+ tcp_routines.aa_close(socket);
+ backup_write_errno = errno;
+ }
+
+ return;
+}
+
+static void tcp_close(char *temp)
+{
+ int socket;
+
+ socket = *((int *)(temp));
+ tcp_routines.aa_close(socket);
+
+ return;
+}
+
+static void file_write(char *temp, char *buf, int nbytes)
+{
+ uint4 status;
+ struct RAB *rab;
+ void gtm_putmsg();
+
+ assert(nbytes > 4);
+ rab = (struct RAB *)(temp);
+ rab->rab$w_rsz = nbytes;
+ rab->rab$l_rbf = buf;
+ if (RMS$_NORMAL != (status = sys$put(rab)))
+ {
+ backup_write_errno = status;
+ gtm_putmsg(status, 0, rab->rab$l_stv);
+ (rab->rab$l_fab)->fab$l_fop |= FAB$M_DLT;
+ sys$close(rab->rab$l_fab);
+ }
+
+ return;
+}
+
+static void file_close(char *temp)
+{
+ uint4 status;
+ struct RAB *rab;
+ void gtm_putmsg();
+
+ rab = (struct RAB *)(temp);
+ if (error_mupip)
+ rab->rab$l_fab->fab$l_fop |= FAB$M_DLT;
+ status = sys$close(rab->rab$l_fab);
+ if (status != RMS$_NORMAL)
+ {
+ backup_close_errno = status;
+ gtm_putmsg(status);
+ util_out_print("FATAL ERROR: System Service failure.",TRUE);
+ }
+
+ return;
+}
diff --git a/sr_vvms/mucblkini.c b/sr_vvms/mucblkini.c
new file mode 100644
index 0000000..71758e3
--- /dev/null
+++ b/sr_vvms/mucblkini.c
@@ -0,0 +1,75 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <ssdef.h>
+
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsfhead.h"
+#include "gdsblk.h"
+#include "efn.h"
+#include "gdsbml.h"
+#include "mucblkini.h"
+#include "iosb_disk.h"
+#include "iosp.h"
+
+#define DIR_ROOT 1
+#define DIR_DATA 2
+
+GBLREF gd_region *gv_cur_region;
+GBLREF sgmnt_addrs *cs_addrs;
+
+void mucblkini(void)
+{
+ unsigned char *c, *bmp;
+ blk_hdr *bp1, *bp2;
+ rec_hdr *rp;
+ uint4 status;
+
+ /* get space for directory tree root and 1st directory tree data block */
+ bp1 = malloc(cs_addrs->hdr->blk_size);
+ bp2 = malloc(cs_addrs->hdr->blk_size);
+ bmp = malloc(cs_addrs->hdr->blk_size);
+ status = dsk_read(0, bmp, NULL, FALSE);
+ if (SS$_NORMAL != status)
+ rts_error(VARLSTCNT(1) status);
+ bml_busy(DIR_ROOT, bmp + SIZEOF(blk_hdr));
+ bml_busy(DIR_DATA, bmp + SIZEOF(blk_hdr));
+
+ DSK_WRITE_NOCACHE(gv_cur_region, 0, bmp, cs_addrs->hdr->desired_db_format, status);
+ if (SS$_NORMAL != status)
+ sys$exit((int4)status);
+
+ rp = (char*)bp1 + SIZEOF(blk_hdr);
+ BSTAR_REC(rp);
+ c = CST_BOK(rp);
+ *(block_id*)c = (block_id)DIR_DATA;
+ bp1->bver = GDSVCURR;
+ bp1->levl = 1;
+ bp1->bsiz = BSTAR_REC_SIZE + SIZEOF(blk_hdr);
+ bp1->tn = 0;
+ bp2->bver = GDSVCURR;
+ bp2->levl = 0;
+ bp2->bsiz = SIZEOF(blk_hdr);
+ bp2->tn = 0;
+
+ DSK_WRITE_NOCACHE(gv_cur_region, DIR_ROOT, bp1, cs_addrs->hdr->desired_db_format, status);
+ if (SS$_NORMAL != status)
+ sys$exit((int4)status);
+
+ DSK_WRITE_NOCACHE(gv_cur_region, DIR_DATA, bp2, cs_addrs->hdr->desired_db_format, status);
+ if (SS$_NORMAL != status)
+ sys$exit((int4)status);
+}
diff --git a/sr_vvms/mumps.hlp b/sr_vvms/mumps.hlp
new file mode 100644
index 0000000..ec724a0
--- /dev/null
+++ b/sr_vvms/mumps.hlp
@@ -0,0 +1,19589 @@
+1 About_GTM
+ GT.M Version 4.4
+
+ VMS Edition
+
+ October 2003
+
+ The information in this manual is subject to change without notice and
+ should not be construed as a commitment by Sanchez Computer Associates.
+ The software described in this manual is furnished under a license and
+ may be used or copied only in accordance with the terms of such a
+ license.
+
+ Copyright 1987 - 2003
+
+ Sanchez Computer Associates
+
+ All rights reserved
+
+ GT.M, and GT.CM are trademarks of Sanchez Computer Associates. All
+ other company and product names may be trademarks of the respective
+ companies with which they are associated.
+
+1 Prog_Dev_Cycle
+ Program Development Cycle
+
+ In contrast to M environments that interpret M code, GT.M compiles M
+ code from source files into the object files. These object files can be
+ directly linked into an image, permanently or dynamically. Source files
+ and object files are independent of one another. Since GT.M permits
+ access to source and object files in multiple directories. they may be
+ managed independently or all placed together in a specific directory.
+
+ GT.M databases are RMS files identified by a small file called a Global
+ Directory. Global Directories allow management of the database files to
+ be independent of the placement of files containing M routines. By
+ changing the Global Directory, you can use the same programs to access
+ different databases.
+
+ Program development may utilize both GT.M and VMS development tools.
+ The development methodology and environment chosen for a particular
+ installation, and tailored by the individual user, determines the
+ actual mix of tools. These tools may vary from entirely GT.M with
+ little VMS, to mostly VMS with a modest use of GT.M.
+
+ Direct Mode serves as an interactive interface to the GT.M run-time
+ environment and the compiler. In Direct Mode, the user enters M
+ commands at the GT.M prompt, and GT.M compiles and executes the
+ command. This feature provides immediate turnaround for rapid program
+ development and maintenance.
+
+2 Comm_Symbols
+ Commands and Symbols
+
+ GT.M components are invoked with commands and symbols. Users who do not
+ perform programming or operational tasks do not need direct access to
+ GT.M components. They access the GT.M run-time libraries, indirectly
+ through their production images.
+
+ GT.M provides the MUMPS command with two fundamental variations.
+ Generally the MUMPS command invokes the GT.M compiler.
+ MUMPS/DIRECT_MODE invokes a simple M routine that enters Direct Mode by
+ executing an M BREAK command. This routine has a name that is not a
+ legal M name and therefore can never conflict with one of your program
+ names.
+
+ The system manager may load the GT.M commands into the system command
+ tables. When the GT.M commands are not in the system command tables,
+ users must place them in their process command tables with the
+ following command.
+
+ $ SET COMMAND GTM$DIST:GTMCOMMANDS
+
+ Other GT.M components may be invoked with the DCL RUN command or with
+ symbols. The general form of the RUN command is:
+
+ $ RUN GTM$DIST:utility-name
+
+ For more information on commonly established GT.M symbols refer to
+ the GT.M Programmer's Guide.
+
+2 Prep_the_DB
+ Preparing the Database
+
+ GT.M databases consist of one or more RMS files. Most database files
+ have a RMS file structure externally and a GT.M Database Structure
+ (GDS) internally. Management of the GDS files by the GT.M run-time
+ system assures high performance and integrity. GT.M database files are
+ coordinated by a Global Directory. The Global Directory identifies
+ which global names belong in which files, and specifies the creation
+ characteristics for each file. To specify access to a database, each M
+ process must define the GTM$GBLDIR logical name to point to the
+ associated Global Directory.
+
+ To define and maintain a Global Directory, use the Global Directory
+ Editor (
+ GDE) utility.The MUPIP command CREATE uses the characteristics as
+ defined in the Global Directory to create the associated database. In a
+ production environment, the system manager typically maintains Global
+ Directories.
+
+ For more information on GDE and MUPIP refer to the "Global Directory
+ Editor" and "MUPIP" chapters in the GT.M Administration and Operations
+ Guide .
+
+ Example:
+
+ This example is a sequence of events that illustrate steps you might
+ typically perform in creating a new global directory, in our example
+ PAYROLL.GLD. To assist you in following the sequence, each actual step
+ appears in typewriter font, as you might see on your terminal screen,
+ followed by an explanation in normal text font.
+
+ To explain the program development cycle, a sample routine is created
+ and used in each subsequent section to illustrate the functionality
+ being described. A routine named PAYROLL calls parts of the routine
+ TAXES with the M commands "DO STATE^TAXES" and "DO FEDERAL^TAXES." Both
+ the PAYROLL and TAXES routines call the general-purpose routines LOOKUP
+ and SUM.
+
+ For the purposes of the example, assume we have already compiled and
+ debugged the LOOKUP and SUM routines.
+
+
+ $ DIR PAYROLL.*
+
+ %DIRECT-W-NOFILES, no files found
+
+ The DIRECTORY command checks to see that there are no existing files
+ with the name PAYROLL.
+
+
+ $ DEFINE GTM$GBLDIR PAYROLL.GLD
+
+ $ GDE
+
+ %GDE-I-GDUSEDEFS, Using defaults for Global Directory
+
+ USER:[EXAMPLE]PAYROLL.GLD
+
+ The DEFINE command establishes the current value of the logical name
+ GTM$GBLDIR as PAYROLL.GLD. GT.M uses the logical name GTM$GBLDIR to
+ identify the current Global Directory. Because we defined it in the
+ process logical table, GTM$GBLDIR maintains the defined value only for
+ the current login session. The next time we log into VMS, we must again
+ define the value of as GTM$GBLDIR as PAYROLL.GLD to use it as the
+ current Global Directory. If you use a Global Directory frequently,
+ DEFINE the GTM$GBLDIR to that Global Directory in a LOGIN.COM file. The
+ system manager may include such a definition in the system login file,
+ or in a system or group logical name table.
+
+ This example defines GTM$GBLDIR without a directory specification. The
+ logical name points to the PAYROLL.GLD file in the current RMS default
+ directory. Therefore if the default directory changes, GT.M attempts to
+ locate the Global Directory in the new default directory and cannot use
+ the original file. If you intend for the Global Directory to
+ consistently point to this file, even if the default directory changes,
+ use a full file-specification for GTM$GBLDIR.
+
+ This invokes the Global Directory Editor by entering GDE at the DCL
+ prompt. Refer to the "Program Development Cycle" in GT.M Programmer's
+ Guide for more details.
+
+ Example:
+
+
+ $ MUPIP LOAD PAYROLL.GLO
+
+ GT.M MUPIP EXTRACT
+
+ 09-OCT-2001 11:26:44
+ %MUPIP-I-KEYCNT, LOAD TOTAL:
+
+ keycnt: 100 max subsc len:12 max data len: 3
+
+ %MUPIP-I-RECCNT, Last record number: 202
+
+ This uses the MUPIP LOAD command to load a sequential file into the
+ database. (The LOAD TOTAL statistics appear on more than one line
+ because of typesetting constraints.)
+
+ Because MUPIP uses the logical name GTM$GBLDIR to locate a Global
+ Directory (which identifies the database file(s)), the LOAD command
+ does not require any information about the target database. Most of the
+ GT.M utilities work this way, with few exceptions.
+
+2 Cre_Edt_Source_Prog
+ Creating and Editing a Source Program
+
+ The first step in developing a GT.M program is to create a source file.
+ In most cases, the user can create and modify GT.M source programs
+ using VMS text editors. You can create and edit a source program from
+ either GT.M or DCL.
+
+ When the program is very simple (and its lines do not need revision
+ after they are entered), you can use DCL command CREATE and redirect
+ the output to your M source file. For more information on CREATE, refer
+ to the VMS DCL Dictionary.
+
+3 Edit_from_GTM
+ Editing from GT.M
+
+ To create and edit a source program in GT.M, invoke Direct Mode. The
+ method you customarily use to invoke Direct Mode depends upon your
+ programming environment. However, in most cases, you can invoke Direct
+ Mode by entering either GTM or MUMPS/DIRECT_MODE at the DCL prompt. GTM
+ is a VMS symbol, which by default is defined to be MUMPS/DIRECT. Once
+ you are at the GTM> prompt, invoke the editor by entering ZEDIT
+ "filename". ZEDIT invokes a TPU-based editor selected by the logical
+ name TPU$SECTION.
+
+ You can create your own customized executable images and set the symbol
+ GTM to invoke your image. For more detailed information about TPU-based
+ editors refer to the VMS Guide to Text Processing. For instructions for
+ customizing an editor to meet specific standards or needs, refer to the
+ VMS TPU Reference Manual.
+
+ Invoke Direct Mode to create and edit a source program in GT.M. At the
+ GTM> prompt, invoke the editor by typing:
+
+ ZEDIT <filename>
+
+ The TPU editor invoked by ZEDIT creates a separate RMS file for each M
+ source module. When you make changes to an existing routine file and
+ save them, the editor creates a new version of the routine file. The
+ system manager typically controls the number of versions of a file that
+ may be stored on disk. The version limit ranges from one to unlimited.
+ The ability to save previous versions of a routine serves as a valuable
+ tool in managing application development and maintenance.
+
+ The GT.M environment works more efficiently if the file has the same
+ name as the M routine it contains, and if it has a file type of .M.
+ Because ZEDIT automatically defaults to the file type .M, ZEDIT
+ commands generally do not specify the file type. If you use other file
+ types, you must specify the type with every reference to of the file.
+
+3 Edit_from_DCL
+ Editing from DCL
+
+ To create and edit a source program from DCL, invoke any VMS editor at
+ the DCL prompt, specifying an RMS file for the source. The GT.M
+ environment works best when you give a file the name of the M routine
+ that it contains, and a type of .M.
+
+ The Guide to VMS Text Processing describes in more detail how to use
+ VMS editors. The default editor for VMS is EDT. For a complete
+ description of all the EDT commands, refer to the VMS EDT Reference
+ Manual.
+
+ Example
+
+ $ EDIT PAYROLL.M
+
+ The EDIT command initiates an editing session for PAYROLL.M from the
+ DCL prompt. If PAYROLL.M does not already exist, EDT creates it.
+
+ Example:
+
+ $ EDIT/TPU PAYROLL.M
+
+ This EDIT/TPU command initiates an editing session for PAYROLL.M. Your
+ installation may have more than one TPU based editor. The logical name
+ TPU$SECTION specifies the default TPU editor. Again, if PAYROLL.M does
+ not already exist, TPU creates it.
+
+ Because these examples use VMS rather than GT.M tools, in both cases we
+ must specify the .M file extension.
+
+2 Comp_Source_Prog
+ Compiling a Source Program
+
+ GT.M compiles M source code files and produces object files for
+ complete integration into the VMS environment consisting of VMS
+ standard object language. The object modules have the same name as the
+ compiled M source file with a .OBJ file extension, unless otherwise
+ specified. The VMS standard object language contains machine
+ instructions and information necessary to connect the routine with
+ other routines, and map it into memory. An M routine source file must
+ be compiled after it is created or modified. Within GT.M, you can
+ compile explicitly with the ZLINK or ZCOMPILE commands, or implicitly
+ with auto-ZLINK. At the DCL command line, compile by issuing the MUMPS
+ command.
+
+ The compiler checks M code for syntax errors and displays error
+ messages on the terminal, when processing is complete. Each error
+ message provides the source line in error with an indicator pointing to
+ the place on the line where the error is occurring. For a list and
+ description of the compiler error messages, refer to the GT.M Message
+ and Recovery Procedures Reference Manual.
+
+ You can also generate a listing file containing the results of the
+ compile, by including the /LIST qualifier as a modifier to the argument
+ to the ZLINK command in Direct Mode or on the MUMPS command when
+ compiling from the DCL command line. The explanation of the MUMPS
+ command in the section "Compiling from DCL" describes /LIST and other
+ valid qualifiers for the MUMPS and ZLINK commands.
+
+ The compiler stops processing a routine line when it detects an error
+ on that line. Under most conditions the compiler continues processing
+ the remaining routine lines. This allows the compiler to produce a more
+ complete error analysis of the routine and to generate code that may
+ have valid executable paths. The compiler does not report multiple
+ syntax errors on the same line. When it detects more than 127 syntax
+ errors in a source file, the compiler ceases to process the file.
+
+3 Comp_from_GTM
+ Compiling from GT.M
+
+ In Direct Mode, GT.M provides access to the compiler explicitly through
+ the ZLINK and ZCOMPILE commands, and implicitly through automatic
+ invocation of ZLINK functionality (auto-ZLINK) to add required routines
+ to the image. ZCOMPILE is a GT.M routine compilation command, it
+ compiles the routine and creates a new object module. The primary task
+ of ZLINK is to place the object code in memory and "connect" it with
+ other routines. However, under certain circumstances, ZLINK may first
+ use the GT.M compiler to create a new object module.
+
+ The difference between ZCOMPILE and ZLINK is that ZCOMPILE creates a
+ new object module on compiling, whereas the ZLINK command links the
+ object module with other routines and places the object code in memory.
+
+
+ ZLINK compiles under these circumstances:
+
+ o ZLINK cannot locate a copy of the object module but can locate a
+ copy of the source module.
+
+ o ZLINK can locate both object and source module, and finds the
+ object module to be older than the source module.
+
+ o The file-specification portion of the ZLINK argument includes an
+ explicit file type of .M.
+
+ Auto-ZLINK compiles under the first two circumstances, but can never
+ encounter the last one.
+
+ When a command refers to an M routine that is not part of the current
+ image, GT.M automatically attempts to ZLINK and, if necessary, compile
+ that routine. In Direct Mode, the most common method to invoke the
+ compiler through an auto-ZLINK is to enter DO ^routinename at the GTM>
+ prompt. When the current image does not contain the routine, GT.M does
+ the following:
+
+ o Locates the source and object
+
+ o Determines whether the source has been edited since it was last
+ compiled
+
+ o Compiles the routine, if appropriate
+
+ o Adds the object to the image
+
+ By using the DO command, you implicitly instruct GT.M to compile, link,
+ and execute the program. With this method, you can test your routine
+ interactively.
+
+ For complete descriptions of ZCOMPILE, ZLINK and auto-ZLINK, refer to
+ the "Commands" chapter in GT.M Programmer's Guide.
+
+ Example:
+
+
+ GTM>DO ^PAYROLL
+
+ GTM>DO ^TAXES
+
+ This uses the M DO command to invoke the GT.M compiler implicitly from
+ the GTM> prompt if the routine requires new object code. When the
+ compiler runs, it produces two object module files, PAYROLL.OBJ and
+ TAXES.OBJ.
+
+ If you receive error messages from the compilation, you may fix them
+ immediately by returning to the editor and correcting the source. By
+ default, the GT.M compiler operates in "compile-as-written" mode, and
+ produces object code even when a routine contains syntax errors. This
+ code includes all lines that are correct and all commands on a line
+ with an error, up to the error. Therefore, you may decide to tailor the
+ debugging cycle by running the program without removing the syntax
+ errors.
+
+3 Comp_from_DCL
+ Compiling from DCL
+
+ In DCL, invoke the compiler by entering MUMPS file-spec at the DCL
+ prompt.
+
+ Example:
+
+
+ $ MUMPS PAYROLL
+
+ $ MUMPS TAXES
+
+ This uses the MUMPS command to invoke the GT.M compiler from the DCL
+ prompt.
+
+ Use the MUMPS command at the DCL prompt to:
+
+ o Check the syntax of a newly entered program.
+
+ o Optionally, get a formatted listing of the program.
+
+ o Ensure that all object code is up to date before linking.
+
+ The MUMPS command invokes the compiler to translate an M source file
+ into object code. Various qualifiers to this command control the output
+ of the compiler. Most of these qualifiers affect the type of listing
+ produced by the compiler.
+
+ The format for the MUMPS command is:
+
+
+ MUMPS [/qualifier[...]] file-spec
+
+ o By default, GT.M assumes source programs have an extension of .M
+
+ o Each file-specification identifies an M source program to compile.
+
+ o Qualifiers determine characteristics of the compiler output.
+
+ o Qualifiers may be applied globally by placing them on the MUMPS
+ command or locally by placing them on a file-specification in the
+ parameter list; local qualifiers override global qualifiers.
+
+ o GT.M allows the VMS * and % wildcards in a file-specification.
+
+ The * wildcard accepts any legal combination of numbers and characters
+ including a null, in the position the wildcard holds.
+ The % wildcard accepts exactly one legal character in its position.
+
+ For example, MUMPS * compiles all files in the current default
+ directory with a .M extension. MUMPS *pay% compiles any .M files with
+ names that contain any characters followed by "pay," followed by one
+ character.
+
+
+
+1 Opr_Dbg_Dir_Mode
+ Operating and Debugging in Direct Mode
+
+ Direct Mode is an important tool in GT.M because it allows you to
+ interactively debug, modify, and execute M routines. Direct Mode is a
+ DCL that immediately compiles and executes GT.M commands providing an
+ interpretive-like interface. M simplifies debugging by using the same
+ commands for debugging that are used for programming.
+
+ The focus of this chapter is to describe the debugging process in
+ Direct Mode, and to illustrate the GT.M language extensions that
+ enhance the process. Command functionality is described only in enough
+ detail to illustrate why a particular command is useful for a debugging
+ activity being described. If you have specific functionality questions
+ about a command or variable, refer to the "Commands", "Functions" or
+ "Intrinsic Special Variables" chapters in GT.M Programmer's Guide.
+
+2 Opr_Dir_Mode
+ Operating in Direct Mode
+
+ This section provides an overview of the following basic operational
+ issues in Direct Mode:
+
+ o Entering Direct Mode
+
+ o Available functionality
+
+ o Exiting Direct Mode
+
+3 Entr_Dir_Mode
+ Entering Direct Mode
+
+ To enter Direct Mode, type MUMPS/DIRECT or GTM at the DCL prompt.
+
+ Example:
+
+
+ $ SHOW SYMBOL GTM
+
+ GTM=="MUMPS/DIRECT"
+
+ The SHOW SYMBOL command entered at the DCL prompt shows that the symbol
+ GTM is equivalent to MUMPS/DIRECT. Your site may have a different
+ definition for GTM in order to provide additional debugging tools. The
+ effect of using the symbol should be generally the same.
+
+3 Func_in_Dir_Mode
+ Functionality Available in Direct Mode
+
+ This section provides an overview of basic functionality and concepts
+ that enhance your use of Direct Mode.
+
+4 Comm_Recall
+ Command Recall
+
+ Direct Mode includes a line command recall function similar to the DCL
+ recall function, which displays previously entered command lines. Use
+ the Up Arrow key at the GTM> prompt to scroll back through command
+ lines. Usethe Down Arrow key to scroll forward through the command
+ lines. GT.M displays one command line at a time. Once you have recalled
+ a command, you can edit it if you wish and then reissue it.
+
+ The RECALL command is another way to access previously entered Direct
+ Mode command lines. RECALL is only valid in Direct Mode and causes an
+ error if it appears in other M code.
+
+ The format of the
+ RECALL command is:
+
+
+ REC[ALL] [intlit|strlit]
+
+ o The optional integer literal specifies a previously entered command
+ by the counting back from the present.
+
+ o The optional string literal specifies the most recently entered
+ command line that starts with characters matching the
+ (case-sensitive) literal.
+
+ o When the RECALL command has no argument, it displays up to a
+ maximum of 99 available past Direct Mode entries.
+
+ If the Direct Mode session has just started, you may not have entered
+ 99 lines for GT.M to save and therefore you will not have 99 lines to
+ look at. The most recently entered GT.M command line has the number one
+ (1), older lines have higher numbers. GT.M does not include the RECALL
+ command in the listing. If the RECALL command is issued from a location
+ other than the Direct Mode prompt, GT.M issues a run-time error.
+
+ Example:
+
+
+ GTM>WRITE $ZGBLDIR
+
+ M.GLD
+
+ GTM>SET $ZGBLDIR TEST.GLD
+
+ GTM>SET A=10
+
+ GTM>SET B=A
+
+ GTM>REC
+
+ 1 SET B=A
+ 2 SET A=10
+ 3 SET $ZGBLDIR TEST.GLD
+ 4 WRITE $ZGBLDIR
+ This REC[ALL] command displays the previously entered commands.
+
+ You can also display a selected command by entering RECALL and the line
+ number of the command you want to retrieve.
+
+ Example:
+
+
+ GTM>REC 2
+
+ GTM>SET A=10
+
+ This RECALLs the line number two (2).
+
+ If the RE[CALL] command includes a text parameter, GT.M displays the
+ most recent command matching the text after the RE[CALL] command.
+
+ Example:
+
+
+ GTM>REC WRITE
+
+ GTM>WRITE $ZGBLDIR
+
+ MUMPS.GLD
+
+ This RECALLs "WRITE", the command most recently beginning with this
+ text. Note that the RECALL command text is case sensitive. The RECALL
+ command with a text argument treats WRITE and write differently, that
+ is, it treats them case sensitively. If you first type the WRITE
+ command in lower-case and then type WRITE in upper-case to recall it,
+ the RECALL command does not find a match.
+
+4 Line_Editing
+ Line Editing
+
+ GT.M permits the use of the VMS command line editor at the Direct Mode
+ prompt and during M READs from a terminal. The VMS line editor allows
+ cursor positioning using the <CTRL> key, edit keypad and function keys.
+ Also, it allows toggling between insert and overstrike modes. The
+ command line editing feature is optional; by default VMS has command
+ line editing turned on.
+
+ For more information regarding the VMS command line editor, refer to
+ the VMS Guide to Using VMS.
+
+4 M_Invo_Stack
+ The M Invocation Stack
+
+ The ANSI M Standard describes certain M operations in terms of how a
+ stack-based virtual machine would operate. A stack is a repository for
+ tracking temporary information on a "last-in/first-out" (LIFO) basis. M
+ program behavior can be understood using a stack-based model. However,
+ the standard is not explicit in defining how an implementation must
+ maintain a stack or even whether it must use one at all.
+
+ The stack model provides a trail of routines currently in progress that
+ shows the location of all the M operations that performed the
+ invocations leading to the current point.
+
+3 Exit_Dir_Mode
+ Exiting Direct Mode
+
+ Four M commands terminate a Direct Mode session:
+
+ o HALT
+
+ o ZCONTINUE
+
+ o GOTO
+
+ o ZGOTO
+
+ The
+ HALT command, or a <CTRL-Z> exits Direct Mode and terminates the M
+ process.
+
+ The
+ ZCONTINUE command instructs GT.M to exit Direct Mode and resume routine
+ execution at the current point in the M invocation stack. This may be
+ the point where GT.M interrupted execution and entered Direct Mode.
+ However, when the Direct Mode interaction includes a QUIT command, it
+ modifies the invocation stack and causes ZCONTINUE to resume execution
+ at another point.
+
+ The
+ GOTO and
+ ZGOTO commands instruct GT.M to leave Direct Mode, and transfer control
+ to a specified entry reference.
+
+2 Debug_Rtn_Dir_Mode
+ Debugging a Routine in Direct Mode
+
+ To begin a debugging session on a specific routine, type the following
+ command at the GTM prompt:
+
+
+ GTM>DO ^routinename
+
+ You can also begin a debugging session by pressing <CTRL-C> after
+ running an M application packaged as an executable image from DCL. To
+ invoke Direct Mode by pressing <CTRL-C>, process must have the
+ Principal Device in the CENABLE state and not have the device set to
+ CTRAP=$C(3).
+
+ When GT.M receives a <CTRL-C> command from the principal device, it
+ invokes Direct Mode at the next opportunity, (usually at a point
+ corresponding to the beginning of the next source line). GT.M can also
+ interrupt at a FOR loop iteration or during a command of indeterminate
+ duration such as JOB, LOCK, OPEN or READ. The GT.M USE command
+ enables/disables the <CTRL-C> interrupt with the [NO]CENABLE
+ deviceparameter. The default setting for <CTRL-C> handling is
+ controlled by GTM$DEFAULTS.M64 and is enabled in the distribution
+ version of that file.
+
+ GT.M displays the GTM> prompt on the principal device. Direct Mode
+ accepts commands from, and reports errors to, the principal device.
+ GT.M uses the current device for all other I/O. If the current device
+ does not match the principal device when GT.M enters Direct Mode, GT.M
+ issues a warning message on the principal device. A USE command changes
+ the current device. For more information on the USE command, refer to
+ the "Input/Output Processing" chapter.
+
+ The default "compile-as-written" mode of the GT.M compiler lets you run
+ a program with errors as part of the debugging cycle. The object code
+ produced includes all lines that are correct and all commands on a line
+ with an error, up to the error. When GT.M encounters an error, it
+ XECUTEs non empty values of $ETRAP or $ZTRAP. By default $ZTRAP
+ contains a BREAK command, so GT.M enters Direct Mode.
+
+ The rest of the chapter illustrates the debugging capabilities of GT.M
+ by taking a sample routine, dmex, through the debugging process. dmex
+ is intended to read and edit a name, print the last and first name, and
+ terminate if the name is an upper-case or lower-case "Q".
+
+ Each of the remaining sections of the chapter uses dmex to illustrate
+ an aspect of the debugging process in GT.M.
+
+3 Creat_Display_M_Rtn
+ Creating and Displaying M Routines
+
+ To create or edit a routine, use the
+ ZEDIT command. ZEDIT invokes the Text Processing Utility (TPU) section
+ file for GT.M and opens the specified file. dmex.m, for editing.
+
+ Example:
+
+
+ GTM>ZEDIT "dmex"
+
+ Once in the editor, use the arrow keys to move between lines of text.
+ When you finish editing, press <CTRL-Z> to save the changes, which
+ returns you to Direct Mode.
+
+ For further details and examples, refer to the GT.M Programmer's
+ Guide.
+
+3 Exec_M_Rtn_Inter
+ Executing M Routines Interactively
+
+ To execute an M routine interactively, it is not necessary to
+ explicitly compile and link your program. When you refer to an M
+ routine that is not part of the current image, GT.M automatically
+ attempts to compile and
+ ZLINK the program.
+
+ Example:
+
+
+ GTM>DO ^dmex
+
+ Name: Revere, Paul
+
+ %GTM-E-UNDEF, Undefined local variable: bame
+
+ At M source location name+3^DMEX
+
+ GTM>
+
+ In this example GT.M places you in Direct Mode, but also cites an error
+ found in the program with a run-time error message. In this example, it
+ was a reference to bame, which is undefined.
+
+ To see additional information about the error message, examine the
+ $ECODE or
+ $ZSTATUS special variables.
+
+ $ECODE is read-write intrinsic special variable that maintains a list
+ of comma delimited codes that describe a history of past errors - the
+ most recent ones appear at the end of the list. In $ECODE, standard
+ errors are prefixed with an "M", user defined errors with a "U", and
+ GT.M errors with a "Z". A GT.M code always follows a standard code.
+
+ $ZSTATUS is a read-write intrinsic special variable that maintains a
+ string containing the error condition code and location of the last
+ exception condition occurring during routine execution. $ZSTATUS
+ information always contains all components of the VMS error message
+ format (message number, facility, error severity, identification and
+ text). GT.M updates $ZSTATUS only for errors found in routines and not
+ for errors entered at the Direct Mode prompt.
+
+ For further details and examples, refer to the GT.M Programmer's
+ Guide.
+
+3 Proc_with_Runtime_Syn_Err
+ Processing with Run-time and Syntax Errors
+
+ When GT.M encounters a run-time or syntax error, it stops executing and
+ displays an error message. GT.M reports the error in the message. In
+ this case, GT.M reports an undefined local variable and the line in
+ error, name+3^DMEX. Note that GT.M re-displays the GTM> prompt so that
+ debugging may continue.
+
+ To re-display the line and identify the error, use the
+ ZPRINT command.
+
+ Example:
+
+
+ GTM>ZPRINT, name+3
+
+ %GTM-E-SPOREOL, Either a space or an end-of-line was expected but not
+ found
+ ZP, name+3
+
+ ^_____
+
+ GTM>
+
+ This example shows the result of incorrectly entering a ZPRINT command
+ in Direct Mode. GT.M reports the location of the syntax error in the
+ command line with an arrow. $ECODE and $ZSTATUS do not maintain this
+ error message because GT.M did not produce the message during routine
+ execution. Enter the correct syntax, (i.e., remove the comma) to
+ re-display the routine line in error.
+
+ Example:
+
+
+ GTM>WRITE $ZPOS
+
+ name+3^DMEX
+
+ This example writes the current line position.
+
+ $ZPOSITION is a read-only GT.M special variable that provides another
+ tool for locating and displaying the current line. It contains the
+ current entry reference as a character string in the format
+ label+offset^routine, where the label is the closest preceding label.
+ The current entry reference appears at the top of the
+ M invocation stack, which can also be displayed with a
+ ZSHOW "S" command.
+
+ To display the current value of every local variable defined, use the
+ ZWRITE command with no arguments.
+
+ Example:
+
+
+ GTM>ZWRITE
+
+ ln=12
+
+ name="Revere, Paul"
+
+ This ZWRITE displays a listing of all the local variables currently
+ defined.
+
+ ZWRITE displays the variable name. ZWRITE does not display a value
+ for bame, confirming that it is not defined.
+
+3 Correcting_Errors
+ Correcting Errors
+
+ Use the
+ ZBREAK command to establish a temporary breakpoint and specify an
+ action. ZBREAK sets or clears routine-transparent breakpoints during
+ debugging. This command simplifies debugging by interrupting execution
+ at a specific point to examine variables, execute commands, or to start
+ using
+ ZSTEP to execute the routine line by line.
+
+ GT.M suspends execution during execution when the entry reference
+ specified by ZBREAK is encountered. If the ZBREAK does not specify an
+ expression "action", the process uses the default,
+ BREAK, and puts GT.M into Direct Mode. If the ZBREAK does specify an
+ expression "action", the process XECUTEs the value of "action", and
+ does not enter Direct Mode unless the action includes a BREAK. The
+ action serves as a "trace-point". The trace-point is silent unless the
+ action specifies terminal output.
+
+ Example:
+
+
+ GTM>ZBREAK name+3^dmex:"set bame=name"
+
+ This uses a ZBREAK with an action that SETs the variable bame equal to
+ name.
+
+3 Stepping_Thru_Rtn
+ Stepping Through a Routine
+
+ The
+ ZSTEP command provides a powerful tool to direct GT.M execution. When
+ you issue a ZSTEP from Direct Mode, GT.M executes the program to the
+ beginning of the next target line and performs the ZSTEP action.
+
+ The optional keyword portion of the argument specifies the class of
+ lines where ZSTEP pauses its execution, and XECUTEs the ZSTEP action
+ specified by the optional action portion of the ZSTEP argument. If the
+ action is specified, it must be an expression that evaluates to valid
+ GT.M code. If no action is specified, ZSTEP XECUTEs the code specified
+ by the $ZSTEP intrinsic special variable; by default $ZSTEP has the
+ value "B", which causes GT.M to enter Direct Mode.
+
+ ZSTEP actions, that include commands followed by a BREAK, perform the
+ specified action, then enter Direct Mode. ZSTEP actions that do not
+ include a BREAK perform the command action and continue execution. Use
+ ZSTEP actions that issue conditional BREAKs and subsequent ZSTEPs to
+ perform tasks such as test for changes in the value of a variable.
+
+ Use ZSTEP to incrementally execute a routine or a series of routines.
+ Execute any GT.M command from Direct Mode at any ZSTEP pause. To resume
+ normal execution, use ZCONTINUE. Note that ZSTEP arguments are keywords
+ rather than expressions, and they do not allow indirection.
+
+ Example:
+
+
+ GTM>ZSTEP INTO
+
+ %GTM-I-BREAKZST, Break instruction encountered during ZSTEP action
+
+ At M source location print^DMEX
+
+ GTM>ZSTEP OUTOF
+
+ Paul Revere
+
+ Name: Q
+
+ %GTM-I-BREAKZST, Break instruction encountered during ZSTEP action
+
+ At M source location name^DMEX
+
+ GTM>ZSTEP OVER
+
+ %GTM-I-BREAKZST, Break instruction encountered during ZSTEP action
+
+ At M source location name+1^DMEX
+
+ This shows using the ZSTEP command to step through the routine DMEX
+ starting where execution was interrupted by the undefined variable
+ error. The ZSTEP INTO command executes line name+3 and then interrupts
+ execution at the beginning of line "print".
+
+ The ZSTEP OUTOF continues execution until line name. The ZSTEP OVER,
+ which is the default, executes until it encounters the next line at
+ this level on the M invocation stack. In this case, the next line is
+ name+1. The ZSTEP OVER could be replaced with a ZSTEP with no argument
+ because they do the same thing.
+
+3 Cont_Exec_Frm_Breakpt
+ Continuing Execution From a Breakpoint
+
+ Use the
+ ZCONTINUE command to continue execution from the breakpoint.
+
+ Example:
+
+
+ GTM>ZCONTINUE
+
+ Paul Revere
+
+ Name: q
+
+ Name: QUIT
+
+ Name: ?
+
+ Please use last-name, first name middle-initial
+
+ or 'Q' to Quit.
+
+ Name:
+
+ This uses a ZCONTINUE command to resume execution from the point where
+ it was interrupted. As a result of the ZBREAK action, bame is defined
+ and the error does not occur again. Because the process does not
+ terminate as intended when the name read has q as a value, we need to
+ continue debugging.
+
+3 Interr_Execution
+ Interruption Execution
+
+ Press <CTRL-C> to interrupt execution, and return to the GTM prompt to
+ continue debugging the program.
+
+ Example:
+
+
+ %GTM-I-CTRLC, CTRLC_C encountered.
+
+ GTM>
+
+ This invokes direct mode with a <CTRL-C>.
+
+3 Using_Invoc_Stac_in_Debug
+ Using the Invocation Stack in Debugging
+
+ M DOs, XECUTEs, and extrinsics add a level to the invocation stack.
+ Matching QUITs take a level off the stack. When GT.M executes either of
+ these commands, an extrinsic function, or an extrinsic special
+ variable, it "pushes" information about the new environment on the
+ stack. When GT.M executes the
+ QUIT, it "pops" the information about the discarded environment off the
+ stack. It then reinstates the invoking routine information using the
+ entries that have now arrived at the active end of the stack.
+
+ In the M stack model, a
+ FOR command does not add a stack frame, and a QUIT that terminates
+ a FOR loop does not remove a stack frame.
+
+4 Deter_Levels_of_Nest
+ Determining Levels of Nesting
+
+ $STACK contains an integer value indicating the "level of nesting"
+ caused by DO commands, XECUTE commands, and extrinsic functions in the
+ M virtual stack.
+
+ $STACK has an initial value of zero (0), and increments by one with
+ each DO, XECUTE, or extrinsic function. Any QUIT that does not
+ terminate a FOR loop or any ZGOTO command decrements $STACK. In
+ accordance with the M standard, a FOR command does not increase $STACK.
+ M routines cannot modify $STACK with the SET or KILL commands.
+
+ Example:
+
+
+ GTM>WRITE $STACK
+
+ 2
+ GTM>WRITE $ZLEVEL
+
+ 3
+ GTM>
+
+ This example shows the current values for
+ $STACK and
+ $ZLEVEL. $ZLEVEL is like $STACK except that uses one (1) as the
+ starting level for the M stack, which $STACK uses zero (0), which means
+ that $ZLEVEL is always one more than $STACK. Using $ZLEVEL with "Z"
+ commands and functions, and $STACK with standard functions avoids the
+ need to calculate the adjustment.
+
+4 Look_Invoc_Stack
+ Looking at the Invocation Stack
+
+ The $STACK intrinsic special variable and the $STACK() function provide
+ a mechanism to access M stack context information.
+
+ Example:
+
+
+ GTM>WRITE $STACK
+
+ 2
+ GTM>WRITE $STACK(2,"ecode")
+
+ ,M6,Z150373850,
+
+ GTM>WRITE $STACK(2,"place")
+
+ name+3^DMEX
+
+ GTM>WRITE $STACK(2,"mcode")
+
+ if ln<30,bame?1.a.1"-".a1","1" "1a.ap do print q
+
+ GTM>
+
+ This example gets the value of $STACK and then uses that value to get
+ various types of information about that stack level using the
+ $STACK() function. The "ecode" value of the error information for level
+ two, "place" is similar to
+ $ZPOSITION, "mcode" is the code for the level.
+
+ In addition to the $STACK intrinsic special variable, which provides
+ the current stack level, $STACK(-1) gives the highest level for which
+ $STACK() can return valid information. Until there is an error $STACK
+ and $STACK(-1) are the same, but once
+ $ECODE shows that there is an "current" error, the information returned
+ by $STACK() is frozen to capture the state at the time of the error; it
+ unfreezes after a SET $ECODE="".
+
+ Example:
+
+
+ GTM>WRITE $STACK
+
+ 2
+ GTM>WRITE $STACK(-1)
+
+ 2
+ GTM>
+
+ This example shows that under the conditions created (in the above
+ example), $STACK and $STACK(-1) have the same value.
+
+ The $STACK() can return information about lower levels.
+
+ Example:
+
+
+ +1^GTM$DMOD
+
+ GTM>WRITE $STACK(1,"ecode")
+
+
+ GTM>WRITE $STACK(1,"place")
+
+ beg^DMEX
+
+ GTM>WRITE $STACK(1,"mcode")
+
+ beg for read !,"Name:",namde do name
+
+ GTM>
+
+ This example shows that there was no error at $STACK level one, as well
+ as the "place" and "mcode" information for that level.
+
+4 Using_ZSHOW_Ex_Context_Info
+ Using ZSHOW to Examine Context Information
+
+ The ZSHOW command displays information about the M environment.
+
+ Example:
+
+
+ GTM>ZSHOW "*"
+
+ $DEVICE=""
+
+ $ECODE=",M6,Z150373850,"
+
+ $ESTACK=2
+
+ $ETRAP=""
+
+ $HOROLOG="59149,36200"
+
+ $IO="_TNA215"
+
+ $JOB=501063439
+
+ $KEY=""
+
+ $PRINCIPAL="_TNA215"
+
+ $QUIT=0
+
+ $REFERENCE=""
+
+ $STACK=2
+
+ $STORAGE=2147483647
+
+ $SYSTEM="47,gtm_sysid"
+
+ $TEST=1
+
+ $TLEVEL=0
+
+ $TRESTART=0
+
+ $X=0
+
+ $Y=23
+
+ $ZA=0
+
+ $ZB=$C(13)
+
+ $ZCMDLINE=""
+
+ $ZCOMPILE=""
+
+ $ZCSTATUS=0
+
+ $ZDIRECTORY="DISK1:[home]"
+
+ $ZEDITOR=0
+
+ $ZEOF=0
+
+ $ZERROR="Unprocessed $ZERROR, see $ZSTATUS"
+
+ $ZGBLDIR="mumps.gld"
+
+ $ZININTERRUPT=0
+
+ $ZINTERRUPT="IF $ZJOBEXAM()"
+
+ $ZIO="_TNA215"
+
+ $ZJOB=0
+
+ $ZLEVEL=3
+
+ $ZMODE="INTERACTIVE"
+
+ $ZPOSITION="name+3^DMEX"
+
+ $ZPROCESS=""
+
+ $ZPROMPT="GTM>"
+
+ $ZROUTINES="[],GTM$DIST"
+
+ $ZSOURCE=""
+
+ $ZSTATUS="150373850,name+3^DMEX,%GTM-E-UNDEF, Undefined local variable:
+ bame"
+ $ZSYSTEM=0
+
+ $ZTRAP="B"
+
+ $ZVERSION="GT.M V4.3-001D VMS AXP"
+
+ $ZYERROR=""
+
+ bame="?"
+
+ ln=12
+
+ name=""
+
+_TNA219: OPEN TERMINAL EDIT NOESCA HOST NOINSE NOPAST NOREADS TTSY TYPE WIDTH=80 LENG=24
+ name+3^DMEX ($ZTRAP)
+
+ (Direct mode)
+
+ beg^DMEX
+
+ ^GTM$DMOD (Direct mode)
+
+
+ GTM>
+
+ This example uses the asterisk (*) argument to show all information
+ that ZSHOW offers in this context. First are the Intrinsic Special
+ Variables ($DEVICE-$ZYERROR, also available with ZSHOW "I"), then the
+ local variables (bame, ln and name, also available with ZSHOW "V"),
+ then the ZBREAK locations (name+3^DMEX, also available with ZSHOW "B"),
+ then the device information (also available with ZSHOW "D"), then the M
+ stack (also available with ZSHOW "S"). ZSHOW "S" is the default for
+ ZSHOW with no arguments.
+
+ Context information that does not exist in this example includes M
+ LOCKs of this process (
+ ZSHOW "L"), and available external calls (ZSHOW "C").
+
+ In addition to directing its output to the current device, ZSHOW can
+ place its output in a local or global variable array. For more
+ information, refer to the ZSHOW section of the "Commands" chapter in
+ GT.M Programmer's Guide.
+
+ ZSHOW "V" produces the same output as ZWRITE with no arguments, but
+ ZSHOW "V" can be directed to a variable as well as a device.
+
+3 Transf_Rtn_Control
+ Transferring Routine Control
+
+ The
+ ZGOTO command transfers control from one part of the routine to
+ another, or from one routine to another, using the specified entry
+ reference. The ZGOTO command takes an optional integer expression that
+ indicates the M stack level reached by performing the ZGOTO, and an
+ optional entry reference specifying the location to where ZGOTO
+ transfers control. A ZGOTO command, with an entry reference, performs a
+ function similar to the GOTO command with the additional capability of
+ reducing the M stack level. In a single operation, the process executes
+ $ZLEVEL-intexpr, implicit QUITs from DO or extrinsic operations, and a
+ GOTO operation transferring control to the named entry reference.
+
+ The ZGOTO command leaves the invocation stack at the level of the value
+ of the integer expression. GT.M implicitly terminates any intervening
+ FOR loops and unstacks variables stacked with NEW commands, as
+ appropriate.
+
+ ZGOTO $ZLEVEL:LABEL^ROUTINE takes the same action as GO LABEL^ROUTINE.
+
+ ZGOTO $ZLEVEL-1 produces the same result as QUIT (followed by
+ ZCONTINUE, if in Direct Mode).
+
+ If the integer expression evaluates to a value greater than the current
+ value of $ZLEVEL, or less than zero (0), GT.M issues a run-time error.
+
+ If ZGOTO has no entry reference, it performs some number of implicit
+ QUITs and transfers control to the next command at the specified level.
+ When no argument is specified, ZGOTO 1 is the result, and operation
+ resumes at the lowest level M routine as displayed by ZSHOW "S". In the
+ image invoked by MUMPS/DIRECT, or a similar image, a ZGOTO without
+ arguments returns the process to Direct Mode.
+
+3 Disp_Source_code
+ Displaying Source Code
+
+ Use the
+ ZPRINT command to display source code lines selected by its argument.
+ ZPRINT allows you to display the source for the current routine and any
+ other related routines. Use the ZPRINT command to display the last call
+ level.
+
+ Example:
+
+
+ GTM>ZPRINT beg
+
+ beg for read !,"Name: ",name do name
+
+ This example uses a ZPRINT command to print the line indicated as the
+ call at the top of the stack. Notice that the routine has an error in
+ logic. The line starting with the label beg has a FOR loop with no
+ control variable, no QUIT, and no GOTO. There is no way out of the FOR
+ loop.
+
+3 Correct_Errs_in_M_Rtn
+ Correcting Errors in an M Routine
+
+ Now that the routine errors have been identified, correct them in the M
+ source file. Use
+ ZEDIT to invoke the editor and open the file for editing. Correct the
+ errors previously identified and enter <CTRL-Z> to exit the editor.
+
+ Example:
+
+
+ GTM>ZEDIT "dmex"
+
+ dmex ;dmex - Direct Mode example
+
+ ;
+
+ beg for read !,"Name: ",name do name q:name="Q"
+
+ quit
+
+ name set ln=$l(name)
+
+ if ln,$e("QUIT",1,ln)=$tr(name,"quit","QUIT") d q
+
+ . s name="Q"
+
+ if ln<30,name?1.a.1"-".a1","1" "1a.ap do print q
+
+ write !,"Please use last-name, "
+
+ write "first-name middle-initial or 'Q' to Quit."
+
+ quit
+
+ print write !,$p(name,", ",2)," ",$p(name,", ")
+
+ quit
+
+ GTM>
+
+ This example shows the final state of a ZEDIT session of dmex.m. Note
+ that the infinite FOR loop at line beg is corrected.
+
+3 Relink_Edited_Rtn
+ Relinking the Edited Routine
+
+ Use the ZLINK command to add the edited routine to the current image.
+ ZLINK automatically recompiles and relinks the routine. If the routine
+ was the most recent one ZEDITed or ZLINKed, you do not have to specify
+ the routine name with the ZLINK command.
+
+ You may have to issue a ZGOTO or a QUIT command to remove the
+ unedited version of the routine from the M invocation stack before
+ ZLINKing the edited version.
+
+ Example:
+
+
+ GTM>ZLINK
+
+ %GTM-E-LOADRUNNING, Cannot ZLINK an active routine
+
+ This illustrates a GT.M error report caused by an attempt to ZLINK a
+ routine that is part of the current invocation stack.
+
+ To ZLINK the routine, remove any invocation levels for the routine off
+ of the call stack. You may use the ZSHOW "S" command to display the
+ current state of the call stack. Use the QUIT command to remove one
+ level at a time from the call stack. Use the ZGOTO command to remove
+ multiple levels off of the call stack.
+
+ For further details and examples, refer to the GT.M Programmer's
+ Guide.
+
+3 Reexec_the_Rtn
+ Re-executing the Routine
+
+ Re-display the DO command using the RECALL command.
+
+ Execute the routine using the DO command.
+
+ Example:
+
+
+ GTM>rec d
+
+ GTM>D ^dmex
+
+
+ Name: Revere, Paul
+
+ Paul Revere
+
+ Name: q
+
+ This example illustrates a successful execution of dmex.
+
+3 Using_Spawned_Proc
+ Using Spawned Processes
+
+ The ZSYSTEM command creates a subprocess of the current process in a
+ fashion analogous to the DCL SPAWN command.
+
+ The
+ ZSYSTEM command creates a new process called the child process, and
+ passes its argument to a Command Language Interpreter (generally DCL)
+ for execution. The new process executes in the same directory as the
+ initiating process. The new process has the same VMS enviroment, such
+ as logical names and input/output devices, as the initiating process.
+ The initiating process pauses until the new process completes before
+ continuing execution.
+
+ Example:
+
+
+ GTM>ZSYSTEM
+
+ $ DIRECTORY dmex.*
+
+ Directory USER: [SMITH]
+
+ DMEX.M;6 DMEX.M;5 DMEX.M;4 DMEX.M;3
+
+ DMEX.M;2 DMEX.M;1 DMEX.OBJ;3 DMEX.OBJ;2 DMEX.OBJ;1
+
+ Total of 9 files
+
+ $ SHOW PROCESS/SUB
+
+ There are 2 processes in this job:
+
+ SMITH
+
+ SMITH_1(*)
+
+ $ATTACH
+
+_Process: SMITH
+ GTM>
+
+ This uses ZSYSTEM to create a subprocess called SMITH_1. Note that the
+ asterisk (*) following SMITH_1 identifies the currently active sub
+ process. Notice that the results of the DIRECTORY command at the DCL
+ prompt shows source (indicated by a .M extension) and object files
+ (indicated by a .OBJ extension) for the routine dmex. The SHOW
+ PROCESS/SUB command shows the main process SMITH, and the newly created
+ subprocess SMITH_1(*). The ATTACH command passes execution control to
+ the process named SMITH and leaves the SMITH_1 subprocess in existence;
+ a LOGOUT command would also return control to SMITH, but would
+ terminate SMITH_1.
+
+1 Lang_Features_M
+ General Language Features of M
+
+ MUMPS is a general purpose language with an embedded database system.
+ This section of the help file describes the features of the language
+ that are not covered as Commands, Functions, or Intrinsic Special
+ Variables.
+
+2 Data_Types
+ Data Types
+
+ M operates with a single basic data type, string. However, M evaluates
+ data using methods that vary according to context.
+
+3 Num_Expressions
+ Numeric Expressions
+
+ When M syntax specifies a numexpr, M evaluates the data as a sequence
+ of ASCII characters that specify a number. M stops the evaluation and
+ provides the result generated from successfully evaluated characters
+ when it encounters any character that is not the following:
+
+ o A digit 0-9
+
+ o A plus sign (+) or minus sign (-) and also the first character in
+ the string
+
+ o The first decimal point (.) in the string
+
+3 Num_Accuracy
+ Numeric Accuracy
+
+ GT.M provides 18 digits of accuracy, independent of the decimal point
+ (.) placement, and a numeric range from 10**(-43) to (10**47). Numbers
+ with three digits or fewer to the right of the decimal point are
+ precise.
+
+3 Int_Expressions
+ Integer Expressions
+
+ When M syntax specifies an intexpr, M evaluates the data as it would a
+ numexpr except that it stops the evaluation at any decimal point
+ including the first.
+
+3 Truth_valued_Expr
+ Truth-valued Expressions
+
+ When M syntax specifies a tvexpr, M evaluates the data as a numeric.
+ However, it stops the evaluation and returns a true value (1) as soon
+ as it encounters a non-zero digit, otherwise it returns a false value
+ (0). In other words, M treats expressions that have a non-zero numeric
+ value as true, and expressions that have a zero numeric value as false.
+ The sign and/or decimal have no affect on the evaluation of a
+ truth-valued expression.
+
+2 M_Names
+ M Names
+
+ M uses names for variables, LOCK command arguments, labels on lines,
+ and routine names. M names are alphanumeric and must start with an
+ alphabetic character or a percent sign (%).
+
+ The percent sign can only appear as the first character in a name. By
+ convention, names starting with percent signs are generally
+ application-independent or distinguished in some similar way.
+
+ M does not reserve any names. That is, M always distinguishes keywords
+ by context. Therefore, M permits a variable or a label called SET even
+ though the language has a command called SET.
+
+ M names are case sensitive. That is, M treats ABC, Abc, ABc, AbC ABC,
+ and abc as six different names. GT.M relies on RMS files to hold
+ routines and, in certain circumstances, on the VMS Linker to manage
+ routines. Because these VMS facilities are not case sensitive, GT.M
+ makes an exception for routine names and always treats them as upper
+ case.
+
+ M does not restrict the length of names in the main body of the
+ standard. However, the portability section of the standard recommends
+ limiting names to a maximum of eight (8) characters. GT.M effectively
+ limits names to eight characters by ignoring any characters after the
+ first eight.
+
+2 Variables
+ Variables
+
+ M does not require predefinition of variable type or size. M variables
+ are either local or global. Any variable may be unsubscripted or
+ subscripted.
+
+3 Arrays_Subscripts
+ Arrays and Subscripts
+
+ In M, subscripted variables identify elements in sparse arrays. Sparse
+ arrays comprise existing subscripts and data nodes - no space is
+ reserved for potential data nodes. These arrays generally serve
+ logical, rather than mathematical, purposes.
+
+ M array subscripts are expressions, and are not restricted to numeric
+ values.
+
+ The format for an M global or local variable is:
+
+ [^]name[(expr1[,...])]
+ o The optional leading caret symbol (^) designates a global variable.
+
+ o The name specifies a particular array.
+
+ o The optional expressions specify the subscripts
+ o and must be enclosed in parentheses and separated by commas (,).
+
+ The body of the M standard places no restrictions on variable names.
+ However, the portability section of the standard does suggest limits on
+ the length of an individual subscript expression, and on the total
+ length of a variable name. The measurement for the length of names
+ includes the length of the global variable name itself, the sum of the
+ lengths of all the evaluated subscripts, and an allowance for an
+ overhead of two (2) times the number of subscripts. The total must not
+ exceed 237. For globals, GT.M permits this total to be modified with
+ GDE up to 255. For locals, GT.M limits the length of individual
+ subscripts to the maximum string length of 32,767. GT.M restricts the
+ number of subscripts for local or global variables to 32.
+
+3 M_Collation_Seq
+ M Collation Sequences
+
+ M collates all canonic numeric subscripts ahead of all string
+ subscripts, including strings such as those with leading zeros that
+ represent non-canonic numbers. Numeric subscripts collate from negative
+ to positive in value order. String subscripts collate in ASCII
+ sequence. In addition, GT.M allows the empty string subscript in most
+ contexts, (the null, or empty, string collates ahead of all canonic
+ numeric subscripts).
+
+ GT.M allows definition of alternative collation sequences. For complete
+ information on enabling this functionality, refer to the
+ "Internationalization" chapter in GT.M Programmer's Guide.
+
+3 Local_Variables
+ Local Variables
+
+ A local variable in M refers to a variable used solely within the scope
+ of a single process. Local variable names have no leading delimiter.
+
+ M makes a local variable available and subject to modification by all
+ routines executed within a process from the time that variable is first
+ SET until it is KILLed, or until the process stops executing M.
+ However, M "protects" a local variable after that variable appears as
+ an argument to a NEW command, or after it appears as an element in a
+ formalist used in parameter passing. When M protects a local variable,
+ it saves a copy of the variable's value and makes that variable
+ undefined. M restores the variable to its saved value during execution
+ of the QUIT that terminates the process stack level associated with the
+ "protecting" NEW or formalist. For more information on NEW and QUIT,
+ refer to the "Commands" chapter in GT.M Programmer's Guide.
+
+ M restricts the following uses of variables to local variables:
+
+ o FOR command control variables.
+
+ o Elements within the parentheses of an "exclusive" KILL.
+
+ o TSTART [with local variables list].
+
+ o A KILL with no arguments removes all current local variables.
+
+ o NEW command arguments.
+
+ Actualnames used by pass-by-reference parameter passing.
+
+3 Glob_Var_Resrc_Nam_Env
+ Global Variables and Resource Name Environments
+
+ M recognizes an optional environment specification in global names or
+ in the LOCK resource names (nrefs), which have analogous syntax. Global
+ variable names have a leading caret symbol (^) as a delimiter.
+
+ M makes a global variable available, and subject to modification by all
+ routines executed within all processes in an environment, from the time
+ that variable is first SET until it is KILLed.
+
+4 Naked_References
+ Naked References
+
+ M accepts an abbreviation of the global name under some circumstances.
+ When the leading caret symbol (^) immediately precedes the left
+ parenthesis delimiting subscripts, the global variable reference is
+ called a naked reference. M evaluates a naked reference by prefixing
+ the last used global variable name, except for its last subscript, to
+ the list of subscripts specified by the naked reference. The prefixed
+ portion is known as the naked indicator. An attempt to use a naked
+ reference when the prior global reference does not exist, or did not
+ contain a subscript, generates an error.
+
+ Because M has only one process-wide naked indicator which it maintains
+ as a side affect of every evaluation of a global variable, using the
+ naked reference requires an understanding of M execution sequence. M
+ execution generally proceeds from left to right within a line, subject
+ to commands that change the flow of control. However, M evaluates the
+ portion of a SET command argument to the right side of the equal sign
+ before the left side. Also, M does not evaluate any further $SELECT()
+ arguments within the function after it encounters a true selection
+ argument.
+
+ In general, using naked references only in very limited circumstances
+ prevents problems associated with the naked indicator.
+
+4 Glob_Var_Name_Env
+ Global Variable Name Environments
+
+ M recognizes an optional environment specification in global names. The
+ environment specification designates one of some set of alternative
+ database files.
+
+ The syntax for global variable names that include an environment
+ specification is:
+
+ ^|expr|name[(subscript[,...])]
+
+ In GT.M, the expression identifies the Global Directory for mapping the
+ global variable.
+
+ Environment specifications permit easy access to global variables in
+ alternative databases, including other "copies" of active variables in
+ the current database. Environment specifications are sometimes referred
+ to as extended global syntax or extended value syntax.
+
+ GT.M also allows:
+
+ ^|expr1,expr2|name[(subscript[,...])]
+
+ Where the first expression identifies the Global Directory and the
+ second expression is accepted but ignored by GT.M.
+
+ To improve compatibility with some other M implementations, GT.M also
+ accepts another non-standard syntax. In this syntax, the leading and
+ trailing up-bar (|) are respectively replaced by a left square-bracket
+ ([) and a right square-bracket (]). This syntax also requires
+ expratoms, rather than expressions.
+
+ The formats for this non-standard syntax are:
+
+ ^[expratom1]name[(subscript...)]
+
+ or
+
+ ^[expratom1,expratom2]name[(subscript...)]
+
+ Where expratom1 identifies the Global Directory and expratom2 is a
+ dummy variable. Note that the first set of brackets in each format is
+ part of the syntax. The second set of square brackets is part of the
+ meta-language identifying an optional element.
+
+ Example:
+
+
+ $ DEFINE GTM$GBLDIR TEST.GLD
+
+ $ MUMPS/DIR
+
+ GTM>WRITE $ZGBLDIR
+
+ TEST.GLD
+
+ GTM>WRITE ^A
+
+ THIS IS ^A IN DATABASE RED
+
+ GTM>WRITE ^|"M1.GLD"|A
+
+ THIS IS ^A IN DATABASE WHITE
+
+ GTM>WRITE $ZGBLDIR
+
+ TEST.GLD
+
+ GTM>HALT
+
+ $ SHOW LOGICAL GTM$GBLDIR
+
+ TEST.GLD
+
+ The statement WRITE ^|"M1.GLD"|A writes variable ^A using the Global
+ Directory, M1.GLD, but does not change the current Global Directory.
+
+ Example:
+
+
+ GTM>WRITE $ZGBLDIR
+
+ M1.GLD
+
+ GTM>WRITE ^A
+
+ THIS IS ^A IN DATABASE WHITE
+
+ GTM>WRITE ^|"M1.GLD"|A
+
+ THIS IS ^A IN DATABASE WHITE
+
+ The statement WRITE ^|"M1.GLD"|A is equivalent to WRITE ^A.
+
+ Specifying separate Global Directories does not always translate to
+ using separate databases.
+
+ Example:
+
+
+ GTM>WRITE ^|"M1.GLD"|A,!,^|"M2.GLD"|A,!,^|"M3.GLD"
+
+|A,!
+ THIS IS ^A IN DATABASE WHITE
+
+ THIS IS ^A IN DATABASE BLUE
+
+ THIS IS ^A IN DATABASE WHITE
+
+ In this example, the WRITE does not display ^A from three GT.M database
+ files. Mapping specified by the Global Directory Editor (GDE)
+ determines the database file to which a Global Directory points.
+
+ This result could have occurred under the following mapping:
+
+
+ ^|"M1.GLD"|A --> REGIONA --> SEGMENTA --> FILE1.DAT
+
+ ^|"M2.GLD"|A --> REGIONA --> SEGMENT1 --> FILE2.DAT
+
+ ^|"M3.GLD"|A --> REGION3 --> SEGMENT3 --> FILE1.DAT
+
+ For more information on Global Directories, refer to the "Global
+ Directory Editor" chapter of the GT.M Administration and Operations
+ Guide.
+
+4 Opt_GTM_Env_Trans_Facility
+ Optional GT.M Environment Translation Facility
+
+ For users who wish to dynamically (at run-time) determine a global
+ directory from non-global directory information (typically UCI and VOL)
+ in the environment specification, GT.M provides an interface to add an
+ appropriate translation.
+
+ Using this facility impacts the performance of every global access that
+ uses environment specification. Make sure you use it only when static
+ determination of the global directory is not feasible. When used, make
+ every effort to keep the translation routines very efficient.
+
+ The use of this facility is enabled by the definition of the logical
+ GTM_ENV_TRANSLATE, which contains the path of a sharable image with the
+ following entry point:
+
+5 gtm_env_xlate
+ gtm_env_xlate
+
+ If the shared object is not accessible or the entry point is not
+ accessible, GT.M reports an error.
+
+ The gtm_env_xlate() routine has the following C prototype:
+
+
+ int gtm_env_xlate(xc_string_t *in1, xc_string_t *in2, xc_string *in3,
+ xc_string_t *out)
+ where xc_string_t is a structure defined in gtmxc_types.h as follows:
+
+
+ typedef struct
+
+ {
+
+ int length;
+
+ char *address;
+
+ } xc_string_t;
+
+ The purpose of the function is to use its three input arguments to
+ derive and return an output argument that can be used as an environment
+ specification by GT.M. Note that the input values passed (in1, in2 and
+ in3) are the result of M evaluation and must not be modified. The first
+ two arguments are the expressions passed within the up-bars "| |" or
+ the square-brackets "[ ]", and the third argument is the current
+ working directory as described by $ZDIRECTORY.
+
+ A return value other than zero (0) indicates an error in translation,
+ and is reported by a GT.M error
+
+ If the length of the output argument is non-zero, GT.M appends a
+ secondary message of GTM-I-TEXT, containing the text found at the
+ address of the output structure.
+
+ GT.M does not do any memory management related to the output argument -
+ space for the output should be allocated by the external routine. The
+ routine must place the returned environment specification at the
+ address it has allocated and adjust the length accordingly. On a
+ successful return, the return value should be zero. If the translation
+ routine must communicate an error to GT.M, it must return a non-zero
+ value, and if it is to communicate additional error information, place
+ the error text at the address where the environment would normally go
+ and adjust the length to match the length of the error text.
+
+ Length of the return value may range from 0-32767, otherwise GT.M
+ reports an error.
+
+ A zero-length (empty) string specifies the current value of $ZGBLDIR.
+ Non-zero lengths must represent the actual length of the file
+ specification pointed to by address, excluding any <NUL> terminator. If
+ the address field of the output argument is NULL, GT.M issues an error.
+
+
+ The file specification may be absolute or relative and may contain a
+ logical name. If the file specified is not accessible, or is not a
+ valid global directory, GT.M reports errors in the same way it does for
+ any invalid global directory.
+
+ It is possible to write this routine in M (as a call-in), however,
+ global variables in such a routine would change the naked indicator,
+ which environment references normally do not. Depending on the
+ conventions of the application, there might be difficult name-space
+ management issues such as protecting the local variables used by the M
+ routine.
+
+ While it is possible for this routine to take any form that the
+ application designer finds appropriate within the given interface
+ definition, the following paragraphs make some recommendations based on
+ the expectation that a routine invoked for any more than a handful of
+ global references should be efficient.
+
+ It is expected that the routine loads one or more tables, either at
+ compilation or the first time it is invoked. The logic of the routine
+ performs a look up on the entry in the set of tables. The lookup might
+ be based on the length of the strings and some unique set of characters
+ in the names, or a hash, with collision provisions as appropriate.
+
+ The routine may have to deal with a case where one or both of the
+ inputs have zero length. A subset of these cases may have the first
+ string holding a comma limited string that needs to be re-interpreted
+ as being equivalent to two input strings (note that the input strings
+ must never be modified). The routine may also have to handle cases
+ where a value (most likely the first) is accidentally or intentionally,
+ already a global directory specification.
+
+ Example:
+
+
+> type gtm_env_translate.c
+ #include <stdio.h>
+
+ #include <string.h>
+
+ #include "gtmxc_types.h"
+
+
+ static int init = 0;
+
+ typedef struct
+
+ {
+
+ xc_string_t field1, field2, ret;
+
+ } line_entry ;
+
+
+ static line_entry table[5], *line, linetmp;
+
+ /* Since these errors may occur before setup is complete, they are
+ statics */
+ static char *errorstring1 = "Error in function initialization,
+ environment variable GTM_CALLIN_START not defined. Environment
+ translation failed.";
+ static char *errorstring2 = "Error in function initialization, function
+ pointers could not be determined. Envrironment translation failed.";
+ void copy_string(char **loc1, char *loc2, int length)
+
+ {
+
+ char *ptr;
+
+ ptr = (char *) gtm_malloc(length);
+
+ strncpy( ptr, loc2, length);
+
+ *loc1 = ptr;
+
+ }
+
+
+ int init_table(xc_string_t *ptr)
+
+ {
+
+ int i = 0;
+
+ char buf[100];
+
+ char *buf1, *buf2;
+
+ FILE *tablefile;
+
+ char *space = " ";
+
+ char *errorstr1 = "Error opening table file table.dat";
+
+ char *errorstr2 = "UNDETERMINED ERROR FROM GTM_ENV_XLATE";
+
+
+ if ((tablefile = fopen("table.dat","r")) == (FILE *)NULL)
+
+ {
+
+ ptr->length = strlen(errorstr1);
+
+ copy_string(&(ptr->address), errorstr1, strlen(errorstr1));
+
+ return 1;
+
+ }
+
+ while (fgets(buf, (int)SIZEOF(buf), tablefile) != (char *)NULL)
+
+ {
+
+ line= &table[i++];
+
+ buf1 = buf;
+
+ buf2 =strstr(buf1, space);
+
+ line->field1.length = buf2 - buf1;
+
+ copy_string( &(line->field1.address), buf1, line->field1.length);
+
+ buf1 = buf2+1;
+
+ buf2 = strstr(buf1, space);
+
+ line->field2.length = buf2-buf1;
+
+ copy_string( &(line->field2.address), buf1, line->field2.length);
+
+ buf1 = buf2+1;
+
+ line->ret.length = strlen(buf1) - 1;
+
+ copy_string( &(line->ret.address), buf1, line->ret.length);
+
+ }
+
+ fclose(tablefile);
+
+ /* In this example, the last entry in the table is the error string
+ */
+ line = &table[4];
+
+ copy_string( &(line->ret.address), errorstr2, strlen(errorstr2));
+
+ line->ret.length = strlen(errorstr2);
+
+ return 0;
+
+ }
+
+
+ int cmp_string(xc_string_t str1, xc_string_t str2)
+
+ {
+
+ if (str1.length == str2.length)
+
+ return strncmp(str1.address, str2.address, (int) str1.length);
+
+ else
+
+ return str1.length - str2.length;
+
+ }
+
+
+ int cmp_line(line_entry *line1, line_entry *line2)
+
+ {
+
+ return (((cmp_string(line1->field1,
+ line2->field1))||(cmp_string(line1->field2, line2->field2))));
+ }
+
+
+ int look_up_table(line_entry *aline, xc_string_t *ret_ptr)
+
+ {
+
+ int i;
+
+ int ret_v;
+
+
+ for(i=0;i<4;i++)
+
+ {
+
+ line = &table[i];
+
+ ret_v = cmp_line( aline, line);
+
+ if (!ret_v)
+
+ {
+
+ ret_ptr->length = line->ret.length;
+
+ ret_ptr->address = line->ret.address;
+
+ return 0;
+
+ }
+
+ }
+
+ /*ERROR OUT*/
+ line = &table[4];
+
+ ret_ptr->length= line->ret.length;
+
+ ret_ptr->address = line->ret.address;
+
+ return 1;
+
+
+ }
+
+
+ int gtm_env_xlate(xc_string_t *ptr1, xc_string_t *ptr2, xc_string_t
+ *ptr_zdir, xc_string_t *ret_ptr)
+ {
+
+
+ int return_val, return_val_init;
+
+ if (!init)
+
+ {
+
+ return_val_init = init_functable(ret_ptr);
+
+ if (return_val_init) return return_val_init;
+
+ return_val_init = init_table(ret_ptr);
+
+ if (return_val_init) return return_val_init;
+
+ init = 1;
+
+ }
+
+ linetmp.field1.length= ptr1->length;
+
+ linetmp.field1.address= ptr1->address;
+
+ linetmp.field2.length= ptr2->length;
+
+ linetmp.field2.address= ptr2->address;
+
+
+ return_val = look_up_table(&linetmp, ret_ptr);
+
+ return return_val;
+
+ }
+
+
+> type table.dat
+ day1 week1 mumps
+
+ day2 week1 a
+
+ day3 week2 b
+
+ day4 week2 c.gld
+
+ This example demonstrates the mechanism. A table is set up the first
+ time for proper memory management, and for each reference, a table
+ lookup is performed. Note that for the purpose of simplicity, no error
+ checking is done, so table.dat is assumed to be in the correct format,
+ and have exactly four entries.
+
+2 Literals
+ Literals
+
+ M has both string and numeric literals.
+
+3 String_Literals
+ String Literals
+
+ String literals (strlit) are enclosed in quotation marks (" ") and must
+ only contain graphic characters. In other words, control characters
+ (ASCII 0-31 and 127) cannot appear in a strlit. M attempts to use
+ character text that appears outside of quotation mark delimiters
+ according to context, which generally means as a local variable name.
+
+ To include a quotation mark (") within a strlit, use a set of two
+ quotation marks ("" "").
+
+ Example:
+
+
+ GTM>WRITE """"
+
+ "
+
+ GTM>
+
+ The WRITE displays a single quotation mark because the first quotation
+ mark delimits the beginning of the string literal, the next two
+ quotation marks denote a single quote within the string, and the last
+ quotation mark delimits the end of the string literal.
+
+ Use the $CHAR function and the concatenation operator to include
+ control characters within a string.
+
+ Example:
+
+
+ GTM>WRITE "A"_$CHAR(9)_"B"
+
+ A B
+
+ GTM>
+
+ The WRITE displays an "A," followed by a tab (<HT>), followed by a "B"
+ using $CHAR(), to introduce the non-graphic character.
+
+3 Numeric_Literals
+ Numeric Literals
+
+ In M, numeric literals (numlit) are entered without surrounding
+ delimiters.
+
+ Example:
+
+
+ GTM>WRITE 1
+
+ 1
+ GTM> WRITE 1.1
+
+ 1.1
+ These display numeric literals that are integer and decimal.
+
+ M also accepts numeric literals in the form of a mantissa and an
+ exponent, separated by a delimiter of "E" in uppercase. The mantissa
+ may be an integer or a decimal fraction. The integer exponent may have
+ an optional leading minus sign (-).
+
+ Example:
+
+
+ GTM>WRITE 8E6
+
+ 8000000
+ GTM> WRITE 8E-6
+
+ .000008
+ GTM>
+
+2 Expressions
+ Expressions
+
+ The following items are legal M expression atoms (expratom). An
+ expression atom is a component of an M expression.
+
+ o Local variables
+
+ o Global variables
+
+ o Intrinsic special variables
+
+ o Intrinsic functions
+
+ o Extrinsic functions
+
+ o Extrinsic special variables
+
+ o Numeric literals
+
+ o String literals
+
+ o An expression enclosed in parentheses
+
+ o Any of the above preceded by a unary operator
+
+ In addition, any of these items may be combined with a binary operator
+ and another expression atom.
+
+2 Operators
+ Operators
+
+ M has both unary and binary operators.
+
+3 Precedence
+ Precedence
+
+ All unary operations have right to left precedence.
+
+ All M binary operations have strict left to right precedence. This
+ includes all arithmetic, string, and logical operations. Hierarchies of
+ operations require explicit establishment of precedence using
+ parentheses (). Although this rule is counterintuitive, it is easy to
+ remember and has no exceptions.
+
+3 Arithmetic_Operators
+ Arithmetic Operators
+
+ All arithmetic operators force M to evaluate the expressions to which
+ they apply as numeric. The arithmetic operators are:
+
+ + as a unary operator simply forces M to evaluate the expression
+ following as numeric; as a binary operator it causes M to perform
+ addition.
+ - as a unary operator causes M to negate the expression following;
+ as a binary operator it causes M to perform subtraction.
+ * binary operator for multiplication.
+ ** binary operator for exponentiation.
+ / binary operator for fractional division.
+ \ binary operator for integer division.
+ # binary operator for modulo, that is, causes M to produce the
+ remainder from integer division of the first argument by the
+ second.
+ Remember that precedence is left to right for all arithmetic operators.
+
+ Example:
+
+
+ GTM>WRITE 1+1
+
+ 2
+ GTM>WRITE 2-1
+
+ 1
+ GTM>WRITE 2*2
+
+ 4
+ GTM>WRITE 3**2
+
+ 9
+ GTM>WRITE 4/2
+
+ 2
+ GTM>WRITE 7
+
+ 2
+ GTM>WRITE 7#3
+
+ 1
+ GTM>
+
+ This simple example demonstrates how each arithmetic binary operation
+ uses numeric literals.
+
+ Example:
+
+
+ GTM>WRITE +"12ABC"
+
+ 12
+ GTM>WRITE --"-3-4"
+
+ -3
+
+ GTM>
+
+ The first WRITE shows the unary plus sign (+) operation forcing the
+ numeric evaluation of a string literal. The second WRITE demonstrates
+ the unary minus sign (-). Note the second minus sign within the string
+ literal does not cause subtraction, but rather, terminates the numeric
+ evaluation with the result of negative three (-3). Each of the leading
+ minus signs causes one negation and therefore, the result is negative
+ three (-3).
+
+3 Logical_Operators
+ Logical Operators
+
+ M logical operators always produce a result that is TRUE (1) or FALSE
+ (0). All logical operators force M to evaluate the expressions to which
+ they apply as truth-valued. The logical operators are:
+
+ ' unary NOT operator negates current truth-value; M accepts
+ placement of the NOT operator next to a relational operator, for
+ example, A'=B as meaning '(A=B).
+ & binary AND operator produces a true result only if both of the
+ expressions are true.
+ ! binary OR operator produces a true result if either of the
+ expressions is true.
+ Remember that precedence is always left to right, and that logical
+ operators have the same precedence as all other operators.
+
+ Example:
+
+
+ GTM>WRITE '0
+
+ 1
+ GTM>WRITE '1
+
+ 0
+ GTM>WRITE '5689
+
+ 0
+ GTM>WRITE '-1
+
+ 0
+ GTM>WRITE '"ABC"
+
+ 1
+ GTM>
+
+ The above example demonstrates the unary NOT operation. Note that any
+ non-zero numeric value is true and has a false negation.
+
+ Example:
+
+
+ GTM>WRITE 0&0
+
+ 0
+ GTM>WRITE 1&0
+
+ 0
+ GTM>WRITE 0&1
+
+ 0
+ GTM>WRITE 1&1
+
+ 1
+ GTM>WRITE 2&1
+
+ 1
+ GTM>WRITE 0!0
+
+ 0
+ GTM>WRITE 1!0
+
+ 1
+ GTM>WRITE 0!1
+
+ 1
+ GTM>WRITE 1!1
+
+ 1
+ GTM>WRITE 2!1
+
+ 1
+ GTM>
+
+ The above example demonstrates all cases covered by the binary logical
+ operators.
+
+3 String_Operators
+ String Operators
+
+ All string operators force M to evaluate the expressions to which they
+ apply as strings. The string operator is:
+
+ _ binary operator causes M to concatenate the second expression
+ with the first expresion
+ Example:
+
+
+ GTM>WRITE "B"_"A"
+
+ BA
+
+ GTM>WRITE "A"_1
+
+ A1
+
+ GTM>
+
+ The above example demonstrates M concatenation.
+
+3 Num_Relational_Operators
+ Numeric Relational Operators
+
+ M relational operators always generate a result of TRUE (1) or FALSE
+ (0). All numeric relational operators force M to evaluate the
+ expressions to which they apply as numeric. The numeric relational
+ operators are:
+
+ > binary arithmetic greater than
+ < binary arithmetic less than
+ The equal sign (=) does not force numeric evaluation, and should be
+ viewed as a string operator. However, the equal sign between two
+ numeric values tests for numeric equality.
+
+ Other numeric relations are formed using the logical NOT operator
+ apostrophe (') as follows:
+
+ '> not greater than, that is, less than or equal to
+ '< not less than, that is, greater than or equal to
+ '= not equal, numeric or string operation
+ Example:
+
+
+ GTM>WRITE 1>2
+
+ 0
+ GTM>WRITE 1<2
+
+ 1
+ GTM>
+
+ The above example demonstrates the basic arithmetic relational
+ operations.
+
+ Example:
+
+
+ GTM>WRITE 1'<2
+
+ 0
+ GTM>WRITE 2'<1
+
+ 1
+ GTM>
+
+ The above example demonstrates combinations of arithmetic, relational
+ operators with the logical NOT operator.
+
+3 Str_Relational_Operators
+ String Relational Operators
+
+ M relational operators always generate a result of TRUE (1) or FALSE
+ (0). All string relational operators force M to evaluate the
+ expressions to which they apply as strings. The string relational
+ operators are:
+
+ = binary operator causes M to produce a TRUE if the expressions are
+ equal.
+ [ binary operator causes M to produce a TRUE if the first
+ expression contains the ordered sequence of characters in the
+ second expression.
+ ] binary operator causes M to produce a TRUE if the first
+ expression lexically follows the second expression in the character
+ encoding sequence, which by default is ASCII.
+ ]] binary operator causes M to produce a TRUE if the first
+ expression lexically sorts after the second expression in the
+ subscript collation sequence.
+ Note that all non-empty strings lexically follow the empty string, and
+ every string contains the empty string.
+
+ Other string relations are formed using the logical NOT operator
+ apostrophe (') as follows:
+
+ '[ does not contain.
+ '] does not follow, that is, lexically less than or equal to.
+ ']] does not sort after, that is, lexically less than or equal to
+ in the subscript collation sequence.
+ '= not equal, numeric or string operation.
+ Example:
+
+
+ GTM>WRITE "A"="B"
+
+ 0
+ GTM>WRITE "C"="C"
+
+ 1
+ GTM>WRITE "A"["B"
+
+ 0
+ GTM>WRITE "ABC"["C"
+
+ 1
+ GTM>WRITE "A"]"B"
+
+ 0
+ GTM>WRITE "B"]"A"
+
+ 1
+ GTM>WRITE "A"]]"B"
+
+ 0
+ GTM>WRITE "B"]]"A"
+
+ 1
+ These examples demonstrate the string relational operators using string
+ literals.
+
+ Example:
+
+
+ GTM>WRITE 2]10
+
+ 1
+ GTM>WRITE 2]]10
+
+ 0
+ GTM>WRITE 0]"$"
+
+ 1
+ GTM>WRITE 0]]"$"
+
+ 0
+ These examples illustrate that when using the primary ASCII character
+ set, the main difference in the "follows" (]) operator and the
+ "sorts-after" (]]) operator is the way they treat numbers.
+
+ Example:
+
+
+ GTM>WRITE 1=1
+
+ 1
+ GTM>WRITE 1=2
+
+ 0
+ GTM>WRITE 1="1"
+
+ 1
+ GTM>WRITE 1=01
+
+ 1
+ GTM>WRITE 1="01"
+
+ 0
+ GTM>WRITE 1=+"01"
+
+ 1
+ GTM>
+
+ These examples illustrate the dual nature of the equal sign operator.
+ If both expressions are string or numeric, the results are straight
+ forward. However, when the expressions are mixed, the native string
+ data type prevails.
+
+ Example:
+
+
+ GTM>WRITE "a"'="A"
+
+ 1
+ GTM>WRITE "FRED"'["RED"
+
+ 0
+ GTM>WRITE "ABC"']""
+
+ 0
+ These examples demonstrate combinations of the string relational
+ operators with the NOT operator.
+
+3 Pat_Match_Operator
+ Pattern Match Operator
+
+ The pattern match operator (?) causes M to return a TRUE if the
+ expression ahead of the operator matches the characteristics described
+ by the pattern following the operator. The pattern is not an
+ expression.
+
+ Patterns are made up of two elements:
+
+ o A repetition count
+
+ o A pattern code, a string literal or an alternation list
+
+ The element following the pattern match operator may consist of an
+ indirection operator, followed by an element that evaluates to a
+ legitimate pattern.
+
+ The repetition count consists of either a single integer literal or a
+ period (.) delimiter with optional leading and trailing integer
+ literals. A single integer literal specifies an exact repetition count.
+ The period syntax specifies a range of repetitions where the leading
+ number is a minimum and the trailing number is a maximum. When the
+ repetition count is missing the leading number, M assumes there is no
+ minimum, (i.e., a minimum of zero). When the repetition count is
+ missing the trailing number, M does not place a maximum on the number
+ of repetitions.
+
+ The pattern codes are:
+
+ A alphabetic characters upper or lower case
+ C control characters ASCII 0-31 and 127
+ E any character; used to pass all characters in portions of the
+ string where the pattern is not restricted
+ L lower-case alphabetic characters, ASCII 97-122
+ N digits 0-9, ASCII 48-57
+ P punctuation, ASCII 32-47, 58-64, 91-96, 123-126
+ U upper-case alphabetic characters, ASCII 65-90
+ Pattern codes may be upper or lower case and may be replaced with a
+ string literal. GT.M allows the M pattern match definition of patcodes
+ A, C, N, U, L, and P to be extended or changed, (A can only be modified
+ implicitly by modifying L or U) and new patcodes added. For detailed
+ information on enabling this functionality, refer to the
+ "Internationalization" chapter in GT.M Programmer's Guide.
+
+ The GT.M compiler accepts pattern codes other than those explicitly
+ defined above. If, at run-time, the pattern codes come into use and
+ no pattern definitions are available, GT.M issues a run-time error
+ (PATNOTFOUND). GT.M does not currently implement a mechanism for Y
+ and Z patterns and continues to treat those as compile-time syntax
+ errors.
+
+ Example:
+
+
+ GTM>WRITE "ABC"?3U
+
+ 1
+ GTM>WRITE "123-45-6789"?3N1"-"2N1"-"4N
+
+ 1
+ The first WRITE has a simple one-element pattern while the second has
+ multiple elements including both codes and string literals. All the
+ repetition counts are fixed.
+
+ Example:
+
+
+ I x?.E1C.E W !,"Must not contain a control character" Q
+
+ This example uses a pattern match to test for control characters.
+
+ Example:
+
+
+ I acn?1U.20A1","1U.10A D
+
+ .S acn=$G((^ACX($P(acn,","),$P(acn,",",2)))
+
+ This example uses a pattern match with implicit minimums to determine
+ that an "account number" is actually a name, and to trigger a look-up
+ of the corresponding account number in the ^ACX cross index.
+
+ The pattern match operator accepts the alteration syntax. Alteration
+ consists of a repeat count followed by a comma-delimited list of
+ patatoms enclosed in parentheses "()". The semantic is that the pattern
+ matches if any of the listed patterns matches the operand string. For
+ example, ?1(2N1"-"7N,3N1"-"2N1"-"4N).1U might be a way to match either
+ a social security number or a taxpayer ID. Since alternation is defined
+ as one of the ways of constructing a patatom, alternation can nest (be
+ used recursively).
+
+ Complex pattern matches may not be efficient to evaluate, so every
+ effort should be made to simplify any commonly used pattern and to
+ determine if more efficient alternative logic would be more
+ appropriate.
+
+2 Gen_M_Comm
+ General M Commands
+
+ M commands may be abbreviated to a defined prefix. Most commands have
+ arguments. However, some commands have either optional arguments or no
+ arguments. When a command has no argument and is followed by more
+ commands on the same line, at least two spaces (<SP>) must follow the
+ command without arguments. Commands that accept arguments generally
+ accept multiple arguments on the same command. M treats multiple
+ arguments the same as multiple occurrences of the same command, each
+ with its own argument.
+
+3 Postconditionals
+ Postconditionals
+
+ M provides postconditionals as a tool for placing a condition on the
+ execution of a single command and, in some cases, a single command
+ argument. A postconditional consists of a colon (:) delimiter followed
+ by a truth-valued expression. When the expression evaluates to true, M
+ executes the command occurrence. When the expression evaluates to
+ false, M does not execute the command occurrence.
+
+4 Comm_Postconditionals
+ Command Postconditionals
+
+ Command postconditionals appear immediately following a command and
+ apply to all arguments for the command when it has multiple arguments.
+ All commands except commands that themselves have a conditional aspect
+ accept a command postconditional. Among the M standard commands, ELSE,
+ FOR, and IF do not accept command postconditionals. All the GT.M
+ command extensions accept command postconditionals.
+
+4 Arg_Postconditionals
+ Argument Postconditionals
+
+ Commands that affect the flow of control may accept postconditionals on
+ individual command arguments. Because multiple arguments act as
+ multiple commands, this is a straight-forward application of the same
+ principal as command postconditional. The only M standard commands that
+ accept argument postconditionals are DO, GOTO, and XECUTE. The GT.M
+ command extensions that accept argument postconditionals are BREAK,
+ ZGOTO, and ZSYSTEM.
+
+3 Timeouts
+ Timeouts
+
+ M provides timeouts as a tool to retain program control over commands
+ of indefinite duration. A timeout consists of a colon (:) delimiter on
+ an argument, followed by a numeric expression specifying the number of
+ seconds for M to attempt to execute the command. When the timeout is
+ zero (0), M makes a single attempt to complete the command.
+
+ When a command has a timeout, M maintains the $TEST intrinsic special
+ variable as the command completes. If the command completes
+ successfully, M sets $TEST to TRUE (1). If the command times out before
+ successful completion, M sets $TEST to FALSE (0). When a command
+ argument does not specify a timeout, M does not maintain $TEST.
+
+ The following commands accept timeouts:
+
+ o LOCK
+
+ o JOB
+
+ o OPEN
+
+ o READ
+
+ o ZALLOCATE
+
+ When a READ times out, M returns any characters that have arrived
+ between the start of the command and the timeout. M does not produce
+ any partial results for any of the other timed commands.
+
+2 Gen_M_Intrin_Func
+ General M Intrinsic Functions
+
+ M Intrinsic Functions start with a single dollar sign ($) and have one
+ or more arguments enclosed in parentheses () and separated by commas
+ (,). These functions provide an expression result by performing actions
+ that would be impossible or difficult to perform using M commands. It
+ is now possible to invoke a C function in a package via the external
+ call mechanism.
+
+2 Gen_M_Intr_Spec_Var
+ General M Intrinsic Special Variables
+
+ M Intrinsic Special Variables start with a single dollar sign ($). GT.M
+ provides such variables for program examination. In some cases, the
+ Intrinsic Special Variables may be SET to modify the corresponding part
+ of the environment.
+
+2 Routines
+ Routines
+
+ M routines have a name and consist of lines of code followed by an
+ end-of-record which is a carriage return, formfeed (<CR><FF>) sequence.
+ M separates the name of a routine from the body of the routine with an
+ end-of-line which is a carriage-return, line-feed (<CR><LF>) sequence.
+
+ GT.M stores routine sources in RMS files and implicitly supplies the
+ end-of-record and end-of-line character sequences.
+
+ In M, a routine has no particular impact on variable management and may
+ include code that is invoked at different times and has no logical
+ intersection.
+
+3 Lines
+ Lines
+
+ A line of M code consists of the following elements in the following
+ order:
+
+ o An optional label.
+
+ o A line-start delimiter. The standard defines the line-start
+ delimiter as a space (<SP>) character. In order to enhance routine
+ readability, GT.M extends M by accepting one or more tab (<HT>)
+ characters as line-start delimiters.
+
+ o Zero or more level indicators, which are periods (.). The level
+ indicators show the level of nesting for argumentless DO commands:
+ the more periods, the deeper the nesting. M ignores lines that
+ contain level indicators unless they directly follow an
+ argumentless DO command with a matching level of nesting.
+
+ o Zero or more commands and their arguments. M accepts multiple
+ commands on a line. The argument(s) of one command are separated
+ from the next command by a command-start delimiter, consisting of
+ one or more spaces (<SP>).
+
+ o A terminating end-of-line, which is a carriage return, line feed
+ (<CR><LF>) sequence.
+
+4 Labels
+ Labels
+
+ In addition to labels that follow the rules for M names, M accepts
+ labels consisting only of digits. In a label consisting only of digits,
+ leading zeros are considered significant. For example, labels 1 and 01
+ are different. Formalists may immediately follow a label. A Formalists
+ consists of one or more names enclosed in parentheses (). Formalists
+ identify local variables that "receive" passed values in M parameter
+ passing.
+
+ In GT.M, a colon (:) delimiter may be appended to the label, which
+ causes the label to be treated as "local." Within the routine in which
+ they appear, they perform exactly as they would without the trailing
+ colon but they are inaccessible to other routines. Using local labels
+ reduces object size and linking overhead, for both ZLINK and host
+ linking.
+
+4 Comments
+ Comments
+
+ In addition to commands, a line may also contain a comment that starts
+ with a leading semi-colon (;) delimiter. The scope of a comment is the
+ remainder of the line. In other words, M ignores anything to the right
+ of the comment delimiter. The standard defines the comment delimiter
+ (;) as it would a command, and therefore requires that it always appear
+ after a linestart. GT.M extends the standard to permit comments to
+ start at the first character of a line or in an argument position.
+
+3 Entry_Ref
+ Entry References
+
+ M entryrefs provide a generalized target for referring to a line within
+ a routine. An entryref may contain some combination of a label, an
+ offset, and a routine name (in that order). The offset is delimited by
+ a plus sign (+) and the routinename is delimited by a caret symbol(^).
+ When an entryref does not contain a label, M assumes the offset is from
+ the beginning of the routine. When an entryref does not contain an
+ offset, M uses an offset of zero (0). When an entryref does not contain
+ a routine name, M assumes the routine that is currently executing.
+
+ M permits every element in an entryref to have the form of an
+ indirection operator, followed by an element that evaluates to a
+ legitimate occurrence of that portion of the entryref.
+
+ While most commands and functions that use entryrefs permit
+ argument indirection, M does not accept indirection that resolves
+ to a combination of label and offset or offset and routine name.
+
+ Offsets provide an extremely useful tool for debugging. However, avoid
+ their use in production code because they generally produce maintenance
+ problems.
+
+3 Label_Ref
+ Label References
+
+ M labelrefs are a subset of entryrefs that exclude offsets and separate
+ indirection. Labelrefs are used with parameter passing.
+
+2 Indirection
+ Indirection
+
+ M provides indirection as a means to defer definition of elements of
+ the code until run-time. Indirection names a variable that holds or
+ "points" to the element. The indirection operator is the "at" symbol
+ (@).
+
+3 Arg_Indirection
+ Argument Indirection
+
+ Most commands accept indirection of their entire argument.
+
+ Example:
+
+
+ GTM>SET x="^INDER"
+
+ GTM>DO @x
+
+ This example is equivalent to DO ^INDER.
+
+3 Atomic_Indirection
+ Atomic Indirection
+
+ Any expratom or any local or global variable name may be replaced by
+ indirection.
+
+ Example:
+
+
+ GTM>SET x="HOOP",b="x"
+
+ GTM>WRITE a="HULA "__ at b
+
+ HULA HOOP
+
+ GTM>
+
+ This example uses indirection within a concatenation operation.
+
+3 Entryref_Indirection
+ Entryref Indirection
+
+ Any element of an entryref may be replaced by indirection.
+
+ Example:
+
+
+ GTM>SET lab="START",routine="PROG"
+
+ GTM>DO @lab^@routine
+
+ This example is equivalent to DO START^PROG.
+
+3 Patt_Code_Indirection
+ Pattern Code Indirection
+
+ A pattern code may be replaced by indirection.
+
+ Example:
+
+
+ GTM>FOR p="1U.20A1"",""1U.20A",5N IF x?@p QUIT
+
+ GTM>ELSE WRITE !,"Incorrect format" QUIT
+
+ This example uses pattern code indirection to test x for either a name
+ or a number.
+
+3 Name_Indirection
+ Name Indirection
+
+ Indirection may replace the prefix of a subscripted global or local
+ variable name. This "name" indirection requires two indirection
+ operators, a leading operator similar to the other forms of
+ indirection, and a trailing operator marking the transition to those
+ subscripts that are not specified by indirection.
+
+ Example:
+
+
+ GTM>SET from="B",to="^A(15),x=""
+
+ GTM>FOR SET x=$O(@from@(x)) Q:x="" S @to@(x)=@from@(x)
+
+ This example uses name indirection to copy the level contents of a
+ local array to a part of a global array. The example assumes that all
+ existing first level nodes of variable B have data.
+
+3 Indirection_Concerns
+ Indirection Concerns
+
+ M indirection provides a very powerful tool for allowing program
+ abstraction. However, because indirection is frequently unnecessary and
+ has some disadvantages, use it carefully.
+
+ Because routines that use indirection in some ways do not contain
+ adequate information for easy reading, such routines tend to be more
+ difficult to debug and maintain.
+
+ To improve run-time performance, GT.M tends to move work from run-time
+ to compile-time. Indirection forces compiler actions to occur at
+ run-time, which minimizes the benefits of compilation.
+
+ M allows most forms of indirection to be recursive. However, in real
+ applications, recursive indirection typically makes the code obscure
+ and slow.
+
+ There are circumstances where indirection serves a worthwhile purpose.
+ For instance, certain utility functions with a general nature may be
+ clearly abstracted and coded using indirection. Because M has no "CASE"
+ command, DO (or GOTO) with argument indirection provides a clear
+ solution to the problem of providing complex branching.
+
+ Some M users prototype with indirection and then replace indirection
+ with generated code that reduces run-time overhead. In any case, always
+ consider whether indirection can be replaced with a clearer or more
+ efficient approach.
+
+2 Param_Passing
+ Parameter Passing
+
+ Parameter passing provides a way of explicitly controlling some or all
+ of the variable context transferred between M routines.
+
+ M uses parameter passing for:
+
+ o A DO command with parameters
+
+ o Extrinsic functions and special variables
+
+ Parameter passing is optional on DO commands.
+
+ Parameter passing uses two argument lists: the actuallist that
+ specifies the parameters that M passes to an invoked routine, and the
+ formalist that specifies the local variables to receive or associate
+ with the parameters.
+
+3 Actuallists
+ Actuallists
+
+ An actuallist specifies the parameters M passes to the invoked routine.
+ The actuallist contains a list of zero or more parameters enclosed in
+ parentheses, immediately following a DO or extrinsic function.
+
+ An actuallist:
+
+ o Is made up of items separated by commas
+
+ o Contains expressions and/or actualnames. Items may be missing, that
+ is, two commas may appear next to each other, with nothing between
+ them.
+
+ o Must be used in an invocation of a label with a formallist, except
+ in the case of extrinsic special variables.
+
+ o Must not contain undefined variables.
+
+ o Must not have more items than a formallist with which it is used.
+
+ o May contain the same item in more than one position.
+
+ Example:
+
+
+ GTM>DO MULT(3,X,.RESULT)
+
+ This example illustrates a DO with parameters. The actuallist contains:
+
+ o 3 - a numeric literal
+
+ o X - a local variable
+
+ o .RESULT - an actualname
+
+3 Actualnames
+ Actualnames
+
+ An actualname starts with a leading period (.) delimiter, followed by
+ an unsubscripted local variable name. Actualnames identify variables
+ that are passed by reference, as described in a subsequent section.
+ While expressions in an actualname are evaluated when control is
+ transferred to a formallabel, the variables identified by actualnames
+ are not; therefore, they do not need to be defined at the time control
+ is transferred.
+
+3 Formallists
+ Formallists
+
+ A formallist specifies the variables M uses to hold passed values. A
+ formallist contains a list of zero or more parameters enclosed in
+ parentheses, immediately following a label.
+
+ A formallist:
+
+ o Is made up of items separated by commas.
+
+ o Contains unsubscripted local variable names.
+
+ o Must be used and only used with a label invoked with an actuallist
+ or an extrinsic.
+
+ o May contain undefined variables.
+
+ o May have more items than an actuallist with which it is used.
+
+ o Must not contain the same item in more than one position.
+
+ o Must contain at least as many items as the actuallist with which it
+ is used.
+
+ Example:
+
+
+ MULT(MP,MC,RES)
+
+ SET RES=MP*MC
+
+ QUIT RES
+
+ In this example, illustrating a simple parameterized routine, the
+ formallist contains the following items:
+
+ o MP
+
+ o MC
+
+ o RES
+
+ An example in the section describing "Actuallists" shows an invocation
+ that matches this routine.
+
+3 Formallabel
+ Formallabel
+
+ A label followed by a formallist is called a formallabel.
+
+3 Param_Pass_Operation
+ Parameter Passing Operation
+
+ M performs an implicit NEW on the formallist names and replaces the
+ formallist items with the actuallist items.
+
+ M provides the actuallist values to the invoked procedure by giving
+ each element in the formallist the value or reference provided by the
+ corresponding element in the actuallist. M associates the first name in
+ the formallist with the first item in the actuallist, the second name
+ in the formallist with the second item in the actuallist and so on. If
+ the actuallist is shorter than the formallist, M ensures that the
+ formallist items with no corresponding value are in effect NEWed. If
+ the formallist item has no corresponding item in the actuallist
+ (indicated by two adjacent commas in the actuallist), that item in the
+ formallist becomes undefined.
+
+ If the actuallist item is an expression and the corresponding
+ formallist variable is an array, parameter passing does not affect the
+ subscripted elements of the array. If an actualname corresponds to a
+ formallist variable, M reflects array operations on the formallist
+ variable, by reference, in the variable specified by the actualname.
+
+ M treats variables that are not part of the formallist as if parameter
+ passing did not exist (i.e., M makes them available to the invoked
+ routine).
+
+ M initiates execution at the first command following the formallabel.
+
+ A QUIT command terminates execution of the invoked routine. At the time
+ of the QUIT, M restores the formallist items to the values they had at
+ the invocation of the routine.
+
+ In the case where a variable name appears as an actualname in the
+ actuallist, and also as a variable in the formallist, the restored
+ value reflects any change made by reference.
+
+ A QUIT from a DO does not take an argument, while a QUIT from an
+ extrinsic must have an argument. This represents one of the two major
+ differences between the DO command with parameters and the extrinsics.
+ M returns the value of the QUIT command argument as the value of the
+ extrinsic function or special variable. The other difference is that M
+ stacks $TEST for extrinsics.
+
+ Example:
+
+ SET X=30,Z="Hello"
+
+ DO WRTSQR(X)
+
+ ZWRITE
+
+ QUIT
+
+ WRTSQR(Z)
+
+ SET Z=Z*Z
+
+ WRITE Z,!
+
+ QUIT
+
+ Produces:
+
+
+ 900
+ X=30
+
+ Z="Hello"
+
+3 Param_Pass_Mechanism
+ Parameter Passing Mechanisms
+
+ M passes the actuallist values to the invoked routine using two
+ parameter-passing mechanisms:
+
+ o Call-by-Value - where expressions appear
+
+ o Call-by-Reference - where actualnames appear
+
+ A call-by-value passes a copy of the value of the actuallist expression
+ to the invoked routine by assigning the copy to a formallist variable.
+ If the parameter is a variable, the invoked routine may change that
+ variable. However, because M constructs that variable to hold the copy,
+ it deletes the variable holding the copy when the QUIT restores the
+ prior formallist values. This also means that changes to the variable
+ by the invoked routine do not affect the value of the variable in the
+ invoking routine.
+
+ Example:
+
+
+ SET X=30
+
+ DO SQR(X)
+
+ ZWRITE
+
+ QUIT
+
+ SQR(Z) SET Z=Z*Z
+
+ QUIT
+
+ Produces:
+
+
+ X=30
+
+ A period followed by a name identifies an actualname and causes a
+ call-by-reference.
+
+ A call-by-reference passes a pointer to the variable of the invoked
+ routine so operations on the assigned formallist variable also act on
+ the actualname variable. Changes, including KILLs to the formallist
+ variable, immediately have the same affect on the corresponding
+ actualname variable. This means that M passes changes to formallist
+ variables in the invoked routine back to the invoking routine as
+ changes in actualname variables.
+
+ Example:
+
+
+ SET X=30
+
+ DO SQR(.X)
+
+ ZWRITE
+
+ QUIT
+
+ SQR(Z) SET Z=Z*Z
+
+ QUIT
+
+ Produces:
+
+
+ X=900
+
+3 GTM_Param_Pass_Extn
+ GT.M Parameter Passing Extensions
+
+ The standard does not provide for indirection of a labelref because the
+ syntax has an ambiguity.
+
+ Example:
+
+
+ DO @X(1)
+
+ This example could be:
+
+ o An invocation of the label specified by X with a parameter of 1.
+
+ o An invocation of the label specified by X(1) with no parameter
+ list.
+
+ GT.M processes the latter interpretation as illustrated in the
+ following example.
+
+ Example:
+
+ The syntax:
+
+
+ SET A(1)="CUBE",X=5
+
+ DO @A(1)(.X)
+
+ WRITE X,!
+
+ QUIT
+
+ CUBE(C) ;cube a variable
+
+ SET C=C*C*C
+
+ QUIT
+
+ Produces the result:
+
+ 125
+ GT.M follows analogous syntax for routine indirection:
+
+ DO ^@X(A) invokes the routine specified by X(A).
+
+ DO ^@(X)(A) invokes the routine specified by X and passes the parameter
+ A.
+
+ DO ^@X(A)(A) invokes the routine specified by X(A) and passes the
+ parameter A.
+
+2 Ext_Calls
+ External Calls
+
+ GT.M supports the MDC Type A external call syntax. The external call
+ syntax provides an externref that specifies a destination for
+ subroutine invocation. The format for an externref is:
+
+&[packagename.]name[^name]
+ The externref is a two-part identification of a program entry point.
+ The entry point can be in any language, including M. The packagename is
+ a name following M rules that identifies a name-space within which the
+ remainder of the externref, after the delimiting period (.), is unique.
+ The portion of the externref after the delimiting period may be a
+ single M name or two M names separated by a caret (^).
+
+ Example:
+
+
+ SET X=$&MATH.NATRLOG(.Y)
+
+ This invokes the NATRLOG function in the MATH package and passes the
+ value of Y by reference.
+
+ GT.M supports external calls to any language that supports the VAX
+ calling standard. GT.M provides external call (ZCALL) tables to
+ interface between the typeless data of M and the typed data supported
+ by the VAX calling standard. ZCALL tables associate packagenames with
+ groups of external routine definitions. Each external routine
+ definition associates the name(s) within the package with an actual
+ routine, and any parameters passed to or from the routine with data
+ typing information. External routine definitions also permit reordering
+ parameters from their presentation in M to the order used in the actual
+ external routine call.
+
+ GT.M supports calls to M from an external routine that was itself
+ called from M.
+
+ DO commands may specify an externref in place of an M entryref.
+ Extrinsic functions and extrinsic special variables may specify an
+ externref in place of a labelref.
+
+ The MDC Type A external call syntax replaces ZCALL, GT.M's
+ implementation-specific method for making external calls. However, GT.M
+ continues to support the ZCALL syntax.
+
+2 Extrinsic_Func
+ Extrinsic Functions
+
+ An extrinsic function is an M subroutine that another M routine can
+ invoke to return a value.
+
+ The format for extrinsic functions is:
+
+
+ $$[label][^routinename]([expr|.lname[,...]])
+
+ o The optional label and optional routinename make up the formallabel
+ that specifies the name of the subroutine performing the extrinsic
+ function. The formallabel must contain at least one of its optional
+ components.
+
+ o The optional expressions and actualnames make up the actuallist
+ that specifies the list of actual parameters M passes to the
+ invoked routine.
+
+ M stacks $TEST for extrinsic functions. This is one of the two major
+ differences between the DO command with parameters and extrinsics. On
+ return from an extrinsic function, M restores the value of $TEST to
+ what it was before the extrinsic function, regardless of the actions
+ executed by the invoked routine.
+
+ M requires a routine that implements an extrinsic function to terminate
+ with an explicit QUIT command which has an argument. M returns the
+ value of the QUIT command argument as the value of the extrinsic
+ function. This is the other major difference between the DO command
+ with parameters and extrinsics. It is now possible to invoke a C
+ function in a package via the external call mechanism.
+
+ Example:
+
+
+ GTM>ZPRINT ^POWER
+
+ POWER(V,X,S,T) ;extrinsic to raise to a power
+
+ ;ignores fractional powers
+
+ SET T=1,S=0
+
+ IF X<0 SET X=-X,S=1
+
+ FOR X=1:1:X S T=T*V
+
+ QUIT $S(S:1/T,1:T)
+
+ GTM> WRITE $$^POWER(3,4)
+
+ 81
+ GTM>
+
+ The POWER routine uses a formallist that is longer than the
+ "expected" actuallist to protect local working variables. Such
+ practice may be encouraged or discouraged by your institution's
+ standards.
+
+2 Extrinsic_Spc_Vars
+ Extrinsic Special Variables
+
+ An extrinsic special variable is a user-written M subroutine that
+ another M routine can invoke to return a value.
+
+ The format for extrinsic special variables is:
+
+ $$[label][^routinename]
+
+ o The optional label and optional routinename make up the
+ formallabel, which specifies the name of the subroutine performing
+ the extrinsic function. The formallabel must contain at least one
+ of its optional component.
+
+ An extrinsic special variable can be thought of as an extrinsic
+ function without input parameters. $$x is equivalent in operation to
+ $$x(). Extrinsic special variables are the only case where invocation
+ of a formallabel does not require an actuallist. M stacks $TEST for
+ extrinsic special variables.
+
+ M requires that a routine that implements an extrinsic special variable
+ terminate with an explicit QUIT command which has an argument. M
+ returns the value of the QUIT command argument as the value of the
+ extrinsic special variable.
+
+ Example:
+
+
+ GTM>ZPRINT ^DAYOWEEK
+
+ DAYOWEEK() ;extrinsic special variable to
+
+ ;provide the day of the week
+
+ QUIT $ZD($H,"DAY")
+
+ GTM>WRITE $$DAYOWEEK^DAYOWEEK
+
+ MON
+
+2 Trans_Processing
+ Transaction Processing
+
+ Transaction Processing (TP) provides a way for M programs to organize
+ database updates into logical groups that occur as a single event
+ (i.e., either all the database updates in a transaction occur, or none
+ of them occur). No other process may behave as if it observed any
+ intermediate state.
+
+ Transaction processing has been designed to improve output and
+ eliminate "live lock" conditions. The number of attempts to complete
+ the transaction is limited to four. The fourth attempt is made inside a
+ "critical section" with all other processes temporarily locked out of
+ the database. Between the second and third tries, GT.M waits for a
+ random interval between 0 and 500 milliseconds.
+
+3 TP_Def
+ TP Definitions
+
+ In M, a transaction is a sequence of commands that begins with a TSTART
+ command, ends with a TCOMMIT command, and is not within the scope of
+ another transaction.
+
+ A successful transaction ends with a COMMIT that is triggered by the
+ TCOMMIT command at the end of the transaction. A COMMIT causes all the
+ database updates performed within the transaction to become available
+ to other processes.
+
+ An unsuccessful transaction ends with a ROLLBACK. ROLLBACK is invoked
+ explicitly by the TROLLBACK command, or implicitly at a process
+ termination that occurs during a transaction in progress. An error
+ within a transaction does not cause an implicit ROLLBACK. A ROLLBACK
+ removes any database updates performed within the transaction before
+ they are made available to other processes. ROLLBACK also releases all
+ resources LOCKed since the start of the transaction, and makes the
+ naked reference undefined.
+
+ A RESTART is a transfer of control to the TSTART at the beginning of
+ the transaction. RESTART implicitly includes a ROLLBACK and may
+ optionally restore local variables to the values they had when the
+ initial TSTART was originally executed. A RESTART always restores $TEST
+ and the naked reference to the values they had when the initial TSTART
+ was executed. RESTART does not manage device state information. A
+ RESTART is invoked by the TRESTART command or by M if it is determined
+ that the transaction is in conflict with other database updates.
+ RESTART can only successfully occur if the initial TSTART includes an
+ argument that enables RESTART.
+
+3 TP_Characteristics
+ TP Characteristics
+
+ Most transaction processing systems try to have transactions meet the
+ "ACID" test-Atomic, Consistent, Isolated, and Durable. To conform with
+ the M approach of providing maximum flexibility and, when possible,
+ backwards compatibility with older versions of the standard, M
+ transaction processing requires the use of programming conventions that
+ meet the ACID test.
+
+ For example, some effects of the BREAK, CLOSE, JOB, OPEN, READ, USE
+ WRITE, and ZSYSTEM commands may be observed by parties to the system.
+ Because the effects of these commands might cause an observing process
+ or person to conclude that a transaction executing them was in progress
+ and perhapsfinished, they violate, in theory, the principle of
+ Isolation.
+
+ The LOCK command is another example. A program may attempt to use a
+ LOCK to determine if another process has a transaction in progress. The
+ answer would depend on the management of LOCKs within transactions,
+ which is implementation-specific. This would therefore clearly violate
+ the principle of Isolation. The LOCK command is discussed later in this
+ section.
+
+ The simplest way to construct a transaction that meets the ACID test is
+ not to use any commands within a transaction whose affects may be
+ immediately "visible" outside the transaction. Unfortunately, because M
+ applications are highly interactive, this is not entirely
+ straightforward. When a user interaction relies on database
+ information, one solution is for the program to save the initial values
+ of any global values that could affect the outcome, in local variables.
+ Then, once the interaction is over and the transaction has been
+ initiated, the program checks the saved values against the
+ corresponding global variables. If they are the same, it proceeds. If
+ they differ, some other update has changed the information, and the
+ program must issue a TROLLBACK, and initiate another interaction as a
+ replacement.
+
+ Even when the "visible" commands appear within a transaction, an M
+ application may provide wholesome operation by relying on additional
+ programming or operating conventions.
+
+ A program using LOCKs to achieve serializability relies on properly
+ designed and universally followed LOCKing conventions to achieve
+ Isolation with respect to database operations. LOCKs placed outside the
+ transaction (usually a LOCK immediately before the TSTART and an unlock
+ immediately after the TCOMMIT) achieve serializability by actually
+ serializing any approximately concurrent transaction. LOCKs placed
+ inside the transaction (frequently a LOCK immediately after the TSTART
+ and an unlock immediately before the TCOMMIT) signal M to ensure that
+ no operations using the same LOCK resource(s) overlap. Within a
+ transaction, an M implementation may defer both LOCKing and unlocking
+ to achieve its goal of serializability. A program using TSTARTs with
+ the SERIAL keyword replaces the convention with a guarantee from M that
+ all the database activity of the transaction meets the test of
+ Isolation with respect to database activity.
+
+ In GT.M the Durability aspect of the ACID properties relies on the
+ journaling feature. When journaling is on, every transaction is
+ recorded in the journal file as well as in the database. The journal
+ file constitutes a serial record of database actions and states. It is
+ always written before the database updates and is designed to permit
+ recovery of the database if the database should be damaged. By default
+ when a process commits a transaction, it does not return control to the
+ application code until the transaction has reached the journal file.
+ The exception to this is that when the TSTART specifies
+ TRANSACTIONID="BATCH" the process resumes application execution without
+ waiting for the file system to confirm the successful write of the
+ journal record. The idea of the TRANSACTIONID="BATCH" has nothing
+ inherently to do with "batch" processing - it is to permit maximum
+ throughput for transactions where the application has its own
+ check-pointing mechanism, or method of recreating the transaction in
+ case of a failure. The real durability of transactions is a function of
+ the durability of the journal files. Putting journal files on reliable
+ devices (RAID with UPS protection) and eliminating common points of
+ failure with the path to the database (separate drives, controllers
+ cabling) improve durability. The use of the replication feature can
+ also improve durability by moving the data to a separate site in real
+ time.
+
+ Attempting to QUIT (implicitly or explicitly) from code invoked by a
+ DO, XECUTE, or extrinsic after that code issued a TSTART not yet
+ matched by a TCOMMIT, produces an error. Although this is a consequence
+ of the RESTART capability, it is true even when that capability is
+ disabled. For example, this means that an XECUTE containing only a
+ TSTART fails, while an XECUTE that performs a complete transaction
+ succeeds.
+
+3 TP_Performance
+ TP Performance
+
+ To achieve the best GT.M performance, transactions should:
+
+ o be as short as possible
+
+ o consist, as much as possible, only of global updates
+
+ o be SERIAL with no associated LOCKs
+
+ o have RESTART enabled with a minimum of local variables protected by
+ a restart portion of the TSTART argument.
+
+ Large concurrent transactions using TCOMMIT may result in repeated and
+ inefficient attempts by competing processes to capture needed scarce
+ resources, resulting in poor performance.
+
+ Example:
+
+
+ TSTART ():SERIAL
+
+ SET (ACCT,^M(0))=^M(0)+1
+
+ SET ^M(ACCT)=PREC,^PN(NAM)=ACCT
+
+ TCOMMIT
+
+ This transaction encapsulates these two SETs. The first increments the
+ tally of patients registered, storing the number in local variable ACCT
+ for faster access in the current program, and in global variable ^M(0).
+ The second SET stores a patient record by account number and the third
+ cross-references the account number with the patient name. Placing the
+ SETs within a single transaction ensures that the database always
+ receive either all of the SETs or none of them, thus protecting
+ database integrity against process or system failure. Similarly,
+ another concurrent process, whether using transactions or not, never
+ finds one of the SETs in place without also finding the other one.
+
+ Example:
+
+ TSTART ():SERIAL
+
+ IF $TRESTART>3 DO QUIT
+
+ .TROLLBACK
+
+ .WRITE !,"Too many RESTARTs"
+
+ .QUIT
+
+ SET (NEXT,^ID(0))=^ID(0)+1
+
+ SET ^ID(NEXT)=RECORD,^XID(ZIP,NEXT)=""
+
+ TCOMMIT
+
+ This transaction will automatically restart if it cannot serialize the
+ SETs to the database, and will terminate with a TROLLBACK if more than
+ 3 RESTARTs occur.
+
+ GT.M provides a way to monitor transaction restarts by reporting them
+ to the operator logging facility. If the logical name
+ TPRESTART_SYSLOG_DELTA is defined, GT.M reports every Nth restart where
+ N is the numeric evaluation of the value of TPRESTART_SYSLOG_DELTA. If
+ the logical name TPRESTART_SYSLOG_LIMIT is defined, the restart
+ reporting begins after the number of restarts specified by the value of
+ TPRESTART_SYSLOG_LIMIT. For example, defining both the logical name to
+ the value 1, causes all TP restarts to be logged. When
+ TPRESTART_SYSLOG_DELTA is defined, leaving TPRESTART_SYSLOG_LIMIT
+ undefined is equivalent to giving it the value 1.
+
+ For more information on enhancements related to TP performance
+ refer to the "NOISOLATION" section under VIEW command topic in the
+ "Commands" chapter in GT.M Programmer's Guide.
+
+3 TP_Example
+ TP Example
+
+ Here is a transaction processing example that lets you exercise the
+ concept. If you use this example, be mindful that the functions
+ "holdit" and "trestart" are included as tools to allow you access to
+ information within a transaction which would normally be hidden from
+ users. These types of functions would not normally appear in production
+ code. Comments have been inserted into the code to explain the function
+ of various segments.
+
+
+ trans
+
+ ;This sets up the program constants
+
+ ;for doit and trestart
+
+ n
+
+ s $p(peekon,"V",51)=""
+
+ s $p(peekon,"V",25)="Peeking inside Job "_$j
+
+ s $p(peekoff,"^",51)=""
+
+ s $p(peekoff,"^",25)="Leaving peeking Job "_$j
+
+ ;This establishes the main loop
+
+ s CNFLTMSG="Conflict, please reenter"
+
+ f r !,"Name: ",nam q:'$l(nam) d
+
+ .i nam="?" d q
+ ..w !,"Current data in ^trans:",! d:$d(^trans) q
+ ...zwrite ^trans
+ .f s ok=1 d q:ok w !,$C(7),CNFLTMSG,$C(7),!
+ ..s old=$g(^trans(nam),"?")
+ ..i old="?" w !,"Not on file" d q
+ ...;This is the code to add a new name
+ ...f d q:data'="?"
+ ....r !,"Enter any info using '#' delimiter: ",!,data
+ ...i data="" w !,"No entry made for ",nam q
+ ...TSTART ():SERIAL i $$trestart ;$$trestart for demo
+ ...i $d(^trans(nam)) s ok=^trans(nam)=data TRO q
+ ...s ^trans(nam)=data
+ ...TCOMMIT:$$doit ;$$doit for demo
+ ..;This is the beginning of the change and delete loop
+ ..f d q:fld=+fld!'$l(fld) w " must be numeric"
+ ...w !,"Current data: ",!,old
+ ...r !,"Piece no. (negative to delete record) : ",fld
+ ..i 'fld w !,"no change made" q
+ ..;This is the code to delete a new name
+ ..i fld<0 d q ; delete record
+ ...f d q:"YyNn"[x
+ ....w !,"Ok to delete ",nam," Y(es) or N(o) <N>? "
+ ....r x s x=$e(x)
+ ...i "Yy"'[x!'$l(x) w !,"No change made" q
+ ...TSTART ():SERIAL i $$trestart ;$$trestart for demo
+ ...i $g(^trans(nam),"?")'=old TROLLBACK s ok=0 q
+ ...kill ^trans(nam)
+ ...TCOMMIT:$$doit; $$doit for demo
+ ..;This is the code to change a field
+ ..f r !,"Data: ",data q:data'="?"&(data'["#") d
+ ...w " must not be a single '?' or contain any '#'"
+ ..TSTART ():SERIAL i $$trestart ;$$trestart for demo
+ ..i '$d(^trans(nam)) s ok=0 TROLLBACK q
+ ..i $p(^trans(nam),"#",fld)=$p(old,"#",fld) d q
+ ...s ok=$p(^trans(nam),"#",fld)=data TROLLBACK
+ ..s $p(^trans(nam),"#",fld)=data
+ ..TCOMMIT:$$doit; $$doit for demo
+ q
+
+
+ doit()
+
+ ;This inserts delay and an optional
+
+ ;rollback only to show how it works
+
+ w !!,peekon d disp
+
+ f d q:"CR"[act
+
+ .r !,"C(ommit), R(ollback), or W(ait) <C>? ",act
+ .s act=$tr($e(act),"cr","CR")
+ .i act="?" d disp
+ i act="R" TROLLBACK w !,"User requested DISCARD"
+
+ w !,peekoff,!
+
+ q $TLEVEL
+
+
+ trestart()
+
+ ;This is only to show what is happening
+
+ i $TRESTART d
+
+ .w !!,peekon,!,">>>RESTART<<<",! d disp w !,peekoff,!
+ q 1
+
+
+ disp
+
+ w !,"Name: ",nam
+
+ w !,"Original data: ",!,old,!,"Current data: "
+
+ w !,$g(^trans(nam),"KILLED!")
+
+ q
+
+ Generally, this type of program would be receiving data from multiple
+ sessions into the same global.
+
+1 BREAK
+ Break
+
+ The BREAK command pauses execution of the code and initiates Direct
+ Mode.
+
+ The format of the BREAK command is:
+
+
+ B[REAK][:tvexpr] [expr[:tvexpr][,...]]
+
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o The optional expression contains a fragment of GT.M code to XECUTE
+ before the process enters Direct Mode.
+
+ o The BREAK command without an argument causes a pause in execution
+ of the routine code and immediately initiates Direct Mode. In this
+ case, at least two (2) spaces must follow the BREAK to separate it
+ from the next command on the line.
+
+ o The optional truth-valued expression immediately following the
+ expression is the argument postconditional that controls whether
+ GT.M XECUTEs the argument. If present and true, the process
+ executes the code before entering Direct Mode. If present and
+ false, the process does not execute the code before entering Direct
+ Mode.
+
+ o An indirection operator and an expression atom evaluating to a list
+ of one or more BREAK arguments form a legal argument for a BREAK.
+
+ Issuing a BREAK command inside a transaction destroys the Isolation of
+ that transaction. Beacuse of the way that GT.M implements transaction
+ processing, a BREAK within a transaction may suffer an indefinite
+ number of restarts ("live lock").
+
+ Generally, programs in production must not include BREAK commands.
+ Therefore, GT.M provides the ZBREAK and ZSTEP commands, which insert
+ temporary breakpoints in the image rather than the source code. BREAKs
+ inserted with ZBREAK only exist until the image terminates or until
+ explicitly removed by another ZBREAK command. ZSTEP also inserts
+ temporary BREAKs in the image that only exist for the execution of the
+ ZSTEP command. In the GT.M debugging environment, ZBREAKs and ZSTEPs
+ that insert BREAKs provide a more flexible and less error-prone means
+ of setting breakpoints than coding BREAKs directly into a routine. For
+ more information on ZBREAK and ZSTEP, refer to the sections that
+ describe those commands.
+
+ To resume execution of the interrupted program, use the ZCONTINUE
+ command.
+
+ GT.M displays messages identifying the source of a BREAK as:
+
+ o The body of a program
+
+ o A
+ o ZBREAK action
+
+ o A device EXCEPTION
+
+ o A ZSTEP action
+
+ The VIEW "BREAKMSG" mask selectively enables or disables these
+ messages. See the section on "VIEW" for an explanation of the mask. By
+ default, a process executing a GT.M image displays all BREAK messages.
+
+ LINKing a GT.M image with a modified GTM$DEFAULTS can alter the default
+ for that image.
+
+ When a process encounters a BREAK, it displays a prompt indicating
+ readiness to process commands in Direct Mode. By default, Direct Mode
+ displays the GTM> prompt. SETting the $ZPROMPT intrinsic special
+ variable alters the prompt.
+
+2 Ex_of_Break
+ Examples of BREAK
+
+ Example:
+
+
+ LOOP0 F S act=$O(^act(act)) Q:act="" B:debug D LOOP1
+
+ This FOR loop contains a BREAK with a command postconditional.
+
+ Example:
+
+
+ B:$D(x) "W !,""OK""":x,"W !,""Wrong again""":'x
+
+ This uses a BREAK with both command and argument postconditionals. The
+ actions display debugging messages.
+
+1 CLOSE
+ Close
+
+ The CLOSE command breaks the connection between a process and a device.
+
+ The format of the CLOSE command is:
+
+
+ C[LOSE][:tvexpr] expr[:(keyword[=expr][:...])][,...]
+
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o The required expression specifies the device to CLOSE.
+
+ o The optional keywords specify device parameters that control device
+ behavior; some device parameters take arguments delimited by an
+ equal sign (=). If there is only one keyword, the surrounding
+ parentheses are optional.
+
+ o An indirection operator and an expression atom evaluating to a list
+ of one or more CLOSE arguments form a legal argument for a CLOSE.
+
+1 DO
+ Do
+
+ The DO command makes an entry in the GT.M invocation stack and
+ transfers execution to the location specified by the entryref.
+
+ The format of the DO command is:
+
+
+ D[O][:tvexpr] [entryref[(expr|.lvn[,...])][:tvexpr][,...]]
+
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o The optional entryref specifies a location (with some combination
+ of label, offset, and routinename) at which execution continues
+ immediately following the DO.
+
+ o A DO command without an argument (that is, a DO followed by two (2)
+ spaces) transfers execution to the next line in the routine if that
+ line contains a number of periods (.) after the optional label and
+ before the required linestart. These periods indicate the current
+ level of "immediate" nesting caused by argumentless DOs. If the
+ line following the DO contains too many periods, GT.M reports an
+ error; if the line following the DO contains too few periods, GT.M
+ ignores the DO command.
+
+ o A DO command without an argument stacks the current value of $TEST,
+ in contrast to a DO with an argument, which does not protect the
+ current value of $TEST.
+
+ o The optional parameter list enclosed in parentheses ( ) contains
+ parameters to pass to the routine entry point.
+
+ o If the DO specifies a parameter list, the entryref location must
+ start with a label and an argument list (that is, GT.M prohibits
+ entryrefs with offsets during parameter passing).
+
+ o If an element in the parameter list starts with a period, it
+ specifies an unsubscripted local variable name and the DO passes
+ that variable by reference. Otherwise, the element specifies an
+ expression that the DO evaluates and passes as a value.
+
+ o The optional truth-valued expression following the parameter list,
+ or the entryref if the argument contains no parameter list,
+ specifies the argument postconditional and controls whether GT.M
+ performs a DO with that argument.
+
+ o An indirection operator and an expression atom evaluating to a list
+ of one or more DO arguments form a legal argument for a DO.
+
+ An explicit or implicit QUIT within the scope of the DO, but not within
+ the scope of any other DO, FOR, XECUTE, or extrinsic, returns execution
+ to the instruction following the calling point. This point may be the
+ next DO argument or another command. At the end of a routine, or the
+ end of a nesting level created by an argumentless DO, GT.M performs an
+ implicit QUIT. Any line that reduces the current level of nesting by
+ changing the number of leading periods (.) causes an implicit QUIT,
+ even if that line only contains a comment.
+
+ Terminating the image and execution of ZGOTO commands are the only ways
+ to avoid eventually returning execution to the calling point. A DO
+ command may optionally pass parameters to the invoked subroutine.
+
+2 Ex_of_Do
+ Examples of DO
+
+ Example:
+
+
+ GTM>DO ^%RD
+
+ This example invokes the routine directory utility program (%RD) from
+ Direct Mode. The caret symbol (^) specifies that the DO command invokes
+ %RD as an external routine.
+
+ Example:
+
+
+ GTM>DO A(3)
+
+ This example invokes the subroutine at label A and passes the value 3
+ as a parameter. Because the DO argument does not have a caret symbol
+ (^), it identifies A as a label in the current routine.
+
+ Example:
+
+
+ Label A;
+
+ SET di="" U outfile
+
+ FOR SET di=$O(^div(di)) Q:di="" D PREP D D POST
+
+ .SET de="",(nr,gr)=0
+
+ .WRITE "Division ",di,! F S de=$O(^de(di,de)) Q:de="" D
+
+ ..WRITE "Department ",de," Gross Rev: ",^grev(di,de),!
+
+ ..WRITE "Department ",de," Net Rev: ",^nrev(di,de),!
+
+ ..SET gr=gr+^grev(di,de),nr=nr+^nrev(di,de)
+
+ .W "Division Gross Rev: ",gr,!,"Division Net Rev: ",nr,!
+
+ DO PRINT^OUTPUT(outfile)
+
+ QUIT
+
+ This routine first uses a DO with a label argument (PREP) to do some
+ pre-processing. Then, it uses an argumentless DO to loop through each
+ division of a company to format a report. Within the first argumentless
+ DO, a second argumentless DO (line 4) loops through and formats each
+ department within a division. After the processing of all departments,
+ control returns to the first argumentless DO, which prints a summary of
+ the division. Following processing of all divisions, a DO with a label
+ argument (POST) does some post-processing. Finally, at the next-to-last
+ line, the routine uses a DO that invokes a subroutine at a label
+ (PRINT) in an external routine (^OUTPUT), passing the name of the
+ output file (outfile) as a parameter.
+
+1 ELSE
+ Else
+
+ GT.M executes the remainder of the line after the ELSE if $TEST is
+ FALSE (0). GT.M does not execute the rest of the line if $TEST is TRUE
+ (1).
+
+ The format of the ELSE command is:
+
+ E[LSE]
+
+ o Because ELSE is a conditional command, it does not support a
+ command postconditional.
+
+ o The scope of the ELSE is the remainder of the line.
+
+ o Because the ELSE has no argument, at least two (2) spaces must
+ follow the command to separate it from the next command on the
+ line.
+
+ Because the scopes of both the IF and the ELSE commands extend to the
+ rest of the GT.M line, placing an ELSE on the same line as the
+ corresponding IF cannot achieve the desired result. If an ELSE were
+ placed on the same line as its corresponding IF, then the expression
+ tested by the IF would be either TRUE or FALSE. If the condition is
+ TRUE, the code following the ELSE would not be executed. If the
+ condition is FALSE, the ELSE and everything following it would not be
+ executed.
+
+ ELSE is analogous to IF '$TEST, except the latter statement switches
+ $TEST to its complement and ELSE never alters $TEST.
+
+ The scope of an ELSE can be extended with DO or XECUTE commands.
+
+2 Ex_of_Else
+ Examples of Else
+
+ Example:
+
+
+ IF x=+x SET x=x+y
+
+ ELSE WRITE !,x
+
+ The IF command evaluates the conditional expression x=+x and sets
+ $TEST. If $TEST=1 (TRUE), GT.M executes the commands following the IF.
+ The ELSE on the following line specifies an alternative action to take
+ if the expression is false.
+
+ Example:
+
+
+ IF x=+x DO ^GOFISH
+
+ ELSE SET x=x_"^"_y
+
+ The DO with an argument after the IF raises the possibility that the
+ routine ^GOFISH changes the value of $TEST, thus making it possible to
+ execute both the commands following the IF and the commands following
+ the ELSE.
+
+ Example:
+
+
+ OPEN dev::0 ELSE WRITE !,"Device unavailable" QUIT
+
+ This ELSE depends on the result of the timeout on the OPEN command. If
+ the OPEN succeeds, it sets $TEST to one (1) and GT.M skips the rest of
+ the line after the ELSE. If the OPEN fails, it sets $TEST to zero (0),
+ and GT.M executes the remainder of the line after the ELSE.
+
+1 FOR
+ For
+
+ The FOR command provides a looping mechanism in GT.M. A FOR command
+ does not generate an additional level on the GT.M invocation stack.
+
+ The format of the FOR command is:
+
+
+ F[OR][lvn=expr[:numexpr1[:numexpr2]][,...]]]
+
+ o Because FOR is a conditional command, it does not support a command
+ postconditional.
+
+ o The scope of the FOR is the remainder of the line.
+
+ o When the FOR has no argument, at least two (2) spaces must follow
+ the command to separate it from the next command on the line. This
+ specifies a loop that must be terminated by a QUIT, HALT, GOTO, or
+ ZGOTO.
+
+ o The optional local variable name specifies a loop control variable
+ delimited by an equal sign (=). A FOR command has only one control
+ variable, even when it has multiple arguments.
+
+ o When initiating the FOR, GT.M assigns the loop control variable the
+ value of the expression. When only an initial value appears, GT.M
+ executes the remainder of the line once for that argument without
+ forcing the control variable to be numeric.
+
+ o If the argument includes an increment and, optionally, a
+ terminator, GT.M treats the initial expression as a number.
+
+ o The optional numeric expression after the first colon (:) delimiter
+ specifies the increment for each iteration. The FOR command does
+ not increment the control variable on the first iteration.
+
+ o The optional numeric expression after the second colon (:)
+ delimiter specifies the limiting value for the control variable.
+ This expression is evaluated only when the control variable is
+ initialized to the corresponding initial value, then used for all
+ subsequent iterations.
+
+ o GT.M does not execute the commands on the same line following the
+ FOR if:
+
+ The increment is non-negative and the initial value of the control
+ variable is greater than the limiting value.
+ The increment is negative and the initial value of the control variable
+ is less than the limiting value.
+ o After the first iteration, GT.M does not alter the control variable
+ and ceases execution under the control of the FOR if:
+
+ The increment is non-negative, and altering the control variable by the
+ increment would cause the control variable to be greater than the
+ limiting value.
+ The increment is negative, and altering the control variable by the
+ increment would cause the control variable to be less than the limiting
+ value.
+ o When the FOR has multiple arguments, each one affects the loop
+ control variable in sequence. For an argument to gain control, no
+ prior argument to the FOR can have an increment without a limit.
+
+ Increments and limits may be positive, negative, an integer, or a
+ fraction. GT.M never increments a control variable "beyond" a limit.
+ Other commands may alter a control variable within the extended scope
+ of a FOR that it controls. When the argument includes a limit, such
+ modification can cause the FOR argument to yield control at the start
+ of the next iteration.
+
+ The scope of a FOR can be extended with DO or XECUTE commands.
+
+ GT.M terminates the execution of a FOR when it executes an explicit
+ QUIT or a GOTO (or ZGOTO in GT.M) that appears on the line after the
+ FOR. FOR commands with arguments that have increments without limits
+ and argumentless FORs can be infinite loops. Such FORs must terminate
+ with a QUIT or a GOTO within the immediate scope of the FOR. Also, such
+ FORs can, but seldom, terminate by a HALT within the scope of the FOR
+ as extended by DOs, XECUTEs, and extrinsics. FORs terminated by such
+ commands act as "while" or "until" control mechanisms.
+
+2 Ex_of_For
+ Examples of FOR
+
+ Example:
+
+
+ GTM>KILL i FOR i=1:1:5 WRITE !,i
+
+ 1
+ 2
+ 3
+ 4
+ 5
+ GTM>WRITE i
+
+ 5
+ GTM>
+
+ This FOR loop has a control variable, i, which has the value one (1) on
+ the first iteration, then the value two (2), and so on, until in the
+ last iteration i has the value five (5). The FOR terminates because
+ incrementing i would cause it to exceed the limit. Notice that i is not
+ incremented beyond the limit.
+
+ Example:
+
+
+ GTM>FOR x="hello",2,"goodbye" WRITE !,x
+
+ hello
+
+ 2
+ goodbye
+
+ GTM>
+
+ This FOR loop uses the control variable x and a series of arguments
+ that have no increments or limits. Notice that the control variable may
+ have a string value.
+
+ Example:
+
+
+ GTM>FOR x="hello":1:-1 WRITE !,x
+
+ GTM>ZWRITE x
+
+ x=0
+
+ GTM>
+
+ Because the argument has an increment, the FOR initializes the control
+ variable x to the numeric evaluation of "hello" (0). Then, GT.M never
+ executes the remainder of the line because the increment is positive,
+ and the value of the control variable (0) is greater than the limiting
+ value (-1).
+
+ Example:
+
+
+ GTM>FOR y=-1:-3:-6,y:4:y+10,"end" WRITE !,y
+
+ -1
+
+ -4
+
+ -4
+
+ 0
+ 4
+ end
+
+ GTM>
+
+ This FOR uses two limited loop arguments and one value argument. The
+ first argument initializes y to negative one (-1), then increments y to
+ negative four (-4). Because another increment would cause y to be less
+ than the limit (-6), the first argument terminates with y equal to
+ negative four (-4). The second argument initializes the loop control
+ variable to its current value and establishes a limit of six (6=-4+10).
+ After two iterations, incrementing y again would cause it to be greater
+ than the limit (6), so the second argument terminates with y equal to
+ four (4). Because the final argument has no increment, the FOR sets y
+ to the value of the argument, and GT.M executes the commands following
+ the FOR one more time.
+
+ Example:
+
+
+ GTM>S x="" F S x=$O(ar(x)) Q:x="" W !,x
+
+ This example shows an argumentless FOR used to examine all first level
+ subscripts of the local array ar. When $ORDER indicates that this level
+ contains no more subscripts, the QUIT with the postconditional
+ terminates the loop.
+
+1 GOTO
+ Goto
+
+ The GOTO command transfers execution to a location specified by its
+ argument.
+
+ The format of the GOTO command is:
+
+
+ G[OTO][:tvexpr] entryref
+
+ [:tvexpr][,...]
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o The required entryref specifies the target location for the control
+ transfer.
+
+ o The optional truth-valued expression immediately following the
+ entryref specifies the argument postconditional, and controls
+ whether GT.M performs a GOTO with that argument.
+
+ o An indirection operator and an expression atom evaluating to a list
+ of one or more GOTO arguments form a legal argument to a GOTO.
+
+ A GOTO command within a line following a FOR command terminates that
+ FOR command.
+
+2 Ex_of_Goto
+ Examples of GOTO
+
+ Example:
+
+
+ GTM>GOTO TIME+4
+
+ This GOTO command transfers control from Direct Mode to the line that
+ is four (4) lines after the line labeled TIME (in the currently active
+ routine). Using an offset is typically a debugging technique and rarely
+ used in production code.
+
+ Example:
+
+
+ GOTO A:x<0,^A:x=0,A^B
+
+ This GOTO command transfers control to label A in the current routine,
+ if x is less than zero (0), to routine ^A if x is equal to zero (0), or
+ to label A in routine ^B. Once any of the transfers occurs, the rest of
+ the arguments have no effect.
+
+1 HALT
+ Halt
+
+ The HALT command stops GT.M program execution and causes GT.M to return
+ control to the VMS environment that invoked the GT.M image.
+
+ The format of the HALT command is:
+
+
+ H[ALT][:tvexpr]
+
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether GT.M
+ executes the command.
+
+ o Because the HALT command has no argument, at least two (2) spaces
+ must follow the command to separate it from the next command on the
+ line. Note that additional commands do not serve any purpose unless
+ the HALT has a postconditional.
+
+ A HALT releases all shared resources held by the process, such as
+ devices OPENed in GT.M, databases, and GT.M LOCKs. If the value of
+ $TLEVEL is greater than zero (0), a ROLLBACK is performed.
+
+ Because HALT and HANG share the same abbreviation (H), GT.M
+ differentiates them based on whether an argument follows the command.
+
+ Example:
+
+
+ $ gtm
+
+ %GTM-I-BREAK, Break instruction encountered
+
+ At M source location +1^GTM$DMOD
+
+ GTM>HALT
+
+ $
+
+ Because we invoke this GT.M image interactively, the HALT in Direct
+ Mode leaves the process at the DCL prompt.
+
+1 HANG
+ Hang
+
+ The HANG command suspends GT.M program execution for a period of time
+ specified by the command argument.
+
+ The format of the HANG command is:
+
+
+ H[ANG][:tvexpr] numexpr[,...]
+
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o The numeric expression specifies the time in seconds to elapse
+ before resuming execution; actual elapsed time may vary slightly
+ from the specified time. If the numeric expression is negative,
+ HANG has no effect. Portability requirements for GT.M only
+ guarantee accuracy to the nearest second. However, more accuracy
+ can be found on VMS systems.
+
+ o An indirection operator and an expression atom evaluating to a list
+ of one or more HANG arguments form a legal argument to a HANG.
+
+ A process that repeatedly tests for some event, such as a device
+ becoming available or another process modifying a global variable, may
+ use a HANG to limit its consumption of computing resources.
+
+ Because HALT and HANG share the same abbreviation (H), GT.M
+ differentiates them based on whether an argument follows the command.
+
+2 Ex_of_Hang
+ Examples of HANG
+
+ Example:
+
+
+ FOR QUIT:$D(^CTRL(1)) HANG 30
+
+ This FOR loop repeatedly tests for the existence of ^CTRL(1), and
+ terminates when that global variable exists. Otherwise the routine
+ HANGs for 30 seconds and tests again.
+
+ Example:
+
+
+ SET t=1 F Q:$D(^CTRL(1)) H t I t<30 S t=t+1
+
+ This is similar to the previous example, except that it uses an
+ adaptive time that lengthens from 1 second to a limit of 30 seconds if
+ the routine stays in the loop.
+
+1 IF
+ IF
+
+ The IF command provides conditional execution of the remaining commands
+ on the line. When IF has an argument, it updates $TEST with the truth
+ value of its evaluated argument. GT.M executes the remainder of a line
+ after an IF statement when $TEST is 1 (TRUE). When $TEST is 0 (FALSE),
+ GT.M does not execute the rest of the line.
+
+ The format of the IF command is:
+
+
+ I[F] [tvexpr[,...]]
+
+ o Because IF is a conditional command, it does not support a command
+ postconditional.
+
+ o The scope of the IF is the remainder of the line.
+
+ o The action of IF is controlled by the value of the expression and
+ by $TEST, if there is no expression.
+
+ o IF with no argument acts on the existing value of $TEST (which it
+ does not change); in this case, at least two (2) spaces must follow
+ the IF to separate it from the next command on the line.
+
+ o An indirection operator, and an expression atom evaluating to a
+ list of one or more IF arguments form a legal argument to IF.
+
+ Example:
+
+ IF A,B ...
+
+ is equivalent to
+
+ IF A IF B
+
+ An IF with more than one argument behaves as if those arguments were
+ logically "ANDed." However, execution of the line ceases with the
+ evaluation of the first false argument. For IF argument expressions
+ containing the "AND" operator (&), execution still ceases with the
+ evaluation of the first false argument. Any global references within
+ the expression act in sequence to maintain the naked reference.
+
+ Postconditionals perform a function similar to IF; however, their scope
+ is limited to a single command or argument, and they do not modify
+ $TEST. For more information on postconditionals.
+
+2 Ex_of_IF
+ Examples of IF
+
+ Example:
+
+
+ IF x=+x!(x="") DO BAL
+
+ In this example, the DO executes if x contains a number or a null
+ string.
+
+ Example:
+
+
+ WRITE !,?50,BAL IF 'BAL WRITE "****"
+
+ IF S EMPTY(acct)=""
+
+ The IF in the first line changes the value of $TEST, determining the
+ execution of the code following the argumentless IF in the second line.
+ Such argumentless IFs may serve as a form of line continuation.
+
+ Example:
+
+
+ GTM>SET X=1,Y=1,Z=2 KILL UNDEF
+
+ GTM>IF X=1,Y=1,Z=3,UNDEF=0 W "HI"
+
+ GTM>
+
+ The IF command causes GT.M to cease executing the line after it
+ determines Z is not equal to three (3). Therefore, GT.M never evaluates
+ the reference to the undefined variable and never generates an error.
+
+ Example:
+
+
+ GTM>SET X=1 KILL UNDEF
+
+ GTM>IF X=1!(UNDEF=3) WRITE "HI"
+
+ HI
+
+ GTM>
+
+ Because GT.M recognizes that the X=1 fulfills the IF, it skips
+ evaluation of the UNDEF variable and executes this IF command without
+ generating an error. Because GT.M does not require such optimizations
+ and in fact discourages them by requiring that all global references
+ maintain the naked indicator, other implementations may generate an
+ error.
+
+1 JOB
+ Job
+
+ The JOB command creates another process, activates the current image or
+ another specified GT.M executable image, and executes a named routine.
+
+ $ZJOB is set to the pid of the process created by the JOB command. For
+ details refer to the "$ZJOB" section in the "Intrinsic Special
+ Variable" chapter of GT.M Programmer's Guide.
+
+ The format of the JOB command is:
+
+
+ J[OB][:tvexpr] entryref
+
+ [(expr[,...])]
+ [:[(keyword[=value][:...])][:numexpr]][,...]
+
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o The required entryref specifies a location at which the new process
+ starts.
+
+ o The optional parameter list enclosed in parentheses () contains
+ parameters to pass to the routine entry point.
+
+ o If the JOB specifies a parameter list, the entryref location must
+ start with a label and a formallist. GT.M prohibits entryrefs with
+ offsets during parameter passing.
+
+ o The optional elements in the parameter list specify expressions
+ that the JOB evaluates and passes as values.
+
+ o The keywords specify optional processparameters that control
+ aspects of the environment for the new process.
+
+ o If the JOB command has only one processparameter, the surrounding
+ parentheses are optional.
+
+ o Some keywords take numeric or string literals delimited by an equal
+ sign (=) as arguments. Because the values are constants, strings
+ must be enclosed in quotation marks (" "), and variable arguments
+ require that the entire argument be constructed and referenced
+ using indirection.
+
+ o The optional numeric expression specifies a time in seconds after
+ which the command should timeout if unsuccessful; 0 results in a
+ single attempt.
+
+ o When a JOB command contains no processparameters, double colons
+ (::) separate the time-out numeric expression from the entryref.
+
+ o An indirection operator and an expression atom, evaluating to a
+ list of one or more JOB command arguments, form a legal argument
+ for a JOB command.
+
+ o The maximum command-line length from a JOB command is 8192 bytes.
+
+ The resultant process can be detached or spawned. VMS deletes the
+ resultant process when the image completes execution. If the job is
+ spawned, VMS deletes the image when the parent process terminates. A
+ detached job can continue after the parent process terminates.
+
+ By default, the new process uses the same base image as the parent
+ process. The IMAGE processparameter specifies an alternative image. If
+ the routine specified by the entryref is not in the linked image, the
+ created process attempts to auto-ZLINK the missing routine.
+
+ If a JOB command specifies a timeout, and GT.M creates the resultant
+ process before the timeout elapses, JOB sets $TEST to true (1). If GT.M
+ cannot create the process within the specified timeout, JOB sets $TEST
+ to false (0). If a JOB command does not specify a timeout, the
+ execution of the command does not affect $TEST.
+
+ If GT.M cannot create the process because of something that is unlikely
+ to change during the timeout interval, such as insufficient privileges
+ or failure to find the specified image, the JOB command generates a
+ run-time error. If the command does not specify a timeout and the
+ environment does not provide adequate resources, the process waits
+ until resources become available to create the resultant process.
+
+ The resultant process executes asynchronously with the current process.
+ Once GT.M starts the resultant process, the current process continues,
+ regardless of whether the JOB is detached or spawned.
+
+2 The_JOB_Env
+ The JOB Environment
+
+ When the JOB is spawned, VMS creates the environment for the new
+ process by copying the environment of the process issuing the JOB
+ command and making a few minor modifications.
+
+ When the JOB is DETACHED, as it is by default, GT.M creates a new VMS
+ job by running LOGINOUT.EXE. LOGINOUT.EXE performs the same tasks for
+ the new job as it does for an interactive login session, except that it
+ assigns the process-permanent logical names for I/O based on the
+ processparameters. If the JOB command does not explicitly specify these
+ processparameters, GT.M provides default values.
+
+3 JOB_Impl_Logi_Name
+ JOB Implications for Logical Names
+
+ If the resultant process is DETACHED, the DETACHED process does not
+ have access to the process or job logical name tables of the initiating
+ process. In this case, the resultant job can acquire logical names as
+ follows:
+
+ o By receiving any assignments made in SYS$LOGIN:LOGIN.COM of the
+ initiating process.
+
+ o By receiving any assignments made in the file specified by the
+ optional STARTUP parameter.
+
+ o By processparameters specifying values for I/O and GTM$GBLDIR.
+
+ When multiple sources specify GTM$GBLDIR, the last source in the
+ previous list overrides the prior sources. When a JOB is DETACHED, as
+ it is by default, take care to provide the proper environment,
+ particularly logical names for the JOBbed process.
+
+3 JOB_Impl_for_Dir
+ JOB Implications for Directories
+
+ By default, GT.M uses the current default directory of the parent
+ process for the default directory of the initiated process.
+
+ DCL commands in the login files of the resultant process and the
+ DEFAULT processparameter can modify the default. If the files specified
+ by processparameters, except LOGFILE, do not exist, and GT.M does not
+ have permission to create them, the JOBed process terminates. When the
+ corresponding files are in the current default directory, the IMAGE,
+ OUTPUT, INPUT, and ERROR processparameters do not require a full
+ file-specification.
+
+ If the file-specification for LOGFILE does not contain a directory,
+ GT.M defaults to the login directory of the parent process.
+
+ A detached JOB executes the LOGIN.COM in the login directory of the
+ initiating process.
+
+3 JOB_Impl_VMS_Priv
+ JOB Implications for VMS Privileges
+
+ Certain options associated with the JOB command require privileges. The
+ sections describing each JOB command processparameter give the VMS
+ privileges required to use the parameter. If you need additional
+ privileges, contact your system manager.
+
+2 JOB_ProcParam
+ JOB Processparameters
+
+ The following sections describe the processparameters available for the
+ JOB command in GT.M.
+
+3 ACCOUNTING
+ [NO]ACC[OUNTING]
+
+ Enables or disables VMS accounting records for the resultant job. To
+ disable accounting, the process issuing the JOB must have the ACNT
+ privilege.
+
+ By default, JOB provides ACCOUNTING.
+
+3 DEFAULT
+ DEF[AULT]=strlit
+
+ The string literal specifies the default directory.
+
+ The maximum directory length is 255 characters.
+
+ If the JOB command does not specify a DEFAULT directory, GT.M uses the
+ current default directory of the parent process.
+
+3 DETACHED
+ [NO]DET[ACHED]
+
+ DETACHED specifies creation of a detached process.
+
+ NODETACHED specifies creation of a spawned job within the same process.
+ A spawned job shares process limits with other jobs in the process and
+ the logical names of the parent process.
+
+ VMS security mechanisms prevent a captive account from creating a
+ DETACHED job.
+
+ The MAXDETACH quota in the user authorization file determines the
+ maximum number of detached processes a user may create.
+
+ By default, JOBs are DETACHED.
+
+3 ERROR
+ ERR[OR]=strlit
+
+ The string literal specifies a value for SYS$ERROR.
+
+ The maximum string length is 255 characters.
+
+ By default, JOB constructs the error file-specification from the
+ ROUTINENAME using a file extension of .MJE and the current directory of
+ the process created by the JOB command.
+
+3 GBLDIR
+ GBL[DIR]=strlit
+
+ The string literal specifies a value for the logical name GTM$GBLDIR.
+
+ The maximum length of the value permitted is 255 characters.
+
+ By default, the job uses the same specification for GTM$GBLDIR as that
+ defined for the process using the JOB command.
+
+3 IMAGE
+ IM[AGE]=strlit
+
+ The string literal specifies the file-specification of the image for
+ the resultant job to activate.
+
+ GT.M does not supply a default file type. Image files generally have a
+ .EXE extension. A JOB command requires a GT.M image that has been
+ linked under a compatible version of GT.M.
+
+ The maximum string length is 255 characters.
+
+ By default, JOB provides the executing current image.
+
+3 INPUT
+ IN[PUT]=strlit
+
+ The string literal specifies a value for the logical name SYS$INPUT.
+
+ GT.M does not supply a default file type. Input files generally have a
+ .COM extension.
+
+ The maximum string length is 255 characters.
+
+ By default, the job takes its input from the null device.
+
+3 LOGFILE
+ LOG[FILE]=strlit
+
+ The string literal specifies the log file for all I/O operations not
+ handled by INPUT, OUTPUT and ERROR.
+
+ GT.M does not supply a default file type. Log files generally have a
+ .LOG extension. The log file is analogous to the log file generated by
+ a batch job.
+
+ The maximum string length is 255 characters.
+
+ By default, the job sends the log to the null device.
+
+3 OUTPUT
+ OUT[PUT]=strlit
+
+ The string literal specifies a value for the logical name SYS$OUTPUT.
+
+ The maximum string length is 255 characters.
+
+ By default, JOB constructs the output file-specification from the
+ ROUTINENAME using a file extension of .MJO and the current default
+ directory of the process created by the JOB command.
+
+3 PRIORITY
+ PRI[ORITY]=intlit
+
+ The integer literal specifies the base priority at which the resultant
+ job executes.
+
+ For the JOB command to raise the PRIORITY of the resultant process
+ above the PRIORITY of the parent process, the parent process must have
+ the ALTPRI privilege.
+
+ The lowest priority is one (1). The highest priority is 31.
+
+ By default, the job has the current priority of the parent process.
+
+3 PROCESS_NAME
+ PRO[CESS_NAME]=strlit
+
+ The string literal specifies the VMS process name for the resultant
+ job. If PROCESS attempts to assign a name that is currently in use by
+ another process of the same GROUP, GT.M suspends the JOB command until
+ the other process stops, or a timeout occurs for the JOB command.
+
+ The maximum string length is 15 alphanumeric characters.
+
+ By default, JOB constructs a name in the form <USER>_<PID>J<cnt>, where
+ <USER> is the username for the parent process truncated to three or
+ four characters, <PID> is the process identification of that process
+ and <cnt> is a decimal number from one (1) to 99. If the process name
+ is longer than 15 characters, GT.M truncates the rightmost characters
+ of the user name. For example, if a process with the user name
+ MacDonald and a PID of hexadecimal 21802227 issues its first JOB
+ command, GT.M assigns the name MACD_21802227J1 to the new process.
+
+3 SCHEDULE
+ SCH[EDULE]=strlit
+
+ The string literal specifies the absolute or delta time when the
+ resultant process should begin running. The process hibernates until
+ that time. The date and time are separated by a space (not a colon).
+
+ By default, GT.M starts the job immediately.
+
+3 STARTUP
+ STA[RTUP]=strlit
+
+ The string literal specifies a command file that the resultant job
+ executes before executing the GT.M routine. The command line may invoke
+ a DCL script or other images.
+
+ If the file-specification for the startup file does not include a
+ directory name, GT.M searches for the file in the current default
+ directory. GT.M does not supply a default file type. If the JOB command
+ does not specify a startup file, VMS executes only the "normal" command
+ procedures.
+
+3 SWAPPING
+ [NO]SWA[PPING]
+
+ Enables or disables swapping of the resultant job in and out of
+ physical memory when the job is in a wait state.
+
+ For the JOB command to disable swapping of the resultant process, the
+ process issuing the JOB must have the PSWAPM privilege.
+
+ By default, JOB enables SWAPPING.
+
+2 Ex_of_JOB
+ Examples of JOB
+
+ Example:
+
+
+ GTM>JOB ^TEST
+
+ This creates a detached job that starts doing the routine ^TEST in the
+ image TEST1.EXE in the current default directory. If ^TEST is not in
+ the image TEST1 (or in the default image, if there were no IMAGE
+ processparameter), GT.M attempts to auto-ZLINK the routine based on
+ $ZROUTINES. GT.M initializes $ZROUTINES to the translation of the
+ logical name GTM$ROUTINES, typically as defined in the login file
+ (SYS$MANAGER:SYLOGIN.COM or SYS$LOGIN:LOGIN.COM) of the account.
+
+ Example:
+
+
+ JOB PRINTLABELS(TYPE,PRNTR,WAITIM):(IMAGE="BACKGRND")
+
+ This passes three values (TYPE, PRNTR, and WAITIM) to the new job,
+ which starts at the label PRINTLABELS of the current routine.
+
+ Example:
+
+
+ SET j=prog_":(STARTUP="""_setup_""":PROCESS_NAME="""
+
+_pname_""")"
+ JOB @(j_":30") ELSE WRITE !,"Print Daemon Already Started"
+
+ This JOB command uses indirection to handle variable job parameters.
+ The new DETACHED process uses the same image as the process issuing the
+ command. It executes the command procedure specified by the
+ file-specification in the variable setup and uses the process name
+ specified in the variable pname. The timeout of 30 seconds deals with
+ the case where a job with the same name already exists for the VMS
+ group of the user issuing the JOB.
+
+1 KILL
+ Kill
+
+ The KILL command deletes local or global variables and their descendant
+ nodes.
+
+ The format of the KILL command is:
+
+
+ K[ILL][:tvexpr] [glvn|[(]lvn[,...][)][,...]]
+
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o The optional global or local variable name specifies the variable
+ to delete; KILL deletes not only the variable specified in the
+ argument, but also all variables descended from that variable, that
+ is, those starting with the identical key-prefix.
+
+ o KILLing a variable that does not currently exist has no effect.
+
+ o The KILL command without an argument deletes all currently existing
+ local variables; in this case, at least two (2) spaces must follow
+ the KILL to separate it from the next command on the line.
+
+ o When a KILL argument is enclosed in parentheses, that "exclusive"
+ KILL deletes all local variables except those listed in the
+ argument.
+
+ o An indirection operator and an expression atom evaluating to a list
+ of one or more KILL arguments
+ o form a legal argument for a KILL.
+
+ KILL does not affect copies of local variables that have been "stacked"
+ by NEW or parameter passing.
+
+ Because a KILL can have a major impact, use KILL with caution.
+
+2 Ex_of_Kill
+ Examples of KILL
+
+ Example:
+
+
+ GTM>KILL SET a=0,a(1)=1,a(1,1)="under" KILL a(1) ZWR
+
+ a=0
+
+ GTM>
+
+ This uses an argumentless KILL to get a "fresh start" by deleting all
+ existing local variables. After SETting a, a(1), and a(1,1), the KILL
+ deletes a(1) and its descendants. The ZWRITE shows only a remaining.
+
+ Example:
+
+
+ GTM>KILL (a,b),^AB(a,b)
+
+ The first argument (an exclusive KILL) specifies to KILL all local
+ variables except a and b. The second argument deletes ^AB(a,b) and any
+ descendants of that global variable node.
+
+1 LOCK
+ Lock
+
+ The LOCK command is used to reserve and release resource names,
+ providing a semaphore capability for GT.M processes. This capability
+ can be used for interprocess synchronization and signaling.
+
+ Assigning a LOCK does not specify any explicit control over variables
+ and does not directly effect either read or write access to global (or
+ local) data. However, an application that adheres to clearly defined
+ conventions of LOCKing before any access can indirectly achieve such an
+ effect.
+
+ The format of the LOCK command is:
+
+
+ L[OCK][:tvexpr] [[-|+]nref|(nref[,...])[:numexpr]
+
+ [,...]]
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o The nref argument specifies a resource name in the format of the
+ GT.M name, with or without subscripts and with or without a
+ preceding caret (^). An nref can optionally have an environment
+ specification, including one without a preceding caret (^).
+
+ o Outside of transactions, only one process in an environment can own
+ a particular LOCK at any given time.
+
+ o Because the data storage in GT.M uses hierarchical sparse arrays,
+ and LOCK frequently serves to protect that data from inappropriate
+ "simultaneous" access by multiple processes, LOCK treats resource
+ names in a hierarchical fashion; a LOCK protects not only the named
+ resource, but also its ancestors and descendants.
+
+ o When one or more nrefs are enclosed in parentheses (), LOCK
+ reserves all the enclosed names "simultaneously," that is, it
+ reserves none of them until all become available.
+
+ o A LOCK with no argument or an argument with no leading sign
+ releases all names currently reserved with previous LOCK commands
+ by the process; when a LOCK has no argument, at least two (2)
+ spaces must follow the LOCK to separate it from the next command on
+ the line.
+
+ o A LOCK argument with a leading plus sign (+) acquires the named
+ resources without releasing currently held resources; if the named
+ resource is already LOCKed, such a LOCK "counts up" the process
+ interest in the resource.
+
+ o A LOCK argument with a leading minus sign (-) "counts down" the
+ process interest in a named resource; if the count on a particular
+ lock reaches zero (0), GT.M releases the lock without releasing any
+ other currently held locks; a LOCK that releases a named resource
+ not currently owned by the process has no effect.
+
+ o The optional numeric expression specifies a time in seconds after
+ which the command should timeout if unsuccessful; 0 provides a
+ single attempt.
+
+ o An indirection operator and an expression atom evaluating to a list
+ of one or more LOCK arguments form a legal argument for a LOCK.
+
+ GT.M records LOCK and ZALLOCATE information in the "lock database."
+ GT.M distributes the lock database in space associated with the
+ database identified by the current Global Directory. However, the lock
+ database does not overlap or coincide with the body of the database
+ files holding the global data. Only the LOCK, ZALLOCATE and ZDEALLOCATE
+ commands, and the LKE utility program access the lock database.
+
+ GT.M maps reservations of names starting with ^ to the database file
+ used to map global variables of the same name. If the Global Directory
+ maps the name A to file A.DAT, GT.M maps all reservations on ^A to file
+ space associated with A.DAT.
+
+ GT.M maps reservations on names not starting with ^ to the region of
+ the database specified with the GDE command LOCK /REGION=. By default,
+ when GDE creates a Global Directory any reservations of local names are
+ mapped to the region $DEFAULT.
+
+ These two factors effect the following result in the programming
+ environment:
+
+ o ^ reservations automatically intersect for all users of the same
+ data in any database file independent of the Global Directory
+ mapping that file.
+
+ o reservations without a leading ^ intersect in an arbitrary pattern
+ dependent on the Global Directory and therefore controlled by a
+ design decision made independently of application code design.
+
+ Since GT.M uses resource names as semaphores for signaling among
+ multiple processes in a database environment, they interlock in a tree
+ structured fashion. When LOCK or ZALLOCATE reserves a subscripted
+ resource name such as ^D(1), other users of the database mapped by the
+ LOCKing (or ZALLOCATEing) process cannot reserve ancestors of that
+ name, such as ^D, or descendants, such as ^D(1,2), until LOCK or
+ ZDEALLOCATE releases that name.
+
+ Execution of the LOCK command does not affect the value or the state of
+ a variable. LOCK tests each argument to determine whether the process
+ can claim the name space. If another GT.M process has a LOCK on that
+ name space, GT.M suspends the current process until the other process
+ releases the name space. To prevent the potential "infinite" suspension
+ of a routine execution, specify a timeout for the LOCK command.
+
+ LOCK with a leading plus (+) or minus (-) sign (incremental LOCKing)
+ allows the acquisition of locks without releasing currently held locks.
+ This can lead to deadlocks.
+
+ To avoid deadlocks, use LOCK without a leading + or - sign on its
+ arguments because such a command releases all previously LOCKed
+ resources; or use a timeout with the LOCK command.
+
+ If a LOCK command specifies a timeout, and GT.M acquires ownership of
+ the named resource before the timeout elapses, LOCK
+ sets $TEST to TRUE (1). If GT.M cannot acquire ownership of the named
+ resource within the specified timeout, LOCK sets $TEST to FALSE (0). If
+ a LOCK command does not specify a timeout, the execution of the command
+ does not affect $TEST. If a LOCK with an argument having a leading
+ minus sign (-) specifies a timeout, the command always sets $TEST to
+ TRUE (1).
+
+ If a process issues a LOCK command for a named resource already
+ ZALLOCATEd by that process, the resource is both ZALLOCATEd and LOCKed.
+ LOCK does not release ZALLOCATEd resources. To release such a named
+ resource, the process must both ZDEALLOCATE and unLOCK the resource.
+ For more information on ZALLOCATE, refer to the "ZALLOCATE".
+
+2 Locks_within_Trans
+ Using Locks within Transactions
+
+ Within transactions LOCKs are used by GT.M to ensure the ability to
+ serialize. There is no guarantee, however, that attempts by other
+ processes to examine LOCKs held with a transaction will produce the
+ same results as when LOCKs are outside of a transaction. In other
+ words, LOCKs within transactions should never be used as simple
+ semaphores.
+
+ The LOCK command locks a specified resource name that controls a tree
+ structured name space. Outside of transactions when one process in an
+ environment acquires a LOCK or a ZALLOCATE on a named resource, no
+ other GT.M process in that environment can LOCK a resource with an
+ "overlapping" name until the first process releases the LOCK that it
+ holds.
+
+2 Ex_of_Lock
+ Examples of LOCK
+
+ Example:
+
+
+ LOCK A,^B, at C
+
+ LOCK (A,B, at C)
+
+ The first LOCK command LOCKs A and unLOCKs A before LOCKing ^B, then
+ unLOCKs ^B before locking the name specified by the variable C. The
+ second LOCK command acquires all three resources at once. GT.M waits
+ until all the named resources in the argument list become available
+ before LOCKing all the resources. For example, if the resource
+ specified by the variable C is not available for LOCKing, GT.M waits
+ until that resource becomes available before LOCKing A and ^B.
+
+ Example:
+
+
+ LOCK (A,B)
+
+ LOCK +C
+
+ LOCK -B
+
+ This LOCKs A and B, then incrementally LOCKs C. Finally it releases the
+ LOCK on B, while retaining the LOCKs on A and C.
+
+ Example:
+
+
+ LOCK (A,B,C)
+
+ LOCK +(B,C)
+
+ LOCK -(B)
+
+ This LOCKs A, B and C together. It then increments the lock "counts" of
+ B and C. The last LOCK command removes one "count" of B, leaving one
+ count of A and B and two counts of C.
+
+ Example:
+
+
+ LOCK ^D:5
+
+ This command attempts to LOCK ^D with a timeout of five seconds. If
+ LOCK acquires the named resource before the timeout elapses, GT.M sets
+ $TEST to 1 (TRUE). If LOCK fails to acquire the named resource before
+ the timeout elapses, GT.M sets $TEST to 0 (FALSE).
+
+1 MERGE
+ Merge
+
+ The MERGE command copies a variable and all its descendants into
+ another variable. MERGE does not delete the destination variable, nor
+ any of its descendants.
+
+ The format of MERGE command is:
+
+
+ M[ERGE][:tvexpr] glvn1=glvn2[,...]
+
+ o The optional truth-valued expression immediately following the
+ command is a command post conditional that controls whether or not
+ GT.M executes the command.
+
+ o When both glvn1 and glvn2 are local variables, the naked indicator
+ is not changed.
+
+ o If glvn2 is a global variable and glvn1 is a local variable, then
+ the naked indicator references glvn2.
+
+ o When both are global variables, the state of the naked indicator is
+ unchanged if glvn2 is undefined ($DATA(glvn2)=0).
+
+ o In all other cases including $DATA(glvn2)=10, the naked indicator
+ takes the same value that it would have if the SET command replaced
+ the MERGE command and glvn2 had a value.
+
+ o If glvn1 is a descendant of glvn2, or if glvn2 is a descendant of
+ glvn1; GT.M generates an error.
+
+ o An indirection operator and an expression atom evaluating to a list
+ of one or more MERGE arguments form a legal argument for a MERGE.
+
+ MERGE simplifies the copying of a sub-tree of a local or global
+ variable to another local or global variable. A sub-tree is all global
+ or local variables that are descendants of an specified variable. MERGE
+ offers a one-command alternative to the current technique for doing
+ sub-tree copy (that is, a series of SET commands with $ORDER
+ references).
+
+ GT.M may permit certain syntax or actions that are described by the
+ standard as in error. For example, a MERGE command that specifies
+ an operation where the source and destination overlap but
+ $DATA(source)=0 does not produce an error (which is equivalent to a
+ no-operation).
+
+2 Ex_of_Merge
+ Examples of MERGE
+
+ Example:
+
+
+ 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
+
+ ^gbl1="one"
+
+ ^gbl1(1)="gbl2_2"
+
+ ^gbl1(1,1)="oneone"
+
+ ^gbl1(1,1,3)="gbl2_2_1_3"
+
+ ^gbl1(1,1,4,5)="gbl2_2_1_4_5"
+
+ ^gbl1(1,2,4)="onetwofour"
+
+ GTM>ZWRITE ^gbl2
+
+ ^gbl2(2)="gbl2_2"
+
+ ^gbl2(2,1,3)="gbl2_2_1_3"
+
+ ^gbl2(2,1,4,5)="gbl2_2_1_4_5"
+
+ GTM>
+
+ The example illustrates how MERGE copies a sub-tree of one global into
+ another. The nodes in the sub-tree of ^gbl(2), for which $DATA() value
+ is 1 or 11, are copied to sub-tree of ^gbl1(1) as follows:
+
+ ^gbl1(1) is updated with value of ^gbl2(2)
+
+ ^gbl1(1,1,3) is updated with value of ^gbl2(2,1,3)
+
+ ^gbl1(1,1,4,5) is updated with value of ^gbl2(2,1,4,5)
+
+ Since ^gbl1(2,1) and ^gbl2(2,2,4) do not have values ($DATA()=0), the
+ corresponding nodes ^gbl1(1,1) and ^gbl(1,2,4) respectively are left
+ unchanged. The naked indicator takes the value ^gbl(1) as if SET
+ replaced MERGE. Notice that the MERGE command does not change ^gbl2(2)
+ or its descendants. Ancestor nodes of ^gbl(1) are also left unchanged.
+
+ Example:
+
+
+ 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
+
+ GTM>ZWRITE lcl
+
+ lcl(3,4,2)="1,2"
+
+ GTM>
+
+ The example illustrates how MERGE creates a sub-tree of a variable when
+ the variable does not exist. Also, notice how the naked indicator is
+ set when the source of the MERGE is a global and the destination a
+ local.
+
+1 NEW
+ New
+
+ The NEW command "stacks" copies of local variables and reinitializes
+ the variables. An explicit or implicit QUIT from a DO, XECUTE or
+ extrinsic function "unstacks" the NEWed variables, that is, restores
+ the variable to the stacked value. A NEW lasts only for the current
+ scope of execution.
+
+ The format of the NEW command is:
+
+
+ N[EW][:tvexpr] [[(]lvn[,...][)][,...]]
+
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o NEW arguments are unsubscripted local variable names; NEW affects
+ not only the variable specified in the argument, but also all
+ variables descended from that variable.
+
+ o When an undefined variable is NEWed, the fact that it is undefined
+ is "stacked", and when leaving the current scope, it returns to
+ being undefined, that is, the variable is KILLed.
+
+ o Without an argument GT.M NEWs all currently existing local
+ variables; in this case, at least two (2) spaces must follow the
+ NEW to separate it from the next command on the line.
+
+ o When a NEW argument is enclosed in parentheses, that NEW is
+ considered "exclusive" and the variables inside the parentheses are
+ excluded from the effect of the NEW.
+
+ o When the flow of execution leaves the scope of an argumentless or
+ an exclusive NEW, GT.M restores all stacked variables to their
+ previous values, and deletes all other local variables.
+
+ o The intrinsic special variables $ESTACK, $ETRAP, $ZGBLDIR, and
+ $ZYERROR can be an explicit argument of a NEW.
+
+ o The intrinsic special variable $ZTRAP can also be an explicit
+ argument of a NEW; this stacks the current value of $ZTRAP and
+ assigns $ZTRAP a null value ($ZTRAP="").
+
+ o An indirection operator and an expression atom evaluating to a list
+ of one or more NEW arguments form a legal argument for a NEW.
+
+ The NEW command provides a means of confining the scope of local
+ variables. NEW operates only on unsubscripted local names and acts on
+ the entire named array.
+
+2 Ex_of_New
+ Examples of NEW
+
+ Example:
+
+
+ SET A(1)=1,B=4,C=5
+
+ WRITE !,"VARIABLES BEFORE NEW:",!
+
+ ZWRITE
+
+ DO LABEL
+
+ WRITE !,"VARIABLES AFTER RETURN:",!
+
+ ZWRITE
+
+ QUIT
+
+ LABEL NEW A SET C=7
+
+ WRITE !,"VARIABLES AFTER NEW:",!
+
+ ZWRITE
+
+ QUIT
+
+ Produces the results:
+
+
+ VARIABLES BEFORE NEW:
+
+ A(1)=1
+
+ B=4
+
+ C=5
+
+ VARIABLES AFTER NEW:
+
+ B=4
+
+ C=7
+
+ VARIABLES AFTER RETURN:
+
+ A(1)=1
+
+ B=4
+
+ C=7
+
+ Example:
+
+
+ SET (A,B,C,D)="TEST"
+
+ DO LABEL
+
+ WRITE !,"VARIABLES AFTER RETURN:",!
+
+ ZWRITE
+
+ QUIT
+
+ LABEL NEW (B,C) SET (A,B,Z)="NEW"
+
+ WRITE !,"VARIABLES AFTER EXCLUSIVE NEW:",!
+
+ ZWRITE
+
+ QUIT
+
+ Produces the results:
+
+
+ VARIABLES AFTER EXCLUSIVE NEW:
+
+ A="NEW"
+
+ B="NEW"
+
+ C="TEST"
+
+ Z="NEW"
+
+ VARIABLES AFTER RETURN:
+
+ A="TEST"
+
+ B="NEW"
+
+ C="TEST"
+
+ D="TEST"
+
+1 OPEN
+ Open
+
+ The OPEN command creates a connection between a GT.M process and a
+ device.
+
+ The format of the OPEN command is:
+
+
+ O[PEN][:tvexpr] expr[:[(keyword[=expr][:...])]
+
+ [:numexpr]][,...]
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o The required expression specifies the device to OPEN.
+
+ o The optional keywords specify deviceparameters that control device
+ behavior; some deviceparameters take arguments delimited by an
+ equal sign (=); if the argument only contains one deviceparameter,
+ the surrounding parentheses are optional.
+
+ o The optional numeric expression specifies a time in seconds after
+ which the command should timeout if unsuccessful; choosing 0
+ results in a single attempt to open the device.
+
+ o When an OPEN command specifying a timeout contains no
+ deviceparameters, double colons (::) separate the timeout numeric
+ expression from the device expression.
+
+ o An indirection operator and an expression atom evaluating to a list
+ of one or more OPEN arguments form a legal argument for an OPEN.
+
+1 QUIT
+ Quit
+
+ Except when a QUIT appears on a line after a FOR, the QUIT command
+ terminates execution of the current GT.M invocation stack level
+ initiated by a DO, XECUTE, extrinsic function or special variable, and
+ returns control to the next "lower" level. In this case, QUIT restores
+ any values stacked at the current level by NEWs or by parameter
+ passing. When a QUIT appears on the line following a FOR, it terminates
+ execution of the FOR.
+
+ The format of the QUIT command is:
+
+
+ Q[UIT][:tvexpr] [expr]
+
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o When a QUIT terminates an extrinsic function, it must have an
+ argument that supplies the value returned by the function; in all
+ other cases, QUIT must not have an argument and must be followed by
+ at least two (2) spaces to separate it from the next command on the
+ line.
+
+ o An indirection operator and an expression atom evaluating to a QUIT
+ argument form a legal argument for a QUIT.
+
+ The QUIT performs two similar, but different, functions depending on
+ its context. Because FORs do not add levels to the GT.M invocation
+ stack, QUITs inside FOR loops simply terminate the loop. QUITs that
+ terminate DOs, XECUTEs and extrinsics remove a GT.M invocation stack
+ level and therefore may adjust the local variable environment resulting
+ from previous NEWs or parameter passing. A QUIT from an extrinsic or a
+ frame created by an argumentless DO restores $TEST to its stacked
+ value.
+
+ Attempting to QUIT (implicitly or explicitly) from code invoked by a
+ DO, XECUTE or extrinsic after that code issued a TSTART not yet matched
+ by a TCOMMIT, produces an error.
+
+2 Ex_of_Quit
+ Examples of QUIT
+
+ Example:
+
+
+ DO A
+
+ QUIT
+
+ A WRITE !,"This is label A"
+
+ The explicit QUIT at the line preceding the label A prevents line A
+ from executing twice. The sub-routine at line A terminates with the
+ implicit QUIT at the end of the routine.
+
+ Example:
+
+
+ WRITE $$ESV
+
+ QUIT
+
+ ESV()
+
+ QUIT "value of this Extrinsic Special Variable"
+
+ Because the label ESV has an argument list (which is empty), GT.M can
+ only legally reach that label with a extrinsic invocation. The QUIT on
+ the second line prevents execution from erroneously "falling through"
+ to the line labelled ESV. Because ESV identifies a subroutine that
+ implements an extrinsic special variable, the QUIT on the line after
+ ESV has an argument to provide the value of the extrinsic.
+
+ Example:
+
+
+ SET x="" F S x=$O(^BAL(x)) Q:x]]"AR5999"!'$L(x) D STF
+
+ The postconditional QUIT terminates the FOR loop.
+
+1 READ
+ Read
+
+ The READ command transfers input from the current device to a global or
+ local variable specified as a READ argument. For convenience, READ also
+ accepts arguments that perform limited output to the current device.
+
+ The format of the READ command is:
+
+
+ R[EAD][:tvexpr] (glvn|*glvn|glvn#intexpr)[:numexpr]|strlit|fcc[,...]
+
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o A subscripted or unsubscripted global or local variable name
+ specifies a variable into which to store the input; the variable
+ does not have to exist prior to the READ; if the variable does
+ exist prior to the READ, the READ replaces its old value.
+
+ o When an asterisk (*) immediately precedes the variable name, READ
+ accepts one character of input and places the ASCII code for that
+ character into the variable.
+
+ o When a number-sign (#) and a non-zero integer expression
+ immediately follow the variable name, the integer expression
+ determines the maximum number of characters accepted as input to
+ the read; such reads terminate when GT.M reads the number of
+ characters specified by the integer expression or a terminator
+ character in the input stream, whichever occurs first.
+
+ o The optional numeric expression specifies a time in seconds at
+ most, for which the command waits for input to be terminated. When
+ a timeout is specified, if the input has been terminated before the
+ timeout expires, $TEST is set to 1 (true), otherwise, $TEST is set
+ to 0 (false).
+
+ o To provide a concise means of issuing prompts, GT.M sends string
+ literal and format control character (!,?intexpr,#) arguments of a
+ READ to the current device as if they were arguments of a WRITE.
+
+ o An indirection operator and an expression atom evaluating to a list
+ of one or more READ arguments form a legal argument for a READ.
+
+1 SET
+ Set
+
+ SET assigns values to variables or to a selected portion of a variable.
+
+ The format of the SET command is:
+
+
+ S[ET][:tvexpr] glvn|$EXTRACT()|$PIECE()|(glvn[,...])=expr[,...]
+
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o A subscripted or unsubscripted local or global variable name on the
+ left of the equal-sign (=) specifies a variable in which to store
+ the expression found on the right side of the equal-sign; the
+ variable need not exist prior to the SET; if the variable exists
+ prior to the SET, the SET replaces its old value.
+
+ o During a SET, GT.M evaluates the right side of the equal sign
+ before the left; this is an exception to the left-to-right order of
+ evaluation in GT.M and means that GT.M maintains the naked
+ indicator using the expression on the right-hand side of the equal
+ sign (=) before setting the variable.
+
+ o When the portion of the argument to the left of the equal-sign is
+ in the form of a list of variables enclosed in parentheses, SET
+ assigns the value of the expression on the right of the equal sign
+ to all the variables.
+
+ o When the portion of the argument to the left of the equal sign is
+ in the form of a $PIECE function, SET replaces the specified piece
+ or pieces of the variable (specified as the first argument to the
+ $PIECE() form) with the value of the expression on the right side
+ of the equal-sign; if the variable did not exist prior to the SET
+ or does not currently contain the pieces identified by the optional
+ third and fourth arguments to the $PIECE() form, SET adds
+ sufficient leading delimiters, as specified by the second argument
+ to the $PIECE form, to make the assignment fit the $PIECE() form.
+ Note that if the fourth argument exceeds the third argument, the
+ target glvn is not changed and the naked indicator is also not
+ modifed.
+
+ o When the portion of the argument to the left of the equal sign is
+ in the form of a $EXTRACT function, SET replaces the specified
+ character or characters of the variable (specified as the first
+ argument to the $EXTRACT() form) with the value of the expression
+ on the right side of the equal-sign; if the variable did not exist
+ prior to the SET or does not contain the characters identified by
+ the optional second and third arguments to the $EXTRACT() form, SET
+ adds sufficient leading spaces to make the assignment fit the
+ $EXTRACT() form. Note that if the third argument exceeds the second
+ argument, the target glvn is not changed and the naked indicator is
+ also not modifed.
+
+ o The left-hand side of the equal-sign may also contain any of the
+ following Intrinsic Special Variables:
+
+$ECODE
+$ETRAP
+$X
+$Y
+$ZCOMPILE
+$ZDIRECTORY
+$ZERROR
+$ZGBLDIR
+$ZINTERRUPT
+$ZMAXTPTIME
+$ZPROMPT
+$ZROUTINES
+$ZSOURCE
+$ZSTATUS
+$ZSTEP
+$ZTRAP
+$ZYERROR
+ o An indirection operator and an expression atom evaluating to a list
+ of one or more SET arguments form a legal argument for a SET.
+
+ Because GT.M does not require predeclaration or typing of variables, a
+ SET with proper syntax always succeeds regardless of the prior state or
+ value of the variable, as long as GT.M can evaluate the expression to
+ the right of the equal sign (=).
+
+2 Ex_of_Set
+ Examples of SET
+
+ Example:
+
+
+ GTM>KILL SET a="x",(b,c)=1, at a="hello" ZWRITE
+
+ a=x
+
+ b=1
+
+ c=1
+
+ x="hello"
+
+ GTM>
+
+ The KILL command deletes any previously defined local variables. The
+ SET command has three arguments. The first shows a simple direct
+ assignment. The second shows the form that assigns the same value to
+ multiple variables. The third shows atomic indirection on the left of
+ the equal sign. The ZWRITE command displays the results of the
+ assignments.
+
+ Example:
+
+
+ GTM>SET ^(3,4)=^X(1,2)
+
+ Because GT.M evaluates the right-hand side of the equal sign before the
+ left-hand side within a SET argument, the right-hand expression
+ determines the
+ naked reference indicator prior to evaluation of the left-hand side.
+ Therefore, this example assigns ^X(1,3,4) the value of ^X(1,2).
+
+ Example:
+
+
+ GTM>KILL x SET $P(x,"^",3)="piece 2" ZWRITE x
+
+ x="^^piece 2"
+
+ GTM>
+
+ This SET demonstrates a "setpiece" and shows how SET generates missing
+ delimiters when required.
+
+ Example:
+
+
+ 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>
+
+ The SET $EXTRACT command replaces and extracts the specified characters
+ with the value of the expression on the right hand side of the
+ equal-sign (=).
+
+1 TCOMMIT
+ TCommit
+
+ The TCOMMIT command marks the end of a transaction or sub-transaction
+ and decrements $TLEVEL. If TCOMMIT marks the end of a transaction
+ (decrements $TLEVEL to zero), it invokes a COMMIT, which makes the
+ database updates performed by the transaction generally available. A
+ TCOMMIT issued when no transaction is in progress ($TLEVEL=0) produces
+ an error.
+
+ The format of the TCOMMIT command is:
+
+
+ TC[OMMIT][:tvexpr]
+
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o Because TCOMMIT has no argument, at least two (2) spaces must
+ follow the command to separate it from the next command on the
+ line.
+
+ For an example of the use of the TCOMMIT command, refer to the chapter
+ on General Language Features of M in GT.M Programmer's Guide.
+
+1 TRESTART
+ TREstart
+
+ The TRESTART command attempts to RESTART the current transaction. A
+ RESTART transfers control back to the initial TSTART and restores much
+ of the process state to what it was when that TSTART was executed.
+ Errors are produced if a TRESTART is used when no transaction is in
+ progress ($TLEVEL=0) and when the transaction does not have RESTART
+ enabled.
+
+ The format for the TRESTART command is:
+
+
+ TRE[START][:tvexpr]
+
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o Because TRESTART has no argument, at least two (2) spaces must
+ follow the command to separate it from the next command on the
+ line.
+
+ TRESTARTs (and implicit RESTARTs) do not restore any device states;
+ they do restore the following to the state they had when GT.M executed
+ the initial TSTART:
+
+ o $TEST
+
+ o The naked indicator
+
+ o LOCKs held by the process
+
+ They also restore any local variables named by one or more active
+ TSTARTs to the values they had when they were first named.
+
+ For an example of the use of the TRESTART command, refer to the chapter
+ on "General Language Features of M" in the GT.M Programmer's Guide.
+
+1 TROLLBACK
+ TROllback
+
+ The TROLLBACK command terminates a transaction by causing a ROLLBACK,
+ which removes all database updates performed within a transaction.
+ TROLLBACK also sets $TLEVEL and $TRESTART to zero (0). Issuing a
+ TROLLBACK when no transaction is in progress ($TLEVEL=0) produces an
+ error.
+
+ The format of the TROLLBACK command is:
+
+
+ TRO[LLBACK][:tvexpr] [intexpr]
+
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o The optional integer expression indicates an argument specifying
+ incremental rollback. If the value of the argument expression is
+ greater than zero, it specifies the value of $TLEVEL to be achieved
+ by the rollback. If the value of the expression is less than zero,
+ the result is the number of levels to rollback. For example; -1
+ means rollback one level. If the argument expression is zero, the
+ effect is same as not specifying the argument, that is, the entire
+ GT.M transaction is rolled back.
+
+ Attempting to rollback more than $TLEVEL levels (the outermost
+ transaction) generates an error.
+
+ o When the TROLLBACK has no argument, at least two (2) spaces must
+ follow the command to separate it from the next command on the
+ line.
+
+ In order to allow for error recovery and/or access to the global
+ context of the error, errors do not initiate implicit ROLLBACKs.
+ Therefore, the code for handling errors during transactions should
+ generally include a TROLLBACK. Because the TROLLBACK releases resources
+ held by the transaction, it should appear as early as possible in the
+ error handling code.
+
+ A TROLLBACK does not cause a transfer of control but is typically
+ associated with one such as a QUIT or GOTO.
+
+ For an example of the use of the TROLLBACK command, refer to the
+ chapter on "General Language Features of M" in the GT.M Programmer's
+ Guide.
+
+1 TSTART
+ TStart
+
+ A TSTART command marks the beginning of a transaction or
+ sub-transaction and increments $TLEVEL. When TSTART marks the beginning
+ of a transaction ($TLEVEL=1), its arguments determine whether the
+ transaction may RESTART and whether serializability is enforced. If a
+ transaction may RESTART, the TSTART arguments determine which local
+ variables are restored during a RESTART. Serializability is enforced by
+ LOCK commands or, if the SERIAL keyword is specified, by GT.M.
+
+ The format of the TSTART command is:
+
+
+ TS[TART][:tvexpr] [([lvn...])|lvn|*|][:keyword|(keyword...)]
+
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o If $TLEVEL is 0 before the TSTART, the TSTART starts a transaction;
+ otherwise it starts a sub-transaction.
+
+ o If the TSTART initiates a transaction and the portion of the
+ argument before the colon (:) delimiter is empty, the transaction
+ is not eligible for RESTART. If the TSTART starts a transaction
+ ($TLEVEL=0) and the portion of the argument before the colon is not
+ empty, the transaction is eligible for RESTART. If the TSTART is
+ nested (starts a sub-transaction), its arguments have no effect on
+ whether the transaction is eligible for RESTART.
+
+ o If the portion of the argument before the colon is an asterisk (*),
+ any subsequent RESTART restores all local variables to the value
+ they had when the TSTART was executed.
+
+ o If the portion of the argument before the colon is an unsubscripted
+ local variable name or a list of such names enclosed in
+ parentheses, a RESTART restores the named variables to the value
+ they had when the TSTART was executed.
+
+ o If the portion of the argument before the colon is a set of empty
+ parentheses (), a RESTART does not restore any local variables.
+
+ o The optional portion of the argument after the colon is a keyword
+ or a colon-separated list of keywords enclosed in parentheses,
+ where the keywords specify transaction characteristics.
+
+ o An indirection operator and an expression atom evaluating to a
+ TSTART argument form a legal argument for a TSTART.
+
+ A TSTART within a transaction starts a sub-transaction. The argument to
+ such a TSTART has no effect on whether the existing transaction may
+ RESTART or whether serializability of the transaction is enforced. This
+ type of TSTART may add local variables to be restored in a transaction
+ that has RESTART enabled.
+
+ It is good coding practice to synchronize enabling of RESTART on
+ TSTARTs at all levels of a transaction. A nested TSTART that does not
+ permit RESTART where the transaction does, may indicate that the
+ sub-transaction has not been coded to properly handle RESTART.
+
+ Sub-transactions cannot COMMIT independently from the transaction, nor
+ can they RESTART independently. Sub-transactions exist largely as a
+ programming convenience to allow flexibility in organizing code in a
+ modular fashion, and in addition to allow incremental ROLLBACKs.
+
+ When journaling, a transaction with an initial TSTART that has an
+ argument specifying TRANSACTIONID=expr, where expr is an expression
+ that evaluates to the keyword (case insensitive) BA[TCH], does not wait
+ for the journal update to be written before returning control to the
+ application after a successful TCOMMIT. The goal of this feature is to
+ permit application control over any performance impact of journaling on
+ any subset of transactions that can be recreated or recovered by means
+ other than journaling.
+
+ For an example of the use of the TSTART command, refer to the chapter
+ on "General Language Features of M" in the GT.M Programmer's Guide.
+
+ The following keywords may appear in a TSTART argument:
+
+2 SERIAL
+ S[ERIAL]
+
+ The SERIAL keyword indicates that GT.M must ensure the serializability
+ of the transaction. When the SERIAL keyword is absent, the GT.M program
+ must ensure serializability by proper use of LOCK commands. On a nested
+ TSTART, this portion of the argument is ignored.
+
+2 TRANSACTIONID
+ T[RANSACTIONID]=expr
+
+ The TRANSACTIONID keyword declares an arbitrary transaction
+ identification.
+
+ If TRANSACTIONID="BATCH" or "BA" at transaction completion, the process
+ immediately continues execution. When a process issues a [final]
+ TCOMMIT for a transaction and journaling is active, by default the
+ process waits until the entire transaction is written to the journal
+ file(s) before executing the next command. This ensures that every
+ transaction is durable before the process moves on to the next step.
+
+ Transactions flagged as "BATCH" have lower latency and higher
+ throughput, but a lower guarantee of durability. Normally this flag is
+ used when operational procedures (such as a backup) or application code
+ (such as a checkpoint algorithm) provides an acceptable alternative
+ means of ensuring durability.
+
+1 USE
+ Use
+
+ The USE command selects the current device for READs (input) and WRITEs
+ (output).
+
+ The format of the USE command is:
+
+
+ U[SE][:tvexpr] expr[:(keyword[=expr][:...])][,...]
+
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o The required expression specifies the device to make the current
+ device.
+
+ o A USE that selects a device not currently OPENed by the process
+ causes a run-time error.
+
+ o The optional keywords specify deviceparameters that control device
+ behavior; some deviceparameters take arguments delimited by an
+ equal sign (=); if the argument only contains one deviceparameter,
+ the surrounding parentheses are optional.
+
+ o An indirection operator and an expression atom evaluating to a list
+ of one or more USE arguments form a legal argument for a USE.
+
+ For more information on USE, devices and deviceparameters, refer to the
+ "Input/Output Processing" chapter in the GT.M Programmer's Guide.
+
+1 VIEW
+ View
+
+ The VIEW command adjusts an environmental factor selected by a keyword
+ argument. For example, VIEW controls journal buffer flushing,
+ determines whether GT.M reports undefined variables as errors or treats
+ them as null, and determines which BREAK commands should display
+ messages.
+
+ The format of the VIEW command is:
+
+
+ V[IEW][:tvexpr] keyword[:expr2[:...]][,...]
+
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o The keyword specifies the environmental factor to change.
+
+ o The optional expression following the keyword specifies the nature
+ of the change to the environmental factor.
+
+ o An indirection operator and an expression atom evaluating to a list
+ of one or more VIEW arguments form a legal argument for a VIEW
+
+2 Key_Words_View
+ Key Words in VIEW Command
+
+ The following sections describe the keywords available for the VIEW
+ command in GT.M.
+
+3 BREAKMSG
+ "BREAKMSG":value
+
+
+ Sets the value of the BREAK message mask. When GT.M processes a BREAK
+ command, the BREAK message mask controls whether to display a message
+ describing the source of the BREAK.
+
+ The mask uses the following four values that are added together to
+ provide the BREAKMSG value.
+
+ 1 - BREAKs within the body of a program
+ 2 - BREAKs within a ZBREAK action
+ 4 - BREAKs within a device EXCEPTION
+ 8 - BREAKs within a ZSTEP action
+ By default GT.M displays all BREAK messages. LINKing a GT.M image with
+ a modified GTM$DEFAULTS alters the default for that image.
+
+ Example:
+
+ GTM>VIEW "BREAKMSG":5
+
+ In this example the BREAKMSG value is 5, representing the sum of 1 and
+ 4. This enables BREAKS within the body of a program (value 1) and for a
+ device EXCEPTION (value 4).
+
+3 GDSCERT
+ "GDSCERT":value
+
+
+ Enables (value=1) or disables (value=0) database block certification.
+
+ Database block certification causes GT.M to check the internal
+ integrity of every block as it writes the block. Block certification
+ degrades performance and exists primarily as a tool for use by Sanchez.
+ The default is GDSCERT:0.
+
+3 JNLFLUSH
+ "JNLFLUSH"[:region]
+
+
+ Writes or flushes journaling buffers associated with the given region
+ to permanent storage, for example, to disk. If the VIEW "JNLFLUSH" does
+ not specify the optional region, GT.M flushes all active regions of the
+ current Global Directory.
+
+ Normally GT.M writes journal buffers when it fills the journal buffer
+ pool or when some period of time passes with no journal activity.
+
+ For more information on journaling, refer to the "GT.M Journaling"
+ chapter in the GT.M Administration and Operations Guide.
+
+3 JNLWAIT
+ "JNLWAIT"
+
+
+ Causes a process to pause until its journaling buffers have been
+ written. JNLWAIT ensures that GT.M successfully transfers all database
+ updates issued by the process to the journal file before the process
+ continues. Normally, GT.M performs journal buffer writes asynchronously
+ while the process continues execution.
+
+ For more information on journaling, refer to the "GT.M Journaling"
+ chapter in the GT.M Administration and Operations Guide.
+
+3 JOBPID
+ "JOBPID":"value"
+
+
+ Enables (value=1) or disables (value=0) the addition of the child
+ process ID to the output and error filenames generated by the JOB
+ command.
+
+ This option prevents output files generated by the JOB command from
+ being overwritten each time a new job is spawned from the GT.M source
+ file.
+
+3 LABELS
+ "LABELS":"value"
+
+
+ Enables (value="LOWER") or disables (value="UPPER") case sensitivity
+ for labels within routines.
+
+ It is important to have the same case handling at compile-time and
+ run-time.
+
+ Because GT.M stores routines in RMS files and RMS does not support
+ lower-case file names, GT.M always treats routine names as upper-case.
+
+ By default, GT.M handles labels as case sensitive. LINKing a GT.M image
+ with a modified GTM$DEFAULTS alters the default for that image.
+
+3 LVNULLSUBS
+ "[NO]LVNULLSUBS"
+
+
+ Allows or disallows local arrays to have null subscripts. The default
+ is LVNULLSUBS. LINKing a GT.M image with a modified GTM$DEFAULTS alters
+ the default for that image.
+
+3 NOISOLATION
+ "NOISOLATION":<expr>
+
+
+ where expr must evaluate to one of the following forms
+
+ o "", that is, empty string : turn off the feature for all globals
+ for which it has previously been turned on
+
+ o "^gvn1,^gvn2,..." : turn on the feature for the globals in the
+ list, turning it off for globals for which it has previously been
+ turned on
+
+ o "+^gvn1,^gvn2,..." : add these globals to the list of globals that
+ have this feature turned on
+
+ o "-^gvn1,^gvn2,..." : turn off the feature for these globals leaving
+ the status for other globals unchanged
+
+ GT.M transaction processing permits the application to specify a set of
+ globals that do not require GT.M to preserve Isolation, one of the
+ "ACID" properties of TP. This shifts the responsibility for Isolation
+ from GT.M to the application logic, and permits GT.M to relax its TP
+ Isolation rules. This avoids TP restarts in certain cases thus
+ improving the performance of the application. For example, if a global
+ variable includes $JOB as a subscript, the application may be written
+ and scheduled in such a way that no more than one process uses a node
+ of that global at any given time. Specifying such a global as
+ "NOISOLATED" avoids transaction restarts that occur when different
+ processes concurrently update and access nodes that share the same GDS
+ block.
+
+ The rules for enforcement by GT.M of Isolation, and therefore
+ potentially Consistency, are relaxed for application-specified global
+ variables in order to allow the application to manage these properties.
+ GT.M is responsible for Atomicity and Durability, as well as for
+ database integrity for all variables, and for Isolation and Consistency
+ for any global variables for which the application does not accept
+ responsibility.
+
+ Note that if an application incorrectly specifies a global to be
+ NOISOLATED, severe, and possibly intermittent and difficult to diagnose
+ damage to application-level integrity is likely to result. A thorough
+ understanding of the application is necessary before declaring a global
+ to be noisolated. GT.M preserves database integrity (accessibility) for
+ NOISOLATED, as well as ISOLATED global variables.
+
+ GT.M ignores attempts to turn on (or off) the feature for globals that
+ already have the feature turned on (or off). It is an error to modify
+ the isolation-status of a global variable within a transaction across
+ different references (either reads or writes) of that global
+ variable.The VIEW command by itself is not considered to be a reference
+ of the global variable. While not recommended programming practice,
+ this means that a process can change a global's isolation-status within
+ a transaction as long as it hasn't referenced it yet.
+
+ Any reads on a NOISOLATION global are validated at the time of the read
+ and not re-validated at TCOMMIT time. This means that if the value that
+ was read changed after the read but before the TCOMMIT, the transaction
+ would still be committed. Therefore it is important that any reads on a
+ NOISOLATED global (if any) should be of data that does not change with
+ time. Sanchez has not identified applications where this could be an
+ issue.
+
+3 PATCODE
+ "PATCODE":"tablename"
+
+
+ Identifies the alternative table of unique patterns for use with the
+ "?" operator to be loaded from the pattern definition file. For
+ additional information refer to the "Internationalization" chapter in
+ the GT.M Programmer's Guide.
+
+3 PATLOAD
+ "PATLOAD":"file-specification"
+
+
+ Identifies the file containing definitions of unique patterns for use
+ with the "?" operator. These pattern definitions can be used in place
+ of, or in addition to, the standard C, N, U, L, and P.
+
+3 UNDEF
+ "[NO]UNDEF"
+
+
+ Enables or disables handling of undefined variables as errors. With
+ UNDEF, GT.M handles all references to undefined local or global
+ variables as errors. With NOUNDEF, GT.M handles all references to
+ undefined local or global variables as if the variable had a value of
+ the null string. In other words, GT.M treats all variables appearing in
+ expressions as if they were the argument of an implicit $GET(). UNDEF
+ is the default.
+
+3 TRACE
+ "TRACE":value<expr>
+
+
+ Traces GT.M program execution and generates profiling information about
+ the lines and functions executed; with low impact on the run-time
+ performance.
+
+ The feature turns on (value=1) or turns off (value=0) tracing. <expr>
+ must evaluate to a string containing the name of a GT.M global
+ variable. The global may also have subscripts; however the subscripts
+ must be literals or the special variable $JOB.
+
+ The <expr> is optional when turning tracing off, if it exists, it
+ overrides the global variable set when tracing was turned on.
+
+ GT.M-tracing uses a technique called Basic Block Counting where calls
+ are made to special profiling functions at key points in a GT.M
+ program. A trace consists of the following run-time data as output for
+ each GT.M function, as well as for each GT.M statement:
+
+ o The number of times it is executed.
+
+ o The total CPU time spent across all invocations for each function
+ and each GT.M statement as a single value.
+
+ Instead of modifying the generated code as done by common profiling
+ tools, such as gprof, GT.M tracing operates entirely within the GT.M
+ run-time system; therefore, this feature does not require a special
+ compilation, has no effect on code size and minimizes run-time
+ overhead.
+
+ When the feature is turned on, it gathers profiling information for
+ each line and GT.M function invocation. The reported time for a GT.M
+ line is the time spent in generated code for that line, and does not
+ include time spent in entreyrefs called from that line. When profiling
+ is turned off, the accumulated statistics are loaded into a GT.M
+ global. GT.M profiling accumulates and provides the data; the user may
+ choose tools and techniques to analyze the data.
+
+ The trace information is stored in the variable in the following
+ format:
+
+ o If <expr> is a global variable without subscripts name such as
+ "^foo", the trace information is stored in the nodes
+ ^foo(<routine>,<label>) and ^foo(<routine>,<label>,<offset>), each
+ of which has a value in the form "<count>:<time>" on VMS.
+
+ o If <expr> has a value such as "^foo("MYTRACE",$J)", the trace
+ information is stored in the nodes
+ ^foo("MYTRACE",<pid>,<routine>,<label>) and
+ ^foo("MYTRACE",<pid>,<routine>,<label>,<offset>), each of which has
+ a value in the form "<count>,<time>" on VMS as described above.
+
+ o For FOR loops, information for each level of the loop is stored in
+ the nodes as described above, with the extra subscipts "FOR_LOOP".
+ <for_level> is the value of the number of iterations at that level
+ of the FOR loop.
+
+ Thus, if the GT.M program lv1.m is:
+
+
+ lv1 f i=1:1:10 d
+
+ .s l(i)=i
+
+ .d bar
+
+ for i=1:1:5 for j=1:1:4 s lij(i,j)=i+j
+
+ q
+
+ bar s l(-i)=-i
+
+ q
+
+
+ And the program lv2.m is:
+
+ lv2 VIEW "TRACE":1:"^lvtr"
+
+ d ^lv1
+
+ VIEW "TRACE":0:"^lvtr"
+
+ zwr ^lvtr
+
+ q
+
+ On executing lv2, the output looks like this (times in the example were
+ chose for clarity of illustration and are not typical):
+
+
+ ^lvtr("lv1","bar")="10:8"
+
+ ^lvtr("lv1","bar",0)="10:5"
+
+ ^lvtr("lv1","bar",1)="10:3"
+
+ ^lvtr("lv1","lv1")="1:37"
+
+ ^lvtr("lv1","lv1",0)="1:8"
+
+ ^lvtr("lv1","lv1",0,"FOR_LOOP",1)=10
+
+ ^lvtr("lv1","lv1",1)="10:3"
+
+ ^lvtr("lv1","lv1",2)="10:19"
+
+ ^lvtr("lv1","lv1",3)="1:15"
+
+ ^lvtr("lv1","lv1",3,"FOR_LOOP",1)=5
+
+ ^lvtr("lv1","lv1",3,"FOR_LOOP",2)=20
+
+ ^lvtr("lv1","lv1",4)="1:0"
+
+ ^lvtr("lv2","lv2",1)="1:47"
+
+ In this case, ^lvtr("lv1","bar",0)="10:5" means that the statement bar
+ s l(-i)=-i was executed 10 times, with a total of 5 microseconds of
+ time. ^lvtr("lv1","lv1")="1:37" means that 37 microseconds of time was
+ spent within that GT.M frame (lv1^lv1), and does not include time spent
+ in routines called from it (such as bar^lv1), whereas
+ ^lvtr("lv1","lv1",3)= "1:15" includes the time spent at bar^lv1.
+
+ Note that there is no data in ^lvtr("lv2","lv2",0) or for
+ ^lvtr("lv2","lv2",2) because the execution of the lines containing the
+ VIEW commands that turn profiling on and off are not profiled.
+
+ Because of the underlying timers provided by the operating systems,
+ times of less than a microsecond are measured as zero. Therefore, even
+ if a statement executes one million times, it may report zero time if
+ it took less than a microsecond each time.
+
+ GT.M profiling cannot handle more than 1024 levels. If the GT.M code
+ executed has more than 1024 levels, frame information cannot be
+ recorded, and frame information upto the first point where this limit
+ is reached is reported with a note (":INCOMPLETE DATA: MAXTRACELEVEL" )
+ appended to the data.
+
+3 ZDIR_FORM
+ "ZDIR_FORM":"value"
+
+
+ Includes (value=0) or excludes (value=1) the device specification in
+ the special variable $ZDIRECTORY. By default, GT.M includes the device
+ specification in $ZDIRECTORY.
+
+ Note that the value of ZDIR_FORM does not affect the value to which
+ $ZDIRECTORY is SET. ZDIR_FORM only modifies the way $ZDIRECTORY is
+ presented. Regardless of the value of ZDIR_FORM, $ZDIRECTORY can be SET
+ to a path that may or may not include device specification.
+
+ LINKing a GT.M image with a modified GTM$DEFAULTS alters the default
+ for that image.
+
+2 Ex_of_View
+ Examples of VIEW
+
+ Example 1:
+
+
+ GTM>KILL A
+
+ GTM>VIEW "NOUNDEF"
+
+ GTM>WRITE A,?10,$L(A)
+
+ 0
+
+ GTM>
+
+ This demonstrates how a VIEW that specifies NOUNDEF prevents UNDEFined
+ errors.
+
+ Example 2:
+
+
+ GTM>ZL "NOSENSE"
+
+ %GTM-E-LABELMISSING Label referenced but
+
+ not defined:lab
+
+ %GTM-I-SRCNAM in source module USR.[WORK]NOSENSE.m
+
+ GTM>
+
+ GTM>ZPRINT ^NOSENSE
+
+
+ NOSENSE;
+
+ DO lab
+
+ QUIT
+
+ LAB WRITE !,"THIS IS NOSENSE"
+
+ QUIT
+
+
+ GTM>VIEW "LABELS":"UPPER"
+
+ GTM>ZLINK "NOSENSE.M"
+
+ GTM>DO ^NOSENSE
+
+ THIS IS NOSENSE
+
+ GTM>
+
+ This demonstrates use of VIEW "LABELS" to make label handling case
+ insensitive. Notice that the routine was ZLINKed with a type of .M to
+ force a recompile and ensure that the object code and the run-time
+ handling of labels is the same.
+
+ Example:
+
+
+ GTM>WRITE $ZDIR
+
+ USER:[WORK.TEMP]
+
+ GTM>VIEW "ZDIR_FORM":1
+
+ GTM>WRITE $ZDIR
+
+ [WORK.TEMP]
+ GTM>SET $ZDIR="OTHER:[DATA.JOURNAL]"
+
+ GTM>WRITE $ZDIR
+
+ [DATA.JOURNAL]
+ This example demonstrates use of VIEW "ZDIR_FORM" to exclude device
+ specification from $ZDIR.
+
+1 WRITE
+ Write
+
+ The WRITE command transfers a character stream specified by its
+ arguments to the current device.
+
+ The format of the WRITE command is:
+
+
+ W[RITE][:tvexpr] expr|*intexpr|fcc[,...]
+
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o An expression argument supplies the text of a WRITE.
+
+ o When a WRITE argument consists of a leading asterisk (*) followed
+ by an integer expression, WRITE outputs one ASCII character
+ associated with the ASCII code specified by the integer evaluation
+ of the expression.
+
+ o WRITE arguments may also be format control characters; format
+ control characters modify the position of a virtual cursor: an
+ exclamation point (!) produces a new line, a number-sign (#)
+ produces a new page and a question-mark (?) followed by an
+ expression moves the virtual cursor to the column specified by the
+ integer evaluation of the expression provided that the virtual
+ cursor is to the "left" of the specified column; if the virtual
+ cursor is not to the left of the specified column, then the text is
+ printed at the current cursor position.
+
+ o An indirection operator and an expression atom evaluating to a list
+ of one or more WRITE arguments form a legal argument for a WRITE.
+
+ For more information on WRITE, devices, input, output and format
+ control characters, refer to the "Input/Output Processing" chapter in
+ GT.M Programmer's Guide.
+
+1 XECUTE
+ Xecute
+
+ The XECUTE command makes an entry in the GT.M invocation stack and
+ executes the argument as GT.M code.
+
+ The format of the XECUTE command is:
+
+
+ X[ECUTE]:tvexpr expr[:tvexpr][,...]
+
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o The required expression specifies a fragment of GT.M source code.
+
+ o The optional truth-valued expression immediately following the
+ argument expression specifies the argument postconditional and
+ controls whether GT.M performs an XECUTE with that argument.
+
+ o An indirection operator and an expression atom evaluating to a list
+ of one or more XECUTE arguments form a legal argument for an
+ XECUTE.
+
+ An explicit or implicit QUIT within the scope of the XECUTE, but not
+ within the scope of any other DO, FOR, XECUTE or extrinsic, returns
+ execution to the instruction following the calling point. This may be
+ the next XECUTE argument or another command. At the end of the code
+ specified by the XECUTE argument expression, GT.M performs an implicit
+ QUIT.
+
+ Because XECUTE causes run-time compilation in GT.M, and because it
+ tends to obscure code, use XECUTE only when other approaches clearly do
+ not meet your particular requirement.
+
+2 Ex_of_Xecute
+ Examples of XECUTE
+
+ Example:
+
+
+ GTM>SET A="HELLO" XECUTE "WRITE A"
+
+ HELLO
+
+ GTM>
+
+ This demonstrates a simple use of XECUTE.
+
+ Example:
+
+
+ SET x="" F S x=$O(^%x(x)) Q:x="" X x
+
+ This $ORDER() loop XECUTEs code out of the first level of the global
+ array ^%x. Note that, in most cases, having the code in a GT.M source
+ file, for example TMPX.M, and using a DO ^TMPX improves efficiency.
+
+1 ZALLOCATE
+ ZAllocate
+
+ The ZALLOCATE command reserves the specified name without releasing
+ previously reserved names. Other GT.M processes cannot reserve the
+ ZALLOCATEd name with a ZALLOCATE or LOCK command.
+
+ The ZALLOCATE command provides compatibility with some other GT.M
+ implementations. The M Development Committee chose to add the + and -
+ delimiters to the LOCK command (incremental locking) rather than adopt
+ the ZALLOCATE and ZDEALLOCATE approach. Therefore, when a design
+ requires an incremental lock mechanism, LOCK +/- has the advantage over
+ ZALLOCATE / ZDEALLOCATE of being part of the M standard. LOCK +/- also
+ has the advantage of working symmetrically when routines using LOCKs
+ are nested. That is, a ZALLOCATE command issued by a process for a
+ named resource already ZALLOCATEd by that process results in no change
+ of state. This means that routines that do ZALLOCATE followed by a
+ ZDEALLOCATE on a named resource that is already ZALLOCATEd by the same
+ process (at routine entry time), will end up ZDEALLOCATEing the named
+ resource (which might not be desired). On the other hand, a LOCK +
+ command issued by a process for a named resource already LOCKed by that
+ process causes the LEVEL of the LOCK to be incremented (as seen in a
+ ZSHOW "L" output). Every LOCK - command on that named resource causes
+ the LEVEL to be decremented. When the LEVEL becomes 0, the named
+ resource is no longer LOCKed.
+
+ For more information on troubleshooting LOCKs with the GT.M Lock
+ Utility (LKE), refer to the appropriate chapter of the GT.M
+ Administration and Operations Guide.
+
+ The format of the ZALLOCATE command is:
+
+
+ ZA[LLOCATE][:tvexpr] [(]nref[,...][)][:intexpr][,...]
+
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o The nref argument specifies a name in the format of a GT.M name
+ with or without subscripts, and with or without a preceding caret
+ (^).
+
+ o Outside of transactions, only one process in an environment can
+ ZALLOCATE (or LOCK) a particular resource name at any given time.
+
+ o Because the data storage in GT.M uses hierarchical sparse arrays
+ and ZALLOCATE may serve to protect that data from inappropriate
+ "simultaneous" access by multiple processes, ZALLOCATE treats
+ resource names in a hierarchical fashion; a ZALLOCATE protects not
+ only the named resource, but also its ancestors and descendants.
+
+ o When one or more nrefs are enclosed in parentheses (), ZALLOCATE
+ reserves all the enclosed names "simultaneously," that is, it
+ reserves none of them until all become available.
+
+ o The optional numeric expression specifies a time in seconds after
+ which the command should timeout if unsuccessful; choosing 0
+ results in a single attempt.
+
+ o An indirection operator and an expression atom evaluating to a list
+ of one or more ZALLOCATE arguments form a legal argument for a
+ ZALLOCATE.
+
+ For an explanation of the LOCK command see the "LOCK" section in the M
+ LOCK Utility chapter of GT.M Administration and Operations Guide.
+
+ If a ZALLOCATE command specifies a timeout, and GT.M acquires ownership
+ of the named resource before the timeout elapses, ZALLOCATE sets $TEST
+ to TRUE (1). If GT.M cannot acquire ownership of the named resource
+ within the specified timeout, ZALLOCATE sets $TEST to FALSE (0). If a
+ ZALLOCATE command does not specify a timeout, the execution of the
+ command does not affect $TEST.
+
+ When given a list of nrefs, ZALLOCATE tries to reserve each nref from
+ left to right in the order specified taking into account the timeout
+ specified for each. If the timeout elapses before reserving an nref,
+ GT.M terminates the ZALLOCATE command. Any nrefs already acquired as
+ part of the current ZALLOCATE command stay acquired.
+
+2 Ex_of_ZAllocate
+ Examples of ZALLOCATE
+
+ Examples:
+
+
+ ZALLOCATE A
+
+ ZALLOCATE ^A
+
+ ZALLOCATE ^A(1)
+
+ ZALLOCATE (^B("smith"),^C("jones"))
+
+ ZALLOCATE @A
+
+ The first command ZALLOCATEs A; the second, ^A; the third, ^A(1) and
+ the fourth, both ^B("smith") and ^C("jones") simultaneously. The last
+ command ZALLOCATEs the resources named by the value of the variable A.
+
+ Example:
+
+
+ ZALLOCATE A,^B, at C
+
+ ZALLOCATE (A,B,C)
+
+ If ZALLOCATE arguments are enclosed in parentheses, the command waits
+ until all names in the argument list become available before reserving
+ any of the names. For example, in the statement ZA (A,B,C), if the
+ resource named C is not available, ZALLOCATE waits until C becomes
+ available before reserving A and B. Using the format illustrated in the
+ first line above, can cause deadlocks because the resource names are
+ reserved as they come available.
+
+ When a process attempts to ZALLOCATE a name currently ZALLOCATEd or
+ LOCKed (with the LOCK command) by another process, the ZALLOCATEing
+ process hangs until the other process releases the name. In the event
+ that names remain unavailable for significant periods of time, timeouts
+ allow the process issuing a ZALLOCATE to regain program control.
+
+ Example:
+
+
+ ZALLOCATE ^D:5
+
+ This example specifies a timeout of five seconds. If GT.M reserves ^D
+ before the five seconds elapses, ZALLOCATE sets $TEST to TRUE. If GT.M
+ cannot reserve ^D within the five second timeout, ZALLOCATE sets $TEST
+ to FALSE.
+
+ When you ZALLOCATE a name, no names previously reserved with ZALLOCATE
+ or the LOCK command are released (similarly, LOCKing a name does not
+ release names that have been ZALLOCATEd). For example, after
+ ZALLOCATEing A and LOCKing B, LOCKing B does not release A, and
+ ZALLOCATEing C does not release A or B.
+
+ To release a ZALLOCATEd name, use the ZDEALLOCATE command. The
+ ZDEALLOCATE command can only release previously ZALLOCATEd (not LOCKed)
+ names.
+
+ Resource name arguments for LOCKs and ZALLOCATEs intersect. That is, if
+ one process holds a LOCK or ZALLOCATE, another process can neither LOCK
+ nor ZALLOCATE any name falling in the hierarchy of the resource name
+ held by the first process. When a process holds a LOCK or ZALLOCATE,
+ that same process may also LOCK or ZALLOCATE resource names falling in
+ the hierarchy of the currently held resource name. When a single
+ process holds both LOCKs and ZALLOCATEs, a LOCK does not release the
+ ZALLOCATEd resource(s) and a ZDEALLOCATE does not release the LOCKed
+ resource(s).
+
+ Example:
+
+
+ L ^AR(PNT)
+
+ .
+ .
+ .
+ ZALLOCATE ^AR(PNT,SUB)
+
+ .
+ .
+ .
+ L ^TOT(TDT)
+
+ .
+ .
+ .
+ ZDEALLOCATE ^AR(PNT,SUB)
+
+
+ This LOCKs ^AR(PNT), then, after performing some unspecified commands,
+ it ZALLOCATEs ^AR(PNT,SUB). Because ZALLOCATE does not imply any change
+ to LOCKs or existing ZALLOCATEd resource names, the LOCK of ^AR(PNT)
+ remains in effect. Assuming the routine does not modify the variable
+ PNT, ^AR(PNT,SUB) is already protected by the LOCK. Next, because an
+ unsigned LOCK releases all resource names currently LOCKed by the
+ process, the routine releases ^AR(PNT) with the LOCK of ^TOT(TDT). This
+ leaves the ZALLOCATE of ^AR(PNT,SUB). The name ^AR and all its
+ subscripts except for those that begin with ^AR(PNT,SUB) are now
+ available for LOCKing by other processes. Finally the routine releases
+ ^AR(PNT,SUB) with a ZDEALLOCATE command. The ZDEALLOCATE does not
+ affect the LOCK on ^TOT(TDT). Note that this example was constructed to
+ illustrate the interaction between LOCK, ZALLOCATE and ZDEALLOCATE, and
+ not to illustrate sound programming practice.
+
+1 ZBREAK
+ ZBreak
+
+ The ZBREAK command sets or clears routine breakpoints during debugging.
+
+ The format of the ZBREAK command is:
+
+
+ ZB[REAK][:tvexpr] [-]entryref[:[expr][:intexpr]]
+
+ [,...]
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o The required entryref specifies a location within a routine at
+ which to set or remove a breakpoint.
+
+ o The optional minus sign (-) specifies that ZBREAK remove the
+ breakpoint; -* means remove all breakpoints.
+
+ o The optional expression specifies a fragment of GT.M code to XECUTE
+ when GT.M execution encounters the breakpoint; if the ZBREAK
+ argument does not specify an action, the default action is "BREAK".
+
+ o The optional integer expression immediately following the
+ expression specifies a count of process transits through the
+ breakpoint before the breakpoint action takes effect; once GT.M
+ exhausts the count and the action takes effect, the action occurs
+ every time the process encounters the breakpoint. If the action
+ expression is omitted, the optional integer expression must be
+ separated from the entryref by two adjacent colons (::).
+
+ o An indirection operator and an expression atom evaluating to a list
+ of one or more ZBREAK arguments form a legal argument for a ZBREAK.
+
+ When GT.M encounters the entryref, GT.M suspends execution of the
+ routine code and XECUTEs the breakpoint action before executing any of
+ the commands on the line.
+
+ When the optional integer expression is used, GT.M activates the
+ breakpoint on the intexpr-th time the process encounters the breakpoint
+ during routine execution. Once GT.M activates the breakpoint, that
+ breakpoint remains active for the process until explicitly replaced or
+ removed, or until the process terminates.
+
+2 Ex_of_ZBreak
+ Examples of ZBREAK
+
+ Example:
+
+
+ GTM>ZPRINT ^ZBTEST
+
+ ZBTEST;
+
+ DO SUB
+
+ QUIT
+
+ 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
+
+ GTM>
+
+ ZSHOW "B"
+
+ SUB^ZBTEST
+
+ This inserts a ZBREAK with a default action at SUB^ZBTEST. After GT.M
+ encounters the BREAK, the ZSHOW "B" displays this as the only ZBREAK in
+ the image.
+
+ Example:
+
+
+ GTM>ZBREAK -*
+
+ GTM>ZGOTO
+
+ GTM>ZBREAK SUB^ZBTEST:"W !,""Trace"""
+
+ GTM>DO ^ZBTEST
+
+ Trace
+
+ This is ZBTEST
+
+ GTM>
+
+ This removes all existing ZBREAKs with a ZBREAK -*. Note that it is not
+ necessary to remove ZBREAKs before modifying them. It also clears the
+ process invocation stack with an argumentless ZGOTO. Then it uses a
+ ZBREAK to insert a trace-point. Every time GT.M executes the line to
+ where ZBREAK has established a trace-point, it performs the specified
+ action without entering Direct Mode.
+
+ Example:
+
+
+ ZBREAK PRINT^TIME::5
+
+ This BREAKs execution at line PRINT in routine just before the fifth
+ time the line is executed.
+
+ Example:
+
+
+ ZBREAK PRINT^TIME:"WRITE AVE BREAK":3
+
+ This inserts a ZBREAK action of WRITE AVE and BREAK before the third
+ execution of PRINT^TIME.
+
+1 ZCOMPILE
+ ZCOMpile
+
+ The ZCOMPILE command invokes the GT.M compiler from within the GT.M
+ run-time environment.
+
+ Within GT.M itself, ZCOMPILE provides the functionality of the MUMPS
+ command, except for MUMPS/DIRECT.
+
+ The format of the ZCOMPILE command is:
+
+
+ ZCOM[PILE][:tvexpr] expr[,...]
+
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o The expression argument specifies one or more file-specifications
+ filenames, (in which wildcards are acceptable) and, optionally,
+ qualifiers valid for a MUMPS command. If the file specification
+ does not include an extension, a default file extension of ".M" is
+ assumed.
+
+ The $ZCSTATUS intrinsic special variable holds the value of the status
+ code for the compilation performed by a ZCOMPILE command.
+
+2 Ex_of_ZCOMpile
+ Examples of ZCOMPILE
+
+ ZCOMPILE "EXAMPLE"
+
+ This compiles EXAMPLE.M in the current default directory.
+
+ Example:
+
+
+ ZCOMPILE "A*/LIST"
+
+ This compiles all files starting with a [capital] A and an extension of
+ .M in the current default directory. This also produces source program
+ listing file.
+
+1 ZCONTINUE
+ ZContinue
+
+ The ZCONTINUE command continues routine execution after a BREAK command
+ or a <CTRL-C>.
+
+ The format of the ZCONTINUE command is:
+
+
+ ZC[ONTINUE][:tvexpr]
+
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o Because ZCONTINUE changes the flow of execution away from control
+ of the principal device back to the current routine, it is usually
+ the final command on a line; however, if it is not, because the
+ ZCONTINUE has no argument, at least two (2) spaces must follow the
+ command to separate it from the next command on the line.
+
+ o If the process is not in Direct Mode, ZCONTINUE has no effect.
+
+1 ZDEALLOCATE
+ ZDeallocate
+
+ The ZDEALLOCATE command releases a specified resource name or names
+ previously reserved by the ZALLOCATE command. The ZDEALLOCATE command
+ releases only the specified name(s) without releasing other names
+ previously reserved with the ZALLOCATE or LOCK command.
+
+ The ZDEALLOCATE command provides compatibility with some other GT.M
+ implementations. The M Development Committee choose to add the + and -
+ delimiters to the LOCK command rather than adopt the ZALLOCATE and
+ ZDEALLOCATE approach. Therefore, when a design requires an incremental
+ lock mechanism, LOCK +/- has the advantage of being part of the M
+ standard. LOCK +/- also has the advantage of working symmetrically when
+ routines using LOCKs are nested.
+
+ The format of the ZDEALLOCATE command is:
+
+
+ ZD[EALLOCATE][:tvexpr] [nref[,...]]
+
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command
+
+ o The nref argument specifies a name in the format of a GT.M name
+ with or without subscripts and with or without a leading caret (^).
+
+ o A ZDEALLOCATE with no argument releases all names currently
+ reserved with ZALLOCATE by the process; in this case, at least two
+ (2) spaces must follow the ZDEALLOCATE to separate it from the next
+ command on the line.
+
+ o ZDEALLOCATEing a named resource that is not currently owned by the
+ process has no effect.
+
+ o An indirection operator and an expression atom evaluating to a list
+ of one or more ZDEALLOCATE arguments form a legal argument for a
+ ZDEALLOCATE.
+
+1 ZEDIT
+ ZEDit
+
+ The ZEDIT command invokes the OpenVMS Text Processing Utility (TPU)
+ section file for GT.M and opens the specified file for editing.
+
+ By default, ZEDIT puts a new file into the first source directory in
+ $ZROUTINES. Previously, it used the current working directory. The old
+ behavior can be obtained by specifying the current working directory
+ explicitly in the argument to the ZEDIT command:
+
+ o ZEDIT "[]file"
+
+ The format of the ZEDIT command is:
+
+
+ ZED[IT][:tvexpr] [expr1[:expr2][,...]]
+
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o The optional first expression specifies the RMS file-specification
+ of a file to edit; note the argument is an expression rather than a
+ routinename; ZEDIT rejects arguments of file type .OBJ as illegal.
+
+ o If ZEDIT has an argument, it not only invokes the editor, but also
+ sets $ZSOURCE=expr1.
+
+ o If ZEDIT has no argument or expr1="", the command acts as a ZEDIT
+ $ZSOURCE; at least two (2) spaces must follow a ZEDIT command with
+ no argument to separate it from the next command on the line.
+
+ o GT.M stores source code in files with standard operating system
+ format; generally the file name is the same as the GT.M routinename
+ with a default type of .M.
+
+ o The optional second expression specifies a string holding TPU
+ qualifiers, each delimited by a slash (/); the qualifiers control
+ special TPU processing options
+
+ o An indirection operator and an expression atom evaluating to a list
+ of one or more ZEDIT arguments form a legal argument for a ZEDIT
+
+ If the expression includes a directory, ZEDIT searches only that
+ directory. If $ZROUTINES is not null, a ZEDIT command that does not
+ specify a directory uses $ZROUTINES to locate files. If $ZROUTINES is
+ null, ZEDIT edits a new file in the first source directory specified in
+ $ZROUTINES.
+
+ When the argument to a ZEDIT includes a file-specification, $ZSOURCE
+ maintains that as a default for ZEDIT and
+ ZLINK.
+
+ The /READONLY qualifier instructs TPU to make the buffer
+ non-modifiable. The /MODIFIABLE qualifier in conjunction with the
+ /READONLY qualifier makes the buffer modifiable, but TPU does not
+ automatically write the buffer to disk when it exits the session. By
+ default, /NOREADONLY, TPU maintains a journal file of the session.
+
+ The /RECOVER qualifier instructs TPU to read a specified journal file
+ at the beginning of the editing session and to restore all commands in
+ that journal file. /RECOVER restores edits after a system interruption.
+ To recover a session, set all terminal characteristics such as page
+ width or length to the same state as they had at the start of the
+ editing session being recovered. By default, ZEDIT starts a new session
+ rather than a /RECOVER.
+
+ For more information on these and other TPU edit qualifiers, refer to
+ the VMS Text Processing Utility Reference Manual.
+
+ You may wish to customize your editor. The logical name TPU$SECTION
+ specifies the TPU image invoked by ZEDIT. The logical name TPU$COMMAND
+ specifies a file containing TPU commands that customize your standard
+ editor by adding to the TPU image at invocation. You may place commands
+ to tailor EVE, the default TPU editor, in the file EVE$INIT.EVE in your
+ login directory. Alternatively, you can define the logical name
+ EVE$INIT to specify a file used at invocation to tailor EVE. For more
+ information on TPU, refer to the VMS Text Processing Utility Reference
+ Manual.
+
+2 Ex_of_ZEDit
+ Examples of ZEDIT
+
+ Example:
+
+
+ $ CREATE EVE$INIT.EVE
+
+ SET KEYPAD EDT
+
+ SET CURSOR BOUND
+
+ SET RIGHT MARGIN 132
+
+ SET WIDTH 132
+
+ <CTRL Z>
+
+ $ DEFINE EVE$INIT SYS$LOGIN:EVE$INIT.EVE
+
+ This creates an EVE$INIT file that sets the EVE keypad and cursor to
+ emulate EDT and assigns the appropriate logical name to the file. The
+ last two commands in the file put the editor and the terminal in 132
+ column mode.
+
+ Example:
+
+
+ GTM>ZEDIT "BAL"
+
+ This invokes the editor for a file with a name of BAL and an extension
+ of .M. Notice that BAL is a string literal.
+
+ Example:
+
+
+ GTM>SET prog="BAL"
+
+ GTM>ZEDIT prog
+
+ This is similar to the first example except that it uses a variable
+ argument rather than a string literal.
+
+ Example:
+
+
+ GTM>ZEDIT "LOGIN.COM"
+
+ This invokes the editor for a file with the name LOGIN and an extension
+ of .COM. In this case the file is not a GT.M file.
+
+1 ZGOTO
+ ZGoto
+
+ The ZGOTO command transfers control to various levels in the GT.M
+ invocation stack. It also can transfer control from one part of the
+ routine to another or from one routine to another using the specified
+ entryref.
+
+ The format of the ZGOTO command is:
+
+
+ ZG[OTO][:tvexpr] [[intexpr][:entryref
+
+ [:tvexpr]],...]
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o The optional integer expression specifies the stack frame nesting
+ level reached by performing the ZGOTO.
+
+ o A ZGOTO with no argument returns control to the next command at the
+ bottom of the stack (level 1); in this case, at least two (2)
+ spaces must follow the command to separate it from the next command
+ on the line.
+
+ o The optional entryref specifies a location to which ZGOTO transfers
+ control.
+
+ o If ZGOTO specifies no entryref, it returns control to the next
+ command at the level specified by the integer expression.
+
+ o The optional truth-valued expression immediately following the
+ entryref specifies the argument postconditional and controls
+ whether GT.M uses the argument.
+
+ o If the ZGOTO includes the level and the argument postconditional
+ but not the entryref, two colons (::) separate the integer
+ expression from the truth-valued expression.
+
+ o An indirection operator and an expression atom evaluating to a list
+ of one or more ZGOTO arguments form a legal argument for a ZGOTO.
+
+ A ZGOTO command with an entryref performs a similar function to the
+ GOTO command, with the additional capability of reducing the GT.M stack
+ level. In a single operation, ZGOTO executes ($ZLEVEL - intexpr)
+ implicit QUITs and a GOTO operation, transferring control to the named
+ entryref.
+
+ The ZGOTO command leaves the invocation stack at the level specified by
+ the integer expression. GT.M implicitly terminates any intervening FOR
+ loops and unstacks variables stacked with NEW commands as appropriate.
+
+ Using ZGOTO results in an exit from the current GT.M invocation. ZGOTO
+ resembles HALT (and not QUIT) in that it causes an exit regardless of
+ the number of active levels in the current invocation. ZGOTO resembles
+ QUIT (and not HALT) in that it destroys the GT.M context and terminates
+ the process only if the current GT.M invocation is at the base of the
+ process. Understanding the difference between ZGOTO and HALT has an
+ impact only in an environment where GT.M is invoked recursively by
+ means of the external calling syntax or from other languages.
+
+ ZGOTO $ZLEVEL:LABEL^ROUTINE produces identical results to GOTO
+ LABEL^ROUTINE. ZGOTO $ZLEVEL-1 responds like a QUIT (followed by
+ ZCONTINUE, if in Direct Mode). If the integer expression evaluates to a
+ value greater than the current value of $ZLEVEL or less than zero (0),
+ GT.M issues a run-time error.
+
+ If ZGOTO has no entryref, it performs some number of implicit QUITs and
+ transfers control to the next command at the specified level. If ZGOTO
+ has no argument, it behaves like ZGOTO 1, which resumes operation of
+ the lowest level GT.M routine as displayed by ZSHOW "S". In the image
+ invoked by MUMPS/DIRECT or a similar image, a ZGOTO without arguments
+ returns the process to Direct Mode.
+
+ ZGOTO provides a useful debugging tool in Direct Mode. However, because
+ ZGOTO is not conducive to structured coding, it is best to restrict its
+ use in production programs to error handling.For more information on
+ error handling, refer to the "Error Processing" chapter in GT.M
+ Programmer's Guide.
+
+2 Ex_of_ZGOTO
+ Examples of ZGOTO
+
+ Example:
+
+
+ GTM>ZGOTO
+
+ %GTM-I-BREAK, Break instruction encountered
+
+ At M source location +1^GTM$DMOD
+
+ GTM>ZSHOW
+
+
+ +1^GTM$DMOD (Direct mode)
+
+ GTM>
+
+ This uses ZGOTO to clear all levels of the GT.M invocation stack. ZSHOW
+ with no arguments displays the stack.
+
+ Example:
+
+
+ SET $ZTRAP="ZGOTO "_$ZLEVEL_":^ERROR"
+
+ This SETs $ZTRAP to contain a ZGOTO, so if an error causes GT.M to
+ XECUTE $ZTRAP, the routine ERROR executes at the same level as the SET
+ command shown in the example.
+
+1 ZHELP
+ ZHelp
+
+ The ZHELP command provides access to help information from the GTM help
+ library or from any help library specified in the command argument.
+
+ The format of the ZHELP command is:
+
+
+ ZH[ELP][:tvexpr] [expr1[:expr2],...]
+
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o The optional first expression specifies the help topic.
+
+ o If ZHELP has no argument or expr1="", ZHELP invokes base level
+ help; at least two (2) spaces must follow a ZHELP command with no
+ argument to separate it from the next command on the line.
+
+ o The optional second expression specifies the help file containing
+ ^HELP.
+
+ o If ZHELP does not specify the second expression, the help
+ file-specification defaults to GTM$HELP:M.HLB.
+
+ o An indirection operator and an expression atom evaluating to a list
+ of one or more ZHELP arguments form a legal argument for a ZHELP
+
+2 Ex_of_ZHelp
+ Examples of ZHELP
+
+ Example:
+
+
+ GTM>zhelp "func $data"
+
+ This lists the help for function $DATA, which is a subtopic of
+ functions topic.
+
+ Example:
+
+
+ GTM>ZHELP "lexical":"SYS$HELP:HELPLIB"
+
+ This uses ZHELP to invoke the standard VMS help library, looking up the
+ topic "lexical" in that library.
+
+ Example:
+
+
+ $ DEFINE GTM$HELP LAB:[TEST]
+
+ $ GTM
+
+ GTM>ZHELP "":"APPL.HLB"
+
+ This uses the DCL command DEFINE to point GTM$HELP to a user help
+ library directory. The ZHELP command then invokes the base level help
+ in the library APPL.HLB.
+
+1 ZLINK
+ ZLink
+
+ If the current image does not contain a copy of a routine, the ZLINK
+ command adds an executable GT.M routine to the current image. If the
+ current image contains a copy of a routine and the routine is not
+ active, the ZLINK command replaces the current routine image with a
+ "new" version. If necessary, the ZLINK command compiles the routine
+ prior to integrating it with the image.
+
+ The format of the ZLINK command is:
+
+
+ ZL[INK][:tvexpr] [expr1[:expr2][,...]]
+
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o The optional first expression specifies the file-specification of a
+ routine to ZLINK; if ZLINK has an argument, it not only adds the
+ routine to the image, but also sets $ZSOURCE=expr.
+
+ o If ZLINK has no argument, or expr1="", it uses value of $ZSOURCE as
+ the routine; at least two (2) spaces must follow a ZLINK command
+ with no argument to separate it from the next command on the line.
+
+ o The optional second expression specifies a string holding MUMPS
+ command qualifiers delimited by a slash (/); the qualifiers control
+ compile options when the current ZLINK requires a compile; if ZLINK
+ omits the second expression, the command uses the $ZCOMPILE
+ intrinsic special variable to determine the compile qualifiers.
+
+ o An indirection operator and an expression atom evaluating to a list
+ of one or more ZLINK arguments form a legal argument for a ZLINK.
+
+ ZLINK cannot change a routine that GT.M is currently executing. An
+ attempt to ZLINK an active routine results in a run-time error because
+ changing a routine in progress could have unpredictable results. Before
+ ZLINKing the routine, use the ZSHOW command to display the currently
+ active routines, then remove it from the GT.M stack using ZGOTO, or the
+ appropriate number of QUITs.
+
+ When the ZLINK command specifies a file, GT.M sets $ZSOURCE to that
+ file-specification. By default, ZLINK and ZEDIT use $ZSOURCE for a
+ specification when they have a missing or null argument. A subsequent
+ ZLINK without an argument is equivalent to ZLINK $ZSOURCE.
+
+ Because RMS does not permit the percent sign (%) in a file name, use an
+ underscore (_) in place of the percent in the ZLINK file-specification
+ for routines beginning with a percent sign.
+
+ If the expression includes an explicit directory, ZLINK searches only
+ that directory. Otherwise, if $ZROUTINES is not null, a ZLINK command
+ uses $ZROUTINES to locate files. If $ZROUTINES is null, ZLINK uses the
+ current directory.
+
+ If the file-specification contains an explicit file type (extension),
+ ZLINK processes the file according to the type, object (.OBJ) or source
+ (usually .M.). If the file-specification does not specify a file type,
+ ZLINK attempts to find and match both the object and source for a
+ routine.
+
+2 ZLINK_Compilation
+ ZLINK Compilation
+
+ If ZLINK compiles a routine and the /OBJECT= qualifier does not
+ redirect the output, it places the resulting object file in the
+ directory indicated by the search criteria. ZLINK incorporates the new
+ object file into the image, regardless of its directory placement.
+
+ If the command does not specify compile qualifiers (with expr2) and
+ $ZCOMPILE is null, GT.M uses the default M command qualifiers, /IGNORE,
+ /LABELS=LOWER, /NOLIST, and /OBJECT. For more information on $ZCOMPILE,
+ refer to the appropriate section in the "Intrinsic Special Variables".
+
+ For information on producing object files, but not adding them to the
+ current image, refer to ZCOMPILE.
+
+2 Ex_of_ZLink
+ Examples of ZLINK
+
+ Example:
+
+
+ GTM>ZLINK "test"
+
+ If ZLINK finds test.M or test.OBJ, it adds the routine "test" to the
+ current image. If ZLINK does not find test.OBJ, or finds that test.OBJ
+ is older than test.M, GT.M compiles test.M to produce a new test.OBJ,
+ and adds the contents of the new object file to the image.
+
+ Example:
+
+
+ GTM>
+
+ ZLINK "test.m":"/noobject/list"
+
+ This compiles the routine "test" and produces a listing but no object
+ file. Because the example produces no object file, it does not change
+ the current image.
+
+ Example:
+
+
+ GTM>ZLINK "[smith]mode.M":"/obj=[]"
+
+ This compiles mode.M, in the directory [smith], to produce mode.OBJ in
+ the current default directory, and then includes the new object file in
+ the current image.
+
+2 Auto_ZLink
+ Auto-ZLINK
+
+ If a GT.M routine refers to a routine that is not linked to the GT.M
+ image, GT.M automatically attempts to ZLINK that routine. An auto-ZLINK
+ is functionally equivalent to an explicit ZLINK of a routine without a
+ specified directory or file extension.
+
+ The following GT.M commands and functions can initiate auto-ZLINKing:
+
+ DO
+
+ GOTO
+
+ ZBREAK
+
+ ZGOTO
+
+ ZPRINT
+
+ $TEXT()
+
+ GT.M auto-ZLINKs the routine if the following conditions are met:
+
+ o ZLINK can locate and process the routine file, as indicated in the
+ previous ZLINK Operation Summary table
+
+ o The name of the routine is the same as the name of the source file;
+ the only exception is in cases where GT.M converts a leading
+ percent sign (%) in a file name to an underscore (_)
+
+ o For DO, GOTO and ZGOTO, the reference must be through code added to
+ the image by GT.M, that is, previously ZLINKed, XECUTEd or
+ referenced through indirection; in other words, explicit routine
+ references using these commands that are not resolved by the VMS
+ LINKER can not be auto-ZLINKed; this restriction does not apply for
+ ZBREAK, ZPRINT, and $TEXT()
+
+2 ZL_AutoZL_and_Rtn_Nam
+ ZLINK, Auto-ZLINK and Routine Names
+
+ In GT.M, the name of the source file determines the name of the GT.M
+ routine. The file-specification of the object file is not required to
+ match the name of the routine. Linking the object file makes the
+ internal routine name (derived from the source file) known to GT.M.
+ This can lead to potential confusion, however, since both ZLINK and
+ auto-ZLINK use the name of the object file to find the routine. When
+ the object file name differs from the name of the routine, auto-ZLINK
+ generates a run-time error.
+
+ Example:
+
+
+ $ TYPE DM.M
+
+
+ $ TYPE NAME.M
+
+ WRITE "This is routine NAME.",!
+
+ $ M NAME/OBJ=NAME1,DM
+
+ $ GTM
+
+
+ GTM>DO ^NAME1
+
+ %GTM-E-ZLINKFILE, Error while zlinking "NAME1"
+
+ -GTM-E-ZLMODULE, Object file name does not match
+
+ module name: NAME
+
+ GTM>DO ^NAME
+
+ This is routine NAME.
+
+ GTM>HALT
+
+
+ $ LINK DM,NAME1
+
+ $ RUN DM
+
+
+ GTM>DO ^NAME
+
+ This is routine NAME.
+
+ GTM>DO ^NAME1
+
+ %GTM-E-ZLINKFILE, Error while zlinking "NAME1"
+
+ -GTM-E-ZLMODULE, Object file name does not match
+
+ module name: NAME
+
+ GTM>HALT
+
+ Note that, in the above example, auto-ZLINK does link the object file
+ to the image, even though it raises an error. The routine becomes
+ available under the internal routine name.
+
+1 ZKILL
+ ZKill
+
+ The ZKILL command KILLs the data value for a variable name without
+ affecting the nodes descended from that node.
+
+ The format of the ZKILL command is:
+
+
+ ZK[ILL][:tvexpr] glvn
+
+ The functionality of ZKILL is identical to ZWITHDRAW. For a
+ comprehensive description of the format and usage, refer to the entry
+ for ZWITHDRAW.
+
+1 ZMESSAGE
+ ZMessage
+
+ The ZMESSAGE command signals a specified condition.
+
+ The format of the ZMESSAGE command is:
+
+
+ ZM[ESSAGE][:tvexpr] intexpr
+
+ [:expr...][,...]
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o The required integer expression specifies the exception condition
+ to signal.
+
+ o The additional expressions specify one or more strings passed as
+ ASCII text to the VMS message formatter by means of descriptors;
+ for example, if the message associated with the condition contains
+ a corresponding FAO !AD directive, the message facility inserts
+ each text string in the message. $ZMESSAGE() function returns the
+ message text with the substitution directives for a given message
+ number.
+
+ o An indirection operator and an expression atom evaluating to a list
+ of one or more ZMESSAGE arguments form a legal argument for a
+ ZMESSAGE.
+
+ For more information on Format ASCII Output (FAO), refer to the
+ description of the F$FAO lexical function in the VMS DCL Dictionary.
+
+2 Ex_of_ZMessage
+ Examples of ZMESSAGE
+
+ All of the following examples issue ZMESSAGE from Direct Mode where
+ exception conditions do not invoke $ZTRAP. ZMESSAGE allows you to feed
+ an undefined message number back into GT.M to try and determine the
+ message and/or mnemonic associated with it.
+
+ Example:
+
+
+ GTM>ZMESSAGE 340
+
+ %SYSTEM-F-IVLOGNAM, invalid logical name
+
+ This ZMESSAGE does not specify substitution text and the message does
+ not include any FAO directives.
+
+ Example:
+
+
+ GTM>ZMESSAGE 150372994
+
+ %GTM-E-GVUNDEF, Global Variable undefined:
+
+ The message specified by this ZMESSAGE command includes FAO !AD
+ directive but the command does not supply any text.
+
+ Example:
+
+
+ GTM>ZMESSAGE 150373850:"x"
+
+ %GTM-E-GVUNDEF, Undefined local variable: x
+
+ This ZMESSAGE command supplies the substitution text for the message.
+
+ VMS treats odd-numbered conditions as "successful." GT.M handles
+ successful conditions by displaying the associated message and
+ continuing execution. VMS treats even-numbered conditions as failures.
+ GT.M handles failure conditions by storing the error information in
+ $ZSTATUS and XECUTEing $ZTRAP or by terminating if $ZTRAP="". In Direct
+ Mode, GT.M only reports failure conditions to the principal device and
+ does not XECUTE $ZTRAP or set $ZSTATUS. For more information on error
+ handling, refer to the "Error Processing" chapter in GT.M Programmer's
+ Guide.
+
+1 ZPRINT
+ ZPrint
+
+ The ZPRINT command displays source code lines selected by its argument.
+
+ The format of the ZPRINT command is:
+
+
+ ZP[RINT][:tvexpr][entryref
+
+ [:label[+intexpr]][,...]]
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o A ZPRINT with no argument prints the entire current routine, which
+ is the routine closest to the top of an invocation stack, as
+ displayed by a ZSHOW "S"; in this case, at least two (2) spaces
+ must follow the command to separate it from the next command on the
+ line.
+
+ o The optional entryref specifies the location in a routine at which
+ to start printing; the entryref can include either a routinename or
+ a label plus a routinename in the format LABEL^ROUTINENAME or
+ LABEL+OFFSET^ROUTINENAME; if the entryref does not contain a
+ routinename, ZPRINT defaults to the current routine.
+
+ o The optional label following the entryref identifies a location at
+ which to stop printing; the optional integer expression specifies
+ an offset from the label; the label and offset together are
+ referred to as a lineref and this lineref identifies the last line
+ to print; if the offset is specified without the label, the offset
+ in the optional lineref is always counted from the beginning of the
+ routine, even when the entryref specifies a label.
+
+ o If the ZPRINT argument includes the colon (:) delimiter, then the
+ argument must also include at least one component of the optional
+ lineref.
+
+ o If the ZPRINT argument contains only the entryref, with no
+ components of the optional lineref and the entryref contains a
+ label or offset, ZPRINT displays only the one line that occurs at
+ that entryref.
+
+ o If the entryref contains only a routinename, ZPRINT displays the
+ entire routine.
+
+ o If the entryref contains only a routinename and the argument
+ includes the optional lineref, ZPRINT starts the display at the
+ beginning of the routine.
+
+ o If the optional lineref specifies a line prior to the lineref
+ specified within the entryref, ZPRINT does not display any lines.
+
+ o If the offset in the optional lineref specifies a line beyond the
+ end of the routine, ZPRINT displays the remainder of the routine.
+
+ o If ZPRINT cannot locate the routine or if either of the labels does
+ not appear in the routine, ZPRINT issues an error.
+
+ o An indirection operator and an expression atom evaluating to a list
+ of one or more ZPRINT arguments form a legal argument for a ZPRINT.
+
+ Note that the routinename may only appear before the colon (:)
+ delimiter. The integer expression offsets may be positive or negative,
+ but they must always be delimited by a plus sign (+).
+
+2 Ex_of_ZPrint
+ Examples of ZPRINT
+
+ Example:
+
+
+ GTM>ZPRINT X^RTN
+
+ This example displays the line beginning with the label X in the
+ routine RTN.
+
+ Example:
+
+
+ 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 lines in routine RTN. The second line displays the 5 lines
+ preceding label X in the same routine and the line beginning with label
+ X. The third line generates a run-time error because the routine name
+ must appear only before the colon in the argument.
+
+1 ZSHOW
+ ZSHow
+
+ The ZSHOW command displays information about the current GT.M
+ environment.
+
+ The format of the ZSHOW command is:
+
+
+ ZSH[OW][:tvexpr][expr[:glvn][,...]]
+
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o The optional expression specifies one or more codes determining the
+ nature of the information displayed.
+
+ o A ZSHOW with no argument defaults to ZSHOW "S"; in this case, at
+ least two (2) spaces must follow the ZSHOW to separate it from the
+ next command on the line.
+
+ o The optional global or local variable name specifies the
+ destination for the ZSHOW output; if the ZSHOW argument does not
+ contain a global or local variable name, ZSHOW directs its display
+ to the current device ($IO).
+
+ o An indirection operator and an expression atom evaluating to a list
+ of one or more ZSHOW arguments form a legal argument for a ZSHOW.
+
+2 ZSH_Info_Codes
+ ZSHOW Information Codes
+
+ A ZSHOW argument is an expression containing codes selecting one or
+ more types of information.
+
+ B displays active ZBREAK breakpoints
+ C displays available external call table entry names
+ D displays device information
+ I displays the current values of all intrinsic special variables
+ L displays GT.M LOCKs and ZALLOCATEs held by the process
+ S displays the GT.M invocation stack
+ V displays local variables
+ * displays all possible types of ZSHOW information
+ Codes may be upper- or lower-case. Invalid codes produce a run-time
+ error. Multiple occurrences of the same code in one ZSHOW argument only
+ produce one output instance of the corresponding information. The order
+ of the first appearance of the codes in the argument determines the
+ order of the corresponding output instances.
+
+ If you are using a local variable destination and place another
+ code ahead of "V", the effect is to have the results of the earlier
+ code also appear in the results of the "V" code.
+
+ If the wildcard (*) occurs in the list, ZSHOW uses the default order:
+
+ o intrinsic special variables
+
+ o $ZCALL table entry names
+
+ o local variables
+
+ o ZBREAK information
+
+ o device information
+
+ o LOCK and ZALLOCATE information
+
+ o the GT.M stack
+
+2 Ex_of_ZSHow
+ Examples of ZSHOW
+
+ Example:
+
+
+ GTM>ZSHOW "db"
+
+ This command displays all devices with deviceparameters reflecting
+ their current characteristics followed by any current ZBREAK locations
+ with their corresponding actions.
+
+ Example:
+
+
+ GTM>ZSHOW "dbd"
+
+ This command displays the same output as the previous example.
+
+ Example:
+
+
+ GTM>ZSHOW "ax"
+
+ This command generates a run-time error.
+
+ Example:
+
+
+ LAB1 DO LAB2
+
+ QUIT
+
+ LAB2 DO LAB3
+
+ QUIT
+
+ LAB3 ZSHOW
+
+ QUIT
+
+ Produces the results:
+
+
+ LAB3^RTN
+
+ LAB2^RTN
+
+ LAB1^RTN
+
+2 ZSH_Destination_Vars
+ ZSHOW Destination Variables
+
+ ZSHOW may specify an unsubscripted or subscripted global or local
+ variable name (glvn) into which ZSHOW places its output. If the
+ argument does not include a global or local variable name, ZSHOW
+ directs its output to the current device.
+
+ When ZSHOW directs its output to a variable, it adds two levels of
+ descendants to that variable. The first level subscript contains a
+ one-character string from the set of upper-case ZSHOW action codes,
+ identifying the type of information. ZSHOW implicitly KILLs all
+ descendants of the first level nodes. ZSHOW stores information elements
+ at the second level using ascending integers, starting at 1.
+
+ When a ZSHOW "V" directs its output to a local variable (lvn), the
+ result does not contain a copy of the descendants of the resulting "V"
+ node.
+
+ Example:
+
+
+ GTM>KILL ZSHOW "s":a ZWRITE
+
+ a("S",1)="+1^GTM$DMOD (Direct Mode) "
+
+ GTM>
+
+ This ZSHOW stores the base level M/DIRECT stack in the local variable
+ a.
+
+ Example:
+
+
+ GTM>KILL SET b(1,"two")="test" ZSHOW "v":a ZWR
+
+ a("V",1)="b(1,""two"")=""test"""
+
+ b(1,"two")="test"
+
+ GTM>
+
+ This ZSHOW stores all local variables in the local variable a. Note
+ that ZSHOW does not replicate a("V") and a("V",1).
+
+ Example:
+
+
+ GTM>KILL SET a(1,"D",3,5)="stuff",a(1,"X",2)="",a(1)=1
+
+ GTM>ZSH "d":a(1)
+
+ GTM>ZWRITE
+
+ a(1)=1
+
+ a(1,"D",1)="_TNA7341: OPEN TERMINAL EDIT NOESCA HOST IN NOPAST NOREADS
+ TTSY TYPE WIDTH=80 LENG=24"
+ a(1,"X",2)=""
+
+ GTM>
+
+ This ZSHOW stores the current open device information under a(1).
+ Notice how the ZSHOW deletes a(1,"D",3,5).
+
+ Example:
+
+
+ GTM>KILL ^ZSHOW
+
+ GTM>ZB -*,lab^rout ZSH "B":^ZSHOW
+
+ GTM>ZWRITE ^ZSHOW
+
+ ^ZSHOW("B",1)="LAB^ROUT"
+
+ GTM>
+
+ This ZSHOW stores the current ZBREAK information under the global
+ variable ^ZSHOW.
+
+2 Use_of_ZSHow
+ Use of ZSHOW
+
+ Use ZSHOW as
+
+ o a debugging tool to display information on the environment.
+
+ o an error-handling tool to capture context information after an
+ unpredictable error with output directed to a sequential file or a
+ global.
+
+ o part of a context-switching mechanism in a server program that must
+ manage multiple contexts.
+
+ o a development tool to determine the ZCALL table entries available
+ from the current image.
+
+ To prevent confusing data interactions, avoid directing ZSHOW output
+ into variables holding other kinds of information and directing ZSHOW
+ "V" output into local variables. For a comparison of ZSHOW "V" and
+ ZWRITE, refer to the ZWRITE section in the "Commands" chapter in GT.M
+ Programmer's Guide.
+
+1 ZSTEP
+ ZSTep
+
+ The ZSTEP command provides the ability to control GT.M execution. When
+ a ZSTEP is issued from Direct Mode, execution continues to the
+ beginning of the next target line and then GT.M XECUTEs the ZSTEP
+ action. The keyword in the optional ZSTEP argument determines the class
+ of eligible target lines.
+
+ The format of the ZSTEP command is:
+
+
+ ZST[EP][:tvexpr] [keyword[:expr]][,...]
+
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o The optional keyword specifies the nature of the step; the keywords
+ are INTO, OVER, and OUTOF.
+
+ o A ZSTEP with no argument performs the default action OVER; in this
+ case, at least two (2) spaces must follow the ZSTEP to separate it
+ from the next command on the line, which will be ignored.
+
+ o The optional expression specifies GT.M code to XECUTE when the
+ ZSTEP arrives at its destination.
+
+ o If the ZSTEP argument does not contain an expression argument,
+ ZSTEP defaults the action to the value of $ZSTEP, which defaults to
+ "BREAK."
+
+ The ZSTEP argument keywords are not expressions and ZSTEP does not
+ accept argument indirection.
+
+ In Direct Mode, ZSTEP performs an implicit ZCONTINUE and therefore GT.M
+ ignores all commands on the Direct Mode command line after the ZSTEP.
+
+ The keyword arguments define the class of lines where ZSTEP next pauses
+ execution to XECUTE the ZSTEP action. When a ZSTEP command has multiple
+ arguments, it ignores all arguments except the last.
+
+2 ZSTEP_Into
+ ZSTEP Into
+
+ ZSTEP INTO pauses at the beginning of the next line, regardless of
+ transfers of control. When the ZSTEPed line invokes another routine or
+ a subroutine in the current routine, ZSTEP INTO pauses at the first
+ line of code associated with the new GT.M stack level.
+
+2 ZSTEP_OUtof
+ ZSTEP OUtof
+
+ ZSTEP OUTOF pauses at the beginning of the next line executed after an
+ explicit or implicit QUIT from the current GT.M invocation stack level.
+ A ZSTEP OUTOF does not pause at lines associated with the current GT.M
+ stack level or with levels invoked from the current level.
+
+2 ZSTEP_OVer
+ ZSTEP OVer
+
+ ZSTEP OVER pauses at the beginning of the next line in the code
+ associated with either the current GT.M stack level or a previous GT.M
+ stack level if the ZSTEPed line contains an explicit or implicit QUIT
+ from the current level. A ZSTEP OVER does not pause at lines invoked
+ from the current line by DOs, XECUTEs or extrinsics.
+
+2 ZSTEP_Actions
+ ZSTEP Actions
+
+ The optional action parameter of a ZSTEP must contain an expression
+ evaluating to valid GT.M code. By default, ZSTEP uses the value of
+ $ZSTEP, which defaults to "B" ("BREAK"), and enters Direct Mode. When a
+ ZSTEP command specifies an action, the process does not enter Direct
+ Mode unless the action explicitly includes a BREAK command.
+
+2 ZSTEP_Interact
+ ZSTEP Interactions
+
+ ZSTEP currently interacts with certain other elements in the GT.M
+ environment.
+
+ o If a <CTRL-C> or a CTRAP character arrives at certain points in
+ ZSTEP processing, there is a small chance GT.M may ignore the
+ <CTRL-C> or CTRAP; in a later release, <CTRL-C> and CTRAPs will
+ always have priority over ZSTEP.
+
+ o If GT.CM reports an asynchronous network error, a ZSTEP may cause
+ the network error to go unreported; the chance of such an
+ occurrence is small and the chance the error would subsequently be
+ reported is high; in a later release, network errors will always be
+ given priority over ZSTEP.
+
+2 Use_of_ZSTEP
+ Use of ZSTEP
+
+ Use ZSTEP to incrementally execute a routine or series of routines.
+ Execute any GT.M command from Direct Mode at any ZSTEP pause. To resume
+ normal execution, use ZCONTINUE.
+
+ Note that ZSTEP arguments are keywords rather than expressions. They do
+ not allow indirection, and argument lists have no utility.
+
+ ZSTEP actions that include commands followed by a BREAK perform some
+ action before entering Direct Mode. ZSTEP actions that do not include a
+ BREAK perform the command action and continue execution. Use ZSTEP
+ actions that issue conditional BREAKs and subsequent ZSTEPs to do such
+ things as test for changes in the value of a variable.
+
+2 Ex_of_ZSTEP
+ Examples of ZSTEP
+
+ Example:
+
+
+ GTM>ZSTEP INTO:"W ! ZP @
+
+ $ZPOS W !"
+
+ This ZSTEP resumes execution of the current routine. At the beginning
+ of the next line executed, the ZSTEP action ZPRINTs the source code for
+ that line. Because the specified action does not contain a BREAK
+ command, execution continues to the next line and all subsequent lines
+ in the program flow.
+
+ Example:
+
+
+ GTM>S curx=$g(x),zact="ZST:curx=$g(x) I:zact B:curx'=$g(x)"
+
+ GTM>ZSTEP INTO:zact
+
+ This sequence uses ZSTEP to invoke Direct Mode at the beginning of the
+ first line after the line that alters the value of x.
+
+1 ZSYSTEM
+ ZSYstem
+
+ The ZSYSTEM command creates a subprocess of the current process in a
+ fashion analogous to the DCL SPAWN command.
+
+ The format of the ZSYSTEM command is:
+
+
+ ZSY[STEM][:tvexpr] [expr[:tvexpr][,...]]
+
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o The optional expression specifies the command passed to the Command
+ Language Interpreter (CLI), usually DCL; after processing the
+ command, CLI returns control to GT.M.
+
+ o If ZSYSTEM has no argument or expr="", the CLI prompts for input
+ until provided with an exit command; at least two (2) spaces must
+ follow a ZSYSTEM command with no argument to separate it from the
+ next command on the line.
+
+ o The optional truth-valued expression following the argument
+ expression specifies the argument postconditional and controls
+ whether ZSYSTEM processes that argument.
+
+ o An indirection operator and an expression atom evaluating to a list
+ of one or more ZSYSTEM arguments form a legal argument for a
+ ZSYSTEM.
+
+ The ZSYSTEM command creates a new process and passes its argument to a
+ Command Language Interpreter (generally DCL) for execution. The new
+ process executes in the same directory as the initiating process. The
+ new process has the same operating system environment, such as logical
+ names and input/output devices, as the initiating process. The
+ initiating process pauses until the new process completes before
+ continuing execution. The return status of the spawned process is
+ reflected in $ZSYSTEM.
+
+ Note that, like any other VMS-spawned process, a process created by
+ ZSYSTEM acquires the privileges currently held by its parent process at
+ the time of its creation.
+
+ If a ZSYSTEM command has multiple arguments, it starts a new process
+ for each argument, one at a time. ZSYSTEM waits for one process to
+ complete before starting the next one.
+
+ A ZSYSTEM with a null argument causes CLI to prompt on SYS$OUTPUT, and
+ accept commands from SYS$INPUT, until it receives a DCL LOGOUT command
+ or other input terminator. For an interactive process, both SYS$OUTPUT
+ and SYS$INPUT generally translate to the user's terminal. A ZSYSTEM
+ with no arguments is equivalent to a ZSYSTEM with a single null string
+ argument.
+
+ If a command postconditional is false, GT.M does not process the
+ ZSYSTEM command. If an argument postconditional is false, GT.M does not
+ process that argument.
+
+ Issuing a ZSYSTEM command inside a transaction destroys the Isolation
+ of that transaction. Because of the way that GT.M implements
+ transaction processing, a ZSYSTEM within a transaction may suffer an
+ indefinite number of restarts ("live lock").
+
+ The flags arguments used by GT.M to call the OpenVMS function LIB$SPAWN
+ to implement the ZSYSTEM command can be set in GTM$DEFAULTS.MAR with a
+ GTM$USER_SPAWN_FLAG == n line, where the bits in n specify various
+ properties as below. Since the exact values are subject to change by
+ Hewlett-Packard, please validate your choice using the OpenVMS RTL
+ Library Manual and the include files in SYS$LIBRARY. In order to
+ prevent unauthorized subversion of OpenVMS security, the default value
+ (0), will be used unless both GTMSHR.EXE and the application image are
+ installed with the CMEXEC privilege.
+
+ NOWAIT 1
+ NOCLISYM 2
+ NOLOGNAM 4
+ NOKEYPAD 8
+ NOTIFY 16
+ NOCONTROL 32
+ TRUSTED 64
+ AUTHPRIV 128
+ SUBSYSTEM 256
+2 Ex_of_ZSYSTEM
+ Examples of ZSYstem
+
+ Example:
+
+
+ GTM>ZSYSTEM "DIR *.M"
+
+ This uses ZSYSTEM to spawn a process that then performs the DCL command
+ files with a type for GT.M source files. Once the command completes,
+ the spawned process terminates.
+
+ Example:
+
+
+ GTM>ZSYSTEM
+
+ $
+
+ This ZSYSTEM has no argument so the spawned process prompts for input.
+
+1 ZTCOMMIT
+ ZTCommit
+
+ The ZTCOMMIT command marks the end of a logical transaction within a
+ GT.M program. ZTCOMMIT used with ZTSTART "fences" transactions (that
+ is, marks the end and beginning). Fencing transactions allows the MUPIP
+ JOURNAL facility to prevent incomplete application transactions
+ consisting of multiple global updates from affecting the database
+ during a database recovery.
+
+ The format of the ZTCOMMIT command is:
+
+
+ ZTC[OMMIT][:tvexpr] [intexpr]
+
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o The optional integer expression specifies the number of currently
+ open ZTSTARTs for the ZTCOMMIT to close.
+
+ o A ZTCOMMIT with no argument closes one ZTSTART; in this case, at
+ least two (2) spaces must follow the command to separate it from
+ the next command on the line; with an argument of 0, ZTCOMMIT
+ closes all open ZTSTARTs.
+
+ o An indirection operator and an expression atom evaluating to a list
+ of one or more ZTCOMMIT arguments form a legal argument for a
+ ZTCOMMIT.
+
+ When an application requires sub-transactions, it may nest ZTSTARTs and
+ ZTCOMMITs to a maximum depth of 255. However, a ZTCOMMIT must "close"
+ the outer-most ZTSTART before journaling accepts any part of the
+ "transaction" as complete.
+
+2 Ex_of_ZTCommit
+ Examples of ZTCOMMIT
+
+ Example:
+
+
+ GTM>ZTCOMMIT 0
+
+ This ZTCOMMIT issued from Direct Mode would close any open ZTSTARTs.
+
+ Example:
+
+1 ZTSTART
+ ZTStart
+
+ The ZTSTART command marks the beginning of a logical transaction within
+ a GT.M program. ZTSTART and ZTCOMMIT "fence" transactions (that is,
+ mark the beginning and end). Fenced transactions prevent the MUPIP
+ JOURNAL facility from recovering incomplete transactions. All ZTSTARTs
+ must be matched with ZTCOMMITs before the journal processing facility
+ recognizes the transaction as complete.
+
+ The format of the ZTSTART command is:
+
+
+ ZTS[TART][:tvexpr]
+
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o Because ZTSTART has no argument, at least two (2) spaces must
+ follow the command to separate it from the next command on the
+ line.
+
+ For more information on Journaling and transaction fencing, refer to
+ the section on ZTCOMMIT and the "GT.M Journaling" chapter in the GT.M
+ Administration and Operations Guide.
+
+2 Ex_of_ZTStart
+ Examples of ZTSTART
+
+ Example:
+
+
+ LOCK ^P(t)
+
+ ZTSTART
+
+ SET ^P(t)=prec,^($H)=$G(^P(t,+$H))+1,^(+$H,s)=hrec
+
+ ZTCOMMIT
+
+ LOCK
+
+ This uses a LOCK on ^P(t) to serialize the transaction. The logical
+ transaction consists of three global sets that are enclosed within a
+ ZTSTART and a ZTCOMMIT.
+
+ Example:
+
+
+ BASE DO WORK
+
+ QUIT
+
+ GRP LOCK ^FAM(prn)
+
+ SET b=^FAM(prn)
+
+ ZTSTART
+
+ FOR i=1:1:$L(b,"|") D GET,WORK
+
+ ZTCOMMIT
+
+ LOCK
+
+ QUIT
+
+ WORK LOCK +^ACT(acct)
+
+ ZTSTART
+
+ SET ^ACT(acct)=actrec
+
+ SET ^ACTX(lname,fname,acct)=""
+
+ ZTCOMMIT
+
+ LOCK -^ACT(acct)
+
+ This has a sub-routine WORK, which BASE invokes directly and GRP
+ invokes to perform a sub-transaction.
+
+1 ZWITHDRAW
+ ZWIthdraw
+
+ The ZWITHDRAW command KILLs the data value for a variable name without
+ affecting the nodes descended from that node.
+
+ The format of the ZWITHDRAW command is:
+
+
+ ZWI[THDRAW][:tvexpr] glvn
+
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o The global or local variable name identifies the variable for which
+ ZWITHDRAW removes the data value.
+
+ o An indirection operator and an expression atom evaluating to a list
+ of one or more ZWITHDRAW arguments form a legal argument for a
+ ZWITHDRAW.
+
+ ZWITHDRAW provides a tool to quickly restore a node to a state where it
+ has descendants and no value-that is, where $DATA for that node will
+ have a value of 10-for the case where such a state has some control
+ meaning. GT.M also provides the ZKILL command, with functionality
+ identical to ZWITHDRAW.
+
+2 Ex_of_ZWIthdraw
+ Examples of ZWITHDRAW
+
+ Example:
+
+
+ KILL A
+
+ SET A="A",A(1)=1,A(1,1)=1
+
+ WRITE $D(A(1)),!
+
+ ZWITHDRAW A(1)
+
+ WRITE $D(A(1)),!
+
+ ZWRITE A
+
+ QUIT
+
+ produces the result:
+
+
+ 11
+ 10
+ A="A"
+
+ A(1,1)=1
+
+ This sets up local variables A and A(1) and A(1,1). It then deletes the
+ data for A(1) with ZWITHDRAW. The ZWRITE command shows ZWITHDRAW KILLed
+ A(1) but left A and A(1,1).
+
+1 ZWRITE
+ ZWRite
+
+ The ZWRITE command displays the current value of one or more local or
+ global variables. ZWRITE formats its output so that each item in the
+ display forms a valid argument to a SET @ command. This means ZWRITE
+ encloses string values in quotes and represents non-graphic (control)
+ characters in $CHAR() syntax.
+
+ The format of the ZWRITE command is:
+
+
+ ZWR[ITE][:tvexpr] [zwrglvn[,...]]
+
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o The optional global or local variable name specifies the variable
+ for ZWRITE to display.
+
+ o ZWRITE accepts several alternative syntaxes in place of subscripts;
+ ZWRITE also accepts arguments specifying naked references to
+ globals. Because ZWRITE is primarily a debugging tool, ZWRITE does
+ not affect the naked indicator.
+
+ o ZWRITE accepts null subscripts in its arguments, when these are
+ allowed, and reports array nodes that have null subscripts.
+
+ o A ZWRITE with no arguments displays all the currently available
+ local variables; in this case, at least two (2) spaces must follow
+ the command to separate it from the next command on the line.
+
+ o If the global or local variable name is unsubscripted, ZWRITE
+ displays the unsubscripted variable and all subscripted
+ descendants.
+
+ o If an asterisk (*) appears in the space normally occupied by the
+ last subscript in a subscripted variable name, ZWRITE displays all
+ variable nodes descended from the previously specified subscripts.
+
+ o ZWRITE accepts GT.M pattern-match syntax in place of both variable
+ names and subscripts.
+
+ o ZWRITE <name>(), where <name> is a local or a global is treated as
+ a synonym for ZWRITE <name>.
+
+ o A colon acts as a range operator for subscript values; ZWRITE
+ displays all subscripts of the variable starting with the value on
+ the left side of the colon and ending with the value on the right
+ side of the colon; if the range delimiter has no left-hand value,
+ or has the empty string as the left-hand value, the display begins
+ at the first subscript; if the range delimiter has no right-hand
+ value or has the empty string as the right-hand value, the display
+ ends at the last subscript at that level; if the range delimiter
+ has no values or empty strings on either side, ZWRITE displays all
+ subscripts at that level; an empty subscript level also displays
+ all subscripts at that level.
+
+ o An indirection operator and an expression atom evaluating to a list
+ of one or more ZWRITE arguments form a legal argument for a ZWRITE.
+
+ o Long ZWRITE format records can be loaded.
+
+2 Ex_of_ZWRite
+ Examples of ZWRITE
+
+ Example:
+
+
+ GTM>ZWRITE ^?1"%"2U(0:":",)
+
+ This command displays the descendants of all subscripts between 0 and
+ ":" of all global names starting with a "%" and having two upper case
+ letters-for example, "%AB".
+
+ Example:
+
+
+ GTM>ZWRITE A(,:,3)
+
+ This command displays all of the third level nodes with a subscript of
+ 3 for local variable A.
+
+ Example:
+
+
+ ZWRITE ?1"A".E(?1"X"3N)
+
+ This would display data for any local variables starting with "A",
+ optionally followed by any characters, and having any subscripts
+ starting with "X" followed by three numerics.
+
+1 Functions
+ Functions
+
+ M Intrinsic Functions start with a single dollar sign ($) and have one
+ or more arguments enclosed in parentheses () and separated by commas
+ (,). These functions provide expression results by performing actions
+ that are impossible or difficult to perform using M commands.
+
+2 $ASCII()
+ $ASCII()
+
+ The $ASCII function returns the integer ASCII code for a character in a
+ string.
+
+ The format for the $ASCII function is:
+
+ $A[SCII](expr[,intexpr])
+
+ o The expression acts as the source string from which $ASCII()
+ extracts the character it decodes.
+
+ o The optional integer expression contains the position within the
+ expression of the character that $ASCII() decodes. If this argument
+ is missing, $ASCII() returns a result based on the first character
+ position. $ASCII() starts numbering character positions at one (1),
+ (i.e., the first character of a string is at position one (1)).
+
+ o If the explicit or implicit position is before the beginning or
+ after the end of the expression, $ASCII() returns a value of
+ negative one (-1).
+
+ $ASCII() provides a means of examining non-graphic characters in a
+ string. Used with $CHAR(), $ASCII() also provides a means to perform
+ arithmetic operations on the codes associated with characters.
+
+3 Ex_of_$ASCII()
+ Examples of $ASCII()
+
+ Example 1:
+
+
+ GTM> FOR i=0:1:3 WRITE !,$A("HI",i)
+
+ -1
+
+ 72
+ 73
+ -1
+
+ GTM>
+
+ This loop displays the result of $ASCII() specifying a character
+ position before, first and second positions, and after the string.
+
+ Example 2:
+
+
+ FOR i=1:1:$LENGTH($ZB) WRITE !,$A($ZB,i)
+
+ This loop displays the ASCII codes of the terminator in the Intrinsic
+ Special Variable, $ZB. Generally this is 13, for <CR>, or an escape
+ sequence.
+
+2 $Char()
+ $CHAR()
+
+ The $CHAR function returns a string of one or more characters
+ corresponding to integer ASCII codes specified in its argument(s).
+
+ The format for the $CHAR function is:
+
+
+ $C[HAR](intexpr[,...])
+
+ o The integer expression(s) specify the ASCII codes of the
+ character(s) $CHAR() returns.
+
+ The M standard does not restrict the number of arguments to $CHAR().
+ However, GT.M does limit the number of arguments to a maximum of 254.
+ $CHAR() provides a means of producing non-graphic characters, as such
+ characters cannot appear directly within an M string literal. Used with
+ $ASCII(), $CHAR() can also perform arithmetic operations on the codes
+ associated with characters.
+
+3 Ex_of_$CHAR()
+ Examples of $CHAR()
+
+ Example:
+
+
+ GTM> WRITE $CHAR(77,85,77,80,83,7)
+
+ MUMPS
+
+ GTM>
+
+ This example uses $CHAR() to WRITE the word MUMPS and signal the
+ terminal "bell."
+
+ Example:
+
+
+ SET nam=$E(nam,1,$L(nam)-1)_$C($A(nam,$L(nam))-1))
+
+ This example uses $CHAR() and $ASCII() to set the variable nam to a
+ value that immediately precedes its previous value in the set of
+ strings of the same length as nam.
+
+2 $Data()
+ $Data()
+
+ The $DATA function returns an integer code describing the value and
+ descendent status of a local or variable.
+
+ The format for the $DATA function is:
+
+
+ $D[ATA](glvn)
+
+ o The subscripted or unsubscripted global or local variable name
+ specifies the target node.
+
+ o If the variable is undefined, $DATA() returns 0.
+
+ o If the variable has a value but no descendants, $DATA() returns 1.
+
+ o If the variable has descendants but no value, $DATA() returns 10.
+
+ o If the variable has a value and descendants, $DATA() returns 11.
+
+3 Ex_of_$Data()
+ Examples of $DATA()
+
+ Example:
+
+
+ GTM> KILL WRITE $DATA(a)
+
+ 0
+ GTM> SET a(1)=1 WRITE $DATA(a(1))
+
+ 1
+ GTM> WRITE $DATA(a)
+
+ 10
+ GTM> SET a=0 WRITE $DATA(a)
+
+ 11
+ GTM>
+
+ This uses $DATA to display all possible $DATA() results.
+
+ Example:
+
+ L ^ACCT(0)
+
+ I '$D(^ACCT(0)) S ^ACCT(0)=0
+
+ S (ACCT,^ACCT(0))=^ACCT(0)+1
+
+ L
+
+ This uses $DATA() to determine whether a global node requires
+ initialization.
+
+ Example:
+
+ FOR SET cus=$O(^cus(cus)) Q:cus="" I $D(^(cus))>1 D WORK
+
+ This uses $DATA() to determine whether a global node has descendants
+ and requires additional processing.
+
+2 $Extract()
+ $EXTRACT()
+
+ The $EXTRACT function returns a substring of a given string.
+
+ The format for the $EXTRACT function is:
+
+
+ $E[XTRACT](expr[,intexpr1[,intexpr2]])
+
+ o The expression specifies a string from which $EXTRACT() derives a
+ substring.
+
+ o The first optional integer expression (second argument) specifies
+ the starting character position in the string expr of the substring
+ result. If the starting position is beyond the end of the
+ expression, $EXTRACT() returns the null string. If the starting
+ position is zero (0) or negative, $EXTRACT() starts at the first
+ position in the expression; if this argument is omitted, $EXTRACT()
+ returns the first character of the expression. $EXTRACT() numbers
+ character positions starting at one (1) (i.e., the first character
+ of a string is at position one (1)).
+
+ o The second optional integer expression (third argument) specifies
+ the ending character position for the result. If the ending
+ position is beyond the end of the expression, $EXTRACT() stops with
+ the last character of the expression. If the ending position
+ precedes the starting position, $EXTRACT() returns the null string.
+ If this argument is omitted, $EXTRACT() returns one character at
+ most.
+
+ $EXTRACT() provides a tool for manipulating strings based on character
+ positions.
+
+ A SET command argument can have something that has the format of a
+ $EXTRACT() on the left-hand side of its equal sign (=). This construct
+ permits easy maintenance of individual pieces within a string. It can
+ also be used to right justify a value padded with blank characters. For
+ more information on SET $EXTRACT(), refer to SET in the "Commands"
+ chapter.
+
+3 Ex_of_$Extract()
+ Examples of $EXTRACT()
+
+ Example:
+
+
+ GTM> FOR i=0:1:3 WRITE !,$EXTRACT("HI",i),"<"
+
+<
+ H<
+
+ I<
+
+<
+ GTM>
+
+ This loop displays the result of $EXTRACT(), specifying no ending
+ character position and a beginning character position "before, " first
+ and second positions, and "after" the string.
+
+ Example:
+
+
+ GTM> FOR i=0:1:3 WRITE !,$E("HI",1,i),"<"
+
+<
+ H<
+
+ HI<
+
+ HI<
+
+ GTM>
+
+ This loop displays the result of $EXTRACT() specifying a beginning
+ character position of 1 and an ending character position "before, "
+ first and second positions, and "after" the string.
+
+ Example:
+
+
+ TRIM(x)
+
+ NEW i,j
+
+ FOR j=$L(x):-1:0 S nx=$E(x,1,j) Q:$EXTRACT(x,j)'=" "
+
+ FOR i=1:1:j S fx=$E(nx,i,$L(x)) Q:$EXTRACT(x,i)'=" "
+
+ QUIT fx
+
+
+ GTM>SET str=" MUMPS "
+
+
+ GTM>WRITE $LENGTH(str)
+
+ 7
+ GTM>WRITE $LENGTH($$TRIM^trim(str))
+
+ 5
+ This extrinsic function uses $EXTRACT() to remove extra leading and
+ trailing spaces from its argument.
+
+2 $Find()
+ $FIND()
+
+ The $FIND function returns an integer character position that locates
+ the occurrence of a substring within a string.
+
+ The format for the $FIND function is:
+
+
+ $F[IND](expr1,expr2[,intexpr])
+
+ o The first expression specifies the string in which $FIND() searches
+ for the substring.
+
+ o The second expression specifies the substring for which $FIND()
+ searches.
+
+ o The optional integer expression identifies the starting position
+ for the $FIND() search. If this argument is missing, zero (0), or
+ negative, $FIND() begins its search in the first position of the
+ string.
+
+ o If $FIND() locates the substring, it returns the position after the
+ last character of the substring. If the end of the substring
+ coincides with the end of the string (expr1), it returns an integer
+ equal to the length of the string plus one ($L(expr1)+1).
+
+ o If $FIND() does not locate the substring, it returns zero (0).
+
+ $FIND() provides a tool to locate characters. The ( [ ) operator and
+ the two-argument $LENGTH() are other tools that provide related
+ functionality.
+
+3 Ex_of_$Find()
+ Examples of $FIND()
+
+ Example:
+
+
+ GTM> WRITE $FIND("HIFI","I")
+
+ 3
+ GTM>
+
+ This example uses $FIND() to WRITE the position of the first occurrence
+ of the character "I." The return of 3 gives the position after the
+ "found" substring.
+
+ Example:
+
+
+ GTM> WRITE $FIND("HIFI","I",3)
+
+ 5
+ GTM>
+
+ This example uses $FIND() to WRITE the position of the next occurrence
+ of the character "I" starting in character position three.
+
+ Example:
+
+
+ GTM> SET t=1 FOR SET t=$FIND("BANANA","AN",t) Q:'t W !,t
+
+ 4
+ 6
+ GTM>
+
+ This example uses a loop with $FIND() to locate all occurrences of "AN"
+ in "BANANA". The $FIND() returns 4 and 6 giving the positions after the
+ two occurrences of "AN".
+
+ Example:
+
+
+ GTM> SET str="MUMPS databases are hierarchical"
+
+
+ GTM>WRITE $FIND(str," ")
+
+ 7
+
+ GTM>WRITE $FIND(str,"Z")
+
+ 0
+
+ GTM>WRITE $FIND(str,"d",1)
+
+ 8
+
+ GTM>WRITE $FIND(str,"d",10)
+
+ 0
+ The above example searches a string for a sub string, and returns an
+ integer value which corresponds to the next character position after
+ locating the sub string.
+
+2 $FNumber()
+ $FNumber()
+
+ The $FNUMBER function returns a string containing a formatted number.
+
+ The format for the $FNUMBER function is:
+
+ $FN[UMBER](numexpr,expr[,intexpr])
+
+ o The numeric expression specifies the number that $FNUMBER()
+ formats.
+
+ o The expression (second argument) specifies zero or more single
+ character format control codes; if the expression contains any
+ character other than the defined codes, $FNUMBER() generates a
+ run-time error.
+
+ o The optional integer expression (third argument) specifies the
+ number of digits after the decimal point. If the numeric expression
+ has more digits than specified by this argument, $FNUMBER() rounds
+ to obtain the result. If the numeric expression has fewer digits
+ than specified by this argument, $FNUMBER() zero-fills to obtain
+ the result.
+
+ o When the optional third argument is specified and the first
+ argument evaluates to a fraction between -1 and 1, $FNUMBER()
+ returns a number with a leading zero (0) before the decimal point
+ (.).
+
+ $FNUMBER() formats or edits numbers, usually for reporting. For more
+ information on rounding performed by $FNUMBER(), refer to the section
+ on $JUSTIFY().
+
+ The formatting codes are:
+
+ + Forces a "+" on positive values.
+ - Suppresses the "-" on negative values.
+ , Inserts commas every third position to the left of the decimal
+ within the number.
+ T Represents the number with a trailing, rather than a leading
+ sign; positive numbers have a trailing space unless the expression
+ includes a plus sign (+).
+ P Represents negative values in parentheses, positive values with a
+ space on either side; combining with any other code except comma
+ (,) causes a run-time error.
+ M accepts both lower-case and upper-case alphabetic codes. The order of
+ the codes does not affect the result.
+
+3 Ex_of_$FNumber()
+ Examples of $FNUMBER()
+
+ Example:
+
+
+ SET X=-100000,Y=2000
+
+ WRITE "SUPPRESS NEGATIVE SIGN:",?35,$FNUMBER(X,"-"),!
+
+ WRITE "TRAILING SIGN:",?35,$FNUMBER(X,"T"),!
+
+ WRITE "NEGATIVE NUMBERS IN ():",?35,$FNUMBER(X,"P"),!
+
+ WRITE "COMMAS IN NUMBER:",?35,$FNUMBER(X,","),!
+
+ WRITE "NUMBER WITH FRACTION:",?35,$FNUMBER(X,"",2),!
+
+ WRITE "FORCE + SIGN IF POSITIVE:",?35,$FNUMBER(Y,"+"),!
+
+ Produces the results:
+
+
+ SUPPRESS NEGATIVE SIGN: 100000
+
+ TRAILING SIGN: 100000-
+
+ NEGATIVE NUMBERS IN (): (100000)
+
+ COMMAS IN NUMBER: -100,000
+
+ NUMBER WITH FRACTION: -100000.00
+
+ FORCE + SIGN IF POSITIVE: +2000
+
+ Example:
+
+
+ SET x=$FNUMBER(x,"-")
+
+ This example uses $FNUMBER() to SET x equal to its absolute value.
+
+2 $Get()
+ $Get()
+
+ The $GET function returns the value of a local or global variable if
+ the variable has a value. If the variable has no value, the function
+ returns a value specified by an optional second argument, and otherwise
+ returns a null string.
+
+ The format for the $GET function is:
+
+ $G[ET](glvn[,expr])
+
+ o The subscripted or unsubscripted global or local variable name
+ specifies the node for which $GET() returns a value.
+
+ o If the global or local variable has a data value, $GET() returns
+ the value of the variable.
+
+ o If the global or local variable has no data value, $GET() returns
+ the value of the optional expression (second argument), or a null
+ string if the expression is not specified.
+
+ M defines $GET(x,y) as equivalent to:
+
+
+ $SELECT($DATA(x)[0:y,1:x)
+
+ and $GET(x) as equivalent to:
+
+ $GET(x,"")
+
+ $GET() provides a tool to eliminate separate initialization of
+ variables. This technique may provide performance benefits when used to
+ increase the density of a sparse global array by eliminating nodes that
+ would otherwise hold absent optional information. On the other hand,
+ some uses of one argument $GET() can mask logic problems.
+
+ GT.M has a "NOUNDEF" mode of operation, which treats all variable
+ references as if they were arguments to a one argument $GET(). The VIEW
+ command and GTM$DEFAULTS controls "NOUNDEF" mode.
+
+3 Ex_of_$Get()
+ Examples of $GET()
+
+ Example:
+
+
+ I '$D(^PNT(NAME,TSTR)) S STATUS="NEW TEST"
+
+ E I ^PNT(NAME,TSTR)="" S STATUS="WAITING FOR RESULT"
+
+ E S STATUS=^PNT(NAME ,TSTR)
+
+ This example can be reduced to two lines of code by using $GET(), shown
+ in the following example. However, by using $GET() in its one-argument
+ form, the distinction between an undefined variable and one with a null
+ value is lost:
+
+
+ S STATUS=$G(^PNT(NAME,TSTR))
+
+ I STATUS="" S STATUS="WAITING FOR RESULT"
+
+ This is solved by using the two-argument form of $GET():
+
+
+ S STATUS=$G(^PNT(NAME,TSTR),"NEW TEST")
+
+ I STATUS="" S STATUS="WAITING FOR RESULT"
+
+2 $Justify()
+ $Justify()
+
+ The $JUSTIFY function returns a formatted string.
+
+ The format for the $JUSTIFY function is:
+
+
+ $J[USTIFY](expr,intexpr1[,intexpr2])
+
+ o The expression specifies the string formatted by $JUSTIFY().
+
+ o The first integer expression (second argument) specifies the
+ minimum size of the resulting string. If the first integer
+ expression is larger than the length of the expression, $JUSTIFY()
+ right justifies the expression to a string of the specified length
+ by adding leading spaces. Otherwise, $JUSTIFY() returns the
+ expression unmodified unless specified by the second integer
+ argument.
+
+ o The optional second integer expression (third argument) specifies
+ the number of digits to follow the decimal point in the result, and
+ forces $JUSTIFY() to evaluate the expression as numeric. If the
+ numeric expression has more digits than this argument specifies,
+ $JUSTIFY() rounds to obtain the result. If the expression had fewer
+ digits than this argument specifies, $JUSTIFY() zero-fills to
+ obtain the result.
+
+ o When the second argument is specified and the first argument
+ evaluates to a fraction between -1 and 1, $JUSTIFY() returns a
+ number with a leading zero (0) before the decimal point (.).
+
+ $JUSTIFY() fills expressions to create fixed length values. However, if
+ the length of the specified expression exceeds the specified field
+ size, $JUSTIFY() does not truncate the result (although it may still
+ round based on the third argument). When required, $EXTRACT() performs
+ truncation.
+
+ $JUSTIFY() optionally rounds the portion of the result after the
+ decimal point. In the absence of the third argument, $JUSTIFY() does
+ not restrict the evaluation of the expression. In the presence of the
+ third (rounding) argument, $JUSTIFY() evaluates the expression as a
+ numeric value. The rounding algorithm can be understood as follows:
+
+ o If necessary, the rounding algorithm extends the expression to the
+ right with 0s (zeros) to have at least one more digit than
+ specified by the rounding argument.
+
+ o Then, it adds 5 (five) to the digit position after the digit
+ specified by the rounding argument.
+
+ o Finally, it truncates the result to the specified number of digits.
+ The algorithm rounds up when excess digits specify a half or more
+ of the last retained digit and rounds down when they specify less
+ than a half.
+
+3 Ex_of_$Justify()
+ Examples of $JUSTIFY()
+
+ Example:
+
+
+ GTM> WRITE $JUSTIFY("HELLO",10),!,$JUSTIFY("GOODBYE",5)
+
+ HELLO
+
+ GOODBYE
+
+ GTM>
+
+ This uses $JUSTIFY() to display "HELLO" in a field of 10 spaces and
+ "GOODBYE" in a field of 5 spaces. Because the length of "GOODBYE"
+ exceeds five spaces, the result overflows the specification.
+
+ Example:
+
+
+ GTM> WRITE "1234567890",!,$JUSTIFY(10.545,10,2)
+
+ 1234567890
+ 10.55
+
+ GTM>
+
+ This uses $JUSTIFY() to WRITE a rounded value right justified in a
+ field of 10 spaces. Notice that the result has been rounded up.
+
+ Example:
+
+
+ GTM> WRITE "1234567890",!,$JUSTIFY(10.544,10,2)
+
+ 1234567890
+ 10.54
+
+ GTM>
+
+ Again, this uses $JUSTIFY() to WRITE a rounded value right justified in
+ a field of 10 spaces. Notice that the result has been rounded down.
+
+ Example:
+
+
+ GTM> WRITE "1234567890",!,$JUSTIFY(10.5,10,2)
+
+ 1234567890
+ 10.50
+
+ GTM>
+
+ Once again, this uses $JUSTIFY() to WRITE a rounded value right
+ justified in a field of 10 spaces. Notice that the result has been
+ zero-filled to 2 places.
+
+ Example:
+
+
+ GTM> WRITE $JUSTIFY(.34,0,2)
+
+ 0.34
+ GTM>
+
+ This example uses $JUSTIFY to ensure that the fraction has a leading
+ zero. Note the use of a second argument of zero in the case that
+ rounding is the only function that $JUSTIFY is to perform.
+
+2 $Length()
+ $Length()
+
+ The $LENGTH function returns the length of a string measured in
+ characters, or in "pieces" separated by a delimiter specified by one of
+ its arguments.
+
+ The format for the $LENGTH function is:
+
+
+ $L[ENGTH](expr1[,expr2])
+
+ o The first expression specifies the string that $LENGTH()
+ "measures."
+
+ o The optional second expression specifies the delimiter that defines
+ the measure; if this argument is missing, $LENGTH() returns the
+ number of characters in the string.
+
+ o If the second argument is present and not a null string, $LENGTH
+ returns one more than the count of the number of occurrences of the
+ second string in the first string; if the second argument is a null
+ string, the M standard specifies that $LENGTH() returns a zero (0).
+
+ $LENGTH() provides a tool for determining the lengths of strings in two
+ ways, characters and pieces. The two argument $LENGTH() returns the
+ number of existing pieces, while the one argument returns the number of
+ characters.
+
+3 Ex_of_$Length()
+ Examples of $LENGTH()
+
+ Example:
+
+
+ GTM> WRITE $LENGTH("KINGSTON")
+
+ 8
+ GTM>
+
+ This uses $LENGTH() to WRITE the length in characters of the string
+ "KINGSTON".
+
+ Example:
+
+
+ GTM> SET x="Smith/John/M/124 Main Street/Ourtown/KA/USA"
+
+ GTM> WRITE $LENGTH(x,"/")
+
+ 7
+ GTM>
+
+ This uses $LENGTH() to WRITE the number of pieces in a string, as
+ delimited by /.
+
+ Example:
+
+
+ GTM> WRITE $LENGTH("/2/3/","/")
+
+ 4
+ GTM>
+
+ This also uses $LENGTH() to WRITE the number of pieces in a string, as
+ delimited by /. Notice that GT.M. adds one count to the final number of
+ pieces (in this case 3), in the string (displays 4).
+
+2 $NAme()
+ $NAme()
+
+ The $NAME function returns an evaluated representation of some or all
+ of a local or global variable name.
+
+ The format for the $NAME function is:
+
+
+ $NA[ME](glvn[,intexpr])
+
+ o The subscripted or unsubscripted global or local variable name,
+ including naked references, specifies the name for which $NAME()
+ returns an evaluated representation.
+
+ o The optional integer expression (second argument) specifies the
+ maximum number of subscript levels in the representation. If the
+ integer expression is not provided or exceeds the actual number of
+ subscript levels, $NAME() returns a representation of the whole
+ name. If the integer expression is zero (0), $NAME() returns only
+ the name. A negative integer expression produces a run-time error.
+
+3 Ex_of_$Name()
+ Examples of $NAME()
+
+ Example:
+
+
+ GTM> SET X="A""B",^Y(1,X,"B",4)=""
+
+ GTM> WRITE $NAME(^(3),3)
+
+ ^Y(1,"A""B","B")
+
+ GTM>
+
+ This example sets up a naked reference and then uses $NAME() to display
+ the first three levels of that four-level reference.
+
+ Example:
+
+
+ GTM> WRITE $NAME(^(3),0)
+
+ ^Y
+
+ GTM>
+
+ This example shows the name level for the same naked reference.
+
+2 $Next()
+ $Next()
+
+ The $NEXT function returns the next subscripted local or global
+ variable name in collation sequence within the array level specified by
+ its argument.
+
+ $NEXT() has been replaced by $ORDER(). $NEXT has been retained in the
+ current standard only for compatibility with earlier versions of the
+ standard. $NEXT() is similar to $ORDER(). However, $NEXT() has the
+ deficiency that when it encounters negative one (-1) as a subscript, it
+ returns the same result as when it finds no other data at the level.
+ This deficiency is particularly disruptive because it occurs in the
+ middle of the M collating sequence.
+
+ As $NEXT() has been removed from the standard in the MDC, you
+ should use $ORDER.
+
+ The format for the $NEXT function is:
+
+
+ $N[EXT](glvn)
+
+ o The subscripted global or local variable name specifies the node
+ following which $NEXT() searches for the next node with data and/or
+ descendants; the number of subscripts contained in the argument
+ implicitly defines the array level.
+
+ o If $NEXT() finds no node at the specified level after the specified
+ global or local variable, it returns negative one (-1).
+
+ o If the last subscript in a subscripted global or local variable
+ name is null or negative one (-1), $NEXT() returns the first node
+ at the specified level.
+
+2 $Order()
+ $Order()
+
+ The $ORDER function returns the subscript of the next or prior local or
+ global variable name in collation sequence within the array level
+ specified by its first argument. In doing so, it moves in the direction
+ specified by the second argument. In GT.M, when $ORDER() has an
+ unsubscripted argument, it returns the next or previous unsubscripted
+ local or global variable name in collating sequence.
+
+ The format for the $ORDER function is:
+
+
+ $O[RDER](glvn[,expr])
+
+ o The subscripted global or local variable name specifies the node
+ from which $ORDER() searches for the next or previous node that has
+ data and/or descendants. The number of subscripts contained in the
+ argument implicitly defines the array level.
+
+ o The optional expression (second argument) specifies the direction
+ for the $ORDER(); 1 specifies forward operation and -1 specifies
+ reverse operation. Any other values for the expression will cause
+ an error.
+
+ o GT.M extends the M standard to allow unsubscripted names. In this
+ case, $ORDER() returns the next or previous unsubscripted name.
+
+ o If $ORDER() finds no node (or name) at the specified level after
+ (or before) the specified global or local variable, it returns a
+ null string (" ").
+
+ o If the last subscript in the subscripted global or local variable
+ name is null, $ORDER() returns the first (or last) node at the
+ specified level.
+
+ $ORDER() provides a tool for retrieving data from M sparse arrays in an
+ ordered fashion, independent of the order in which it was entered. In
+ M, routines generally sort by SETting data into an array with
+ appropriate subscripts and then retrieving the information with
+ $ORDER().
+
+ $ORDER() returns subscripts, not data values, and does not discriminate
+ between nodes that have data values and nodes that have descendants.
+ Once $ORDER() provides the subscript, the routine must use the
+ subscript to access the data value, if appropriate. Using $ORDER()
+ maintains the naked reference indicator, even if $ORDER() returns a
+ null.
+
+ GT.M optionally permits the use of null subscripts. This feature is
+ enabled via the VIEW command for local variables and a REGION qualifier
+ in GDE for global variables. When an application uses null subscripts,
+ they are "invisible" in a $ORDER() loop so the application must test
+ for them as a special case, perhaps using $DATA().
+
+3 Ex_of_$Order()
+ Examples of $ORDER()
+
+ Example:
+
+
+ GTM>K S (a(1),a(2000),a("CAT"),a("cat"),a("ALF"), a(12))=1
+
+ GTM>S x="" F S x=$O(a(x)) Q:x="" W !,x
+
+ 1
+ 12
+ 2000
+ ALF
+
+ CAT
+
+ cat
+
+ GTM>K a("CAT") SET a(5,10)="woolworths",a("cat")="last"
+
+ GTM> S x="" F S x=$O(a(x),-1) Q:x="" W !,x
+
+ cat
+
+ ALF
+
+ 2000
+ 12
+ 5
+ 1
+ GTM>
+
+ This example uses a $ORDER() loop to display all the subscripts at the
+ first level of local variable a, make some changes in a, and then
+ display all the subscripts in reverse order. Notice that $ORDER()
+ returns only the existing subscripts in the sparse array and returns
+ them in M collation sequence, regardless of the order in which they
+ were entered. Also, $ORDER() does not differentiate between node A(5),
+ which has only descendants (no data value), and the other nodes, which
+ have data values.
+
+ Example:
+
+
+ GTM>k s (%(1),tiva(2),A(3),tiv(4),Q(5),%a(6))=""
+
+ GTM>s x="%"
+
+ GTM>w:$d(@x) !,x f s x=$order(@x) q:x="" w !,x
+
+ %
+
+ %a
+
+ A
+
+ Q
+
+ tiv
+
+ tiva
+
+ x
+
+ GTM>s x="zzzzzzzz"
+
+ GTM>w:$d(@x) !,x f s x=$order(@x,-1) q:x="" w !,x
+
+ x
+
+ tiva
+
+ tiv
+
+ Q
+
+ A
+
+ %a
+
+ %
+
+ GTM>
+
+ This loop uses $ORDER() to display the current local variable names in
+ both forward and reverse order. Notice that the first ([^]%) and last
+ ([^]zzzzzzzz) names require handling as special cases and require a
+ $DATA() function.
+
+ Example:
+
+
+ SET acct="",cntt=""
+
+ FOR SET acct=$OREDER(^acct(acct)) QUIT:acct="" DO
+
+ . F SET cntt=$ORDER(^acct(acct,cntt)) DO WORK
+
+ QUIT
+
+ This uses two nested $ORDER() loops to cycle through the ^acct global
+ array and perform some action for each second level node.
+
+2 $Piece()
+ $Piece()
+
+ The $PIECE function returns a substring delimited by a specified string
+ delimiter made up of one or more characters. In M, $PIECE() returns a
+ logical field from a logical record.
+
+ The format for the $PIECE function is:
+
+
+ $P[IECE](expr1,expr2[,intexpr1[,intexpr2]])
+
+ o The first expression specifies the string from which $PIECE() takes
+ its result.
+
+ o The second expression specifies the delimiting string that
+ determines the piece "boundaries"; if this argument is a null
+ string, $PIECE() returns a null string.
+
+ o If the second expression does not appear anywhere in the first
+ expression, $PIECE() returns the entire first expression (unless
+ forced to return a null string by the second integer expression).
+
+ o The optional first integer expression (third argument) specifies
+ the beginning piece to return; if this argument is missing,
+ $PIECE() returns the first piece.
+
+ o The optional second integer expression (fourth argument) specifies
+ the last piece to return. If this argument is missing, $PIECE()
+ returns only one piece unless the first integer expression is zero
+ (0) or negative, in which case it returns a null string. If this
+ argument is less than the first integer expression, $PIECE()
+ returns a null string.
+
+ o If the second integer expression exceeds the actual number of
+ pieces in the first expression, $PIECE() returns all of the
+ expression after the delimiter selected by the first integer
+ expression.
+
+ o The $PIECE() result never includes the "outside" delimiters;
+ however, when the second integer argument specifies multiple
+ pieces, the result contains the "inside" occurrences of the
+ delimiter.
+
+ $PIECE() provides a tool for efficiently using values that contain
+ multiple elements or fields, each of which may be variable in length.
+
+ Applications typically use a single character for a $PIECE() delimiter
+ (second argument) to minimize storage overhead, and increase efficiency
+ at run-time. The delimiter must be chosen so the data values never
+ contain the delimiter. Failure to enforce this convention with edit
+ checks may result in unanticipated changes in the position of pieces
+ within the data value. The caret symbol (^), backward slash (\), and
+ asterisk (*) characters are examples of popular visible delimiters.
+ Multiple character delimiters may reduce the likelihood of conflict
+ with field contents. However, they decrease storage efficiency, and are
+ processed with less efficiency than single character delimiters. Some
+ applications use control characters, which reduce the chances of the
+ delimiter appearing in the data but sacrifice the readability provided
+ by visible delimiters.
+
+ A SET command argument can have something that has the format of a
+ $PIECE() on the left-hand side of its equal sign (=). This construct
+ permits easy maintenance of individual pieces within a string. It also
+ can be used to generate a string of delimiters. For more information on
+ SET $PIECE(), refer to SET in the "Commands" chapter.
+
+3 Ex_of_$Piece()
+ Examples of $PIECE()
+
+ Example:
+
+
+ GTM> FOR i=0:1:3 WRITE !,$PIECE("1 2"," ",i),"<"
+
+<
+ 1<
+ 2<
+<
+ GTM>
+
+ This loop displays the result of $PIECE(), specifying a space as a
+ delimiter, a piece position "before," first and second, and "after" the
+ string.
+
+ Example:
+
+
+ GTM> FOR i=-1:1:3 WRITE !,$PIECE("1 2"," ",i,i+1),"<"
+
+<
+ 1<
+ 1 2<
+ 2<
+<
+ GTM>
+
+ This example is similar to the previous example except that it displays
+ two pieces on each iteration. Notice the delimiter (a space) in the
+ middle of the output for the third iteration, which displays both
+ pieces.
+
+ Example:
+
+
+ F p=1:1:$L(x,"/") W ?p-1*10,$piece(x,"/",p)
+
+ This loop uses $LENGTH() and $PIECE() to display all the pieces of x in
+ columnar format.
+
+ Example:
+
+
+ GTM> s $P(x,".",25)="" W x
+
+ ........................
+ This SETs the 25th piece of the variable x to null, with a delimiter of
+ a period. This produces a string of 24 periods preceding the null.
+
+2 $Qlength()
+ $Qlength()
+
+ The $QLENGTH function returns the number of subscripts in a variable
+ name. The format is:
+
+
+ $QL[ENGTH] (namevalue)
+
+ o The namevalue has the form of an evaluated subscripted or
+ unsubscripted global variable (which yields a length of zero, and
+ which may have an environment - not counted) or local variable
+ name.
+
+ o The form returns a value which is derived from namevalue. If
+ namevalue has the form NAME(s1, s2,..., sn), considering n to be
+ zero, if there are no subscripts, then the function returns n.
+
+ o This function only affects the naked indicator if the string in
+ question is stored in a global variable.
+
+3 Ex_of_$Qlength()
+ Examples of $Qlength()
+
+ Example:
+
+
+ WRITE $DATA(^|"XXX"|ABC(1,2,3,4))
+
+
+ GTM>0
+
+
+ SET X=$NAME(^(5,6))
+
+ WRITE $QLENGTH(X)
+
+ GTM>5
+
+ Refer to $NAme() section earlier in this chapter for an understanding
+ of the $NAME function.
+
+2 $Qsubscript()
+ $Qsubscript()
+
+ The $QSUBSCRIPT function returns a component of a variable name.
+
+ The format of the $QSUBSCRIPT function is:
+
+
+ $QS[UBSCRIPT](namevalue, intexpr)
+
+ o The namevalue has the form of an evaluated subscripted or
+ unsubscripted global or local variable name.
+
+ o The intexpr selects the component of the name as follows:
+
+ -2 is reserved but may be "error",
+
+ -1 for environment,
+
+ 0 for the unsubscripted name,
+ 1 for the first subscript,
+ 2 for the second subscript, and so on.
+ If the second argument selects a component that is not part of the
+ specified name, $QSUBSCRIPT() returns an empty string ("").
+
+3 Ex_of_$Qsubscript()
+ Examples of $Qsubscript()
+
+ Example:
+
+ Assume that X is defined as in the "Examples of $Qlength()" earlier in
+ this chapter;
+
+
+ $QLENGTH (X="^|""XXX""|ABC(1,2,3,5,6)")
+
+
+ WRITE $QSUBSCRIPT(X,-2)
+
+ GTM>error
+
+
+ WRITE $QSUBSCRIPT(X,-1)
+
+ GTM>XXX
+
+
+ WRITE $QSUBSCRIPT(X,0)
+
+ GTM>^ABC
+
+
+ WRITE $QSUBSCRIPT(X,1)
+
+ GTM>1
+
+
+ WRITE $QSUBSCRIPT(X,4)
+
+ GTM>5
+
+
+ WRITE $QSUBSCRIPT(X,7)
+
+ GTM>""
+
+2 $Query()
+ $Query()
+
+ The $QUERY function returns the next subscripted local or global
+ variable node name, independent of level, which follows the node
+ specified by its argument in M collating sequence and has a data value.
+
+ The format for the $QUERY function is:
+
+
+ $Q[UERY](glvn)
+
+ o The subscripted or unsubscripted global or local variable name
+ specifies the starting node from which $QUERY() searches for a node
+ with a data value.
+
+ o If $QUERY() finds no node after the specified global or local
+ variable, it returns a null string.
+
+ $QUERY() provides a tool for scanning an entire array for nodes that
+ have data values. Because $QUERY() can return a result specifying a
+ different level than its argument, the result provides a full variable
+ name. This contrasts with $ORDER(), which returns a subscript value. To
+ access the data value at a node, a $ORDER() return can be used as a
+ subscript; however, a $QUERY() return must be used with indirection.
+ Because arrays tend to have homogeneous values within a level but not
+ between levels, $QUERY() is more useful as a tool in utility programs
+ than in application programs. The $QUERY() is useful in avoiding nested
+ $ORDER loops.
+
+ Note that the standard does not unambiguously define the state of the
+ naked reference indicator after a $QUERY(). While in GT.M after
+ $QUERY(), the naked reference indicator reflects the $QUERY() argument,
+ NOT its result.
+
+3 Ex_of_$Query()
+ Examples of $QUERY()
+
+ Example:
+
+
+ SET ^X(1,2,3)="123"
+
+ SET ^X(1,2,3,7)="1237"
+
+ SET ^X(1,2,4)="124"
+
+ SET ^X(1,2,5,9)="1259"
+
+ SET ^X(1,6)="16"
+
+ SET ^X("B",1)="AB"
+
+ The following routine:
+
+
+ SET y="^X"
+
+ FOR SET y=$QUERY(@y) QUIT:y="" WRITE !,y,"=", at y
+
+ produces the results:
+
+
+ ^X(1,2,3)=123
+
+ ^X(1,2,3,7)=1237
+
+ ^X(1,2,4)=124
+
+ ^X(1,2,5,9)=1259
+
+ ^X(1,6)=16
+
+ ^X("B",1)=AB
+
+2 $Random()
+ $Random()
+
+ The $RANDOM function returns a random integer from a range specified by
+ its argument.
+
+ The format for the $RANDOM function is:
+
+
+ $R[ANDOM](intexpr)
+
+ o The integer expression specifies the upper exclusive limit of a
+ range of integers from which $RANDOM() may pick a result; $RANDOM()
+ never returns a number less than zero (0).
+
+ o If $RANDOM() has an argument less than one (1), it generates a
+ run-time error.
+
+ o $RANDOM can generate numbers up to 2147483646 (that is 2GB - 2).
+
+ $RANDOM() provides a tool for generating pseudo-random patterns useful
+ in testing or statistical calculations. $RANDOM() results fall between
+ zero (0) and one less than the argument.
+
+ Random number generators use factors from the environment to create
+ sequences of numbers. True random number generation requires a source
+ of what is known as noise. Pseudo-random numbers appear to have no
+ pattern, but are developed using interactions between factors that vary
+ in ways not guaranteed to be entirely random. In accordance with the M
+ standard, the GT.M implementation of $RANDOM() produces pseudo-random
+ numbers.
+
+3 Ex_of_$Random()
+ Examples of $RANDOM()
+
+ Example:
+
+
+ GTM> FOR i=1:1:10 WRITE $RANDOM(1)
+
+ 0000000000
+ GTM>
+
+ This shows that when $RANDOM() has an argument of one (1), the result
+ is too confined to be random.
+
+ Example:
+
+
+ SET x=$RANDOM(100)+1*.01
+
+ This $RANDOM() example produces a number between 0 and 99. The example
+ then shifts with addition, and scales with multiplication to create a
+ value between .01 and 1.
+
+2 $Reverse()
+ $Reverse()
+
+ The $REVERSE function returns a string with the characters in the
+ reverse order from that of its argument.
+
+ The format for the $REVERSE function is:
+
+
+ $RE[VERSE](expr)
+
+ o The expr in the syntax is the string to be reversed.
+
+3 Ex_of_$Reverse()
+ Examples of $REVERSE()
+
+ Example:
+
+
+ WRITE $REVERSE(123)
+
+ GTM>321
+
+
+ WRITE $REVERSE("AbCDe")
+
+ GTM>"eDCbA"
+
+2 $Select()
+ $Select()
+
+ The $SELECT function returns a value associated with the first true
+ truth-valued expression in a list of paired expression arguments.
+
+ The format for the $SELECT function is:
+
+
+ $S[ELECT](tvexpr:expr[,...])
+
+ o $SELECT() evaluates expressions from left to right.
+
+ o If a truth-valued expression is TRUE (1), $SELECT() returns the
+ corresponding expression after the colon (:) delimiter.
+
+ o Once $SELECT() finds a TRUE, the function does not process any
+ remaining arguments.
+
+ o If $SELECT() finds no TRUE truth-value in its list of arguments,
+ the function generates a run-time error.
+
+ $SELECT() is one of a limited set of functions that permit an
+ indefinite number of arguments. $SELECT() provides a means of selecting
+ from a list of alternatives.
+
+ Generally, the last $SELECT() argument has numeric literal one (1) for
+ a truth-value to prevent run-time errors, and to provide a "default"
+ value.
+
+3 Ex_of_$Select()
+ Examples of $SELECT()
+
+ Example:
+
+
+ GTM> F i=3:-1:0 W !,$S(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 true argument on the fourth iteration, when i=0, $SELECT() produces
+ an error.
+
+ Example:
+
+
+ SET name=$S(sex="M":"Mr. ",sex="F":"Ms. ",1:"")_name
+
+ This example uses $SELECT() to add a prefix to the name based on a sex
+ code held in the variable sex. Notice that the default handles the case
+ of a missing or incorrect code.
+
+ Example:
+
+
+ IF $S(x=+x:x,x="":0,"JANAPRJULOCT"[x:1,1:0) D THING
+
+ This uses $SELECT() to perform complex logic as the truth-valued
+ expression argument to an IF command.
+
+2 $Stack()
+ $Stack()
+
+ The $STACK function returns strings describing aspects of the execution
+ environment.
+
+ The format for the $STACK function is:
+
+
+ $ST[ACK](intexpr[,expr])
+
+ o The intexpr identifies the M virtual machine stack level (as
+ described by the standard), on which the function is to provide
+ information.
+
+ o The optional second argument is evaluated as a keyword that
+ specifies a type of information to be returned as follows: "PLACE"
+ for position in the code (for which, GT.M. due to its compiled
+ nature, has no information), "MCODE" for the source code if
+ available, or "ECODE" for the $ECODE value associated with the
+ stack level.
+
+ o When $STACK has only one argument, values corresponding to
+ available stack levels specify a return value that indicates how
+ the level was created, as follows:
+
+ o If intexpr is zero (0), the function returns information on how
+ GT.M was invoked.
+
+ o If intexpr is minus one (-1), the function returns the highest
+ level for which $STACK can return information. Note that, if
+ $ECODE="", $STACK(-1) returns the same value as $STACK.
+
+ o If intexpr is greater than zero (0) and less than or equal to
+ $STACK (-1), indicates how this level of process stack was created
+ ("DO", "XECUTE", or "$$". "$$" being for an extrinsic function).
+
+ o If intexpr is greater than $STACK (-1), the function returns an
+ empty string.
+
+ o For any integer value of "level" between 0 and max (inclusive), the
+ function $STACK(level, type) provides the following information:
+
+ Type Information
+ "MCODE" the line of code that was executed
+ "PLACE" the address of the above line of code or the symbol at
+ ("@") to indicate code executed from a string value
+ "ECODE" either an empty string, or the error code(s) that was added
+ at this execution level.
+3 Ex_of_$Stack()
+ Examples of $STACK()
+
+ Example:
+
+
+ WRITE !,$STACK
+
+ XECUTE "WRITE !,$STACK"
+
+ DO Label
+
+ WRITE !,$$ELabel
+
+ WRITE !,$STACK
+
+ QUIT
+
+
+ Label
+
+ WRITE !,$STACK
+
+ DO DLabel
+
+ QUIT
+
+
+ ELabel()
+
+ QUIT $STACK
+
+
+ DLabel
+
+ WRITE !,$STACK
+
+ QUIT
+
+ The above example when executed displays the current M stack level. The
+ result of the execution is:
+
+
+ GTM>0
+
+ 1
+ 1
+ 2
+ 1
+ 0
+ Example for error processing:
+
+
+ For i=$STACK(-1):-1:1 DO
+
+ . WRITE !,$STACK(i,"PLACE"),":"
+ . WRITE $STACK(i,"MCODE")
+ . QUIT
+ The above example can be used to display a trace of the code path that
+ led to an error.
+
+2 $Text()
+ $Text()
+
+ The $TEXT function returns source text for the line specified by its
+ argument.
+
+ The format for the $TEXT function is:
+
+
+ $T[EXT](entryref)
+
+ o The entryref specifies the label, offset, and routine of the source
+ line that $TEXT() returns.
+
+ o If the label+offset combination do not fall within the routine,
+ $TEXT returns a null string.
+
+ o If the entryref explicitly or implicitly specifies an offset of
+ zero (0) from the beginning of the routine, $TEXT() returns the
+ routine name.
+
+ o If the entryref does not specify a routine, GT.M assumes the
+ current routine, that is, the routine at the top of a ZSHOW "S."
+
+ o A GT.M extension to $TEXT() permits negative offsets; however,
+ every offset must still be preceded by a plus sign (+) delimiter,
+ (for example, LABEL+-3). If a negative offset points to a line
+ prior to the zero line, $TEXT() generates a run-time error.
+
+ $TEXT() provides a tool for examining routine source code and the name
+ of the current routine. $TEXT() assists, along with the ZPRINT command,
+ in debugging programs. $TEXT() also allows the insertion of small
+ tables of driver information into a routine. Because $TEXT() is not
+ very efficient and the table-driven technique is generally best suited
+ to minimal program changes, this approach is best used for prototyping
+ and the tables should reside in global variables for production.
+
+ If $TEXT() cannot access the source file for the current object, either
+ because it is not in the location from which it was compiled or because
+ the process does not have access to some piece of the path to the
+ source, or if the located source does not match the object currently in
+ use by the process, $TEXT() returns the empty string.
+
+3 Ex_of_$Text()
+ Examples of $TEXT()
+
+ Example:
+
+
+ F i=1:1 S x=$T(+i) Q:x="" W !,x
+
+ This loop uses $TEXT() to write out the entire source for the current
+ routine.
+
+ Example:
+
+
+ GTM> WRITE $TEXT(+0)
+
+ GTM$DMOD
+
+ GTM> WRITE $TEXT(+1)
+
+ GTM>
+
+ This uses $TEXT() to WRITE the name of the current routine, then it
+ tries to access the source and returns an empty string. This occurs
+ because the default Direct Mode image is compiled by Sanchez and
+ delivered without source. The exact failure message may vary.
+
+2 $TRanslate()
+ $TRanslate()
+
+ The $TRANSLATE function returns a string that results from replacing or
+ dropping characters in the first of its arguments as specified by the
+ patterns of its other arguments.
+
+ The format for the $TRANSLATE function is:
+
+
+ $TR[ANSLATE](expr1[,expr2[,expr3]])
+
+ o The first expression specifies the string on which $TRANSLATE()
+ operates. If the other arguments are omitted, $TRANSLATE() returns
+ this expression.
+
+ o The optional second expression specifies the characters for
+ $TRANSLATE() to replace. If a character occurs more than once in
+ the second expression, the first occurrence controls the
+ translation, and $TRANSLATE() ignores subsequent occurrences. If
+ this argument is omitted, $TRANSLATE() returns the first expression
+ without modification.
+
+ o The optional third expression specifies the replacement characters
+ for the second expression that corresponds by position. If this
+ argument is omitted or shorter than the second expression,
+ $TRANSLATE() drops all occurrences of characters in the second
+ expression that have no replacement in the corresponding position
+ of the third expression.
+
+ $TRANSLATE() provides a tool for tasks such as changing case and doing
+ encryption. For examples of case translation, refer to the ^%LCASE and
+ ^%UCASE utility routines.
+
+ The $TRANSLATE() algorithm can be understood as follows:
+
+ o $TRANSLATE() evaluates each character in the first expression,
+ comparing it character by character to the second expression
+ looking for a match. If there is no match in the second expression,
+ the resulting expression contains the character without
+ modification.
+
+ o When it locates a character match, $TRANSLATE() uses the position
+ of the match in the second expression to identify the appropriate
+ replacement for the original expression. If the second expression
+ has more characters than the third expression, $TRANSLATE()
+ replaces the original character with a null, thereby deleting it
+ from the result. By extension of this principle, if the third
+ expression is missing, $TRANSLATE() deletes all characters from the
+ first expression that occur in the second expression.
+
+3 Ex_of_$TRanslate()
+ Examples of $TRANSLATE()
+
+ Example:
+
+
+ GTM> WRITE $TR("ABC","CB","1")
+
+ A1
+
+ GTM>
+
+ o First, $TRANSLATE() searches for "A" (the first character in the
+ first expression, "ABC") within the second expression ("CB"). Since
+ "A" does not exist in the second expression, it appears unchanged
+ in the result.
+
+ o Next, $TRANSLATE() searches for "B" (the second character in the
+ first expression) within the second expression ("CB"). Because "B"
+ holds the second position in the second expression ("CB"),
+ $TRANSLATE() searches for the character holding the second position
+ in the third expression. Since there is no second character in the
+ third expression, $TRANSLATE() replaces "B" with a null,
+ effectively deleting it from the result.
+
+ o Finally, $TRANSLATE() searches for "C" (the third character in the
+ first expression) within the second expression ("CB"), finds it in
+ the first position, and replaces it with the number 1, which is in
+ the first position of the third expression. The translated result
+ is "A1."
+
+ Example:
+
+
+ GTM> WRITE $TR("A","AA","BC")
+
+ B
+
+ GTM>
+
+ This $TRANSLATE() example finds the first occurrence of "A" in the
+ second expression, which holds the first character position, and
+ substitutes the character in the first position of the third
+ expression.
+
+ Example:
+
+
+ GTM> WRITE $TR("BACKUP","AEIOU")
+
+ BCKP
+
+ GTM>
+
+ Because the $TRANSLATE() has only two parameters in this example, it
+ finds the characters in the first expression that also exist in the
+ second expression and deletes them from the result.
+
+2 $View()
+ $View()
+
+ The $VIEW function returns information about an environmental factor
+ selected by the arguments. In GT.M, the first argument contains a
+ keyword identifying the environmental factor and, where appropriate,
+ subsequent arguments select among multiple possible occurrences of that
+ factor.
+
+ The format for the $VIEW() function is:
+
+
+ $V[IEW](expr1[,expr2])
+
+ o The first expression specifies a keyword identifying the target
+ factor for $VIEW() to examine.
+
+ o The second expression differentiates between multiple possible
+ targets for some keywords. $VIEW() requires the second expression
+ for some keywords and does not permit it for others.
+
+ The $VIEW function returns 1 (true) if the region is frozen by MUPIP or
+ DSE and returns 0 (false) otherwise.
+
+3 Arg_Key_of_$View()
+ Argument Keywords of $VIEW()
+
+ $VIEW() provides a means of accessing GT.M environmental information.
+ $VIEW() is similar in purpose to Intrinsic Special Variables. When GT.M
+ permits modification of the factors accessible with $VIEW(), the VIEW
+ command generally provides the tool for performing the change.
+
+3 Ex_of_$View()
+ Examples of $VIEW()
+
+ Example:
+
+
+ S len=$L(name)
+
+ S be4=$EXTRACT(name,1,len-1)_$CHAR($ASCII(name,len)-1)
+
+ I $V("RTNNEXT",be4_$E("ZZZZZZZ",1,8-len))=name D
+
+ . ZLINK name
+ Given a routine name this uses $VIEW() to determine whether the image
+ contains the routine. If the routine already exists the ZLINK replaces
+ it. Otherwise, auto-ZLINK will bring in a new copy.
+
+2 $ZBIT_Func
+ $ZBIT Functions
+
+ A series of functions beginning with $ZBIT let you manipulate bits.
+ Each function is described in its own section, and an example at the
+ end of the last section illustrates the use of several of the functions
+ in context.
+
+3 $ZBITAND()
+ $ZBITAND()
+
+ The $ZBITAND function performs an AND function on two bit strings and
+ returns a bit string equal in length to the shorter of the two
+ arguments (containing set bits in those positions where both of the
+ input strings have set bits). Positions corresponding to positions
+ where either of the input strings have a cleared bit, also have cleared
+ bits in the resulting string.
+
+ The format for the $ZBITAND() function is:
+
+
+ $ZBITAND(expr1,expr2)
+
+ o The first expression specifies one of the bit strings that is input
+ to the AND operation.
+
+ o The second expression specifies the other bit string that is input
+ to the AND operation.
+
+3 $ZBITCOUNT()
+ $ZBITCOUNT()
+
+ The $ZBITCOUNT function returns the number of ON bits in a bit string.
+
+ The format for the $ZBITCOUNT function is:
+
+
+ $ZBITCOUNT(expr)
+
+ o The expression specifies the bit string to examine.
+
+3 $ZBITFIND()
+ $ZBITFIND()
+
+ The $ZBITFIND function performs the analog of the $FIND function on a
+ bit string. It returns an integer that identifies the position after
+ the first position equal to a truth-valued expression that occurs at,
+ or after, the specified starting position.
+
+ The format for the $ZBITFIND function is:
+
+
+ $ZBITFIND(expr,tvexpr[,intexpr])
+
+ o The expression specifies the bit string to examine.
+
+ o The truth-valued expression specifies the bit value for which
+ $ZBITFIND() searches (1 or 0).
+
+ o The optional integer argument specifies the starting position at
+ which to begin the search. If this argument is missing, $ZBITFIND()
+ begins searching at the first position of the string. $ZBIT
+ functions count the first bit as position one (1).
+
+ If the optional integer argument exceeds the length of the string, or
+ if the function finds no further bits, $ZBITFIND() returns a zero
+ value.
+
+3 $ZBITGET()
+ $ZBITGET()
+
+ The $ZBITGET function returns the value of a specified position in the
+ bit string.
+
+ The format for the $ZBITGET function is:
+
+
+ $ZBITGET(expr,intexpr)
+
+ o The expression specifies the bit string to examine.
+
+ o The integer argument specifies the position in the string for which
+ the value is requested. If the integer argument is negative, zero,
+ or exceeds the length of the bit string, it is rejected with a
+ run-time error. $ZBIT functions count the first bit as position one
+ (1).
+
+3 $ZBITLEN()
+ $ZBITLEN()
+
+ The $ZBITLEN function returns the length of a bit string, in bits.
+
+ The format for the $ZBITLEN function is:
+
+
+ $ZBITLEN(expr)
+
+ o The expression specifies the bit string to examine.
+
+3 $ZBITNOT()
+ $ZBITNOT()
+
+ The $ZBITNOT function returns a copy of the bit string with each input
+ bit position inverted.
+
+ The format for the $ZBITNOT function is:
+
+
+ $ZBITNOT(expr)
+
+ o The expression specifies the bit string whose inverted bit pattern
+ becomes the result of the function.
+
+3 $ZBITOR()
+ $ZBITOR()
+
+ The $ZBITOR function performs a bitwise OR on two bit strings, and
+ returns a bit string equal in length to the longer of the two arguments
+ (containing set bits in those positions where either or both of the
+ input strings have set bits). Positions that correspond to positions
+ where neither input string has a set bit have cleared bits in the
+ resulting string.
+
+ The format for the $ZBITOR function is:
+
+ $ZBITOR(expr1,expr2)
+
+ o The first expression specifies one of the bit strings that is input
+ to the OR operation.
+
+ o The second expression specifies the other bit string that is input
+ to the OR operation.
+
+3 $ZBITSET()
+ $ZBITSET()
+
+ The $ZBITSET function returns an edited copy of the input bit string
+ with a specified bit set to the value of the truth-valued expression.
+
+ The format for the $ZBITSET function is:
+
+
+ $ZBITSET(expr,intexpr,tvexpr)
+
+ o The expression specifies the input bit string.
+
+ o The integer expression specifies the position of the bit to
+ manipulate. Arguments that are negative, zero, or exceed the length
+ of the bit string produce a run-time error. $ZBIT functions count
+ the first bit as position one (1).
+
+ o The truth-valued expression specifies the value to which to set the
+ specified bit (0 or 1).
+
+3 $ZBITSTR()
+ $ZBITSTR()
+
+ The $ZBITSTR function returns a bit string of a specified length with
+ all bit positions initially set to either zero or one.
+
+ The format for the $ZBITSTR function is:
+
+
+ $ZBITSTR(intexpr[,tvexpr])
+
+ o The integer expression specifies the length of the bit string to
+ return; arguments that exceed the maximum length of 253,952 produce
+ a run-time error.
+
+ o The optional truth-valued expression specifies the value to which
+ all bit positions should initially be set (0 or 1). If this
+ argument is missing, the bits are set to zero.
+
+3 $ZBITXOR()
+ $ZBITXOR()
+
+ The $ZBITXOR performs a bitwise exclusive OR on two bit strings, and
+ returns a bit string equal in length to the shorter of the two
+ arguments (containing set bits in those position where either but not
+ both of the input strings have set bits). Positions that correspond to
+ positions where neither or both input string has a set bit have cleared
+ bits in the resulting string.
+
+ The format for the $ZBITXOR function is:
+
+
+ $ZBITXOR(expr1,expr2)
+
+ o The first expression specifies one of the bit strings that is input
+ to the XOR operation.
+
+ o The second expression specifies the other bit string that is input
+ to the XOR operation.
+
+3 Ex_of_$ZBIT_Func
+ Examples of $ZBIT Functions
+
+ Example:
+
+
+ ZCRC(X)
+
+ NEW R,I,J,B,X1,K
+
+ SET R=$ZBITSTR(8,0)
+
+ FOR I=1:1:$L(X) S R=$ZBITXOR(R,$$BITIN($A(X,I)))
+
+ QUIT $$BITOUT(R)
+
+ ;CONVERT A BYTE TO A BIT STRING
+
+
+ BITIN(X)
+
+ SET X1=$ZBITSTR(8,0)
+
+ FOR J=1:1:8 S B=X#2,X=X\2 i B s X1=$ZBITSET(X1,J,1)
+
+ QUIT X1
+
+ ; CONVERT A BITSTRING TO A NUMBER
+
+
+ BITOUT(X)
+
+ SET X1=0
+
+ FOR K=1:1:8 I $ZBITGET(X,K) S X1=X1+(2**(K-1))
+
+ QUIT X1
+
+ This uses several $ZBIT functions to turn a character into a bit stream
+ and return a coded value.
+
+ While this example illustrates the use of several of the $ZBIT
+ functions, the following example produces identical results if you need
+ to code the function illustrated above for production.
+
+
+ ZCRC(X)
+
+ NEW R,I,J,B,X1,K
+
+ SET R=$ZBITSTR(8,0)
+
+ FOR I=1:1:$L(X) S R=$ZBITXOR(R,$C(0)_$E(X,I))
+
+ QUIT $A(R,2)
+
+ This example illustrates the use of $C to specify the number of invalid
+ bits that exist at the end of the character string. In this case there
+ are zero invalid bits.
+
+2 $Zcall()
+ $Zcall()
+
+ The $ZCALL function returns a value supplied by an external routine
+ written in another programming language. For more information on the
+ $ZCALL function, refer to the "Integrating External Routines" chapter
+ in GT.M Programmer's Guide.
+
+2 $ZDate()
+ $ZDate()
+
+ The $ZDATE function returns a date and/or time formatted as text based
+ on an argument formatted in the manner of $HOROLOG. For information on
+ the format of $HOROLOG, refer to the "Intrinsic Special Variables"
+ chapter in this manual.
+
+ The format for the $ZDATE function is:
+
+
+ $ZD[ATE](expr1[,expr2[,expr3[,expr4]]]])
+
+ o The first expression specifies in $HOROLOG format the date and/or
+ time that $ZDATE() returns in text format. If the output requires
+ only the date or the time, the other piece of the argument that is
+ delimited by a comma (,) may be null.
+
+ o The optional second expression specifies a string providing
+ $ZDATE() with a "picture" of the desired output format. If this
+ argument is missing or null, $ZDATE() uses the default format
+ string "MM/DD/YY". If the optional second expression exceeds 64
+ characters, $ZDATE() generates a run-time error.
+
+ o The optional third expression specifies a list of 12 month codes,
+ separated by commas (,), that $ZDATE() uses in formatting text
+ months called for by the "MON" picture, (i.e., $ZDATE() outputs
+ $PIECE(expr3,",",month-number) when "MON" appears in the second
+ expression). If this argument is missing or null, $ZDATE() uses
+ three-character English abbreviations for months.
+
+ o The optional fourth expression specifies a list of seven day codes,
+ separated by commas (,), which $ZDATE() uses in formatting text
+ days of the week called for by the "DAY" picture, $ZDATE() outputs
+ $PIECE (expr4,",",day-of-week-number) when "DAY" appears in the
+ second expression; if this argument is missing or null, $ZDATE()
+ uses three-character English abbreviations for days of the week.
+
+ $ZDATE() provides an easy and flexible tool for putting M internal
+ date/time ($HOROLOG) formats into more user-friendly formats.
+
+ The Intrinsic Special Variable $ZDATEFORM determines the output format
+ for years. The default value is zero (0), in which case $ZDATE() with
+ one argument (no format specification) uses a "YY" (two digit) format
+ for all years. If $ZDATEFORM is one (1), a "YYYY" (four digit) format
+ is used for years later than 1999. For all other values of $ZDATEFORM,
+ "YYYY" (four digit) format is used for all years. $ZDATEFORM does not
+ affect $ZDATE() when the format argument is specified.
+
+3 $ZDate_Form_Spec_Ele
+ $ZDATE Format Specification Elements
+
+ This section lists the $ZDATE() format specification elements. $ZDATE()
+ format specifications must appear in upper case. When any alphabetic
+ characters in format specifications are in lower case, $ZDATE()
+ generates a run-time error.
+
+ YY Outputs the rightmost two digits of the year.
+ YEAR Outputs the year as a four-digit number.
+ MM Outputs the month as a two-digit zero-filled number between 01
+ and 12.
+ MON Outputs the month as a three-letter abbreviation. (You can
+ modify the output further using expr3).
+ DD Outputs the day of the month as a two-digit zero-filled number
+ between 01 and 31.
+ DAY Outputs the day of the week as a three-letter abbreviation.
+ (You can modify the output further using expr4).
+ 24 Outputs the hour of the day as a zero-filled number between 00
+ and 23.
+ 12 Outputs the hour of the day as a zero-filled number between 01
+ and 12.
+ 60 Outputs the minute of the hour as a zero-filled number between
+ 00 and 59.
+ SS Outputs the second of the minute as a zero-filled number between
+ 00 and 59.
+ AM Outputs the letters AM and PM depending on the time.
+ + Inserts a plus sign (+) in the output string
+ - Inserts a minus sign (-) in the output string.
+ . Inserts a period (.) in the output string.
+ , Inserts a comma (,)in the output string.
+ / Inserts a slash (/) in the output string.
+ : Inserts a colon (:) in the output string.
+ ; Inserts a semi-colon (;) in the output string.
+ * Inserts an asterisk (*) in the output string.
+ A blank space inserts a blank space in the output string.
+
+3 Ex_of_$ZDate()
+ Examples of $ZDATE()
+
+ Example:
+
+
+ GTM> WRITE $H,!,$ZDATE($H)
+
+ 55243,43223
+ 04/01/2002
+ GTM>
+
+ This displays $HOROLOG and then uses $ZDATE() to display today's date.
+ The output shown would appear if today were the first of April, 2002.
+
+ Example:
+
+
+ GTM> W $ZDATE($H,"DD-MON-YEAR")
+
+ 01-APR-2002
+ GTM>
+
+ This uses the second argument to specify a text format different from
+ the default.
+
+ Example:
+
+
+ GTM> SET m="Januar,Februar,Marz,April,Mai,Juni,Juli,August,"
+
+ GTM> SET m=m_"September,October,November,Dezember"
+
+ GTM> WRITE $ZDATE($H,"DD-MON-YEAR",m)
+
+ 01-April-2002
+ GTM>
+
+ This is similar to the prior example, however it uses the third
+ argument to specify the months in German.
+
+ Example:
+
+
+ GTM> SET d="Dimanche,Lundi,Mardi,Mercredi,Jeudi,Vendredi,Samedi"
+
+ GTM> WRITE $ZD($H,"DAY, DD/MM/YY","",d)
+
+ Mercredi, 01/04/2002
+
+ GTM>
+
+ This example displays the first of April, however it uses the fourth
+ argument to specify the days of the week in French.
+
+ Example:
+
+
+ GTM> WRITE !,$ZDATE($H,"12:60:55 AM")
+
+ 10:35:51 PM
+ GTM>
+
+ This example shows hours, minutes, and seconds in a 12 hour clock with
+ an AM/PM indicator.
+
+ Example:
+
+
+ GTM> WRITE !,$ZDATE(",36524","24-60")
+
+ 10-08
+ GTM>
+
+ This example shows hours and minutes on a 24 hour clock. Notice that
+ the first argument must provide the time in the second comma delimiter
+ piece to match $HOROLOG format.
+
+ Example:
+
+
+ GTM>WRITE $ZDATEFORM
+
+ 0
+ GTM>WRITE $ZDATE($H)
+
+ 11/15/02
+ GTM>SET $ZDATEFORM=1
+
+ GTM>WRITE $ZDATE($H)
+
+ 11/15/2002
+ GTM>WRITE $ZDATE($H,"MM/DD/YY")
+
+ 11/15/02
+ This example converts the output format for years from the default
+ ("YY") format to the four digit format ("YYYY") using the Intrinsic
+ Special Variable $ZDATEFORM.
+
+2 $ZFILEattributes()
+ $ZFILEattributes()
+
+ The $ZFILEATTRIBUTES function returns an item of information about a
+ specified file. The $ZFILEATTRIBUTES function is analogous to the DCL
+ Lexical function F$FILE_ATTRIBUTES.
+
+ The format for the $ZFILEATTRIBUTES function is:
+
+
+ $ZFILE[ATTRIBUTES](expr1,expr2)
+
+ o The first expression specifies the target file
+
+ o The second expression specifies the item keyword identifying the
+ information for $ZFILEATTRIBUTES() to return; keywords may be
+ upper-, lower-, or mixed-case
+
+ $ZFILEATTRIBUTES() provides a tool for examining the RMS
+ characteristics of a file from GT.M.
+
+3 Ex_of_$ZFILE
+ Examples of $$ZFILEATTRIBUTES()
+
+ Example 1:
+
+
+ GTM> WRITE $ZFILEATTRIBUTES("GTMSHR","PRO")
+
+ RWED,RWED,RE,RE
+
+ GTM>
+
+ This uses $ZFILEATTRIBUTES() to display the UIC protection mask for
+ GTMSHR.EXE.
+
+ Example 2:
+
+
+ GTM> WRITE $ZFILE("M.DAT","deq")
+
+ 100
+ GTM>
+
+ This uses $ZFILEATTRIBUTES() to examine the default extension size for
+ M.DAT.
+
+2 $ZGETDVI()
+ $ZGETDVI()
+
+ The $ZGETDVI function returns an item of information about a specified
+ device. The $ZGETDVI function is analogous to the DCL Lexical function
+ F$GETDVI.
+
+ The format for the $ZGETDVI function is:
+
+
+ $ZGETDVI(expr1,expr2)
+
+ o The first expression specifies the target device
+
+ o The second expression specifies the item keyword identifying the
+ type of information returned; keywords may be upper-, lower-, or
+ mixed-case
+
+ $ZGETDVI() provides a tool for examining the characteristics of devices
+ in the VMS environment from within GT.M. There are three instances when
+ the values returned by F$GETDVI and $ZGETDVI are not identical.
+
+3 Ex_of_$ZGETDVI()
+ Examples of $ZGETDVI()
+
+ Example:
+
+
+ GTM> W $ZGETDVI($ZPARSE("cus.dat","device"),"freeblocks")
+
+ 296697
+ GTM>
+
+ This uses $ZGETDVI() and $ZPARSE() to display the number of free RMS
+ blocks on the disk drive that holds the CUS.DAT file.
+
+ Example:
+
+
+ IF $ZGETDVI($IO,"PRINTER") WRITE clrtop
+
+ This uses $ZGETDVI() as the argument to an IF command, such that the
+ WRITE command executes only if the current device has an attached
+ printer port.
+
+2 $ZGETJPI()
+ $ZGETJPI()
+
+ The $ZGETJPI function returns an item of job or process information
+ about a specified process. The $ZGETJPI function is analogous to the
+ DCL F$GETJPI lexical function.
+
+ The format for the $ZGETJPI function is:
+
+
+ $ZGETJPI(expr1,expr2)
+
+ o The first expression identifies the PID of the target job, if this
+ argument is a null string (""), $ZGETJPI() returns information
+ about the current process.
+
+ o The second expression specifies the item keyword identifying the
+ type of information returned; keywords may be upper-, lower-, or
+ mixed-case.
+
+ $ZGETJPI() provides a tool for examining the characteristics of a VMS
+ process and the job in which it operates. Accessing information about
+ processes belonging to other users requires certain VMS privileges.
+ Consult your system manager if you feel you require additional
+ privileges.
+
+ The function $ZGETJPI($J,"TERMINAL") returns the output device only
+ when the process is the first (master) process with a job. Within a
+ spawned process, the VMS system service used by $ZGETJPI returns a null
+ string for the item TERMINAL. However, the following alternative
+ acquires the PID of the primary process and uses that to in turn get
+ the terminal.
+
+
+ $ZGETJPI($ZGETJPI($J,"MASTER_PID"),"TERMINAL")
+
+3 Ex_of_$ZGETJPI()
+ Examples of $ZGETJPI()
+
+ Example 1:
+
+
+ GTM> WRITE $ZGETJPI("","IMAGECOUNT")
+
+ 12
+ GTM>
+
+ This uses $ZGETJPI() to determine how many images the process has used,
+ not including the current image, to arrive at the current point.
+
+ Example 2:
+
+
+ GTM> SET t=$ZGETJPI("","cputim")
+
+ GTM> DO BENCH WRITE $ZGETJPI("","cputim")-t
+
+ 1738
+ GTM>
+
+ This uses $ZGETJPI() to measure the actual CPU time, measured in
+ hundredths of a second, consumed by performing the BENCH sub-routine.
+
+2 $ZGETLKI()
+ $ZGETLKI()
+
+ The $ZGETLKI function returns an item of information about a VMS lock.
+
+ The format for the $ZGETLKI() function is:
+
+
+ $ZGETLKI(expr1,expr2)
+
+ o The first expression specifies a lock-id identifying the target VMS
+ lock.
+
+ o The second expression specifies the item keyword identifying the
+ type of information returned; keywords may be in upper-, lower-, or
+ mixed-case.
+
+ $ZGETLKI() provides a tool for examining VMS lock characteristics from
+ within M. Accessing information about locks belonging to other users
+ requires WORLD or SYSLCK privileges. Note that VMS locks and M LOCKs
+ are not at all the same, even though they serve corresponding purposes
+ in their respective environments. For information about VMS locks,
+ refer to the VMS Introduction to System Services.
+
+3 Ex_of_$ZGETLKI()
+ Examples of $ZGETLKI()
+
+ Example 1:
+
+
+ GTM> WRITE $ZGETLKI(lk,"RESNAM")
+
+ GTM$LM
+
+ GTM>
+
+ This uses $ZGETLKI() to examine a VMS lock resource name.
+
+ Example 2:
+
+ IF $ZGETLKI(lk,"PID")=$JOB WRITE lk,!,?10,"is mine"
+
+ This uses $ZGETLKI() as the argument to an IF command such that the
+ write only executes when the process owns the VMS lock, identified by
+ lk. This depends on the fact that GT.M uses the VMS PID for the value
+ of the $JOB Intrinsic Special Variable.
+
+2 $ZGETSYI()
+ $ZGETSYI()
+
+ The $ZGETSYI function returns an item of information about a VMS
+ system. The $ZGETSYI function is analogous to the DCL lexical function
+ F$GETSYI.
+
+ The format for the $ZGETSYI() function is:
+
+
+ $ZGETSYI(expr1[,expr2])
+
+ o The first expression specifies the item keyword identifying the
+ type of information $ZGETSYI() returns; keywords may be upper-,
+ lower-, or mixed-case.
+
+ o The optional second expression specifies the target node; if this
+ argument is missing or null, $ZGETSYI() returns information about
+ the current host system.
+
+ $ZGETSYI() provides a tool for examining operating system parameters
+ from within GT.M.
+
+3 Ex_of_$ZGETSYI()
+ Examples of $ZGETSYI()
+
+ Example 1:
+
+
+ GTM> WRITE $ZGETSYI("CLUSTER_NODES")
+
+ 3
+ GTM>
+
+ This uses $ZGETSYI() to display the number of nodes in the VMS cluster,
+ in this case 3.
+
+ Example 2:
+
+
+ FOR node="MIKE","IKE" D
+
+ .F item="node_swtype","version" W !,$ZGETSYI(item,node)
+ QUIT
+
+ This uses nested FOR loops with $ZGETSYI() to display the operating
+ system type for the nodes "MIKE" and "IKE". Note that because "VERSION"
+ is only available for the local node, the attempt to also show the
+ operating system version displays a blank line, except when the current
+ node is MIKE or IKE.
+
+2 $ZJOBEXAM()
+ $ZJOBEXAM()
+
+ The $ZJOBEXAM function returns the full specification of the file into
+ which the function places a ZSHOW "*". The return value serves as a way
+ to save, to notify others of the exact location of the output, or to
+ open the file for further processing. GT.M reports each $ZJOBEXAM() to
+ the operator log facility with its file specification.
+
+ The optional expression argument is a template output device
+ specification. It can be a device, a file directory, or a file name.
+ The template is an expression that is pre-processed to create a file
+ specification as the target for the ZSHOW. The preprocessing is
+ equivalent to $ZPARSE(), as illustrated by the following M code:
+
+
+ Set deffn="GTM_JOBEXAMINE.ZSHOW_DMP_"_$JOB_"_"_<cntr>
+
+ Set filespec=$ZPARSE(expr1,,deffn,,NO_CONCEAL)
+
+ The $ZJOBEXAM()does not trigger error processing except when there is a
+ problem storing its return value, so no error is reported to the
+ process until after any dump is complete. In the event of any error
+ encountered during the $ZJOBEXAM(), GT.M sends an appropriate message
+ to operator log facility and returns control to the caller. Note that
+ this special error handling applies only to the $ZJOBEXAM(), and is not
+ a property of the $ZINTERRUPT interrupt handler, which uses $ZJOBEXAM()
+ by default.
+
+ $ZJOBEXAM() dump files contain the context of a process at the time the
+ function executes. Placement and management of these files should
+ consider their potential size and security implications.
+
+3 Ex_of_$ZJOBEXAM()
+ Examples of $ZJOBEXAM()
+
+ Example:
+
+
+ GTM>Set x=$zjobexam("TESTEXAM")
+
+ GTM>zwr x
+
+ x="ASGARD$DKB100:[LIBRARY.V999.PRO]TESTEXAM.ZSHOW_DMP_539119331_1;"
+
+ GTM>
+
+ This example shows the fully qualified name of the dump file that was
+ created by $ZJOBEXAM
+
+2 $ZLKID()
+ $ZLKID()
+
+ The $ZLKID function returns the identification number of the first or
+ next lock in the VMS distributed lock environment.
+
+ The syntax of the $ZLKID function is:
+
+
+ $ZLKID(tvexpr)
+
+ o If the truth-valued expression is false (0), $ZLKID() returns the
+ first accessible, currently active lock in the VMS distributed lock
+ environment; if the truth-valued expression is true (non-zero),
+ $ZLKID() returns the "next" lock, with respect to the last call to
+ $ZLKID(); if $ZLKID() has a non-zero argument before it has a ()
+ argument, the function generates a run-time error.
+
+ o If the last prior lock returned is the last lock accessible,
+ $ZLKID() returns a null string.
+
+ $ZLKID() provides a tool for identifying VMS locks from within GT.M.
+ Accessing information about locks belonging to other users requires
+ WORLD or SYSLCK privileges. Consult your system manager if you feel you
+ require additional privileges.
+
+3 Ex_of_$ZLKID()
+ Examples of $ZLKID()
+
+ Example 1:
+
+
+ SET x=$ZLKID(0) F cnt=0:1 Q:x="" S x=$ZLKID(1)
+
+ This uses $ZLKID() to count the number of currently accessible VMS
+ locks.
+
+ Example 2:
+
+
+ SET L=$ZLKID(0)
+
+ FOR Q:L="" D
+
+ .I $ZGETLKI(L,"RESNAM")="GTM$LM" SHWJOB($ZGETLKI(L,"PID"))
+ D
+
+ .SET L=$ZLKID(1)
+ QUIT
+
+ This uses $ZLKID() and $ZGETLKI() to identify GT.M processes based on
+ whether they hold a VMS lock with the resource name "GTM$LM". Once the
+ routine has identified a process, it invokes the subroutine SHWJOB
+ passing the VMS PID. For a more extensive example, refer to the "M
+ Utility Routines" chapter in GT.M Programmer's Guide.
+
+2 $ZMessage()
+ $ZMessage()
+
+ The $ZMESSAGE function returns a message string associated with a
+ specified status code in the standard VMS error message format. The
+ $ZMESSAGE function is analogous to the DCL F$MESSAGE lexical function.
+
+ The format for the $ZMESSAGE function is:
+
+
+ $ZM[ESSAGE](intexpr)
+
+ o The integer expression specifies the status code for which
+ $ZMESSAGE() returns error message textin the standard VMS error
+ message format.
+
+ $ZMESSAGE() provides a tool for examining the message associated with a
+ particular message code as reported in $ZSTATUS.
+
+ The standard VMS error message format is:
+
+
+ %FACILITY-S-IDENT, TEXT
+
+ Where:
+
+ % Identifies the first message issued for a given error. A hyphen
+ (-) prefaces subsequent messages for the same error.
+ FACILITY Identifies the source of the error.
+ S Indicates one of five severity level indicators.
+ The indicators and their meanings are:
+
+ S Successful completion
+ I Information
+ W Warning
+ E Error
+ F Fatal or severe error
+ IDENT Represents an abbreviation of the message text.
+ TEXT Explains the message
+ The DCL command SET MESSAGE controls which message fields $ZMESSAGE()
+ returns. By default, the VMS message facility returns all four fields.
+
+ The $ZSTATUS Intrinsic Special Variable holds the message code and the
+ message of the last non-Direct Mode GT.M error. For more information on
+ $ZSTATUS, refer to the "Intrinsic Special Variables" chapter in GT.M
+ Programmer's Guide.
+
+3 Ex_of_$ZMessage()
+ Examples of $ZMESSAGE()
+
+ Example 1:
+
+
+ GTM> WRITE $ZMESSAGE(36)
+
+ %SYSTEM-F-NOPRIV, no privilege for attempted operation
+
+ GTM>
+
+ This uses $ZMESSAGE() to display the message string corresponding to
+ code 36. Note that the display might vary depending on DCL SET MESSAGE
+ commands issued prior to invoking GT.M.
+
+ Example 2:
+
+
+ GTM> FOR i=32:1:36 WRITE !,$ZMESSAGE(i)
+
+ This FOR loop uses $ZMESSAGE() to display all severities of the NOPRIV
+ error.
+
+2 $ZPARSE()
+ $ZPARSE()
+
+ The $ZPARSE function expands a file name to a full file-specification
+ and then returns the full file-specification or one of its fields
+ (node, device, directory, name, type, or version). The $ZPARSE function
+ is analogous to the DCL F$PARSE lexical function. The order of the
+ operands differs from the DCL F$PARSE function.
+
+ The format for the $ZPARSE function is:
+
+
+ $ZPARSE(expr1[,expr2[,expr3[,expr4[,expr5]]]])
+
+ o The first expression specifies the file-specification to parse; if
+ the file-specification is not valid, $ZPARSE() returns a null
+ string; if the file-specification contains a VMS wildcard (* and/or
+ %), $ZPARSE() returns a file-specification containing the
+ wildcard(s).
+
+ o The optional second expression specifies the field of the
+ file-specification that $ZPARSE() returns; if this argument is
+ missing or null, $ZPARSE() returns a full file-specification
+ constructed using default values in place of any fields missing for
+ node, directory, file, type, and version.
+
+ o The optional third and fourth expressions specify default values to
+ use during file name expansion for missing fields (node, device,
+ directory, name, type, or version), if any, in the original file
+ name. For any field missing in the original file name specified in
+ expr1, $ZPARSE() will attempt to substitute the corresponding field
+ from expr3; if that field is not present in expr3, $ZPARSE() will
+ attempt to use the corresponding field from expr4.
+
+ o If the file name, type, or version is missing from all three of
+ expr1, expr3, and expr4, $ZPARSE() will return a null string for
+ the corresponding field. If the file node, device, or directory is
+ missing from all three of expr1, expr3, and expr4, $ZPARSE() will
+ substitute the information from your current default directory.
+
+ o The optional fifth expression specifies the mode or type of parse
+ that $ZPARSE() performs.
+
+ $ZPARSE() provides a tool for verifying that a file-specification is
+ syntactically correct, for examining specific fields of a
+ file-specification, and for filling in missing pieces in a partial
+ specification based on a hierarchy of defaults. For information about
+ determining whether a file exists, refer to the description of
+ $ZSEARCH().
+
+ $ZPARSE() arguments, after the first, are optional. If you use no other
+ arguments, a single argument is sufficient. However, if you use
+ selected arguments $ZPARSE() requires that null strings ("") be filled
+ in for the unspecified arguments.
+
+ The acceptable keywords for the second argument are:
+
+ "NODE" Node name
+ "DEVICE" Device name
+ "DIRECTORY" Directory name
+ "NAME" File name (excluding file extension)
+ "TYPE" File typeextension
+ "VERSION" File version number
+ The keywords may be entered in either upper or lower case. Variables
+ that evaluate to these strings and indirection are acceptable for
+ argument two. When the keywords themselves appear as string literals,
+ they must be enclosed in quotation marks (" ").
+
+ The keywords for the fifth argument $ZPARSE() are:
+
+ NULL ("") Returns a full file-specification or device
+ "SYNTAX_ONLY"
+ Disables checking for the existence of the directory or device.
+ "NO_CONCEAL"
+ Disables the "conceal" attribute in the translation of logical
+ names in a file-specification.
+ The mode names may be upper or lower case but cannot be abbreviated.
+
+3 Ex_of_$ZPARSE()
+ Examples of $ZPARSE()
+
+ Example:
+
+
+ GTM> WRITE $ZPARSE("TEST","",";3","DUST.LIS")
+
+ SYS$:[THOMPSON.WORK]TEST.LIS;3
+
+ GTM>
+
+ This uses $ZPARSE() to demonstrate defaulting using the third and
+ fourth arguments. The result gets the device and directory field from
+ the process current default directory, the name from the first
+ expression, the type from the fourth extension, and the version from
+ the third expression.
+
+
+ $ SET DEF[WORK.NEW]
+
+ $ GTM
+
+ GTM>WRITE $ZPARSE("TEST","","X.LIS","Y.C")
+
+ USER:[WORK.NEW]TEST.LIS;
+
+ GTM>WRITE $ZPARSE("test","","[WORK.NEW]","Y.C")
+
+ USER:[WORK.NEW]TEST.C;
+
+ GTM>
+
+ This example illustrates the use of the third and fourth arguments to
+ $ZPARSE(). In the first statement, the first argument has no directory
+ or extension fields, so $ZPARSE() substitutes the extension field from
+ the third argument. Since neither the third nor fourth argument
+ specifies a directory, $ZPARSE() substitutes the current working
+ directory, and because the fourth argument does not contain any fields
+ that are not present in the third argument, the fourth argument is not
+ used.
+
+ In the second statement, the first argument to $ZPARSE() is again
+ missing both the directory and extension. In this instance, $ZPARSE()
+ uses the directory specified in the third argument and, because neither
+ the first nor third argument specifies a file extension, $ZPARSE() uses
+ the file extension from the fourth argument.
+
+
+ GTM> W $ZPARSE("GTM$DIST","DIRECTORY","","","NO_CONCEAL")
+
+ [SYS1.SYSCOMMON.][GTM_DIST]
+ GTM>
+
+ This uses $ZPARSE() to display the directory structure for the logical
+ name GTM$DIST. The "NO_CONCEAL" keyword in the fifth argument causes
+ the function to return information about the concealed logical name
+ SYS$COMMON. Note the top level system directory may be different on
+ your system and other parts of the path may vary if your shop uses a
+ non-standard GT.M installation.
+
+2 $ZPID()
+ $ZPID()
+
+ The $ZPID function returns the process identification number (PID) of
+ the first or next currently accessible process in the system. The
+ $ZPID() function is similar to the DCL lexical function F$PID except
+ that M represents the resulting PIDs in decimal.
+
+ The format for the $ZPID function is:
+
+ $ZPID(tvexpr)
+
+ o If the truth-valued expression is false (0), $ZPID returns the
+ first accessible, currently active PID in the VMS system; if the
+ truth-valued expression is true (non-zero), $ZPID returns the
+ "next" PID, with respect to the last call to $ZPID; if $ZPID() has
+ a non-zero argument before it has a zero (0) argument, the function
+ generates a run-time error.
+
+ o If the last prior PID returned is the last PID accessible, $ZPID()
+ returns a null string.
+
+ $ZPID() provides a tool for identifying processes in the VMS
+ environment from within GT.M. Accessing information about processes
+ belonging to other users requires certain VMS privileges. Consult your
+ system manager if you feel you require additional privileges.
+
+3 Ex_of_$ZPID()
+ Examples of $ZPID()
+
+ The examples in this section illustrate the previous verbal description
+ of $ZPID().
+
+ Example 1:
+
+
+ $ GTM
+
+ GTM> WRITE $ZPID(1)
+
+ %GTM-E-ZPIDBADARG,
+
+ The tvexpr must be FALSE if the last ZPID not found
+
+ GTM>
+
+ This $ZPID() attempts to get the next PID without getting the first PID
+ and, therefore, generates an error.
+
+ Example 2:
+
+
+ S pid=$ZPID(0) F Q:pid="" D SHWPRC(pid) S pid=$ZPID(1)
+
+ This uses a $ZPID() loop to examine all accessible processes. The logic
+ is analogous to that in a $ORDER() loop. If this routine runs without
+ the VMS WORLD privilege, it may not "see" all processes.
+
+2 $ZPrevious()
+ $ZPrevious()
+
+ The $ZPREVIOUS function returns the subscript of the previous local or
+ global variable name in collation sequence within the array level
+ specified by its argument. When $ZPREVIOUS() has an unsubscripted
+ argument, it returns the previous unsubscripted local or global
+ variable name in collating sequence.
+
+ The $ZPREVIOUS function provides compatibility with some other M
+ implementations. The M Development Committee chose to implement this
+ functionality with the optional second -1 argument of $ORDER().
+ Therefore, when a design requires this functionality $ORDER() has the
+ advantage over $ZPREVIOUS of being part of the M standard.
+
+ The format for the $ZPREVIOUS function is:
+
+
+ $ZP[REVIOUS](glvn)
+
+ o The subscripted or unsubscripted global or local variable name
+ specifies the node prior to which $ZPREVIOUS() searches backwards
+ for a defined node with data and/or descendants. The number of
+ subscripts contained in the argument implicitly defines the array
+ level.
+
+ o If $ZPREVIOUS() finds no node at the specified level before the
+ specified global or local variable, it returns a null string.
+
+ o If the last subscript in the subscripted global or local variable
+ name is null, $ZPREVIOUS() returns the last node at the specified
+ level.
+
+ $ZPREVIOUS() is equivalent to $ORDER() with a second argument of -1.
+
+2 $ZPRIVilege()
+ $ZPRIVilege()
+
+ The $ZPRIVILEGE function returns a boolean value depending on whether
+ the current process privileges include all privileges listed in the
+ $ZPRIVILEGE argument. The $ZPRIVILEGE function is analogous to the DCL
+ lexical function F$PRIVILEGE.
+
+ The format for the $ZPRIVILEGE function is:
+
+
+ $ZPRIV[ILEGE](expr)
+
+ o The expression specifies a VMS privilege or a list of privileges
+ separated by commas.
+
+ o If the process currently has all of the specified privileges,
+ $ZPRIVILEGE() returns a true (1).
+
+ o If the process currently lacks any one of the privileges,
+ $ZPRIVILEGE() returns a false (0).
+
+ $ZPRIVILEGE() provides a tool for determining within GT.M whether the
+ current process privileges are adequate for some task. For information
+ about adjusting privileges and a list of VMS privileges, refer to the
+ section on $ZSETPRV() in the "Functions" chapter in GT.M Programmer's
+ Guide
+
+3 Ex_of_$ZPRIVilege()
+ Examples of $ZPRIVILEGE()
+
+ Example 1:
+
+
+ GTM> WRITE $ZPRIVILEGE("NETMBX,TMPMBX")
+
+ 1
+ GTM> WRITE $ZPRIVILEGE("BYPASS")
+
+ 0
+ GTM>
+
+ This uses $ZPRIVILEGE() to show that the process has the NETMBX and
+ TMPMBX privileges, but not the BYPASS privilege.
+
+ Example 2:
+
+
+ IF $ZPRIVILEGE("SYSLCK") DO WORK
+
+ This loop uses $ZPRIVILEGE() as the argument to an IF command such that
+ DO WORK only executes if the process has SYSLCK privileges.
+
+2 $ZQGBLMOD()
+ $ZQGBLMOD()
+
+ The $ZQGBLMOD function enables an application to determine whether it
+ can safely apply a lost transaction to the database. A lost transaction
+ is a transaction that must be rolled off a database to maintain
+ dual-site consistency.
+
+ The format for the $ZQGBLMOD function is:
+
+
+ $ZQGBLMOD(gvn)
+
+ o The subscripted or non-subscripted global variable name (gvn)
+ specifies the target node.
+
+ o A return value of zero (0) means the value of the global variable
+ has not changed since the last synchronization of the primary and
+ secondary.
+
+ o A return value of one (1) means the value of the global variable
+ may have changed since the last synchronization of the primary and
+ secondary.
+
+ $ZQGBLMOD function produces an error if you submit an argument that is
+ not a global variable name.
+
+ Internally, $ZQGBLMOD (gvn) compares the GT.M transaction number in the
+ database block in which the global variable name is stored with the
+ value in the resync_tn field stored in the database file header.
+
+ For example, if x is the transaction number of the level-0 database
+ block in which gvn resides, and y is the value of resync_tn of region
+ reg containing gvn, then the following is true:
+
+ o If x £ y, no transaction modified the level-0 database block z in
+ which gvn resides since the databases at primary and secondary
+ became synchronized with each other. $ZQGBLMOD() returns a zero
+ (0).
+
+ o If x > y, some transaction modified z, but not necessarily
+❇❖■
+, after the primary and secondary system databases synchronized with each
+, after the primary and secondary system databases synchronized with each
+, after the primary and secondary system databases synchronized with each
+, after the primary and secondary system databases synchronized with each
+, after the primary and secondary system databases synchronized with each
+, after the primary and secondary system databases synchronized with each
+, after the primary and secondary system databases synchronized with each
+, after the primary and secondary system databases synchronized with each
+
+ If a transaction is a lost transaction that has been rolled back and it
+ is determined that for all the M globals set and killed in the
+ transaction $ZQGBLMOD() is zero (0), it is probably safe to apply the
+ updates automatically. However, this determination of safety can only
+ be made by the application designer and not by GT.M. If the $ZQGBLMOD()
+ is one (1) for any set or kill in the transaction, it is not safe to
+ apply the update.
+
+ The test of $ZQGBLMOD() and applying the updates must be
+ encapsulated inside a GT.M transaction.
+
+ Another approach to handling lost transactions would be to store in the
+ database the initial message sent by a client, as well as the outcome
+ and the response, and to reprocess the message with normal business
+ logic. If the outcome is the same, the transaction can be safely
+ applied.
+
+ If restartable batch operations are implemented, lost batch
+ transactions can be ignored since a subsequent batch restart will
+ process them correctly.
+
+2 $ZSEARCH()
+ $ZSEARCH()
+
+ The $ZSEARCH function returns the full file-specification of a located
+ RMS file. The $ZSEARCH function is analogous to the DCL Lexical
+ function F$SEARCH. However, $ZSEARCH(), consistent with $ORDER(),
+ always returns a null after returning the last file even when the
+ function finds only one matching file, while the DCL lexical returns
+ the sole file-specification every time.
+
+ The format for the $ZSEARCH function is:
+
+
+ $ZSEARCH(expr[,intexpr])
+
+ o The expression contains a file-specification, with or without VMS
+ wildcards, for which $ZSEARCH() attempts to locate a matching file.
+ Repeating $ZSEARCH with the same filename uses the same context and
+ return a sequence of matching files when they exist; when the
+ sequence is exhausted, $ZSEARCH() returns an empty string (""). Any
+ change to the file name starts a new context.
+
+ o If the expression does not specify a device and directory,
+ $ZSEARCH() uses the process current default directory.
+
+ o If the argument omits the version number, $ZSEARCH() uses the
+ latest version of the file.
+
+ o The optional integer expression specifies a "stream" number from 0
+ to 255 for each search; streams provide a means of having up to 256
+ $ZSEARCH() contexts simultaneously in progress.
+
+ o If a $ZSEARCH() stream has never been used or if the expression
+ differs from the argument to the last $ZSEARCH() of the stream, the
+ function resets the context and returns the first
+ file-specification matching the expression; otherwise, it returns
+ the next matching file in collating sequence; if the last prior
+ file-specification returned for the same expression and same stream
+ was the last one matching the argument, $ZSEARCH() returns a null
+ string.
+
+ $ZSEARCH() provides a tool for verifying that a file-specification
+ exists and for finding all files that match a specificationa file
+ exists. For information to help determine the validity of a
+ file-specification and about specifying directories and file
+ extensions,file name, refer to the section on $ZPARSE().
+
+3 Ex_of_$ZSEARCH()
+ Examples of $ZSEARCH()
+
+ Example:
+
+
+ GTM> WRITE $ZSEARCH("DATA.DAT")
+
+ PROJK:[TEST]DATA.DAT;6
+
+ GTM>
+
+ This uses $ZSEARCH() to display the full RMS file-specification of the
+ current version of "DATA.DAT" in the process current default directory.
+
+ Example:
+
+
+ GTM>SET x=$ZSEARCH("*.M")
+
+ GTM>FOR S x=$ZSEARCH("*.M") Q:x="" W !,$ZPARSE(x,"NAME")
+
+ This FOR loop uses $ZSEARCH() and $ZPARSE() to display M source file
+ names in the process current default directory. To ensure that the
+ search starts at the beginning, the example resets the context by first
+ searching with a different argument.
+
+2 $ZSETPRV()
+ $ZSETPRV()
+
+ The $ZSETPRV function enables or disables privileges for the process
+ and returns prior states for the specified privileges. The $ZSETPRV
+ function is analogous to the DCL Lexical function F$SETPRV.
+
+ The format for the $ZSETPRV function is:
+
+
+ $ZSETPRV(expr)
+
+ o The expression specifies a VMS privilege or a list of privileges,
+ separated by commas, which $ZSETPRV() enables or, if they have a
+ prefix of "NO", disables.
+
+ o $ZSETPRV() returns a list similar to its argument with a prefix of
+ "NO" on any privilege that was previously disabled.
+
+ o $ZSETPRV() can always disable privileges; however, it cannot enable
+ privileges to which the account does not have access.
+
+ $ZSETPRV() provides a tool for adjusting VMS privileges from within
+ GT.M. Because the $ZSETPRV() return provides the prior state of the
+ privileges in the same format as the function input, the program can
+ subsequently use $ZSETPRV() to restore the prior state. For information
+ on passive determination of privileges, refer to the section on
+ $ZPRIVILEGE() in the "Functions" chapter in GT.M Programmer's Guide.
+
+3 Ex_of_$ZSETPRV()
+ Examples of $ZSETPRV()
+
+ Example 1:
+
+
+ GTM> WRITE $ZSETPRV("TMPMBX")
+
+ TMPMBX
+
+ GTM>
+
+ This uses $ZSETPRV() to (attempt to) enable the TMPMBX privilege. The
+ display from the WRITE command shows that the privilege was already
+ enabled when the function executed.
+
+ Example 2:
+
+
+ SET savprv=$ZSETPRV("SYSLCK")
+
+ IF '$ZPRIVILEGE("SYSLCK") WRITE !,"Inadequate Privileges"
+
+ ELSE DO ^%ST
+
+ SET savprv=$ZSETPRV(savprv)
+
+ This uses $ZSETPRV() to attempt to enable the SYSLCK privilege. Then
+ $ZPRIVILEGE() checks to determine if the privilege was granted. This
+ controls whether to issue a message or run the %ST utility program.
+ Finally, the routine restores the original state of the SYSLCK
+ privilege that was stored in savprv by again using $ZSETPRV().
+
+2 $ZTRNLNM()
+ $ZTRNLNM()
+
+ The $ZTRNLNM function returns information about an equivalence stored
+ in the VMS logical name tables. The $ZTRNLNM function is analogous to
+ the DCL Lexical function F$TRNLNM. $ZTRNLNM() optionally does iterative
+ translation, while the DCL lexical does not. This difference only
+ manifests itself when a logical name translates to another logical
+ name.
+
+ The format for the $ZTRNLNM function is:
+
+
+ $ZTRNLNM(expr1[,expr2[,expr3[,expr4[,expr5[,expr6]]]]])
+
+ o The first expression specifies the target logical name.
+
+ o The second optional expression specifies the logical name table(s)
+ for $ZTRNLNM() to use; if the argument is missing or null,
+ $ZTRNLNM() uses the tables identified by LNM$DCL_LOGICAL, which
+ usually uses LNM$FILE_DEV to specify searching the process, job,
+ group and system tables in that order.
+
+ o The third optional expression specifies the index (numbered from 0)
+ that $ZTRNLNM uses if the look-up encounters a search list; if the
+ argument is missing or null, $ZTRNLNM() uses the first element of
+ the search list.
+
+ o The fourth optional expression specifies the initial mode of the
+ look-up; if this argument is missing or null, $ZTRNLNM() starts the
+ look-up in USER mode (alternatives are SUPERVISOR and EXECUTIVE).
+
+ o The optional fifth expression specifies a keyword indicating
+ whether the look-up is CASE_SENSITIVE (the alternative and default
+ is CASE_BLIND).
+
+ o The optional sixth argument specifies the item keyword indicating
+ the item of information that $ZTRNLNM() returns; if the argument is
+ missing or null, $ZTRNLNM() returns the "VALUE" of the translated
+ equivalence name.
+
+ $ZTRNLNM() provides a tool for examining VMS logical names environment
+ variables from within GT.M.
+
+ If the (third) index argument is specified in conjunction with the
+ (sixth) item argument of "FULL", the $ZTRNLNM() uses the index value
+ throughout the iterative translation, and terminates with a null result
+ when it encounters no equivalence name at the specified index within
+ each iteration.
+
+ Only the first argument is required, but missing arguments before the
+ last argument specified, must be filled with null strings ("").
+
+3 Ex_of_$ZTRNLNM()
+ Examples of ZTRNLNM()
+
+ Example 1:
+
+
+ GTM> WRITE $ZTRNLNM("GTM$DIST")
+
+ SYS$COMMON:[GTM_DIST]
+
+ GTM>
+
+ This uses $ZTRNLNM() to display the translation value for GTM$DIST.
+
+ Example 2:
+
+
+ SET x=$ZTRNLNM("blotto","","","","CASE_SENSITIVE")
+
+ This uses the case argument to find the translation value for "blotto".
+ The example holds the place of the three unused optional arguments to
+ the left of that with null strings ("").
+
+1 Intr_Spe_Vars
+ Intrinsic Special Variables
+
+ M Intrinsic Special Variables start with a single dollar sign ($). GT.M
+ provides such variables for program examination. In some cases, the
+ Intrinsic Special Variables may be set to modify the corresponding part
+ of the environment.
+
+ None of the Intrinsic Special Variables can be KILLed. SETting or
+ NEWing is generally not allowed, but is specifically noted in the
+ descriptions of those that do.
+
+2 $Device
+ $Device
+
+ $D[EVICE] reflects the status of the current device. If the status of
+ the device does not reflect any error-condition, the value of $DEVICE,
+ when interpreted as a truth-value is 0 (FALSE). If the status of the
+ device reflect any error-condition, the value of $DEVICE, when
+ interpreted as a truth-value is 1 (TRUE).
+
+ The initial value of $DEVICE is implementation dependant. However,
+ if the initial value of $IO is the empty string, then the initial
+ value of $DEVICE is also empty string.
+
+ $DEVICE gives status code and meaning, in one access:
+
+ Example:
+
+ 1,Connection reset by peer
+ The above message is displayed on the server side when the socket
+ device is closed on the client side.
+
+2 $ECode
+ $ECode
+
+ $EC[ODE] contains a list of error codes for "active" errors -the error
+ conditions which are not yet resolved. If there are no active errors,
+ $ECODE contains the empty string. Whenever an error occurs, a code for
+ that error is appended to the value of $ECODE in such a way that the
+ value of $ECODE always starts and ends with a comma.
+
+ The value of $ECODE can be SET, and when it is set to a non-NULL value,
+ error processing starts.
+
+ List of codes for $ECODE start with comma seperated by commas. A code
+ starts with "M", "U", or "Z", with rest numeric. "M" codes are assigned
+ by MDC (MUMPS Development Committee), "U" by application (programmers),
+ and "Z" codes by MUMPS implementors (in this case GT.M).
+
+ An error always has a GT.M specified code and many errors also have an
+ ANSI Standard code. The complete list of standardized error codes can
+ be referenced from GT.M Message and Recovery Procedures Reference
+ Manual version 4.3 and onwards.
+
+
+ IF $ECODE[",M61," WRITE "Undefined local variable"
+
+ The leftmost character of the value of $ECODE is always a comma.
+ This means that every error code that is stored in $ECODE is
+ surrounded by commas. If $ECODE was to contains the error code
+ without the commas (that is, "M61"), the variable would check for
+ subset "M6" as well. Thus, it is recommended that you include the
+ commas in the value to check. For example; check whether $ECODE
+ contains ",M61,".
+
+ $ECODE can be SET but not NEW'd. When $ECODE is set to the empty string
+ (" "), error handling becomes "inactive" and therefore QUIT does not
+ trigger additional error handling.
+
+ When $ECODE is not set to the empty string, M error handling is active,
+ which also affects behaviour in some aspects of $STACK.
+
+2 $EStack
+ $EStack
+
+ $ES[TACK] contains an integer count of the number of M virtual machine
+ stack levels that have been activated and not removed since the last
+ time $ESTACK was NEW'd.
+
+ A NEW $ESTACK saves the value of current $ESTACK and then sets its
+ value to zero (0). If $ESTACK has not been NEW'd in the current
+ execution path, $ESTACK=$STACK.
+
+
+ SET $ETRAP="QUIT:$ESTACK GOTO LABEL^ROUTINE"
+
+ $ESTACK maybe used as a flag to indicate error traps invoked in
+ particular stack levels needed to perform some different action(s).
+ $ESTACK can be most useful in setting up a layered error trapping
+ mechanism.
+
+ GT.M does not permit $ESTACK to be SET, however $ESTACK can be
+ NEWed.
+
+2 $ETrap
+ $ETrap
+
+ $ET[RAP] contains a string value that GT.M invokes when an error occurs
+ during routine execution. When a process is initiated, but before any
+ commands are processed, the value of $ETRAP is empty string.
+
+ The value of this variable is the M[UMPS] code that gets executed when
+ an error occurs.
+
+
+ SET $ETRAP="QUIT:$ESTACK GOTO LABEL^ROUTINE"
+
+ The value of $ETRAP is changed with the SET command. Changing the value
+ of $ETRAP with the SET command initiates a new trap; it does not save
+ the old trap.
+
+ For more examples of the use of special variable $ETRAP, see the
+ function $STACK().
+
+2 $Horolog
+ $Horolog
+
+ $H[OROLOG] contains a string value specifying the number of days since
+ "31 December, 1840," and the number of seconds since midnight of the
+ current day, separated by a comma (,).
+
+ At midnight, the piece of the string following the comma resets to zero
+ (0) and the piece preceding the comma increments by one (1). GT.M does
+ not permit the SET command to modify $HOROLOG.
+
+ Example:
+
+
+ GTM> WRITE $HOROLOG
+
+ Produces the result 58883,55555 at 3:25:55 pm on 20 March, 2002.
+
+ For further information on formatting $HOROLOG for external use, see
+ the section on $ZDATE().
+
+2 $Io
+ $IO
+
+ $I[O] contains the name of the current device specified by the last USE
+ command. The M standard does not permit the SET command to modify $IO.
+ USE 0 produces the same $IO as USE $P[RINCIPAL], but $P is the
+ preferred construct.
+
+2 $Job
+ $Job
+
+ $J[OB] contains an integer value uniquely identifying the process
+ within the system environment.
+
+ GT.M uses the decimal representation of the VMS process identifier
+ (PID) for the value of $JOB. $JOB is guaranteed to be unique for every
+ concurrently operating process on a system. However, operating systems
+ reuse PIDs over time. GT.M does not permit the SET command to modify
+ $JOB.
+
+ Example:
+
+
+ LOOP0 FOR SET itm=$O(^tmp($J,itm)) Q:itm="" DO LOOP1
+
+ This uses $J as the first subscript in a temporary global to insure
+ that every process uses separate data space in the global ^tmp.
+
+2 $Key
+ $Key
+
+ $K[EY] contains the string that terminated the most recent READ command
+ from the current device (including any introducing and terminating
+ characters). If no READ command s issued to the current device or if no
+ terminator is used, the value of $KEY is an empty string. However, when
+ input is terminated by typing a function key, the value of $KEY is
+ equal to the string of characters that is transmitted by that function
+ key.
+
+ The effect of a READ *glvn on $KEY is unspecified.
+
+ If a Character Set Profile input-transform is in effect, then this is
+ also applied to the value stored in $KEY.
+
+2 $Principal
+ $Principal
+
+ $P[RINCIPAL] contains the name of the principal (initial $IO) device.
+ GT.M establishes $PRINCIPAL as a fully expanded VMS device
+ specification. $PRINCIPAL is an MDC Type A enhancement to standard M.
+
+ Input and output for a process may come from separate devices. VMS
+ designates these devices with the process-permanent logical names
+ SYS$INPUT and SYS$OUTPUT. However, the M I/O model allows only one
+ device to be USEd (or active) at a time. When an image starts, GT.M
+ implicitly OPENs the devices(s) identified by SYS$INPUT and SYS$OUTPUT
+ and assigns the device(s) to $PRINCIPAL. For USE deviceparameters, it
+ is the standard input that determines the device type.
+
+ For an image invoked interactively, $PRINCIPAL is the user's terminal.
+ For a batch job, $PRINCIPAL is the command file for input and the log
+ file for output. For an image invoked from a terminal by means of a
+ command file, $PRINCIPAL is the command file for input and the terminal
+ for output, unless the command file redefines the logical names
+ SYS$INPUT and/or SYS$OUTPUT. Generally an interactive command file
+ contains the following command immediately before it starts a GT.M
+ image.
+
+ Example:
+
+
+ $ DEFINE SYS$INPUT 'F$TRNLNM("SYS$COMMAND")'
+
+ This redirects the input for the process to come from the terminal.
+
+ GT.M provides a mechanism for the user to create a name for $PRINCIPAL
+ in DCL before invoking GT.M. The logical GTM$PRINCIPAL, if defined
+ becomes a synonym for the actual device and the value for $PRINCIPAL.
+ $IO holds the same value as $PRINCIPAL. $ZIO in this case, holds the
+ fully expanded name of the actual device. Refer to $ZIO section in this
+ chapter for an example of its usage.
+
+ GT.M ignores a CLOSE specifying the principal device. GT.M does not
+ permit the SET command to modify $PRINCIPAL.
+
+2 $Quit
+ $Quit
+
+ $Q[UIT] indicates whether the current block of code was called as an
+ extrinsic function or as a subroutine.
+
+ If $Q[UIT] contains 1 (when the current process-stack frame is invoked
+ by an extrinsic function), the QUIT would therefore require an
+ argument.
+
+ When a process is initiated, but before any commands are processed,
+ the value of $Q[UIT] is zero (0).
+
+ This special variable is mainly used in error-trapping conditions. Its
+ value tells whether the current DO level was reached by means of a
+ subroutine call (DO xxx) or by a function call (SET variable=$$xxx).
+
+ A typical way of exiting from an error trap is:
+
+ QUIT:$QUIT "" QUIT
+
+ GT.M does not permit $QUIT to be SET or NEWed.
+
+2 $Reference
+ $Reference
+
+ $R[EFERENCE] contains the last global reference. Until the first global
+ reference is made by an M program, $REFERENCE contains the empty string
+ (""). This way it is useful in determining if the usage of a naked
+ reference is valid.
+
+ A typical way of using this is:
+
+
+ IF $REFERENCE="" QUIT "<undefined>"
+
+ $R[EFERENCE] being a read-only variable cannot be SET or NEW'd.
+
+2 $STack
+ $STack
+
+ $ST[ACK] contains an integer value of zero (0) or greater indicating
+ the current level of M execution stack depth.
+
+ When a process is initiated but before any command is executed, the
+ value of $STACK is zero (0).
+
+ The difference between $STACK and $ESTACK is that $ESTACK may
+ appear as an argument of the NEW command. NEWing $ESTACK resets its
+ value to zero (0), and can be useful to set up a layered error
+ trapping mechanism.
+
+ The value of $STACK is "absolute" since the start of a GT.M. process,
+ whereas the value of $ESTACK is "relative" to the most recent
+ "anchoring point".
+
+ For examples on the use of special variable $STACK, refer to $STACK()
+ in the "Functions" chapter in this manual.
+
+2 $Storage
+ $Storage
+
+ $S[TORAGE] contains an integer value specifying the number of free
+ bytes of address space remaining between the memory currently under
+ management by the process and the theoretical maximum available to the
+ process.
+
+ GT.M uses memory for code (instructions) and data. If the amount of
+ virtual memory available to the process exceeds 2,147,483,647 bytes, it
+ is reported as 2,147,483,647 bytes.
+
+ Instruction space starts out with the original LINKed executable image.
+ However, GT.M may expand instruction space by ZLINKing additional
+ routines.
+
+ Data space starts out with stack space that never expands, and pool
+ space which may expand. GTM$DEFAULTS controls the initial sizes for
+ both elements of data space. Operations such as opening a database or
+ creating a local variable may cause an expansion in pool space. GT.M
+ expands pool space in fairly large increments. Therefore, SETs of local
+ variables may not affect $STORAGE at all or may cause an apparently
+ disproportionate drop in its value.
+
+ Once a GT.M process adds either instruction or data space, it never
+ releases that space. However, GT.M does reuse process space made
+ available by actions such as KILLs of local variables. $STORAGE can
+ neither be SET or NEWed.
+
+2 $SYstem
+ $SYstem
+
+ $SY[STEM] contains a string that identifies the executing M instance.
+ The value of $SYSTEM is a string that starts with a unique numeric code
+ that identifies the manufacturer. Codes are assigned by the MDC (MUMPS
+ Development Committee).
+
+ $SYSTEM in GT.M starts with "47" followed by a comma and the evaluation
+ of the logical name gtm_sysid. If the name has no evaluation, the value
+ after the comma is gtm_sysid.
+
+2 $Test
+ $Test
+
+ $T[EST] contains a truth value specifying the evaluation of the last IF
+ argument or the result of the last operation with timeout. If the last
+ timed operation timed out, $TEST contains FALSE (0); otherwise, it
+ contains TRUE (1).
+
+ $TEST serves as the implicit argument for ELSE commands and
+ argumentless IF commands.
+
+ M stacks $TEST when invoking an extrinsic and performing an
+ argumentless DO. After these operations complete with an implicit or
+ explicit QUIT, M restores the corresponding stacked value. Because,
+ with these two exceptions, $TEST reflects the last IF argument or
+ timeout result on a process wide basis. Use $TEST only in immediate
+ proximity to the operation that last updated it.
+
+ M routines cannot modify $TEST with the SET command.
+
+ Example:
+
+
+ IF x=+x DO ^WORK
+
+ ELSE SET x=0
+
+ The ELSE statement causes M to use the value of $TEST to determine
+ whether to execute the rest of the line. Because the code in routine
+ WORK may use IFs and timeouts, this use of $TEST is not recommended.
+
+ Example:
+
+
+ SET MYFLG=x=+x
+
+ IF MYFLG DO ^WORK
+
+ IF 'MYFLG SET x=0
+
+ This example introduces a local variable flag to address the problems
+ of the prior example. Note that its behavior results in the opposite
+ $TEST value from the prior example.
+
+ Example:
+
+
+ IF x=+x DO ^WORK IF 1
+
+ ELSE SET x=0
+
+ This example uses the IF 1 to ensure that the ELSE works counter to the
+ IF.
+
+2 $TLevel
+ $TLevel
+
+ $TL[EVEL] contains a count of executed TSTARTs that are currently
+ unmatched by TCOMMITs. $TLEVEL is zero (0) when there is no TRANSACTION
+ in progress. When $TLEVEL is greater than one (>1), it indicates that
+ there are nested sub-transactions in progress. Sub-transactions are
+ always subject to the completion of the main TRANSACTION and cannot be
+ independently acted upon by COMMIT, ROLLBACK, or RESTART.
+
+ $TLEVEL can be used to determine whether there is a TRANSACTION in
+ progress and to determine the level of nesting of sub-transactions.
+
+ M routines cannot modify $TLEVEL with SET.
+
+ Example:
+
+
+ IF $TLEVEL TROLLBACK
+
+ This example performs a TROLLBACK if a transaction is in progress. A
+ statement like this should appear in any error handler used with
+ transaction processing. For more information on transaction processing
+ refer to the "General Language Features of M" chapter in GT.M
+ Programmer's Guide.
+
+2 $TRestart
+ $TRestart
+
+ $TR[ESTART] contains a count of the number of times the current
+ TRANSACTION has been RESTARTed. A RESTART can be explicit (specified in
+ M as a TRESTART) or implicit (initiated by GT.M as part of its internal
+ concurrency control mechanism). When there is no TRANSACTION in
+ progress, $TRESTART is zero (0).
+
+ $TRESTART can be used by the application to limit the number of
+ RESTARTs, or to cause a routine to perform different actions during a
+ RESTART than during the initial execution.
+
+ GT.M does not permit the SET command to modify $TRESTART.
+
+ Example:
+
+
+ TRANS TSTART ():SERIAL
+
+ IF $TRESTART>2 WRITE !;"Access Conflict" QUIT
+
+ This example terminates the sub-routine with a message if the number of
+ RESTARTs exceeds 2.
+
+ For more information on transaction processing, refer to the section on
+ that topic in the "General Language Features of M" chapter in GT.M
+ Programmer's Guide.
+
+2 $X
+ $X
+
+ $X contains an integer value ranging from 0 to 65,535, specifying the
+ horizontal position of a virtual cursor in the current output record.
+ $X=0 represents the left-most position of a record or row.
+
+ Every OPEN device has a $X. However, M only accesses $X of the current
+ device. Therefore, exercise care in sequencing USE commands and
+ references to $X.
+
+ Generally, GT.M increments $X for every character written to and read
+ from the current device. M format control characters, write filtering,
+ and the device WIDTH also have an effect on $X.
+
+ $X never equals or exceeds the value of the device WIDTH. Whenever it
+ reaches the value equal to the device WIDTH, it gets reset to zero (0).
+
+ GT.M follows the MDC Type A recommendation and permits an M routine to
+ SET $X. However, SET $X does not automatically issue device commands or
+ escape sequences to reposition the physical cursor.
+
+ For more information on $X, refer to the "Input/Output Processing"
+ chapter in GT.M Programmer's Guide.
+
+2 $Y
+ $Y
+
+ $Y contains an integer value ranging from 0 to 65,535 specifying the
+ vertical position of a virtual cursor in the current output page. $Y=0
+ represents the top row or line.
+
+ Every OPEN device has a $Y. However, M only accesses $Y of the current
+ device. Therefore, exercise care in sequencing USE commands and
+ references to $Y.
+
+ When GT.M finishes the logical record in progress, it generally
+ increments $Y. GT.M recognizes the end of a logical record when it
+ processes certain M format control characters, or when the record
+ reaches its maximum size, as determined by the device WIDTH, and the
+ device is set to WRAP. The definition of "logical record" varies from
+ device to device. For an exact definition, see the sections on each
+ device type. Write filtering and the device LENGTH also have an effect
+ on $Y.
+
+ $Y never equals or exceeds the value of the device LENGTH. Whenever it
+ reaches the value equal to the device LENGTH, it gets reset to zero (0)
+
+ GT.M permits an M routine to SET $Y. However, SET $Y does not
+ automatically issue device commands or escape sequences to reposition
+ the physical cursor.
+
+ For more information on $Y, refer to the "Input/Output Processing"
+ chapter in GT.M Programmer's Guide.
+
+2 $ZA
+ $ZA
+
+ $ZA contains a status determined by the last read on the device. The
+ value is a decimal integer with a meaning determined by the device as
+ follows:
+
+ For Terminal I/O:
+
+ 0 Indicating normal termination of a read operation
+ 1 Indicating a parity error
+ 2 Indicating that the terminator sequence was too long
+ 3 Indicating a hardware contention or failure
+ 4 Indicating a system configuration issue
+ 5 Indicating a process limit/quota being exceeded
+ 9 Indicating a default for all other errors
+ For Sequential Disk Files I/O:
+
+ 0 Indicating normal termination of a read operation
+ 9 Indicating a failure of a read operation
+ For Mailbox I/O:
+
+ Decimal representing $JOB (identifier) of the process that wrote the
+ last message the current process read
+ $ZA refers to the status of the current device. Therefore, exercise
+ care in sequencing USE commands and references to $ZA.
+
+ GT.M does not permit the SET command to modify $ZA.
+
+ For more information on $ZA, refer to the "Input/Output Processing"
+ chapter in GT.M Programmer's Guide.
+
+2 $ZB
+ $ZB
+
+ $ZB contains a string specifying the input terminator for the last
+ terminal READ. $ZB contains null and is not maintained for devices
+ other than terminals. $ZB may contain any legal input terminator, such
+ as <CR> (ASCII 13) or an escape sequence starting with <ESC> (ASCII
+ 27), from zero (0) to 15 bytes in length. $ZB contains null for any
+ READ terminated by a timeout or any fixed-length READ terminated by
+ input reaching the maximum length.
+
+ $ZB contains the actual character string, not a sequence of numeric
+ ASCII codes.
+
+ Example:
+
+
+ SET zb=$ZB FOR i=1:1:$L(zb) WRITE !,i,?5,$A(zb,i)
+
+ This displays the series of ASCII codes for the characters in $ZB.
+
+ $ZB refers to the last READ terminator of the current device.
+ Therefore, exercise care in sequencing USE commands and references to
+ $ZB.
+
+ GT.M does not permit the SET command to modify $ZB.
+
+ For more information on $ZB, refer to the "Input/Output Processing"
+ chapter in GT.M Programmer's Guide.
+
+2 $ZCMdline
+ $ZCMdline
+
+ $ZCM[DLINE] contains a string value specifying the "excess" portion of
+ the command line that invoked the GT.M process. By "excess" is meant
+ the portion of the command line excluding the first argument (the VMS
+ command that corresponds to an image).When the VMS Command Language
+ Interpreter (CLI) invokes an image with a foreign command, it does not
+ process the "excess" of the command line. GT.M places this part of the
+ command line in $ZCMDLINE. $ZCMDLINE gives the M routine access to any
+ user DCL command line input. The DCL Shell interpretation of the input
+ removes one level of quotes. By default, if the input is not enclosed
+ in quotes (""), the CLI parser forces the input to upper case. M
+ routines cannot modify $ZCMDLINE.
+
+ Example:
+
+
+ $ create test.M
+
+ write $ZCMDLINE
+
+ halt
+
+ $ mumps test
+
+ $ link test
+
+ $ test == "$" + f$parse("TEST.EXE;")
+
+ $ test other information
+
+ OTHER INFORMATION
+
+ $
+
+ This creates the program test.M, then compiles and links it. The
+ example then assigns the symbol "test" and invokes "test" as a foreign
+ command. The M program writes out the remaining text from the invoking
+ DCL command line.
+
+ Example:
+
+
+ $ DCL2M :== $'f$parse("BASE.EXE;")
+
+ $ DCL2M PRINT^RPT2
+
+ This assigns the symbol DCL2M a value that is used to invoke BASE.EXE
+ as a foreign command. Then the example uses DCL2M with the "parameter"
+ PRINT^RPT2. Assuming BASE is a GT.M image, when the image activates,
+ $ZCMDLINE contains PRINT^RPT2.
+
+ Example:
+
+
+ BASE SET XECSTR="SET LEN=$LENGTH($T("_$ZCMDLINE_"))" X XECSTR IF
+ $L($ZCMDLINE),LEN DO @$ZCMDLINE
+ If $TEXT() can locate the entryref, this dispatches to a (sub-)routine
+ specified in $ZCMDLINE.
+
+2 $ZCOmpile
+ $ZCOmpile
+
+ $ZCO[MPILE] contains a string value composed of one or more qualifiers
+ that control the GT.M compiler. Explicit ZLINKs and auto-ZLINKs use
+ these qualifiers as defaults for any compilations that they perform.
+
+ $ZCOMPILE is a read-write Intrinsic Special Variable, that is, it can
+ appear on the left side of the equal sign (=) in the argument to the
+ SET command. A $ZCOMPILE value has the form of a list of M command
+ qualifiers, separated with a slash (/).
+
+ When the logical name GTM$COMPILE is defined, GT.M initializes
+ $ZCOMPILE to the translation of GTM$COMPILE. Otherwise, GT.M
+ initializes $ZCOMPILE to null. Changes to the value of $ZCOMPILE during
+ a GT.M invocation only last for the current invocation and do not
+ change the value of GTM$COMPILE.
+
+ When $ZCOMPILE is null, GT.M uses the default M command qualifiers
+ /IGNORE, /LABEL=LOWER, /NOLIST and /OBJECT. For detailed descriptions
+ of the M command qualifiers, refer to the "Program Development Cycle"
+ chapter in GT.M Programmer's Guide.
+
+ Example:
+
+
+ $ DEFINE GTM$COMPILE "/LIST/LENGTH=56/SPACE=2"
+
+ $ GTM
+
+ GTM> WRITE $ZCOMPILE
+
+ /LIST/LENGTH=56/SPACE=2
+
+ GTM> SET $ZCOMPILE="/LIST/NOIGNORE"
+
+ GTM> WRITE $ZCOMPILE
+
+ /LIST/NOIGNORE
+
+ GTM> ZLINK "A.M"
+
+ GTM> HALT
+
+ $ SHOW LOGICAL GTM$COMPILE
+
+ "GTM$COMPILE" = "/LIST/LENGTH=56/SPACE=2"
+
+ This uses the logical name GTM$COMPILE to set up $ZCOMPILE. Then it
+ modifies $ZCOMPILE with an M SET command. The ZLINK argument specifies
+ a file with a .M extension (type), which forces a compile. The compile
+ produces a listing for routine A.M and does not produce an object
+ module if ^A contains errors. After GT.M terminates, the DCL command
+ SHOW LOGICAL demonstrates that the M SET command did not change the
+ logical name equivalence.
+
+2 $ZCstatus
+ $ZCstatus
+
+ $ZC[STATUS] holds the value of the status code for the last compilation
+ performed by a ZCOMPILE command.
+
+ GT.M does not permit the SET command to modify $ZSTATUS.
+
+2 $ZDAteform
+ $ZDAteform
+
+ $ZDA[TEFORM] contains an integer value, specifying the output year
+ format of $ZDATE(). $ZDATEFORM can be modified using the SET command.
+ GT.M initializes $ZDATEFORM to the translation of the logical name
+ gtm_zdate_form. If gtm_zdate_form is not defined, GT.M initializes
+ $ZDATEFORM to zero (0).
+
+ Refer to "Functions" and "M utility Routines" chapter in GT.M
+ Programmer's Guide for more details.
+
+ Example:
+
+
+ GTM>WRITE $ZDATEFROM
+
+ 0
+ GTM>WRITE $ZDATE($H)
+
+ 11/15/02
+ GTM>SET $ZDATEFORM=1
+
+ GTM>WRITE $ZDATE($H)
+
+ 11/15/2002
+2 $ZDirectory
+ $ZDirectory
+
+ $ZD[IRECTORY] contains the string value of the full path of the current
+ directory. Initially $ZDIRECTORY contains the default/current directory
+ from which the GT.M image/process was activated.
+
+ GT.M supports different forms for the intrinsic special variable
+ $ZDIRECTORY. The symbol GTM$ZDIR_FORM in GTM$DEFAULTS controls the form
+ of $ZDIRECTORY. By default, $ZDIRECTORY contains the full path of the
+ default directory, including the device and directory specification.
+ The default form corresponds to GTM$ZDIR_FORM holding the value zero
+ (0). The other possible value for GTM$ZDIR_FORM is one (1). This value
+ causes $ZDIRECTORY to contain only the directory specification,
+ excluding the device specification.
+
+ If the application would like to use the non-default form of
+ $ZDIRECTORY, one can modify the value for GTM$ZDIR_FORM in GTM$DEFAULTS
+ appropriately before creating a linked image of the application.
+
+ Example:
+
+
+ GTM>WRITE $ZDIR
+
+ DISK$USER11:[PROD.AP.ROUTINES]
+
+ GTM>SET $ZDIR="[-]"
+
+ GTM>WRITE $ZDIR
+
+ DISK$USER11:[PROD.AP]
+
+ This example displays the current default directory in the default form
+ of ZDIRECTORY which includes both the device and the directory
+ specification. It also changes $ZDIRECTORY to point to the parent
+ directory.
+
+ $ZDIRECTORY is a read-write Intrinsic Special Variable, that is, it can
+ appear on the left side of the equal sign (=) in the argument to a SET
+ command. If an attempt is made to set $ZDIRECTORY to a non-existent
+ directory specification, GT.M issues an error and keeps the value of
+ $ZDIRECTORY unchanged.
+
+ At image exit, GT.M restores the working directory to the directory
+ that was the default when GT.M was invoked. The only exception to this
+ is in case the directory does not exist and GT.M had successfully
+ modified its default directory using SET $ZDIR at least once. In such
+ cases, the default directory at image exit is the last directory to
+ which GT.M successfully changed its default directory using SET $ZDIR.
+
+2 $ZEDit
+ $ZEDit
+
+ $ZED[IT] holds the value of the status code for the last edit session
+ invoked by a ZEDIT command.
+
+ GT.M does not permit the SET or NEW command to modify $ZEDIT.
+
+2 $ZEOf
+ $ZEOf
+
+ $ZEO[F] contains a truth-valued expression indicating whether the last
+ READ operation reached the end-of-file. $ZEOF equals TRUE (1) at EOF
+ and FALSE (0) at other positions.
+
+ GT.M does not maintain $ZEOF for terminal devices.
+
+ $ZEOF refers to the end-of-file status of the current device.
+ Therefore, exercise care in sequencing USE commands and references to
+ $ZEOF.
+
+ GT.M does not permit the SET or NEW command to modify $ZEOF.
+
+ For more information on $ZEOF, refer to the "Input/Output Processing"
+ chapter.
+
+2 $ZError
+ $ZError
+
+ $ZE[RROR] is supposed to hold the application-specific error-code
+ corresponding to the GT.M error-code stored in $ECODE/$ZSTATUS (refer
+ to their description in this chapter).
+
+ $ZERROR contains a default value of "Unprocessed $ZERROR, see $ZSTATUS"
+ at process startup.
+
+ $ZERROR can be SET but not NEWed.
+
+ The mapping of a GT.M error-code to the application-specific error-code
+ is achieved as follows. Whenever GT.M encounters an error,
+ $ECODE/$ZSTATUS gets set first. It then invokes the code that $ZYERROR
+ (see description later in this chapter) points to if it is not null. It
+ is intended that the code invoked by $ZYERROR use the value of $ZSTATUS
+ to select or construct a value to which it SETs $ZERROR. If an error is
+ encountered by the attempt to execute the code specified in $ZYERROR,
+ GT.M sets $ZERROR to the error status encountered. If $ZYERROR is null,
+ GT.M does not change the value of $ZERROR. In all cases, GT.M proceeds
+ to return control to the code specified by $ZTRAP/$ETRAP or device
+ EXCEPTION whichever is applicable.
+
+2 $ZGbldir
+ $ZGbldir
+
+ $ZG[BLDIR] contains the value of the current Global Directory filename.
+ When $ZGBLDIR specifies an invalid or inaccessible file, GT.M cannot
+ successfully perform database operations.
+
+ GT.M initializes $ZGBLDIR to the translation of the logical name
+ GTM$GBLDIR. If GTM$GBLDIR is not defined, GTM initializes $ZGBLDIR to
+ null. When $ZGBLDIR is null, GT.M constructs a file-specification for
+ the Global Directory using the name GTM$GBLDIR and the extension .GLD
+ in the process current default directory. A $ZGBLDIR value has the form
+ of an RMS file-specification, which may include a logical name. GT.M
+ handles logical names that translate to other logical names by
+ performing iterative translations according to VMS conventions. If a
+ logical name translates to a VMS search list, GT.M uses only the first
+ name in the list.
+
+ $ZGBLDIR is a read-write Intrinsic Special Variable, that is, it can
+ appear on the left side of the equal sign (=) in the argument to the
+ SET command. SET $ZGBLDIR="" causes GT.M to assign $ZGBLDIR to the
+ translation of GTM$GBLDIR, if that logical name is defined. If
+ GTM$GBLDIR is not defined, then SET $ZGBLDIR="" causes GT.M to assign
+ the string "GTM$GBLDIR" to $ZGBLDIR. This specifies the file
+ GTM$GBLDIR.GLD in the current directory. GT.M permits $ZGBLDIR to be
+ NEW'd.
+
+ SETting $ZGBLDIR also causes GT.M to attempt to open the specified
+ file. If the file name is invalid or the file is inaccessible, GT.M
+ triggers an error without changing the value of $ZGBLDIR.
+
+ To establish a value for $ZGBLDIR outside of M, use the DCL DEFINE
+ command to assign a translation to GTM$GBLDIR. Defining GTM$GBLDIR
+ provides a convenient way to use the same Global Directory during a
+ session where you repeatedly invoke and leave GT.M.
+
+ Frequently, a system manager provides a default definition of
+ GTM$GBLDIR in the system logical name table or in the login command
+ files. You can override such a definition by (re)defining GTM$GBLDIR in
+ your process logical name table.
+
+ Changes to the value of $ZGBLDIR during a GT.M invocation only last for
+ the current invocation and do not change the value of GTM$GBLDIR.
+
+ Example:
+
+
+ $ DEFINE GTM$GBLDIR TEST.GLD
+
+ $ GTM
+
+ GTM> WRITE $ZGBLDIR
+
+ TEST.GLD
+
+ GTM> SET $ZGBLDIR="MUMPS.GLD"
+
+ GTM> WRITE $ZGBLDIR
+
+ MUMPS.GLD
+
+ GTM> HALT
+
+ $ SHOW LOGICAL GTM$GBLDIR
+
+ TEST.GLD
+
+ This defines the logical name, GTM$GBLDIR. In GT.M Direct Mode,
+ $ZGBLDIR has the value supplied by GTM$GBLDIR. The SET command changes
+ the value. After the GT.M image terminates, the DCL command SHOW
+ LOGICAL demonstrates that GTM$GBLDIR was not modified by the M SET
+ command.
+
+ Example:
+
+
+ $ DIR TEST.GLD
+
+ %DIRECT-W-NOFILES, no files found
+
+ $ GTM
+
+ GTM> WRITE $ZGBLDIR
+
+ MUMPS.GLD
+
+ GTM> SET $ZGBLDIR="TEST.GLD"
+
+ %GTM-E-ZGBLDIRACC, Cannot access global
+
+ directory "TEST.GLD". Continuing with "MUMPS.GLD
+
+ %RMS-E-FNF, file not found
+
+ GTM> WRITE $ZGBLDIR
+
+ MUMPS.GLD
+
+ GTM> HALT
+
+ $
+
+ The SET command attempts to change the value of $ZGBLDIR to TEST.GLD,
+ but because the file does not exist, GT.M reports an error and does not
+ change the value of $ZGBLDIR.
+
+ Attempting to restore an inaccessible initial Global Directory that
+ has been NEW'd, can cause an error.
+
+2 $ZINTerrupt
+ $ZINTerrupt
+
+ $ZINT[ERRUPT] specifies the code to be XECUTE'd when an interrupt (for
+ example, through a MUPIP INTRPT) is processed. While a $ZINTERRUPT
+ action is in process, any additional interrupt signals are discarded.
+ When an interrupt handler is invoked, the current values of $REFERENCE
+ is saved and restored when the interrupt handler returns. The current
+ device ($IO) is neither saved nor restored.
+
+ GT.M permits the SET command to modify the value of $ZINTERRUPT.
+
+ If an interrupt handler changes the current IO device (via USE), it is
+ the responsibility of the interrupt handler to restore the current IO
+ device before returning. There are sufficient legitimate possibilities
+ why an interrupt routine would want to change the current IO device
+ (for example; daily log switching), that this part of the process
+ context is not saved and restored automatically.
+
+ The initial value for $ZINTERRUPT is taken from the VMS logical name
+ GTM_ZINTERRUPT if it is specified, otherwise it defaults to the
+ following string:
+
+ IF $ZJOBEXAM()
+
+ The IF statement executes the $ZJOBEXAM function but effectively
+ discards the return value.
+
+ If the default value for $ZINTERRUPT is modified, no $ZJOBEXAM()
+ will occur unless the replacement value directly or indirectly
+ invokes that function. In other words, while $ZJOBEXAM() is part of
+ the interrupt handling by default, it is not an implicit part of
+ the interrupt handling.
+
+3 Inter_Handl_GTM
+ Interrupt Handling in GT.M
+
+ The interrupt handler is executed by GT.M when on a statement boundary
+ or on an appropriate boundary in a potentially long running COMMAND (in
+ the same place as <CTRL>-C is recognized). If a GT.M process is in a
+ long running external call (for example; waiting in a message queue)
+ the interrupt handler cannot be driven immediately. The interrupt
+ request is recognized and the handler is driven after the external call
+ returns to GT.M and an appropriate execution boundary is reached.
+
+ Since sending an interrupt signal requires the sender to have
+ appropriate permissions from VMS, the use of the interrupt facility
+ itself does not present any inherent security exposures. Nonetheless,
+ because the dump files created by the default action contain the values
+ of every local variable in the context at the time they are made,
+ inappropriate access to the dump files would constitute a security
+ exposure. Make sure the design and implementation of any interrupt
+ logic includes careful consideration to security issues.
+
+ If an error occurs while compiling the $ZINTERRUPT code, the action
+ taken depends on the process state at the time the interrupt was
+ received and the error handler is not invoked (the error handler is
+ invoked if an error occurs while executing the $ZINTERRUPT code). If
+ the GT.M process is at a direct mode prompt or is executing a direct
+ mode command (for example, a FOR loop), the error message is sent to
+ the user console along with the GTM-ERRWZINTR error (refer to the GT.M
+ Error and Message Recovery Manual). In addition, the GTM-ERRWZINTR
+ error is also sent to the operator log facility. IF the process is not
+ at a direct mode prompt or executing a direct mode command, the
+ GTM-ERRWZINTR message and the compiler error message are sent to the
+ operator log facility and nothing is displayed on the user's console.
+ In both cases, the interrupted process resumes execution.
+
+ If an error occurs during execution of the interrupt handler's stack
+ frame (before it calls anything), that error is prefixed with the
+ GTM-ERRWZINTR error. The error handler then executes normal error
+ processing associated with the module that was interrupted. Any other
+ errors that occur in code called by the interrupt handler are handled
+ by normal error handling.
+
+ The interrupt handler does not operate "outside" the current M
+ environment but rather within the environment of the process.
+
+ If a TP transaction is in progress (0<$TLEVEL), updates to globals are
+ not safe since a TP restart can be signaled at any time prior to the
+ transaction being committed - even after the interrupt handler returns.
+ A TP restart reverses all global updates and unwinds the M stack so it
+ is as if the interrupt never occurred. The interrupt handler is not
+ redriven as part of a transaction restart. Referencing (reading)
+ globals inside an interrupt handler can trigger a TP restart if a
+ transaction is active. When programming interrupt handling, either
+ discard interrupts when 0<$TLEVEL (forcing the interrupting party to
+ try again), or use local variables that are not restored by a TRESTART
+ to defer the interrupt action until after the final TCOMMIT.
+
+ Note that it is possible for the interrupt handler to be executed while
+ the process executing the M routine is holding the critical section for
+ one or more regions. Use of this feature may create temporary hangs or
+ pauses while the interrupt handler executes. For the default case where
+ the interrupt handler uses $ZJOBEXAM() to create a dump, the pause
+ duration depends on the number of local variables in the process at the
+ time of the dump and on the speed of the disk being written to. The
+ dumps are slower on a network-mounted disk than on a disk directly
+ connected to the local system. Any interrupt driven code should be
+ designed to account for this issue.
+
+2 $ZINInterrupt
+ $ZINInterrupt
+
+ $ZINI[NTERRUPT] evaluates to 1 (TRUE) when a process is executing code
+ initiated by the interrupt mechanism, and otherwise 0 (FALSE).
+
+ GT.M does not permit the SET or NEW commands to modify $ZININTERRUPT.
+
+2 $ZIO
+ $ZIO
+
+ $ZIO contains the translated name of the current device, in contrast to
+ $IO, which contains the name as specified by the USE command.
+
+ GT.M does not permit the SET or NEW command to modify $ZIO.
+
+ An example where $ZIO contains a value different from $IO is if the
+ logical GTM$PRINCIPAL is defined.
+
+ Example:
+
+
+ $ define gtm$principal foo
+
+ GTM>WRITE $IO
+
+ FOO
+
+ GTM>WRITE $ZIO
+
+_TNA275:
+ Notice that $ZIO contains the actual terminal device name while $IO
+ contains the string pointed to by the logical GTM$PRINCIPAL.
+
+2 $ZJob
+ $ZJob
+
+ $ZJ[OB] holds the pid of the process created by the last JOB command
+ performed by the current process.
+
+ GT.M initializes $ZJOB to zero (0) at process startup. If the JOB
+ command fails to spawn a new job, GT.M sets $ZJOB to zero (0). Note
+ that because of the left to right evaluation order of M, using $ZJOB in
+ the jobparameter string results in using the value created by the last,
+ rather than the current JOB command, which is not likely to match
+ common coding practice.
+
+ GT.M does not permit the SET or NEW command to modify $ZJOB.
+
+2 $ZLevel
+ $ZLevel
+
+ $ZL[EVEL] contains an integer value indicating the "level of nesting"
+ caused by DO commands, XECUTE commands, and extrinsic functions in the
+ M invocation stack.
+
+ $ZLEVEL has an initial value of one (1) and increments by one with each
+ DO, XECUTE or extrinsic function. Any QUIT that does not terminate a
+ FOR loop decrements $ZLEVEL. ZGOTO may also reduce $ZLEVEL. In
+ accordance with the M standard, a FOR command does not increase
+ $ZLEVEL. M routines cannot modify $ZLEVEL with the SET or NEW commands.
+
+ Use $ZLEVEL in debugging or in an error-handling mechanism to capture a
+ level for later use in a ZGOTO argument.
+
+ Example:
+
+
+ GTM>ZPRINT ^ZLEV
+
+ A DO B
+
+ WRITE X,!
+
+ QUIT
+
+ B GOTO C
+
+ QUIT
+
+ C DO D
+
+ QUIT
+
+ D SET X=$ZLEVEL
+
+ QUIT
+
+ GTM>DO ^ZLEV
+
+ 4
+ This program, executed from Direct Mode, produces a value of 4 for
+ $ZLEVEL. Note that if we RUN this program from the DCL level the value
+ of $ZLEVEL is three (3).
+
+2 $ZMAXTPTIme
+ $ZMAXTPTIme
+
+ $ZMAXTPTI[ME] contains an integer value indicating the time duration
+ GT.M should wait for the completion of all activities fenced by the
+ current transaction's outermost TSTART/TCOMMIT pair.
+
+ $ZMAXTPTIME can be SET but cannot be NEWed.
+
+ The initial value of $ZMAXTPTIME is zero (0) seconds, which indicates
+ "no timeout" (unlimited time). The value of $ZMAXTPTIME when a
+ transaction's outermost TSTART operation executes determines the
+ timeout setting for that transaction.
+
+ When a $ZMAXTPTIME expires, GT.M executes the $ETRAP/$ZTRAP exception
+ handler currently in effect.
+
+ Negative values of $ZMAXTPTIME are also treated as "no timeout".
+ Timeouts apply only to the outermost transaction, that is,
+ $ZMAXTPTIME has no effect when TSTART is nested within another
+ transaction.
+
+ Example:
+
+
+ Test ;testing TP timeouts
+
+ set $ZMAXTPTIME=6,^X=0,^Y=0,^Z=0
+
+ write "Start with $ZMAXTPTIME=",$ZMAXTPTIME,":",!
+
+ for sleep=3:2:9 do
+
+ . set retlvl=$zl
+
+ . do longtran ;ztrap on longtran
+
+ ;continues execution
+
+ ;on next line
+
+ . write "(^X,^Y)=(",^X,",",^Y,")",!
+
+ write !,"Done TP Timeout test.",!
+
+ quit
+
+ longtran ;I/O in TP doesn't get rolled back
+
+ set newzt="set $ZT="""" ";avoid recursive ZTRAP
+
+ set $ZT=newzt_" goto err"
+
+ tstart ():serial ;plain tstart works as well
+
+ set ^X=1+^X
+
+ write !,"^X=",^X,",will set ^Y to ",sleep
+
+ write " in ",sleep," seconds..."
+
+ hang sleep
+
+ set ^Y=sleep
+
+ write "^Y=",^Y
+
+ tcommit
+
+ write "...committed.",!
+
+ quit
+
+ err ;
+
+ set $ZT=""
+
+ write !,"In $ZTRAP handler. Error was: "
+
+ write !," ",$zstatus
+
+ if $TLEVEL do ;test allows handler use outside of TP
+
+ . trollback
+
+ . write "Rolled back transaction."
+
+ write !
+
+ zgoto retlvl
+
+
+ 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
+ $ZMOde
+
+ $ZMO[DE] contains a string value indicating the process execution mode.
+
+ The mode can be:
+
+ o INTERACTIVE
+
+ o BATCH
+
+ o NETWORK
+
+ o OTHER
+
+ M routines cannot modify $ZMODE.
+
+ Example:
+
+
+ GTM> WRITE $ZMODE
+
+ INTERACTIVE
+
+ This displays the process mode.
+
+2 $ZPOSition
+ $ZPOSition
+
+ $ZPOS[ITION] contains a string value specifying the current entryref,
+ where entryref is [label][+offset]^routine, and the offset is evaluated
+ from the closest preceding label.
+
+ GT.M does not permit the SET or NEW commands to modify $ZPOSITION.
+
+ Example:
+
+ GTM>WRITE !,$ZPOS,! ZPRINT @$ZPOS
+
+ This example displays the current location followed by the source code
+ for that line.
+
+2 $ZPROCess
+ $ZPROCess
+
+ $ZPROC[ESS] contains the string value of the current process name.
+
+ M routines cannot modify $ZPROCESS.
+
+ Example:
+
+
+ GTM> WRITE $ZPROCESS
+
+ JONES_SUSAN_1
+
+ This displays the process name.
+
+2 $ZPROMpt
+ $ZPROMpt
+
+ $ZPROM[PT] contains a string value specifying the current Direct Mode
+ prompt. By default, GTM> is the Direct Mode prompt. M routines can
+ modify $ZPROMPT by means of a SET command. $ZPROMPT cannot exceed 16
+ characters. If an attempt is made to assign $ZPROMPT to a longer
+ string, only the first 16 characters will be taken.
+
+ Example:
+
+
+ GTM>SET $ZPROMPT="NEWZPROMPT>"
+
+ NEWZPROMPT>
+
+ This example changes the GT.M prompt to be NEWZPROMPT
+
+2 $ZROutines
+ $ZROutines
+
+ $ZRO[UTINES] contains a string value specifying a VMS directory or
+ object library, or list of VMS directories and/or object libraries,
+ containing object files. Each object directory may also have an
+ associated directory, or list of directories, containing the
+ corresponding source files. These directory lists are used by certain
+ GT.M functions, primarily auto-ZLINK, to locate object and source
+ files. The order in which directories appear in a given list determines
+ the order in which they are searched for the appropriate item.
+
+ Searches that use $ZROUTINES treat files as either object or source
+ files. GT.M treats files with a type of .OBJ or files in an object
+ library as object files and all other files as source files. GT.M
+ always assumes source files have a type of .M unless an explicit ZLINK,
+ $ZSOURCE or the source file pointer in an object file specify
+ otherwise.
+
+3 Est_Val_frm_GTM$ROUTINES
+ Establishing the Value from GTM$ROUTINES
+
+ When the logical name GTM$ROUTINES is defined, GT.M initializes
+ $ZROUTINES to the value of GTM$ROUTINES. Otherwise, GT.M initializes
+ $ZROUTINES to null. When $ZROUTINES is null, GT.M attempts to locate
+ all source and object files in the process current default directory.
+ $ZROUTINES="" is equivalent to $ZROUTINES="[]".
+
+ Commands or functions such as DO, GOTO, ZGOTO, ZBREAK, ZPRINT, and
+ $TEXT may auto-ZLINK and thereby indirectly use $ZROUTINES. If their
+ argument does not specify a directory, ZEDIT and explicit ZLINK use
+ $ZROUTINES. ZPRINT and $TEXT use $ZROUTINES to locate a source file if
+ GT.M cannot find the source file pointed to by the object file. For
+ more information on ZLINK and auto-ZLINK, refer to the "Program
+ Development Cycle" and "Commands" chapters in GT.M Programmer's Guide.
+
+ $ZROUTINES is a read-write Intrinsic Special Variable, which M can also
+ SET the value. A $ZROUTINES value must have the form of a list of RMS
+ directory and/or file-specifications delimited by commas (,).
+
+3 Set_Val_for_$ZRO
+ Setting a Value for $ZROUTINES
+
+ By default, each directory entry in $ZROUTINES is assumed to contain
+ both object and source files. However, each object directory may have
+ an associated directory or list of directories in which to search for
+ the corresponding source files. This is done with the
+ /SRC=directory-list qualifier. If /SRC= specifies more than one
+ directory, the directories must be separated by commas, and the entire
+ list must be enclosed in parentheses ().
+
+ If a directory has a /SRC= qualifier, and it should be searched for
+ source, the argument for the /SRC must include the name of that
+ directory, usually as the first element in the list.
+ Directory-specifications may also have a /NOSRC qualifier, directing
+ GT.M to proceed as if no source files exist for objects located in the
+ qualified directory.
+
+ File-specifications in $ZROUTINES indicate object libraries. If you
+ specify file-specifications, indicating object-libraries, rather than
+ specifying object directories, the command assumes the /NOSRC
+ qualifier. You may not specify source directories for an object
+ library.
+
+ Because /NOSRC directories and object libraries prevent automatic
+ recompilation of the objects they contain, use them with caution in a
+ development environment.
+
+ To set $ZROUTINES outside of M, use the DCL command DEFINE to assign a
+ translation to GTM$ROUTINES. Because GTM$ROUTINES is not a VMS search
+ list, but rather a piece of data, usually containing one or more commas
+ (,), that is passed to a GT.M process, enclose the equivalent parameter
+ to the DEFINE or ASSIGN command in quotes (" "). If the definition
+ contains commas and is not enclosed in quotes, VMS treats it as a VMS
+ search list and the GT.M process subsequently receives an improperly
+ formatted $ZROUTINES.
+
+ Frequently a system manager provides a default definition of
+ GTM$ROUTINES in the system logical name table or in the login command
+ files. You can override such a definition by (re)defining GTM$ROUTINES
+ in your process logical name table. Changes to the value of $ZROUTINES
+ during a GT.M invocation only last for the current invocation and do
+ not change the value of GTM$ROUTINES.
+
+ Either directory- or file-specifications may include a logical name.
+ GT.M handles logical names that translate to other logical names by
+ performing iterative translations according to VMS conventions. If a
+ logical name translates to a VMS search list, GT.M uses only the first
+ name in the list. If the directory or file exists on a different node
+ or device, the list element must specify the node and/or device. When
+ GT.M SETs $ZROUTINES, it translates all logical names and verifies the
+ syntax and the existence of all specified directories and libraries. If
+ $ZROUTINES is set to an invalid value, GT.M generates a run-time error
+ and does not change the value of $ZROUTINES. Because the logical names
+ are translated when $ZROUTINES is set, any changes to their definition
+ have no effect until $ZROUTINES is next set.
+
+3 $ZRO_Examples
+ $ZROUTINES Examples
+
+ Example:
+
+
+ $ DEFINE GTM$ROUTINES "[JONES],[SMITH]"
+
+ $ GTM
+
+ GTM> WRITE $ZROUTINES
+
+ "[JONES],[SMITH]"
+
+ GTM> SET $ZRO="[JONES.UTL],[SMITH.UTL]"
+
+ GTM> WRITE $ZRO
+
+ [JONES.UTL],[SMITH.UTL]
+ GTM> HALT
+
+ $ SHOW LOGICAL GTM$ROUTINES
+
+ "GTM$ROUTINES" = "[JONES],[SMITH]"(LNM$PROCESS_TABLE)
+
+ This defines the logical name, GTM$ROUTINES. Upon entering GT.M Direct
+ Mode $ZROUTINES has the value supplied by GTM$ROUTINES. The SET command
+ changes the value. When the GT.M image terminates, the DCL command SHOW
+ demonstrates that GTM$ROUTINES has not been modified by the M SET
+ command.
+
+ Example:
+
+
+ GTM> SET $ZRO="[],[SMITH],MYLIB.OLB"
+
+ This sets $ZROUTINES to a list containing two directories and an object
+ library in the process current default directory.
+
+ Example:
+
+
+ GTM> SET $ZRO="[SMITH]/SRC=([SMITH.TAX],[SMITH.FICA])"
+
+ This specifies that GT.M should search the directory [SMITH] for object
+ files and the directories [SMITH.TAX] and [SMITH.FICA] for source
+ files. Note that in this example, GT.M does not search [SMITH] for
+ source files.
+
+ Example:
+
+ GTM> SET $ZRO="[SMITH]/SRC=([SMITH],[SMITH.TAX],[SMITH.FICA])"
+
+ This specifies that GT.M should search the directory [SMITH] for object
+ files and the directories [SMITH.TAX] and [SMITH.FICA] for source
+ files. Note that the difference between this example and the previous
+ one is that in this example GT.M searches [SMITH] for both object and
+ source files.
+
+ Example:
+
+
+ GTM> SET $ZRO="[SMITH],[SMITH.TAX]/NOSRC,
+
+ [SMITH.FICA]"
+ This specifies that GT.M should search [SMITH] and [SMITH.FICA] for
+ object and source files. However, because the /NOSRC qualifier
+ indicates directories searched only for object files, GT.M does not
+ search [SMITH.TAX] for source files.
+
+ Omission of the /SRC= and /NOSRC indicates GT.M can search the
+ directory for both source and object files. $ZROUTINES="[SMITH]" is
+ equivalent to $ZROUTINES="[SMITH]/SRC=[SMITH]".
+
+3 $ZRO_Search_Types
+ $ZROUTINES Search Types
+
+ GT.M uses $ZRO[UTINES] to perform three types of searches:
+
+ o Object-only when the command or function using $ZROUTINES requires
+ a .OBJ file extension.
+
+ o Source-only when the command or function using $ZROUTINES requires
+ a file extension other than .OBJ.
+
+ o Object-source match when the command or function using $ZROUTINES
+ does not specify a file extension.
+
+ An explicit ZLINK that specifies a non .OBJ extension is considered as
+ a function that has not specified a file extension for the above
+ searching purposes.
+
+ All searches proceed from left to right through $ZROUTINES. By default,
+ GT.M searches directories for both source and object files. GT.M
+ searches /NOSRC directories and object libraries only for object files.
+ GT.M searches directories listed in a /SRC= qualifier only for source
+ files.
+
+ Once an object-matching search locates an object file, the source
+ search becomes limited. If the directory containing the object file has
+ a /SRC= qualifier, GT.M only searches the directories in the attached
+ list for matching source files. If the directory containing the object
+ files has no qualifier, GT.M restricts the search for matching source
+ files to the same directory. If the object module is in an object
+ library, or a directory qualified by /NOSRC, GT.M cannot perform any
+ operation that references the source file.
+
+3 $ZRO_Search_Ex
+ $ZROUTINES Search Examples
+
+ This section describes a model for understanding $ZROUTINES operations
+ and the illustrating examples, which may assist you if you wish to
+ examine the topic closely.
+
+ You may think of $ZROUTINES as supplying a two dimensional matrix of
+ places to look for files. The matrix has one or more rows. The first
+ row in the matrix contains places to look for object and the second and
+ following rows contain places to look for source. Each column
+ represents the set of places that contain information related to the
+ object modules in the first row of the column.
+
+ Example:
+
+
+ GTM> s $zro="[],[smi.utl]/nosrc,[jon.utl]
+
+ /src=([jon.utl.so],[smi.utl)"
+
+2 $ZSOurce
+ $ZSOurce
+
+ $ZSO[URCE] contains a string value specifying the default
+ file-specification for the ZEDIT and ZLINK commands. ZEDIT or ZLINK
+ without an argument is equivalent to ZEDIT/ZLINK $ZSOURCE.
+
+ $ZSOURCE initially contains the null string. When ZEDIT and ZLINK
+ commands have an argument, they implicitly set $ZSOURCE to a partial
+ file-specification derived from their argument. The partial
+ specification consists of a device name, a directory path and a file
+ name. The file-specification may contain a file type without a version
+ number. ZEDIT or ZLINK without an argument is equivalent to ZEDIT/ZLINK
+ $ZSOURCE.
+
+ $ZSOURCE never contains the ".M" or ".OBJ" file types.
+
+ $ZSOURCE is a read-write Intrinsic Special Variable, (i.e., it can
+ appear on the left side of the equal sign (=) in the argument to the
+ SET command). A $ZSOURCE value has the form of an RMS
+ file-specification, which may include a logical name. GT.M handles
+ logical names that translate to other logical names by performing
+ iterative translations according to VMS conventions. If a logical name
+ translates to a VMS search list, GT.M uses only the first name in the
+ list.
+
+ Example:
+
+
+ GTM> ZEDIT "SUBR.M"
+
+ .
+
+ .
+
+ GTM> WRITE $ZSOURCE
+
+ SUBR
+
+ Example:
+
+ GTM> ZEDIT "TEST"
+
+ .
+
+ .
+
+ .
+
+ GTM> WRITE $ZSOURCE
+
+ TEST
+
+ Example:
+
+
+ GTM> ZEDIT "[USER.SMITH]REPORT.TXT"
+
+ .
+
+ .
+
+ .
+
+ GTM> WRITE $ZSOURCE
+
+ [USER.SMITH]REPORT.TXT
+ Example:
+
+ GTM> ZLINK "BASE.OBJ"
+
+ .
+
+ .
+
+ .
+
+ GTM> WRITE $ZSOURCE
+
+ BASE
+
+2 $ZStatus
+ $ZStatus
+
+ $ZS[TATUS] contains a string value specifying the error condition code
+ and location of the last exception condition that occurred during
+ routine execution.
+
+ GT.M maintains $ZSTATUS as a string consisting of three or more
+ substrings. The string consists of the following:
+
+ o An error message number as the first substring.
+
+ o The entryref of the line in error as the second substring; a comma
+ (,) separates the first and second substrings.
+
+ o The message detail as the third substring. The format of this is a
+ percent sign (%) identifying the message facility, a hyphen (-)
+ identifying the error severity, another hyphen identifying the
+ message identification followed by a comma (,), which is followed
+ by the message text if any:
+
+ Format: %<FAC>-<SEV>-<ID>, <TEXT>
+
+ Example: %GTM-E-DIVZERO, Attempt to divide by zero
+
+ The DCL command SET MESSAGE does not affect the format of the $ZSTATUS
+ string. $ZSTATUS always contains all components of the VMS error
+ message format (message number, facility, error severity,
+ identification and text).GT.M sets $ZSTATUS when it encounters errors
+ during program execution, but not when it encounters errors in a Direct
+ Mode command.
+
+ When a VMS system component such as RMS detects an error, the error
+ message number is a VMS condition code. When a GT.M system component
+ detects an error, the message number is a GT.M condition code. You can
+ establish your own condition codes using the VMS MESSAGE utility and
+ invoke them using the GT.M ZMESSAGE command. For more information on
+ GT.M condition codes, refer to the "GT.M Messages & Recovery Manual".
+ For more information on the VMS message facility, refer to the VMS
+ Message Utility Manual.
+
+ $ZSTATUS is a read-write Intrinsic Special Variable, (i.e., it can
+ occur on the left side of the equal sign (=) in the argument to the SET
+ command). While it will accept any string, Sanchez Computer Associates
+ recommends setting it to null. M routines cannot modify $ZSTATUS with
+ the NEW command.
+
+ Example:
+
+
+ GTM> WRITE $ZSTATUS
+
+ 1212,+1^GTM$DMOD,%SYSTEM-F-FLTDIV_F,
+ arithmetic fault, floating
+
+ divide by zero at PC=00080C01, PSL=03C00000
+
+ This example displays the status generated by a divide by zero (0).
+
+2 $ZSTep
+ $ZSTep
+
+ $ZST[EP] contains a string value specifying the default action for the
+ ZSTEP command. $ZSTEP provides the ZSTEP action only when the ZSTEP
+ command does not specify an action.
+
+ $ZSTEP initially contains the string "B" to enter direct mode. $ZSTEP
+ is a read-write Intrinsic Special Variable, (i.e., it can appear on the
+ left side of the equal sign (=) in the argument to the SET command).
+
+ Example:
+
+ GTM> WRITE $ZSTEP
+
+ B
+
+ GTM>
+
+ This example displays the current value of $ZSTEP, which is the
+ default.
+
+ Example:
+
+
+ GTM> SET $ZSTEP="ZP @$ZPOS B"
+
+ This example sets $ZSTEP to code that displays the contents of the next
+ line to execute, and then enters Direct Mode.
+
+2 $ZSYstem
+ $ZSYstem
+
+ $ZSY[STEM] holds the value of the status code for the last subprocess
+ invoked with the ZSYSTEM command.
+
+2 $ZTExit
+ $ZTExit
+
+ $ZTE[XIT] contains a string value that controls the GT.M interrupt
+ facility at the transaction commit or rollback. At each outermost
+ TCOMMIT or TROLLBACK, If +$ZTEXIT evaluates to non-zero (TRUE), then
+ $ZINTERRUPT is XECUTEd after completing the commit or rollback.
+
+ $ZTEXIT is a read-write ISV, that is, it can appear on the left side of
+ the equal sign (=) in the argument to the SET command. M routines
+ cannot NEW $ZTEXIT. GT.M initializes $ZTEXIT to null at the process
+ startup. Note that the changes to the value of $ZTEXIT during a GT.M
+ invocation last for the entire duration of the process, so it is the
+ application’s responsibility to reset $ZTEXIT after $ZINTERRUPT is
+ delivered in order to turn off redelivering the interrupt each every
+ subsequent transaction commit or rollback.
+
+ Example:
+
+ ztran.m
+
+ foo ;
+
+ set $zte=1
+
+ set $zint="d ^throwint"
+
+ tstart ()
+
+ for i=1:1:10 do
+
+ . set ^ACN(i,"bal")=i*100
+
+ tstart ()
+
+ do ^throwint
+
+ do ^proc
+
+ tcommit:$tlevel=2
+
+ for i=1:1:10 do
+
+ . set ^ACN(i,"int")=i*0.05
+
+ do ^srv
+
+ if $tlevel trollback
+
+ do ^exc
+
+ set $zte="",$zint=""
+
+ quit
+
+ bar ;
+
+ write "Begin Transaction",!
+
+ set $zte=1
+
+ tstart ()
+
+ i '$zsigproc($j,$ztrnlnm("sigusrval")) w "interrupt sent...",!!
+
+ for i=1:1:4 set ^B(i)=i*i
+
+ tcommit
+
+ write "End Transaction",!
+
+ do ^srv
+
+ quit
+
+
+ throwint.m
+
+ thrint
+
+ set $zint="write !,""interrupt occurred at :
+ "",$stack($stack-1,""PLACE""),! set $zte=1"
+ if '$zsigproc($j,$ztrnlnm("sigusrval")) write "interrupt sent to
+ process"
+ write "***************************************",!!
+
+ quit
+
+ Example:
+
+
+ GTM>d foo^ztran
+
+ interrupt sent to process
+
+ interrupt occurred at : thrint+3^throwint
+
+***************************************
+
+
+ interrupt occurred at : foo+13^ztran
+
+
+ GTM>
+
+ In the above call to foo^ztran, the interrupt handler is a user-defined
+ routine, throwint. The process is sent a signal (SIGUSR1), and
+ $ZINTERRUPT is executed. At the outermost trollback, the interrupt is
+ rethrown, causing $ZINTERRUPT to be executed again.
+
+ Example:
+
+
+ GTM>w $zint
+
+ IF $ZJOBEXAM()
+
+ GTM>f s x=$zsearch("GTM_JOBEXAM.*") q:x="" w !,x
+
+
+ GTM>d bar^ztran
+
+ Begin Transaction
+
+ interrupt sent...
+
+
+ End Transaction
+
+
+ GTM>f s x=$zsearch("GTM_JOBEXAM.*") q:x="" w !,x
+
+
+ DISK$TESTAREA3:[V967.ZTE]GTM_JOBEXAM.ZSHOW_DMP_541068433_1;1
+
+ DISK$TESTAREA3:[V967.ZTE]GTM_JOBEXAM.ZSHOW_DMP_541068433_2;1
+
+
+ GTM>
+
+
+ This uses the default value of $ZINTERRUPT to service interrupts issued
+ to the process. The $ZJOBEXAM function executes a ZSHOW "*", and stores
+ the output in each GTM_ZJOBEXAM_ZSHOW_DMP for the initial interrupt,
+ and at tcommit when the interrupt is rethrown.
+
+2 $ZTrap
+ $ZTrap
+
+ $ZT[RAP] contains a string value that GT.M XECUTEs when an error occurs
+ during routine execution.
+
+ The following discussion assumes that $ETRAP error handling is
+ simultaneously not in effect (that is, $ETRAP="").
+
+ When the $ZTRAP variable is not null, GT.M executes $ZTRAP at the
+ current level. The $ZTRAP variable has the initial value of "B," and
+ puts the process in Direct Mode when an error condition occurs. If the
+ value of $ZTRAP is null (""), an exception causes the image to run-down
+ with the condition code associated with the exception. If $ZTRAP
+ contains invalid source code, GT.M displays an error message and puts
+ the process into Direct Mode.
+
+ $ZTRAP is a read-write Intrinsic Special Variable, (i.e., it can appear
+ on the left side of the equal sign (=) in the argument to the SET
+ command).
+
+ $ZTRAP may also appear as an argument to an inclusive NEW command. NEW
+ $ZTRAP causes GT.M to set $ZTRAP to null ($ZTRAP="") and to stack the
+ old value of $ZTRAP. When the program QUITs from the invocation level
+ where the NEW occurred, GT.M restores the value previously stacked by
+ the NEW. NEW $ZTRAP provides nesting of $ZTRAP. Because $ZTRAP=""
+ terminates the image when an error occurs, SET $ZTRAP= generally
+ follows immediately after NEW $ZTRAP. You may use this technique to
+ construct error handling strategies corresponding to the nesting of
+ your programs. If the logical name gtm_ztrap_new evaluates to boolean
+ TRUE (case insensitive string "TRUE", or case insensitive string "YES",
+ or a non-zero number), $ZTRAP is NEWed when $ZTRAP is SET; otherwise
+ $ZTRAP is not stacked when it is SET.
+
+ QUIT from a $ZTRAP terminates the level at which the $ZTRAP was
+ activated.
+
+ Keep $ZTRAP simple and put complicated logic in another routine. If the
+ action specified by $ZTRAP results in another run-time error before
+ changing the value of $ZTRAP, GT.M invokes $ZTRAP until it exhausts the
+ process stack space, terminating the image. Carefully debug exception
+ handling.
+
+ Example:
+
+
+ GTM> S $ZTRAP="ZP @$ZPOS B"
+
+ This example modifies $ZTRAP to display source code for the line where
+ GT.M encounters an error before entering Direct Mode.
+
+ There are four accepted behavioural forms of $ZTRAP controlled by the
+ VMS logical name gtm_ztrap_form. If gtm_ztrap_form is defined to "code"
+ (or not defined to one of the subsequently described values), then GT.M
+ treats $ZTRAP as code and handles it as previously described in the
+ documentation.
+
+ The four different behavioural forms of gtm_ztrap_form are:
+
+ o entryref - If gtm_ztrap_form evaluates to "entryref" then GT.M
+ treats it as an entryref argument to an implicit GOTO command.
+
+ o adaptive - If gtm_ztrap_form evaluates to "adaptive" then if
+ $ZTRAP does not compile to valid M code, then $ZTRAP is treated as
+ just described for "entryref." Since there is little ambiguity,
+ code and entryref forms of $ZTRAP can be intermixed in the same
+ application.
+
+ Note that GT.M attempts to compile $ZTRAP before evaluating $ZTRAP as
+ an entryref. Since GT.M allows commands without arguments such as QUIT,
+ ZGOTO, or HANG as valid labels, be careful not to use such keywords as
+ labels for error handling code in "adaptive" mode.
+
+ o pope[ntryref] / popa[daptive] - If gtm_ztrap_form evaluates to
+ "POPE[NTRYREF]" or "POPA[DAPTIVE]" (case insensitive) and $ZTRAP
+ value is in the form of entryref, GT.M unwinds the M stack from the
+ level at which an error occurred to (but not including) the level
+ at which $ZTRAP was last SET. Then, GT.M transfers control to the
+ entryref in $ZTRAP at the level where the $ZTRAP value was SET. If
+ the VMS logical name gtm_zyerror is defined to a valid entryref,
+ GT.M transfers control to the entryref specified by GTM_ZYERROR
+ (with an implicit DO) after unwinding the stack and before
+ transferring control to the entyref specified in $ZTRAP.
+
+2 $ZVersion
+ $ZVersion
+
+ $ZV[ERSION] contains a string value specifying the currently installed
+ GT.M. $ZV[ERSION] is a space-delimited string with four pieces
+ described below:
+
+ o The M product name, for example "GT.M".
+
+ o The M product version identifier; the format is: the capital letter
+ "V" followed by the major version number, then a period (.),
+ followed by the minor version number, then a patch number.
+
+ o The host operating system name and optional version identifier;
+ this identifier is only included if different versions of the OS
+ support different, compatible versions of the M product.
+
+ o The host hardware designation and optional chipset identifier; this
+ identifier is only included if different versions of the hardware
+ support different compatible versions of the M product.
+
+ M routines cannot modify $ZVERSION.
+
+ Example:
+
+
+ GTM> WRITE $ZVERSION
+
+ GT.M V4.3-001B VMS AXP
+
+ This example displays the current version identifier for GT.M.
+
+2 $ZYERror
+ $ZYERror
+
+ $ZYER[ROR] is a read/write ISV that contains a string value pointing to
+ an entryref. After GT.M encounters an error, if $ZYERROR is set a
+ non-null value, GT.M invokes the routine at the entryref specified by
+ $ZYERROR with an implicit DO. It is intended that the code invoked by
+ $ZYERROR use the value of $ZSTATUS to select or construct a value to
+ which it SETs $ZERROR. If $ZYERROR is not a valid entryref or if an
+ error occurs while executing the entryref specified by $ZYERROR, GT.M
+ SETs $ZERROR to the error status encountered. GT.M then returns control
+ to the M code specified by $ETRAP/$ZTRAP or device EXCEPTION.
+
+ $ZYERROR is implicitly NEWed on entry to the routine specified by
+ $ZYERROR. However, if GT.M fails to compile, GT.M does not transfer
+ control to the entryref specified by $ZYERROR.
+
+ GT.M permits $ZYERROR to be modified by the SET and NEW commands.
+
+1 In_Out_Processing
+ Input Output Processing
+
+ OPEN, USE, and CLOSE commands accept deviceparameters, which are
+ keywords that permit an GT.M process to control the device state. Some
+ deviceparameters accept arguments, and some require them. The current
+ ANSI standard for GT.M does not define the deviceparameters for all
+ devices.
+
+2 IO_ISV
+ I/O Intrinsic Special Variables
+
+ GT.M intrinsic special variables provide a means of communication
+ between a device and its device driver and GT.M routines. These
+ variables allow a GT.M routine to manage the I/O with a particular
+ device.
+
+3 Device_Nam_Var
+ Device Name Variables
+
+ GT.M provides three intrinsic special variables that identify devices.
+
+4 $IO
+ $IO
+
+ $I[O] contains the name of the current device specified by the last USE
+ command. The M standard does not permit a SET command to modify $IO.
+ USE produces the same $IO as USE $PRINCIPAL, but $P is the preferred
+ construct.
+
+4 $Principal
+ $Principal
+
+ $P[RINCIPAL] contains the name of the principal (initial $IO) device.
+ GT.M establishes $PRINCIPAL as a fully expanded VMS device
+ specification.
+
+ Input and output for a process may come from separate devices. VMS
+ designates these devices with the process-permanent logical names
+ SYS$INPUT and SYS$OUTPUT. However, the GT.M I/O model allows only one
+ device to be USEd (or active) at a time. When an image starts, GT.M
+ implicitly OPENs the devices identified by SYS$INPUT and SYS$OUTPUT and
+ assigns the device(s) to $PRINCIPAL. For USE deviceparameters, it is
+ the standard input that determines the device type.
+
+ For an image invoked interactively, $PRINCIPAL is the user's terminal.
+ For a batch job, $PRINCIPAL is the command file for input and the log
+ file for output. For an image invoked from a terminal by means of a
+ command file, $PRINCIPAL is the command file for input and the terminal
+ for output, unless the command file redefines the logical names
+ SYS$INPUT and/or SYS$OUTPUT. Generally an interactive command file
+ contains the following command immediately before it starts a GT.M
+ image.
+
+ Example:
+
+ $ DEFINE SYS$INPUT 'F$TRNLNM("SYS$COMMAND")'
+
+ This redirects the input for the process to come from the terminal.
+ GT.M ignores a CLOSE command specifying the principal device.
+
+ GT.M does not permit a SET command to modify $PRINCIPAL.
+
+4 $ZIO
+ $ZIO
+
+ $ZIO contains the translated name of the current device, in contrast to
+ $IO, which contains the name as specified by the USE command.
+
+3 Cur_Position_Var
+ Cursor Position Variables
+
+ GT.M provides two intrinsic special variables for determining the
+ virtual cursor position. $X refers to the current column, while $Y
+ refers to the current row.
+
+4 $X
+ $X
+
+ $X contains an integer value ranging from 0 to 65,535, specifying the
+ horizontal position of a virtual cursor in the current output record.
+ $X=0 represents the left-most position of a record or row.
+
+ Every OPENed device has a $X. However, GT.M only has access to $X of
+ the current device. Therefore, be careful when sequencing USE commands
+ and references to $X.
+
+ Generally, GT.M increments $X for every character written to and read
+ from the current device. GT.M format control characters, FILTER, and
+ the device WIDTH and WRAP also have an effect on $X.
+
+ SET $X does not automatically issue device commands or escape sequences
+ to reposition the physical cursor.
+
+4 $Y
+ $Y
+
+ $Y contains an integer value ranging from 0 to 65,535, specifying the
+ vertical position of a virtual cursor in the current output record.
+ $Y=0 represents the top row or line.
+
+ Every OPEN device has a $Y. However, GT.M only accesses $Y of the
+ current device. Therefore, be careful when sequencing USE commands and
+ references to $Y.
+
+ When GT.M finishes the logical record in progress, it generally
+ increments $Y. GT.M recognizes the end of a logical record when it
+ processes certain GT.M format control characters, or when the record
+ reaches its maximum size, as determined by the device WIDTH, and the
+ device is set to WRAP. The definition of "logical record" varies from
+ device to device. For an exact definition, see the sections on each
+ device type. FILTER and the device LENGTH also have an effect on $Y.
+
+ SET $Y does not automatically issue device commands or escape sequences
+ to reposition the physical cursor.
+
+4 Maint_of_$X_and_&Y
+ Maintenance of $X and $Y
+
+ In GT.M, the following factors affect the maintenance of the virtual
+ cursor position ($X and $Y):
+
+ o The bounds of the virtual "page"
+
+ o GT.M format control characters
+
+ o GT.M character filtering
+
+ Each device has a WIDTH and a LENGTH that define the virtual "page."
+ The WIDTH determines the maximum size of a record for a device, while
+ the LENGTH determines how many records fit on a page. GT.M starts a new
+ record when the current record size ($X) reaches the maximum WIDTH and
+ the device has WRAP enabled. When the current line ($Y) reaches the
+ maximum LENGTH, GT.M starts a new page.
+
+ GT.M has several format control characters that allow the manipulation
+ of the virtual cursor. For all I/O devices, the GT.M format control
+ characters do the following:
+
+ ! Sets $X to zero (0) and increments $Y, and terminates the logical
+ record in progress. The definition of "logical record" varies from
+ device to device, and is discussed in each device section.
+ # Sets $X and $Y to zero (0), and terminates the logical record in
+ progress.
+ ?n If n is greater than $X, writes n-$X spaces to the device,
+ bringing $X to n. If n is less than or equal to $X, ?n has no
+ effect. When WRAP is enabled and n exceeds the WIDTH of the line,
+ WRITE ?n increments $Y and sets $X equal to n#WIDTH, where # is the
+ GT.M modulo operator.
+ GT.M provides two modes of character filtering. When filtering is
+ enabled, certain <CTRL> characters and/or escape sequences have special
+ effects on the cursor position (e.g., <BS> (ASCII 8) may decrement $X,
+ if $X is non-zero). For more information on write filtering, refer to
+ the section on the [NO]FILTER deviceparameter.
+
+3 Status_Var
+ Status Variables
+
+ GT.M provides several I/O status variables that convey information
+ about the status of individual operations.
+
+4 $ZA
+ $ZA
+
+ $ZA contains a status determined by the last read on the device. The
+ value is a decimal integer with a meaning determined by the device as
+ follows:
+
+ For Terminal I/O:
+
+ 0 Indicating normal termination of a read operation
+ 1 Indicating a parity error
+ 2 Indicating the terminator sequence was malformed or too long
+ 3 Indicating hardware contention or failure
+ 4 Indicating a system configuration problem
+ 5 Indicating a process limit was exceeded or the process does not
+ have a required privilege
+ 9 Indicating a default for all other errors
+ For Sequential Disk Files I/O:
+
+ 0 Indicating normal termination of a read operation
+ 9 Indicating a failure of a read operation
+ For Mailbox I/O:
+
+ A decimal integer Indicating $JOB (VMS PID) of the process that
+ wrote the last message the current process read
+ For socket:
+
+ 0 Indicating normal termination or time out
+ 9 Indicating failure of a read operation
+ $ZA refers to the status of the current device. Therefore, exercise
+ care in sequencing USE commands and references to $ZA.
+
+4 $ZB
+ $ZB
+
+ $ZB contains a string specifying the input terminator for the last
+ terminal READ. $ZB is null, and it is not maintained for devices other
+ than terminals. $ZB may contain any legal input terminator, such as
+ <CR> (ASCII 13) or an escape sequence starting with <ESC> (ASCII 27),
+ from zero (0) to 15 bytes in length. $ZB is null for any READ
+ terminated by a timeout or any fixed-length READ terminated by input
+ reaching the maximum length.
+
+ $ZB contains the actual character string, not a sequence of numeric
+ ASCII codes.
+
+ Example:
+
+ SET zb=$ZB FOR i=1:1:$LENGTH(zb) WRITE !,i,?5,$A(zb,i)
+
+ This example displays the series of ASCII codes for the characters in
+ $ZB.
+
+ $ZB refers to the last READ terminator of the current device.
+ Therefore, be careful when sequencing USE commands and references to
+ $ZB.
+
+4 $ZEOF
+ $ZEOF
+
+ $ZEOF contains a truth-valued expression indicating whether the last
+ READ operation reached the end-of-file. $ZEOF is TRUE(1) at EOF and
+ FALSE (0) at other positions. GT.M does not maintain $ZEOF for terminal
+ devices.
+
+ $ZEOF refers to the end-of-file status of the current device.
+ Therefore, be careful when sequencing USE commands and references to
+ $ZEOF.
+
+2 IO_Devices
+ I/O Devices
+
+ Each device type supported by GT.M responds to a particular subset of
+ deviceparameters, while ignoring others. Devices may be programmed in a
+ device-specific manner, or in a device-independent manner.
+ Device-specific I/O routines are intended for use with only one type of
+ device. Device-independent I/O routines contain appropriate
+ deviceparameters for all devices to be supported by the function, so
+ the user can redirect to a different device output while using the same
+ program.
+
+ GT.M supports the following I/O device types:
+
+ o Terminals and Printers
+
+ o Sequential Disk RMS Files
+
+ o VMS Mailboxes
+
+ o Null Devices
+
+ o Socket Devices
+
+3 IO_Devi_Recog
+ I/O Device Recognition
+
+ GT.M OPEN, USE, and CLOSE commands have an argument expression
+ specifying a device name. In the OpenVMS environment, a device may be
+ referred to either by its physical name or by a logical name to which
+ its physical name has been assigned. Because logical names permit
+ program coding independent of hardware configuration, logical names are
+ more common than physical names.
+
+ During an OPEN, GT.M attempts to resolve the specified device names to
+ physical names. When GT.M successfully resolves a device name to a
+ physical device, that device becomes the target of the OPEN. When the
+ device name does not resolve to a physical device, GT.M attempts
+ logical name translation; the result becomes the name of an RMS
+ sequential disk file. The TMPMBX and PRMMBX deviceparameters on an OPEN
+ command override the default mechanism, and specify that the device is
+ a VMS mailbox.
+
+ Once a device is OPEN, GT.M establishes an internal correspondence
+ between a name and the device or file. Therefore, while the device is
+ OPEN, changing the translation of a logical name in the device
+ specification does not change the device.
+
+ The following names identify the original $IO for the process:
+
+ o $PRINCIPAL
+
+ 0
+
+ o "SYS$INPUT"
+
+ o "SYS$OUTPUT"
+
+ Some versions of GT.M also treat the empty string as identifying $P.
+ However, Sanchez recommends using the empty string to identify a null
+ device, so it would be wise to avoid or eliminate this behavior.
+
+3 Devi_Spec_Defaults
+ Device Specification Defaults
+
+ GT.M uses standard OpenVMS file-specifications for device specifiers.
+
+ The complete format for a file-specification is:
+
+ node::device:[directory]file.filetype;version
+
+ If the expression specifying a device does not contain a complete
+ file-specification, the expression may start with a logical name that
+ translates to one or more leading components of the file-specification.
+ GT.M applies default values for the missing components.
+
+ The GT.M file-specification defaults are the following:
+
+ Node Current user node
+ Device Current default OpenVMS device
+ Directory Current default OpenVMS directory
+ Filetype .DAT for the file extension
+ Version Latest version number
+3 How_IO_DeviParam_Work
+ How I/O Deviceparameters Work
+
+ I/O deviceparameters either perform actions that cause the device to do
+ something (for example, CLEARSCREEN), or specify characteristics that
+ modify the way the device subsequently behaves (for example,
+ RECORDSIZE, ALLOCATION). When an I/O command has multiple action
+ deviceparameters, GT.M performs the actions in the order of the
+ deviceparameters within the command argument. When a command has
+ characteristic deviceparameters, the last occurrence of a repeated or
+ conflicting deviceparameter determines the characteristic.
+
+ Deviceparameters often relate to a specific device type. GT.M ignores
+ any deviceparameters that do not apply to the type of the device
+ specified by the command argument. Specified device characteristics are
+ in force for the duration of the GT.M image, or until modified by an
+ OPEN, USE, or CLOSE command.
+
+ When reopening a device that it previously closed, a GT.M process
+ restores all characteristics not specified on the OPEN to the values
+ the device had when it was last CLOSEd. GT.M treats sequential disk
+ files differently and uses defaults for unspecified sequential disk
+ file characteristics on every OPEN (that is, GT.M does not retain
+ sequential disk file characteristics on a CLOSE).
+
+ The ZSHOW command with an argument of "D" displays the current
+ characteristics for all devices OPENed by the process. ZSHOW can direct
+ its output into a GT.M variable.
+
+3 Abbv_DeviParam
+ Abbreviating Deviceparameters
+
+ GT.M deviceparameters do not have predefined abbreviations. GT.M
+ recognizes deviceparameters using a minimum recognizable prefix
+ technique. Most deviceparameters can be represented by four leading
+ characters, except ERASELINE, READSYNC, all deviceparameters starting
+ with WRITE, and Z* deviceparameters in a mnemonicspace (such as
+ SOCKET). The four leading characters recognized do not include a
+ leading NO for negation.
+
+ For compatibility with previous versions, GT.M may recognize certain
+ deviceparameters by abbreviations shorter than the minimum. While it is
+ convenient in Direct Mode to use shorter abbreviations, Sanchez
+ Computer Associates may add additional deviceparameters, and therefore,
+ recommends all programs use at least four characters. Because GT.M
+ compiles the code, spelling out deviceparameters completely has no
+ performance penalty, except when used with indirection or XECUTEd
+ arguments.
+
+
+3 Devi_Independent_Prog
+ Device-Independent Programming
+
+ When a user may choose a device for I/O, GT.M routines can take one of
+ two basic programming approaches.
+
+ o The user selection directs the program into different code
+ branches, each of which handles a different device type.
+
+ o The user selection identifies the device. There is a single code
+ path written with a full complement of deviceparameters to handle
+ all selectable device types.
+
+ The latter approach is called device-independent programming. To permit
+ device independent programming, GT.M uses the same deviceparameter for
+ all devices that have an equivalent facility, and ignores
+ deviceparameters applied to a device that does not support that
+ facility.
+
+ Example:
+
+ OPEN dev:(EXCE=exc:REWIND:VARIABLE:NEWVERSION:WRITEONLY)
+
+ This OPENs a device with deviceparameters that affect different
+ devices. Only the EXCEPTION has an effect for all device types. When
+ dev is a terminal or a null device, GT.M ignores the other
+ deviceparameters. When dev is an RMS file on disk, GT.M uses REWIND,
+ VARIABLE, and NEWVERSION. When dev is a mailbox, GT.M only uses
+ WRITEONLY. This command performs a valid OPEN for all the different
+ device types.
+
+ A file that has been previously created and contains data that
+ should be retained can also be opened with the device parameter
+ APPEND.
+
+2 Terminals
+ Using Terminals
+
+ A typical GT.M application is largely interactive and uses terminals
+ extensively. By default, a GT.M process directs its terminal I/O to
+ $PRINCIPAL. $PRINCIPAL identifies the terminal that the user signed
+ onto in VMS.
+
+ While all terminals support the CTRAP deviceparameter, which optionally
+ allows terminal input to optionally redirect program flow, only
+ $PRINCIPAL supports CENABLE, which optionally allows the terminal user
+ to invoke the Direct Mode shell.
+
+ Directly connected printers often appear to GT.M as a terminal
+ (although printers generally do not provide input) regardless of
+ whether the printer is connected to the Open VMS with a high speed
+ parallel interface, or an asynchronous terminal controller.
+
+3 Set_Terminal_Char
+ Setting Terminal Characteristics
+
+ GT.M does not isolate its handling of terminal characteristics from the
+ VMS environment at large. GT.M inherits the VMS terminal
+ characteristics in effect at the time the GT.M image is invoked.
+ Therefore, DCL SET TERMINAL commands that precede invocation of a GT.M
+ image affect the way the terminal behaves initially. For more
+ information on setting terminal characteristics, refer to the SET
+ TERMINAL command in the OpenVMS DCL Dictionary.
+
+ However, if the process temporarily leaves the GT.M environment with a
+ ZSYSTEM command or a $ZCALL() function, GT.M does not recognize any
+ changes to the terminal characteristics left by the external
+ environment. This may cause disparities between the physical behavior
+ of the terminal, and the perceived behavior by GT.M.
+
+ VMS enforces standard device security for explicit OPENs of terminals
+ other than the sign-in terminal (SYS$COMMAND). If you are unable to
+ OPEN a terminal, contact your system manager.
+
+ Most terminal characteristics respond to deviceparameters on the USE
+ command. Many $PRINCIPAL terminal characteristics modified by
+ deviceparameters in GT.M persist after the GT.M image terminates.
+
+ USE of a terminal causes the device driver to flush the output buffer.
+ This feature of the USE command provides routine control over the
+ timing of output, which is occasionally required. However, it also
+ means that redundant USE commands may induce an unnecessary performance
+ penalty. Therefore, Sanchez Computer Associates recommends restricting
+ USE commands to redirecting I/O, modifying deviceparameters, and
+ initiating specifically required flushes.
+
+3 Logical_Rec_for_Term
+ Logical Records for Terminals
+
+ A logical record for a terminal equates to a line on the physical
+ screen. The WIDTH device characteristic specifies the width of the
+ screen, while the LENGTH device characteristic specifies the number of
+ lines on the screen.
+
+3 Terminating_Term_READ
+ Terminating a Terminal READ
+
+ To terminate a READ command for terminals with anything other than a
+ carriage return (<CR>) or an escape (<ESC>), use the TERMINATOR
+ deviceparameter with the USE command. By default, terminals recognize
+ the terminators <CR> (ASCII 13) and <ESC> (ASCII 27).
+
+ A successful READ operation sets $ZB to the input terminator or
+ terminating escape sequence. For example, if a READ terminates with a
+ <CR>, $ZB equals $C(13). If the READ times out or the input exceeds the
+ maximum length, the terminal device driver sets $ZB to null.
+
+3 READ_Comm_for_Term
+ READ* Command for Terminals
+
+ If the terminal has ESCAPE sequencing enabled, and the input contains a
+ valid escape sequence or a terminator character, the terminal device
+ driver stores the entire sequence in $ZB and returns the ASCII
+ representation of the first character.
+
+ Example:
+
+ GTM> KILL
+
+ GTM> USE $P:ESCAPE
+
+ GTM> READ *X SET ZB=$ZB ZWRITE
+
+ (Press the F11 key on the VT220 terminal keyboard)
+ x=27
+
+ zb=$C(27)_"[23~"
+
+ This enters an escape sequence in response to a READ *. The READ *
+ assigns the code for <ESC> to the variable X. The terminal handler
+ places the entire escape sequence in $ZB. Because some of the
+ characters are not graphic, that is, visible on a terminal, the example
+ transfers the contents of $ZB to the local variable ZB and uses a
+ ZWRITE so that the non-graphic characters appear in $CHAR() format.
+
+ The READ * command for terminals does not affect $ZB when escape
+ sequencing is not enabled. If the input contains a valid escape
+ sequence and escape sequencing is not enabled, the variable for the
+ READ * command returns the first character of the escape sequence, for
+ example, ASCII 27. The terminal device driver stores the remaining
+ characters of the escape sequence in the read buffer. A READ command
+ following a READ * command returns the remaining characters of the
+ escape sequence. An application that operates with NOESCAPE must
+ provide successive READ * commands to remove the remaining escape
+ characters from the buffer.
+
+ Example:
+
+ GTM> KILL
+
+ GTM> USE $P:(NOESCAPE:TERM=$C(13))
+
+ GTM> READ *X SET ZB=$ZB READ Y:0 ZWRITE
+
+ (Press the F11 key on the terminal keyboard)
+ [23~i=5
+ x=27
+
+ y="[23~"
+
+ zb=""
+
+ GTM> USE $P:NOECHO READ *X S ZB=$ZB READ Y:0 USE $P:ECHO ZW
+
+ i=5
+
+ x=27
+
+ y="[23~"
+
+ zb=""
+
+ GTM> READ *X SET ZB=$ZB USE $P:FLUSH READ Y:0 ZWRITE
+
+ i=5
+
+ x=27
+
+ y=""
+
+ zb=""
+
+ While the first READ Y:0 picks up the sequence after the first
+ character, notice how the graphic portion of the sequence appears on
+ the terminal - this is because the READ *X separated the escape
+ character from the rest of the sequence thus preventing the VMS
+ terminal driver logic from recognizing it as a sequence, and
+ suppressing its echo. The explicit suppression of echo removes this
+ visual artifact. In the case of the final READ *X, the FLUSH clears the
+ input buffer so that it is empty by the time of the READ Y:0.
+
+3 READmaxlen_Comm_for_Term
+ READ X#maxlen Command for Terminals
+
+ Generally, GT.M performs the same maintenance on $ZB for a READ
+ X#maxlen as for a READ. However, if the READ X#maxlen terminates
+ because the input has reached the maximum length, GT.M sets $ZB to
+ null. When the terminal has ESCAPE sequencing enabled, and the input
+ contains an escape sequence that does not fit in the read buffer, GT.M
+ sets $ZB to contain the escape sequence.
+
+3 Term_Examples
+ Terminal Examples
+
+ This section contains examples of GT.M terminal handling.
+
+ Example:
+
+ USE $PIECE:(ctrap=$c(3):exception="zg "_$zl_":C^MENU")
+
+ This example USEs the principal device, and sets up an EXCEPTION
+ handler. If the device is a terminal, the USE also sets up a trap for
+ <CTRL-C>. When an EXCEPTION occurs, it transfers control to label C in
+ the routine ^MENU at the process stack level where the EXCEPTION was
+ established.
+
+ Example:
+
+ USE $PIECE:(X=0:Y=0:CLEARSCREEN)
+
+ This example positions the cursor to the upper left-hand corner and
+ clears the entire screen.
+
+ Example:
+
+ USE $PIECE:(NOECHO:WIDTH=132:WRAP)
+
+ This example disables ECHOing, enables automatic WRAPping, and sets the
+ line width to 132 characters.
+
+ Example:
+
+ USE $PIECE:NOCENABLE
+
+ This example disables <CTRL-C>.
+
+ Example:
+
+ USE $PIECE:(PASTHRU:ESCAPE) R *X U $P:(NOPASTHRU)
+
+ WRITE !,X,?5 I $L($ZB) W $A($ZB) F i=2:1:$L($ZB) W ",",$A
+
+ ($ZB,i)
+ This USEs the principal device and, if it is a terminal, turns on
+ PASTHRU and ESCAPE sequence processing. The READ *X places an ASCII
+ code in X corresponding to the character read. The second USE turns off
+ PASTHRU. The second line displays the resulting value for X and the
+ ASCII codes in $ZB. $ZB holds the terminator, if any. This routine
+ examines the input from all keys and key combinations on the keyboard
+ except <CTRL-Q> and <CTRL-S>.
+
+2 Sequential_Files
+ Using Sequential (RMS) Files
+
+ GT.M provides access to sequential files both on disk. These files use
+ the Files-11 RMS format, which allows linear access to records.
+ Sequential files are used to create programs, store reports, and to
+ communicate with facilities outside of GT.M.
+
+3 Setting_Seq_File_Charc
+ Setting Sequential File Characteristics
+
+ The ANSI standard specifies that when a process CLOSEs and then reOPENs
+ a device, GT.M restores any characteristics not explicitly specified
+ with deviceparameters to the values they had prior to the last CLOSE.
+ However, because it is difficult for a large menu-driven application to
+ ensure the previous OPEN state, GT.M always sets unspecified sequential
+ file characteristics to their default value on OPEN. This approach also
+ reduces potential memory overhead imposed by OPENing and CLOSEing a
+ large number of sequential files during the life of a process.
+
+ GT.M does not restrict multiple OPEN commands. However, if a file is
+ already open, GT.M ignores attempts to modify sequential file OPEN
+ characteristics, except for RECORDSIZE and for deviceparameters that
+ also exist for USE.
+
+ Sequential files can be READONLY, or read/write (NOREADONLY). Disk
+ files can also be SHARED or exclusive. A file OPENed SHARED can
+ accommodate a theoretically unlimited number of readers and a single
+ writer. OPENing a file SHARED complicates access to the file, and
+ therefore significantly reduces the performance of I/O to that file.
+
+ Sequential files can be composed of either FIXED or VARIABLE (NOFIXED)
+ length records. By default, records have VARIABLE length. A BLOCKSIZE
+ for VARIABLE length records must specify at least four bytes more than
+ the maximum record length. In order to use FIXED length records, the
+ command must explicitly include the FIXED deviceparameter. Changing the
+ RECORDSIZE for FIXED length record files produces subsequent errors on
+ READ or WRITE.
+
+ VMS enforces its standard security when GT.M OPENs a Files-11 RMS file.
+ This includes any directory access required to locate or create the
+ file. If you are unable to OPEN a file, contact your system manager.
+
+3 Logi_Rec_for_SeqFiles
+ Logical Records for Sequential Files
+
+ GT.M views a record in a sequential file in the same way as the
+ operating system does. The RECORDSIZE deviceparameter sets the maximum
+ size of the record, while the FIXED and VARIABLE deviceparameters
+ specify the format of the record in the file.
+
+3 SeqFile_Pointers
+ Sequential File Pointers
+
+ Sequential file (RMS) I/O operations use a construct called a file
+ pointer. The file pointer logically identifies the next record to read
+ or write. OPEN commands position the file pointer at the beginning of
+ the file (REWIND) or at the end-of-file (APPEND). APPEND cannot
+ reposition a file currently open. Because the position of each record
+ depends on the previous record, a WRITE destroys the ability to
+ reliably position the file pointer to subsequent records in a file.
+ Therefore, by default (NOTRUNCATE), GT.M permits WRITEs only when the
+ file pointer is positioned at the end of the file.
+
+ If a device has TRUNCATE enabled, a WRITE issued when the file pointer
+ is not at the end of the file causes all contents after the current
+ file pointer to be discarded. This effectively moves the end of the
+ file to the current position and permits the WRITE.
+
+3 SPOOL_SUBMIT_for_SeqFile
+ SPOOL or SUBMIT for Sequential Files
+
+ CLOSE may send sequential files to the VMS queue manager for
+ processing. The CLOSE command provides deviceparameters that SPOOL the
+ file for printing on a printer or terminal, or SUBMIT the file to batch
+ for execution. Many of the CLOSE deviceparameters for sequential files
+ control queue behavior for either SPOOL or SUBMIT or both, and
+ therefore must be used with SPOOL and/or SUBMIT to have any effect.
+
+3 SeqFile_Examples
+ Sequential File Examples
+
+ This section contains a few brief examples of GT.M sequential file
+ handling.
+
+ Example:
+
+ READ "File > ",sd
+
+ OPEN sd:(readonly:exception="G BADOPEN")
+
+ USE sd:exception="G EOF"
+
+ FOR USE sd READ x USE $PRINCIPAL WRITE x,!
+
+ EOf IF '$ZEOF ZM +$ZS
+
+ CLOSE sd
+
+ QUIT
+
+ BADOPEN IF $ZS["-FNF," DO QUIT
+
+ . WRITE !,"The file ",sd," does not exist."
+
+ IF $ZS["-PRV," DO QUIT
+
+ . WRITE !,"The file ",sd," is not accessible."
+
+ ZM +$ZS
+
+ QUIT
+
+ This example OPENs a file READONLY and specifies an EXCEPTION. The
+ exception handler for the OPEN deals with file-not-found and
+ file-access errors, and reissues all other errors with the ZMESSAGE
+ command. The first USE sets the EXCEPTION to handle end-of-file. The
+ FOR loop reads the file one record at a time and transfers each record
+ to the principal device. The GOTO in the EXCEPTION terminates the FOR
+ loop. At label EOF, if $ZEOF is false, the code reissues the error that
+ triggered the exception. Otherwise, the CLOSE releases the file.
+
+ Example:
+
+ SET sd="temp.dat",acct=""
+
+ OPEN sd:newversion U sd:width=132
+
+ FOR SET acct=$O(^ACCT(acct)) QUIT:acct="" DO
+
+ . SET rec=$$FORMAT(acct)
+
+ . WRITE:$Y>55 #,hdr W !,rec
+
+ CLOSE sd:(spool:delete)
+
+ This OPENs a NEWVERSION of file TEMP.DAT. The USE sets the line width
+ to 132 characters. The FOR loop cycles through the ^ACCT global
+ formatting (not shown in this code fragment) lines and writing them to
+ the file. The FOR loop uses the argumentless DO construct to break a
+ long line of code for greater readability. The program writes a header
+ record (set up in initialization not, shown in this code fragment)
+ every 55 lines, because that is the application page length, allowing
+ for top and bottom margins. Finally the CLOSE releases the file to the
+ VMS spooler for printing on the default print queue SYS$PRINT and also
+ for deletion when the printing finishes.
+
+2 Mailboxes
+ Using Mailboxes
+
+ A mailbox is a VMS facility that uses shared system memory to pass
+ messages from one process to another. Because they use shared memory,
+ mailboxes can only be used for communication between process on the
+ same computer. They cannot be used to pass messages between machines in
+ a VMSCluster. A GT.M image can use mailboxes to communicate with any
+ process on the same system, including non-GT.M processes. Mailbox
+ device names have the format MBA<number>:. VMS creates mailboxes with
+ associated logical names, which translates to the device name. When
+ GT.M creates a mailbox, it uses the device name argument of the OPEN
+ command and creates a logical name that translates to the mailbox
+ specification. Because of VMS conventions, logical names for mailboxes
+ are not case sensitive and cannot have a leading undescore(_).
+
+ If the OPEN specifies a device name in the form MBA<number>:, and
+ the mailbox does not exist, OPEN creates a new mailbox and uses the
+ OPEN argument to create a logical name translating to the new
+ mailbox.
+
+ VMS provides permanent and temporary mailboxes, requiring respectively
+ the PRMMBX and TMPMBX priviliges for creation. Because, by default,
+ permanent mailbox names are translated in the SYSTEM logical name
+ table, their creation also nornamlly requires the SYSNAM privilege. To
+ allow the possibility of using temporary mailboxes for inter-job
+ communication, GT.M uses the GROUP logical name table to translate
+ temporary mailbox names, and so requires the GRPNAM privilege to create
+ temporary mailboxes.
+
+ Accessing an existing mailbox does not require any VMS privileges. The
+ system manager typically creates permanent mailboxes, usually at system
+ startup. Therefore, permanent mailboxes serve to limit the number of
+ accounts requiring VMS privileges. The last process to CLOSE a
+ temporary mailbox deletes it. Using temporary mailboxes for short
+ infrequent communications tends to conserve system memory. Because VMS
+ uses temporary mailboxes primarily for communication between
+ subprocesses of a single job, VMS uses the JOB table as the VMS default
+ lofical name table for translating mailbox names.
+
+ GT.M ignores all deviceparameters on an OPEN command issued for an
+ already open mailbox.
+
+3 Logi_Rec_for_Mailb
+ Logical Records for Mailboxes
+
+ GT.M does not buffer mailbox output into logical records but instead
+ sends all characters directly to the mailbox. When a process attempts
+ to WRITE to a mailbox that does not have room to receive the message,
+ VMS places the process in a resource wait state. A process in a
+ resource wait state does not respond to <CTRL-C>. For such a process to
+ resume processing, another process must READ one or more messages from
+ the full mailbox.
+
+ Only GT.M format control characters manipulate the virtual cursor
+ position. Mailboxes do not recognize the WRAP deviceparameter, nor are
+ they subject to character filtering. WRITE increments $X for every
+ character sent to a mailbox. READ* and fixed length READs increments $X
+ for every character read from a mailbox. A normal READ sets $X to zero
+ and increments $Y.
+
+ GT.M format control characters send ASCII representations of the
+ function to the mailbox (for example W ! sends the ASCII characters
+ <CR> <LF> to the mailbox).
+
+3 Mailb_Examples
+ Mailbox Examples
+
+ This section contains a few brief examples of GT.M mailbox handling.
+
+ Example:
+
+ SET mb="FASTREPORT" O mb:PRMMBX u mb
+
+ FOR READ msg QUIT:msg="$STOP$" DO print(msg)
+
+ QUIT
+
+ This OPENs "FASTREPORT" as a permanent mailbox. "FASTREPORT" is the
+ logical name that translates to the mailbox specification. Generally
+ the system manager creates permanent mailboxes as part of system
+ start-up. If this is not the case, the process running our example
+ requires PRMMBX and SYSNAM privileges.
+
+ Example:
+
+ SET mb="SYNC" OPEN mb:(TMPMBX:WRITEONLY) USE mb:WAIT
+
+ SET x="" WRITE "$START$",$J
+
+ FOR SET x=$O(^tmp($J,x)) q:x="" WRITE ^(x)
+
+ WRITE "$END$"
+
+ CLOSE mb
+
+ This OPENs "SYNC" as a temporary mailbox for synchronous writes. If
+ "SYNC" does not exist as a temporary mailbox in the GROUP logical name
+ table of our process, GT.M creates a mailbox and places "SYNC" in the
+ GROUP table. Creating "SYNC" requires TMPMBX and GRPNAM privileges. The
+ process executing the example waits for another process to read each of
+ its writes. If no other process reads from the mailbox, the process
+ hangs indefinitely.
+
+2 NULL_Devices
+ Using NULL Devices
+
+ In VMS, null devices have the names "NL:", "_NL:", "NLA0:", and
+ "_NLA0:". A null device fulfills every input request by returning a
+ null string and setting $ZEOF. A null device discards all output. GT.M
+ maintains a virtual cursor position for null devices as it does for
+ terminals. Use null devices for program testing and debugging, or for
+ jobs that permit I/O to be discarded under certain circumstances. For
+ example, JOB processes must have input and output devices associated
+ with them, even though they do not use them. Null devices are low
+ overhead never-fail alternatives.
+
+3 Null_Dev_Ex
+ Null Device Examples
+
+ Example:
+
+ SET dev="nl:"
+
+ OPEN dev USE dev
+
+ SET x="" WRITE hdr,!,$ZDATE($h),?30,$J,!
+
+ FOR SET x=$O(^tmp($J,x)) q:x="" DO REPORT
+
+ CLOSE dev
+
+ This program produces a report derived from the information in the
+ global variable ^tmp. The unspecified routine REPORT may potentially
+ contain a large amount of code. To see that the basic program functions
+ without error, the programmer may wish to simply discard the output
+ involved in favor of watching the function. To run the program
+ normally, the programmer simply has to change the variable dev to name
+ another device.
+
+ Example:
+
+ JOB ^X:(INPUT="NL:":OUTPUT="NL:"ERROR="ERROR.LOG"
+
+ This issues an M JOB command to execute the routine ^X in another
+ process. This routine simply processes a large number of global
+ variables and produces no output. In the example, the JOBbed process
+ takes its INPUT from a null device (it shouldn't ask for any), and
+ sends its OUTPUT to a null device (it shouldn't produce any). If the
+ JOBbed process encounters an error, it directs the error message to
+ ERROR.LOG.
+
+2 Socket_Devices
+ Using Socket Devices
+
+ SOCKET devices are used to access and manipulate sockets. A SOCKET
+ device can have from zero (0) to 64 associated sockets. At any time,
+ only one socket from the collection can be the current socket. If there
+ is no current socket, an attempt to READ from, or WRITE to the device,
+ generates an error.
+
+ Sockets can be attached and detached from the collection of sockets
+ associated with a device. Detached sockets belong to a pseudo-device
+ called the "socketpool". A process can detach a socket from a device
+ and later attach it to the same device or another device.
+
+ The GT.M socket device interface does not have the ability to pass
+ sockets between related or unrelated processes. Currently error
+ trapping operates on a device, rather than on a socket.
+
+3 Msg_Mgmt
+ Message Management
+
+ From an application perspective, the transport layers used by a socket
+ device are stream-oriented media, with no provisions for implicit
+ application messages. Therefore, the following are two common protocols
+ used to segment application messages.
+
+ o One method is to use a, typically small, fixed length message
+ containing the length of the next, variable length, message. In
+ GT.M a simplistic writer might be:
+
+ Write $Justify($Length(x),4),x
+
+ A corresponding simplistic reader might be:
+
+ Read len#4,x#len
+
+ The advantage of this approach is that the message content (the value
+ of x in the code fragments above) can contain any character. The
+ disadvantage is that detecting that the protocol has become
+ desynchronized is a problem.
+ o The other common method is to place a delimiter between each
+ application message. The protocol breaks if a message ever includes
+ a delimiter as part of its content.
+
+ The SOCKET device has the capability to handle delimiters because
+ parsing messages for delimiters is cumbersome.
+
+3 Msg_Delimi
+ Message Delimiters
+
+ Each device can have from zero (0) to 64 delimiters associated with it.
+ Each delimiter can be from one (1) to 64 characters. All the delimiters
+ declared for a device are valid for any READ from any associated
+ socket, which means, any of the defined delimiters terminate the READ.
+ The actual terminating delimiter is available in $KEY. A WRITE to a
+ socket associated with a device with one or more delimiters inserts the
+ first of the delimiters for any WRITE ! format.
+
+3 Read_Comm
+ READ Command
+
+ The READ command may be used to obtain data from a socket. A
+ non-fixed-length read, with no timeout and no delimiters requires a
+ complex implementation of sequence of READs to ensure a predictable
+ result. This is because the transport layer stream fragments delivered
+ to the reader has only accidental correspondence with the operations
+ performed by the writer. For example, the following
+
+ Write "Message 1","Message 2"
+
+ is presented to the reader as the stream "Message1Message2" but it can
+ take from one (1) to 18 READ commands to retrieve the entire stream.
+
+3 Write_Comm
+ WRITE Command
+
+ The WRITE command sends data to a socket.
+
+ The WRITE command for SOCKET devices accepts following controlmnemonics
+ on a bound socket:
+
+
+ /L[ISTEN][(numexpr)]
+
+ Where numexpr is in the range 1-5 and specifies the listen queue depth.
+
+
+ /W[AIT][(timeout)]
+
+ Where timeout is a "numexpr" that specifies how long a server waits for
+ a connect before returning control to the GT.M routine.
+
+ "WRITE !" inserts the character(s) of the first I/O delimiter (if any)
+ to the sending buffer. If "ZFF=expr" has been used to define a
+ delimiter, "WRITE #" inserts the characters of that delimiter.
+ Otherwise WRITE # has no effect on the stream content. WRITE ! and
+ WRITE # always maintain $X and $Y in a fashion that emulates a terminal
+ cursor position.
+
+3 Socket_Devi_Ops
+ Socket Device Operation
+
+ Each socket may be in one of the following states:
+
+ o Created - indicates that the socket exists.
+
+ o Bound - indicates that the socket exists and is bound to a port; a
+ "Bound socket" needs a listen queue which currently requires a
+ WRITE /LISTEN [after a USE].
+
+ o Connected - indicates that the socket exists and has a connection.
+
+ A server socket used for accepting new connections goes through the
+ first two states in one step with a single OPEN or in two steps with an
+ OPEN and a USE. When a server does a WRITE /WAIT on a Bound socket, a
+ client can establish a connection which Creates another server socket
+ that is Connected. In server operation, $KEY supplies the port value
+ when a socket is bound (important when port 0 is specified to get the
+ system to choose the port), and a socket id when a Connected socket is
+ created. A client socket goes through the first and third states with a
+ single OPEN or in two steps with an OPEN and a USE.
+
+3 Socket_Devi_Ex
+ Socket Device Examples
+
+ This section contains examples on Socket Device usage.
+
+
+ ;server.m
+
+ Set portno=6321,delim=$c(13)
+
+ Set tcpdev="server$"_$j,timeout=30
+
+ Open tcpdev:(ZLISTEN=portno_":TCP":attach="server"):timeout:"SOCKET"
+
+ Use tcpdev
+
+ Write /listen(1)
+
+ Write /wait(timeout)
+
+ ;
+ ;dialogue with the client
+
+ ;
+ ;client.m
+
+ Set host="orlando"
+ Set portno=6321
+ Set delim=$c(13)
+ Set tcpdev="client$"_$j,timeout=30
+ O
+ tcpdev:(connect=host_":"_portno_":TCP":attach="client"):timeout:"SOCKET"
+ Use tcpdev
+ ;
+ ;dialogue with the server
+
+ ;
+2 IO_Comm
+ I/O Commands
+
+ This section describes the following GT.M I/O commands:
+
+ o OPEN establishes a connection from a GT.M process to a device.
+
+ o USE declares a device as the current source of input and
+ destination for output.
+
+ o READ accepts characters from the current device into a global or
+ local variable.
+
+ o WRITE sends characters to the current device.
+
+ o CLOSE breaks the connection between a GT.M process and a device.
+
+2 Open
+ Open
+
+ The OPEN command establishes a connection from a GT.M process to a
+ device.
+
+ The format of the OPEN command is:
+
+ O[PEN][:tvexpr] expr[:[(keyword[=expr][:...])][:numexpr][:expr]][,...]
+
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o The required expression specifies the device to OPEN.
+
+ o The optional keywords specify deviceparameters that control device
+ behavior; some deviceparameters take arguments delimited by an
+ equal sign (=); if the argument only contains one deviceparameter,
+ the surrounding parentheses are optional.
+
+ o The optional numeric expression specifies a time in seconds after
+ which the command should timeout if unsuccessful; 0 provides a
+ single attempt to open the device.
+
+ o When an OPEN command specifying a timeout contains no
+ deviceparameters, double colons (::) separate the timeout numeric
+ expression from the device expression.
+
+ o The optional expression specifies a mnemonicspace that selects a
+ device binding. The only mnemonicspace that GT.M currently accepts
+ is SOCKET.
+
+ o When an OPEN command specifies a mnemonicspace with no timeout,
+ double colons separate the mnemonicspace string expression from the
+ deviceparameters; if there are neither a timeout nor
+ deviceparameters, triple colons separate the mnemonicspace from the
+ device expression.
+
+ o An indirection operator and an expression atom evaluating to a list
+ of one or more OPEN arguments form a legal argument for an OPEN.
+
+ With the exception of mailboxes, spooled devices and SHARED sequential
+ disk files, VMS device access is exclusive. READONLY sequential disk
+ files may be shared among many readers, but no writers. Spooled devices
+ are devices, usually printers, which buffer output from multiple
+ sources, processing it after the writing process CLOSEs the file.
+ Spooled devices appear to GT.M as a terminal type device. For more
+ information on spooled devices, refer to the OpenVMS System Manager’s
+ Manual. When one process successfully OPENs a device exclusively, no
+ other process can access that device until the first process CLOSEs
+ that device.
+
+ By default, when a device is unavailable, GT.M retries the OPEN
+ indefinitely at approximately one second intervals. A device is
+ unavailable when another process is using it exclusively, or when the
+ OPENing process does not have the resources left to open the device.
+
+ All other errors on OPEN raise an error condition and interrupt program
+ flow. A timeout is a tool that lets a GT.M routine regain program
+ control when a device remains unavailable. When the OPEN specifies a
+ timeout, GT.M keeps retrying until either the OPEN succeeds or the
+ timeout expires.
+
+ If OPEN establishes a connection with a device before the timeout
+ expires, GT.M sets $TEST to TRUE (1). If the timeout expires, GT.M sets
+ $TEST to FALSE (0). If an OPEN command does not specify a timeout, the
+ execution of the command does not affect $TEST.
+
+ If a process has not previously OPENed a device within the context of
+ an image, any deviceparameters not supplied on the OPEN take their
+ default values. When reOPENing a device that it previously closed, a
+ GT.M process restores all characteristics not specified on the OPEN to
+ the values the device had when it was last CLOSEd, except with
+ sequential disk files. If you have a menu-driven application that OPENs
+ and CLOSEs devices based on user selections, take care that every OPEN
+ explicitly includes all deviceparameters important to the application.
+
+ GT.M treats sequential disk files differently and uses defaults for
+ unspecified sequential disk file characteristics on every OPEN (i.e.,
+ GT.M does not retain sequential disk file characteristics on a CLOSE).
+
+ VMS does not permit the alteration of certain characteristics once the
+ device or file has been OPENed. If a process OPENs an already OPEN
+ device, GT.M modifies any characteristics that accept changes when a
+ device is OPEN to reflect any new deviceparameter specifications.
+
+3 Ex_of_Open
+ Examples of OPEN
+
+ Example:
+
+ SET sd="report.dat" OPEN sd:NEWVERSION
+
+ This OPENs a NEWVERSION of a sequential disk file named "report.dat"
+ for both read and write access. The process has sole access to the
+ file.
+
+ SET mb="sync1" OPEN mb:(PRMMBX:WRITEONLY)
+
+ This OPENs a permanent mailbox restricted to writing.
+
+3 Open_DeviParam
+ OPEN Deviceparameters
+
+4 ALLOCATION
+ ALLOCATION=intexpr Applies to: Sequential Files
+
+ Specifies the initial size of the file in RMS 512 byte blocks.
+ ALLOCATION accepts an integer argument in the range of 0 to
+ 4,294,967,295. An argument of zero (0) does not allocate any space for
+ the file at file creation. When a WRITE requires space in a file that
+ is full, RMS extends the file by the amount specified in the EXTENSION
+ deviceparameter.
+
+ By default, new files have an ALLOCATION of zero (0).
+
+4 APPEND
+ APPEND Applies to: Sequential Files
+
+ Positions the file pointer at the end-of-file. This deviceparameter
+ only affects the device on the first OPEN command. Re-OPENing an
+ already OPEN device with this deviceparameter has no effect.
+
+ By default, OPEN sets the file pointer to the beginning-of-file.
+
+4 ATTACH
+ Attach=expr Applies to: Socket Device
+
+ When ATTACH is used and one of ZLISTEN and CONNECT is specified at the
+ same time, the value of expr becomes the identifier of the newly
+ created socket. If neither ZLISTEN nor CONNECT is specified, ATTACH is
+ ignored.
+
+4 BLOCKSIZE
+ BLOCKSIZE=intexpr Applies to: Terminals and Printers and VMS Mailboxes
+
+ Specifies the size in bytes of the maximum single read or write for the
+ specified device.
+
+4 CONNECT
+ CONNECT=expr Applies to: Socket Device
+
+ Enables a client connection with a server, which is located by the
+ information provided by expr. A new socket is allocated for the client
+ connection and is made the current socket for the device, if the
+ operation is successful.
+
+ expr specifies the protocol and protocol specific information.
+ Currently, TCP/IP is the only protocol GT.M supports. expr should be of
+ the format "<host>:<port>:TCP", where host is either an IP address or a
+ hostname like server.sanchez.com.
+
+ CONNECT is not compatible with ZLISTEN.
+
+4 CONTIGUOUS
+ CONTIGUOUS Applies to: Sequential Files
+
+ Specifies that RMS must allocate physically contiguous (adjacent) disk
+ space for a new file. If the disk cannot supply the required amount of
+ contiguous space, the OPEN fails.
+
+ By default, RMS the operating system uses a contiguous-best-try
+ algorithm. The algorithm uses contiguous space if available; otherwise,
+ it pieces the file together out of the largest available extents.
+
+4 DELIMITER
+ [NO]DELIMITER=expr Applies to: Socket Device
+
+ DELIMITER establishes or replaces the list of delimiters used by the
+ sockets associated with the device. The default for on a command that
+ first OPENs a device is NODELIMITER. The delimiter list on a
+ preexisting device remains the same until it is explicitly replaced or
+ deleted.
+
+ expr must be a string of the following format:
+
+ ':' is used to separate delimiters (it is the delimiter for
+ delimiters).
+
+ '/' serves as an escape character.
+
+ expr "ab:/:://:bc" is interpreted as four delimiters, which are "ab",
+ ":", "/", and "bc". One socket can have 0-64 delimiters and each
+ delimiter can contain 1-64 characters.
+
+4 EXCEPTION
+ EXCEPTION=expr Applies to: All devices
+
+ Defines an error handler for an I/O device. The expression must contain
+ a fragment of GT.M code (for example, GOTO ERRFILE) that GT.M XECUTEs
+ when the driver for the device detects an error, or an entryref to
+ which GT.M transfers control, as appropriate for the current
+ gtm_ztrap_form.
+
+ For more information on error handling, refer to the "Error Processing"
+ chapter in GT.M Programmer's Guide.
+
+4 EXTENSION
+ EXTENSION=intexpr Applies to: Sequential Files
+
+ Specifies the number of 512 byte blocks for RMS to extend the file when
+ the original ALLOCATION is exhausted. If integer expression equals zero
+ (0), the default for the disk volume, which is generally small,
+ determines the extension size.
+
+ By default, RMS uses an EXTENSION of zero (0).
+
+4 FIXED
+ [NO]FIXED Applies to: Sequential Files
+
+ Selects a fixed record length format for sequential disk files. FIXED
+ does not specify the actual length of a record. Use RECORDSIZE to
+ specify the record length.
+
+ NOFIXED specifies a variable length record format for sequential disk
+ files. NOFIXED is a synonym for VARIABLE. FIXED is incompatible with
+ VARIABLE.
+
+ By default, records have VARIABLE length.
+
+4 GROUP
+ GROUP=expr Applies to: Sequential Files
+
+ Specifies UIC-based security on RMS files. The expression is a mask
+ evaluating to null or to any combination of the letters REWD,
+ indicating respectively READ, EXECUTE, WRITE, and DELETE access. When
+ any one of these deviceparameters appears on an OPEN of a new file, any
+ user category (OWNER, SYSTEM, WORLD) that is not explicitly specified
+ is given the default mask. When any one of these deviceparameters
+ appears on an OPEN of an existing device, any user category that is not
+ explicitly specified remains unchanged.
+
+ In order to modify file security, the user who issues the OPEN must
+ have control access.
+
+ By default, OPEN does not modify the UIC-based security on an existing
+ file. Unless otherwise specified, when OPEN creates a new file, it
+ establishes security using standard defaulting rules.
+
+4 IOERROR
+ IOERROR=expr Applies to: Socket Device
+
+ Enables exception handling in socket devices. expr specifies the I/O
+ error trapping mode. A value equal to "TRAP" specifies that I/O errors
+ on a device raise error conditions. A value equal to "NOTRAP", or when
+ IOERROR is not specified, indicates that I/O error on a device does not
+ raise error conditions.
+
+ GT.M currently handles exception handling at device level instead
+ of socket level.
+
+4 NEWVERSION
+ NEWVERSION Applies to: Sequential Files
+
+ The NEWVERSION deviceparameter creates a new version of the file.
+
+ By default, if any version of the file exists, OPEN accesses the
+ current version. Otherwise, if no version of the file exists, OPEN
+ without READONLY creates a new file.
+
+4 OWNER
+ OWNER=expr Applies to: Sequential Files
+
+ Specifies UIC-based security on RMS files. The expression is a mask
+ evaluating to null or to any combination of the letters REWD,
+ indicating respectively READ, EXECUTE, WRITE, and DELETE access. When
+ any one of these deviceparameters appears on an OPEN of a new file, any
+ user category that is not explicitly specified is given the default
+ mask. When any one of these deviceparameters appears on an OPEN of an
+ existing file, any user category (GROUP, SYSTEM, WORLD) that is not
+ explicitly specified remains unchanged.
+
+ To modify file security, the user who issues the OPEN must have control
+ access.
+
+ By default, OPEN does not modify the UIC-based security on an existing
+ file. Unless otherwise specified, OPEN establishes security using
+ standard defaulting rules when it creates a new file.
+
+4 PRMMBX
+ PRMMBX Applies to: VMS Mailboxes
+
+ Specifies that the argument of the OPEN is a permanent mailbox name. If
+ the mailbox does not exist and the process has adequate privileges,
+ GT.M creates the mailbox. If the mailbox does not exist and the process
+ does not have adequate privileges, the process generates a run-time
+ error. A process does not require any privileges to OPEN an existing
+ mailbox. See the Using Mailboxes section for a discussion of the
+ required privileges.
+
+ By default, OPEN translates its device argument as a logical name and
+ uses the result as the actual device/file-specification. This means
+ that if the result is not an existing device or file, OPEN attempts to
+ create an RMS sequential disk file with that name.
+
+4 READONLY
+ [NO]READONLY Applies to: Sequential Files and VMS Mailboxes
+
+ OPENs a device for reading only (READONLY) or reading and writing
+ (NOREADONLY).
+
+ To open a sequential file using the READONLY parameter, the file must
+ exist on the disk. If it does not, GT.M issues a run-time error.
+
+ When GT.M encounters a WRITE directed to a file or mailbox OPENed
+ READONLY, GT.M issues a run-time error.
+
+ By default, OPEN accesses the device or file NOREADONLY (read-write).
+
+4 RECORDSIZE
+ RECORDSIZE=intexpr Applies to: Sequential Files
+
+ Overrides the default record size for a disk and specifies the new
+ maximum record size in bytes.
+
+ For mailboxes, BLOCKSIZE controls both block-size and record-size, and
+ RECORDSIZE is ignored.
+
+4 REWIND
+ REWIND Applies to: Sequential Files
+
+ REWIND positions the file pointer of a sequential disk to the first
+ record.
+
+ By default, OPEN does not REWIND.
+
+4 SHARED
+ SHARED Applies to: Sequential Files
+
+ Allows more than one user to access the same disk file. A file OPENed
+ SHARED can accommodate a theoretically unlimited number of readers and
+ a single writer. Any attempt to OPEN a file that is already OPEN by
+ another process causes a run-time error unless all processes OPEN the
+ file SHARED or READONLY. OPENing a file SHARED prevents RMS from using
+ most of its algorithms for optimizing access and therefore
+ significantly reduces the performance of I/O to that file.
+
+ By default, OPEN accesses the file or device exclusively (not SHARED).
+
+4 SYSTEM
+ SYSTEM=expr Applies to: Sequential Files
+
+ Specifies UIC-based security on RMS files. The expression is a mask
+ evaluating to null or to any combination of the letters REWD,
+ indicating respectively READ, EXECUTE, WRITE, and DELETE access. When
+ any one of these deviceparameters appears on an OPEN of a new file, any
+ user category that is not explicitly specified is given the default
+ mask. When any one of these deviceparameters appears on an OPEN of an
+ existing file, any user category (OWNER, GROUP, WORLD), that is not
+ explicitly specified remains unchanged.
+
+ In order to modify file security, the user who issues the OPEN or CLOSE
+ must have control access ownership.
+
+ By default, OPEN does not modify the UIC-based security permissions on
+ an existing file. Unless otherwise specified, when OPEN creates a new
+ file, it establishes security using standard defaulting rules.
+
+4 TMPMBX
+ TMPMBX Applies to: VMS Mailboxes
+
+ Specifies that the argument of the OPEN is a temporary mailbox name. If
+ the mailbox does not exist, and the process has adequate privileges,
+ GT.M creates the mailbox. If the mailbox does not exist and the process
+ does not have adequate privileges, the process generates a run-time
+ error. A process does not require any privileges to OPEN an existing
+ mailbox. See the Using Mailboxes section for a discussion of the
+ required privileges.
+
+ By default, OPEN translates its device argument as a logical name and
+ uses the result as the actual device/file-specification. This means
+ that if the result is not an existing device or file, OPEN attempts to
+ create an RMS sequential disk file with that name.
+
+4 TRUNCATE
+ [NO]TRUNCATE Applies to: Sequential Files
+
+ Enables or disables overwriting of existing data in Files-11 RMS files.
+ Because the position of each record depends on the prior record, a
+ WRITE destroys the ability to position reliably to subsequent records
+ in a file. Therefore, by default (NOTRUNCATE), GT.M permits WRITEs only
+ when the file pointer is positioned at the end-of-file. When a device
+ has TRUNCATE enabled, a WRITE issued when the file pointer is not at
+ end-of-file truncates the file by destroying all data from the file
+ pointer to the end-of-file.
+
+ By default, OPEN accesses the file NOTRUNCATE, which does not allow
+ overwriting of Files-11 RMS files.
+
+4 VARIABLE
+ VARIABLE Applies to: Sequential Files
+
+ Specifies the VARIABLE record length format for sequential disk files.
+
+ VARIABLE is a synonym for NOFIXED. VARIABLE length records on disk
+ start with two bytes of overhead for the device driver that hold the
+ actual record-length represented as a two's complement binary number.
+ VARIABLE length tape records start with four bytes of overhead, and
+ represent the length as ASCII digits. A BLOCKSIZE for VARIABLE length
+ tape records must specify at least four bytes more than the maximum
+ record length. VARIABLE is incompatible with FIXED.
+
+ By default, records have VARIABLE length.
+
+4 WORLD
+ WORLD=expr Applies to: Sequential Files
+
+ Specifies UIC-based security on RMS files. The expression is a mask
+ evaluating to null or to any combination of the letters REWD,
+ indicating respectively READ, EXECUTE, WRITE, and DELETE access. When
+ any one of these deviceparameters appears on an OPEN of a new file, any
+ user category that is not explicitly specified is given the default
+ mask. When any one of these deviceparameters appears on an OPEN of an
+ existing file, any user category (OWNER, GROUP, SYSTEM), that is not
+ explicitly specified remains unchanged.
+
+ To modify file security, the user who issues the OPEN must have control
+ access.
+
+ By default, OPEN and CLOSE do not modify the UIC-based security on an
+ existing file. Unless otherwise specified, when OPEN creates a new
+ file, it establishes security using standard defaulting rules.
+
+4 WRAP
+ [Z][NO]WRAP Applies to: NULL Devices, Sequential Devices, and Socket
+ Device
+
+ Enables or disables automatic record termination. When the current
+ record size ($X) reaches the maximum WIDTH and the device has WRAP
+ enabled, GT.M starts a new record, as if the routine had issued a WRITE
+ ! command.
+
+ NOWRAP causes GT.M to require a WRITE ! to terminate the record. NOWRAP
+ allows $X to become greater than the device WIDTH for terminals and
+ null devices. Sequential files discard any portion of the current
+ output record over the device width
+
+ By default, records WRAP.
+
+4 WRITEONLY
+ [NO]WRITEONLY Applies to: VMS Mailboxes
+
+ OPENs a mailbox for writing only (WRITEONLY) or reading and writing
+ (NOWRITEONLY).
+
+ By default, OPEN creates new mailboxes NOWRITEONLY (read-write).
+
+4 ZBFSIZE
+ ZBFSIZE Applies to: Socket Devices
+
+ Allocates a buffer used by GT.M when reading from a socket. The ZBFSIZE
+ deviceparameter should be at least as big as the largest message
+ expected.
+
+ By default, the size of ZBFSIZE is 1024 and the maximum it can be is
+ 1048576.
+
+4 ZDELAY
+ Z[NO]DELAY Applies to: Socket Devices
+
+ Controls buffering of data packets by the system TCP stack using the
+ TCP_NODELAY option to the SETSOCKOPT system call. This behavior is
+ sometimes known as the Nagle algorithm. The default is ZDELAY. This
+ delays sending additional packets until either an acknowledgement of
+ previous packets is received or an interval passes. If several packets
+ are sent from one end of a connection before the other end responds,
+ setting ZNODELAY may be desirable though at the cost of additional
+ packets being transmitted over the network. ZNODELAY must be fully
+ spelled out.
+
+4 ZFF
+ Z[NO]FF=expr Applies to: Socket Device
+
+ expr specifies a string of characters, typically in $CHAR() format to
+ send to socket device, whenever a routine issues a WRITE #. When no
+ string is specified or when ZFF="", then no characters are sent. The
+ default in GT.M is ZNOFF.
+
+4 ZIBFSIZE
+ ZIBFSIZE Applies to: Socket Device
+
+ Sets the buffer size used by the network software (setsockopt
+ SO_RCVBUF).
+
+ The default and the maximum values depend on the platform and/or system
+ parameters.
+
+4 ZLISTEN
+ ZLISTEN=expr Applies to: Socket Device
+
+ A new socket is allocated to listen for a connection. It is made the
+ current socket for the device, if the operation is successful. Upon
+ successful completion, $KEY is set to the format of
+ "BOUND|<socket handle>|<port number>"
+
+ otherwise, $KEY is assigned the empty string.
+
+ expr specifies the protocol and protocol specific information.
+ Currently, TCP/IP is the only protocol GT.M supports. expr must be of
+ the format "<port>:TCP", where port specifies the port number at which
+ the socket is waiting for a connection.
+
+ ZLISTEN is not compatible with ATTACH in the USE command and
+ CONNECT in both USE and OPEN commands.
+
+2 Use
+ Use Command
+
+ The USE command selects the current device for READs (input) and WRITEs
+ (output).
+
+ The format of the USE command is:
+
+ U[SE][:tvexpr] expr[:(keyword[=expr][:...])][,...]
+
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o The required expression specifies the device to make the current
+ device.
+
+ o A USE that selects a device not currently OPENed by the process
+ causes a run-time error.
+
+ o The optional keywords specify deviceparameters that control device
+ behavior; some deviceparameters take arguments delimited by an
+ equal sign (=). If there is only one deviceparameter, the
+ surrounding parentheses are optional.
+
+ o An indirection operator and an expression atom evaluating to a list
+ of one or more USE arguments form a legal argument for a USE.
+
+ The intrinsic special variable $IO identifies the current device, so
+ GT.M directs all READs and WRITEs to $IO. When a GT.M image starts,
+ $PRINCIPAL is implicitly OPENed and USEd. Once the GT.M image USEs a
+ device, $IO holds the name of that device until the next USE command.
+
+ A USE command modifies the device in accordance with the
+ deviceparameters that apply to the device type and ignores those that
+ do not apply. Characteristics set with USE deviceparameters persist
+ until another USE for the same device with the corresponding
+ deviceparameter. Characteristics persist through USEs of other devices
+ and, except for Files-11 RMS devices, through a subsequent CLOSE and
+ re-OPEN.
+
+ Example:
+
+ USE $P:(X=0:Y=$Y-1:NOECHO)
+
+ This example USEs the principal device. If that device is a terminal,
+ the deviceparameters turn off echo and position the cursor to the
+ beginning of the previous line.
+
+3 Use_DeviParam
+ Use Deviceparameters
+
+4 ATTACH
+ ATTACH=expr Applies to: Socket Device
+
+ When ATTACH is used and one of ZLISTEN and CONNECT is specified at the
+ same time, the value of expr becomes the identifier of the newly
+ created socket. If neither ZLISTEN nor CONNECT is specified, expr
+ specifies the socket to be moved from the socketpool to the socket
+ device argument of USE.
+
+4 CENABLE
+ [NO]CENABLE Applies to: Terminals and Printers
+
+ Enables or disables the ability to force GT.M into Direct Mode by
+ entering <CTRL-C> at $PRINCIPAL.
+
+ [NO]CENABLE is subordinate to a CTRAP that includes <CTRL-C> ($C(3)).
+
+ By default, images have CENABLEd. Linking the image with a GTM$DEFAULTS
+ that has parameter GTM$CTRLC_ENABLE==0 changes the default for the
+ image.
+
+4 CLEARSCREEN
+ CLEARSCREEN Applies to: Terminals and Printers
+
+ Clears the terminal screen from the present cursor position to the
+ bottom of the screen. The CLEARSCREEN deviceparameter does not change
+ the cursor position or the $X and $Y variables.
+
+ Example:
+
+ U $P:(X=0:Y=0:CLEAR)
+
+ This example positions the cursor to "home" in the upper left corner of
+ a VDT and clears the entire current screen "page."
+
+4 CONNECT
+ CONNECT=expr Applies to: Socket Device
+
+ Enables a client connection with a server, which is located by the
+ information provided by expr. A new socket is allocated for the client
+ connection and is made the current socket for the device, if the
+ operation is successful.
+
+ expr specifies the protocol and protocol specific information.
+ Currently, TCP/IP is the only protocol GT.M supports. expr should be of
+ the format "<host>:<port>:TCP", where host is either an IP address or a
+ hostname like server.sanchez.com.
+
+ CONNECT is not compatible with ZLISTEN.
+
+4 CONVERT
+ [NO]CONVERT Applies to: Terminals and Printers
+
+ Enables or disables the terminal device driver from converting
+ lowercase input to uppercase during READs.
+
+ By default, the VMS terminal device driver operates NOCONVERT.
+
+4 CTRAP
+ CTRAP=expr Applies to: Terminals and Printers
+
+ Establishes the <CTRL> characters in the expression as trap characters
+ for the current device. When the terminal device driver receives a trap
+ character in the input from a device, GT.M issues a run-time exception.
+ The device does not have to be the current device, that is $IO.
+
+ The <CTRL> characters are ASCII 0 though 31.
+
+ For example, the command U $P:CTRAP=$C(26,30,7,19) sets a trap for the
+ ASCII characters <SUB>, <RS>, <BEL> and <DC3>.
+
+ Specifying CTRAP completely replaces the previous CTRAP list. Setting
+ CTRAP to the null string ("") disables character trapping.
+
+ A trap character enabled by CTRAP produces one of the following
+ actions:
+
+ o If an EXCEPTION deviceparameter has been issued for the device, the
+ process executes the EXCEPTION argument.
+
+ o Otherwise, if $ETRAP is not the empty string, execute $ETRAP.
+
+ o Otherwise, if $ZTRAP is not the empty string, the process executes
+ $ZTRAP.
+
+ o Otherwise, the GT.M image terminates.
+
+ For more information on error handling, refer to the "Error Processing"
+ chapter in GT.M Programmer's Guide.
+
+ When CTRAP includes <CTRL-C>, [NO]CENABLE has no effect. CTRAPping
+ <CTRL-C> also takes precedence over CENABLE.
+
+4 DELIMITER
+ [NO]DELIMITER Applies to: Socket Device
+
+ DELIMITER establishes or replaces the list of delimiters used by the
+ sockets associated with the device. The default when the socket device
+ is first OPENed is NODELIMITER. The delimiter list on a preexisting
+ device remains the same until it is explicitly replaced or deleted.
+
+ expr must be a string of the following format:
+
+ ':' is used to separate delimiters (it is the delimiter for
+ delimiters).
+
+ '/' serves as an escape character.
+
+ expr "ab:/:://:bc" is interpreted as four delimiters, which are "ab",
+ ":", "/", and "bc". One socket can have 0-64 delimiters and each
+ delimiter can contain 1-64 characters.
+
+4 DETACH
+ DETACH=expr Applies to: Socket Device
+
+ Removes the socket identified by expr from the current socket device,
+ without affecting any existing connection of that socket. The removed
+ socket is placed in the socketpool and may be attached to another
+ socket device. If the socket being removed is the current socket, then
+ GT.M does the following:
+
+ o The socket ATTACHed prior to the removed socket, is made current,
+ if one such exists.
+
+ o The socket ATTACHed after the removed socket, is made current, if
+ the removed one was the first socket.
+
+ o $PRINCIPAL is made the current device ($IO), if the removed socket
+ was the only one in the current socket device.
+
+4 DOWNSCROLL
+ DOWNSCROLL Applies to: Terminals and Printers
+
+ If $Y=0, DOWNSCROLL does nothing. Otherwise, DOWNSCROLL moves the
+ cursor up one line on the terminal screen and decrements $Y by one.
+ DOWNSCROLL does not change the column position or $X. Some terminal
+ hardware may not support DOWNSCROLL.
+
+4 ECHO
+ [NO]ECHO Applies to: Terminals and Printers
+
+ Enables or disables terminal device driver echo of input.
+
+ By default, VMS terminal device drivers ECHO.
+
+4 EDITING
+ [NO]EDITING Applies to: Terminals and Printers
+
+ Enables or disables the VMS terminal line editor. The VMS line editor
+ allows the use of the left and right cursor movement keys, function
+ keys 11 through 14 and certain <CTRL> characters, in modifying the
+ current input line. Note that this is analogous to the
+ /[NO]LINE_EDITING qualifier of the DCL SET TERMINAL command, not the
+ /[NO]EDIT_MODE qualifier.
+
+ By default, the VMS terminal device driver supports EDITING.
+
+4 ERASELINE
+ ERASELINE Applies to: Terminals and Printers
+
+ Clears the current line from the physical cursor position to the end of
+ the line. ERASELINE does not affect the physical cursor position, or $X
+ and $Y.
+
+4 ESCAPE
+ [NO]ESCAPE Applies to: Terminals and Printers
+
+ Enables or disables terminal device driver processing of escape
+ sequences.
+
+ The following events result when a terminal has ESCAPE sequencing
+ enabled. When an <ESC> or <CSI> arrives in the terminal input, the
+ device driver verifies the sequence that follows as a valid ANSI escape
+ sequence, terminates the READ, and sets $ZB to contain the entire
+ escape sequence. In this case, if the sequence starts with an <ESC>,
+ READ * returns the decimal ASCII representation for the character of
+ the escape introducer.
+
+ When escape processing is disabled, READ *x returns 27 in x for an
+ <ESC>. If the escape introducer is also a TERMINATOR, $ZB has a string
+ of length one (1), and a value of the $ASCII() representation of the
+ escape introducer; otherwise, $ZB holds the empty string. For single
+ character and short fixed reads with NOESCAPE, the terminal device
+ driver places the remaining characters of the escape sequence in the
+ input buffer for subsequent READs, regardless of [NO]TYPEAHEAD."
+
+ Since most escape sequences have special VMS interpretations,
+ particularly for VMS line editing, escape sequence processing does not
+ terminate READs, except for single character READs, unless the terminal
+ has NOEDITING or PASTHRU set to turn off VMS interpretation of the
+ sequences.
+
+ By default, the VMS terminal device driver performs ESCAPE sequencing.
+
+4 EXCEPTION
+ EXCEPTION=expr Applies to: All devices
+
+ Defines an error handler for an I/O device. The expression must contain
+ a fragment of GT.M code (e.g., GOTO ERRFILE) that GT.M XECUTEs when the
+ driver for the device detects an error, or an entryref to which GT.M
+ transfers control, as appropriate for the current gtm_ztrap_form.
+
+ For more information on error handling, refer to the "Error Processing"
+ chapter in GT.M Programmer's Guide.
+
+4 FIELD
+ FIELD=intexpr Applies to: Terminals and Printers
+
+ FIELD sets the maximum length of a single terminal READ operation. By
+ default, the terminal device driver uses a FIELD size of 1024 bytes.
+ Specifying an integer expression of zero (0) resets the FIELD size to
+ 1024 bytes.
+
+ Every READ which is not a READ * or an explicit fixed-length READ, is
+ treated as a READ x# FIELD.
+
+4 FILTER
+ [NO]FILTER[=expr] Applies to: Terminals and Printers, Socket Device,
+ and NULL Device
+
+ Specifies character filtering for valid filtering expressions.
+ Filtering requires character by character examination of all output and
+ reduces I/O performance.
+
+ Each FILTER deviceparameter can have only one argument. However,
+ multiple FILTER deviceparameters can appear in a single USE command,
+ each with different arguments.
+
+ The valid values for expr:
+
+ [NO]CHARACTERS enables or disables maintenance of $X and $Y according
+ to the M ANSI standard for the characters <BS>, <LF>, <CR> and <FF>.
+ CHARACTERS causes the device driver to examine all output for the above
+ characters, and to adjust $X and $Y accordingly. By default, GT.M
+ performs special maintenance on $X and $Y only for M format control
+ characters, WRAPped records, and certain action deviceparameters.
+
+ [NO]ESCAPE alters the effect of ANSI escape sequences on $X and $Y.
+ ESCAPE causes GT.M to filter the output, searching for ANSI escape
+ sequences and preventing them from updating $X and $Y. By default, GT.M
+ does not screen output for escape sequences.
+
+ By default, GT.M does not perform output filtering. For GT.M to
+ maintain $X for non-graphic characters as described by the standard,
+ FILTER="CHARACTERS" must be enabled. Output filtering adds additional
+ overhead to I/O processing. Linking the image with a GTM$DEFAULTS that
+ has a modified GTM$USER_WRITE_FILTER parameter changes the default for
+ the image. A value of 0x80 specifies CHARACTER filtering, a value of
+ 0x01 specifies ESCAPE filtering, and a value of 0x81 specifies both.
+
+4 FLUSH
+ FLUSH Applies to: Terminals and Printers
+
+ Discards the contents of the type-ahead buffer. When a terminal has no
+ outstanding READ and has TYPEAHEAD enabled, the device driver stores
+ arriving input entered in a type-ahead buffer. The device driver uses
+ data from the type-ahead buffer for subsequent READs.
+
+ The FLUSH deviceparameter can be useful for application error recovery.
+ An application may be designed to detect an error and write a message
+ to the terminal followed by a request for operator action. In this
+ case, a USE $P:FLUSH preceding the READ eliminates type-ahead and
+ prevents the type-ahead from being inappropriately used during error
+ recovery.
+
+4 HOSTSYNC
+ [NO]HOSTSYNC Applies to: Terminals and Printers
+
+ Enables or disables the use of XON/XOFF by the host to throttle input
+ and prevent impending buffer overruns for a terminal. This
+ deviceparameter provides a control mechanism for the host over
+ asynchronous communication lines to help prevent data loss when
+ hardware is slow and/or processing load is high.
+
+ By default, the VMS device driver operates HOSTSYNC.
+
+4 INSERT
+ [NO]INSERT Applies to: Terminals and Printers
+
+ Enables or disables insert mode for a terminal. When a terminal has
+ INSERT mode enabled, the device driver inserts input characters at the
+ logical position in the input stream designated by the cursor, .for
+ example in the middle of the line/record. When a terminal has INSERT
+ mode disabled, the device driver overwrites existing characters in the
+ input stream at the logical position designated by the cursor.
+
+ By default, the VMS terminal driver operates NOINSERT (OVERSTRIKE).
+
+4 IOERROR
+ IOERROR=expr Applies to: Socket Device
+
+ Enables exception handling in socket devices. expr specifies the I/O
+ error trapping mode. A value equal to "TRAP" specifies that I/O errors
+ on a device raise error conditions. A value equal to "NOTRAP", or when
+ IOERROR is not specified, indicates that I/O error on a device does not
+ raise error conditions.
+
+ GT.M currently handles exception handling at device level instead
+ of socket level.
+
+4 LENGTH
+ [Z]LENGTH=intexpr Applies to: Terminals and Printers, VMS Mailboxes,
+ Socket Device, and NULL Device.
+
+ Sets the virtual page length for an I/O device to the integer
+ expression. The page length controls the point at which the device
+ driver automatically resets $Y to 0.
+
+ By default, GT.M uses the LENGTH specified by the VMS device
+ characteristics at image activation. Sequential files, socket devices,
+ mailboxes and null devices have a default of 66. The terminal default
+ depends on the type of terminal.
+
+4 OVERSTRIKE
+ OVERSTRIKE Applies to: Terminals and Printers
+
+ Disables INSERT mode for a terminal. OVERSTRIKE is a synonym for
+ NOINSERT.
+
+ By default, the VMS terminal driver operates OVERSTRIKE (NOINSERT).
+
+4 PASTHRU
+ [NO]PASTHRU Applies to: Terminals and Printers
+
+ Enables or disables operating system interpretation of <CTRL>
+ characters for a terminal. When a terminal has PASTHRU enabled, the
+ operating system passes the characters that it normally uses to control
+ terminal interaction through to the application program.
+
+ PASTHRU supersedes line editing.
+
+ Exercise caution with PASTHRU in debugging, because using a PASTHRU
+ terminal in Direct Mode is somewhat awkward.
+
+ [NO]TTSYNC must be used with [NO]PASTHRU to control XON/XOFF handling.
+
+ By default, the VMS device driver operates NOPASTHRU.
+
+4 READSYNC
+ [NO]READSYNC Applies to: Terminals and Printers
+
+ Enables or disables automatic output of <XON> before a READ and <XOFF>
+ after a READ.
+
+ By default, the VMS terminal drivers operate NOREADSYNC.
+
+4 REWIND
+ REWIND Applies to: Sequential Files
+
+ REWIND for a disk file is a logical rather than a physical operation.
+
+ By default, USE does not REWIND.
+
+4 SOCKET
+ SOCKET=expr Applies to: Socket Device
+
+ The socket specified in expr is made the current socket. Specifying a
+ socket that has not been previously OPENed generates an error.
+
+ SOCKET is compatible with DELIMITER only.
+
+4 TERMINATOR
+ [NO]TERMINATOR[=expr] Applies to: Terminals and Printers
+
+ Specifies which of the 256 ASCII characters terminate a READ. For
+ example, TERMINATOR=$C(0) makes <NUL> the terminator.
+
+ When [NO]ESCAPE is in effect, TERMINATOR controls whether or not <ESC>
+ or <CSI> are treated as terminators, however, when ESCAPE processing is
+ enabled, the entire escape sequence is treated as a terminator
+ regardless of the TERMINATOR specification.
+
+ NOTERMINATOR eliminates all terminators. When a terminal has all
+ terminators disabled, fixed length READ and READ * terminate on receipt
+ of some number of characters, and a timed READ terminates on timeout,
+ but any other READ only terminates when the input fills the terminal
+ read buffer.
+
+ By default, terminals recognize <CR> and <ESC> as terminators, (i.e.,
+ TERMINATOR=$C(13,27)). TERMINATOR="" restores the default. However,
+ unless the terminal has PASTHRU or NOEDITING, the operating system
+ interprets some escape sequences rather than passing them to the READ.
+
+ Example:
+
+ GTM> USE $P:TERM=$C(26,13,11,7)
+
+ This example enables the ASCII characters <SUB>, <CR>, <VT> and <BEL>
+ as READ terminators.
+
+4 TRUNCATE
+ [NO]TRUNCATE Applies to: Sequential Files
+
+ Enables or disables overwriting of existing data in sequential files.
+ Because the position of each record depends on the prior record, a
+ WRITE destroys the ability to reliably position to subsequent records
+ in a file. Therefore, by default (NOTRUNCATE), GT.M permits WRITEs only
+ when the file pointer is positioned at the end-of-file. When a device
+ has TRUNCATE enabled, a WRITE issued when the file pointer is not at
+ end-of-file truncates the file by destroying all data from the file
+ pointer to the end-of-file.
+
+ By default, OPEN accesses files NOTRUNCATE, which does not allow
+ overwriting of sequential files.
+
+4 TTSYNC
+ [NO]TTSYNC Applies to: Terminals and Printers
+
+ Enables or disables recognition of XON/XOFF for terminal output.
+ When a terminal has PASTHRU and NOTTSYNC in effect, the device
+ driver passes <XON> and <XOFF> on to the GT.M application programs.
+ When a terminal does not have PASTHRU enabled, [NO]TTSYNC has no
+ effect on the GT.M process. A terminal may have its own handling of
+ XON/XOFF, controlled by a set-up mode or by switches. If an
+ application requires program recognition of <CTRL-S> and <CTRL-Q>,
+ the terminals may require reconfiguration.
+
+ By default, the VMS terminal device driver operates TTSYNC.
+
+4 TYPEAHEAD
+ [NO]TYPEAHEAD Applies to: Terminals and Printers
+
+ Enables or disables type-ahead buffering for a terminal. With
+ NOTYPEAHEAD and no outstanding READ, the terminal device driver
+ discards input entered at the terminal. With TYPEAHEAD and no
+ outstanding READ, the device driver stores input entered at the
+ terminal in a type-ahead buffer. The device driver uses data from the
+ type-ahead buffer for subsequent READs.
+
+ The size of the type-ahead buffer limits the amount of data entered at
+ the terminal that the device driver can store in anticipation of future
+ READs. When the type-ahead buffer is full, the device driver sends a
+ warning <BEL> character to the terminal and discards input that would
+ overflow the buffer.
+
+ FLUSH discards the contents of the type-ahead buffer.
+
+ By default, the VMS terminal device driver accepts TYPEAHEAD.
+
+4 UPSCROLL
+ UPSCROLL Applies to: Terminals and Printers
+
+ Moves the cursor down one line on the terminal screen. If $Y=LENGTH-1,
+ UPSCROLL sets $Y=0. Otherwise UPSCROLL increments $Y by one. If the
+ cursor is physically at the bottom of the page, the screen scrolls up
+ one line. UPSCROLL does not change the column position or $X.
+
+4 WAIT
+ [NO]WAIT Applies to: VMS Mailboxes
+
+ Enables or disables synchronization of mailbox WRITEs.
+
+ A synchronized WRITE does not return control to the application program
+ until some other process READs the written message. Such mailbox WRITEs
+ serve as a tool for synchronizing two processes. Because GT.M does not
+ have a timeout on the WRITE command, there is no way, other than a READ
+ of the mailbox by another process or a <CTRL-C> on $PRINCIPAL, for the
+ writing program to regain control of its process.
+
+ NOWAIT provides asynchronous WRITEs analogous to those always used for
+ other device types.
+
+ By default, WRITE to a mailbox operates NOWAIT.
+
+4 WIDTH
+ [Z]WIDTH=intexpr Applies to: Terminals and Printers, Socket Device,
+ NULL Device, and Sequential Files
+
+ Sets the device's logical record size and enables WRAP.
+
+ NOWRAP and WIDTH supersede each other. When WIDTH and NOWRAP appear
+ together on the same USE command, the final one controls the device
+ behavior. For a terminal, WIDTH=0 is equivalent to WIDTH=n:NOWRAP,
+ where n is the default length of a logical record on that terminal.
+
+ By default, disks have a WIDTH of 1024, and sockets have a WIDTH of
+ 255. Terminals inherit their default WIDTH in GT.M from the invoking
+ VMS environment.
+
+ The default WIDTH for null and socket device is 255.
+
+4 WRAP
+ [Z][NO]WRAP Applies to: Terminals and Printers, Socket Device, NULL
+ Device, and Sequential Files
+
+ Enables or disables automatic record termination. When the current
+ record size ($X) reaches the maximum WIDTH and the device has WRAP
+ enabled, GT.M starts a new record, as if the routine had issued a WRITE
+ ! command.
+
+ NOWRAP causes GT.M to require a WRITE ! to terminate the record. NOWRAP
+ allows $X to become greater than the device WIDTH for terminals and
+ null devices. Sequential files discard any portion of the current
+ output record over the device width.
+
+ By default, WIDTH sets WRAP. When WIDTH and NOWRAP appear together on
+ the same USE command, the last one controls the device behavior.
+
+ By default, records WRAP.
+
+4 WRITEOF
+ WRITEOF Applies to: VMS Mailboxes
+
+ Writes an end-of-file (EOF) message to a mailbox device. GT.M fulfills
+ the corresponding READ by returning a null string and setting $ZEOF to
+ true.
+
+4 X
+ X=intexpr Applies to: Terminals and Printers
+
+ $X positions the cursor to a vertical column on the terminal. If NOWRAP
+ is enabled or intexpr<WIDTH, the terminal device driver sets
+ $X=intexpr. If WRAP is enabled and intexpr>WIDTH, GT.M sets
+ $X=intexpr#WIDTH, where # is the GT.M modulo operator. The resulting $X
+ determines the actual physical position.
+
+ To ensure that $Y and $X match what is occurring visually on the
+ terminal, the GT.M deviceparameters and the VMS device characteristics
+ must match at all times. For example, if a process spawns out of GT.M
+ and changes the terminal wrap setting from NOWRAP, to WRAP with the DCL
+ SET TERMINAL/WRAP command, GT.M returns to the NOWRAP condition when
+ the subprocess completes, and wraps on the terminal do not reflect in
+ the values of $X and $Y.
+
+ The terminal hardware may affect physical cursor positioning. The X
+ deviceparameter does not change the cursor row or update $Y.
+
+4 Y
+ Y=intexpr Applies to: Terminals and Printers, and NULL Device
+
+ Positions the cursor to a horizontal row on the terminal.
+
+ The terminal device driver sets $Y=intexpr#LENGTH, where # is the GT.M
+ modulo operator. If intexpr<LENGTH, the resulting $Y determines the
+ physical position. If intexpr>LENGTH, the cursor is positioned so that
+ $Y=intexpr#LENGTH, where # is the GT.M module operator. The terminal
+ hardware may affect physical cursor positioning.
+
+ To ensure that $Y and $X match what is occurring visually on the
+ terminal, the GT.M deviceparameters and the VMS device characteristics
+ must match at all times. For example, if a process spawns out of GT.M
+ and changes the terminal wrap setting from NOWRAP, previously set with
+ the GT.M USE command to WRAP with the DCL SET TERMINAL/WRAP command,
+ GT.M does not reflect the change when the subprocess completes.
+ Therefore, wraps on the terminal do not reflect in the values of $X and
+ $Y.
+
+ The Y deviceparameter does not change the cursor column or update $X.
+
+4 ZBFSIZE
+ ZBFSIZE Applies to: Socket Device
+
+ Allocates a buffer used by GT.M when reading from a socket. The ZBFSIZE
+ deviceparameter should be at least as big as the largest message
+ expected.
+
+ By default, the size of ZBFSIZE is 1024 and the maximum it can be is
+ 1048576.
+
+4 ZDELAY
+ Z[NO]DELAY Applies to: Socket Device
+
+ Controls buffering of data packets by the system TCP stack using the
+ TCP_NODELAY option to the SETSOCKOPT system call. This behavior is
+ sometimes known as the Nagle algorithm. The default is ZDELAY. This
+ delays sending additional packets until either an acknowledgement of
+ previous packets is received or an interval passes. If several packets
+ are sent from one end of a connection before the other end responds,
+ setting ZNODELAY may be desirable though at the cost of additional
+ packets being transmitted over the network. ZNODELAY must be fully
+ spelled out.
+
+4 ZFF
+ Z[NO]FF=expr Applies to: Socket Device
+
+ expr specifies a string of characters, typically in $CHAR() format to
+ send to socket device, whenever a routine issues a WRITE #. When no
+ string is specified or when ZFF="", then no characters are sent. The
+ default in GT.M is ZNOFF.
+
+4 ZIBFSIZE
+ ZIBFSIZE Applies to: Socket Device
+
+ Sets the buffer size used by the network software (setsockopt
+ SO_RCVBUF).
+
+ The default and the maximum values depend on the platform and/or system
+ parameters.
+
+4 ZLISTEN
+ ZLISTEN=expr Applies to: Socket Device
+
+ A new socket is allocated to listen for a connection. It is made the
+ current socket for the device, if the operation is successful. Upon
+ successful completion, $KEY is set to the format of
+ "BOUND|<socket handle>|<port number>"
+
+ otherwise, $KEY is assigned the empty string.
+
+ expr specifies the protocol and protocol specific information.
+ Currently, TCP/IP is the only protocol GT.M supports. expr must be of
+ the format "<port>:TCP", where port specifies the port number at which
+ the socket is waiting for a connection.
+
+2 Read
+ Read
+
+ The READ command transfers input from the current device to a global or
+ local variable specified as a READ argument. For convenience, READ also
+ accepts arguments that perform limited output to the current device.
+
+ The format of the READ command is:
+
+ R[EAD][:tvexpr] glvn|*glvn|glvn#intexpr|strlit|fcc[,...]
+
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o A subscripted or unsubscripted global or local variable name
+ specifies a variable into which to store the input; the variable
+ does not have to exist prior to the READ; if the variable does
+ exist prior to the READ, the READ replaces its old value.
+
+ o When an asterisk (*) immediately precedes the variable name, READ
+ accepts one character of input and places the ASCII code for that
+ character in the variable.
+
+ o When a number sign (#) and a non-zero integer expression
+ immediately follow the variable name, the integer expression
+ determines the maximum number of characters accepted as input to
+ the read; such reads terminate when GT.M reads the number of
+ characters specified by the integer expression or a terminator in
+ the input stream, whichever occurs first.
+
+ o To provide a concise means of issuing prompts, GT.M sends string
+ literal and format control character (!,?intexpr,#) arguments of a
+ READ to the current device as if they were arguments of a WRITE.
+
+ o An indirection operator and an expression atom evaluating to a list
+ of one or more READ arguments form a legal argument for a READ.
+
+ The maximum length of the input string is the smaller of the device
+ buffer size limitation or the GT.M maximum string length (32,767
+ characters). If a record is longer than the maximum record length, GT.M
+ returns the record piece by piece during sequential reads, for devices
+ that allow it.
+
+ When a string literal appears as an argument to a READ, M writes the
+ literal to the current device. String literals appear as READ arguments
+ to serve as prompts for input. GT.M does not permit expression
+ arguments on a READ to act as prompts. Variable prompts must appear as
+ arguments to a WRITE. If a variable appears as an argument to a READ,
+ GT.M always interprets it as input, never as output. This facility is
+ used mostly with terminal I/O.
+
+ The READ commands adjust $X and $Y, based on the length of the input
+ read.
+
+3 Read_Comm
+ READ * Command
+
+ The READ * command reads one character from the current device and
+ returns the decimal ASCII representation of that character into the
+ variable specified for the READ * command. READ * appears most
+ frequently in communication protocols, or in interactive programs where
+ single character answers are appropriate.
+
+ The following example reads the value "A", and returns the decimal
+ ASCII representation of "A" in the variable X.
+
+ Example:
+
+ GTM> READ *X
+
+ A
+
+ GTM> WRITE X
+
+ 65
+ If a timeout occurs before GT.M reads a character, the READ * returns a
+ negative one (-1) in the variable.
+
+3 Read_maxlen_Comm
+ READ X#maxlen Command
+
+ The READ X#maxlen command limits the maximum size of the input to a
+ maximum of "maxlen" characters, where maxlen is an integer expression.
+
+ If a READ follows a READ X#maxlen command, the READ returns the
+ remainder of the current record.
+
+ If a terminator arrives before maxlen characters are received the READ
+ X#maxlen terminates.
+
+2 Write
+ Write
+
+ The WRITE command transfers a character stream specified by its
+ arguments to the current device.
+
+ The format of the WRITE command is:
+
+ W[RITE][:tvexpr] expr|*intexpr|fcc[,...]
+
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o An expression argument supplies the text of a WRITE.
+
+ o When a WRITE argument consists of a leading asterisk (*) followed
+ by an integer expression, WRITE outputs one character associated
+ with the ASCII code specified by the integer evaluation of the
+ expression.
+
+ o WRITE also accepts format control characters as arguments; format
+ control characters modify the position of a virtual cursor: an
+ exclamation point (!) produces the device specific record
+ terminator (for example, new line for a terminal), a number sign
+ (#) produces device specific page terminator (for example, form
+ feed for a terminal) and a question mark (?) followed by an
+ expression moves the virtual cursor to the column specified by the
+ integer evaluation of the expression if the virtual cursor is to
+ the "left" of the specified column.
+
+ o When directed to a device bound to a mnemonicspace, WRITE also
+ accepts controlmnemonics, which are keywords specific to the
+ binding - they are delimited by a slash (/) prefix and optionally
+ followed by a parenthetical list of arguments. The parentheses "(
+ )" are optional when there are no arguments, but must appear even
+ if there is a single argument
+
+ o An indirection operator and an expression atom evaluating to a list
+ of one or more WRITE arguments form a legal argument for a WRITE.
+
+ GT.M can write up to 32,767 bytes (the GT.M maximum string length) as a
+ result of a single WRITE argument. GT.M buffers output into a "logical
+ record" for all devices except mailboxes and sockets without
+ DELIMITERs. The WRITE command appends a string to the current record of
+ the current device. GT.M does not write to the output device until the
+ buffer is full, a GT.M format control character forces a write, a USE
+ command, a CLOSE command, or, for terminals, the buffer becomes stale
+ (the terminal staleness timer is adjustable through GTM$DEFAULTS).
+
+ Each device has a WIDTH and a LENGTH that define the virtual "page".
+ The WIDTH determines the maximum size of a record for a device, while
+ the LENGTH determines how many records fit on a page. When the current
+ record size ($X) reaches the maximum WIDTH and the device has WRAP
+ enabled, GT.M starts a new record. When the current line ($Y) reaches
+ the maximum LENGTH, GT.M starts a new page.
+
+ A WRITE with an asterisk preceding the argument, which it would expect
+ to be a decimal ASCII representation, writes the character
+ corresponding to the ASCII representation. The WRITE command also has
+ several format control characters that allow the manipulation of the
+ virtual cursor. For all I/O devices, the GT.M format control characters
+ do the following:
+
+ WRITE ! Clears $X and increments $Y and terminates the logical
+ record in progress. The definition of "logical record" varies from
+ device to device, and is discussed in each device section.
+ WRITE # Clears $X and $Y and terminates the logical record in
+ progress.
+ WRITE ?n If n is greater than $X, writes n-$X spaces to the device,
+ bringing $X to n. If n is less than or equal to $X, WRITE ?n has no
+ effect. When WRAP is enabled and n exceeds the LENGTH of the line,
+ WRITE ?n increments $Y.
+ For more information, refer to the sections on specific I/O devices.
+
+2 Close
+ Close
+
+ The CLOSE command breaks the connection between a process and a device.
+
+ The format of the CLOSE command is:
+
+ C[LOSE][:tvexpr] expr[:(keyword[=expr][:...])][,...]
+
+ o The optional truth-valued expression immediately following the
+ command is a command postconditional that controls whether or not
+ GT.M executes the command.
+
+ o The required expression specifies the device to CLOSE.
+
+ o The optional keywords specify deviceparameters that control device
+ behavior; some deviceparameters take arguments delimited by an
+ equal sign (=); if there is only one keyword, the surrounding
+ parentheses are optional.
+
+ o An indirection operator and an expression atom evaluating to a list
+ of one or more CLOSE arguments form a legal argument for a CLOSE.
+
+ When a CLOSE is issued, GT.M flushes all pending output to the device,
+ and processes any deviceparameters. CLOSEing a device not currently
+ OPEN has no effect.
+
+ If the device is a temporary mailbox and the process is the only
+ process accessing the mailbox, the device driver deletes the mailbox.
+
+ GT.M retains the characteristics of all device types, except a Files-11
+ RMS, for use in case of subsequent re-OPENs. If the device is a
+ Files-11 RMS, characteristics controlled by deviceparameters are lost
+ after the CLOSE.
+
+ CLOSE may send sequential files to the VMS queue manager for
+ processing. The CLOSE command provides deviceparameters that SPOOL the
+ file for printing on a printer or terminal, or SUBMIT the file to batch
+ for execution. Many of the CLOSE deviceparameters for sequential files
+ control queue behavior for either SPOOL or SUBMIT or both, and
+ therefore must be used with SPOOL and/or SUBMIT to have any effect.
+
+ If the device being CLOSEd is $IO, GT.M implicitly USEs $PRINCIPAL.
+ GT.M ignores CLOSE $PRINCIPAL.
+
+ Example:
+
+ CLOSE sd:(SPOOL:QUEUE=que:DELETE)
+
+ This CLOSEs the device, and if it is an RMS file on disk, it spools the
+ file for printing on the QUEUE specified by the variable que. The CLOSE
+ also marks the file for deletion after printing.
+
+ Example:
+
+ CLOSE SD:RENAME=SD_".SAV"
+
+ This closes the device and, if it is a disk file, renames it to have
+ the type .SAV.
+
+3 Close_DeviParam
+ CLOSE Deviceparamenter
+
+4 AFTER
+ AFTER=expr Applies to: Sequential Disk Files
+
+ Specifies a time when a SPOOLed or SUBMITted job should start. The
+ expression provides a value for the time in DCL absolute or delta time
+ format.
+
+ By default, the VMS job controller starts processing a SUBMITted or
+ SPOOLed file as soon as system resources permit.
+
+4 BURST
+ [NO]BURST Applies to: Sequential Disk Files when used with SPOOL
+
+ Enables or disables printing burst flags on a SPOOLed file.
+
+ By default, the queue controls whether to print burst flags.
+
+4 CHARACTERISTIC
+ CHARACTERISTIC=intexpr Applies to: SPOOL or SUBMIT for Sequential Files
+
+ Specifies a characteristic required of the queue for processing a
+ SUBMITted or SPOOLed job. The expression supplies a single
+ characteristic number. To specify multiple characteristics, use the
+ CHARACTERISTIC deviceparameter more than once on the CLOSE.
+
+ The VMS system manager assigns queue CHARACTERISTICs. VMS gives
+ CHARACTERISTICs both names and numbers. However, the CHARACTERISTIC
+ deviceparameter only accepts numeric identifications.
+
+ By default, CLOSE does not limit the queue selection with
+ characteristics.
+
+ Example:
+
+ CLOSE sd:(SUBMIT:CHARACTERISTIC=4:CHAR=5)
+
+ This CLOSEs the device, and if the device is an RMS file, SUBMITs the
+ file to batch, restricting the VMS job controller to execute the job in
+ a queue with CHARACTERISTICs numbers 4 and 5.
+
+4 CLI
+ CLI=expr Applies to: Sequential Files when used with SUBMIT
+
+ Specifies a command language for a SUBMITted job. The expression must
+ name an available CLI.
+
+ By default, VMS uses the CLI identified by the account under which the
+ job was SUBMITted, generally DCL.
+
+4 COPIES
+ COPIES=intexp Applies to: Sequential Files when used with SPOOL
+
+ Specifies the number of copies of a SPOOLed file to print. The integer
+ expression supplies a number of copies.
+
+ By default, the spooler prints one copy.
+
+4 CPULIMIT
+ CPULIMIT=intexpr Applies to: SPOOL or SUBMIT for Sequential Files
+
+ Specifies the maximum CPU time a SPOOLed or SUBMITted job can consume
+ before VMS terminates it. The integer expression supplies a time as a
+ number of 10 millisecond increments. CPULIMIT=0 requests unlimited CPU
+ time. This is analogous to the /CPUTIME qualifier on the DCL SUBMIT
+ command.
+
+ By default, the account and/or the queue control the maximum CPU time.
+
+4 DELETE
+ DELETE Applies to: Sequential Files, and VMS Mailboxes
+
+ Instructs GT.M to delete the mailbox or the current version of the disk
+ file after GT.M closes it. When the file is SPOOLed or SUBMITted, VMS
+ deletes the file after processing it.
+
+4 DOUBLESPACE
+ [NO]DOUBLESPACE Applies to: Sequential Files when used with SPOOL
+
+ Enables or disables double spacing of a SPOOLed file.
+
+ By default, the spooler prints files single spaced.
+
+4 EXCEPTION
+ EXCEPTION=expr Applies to: All devices
+
+ Defines an error handler for an I/O device. The expression must contain
+ a fragment of GT.M code (for example, GOTO ERRFILE) that GT.M XECUTEs
+ when the driver for the device detects an error, or an entryref to
+ which GT.M transfers control, as appropriate for the current
+ gtm_ztrap_form.
+
+ For more information on error handling, refer to the "Error Processing"
+ chapter in GT.M Programmer's Guide.
+
+4 FIRSTPAGE
+ FIRSTPAGE=intexpr Applies to: Sequential Files when used with SPOOL
+
+ Specifies the page number at which to start printing a SPOOLed file.
+ This is analogous to the first argument to the /PAGE qualifier on the
+ DCL PRINT command.
+
+ By default, the spooler starts printing at the beginning of a file.
+
+4 FLAG
+ [NO]FLAG Applies to: Sequential Files when used with SPOOL
+
+ Enables or disables printing a flag page before a SPOOLed file.
+
+ By default, the queue controls whether to print a flag page.
+
+4 FORM
+ FORM=intexpr Applies to: Sequential Files when used with SPOOL
+
+ Specifies a predefined form number to use while printing a SPOOLed
+ file.
+
+ The VMS system manager sets up queue FORMs. VMS gives FORMs both names
+ and numbers. However, the FORM deviceparameter only accepts numeric
+ identifications.
+
+ By default, the spooler prints files on the default form.
+
+4 GROUP
+ GROUP=expr Applies to: Sequential Disk Files
+
+ Specifies UIC-based security on RMS files. The expression is a mask
+ evaluating to null or to any combination of the letters REWD,
+ indicating respectively READ, EXECUTE, WRITE, and DELETE access. When
+ any one of these deviceparameters appears on a CLOSE, any user category
+ (OWNER, SYSTEM, WORLD), that is not explicitly specified remains
+ unchanged.
+
+ In order to modify file security, the user who issues the CLOSE must
+ have control access.
+
+ By default, CLOSE does not modify the UIC-based security on an existing
+ file.
+
+4 HEADER
+ [NO]HEADER Applies to: Sequential Files when used with SPOOL
+
+ Enables or disables printing a VMS header on the top of each page of a
+ SPOOLed file. This header includes the file specification and the time
+ and date. When using this header, ensure that the form size is 2 lines
+ larger than the page size of material in the file. Otherwise, printing
+ intended for a single page may overflow onto 2 pages.
+
+ By default, the spooler does not print a VMS header.
+
+4 HOLD
+ [NO]HOLD Applies to: SPOOL or SUBMIT for Sequential Files
+
+ Enables or disables holding the SPOOLed or SUBMITted job for release by
+ an operator.
+
+ By default, The VMS job controller starts processing the SUBMITted or
+ SPOOLed file as soon as system resources permit.
+
+4 LASTPAGE
+ LASTPAGE=intexpr Applies to: Sequential Files when used with SPOOL
+
+ Specifies the page number at which to stop printing a SPOOLed file.
+ This is analogous to the second argument to the /PAGE qualifier on the
+ DCL PRINT command.
+
+ By default, the spooler stops printing at the end-of-file.
+
+4 LOGFILE
+ LOGFILE=expr Applies to: Sequential Files when used with SUBMIT
+
+ Specifies the file into which a SUBMITted job should log its output.
+ The expression supplies an RMS file specification. This is analogous to
+ the /LOG_FILE qualifier on the DCL SUBMIT command.
+
+ By default, the VMS job controller logs a job into the login directory
+ of the account under which the job runs, with a file name constructed
+ from the job name and a file type of .LOG.
+
+4 LOGQUEUE
+ LOGQUEUE=expr Applies to: Sequential Files when used with SUBMIT
+
+ Specifies the queue used to print the log file of a SUBMITted job. The
+ expression supplies a queue name.
+
+ By default, the VMS job controller uses the SYS$PRINT queue.
+
+4 LOWERCASE
+ [NO]LOWERCASE Applies to: Sequential Files when used with SPOOL
+
+ Specifies whether a SPOOLed file prints on a queue supporting a device
+ that can print lower-case characters.
+
+ By default, CLOSE does not restrict printing based on this capability.
+
+4 NAME
+ NAME=expr Applies to: SPOOL or SUBMIT for Sequential Files
+
+ Specifies the name of a SPOOLed or SUBMITted job. The expression
+ supplies a name from one to 39 characters in length.
+
+ By default, a job takes the name of the SPOOLed or SUBMITted file.
+
+4 NOTE
+ NOTE=expr Applies to: Sequential Files when used with SPOOL
+
+ Specifies a note to print on the flag pages of a SPOOLed job. The
+ expression specifies the text of a note. NOTE performs no function if
+ neither the job nor the queue specify BURST and/or FLAG and/or TRAILER.
+
+ By default, the spooler does not print the note on flag pages.
+
+4 NOTIFY
+ [NO]NOTIFY Applies to: SPOOL or SUBMIT for Sequential Files
+
+ Specifies whether the process receives notification when a SPOOLed or
+ SUBMITted job completes, in the form of a broadcast mailbox message.
+
+ By default, when a job completes, the VMS job controller does not
+ notify the other active processes belonging to the same user as the
+ job.
+
+4 OPERATOR
+ OPERATOR=expr Applies to: SPOOL or SUBMIT for Sequential Files
+
+ Pauses the queue and notifies the operator to take action when a
+ SPOOLed or SUBMITted job is ready for execution. The expression
+ contains a message, which the VMS job controller sends to the operator
+ console(s).
+
+ By default, The VMS job controller does not require operator action
+ before a SPOOLed job prints or a SUBMITted job runs.
+
+4 OWNER
+ OWNER=expr Applies to: Sequential Disk Files
+
+ Specifies UIC-based security on RMS files. The expression is a mask
+ evaluating to null or to any combination of the letters REWD,
+ indicating respectively READ, EXECUTE, WRITE, and DELETE access. When
+ any one of these deviceparameters appears on a CLOSE, any user category
+ (GROUP, SYSTEM, WORLD), that is not explicitly specified remains
+ unchanged.
+
+ In order to modify file security, the user who issues the CLOSE must
+ have control access.
+
+ By default, CLOSE does not modify the UIC-based security on an existing
+ file.
+
+4 P1_to_P8
+ P1=expr to P8=expr Applies to: SPOOL or SUBMIT for Sequential Files
+
+ Specifies the parameters supplied to a SPOOLed or SUBMITted job. Each
+ expression supplies a parameter value. The CLOSE must specify each
+ parameter with a separate Pn deviceparameter. VMS assigns every
+ parameter value to a DCL symbol of the same (Pn) name in the job. This
+ is analogous to the /PARAMETER qualifier on the DCL PRINT and SUBMIT
+ commands.
+
+ By default, P1 to P8 have null values.
+
+ Example:
+
+ CLOSE sd:(SUBMIT:P1=p1:P2=5:P3="INIT")
+
+ This CLOSEs the device, and if the device is an RMS file, SUBMITs it to
+ batch with three parameters that are respectively: the value of the
+ variable p1 , the integer 5 and the string "INIT".
+
+4 PAGINATE
+ [NO]PAGINATE Applies to: Sequential Files when used with SPOOL
+
+ Instructs the spooler whether to insert appropriate carriage control
+ characters whenever output exceeds the form length. This is analogous
+ to the /[NO]FEED qualifier on the DCL PRINT command.
+
+ By default, the spooler adds its own pagination.
+
+4 PASSALL
+ [NO]PASSALL Applies to: Sequential Files when used with SPOOL
+
+ Enables or disables spooler suppression of non-graphic character
+ sequences in a SPOOLed file. Non-graphic characters should be PASSALLed
+ when they control printer behavior.
+
+ By default, the spooler does not send non-graphic sequences to the
+ printer.
+
+4 PRINT
+ [NO]PRINT Applies to: Sequential Files when used with SUBMIT
+
+ Specifies whether to print and delete, or not print and retain, the log
+ file generated by a SUBMITted job. This is analogous to a combination
+ of the /KEEP and /PRINT qualifiers on the DCL SUBMIT command.
+
+ By default, the VMS job controller prints and deletes the log file.
+
+4 PRIORITY
+ PRIORITY=intexpr Applies to: SPOOL or SUBMIT for Sequential Files
+
+ Specifies the priority of a SPOOLed or SUBMITted job. Attempts to raise
+ priority above a SYSGEN established maximum (MAXQUEPRI) only succeed if
+ the user has appropriate VMS privileges (OPER or ALTPRI).
+
+ By default, a SYSGEN parameter (DEFQUEPRI) and the priority of the
+ submitting process control the priority of a SPOOLed or SUBMITted job.
+
+4 QUEUE
+ QUEUE=expr Applies to: SPOOL or SUBMIT for Sequential Files
+
+ Specifies the queue for a SPOOLed or SUBMITted job. The expression
+ supplies a queue name.
+
+ By default, SPOOLed jobs go to SYS$PRINT and SUBMITted jobs go to
+ SYS$BATCH.
+
+4 REMOTE
+ REMOTE=expr Applies to: SPOOL or SUBMIT for Sequential Files
+
+ Specifies the node on the network where a SPOOLed or SUBMITted job
+ executes. The expression supplies the node name of the target system.
+ Within a VMSCluster, a shared queue management system may direct
+ SPOOLed or SUBMITted jobs to other members of the cluster without use
+ of the REMOTE parameter.
+
+ By default, the VMS job controller executes a job on the system from
+ which it is SPOOLed or SUBMITted. However, by default, in a VMSCluster
+ with a shared queue management system, the VMS job controller executes
+ a job on the cluster member with the largest current supply of required
+ resources.
+
+4 RENAME
+ RENAME=expr Applies to: Sequential Disk Files
+
+ Changes the file name to the name contained in the argument string.
+ When the expression omits part of the file specification, GT.M
+ constructs the full file specification by applying the defaults
+ discussed in the section on device specifications.
+
+ If the process has sufficient access permissions, it may use RENAME to
+ specify a different directory as well as file name, type and version.
+ RENAME cannot move a file to a different device.
+
+4 RESTART
+ [NO]RESTART Applies to: SPOOL or SUBMIT for Sequential Files
+
+ Enables or disables automatic restart on reboot after a system failure
+ for a SPOOLed or SUBMITted job.
+
+ By default, the VMS job controller requires operator intervention to
+ restart jobs running at the time of a system failure.
+
+4 SETUP
+ SETUP=expr Applies to: SPOOL or SUBMIT for Sequential Files
+
+ Specifies one or more setup modules to copy to the printing device
+ before the contents of a SPOOLed file. The expression supplies a list
+ of setup module names separated by commas (,). VMS stores setup modules
+ in a device control library and the spooler uses them to initialize or
+ download programmable printers.
+
+ By default, the spooler sends no setup modules to the printer ahead of
+ a SPOOLed file.
+
+4 SOCKET
+ SOCKET=expr Applies to: Socket Device
+
+ The socket specified in expr is closed. Specifying a socket that has
+ not been previously OPENed generates an error. If no SOCKET
+ deviceparameter is specified on a CLOSE for a socket device, the socket
+ device and all sockets associated with it are closed.
+
+4 SPOOL
+ SPOOL Applies to: Sequential Disk Files
+
+ Sends the sequential file to the default print queue SYS$PRINT. The
+ deviceparameter QUEUE provides a means to specify different print
+ queues.
+
+4 SUBMIT
+ SUBMIT Applies to: Sequential Disk Files
+
+ Submits the named sequential file to the default batch queue SYS$BATCH.
+ The deviceparameter QUEUE provides a means to specify different print
+ queues.
+
+ Specifies UIC-based security on RMS files. The expression is a mask
+ evaluating to null or to any combination of the letters REWD,
+ indicating respectively READ, EXECUTE, WRITE, and DELETE access. When
+ any one of these deviceparameters appears on a CLOSE, any user category
+ that is not explicitly specified remains unchanged.
+
+4 SYSTEM
+ SYSTEM=expr Applies to: Sequential Disk Files
+
+ Specifies UIC-based security on RMS files. The expression is a mask
+ evaluating to null or to any combination of the letters REWD,
+ indicating respectively READ, EXECUTE, WRITE, and DELETE access. When
+ any one of these deviceparameters appears on an OPEN of a new file, any
+ user category that is not explicitly specified is given the default
+ mask. When any one of these deviceparameters appears on an OPEN of an
+ existing file, any user category (OWNER, GROUP, WORLD), that is not
+ explicitly specified remains unchanged.
+
+ In order to modify file security, the user who issues the OPEN or CLOSE
+ must have control access ownership.
+
+ By default, CLOSE does not modify the UIC-based security on an existing
+ file.
+
+4 TRAILER
+ [NO]TRAILER Applies to: Sequential Files when used with SPOOL
+
+ Enables and disables printing a flag page after a SPOOLed file.
+
+ By default, the queue controls printing of trailing flag pages.
+
+4 USER
+ USER=expr Applies to: SPOOL or SUBMIT for Sequential Files
+
+ Specifies the user name under which a SPOOLed or SUBMITted job runs.
+ The expression supplies a currently valid one to 12 character user
+ name. USER requires the VMS CMKRNL privilege.
+
+ By default, the VMS job controller runs the job under the account of
+ the process by which it was SPOOLed or SUBMITted.
+
+4 WORLD
+ WORLD=expr Applies to: Sequential Disk Files
+
+ Specifies UIC-based security on RMS files. The expression is a mask
+ evaluating to null or to any combination of the letters REWD,
+ indicating respectively READ, EXECUTE, WRITE, and DELETE access. When
+ any one of these deviceparameters appears on a CLOSE, any user category
+ (OWNER, GROUP, SYSTEM), that is not explicitly specified remains
+ unchanged.
+
+ In order to modify file security, the user who issues the CLOSE must
+ have control access.
+
+ By default, CLOSE and CLOSE do not modify the UIC-based security on an
+ existing file. Unless otherwise specified, when CLOSE creates a new
+ file, it establishes security using standard defaulting rules.
+
+ In order to modify file security, the user who issues the CLOSE must
+ have control access.
+
+ By default, CLOSE does not modify the UIC-based security on an existing
+ file.
+
+1 M_Utility_Rtns
+ M Utility Routines
+
+ GT.M provides library utilities to perform frequently used tasks, and
+ to access frequently used information. Most of the utilities are for
+ GT.M programmers, but some provide tools for system administration and
+ operation.
+
+ The GT.M utilities fall into the following general categories:
+
+ o Date and time utilities
+
+ o Conversion utilities
+
+ o Mathematic utilities
+
+ o Global utilities
+
+ o Routine utilities
+
+ o Internationalization utilities
+
+ o System Management utilities
+
+ The GT.M distribution includes the source files for these utilities.
+ The default installation compiles them to produce object modules in the
+ GTM$DIST distribution library.
+
+ The default installation also defines the logical name GTM$ROUTINES to
+ include GTM$DIST so the $ZROUTINES search list gives GT.M users access
+ to both the source and object files. If you cannot locate the
+ utilities, consult your system manager.
+
+ You may wish to examine the utilities and include some of them in your
+ programs if the programs access the function frequently or you may want
+ to modify the utilities to better fit your particular needs. If you
+ modify a utility, store your copy in a directory that precedes GTM$DIST
+ in the search list $ZROUTINES to prevent a new release of GT.M from
+ overlaying your copy.
+
+2 Using_Util
+ Using the Utilities
+
+ You can either use a utility in Direct Mode or include it in a source
+ application program with one or more of the following formats.
+ Italicized items are to be supplied by the user:
+
+ o DO ^%UTILITYNAME
+
+ o DO LABEL^%UTILITYNAME
+
+ o $$FUNC^%UTILITYNAME[(para1,...)]
+
+ Many utilities contain labels that invoke variations of the basic
+ utility functionality. Some also provide the label FUNC to invoke an
+ extrinsic function with optional or required parameters.
+
+ GT.M passes input to non-extrinsic forms of the utilities interactively
+ or by using "input" variables. GT.M passes output from non-extrinsic
+ forms of the utilities using "output" variables. For extrinsic entry
+ points, the utilities receive input as parameters and pass output as
+ the returned result. For other entry points, GT.M uses predefined
+ "input" and "output" variables to pass information. Some utilities
+ interactively request user inputs and display their results. Each
+ utility is described individually in this chapter where appropriate
+ labels, input, and output variables are identified.
+
+ By convention, the utilities use upper-case variables for external
+ input and output. Since M is case-sensitive, when an invocation uses a
+ lower-case or misspelled variable name, the routine does not output the
+ expected information. Instead it supplies a default value, if one
+ exists, or produces an error message.
+
+ Example:
+
+
+ GTM>SET %ds="11/22/2002"
+
+ GTM>DO INT^%DATE
+
+ GTM>ZWRITE
+
+ %DN=59123
+
+ %ds="11/22/2002"
+
+ This example sets the lowercase variable %ds to the date 11/22/2002.
+ Since the %DATE routine expects the input to be provided in the
+ uppercase %DS variable, it returns a default value in the output
+ variable $DN. The default is the $HOROLOG format of the current date,
+ which is 11/15/2002 in the example.
+
+2 Date_Time_Util
+ Date and Time Utilities
+
+ The date and time utilities are:
+
+ %D Displays the current date using the [d]d-mmm-[yy]yy format.
+ %DATE Converts input date to the $HOROLOG format.
+ %H Converts date and time to and from $HOROLOG format.
+ %T Displays the current time in [h]h:mm AM/PM format.
+ %TI Converts time to $HOROLOG format.
+ %TO Converts the current time from $HOROLOG format to [h]h:mm AM/PM
+ format.
+ For details and examples, refer to the GT.M Programmer's Guide.
+
+ The "%" sign has been removed from the topic headings below,
+ intentionally.
+
+3 D_
+ %D
+
+
+ The %D utility displays the current date using the [d]d-mmm-[yy]yy
+ format. If a routine uses this function repetitively, put the utility
+ code directly into the M program.
+
+4 Util_Labels
+ Utility Labels
+
+ INT Sets variable %DAT to current date.
+ FUNC[()] Invokes an extrinsic function returning today's date.
+4 Output_Vars
+ Output Variables
+
+ %DAT Contains the current date.
+4 Ex_of_D
+ Examples of %D
+
+ For the following examples, $ZDATEFORM is assumed to be one (1).
+
+ Example:
+
+
+ GTM>DO ^%D
+
+ 22-NOV-2002
+ This example invokes %D in Direct Mode. Then %D displays the current
+ date.
+
+ Example:
+
+
+ GTM>DO INT^%D
+
+ GTM>ZWRITE
+
+ %DAT="22-NOV-2002"
+
+ This example invokes %D with the label INT (INT^%D). The variable %DAT
+ contains the current date. ZWRITE displays the contents of the output
+ variable.
+
+ Example:
+
+
+ GTM>WRITE $$FUNC^%D
+
+ 22-NOV-2002
+ This example invokes %D as an extrinsic function with the label FUNC.
+ $$FUNC^%D returns today's date.
+
+3 DATE
+ %DATE
+
+
+ The %DATE utility converts an input date to the $HOROLOG format. The
+ $HOROLOG format represents time as the number of days since December
+ 31, 1840. The routine has entry points for interactive or
+ non-interactive use.
+
+4 Util_Labels
+ Utility Labels
+
+ INT Converts %DS input non-interactively, if defined, otherwise the
+ current date.
+ FUNC(t) Invokes an extrinsic function returning $HOROLOG format of
+ the argument.
+4 Prompts
+ Prompts
+
+ Date: Interactively requests a date for conversion to $HOROLOG
+ format.
+4 Input_Vars
+ Input Variables
+
+ %DS Contains input date; refer to %DATE Input Formats table.
+4 Output_Vars
+ Output Variables
+
+ %DN Contains output date in $HOROLOG format
+4 Ex_of_DATE
+ Examples of %DATE
+
+ Example:
+
+
+ GTM>DO ^%DATE
+
+ Date:
+
+ GTM>ZWRITE
+
+ %DN=59105
+
+ This example invokes %DATE at the GTM> prompt. After pressing <RETURN>
+ at the Date: prompt, %DATE converts today's date (for example,
+ 10/28/2002) to the $HOROLOG format. ZWRITE displays the contents of the
+ output variable.
+
+ Example:
+
+
+ GTM>DO INT^%DATE
+
+ GTM>ZWRITE
+
+ %DN=59105
+
+ This example invokes INT^%DATE, which converts the current date
+ non-interactively into $HOROLOG format. ZWRITE displays the contents of
+ the output variable.
+
+ Example:
+
+
+ GTM>SET %DS="10/20/2002"
+
+ GTM>DO INT^%DATE
+
+ GTM>ZWRITE
+
+ %DN=59097
+
+ %DS="10/20/2002"
+
+ This example sets the input variable %DS prior to invoking INT^%DATE,
+ which converts that date non-interactively to $HOROLOG format.
+
+ Example:
+
+
+ GTM>WRITE $$FUNC^%DATE("10/20/2002")
+
+ 59097
+ This example invokes %DATE with the label FUNC as an extrinsic function
+ to convert an input date to $HOROLOG. If the invocation does not supply
+ a date for $$FUNC^%DATE, FUNC converts the current date.
+
+ Example:
+
+
+ GTM>WRITE $ZDATEFORM
+
+ 1975
+ GTM>WRITE $$FUNC^%DATE("10/20/80")
+
+ 51062
+ GTM>WRITE $ZDATE(51062)
+
+ 10/20/1980
+ GTM>WRITE $$FUNC^%DATE("10/20/10")
+
+ 62019
+ GTM>WRITE $ZDATE(62019)
+
+ 10/20/2010
+ This example shows the use of a year limit in $ZDATEFORM. Two digit
+ years are interpreted to be in the interval (1975, 2074) since
+ $ZDATEFORM is 1975; the input year "80" is interpreted as the year
+ "1980" and "10" is interpreted as the year "2010". The example invokes
+ FUNC^%DATE to convert the input date to $HOROLOG format. $ZDATE() is
+ used to convert the $HOROLOG format date to mm/dd/yyyy format.
+
+3 H
+ %H
+
+
+ The %H utility converts date and time to and from $HOROLOG format.
+
+4 Util_Labels
+ Utility Labels
+
+ %CDS Converts %DT $HOROLOG input date to mm/dd/yyyy format.
+ %CTS Converts %TM $HOROLOG input time to external format.
+ %CDN Converts %DT input date to $HOROLOG format.
+ %CTN Converts %TM input time to $HOROLOG format.
+ CDS(dt) Extrinsic entry that converts the $HOROLOG argument to
+ external date format.
+ CTS(tm) Extrinsic entry that converts the $HOROLOG argument to
+ external time format.
+ CDN(dt) Extrinsic entry that converts the argument to $HOROLOG
+ format.
+ CTN(tm) Extrinsic entry that converts the argument to $HOROLOG
+ format.
+4 Input_Vars
+ Input Variables
+
+ %DT Contains input date in either $HOROLOG or mm/dd/[yy]yy format,
+ depending on the format expected by the utility entry point.
+ %TM Contains input time in either $HOROLOG or [h]h:mm:ss format,
+ depending on the format expected by the utility entry point.
+4 Output_Vars
+ Output Variables
+
+ %DAT Contains converted output date,
+ %TIM Contains converted output time,
+4 Ex_of_H
+ Examples of %H
+
+ Example:
+
+
+ GTM>SET %DT=+$H DO %CDS^%H
+
+ GTM>ZWRITE
+
+ %DAT="10/20/2002"
+
+ %DT=59097
+
+ This example sets %DT to the current date in $HOROLOG format and
+ converts it to mm/dd/yyyy format by invoking %H at the label %CDS. %H
+ returns the converted date in the variable %DAT. ZWRITE displays the
+ contents of the variables.
+
+ Example:
+
+
+ GTM>SET %DT="10/20/2002" DO %CDN^%H
+
+ GTM>ZWRITE
+
+ %DAT=59097
+
+ %DT="10/20/2002"
+
+ This example sets the variable %DT to a date in mm/dd/yyyy format and
+ invokes %H at the label %CDN. %H returns the converted date in the
+ variable %DAT. ZWRITE displays the contents of the variables.
+
+ Example:
+
+
+ GTM>SET %TM=$P($H,",",2) DO %CTS^%H
+
+ GTM>ZWRITE
+
+ %TIM="17:41:18"
+
+ %TM=63678
+
+ This example sets the variable %TM to the current time in $HOROLOG
+ format using a $PIECE() function to return only those digits of the
+ $HOROLOG string that represent the time. The example then invokes %H at
+ the label %CTS. %H returns the converted time in the variable %TIM.
+ ZWRITE displays the contents of the variables.
+
+ Example:
+
+
+ GTM>SET %TM="17:41:18" DO %CTN^%H
+
+ GTM>ZWRITE
+
+ %TIM=63678
+
+ %TM="17:41:18"
+
+ This example sets the variable %TM to a time in hh:mm:ss format, and
+ invokes %H at the label %CTN. %H returns the converted time in the
+ variable %TIM. ZWRITE displays the contents of the variables.
+
+ Example:
+
+
+ GTM>WRITE $$CDS^%H(59130)
+
+ 11/22/2002
+ This invokes CDS^%H as an extrinsic function to convert the external
+ argument to external date format.
+
+ Example:
+
+
+ GTM>WRITE $ZDATEFORM
+
+ 1980
+ GTM>WRITE $$CDN^%H("10/20/02")
+
+ 59097
+ GTM>WRITE $ZDATE(59097)
+
+ 10/20/2002
+ GTM>WRITE $$CDN^%H("10/20/92")
+
+ 55445
+ GTM>WRITE $ZDATE(55445)
+
+ 10/20/1992
+ This example shows the use of a year limit in $ZDATEFORM. Two digit
+ years are interpreted to be in the interval of 1980 - 2079; since
+ $ZDATEFORM is 1980, the input year "02" is interpreted as "2002" and
+ "92" is interpreted as "1992". This example invokes CDN^%H to convert
+ the argument in mm/dd/yy format to $HOROLOG format. $ZDATE() is used to
+ conver the $HOROLOG format date to mm/dd/yyyy format.
+
+3 T_
+ %T
+
+
+ The %T utility displays the current time in [h]h:mm AM/PM. If a routine
+ uses this function repetitively, put the utility code directly into the
+ M program.
+
+4 Util_Labels
+ Utility Labels
+
+ INT Sets %TIM to current time in [h]h:mm AM/PM format.
+ FUNC[()] Invokes an extrinsic function returning the current time.
+4 Output_Vars
+ Output Variables
+
+ %TIM Contains current time in [h]h:mm AM/PM format.
+
+
+4 Ex_of_T
+ Examples of %T
+
+ Example:
+
+
+ GTM>DO ^%T
+
+ 8:30 AM
+ This example invokes %T, which prints the current time and does not set
+ %TIM.
+
+ Example:
+
+
+ GTM>DO INT^%T
+
+ GTM>ZWRITE
+
+ %TIM="8:30 AM"
+
+ This example invokes INT^%T, which sets the variable %TIM to the
+ current time. ZWRITE displays the contents of the variable.
+
+ Example:
+
+
+ GTM>WRITE $$FUNC^%T
+
+ 8:30 AM
+ This example invokes FUNC as an extrinsic function, which returns the
+ current time.
+
+3 TI
+ %TI
+
+
+ The %TI utility converts time to $HOROLOG format. The $HOROLOG format
+ represents time as the number of seconds since midnight. %TI returns
+ the converted time in the variable %TN. The routine has entry points
+ for interactive or non-interactive use.
+
+4 Util_Labels
+ Utility Labels
+
+ INT Non-interactively converts %TS to $HOROLOG format; if %TS is
+ not defined, then current time is converted.
+ FUNC[(ts)] Invokes an extrinsic function returning $HOROLOG format
+ of the argument, or if no argument, the $HOROLOG format of the
+ current time.
+4 Prompts
+ Prompts
+
+ Time: Requests time in [h]h:mm:ss format to convert to $HOROLOG
+ format.
+4 Input_Vars
+ Input Variables
+
+ %TS Contains input time.
+4 Output_Vars
+ Output Variables
+
+ %TN Contains output time in $HOROLOG format
+4 Ex_of_TI
+ Examples of %TI
+
+ Example:
+
+
+ GTM>DO ^%TI
+
+ Time: 4:02 PM
+
+ GTM>ZWRITE
+
+ %TN=57720
+
+ This example invokes %TI, which prompts for an input time. Press
+ <RETURN> to convert the current time. ZWRITE displays the contents of
+ the output variable.
+
+ Example:
+
+
+ GTM>ZWRITE
+
+ GTM>DO INT^%TI
+
+ GTM>ZWRITE
+
+ %TN=40954
+
+ This example invokes INT^%TI to convert the current time
+ non-interactively. ZWRITE displays the contents of the output variable
+ %TN.
+
+ Example:
+
+
+ GTM>SET %TS="8:30AM"
+
+ GTM>DO INT^%TI
+
+ GTM>ZWRITE
+
+ %TN=30600
+
+ %TS="8:30AM"
+
+ This example sets the variable %TS prior to invoking INT^%TI. %TI uses
+ %TS as the input time. ZWRITE displays the contents of the variables.
+
+ Example:
+
+
+ GTM>WRITE $$FUNC^%TI("8:30AM")
+
+ 30600
+ This example invokes %TI as an extrinsic function to convert the
+ supplied time to $HOROLOG format. If there is no argument (i.e.,
+ $$FUNC^%TI), %TI converts the current time.
+
+3 TO
+ %TO
+
+
+ The %TO utility converts the input time from $HOROLOG format to [h]h:mm
+ AM/PM format. Put the utility code directly into the M program if the
+ routine uses this function repetitively.
+
+4 Util_Labels
+ Utility Labels
+
+ INT Converts non-interactively %TS, or if %TS is not defined the
+ current time to [h]h:mm AM/PM format.
+4 Input_Vars
+ Input Variables
+
+ %TN Contains input time in $HOROLOG format.
+4 Output_Vars
+ Output Variables
+
+ %TS Contains output time in [h]h:mm AM/PM format.
+4 Ex_of_TO
+ Examples of %TO
+
+ Example:
+
+
+ GTM>DO INT^%TI,^%TO
+
+ GTM>ZWRITE
+
+ %TN=62074
+
+ %TS="5:14 PM"
+
+ This example invokes INT^%TI to set %TN to the current time and invokes
+ %TO to convert the time contained in %TN to the [h]h:mm AM/PM format.
+ %TO returns the converted time in the variable %TS. ZWRITE displays the
+ contents of the variables.
+
+2 Conversion_Util
+ Conversion Utilities
+
+ The conversion utilities are:
+
+ %DH Decimal to hexadecimal conversion.
+ %DO Decimal to octal conversion.
+ %HD Hexadecimal to decimal conversion.
+ %HO Hexadecimal to octal conversion.
+ %LCASE Converts a string to all lower case.
+ %OD Octal to decimal conversion.
+ %OH Octal to hexadecimal conversion.
+ %UCASE Converts a string to all upper case.
+ The conversion utilities can be invoked as extrinsic functions.
+
+ Some of these conversions may be performed by VMS run-time library
+ routines. If you need to use the numeric utilities as extrinsic
+ functions frequently, consider calling the VMS run-time library
+ routines using the GT.M $ZCALL function. Refer to the "Functions"
+ chapter in GT.M Programmer's Guide for further information on $ZCALL().
+
+
+ The "%" sign has been removed from the topic headings below,
+ intentionally.
+
+3 DH
+ %DH
+
+
+ The %DH utility converts numeric values from decimal to hexadecimal.
+ %DH defaults the length of its output to eight digits. However the
+ input variable %DL overrides the default and controls the length of the
+ output. The routine has entry points for interactive or non-interactive
+ use.
+
+4 Util_Labels
+ Utility Labels
+
+ INT Converts interactively entered decimal number to hexadecimal
+ number with the number of digits specified.
+ FUNC(d[,l]) Invokes %DH as an extrinsic function returning the
+ hexadecimal equivalent of the argument.
+4 Input_Vars
+ Input Variables
+
+ %DH As input, contains input decimal number.
+ %DL Specifies how many digits appear in the output, defaults to
+ eight.
+4 Prompts
+ Prompts
+
+ Decimal: Requests a decimal number for conversion to hexadecimal.
+ Digits: Requests the length of the output in digits; eight by
+ default.
+4 Output_Vars
+ Output Variables
+
+ %DH As output, contains the converted number in hexadecimal.
+4 Ex_of_DH
+ Examples of %DH
+
+ Example:
+
+
+ GTM>DO INT^%DH
+
+ Decimal: 12
+
+ Digits: 1
+
+ GTM>ZWRITE
+
+ %DH="C"
+
+ This example invokes %DH interactively with INT^%DH. %DH prompts for a
+ decimal number and output length, then returns the result in the
+ variable %DH. ZWRITE displays the contents of the variables.
+
+ Example:
+
+
+ GTM>SET %DH=12
+
+ GTM>DO ^%DH
+
+ GTM>ZWRITE
+
+ %DH="0000000C"
+
+ %DL=8
+
+ This example sets the read-write variable %DH to 12 and invokes %DH to
+ convert the number to a hexadecimal number. Because the number of
+ digits was not specified, %DH used the default of 8 digits. Set %DL to
+ specify the number of output digits.
+
+ Example:
+
+
+ GTM>WRITE $$FUNC^%DH(12,4)
+
+ 000C
+ This example invokes %DH as an extrinsic function using the FUNC label.
+ The first argument specifies the input decimal number and the optional,
+ second argument specifies the number of output digits. If the extrinsic
+ does not have a second argument, the length of the output defaults to
+ eight characters.
+
+3 DO
+ %DO
+
+
+ The %DO utility converts numeric values from decimal to octal. The
+ default length of its output is 12 digits. The value assigned to the
+ input variable %DL overrides the default and controls the length of the
+ output. The routine has entry points for interactive or non-interactive
+ use.
+
+4 Util_Labels
+ Utility Labels
+
+ INT Converts the specified decimal number to an octal number with
+ the specified number of digits, interactively.
+ FUNC(d[,ln]) Invokes %DO as an extrinsic function, returning the
+ octal equivalent of the argument.
+4 Prompts
+ Prompts
+
+ Decimal: Requests a decimal number for conversion to octal.
+ Digits: Requests the length of the output in digits; 12 by default.
+4 Input_Vars
+ Input Variables
+
+ %DO As input, contains input decimal number.
+ %DL Specifies the number of digits in the output, defaults to 12.
+4 Output_Vars
+ Output Variables
+
+ %DO As output, contains the converted number in octal.
+4 Ex_of_DO
+ Examples of %DO
+
+ Example:
+
+
+ GTM>DO INT^%DO
+
+ Decimal: 12
+
+ Digits: 4
+
+ GTM>ZWRITE
+
+ %DO="0014"
+
+ This example invokes %DO interactively with INT^%DO. %DO prompts for a
+ decimal number and an output length. If the output value of %DO has
+ leading zeros, the value is a string. ZWRITE displays the contents of
+ the variables.
+
+ Example:
+
+
+ GTM>SET %DO=12
+
+ GTM>DO ^%DO
+
+ GTM>ZWRITE
+
+ %DO="000000000014"
+
+ This example sets the read-write variable %DO to 12 and invokes %DO to
+ convert the number non-interactively. Because the number of digits was
+ not specified, %DO used the default of 12 digits. Set %DL to specify
+ the number of output digits. ZWRITE displays the contents of the
+ variables.
+
+ Example:
+
+
+ GTM>WRITE $$FUNC^%DO(12,7)
+
+ 0000014
+ This example invokes %DO as an extrinsic function with the label FUNC.
+ The first argument specifies the number to be converted and the
+ optional, second argument specifies the number of output digits. If the
+ second argument is not specified, %DO uses the default of 12 digits.
+
+3 HD
+ %HD
+
+
+ The %HD utility converts numeric values from hexadecimal to decimal.
+ %HD returns the decimal number in the read-write variable %HD. %HD
+ rejects input numbers beginning with a minus (-) sign and returns null
+ (""). The routine has entry points for interactive or non-interactive
+ use.
+
+4 Util_Labels
+ Utility Labels
+
+ INT Converts hexadecimal number entered interactively to decimal
+ number.
+ FUNC(h) Invokes %HD as an extrinsic function returning the decimal
+ equivalent of the argument.
+4 Prompts
+ Prompts
+
+ Hexadecimal: Requests a hexadecimal number for conversion to
+ decimal.
+4 Input_Vars
+ Input Variables
+
+ %HD As input, contains input hexadecimal number.
+4 Output_Vars
+ Output Variables
+
+ %HD As output, contains the converted number in decimal.
+4 Ex_of_HD
+ Examples of %HD
+
+ Example:
+
+
+ GTM>DO INT^%HD
+
+ Hexadecimal:E
+
+ GTM>ZWRITE
+
+ %HD=14
+
+ This example invokes %HD in interactive mode with INT^%HD. %HD prompts
+ for a hexadecimal number, then returns the converted number in the
+ variable %HD. ZWRITE displays the contents of the variable.
+
+ Example:
+
+
+ GTM>SET %HD="E"
+
+ GTM>DO ^%HD
+
+ GTM>ZWRITE
+
+ %HD=14
+
+ This example sets the read-write variable %HD to "E" and invokes %HD to
+ convert non-interactively the value of %HD to a decimal number. %HD
+ places the converted value into the read-write variable %HD.
+
+ Example:
+
+
+ GTM>WRITE $$FUNC^%HD("E")
+
+ 14
+ This example invokes %HD as an extrinsic function with the label FUNC
+ and writes the results.
+
+3 HO
+ %HO
+
+
+ The %HO utility converts numeric values from hexadecimal to octal. %HO
+ returns the octal number in the read-write variable %HO. %HO rejects
+ input numbers beginning with a minus (-) sign and returns null ("").
+ The routine has entry points for interactive or non-interactive use.
+
+4 Util_Labels
+ Utility Labels
+
+ INT Converts hexadecimal number entered interactively to octal
+ number.
+ FUNC(h) Invokes %HO as an extrinsic function returning the octal
+ equivalent of the argument.
+4 Prompts
+ Prompts
+
+ Hexadecimal: Requests a hexadecimal number for conversion to octal.
+4 Input_Vars
+ Input Variables
+
+ %HO As input, contains input hexadecimal number.
+4 Output_Vars
+ Output Variables
+
+ %HO As output, contains the converted number in octal.
+4 Ex_of_HO
+ Examples pf %HO
+
+ Example:
+
+
+ GTM>DO INT^%HO
+
+ Hexadecimal:C3
+
+ GTM>ZWRITE
+
+ %HO=303
+
+ This example invokes %HO in interactive mode using INT^%HO. %HO prompts
+ for a hexadecimal number that it converts to an octal number. ZWRITE
+ displays the contents of the variable.
+
+ Example:
+
+
+ GTM>SET %HO="C3"
+
+ GTM>DO ^%HO
+
+ GTM>ZWRITE
+
+ %HO=303
+
+ This example sets the read-write variable %HO to "C3" and invokes %HO
+ to convert the value of %HO non-interactively. ZWRITE displays the
+ contents of the variable.
+
+ Example:
+
+
+ GTM>WRITE $$FUNC^%HO("C3")
+
+ 303
+ This example invokes %HO as an extrinsic function with the FUNC label.
+
+3 LCASE
+ %LCASE
+
+
+ The %LCASE utility converts a string to all lower-case letters. If a
+ routine uses this function repetitively, put the utility code directly
+ into the M program.
+
+4 Util_Labels
+ Utility Labels
+
+ INT Converts interactively a string to lower-case.
+ FUNC(s) Invokes %LCASE as an extrinsic function returning the
+ lower-case form of the argument.
+4 Prompts
+ Prompts
+
+ String: Requests a string for conversion to lower case.
+4 Input_Vars
+ Input Variables
+
+ %S As input, contains string to be converted to lower case.
+4 Output_Vars
+ Output Variables
+
+ %S As output, contains the converted string in lower case.
+4 Ex_of_LCASE
+ Examples of %LCASE
+
+ Example:
+
+
+ GTM>DO INT^%LCASE
+
+ String: LABEL
+
+ Lower: label
+
+ This example invokes %LCASE in interactive mode using INT^%LCASE.
+ %LCASE prompts for a string that it converts to all lower case.
+
+ Example:
+
+
+ GTM>SET %S="Hello"
+
+ GTM>do ^%LCASE
+
+ GTM>zwrite
+
+ %S="hello"
+
+ This example sets the variable %S to the string "Hello" and invokes
+ %LCASE non-interactively to convert the string.
+
+ Example:
+
+
+ GTM>SET ^X="Hello"
+
+ GTM>WRITE $$FUNC^%LCASE(^X)
+
+ hello
+
+ This example sets the variable ^X to the string "Hello" and invokes
+ %LCASE as an extrinsic function that returns "hello" in lower case.
+
+3 OD
+ %OD
+
+
+ The %OD utility converts numeric values from octal to decimal. %OD
+ returns the decimal number in the read-write variable %OD. %OD rejects
+ input numbers beginning with a minus (-) sign and returns null ("").
+ The routine has entry points for interactive or non-interactive use.
+
+4 Util_Labels
+ Utility Labels
+
+ INT Converts octal number entered interactively to decimal number.
+ FUNC(oct) Invokes %OD as an extrinsic function returning the
+ decimal equivalent of the argument.
+4 Prompts
+ Prompts
+
+ Octal: Requests an octal number for conversion to decimal.
+4 Input_Vars
+ Input Variables
+
+ %OD As input, contains input octal number.
+4 Output_Vars
+ Output Variables
+
+ %OD As output, contains the converted number in decimal.
+4 Ex_of_OD
+ Examples of %OD
+
+ Example:
+
+
+ GTM>DO INT^%OD
+
+ Octal:14
+
+ GTM>ZWRITE
+
+ %OD=12
+
+ This example invokes INT^%OD to interactively convert the octal number
+ entered. %OD prompts for an octal number that it converts to a decimal.
+ %OD returns the converted value in the variable %OD.
+
+ Example:
+
+
+ GTM>SET %OD=14
+
+ GTM>DO ^%OD
+
+ GTM>ZWRITE
+
+ %OD=12
+
+ This example sets the read-write variable %OD to 14 and invokes %OD to
+ convert the number non-interactively. ZWRITE displays the contents of
+ the variables.
+
+ Example:
+
+
+ GTM>WRITE $$FUNC^%OD(14)
+
+ 12
+ This example invokes %OD as an extrinsic function with the FUNC label.
+ The argument specifies the number to be converted.
+
+3 OH
+ %OH
+
+
+ The %OH utility converts numeric values from octal to hexadecimal. %OH
+ returns the hexadecimal number in the read-write variable %OH. %OH
+ rejects input numbers beginning with a minus (-) sign. The routine has
+ entry points for interactive or non-interactive use. In interactive
+ mode, %OH rejects non-octal numbers with the following message, "Input
+ must be an octal number". In non-interactive mode, %OH returns a null
+ string ("") upon encountering a non-octal number.
+
+4 Util_Labels
+ Utility Labels
+
+ INT Converts interactively octal number entered to hexadecimal
+ number.
+ FUNC(oct) Invokes %OH as an extrinsic function returning the
+ hexadecimal equivalent of the argument.
+4 Prompts
+ Prompts
+
+ Octal: Requests an octal number for conversion to hexadecimal.
+4 Input_Vars
+ Input Variables
+
+ %OH As input, contains input octal number.
+4 Output_Vars
+ Output Variables
+
+ %OH As output, contains the converted number in hexadecimal.
+4 Ex_of_OH
+ Examples of %OH
+
+ Example:
+
+
+ GTM>DO INT^%OH
+
+ Octal:16
+
+ GTM>ZWRITE
+
+ %OH="E"
+
+ This example invokes %OH in interactive mode using INT^%OH. %OH prompts
+ for an octal number that it converts to a hexadecimal number. ZWRITE
+ displays the contents of the variable.
+
+ Example:
+
+
+ GTM>SET %OH=16
+
+ GTM>DO ^%OH
+
+ GTM>ZWRITE
+
+ %OH="E"
+
+ This example sets the read-write variable %OH to 16 and invokes %OH to
+ convert the value of %OH non-interactively. ZWRITE displays the
+ contents of the variable.
+
+ Example:
+
+
+ GTM>WRITE $$FUNC^%OH(16)
+
+ E
+
+ This example invokes %OH as an extrinsic function with the FUNC label.
+
+3 UCASE
+ %UCASE
+
+
+ The %UCASE utility converts a string to all upper-case letters. If a
+ routine uses this function repetitively, put the utility code directly
+ into the M program.
+
+4 Util_Labels
+ Utility Labels
+
+ INT Converts a string to upper case interactively.
+ FUNC(s) Invokes %UCASE as an extrinsic function, returning the
+ upper-case form of the argument.
+4 Prompts
+ Prompts
+
+ String: Requests a string for conversion to upper case.
+4 Input_Vars
+ Input Variables
+
+ %S As input, contains string to be converted to upper case.
+4 Output_Vars
+ Output Variables
+
+ %S As output, contains the converted string in upper case.
+4 Ex_of_UCASE
+ Examples of %UCASE
+
+ Example:
+
+
+ GTM>DO INT^%UCASE
+
+ String: test
+
+ Upper: TEST
+
+ This example invokes %UCASE in interactive mode using INT^%UCASE.
+ %UCASE prompts for a string that it converts to all upper case.
+
+ Example:
+
+
+ GTM>SET ^X="hello"
+
+ GTM>WRITE $$FUNC^%UCASE(^X)
+
+ HELLO
+
+ This example sets the variable X to the string "hello" and invokes
+ %UCASE as an extrinsic function that returns "HELLO" in upper case.
+
+2 Math_Util
+ Mathematic Utilities
+
+ The mathematic utilities are:
+
+ %EXP Raises one number to the power of another number.
+ %SQROOT Calculates the square root of a number.
+ The mathematic utilities can be invoked as extrinsic functions.
+
+ These mathematic routines may be performed by VMS run-time library
+ routines. If you often need to use the mathematic utilities as
+ extrinsic functions, consider calling the VMS run-time library
+ routines, using the GT.M $ZCALL function. For information on $ZCALL(),
+ refer to the "Functions" chapter in GT.M Programmer's Guide.
+
+ The "%" sign has been removed from the topic headings below,
+ intentionally.
+
+3 EXP
+ %EXP
+
+
+ The %EXP utility raises one number provided to the power of another
+ number provided. While this utility provides an interactive interface
+ for exponential calculations, most production code would perform inline
+ calculation with the "**" operator. The routine has entry points for
+ interactive or non-interactive use.
+
+4 Util_Labels
+ Utility Labels
+
+ INT Calculates a number to the power of another number
+ interactively.
+ FUNC(i,j) Invokes %EXP as an extrinsic function returning the first
+ argument raised to the power of the second argument.
+4 Prompts
+ Prompts
+
+ Power: Requests an exponent or power.
+ Number: Requests a base number to raise by the power.
+4 Input_Vars
+ Input Variables
+
+ %I As input, contains number to be raised to a power.
+ %J Contains exponential power by which to raise %I.
+4 Output_Vars
+ Output Variables
+
+ %I As output, contains the result of the exponential calculation.
+4 Ex_of_EXP
+ Examples of %EXP
+
+ Example:
+
+
+ GTM>DO INT^%EXP
+
+ Power: 3
+
+ Number: 12
+
+ 12 raised to 3 is 1728
+ This example invokes %EXP in interactive mode using INT^%EXP. %EXP
+ prompts for an exponent (power) and a base number.
+
+ Example:
+
+
+ GTM>SET %I=2,%J=9
+
+ GTM>DO ^%EXP
+
+ GTM>ZWRITE
+
+ %I=512
+
+ %J=9
+
+ This example sets the read-write variable %I to 2, variable %J to 9,
+ and invokes %EXP to calculate the result. ZWRITE displays the contents
+ of the variables. %I contains the result.
+
+ Example:
+
+
+ GTM>WRITE $$FUNC^%EXP(2,9)
+
+ 512
+ This example invokes %EXP as an extrinsic function with the label FUNC.
+
+
+3 SQROOT
+ %SQROOT
+
+
+ The %SQROOT utility calculates the square root of a number provided.
+ While this utility provides an interactive interface for taking square
+ roots, most production code would perform inline calculation by raising
+ a number to the .5 power (n**.5). The routine has entry points for
+ interactive or non-interactive use.
+
+4 Util_Labels
+ Utility Labels
+
+ INT Calculates the square root of a number interactively.
+ FUNC(s) Invokes %SQROOT as an extrinsic function returning the
+ square root of the argument.
+4 Prompts
+ Prompts
+
+ The square root of: Requests a number.
+4 Input_Vars
+ Input Variables
+
+ %X Contains the number for which to calculate the square root.
+4 Output_Vars
+ Output Variables
+
+ %Y Contains the square root of %X.
+4 Ex_of_SQROOT
+ Examples of %SQROOT
+
+ Example:
+
+
+ GTM>SET %X=81
+
+ GTM>DO ^%SQROOT
+
+ GTM>ZWRITE
+
+ %X=81
+
+ %Y=9
+
+ This example sets the variable %X to 81 and invokes %SQROOT to
+ calculate the square root non-interactively. ZWRITE displays the
+ contents of the variables.
+
+ Example:
+
+
+ GTM>DO INT^%SQROOT
+
+ The square root of: 81 is: 9
+
+ The square root of: <RETURN>
+
+ GTM>
+
+ This example invokes INT^%SQROOT interactively that prompts for a
+ number. The square root of the number appears on the same line. %SQROOT
+ then prompts for another number. Press <RETURN> to exit.
+
+ Example:
+
+
+ GTM>WRITE $$FUNC^%SQROOT(81)
+
+ 9
+ This example invokes %SQROOT as an extrinsic function with the label
+ FUNC.
+
+2 Glob_Util
+ Global Utilities
+
+ The Global utilities are:
+
+ %G Displays global variables and their values.
+ %GC Copies a global or global sub-tree.
+ %GCE Replaces a specified value or part of a value in a set of
+ variables.
+ %GD Displays existing globals in the current global directory
+ without displaying their values or descendants.
+ %GED Provides full-screen editing capabilities for global variables
+ and values.
+ %GI Loads global data from a sequential file into a GT.M database.
+ %GO Extracts global data from a GT.M database into a sequential
+ file.
+ %GSE Displays global variables and their values when the values
+ contain a specified string or number.
+ %GSEL Selects globals.
+ The "%" sign has been removed from the topic headings below,
+ intentionally.
+
+3 G_
+ %G
+
+
+ The %G utility displays names, descendants and values of globals
+ currently existing in the database. Use %G to examine global variables
+ and their values. Enter a question mark (?) at any prompt to display
+ help information.
+
+4 Prompts
+ Prompts
+
+ Output Device: <terminal>:
+ Requests a destination device; defaults to the principal device.
+ List ^ Requests the name, in ZWRITE format, of a global to display.
+4 Ex_of_G
+ Examples of %G
+
+ Example:
+
+
+ GTM>do ^%G
+
+ Output Device: <terminal>: <RETURN>
+
+ List ^C
+
+ ^C="CLASS"
+
+ ^C(1)="MARY"
+
+ ^C(1,2)="MATH"
+
+ ^C(1,2,1)=80
+
+ ^C(1,3)="BIO"
+
+ ^C(1,3,1)=90
+
+ ^C(2)="JOHN"
+
+ ^C(3)="PETER"
+
+ List ^ <RETURN>
+
+ GTM>
+
+ This example lists the nodes of global ^C. %G displays the global and
+ its descendants and values, if the node exists.
+
+ Example:
+
+
+ GTM>do ^%G
+
+ Output Device: <terminal>: <RETURN>
+
+ List ^C(1)
+
+ ^C(1)="MARY"
+
+ This example lists only the node entered and its value.
+
+ Example:
+
+
+ GTM>do ^%G
+
+ Output Device: <terminal>: <RETURN>
+
+ List ^C(1,*)
+
+ ^C(1)="MARY"
+
+ ^C(1,2)="MATH"
+
+ ^C(1,2,1)=80
+
+ ^C(1,3)="BIO"
+
+ ^C(1,3,1)=90
+
+ List ^ <RETURN>
+
+ GTM>
+
+ This example uses the asterisk (*) wildcard to list node ^C(1), its
+ descendants and values.
+
+ Example:
+
+
+ GTM>do ^%G
+
+ Output Device: <terminal>: <RETURN>
+
+ List ^?D
+
+ Global Directory
+
+ Global ^ <RETURN>
+
+ ^C ^D ^S ^Y ^a
+
+ Total of 5 globals.
+
+ List ^
+
+ GTM>
+
+ This example specifies "?D" as the global that invokes the %GD utility.
+ %GD displays existing globals in the current global directory without
+ displaying their values or descendants.
+
+3 GC_
+ %GC
+
+
+ The %GC utility copies values of globals from one global to another. It
+ is useful for testing and for moving misfiled data.
+
+4 Prompts
+ Prompts
+
+ Show copied nodes <Yes>?
+ Asks whether to display the "source nodes" on the principal device.
+ From global ^ Requests a global variable name from which to copy
+ variable and descendants.
+ To global ^ Request a global variable name to receive the copy.
+4 Ex_of_GC
+ Example:
+
+
+ GTM>do ^%GC
+
+ Global copy
+
+ Show copied nodes <Yes>? <RETURN>
+
+ From global ^b
+
+ To global ^g
+
+ ^g(1)=1
+
+ ^g(2)=2
+
+ ^g(3)=3
+
+ Total 3 nodes copied.
+
+ From global ^<RETURN>
+
+ GTM>
+
+ This example makes a copy of the nodes and values of global ^b to
+ global ^g.
+
+3 GCE
+ %GCE
+
+
+ The %GCE utility changes every occurrence of a string within the data
+ of selected global nodes to a replacement string. ^%GCE changes the
+ string in each place it occurs, even if it forms part of a longer
+ string. For example, changing the string 12 to 55 changes 312 to 355.
+
+4 Prompts
+ Prompts
+
+ Global ^ Requests (using %GSEL) the name(s) of the globals to
+ change; <RETURN> ends selection.
+ Old string: Requests an existing string to find.
+ New string: Requests the replacement string.
+ Show changed nodes <Yes>?
+ Asks whether to display the before and after versions of modified
+ nodes on the current device.
+ Output Device: <terminal>:
+ Requests a destination device; defaults to the principal device.
+4 Ex_of_GCE
+ Examples of %GCE
+
+ Example:
+
+
+ GTM>DO ^%GCE
+
+ Global Change Every occurrence
+
+ Global ^a:^b
+
+ ^a ^b
+
+ Current total of 2 globals.
+
+ Global ^ <RETURN>
+
+ Old String: hello
+
+ New String: good-bye
+
+ Show changed nodes <Yes>?: <RETURN>
+
+ Output Device: <terminal>: <RETURN>
+
+ ^a
+
+ No changes made in total 1 nodes.
+
+ ^b
+
+ ^b(10)
+
+ Was : hello Adam
+
+ Now : good-bye Adam
+
+ 1 changes made in total 25 nodes.
+ Global ^ <RETURN>
+
+ GTM>
+
+ This example searches a range of globals and its nodes for the old
+ string value entered. GT.M searches each global and displays the
+ changes and number of nodes changed and checked.
+
+ Example:
+
+
+ GTM>set ^b(12)=12
+
+ GTM>set ^b(122)=122
+
+ GTM>set ^b(30)=656
+
+ GTM>set ^b(45)=344
+
+ GTM>set ^b(1212)=012212
+
+ GTM>DO ^%GCE
+
+ Global Change Every occurrence
+
+ Global ^b
+
+ Current total of 1 global.
+
+ Global ^ <RETURN>
+
+ Old String: 12
+
+ New String: 35
+
+ Show changed nodes <Yes>?: <RETURN>
+
+ Output Device: <terminal>: <RETURN>
+
+ ^b(12)
+
+ Was : 12
+
+ Now : 35
+
+ ^b(122)
+
+ Was : 122
+
+ Now : 352
+
+ ^b(1212)
+
+ Was : 12212
+
+ Now : 35235
+
+ 5 changes made in total 5 nodes
+ Global ^ <RETURN>
+
+ GTM>DO ^%G
+
+ Output device: <terminal>: <RETURN>
+
+ List ^b
+
+ ^b(12)=35
+
+ ^b(30)=656
+
+ ^b(45)=344
+
+ ^b(122)=352
+
+ ^b(1212)=35235
+
+ This example shows that executing %GCE replaces all occurrences of "12"
+ in the data stored in the global ^b with "35" and displays the affected
+ nodes before and after the change. Then the %G demonstrates that "12"
+ as data was changed, while "12" in the subscripts remained untouched.
+
+3 GD
+ %GD
+
+
+ The %GD utility displays existing globals in the current global
+ directory without displaying their values or descendants.
+
+ %GD prompts for a global name and redisplays the name if that global
+ exists.
+
+ %GD allows the wildcard characters asterisk (*) and percent sign (%).
+ The wildcards carry their DCL meanings with one exception. %GD
+ interprets a percent sign (%) in the first position of a global name
+ literally.
+
+ A colon (:) between two globals specifies a range. %GD displays
+ existing globals within that range.
+
+ After each selection %GD reports the number of globals selected by the
+ input.
+
+ A question mark (?) entered at a prompt displays help information.
+ Pressing <RETURN> exits %GD.
+
+4 Prompts
+ Prompts
+
+ Global ^ Requests (using %GSEL) a global name with optional
+ wildcards or a range of names; <RETURN> terminates %GD.
+4 Ex_of_GD
+ Exampels of %GD
+
+ Example:
+
+
+ GTM>DO ^%GD
+
+ Global directory
+
+ Global ^k
+
+ ^k
+
+ Total of 1 global.
+
+ Global ^ <RETURN>
+
+ GTM>
+
+ This example verifies that ^k exists in the global directory.
+
+ Example:
+
+
+ GTM>DO ^%GD
+
+ Global directory
+
+ Global ^C:S
+
+ ^C ^D ^S
+
+ Total of 3 globals
+
+ Global ^ <RETURN>
+
+ GTM>
+
+ This example displays a range of globals that exist from ^C to ^S.
+
+ Example:
+
+
+ GTM>DO ^%GD Global directory
+
+ Global ^*
+
+ ^C ^D ^S ^Y ^a
+
+ Total of 5 globals
+
+ Global ^ <RETURN>
+
+ GTM>
+
+ The asterisk (*) wildcard at the Global ^ prompt displays all globals
+ in the global directory.
+
+3 GED
+ %GED
+
+
+ The %GED utility enables you to edit the globals in a full-screen
+ editor environment. %GED invokes your default TPU editor. When you
+ finish the edit, use <CTRL-Z> or an EXIT command to exit.
+
+4 Prompts
+ Prompts
+
+ Edit ^ Requests the name, in ZWRITE format, of a global to edit.
+ Only one global can be edited at a time with %GED, refer to GT.M
+ Programmer's Guide for descriptions of valid input for subscripts.
+
+4 Ex_of_GED
+ Examples of %GED
+
+ Example:
+
+
+ GTM>DO ^%GED
+
+ Edit ^b
+
+ Beginning screen:
+
+ ^b(1)="melons"
+
+ ^b(2)="oranges"
+
+ ^b(3)="bananas"
+
+<End of File>
+ Screen with a change to ^b(1), elimination of ^b(3), and two new
+ entries ^b(4) and ^b(5):
+
+ ^b(1)="apples"
+
+ ^b(2)="oranges"
+
+ ^b(4)=pears
+
+ ^b(5)="grapes"
+
+<End of File>
+
+ %GED responds:
+
+
+ Invalid syntax: b(4)=pears
+
+ return to continue:
+
+ After screen:
+
+ ^b(1)="apples"
+
+ ^b(2)="oranges"
+
+ ^b(4)="pears"
+
+ ^b(5)="grapes"
+
+<End of File>
+ %GED responds:
+
+
+ node : ^b
+
+ selected : 3
+
+ changed : 1
+
+ added : 2
+
+ killed : 1
+
+ Edit ^ <RETURN>
+
+ GTM>
+
+ This example shows the use of the full-screen editor to change, add,
+ and delete (kill) nodes. When you exit from the editor, %GED checks the
+ syntax and reports any problems. By pressing <RETURN>, return to the
+ full-screen editor to fix the error. At the end of the session, %GED
+ reports how many nodes were selected, changed, killed, and added.
+
+3 GI
+ %GI
+
+
+ %GI loads global variable names and their corresponding data values
+ into a GT.M database from a sequential file. %GI uses the global
+ directory to determine which database files to use. %GI may operate
+ concurrently with normal GT.M database access. However, a %GI does not
+ use M LOCKs and may produce application-level integrity problems if run
+ concurrently with many applications.
+
+ The %GI utility corresponds to MUPIP LOAD. The format of the input file
+ (GO or ZWRITE) is automatically detected.
+
+4 Prompts
+ Prompts
+
+ Enter input file:
+ Requests name of a file; file should be in standard Global Output
+ (GO) format or Zwrite (ZWR) format .
+ OK <Yes>?: Asks for confirmation.
+4 Ex_of_GI
+ Examples of %GI
+
+ Example:
+
+
+ GTM>DO ^%GI
+
+ Global Input Utility
+
+ Input device <terminal>: DATA.GBL
+
+ Saved from user's development area
+
+ GT.M 07-MAY-2002 14:14:09
+
+ OK <Yes>? <RETURN>
+
+ ^IB ^INFO
+
+ Restored 10 nodes in 2 globals
+
+ GTM>
+
+3 GO
+ %GO
+
+
+ %GO copies specified globals from the current database to a sequential
+ output file in either GO or ZWR format. Use %GO to back up specific
+ globals or when extracting data from the database for use by another
+ system. %GO uses the global directory to determine which database files
+ to use. %GO may operate concurrently with normal GT.M database access.
+ To ensure that a %GO reflects a consistent application state, suspend
+ database updates to all regions involved in the extract.
+
+ The %GO utility corresponds to MUPIP EXTRACT (FORMAT=GO or FORMAT=ZWR).
+
+4 Prompts
+ Prompts
+
+ Global ^ Requests (using %GSEL) the name(s) of the globals to
+ search; <RETURN> ends selection.
+ Header label: Requests text describing contents of extract file.
+ Output Format: GO or ZWR:
+ Requests the format to output the data. Defaults to ZWR.
+ Output Device: <terminal>:
+ Requests destination device, which may be any legal filename.
+4 Ex_of_GO
+ Examples of %GO
+
+ Example:
+
+
+ GTM>DO ^%GO
+
+ Global Output Utility
+
+ Global ^A
+
+ ^A
+
+ Current total of 1 global
+
+ Global ^<RETURN>
+
+ Header label: Revenues May, 2002
+
+ Output Format: GO or ZWR: ZWR
+
+ Output device: DEV$:[USER]OUT.GO
+
+ ^A
+
+ Total of 1 node in 1 global.
+
+ GTM>
+
+3 GSE_
+ %GSE
+
+
+ The %GSE utility finds occurrences of a string within the data values
+ for selected global nodes and displays the variable name and data on a
+ specified output device.
+
+4 Prompts
+ Prompts
+
+ Output Device: <terminal>:
+ Requests a destination device; defaults to the principal device.
+ Global ^ Requests (using %GSEL) the name(s) of the globals to
+ search; <RETURN> ends selection.
+ String: Requests a search string.
+4 Ex_of_GSE
+ Examples of %GSE
+
+ Example:
+
+
+ GTM>do ^%GSE
+
+ Global Search For Every Occurence
+
+ Output device: <terminal>: Test.dat
+
+ Global ^a <RETURN>
+
+ ^a
+
+ Current total of 1 global.
+
+ Global ^ <RETURN>
+
+ String: Hello
+
+ ^a
+
+ ^a(10) Hello Adam
+
+ Total 1 matches found in 25 nodes.
+
+ Global ^ <RETURN>
+
+ GTM>
+
+ This example searches global ^a for the string "Hello" and displays all
+ nodes that contain that string.
+
+3 GSEL
+ %GSEL
+
+
+ The %GSEL utility selects globals. %GSEL creates a variable %ZG that is
+ a local array of the selected globals. After each selection %GSEL
+ displays the number of globals in %ZG.
+
+ %GSEL accepts the wildcard characters asterisk (*), percent sign (%)
+ and question mark (?). The wildcards carry their DCL meanings, with one
+ exception. The wildcards question mark (?) and percent sign (%) lose
+ their meanings when in the first position of a global name. %GSEL
+ interprets a percent sign (%) in the first position of a global name
+ literally.
+
+ A colon (:) between two globals specifies a range.
+
+ A minus sign (-) or quotation mark (') preceding a global name removes
+ that global from the %ZG array. A question mark (?) provides online
+ help, and "?D" displays global names currently in the array.
+
+4 Util_Labels
+ Utility Labels
+
+ CALL Runs %GSEL without reinitializing %ZG.
+4 Output_Vars
+ Output Variables
+
+ %ZG Contains array of all globals selected.
+4 Prompts
+ Prompts
+
+ Global ^ Requests a global name with optional wildcards or a range
+ of names.
+4 Ex_of_GSEL
+ Examples of %GSEL
+
+ Example:
+
+
+ GTM>DO ^%GSEL
+
+ Global ^C
+
+ ^C
+
+ Current total of 1 global
+
+ Global ^*
+
+ ^S ^Y ^c ^class
+
+ Current total of 5 globals
+
+ Global ^-S
+
+ ^S
+
+ Current total of 4 globals
+
+ Global ^'Y
+
+ ^Y
+
+ Current total of 3 globals
+
+ Global ^?D
+
+ ^C ^c ^class
+
+ Current total of 3 globals
+
+ Global ^ <RETURN>
+
+ GTM>ZWRITE
+
+ %ZG=3
+
+ %ZG("^C")=""
+
+ %ZG("^c")=""
+
+ %ZG("^class")=""
+
+ GTM>
+
+ This example adds and subtracts globals from the list of selected
+ globals. "?D" displays all globals selected. ZWRITE displays the
+ contents of the %ZG array.
+
+ Example:
+
+
+ GTM>DO ^%GSEL
+
+ Global ^a
+
+ ^a
+
+ Current total of 1 global.
+
+ Global ^<RETURN>
+
+ GTM>ZWRITE
+
+ %ZG=1
+
+ %ZG("^a")=""
+
+ GTM>DO CALL^%GSEL
+
+ Global ^?d
+
+ ^a
+
+ Global ^iv
+
+ ^iv
+
+ Current total of 2 globals.
+
+ Global ^<RETURN>
+
+ GTM>ZWRITE
+
+ %ZG=2
+
+ %ZG("^a")=""
+
+ %ZG("^iv")=""
+
+ GTM>
+
+ This example uses CALL^%GSEL to add to an existing %ZG array of
+ selected globals.
+
+2 Rtn_Util
+ Routine Utilities
+
+ The routine utilities are:
+
+ %FL Lists the comment lines at the beginning of source programs.
+ %RCE Replaces every occurrence of a text string with another text
+ string in a routine or a list of routines.
+ %RD Lists routine names available through $ZROUTINES.
+ %RI Loads routines from RO file to *.M files in GT.M format.
+ %RO Writes M source code for one or more routines to a sequential
+ device such as a terminal, or a disk file.
+ %RSE Searches for every occurrence of a text string in a routine or
+ a list of routines.
+ %RSEL Selects M routines and places their directories and names in
+ a local array.
+ The "%" sign has been removed from the topic headings below,
+ intentionally.
+
+3 FL
+ %FL
+
+
+ The %FL utility lists the comment lines at the beginning of source
+ programs. %FL writes the routines in alphabetical order to the
+ specified device. If the output device is not the principal device, %FL
+ displays the name of each routine on the principal device as it writes
+ the routine to the output device.
+
+ %FL uses %RSEL to select routines. For more information, refer to the
+ section on %RSEL in this chapter.
+
+4 Prompts
+ Prompts
+
+ Routine: Requests the name(s) of the routines (using %RSEL);
+ <RETURN> ends the selection.
+ Output Device: <terminal>:
+ Requests a destination device; defaults to the principal device.
+4 Ex_of_FL
+ Examples of %FL
+
+ Example:
+
+
+ GTM>DO ^%FL
+
+ First Line Lister
+
+ Routine: %D
+
+ %D
+
+ Current total of 1 routine.
+
+ Routine: %GS*
+
+ %GSE %GSEL
+
+ Current total of 3 routines.
+
+ Routine: - %D
+
+ %D
+
+ Current total of 2 routines.
+
+ Routine: ?D
+
+ %GSE %GSEL
+
+ Routine: <RETURN>
+
+ Output Device: <RETURN>
+
+ Routine First Line Lister Utility
+
+ GT.M 21-MAR-2002 16:44:09
+
+ %GSE
+
+ %GSE ;GT.M %GSE utility - global search
+
+ ;
+
+ %GSEL ;
+
+ %GSEL ;GT.M %GSEL utility - global select into a local array
+
+ ;
+
+ ;invoke ^%GSEL to create %ZG - a local array of existing globals,
+ interactively
+ ;
+
+ Total 5 lines in of 2 routines.
+
+ GTM>
+
+ This example selects %D, then selects %GSE and %GSEL and deselects %D.
+ Because the example enters <RETURN> at the Output Device: <terminal>:
+ prompt, the output goes to the principal device.
+
+3 RCE
+ %RCE
+
+
+ The %RCE utility replaces every occurrence of a text string with
+ another text string in a routine or a list of routines.
+
+ %RCE uses %RSEL to select routines. For more information, refer to the
+ section on %RSEL in this chapter.
+
+ %RCE prompts for a text string to replace and its replacement. %RCE
+ searches for text strings in a case-sensitive manner. %RCE issues a
+ warning message if you specify a control character such as a <TAB> in
+ the text string or its replacement. %RCE confirms your selection by
+ displaying the text string and its replacement between a left and right
+ arrow. The arrows highlight any blank spaces that you might have
+ included in the text string or its replacement.
+
+ If the output device is a file name with no extension, %RCE defaults
+ the extension to .DAT. Regardless of whether you select a display of
+ every change, %RCE displays the name of each routine as it is processed
+ and completes processing with a count of replacements and routines
+ changed.
+
+4 Prompts
+ Prompts
+
+ Routine: Requests (using %RSEL) the name(s) of the routines to
+ change; <RETURN> ends the selection.
+ Old string: Requests string to be replaced.
+ New string: Requests replacement string.
+ Show changed lines <Yes>?:
+ Asks whether to display the before and after versions of the
+ modified lines on an output device.
+ Output Device: <terminal>:
+ Requests a destination device; defaults to the principal device.
+4 Util_Labels
+ Utility Labels
+
+ CALL Works without user interaction unless %ZR is not defined.
+4 Input_Vars
+ Input Variable
+
+ The following input variables are only applicable when invoking
+ CALL^%RCE.
+
+ %ZR Contains an array of routines provided or generated with %RSEL.
+ %ZF Contains string to find.
+ %ZN Contains a replacement string.
+ %ZD Identifies the device to display the change trail, defaults to
+ principal device. Make sure you open the device if the device is
+ not the principal device.
+ %ZC Truth-value indicating whether to display the change trail,
+ defaults to 0 (no).
+4 Ex_of_RCE
+ Examples of %RCE
+
+ Example:
+
+
+ GTM>DO ^%RCE
+
+ Routine Change Every occurrence
+
+ Routine: BES*
+
+ BEST BEST2 BEST3 BEST4
+
+ Current total of 4 routines
+
+ Routine: <RETURN>
+
+ Old string:^NAME
+
+ New string:^STUDENT
+
+ Replace all occurrences of:
+
+>^NAME<
+ With
+
+>^STUDENT<
+ Show changed lines <Yes>?: <RETURN>
+
+ Output Device: <RETURN>
+
+ USER:[SMITH.WORK]BEST.M
+
+ Was: S ^NAME=SMITH
+
+ Now: S ^STUDENT=SMITH
+
+ Was: S ^NAME(1)=JOHN
+
+ Now: S ^STUDENT(1)=JOHN
+
+ USER:[SMITH.WORK] BEST2.M
+
+ USER:[SMITH.WORK]BEST3.M
+
+ Was: S ^NAME=X
+
+ Now: S ^STUDENT=X
+
+ Was: W ^NAME
+
+ Now: W ^STUDENT
+
+ USER:[SMITH.WORK]BEST4.M
+
+ Total of 4 routines parsed.
+
+ 4 occurrences changed in 2 routines.
+ GTM>
+
+ This example selects a list of routines that change the string "^NAME"
+ to the string "^STUDENT," and displays a trail of the changes.
+
+ Example:
+
+
+ GTM>DO ^%RCE
+
+ Routine Change Every occurrence
+
+ Routine: BES*
+
+ BEST BEST2 BEST3 BEST4
+
+ Current total of 4 routines
+
+ Routine: <RETURN>
+
+ Old String:<TAB>
+
+ The find string contains control characters
+
+ New string: <RETURN>
+
+ Replace all occurrences of:
+
+><TAB><
+ With:
+
+><
+ Show changed lines <Yes>?: N
+
+ BEST BEST2 BEST3 BEST4
+
+ Total 4 routines parsed.
+
+ 4 occurrences changed in 2 routines.
+ GTM>
+
+ This example removes all occurrences of the <TAB> key from specified
+ routines and suppresses the display trail of changes.
+
+3 RD
+ %RD
+
+
+ The %RD utility lists routine names accessible through the current
+ $ZROUTINES. %RD calls %RSEL and displays any routines accessible
+ through %RSEL. Use %RD to locate routines.
+
+ %RD accepts the wildcard characters asterisk (*) and percent sign (%).
+ The wildcards carry their DCL meanings, with one exception. %GSEL
+ interprets a percent sign (%) in the first position of a routine name
+ literally.
+
+ A colon (:) between two routine names specifies a range of routines.
+ %RD displays only those routine names accessible through the current
+ $ZROUTINES.
+
+ After each selection %RD displays the total number of routines listed.
+
+ Pressing <RETURN> exits %RD.
+
+4 Prompts
+ Prompts
+
+ Routine: Requests (using %RSEL) the name(s) of the routines to
+ list; <RETURN> ends the selection.
+4 Util_Labels
+ Utility Labels
+
+ OBJ Lists object modules accessible through the current $ZROUTINES.
+ LIB Lists percent (%) routines accessible through the current
+ $ZROUTINES.
+ SRC Lists the source modules accessible through the current
+ $ZROUTINES (same as %RD).
+4 Ex_of_RD
+ Examples of %RD
+
+ Example:
+
+
+ GTM>DO ^%RD
+
+ Routine directory
+
+ Routine: TAXES
+
+ TAXES
+
+ Total of 1 routine
+
+ Routine:*
+
+ EMP FICA PAYROLL TAXES YTD
+
+ Total of 5 Routines
+
+ Routine: <RETURN>
+
+ GTM>
+
+ This example invokes %RD that prompts for routine TAXES and the
+ wildcard (*). %RD lists five routines accessible through the current
+ $ZROUTINES.
+
+ Example:
+
+
+ GTM>DO OBJ^%RD
+
+ Routine directory
+
+ Routine:*
+
+ EMP FICA
+
+ Total of 2 routines
+
+ Routine: <RETURN>
+
+ GTM>
+
+ This example invokes %RD with the label OBJ that lists only object
+ modules accessible through the current $ZROUTINES.
+
+ Example:
+
+
+ GTM>DO LIB^%RD
+
+ Routine directory
+
+ %D %DATE %DH %G %GD %GSEL
+
+ GTM>
+
+ This example invokes %RD with the LIB label that lists all the %
+ routines accessible through the current $ZROUTINES.
+
+ Example:
+
+
+ GTM>DO SRC^%RD
+
+ Routine directory
+
+ Routine:*
+
+ DATACHG
+
+ Total of 1 routines
+
+ Routine: <RETURN>
+
+ GTM>
+
+ This example invokes %RD with the label SRC that lists only source
+ modules accessible through the current $ZROUTINES.
+
+3 RI
+ %RI
+
+
+ %RI transforms M routines in the sequential format described in the
+ ANSI standard into individual .M files in GT.M format. Use %RI to make
+ M RO format accessible as GT.M routines.
+
+4 Prompts
+ Prompts
+
+ Formfeed delimited <No>?
+ Requests whether lines should be delimited by formfeed characters
+ rather than carriage returns.
+ Input Device: <terminal>:
+ Requests name of RO file containing M routines.
+ Output Directory:
+ Requests name of directory to output M routines.
+ The %RI utility corresponds to the MUPIP CONVERT command.
+
+4 Ex_of_RI
+ Examples of %RI
+
+ Example:
+
+
+ GTM>DO ^%RI
+
+ Routine Input utility - Converts RO file to *.m files
+
+ Formfeed delimited <No>? <RETURN>
+
+ Input device: <terminal>: file.ro
+
+ Files saved from FILEMAN directory
+
+ GT.M 07-MAY-2002 15:17:54
+
+ Output directory: USER:[SMITH.WORK]
+
+ DI DIA DIAO DIAI DIB DIBI
+
+ Restored 753 lines in 6 routines.
+
+ GTM>
+
+3 RO
+ %RO
+
+
+ The %RO utility writes M source code for one or more routines to a
+ sequential device such as a disk file or a printer. %RO writes M source
+ code in a format that can be used as input to the GT.M utility MUPIP
+ CONVERT.
+
+ %RO uses %RSEL to select routines. For more information, refer to the
+ section on %RSEL in this chapter.
+
+ %RO writes the routines in alphabetical order to the specified device.
+ %RO displays the name of each routine as it writes the routine to the
+ device.
+
+4 Prompts
+ Prompts
+
+ Routine: Requests (using %RSEL) the name(s) of the routines to
+ output; <RETURN> ends selection.
+ Output device: <terminal>:
+ Requests a destination device; defaults to the principal device.
+ Header label: Requests text to place in the first of the two header
+ records.
+ Strip comments <No>?:
+ Asks whether to remove all comment lines except those with two
+ adjacent semicolons.
+4 Util_Labels
+ Utility Labels
+
+ CALL Works without user interaction unless %ZR is not defined.
+4 Input_Vars
+ Input Variables
+
+ The following input variables are only applicable when invoking
+ CALL^%RO.
+
+ %ZR Contains an array of routines provided or generated with %RSEL.
+ %ZD Identifies the device to display output, defaults to principal
+ device.
+4 Ex_of_RO
+ Examples of %RO
+
+ Example:
+
+
+ GTM>DO ^%RO
+
+ Routine Output - Save selected routines into RO file.
+
+ Routine: %D
+
+ %D
+
+ Current total of 1 routines.
+
+ Routine: -%D
+
+ %D
+
+ Current total of 0 routines.
+
+ Routine: BEST*
+
+ BEST BEST1 BEST2
+
+ Current total of 3 routines.
+
+ Routine: ?D
+
+ BEST BEST1 BEST2
+
+ Routine: <RETURN>
+
+ Output Device: <terminal>: $PRINTER
+
+ Header Label: Source code for the BEST modules.
+
+ Strip comments <No>?:<RETURN>
+
+ BEST BEST1 BEST2
+
+ Total of 53 lines in 3 routines
+
+ GTM>
+
+ This example adds and subtracts %D from the selection, then adds all
+ routines starting with "BEST" and confirms the current selection. The
+ example sends output to $PRINTER, which sends the output to the system
+ printer. %RO displays the label at the beginning of the output file.
+ The first record of the header label is the text entered at the prompt.
+ The second record of the header label consists of the word "GT.M" and
+ the current date and time.
+
+3 RSE_
+ %RSE
+
+
+ The %RSE utility searches for every occurrence of a text string in a
+ routine or a list of routines.
+
+ %RSE uses %RSEL to select routines. For more information, refer to the
+ section on %RSEL in this chapter.
+
+ %RSE searches for text strings are case-sensitive. %RSE issues a
+ warning message if you specify a control character such as a <TAB> in
+ the text string. %RSE confirms your selection by displaying the text
+ string between a left and right arrow. The arrows display any blank
+ spaces included in the text string.
+
+ If the output device is a file name with no extension, %RSE defaults
+ the extension to .DAT. %RSE completes processing with a count of
+ occurrences found.
+
+4 Prompts
+ Prompts
+
+ Routine: Requests (using %RSEL) the name(s) of the routines to
+ search; <RETURN> ends selection.
+ Find string: Requests string for which to search.
+ Output device: <terminal>:
+ Requests a destination device; defaults to the principal device.
+4 Util_Labels
+ Utility Labels
+
+ CALL Works without user interaction unless %ZR is not defined.
+4 Input_Vars
+ Input Variables
+
+ The following input variables are only applicable when invoking
+ CALL^%RSE.
+
+ %ZR Contains an array of routines provided or generated with %RSEL.
+ %ZF Contains the string to find.
+ %ZD Identifies the device to display the results, defaults to
+ principal device. Make sure you open the device if the device is
+ not the principal device.
+4 Ex_of_RSE
+ Examples of %RSE
+
+ Example:
+
+
+ GTM>DO ^%RSE
+
+ Routine Search for Every occurrence
+
+ Routine: BES*
+
+ BEST BEST2 BEST3 BEST4
+
+ Current total of 4 routines
+
+ Routine: <RETURN>
+
+ Find string:^NAME
+
+ Find all occurrences of:
+
+>^NAME<
+ Output device: <terminal>:
+
+ USER:[SMITH.WORK]BEST.M
+
+ S ^NAME=SMITH
+
+ S ^NAME(1)=JOHN
+
+ USER:[SMITH.WORK]BEST2.M
+
+ USER:[SMITH.WORK]BEST3.M
+
+ S ^NAME=X
+
+ W ^NAME
+
+ USER:[SMITH.WORK]BEST4.M
+
+ Total of 4 routines parsed.
+
+ 4 occurrences found in 2 routines.
+ GTM>
+
+ This example invokes %RSE that searches and finds a given string. The
+ output device specifies a terminal display of all lines where the text
+ string occurs.
+
+ Example:
+
+
+ GTM>DO ^%RSE
+
+ Routine Search for Every occurrence
+
+ Routine: BEST
+
+ BEST
+
+ Current total of 1 routine
+
+ Routine: <RETURN>
+
+ Find string:^NAME
+
+ Find all occurrences of:
+
+>^NAME<
+ Output Device: OUT.LIS
+
+ BEST
+
+ GTM>
+
+ This example instructs ^%RSE to write all lines where the text string
+ occurs to an output file, OUT.LIS.
+
+3 RSEL
+ %RSEL
+
+
+ The %RSEL utility selects M routines. %RSEL selects routines using
+ directories specified by the GT.M special variable $ZROUTINES.
+ $ZROUTINES contains an ordered list of VMS directories that certain
+ GT.M functions use to locate source and object files. If $ZROUTINES is
+ not defined, %RSEL searches only the current default directory. Other
+ GT.M utilities call %RSEL.
+
+ %RSEL prompts for the name of a routine(s).
+
+
+ %RSEL accepts the wildcard characters asterisk (*) and percent sign
+ (%). The wildcards carry their DCL meanings, with one exception. %GSEL
+ interprets a % sign in the first position of a global name literally.
+
+ A colon (:) between two routines specifies a range.
+
+ %RSEL creates a read-write variable %ZR, which is a local array of
+ selected routines. After each selection, %RSEL reports the number of
+ routines in %ZR. A minus sign (-) or an apostrophe (') character
+ preceding a routine name removes that routine from the %ZR array. A
+ question mark (?) provides online help, and "?D" displays M routines
+ currently in the array.
+
+ If a local variable %ZRSET is defined, %RSEL places the output
+ information into a global variable (^%RSET) instead of the local
+ variable %ZR.
+
+4 Prompts
+ Prompts
+
+ Routine: Requests the name(s) of the routines; <RETURN> ends
+ selection.
+4 Util_Labels
+ Utility Labels
+
+ CALL Performs %RSEL without reinitializing %ZR.
+ OBJ Searches only object files.
+ SRC Searches only source files (same as %RSEL).
+4 Input_Vars
+ Input Variables
+
+ The following input variables are only valid when invoking CALL^%RSEL:
+
+ %ZE Contains the file extension, usually either .M for source files
+ or .OBJ for object files.
+ %ZR As input, contains an existing list of routines to be modified.
+ %ZRSET On being set, requests %RSEL to place the output in the
+ global variable ^%RSET.
+4 Output_Vars
+ Output Variables
+
+ %ZR As output, contains list of directories indexed by selected
+ routine names.
+ ^%RSET($JOB) The output global variable ^%RSET is used instead of
+ the local variable %RD if the input variable %ZRSET is set. It is
+ indexed by job number $JOB and the selected routine names.
+4 Ex_of_RSEL
+ Examples of %RSEL
+
+ Example:
+
+
+ GTM>DO ^%RSEL
+
+ Routine: TES*
+
+ TEST2 TEST3
+
+ Current total of 2 routines
+
+ Routine: <RETURN>
+
+ GTM>DO OBJ^%RSEL
+
+ Routine:Test%
+
+ Current total of 0 routines
+
+ Routine: <RETURN>
+
+ GTM>ZWRITE
+
+ %ZR=0
+
+ This example selects two source routines starting with "TES" as the
+ first three characters. Then, the example invokes %RSEL at the OBJ
+ label to select object modules only. OBJ^%RSEL returns a %ZR=0 because
+ object modules for the TEST routines do not exist.
+
+ Example:
+
+
+ GTM>DO ^%RSEL
+
+ Routine: BES*
+
+ BEST BEST2 BEST3 BEST4
+
+ Current total of 4 routines
+
+ Routine: - BEST
+
+ BEST
+
+ Current total of 3 routines
+
+ Routine: ?D
+
+ BEST2 BEST3 BEST4
+
+ Routine: 'BEST2
+
+ BEST2
+
+ Current total of 2 routines
+
+ Routine: ?D
+
+ BEST3 BEST4
+
+ Routine: <RETURN>
+
+ GTM>ZWRITE
+
+ %ZR=2
+
+ %ZR("BEST3")="USER:[SMITH.WORK]"
+
+ %ZR("BEST4")="USER:[SMITH.TEST]"
+
+ GTM>
+
+ This example selects the routines using the asterisk (*) wildcard and
+ illustrates how to tailor your selection list. Note that %ZR contains
+ two routines from different directories.
+
+ By default, %RSEL bases the contents of %ZR on source files that have a
+ .M extension.
+
+ Example:
+
+
+ GTM>DO ^%RSEL
+
+ Routine:BEST*
+
+ BEST2 BEST3
+
+ Current total of 2 routines
+
+ Routine: <RETURN>
+
+ GTM>ZWRITE
+
+ %ZR=2
+
+ %ZR("BEST2")="USER:[SMITH.WORK]"
+
+ %ZR("BEST3")="USER:[SMITH.WORK]"
+
+ This example creates a %ZR array with BEST2 and BEST3.
+
+ Example:
+
+
+ GTM>DO ^%RSEL
+
+ Routine:LOCK
+
+ LOCK
+
+ Current total of 1 routine
+
+ Routine: <RETURN>
+
+ GTM>ZWRITE
+
+ %ZR=1
+
+ %ZR("LOCK")="USER:[SMITH.WORK]"
+
+ GTM>DO CALL^%RSEL
+
+ Routine:BEST*
+
+ BEST2 BEST3
+
+ Current total of 2 routines
+
+ Routine: <RETURN>
+
+ GTM>ZWRITE
+
+ %ZR=3
+
+ %ZR("BEST2")="USER:[SMITH.WORK]"
+
+ %ZR("BEST3")="USER:[SMITH.WORK]"
+
+ %ZR("LOCK")="USER:[SMITH.WORK]"
+
+ GTM>
+
+ This example creates a %ZR array with LOCK and adds to it using
+ CALL%RSEL.
+
+2 Internationalization_Util
+ Internationalization Utilities
+
+ The internationalization utilities are:
+
+ %GBLDEF Manipulates the collation sequence assigned to a global.
+ %LCLCOL Manipulates the collation sequence assigned to local
+ variables in an active process.
+ %PATCODE Loads pattern definition files for use within an active
+ database.
+ These utilities are an integral part of the GT.M functionality that
+ permits you to customize your applications for use with other
+ languages. For a description of these utilities, refer to the
+ "Internationalization" chapter in GT.M Programmers Guide.
+
+2 Sys_Mgmt_Util
+ System Management Utilities
+
+ The System Management utilities are:
+
+ %FREECNT Displays the number of free blocks in the database files
+ associated with the current global directory.
+ %ST Displays the current users of the GT.M run-time library,
+ optionally by image.
+3 FREECNT
+ %FREECNT
+
+
+ The %FREECNT utility displays the number of free blocks in the database
+ files associated with the current global directory.
+
+3 ST
+ %ST
+
+
+ The %ST utility displays the number of current users of the GT.M
+ run-time library and information about those processes that you have
+ privileges to view. You must have the VMS SYSLCK privilege to run this
+ utility. If there are no users accessing GT.M, the message "No current
+ GT.M users" appears.
+
+ %ST displays the access method used by the processes. For a list of the
+ possible access methods, refer to the Access Methods table in GT.M
+ Programmer's Guide.
+
+4 Util_Labels
+ Utility Labels
+
+
diff --git a/sr_vvms/mumps_clitab.cld b/sr_vvms/mumps_clitab.cld
new file mode 100644
index 0000000..9cf8934
--- /dev/null
+++ b/sr_vvms/mumps_clitab.cld
@@ -0,0 +1,25 @@
+MODULE MUMPS_CLITAB
+
+DEFINE VERB MUMPS
+ QUALIFIER CROSS_REFERENCE PLACEMENT=POSITIONAL
+ QUALIFIER DEBUG PLACEMENT=POSITIONAL
+ QUALIFIER LIST VALUE(TYPE=$FILE)
+ PLACEMENT=POSITIONAL
+ QUALIFIER MACHINE_CODE PLACEMENT=POSITIONAL
+ QUALIFIER IGNORE PLACEMENT=POSITIONAL
+ QUALIFIER LENGTH VALUE(REQUIRED,TYPE=$NUMBER)
+ PLACEMENT=POSITIONAL
+ QUALIFIER SPACE VALUE(REQUIRED,TYPE=$NUMBER)
+ PLACEMENT=POSITIONAL
+ QUALIFIER OBJECT VALUE(TYPE=$FILE)
+ PLACEMENT=POSITIONAL
+ QUALIFIER WARNINGS PLACEMENT=POSITIONAL
+ QUALIFIER LABELS VALUE(REQUIRED)
+ PLACEMENT=POSITIONAL
+ QUALIFIER LINE_ENTRY PLACEMENT=POSITIONAL
+ QUALIFIER INLINE_LITERALS PLACEMENT=POSITIONAL
+ QUALIFIER ALIGN_STRINGS PLACEMENT=POSITIONAL
+ QUALIFIER CE_PREPROCESS VALUE(TYPE=$FILE)
+ PLACEMENT=POSITIONAL
+ DISALLOW(CROSS_REFERENCE AND NOT LIST)
+ PARAMETER P1, LABEL=INFILE,PROMPT="FILE",VALUE(LIST,TYPE=$FILE)
diff --git a/sr_vvms/mup_bak_sys.c b/sr_vvms/mup_bak_sys.c
new file mode 100644
index 0000000..e5db9a6
--- /dev/null
+++ b/sr_vvms/mup_bak_sys.c
@@ -0,0 +1,56 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <ssdef.h>
+#include <descrip.h>
+#include "efn.h"
+#include <dvidef.h>
+#include "util.h"
+
+GBLREF mstr directory;
+GBLREF int4 mubmaxblk;
+GBLREF bool error_mupip;
+
+void mup_bak_mag(void)
+{
+ int4 item_code;
+ $DESCRIPTOR(dir,"");
+ uint4 devbufsiz;
+
+ item_code = DVI$_DEVBUFSIZ;
+ dir.dsc$a_pointer = directory.addr;
+ dir.dsc$w_length = directory.len;
+ devbufsiz = 0;
+ lib$getdvi(&item_code, 0, &dir, &devbufsiz, 0, 0);
+ if (devbufsiz < mubmaxblk + 8)
+ {
+ util_out_print("!/Buffer size !UL may not accomodate maximum GDS block size of !UL.", FALSE,
+ devbufsiz, mubmaxblk - 4);
+ util_out_print("!/4 bytes/GDS block + 8 bytes/tape block in overhead required for device.", FALSE);
+ util_out_print("!/MUPIP cannot start backup with above errors!/",TRUE);
+ error_mupip = TRUE;
+ }
+ return;
+}
+
+void mup_bak_pause(void)
+{
+ int4 pause[2];
+
+ pause[0] = 2 * -10000000;
+ pause[1] = -1;
+ if (sys$setimr( efn_immed_wait, &pause, 0, 0, 0) == SS$_NORMAL) /* Safety wait to make sure that all blocks have been */
+ { sys$synch(efn_immed_wait, 0); /* returned to the frozen queues before flushing */
+ }
+
+ return;
+}
diff --git a/sr_vvms/mupip.c b/sr_vvms/mupip.c
new file mode 100644
index 0000000..eba05b0
--- /dev/null
+++ b/sr_vvms/mupip.c
@@ -0,0 +1,145 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <ssdef.h>
+#include <descrip.h>
+
+#include "gtm_inet.h"
+
+#include "cryptdef.h"
+#include "ladef.h"
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "gdscc.h"
+#include "gdskill.h"
+#include "filestruct.h"
+#include "error.h" /* for EXIT_HANDLER macro used in SET_EXIT_HANDLER macro */
+#include "jnl.h"
+#include "buddy_list.h" /* needed for tp.h */
+#include "hashtab_int4.h" /* needed for tp.h */
+#include "tp.h"
+#include "min_max.h" /* needed for init_root_gv.h */
+#include "init_root_gv.h"
+#include "desblk.h" /* for desblk structure */
+#include "repl_msg.h"
+#include "gtmsource.h"
+#include "gtmimagename.h"
+#include "stp_parms.h"
+#include "stringpool.h"
+#include "util.h"
+#include "mupip_exit.h"
+#include "lmdef.h"
+#include "getjobnum.h"
+#include "patcode.h"
+#include "generic_exit_handler.h"
+#include "ast_init.h"
+#include "get_page_size.h"
+#include "init_secshr_addrs.h"
+#include "mupip_getcmd.h"
+#include "gtm_env_init.h" /* for gtm_env_init() prototype */
+#include "gtm_imagetype_init.h"
+#include "gtm_threadgbl_init.h"
+
+GBLREF desblk exi_blk;
+GBLREF bool licensed;
+GBLREF int4 lkid, lid;
+GBLREF bool in_backup;
+GBLREF mval curr_gbl_root;
+GBLREF int4 exi_condition;
+GBLREF spdesc rts_stringpool, stringpool;
+
+error_def (ERR_WILLEXPIRE);
+error_def (LP_NOCNFDB);
+error_def (LP_INVCSM);
+
+OS_PAGE_SIZE_DECLARE
+
+LITREF char gtm_product[PROD];
+LITREF int4 gtm_product_len;
+LITREF char gtm_version[VERS];
+LITREF int4 gtm_version_len;
+
+mupip()
+{
+ unsigned int status;
+ int4 inid = 0;
+ int4 nid = 0; /* system ID, node number */
+ int4 days = 128; /* days to expiration */
+ int4 lic_x = 0; /* license value */
+ char *h = NULL; /* license data base */
+ char *pak = NULL; /* pak record */
+ int4 mdl = 0; /* hardw. model type */
+ $DESCRIPTOR(dprd, gtm_product);
+ $DESCRIPTOR(dver, gtm_version);
+ DCL_THREADGBL_ACCESS;
+
+ GTM_THREADGBL_INIT;
+ gtm_imagetype_init(MUPIP_IMAGE);
+ gtm_env_init(); /* read in all environment variables */
+ licensed = TRUE;
+ TREF(transform) = TRUE;
+ in_backup = FALSE;
+ util_out_open(0);
+ SET_EXIT_HANDLER(exi_blk, generic_exit_handler, exi_condition); /* Establish exit handler */
+ ESTABLISH(util_base_ch);
+ get_page_size();
+ getjobnum();
+ INVOKE_INIT_SECSHR_ADDRS;
+# ifdef NOLICENSE
+ status = SS$_NORMAL;
+ lid = 1;
+ lic_x = 32767;
+# else
+ if (NULL == (h = la_getdb(LMDB))) /* license db in mem */
+ status = LP_NOCNFDB;
+ else
+ status = SS$_NORMAL;
+ if (1 == (status & 1)) /* licensing: node+ system */
+ status = lm_mdl_nid(&mdl, &nid, &inid);
+ if (1 == (status & 1)) /* licensing: license */
+ {
+ dprd.dsc$w_length = gtm_product_len;
+ dver.dsc$w_length = gtm_version_len;
+ status = lp_licensed(h, &dprd, &dver, mdl, nid, &lid, &lic_x, &days, pak);
+ }
+# endif
+ if (1 == (status & 1)) /* licensing: license units */
+ status = LP_ACQUIRE(pak, lic_x, lid, &lkid); /* def in cryptdef */
+# ifdef NOLICENSE
+ status = SS$_NORMAL;
+# else
+ if (LP_NOCNFDB != status)
+ la_freedb(h);
+ if (1 == (status & 1)) /* licensing */
+ {
+ if (days < 14)
+ lm_putmsgu(ERR_WILLEXPIRE, 0, 0);
+ }
+ else
+ {
+ licensed = FALSE;
+ if (LP_INVCSM != status)
+ rts_error(VARLSTCNT(1) status);
+ }
+# endif
+ ast_init();
+ initialize_pattern_table();
+ INIT_GBL_ROOT();
+ stp_init(STP_INITSIZE);
+ rts_stringpool = stringpool;
+ mupip_getcmd();
+ mupip_exit(SS$_NORMAL);
+}
diff --git a/sr_vvms/mupip.hlp b/sr_vvms/mupip.hlp
new file mode 100644
index 0000000..d17bcfa
--- /dev/null
+++ b/sr_vvms/mupip.hlp
@@ -0,0 +1,2355 @@
+
+
+1 Overview
+ MUPIP overview
+ The GT.M MUMPS Peripheral Interchange Program, MUPIP, is a utility
+ that provides an assortment of tools for GT.M database management and
+ database journaling.
+
+ MUPIP provides the following commands:
+
+ For stand-alone database services:
+
+ o CREATE database files
+
+ o EXTEND Mapped Memory database files
+
+ o JOURNAL, recover database files and extract journal records
+
+ o INTEG, check the integrity of GDS database files
+
+ o RESTORE incremental backups to GDS database files
+
+ o SET database file characteristics
+
+ For concurrent database services:
+
+ o BACKUP GDS database files
+
+ o BACKUP/INCREMENTAL changes to GDS database files
+
+ o EXTEND Buffered Global database files
+
+ o EXTRACT data from GDS databases
+
+ o INTEG, check the integrity of GDS databases
+
+ o LOAD databases from sequential files
+
+ o REORGanize database files to optimize performance
+
+ o RUNDOWN database files that are not currently accessed
+
+ For non-database services:
+
+ o CONVERT MUMPS programs in sequential format into RMS files
+
+ o HELP for MUPIP commands
+
+ o STOP GT.M processes
+
+1 Global_dir
+ MUPIP and the Global Directory
+ Some of the MUPIP commands require information contained in the Global
+ Directory. Therefore, a process must have access to a valid Global
+ Directory before using any MUPIP database service commands other than
+ JOURNAL, RESTORE, and the /FILE options of INTEG and SET.
+
+ The logical name GTM$GBLDIR specifies the Global Directory. Define
+ GTM$GBLDIR using the DCL command DEFINE. The system manager may define
+ GTM$GBLDIR in a GROUP or SYSTEM table. Individual users define
+ GTM$GBLDIR in their LOGIN.COM or other command files.
+
+ Example
+
+ $ DEFINE GTM$GBLDIR PROD.GLD
+
+1 BACKUP
+ B[ACKUP]
+ BACKUP copies blocks from one or more Greystone Technology Database
+ Structure (GDS) files to a new file or files. BACKUP suspends updates
+ to all regions specified by the BACKUP command from the time it starts
+ the first region until it finishes the last region. This ensures that
+ BACKUP captures a consistent application state. BACKUP does not
+ suspend processes that only perform retrievals.
+
+ The format of the BACKUP command is:
+
+ B[ACKUP][/qualifier[...]] region-list[,...] file-spec
+
+
+ By default, BACKUP is /COMPREHENSIVE.
+
+ The first argument may specify more than one region of the current
+ Global Directory in a list separated with commas. Any region-name may
+ include the DCL wildcard characters * and %.
+
+ To BACKUP only one region, the file-specification must resolve to an
+ RMS file or directory name. To BACKUP several regions, the
+ file-specification must be a directory specification. If the
+ file-specification is a directory, MUPIP assigns the backup files the
+ same name as the file associated with the dynamic segment of each
+ region. Therefore, the target directory must not contain any of the
+ regions included in the BACKUP.
+
+2 Qualifiers
+/COMPREHENSIVE
+ /C[OMPREHENSIVE]
+ Specifies that BACKUP copy the entire file from disk to disk. On
+ completion, the result is ready for use as a GT.M database. This
+ option does not support operation to magnetic tape.
+
+ BACKUP /COMPREHENSIVE produces a result similar to the result
+ produced by a DCL COPY command or some variations of the DCL
+ BACKUP command, but it has the following advantages:
+
+ o It does not require exclusive access to the file
+
+ o It can interlock multiple files simultaneously
+
+ The /COMPREHENSIVE qualifier is not compatible with any other
+ qualifier.
+
+ By default, BACKUP operates /COMPREHENSIVE.
+
+/INCREMENTAL
+ /I[NCREMENTAL]
+ Specifies that BACKUP include only blocks from the database that
+ have changed since a prior point specified by the /SINCE or
+ /TRANSACTION qualifier. MUPIP RESTORE integrates the results of
+ a BACKUP /INCREMENTAL into a database.
+
+ When directing the output file to a magnetic tape, use DCL to
+ MOUNT the tape /INITIALIZE=CONTINUATION. This causes automatic
+ handling of multiple volumes. When mounting a volume to tape for
+ a BACKUP /INCREMENTAL, specify a blocksize twelve (12) bytes
+ larger than the size of the blocks in the database to
+ accommodate overhead (i.e., 4 bytes for GTM overhead and 8 bytes
+ for RMS overhead). If the block size is too small, the BACKUP
+ fails when it encounters a full block.
+
+ The /INCREMENTAL qualifier is not compatible with the
+ /COMPREHENSIVE qualifier.
+
+/RECORD
+ /R[ECORD]
+ Specifies that the BACKUP utility record this backup as a
+ reference point for subsequent backups. Each time a BACKUP
+ specifies /RECORD, that backup replaces the previous recorded
+ backup as the RECORD reference point for the file.
+
+/SINCE
+ /S[INCE]=keyword
+ Specifies that a BACKUP /INCREMENTAL includes blocks changed
+ since the last specified BACKUP.
+
+ /SINCE accepts the keywords:
+
+ o C[OMPREHENSIVE] - Backup all changes since the last BACKUP
+ /COMPREHENSIVE
+
+ o I[NCREMENTAL] - Backup all changes since the last BACKUP
+ /INCREMENTAL
+
+ o R[ECORD] - Backup all changes since the last BACKUP /RECORD
+
+ The /SINCE qualifier is incompatible with the /COMPREHENSIVE and
+ /TRANSACTION qualifiers.
+
+ By default, BACKUP /INCREMENTAL operates /SINCE=COMPREHENSIVE.
+
+/TRANSACTION
+ /T[RANSACTION]=transaction-number
+ Specifies a hexadecimal starting transaction which causes BACKUP
+ /INCREMENTAL to copy all blocks that have been changed by the
+ specified and all subsequent transactions. Transaction numbers
+ appear in a DSE DUMP /FILEHEADER, with a "Current TN" label. If
+ the transaction number is invalid, BACKUP reports an error and
+ rejects the command.
+
+ BACKUP /INCREMENTAL /TRANSACTION=1 copies all in-use blocks and
+ produces a result similar to the result produced by some
+ variations of the DCL BACKUP command but it has the following
+ advantages:
+
+ o It does not require exclusive access to the file
+
+ o It can interlock multiple files simultaneously
+
+ o It should be faster, if the database is not very full (it
+ must be nearly empty to be an advantage)
+
+ o It is useful for backing up an entire database to tape
+
+ Different regions do not normally have a single transaction
+ number that marks a meaningful point. Therefore, a BACKUP
+ command specifying multiple regions and using the /TRANSACTION
+ qualifier with arguments other than one (1) is unlikely to
+ produce desirable results.
+
+ The /TRANSACTION qualifier is incompatible with the
+ /COMPREHENSIVE and /SINCE qualifiers.
+
+2 Examples
+ BACKUP Examples
+ Example:
+
+ $ MUPIP BACKUP * [.backup]
+
+ This comprehensively backs up all regions of the entire database
+ (defined by the current Global Directory) into the RMS
+ sub-directory [.backup]. BACKUP creates a copy of each dynamic
+ segment in the sub-directory. The file for each segment has the
+ same name as the file being backed up.
+
+ Example
+
+ $ INIT MSA0: FULL
+ $ MOUNT/INIT=CONT/BLOCK=2060 MSA0: FULL
+ $ MUPIP BACKUP/INCREMENTAL/TRANSACTION=1 MAIN_REG FULL:MAIN
+
+ In this example, the first command initializes a magnetic tape with
+ the label FULL. The second command mounts the tape with VMS
+ automatic volume initialization and a block size of 2060. The
+ magnetic tape block size of 2060 handles a database block of 2048
+ bytes. The MUPIP command backs up the dynamic segment associated
+ with MAIN_REG to the tape. Because of the /TRANSACTION=1, BACKUP
+ copies all blocks in use to the tape.
+
+ Example
+
+ $ MUPIP BACKUP main*,%xref usr$bck:[tuesday]
+
+ This comprehensively backs up all regions that have names starting
+ with "main" and all regions that have names starting with any
+ single character and ending with "xref" to the directory
+ usr$bck:[tuesday].
+
+ Example
+
+ $ MUPIP BACKUP/INCREMENTAL/SINCE=COMPREHENSIVE * [19880505]
+
+ This backs up all changes made since the last BACKUP /COMPREHENSIVE
+ for all regions of the database defined by the current Global
+ Directory into the RMS directory [19880505]. BACKUP creates files
+ in the directory, with names corresponding to each dynamic
+ segment's file name.
+
+ Note: BACKUPs of multiple regions can lead to more than one file
+ with the same name in the backup directory, as different regions
+ can have the same file names as long as they use different
+ directory paths or logical names to access them.
+
+1 CONVERT
+ CO[NVERT]
+ CONVERT transforms MUMPS routines in the sequential format described
+ in the ANSI standard into individual RMS source files for use by GT.M.
+ Use CONVERT to make MUMPS RO format files accessable as GT.M routines.
+
+ The format of the CONVERT command is:
+
+ CO[NVERT][/F[ORMAT]=RO] file-spec directory-spec
+
+ CONVERT takes its input from the file defined by the
+ file-specification. CONVERT places the output files in the directory
+ defined by the directory-specification. CONVERT uses the routine name
+ and a ".M" extension as the output file name for each routine.
+
+
+2 Qualifiers
+/FORMAT
+ /F[ORMAT]=RO
+ Specifies the format of the input file. The RO (Routine Output)
+ format code is the default and the only code CONVERT recognizes.
+
+
+1 CREATE
+ CR[EATE]
+ CREATE generates database files using the characteristics stored in a
+ Global Directory by the Global Directory Editor (GDE). CREATE uses the
+ Global Directory to map a region to a segment and a segment to a file.
+ Use the MUPIP CREATE command to create a new database or a new copy of
+ a previously existing file during a database reorganization. If a
+ database file already exists for the segment, CREATE takes no action.
+ If a file does not exist, CREATE sets up the file. CREATE also
+ initializes the database structure (GDS).
+
+ The format of the CREATE command is:
+
+ CR[EATE] [/R[EGION]=region-name]
+
+ The optional /REGION qualifier specifies a single region for which to
+ create a database file.
+
+ By default, CREATE sets up database files for all regions in the
+ current Global Directory.
+
+2 Qualifiers
+/REGION
+ /R[EGION]=region-name
+ Specifies a single region for creation of a database file. By
+ default, CREATE sets up (creates) database files for all regions
+ in the current Global Directory.
+
+1 EXIT
+ EXI[T]
+ EXIT or <CTRL Z> terminates MUPIP and returns control to the point
+ where MUPIP was invoked. This command is useful when you invoke MUPIP
+ without an action and wish to leave without performing one, or after
+ using MUPIP HELP.
+
+ The format of the EXIT command is:
+
+ EXI[T]
+
+ The Exit command does not accept any qualifiers.
+
+1 EXTEND
+ EXTE[ND]
+ EXTEND expands a GDS database file. Databases with a BG access method
+ generally extend automatically when they become full. MM databases
+ must be MUPIP EXTENDed. For MM segments, EXTEND requires exclusive or
+ stand-alone access to the file. When EXTEND requires exclusive
+ database access and cannot obtain it, MUPIP rejects the command.
+
+ The format of the EXTEND command is:
+
+ EXTE[ND] region-name [/B[LOCKS]=blocks]
+
+ The required region-name parameter specifies the name of the region to
+ expand. EXTEND uses the Global Directory to map the region to the
+ dynamic segment and the segment to the file.
+
+2 Qualifiers
+/BLOCKS
+ /B[LOCKS]=blocks
+ Specifies the number of GDS database blocks by which GT.M should
+ extend the file. GDS files use some blocks for bit maps. EXTEND
+ adds the specified number of blocks and the bit map blocks
+ required as overhead. For more information about bit maps, refer
+ to the "GDS" chapter of the GT.M Administration and Operations
+ Guide.
+
+ EXTEND uses the value in the fileheader as the number of GDS
+ blocks by which to extend the database file.
+
+1 EXTRACT
+ EXTR[ACT]
+ EXTRACT copies specified globals from the current database to a
+ sequential output file in one of two formats (i.e., GO, or BINARY).
+ Use EXTRACT to back up specific globals or when extracting data from
+ the database for use by another system. EXTRACT uses the Global
+ Directory to determine which database files to use. EXTRACT may
+ operate concurrently with normal GT.M database access. To ensure that
+ an EXTRACT reflects a consistent application state, suspend database
+ updates to all regions involved in the extract with the /FREEZE
+ qualifier.
+
+ The format of the EXTRACT command is:
+
+ EXTR[ACT][/qualifier[...]] file-specification
+
+ EXTRACT places its output in the file defined by the
+ file-specification. EXTRACT may output to an RMS file on any device
+ that supports such files, including magnetic tapes. Note that magnetic
+ tapes may have a smaller file maximum size than disks. When directing
+ the output file to a magnetic tape, use DCL to MOUNT the tape
+ /INITIALIZE=CONTINUATION. This causes automatic handling of multiple
+ volumes. When mounting a volume to tape for an EXTRACT, specify a
+ blocksize that is eight (8) bytes larger than the size of the blocks
+ in the database to accommodate RMS overhead. <CTRL C> produces a
+ status message from EXTRACT. <CTRL Y> aborts EXTRACT. An EXTRACT
+ terminated abnormally by operator action or error produces incomplete
+ output.
+
+2 Qualifiers
+/SELECT
+ /S[ELECT]=global-name-list
+ Specifies the globals to extract. The "^" in the specification
+ of the global name is optional. Enclose lowercase global names
+ in quotes ("").
+
+ The global-specification can be:
+
+ o A global name, such as MEF
+
+ o A range of global names, such as A7:B6
+
+ o A parenthetical list, such as (A,B,C)
+
+ o Global names with the same prefix, such as TMP*
+
+ In the first case, EXTRACT selects only global ^MEF. In the
+ second case, EXTRACT selects all global names between ^A7 and
+ ^B6, inclusive. In the third case, EXTRACT selects globals ^A,
+ ^B, and ^C. In the fourth case, EXTRACT selects all global names
+ from ^TMP through ^TMPzzzzz.
+
+ By default, EXTRACT selects all globals, as if it had the
+ qualifier /SELECT=*.
+
+/FORMAT
+ /FO[RMAT]=GO|B[INARY]
+ Specifies the format of the output file.
+
+ The format codes are:
+
+ o GO - Global Output format, used for files you want to
+ transport or archive
+
+ o B[INARY] - Binary format, used for database reorganization
+ or short term backups
+
+ /FORMAT=GO stores the data in record pairs. Each global node
+ produces one record for the key and one for the data. FORMAT=GO
+ has two header records.
+
+ /FORMAT=BINARY only applies for Greystone Technology Database
+ Structure (GDS) files. EXTRACT /FORMAT=BINARY works much faster
+ than EXTRACT /FORMAT=GO.
+
+ By default, EXTRACT uses /FORMAT=GO.
+
+/FREEZE
+ /FR[EEZE]
+ Prevents database updates to all regions of the Global Directory
+ used by the EXTRACT for the duration of the EXTRACT.
+
+ By default, EXTRACT does not freeze regions during operation.
+
+/LABEL
+ /LA[BEL]=text
+ Specifies a text string which becomes the first record in the
+ output file. Enclose labels containing punctuation or lowercase
+ labels in quotes (""). EXTRACT /FORMAT=BINARY truncates the
+ label text to 32 characters.
+
+ By default, EXTRACT uses the label "GT.M MUPIP EXTRACT".
+
+ For a description of the /FORMAT=BINARY header label, refer to
+ the subsequent section on EXTRACT /FORMAT=BINARY.
+
+/LOG
+ /[NO]LO[G]
+ Specifies whether or not to display a message on SYS$OUTPUT for
+ each global extracted. The message shows the number of global
+ nodes, the maximum subscript length and maximum data length for
+ each global.
+
+ By default, EXTRACT operates /LOG.
+
+2 Examples
+ EXTRACT Examples
+ Example:
+
+ $ MUPIP EXTRACT/NOLOG FL.GLO
+
+ This instructs EXTRACT to create the global output file, FL.GLO,
+ consisting of all global variables in the database, without
+ displaying statistics on a global-by-global basis. Because no label
+ is specified, the first record in FL.GLO contain "GT.M MUPIP
+ EXTRACT" as text.
+
+ Example
+
+ $ INIT MSA0: SPECIAL
+ $ MOUNT/INIT=CONT/BLOCK=4104 MSA0: SPECIAL
+ $ MUPIP EXTR/FO=BIN/SEL=("a22",M:Z)/LAB="SPSAVE" MSA0:SPEC.SVX
+
+ In this example, the first command initializes a magnetic tape with
+ the label SPECIAL. The second command mounts the tape with VMS
+ automatic volume initialization and a block size of 4104. The
+ magnetic tape block size of 4104 handles a database block of 4096
+ bytes. The MUPIP command instructs EXTRACT to create a BINARY
+ output file, SPEC.SVX, with the label SPSAVE. The file contains the
+ global ^a22, every global starting with the letters M through Y and
+ the global ^Z. EXTRACT displays statistics for each global.
+
+ Example
+
+ $ MUPIP EXTRACT/SELECT=DRG TT
+
+ This instructs EXTRACT to dump the global ^DRG to the device with
+ the logical name TT (normally the login terminal).
+
+1 HELP
+ H[ELP]
+ HELP provides online information about MUPIP commands and qualifiers.
+ HELP uses similar conventions to the VAX/VMS help facility.
+
+ The format of the HELP command is:
+
+ H[ELP] [options...]
+
+ The HELP command does not accept any qualifiers. Enter the MUPIP
+ command for which you want information at the Topic prompt. Use
+ <RETURN> or <CTRL Z> to leave the help facility.
+
+1 INTEG
+ I[NTEG]
+ The INTEG command performs an integrity check on a GDS database file.
+ INTEG operates on one or more regions in the current global directory
+ by suspending concurrent updates to those regions. INTEG of a single
+ file database without a Global Directory requires exclusive
+ (stand-alone) access to that file.
+
+ Use INTEG at the following times:
+
+ o Periodically - to insure ongoing integrity of database(s); frequent
+ INTEGs help catch integrity problems before they spread through the
+ database file
+
+ o After a crash - to insure the database was not corrupted
+
+ o When database errors are reported - to troubleshoot the problem
+
+ The format of the INTEG command is:
+
+ I[NTEG][/qualifier[...]] file-spec | region-list
+
+ The file-specification directly identifies the GDS file to INTEG. The
+ region-list identifies one or more regions that in turn identify GDS
+ files through the current Global Directory.
+
+ Always analyze errors reported by INTEG immediately to prevent further
+ corruption. Greystone strongly recommends fixing the following errors
+ as soon as they are discovered:
+
+ o Blocks incorrectly marked free - these may cause accelerating
+ damage when processes make updates to any part of the database
+ region.
+
+ o Integrity errors in an index block - these may cause accelerating
+ damage when processes make updates to that area of the database
+ region that uses the faulty index.
+
+ INTEG /FAST and the "regular" INTEG both report these errors. Other
+ database errors do not pose the threat of rapidly spreading problems
+ in GDS files, but if operations continue the errors may cause the
+ following:
+
+ o Invalid application operation due to "missing" data
+
+ o Process errors when a database access encounters an error
+
+ o Degrading application level integrity as a result of incomplete
+ update sequences caused by the prior symptoms
+
+ You must assess the type of damage, the risk of continued operations,
+ and the disruption of stopping normal operation for database repair.
+ For information on analyzing and correcting database errors, refer to
+ the "Database Integrity" chapter in the GT.M Administration and
+ Operations Guide.
+
+ <CTRL C> or <CTRL Y> aborts INTEG. Because INTEG does most of its
+ reporting at the end, aborting the process before it completes may not
+ give you all the information you need.
+
+2 /FAST
+ /FA[ST]
+ Specifies that INTEG checks only index blocks. INTEG /FAST does not
+ check data blocks. INTEG /FAST produces results dramatically faster
+ than a full INTEG. While INTEG /FAST is not a replacement for a
+ full INTEG, it very quickly detects the most dangerous structural
+ errors in a database.
+
+ The /FAST qualifier is incompatible with the /TN_RESET qualifier.
+
+ By default, INTEG checks all active index and data blocks in the
+ database.
+
+2 /REGION
+ /R[EGION]
+ Specifies that the INTEG parameter identifies one or more regions
+ rather than a database file.
+
+ INTEG /REGION does not require sole access to databases. Instead,
+ it freezes updates to the database during the check. The
+ region-list argument may specify more than one region of the
+ current Global Directory in a list separated with commas. Any
+ region-name may include the DCL wildcard characters * and %. INTEG
+ /REGION requires the logical name GTM$GBLDIR to specify a valid
+ Global Directory. For more information on defining GTM$GBLDIR,
+ refer to the "Global Directory Editor" chapter of the GT.M
+ Administration and Operations Guide.
+
+ Note: Because a KILL may briefly defer marking the blocks it
+ releases "free" in the bit maps, INTEG /REGION may report spurious
+ block incorrectly marked busy errors. Because block incorrectly
+ marked busy errors are benign, ignore these errors unless INTEG
+ consistently reports a block as incorrectly marked busy.
+
+ The /REGION qualifier is incompatible with the /FILE and /TN_RESET
+ qualifiers.
+
+ By default, INTEG operates /FILE.
+
+2 /FILE
+ /FI[LE]
+ Specifies that the parameter to the INTEG command is a
+ file-specification. INTEG /FILE requires exclusive (stand-alone)
+ access to a database file and does not require a Global Directory.
+ Because it has stand-alone access to the file, INTEG /FILE is able
+ to check reference counts.
+
+ The /FILE qualifier is incompatible with the /REGION qualifier.
+
+ By default, INTEG operates /FILE.
+
+2 /TN_RESET
+ /TN[_RESET]
+ Instructs an INTEG /FILE to reset the transaction number to one in
+ every database block currently holding valid data.
+
+ Transaction number overflow back to 0 disrupts the integrity of the
+ database.
+
+ The /TN_RESET qualifier is incompatible with the /BLOCK, /FAST,
+ /REGION and /SUBSCRIPT qualifiers.
+
+ By default, INTEG does not modify the block transaction numbers.
+
+2 /SUBSCRIPT
+ /S[UBSCRIPT]=subscript
+ Specifies a global or a range of keys to INTEG. Enclose the global
+ key in quotes ("") and identify a range by separating two
+ subscripts with a colon (:). /SUBSCRIPT limits map checking to
+ incorrectly marked free errors.
+
+ Use /SUBSCRIPT only if you know the path to the keys in the
+ subscript and have reason to believe the path is not damaged. If
+ the path is questionable or known to be damaged, use DSE to find
+ the block(s) and INTEG /BLOCK.
+
+ The /SUBSCRIPT qualifier is incompatible with the /BLOCK and
+ /TN_RESET qualifiers.
+
+ Use /FULL to have INTEG report all global-names covered by a range.
+
+2 Examples
+ INTEG /SUBSCRIPT= Examples
+
+ Example
+
+ MUPIP INTEG /SUBSCRIPT="^a" MUMPS.DAT
+
+ This INTEGs the global variable ^a in the database file MUMPS.DAT.
+
+ Example
+
+ MUPIP INTEG/SUBSCRIPT="^a(100)":"^b(""c"")"/reg $DEFAULT
+
+ This INTEGs all global variables greater than or equal to ^a(100)
+ and less than ^b("c") in the default region.
+
+ Note: To specify a literal in the command string, use double quotes
+ e.g., ^b(""c"").
+
+2 /BLOCK
+ /BL[OCK]=block-number
+ Specifies the block at which to start checking a sub-tree of the
+ database. /BLOCK limits map checking to incorrectly marked free
+ errors.
+
+ The /BLOCK qualifier is incompatible with the /SUBSCRIPT and
+ /TN_RESET qualifiers.
+
+2 /KEYRANGES
+ /[NO]K[EYRANGES]
+ Specifies whether or not the INTEG report includes key ranges that
+ identify the data suspected of problems detected by INTEG.
+
+ By default, INTEG displays /KEYRANGES.
+
+2 /MAP
+ /[NO]MAP[=integer]
+ Specifies the maximum number of incorrectly marked busy errors that
+ INTEG reports.
+
+ /NOMAP removes limits on incorrectly marked busy reporting, i.e.,
+ INTEG reports all map errors. /NOMAP does not accept assignment of
+ an argument.
+
+ Because incorrectly marked free errors are very dangerous, INTEG
+ always reports them, and /MAP does not affect them.
+
+ An error in an index block prevents INTEG from processing
+ potentially large areas of the database. A single "primary" error
+ may cause large numbers of "secondary" incorrectly marked busy
+ errors. Because "real" or primary incorrectly marked busy errors
+ only make "empty" blocks unavailable to the system, they are
+ relatively benign.
+
+ By default, INTEG reports a maximum of 10 map errors (/MAP=10).
+
+2 /MAXKEYSIZE
+ /[NO]MAX[KEYSIZE][=integer]
+ Specifies the maximum number of key size too large errors that
+ INTEG reports.
+
+ /NOMAXKEYSIZE removes limits on key size reporting, i.e., INTEG
+ reports all key size too large errors. /NOMAXKEYSIZE does not
+ accept assignment of an argument.
+
+ Key size too large error should only occur after someone uses DSE
+ CHANGE /FILEHEADER /KEY_MAX_SIZE to reduce the maximum key-size.
+
+ By default, INTEG reports a maximum of 10 key size errors
+ (/NOMAXKEYSIZE=10).
+
+2 /TRANSACTION
+ /[NO]TR[ANSACTION][=integer]
+ Specifies the maximum number of block transaction number too large
+ errors that INTEG reports.
+
+ /NOTRANSACTION removes limits on transaction reporting, i.e.,
+ INTEG reports all transaction number errors. /NOTRANSACTION does
+ not accept assignment of an argument.
+
+ A system crash may generate many block transaction number too large
+ errors. These errors can cause problems for BACKUP /INCREMENTAL,
+ but have no effect on the run-time environment. The DSE CHANGE
+ /FILEHEADER /BLOCKS_FREE= command quickly fixes block transaction
+ number too large number errors.
+
+ By default, INTEG reports a maximum of 10 block transaction errors
+ (/TRANSACTION=10).
+
+2 /BRIEF
+ /BR[IEF]
+ Specifies an INTEG summary report which displays the total number
+ of directory, index and data blocks. The /BRIEF qualifier is
+ incompatible with the /FULL qualifier.
+
+ By default, INTEG reports are /BRIEF.
+
+2 /FULL
+ /FU[LL]
+ Specifies an expanded INTEG report which displays the number of
+ index and data blocks in the directory tree and in each global tree
+ as well as the total number of directory, index and data blocks.
+ The /FULL qualifier is incompatible with the /BRIEF qualifier.
+
+ By default, INTEG reports are /BRIEF.
+
+2 /ADJACENCY
+ /A[DJACENCY]=integer
+ Specifies the range of blocks within which INTEG considers a block
+ adjacent to another database block on the same level. The adjacency
+ report from INTEG gives an approximation of physical data density
+ which directly affects efficient database access. Use the
+ /ADJACENCY qualifier to adjust the reporting to reflect
+ characteristics of your disks, e.g., pick a factor that matches the
+ number of sectors on a drive.
+
+ By default, INTEG uses /ADJACENCY=10.
+
+1 Jrnl_overview
+ Journaling overview
+ Journaling records an extra copy of information during database
+ updates in order to provide resiliency against hardware and software
+ failures. Journaling can reduce the "window of exposure" from some of
+ the most common types of failure: power loss and media loss due to
+ head-to-disk interference. Journals also provide a valuable tool in
+ cases of software errors and operational miscues. A journal file has
+ questionable value only in the case where the database and the journal
+ share a common point of failure that affects the information in both,
+ over a significant period of time. Therefore, using different disks
+ and, when possible, different disk controllers for the journal and the
+ database files improves the likelihood of the journal serving its
+ intended purpose.
+
+ The database management portion of a MUMPS implementation ensures that
+ multiple concurrent updates and retrievals of the same information (or
+ information "close together" in ordered sequence) are handled in a
+ predictable and logical fashion. The database manager may have to
+ change multiple records, usually indices, as a result of a single
+ update. Therefore, interrupting a process performing such a
+ "multi-point" update violates a design assumption of the MUMPS
+ implementation and results in a malformed database. Access to a
+ damaged area of the database does not produce the desired result.
+ Instead, such an "integrity" problem causes symptoms including system
+ hangs, misplaced updates, failure to find information that exists,
+ finding information out of sequence, and run-time errors. If the bad
+ records contain no valid information or redundant information, the
+ simplest cures for integrity errors entail deleting incorrectly
+ formatted records. However, sometimes crashes damage information of
+ value and, in any case, database repair requires time and skill. GT.M
+ journaling provides a means to recover or replace databases that have
+ integrity problems. Use of journaling at this "global" level requires
+ no MUMPS programming.
+
+ MUPIP and its documentation uses the term transaction to mean database
+ update. In journaling, the term transaction may refer to multiple
+ related database updates.
+
+2 Forward_Recovery
+ Forward Recovery
+ Forward Recovery consists of restoring a backup copy of the
+ database and applying the journal file to that database file. The
+ journal file contains copies of each database update. Forward
+ Recovery reads the entire journal file from beginning to end (in a
+ "forward" direction) and updates the backup copy of the database.
+ The optional MUPIP JOURNAL /BEFORE= qualifier specifies a journal
+ ending time that stops journal processing before the physical end
+ of the journal file. In general, Forward Recovery takes longer than
+ Backward Recovery. However, if the current database is somehow
+ destroyed, you must use Forward Recovery. Also, if a journal file
+ was created NOBEFORE_IMAGE with a MUPIP SET, that journal only
+ permits Forward Recovery.
+
+ Example of Forward Recovery:
+
+ MUPIP JOURNAL /RECOVER /FORWARD
+
+
+ /BEFORE
+ |
+ --------------------------------V-----------X--------->time
+ 10:30 10:32
+ �+++++++++++++++++++++++++++++++�+++++++++��
+
+
+ This shows a recovery after a system crash at 10:32, which
+ processes the entire journal file forward. If we add /BEFORE="--
+ 10:30" to the command, the recovery stops when processing
+ encounters updates that originally occurred after 10:30.
+
+2 Backward_Recovery
+ Backward Recovery
+ Backward Recovery works by processing from the end of the journal
+ file that contains information for the period just prior to the
+ failure event, thereby minimizing recovery time. Backward Recovery
+ uses "before-image" journaling. With "before-image" journaling,
+ GT.M captures the database updates, as well as "snap-shots" of
+ portions of the database immediately prior to the change caused by
+ the update. In effect, MUPIP JOURNAL=BEFORE_IMAGE creates
+ "mini-backups" preceding each database update. Backward Recovery
+ uses the mini-backups to restore the database as far back in time
+ as specified, then it goes forward in time replaying the database
+ updates. Using Backward Recovery with the MUPIP JOURNAL qualifiers
+ /BEFORE=, /SINCE=, and /LOOKBACK=, you can specify a block of time
+ to recover. JOURNAL /RECOVER /BACKWARD only works if the production
+ database is useable, and if the MUPIP SET command that created the
+ journal file specified the BEFORE_IMAGE characteristic.
+
+ Note: Before-images require more disk I/O and storage space.
+
+ Example of Backward Recovery:
+
+ MUPIP JOURNAL /RECOVER /BACKWARD /SINCE="-- 9:30"
+
+
+ /LOOKBACK_LIMIT
+ | /SINCE
+ | | /BEFORE
+ | | |
+ ----------------V-------V-------V------X--------->time
+ 9:30 10:30 10:32
+ <*******<++++++++++++++�
+ ********++++++++�++++++�
+
+
+
+ This shows a recovery after a system crash at 10:32. The recovery
+ "undoes" the database updates backward to 9:30 and then forward
+ until the crash. If we add /BEFORE="-- 10:30" to the command, the
+ recovery stops when forward processing encounters updates that
+ originally occurred after 10:30. If the application includes
+ ZTSTART and ZTCOMMIT commands to fence a group of transactions,
+ backwards processing may continue back prior to 9:30 searching to
+ resolve fenced transactions that were incomplete at 9:30. The
+ /LOOKBACK_LIMIT= qualifier controls the maximum amount of
+ additional backward processing.
+
+2 Fencing_Transactions
+ Fencing Transactions
+ Journaling without fences in MUMPS addresses the fact that a system
+ crash can damage the database integrity. However, sound design
+ frequently dictates modelling a single "real-world" event in
+ updates to more than one global variable. Such real-world events
+ are usually captured in a single data entry session and are
+ referred to as logical transactions. Therefore, interrupting a
+ process performing a "multi-node" logical transaction violates a
+ design assumption of the application and results in logical
+ inconsistencies in the database. Such logical inconsistencies
+ produce symptoms including run-time errors, inappropriate branching
+ and incorrect reports. Sometimes logical inconsistencies are
+ referred to as application-level database integrity problems.
+
+ Standard MUMPS does not yet include a method to identify the fact
+ that a single logical transaction may be made up of multiple global
+ updates. Therefore, a journal recovery that corrects database
+ integrity problems may perform an update that is part of an
+ incomplete sequence of updates intended as a single logical unit.
+
+ GT.M provides the MUMPS commands ZTSTART to mark the beginning of a
+ logical transaction and ZTCOMMIT to mark the end of a logical
+ transaction. When ZTSTART and ZTCOMMIT fence a logical transaction,
+ the journal recovery can refrain from starting an incomplete
+ update. To take advantage of this additional level of journaling
+ functionality, the application must use ZTSTART and ZTCOMMIT
+ commands.
+
+ Journaling does not require modification of application programs.
+ However, using ZTSTART and ZTCOMMIT to add transaction fences
+ around updates that comprise a logical unit significantly improves
+ the benefit of journaling. For instance, the logical transaction
+ "transfer funds between accounts" consists of a debit update to one
+ account and a credit update to another account. One of the updates
+ made without the other is not valid. When recovering from journal
+ files, JOURNAL processing recovers either all updates within the
+ transaction fences or none of them. MUPIP JOURNAL /RECOVER reports
+ the latter case during recovery.
+
+1 SET
+ SE[T]
+
+ MUPIP SET changes some database characteristics, such as whether a
+ specified file or region(s) have journaling activated. SET requires
+ sole access to the database. SET operates on either regions or files.
+
+ The format for the SET command is:
+
+ SE[T] /qualifier... file-spec or region-list
+
+ The file-specification or region-list identifies the target of the
+ SET. Region-names separated by commas (,) make up a region-list.
+ Region-names may include the DCL wildcards % and *. For a summary
+ table of MUPIP commands and qualifiers including MUPIP SET, refer to
+ the MUPIP chapter in the GT.M Administration and Operations Guide.
+
+2 Object_qualifiers
+ Object Qualifiers
+
+/FILE
+ /F[ILE]
+ Specifies that the argument contains a file-specification for a
+ single database file. The /FILE qualifier is incompatible with
+ the /REGION qualifier.
+
+/REGION
+ /R[EGION]
+ Specifies that the argument contains a region-name which,
+ through the mapping of the current Global Directory, identifies
+ a database file. SET /REGION modifies multiple files when the
+ parameter contains more than one name and/or wildcards. The
+ /REGION qualifier is incompatible with the /FILE qualifier.
+
+2 Action_qualifiers
+ Action Qualifiers
+
+/ACCESS_METHOD
+ /A[CCESS_METHOD]=BG or MM
+ Specifies the access method for a GDS database file. For
+ information on ACCESS_METHOD, refer to the "Global Directory
+ Editor" chapter of the GT.M Administration and Operations Guide.
+
+ By default, MUPIP CREATE establishes ACCESS_METHOD from
+ information entered in the Global Directory with GDE.
+
+/GLOBAL_BUFFERS
+ /G[LOBAL_BUFFERS]=integer
+ Specifies the number of cache buffers for a BG database. For
+ information on determining good working sizes of GLOBAL_BUFFERS,
+ refer to the "Global Directory Editor" chapter of the GT.M
+ Administration and Operations Guide.
+
+ The minimum is 64 buffers and the maximum is 4096 buffers. By
+ default, MUPIP CREATE establishes GLOBAL_BUFFERS from
+ information entered in the Global Directory with GDE.
+
+/JOURNAL
+ /[NO]J[OURNAL][=journal-option-list]
+ Specifies whether the database allows journaling and, if it
+ does, characteristics for the journal file.
+
+ /NOJOURNAL specifies that the database does not allow
+ journaling. /NOJOURNAL does not accept an argument assignment.
+ /NOJOURNAL does not create new journal files. When a database
+ has been SET /NOJOURNAL, it appears to have no journaling file
+ name or other characteristics.
+
+ /JOURNAL= enables journaling for a database file. /JOURNAL=
+ takes one or more arguments in a journal-option-list. Except
+ when used with the OFF option, SET /JOURNAL= always creates a
+ new version of the specified journal file(s). The
+ journal-option-list contains keywords separated with commas (,)
+ enclosed in parentheses (). When the list contains only one
+ keyword, the parentheses are optional.
+
+ For details on the list refer to the journal-option-list topic.
+
+2 journal-option-list
+ journal-option-list elements
+
+ The following topics detail the journal-option-list elements.
+
+3 ON
+ ON
+ ON specifies that MUPIP create a new journal file and that GT.M
+ record subsequent updates to the database in that journal file.
+ A SET /JOURNAL=ON must include either BEFORE_IMAGE or
+ NOBEFORE_IMAGE in the accompanying journal-option-list. When a
+ database has been SET /JOURNAL=ON, GT.M journals updates to that
+ file.
+
+ By default, SET /JOURNAL= turns journaling on.
+
+3 OFF
+ OFF
+ OFF specifies that GT.M not record subsequent updates to the
+ database in the journal file. OFF may also be used to set up
+ journaling characteristics without creating a journal file or
+ starting journaling. When a database has been SET /JOURNAL=OFF,
+ it has established journal characteristics ready to turn ON, but
+ GT.M does not journal updates to that file.
+
+ By default, SET /JOURNAL= turns journaling on.
+
+3 BEFORE_IMAGE
+ [NO]BE[FORE_IMAGE]
+ [NO]BEFORE_IMAGE controls whether the journal should capture
+ before-images of information that an update is about to modify.
+ MM databases must use NOBEFORE_IMAGE journaling. A SET
+ /JOURNAL=ON must include either BEFORE_IMAGE or NOBEFORE_IMAGE
+ in the accompanying journal-option-list.
+
+ A BEFORE_IMAGE journal permits the possibility of performing
+ "roll-back" recovery (i.e., Backward Recovery) of the associated
+ database. BEFORE_IMAGE increases the load on I/O and CPU
+ resources and therefore may affect performance.
+
+3 FILE_NAME
+ F[ILE_NAME]=file-specification
+ FILE_NAME=file-specification specifies the name of the journal
+ file. FILE_NAME is incompatible with SET /REGION.
+
+ Journal file-specifications are limited to 55 characters.
+
+ By default, MUPIP CREATE establishes the journal
+ file-specification from the Global Directory. If the Global
+ Directory does not contain a journal file-specification SET
+ /JOURNAL derives the journal file-specification from the
+ database file-specification using a file type of .MJL. Note that
+ because the default usually places the journal file on the same
+ disk drive as the database file, it does not protect well
+ against disk hardware failures.
+
+3 ALLOCATION
+ A[LLOCATION]=blocks
+ ALLOCATION=blocks specifies the initial size of the journal file
+ in RMS blocks. Because frequent journal file extensions degrade
+ run-time performance, make journal file allocation ample for a
+ production database.
+
+ The minimum ALLOCATION is 10 blocks and the maximum is
+ 16,777,216 blocks.
+
+ If journaling characteristics have not been previously
+ established by GDE or a prior SET /FILE /JOURNAL and a SET
+ /JOURNAL= specifies ALLOCATION but does not specify EXTENSION,
+ the command automatically changes EXTENSION to equal 10% of the
+ new ALLOCATION.
+
+ By default, MUPIP CREATE establishes the ALLOCATION from the
+ Global Directory, where the Greystone supplied default is 100
+ blocks. If the Global Directory does not contain ALLOCATION
+ information, SET /JOURNAL uses a default of 100 blocks.
+
+3 EXTENSION=blocks
+ E[XTENSION]=blocks
+ EXTENSION=blocks specifies the size by which a journal file
+ extends when it becomes full. EXTENSION=0 disables automatic
+ journal file extension. While this technique exerts firm control
+ over disk space consumption by a journal file, running out of
+ journal file space terminates journaling for the region. Because
+ frequent journal file extensions degrade run-time performance,
+ make the journal file extension ample for a production database.
+
+ The minimum EXTENSION is 0 blocks and the maximum is 65,536
+ blocks.
+
+ If journaling characteristics have not been previously
+ established by GDE or a prior SET /FILE /JOURNAL and a SET
+ /JOURNAL= specifies ALLOCATION but does not specify EXTENSION,
+ the command automatically changes EXTENSION to equal 10% of the
+ new ALLOCATION.
+
+ By default, MUPIP CREATE establishes the EXTENSION from the
+ Global Directory, where the Greystone-supplied default is 100
+ blocks. If the Global Directory does not contain EXTENSION
+ information and the SET /JOURNAL does not specify either
+ ALLOCATION or EXTENSION, MUPIP uses a default of 100 blocks.
+
+3 BUFFER_SIZE=pages
+ BU[FFER_SIZE]=pages
+ BUFFER_SIZE=pages specifies the amount of memory used to buffer
+ journal file output.
+
+ A larger BUFFER_SIZE usually smooths and improves run-time
+ performance by allowing larger, less frequent writes. On the
+ other hand, a larger BUFFER_SIZE requires more memory resources,
+ which may be scarce. A larger BUFFER_SIZE provides more room for
+ journal records in buffered memory and therefore increases the
+ number of update records that may be lost in a system failure.
+
+ The minimum BUFFER_SIZE is enough 512-byte pages to hold two GDS
+ database blocks and the maximum is 2000 pages.
+
+ By default, MUPIP CREATE establishes the BUFFER_SIZE from the
+ Global Directory, where the Greystone-supplied default is 128
+ pages. If the Global Directory does not contain BUFFER_SIZE
+ information, SET /JOURNAL uses a default of 128 pages.
+
+2 Examples
+ SET /JOURNAL Examples
+
+ Example
+
+ $ mupip set /file /journal=(nobefore,buff=128) cus.dat
+
+ This initiates journaling for the database file cus.dat. Because
+ the parameters include NOBEFORE, subsequent JOURNAL commands to
+ /RECOVER the database updates in the journal must specify /FORWARD.
+ The journal file created has the name cus.mjl.
+
+ Example
+
+ mupip set /region /journal=(before,alloc=50000,ext=5000) *
+
+ This enables journaling with BEFORE_IMAGES on all regions of the
+ current Global Directory and gives each journal an ALLOCATION of
+ 50000 RMS blocks and an EXTENSION of 5000 RMS blocks. If the
+ regions have significantly different levels of update, either set
+ the ALLOCATION and EXTENSION in the Global Directory before the
+ MUPIP CREATE(s) or use several MUPIP SET /FILE commands.
+
+ Example
+
+ mupip set /region /journal=before *
+
+ This declares journaling active with before-images for all regions
+ of the current Global Directory when they are next opened.
+
+ Example
+
+ mupip set /file /nojournal MUMPS.DAT
+
+ This disables journaling on the database file MUMPS.DAT in the
+ current default directory.
+
+1 JOURNAL
+ J[OURNAL]
+
+ The MUPIP JOURNAL command analyzes, extracts from, reports on, and
+ recovers journal files.
+
+ Another MUPIP command, SET, turns journaling on and off, identifies
+ the type of journaling, and sets some database journaling
+ characteristics.
+
+ The format for the JOURNAL command is:
+
+ MUPIP J[OURNAL] /qualifier[...] file-specification[,...]
+
+
+2 Action_qualifiers
+ Action Qualifiers
+
+/RECOVER
+ /REC[OVER]
+ Instructs the JOURNAL command to replay database updates in the
+ specified journal file into the appropriate database. /RECOVER
+ initiates the central JOURNAL operation. JOURNAL commands may
+ specify /RECOVER alone or with other action qualifiers.
+
+/VERIFY
+ /[NO]V[ERIFY]
+ Checks a journal file for proper form. JOURNAL commands may
+ specify /VERIFY alone or with other action qualifiers. JOURNAL
+ /RECOVER commands implicitly /VERIFY the file(s) on which they
+ operate. JOURNAL /RECOVER ignores /NOVERIFY for all qualifier
+ combinations that do not include /FORWARD and /FENCES=NONE.
+
+/EXTRACT
+ /EX[TRACT][=file-specification]
+ Specifies that JOURNAL transfer the contents of one or more
+ journal files to a single output file in a format intended for
+ processing by a MUMPS program. For a description of /EXTRACT
+ output record formats, refer to the section on JOURNAL /EXTRACT
+ output records. JOURNAL commands may specify /EXTRACT alone or
+ with other action qualifiers.
+
+ /EXTRACT takes an optional argument, which provides an output
+ file-specification.
+
+ By default, MUPIP JOURNAL derives the output file specification
+ using the name of the original database file associated with the
+ journal and a file type of .MJF. If the command specifies more
+ than one journal file, JOURNAL /EXTRACT derives the default
+ output file specification from the name of the first database.
+
+/SHOW
+ /SH[OW]=show-option-list
+ Specifies what information the JOURNAL command displays about a
+ journal file. JOURNAL commands may specify /SHOW alone or with
+ other action qualifiers.
+
+ For information on the options refer to the show-option-list
+ topic.
+
+2 show-option-list
+ show-option-list
+
+ The following topics detail the show-option-list elements.
+
+3 ALL
+ AL[L]
+ ALL displays every available type of information about the
+ journal file. For additional information, refer to the
+ descriptions of each of the other SHOW keywords.
+
+3 HEADER
+ H[EADER]
+ HEADER displays the journal file header information.
+
+ This includes:
+
+ o Database file name
+
+ o Journal file name
+
+ o Journal file version label (.e.g. GDSJNLnn)
+
+ o Whether before-images were captured
+
+ o Journal creation time/date
+
+ o Journal creator
+
+ o The last user to open the journal
+
+ o The last time the journal file was opened
+
+ The information for the creator and last user includes:
+
+ o Process Name
+
+ o Process Identification Number
+
+ o Node Name
+
+ o Terminal Number
+
+ o Login date and time
+
+3 PROCESSES
+ P[ROCESSES]
+ PROCESSES displays all processes active during the period
+ specified implicitly or explicitly by JOURNAL command time
+ qualifiers.
+
+3 ACTIVE_PROCESSES
+ AC[TIVE_PROCESSES]
+ ACTIVE_PROCESSES displays all processes active at the end of the
+ period specified implicitly or explicitly by JOURNAL command
+ time qualifiers.
+
+3 BROKEN_TRANSACTIONS
+ B[ROKEN_TRANSACTIONS]
+ BROKEN_TRANSACTIONS displays all processes that had incomplete
+ fenced transactions at the end of the period covered by the
+ JOURNAL command.
+
+3 STATISTICS
+ S[TATISTICS]
+ STATISTICS displays a count of all journal record types
+ processed during the period specified implicitly or explicitly
+ by JOURNAL command time qualifiers.
+
+2 Direction_qualifiers
+ Direction Qualifiers
+
+/FORWARD
+ /FO[RWARD]
+ Specifies that JOURNAL processing should proceed from the
+ beginning of the given journal files. If the actions include
+ /RECOVER, the target database file should contain a copy of that
+ database made at the time when MUPIP SET /JOURNAL= created the
+ journal files.
+
+ /FORWARD is incompatible with /BACKWARD.
+
+/BACKWARD
+ /BA[CKWARD]
+ Specifies that JOURNAL processing should proceed from the end of
+ the journal files. If the actions include /RECOVER, JOURNAL
+ /BACKWARD starts restoring before-images starting at the end of
+ the file, back to an explicitly or implicitly specified point
+ before it "reverses" and processes database updates in the
+ forward direction. The target database file should "match" the
+ end of the journal file, i.e., be the same as when GT.M wrote
+ the last record of the journal.
+
+ /BACKWARD is incompatible with /FORWARD.
+
+2 Time_qualifiers
+ Journal time specifications
+ Journal qualifiers specifying time take arguments in VMS absolute
+ or delta time format. Enclose time arguments in quotes ("") and
+ include all leading delimiters. Absolute format is "day-mm-yyyy
+ hh:mm:ss:cc" , where cc represents hundredths of a second. Absolute
+ time may indicate today's date with "--" before the hours. Delta
+ format is "day hh:mm:ss:cc" , where cc represents hundredths of a
+ second. If delta time is less than a day, it must start with zero
+ (0) followed by a space, or just a space, before the hours. For
+ information on how to specify the time, refer to the VAX/VMS System
+ Services Manual.
+
+ Delta time is always relative to the time of the last record in all
+ journal file arguments to the MUPIP JOURNAL command. A normal
+ database closure, caused by the last accessing process leaving
+ GT.M, also properly closes the associated journal file.
+ Alternatively, a system failure causes the journal to end in an
+ abnormal or "disorganized" fashion. JOURNAL processing deals with
+ both cases.
+
+ The time qualifiers perform as follows:
+
+ o /AFTER= only applies to JOURNAL /EXTRACT /FORWARD and specifies
+ a starting time; processing for all other /FORWARD actions must
+ start at the beginning of the journal files
+
+ o /BEFORE= specifies an ending time for any action /FORWARD or
+ /BACKWARD
+
+ o /SINCE= specifies a starting time for any action /BACKWARD
+
+ o /LOOKBACK_LIMIT= specifies a "safety zone" for resolving open
+ fenced transactions when processing any action /BACKWARD; the
+ /LOOKBACK_LIMIT= argument may be a list of limits: "TIME=time"
+ and/or "OPERATIONS=integer"
+
+ Because GT.M rounds time-stamps within the journal to hundredths of
+ a second and the JOURNAL processing can only determine time as
+ exactly as the journal records permit, the JOURNAL command
+ processes specified times in a "fuzzy" fashion. Because they deal
+ with processing completed logical transactions, /SINCE= and
+ /LOOKBACK= times have more "blur" than /AFTER= and /BEFORE= times.
+
+/AFTER
+ /A[FTER]=time
+ Specifies the starting time for JOURNAL /EXTRACT /FORWARD to
+ commence output. The time specified references time stamps in
+ the journal and identifies the point after which JOURNAL
+ processing starts extracting information out of the journal
+ file. /AFTER= specifies time in VMS absolute or delta time
+ formats. Delta format specifies an offset from the time of the
+ last record of the journal file. If /AFTER= provides a time
+ following the last time recorded in the journal file or
+ following any /BEFORE= time, JOURNAL processing produces no
+ result. Using /BEFORE= with /AFTER= restricts /EXTRACT to a
+ particular period of time.
+
+ /AFTER= is incompatible with /BACKWARD and with all action
+ qualifiers except /EXTRACT.
+
+ By default, /EXTRACT starts at the beginning of the journal
+ file.
+
+/BEFORE
+ /BE[FORE]=time
+ Specifies the ending time at which JOURNAL processing stops
+ extracting or recovering data. The time specified references
+ time stamps in the journal files. /BEFORE= specifies time in VMS
+ absolute or delta time formats. Delta format specifies an offset
+ from the time stamp in the last record of each the journal file.
+ If /BEFORE= provides a time preceding the first time recorded in
+ the journal file or preceding any /AFTER= or /SINCE= time,
+ JOURNAL processing produces no result.
+
+ /BEFORE= is compatible with all other JOURNAL qualifiers.
+
+ By default, JOURNAL processing terminates at the end of the
+ journal file.
+
+/SINCE
+ /SI[NCE]=time
+ Specifies how far back in time JOURNAL /BACKWARD should process
+ from the end of the journal file, before starting its forward
+ processing. The time specified references time stamps in the
+ journal files. /SINCE= specifies time in VMS absolute or delta
+ time formats. Delta format specifies an offset from the time of
+ the last record of the journal file. When JOURNAL /BACKWARD
+ locates the /SINCE= time, if it has open fenced transactions, it
+ continues processing backward to resolve them unless the command
+ also specifies /FENCES=NONE. The /LOOKBACK= qualifier controls
+ the length of processing backward past the /SINCE= time.
+
+ If /SINCE= time exceeds the last time recorded in the journal
+ files, JOURNAL processing effectively ignores the qualifier.
+ /SINCE= is incompatible with /FORWARD. If /SINCE= provides a
+ time preceding any /BEFORE= time, JOURNAL processing produces no
+ result.
+
+ By default, JOURNAL /BACKWARD processes the last five (5)
+ minutes of the journal file(s).
+
+/LOOKBACK_LIMIT
+ /[NO]LOO[KBACK_LIMIT][=lookback-option-list]
+ Specifies how far JOURNAL /BACKWARD processes back past the
+ explicit (/SINCE=) or implicit turn around time while attempting
+ to resolve open transaction fences. /LOOKBACK= options include
+ time and transaction counts.
+
+ /NOLOOKBACK_LIMIT specifies that JOURNAL /BACKWARD can process
+ all the way to the beginning of the journal file, if necessary,
+ to resolve open transaction fences.
+
+ /LOOKBACK_LIMIT= is incompatible with /FORWARD. When
+ /FENCES=NONE, JOURNAL processing ignores /LOOKBACK_LIMIT=.
+
+ The lookback-options are:
+
+ TIME=time limits lookback by a specified amount of
+ delta or absolute journal time
+
+ OPERATIONS=integer limits lookback to some number of database
+ updates
+
+ The lookback-option names and values must be enclosed in quotes
+ (""), e.g., "Time=0 00:05" or "Oper=10." When /LOOKBACK=
+ specifies both options, they must be enclosed in parentheses ()
+ and separated by a comma (,). When /LOOKBACK= specifies both
+ options, the first limit reached terminates the lookback.
+
+ By default, MUPIP JOURNAL uses /LOOKBACK_LIMIT="TIME=0 00:05"
+ providing five minutes of journal time prior to /SINCE= in which
+ to resolve open fences.
+
+2 Control_qualifiers
+ Control Qualifiers
+
+/REDIRECT
+ /RED[IRECT]=file-pair-list
+ Specifies that JOURNAL /RECOVER replay the journal file to a
+ database different than the one for which it was created. Use
+ this qualifier to create or maintain databases for training or
+ testing.
+
+ JOURNAL rejects /REDIRECT unless it appears with /RECOVER.
+
+ The file-pair-list consists of one or more pairs of
+ file-specifications enclosed in parentheses () and separated by
+ commas (,). The pairs are separated by an equal sign in the
+ form:
+
+ old-file-specification=new-file-specification
+
+ where the first file-specification names the original database
+ file and the second file-specification names the target of the
+ /RECOVER. When /REDIRECT specifies only one file pair, the
+ parentheses are optional.
+
+ By default, JOURNAL directs /RECOVER to the database file from
+ which the journal was made.
+
+/FENCES
+ /FE[NCES]=fence-option
+ Specifies how JOURNAL processes fenced transactions. Fenced
+ transactions are logical transactions made up of database
+ updates preceded in MUMPS by a ZTSTART command and followed by a
+ ZTCOMMIT command. All updates between a ZTSTART and a ZTCOMMIT
+ are designed such that they should all occur together, i.e., no
+ one of them should reach the database unless they all do.
+
+ The fence options are:
+
+ o NONE, which causes JOURNAL to apply all individual updates as
+ if transaction fences did not exist
+
+ o ALWAYS, which causes JOURNAL to treat any unfenced or
+ improperly fenced updates as errors
+
+ o PROCESS, which causes JOURNAL to accept unfenced database
+ updates, and also to observe fences when they appear,
+ generating an error in the case of a ZTSTART with no
+ corresponding ZTCOMMIT
+
+ By default, MUPIP JOURNAL uses /FENCES=PROCESS.
+
+/INTERACTIVE
+ /[NO]IN[TERACTIVE]
+ Specifies whether, for each error over the /ERROR_LIMIT, JOURNAL
+ processing prompts the invoking operator for an answer
+ controlling continuation of processing. If the operator responds
+ that processing should not continue, the JOURNAL command
+ terminates.
+
+ /NOINTERACTIVE terminates the journal processing as soon as the
+ process generates the number of errors specified in
+ /ERROR_LIMIT.
+
+ When processing in INTERACTIVE mode, the default is
+ /INTERACTIVE, otherwise, e.g., BATCH mode, the default is
+ /NOINTERACTIVE.
+
+/ERROR_LIMIT
+ /[NO]ER[ROR_LIMIT][=integer]
+ Specifies the number of errors that JOURNAL processing treats as
+ acceptable. When the number of errors exceeds the /ERROR_LIMIT,
+ the /INTERACTIVE qualifier determines whether JOURNAL processing
+ halts or defers to the operator.
+
+ /NOERROR_LIMIT prevents JOURNAL from stopping because of errors.
+ Journal processing will continue until it reaches the end of the
+ journal file, regardless of the number of errors. Note that
+ /NOERROR_LIMIT is not the same as /ERROR_LIMIT=0.
+
+ By default, MUPIP JOURNAL uses /ERROR_LIMIT=0, causing the first
+ error to initiate the appropriate error action.
+
+/LOG
+ /[NO]LOG[=file-specification]
+ Specifies whether JOURNAL reports its actions as it performs
+ them. /NOLOG suppresses JOURNAL messages.
+ /LOG=file-specification specifies the name of a log file.
+
+ By default, MUPIP JOURNAL uses /LOG=SYS$OUTPUT.
+
+/CHECKTN
+ /[NO]C[HECKTN]
+ /CHECKTN specifies that JOURNAL /FORWARD must ensure that the
+ first database update in the journal file has the next
+ transaction number after the current transaction in the database
+ file.
+
+ /NOCHECKTN suppresses checking of the starting journal
+ transaction against the ending database transaction number.
+
+ /CHECKTN is incompatible with the /BACKWARD qualifier.
+
+ By default, JOURNAL /FORWARD uses /CHECKTN.
+
+2 Selection_qualifiers
+ Selection Qualifiers
+
+/GLOBAL
+ /G[LOBAL]=global-list
+ Specifies globals for JOURNAL to include or exclude from
+ processing. You may find this qualifier useful for extracting
+ and analyzing specific data.
+
+ The global-list contains names of one or more global-names (not
+ including subscripts) preceded by "^" enclosed in parentheses ()
+ and separated by commas (,). If /GLOBAL specifies only one item,
+ the parentheses are optional. The names may include the DCL
+ wildcards % and *. However, to allow specification of global
+ names starting with a "percent" (%), MUPIP JOURNAL does not
+ interpret the first character in a global-name as a wildcard.
+ The entire list or each name may optionally be preceded by a
+ minus (-), requiring JOURNAL to exclude database updates that
+ update the specified global(s). When the global-list with a
+ JOURNAL /GLOBAL does not start with a minus, JOURNAL processes
+ only the explicitly named globals.
+
+ By default, JOURNAL processes all globals.
+
+/USER
+ /U[SER]=user-list
+ Specifies that JOURNAL processing include or exclude database
+ updates generated by one or more users. You may use this
+ qualifier to "back-out" database updates erroneously entered by
+ a specific user.
+
+ The user-list contains names of one or more users enclosed in
+ parentheses () and separated by commas (,). If /USER specifies
+ only one item, the parentheses are optional. The names may
+ include the DCL wildcards % and *. The entire list or each name
+ may optionally be preceded by a minus (-), requiring JOURNAL to
+ exclude database updates initiated by the specified user(s).
+ When the user-list with a JOURNAL /USER does not start with a
+ minus, JOURNAL processes only database updates generated by the
+ explicitly named users.
+
+ By default, JOURNAL processes database updates regardless of the
+ user by which they were initiated.
+
+/ID
+ /ID=pid-list
+ Specifies that JOURNAL processing include or exclude database
+ updates generated by one or more processes, identified by
+ process identification numbers (PIDs) in hexadecimal. You may
+ use this qualifier for troubleshooting or analysis of data.
+
+ The pid-list contains one or more PIDs enclosed in parentheses
+ () and separated by commas (,). If /ID specifies only one item,
+ the parentheses are optional. The entire list or each PID may
+ optionally be preceded by a minus (-), requiring JOURNAL to
+ exclude database updates associated with the specified PID(s).
+ When the pid-list with a JOURNAL /ID does not start with a
+ minus, JOURNAL processes only database updates associated with
+ the explicitly listed PIDs.
+
+ By default, JOURNAL processes database updates regardless of the
+ process by which they were initiated.
+
+/PROCESS
+ /P[ROCESS]=process-name-list
+ Specifies that JOURNAL processing include or exclude database
+ updates generated by one or more processes, identified by names.
+ You may use this qualifier to extract specific process-related
+ data for testing or troubleshooting.
+
+ The process-name-list contains names of one or more processes
+ enclosed in parentheses () and separated by commas (,). If
+ /PROCESS specifies only one item, the parentheses are optional.
+ The names may include the DCL wildcards % and *. The entire list
+ or each process-name may optionally be preceded by a minus (-)
+ requiring JOURNAL to exclude database updates associated with
+ the specified process name(s). When the process-name-list with a
+ JOURNAL /PROCESS does not start with a minus, JOURNAL processes
+ only database updates associated with the explicitly named
+ processes.
+
+ By default, JOURNAL processes database updates regardless of the
+ process by which they were initiated.
+
+/TRANSACTION
+ /T[RANSACTION]=transaction-type
+ Specifies transaction-types for JOURNAL to include or exclude
+ from processing. For example, you may use this qualifier to
+ exclude KILL transactions and prevent an accidental KILL from
+ reoccurring during replay.
+
+ The transaction-types are:
+
+ SET
+
+ KILL
+
+ These types correspond to the MUMPS commands of the same names.
+ The transaction-type may optionally be preceded by a minus (-)
+ requiring JOURNAL to exclude transactions of the specified type.
+ When the transaction-type with a JOURNAL /TRANSACTION does not
+ start with a minus, JOURNAL processes only transactions of the
+ explicitly named type.
+
+ By default, JOURNAL processes transactions regardless of type.
+
+2 Examples
+ Journal Examples
+
+ Example
+
+ $ copy sys$dat:cus.dat []
+ $ mupip journal /recover /forward /fences=none cus.mjl
+
+ The COPY statement copies a backup copy of the database for use in
+ recovery. The MUPIP JOURNAL command recovers the database using the
+ cus.mjl journal file. The JOURNAL command processes the journal
+ file in a forward direction (from the beginning of the journal).
+ The /FENCES=NONE directs JOURNAL to ignore any fences and recover
+ all individual updates.
+
+ Example
+
+ $ mupip set /file /journal=(before,buff=128) cus.dat
+ $ mupip set /file /journal=(before,buff=128) acc.dat
+ ...
+ $ mupip journal/recover/verify/back/error=2 cus.mjl,acc.mjl
+
+ The first two command lines initiate journaling for the two
+ specified database files. MUPIP JOURNAL does not accept wildcards
+ in database file names. Because the MUPIP SET command specifies
+ JOURNAL=BEFORE, subsequent JOURNAL /RECOVER may have either
+ /FORWARD or /BACKWARD direction. The last line contains the command
+ to recover the two database files using the two specified journal
+ files. The journal recover processes in a BACKWARD direction using
+ before-image processing. If JOURNAL processing encounters two or
+ more errors (/ERROR=2), the recovery process terminates.
+
+ Example
+
+ $ mupip journal/forw/befo="-- 10:30"/glob="^bv%r*"/extr=bv cus.mjl
+
+ This command line extracts database updates that occurred from the
+ beginning of the journal until 10:30 to global variables with the
+ prefix ^bv , followed by some character, followed by r, optionally
+ followed by more characters. The JOURNAL /EXTRACT places the
+ updates in a file called bv.mjf
+
+ Because the command does not specify an extension, JOURNAL assigns
+ the default extension .mjf to the output file.
+
+ Example
+
+ $ mupip jour/rec/back/befo="-- 10:30"/since="-- 9:30" -
+ /lookback="time=0 00:05" cus.mjl
+
+ This command line performs a /RECOVERY /BACKWARD of the database
+ file that corresponds to the journal file cus.mjl. JOURNAL
+ /RECOVER processes from the journal time 9:30 to journal time
+ 10:30. If the JOURNAL finds open fenced transactions, it "looks
+ back" an additional five minutes to resolve them. The /BEFORE= and
+ /SINCE= qualifiers in this example use absolute time. Because the
+ time specification omits the date, JOURNAL assumes today's date.
+
+2 extract_formats
+ JOURNAL /EXTRACT formats
+ EXTRACT output records are constructed of fields or "pieces"
+ delimited by back-slashes (\).
+
+ The first piece of an EXTRACT output record always contains the
+ two-digit decimal transaction record type, e.g., 01 for a process
+ initialization record.
+
+ The second piece always contains the full date and time of
+ operation, represented in $HOROLOG-format, with decimal seconds,
+ e.g., 54271,44580.55.
+
+ The third piece always contains the process id (PID) of the process
+ that performed the operation, represented as a decimal number. The
+ remainder of the record depends on the record type.
+
+ The fields described as "database transaction number" contain a
+ GT.M assigned number that is unique within the journal file.
+
+3 proc_initialization
+ Process Initialization Record
+ A type 1 record indicates an image-initiated contact with the
+ GT.M database region for the first time. The format for a
+ process initialization record is:
+
+ 01\time\pid\pnam\nnam\unam\mode\term\ltim\icnt
+
+ where
+
+ time full time/date
+
+ pid process id
+
+ pnam process name
+
+ nnam node name
+
+ unam user name
+
+ mode process mode, i.e., $zgetjpi("jobtype")
+
+ term terminal name
+
+ ltim process login time/date
+
+ icnt process image count
+
+3 proc_termination
+ Type 2 - Process Termination Record
+ A type 2 record indicates an image terminated and dropped
+ interest in the GT.M database region. The format for a process
+ termination record is:
+
+ 02\time\pid\pnam\nnam\unam\mode\term\ltim\icnt
+
+ where
+
+ time full time/date
+
+ pid process id
+
+ pnam process name
+
+ nnam node name
+
+ unam user name
+
+ mode process mode, i.e., $zgetjpi("jobtype")
+
+ term terminal name
+
+ ltim process login time/date
+
+ icnt process image count
+
+ tnum database transaction number
+
+3 end_of_file
+ Type 3 - End of File Record
+ A type 3 record indicates all GT.M images dropped interest in
+ the region and the journal file was closed normally. The format
+ for an end-of-file record is:
+
+ 03\time\pid\pnam\nnam\unam\mode\term\ltim\icnt\tnum
+
+ where
+
+ time full time/date
+
+ pid process id
+
+ pnam process name
+
+ nnam node name
+
+ unam user name
+
+ mode process mode, i.e., $zgetjpi("jobtype")
+
+ term terminal name
+
+ ltim process login time/date
+
+ icnt process image count
+
+ tnum database transaction number
+
+3 Kill
+ Type 4 - Kill Record
+ A type 4 record indicates a database update caused by a KILL
+ command. The format for a KILL record is:
+
+ 04\time\pid\tnum\node
+
+ where
+
+ time full time/date
+
+ pid process id
+
+ tnum database transaction number
+
+ node a MUMPS node reference in external format
+
+3 Set
+ Type 5 - Set Record
+ A type 5 record indicates a database update caused by a SET
+ command. The format for a SET record is:
+
+ 05\time\pid\tnum\sarg
+
+ where
+
+ time full time/date
+
+ pid process id
+
+ tnum database transaction number
+
+ sarg a MUMPS set argument
+
+ Note a MUMPS SET argument has a node reference followed by an
+ equal-sign (=) and MUMPS data string expression.
+
+3 tr_start
+ Type 6 - Transaction Start Record
+ A type 6 record indicates a ZTSTART command. The format for a
+ transaction start record is:
+
+ 06\time\pid
+
+ where
+
+ time full time/date
+
+ pid process id
+
+3 tr_commit
+ Type 7 - Transaction Commit Record
+ A type 7 record indicates a ZTCOMMIT command. The format for a
+ transaction commit record is:
+
+ 07\time\pid\tnum\part
+
+ where
+
+ time full time/date
+
+ pid process id
+
+ tnum database transaction number
+
+ part number of journal entries in the transaction
+
+1 Jrnl_examples
+ The following examples present a typical use of database
+ journaling to prevent loss of data. In our examples the database
+ consists of three regions, ACC, MAIN, and TMP, mapped
+ respectively to files USER:[PROD]ACC.DAT, USER:[PROD]MUMPS.DAT
+ and USER:[PROD]TMP.DAT.
+
+2 Setting_Database_Regions_for_Journaling
+ We assume that region TMP holds only process-local data, and,
+ therefore, does not require backups or journaling. We assume, on
+ the other hand, that regions ACC and MAIN hold production
+ application data that should be protected by journaling.
+ Moreover, our application requires a high degree of
+ availability. Therefore, we set up journaling with BEFORE_IMAGES
+ for regions ACC and MAIN. The BEFORE_IMAGES allow for JOURNAL
+ RECOVER /BACKWARD, which generally works faster than JOURNAL
+ RECOVER /FORWARD. Because both our journaled regions map to the
+ database files on device USER:, we choose a different disk with
+ a different controller to accommodate the journal files. This
+ choice improves resiliency against hardware failures.
+
+ Example
+
+ $ mupip set /region/journal=(off,buff=200,file=JNL:[PROD]ACC)
+ ACC
+ $ mupip set/region/journal=(off,buff=200,file=JNL:[PROD]MAIN)
+ MAIN
+
+ These commands must be issued when the database files are
+ available for exclusive (stand-alone) access. They establish
+ several journal characteristics. The example increases the
+ journal buffer size from the default of 128 pages to 200 pages.
+
+2 Journal_Maintenance
+ First backup the database files. Thencreate and initialize new
+ journal files.
+
+ Example
+
+ $ mupip backup ACC,MAIN USR$BCK:[051590]
+ $ mupip set /region /journal=(on,before) ACC,MAIN
+ $ purge JNL:[PROD]*.MJL
+
+ This sequence of commands backs up the database files to disk,
+ initializes new journal files for each and purges the old
+ journal files. MUPIP BACKUP can operate without exclusive access
+ to the database files by freezing all updates. However, in order
+ to ensure that the BACKUP captures an application state matching
+ the beginning of the journal files, it should run stand-alone.
+
+ Some applications with high rates of updates may create
+ considerable amount of journaling data. To save the disk space,
+ you may archive journal files to magnetic tapes until the next
+ database backup. Before archiving a journal file, first create a
+ new one.
+
+ Example
+
+ $ mupip set /file /journal=(on,before) ACC.DAT
+ $ backup []ACC.MJL;-1 MSA0:051590JNL.BCK /save_set
+ $ purge JNL:[PROD]ACC.MJL
+
+ This sequence creates a new journal file, backs up the old
+ journal file to the tape and finally, purges the old file.
+ Notice that the MUPIP SET requires exclusive access to the
+ database file to ensure that the old journal stops and the new
+ journal starts with consistent transaction states.
+
+2 Recovery_from_Journal_Files
+ Because we set up our databases with BEFORE_IMAGE journaling,
+ when both the database and journal files are available after a
+ failure event, we can use JOURNAL /RECOVER /BACKWARD.
+
+ Example
+
+ $ delete user:[prod]tmp.dat.
+ $ mupip create /region=tmp
+ $ mupip journal/reco/show/back/nointer JNL:[PROD]ACC,MAIN
+ $ mupip integ /region *
+
+ This first deletes and recreates TMP.DAT. The MUPIP JOURNAL
+ command includes the /SHOW qualifier to generate a report on the
+ status of activity in the journal files. It also includes the
+ /NOINTERACTIVE qualifier to prevent operator interaction when
+ JOURNAL processing encounters an error. By default, this JOURNAL
+ /RECOVER has an implicit /ERROR_LIMIT=0, which causes the first
+ broken transaction to terminate processing. In addition to
+ checking database integrity, the MUPIP INTEG /REGION acts as the
+ first database access after the recovery and, if the old journal
+ file terminates improperly, creates a new journal file. Unlike
+ INTEG /REGION, the command MUPIP INTEG /FILE does not initialize
+ a new journal file. However, if the old journal file has damage,
+ any other access to the data base creates a new version. If
+ MUPIP JOURNAL /RECOVER reports broken transactions during
+ recovery, reenter the transactions.
+
+ If the databases were lost, for instance due to a disk drive
+ failure, we would have to use JOURNAL /RECOVER /FORWARD after
+ replacing the drive and retrieving backups of the databases.
+ This recovery may take much longer than backward recovery,
+ depending on the amount of data in the journal.
+
+ Example
+
+ $ delete USER:[PROD]*.DAT;*
+ $ backup USR$BCK:[051590]ACC.DAT USER:[PROD]
+ $ backup USR$BCK:[051590]MUMPS.DAT USER:[PROD]
+ $ mupip journal /reco /forw /err=5 JNL:[JNL]ACC,MAIN
+ $ mupip create /region=TMP
+ $ mupip integ /region /fast *
+
+ This sequence of commands recreates the databases to the point
+ of the last backup. Then it recovers all updates from the
+ journal files. The /ERROR_LIMIT= qualifier causes JOURNAL
+ /RECOVER to attempt processing through up to five (5) errors. By
+ default, when the JOURNAL /RECOVER executes in batch, processing
+ terminates after five errors. However if the command executes
+ interactively, after five errors, MUPIP JOURNAL prompts the the
+ operator at the invoking terminal to choose between continuing
+ or terminating. Also by default, the JOURNAL /RECOVER command
+ implies a /VERIFY, causing a check of the journal prior to
+ /RECOVER processing. The commands up to this point require
+ exclusive (stand-alone) access to the database files. MUPIP
+ INTEG /REGION verifies the integrity of the recovered database.
+ If the journal was not properly closed, the INTEG /REGION also
+ creates a new version of the journal file. Because the databases
+ are large, we use the /FAST qualifier on the INTEG. Because
+ INTEG freezes all updates and we wish to ensure database
+ integrity before going back into production, we continue to
+ restrict access to the database until the INTEG completes. Once
+ the database has been verified, we can resume work. One of the
+ first items of business should be to reenter any broken
+ transactions.
+
+ Should the system crash again and something such as a hard disk
+ failure prevent backward recovery, we must recover the database
+ forward, twice. First, restore the database from backup, then
+ recover to the point of the first crash, finally, recover from
+ that point to the point of the second crash. To recover
+ transactions in their proper order, include the file versions.
+ Notice that it is not necessary to reenter the broken
+ transactions after the first recovery because the current
+ version of the journal file contains those transactions.
+
+ Example
+
+ $ delete *.DAT;*
+ $ mupip restore ACC.DAT USR$BCK:[051590]ACC.BCK
+ $ backup USR$BCK:[051590]ACC.DAT USER:[PROD]
+ $ backup USR$BCK:[051590]MUMPS.DAT USER:[PROD]
+ $ mupip journal/reco/veri/forw/err=5
+ JNL:[JNL]ACC.MJL;-1,MUMPS.MJL;-1
+ $ mupip journal/reco/veri/forw/err=5 JNL:[JNL]ACC.MJL,MUMPS.MJL
+ $ mupip create /region=TMP
+ $ mupip integ /region /fast *
+
+ This is similar to the previous example, however, this sequence
+ recovers the database regions from two consecutive journal
+ files.
+
+
+1 LOAD
+ L[OAD]
+ LOAD enters global variable names and their corresponding data values
+ into a GT.M database from a sequential file. LOAD uses the Global
+ Directory to determine which database files to use. LOAD may operate
+ concurrently with normal GT.M database access. However, a LOAD does
+ not use MUMPS LOCKs and therefore may produce application-level
+ integrity problems if run concurrently with many applications.
+
+ The format of the LOAD command is:
+
+ L[OAD] [qualifier...] file-specification
+
+ LOAD takes its input from the file defined by the file-specification.
+
+ <CTRL C> produces a status message from LOAD. <CTRL Y> aborts LOAD. A
+ LOAD terminated abnormally by operator action or error is incomplete
+ but does not adversely affect the database structure.
+
+2 /FORMAT
+ /FO[RMAT]=keyword
+ Specifies the format of the input file. The format must match the
+ actual format of the input file for LOAD to operate.
+
+ The format codes are:
+
+ GO - Global Output format
+
+ B[INARY] - Binary format
+
+ GOQ - Format produced by certain MUMPS implementations
+
+ By default, LOAD uses /FORMAT=GO.
+
+3 GO
+ /FORMAT=GO
+ /FORMAT=GO stores the data in record pairs. Each global node produces
+ one record for the key
+ and one for the data. /FORMAT=GO has two header records, therefore
+ LOAD /FORMAT=GO
+ starts active work with record number three (3).
+
+3 BINARY
+ /FORMAT=BINARY
+ /FORMAT=BINARY only applies for Greystone Technology Database
+ Structure (GDS) files. A
+ BINARY format file loads significantly faster than a GO format file.
+ /FORMAT=BINARY stores
+ the data in internal GDS format. /FORMAT=BINARY has one header record,
+ therefore LOAD
+ /FORMAT=BINARY starts active work with record number two (2).
+
+3 GOQ
+ /FORMAT=GOQ
+ /FORMAT=GOQ loads files prepared by certain MUMPS implementations and
+ is significantly
+ faster than a GO format file. Use the GOQ format as a conversion aid.
+ /FORMAT=GOQ stores the
+ data in fixed length 2048 byte blocks which contain a variable number
+ of keys and data.
+ FORMAT=GOQ has one or more header records depending on the number of
+ globals in the tape.
+
+2 /BEGIN
+ /BE[GIN]=integer
+ Specifies the record number of the input file with which LOAD should
+ begin. Directing LOAD to begin
+ at a point other than the beginning of a valid key causes an error.
+
+ Each format has some number of header records to consider when choosing
+ a /BEGIN point. For more
+ information, refer to the section on /FORMAT.
+
+ For /FORMAT=GO input, normally the value should be an odd number.
+
+ Because /FORMAT=BINARY requires important information from the header,
+ this type of load requires
+ an intact file header regardless of the /BEGIN value.
+
+ By default, LOAD starts at the beginning of the input file.
+
+2 /END
+ /E[ND]=integer
+ Specifies the record number of the input file at which LOAD should stop.
+ The /END=integer must be
+ greater than the /BEGIN=integer for LOAD to operate. LOAD terminates
+ after processing the record of
+ the number specified by /END or reaching the end of the input file.
+
+ For /FORMAT=GO input, normally the value should be an even number.
+
+ By default, LOAD continues to the end of the input file.
+
+2 /FILL_FACTOR
+ /FI[LL_FACTOR]=integer
+ Specifies the target fill density for the data blocks updated in the
+ database file. /FILL_FACTOR must be
+ an integer between 5 and 100 specifying the percentage fill rate for the
+ block.
+
+ In general, maximum data densities provide the best performance.
+ However, if you have an
+ understanding of the update patterns of your application, you may
+ achieve a performance benefit over
+ time from lowering the initial fill-factor.
+
+ By default, LOAD uses /FILL_FACTOR=100 for maximum data density.
+
+1 REORG
+ REO[RG]
+ MUPIP REORG offers a tool for optimizing your database files for peak
+ database performance. REORG
+ requires minimal operator resources, and runs concurrently with other
+ database activity, including updates.
+ Competing activity generally increases the time to perform a REORG, as
+ well as that of the competing
+ operations. If you use REORG concurrently with normal database access, you
+ may wish to lower the priority
+ of the process performing the REORG to minimize its impact on normal
+ operations.
+
+ Note that while REORG optimizes the GDS structure of database files, it
+ does not deal with native file system
+ file fragmentation. Because native file fragmentation may significantly
+ impair database performance, its
+ prevention and control is still important. Always create files with
+ appropriate allocations and extensions, on
+ disks with large contiguous free-space. Use native utilities and,
+ depending on your procedures, MUPIP
+ utilities to eliminate file fragmentation when database files have been
+ extended more than a dozen times.
+
+ The format of the REORG command is:
+
+ REO[RG] [qualifier...] file-specification
+
+ <CTRL C> produces a status message from REORG. <CTRL Y> aborts REORG. A
+ REORG terminated
+ abnormally by operator action or error is incomplete but does not
+ adversely affect the database structure.
+
+2 Qualifiers
+/SELECT
+ /SELECT=global-name-list
+ Restricts REORG operation to a subset of specified globals. By
+ default, REORG operates on all
+ globals in all database files identified by the current global
+ directory for the process executing the
+ MUPIP command.
+
+ Arguments to this qualifier may be an individual global name, a prefix
+ followed by an asterisk (*)
+ wild-card symbol, or a list of names and/or prefixes followed by the
+ wild-card symbol. The "^" in
+ the specification of the global name is optional. Enclose lowercase
+ global names in quotes ("").
+
+ The global-specification can be:
+
+ o A global name, such as MEF
+
+ o A range of global names, such as A7:B6
+
+ o A parenthetical list, such as (A,B,C)
+
+ o Global names with the same prefix, such as TMP*
+
+ In the first case, EXTRACT selects only global ^MEF. In the second
+ case, EXTRACT selects all
+ global names between ^A7 and ^B6, inclusive. In the third case,
+ EXTRACT selects globals ^A, ^B,
+ and ^C. In the fourth case, EXTRACT selects all global names from ^TMP
+ through ^TMPzzzzz.
+
+/FILL_FACTOR
+ /FILL_FACTOR=percent-qualifier
+ Directs REORG to leave free space within blocks for future updates.
+ Arguments to this qualifier must be
+ integers from 5 to 100. REORG uses this figure in deciding whether to
+ place more information in a
+ block; currently REORG does not move information out of a block to
+ make more room. By default,
+ REORG attempts to fill blocks to their maximum capacity.
+
+1 RESTORE
+ RE[STORE]
+ RESTORE integrates one or more BACKUP /INCREMENTAL files into a
+ corresponding database. For a
+ RESTORE to work, the transaction numbers in the incremental file(s) must
+ sequentially follow those in the
+ database. Gaps or overlaps in the transaction numbers at RESTORE input
+ file boundaries cause RESTORE to
+ issue errors.
+
+ The format of the RESTORE command is:
+
+ RE[STORE] [qualifier] file-spec file-list
+
+ The file-specification identifies the name of the database file that
+ RESTORE uses as a starting point. The
+ transaction number in the database must match the starting transaction
+ number of each successive input to the
+ RESTORE. If the BACKUP /INCREMENTAL was created using /TRANSACTION=1, set
+ the database up
+ with MUPIP CREATE and do not access it with anything except the MUPIP
+ commands INTEG, EXTEND,
+ and SET before initiating the RESTORE.
+
+ The file list specifies one or more files produced by BACKUP /INCREMENTAL
+ to RESTORE into the
+ database. The file-specifications are separated by commas (,) and must be
+ in sequential order, from the oldest
+ transaction number to the most recent. RESTORE may take its input from an
+ RMS file on any device that
+ supports such files, including magnetic tape devices. When using an input
+ file on a magnetic tape, use DCL
+ to MOUNT specifying the same /BLOCKSIZE= as the one used to make the tape.
+
+2 Qualifiers
+/EXTEND
+ /[NO]EXTEND
+ Specifies whether RESTORE should extend automatically if its target
+ database file is smaller than the file
+ size identified by the input BACKUP /INCREMENTAL file. MUMPS activity
+ between backups may
+ automatically extend a database file. Therefore, the database file
+ specified as the starting point for a
+ RESTORE may require an extension before the RESTORE. If the database
+ needs an extension, MUPIP
+ displays a message. The message gives the sizes of the input and
+ output database files and the number of
+ blocks by which to extend the database. If the RESTORE specifies more
+ than one incremental backup
+ with a file list, the database file may require more than one
+ extension.
+
+ By default, RESTORE automatically extends the database file.
+1 RUNDOWN
+ RU[NDOWN]
+ When database files have not been properly closed, RUNDOWN closes those
+ currently inactive databases and
+ releases the central memory they claim. In normal operation, the last
+ process to close a database file performs
+ the RUNDOWN actions.
+
+ The format of the RUNDOWN command is:
+
+ RU[NDOWN] [/qualifier file-spec or region-list]
+
+ The file-specification or region-list identifies the target of the
+ RUNDOWN. If RUNDOWN has no parameter,
+ it ignores any qualifier and flushes the memory associated with all
+ database files that currently have associated
+ memory and no active users.
+
+ Use RUNDOWN after a system crash or after the last process accessing a
+ database terminates abnormally.
+ RUNDOWN ensures that an inactive database is properly closed and ready for
+ subsequent use. RUNDOWN
+ has no effect on any database that is actively being accessed at the time
+ the RUNDOWN is issued.
+
+ A RUNDOWN that specifies a target file or region can correct file state
+ problems which a RUNDOWN with
+ no parameters does not find.
+
+2 Qualifiers
+/FILE
+ /F[ILE]
+ Specifies that the argument is a file-specification for a single
+ database file. The /FILE qualifier is
+ incompatible with the /REGION qualifier. If the rundown parameter
+ consists of a list of files, the
+ command only operates on the first item in the list.
+
+/REGION
+ /R[EGION]
+ Specifies that the argument contains one or more region-names which
+ identify database files mapped
+ by the current Global Directory. Region-names may include the DCL
+ wildcards % and *. The
+ /REGION qualifier is incompatible with the /FILE qualifier.
+
+1 STOP
+ ST[OP]
+ STOP terminates a GT.M image. The image executes an orderly rundown of all
+ databases in which it
+ currently has an interest and then exits. A MUPIP STOP performs a VMS
+ FORCEX system service and
+ therefore may also be used to stop non-GT.M images.
+
+ The format of the STOP command is:
+
+ ST[OP] /N[AME]=process-name | /ID=process-id
+
+ At least one of the qualifiers must appear. If both qualifiers appear,
+ they must refer to the same process or
+ STOP rejects the command.
+
+ Use the DCL command SHOW SYSTEM to display a list of active process names
+ and process identifiers
+ (PIDs). PIDs appear as hexadecimal numbers on a SHOW SYSTEM display, which
+ is how they are specified
+ to MUPIP STOP.
+
+
+2 Qualifiers
+/ID
+ /I[D]=process-id
+ Specifies the PID of the process to stop. STOP interprets the /ID
+ qualifier as a hexadecimal number
+ that corresponds to the form displayed by the DCL command SHOW SYSTEM.
+
+/NAME
+ /N[AME]=process-name
+ Specifies the name of the process to stop. The maximum length of the
+ name is 15 characters. Use
+ the /ID qualifier if the process belongs to an owner in a different
+ group.
+
+
diff --git a/sr_vvms/mupip_cmd.cld b/sr_vvms/mupip_cmd.cld
new file mode 100644
index 0000000..5bdd2b4
--- /dev/null
+++ b/sr_vvms/mupip_cmd.cld
@@ -0,0 +1,482 @@
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+! !
+! Copyright 2005, 2013 Fidelity Information Services, Inc.!
+! !
+! This source code contains the intellectual property !
+! of its copyright holder(s), and is made available !
+! under a license. If you do not know the terms of !
+! the license, please stop and do not read further. !
+! !
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+MODULE MUPIP_CMD
+DEFINE VERB backup
+ ROUTINE mupip_backup
+ PARAMETER P1, LABEL=REG_NAME, PROMPT="Region", VALUE(REQUIRED,LIST)
+ PARAMETER P2, LABEL=DIRECTORY, PROMPT="Backup Directory", VALUE(REQUIRED,LIST)
+
+ QUALIFIER BYTESTREAM NONNEGATABLE
+ QUALIFIER COMPREHENSIVE NONNEGATABLE
+ QUALIFIER DATABASE NONNEGATABLE
+ QUALIFIER DBG NONNEGATABLE
+ QUALIFIER INCREMENTAL NONNEGATABLE
+ QUALIFIER JOURNAL NEGATABLE VALUE (LIST, TYPE = journal_options)
+ QUALIFIER NETTIMEOUT VALUE (TYPE = $NUMBER, REQUIRED)
+ QUALIFIER NEWJNLFILES NEGATABLE VALUE(LIST, TYPE = newjnlfiles_options)
+ QUALIFIER BKUPDBJNL NONNEGATABLE VALUE(REQUIRED, TYPE = bkupdbjnl_options)
+ QUALIFIER ONLINE NEGATABLE
+ QUALIFIER RECORD NONNEGATABLE
+ QUALIFIER REPLICATION NEGATABLE VALUE(REQUIRED, TYPE = replication_options)
+ QUALIFIER SINCE NONNEGATABLE VALUE (TYPE = SINCE_FMT)
+ QUALIFIER TRANSACTION VALUE (REQUIRED)
+
+ DISALLOW((TRANSACTION OR SINCE) AND NOT(INCREMENTAL OR BYTESTREAM) )
+ DISALLOW(((INCREMENTAL OR BYTESTREAM) AND (COMPREHENSIVE OR DATABASE)) OR (TRANSACTION AND SINCE))
+ DISALLOW((BKUPDBJNL.DISABLE) AND (BKUPDBJNL.OFF))
+ DISALLOW(REPLICATION.off)
+ DISALLOW(REPLICATION.on AND NEG NEWJNLFILES)
+
+DEFINE TYPE newjnlfiles_options
+ KEYWORD prevlink NEGATABLE
+ KEYWORD cache NEGATABLE
+
+DEFINE TYPE bkupdbjnl_options
+ KEYWORD disable NONNEGATABLE
+ KEYWORD off NONNEGATABLE
+
+DEFINE TYPE SINCE_FMT
+ KEYWORD BYTESTREAM
+ KEYWORD DATABASE, DEFAULT
+ KEYWORD RECORD
+ KEYWORD COMPREHENSIVE
+ KEYWORD INCREMENTAL
+
+DEFINE VERB convert
+ ROUTINE mupip_cvtpgm
+ PARAMETER P1, LABEL=FILE, PROMPT="Input File", VALUE(TYPE = $FILE, REQUIRED)
+ PARAMETER P2, LABEL=DIR, PROMPT="Output Directory", VALUE(TYPE = $FILE, REQUIRED)
+
+ QUALIFIER FORMAT NONNEGATABLE VALUE(TYPE = CVT_FMT)
+
+DEFINE VERB create
+ ROUTINE mupip_create
+
+ QUALIFIER REGION NONNEGATABLE VALUE(REQUIRED)
+
+DEFINE VERB downgrade
+ ROUTINE mupip_downgrade
+ PARAMETER P1, LABEL=FILE, PROMPT="File", VALUE(REQUIRED, TYPE = $FILE)
+
+ QUALIFIER version NONNEGATABLE VALUE(REQUIRED, TYPE = downgrade_dbver)
+
+DEFINE VERB exit
+ ROUTINE mupip_exit
+
+DEFINE VERB extend
+ ROUTINE mupip_extend
+ PARAMETER P1, LABEL=REG_NAME, PROMPT="Region", VALUE(REQUIRED)
+
+ QUALIFIER BLOCKS VALUE(TYPE = $NUMBER, REQUIRED)
+
+DEFINE TYPE CVT_FMT
+ KEYWORD RO
+
+DEFINE VERB extract
+ ROUTINE mu_extract
+ PARAMETER P1, LABEL=FILE, PROMPT="Output File", VALUE(TYPE = $FILE, REQUIRED)
+
+ QUALIFIER SELECT DEFAULT NONNEGATABLE VALUE(LIST, DEFAULT = "*", TYPE = $QUOTED_STRING)
+ QUALIFIER LABEL DEFAULT NONNEGATABLE VALUE(DEFAULT = "GT.M MUPIP EXTRACT")
+ QUALIFIER LOG NEGATABLE
+ QUALIFIER FORMAT NONNEGATABLE VALUE(TYPE = EXTR_FMT, REQUIRED)
+ QUALIFIER FREEZE NONNEGATABLE
+ QUALIFIER OCHSET NONNEGATABLE VALUE(TYPE = $QUOTED_STRING, REQUIRED)
+
+DEFINE TYPE EXTR_FMT
+ KEYWORD ZWR, DEFAULT
+ KEYWORD GO
+ KEYWORD BINARY
+
+DEFINE VERB freeze
+ ROUTINE mupip_freeze
+ PARAMETER P1, LABEL=REG_NAME, PROMPT="Region", VALUE(REQUIRED,LIST)
+ QUALIFIER DBG NONNEGATABLE
+ QUALIFIER ON NONNEGATABLE
+ QUALIFIER RECORD NONNEGATABLE
+ QUALIFIER OFF NONNEGATABLE
+ QUALIFIER OVERRIDE NONNEGATABLE
+
+ DISALLOW(NOT(ON) AND NOT(OFF))
+ DISALLOW(RECORD AND NOT(ON))
+ DISALLOW(OVERRIDE AND NOT(OFF))
+ DISALLOW(ON AND OFF)
+
+DEFINE VERB integ
+ ROUTINE mupip_integ
+ PARAMETER P1, LABEL=WHAT, PROMPT="File or Region", VALUE(REQUIRED,LIST)
+ QUALIFIER DBG NONNEGATABLE
+ QUALIFIER KEYRANGES NEGATABLE
+ QUALIFIER BRIEF NONNEGATABLE
+ QUALIFIER FULL NONNEGATABLE
+ QUALIFIER FAST NONNEGATABLE
+ QUALIFIER BLOCK NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER MAP NEGATABLE VALUE(TYPE = $NUMBER, DEFAULT = 10)
+ QUALIFIER REGION NONNEGATABLE
+ QUALIFIER FILE NONNEGATABLE
+ QUALIFIER TRANSACTION NEGATABLE VALUE(TYPE = $NUMBER, DEFAULT = 10)
+ QUALIFIER SUBSCRIPT NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER ADJACENCY NONNEGATABLE VALUE(REQUIRED)
+ QUALIFIER MAXKEYSIZE NEGATABLE VALUE(TYPE = $NUMBER, DEFAULT = 10)
+ QUALIFIER TN_RESET NONNEGATABLE
+
+ DISALLOW(BRIEF AND FULL)
+ DISALLOW(FILE AND REGION)
+ DISALLOW(TN_RESET AND (FAST OR BLOCK OR SUBSCRIPT OR REGION))
+
+DEFINE VERB intrpt
+ ROUTINE mupip_intrpt
+ QUALIFIER name VALUE(TYPE = $QUOTED_STRING)
+ QUALIFIER id VALUE(REQUIRED)
+
+ DISALLOW NOT(name OR id)
+
+DEFINE VERB load
+ ROUTINE mupip_cvtgbl
+ PARAMETER P1, LABEL=FILE, PROMPT="Input File", VALUE(TYPE = $FILE, REQUIRED)
+ QUALIFIER FORMAT NONNEGATABLE VALUE(TYPE = LOAD_FMT, REQUIRED)
+ QUALIFIER FILL_FACTOR DEFAULT NONNEGATABLE VALUE(TYPE = $NUMBER, DEFAULT = 99)
+ QUALIFIER BLOCK_DENSITY DEFAULT NONNEGATABLE VALUE(TYPE = $NUMBER, DEFAULT = 99)
+ QUALIFIER BEGIN VALUE(REQUIRED)
+ QUALIFIER END VALUE(REQUIRED)
+ QUALIFIER OCHSET NONNEGATABLE VALUE(REQUIRED, TYPE = $QUOTED_STRING)
+
+DEFINE TYPE LOAD_FMT
+ KEYWORD ZWR, DEFAULT
+ KEYWORD GO
+ KEYWORD BINARY
+ KEYWORD GOQ
+
+DEFINE VERB help
+ ROUTINE mupip_help
+ PARAMETER P1, LABEL=QUERY
+
+DEFINE VERB quit
+ ROUTINE mupip_exit
+
+DEFINE VERB restore
+ ROUTINE mupip_restore
+ PARAMETER P1, LABEL=DATABASE, PROMPT="Database", VALUE (REQUIRED)
+ PARAMETER P2, LABEL=INPUT_FILE, PROMPT="Input_file", VALUE (REQUIRED, LIST)
+
+ QUALIFIER EXTEND NEGATABLE
+ QUALIFIER NETTIMEOUT VALUE (TYPE = $NUMBER, REQUIRED)
+
+DEFINE VERB journal
+ ROUTINE mupip_recover
+ PARAMETER P1, LABEL=FILE, PROMPT="Journal File(s)", VALUE(TYPE = $FILE, REQUIRED, LIST)
+
+ ! -- JOURNAL ACTION QUALIFIERS --
+ QUALIFIER recover NONNEGATABLE
+ QUALIFIER rollback NONNEGATABLE
+ QUALIFIER verify NEGATABLE
+ QUALIFIER show NONNEGATABLE VALUE(LIST, TYPE = SHOW_FMT)
+ QUALIFIER extract NONNEGATABLE VALUE(TYPE = $FILE)
+
+ ! -- JOURNAL DIRECTION QUALIFIERS --
+ QUALIFIER forward NONNEGATABLE
+ QUALIFIER backward NONNEGATABLE
+
+ ! -- JOURNAL TIME QUALIFIERS --
+ QUALIFIER after NONNEGATABLE VALUE(REQUIRED, TYPE = $QUOTED_STRING)
+ QUALIFIER before NONNEGATABLE VALUE(REQUIRED, TYPE = $QUOTED_STRING)
+ QUALIFIER since NONNEGATABLE VALUE(REQUIRED, TYPE = $QUOTED_STRING)
+ QUALIFIER lookback_limit NEGATABLE VALUE(LIST, TYPE = LOOKBK_FMT, DEFAULT = "TIME=0 00:05")
+
+ ! -- JOURNAL SEQUENCE NUMBER QUALIFIERS --
+ QUALIFIER fetchresync NONNEGATABLE VALUE(REQUIRED, TYPE = $NUMBER)
+ QUALIFIER resync NONNEGATABLE VALUE(REQUIRED)
+
+ ! -- JOURNAL CONTROL QUALIFIERS --
+ QUALIFIER redirect NONNEGATABLE VALUE(LIST, REQUIRED)
+ QUALIFIER fences NONNEGATABLE VALUE(TYPE = FENCE_FMT)
+ QUALIFIER interactive NEGATABLE
+ QUALIFIER error_limit NEGATABLE VALUE(REQUIRED, TYPE = $NUMBER)
+ QUALIFIER checktn NEGATABLE
+ QUALIFIER chain NEGATABLE
+ QUALIFIER detail NONNEGATABLE
+ QUALIFIER apply_after_image NEGATABLE
+ QUALIFIER losttrans NONNEGATABLE VALUE(REQUIRED, TYPE = $FILE)
+ QUALIFIER brokentrans NONNEGATABLE VALUE(REQUIRED, TYPE = $FILE)
+ QUALIFIER full NONNEGATABLE
+ QUALIFIER output NONNEGATABLE VALUE(REQUIRED, TYPE = $FILE)
+ QUALIFIER verbose NONNEGATABLE
+
+ ! -- JOURNAL SELECTION QUALIFIERS --
+ QUALIFIER global NONNEGATABLE VALUE(LIST, REQUIRED, TYPE = $QUOTED_STRING)
+ QUALIFIER user NONNEGATABLE VALUE(LIST, REQUIRED)
+ QUALIFIER id NONNEGATABLE VALUE(LIST, REQUIRED)
+ QUALIFIER transaction NONNEGATABLE VALUE(REQUIRED, TYPE = TRANS_FMT)
+ QUALIFIER process NONNEGATABLE VALUE(LIST, REQUIRED)
+
+ DISALLOW NOT (recover OR verify OR show OR extract OR rollback)
+ DISALLOW recover and rollback
+ DISALLOW NOT (forward OR backward)
+ DISALLOW forward AND backward
+ DISALLOW since AND forward
+ DISALLOW lookback_limit AND forward
+ DISALLOW redirect AND NOT recover
+ DISALLOW checktn AND backward
+ DISALLOW resync and fetchresync
+ DISALLOW (resync OR fetchresync) AND NOT(rollback)
+ DISALLOW losttrans AND NOT(recover OR rollback OR extract)
+ DISALLOW brokentrans AND NOT(recover OR rollback OR extract)
+ DISALLOW forward AND rollback
+ DISALLOW full AND (recover OR rollback)
+ DISALLOW detail AND NOT extract
+ DISALLOW after and NOT forward
+ DISALLOW after and (recover OR rollback)
+ DISALLOW since and NOT backward
+ DISALLOW lookback_limit AND NOT backward
+ DISALLOW lookback_limit AND NOT (verify OR recover OR extract OR show)
+ DISALLOW apply_after_image AND NOT (recover OR rollback)
+ DISALLOW redirect AND NOT recover
+ DISALLOW redirect AND NOT forward
+ DISALLOW backward AND NEG chain
+ DISALLOW (after OR before OR since OR lookback_limit) AND rollback
+ DISALLOW (global OR user OR id OR process OR transaction) AND (recover OR rollback OR verify)
+ DISALLOW output AND interactive ! output is VMS only qualifier
+
+DEFINE TYPE SHOW_FMT
+ KEYWORD header
+ KEYWORD statistics
+ KEYWORD broken_transactions
+ KEYWORD processes
+ KEYWORD active_processes
+ KEYWORD all, DEFAULT
+
+DEFINE TYPE LOOKBK_FMT
+ KEYWORD time NONNEGATABLE VALUE(REQUIRED, TYPE=$QUOTED_STRING)
+ KEYWORD operations NONNEGATABLE VALUE(REQUIRED, TYPE=$NUMBER)
+
+DEFINE TYPE FENCE_FMT
+ KEYWORD always
+ KEYWORD process, DEFAULT
+ KEYWORD none
+
+DEFINE TYPE TRANS_FMT
+ KEYWORD set NEGATABLE
+ KEYWORD kill NEGATABLE
+
+DEFINE VERB reorg
+ ROUTINE mupip_reorg
+ PARAMETER P1, LABEL=REG_NAME, VALUE(LIST, TYPE = $QUOTED_STRING)
+ QUALIFIER SELECT DEFAULT NONNEGATABLE VALUE(LIST, DEFAULT = "*", TYPE = $QUOTED_STRING)
+ QUALIFIER EXCLUDE DEFAULT NONNEGATABLE VALUE(LIST, DEFAULT = "*", TYPE = $QUOTED_STRING)
+ QUALIFIER FILL_FACTOR DEFAULT NONNEGATABLE VALUE(TYPE = $NUMBER, DEFAULT = 99)
+ QUALIFIER INDEX_FILL_FACTOR DEFAULT NONNEGATABLE VALUE(TYPE = $NUMBER, DEFAULT = 99)
+ QUALIFIER RESUME NONNEGATABLE
+ QUALIFIER USER_DEFINED_REORG DEFAULT NONNEGATABLE VALUE(LIST, DEFAULT = "*", TYPE = $QUOTED_STRING)
+ QUALIFIER UPGRADE NONNEGATABLE
+ QUALIFIER DOWNGRADE NONNEGATABLE
+ QUALIFIER SAFEJNL NEGATABLE
+ QUALIFIER REGION NONNEGATABLE
+ QUALIFIER STARTBLK NONNEGATABLE
+ QUALIFIER STOPBLK NONNEGATABLE
+ DISALLOW(SELECT or EXCLUDE or FILL_FACTOR or INDEX_FILL_FACTOR or RESUME or USER_DEFINED_REORG) AND
+ (UPGRADE or DOWNGRADE)
+ DISALLOW(UPGRADE and DOWNGRADE)
+ DISALLOW((UPGRADE or DOWNGRADE) and NOT(REGION))
+ DISALLOW((SAFEJNL or NEG SAFEJNL or STARTBLK or STOPBLK) and NOT(UPGRADE or DOWNGRADE))
+
+DEFINE VERB rundown
+ ROUTINE mupip_rundown
+ PARAMETER P1, LABEL=DBFILE, PROMPT="File or Region", VALUE(LIST)
+
+ QUALIFIER REGION NONNEGATABLE
+ QUALIFIER FILE NONNEGATABLE
+
+ DISALLOW(FILE AND REGION)
+
+DEFINE VERB set
+ ROUTINE mupip_set
+ PARAMETER P1, LABEL=WHAT, PROMPT="File or Region", VALUE(REQUIRED,LIST)
+
+ QUALIFIER file NONNEGATABLE
+ QUALIFIER region NONNEGATABLE
+
+ QUALIFIER journal NEGATABLE VALUE(LIST, TYPE = journal_options)
+
+ QUALIFIER access_method NONNEGATABLE VALUE(REQUIRED, TYPE = acc_type)
+ QUALIFIER defer_time NONNEGATABLE VALUE(REQUIRED, TYPE = $NUMBER)
+ QUALIFIER extension_count NONNEGATABLE VALUE(REQUIRED, TYPE = $NUMBER)
+ QUALIFIER flush_time NONNEGATABLE VALUE(TYPE = $DELTATIME, DEFAULT = 100)
+ QUALIFIER global_buffers NONNEGATABLE VALUE(REQUIRED, TYPE = $NUMBER)
+ QUALIFIER lock_space NONNEGATABLE VALUE(REQUIRED, TYPE = $NUMBER)
+ QUALIFIER mutex_slots NONNEGATABLE VALUE(REQUIRED, TYPE = $NUMBER)
+ QUALIFIER reserved_bytes NONNEGATABLE VALUE(REQUIRED, TYPE = $NUMBER)
+
+ QUALIFIER jnlfile NONNEGATABLE !dummy qualifier to go with unix impl.
+ QUALIFIER replication NEGATABLE VALUE(REQUIRED, TYPE = replication_options)
+
+ QUALIFIER bypass NONNEGATABLE
+ QUALIFIER partial_recov_bypass NONNEGATABLE
+ QUALIFIER dbfilename NEGATABLE VALUE(REQUIRED, TYPE = $QUOTED_STRING)
+ QUALIFIER prevjnlfile NEGATABLE VALUE(REQUIRED, TYPE = $QUOTED_STRING)
+ QUALIFIER repl_state NEGATABLE VALUE(REQUIRED, TYPE = $QUOTED_STRING)
+ QUALIFIER standalonenot
+ QUALIFIER version NONNEGATABLE VALUE(REQUIRED, TYPE = dbvers)
+ QUALIFIER wait_disk NONNEGATABLE VALUE(REQUIRED, TYPE = $NUMBER)
+
+ DISALLOW ANY2(file, region, jnlfile)
+ DISALLOW(NOT(file OR region OR jnlfile))
+ DISALLOW(journal.on AND journal.off)
+ ! --- disallow /NOJOURNAL=DISABLE ---
+ DISALLOW(journal.disable AND NEG journal)
+ ! --- disallow any other journal options for both /NOJOURNAL and DISABLE (Unix CLI disallows assignment for /NOJOURNAL) ---
+ DISALLOW((journal.disable OR NEG journal) AND (journal.on OR journal.off OR journal.enable OR journal.before_images
+ OR journal.filename OR journal.allocation OR journal.extension OR journal.buffer_size OR journal.alignsize
+ OR journal.epoch_interval OR journal.autoswitchlimit OR NEG journal.before_images))
+ DISALLOW(journal AND NOT(journal.disable OR journal.off OR journal.before_images OR NEG journal.before_images))
+ DISALLOW(replication.on AND replication.off)
+ DISALLOW(replication.on AND (journal.off OR journal.disable OR NEG journal OR NEG journal.before_images))
+ DISALLOW(prevjnlfile AND NOT(jnlfile))
+ DISALLOW(version AND (access_method OR global_buffers OR reserved_bytes OR flush_time OR lock_space
+ OR defer_time OR wait_disk OR partial_recov_bypass))
+
+DEFINE TYPE journal_options
+ KEYWORD on NONNEGATABLE
+ KEYWORD off NONNEGATABLE
+ KEYWORD enable NONNEGATABLE
+ KEYWORD disable NONNEGATABLE
+ KEYWORD before_images NEGATABLE
+ KEYWORD filename NONNEGATABLE VALUE(REQUIRED, TYPE=$FILE)
+ KEYWORD allocation NONNEGATABLE VALUE(REQUIRED, TYPE=$NUMBER)
+ KEYWORD extension NONNEGATABLE VALUE(REQUIRED, TYPE=$NUMBER)
+ KEYWORD buffer_size NONNEGATABLE VALUE(REQUIRED, TYPE=$NUMBER)
+ KEYWORD alignsize NONNEGATABLE VALUE(REQUIRED, TYPE=$NUMBER)
+ KEYWORD epoch_interval NONNEGATABLE VALUE(REQUIRED, TYPE=$NUMBER)
+ KEYWORD autoswitchlimit NONNEGATABLE VALUE(REQUIRED, TYPE=$NUMBER)
+ KEYWORD cache NEGATABLE
+
+DEFINE TYPE replication_options
+ KEYWORD on NONNEGATABLE
+ KEYWORD off NONNEGATABLE
+
+DEFINE TYPE acc_type
+ KEYWORD bg
+ KEYWORD mm
+
+DEFINE TYPE dbvers
+ KEYWORD v4
+ KEYWORD v6
+
+DEFINE TYPE downgrade_dbver
+ KEYWORD v4
+ KEYWORD v5
+
+DEFINE VERB stop
+ ROUTINE mupip_stop
+ QUALIFIER name VALUE(TYPE = $QUOTED_STRING)
+ QUALIFIER id VALUE(REQUIRED)
+
+ DISALLOW NOT(name OR id)
+
+DEFINE VERB upgrade
+ ROUTINE mupip_upgrade
+ PARAMETER P1, LABEL=FILE, PROMPT="File", VALUE(REQUIRED, TYPE = $FILE)
+
+DEFINE VERB replicate
+ QUALIFIER RECEIVER SYNTAX=REPL_RECV_SYN NONNEGATABLE
+ QUALIFIER SOURCE SYNTAX=REPL_SRC_SYN NONNEGATABLE
+ QUALIFIER UPDATEPROC SYNTAX=REPL_UPD_SYN NONNEGATABLE
+ QUALIFIER UPDHELPER SYNTAX=REPL_UPD_HELPER NONNEGATABLE
+
+ DISALLOW NOT(RECEIVER OR SOURCE OR UPDATEPROC OR UPDHELPER)
+
+DEFINE SYNTAX REPL_RECV_SYN
+ ROUTINE gtmrecv
+ QUALIFIER buffsize NONNEGATABLE VALUE(REQUIRED, TYPE = $NUMBER)
+ QUALIFIER changelog NONNEGATABLE
+ QUALIFIER checkhealth NONNEGATABLE
+ QUALIFIER filter NONNEGATABLE VALUE(REQUIRED, TYPE = $QUOTED_STRING)
+ QUALIFIER helpers NONNEGATABLE VALUE(TYPE = $QUOTED_STRING, DEFAULT = "8,5") ! Keep DEFAULT_UPD_HELPERS_STR
+ ! (in gtmrecv.h) and DEFAULT
+ ! value for /helpers in sync
+ QUALIFIER listenport NONNEGATABLE VALUE(REQUIRED, TYPE = $NUMBER)
+ QUALIFIER log NONNEGATABLE VALUE(REQUIRED, TYPE = $QUOTED_STRING)
+ QUALIFIER log_interval NONNEGATABLE VALUE(REQUIRED, TYPE = $QUOTED_STRING)
+ QUALIFIER startup_file NONNEGATABLE VALUE(REQUIRED, TYPE = $QUOTED_STRING)
+ QUALIFIER showbacklog NONNEGATABLE
+ QUALIFIER shutdown NONNEGATABLE
+ QUALIFIER start NONNEGATABLE
+ QUALIFIER statslog NONNEGATABLE VALUE(REQUIRED, TYPE = $QUOTED_STRING)
+ QUALIFIER stopsourcefilter NONNEGATABLE
+ QUALIFIER timeout NEGATABLE VALUE(TYPE = $NUMBER, DEFAULT = 30)
+ QUALIFIER updateonly NONNEGATABLE
+ QUALIFIER updateresync NONNEGATABLE
+ QUALIFIER dummy_start NONNEGATABLE ! For internal use
+
+ DISALLOW ANY2(start, shutdown, checkhealth, statslog, showbacklog, changelog)
+ DISALLOW NOT(start OR shutdown OR checkhealth OR statslog OR showbacklog OR changelog)
+ DISALLOW (start AND NOT(listenport OR updateonly OR helpers))
+ DISALLOW (start AND listenport AND NOT(log))
+ DISALLOW (NOT(start) AND (listenport OR updateresync))
+ DISALLOW (NOT(start OR shutdown) AND updateonly)
+ DISALLOW (NOT(start OR shutdown OR checkhealth) AND helpers)
+ DISALLOW (listenport AND updateonly)
+ DISALLOW (updateonly AND helpers)
+ DISALLOW (changelog AND NOT(log OR log_interval))
+ DISALLOW (statslog AND log)
+
+DEFINE SYNTAX REPL_SRC_SYN
+ ROUTINE gtmsource
+ QUALIFIER activate NONNEGATABLE
+ QUALIFIER buffsize NONNEGATABLE VALUE(REQUIRED, TYPE = $NUMBER)
+ QUALIFIER changelog NONNEGATABLE
+ QUALIFIER checkhealth NONNEGATABLE
+ QUALIFIER connectparams NONNEGATABLE VALUE(REQUIRED, TYPE = $QUOTED_STRING)
+ QUALIFIER deactivate NONNEGATABLE
+ QUALIFIER filter NONNEGATABLE VALUE(REQUIRED, TYPE = $QUOTED_STRING)
+ QUALIFIER log NONNEGATABLE VALUE(REQUIRED, TYPE = $QUOTED_STRING)
+ QUALIFIER log_interval NONNEGATABLE VALUE(REQUIRED, TYPE = $NUMBER)
+ QUALIFIER startup_file NONNEGATABLE VALUE(REQUIRED, TYPE = $QUOTED_STRING)
+ QUALIFIER passive NONNEGATABLE
+ QUALIFIER secondary NONNEGATABLE VALUE(REQUIRED, TYPE = $QUOTED_STRING)
+ QUALIFIER showbacklog NONNEGATABLE
+ QUALIFIER shutdown NONNEGATABLE
+ QUALIFIER start NONNEGATABLE
+ QUALIFIER statslog NONNEGATABLE VALUE(REQUIRED, TYPE = $QUOTED_STRING)
+ QUALIFIER stopsourcefilter NONNEGATABLE
+ QUALIFIER timeout NEGATABLE VALUE(TYPE = $NUMBER, DEFAULT = 30)
+ QUALIFIER update NONNEGATABLE VALUE(REQUIRED, TYPE = $QUOTED_STRING)
+ QUALIFIER dummy_start NONNEGATABLE ! For internal use
+
+ DISALLOW ANY2(start, shutdown, activate, deactivate, checkhealth, statslog, showbacklog, changelog, stopsourcefilter)
+ DISALLOW NOT(start OR shutdown OR activate OR deactivate OR checkhealth
+ OR statslog OR showbacklog OR changelog OR stopsourcefilter)
+ DISALLOW (start AND passive AND secondary)
+ DISALLOW (start AND NOT(passive) AND NOT(secondary))
+ DISALLOW (start AND NOT(log))
+ DISALLOW (activate AND NOT(secondary))
+ DISALLOW (changelog AND NOT(log) AND NOT(log_interval))
+ DISALLOW (statslog AND log)
+
+DEFINE SYNTAX REPL_UPD_SYN
+ ROUTINE updproc
+
+DEFINE SYNTAX REPL_UPD_HELPER
+ QUALIFIER reader SYNTAX=REPL_UPDHR_SYN NONNEGATABLE
+ QUALIFIER writer SYNTAX=REPL_UPDHW_SYN NONNEGATABLE
+ DISALLOW NOT(reader OR writer)
+
+DEFINE SYNTAX REPL_UPDHR_SYN
+ ROUTINE updhelper_reader
+
+DEFINE SYNTAX REPL_UPDHW_SYN
+ ROUTINE updhelper_writer
+
+DEFINE VERB ftok
+ ROUTINE mupip_ftok
+ PARAMETER P1, LABEL=FILE, PROMPT="File", VALUE(TYPE = $FILE, REQUIRED)
+
+ QUALIFIER prefix NONNEGATABLE VALUE(TYPE = $QUOTED_STRING, DEFAULT = "GT$S")
diff --git a/sr_vvms/mupip_ctrl.c b/sr_vvms/mupip_ctrl.c
new file mode 100644
index 0000000..a81c656
--- /dev/null
+++ b/sr_vvms/mupip_ctrl.c
@@ -0,0 +1,33 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <ssdef.h>
+#include "mupip_ctrl.h"
+
+#define CTRLC 3
+#define CTRLY 25
+
+GBLDEF bool mu_ctrly_occurred;
+GBLDEF bool mu_ctrlc_occurred;
+
+void mupip_ctrl(int4 ob_char)
+{
+
+ if (ob_char == CTRLC)
+ { mu_ctrlc_occurred = TRUE;
+ }else if ( ob_char == CTRLY)
+ { mu_ctrly_occurred = TRUE;
+ }else
+ {
+ GTMASSERT;
+ }
+}
diff --git a/sr_vvms/mupip_ctrl.h b/sr_vvms/mupip_ctrl.h
new file mode 100644
index 0000000..5f320d5
--- /dev/null
+++ b/sr_vvms/mupip_ctrl.h
@@ -0,0 +1,17 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef MUPIP_CTRL_INCLUDED
+#define MUPIP_CTRL_INCLUDED
+
+void mupip_ctrl(int4 ob_char);
+
+#endif /* MUPIP_CTRL_INCLUDED */
diff --git a/sr_vvms/mupip_cvtgbl.c b/sr_vvms/mupip_cvtgbl.c
new file mode 100644
index 0000000..5a9fc57
--- /dev/null
+++ b/sr_vvms/mupip_cvtgbl.c
@@ -0,0 +1,177 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include <rms.h>
+#include <ssdef.h>
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "muextr.h"
+#include "util.h"
+#include "io.h"
+#include "mupip_exit.h"
+#include "load.h"
+#include "mu_outofband_setup.h"
+#include "mupip_cvtgbl.h"
+#include "trans_log_name.h"
+#include "cli.h"
+
+#define MAX_TRAN_NAM_LEN 257
+
+GBLREF gd_region *gv_cur_region;
+GBLREF bool mupip_error_occurred;
+GBLREF int gv_fillfactor;
+GBLREF boolean_t is_replicator;
+
+error_def(ERR_LOADFMT);
+error_def(ERR_LOADBGSZ);
+error_def(ERR_LOADBGSZ2);
+error_def(ERR_LOADEDSZ);
+error_def(ERR_LOADEDSZ2);
+error_def(ERR_LOADEDBG);
+error_def(ERR_LOADFILERR);
+error_def(ERR_MUPCLIERR);
+error_def(ERR_MUNOACTION);
+error_def(ERR_MUNOFINISH);
+
+void mupip_cvtgbl(void)
+{
+ char *c, *b, format_buffer[50], infilename[256];
+ unsigned char buf[MAX_TRAN_NAM_LEN];
+ unsigned short n_len;
+ uint4 begin, end;
+ uint4 stat;
+ int format, len, n;
+ struct FAB infab;
+ struct RAB inrab;
+ struct XABPRO xabpro;
+ mstr transed_file, untransed_file;
+ gtm_int64_t begin_i8, end_i8;
+
+ is_replicator = TRUE;
+ n_len = SIZEOF(format_buffer);
+ if (0 == cli_get_str("FORMAT", format_buffer, &n_len))
+ {
+ n_len = SIZEOF("ZWR") - 1;
+ memcpy(format_buffer, "ZWR", n_len);
+ format = MU_FMT_ZWR;
+ } else
+ {
+ if (0 == memcmp(format_buffer, "ZWR", n_len))
+ format = MU_FMT_ZWR;
+ else if (0 == memcmp(format_buffer, "GO", n_len))
+ format = MU_FMT_GO;
+ else if (0 == memcmp(format_buffer, "BINARY", n_len))
+ format = MU_FMT_BINARY;
+ else if (0 == memcmp(format_buffer, "GOQ", n_len))
+ format = MU_FMT_GOQ;
+ else
+ mupip_exit (ERR_LOADFMT);
+ }
+ mu_outofband_setup();
+ mupip_error_occurred = FALSE;
+ n_len = SIZEOF(infilename);
+ if (0 == cli_get_str("FILE", infilename, &n_len))
+ mupip_exit(ERR_MUPCLIERR);
+ if (0 == cli_get_int("FILL_FACTOR", &gv_fillfactor))
+ gv_fillfactor = MAX_FILLFACTOR;
+ else if (gv_fillfactor > MAX_FILLFACTOR)
+ gv_fillfactor = MAX_FILLFACTOR;
+ else if (gv_fillfactor < MIN_FILLFACTOR)
+ gv_fillfactor = MIN_FILLFACTOR;
+
+ if (cli_get_int64("BEGIN", &begin_i8))
+ {
+ if (1 > begin_i8)
+ mupip_exit(ERR_LOADBGSZ);
+ else if (MAXUINT4 < begin_i8)
+ mupip_exit(ERR_LOADBGSZ2);
+ begin = begin_i8;
+ } else
+ {
+ begin = 1;
+ begin_i8 = 1;
+ }
+ if (cli_get_int64("END", &end_i8))
+ {
+ if (1 > end_i8)
+ mupip_exit(ERR_LOADEDSZ);
+ else if (MAXUINT4 < end_i8)
+ mupip_exit(ERR_LOADEDSZ2);
+ if (end_i8 < 1)
+ mupip_exit(ERR_LOADEDSZ);
+ if (end_i8 < begin_i8)
+ mupip_exit(ERR_LOADEDBG);
+ end = end_i8;
+ } else
+ end = MAXUINT4;
+ gvinit();
+ infab = cc$rms_fab;
+ inrab = cc$rms_rab;
+ inrab.rab$l_fab = &infab;
+ untransed_file.addr = &infilename;
+ untransed_file.len = n_len;
+ switch(stat = trans_log_name(&untransed_file, &transed_file, buf))
+ {
+ case SS$_NORMAL:
+ infab.fab$l_fna = transed_file.addr;
+ infab.fab$b_fns = transed_file.len;
+ break;
+ case SS$_NOLOGNAM:
+ infab.fab$l_fna = infilename;
+ infab.fab$b_fns = n_len;
+ break;
+ default:
+ mupip_exit(stat);
+ }
+ if (MU_FMT_GOQ == format)
+ {
+ infab.fab$l_fop = FAB$M_UFO;
+ infab.fab$b_fac = FAB$M_BIO;
+ } else
+ {
+ infab.fab$l_fop = FAB$M_SQO;
+ infab.fab$b_fac = FAB$M_GET;
+ }
+ infab.fab$l_xab = &xabpro;
+ xabpro = cc$rms_xabpro;
+ inrab.rab$l_rop |= (RAB$M_LOC | RAB$M_RAH);
+ inrab.rab$b_mbf = 20;
+ stat = sys$open(&infab);
+ if ((RMS$_NORMAL == stat) && (MU_FMT_GOQ != format))
+ stat = sys$connect(&inrab);
+ if (RMS$_NORMAL != stat)
+ {
+ rts_error(VARLSTCNT(8) ERR_LOADFILERR, 2, infab.fab$b_fns, infab.fab$l_fna, stat, 0, infab.fab$l_stv, 0);
+ mupip_exit(ERR_MUNOACTION);
+ }
+ switch(format)
+ {
+ case MU_FMT_ZWR:
+ case MU_FMT_GO:
+ go_load(begin, end, &inrab, &infab);
+ break;
+ case MU_FMT_BINARY:
+ bin_load(begin, end, &inrab, &infab);
+ break;
+ case MU_FMT_GOQ:
+ goq_load(begin, end, &infab);
+ }
+ gv_cur_region = NULL;
+ mupip_exit(mupip_error_occurred ? ERR_MUNOFINISH : SS$_NORMAL);
+}
diff --git a/sr_vvms/mupip_cvtpgm.c b/sr_vvms/mupip_cvtpgm.c
new file mode 100644
index 0000000..f1ee66a
--- /dev/null
+++ b/sr_vvms/mupip_cvtpgm.c
@@ -0,0 +1,215 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <rms.h>
+#include <rmsdef.h>
+#include <ssdef.h>
+
+#include "io.h"
+#include "cli.h"
+#include "mupip_exit.h"
+#include "mupip_cvtpgm.h"
+#include "trans_log_name.h"
+
+static struct FAB infab, outfab;
+static struct RAB inrab, outrab;
+static unsigned char buffer[512];
+static int buflen;
+static char dirname[512];
+static short full_name_len = 0;
+static unsigned short prog_converted = 0;
+
+void mupip_cvtpgm(void)
+{
+ char infilename[256];
+ unsigned char buf[MAX_TRANS_NAME_LEN];
+ unsigned short dir_len = 255;
+ unsigned short in_len = 255;
+ uint4 stat;
+ int status;
+ mstr transed_dir, transed_file, untransed_dir, untransed_file;
+
+ status = cli_get_str("FILE", infilename, &in_len);
+ assert(TRUE == status);
+ status = cli_get_str("DIR", dirname, &dir_len);
+ assert(TRUE == status);
+ infab = cc$rms_fab;
+ inrab = cc$rms_rab;
+ inrab.rab$l_fab = &infab;
+ infab.fab$b_fac = FAB$M_GET;
+ untransed_file.addr = &infilename;
+ untransed_file.len = in_len;
+ switch(stat = trans_log_name(&untransed_file, &transed_file, buf))
+ {
+ case SS$_NORMAL:
+ infab.fab$l_fna = transed_file.addr;
+ infab.fab$b_fns = transed_file.len;
+ break;
+ case SS$_NOLOGNAM:
+ infab.fab$l_fna = infilename;
+ infab.fab$b_fns = in_len;
+ break;
+ default:
+ rts_error(VARLSTCNT(1) stat);
+ }
+ infab.fab$l_fop = FAB$M_SQO;
+ infab.fab$w_mrs = 511;
+ inrab.rab$l_ubf = buffer;
+ inrab.rab$w_usz = SIZEOF(buffer) - 1;
+ status = sys$open(&infab);
+ if (RMS$_NORMAL != status)
+ rts_error(status);
+ status = sys$connect(&inrab);
+ if (RMS$_NORMAL != status)
+ rts_error(status);
+ status = sys$get(&inrab);
+ if (RMS$_NORMAL != status)
+ rts_error(status);
+ status = sys$get(&inrab);
+ if (RMS$_NORMAL != status)
+ rts_error(status);
+ for (;;)
+ {
+ if (RMS$_EOF == status)
+ break;
+ /* get program name */
+ status = sys$get(&inrab);
+ if (RMS$_EOF == status)
+ break;
+ if (RMS$_NORMAL != status)
+ rts_error(status);
+ fixup();
+ if (buflen < 1)
+ continue;
+ if (*buffer == '%')
+ *buffer = '_';
+ untransed_dir.addr = &dirname;
+ untransed_dir.len = dir_len;
+ switch(stat = trans_log_name(&untransed_dir, &transed_dir, buf))
+ {
+ case SS$_NORMAL:
+ dir_len = transed_dir.len;
+ memcpy(&dirname, transed_dir.addr, dir_len);
+ break;
+ case SS$_NOLOGNAM:
+ break;
+ default:
+ rts_error(VARLSTCNT(1) stat);
+ }
+ memcpy(&dirname[dir_len], buffer, buflen);
+ full_name_len = dir_len + buflen;
+ openoutfile(dirname, full_name_len);
+ for (;;)
+ {
+ status = sys$get(&inrab);
+ if (RMS$_EOF == status)
+ break;
+ if (RMS$_NORMAL != status)
+ rts_error(status);
+ fixup();
+ if (!buflen)
+ {
+ closeoutfile();
+ break;
+ }
+ putdata(buffer, buflen);
+ }
+ prog_converted++;
+ }
+ status = sys$close(&infab);
+ if (RMS$_NORMAL != status)
+ rts_error(status);
+ mupip_exit(status);
+}
+
+openoutfile(char *fa, int fn)
+{
+ int status;
+ char *ch;
+
+ outfab = cc$rms_fab;
+ outrab = cc$rms_rab;
+ outrab.rab$l_fab = &outfab;
+ outfab.fab$l_dna = DOTM;
+ outfab.fab$b_dns = SIZEOF(DOTM);
+ outfab.fab$b_fac = FAB$M_PUT;
+ outfab.fab$l_fna = fa;
+ outfab.fab$b_fns = fn;
+ outfab.fab$l_fop = FAB$M_SQO | FAB$M_MXV;
+ outfab.fab$w_mrs = 511;
+ outfab.fab$b_rat = FAB$M_CR;
+ outrab.rab$l_ubf = buffer;
+ outrab.rab$w_usz = SIZEOF(buffer) - 1;
+ status = sys$create(&outfab);
+ switch (status )
+ {
+ case RMS$_NORMAL:
+ case RMS$_CREATED:
+ case RMS$_SUPERSEDE:
+ case RMS$_FILEPURGED:
+ break;
+ default:
+ rts_error(status);
+ }
+ status = sys$connect(&outrab);
+ if (RMS$_NORMAL != status)
+ rts_error(status);
+}
+
+closeoutfile()
+{
+ int status;
+
+ status = sys$close(&outfab);
+ if (RMS$_NORMAL != status)
+ rts_error(status);
+}
+
+putdata(unsigned char *buff, int len)
+{
+ char *tempbuf;
+ unsigned char *inpt, *cp, *ctop;
+ int n;
+ int status;
+
+ cp = tempbuf = malloc(512);
+ inpt = buff;
+ ctop = inpt + len;
+ /* copy label */
+ while (inpt < ctop && *inpt != ' ' && *inpt != '\t')
+ *cp++ = *inpt++;
+ /* use one tab as line separator*/
+ *cp++ = '\t';
+ /* get rid of spaces and tabs in input stream */
+ while (inpt < ctop && ((' ' == *inpt) || ('\t' == *inpt)))
+ inpt++;
+ if ((n = ctop - inpt) > 0)
+ { memcpy(cp, inpt, n);
+ cp += n;
+ }
+ outrab.rab$l_rbf = tempbuf;
+ outrab.rab$w_rsz = cp - (unsigned char *) tempbuf;
+ status = sys$put(&outrab);
+ free(tempbuf);
+ if (RMS$_NORMAL != status)
+ rts_error(status);
+ return;
+}
+
+fixup()
+{
+ buflen = inrab.rab$w_rsz;
+ while (buflen > 0 &&
+ (('\n' == buffer[buflen - 1]) || ('\r' == buffer[buflen - 1])))
+ buflen--;
+}
diff --git a/sr_vvms/mupip_dispatch.c b/sr_vvms/mupip_dispatch.c
new file mode 100644
index 0000000..7d4bb54
--- /dev/null
+++ b/sr_vvms/mupip_dispatch.c
@@ -0,0 +1,148 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2005 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/*------------------------------------------------------------------------------
+ *
+ * The 3 files, GTMCOMMANDS.CLDX, MUPIP_CMD.CLD and MUPIP_DISPATCH.C, must
+ * be maintained in parallel. In order to add a MUPIP command, first update
+ * GTMCOMMANDS.CLDX. The new command must be added as a member of the
+ * TYPE MUPIP_ACTIONS. The new syntax MUST have the first parameter:
+ *
+ * PARAMETER P1
+ * LABEL = MUPIP_ACTION
+ * VALUE (REQUIRED)
+ *
+ * The actual routine which executes the new command must be added to
+ * MUPIP_DISPATCH.C by including a new descriptor:
+ *
+ * $DESCRIPTOR (newcommand, "NEWCOMMAND");
+ *
+ * and by adding a new comparison:
+ *
+ * if (!dsccmp (action, &newcommand)) mupip_newcommand ();
+ * else ...
+ *
+ * The new syntax should be converted to a verb definition and added to
+ * MUPIP_CMD.CLD. In order to convert a syntax definition in GTMCOMMANDS.CLDX
+ * to a verb definition in MUPIP_CMD.CLD:
+ *
+ * 1. Change the line DEFINE SYNTAX MUPIP_NEWCOMMAND to
+ * DEFINE VERB NEWCOMMAND.
+ * 2. Add the routine clause ROUTINE mupip_newcommand, where mupip_newcommand
+ * is the name of the routine used in MUPIP_DISPATCH.C.
+ * 3. Subtract 1 from every parameter number, i.e., P8 becomes P7, P7
+ * becomes P6, etc.
+ *
+ *----------------------------------------------------------------------------*/
+
+
+#include "mdef.h"
+#include <descrip.h>
+#include <ssdef.h>
+#include <rms.h>
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "jnl.h"
+
+#include "mupip_exit.h"
+#include "muextr.h"
+#include "mupip_create.h"
+#include "mupip_set.h"
+#include "mupip_backup.h"
+#include "mupip_cvtgbl.h"
+#include "mupip_cvtpgm.h"
+#include "mupip_help.h"
+#include "mupip_integ.h"
+#include "mupip_extend.h"
+#include "mupip_recover.h"
+#include "mupip_restore.h"
+#include "mupip_rundown.h"
+#include "mupip_stop.h"
+#include "mupip_upgrade.h"
+#include "buddy_list.h"
+#include "hashtab_mname.h" /* needed for muprec.h */
+#include "hashtab_int4.h" /* needed for muprec.h */
+#include "hashtab_int8.h" /* needed for muprec.h */
+#include "muprec.h"
+
+#define dsccmp(a,b) (memcmp ((a)->dsc$a_pointer, (b)->dsc$a_pointer, mupip_action_len (a)))
+
+mupip_dispatch ( struct dsc$descriptor *action)
+{
+ int status;
+
+ $DESCRIPTOR (backup, "BACKUP");
+ $DESCRIPTOR (convert, "CONVERT");
+ $DESCRIPTOR (create,"CREATE");
+ $DESCRIPTOR (exit, "EXIT");
+ $DESCRIPTOR (extend, "EXTEND");
+ $DESCRIPTOR (extract, "EXTRACT");
+ $DESCRIPTOR (integ, "INTEG");
+ $DESCRIPTOR (load, "LOAD");
+ $DESCRIPTOR (help, "HELP");
+ $DESCRIPTOR (quit, "QUIT");
+ $DESCRIPTOR (journal, "JOURNAL");
+ $DESCRIPTOR (restore, "RESTORE");
+ $DESCRIPTOR (rundown, "RUNDOWN");
+ $DESCRIPTOR (set, "SET");
+ $DESCRIPTOR (stop, "STOP");
+ $DESCRIPTOR (upgrade, "UPGRADE");
+
+ if (!dsccmp (action, &backup)) mupip_backup ();
+ else
+ if (!dsccmp (action, &convert)) mupip_cvtpgm ();
+ else
+ if (!dsccmp (action, &create)) mupip_create ();
+ else
+ if (!dsccmp (action, &exit)) mupip_exit (SS$_NORMAL);
+ else
+ if (!dsccmp (action, &extend)) mupip_extend ();
+ else
+ if (!dsccmp (action, &extract)) mu_extract ();
+ else
+ if (!dsccmp (action, &integ)) mupip_integ ();
+ else
+ if (!dsccmp (action, &load)) mupip_cvtgbl ();
+ else
+ if (!dsccmp (action, &help)) mupip_help ();
+ else
+ if (!dsccmp (action, &quit)) mupip_exit (SS$_NORMAL);
+ else
+ if (!dsccmp (action, &journal)) mupip_recover ();
+ else
+ if (!dsccmp (action, &restore)) mupip_restore ();
+ else
+ if (!dsccmp (action, &rundown)) mupip_rundown ();
+ else
+ if (!dsccmp (action, &set)) mupip_set ();
+ else
+ if (!dsccmp (action, &stop)) mupip_stop ();
+ else
+ if (!dsccmp (action, &upgrade)) mupip_upgrade ();
+ else
+ GTMASSERT;
+}
+
+int mupip_action_len ( struct dsc$descriptor *d)
+{
+ unsigned char *cp;
+
+ for (cp = d->dsc$a_pointer;
+ (char *) cp - d->dsc$a_pointer <= d->dsc$w_length &&
+ *cp != SP && *cp && *cp != 9;
+ cp++) ;
+ return (char *) cp - d->dsc$a_pointer;
+}
+
diff --git a/sr_vvms/mupip_exit.c b/sr_vvms/mupip_exit.c
new file mode 100644
index 0000000..89bd533
--- /dev/null
+++ b/sr_vvms/mupip_exit.c
@@ -0,0 +1,23 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <ssdef.h>
+#include "mupip_exit.h"
+
+GBLREF boolean_t mupip_exit_status_displayed;
+
+void mupip_exit(int4 stat)
+{
+ mupip_exit_status_displayed = TRUE;
+ sys$exit(stat ? stat : SS$_NORMAL);
+}
diff --git a/sr_vvms/mupip_ftok.c b/sr_vvms/mupip_ftok.c
new file mode 100644
index 0000000..8208070
--- /dev/null
+++ b/sr_vvms/mupip_ftok.c
@@ -0,0 +1,52 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <ssdef.h>
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "vmsdtype.h"
+#include "gtm_logicals.h"
+#include "cli.h"
+#include "util.h"
+#include "is_file_identical.h"
+#include "mupip_exit.h"
+
+#define MAX_PATH_LEN 256
+#define MAX_FTOK_LEN 32 /* 1 for length, 31 for the actual ftok */
+#define FTOK_PREFIX_SIZE 4
+
+void mupip_ftok()
+{
+ unsigned short prefix_size;
+ unsigned short filename_len;
+ char filename[MAX_PATH_LEN], prefix[FTOK_PREFIX_SIZE] = {'G', 'T', '$', 'S'};
+ gds_file_id gds_fid;
+ char ftok[MAX_FTOK_LEN];
+ error_def(ERR_MUPCLIERR);
+
+ filename_len = SIZEOF(filename);
+ prefix_size = SIZEOF(prefix);
+ if (!cli_get_str("FILE", filename, &filename_len))
+ mupip_exit(ERR_MUPCLIERR);
+ if (CLI_PRESENT == cli_present("PREFIX") && !cli_get_str("PREFIX", prefix, &prefix_size))
+ mupip_exit(ERR_MUPCLIERR);
+ set_gdid_from_file(&gds_fid, filename, filename_len);
+ global_name(prefix, &gds_fid, ftok);
+ util_out_print("!AD", TRUE, (char) ftok[0], &ftok[1]);
+ mupip_exit(SS$_NORMAL);
+}
diff --git a/sr_vvms/mupip_getcmd.c b/sr_vvms/mupip_getcmd.c
new file mode 100644
index 0000000..481ee37
--- /dev/null
+++ b/sr_vvms/mupip_getcmd.c
@@ -0,0 +1,76 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <rmsdef.h>
+#include <descrip.h>
+#include <climsgdef.h>
+#include <ssdef.h>
+#include "mupip_exit.h"
+
+#ifdef IPCRM_FOR_SANCHEZ_ONLY
+#define CMD_MODULE IPCRM_CMD
+#else
+#define CMD_MODULE MUPIP_CMD
+#endif
+
+
+extern int MUPIP_CMD(), IPCRM_CMD(),
+ CLI$DCL_PARSE(), CLI$DISPATCH();
+
+void mupip_getcmd(void)
+{
+ char buff[512];
+ $DESCRIPTOR(command,buff);
+
+ int status;
+ unsigned short outlen;
+ unsigned char buf[256];
+ $DESCRIPTOR (action, buf);
+ $DESCRIPTOR (prompt,"MUPIP> ");
+ $DESCRIPTOR (mupip_action, "MUPIP_ACTION");
+
+ status = lib$get_foreign(&command,0,&outlen,0);
+ if ((status & 1) && outlen > 0)
+ { command.dsc$w_length = outlen;
+ status = CLI$DCL_PARSE(&command ,&CMD_MODULE, &lib$get_input, 0, 0);
+ if (status == CLI$_NORMAL)
+ CLI$DISPATCH();
+ }else
+ { for (;;)
+ {
+ status = CLI$DCL_PARSE (0, &CMD_MODULE,
+ &lib$get_input, &lib$get_input,
+ &prompt);
+ if (status == RMS$_EOF)
+ break;
+ if (status == CLI$_NORMAL)
+ CLI$DISPATCH ();
+ }
+ }
+/*****************REVERT TO DCL COMMAND TABLE CODE**********************
+ status = CLI$GET_VALUE (&mupip_action, &action, 0);
+ if (status == CLI$_ABSENT)
+ for (;;)
+ {
+ status = CLI$DCL_PARSE (0, &CMD_MODULE,
+ &lib$get_input, &lib$get_input,
+ &prompt);
+ if (status == RMS$_EOF)
+ mupip_exit(SS$_NORMAL);
+ if (status == CLI$_NORMAL)
+ CLI$DISPATCH ();
+ }
+ else
+ mupip_dispatch (&action);
+**************************************************************************/
+ mupip_exit(SS$_NORMAL);
+}
diff --git a/sr_vvms/mupip_getcmd.h b/sr_vvms/mupip_getcmd.h
new file mode 100644
index 0000000..15b0eda
--- /dev/null
+++ b/sr_vvms/mupip_getcmd.h
@@ -0,0 +1,17 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef MUPIP_GETCMD_INCLUDED
+#define MUPIP_GETCMD_INCLUDED
+
+void mupip_getcmd(void);
+
+#endif /* MUPIP_GETCMD_INCLUDED */
diff --git a/sr_vvms/mupip_help.c b/sr_vvms/mupip_help.c
new file mode 100644
index 0000000..a86e96d
--- /dev/null
+++ b/sr_vvms/mupip_help.c
@@ -0,0 +1,36 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <ssdef.h>
+#include <climsgdef.h>
+#include <descrip.h>
+#include "mupip_help.h"
+
+#define HLP$M_PROMPT 1
+#define HELP_LIBRARY "GTM$HELP:MUPIP"
+
+void mupip_help(void)
+{
+
+ uint4 flags;
+ char buff[256];
+ $DESCRIPTOR(line, buff);
+ $DESCRIPTOR(libr, HELP_LIBRARY);
+ $DESCRIPTOR(ent, "QUERY");
+
+ if (CLI$PRESENT(&ent) != CLI$_PRESENT || CLI$GET_VALUE(&ent,&line) != SS$_NORMAL)
+ line.dsc$w_length = 0;
+ flags = HLP$M_PROMPT;
+ lbr$output_help(lib$put_output,0,&line,&libr,&flags,lib$get_input);
+ return;
+
+}
diff --git a/sr_vvms/mupip_restore.c b/sr_vvms/mupip_restore.c
new file mode 100644
index 0000000..b73fd1a
--- /dev/null
+++ b/sr_vvms/mupip_restore.c
@@ -0,0 +1,555 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <descrip.h>
+#include <iodef.h>
+#include <lckdef.h>
+#include <psldef.h>
+#include <rms.h>
+#include <ssdef.h>
+#include <errno.h>
+#include "gtm_socket.h"
+#include "gtm_inet.h"
+#include "gtm_time.h"
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "cli.h"
+#include "efn.h"
+#include "gdsblk.h"
+#include "gdsbml.h"
+#include "mupipbckup.h"
+#include "murest.h"
+#include "iotcproutine.h"
+#include "iotcpdef.h"
+#include "gt_timer.h"
+#include "io.h"
+#include "iotimer.h"
+#include "util.h"
+#include "gtm_caseconv.h"
+#include "bit_set.h"
+#include "is_proc_alive.h"
+#include "locks.h"
+#include "mu_rndwn_file.h"
+#include "dbfilop.h"
+#include "mupip_exit.h"
+#ifdef BACKUP_TO_EXEC
+#include "gtm_pipe.h"
+#include "mupip_restore.h"
+#endif
+#include "mu_outofband_setup.h"
+#include "mu_gv_cur_reg_init.h"
+#include "gtmmsg.h"
+#include "shmpool.h"
+#include "gds_blk_downgrade.h"
+#include "min_max.h"
+
+#define TCP_LENGTH 5
+#define COMMON_READ(A, B, C) { \
+ (*common_read)(A, B, C); \
+ if (0 != restore_read_errno) \
+ { \
+ free(inbuf); \
+ free(old_data); \
+ mupip_exit(restore_read_errno); \
+ } \
+ }
+
+GBLDEF inc_list_struct in_files;
+GBLREF gd_region *gv_cur_region;
+GBLREF uint4 restore_read_errno;
+GBLREF tcp_library_struct tcp_routines;
+GBLREF bool mubtomag;
+GBLREF int4 mubmaxblk;
+
+LITREF char *gtm_dbversion_table[];
+
+error_def(ERR_MUNODBNAME);
+error_def(ERR_MUPRESTERR);
+error_def(ERR_MUSTANDALONE);
+
+static void tcp_read(char *temp, char *buf, int nbytes);
+static void record_read(char *temp, char *buf, int nbytes);
+void exec_read(char *temp, char *buf, int nbytes);
+
+void mupip_restore(void)
+{
+ static readonly char label[] = GDS_LABEL;
+ inc_list_struct *ptr;
+ inc_header *inhead;
+ sgmnt_data *old_data;
+ trans_num curr_tn;
+ block_id blk_num;
+ struct FAB extfab, infab;
+ struct XABFHC muxab;
+ struct RAB inrab, extrab;
+ file_control *fc;
+ int i, size, next_pos, backup_socket, size1;
+ uint4 cli_status, cur_tot, rest_blks, status, totblks, bplmap, ii;
+ char buff[DISK_BLOCK_SIZE], *inbuf, *common, *p, tcp[TCP_LENGTH], addr[SA_MAXLEN+1], *blk_ptr;
+ char *newmap, *newmap_bptr;
+ char_ptr_t ptr1, ptr1_top;
+ backup_type type;
+ int4 timeout, cut, match, temp_int4;
+ unsigned short port;
+ boolean_t extend;
+ void (*common_read)(char *, char *, int);
+ muinc_blk_hdr_ptr_t sblkh_p;
+
+ if (!mubtomag)
+ mubmaxblk = BACKUP_TEMPFILE_BUFF_SIZE;
+ extend = TRUE;
+ if (CLI_NEGATED == (cli_status = cli_present("EXTEND")))
+ extend = FALSE;
+ mu_outofband_setup();
+ mu_gv_cur_reg_init();
+ gv_cur_region->dyn.addr->fname_len = SIZEOF(gv_cur_region->dyn.addr->fname);
+ if (0 == cli_get_str("DATABASE", gv_cur_region->dyn.addr->fname, &gv_cur_region->dyn.addr->fname_len))
+ mupip_exit(ERR_MUNODBNAME);
+ if (!mu_rndwn_file(TRUE))
+ {
+ gtm_putmsg(VARLSTCNT(4) ERR_MUSTANDALONE, 2, DB_LEN_STR(gv_cur_region));
+ mupip_exit(ERR_MUPRESTERR);
+ }
+ fc = gv_cur_region->dyn.addr->file_cntl;
+ fc->file_type = dba_bg;
+ fc->op = FC_OPEN;
+ status = dbfilop(fc);
+ if (SS$_NORMAL != status)
+ {
+ gtm_putmsg(VARLSTCNT(1) status);
+ util_out_print("Error accessing output file !AD. Aborting restore.", TRUE, DB_LEN_STR(gv_cur_region));
+ mupip_exit(status);
+ }
+ murgetlst();
+ old_data = malloc(ROUND_UP(SIZEOF(sgmnt_data), DISK_BLOCK_SIZE));
+ fc->op = FC_READ;
+ fc->op_buff = old_data;
+ fc->op_len = ROUND_UP(SIZEOF(sgmnt_data), DISK_BLOCK_SIZE);
+ fc->op_pos = 1;
+ dbfilop(fc);
+ if (memcmp(&old_data->label[0], &label[0], SIZEOF(old_data->label)))
+ {
+ util_out_print("Output file !AD has an unrecognizable format", TRUE, DB_LEN_STR(gv_cur_region));
+ free(old_data);
+ mupip_exit(ERR_MUPRESTERR);
+ }
+ inbuf = malloc(MAX(mubmaxblk, MAX((old_data->blk_size + SIZEOF(muinc_blk_hdr)),
+ MAX(SGMNT_HDR_LEN, MASTER_MAP_SIZE_MAX))));
+ cur_tot = old_data->trans_hist.total_blks;
+ curr_tn = old_data->trans_hist.curr_tn;
+ bplmap = old_data->bplmap;
+ inhead = malloc(SIZEOF(inc_header));
+ rest_blks = 0;
+ for (ptr = in_files.next; ptr; ptr = ptr->next)
+ {
+ /* --- determine source type --- */
+ type = backup_to_file;
+ if (0 == ptr->input_file.len)
+ continue;
+ else if ('|' == *(ptr->input_file.addr + ptr->input_file.len - 1))
+ {
+ type = backup_to_exec;
+ ptr->input_file.len--;
+ *(ptr->input_file.addr + ptr->input_file.len) = '\0';
+ } else if (ptr->input_file.len > TCP_LENGTH)
+ {
+ lower_to_upper(tcp, ptr->input_file.addr, TCP_LENGTH);
+ if (0 == memcmp(tcp, "TCP:/", TCP_LENGTH))
+ {
+ type = backup_to_tcp;
+ cut = TCP_LENGTH;
+ while ('/' == *(ptr->input_file.addr + cut))
+ cut++;
+ ptr->input_file.len -= cut;
+ p = ptr->input_file.addr;
+ while (p < ptr->input_file.addr + ptr->input_file.len)
+ {
+ *p = *(p + cut);
+ p++;
+ }
+ *p = '\0';
+ }
+ }
+ /* --- open the input stream --- */
+ restore_read_errno = 0;
+ switch(type)
+ {
+ case backup_to_file:
+ infab = cc$rms_fab;
+ infab.fab$b_fac = FAB$M_GET;
+ infab.fab$l_fna = ptr->input_file.addr;
+ infab.fab$b_fns = ptr->input_file.len;
+ inrab = cc$rms_rab;
+ inrab.rab$l_fab = &infab;
+ if ((RMS$_NORMAL != (status = sys$open(&infab))) ||
+ (RMS$_NORMAL != (status = sys$connect(&inrab))))
+ {
+ gtm_putmsg(VARLSTCNT(1) status);
+ util_out_print("Error accessing input file !AD. Aborting restore.", TRUE,
+ infab.fab$b_fns, infab.fab$l_fna);
+ free(inbuf);
+ free(old_data);
+ free(inhead);
+ mupip_exit(status);
+ }
+ common_read = record_read;
+ common = (char *)(&inrab);
+ break;
+ case backup_to_exec:
+# ifdef BACKUP_TO_EXEC
+ pipe_child = 0;
+ common_read = exec_read;
+ in = (BFILE *)malloc(SIZEOF(BFILE));
+ if (0 > (in->fd = gtm_pipe(ptr->input_file.addr, input_from_comm)))
+ {
+ util_out_print("Error creating input pipe from !AD.", TRUE, ptr->input_file.len, ptr->input_
+ file.addr);
+ mupip_exit(ERR_MUPRESTERR);
+ }
+ DBGFPF(stdout, "file descriptor for the openned pipe is %d.\n", in->fd);
+ DBGFPF(stdout, "the command passed to gtm_pipe is %s.\n", ptr->input_file.addr);
+ break;
+# endif
+ case backup_to_tcp:
+ /* parse the input */
+ switch (match = SSCANF(ptr->input_file.addr, "%[^:]:%hu", addr, &port))
+ {
+ case 1:
+ port = DEFAULT_BKRS_PORT;
+ case 2:
+ break;
+ default:
+ util_out_print("Error : A hostname has to be specified.", TRUE);
+ free(inbuf);
+ free(old_data);
+ free(inhead);
+ mupip_exit(ERR_MUPRESTERR);
+ }
+ if ((0 == cli_get_int("NETTIMEOUT", &timeout)) || (0 > timeout))
+ timeout = DEFAULT_BKRS_TIMEOUT;
+ iotcp_fillroutine();
+ if (0 > (backup_socket = tcp_open(addr, port, timeout, TRUE)))
+ {
+ util_out_print("Error establishing TCP connection to !AD.", TRUE,
+ ptr->input_file.len, ptr->input_file.addr);
+ free(inbuf);
+ free(old_data);
+ free(inhead);
+ mupip_exit(ERR_MUPRESTERR);
+ }
+ common_read = tcp_read;
+ common = (char *)(&backup_socket);
+ break;
+ default:
+ util_out_print("Aborting restore!/", TRUE);
+ util_out_print("Unrecognized input format !AD", TRUE, ptr->input_file.len, ptr->input_file.addr);
+ free(inbuf);
+ free(old_data);
+ free(inhead);
+ mupip_exit(ERR_MUPRESTERR);
+ }
+ size = SIZEOF(inc_header);
+ COMMON_READ(common, (char *)(inhead), size);
+ /* validate incremental backup header */
+ if (0 != memcmp(&inhead->label[0], INC_HEADER_LABEL, INC_HDR_LABEL_SZ))
+ {
+ util_out_print("Input !AD has an unrecognizable format", TRUE, ptr->input_file.len, ptr->input_file.addr);
+ free(inbuf);
+ free(old_data);
+ free(inhead);
+ mupip_exit(ERR_MUPRESTERR);
+ }
+ if (curr_tn != inhead->start_tn)
+ {
+ util_out_print("Transaction in input !AD does not align with database TN.!/DB: 0x!16 at XQ!_Input : 0x!16 at XQ",
+ TRUE, ptr->input_file.len, ptr->input_file.addr, &curr_tn, &inhead->start_tn);
+ free(inbuf);
+ free(old_data);
+ free(inhead);
+ mupip_exit(ERR_MUPRESTERR);
+ }
+ if (old_data->blk_size != inhead->blk_size)
+ {
+ util_out_print("Incompatible block size. Output file !AD has block size !XL,", TRUE,
+ DB_LEN_STR(gv_cur_region), old_data->blk_size);
+ util_out_print("while input !AD is from a database with block size !XL,", TRUE,
+ ptr->input_file.len, ptr->input_file.addr, inhead->blk_size);
+ free(inbuf);
+ free(old_data);
+ free(inhead);
+ mupip_exit(ERR_MUPRESTERR);
+ }
+ assert(0 < cur_tot);
+ if (cur_tot != inhead->db_total_blks)
+ {
+ if (cur_tot > inhead->db_total_blks || !extend)
+ {
+ totblks = cur_tot - DIVIDE_ROUND_UP(cur_tot, DISK_BLOCK_SIZE);
+ util_out_print("Incompatible database sizes. Output file !AD has!/ !UL (!XL hex) total blocks,",
+ TRUE, DB_LEN_STR(gv_cur_region), totblks, totblks);
+ totblks = inhead->db_total_blks - DIVIDE_ROUND_UP(inhead->db_total_blks, DISK_BLOCK_SIZE);
+ util_out_print("while input !AD is from a database with!/ !UL (!XL hex) total blocks", TRUE,
+ ptr->input_file.len, ptr->input_file.addr, totblks, totblks);
+ free(inbuf);
+ free(old_data);
+ free(inhead);
+ mupip_exit(ERR_MUPRESTERR);
+ } else
+ { /* Although we are extending the file, we need not write any local bit maps like would occur
+ * with a regular extension of the db. This is because the backup process makes sure that any
+ * necessary bitmaps are part of the backup and will thus be properly restored.
+ */
+ muxab = cc$rms_xabfhc;
+ extrab = cc$rms_rab;
+ extrab.rab$l_fab = &extfab;
+ extfab = cc$rms_fab;
+ extfab.fab$l_xab = &muxab;
+ extfab.fab$l_fna = gv_cur_region->dyn.addr->fname;
+ extfab.fab$b_fns = gv_cur_region->dyn.addr->fname_len;
+ extfab.fab$b_fac = FAB$M_BIO | FAB$M_PUT;
+ extfab.fab$l_fop = FAB$M_CBT;
+ extfab.fab$b_shr = FAB$M_SHRPUT | FAB$M_UPI;
+ if ((RMS$_NORMAL != (status = sys$open(&extfab))) ||
+ (RMS$_NORMAL != (status = sys$connect(&extrab))))
+ {
+ util_out_print("Cannot extend output file.",TRUE);
+ free(inbuf);
+ free(old_data);
+ free(inhead);
+ mupip_exit(ERR_MUPRESTERR);
+ }
+ memset(buff, 0, DISK_BLOCK_SIZE);
+ extrab.rab$l_rbf = buff;
+ extrab.rab$w_rsz = DISK_BLOCK_SIZE;
+ extrab.rab$l_bkt =
+ old_data->start_vbn - 1 + (inhead->db_total_blks * (old_data->blk_size / DISK_BLOCK_SIZE));
+ if (RMS$_NORMAL != (status = sys$write(&extrab)))
+ {
+ util_out_print("Cannot write to output file.",TRUE);
+ free(inbuf);
+ free(old_data);
+ free(inhead);
+ mupip_exit(ERR_MUPRESTERR);
+ }
+ sys$close(&extfab);
+ /* --- initialize all new bitmaps, just in case they are not touched later --- */
+ if (DIVIDE_ROUND_DOWN(inhead->db_total_blks, bplmap) > DIVIDE_ROUND_DOWN(cur_tot, bplmap))
+ { /* -- similar logic exist in bml_newmap.c, which need to pick up any new updates here -- */
+ newmap = (char *)malloc(old_data->blk_size);
+ ((blk_hdr *)newmap)->bver = GDSVCURR;
+ ((blk_hdr *)newmap)->bsiz = BM_SIZE(bplmap);
+ ((blk_hdr *)newmap)->levl = LCL_MAP_LEVL;
+ ((blk_hdr *)newmap)->tn = curr_tn;
+ newmap_bptr = newmap + SIZEOF(blk_hdr);
+ *newmap_bptr++ = THREE_BLKS_FREE;
+ memset(newmap_bptr, FOUR_BLKS_FREE, BM_SIZE(bplmap) - SIZEOF(blk_hdr) - 1);
+ fc->op = FC_WRITE;
+ fc->op_buff = newmap;
+ for (ii = ROUND_UP(cur_tot, bplmap); ii < inhead->db_total_blks; ii += bplmap)
+ {
+ fc->op_pos = old_data->start_vbn
+ + ((gtm_int64_t)old_data->blk_size / DISK_BLOCK_SIZE * ii);
+ dbfilop(fc);
+ }
+ free(newmap);
+ }
+ cur_tot = inhead->db_total_blks;
+ }
+ }
+ fc->op = FC_WRITE;
+ fc->op_buff = inbuf + SIZEOF(muinc_blk_hdr);
+ sblkh_p = (muinc_blk_hdr_ptr_t)inbuf;
+ size = SIZEOF(muinc_blk_hdr) + old_data->blk_size;
+ for ( ; ;)
+ {
+ COMMON_READ(common, inbuf, size);
+ if (0 == MEMCMP_LIT(inbuf, END_MSG))
+ break;
+ blk_num = ((muinc_blk_hdr_ptr_t)inbuf)->blkid;
+ fc->op_pos = old_data->start_vbn + ((gtm_int64_t)old_data->blk_size / DISK_BLOCK_SIZE * blk_num);
+ /* For blocks that were read during the main backup phase of stream backup, the blocks are
+ * recorded without version (there may even be some garbage blocks in the stream of
+ * indeterminate/invalid format if a bitmap was written out prior to the data blocks that
+ * were recently allocated in it). For these blocks, we just write out what we have as a
+ * full block. For blocks that were written out during the backup as part of the online
+ * image processing, these are always recorded in V5 mode. We will rewrite these in the mode
+ * they were oringally found on disk (potentially necessitating a downgrade of the block).
+ * This allows us to exactly match the blks_to_upgrade counter in the saved file-header without
+ * worrying about what blocks were converted (or not) in the interim.
+ */
+ blk_ptr = inbuf + SIZEOF(muinc_blk_hdr);
+ if (GDSNOVER != sblkh_p->use.bkup.ondsk_blkver)
+ { /* Specifically versioned blocks - Put them back in the version they were originally */
+ if (GDSV4 == sblkh_p->use.bkup.ondsk_blkver)
+ {
+ gds_blk_downgrade((v15_blk_hdr_ptr_t)blk_ptr, (blk_hdr_ptr_t)blk_ptr);
+ fc->op_len = (((v15_blk_hdr_ptr_t)blk_ptr)->bsiz + 1) & ~1;
+ } else
+ fc->op_len = (((blk_hdr_ptr_t)blk_ptr)->bsiz + 1) & ~1;
+ } else
+ fc->op_len = old_data->blk_size;
+ rest_blks++;
+ dbfilop(fc);
+ }
+ /* Next section is the file header which we need to restore. */
+ ptr1 = inbuf;
+ size1 = ROUND_UP(SIZEOF(sgmnt_data), DISK_BLOCK_SIZE);
+ ptr1_top = ptr1 + size1;
+ fc->op_len = size1;
+ assert(size1 <= mubmaxblk);
+ COMMON_READ(common, ptr1, size1);
+ ((sgmnt_data_ptr_t)inbuf)->start_vbn = old_data->start_vbn;
+ ((sgmnt_data_ptr_t)inbuf)->free_space = ((old_data->start_vbn - 1) * DISK_BLOCK_SIZE) - SIZEOF_FILE_HDR(inbuf);
+ fc->op_buff = inbuf; /* reset since no block_id for header */
+ fc->op_pos = 1;
+ dbfilop(fc);
+ size1 = ROUND_UP(((sgmnt_data_ptr_t)inbuf)->master_map_len, DISK_BLOCK_SIZE);
+ COMMON_READ(common, inbuf, SIZEOF(HDR_MSG));
+ if (MEMCMP_LIT(inbuf, HDR_MSG))
+ { /* We didn't read the record we were supposed to. We just wrecked the db most likely */
+ util_out_print("Invalid information in restore file !AD. Aborting restore.",
+ TRUE, ptr->input_file.len,
+ ptr->input_file.addr);
+ assert(FALSE);
+ free(inbuf);
+ free(old_data);
+ free(inhead);
+ mupip_exit(ERR_MUPRESTERR);
+ }
+ /* Now for the master map. Use size gleened from master map length */
+ ptr1 = inbuf;
+ ptr1_top = ptr1 + size1;
+ fc->op_len = size1;
+ for (;ptr1 < ptr1_top ; ptr1 += size1)
+ {
+ if ((size1 = ptr1_top - ptr1) > mubmaxblk)
+ size1 = (mubmaxblk / DISK_BLOCK_SIZE) * DISK_BLOCK_SIZE;
+ COMMON_READ(common, ptr1, size1);
+ }
+ fc->op_buff = inbuf; /* reset since no block_id for header */
+ fc->op_pos = MM_BLOCK;
+ dbfilop(fc);
+ COMMON_READ(common, inbuf, SIZEOF(MAP_MSG));
+ if (MEMCMP_LIT(inbuf, MAP_MSG))
+ { /* We didn't read the record we were supposed to. We just wrecked the db most likely */
+ util_out_print("Invalid information in restore file !AD. Aborting restore.",
+ TRUE, ptr->input_file.len,
+ ptr->input_file.addr);
+ assert(FALSE);
+ free(inbuf);
+ free(old_data);
+ free(inhead);
+ mupip_exit(ERR_MUPRESTERR);
+ }
+ curr_tn = inhead->end_tn;
+ switch(type)
+ {
+ case backup_to_file:
+ if (RMS$_NORMAL != (status = sys$close(&infab)))
+ {
+ gtm_putmsg(VARLSTCNT(1) status);
+ util_out_print("WARNING: DB file !AD restore aborted, file !AD not valid", TRUE,
+ DB_LEN_STR(gv_cur_region),
+ ptr->input_file.len, ptr->input_file.addr);;
+ free(inbuf);
+ free(old_data);
+ free(inhead);
+ mupip_exit(ERR_MUPRESTERR);
+ }
+ break;
+ case backup_to_exec:
+# ifdef BACKUP_TO_EXEC
+ close(in->fd);
+ if ((pipe_child > 0) && (FALSE != is_proc_alive(pipe_child, 0)))
+ waitpid(pipe_child, &status, 0); /* BYPASSOK */
+# endif
+ break;
+ case backup_to_tcp:
+ tcp_routines.aa_close(backup_socket);
+ break;
+ }
+ }
+ util_out_print("!/RESTORE COMPLETED", TRUE);
+ util_out_print("!UL blocks restored", TRUE, rest_blks);
+ free(inbuf);
+ free(old_data);
+ free(inhead);
+ mupip_exit(SS$_NORMAL);
+}
+
+static void record_read(char *temp, char *buf, int nbytes) /* *nbytes is what we are asking, normally, is what we get + 4 */
+{
+ struct RAB *rab;
+ int4 status;
+
+ rab = (struct RAB *)(temp);
+ rab->rab$w_usz = nbytes;
+ rab->rab$l_ubf = buf;
+ status = sys$get(rab);
+ if (RMS$_NORMAL != status)
+ {
+ gtm_putmsg(VARLSTCNT(1) status);
+ util_out_print("Error accessing input file !AD. Aborting restore.", TRUE,
+ rab->rab$l_fab->fab$b_fns, rab->rab$l_fab->fab$l_fna);
+ sys$close(rab->rab$l_fab);
+ mupip_exit(status);
+ }
+ assert(nbytes == (int)(rab->rab$w_rsz) || 0 == MEMCMP_LIT(buf, "GDS"));
+ return;
+}
+
+static void tcp_read(char *temp, char *buf, int nbytes) /* asking for *nbytes, have to return *nbytes */
+{
+ int socket, needed, status;
+ char *curr;
+ fd_set fs;
+ ABS_TIME nap;
+
+ needed = nbytes;
+ curr = buf;
+ socket = *(int *)(temp);
+ nap.at_sec = 1;
+ nap.at_usec = 0;
+ while (1)
+ {
+ FD_ZERO(&fs);
+ FD_SET(socket, &fs);
+ assert(0 != FD_ISSET(socket, &fs));
+ status = tcp_routines.aa_select(socket + 1, (void *)(&fs), (void *)0, (void *)0, &nap);
+ if (status > 0)
+ {
+ status = tcp_routines.aa_recv(socket, curr, needed, 0);
+ if ((0 == status) || (needed == status)) /* lost connection or all set */
+ {
+ break;
+ } else if (status > 0)
+ {
+ needed -= status;
+ curr += status;
+ }
+ }
+ if ((status < 0) && (errno != EINTR))
+ {
+ gtm_putmsg(VARLSTCNT(1) errno);
+ tcp_routines.aa_close(socket);
+ restore_read_errno = errno;
+ break;
+ }
+ }
+ return;
+}
diff --git a/sr_vvms/mupip_rundown.c b/sr_vvms/mupip_rundown.c
new file mode 100644
index 0000000..8f7192e
--- /dev/null
+++ b/sr_vvms/mupip_rundown.c
@@ -0,0 +1,376 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_fcntl.h"
+#include "gtm_unistd.h"
+#include "gtm_inet.h" /* Required for gtmsource.h */
+#include "gtm_stdlib.h"
+#include "gtm_string.h"
+#include <clidef.h>
+#include <iodef.h>
+#include <jpidef.h>
+#include <rms.h>
+#include <ssdef.h>
+#include <prtdef.h>
+#include <secdef.h>
+#include <psldef.h>
+#include <descrip.h>
+#include <errno.h>
+#include <efndef.h>
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "cli.h"
+#include "error.h"
+#include "mupipbckup.h"
+#include "vmsdtype.h"
+#include "gdscc.h"
+#include "gdskill.h"
+#include "jnl.h"
+#include "buddy_list.h" /* needed for tp.h */
+#include "hashtab_int4.h" /* needed for tp.h */
+#include "tp.h"
+#include "iosp.h"
+#include "gbldirnam.h"
+#include "repl_sem.h"
+#include "repl_msg.h"
+#include "gtmsource.h"
+#include "gtmrecv.h"
+#include "util.h"
+#include "mu_rndwn_file.h"
+#include "mu_rndwn_replpool.h"
+#include "is_file_identical.h"
+#include "dbfilop.h"
+#include "mupip_exit.h"
+#include "del_sec.h"
+#include "fid_from_sec.h"
+#include "mu_getlst.h"
+#include "mu_outofband_setup.h"
+#include "dpgbldir.h"
+#include "dpgbldir_sysops.h"
+#include "mu_gv_cur_reg_init.h"
+#include "gtmmsg.h"
+#include "gtm_logicals.h"
+
+#define SYS_EXC 0
+#define MAILBOX_SIZE 512
+
+GBLREF tp_region *grlist;
+GBLREF bool in_backup;
+GBLREF bool error_mupip;
+GBLREF gd_region *gv_cur_region;
+GBLREF bool mu_ctrly_occurred;
+GBLREF bool mu_ctrlc_occurred;
+GBLREF boolean_t mu_star_specified;
+GBLREF boolean_t mu_rndwn_process;
+static readonly $DESCRIPTOR(d_pnam, "GTM$MURNDWNPRC");
+static uint4 rndwn_pid;
+
+error_def(ERR_ASSERT);
+error_def(ERR_GTMASSERT);
+error_def(ERR_GTMASSERT2);
+error_def(ERR_GTMCHECK);
+error_def(ERR_MUDESTROYFAIL);
+error_def(ERR_MUDESTROYSUC);
+error_def(ERR_MUFILRNDWNFL);
+error_def(ERR_MUFILRNDWNSUC);
+error_def(ERR_MUJPOOLRNDWNFL);
+error_def(ERR_MUJPOOLRNDWNSUC);
+error_def(ERR_MUNOACTION);
+error_def(ERR_MUNODBNAME);
+error_def(ERR_MUNOTALLSEC);
+error_def(ERR_MUPCLIERR);
+error_def(ERR_MUREPLSECDEL);
+error_def(ERR_MUREPLSECNOTDEL);
+error_def(ERR_MURPOOLRNDWNFL);
+error_def(ERR_MURPOOLRNDWNSUC);
+error_def(ERR_MUSECDEL);
+error_def(ERR_MUSECNOTDEL);
+error_def(ERR_STACKOFLOW);
+error_def(ERR_VMSMEMORY);
+
+CONDITION_HANDLER(mupip_rundown_ch)
+{
+ START_CH;
+ if ((0 != rndwn_pid) && !(SEVERITY & SUCCESS))
+ {
+ if (DUMPABLE)
+ {
+ sys$delprc(NULL, &d_pnam);
+ if (!SUPPRESS_DUMP)
+ TERMINATE;
+ } else
+ UNWIND(NULL, NULL);
+ } else if (DUMPABLE && !SUPPRESS_DUMP)
+ TERMINATE;
+ NEXTCH;
+}
+
+void mupip_rundown(void)
+{
+ uint4 channel, exit_status, flags, status;
+ unsigned int full_len;
+ unsigned short iosb[4];
+ unsigned char *c, mbuff[MAILBOX_SIZE];
+ boolean_t region, file, arg_present;
+ file_control *fc;
+ tp_region *rptr;
+ char name_buff[GLO_NAME_MAXLEN], res_name[MAX_NAME_LEN + 2]; /* +1 for the terminating null and another +1 for
+ the length stored in [0] by global_name() */
+ boolean_t sgmnt_found;
+ mstr gbldir_mstr, *tran_name;
+ gds_file_id file_id;
+ replpool_identifier replpool_id;
+ struct dsc$descriptor_s name_dsc;
+ $DESCRIPTOR(d_sec, mbuff);
+ static readonly $DESCRIPTOR(d_cmd, "install lis/glo");
+ static readonly $DESCRIPTOR(d_mnam, "GTM$MURNDWNMBX");
+
+ exit_status = SS$_NORMAL;
+ mu_rndwn_process = TRUE;
+ mu_outofband_setup();
+
+ file = (CLI_PRESENT == cli_present("FILE"));
+ region = (CLI_PRESENT == cli_present("REGION"));
+ arg_present = (CLI_PRESENT == cli_present("DBFILE"));
+ if (arg_present && !file && !region)
+ {
+ util_out_print("MUPIP RUNDOWN only accepts a parameter when -FILE or -REGION is specified.", TRUE);
+ mupip_exit(ERR_MUPCLIERR);
+ }
+ if (!arg_present)
+ {
+ mu_gv_cur_reg_init();
+ status = sys$crembx(0, &channel, SIZEOF(mbuff), 0, 0, PSL$C_USER, &d_mnam);
+ if (SS$_NORMAL != status)
+ mupip_exit(status);
+ flags = CLI$M_NOWAIT | CLI$M_NOLOGNAM;
+ ESTABLISH(mupip_rundown_ch);
+ status = lib$spawn(&d_cmd, 0, &d_mnam, &flags, &d_pnam, &rndwn_pid);
+ if (SS$_NORMAL != status)
+ {
+ if (SS$_DUPLNAM == status)
+ util_out_print("Spawned process GTM$MURNDWNPRC already exists, cannot continue rundown", TRUE);
+ util_out_print("If the prior RUNDOWN ended abnormally, STOP GTM$MURNDWNPRC and retry", TRUE);
+ mupip_exit(status);
+ }
+ for (; ;)
+ {
+ status = sys$qiow(EFN$C_ENF, channel, IO$_READVBLK, &iosb, 0, 0, mbuff, SIZEOF(mbuff), 0, 0, 0, 0);
+ if (SS$_NORMAL != status)
+ {
+ mupip_exit(status);
+ break;
+ }
+ if (SS$_ENDOFFILE == iosb[0])
+ break;
+ if (SS$_NORMAL != iosb[0])
+ {
+ mupip_exit(iosb[0]);
+ break;
+ }
+ if ((FALSE == mu_ctrly_occurred) && (FALSE == mu_ctrlc_occurred))
+ {
+ if (0 == memcmp("GT$S", mbuff, SIZEOF("GT$S") - 1))
+ {
+ for (c = mbuff; *c > 32; c++)
+ ;
+ d_sec.dsc$w_length = c - mbuff;
+ fid_from_sec(&d_sec, &FILE_INFO(gv_cur_region)->file_id);
+ status = mu_rndwn_file(FALSE);
+ if (gv_cur_region->read_only)
+ status = RMS$_PRV;
+ if (SS$_NORMAL == status)
+ {
+ sys$dassgn(FILE_INFO(gv_cur_region)->fab->fab$l_stv);
+ gv_cur_region->open = FALSE;
+ } else
+ {
+ if (RMS$_FNF == status)
+ status = del_sec(SEC$M_SYSGBL, &d_sec, 0);
+ }
+ if (status & 1)
+ rts_error(VARLSTCNT(4) ERR_MUSECDEL, 2, d_sec.dsc$w_length, d_sec.dsc$a_pointer);
+ else
+ {
+ if (status)
+ gtm_putmsg(VARLSTCNT(1) status);
+ rts_error(VARLSTCNT(4) ERR_MUSECNOTDEL, 2, d_sec.dsc$w_length, d_sec.dsc$a_pointer);
+ exit_status = ERR_MUNOTALLSEC;
+ }
+ } else if ((0 == memcmp("GT$P", mbuff, SIZEOF("GT$P") - 1)) ||
+ (0 == memcmp("GT$R", mbuff, SIZEOF("GT$R") - 1)))
+ {
+ for (c = mbuff; *c > 32; c++)
+ ;
+ mbuff[c - mbuff] = '\0';
+ strcpy(replpool_id.repl_pool_key, mbuff);
+ if (!memcmp("GT$P", mbuff, SIZEOF("GT$P") - 1))
+ replpool_id.pool_type = JNLPOOL_SEGMENT;
+ else
+ replpool_id.pool_type = RECVPOOL_SEGMENT;
+ sgmnt_found = FALSE;
+ if (mu_rndwn_replpool(&replpool_id, TRUE, &sgmnt_found) && sgmnt_found)
+ rts_error(VARLSTCNT(4) ERR_MUREPLSECDEL, 2, LEN_AND_STR(mbuff));
+ else if (sgmnt_found)
+ {
+ rts_error(VARLSTCNT(4) ERR_MUREPLSECNOTDEL, 2, LEN_AND_STR(mbuff));
+ exit_status = ERR_MUNOTALLSEC;
+ }
+ }
+ }
+ }
+ rndwn_pid = 0;
+ REVERT;
+ mupip_exit(exit_status);
+ } else
+ {
+ if (region)
+ {
+ gvinit();
+ region = TRUE;
+ mu_getlst("DBFILE", SIZEOF(tp_region));
+ rptr = grlist;
+ if (error_mupip)
+ exit_status = ERR_MUNOTALLSEC;
+ } else
+ {
+ region = FALSE;
+ mu_gv_cur_reg_init();
+ gv_cur_region->dyn.addr->fname_len = SIZEOF(gv_cur_region->dyn.addr->fname);
+ if (0 == cli_get_str("DBFILE", (char *)&gv_cur_region->dyn.addr->fname,
+ &gv_cur_region->dyn.addr->fname_len))
+ mupip_exit(ERR_MUNODBNAME);
+ }
+ for (; ; rptr = rptr->fPtr)
+ {
+ if (region)
+ {
+ if (NULL == rptr)
+ break;
+ if (dba_usr == rptr->reg->dyn.addr->acc_meth)
+ {
+ util_out_print("!/Can't RUNDOWN region !AD; not GDS format", TRUE, REG_LEN_STR(rptr->reg));
+ continue;
+ }
+ if (!mupfndfil(rptr->reg, NULL))
+ {
+ exit_status = ERR_MUNOTALLSEC;
+ continue;
+ }
+ gv_cur_region = rptr->reg;
+ if (NULL == gv_cur_region->dyn.addr->file_cntl)
+ {
+ gv_cur_region->dyn.addr->acc_meth = dba_bg;
+ gv_cur_region->dyn.addr->file_cntl =
+ (file_control *)malloc(SIZEOF(*gv_cur_region->dyn.addr->file_cntl));
+ memset(gv_cur_region->dyn.addr->file_cntl, 0, SIZEOF(*gv_cur_region->dyn.addr->file_cntl));
+ gv_cur_region->dyn.addr->file_cntl->file_type = dba_bg;
+ gv_cur_region->dyn.addr->file_cntl->file_info = (GDS_INFO *)malloc(SIZEOF(GDS_INFO));
+ memset(gv_cur_region->dyn.addr->file_cntl->file_info, 0, SIZEOF(GDS_INFO));
+ }
+ }
+ status = mu_rndwn_file(FALSE);
+ if (SS$_NORMAL == status)
+ {
+#ifdef IPCRM_FOR_SANCHEZ_ONLY
+ global_name("GT$S", &FILE_INFO(gv_cur_region)->file_id, name_buff);
+ name_dsc.dsc$a_pointer = &name_buff[1];
+ name_dsc.dsc$w_length = (short)name_buff[0];
+ name_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
+ name_dsc.dsc$b_class = DSC$K_CLASS_S;
+ status = del_sec(SEC$M_SYSGBL, &name_dsc, 0);
+#endif
+ sys$dassgn(FILE_INFO(gv_cur_region)->fab->fab$l_stv);
+ }
+ if (status & 1)
+ {
+#ifdef IPCRM_FOR_SANCHEZ_ONLY
+ rts_error(VARLSTCNT(6) ERR_MUDESTROYSUC, 4,
+ name_dsc.dsc$w_length, name_dsc.dsc$a_pointer, DB_LEN_STR(gv_cur_region));
+#else
+ rts_error(VARLSTCNT(4) ERR_MUFILRNDWNSUC, 2, DB_LEN_STR(gv_cur_region));
+#endif
+ }
+ else
+ {
+ if (status)
+ gtm_putmsg(VARLSTCNT(1) status);
+#ifdef IPCRM_FOR_SANCHEZ_ONLY
+ rts_error(VARLSTCNT(6) ERR_MUDESTROYFAIL, 4,
+ name_dsc.dsc$w_length, name_dsc.dsc$a_pointer, DB_LEN_STR(gv_cur_region));
+ exit_status = ERR_MUNOACTION;
+#else
+ gtm_putmsg(VARLSTCNT(4) ERR_MUFILRNDWNFL, 2, DB_LEN_STR(gv_cur_region));
+ exit_status = ERR_MUNOTALLSEC;
+#endif
+ }
+ if ((FALSE == region) || (TRUE == mu_ctrly_occurred) || (TRUE == mu_ctrlc_occurred))
+ break;
+ }
+ if (region && mu_star_specified)
+ {
+ gbldir_mstr.addr = GTM_GBLDIR;
+ gbldir_mstr.len = SIZEOF(GTM_GBLDIR) - 1;
+ tran_name = get_name(&gbldir_mstr);
+ memcpy(replpool_id.gtmgbldir, tran_name->addr, tran_name->len);
+ replpool_id.gtmgbldir[tran_name->len] = '\0';
+ full_len = tran_name->len;
+ if (!get_full_path(replpool_id.gtmgbldir, tran_name->len,
+ replpool_id.gtmgbldir, &full_len, SIZEOF(replpool_id.gtmgbldir), &status))
+ {
+ util_out_print("Failed to get full path for gtmgbldir, !AD", TRUE, tran_name->len, tran_name->addr);
+ gtm_putmsg(VARLSTCNT(1) status);
+ exit_status = ERR_MUNOTALLSEC;
+ } else
+ {
+ tran_name->len = full_len; /* since on vax, mstr.len is a 'short' */
+ set_gdid_from_file((gd_id_ptr_t)&file_id, replpool_id.gtmgbldir, tran_name->len);
+ global_name("GT$P", &file_id, res_name); /* P - Stands for Journal Pool */
+ res_name[res_name[0] + 1] = '\0';
+ strcpy(replpool_id.repl_pool_key, &res_name[1]);
+ replpool_id.pool_type = JNLPOOL_SEGMENT;
+ sgmnt_found = FALSE;
+ if (mu_rndwn_replpool(&replpool_id, FALSE, &sgmnt_found) && sgmnt_found)
+ rts_error(VARLSTCNT(6) ERR_MUJPOOLRNDWNSUC, 4, res_name[0], &res_name[1],
+ tran_name->len, replpool_id.gtmgbldir);
+ else if (sgmnt_found)
+ {
+ gtm_putmsg(VARLSTCNT(6) ERR_MUJPOOLRNDWNFL, 4, res_name[0], &res_name[1],
+ tran_name->len, replpool_id.gtmgbldir);
+ exit_status = ERR_MUNOTALLSEC;
+ }
+ global_name("GT$R", &file_id, res_name); /* R - Stands for Recv Pool */
+ res_name[res_name[0] + 1] = '\0';
+ strcpy(replpool_id.repl_pool_key, &res_name[1]);
+ replpool_id.pool_type = RECVPOOL_SEGMENT;
+ sgmnt_found = FALSE;
+ if (mu_rndwn_replpool(&replpool_id, FALSE, &sgmnt_found) && sgmnt_found)
+ rts_error(VARLSTCNT(6) ERR_MURPOOLRNDWNSUC, 4, res_name[0], &res_name[1],
+ tran_name->len, replpool_id.gtmgbldir);
+ else if (sgmnt_found)
+ {
+ gtm_putmsg(VARLSTCNT(6) ERR_MURPOOLRNDWNFL, 4, res_name[0], &res_name[1],
+ tran_name->len, replpool_id.gtmgbldir);
+ exit_status = ERR_MUNOTALLSEC;
+ }
+
+ }
+ }
+ }
+ mupip_exit(exit_status);
+}
diff --git a/sr_vvms/mupip_set_file.c b/sr_vvms/mupip_set_file.c
new file mode 100644
index 0000000..62f57b4
--- /dev/null
+++ b/sr_vvms/mupip_set_file.c
@@ -0,0 +1,562 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <climsgdef.h>
+#include <descrip.h>
+#include <fab.h>
+#include <iodef.h>
+#include <lckdef.h>
+#include <psldef.h>
+#include <rmsdef.h>
+#include <ssdef.h>
+#include <syidef.h>
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "cli.h"
+#include "efn.h"
+#include "gdsblk.h"
+#include "iosp.h"
+#include "mupipbckup.h"
+#include "vmsdtype.h"
+#include "gdscc.h"
+#include "gdskill.h"
+#include "jnl.h"
+#include "buddy_list.h" /* needed for tp.h */
+#include "hashtab_int4.h" /* needed for tp.h */
+#include "tp.h"
+#include "timers.h"
+#include "gt_timer.h"
+#include "util.h"
+#include "mupip_set.h"
+#include "locks.h"
+#include "mu_rndwn_file.h"
+#include "dbfilop.h"
+#include "mupip_exit.h"
+#include "dbcx_ref.h"
+#include "mu_gv_cur_reg_init.h"
+#include "gvcst_protos.h" /* for gvcst_init prototype */
+#include "gtmmsg.h"
+#include "wcs_flu.h"
+#include "gds_rundown.h"
+#include "change_reg.h"
+#include "desired_db_format_set.h"
+
+GBLREF tp_region *grlist;
+GBLREF gd_region *gv_cur_region;
+GBLREF bool region;
+GBLREF sgmnt_data_ptr_t cs_data;
+GBLREF sgmnt_addrs *cs_addrs;
+LITREF char *gtm_dbversion_table[];
+
+error_def(ERR_DBFILERR);
+error_def(ERR_DBOPNERR);
+error_def(ERR_DBRDERR);
+error_def(ERR_DBRDONLY);
+error_def(ERR_MUNOACTION);
+error_def(ERR_MUPCLIERR);
+error_def(ERR_MUSTANDALONE);
+error_def(ERR_WCERRNOTCHG);
+error_def(ERR_WCWRNNOTCHG);
+
+#define CHANGE_FLUSH_TIME_IF_NEEDED(csd) \
+{ \
+ if (flush_time_specified) \
+ { /* Do not invoke change_fhead_timer("FLUSH_TIME"...) more than once in this function \
+ * as that uses a function CLI$GET_VALUE which returns CLI$_ABSENT if called with the \
+ * same qualifier more than once. To work around this, invoke "change_fhead_timer" once \
+ * (for the first region in this loop) and store the "flush_time" that it calculated \
+ * into a temporary variable that is used for the other regions. The only thing that might \
+ * affect this is if a mix of regions with BG and MM access methods is specified in this \
+ * region list. That might present a problem since BG and MM have different default times \
+ * (TIM_FLU_MOD_BG and TIM_FLU_MOD_MM). But default time is used only if "NOFLUSH_TIME" \
+ * is specified which is not possible since FLUSH_TIME is NON-NEGATABLE. \
+ */ \
+ assert(SIZEOF(save_flush_time) == SIZEOF(csd->flush_time)); \
+ if (!flush_time_processed) \
+ { \
+ change_fhead_timer("FLUSH_TIME", csd->flush_time, \
+ (dba_bg == (n_dba == access ? csd->acc_meth : access) \
+ ? TIM_FLU_MOD_BG : TIM_FLU_MOD_MM), FALSE); \
+ flush_time_processed = TRUE; \
+ save_flush_time[0] = csd->flush_time[0]; \
+ save_flush_time[1] = csd->flush_time[1]; \
+ } else \
+ { \
+ csd->flush_time[0] = save_flush_time[0]; \
+ csd->flush_time[1] = save_flush_time[1]; \
+ } \
+ } \
+}
+
+int4 mupip_set_file(int db_fn_len, char *db_fn)
+{
+ boolean_t bypass_partial_recov, need_standalone = FALSE, flush_time_specified, flush_time_processed;
+ char exit_status, *command = "MUPIP SET VERSION";
+ enum db_acc_method access;
+ enum db_ver desired_dbver;
+ file_control *fc;
+ int defer_status, new_extn_count, new_lock_space, new_wait_disk, new_wc_size,
+ reserved_bytes, size, temp_new_wc_size, wait_disk_status, new_mutex_space;
+ sgmnt_addrs *csa;
+ sgmnt_data *sd, *sd1;
+ short new_defer_time;
+ tp_region *rptr, single;
+ uint4 space_available, space_needed, status, save_flush_time[2];
+ int4 status1;
+ vms_gds_info *gds_info;
+
+ $DESCRIPTOR(mm_qualifier,"MM");
+ $DESCRIPTOR(bg_qualifier,"BG");
+ $DESCRIPTOR(access_qualifier, "ACCESS_METHOD");
+ $DESCRIPTOR(dbver_v4, "V4");
+ $DESCRIPTOR(dbver_v6, "V6");
+ $DESCRIPTOR(dbver_qualifier, "VERSION");
+
+ exit_status = EXIT_NRM;
+ bypass_partial_recov = cli_present("PARTIAL_RECOV_BYPASS") == CLI_PRESENT;
+ if (bypass_partial_recov)
+ need_standalone = TRUE;
+ if (CLI_PRESENT == (wait_disk_status = cli_present("WAIT_DISK")))
+ {
+ if (!cli_get_int("WAIT_DISK", &new_wait_disk))
+ {
+ util_out_print("Error getting WAIT_DISK qualifier value", TRUE);
+ mupip_exit(ERR_MUPCLIERR);
+ }
+ need_standalone = TRUE;
+ }
+ flush_time_specified = (CLI_PRESENT == cli_present("FLUSH_TIME")) ? TRUE : FALSE;
+ flush_time_processed = FALSE;
+ if (CLI_PRESENT == (defer_status = cli_present("DEFER_TIME")))
+ {
+ if (!cli_get_num("DEFER_TIME", &new_defer_time))
+ {
+ util_out_print("Error getting DEFER_TIME qualifier value", TRUE);
+ mupip_exit(ERR_MUPCLIERR);
+ }
+ if (-1 > new_defer_time)
+ {
+ util_out_print("DEFER_TIME cannot take negative values other than -1", TRUE);
+ mupip_exit(ERR_MUPCLIERR);
+ }
+ need_standalone = TRUE;
+ } else
+ defer_status = 0;
+ if (cli_get_int("GLOBAL_BUFFERS", &new_wc_size))
+ {
+ if (new_wc_size > WC_MAX_BUFFS)
+ {
+ util_out_print("!UL too large, maximum cache buffers allowed is !UL",TRUE,new_wc_size,WC_MAX_BUFFS);
+ mupip_exit(ERR_MUPCLIERR);
+ }
+ if (new_wc_size < WC_MIN_BUFFS)
+ {
+ util_out_print("!UL too small, minimum cache buffers allowed is !UL",TRUE,new_wc_size,WC_MIN_BUFFS);
+ mupip_exit(ERR_MUPCLIERR);
+ }
+ need_standalone = TRUE;
+ } else
+ new_wc_size = 0;
+ /* EXTENSION_COUNT does not require standalone access and hence need_standalone will not be set to TRUE for this. */
+ if (cli_get_int("EXTENSION_COUNT", &new_extn_count))
+ {
+ if (new_extn_count > MAX_EXTN_COUNT)
+ {
+ util_out_print("!UL too large, maximum extension count allowed is !UL",TRUE,new_extn_count,MAX_EXTN_COUNT);
+ mupip_exit(ERR_MUPCLIERR);
+ }
+ if (new_extn_count < MIN_EXTN_COUNT)
+ {
+ util_out_print("!UL too small, minimum extension count allowed is !UL",TRUE,new_extn_count,MIN_EXTN_COUNT);
+ mupip_exit(ERR_MUPCLIERR);
+ }
+ } else
+ new_extn_count = 0;
+ if (cli_get_int("LOCK_SPACE", &new_lock_space))
+ {
+ if (new_lock_space > MAX_LOCK_SPACE)
+ {
+ util_out_print("!UL too large, maximum lock space allowed is !UL",TRUE,new_lock_space, MAX_LOCK_SPACE);
+ mupip_exit(ERR_MUPCLIERR);
+ }
+ if (new_lock_space < MIN_LOCK_SPACE)
+ {
+ util_out_print("!UL too small, minimum lock space allowed is !UL",TRUE,new_lock_space, MIN_LOCK_SPACE);
+ mupip_exit(ERR_MUPCLIERR);
+ }
+ need_standalone = TRUE;
+ } else
+ new_lock_space = 0;
+ if (cli_get_int("MUTEX_SLOTS", &new_mutex_space))
+ {
+ if (new_mutex_space > MAX_CRIT_ENTRY)
+ {
+ util_out_print("!UL too large, maximum number of mutex slots allowed is !UL", TRUE,
+ new_mutex_space, MAX_CRIT_ENTRY);
+ return (int4)ERR_WCWRNNOTCHG;
+ } else if (new_mutex_space < MIN_CRIT_ENTRY)
+ {
+ util_out_print("!UL too small, minimum number of mutex slots allowed is !UL", TRUE,
+ new_mutex_space, MIN_CRIT_ENTRY);
+ return (int4)ERR_WCWRNNOTCHG;
+ }
+ need_standalone = TRUE;
+ } else
+ new_mutex_space = 0;
+ if (0 == cli_get_num("RESERVED_BYTES" ,&reserved_bytes))
+ reserved_bytes = -1;
+ else
+ need_standalone = TRUE;
+ if (CLI$_ABSENT != cli$present(&access_qualifier))
+ {
+ if (CLI$_PRESENT == cli$present(&mm_qualifier))
+ access = dba_mm;
+ else if (CLI$_PRESENT == cli$present(&bg_qualifier))
+ access = dba_bg;
+ else
+ /* ??? */
+ mupip_exit(ERR_MUPCLIERR);
+ need_standalone = TRUE;
+ } else
+ access = n_dba; /* really want to keep current method, which has not yet been read */
+ if (CLI$_ABSENT != cli$present(&dbver_qualifier))
+ {
+ assert(!need_standalone);
+ if (CLI$_PRESENT == cli$present(&dbver_v4))
+ desired_dbver = GDSV4;
+ else if (CLI$_PRESENT == cli$present(&dbver_v6))
+ desired_dbver = GDSV6;
+ else
+ GTMASSERT; /* CLI should prevent us ever getting here */
+ } else
+ desired_dbver = GDSVLAST; /* really want to keep current format, which has not yet been read */
+ if (region)
+ rptr = grlist;
+ else
+ {
+ rptr = &single;
+ memset(&single, 0, SIZEOF(single));
+ mu_gv_cur_reg_init();
+ }
+ sd = malloc(ROUND_UP(SIZEOF(sgmnt_data), DISK_BLOCK_SIZE));
+ for (;rptr; rptr = rptr->fPtr)
+ {
+ if (region)
+ {
+ if (dba_usr == rptr->reg->dyn.addr->acc_meth)
+ {
+ util_out_print("!/Region !AD is not a GDS access type",TRUE, REG_LEN_STR(rptr->reg));
+ exit_status |= EXIT_WRN;
+ continue;
+ }
+ if (!mupfndfil(rptr->reg, NULL))
+ {
+ exit_status |= EXIT_ERR;
+ continue;
+ }
+ gv_cur_region = rptr->reg;
+ if (NULL == gv_cur_region->dyn.addr->file_cntl)
+ {
+ gv_cur_region->dyn.addr->acc_meth = dba_bg;
+ gv_cur_region->dyn.addr->file_cntl =
+ (file_control *)malloc(SIZEOF(*gv_cur_region->dyn.addr->file_cntl));
+ memset(gv_cur_region->dyn.addr->file_cntl, 0, SIZEOF(*gv_cur_region->dyn.addr->file_cntl));
+ gv_cur_region->dyn.addr->file_cntl->file_type = dba_bg;
+ gds_info =
+ gv_cur_region->dyn.addr->file_cntl->file_info = (GDS_INFO *)malloc(SIZEOF(GDS_INFO));
+ memset(gds_info, 0, SIZEOF(GDS_INFO));
+ }
+ } else
+ {
+ gv_cur_region->dyn.addr->fname_len = db_fn_len;
+ memcpy(gv_cur_region->dyn.addr->fname, db_fn, db_fn_len);
+ }
+ if (!need_standalone)
+ {
+ gvcst_init(gv_cur_region);
+ change_reg();
+ if (gv_cur_region->read_only)
+ {
+ gtm_putmsg(VARLSTCNT(4) ERR_DBRDONLY, 2, DB_LEN_STR(gv_cur_region));
+ exit_status |= EXIT_ERR;
+ gds_rundown();
+ continue;
+ }
+ grab_crit(gv_cur_region);
+ status = EXIT_NRM;
+ CHANGE_FLUSH_TIME_IF_NEEDED(cs_data);
+ if (GDSVLAST != desired_dbver)
+ {
+ status1 = desired_db_format_set(gv_cur_region, desired_dbver, command);
+ if (SS_NORMAL != status1)
+ { /* "desired_db_format_set" would have printed appropriate error messages */
+ if (ERR_MUNOACTION != status1)
+ { /* real error occurred while setting the db format. skip to next region */
+ status = EXIT_ERR;
+ }
+ }
+ }
+ if (EXIT_NRM == status)
+ {
+ if (new_extn_count)
+ cs_data->extension_size = new_extn_count;
+ wcs_flu(WCSFLU_FLUSH_HDR);
+ if (new_extn_count)
+ util_out_print("Database file !AD now has extension count !UL",
+ TRUE, db_fn_len, db_fn, cs_data->extension_size);
+ if (GDSVLAST != desired_dbver)
+ util_out_print("Database file !AD now has desired DB format !AD", TRUE,
+ db_fn_len, db_fn, LEN_AND_STR(gtm_dbversion_table[cs_data->desired_db_format]));
+ } else
+ exit_status |= status;
+ rel_crit(gv_cur_region);
+ gds_rundown();
+ } else
+ { /* Following part needs standalone access */
+ assert(GDSVLAST == desired_dbver);
+ if (!mu_rndwn_file(TRUE))
+ {
+ gtm_putmsg(VARLSTCNT(4) ERR_MUSTANDALONE, 2, DB_LEN_STR(gv_cur_region));
+ exit_status |= EXIT_ERR;
+ continue;
+ }
+ gds_info = FILE_INFO(gv_cur_region);
+ fc = gv_cur_region->dyn.addr->file_cntl;
+ fc->op = FC_OPEN;
+ fc->file_type = dba_bg;
+ status = dbfilop(fc);
+ if (SS$_NORMAL != status)
+ {
+ gtm_putmsg(VARLSTCNT(6) ERR_DBOPNERR, 2,
+ DB_LEN_STR(gv_cur_region), status, gds_info->fab->fab$l_stv);
+ exit_status |= EXIT_ERR;
+ continue;
+ }
+ if (gv_cur_region->read_only)
+ {
+ gtm_putmsg(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region), RMS$_PRV);
+ exit_status |= EXIT_ERR;
+ sys$dassgn(gds_info->fab->fab$l_stv);
+ continue;
+ }
+ fc->op = FC_READ;
+ fc->op_buff = sd;
+ fc->op_len = SGMNT_HDR_LEN;
+ fc->op_pos = 1;
+ status = dbfilop(fc);
+ if (SS_NORMAL != status)
+ {
+ gtm_putmsg(VARLSTCNT(6) ERR_DBRDERR, 2,
+ DB_LEN_STR(gv_cur_region), status, gds_info->fab->fab$l_stv);
+ exit_status |= EXIT_ERR;
+ sys$dassgn(gds_info->fab->fab$l_stv);
+ continue;
+ }
+ if (-1 != reserved_bytes)
+ {
+ if (reserved_bytes < 0 || (reserved_bytes > MAX_RESERVE_B(sd)))
+ {
+ util_out_print("!UL too large, maximum reserved bytes allowed is !UL for database file !AD",
+ TRUE, reserved_bytes, MAX_RESERVE_B(sd), gv_cur_region->dyn.addr->fname_len,
+ gv_cur_region->dyn.addr->fname);
+ exit_status |= EXIT_WRN;
+ } else
+ sd->reserved_bytes = reserved_bytes;
+ }
+ CHANGE_FLUSH_TIME_IF_NEEDED(sd);
+ if (new_extn_count)
+ sd->extension_size = new_extn_count;
+ if (CLI_PRESENT == wait_disk_status)
+ sd->wait_disk_space = new_wait_disk;
+ if (new_lock_space)
+ sd->lock_space_size = new_lock_space * OS_PAGELET_SIZE;
+ if (new_mutex_space)
+ NUM_CRIT_ENTRY(sd) = new_mutex_space;
+ if (bypass_partial_recov)
+ sd->file_corrupt = FALSE;
+ if (dba_mm == (n_dba == access ? sd->acc_meth : access))
+ /* always recalculate; n_dba is a proxy for no change */
+ {
+ if (CLI_NEGATED == defer_status)
+ sd->defer_time = 1;
+ /* default defer_time = 1 => defer time is 1*flush_time[0] */
+ else if (CLI_PRESENT == defer_status)
+ {
+ sd->defer_time = new_defer_time;
+ }
+
+ if (dba_bg == sd->acc_meth)
+ {
+ if (FALSE == sd->unbacked_cache)
+ sd->free_space += (sd->n_bts + sd->bt_buckets + 1) * SIZEOF(bt_rec);
+#ifdef GT_CX_DEF
+ sd->free_space += sd->lock_space_size;
+#endif
+ }
+ sd->n_bts = sd->bt_buckets = 0;
+ if (n_dba != access) /* n_dba is a proxy for no change */
+ {
+ if (dba_mm == access)
+ {
+ if (0 != sd->blks_to_upgrd)
+ { /* changing to MM and blocks to upgrade */
+ util_out_print("MM access method cannot be set if there are blocks"
+ " to upgrade", TRUE);
+ util_out_print("Database file !AD not changed", TRUE,
+ DB_LEN_STR(gv_cur_region));
+ exit_status |= EXIT_WRN;
+ continue;
+ } else if (GDSVCURR != sd->desired_db_format)
+ { /* changing to MM and DB not current format */
+ util_out_print("MM access method cannot be set in DB compatibility mode",
+ TRUE);
+ util_out_print("Database file !AD not changed", TRUE,
+ DB_LEN_STR(gv_cur_region));
+ exit_status |= EXIT_WRN;
+ continue;
+ } else if (JNL_ENABLED(sd) && (sd->jnl_before_image))
+ { /* changing to MM and BEFORE image journaling set */
+ util_out_print("MM access cannot be used with BEFORE image journaling",
+ TRUE);
+ util_out_print("Database file !AD not changed", TRUE,
+ DB_LEN_STR(gv_cur_region));
+ exit_status |= EXIT_WRN;
+ continue;
+ } else
+ {
+ if (!JNL_ENABLED(sd))
+ sd->jnl_before_image = 0; /* default to NO_BEFORE journal imaging */
+ sd->acc_meth = access;
+ }
+ }
+ }
+ sd->clustered = FALSE;
+ } else
+ {
+ if (defer_status)
+ {
+ util_out_print("DEFER cannot be specified with BG access method, file - !AD not changed",
+ TRUE, DB_LEN_STR(gv_cur_region));
+ exit_status |= EXIT_WRN;
+ continue;
+ }
+
+ if (dba_mm == sd->acc_meth)
+ space_available = sd->free_space;
+ else
+ {
+ space_available = sd->free_space + sd->lock_space_size;
+ if (FALSE == sd->unbacked_cache)
+ space_available += ((sd->n_bts + sd->bt_buckets + 1) * SIZEOF(bt_rec));
+ }
+
+ temp_new_wc_size = new_wc_size;
+ if (0 == new_wc_size)
+ if (sd->n_bts)
+ temp_new_wc_size = sd->n_bts;
+ else
+ temp_new_wc_size = WC_DEF_BUFFS;
+ if (sd->clustered)
+ {
+ /* this code needs to be maintained to account for the new bt allocation algorithm - rprp */
+ space_needed = (temp_new_wc_size + getprime(temp_new_wc_size) + 1) * SIZEOF(bt_rec)
+ + sd->lock_space_size;
+ if (space_needed > space_available)
+ {
+ if (space_available < (sd->lock_space_size +
+ (WC_MIN_BUFFS + getprime(WC_MIN_BUFFS) + 1) * SIZEOF(bt_rec)))
+ {
+ util_out_print("!/File !AD does not have enough space to be converted to BG"
+ , TRUE, DB_LEN_STR(gv_cur_region));
+ } else
+ {
+ util_out_print("!/File !AD does not have enough space for !UL cache "
+ "records." , TRUE, DB_LEN_STR(gv_cur_region),
+ temp_new_wc_size);
+ util_out_print("The maximum it will support is !UL",TRUE,
+ sd->n_bts + (sd->free_space / (2 * SIZEOF(bt_rec))));
+ }
+ exit_status |= EXIT_WRN;
+ } else
+ sd->free_space = space_available - space_needed;
+ } else
+ {
+ sd->unbacked_cache = TRUE;
+#ifdef GT_CX_DEF
+ sd->free_space = space_available - sd->lock_space_size;
+#endif
+ }
+
+ /* On Unix, following block was moved out of this 'if' check, as part of 'targetted msync' changes,
+ * which is not relevant in VMS context */
+ sd->n_bts = BT_FACTOR(temp_new_wc_size);
+ sd->bt_buckets = getprime(sd->n_bts);
+ sd->n_wrt_per_flu = 7;
+ sd->flush_trigger = FLUSH_FACTOR(sd->n_bts);
+ if (n_dba != access) /* n_dba is a proxy for no change */
+ sd->acc_meth = access;
+ if (sd->clustered)
+ {
+ size = LOCK_BLOCK(sd) + ROUND_UP(sd->lock_space_size, DISK_BLOCK_SIZE);
+ sd1 = malloc(size);
+ memcpy(sd1,sd,SIZEOF(sgmnt_data));
+ status = dbcx_ref(sd1, gds_info->fab->fab$l_stv);
+ if (0 == (status & 1))
+ {
+ if (SS$_NORMAL != gtm_deq(gds_info->file_cntl_lsb.lockid, NULL, PSL$C_USER, 0))
+ GTMASSERT;
+ gds_info->file_cntl_lsb.lockid = 0;
+ sys$dassgn(gds_info->fab->fab$l_stv);
+ free(sd1);
+ gtm_putmsg(VARLSTCNT(6) ERR_DBFILERR, 2,
+ DB_LEN_STR(gv_cur_region), status, gds_info->fab->fab$l_stv);
+ exit_status |= EXIT_ERR;
+ continue;
+ }
+ free(sd1);
+ }
+ }
+ if (FALSE == sd->clustered)
+ {
+ fc->op = FC_WRITE;
+ fc->op_buff = sd;
+ fc->op_len = SGMNT_HDR_LEN;
+ fc->op_pos = 1;
+ status = dbfilop(fc);
+ if (SS_NORMAL != status)
+ {
+ gtm_putmsg(VARLSTCNT(6) ERR_DBFILERR, 2,
+ DB_LEN_STR(gv_cur_region), status, gds_info->fab->fab$l_stv);
+ exit_status |= EXIT_ERR;
+ }
+ }
+ status = gtm_deq(gds_info->file_cntl_lsb.lockid, NULL, PSL$C_USER, 0);
+ assert(SS$_NORMAL == status);
+ gds_info->file_cntl_lsb.lockid = 0;
+ sys$dassgn(gds_info->fab->fab$l_stv);
+ util_out_print("!/File !AD updated.", TRUE, DB_LEN_STR(gv_cur_region));
+ } /* end of else part if (!need_standalone) */
+ }
+ free(sd);
+ assert(!(exit_status & EXIT_INF));
+ if (exit_status & EXIT_ERR)
+ mupip_exit(ERR_WCERRNOTCHG);
+ else if (exit_status & EXIT_WRN)
+ mupip_exit(ERR_WCWRNNOTCHG);
+ return SS_NORMAL; /* for prototype compatibility with Unix */
+}
diff --git a/sr_vvms/mupip_set_jnlfile.c b/sr_vvms/mupip_set_jnlfile.c
new file mode 100644
index 0000000..f39b2cc
--- /dev/null
+++ b/sr_vvms/mupip_set_jnlfile.c
@@ -0,0 +1,137 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_fcntl.h"
+#include <unistd.h>
+#include <errno.h>
+#include "gtm_string.h"
+
+#include <fab.h>
+#include <iodef.h>
+#include <nam.h>
+#include <rmsdef.h>
+#include <ssdef.h>
+#include <efndef.h>
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "cli.h"
+#include "iosp.h"
+#include "jnl.h"
+#include "mupip_set.h"
+#include "mupint.h"
+#include "eintr_wrappers.h"
+#include "util.h"
+#include "gtm_file_stat.h"
+#include "gtmmsg.h"
+
+#define DB_EXT_DEF ".DAT"
+
+int4 mupip_set_jnlfile(char *jnl_fname, int jnl_fn_len)
+{
+ int4 jnl_len, temp_jnl_fn_len;
+ uint4 status;
+ char hdr_buffer[SIZEOF(jnl_file_header)];
+ char es_buffer[MAX_FN_LEN], name_buffer[MAX_FN_LEN], temp_jnl_fn[MAX_FN_LEN];
+ jnl_file_header *header;
+ struct FAB fab;
+ struct NAM nam;
+ short iosb[4];
+ mstr dbfile, def;
+
+ error_def(ERR_JNLFILNOTCHG);
+
+ jnl_len = strlen(jnl_fname);
+ temp_jnl_fn_len = jnl_len;
+ memcpy(temp_jnl_fn, jnl_fname, jnl_len);
+ temp_jnl_fn[jnl_len] = '\0';
+ if (!get_full_path(temp_jnl_fn, temp_jnl_fn_len, jnl_fname, &jnl_len, jnl_fn_len, &status))
+ {
+ util_out_print("!/Unable to get full path file !AD", TRUE, temp_jnl_fn_len, temp_jnl_fn);
+ gtm_putmsg(VARLSTCNT(1) status);
+ return((int4)ERR_JNLFILNOTCHG);
+ }
+ nam = cc$rms_nam;
+ nam.nam$l_rsa = name_buffer;
+ nam.nam$b_rss = SIZEOF(name_buffer);
+ nam.nam$l_esa = es_buffer;
+ nam.nam$b_ess = SIZEOF(es_buffer);
+ fab = cc$rms_fab;
+ fab.fab$l_nam = &nam;
+ fab.fab$l_fna = jnl_fname;
+ fab.fab$b_fns = jnl_len;
+ fab.fab$l_fop = FAB$M_UFO | FAB$M_MXV | FAB$M_CBT;
+ fab.fab$b_fac = FAB$M_GET | FAB$M_PUT | FAB$M_BIO;
+ fab.fab$l_dna = JNL_EXT_DEF;
+ fab.fab$b_dns = SIZEOF(JNL_EXT_DEF) - 1;
+ if ((status = sys$open(&fab))!= RMS$_NORMAL)
+ {
+ util_out_print("Error opening journal file !AD", TRUE, jnl_len, jnl_fname);
+ if (0 != fab.fab$l_stv)
+ gtm_putmsg(VARLSTCNT(3) status, 0, (uint4)fab.fab$l_stv);
+ else
+ gtm_putmsg(VARLSTCNT(1) status);
+ return((int4)ERR_JNLFILNOTCHG);
+ }
+ /* Read Jnl Header */
+ status = sys$qiow(EFN$C_ENF, fab.fab$l_stv, IO$_READVBLK, &iosb[0], 0, 0,
+ (sm_uc_ptr_t)hdr_buffer, SIZEOF(hdr_buffer), 1, 0, 0, 0);
+ if (status == SS$_NORMAL)
+ status = iosb[0];
+ if (status != SS$_NORMAL)
+ {
+ util_out_print("Error reading file !AD", TRUE, jnl_len, jnl_fname);
+ gtm_putmsg(VARLSTCNT(1) status);
+ return((int4)ERR_JNLFILNOTCHG);
+ }
+ header = (jnl_file_header *)hdr_buffer;
+ /* check if database is existing, warn if not */
+ dbfile.addr = header->data_file_name;
+ dbfile.len = header->data_file_name_length;
+ def.addr = DB_EXT_DEF;
+ def.len = SIZEOF(DB_EXT_DEF)-1;
+ if (FILE_PRESENT != gtm_file_stat(&dbfile, &def, NULL, FALSE, &status))
+ {
+ util_out_print("WARNING : Data base file !AD for this journal does not exist, proceeding",
+ TRUE, header->data_file_name_length, header->data_file_name);
+ gtm_putmsg(VARLSTCNT(1) status);
+ }
+ /* Processing */
+ if(SS_NORMAL != (status = mupip_set_jnlfile_aux(header, jnl_fname)))
+ return status;
+ /* Write Back Jnl Header */
+ status = sys$qiow(EFN$C_ENF, fab.fab$l_stv, IO$_WRITEVBLK, &iosb[0], 0, 0,
+ (sm_uc_ptr_t)hdr_buffer, SIZEOF(hdr_buffer), 1, 0, 0, 0);
+ if (status == SS$_NORMAL)
+ status = iosb[0];
+ if (status != SS$_NORMAL)
+ {
+ util_out_print("Error writing file !AD", TRUE, jnl_len, jnl_fname);
+ gtm_putmsg(VARLSTCNT(1) status);
+ return((int4)ERR_JNLFILNOTCHG);
+ }
+ /* Close Jnl File */
+ if(SS$_NORMAL != (status = sys$dassgn(fab.fab$l_stv)))
+ {
+ util_out_print("Error closing journal file !AD", jnl_len, jnl_fname);
+ gtm_putmsg(VARLSTCNT(1) status);
+ return((int4)ERR_JNLFILNOTCHG);
+ }
+
+ return SS_NORMAL;
+}
diff --git a/sr_vvms/muprecsp.h b/sr_vvms/muprecsp.h
new file mode 100644
index 0000000..0bce9d5
--- /dev/null
+++ b/sr_vvms/muprecsp.h
@@ -0,0 +1,21 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2003 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef MUPRECSP_H_INCLUDED
+#define MUPRECSP_H_INCLUDED
+
+#define EXT_MJF ".MJF"
+#define EXT_BROKEN ".BROKEN"
+#define EXT_LOST ".LOST"
+#define FN_LEN_EXTR_FILE_INFO(file_info) file_info->fab$b_fns
+#define FN_EXTR_FILE_INFO(file_info) file_info->fab$l_fna
+
+#endif
diff --git a/sr_vvms/mur_cre_file_extfmt.c b/sr_vvms/mur_cre_file_extfmt.c
new file mode 100644
index 0000000..16ea33e
--- /dev/null
+++ b/sr_vvms/mur_cre_file_extfmt.c
@@ -0,0 +1,136 @@
+/****************************************************************
+ * *
+ * Copyright 2003, 2010 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <ssdef.h>
+#include <fab.h>
+#include <rms.h>
+#include <iodef.h>
+#include <descrip.h>
+
+#include "gtm_string.h"
+#include "gtm_stdio.h"
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "buddy_list.h"
+#include "jnl.h"
+#include "hashtab_mname.h" /* needed for muprec.h */
+#include "hashtab_int4.h" /* needed for muprec.h */
+#include "hashtab_int8.h" /* needed for muprec.h */
+#include "muprec.h"
+#include "gtmio.h"
+#include "gtmmsg.h"
+#include "gtm_rename.h"
+
+GBLREF mur_gbls_t murgbl;
+GBLREF mur_opt_struct mur_options;
+
+/* VMS does not need rename if file name matches ??? */
+int4 mur_cre_file_extfmt(jnl_ctl_list *jctl, int recstat)
+{
+ fi_type *file_info;
+ struct FAB *fab_ptr;
+ struct NAM nam;
+ uint4 status;
+ int base_len, rename_fn_len, fn_exten_size;
+ char fn_buffer[MAX_FN_LEN], *ptr;
+ static readonly char *fn_exten[] = {EXT_MJF, EXT_BROKEN, EXT_LOST};
+ static readonly char *ext_file_type[] = {STR_JNLEXTR, STR_BRKNEXTR, STR_LOSTEXTR};
+
+ error_def(ERR_FILENOTCREATE);
+ error_def(ERR_FILEPARSE);
+ error_def(ERR_FILECREATE);
+ error_def(ERR_TEXT);
+
+ assert(GOOD_TN == recstat || BROKEN_TN == recstat || LOST_TN == recstat);
+ assert(0 == GOOD_TN);
+ assert(1 == BROKEN_TN);
+ assert(2 == LOST_TN);
+ assert(GOOD_TN != recstat || mur_options.extr[GOOD_TN]);
+ ptr = &jctl->jnl_fn[jctl->jnl_fn_len];
+ while (DOT != *ptr) /* we know journal file name alway has a DOT */
+ ptr--;
+ base_len = ptr - (char *)&jctl->jnl_fn[0];
+ file_info = murgbl.file_info[recstat] = (void *)malloc(SIZEOF(fi_type));
+ fab_ptr = file_info->fab = (struct FAB *)malloc(SIZEOF(struct FAB));
+ *fab_ptr = cc$rms_fab;
+ fn_exten_size = strlen(fn_exten[recstat]);
+ if (0 == mur_options.extr_fn_len[recstat])
+ {
+ mur_options.extr_fn[recstat] = malloc(MAX_FN_LEN);
+ mur_options.extr_fn_len[recstat] = base_len;
+ memcpy(mur_options.extr_fn[recstat], jctl->jnl_fn, base_len);
+ memcpy(mur_options.extr_fn[recstat] + base_len, fn_exten[recstat], fn_exten_size);
+ mur_options.extr_fn_len[recstat] += fn_exten_size;
+ }
+ if (RENAME_FAILED == rename_file_if_exists(mur_options.extr_fn[recstat], mur_options.extr_fn_len[recstat],
+ fn_buffer, &rename_fn_len, &status))
+ return status;
+ fab_ptr->fab$b_fns = mur_options.extr_fn_len[recstat];
+ fab_ptr->fab$l_fna = mur_options.extr_fn[recstat];
+ fab_ptr->fab$b_dns = fn_exten_size;
+ fab_ptr->fab$l_dna = fn_exten[recstat];
+ fab_ptr->fab$l_nam = &nam;
+ nam = cc$rms_nam;
+ nam.nam$b_ess = SIZEOF(fn_buffer);
+ nam.nam$l_esa = fn_buffer;
+ nam.nam$b_nop |= NAM$M_SYNCHK;
+ file_info->rab = (struct RAB *)malloc(SIZEOF(struct RAB));
+ *file_info->rab = cc$rms_rab;
+ file_info->rab->rab$l_fab = fab_ptr;
+ file_info->rab->rab$l_rop = RAB$M_WBH;
+ status = sys$parse(fab_ptr);
+ if (!(1 & status))
+ {
+ gtm_putmsg(VARLSTCNT(6) ERR_FILEPARSE, 2, fab_ptr->fab$b_fns, fab_ptr->fab$l_fna, status, fab_ptr->fab$l_stv);
+ return status;
+ }
+ if (0 != nam.nam$b_node)
+ {
+ gtm_putmsg(VARLSTCNT(8) ERR_FILEPARSE, 2, fab_ptr->fab$b_fns, fab_ptr->fab$l_fna, ERR_TEXT, 2,
+ LEN_AND_LIT("Cannot open lost transactions file across network"));
+ return ERR_FILEPARSE;
+ }
+ fab_ptr->fab$l_nam = NULL;
+ fab_ptr->fab$w_mrs = 32767;
+ fab_ptr->fab$b_rat = FAB$M_CR;
+ fab_ptr->fab$l_fop = FAB$M_CBT | FAB$M_MXV;
+ fab_ptr->fab$b_fac = FAB$M_PUT;
+ status = sys$create(fab_ptr);
+ if (1 & status)
+ {
+ status = sys$connect(file_info->rab);
+ if (!(1 & status))
+ sys$close(fab_ptr); /* use sys$close() if FAB$M_UFO was not specified in fab$l_fop in open */
+ }
+ if (!(1 & status))
+ {
+ gtm_putmsg(VARLSTCNT(6) ERR_FILENOTCREATE, 2, fab_ptr->fab$b_fns, fab_ptr->fab$l_fna, status, fab_ptr->fab$l_stv);
+ return status;
+ }
+ /* Write file version info for the file created here. See C9B08-001729 */
+ if (!mur_options.detail)
+ {
+ MEMCPY_LIT(murgbl.extr_buff, JNL_EXTR_LABEL);
+ jnlext_write(file_info, murgbl.extr_buff, SIZEOF(JNL_EXTR_LABEL));
+ } else
+ {
+ MEMCPY_LIT(murgbl.extr_buff, JNL_DET_EXTR_LABEL);
+ jnlext_write(file_info, murgbl.extr_buff, SIZEOF(JNL_DET_EXTR_LABEL));
+ }
+ gtm_putmsg(VARLSTCNT(6) ERR_FILECREATE, 4, LEN_AND_STR(ext_file_type[recstat]), fab_ptr->fab$b_fns, fab_ptr->fab$l_fna);
+ return SS$_NORMAL;
+}
diff --git a/sr_vvms/mur_read_file_sp.c b/sr_vvms/mur_read_file_sp.c
new file mode 100644
index 0000000..dd1baa9
--- /dev/null
+++ b/sr_vvms/mur_read_file_sp.c
@@ -0,0 +1,171 @@
+/****************************************************************
+ * *
+ * Copyright 2003, 2010 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <fab.h>
+#include <rmsdef.h>
+#include <xab.h>
+#include <iodef.h>
+#include <ssdef.h>
+#include <efndef.h>
+
+#include "min_max.h"
+#include "gtmio.h"
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "jnl.h"
+#include "iosb_disk.h"
+#include "buddy_list.h"
+#include "hashtab_mname.h" /* needed for muprec.h */
+#include "hashtab_int4.h" /* needed for muprec.h */
+#include "hashtab_int8.h" /* needed for muprec.h */
+#include "muprec.h"
+#include "mur_read_file.h"
+#include "util.h"
+#include "gtmmsg.h"
+#include "iosp.h" /* for SS_NORMAL */
+
+
+error_def(ERR_PREMATEOF);
+
+GBLREF mur_opt_struct mur_options;
+
+static void mur_fread_fini(void)
+{
+ sys$wake(NULL, NULL);
+ return;
+}
+/****************************************************************************************
+ * Function Name: mur_fread_start
+ * Input: struct mur_buffer_desc * buff
+ * Output : SS_NORMAL on successful
+ * error status on unsuccessful
+ *This function starts an asynchrounous read in a given buffer
+ ****************************************************************************************/
+
+uint4 mur_fread_start(jnl_ctl_list *jctl, mur_buff_desc_t *buff)
+{
+ assert(0 == buff->dskaddr % DISK_BLOCK_SIZE);
+ buff->blen = MIN(MUR_BUFF_SIZE, jctl->eof_addr - buff->dskaddr);
+ buff->rip_channel = jctl->channel; /* store channel that issued the AIO in order to use later for sys$_cancel() */
+ assert(!buff->read_in_progress);
+ buff->read_in_progress = TRUE;
+ jctl->status = sys$qio(EFN$C_ENF, jctl->channel, IO$_READVBLK, &buff->iosb, mur_fread_fini, buff, buff->base,
+ buff->blen, (buff->dskaddr >> LOG2_DISK_BLOCK_SIZE) + 1, 0, 0, 0);
+ return jctl->status;
+}
+
+/************************************************************************************
+ * Function name: mur_fread_wait
+ * Input : struct mur_buffer_desc *buff
+ * Output: SS_NORMAL on success
+ * error status on unsuccessful
+ * Purpose: The purpose of this routine is to make sure that a previously issued asynchrounous
+ * read in a given buffer has completed
+ **************************************************************************************/
+uint4 mur_fread_wait(jnl_ctl_list *jctl, mur_buff_desc_t *buff)
+{
+ uint4 status;
+
+ assert(buff->read_in_progress);
+ buff->read_in_progress = FALSE;
+ /* sys$qio clears iosb when it begins execution */
+ while ((status = buff->iosb.cond) == 0)
+ sys$hiber();
+ return ((SS$_NORMAL == status || SS$_CANCEL == status || SS$_ABORT == status) ? SS_NORMAL : status);
+}
+/************************************************************************************************
+ * Function Name: mur_fread_cancel
+ * Input: buffer index
+ * Output: SS_NORMAL on successful
+ * error status on unsuccessful
+ * This function is used for cancelling asynchronous I/O issued for seq buffers
+ * ************************************************************************************************/
+uint4 mur_fread_cancel(jnl_ctl_list *jctl)
+{
+ uint4 status, save_err;
+ int index;
+ reg_ctl_list *rctl;
+ mur_read_desc_t *mur_desc;
+ mur_buff_desc_t *seq_buff;
+
+ rctl = jctl->reg_ctl;
+ mur_desc = rctl->mur_desc;
+ /* At most one buffer can have read_in_progress, not both */
+ assert(!(mur_desc->seq_buff[0].read_in_progress && mur_desc->seq_buff[1].read_in_progress));
+ for (index = 0, save_err = SS_NORMAL; index < ARRAYSIZE(mur_desc->seq_buff); index++)
+ {
+ seq_buff = &mur_desc->seq_buff[index];
+ if (seq_buff->read_in_progress)
+ {
+ status = sys$cancel(seq_buff->rip_channel);
+ if (1 & status)
+ {
+ if (SS_NORMAL != (status = mur_fread_wait(jctl, seq_buff)))
+ save_err = status;
+ } else
+ save_err = status;
+ seq_buff->read_in_progress = FALSE;
+ }
+ }
+ /* Note that although the cancellation errored out for rip_channel, we are storing the status in jctl which need not
+ * actually be the jctl corresponding to rip_channel
+ */
+ return (jctl->status = ((SS_NORMAL == save_err) ? SS_NORMAL : save_err));
+}
+/**************************************************************************************
+ * Function name: mur_fopen
+ * Input: jnl_ctl_list *
+ * Return value : TRUE or False
+ * *************************************************************************************/
+boolean_t mur_fopen_sp(jnl_ctl_list *jctl)
+{
+ struct FAB *fab;
+ struct XABFHC *xab;
+ uint4 status;
+
+ error_def(ERR_JNLFILEOPNERR);
+
+ fab = jctl->fab = malloc(SIZEOF(*fab));
+ *fab = cc$rms_fab;
+ fab->fab$l_fna = jctl->jnl_fn;
+ fab->fab$b_fns = jctl->jnl_fn_len;
+ fab->fab$b_fac = FAB$M_BIO | FAB$M_GET;
+ fab->fab$l_fop = FAB$M_UFO;
+ fab->fab$b_shr = FAB$M_SHRPUT | FAB$M_SHRGET | FAB$M_UPI;
+ xab = fab->fab$l_xab = malloc(SIZEOF(*xab));
+ *xab = cc$rms_xabfhc;
+ jctl->read_only = TRUE;
+ /* Both for recover and rollback open in read/write mode. We do not need to write in journal file
+ * for mupip journal extract/show/verify or recover -forward. So open it as read-only
+ */
+ if (mur_options.update && !mur_options.forward)
+ {
+ fab->fab$b_fac |= FAB$M_PUT;
+ jctl->read_only = FALSE;
+ }
+ status = sys$open(fab);
+ if (SYSCALL_SUCCESS(status))
+ {
+ jctl->channel = fab->fab$l_stv; /* if $open() is succedded, fab$l_stv contains the I/O channel */
+ jctl->os_filesize = (xab->xab$l_ebk - 1) * DISK_BLOCK_SIZE;
+ return TRUE;
+ }
+ jctl->status = status;
+ jctl->status2 = fab->fab$l_stv;
+ jctl->channel = NOJNL;
+ gtm_putmsg(VARLSTCNT(6) ERR_JNLFILEOPNERR, 2, jctl->jnl_fn_len, jctl->jnl_fn, jctl->status, jctl->status2);
+ return FALSE;
+}
diff --git a/sr_vvms/murgetlst.c b/sr_vvms/murgetlst.c
new file mode 100644
index 0000000..1f9c3f5
--- /dev/null
+++ b/sr_vvms/murgetlst.c
@@ -0,0 +1,48 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include <climsgdef.h>
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "murest.h"
+#include <descrip.h>
+
+GBLREF inc_list_struct in_files;
+
+void murgetlst(void)
+{
+static readonly $DESCRIPTOR(inc_ent,"INPUT_FILE");
+unsigned char buffer[MAX_FN_LEN + 1];
+$DESCRIPTOR(rn_buf,buffer);
+inc_list_struct *ptr;
+unsigned short ret_len;
+
+ptr = &in_files;
+for (rn_buf.dsc$w_length = MAX_FN_LEN + 1; CLI$GET_VALUE(&inc_ent, &rn_buf, &ret_len) != CLI$_ABSENT;
+ rn_buf.dsc$w_length = MAX_FN_LEN + 1)
+{
+ rn_buf.dsc$w_length = ret_len;
+ ptr->next = malloc(SIZEOF(inc_list_struct));
+ ptr = ptr->next;
+ ptr->next = 0;
+ ptr->input_file.len = ret_len;
+ ptr->input_file.addr = malloc(ret_len);
+ memcpy(ptr->input_file.addr, buffer, ret_len);
+}
+return;
+}
diff --git a/sr_vvms/mutexsp.h b/sr_vvms/mutexsp.h
new file mode 100644
index 0000000..0fcc616
--- /dev/null
+++ b/sr_vvms/mutexsp.h
@@ -0,0 +1,51 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2004 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef MUTEXSP_H
+#define MUTEXSP_H
+
+/*
+ * Initialize a mutex with n que entries. If crash is TRUE, then this is
+ * a "crash" reinitialization; otherwise it's a "clean" initialization.
+ */
+void mutex_init(mutex_struct_ptr_t addr, int4 n, bool crash);
+
+/* mutex_lockw - write access to mutex at addr */
+#if defined(__vax)
+enum cdb_sc mutex_lockw(mutex_struct_ptr_t addr, int4 crash_count, uint4 *write_lock);
+#define MUTEX_LOCKW(addr, seq, flag, spin_parms) mutex_lockw(addr, seq, flag) /* ignore spin_parms on VAX */
+
+#elif defined(__alpha)
+enum cdb_sc mutex_lockw(mutex_struct_ptr_t addr, int4 crash_count, uint4 *write_lock, mutex_spin_parms_ptr_t spin_parms);
+#define MUTEX_LOCKW(addr, seq, flag, spin_parms) mutex_lockw(addr, seq, flag, spin_parms)
+
+#else
+#error UNSUPPORTED_PLATFORM /* neither ALPHA VMS, nor VAX VMS */
+#endif
+
+/*
+ * mutex_lockwim - write access to mutex at addr; if cannot lock,
+ * immediately return cdb_sc_nolock
+ */
+enum cdb_sc mutex_lockwim(mutex_struct_ptr_t addr, int4 crash_count, uint4 *write_lock);
+
+/*
+ * mutex_lockw_ccp - write access to mutex at addr; if cannot lock,
+ * queue CCP for "wakeup" and return
+ * cdb_sc_nolock (do NOT hiber)
+ */
+enum cdb_sc mutex_lockw_ccp(mutex_struct_ptr_t addr, int4 crash_count, uint4 *write_lock, void *super_crit);
+
+/* mutex_unlockw - unlock write access to mutex at addr */
+enum cdb_sc mutex_unlockw(mutex_struct_ptr_t addr, int4 crash_count, uint4 *write_lock);
+
+
+#endif /* MUTEXSP_H */
diff --git a/sr_vvms/mval2desc.c b/sr_vvms/mval2desc.c
new file mode 100644
index 0000000..4e41f06
--- /dev/null
+++ b/sr_vvms/mval2desc.c
@@ -0,0 +1,255 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <descrip.h>
+#include "mvalconv.h"
+#include "mval2desc.h"
+
+error_def(ERR_ERRCALL);
+error_def(ERR_NUMOFLOW);
+error_def(ERR_SYSCALL);
+error_def(ERR_UNSDCLASS);
+error_def(ERR_UNSDDTYPE);
+
+void mval2desc(mval *v, struct dsc$descriptor *d)
+{
+ if ($is_desc64(d))
+ mval2desc_64(v, (struct dsc64$descriptor *)d);
+ else
+ mval2desc_32(v, d);
+}
+
+void mval2desc_32(mval *v, struct dsc$descriptor *d)
+{
+ int4 status;
+ int4 lx;
+ struct dsc$descriptor src;
+ double srcnm;
+
+ switch(d->dsc$b_class)
+ {
+ case DSC$K_CLASS_D: /* dynamic string descriptor */
+ switch(d->dsc$b_dtype)
+ {
+ case DSC$K_DTYPE_T:
+ MV_FORCE_STR(v);
+ if (v->str.len != d->dsc$w_length)
+ { /* re-allocate descriptor if length doesn't match */
+ if (d->dsc$a_pointer) /* free only if already allocated */
+ {
+ status = lib$sfree1_dd(d);
+ if (0 == (status & 1))
+ rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("LIB$SFREE1_DD"),
+ CALLFROM, status);
+ }
+ status = lib$sget1_dd(&v->str.len, d);
+ if (0 == (status & 1))
+ rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("LIB$SGET1_DD"),
+ CALLFROM, status);
+ }
+ memcpy(d->dsc$a_pointer, v->str.addr, v->str.len);
+ break;
+ default:
+ rts_error(VARLSTCNT(1) ERR_UNSDDTYPE);
+ }
+ break;
+ case DSC$K_CLASS_S: /* scalar or string descriptor */
+ switch(d->dsc$b_dtype)
+ {
+ case DSC$K_DTYPE_T:
+ MV_FORCE_STR(v);
+ lx = v->str.len;
+ if (lx > d->dsc$w_length)
+ lx = d->dsc$w_length;
+ if (lx)
+ memcpy(d->dsc$a_pointer, v->str.addr, lx);
+ if (d->dsc$w_length > lx)
+ memset(d->dsc$a_pointer + lx, 0, d->dsc$w_length - lx);
+ break;
+ case DSC$K_DTYPE_G:
+ MV_FORCE_NUM(v);
+ *(double *)d->dsc$a_pointer = mval2double(v);
+ break;
+ case DSC$K_DTYPE_B:
+ lx = MV_FORCE_INT(v);
+ if (lx > 127 || lx < -127)
+ rts_error(VARLSTCNT(1) ERR_NUMOFLOW);
+ *(char *)d->dsc$a_pointer = lx;
+ break;
+ case DSC$K_DTYPE_BU:
+ lx = MV_FORCE_INT(v);
+ if (lx > 255)
+ rts_error(VARLSTCNT(1) ERR_NUMOFLOW);
+ *(unsigned char *)d->dsc$a_pointer = lx;
+ break;
+ case DSC$K_DTYPE_W:
+ lx = MV_FORCE_INT(v);
+ if (lx > 32767 || lx < -32767)
+ rts_error(VARLSTCNT(1) ERR_NUMOFLOW);
+ *(short *)d->dsc$a_pointer = lx;
+ break;
+ case DSC$K_DTYPE_WU:
+ lx = MV_FORCE_INT(v);
+ if (lx > 65535)
+ rts_error(VARLSTCNT(1) ERR_NUMOFLOW);
+ *(unsigned short *)d->dsc$a_pointer = lx;
+ break;
+ case DSC$K_DTYPE_LU:
+ /* This case has been separated from the group immediately below
+ to get around a bug in lib$cvt_dx_dx introduced in OpenVMS AXP V6.1
+ that returns LIB$_INTOVF for any LU value greater than 2147483647. */
+ MV_FORCE_NUM(v);
+ srcnm = mval2double(v);
+ if (srcnm > 4294967295.0)
+ rts_error(VARLSTCNT(1) ERR_NUMOFLOW);
+ *(uint4 *)d->dsc$a_pointer = srcnm;
+ break;
+ case DSC$K_DTYPE_L:
+ case DSC$K_DTYPE_Q:
+ case DSC$K_DTYPE_QU:
+ case DSC$K_DTYPE_D:
+ case DSC$K_DTYPE_F:
+ case DSC$K_DTYPE_H:
+ MV_FORCE_NUM(v);
+ srcnm = mval2double(v);
+ src.dsc$w_length = 0;
+ src.dsc$b_dtype = DSC$K_DTYPE_G;
+ src.dsc$b_class = DSC$K_CLASS_S;
+ src.dsc$a_pointer = &srcnm;
+ status = lib$cvt_dx_dx(&src, d);
+ if (0 == (status & 1))
+ rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("LIB$CVT_DX_DX"),
+ CALLFROM, status);
+ break;
+ default:
+ rts_error(VARLSTCNT(1) ERR_UNSDDTYPE);
+ }
+ break;
+ default:
+ rts_error(VARLSTCNT(7) ERR_UNSDCLASS, 5, ERR_ERRCALL, 3, CALLFROM);
+ }
+}
+
+void mval2desc_64(mval *v, struct dsc64$descriptor *d)
+{
+ int4 status;
+ int4 lx;
+ struct dsc64$descriptor src;
+ double srcnm;
+
+ switch(d->dsc64$b_class)
+ {
+
+ case DSC64$K_CLASS_D: /* dynamic string descriptor */
+ switch(d->dsc64$b_dtype)
+ {
+ case DSC64$K_DTYPE_T:
+ MV_FORCE_STR(v);
+ if (v->str.len != d->dsc64$q_length)
+ { /* re-allocate descriptor if length doesn't match */
+ if (d->dsc64$pq_pointer) /* free only if already allocated */
+ {
+ status = lib$sfree1_dd(d);
+ if (0 == (status & 1))
+ rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("LIB$SFREE1_DD"),
+ CALLFROM, status);
+ }
+ d->dsc64$q_length = v->str.len;
+ status = lib$sget1_dd_64(&d->dsc64$q_length, d);
+ if (0 == (status & 1))
+ rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("LIB$SGET1_DD_64"),
+ CALLFROM, status);
+ }
+ memcpy(d->dsc64$pq_pointer, v->str.addr, v->str.len);
+ break;
+ default:
+ rts_error(VARLSTCNT(1) ERR_UNSDDTYPE);
+ }
+ break;
+ case DSC64$K_CLASS_S: /* scalar or string descriptor */
+ switch(d->dsc64$b_dtype)
+ {
+ case DSC64$K_DTYPE_T:
+ MV_FORCE_STR(v);
+ lx = v->str.len;
+ if (lx > d->dsc64$q_length)
+ lx = d->dsc64$q_length;
+ if (lx)
+ memcpy(d->dsc64$pq_pointer, v->str.addr, lx);
+ if (d->dsc64$q_length > lx)
+ memset(d->dsc64$pq_pointer + lx, 0, d->dsc64$q_length - lx);
+ break;
+ case DSC64$K_DTYPE_G:
+ MV_FORCE_NUM(v);
+ *(double *)d->dsc64$pq_pointer = mval2double(v);
+ break;
+ case DSC64$K_DTYPE_B:
+ lx = MV_FORCE_INT(v);
+ if (lx > 127 || lx < -127)
+ rts_error(VARLSTCNT(1) ERR_NUMOFLOW);
+ *(char *)d->dsc64$pq_pointer = lx;
+ break;
+ case DSC64$K_DTYPE_BU:
+ lx = MV_FORCE_INT(v);
+ if (lx > 255)
+ rts_error(VARLSTCNT(1) ERR_NUMOFLOW);
+ *(unsigned char *)d->dsc64$pq_pointer = lx;
+ break;
+ case DSC64$K_DTYPE_W:
+ lx = MV_FORCE_INT(v);
+ if (lx > 32767 || lx < -32767)
+ rts_error(VARLSTCNT(1) ERR_NUMOFLOW);
+ *(short *)d->dsc64$pq_pointer = lx;
+ break;
+ case DSC64$K_DTYPE_WU:
+ lx = MV_FORCE_INT(v);
+ if (lx > 65535)
+ rts_error(VARLSTCNT(1) ERR_NUMOFLOW);
+ *(unsigned short *)d->dsc64$pq_pointer = lx;
+ break;
+ case DSC64$K_DTYPE_LU:
+ /* This case has been separated from the group immediately below
+ to get around a bug in lib$cvt_dx_dx introduced in OpenVMS AXP V6.1
+ that returns LIB$_INTOVF for any LU value greater than 2147483647. */
+ MV_FORCE_NUM(v);
+ srcnm = mval2double(v);
+ if (srcnm > 4294967295.0)
+ rts_error(VARLSTCNT(1) ERR_NUMOFLOW);
+ *(uint4 *)d->dsc64$pq_pointer = srcnm;
+ break;
+ case DSC64$K_DTYPE_L:
+ case DSC64$K_DTYPE_Q:
+ case DSC64$K_DTYPE_QU:
+ case DSC64$K_DTYPE_F:
+ case DSC64$K_DTYPE_D:
+ case DSC64$K_DTYPE_H:
+ MV_FORCE_NUM(v);
+ srcnm = mval2double(v);
+ src.dsc64$w_mbo = 1;
+ src.dsc64$l_mbmo = -1;
+ src.dsc64$q_length = 0;
+ src.dsc64$b_dtype = DSC64$K_DTYPE_G;
+ src.dsc64$b_class = DSC64$K_CLASS_S;
+ src.dsc64$pq_pointer = (char *)&srcnm;
+ status = lib$cvt_dx_dx(&src, d);
+ if (0 == (status & 1))
+ rts_error(VARLSTCNT(8) ERR_SYSCALL, 5, LEN_AND_LIT("LIB$CVT_DX_DX"), CALLFROM,
+ status);
+ break;
+ default:
+ rts_error(VARLSTCNT(1) ERR_UNSDDTYPE);
+ }
+ break;
+ default:
+ rts_error(VARLSTCNT(7) ERR_UNSDCLASS, 5, ERR_ERRCALL, 3, CALLFROM);
+ }
+}
diff --git a/sr_vvms/mval2desc.h b/sr_vvms/mval2desc.h
new file mode 100644
index 0000000..89a9ce9
--- /dev/null
+++ b/sr_vvms/mval2desc.h
@@ -0,0 +1,19 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2004 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef MVAL2DESC_INCLUDED
+#define MVAL2DESC_INCLUDED
+
+void mval2desc(mval *v, struct dsc$descriptor *d); /***type int added***/
+void mval2desc_32(mval *v, struct dsc$descriptor *d);
+void mval2desc_64(mval *v, struct dsc64$descriptor *d);
+
+#endif /* MVAL2DESC_INCLUDED */
diff --git a/sr_vvms/newincver.com b/sr_vvms/newincver.com
new file mode 100644
index 0000000..c09495e
--- /dev/null
+++ b/sr_vvms/newincver.com
@@ -0,0 +1,224 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2005 Fidelity Information Services, Inc !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$! newincver - create incremental version of gtm
+$! parameters:
+$! p1 = platform
+$! p2 = newver
+$! p3 = oldver
+$! p4 = copyolb (y or n)
+$! p5 = cms class from which to download following scripts into [.tools] (e.g. "V4.3001B" or "" for V9.9-0 or "n" for none)
+$! p6 = copy all src (y or n)
+$! cms_load.com
+$! cms_load_verify_from_to_version.com
+$! fetch_cms_version.com
+$! vms_cms_load.com
+$!
+$ interact = (f$mode() .eqs. "INTERACTIVE")
+$!
+$ set noon
+$!
+$ if p1 .nes. "AXP" .and. p1 .nes. "VAX"
+$ then
+$ if interact then inquire p1 "Platform (AXP/VAX)"
+$ if p1 .nes. "AXP" .and. p1 .nes. "VAX"
+$ then
+$ write sys$output "No action taken"
+$ exit
+$ endif
+$ endif
+$ if f$getsyi("arch_name") .eqs. "VAX"
+$ then
+$ platform = "VAX"
+$ else
+$ platform = "AXP"
+$ endif
+$ if platform .nes. p1
+$ then
+$ write sys$output "NEWINCVER-E-PLATFORMUM Platform does not match. Install requires platform to match."
+$ exit
+$ endif
+$!
+$asknew:
+$ if p2 .eqs. ""
+$ then
+$ write sys$output "Must specify a new directory"
+$ if interact then inquire p2 "New directory"
+$ if p2 .eqs. ""
+$ then
+$ write sys$output "No action taken"
+$ exit
+$ endif
+$ endif
+$!
+$ if f$search(p1+"_gtm$gtmdev:[library]"+p2+".dir") .nes. ""
+$ then
+$ write sys$output "Destination directory "+p2+" already exists. Can't continue on existing directory."
+$ p2 :=
+$ goto asknew
+$ endif
+$!
+$askold:
+$ if p3 .eqs. ""
+$ then
+$ write sys$output "Must specify an old directory"
+$ if interact then inquire p3 "Old directory"
+$ if p3 .eqs. ""
+$ then
+$ write "No action taken"
+$ exit
+$ endif
+$ endif
+$!
+$ if f$search(p1+"_gtm$gtmdev:[library]"+p3+".dir") .eqs. ""
+$ then
+$ write sys$output "Old directory not found"
+$ p3 :=
+$ goto askold
+$ endif
+$!
+$ if interact .and. (p4 .eqs. "")
+$ then
+$ write sys$output "Must specify whether to copy mumps.olb's"
+$ inquire p4 "Copy? <Yes>"
+$ endif
+$ if p4 .eqs. "" then p4 := y
+$!
+$! -------------- set up directories for a new version (used to be newverdir.com) -----------------
+$!
+$ create/dir/prot=(o:rwed,s=rwe,g=re,w=re)/log 'p1'_gtm$gtmdev:[library.'p2'] /owner='f$user()'
+$ set def 'p1'_gtm$gtmdev:[library.'p2']
+$!
+$ create/dir/prot=(o:rwed,s=rwe,g=re,w=re)/log [.cmi]
+$ create/dir/prot=(o:rwed,s=rwe,g=re,w=re)/log [.dist]
+$ create/dir/prot=(o:rwed,s=rwe,g=re,w=re)/log [.hlp]
+$ create/dir/prot=(o:rwed,s=rwe,g=re,w=re)/log [.pct]
+$ create/dir/prot=(o:rwed,s=rwe,g=re,w="")/log [.src]
+$ create/dir/prot=(o:rwed,s=rwe,g=re,w=re)/log [.tools]
+$!
+$ create/dir/prot=(o:rwed,s=rwe,g=re,w=re)/log [.tcm]
+$ create/dir/prot=(o:rwed,s=rwe,g=re,w=re)/log [.tcx]
+$ create/dir/prot=(o:rwed,s=rwe,g=re,w=re)/log [.tdp]
+$ create/dir/prot=(o:rwed,s=rwe,g=re,w=re)/log [.tdc]
+$ create/dir/prot=(o:rwed,s=rwe,g=re,w=re)/log [.tfi]
+$ create/dir/prot=(o:rwed,s=rwe,g=re,w=re)/log [.tls]
+$!
+$ create/dir/prot=(o:rwed,s=rwe,g=re,w=re)/log [.pro]
+$ set def [.pro]
+$ create/dir/prot=(o:rwed,s=rwe,g=re,w="")/log [.map]
+$ create/dir/prot=(o:rwed,s=rwe,g=re,w=re)/log [.obj]
+$ set def [-]
+$!
+$ create/dir/prot=(o:rwed,s=rwe,g=re,w=re)/log [.bta]
+$ set def [.bta]
+$ create/dir/prot=(o:rwed,s=rwe,g=re,w="")/log [.map]
+$ create/dir/prot=(o:rwed,s=rwe,g=re,w=re)/log [.obj]
+$ set def [-]
+$!
+$ create/dir/prot=(o:rwed,s=rwe,g=re,w=re)/log [.dbg]
+$ set def [.dbg]
+$ create/dir/prot=(o:rwed,s=rwe,g=re,w="")/log [.map]
+$ create/dir/prot=(o:rwed,s=rwe,g=re,w="")/log [.obj]
+$ set def [-]
+$!
+$! ---------- copy over stuff from old directory to new directory structure -----------
+$!
+$ set def 'p1'_gtm$gtmdev:[library.'p2']
+$!
+$ open/write newsrc 'p1'_gtm$gtmdev:[library.'p2']gtmsrc.com
+$ write newsrc "$ define/nolog/proc gtmsecshr gtm$sec:"+p2+"_gtmsecshr.exe"
+$ write newsrc "$ define/nolog/job gtmsecshr gtm$sec:"+p2+"_gtmsecshr.exe"
+$ write newsrc "$ define/nolog/proc/exec cmishr gtm$sec:"+p2+"_cmishr.exe"
+$ write newsrc "$ define/nolog/job/exec cmishr gtm$sec:"+p2+"_cmishr.exe"
+$ write newsrc "$ define gtm$src gtm$root:["+p2+".src]"
+$ close newsrc
+$ set prot=(w:re) 'p1'_gtm$gtmdev:[library.'p2']gtmsrc.com
+$!
+$ exclude_list = "gtmsrc.com,*comlist.com,*.log,*.dir,minclude.tlb,dbgflip.com"
+$ copy/log 'p1'_gtm$gtmdev:[library.'p3']*.* 'p1'_gtm$gtmdev:[library.'p2']/excl=('exclude_list')
+$!
+$ if "" .NES. f$search(p1+"_gtm$gtmdev:[library."+p3+"]cmi.dir")
+$ then
+$! smw 2001/08/15 cmi is small enough so we will just copy it
+$ copy/log 'p1'_gtm$gtmdev:[library.'p3'.cmi]*.* 'p1'_gtm$gtmdev:[library.'p2'.cmi]
+$ endif
+$!
+$ copy/log 'p1'_gtm$gtmdev:[library.'p3'.pct]*.* 'p1'_gtm$gtmdev:[library.'p2'.pct]
+$ if ((p6 .nes. "y") .and. (p6 .nes. "Y"))
+$ then
+$ p6 = "N"
+$ copy/log 'p1'_gtm$gtmdev:[library.'p3'.src]*.%lb/excl=(minclude.tlb) 'p1'_gtm$gtmdev:[library.'p2'.src]
+$ else
+$ copy/log 'p1'_gtm$gtmdev:[library.'p3'.src]*.*/excl=(minclude.tlb) 'p1'_gtm$gtmdev:[library.'p2'.src]
+$ endif
+$ if ("" .nes. f$search("''p1'_gtm$gtmdev:[library.''p3'.tools]*.*"))
+$ then
+$ copy/log 'p1'_gtm$gtmdev:[library.'p3'.tools]*.* 'p1'_gtm$gtmdev:[library.'p2'.tools]
+$ endif
+$!
+$ if p4
+$ then
+$ set noon
+$ copy/log 'p1'_gtm$gtmdev:[library.'p3'.bta.obj]*.%lb. 'p1'_gtm$gtmdev:[library.'p2'.bta.obj]
+$ copy/log 'p1'_gtm$gtmdev:[library.'p3'.dbg.obj]*.%lb. 'p1'_gtm$gtmdev:[library.'p2'.dbg.obj]
+$ copy/log 'p1'_gtm$gtmdev:[library.'p3'.pro.obj]*.%lb. 'p1'_gtm$gtmdev:[library.'p2'.pro.obj]
+$ write sys$output " "
+$ endif
+$!
+$!the following copy supplies an environment to bootstrap a build
+$ copy/log 'p1'_gtm$gtmdev:[library.'p3'.pro]*.exe,*.mlb,*.olb,*.cld/excl=(lmu.exe,ipcrm.exe) 'p1'_gtm$gtmdev:[library.'p2'.pro]
+$ rename/log 'p1'_gtm$gtmdev:[library.'p2'.pro]'p3'_gtmsecshr.exe 'p1'_gtm$gtmdev:[library.'p2'.pro]'p2'_gtmsecshr.exe
+$ rename/log 'p1'_gtm$gtmdev:[library.'p2'.pro]'p3'_cmishr.exe 'p1'_gtm$gtmdev:[library.'p2'.pro]'p2'_cmishr.exe
+$ if "" .NES. f$search(p1 + "_gtm$gtmdev:[library." + p2 + ".pro]" + p3 + "_crashandburn.exe")
+$ then
+$ rename/log 'p1'_gtm$gtmdev:[library.'p2'.pro]'p3'_crashandburn.exe 'p1'_gtm$gtmdev:[library.'p2'.pro]'p2'_crashandburn.exe
+$ endif
+$ set file/protection=w=re 'p1'_gtm$gtmdev:[library.'p2'.pro]'p2'_gtmsecshr.exe
+$ curr_priv = f$setprv("cmkrnl,bypas")
+$ if f$priv("cmkrnl,bypas")
+$ then
+$ copy 'p1'_gtm$gtmdev:[library.'p2'.pro]'p2'_gtmsecshr.exe gtm$sec:
+$ install replace gtm$sec:'p2'_gtmsecshr.exe/prot/shar/head/open
+$ install list gtm$sec:'p2'_gtmsecshr.exe
+$ purge gtm$sec:'p2'_gtmsecshr.exe
+$ copy 'p1'_gtm$gtmdev:[library.'p2'.pro]'p2'_cmishr.exe gtm$sec:
+$ install replace gtm$sec:'p2'_cmishr.exe/prot/shar/head/open
+$ install list gtm$sec:'p2'_cmishr.exe
+$ purge gtm$sec:'p2'_cmishr.exe
+$ else
+$ write sys$output "WARNING - not able to install gtmsecshr and cmishr due to privileges"
+$ endif
+$ curr_priv=f$setprv(curr_priv)
+$!
+$ dir = ''f$trnlnm("''p1'_gtm$gtmdev") + "[library.''p2']"
+$ set default 'dir'
+$ purge/log [...]
+$!
+$! ---------- download cms_load* scripts into [.tools] if necessary -----------
+$!
+$ if ((p5 .nes. "n") .and. (p5 .nes. "N"))
+$ then
+$ set def [.tools]
+$ cms set lib sl_vvms
+$ if (p5 .eqs. "")
+$ then
+$ classgener = ""
+$ else
+$ classgener = "/gener=''p5'"
+$ endif
+$ cms fetch 'classgener' cms_load.com
+$ cms fetch 'classgener' cms_load_verify_from_to_version.com
+$ cms fetch 'classgener' fetch_cms_version.com
+$ cms fetch 'classgener' vms_cms_load.com
+$ set def [-]
+$ endif
+$!
+$ exit
diff --git a/sr_vvms/nmadef.h b/sr_vvms/nmadef.h
new file mode 100644
index 0000000..dd1e599
--- /dev/null
+++ b/sr_vvms/nmadef.h
@@ -0,0 +1,1128 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#define NMA$C_OBJ_NIC 19
+#define NMA$C_FNC_LOA 15
+#define NMA$C_FNC_DUM 16
+#define NMA$C_FNC_TRI 17
+#define NMA$C_FNC_TES 18
+#define NMA$C_FNC_CHA 19
+#define NMA$C_FNC_REA 20
+#define NMA$C_FNC_ZER 21
+#define NMA$C_FNC_SYS 22
+#define NMA$M_OPT_ENT 7
+#define NMA$M_OPT_CLE 64
+#define NMA$M_OPT_PER 128
+#define NMA$M_OPT_INF 112
+#define NMA$C_OPINF_SUM 0
+#define NMA$C_OPINF_STA 1
+#define NMA$C_OPINF_CHA 2
+#define NMA$C_OPINF_COU 3
+#define NMA$C_OPINF_EVE 4
+#define NMA$M_OPT_ACC 128
+#define NMA$M_OPT_REA 128
+#define NMA$C_SYS_RST 1
+#define NMA$C_SYS_RSX 2
+#define NMA$C_SYS_TOP 3
+#define NMA$C_SYS_VMS 4
+#define NMA$C_SYS_RT 5
+#define NMA$C_ENT_NOD 0
+#define NMA$C_ENT_LIN 1
+#define NMA$C_ENT_LOG 2
+#define NMA$C_ENT_CIR 3
+#define NMA$C_ENT_MOD 4
+#define NMA$C_ENT_ARE 5
+#define NMA$C_SENT_PROXY 2
+#define NMA$C_SENT_ALI 3
+#define NMA$C_SENT_OBJ 4
+#define NMA$C_SENT_PRO 5
+#define NMA$C_SENT_SYS 6
+#define NMA$C_SENT_LNK 7
+#define NMA$C_SENT_WLD -30
+#define NMA$M_ENT_EXE 128
+#define NMA$C_ENT_WAR -7
+#define NMA$C_ENT_WAD -6
+#define NMA$C_ENT_ADJ -4
+#define NMA$C_ENT_ACT -2
+#define NMA$C_ENT_KNO -1
+#define NMA$C_ENT_ADD 0
+#define NMA$C_ENT_ALL -3
+#define NMA$C_ENT_LOO -3
+#define NMA$C_SNK_CON 1
+#define NMA$C_SNK_FIL 2
+#define NMA$C_SNK_MON 3
+#define NMA$M_CNT_TYP 4095
+#define NMA$M_CNT_MAP 4096
+#define NMA$M_CNT_WID 24576
+#define NMA$M_CNT_COU 32768
+#define NMA$M_CNT_WIL 8192
+#define NMA$M_CNT_WIH 16384
+#define NMA$S_OPT_ENT 3
+#define NMA$V_OPT_ENT 0
+#define NMA$V_OPT_CLE 6
+#define NMA$V_OPT_PER 7
+#define NMA$S_OPT_INF 3
+#define NMA$V_OPT_INF 4
+#define NMA$V_OPT_ACC 7
+#define NMA$V_OPT_REA 7
+#define NMA$V_ENT_EXE 7
+#define NMA$S_CNT_TYP 12
+#define NMA$V_CNT_TYP 0
+#define NMA$V_CNT_MAP 12
+#define NMA$S_CNT_WID 2
+#define NMA$V_CNT_WID 13
+#define NMA$V_CNT_COU 15
+#define NMA$V_CNT_WIL 13
+#define NMA$V_CNT_WIH 14
+#define NMA$M_PTY_TYP 32767
+#define NMA$C_PTY_MAX 15
+#define NMA$M_PTY_CLE 63
+#define NMA$M_PTY_MUL 64
+#define NMA$M_PTY_COD 128
+#define NMA$M_PTY_CMU 192
+#define NMA$M_PTY_NLE 15
+#define NMA$M_PTY_NTY 48
+#define NMA$M_PTY_ASC 64
+#define NMA$C_NTY_DU 0
+#define NMA$C_NTY_DS 1
+#define NMA$C_NTY_H 2
+#define NMA$C_NTY_O 3
+#define NMA$C_NLE_IMAGE 0
+#define NMA$C_NLE_BYTE 1
+#define NMA$C_NLE_WORD 2
+#define NMA$C_NLE_LONG 4
+#define NMA$C_NLE_QUAD 8
+#define NMA$C_PTY_AI 64
+#define NMA$C_PTY_HI 32
+#define NMA$C_PTY_H1 33
+#define NMA$C_PTY_H2 34
+#define NMA$C_PTY_H4 36
+#define NMA$C_PTY_DU1 1
+#define NMA$C_PTY_DU2 2
+#define NMA$C_PTY_CD1 129
+#define NMA$C_PTY_CM2 194
+#define NMA$C_PTY_CM3 195
+#define NMA$C_PTY_CM4 196
+#define NMA$C_PTY_CM5 197
+#define NMA$C_CTLVL_UI 3
+#define NMA$C_CTLVL_XID 175
+#define NMA$C_CTLVL_XID_P 191
+#define NMA$C_CTLVL_TEST 227
+#define NMA$C_CTLVL_TEST_P 243
+#define NMA$C_PCCI_STA 0
+#define NMA$C_PCCI_SUB 1
+#define NMA$C_PCCI_SER 100
+#define NMA$C_PCCI_LCT 110
+#define NMA$C_PCCI_SPY 120
+#define NMA$C_PCCI_SSB 121
+#define NMA$C_PCCI_CNO 200
+#define NMA$C_PCCI_COB 201
+#define NMA$C_PCCI_LOO 400
+#define NMA$C_PCCI_ADJ 800
+#define NMA$C_PCCI_DRT 801
+#define NMA$C_PCCI_BLO 810
+#define NMA$C_PCCI_COS 900
+#define NMA$C_PCCI_MRT 901
+#define NMA$C_PCCI_RPR 902
+#define NMA$C_PCCI_HET 906
+#define NMA$C_PCCI_LIT 907
+#define NMA$C_PCCI_BLK 910
+#define NMA$C_PCCI_MRC 920
+#define NMA$C_PCCI_RCT 921
+#define NMA$C_PCCI_NUM 930
+#define NMA$C_PCCI_USR 1000
+#define NMA$C_PCCI_POL 1010
+#define NMA$C_PCCI_PLS 1011
+#define NMA$C_PCCI_OWN 1100
+#define NMA$C_PCCI_LIN 1110
+#define NMA$C_PCCI_USE 1111
+#define NMA$C_PCCI_TYP 1112
+#define nma$c_pcci_net 1119
+#define NMA$C_PCCI_DTE 1120
+#define NMA$C_PCCI_CHN 1121
+#define NMA$C_PCCI_MBL 1122
+#define NMA$C_PCCI_MWI 1123
+#define NMA$C_PCCI_TRI 1140
+#define NMA$C_PCCI_BBT 1141
+#define NMA$C_PCCI_TRT 1142
+#define NMA$C_PCCI_RTT 1143
+#define NMA$C_PCCI_MRB 1145
+#define NMA$C_PCCI_MTR 1146
+#define NMA$C_PCCI_ACB 1150
+#define NMA$C_PCCI_ACI 1151
+#define NMA$C_PCCI_IAB 1152
+#define NMA$C_PCCI_IAI 1153
+#define NMA$C_PCCI_IAT 1154
+#define NMA$C_PCCI_DYB 1155
+#define NMA$C_PCCI_DYI 1156
+#define NMA$C_PCCI_DYT 1157
+#define NMA$C_PCCI_DTH 1158
+#define NMA$C_PCCI_RSX_MAC 2320
+#define NMA$C_PCCI_RSX_LOG 2380
+#define NMA$C_PCCI_RSX_DLG 2385
+#define NMA$C_PCCI_RSX_ACT 2390
+#define NMA$C_PCCI_VER 2700
+#define NMA$C_PCCI_XPT 2720
+#define NMA$C_PCCI_IRC 2750
+#define NMA$C_PCCI_ORC 2751
+#define NMA$C_PCCI_GRP 2752
+#define NMA$C_PCCI_NOP 2753
+#define NMA$C_PCCI_CAL 2754
+#define NMA$C_PCCI_INA 2755
+#define NMA$C_PCCI_RED 2756
+#define NMA$C_PCCI_MOD 2757
+#define NMA$C_PCCI_REQ 2758
+#define NMA$C_PCCI_DTW 2759
+#define NMA$C_PCCI_PRO 2760
+#define NMA$C_PCCI_INF 2761
+#define NMA$C_PCCI_ACC 2762
+#define NMA$C_PCCI_CLR 2763
+#define NMA$C_PCCI_DTC 2764
+#define NMA$C_PCCI_CCG 2765
+#define NMA$C_PCCI_ESA 2766
+#define NMA$C_PCCI_DTI 2767
+#define NMA$C_PCCI_SWC 2768
+#define NMA$C_PCCI_TIC 2769
+#define NMA$C_PCCI_CSG 2770
+#define NMA$C_PCCI_AAS 2771
+#define NMA$C_PCCI_DTS 2772
+#define NMA$C_PCCI_CAS 2773
+#define NMA$C_PCCI_CPS 2774
+#define NMA$C_PCCI_CNT 2775
+#define NMA$C_PCCI_RAT 2776
+#define NMA$C_PCCI_PRD 2777
+#define NMA$C_PCCI_DAY 2778
+#define NMA$C_PCCI_BFN 2779
+#define NMA$C_PCCI_BSZ 2780
+#define NMA$C_PCCI_MDM 2781
+#define NMA$C_PCCI_DTL 2782
+#define NMA$C_PCCI_IDL 2783
+#define NMA$C_PCCI_IMT 2784
+#define NMA$C_PCCI_CAC 2785
+#define NMA$C_PCCI_ORD 2786
+#define NMA$C_PCCI_CID 2787
+#define NMA$C_PCCI_MST 2810
+#define NMA$C_PCCI_SRV_LOG 3380
+#define NMA$C_PCCI_SRV_DLG 3385
+#define NMA$C_PCCI_SRV_ACT 3390
+#define NMA$C_PCLI_STA 0
+#define NMA$C_PCLI_SUB 1
+#define NMA$C_PCLI_SER 100
+#define NMA$C_PCLI_LCT 110
+#define NMA$C_PCLI_LOO 400
+#define NMA$C_PCLI_ADJ 800
+#define NMA$C_PCLI_BLO 810
+#define NMA$C_PCLI_COS 900
+#define NMA$C_PCLI_DEV 1100
+#define NMA$C_PCLI_BFN 1105
+#define NMA$C_PCLI_CON 1110
+#define NMA$C_PCLI_DUP 1111
+#define NMA$C_PCLI_PRO 1112
+#define NMA$C_PCLI_LTY 1112
+#define NMA$C_PCLI_CLO 1113
+#define NMA$C_PCLI_STI 1120
+#define NMA$C_PCLI_NTI 1121
+#define NMA$C_PCLI_RTT 1121
+#define NMA$C_PCLI_HTI 1122
+#define NMA$C_PCLI_MBL 1130
+#define NMA$C_PCLI_MRT 1131
+#define NMA$C_PCLI_MWI 1132
+#define NMA$C_PCLI_TRI 1140
+#define NMA$C_PCLI_SLT 1150
+#define NMA$C_PCLI_DDT 1151
+#define NMA$C_PCLI_DLT 1152
+#define NMA$C_PCLI_SRT 1153
+#define NMA$C_PCLI_HWA 1160
+#define nma$c_pcli_net 1190
+#define NMA$C_PCLI_XMD 1191
+#define NMA$C_PCLI_RSX_OWN 2300
+#define NMA$C_PCLI_RSX_CCS 2310
+#define NMA$C_PCLI_RSX_UCS 2311
+#define NMA$C_PCLI_RSX_VEC 2312
+#define NMA$C_PCLI_RSX_PRI 2313
+#define NMA$C_PCLI_RSX_MDE 2321
+#define NMA$C_PCLI_RSX_LLO 2330
+#define NMA$C_PCLI_RSX_LOG 2380
+#define NMA$C_PCLI_RSX_DLG 2385
+#define NMA$C_PCLI_RSX_ACT 2390
+#define NMA$C_PCLI_MCD 2701
+#define NMA$C_PCLI_EPT 2720
+#define NMA$C_PCLI_LNS 2730
+#define NMA$C_PCLI_SWI 2740
+#define NMA$C_PCLI_HNG 2750
+#define NMA$C_PCLI_TPI 2760
+#define nma$c_pcli_nrzi 2761
+#define nma$c_pcli_code 2762
+#define NMA$C_PCLI_FMT 2770
+#define NMA$C_PCLI_SRV 2771
+#define NMA$C_PCLI_SAP 2772
+#define NMA$C_PCLI_GSP 2773
+#define NMA$C_PCLI_PID 2774
+#define NMA$C_PCLI_BUS 2801
+#define NMA$C_PCLI_NMS 2810
+#define NMA$C_PCLI_PHA 2820
+#define NMA$C_PCLI_DPA 2821 ; (same as HWA)
+#define NMA$C_PCLI_PTY 2830
+#define NMA$C_PCLI_MCA 2831
+#define NMA$C_PCLI_ILP 2839
+#define NMA$C_PCLI_PRM 2840
+#define NMA$C_PCLI_MLT 2841
+#define NMA$C_PCLI_PAD 2842
+#define NMA$C_PCLI_DCH 2843
+#define NMA$C_PCLI_CRC 2844
+#define NMA$C_PCLI_HBQ 2845
+#define NMA$C_PCLI_ACC 2846
+#define NMA$C_PCLI_EKO 2847
+#define NMA$C_PCLI_BSZ 2848
+#define NMA$C_PCLI_DES 2849
+#define NMA$C_PCLI_RET 2850
+#define NMA$C_PCLI_MOD 2851
+#define NMA$C_PCLI_RIB 2852
+#define NMA$C_PCLI_MNTL 2860
+#define NMA$C_PCLI_INTL0 2861
+#define NMA$C_PCLI_INTL1 2862
+#define NMA$C_PCLI_INTL2 2863
+#define NMA$C_PCLI_INTL3 2864
+#define NMA$C_PCLI_FRA 2865
+#define NMA$C_PCLI_STI1 2866
+#define NMA$C_PCLI_STI2 2867
+#define NMA$C_PCLI_TMO 2868
+#define NMA$C_PCLI_MCL 2869
+#define NMA$C_PCLI_SYC 2870
+#define NMA$C_PCLI_BPC 2871
+#define NMA$C_PCLI_MBS 2872
+#define NMA$C_PCLI_RES 2873
+#define NMA$C_PCLI_SRV_OWN 3300
+#define NMA$C_PCLI_SRV_UCS 3311
+#define NMA$C_PCLI_SRV_VEC 3312
+#define NMA$C_PCLI_SRV_PRI 3313
+#define NMA$C_PCLI_SRV_LOG 3380
+#define NMA$C_PCLI_SRV_DLG 3385
+#define NMA$C_PCLI_SRV_ACT 3390
+#define NMA$C_PCCO_RTR 110
+#define NMA$C_PCLD_ASS 10
+#define NMA$C_PCLP_ASS 10
+#define NMA$C_PCCN_CIR 100
+#define NMA$C_PCCN_SUR 110
+#define NMA$C_PCCN_ELT 111
+#define NMA$C_PCCN_PHA 120
+#define NMA$C_PCCN_LRP 130
+#define NMA$C_PCCN_MVR 20001
+#define NMA$C_PCCN_FCT 20002
+#define NMA$C_PCCN_CUS 20003
+#define NMA$C_PCCN_RTR 20004
+#define NMA$C_PCCN_CSZ 20005
+#define NMA$C_PCCN_RSZ 20006
+#define NMA$C_PCCN_HWA 20007
+#define NMA$C_PCCN_DTY 20100
+#define NMA$C_PCCN_SFI 20200
+#define NMA$C_PCCN_SPR 20300
+#define NMA$C_PCCN_DLK 20400
+#define NMA$C_PCLO_STA 0
+#define NMA$C_PCLO_LNA 100
+#define NMA$C_PCLO_SIN 200
+#define NMA$C_PCLO_EVE 201
+#define NMA$C_PCXA_NOD 320
+#define NMA$C_PCXA_USR 330
+#define NMA$C_PCXA_SPW 331
+#define NMA$C_PCXA_RPW 331
+#define NMA$C_PCXA_ACC 332
+#define NMA$C_PCXA_NET 1110
+#define NMA$C_PCXA_RSX_ADS 2310
+#define NMA$C_PCXA_RSX_ANB 2320
+#define NMA$C_PCXA_RSX_ASC 2330
+#define NMA$C_PCXA_SRV_ADS 3310
+#define NMA$C_PCXA_SRV_ANB 3320
+#define NMA$C_PCXA_SRV_ASC 3330
+#define NMA$C_PCXP_STA 0
+#define NMA$C_PCXP_SBS 1
+#define NMA$C_PCXP_CTM 100
+#define NMA$C_PCXP_ACH 1000
+#define NMA$C_PCXP_ASW 1010
+#define NMA$C_PCXP_DTE 1100
+#define NMA$C_PCXP_GRP 1101
+#define NMA$C_pcxp_netent 1110
+#define NMA$C_pcxp_dnt 1111
+#define NMA$C_PCXP_LIN 1120
+#define NMA$C_PCXP_CHN 1130
+#define NMA$C_PCXP_MCH 1131
+#define NMA$C_PCXP_DBL 1140
+#define NMA$C_PCXP_DWI 1141
+#define NMA$C_PCXP_MBL 1150
+#define NMA$C_PCXP_MWI 1151
+#define NMA$C_PCXP_MCL 1152
+#define NMA$C_PCXP_MRS 1153
+#define NMA$C_PCXP_MST 1154
+#define NMA$C_PCXP_CAT 1160
+#define NMA$C_PCXP_CLT 1161
+#define NMA$C_PCXP_RST 1162
+#define NMA$C_PCXP_STT 1163
+#define NMA$C_pcxp_itt 1164
+#define NMA$C_PCXP_GDT 1170
+#define NMA$C_PCXP_GNM 1171
+#define NMA$C_PCXP_GTY 1172
+#define NMA$C_pcxp_gnt 1173
+#define nma$c_pcxp_mode 1180
+#define nma$c_pcxp_prof 1190
+#define NMA$C_PCXP_RSX_PMC 2300
+#define NMA$C_PCXP_MCI 2710
+#define NMA$C_PCXP_SRV_PMC 3300
+#define nma$c_pcxs_sta 1
+#define NMA$C_PCXS_CTM 100
+#define NMA$C_PCXS_ACI 200
+#define NMA$C_PCXS_DST 300
+#define NMA$C_PCXS_MCI 310
+#define NMA$C_PCXS_NOD 320
+#define NMA$C_PCXS_USR 330
+#define NMA$C_PCXS_SPW 331
+#define NMA$C_PCXS_RPW 331
+#define NMA$C_PCXS_ACC 332
+#define NMA$C_PCXS_OBJ 340
+#define NMA$C_PCXS_PRI 350
+#define NMA$C_PCXS_CMK 351
+#define NMA$C_PCXS_CVL 352
+#define NMA$C_PCXS_GRP 353
+#define NMA$C_PCXS_SDTE 354
+#define NMA$C_PCXS_SAD 355
+#define nma$c_pcxs_red 390
+#define nma$c_pcxs_cdte 391
+#define nma$c_pcxs_rdte 392
+#define nma$c_pcxs_net 393
+#define nma$C_pcxs_emk 394
+#define nma$C_pcxs_evl 395
+#define nma$C_pcxs_idte 396
+#define NMA$C_PCXS_RSX_5ST 2310
+#define NMA$C_PCXS_FIL 2710
+#define NMA$C_PCXS_SRV_5ST 3310
+#define NMA$C_PCXT_STA 0
+#define NMA$C_PCXT_BSZ 100
+#define NMA$C_PCXT_MBK 101
+#define NMA$C_PCXT_FNM 102
+#define NMA$C_PCXT_MBF 103
+#define NMA$C_PCXT_CPL 104
+#define NMA$C_PCXT_MVR 105
+#define NMA$C_PCXT_TPT 106
+#define NMA$C_PCXT_CPS 110
+#define NMA$C_PCXT_TST 111
+#define NMA$C_PCNO_STA 0
+#define NMA$C_PCNO_PHA 10
+#define NMA$C_PCNO_IDE 100
+#define NMA$C_PCNO_MVE 101
+#define NMA$C_PCNO_SLI 110
+#define NMA$C_PCNO_SPA 111
+#define NMA$C_PCNO_SDV 112
+#define NMA$C_PCNO_CPU 113
+#define NMA$C_PCNO_HWA 114
+#define NMA$C_PCNO_SNV 115
+#define NMA$C_PCNO_LOA 120
+#define NMA$C_PCNO_SLO 121
+#define NMA$C_PCNO_TLO 122
+#define NMA$C_PCNO_DFL 123
+#define NMA$C_PCNO_STY 125
+#define NMA$C_PCNO_SID 126
+#define NMA$C_PCNO_MFL 127
+#define NMA$C_PCNO_DUM 130
+#define NMA$C_PCNO_SDU 131
+#define NMA$C_PCNO_DAD 135
+#define NMA$C_PCNO_DCT 136
+#define NMA$C_PCNO_OHO 140
+#define NMA$C_PCNO_IHO 141
+#define NMA$C_PCNO_LPC 150
+#define NMA$C_PCNO_LPL 151
+#define NMA$C_PCNO_LPD 152
+#define NMA$C_PCNO_LPA 153
+#define NMA$C_PCNO_LPH 154
+#define NMA$C_PCNO_LPN 155
+#define NMA$C_PCNO_LAN 156
+#define NMA$C_PCNO_CTI 160
+#define NMA$C_PCNO_NNA 500
+#define NMA$C_PCNO_NLI 501
+#define NMA$C_PCNO_ADD 502
+#define NMA$C_PCNO_ITI 510
+#define NMA$C_PCNO_OTI 511
+#define NMA$C_PCNO_IPR 522
+#define NMA$C_PCNO_OPR 523
+#define NMA$C_PCNO_ACL 600
+#define NMA$C_PCNO_DEL 601
+#define NMA$C_PCNO_NVE 700
+#define NMA$C_PCNO_MLK 710
+#define NMA$C_PCNO_DFA 720
+#define NMA$C_PCNO_DWE 721
+#define NMA$C_PCNO_IAT 722
+#define NMA$C_PCNO_RFA 723
+#define NMA$C_PCNO_DTY 810
+#define NMA$C_PCNO_DCO 820
+#define NMA$C_PCNO_DHO 821
+#define NMA$C_PCNO_DLI 822
+#define NMA$C_PCNO_NND 830
+#define NMA$C_PCNO_RVE 900
+#define NMA$C_PCNO_ETY 901
+#define NMA$C_PCNO_RTI 910
+#define NMA$C_PCNO_SAD 911
+#define NMA$C_PCNO_BRT 912
+#define NMA$C_PCNO_MAD 920
+#define NMA$C_PCNO_MLN 921
+#define NMA$C_PCNO_MCO 922
+#define NMA$C_PCNO_MHO 923
+#define NMA$C_PCNO_MVI 924
+#define NMA$C_PCNO_MAR 925
+#define NMA$C_PCNO_MBE 926
+#define NMA$C_PCNO_MBR 927
+#define NMA$C_PCNO_AMC 928
+#define NMA$C_PCNO_AMH 929
+#define NMA$C_PCNO_MBU 930
+#define NMA$C_PCNO_BUS 931
+#define NMA$C_PCNO_SBS 932
+#define NMA$C_PCNO_MPS 933
+#define NMA$C_PCNO_FBS 933
+#define NMA$C_PCNO_RSX_RPA 2300
+#define NMA$C_PCNO_RSX_TPA 2301
+#define NMA$C_PCNO_RSX_VER 2310
+#define NMA$C_PCNO_PUS 2704
+#define NMA$C_PCNO_PAC 2705
+#define NMA$C_PCNO_PPW 2706
+#define NMA$C_PCNO_NUS 2712
+#define NMA$C_PCNO_NAC 2713
+#define NMA$C_PCNO_NPW 2714
+#define NMA$C_PCNO_RPA 2720
+#define NMA$C_PCNO_TPA 2721
+#define NMA$C_PCNO_ACC 2730
+#define NMA$C_PCNO_DAC 2731
+#define NMA$C_PCNO_PIQ 2740
+#define NMA$C_PCNO_ALI 2742
+#define NMA$C_PCNO_ALM 2743
+#define NMA$C_PCNO_ALN 2744
+#define NMA$C_PCNO_PRX 2750
+#define NMA$C_PCNO_DPX 2751
+#define NMA$C_PCNO_COP 2760
+#define NMA$C_PCNO_INB 2765
+#define NMA$C_PCNO_LAA 2770
+#define NMA$C_PCNO_LAP 2771
+#define NMA$C_PCNO_PSP 2780
+#define NMA$C_PCNO_MDO 2785
+#define NMA$C_PCNO_SRV_RPA 3300
+#define NMA$C_PCNO_SRV_TPA 3301
+#define NMA$C_PCNO_SRV_VER 3310
+#define NMA$C_PCNO_SRV_ACB 3402
+#define NMA$C_PCNO_SRV_ASB 3404
+#define NMA$C_PCNO_SRV_ALB 3406
+#define NMA$C_PCNO_SRV_MCB 3410
+#define NMA$C_PCNO_SRV_MSB 3420
+#define NMA$C_PCNO_SRV_MLB 3430
+#define NMA$C_PCNO_SRV_LBS 3431
+#define NMA$C_PCNO_SRV_NRB 3440
+#define NMA$C_PCNO_SRV_CPT 3450
+#define NMA$C_PCNO_SRV_CPF 3452
+#define NMA$C_PCNO_SRV_CPL 3454
+#define NMA$C_PCNO_SRV_XPT 3460
+#define NMA$C_PCNO_SRV_XPF 3462
+#define NMA$C_PCNO_SRV_XPL 3464
+#define NMA$C_PCAR_STA 0
+#define NMA$C_PCAR_COS 820
+#define NMA$C_PCAR_HOP 821
+#define NMA$C_PCAR_CIR 822
+#define NMA$C_PCAR_NND 830
+#define NMA$C_PCOB_OAN 400
+#define NMA$C_PCOB_OAC 410
+#define NMA$C_PCOB_ONA 500
+#define NMA$C_PCOB_OCO 510
+#define NMA$C_PCOB_OUS 511
+#define NMA$C_PCOB_OVE 520
+#define NMA$C_PCOB_NAM 500
+#define NMA$C_PCOB_NUM 513
+#define NMA$C_PCOB_FID 530
+#define NMA$C_PCOB_PID 535
+#define NMA$C_PCOB_PRV 540
+#define NMA$C_PCOB_USR 550
+#define NMA$C_PCOB_ACC 551
+#define NMA$C_PCOB_PSW 552
+#define NMA$C_PCOB_PRX 560
+#define NMA$C_PCOB_ALO 565
+#define NMA$C_PCOB_ALI 566
+#define NMA$C_PCLK_STA 0
+#define NMA$C_PCLK_PID 101
+#define NMA$C_PCLK_NID 102
+#define NMA$C_PCLK_LAD 105
+#define NMA$C_PCLK_DLY 110
+#define NMA$C_PCLK_RLN 120
+#define NMA$C_PCLK_RID 121
+#define NMA$C_PCLK_USR 130
+#define NMA$C_PCLK_PRC 131
+#define NMA$C_CTCIR_ZER 0
+#define NMA$C_CTCIR_APR 800
+#define NMA$C_CTCIR_DPS 801
+#define NMA$C_CTCIR_ACL 802
+#define NMA$C_CTCIR_CRL 805
+#define NMA$C_CTCIR_TPR 810
+#define NMA$C_CTCIR_TPS 811
+#define NMA$C_CTCIR_TCL 812
+#define NMA$C_CTCIR_LDN 820
+#define NMA$C_CTCIR_IFL 821
+#define NMA$C_CTCIR_AJD 822
+#define NMA$C_CTCIR_PAJ 900
+#define NMA$C_CTCIR_BRC 1000
+#define NMA$C_CTCIR_BSN 1001
+#define NMA$C_CTCIR_MBY 1002
+#define NMA$C_CTCIR_DBR 1010
+#define NMA$C_CTCIR_DBS 1011
+#define NMA$C_CTCIR_DEI 1020
+#define NMA$C_CTCIR_DEO 1021
+#define NMA$C_CTCIR_RRT 1030
+#define NMA$C_CTCIR_LRT 1031
+#define NMA$C_CTCIR_RBE 1040
+#define NMA$C_CTCIR_LBE 1041
+#define NMA$C_CTCIR_SIE 1050
+#define NMA$C_CTCIR_SLT 1051
+#define NMA$C_CTCIR_UBU 1065
+#define NMA$C_CTCIR_RPE 1100
+#define NMA$C_CTCIR_LPE 1101
+#define NMA$C_CTCIR_LIR 1240
+#define NMA$C_CTCIR_RIR 1241
+#define NMA$C_CTCIR_NIR 1242
+#define NMA$C_CTCIR_MNE 2701
+#define NMA$C_CTCIR_ERI 2750
+#define NMA$C_CTCIR_ERO 2751
+#define NMA$C_CTCIR_RTO 2752
+#define NMA$C_CTCIR_LTO 2753
+#define NMA$C_CTCIR_BER 2754
+#define NMA$C_CTCIR_BEL 2755
+#define NMA$C_CTLIN_ZER 0
+#define NMA$C_CTLIN_APR 800
+#define NMA$C_CTLIN_DPS 801
+#define NMA$C_CTLIN_ACL 802
+#define NMA$C_CTLIN_TPR 810
+#define NMA$C_CTLIN_TPS 811
+#define NMA$C_CTLIN_TCL 812
+#define NMA$C_CTLIN_LDN 820
+#define NMA$C_CTLIN_IFL 821
+#define NMA$C_CTLIN_BRC 1000
+#define NMA$C_CTLIN_BSN 1001
+#define NMA$C_CTLIN_MBY 1002
+#define NMA$C_CTLIN_DBR 1010
+#define NMA$C_CTLIN_DBS 1011
+#define NMA$C_CTLIN_MBL 1012
+#define NMA$C_CTLIN_BID 1013
+#define NMA$C_CTLIN_BS1 1014
+#define NMA$C_CTLIN_BSM 1015
+#define NMA$C_CTLIN_DEI 1020
+#define NMA$C_CTLIN_DEO 1021
+#define NMA$C_CTLIN_RRT 1030
+#define NMA$C_CTLIN_LRT 1031
+#define NMA$C_CTLIN_RBE 1040
+#define NMA$C_CTLIN_LBE 1041
+#define NMA$C_CTLIN_SIE 1050
+#define NMA$C_CTLIN_SLT 1051
+#define NMA$C_CTLIN_SFL 1060
+#define NMA$C_CTLIN_CDC 1061
+#define NMA$C_CTLIN_RFL 1062
+#define NMA$C_CTLIN_UFD 1063
+#define NMA$C_CTLIN_OVR 1064
+#define NMA$C_CTLIN_SBU 1065
+#define NMA$C_CTLIN_UBU 1066
+#define NMA$C_CTLIN_RPE 1100
+#define NMA$C_CTLIN_LPE 1101
+#define NMA$W_NODE 0
+#define NMA$S_ADDR 10
+#define NMA$V_ADDR 0
+#define NMA$S_AREA 6
+#define NMA$V_AREA 10
+#define NMA$S_PTY_TYP 15
+#define NMA$V_PTY_TYP 0
+#define NMA$S_PTY_CLE 6
+#define NMA$V_PTY_CLE 0
+#define NMA$V_PTY_MUL 6
+#define NMA$V_PTY_COD 7
+#define NMA$S_PTY_CMU 2
+#define NMA$V_PTY_CMU 6
+#define NMA$S_PTY_NLE 4
+#define NMA$V_PTY_NLE 0
+#define NMA$S_PTY_NTY 2
+#define NMA$V_PTY_NTY 4
+#define NMA$V_PTY_ASC 6
+#define NMA$M_CTLIN_BTL 8
+#define NMA$M_CTLIN_FCS 16
+#define NMA$M_CTLIN_TRJ 32
+#define NMA$V_CTLIN_BTL 3
+#define NMA$V_CTLIN_FCS 4
+#define NMA$V_CTLIN_TRJ 5
+#define NMA$M_CTLIN_RRJ 8
+#define NMA$V_CTLIN_RRJ 3
+#define NMA$M_CTLIN_RRN 4
+#define NMA$V_CTLIN_RRN 2
+#define NMA$M_CTLIN_TRN 4
+#define NMA$V_CTLIN_TRN 2
+#define NMA$M_CTLIN_INR 16
+#define NMA$M_CTLIN_FMS 32
+#define NMA$V_CTLIN_INR 4
+#define NMA$V_CTLIN_FMS 5
+#define NMA$M_CTLIN_TUN 4
+#define NMA$M_CTLIN_RUN 16
+#define NMA$M_CTLIN_FMR 32
+#define NMA$C_CTLIN_MBS 2701
+#define NMA$C_CTLIN_MSN 2702
+#define NMA$C_CTLIN_RME 2750
+#define NMA$C_CTLIN_LCE 2751
+#define NMA$C_CTLIN_MSE 2752
+#define NMA$C_CTNOD_ZER 0
+#define NMA$C_CTNOD_BRC 600
+#define NMA$C_CTNOD_BSN 601
+#define NMA$C_CTNOD_MRC 610
+#define NMA$C_CTNOD_MSN 611
+#define NMA$C_CTNOD_CRC 620
+#define NMA$C_CTNOD_CSN 621
+#define NMA$C_CTNOD_RTO 630
+#define NMA$C_CTNOD_RSE 640
+#define NMA$C_CTNOD_BUN 650
+#define NMA$C_CTNOD_MLL 700
+#define NMA$C_CTNOD_APL 900
+#define NMA$C_CTNOD_NUL 901
+#define NMA$C_CTNOD_NOL 902
+#define NMA$C_CTNOD_OPL 903
+#define NMA$C_CTNOD_PFE 910
+#define NMA$C_CTNOD_RUL 920
+#define NMA$C_CTNOD_VER 930
+#define NMA$C_CTNOD_SRV_SYC 3310
+#define NMA$C_CTNOD_SRV_SYS 3320
+#define NMA$C_CTNOD_SRV_SYL 3330
+#define NMA$C_CTNOD_SRV_SYR 3340
+#define NMA$C_CTXP_ZER 0
+#define NMA$C_CTXP_BRC 1000
+#define NMA$C_CTXP_BSN 1001
+#define NMA$C_CTXP_BLR 1010
+#define NMA$C_CTXP_BLS 1011
+#define NMA$C_CTXP_CRC 1200
+#define NMA$C_CTXP_CSN 1201
+#define NMA$C_CTXP_FSR 1210
+#define NMA$C_CTXP_FSS 1211
+#define NMA$C_CTXP_MSA 1220
+#define NMA$C_CTXP_MCA 1221
+#define NMA$C_CTXP_RSE 1230
+#define NMA$C_CTXP_LIR 1240
+#define NMA$C_CTXP_RIR 1241
+#define NMA$C_CTXP_NIR 1242
+#define NMA$C_CTXP_RST 1250
+#define NMA$C_CTXS_ZER 0
+#define NMA$C_CTXS_MCA 200
+#define NMA$C_CTXS_ICR 210
+#define NMA$C_CTXS_LLR 211
+#define NMA$C_LOOP_MIX 2
+#define NMA$C_LOOP_ONE 1
+#define NMA$C_LOOP_ZER 0
+#define NMA$C_LOOP_DCNT 1
+#define NMA$C_LOOP_DSIZ 40
+#define NMA$C_LOOP_XMIT 0
+#define NMA$C_LOOP_RECV 1
+#define NMA$C_LOOP_FULL 2
+#define NMA$C_STATE_ON 0
+#define NMA$C_STATE_OFF 1
+#define NMA$C_STATE_SER 2
+#define NMA$C_STATE_CLE 3
+#define NMA$C_STATE_HOL 2
+#define NMA$C_STATE_SHU 2
+#define NMA$C_STATE_RES 3
+#define NMA$C_STATE_REA 4
+#define NMA$C_STATE_UNR 5
+#define NMA$C_PCNO_DMAD 1023
+#define NMA$C_ASS_ENA 0
+#define NMA$C_ASS_DIS 1
+#define NMA$C_SUR_ENA 0
+#define NMA$C_SUR_DIS 1
+#define NMA$C_LINSS_STA 0
+#define NMA$C_LINSS_REF 1
+#define NMA$C_LINSS_LOO 2
+#define NMA$C_LINSS_LOA 3
+#define NMA$C_LINSS_DUM 4
+#define NMA$C_LINSS_TRI 5
+#define NMA$C_LINSS_ASE 6
+#define NMA$C_LINSS_ALO 7
+#define NMA$C_LINSS_ADU 8
+#define NMA$C_LINSS_ATR 9
+#define NMA$C_LINSS_SYN 10
+#define NMA$C_LINSS_FAI 11
+#define NMA$C_LINSS_RUN 12
+#define NMA$C_LINSS_UNS 13
+#define NMA$C_LINSS_IDL 14
+#define NMA$C_CIRTY_POI 0
+#define NMA$C_CIRTY_CON 1
+#define NMA$C_CIRTY_TRI 2
+#define NMA$C_CIRTY_X25 3
+#define NMA$C_CIRTY_DMC 4
+#define NMA$C_CIRTY_NI 6
+#define NMA$C_LINSV_ENA 0
+#define NMA$C_LINSV_DIS 1
+#define NMA$C_CIRPST_AUT 1
+#define NMA$C_CIRPST_ACT 2
+#define NMA$C_CIRPST_INA 3
+#define NMA$C_CIRPST_DIE 4
+#define NMA$C_CIRPST_DED 5
+#define NMA$C_CIRBLK_ENA 0
+#define NMA$C_CIRBLK_DIS 1
+#define NMA$C_CIRUS_PER 0
+#define NMA$C_CIRUS_INC 1
+#define NMA$C_CIRUS_OUT 2
+#define NMA$C_CIRHS_ENA 0
+#define NMA$C_CIRHS_DIS 1
+#define NMA$C_CIRBF_UNL 255
+#define NMA$C_CIRVE_ENA 0
+#define NMA$C_CIRVE_DIS 1
+#define NMA$C_CIRVE_INB 2
+#define NMA$C_CIRXPT_ZND 1
+#define NMA$C_CIRXPT_PH2 2
+#define NMA$C_CIRXPT_PH3 3
+#define NMA$C_CIRXPT_RO3 3
+#define NMA$C_CIRXPT_NR4 4
+#define NMA$C_DPX_FUL 0
+#define NMA$C_DPX_HAL 1
+#define NMA$C_DPX_MPT 4
+#define NMA$C_LINCN_NOR 0
+#define NMA$C_LINCN_LOO 1
+#define NMA$C_LINPR_POI 0
+#define NMA$C_LINPR_CON 1
+#define NMA$C_LINPR_TRI 2
+#define NMA$C_LINPR_DMC 4
+#define NMA$C_LINPR_LAPB 5
+#define NMA$C_LINPR_NI 6
+#define NMA$C_LINPR_BSY 9
+#define nma$c_linpr_lapbe 10
+#define nma$c_linpr_ea_hdlc 20
+#define nma$c_linpr_sdlc 21
+#define nma$c_linpr_bisync 22
+#define nma$m_linpr_mop 128
+#define nma$c_code_ascii 1
+#define nma$c_code_ebcdic 2
+#define NMA$C_LINPR_MAS 1
+#define NMA$C_LINPR_NEU 2
+#define NMA$C_LINPR_SEC 0
+#define NMA$C_LINCL_EXT 0
+#define NMA$C_LINCL_INT 1
+#define NMA$C_LINFM_802E 0
+#define NMA$C_LINFM_ETH 1
+#define NMA$C_LINFM_802 2
+#define NMA$C_LINSR_USR 1
+#define NMA$C_LINSR_CLI 2
+#define NMA$C_LINSWI_DIS 1
+#define NMA$C_LINSWI_ENA 0
+#define NMA$C_LINHNG_DIS 1
+#define NMA$C_LINHNG_ENA 0
+#define NMA$C_LINRES_DIS 1
+#define NMA$C_LINRES_ENA 0
+#define NMA$C_LINTY_POI 0
+#define NMA$C_LINTY_CON 1
+#define NMA$C_LINTY_TRI 2
+#define NMA$C_LINTY_DMC 3
+#define NMA$C_LINMC_SET 1
+#define NMA$C_LINMC_CLR 2
+#define NMA$C_LINMC_CAL 3
+#define NMA$C_LINMC_SDF 4
+#define NMA$C_ACC_SHR 1
+#define NMA$C_ACC_LIM 2
+#define NMA$C_ACC_EXC 3
+#define NMA$C_LINMO_AUT 1
+#define NMA$C_LINMO_SIL 2
+#define NMA$C_X25MD_DTE 1
+#define NMA$C_X25MD_DCE 2
+#define NMA$C_X25MD_DTL 3
+#define NMA$C_X25MD_DCL 4
+#define nma$c_x25md_neg 5
+#define nma$c_x25red_busy 0
+#define nma$c_x25red_out_of_order 1
+#define nma$c_x25red_systematic 2
+#define NMA$C_NODTY_ROU 0
+#define NMA$C_NODTY_NON 1
+#define NMA$C_NODTY_PHA 2
+#define NMA$C_NODTY_AREA 3
+#define NMA$C_NODTY_RT4 4
+#define NMA$C_NODTY_NR4 5
+#define NMA$C_NODINB_ROUT 1
+#define NMA$C_NODINB_ENDN 2
+#define NMA$C_NODPW_SET 0
+#define NMA$C_CPU_8 0
+#define NMA$C_CPU_11 1
+#define NMA$C_CPU_1020 2
+#define NMA$C_CPU_VAX 3
+#define NMA$C_NODSNV_PH3 0
+#define NMA$C_NODSNV_PH4 1
+#define NMA$C_SOFT_SECL 0
+#define NMA$C_SOFT_TERL 1
+#define NMA$C_SOFT_OSYS 2
+#define NMA$C_SOFT_DIAG 3
+#define NMA$C_ACES_NONE 0
+#define NMA$C_ACES_INCO 1
+#define NMA$C_ACES_OUTG 2
+#define NMA$C_ACES_BOTH 3
+#define NMA$C_ACES_REQU 4
+#define NMA$C_ALIINC_ENA 0
+#define NMA$C_ALIINC_DIS 1
+#define NMA$C_ALOUT_ENA 0
+#define NMA$C_ALOUT_DIS 1
+#define NMA$C_ALINC_ENA 0
+#define NMA$C_ALINC_DIS 1
+#define NMA$C_PRXY_ENA 0
+#define NMA$C_PRXY_DIS 1
+#define NMA$C_PSPCY_NOR 0
+#define NMA$C_PSPCY_INT 1
+#define NMA$C_XPRTY_BIL 1
+#define NMA$C_XPRST_ON 0
+#define NMA$C_XPRST_OFF 1
+#define NMA$C_XPRST_SHU 2
+#define NMA$C_XPRMN_ENA 0
+#define NMA$C_XPRMN_DIS 1
+#define NMA$C_XPRSB_RUN 12
+#define NMA$C_XPRSB_UNS 13
+#define NMA$C_XPRSB_SYN 10
+#define NMA$C_Clear_String 0
+#define NMA$C_Clear_Longword -1
+#define NMA$C_CAL_CLR 0
+#define NMA$C_CAL_NOW 1
+#define NMA$C_DAY_ALL 0
+#define NMA$C_DAY_MON 1
+#define NMA$C_DAY_TUE 2
+#define NMA$C_DAY_WED 3
+#define NMA$C_DAY_THU 4
+#define NMA$C_DAY_FRI 5
+#define NMA$C_DAY_SAT 6
+#define NMA$C_DAY_SUN 7
+#define NMA$C_TIC_No_Cut 0
+#define NMA$C_TIC_Cut 1
+#define NMA$C_CSG_No_Signal 0
+#define NMA$c_CSG_Signal 1
+#define NMA$c_IRC_DIS 0
+#define NMA$c_IRC_ENA 1
+#define NMA$c_ORC_DIS 0
+#define NMA$c_ORC_ENA 1
+#define NMA$c_RED_DIS 0
+#define NMA$c_RED_ENA 1
+#define NMA$c_MOD_NOAUTO 0
+#define NMA$c_MOD_AUTO 1
+#define NMA$c_SWC_DIS 0
+#define NMA$c_SWC_ENA 1
+#define NMA$c_MDM_OFF 0
+#define NMA$c_MDM_ON 1
+#define NMA$c_DTS_NO_CABLE 1
+#define NMA$c_DTS_NO_X21_CABLE 2
+#define NMA$c_DTS_READY 3
+#define NMA$c_DTS_NOT_READY 4
+#define NMA$c_DTS_ACTIVE 5
+#define NMA$c_DTS_NO_OUTGOING 6
+#define NMA$c_CAS_NONE 1
+#define NMA$c_CAS_OUT 2
+#define NMA$c_CAS_IN 3
+#define NMA$c_CAS_OUT_R 4
+#define NMA$c_CAS_IN_R 5
+#define NMA$c_DTL_ACCEPT 1
+#define NMA$c_DTL_REJECT 2
+#define NMA$C_CAC_MAN 1
+#define NMA$C_CAC_AUTO_CONNECT 2
+#define NMA$C_CAC_AUTO_ACCEPT 3
+#define NMA$C_JAN 1
+#define NMA$C_FEB 2
+#define NMA$C_MAR 3
+#define NMA$C_APR 4
+#define NMA$C_MAY 5
+#define NMA$C_JUN 6
+#define NMA$C_JUL 7
+#define NMA$C_AUG 8
+#define NMA$C_SEP 9
+#define NMA$C_OCT 10
+#define NMA$C_NOV 11
+#define NMA$C_DEC 12
+#define NMA$C_SOFD_DP 0
+#define NMA$C_SOFD_UNA 1
+#define NMA$C_SOFD_DU 2
+#define NMA$C_SOFD_CNA 3
+#define NMA$C_SOFD_DL 4
+#define NMA$C_SOFD_QNA 5
+#define NMA$C_SOFD_DQ 6
+#define NMA$C_SOFD_CI 7
+#define NMA$C_SOFD_DA 8
+#define NMA$C_SOFD_PCL 9
+#define NMA$C_SOFD_DUP 10
+#define NMA$C_SOFD_LUA 11
+#define NMA$C_SOFD_DMC 12
+#define NMA$C_SOFD_LNA 13
+#define NMA$C_SOFD_DN 14
+#define NMA$C_SOFD_DLV 16
+#define NMA$C_SOFD_LCS 17
+#define NMA$C_SOFD_DMP 18
+#define NMA$C_SOFD_AMB 19
+#define NMA$C_SOFD_DTE 20
+#define NMA$C_SOFD_DBT 21
+#define NMA$C_SOFD_DV 22
+#define NMA$C_SOFD_BNA 23
+#define NMA$C_SOFD_BNT 23
+#define NMA$C_SOFD_DZ 24
+#define NMA$C_SOFD_LPC 25
+#define NMA$C_SOFD_DSV 26
+#define NMA$C_SOFD_CEC 27
+#define NMA$C_SOFD_KDP 28
+#define NMA$C_SOFD_IEC 29
+#define NMA$C_SOFD_KDZ 30
+#define NMA$C_SOFD_UEC 31
+#define NMA$C_SOFD_KL8 32
+#define NMA$C_SOFD_DS2 33
+#define NMA$C_SOFD_DMV 34
+#define NMA$C_SOFD_DS5 35
+#define NMA$C_SOFD_DPV 36
+#define NMA$C_SOFD_LQA 37
+#define NMA$C_SOFD_DMF 38
+#define NMA$C_SOFD_SVA 39
+#define NMA$C_SOFD_DMR 40
+#define NMA$C_SOFD_MUX 41
+#define NMA$C_SOFD_KMY 42
+#define NMA$C_SOFD_DEP 43
+#define NMA$C_SOFD_KMX 44
+#define NMA$C_SOFD_LTM 45
+#define NMA$C_SOFD_DMB 46
+#define NMA$C_SOFD_DES 47
+#define NMA$C_SOFD_KCP 48
+#define NMA$C_SOFD_MX3 49
+#define NMA$C_SOFD_SYN 50
+#define NMA$C_SOFD_MEB 51
+#define NMA$C_SOFD_DSB 52
+#define NMA$C_SOFD_BAM 53
+#define NMA$C_SOFD_DST 54
+#define NMA$C_SOFD_FAT 55
+#define NMA$C_SOFD_RSM 56
+#define NMA$C_SOFD_RES 57
+#define NMA$C_SOFD_3C2 58
+#define NMA$C_SOFD_3CM 59
+#define NMA$C_SOFD_DS3 60
+#define NMA$C_SOFD_MF2 61
+#define NMA$C_SOFD_MMR 62
+#define NMA$C_SOFD_VIT 63
+#define NMA$C_SOFD_VT5 64
+#define NMA$C_SOFD_BNI 65
+#define NMA$C_SOFD_MNA 66
+#define NMA$C_SOFD_PMX 67
+#define NMA$C_SOFD_NI5 68
+#define NMA$C_SOFD_NI9 69
+#define NMA$C_SOFD_KMK 70
+#define NMA$C_SOFD_3CP 71
+#define NMA$C_SOFD_DP2 72
+#define NMA$C_SOFD_ISA 73
+#define NMA$C_SOFD_DIV 74
+#define NMA$C_SOFD_QTA 75
+#define NMA$_SUCCESS 1
+#define NMA$_SUCCFLDRPL 9
+#define NMA$_BADFID 0
+#define NMA$_BADDAT 8
+#define NMA$_BADOPR 16
+#define NMA$_BUFTOOSMALL 24
+#define NMA$_FLDNOTFND 32
+#define NMA$C_OPN_MIN 0
+#define NMA$C_OPN_NODE 0
+#define NMA$C_OPN_LINE 1
+#define NMA$C_OPN_LOG 2
+#define NMA$C_OPN_OBJ 3
+#define NMA$C_OPN_CIR 4
+#define NMA$C_OPN_X25 5
+#define NMA$C_OPN_X29 6
+#define NMA$C_OPN_CNF 7
+#define NMA$C_OPN_MAX 7
+#define NMA$C_OPN_ALL 127
+#define NMA$C_OPN_AC_RO 0
+#define NMA$C_OPN_AC_RW 1
+#define NMA$C_FN2_DLL 2
+#define NMA$C_FN2_ULD 3
+#define NMA$C_FN2_TRI 4
+#define NMA$C_FN2_LOO 5
+#define NMA$C_FN2_TES 6
+#define NMA$C_FN2_SET 7
+#define NMA$C_FN2_REA 8
+#define NMA$C_FN2_ZER 9
+#define NMA$C_FN2_LNS 14
+#define NMA$C_OP2_CHNST 5
+#define NMA$C_OP2_CHLST 8
+#define NMA$C_OP2_RENCT 0
+#define NMA$C_OP2_RENST 1
+#define NMA$C_OP2_RELCT 4
+#define NMA$C_OP2_RELST 5
+#define NMA$C_OP2_ZENCT 0
+#define NMA$C_OP2_ZELCT 2
+#define NMA$C_EN2_KNO 0
+#define NMA$C_EN2_LID 1
+#define NMA$C_EN2_LCN 2
+#define NMA$C_STS_SUC 1
+#define NMA$C_STS_MOR 2
+#define NMA$C_STS_PAR 3
+#define NMA$C_STS_DON -128
+#define NMA$C_STS_FUN -1
+#define NMA$C_STS_INV -2
+#define NMA$C_STS_PRI -3
+#define NMA$C_STS_SIZ -4
+#define NMA$C_STS_MPR -5
+#define NMA$C_STS_PTY -6
+#define NMA$C_STS_MVE -7
+#define NMA$C_STS_CMP -8
+#define NMA$C_STS_IDE -9
+#define NMA$C_STS_LCO -10
+#define NMA$C_STS_STA -11
+#define NMA$C_STS_FOP -13
+#define NMA$C_STS_FCO -14
+#define NMA$C_STS_RES -15
+#define NMA$C_STS_PVA -16
+#define NMA$C_STS_LPR -17
+#define NMA$C_STS_FIO -18
+#define NMA$C_STS_MLD -19
+#define NMA$C_STS_ROO -20
+#define NMA$C_STS_MCF -21
+#define NMA$C_STS_PNA -22
+#define NMA$C_STS_PLO -23
+#define NMA$C_STS_HAR -24
+#define NMA$C_STS_OPE -25
+#define NMA$C_STS_SYS -26
+#define NMA$C_STS_PGP -27
+#define NMA$C_STS_BLR -28
+#define NMA$C_STS_PMS -29
+#define NMA$C_STS_ALI -127
+#define NMA$C_STS_OBJ -126
+#define NMA$C_STS_PRO -125
+#define NMA$C_STS_LNK -124
+#define NMA$C_FOPDTL_PDB 0
+#define NMA$C_FOPDTL_LFL 1
+#define NMA$C_FOPDTL_DFL 2
+#define NMA$C_FOPDTL_SLF 3
+#define NMA$C_FOPDTL_TLF 4
+#define NMA$C_FOPDTL_SDF 5
+#define NMA$C_FOPDTL_PDR 6
+#define NMA$C_FOPDTL_MFL 7
+#define NMA$C_NCEDTL_NNA 0
+#define NMA$C_NCEDTL_INN 1
+#define NMA$C_NCEDTL_UNA 2
+#define NMA$C_NCEDTL_UNR 3
+#define NMA$C_NCEDTL_RSC 4
+#define NMA$C_NCEDTL_RJC 5
+#define NMA$C_NCEDTL_ONA 6
+#define NMA$C_NCEDTL_OBJ 7
+#define NMA$C_NCEDTL_ACC 8
+#define NMA$C_NCEDTL_BSY 9
+#define NMA$C_NCEDTL_NRS 10
+#define NMA$C_NCEDTL_NSD 11
+#define NMA$C_NCEDTL_DIE 12
+#define NMA$C_NCEDTL_DIS 13
+#define NMA$C_NCEDTL_ABO 14
+#define NMA$C_NCEDTL_ABM 15
+#define NMA$C_OPEDTL_DCH 0
+#define NMA$C_OPEDTL_TIM 1
+#define NMA$C_OPEDTL_ORN 2
+#define NMA$C_OPEDTL_ACT 3
+#define NMA$C_OPEDTL_BAF 4
+#define NMA$C_OPEDTL_RUN 5
+#define NMA$C_OPEDTL_DSC 6
+#define NMA$C_OPEDTL_FTL 8
+#define NMA$C_OPEDTL_MNT 11
+#define NMA$C_OPEDTL_LST 12
+#define NMA$C_OPEDTL_THR 13
+#define NMA$C_OPEDTL_TRB 14
+#define NMA$C_OPEDTL_STA 15
+#define NMA$V_CTLIN_TUN 2
+#define NMA$V_CTLIN_RUN 4
+#define NMA$V_CTLIN_FMR 5
diff --git a/sr_vvms/ntd_root.c b/sr_vvms/ntd_root.c
new file mode 100644
index 0000000..efdb101
--- /dev/null
+++ b/sr_vvms/ntd_root.c
@@ -0,0 +1,15 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+GBLDEF struct NTD *ntd_root;
+
diff --git a/sr_vvms/obj_code.c b/sr_vvms/obj_code.c
new file mode 100644
index 0000000..0d586e1
--- /dev/null
+++ b/sr_vvms/obj_code.c
@@ -0,0 +1,213 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_fcntl.h"
+#include "gtm_stdio.h"
+#include <errno.h>
+#include <sys/types.h>
+#include "gtm_stat.h"
+#include "gtm_unistd.h"
+
+#include "compiler.h"
+#include "obj_gen.h"
+#include <rtnhdr.h>
+#include "cmd_qlf.h"
+#include "cgp.h"
+#include "mmemory.h"
+#include "obj_file.h"
+#include "alloc_reg.h"
+#include "jmp_opto.h"
+#include "mlabel2xtern.h"
+#include "cg_var.h"
+#include "gtm_string.h"
+#include "stringpool.h"
+
+GBLREF boolean_t run_time;
+GBLREF command_qualifier cmd_qlf;
+GBLREF int4 mvmax, mlmax, mlitmax, psect_use_tab[], sa_temps[], sa_temps_offset[];
+GBLREF mlabel *mlabtab;
+GBLREF mline mline_root;
+GBLREF mvar *mvartab;
+GBLREF mident module_name;
+GBLREF spdesc stringpool;
+GBLREF int4 curr_addr, code_size;
+GBLREF char cg_phase; /* code generation phase */
+GBLREF char cg_phase_last; /* previous code generation phase */
+
+error_def(ERR_TEXT);
+
+void cg_lab (mlabel *l, int4 base);
+
+/* The sections of the internal GT.M object are grouped according to native sections.
+ * Note: Once an object is linked, no section will be released from memory. All sections
+ * will be retained.
+ *
+ * The GT.M object layout on the disk is as follows:
+ *
+ * +---------------+
+ * | rhead | \
+ * +---------------+ \
+ * | generated | |
+ * | code | |
+ * + - - - - - - - + |
+ * | variable tbl | | - R/O (GTM$CODE psect)
+ * + - - - - - - - + |
+ * | label tbl | |
+ * +---------------+ /
+ * | line num tbl | /
+ * + - - - - - - - +
+ * | lit text pool | \
+ * +---------------+ | - R/W (GTM$LITERALS)
+ * | lit mval tbl | /
+ * +---------------+
+ * | GTM$Rxxx | > - R/W (GTM$Rxx psect)
+ * +---------------+
+ * | symbol tbl | > - External symbol table
+ * +---------------+
+ *
+ */
+
+void obj_code (uint4 src_lines, uint4 checksum)
+{
+ rhdtyp rhead;
+ mline *mlx, *mly;
+ var_tabent *vptr;
+ mstr rname_mstr;
+ int4 mv, lnr_pad_len;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ assert(!run_time);
+ obj_init();
+
+ /* Define the routine name global symbol. */
+ rname_mstr.addr = module_name.addr;
+ rname_mstr.len = module_name.len;
+ define_symbol(GTM_MODULE_DEF_PSECT, &rname_mstr, 0);
+ memset(&rhead, 0, SIZEOF(rhead));
+ alloc_reg();
+ jmp_opto();
+ curr_addr = SIZEOF(rhdtyp);
+ cg_phase = CGP_APPROX_ADDR;
+ cg_phase_last = CGP_NOSTATE;
+ code_gen();
+ code_size = curr_addr;
+ cg_phase = CGP_ADDR_OPT;
+ comp_lits(&rhead);
+ shrink_trips();
+ if ((cmd_qlf.qlf & CQ_MACHINE_CODE))
+ {
+ cg_phase = CGP_ASSEMBLY;
+ code_gen();
+ }
+ if (!(cmd_qlf.qlf & CQ_OBJECT))
+ return;
+ rhead.ptext_ptr = SIZEOF(rhead);
+ rhead.checksum = checksum;
+ rhead.vartab_ptr = code_size;
+ rhead.vartab_len = mvmax;
+ code_size += mvmax * SIZEOF(var_tabent);
+ rhead.labtab_ptr = code_size;
+ rhead.labtab_len = mlmax;
+ code_size += mlmax * SIZEOF(lab_tabent);
+ rhead.lnrtab_ptr = code_size;
+ rhead.lnrtab_len = src_lines;
+ rhead.compiler_qlf = cmd_qlf.qlf;
+ rhead.temp_mvals = sa_temps[TVAL_REF];
+ rhead.temp_size = sa_temps_offset[TCAD_REF];
+ code_size += src_lines * SIZEOF(int4);
+ lnr_pad_len = PADLEN(code_size, SECTION_ALIGN_BOUNDARY);
+ code_size += lnr_pad_len;
+ create_object_file(&rhead);
+ cg_phase = CGP_MACHINE;
+ code_gen();
+ /* Variable table: */
+ vptr = (var_tabent *)mcalloc(mvmax * SIZEOF(var_tabent));
+ if (mvartab)
+ walktree(mvartab, cg_var, (char *)&vptr);
+ else
+ assert(0 == mvmax);
+ /* Although entire vartab is available, we cannot emit the table in one chunk using emit_immed()
+ * since var_name.addr of each entry needs relocation and should be emitted using emit_pidr()
+ * strictly in that order to maintain proper relocation base for fixup generation.
+ */
+ for (mv = 0; mv < mvmax; mv++)
+ {
+ emit_immed((char *)&vptr[mv], ((char *)&vptr[mv].var_name.addr - (char *)&vptr[mv]));
+ emit_pidr((int4)vptr[mv].var_name.addr, GTM_LITERALS);
+ emit_immed(&vptr[mv].hash_code, SIZEOF(vptr[mv].hash_code));
+ emit_immed(&vptr[mv].marked, SIZEOF(vptr[mv].marked));
+ }
+ /* Label table: */
+ if (mlabtab)
+ {
+ TREF(lbl_tbl_entry_index) = -1; /* this is incremented by 1 each time a label is emitted */
+ walktree((mvar *)mlabtab, cg_lab, (char *)&rhead);
+ } else
+ assert(0 == mlmax);
+ /* External entry definitions: */
+ emit_immed((char *)&(mline_root.externalentry->rtaddr), SIZEOF(mline_root.externalentry->rtaddr)); /* line 0 */
+ for (mlx = mline_root.child ; mlx ; mlx = mly)
+ {
+ if (mlx->table)
+ emit_immed((char *)&(mlx->externalentry->rtaddr), SIZEOF(mlx->externalentry->rtaddr));
+ if (0 == (mly = mlx->child)) /* note the assignment */
+ if (0 == (mly = mlx->sibling)) /* note the assignment */
+ for (mly = mlx; ; )
+ {
+ if (0 == (mly = mly->parent)) /* note the assignment */
+ break;
+ if (mly->sibling)
+ {
+ mly = mly->sibling;
+ break;
+ }
+ }
+ }
+ if (0 != lnr_pad_len) /* emit padding so literal text pool starts on proper boundary */
+ emit_immed(PADCHARS, lnr_pad_len);
+ emit_literals();
+ close_object_file(&rhead);
+}
+
+void cg_lab (mlabel *l, int4 base)
+{
+ mstr glob_name;
+ int4 value;
+ boolean_t has_parms;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ if (l->ml && l->gbl)
+ {
+ if (l->mvname.len)
+ { /* Non-null label: emit relocation */
+ emit_immed((char *)&l->mvname.len, SIZEOF(l->mvname.len));
+ emit_pidr((l->mvname.addr - (char *)stringpool.base), GTM_LITERALS); /* Offset into literal text pool */
+ } else
+ /* Null label: no relocation needed, emit mident as it is */
+ emit_immed((char *)&l->mvname, SIZEOF(l->mvname));
+ value = (SIZEOF(int4) * l->ml->line_number) + ((rhdtyp *)base)->lnrtab_ptr;
+ emit_immed((char *)&value, SIZEOF(value));
+ has_parms = (NO_FORMALLIST != l->formalcnt); /* Flag to indicate a formallist */
+ emit_immed((char *)&has_parms, SIZEOF(has_parms));
+ mlabel2xtern(&glob_name, &module_name, &l->mvname);
+ (TREF(lbl_tbl_entry_index))++; /* Find out the index of this label in the label table */
+ /* Define this symbol by calculating the offset of lab_ln_ptr field of the current label relatively to
+ * the routine header.
+ */
+ define_symbol(GTM_CODE, &glob_name, ((rhdtyp *)base)->labtab_ptr
+ + (SIZEOF(lab_tabent) * TREF(lbl_tbl_entry_index)) + OFFSETOF(lab_tabent, lab_ln_ptr));
+ }
+ return;
+}
diff --git a/sr_vvms/ojastread.c b/sr_vvms/ojastread.c
new file mode 100644
index 0000000..5f60f24
--- /dev/null
+++ b/sr_vvms/ojastread.c
@@ -0,0 +1,62 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <accdef.h>
+#include <stsdef.h>
+#include <iodef.h>
+#include "efn.h"
+#include "job.h"
+
+GBLREF short ojpchan;
+GBLREF int4 ojcpid;
+
+void ojastread (int expected)
+{
+ int4 status;
+ mstr stsdsc;
+ struct
+ {
+ pmsg_type msg;
+ char filler[ACC$K_TERMLEN - sizeof (pmsg_type)];
+ } stsmsg;
+ mbx_iosb iosb;
+ error_def (ERR_JOBFAIL);
+ error_def (ERR_UIDMSG);
+ error_def (ERR_UIDSND);
+
+ stsdsc.addr = &stsmsg.msg;
+ stsdsc.len = sizeof stsmsg;
+ ojmbxio (IO$_READVBLK, ojpchan, &stsdsc, &iosb, TRUE);
+ if (iosb.pid != ojcpid)
+ {
+ ojerrcleanup ();
+ rts_error(VARLSTCNT(1) ERR_UIDSND);
+ }
+ if ((iosb.byte_count != sizeof stsmsg.msg) &&
+ (iosb.byte_count != ACC$K_TERMLEN))
+ {
+ ojerrcleanup ();
+ rts_error(VARLSTCNT(1) ERR_UIDMSG);
+ }
+ if (stsmsg.msg.finalsts != expected)
+ {
+ ojerrcleanup ();
+ rts_error(VARLSTCNT(3) ERR_JOBFAIL, 0, (stsmsg.msg.finalsts & ~STS$M_INHIB_MSG));
+ }
+ status = sys$setef (efn_op_job);
+ if (!(status & 1))
+ {
+ ojerrcleanup ();
+ rts_error(VARLSTCNT(3) ERR_JOBFAIL, 0, status);
+ }
+ return;
+}
diff --git a/sr_vvms/ojch.c b/sr_vvms/ojch.c
new file mode 100644
index 0000000..95e5db0
--- /dev/null
+++ b/sr_vvms/ojch.c
@@ -0,0 +1,56 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "error.h"
+#include <iodef.h>
+#include <stsdef.h>
+#include "job.h"
+
+#define FATAL(error) (error & STS$M_COND_ID | STS$K_SEVERE)
+GBLREF pchan;
+
+error_def(ERR_ASSERT);
+error_def(ERR_GTMASSERT);
+error_def(ERR_GTMASSERT2);
+error_def(ERR_GTMCHECK);
+
+CONDITION_HANDLER(ojch)
+{
+ mstr stsdsc;
+ pmsg_type stsmsg;
+ mbx_iosb iosb;
+
+ switch(SIGNAL)
+ {
+ case SS$_ACCVIO:
+ case SS$_ASTFLT:
+ case SS$_OPCCUS:
+ case SS$_OPCDEC:
+ case SS$_PAGRDERR:
+ case SS$_RADRMOD:
+ case SS$_ROPRAND:
+ gtm_dump();
+ break;
+ default:
+ if ((SIGNAL == ERR_ASSERT) || (SIGNAL == ERR_GTMCHECK) || (SIGNAL == ERR_GTMASSERT) /* BYPASSOK */
+ || (SIGNAL == ERR_GTMASSERT))
+ gtm_dump();
+ break;
+ }
+ stsdsc.addr = &stsmsg;
+ stsdsc.len = SIZEOF(stsmsg);
+ stsmsg.unused = 0;
+ stsmsg.finalsts = SIGNAL;
+ ojmbxio(IO$_WRITEVBLK, pchan, &stsdsc, &iosb, TRUE);
+ EXIT(FATAL(SIGNAL));
+ NEXTCH;
+}
diff --git a/sr_vvms/ojchkbytcnt.c b/sr_vvms/ojchkbytcnt.c
new file mode 100644
index 0000000..5443720
--- /dev/null
+++ b/sr_vvms/ojchkbytcnt.c
@@ -0,0 +1,47 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <ssdef.h>
+#include <jpidef.h>
+#include <accdef.h>
+#include "vmsdtype.h"
+
+#define TERM_READ_MIN_BCOUNT 1036
+#define CREMBX_OVRHD 144
+
+bool ojchkbytcnt (cmaxmsg)
+int4 cmaxmsg;
+{
+ int4 preq, creq;
+ int4 status;
+ int4 bytcnt;
+ unsigned short ret;
+ int4 iosb[2];
+ struct
+ {
+ item_list_3 item[1];
+ int4 terminator;
+ } jpi_list = {4, JPI$_BYTCNT, &bytcnt, &ret, 0};
+
+ preq = CREMBX_OVRHD + ACC$K_TERMLEN;
+ creq = CREMBX_OVRHD + cmaxmsg;
+
+ status = sys$getjpi (0, 0, 0, &jpi_list, &iosb[0], 0, 0);
+ if (status != SS$_NORMAL) rts_error(VARLSTCNT(1) status);
+ sys$synch (0, &iosb[0]);
+ if (iosb[0] != SS$_NORMAL) rts_error(VARLSTCNT(1) iosb[0]);
+
+ if (bytcnt < preq + creq) return FALSE;
+ if (bytcnt - creq < TERM_READ_MIN_BCOUNT) return FALSE;
+ return TRUE;
+}
+
diff --git a/sr_vvms/ojchkfs.c b/sr_vvms/ojchkfs.c
new file mode 100644
index 0000000..e571850
--- /dev/null
+++ b/sr_vvms/ojchkfs.c
@@ -0,0 +1,47 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <rms.h>
+#include "io.h"
+#include "job.h"
+
+int4 ojchkfs (char *addr, int4 len, bool exist)
+{
+ int4 status;
+ struct FAB fab;
+ struct NAM nam;
+ char es[MAX_FILSPC_LEN];
+ mstr tn; /* translated name */
+ enum io_dev_type dev_typ;
+
+ fab = cc$rms_fab;
+ fab.fab$l_fna = addr;
+ fab.fab$b_fns = len;
+ if (exist)
+ {
+ nam = cc$rms_nam;
+ nam.nam$l_esa = &es[0];
+ nam.nam$b_ess = MAX_FILSPC_LEN;
+ fab.fab$l_nam = &nam;
+ }
+ status = sys$parse (&fab);
+ if (exist)
+ {
+ tn.addr = addr;
+ tn.len = len;
+ dev_typ = io_type(&tn);
+
+ if (dev_typ == rm)
+ status = sys$search (&fab);
+ }
+ return status;
+}
diff --git a/sr_vvms/ojcleanup.c b/sr_vvms/ojcleanup.c
new file mode 100644
index 0000000..80cadb6
--- /dev/null
+++ b/sr_vvms/ojcleanup.c
@@ -0,0 +1,60 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <ssdef.h>
+
+#include "ast.h"
+#include "job.h"
+
+GBLREF short astq_dyn_avail;
+GBLREF bool ojtimeout;
+GBLREF short ojpchan;
+GBLREF short ojcchan;
+GBLREF int4 ojcpid;
+GBLREF short ojastq;
+
+void ojcleanup(void)
+{
+ unsigned int ast_stat, status;
+
+ ast_stat = sys$setast(DISABLE);
+ if (FALSE == ojtimeout)
+ {
+ if (SS$_NORMAL != (status = sys$cantim(&(ojtimeout), 0)))
+ rts_error(VARLSTCNT(1) status);
+ ojtimeout = TRUE;
+ }
+ if (0 != ojpchan)
+ {
+ if (SS$_NORMAL != (status = sys$dassgn(ojpchan)))
+ rts_error(VARLSTCNT(1) status);
+ ojpchan = 0;
+ }
+ astq_dyn_avail += ojastq;
+ if (SS$_WASSET == ast_stat)
+ ENABLE_AST;
+ ojastq = 0;
+ if (0 != ojcchan)
+ {
+ if (SS$_NORMAL != (status = sys$dassgn(ojcchan)))
+ rts_error(VARLSTCNT(1) status);
+ ojcchan = 0;
+ }
+ if (ojcpid != 0)
+ {
+ if (SS$_NORMAL != (status = sys$delprc(ojcpid)))
+ rts_error(VARLSTCNT(1) status);
+ ojcpid = 0;
+ }
+ return;
+}
diff --git a/sr_vvms/ojcrembxs.c b/sr_vvms/ojcrembxs.c
new file mode 100644
index 0000000..16fec3d
--- /dev/null
+++ b/sr_vvms/ojcrembxs.c
@@ -0,0 +1,160 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <descrip.h>
+#include <lnmdef.h>
+#include <ssdef.h>
+#include "vmsdtype.h"
+#include <accdef.h>
+#include "job.h"
+#include "gt_timer.h"
+#include "outofband.h"
+#include "dfntmpmbx.h"
+
+GBLREF bool ojtimeout;
+GBLREF short ojpchan;
+GBLREF short ojcchan;
+GBLREF int4 outofband;
+
+static readonly mstr lnm$group = {9, "LNM$GROUP"};
+static readonly mstr lnm$process = {11, "LNM$PROCESS"};
+
+bool ojcrembxs(uint4 *punit, struct dsc$descriptor_s *cmbx, int4 cmaxmsg, bool timed)
+{
+ int4 status;
+ $DESCRIPTOR (plognam, "GTM$JOB_PMBX");
+ $DESCRIPTOR (clognam, "GTM$JOB_CMBX");
+ $DESCRIPTOR (lnmtab, "LNM$TEMPORARY_MAILBOX");
+ char pmbxnam[MAX_MBXNAM_LEN];
+ short pmbxnamsz;
+ struct
+ {
+ item_list_3 le[1];
+ int4 terminator;
+ } item_list;
+ uint4 ojmba_to_unit ();
+
+
+ status = dfntmpmbx (lnm$process.len, lnm$process.addr);
+ if (!(status & 1))
+ {
+ ojerrcleanup ();
+ rts_error(VARLSTCNT(1) status);
+ }
+ do {
+ status = sys$crembx (0, &ojpchan, ACC$K_TERMLEN, ACC$K_TERMLEN,
+ 0, 0, &plognam);
+ if (outofband)
+ { ojcleanup();
+ outofband_action(FALSE);
+ }
+ switch (status)
+ {
+ case SS$_NORMAL:
+ break;
+ case SS$_NOIOCHAN:
+ hiber_start (1000);
+ if (timed && ojtimeout)
+ {
+ status = dfntmpmbx (lnm$group.len, lnm$group.addr);
+ if (!(status & 1))
+ {
+ ojerrcleanup ();
+ rts_error(VARLSTCNT(1) status);
+ }
+ return FALSE;
+ }
+ break;
+ default:
+ dfntmpmbx (lnm$group.len, lnm$group.addr);
+ ojerrcleanup ();
+ rts_error(VARLSTCNT(1) status);
+ break;
+ }
+ } while (status != SS$_NORMAL);
+ item_list.le[0].buffer_length = MAX_MBXNAM_LEN;
+ item_list.le[0].item_code = LNM$_STRING;
+ item_list.le[0].buffer_address = &pmbxnam[0];
+ item_list.le[0].return_length_address = &pmbxnamsz;
+ item_list.terminator = 0;
+ status = sys$trnlnm (0, &lnmtab, &plognam, 0, &item_list);
+ if (!(status & 1))
+ {
+ dfntmpmbx (lnm$group.len, lnm$group.addr);
+ ojerrcleanup ();
+ rts_error(VARLSTCNT(1) status);
+ }
+ status = sys$dellnm (&lnmtab, &plognam, 0);
+ if (!(status & 1))
+ {
+ dfntmpmbx (lnm$group.len, lnm$group.addr);
+ ojerrcleanup ();
+ rts_error(VARLSTCNT(1) status);
+ }
+ *punit = ojmba_to_unit (&pmbxnam[0]);
+
+ do {
+ status = sys$crembx (0, &ojcchan, cmaxmsg, cmaxmsg,
+ 0, 0, &clognam);
+ if (outofband)
+ { ojcleanup();
+ outofband_action(FALSE);
+ }
+ switch (status)
+ {
+ case SS$_NORMAL:
+ break;
+ case SS$_NOIOCHAN:
+ hiber_start (1000);
+ if (timed && ojtimeout)
+ {
+ status = dfntmpmbx (lnm$group.len, lnm$group.addr);
+ if (!(status & 1))
+ {
+ ojerrcleanup ();
+ rts_error(VARLSTCNT(1) status);
+ }
+ return FALSE;
+ }
+ break;
+ default:
+ dfntmpmbx (lnm$group.len, lnm$group.addr);
+ ojerrcleanup ();
+ rts_error(VARLSTCNT(1) status);
+ break;
+ }
+ } while (status != SS$_NORMAL);
+ item_list.le[0].buffer_address = cmbx->dsc$a_pointer;
+ item_list.le[0].return_length_address = &(cmbx->dsc$w_length);
+ status = sys$trnlnm (0, &lnmtab, &clognam, 0, &item_list);
+ if (!(status & 1))
+ {
+ dfntmpmbx (lnm$group.len, lnm$group.addr);
+ ojerrcleanup ();
+ rts_error(VARLSTCNT(1) status);
+ }
+ status = sys$dellnm (&lnmtab, &clognam, 0);
+ if (!(status & 1))
+ {
+ dfntmpmbx (lnm$group.len, lnm$group.addr);
+ ojerrcleanup ();
+ rts_error(VARLSTCNT(1) status);
+ }
+
+ status = dfntmpmbx (lnm$group.len, lnm$group.addr);
+ if (!(status & 1))
+ {
+ ojerrcleanup ();
+ rts_error(VARLSTCNT(1) status);
+ }
+ return TRUE;
+}
diff --git a/sr_vvms/ojdefbaspri.c b/sr_vvms/ojdefbaspri.c
new file mode 100644
index 0000000..63a7cb1
--- /dev/null
+++ b/sr_vvms/ojdefbaspri.c
@@ -0,0 +1,40 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <jpidef.h>
+#include "vmsdtype.h"
+#include "efn.h"
+#include "job.h"
+
+void ojdefbaspri (int4 *baspri)
+{
+ int4 status;
+ unsigned short ret;
+ short iosb[4];
+ struct
+ {
+ item_list_3 le[1];
+ int4 terminator;
+ } item_list;
+
+ item_list.le[0].buffer_length = sizeof *baspri;
+ item_list.le[0].item_code = JPI$_PRIB;
+ item_list.le[0].buffer_address = baspri;
+ item_list.le[0].return_length_address = &ret;
+ item_list.terminator = 0;
+
+ status = sys$getjpi (0, 0, 0, &item_list, &iosb[0], 0, 0);
+ if (!(status & 1)) rts_error(VARLSTCNT(1) status);
+ sys$synch (efn_immed_wait, &iosb[0]);
+ if (!(iosb[0] & 1)) rts_error(VARLSTCNT(1) iosb[0]);
+ return;
+}
diff --git a/sr_vvms/ojdefdeffs.c b/sr_vvms/ojdefdeffs.c
new file mode 100644
index 0000000..dc16aef
--- /dev/null
+++ b/sr_vvms/ojdefdeffs.c
@@ -0,0 +1,40 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <ssdef.h>
+#include <rms.h>
+#include "job.h"
+
+static unsigned char *deffsbuf;
+
+void ojdefdeffs (mstr *deffs)
+{
+ int4 status;
+ struct FAB fab;
+ struct NAM nam;
+
+ if (!deffsbuf)
+ deffsbuf = malloc(MAX_FILSPC_LEN);
+ fab = cc$rms_fab;
+ nam = cc$rms_nam;
+ fab.fab$l_nam = &nam;
+ fab.fab$l_fna = "[]";
+ fab.fab$b_fns = 2;
+ nam.nam$l_esa = &deffsbuf[0];
+ nam.nam$b_ess = MAX_FILSPC_LEN;
+ status = sys$parse (&fab);
+ if (status != RMS$_NORMAL) rts_error(VARLSTCNT(1) status);
+
+ deffs->len = nam.nam$b_esl - 2;
+ deffs->addr = &deffsbuf[0];
+ return;
+}
diff --git a/sr_vvms/ojdefimage.c b/sr_vvms/ojdefimage.c
new file mode 100644
index 0000000..7754457
--- /dev/null
+++ b/sr_vvms/ojdefimage.c
@@ -0,0 +1,50 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <jpidef.h>
+#include "vmsdtype.h"
+#include "job.h"
+#include "efn.h"
+
+void ojdefimage (mstr *image)
+{
+ static mstr imagebuf = {0, 0};
+ int4 status;
+ unsigned char local_buff[MAX_FILSPC_LEN];
+ short iosb[4];
+ unsigned short length;
+ struct
+ {
+ item_list_3 le[1];
+ int4 terminator;
+ } item_list;
+
+ if (!imagebuf.addr)
+ {
+ item_list.le[0].buffer_length = MAX_FILSPC_LEN;
+ item_list.le[0].item_code = JPI$_IMAGNAME;
+ item_list.le[0].buffer_address = local_buff;
+ item_list.le[0].return_length_address = &length;
+ item_list.terminator = 0;
+ status = sys$getjpi (0, 0, 0, &item_list, &iosb[0], 0, 0);
+ if (!(status & 1))
+ rts_error(VARLSTCNT(1) status);
+ sys$synch (efn_immed_wait, &iosb[0]);
+ if (!(iosb[0] & 1))
+ rts_error(VARLSTCNT(1) iosb[0]);
+ imagebuf.addr = malloc(length);
+ imagebuf.len = length;
+ memcpy(imagebuf.addr, local_buff, length);
+ }
+ *image = imagebuf;
+ return;
+}
diff --git a/sr_vvms/ojdefprcnam.c b/sr_vvms/ojdefprcnam.c
new file mode 100644
index 0000000..872bbce
--- /dev/null
+++ b/sr_vvms/ojdefprcnam.c
@@ -0,0 +1,82 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2008 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <jpidef.h>
+#include <descrip.h>
+
+#include "vmsdtype.h"
+#include "job.h"
+#include "efn.h"
+#include "min_max.h"
+
+
+GBLREF mval dollar_job;
+GBLDEF char defprcnambuf[MAX_PRCNAM_LEN];
+
+static short jobcnt = 0;
+
+void ojdefprcnam (struct dsc$descriptor_s *prcnam)
+{
+ int4 status;
+ char *t;
+ unsigned short prcnamlen;
+ char username[12];
+ unsigned short ret;
+ short iosb[4];
+ struct
+ {
+ item_list_3 le[1];
+ int4 terminator;
+ } item_list;
+ $DESCRIPTOR (blank, " ");
+ $DESCRIPTOR (usrnam, &username[0]);
+ unsigned short usernamelen;
+ char pidstr[8];
+ unsigned short pidstrlen;
+ char jobcntstr[8];
+ unsigned short jobcntstrlen;
+ unsigned short ojhex_to_str ();
+
+ item_list.le[0].buffer_length = sizeof username;
+ item_list.le[0].item_code = JPI$_USERNAME;
+ item_list.le[0].buffer_address = &username[0];
+ item_list.le[0].return_length_address = &ret;
+ item_list.terminator = 0;
+
+ status = sys$getjpi (0, 0, 0, &item_list, &iosb[0], 0, 0);
+ if (!(status & 1)) rts_error(VARLSTCNT(1) status);
+ sys$synch (efn_immed_wait, &iosb[0]);
+ if (!(iosb[0] & 1)) rts_error(VARLSTCNT(1) iosb[0]);
+
+ usrnam.dsc$w_length = sizeof username;
+ if ((usernamelen = lib$locc (&blank, &usrnam)) == 0)
+ usernamelen = 13;
+
+ --usernamelen;
+ pidstrlen = ojhex_to_str ((int4) MV_FORCE_INTD(&dollar_job), &pidstr[0]);
+ jobcnt++;
+ jobcntstrlen = ojhex_to_str (jobcnt, &jobcntstr[0]);
+ usernamelen = MIN(usernamelen, MAX_PRCNAM_LEN - (1 + pidstrlen + 1 + jobcntstrlen));
+ prcnamlen = usernamelen + 1 + pidstrlen + 1 + jobcntstrlen;
+ assert (prcnamlen <= MAX_PRCNAM_LEN);
+ prcnam->dsc$w_length = prcnamlen;
+ t = prcnam->dsc$a_pointer = &defprcnambuf[0];
+ memcpy (t, &username[0], usernamelen);
+ t += usernamelen;
+ *t++ = '_';
+ memcpy (t, &pidstr[0], pidstrlen);
+ t += pidstrlen;
+ *t++ = 'J';
+ memcpy (t, &jobcntstr[0], jobcntstrlen);
+ return;
+}
diff --git a/sr_vvms/ojerrcleanup.c b/sr_vvms/ojerrcleanup.c
new file mode 100644
index 0000000..a62d93a
--- /dev/null
+++ b/sr_vvms/ojerrcleanup.c
@@ -0,0 +1,50 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "ast.h"
+#include "job.h"
+
+GBLREF short astq_dyn_avail;
+GBLREF bool ojtimeout;
+GBLREF short ojpchan;
+GBLREF short ojcchan;
+GBLREF int4 ojcpid;
+GBLREF short ojastq;
+
+void ojerrcleanup ()
+{
+ sys$setast(DISABLE);
+ if (FALSE == ojtimeout)
+ {
+ sys$cantim(&(ojtimeout), 0);
+ ojtimeout = TRUE;
+ }
+ if (0 != ojpchan)
+ {
+ sys$dassgn(ojpchan);
+ ojpchan = 0;
+ }
+ astq_dyn_avail += ojastq;
+ sys$setast(ENABLE);
+ ojastq = 0;
+ if (0 != ojcchan)
+ {
+ sys$dassgn(ojcchan);
+ ojcchan = 0;
+ }
+ if (0 != ojcpid)
+ {
+ sys$delprc(ojcpid);
+ ojcpid = 0;
+ }
+ return;
+}
diff --git a/sr_vvms/ojhex_to_str.c b/sr_vvms/ojhex_to_str.c
new file mode 100644
index 0000000..34f4813
--- /dev/null
+++ b/sr_vvms/ojhex_to_str.c
@@ -0,0 +1,33 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+unsigned short ojhex_to_str (s, t)
+uint4 s;
+char *t;
+{
+ char buf[8];
+ unsigned short i, d, len;
+
+ i = 0;
+ do {
+ d = s % 0x10;
+ s = s / 0x10;
+ buf[i++] = d + ((d <= 9) ? '0' : 'A' - 0xA);
+ } while (s > 0);
+ len = i;
+ do {
+ *t++ = buf[--i];
+ } while (i > 0);
+
+ return len;
+}
diff --git a/sr_vvms/ojmba_to_unit.c b/sr_vvms/ojmba_to_unit.c
new file mode 100644
index 0000000..0eb9caa
--- /dev/null
+++ b/sr_vvms/ojmba_to_unit.c
@@ -0,0 +1,34 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+uint4 ojmba_to_unit (src)
+char *src;
+{
+ uint4 n;
+
+ n = 0;
+ assert (*src == 'M');
+ src++;
+ assert (*src == 'B');
+ src++;
+ assert (*src == 'A');
+ src++;
+ while (('0' <= *src) && (*src <= '9'))
+ {
+ n *= 10;
+ n += (*src - '0');
+ src++;
+ }
+
+ return n;
+}
diff --git a/sr_vvms/ojmbxio.c b/sr_vvms/ojmbxio.c
new file mode 100644
index 0000000..45e08ff
--- /dev/null
+++ b/sr_vvms/ojmbxio.c
@@ -0,0 +1,39 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <iodef.h>
+#include "efn.h"
+#include "job.h"
+
+void ojmbxio (int4 func, short chan, mstr *msg, short *iosb, bool now)
+{
+ int4 status;
+
+ assert (func == IO$_READVBLK ||
+ func == IO$_WRITEVBLK ||
+ func == IO$_WRITEOF);
+ if (now) func |= IO$M_NOW;
+ status = sys$qio (efn_immed_wait, chan, func, iosb, 0, 0,
+ msg->addr, msg->len, 0, 0, 0, 0);
+ if (!(status & 1))
+ {
+ ojerrcleanup ();
+ rts_error(VARLSTCNT(1) status);
+ }
+ sys$synch (efn_immed_wait, iosb);
+ if (!(*iosb & 1))
+ {
+ ojerrcleanup ();
+ rts_error(VARLSTCNT(1) *iosb);
+ }
+ return;
+}
diff --git a/sr_vvms/ojparams.c b/sr_vvms/ojparams.c
new file mode 100644
index 0000000..1d023f2
--- /dev/null
+++ b/sr_vvms/ojparams.c
@@ -0,0 +1,269 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include <ssdef.h>
+#include <descrip.h>
+#include <rmsdef.h>
+#include <prcdef.h>
+#include "job.h"
+#include "min_max.h"
+
+static readonly unsigned char definput[] = "NL:";
+static readonly unsigned char deflogfile[] = "NL:";
+
+static unsigned char *defoutbuf;
+static unsigned char *deferrbuf;
+
+LITREF jp_datatype job_param_datatypes[];
+LITREF mstr define_gtm$job$_;
+LITREF mstr set_default_;
+LITREF mstr atsign;
+LITREF mstr run__nodebug_;
+
+error_def (ERR_IVTIME);
+error_def (ERR_PRCNAMLEN);
+error_def (ERR_PARFILSPC);
+
+void ojparams(unsigned char *p, mval *routine, bool *defprcnam, int4 *cmaxmsg, mstr *image,
+ mstr *input, mstr *output, mstr *error, struct dsc$descriptor_s *prcnam, int4 *baspri,
+ int4 *stsflg, mstr *gbldir, mstr *startup, struct dsc$descriptor_s *logfile, mstr *deffs,
+ quadword *schedule)
+{
+ jp_type ch;
+ int4 status;
+ struct dsc$descriptor_s timdsc;
+ int4 defstsflg;
+ MSTR_CONST(defoutext, ".MJO");
+ MSTR_CONST(deferrext, ".MJE");
+
+/* Initializations */
+ *defprcnam = FALSE;
+ defstsflg = PRC$M_DETACH;
+ *cmaxmsg = MAX(*cmaxmsg, (define_gtm$job$_.len + MAX_PIDSTR_LEN));
+ image->len = 0;
+ input->len = output->len = error->len = 0;
+ prcnam->dsc$w_length = 0;
+ prcnam->dsc$b_dtype = DSC$K_DTYPE_T;
+ prcnam->dsc$b_class = DSC$K_CLASS_S;
+ *baspri = JP_NO_BASPRI;
+ *stsflg = defstsflg;
+ gbldir->len = 0;
+ startup->len = 0;
+ logfile->dsc$w_length = 0;
+ logfile->dsc$b_dtype = DSC$K_DTYPE_T;
+ logfile->dsc$b_class = DSC$K_CLASS_S;
+ deffs->len = 0;
+ schedule->hi = schedule->lo = 0;
+
+/* Process parameter list */
+ while (*p != jp_eol)
+ {
+ switch (ch = *p++)
+ {
+ case jp_account:
+ *stsflg &= (~PRC$M_NOACNT);
+ break;
+ case jp_default:
+ if (*p != 0)
+ {
+ deffs->len = (int)((unsigned char) *p);
+ deffs->addr = (p + 1);
+ }
+ break;
+ case jp_detached:
+ *stsflg |= PRC$M_DETACH;
+ break;
+ case jp_error:
+ if (*p != 0)
+ {
+ error->len = (int)((unsigned char) *p);
+ error->addr = (p + 1);
+ }
+ break;
+ case jp_gbldir:
+ if (*p != 0)
+ {
+ gbldir->len = (int)((unsigned char) *p);
+ gbldir->addr = (p + 1);
+ }
+ break;
+ case jp_image:
+ if (*p != 0)
+ {
+ image->len = (int)((unsigned char) *p);
+ image->addr = p + 1;
+ }
+ break;
+ case jp_input:
+ if (*p != 0)
+ {
+ input->len = (int)((unsigned char) *p);
+ input->addr = p + 1;
+ }
+ break;
+ case jp_logfile:
+ if (*p != 0)
+ {
+ logfile->dsc$w_length = (int)((unsigned char) *p);
+ logfile->dsc$a_pointer = p + 1;
+ }
+ break;
+ case jp_noaccount:
+ *stsflg |= PRC$M_NOACNT;
+ break;
+ case jp_nodetached:
+ *stsflg &= (~PRC$M_DETACH);
+ break;
+ case jp_noswapping:
+ *stsflg |= PRC$M_PSWAPM;
+ break;
+ case jp_output:
+ if (*p != 0)
+ {
+ output->len = (int)((unsigned char) *p);
+ output->addr = p + 1;
+ }
+ break;
+ case jp_priority:
+ *baspri = *(int4 *)p;
+ break;
+ case jp_process_name:
+ if (*p != 0)
+ {
+ prcnam->dsc$w_length = (int)((unsigned char) *p);
+ prcnam->dsc$a_pointer = p + 1;
+ }
+ break;
+ case jp_schedule:
+ timdsc.dsc$w_length = (int)((unsigned char) *p);
+ timdsc.dsc$b_dtype = DSC$K_DTYPE_T;
+ timdsc.dsc$b_class = DSC$K_CLASS_S;
+ timdsc.dsc$a_pointer = p + 1;
+ status = sys$bintim (&timdsc, schedule);
+ if (status != SS$_NORMAL)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(4) ERR_IVTIME, 2, timdsc.dsc$w_length, timdsc.dsc$a_pointer);
+ break;
+ case jp_startup:
+ if (*p != 0)
+ {
+ startup->len = (int)((unsigned char) *p);
+ startup->addr = p + 1;
+ }
+ break;
+ case jp_swapping:
+ *stsflg &= (~PRC$M_PSWAPM);
+ break;
+ default:
+ GTMASSERT;
+ }
+ switch (job_param_datatypes[ch])
+ {
+ case jpdt_nul:
+ break;
+ case jpdt_num:
+ p += SIZEOF(int4);
+ break;
+ case jpdt_str:
+ p += ((int)((unsigned char)*p)) + 1;
+ break;
+ default:
+ GTMASSERT;
+ }
+ }
+
+/* Defaults and Checks */
+ if (image->len == 0)
+ ojdefimage (image);
+ else
+ if ((status = ojchkfs (image->addr, image->len, TRUE)) != RMS$_NORMAL)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_PARFILSPC, 4, 5, "IMAGE", image->len, image->addr, status);
+ *cmaxmsg = MAX(*cmaxmsg, run__nodebug_.len + image->len);
+ if (input->len == 0)
+ {
+ input->len = SIZEOF(definput) - 1;
+ input->addr = definput;
+ }
+ else
+ if ((status = ojchkfs (input->addr, input->len, TRUE)) != RMS$_NORMAL)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_PARFILSPC, 4, 5, "INPUT", input->len, input->addr, status);
+ *cmaxmsg = MAX(*cmaxmsg, 1 + input->len);
+ if (output->len == 0)
+ {
+ if (!defoutbuf)
+ defoutbuf = malloc(MAX_FILSPC_LEN);
+ memcpy (&defoutbuf[0], routine->str.addr, routine->str.len);
+ memcpy (&defoutbuf[routine->str.len], defoutext.addr, defoutext.len);
+ if (*defoutbuf == '%')
+ *defoutbuf = '_';
+ output->len = routine->str.len + defoutext.len;
+ output->addr = &defoutbuf[0];
+ }
+ else
+ if ((status = ojchkfs (output->addr, output->len, FALSE)) != RMS$_NORMAL)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_PARFILSPC, 4, 6, "OUTPUT", output->len, output->addr, status);
+ *cmaxmsg = MAX(*cmaxmsg, 1 + output->len);
+ if (error->len == 0)
+ {
+ if (!deferrbuf)
+ deferrbuf = malloc(MAX_FILSPC_LEN);
+ memcpy (&deferrbuf[0], routine->str.addr, routine->str.len);
+ memcpy (&deferrbuf[routine->str.len], deferrext.addr, deferrext.len);
+ if (*deferrbuf == '%')
+ *deferrbuf = '_';
+ error->len = routine->str.len + deferrext.len;
+ error->addr = &deferrbuf[0];
+ }
+ else
+ if ((status = ojchkfs (error->addr, error->len, FALSE)) != RMS$_NORMAL)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_PARFILSPC, 4, 5, "ERROR", error->len, error->addr, status);
+ *cmaxmsg = MAX(*cmaxmsg, 1 + error->len);
+
+ if (prcnam->dsc$w_length > MAX_PRCNAM_LEN)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5)
+ ERR_PRCNAMLEN, 3, prcnam->dsc$w_length, prcnam->dsc$a_pointer, MAX_PRCNAM_LEN);
+ if (prcnam->dsc$w_length == 0)
+ {
+ ojdefprcnam (prcnam);
+ *defprcnam = TRUE;
+ }
+ if (*baspri == JP_NO_BASPRI)
+ ojdefbaspri (baspri);
+
+ if (gbldir->len != 0)
+ if ((status = ojchkfs (gbldir->addr, gbldir->len, FALSE)) != RMS$_NORMAL)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_PARFILSPC, 4, 6, "GBLDIR", gbldir->len, gbldir->addr, status);
+ *cmaxmsg = MAX(*cmaxmsg, 1 + gbldir->len);
+ if (startup->len != 0)
+ if ((status = ojchkfs (startup->addr, startup->len, TRUE)) != RMS$_NORMAL)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7)
+ ERR_PARFILSPC, 4, 7, "STARTUP", startup->len, startup->addr, status);
+ *cmaxmsg = MAX(*cmaxmsg, atsign.len + startup->len);
+ if (deffs->len == 0)
+ ojdefdeffs (deffs);
+ else
+ if ((status = ojchkfs (deffs->addr, deffs->len, FALSE)) != RMS$_NORMAL)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_PARFILSPC, 4, 7, "DEFAULT", deffs->len, deffs->addr, status);
+ *cmaxmsg = MAX(*cmaxmsg, set_default_.len + deffs->len);
+ if (logfile->dsc$w_length == 0)
+ {
+ logfile->dsc$w_length = SIZEOF(deflogfile) - 1;
+ logfile->dsc$a_pointer = deflogfile;
+ }
+ else
+ if ((status = ojchkfs (logfile->dsc$a_pointer, logfile->dsc$w_length, FALSE)) != RMS$_NORMAL)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_PARFILSPC, 4, 7, "LOGFILE", logfile->dsc$w_length,
+ logfile->dsc$a_pointer, status);
+ return;
+}
diff --git a/sr_vvms/ojsetattn.c b/sr_vvms/ojsetattn.c
new file mode 100644
index 0000000..175c785
--- /dev/null
+++ b/sr_vvms/ojsetattn.c
@@ -0,0 +1,44 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <iodef.h>
+#include "efn.h"
+#include "job.h"
+
+GBLREF short ojpchan;
+
+void ojsetattn (int msg)
+{
+ int4 status;
+ short iosb[4];
+
+ status = sys$clref (efn_op_job);
+ if (!(status & 1))
+ {
+ ojerrcleanup ();
+ rts_error(VARLSTCNT(1) status);
+ }
+ status = sys$qio (efn_immed_wait, ojpchan, IO$_SETMODE | IO$M_WRTATTN,
+ iosb, 0, 0, ojastread, msg, 0, 0, 0, 0);
+ if (!(status & 1))
+ {
+ ojerrcleanup ();
+ rts_error(VARLSTCNT(1) status);
+ }
+ sys$synch (efn_immed_wait, iosb);
+ if (!(iosb[0] & 1))
+ {
+ ojerrcleanup ();
+ rts_error(VARLSTCNT(1) iosb[0]);
+ }
+ return;
+}
diff --git a/sr_vvms/ojtmrinit.c b/sr_vvms/ojtmrinit.c
new file mode 100644
index 0000000..850d90e
--- /dev/null
+++ b/sr_vvms/ojtmrinit.c
@@ -0,0 +1,54 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <ssdef.h>
+
+#include "ast.h"
+#include "efn.h"
+#include "iotimer.h"
+#include "job.h"
+#include "rel_quant.h"
+
+GBLREF short astq_dyn_avail;
+GBLREF bool ojtimeout;
+GBLREF short ojastq;
+
+void ojtmrinit(int4 *timeout)
+{
+ int4 addend, onesec;
+ unsigned int ast_stat, status;
+ quadword timblk;
+
+ onesec = -10000000; /* 1 second delta time */
+ addend = 0;
+ lib$emul(timeout, &onesec, &addend, &timblk);
+ ast_stat = sys$setast(DISABLE);
+ while (astq_dyn_avail < 1)
+ {
+ ENABLE_AST;
+ rel_quant();
+ DISABLE_AST;
+ }
+ ojastq++;
+ --astq_dyn_avail;
+ if (SS$_WASSET == ast_stat)
+ sys$setast(ENABLE);
+ ojtimeout = FALSE;
+ status = sys$setimr(efn_timer, &timblk, &ojtmrrtn, &(ojtimeout), 0);
+ if (!(status & 1))
+ {
+ astq_dyn_avail++;
+ rts_error(VARLSTCNT(1) status);
+ }
+ return;
+}
diff --git a/sr_vvms/ojtmrrtn.c b/sr_vvms/ojtmrrtn.c
new file mode 100644
index 0000000..be036c7
--- /dev/null
+++ b/sr_vvms/ojtmrrtn.c
@@ -0,0 +1,27 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "job.h"
+
+GBLREF short astq_dyn_avail;
+GBLREF bool ojtimeout;
+GBLREF short ojastq;
+
+void ojtmrrtn (void)
+{
+ assert (lib$ast_in_prog());
+ assert (ojtimeout == FALSE);
+ --ojastq;
+ astq_dyn_avail++;
+ ojtimeout = TRUE;
+ return;
+}
diff --git a/sr_vvms/ojunit_to_mba.c b/sr_vvms/ojunit_to_mba.c
new file mode 100644
index 0000000..9243a1d
--- /dev/null
+++ b/sr_vvms/ojunit_to_mba.c
@@ -0,0 +1,38 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+unsigned short ojunit_to_mba (targ, n)
+char *targ;
+uint4 n;
+{
+ char buf[16];
+ unsigned short i, len;
+
+ i = 0;
+ do {
+ buf[i++] = '0' + n % 10;
+ n = n / 10;
+ } while (n != 0);
+ len = i + 5;
+
+ *targ++ = '_';
+ *targ++ = 'M';
+ *targ++ = 'B';
+ *targ++ = 'A';
+ do {
+ *targ++ = buf[--i];
+ } while (i > 0);
+ *targ++ = ':';
+
+ return len;
+}
diff --git a/sr_vvms/op_fgnlookup.c b/sr_vvms/op_fgnlookup.c
new file mode 100644
index 0000000..cab6150
--- /dev/null
+++ b/sr_vvms/op_fgnlookup.c
@@ -0,0 +1,65 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2005 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "zcall.h"
+
+GBLREF zctabrtn *zctab, *zctab_end;
+GBLREF zcpackage *zcpack_start, *zcpack_end;
+
+zctabrtn *op_fgnlookup (mval *package, mval *extref)
+{
+ zctabrtn *zcrtn, *zcrtn_top;
+ zcpackage *zcpack;
+ error_def (ERR_ZCALLTABLE);
+
+ assert(MV_IS_STRING(package)); /* package and routine are literal strings */
+ assert(MV_IS_STRING(extref));
+
+ if (package->str.len)
+ {
+ zcpack = zcpack_start;
+ while (zcpack < zcpack_end)
+ {
+ if (*zcpack->packname == 0) rts_error (ERR_ZCALLTABLE);
+ if ((*zcpack->packname == package->str.len) &&
+ !memcmp (zcpack->packname + 1, package->str.addr, package->str.len))
+ break;
+ zcpack++;
+ }
+ if (zcpack >= zcpack_end)
+ { return (zctabrtn *) 0;
+ }
+ zcrtn = zcpack->begin;
+ zcrtn_top = zcpack->end;
+ if ((zcrtn > zctab_end || zcrtn < zctab) ||
+ (zcrtn_top > zctab_end || zcrtn_top < zctab) || (zcrtn > zcrtn_top))
+ rts_error(ERR_ZCALLTABLE);
+ }
+ else
+ { zcrtn = zctab;
+ zcrtn_top = zctab_end;
+ }
+
+ while (zcrtn < zcrtn_top)
+ {
+ if ((zcrtn >= zctab_end) || (zcrtn->entry_length == 0) || (zcrtn->callnamelen == 0))
+ rts_error (ERR_ZCALLTABLE);
+ if ((zcrtn->callnamelen == extref->str.len) &&
+ !memcmp (zcrtn->callname, extref->str.addr, extref->str.len))
+ break;
+ zcrtn = (zctabrtn *) ((char *) zcrtn + zcrtn->entry_length);
+ }
+ if (zcrtn >= zcrtn_top)
+ { zcrtn = (zctabrtn *) 0;
+ }
+ return zcrtn;
+}
diff --git a/sr_vvms/op_fgnlookup.h b/sr_vvms/op_fgnlookup.h
new file mode 100644
index 0000000..58f9116
--- /dev/null
+++ b/sr_vvms/op_fgnlookup.h
@@ -0,0 +1,17 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+#ifndef __OP_FGNLOOKUP_H__
+#define __OP_FGNLOOKUP_H__
+
+zctabrtn *op_fgnlookup(mval *package, mval *extref);
+
+#endif
+
diff --git a/sr_vvms/op_fn.h b/sr_vvms/op_fn.h
new file mode 100644
index 0000000..c7ce33d
--- /dev/null
+++ b/sr_vvms/op_fn.h
@@ -0,0 +1,31 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* File modified by Maccrone on 4-DEC-1986 14:45:13.23 */
+/* File modified by Maccrone on 4-DEC-1986 08:28:30.71 */
+typedef struct
+{ char len;
+ char name[20];
+ short int item_code;
+}dvi_struct;
+
+typedef struct
+{ char index;
+ char len;
+}dvi_index_struct;
+
+typedef struct
+{ short int bufflen;
+ short int itmcode;
+ int4 buffaddr;
+ int4 retlen;
+ int4 end;
+}itmlist_struct;
diff --git a/sr_vvms/op_fnfgncal.c b/sr_vvms/op_fnfgncal.c
new file mode 100644
index 0000000..16f49dd
--- /dev/null
+++ b/sr_vvms/op_fnfgncal.c
@@ -0,0 +1,71 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include <stdarg.h>
+
+#include "zcall.h"
+#include "have_crit.h"
+
+GBLREF volatile int4 gtmMallocDepth;
+
+error_def(ERR_ZCALLTABLE);
+error_def(ERR_ZCRTENOTF);
+error_def(ERR_ZCARGMSMTCH);
+
+void op_fnfgncal (mval *dst, ...)
+{
+ va_list var;
+ int4 mask, i, argcnt;
+ mval *mvallist[256]; /* maximum of fewer than 256 arguments passed via VAX calls instruction */
+ zctabrtn *zcrtn;
+ unsigned char *lastout;
+
+ va_start(var, dst);
+ zcrtn = va_arg(var, zctabrtn *);
+ if (!zcrtn)
+ {
+ va_end(var);
+ rts_error (VARLSTCNT(4) ERR_ZCRTENOTF, 2, 0, 0);
+ }
+ mask = va_arg(var, int4);
+ argcnt = va_arg(var, int4);
+
+ if (argcnt > zcrtn->n_inputs)
+ {
+ va_end(var);
+ rts_error (ERR_ZCARGMSMTCH, 2, argcnt, zcrtn->n_inputs);
+ }
+
+ lastout = (unsigned char *) zcrtn
+ + ROUND_UP(SIZEOF(zctabrtn) + zcrtn->callnamelen - 1 + SIZEOF(zctabret), SIZEOF(int4))
+ + zcrtn->n_inputs * SIZEOF(zctabinput)
+ + zcrtn->n_outputs * SIZEOF(zctaboutput);
+
+ if (ROUND_UP((int) lastout + 1, SIZEOF(int4)) != (unsigned char *) zcrtn + zcrtn->entry_length)
+ {
+ va_end(var);
+ rts_error (ERR_ZCALLTABLE);
+ }
+
+ for (i = 0; i < argcnt; i++)
+ mvallist[i] = va_arg(var, mval *);
+ va_end(var);
+
+ assert(INTRPT_OK_TO_INTERRUPT == intrpt_ok_state); /* interrupts should be enabled for external calls */
+
+ zc_makespace (dst, mask, mvallist, &mvallist[argcnt], zcrtn, *lastout);
+
+ return;
+}
diff --git a/sr_vvms/op_fngetdvi.c b/sr_vvms/op_fngetdvi.c
new file mode 100644
index 0000000..1a47603
--- /dev/null
+++ b/sr_vvms/op_fngetdvi.c
@@ -0,0 +1,297 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <dvidef.h>
+#include <devdef.h>
+#include <ssdef.h>
+#include <descrip.h>
+#include "stringpool.h"
+#include "op_fn.h"
+#include "efn.h"
+#include "gtm_caseconv.h"
+#include "mvalconv.h"
+#include "op.h"
+
+#define MIN_INDEX 0
+#define MAX_INDEX 25
+#define MAX_DVI_STRLEN 128
+#define MAX_DEV_LENGTH 63
+#define MAX_KEY_LENGTH 14
+#define VAL_LENGTH 4
+#define SPL_CODE 83
+#define HEX_LEN 8
+
+
+static readonly dvi_struct dvi_table[] =
+{
+ { 6, "ACPPID" , DVI$_ACPPID }, { 7, "ACPTYPE", DVI$_ACPTYPE },
+ { 3, "ALL" ,DVI$_ALL }, { 9, "ALLDEVNAM", DVI$_ALLDEVNAM },
+ { 9, "ALTYPEAHD", DVI$_TT_ALTYPEAHD }, { 7, "ANSICRT", DVI$_TT_ANSICRT },
+ { 10, "APP_KEYPAD", DVI$_TT_APP_KEYPAD },{ 8, "AUTOBAUD", DVI$_TT_AUTOBAUD },
+ { 3,"AVL" , DVI$_AVL }, { 3, "AVO", DVI$_TT_AVO },
+ { 5, "BLOCK", DVI$_TT_BLOCK }, { 9, "BRDCSTMBX", DVI$_TT_BRDCSTMBX },
+ { 3,"CCL" , DVI$_CCL }, { 7, "CLUSTER", DVI$_CLUSTER },
+ { 9, "CONCEALED", DVI$_CONCEALED }, { 6, "CRFILL", DVI$_TT_CRFILL },
+ { 9, "CYLINDERS", DVI$_CYLINDERS },
+ { 6, "DECCRT", DVI$_TT_DECCRT },
+ { 9, "DEVBUFSIZ", DVI$_DEVBUFSIZ }, { 7, "DEVCHAR", DVI$_DEVCHAR },
+ { 8, "DEVCHAR2", DVI$_DEVCHAR2 }, { 8, "DEVCLASS", DVI$_DEVCLASS },
+ { 9, "DEVDEPEND", DVI$_DEVDEPEND }, { 10, "DEVDEPEND2", DVI$_DEVDEPEND2 },
+ { 10, "DEVLOCKNAM", DVI$_DEVLOCKNAM }, { 6, "DEVNAM", DVI$_DEVNAM },
+ { 6, "DEVSTS", DVI$_DEVSTS }, { 7, "DEVTYPE", DVI$_DEVTYPE },
+ { 6, "DIALUP", DVI$_TT_DIALUP },
+ { 3,"DIR" , DVI$_DIR }, { 10, "DISCONNECT", DVI$_TT_DISCONNECT },
+ { 3, "DMA", DVI$_TT_DMA }, { 3, "DMT" , DVI$_DMT },
+ { 4, "DRCS", DVI$_TT_DRCS }, { 3, "DUA" , DVI$_DUA },
+ { 4, "EDIT", DVI$_TT_EDIT }, { 7, "EDITING", DVI$_TT_EDITING },
+ { 8, "EIGHTBIT", DVI$_TT_EIGHTBIT }, { 3, "ELG" , DVI$_ELG },
+ { 6, "ERRCNT", DVI$_ERRCNT }, { 6, "ESCAPE", DVI$_TT_ESCAPE },
+ { 8, "FALLBACK", DVI$_TT_FALLBACK }, { 3, "FOD" , DVI$_FOD },
+ { 3, "FOR" , DVI$_FOR }, { 10, "FREEBLOCKS", DVI$_FREEBLOCKS },
+ { 10, "FULLDEVNAM", DVI$_FULLDEVNAM },
+ { 3, "GEN" , DVI$_GEN },
+ { 7, "HALFDUP", DVI$_TT_HALFDUP },
+ { 6, "HANGUP", DVI$_TT_HANGUP }, { 8, "HOSTSYNC", DVI$_TT_HOSTSYNC },
+ { 3, "IDV" , DVI$_IDV }, { 6, "INSERT", DVI$_TT_INSERT },
+ { 6, "LFFILL", DVI$_TT_LFFILL }, { 9, "LOCALECHO", DVI$_TT_LOCALECHO },
+ { 6, "LOCKID", DVI$_LOCKID },
+ { 9, "LOGVOLNAM", DVI$_LOGVOLNAM }, { 5, "LOWER", DVI$_TT_LOWER },
+ { 8, "MAXBLOCK", DVI$_MAXBLOCK }, { 8, "MAXFILES", DVI$_MAXFILES },
+ { 3, "MBX" , DVI$_MBX }, { 8, "MBXDSABL", DVI$_TT_MBXDSABL },
+ { 8, "MECHFORM", DVI$_TT_MECHFORM }, { 7, "MECHTAB", DVI$_TT_MECHTAB },
+ { 3, "MNT" , DVI$_MNT }, { 5, "MODEM", DVI$_TT_MODEM },
+ { 9, "MODHANGUP", DVI$_TT_MODHANGUP }, { 8, "MOUNTCNT", DVI$_MOUNTCNT },
+ { 3, "NET" , DVI$_NET }, { 10, "NEXTDEVNAM", DVI$_NEXTDEVNAM },
+ { 8, "NOBRDCST", DVI$_TT_NOBRDCST },
+ { 6, "NOECHO", DVI$_TT_NOECHO }, { 9, "NOTYPEAHD", DVI$_TT_NOTYPEAHD },
+ { 3, "ODV" , DVI$_ODV }, { 5, "OPCNT", DVI$_OPCNT },
+ { 4, "OPER", DVI$_TT_OPER}, { 3, "OPR" , DVI$_OPR },
+ { 6, "OWNUIC", DVI$_OWNUIC },
+ { 7, "PASTHRU", DVI$_TT_PASTHRU },
+ { 3, "PID", DVI$_PID }, { 7, "PRINTER", DVI$_TT_PRINTER },
+ { 3, "RCK" , DVI$_RCK }, { 8, "READSYNC", DVI$_TT_READSYNC },
+ { 3, "REC" , DVI$_REC }, { 6, "RECSIZ", DVI$_RECSIZ },
+ { 6, "REFCNT", DVI$_REFCNT }, { 5, "REGIS", DVI$_TT_REGIS },
+ { 3, "RND" , DVI$_RND }, { 10, "ROOTDEVNAM", DVI$_ROOTDEVNAM },
+ { 3, "RTM" , DVI$_RTM },
+ { 5, "SCOPE", DVI$_TT_SCOPE }, { 3, "SDI" , DVI$_SDI },
+ { 7, "SECTORS", DVI$_SECTORS }, { 6, "SECURE", DVI$_TT_SECURE },
+ { 9, "SERIALNUM", DVI$_SERIALNUM }, {13, "SERVED_DEVICE", DVI$_SERVED_DEVICE},
+ { 8, "SETSPEED", DVI$_TT_SETSPEED },
+ { 3, "SHR" , DVI$_SHR }, { 5, "SIXEL", DVI$_TT_SIXEL },
+ { 3, "SPL" , DVI$_SPL }, { 9, "SPLDEVNAM", DVI$_DEVNAM },
+ { 3, "SQD" , DVI$_SQD }, { 3, "STS", DVI$_STS },
+ { 3, "SWL" , DVI$_SWL }, { 6, "SYSPSW", DVI$_TT_SYSPWD },
+ { 6, "TRACKS", DVI$_TRACKS }, { 8, "TRANSCNT", DVI$_TRANSCNT },
+ { 3, "TRM" , DVI$_TRM }, { 12, "TT_ACCPORNAM" , DVI$_TT_ACCPORNAM },
+ { 12, "TT_PHYDEVNAM" , DVI$_TT_PHYDEVNAM }, { 6, "TTSYNC", DVI$_TT_TTSYNC },
+ { 4, "UNIT", DVI$_UNIT }, { 8, "VOLCOUNT", DVI$_VOLCOUNT },
+ { 6, "VOLNAM", DVI$_VOLNAM }, { 9, "VOLNUMBER", DVI$_VOLNUMBER },
+ { 9, "VOLSETMEM", DVI$_VOLSETMEM }, { 5, "VPROT", DVI$_VPROT },
+ { 3, "WCK" , DVI$_WCK }, { 4, "WRAP", DVI$_TT_WRAP }
+};
+
+static readonly dvi_index_struct dvi_index[] = {
+ /* A B C D E F G */
+ { 0 , 10 }, { 10 , 12 }, { 12 , 17 }, { 17, 35 }, { 35 , 41 }, { 41 , 46 }, { 46, 47 },
+ /* H I J K L M N */
+ { 47, 50 }, { 50 , 52 }, { 0 , 0 }, { 0 , 0 }, { 52 , 57 }, { 57 , 67 }, { 67 , 72 },
+ /* O P Q R S T U */
+ { 72 , 77 }, { 77 , 80 }, { 0 , 0 }, { 80 , 89 }, { 89 , 104 }, { 104 , 110 }, {110 , 111},
+ /* V W X Y Z */
+ { 111,116},{116,118},{0,0},{0,0},{0,0}
+};
+GBLREF spdesc stringpool;
+
+void op_fngetdvi(mval *device, mval *keyword, mval *ret)
+{
+ itmlist_struct item_list;
+ short out_len, iosb[4];
+ uint4 status;
+ char index, slot, last_slot;
+ int4 item_code, out_value;
+ unsigned char buff[MAX_KEY_LENGTH], *upper_case;
+ bool want_secondary;
+ $DESCRIPTOR(device_name,"");
+ error_def(ERR_DVIKEYBAD);
+ error_def(ERR_INVSTRLEN);
+
+ MV_FORCE_STR(device);
+ MV_FORCE_STR(keyword);
+
+ if (MAX_DEV_LENGTH < device->str.len)
+ rts_error(VARLSTCNT(1) SS$_IVLOGNAM);
+ if (keyword->str.len > MAX_KEY_LENGTH)
+ rts_error(VARLSTCNT(4) ERR_INVSTRLEN, 2, keyword->str.len, MAX_KEY_LENGTH);
+ if (!keyword->str.len)
+ { rts_error(VARLSTCNT(6) ERR_DVIKEYBAD, 4, device->str.len, device->str.addr, 4, "NULL");
+ }
+
+ lower_to_upper(&buff[0], keyword->str.addr, keyword->str.len);
+ upper_case = buff;
+ if ( device->str.len == 0 || (device->str.len == 1 && *device->str.addr == '0'))
+ { device_name.dsc$a_pointer = "SYS$INPUT";
+ device_name.dsc$w_length = SIZEOF("SYS$INPUT")-1;
+ }
+ else
+ { device_name.dsc$a_pointer = device->str.addr;
+ device_name.dsc$w_length = device->str.len;
+ }
+ item_list.bufflen = VAL_LENGTH;
+ item_list.itmcode = SPL_CODE;
+ item_list.buffaddr = &out_value;
+ item_list.retlen = &out_len;
+ item_list.end = NULL;
+ status = sys$getdvi( efn_immed_wait, 0, &device_name, &item_list, &iosb[0], 0, 0, 0 );
+ if (status != SS$_NORMAL && status != SS$_NONLOCAL)
+ { rts_error(VARLSTCNT(1) status ) ;
+ }
+ sys$synch(efn_immed_wait, &iosb[0]);
+ if (iosb[0] != SS$_NORMAL && iosb[0] != SS$_NONLOCAL)
+ { rts_error(VARLSTCNT(1) iosb[0] );
+ }
+ if (out_value != NULL)
+ { want_secondary = TRUE;
+ }
+ else
+ { want_secondary = FALSE;
+ }
+
+ if ((index = *upper_case - 'A') < MIN_INDEX || index > MAX_INDEX)
+ { rts_error(VARLSTCNT(6) ERR_DVIKEYBAD, 4, device->str.len, device->str.addr, keyword->str.len, keyword->str.addr);
+ }
+ item_code = 0;
+ if ( dvi_index[ index ].len)
+ {
+ slot = dvi_index[ index ].index;
+ last_slot = dvi_index[ index ].len;
+ for ( ; slot < last_slot ; slot++ )
+ { if (keyword->str.len == dvi_table[ slot ].len &&
+ !memcmp(dvi_table[ slot ].name, upper_case, keyword->str.len))
+ { item_code = dvi_table[ slot ].item_code;
+ break;
+ }
+ }
+ }
+ if (!item_code)
+ { rts_error(VARLSTCNT(6) ERR_DVIKEYBAD, 4, device->str.len, device->str.addr, keyword->str.len, keyword->str.addr);
+ }
+
+ switch( item_code )
+ {
+ /* **** the following item codes require a string be returned **** */
+ case DVI$_ALLDEVNAM:
+ case DVI$_DEVLOCKNAM:
+ case DVI$_DEVNAM:
+ case DVI$_FULLDEVNAM:
+ case DVI$_LOGVOLNAM:
+ case DVI$_NEXTDEVNAM:
+ case DVI$_ROOTDEVNAM:
+ case DVI$_TT_ACCPORNAM:
+ case DVI$_TT_PHYDEVNAM:
+ case DVI$_VOLNAM:
+ if (want_secondary)
+ {
+ if (!((item_code == DVI$_DEVNAM) && (keyword->str.len == 9)))
+ { item_code |= DVI$C_SECONDARY;
+ }
+ }
+ assert(stringpool.free >= stringpool.base);
+ assert(stringpool.top >= stringpool.free);
+ ENSURE_STP_FREE_SPACE(MAX_DVI_STRLEN);
+ item_list.bufflen = MAX_DVI_STRLEN;
+ item_list.itmcode = item_code;
+ item_list.buffaddr = stringpool.free;
+ item_list.retlen = &out_len;
+ item_list.end = NULL;
+ status = sys$getdvi( efn_immed_wait, 0, &device_name, &item_list, &iosb[0], 0, 0, 0 );
+ if (status != SS$_NORMAL && status != SS$_NONLOCAL)
+ { rts_error(VARLSTCNT(1) status );
+ }
+ sys$synch(efn_immed_wait, &iosb[0]);
+ if (iosb[0] != SS$_NORMAL && iosb[0] != SS$_NONLOCAL)
+ { rts_error(VARLSTCNT(1) iosb[0] ) ;
+ }
+ ret->str.addr = stringpool.free;
+ ret->str.len = out_len;
+ ret->mvtype = MV_STR;
+ stringpool.free += out_len;
+ assert(stringpool.free >= stringpool.base);
+ assert(stringpool.top >= stringpool.free);
+ return;
+
+ default:
+ if (want_secondary)
+ item_code |= DVI$C_SECONDARY;
+ item_list.itmcode = item_code;
+ item_list.bufflen = VAL_LENGTH;
+ item_list.buffaddr = &out_value;
+ item_list.retlen = &out_len;
+ item_list.end = NULL;
+ status = sys$getdvi( efn_immed_wait, 0, &device_name, &item_list, &iosb[0], 0, 0, 0 );
+ if (status != SS$_NORMAL && status != SS$_NONLOCAL)
+ rts_error(VARLSTCNT(1) status );
+ sys$synch(efn_immed_wait, &iosb[0]);
+ if (iosb[0] != SS$_NORMAL && iosb[0] != SS$_NONLOCAL)
+ rts_error(VARLSTCNT(1) iosb[0] );
+ if (want_secondary)
+ item_code = item_code - 1;
+ switch(item_code)
+ { case DVI$_LOCKID:
+ case DVI$_ACPPID:
+ case DVI$_OWNUIC:
+ if (out_value)
+ { assert(stringpool.free >= stringpool.base);
+ assert(stringpool.top >= stringpool.free);
+ ENSURE_STP_FREE_SPACE(HEX_LEN);
+ i2hex(out_value, stringpool.free, HEX_LEN);
+ ret->str.addr = stringpool.free;
+ ret->str.len = HEX_LEN;
+ stringpool.free += HEX_LEN;
+ assert(stringpool.free >= stringpool.base);
+ assert(stringpool.top >= stringpool.free);
+ }
+ else
+ { ret->str.addr = "";
+ ret->str.len = 0;
+ }
+ ret->mvtype = MV_STR;
+ break;
+ case DVI$_ACPTYPE:
+ switch(out_value)
+ {
+ case 0: ret->str.addr = "ILLEGAL";
+ ret->str.len = 7;
+ break;
+ case 1: ret->str.addr = "F11V1";
+ ret->str.len = 5;
+ break;
+ case 2: ret->str.addr = "F11V2";
+ ret->str.len = 5;
+ break;
+ case 3: ret->str.addr = "MTA";
+ ret->str.len = 3;
+ break;
+ case 4: ret->str.addr = "NET";
+ ret->str.len = 3;
+ break;
+ case 5: ret->str.addr = "REM";
+ ret->str.len = 3;
+ }
+ ret->mvtype = MV_STR;
+ break;
+ default:
+ i2mval(ret,out_value) ;
+ }
+ return;
+ }
+}
diff --git a/sr_vvms/op_fngetjpi.c b/sr_vvms/op_fngetjpi.c
new file mode 100644
index 0000000..965905d
--- /dev/null
+++ b/sr_vvms/op_fngetjpi.c
@@ -0,0 +1,227 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include "stringpool.h"
+#include <ssdef.h>
+#include <descrip.h>
+#include <jpidef.h>
+#include "gtm_caseconv.h"
+#include "op.h"
+#include "mvalconv.h"
+
+#define MAX_KEY_LEN 20 /* maximum length across all keywords in the jpi_param_table[] array as well as "ISPROCALIVE" */
+
+typedef struct
+{ char len;
+ char name[MAX_KEY_LEN];
+ short int item_code;
+}jpi_tab;
+
+typedef struct
+{ char index;
+ char len;
+}jpi_ind;
+
+typedef struct
+{ int4 x;
+ int4 y;
+}out_struct;
+
+static readonly jpi_tab jpi_param_table[] =
+{
+ { 7, "ACCOUNT" , JPI$_ACCOUNT }, { 6, "APTCNT" , JPI$_APTCNT },
+ { 6, "ASTACT" , JPI$_ASTACT}, { 6, "ASTCNT" , JPI$_ASTCNT },
+ { 5, "ASTEN" , JPI$_ASTEN }, { 5, "ASTLM" , JPI$_ASTLM },
+ { 7, "AUTHPRI" , JPI$_AUTHPRI }, { 8, "AUTHPRIV" , JPI$_AUTHPRIV },
+ { 6, "BIOCNT" , JPI$_BIOCNT }, { 5, "BIOLM" , JPI$_BIOLM },
+ { 5, "BUFIO" , JPI$_BUFIO }, { 6, "BYTCNT" , JPI$_BYTCNT },
+ { 5,"BYTLM" , JPI$_BYTLM }, { 7, "CLINAME" , JPI$_CLINAME },
+ { 6, "CPULIM" , JPI$_CPULIM }, { 6, "CPUTIM" , JPI$_CPUTIM },
+ { 11, "CREPRCFLAGS" , JPI$_CREPRC_FLAGS },
+ { 7, "CURPRIV" , JPI$_CURPRIV }, { 5, "DFPFC" , JPI$_DFPFC },
+ { 7, "DFWSCNT" , JPI$_DFWSCNT }, { 6, "DIOCNT" , JPI$_DIOCNT },
+ { 5, "DIOLM" , JPI$_DIOLM }, { 5, "DIRIO" , JPI$_DIRIO },
+ { 4, "EFCS" , JPI$_EFCS }, { 4, "EFCU" , JPI$_EFCU },
+ { 4, "EFWM" , JPI$_EFWM }, { 6, "ENQCNT" , JPI$_ENQCNT },
+ { 5, "ENQLM" , JPI$_ENQLM }, { 6, "EXCVEC" , JPI$_EXCVEC },
+ { 6, "FILCNT" , JPI$_FILCNT }, { 5, "FILLM" , JPI$_FILLM },
+ { 8, "FINALEXC" , JPI$_FINALEXC }, { 7, "FREP0VA" , JPI$_FREP0VA },
+ { 7, "FREP1VA" , JPI$_FREP1VA }, { 9, "FREPTECNT" , JPI$_FREPTECNT },
+ { 6, "GPGCNT" , JPI$_GPGCNT }, { 3, "GRP" , JPI$_GRP },
+ { 10, "IMAGECOUNT" , JPI$_IMAGECOUNT }, { 8, "IMAGNAME" , JPI$_IMAGNAME },
+ { 8, "IMAGPRIV" , JPI$_IMAGPRIV }, { 9, "JOBPRCCNT" , JPI$_JOBPRCCNT },
+ { 7, "JOBTYPE" , JPI$_JOBTYPE },
+ { 8, "LOGINTIM" , JPI$_LOGINTIM }, { 10, "MASTER_PID" , JPI$_MASTER_PID },
+ { 9, "MAXDETACH" , JPI$_MAXDETACH }, { 7, "MAXJOBS" , JPI$_MAXJOBS },
+ { 3, "MEM" , JPI$_MEM }, { 4, "MODE" ,JPI$_MODE },
+ { 7, "MSGMASK" , JPI$_MSGMASK }, { 5, "OWNER" , JPI$_OWNER },
+ { 8, "PAGEFLTS" , JPI$_PAGEFLTS }, { 9, "PAGFILCNT" , JPI$_PAGFILCNT },
+ { 9, "PAGFILLOC" , JPI$_PAGFILLOC },
+ { 9, "PGFLQUOTA" , JPI$_PGFLQUOTA }, { 8, "PHDFLAGS" , JPI$_PHDFLAGS },
+ { 3, "PID" , JPI$_PID }, { 6, "PPGCNT" , JPI$_PPGCNT },
+ { 6, "PRCCNT" , JPI$_PRCCNT }, { 5, "PRCLM" ,JPI$_PRCLM },
+ { 6, "PRCNAM" , JPI$_PRCNAM }, { 3, "PRI" , JPI$_PRI },
+ { 4, "PRIB" , JPI$_PRIB }, { 9, "PROCINDEX" , JPI$_PROC_INDEX },
+ { 8, "PROCPRIV" , JPI$_PROCPRIV }, { 8, "SHRFILLM" , JPI$_SHRFILLM },
+ { 8, "SITESPEC" , JPI$_SITESPEC },
+ { 5, "STATE" , JPI$_STATE }, { 3, "STS" , JPI$_STS },
+ { 9, "SWPFILLOC" , JPI$_SWPFILLOC }, { 9, "TABLENAME" , JPI$_TABLENAME },
+ { 8, "TERMINAL" ,JPI$_TERMINAL },
+ { 4, "TMBU" , JPI$_TMBU }, { 5, "TQCNT" , JPI$_TQCNT },
+ { 4, "TQLM" , JPI$_TQLM }, { 8, "UAFFLAGS" , JPI$_UAF_FLAGS },
+ { 3, "UIC" , JPI$_UIC },
+ { 8, "USERNAME" ,JPI$_USERNAME }, { 8, "VIRTPEAK" , JPI$_VIRTPEAK },
+ { 7, "VOLUMES" , JPI$_VOLUMES }, { 6, "WSAUTH" , JPI$_WSAUTH },
+ { 9, "WSAUTHEXT" , JPI$_WSAUTHEXT }, { 8, "WSEXTENT" , JPI$_WSEXTENT },
+ { 6, "WSPEAK" , JPI$_WSPEAK }, { 7, "WSQUOTA" , JPI$_WSQUOTA },
+ { 6, "WSSIZE" , JPI$_WSSIZE }
+};
+
+static readonly jpi_ind jpi_index_table[] =
+{
+ { 0 , 8 }, { 8 , 13 }, { 13 , 18 }, { 18 , 23 }, { 23 , 29 }, { 29 , 35 },
+ { 35 , 37 }, { 0 , 0 }, { 37 , 40 }, { 40 , 42 }, { 0, 0 }, { 42 , 43 },
+ { 43, 49 }, { 0 , 0 }, { 49 , 50 }, { 50 , 64 }, { 0 , 0 }, { 0 , 0 },
+ { 64 , 69 }, { 69 , 74 }, { 74 , 77 }, { 77 , 79 }, { 79 , 85 },
+ { 0 , 0 }, { 0 , 0 }, { 0 , 0 },
+};
+
+#define MAX_JPI_STRLEN 512
+#define MIN_INDEX 0
+#define MAX_INDEX 25
+
+GBLREF spdesc stringpool;
+
+void op_fngetjpi(mint jpid, mval *keyword, mval *ret)
+{
+ out_struct out_quad;
+ int4 out_long, jpi_code, pid;
+ short index, length, slot, last_slot, out_len;
+ uint4 status;
+ char upcase[MAX_KEY_LEN];
+
+ $DESCRIPTOR(out_string, "");
+ error_def(ERR_BADJPIPARAM);
+
+ assert (stringpool.free >= stringpool.base);
+ assert (stringpool.top >= stringpool.free);
+ ENSURE_STP_FREE_SPACE(MAX_JPI_STRLEN);
+ MV_FORCE_STR(keyword);
+ if (keyword->str.len == 0)
+ rts_error(VARLSTCNT(4) ERR_BADJPIPARAM, 2, 4, "Null");
+ if (keyword->str.len > MAX_KEY_LEN)
+ rts_error(VARLSTCNT(4) ERR_BADJPIPARAM, 2, keyword->str.len, keyword->str.addr );
+ lower_to_upper((uchar_ptr_t)upcase, (uchar_ptr_t)keyword->str.addr, keyword->str.len);
+ if ((index = upcase[0] - 'A') < MIN_INDEX || index > MAX_INDEX)
+ rts_error(VARLSTCNT(4) ERR_BADJPIPARAM, 2, keyword->str.len, keyword->str.addr );
+ /* Before checking if it is a VMS JPI attribute, check if it is GT.M specific "ISPROCALIVE" attribute */
+ if ((keyword->str.len == STR_LIT_LEN("ISPROCALIVE")) && !memcmp(upcase, "ISPROCALIVE", keyword->str.len))
+ {
+ out_long = (0 != jpid) ? is_proc_alive(jpid, 0) : 1;
+ i2mval(ret, out_long);
+ return;
+ }
+ /* Check if it is a VMS JPI attribute */
+ slot = jpi_index_table[ index ].index;
+ last_slot = jpi_index_table[ index ].len;
+ jpi_code = 0;
+ /* future enhancement:
+ * (i) since keywords are sorted, we can exit the for loop if 0 < memcmp.
+ * (ii) also, the current comparison relies on kwd->str.len which means a C would imply CPUTIM instead of CSTIME
+ * or CUTIME this ambiguity should probably be removed by asking for an exact match of the full keyword
+ */
+ for ( ; slot < last_slot ; slot++ )
+ {
+ if (jpi_param_table[ slot ].len == keyword->str.len
+ && !(memcmp(jpi_param_table[ slot ].name, upcase, keyword->str.len)))
+ {
+ jpi_code = jpi_param_table[ slot ].item_code;
+ break;
+ }
+ }
+ if (!jpi_code)
+ rts_error(VARLSTCNT(4) ERR_BADJPIPARAM, 2, keyword->str.len, keyword->str.addr);
+ assert (jpid >= 0);
+ switch( jpi_code )
+ {
+ /* **** This is a fall through for all codes that require a string returned **** */
+ case JPI$_ACCOUNT:
+ case JPI$_AUTHPRIV:
+ case JPI$_CLINAME:
+ case JPI$_CURPRIV:
+ case JPI$_IMAGNAME:
+ case JPI$_IMAGPRIV:
+ case JPI$_PRCNAM:
+ case JPI$_PROCPRIV:
+ case JPI$_TABLENAME:
+ case JPI$_TERMINAL:
+ case JPI$_USERNAME:
+ out_string.dsc$a_pointer = stringpool.free;
+ out_string.dsc$w_length = MAX_JPI_STRLEN;
+ if ((status = lib$getjpi( &jpi_code
+ ,&jpid
+ ,0
+ ,0
+ ,&out_string
+ ,&out_len )) != SS$_NORMAL)
+ { rts_error(VARLSTCNT(1) status ); /* need a more specific GTM error message here and below */
+ }
+ ret->str.addr = stringpool.free;
+ ret->str.len = out_len;
+ ret->mvtype = MV_STR;
+ stringpool.free += out_len;
+ assert (stringpool.top >= stringpool.free);
+ assert (stringpool.free >= stringpool.base);
+ return;
+ case JPI$_LOGINTIM:
+ { int4 days;
+ int4 seconds;
+
+ if ((status = lib$getjpi( &jpi_code
+ ,&jpid
+ ,0
+ ,&out_quad
+ ,0
+ ,0 )) != SS$_NORMAL)
+ { rts_error(VARLSTCNT(1) status );
+ }
+ if ((status = lib$day( &days
+ ,&out_quad
+ ,&seconds)) != SS$_NORMAL)
+ { rts_error(VARLSTCNT(1) status );
+ }
+ days += DAYS;
+ seconds /= CENTISECONDS;
+ ret->str.addr = stringpool.free;
+ stringpool.free = i2s(&days);
+ *stringpool.free++ = ',';
+ stringpool.free = i2s(&seconds);
+ ret->str.len = (char *) stringpool.free - ret->str.addr;
+ ret->mvtype = MV_STR;
+ return;
+ }
+ default:
+ if ((status = lib$getjpi( &jpi_code
+ ,&jpid
+ ,0
+ ,&out_long
+ ,0
+ ,0 )) != SS$_NORMAL)
+ { rts_error(VARLSTCNT(1) status );
+ }
+ i2mval(ret, out_long) ;
+ return;
+ }
+}
diff --git a/sr_vvms/op_fngetlki.c b/sr_vvms/op_fngetlki.c
new file mode 100644
index 0000000..190aa1c
--- /dev/null
+++ b/sr_vvms/op_fngetlki.c
@@ -0,0 +1,171 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <lkidef.h>
+#include "op_fn.h"
+#include "stringpool.h"
+#include <ssdef.h>
+#include <descrip.h>
+#include "gtm_caseconv.h"
+#include "mvalconv.h"
+#include "mval2desc.h"
+#include "op.h"
+
+#define MAX_KEY_LEN 12
+#define MAX_LKI_STRLEN 64
+#define MAX_LKI_VALBLK 16
+#define MIN_INDEX 0
+#define MAX_INDEX 25
+
+typedef struct
+{ char len;
+ char name[MAX_KEY_LEN];
+ short int item_code;
+} lki_tab;
+
+typedef struct
+{ char index;
+ char len;
+} lki_ind;
+
+static readonly lki_tab lki_param_table[] =
+{
+ { 4, "CSID", LKI$_CSID },
+ { 8, "CVTCOUNT", LKI$_CVTCOUNT },
+ { 10, "GRANTCOUNT", LKI$_GRANTCOUNT },
+ { 9, "LCKREFCNT", LKI$_LCKREFCNT },
+ { 4, "LKID", LKI$_LKID },
+ { 6, "LOCKID", LKI$_LOCKID },
+ { 7, "MSTCSID", LKI$_MSTCSID },
+ { 7, "MSTLKID", LKI$_MSTLKID },
+ { 8, "NAMSPACE", LKI$_NAMSPACE },
+ { 6, "PARENT", LKI$_PARENT },
+ { 3, "PID", LKI$_PID },
+ { 6, "RESNAM", LKI$_RESNAM },
+ { 9, "RSBREFCNT", LKI$_RSBREFCNT },
+ { 5, "STATE", LKI$_STATE },
+ { 6, "VALBLK", LKI$_VALBLK },
+ { 9, "WAITCOUNT", LKI$_WAITCOUNT }
+};
+
+static readonly lki_ind lki_index_table[] =
+{
+ { 0 , 0 }, { 0 , 0 }, { 0 , 2 }, { 0 , 0 }, { 0 , 0 }, { 0 , 0 }, { 2 , 3 },
+ { 0 , 0 }, { 0 , 0 }, { 0 , 0 }, { 0 , 0 }, { 3 , 6 }, { 6 , 8 }, { 8 , 9 },
+ { 0 , 0 }, { 9 , 11 }, { 0 , 0 }, { 11 , 13 }, { 13 , 14 }, { 0 , 0 }, { 0 , 0 },
+ { 14 , 15 }, { 15 , 16 }, { 0 , 0 }, { 0 , 0 }, { 0 , 0 }
+};
+
+GBLREF spdesc stringpool;
+
+error_def(ERR_BADLKIPARAM);
+
+
+void op_fngetlki(mval *lkid_mval, mval *keyword, mval *ret)
+{
+ itmlist_struct item_list;
+ int i;
+ uint4 lkid, out_long, out_len, status, value_block[4];
+ short int index, slot, last_slot, lki_code;
+ char *p, upcase[MAX_KEY_LEN];
+ struct dsc$descriptor lkid_desc;
+
+assert (stringpool.free >= stringpool.base);
+assert (stringpool.top >= stringpool.free);
+ENSURE_STP_FREE_SPACE(MAX_LKI_STRLEN);
+MV_FORCE_STR(keyword);
+if (keyword->str.len == 0)
+ rts_error(VARLSTCNT(4) ERR_BADLKIPARAM,2,4,"Null");
+lower_to_upper(upcase,keyword->str.addr,keyword->str.len);
+if ((index = upcase[0] - 'A') < MIN_INDEX || index > MAX_INDEX)
+ rts_error(VARLSTCNT(4) ERR_BADLKIPARAM,2,keyword->str.len,keyword->str.addr );
+slot = lki_index_table[ index ].index;
+last_slot = lki_index_table[ index ].len;
+lki_code = 0;
+for ( ; slot < last_slot ; slot++ )
+{
+ if (lki_param_table[ slot ].len == keyword->str.len
+ && !(memcmp(lki_param_table[ slot ].name,upcase,keyword->str.len)))
+ { lki_code = lki_param_table[ slot ].item_code;
+ break;
+ }
+}
+if (!lki_code)
+ rts_error(VARLSTCNT(4) ERR_BADLKIPARAM, 2, keyword->str.len, keyword->str.addr);
+lkid_desc.dsc$b_class = DSC$K_CLASS_S;
+lkid_desc.dsc$b_dtype = DSC$K_DTYPE_LU;
+lkid_desc.dsc$w_length = SIZEOF(lkid);
+lkid_desc.dsc$a_pointer = &lkid;
+mval2desc(lkid_mval, &lkid_desc);
+switch( lki_code )
+{
+case LKI$_VALBLK:
+ assert(stringpool.free >= stringpool.base);
+ assert(stringpool.top >= stringpool.free);
+ ENSURE_STP_FREE_SPACE(MAX_LKI_VALBLK*2);
+ item_list.itmcode = lki_code;
+ item_list.bufflen = MAX_LKI_VALBLK;
+ item_list.buffaddr = &value_block[0];
+ item_list.retlen = &out_len;
+ item_list.end = NULL;
+
+ if ((status = sys$getlkiw( 0, &lkid, &item_list, 0, 0, 0, 0)) != SS$_NORMAL)
+ { rts_error(VARLSTCNT(1) status );
+ }
+
+ for (p = stringpool.free, i = 0; i < 4; i++, p += 8)
+ i2hex (value_block[i], p, 8);
+
+ ret->mvtype = MV_STR;
+ ret->str.addr = stringpool.free;
+ ret->str.len = MAX_LKI_VALBLK*2;
+ stringpool.free += MAX_LKI_VALBLK*2;
+ assert (stringpool.free >= stringpool.base);
+ assert (stringpool.top >= stringpool.free);
+ return;
+
+case LKI$_RESNAM:
+ assert(stringpool.free >= stringpool.base);
+ assert(stringpool.top >= stringpool.free);
+ ENSURE_STP_FREE_SPACE(MAX_LKI_STRLEN);
+ item_list.itmcode = lki_code;
+ item_list.bufflen = MAX_LKI_STRLEN;
+ item_list.buffaddr = stringpool.free;
+ item_list.retlen = &out_len;
+ item_list.end = NULL;
+
+ if ((status = sys$getlkiw( 0, &lkid, &item_list, 0, 0, 0, 0)) != SS$_NORMAL)
+ { rts_error(VARLSTCNT(1) status );
+ }
+
+ ret->mvtype = MV_STR;
+ ret->str.addr = stringpool.free;
+ ret->str.len = out_len; /* Note: this truncates the irrelevant high order word of out_len */
+ stringpool.free += ret->str.len;
+ assert (stringpool.free >= stringpool.base);
+ assert (stringpool.top >= stringpool.free);
+ return;
+
+default:
+ item_list.itmcode = lki_code;
+ item_list.bufflen = 4;
+ item_list.buffaddr = &out_long;
+ item_list.retlen = &out_len;
+ item_list.end = 0;
+
+ if ((status = sys$getlkiw( 0, &lkid, &item_list, 0, 0, 0, 0)) != SS$_NORMAL)
+ { rts_error(VARLSTCNT(1) status );
+ }
+ i2mval(ret,out_long) ;
+ return;
+}
+}
diff --git a/sr_vvms/op_fngetsyi.c b/sr_vvms/op_fngetsyi.c
new file mode 100644
index 0000000..06be97d
--- /dev/null
+++ b/sr_vvms/op_fngetsyi.c
@@ -0,0 +1,181 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <syidef.h>
+#include <descrip.h>
+#include "stringpool.h"
+#include <ssdef.h>
+#include "op_fn.h"
+#include "min_max.h"
+#include "gtm_caseconv.h"
+#include "op.h"
+#include "mvalconv.h"
+
+#define MAX_SYI_STRLEN 32
+#define MAX_KW_LEN 20
+#define MAX_ND_LEN 64
+#define ZINDX 25 /* index for char 'Z' */
+#define ALFA(k) ('A'<=k && k<='Z')
+#define PROPER(status) if (status != SS$_NORMAL) { rts_error(VARLSTCNT(1) status) ;}
+
+typedef struct
+{
+ char kwlen ; /* item keyword length */
+ char kw[MAX_KW_LEN] ; /* item keyword */
+ unsigned short code ; /* syi code */
+ unsigned char valsiz ; /* size of item value */
+ unsigned char valtyp ; /* item type */
+}syi_item ;
+
+static readonly syi_item kw_syi[] =
+{
+ {13,"ACTIVECPU_CNT", SYI$_ACTIVECPU_CNT, 4, MV_NM}
+ ,{12,"AVAILCPU_CNT", SYI$_AVAILCPU_CNT, 4, MV_NM}
+ ,{ 8,"BOOTTIME", SYI$_BOOTTIME , 8, MV_STR}
+ ,{18,"CHARACTER_EMULATED",SYI$_CHARACTER_EMULATED,1, MV_NM}
+ ,{14,"CLUSTER_EVOTES", SYI$_CLUSTER_EVOTES, 2, MV_NM}
+ ,{14,"CLUSTER_FSYSID", SYI$_CLUSTER_FSYSID, 6, MV_NM}
+ ,{13,"CLUSTER_FTIME", SYI$_CLUSTER_FTIME, 8, MV_STR}
+ ,{14,"CLUSTER_MEMBER", SYI$_CLUSTER_MEMBER, 1, MV_NM}
+ ,{13,"CLUSTER_NODES", SYI$_CLUSTER_NODES, 2, MV_NM}
+ ,{14,"CLUSTER_QUORUM", SYI$_CLUSTER_QUORUM, 2, MV_STR}
+ ,{13,"CLUSTER_VOTES", SYI$_CLUSTER_VOTES, 2, MV_STR}
+ ,{15,"CONTIG_GBLPAGES", SYI$_CONTIG_GBLPAGES, 4, MV_NM}
+ ,{ 3,"CPU", SYI$_CPU, 4, MV_STR}
+ ,{16,"DECIMAL_EMULATED",SYI$_DECIMAL_EMULATED, 1, MV_NM}
+ ,{16,"D_FLOAT_EMULATED",SYI$_D_FLOAT_EMULATED, 1, MV_NM}
+ ,{15,"ERRORLOGBUFFERS", SYI$_ERRORLOGBUFFERS, 2, MV_NM}
+ ,{16,"F_FLOAT_EMULATED",SYI$_F_FLOAT_EMULATED, 1, MV_NM}
+ ,{13,"FREE_GBLPAGES", SYI$_FREE_GBLPAGES, 4, MV_NM}
+ ,{13,"FREE_GBLSECTS", SYI$_FREE_GBLSECTS, 4, MV_NM}
+ ,{16,"G_FLOAT_EMULATED",SYI$_G_FLOAT_EMULATED, 1, MV_NM}
+ ,{ 8,"HW_MODEL", SYI$_HW_MODEL, 2, MV_NM}
+ ,{ 7,"HW_NAME", SYI$_HW_NAME, 31, MV_STR}
+ ,{14,"H_FLOAT_EMULATED",SYI$_H_FLOAT_EMULATED, 1, MV_NM}
+ ,{ 9,"NODE_AREA", SYI$_NODE_AREA, 4, MV_STR}
+ ,{ 9,"NODE_CSID", SYI$_NODE_CSID, 4, MV_NM}
+ ,{11,"NODE_EVOTES", SYI$_NODE_EVOTES, 2, MV_NM}
+ ,{11,"NODE_HWVERS", SYI$_NODE_HWVERS, 12, MV_STR}
+ ,{11,"NODE_NUMBER", SYI$_NODE_NUMBER, 4, MV_STR}
+ ,{11,"NODE_QUORUM", SYI$_NODE_QUORUM, 2, MV_NM}
+ ,{13,"NODE_SWINCARN", SYI$_NODE_SWINCARN, 8, MV_STR}
+ ,{11,"NODE_SWTYPE", SYI$_NODE_SWTYPE, 4, MV_STR}
+ ,{11,"NODE_SWVERS", SYI$_NODE_SWVERS, 4, MV_STR}
+ ,{13,"NODE_SYSTEMID", SYI$_NODE_SYSTEMID, 6, MV_STR}
+ ,{10,"NODE_VOTES", SYI$_NODE_VOTES, 2, MV_NM}
+ ,{ 8,"NODENAME", SYI$_NODENAME, 15, MV_STR}
+ ,{13,"PAGEFILE_FREE", SYI$_PAGEFILE_FREE, 4, MV_NM}
+ ,{13,"PAGEFILE_PAGE", SYI$_PAGEFILE_PAGE, 4, MV_NM}
+ ,{10,"SCS_EXISTS", SYI$_SCS_EXISTS, 4, MV_NM}
+ ,{ 3,"SID", SYI$_SID, 4, MV_STR}
+ ,{13,"SWAPFILE_FREE", SYI$_SWAPFILE_FREE, 4, MV_NM}
+ ,{13,"SWAPFILE_PAGE", SYI$_SWAPFILE_PAGE, 4, MV_NM}
+ ,{ 7,"VERSION", SYI$_VERSION, 8, MV_STR}
+ ,{ 4,"XCPU", SYI$_XCPU, 4, MV_STR}
+ ,{ 4,"XSID", SYI$_XSID, 4, MV_STR}
+} ;
+
+static readonly unsigned char kw_syi_index[] =
+{
+ 0,2,3,13,14,15,18,19,22,22,22,22,22,22,35,35,37,37,37,41,41,41,42,42,44,44,44
+} ;
+
+GBLREF spdesc stringpool;
+
+void op_fngetsyi(mval *keyword,mval *node,mval *ret)
+{
+ error_def (ERR_BADSYIPARAM) ;
+ error_def (ERR_AMBISYIPARAM) ;
+ char bufw[MAX_KW_LEN] ;
+ char bufn[MAX_ND_LEN] ;
+ short bufwlen ;
+ short bufnlen ;
+ $DESCRIPTOR (res_str,stringpool.free) ;
+ $DESCRIPTOR (dnode,bufn) ;
+ uint4 res_val[2] ;
+ short res_len ;
+ unsigned char *pnode ;
+ unsigned char k,j ;
+ bool match ;
+ int4 item ;
+ uint4 status ;
+ mval *tmp ;
+
+ assert(stringpool.top >= stringpool.free);
+ assert(stringpool.free >= stringpool.base);
+ MV_FORCE_STR(node);
+ MV_FORCE_STR(keyword);
+ ENSURE_STP_FREE_SPACE(MAX_SYI_STRLEN);
+ bufwlen = MIN(keyword->str.len,SIZEOF(bufw)) ;
+ bufnlen = MIN(node->str.len,SIZEOF(bufn)) ;
+ lower_to_upper(bufw,keyword->str.addr,bufwlen) ;
+ lower_to_upper(bufn,node->str.addr,bufnlen) ;
+ dnode.dsc$w_length = bufnlen ;
+ pnode = ((node->str.len != 0) ? &dnode : NULL) ;
+ k = bufw[0] ;
+ k = ( ALFA(k) ? k - 'A' : ZINDX ) ;
+ match = FALSE ;
+ for ( j = kw_syi_index[k] ; !match && j!=kw_syi_index[k+1] ; j++ )
+ {
+ match = (keyword->str.len<=kw_syi[j].kwlen && !memcmp(bufw,kw_syi[j].kw,keyword->str.len)) ;
+ }
+ if (!match)
+ {
+ rts_error(VARLSTCNT(4) ERR_BADSYIPARAM,2,keyword->str.len,keyword->str.addr) ;
+ return ;
+ }
+ else
+ {
+ if (j!=kw_syi_index[k+1] && keyword->str.len<=kw_syi[j].kwlen && !memcmp(bufw,kw_syi[j].kw,keyword->str.len))
+ {
+ rts_error(VARLSTCNT(4) ERR_AMBISYIPARAM,2,keyword->str.len,keyword->str.addr) ;
+ return ;
+ }
+ else
+ {
+ item = kw_syi[j-1].code ;
+ res_str.dsc$w_length = MAX_SYI_STRLEN ;
+ res_str.dsc$a_pointer = stringpool.free ;
+ status = lib$getsyi(&item,res_val,&res_str,&res_len,0,pnode) ;
+ PROPER(status) ;
+ ret->mvtype = kw_syi[j-1].valtyp ;
+ }
+ }
+ if (item != SYI$_BOOTTIME && item != SYI$_CLUSTER_FTIME)
+ {
+ ret->str.addr = stringpool.free ;
+ ret->str.len = res_len ;
+ stringpool.free += res_len ;
+ }
+ else
+ {
+ int4 day ;
+ int4 sec ;
+ status = lib$day(&day,res_val,&sec) ;
+ PROPER(status) ;
+ day += DAYS;
+ sec /= CENTISECONDS;
+ ret->str.addr = stringpool.free;
+ stringpool.free = i2s(&day) ;
+ *stringpool.free++ = ',' ;
+ stringpool.free = i2s(&sec) ;
+ ret->str.len = (char *) stringpool.free - ret->str.addr;
+ assert(stringpool.free >= stringpool.base);
+ assert(stringpool.top >= stringpool.free);
+ }
+ if (MV_IS_NUMERIC(ret))
+ {
+ i2mval(ret,res_val[0]) ;
+ }
+ assert (stringpool.top >= stringpool.free);
+}
diff --git a/sr_vvms/op_fnrandom.c b/sr_vvms/op_fnrandom.c
new file mode 100644
index 0000000..aae4345
--- /dev/null
+++ b/sr_vvms/op_fnrandom.c
@@ -0,0 +1,40 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <lib$routines.h>
+#include "gtm_stdlib.h"
+#include "gtm_string.h"
+
+#include "mvalconv.h"
+
+GBLREF int4 process_id;
+
+error_def(ERR_RANDARGNEG);
+
+void op_fnrandom (int4 interval, mval *ret)
+{
+ static int4 seed = 0;
+ int4 day;
+ double randfloat;
+
+ if (1 > interval)
+ rts_error(VARLSTCNT(1) ERR_RANDARGNEG);
+ if (0 == seed)
+ {
+ lib$day(&day, 0, &seed);
+ seed *= process_id;
+ srandom(seed);
+ }
+ randfloat = ((double)random()) / RAND_MAX;
+ MV_FORCE_MVAL(ret, ((uint4)(interval * randfloat)));
+}
diff --git a/sr_vvms/op_fnzcall.c b/sr_vvms/op_fnzcall.c
new file mode 100644
index 0000000..f449b7a
--- /dev/null
+++ b/sr_vvms/op_fnzcall.c
@@ -0,0 +1,86 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "zcall.h"
+#include <stdarg.h>
+
+GBLREF zctabrtn *zctab, *zctab_end;
+
+void op_fnzcall(mval *dst, ...)
+{
+ va_list var;
+ mval *v;
+ int4 n_mvals; /* number of input parameters supplied in $ZCALL command */
+ int i;
+ mval *mvallist[256];
+ zctabrtn *zcrtn;
+ unsigned char *lastout;
+ error_def (ERR_ZCALLTABLE);
+ error_def (ERR_ZCRTENOTF);
+ error_def (ERR_ZCARGMSMTCH);
+
+
+ VAR_START(var, dst);
+ va_count(n_mvals);
+ v = va_arg(var, mval *);
+ MV_FORCE_STR(v);
+
+ zcrtn = zctab;
+ while (zcrtn < zctab_end)
+ {
+ if (!zcrtn->entry_length)
+ {
+ va_end(var);
+ rts_error(VARLSTCNT(1) ERR_ZCALLTABLE);
+ }
+ if (zcrtn->callnamelen == 0)
+ {
+ va_end(var);
+ rts_error(VARLSTCNT(1) ERR_ZCALLTABLE);
+ }
+ if ((zcrtn->callnamelen == v->str.len) &&
+ !memcmp (zcrtn->callname, v->str.addr, v->str.len))
+ break;
+ zcrtn = (zctabrtn *) ((char *) zcrtn + zcrtn->entry_length);
+ }
+
+ if (zcrtn == zctab_end)
+ {
+ va_end(var);
+ rts_error(VARLSTCNT(4) ERR_ZCRTENOTF, 2, v->str.len, v->str.addr);
+ }
+
+ n_mvals -= 2;
+ if (n_mvals > zcrtn->n_inputs)
+ {
+ va_end(var);
+ rts_error(VARLSTCNT(4) ERR_ZCARGMSMTCH, 2, n_mvals, zcrtn->n_inputs);
+ }
+
+ lastout = (unsigned char *) zcrtn
+ + ROUND_UP(SIZEOF(zctabrtn) + zcrtn->callnamelen - 1 + SIZEOF(zctabret), SIZEOF(int4))
+ + zcrtn->n_inputs * SIZEOF(zctabinput)
+ + zcrtn->n_outputs * SIZEOF(zctaboutput);
+
+ if (ROUND_UP((int) lastout + 1, SIZEOF(int4)) != (unsigned char *) zcrtn + zcrtn->entry_length)
+ {
+ va_end(var);
+ rts_error(VARLSTCNT(1) ERR_ZCALLTABLE);
+ }
+
+ for (i = 0; i < n_mvals; ++i)
+ mvallist[i] = va_arg(var, mval *);
+ va_end(var);
+
+ zc_makespace (dst, 0, mvallist, &mvallist[n_mvals], zcrtn, *lastout);
+ return;
+}
diff --git a/sr_vvms/op_fnzfile.c b/sr_vvms/op_fnzfile.c
new file mode 100644
index 0000000..2d8b2a7
--- /dev/null
+++ b/sr_vvms/op_fnzfile.c
@@ -0,0 +1,496 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <ssdef.h>
+#include <rms.h>
+
+#include "stringpool.h"
+#include "min_max.h"
+#include "gtm_caseconv.h"
+#include "mvalconv.h"
+#include "op.h"
+
+GBLREF spdesc stringpool;
+
+#define ZF_ALQ 0
+#define ZF_BDT 1
+#define ZF_BKS 2
+#define ZF_BLS 3
+#define ZF_CBT 4
+#define ZF_CDT 5
+#define ZF_CTG 6
+#define ZF_DEQ 7
+#define ZF_DID 8
+#define ZF_DVI 9
+#define ZF_EDT 10
+#define ZF_EOF 11
+#define ZF_FID 12
+#define ZF_FSZ 13
+#define ZF_GRP 14
+#define ZF_KNO 15
+#define ZF_MBM 16
+#define ZF_MRN 17
+#define ZF_MRS 18
+#define ZF_NOA 19
+#define ZF_NOK 20
+#define ZF_ORG 21
+#define ZF_PRO 22
+#define ZF_PVN 23
+#define ZF_RAT 24
+#define ZF_RCK 25
+#define ZF_RDT 26
+#define ZF_RFM 27
+#define ZF_RVN 28
+#define ZF_UIC 29
+#define ZF_WCK 30
+
+#define KEY_LEN 3
+#define MAX_ZF_LEN 128
+#define PRO_GRP_LEN 3
+#define PRO_MBM_LEN 5
+#define ORG_LEN 3
+#define RAT_LEN 3
+#define RAT_CR_LEN 2
+#define RFM_LEN 3
+#define RFM_STM_LEN 5
+#define MIN_ZF_INDEX 0
+#define MAX_ZF_INDEX 25
+#define PRO_FLDS 4
+#define ACC_FLDS 4
+#define FLD_SZ 4
+
+#define MAX_KW_LEN 8
+
+typedef struct
+{ char *name;
+}zfile_key_struct;
+
+static readonly zfile_key_struct zfile_key[] =
+{
+ "ALQ","BDT","BKS","BLS","CBT","CDT","CTG","DEQ","DID","DVI","EDT","EOF","FID",
+ "FSZ","GRP","KNO","MBM","MRN","MRS","NOA","NOK","ORG","PRO","PVN","RAT","RCK",
+ "RDT","RFM","RVN","UIC","WCK"
+};
+
+typedef struct
+{ char index;
+ char last_index;
+}zfile_index_struct;
+
+static readonly zfile_index_struct zfile_index[] =
+{
+ {0,1},{1,4},{4,7},{7,10},{10,12},{12,14},{14,15},{0,0},{0,0},{0,0},{15,16},{0,0},
+ {16,19},{19,21},{21,22},{22,24},{0,0},{24,29},{0,0},{0,0},{29,30},{0,0},{30,31},
+ {0,0},{0,0},{0,0}
+};
+
+typedef struct
+{ unsigned x;
+ unsigned y;
+}quad_struct;
+
+void op_fnzfile(mval *name,mval *key,mval *ret)
+{
+ struct NAM nm;
+ struct XABDAT dat;
+ struct XABSUM sum;
+ struct XABPRO pro;
+ struct XABFHC fhc;
+ quad_struct *bdt;
+ quad_struct *cdt;
+ quad_struct *edt;
+ quad_struct *rdt;
+ int4 days;
+ int4 seconds;
+ error_def(ERR_ZFILNMBAD);
+ error_def(ERR_ZFILKEYBAD);
+ struct FAB f;
+ int4 status;
+ char index,slot,last_slot;
+ char buf[MAX_KW_LEN] ;
+
+ assert(stringpool.free >= stringpool.base);
+ assert(stringpool.top >= stringpool.free);
+ MV_FORCE_STR(name);
+ if (name->str.len == 0)
+ { rts_error(VARLSTCNT(4) ERR_ZFILNMBAD,2,4,"NULL");
+ }
+ MV_FORCE_STR(key);
+ if (key->str.len == 0 || key->str.len != KEY_LEN)
+ { rts_error(VARLSTCNT(4) ERR_ZFILKEYBAD,2,key->str.len,key->str.addr);
+ }
+ lower_to_upper(buf,key->str.addr,MIN(key->str.len,MAX_KW_LEN)) ;
+ nm = cc$rms_nam;
+ dat = cc$rms_xabdat;
+ sum = cc$rms_xabsum;
+ pro = cc$rms_xabpro;
+ fhc = cc$rms_xabfhc;
+ bdt = &(dat.xab$q_bdt);
+ cdt = &(dat.xab$q_cdt);
+ edt = &(dat.xab$q_edt);
+ rdt = &(dat.xab$q_rdt);
+ dat.xab$l_nxt = ∑
+ sum.xab$l_nxt = &pro;
+ pro.xab$l_nxt = &fhc;
+ if ((index = buf[0] - 'A') < MIN_ZF_INDEX || index > MAX_ZF_INDEX)
+ rts_error(VARLSTCNT(4) ERR_ZFILKEYBAD,2,key->str.len,key->str.addr);
+ if (!(last_slot = zfile_index[ index ].last_index))
+ rts_error(VARLSTCNT(4) ERR_ZFILKEYBAD,2,key->str.len,key->str.addr);
+ slot = zfile_index[ index ].index;
+ for ( ; slot < last_slot ; slot++ )
+ {
+ if (!memcmp(zfile_key[slot].name,buf,3))
+ { break;
+ }
+ }
+ if (slot == last_slot)
+ rts_error(VARLSTCNT(4) ERR_ZFILKEYBAD,2,key->str.len,key->str.addr);
+ f = cc$rms_fab;
+ f.fab$b_shr = FAB$M_SHRPUT | FAB$M_SHRGET | FAB$M_SHRDEL | FAB$M_SHRUPD;
+ f.fab$l_nam = &nm;
+ f.fab$l_xab = &dat;
+ f.fab$l_fna = name->str.addr;
+ f.fab$b_fns = name->str.len;
+ if ((status = sys$open(&f)) != RMS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+ ENSURE_STP_FREE_SPACE(MAX_ZF_LEN);
+ switch( slot )
+ {
+ case ZF_ALQ:
+ i2mval(ret,f.fab$l_alq) ;
+ break;
+ case ZF_BDT:
+ { ret->mvtype = MV_STR;
+ if (!bdt->x && !bdt->y)
+ { ret->str.len = 0;
+ break;
+ }
+ if ((status= lib$day( &days, bdt, &seconds )) != SS$_NORMAL)
+ { rts_error(VARLSTCNT(1) status );
+ }
+ days += DAYS;
+ seconds /= CENTISECONDS;
+ ret->str.addr = stringpool.free;
+ stringpool.free = i2s(&days);
+ *stringpool.free++ = ',';
+ stringpool.free = i2s(&seconds);
+ ret->str.len = (char *) stringpool.free - ret->str.addr;
+ assert(stringpool.free >= stringpool.base);
+ assert(stringpool.top >= stringpool.free);
+
+ break;
+ }
+ case ZF_BKS:
+ i2mval(ret,f.fab$b_bks) ;
+ break;
+ case ZF_BLS:
+ i2mval(ret,f.fab$w_bls) ;
+ break;
+ case ZF_CBT:
+ i2mval (ret,(f.fab$l_fop & FAB$M_CBT ? 1 : 0 )) ;
+ break;
+ case ZF_CDT:
+ {
+ if ((status= lib$day( &days, cdt, &seconds )) != SS$_NORMAL)
+ { rts_error(VARLSTCNT(1) status );
+ }
+ days += DAYS;
+ seconds /= CENTISECONDS;
+ ret->mvtype = MV_STR;
+ ret->str.addr = stringpool.free;
+ stringpool.free = i2s(&days);
+ *stringpool.free++ = ',';
+ stringpool.free = i2s(&seconds);
+ ret->str.len = (char *) stringpool.free - ret->str.addr;
+ assert(stringpool.free >= stringpool.base);
+ assert(stringpool.top >= stringpool.free);
+ break;
+ }
+ case ZF_CTG:
+ i2mval (ret,(f.fab$l_fop & FAB$M_CTG ? 1 : 0 )) ;
+ break;
+ case ZF_DEQ:
+ i2mval(ret,f.fab$w_deq) ;
+ break;
+ case ZF_DID:
+ { int4 did;
+
+ ret->mvtype = MV_STR;
+ ret->str.addr = stringpool.free;
+ did = nm.nam$w_did[0];
+ stringpool.free = i2s(&did);
+ *stringpool.free++ = ',';
+ did = nm.nam$w_did[1];
+ stringpool.free = i2s(&did);
+ *stringpool.free++ = ',';
+ did = nm.nam$w_did[2];
+ stringpool.free = i2s(&did);
+ ret->str.len = (char *) stringpool.free - ret->str.addr;
+ assert(stringpool.free >= stringpool.base);
+ assert(stringpool.top >= stringpool.free);
+ break;
+ }
+ case ZF_DVI:
+ ret->mvtype = MV_STR;
+ ret->str.addr = stringpool.free;
+ memcpy(stringpool.free,&(nm.nam$t_dvi[1]),nm.nam$t_dvi[0]);
+ ret->str.len = nm.nam$t_dvi[0];
+ stringpool.free += ret->str.len;
+ break;
+ case ZF_EDT:
+ { ret->mvtype = MV_STR;
+ if (!edt->x && !edt->y)
+ { ret->str.len = 0;
+ break;
+ }
+ if ((status= lib$day( &days
+ ,edt
+ ,&seconds )) != SS$_NORMAL)
+ { rts_error(VARLSTCNT(1) status );
+ }
+ days += DAYS;
+ seconds /= CENTISECONDS;
+ ret->mvtype = MV_STR;
+ ret->str.addr = stringpool.free;
+ stringpool.free = i2s(&days);
+ *stringpool.free++ = ',';
+ stringpool.free = i2s(&seconds);
+ ret->str.len = (char *) stringpool.free - ret->str.addr;
+ assert(stringpool.free >= stringpool.base);
+ assert(stringpool.top >= stringpool.free);
+ break;
+ }
+ case ZF_EOF:
+ i2mval(ret,fhc.xab$l_ebk - 1) ;
+ break;
+ case ZF_FID:
+ { int4 fid;
+
+ ret->mvtype = MV_STR;
+ ret->str.addr = stringpool.free;
+ fid = nm.nam$w_fid[0];
+ stringpool.free = i2s(&fid);
+ *stringpool.free++ = ',';
+ fid = nm.nam$w_fid[1];
+ stringpool.free = i2s(&fid);
+ *stringpool.free++ = ',';
+ fid = nm.nam$w_fid[2];
+ stringpool.free = i2s(&fid);
+ ret->str.len = (char *) stringpool.free - ret->str.addr;
+ assert(stringpool.free >= stringpool.base);
+ assert(stringpool.top >= stringpool.free);
+ break;
+ }
+ case ZF_FSZ:
+ i2mval(ret,f.fab$b_fsz) ;
+ break;
+ case ZF_GRP:
+ { char *pro_ptr;
+
+ pro_ptr = ((char *)&pro + XAB$C_PROLEN - PRO_GRP_LEN);
+ i2mval(ret,*(short *)pro_ptr) ;
+ break;
+ }
+ case ZF_KNO:
+ ret->mvtype = MV_STR;
+ ret->str.len = 0;
+ break;
+ case ZF_MBM:
+ { char *pro_ptr;
+ pro_ptr = ((char *)&pro + XAB$C_PROLEN - PRO_MBM_LEN);
+ i2mval(ret,*(short *)pro_ptr) ;
+ break;
+ }
+ case ZF_MRN:
+ i2mval(ret,f.fab$l_mrn) ;
+ break;
+ case ZF_MRS:
+ i2mval(ret,f.fab$w_mrs) ;
+ break;
+ case ZF_NOA:
+ i2mval(ret,sum.xab$b_noa) ;
+ break;
+ case ZF_NOK:
+ i2mval(ret,sum.xab$b_nok) ;
+ break;
+ case ZF_ORG:
+ ret->mvtype = MV_STR;
+ ret->str.addr = stringpool.free;
+ if (f.fab$b_org == FAB$C_SEQ)
+ { memcpy(stringpool.free,"SEQ",ORG_LEN);
+ }
+ else if (f.fab$b_org == FAB$C_REL)
+ { memcpy(stringpool.free,"REL",ORG_LEN);
+ }
+ else if (f.fab$b_org == FAB$C_IDX)
+ { memcpy(stringpool.free,"IDX",ORG_LEN);
+ }
+ else if (f.fab$b_org == FAB$C_HSH)
+ { memcpy(stringpool.free,"HSH",ORG_LEN);
+ }
+ ret->str.len = ORG_LEN;
+ stringpool.free += ORG_LEN;
+ break;
+ case ZF_PRO:
+ { unsigned short mask;
+ char x,i;
+
+ x = XAB$V_SYS;
+ mask = pro.xab$w_pro;
+ ret->str.addr = stringpool.free;
+ ret->mvtype = MV_STR;
+ for ( x = 0 ; x < PRO_FLDS ;x++ )
+ { if (x)
+ { *stringpool.free++ = ',';
+ }
+ for (i = 0 ; i < ACC_FLDS ; i++ )
+ { switch(i)
+ {
+ case XAB$V_NOREAD:
+ if ((mask & XAB$M_NOREAD) == 0)
+ { *stringpool.free++ = 'R';
+ }
+ break;
+ case XAB$V_NOWRITE:
+ if ((mask & XAB$M_NOWRITE) == 0)
+ { *stringpool.free++ = 'W';
+ }
+ break;
+ case XAB$V_NOEXE:
+ if ((mask & XAB$M_NOEXE) == 0)
+ { *stringpool.free++ = 'E';
+ }
+ break;
+ case XAB$V_NODEL:
+ if ((mask & XAB$M_NODEL) == 0)
+ { *stringpool.free++ = 'D';
+ }
+ break;
+ }
+ }
+ mask = (mask >> FLD_SZ);
+ }
+ ret->str.len = (char *) stringpool.free - ret->str.addr;
+ break;
+ }
+ case ZF_PVN:
+ i2mval(ret,sum.xab$w_pvn) ;
+ break;
+ case ZF_RAT:
+ ret->mvtype = MV_STR;
+ ret->str.addr = stringpool.free;
+ if (f.fab$b_rat & FAB$M_BLK)
+ { memcpy(stringpool.free,"BLK",RAT_LEN);
+ stringpool.free += RAT_LEN;
+ *stringpool.free++ = ',';
+ }
+ if (f.fab$b_rat & FAB$M_CR)
+ { memcpy(stringpool.free,"CR",RAT_CR_LEN);
+ stringpool.free += RAT_CR_LEN;
+ *stringpool.free++ = ',';
+ }
+ if (f.fab$b_rat & FAB$M_FTN)
+ { memcpy(stringpool.free,"FTN",RAT_LEN);
+ stringpool.free += RAT_LEN;
+ *stringpool.free++ = ',';
+ }
+ if (f.fab$b_rat & FAB$M_PRN)
+ { memcpy(stringpool.free,"PRN",RAT_LEN);
+ stringpool.free += RAT_LEN;
+ *stringpool.free++ = ',';
+ }
+ if (stringpool.free != ret->str.addr)
+ { stringpool.free--;
+ }
+ ret->str.len = (char *) stringpool.free - ret->str.addr;
+ break;
+ case ZF_RCK:
+ i2mval(ret, (f.fab$l_fop & FAB$M_RCK ? 1 : 0 )) ;
+ break;
+ case ZF_RDT:
+ { ret->mvtype = MV_STR;
+ if (!rdt->x && !rdt->y)
+ { ret->str.len = 0;
+ break;
+ }
+ if ((status= lib$day( &days
+ ,rdt
+ ,&seconds )) != SS$_NORMAL)
+ { rts_error(VARLSTCNT(1) status );
+ }
+ days += DAYS;
+ seconds /= CENTISECONDS;
+ ret->str.addr = stringpool.free;
+ stringpool.free = i2s(&days);
+ *stringpool.free++ = ',';
+ stringpool.free = i2s(&seconds);
+ ret->str.len = (char *) stringpool.free - ret->str.addr;
+ assert(stringpool.free >= stringpool.base);
+ assert(stringpool.top >= stringpool.free);
+ break;
+ }
+ case ZF_RFM:
+ ret->mvtype = MV_STR;
+ ret->str.addr = stringpool.free;
+ switch( f.fab$b_rfm )
+ {
+ case FAB$C_FIX:
+ memcpy(stringpool.free,"FIX",RFM_LEN);
+ stringpool.free += RFM_LEN;
+ break;
+ case FAB$C_STM:
+ memcpy(stringpool.free,"STM",RFM_LEN);
+ stringpool.free += RFM_LEN;
+ break;
+ case FAB$C_STMCR:
+ memcpy(stringpool.free,"STMCR",RFM_STM_LEN);
+ stringpool.free += RFM_STM_LEN;
+ break;
+ case FAB$C_STMLF:
+ memcpy(stringpool.free,"STMLF",RFM_STM_LEN);
+ stringpool.free += RFM_STM_LEN;
+ break;
+ case FAB$C_UDF:
+ memcpy(stringpool.free,"UDF",RFM_LEN);
+ stringpool.free += RFM_LEN;
+ break;
+ case FAB$C_VAR:
+ memcpy(stringpool.free,"VAR",RFM_LEN);
+ stringpool.free += RFM_LEN;
+ break;
+ case FAB$C_VFC:
+ memcpy(stringpool.free,"VFC",RFM_LEN);
+ stringpool.free += RFM_LEN;
+ break;
+ default:
+ assert(0);
+ }
+ ret->str.len = (char *) stringpool.free - ret->str.addr;
+ break;
+ case ZF_RVN:
+ i2mval(ret,dat.xab$w_rvn) ;
+ break;
+ case ZF_UIC:
+ i2mval(ret,pro.xab$l_uic) ;
+ break;
+ case ZF_WCK:
+ i2mval(ret,(f.fab$l_fop & FAB$M_WCK ? 1 : 0 )) ;
+ break;
+ default:
+ assert(0);
+ }
+ if ((status = sys$close(&f)) != RMS$_NORMAL)
+ { rts_error(VARLSTCNT(1) status );
+ }
+ return;
+}
diff --git a/sr_vvms/op_fnzlkid.c b/sr_vvms/op_fnzlkid.c
new file mode 100644
index 0000000..c2f1c14
--- /dev/null
+++ b/sr_vvms/op_fnzlkid.c
@@ -0,0 +1,52 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "op_fn.h"
+#include <lkidef.h>
+#include <ssdef.h>
+#include "op.h"
+#include "mvalconv.h"
+
+static bool lock_used = FALSE;
+
+void op_fnzlkid (mint boolex, mval *retval)
+{
+error_def(ERR_ZLKIDBADARG);
+static itmlist_struct item_list;
+static int4 lock_id = -1;
+static int4 out_value;
+static int4 out_len;
+static int4 status;
+
+ if (!lock_used && boolex)
+ rts_error(VARLSTCNT(1) ERR_ZLKIDBADARG);
+
+ if (!boolex) lock_id = -1;
+ item_list.itmcode = LKI$_LOCKID;
+ item_list.bufflen = 4;
+ item_list.buffaddr = &out_value;
+ item_list.retlen = &out_len;
+ item_list.end = 0;
+ if ((status = sys$getlkiw (0, &lock_id, &item_list, 0, 0, 0, 0)) == SS$_NORMAL)
+ {
+ i2mval(retval,out_value) ;
+ lock_used = TRUE;
+ }
+ else
+ {
+ if (status != SS$_NOMORELOCK) rts_error(VARLSTCNT(1) status);
+ retval->mvtype = MV_STR;
+ retval->str.addr = 0;
+ retval->str.len = 0;
+ lock_used = FALSE;
+ }
+}
diff --git a/sr_vvms/op_fnzp1.c b/sr_vvms/op_fnzp1.c
new file mode 100644
index 0000000..da5ffcf
--- /dev/null
+++ b/sr_vvms/op_fnzp1.c
@@ -0,0 +1,219 @@
+/****************************************************************
+ * *
+ * Copyright 2006, 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. *
+ * *
+ ****************************************************************/
+
+/*
+ * -----------------------------------------------
+ * op_fnzp1 $ZPIece function (the piecemaker) (and non-unicode $PIECE)
+ * Special case of 1 char delimiter and 1 piece (reference)
+ *
+ * Arguments:
+ * src - pointer to Source mval
+ * del - delimiter char to use looking for a piece
+ * trgpcidx - index of piece to extract from source string
+ * dst - pointer to Destination mval to save the piece in
+ *
+ * Return:
+ * none
+ *
+ * Side effects:
+ * dst structure gets filled with the result
+ * -----------------------------------------------
+ */
+
+
+#include "mdef.h"
+
+#include "fnpc.h"
+#include "min_max.h"
+#include "op.h"
+
+GBLREF boolean_t badchar_inhibit; /* Not recognizing bad characters in UTF8 */
+
+#ifdef DEBUG
+GBLREF uint4 process_id;
+GBLREF boolean_t setp_work; /* The work we are doing is for set $piece */
+GBLREF int c_miss; /* cache misses (debug) */
+GBLREF int c_hit; /* cache hits (debug) */
+GBLREF int c_small; /* scanned small string brute force */
+GBLREF int c_small_pcs; /* chars scanned by small scan */
+GBLREF int c_pskip; /* number of pieces "skipped" */
+GBLREF int c_pscan; /* number of pieces "scanned" */
+GBLREF int c_parscan; /* number of partial scans (partial cache hits) */
+GBLREF int cs_miss; /* cache misses (debug) */
+GBLREF int cs_hit; /* cache hits (debug) */
+GBLREF int cs_small; /* scanned small string brute force */
+GBLREF int cs_small_pcs; /* chars scanned by small scan */
+GBLREF int cs_pskip; /* number of pieces "skipped" */
+GBLREF int cs_pscan; /* number of pieces "scanned" */
+GBLREF int cs_parscan; /* number of partial scans (partial cache hits) */
+GBLREF int c_clear; /* cleared due to (possible) value change */
+# define COUNT_EVENT(x) if (setp_work) ++cs_##x; else ++c_##x;
+# define INCR_COUNT(x,y) if (setp_work) cs_##x += y; else c_##x += y;
+#else
+# define COUNT_EVENT(x)
+# define INCR_COUNT(x,y)
+#endif
+
+void op_fnzp1(mval *src, int delim, int trgpcidx, mval *dst, boolean_t srcisliteral)
+{
+ unsigned char *first, *last, *start, *end;
+ unsigned char dlmc;
+ unsigned int *pcoff, *pcoffmax, fnpc_indx, slen;
+ int trgpc, cpcidx, spcidx;
+ fnpc *cfnpc;
+ delimfmt ldelim;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ MV_FORCE_STR(src);
+ dst->mvtype = MV_STR;
+ ldelim.unichar_val = delim;
+ dlmc = ldelim.unibytes_val[0];
+ assert(0 == ldelim.unibytes_val[1] && 0 == ldelim.unibytes_val[2] &&
+ 0 == ldelim.unibytes_val[3]); /* delimiter should be 1-byte char */
+ start = first = last = (unsigned char *)src->str.addr;
+ slen = src->str.len;
+ end = start + slen;
+
+ /* Detect annoyance cases and deal with quickly so we don't muck up the
+ logic below trying to handle it properly */
+ if (0 >= trgpcidx || 0 == slen)
+ {
+ dst->str.addr = (char *)start;
+ dst->str.len = 0;
+ return;
+ }
+
+ /* If the string length meets our minimum requirements, lets play
+ "What's in my cache" */
+ if (FNPC_STRLEN_MIN < slen && !srcisliteral)
+ {
+ /* Test mval for valid cache: index ok, mval addr same, delim same */
+ fnpc_indx = src->fnpc_indx - 1;
+ cfnpc = &(TREF(fnpca)).fnpcs[fnpc_indx];
+ if (FNPC_MAX > fnpc_indx && cfnpc->last_str.addr == (char *)first &&
+ cfnpc->last_str.len == slen && cfnpc->delim == ldelim.unichar_val)
+ {
+ assert(cfnpc->byte_oriented);
+ /* Have valid cache. See if piece we want already in cache */
+ COUNT_EVENT(hit);
+ INCR_COUNT(pskip, cfnpc->npcs);
+
+ if (trgpcidx <= cfnpc->npcs)
+ {
+ /* Piece is totally in cache no scan needed */
+ dst->str.addr = (char *)first + cfnpc->pstart[trgpcidx - 1];
+ dst->str.len = cfnpc->pstart[trgpcidx] - cfnpc->pstart[trgpcidx - 1] - 1;
+ assert(dst->str.len >= 0 && dst->str.len <= src->str.len);
+ return;
+ } else
+ {
+ /* Not in cache but pick up scan where we left off */
+ cpcidx = cfnpc->npcs;
+ first = last = start + cfnpc->pstart[cpcidx]; /* First char of next pc */
+ pcoff = &cfnpc->pstart[cpcidx];
+ if (pcoff == cfnpc->pcoffmax)
+ ++pcoff; /* No further updates to pstart array */
+ ++cpcidx; /* Now past last piece and on to next one */
+ COUNT_EVENT(parscan);
+ }
+ } else
+ {
+ /* The piece cache index or mval validation was incorrect.
+ Start from the beginning */
+
+ COUNT_EVENT(miss);
+
+ /* Need to steal a new piece cache, get "least recently reused" */
+ cfnpc = (TREF(fnpca)).fnpcsteal; /* Get next element to steal */
+ if ((TREF(fnpca)).fnpcmax < cfnpc)
+ cfnpc = &(TREF(fnpca)).fnpcs[0];
+ (TREF(fnpca)).fnpcsteal = cfnpc + 1; /* -> next element to steal */
+
+ cfnpc->last_str = src->str; /* Save validation info */
+ cfnpc->delim = ldelim.unichar_val;
+ cfnpc->npcs = 0;
+ cfnpc->byte_oriented = TRUE;
+ src->fnpc_indx = cfnpc->indx + 1; /* Save where we are putting this element
+ (1 based index in mval so 0 isn't so common) */
+ pcoff = &cfnpc->pstart[0];
+ cpcidx = 1; /* current piece index */
+ }
+
+ /* Do scan filling in offsets of pieces if they fit in the cache */
+ spcidx = cpcidx; /* Starting value for search */
+ pcoffmax = cfnpc->pcoffmax; /* Local end of array value */
+ while (cpcidx <= trgpcidx && last < end)
+ {
+ /* Once through for each piece we pass, last time through to find length of piece we want */
+ first = last; /* first char of current piece */
+ while (last != end && *last != dlmc) last++; /* Find delim signaling end of piece */
+ last++; /* Bump past delim to first char next piece,
+ or if hit last char, +2 past end of piece */
+ ++cpcidx; /* Next piece */
+ if (pcoff < pcoffmax)
+ *pcoff++ = first - start; /* offset to this piece */
+ if (pcoff == pcoffmax)
+ *pcoff++ = last - start; /* store start of first piece beyond what is in cache */
+ }
+
+ dst->str.addr = (char *)first;
+
+ /* If we scanned some chars, adjust end pointer and save end of final piece */
+ if (spcidx != cpcidx)
+ {
+ if (pcoff < pcoffmax)
+ *pcoff = last - start; /* If not at end of cache, save start of "next" piece */
+
+ --last; /* Undo bump past last delim or +2 past end char
+ of piece for accurate string len */
+ /* Update count of pieces in cache */
+ cfnpc->npcs = MIN((cfnpc->npcs + cpcidx - spcidx), FNPC_ELEM_MAX);
+ assert(cfnpc->npcs <= FNPC_ELEM_MAX);
+ assert(cfnpc->npcs > 0);
+
+ /* If the above loop ended prematurely because we ran out of text, we return null string */
+ if (trgpcidx < cpcidx)
+ dst->str.len = last - first; /* Length of piece we located */
+ else
+ dst->str.len = 0;
+
+ INCR_COUNT(pscan, cpcidx - spcidx); /* Pieces scanned */
+ } else
+ dst->str.len = 0;
+
+ assert(cfnpc->npcs > 0);
+ assert(dst->str.len >= 0 && dst->str.len <= src->str.len);
+ } else
+ {
+ /* We have too small a string to worry about cacheing with or the string is a literal for which we cannot
+ change the fnpc index. In the first case it would take more work to set up the cache than it would to
+ just scan it (several times). In the second case, linked images have their literal mvals in readonly
+ storage so any attempt to set cacheing info into the mval results in an ACCVIO so cacheing must be
+ bypassed.
+ */
+ COUNT_EVENT(small);
+ cpcidx = 0 ;
+ while (cpcidx < trgpcidx && last < end)
+ {
+ first = last;
+ while (last != end && *last != dlmc) last++ ;
+ last++; cpcidx++;
+ }
+ last-- ;
+ dst->mvtype = MV_STR;
+ dst->str.addr = (char *)first;
+ dst->str.len = (cpcidx == trgpcidx && cpcidx != 0 ? last - first : 0);
+ INCR_COUNT(small_pcs, cpcidx);
+ }
+ return;
+
+}
diff --git a/sr_vvms/op_fnzparse.c b/sr_vvms/op_fnzparse.c
new file mode 100644
index 0000000..d8a7396
--- /dev/null
+++ b/sr_vvms/op_fnzparse.c
@@ -0,0 +1,211 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include <rms.h>
+#include <ssdef.h>
+#include "gtm_caseconv.h"
+#include "stringpool.h"
+#include "op.h"
+
+#define ZP_DEVICE 1
+#define ZP_DIRECTORY 2
+#define ZP_NAME 3
+#define ZP_NODE 4
+#define ZP_TYPE 5
+#define ZP_VERSION 6
+#define ZP_FULL 7
+
+#define DEV_LEN 6
+#define DIR_LEN 9
+#define VER_LEN 7
+#define ZP_LEN 4
+#define ZP_STR_LEN 255
+#define NCON_LEN 10
+#define SYN_LEN 11
+
+void op_fnzparse( mval *file, mval *field, mval *def1, mval *def2, mval *type, mval *ret)
+{
+char field_type;
+uint4 status;
+unsigned char field_buf[DIR_LEN],type_buf[SYN_LEN], def_buf[ZP_STR_LEN], esa[ZP_STR_LEN];
+struct FAB fab, fab_def;
+struct NAM nam, nam_def;
+error_def(ERR_ZPARSETYPE);
+error_def(ERR_ZPARSFLDBAD);
+error_def(ERR_INVSTRLEN);
+
+MV_FORCE_STR(field);
+MV_FORCE_STR(def1);
+MV_FORCE_STR(def2);
+MV_FORCE_STR(file);
+MV_FORCE_STR(type);
+
+if (def1->str.len > ZP_STR_LEN)
+ rts_error(VARLSTCNT(4) ERR_INVSTRLEN, 2, def1->str.len, ZP_STR_LEN);
+if (def2->str.len > ZP_STR_LEN)
+ rts_error(VARLSTCNT(4) ERR_INVSTRLEN, 2, def2->str.len, ZP_STR_LEN);
+
+if (field->str.len == 0)
+{ field_type = ZP_FULL;
+}
+else
+{ field_type = 0;
+ if (field->str.len <= DIR_LEN)
+ {
+ lower_to_upper(&field_buf[0], field->str.addr, field->str.len);
+ switch( field_buf[0] )
+ {
+ case 'D':
+ if (field->str.len <= DEV_LEN &&
+ !memcmp(&field_buf[0],"DEVICE",field->str.len))
+ { field_type = ZP_DEVICE;
+ }
+ else if (field->str.len <= DIR_LEN &&
+ !memcmp(&field_buf[0],"DIRECTORY",field->str.len))
+ { field_type = ZP_DIRECTORY;
+ }
+ break;
+ case 'N':
+ if (field->str.len <= ZP_LEN)
+ { if(!memcmp(&field_buf[0],"NAME",field->str.len))
+ { field_type = ZP_NAME;
+ }
+ else if (!memcmp(&field_buf[0],"NODE",field->str.len))
+ { field_type = ZP_NODE;
+ }
+ }
+ break;
+ case 'T':
+ if (field->str.len <= ZP_LEN &&
+ !memcmp(&field_buf[0],"TYPE",field->str.len))
+ { field_type = ZP_TYPE;
+ }
+ break;
+ case 'V':
+ if (field->str.len <= VER_LEN &&
+ !memcmp(&field_buf[0],"VERSION",field->str.len))
+ { field_type = ZP_VERSION;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ if(!field_type)
+ { rts_error(VARLSTCNT(4) ERR_ZPARSFLDBAD,2,field->str.len,field->str.addr);
+ }
+}
+fab = cc$rms_fab;
+nam = cc$rms_nam;
+if (type->str.len == 0)
+{ nam.nam$b_nop = 0;
+}
+else
+{
+ if (type->str.len <= SYN_LEN)
+ lower_to_upper(&type_buf[0], type->str.addr, type->str.len);
+ if (type->str.len <= SYN_LEN && !memcmp(&type_buf[0],"SYNTAX_ONLY",type->str.len))
+ { nam.nam$b_nop = NAM$M_SYNCHK;
+ }
+ else if (type->str.len <= NCON_LEN &&
+ !memcmp(&type_buf[0],"NO_CONCEAL",type->str.len))
+ { nam.nam$b_nop = NAM$M_NOCONCEAL;
+ }
+ else
+ { rts_error(VARLSTCNT(4) ERR_ZPARSETYPE,2,type->str.len,type->str.addr);
+ }
+}
+
+fab.fab$l_nam = &nam;
+fab.fab$l_fop = FAB$M_NAM;
+fab.fab$l_fna = file->str.addr;
+fab.fab$b_fns = file->str.len;
+nam.nam$l_esa = esa;
+nam.nam$b_ess = sizeof (esa);
+
+if (def2->str.len)
+{
+ fab_def = cc$rms_fab;
+ nam_def = cc$rms_nam;
+ fab_def.fab$l_nam = &nam_def;
+ fab_def.fab$l_fop = FAB$M_NAM;
+ fab_def.fab$l_fna = def2->str.addr;
+ fab_def.fab$b_fns = def2->str.len;
+ nam_def.nam$b_nop = NAM$M_SYNCHK;
+ nam_def.nam$l_esa = def_buf;
+ nam_def.nam$b_ess = sizeof (def_buf);
+ if ((status = sys$parse(&fab_def,0,0)) != RMS$_NORMAL)
+ { ret->mvtype = MV_STR;
+ ret->str.len = 0;
+ return;
+ }
+ nam_def.nam$l_rsa = nam_def.nam$l_esa;
+ nam_def.nam$b_rsl = nam_def.nam$b_esl;
+ nam.nam$l_rlf = &nam_def;
+}
+if (def1->str.len)
+{ fab.fab$l_dna = def1->str.addr;
+ fab.fab$b_dns = def1->str.len;
+}
+
+if ((status = sys$parse(&fab, 0, 0)) != RMS$_NORMAL)
+{ ret->mvtype = MV_STR;
+ ret->str.len = 0;
+ return;
+}
+
+ret->mvtype = MV_STR;
+switch( field_type )
+{
+case ZP_DEVICE:
+ ret->str.addr = nam.nam$l_dev;
+ ret->str.len = nam.nam$b_dev;
+ break;
+case ZP_DIRECTORY:
+ ret->str.addr = nam.nam$l_dir;
+ ret->str.len = nam.nam$b_dir;
+ break;
+case ZP_NAME:
+ ret->str.addr = nam.nam$l_name;
+ ret->str.len = nam.nam$b_name;
+ break;
+case ZP_NODE:
+ ret->str.addr = nam.nam$l_node;
+ ret->str.len = nam.nam$b_node;
+ break;
+case ZP_TYPE:
+ ret->str.addr = nam.nam$l_type;
+ ret->str.len = nam.nam$b_type;
+ break;
+case ZP_VERSION:
+ ret->str.addr = nam.nam$l_ver;
+ ret->str.len = nam.nam$b_ver;
+ break;
+default:
+ ret->str.addr = nam.nam$l_esa;
+ ret->str.len = nam.nam$b_esl;
+ break;
+}
+s2pool(&ret->str);
+
+if (nam.nam$b_nop != NAM$M_SYNCHK)
+{ /* release channel from parse */
+ fab.fab$b_dns = fab.fab$b_fns = 0;
+ nam.nam$b_nop = NAM$M_SYNCHK;
+ sys$parse(&fab, 0, 0);
+}
+
+return;
+}
diff --git a/sr_vvms/op_fnzpid.c b/sr_vvms/op_fnzpid.c
new file mode 100644
index 0000000..745f18f
--- /dev/null
+++ b/sr_vvms/op_fnzpid.c
@@ -0,0 +1,94 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <jpidef.h>
+#include <ssdef.h>
+#include "op.h"
+#include "mvalconv.h"
+
+static uint4 last_pid = 0;
+static uint4 new_pid;
+static bool pid_used = FALSE;
+static int4 jpi_code = JPI$_PID;
+
+void op_fnzpid(mint boolexpr,mval *ret)
+{
+ error_def(ERR_ZPIDBADARG);
+ uint4 status;
+ int4 pid = -1;
+
+ if(!pid_used && boolexpr)
+ { rts_error(VARLSTCNT(1) ERR_ZPIDBADARG);
+ }
+ if ( !boolexpr )
+ { do
+ { status = lib$getjpi(&jpi_code
+ ,&pid
+ ,0
+ ,&new_pid
+ ,0 ,0);
+ }while (status == SS$_NOPRIV || status == SS$_SUSPENDED);
+ if (status == SS$_NORMAL)
+ {
+ i2mval(ret,new_pid) ;
+ pid_used = TRUE;
+ last_pid = new_pid;
+ return;
+ }
+ else
+ { rts_error(VARLSTCNT(1) status);
+ }
+ }
+ else
+ { do
+ { do
+ { status = lib$getjpi( &jpi_code
+ ,&pid
+ ,0
+ ,&new_pid
+ ,0 ,0 );
+ }while (status == SS$_NOPRIV || status == SS$_SUSPENDED);
+ }while (new_pid != last_pid && status == SS$_NORMAL);
+ switch (status )
+ {
+ case SS$_NOMOREPROC:
+ ret->str.len = 0;
+ ret->mvtype = MV_STR;
+ pid_used = FALSE;
+ return;
+ case SS$_NORMAL:
+ do
+ { status = lib$getjpi( &jpi_code
+ ,&pid
+ ,0
+ ,&new_pid
+ ,0 ,0 );
+ }while (status == SS$_NOPRIV || status == SS$_SUSPENDED);
+ if (status == SS$_NORMAL)
+ {
+ i2mval(ret,new_pid) ;
+ pid_used = TRUE;
+ last_pid = new_pid;
+ return;
+ }
+ else if (status == SS$_NOMOREPROC)
+ { ret->str.len = 0;
+ ret->mvtype = MV_STR;
+ pid_used = FALSE;
+ return;
+ }
+ else
+ { rts_error(VARLSTCNT(1) status );
+ }
+ }
+ }
+}
diff --git a/sr_vvms/op_fnzpiece.c b/sr_vvms/op_fnzpiece.c
new file mode 100644
index 0000000..3884692
--- /dev/null
+++ b/sr_vvms/op_fnzpiece.c
@@ -0,0 +1,97 @@
+/****************************************************************
+ * *
+ * Copyright 2006, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "op.h"
+#include "matchc.h"
+#include "fnpc.h"
+
+/*
+ * -----------------------------------------------
+ * op_fnzpiece()
+ * MUMPS $ZPIece function (and non-unicode $PIECE)
+ *
+ * Arguments:
+ * src - Pointer to Source string mval
+ * del - Pointer to delimiter mval
+ * first - starting piece number
+ * last - last piece number
+ * dst - destination buffer to save the piece in
+ *
+ * Return:
+ * none
+ * -----------------------------------------------
+ */
+void op_fnzpiece(mval *src, mval *del, int first, int last, mval *dst, boolean_t srcisliteral)
+{
+ int piece_cnt, ofirst;
+ int del_len, src_len;
+ char *del_str, *src_str, *tmp_str;
+ char *match_start;
+ int match_res, numpcs;
+ delimfmt unichar;
+
+ ofirst = first;
+ if (--first < 0)
+ first = 0;
+
+ if ((piece_cnt = last - first) < 1)
+ {
+ dst->str.len = 0;
+ dst->mvtype = MV_STR;
+ return;
+ }
+
+ MV_FORCE_STR(src);
+ MV_FORCE_STR(del);
+
+ /* See if we can take a short cut to op_fnzp1 (need to reformat delim argument) */
+ if (1 == del->str.len && ofirst == last)
+ {
+ unichar.unichar_val = 0;
+ unichar.unibytes_val[0] = *del->str.addr;
+ op_fnzp1(src, unichar.unichar_val, ofirst, dst, srcisliteral);
+ return;
+ }
+ src_len = src->str.len;
+ src_str = src->str.addr;
+ del_len = del->str.len;
+ del_str = del->str.addr;
+ while (first--)
+ {
+ numpcs = 1;
+ tmp_str = (char *)matchb(del_len, (uchar_ptr_t)del_str, src_len, (uchar_ptr_t)src_str, &match_res, &numpcs);
+ src_len -= (tmp_str - src_str);
+ src_str = tmp_str;
+ if (0 == match_res)
+ {
+ dst->str.len = 0;
+ dst->mvtype = MV_STR;
+ return;
+ }
+ }
+ match_start = src_str;
+ while (piece_cnt--)
+ {
+ numpcs = 1;
+ tmp_str = (char *)matchb(del_len, (uchar_ptr_t)del_str, src_len, (uchar_ptr_t)src_str, &match_res, &numpcs);
+ src_len -= (tmp_str - src_str);
+ src_str = tmp_str;
+ if (0 == match_res)
+ break;
+ }
+ if (0 != match_res)
+ src_str -= del_len;
+ dst->str.addr = match_start;
+ dst->str.len = src_str - match_start;
+ dst->mvtype = MV_STR;
+ return;
+}
diff --git a/sr_vvms/op_fnzpriv.c b/sr_vvms/op_fnzpriv.c
new file mode 100644
index 0000000..bc42019
--- /dev/null
+++ b/sr_vvms/op_fnzpriv.c
@@ -0,0 +1,135 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "prvdef.h"
+#include <jpidef.h>
+#include <ssdef.h>
+
+#include "min_max.h"
+#include "gtm_caseconv.h"
+#include "op.h"
+#include "mvalconv.h"
+
+typedef struct
+{ char len;
+ char name[20];
+ char bit_number;
+}prv_struct;
+
+typedef struct
+{ char index;
+ char last_index;
+}ind_struct;
+
+static readonly prv_struct priv_table[] =
+{
+ { 8, "ALLSPOOL", PRV$V_ALLSPOOL }, { 6, "BUGCHK", PRV$V_BUGCHK },
+ { 6, "BYPASS", PRV$V_BYPASS }, { 6, "CMEXEC", PRV$V_CMEXEC },
+ { 6, "CMKRNL", PRV$V_CMKRNL }, { 6, "DETACH", PRV$V_DETACH },
+ { 8, "DIAGNOSE", PRV$V_DIAGNOSE }, { 9, "DOWNGRADE", PRV$V_DOWNGRADE },
+ { 7, "EXQUOTA", PRV$V_EXQUOTA }, { 5, "GROUP", PRV$V_GROUP },
+ { 6, "GRPNAM", PRV$V_GRPNAM }, { 6, "GRPPRV", PRV$V_GRPPRV },
+ { 6, "LOG_IO", PRV$V_LOG_IO }, { 5, "MOUNT", PRV$V_MOUNT },
+ { 6, "NETMBX", PRV$V_NETMBX }, { 6, "NOACNT", PRV$V_NOACNT },
+ { 4, "OPER", PRV$V_OPER }, { 6, "PFNMAP", PRV$V_PFNMAP },
+ { 6, "PHY_IO", PRV$V_PHY_IO }, { 6, "PRMCEB", PRV$V_PRMCEB },
+ { 6, "PRMGBL", PRV$V_PRMGBL }, { 6, "PRMJNL", PRV$V_PRMJNL },
+ { 6, "PRMMBX", PRV$V_PRMMBX }, { 6, "PSWAPM", PRV$V_PSWAPM },
+ { 7, "READALL", PRV$V_READALL }, { 8, "SECURITY", PRV$V_SECURITY },
+ { 6, "SETPRI", PRV$V_SETPRI }, { 6, "SETPRV", PRV$V_SETPRV },
+ { 5, "SHARE", PRV$V_SHARE }, { 5, "SHMEM", PRV$V_SHMEM },
+ { 6, "SYSGBL", PRV$V_SYSGBL }, { 6, "SYSLCK", PRV$V_SYSLCK },
+ { 6, "SYSNAM", PRV$V_SYSNAM }, { 6, "SYSPRV", PRV$V_SYSPRV },
+ { 6, "TMPJNL", PRV$V_TMPJNL }, { 6, "TMPMBX", PRV$V_TMPMBX },
+ { 7, "UPGRADE", PRV$V_UPGRADE }, { 6, "VOLPRO", PRV$V_VOLPRO },
+ { 5, "WORLD", PRV$V_WORLD}
+};
+
+static readonly ind_struct prv_index[] =
+{
+ { 0 , 1 }, { 1 , 3 }, { 3 , 5 }, { 5 , 8 }, { 8 , 9 }, { 0 , 0 }, { 9 , 12 }, { 0 , 0 },
+ { 0 , 0 }, { 0 , 0 }, { 0 , 0 }, { 12 , 13 }, { 13 , 14 }, { 14 , 16 }, { 16 , 17 },
+ { 17, 24 }, { 0 , 0 }, { 24 , 25 }, { 25 , 34 }, { 34 , 36 }, { 36 , 37 }, { 37 , 38 },
+ { 38 , 39 }, { 0 , 0 }, { 0 , 0 }, { 0 , 0 }
+};
+
+static int4 jpi_code = JPI$_CURPRIV;
+
+#define MAX_KW_LEN 128
+#define MIN_INDEX 0
+#define MAX_INDEX 25
+
+void op_fnzpriv(mval *prv,mval *ret)
+{
+uint4 status;
+int4 priv_bit;
+short index, slot, last_slot, prv_len;
+short buflen ;
+unsigned char out_value[8];
+char buf[MAX_KW_LEN] ;
+char *str_end,*str_cur,*prv_start;
+error_def (ERR_ZPRIVARGBAD);
+error_def (ERR_ZPRIVSYNTAXERR);
+
+MV_FORCE_STR(prv);
+ret->mvtype = MV_NM;
+if (prv->str.len == 0)
+{ rts_error(VARLSTCNT(4) ERR_ZPRIVARGBAD,2,4,"Null");
+}
+if ((status = lib$getjpi( &jpi_code
+ ,0 ,0
+ ,out_value
+ ,0 ,0 )) != SS$_NORMAL)
+{ rts_error(VARLSTCNT(1) status );
+}
+
+buflen = MIN(prv->str.len,MAX_KW_LEN) ;
+lower_to_upper(buf,prv->str.addr,buflen) ;
+str_cur = prv_start = str_end = buf ;
+str_end += buflen ;
+
+while (prv_start < str_end)
+{
+ while (*str_cur != ',' && str_cur != str_end)
+ { str_cur++;
+ }
+ prv_len = str_cur - prv_start;
+ if ((index = *prv_start - 'A') < MIN_INDEX || index > MAX_INDEX
+ || !(last_slot = prv_index[ index ].last_index) )
+ { rts_error(VARLSTCNT(4) ERR_ZPRIVARGBAD,2,prv_len,prv_start);
+ }
+ slot = prv_index[ index ].index;
+ priv_bit = -1;
+ for ( ; slot < last_slot ; slot++)
+ { if (prv_len == priv_table[slot].len && !memcmp(prv_start,priv_table[ slot ].name,prv_len))
+ { priv_bit = priv_table[slot].bit_number;
+ break;
+ }
+ }
+ if (priv_bit == -1)
+ { rts_error(VARLSTCNT(4) ERR_ZPRIVARGBAD,2,prv_len,prv_start);
+ }
+ if ( !lib$bbssi(&priv_bit,out_value) )
+ { ret->m[1] = 0 ;
+ return;
+ }
+ if (str_cur++ == str_end)
+ { break;
+ }
+ if (str_cur == str_end)
+ { rts_error(VARLSTCNT(1) ERR_ZPRIVSYNTAXERR);
+ }
+ prv_start = str_cur;
+}
+MV_FORCE_MVAL(ret,1);
+}
diff --git a/sr_vvms/op_fnzsearch.c b/sr_vvms/op_fnzsearch.c
new file mode 100644
index 0000000..db11fd5
--- /dev/null
+++ b/sr_vvms/op_fnzsearch.c
@@ -0,0 +1,145 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include <rms.h>
+#include <ssdef.h>
+#include "stringpool.h"
+#include "op.h"
+
+#define MAX_STRM_CT 256
+
+typedef struct fnzsearch
+{ short index;
+ struct FAB fab;
+ struct NAM nam;
+ struct fnzsearch *next;
+} search_struct;
+
+#define SEA_SIZE SIZEOF(search_struct)
+
+static search_struct *fab_sea;
+static bool search_init = FALSE;
+
+GBLREF spdesc stringpool;
+
+error_def(ERR_ZFILENMTOOLONG);
+error_def(ERR_ZSRCHSTRMCT);
+
+int op_fnzsearch(mval *file,mint strm,mval *ret)
+{
+ search_struct *sea_ptr,*sea,*ptr;
+ unsigned char esa[MAX_FN_LEN];
+ uint4 status;
+ int retlen;
+ short index, ct;
+
+ if (!search_init)
+ {
+ fab_sea = malloc(SEA_SIZE);
+ fab_sea->index = 0;
+ fab_sea->fab = cc$rms_fab;
+ fab_sea->nam = cc$rms_nam;
+ fab_sea->fab.fab$l_nam = &(fab_sea->nam);
+ fab_sea->fab.fab$l_fop = FAB$M_NAM;
+ fab_sea->fab.fab$l_fna = malloc(MAX_FN_LEN);
+ fab_sea->nam.nam$l_esa = malloc(MAX_FN_LEN);
+ fab_sea->nam.nam$b_ess = MAX_FN_LEN;
+ fab_sea->nam.nam$l_rsa = malloc(MAX_FN_LEN);
+ fab_sea->nam.nam$b_rss = MAX_FN_LEN;
+ fab_sea->fab.fab$b_fns = 0;
+ fab_sea->next = 0;
+ search_init = TRUE;
+ }
+ assert(fab_sea != 0);
+ index = (short)strm;
+ if (index > MAX_STRM_CT || index < 0)
+ rts_error(VARLSTCNT(1) ERR_ZSRCHSTRMCT);
+ MV_FORCE_STR(file);
+ if (file->str.len > MAX_FN_LEN)
+ rts_error(VARLSTCNT(4) ERR_ZFILENMTOOLONG,2,file->str.len,file->str.addr);
+ sea_ptr = fab_sea;
+ while(sea_ptr->next != 0 && sea_ptr->next->index <= index)
+ sea_ptr = sea_ptr->next;
+ if (sea_ptr->index != index)
+ {
+ sea = malloc(SEA_SIZE);
+ sea->index = index;
+ sea->fab = cc$rms_fab;
+ sea->nam = cc$rms_nam;
+ sea->fab.fab$l_nam = &(sea->nam);
+ sea->fab.fab$l_fop = FAB$M_NAM;
+ sea->fab.fab$l_fna = malloc(file->str.len);
+ sea->fab.fab$b_fns = file->str.len;
+ sea->nam.nam$l_esa = malloc(MAX_FN_LEN);
+ sea->nam.nam$b_ess = MAX_FN_LEN;
+ sea->nam.nam$l_rsa = malloc(MAX_FN_LEN);
+ sea->nam.nam$b_rss = MAX_FN_LEN;
+ sea->next = sea_ptr->next;
+ sea_ptr->next = sea;
+ sea_ptr =sea_ptr->next;
+ memcpy(sea_ptr->fab.fab$l_fna,file->str.addr,file->str.len);
+ if ((status = sys$parse(&(sea_ptr->fab),0,0)) != RMS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+ } else
+ {
+ if (file->str.len > sea_ptr->fab.fab$b_fns)
+ {
+ free (sea_ptr->fab.fab$l_fna);
+ sea_ptr->fab.fab$l_fna = malloc(file->str.len);
+ }
+ if (file->str.len != sea_ptr->fab.fab$b_fns || memcmp(sea_ptr->fab.fab$l_fna,file->str.addr,file->str.len))
+ {
+ memcpy(sea_ptr->fab.fab$l_fna,file->str.addr,file->str.len);
+ sea_ptr->fab.fab$b_fns = file->str.len;
+ if ((status = sys$parse(&(sea_ptr->fab),0,0)) != RMS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+ }
+ }
+ status = sys$search(&(sea_ptr->fab), 0, 0);
+ switch(status)
+ {
+ case RMS$_NORMAL:
+ assert(stringpool.free >= stringpool.base);
+ assert(stringpool.top >= stringpool.free);
+ retlen = sea_ptr->nam.nam$b_rsl;
+ ENSURE_STP_FREE_SPACE(retlen);
+ ret->str.len = retlen;
+ ret->str.addr = stringpool.free;
+ memcpy(ret->str.addr,sea_ptr->nam.nam$l_rsa,ret->str.len);
+ stringpool.free += ret->str.len;
+ assert(stringpool.free >= stringpool.base);
+ assert(stringpool.top >= stringpool.free);
+ break;
+ case RMS$_NMF:
+ case RMS$_FNF:
+ ret->str.len = 0;
+ if (sea_ptr->index != 0)
+ { ptr = fab_sea;
+ while(ptr->next->index < sea_ptr->index)
+ ptr = ptr->next;
+ ptr->next = sea_ptr->next;
+ free(sea_ptr->nam.nam$l_esa);
+ free(sea_ptr->nam.nam$l_rsa);
+ free(sea_ptr->fab.fab$l_fna);
+ free(sea_ptr);
+ } else
+ sea_ptr->fab.fab$b_fns = 0;
+ break;
+ default:
+ rts_error(VARLSTCNT(1) status );
+ }
+ ret->mvtype = MV_STR;
+ return 0; /* dummy for compatibility with unix prototype */
+}
diff --git a/sr_vvms/op_fnzsetprv.c b/sr_vvms/op_fnzsetprv.c
new file mode 100644
index 0000000..99cefd4
--- /dev/null
+++ b/sr_vvms/op_fnzsetprv.c
@@ -0,0 +1,182 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "prvdef.h"
+#include <jpidef.h>
+#include <ssdef.h>
+
+#include "stringpool.h"
+#include "min_max.h"
+#include "gtm_caseconv.h"
+#include "op.h"
+
+typedef struct
+{ char len;
+ char name[20];
+ char bit_number;
+}prv_struct;
+
+typedef struct
+{ char index;
+ char last_index;
+}ind_struct;
+
+static readonly prv_struct priv_table[] =
+{
+ { 4, "ACNT", PRV$V_NOACNT }, { 8, "ALLSPOOL", PRV$V_ALLSPOOL },
+ { 6, "BUGCHK", PRV$V_BUGCHK },
+ { 6, "BYPASS", PRV$V_BYPASS }, { 6, "CMEXEC", PRV$V_CMEXEC },
+ { 6, "CMKRNL", PRV$V_CMKRNL }, { 6, "DETACH", PRV$V_DETACH },
+ { 8, "DIAGNOSE", PRV$V_DIAGNOSE }, { 9, "DOWNGRADE", PRV$V_DOWNGRADE },
+ { 7, "EXQUOTA", PRV$V_EXQUOTA }, { 5, "GROUP", PRV$V_GROUP },
+ { 6, "GRPNAM", PRV$V_GRPNAM }, { 6, "GRPPRV", PRV$V_GRPPRV },
+ { 6, "LOG_IO", PRV$V_LOG_IO }, { 5, "MOUNT", PRV$V_MOUNT },
+ { 6, "NETMBX", PRV$V_NETMBX },
+ { 4, "OPER", PRV$V_OPER }, { 6, "PFNMAP", PRV$V_PFNMAP },
+ { 6, "PHY_IO", PRV$V_PHY_IO }, { 6, "PRMCEB", PRV$V_PRMCEB },
+ { 6, "PRMGBL", PRV$V_PRMGBL }, { 6, "PRMJNL", PRV$V_PRMJNL },
+ { 6, "PRMMBX", PRV$V_PRMMBX }, { 6, "PSWAPM", PRV$V_PSWAPM },
+ { 7, "READALL", PRV$V_READALL }, { 8, "SECURITY", PRV$V_SECURITY },
+ { 6, "SETPRI", PRV$V_SETPRI }, { 6, "SETPRV", PRV$V_SETPRV },
+ { 5, "SHARE", PRV$V_SHARE }, { 5, "SHMEM", PRV$V_SHMEM },
+ { 6, "SYSGBL", PRV$V_SYSGBL }, { 6, "SYSLCK", PRV$V_SYSLCK },
+ { 6, "SYSNAM", PRV$V_SYSNAM }, { 6, "SYSPRV", PRV$V_SYSPRV },
+ { 6, "TMPJNL", PRV$V_TMPJNL }, { 6, "TMPMBX", PRV$V_TMPMBX },
+ { 7, "UPGRADE", PRV$V_UPGRADE }, { 6, "VOLPRO", PRV$V_VOLPRO },
+ { 5, "WORLD", PRV$V_WORLD}
+};
+
+static readonly ind_struct prv_index[] =
+{
+ { 0 , 2 }, { 2 , 4 }, { 4 , 6 }, { 6 , 9 }, { 9 , 10 }, { 0 , 0 }, { 10 , 13 }, { 0 , 0 },
+ { 0 , 0 }, { 0 , 0 }, { 0 , 0 }, { 13 , 14 }, { 14 , 15 }, { 15 , 16 }, { 16 , 17 },
+ { 17, 24 }, { 0 , 0 }, { 24 , 25 }, { 25 , 34 }, { 34 , 36 }, { 36 , 37 }, { 37 , 38 },
+ { 38 , 39 }, { 0 , 0 }, { 0 , 0 }, { 0 , 0 }
+};
+
+#define MIN_INDEX 0
+#define MAX_INDEX 25
+#define MAX_STPRV_LEN 512
+#define QUAD_STR 8
+#define is_priv_set(a,b) ((b[a/QUAD_STR] & (1 << (a % QUAD_STR))) ? TRUE : FALSE)
+#define set_bit(a,b) (b[a/QUAD_STR] |= (1 << (a % QUAD_STR)))
+
+static unsigned char priv_disable = 0;
+static unsigned char priv_enable = 1;
+static int4 cur_priv_code = JPI$_CURPRIV;
+static unsigned char permanent = TRUE;
+
+GBLREF spdesc stringpool;
+
+void op_fnzsetprv(mval *prv,mval *ret)
+{
+int4 priv_bit, status ;
+short index, slot, last_slot, prv_len, out_len;
+unsigned char cur_priv[QUAD_STR], auth_priv[QUAD_STR], enable[QUAD_STR], disable[QUAD_STR], set_priv, priv_set;
+char *str_end, *str_cur, *prv_start;
+char buf[MAX_STPRV_LEN] ;
+error_def (ERR_ZSETPRVARGBAD);
+error_def (ERR_ZSETPRVSYNTAX);
+
+assert(stringpool.free >= stringpool.base);
+assert(stringpool.top >= stringpool.free);
+MV_FORCE_STR(prv);
+if (prv->str.len == 0)
+ rts_error(VARLSTCNT(4) ERR_ZSETPRVARGBAD,2,4,"Null");
+ENSURE_STP_FREE_SPACE(MAX_STPRV_LEN);
+if ((status = lib$getjpi( &cur_priv_code
+ ,0 ,0
+ ,cur_priv
+ ,0 ,0 )) != SS$_NORMAL)
+{ rts_error(VARLSTCNT(1) status );
+}
+prv_len = MIN(prv->str.len,MAX_STPRV_LEN) ;
+lower_to_upper(buf,prv->str.addr,prv_len) ;
+str_cur = prv_start = str_end = buf ;
+str_end += prv_len;
+ret->str.addr = stringpool.free;
+ret->mvtype = MV_STR;
+out_len = 0;
+memset(enable,'\0',QUAD_STR);
+memset(disable,'\0',QUAD_STR);
+while (prv_start < str_end)
+{ if (!memcmp(str_cur,"NO",2))
+ { str_cur += 2;
+ set_priv = FALSE;
+ prv_start = str_cur;
+ }
+ else
+ { set_priv = TRUE;
+ }
+ while (*str_cur != ',' && str_cur != str_end)
+ { str_cur++;
+ }
+ prv_len = str_cur - prv_start;
+ if ((index = *prv_start - 'A') < MIN_INDEX || index > MAX_INDEX
+ || !(last_slot = prv_index[ index ].last_index) )
+ { rts_error(VARLSTCNT(4) ERR_ZSETPRVARGBAD,2,prv_len,prv_start);
+ }
+ slot = prv_index[ index ].index;
+ priv_bit = -1;
+ for ( ; slot < last_slot ; slot++)
+ { if (prv_len == priv_table[slot].len && !memcmp(prv_start,priv_table[ slot ].name,prv_len))
+ { priv_bit = priv_table[slot].bit_number;
+ break;
+ }
+ }
+ if (priv_bit == -1)
+ { rts_error(VARLSTCNT(4) ERR_ZSETPRVARGBAD,2,prv_len,prv_start);
+ }
+ assert(stringpool.top >= stringpool.free);
+ if( !is_priv_set(priv_bit,cur_priv) )
+ { memcpy(stringpool.free,"NO",2);
+ stringpool.free += 2;
+ }
+ memcpy(stringpool.free,prv_start,prv_len);
+ stringpool.free += prv_len;
+ if ( set_priv )
+ { set_bit(priv_bit,enable);
+ }
+ else
+ { set_bit(priv_bit,disable);
+ }
+ assert(stringpool.top >= stringpool.free);
+ if (str_cur++ == str_end)
+ { break;
+ }
+ if (str_cur == str_end)
+ { rts_error(VARLSTCNT(1) ERR_ZSETPRVSYNTAX);
+ }
+ prv_start = str_cur;
+ *stringpool.free++ = ',';
+}
+ret->str.len = (char *) stringpool.free - ret->str.addr;
+if ((status = sys$setprv( priv_disable
+ ,disable
+ ,permanent
+ ,0 )) != SS$_NORMAL)
+{ rts_error(VARLSTCNT(1) status );
+}
+if ((status = sys$setprv( priv_enable
+ ,enable
+ ,permanent
+ ,0 )) != SS$_NORMAL)
+{
+ if ((status & 1)==0)
+ {
+ rts_error(VARLSTCNT(1) status );
+ }
+}
+return ;
+}
+
diff --git a/sr_vvms/op_fnztrnlnm.c b/sr_vvms/op_fnztrnlnm.c
new file mode 100644
index 0000000..d95df42
--- /dev/null
+++ b/sr_vvms/op_fnztrnlnm.c
@@ -0,0 +1,296 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+#include "gtm_limits.h"
+
+#include <ssdef.h>
+#include "stringpool.h"
+#include <descrip.h>
+#include "op_fn.h"
+#include <psldef.h>
+#include <lnmdef.h>
+#include "vmsdtype.h"
+#include "gtm_caseconv.h"
+#include "op.h"
+#include "mvalconv.h"
+#include "min_max.h"
+
+#define FULL_VALUE -2
+#define NOVALUE -1
+#define MAX_INDEX 25
+#define MAX_RESULT_SIZE 256
+#define MAX_LOGNAM_LENGTH 255
+#define MIN_INDEX 0
+
+GBLREF spdesc stringpool;
+static readonly dvi_struct trnlnm_table[] =
+{
+ { 11, "ACCESS_MODE", LNM$_ACMODE}, { 9, "CONCEALED", LNM$_ATTRIBUTES },
+ { 7, "CONFINE", LNM$_ATTRIBUTES}, { 4, "FULL", FULL_VALUE },
+ { 6, "LENGTH", LNM$_LENGTH}, { 9, "MAX_INDEX", LNM$_MAX_INDEX},
+ { 8, "NO_ALIAS", LNM$_ATTRIBUTES}, { 5, "TABLE", LNM$_ATTRIBUTES},
+ { 10, "TABLE_NAME", LNM$_TABLE}, { 8, "TERMINAL", LNM$_ATTRIBUTES},
+ { 5, "VALUE", LNM$_STRING}
+};
+
+static readonly int attr_tab[] = {NOVALUE, LNM$M_CONCEALED, LNM$M_CONFINE,NOVALUE,NOVALUE,NOVALUE,LNM$M_NO_ALIAS,
+ LNM$M_TABLE,NOVALUE,LNM$M_TERMINAL,NOVALUE};
+
+static readonly dvi_index_struct trnlnm_index[] = {
+ { 0, 1 }, { 0, 0 }, { 1, 3}, { 0, 0}, { 0, 0}, { 3, 4}, { 0, 0}, { 0, 0}, { 0, 0},
+ { 0, 0}, { 0, 0}, { 4, 5}, { 5, 6}, { 6, 7}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0},
+ { 0, 0}, { 7, 10}, { 0, 0}, { 10, 11}, { 0, 0}, { 0, 0}, { 0, 0}, { 0, 0}
+};
+
+void op_fnztrnlnm(mval *name,mval *table,int4 ind,mval *mode,mval *case_blind,mval *item,mval *ret)
+{
+ struct dsc$descriptor lname, ltable;
+ uint4 attribute, status, retlen, mask, full_mask;
+ char acmode;
+ short int *item_code, pass, index;
+ bool full;
+ char buff[256], result[MAX_RESULT_SIZE];
+ char i, slot, last_slot;
+ char def_table[] = "LNM$DCL_LOGICAL";
+
+ struct
+ {
+ item_list_3 item[3];
+ int4 terminator;
+ } item_list;
+ error_def(ERR_BADTRNPARAM);
+
+ if(!name->str.len || MAX_LOGNAM_LENGTH < name->str.len || MAX_LOGNAM_LENGTH < table->str.len)
+ rts_error(VARLSTCNT(1) SS$_IVLOGNAM);
+ memset(&item_list,0,SIZEOF(item_list));
+ item_list.item[0].item_code = 0;
+ item_list.item[0].buffer_address = result;
+ item_list.item[0].buffer_length = MAX_RESULT_SIZE;
+ item_list.item[0].return_length_address = &retlen;
+ item_code = &item_list.item[0].item_code;
+
+ lname.dsc$w_length = name->str.len;
+ lname.dsc$a_pointer = name->str.addr;
+ lname.dsc$b_dtype = DSC$K_DTYPE_T;
+ lname.dsc$b_class = DSC$K_CLASS_S;
+
+ if (table->str.len)
+ { ltable.dsc$w_length = table->str.len;
+ ltable.dsc$a_pointer = table->str.addr;
+ }else
+ { ltable.dsc$a_pointer = def_table;
+ ltable.dsc$w_length = strlen(def_table);
+ }
+ ltable.dsc$b_dtype = DSC$K_DTYPE_T;
+ ltable.dsc$b_class = DSC$K_CLASS_S;
+
+ if(ind)
+ { item_list.item[0].item_code = LNM$_INDEX;
+ item_list.item[0].buffer_address = &ind;
+ item_list.item[1].item_code = 0;
+ item_list.item[1].buffer_address = result;
+ item_list.item[1].buffer_length = MAX_RESULT_SIZE;
+ item_list.item[1].return_length_address = &retlen;
+ item_code = &item_list.item[1].item_code;
+ }
+
+ attribute = LNM$M_CASE_BLIND;
+ if (case_blind->str.len)
+ {
+ if (case_blind->str.len > 14)
+ rts_error(VARLSTCNT(4) ERR_BADTRNPARAM, 2,
+ MIN(SHRT_MAX, case_blind->str.len), case_blind->str.addr);
+ lower_to_upper(buff,case_blind->str.addr,case_blind->str.len);
+ if (case_blind->str.len == 14 && !memcmp(buff,"CASE_SENSITIVE",14))
+ attribute = 0;
+ else if (case_blind->str.len != 10 || memcmp(buff,"CASE_BLIND",10))
+ rts_error(VARLSTCNT(4) ERR_BADTRNPARAM,2,case_blind->str.len,case_blind->str.addr);
+ }
+
+ acmode = NOVALUE;
+ if (mode->str.len)
+ {
+ if (mode->str.len > 14)
+ rts_error(VARLSTCNT(4) ERR_BADTRNPARAM, 2,
+ MIN(SHRT_MAX, mode->str.len), mode->str.addr);
+ lower_to_upper(buff,mode->str.addr,mode->str.len);
+ switch (buff[0])
+ {
+ case 'U':
+ if ( mode->str.len = 4 && !memcmp(buff, "USER", 4))
+ acmode = PSL$C_USER;
+ case 'S':
+ if ( mode->str.len = 10 && !memcmp(buff, "SUPERVISOR", 10))
+ acmode = PSL$C_SUPER;
+ case 'K':
+ if ( mode->str.len = 6 && !memcmp(buff, "KERNEL", 6))
+ acmode = PSL$C_KERNEL;
+ case 'E':
+ if ( mode->str.len = 9 && !memcmp(buff, "EXECUTIVE", 9))
+ acmode = PSL$C_EXEC;
+ }
+ if (acmode == NOVALUE)
+ rts_error(VARLSTCNT(4) ERR_BADTRNPARAM,2,mode->str.len,mode->str.addr);
+ }
+
+ full = FALSE;
+ *item_code = NOVALUE;
+ if (item->str.len)
+ { if (item->str.len > 12)
+ rts_error(VARLSTCNT(4) ERR_BADTRNPARAM, 2,
+ MIN(SHRT_MAX, item->str.len), item->str.addr);
+ lower_to_upper(buff,item->str.addr,item->str.len);
+ if ((i = buff[0] - 'A') < MIN_INDEX || i > MAX_INDEX)
+ { rts_error(VARLSTCNT(4) ERR_BADTRNPARAM, 2, item->str.len, item->str.addr);
+ }
+ if ( trnlnm_index[i].len)
+ { slot = trnlnm_index[i].index;
+ last_slot = trnlnm_index[i].len;
+ for (; slot < last_slot; slot++)
+ { if (item->str.len == trnlnm_table[slot].len &&
+ !memcmp(trnlnm_table[slot].name, buff, item->str.len))
+ { if (trnlnm_table[slot].item_code == FULL_VALUE)
+ { if (ind)
+ index = 2;
+ else
+ index = 1;
+ *item_code = LNM$_STRING;
+ item_list.item[index].buffer_address = &full_mask;
+ item_list.item[index].buffer_length = SIZEOF(full_mask);
+ item_list.item[index].item_code = LNM$_ATTRIBUTES;
+ item_code = &item_list.item[index].item_code;
+ full = TRUE;
+ }else
+ { *item_code = trnlnm_table[slot].item_code;
+ }
+ break;
+ }
+ }
+ }
+ if (*item_code == NOVALUE)
+ { rts_error(VARLSTCNT(4) ERR_BADTRNPARAM,2,item->str.len,item->str.addr);
+ }
+ }else
+ { *item_code = LNM$_STRING;
+ }
+ for ( pass = 0 ; ; pass++ )
+ { retlen = 0;
+ status = sys$trnlnm(&attribute, <able, &lname, acmode == NOVALUE ? 0 : &acmode, &item_list);
+ if (status & 1)
+ { if (*item_code == LNM$_STRING || *item_code == LNM$_TABLE)
+ { ret->mvtype = MV_STR;
+ ENSURE_STP_FREE_SPACE(retlen);
+ ret->str.addr = stringpool.free;
+ ret->str.len = retlen;
+ memcpy(ret->str.addr, result, retlen);
+ stringpool.free += retlen;
+ return;
+ }else if (*item_code == LNM$_LENGTH || *item_code == LNM$_MAX_INDEX)
+ {
+ MV_FORCE_MVAL(ret,*(int4 *)result) ;
+ n2s(ret);
+ return;
+ }else if (*item_code == LNM$_ACMODE)
+ { ret->mvtype = MV_STR;
+ switch(*result)
+ { case PSL$C_USER:
+ ENSURE_STP_FREE_SPACE(4);
+ ret->str.addr = stringpool.free;
+ ret->str.len = 4;
+ memcpy(ret->str.addr, "USER", 4);
+ stringpool.free += 4;
+ return;
+ case PSL$C_SUPER:
+ ENSURE_STP_FREE_SPACE(5);
+ ret->str.addr = stringpool.free;
+ ret->str.len = 5;
+ memcpy(ret->str.addr, "SUPER", 5);
+ stringpool.free += 5;
+ return;
+ case PSL$C_EXEC:
+ ENSURE_STP_FREE_SPACE(9);
+ ret->str.addr = stringpool.free;
+ ret->str.len = 9;
+ memcpy(ret->str.addr, "EXECUTIVE", 9);
+ stringpool.free += 9;
+ return;
+ case PSL$C_KERNEL:
+ ENSURE_STP_FREE_SPACE(6);
+ ret->str.addr = stringpool.free;
+ ret->str.len = 6;
+ memcpy(ret->str.addr, "KERNEL", 6);
+ stringpool.free += 6;
+ return;
+ default:
+ GTMASSERT;
+ }
+ }else
+ { assert(*item_code == LNM$_ATTRIBUTES);
+ if (full)
+ { if (!retlen) /* If the logical name exists, but has no entry for the specified index, */
+ { /* then the return status will be normal as the TERMINAL attribute will */
+ /* be filled in, but there will be no equivalence name, thus retlen == 0 */
+ ret->mvtype = MV_STR;
+ if (!pass)
+ { ret->str.len = 0;
+ return;
+ }
+ ENSURE_STP_FREE_SPACE(lname.dsc$w_length);
+ ret->str.addr = stringpool.free;
+ ret->str.len = lname.dsc$w_length;
+ memcpy(ret->str.addr, lname.dsc$a_pointer, lname.dsc$w_length);
+ stringpool.free += lname.dsc$w_length;
+ return;
+ }
+ if(full_mask & LNM$M_TERMINAL)
+ { ret->mvtype = MV_STR;
+ ENSURE_STP_FREE_SPACE(retlen);
+ ret->str.addr = stringpool.free;
+ ret->str.len = retlen;
+ memcpy(ret->str.addr, result, retlen);
+ stringpool.free += retlen;
+ return;
+ }
+ memcpy(buff,result,retlen);
+ lname.dsc$w_length = retlen;
+ lname.dsc$a_pointer = buff;
+ }else
+ { mask = attr_tab[slot];
+ if (mask == NOVALUE)
+ GTMASSERT;
+ MV_FORCE_MVAL(ret,( *((int4*)result) & mask ? 1 : 0 )) ;
+ n2s(ret);
+ return;
+ }
+ }
+ }else if (status == SS$_NOLOGNAM)
+ { ret->mvtype = MV_STR;
+ if (full && pass > 0)
+ {
+ ENSURE_STP_FREE_SPACE(lname.dsc$w_length);
+ ret->str.addr = stringpool.free;
+ ret->str.len = lname.dsc$w_length;
+ memcpy(ret->str.addr, lname.dsc$a_pointer, lname.dsc$w_length);
+ stringpool.free += lname.dsc$w_length;
+ }else
+ { ret->str.len = 0;
+ }
+ return;
+ }else
+ { rts_error(VARLSTCNT(1) status);
+ }
+ }
+ MV_FORCE_MVAL(ret, 0) ;
+ return;
+}
diff --git a/sr_vvms/op_horolog.c b/sr_vvms/op_horolog.c
new file mode 100644
index 0000000..7f9ceb7
--- /dev/null
+++ b/sr_vvms/op_horolog.c
@@ -0,0 +1,36 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "stringpool.h"
+#include "op.h"
+
+GBLREF spdesc stringpool;
+
+void op_horolog(mval *s)
+{
+ int4 seconds,days;
+ uint4 lib$day();
+
+ assert (stringpool.free <= stringpool.top);
+ assert (stringpool.free >= stringpool.base);
+ ENSURE_STP_FREE_SPACE(MAXNUMLEN);
+ lib$day(&days,0,&seconds);
+ days += DAYS;
+ seconds /= CENTISECONDS;
+ s->str.addr = stringpool.free;
+ stringpool.free = i2s(&days);
+ *stringpool.free++ = ',';
+ stringpool.free = i2s(&seconds);
+ s->str.len = (char *) stringpool.free - s->str.addr;
+ s->mvtype = MV_STR;
+ return;
+}
diff --git a/sr_vvms/op_job.c b/sr_vvms/op_job.c
new file mode 100644
index 0000000..96f780d
--- /dev/null
+++ b/sr_vvms/op_job.c
@@ -0,0 +1,366 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <descrip.h>
+#include <iodef.h>
+#include <ssdef.h>
+#include <stdarg.h>
+
+#include "ast.h"
+#include "efn.h"
+#include "job.h"
+#include "op.h"
+#include "io.h"
+#include "gt_timer.h"
+#include "iotimer.h"
+#include "outofband.h"
+#include "rel_quant.h"
+
+#include "gdsroot.h"
+#include "gdskill.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsfhead.h"
+#include "gdscc.h"
+#include "filestruct.h"
+#include "buddy_list.h" /* needed for tp.h */
+#include "jnl.h"
+#include "hashtab_int4.h" /* needed for tp.h */
+#include "tp.h"
+#include "send_msg.h"
+#include "gtmmsg.h" /* for gtm_putmsg() prototype */
+#include "change_reg.h"
+#include "setterm.h"
+#include "getzposition.h"
+#ifdef DEBUG
+#include "have_crit.h" /* for the TPNOTACID_CHECK macro */
+#endif
+
+LITDEF mstr define_gtm$job$_ = {16, "DEFINE GTM$JOB$ "};
+LITDEF mstr set_default_ = {12, "SET DEFAULT "};
+LITDEF mstr atsign = {1, "@"};
+LITDEF mstr run__nodebug_ = {13, "RUN /NODEBUG "};
+LITDEF mstr set_noverify = {12, "SET NOVERIFY"};
+
+GBLDEF bool ojtimeout = TRUE;
+GBLDEF short ojpchan = 0;
+GBLDEF short ojcchan = 0;
+GBLDEF uint4 ojcpid = 0;
+GBLDEF short ojastq;
+
+GBLREF short astq_dyn_avail;
+GBLREF mval dollar_job;
+GBLREF uint4 dollar_trestart;
+GBLREF uint4 dollar_zjob;
+GBLREF int4 outofband;
+
+error_def(ERR_ACK);
+error_def(ERR_ENQ);
+error_def(ERR_INSFFBCNT);
+error_def(ERR_JOBARGMISSING);
+error_def(ERR_JOBFAIL);
+
+readonly $DESCRIPTOR (loginout, "SYS$SYSTEM:LOGINOUT.EXE");
+
+#define JOBTIMESTR "JOB time too long"
+
+int op_job(mval *label, ...)
+{
+ va_list var, save;
+ bool defprcnam, timed;
+ /* The max possible value for combuff is 268, 256 bytes for DEFAULT + 12 bytes for set_default_ */
+ char combuf[268];
+ int4 argcnt, i, offset, timeout;
+ unsigned int ast_stat;
+ mstr command;
+ mval *parameters, *routine;
+ /* Parameters ... */
+ mval *inp;
+ mstr deffs, error, gbldir, image, input, output, startup;
+ struct dsc$descriptor_s logfile, prcnam;
+ int4 baspri, stsflg;
+ quadword schedule;
+ /* Mailboxes ... */
+ int4 cmaxmsg, punit;
+ char cmbxnam[MAX_MBXNAM_LEN];
+ $DESCRIPTOR(cmbx, cmbxnam);
+ /* $CREPRC ... */
+ unsigned int status;
+ /* Messages */
+ mstr dummstr, isddsc;
+ isd_type isd;
+ mbx_iosb iosb;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ /* Initializations ... */
+ assert(TRUE == ojtimeout);
+ assert(0 == ojpchan);
+ assert(0 == ojcchan);
+ assert(0 == ojcpid);
+ assert(0 == ojastq);
+ VAR_START(var, label);
+ va_count(argcnt);
+ assert(argcnt >= 5);
+ offset = va_arg(var, int4);
+ routine = va_arg(var, mval *);
+ parameters = va_arg(var, mval *);
+ timeout = va_arg(var, int4);
+ argcnt -= 5;
+ VAR_COPY(save, var);
+ /* initialize $zjob = 0, in case JOB fails */
+ dollar_zjob = 0;
+ MV_FORCE_DEFINED(label);
+ MV_FORCE_DEFINED(routine);
+ MV_FORCE_DEFINED(parameters);
+ cmaxmsg = SIZEOF(isd_type);
+ for (i = argcnt; i; i--)
+ {
+ inp = va_arg(var, mval *);
+ if (!inp->mvtype)
+ {
+ if (1 == i)
+ { /* if it's really empty let it work like it did before, even though it's not right */
+ argcnt--;
+ break;
+ }
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_JOBARGMISSING, 1, argcnt - i);
+ }
+ MV_FORCE_STR(inp);
+ if (inp->str.len > cmaxmsg)
+ cmaxmsg = inp->str.len;
+ }
+ va_end(var); /* need before used as destination in va_copy */
+ command.addr = combuf;
+ ojparams(parameters->str.addr, routine, &defprcnam, &cmaxmsg,
+ &image, &input, &output, &error, &prcnam, &baspri,
+ &stsflg, &gbldir, &startup, &logfile, &deffs,
+ &schedule);
+ flush_pio();
+ if (!ojchkbytcnt(cmaxmsg))
+ {
+ va_end(save);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) ERR_INSFFBCNT);
+ }
+ if (timeout < 0)
+ timeout = 0;
+ else if (TREF(tpnotacidtime) < timeout)
+ TPNOTACID_CHECK(JOBTIMESTR);
+ timed = (NO_M_TIMEOUT != timeout);
+ if (timed)
+ ojtmrinit(&timeout);
+ if (!ojcrembxs(&punit, &cmbx, cmaxmsg, timed))
+ {
+ assert(timed);
+ assert(ojtimeout);
+ if (0 != ojpchan)
+ {
+ status = sys$dassgn(ojpchan);
+ if (!(status & 1))
+ {
+ ojerrcleanup();
+ va_end(save);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status);
+ }
+ ojpchan = 0;
+ }
+ if (0 != ojcchan)
+ {
+ status = sys$dassgn(ojcchan);
+ if (!(status & 1))
+ {
+ ojerrcleanup();
+ va_end(save);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status);
+ }
+ ojcchan = 0;
+ }
+ return (FALSE);
+ }
+ /* Allocate AST for mailbox reads */
+ ast_stat = sys$setast(DISABLE);
+ while (astq_dyn_avail < 1)
+ {
+ ENABLE_AST;
+ rel_quant();
+ DISABLE_AST;
+ }
+ ojastq++;
+ --astq_dyn_avail;
+ if (SS$_WASSET == ast_stat)
+ sys$setast(ENABLE);
+ ojsetattn(ERR_ENQ);
+ do
+ {
+ status = sys$creprc(&ojcpid, &loginout, &cmbx, &logfile, 0,
+ 0, 0, &prcnam, baspri, 0, punit, stsflg);
+ if (outofband)
+ {
+ ojcleanup();
+ va_end(save);
+ outofband_action(FALSE);
+ }
+ switch (status)
+ {
+ case SS$_NORMAL:
+ break;
+ case SS$_DUPLNAM:
+ if (defprcnam)
+ {
+ ojdefprcnam(&prcnam);
+ continue;
+ }
+ case SS$_NOSLOT:
+ case SS$_INSSWAPSPACE:
+ case SS$_EXPRCLM:
+ hiber_start(1000);
+ if (timed && ojtimeout)
+ {
+ status = sys$dassgn(ojpchan);
+ if (!(status & 1))
+ {
+ ojerrcleanup();
+ va_end(save);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status);
+ }
+ ojpchan = 0;
+ status = sys$dassgn(ojcchan);
+ if (!(status & 1))
+ {
+ ojerrcleanup();
+ va_end(save);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status);
+ }
+ ojcchan = 0;
+ ojcpid = 0;
+ --ojastq;
+ astq_dyn_avail++;
+ va_end(save);
+ return (FALSE);
+ }
+ break;
+ default:
+ ojerrcleanup();
+ va_end(save);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(3) ERR_JOBFAIL, 0, status);
+ break;
+ }
+ } while (SS$_NORMAL != status);
+ ojmbxio(IO$_WRITEVBLK, ojcchan, &set_noverify, &iosb, TRUE);
+ memcpy(combuf, define_gtm$job$_.addr, define_gtm$job$_.len);
+ assert(MV_IS_STRING(&dollar_job));
+ memcpy(&combuf[define_gtm$job$_.len], dollar_job.str.addr, dollar_job.str.len);
+ command.len = define_gtm$job$_.len + dollar_job.str.len;
+ ojmbxio(IO$_WRITEVBLK, ojcchan, &command, &iosb, TRUE);
+ memcpy(combuf, set_default_.addr, set_default_.len);
+ memcpy(&combuf[set_default_.len], deffs.addr, deffs.len);
+ command.len = set_default_.len + deffs.len;
+ ojmbxio(IO$_WRITEVBLK, ojcchan, &command, &iosb, TRUE);
+ if (0 != startup.len)
+ {
+ memcpy(combuf, atsign.addr, atsign.len);
+ memcpy(&combuf[atsign.len], startup.addr, startup.len);
+ command.len = atsign.len + startup.len;
+ ojmbxio(IO$_WRITEVBLK, ojcchan, &command, &iosb, TRUE);
+ }
+ memcpy(combuf, run__nodebug_.addr, run__nodebug_.len);
+ memcpy(&combuf[run__nodebug_.len], image.addr, image.len);
+ command.len = run__nodebug_.len + image.len;
+ ojmbxio(IO$_WRITEVBLK, ojcchan, &command, &iosb, TRUE);
+ status = sys$waitfr(efn_op_job);
+ if (!(status & 1))
+ {
+ ojerrcleanup();
+ va_end(save);
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status);
+ }
+ /* Assertion: successful ENQ */
+ ojsetattn(ERR_ACK);
+ ojmbxio(IO$_WRITEVBLK, ojcchan, &input, &iosb, TRUE);
+ ojmbxio(IO$_WRITEVBLK, ojcchan, &output, &iosb, TRUE);
+ ojmbxio(IO$_WRITEVBLK, ojcchan, &error, &iosb, TRUE);
+ ojmbxio(IO$_WRITEVBLK, ojcchan, &gbldir, &iosb, TRUE);
+ isddsc.len = SIZEOF(isd);
+ isddsc.addr = &isd;
+ assert(label->str.len <= MAX_MIDENT_LEN);
+ memset(&isd.label, 0, SIZEOF(isd.label));
+ memcpy(&isd.label.c[0], label->str.addr, label->str.len);
+ isd.offset = offset;
+ assert(routine->str.len <= MAX_MIDENT_LEN);
+ memset(&isd.routine, 0, SIZEOF(isd.routine));
+ memcpy(&isd.routine.c[0], routine->str.addr, routine->str.len);
+ isd.schedule.lo = schedule.lo;
+ isd.schedule.hi = schedule.hi;
+ ojmbxio(IO$_WRITEVBLK, ojcchan, &isddsc, &iosb, TRUE);
+ isddsc.len = SIZEOF(argcnt);
+ isddsc.addr = &argcnt;
+ ojmbxio(IO$_WRITEVBLK, ojcchan, &isddsc, &iosb, TRUE);
+ if (argcnt)
+ {
+ while (argcnt--)
+ {
+ inp = va_arg(save, mval *);
+ MV_FORCE_DEFINED(inp); /* In case undefined mval in NOUNDEF mode */
+ assert(inp->mvtype & MV_STR);
+ isddsc = inp->str;
+ ojmbxio(IO$_WRITEVBLK, ojcchan, &isddsc, &iosb, TRUE);
+ }
+ }
+ va_end(save);
+ status = sys$waitfr(efn_op_job);
+ if (!(status & 1))
+ {
+ ojerrcleanup();
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status);
+ }
+ /* Assertion: successful ACK */
+ --ojastq;
+ astq_dyn_avail++;
+ status = sys$dassgn(ojpchan);
+ if (!(status & 1))
+ {
+ ojerrcleanup();
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status);
+ }
+ ojpchan = 0;
+ dummstr.len = 0;
+ dummstr.addr = 0;
+ ojmbxio(IO$_WRITEOF, ojcchan, &dummstr, &iosb, TRUE);
+ status = sys$dassgn(ojcchan);
+ if (!(status & 1))
+ {
+ ojerrcleanup();
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(1) status);
+ }
+ ojcchan = 0;
+ if (timed)
+ {
+ ast_stat = sys$setast(DISABLE);
+ if (!ojtimeout)
+ {
+ assert(1 == ojastq);
+ sys$cantim(&(ojtimeout), 0);
+ --ojastq;
+ astq_dyn_avail++;
+ ojtimeout = TRUE;
+ }
+ if (SS$_WASSET == ast_stat)
+ sys$setast(ENABLE);
+ }
+ assert(TRUE == ojtimeout);
+ assert(0 != ojcpid);
+ dollar_zjob = ojcpid;
+ ojcpid = 0;
+ return TRUE;
+}
diff --git a/sr_vvms/op_setzp1.c b/sr_vvms/op_setzp1.c
new file mode 100644
index 0000000..eeaca0c
--- /dev/null
+++ b/sr_vvms/op_setzp1.c
@@ -0,0 +1,292 @@
+/****************************************************************
+ * *
+ * Copyright 2006, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+#include "stringpool.h"
+#include "min_max.h"
+#include "fnpc.h"
+#include "op.h"
+
+GBLREF spdesc stringpool;
+
+#ifdef DEBUG
+GBLREF boolean_t setp_work;
+GBLREF int cs_small; /* scanned small string brute force */
+GBLREF int cs_small_pcs; /* chars scanned by small scan */
+# define SETWON setp_work = TRUE;
+# define SETWOFF setp_work = FALSE;
+# define COUNT_EVENT(x) ++x;
+# define INCR_COUNT(x,y) x += y;
+#else
+# define SETWON
+# define SETWOFF
+# define COUNT_EVENT(x)
+# define INCR_COUNT(x,y)
+#endif
+
+error_def(ERR_MAXSTRLEN);
+
+/*
+ * ----------------------------------------------------------
+ * Fast path setzpiece when delimiter is one (lit) char replacing
+ * a single piece (last is same as first).
+ *
+ * Arguments:
+ * src - source mval
+ * delim - delimiter char
+ * expr - expression string mval
+ * ind - index in source mval to be set
+ * dst - destination mval where the result is saved.
+ *
+ * Return:
+ * none
+ * ----------------------------------------------------------
+ */
+void op_setzp1(mval *src, int delim, mval *expr, int ind, mval *dst)
+{
+ size_t str_len, delim_cnt;
+ int len, pfx_str_len, sfx_start_offset, sfx_str_len, rep_str_len, pfx_scan_offset;
+ int cpy_cache_lines;
+ unsigned char ldelimc, lc, *start_sfx, *str_addr, *end_pfx, *end_src, *start_pfx;
+ boolean_t do_scan;
+ mval dummymval; /* It's value is not used but is part of the call to op_fnp1() */
+ fnpc *cfnpc, *pfnpc;
+ delimfmt ldelim;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ ldelim.unichar_val = delim; /* Local copys (in unsigned char and integer formats) */
+ ldelimc = ldelim.unibytes_val[0];
+ do_scan = FALSE;
+ cpy_cache_lines = -1;
+ MV_FORCE_STR(expr); /* Expression to put into piece place */
+ if (MV_DEFINED(src))
+ {
+ /* We have 3 possible scenarios:
+ *
+ * 1) If length of src is too small to cause cacheing by op_fnzp1, then just do
+ * the work ourselves with no cacheing.
+ * 2) If the requested piece is larger than can be cached by op_fnzp1, call fnzp1
+ * for the maximum piece possible, use the cache info to "prime the pump" and
+ * then process the rest of the string ourselves.
+ * 3) If the requested piece can be obtained from the cache, call op_fnzp1 to validate
+ * and rebuild the cache if necessary and then retrieve the necessary info from
+ * the fnpc cache.
+ */
+ MV_FORCE_STR(src); /* Make sure is string prior to length check */
+ if (FNPC_STRLEN_MIN < src->str.len && FNPC_ELEM_MAX >= ind)
+ { /* 3) Best of all possible cases. The op_fnzp1 can do most of our work for us
+ * and we can preload the cache on the new string to help its subsequent
+ * uses along as well.
+ */
+ SETWON;
+ op_fnzp1(src, delim, ind, &dummymval, FALSE);
+ SETWOFF;
+ cfnpc = &(TREF(fnpca)).fnpcs[src->fnpc_indx - 1];
+ assert(cfnpc->last_str.addr == src->str.addr);
+ assert(cfnpc->last_str.len == src->str.len);
+ assert(cfnpc->delim == ldelim.unichar_val);
+ assert(0 < cfnpc->npcs);
+ /* Three more scenarios: #1 piece all in cache, #2 piece would be in cache but ran
+ * out of text or #3 piece is beyond what can be cached
+ */
+ if (cfnpc->npcs >= ind)
+ { /* #1 The piece we want is totally within the cache which is good news */
+ pfx_str_len = cfnpc->pstart[ind - 1];
+ delim_cnt = 0;
+ sfx_start_offset = cfnpc->pstart[ind] - 1; /* Include delimiter */
+ rep_str_len = cfnpc->pstart[ind] - cfnpc->pstart[ind - 1] - 1; /* Replace string length */
+ sfx_str_len = src->str.len - pfx_str_len - rep_str_len;
+ cpy_cache_lines = ind - 1;
+ } else
+ { /* #2 The string was too short so the cache does not contain our string. This means
+ * that the prefix becomes any text that IS in the cache and we set the delim_cnt
+ * to be the number of missing pieces so the delimiters can be put in as part of the
+ * prefix when we build the new string.
+ */
+ pfx_str_len = cfnpc->pstart[cfnpc->npcs] - 1;
+ delim_cnt = (size_t)(ind - cfnpc->npcs);
+ sfx_start_offset = 0;
+ sfx_str_len = 0;
+ cpy_cache_lines = cfnpc->npcs;
+ }
+ } else if (FNPC_STRLEN_MIN < src->str.len)
+ { /* 2) We have a element that would not be able to be in the fnpc cache. Go ahead
+ * and call op_fnzp1 to get cache info up to the maximum and then we will continue
+ * the scan on our own.
+ */
+ SETWON;
+ op_fnzp1(src, delim, FNPC_ELEM_MAX, &dummymval, FALSE);
+ SETWOFF;
+ cfnpc = &(TREF(fnpca)).fnpcs[src->fnpc_indx - 1];
+ assert(cfnpc->last_str.addr == src->str.addr);
+ assert(cfnpc->last_str.len == src->str.len);
+ assert(cfnpc->delim == ldelim.unichar_val);
+ assert(0 < cfnpc->npcs);
+ if (FNPC_ELEM_MAX > cfnpc->npcs)
+ { /* We ran out of text so the scan is complete. This is basically the same
+ * as case #2 above.
+ */
+ pfx_str_len = cfnpc->pstart[cfnpc->npcs] - 1;
+ delim_cnt = (size_t)(ind - cfnpc->npcs);
+ sfx_start_offset = 0;
+ sfx_str_len = 0;
+ cpy_cache_lines = cfnpc->npcs;
+ } else
+ { /* We have a case where the piece we want cannot be kept in cache. In the special
+ * case where there is no more text to handle, we don't need to scan further. Otherwise
+ * we prime the pump and continue the scan where the cache left off.
+ */
+ if ((pfx_scan_offset = cfnpc->pstart[FNPC_ELEM_MAX]) < src->str.len)
+ { /* Normal case where we prime the pump */
+ do_scan = TRUE;
+ } else
+ { /* Special case -- no more text to scan */
+ pfx_str_len = cfnpc->pstart[FNPC_ELEM_MAX] - 1;
+ sfx_start_offset = 0;
+ sfx_str_len = 0;
+ }
+ delim_cnt = (size_t)ind - FNPC_ELEM_MAX;
+ cpy_cache_lines = FNPC_ELEM_MAX;
+ }
+ } else
+ { /* 1) We have a short string where no cacheing happens. Do the scanning work ourselves */
+ MV_FORCE_STR(src);
+ do_scan = TRUE;
+ pfx_scan_offset = 0;
+ delim_cnt = (size_t)ind;
+ }
+ } else
+ { /* Source is not defined -- treat as a null string */
+ pfx_str_len = sfx_str_len = sfx_start_offset = 0;
+ delim_cnt = (size_t)ind - 1;
+ }
+ /* If we have been forced to do our own scan, do that here. Note the variable pfx_scan_offset has been
+ * set to where the scan should begin in the src string and delim_cnt has been set to how many delimiters
+ * still need to be processed.
+ */
+ if (do_scan)
+ { /* Scan the line isolating prefix piece, and end of the piece being replaced */
+ COUNT_EVENT(cs_small);
+ end_pfx = start_sfx = (unsigned char *)src->str.addr + pfx_scan_offset;
+ end_src = (unsigned char *)src->str.addr + src->str.len;
+ /* The compiler would unroll this loop this way anyway but we want to
+ * adjust the start_sfx pointer after the loop but only if we have gone
+ * into it at least once.
+ */
+ if ((0 < delim_cnt) && (start_sfx < end_src))
+ {
+ do
+ {
+ end_pfx = start_sfx;
+ while (start_sfx < end_src && (lc = *start_sfx) != ldelimc) start_sfx++;
+ start_sfx++;
+ delim_cnt--;
+ } while ((0 < delim_cnt) && (start_sfx < end_src));
+ /* We have to backup up the suffix start pointer except under the condition
+ * that the last character in the buffer is the last delimiter we were looking
+ * for.
+ */
+ if ((0 == delim_cnt) || (start_sfx < end_src) || (lc != ldelimc))
+ --start_sfx; /* Back up suffix to include delimiter char */
+ /* If we scanned to the end (no text left) and still have delimiters to
+ * find, the entire src text should be part of the prefix
+ */
+ if ((start_sfx >= end_src) && (0 < delim_cnt))
+ {
+ end_pfx = start_sfx;
+ if (lc == ldelimc) /* if last char was delim, reduce delim cnt */
+ --delim_cnt;
+ }
+ } else
+ {
+ /* If not doing any token finding, then this count becomes the number
+ * of tokens to output. Adjust accordingly.
+ */
+ if (0 < delim_cnt)
+ delim_cnt--;
+ }
+ INCR_COUNT(cs_small_pcs, (int)((size_t)ind - delim_cnt));
+ /* Now having the following situation:
+ * end_pfx -> end of the prefix piece including delimiter
+ * start_sfx -> start of suffix piece (with delimiter) or = end_pfx/src->str.addr if none
+ */
+ pfx_str_len = end_pfx - (unsigned char *)src->str.addr;
+ if (0 > pfx_str_len)
+ pfx_str_len = 0;
+ sfx_start_offset = start_sfx - (unsigned char *)src->str.addr;
+ sfx_str_len = src->str.len - sfx_start_offset;
+ if (0 > sfx_str_len)
+ sfx_str_len = 0;
+ }
+ /* Calculate total string len. delim_cnt has needed padding delimiters for null fields */
+ str_len = (size_t)expr->str.len + (size_t)pfx_str_len + delim_cnt + (size_t)sfx_str_len;
+ if (MAX_STRLEN < str_len)
+ rts_error(VARLSTCNT(1) ERR_MAXSTRLEN);
+ ENSURE_STP_FREE_SPACE((int)str_len);
+ str_addr = stringpool.free;
+ start_pfx = (unsigned char *)src->str.addr;
+ /* copy prefix */
+ if (0 < pfx_str_len)
+ {
+ memcpy(str_addr, src->str.addr, pfx_str_len);
+ str_addr += pfx_str_len;
+ }
+ /* copy delimiters */
+ while (0 < delim_cnt--)
+ *str_addr++ = ldelimc;
+ /* copy expression */
+ if (0 < expr->str.len)
+ {
+ memcpy(str_addr, expr->str.addr, expr->str.len);
+ str_addr += expr->str.len;
+ }
+ /* copy suffix */
+ if (0 < sfx_str_len)
+ {
+ memcpy(str_addr, start_pfx + sfx_start_offset, sfx_str_len);
+ str_addr += sfx_str_len;
+ }
+ assert((str_addr - stringpool.free) == str_len);
+ dst->mvtype = MV_STR;
+ dst->str.len = str_addr - stringpool.free;
+ dst->str.addr = (char *)stringpool.free;
+ stringpool.free = str_addr;
+ /* If available, update the cache information for this newly created mval to hopefully
+ * give it a head start on its next usage. Note that we can only copy over the cache info
+ * for the prefix. We cannot include information for the 'expression' except where it starts
+ * because the expression could itself contain delimiters that would be found on a rescan.
+ */
+ if (0 < cpy_cache_lines)
+ {
+ pfnpc = cfnpc; /* pointer for src mval's cache */
+ do
+ {
+ cfnpc = (TREF(fnpca)).fnpcsteal; /* Next cache element to steal */
+ if ((TREF(fnpca)).fnpcmax < cfnpc)
+ cfnpc = &(TREF(fnpca)).fnpcs[0];
+ (TREF(fnpca)).fnpcsteal = cfnpc + 1; /* -> next element to steal */
+ } while (cfnpc == pfnpc); /* Make sure we don't step on ourselves */
+ cfnpc->last_str = dst->str; /* Save validation info */
+ cfnpc->delim = ldelim.unichar_val;
+ cfnpc->npcs = cpy_cache_lines;
+ cfnpc->byte_oriented = TRUE;
+ dst->fnpc_indx = cfnpc->indx + 1; /* Save where we are putting this element
+ * (1 based index in mval so 0 isn't so common)
+ */
+ memcpy(&cfnpc->pstart[0], &pfnpc->pstart[0], (cfnpc->npcs + 1) * SIZEOF(unsigned int));
+ } else
+ /* No cache available -- just reset index pointer to get fastest cache validation failure */
+ dst->fnpc_indx = -1;
+
+}
diff --git a/sr_vvms/op_zattach.c b/sr_vvms/op_zattach.c
new file mode 100644
index 0000000..e370150
--- /dev/null
+++ b/sr_vvms/op_zattach.c
@@ -0,0 +1,82 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2004 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gtm_limits.h"
+#include "io.h"
+#include <descrip.h>
+#include <ssdef.h>
+#include <jpidef.h>
+#include "gtm_caseconv.h"
+#include "setterm.h"
+#include "op.h"
+#include "min_max.h"
+
+#define PID_BUFF 15
+GBLREF io_pair io_std_device;
+GBLREF mval dollar_zproc;
+static int4 parent_id;
+static bool once_thru = FALSE;
+
+void op_zattach(mval *v)
+{
+ int4 pid;
+ int4 jpi_code;
+ uint4 status;
+ $DESCRIPTOR(p_name,"");
+ error_def(ERR_ZATTACHERR);
+
+ MV_FORCE_STR(v);
+ if (PID_BUFF < v->str.len)
+ rts_error(VARLSTCNT(5) ERR_ZATTACHERR, 2, MIN(SHRT_MAX, v->str.len), v->str.addr, SS$_IVLOGNAM);
+ if (once_thru == FALSE)
+ { once_thru = TRUE;
+
+ p_name.dsc$w_length = dollar_zproc.str.len;
+ p_name.dsc$a_pointer = dollar_zproc.str.addr;
+ jpi_code = JPI$_MASTER_PID;
+
+ lib$getjpi(&jpi_code, 0, &p_name, &parent_id, 0, 0);
+ }
+
+ p_name.dsc$w_length = v->str.len;
+ if (!p_name.dsc$w_length)
+ { pid = parent_id;
+ }
+ else
+ {
+ jpi_code = JPI$_PID;
+ p_name.dsc$a_pointer = v->str.addr;
+
+ status = lib$getjpi(&jpi_code, 0, &p_name, &pid, 0, 0);
+ if (status == SS$_NONEXPR)
+ {
+ char buf[PID_BUFF];
+
+ assert (v->str.len <= PID_BUFF);
+ lower_to_upper(&buf[0], v->str.addr, v->str.len);
+ p_name.dsc$a_pointer = buf;
+ status = lib$getjpi(&jpi_code, 0, &p_name, &pid, 0, 0);
+ }
+ if (status != SS$_NORMAL)
+ { rts_error(VARLSTCNT(6) ERR_ZATTACHERR, 2, v->str.len, v->str.addr, status, 0);
+ }
+ }
+ flush_pio();
+ if (io_std_device.in->type == tt)
+ resetterm(io_std_device.in);
+ status = lib$attach(&pid);
+ if (io_std_device.in->type == tt)
+ setterm(io_std_device.in);
+ if (status != SS$_NORMAL)
+ { rts_error(VARLSTCNT(6) ERR_ZATTACHERR, 2, v->str.len, v->str.addr, status, 0);
+ }
+}
diff --git a/sr_vvms/op_zedit.c b/sr_vvms/op_zedit.c
new file mode 100644
index 0000000..4eaa046
--- /dev/null
+++ b/sr_vvms/op_zedit.c
@@ -0,0 +1,128 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gtm_limits.h"
+
+#include <descrip.h>
+#include <rms.h>
+#include <ssdef.h>
+
+#include "io.h"
+#include "zroutines.h"
+#include "stringpool.h"
+#include "op.h"
+#include "setterm.h"
+#include "get_tpu_addr.h"
+#include "min_max.h"
+
+GBLREF io_pair io_std_device;
+GBLREF mval dollar_zsource;
+GBLREF int4 dollar_zeditor;
+
+error_def (ERR_ZEDFILSPEC);
+error_def (ERR_FILENAMETOOLONG);
+
+void op_zedit(mval *v, mval *p)
+{
+ char combuf[259] = {'T', 'P', 'U', ' '};
+ uint4 status;
+ static uint4 (*tpu_entry)() = 0;
+ int comlen, objcnt, typ, ver;
+ struct FAB fab;
+ struct NAM nam;
+ unsigned char es[MAX_FN_LEN];
+ zro_ent *sp, *srcdir;
+ mstr src;
+ $DESCRIPTOR (com,combuf);
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ MV_FORCE_STR(v);
+ MV_FORCE_STR(p);
+ if (MAX_FN_LEN < v->str.len)
+ rts_error(VARLSTCNT(5) ERR_ZEDFILSPEC, 2, MIN(SHRT_MAX, v->str.len), v->str.addr,
+ ERR_FILENAMETOOLONG);
+ fab = cc$rms_fab;
+ fab.fab$l_fna = v->str.addr;
+ fab.fab$b_fns = v->str.len;
+ fab.fab$l_dna = DOTM;
+ fab.fab$b_dns = SIZEOF(DOTM) - 1;
+ fab.fab$l_nam = &nam;
+ nam = cc$rms_nam;
+ nam.nam$l_esa = es;
+ nam.nam$b_ess = SIZEOF(es);
+ status = sys$parse (&fab);
+ if (!(status & 1))
+ rts_error(VARLSTCNT(1) status);
+ if ((SIZEOF(DOTOBJ) - 1 == nam.nam$b_type) && !memcmp (nam.nam$l_type, LIT_AND_LEN(DOTOBJ)))
+ rts_error(VARLSTCNT(4) ERR_ZEDFILSPEC, 2, v->str.len, v->str.addr);
+ ver = nam.nam$b_ver;
+ if (!memcmp(nam.nam$l_type, LIT_AND_LEN(DOTM)))
+ typ = 0;
+ else
+ typ = nam.nam$b_type;
+ if (!(nam.nam$l_fnb & (NAM$M_NODE | NAM$M_EXP_DEV | NAM$M_EXP_DIR)))
+ {
+ src.addr = nam.nam$l_name;
+ src.len = nam.nam$b_name + nam.nam$b_type + nam.nam$b_ver;
+ zro_search (0, 0, &src, &srcdir);
+ if (NULL == srcdir)
+ { /* find the first source directory */
+ objcnt = (TREF(zro_root))->count;
+ for (sp = TREF(zro_root) + 1; (NULL == srcdir) && (0 < objcnt--);)
+ {
+ sp++;
+ if (0 != sp++->count)
+ srcdir = sp;
+ }
+ }
+ if (NULL != srcdir)
+ {
+ fab.fab$l_dna = srcdir->str.addr;
+ fab.fab$b_dns = srcdir->str.len;
+ nam.nam$b_nop = NAM$M_SYNCHK;
+ fab.fab$l_fna = src.addr;
+ fab.fab$b_fns = src.len;
+ status = sys$parse (&fab);
+ if (!(status & 1))
+ rts_error(VARLSTCNT(1) status);
+ }
+ dollar_zsource.str.addr = nam.nam$l_name;
+ dollar_zsource.str.len = nam.nam$b_name + typ;
+ } else
+ {
+ dollar_zsource.str.addr = es;
+ dollar_zsource.str.len = nam.nam$b_esl - nam.nam$b_type + typ - ver;
+ }
+ s2pool(&dollar_zsource.str);
+ comlen = 4;
+ memcpy (&combuf[comlen], es, nam.nam$b_esl);
+ comlen += nam.nam$b_esl;
+ if (0 != p->str.len && (comlen + p->str.len <= SIZEOF(combuf)))
+ {
+ memcpy (&combuf[comlen], p->str.addr, p->str.len);
+ comlen += p->str.len;
+ }
+ com.dsc$w_length = comlen;
+
+ if (tt == io_std_device.in->type)
+ resetterm(io_std_device.in);
+ if (0 == tpu_entry)
+ /* get_tpu_addr really should return a pointer to a uint4 function */
+ tpu_entry = get_tpu_addr();
+ status = (*tpu_entry)(&com);
+ if (tt == io_std_device.in->type)
+ setterm(io_std_device.in);
+ dollar_zeditor = status;
+ if (!(status & 1))
+ rts_error(VARLSTCNT(1) status);
+}
diff --git a/sr_vvms/op_zhelp.c b/sr_vvms/op_zhelp.c
new file mode 100644
index 0000000..8bb9fff
--- /dev/null
+++ b/sr_vvms/op_zhelp.c
@@ -0,0 +1,53 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2004 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gtm_limits.h"
+#include <descrip.h>
+#include "io.h"
+
+#define HLP$M_PROMPT 1
+#define DEFAULT_LIBRARY "GTM$HELP:MUMPS.HLB"
+
+void op_zhelp(mval *text,mval *lib)
+{
+ struct dsc$descriptor helptext, library;
+ int status, flags;
+ error_def(ERR_INVSTRLEN);
+
+ MV_FORCE_STR(text);
+ MV_FORCE_STR(lib);
+ if (SHRT_MAX < text->str.len)
+ rts_error(VARLSTCNT(4) ERR_INVSTRLEN, 2, text->str.len, SHRT_MAX);
+ if (SHRT_MAX < lib->str.len)
+ rts_error(VARLSTCNT(4) ERR_INVSTRLEN, 2, lib->str.len, SHRT_MAX);
+ flush_pio();
+ helptext.dsc$w_length = text->str.len;
+ helptext.dsc$b_dtype = DSC$K_DTYPE_T;
+ helptext.dsc$b_class = DSC$K_CLASS_D;
+ helptext.dsc$a_pointer = text->str.addr;
+ library.dsc$b_dtype = DSC$K_DTYPE_T;
+ library.dsc$b_class = DSC$K_CLASS_D;
+ if (!lib->str.len)
+ {
+ library.dsc$w_length = sizeof DEFAULT_LIBRARY - 1;
+ library.dsc$a_pointer = DEFAULT_LIBRARY;
+ }
+ else
+ {
+ library.dsc$w_length = lib->str.len;
+ library.dsc$a_pointer = lib->str.addr;
+ }
+ flags = HLP$M_PROMPT;
+ status = lbr$output_help(lib$put_output, 0, &helptext, &library, &flags, lib$get_input);
+ if (!(status & 1)) rts_error(VARLSTCNT(1) status);
+ return;
+}
diff --git a/sr_vvms/op_zlink.c b/sr_vvms/op_zlink.c
new file mode 100644
index 0000000..f8876a0
--- /dev/null
+++ b/sr_vvms/op_zlink.c
@@ -0,0 +1,421 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <rms.h>
+#include "gtm_limits.h"
+
+#include "cmd_qlf.h"
+#include "stringpool.h"
+#include "zroutines.h"
+#include "gt_timer.h"
+#include "incr_link.h"
+#include "compiler.h"
+#include "zl_olb.h"
+#include "min_max.h"
+
+#define SRC 1
+#define OBJ 2
+#define NOTYPE 3
+
+#define QUADCMP(p1, p2) (*((unsigned *)p1 + 1) > *((unsigned *)p2 + 1) || \
+ *((unsigned *)p1 + 1) == *((unsigned *)p2 + 1) && *(unsigned *)p1 > *(unsigned *)p2)
+
+GBLREF spdesc stringpool;
+GBLREF command_qualifier cmd_qlf, glb_cmd_qlf;
+GBLREF mval dollar_zsource;
+GBLREF char object_file_name[];
+GBLREF short object_name_len;
+GBLREF struct FAB obj_fab;
+
+error_def (ERR_WILDCARD);
+error_def (ERR_VERSION);
+error_def (ERR_FILENOTFND);
+error_def (ERR_ZLINKFILE);
+error_def (ERR_FILEPARSE);
+error_def (ERR_ZLNOOBJECT);
+error_def (ERR_FILENAMETOOLONG);
+
+void op_zlink(mval *v, mval *quals)
+{
+ struct FAB srcfab;
+ struct NAM srcnam, objnam;
+ struct XABDAT srcxab, objxab;
+ boolean_t compile, expdir, libr, obj_found, src_found;
+ short flen;
+ unsigned short type;
+ unsigned char srccom[MAX_FN_LEN], srcnamebuf[MAX_FN_LEN], objnamebuf[MAX_FN_LEN], objnamelen, srcnamelen,ver[6];
+ unsigned char objcom[MAX_FN_LEN], list_file[MAX_FN_LEN], ceprep_file[MAX_FN_LEN], *fname;
+ zro_ent *srcdir, *objdir;
+ mstr srcstr, objstr, version;
+ mval qualifier;
+ unsigned status, srcfnb;
+ uint4 lcnt, librindx, qlf;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ MV_FORCE_STR(v);
+ if (MAX_FN_LEN < v->str.len)
+ rts_error(VARLSTCNT(5) ERR_ZLINKFILE, 2, MIN(UCHAR_MAX, v->str.len), v->str.addr, ERR_FILENAMETOOLONG);
+ version.len = 0;
+ srcdir = objdir = 0;
+ version.addr = ver;
+ libr = FALSE;
+ obj_fab = cc$rms_fab;
+ if (quals)
+ {
+ MV_FORCE_STR(quals);
+ srcfab = cc$rms_fab;
+ srcfab.fab$l_fna = v->str.addr;
+ srcfab.fab$b_fns = v->str.len;
+ srcfab.fab$l_nam = &srcnam;
+ srcnam = cc$rms_nam;
+ srcnam.nam$l_esa = srcnamebuf;
+ srcnam.nam$b_ess = SIZEOF(srcnamebuf);
+ srcnam.nam$b_nop = NAM$M_SYNCHK;
+ status = sys$parse(&srcfab);
+ if (!(status & 1))
+ rts_error(VARLSTCNT(9) ERR_ZLINKFILE, 2, v->str.len, v->str.addr,
+ ERR_FILEPARSE, 2, v->str.len, v->str.addr, status);
+ if (srcnam.nam$l_fnb & NAM$M_WILDCARD)
+ rts_error(VARLSTCNT(8) ERR_ZLINKFILE, 2, v->str.len, v->str.addr,
+ ERR_WILDCARD, 2, v->str.len, v->str.addr);
+ srcfnb = srcnam.nam$l_fnb;
+ expdir = (srcfnb & (NAM$M_NODE | NAM$M_EXP_DEV | NAM$M_EXP_DIR));
+ if (srcfnb & NAM$M_EXP_VER)
+ {
+ memcpy(version.addr, srcnam.nam$l_ver, srcnam.nam$b_ver);
+ version.len = srcnam.nam$b_ver;
+ }
+ if (expdir)
+ {
+ if (version.len)
+ flen = srcnam.nam$b_esl - srcnam.nam$b_type - version.len;
+ else
+ flen = srcnam.nam$b_esl - srcnam.nam$b_type - 1; /* semicolon is put in by default */
+ fname = srcnam.nam$l_esa;
+ } else
+ {
+ flen = srcnam.nam$b_name;
+ fname = srcnam.nam$l_name;
+ }
+ ENSURE_STP_FREE_SPACE(flen);
+ memcpy(stringpool.free, fname, flen);
+ dollar_zsource.str.addr = stringpool.free;
+ dollar_zsource.str.len = flen;
+ stringpool.free += flen;
+ if (srcfnb & NAM$M_EXP_TYPE)
+ {
+ if ((SIZEOF(DOTOBJ) - 1 == srcnam.nam$b_type) &&
+ !MEMCMP_LIT(srcnam.nam$l_type, DOTOBJ))
+ {
+ type = OBJ;
+ objstr.addr = srcnam.nam$l_esa;
+ objstr.len = srcnam.nam$b_esl;
+ } else
+ {
+ type = SRC;
+ memcpy(srcnamebuf, dollar_zsource.str.addr, flen);
+ memcpy(&srcnamebuf[flen], srcnam.nam$l_type, srcnam.nam$b_type);
+ memcpy(&srcnamebuf[flen + srcnam.nam$b_type],
+ version.addr, version.len);
+ srcnamelen = flen + srcnam.nam$b_type + version.len;
+ srcnamebuf[srcnamelen] = 0;
+ srcstr.addr = srcnamebuf;
+ srcstr.len = srcnamelen;
+ memcpy(objnamebuf, dollar_zsource.str.addr, flen);
+ memcpy(&objnamebuf[flen], DOTOBJ, SIZEOF(DOTOBJ));
+ objnamelen = flen + SIZEOF(DOTOBJ) - 1;
+ objstr.addr = objnamebuf;
+ objstr.len = objnamelen;
+ }
+ } else
+ {
+ type = NOTYPE;
+ memcpy(srcnamebuf, dollar_zsource.str.addr, flen);
+ memcpy(&srcnamebuf[flen], DOTM, SIZEOF(DOTM));
+ srcnamelen = flen + SIZEOF(DOTM) - 1;
+ memcpy(objnamebuf, dollar_zsource.str.addr, flen);
+ MEMCPY_LIT(&objnamebuf[flen], DOTOBJ);
+ memcpy(&objnamebuf[flen + SIZEOF(DOTOBJ) - 1], version.addr, version.len);
+ objnamelen = flen + SIZEOF(DOTOBJ) + version.len - 1;
+ objnamebuf[objnamelen] = 0;
+ srcstr.addr = srcnamebuf;
+ srcstr.len = srcnamelen;
+ objstr.addr = objnamebuf;
+ objstr.len = objnamelen;
+ }
+ if (!expdir)
+ {
+ if (OBJ == type)
+ {
+ zro_search(&objstr, &objdir, 0, 0);
+ if (!objdir)
+ rts_error(VARLSTCNT(8) ERR_ZLINKFILE, 2, dollar_zsource.str.len, dollar_zsource.str.addr,
+ ERR_FILENOTFND, 2, dollar_zsource.str.len, dollar_zsource.str.addr);
+ } else if (SRC == type)
+ {
+ zro_search(&objstr, &objdir, &srcstr, &srcdir);
+ if (!srcdir)
+ rts_error(VARLSTCNT(8) ERR_ZLINKFILE, 2, srcnamelen, srcnamebuf,
+ ERR_FILENOTFND, 2, srcnamelen, srcnamebuf);
+ } else
+ {
+ zro_search(&objstr, &objdir, &srcstr, &srcdir);
+ if (!objdir && !srcdir)
+ rts_error(VARLSTCNT(8) ERR_ZLINKFILE, 2, dollar_zsource.str.len, dollar_zsource.str.addr,
+ ERR_FILENOTFND, 2, dollar_zsource.str.len, dollar_zsource.str.addr);
+ }
+ }
+ } else
+ {
+ expdir = FALSE;
+ type = NOTYPE;
+ flen = v->str.len;
+ memcpy(srcnamebuf, v->str.addr, flen);
+ MEMCPY_LIT(&srcnamebuf[flen], DOTM);
+ srcnamelen = flen + SIZEOF(DOTM) - 1;
+ if ('%' == srcnamebuf[0])
+ srcnamebuf[0] = '_';
+ memcpy(objnamebuf, srcnamebuf, flen);
+ MEMCPY_LIT(&objnamebuf[flen], DOTOBJ);
+ objnamelen = flen + SIZEOF(DOTOBJ) - 1;
+ srcstr.addr = srcnamebuf;
+ srcstr.len = srcnamelen;
+ objstr.addr = objnamebuf;
+ objstr.len = objnamelen;
+ zro_search(&objstr, &objdir, &srcstr, &srcdir);
+ if (!objdir && !srcdir)
+ rts_error(VARLSTCNT(8) ERR_ZLINKFILE, 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)
+ {
+ obj_fab.fab$b_fac = FAB$M_GET;
+ obj_fab.fab$b_shr = FAB$M_SHRGET;
+ if (NULL != objdir)
+ {
+ if (ZRO_TYPE_OBJLIB == objdir->type)
+ libr = TRUE;
+ else
+ {
+ srcfab.fab$l_dna = objdir->str.addr;
+ srcfab.fab$b_dns = objdir->str.len;
+ }
+ }
+ for (lcnt = 0; lcnt < MAX_FILE_OPEN_TRIES; lcnt++)
+ {
+ status = (FALSE == libr) ? sys$open(&srcfab): zl_olb(&objdir->str, &objstr, &librindx);
+ if (RMS$_FLK != status)
+ break;
+ hiber_start(WAIT_FOR_FILE_TIME);
+ }
+ if (FALSE == (status & 1))
+ rts_error(VARLSTCNT(5) ERR_ZLINKFILE, 2, dollar_zsource.str.len, dollar_zsource.str.addr, status);
+ if (FALSE == ((FALSE == libr) ? incr_link(&srcfab, libr) : incr_link(&librindx, libr)))
+ rts_error(VARLSTCNT(5) ERR_ZLINKFILE, 2, dollar_zsource.str.len, dollar_zsource.str.addr, ERR_VERSION);
+ status = (FALSE == libr) ? sys$close(&srcfab) : lbr$close(&librindx);
+ if (FALSE == (status & 1))
+ rts_error(VARLSTCNT(5) ERR_ZLINKFILE, 2, dollar_zsource.str.len, dollar_zsource.str.addr, status);
+ } else /* either NO type or SOURCE type */
+ {
+ src_found = obj_found = compile = FALSE;
+ srcfab = obj_fab = cc$rms_fab;
+ obj_fab.fab$l_xab = &objxab;
+ srcxab = objxab = cc$rms_xabdat;
+ obj_fab.fab$l_nam = &objnam;
+ srcnam = objnam = cc$rms_nam;
+ obj_fab.fab$l_fna = objnamebuf;
+ obj_fab.fab$b_fns = objnamelen;
+ obj_fab.fab$b_fac = FAB$M_GET;
+ obj_fab.fab$b_shr = FAB$M_SHRGET;
+ objnam.nam$l_esa = objcom;
+ objnam.nam$b_ess = SIZEOF(objcom);
+ srcfab.fab$l_nam = &srcnam;
+ srcfab.fab$l_xab = &srcxab;
+ srcfab.fab$l_fna = srcnamebuf;
+ srcfab.fab$b_fns = srcnamelen;
+ srcfab.fab$b_fac = FAB$M_GET;
+ srcfab.fab$b_shr = FAB$M_SHRGET;
+ srcnam.nam$l_esa = srccom;
+ srcnam.nam$b_ess = SIZEOF(srccom);
+ cmd_qlf.object_file.str.addr = objcom;
+ cmd_qlf.object_file.str.len = 255;
+ cmd_qlf.list_file.str.addr = list_file;
+ cmd_qlf.list_file.str.len = 255;
+ cmd_qlf.ceprep_file.str.addr = ceprep_file;
+ cmd_qlf.ceprep_file.str.len = 255;
+ if (srcdir && srcdir->str.len)
+ {
+ srcfab.fab$l_dna = srcdir->str.addr;
+ srcfab.fab$b_dns = srcdir->str.len;
+ }
+ if (objdir && objdir->str.len)
+ {
+ if (ZRO_TYPE_OBJLIB == objdir->type)
+ libr = TRUE;
+ else
+ {
+ obj_fab.fab$l_dna = objdir->str.addr;
+ obj_fab.fab$b_dns = objdir->str.len;
+ }
+ }
+ if (SRC != type)
+ {
+ if (!expdir && !objdir)
+ obj_found = FALSE;
+ else if (!libr)
+ {
+ for (lcnt = 0; lcnt < MAX_FILE_OPEN_TRIES; lcnt++)
+ {
+ status = sys$open(&obj_fab);
+ if (RMS$_FLK != status)
+ break;
+ hiber_start(WAIT_FOR_FILE_TIME);
+ }
+ if (!(status & 1))
+ {
+ if (RMS$_FNF == status)
+ obj_found = FALSE;
+ else
+ rts_error(VARLSTCNT(5) ERR_ZLINKFILE, 2, objnamelen, objnamebuf, status);
+ } else
+ obj_found = TRUE;
+ } else
+ {
+ status = zl_olb(&objdir->str, &objstr, &librindx);
+ if (status)
+ obj_found = TRUE;
+ }
+ } else
+ compile = TRUE;
+ if (!expdir && !srcdir)
+ src_found = FALSE;
+ else
+ {
+ for (lcnt = 0; lcnt < MAX_FILE_OPEN_TRIES; lcnt++)
+ {
+ status = sys$open(&srcfab);
+ if (RMS$_FLK != status)
+ break;
+ hiber_start(WAIT_FOR_FILE_TIME);
+ }
+ if (!(status & 1))
+ {
+ if ((RMS$_FNF == status) && (SRC != type))
+ src_found = FALSE;
+ else
+ rts_error(VARLSTCNT(5) ERR_ZLINKFILE, 2, srcnamelen, srcnamebuf, status);
+ } else
+ {
+ src_found = TRUE;
+ if (SRC == type)
+ {
+ status = sys$close(&srcfab);
+ if (!(status & 1))
+ rts_error(VARLSTCNT(5) ERR_ZLINKFILE, 2, srcnamelen, srcnamebuf, status);
+ }
+ }
+ }
+ if (SRC != type)
+ {
+ if (src_found)
+ {
+ if (obj_found)
+ {
+ if (QUADCMP(&srcxab.xab$q_rdt, &objxab.xab$q_rdt))
+ {
+ status = sys$close(&obj_fab);
+ obj_fab = cc$rms_fab;
+ if (!(status & 1))
+ rts_error(VARLSTCNT(5) ERR_ZLINKFILE, 2, objnamelen, objnamebuf, status);
+ compile = TRUE;
+ }
+ } else
+ compile = TRUE;
+ status = sys$close(&srcfab);
+ if (!(status & 1))
+ rts_error(VARLSTCNT(5) ERR_ZLINKFILE, 2, srcnamelen, srcnamebuf, status);
+ } else if (!obj_found)
+ rts_error(VARLSTCNT(8) ERR_ZLINKFILE, 2, objnamelen, objnamebuf,
+ ERR_FILENOTFND, 2, objnamelen, objnamebuf);
+ }
+ if (compile)
+ {
+ zl_cmd_qlf(&quals->str, &cmd_qlf);
+ if (!MV_DEFINED(&cmd_qlf.object_file))
+ {
+ objnam.nam$b_nop = NAM$M_SYNCHK;
+ status = sys$parse(&obj_fab);
+ if (!(status & 1))
+ rts_error(VARLSTCNT(4) ERR_FILEPARSE, 2, obj_fab.fab$b_fns, obj_fab.fab$l_fna);
+ cmd_qlf.object_file.mvtype = MV_STR;
+ cmd_qlf.object_file.str.len = objnam.nam$b_esl - objnam.nam$b_ver;
+ }
+ qlf = cmd_qlf.qlf;
+ if (!(cmd_qlf.qlf & CQ_OBJECT) && (SRC != type))
+ {
+ cmd_qlf.qlf = glb_cmd_qlf.qlf;
+ rts_error(VARLSTCNT(5) ERR_ZLINKFILE, 2, srcnamelen, srcnamebuf, ERR_ZLNOOBJECT);
+ }
+ zlcompile(srcnam.nam$b_esl, srcnam.nam$l_esa);
+ if ((SRC == type) && !(qlf & CQ_OBJECT))
+ return;
+ }
+ status = libr ? incr_link(&librindx, libr) : incr_link(&obj_fab, libr);
+ if (!status) /* due only to version mismatch, so recompile */
+ {
+ if (!libr)
+ {
+ status = sys$close(&obj_fab);
+ obj_fab = cc$rms_fab;
+ } else
+ status = lbr$close(&librindx);
+ if (!(status & 1))
+ rts_error(VARLSTCNT(5) ERR_ZLINKFILE, 2, objstr.len, objstr.addr, status);
+ if (compile)
+ GTMASSERT;
+ if (!src_found)
+ rts_error(VARLSTCNT(5) ERR_ZLINKFILE, 2, srcnamelen, srcnamebuf, ERR_VERSION);
+ zl_cmd_qlf(&quals->str, &cmd_qlf);
+ if (!MV_DEFINED(&cmd_qlf.object_file))
+ {
+ objnam.nam$b_nop = NAM$M_SYNCHK;
+ status = sys$parse(&obj_fab);
+ if (!(status & 1))
+ rts_error(VARLSTCNT(4) ERR_FILEPARSE, 2, obj_fab.fab$b_fns, obj_fab.fab$l_fna);
+ cmd_qlf.object_file.mvtype = MV_STR;
+ cmd_qlf.object_file.str.len = objnam.nam$b_esl - objnam.nam$b_ver;
+ }
+ if (!(cmd_qlf.qlf & CQ_OBJECT) && (SRC != type))
+ {
+ cmd_qlf.qlf = glb_cmd_qlf.qlf;
+ rts_error(VARLSTCNT(5) ERR_ZLINKFILE, 2, srcnamelen, srcnamebuf, ERR_ZLNOOBJECT);
+ }
+ zlcompile(srcnam.nam$b_esl, srcnam.nam$l_esa);
+ if (!incr_link(&obj_fab, libr))
+ GTMASSERT;
+ }
+ if (!libr)
+ {
+ status = sys$close(&obj_fab);
+ obj_fab = cc$rms_fab;
+ } else
+ status = lbr$close(&librindx);
+ if (!(status & 1))
+ rts_error(VARLSTCNT(5) ERR_ZLINKFILE, 2, objstr.len, objstr.addr, status);
+ }
+ return;
+}
diff --git a/sr_vvms/op_zmess.c b/sr_vvms/op_zmess.c
new file mode 100644
index 0000000..f29e6fd
--- /dev/null
+++ b/sr_vvms/op_zmess.c
@@ -0,0 +1,71 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "fao_parm.h"
+#include <descrip.h>
+#include <ssdef.h>
+#include <stdarg.h>
+#include "mval2fao.h"
+#include "op.h"
+#include "tp_restart.h"
+
+#define FAO_BUFFER_SPACE 2048
+#define MAX_MSG_SIZE 256
+
+void op_zmess(int4 errnum, ...)
+{
+ va_list var;
+ int4 status, cnt, faocnt;
+ unsigned short m_len;
+ unsigned char faostat[4];
+ unsigned char msgbuff[MAX_MSG_SIZE + 1];
+ unsigned char buff[FAO_BUFFER_SPACE];
+ int4 fao[MAX_FAO_PARMS + 1];
+ $DESCRIPTOR(d_sp, msgbuff);
+
+ error_def(ERR_TPRETRY);
+
+ VAR_START(var, errnum);
+ va_count(cnt);
+ cnt--;
+ status = sys$getmsg(errnum, &m_len, &d_sp, 0, &faostat[0]);
+ if ((status & 1) && m_len)
+ {
+ buff[m_len] = 0;
+ memset(&fao[0], 0, SIZEOF(fao));
+ faocnt = (cnt ? faostat[1] : cnt);
+ faocnt = (faocnt > MAX_FAO_PARMS ? MAX_FAO_PARMS : faocnt);
+ if (faocnt)
+ faocnt = mval2fao(msgbuff, var, &fao[0], cnt, faocnt, buff, buff + SIZEOF(buff));
+ va_end(var);
+ if (faocnt != -1)
+ {
+ /* Currently there are a max of 20 fao parms (MAX_FAO_PARMS) allowed, hence passing upto fao_list[19].
+ * An assert is added to ensure this code is changed whenever the macro MAX_FAO_PARMS is changed.
+ * The # of arguments passed below should change accordingly.
+ */
+ assert(MAX_FAO_PARMS == 20);
+ if (ERR_TPRETRY == errnum)
+ { /* A TP restart is being signalled. Set t_fail_hist just like a TRESTART command would */
+ op_trestart_set_cdb_code();
+ }
+ rts_error(VARLSTCNT(MAX_FAO_PARMS + 2) errnum, faocnt, fao[0], fao[1], fao[2], fao[3], fao[4], fao[5],
+ fao[6], fao[7], fao[8], fao[9], fao[10], fao[11], fao[12], fao[13], fao[14], fao[15], fao[16],
+ fao[17], fao[18], fao[19]);
+ }
+ return;
+ } else
+ {
+ va_end(var);
+ rts_error(VARLSTCNT(1) status);
+ }
+}
diff --git a/sr_vvms/pid.m b/sr_vvms/pid.m
new file mode 100644
index 0000000..20bfce0
--- /dev/null
+++ b/sr_vvms/pid.m
@@ -0,0 +1,64 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ;
+; Copyright 1990, 2002 Sanchez Computer Associates, Inc. ;
+; ;
+; This source code contains the intellectual property ;
+; of its copyright holder(s), and is made available ;
+; under a license. If you do not know the terms of ;
+; the license, please stop and do not read further. ;
+; ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+PID ; operations on VMS pids
+ ;
+DELPRC(p);
+ n id,oldpriv,st,$zt
+ s ($zt,zt)="d error",oldpriv=$zsetprv("GROUP,WORLD"),id=""
+ f s id=$o(p(id)) q:id="" s st=$zc("DELPRC",id) w !,"Deleting process ",p(id)
+ i $zsetprv(oldpriv)
+ q
+FORCEX(p);
+ n id,oldpriv,st,$zt
+ s ($zt,zt)="d error",oldpriv=$zsetprv("GROUP,WORLD"),id=""
+ f s id=$o(p(id)) q:id="" s st=$zc("FORCEX",id) w !,"Stopping process ",p(id)
+ i $zsetprv(oldpriv)
+ q
+GETIMG(img,p);
+ q:'$l($g(img))
+ n id,oldpriv,$zt
+ k p s p=0,img=$tr(img,"abcdefghijklmnopqrstuvwxyz","ABCDEFGHIJKLMNOPQRSTUVWXYZ")
+ s ($zt,zt)="d error",oldpriv=$zsetprv("GROUP,WORLD"),id=$zpid(0)
+ d f s id=$zpid(1) q:id="" d
+ . i $zparse($zgetjpi(id,"IMAGNAME"),"NAME")=img s p(id)=$$FUNC^%DH(id,8),p=p+1
+ i $zsetprv(oldpriv)
+ q
+SHOW(p);
+ n id s id=""
+ f s id=$o(p(id)) q:id="" w !,p(id)
+ q
+SHOWIMG n image,pid
+ r !,"Image name: ",image d GETIMG(image,.pid)
+ i 'pid w !,"No processes found running that image" q
+ w !,"The following processes are running image ",image,":"
+ d SHOW(.pid)
+ q
+STOPIMG n image,pid,wait
+ r !,"Image name: ",image d GETIMG(image,.pid)
+ i 'pid w !,"No processes found running that image" q
+ r !,"Pause in seconds between FORCEX and DELPRC: ",wait
+ d STPIMG(image,wait)
+ q
+STPIMG(img,wt)
+ q:'$l($g(img))
+ n t,pid s wt=$g(wt) s:wt<1 wt=20
+ d GETIMG(img,.pid)
+ i 'pid w !,"No processes stopped" q
+ d FORCEX(.pid)
+ f t=1:1:wt h 1 d GETIMG(img,.pid) q:'pid
+ i pid d DELPRC(.pid):pid
+ q
+error w !
+ i $d(id),id w "Unable to access process with pid: ",$$FUNC^%DH(id)
+ e w $p($zs,",",2,99),!
+ i $zs["GETIMG" s id=0
+ s $zt=zt
+ q
diff --git a/sr_vvms/probe.c b/sr_vvms/probe.c
new file mode 100644
index 0000000..b0e4b00
--- /dev/null
+++ b/sr_vvms/probe.c
@@ -0,0 +1,44 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "min_max.h"
+
+GBLREF int4 rundown_os_page_size;
+
+boolean_t probe(uint4 len, sm_uc_ptr_t addr, boolean_t write)
+{
+ sm_uc_ptr_t top;
+ uint4 status;
+
+ if ((int4)len <= 0)
+ return FALSE;
+ top = addr + len;
+ if (addr >= top) /* in case addr + len resulted in a top that wrapped (was beyond the representable range) */
+ return FALSE;
+ /* the following MUST use ROUND_DOWN2 to avoid bringing in the C RTL to help with integer division;
+ if any RTL comes into GTMSECSHR, the link looks fine, but the loader doesn't and the 1st call to SYS$ ACCVIOs */
+ len = MIN(ROUND_DOWN2((sm_ulong_t)addr, 2 * rundown_os_page_size) + (2 * rundown_os_page_size) - (sm_ulong_t)addr, len);
+ for (; addr < top; )
+ { /* check every page from addr to addr + len - 1, at most, 2 at a time,
+ * because probe just checks the first and last bytes of the interval specified by its arguments */
+ if (write)
+ status = probew(len > 1 ? len - 1 : 0, addr);
+ else
+ status = prober(len > 1 ? len - 1 : 0, addr);
+ if (!status)
+ return FALSE;
+ addr += len;
+ len = MIN(top - addr, 2 * rundown_os_page_size);
+ }
+ return TRUE;
+}
diff --git a/sr_vvms/prvdef.h b/sr_vvms/prvdef.h
new file mode 100644
index 0000000..42f8d07
--- /dev/null
+++ b/sr_vvms/prvdef.h
@@ -0,0 +1,87 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#define PRV$M_CMKRNL 1
+#define PRV$M_CMEXEC 2
+#define PRV$M_SYSNAM 4
+#define PRV$M_GRPNAM 8
+#define PRV$M_ALLSPOOL 16
+#define PRV$M_DETACH 32
+#define PRV$M_DIAGNOSE 64
+#define PRV$M_LOG_IO 128
+#define PRV$M_GROUP 256
+#define PRV$M_NOACNT 512
+#define PRV$M_PRMCEB 1024
+#define PRV$M_PRMMBX 2048
+#define PRV$M_PSWAPM 4096
+#define PRV$M_SETPRI 8192
+#define PRV$M_SETPRV 16384
+#define PRV$M_TMPMBX 32768
+#define PRV$M_WORLD 65536
+#define PRV$M_MOUNT 131072
+#define PRV$M_OPER 262144
+#define PRV$M_EXQUOTA 524288
+#define PRV$M_NETMBX 1048576
+#define PRV$M_VOLPRO 2097152
+#define PRV$M_PHY_IO 4194304
+#define PRV$M_BUGCHK 8388608
+#define PRV$M_PRMGBL 16777216
+#define PRV$M_SYSGBL 33554432
+#define PRV$M_PFNMAP 67108864
+#define PRV$M_SHMEM 134217728
+#define PRV$M_SYSPRV 268435456
+#define PRV$M_BYPASS 536870912
+#define PRV$M_SYSLCK 1073741824
+#define PRV$M_SHARE -2147483648
+#define PRV$M_ACNT 512
+#define PRV$M_ALTPRI 8192
+#define PRV$S_PRVDEF 5
+#define PRV$V_CMKRNL 0
+#define PRV$V_CMEXEC 1
+#define PRV$V_SYSNAM 2
+#define PRV$V_GRPNAM 3
+#define PRV$V_ALLSPOOL 4
+#define PRV$V_DETACH 5
+#define PRV$V_DIAGNOSE 6
+#define PRV$V_LOG_IO 7
+#define PRV$V_GROUP 8
+#define PRV$V_NOACNT 9
+#define PRV$V_PRMCEB 10
+#define PRV$V_PRMMBX 11
+#define PRV$V_PSWAPM 12
+#define PRV$V_SETPRI 13
+#define PRV$V_SETPRV 14
+#define PRV$V_TMPMBX 15
+#define PRV$V_WORLD 16
+#define PRV$V_MOUNT 17
+#define PRV$V_OPER 18
+#define PRV$V_EXQUOTA 19
+#define PRV$V_NETMBX 20
+#define PRV$V_VOLPRO 21
+#define PRV$V_PHY_IO 22
+#define PRV$V_BUGCHK 23
+#define PRV$V_PRMGBL 24
+#define PRV$V_SYSGBL 25
+#define PRV$V_PFNMAP 26
+#define PRV$V_SHMEM 27
+#define PRV$V_SYSPRV 28
+#define PRV$V_BYPASS 29
+#define PRV$V_SYSLCK 30
+#define PRV$V_SHARE 31
+#define PRV$V_UPGRADE 32
+#define PRV$V_DOWNGRADE 33
+#define PRV$V_GRPPRV 34
+#define PRV$V_READALL 35
+#define PRV$V_TMPJNL 36
+#define PRV$V_PRMJNL 37
+#define PRV$V_SECURITY 38
+#define PRV$V_ACNT 9
+#define PRV$V_ALTPRI 13
diff --git a/sr_vvms/quad2asc.c b/sr_vvms/quad2asc.c
new file mode 100644
index 0000000..7967c4c
--- /dev/null
+++ b/sr_vvms/quad2asc.c
@@ -0,0 +1,96 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <descrip.h>
+#include <libdef.h>
+#include "quad2asc.h"
+
+/* convert a GOQ data value to a canonical MUMPS string */
+
+int quad2asc(int4 mantissa[2],char exponent,unsigned char *outaddr,unsigned short outaddrlen,unsigned short *actual_len)
+/*
+int4 mantissa[2]; a quad word which is the 'mantissa'
+char exponent; the decimal exponent
+unsigned char *outaddr; the address to put the output string
+unsigned short outaddrlen; the maximum length of the output string
+unsigned short *actual_len; the actual length of the output string
+*/
+/* value returned: status code */
+{
+ struct dsc$descriptor in, out;
+ int4 status;
+ int n,m;
+ unsigned char *cp;
+ int4 exp;
+
+ in.dsc$w_length = SIZEOF(mantissa);
+ in.dsc$b_dtype = DSC$K_DTYPE_Q;
+ in.dsc$b_class = DSC$K_CLASS_S;
+ in.dsc$a_pointer = mantissa;
+ out.dsc$w_length = outaddrlen;
+ out.dsc$b_dtype = DSC$K_DTYPE_T;
+ out.dsc$b_class = DSC$K_CLASS_S;
+ out.dsc$a_pointer = outaddr;
+ status = lib$cvt_dx_dx(&in,&out,actual_len);
+ if ((status & 1) == 0)
+ rts_error(VARLSTCNT(1) status);
+ exp = exponent;
+ if (*actual_len == 1 && *outaddr == '0')
+ return status;
+ if (exp > 0)
+ {
+ n = exp + *actual_len;
+ if (n > outaddrlen)
+ return LIB$_DESSTROVF;
+ for (m = exp, cp = outaddr + *actual_len ; m > 0 ; m--)
+ *cp++ = '0';
+ *actual_len = n;
+ }
+ else if (exp < 0)
+ {
+ exp = - exp;
+ n = *actual_len;
+ cp = outaddr;
+ if (*cp == '-')
+ {
+ n--;
+ cp++;
+ }
+ m = n - exp;
+ if (m <= 0)
+ {
+ m = - m;
+ if (n + m + 1 > outaddrlen)
+ return LIB$_DESSTROVF;
+ *actual_len += m + 1;
+ memcpy(cp + m + 1, cp, n);
+ *cp++ = '.';
+ memset(cp, '0', m);
+ } else
+ {
+ if (n + 1 > outaddrlen)
+ return LIB$_DESSTROVF;
+ *actual_len += 1;
+ cp += m;
+ memcpy(cp + 1, cp, n - 1);
+ *cp = '.';
+ }
+ for (cp = outaddr + *actual_len, n = 0; cp > outaddr + 1; *actual_len -= 1)
+ {
+ if (*--cp != '0')
+ break;
+ }
+ if (*cp == '.')
+ *actual_len -= 1;
+ }
+ return status;
+}
diff --git a/sr_vvms/quad2asc.h b/sr_vvms/quad2asc.h
new file mode 100644
index 0000000..109d246
--- /dev/null
+++ b/sr_vvms/quad2asc.h
@@ -0,0 +1,18 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef QUAD2ASC_INCLUDED
+#define QUAD2ASC_INCLUDED
+
+int quad2asc(int4 mantissa[], char exponent, unsigned char *outaddr,
+ unsigned short outaddrlen, unsigned short *actual_len); /***type int added***/
+
+#endif /* QUAD2ASC_INCLUDED */
diff --git a/sr_vvms/rc_cpt_ops.c b/sr_vvms/rc_cpt_ops.c
new file mode 100644
index 0000000..cbd65e9
--- /dev/null
+++ b/sr_vvms/rc_cpt_ops.c
@@ -0,0 +1,37 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* STUB file for VMS */
+#include "rc_cpt_ops.h"
+
+int rc_cpt_entry(int blk)
+{
+ return 0;
+}
+
+void rc_cpt_unlock(void)
+{ return;
+}
+
+void rc_cpt_lock(void)
+{ return;
+}
+
+int rc_cpt_inval(void)
+{ return 0;
+}
+
+void rc_close_section(void)
+{
+ return;
+}
+
+
diff --git a/sr_vvms/recvpool_init.c b/sr_vvms/recvpool_init.c
new file mode 100644
index 0000000..80a9d38
--- /dev/null
+++ b/sr_vvms/recvpool_init.c
@@ -0,0 +1,216 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <ssdef.h>
+#include <prtdef.h>
+#include <secdef.h>
+#include <psldef.h>
+#include <descrip.h>
+#include <stddef.h>
+
+#include <errno.h>
+#include "gtm_fcntl.h"
+#include "gtm_unistd.h"
+#include "gtm_inet.h"
+#include "gtm_string.h"
+
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "repl_sem.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "iosp.h"
+#include "jnl.h"
+#include "gtmrecv.h"
+#include "gtm_logicals.h"
+#include "repl_shm.h"
+#include "repl_shutdcode.h"
+#include "io.h"
+#include "is_file_identical.h"
+#include "trans_log_name.h"
+#include "interlock.h"
+
+GBLREF recvpool_addrs recvpool;
+GBLREF int recvpool_shmid;
+GBLREF uint4 process_id;
+GBLREF gtmrecv_options_t gtmrecv_options;
+
+error_def(ERR_RECVPOOLSETUP);
+error_def(ERR_TEXT);
+
+LITREF char gtm_release_name[];
+LITREF int4 gtm_release_name_len;
+
+#define MAX_RES_TRIES 620 /* Also defined in gvcst_init_sysops.c */
+#define MEGA_BOUND (1024*1024)
+
+void recvpool_init(recvpool_user pool_user,
+ boolean_t gtmrecv_startup,
+ boolean_t lock_opt_sem)
+{
+ mstr log_nam, trans_log_nam;
+ char trans_buff[MAX_FN_LEN+1];
+ key_t recvpool_key;
+ int4 status;
+ uint4 ustatus;
+ int lcnt;
+ unsigned int full_len;
+ sm_long_t status_l;
+ boolean_t shm_created;
+ int semflgs;
+ struct dsc$descriptor_s name_dsc;
+ char res_name[MAX_NAME_LEN + 2]; /* +1 for null terminator and another +1 for the length stored in [0]
+ by global_name() */
+ gds_file_id file_id;
+
+ log_nam.addr = GTM_GBLDIR;
+ log_nam.len = SIZEOF(GTM_GBLDIR) - 1;
+ if (SS_NORMAL != trans_log_name(&log_nam, &trans_log_nam, trans_buff))
+ rts_error(VARLSTCNT(6) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("gtm$gbldir not defined"));
+ trans_buff[trans_log_nam.len] = '\0';
+ full_len = trans_log_nam.len;
+ if (!get_full_path(&trans_buff, trans_log_nam.len, &trans_buff, &full_len, MAX_TRANS_NAME_LEN, &ustatus))
+ rts_error(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Failed to get full path for gtm$gbldir"), ustatus);
+ trans_log_nam.len = full_len; /* since on vax, mstr.len is a 'short' */
+ /* Get Journal Pool Resource Name : name_dsc holds the resource name */
+ set_gdid_from_file((gd_id_ptr_t)&file_id, trans_buff, trans_log_nam.len);
+ global_name("GT$R", &file_id, res_name); /* R - Stands for Receiver Pool */
+ name_dsc.dsc$a_pointer = &res_name[1];
+ name_dsc.dsc$w_length = res_name[0];
+ name_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
+ name_dsc.dsc$b_class = DSC$K_CLASS_S;
+ name_dsc.dsc$a_pointer[name_dsc.dsc$w_length] = '\0';
+
+ /*
+ * We need to do some receive pool locking. The first lock
+ * to obtain is the receive pool access control
+ * lock which is also used as the rundown lock. When one has
+ * this, no new attaches to the receive pool are allowed.
+ * Also, a rundown cannot occur. We will get this lock,
+ * then initialize the fields (if not already initialized)
+ * before we release the access control lock.
+ * Refer to repl_sem.h for an enumeration of semaphores in the sem-set
+ */
+
+ assert(NUM_SRC_SEMS == NUM_RECV_SEMS);
+ if(0 != init_sem_set_recvr(&name_dsc))
+ rts_error(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0,
+ ERR_TEXT, 2, RTS_ERROR_LITERAL("Error with receiver pool sem init."), REPL_SEM_ERRNO);
+ if(0 != grab_sem(RECV, RECV_POOL_ACCESS_SEM))
+ rts_error(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0,
+ ERR_TEXT, 2, RTS_ERROR_LITERAL("Error with receive pool semaphores"), REPL_SEM_ERRNO);
+
+ /* Store the recvpool key */
+ memcpy(recvpool.vms_recvpool_key.name, name_dsc.dsc$a_pointer, name_dsc.dsc$w_length);
+ recvpool.vms_recvpool_key.desc.dsc$a_pointer = recvpool.vms_recvpool_key.name;
+ recvpool.vms_recvpool_key.desc.dsc$w_length = name_dsc.dsc$w_length;
+ recvpool.vms_recvpool_key.desc.dsc$b_dtype = DSC$K_DTYPE_T;
+ recvpool.vms_recvpool_key.desc.dsc$b_class = DSC$K_CLASS_S;
+
+ /* Registering with the global section involves grabbing a lock on the recvpool global section
+ * in the ConcurrentRead mode (CR). This lock will be used when deleting the recvpool (in signoff_from_gsec())
+ * to make sure that nobody else is attached to the recvpool global section when detaching from it*/
+
+ if (SS$_NORMAL != (status = register_with_gsec(&recvpool.vms_recvpool_key.desc, &recvpool.shm_lockid)))
+ rts_error(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Unable to get lock on recvpool"), status);
+
+ if (GTMRECV != pool_user || !gtmrecv_startup)
+ { /* Global section should already exist */
+ if(SS$_NORMAL != (status = map_shm(RECV, &name_dsc, recvpool.shm_range)))
+ {
+ signoff_from_gsec(recvpool.shm_lockid);
+ rts_error(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Receive pool does not exist"), status);
+ }
+ shm_created = FALSE;
+ } else
+ {
+ status = create_and_map_shm(RECV, &name_dsc, gtmrecv_options.buffsize, recvpool.shm_range);
+ if (SS$_CREATED == status)
+ shm_created = TRUE;
+ else if (SS$_NORMAL == status)
+ shm_created = FALSE;
+ else
+ {
+ signoff_from_gsec(recvpool.shm_lockid);
+ rts_error(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0,
+ ERR_TEXT, 2, RTS_ERROR_LITERAL("Unalble to create or map to recvpool global section"), status);
+ }
+ }
+
+ recvpool_shmid = 1; /* A value > 0, as an indication of the existance of recvpool gsec */
+
+ /* Initialize receiver pool pointers to point to appropriate shared memory locations */
+ recvpool.recvpool_ctl = recvpool.shm_range[0];
+ if (shm_created)
+ recvpool.recvpool_ctl->initialized = FALSE;
+ recvpool.upd_proc_local = (upd_proc_local_ptr_t)((sm_uc_ptr_t)recvpool.recvpool_ctl + RECVPOOL_CTL_SIZE);
+ recvpool.gtmrecv_local = (gtmrecv_local_ptr_t)((sm_uc_ptr_t)recvpool.upd_proc_local + UPD_PROC_LOCAL_SIZE);
+ recvpool.upd_helper_ctl = (upd_helper_ctl_ptr_t)((sm_uc_ptr_t)recvpool.gtmrecv_local + GTMRECV_LOCAL_SIZE);
+ recvpool.recvdata_base = (sm_uc_ptr_t)recvpool.recvpool_ctl + RECVDATA_BASE_OFF;
+ if (GTMRECV == pool_user && gtmrecv_startup)
+ recvpool.recvpool_ctl->fresh_start = FALSE;
+ if (!recvpool.recvpool_ctl->initialized)
+ {
+ if (pool_user != GTMRECV || !gtmrecv_startup)
+ rts_error(VARLSTCNT(6) ERR_RECVPOOLSETUP, 0,
+ ERR_TEXT, 2, RTS_ERROR_LITERAL("Receive pool has not been initialized"));
+
+ /* Initialize the shared memory fields */
+ QWASSIGNDW(recvpool.recvpool_ctl->start_jnl_seqno, 0);
+ recvpool.recvpool_ctl->recvdata_base_off = RECVDATA_BASE_OFF;
+ recvpool.recvpool_ctl->recvpool_size = gtmrecv_options.buffsize - recvpool.recvpool_ctl->recvdata_base_off;
+ recvpool.recvpool_ctl->write = 0;
+ recvpool.recvpool_ctl->write_wrap = recvpool.recvpool_ctl->recvpool_size;
+ strcpy(recvpool.recvpool_ctl->recvpool_id.repl_pool_key, name_dsc.dsc$a_pointer);
+ recvpool.recvpool_ctl->wrapped = FALSE;
+ strcpy(recvpool.recvpool_ctl->recvpool_id.gtmgbldir, trans_buff);
+ memcpy(recvpool.recvpool_ctl->recvpool_id.label, GDS_RPL_LABEL, GDS_LABEL_SZ);
+ memcpy(recvpool.recvpool_ctl->recvpool_id.now_running, gtm_release_name, gtm_release_name_len + 1);
+ assert(0 == (offsetof(recvpool_ctl_struct, start_jnl_seqno) % 8));
+ /* ensure that start_jnl_seqno starts at an 8 byte boundary */
+ assert(0 == offsetof(recvpool_ctl_struct, recvpool_id));
+ /* ensure that the pool identifier is at the top of the pool */
+ recvpool.recvpool_ctl->recvpool_id.pool_type = RECVPOOL_SEGMENT;
+ recvpool.upd_proc_local->upd_proc_shutdown = NO_SHUTDOWN;
+ recvpool.upd_proc_local->upd_proc_shutdown_time = -1;
+ recvpool.upd_proc_local->upd_proc_pid = 0;
+ recvpool.upd_proc_local->upd_proc_pid_prev = 0;
+ recvpool.upd_proc_local->updateresync = gtmrecv_options.updateresync;
+ recvpool.gtmrecv_local->recv_serv_pid = process_id;
+ recvpool.gtmrecv_local->lastrecvd_time = -1;
+ recvpool.gtmrecv_local->restart = GTMRECV_NO_RESTART;
+ recvpool.gtmrecv_local->statslog = FALSE;
+ recvpool.gtmrecv_local->shutdown = NO_SHUTDOWN;
+ recvpool.gtmrecv_local->shutdown_time = -1;
+ strcpy(recvpool.gtmrecv_local->filter_cmd, gtmrecv_options.filter_cmd);
+ recvpool.gtmrecv_local->statslog_file[0] = '\0';
+ memset(recvpool.upd_helper_ctl, 0, SIZEOF(*recvpool.upd_helper_ctl));
+ SET_LATCH_GLOBAL(&recvpool.upd_helper_ctl->pre_read_lock, LOCK_AVAILABLE);
+ recvpool.recvpool_ctl->initialized = TRUE;
+ recvpool.recvpool_ctl->fresh_start = TRUE;
+ }
+
+ /* If startup, lock out checkhealth and receiver startup */
+ if (GTMRECV == pool_user && lock_opt_sem && 0 != grab_sem(RECV, RECV_SERV_OPTIONS_SEM))
+ rts_error(VARLSTCNT(7) ERR_RECVPOOLSETUP, 0, ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Error with receive pool options semaphore"), REPL_SEM_ERRNO);
+ /* Release receiver pool control lock out now that it is initialized */
+ rel_sem(RECV, RECV_POOL_ACCESS_SEM);
+ return;
+}
diff --git a/sr_vvms/reg_cmcheck.c b/sr_vvms/reg_cmcheck.c
new file mode 100644
index 0000000..072083b
--- /dev/null
+++ b/sr_vvms/reg_cmcheck.c
@@ -0,0 +1,51 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include <syidef.h>
+#include <rms.h>
+
+bool reg_cmcheck(gd_region *reg)
+{
+ struct FAB fcb;
+ struct NAM nam;
+ int4 status, iosb[2];
+ short i, len;
+ char node[16], nambuf[MAX_FN_LEN];
+ struct {short blen; short code; char *buf; short *len;} itm[2] = {{15, SYI$_NODENAME, &node, &len},{0, 0, 0, 0}};
+ error_def(ERR_DBOPNERR);
+
+ nam = cc$rms_nam;
+ nam.nam$l_esa = nambuf;
+ nam.nam$b_ess = SIZEOF(nambuf);
+ nam.nam$b_nop |= NAM$M_SYNCHK;
+ fcb = cc$rms_fab;
+ fcb.fab$l_fna = reg->dyn.addr->fname;
+ fcb.fab$b_fns = reg->dyn.addr->fname_len;
+ fcb.fab$l_dna = reg->dyn.addr->defext;
+ fcb.fab$b_dns = SIZEOF(reg->dyn.addr->defext);
+ fcb.fab$l_nam = &nam;
+ fcb.fab$w_deq = 0;
+ if ((status = sys$parse(&fcb, 0, 0)) != RMS$_NORMAL)
+ rts_error(VARLSTCNT(5) ERR_DBOPNERR, 2, fcb.fab$b_fns, fcb.fab$l_fna, status);
+ i = nam.nam$b_node ;
+ if (0 != i)
+ {
+ sys$getsyi(0, 0, 0, itm, iosb, 0, 0);
+ return ((i - 2) != len || 0 != memcmp(nam.nam$l_esa, node, len));
+ }
+ return FALSE;
+}
diff --git a/sr_vvms/rel_crit.c b/sr_vvms/rel_crit.c
new file mode 100644
index 0000000..77b5d9d
--- /dev/null
+++ b/sr_vvms/rel_crit.c
@@ -0,0 +1,85 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2008 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <signal.h> /* for VSIG_ATOMIC_T type */
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "ccp.h"
+#include "ccpact.h"
+#include "filestruct.h"
+#include "have_crit.h"
+
+error_def(ERR_CRITRESET);
+error_def(ERR_DBCCERR);
+
+GBLREF short crash_count;
+GBLREF volatile int4 crit_count;
+GBLREF uint4 process_id;
+
+void rel_crit(gd_region *reg)
+{
+ ccp_action_aux_value msg;
+ sgmnt_addrs *csa;
+ enum cdb_sc status;
+
+ csa = &FILE_INFO(reg)->s_addrs;
+ if (csa->now_crit)
+ {
+ assert(0 == crit_count);
+ crit_count++;
+ assert(csa->nl->in_crit == process_id || csa->nl->in_crit == 0); /* : crit was held by this process */
+
+ /* [lidral] The next assert is commented out because it caused failures in the test suite, although it was
+ * believed to be correct when added. At the time it was added, no one knew what the comment about timeout
+ * causing re-entry with in_crit cleared meant -- it has been left as a potential clue for future
+ * investigation.
+ */
+ /* Timeout can cause reentry with in_crit cleared */
+ /* assert(csa->hdr->clustered || csa->nl->in_crit != 0); */ /* : in_crit can be clear only if clustered */
+
+ CRIT_TRACE(crit_ops_rw); /* see gdsbt.h for comment on placement */
+
+ csa->nl->in_crit = 0;
+
+ if (csa->hdr->clustered && csa->nl->ccp_crit_blocked)
+ {
+ /* For an explanation of the code dealing with clusters, see CCP_EXITWM_ATTEMPT.C.
+ Please do not change this code without updating the comments in that file. */
+ msg.exreq.fid = FILE_INFO(reg)->file_id;
+ msg.exreq.cycle = csa->nl->ccp_cycle;
+ (void)ccp_sendmsg(CCTR_EXITWM, &msg);
+ (void)ccp_userwait(reg, CCST_MASK_WMXGNT | CCST_MASK_RDMODE, 0, msg.exreq.cycle);
+ }
+
+ if ((status = mutex_unlockw(csa->critical, crash_count, &csa->now_crit)) != cdb_sc_normal)
+ {
+ csa->now_crit = FALSE;
+ crit_count = 0;
+ if (status == cdb_sc_critreset)
+ rts_error(ERR_CRITRESET, 2, REG_LEN_STR(reg));
+ else
+ {
+ assert(status == cdb_sc_dbccerr);
+ rts_error(ERR_DBCCERR, 2, REG_LEN_STR(reg));
+ }
+ return;
+ }
+ crit_count = 0;
+ }
+ /* Now that crit for THIS region is released, check if deferred signal/exit handling can be done and if so do it */
+ DEFERRED_EXIT_HANDLING_CHECK;
+}
diff --git a/sr_vvms/rel_lock.c b/sr_vvms/rel_lock.c
new file mode 100644
index 0000000..cbaaa2d
--- /dev/null
+++ b/sr_vvms/rel_lock.c
@@ -0,0 +1,63 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2008 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <signal.h> /* for VSIG_ATOMIC_T type */
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "have_crit.h"
+
+error_def(ERR_CRITRESET);
+error_def(ERR_DBCCERR);
+
+GBLREF volatile int4 crit_count;
+GBLREF uint4 process_id;
+
+void rel_lock(gd_region *reg)
+{
+ enum cdb_sc status;
+ sgmnt_addrs *csa;
+
+ csa = &FILE_INFO(reg)->s_addrs;
+
+ if (csa->now_crit)
+ {
+ assert(0 == crit_count);
+ crit_count++;
+ assert(csa->nl->in_crit == process_id || csa->nl->in_crit == 0); /* crit was held by this process */
+ CRIT_TRACE(crit_ops_rw); /* see gdsbt.h for comment on placement */
+
+ csa->nl->in_crit = 0;
+
+ if ((status = mutex_unlockw(csa->critical, 0, &csa->now_crit)) != cdb_sc_normal)
+ {
+ csa->now_crit = FALSE;
+ crit_count = 0;
+ if (status == cdb_sc_critreset)
+ rts_error(ERR_CRITRESET, 2, REG_LEN_STR(reg));
+ else
+ {
+ assert(status == cdb_sc_dbccerr);
+ rts_error(ERR_DBCCERR, 2, REG_LEN_STR(reg));
+ }
+ return;
+ }
+ crit_count = 0;
+ }
+ /* Now that crit for THIS region is released, check if deferred signal/exit handling can be done and if so do it */
+ DEFERRED_EXIT_HANDLING_CHECK;
+}
diff --git a/sr_vvms/rel_quant.c b/sr_vvms/rel_quant.c
new file mode 100644
index 0000000..f7356f6
--- /dev/null
+++ b/sr_vvms/rel_quant.c
@@ -0,0 +1,51 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2005 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <ssdef.h>
+
+#include "efn.h"
+#include "rel_quant.h"
+
+#define TINY_WAIT (-5000)
+
+static void rel_quant_ast(void)
+{ /* Only purpose of this function is to provide a unique identifier for hiber_start timr driven while in an AST */
+ return;
+}
+
+void rel_quant(void)
+{
+ int4 pause[2];
+ int status_timr, status_wait, ast_in_prog;
+ int4 event_flag;
+ gtm_int64_t reqidt;
+
+ pause[0] = TINY_WAIT;
+ pause[1] = -1;
+ if (0 != (ast_in_prog = lib$ast_in_prog()))
+ {
+ reqidt = (gtm_int64_t)rel_quant_ast;
+ event_flag = efn_timer_ast;
+ } else
+ {
+ reqidt = (gtm_int64_t)rel_quant;
+ event_flag = efn_immed_wait;
+ }
+ status_timr = sys$setimr(event_flag, &pause, 0, reqidt, 0);
+ assert(SS$_NORMAL == status_timr);
+ if (SS$_NORMAL == status_timr)
+ {
+ status_wait = sys$waitfr(event_flag);
+ assert(SS$_NORMAL == status_wait);
+ }
+}
diff --git a/sr_vvms/relqueopi.mar b/sr_vvms/relqueopi.mar
new file mode 100644
index 0000000..5d9e5e4
--- /dev/null
+++ b/sr_vvms/relqueopi.mar
@@ -0,0 +1,195 @@
+ .title relqueopi C-callable relative queue interlocked routines
+
+; These routines perform interlocked operations on doubly-linked
+; relative queues. They are designed to emulate the VAX machine
+; instructions (and corresponding VAX C library routines) after
+; which they are named.
+;
+; insqhi - insert entry into queue at head, interlocked
+; insqti - insert entry into queue at tail, interlocked
+; remqhi - remove entry from queue at head, interlocked
+; remqti - remove entry from queue at tail, interlocked
+
+
+QI_STARVATION = 1000 ; for (lcnt = 0; lcnt < QI_STARVATION; lcnt++) wcs_sleep(lcnt) implies 1.5 minute wait
+QI_RETRY = 128 ; times to retry in a spin loop before going to sleep
+
+; the code below should use wcs_backoff() instead of wcs_sleep() to give a random component for the wait
+; at the same time ensuring we wait for a minimum period of time (say 1 minute). note that if we use wcs_backoff()
+; it is possible (though statistically improbable) that we end up waiting for less than a second even with a loopcnt of 1000.
+
+ code_psect
+
+
+; vax_insqhi - insert entry into self-relative queue at head, interlocked
+;
+; calling sequence:
+;
+; typedef struct
+; {
+; long flink,blink;
+; } self_rel_que;
+;
+; self_rel_que *insqhi (queheader)
+; self_rel_que *queheader;
+;
+; return:
+; if 1, success; the entry is the only entry in the queue
+; if 0, success; the entry is not the only entry in the queue
+;
+; if -1, failure; the secondary interlock failed, the instruction may
+; be retried, but should declare a GTMCHECK if the secondary
+; interlock fails repeatedly
+;
+
+
+ .entry vax_insqhi,^m<r2,r3>
+
+ clrl r0
+ movl #QI_STARVATION,r2
+3$: movl #QI_RETRY,r1
+5$: insqhi @4(ap), at 8(ap)
+ bcs 20$
+ bneq 10$
+ incl r0
+10$: ret
+
+20$: sobgtr r1,5$
+ subl3 r2,#QI_STARVATION+1,r3
+ pushl r3
+ calls #1,G^wcs_sleep
+ clrl r0 ; we rely on r0 in the 5$: loop so reset it in case wcs_sleep trashed it
+ sobgtr r2,3$
+ decl r0
+ ret
+
+
+; vax_insqti - insert entry into self-relative queue at tail, interlocked
+;
+; calling sequence:
+;
+; typedef struct
+; {
+; long flink,blink;
+; } self_rel_que;
+;
+; self_rel_que *insqti (queheader)
+; self_rel_que *queheader;
+;
+; return:
+; if 1, success; the entry is the only entry in the queue
+; if 0, sucesss; the entry is not the only entry in the queue
+;
+; if -1, failure; the secondary interlock failed, the instruction may
+; be retried, but should declare a GTMCHECK if the secondary
+; interlock fails repeatedly
+;
+
+ .entry vax_insqti,^m<r2,r3>
+
+ clrl r0
+ movl #QI_STARVATION,r2
+3$: movl #QI_RETRY,r1
+5$: insqti @4(ap), at 8(ap)
+ bcs 20$
+ bneq 10$
+ incl r0
+10$: ret
+
+20$: sobgtr r1,5$
+ subl3 r2,#QI_STARVATION+1,r3
+ pushl r3
+ calls #1,G^wcs_sleep
+ clrl r0 ; we rely on r0 in the 5$: loop so reset it in case wcs_sleep trashed it
+ sobgtr r2,3$
+ decl r0
+ ret
+
+
+; vax_remqhi - remove entry from self-relative queue at head, interlocked
+;
+; calling sequence:
+;
+; typedef struct
+; {
+; long flink,blink;
+; } self_rel_que;
+;
+; self_rel_que *remqhi (queheader)
+; self_rel_que *queheader;
+;
+; return:
+; if non-zero, success; a pointer to the queue entry which was removed
+;
+; if zero, then the queue was empty (operation succeeded, but nothing
+; was in the queue to remove)
+;
+; if -1, failure; the secondary interlock failed, the instruction may
+; be retried, but should declare a GTMCHECK if the secondary
+; interlock fails repeatedly
+;
+
+
+ .entry vax_remqhi,^m<r2,r3>
+
+ movl #QI_STARVATION,r2
+3$: movl #QI_RETRY,r1
+5$: remqhi @4(ap),r0
+ bcs 20$
+ bvc 10$
+ clrl r0
+10$: ret
+
+20$: sobgtr r1,5$
+ subl3 r2,#QI_STARVATION+1,r3
+ pushl r3
+ calls #1,G^wcs_sleep
+ sobgtr r2,3$
+ mnegl #1,r0
+ ret
+
+
+; vax_remqti - remove entry from self-relative queue at tail, interlocked
+;
+; calling sequence:
+;
+; typedef struct
+; {
+; long flink,blink;
+; } self_rel_que;
+;
+; self_rel_que *remqti (queheader)
+; self_rel_que *queheader;
+;
+; return:
+; if non-zero, success; a pointer to the queue entry which was removed
+;
+; if zero, then the queue was empty (operation succeeded, but nothing
+; was in the queue to remove)
+;
+; if -1, failure; the secondary interlock failed, the instruction may
+; be retried, but should declare a GTMCHECK if the secondary
+; interlock fails repeatedly
+;
+
+
+ .entry vax_remqti,^m<r2,r3>
+
+ movl #QI_STARVATION,r2
+3$: movl #QI_RETRY,r1
+5$: remqti @4(ap),r0
+ bcs 20$
+ bvc 10$
+ clrl r0
+10$: ret
+
+20$: sobgtr r1,5$
+ subl3 r2,#QI_STARVATION+1,r3
+ pushl r3
+ calls #1,G^wcs_sleep
+ sobgtr r2,3$
+ mnegl #1,r0
+ ret
+
+ .end
+
diff --git a/sr_vvms/remove_rms.c b/sr_vvms/remove_rms.c
new file mode 100644
index 0000000..441d846
--- /dev/null
+++ b/sr_vvms/remove_rms.c
@@ -0,0 +1,48 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <fab.h>
+#include <rab.h>
+#include <nam.h>
+#include "io.h"
+#include "iormdef.h"
+
+GBLREF io_log_name *io_root_log_name;
+
+void remove_rms ( io_desc *ciod)
+{
+ io_log_name **lpp, *lp; /* logical name pointers */
+ d_rm_struct *rm_ptr;
+
+ assert (ciod->type == rm);
+ assert (ciod->state == dev_closed || ciod->state == dev_never_opened);
+ rm_ptr = (d_rm_struct *) ciod->dev_sp;
+ for (lpp = &io_root_log_name, lp = *lpp; lp; lp = *lpp)
+ {
+ if (lp->iod->pair.in == ciod)
+ {
+ assert (lp->iod == ciod);
+ *lpp = (*lpp)->next;
+ free (lp);
+ }
+ else
+ lpp = &lp->next;
+ }
+ assert (rm_ptr->inbuf);
+ assert (rm_ptr->outbuf_start);
+ if (rm_ptr->f.fab$l_nam)
+ free(rm_ptr->f.fab$l_nam);
+ free (rm_ptr->outbuf_start);
+ free (rm_ptr->inbuf);
+ free (rm_ptr);
+ free (ciod);
+}
diff --git a/sr_vvms/repl_create_server.c b/sr_vvms/repl_create_server.c
new file mode 100644
index 0000000..2b8d9c7
--- /dev/null
+++ b/sr_vvms/repl_create_server.c
@@ -0,0 +1,301 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <ssdef.h>
+#include <prtdef.h>
+#include <prcdef.h>
+#include <secdef.h>
+#include <psldef.h>
+#include <descrip.h>
+#include <iodef.h>
+#include <prvdef.h>
+#include <lnmdef.h>
+#include <rms.h>
+#include <efndef.h>
+
+#include "gtm_string.h"
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_logicals.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "iosp.h"
+#include "vmsdtype.h"
+#include "repl_shutdcode.h"
+#include "repl_sp.h"
+#include "cli.h"
+#include "io.h"
+#include "job.h"
+#include "gtmmsg.h"
+#include "trans_log_name.h"
+
+#define MAX_MSG 1024
+#define MAX_TRIES 50
+#define MAX_PATH_LEN 255
+#define MAX_MBX_NAME_LEN 255
+#define SHORT_WAIT 10
+#define TRY(X) if (SS$_NORMAL != (status = X)) { sys$dassgn(*cmd_channel); return status; }
+
+int4 repl_mbx_wr(uint4 channel, sm_uc_ptr_t msg, int len, uint4 err_code)
+{
+ int4 status;
+ unsigned short mbsb[4];
+
+ error_def(ERR_TEXT);
+
+ /* Qio's should be used with care, We should use qiow or wait properly to ensure that
+ qio finished properly ( any arguments must not be on the stack before returning
+ from the routine which issues qio) checking the iosb status block. */
+
+ status = sys$qiow(EFN$C_ENF, channel, IO$_WRITEVBLK | IO$M_NOW, &mbsb[0], 0, 0, msg, len, 0, 0, 0, 0);
+ if (SS$_NORMAL != status)
+ {
+ gtm_putmsg(VARLSTCNT(11) err_code, 0,
+ ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to write to send-cmd mailbox the message, "),
+ ERR_TEXT, 2, len, msg, status);
+ }
+ return status;
+}
+
+int4 repl_trnlnm(struct dsc$descriptor_s *d_tbl_srch_list, struct dsc$descriptor_s *d_logical,
+ struct dsc$descriptor_s *d_expanded, struct dsc$descriptor_s *d_foundin_tbl)
+{
+ struct
+ {
+ item_list_3 le[2];
+ int4 terminator;
+ } item_list;
+ uint4 attr = LNM$M_CASE_BLIND;
+
+ item_list.le[0].buffer_length = LEN_OF_DSC(*d_expanded);
+ item_list.le[0].item_code = LNM$_STRING;
+ item_list.le[0].buffer_address = STR_OF_DSC(*d_expanded);
+ item_list.le[0].return_length_address = &(LEN_OF_DSC(*d_expanded));
+ item_list.le[1].buffer_length = LEN_OF_DSC(*d_foundin_tbl);
+ item_list.le[1].item_code = LNM$_TABLE;
+ item_list.le[1].buffer_address = STR_OF_DSC(*d_foundin_tbl);
+ item_list.le[1].return_length_address = &(LEN_OF_DSC(*d_foundin_tbl));
+ item_list.terminator = 0;
+ return (sys$trnlnm(&attr, d_tbl_srch_list, d_logical, 0, &item_list));
+}
+
+int4 get_mbx_devname(struct dsc$descriptor_s *d_cmd_mbox, struct dsc$descriptor_s *d_cmd_dev)
+{
+ $DESCRIPTOR (d_lnmtab, "LNM$TEMPORARY_MAILBOX");
+ struct
+ {
+ item_list_3 le[1];
+ int4 terminator;
+ } item_list;
+
+ item_list.le[0].buffer_length = d_cmd_dev->dsc$w_length;
+ item_list.le[0].item_code = LNM$_STRING;
+ item_list.le[0].buffer_address = d_cmd_dev->dsc$a_pointer;
+ item_list.le[0].return_length_address = &(d_cmd_dev->dsc$w_length);
+ item_list.terminator = 0;
+ return (sys$trnlnm(0, &d_lnmtab, d_cmd_mbox, 0, &item_list));
+}
+
+int4 repl_create_server(struct dsc$descriptor_s *d_cmd, char *mbx_prefix, char *mbx_suffix, uint4 *cmd_channel, uint4 *server_pid,
+ uint4 err_code)
+{
+ int cnt, i;
+ int4 status;
+ char gbldir_path[MAX_PATH_LEN], gbldir_tbl[MAX_PATH_LEN], secshr_path[MAX_PATH_LEN], secshr_tbl[MAX_PATH_LEN];
+ char cmdmbox_devname[MAX_PATH_LEN], def_dir[MAX_PATH_LEN];
+ char creprc_log[MAX_PATH_LEN], creprc_log_exp[MAX_PATH_LEN];
+ char startup_cmd[MAX_PATH_LEN+1];
+ char cmdmbx_name[MAX_MBX_NAME_LEN + 1], trans_buff[MAX_FN_LEN];
+ char proc_name[PROC_NAME_MAXLEN + 1];
+ mstr image, log_nam, trans_log_nam;
+ unsigned short length;
+ gds_file_id file_id;
+
+ static char startup_file[MAX_PATH_LEN];
+ static boolean_t first_time = TRUE;
+
+ $DESCRIPTOR(d_null_str, "");
+ $DESCRIPTOR(d_loginout_image,"SYS$SYSTEM:LOGINOUT.EXE");
+ $DESCRIPTOR(d_null_dev, "NL:");
+ $DESCRIPTOR(d_secshr_logical, "GTMSECSHR");
+ $DESCRIPTOR(d_gbldir_logical, "GTM$GBLDIR");
+ $DESCRIPTOR(d_tbl_srch_list, "LNM$FILE_DEV");
+ $DESCRIPTOR(d_startup_qualifier, "STARTUP_FILE");
+ $DESCRIPTOR(d_cmd_dev, cmdmbox_devname);
+ $DESCRIPTOR(d_out_dev, creprc_log);
+ $DESCRIPTOR(d_out_dev_exp, creprc_log_exp);
+ $DESCRIPTOR(d_def_dir, def_dir);
+ $DESCRIPTOR(d_secshr, secshr_path);
+ $DESCRIPTOR(d_gbldir, gbldir_path);
+ $DESCRIPTOR(d_secshr_tbl, secshr_tbl);
+ $DESCRIPTOR(d_gbldir_tbl, gbldir_tbl);
+ $DESCRIPTOR(d_cmd_mbox, cmdmbx_name);
+ $DESCRIPTOR(d_proc_name, proc_name);
+ $DESCRIPTOR(d_startup_file, startup_file);
+ $DESCRIPTOR(d_startup_cmd, startup_cmd);
+
+ error_def(ERR_TEXT);
+ error_def(ERR_MULOGNAMEDEF);
+ error_def(ERR_MUNOACTION);
+
+ /* Generate a unique name for the cmd_mbx using global_name(gbldir) and mbx_prefix*/
+ log_nam.addr = GTM_GBLDIR;
+ log_nam.len = SIZEOF(GTM_GBLDIR) - 1;
+ if (SS_NORMAL != (status = trans_log_name(&log_nam, &trans_log_nam, trans_buff)))
+ {
+ gtm_putmsg(VARLSTCNT(6) err_code, 0, ERR_TEXT, 2, RTS_ERROR_LITERAL("gtm$gbldir not defined"));
+ return status;
+ }
+ set_gdid_from_file((gd_id_ptr_t)&file_id, trans_buff, trans_log_nam.len);
+ global_name(mbx_prefix, &file_id, cmdmbx_name);
+ STR_OF_DSC(d_cmd_mbox)++;
+ LEN_OF_DSC(d_cmd_mbox) = cmdmbx_name[0]; /* global_name() returns the length in the first byte */
+ assert(SIZEOF(cmdmbx_name) > LEN_OF_DSC(d_cmd_mbox) + strlen(mbx_suffix));
+ DSC_APND_STR(d_cmd_mbox, mbx_suffix);
+ /* Prepare for the startup commands */
+ if (RMS$_NORMAL != (status = parse_filename(&d_null_str, &d_def_dir, 0)))
+ {
+ gtm_putmsg(VARLSTCNT(7) err_code, 0,
+ ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to get value of default directory"), status);
+ return status;
+ }
+ DSC_CPY(d_out_dev, d_def_dir);
+ DSC_APND_LIT(d_out_dev, "loginout_");
+ STR_OF_DSC(d_out_dev)[LEN_OF_DSC(d_out_dev)++] = STR_OF_DSC(d_cmd_mbox)[3];
+ DSC_APND_LIT(d_out_dev, ".log");
+ if ('\0' != mbx_suffix[0])
+ {
+ DSC_APND_LIT(d_out_dev, "_");
+ DSC_APND_STR(d_out_dev, mbx_suffix);
+ }
+ if (RMS$_NORMAL != (status = parse_filename(&d_out_dev, &d_out_dev_exp, 1)))
+ {
+ gtm_putmsg(VARLSTCNT(7) err_code, 0,
+ ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to expand creprc_logfile"), status);
+ return status;
+ }
+ /* Create a mailbox to send commands to the detached 'loginout' process to start the server */
+ /* Before creating the mailbox, check to see that the mail box's logical is not already defined.
+ * This is to take care of the cases where the previous incarnation of the server is just in the
+ * shutdown logic and the current server (which is just being brought up) gets to read from that
+ * server's mailbox (which contains just an 'exit' command). So, the current server fails to come up.
+ * As a side affect, this message also appears when a server is attempted to be started while
+ * another is already running from the same terminal.
+ */
+ if (SS$_NORMAL == get_mbx_devname(&d_cmd_mbox, &d_cmd_dev))
+ {
+ gtm_putmsg(VARLSTCNT(6) err_code, 0, ERR_MULOGNAMEDEF, 2, LEN_STR_OF_DSC(d_cmd_mbox));
+ return ERR_MUNOACTION;
+ }
+ status = sys$crembx(0, cmd_channel, MAX_MSG, MAX_MSG, 0, PSL$C_USER, &d_cmd_mbox);
+ if (SS$_NORMAL != status)
+ {
+ gtm_putmsg(VARLSTCNT(7) err_code, 0,
+ ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to create send-command mailbox"), status);
+ return status;
+ }
+ /* Get the name of the send-command mailbox, which is needed for creprc() */
+ for (cnt = 0; SS$_NORMAL != (status = get_mbx_devname(&d_cmd_mbox, &d_cmd_dev)) && (MAX_TRIES > cnt); cnt++)
+ {
+ SHORT_SLEEP(SHORT_WAIT);
+ }
+ if (SS$_NORMAL != status)
+ {
+ gtm_putmsg(VARLSTCNT(7) err_code, 0,
+ ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to get dev-name of send-command mailbox"), status);
+ sys$dassgn(*cmd_channel);
+ return status;
+ }
+ /* Construct process name */
+ LEN_OF_DSC(d_proc_name) = (int) get_proc_name(STR_AND_LEN(mbx_prefix), getpid(), proc_name);
+ /* Create the server as a detached process */
+ status = sys$creprc( server_pid, /* process id */
+ &d_loginout_image, /* image */
+ &d_cmd_dev, /* input SYS$INPUT device */
+ &d_out_dev_exp, /* output SYS$OUTPUT device*/
+ &d_out_dev_exp, /* error SYS$ERROR device*/
+ 0, 0,
+ &d_proc_name, /* process name */
+ 0, 0, 0, PRC$M_DETACH | PRC$M_IMGDMP);
+ if (SS$_NORMAL != status)
+ {
+ gtm_putmsg(VARLSTCNT(7) err_code, 0,
+ ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to create detached server"), status);
+ sys$dassgn(*cmd_channel);
+ return status;
+ }
+ ojdefimage(&image);
+ if (SS$_NORMAL != (status = repl_trnlnm(&d_tbl_srch_list, &d_secshr_logical, &d_secshr, &d_secshr_tbl)))
+ {
+ gtm_putmsg(VARLSTCNT(7) err_code, 0,
+ ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to translate GTMSECSHR logical"), status);
+ sys$dassgn(*cmd_channel);
+ return status;
+ }
+ if (SS$_NORMAL != (status = repl_trnlnm(&d_tbl_srch_list, &d_gbldir_logical, &d_gbldir, &d_gbldir_tbl)))
+ {
+ gtm_putmsg(VARLSTCNT(7) err_code, 0,
+ ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to translate GTM$GBLDIR logical"), status);
+ sys$dassgn(*cmd_channel);
+ return status;
+ }
+ if (CLI_PRESENT == cli_present("STARTUP_FILE"))
+ {
+ if (first_time && SS$_NORMAL != (status = cli$get_value(&d_startup_qualifier, &d_startup_file, &length)))
+ {
+ gtm_putmsg(VARLSTCNT(7) err_code, 0,
+ ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to get value of /STARTUP_FILE qualifier"), status);
+ sys$dassgn(*cmd_channel);
+ return status;
+ }
+ first_time = FALSE;
+ STR_OF_DSC(d_startup_cmd)[0] = '@';
+ LEN_OF_DSC(d_startup_cmd) = 1;
+ DSC_APND_DSC(d_startup_cmd, d_startup_file);
+ TRY(repl_mbx_wr(*cmd_channel, STR_LEN_OF_DSC(d_startup_cmd), err_code));
+ }
+ /* Write the mupip command (constructed earlier) to start the server into the send-command mailbox */
+ TRY(repl_mbx_wr(*cmd_channel, LIT_AND_LEN("set default -"), err_code));
+ TRY(repl_mbx_wr(*cmd_channel, STR_LEN_OF_DSC(d_def_dir), err_code));
+ if ((0 != memcmp(STR_OF_DSC(d_secshr_tbl), LIT_AND_LEN("LNM$GROUP"))) &&
+ (0 != memcmp(STR_OF_DSC(d_secshr_tbl), LIT_AND_LEN("LNM$SYSTEM_TABLE"))))
+ {
+ if (0 == memcmp(STR_OF_DSC(d_secshr_tbl), LIT_AND_LEN("LNM$JOB"))) /* chop the job specific suffix */
+ LEN_OF_DSC(d_secshr_tbl) = SIZEOF("LNM$JOB") - 1;
+ TRY(repl_mbx_wr(*cmd_channel, LIT_AND_LEN("define gtmsecshr /table= -"), err_code));
+ STR_OF_DSC(d_secshr_tbl)[LEN_OF_DSC(d_secshr_tbl)] = ' ';
+ STR_OF_DSC(d_secshr_tbl)[LEN_OF_DSC(d_secshr_tbl) +1 ] = '-';
+ LEN_OF_DSC(d_secshr_tbl) += 2;
+ TRY(repl_mbx_wr(*cmd_channel, STR_LEN_OF_DSC(d_secshr_tbl), err_code));
+ TRY(repl_mbx_wr(*cmd_channel, STR_LEN_OF_DSC(d_secshr), err_code));
+ }
+ if ((0 != memcmp(STR_OF_DSC(d_gbldir_tbl), LIT_AND_LEN("LNM$GROUP"))) &&
+ (0 != memcmp(STR_OF_DSC(d_gbldir_tbl), LIT_AND_LEN("LNM$SYSTEM_TABLE"))))
+ {
+ if (0 == memcmp(STR_OF_DSC(d_gbldir_tbl), LIT_AND_LEN("LNM$JOB"))) /* chop the job specific suffix */
+ LEN_OF_DSC(d_gbldir_tbl) = SIZEOF("LNM$JOB") - 1;
+ TRY(repl_mbx_wr(*cmd_channel, LIT_AND_LEN("define gtm$gbldir /table= -"), err_code));
+ STR_OF_DSC(d_gbldir_tbl)[LEN_OF_DSC(d_gbldir_tbl)] = ' ';
+ STR_OF_DSC(d_gbldir_tbl)[LEN_OF_DSC(d_gbldir_tbl) +1 ] = '-';
+ LEN_OF_DSC(d_gbldir_tbl) += 2;
+ TRY(repl_mbx_wr(*cmd_channel, STR_LEN_OF_DSC(d_gbldir_tbl), err_code));
+ TRY(repl_mbx_wr(*cmd_channel, STR_LEN_OF_DSC(d_gbldir), err_code));
+ }
+ TRY(repl_mbx_wr(*cmd_channel, LIT_AND_LEN("run -"), err_code));
+ TRY(repl_mbx_wr(*cmd_channel, image.addr, image.len, err_code));
+ TRY(repl_mbx_wr(*cmd_channel, STR_LEN_OF_DSC(*d_cmd), err_code));
+ TRY(repl_mbx_wr(*cmd_channel, LIT_AND_LEN("exit"), err_code));
+ return status;
+}
diff --git a/sr_vvms/repl_fork_rcvr_server.c b/sr_vvms/repl_fork_rcvr_server.c
new file mode 100644
index 0000000..5ed08bc
--- /dev/null
+++ b/sr_vvms/repl_fork_rcvr_server.c
@@ -0,0 +1,107 @@
+/****************************************************************
+ * *
+ * Copyright 2005, 2009 Fidelity Information Services, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gtm_string.h"
+#include <ssdef.h>
+#include <descrip.h>
+
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "repl_sp.h"
+#include "gdsfhead.h"
+#include "gtmrecv.h"
+#include "cli.h"
+
+error_def(ERR_JNLPOOLSETUP);
+error_def(ERR_RECVPOOLSETUP);
+
+
+GBLREF gtmrecv_options_t gtmrecv_options;
+
+int repl_fork_rcvr_server(uint4 *pid, uint4 *cmd_channel)
+{
+ int status, retval=0;
+ char cmd_str[MAX_COMMAND_LINE_LENGTH];
+ uint4 flags, channel;
+ unsigned short cmd_len, mbsb[4];
+ uint4 buff, server_pid, clus_flags_stat;
+ mstr log_nam, trans_log_nam;
+ gds_file_id file_id;
+ unsigned short log_file_len;
+ int exp_log_file_name_len, len;
+ char *ptr, qwstring[100];
+
+ $DESCRIPTOR(cmd_desc, cmd_str);
+
+ /* Get the cmd line */
+ if (((status = lib$get_foreign(&cmd_desc, 0, &cmd_len)) & 1) == 0)
+ return status;
+ if (0 == cmd_len)
+ { /* Command issued on the MUPIP command line, we have to build the argument string to pass to child */
+ MEMCPY_LIT(&cmd_str[cmd_len], RECV_PROMPT_START_QUAL);
+ cmd_len += SIZEOF(RECV_PROMPT_START_QUAL) - 1;
+ if (CLI_PRESENT == cli_present("BUFFSIZE"))
+ {
+ MEMCPY_LIT(&cmd_str[cmd_len], BUFF_QUAL);
+ cmd_len += SIZEOF(BUFF_QUAL) - 1;
+ ptr = i2asc(qwstring, gtmrecv_options.buffsize);
+ memcpy(&cmd_str[cmd_len], qwstring, ptr - qwstring);
+ cmd_len += ptr - qwstring;
+ }
+ if (CLI_PRESENT == cli_present("FILTER"))
+ {
+ MEMCPY_LIT(&cmd_str[cmd_len], FILTER_QUAL);
+ cmd_len += SIZEOF(FILTER_QUAL) - 1;
+ len = strlen(gtmrecv_options.filter_cmd);
+ memcpy(&cmd_str[cmd_len], gtmrecv_options.filter_cmd, len);
+ cmd_len += len;
+ }
+ if (CLI_PRESENT == cli_present("LOG"))
+ {
+ MEMCPY_LIT(&cmd_str[cmd_len], LOG_QUAL);
+ cmd_len += SIZEOF(LOG_QUAL) - 1;
+ len = strlen(gtmrecv_options.log_file);
+ memcpy(&cmd_str[cmd_len], gtmrecv_options.log_file, len);
+ cmd_len += len;
+ }
+ if (CLI_PRESENT == cli_present("LOG_INTERVAL"))
+ {
+ MEMCPY_LIT(&cmd_str[cmd_len], LOGINTERVAL_QUAL);
+ cmd_len += SIZEOF(LOGINTERVAL_QUAL) - 1;
+ cmd_str[cmd_len++] = '"'; /* begin quote */
+ ptr = i2asc(qwstring, gtmrecv_options.rcvr_log_interval);
+ memcpy(&cmd_str[cmd_len], qwstring, ptr - qwstring);
+ cmd_len += ptr - qwstring;
+ cmd_str[cmd_len++] = ','; /* delimiter */
+ ptr = i2asc(qwstring, gtmrecv_options.upd_log_interval);
+ memcpy(&cmd_str[cmd_len], qwstring, ptr - qwstring);
+ cmd_len += ptr - qwstring;
+ cmd_str[cmd_len++] = '"'; /* end quote */
+ }
+ if (CLI_PRESENT == cli_present("LISTENPORT"))
+ {
+ MEMCPY_LIT(&cmd_str[cmd_len], LISTENPORT_QUAL);
+ cmd_len += SIZEOF(LISTENPORT_QUAL) - 1;
+ ptr = i2asc(qwstring, gtmrecv_options.listen_port);
+ memcpy(&cmd_str[cmd_len], qwstring, ptr - qwstring);
+ cmd_len += ptr - qwstring;
+ }
+ }
+
+ /* Append a dummy qualifier */
+ MEMCPY_LIT(&cmd_str[cmd_len], DUMMY_START_QUAL);
+ cmd_desc.dsc$w_length = cmd_len + SIZEOF(DUMMY_START_QUAL) - 1;
+ /* Create detached server and write startup commands to it */
+ return repl_create_server(&cmd_desc, "GTMR", "", cmd_channel, pid, ERR_RECVPOOLSETUP);
+}
diff --git a/sr_vvms/repl_ipc_cleanup.c b/sr_vvms/repl_ipc_cleanup.c
new file mode 100644
index 0000000..be03508
--- /dev/null
+++ b/sr_vvms/repl_ipc_cleanup.c
@@ -0,0 +1,184 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_inet.h" /* Required for gtmsource.h */
+
+#include <ssdef.h>
+#include <secdef.h>
+#include <psldef.h>
+#include <descrip.h>
+
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "repl_msg.h"
+#include "gtmsource.h"
+#include "gtmrecv.h"
+#include "repl_dbg.h"
+#include "gtm_stdio.h"
+#include "repl_shutdcode.h"
+#include "repl_sem.h"
+#include "repl_shm.h"
+#include "repl_log.h"
+
+GBLREF jnlpool_addrs jnlpool;
+GBLREF boolean_t pool_init;
+GBLREF jnlpool_ctl_ptr_t jnlpool_ctl;
+GBLREF int4 jnlpool_shmid;
+GBLREF recvpool_addrs recvpool;
+GBLREF int recvpool_shmid;
+GBLREF int gtmsource_srv_count;
+GBLREF int gtmrecv_srv_count;
+
+int gtmsource_ipc_cleanup(boolean_t auto_shutdown, int *exit_status)
+{
+ int status, detach_status, remove_status;
+ boolean_t attempt_ipc_cleanup;
+ int4 shm_lockid;
+
+ attempt_ipc_cleanup = TRUE; /* attempt cleaning up the IPCs */
+ /* Wait for the Source Server to detach and takeover the semaphore */
+ if (!auto_shutdown && 0 > grab_sem(SOURCE, SRC_SERV_COUNT_SEM))
+ {
+ repl_log(stderr, FALSE, TRUE, "Error taking control of source server count semaphore : %s. Shutdown not complete\n",
+ REPL_SEM_ERROR);
+ *exit_status = ABNORMAL_SHUTDOWN;
+ attempt_ipc_cleanup = FALSE;
+ }
+ /* Now we have locked out all users from the journal pool and no process can initiate any other action.
+ * Save the lock-id in a local variable because the structure holding it ("jnlpool") is memset to 0 below */
+ shm_lockid = jnlpool.shm_lockid;
+ if (SS$_NORMAL != (status = lastuser_of_gsec(shm_lockid)))
+ {
+ repl_log(stderr, FALSE, TRUE,
+ "Not deleting jnlpool global section as other processes are still attached to it : %s\n",
+ REPL_STR_ERROR);
+ attempt_ipc_cleanup = FALSE;
+ *exit_status = ABNORMAL_SHUTDOWN;
+ }
+ if (attempt_ipc_cleanup)
+ {
+ if ((0 < jnlpool_shmid) && (auto_shutdown || SS$_NORMAL == (detach_status = detach_shm(jnlpool.shm_range)))
+ && SS$_NORMAL == (remove_status = delete_shm(&jnlpool.vms_jnlpool_key.desc)))
+ {
+ memset((uchar_ptr_t)&jnlpool, 0, SIZEOF(jnlpool)); /* For gtmsource_exit */
+ jnlpool.jnlpool_ctl = NULL;
+ jnlpool_ctl = NULL;
+ jnlpool_shmid = 0;
+ pool_init = FALSE;
+ repl_log(stdout, FALSE, FALSE, "Journal pool shared memory removed\n");
+ if (0 == remove_sem_set(SOURCE))
+ repl_log(stdout, FALSE, TRUE, "Journal pool semaphore removed\n");
+ else
+ {
+ repl_log(stderr, FALSE, TRUE, "Error removing jnlpool semaphore : %s\n", REPL_SEM_ERROR);
+ *exit_status = ABNORMAL_SHUTDOWN;
+ }
+ } else if (0 < jnlpool_shmid)
+ {
+ if (!auto_shutdown && SS$_NORMAL != detach_status)
+ repl_log(stderr, TRUE, TRUE, "Error detaching from jnlpool : %s\n", REPL_STR_ERROR1(detach_status));
+ else if (SS$_NORMAL != remove_status)
+ {
+ if (!auto_shutdown)
+ {
+ jnlpool.jnlpool_ctl = NULL; /* Detached successfully */
+ jnlpool_ctl = NULL;
+ pool_init = FALSE;
+ }
+ repl_log(stderr, FALSE, TRUE, "Error removing jnlpool shared memory : %s\n",
+ REPL_STR_ERROR1(remove_status));
+ }
+ *exit_status = ABNORMAL_SHUTDOWN;
+ }
+ if (SS$_NORMAL != (status = signoff_from_gsec(shm_lockid)))
+ repl_log(stderr, TRUE, TRUE, "Error dequeueing lock on jnlpool global section : %s\n", REPL_STR_ERROR);
+ }
+ return attempt_ipc_cleanup;
+}
+
+int gtmrecv_ipc_cleanup(boolean_t auto_shutdown, int *exit_status)
+{
+ int status, detach_status, remove_status;
+ boolean_t attempt_ipc_cleanup;
+ int4 shm_lockid;
+
+ attempt_ipc_cleanup = TRUE; /* attempt cleaning up the IPCs */
+ /* Wait for the Receiver Server and Update Process to detach and takeover the semaphores.
+ * Note that the Receiver Server has already waited for the Update Process to detach.
+ * It is done here as a precaution against Receiver Server crashes.
+ */
+ if (!auto_shutdown)
+ status = grab_sem(RECV, RECV_SERV_COUNT_SEM);
+ else
+ status = 0;
+ if (0 == status && 0 > (status = grab_sem(RECV, UPD_PROC_COUNT_SEM)))
+ rel_sem(RECV, RECV_SERV_COUNT_SEM);
+ if (status < 0)
+ {
+ repl_log(stderr, FALSE, TRUE,
+ "Error taking control of Receiver Server/Update Process count semaphore : "
+ "%s. Shutdown not complete\n", REPL_SEM_ERROR);
+ *exit_status = ABNORMAL_SHUTDOWN;
+ attempt_ipc_cleanup = FALSE;
+ }
+ /* Now we have locked out all users from the receive pool and no process can initiate any other action.
+ * Save the lock-id in a local variable because the structure holding it ("jnlpool") is memset to 0 below */
+ shm_lockid = recvpool.shm_lockid;
+ if ((!auto_shutdown || gtmrecv_srv_count) && SS$_NORMAL != (status = lastuser_of_gsec(shm_lockid)))
+ {
+ repl_log(stderr, FALSE, TRUE,
+ "Not deleting recvpool global section as other processes are still attached to it : "
+ "%s\n", REPL_STR_ERROR);
+ attempt_ipc_cleanup = FALSE;
+ *exit_status = ABNORMAL_SHUTDOWN;
+ }
+ if (attempt_ipc_cleanup)
+ {
+ if ((0 < recvpool_shmid) && (auto_shutdown || SS$_NORMAL == (detach_status = detach_shm(recvpool.shm_range)))
+ && SS$_NORMAL == (remove_status = delete_shm(&recvpool.vms_recvpool_key.desc)))
+ {
+ memset((uchar_ptr_t)&recvpool, 0, SIZEOF(recvpool)); /* For gtmrecv_exit */
+ recvpool.recvpool_ctl = NULL;
+ recvpool_shmid = 0;
+ repl_log(stdout, FALSE, FALSE, "Recv pool shared memory removed\n");
+ if (0 == remove_sem_set(RECV))
+ repl_log(stdout, FALSE, TRUE, "Recv pool semaphore removed\n");
+ else
+ {
+ repl_log(stderr, FALSE, TRUE, "Error removing recvpool semaphore : %s\n", REPL_SEM_ERROR);
+ *exit_status = ABNORMAL_SHUTDOWN;
+ }
+ } else if (0 < recvpool_shmid)
+ {
+ if (!auto_shutdown && SS$_NORMAL != detach_status)
+ repl_log(stderr, TRUE, TRUE,
+ "Error detaching from recvpool : %s\n", REPL_STR_ERROR1(detach_status));
+ else if (SS$_NORMAL != remove_status)
+ {
+ if (!auto_shutdown)
+ recvpool.recvpool_ctl = NULL; /* Detached successfully */
+ repl_log(stderr, FALSE, TRUE, "Error removing recvpool shared memory : %s\n",
+ REPL_STR_ERROR1(remove_status));
+ }
+ *exit_status = ABNORMAL_SHUTDOWN;
+ }
+ }
+ if (SS$_NORMAL != (status = signoff_from_gsec(shm_lockid)))
+ repl_log(stderr, TRUE, TRUE, "Error dequeueing lock on recvpool global section : %s\n", REPL_STR_ERROR);
+ return attempt_ipc_cleanup;
+}
diff --git a/sr_vvms/repl_log.c b/sr_vvms/repl_log.c
new file mode 100644
index 0000000..8c97eb7
--- /dev/null
+++ b/sr_vvms/repl_log.c
@@ -0,0 +1,98 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <stdarg.h>
+#include "gtm_string.h"
+#include "gtm_stdlib.h"
+#include "gtm_time.h"
+#include "gtm_stdio.h"
+
+#include "repl_log.h"
+#include "iosp.h"
+#include "util.h"
+
+#define MAX_MSG_LEN 1024
+
+GBLREF int gtmsource_log_fd;
+GBLREF int gtmrecv_log_fd;
+GBLREF int updproc_log_fd;
+
+GBLREF FILE *gtmsource_log_fp;
+GBLREF FILE *gtmrecv_log_fp;
+GBLREF FILE *updproc_log_fp;
+
+/* Note : On VMS 'fp' argument is dummy. Message is always logged to the log file specified by the
+ /LOG qualifier, or to the stdout otherwise */
+
+void map_esc_seq(char *in_msg)
+{
+ char out_msg[MAX_MSG_LEN];
+ char *out_ptr, *in_ptr;
+
+ in_ptr = in_msg;
+ out_ptr = out_msg;
+ while('\0' != *in_ptr)
+ {
+ switch(*in_ptr)
+ {
+ case '\n': *out_ptr++ = '!';
+ *out_ptr++ = '/';
+ break;
+ case '\t': *out_ptr++ = '!';
+ *out_ptr++ = '_';
+ break;
+ case '\f': *out_ptr++ = '!';
+ *out_ptr++ = '^';
+ break;
+ case '!': *out_ptr++ = '!';
+ *out_ptr++ = '!';
+ break;
+ default : *out_ptr++ = *in_ptr;
+ }
+ in_ptr++;
+ }
+ *out_ptr = '\0';
+ strcpy(in_msg, out_msg);
+}
+
+int repl_log(FILE *fp, boolean_t stamptime, boolean_t flush, char *fmt, ...)
+{
+ va_list printargs;
+ now_t now; /* for GET_CUR_TIME macro */
+ char *time_ptr, time_str[CTIME_BEFORE_NL + 2]; /* for GET_CUR_TIME macro */
+ char fmt_str[BUFSIZ];
+ char msg[MAX_MSG_LEN];
+ int msg_len, rc;
+
+ if (stamptime)
+ {
+ GET_CUR_TIME;
+ strcpy(fmt_str, time_ptr);
+ fmt_str[CTIME_BEFORE_NL] = ' '; /* Overwrite \n */
+ fmt_str[CTIME_BEFORE_NL + 1] = ':';
+ fmt_str[CTIME_BEFORE_NL + 2] = ' ';
+ strcpy(fmt_str + CTIME_BEFORE_NL + 3, fmt);
+ fmt = &fmt_str[0];
+ }
+
+ va_start(printargs, fmt);
+ VSPRINTF(msg, fmt, printargs, rc);
+ va_end(printargs);
+ msg_len = strlen(msg);
+ if (flush && '\n' == msg[msg_len - 1])
+ msg[msg_len - 1] = '\0'; /* Since the util_out_print() puts a CR by itself */
+ map_esc_seq(msg);
+ util_out_print(msg, flush);
+
+ return(SS_NORMAL);
+}
diff --git a/sr_vvms/repl_log_init.c b/sr_vvms/repl_log_init.c
new file mode 100644
index 0000000..31bdc58
--- /dev/null
+++ b/sr_vvms/repl_log_init.c
@@ -0,0 +1,23 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "gtm_stdio.h"
+
+GBLDEF int gtmsource_log_fd = FD_INVALID;
+GBLDEF int gtmrecv_log_fd = FD_INVALID;
+GBLDEF int updproc_log_fd = FD_INVALID;
+GBLDEF int updhelper_log_fd = FD_INVALID;
+
+GBLDEF FILE *gtmsource_log_fp = NULL;
+GBLDEF FILE *gtmrecv_log_fp = NULL;
+GBLDEF FILE *updproc_log_fp = NULL;
+GBLDEF FILE *updhelper_log_fp = NULL;
diff --git a/sr_vvms/repl_msg.h b/sr_vvms/repl_msg.h
new file mode 100644
index 0000000..6a85b64
--- /dev/null
+++ b/sr_vvms/repl_msg.h
@@ -0,0 +1,119 @@
+/****************************************************************
+ * *
+ * Copyright 2006, 2011 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef _REPL_MSG_H
+#define _REPL_MSG_H
+
+enum
+{
+ REPL_START_JNL_SEQNO = 0,
+ REPL_TR_JNL_RECS, /* 1 */
+ REPL_ROLLBACK_FIRST, /* 2 */
+ REPL_WILL_RESTART_OBSOLETE, /* 3 */ /* Obsoleted effective V4.4-002 since we no longer support dual site config with
+ * V4.1 versions. But, DO NOT remove this message type to keep other message types
+ * same as in V4.2 and V4.3 versions */
+ REPL_XOFF, /* 4 */
+ REPL_XON, /* 5 */
+ REPL_BADTRANS, /* 6 */
+ REPL_HEARTBEAT, /* 7 */
+ REPL_FETCH_RESYNC, /* 8 */
+ REPL_RESYNC_SEQNO, /* 9 */
+ REPL_START_SEQNO_STOPSRCFILTER, /* 10 */ /* needed for backward compatibility with 4.1-000 */
+ REPL_XOFF_ACK_ME, /* 11 */
+ REPL_XOFF_ACK, /* 12 */
+ REPL_WILL_RESTART_WITH_INFO /* 13 */
+};
+
+#define START_FLAG_NONE 0x00000000
+#define START_FLAG_STOPSRCFILTER 0x00000001
+#define START_FLAG_UPDATERESYNC 0x00000002
+#define START_FLAG_HASINFO 0x00000004
+#define START_FLAG_COLL_M 0x00000008
+#define START_FLAG_VERSION_INFO 0x00000010
+#define START_FLAG_TRIGGER_SUPPORT 0x00000020
+#define START_FLAG_SRCSRV_IS_VMS 0x00000040
+
+#define MIN_REPL_MSGLEN 32 /* To keep compiler happy with
+ * the definition of repl_msg_t as well
+ * as to accommodate a seq_num */
+
+#define REPL_MSG_HDRLEN (SIZEOF(int4) + SIZEOF(int4)) /* For type and
+ * len fields */
+
+typedef struct
+{
+ int4 type;
+ int4 len;
+ unsigned char msg[MIN_REPL_MSGLEN - REPL_MSG_HDRLEN];
+ /* All that we need is msg[1], but keep the compiler happy with
+ * this definition for msg. Also provide space to accommodate a seq_num
+ * so that a static definition would suffice instead of malloc'ing a
+ * small message buffer */
+} repl_msg_t;
+
+#define MAX_REPL_MSGLEN (1 * 1024 * 1024) /* should ideally match the TCP send (recv) bufsiz of source (receiver) server */
+#define MAX_TR_BUFFSIZE (MAX_REPL_MSGLEN - REPL_MSG_HDRLEN) /* allow for replication message header */
+
+typedef struct
+{
+ int4 type;
+ int4 len;
+ unsigned char start_seqno[SIZEOF(seq_num)];
+ uint4 start_flags;
+ unsigned char jnl_ver;
+ char filler[MIN_REPL_MSGLEN - REPL_MSG_HDRLEN - SIZEOF(seq_num) -
+ SIZEOF(uint4) - SIZEOF(unsigned char)];
+} repl_start_msg_t; /* The first two fields should be as in repl_msg_t */
+
+typedef struct
+{
+ int4 type;
+ int4 len;
+ unsigned char start_seqno[SIZEOF(seq_num)];
+ unsigned char jnl_ver;
+ char start_flags[4];
+ char filler[MIN_REPL_MSGLEN - REPL_MSG_HDRLEN - SIZEOF(seq_num) -
+ - SIZEOF(unsigned char) - 4 * SIZEOF(char)];
+} repl_start_reply_msg_t; /* The first two fields should be as in repl_msg_t */
+
+typedef struct
+{
+ int4 type;
+ int4 len;
+ unsigned char ack_seqno[SIZEOF(seq_num)];
+ unsigned char ack_time[SIZEOF(time_t)];
+ unsigned char filler[MIN_REPL_MSGLEN - REPL_MSG_HDRLEN - SIZEOF(seq_num) - SIZEOF(time_t)];
+} repl_heartbeat_msg_t; /* The first two fields should be as in repl_msg_t */
+
+typedef struct
+{
+ struct
+ {
+ int4 fl;
+ int4 bl;
+ } que;
+ repl_heartbeat_msg_t heartbeat;
+} repl_heartbeat_que_entry_t;
+
+#if defined(__osf__) && defined(__alpha)
+# pragma pointer_size(save)
+# pragma pointer_size(long)
+#endif
+
+typedef repl_msg_t *repl_msg_ptr_t;
+typedef repl_start_msg_t *repl_start_msg_ptr_t;
+typedef repl_start_reply_msg_t *repl_start_reply_msg_ptr_t;
+
+#if defined(__osf__) && defined(__alpha)
+# pragma pointer_size(restore)
+#endif
+
+#endif
diff --git a/sr_vvms/repl_sem.c b/sr_vvms/repl_sem.c
new file mode 100644
index 0000000..eb25edd
--- /dev/null
+++ b/sr_vvms/repl_sem.c
@@ -0,0 +1,326 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2002 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <ssdef.h>
+#include <prtdef.h>
+#include <secdef.h>
+#include <psldef.h>
+#include <syidef.h>
+#include <descrip.h>
+#include <lkidef.h>
+#include <lckdef.h>
+#include <efndef.h>
+
+#include "gtm_string.h"
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "repl_sem.h"
+#include "vmsdtype.h"
+#include "repl_sp.h"
+#include "locks.h"
+#include "min_max.h"
+
+/* In the present shape, this module is not generic enough. Coded with the
+ * view of brining SEM related code out of replication module. Could be made
+ * more generic. Handles two semaphore sets one for source and another for
+ * receiver server */
+
+#define SEMS_PER_SET (MAX(NUM_SRC_SEMS, NUM_RECV_SEMS))
+#define MAX_LOCKS_QUED 20 /* Max. number of locks for a resource. Required for get_sem_pid() */
+#define BUFF_SIZE 255
+#define descrcpy(A, B) (A)->dsc$b_dtype = (B)->dsc$b_dtype;\
+ (A)->dsc$b_class = (B)->dsc$b_class;\
+ (A)->dsc$w_length= (B)->dsc$w_length;\
+ memcpy((A)->dsc$a_pointer, (B)->dsc$a_pointer, (B)->dsc$w_length);
+#define INITIAL_N_LOCKS 8 /* Used in get_lkpid() */
+
+GBLDEF int4 repl_sem_errno;
+GBLDEF char repl_msg_buff[BUFF_SIZE];
+GBLDEF mstr repl_msg_str = {BUFF_SIZE, repl_msg_buff};
+
+typedef struct
+{
+ char res_name[MAX_NAME_LEN + 1];
+ sem_key_t key;
+ int4 lock_id;
+} sem_ctl_t;
+
+typedef struct
+{
+ short int buffer_length;
+ short int item_code;
+ void *bufaddress;
+ void *retaddress;
+} t_lki_item_list;
+
+#ifndef __NEW_STARLET
+typedef struct lkidef LKIDEF;
+#endif
+
+static sem_ctl_t sem_ctl[NUM_SEM_SETS][SEMS_PER_SET];
+
+boolean_t sem_set_exists(int which_set)
+{
+ return (0 < sem_ctl[which_set][0].lock_id);
+}
+
+int init_sem_set_source(sem_key_t *key)
+{
+ int status;
+ int i, j;
+
+ /* Resource Name format : refer to global_name.c
+ * Example - GT$P_ALPHA2$DKA300$B522D2000000
+ * prefix - 4 chars = GT$P
+ * Dev-Id - 14 chars = _ALPHA2$DKA300
+ * Delimit- 1 char = $
+ * File-Id- 12 chars = B522D2000000
+ * Total 31 chars (Max. length allowed for lock and gsec names!)
+ * Since the length is limited and maximum is already reached, to get unique names for sems in the sem-set,
+ * modify the prefix: GT$P to GT$K, GT$L, and GT$M
+ */
+
+ /* Fill in the resource names */
+ for (i = JNL_POOL_ACCESS_SEM; i < NUM_SRC_SEMS; i++)
+ {
+ sem_ctl[SOURCE][i].key.dsc$a_pointer = sem_ctl[SOURCE][i].res_name;
+ descrcpy(&sem_ctl[SOURCE][i].key, key );
+ }
+
+ sem_ctl[SOURCE][JNL_POOL_ACCESS_SEM].res_name[3] = 'K'; /* K - Journal Pool Access */
+ sem_ctl[SOURCE][SRC_SERV_COUNT_SEM].res_name[3] = 'L'; /* L - Source Server Count */
+ sem_ctl[SOURCE][SRC_SERV_OPTIONS_SEM].res_name[3] = 'M'; /* M - Source Server Options */
+
+ /* Keep all the SEMs(locks) in NULL mode */
+ for (i = JNL_POOL_ACCESS_SEM; i < NUM_SRC_SEMS; i++)
+ if (status = grab_null_lock(SOURCE, i))
+ break;
+ if (status)
+ {
+ for (j = JNL_POOL_ACCESS_SEM; j < i; j++) /* grab_null_lock() on i-th sem failed */
+ {
+ if (SS$_NORMAL != gtm_deq(sem_ctl[SOURCE][j].lock_id, NULL, PSL$C_USER, 0))
+ {
+ assert(FALSE);
+ break;
+ }
+ sem_ctl[SOURCE][j].lock_id = 0;
+ }
+ }
+ return status;
+}
+
+int init_sem_set_recvr(sem_key_t *key)
+{
+ int status;
+ int i, j;
+
+ /* Fill in the resource names */
+ /* Refer to init_sem_set_source() for an explanation */
+
+ for (i = RECV_POOL_ACCESS_SEM; i < NUM_RECV_SEMS; i++)
+ {
+ sem_ctl[RECV][i].key.dsc$a_pointer = sem_ctl[RECV][i].res_name;
+ descrcpy(&sem_ctl[RECV][i].key, key );
+ }
+ sem_ctl[RECV][RECV_POOL_ACCESS_SEM].res_name[3] = 'T'; /* T - Recv. Pool Access */
+ sem_ctl[RECV][RECV_SERV_COUNT_SEM].res_name[3] = 'U'; /* U - Recv. Server Count */
+ sem_ctl[RECV][UPD_PROC_COUNT_SEM].res_name[3] = 'V'; /* V - Update Process Count */
+ sem_ctl[RECV][RECV_SERV_OPTIONS_SEM].res_name[3] = 'W'; /* W - Recv. Server Options */
+
+ /* Keep all the SEMs in NULL mode */
+ for (i = RECV_POOL_ACCESS_SEM; i < NUM_RECV_SEMS; i++)
+ if (status = grab_null_lock(RECV, i))
+ break;
+ if (status)
+ {
+ for (j = RECV_POOL_ACCESS_SEM; j < i; j++) /* grab_null_lock() on i-th sem failed */
+ {
+ if (SS$_NORMAL != gtm_deq(sem_ctl[RECV][j].lock_id, NULL, PSL$C_USER, 0))
+ {
+ assert(FALSE);
+ break;
+ }
+ sem_ctl[RECV][j].lock_id = 0;
+ }
+ }
+ return status;
+}
+
+int grab_sem(int set_index, int sem_num)
+{
+ vms_lock_sb lksb;
+ REPL_SEM_ENQW(set_index, sem_num, LCK$K_EXMODE, LCK$M_CONVERT | LCK$M_NODLCKWT);
+ return REPL_SEM_STATUS;
+}
+
+int grab_sem_immediate(int set_index, int sem_num)
+{
+ vms_lock_sb lksb;
+ REPL_SEM_ENQW(set_index, sem_num, LCK$K_EXMODE, LCK$M_CONVERT | LCK$M_NODLCKWT | LCK$M_NOQUEUE);
+ return REPL_SEM_STATUS;
+}
+
+int rel_sem(int set_index, int sem_num)
+{
+ vms_lock_sb lksb;
+ REPL_SEM_ENQW(set_index, sem_num, LCK$K_NLMODE, LCK$M_CONVERT | LCK$M_NODLCKWT);
+ return REPL_SEM_STATUS;
+}
+
+int rel_sem_immediate(int set_index, int sem_num)
+{
+ vms_lock_sb lksb;
+ REPL_SEM_ENQW(set_index, sem_num, LCK$K_NLMODE, LCK$M_CONVERT | LCK$M_NODLCKWT | LCK$M_NOQUEUE);
+ return REPL_SEM_STATUS;
+}
+
+int remove_sem_set(int set_index)
+{
+ int i;
+
+ ASSERT_SET_INDEX;
+ if (SOURCE == set_index)
+ {
+ for (i = JNL_POOL_ACCESS_SEM; i < NUM_SRC_SEMS; i++)
+ {
+ if (SS$_NORMAL != (repl_sem_errno = gtm_deq(sem_ctl[SOURCE][i].lock_id, NULL, PSL$C_USER, 0)))
+ {
+ assert(FALSE);
+ break;
+ }
+ sem_ctl[SOURCE][i].lock_id = 0;
+ }
+ }
+ else /* RECIEVER */
+ {
+ for (i = RECV_POOL_ACCESS_SEM; i < NUM_SRC_SEMS; i++)
+ {
+ if (SS$_NORMAL != (repl_sem_errno = gtm_deq(sem_ctl[RECV][i].lock_id, NULL, PSL$C_USER, 0)))
+ {
+ assert(FALSE);
+ break;
+ }
+ sem_ctl[RECV][i].lock_id = 0;
+ }
+ }
+ return REPL_SEM_STATUS;
+}
+
+int get_sem_info(int set_index, int sem_num, sem_info_type info_id)
+{
+ int ret_val;
+ uint4 status, lk_pid, get_lkpid(struct dsc$descriptor_s *, int, uint4 *);
+
+ ASSERT_SET_INDEX;
+ switch(info_id)
+ {
+ case SEM_INFO_VAL :
+ status = get_lkpid(&sem_ctl[set_index][sem_num].key, LCK$K_EXMODE, &lk_pid);
+ if (SS$_NORMAL != status)
+ {
+ repl_sem_errno = status;
+ ret_val = -1;
+ } else if (lk_pid)
+ ret_val = 1;
+ else
+ ret_val = 0;
+ break;
+ default :
+ ret_val = -1;
+ break;
+ }
+ return ret_val;
+}
+
+static int grab_null_lock(int set_index, int sem_num)
+{
+ vms_lock_sb lksb;
+
+ repl_sem_errno = gtm_enqw(EFN$C_ENF, LCK$K_NLMODE, &lksb, LCK$M_SYSTEM | LCK$M_EXPEDITE, &sem_ctl[set_index][sem_num].key,
+ 0, NULL, 0, NULL, PSL$C_USER, 0);
+ assert(SS$_NORMAL == repl_sem_errno);
+ if (SS$_NORMAL == repl_sem_errno)
+ repl_sem_errno = lksb.cond;
+ assert(SS$_NORMAL == repl_sem_errno);
+ if (SS$_NORMAL == repl_sem_errno)
+ sem_ctl[set_index][sem_num].lock_id = lksb.lockid;
+ return REPL_SEM_STATUS;
+}
+
+/* check if any process holds the lock identified by name_dsc in a mode at or above given lkmode.
+ * If so, return the pid of such a process thru third arg. If there are multiple processes satisfying
+ * the criterion, pid of any one such processes is returned. If there is no such process, zero is
+ * returned in third arg.
+ */
+
+uint4 get_lkpid(struct dsc$descriptor_s *name_dsc, int lkmode, uint4 *lk_pid)
+{
+ static char *lki_locks = NULL;
+ static int size = INITIAL_N_LOCKS;
+ uint4 ret_len, status;
+ vms_lock_sb lksb;
+ LKIDEF *item, *lki_top;
+ t_lki_item_list lki_item_list[2] = {
+ {0, LKI$_LOCKS, 0, &ret_len},
+ {0, 0, 0, 0}
+ };
+
+ *lk_pid = 0;
+ /* Grab Null lock on the resource */
+ if (SS$_NORMAL != (status = gtm_enqw(EFN$C_ENF, LCK$K_NLMODE, &lksb, LCK$M_SYSTEM | LCK$M_EXPEDITE,
+ name_dsc, 0, NULL, 0, NULL, PSL$C_USER, 0)))
+ {
+ assert(FALSE);
+ return status;
+ }
+ /* Get a list of all the locks on the resource of interest */
+ do
+ {
+ if (NULL == lki_locks)
+ lki_locks = (char *)malloc(size * LKI$C_LENGTH); /* see lkidef.h for LKI$C_LENGTH */
+ lki_item_list[0].buffer_length = size * LKI$C_LENGTH;
+ lki_item_list[0].bufaddress = lki_locks;
+ if (SS$_NORMAL != (status = gtm_getlkiw(EFN$C_ENF, &lksb.lockid, lki_item_list, 0, 0, 0, 0)))
+ {
+ gtm_deq(lksb.lockid, NULL, PSL$C_USER, 0); /* return status not as important as gtm_getlkiw()'s */
+ return status;
+ }
+ if (!(ret_len >> 31)) /* size of user buffer passed to gtm_getlkiw() was enough */
+ break;
+ free(lki_locks);
+ lki_locks = NULL;
+ size <<= 1;
+ } while(TRUE);
+ /* Release Null lock on the resource (grabbed above) */
+ if (SS$_NORMAL != (status = gtm_deq(lksb.lockid, NULL, PSL$C_USER, 0)))
+ {
+ assert(FALSE);
+ return status;
+ }
+ /* Check through the Locks list got above, if anyone holds the lock in mode >= lkmode.
+ If so fill lk_pid with the pid of that process */
+ lki_top = (LKIDEF *)(lki_locks + (ret_len & 0x0000FFFF));
+ /* On vax sizeof LKIDEF is not the same as LKI$C_LENGTH (56 vs 24), hence the kludgery below */
+ for (item = (LKIDEF *)lki_locks; item < lki_top; item = (LKIDEF *) ((char *)item + LKI$C_LENGTH))
+ if (LKI$C_GRANTED == item->lki$b_queue && lkmode <= item->lki$b_grmode)
+ {
+ *lk_pid = item->lki$l_pid;
+ return SS$_NORMAL;
+ }
+ return SS$_NORMAL; /* Nobody holds the lock in mode >= lkmode */
+}
diff --git a/sr_vvms/repl_sem.h b/sr_vvms/repl_sem.h
new file mode 100644
index 0000000..b49c419
--- /dev/null
+++ b/sr_vvms/repl_sem.h
@@ -0,0 +1,74 @@
+/****************************************************************
+ * *
+ * Copyright 2006 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef _REPL_SEM_H
+#define _REPL_SEM_H
+
+#include "repl_sem_sp.h"
+
+#define ASSERT_SET_INDEX assert (NUM_SEM_SETS > set_index)
+
+enum
+{
+ SOURCE,
+ RECV,
+ NUM_SEM_SETS
+};
+
+typedef enum
+{
+ JNL_POOL_ACCESS_SEM, /* For Startup / Shutdown */
+ SRC_SERV_COUNT_SEM, /* Source sever holds it while alive */
+ SRC_SERV_OPTIONS_SEM, /* For options change, since it is done through the shared memory */
+ DUMMY_SEM, /* added just to make the number of semaphores same as in recvpool */
+ SOURCE_ID_SEM,
+ NUM_SRC_SEMS
+} source_sem_type;
+
+typedef enum
+{
+ RECV_POOL_ACCESS_SEM, /* For Startup / Shutdown */
+ RECV_SERV_COUNT_SEM, /* Receiver sever holds it while alive */
+ UPD_PROC_COUNT_SEM, /* Update process holds it while alive */
+ RECV_SERV_OPTIONS_SEM, /* For options change, since it is done through the shared memory */
+ RECV_ID_SEM,
+ NUM_RECV_SEMS
+} recv_sem_type;
+
+typedef enum
+{
+ SEM_INFO_VAL,
+ SEM_INFO_PID,
+ SEM_NUM_INFOS
+} sem_info_type;
+
+int grab_sem(int set_index, int sem_num); /* set_index can be SOURCE or RECV */
+int grab_sem_immediate(int set_index, int sem_num);
+int rel_sem(int set_index, int sem_num);
+int rel_sem_immediate(int set_index, int sem_num);
+int get_sem_info(int set_index, int sem_num, sem_info_type info_id);
+int remove_sem_set(int set_index);
+boolean_t sem_set_exists(int which_set);
+
+#ifdef UNIX
+void rel_recvpool_ftok_sems(boolean_t, boolean_t);
+void rel_jnlpool_ftok_sems(boolean_t, boolean_t);
+void lock_recvpool_ftok_sems(boolean_t, boolean_t);
+void lock_jnlpool_ftok_sems(boolean_t, boolean_t);
+void get_lock_recvpool_ftok_sems(boolean_t, boolean_t);
+void get_lock_jnlpool_ftok_sems(boolean_t, boolean_t);
+void set_sem_set_src(int semid);
+void set_sem_set_recvr(int semid);
+int grab_sem_all_source(void); /* rollback needs this */
+int grab_sem_all_receive(void); /* rollback needs this */
+#endif
+
+#endif /* _REPL_SEM_H */
diff --git a/sr_vvms/repl_sem_sp.h b/sr_vvms/repl_sem_sp.h
new file mode 100644
index 0000000..179514f
--- /dev/null
+++ b/sr_vvms/repl_sem_sp.h
@@ -0,0 +1,40 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2002 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef _REPL_SEM_SP_H
+#define _REPL_SEM_SP_H
+
+#define REPL_SEM_ERRNO repl_sem_errno
+#define REPL_SEM_ERROR (gtm_getmsg(repl_sem_errno, &repl_msg_str),repl_msg_buff)
+#define REPL_SEM_NOT_GRABBED (SS$_NOTQUEUED == repl_sem_errno)
+#define REPL_SEM_NOT_GRABBED1 (SS$_NOTQUEUED == save_errno)
+#define REPL_STR_ERROR (gtm_getmsg(status, &repl_msg_str),repl_msg_buff)
+#define REPL_STR_ERROR1(status) (gtm_getmsg(status, &repl_msg_str),repl_msg_buff)
+#define REPL_SEM_STATUS ((SS$_NORMAL == repl_sem_errno) ? 0 : -1)
+
+#define REPL_SEM_ENQW(set_index, sem_num, mode, flags) \
+ ASSERT_SET_INDEX; \
+ lksb.lockid = sem_ctl[set_index][sem_num].lock_id; \
+ repl_sem_errno = gtm_enqw(EFN$C_ENF, mode, &lksb, flags, NULL, 0, NULL, 0, NULL, PSL$C_USER, 0); \
+ assert(SS$_NORMAL == repl_sem_errno || (((flags) & LCK$M_NOQUEUE) && (SS$_NOTQUEUED == repl_sem_errno))); \
+ if (SS$_NORMAL == repl_sem_errno) \
+ repl_sem_errno = lksb.cond; \
+ assert(SS$_NORMAL == repl_sem_errno || (((flags) & LCK$M_NOQUEUE) && (SS$_NOTQUEUED == repl_sem_errno))); \
+
+typedef struct dsc$descriptor_s sem_key_t;
+
+int init_sem_set_source(sem_key_t *key);
+int init_sem_set_recvr(sem_key_t *key);
+
+GBLREF int4 repl_sem_errno;
+GBLREF char repl_msg_buff[];
+GBLREF mstr repl_msg_str;
+#endif /* _REPL_SEM_SP_H */
diff --git a/sr_vvms/repl_shm.c b/sr_vvms/repl_shm.c
new file mode 100644
index 0000000..c8e55ee
--- /dev/null
+++ b/sr_vvms/repl_shm.c
@@ -0,0 +1,224 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_inet.h"
+
+#include <stddef.h>
+#include <lkidef.h>
+#include <ssdef.h>
+#include <clidef.h>
+#include <iodef.h>
+#include <prtdef.h>
+#include <prvdef.h>
+#include <secdef.h>
+#include <psldef.h>
+#include <syidef.h>
+#include <descrip.h>
+#include <lckdef.h>
+#include <efndef.h>
+
+#include "gtm_string.h"
+
+#include "vmsdtype.h"
+#include "gdsroot.h"
+#include "repl_sem.h"
+#include "repl_shm.h"
+#include "repl_sp.h"
+
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "jnl.h"
+#include "repl_msg.h"
+#include "gtmsource.h"
+#include "gtmrecv.h"
+#include "locks.h"
+#include "mem_list.h"
+#include "init_sec.h"
+
+#define MAILBOX_SIZE 512
+
+error_def(ERR_RECVPOOLSETUP);
+error_def(ERR_JNLPOOLSETUP);
+error_def(ERR_TEXT);
+error_def(ERR_REPLWARN);
+
+static uint4 header_size[2] = {JNLDATA_BASE_OFF, RECVDATA_BASE_OFF};
+static uint4 size_offset[2] = {offsetof(jnlpool_ctl_struct, jnlpool_size), offsetof(recvpool_ctl_struct, recvpool_size)};
+static uint4 ERR_POOLSETUP[2] = {ERR_JNLPOOLSETUP, ERR_RECVPOOLSETUP};
+
+static uint4 get_pagelet_count(boolean_t src_or_rcv, char *gsec_name, int4 *pgcnt)
+{
+ sm_uc_ptr_t shm_range[2];
+ uint4 hdr_pglets;
+ uint4 status, *psize, size;
+ $DESCR(d_gsec, gsec_name);
+
+ /* Map initial pages required to get the header*/
+ hdr_pglets = DIVIDE_ROUND_UP(header_size[src_or_rcv], OS_PAGELET_SIZE);
+ if (SS$_NORMAL != (status = map_shm_aux(src_or_rcv, &d_gsec, hdr_pglets, shm_range)))
+ /* Global section doesn't exist. Just return. Caller has to handle */
+ return status;
+
+ /* Get the size from the header */
+ psize = (uint4 *) (shm_range[0]+size_offset[src_or_rcv]);
+ size = header_size[src_or_rcv] + (*psize);
+ *pgcnt = DIVIDE_ROUND_UP(size, OS_PAGELET_SIZE);
+
+ /* Unmap */
+ detach_shm(shm_range);
+
+ return SS$_NORMAL;
+}
+
+static int4 map_shm_aux(boolean_t src_or_rcv, struct dsc$descriptor_s *name_dsc, int4 buff_pagelets, sm_uc_ptr_t *shm_range)
+{
+ int4 status;
+ uint4 flags;
+ sm_uc_ptr_t inadr[2];
+
+ /* Expand virtual address space */
+ status = gtm_expreg(buff_pagelets, inadr, PSL$C_USER, 0);
+ if (SS$_NORMAL != status)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_POOLSETUP[src_or_rcv], 0,
+ ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to expand virtual address space"), status);
+
+ /* Optional gaurding of the shared space - to be done here, if needed.(gvcst_init_sysops.c is a sample)*/
+
+ /* map to the global section */
+ flags = SEC$M_SYSGBL | SEC$M_WRT;
+ if (SS$_NORMAL != (status = sys$mgblsc(inadr, shm_range, PSL$C_USER, flags, name_dsc, NULL, 0)))
+ detach_shm(inadr);
+ return status;
+}
+
+int4 create_and_map_shm(boolean_t src_or_rcv, struct dsc$descriptor_s *name_dsc, int4 buffsize, sm_uc_ptr_t *shm_range)
+{
+ int4 buff_pagelets, status;
+ uint4 flags;
+ /* uint4 inadr[2]; temp for init_sec */
+
+ buff_pagelets = DIVIDE_ROUND_UP(buffsize, OS_PAGELET_SIZE);
+ /* If jnl-pool-size has to be in multiple of pages, uncomment the next line */
+ /* buff_pagelets = ROUND_UP(buff_pagelets, OS_PAGE_SIZE / OS_PAGELET_SIZE); */
+
+ /* Expand virtual address space */
+ status = gtm_expreg(buff_pagelets, shm_range, PSL$C_USER, 0);
+ if (SS$_NORMAL != status)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_POOLSETUP[src_or_rcv], 0,
+ ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to expand virtual address space"), status);
+
+ /* Optional gaurding of the shared space - to be done here, if needed.(gvcst_init_sysops.c is a sample)*/
+
+ /* Create if not already existing, and map the global section */
+ flags = SEC$M_GBL | SEC$M_SYSGBL | SEC$M_WRT | SEC$M_PAGFIL | SEC$M_PERM;
+ status = init_sec(shm_range, name_dsc, 0, buff_pagelets, flags);
+
+ if ((SS$_NORMAL != status) && (SS$_CREATED != status))
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_POOLSETUP[src_or_rcv], 0,
+ ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to Create/Map global section"), status);
+ return status;
+}
+
+int4 map_shm(boolean_t src_or_rcv, struct dsc$descriptor_s *name_dsc, sm_uc_ptr_t *shm_range)
+{
+ int4 buff_pagelets, status;
+ uint4 flags;
+ sm_uc_ptr_t inadr[2];
+
+ status = get_pagelet_count(src_or_rcv, name_dsc->dsc$a_pointer, &buff_pagelets);
+ if (SS$_NORMAL != status)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(7) ERR_POOLSETUP[src_or_rcv], 0,
+ ERR_TEXT, 2, RTS_ERROR_LITERAL("Unable to get the number of gblsection pagelets"), status);
+
+ /* If jnl-pool-size has to be in multiple of pages, uncomment the next line */
+ /* buff_pagelets = ROUND_UP(buff_pagelets, OS_PAGE_SIZE / OS_PAGELET_SIZE); */
+
+ return (map_shm_aux(src_or_rcv, name_dsc, buff_pagelets, shm_range));
+}
+
+boolean_t shm_exists(boolean_t src_or_rcv, struct dsc$descriptor_s *name_dsc)
+{
+ int4 buff_pagelets, status;
+ uint4 flags;
+ sm_uc_ptr_t inadr[2], shm_range[2];
+ boolean_t res;
+
+ buff_pagelets = 1;
+ status = gtm_expreg(buff_pagelets, inadr, PSL$C_USER, 0);
+ if (SS$_NORMAL != status)
+ {
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_TEXT, 2,
+ RTS_ERROR_LITERAL("Unable to expand virtual address space"), status);
+ return FALSE;
+ }
+
+ /* map to the global section */
+ flags = SEC$M_SYSGBL | SEC$M_WRT;
+ res = (SS$_NORMAL == sys$mgblsc(inadr, shm_range, PSL$C_USER, flags, name_dsc, NULL, 0));
+ status = gtm_deltva(inadr, NULL, PSL$C_USER);
+ if (SS$_NORMAL != status)
+ if (SOURCE == src_or_rcv)
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_REPLWARN, 2,
+ RTS_ERROR_LITERAL("Could not detach from journal pool"), status);
+ else
+ rts_error_csa(CSA_ARG(NULL) VARLSTCNT(5) ERR_REPLWARN, 2,
+ RTS_ERROR_LITERAL("Could not detach from receiver pool"), status);
+ return res;
+}
+
+int4 register_with_gsec(struct dsc$descriptor_s *name_dsc, int4 *lockid)
+{
+ int4 status;
+ vms_lock_sb lksb;
+
+ status = gtm_enqw(EFN$C_ENF, LCK$K_NLMODE, &lksb, LCK$M_SYSTEM | LCK$M_EXPEDITE, name_dsc, 0, NULL, 0, NULL, PSL$C_USER, 0);
+ assert(SS$_NORMAL == status);
+ if (SS$_NORMAL == status)
+ {
+ status = gtm_enqw(EFN$C_ENF, LCK$K_CRMODE, &lksb, LCK$M_CONVERT, name_dsc, 0, NULL, 0, NULL, PSL$C_USER, 0);
+ assert(SS$_NORMAL == status);
+ if (SS$_NORMAL == status)
+ status = lksb.cond;
+ assert(SS$_NORMAL == status);
+ }
+ if (SS$_NORMAL == status)
+ *lockid = lksb.lockid;
+ return status;
+}
+
+int4 lastuser_of_gsec(int4 gsec_lockid)
+{
+ int4 status;
+ vms_lock_sb lksb;
+
+ lksb.lockid = gsec_lockid;
+ status = gtm_enqw(EFN$C_ENF, LCK$K_EXMODE, &lksb, LCK$M_CONVERT | LCK$M_NOQUEUE, NULL, 0, NULL, 0, NULL, PSL$C_USER, 0);
+ assert(SS$_NORMAL == status || SS$_NOTQUEUED == status);
+ if (SS$_NORMAL == status)
+ status = lksb.cond;
+ assert(SS$_NORMAL == status || SS$_NOTQUEUED == status);
+ return status;
+}
+
+uint4 signoff_from_gsec_dbg(unsigned int gsec_lockid)
+{
+ uint4 status;
+
+ status = gtm_deq(gsec_lockid, NULL, PSL$C_USER, 0);
+ assert(SS$_NORMAL == status);
+ return status;
+}
diff --git a/sr_vvms/repl_shm.h b/sr_vvms/repl_shm.h
new file mode 100644
index 0000000..ae2c28d
--- /dev/null
+++ b/sr_vvms/repl_shm.h
@@ -0,0 +1,49 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef _REPL_SHM_H
+#define _REPL_SHM_H
+
+/* signoff_from_gsec() invokes gtm_deq() and is used in a lot of places.
+ * In DBG mode, we want to assert fail whenever gtm_deq() returns abnormal status.
+ * Hence we define a new function that does a call to gtm_deq() and asserts on status.
+ * In PRO, we dont want the extra-function-call overhead, hence the macro is a direct call to gtm_deq().
+ */
+#ifndef DEBUG
+#define signoff_from_gsec(gsec_lockid) gtm_deq(gsec_lockid, NULL, PSL$C_USER, 0)
+#else
+#define signoff_from_gsec(gsec_lockid) signoff_from_gsec_dbg(gsec_lockid)
+#endif
+
+#define detach_shm(shm_range) gtm_deltva(shm_range, NULL, PSL$C_USER)
+#define delete_shm(name_dsc) del_sec(SEC$M_SYSGBL, name_dsc, NULL)
+
+boolean_t create_and_map_shm(boolean_t src_or_rcv, struct dsc$descriptor_s *name_dsc, int4 buffsize, sm_uc_ptr_t *shm_range);
+int4 map_shm(boolean_t src_or_rcv, struct dsc$descriptor_s *name_dsc, sm_uc_ptr_t *shm_range);
+boolean_t shm_exists(boolean_t src_or_rcv, struct dsc$descriptor_s *name_dsc);
+int4 register_with_gsec(struct dsc$descriptor_s *name_dsc, int4 *lockid);
+int4 lastuser_of_gsec(int4 gsec_lockid);
+uint4 signoff_from_gsec_dbg(unsigned int gsec_lockid);
+
+#define DETACH_FROM_JNLPOOL(pool_init, jnlpool, jnlpool_ctl) \
+{ \
+ if (pool_init) \
+ { \
+ rel_lock(jnlpool.jnlpool_dummy_reg); \
+ detach_shm(jnlpool.shm_range); \
+ signoff_from_gsec(jnlpool.shm_lockid); \
+ memset(&jnlpool, 0, SIZEOF(jnlpool)); \
+ jnlpool_ctl = NULL; \
+ pool_init = FALSE; \
+ } \
+}
+
+#endif /* _REPL_SHM_H */
diff --git a/sr_vvms/repl_sp.h b/sr_vvms/repl_sp.h
new file mode 100644
index 0000000..3e8168f
--- /dev/null
+++ b/sr_vvms/repl_sp.h
@@ -0,0 +1,90 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2010 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include <descrip.h>
+
+#ifndef _REPL_SP_H
+#define _REPL_SP_H
+
+#define ERRNO ((EVMSERR != errno)? errno : vaxc$errno)
+#define FORMAT_STR "PID %X %s is%s alive\n"
+
+#define MAX_COMMAND_LINE_LENGTH 512
+#define DUMMY_START_QUAL "/DUMMY_START"
+#define NOWAIT 0x1
+#define SERVER_UP 1
+#define MUPIP_CMD "MUPIP "
+#define PROC_NAME_MAXLEN 15
+#define SOURCE_PROMPT_START_QUAL "REPLICATE/SOURCE/START"
+#define RECV_PROMPT_START_QUAL "REPLICATE /RECEIVER/START"
+#define BUFF_QUAL "/BUFFSIZE="
+#define CONNECT_QUAL "/CONNECTPARAMS="
+#define FILTER_QUAL "/FILTER="
+#define SECONDARY_QUAL "/SECONDARY="
+#define LISTENPORT_QUAL "/LISTENPORT="
+#define LOG_QUAL "/LOG="
+#define LOGINTERVAL_QUAL "/LOG_INTERVAL="
+#define PASSIVE_QUAL "/PASSIVE"
+#define $DESCR(name,string) struct dsc$descriptor_s name = { strlen(string), DSC$K_DTYPE_T, DSC$K_CLASS_S, string }
+#define SET_PRIV(X, Y) \
+{ \
+ prvadr[1] = 0; \
+ prvadr[0] = (X); \
+ Y = sys$setprv(TRUE, prvadr, FALSE, prvprv); \
+}
+#define REL_PRIV \
+if (0 != (prvadr[0] &= ~prvprv[0])) \
+{ \
+ sys$setprv(FALSE, prvadr, FALSE, NULL); \
+}
+
+uint4 get_proc_name(unsigned char *prefix, uint4 prefix_size, uint4 pid, unsigned char *buff);
+uint4 get_proc_info(uint4 pid, uint4 *time, uint4 *icount);
+int repl_fork_rcvr_server(uint4 *pid, uint4 *cmd_channel);
+int4 repl_mbx_wr(uint4 channel, sm_uc_ptr_t msg, int len, uint4 err_code);
+int4 repl_trnlnm(struct dsc$descriptor_s *d_tbl_srch_list, struct dsc$descriptor_s *d_logical,
+ struct dsc$descriptor_s *d_expanded, struct dsc$descriptor_s *d_foundin_tbl);
+int4 get_mbx_devname(struct dsc$descriptor_s *d_cmd_mbox, struct dsc$descriptor_s *d_cmd_dev);
+int4 repl_create_server(struct dsc$descriptor_s *d_cmd, char *mbx_prefix, char *mbx_suffix, uint4 *cmd_channel, uint4 *server_pid,
+ uint4 err_code);
+
+/*----- FILE I/O related -----*/
+#define F_CLOSE(CHANNEL, RC) (RC) = sys$dassgn(CHANNEL)
+#define F_COPY_GDID(to, from) \
+{\
+ memcpy(&(to).dvi, &(from).dvi, SIZEOF((to).dvi));\
+ memcpy(&(to).did, &(from).did, SIZEOF((to).did));\
+ memcpy(&(to).fid, &(from).fid, SIZEOF((to).fid));\
+}
+
+#define F_COPY_GDID_FROM_STAT(to, nam) \
+{\
+ memcpy(&(to).dvi, &(nam).nam$t_dvi, SIZEOF((to).dvi));\
+ memcpy(&(to).did, &(nam).nam$w_did, SIZEOF((to).did));\
+ memcpy(&(to).fid, &(nam).nam$w_fid, SIZEOF((to).fid));\
+}
+
+#define F_READ_BLK_ALIGNED(channel, from, buff, size, status) \
+{\
+ status = sys$qiow(EFN$C_ENF, channel, IO$_READVBLK, &iosb[0], 0, 0,\
+ (sm_uc_ptr_t)buff, size, 1+DIVIDE_ROUND_DOWN(from, DISK_BLOCK_SIZE), 0, 0, 0);\
+ if (status == SS$_NORMAL) \
+ status = iosb[0];\
+}
+
+#define F_WRITE_BLK_ALIGNED(channel, to, buff, size, status) \
+{\
+ status = sys$qiow(EFN$C_ENF, channel, IO$_WRITEVBLK, &iosb[0], 0, 0,\
+ (sm_uc_ptr_t)buff, size, 1+DIVIDE_ROUND_DOWN(to, DISK_BLOCK_SIZE), 0, 0, 0);\
+ if (status == SS$_NORMAL) \
+ status = iosb[0];\
+}
+#endif
diff --git a/sr_vvms/repl_utils.c b/sr_vvms/repl_utils.c
new file mode 100644
index 0000000..ab747fe
--- /dev/null
+++ b/sr_vvms/repl_utils.c
@@ -0,0 +1,99 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <ssdef.h>
+#include <fab.h>
+#include <rms.h>
+#include <iodef.h>
+#include <descrip.h>
+#include <secdef.h>
+#include <efndef.h>
+
+#include "gtm_inet.h"
+#include "gtm_string.h"
+
+#include "gdsroot.h"
+#include "gdskill.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "gdscc.h"
+#include "copy.h"
+#include "filestruct.h"
+#include "jnl.h"
+#include "buddy_list.h" /* needed for tp.h */
+#include "hashtab_int4.h" /* needed for tp.h and muprec.h */
+#include "tp.h"
+#include "hashtab_mname.h" /* needed for muprec.h */
+#include "hashtab_int8.h" /* needed for muprec.h */
+#include "muprec.h"
+#include "iosp.h"
+#include <rtnhdr.h>
+#include "mv_stent.h"
+#include "stack_frame.h"
+#include "gtmrecv.h"
+#include "cli.h"
+#include "error.h"
+#include "repl_msg.h"
+#include "gtmsource.h"
+#include "repl_shutdcode.h"
+#include "repl_sp.h"
+#include "util.h"
+#include "gtmmsg.h"
+
+GBLREF mur_gbls_t murgbl;
+
+uint4 get_proc_name(unsigned char *prefix, uint4 prefix_size, uint4 pid, unsigned char *buff)
+{
+ unsigned char *cp;
+ int j, n, nbcd;
+
+ cp = buff;
+ memcpy(cp, prefix, prefix_size);
+ cp += prefix_size;
+ nbcd = SIZEOF(pid) * 2;
+ for (j = 0 ; j < nbcd; j++, pid >>= 4)
+ {
+ n = pid & 0xf;
+ cp[nbcd - 1 - j] = n + (n < 10 ? 48 : 55);
+ }
+ cp += nbcd;
+ *cp = '\0';
+ assert(cp - buff <= PROC_NAME_MAXLEN);
+ return (cp - buff);
+}
+
+int4 *parse_filename(struct dsc$descriptor_s *d_file, struct dsc$descriptor_s *d_exp_file, boolean_t exp_concealed)
+{
+ int4 status;
+ struct FAB fab;
+ struct NAM nam;
+
+ fab = cc$rms_fab;
+ nam = cc$rms_nam;
+ fab.fab$l_nam = &(nam);
+ fab.fab$l_fop = FAB$M_NAM;
+ fab.fab$l_fna = STR_OF_DSC(*d_file);
+ fab.fab$b_fns = LEN_OF_DSC(*d_file);
+ nam.nam$l_esa = STR_OF_DSC(*d_exp_file);
+ nam.nam$b_ess = LEN_OF_DSC(*d_exp_file);
+ nam.nam$b_nop = (exp_concealed * NAM$M_NOCONCEAL) | NAM$M_SYNCHK;
+ if (RMS$_NORMAL == (status = sys$parse(&fab,0,0)))
+ if (nam.nam$b_name != 0)
+ LEN_OF_DSC(*d_exp_file) = nam.nam$b_esl;
+ else
+ LEN_OF_DSC(*d_exp_file) = nam.nam$b_esl - nam.nam$b_type - nam.nam$b_ver;
+ return status;
+}
diff --git a/sr_vvms/route_table.c b/sr_vvms/route_table.c
new file mode 100644
index 0000000..22b8af3
--- /dev/null
+++ b/sr_vvms/route_table.c
@@ -0,0 +1,208 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include "ddphdr.h"
+#include "ddpcom.h"
+#include "route_table.h"
+
+GBLREF unsigned short my_group_mask;
+GBLREF volset_tab volset_table[DDP_MAX_VOLSETS];
+
+static routing_tab routing_table[MAXIMUM_CIRCUITS];
+static circuit_tab circuit_table[MAXIMUM_CIRCUITS * DDP_MAX_VOLSETS];
+
+void remove_circuits(ddp_hdr_t *dp)
+{
+ unsigned short target_circuit, ckt;
+ routing_tab *rp1, *rp2;
+ circuit_tab *ct1, *ct2;
+
+ if (0 == (((ddp_announce_msg_t *)dp->txt)->group_mask & my_group_mask)) /* we are not part of any of the announcer's */
+ return; /* groups; ignore announce/status change message */
+ target_circuit = dp->source_circuit_name;
+ for (rp1 = routing_table; (0 != (ckt = rp1->circuit_name)) && (ckt < target_circuit); rp1++)
+ ;
+ if (ckt == target_circuit)
+ {
+ for (rp2 = rp1 + 1; 0 != rp2->circuit_name; rp2++)
+ ;
+ memmove(rp1, rp1 + 1, (rp2 - rp1) * SIZEOF(*rp1));
+ }
+ for (ct2 = ct1 = circuit_table; 0 != ct1->volset_name; ct1++)
+ {
+ if (ct1->circuit_name != target_circuit)
+ *ct2++ = *ct1;
+ }
+ *ct2 = *ct1;
+ return;
+}
+
+boolean_t enter_circuits(ddp_hdr_t *dp)
+{
+ unsigned short target_circuit, ckt, vol, *fb;
+ routing_tab *rp1, *rp2;
+ circuit_tab *ct1, *ctop;
+ int volset_index;
+ ddp_announce_msg_t *ap;
+
+ ap = (ddp_announce_msg_t *)dp->txt;
+ if (0 == (ap->group_mask & my_group_mask)) /* we are not part of any of the announcer's groups; ignore announce */
+ return FALSE;
+ target_circuit = dp->source_circuit_name;
+ for (rp1 = routing_table; (0 != (ckt = rp1->circuit_name)) && (ckt < target_circuit); rp1++)
+ ;
+ if (ckt != target_circuit)
+ {
+ for (rp2 = rp1 + 1; 0 != rp2->circuit_name; rp2++)
+ ;
+ memmove(rp1 + 1, rp1, (rp2 - rp1) * SIZEOF(*rp1));
+ rp1->circuit_name = target_circuit;
+ memcpy(rp1->ether_addr, ap->ether_addr, ETHERADDR_LENGTH);
+ memset(&rp1->incoming_users[0], 0, SIZEOF(rp1->incoming_users));
+ memset(&rp1->outgoing_users[0], 0, SIZEOF(rp1->outgoing_users));
+ }
+ for (ctop = circuit_table; 0 != ctop->volset_name; ctop++)
+ ;
+ for (volset_index = 0; volset_index < DDP_MAX_VOLSETS; volset_index++)
+ {
+ if (0 != (vol = ap->volset[volset_index]))
+ {
+ for (ct1 = circuit_table; (0 != ct1->volset_name) && (ct1->volset_name < vol); ct1++)
+ ;
+ if (ct1->volset_name != vol)
+ {
+ memmove(ct1 + 1, ct1, (ctop - ct1) * SIZEOF(ct1));
+ ctop++;
+ ct1->volset_name = vol;
+ ct1->circuit_name = target_circuit;
+ }
+ }
+ }
+ return TRUE;
+}
+
+unsigned short find_circuit(unsigned short vol)
+{ /* given volume set, find circuit */
+ circuit_tab *ct;
+ unsigned short volset;
+
+ for (volset = vol, ct = circuit_table; 0 != ct->volset_name && ct->volset_name < volset; ct++)
+ ;
+ if (volset == ct->volset_name)
+ return ct->circuit_name;
+ return 0;
+}
+
+routing_tab *find_route(unsigned short ckt)
+{ /* given circuit, find the corresponding routing table entry */
+ routing_tab *rt;
+ unsigned short circuit;
+
+ for (circuit = ckt, rt = routing_table; 0 != rt->circuit_name && rt->circuit_name < circuit; rt++)
+ ;
+ if (circuit == rt->circuit_name)
+ return rt;
+ return 0;
+}
+
+void reset_user_count(int jobindex)
+{
+ routing_tab *rt;
+
+ for (rt = routing_table; 0 != rt->circuit_name; rt++)
+ rt->outgoing_users[jobindex] = 0;
+}
+
+boolean_t enter_vug(unsigned short vol, unsigned short uci, mstr *gld)
+{
+ boolean_t new_entry;
+ volset_tab *volset_entry, *volset_top;
+ uci_gld_pair *ug, **ugp;
+
+ assert(0 != vol);
+ assert(0 != uci);
+ assert(NULL != gld);
+ assert(NULL != gld->addr);
+ assert(0 != gld->len);
+ for (volset_entry = volset_table; 0 != volset_entry->vol && volset_entry->vol < vol; volset_entry++)
+ ;
+ if (volset_entry->vol != vol)
+ {
+ for (volset_top = volset_entry; 0 != volset_top->vol; volset_top++)
+ ;
+ assert(DDP_MAX_VOLSETS >= volset_top + 1 - volset_table); /* We expect the callers of this function to make sure
+ * that no more than DDP_MAX_VOLSETS vols are entered */
+ memmove(volset_entry + 1, volset_entry, (volset_top - volset_entry) * SIZEOF(*volset_entry));/* make space */
+ volset_entry->vol = vol;
+ volset_entry->ug = NULL;
+ }
+ for (ugp = &volset_entry->ug; NULL != *ugp && (*ugp)->uci < uci; ugp = &(*ugp)->next)
+ ;
+ if (FALSE != (new_entry = (NULL == *ugp || (*ugp)->uci != uci)))
+ {
+ ug = (uci_gld_pair *)malloc(SIZEOF(uci_gld_pair));
+ ug->gld.addr = malloc(gld->len);
+ ug->next = *ugp;
+ *ugp = ug;
+ ug->uci = uci;
+ } else /* if there are multiple entries in the configuration file for the same <vol, uci> pair, the last one wins */
+ {
+ ug = *ugp;
+ free(ug->gld.addr);
+ ug->gld.addr = malloc(gld->len);
+ }
+ memcpy(ug->gld.addr, gld->addr, gld->len);
+ ug->gld.len = gld->len;
+ return new_entry;
+}
+
+void clear_volset_table(void)
+{
+ volset_tab *volset_entry;
+ uci_gld_pair *ug, *free_ug;
+
+ for (volset_entry = volset_table; 0 != volset_entry->vol; volset_entry++)
+ {
+ for (ug = volset_entry->ug; ug != NULL; )
+ {
+ free_ug = ug;
+ ug = ug->next;
+ free(free_ug->gld.addr);
+ free(free_ug);
+ }
+ }
+ memset(volset_table, 0, SIZEOF(volset_table) * SIZEOF(volset_table[0]));
+ return;
+}
+
+mstr *find_gld(unsigned short vol, unsigned short uci)
+{ /* given <vol,uci> pair, find the global directory used by the server */
+ volset_tab *volset_entry;
+ uci_gld_pair *ug;
+
+ if (0 == vol || 0 == uci)
+ return NULL;
+ for (volset_entry = volset_table; 0 != volset_entry->vol && volset_entry->vol < vol; volset_entry++)
+ ;
+ if (vol == volset_entry->vol)
+ {
+ assert(NULL != volset_entry->ug); /* there has to be at least one uci/gld entry */
+ for (ug = volset_entry->ug; ug != NULL && ug->uci < uci; ug = ug->next)
+ ;
+ if (NULL != ug && ug->uci == uci)
+ return &ug->gld;
+ }
+ return NULL;
+}
diff --git a/sr_vvms/route_table.h b/sr_vvms/route_table.h
new file mode 100644
index 0000000..ffbf3bf
--- /dev/null
+++ b/sr_vvms/route_table.h
@@ -0,0 +1,24 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2002 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef ROUTE_TABLE_H_INCLUDED
+#define ROUTE_TABLE_H_INCLUDED
+
+void remove_circuits(ddp_hdr_t *dp);
+boolean_t enter_circuits(ddp_hdr_t *dp);
+unsigned short find_circuit(unsigned short vol);
+routing_tab *find_route(unsigned short ckt);
+void reset_user_count(int jobindex);
+boolean_t enter_vug(unsigned short vol, unsigned short uci, mstr *gld);
+void clear_volset_table(void);
+mstr *find_gld(unsigned short vol, unsigned short uci);
+
+#endif /* ROUTE_TABLE_H_INCLUDED */
diff --git a/sr_vvms/rtn_tbl_sort.c b/sr_vvms/rtn_tbl_sort.c
new file mode 100644
index 0000000..d17d40b
--- /dev/null
+++ b/sr_vvms/rtn_tbl_sort.c
@@ -0,0 +1,164 @@
+/****************************************************************
+ * *
+ * Copyright 2004, 2011 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* NOTE: The rtn_tbl_qsort below uses exactly the same quick sort algorithm used in stpg_sort() and gvcst_kill_sort() */
+
+#include "mdef.h"
+#include <rtnhdr.h>
+#include "obj_file.h" /* for RNAMB_PREF_LEN */
+#include "objlangdefs.h" /* for EGPS$S_NAME */
+#include "min_max.h" /* MIDENT_CMP needs MIN */
+
+#define S_CUTOFF 15
+
+void rtn_tbl_qsort(rtn_tabent *start, rtn_tabent *end);
+
+void rtn_tbl_sort(rtn_tabent *rtab_base, rtn_tabent *rtab_end)
+{
+ rtn_tabent *start, *end;
+
+ for (start = rtab_base; start < rtab_end; start = end)
+ { /* Since the table is already sorted by the VMS linker based on the first 26 characters of rt_name,
+ we only need to sort those routines with longer than 26 char names. However, if the routine name
+ starts with 26 all z's, it may not have been sorted. So, to avoid special cases, each iteration
+ of this loop needs to find a contiguous segment of routines of more than 25 chars and invoke
+ the quicksort on that segment. */
+ for (; start < rtab_end && start->rt_name.len < RNAME_SORTED_LEN; start++)
+ ;
+ for (end = start; end < rtab_end && end->rt_name.len >= RNAME_SORTED_LEN; end++)
+ ;
+ if (start < end)
+ {
+ if (end < rtab_end)
+ rtn_tbl_qsort(start, end - 1);
+ else
+ rtn_tbl_qsort(start, end);
+ }
+ }
+}
+
+/* Sorts a segment of contiguous routine table entries using the value of each rt_name.addr field as the key.
+ * The algorithm is a modified QuickSort algorithm which assumes that top+1 has a greater key value than
+ * any element in the segment. */
+void rtn_tbl_qsort(rtn_tabent *base, rtn_tabent *top)
+{
+ /* Since a pair of pointers are pushed at each level, the stack space of 64 is sufficient
+ * upto a table size of 2**32 elements */
+ rtn_tabent *stack[64], **sp;
+ rtn_tabent v, t;
+ rtn_tabent *l, *r;
+ rtn_tabent *ix, *jx, *kx;
+ mident *tval;
+ int cmp;
+
+ sp = &stack[0];
+ l = base;
+ r = top;
+ for (;;)
+ {
+ if (r - l < S_CUTOFF)
+ {
+ for (ix = l + 1; ix <= r; ix++)
+ {
+ for (jx = ix, t = *ix, tval = &t.rt_name; 1 < jx; jx--)
+ {
+ MIDENT_CMP(&(jx - 1)->rt_name, tval, cmp);
+ if (0 >= cmp)
+ break;
+ *jx = *(jx - 1);
+ }
+ if (ix != jx)
+ *jx = t;
+ }
+ if (sp <= stack)
+ break;
+ else
+ { /* Pop the anchors of a subtable that were pushed earlier and begin a new sort */
+ l = *--sp;
+ r = *--sp;
+ }
+ } else
+ {
+ ix = l;
+ jx = r;
+ kx = l + ((int)(r - l) / 2); /* pivotal key */
+ /* Find the best possible pivotal key among ix, jx and kx (sorta median of those) */
+ MIDENT_CMP(&ix->rt_name, &jx->rt_name, cmp);
+ if (0 < cmp)
+ {
+ MIDENT_CMP(&jx->rt_name, &kx->rt_name, cmp);
+ if (0 < cmp)
+ kx = jx;
+ else
+ {
+ MIDENT_CMP(&ix->rt_name, &kx->rt_name, cmp);
+ if (0 >= cmp)
+ kx = ix;
+ /* else "kx" is already the right choice */
+ }
+ } else
+ {
+ MIDENT_CMP(&jx->rt_name, &kx->rt_name, cmp);
+ if (0 > cmp)
+ kx = jx;
+ else
+ {
+ MIDENT_CMP(&ix->rt_name, &kx->rt_name, cmp);
+ if (0 < cmp)
+ kx = ix;
+ /* else "kx" is already the right choice */
+ }
+ }
+ /* Partition the table into two subtables based on the pivotal */
+ v = *kx;
+ *kx = *jx;
+ *jx = v;
+ tval = &v.rt_name;
+ ix--;
+ do
+ {
+ do
+ {
+ ix++;
+ MIDENT_CMP(&ix->rt_name, tval, cmp);
+ } while (cmp < 0);
+ do
+ {
+ jx--;
+ MIDENT_CMP(&jx->rt_name, tval, cmp);
+ } while (cmp > 0);
+ t = *ix;
+ *ix = *jx;
+ *jx = t;
+ } while (jx > ix);
+ *jx = *ix;
+ *ix = *r;
+ *r = t;
+
+ /* Ensure there are at least two more slots available in the stack for the pushes below */
+ assert((sp - &stack[0]) + 2 < (SIZEOF(stack)/SIZEOF(stack[0])));
+ /* Push the anchors of the large subtable into the stack and begin a new sort on the smaller subtable */
+ if (ix - l > r - ix)
+ {
+ *sp++ = ix - 1;
+ *sp++ = l;
+ l = ix + 1;
+ }
+ else
+ {
+ *sp++ = r;
+ *sp++ = ix + 1;
+ r = ix - 1;
+ }
+ }
+ }
+ return;
+}
diff --git a/sr_vvms/rtnhdr.h b/sr_vvms/rtnhdr.h
new file mode 100644
index 0000000..2f28c4b
--- /dev/null
+++ b/sr_vvms/rtnhdr.h
@@ -0,0 +1,152 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+#ifndef RTNHDR_H_INCLUDED
+#define RTNHDR_H_INCLUDED
+
+/* rtnhdr.h - routine header */
+
+/* There are several references to this structure from assembly language; these include:
+ *
+ * From VAX VMS: G_MSF.MAX,
+ * GTM$FGNCALL.MAR, FGNCAL_RTN.MAR
+ *
+ * From Alpha VMS: G_MSF.MAX,
+ * GTM$FGNCAL.M64, FGNCAL_RTN.M64
+ *
+ * From Unix: g_msf.si
+ *
+ * Any changes to the routine header must be reflected in those files as well.
+ *
+ * Warning: the lists above may not be complete.
+ */
+
+/* rhead_struct is the routine header; it occurs at the beginning of the
+ * object code part of each module.
+ *
+ * The routine header is initialized when a module is first linked into
+ * an executable. If a new version of that module is subsequently ZLINK'ed
+ * into a running image, some of the fields will be updated to describe
+ * the new version of the module so that existing references from other
+ * modules to earlier versions of this module will be re-directed to the
+ * current version.
+ */
+
+typedef struct rhead_struct
+{
+ char jsb[RHEAD_JSB_SIZE];
+ mstr src_full_name; /* (updated) full source name of current module version */
+ mident routine_name;
+ int4 vartab_off; /* (updated) offset to variable table of current module version */
+ short int vartab_len; /* (updated) length of variable table of current module version */
+ int4 labtab_off;
+ short int labtab_len;
+ int4 lnrtab_off;
+ short int lnrtab_len;
+ int4 ptext_off; /* (updated) offset to start of instructions for current module version */
+ int4 checksum;
+ uint4 compiler_qlf; /* bit flags of compiler qualifiers used (see cmd_qlf.h) */
+ int4 old_rhead_off;
+ int4 current_rhead_off; /* (updated) offset to routine header of current module version */
+ short int temp_mvals; /* (updated) temp_mvals value of current module version */
+ unsigned short temp_size; /* (updated) temp_size value of current module version */
+#ifdef HAS_LITERAL_SECT
+ int4 *linkage_ptr; /* (updated) address of linkage Psect of current module version */
+ unsigned char *literal_ptr; /* (updated) address of literal Psect of current module version */
+#endif
+} rhdtyp;
+
+/* Although the names change from _ptr to _off is politically correct, (they ARE offsets, not pointers),
+ * there is a lot of old code, espcially platform dependent code, that still deals with _ptr that we
+ * do not wish to change at this time. Provide some translations for those entries to the proper ones.
+*/
+#define vartab_ptr vartab_off
+#define labtab_ptr labtab_off
+#define lnrtab_ptr lnrtab_off
+#define ptext_ptr ptext_off
+#define old_rhead_ptr old_rhead_off
+#define current_rhead_ptr current_rhead_off
+
+/* Macros for accessing routine header fields in a portable way */
+#define VARTAB_ADR(rtnhdr) ((var_tabent *)((char *)(rtnhdr) + (rtnhdr)->vartab_off))
+#define LABTAB_ADR(rtnhdr) ((lab_tabent *)((char *)(rtnhdr) + (rtnhdr)->labtab_off))
+#define LNRTAB_ADR(rtnhdr) ((lnr_tabent *)((char *)(rtnhdr) + (rtnhdr)->lnrtab_off))
+#define LITERAL_ADR(rtnhdr) ((unsigned char *)(rtnhdr)->literal_ptr)
+#define LINKAGE_ADR(rtnhdr) ((caddr_t)(rtnhdr)->linkage_ptr)
+#define PTEXT_ADR(rtnhdr) ((unsigned char *)((char *)(rtnhdr) + (rtnhdr)->ptext_off))
+#define PTEXT_END_ADR(rtnhdr) ((unsigned char *)((char *)(rtnhdr) + (rtnhdr)->vartab_off))
+#define CURRENT_RHEAD_ADR(rtnhdr) ((rhdtyp *)((char *)(rtnhdr) + (rtnhdr)->current_rhead_off))
+#define OLD_RHEAD_ADR(rtnhdr) ((rhdtyp *)((char *)(rtnhdr) + (rtnhdr)->old_rhead_off))
+#define LINE_NUMBER_ADDR(rtnhdr, lnr_tabent_ptr) ((unsigned char *)((char *)(rtnhdr) + *(lnr_tabent_ptr)))
+#define LABENT_LNR_ENTRY(rtnhdr, lab_tabent_ptr) ((lnr_tabent *)((char *)(rtnhdr) + (lab_tabent_ptr)->lab_ln_ptr))
+#define LABEL_ADDR(rtnhdr, lab_tabent_ptr)(CODE_BASE_ADDR(rtnhdr) + *(LABENT_LNR_ENTRY(rtnhdr, lab_tabent_ptr)))
+#define CODE_BASE_ADDR(rtnhdr) ((unsigned char *)(rtnhdr))
+#define CODE_OFFSET(rtnhdr, addr) ((char *)(addr) - (char *)(rtnhdr))
+
+#define DYNAMIC_LITERALS_ENABLED(rtnhdr) FALSE
+
+/* Macro to determine if given address is inside code segment. Note that even though
+ * the PTEXT_END_ADR macro is the address of end_of_code + 1, we still want a <= check
+ * here because in many cases, the address being tested is the RETURN address from a
+ * call that was done as the last instruction in the code segment. Sometimes this call
+ * is to an error or it could be the implicit quit. On HPUX, the delay slot for the
+ * implicit quit call at the end of the module can also cause the problem. Without
+ * the "=" check also being there, the test will fail when it should succeed.
+ */
+#define ADDR_IN_CODE(caddr, rtnhdr) (PTEXT_ADR((rtnhdr)) <= (caddr) && (caddr) <= PTEXT_END_ADR((rtnhdr)))
+
+/* Types that are different across the versions */
+#define LABENT_LNR_OFFSET lab_ln_ptr
+
+/* Variable table entry */
+typedef mname_entry var_tabent; /* the actual variable name is stored in the literal text pool */
+
+/* Routine table entry */
+typedef struct
+{
+ mident rt_name; /* The name of the routine (in the literal text pool) */
+ rhdtyp *rt_adr; /* Pointer to its routine header */
+} rtn_tabent;
+
+/* Line number table entry */
+typedef int4 lnr_tabent;
+
+typedef struct
+{
+ mident lab_name; /* The name of the label */
+ int4 lab_ln_ptr; /* Offset of the lnrtab entry from the routine header */
+ boolean_t has_parms; /* Flag to indicate whether the callee has a formallist */
+} lab_tabent;
+
+/* Label table entry proxy for run-time linking */
+typedef struct
+{
+ int4 lab_ln_ptr; /* Pointer to lnrtab entry offset into code for this label */
+ boolean_t has_parms; /* Flag to indicate whether the callee has a formallist */
+} lab_tabent_proxy;
+
+/* Flag values for get_src_line call */
+#define VERIFY TRUE
+#define NOVERIFY FALSE
+
+int get_src_line(mval *routine, mval *label, int offset, mstr **srcret, boolean_t verifytrig);
+unsigned char *find_line_start(unsigned char *in_addr, rhdtyp *routine);
+int4 *find_line_addr(rhdtyp *routine, mstr *label, int4 offset, mident **lent_name);
+rhdtyp *find_rtn_hdr(mstr *name);
+bool zlput_rname(rhdtyp *hdr);
+rhdtyp *make_dmode(void);
+void comp_lits(rhdtyp *rhead);
+rhdtyp *op_rhdaddr(mval *name, rhdtyp *rhd);
+lnr_tabent *op_labaddr(rhdtyp *routine, mval *label, int4 offset);
+void urx_resolve(rhdtyp *rtn, lab_tabent *lbl_tab, lab_tabent *lbl_top);
+char *rtnlaboff2entryref(char *entryref_buff, mident *rtn, mident *lab, int offset);
+void rtn_tbl_sort(rtn_tabent *base, rtn_tabent *end);
+
+#endif /* RTNHDR_H_INCLUDED */
diff --git a/sr_vvms/runall.com b/sr_vvms/runall.com
new file mode 100644
index 0000000..e950fee
--- /dev/null
+++ b/sr_vvms/runall.com
@@ -0,0 +1,170 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2013 Fidelity Information Services, Inc !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$! p1 - comma separated set of C files (wildcards supported '*' and '%')
+$!
+$ if (p1 .eqs. "")
+$ then
+$ write sys$output ""
+$ write sys$output "Syntax : runall file1,file2,... "
+$ write sys$output ""
+$ write sys$output " where wild-cards are accepted "
+$ write sys$output ""
+$ write sys$output " e.g. runall t_end.c,gds*.c,gvcst_init.c,w*.c"
+$ write sys$output ""
+$ exit
+$ endif
+$!
+$ proc_verify = f$environment("VERIFY_PROCEDURE")
+$ image_verify = f$environment("VERIFY_IMAGE")
+$!
+$ set noverify
+$ pwd = f$environment("DEFAULT")
+$!
+$ on control_y then goto TERMINATE
+$ on severe_error then goto TERMINATE
+$ on error then goto TERMINATE
+$!
+$ minimal = f$trnlnm("minimal_build")
+$ bypass_vercheck = f$trnlnm("runall_bypass_version_check")
+$ stop_with_compile = f$trnlnm("runall_stop_with_compile")
+$!
+$ common_options := /standard=vaxc/share/assume=nowrit/float=g_float
+$ common_options := 'common_options'/warn=disable=(signedknown,signedmember)/inc=(gtm$src:,tcpip$examples:)
+$ ccdbg := cc'common_options'/define=(debug,nolicense)/debug/nooptimize
+$ ccbta := cc'common_options'/debug/nooptimize
+$ ccpro := cc'common_options'
+$!
+$ verno = f$trnlnm("gtm$verno")
+$ image = f$trnlnm("gtm$exe")
+$ img = f$extract(4,3,image)
+$!
+$ if (bypass_vercheck .eqs. "" .and. (f$extract(1,1,verno) .nes. "9" .or. f$extract(1,3,verno) .eqs. "990"))
+$ then
+$ write sys$output " "
+$ write sys$output "RUNALL-E-WRONGVERSION -- Cannot Runall Non-Developmental version :: [7m",verno,"[0m"
+$ write sys$output "Define the logical, RUNALL_BYPASS_VERSION_CHECK to bypass this check"
+$ write sys$output " "
+$ goto TERMINATE
+$ endif
+$!
+$! rebuild this which won't cause any recompilations itself but may be usable.
+$ @gtm$tools:gen_gtm_threadgbl_deftypes
+$!
+$ write sys$output ""
+$ write sys$output "---------------------------------------------------------------------------------------------------"
+$ write sys$output " **** Compiling from USER:[LIBRARY.''verno'.SRC] ------------> USER:[LIBRARY.''verno'.''img'.OBJ]"
+$ write sys$output "---------------------------------------------------------------------------------------------------"
+$ write sys$output ""
+$ len_cur = 0
+$ len_index = 0
+$ len_max = f$length(p1)
+$ offset = 0
+$!
+$ star_element = ""
+$!
+$outer_loop:
+$ element = ""
+$ cur_index = 0
+$!
+$inner_loop:
+$ if (star_element .eqs. "")
+$ then
+$ t_element = f$element(len_index,",",p1)
+$ len_index = len_index + 1
+$ if (t_element .eqs. ",") then goto end_inner_loop
+$ endif
+$!
+$ if (f$locate("*",t_element) .eqs. f$length(t_element) .and. f$locate("%",t_element) .eqs. f$length(t_element))
+$ then
+$ leaf_element = t_element
+$ else
+$ star_element = f$search(t_element,1)
+$ leaf_element = star_element
+$ endif
+$!
+$ if (leaf_element .nes. "")
+$ then
+$ leaf_element_head = f$element(0,"]",leaf_element)
+$ if (leaf_element_head .nes. leaf_element)
+$ then
+$ leaf_element_tail = f$element(1,"]",leaf_element)
+$ else
+$ leaf_element_tail = leaf_element
+$ endif
+$!
+$ leaf_element = f$element(0,";",leaf_element_tail)
+$!
+$ if (f$location(".CLD",leaf_element) .nes. f$length(leaf_element))
+$ then
+$ set def gtm$vrt:['img'.obj]
+$ write sys$output " ----> set command/object/nolist gtm$src:''leaf_element'"
+$ set command/object/nolist gtm$src:'leaf_element'
+$ set def 'pwd'
+$ else
+$ if (f$location(".MSG",leaf_element) .nes. f$length(leaf_element))
+$ then
+$ set def gtm$vrt:['img'.obj]
+$ write sys$output " ----> message object/nolist gtm$src:''leaf_element'"
+$ message /object/nolist gtm$src:'leaf_element'
+$ set def 'pwd'
+$ else
+$ if (leaf_element .nes. "SECSHR_DB_CLNUP.C" .and. leaf_element .nes. "SEC_SHR_BLK_BUILD.C")
+$ then
+$ element = element + "," + leaf_element
+$ cur_index = cur_index + 1
+$ endif
+$ endif
+$ endif
+$ endif
+$!
+$ if (cur_index .eqs. 5) then goto end_inner_loop
+$ goto inner_loop
+$!
+$end_inner_loop:
+$ if (element .nes. "")
+$ then
+$ element = element - ","
+$ set def gtm$vrt:['img'.obj]
+$ write sys$output " ----> cc''img' gtm$src:''element'"
+$ cc'img' gtm$src:'element'
+$ set def 'pwd'
+$ goto outer_loop
+$ endif
+$!
+$ write sys$output ""
+$!
+$end_outer_loop:
+$!
+$ set def gtm$vrt:['img'.obj]
+$ libr/repl mumps *.obj
+$ delete/nolog *.obj;*
+$!
+$ if (stop_with_compile .nes. "")
+$ then
+$ goto TERMINATE
+$ endif
+$!
+$ write sys$output ""
+$ write sys$output "----------------------------------------------------------------------------------"
+$ write sys$output " **** Linking and forming executables in USER:[LIBRARY.''verno'.''img']"
+$ write sys$output "----------------------------------------------------------------------------------"
+$ write sys$output ""
+$!
+$ @gtm$tools:build'img' 'verno' V72
+$!
+$ write sys$output ""
+$ write sys$output ""
+$!
+$TERMINATE:
+$ set def 'pwd'
+$ temp = f$verify(proc_verify, image_verify)
+$!
diff --git a/sr_vvms/same_device_check.c b/sr_vvms/same_device_check.c
new file mode 100644
index 0000000..3e0faf5
--- /dev/null
+++ b/sr_vvms/same_device_check.c
@@ -0,0 +1,32 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "io.h"
+
+#define TRL_OFF 4
+
+GBLREF io_pair io_curr_device; /* current device */
+
+/* This module checks whether standard and out are the same.
+In VMS, it gets the input device from the previously established GT.M structure and the output device from its caller.
+In UNIX, it ignores its arguments and gets the devices from the system designators */
+bool same_device_check(mstr tname, char buf[MAX_TRANS_NAME_LEN])
+{
+ if (io_curr_device.in->type == io_type(&tname))
+ {
+ if (io_curr_device.in->trans_name->len == tname.len - TRL_OFF &&
+ !memcmp(&io_curr_device.in->trans_name->dollar_io[0],
+ &buf[TRL_OFF], tname.len - TRL_OFF))
+ return TRUE;
+ }
+ return FALSE;
+}
diff --git a/sr_vvms/send_msg.c b/sr_vvms/send_msg.c
new file mode 100644
index 0000000..b5b21f8
--- /dev/null
+++ b/sr_vvms/send_msg.c
@@ -0,0 +1,116 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_stdio.h"
+#include <stdarg.h>
+
+#include "error.h"
+#include "fao_parm.h"
+#include "util.h"
+#include "gtmmsg.h"
+
+GBLREF bool caller_id_flag;
+
+#define NOFLUSH 0
+#define FLUSH 1
+#define RESET 2
+#define OPER 4
+
+
+
+/*
+** WARNING: For chained error messages, all messages MUST be followed by an fao count;
+** ======= zero MUST be specified if there are no parameters.
+*/
+
+/* This routine is a variation on the unix version of rts_error, and has an identical interface */
+
+void send_msg(int msg_id_arg, ...)
+{
+ va_list var;
+ int arg_count, dummy, fao_actual, fao_count, fao_list[MAX_FAO_PARMS + 1], i, msg_id;
+ char msg_buffer[1024];
+ mstr msg_string;
+ char *save_util_outptr;
+ va_list save_last_va_list_ptr;
+ boolean_t util_copy_saved = FALSE;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ VAR_START(var, msg_id_arg);
+ va_count(arg_count);
+ assert(arg_count > 0);
+ msg_id = msg_id_arg;
+ if ((NULL != TREF(util_outptr)) && (TREF(util_outptr) != TREF(util_outbuff_ptr)))
+ {
+ SAVE_UTIL_OUT_BUFFER(save_util_outptr, save_last_va_list_ptr, util_copy_saved);
+ }
+ util_out_print(NULL, RESET);
+
+ for (;;)
+ {
+ --arg_count;
+
+ msg_string.addr = msg_buffer;
+ msg_string.len = SIZEOF(msg_buffer);
+ gtm_getmsg(msg_id, &msg_string);
+
+ if (arg_count > 0)
+ {
+ fao_actual = va_arg(var, int);
+ --arg_count;
+
+ fao_count = fao_actual;
+ if (fao_count > MAX_FAO_PARMS)
+ {
+ assert(FALSE);
+ fao_count = MAX_FAO_PARMS;
+ }
+ } else
+ fao_actual = fao_count = 0;
+
+ memset(fao_list, 0, SIZEOF(fao_list));
+
+ for (i = 0; i < fao_count; ++i)
+ {
+ fao_list[i] = va_arg(var, int);
+ --arg_count;
+ }
+
+ /* Currently there are a max of 20 fao parms (MAX_FAO_PARMS) allowed, hence passing upto fao_list[19].
+ * An assert is added to ensure this code is changed whenever the macro MAX_FAO_PARMS is changed.
+ * The # of arguments passed below should change accordingly.
+ */
+ assert(MAX_FAO_PARMS == 20);
+ util_out_print(msg_string.addr, NOFLUSH, fao_list[0], fao_list[1], fao_list[2], fao_list[3], fao_list[4],
+ fao_list[5], fao_list[6], fao_list[7], fao_list[8], fao_list[9], fao_list[10], fao_list[11],
+ fao_list[12], fao_list[13], fao_list[14], fao_list[15], fao_list[16], fao_list[17],
+ fao_list[18], fao_list[19]);
+
+ if (arg_count < 1)
+ {
+ if (caller_id_flag)
+ PRINT_CALLERID;
+ break;
+ } else
+ msg_id = va_arg(var, int);
+ util_out_print("!/", NOFLUSH);
+ }
+ va_end(var);
+
+ util_out_print(NULL, OPER);
+ RESTORE_UTIL_OUT_BUFFER(save_util_outptr, save_last_va_list_ptr, util_copy_saved);
+ /* it has been suggested that this would be a place to check a view_debugN
+ * and conditionally enter a "forever" loop on wcs_sleep for unix debugging
+ */
+}
diff --git a/sr_vvms/set_jnl_file_close.c b/sr_vvms/set_jnl_file_close.c
new file mode 100644
index 0000000..babddcd
--- /dev/null
+++ b/sr_vvms/set_jnl_file_close.c
@@ -0,0 +1,135 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <lckdef.h>
+#include <psldef.h>
+#include <ssdef.h>
+#include <efndef.h>
+
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsblk.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "efn.h"
+#include "error.h"
+#include "jnl.h"
+#include "locks.h"
+#include "wcs_flu.h"
+
+GBLREF gd_region *gv_cur_region;
+GBLREF boolean_t is_src_server;
+GBLREF jnl_gbls_t jgbl;
+
+static const int4 delta_30_sec[2] = { -300000000, -1 };
+
+static void enq_timeout_ast(sgmnt_addrs *csa)
+{
+ uint4 status;
+
+ assert(0 != csa->jnl->jnllsb->lockid);
+ status = gtm_deq(csa->jnl->jnllsb->lockid, NULL, PSL$C_USER, LCK$M_CANCEL);
+ assert(SS$_NORMAL == status);
+ csa->jnl->jnllsb->lockid = 0;
+}
+
+uint4 set_jnl_file_close(set_jnl_file_close_opcode_t set_jnl_file_close_opcode)
+{
+ sgmnt_addrs *csa;
+ sgmnt_data_ptr_t csd;
+ uint4 status, jnl_status;
+ jnl_private_control *jpc;
+
+ csa = &FILE_INFO(gv_cur_region)->s_addrs;
+ csd = csa->hdr;
+ jpc = csa->jnl;
+ assert(!is_src_server); /* source server does not hold the journal lock (jpc->jnllsb) so it should never come here */
+ assert(TRUE == csa->now_crit);
+ jnl_status = jnl_ensure_open();
+ if (jnl_status)
+ rts_error(VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(gv_cur_region));
+ assert(NOJNL != jpc->channel);
+ status = sys$setimr(efn_timer, delta_30_sec, enq_timeout_ast, csa, 0);
+ if (SS$_NORMAL == status)
+ { /* Notify any active GT.M processes (via a blocking AST) that they must close the journal file */
+ csd->jnl_state = jnl_closed;
+ status = gtm_enqw(EFN$C_ENF, LCK$K_EXMODE, jpc->jnllsb, LCK$M_CONVERT | LCK$M_NODLCKBLK,
+ NULL, 0, NULL, 0, NULL, PSL$C_USER, 0);
+ if (SS$_NORMAL == status)
+ status = jpc->jnllsb->cond;
+ if (SS$_NORMAL == status)
+ { /* The cantim below also has the side effect of cancelling all pending dbsync timers, but it is
+ * fine since anyway we are going to do the dbsync timer's job, i.e. a wcs_flu() right here.
+ */
+ sys$cantim(csa, PSL$C_USER);
+ if (0 != jpc->jnllsb->lockid)
+ {
+ status = gtm_deq(jpc->jnllsb->lockid, NULL, PSL$C_USER, 0);
+ assert(SS$_NORMAL == status);
+ jpc->jnllsb->lockid = 0;
+ }
+ /* Re-enable journalling so that we can clean up */
+ csd->jnl_state = jnl_open;
+ switch (set_jnl_file_close_opcode)
+ {
+ case SET_JNL_FILE_CLOSE_EXTEND:
+ assert(0 == jpc->pini_addr);
+ /* at this point we have the new journal opened but have released the jpc->jnllsb lock.
+ * the best thing to do here is to do a gtm_enqw() of jpc->jnllsb and get that journal lock
+ * in CR mode. but since this change is going in last minute in V4.3-001, and that change involves
+ * dealing with system calls, a relatively safer but sleazy overhead method is used.
+ * We close the file here. jnl_file_extend() then re-opens the journal immediately.
+ * jnl_ensure_open() makes sure we reopen the journal file and get the jnllsb lock in the
+ * appropriate mode. This can be improved in V4.4 --- nars -- 2002/04/18
+ */
+ jnl_file_close(gv_cur_region, FALSE, FALSE);
+ /* At this point, jpc->cycle == jb->cycle (due to the jnl_ensure_open() above in this routine)
+ * although jpc->channel is NOJNL. It is desired that jnl_ensure_open() will do only a
+ * JNL_FILE_SWITCHED(jpc) check (in the future) and not the (NOJNL == jpc->channel) check.
+ * That would mean the jnl_ensure_open() done immediately after returning from here to
+ * jnl_file_extend() is going to consider there is nothing to open as the cycle numbers match.
+ * To avoid this situation, we decrement the private cycle to induce a cycle mismatch.
+ */
+ jpc->cycle--;
+ break;
+ case SET_JNL_FILE_CLOSE_RUNDOWN:
+ if (!jgbl.mur_extract)
+ {
+ if (0 == jpc->pini_addr)
+ jnl_put_jrt_pini(csa);
+ jnl_put_jrt_pfin(csa);
+ }
+ if (dba_mm == csd->acc_meth) /* this should parallel vvms/gds_rundown() */
+ sys$cantim(gv_cur_region, PSL$C_USER); /* see comment there for details. */
+ jnl_file_close(gv_cur_region, TRUE, FALSE);
+ break;
+ case SET_JNL_FILE_CLOSE_SETJNL:
+ assert(0 == jpc->pini_addr);
+ case SET_JNL_FILE_CLOSE_BACKUP:
+ if (0 == jpc->pini_addr)
+ jnl_put_jrt_pini(csa);
+ wcs_flu(WCSFLU_FLUSH_HDR | WCSFLU_WRITE_EPOCH);
+ jnl_put_jrt_pfin(csa);
+ jnl_file_close(gv_cur_region, TRUE, TRUE);
+ break;
+ default:
+ GTMASSERT;
+ }
+ }
+ }
+ assert(SS$_NORMAL == status);
+ return (status);
+}
diff --git a/sr_vvms/set_num_additional_processors.c b/sr_vvms/set_num_additional_processors.c
new file mode 100644
index 0000000..cb3637f
--- /dev/null
+++ b/sr_vvms/set_num_additional_processors.c
@@ -0,0 +1,50 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <syidef.h>
+#include <ssdef.h>
+#include <efndef.h>
+
+
+#include "vmsdtype.h"
+#include "send_msg.h"
+#include "set_num_additional_processors.h"
+
+GBLREF int num_additional_processors;
+
+void set_num_additional_processors(void)
+{
+ struct
+ {
+ item_list_3 item[1];
+ int4 terminator;
+ } item_list;
+ unsigned short iosb[4];
+ uint4 mode, status, dummy, numcpus = 1;
+ error_def(ERR_NUMPROCESSORS);
+
+ item_list.item[0].buffer_length = SIZEOF(numcpus);
+ item_list.item[0].item_code = SYI$_ACTIVECPU_CNT;
+ item_list.item[0].buffer_address = &numcpus;
+ item_list.item[0].return_length_address = &dummy;
+
+ item_list.terminator = 0;
+
+ if ((status = sys$getsyiw(EFN$C_ENF, NULL, NULL, &item_list, iosb, NULL, 0)) != SS$_NORMAL ||
+ (status = iosb[0]) != SS$_NORMAL)
+ {
+ numcpus = 1;
+ send_msg(VARLSTCNT(3) ERR_NUMPROCESSORS, 0, status);
+ }
+
+ num_additional_processors = numcpus - 1;
+}
diff --git a/sr_vvms/set_zstatus.c b/sr_vvms/set_zstatus.c
new file mode 100644
index 0000000..0379c0e
--- /dev/null
+++ b/sr_vvms/set_zstatus.c
@@ -0,0 +1,122 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2008 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include <chfdef.h>
+#include <descrip.h>
+
+#include "stringpool.h"
+#include "mlkdef.h"
+#include "zshow.h"
+#include <rtnhdr.h>
+#include "stack_frame.h"
+#include "mvalconv.h"
+#include "error_trap.h"
+#include "trans_code_cleanup.h"
+
+GBLREF mval dollar_zstatus, dollar_zerror;
+GBLREF mval dollar_ztrap, dollar_etrap;
+GBLREF spdesc rts_stringpool, stringpool;
+GBLREF stack_frame *zyerr_frame, *frame_pointer;
+GBLREF mstr *err_act;
+
+#define DSZ_BUF_SIZ 512
+
+static short zs_size;
+int put_zstatus(struct dsc$descriptor_s *txt, unsigned char *buffer);
+
+unsigned char *set_zstatus(mstr *src, struct chf$signal_array *sig, unsigned char **ctxtp, boolean_t need_rtsloc)
+{
+ unsigned char *b_line; /* beginning of line (used to restart line) */
+ mval val; /* dummy mval */
+ int4 save_sig_args, save_sig_name;
+ unsigned char zstatus_buff[DSZ_BUF_SIZ];
+ mval *status_loc;
+ boolean_t trans_frame;
+ short save_zs_size;
+ error_def(ERR_VMSMEMORY);
+
+ b_line = 0;
+ if (need_rtsloc)
+ {
+ /* get the line address of the last "known" MUMPS code that was executed. MUMPS indirection
+ * consitutes MUMPS code that is "unknown" is the sense that there is no line address for it.
+ */
+ src->len = get_symb_line((unsigned char*)src->addr, &b_line, ctxtp) - (unsigned char*)src->addr;
+ trans_frame = (!(SFT_DM & frame_pointer->type) &&
+ ((!(frame_pointer->type & SFT_COUNT || 0 == frame_pointer->type)) ||
+ (SFT_ZINTR & frame_pointer->type)));
+ if (trans_frame)
+ {
+ save_sig_name = sig->chf$l_sig_name;
+ SET_ERR_CODE(frame_pointer, sig->chf$l_sig_name);
+ }
+ } else
+ trans_frame = FALSE;
+ MV_FORCE_MVAL(&val, sig->chf$l_sig_name) ;
+ n2s(&val);
+ memcpy(zstatus_buff, val.str.addr, val.str.len);
+ zs_size = val.str.len;
+ zstatus_buff[zs_size++] = ',';
+ if (0 != b_line)
+ {
+ memcpy(&(zstatus_buff[zs_size]), src->addr, src->len);
+ zs_size += src->len;
+ }
+ save_sig_args = sig->chf$l_sig_args;
+ assert(2 < sig->chf$l_sig_args);
+ sig->chf$l_sig_args -= 2;
+ sig->chf$l_sig_args |= 0x000F0000;
+ if (trans_frame)
+ { /* currently no inserted message (sig->chf$l_sig_name) needs arguments.
+ The following code needs to be changed for any new message with arguments */
+ sys$putmsg(sig, put_zstatus, 0, zstatus_buff);
+ save_zs_size = zs_size;
+ sig->chf$l_sig_name = save_sig_name;
+ sys$putmsg(sig, put_zstatus, 0, zstatus_buff);
+ zstatus_buff[save_zs_size + 1] = '-'; /* auxiliary msgs need prefix '-' instead of '%' */
+ } else
+ sys$putmsg(sig, put_zstatus, 0, zstatus_buff);
+ sig->chf$l_sig_args = save_sig_args;
+ status_loc = (NULL == zyerr_frame) ? &dollar_zstatus : &dollar_zerror;
+ status_loc->str.len = zs_size;
+ status_loc->str.addr = zstatus_buff;
+ assert(stringpool.base == rts_stringpool.base);
+ s2pool(&status_loc->str);
+ status_loc->mvtype = MV_STR;
+ /* If this is a VMSMEMORY issue, setting the ecode is of dubious worth since we are not going
+ to drive any handlers and it can definitely be expensive in terms of memory use as ecode_add()
+ (further down the pike) is likely to load the text of the module into storage if it can. So we bypass
+ ecode setting for these two fatal errors. 02/2008 se
+ */
+ if (ERR_VMSMEMORY != sig->chf$l_sig_name)
+ ecode_set(sig->chf$l_sig_name);
+ return (b_line);
+}
+
+int put_zstatus(struct dsc$descriptor_s *txt, unsigned char *buffer)
+{
+ short msg_len;
+
+ assert(DSZ_BUF_SIZ >= zs_size);
+ msg_len = (zs_size + 1 + txt->dsc$w_length < DSZ_BUF_SIZ ? 1 + txt->dsc$w_length : DSZ_BUF_SIZ - zs_size);
+ if (msg_len)
+ {
+ *(buffer + zs_size++) = ',';
+ memcpy(buffer + zs_size, txt->dsc$a_pointer, txt->dsc$w_length);
+ zs_size += txt->dsc$w_length;
+ assert(DSZ_BUF_SIZ >= zs_size);
+ }
+ return 0; /* suppress display on SYS$OUTPUT */
+}
diff --git a/sr_vvms/setactive_silent.com b/sr_vvms/setactive_silent.com
new file mode 100644
index 0000000..60afa4f
--- /dev/null
+++ b/sr_vvms/setactive_silent.com
@@ -0,0 +1,24 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2003 Sanchez Computer Associates, Inc. !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$! same as setactive.com except that this does not print output unless "set verify" is on
+$!
+$ if f$environment("VERIFY_PROCEDURE")
+$ then
+$ ver 'p1' 'p2'
+$ else
+$ define sys$output nl:
+$ define sys$error nl:
+$ ver 'p1' 'p2'
+$ deassign sys$output
+$ deassign sys$error
+$ endif
+$!
diff --git a/sr_vvms/setfileprot.c b/sr_vvms/setfileprot.c
new file mode 100644
index 0000000..77380d9
--- /dev/null
+++ b/sr_vvms/setfileprot.c
@@ -0,0 +1,52 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* should not be called from runtime routines, otherwise, get rid of the util_out_print/gtm_putmsg */
+#include "mdef.h"
+
+#include <rms.h>
+#include "util.h"
+#include "setfileprot.h"
+#include "gtmmsg.h"
+
+boolean_t setfileprot(char *filename, int4 filelen, unsigned short mask)
+{
+ struct FAB fab;
+ struct XABPRO xabpro;
+ int4 status;
+
+ fab = cc$rms_fab;
+ xabpro = cc$rms_xabpro;
+
+ fab.fab$l_fop = FAB$M_MXV | FAB$M_CBT | FAB$M_TEF | FAB$M_CIF;
+ fab.fab$b_fac = FAB$M_GET | FAB$M_PUT | FAB$M_BIO | FAB$M_TRN;
+ fab.fab$l_xab = &xabpro;
+ fab.fab$l_fna = filename;
+ fab.fab$b_fns = filelen;
+
+ if (RMS$_NORMAL != (status = sys$open(&fab)))
+ {
+ gtm_putmsg(VARLSTCNT(1) status);
+ util_out_print("Error openning !AD", TRUE, filelen, filename);
+ return FALSE;
+ }
+
+ xabpro.xab$w_pro = mask;
+
+ if (RMS$_NORMAL != (status = sys$close(&fab)))
+ {
+ gtm_putmsg(VARLSTCNT(1) status);
+ util_out_print("Error closing !AD", TRUE, filelen, filename);
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/sr_vvms/setfileprot.h b/sr_vvms/setfileprot.h
new file mode 100644
index 0000000..51786a9
--- /dev/null
+++ b/sr_vvms/setfileprot.h
@@ -0,0 +1,17 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef SETFILEPROT_INCLUDED
+#define SETFILEPROT_INCLUDED
+
+boolean_t setfileprot(char *filename, int4 filelen, unsigned short mask);
+
+#endif /* SETFILEPROT_INCLUDED */
diff --git a/sr_vvms/setterm.c b/sr_vvms/setterm.c
new file mode 100644
index 0000000..30a5a92
--- /dev/null
+++ b/sr_vvms/setterm.c
@@ -0,0 +1,54 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <ssdef.h>
+#include <iodef.h>
+#include <efndef.h>
+
+#include "io.h"
+#include "iottdef.h"
+#include "outofband.h"
+#include "setterm.h"
+
+GBLREF int4 outofband;
+
+void resetterm(io_desc *iod)
+{
+ short iosb[4];
+ uint4 status;
+ d_tt_struct *tt_ptr;
+
+ assert(iod->type == tt);
+ if (outofband)
+ {
+ outofband_action(FALSE);
+ assert(FALSE);
+ }
+ tt_ptr = (d_tt_struct *) iod->dev_sp;
+ status = sys$qiow(EFN$C_ENF, tt_ptr->channel ,(IO$_SETMODE | IO$M_OUTBAND) ,iosb ,NULL ,0 ,0 ,0 ,0 ,0 ,0 ,0);
+ if (status == SS$_NORMAL)
+ status = iosb[0];
+ if (status != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+}
+
+void setterm(io_desc *iod)
+{
+ uint4 disable_msk, dummy_msk, status;
+
+ assert(iod->type == tt);
+ disable_msk = CTRLY_MSK;
+ status = lib$disable_ctrl(&disable_msk, &dummy_msk);
+ if (status != SS$_NORMAL)
+ rts_error(VARLSTCNT(1) status);
+ iott_resetast(iod);
+}
diff --git a/sr_vvms/sgtm_putmsg.c b/sr_vvms/sgtm_putmsg.c
new file mode 100644
index 0000000..f0b31ae
--- /dev/null
+++ b/sr_vvms/sgtm_putmsg.c
@@ -0,0 +1,108 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+
+#include "gtm_stdio.h"
+#include <stdarg.h>
+
+#include "error.h"
+#include "fao_parm.h"
+#include "util.h"
+#include "gtmmsg.h"
+#include "sgtm_putmsg.h"
+
+/*
+** WARNING: For chained error messages, all messages MUST be followed by an fao count;
+** ======= zero MUST be specified if there are no parameters.
+*/
+
+/* This routine is a variation on the unix version of rts_error, and has an identical interface */
+
+void sgtm_putmsg(char *out_str, ...)
+{
+ va_list var;
+ int arg_count, dummy, fao_actual, fao_count, fao_list[MAX_FAO_PARMS + 1], i, msg_id;
+ char msg_buffer[1024];
+ mstr msg_string;
+ int util_outbufflen;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ VAR_START(var, out_str);
+ va_count(arg_count);
+ arg_count--;
+ assert(arg_count > 0);
+ util_out_print(NULL, RESET);
+
+ for (;;)
+ {
+ msg_id = va_arg(var, int);
+ --arg_count;
+
+ msg_string.addr = msg_buffer;
+ msg_string.len = SIZEOF(msg_buffer);
+ gtm_getmsg(msg_id, &msg_string);
+
+ if (arg_count > 0)
+ {
+ fao_actual = va_arg(var, int);
+ --arg_count;
+
+ fao_count = fao_actual;
+ if (fao_count > MAX_FAO_PARMS)
+ {
+ assert(FALSE);
+ fao_count = MAX_FAO_PARMS;
+ }
+ }
+ else
+ fao_actual = fao_count
+ = 0;
+
+ memset(fao_list, 0, SIZEOF(fao_list));
+
+ for (i = 0; i < fao_count; ++i)
+ {
+ fao_list[i] = va_arg(var, int);
+ --arg_count;
+ }
+
+ /* Currently there are a max of 20 fao parms (MAX_FAO_PARMS) allowed, hence passing upto fao_list[19].
+ * An assert is added to ensure this code is changed whenever the macro MAX_FAO_PARMS is changed.
+ * The # of arguments passed below should change accordingly.
+ */
+ assert(MAX_FAO_PARMS == 20);
+ util_out_print(msg_string.addr, NOFLUSH, fao_list[0], fao_list[1], fao_list[2], fao_list[3], fao_list[4],
+ fao_list[5], fao_list[6], fao_list[7], fao_list[8], fao_list[9], fao_list[10], fao_list[11],
+ fao_list[12], fao_list[13], fao_list[14], fao_list[15], fao_list[16], fao_list[17],
+ fao_list[18], fao_list[19]);
+
+ if (arg_count < 1)
+ break;
+
+ util_out_print("!/", NOFLUSH);
+ }
+ va_end(var);
+ util_out_print(NULL, SPRINT);
+ util_outbufflen = STRLEN(TREF(util_outbuff_ptr));
+ memcpy(out_str, TREF(util_outbuff_ptr), util_outbufflen);
+ out_str[util_outbufflen] = '\n';
+ out_str[util_outbufflen + 1] = '\0';
+}
diff --git a/sr_vvms/source_file.c b/sr_vvms/source_file.c
new file mode 100644
index 0000000..75a5b63
--- /dev/null
+++ b/sr_vvms/source_file.c
@@ -0,0 +1,207 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+#include "gtm_limits.h"
+
+#include <descrip.h>
+#include <ssdef.h>
+#include <rms.h>
+#include <devdef.h>
+
+#include "compiler.h"
+#include "cmd_qlf.h"
+#include "source_file.h"
+
+GBLREF char object_file_name[];
+GBLREF char rev_time_buf[];
+GBLREF char source_file_name[];
+GBLREF unsigned char *source_buffer;
+GBLREF short object_name_len;
+GBLREF unsigned short source_name_len;
+GBLREF command_qualifier cmd_qlf;
+GBLREF mident routine_name, module_name;
+GBLREF struct FAB obj_fab; /* file access block for the object file */
+
+error_def(ERR_ERRORSUMMARY);
+error_def(ERR_FILENOTFND);
+error_def(ERR_OBJFILERR);
+error_def(ERR_SRCFILERR);
+
+static bool tt_so_do_once;
+static struct FAB fab;
+static struct RAB rab;
+
+void compile_source_file(unsigned short flen, char *faddr, boolean_t mExtReqd /* not used in VMS */)
+{
+ struct FAB srch_fab;
+ struct NAM srch_nam;
+ char exp_string_area[255], list_file[256], obj_file[256], ceprep_file[256];
+ int status;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ obj_fab = cc$rms_fab;
+ srch_fab = cc$rms_fab;
+ srch_fab.fab$l_dna = DOTM;
+ srch_fab.fab$b_dns = STR_LIT_LEN(DOTM);
+ srch_fab.fab$l_fna = faddr;
+ srch_fab.fab$b_fns = flen;
+ srch_fab.fab$l_fop |= FAB$M_NAM;
+ srch_fab.fab$l_nam = &srch_nam;
+ srch_nam = cc$rms_nam;
+ srch_nam.nam$l_rsa = source_file_name;
+ srch_nam.nam$b_rss = NAME_MAX; /* 255 since PATH_MAX is 256 on 7.3-2 */
+ srch_nam.nam$l_esa = exp_string_area;
+ srch_nam.nam$b_ess = SIZEOF(exp_string_area);
+ status = sys$parse(&srch_fab);
+ if (RMS$_NORMAL != status)
+ { dec_err(VARLSTCNT(4) ERR_SRCFILERR, 2, source_name_len, source_file_name);
+ dec_err(VARLSTCNT(1) status);
+ TREF(dollar_zcstatus) = ERR_ERRORSUMMARY;
+ } else
+ {
+ cmd_qlf.object_file.str.addr = obj_file;
+ cmd_qlf.object_file.str.len = 255;
+ cmd_qlf.list_file.str.addr = list_file;
+ cmd_qlf.list_file.str.len = 255;
+ cmd_qlf.ceprep_file.str.addr = ceprep_file;
+ cmd_qlf.ceprep_file.str.len = 255;
+ get_cmd_qlf(&cmd_qlf);
+ tt_so_do_once = FALSE;
+ for (; ;)
+ {
+ if (srch_fab.fab$l_dev & DEV$M_FOD)
+ { status = sys$search(&srch_fab);
+ if (status == RMS$_NMF )
+ { break;
+ }
+ else if (status == RMS$_FNF)
+ { dec_err(VARLSTCNT(4) ERR_FILENOTFND, 2, srch_nam.nam$b_esl, srch_nam.nam$l_esa);
+ TREF(dollar_zcstatus) = ERR_ERRORSUMMARY;
+ break;
+ }
+ else if (status != RMS$_NORMAL)
+ { dec_err(VARLSTCNT(4) ERR_SRCFILERR, 2, source_name_len, source_file_name);
+ dec_err(VARLSTCNT(1) status);
+ TREF(dollar_zcstatus) = ERR_ERRORSUMMARY;
+ break;
+ }
+ else
+ { source_name_len = srch_nam.nam$b_rsl;
+ source_file_name[source_name_len] = '\0';
+ }
+ } else
+ { source_name_len = SIZEOF("SYS$INPUT");
+ memcpy(source_file_name, "SYS$INPUT", source_name_len);
+ source_file_name[source_name_len] = '\0';
+ tt_so_do_once = TRUE;
+ }
+ if (compiler_startup())
+ TREF(dollar_zcstatus) = ERR_ERRORSUMMARY;
+ else
+ {
+ status = sys$close(&obj_fab);
+ obj_fab = cc$rms_fab;
+ if (RMS$_NORMAL != status)
+ rts_error(VARLSTCNT(6) ERR_OBJFILERR, 2, object_name_len, object_file_name, status,
+ obj_fab.fab$l_stv);
+ }
+ if (tt_so_do_once)
+ break;
+ }
+ }
+}
+
+bool open_source_file(void)
+{
+ static readonly char inprompt[] = "\015\012>";
+ struct NAM nam;
+ struct XABDAT xab;
+ char exp_name[255];
+ char *p;
+ int n;
+ int rms_status;
+ struct dsc$descriptor_s t_desc
+ = {REV_TIME_BUFF_LEN, DSC$K_DTYPE_T, DSC$K_CLASS_S, rev_time_buf};
+
+ fab = cc$rms_fab;
+ fab.fab$l_fna = source_file_name;
+ fab.fab$b_fns = source_name_len;
+ fab.fab$w_mrs = MAX_SRCLINE;
+ fab.fab$l_xab = &xab;
+ fab.fab$l_nam = &nam;
+ nam = cc$rms_nam;
+ nam.nam$l_esa = exp_name;
+ nam.nam$b_ess = SIZEOF(exp_name);
+ xab = cc$rms_xabdat;
+ rms_status = sys$open(&fab);
+ fab.fab$l_xab = 0;
+ fab.fab$l_nam = 0;
+ if (RMS$_NORMAL != rms_status)
+ {
+ dec_err(VARLSTCNT(4) ERR_SRCFILERR, 2, source_name_len, source_file_name);
+ dec_err(VARLSTCNT(1) rms_status);
+ return FALSE;
+ }
+ assert(tt_so_do_once || (source_name_len == nam.nam$b_esl && !memcmp(source_file_name, exp_name, nam.nam$b_esl)));
+ rab = cc$rms_rab;
+ rab.rab$l_fab = &fab;
+ rab.rab$l_pbf = inprompt;
+ rab.rab$b_psz = SIZEOF(inprompt) - 1;
+ rab.rab$l_rop = RAB$M_PMT;
+ rab.rab$l_ubf = source_buffer;
+ rab.rab$w_usz = MAX_SRCLINE;
+ rms_status = sys$connect(&rab);
+ if (RMS$_NORMAL != rms_status)
+ {
+ dec_err(VARLSTCNT(4) ERR_SRCFILERR, 2, source_name_len, source_file_name);
+ dec_err(VARLSTCNT(1) rms_status);
+ return FALSE;
+ }
+ sys$asctim(0,&t_desc,&xab.xab$q_rdt,0);
+ p = nam.nam$l_name ;
+ n = nam.nam$b_name ;
+ if (n > MAX_MIDENT_LEN)
+ n = MAX_MIDENT_LEN;
+ else if (!n)
+ {
+ p = "MDEFAULT";
+ n = STR_LIT_LEN("MDEFAULT");
+ }
+ memcpy(routine_name.addr, p, n);
+ memcpy(module_name.addr, p, n);
+ routine_name.len = module_name.len = n;
+ if ('_' == *p)
+ routine_name.addr[0] = '%';
+ return TRUE;
+}
+
+int4 read_source_file(void)
+{
+ int rms_status;
+
+ rms_status = sys$get(&rab);
+ if (RMS$_EOF == rms_status)
+ return -1;
+ if (RMS$_NORMAL != rms_status)
+ rts_error(VARLSTCNT(5) ERR_SRCFILERR, 2, source_name_len, source_file_name, rms_status);
+ *(rab.rab$l_ubf + rab.rab$w_rsz + 1) = *(rab.rab$l_ubf + rab.rab$w_rsz)= 0;
+ return rab.rab$w_rsz;
+}
+
+void close_source_file(void)
+{
+ sys$close(&fab);
+ return;
+}
diff --git a/sr_vvms/spawn_and_bgwait.c b/sr_vvms/spawn_and_bgwait.c
new file mode 100644
index 0000000..4923bbb
--- /dev/null
+++ b/sr_vvms/spawn_and_bgwait.c
@@ -0,0 +1,33 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <descrip.h>
+#include <ssdef.h>
+#include <clidef.h>
+
+#include "efn.h"
+
+uint4 spawn_and_bgwait(struct dsc$descriptor_s *d_cmd, struct dsc$descriptor_s *d_infile, struct dsc$descriptor_s *d_outfile,
+ uint4 *flags, struct dsc$descriptor_s *d_prcname, uint4 *pid, int4 *completion_status)
+{
+ uint4 status;
+ uint4 flags_with_nowait = CLI$M_NOWAIT;
+ unsigned char ef = efn_sys_wait;
+
+ if (flags)
+ flags_with_nowait |= *flags;
+ status = lib$spawn(d_cmd, d_infile, d_outfile, &flags_with_nowait, d_prcname, pid, completion_status, &ef);
+ if (SS$_NORMAL == status)
+ status = sys$waitfr(ef);
+ return status;
+}
diff --git a/sr_vvms/spkitbld.m b/sr_vvms/spkitbld.m
new file mode 100644
index 0000000..b4aac7d
--- /dev/null
+++ b/sr_vvms/spkitbld.m
@@ -0,0 +1,42 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ;
+; Copyright 2001, 2003 Sanchez Computer Associates, Inc. ;
+; ;
+; This source code contains the intellectual property ;
+; of its copyright holder(s), and is made available ;
+; under a license. If you do not know the terms of ;
+; the license, please stop and do not read further. ;
+; ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+spkitbld ; ; ; edit the gtm$vrt:[t%%]*_spkitbld.dat version
+ ;
+ New
+ Set cnt=0
+ New $ZTrap Set $ZTrap="Use $Principal Write !,""FAILED!!"",!,$ZStatus ZGoto "_$ZLevel_":error"
+ Set gtmvrt=$TRanslate($ZCMDLINE,""""),temp=gtmvrt_"temp.dat",mask=$Piece(gtmvrt,"]")_".t%%]*_spkitbld.dat"
+ If gtmvrt=""!(gtmvrt="/DIR") Do ;arg overrides gtm$vrt
+ . Set gtmvrt=$ZTRNLNM("gtm$vrt"),temp="gtm$vrt:[000000]temp.dat",mask="gtm$vrt:[t%%]*_spkitbld.dat"
+ Set gtmvrt=$Piece(gtmvrt,"]")
+ Set newver=$$FUNC^%ucase($Piece(gtmvrt,".",2))
+ If newver'?1"V"2N.2A1.3N.1A Write !,"Invalid version designation" Quit
+ Set newver=$Extract(newver,2,9999)
+ For tv="BL","FT" If newver[tv Set newver=$Piece(newver,tv)_$Select(tv="BL":88,1:99)_$Piece(newver,tv,2)
+ If newver?.N1.A For i=$Length(newver):-1:2 Set newver=$Extract(newver,1,i-1)_($Ascii(newver,i)#10)_$Extract(newver,i+1,9999)
+ Set file=$ZSEARCH("foo.bar") ;clear any current search
+ For Set file=$Piece($ZSEARCH(mask),";") Quit:'$l(file) Do
+ . Open file:(readonly:exception="Goto eof"),temp:newversion
+ . Use file
+ . Read line
+ . Set oldver=$Piece(line," ",3)
+ . For i=1:1:$l(oldver) Quit:$Extract(oldver,i)?1N
+ . Set prod=$Extract(oldver,1,i-1)
+ . Set $Piece(line," ",3)=prod_newver
+ . Use temp
+ . Write line,!
+ . For Use file Read line Use temp Write line,!
+eof . Close file:delete
+ . Close temp:rename=file
+ . Set cnt=cnt+1
+ Write !,"Complete"
+error Write !,"Updated ",cnt," files",!
+ Quit
diff --git a/sr_vvms/spkitupdate.com b/sr_vvms/spkitupdate.com
new file mode 100644
index 0000000..e64a338
--- /dev/null
+++ b/sr_vvms/spkitupdate.com
@@ -0,0 +1,28 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2013 Fidelity Information Services Inc !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$! spkitupdate.com p1=version
+$!
+$ vno = p1
+$ p1 = ""
+$ say = "write sys$output"
+$ gawk:=$gtm_bin:gawk.exe
+$ say "Fixing the version in packaging config files to "'vno'
+$ ver 'vno' p
+$ curr_priv = f$setprv("sysprv")
+$ gtma := $ gtm$exe:gtm$dmod.exe
+$ gtma "user:[library.''vno']"
+d ^spkitbld
+$ curr_priv=f$setprv(curr_priv)
+$ delete/nolog/since spkitbld.obj.,_ucase.obj.
+$ say "Should show the correct version"
+$ pipe gawk /commands ="/KITNAME/{printf(""%-32s\t%s\n"", FILENAME, $2);}" /field_sep=":=" gtm$vrt:[t%%]*_spkitbld.dat
+$ exit
diff --git a/sr_vvms/srm_check.com b/sr_vvms/srm_check.com
new file mode 100644
index 0000000..9ad5f37
--- /dev/null
+++ b/sr_vvms/srm_check.com
@@ -0,0 +1,29 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2003 Sanchez Computer Associates, Inc. !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$! check for invalid alpha code sequences in .exe files found in directory p1
+$!
+$ proc_verify = f$environment("VERIFY_PROCEDURE")
+$ set noverify
+$!
+$ if "" .nes. p1 then $ set def 'p1'
+$ srmck := $ sys$system:srm_check.exe
+$ exe = f$search("foo.exe") ! clear any active search list
+$loop:
+$ exe = f$search("*.exe.")
+$ if "" .nes. exe
+$ then
+$ srmck 'exe'
+$ goto loop
+$ endif
+$!
+$ temp = f$verify(proc_verify)
+$ exit
diff --git a/sr_vvms/st.mpt b/sr_vvms/st.mpt
new file mode 100644
index 0000000..faa965b
--- /dev/null
+++ b/sr_vvms/st.mpt
@@ -0,0 +1,77 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ;
+; Copyright 1989,2001 Sanchez Computer Associates, Inc. ;
+; ;
+; This source code contains the intellectual property ;
+; of its copyright holder(s), and is made available ;
+; under a license. If you do not know the terms of ;
+; the license, please stop and do not read further. ;
+; ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%ST ;GT.M %ST utility - status display
+ ;
+ n image s image=0 d work
+ q
+IMAGE n image s image=1 d work
+ q
+work n nopriv,lock,pid,access,users,ctime,group,jtype,ltime,member,procid,tname,uname,iname,i,sort,oldpriv,$zt
+ s (lock,nopriv,users)=0
+ s $zt="zg "_$zl_":ERR^%ST" u $p:ctrap=$c(3)
+ s oldpriv=$zsetprv("SYSLCK,GROUP,WORLD")
+ i '$zpriv("SYSLCK") w !,"You need SYSLCK privilege to run this program.",! d exit q
+ s access(0)="Detach",access(1)="Network",access(2)="Batch",access(3)="Local",access(4)="Dialup",access(5)="Remote"
+ s lock=$zlkid(0)
+ i lock d f s lock=$zlkid(1) q:'lock d
+ . i $extract($zgetlki(lock,"RESNAM"),1,6)="GTM$LM" s pid=$zgetlki(lock,"PID") d getjob(pid)
+ s users=users+nopriv
+ i users d header,ishow:image,ushow:'image w !!,"Total ",users," user",$s(users>1:"s.",1:"."),!
+ e w !,"No current GT.M users.",!
+ i nopriv w !,"Insufficient privileges to examine ",nopriv," process",$s(nopriv>1:"es.",1:"."),!
+exit s oldpriv=$zsetprv(oldpriv) u $p:ctrap=""
+ q
+header w !,"GT.M Mumps users on ",$$datetime($horolog),!
+ w !,"Terminal",?9,"Username",?24,"UIC",?30,"Proc. id",?39,"Access",?47,"CPU time",?61,"Login time"
+ w !,"--------",?9,"------------",?22,"-------",?30,"--------",?39,"------",?47,"-------------",?61,"------------------"
+ q
+ushow s uname="" f s uname=$order(sort(uname)) q:uname="" f i=1:1:sort(uname) d
+ . s tname=$piece(sort(uname,i),"^",1),procid=$piece(sort(uname,i),"^",2),group=$piece(sort(uname,i),"^",3)
+ . s member=$piece(sort(uname,i),"^",4),jtype=$piece(sort(uname,i),"^",5),ctime=$piece(sort(uname,i),"^",6)
+ . s ltime=$piece(sort(uname,i),"^",7)
+ . w !,tname,?9,uname,?22,group,",",member,?30,procid,?39,access(jtype),?47,ctime,?61,ltime
+ q
+ishow s iname="" f s iname=$order(sort(iname)) q:iname="" d
+ . w !,"Image : ",iname s uname="" f s uname=$order(sort(iname,uname)) q:uname="" f i=1:1:sort(iname,uname) d
+ . . s tname=$piece(sort(iname,uname,i),"^",1),procid=$piece(sort(iname,uname,i),"^",2)
+ . . s group=$piece(sort(iname,uname,i),"^",3),member=$piece(sort(iname,uname,i),"^",4)
+ . . s jtype=$piece(sort(iname,uname,i),"^",5),ctime=$piece(sort(iname,uname,i),"^",6)
+ . . s ltime=$piece(sort(iname,uname,i),"^",7)
+ . . w !,tname,?9,uname,?22,group,",",member,?30,procid,?39,access(jtype),?47,ctime,?61,ltime
+ . w !
+ q
+getjob(pid)
+ n $zt
+ s $zt="g blindpid"
+ s procid=$$FUNC^%DH(pid,8),tname=$zgetjpi(pid,"terminal"),uname=$zgetjpi(pid,"USERNAME")
+ s group=$$FUNC^%DO($zgetjpi(pid,"grp"),3),member=$$FUNC^%DO($zgetjpi(pid,"mem"),3),jtype=$zgetjpi(pid,"JOBTYPE")
+ s ltime=$$datetime($zgetjpi(pid,"logintim")),ctime=$$cputime($zgetjpi(pid,"CPUTIM"))
+ i image s iname=$zgetjpi(pid,"IMAGNAME"),i=$get(sort(iname,uname))+1,sort(iname,uname)=i
+ i s sort(iname,uname,i)=tname_"^"_procid_"^"_group_"^"_member_"^"_jtype_"^"_ctime_"^"_ltime_"^"_iname
+ e s i=$get(sort(uname))+1,sort(uname)=i,sort(uname,i)=tname_"^"_procid_"^"_group_"^"_member_"^"_jtype_"^"_ctime_"^"_ltime
+ s users=users+1
+ q
+datetime(horolog)
+ q $zdate(horolog,"DD-MON-YY 24:60:SS","Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec")
+ ;
+cputime(s)
+ n T,S,M,H,D
+ s T=s#100,s=s\100 s:$length(T)=1 T="0"_T
+ s S=s#60,s=s\60 s:$length(S)=1 S="0"_S
+ s M=s#60,s=s\60 s:$length(M)=1 M="0"_M
+ s H=s#24,D=s\24 s:$length(H)=1 H="0"_H
+ q D_" "_H_":"_M_":"_S_"."_T
+ ;
+blindpid
+ i $zs["NOPRIV" s nopriv=nopriv+1 q
+ERR w !,"lock = ",lock,!
+ w !,$p($zs,",",2,99),! u $p:ctrap="" s:$d(oldpriv) oldpriv=$zsetprv(oldpriv)
+ q
diff --git a/sr_vvms/std_dev_outbndset.c b/sr_vvms/std_dev_outbndset.c
new file mode 100644
index 0000000..e837b60
--- /dev/null
+++ b/sr_vvms/std_dev_outbndset.c
@@ -0,0 +1,52 @@
+/****************************************************************
+ * *
+ * Copyright 2001,2011 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "io.h"
+#include "iottdef.h"
+#include "outofband.h"
+#include "deferred_events.h"
+#include "std_dev_outbndset.h"
+
+GBLREF volatile io_pair io_std_device;
+GBLREF volatile int4 spc_inp_prc;
+GBLREF volatile bool ctrlu_occurred;
+GBLREF volatile bool std_dev_outbnd;
+
+/* NOTE: xfer_set_handlers() returns success or failure for attempts to set
+ * xfer_table. That value is not currently used here, hence the
+ * cast to void.
+ */
+
+void std_dev_outbndset(int4 ob_char)
+{
+ uint4 mask;
+ d_tt_struct *tt_ptr;
+
+ if (MAXOUTOFBAND < ob_char)
+ GTMASSERT;
+ else if (tt == io_std_device.in->type)
+ {
+ tt_ptr = (d_tt_struct *)io_std_device.in->dev_sp;
+ std_dev_outbnd = TRUE;
+ mask = SHFT_MSK << ob_char;
+ if (mask & tt_ptr->enbld_outofbands.mask)
+ (void)xfer_set_handlers(outofband_event, &ctrap_set, ob_char);
+ else if (mask & CTRLC_MSK)
+ (void)xfer_set_handlers(outofband_event, &ctrlc_set, 0);
+ else if (mask & CTRLY_MSK)
+ (void)xfer_set_handlers(outofband_event, &ctrly_set, 0);
+ else if ((ob_char == CTRL_U) && (spc_inp_prc & (SHFT_MSK << CTRL_U)))
+ ctrlu_occurred = TRUE;
+ else
+ GTMASSERT;
+ }
+}
diff --git a/sr_vvms/stpimg.m b/sr_vvms/stpimg.m
new file mode 100644
index 0000000..9b70425
--- /dev/null
+++ b/sr_vvms/stpimg.m
@@ -0,0 +1,22 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ;
+; Copyright 1991, 2002 Sanchez Computer Associates, Inc. ;
+; ;
+; This source code contains the intellectual property ;
+; of its copyright holder(s), and is made available ;
+; under a license. If you do not know the terms of ;
+; the license, please stop and do not read further. ;
+; ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+stpimg ; stpimg is takes parameters passed to GT.M by the invoking CLI and
+ ; passes them to ^PID which tries to stop all processes running a
+ ; given image.
+ ; P1 is the image name
+ ; P2 is the number of second to wait after issuing a FORCEX before
+ ; using a DELPRC against a process which doesn't leave the image
+ ;
+ n image,$zt
+ s image=$p($zcmdline," ")
+ i '$l(image) w "Invoked with no image name" q
+ d STPIMG^PID(image,+$p($zcmdline," ",2))
+ q
diff --git a/sr_vvms/term_setup.c b/sr_vvms/term_setup.c
new file mode 100644
index 0000000..d1bfe98
--- /dev/null
+++ b/sr_vvms/term_setup.c
@@ -0,0 +1,45 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <ssdef.h>
+#include <iodef.h>
+#include "io.h"
+#include "iottdef.h"
+#include "efn.h"
+#include "outofband.h"
+#include "term_setup.h"
+
+GBLREF int4 outofband; /* enumerated:ctrap,ctrlc or ctrly */
+GBLREF int4 std_dev_outofband_msk;
+GBLREF io_pair io_std_device; /* standard device */
+
+GBLDEF bool ctrlc_on; /* whether ctrlc trap enabled */
+
+void term_setup(bool ctrlc_enable)
+
+{
+ uint4 status;
+ io_terminator outofbands;
+
+ status = sys$clref(efn_outofband);
+ assert(status == SS$_WASSET || status == SS$_WASCLR);
+ outofband = 0;
+
+ if (io_std_device.in->type == tt)
+ {
+ ctrlc_on = ctrlc_enable ;
+ if (ctrlc_on)
+ std_dev_outofband_msk |= CTRLC_MSK;
+ iott_resetast(io_std_device.in);
+ }else
+ ctrlc_on = FALSE;
+}
diff --git a/sr_vvms/timedef.h b/sr_vvms/timedef.h
new file mode 100644
index 0000000..42de8d0
--- /dev/null
+++ b/sr_vvms/timedef.h
@@ -0,0 +1,24 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+typedef struct
+{
+ int4 mask1;
+ int4 mask2;
+}quad_mask;
+
+#define quadgtr(a,b) (a[1] > b[1] || a[1] == b[1] && a[0] > b[0])
+#define time_low(t) ((t % 430) * 10000000) /* time in 100 nanosecond intervals */
+#define time_high(t) (t / 430)
+ /* Convert time in msecs. to Quadword Hi and Low */
+#define time_low_ms(t) ((t % 429496) * 10000)
+#define time_high_ms(t) (t / 429496)
+#define status_normal(a) ((norm_stat = (a)) == SS$_NORMAL ? TRUE : rts_error(norm_stat))
diff --git a/sr_vvms/timersp.h b/sr_vvms/timersp.h
new file mode 100644
index 0000000..f275900
--- /dev/null
+++ b/sr_vvms/timersp.h
@@ -0,0 +1,22 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef TIMERSP_included
+#define TIMERSP_included
+
+#define TIMER_SCALE -10000 /* 100 nanoseconds / millisecond (delta time representations are negative) */
+
+/* These values are used during file creation but may be changed on the fly */
+#define TIM_FLU_MOD_BG (1000 * TIMER_SCALE) /* 1 sec */
+#define TIM_FLU_MOD_MM (30000 * TIMER_SCALE) /* 30 sec - longer since is a full sync */
+#define TIM_AST_WAIT (5 * TIMER_SCALE) /* 5 msec */
+
+#endif /*TIMERSP_included */
diff --git a/sr_vvms/trans_log_name.c b/sr_vvms/trans_log_name.c
new file mode 100644
index 0000000..4b096b8
--- /dev/null
+++ b/sr_vvms/trans_log_name.c
@@ -0,0 +1,134 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <descrip.h>
+#include <lnmdef.h>
+#include <ssdef.h>
+
+#include "io.h"
+#include "iottdef.h"
+#include "trans_log_name.h"
+
+static $DESCRIPTOR(tables,"LNM$FILE_DEV");
+static $DESCRIPTOR(lognam,"");
+static $DESCRIPTOR(colon,":");
+static $DESCRIPTOR(src_str,"");
+static uint4 attr = LNM$M_CASE_BLIND;
+
+#define TRL_SZ 3
+#define MAX_TRAN_DEPTH 10
+
+int4 trans_log_name(mstr *log, mstr *trans, char *buffer)
+/* 1st arg: logical name */
+/* 2nd arg: translated name */
+{
+ item_list_struct trl_list[TRL_SZ];
+ char buff1[MAX_TRANS_NAME_LEN], buff2[MAX_TRANS_NAME_LEN], tail_buff[MAX_TRANS_NAME_LEN];
+ char *temp_buffer, *tail_ptr;
+ int4 status, max_index, x, new_pos;
+ uint4 attr_mask, pos, tail_len;
+ unsigned short ret_len, pass;
+
+ error_def(ERR_INVSTRLEN);
+
+ if (MAX_TRANS_NAME_LEN < log->len)
+ rts_error(VARLSTCNT(4) ERR_INVSTRLEN, 2, log->len, MAX_TRANS_NAME_LEN);
+ trl_list[0].buf_len = SIZEOF(attr_mask);
+ trl_list[0].item_code = LNM$_ATTRIBUTES;
+ trl_list[0].addr = &attr_mask;
+ trl_list[0].ret_addr = &ret_len;
+ trl_list[1].buf_len = MAX_TRANS_NAME_LEN;
+ trl_list[1].item_code = LNM$_STRING;
+ trl_list[1].addr = buff1;
+ trl_list[1].ret_addr = &ret_len;
+ trl_list[2].buf_len = 0;
+ trl_list[2].item_code = 0;
+
+ src_str.dsc$a_pointer = log->addr;
+ src_str.dsc$w_length = log->len;
+
+ tail_ptr = &tail_buff[MAX_TRANS_NAME_LEN];
+ tail_len = 0;
+
+ for (pass = 0; ;pass++)
+ {
+ ret_len = 0;
+ attr_mask = 0;
+ pos = lib$locc(&colon,&src_str);
+ if (pos != 0 && pos != log->len)
+ {
+ tail_len += src_str.dsc$w_length - pos;
+ if (tail_len > MAX_TRANS_NAME_LEN)
+ rts_error(VARLSTCNT(4) ERR_INVSTRLEN, 2, tail_len, MAX_TRANS_NAME_LEN);
+ tail_ptr -= src_str.dsc$w_length - pos;
+ memcpy(tail_ptr, src_str.dsc$a_pointer + pos, src_str.dsc$w_length - pos);
+ src_str.dsc$w_length = pos - 1;
+ } else
+ pos = 0;
+ status = sys$trnlnm(&attr ,&tables ,&src_str,0,trl_list);
+ if ((status & 1) || (status == SS$_NOLOGNAM && pass))
+ {
+ if (attr_mask & LNM$M_TERMINAL)
+ {
+ memcpy(buffer, trl_list[1].addr, ret_len);
+ trans->addr = buffer;
+ trans->len = ret_len;
+ if (tail_len)
+ {
+ if (tail_len + trans->len > MAX_TRANS_NAME_LEN)
+ rts_error(VARLSTCNT(4) ERR_INVSTRLEN, 2, tail_len, MAX_TRANS_NAME_LEN);
+ memcpy(trans->addr + trans->len, tail_ptr, tail_len);
+ trans->len += tail_len;
+ }
+ /* Null-terminate returned string (even though an mstr), as this is relied upon
+ * by callers who do ATOI etc. directly on the return string.
+ */
+ trans->addr[trans->len] = '\0';
+ return (SS$_NORMAL);
+ }
+ if (status == SS$_NOLOGNAM || pass > MAX_TRAN_DEPTH)
+ {
+ memcpy(buffer, src_str.dsc$a_pointer, src_str.dsc$w_length);
+ trans->addr = buffer;
+ trans->len = src_str.dsc$w_length;
+ if (pos)
+ {
+ if (trans->len + 1 > MAX_TRANS_NAME_LEN)
+ rts_error(VARLSTCNT(4) ERR_INVSTRLEN, 2, trans->len + 1, MAX_TRANS_NAME_LEN);
+ *((unsigned char *) trans->addr + trans->len) = ':';
+ trans->len++;
+ }
+ if (tail_len)
+ {
+ if (tail_len + trans->len > MAX_TRANS_NAME_LEN)
+ rts_error(VARLSTCNT(4) ERR_INVSTRLEN, 2, tail_len + trans->len, MAX_TRANS_NAME_LEN);
+ memcpy(trans->addr + trans->len, tail_ptr, tail_len);
+ trans->len += tail_len;
+ }
+ /* Null-terminate returned string (even though an mstr), as this is relied upon
+ * by callers who do ATOI etc. directly on the return string.
+ */
+ trans->addr[trans->len] = '\0';
+ return (SS$_NORMAL);
+ }
+ temp_buffer = pass ? src_str.dsc$a_pointer : buff2;
+ src_str.dsc$a_pointer = trl_list[1].addr;
+ src_str.dsc$w_length = ret_len;
+ trl_list[1].addr = temp_buffer;
+ } else
+ { trans->addr = 0;
+ trans->len = 0;
+ return(status);
+ }
+ }
+}
diff --git a/sr_vvms/ttt.c b/sr_vvms/ttt.c
new file mode 100644
index 0000000..83e0ae3
--- /dev/null
+++ b/sr_vvms/ttt.c
@@ -0,0 +1,695 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "vxi.h"
+#include "vxt.h"
+#include "xfer_enum.h"
+LITDEF short ttt[4203] = {
+
+/* 0 */ 0,0,0,0,322,3463,2919,566,
+/* 8 */ 2297,2904,2934,1978,418,3413,2099,3035,
+/* 16 */ 2176,2167,3646,3683,2140,2149,2215,2161,
+/* 24 */ 2206,2185,2122,786,801,813,825,864,
+/* 32 */ 882,903,932,962,977,992,1010,3020,
+/* 40 */ 1082,1115,1151,1217,1268,1565,1598,1613,
+/* 48 */ 1643,1709,1739,1763,1826,1847,1862,3478,
+/* 56 */ 3500,0,0,0,0,581,0,522,
+/* 64 */ 0,1964,0,3006,0,0,0,0,
+/* 72 */ 0,0,354,430,2275,2281,2696,2723,
+/* 80 */ 2741,2844,2782,2773,2859,3552,3636,2955,
+/* 88 */ 0,2985,3101,3064,3049,3079,3427,3277,
+/* 96 */ 3558,3570,3585,3609,3618,3603,3594,3312,
+/* 104 */ 3679,3692,3714,3751,3763,3784,3808,3874,
+/* 112 */ 0,0,2892,2257,3153,4152,660,4155,
+/* 120 */ 714,2753,3119,536,542,4158,2360,2447,
+/* 128 */ 2347,489,2383,2467,2131,2405,2477,4161,
+/* 136 */ 2242,2233,4165,1286,4166,350,346,3301,
+/* 144 */ 442,4170,4173,4176,2971,4179,4182,4185,
+/* 152 */ 4188,4191,4194,3449,0,2868,2536,2514,
+/* 160 */ 1526,2505,2293,2113,2819,1999,739,2809,
+/* 168 */ 0,0,2312,3627,3655,1490,3579,2395,
+/* 176 */ 1992,551,3775,1811,2224,1202,337,3105,
+/* 184 */ 623,692,604,670,3739,1130,3707,2948,
+/* 192 */ 2251,2883,2962,642,1022,2823,4197,2457,
+/* 200 */ 3826,3844,3859,513,2838,3097,1925,3895,
+/* 208 */ 3886,1304,3441,595,1628,1697,2420,4200,
+/* 216 */ 3512,2493,748,843,3136,3667,3536,3522,
+/* 224 */ 3529,3518,724,917,2370,1064,2334,1052,
+/* 232 */ 2194,1037,1097,2432,1460,1403,1388,1442,
+/* 240 */ 1358,1370,1415,1343,1427,1475,769,3399,
+/* 248 */ 0,941,950,3256,1838,3235,2321,3931,
+/* 256 */ 3901,3907,3919,3941,1241,1253,1175,1187,
+/* 264 */ 1229,3490,1673,1910,0,1316,1502,1547,
+/* 272 */ 3333,1580,1658,1685,1796,1775,3375,1721,
+/* 280 */ 3354,1892,0,0,1952,3964,1874,3163,
+/* 288 */ 3175,3187,3199,2732,2747,1514,453,1331,
+/* 296 */ 0,651,3211,3223,0,3955,0,0,
+/* 304 */ 0,0,3730,3976,3987,3999,4008,4022,
+/* 312 */ 4035,4045,4062,4071,4080,4092,4104,4116,
+/* 320 */ 4131,4143,VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,
+/* 328 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_add,
+/* 336 */ VXT_END,
+/* 337 */ VXT_IREPL,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_bindparm,
+/* 345 */ VXT_END,
+/* 346 */ VXI_INCL,VXT_VAL,1,VXT_END,
+/* 350 */ VXI_CLRL,VXT_VAL,0,VXT_END,
+/* 354 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_break,VXT_END,
+/* 358 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callb,VXI_BRB,VXT_JMP,
+/* 366 */ 1,VXT_END,
+/* 368 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_calll,VXI_JMP,VXT_JMP,
+/* 376 */ 1,VXT_END,
+/* 378 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callw,VXI_BRW,VXT_JMP,
+/* 386 */ 1,VXT_END,
+/* 388 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callspb,VXI_BRB,VXT_JMP,
+/* 396 */ 1,VXT_END,
+/* 398 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callspl,VXI_JMP,VXT_JMP,
+/* 406 */ 1,VXT_END,
+/* 408 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callspw,VXI_BRW,VXT_JMP,
+/* 416 */ 1,VXT_END,
+/* 418 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL,
+/* 426 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_cat,VXT_END,
+/* 430 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 438 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_close,VXT_END,
+/* 442 */ VXI_BICB2,VXT_LIT,1,VXT_REG,0x5A,VXI_CALLS,VXT_LIT,0,
+/* 450 */ VXT_XFER,SIZEOF(char *) * (short int)xf_dt_false,VXT_END,
+/* 453 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_clralsvars,
+/* 461 */ VXT_END,
+/* 462 */ VXI_TSTL,VXT_VAL,1,VXT_END,
+/* 466 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_mval2bool,
+/* 474 */ VXT_END,
+/* 475 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_mval2mint,
+/* 483 */ VXI_MOVL,VXT_REG,0x50,VXT_VAL,0,VXT_END,
+/* 489 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
+/* 497 */ SIZEOF(char *) * (short int)xf_commarg,VXT_END,
+/* 499 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x50,VXI_MOVL,VXT_VAL,1,
+/* 507 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_mint2mval,VXT_END,
+/* 513 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_mval2num,
+/* 521 */ VXT_END,
+/* 522 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2,
+/* 530 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_contain,VXT_END,
+/* 536 */ VXI_MOVL,VXT_REG,0x6C,VXT_ADDR,0,VXT_END,
+/* 542 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_currtn,
+/* 550 */ VXT_END,
+/* 551 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,
+/* 559 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_cvtparm,VXT_END,
+/* 566 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 574 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_div,VXT_END,
+/* 581 */ VXI_MOVAB,VXT_VAL,2,VXT_REG,0x51,VXI_MOVAB,VXT_VAL,1,
+/* 589 */ VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_equ,VXT_END,
+/* 595 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_equnul,
+/* 603 */ VXT_END,
+/* 604 */ VXT_IREPAB,VXT_VAL,5,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
+/* 612 */ 3,VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_LIT,0,VXI_JSB,
+/* 620 */ VXT_XFER,SIZEOF(char *) * (short int)xf_exfun,VXT_END,
+/* 623 */ VXT_IREPAB,VXT_VAL,5,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
+/* 631 */ 3,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_JSB,
+/* 639 */ VXT_XFER,SIZEOF(char *) * (short int)xf_exfun,VXT_END,
+/* 642 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_exfunret,
+/* 650 */ VXT_END,
+/* 651 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_exfunretals,
+/* 659 */ VXT_END,
+/* 660 */ VXI_PUSHAB,VXT_GREF,2,VXI_PUSHAB,VXT_GREF,1,VXI_JSB,VXT_XFER,
+/* 668 */ SIZEOF(char *) * (short int)xf_extcall,VXT_END,
+/* 670 */ VXT_IREPAB,VXT_VAL,5,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
+/* 678 */ 3,VXI_PUSHL,VXT_LIT,0,VXI_PUSHAB,VXT_GREF,2,VXI_PUSHAB,
+/* 686 */ VXT_GREF,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_extexfun,VXT_END,
+/* 692 */ VXT_IREPAB,VXT_VAL,5,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
+/* 700 */ 3,VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_GREF,2,VXI_PUSHAB,
+/* 708 */ VXT_GREF,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_extexfun,VXT_END,
+/* 714 */ VXI_PUSHAB,VXT_GREF,2,VXI_PUSHAB,VXT_GREF,1,VXI_JSB,VXT_XFER,
+/* 722 */ SIZEOF(char *) * (short int)xf_extjmp,VXT_END,
+/* 724 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 732 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_exp,VXT_END,
+/* 739 */ VXT_IREPL,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fetch,
+/* 747 */ VXT_END,
+/* 748 */ VXT_IREPAB,VXT_VAL,5,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
+/* 756 */ 3,VXI_PUSHAB,VXT_GREF,2,VXI_PUSHL,VXT_LIT,0,VXI_CALLS,
+/* 764 */ VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnfgncal,VXT_END,
+/* 769 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 777 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fgnlookup,VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,
+/* 785 */ VXT_END,
+/* 786 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL,
+/* 794 */ 2,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnascii,VXT_END,
+/* 801 */ VXT_IREPL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL,
+/* 809 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnchar,VXT_END,
+/* 813 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 821 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fndata,VXT_END,
+/* 825 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL,
+/* 833 */ 2,VXI_PUSHL,VXT_VAL,3,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 841 */ SIZEOF(char *) * (short int)xf_fnextract,VXT_END,
+/* 843 */ VXT_IREPAB,VXT_VAL,5,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
+/* 851 */ 3,VXI_PUSHAB,VXT_GREF,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,
+/* 859 */ VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnfgncal,VXT_END,
+/* 864 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
+/* 872 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 880 */ SIZEOF(char *) * (short int)xf_fnfind,VXT_END,
+/* 882 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
+/* 890 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
+/* 898 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnfnumber,VXT_END,
+/* 903 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_MOVAB,VXT_VAL,0,
+/* 911 */ VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_fnget,VXT_END,
+/* 917 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 925 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnget2,VXT_END,
+/* 932 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fngvget,
+/* 940 */ VXT_END,
+/* 941 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fngvget1,
+/* 949 */ VXT_END,
+/* 950 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 958 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnget1,VXT_END,
+/* 962 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 970 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnincr,VXT_END,
+/* 977 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 985 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnj2,VXT_END,
+/* 992 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
+/* 1000 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 1008 */ SIZEOF(char *) * (short int)xf_fnj3,VXT_END,
+/* 1010 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1018 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnlength,VXT_END,
+/* 1022 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1030 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnlvname,VXT_END,
+/* 1037 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,
+/* 1045 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnlvnameo2,VXT_END,
+/* 1052 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1060 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnlvprvname,VXT_END,
+/* 1064 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL,
+/* 1072 */ 3,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL,2,VXT_XFER,
+/* 1080 */ SIZEOF(char *) * (short int)xf_fnname,VXT_END,
+/* 1082 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1090 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnnext,VXT_END,
+/* 1097 */ VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,
+/* 1105 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 1113 */ SIZEOF(char *) * (short int)xf_fno2,VXT_END,
+/* 1115 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1123 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnorder,VXT_END,
+/* 1130 */ VXI_PUSHL,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,
+/* 1138 */ 3,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
+/* 1146 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnp1,VXT_END,
+/* 1151 */ VXI_PUSHL,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,
+/* 1159 */ 4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,
+/* 1167 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,6,VXT_XFER,SIZEOF(char *) * (short int)xf_fnpiece,VXT_END,
+/* 1175 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1183 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnqlength,VXT_END,
+/* 1187 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1195 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnqsubscript,VXT_END,
+/* 1202 */ VXT_IREPAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1210 */ 0,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnquery,VXT_END,
+/* 1217 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1225 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnrandom,VXT_END,
+/* 1229 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1237 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnreverse,VXT_END,
+/* 1241 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1249 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnstack1,VXT_END,
+/* 1253 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,
+/* 1261 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnstack2,VXT_END,
+/* 1268 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
+/* 1276 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 1284 */ SIZEOF(char *) * (short int)xf_fntext,VXT_END,
+/* 1286 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
+/* 1294 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 1302 */ SIZEOF(char *) * (short int)xf_fntranslate,VXT_END,
+/* 1304 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL,
+/* 1312 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnview,VXT_END,
+/* 1316 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL,
+/* 1324 */ 2,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzascii,VXT_END,
+/* 1331 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1339 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzahandle,VXT_END,
+/* 1343 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
+/* 1351 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitand,VXT_END,
+/* 1358 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,
+/* 1366 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitcoun,VXT_END,
+/* 1370 */ VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1378 */ 1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 1386 */ SIZEOF(char *) * (short int)xf_fnzbitfind,VXT_END,
+/* 1388 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
+/* 1396 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitget,VXT_END,
+/* 1403 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,
+/* 1411 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitlen,VXT_END,
+/* 1415 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,
+/* 1423 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitnot,VXT_END,
+/* 1427 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
+/* 1435 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitor,VXT_END,
+/* 1442 */ VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1450 */ 1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 1458 */ SIZEOF(char *) * (short int)xf_fnzbitset,VXT_END,
+/* 1460 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
+/* 1468 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitstr,VXT_END,
+/* 1475 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
+/* 1483 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitxor,VXT_END,
+/* 1490 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL,
+/* 1498 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzcall,VXT_END,
+/* 1502 */ VXT_IREPL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL,
+/* 1510 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzchar,VXT_END,
+/* 1514 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1522 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzdata,VXT_END,
+/* 1526 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,
+/* 1534 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
+/* 1542 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzdate,VXT_END,
+/* 1547 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL,
+/* 1555 */ 2,VXI_PUSHL,VXT_VAL,3,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 1563 */ SIZEOF(char *) * (short int)xf_fnzextract,VXT_END,
+/* 1565 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1573 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzfile,VXT_END,
+/* 1580 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
+/* 1588 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 1596 */ SIZEOF(char *) * (short int)xf_fnzfind,VXT_END,
+/* 1598 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1606 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngetdvi,VXT_END,
+/* 1613 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,
+/* 1621 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngetjpi,VXT_END,
+/* 1628 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1636 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngetlki,VXT_END,
+/* 1643 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1651 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngetsyi,VXT_END,
+/* 1658 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1666 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzj2,VXT_END,
+/* 1673 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1681 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzjobexam,VXT_END,
+/* 1685 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1693 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzlength,VXT_END,
+/* 1697 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1705 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzlkid,VXT_END,
+/* 1709 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1717 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzm,VXT_END,
+/* 1721 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
+/* 1729 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 1737 */ SIZEOF(char *) * (short int)xf_fnzp1,VXT_END,
+/* 1739 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,
+/* 1747 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,
+/* 1755 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,6,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzparse,VXT_END,
+/* 1763 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1771 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpid,VXT_END,
+/* 1775 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
+/* 1783 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
+/* 1791 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpiece,VXT_END,
+/* 1796 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1804 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpopulation,VXT_END,
+/* 1811 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1819 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzprevious,VXT_END,
+/* 1826 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1834 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpriv,VXT_END,
+/* 1838 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzqgblmod,
+/* 1846 */ VXT_END,
+/* 1847 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1855 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzsearch,VXT_END,
+/* 1862 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1870 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzsetprv,VXT_END,
+/* 1874 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
+/* 1882 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 1890 */ SIZEOF(char *) * (short int)xf_fnzsubstr,VXT_END,
+/* 1892 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
+/* 1900 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 1908 */ SIZEOF(char *) * (short int)xf_fnztranslate,VXT_END,
+/* 1910 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,
+/* 1918 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzsigproc,VXT_END,
+/* 1925 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,6,VXI_PUSHAB,VXT_VAL,
+/* 1933 */ 5,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,
+/* 1941 */ VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,7,
+/* 1949 */ VXT_XFER,SIZEOF(char *) * (short int)xf_fnztrnlnm,VXT_END,
+/* 1952 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1960 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzwidth,VXT_END,
+/* 1964 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2,
+/* 1972 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_follow,VXT_END,
+/* 1978 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,1,
+/* 1986 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forcenum,VXT_END,
+/* 1992 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forchk1,VXT_END,
+/* 1999 */ VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 2007 */ 1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forinit,VXT_END,
+/* 2012 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forlcldob,VXI_BRB,VXT_JMP,
+/* 2020 */ 1,VXT_END,
+/* 2022 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forlcldol,VXI_JMP,VXT_JMP,
+/* 2030 */ 1,VXT_END,
+/* 2032 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forlcldow,VXI_BRW,VXT_JMP,
+/* 2040 */ 1,VXT_END,
+/* 2042 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_JMP,1,VXI_PUSHAB,VXT_VAL,
+/* 2050 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_JSB,
+/* 2058 */ VXT_XFER,SIZEOF(char *) * (short int)xf_forloop,VXT_END,
+/* 2061 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_JMP,1,VXI_PUSHAB,VXT_VAL,
+/* 2069 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_JSB,
+/* 2077 */ VXT_XFER,SIZEOF(char *) * (short int)xf_forloop,VXT_END,
+/* 2080 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_JMP,1,VXI_PUSHAB,VXT_VAL,
+/* 2088 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_JSB,
+/* 2096 */ VXT_XFER,SIZEOF(char *) * (short int)xf_forloop,VXT_END,
+/* 2099 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_getindx,
+/* 2107 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END,
+/* 2113 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_gettruth,
+/* 2121 */ VXT_END,
+/* 2122 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvdata,
+/* 2130 */ VXT_END,
+/* 2131 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvextnam,
+/* 2139 */ VXT_END,
+/* 2140 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvget,
+/* 2148 */ VXT_END,
+/* 2149 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT,
+/* 2157 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_gvincr,VXT_END,
+/* 2161 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_gvkill,VXT_END,
+/* 2167 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvnaked,
+/* 2175 */ VXT_END,
+/* 2176 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvname,
+/* 2184 */ VXT_END,
+/* 2185 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvnext,
+/* 2193 */ VXT_END,
+/* 2194 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,
+/* 2202 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_gvo2,VXT_END,
+/* 2206 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvorder,
+/* 2214 */ VXT_END,
+/* 2215 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvput,
+/* 2223 */ VXT_END,
+/* 2224 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvquery,
+/* 2232 */ VXT_END,
+/* 2233 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvrectarg,
+/* 2241 */ VXT_END,
+/* 2242 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvsavtarg,
+/* 2250 */ VXT_END,
+/* 2251 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_gvzwithdraw,VXT_END,
+/* 2257 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
+/* 2265 */ 3,VXI_PUSHL,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,
+/* 2273 */ SIZEOF(char *) * (short int)xf_gvzwrite,VXT_END,
+/* 2275 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_halt,VXT_END,
+/* 2281 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 2289 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_hang,VXT_END,
+/* 2293 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_hardret,VXT_END,
+/* 2297 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 2305 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_idiv,VXT_END,
+/* 2312 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_igetsrc,
+/* 2320 */ VXT_END,
+/* 2321 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 2329 */ 1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_inddevparms,VXT_END,
+/* 2334 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
+/* 2342 */ 0,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indfnname,VXT_END,
+/* 2347 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 2355 */ 1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indfun,VXT_END,
+/* 2360 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
+/* 2368 */ SIZEOF(char *) * (short int)xf_indglvn,VXT_END,
+/* 2370 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 2378 */ 0,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indincr,VXT_END,
+/* 2383 */ VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indlvadr,VXI_MOVL,VXT_REG,
+/* 2391 */ 0x50,VXT_ADDR,0,VXT_END,
+/* 2395 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
+/* 2403 */ SIZEOF(char *) * (short int)xf_indlvarg,VXT_END,
+/* 2405 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
+/* 2413 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_indname,VXT_END,
+/* 2420 */ VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indlvnamadr,VXI_MOVL,VXT_REG,
+/* 2428 */ 0x50,VXT_ADDR,0,VXT_END,
+/* 2432 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
+/* 2440 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_indo2,VXT_END,
+/* 2447 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
+/* 2455 */ SIZEOF(char *) * (short int)xf_indpat,VXT_END,
+/* 2457 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
+/* 2465 */ SIZEOF(char *) * (short int)xf_indrzshow,VXT_END,
+/* 2467 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
+/* 2475 */ SIZEOF(char *) * (short int)xf_indset,VXT_END,
+/* 2477 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
+/* 2485 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indtext,VXT_END,
+/* 2493 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,
+/* 2501 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_iocontrol,VXT_END,
+/* 2505 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_iretmvad,
+/* 2513 */ VXT_END,
+/* 2514 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
+/* 2522 */ SIZEOF(char *) * (short int)xf_iretmval,VXT_END,
+/* 2524 */ VXI_BRB,VXT_JMP,1,VXT_END,
+/* 2528 */ VXI_JMP,VXT_JMP,1,VXT_END,
+/* 2532 */ VXI_BRW,VXT_JMP,1,VXT_END,
+/* 2536 */ VXI_JMP,VXT_VAL,1,VXT_END,
+/* 2540 */ VXI_BEQL,VXT_JMP,1,VXT_END,
+/* 2544 */ VXI_BNEQ,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END,
+/* 2551 */ VXI_BNEQ,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END,
+/* 2558 */ VXI_BGEQ,VXT_JMP,1,VXT_END,
+/* 2562 */ VXI_BLSS,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END,
+/* 2569 */ VXI_BLSS,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END,
+/* 2576 */ VXI_BGTR,VXT_JMP,1,VXT_END,
+/* 2580 */ VXI_BLEQ,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END,
+/* 2587 */ VXI_BLEQ,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END,
+/* 2594 */ VXI_BLEQ,VXT_JMP,1,VXT_END,
+/* 2598 */ VXI_BGTR,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END,
+/* 2605 */ VXI_BGTR,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END,
+/* 2612 */ VXI_BLSS,VXT_JMP,1,VXT_END,
+/* 2616 */ VXI_BGEQ,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END,
+/* 2623 */ VXI_BGEQ,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END,
+/* 2630 */ VXI_BNEQ,VXT_JMP,1,VXT_END,
+/* 2634 */ VXI_BNEQ,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END,
+/* 2641 */ VXI_BEQL,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END,
+/* 2648 */ VXI_BLBC,VXT_REG,0x5A,VXT_JMP,1,VXT_END,
+/* 2654 */ VXI_BLBS,VXT_REG,0x5A,VXT_LIT,6,VXI_JMP,VXT_JMP,1,
+/* 2662 */ VXT_END,
+/* 2663 */ VXI_BLBS,VXT_REG,0x5A,VXT_LIT,3,VXI_BRW,VXT_JMP,1,
+/* 2671 */ VXT_END,
+/* 2672 */ VXI_BLBS,VXT_REG,0x5A,VXT_JMP,1,VXT_END,
+/* 2678 */ VXI_BLBC,VXT_REG,0x5A,VXT_LIT,6,VXI_JMP,VXT_JMP,1,
+/* 2686 */ VXT_END,
+/* 2687 */ VXI_BLBC,VXT_REG,0x5A,VXT_LIT,3,VXI_BRW,VXT_JMP,1,
+/* 2695 */ VXT_END,
+/* 2696 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,7,VXI_PUSHL,VXT_VAL,
+/* 2704 */ 6,VXI_PUSHAB,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL,
+/* 2712 */ VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,
+/* 2720 */ VXT_XFER,SIZEOF(char *) * (short int)xf_job,VXT_END,
+/* 2723 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_kill,
+/* 2731 */ VXT_END,
+/* 2732 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_killalias,
+/* 2740 */ VXT_END,
+/* 2741 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_killall,VXT_END,
+/* 2747 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_killaliasall,VXT_END,
+/* 2753 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
+/* 2761 */ 3,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_labaddr,VXI_MOVL,VXT_REG,
+/* 2769 */ 0x50,VXT_ADDR,0,VXT_END,
+/* 2773 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lckdecr,
+/* 2781 */ VXT_END,
+/* 2782 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lckincr,
+/* 2790 */ VXT_END,
+/* 2791 */ VXI_MOVAB,VXT_JMP,1,VXT_ADDR,0,VXT_END,
+/* 2797 */ VXI_MOVAB,VXT_JMP,1,VXT_ADDR,0,VXT_END,
+/* 2803 */ VXI_MOVAB,VXT_JMP,1,VXT_ADDR,0,VXT_END,
+/* 2809 */ VXT_IREPL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,
+/* 2817 */ SIZEOF(char *) * (short int)xf_linefetch,VXT_END,
+/* 2819 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_linestart,VXT_END,
+/* 2823 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
+/* 2831 */ 2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lkname,VXT_END,
+/* 2838 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_lkinit,VXT_END,
+/* 2844 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
+/* 2852 */ 2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lkname,VXT_END,
+/* 2859 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lock,
+/* 2867 */ VXT_END,
+/* 2868 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
+/* 2876 */ 2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lvpatwrite,VXT_END,
+/* 2883 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lvzwithdraw,
+/* 2891 */ VXT_END,
+/* 2892 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,
+/* 2900 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_lvzwrite,VXT_END,
+/* 2904 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 2912 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_flt_mod,VXT_END,
+/* 2919 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 2927 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_mul,VXT_END,
+/* 2934 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,1,
+/* 2942 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_neg,VXT_END,
+/* 2948 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_newintrinsic,VXT_END,
+/* 2955 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_newvar,VXT_END,
+/* 2962 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_nullexp,
+/* 2970 */ VXT_END,
+/* 2971 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2,
+/* 2979 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_numcmp,VXT_END,
+/* 2985 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
+/* 2993 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
+/* 3001 */ VXT_LIT,4,VXT_XFER,SIZEOF(char *) * (short int)xf_open,VXT_END,
+/* 3006 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2,
+/* 3014 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_pattern,VXT_END,
+/* 3020 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 3028 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnpopulation,VXT_END,
+/* 3035 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_putindx,
+/* 3043 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END,
+/* 3049 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
+/* 3057 */ 0,VXI_CALLS,VXT_LIT,2,VXT_XFER,SIZEOF(char *) * (short int)xf_rdone,VXT_END,
+/* 3064 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
+/* 3072 */ 0,VXI_CALLS,VXT_LIT,2,VXT_XFER,SIZEOF(char *) * (short int)xf_read,VXT_END,
+/* 3079 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,
+/* 3087 */ 1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,3,VXT_XFER,
+/* 3095 */ SIZEOF(char *) * (short int)xf_readfl,VXT_END,
+/* 3097 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_END,
+/* 3101 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_ret,VXT_END,
+/* 3105 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVL,VXT_VAL,2,
+/* 3113 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_retarg,VXT_END,
+/* 3119 */ VXI_PUSHAB,VXT_GREF,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3127 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_rhdaddr,VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,
+/* 3135 */ VXT_END,
+/* 3136 */ VXI_PUSHL,VXT_LIT,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3144 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_rhdaddr,VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,
+/* 3152 */ VXT_END,
+/* 3153 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,
+/* 3161 */ SIZEOF(char *) * (short int)xf_rterror,VXT_END,
+/* 3163 */ VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT,
+/* 3171 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setals2als,VXT_END,
+/* 3175 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT,
+/* 3183 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setalsin2alsct,VXT_END,
+/* 3187 */ VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT,
+/* 3195 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setalsctin2als,VXT_END,
+/* 3199 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT,
+/* 3207 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setalsct2alsct,VXT_END,
+/* 3211 */ VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT,
+/* 3219 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setfnretin2als,VXT_END,
+/* 3223 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT,
+/* 3231 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setfnretin2alsct,VXT_END,
+/* 3235 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
+/* 3243 */ 2,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
+/* 3251 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setextract,VXT_END,
+/* 3256 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
+/* 3264 */ 4,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
+/* 3272 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setp1,VXT_END,
+/* 3277 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
+/* 3285 */ 3,VXI_PUSHAB,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,
+/* 3293 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,6,VXT_XFER,SIZEOF(char *) * (short int)xf_setpiece,VXT_END,
+/* 3301 */ VXI_BISB2,VXT_LIT,1,VXT_REG,0x5A,VXI_CALLS,VXT_LIT,0,
+/* 3309 */ VXT_XFER,SIZEOF(char *) * (short int)xf_dt_true,VXT_END,
+/* 3312 */ VXI_PUSHL,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
+/* 3320 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,3,VXI_CALLS,
+/* 3328 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setzbrk,VXT_END,
+/* 3333 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
+/* 3341 */ 2,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
+/* 3349 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setzextract,VXT_END,
+/* 3354 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
+/* 3362 */ 4,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
+/* 3370 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setzp1,VXT_END,
+/* 3375 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
+/* 3383 */ 3,VXI_PUSHAB,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,
+/* 3391 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,6,VXT_XFER,SIZEOF(char *) * (short int)xf_setzpiece,VXT_END,
+/* 3399 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2,
+/* 3407 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_sorts_after,VXT_END,
+/* 3413 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_srchindx,
+/* 3421 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END,
+/* 3427 */ VXI_MOVAB,VXT_VAL,2,VXT_REG,0x51,VXI_MOVAB,VXT_VAL,1,
+/* 3435 */ VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_sto,VXT_END,
+/* 3441 */ VXI_MOVC3,VXT_LIT,16,VXT_VAL,2,VXT_VAL,1,VXT_END,
+/* 3449 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_MOVAB,VXT_VAL,0,
+/* 3457 */ VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_sto,VXT_END,
+/* 3463 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 3471 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_sub,VXT_END,
+/* 3478 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3486 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_svget,VXT_END,
+/* 3490 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,
+/* 3498 */ SIZEOF(char *) * (short int)xf_psvput,VXT_END,
+/* 3500 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3508 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_svput,VXT_END,
+/* 3512 */ VXI_MOVL,VXT_REG,0x50,VXT_REG,0x5A,VXT_END,
+/* 3518 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_tcommit,VXT_END,
+/* 3522 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_trollback,VXT_END,
+/* 3529 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_trestart,VXT_END,
+/* 3536 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
+/* 3544 */ 2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_tstart,VXT_END,
+/* 3552 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_unlock,VXT_END,
+/* 3558 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3566 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_use,VXT_END,
+/* 3570 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_view,
+/* 3578 */ VXT_END,
+/* 3579 */ VXI_CMPL,VXT_VAL,1,VXT_VAL,2,VXT_END,
+/* 3585 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_write,
+/* 3593 */ VXT_END,
+/* 3594 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_wteol,
+/* 3602 */ VXT_END,
+/* 3603 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_wtff,VXT_END,
+/* 3609 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_wtone,
+/* 3617 */ VXT_END,
+/* 3618 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_wttab,
+/* 3626 */ VXT_END,
+/* 3627 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_xkill,
+/* 3635 */ VXT_END,
+/* 3636 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,
+/* 3644 */ SIZEOF(char *) * (short int)xf_xnew,VXT_END,
+/* 3646 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zallocate,
+/* 3654 */ VXT_END,
+/* 3655 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3663 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_zattach,VXT_END,
+/* 3667 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3675 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zcompile,VXT_END,
+/* 3679 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zcont,VXT_END,
+/* 3683 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zdeallocate,
+/* 3691 */ VXT_END,
+/* 3692 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 3700 */ 1,VXI_CALLS,VXT_LIT,2,VXT_XFER,SIZEOF(char *) * (short int)xf_zedit,VXT_END,
+/* 3707 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zg1,VXT_END,
+/* 3714 */ VXI_PUSHL,VXT_VAL,1,VXI_PUSHL,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,
+/* 3722 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zgoto,VXT_END,
+/* 3730 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zhalt,
+/* 3738 */ VXT_END,
+/* 3739 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3747 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zhelp,VXT_END,
+/* 3751 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3759 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zlink,VXT_END,
+/* 3763 */ VXT_IREPAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL,2,VXI_CALLS,VXT_VAL,
+/* 3771 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_zmess,VXT_END,
+/* 3775 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zprevious,
+/* 3783 */ VXT_END,
+/* 3784 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,
+/* 3792 */ 4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,
+/* 3800 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_zprint,VXT_END,
+/* 3808 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_LIT,0,VXI_PUSHL,VXT_VAL,
+/* 3816 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,3,VXT_XFER,
+/* 3824 */ SIZEOF(char *) * (short int)xf_zshow,VXT_END,
+/* 3826 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
+/* 3834 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,3,VXT_XFER,
+/* 3842 */ SIZEOF(char *) * (short int)xf_zshow,VXT_END,
+/* 3844 */ VXI_PUSHL,VXT_LIT,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3852 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zstep,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zcont,VXT_END,
+/* 3859 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3867 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zstep,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zcont,VXT_END,
+/* 3874 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3882 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_zsystem,VXT_END,
+/* 3886 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_ztcommit,
+/* 3894 */ VXT_END,
+/* 3895 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_ztstart,VXT_END,
+/* 3901 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_merge,VXT_END,
+/* 3907 */ VXI_PUSHL,VXT_LIT,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3915 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_merge_arg,VXT_END,
+/* 3919 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3927 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_merge_arg,VXT_END,
+/* 3931 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_JSB,VXT_XFER,
+/* 3939 */ SIZEOF(char *) * (short int)xf_indmerge,VXT_END,
+/* 3941 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_m_srchindx,
+/* 3949 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END,
+/* 3955 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zwritesvn,
+/* 3963 */ VXT_END,
+/* 3964 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3972 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzwrite,VXT_END,
+/* 3976 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_igetdst,VXI_MOVL,VXT_REG,0x50,
+/* 3984 */ VXT_ADDR,0,VXT_END,
+/* 3987 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3995 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_indget1,VXT_END,
+/* 3999 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_glvnpop,
+/* 4007 */ VXT_END,
+/* 4008 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_glvnslot,
+/* 4016 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END,
+/* 4022 */ VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 4030 */ 1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indsavglvn,VXT_END,
+/* 4035 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
+/* 4043 */ SIZEOF(char *) * (short int)xf_indsavlvn,VXT_END,
+/* 4045 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 4053 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_rfrshlvn,VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,
+/* 4061 */ VXT_END,
+/* 4062 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_savgvn,
+/* 4070 */ VXT_END,
+/* 4071 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_savlvn,
+/* 4079 */ VXT_END,
+/* 4080 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 4088 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_shareslot,VXT_END,
+/* 4092 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 4100 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_stoglvn,VXT_END,
+/* 4104 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 4112 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_rfrshgvn,VXT_END,
+/* 4116 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
+/* 4124 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_indfnname2,VXT_END,
+/* 4131 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,
+/* 4139 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_indget2,VXT_END,
+/* 4143 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_indmerge2,
+/* 4151 */ VXT_END,
+/* 4152 */ 358,378,368,2524,2532,2528,2791,2803,
+/* 4160 */ 2797,0,0,0,499,475,466,0,
+/* 4168 */ 0,462,2042,2080,2061,2672,2687,2678,
+/* 4176 */ 2648,2663,2654,2540,2551,2544,2630,2641,
+/* 4184 */ 2634,2576,2587,2580,2594,2605,2598,2612,
+/* 4192 */ 2623,2616,2558,2569,2562,2012,2032,2022,
+/* 4200 */ 388,408,398};
diff --git a/sr_vvms/ttt.txt b/sr_vvms/ttt.txt
new file mode 100644
index 0000000..9ce62fa
--- /dev/null
+++ b/sr_vvms/ttt.txt
@@ -0,0 +1,1008 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; ;
+; Copyright 2001, 2012 Fidelity Information Services, Inc ;
+; ;
+; This source code contains the intellectual property ;
+; of its copyright holder(s), and is made available ;
+; under a license. If you do not know the terms of ;
+; the license, please stop and do not read further. ;
+; ;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;This table defines the intermediate code (vax code) generated by an opcode.
+;It drives tttgen.m to generate ttt.c.
+;There are multiple versions of this file by platform family and
+;changes to one should trigger review and likely changes to the others.
+;The format is OC_<opcode name>:<tabs>list of vax instructions,one to a line.
+;The opcode must have a corresponding entry in opcode_def.h
+OC_ADD: pushab val.0
+ pushab val.2
+ pushab val.1
+ calls #3,xfer.xf_add
+OC_BINDPARM: irepl val.2
+ calls val.1,xfer.xf_bindparm
+OC_BOOLFINI: incl val.1
+OC_BOOLINIT: clrl val.0
+OC_BREAK: jsb xfer.xf_break
+OC_CALL-BYTE: pushl val.2
+ jsb xfer.xf_callb
+ brb jmp.1
+OC_CALL-LONG: pushl val.2
+ jsb xfer.xf_calll
+ jmp jmp.1
+OC_CALL-WORD: pushl val.2
+ jsb xfer.xf_callw
+ brw jmp.1
+OC_CALLSP-BYTE: pushl val.2
+ jsb xfer.xf_callspb
+ brb jmp.1
+OC_CALLSP-LONG: pushl val.2
+ jsb xfer.xf_callspl
+ jmp jmp.1
+OC_CALLSP-WORD: pushl val.2
+ jsb xfer.xf_callspw
+ brw jmp.1
+OC_CAT: irepab val.2
+ pushab val.0
+ calls val.1,xfer.xf_cat
+OC_CLOSE: pushab val.2
+ pushab val.1
+ calls #2,xfer.xf_close
+OC_CLRTEST: bicb2 #1,r10
+ calls #0,xfer.xf_dt_false
+OC_CLRALSVARS: pushab val.1
+ calls #1,xfer.xf_clralsvars
+OC_COBOOL-MINT: tstl val.1
+OC_COBOOL-MVAL: movab val.1,r1
+ jsb xfer.xf_mval2bool
+OC_COMINT-MVAL: movab val.1,r1
+ jsb xfer.xf_mval2mint
+ movl r0,val.0
+OC_COMMARG: pushl val.2
+ pushab val.1
+ jsb xfer.xf_commarg
+OC_COMVAL-MINT: movab val.0,r0
+ movl val.1,r1
+ jsb xfer.xf_mint2mval
+OC_CONUM: movab val.1,r1
+ jsb xfer.xf_mval2num
+OC_CONTAIN: movab val.1,r0
+ movab val.2,r1
+ jsb xfer.xf_contain
+OC_CURRHD: movl (ap),addr.0
+OC_CURRTN: movab val.0,r1
+ jsb xfer.xf_currtn
+OC_CVTPARM: pushab val.0
+ pushab val.2
+ pushl val.1
+ calls #3,xfer.xf_cvtparm
+OC_DIV: pushab val.0
+ pushab val.2
+ pushab val.1
+ calls #3,xfer.xf_div
+OC_EQU: movab val.2,r1
+ movab val.1,r0
+ jsb xfer.xf_equ
+OC_EQUNUL: movab val.1,r0
+ jsb xfer.xf_equnul
+OC_EXCAL: irepab val.5
+ pushl val.4
+ pushl val.3
+ pushl val.2
+ pushl #0
+ jsb xfer.xf_exfun
+OC_EXFUN: irepab val.5
+ pushl val.4
+ pushl val.3
+ pushl val.2
+ pushab val.0
+ jsb xfer.xf_exfun
+OC_EXFUNRET: pushab val.1
+ calls #1,xfer.xf_exfunret
+OC_EXFUNRETALS: pushab val.1
+ calls #1,xfer.xf_exfunretals
+OC_EXTCALL: pushab G^val.2
+ pushab G^val.1
+ jsb xfer.xf_extcall
+OC_EXTEXCAL: irepab val.5
+ pushl val.4
+ pushl val.3
+ pushl #0
+ pushab G^val.2
+ pushab G^val.1
+ jsb xfer.xf_extexfun
+OC_EXTEXFUN: irepab val.5
+ pushl val.4
+ pushl val.3
+ pushab val.0
+ pushab G^val.2
+ pushab G^val.1
+ jsb xfer.xf_extexfun
+OC_EXTJMP: pushab G^val.2
+ pushab G^val.1
+ jsb xfer.xf_extjmp
+OC_EXP: pushab val.0
+ pushab val.2
+ pushab val.1
+ calls #3,xfer.xf_exp
+OC_FETCH: irepl val.2
+ calls val.1,xfer.xf_fetch
+OC_FGNCAL: irepab val.5
+ pushl val.4
+ pushl val.3
+ pushab G^val.2
+ pushl #0
+ calls val.1,xfer.xf_fnfgncal
+OC_FGNLOOKUP: pushab val.2
+ pushab val.1
+ calls #2,xfer.xf_fgnlookup
+ movl r0,addr.0
+OC_FNASCII: pushab val.0
+ pushab val.1
+ pushl val.2
+ calls #3,xfer.xf_fnascii
+OC_FNCHAR: irepl val.2
+ pushab val.0
+ calls val.1,xfer.xf_fnchar
+OC_FNDATA: pushab val.0
+ pushab val.1
+ calls #2,xfer.xf_fndata
+OC_FNEXTRACT: pushab val.0
+ pushab val.1
+ pushl val.2
+ pushl val.3
+ calls #4,xfer.xf_fnextract
+OC_FNFGNCAL: irepab val.5
+ pushl val.4
+ pushl val.3
+ pushab G^val.2
+ pushab val.0
+ calls val.1,xfer.xf_fnfgncal
+OC_FNFIND: pushab val.0
+ pushl val.3
+ pushab val.2
+ pushab val.1
+ calls #4,xfer.xf_fnfind
+OC_FNFNUMBER: pushab val.0
+ pushl val.4
+ pushl val.3
+ pushab val.2
+ pushab val.1
+ calls #5,xfer.xf_fnfnumber
+OC_FNGET: movab val.1,r1
+ movab val.0,r0
+ jsb xfer.xf_fnget
+OC_FNGET2: pushab val.0
+ pushab val.2
+ pushab val.1
+ calls #3,xfer.xf_fnget2
+OC_FNGVGET: pushab val.0
+ calls #1,xfer.xf_fngvget
+OC_FNGVGET1: pushab val.0
+ calls #1,xfer.xf_fngvget1
+OC_FNGET1: pushab val.0
+ pushab val.1
+ calls #2,xfer.xf_fnget1
+OC_FNINCR: pushab val.0 ; result of $INCR
+ pushab val.2 ; r->operand[1] = increment
+ pushab val.1 ; r->operand[0] = local-variable to increment
+ calls #3,xfer.xf_fnincr
+OC_FNJ2: pushab val.0
+ pushl val.2
+ pushab val.1
+ calls #3,xfer.xf_fnj2
+OC_FNJ3: pushab val.0
+ pushl val.3
+ pushl val.2
+ pushab val.1
+ calls #4,xfer.xf_fnj3
+OC_FNLENGTH: pushab val.0
+ pushab val.1
+ calls #2,xfer.xf_fnlength
+OC_FNLVNAME: pushab val.0
+ pushl val.2
+ pushab val.1
+ calls #3,xfer.xf_fnlvname
+OC_FNLVNAMEO2: pushab val.2
+ pushab val.0
+ pushab val.1
+ calls #3,xfer.xf_fnlvnameo2
+OC_FNLVPRVNAME: pushab val.0
+ pushab val.1
+ calls #2,xfer.xf_fnlvprvname
+OC_FNNAME: irepab val.4
+ pushab val.1 ; r->operand[0]
+ pushl val.3
+ pushab val.0 ; result of $NAME
+ calls val.2,xfer.xf_fnname
+OC_FNNEXT: pushab val.0
+ pushab val.2
+ pushab val.1
+ calls #3,xfer.xf_fnnext
+OC_FNO2: pushab val.3
+ pushab val.0
+ pushab val.2
+ pushab val.1
+ calls #4,xfer.xf_fno2
+OC_FNORDER: pushab val.0
+ pushab val.2
+ pushab val.1
+ calls #3,xfer.xf_fnorder
+OC_FNP1: pushl val.4
+ pushab val.0
+ pushl val.3
+ pushl val.2
+ pushab val.1
+ calls #5,xfer.xf_fnp1
+OC_FNPIECE: pushl val.5
+ pushab val.0
+ pushl val.4
+ pushl val.3
+ pushab val.2
+ pushab val.1
+ calls #6,xfer.xf_fnpiece
+OC_FNQLENGTH: pushab val.0
+ pushab val.1
+ calls #2,xfer.xf_fnqlength
+OC_FNQSUBSCR: pushab val.0
+ pushl val.2
+ pushab val.1
+ calls #3,xfer.xf_fnqsubscript
+OC_FNQUERY: irepab val.3
+ pushab val.2
+ pushab val.0
+ calls val.1,xfer.xf_fnquery
+OC_FNRANDOM: pushab val.0
+ pushl val.1
+ calls #2,xfer.xf_fnrandom
+OC_FNREVERSE: pushab val.0
+ pushab val.1
+ calls #2,xfer.xf_fnreverse
+OC_FNSTACK1: pushab val.0
+ pushl val.1
+ calls #2,xfer.xf_fnstack1
+OC_FNSTACK2: pushab val.0
+ pushab val.2
+ pushl val.1
+ calls #3,xfer.xf_fnstack2
+OC_FNTEXT: pushab val.0
+ pushab val.3
+ pushl val.2
+ pushab val.1
+ calls #4,xfer.xf_fntext
+OC_FNTRANSLATE: pushab val.0
+ pushab val.3
+ pushab val.2
+ pushab val.1
+ calls #4,xfer.xf_fntranslate
+OC_FNVIEW: irepab val.2
+ pushab val.0
+ calls val.1,xfer.xf_fnview
+OC_FNZASCII: pushab val.0
+ pushab val.1
+ pushl val.2
+ calls #3,xfer.xf_fnzascii
+OC_FNZAHANDLE: pushab val.0
+ pushab val.1
+ calls #2,xfer.xf_fnzahandle
+OC_FNZBITAND: pushab val.2
+ pushab val.1
+ pushab val.0
+ calls #3,xfer.xf_fnzbitand
+OC_FNZBITCOUN: pushab val.1
+ pushab val.0
+ calls #2,xfer.xf_fnzbitcoun
+OC_FNZBITFIND: pushl val.3
+ pushl val.2
+ pushab val.1
+ pushab val.0
+ calls #4,xfer.xf_fnzbitfind
+OC_FNZBITGET: pushl val.2
+ pushab val.1
+ pushab val.0
+ calls #3,xfer.xf_fnzbitget
+OC_FNZBITLEN: pushab val.1
+ pushab val.0
+ calls #2,xfer.xf_fnzbitlen
+OC_FNZBITNOT: pushab val.1
+ pushab val.0
+ calls #2,xfer.xf_fnzbitnot
+OC_FNZBITOR: pushab val.2
+ pushab val.1
+ pushab val.0
+ calls #3,xfer.xf_fnzbitor
+OC_FNZBITSET: pushl val.3
+ pushl val.2
+ pushab val.1
+ pushab val.0
+ calls #4,xfer.xf_fnzbitset
+OC_FNZBITSTR: pushl val.2
+ pushl val.1
+ pushab val.0
+ calls #3,xfer.xf_fnzbitstr
+OC_FNZBITXOR: pushab val.2
+ pushab val.1
+ pushab val.0
+ calls #3,xfer.xf_fnzbitxor
+OC_FNZCALL: irepab val.2
+ pushab val.0
+ calls val.1,xfer.xf_fnzcall
+OC_FNZCHAR: irepl val.2
+ pushab val.0
+ calls val.1,xfer.xf_fnzchar
+OC_FNZDATA: pushab val.0
+ pushab val.1
+ calls #2,xfer.xf_fnzdata
+OC_FNZDATE: pushab val.0
+ pushab val.4
+ pushab val.3
+ pushab val.2
+ pushab val.1
+ calls #5,xfer.xf_fnzdate
+OC_FNZEXTRACT: pushab val.0
+ pushab val.1
+ pushl val.2
+ pushl val.3
+ calls #4,xfer.xf_fnzextract
+OC_FNZFILE: pushab val.0
+ pushab val.2
+ pushab val.1
+ calls #3,xfer.xf_fnzfile
+OC_FNZFIND: pushab val.0
+ pushl val.3
+ pushab val.2
+ pushab val.1
+ calls #4,xfer.xf_fnzfind
+OC_FNZGETDVI: pushab val.0
+ pushab val.2
+ pushab val.1
+ calls #3,xfer.xf_fngetdvi
+OC_FNZGETJPI: pushab val.0
+ pushab val.2
+ pushl val.1
+ calls #3,xfer.xf_fngetjpi
+OC_FNZGETLKI: pushab val.0
+ pushab val.2
+ pushab val.1
+ calls #3,xfer.xf_fngetlki
+OC_FNZGETSYI: pushab val.0
+ pushab val.2
+ pushab val.1
+ calls #3,xfer.xf_fngetsyi
+OC_FNZJ2: pushab val.0
+ pushl val.2
+ pushab val.1
+ calls #3,xfer.xf_fnzj2
+OC_FNZJOBEXAM: pushab val.0
+ pushab val.1
+ calls #2,xfer.xf_fnzjobexam
+OC_FNZLENGTH: pushab val.0
+ pushab val.1
+ calls #2,xfer.xf_fnzlength
+OC_FNZLKID: pushab val.0
+ pushl val.1
+ calls #2,xfer.xf_fnzlkid
+OC_FNZM: pushab val.0
+ pushl val.1
+ calls #2,xfer.xf_fnzm
+OC_FNZP1: pushab val.0
+ pushl val.3
+ pushl val.2
+ pushab val.1
+ calls #4,xfer.xf_fnzp1
+OC_FNZPARSE: pushab val.0
+ pushab val.5
+ pushab val.4
+ pushab val.3
+ pushab val.2
+ pushab val.1
+ calls #6,xfer.xf_fnzparse
+OC_FNZPID: pushab val.0
+ pushl val.1
+ calls #2,xfer.xf_fnzpid
+OC_FNZPIECE: pushab val.0
+ pushl val.4
+ pushl val.3
+ pushab val.2
+ pushab val.1
+ calls #5,xfer.xf_fnzpiece
+OC_FNZPOPULATION: pushab val.0
+ pushab val.2
+ pushab val.1
+ calls #3,xfer.xf_fnzpopulation
+OC_FNZPREVIOUS: pushab val.0
+ pushab val.2
+ pushab val.1
+ calls #3,xfer.xf_fnzprevious
+OC_FNZPRIV: pushab val.0
+ pushab val.1
+ calls #2,xfer.xf_fnzpriv
+OC_FNZQGBLMOD: pushab val.0
+ calls #1,xfer.xf_fnzqgblmod
+OC_FNZSEA: pushab val.0
+ pushl val.2
+ pushab val.1
+ calls #3,xfer.xf_fnzsearch
+OC_FNZSETPRV: pushab val.0
+ pushab val.1
+ calls #2,xfer.xf_fnzsetprv
+OC_FNZSUBSTR: pushab val.0 ; Destination mval
+ pushl val.3 ; max byte length
+ pushl val.2 ; starting character position
+ pushab val.1 ; string
+ calls #4,xfer.xf_fnzsubstr
+OC_FNZTRANSLATE: pushab val.0
+ pushab val.3
+ pushab val.2
+ pushab val.1
+ calls #4,xfer.xf_fnztranslate
+OC_FNZSIGPROC: pushab val.0
+ pushl val.2
+ pushl val.1
+ calls #3,xfer.xf_fnzsigproc
+OC_FNZTRNLNM: pushab val.0
+ pushab val.6
+ pushab val.5
+ pushab val.4
+ pushl val.3
+ pushab val.2
+ pushab val.1
+ calls #7,xfer.xf_fnztrnlnm
+OC_FNZWIDTH: pushab val.0 ; destination mval
+ pushab val.1 ; string
+ calls #2,xfer.xf_fnzwidth
+OC_FOLLOW: movab val.1,r0
+ movab val.2,r1
+ jsb xfer.xf_follow
+OC_FORCENUM: movab val.0,r0
+ movab val.1,r1
+ jsb xfer.xf_forcenum
+OC_FORCHK1: jsb xfer.xf_restartpc
+ jsb xfer.xf_forchk1
+OC_FORINIT: pushab val.3
+ pushab val.2
+ pushab val.1
+ jsb xfer.xf_forinit
+OC_FORLCLDO-BYTE: pushl val.2
+ jsb xfer.xf_forlcldob
+ brb jmp.1
+OC_FORLCLDO-LONG: pushl val.2
+ jsb xfer.xf_forlcldol
+ jmp jmp.1
+OC_FORLCLDO-WORD: pushl val.2
+ jsb xfer.xf_forlcldow
+ brw jmp.1
+OC_FORLOOP-BYTE:jsb xfer.xf_restartpc
+ pushab jmp.1
+ pushab val.4
+ pushab val.3
+ pushab val.2
+ jsb xfer.xf_forloop
+OC_FORLOOP-LONG:jsb xfer.xf_restartpc
+ pushab jmp.1
+ pushab val.4
+ pushab val.3
+ pushab val.2
+ jsb xfer.xf_forloop
+OC_FORLOOP-WORD:jsb xfer.xf_restartpc
+ pushab jmp.1
+ pushab val.4
+ pushab val.3
+ pushab val.2
+ jsb xfer.xf_forloop
+OC_GETINDX: irepab val.2
+ calls val.1,xfer.xf_getindx
+ movl r0,addr.0
+OC_GETTRUTH: movab val.0,r1
+ jsb xfer.xf_gettruth
+OC_GVDATA: pushab val.0
+ calls #1,xfer.xf_gvdata
+OC_GVEXTNAM: irepab val.2
+ calls val.1,xfer.xf_gvextnam
+OC_GVGET: pushab val.0
+ calls #1,xfer.xf_gvget
+OC_GVINCR: pushab val.0 ; result of $INCR
+ pushab val.2 ; r->operand[1] = increment (global-variable to increment is gv_currkey so no operand[0])
+ calls #2,xfer.xf_gvincr
+OC_GVKILL: calls #0,xfer.xf_gvkill
+OC_GVNAKED: irepab val.2
+ calls val.1,xfer.xf_gvnaked
+OC_GVNAME: irepab val.2
+ calls val.1,xfer.xf_gvname
+OC_GVNEXT: pushab val.0
+ calls #1,xfer.xf_gvnext
+OC_GVO2: pushab val.1
+ pushab val.0
+ calls #2,xfer.xf_gvo2
+OC_GVORDER: pushab val.0
+ calls #1,xfer.xf_gvorder
+OC_GVPUT: pushab val.1
+ calls #1,xfer.xf_gvput
+OC_GVQUERY: pushab val.0
+ calls #1,xfer.xf_gvquery
+OC_GVRECTARG: pushab val.1
+ calls #1,xfer.xf_gvrectarg
+OC_GVSAVTARG: pushab val.0
+ calls #1,xfer.xf_gvsavtarg
+OC_GVZWITHDRAW: calls #0,xfer.xf_gvzwithdraw
+OC_GVZWRITE: jsb xfer.xf_restartpc
+ irepab val.4
+ pushl val.3
+ pushl val.2
+ calls val.1,xfer.xf_gvzwrite
+OC_HALT: calls #0,xfer.xf_halt
+OC_HANG: jsb xfer.xf_restartpc
+ pushab val.1
+ calls #1,xfer.xf_hang
+OC_HARDRET: jsb xfer.xf_hardret
+OC_IDIV: pushab val.0
+ pushab val.2
+ pushab val.1
+ calls #3,xfer.xf_idiv
+OC_IGETSRC: pushab val.0
+ calls #1,xfer.xf_igetsrc
+OC_INDDEVPARMS: pushab val.0
+ pushl val.2
+ pushab val.1
+ jsb xfer.xf_inddevparms
+OC_INDFNNAME: pushab val.2 ; r->operand[1] = depth
+ pushab val.1 ; r->operand[0] = name
+ pushab val.0 ; r->dst
+ jsb xfer.xf_indfnname
+OC_INDFUN: pushab val.0
+ pushl val.2
+ pushab val.1
+ jsb xfer.xf_indfun
+OC_INDGLVN: pushab val.0
+ pushab val.1
+ jsb xfer.xf_indglvn
+OC_INDINCR: pushab val.1 ; r->operand[0] = indirection expression
+ pushab val.2 ; r->operand[1] = increment (ILIT)
+ pushab val.0 ; r->dst
+ jsb xfer.xf_indincr
+OC_INDLVADR: pushab val.1
+ jsb xfer.xf_indlvadr
+ movl r0,addr.0
+OC_INDLVARG: pushab val.0
+ pushab val.1
+ jsb xfer.xf_indlvarg
+OC_INDNAME: pushab val.2
+ pushab val.1
+ pushab val.0
+ calls #3,xfer.xf_indname
+OC_INDLVNAMADR: pushab val.1
+ jsb xfer.xf_indlvnamadr
+ movl r0,addr.0
+OC_INDO2: pushab val.2
+ pushab val.1
+ pushab val.0
+ calls #3,xfer.xf_indo2
+OC_INDPAT: pushab val.0
+ pushab val.1
+ jsb xfer.xf_indpat
+OC_INDRZSHOW: pushab val.2
+ pushab val.1
+ jsb xfer.xf_indrzshow
+OC_INDSET: pushab val.2
+ pushab val.1
+ jsb xfer.xf_indset
+OC_INDTEXT: pushab val.0
+ pushab val.3
+ pushl val.2
+ pushab val.1
+ jsb xfer.xf_indtext
+OC_IOCONTROL: jsb xfer.xf_restartpc
+ irepab val.2
+ calls val.1,xfer.xf_iocontrol
+OC_IRETMVAD: movab val.1,r1
+ jsb xfer.xf_iretmvad
+OC_IRETMVAL: pushab val.2
+ pushab val.1
+ jsb xfer.xf_iretmval
+OC_JMP-BYTE: brb jmp.1
+OC_JMP-LONG: jmp jmp.1
+OC_JMP-WORD: brw jmp.1
+OC_JMPAT: jmp val.1
+OC_JMPEQU-BYTE: beql jmp.1
+OC_JMPEQU-LONG: bneq #6
+ jmp jmp.1
+OC_JMPEQU-WORD: bneq #3
+ brw jmp.1
+OC_JMPGEQ-BYTE: bgeq jmp.1
+OC_JMPGEQ-LONG: blss #6
+ jmp jmp.1
+OC_JMPGEQ-WORD: blss #3
+ brw jmp.1
+OC_JMPGTR-BYTE: bgtr jmp.1
+OC_JMPGTR-LONG: bleq #6
+ jmp jmp.1
+OC_JMPGTR-WORD: bleq #3
+ brw jmp.1
+OC_JMPLEQ-BYTE: bleq jmp.1
+OC_JMPLEQ-LONG: bgtr #6
+ jmp jmp.1
+OC_JMPLEQ-WORD: bgtr #3
+ brw jmp.1
+OC_JMPLSS-BYTE: blss jmp.1
+OC_JMPLSS-LONG: bgeq #6
+ jmp jmp.1
+OC_JMPLSS-WORD: bgeq #3
+ brw jmp.1
+OC_JMPNEQ-BYTE: bneq jmp.1
+OC_JMPNEQ-LONG: bneq #6
+ jmp jmp.1
+OC_JMPNEQ-WORD: beql #3
+ brw jmp.1
+OC_JMPTCLR-BYTE: blbc r10,jmp.1
+OC_JMPTCLR-LONG: blbs r10,#6
+ jmp jmp.1
+OC_JMPTCLR-WORD: blbs r10,#3
+ brw jmp.1
+OC_JMPTSET-BYTE: blbs r10,jmp.1
+OC_JMPTSET-LONG: blbc r10,#6
+ jmp jmp.1
+OC_JMPTSET-WORD: blbc r10,#3
+ brw jmp.1
+OC_JOB: jsb xfer.xf_restartpc
+ irepab val.7
+ pushl val.6
+ pushab val.5
+ pushab val.4
+ pushl val.3
+ pushab val.2
+ calls val.1,xfer.xf_job
+OC_KILL: pushab val.1
+ calls #1,xfer.xf_kill
+OC_KILLALIAS: pushl val.1
+ calls #1,xfer.xf_killalias
+OC_KILLALL: calls #0,xfer.xf_killall
+OC_KILLALIASALL: calls #0,xfer.xf_killaliasall
+OC_LABADDR: pushl val.2
+ pushab val.1
+ pushab val.3
+ calls #3,xfer.xf_labaddr
+ movl r0,addr.0
+OC_LCKDECR: pushl val.1
+ calls #1,xfer.xf_lckdecr
+OC_LCKINCR: pushl val.1
+ calls #1,xfer.xf_lckincr
+OC_LDADDR-BYTE: movab jmp.1,addr.0
+OC_LDADDR-LONG: movab jmp.1,addr.0
+OC_LDADDR-WORD: movab jmp.1,addr.0
+OC_LINEFETCH: irepl val.2
+ pushl val.1
+ jsb xfer.xf_linefetch
+OC_LINESTART: jsb xfer.xf_linestart
+OC_LKEXTNAME: irepab val.4
+ pushab val.3
+ pushab val.2
+ calls val.1,xfer.xf_lkname
+OC_LKINIT: calls #0,xfer.xf_lkinit
+OC_LKNAME: irepab val.4
+ pushab val.3
+ pushl val.2
+ calls val.1,xfer.xf_lkname
+OC_LOCK: pushl val.1
+ calls #1,xfer.xf_lock
+OC_LVPATWRITE: jsb xfer.xf_restartpc
+ irepab val.3
+ pushl val.2
+ calls val.1,xfer.xf_lvpatwrite
+OC_LVZWITHDRAW: pushab val.1
+ calls #1,xfer.xf_lvzwithdraw
+OC_LVZWRITE: jsb xfer.xf_restartpc
+ irepab val.2
+ calls val.1,xfer.xf_lvzwrite
+OC_MOD: pushab val.0
+ pushab val.2
+ pushab val.1
+ calls #3,xfer.xf_flt_mod
+OC_MUL: pushab val.0
+ pushab val.2
+ pushab val.1
+ calls #3,xfer.xf_mul
+OC_NEG: movab val.0,r0
+ movab val.1,r1
+ jsb xfer.xf_neg
+OC_NEWINTRINSIC: pushl val.1
+ jsb xfer.xf_newintrinsic
+OC_NEWVAR: pushl val.1
+ jsb xfer.xf_newvar
+OC_NULLEXP: pushab val.0
+ calls #1,xfer.xf_nullexp
+OC_NUMCMP: movab val.1,r0
+ movab val.2,r1
+ jsb xfer.xf_numcmp
+OC_OPEN: jsb xfer.xf_restartpc
+ pushab val.4
+ pushl val.3
+ pushab val.2
+ pushab val.1
+ calls #4,xfer.xf_open
+OC_PATTERN: movab val.1,r0
+ movab val.2,r1
+ jsb xfer.xf_pattern
+OC_FNPOPULATION: pushab val.0
+ pushab val.2
+ pushab val.1
+ calls #3,xfer.xf_fnpopulation
+OC_PUTINDX: irepab val.2
+ calls val.1,xfer.xf_putindx
+ movl r0,addr.0
+OC_RDONE: jsb xfer.xf_restartpc
+ pushl val.1
+ pushab val.0
+ calls #2,xfer.xf_rdone
+OC_READ: jsb xfer.xf_restartpc
+ pushl val.1
+ pushab val.0
+ calls #2,xfer.xf_read
+OC_READFL: jsb xfer.xf_restartpc
+ pushl val.2
+ pushl val.1
+ pushab val.0
+ calls #3,xfer.xf_readfl
+OC_RESTARTPC: jsb xfer.xf_restartpc
+OC_RET: jsb xfer.xf_ret
+OC_RETARG: movab val.1,r0
+ movl val.2,r1
+ jsb xfer.xf_retarg
+OC_RHDADDR: pushab G^val.2
+ pushab val.1
+ calls #2,xfer.xf_rhdaddr
+ movl r0,addr.0
+OC_RHDADDR1: pushl #0
+ pushab val.1
+ calls #2,xfer.xf_rhdaddr
+ movl r0,addr.0
+OC_RTERROR: pushl val.2 ; Note if OC_RTERROR call changes, linetail.c and eval_expr.c will also need
+ pushl val.1 ; to change due to them dereferencing the backpoints to get to the opcode.
+ jsb xfer.xf_rterror
+OC_SETALS2ALS: pushl val.1
+ pushab val.2
+ calls #2,xfer.xf_setals2als
+OC_SETALSIN2ALSCT: pushab val.1
+ pushab val.2
+ calls #2,xfer.xf_setalsin2alsct
+OC_SETALSCTIN2ALS: pushl val.1
+ pushab val.2
+ calls #2,xfer.xf_setalsctin2als
+OC_SETALSCT2ALSCT: pushab val.1
+ pushab val.2
+ calls #2,xfer.xf_setalsct2alsct
+OC_SETFNRETIN2ALS: pushl val.1
+ pushab val.2
+ calls #2,xfer.xf_setfnretin2als
+OC_SETFNRETIN2ALSCT: pushab val.1
+ pushab val.2
+ calls #2,xfer.xf_setfnretin2alsct
+OC_SETEXTRACT: pushab val.0
+ pushl val.3
+ pushl val.2
+ pushab val.4
+ pushab val.1
+ calls #5,xfer.xf_setextract
+OC_SETP1: pushab val.0
+ pushl val.3
+ pushab val.4
+ pushl val.2
+ pushab val.1
+ calls #5,xfer.xf_setp1
+OC_SETPIECE: pushab val.0
+ pushl val.4
+ pushl val.3
+ pushab val.5
+ pushab val.2
+ pushab val.1
+ calls #6,xfer.xf_setpiece
+OC_SETTEST: bisb2 #1,r10
+ calls #0,xfer.xf_dt_true
+OC_SETZBRK: pushl val.5
+ pushab val.4
+ pushl val.2
+ pushab val.1
+ pushab val.3
+ calls #5,xfer.xf_setzbrk
+OC_SETZEXTRACT: pushab val.0
+ pushl val.3
+ pushl val.2
+ pushab val.4
+ pushab val.1
+ calls #5,xfer.xf_setzextract
+OC_SETZP1: pushab val.0
+ pushl val.3
+ pushab val.4
+ pushl val.2
+ pushab val.1
+ calls #5,xfer.xf_setzp1
+OC_SETZPIECE: pushab val.0
+ pushl val.4
+ pushl val.3
+ pushab val.5
+ pushab val.2
+ pushab val.1
+ calls #6,xfer.xf_setzpiece
+OC_SORTS_AFTER: movab val.1,r0
+ movab val.2,r1
+ jsb xfer.xf_sorts_after
+OC_SRCHINDX: irepab val.2
+ calls val.1,xfer.xf_srchindx
+ movl r0,addr.0
+OC_STO: movab val.2,r1
+ movab val.1,r0
+ jsb xfer.xf_sto
+OC_STOLIT: movc3 #16,val.2,val.1
+OC_STOTEMP: movab val.1,r1
+ movab val.0,r0
+ jsb xfer.xf_sto
+OC_SUB: pushab val.0
+ pushab val.2
+ pushab val.1
+ calls #3,xfer.xf_sub
+OC_SVGET: pushab val.0
+ pushl val.1
+ calls #2,xfer.xf_svget
+OC_PSVPUT: pushab val.2
+ pushl val.1
+ jsb xfer.xf_psvput
+OC_SVPUT: pushab val.2
+ pushl val.1
+ calls #2,xfer.xf_svput
+OC_TIMTRU: movl r0,r10
+OC_TCOMMIT: jsb xfer.xf_tcommit
+OC_TROLLBACK: pushl val.1
+ jsb xfer.xf_trollback
+OC_TRESTART: pushl val.1
+ jsb xfer.xf_trestart
+OC_TSTART: irepab val.4
+ pushl val.3
+ pushab val.2
+ pushl val.1
+ jsb xfer.xf_tstart
+OC_UNLOCK: calls #0,xfer.xf_unlock
+OC_USE: pushab val.2
+ pushab val.1
+ calls #2,xfer.xf_use
+OC_VIEW: irepab val.2
+ calls val.1,xfer.xf_view
+OC_VXCMPL: cmpl val.1,val.2
+OC_WRITE: pushab val.1
+ calls #1,xfer.xf_write
+OC_WTEOL: pushl val.1
+ calls #1,xfer.xf_wteol
+OC_WTFF: calls #0,xfer.xf_wtff
+OC_WTONE: pushl val.1
+ calls #1,xfer.xf_wtone
+OC_WTTAB: pushl val.1
+ calls #1,xfer.xf_wttab
+OC_XKILL: irepab val.2
+ calls val.1,xfer.xf_xkill
+OC_XNEW: irepab val.2
+ pushl val.1
+ jsb xfer.xf_xnew
+OC_ZALLOCATE: pushl val.1
+ calls #1,xfer.xf_zallocate
+OC_ZATTACH: jsb xfer.xf_restartpc
+ pushab val.1
+ calls #1,xfer.xf_zattach
+OC_ZCOMPILE: pushl val.2
+ pushab val.1
+ calls #2,xfer.xf_zcompile
+OC_ZCONT: jsb xfer.xf_zcont
+OC_ZDEALLOCATE: pushl val.1
+ calls #1,xfer.xf_zdeallocate
+OC_ZEDIT: jsb xfer.xf_restartpc
+ pushab val.2
+ pushab val.1
+ calls #2,xfer.xf_zedit
+OC_ZG1: pushl val.1
+ jsb xfer.xf_zg1
+OC_ZGOTO: pushl val.1
+ pushl val.4
+ pushab val.3
+ pushab val.2
+ jsb xfer.xf_zgoto
+OC_ZHALT: pushab val.1
+ calls #1,xfer.xf_zhalt
+OC_ZHELP: pushab val.2
+ pushab val.1
+ calls #2,xfer.xf_zhelp
+OC_ZLINK: pushab val.2
+ pushab val.1
+ calls #2,xfer.xf_zlink
+OC_ZMESS: irepab val.3
+ pushl val.2
+ calls val.1,xfer.xf_zmess
+OC_ZPREVIOUS: pushab val.0
+ calls #1,xfer.xf_zprevious
+OC_ZPRINT: jsb xfer.xf_restartpc
+ pushl val.5
+ pushab val.4
+ pushl val.3
+ pushab val.2
+ pushab val.1
+ calls #5,xfer.xf_zprint
+OC_ZSHOW: jsb xfer.xf_restartpc
+ pushl #0
+ pushl val.2
+ pushab val.1
+ calls #3,xfer.xf_zshow
+OC_ZSHOWLOC: jsb xfer.xf_restartpc
+ pushab val.3
+ pushl val.2
+ pushab val.1
+ calls #3,xfer.xf_zshow
+OC_ZSTEP: pushl #0
+ pushl val.1
+ calls #2,xfer.xf_zstep
+ jsb xfer.xf_zcont
+OC_ZSTEPACT: pushab val.2
+ pushl val.1
+ calls #2,xfer.xf_zstep
+ jsb xfer.xf_zcont
+OC_ZSYSTEM: jsb xfer.xf_restartpc
+ pushab val.1
+ calls #1,xfer.xf_zsystem
+OC_ZTCOMMIT: pushl val.1
+ calls #1,xfer.xf_ztcommit
+OC_ZTSTART: calls #0,xfer.xf_ztstart
+OC_MERGE: calls #0,xfer.xf_merge
+OC_MERGE_GVARG: pushl #0
+ pushl val.1
+ calls #2,xfer.xf_merge_arg
+OC_MERGE_LVARG: pushab val.2
+ pushl val.1
+ calls #2,xfer.xf_merge_arg
+OC_INDMERGE: pushab val.1
+ pushab val.2
+ jsb xfer.xf_indmerge
+OC_M_SRCHINDX: irepab val.2
+ calls val.1,xfer.xf_m_srchindx
+ movl r0,addr.0
+OC_ZWRITESVN: pushl val.1
+ calls #1,xfer.xf_zwritesvn
+OC_FNZWRITE: pushab val.0 ; destination mval
+ pushab val.1 ; string
+ calls #2,xfer.xf_fnzwrite
+OC_IGETDST: calls #0,xfer.xf_igetdst
+ movl r0,addr.0
+OC_INDGET1: pushab val.0
+ pushab val.1
+ calls #2,xfer.xf_indget1
+OC_GLVNPOP: pushab val.1
+ calls #1,xfer.xf_glvnpop
+OC_GLVNSLOT: pushl val.1
+ calls #1,xfer.xf_glvnslot
+ movl r0,addr.0
+OC_INDSAVGLVN: pushl val.3
+ pushab val.2
+ pushab val.1
+ jsb xfer.xf_indsavglvn
+OC_INDSAVLVN: pushab val.2
+ pushab val.1
+ jsb xfer.xf_indsavlvn
+OC_RFRSHLVN: pushl val.2
+ pushab val.1
+ calls #2,xfer.xf_rfrshlvn
+ movl r0,addr.0
+OC_SAVGVN: irepab val.2
+ calls val.1,xfer.xf_savgvn
+OC_SAVLVN: irepab val.2
+ calls val.1,xfer.xf_savlvn
+OC_SHARESLOT: pushl val.2
+ pushab val.1
+ calls #2,xfer.xf_shareslot
+OC_STOGLVN: pushab val.2
+ pushab val.1
+ calls #2,xfer.xf_stoglvn
+OC_RFRSHGVN: pushl val.2
+ pushab val.1
+ calls #2,xfer.xf_rfrshgvn
+OC_INDFNNAME2: pushab val.2
+ pushab val.1
+ pushab val.0
+ calls #3,xfer.xf_indfnname2
+OC_INDGET2: pushab val.1
+ pushab val.0
+ calls #2,xfer.xf_indget2
+OC_INDMERGE2: pushab val.1
+ calls #1,xfer.xf_indmerge2
diff --git a/sr_vvms/upd_log_init.c b/sr_vvms/upd_log_init.c
new file mode 100644
index 0000000..f16884e
--- /dev/null
+++ b/sr_vvms/upd_log_init.c
@@ -0,0 +1,74 @@
+/****************************************************************
+ * *
+ * Copyright 2005 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+#ifdef VMS
+#include <descrip.h> /* Required for gtmrecv.h */
+#endif
+
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "gtmrecv.h"
+#include "iosp.h"
+#include "repl_log.h"
+#include "repl_dbg.h"
+#include "gtm_stdio.h"
+#include "util.h"
+#include "gtm_event_log.h"
+#include "read_db_files_from_gld.h"
+#include "updproc.h"
+
+#define UPDPROC_LOG_FILE_SUFFIX "_updproc"
+#define UPDHELPER_READER_LOG_FILE_SUFFIX "_uhr_"
+#define UPDHELPER_WRITER_LOG_FILE_SUFFIX "_uhw_"
+
+GBLREF recvpool_addrs recvpool;
+GBLREF uint4 process_id;
+
+int upd_log_init(recvpool_user who)
+{
+ char log_file[MAX_FN_LEN + 1], file_suffix_str[MAX_FN_LEN + 1], pid_str[9], *file_suffix;
+ int status = SS_NORMAL, len;
+
+ strcpy(log_file, recvpool.gtmrecv_local->log_file);
+ if (UPDPROC == who)
+ file_suffix = UPDPROC_LOG_FILE_SUFFIX;
+ else
+ {
+ if (UPD_HELPER_READER == who)
+ strcpy(file_suffix_str, UPDHELPER_READER_LOG_FILE_SUFFIX);
+ else /* UPD_HELPER_WRITER == who */
+ strcpy(file_suffix_str, UPDHELPER_WRITER_LOG_FILE_SUFFIX);
+ i2hex(process_id, pid_str, 8);
+ pid_str[8] = '\0';
+ strcat(file_suffix_str, pid_str);
+ file_suffix = file_suffix_str;
+ }
+ strcat(log_file, file_suffix);
+ len = strlen(log_file);
+ if (!util_is_log_open() || UPDPROC != who || 0 != memcmp(log_file, recvpool.upd_proc_local->log_file, len))
+ {
+ util_log_open(log_file, len);
+ if (UPDPROC == who)
+ {
+ memcpy(recvpool.upd_proc_local->log_file, log_file, len+1); /* +1 for '\0' */
+ gtm_event_log_init();
+ }
+ }
+ return(status);
+}
diff --git a/sr_vvms/user_rundown.c b/sr_vvms/user_rundown.c
new file mode 100644
index 0000000..4008b80
--- /dev/null
+++ b/sr_vvms/user_rundown.c
@@ -0,0 +1,76 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <lkidef.h>
+#include <prvdef.h>
+#include <psldef.h>
+#include <ssdef.h>
+#include <efndef.h>
+
+#include "gtmsecshr.h"
+#include "secshr_db_clnup.h"
+#include "locks.h"
+#include "vmsdtype.h"
+
+GBLREF uint4 rundown_process_id;
+GBLREF lock_sb vms_lock_list[MAX_VMS_LOCKS + 1];
+GBLREF int vms_lock_tail;
+
+#define MAX_TRIES 10
+
+void user_rundown()
+{
+ struct
+ {
+ item_list_3 item[1];
+ int4 terminator;
+ } item_list;
+ boolean_t repeat;
+ int index, lcnt;
+ unsigned short iosb[4];
+ uint4 lk_pid, retlen, status;
+ uint4 prvadr[2], prvprv[2];
+
+#ifndef TEST_REPL
+ secshr_db_clnup(ABNORMAL_TERMINATION);
+#endif
+ GTMSECSHR_SET_DBG_PRIV(PRV$M_SYSLCK, status);
+ if (SS$_NORMAL == status)
+ {
+ item_list.item[0].buffer_length = SIZEOF(lk_pid);
+ item_list.item[0].item_code = LKI$_PID;
+ item_list.item[0].buffer_address = &lk_pid;
+ item_list.item[0].return_length_address = &retlen;
+ item_list.terminator = 0;
+ repeat = TRUE;
+ for (lcnt = 0; repeat && lcnt < MAX_TRIES; lcnt++)
+ {
+ repeat = FALSE;
+ for (index = 0; index < vms_lock_tail; index++)
+ {
+ if (vms_lock_list[index].lockid)
+ {
+ if ((SS$_NORMAL == (status = sys$getlkiw(EFN$C_ENF, &vms_lock_list[index].lockid,
+ &item_list, iosb, NULL, 0, 0)))
+ && (lk_pid == rundown_process_id))
+ status = sys$deq(vms_lock_list[index].lockid, NULL, PSL$C_USER, 0);
+ if (SS$_SUBLOCKS != status)
+ vms_lock_list[index].lockid = 0;
+ else
+ repeat = TRUE;
+ }
+ }
+ }
+ GTMSECSHR_REL_DBG_PRIV;
+ }
+}
diff --git a/sr_vvms/util_input.c b/sr_vvms/util_input.c
new file mode 100644
index 0000000..7916c25
--- /dev/null
+++ b/sr_vvms/util_input.c
@@ -0,0 +1,76 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <fab.h>
+#include <rab.h>
+#include <descrip.h>
+#include <climsgdef.h>
+
+#define IN_BUFF_SIZE 256
+
+static struct RAB *util_input_rab = 0;
+static struct FAB *util_input_fab = 0;
+static char inbuff[IN_BUFF_SIZE];
+static char *inptr;
+
+void util_in_open(file_prompt)
+struct dsc$descriptor_s *file_prompt;
+{
+ static readonly unsigned char sys_input_name[] = "SYS$INPUT";
+ short unsigned innamlen;
+ uint4 status;
+ char input_name[255];
+ $DESCRIPTOR(input_name_desc, input_name);
+
+ if (file_prompt)
+ { status = cli$get_value(file_prompt, &input_name_desc, &innamlen);
+ if (status != 1)
+ {
+ innamlen = SIZEOF(sys_input_name) - 1;
+ input_name_desc.dsc$a_pointer = sys_input_name;
+ }
+ }else
+ {
+ innamlen = SIZEOF(sys_input_name) - 1;
+ input_name_desc.dsc$a_pointer = sys_input_name;
+ }
+ inptr = inbuff;
+ util_input_fab = malloc(SIZEOF(*util_input_fab));
+ util_input_rab = malloc(SIZEOF(*util_input_rab));
+ *util_input_fab = cc$rms_fab;
+ *util_input_rab = cc$rms_rab;
+ util_input_rab->rab$l_fab = util_input_fab;
+ util_input_rab->rab$w_usz = 255;
+ util_input_fab->fab$w_mrs = 255;
+ util_input_fab->fab$b_fac = FAB$M_GET | FAB$M_PUT;
+ util_input_fab->fab$l_fna = input_name_desc.dsc$a_pointer;
+ util_input_fab->fab$b_fns = innamlen;
+ status = sys$open(util_input_fab, 0, 0);
+ if ((status & 1) == 0)
+ lib$signal(status);
+ status = sys$connect(util_input_rab, 0, 0);
+ if ((status & 1) == 0)
+ lib$signal(status);
+}
+
+char *util_in_read(len)
+int *len;
+{
+ int status;
+
+ util_input_rab->rab$l_ubf = inbuff;
+ status = sys$get(util_input_rab,0 ,0);
+ if ((status & 1) == 0)
+ lib$signal(status);
+ *len = util_input_rab->rab$w_rsz;
+ return util_input_rab->rab$l_rbf;
+}
diff --git a/sr_vvms/util_output.c b/sr_vvms/util_output.c
new file mode 100644
index 0000000..1c528d8
--- /dev/null
+++ b/sr_vvms/util_output.c
@@ -0,0 +1,330 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include <climsgdef.h>
+#include <descrip.h>
+#include <fab.h>
+#include <rab.h>
+#include <opcdef.h>
+#include <rmsdef.h>
+#include <ssdef.h>
+#include <stdarg.h>
+
+#include "gdsroot.h"
+#include "gdsblk.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "fao_parm.h"
+#include "util.h"
+#include "gt_timer.h"
+
+static struct RAB *util_output_rab = NULL;
+static struct FAB *util_output_fab = NULL;
+
+GBLDEF unsigned int sndopr_missed = 0, sndopr_mbfull = 0;
+
+error_def(ERR_DEVOPENFAIL);
+error_def(ERR_SYSCALL);
+error_def(ERR_TEXT);
+
+void format_special_chars(void);
+void util_out_close(void);
+
+boolean_t util_is_log_open(void)
+{
+ return (NULL != util_output_fab);
+}
+
+void util_log_open(char *filename, uint4 len)
+{
+ unsigned int status;
+ uint4 ustatus;
+ char exp_file_name[MAX_FN_LEN];
+ int exp_file_name_len;
+
+ if(util_output_fab)
+ util_out_close();
+ memcpy(exp_file_name, filename, len);
+ exp_file_name_len = len;
+ if (!get_full_path(filename, len, exp_file_name, &exp_file_name_len, SIZEOF(exp_file_name), &ustatus))
+ rts_error(VARLSTCNT(5) ERR_DEVOPENFAIL, 2, len, filename, ustatus);
+ util_output_fab = malloc(SIZEOF(*util_output_fab));
+ util_output_rab = malloc(SIZEOF(*util_output_rab));
+ *util_output_fab = cc$rms_fab;
+ *util_output_rab = cc$rms_rab;
+ util_output_rab->rab$l_fab = util_output_fab;
+ util_output_rab->rab$w_usz = OUT_BUFF_SIZE;
+ util_output_fab->fab$w_mrs = OUT_BUFF_SIZE;
+ util_output_fab->fab$b_fac = FAB$M_GET | FAB$M_PUT;
+ util_output_fab->fab$b_rat = FAB$M_CR;
+ util_output_fab->fab$b_shr = FAB$M_SHRPUT | FAB$M_SHRGET;
+ util_output_fab->fab$l_fna = exp_file_name;
+ util_output_fab->fab$b_fns = exp_file_name_len;
+ status = sys$create(util_output_fab, 0, 0);
+ if (1 & status)
+ status = sys$connect(util_output_rab, 0, 0);
+ if (RMS$_NORMAL != status)
+ rts_error(VARLSTCNT(10) ERR_SYSCALL, 5, LEN_AND_LIT("SYS$CONNECT"), CALLFROM, status, 0,util_output_fab->fab$l_stv);
+}
+
+void util_out_open(struct dsc$descriptor_s *file_prompt)
+{
+ short unsigned outnamlen;
+ unsigned int status;
+ char output_name[255];
+ $DESCRIPTOR(output_name_desc, output_name);
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ TREF(util_outptr) = TREF(util_outbuff_ptr);
+ util_output_fab = NULL;
+ util_output_rab = NULL;
+ if (file_prompt)
+ {
+ status = cli$get_value(file_prompt, &output_name_desc, &outnamlen);
+ if (SS$_NORMAL == status)
+ {
+ util_output_fab = malloc(SIZEOF(*util_output_fab));
+ util_output_rab = malloc(SIZEOF(*util_output_rab));
+ *util_output_fab = cc$rms_fab;
+ *util_output_rab = cc$rms_rab;
+ util_output_rab->rab$l_fab = util_output_fab;
+ util_output_rab->rab$w_usz = OUT_BUFF_SIZE;
+ util_output_fab->fab$w_mrs = OUT_BUFF_SIZE;
+ util_output_fab->fab$b_fac = FAB$M_GET | FAB$M_PUT;
+ util_output_fab->fab$b_rat = FAB$M_CR;
+ util_output_fab->fab$b_shr = FAB$M_SHRPUT | FAB$M_SHRGET;
+ util_output_fab->fab$l_fna = output_name_desc.dsc$a_pointer;
+ util_output_fab->fab$b_fns = outnamlen;
+ status = sys$create(util_output_fab, 0, 0);
+ if (1 & status)
+ status = sys$connect(util_output_rab, 0, 0);
+ if (RMS$_NORMAL != status)
+ rts_error(VARLSTCNT(10) ERR_SYSCALL, 5, LEN_AND_LIT("SYS$CONNECT"), CALLFROM, status, 0,
+ util_output_fab->fab$l_stv);
+ }
+ }
+}
+
+void util_out_write(unsigned char *addr, unsigned int len)
+{
+ unsigned int status;
+ $DESCRIPTOR(output_mess_desc, "");
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ if (NULL == util_output_rab)
+ {
+ output_mess_desc.dsc$a_pointer = addr;
+ output_mess_desc.dsc$w_length = len;
+ status = lib$put_output(&output_mess_desc);
+ if (SS$_NORMAL != status)
+ lib$signal(status);
+ } else
+ {
+ util_output_rab->rab$l_rbf = addr;
+ util_output_rab->rab$w_rsz = len;
+ assert(!lib$ast_in_prog());
+ if (RMS$_NORMAL == (status = sys$put(util_output_rab, 0, 0)))
+ status = sys$flush(util_output_rab);
+ if (RMS$_NORMAL != status)
+ {
+ assert(FALSE);
+ if (TREF(gtm_environment_init))
+ GTMASSERT;
+ gtm_putmsg(ERR_TEXT, 2, LEN_AND_LIT("Error in util_output"));
+ lib$signal(status, util_output_rab->rab$l_stv);
+ }
+ }
+ return;
+}
+
+void util_out_send_oper(char *addr, unsigned int len)
+{
+
+ unsigned int status, thislen;
+ int retry = SNDOPR_TRIES;
+ uchar_ptr_t operptr;
+ oper_msg_struct oper;
+ $DESCRIPTOR(opmsg, "");
+
+ if (len > SIZEOF(oper.text))
+ len = SIZEOF(oper.text);
+ do
+ {
+ oper.req_code = OPC$_RQ_RQST;
+ oper.target = OPC$M_NM_CENTRL | OPC$M_NM_DEVICE | OPC$M_NM_DISKS;
+ memcpy(&oper.text, addr, len);
+ opmsg.dsc$a_pointer = &oper;
+ opmsg.dsc$w_length = SIZEOF(oper) - SIZEOF(oper.text) + len;
+ status = sys$sndopr(&opmsg, 0);
+ if (SS$_MBFULL == status)
+ hiber_start(SNDOPR_DELAY); /* OPCOM mailbox full so give it a chance to empty */
+ } while ((SS$_MBFULL == status) && (0 < --retry));
+ assert((SS$_NORMAL == status) || (OPC$_NOPERATOR == status) || (SS$_MBFULL == status));
+ /* the documentation of sys$sndopr() indicates that a success status OPC-S-OPC$_NOPERATOR status
+ * gets returned in case OPCOM is not running. hence the explicit || check in the assert above.
+ * If %SYSTEM-W-MBFULL, mailbox is full, we gave it our best try but
+ * the message could be dropped if OPCOM is busy enough.
+ */
+ if (SS$_MBFULL == status)
+ sndopr_mbfull++;
+ else if ((SS$_NORMAL != status) && (OPC$_NOPERATOR != status))
+ sndopr_missed++;
+ else if (0 < sndopr_mbfull || 0 < sndopr_missed)
+ { /* sndopr with info on missed and mbfull then reset */
+ oper.req_code = OPC$_RQ_RQST;
+ oper.target = OPC$M_NM_CENTRL | OPC$M_NM_DEVICE | OPC$M_NM_DISKS;
+ thislen = SIZEOF(GTMOPCOMMISSED1) - 1;
+ memcpy(&oper.text, GTMOPCOMMISSED1, thislen);
+ operptr = i2asc((uchar_ptr_t)&oper.text + thislen, sndopr_missed);
+ thislen = SIZEOF(GTMOPCOMMISSED2) - 1;
+ memcpy(operptr, GTMOPCOMMISSED2, thislen);
+ operptr = i2asc(operptr + thislen, sndopr_mbfull);
+ thislen = SIZEOF(GTMOPCOMMISSED3) - 1;
+ memcpy(operptr, GTMOPCOMMISSED3, thislen);
+ opmsg.dsc$a_pointer = &oper;
+ opmsg.dsc$w_length = SIZEOF(oper) - SIZEOF(oper.text) + ((operptr - &oper.text) + thislen);
+ status = sys$sndopr(&opmsg, 0);
+ if ((SS$_NORMAL == status) || (OPC$_NOPERATOR == status))
+ sndopr_missed = sndopr_mbfull = 0;
+ }
+ return;
+}
+
+void util_out_close()
+{
+ unsigned int status;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ if (TREF(util_outbuff_ptr) != TREF(util_outptr))
+ util_out_write(TREF(util_outbuff_ptr), TREF(util_outptr) - TREF(util_outbuff_ptr));
+ if (NULL != util_output_fab)
+ {
+ status = sys$close(util_output_fab, 0, 0);
+ free(util_output_fab);
+ free(util_output_rab);
+ util_output_fab = NULL;
+ util_output_rab = NULL;
+ if (RMS$_NORMAL != status)
+ lib$signal(status);
+ }
+ return;
+}
+
+#define NOFLUSH 0
+#define FLUSH 1
+#define RESET 2
+#define OPER 4
+#define SPRINT 5
+
+void util_out_print(char *message, int flush, ...)
+{
+ va_list var;
+ int4 cnt, faocnt, faolist[MAX_FAO_PARMS + 1];
+ char *util_format();
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ VAR_START(var, flush);
+ va_count(cnt);
+
+ cnt -= 2; /* for message and flush */
+ assert(cnt <= MAX_FAO_PARMS);
+ faocnt = cnt;
+ memset(faolist, 0, SIZEOF(faolist));
+ for (cnt = 0; cnt < faocnt; cnt++)
+ faolist[cnt] = va_arg(var, int4);
+ va_end(var);
+ if (message)
+ TREF(util_outptr) = util_format(message, faolist, TREF(util_outptr),
+ OUT_BUFF_SIZE - (TREF(util_outptr) - TREF(util_outbuff_ptr)));
+ switch (flush)
+ {
+ case NOFLUSH : break;
+ case FLUSH : util_out_write(TREF(util_outbuff_ptr), TREF(util_outptr) - TREF(util_outbuff_ptr));
+ TREF(util_outptr) = TREF(util_outbuff_ptr);
+ break;
+ case RESET : TREF(util_outptr) = TREF(util_outbuff_ptr);
+ break;
+ case OPER : util_out_send_oper(TREF(util_outbuff_ptr), TREF(util_outptr) - TREF(util_outbuff_ptr));
+ TREF(util_outptr) = TREF(util_outbuff_ptr);
+ break;
+ case SPRINT : *(TREF(util_outptr)) = '\0';
+ format_special_chars();
+ TREF(util_outptr) = TREF(util_outbuff_ptr);
+ break;
+ default : break;
+ }
+ return;
+}
+
+
+char *util_format(char *message, int4 fao[], char *buff, int4 size)
+{
+ short faolen;
+ unsigned int status;
+ struct dsc$descriptor desc;
+ struct dsc$descriptor out;
+
+ desc.dsc$a_pointer = message;
+ desc.dsc$b_dtype = DSC$K_DTYPE_T;
+ desc.dsc$b_class = DSC$K_CLASS_S;
+ desc.dsc$w_length = STRLEN(message);
+ out.dsc$b_dtype = DSC$K_DTYPE_T;
+ out.dsc$b_class = DSC$K_CLASS_S;
+ out.dsc$a_pointer = buff;
+ out.dsc$w_length = size;
+ status = sys$faol(&desc, &faolen, &out, fao);
+ if (SS$_NORMAL != status)
+ lib$signal(status);
+ return buff + faolen;
+}
+
+void format_special_chars(void)
+{
+ /* Taken from util_out_print_vaparm() of Unix (see there for potential truncation of input in case of buffer overflow) */
+ char fmt_buff[OUT_BUFF_SIZE]; /* needs to be same size as that of util_outbuff */
+ char *pout, *pin;
+ char *fmt_top1, *fmt_top2; /* the top of the buffer after leaving 1 (and 2 bytes respectively) at the end */
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ fmt_top1 = fmt_buff + SIZEOF(fmt_buff) - 1; /* leave out last byte for null byte termination */
+ fmt_top2 = fmt_top1 - 1;
+ for (pin = TREF(util_outbuff_ptr), pout = fmt_buff; ('\0' != *pin) && (pout < fmt_top1); )
+ {
+ if ('%' == *pin)
+ {
+ if (pout >= fmt_top2) /* Check if there is room for 2 bytes. If not stop copying */
+ break;
+ *pout++ = '%'; /* escape for '%' */
+ }
+ if ('\n' == *pin)
+ {
+ if (pout >= fmt_top2) /* Check if there is room for 2 bytes. If not stop copying */
+ break;
+ *pout++ = ',';
+ *pout++ = ' ';
+ pin++;
+ continue;
+ }
+ *pout++ = *pin++;
+ }
+ assert(pout <= fmt_top1);
+ *pout++ = '\0';
+ memcpy(TREF(util_outbuff_ptr), fmt_buff, pout-(char *)fmt_buff);
+}
diff --git a/sr_vvms/util_output_cm.c b/sr_vvms/util_output_cm.c
new file mode 100644
index 0000000..586d29c
--- /dev/null
+++ b/sr_vvms/util_output_cm.c
@@ -0,0 +1,91 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+#include <stdarg.h>
+
+#include "cmidef.h"
+#include "hashtab_mname.h" /* needed for cmmdef.h */
+#include "cmmdef.h"
+#include <descrip.h>
+#include "util.h"
+#include "cmi.h"
+
+#include "fao_parm.h"
+#include "gvcmz.h"
+
+#define PROPER(X,status) if ((status & 1)==0) { ((link_info *)(lnk->usr))->neterr = TRUE ; gvcmz_error(X,status) ;}
+
+#define NOFLUSH 0
+#define FLUSH 1
+#define RESET 2
+
+static char outbuff[OUT_BUFF_SIZE];
+static char *outptr;
+
+void util_cm_print(clb_struct *lnk, int code, char *message, int flush, ...)
+{
+ va_list var;
+
+
+ int4 status;
+ short faolen;
+ struct dsc$descriptor desc;
+ struct dsc$descriptor out;
+
+ int4 cnt, faolist[MAX_FAO_PARMS + 1];
+ int i;
+
+ VAR_START(var, flush);
+ va_count(cnt);
+ memset(faolist, 0, SIZEOF(faolist));
+ for(i = 0; i < (cnt - 4); i++) /* already 4 args */
+ {
+ faolist[i] = va_arg(var, int4);
+ }
+ va_end(var);
+
+ if (outptr==outbuff)
+ {
+ outbuff[0] = code ; outptr++ ;
+ }
+ if (message)
+ { desc.dsc$a_pointer = message;
+ desc.dsc$b_dtype = DSC$K_DTYPE_T;
+ desc.dsc$b_class = DSC$K_CLASS_S;
+ desc.dsc$w_length = strlen(message);
+ out.dsc$b_dtype = DSC$K_DTYPE_T;
+ out.dsc$b_class = DSC$K_CLASS_S;
+ out.dsc$a_pointer = outptr;
+ out.dsc$w_length = OUT_BUFF_SIZE - (outptr - outbuff);
+ faolen = 0;
+ status = sys$faol(&desc,&faolen,&out,faolist);
+ if (!(status & 1))
+ { lib$signal(status);
+ }
+ outptr += faolen;
+ }
+ switch (flush)
+ {
+ case NOFLUSH: break;
+ case FLUSH : *outptr++ = 0 ; lnk->mbf = outbuff ; lnk->cbl = outptr - outbuff ; lnk->ast = 0 ;
+ status = cmi_write(lnk) ;
+ PROPER (code,status) ;
+ outptr = outbuff ;
+ break;
+ case RESET : outptr = outbuff ;
+ break;
+ default : break ;
+ }
+ return;
+}
diff --git a/sr_vvms/util_spawn.c b/sr_vvms/util_spawn.c
new file mode 100644
index 0000000..568ae03
--- /dev/null
+++ b/sr_vvms/util_spawn.c
@@ -0,0 +1,38 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <descrip.h>
+#include <ssdef.h>
+#include <climsgdef.h>
+#include "util_spawn.h"
+
+void util_spawn(void)
+{
+
+ char buf[256];
+ $DESCRIPTOR(d_buf,buf);
+ $DESCRIPTOR(d_ent," ");
+
+ d_ent.dsc$a_pointer = "COMMAND";
+ d_ent.dsc$w_length = 7;
+
+ if (CLI$PRESENT(&d_ent) == CLI$_PRESENT)
+ {
+ if (CLI$GET_VALUE(&d_ent,&d_buf) == SS$_NORMAL)
+ lib$spawn(&d_buf);
+ return;
+ }
+ d_buf.dsc$w_length = 0;
+ lib$spawn(&d_buf);
+ return;
+
+}
diff --git a/sr_vvms/v010_jnl_prc_vector.c b/sr_vvms/v010_jnl_prc_vector.c
new file mode 100644
index 0000000..d0657dd
--- /dev/null
+++ b/sr_vvms/v010_jnl_prc_vector.c
@@ -0,0 +1,100 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include <jpidef.h>
+#include <syidef.h>
+#include <ssdef.h>
+#include "gdsroot.h"
+#include "gdsbt.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "v010_jnl.h"
+#include "vmsdtype.h"
+
+int v010_jnl_process_vector_size(void)
+{
+ return V010_JNL_PROCESS_VECTOR_SIZE;
+}
+
+void v010_jnl_prc_vector(jnl_process_vector *pv)
+{
+ struct
+ {
+ item_list_3 item[7];
+ int4 terminator;
+ } item_list;
+ unsigned short iosb[4];
+ uint4 mode, status, dummy;
+
+
+ memset(pv, 0, SIZEOF(jnl_process_vector));
+
+ sys$gettim(&pv->jpv_time);
+
+ item_list.item[0].buffer_length = SIZEOF(pv->jpv_pid);
+ item_list.item[0].item_code = JPI$_PID;
+ item_list.item[0].buffer_address = &pv->jpv_pid;
+ item_list.item[0].return_length_address = &dummy;
+
+ item_list.item[1].buffer_length = SIZEOF(pv->jpv_login_time);
+ item_list.item[1].item_code = JPI$_LOGINTIM;
+ item_list.item[1].buffer_address = &pv->jpv_login_time;
+ item_list.item[1].return_length_address = &dummy;
+
+ item_list.item[2].buffer_length = SIZEOF(pv->jpv_image_count);
+ item_list.item[2].item_code = JPI$_IMAGECOUNT;
+ item_list.item[2].buffer_address = &pv->jpv_image_count;
+ item_list.item[2].return_length_address = &dummy;
+
+ item_list.item[3].buffer_length = SIZEOF(mode);
+ item_list.item[3].item_code = JPI$_JOBTYPE;
+ item_list.item[3].buffer_address = &mode; /* jpv_mode set below */
+ item_list.item[3].return_length_address = &dummy;
+
+ item_list.item[4].buffer_length = SIZEOF(pv->jpv_user);
+ item_list.item[4].item_code = JPI$_USERNAME;
+ item_list.item[4].buffer_address = pv->jpv_user;
+ item_list.item[4].return_length_address = &dummy;
+
+ item_list.item[5].buffer_length = SIZEOF(pv->jpv_prcnam);
+ item_list.item[5].item_code = JPI$_PRCNAM;
+ item_list.item[5].buffer_address = pv->jpv_prcnam;
+ item_list.item[5].return_length_address = &dummy;
+
+ item_list.item[6].buffer_length = SIZEOF(pv->jpv_terminal);
+ item_list.item[6].item_code = JPI$_TERMINAL;
+ item_list.item[6].buffer_address = pv->jpv_terminal;
+ item_list.item[6].return_length_address = &dummy;
+
+ item_list.terminator = 0;
+
+ if ((status = sys$getjpiw(0, NULL, NULL, &item_list, iosb, NULL, 0)) != SS$_NORMAL ||
+ (status = iosb[0]) != SS$_NORMAL)
+ rts_error(status);
+
+ pv->jpv_mode = mode;
+
+
+ item_list.item[0].buffer_length = SIZEOF(pv->jpv_node);
+ item_list.item[0].item_code = SYI$_NODENAME;
+ item_list.item[0].buffer_address = pv->jpv_node;
+ item_list.item[0].return_length_address = &dummy;
+
+ *((int4 *)&item_list.item[1]) = 0; /* terminator */
+
+ if ((status = sys$getsyiw(0, NULL, NULL, &item_list, iosb, NULL, 0)) != SS$_NORMAL ||
+ (status = iosb[0]) != SS$_NORMAL)
+ rts_error(status);
+
+}
diff --git a/sr_vvms/v010_jnlsp.h b/sr_vvms/v010_jnlsp.h
new file mode 100644
index 0000000..9f64c23
--- /dev/null
+++ b/sr_vvms/v010_jnlsp.h
@@ -0,0 +1,80 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* Start jnlsp.h - platform-specific journaling definitions. */
+
+#ifndef V010_JNLSP_H_INCLUDED
+#define V010_JNLSP_H_INCLUDED
+
+#ifndef SS$_NORMAL
+#include <ssdef.h>
+#endif
+
+
+#ifdef __ALPHA
+# pragma member_alignment save
+# pragma nomember_alignment
+#endif
+
+typedef struct
+{
+ short low_time;
+ uint4 mid_time;
+ short hi_time;
+} jnl_proc_time;
+
+#ifdef __ALPHA
+# pragma member_alignment restore
+#endif
+
+/* in disk blocks but jnl file addresses are kept by byte so limited by uint4 for now */
+#define JNL_ALLOC_MAX 8388608
+
+#define JPV_LEN_NODE 15
+#define JPV_LEN_USER 12
+#define JPV_LEN_PRCNAM 15
+#define JPV_LEN_TERMINAL 8
+
+typedef struct jnl_process_vector_struct
+{
+ uint4 jpv_pid; /* Process id */
+ jnl_proc_time jpv_time, /* Journal record timestamp; also used for process termination time */
+ jpv_login_time; /* Process login time; also used for process initialization time */
+ int4 jpv_image_count; /* Image activations [VMS only] */
+ unsigned char jpv_mode; /* a la JPI$_MODE [VMS only] */
+ char jpv_node[JPV_LEN_NODE], /* Node name */
+ jpv_user[JPV_LEN_USER], /* User name */
+ jpv_prcnam[JPV_LEN_PRCNAM], /* Process name */
+ jpv_terminal[JPV_LEN_TERMINAL]; /* Login terminal */
+ /* SIZEOF(jnl_process_vector) must be a multiple of SIZEOF(int4) */
+ char jpv_padding;
+} jnl_process_vector;
+
+#define V010_JNL_PROCESS_VECTOR_SIZE 76
+
+typedef short fd_type;
+typedef vms_file_info fi_type;
+
+#define NOJNL 0
+#define LENGTH_OF_TIME 23
+#define SOME_TIME(X) (X.mid_time != 0)
+#define JNL_S_TIME(Y,X) Y->val.X.process_vector.jpv_time.mid_time
+#define JNL_M_TIME(X) mur_options.X.mid_time
+#define EXTTIME(T) extract_len = exttime(T->mid_time, ref_time, extract_len)
+#define EXTTIMEVMS(T) extract_len = exttime(T.mid_time, &T, extract_len)
+#define EXTINTVMS(I) EXTINT(I)
+#define EXTTXTVMS(T,L) EXTTXT(T,L)
+
+#define JNL_FILE_SWITCHED(reg) (memcmp((&FILE_INFO(reg)->s_addrs)->hdr->jnl_file.jnl_file_id.fid, (&FILE_INFO(reg)->s_addrs)->jnl->fileid.fid, SIZEOF((&FILE_INFO(reg)->s_addrs)->jnl->fileid.fid)) != 0)
+
+/* End of jnlsp.h */
+
+#endif
diff --git a/sr_vvms/v15_filestruct.h b/sr_vvms/v15_filestruct.h
new file mode 100644
index 0000000..67a5fdf
--- /dev/null
+++ b/sr_vvms/v15_filestruct.h
@@ -0,0 +1,15 @@
+/****************************************************************
+ * *
+ * Copyright 2005 Fidelity Information Services, LLC. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* filestruct.h */
+
+#define V15_GDS_LABEL "GDSDYNSEG10" /* This string must be of length GDS_LABEL_SZ */
+
diff --git a/sr_vvms/vaxsym.h b/sr_vvms/vaxsym.h
new file mode 100644
index 0000000..ffe6021
--- /dev/null
+++ b/sr_vvms/vaxsym.h
@@ -0,0 +1,19 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+#ifndef VAXSYM_H_INCLUDED
+#define VAXSYM_H_INCLUDED
+
+/* Maximum size of an package or external routine reference of the form routine^label */
+#define MAX_EXTREF (2 * MAX_MIDENT_LEN + STR_LIT_LEN("^"))
+#define ZCSYM_PREFIX "__GTM$ZC"
+#define MAX_SYMREF SIZEOF(ZCSYM_PREFIX) + 2 * MAX_EXTREF /* __GTM$ZC<package>.<extref> */
+
+#endif /* VAXSYM_H_INCLUDED */
diff --git a/sr_vvms/vms_cms_load.com b/sr_vvms/vms_cms_load.com
new file mode 100644
index 0000000..350a0e6
--- /dev/null
+++ b/sr_vvms/vms_cms_load.com
@@ -0,0 +1,211 @@
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$! !
+$! Copyright 2001, 2005 Fidelity Information Services, Inc !
+$! !
+$! This source code contains the intellectual property !
+$! of its copyright holder(s), and is made available !
+$! under a license. If you do not know the terms of !
+$! the license, please stop and do not read further. !
+$! !
+$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+$!
+$! This DCL command file fetches a version of GT.M and GT.CM (GDP) from the CMS libraries
+$! into the appropriate VMS source directory.
+$!
+$! p1 - "to version", version of GT.M to populate on the target platform
+$! p2 - name of the platform (e.g., CETUS, ASGARD, etc.)
+$! p3 - CMS library specification for the target platform (e.g., S_VMS, S_AVMS, etc.)
+$! p4 - ignored, only used by UNIX_CMS_LOAD.COM
+$! p5 - "from version", version of GT.M to fetch from the CMS libraries
+$!
+$ set verify
+$ set noon
+$ interact = (f$mode() .eqs. "INTERACTIVE")
+$!
+$ if ( p1 .eqs. "" )
+$ then
+$! N.B., there is no need to download V9.9-0 on VMS targets.
+$ write sys$output "%CMS_LOAD-E-NOPARAM, Must provide a Version"
+$ if ( interact )
+$ then
+$ inquire "Version ",p1
+$ endif
+$ if ( p1 .eqs. "" )
+$ then
+$ write sys$output "No action taken"
+$ exit
+$ endif
+$ endif
+$ to_version = ''p1'
+$!
+$ if ( (p2 .nes. "ASGARD") .and. (p2 .nes. "ALPHA2") .and. (p2 .nes. "CETUS") .and. (p2 .nes. "WIGLAF") )
+$ then
+$ write sys$putput "%CMS_LOAD-E-NOTARGET, Must provide a Platform"
+$ if ( interact )
+$ then
+$ inquire "Platform ",p2
+$ endif
+$ if ( (p2 .nes. "ASGARD") .and. (p2 .nes. "ALPHA2") .and. (p2 .nes. "CETUS") .and. (p2 .nes. "WIGLAF") )
+$ then
+$ write sys$output "No action taken"
+$ exit
+$ endif
+$ endif
+$!
+$ dirname = to_version - "." - "-"
+$ if ( dirname .eqs. "V990" )
+$ then
+$ write sys$output "%CMS_LOAD-E-V990, Cannot download to V9.9-0 on VMS"
+$ exit
+$ endif
+$!
+$ device = f$trnlnm("gtm$gtmdev")
+$ if ( f$locate("_",device) .eq. f$length(device) )
+$ then
+$ device := gtm$gtmdev
+$ endif
+$!
+$ if ( (p2 .eqs. "ASGARD") .or. (p2 .eqs. "ALPHA2") .or. (p2 .eqs. "WIGLAF") )
+$ then
+$ type := AXP
+$ endif
+$!
+$ if ( p2 .eqs. "CETUS" )
+$ then
+$ type := VAX
+$ endif
+$!
+$ toolsdir = "user:[library.''dirname'.tools]"
+$!
+$ version 'dirname' p
+$ if ( f$trnlnm("gtm$verno") .nes. dirname )
+$ then
+$ write sys$output "%CMS_LOAD-E-VERSIONFAIL, Version command failed"
+$ exit
+$ endif
+$!
+$! set default gtm$vrt:[src]
+$ if ( type .eqs. "VAX")
+$ then
+$ set default 'type'_gtm$gtmdev:[library.'dirname'.src]
+$ else
+$! 'type'_gtm$gtmdev should ideally be used here, but it is a search list and edrelnam fails for search lists
+$! in fetch_cms_version.com. hence using alternate "user" logical.
+$ set default user:[library.'dirname'.src]
+$ endif
+$!
+$! clean up the source directory
+$ if ( f$search("*.c") .nes. "" )
+$ then
+$ delete/log *.*;*/exclude=(maclib.mlb)
+$ endif
+$!
+$ rename/log maclib.mlb; maclib.mlb;1
+$!
+$ if ( p3 .eqs. "" )
+$ then
+$ if ( type .eqs. "AXP" )
+$ then
+$ p3 = S_AVMS
+$ endif
+$ if ( type .eqs. "VAX" )
+$ then
+$ p3 = S_VMS
+$ endif
+$ endif
+$!
+$ @'toolsdir'cms_load_verify_from_to_version 'to_version' 'p5'
+$ if ( $status .ne. 1 )
+$ then
+$ exit $status
+$ endif
+$!
+$ t1 = "=" + from_version
+$ if (f$extract(0, 3, from_version) .eqs. "V9.") .or. ("NEXT" .eqs. from_version) then $ t1 :=
+$ cms set library sl_cmi
+$ cms fetch cmierrors.msg /generation't1' ""
+$ @'toolsdir'fetch_cms_version 'from_version' 'p3'
+$ @'toolsdir'fetch_cms_version 'from_version' S_VMS_CM
+$ set def [-]
+$!
+$! -----------------------------------------------------------------------------
+$! download the CMI sources onto gtm$vrt:[cmi] directory
+$! -----------------------------------------------------------------------------
+$ if ( f$search("cmi.dir") .eqs. "" )
+$ then
+$ create/dir [.cmi]
+$ else
+$ set def [.cmi]
+$ delete/log *.*;*
+$ set def [-]
+$ endif
+$ set def [.cmi]
+$ @'toolsdir'fetch_cms_version 'from_version' SL_CMI
+$ set def [-]
+$!
+$! ----------------------------------------------------------------------------------
+$! move kit building stuff into gtm$vrt:[tcm,tcx,tdp,tfi,tls,tdc] directories
+$! ----------------------------------------------------------------------------------
+$ set def [.tcm]
+$ rename/log [-.src]GTCMKITHLP.COM []
+$ rename/log [-.src]GTCM_SPKITBLD.DAT []
+$ rename/log [-.src]GTCMKITINSTAL.COM []KITINSTAL.COM
+$ set def [-]
+$ set def [.tcx]
+$ rename/log [-.src]GTCXKITHLP.COM []
+$ rename/log [-.src]GTCX_SPKITBLD.DAT []
+$ rename/log [-.src]GTCXKITINSTAL.COM []KITINSTAL.COM
+$ set def [-]
+$ set def [.tdp]
+$ rename/log [-.src]DDPKITHLP.COM []
+$ rename/log [-.src]DDP_SPKITBLD.DAT []
+$ rename/log [-.src]DDPKITINSTAL.COM []KITINSTAL.COM
+$ set def [-]
+$ set def [.tdc]
+$ rename/log [-.src]GTMDCKITHLP.COM []
+$ rename/log [-.src]GTMDC_SPKITBLD.DAT []
+$ rename/log [-.src]GTMDCKITINSTAL.COM []KITINSTAL.COM
+$ set def [-]
+$ set def [.tfi]
+$ rename/log [-.src]GTMFIKITHLP.COM []
+$ rename/log [-.src]GTMFI_SPKITBLD.DAT []
+$ rename/log [-.src]GTMFIKITINSTAL.COM []KITINSTAL.COM
+$ set def [-]
+$ set def [.tls]
+$ rename/log [-.src]GTMKITHLP.COM []
+$ rename/log [-.src]GTM_SPKITBLD.DAT []
+$ rename/log [-.src]GTMKITINSTAL.COM []KITINSTAL.COM
+$ rename/log [-.src]GTM$IVP.TLB []
+$ rename/log [-.src]GTM$CE.H []
+$ copy/log [-.src]GTM$DEFAULTS.M64 [] ! gtm$src copy is used by the build so take only a copy
+$ rename/log [-.src]GTMCOLLECT.OPT []
+$ set def [-]
+$!
+$! -----------------------------------------------------------------------------
+$! move scripts into gtm$vrt:[tools] directory
+$! -----------------------------------------------------------------------------
+$ set def [.tools]
+$ rename/log [-.src]*.com []
+$ rename/log [-.src]*.axp []
+$ rename/log [-.src]*.awk []
+$ purge/log *.*/(excl=vms_cms_load.com,cms_load.com) ! remove versions of *.com files copied over by newincver.com
+$ ! except cms_load.com and vms_cms_load.com as they are the currently running scripts
+$ set def [-]
+$!
+$! -----------------------------------------------------------------------------
+$! edit gtm$vrt:[t%%]*_spkitbld.dat version ids
+$! -----------------------------------------------------------------------------
+$ set def [.src]
+$ ver p p
+$ curr_priv = f$setprv("bypas")
+$ gtma := $ gtm$exe:gtm$dmod.exe
+$ define/user gtm$routines "[]/src=(gtm$root:[''dirname'.src],gtm$root:[''dirname'.pct])"
+$ gtma "user:[library.''dirname']"
+d ^spkitbld
+$ curr_priv=f$setprv(curr_priv)
+$ delete/nolog/since spkitbld.obj.,_ucase.obj.
+$!
+$! write sys$output "Please review the version ids in gtm$vrt:[t%%]*_spkitbld.dat"
+$! write sys$output "Please edit GTMSRC.COM and README.TXT as appropriate"
+$!
+$ exit
diff --git a/sr_vvms/vmsdtype.h b/sr_vvms/vmsdtype.h
new file mode 100644
index 0000000..8027d91
--- /dev/null
+++ b/sr_vvms/vmsdtype.h
@@ -0,0 +1,29 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2002 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef VMSDTYPE_H_INCLUDED
+#define VMSDTYPE_H_INCLUDED
+
+#pragma member_alignment save
+#pragma nomember_alignment
+
+/* user-defined VMS 'conceptual' data type */
+typedef struct
+{ unsigned short int buffer_length;
+ unsigned short int item_code;
+ void *buffer_address;
+ void *return_length_address; /* some system services expect this to be short * (eg. sys$getsyi), but
+ * some expect this to be a int4 * (eg. sys$getlki). Hence, we use void * */
+} item_list_3;
+
+#pragma member_alignment restore
+
+#endif /* VMSDTYPE_H_INCLUDED */
diff --git a/sr_vvms/wait_for_block_flush.c b/sr_vvms/wait_for_block_flush.c
new file mode 100644
index 0000000..4e4f162
--- /dev/null
+++ b/sr_vvms/wait_for_block_flush.c
@@ -0,0 +1,42 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* This function is called from t_qread to wait out a "flushing" state.
+ It assumes that the database is clustered. */
+
+#include "mdef.h"
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "ccp.h"
+#include "filestruct.h"
+
+GBLREF sgmnt_addrs *cs_addrs;
+GBLREF gd_region *gv_cur_region;
+
+void wait_for_block_flush(bt_rec *bt, block_id block)
+{
+ register sgmnt_addrs *csa;
+ unsigned short cycle;
+
+ csa = cs_addrs;
+ assert(csa->hdr->clustered);
+
+ for (;(bt->blk == block) && bt->flushing && !CCP_SEGMENT_STATE(csa->nl,CCST_MASK_HAVE_DIRTY_BUFFERS);)
+ { /* as int4 as the bt and block match, the bt shows flushing, and the ccp state indicates */
+ cycle = csa->nl->ccp_cycle;
+ CCP_FID_MSG(gv_cur_region, CCTR_FLUSHLK);
+ ccp_userwait(gv_cur_region, CCST_MASK_HAVE_DIRTY_BUFFERS, 0, cycle);
+ }
+ return;
+}
diff --git a/sr_vvms/wcs_clean_dbsync_ast.c b/sr_vvms/wcs_clean_dbsync_ast.c
new file mode 100644
index 0000000..ae5e656
--- /dev/null
+++ b/sr_vvms/wcs_clean_dbsync_ast.c
@@ -0,0 +1,306 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <stddef.h> /* for offsetof macro */
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "gdskill.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h" /* for the FILE_INFO macros */
+#include "jnl.h"
+#include "iosp.h"
+#include "efn.h" /* for efn_immed_wait and efn_ignore */
+#include "gdsbgtr.h" /* for the BG_TRACE_PRO_ANY macros */
+#include "timers.h" /* for TIM_AST_WAIT */
+#include "wcs_phase2_commit_wait.h"
+
+#define MAX_DBSYNC_DEFERS 10 /* 10 times deferring of 5 sec (TIM_DEFER_DBSYNC) each for a total of 50 seconds */
+#define MAX_DBSYNC_LOOPS 600 /* each loop is of 5msec and we wait for a max. of 30 seconds */
+
+#ifdef GTM_MALLOC_RENT
+# define GTM_MALLOC_NO_RENT_ONLY(X)
+#else
+# define GTM_MALLOC_NO_RENT_ONLY(X) X
+#endif
+
+GBLDEF int4 defer_dbsync[2] = { TIM_DEFER_DBSYNC, -1 }; /* picked from timers.h */
+
+GBLREF gd_region *gv_cur_region;
+GBLREF int4 wtfini_in_prog;
+GBLREF short astq_dyn_avail;
+GBLREF volatile int4 gtmMallocDepth; /* Recursion indicator */
+GBLREF uint4 process_id;
+GBLREF boolean_t mupip_jnl_recover;
+GBLREF jnl_gbls_t jgbl;
+GBLREF volatile int4 fast_lock_count;
+GBLREF volatile int4 crit_count;
+GBLREF volatile boolean_t in_mutex_deadlock_check;
+
+error_def(ERR_JNLFLUSH);
+error_def(ERR_TEXT);
+
+/* Sync the filehdr (and epoch in the journal file if before imaging). The goal is to sync the database,
+ * but if we find us in a situation where we need to block on someone else, then we defer this to the next round.
+ * This is the equivalent of the Unix wcs_clean_dbsync() routine.
+ */
+void wcs_clean_dbsync_ast(sgmnt_addrs *csa)
+{
+ static readonly int4 pause[2] = { TIM_AST_WAIT, -1 }; /* picked from wcs_timer_start */
+ boolean_t bimg_jnl, dbsync_defer_timer; /* bimg_jnl --> before-imaging or not */
+ cache_que_head *crqwip;
+ int counter, status;
+ gd_region *reg;
+ jnl_private_control *jpc;
+ jnl_buffer_ptr_t jb;
+ node_local_ptr_t cnl;
+ sgmnt_addrs *save_csa;
+ sgmnt_data_ptr_t csd;
+ void fileheader_sync();
+ uint4 jnl_status;
+
+ assert(lib$ast_in_prog()); /* If dclast fails and setast is used, this assert trips, but in that
+ * case, we anyway want to know why we needed setast. */
+ /* Although csa->dbsync_timer is almost always TRUE if here, there is a small possibility it is FALSE. This is
+ * possible if we are currently in gds_rundown for this region where the flag is reset to FALSE irrespective
+ * of whether we have a pending timer or a sys$qio-termination-signalling-ast. In the case dbsync_timer is
+ * FALSE, return. There is a very remote possibility that we miss syncing the db if the qio of the last
+ * dirty buffer finishes after we die and we are not the last writer. In this case the sync won't be done
+ * since all the maintenance is process-private. But that possibility is too remote and we will live with
+ * it for now since otherwise we need to implement grander mechanisms involving shared memory and the like.
+ */
+ reg = csa->region;
+ assert(FALSE == csa->dbsync_timer || reg->open);
+ /* Don't know how this can happen, but if region is closed, just return in PRO */
+ /* In MM, not yet sure whether it will work */
+ if (FALSE == csa->dbsync_timer || dba_mm == reg->dyn.addr->acc_meth || !reg->open)
+ {
+ csa->dbsync_timer = FALSE;
+ astq_dyn_avail++;
+ return;
+ }
+ /* Save to see if we are in crit anywhere */
+ save_csa = ((NULL == gv_cur_region || FALSE == gv_cur_region->open) ? NULL : (&FILE_INFO(gv_cur_region)->s_addrs));
+ csa = &FILE_INFO(reg)->s_addrs;
+ csd = csa->hdr;
+ cnl = csa->nl;
+ jpc = csa->jnl;
+ BG_TRACE_PRO_ANY(csa, n_dbsync_timers);
+ assert(!JNL_ALLOWED(csd) || NULL != jpc);
+
+ /* Note that even if the active queue was emptied when this routine was called, due to
+ * concurrent update activity, cnl->wcs_active_lvl can be non-zero when we reach here. We
+ * defer syncing the database in this case to the next time the active queue becomes empty or
+ * when we reach the next scheduled epoch_time (only if before-imaging) whichever is earlier.
+ */
+ dbsync_defer_timer = FALSE;
+ if (!cnl->wcs_active_lvl)
+ { /* Currently VMS timer writes don't have the optimizations for deferring expensive IO at
+ * critical times that exist in Unix. Need to get them (those that apply) to VMS too. They are
+ * 1) We are in the midst of lseek/read/write IO. This could reset an lseek. (Doesn't apply to VMS).
+ * 2) We are aquiring/releasing crit in any region (Strictly speaking it is enough
+ * to check this in the current region, but doesn't harm us much).
+ * Note that the function "mutex_deadlock_check" resets crit_count to 0 temporarily even though we
+ * might actually be in the midst of acquiring crit. Therefore we should not interrupt mainline code
+ * if we are in the "mutex_deadlock_check" as otherwise it presents reentrancy issues.
+ * 3) We have crit in the current region OR are in the middle of commit for this region (even though
+ * we dont hold crit) OR are in wcs_wtstart (potentially holding write interlock and keeping another
+ * process in crit waiting) OR we need to wait to obtain crit.
+ * 4) We are in a "fast lock".
+ * Out of the above, items (2) & (3) are currently being taken care of below since they can cause
+ * deadlocks (if not taken care of) while the others are just performance enhancements. Note
+ * that the last part of (3) is taken care of by doing a grab_crit_immediate() rather than a grab_crit().
+ * Also to be taken care of are the following situations.
+ * 1) We are currently in wcs_wtfini be it the same or a different region.
+ * To avoid reentrancy issues (if same region) and deadlock issues (if different region).
+ * 2) We are currently in malloc(). Although nested malloc() now works and we won't be needing it
+ * as much, want to be paranoid here since there are quite a few functions called from here.
+ * Other reentrancy issues to be taken care of are
+ * 1) Avoid doing recursive wcs_recovers.
+ */
+ dbsync_defer_timer = TRUE;
+ crqwip = &csa->acc_meth.bg.cache_state->cacheq_wip;
+ if (!mupip_jnl_recover && 0 == crit_count && !in_mutex_deadlock_check && !wtfini_in_prog && !fast_lock_count
+ GTM_MALLOC_NO_RENT_ONLY(&& 0 == gtmMallocDepth)
+ && ((NULL == save_csa) || !T_IN_CRIT_OR_COMMIT_OR_WRITE(save_csa))
+ && !T_IN_CRIT_OR_COMMIT_OR_WRITE(csa)
+ && (TRUE == grab_crit_immediate(reg)))
+ { /* Note that if we are here, we have obtained crit using grab_crit_immediate. Also grab_crit_immediate
+ * doesn't call wcs_recover if wc_blocked is TRUE in order to prevent possible deadlocks.
+ * Note that mutex_lockwim() cannot be used since crit_count is not maintained there.
+ */
+ assert(csa->ti->early_tn == csa->ti->curr_tn);
+ /* if wcs_wtfini() returns FALSE, it means the cache is suspect. but we are in interrupt code
+ * and therefore want to play it safe. Hence we will not set wc_blocked. we will defer writing
+ * epoch and wait for a future call to mainline code to detect this and initiate cache recovery.
+ */
+ /* Wait for ALL active phase2 commits to complete first. If they dont complete in time then defer
+ * writing the epoch. Also dont wait if cnl->wc_blocked is already set to TRUE. In that case
+ * defer writing the EPOCH unconditionally. */
+ if (!cnl->wc_blocked && (!cnl->wcs_phase2_commit_pidcnt || wcs_phase2_commit_wait(csa, NULL))
+ && wcs_wtfini(reg)) /* wcs_wtfini handles calls from ASTs appropriately */
+ {
+ if (JNL_ENABLED(csd))
+ {
+ jb = jpc->jnl_buff;
+ if (jb->before_images)
+ bimg_jnl = TRUE;
+ } else
+ bimg_jnl = FALSE;
+ /* Note that if before-imaging and we haven't opened the journal file, then we
+ * can't write an epoch record here because opening the jnl file involves a
+ * heavyweight routine jnl_file_open() which is risky in this ast-prone code.
+ * Also, if before-imaging and the journal file has been switched since the time the
+ * dbsync timer started, we do not want to do any writes as they will go to the older
+ * generation journal file. It is ok not to write an EPOCH record in the older generation
+ * journal file because whichever process did the journal file switch would have done
+ * exactly that. And therefore there is no need to start a new dbsync timer in this case.
+ */
+ if (cnl->wcs_active_lvl || bimg_jnl && ((NOJNL == jpc->channel) || JNL_FILE_SWITCHED(jpc)))
+ dbsync_defer_timer = FALSE; /* don't/can't write epoch. */
+ else if (0 == crqwip->fl)
+ {
+ if (!bimg_jnl)
+ { /* Entire wip queue is flushed. So sync the file-header now */
+ assert(cnl->wc_in_free == csd->n_bts);
+ BG_TRACE_PRO_ANY(csa, n_dbsync_writes);
+ fileheader_sync(reg); /* sync the fileheader to disk */
+ dbsync_defer_timer = FALSE;
+ } else if (jb->dskaddr == jb->freeaddr)
+ { /* Entire wip queue and jnl buffer is flushed. So write an epoch record now. */
+ assert(cnl->wc_in_free == csd->n_bts);
+ BG_TRACE_PRO_ANY(csa, n_dbsync_writes);
+ fileheader_sync(reg); /* sync the fileheader to disk */
+ /* To avoid deadlocks (e.g. we waiting for a jnl_flush while someone
+ * is holding the io_in_prog lock) we use a kludge. Setting jb->blocked
+ * prevents others from picking up the io_in_prog lock. We then check
+ * whether there is anyone holding the lock. If so, we defer writing the
+ * epoch to the next round and if not go ahead with the flush. Note that
+ * "someone" above includes ourselves too since the qio we have done prior
+ * to entering wcs_wipchk_ast will again be delivered as a jnl_qio_end AST
+ * which will again be blocked.
+ */
+ jb->blocked = process_id;
+ if (!jb->io_in_prog)
+ {
+ assert(NOJNL != jpc->channel);
+ /* Since the journal buffer is flushed to disk at this point
+ * we don't expect any other routines (like jnl_write_attempt etc.)
+ * to be called. Also since the epoch-record is less than a hundred
+ * bytes, we don't expect a jnl_qio_start to be called at the end
+ * of jnl_write(). We also assume that the check for extension of
+ * journal file takes into account space for an epoch + eof + align.
+ * Note that the assert below checks that the min_write_size (the value
+ * needed to trigger a jnl_qio_write) is less than the maximum number of
+ * bytes that will be written in the journal buffer by jnl_write_epoch_rec
+ * (= size of the epoch record + maximum size of align record if needed).
+ */
+ /* Is there a correctness issue if the file gets extended? The assumption
+ * about space check for epoch + eof + align may not be correct. Also,
+ * now we may be writing a PINI as well. Vinaya, 2003, May 2. Check with
+ * Narayanan */
+ assert(2 * EPOCH_RECLEN + PINI_RECLEN + 3 * MIN_ALIGN_RECLEN <
+ jb->min_write_size);
+ assert(csa->ti->curr_tn == csa->ti->early_tn);
+ /* There is no need for jnl_ensure_open here since we have crit and
+ * have already determined that the journal file has not been switched.
+ */
+ /* Initialize gbl_jrec_time if necessary before jnl_put_jrt_pini */
+ if (!jgbl.dont_reset_gbl_jrec_time)
+ SET_GBL_JREC_TIME;
+ /* Before writing to jnlfile, adjust jgbl.gbl_jrec_time (if needed) to
+ * maintain time order of jnl records. This needs to be done BEFORE
+ * writing any records to the journal file.
+ */
+ ADJUST_GBL_JREC_TIME(jgbl, jb);
+ if (0 == jpc->pini_addr)
+ {/* in the rare case when we haven't done any updates to the db (till
+ * now only db reads), but had to flush the jnl buffer and cache due to
+ * lack of cache buffer (flush trigger mechanism in t_qread) we may not
+ * have written our PINI record yet */
+ jnl_put_jrt_pini(csa);
+ }
+ jnl_write_epoch_rec(csa);
+ INCR_GVSTATS_COUNTER(csa, cnl, n_jrec_epoch_idle, 1);
+ /* Need to flush this epoch record out */
+ jnl_status = jnl_flush(reg); /* handles calls from ASTs appropriately */
+ if (SS_NORMAL == jnl_status)
+ {
+ assert(jb->dskaddr == jb->freeaddr);
+ dbsync_defer_timer = FALSE;
+ assert(0 == jb->blocked); /* jnl_flush should have reset this.*/
+ if (process_id == jb->blocked)
+ jb->blocked = 0;
+ } else
+ {
+ send_msg(VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(csd),
+ ERR_TEXT, 2,
+ RTS_ERROR_TEXT("Error with journal flush in wcsdbsyncast"),
+ jnl_status);
+ assert(NOJNL == jpc->channel);/* jnl file lost has been triggered */
+ /* In this routine, all code that follows from here on does not
+ * assume anything about the journaling characteristics of this
+ * database so it is safe to continue execution even though
+ * journaling got closed in the middle.
+ */
+ }
+ } else
+ jb->blocked = 0;
+ } else
+ jnl_start_ast(jpc); /* Start a journal write and defer epoch writing. */
+ }
+ }
+ rel_crit(reg);
+ }
+ }
+ if (FALSE != dbsync_defer_timer)
+ {
+ for (counter = 0; 1 > astq_dyn_avail; counter++)
+ { /* Wait until we have room to queue our timer AST for wcs_clean_dbsync_ast. */
+ assert(FALSE);
+ if (SS$_NORMAL == sys$setimr(efn_timer_ast, &pause, 0, 0, 0))
+ sys$synch(efn_timer_ast, 0);
+ if (counter > MAX_DBSYNC_LOOPS)
+ {
+ csa->dbsync_timer = FALSE;
+ astq_dyn_avail++;
+ return; /* in this case, we skip syncing the db. */
+ }
+ }
+ astq_dyn_avail--;
+ if (MAX_DBSYNC_DEFERS > csa->dbsync_timer++)
+ {
+ status = sys$setimr(efn_ignore, &defer_dbsync[0], wcs_clean_dbsync_ast, csa, 0);
+ if (0 == (status & 1))
+ {
+ assert(FALSE);
+ csa->dbsync_timer = FALSE;
+ astq_dyn_avail++; /* in this case too, we skip syncing the db. */
+ }
+ } else
+ { /* We have deferred the dbsync timer at least MAX_DBSYNC_DEFERS times (nearly 50 seconds). We cannot keep
+ * doing this indefinitely as it is possible that whatever is causing us to defer this timer (crit_count
+ * being non-zero etc.) is in turn blocked because it needs a timer queue entry but cannot find one due
+ * to wcs_clean_dbsync_ast eternally using up the same (eats up the TQELM job/process quota). Therefore
+ * to avoid a potential deadlock, we stop requeueing ourselves even though it means we will skip syncing
+ * the db. The only one that cares for this dbsync is journal recovery which anyways has been worked around
+ * to take care of indefinite deferring (equivalent to skipping the syncing) so that should not be an issue.
+ */
+ csa->dbsync_timer = FALSE; /* in this case, we skip syncing the db. */
+ }
+ } else
+ csa->dbsync_timer = FALSE;
+ astq_dyn_avail++;
+ return;
+}
diff --git a/sr_vvms/wcs_clean_dbsync_timer_ast.c b/sr_vvms/wcs_clean_dbsync_timer_ast.c
new file mode 100644
index 0000000..b70bf9e
--- /dev/null
+++ b/sr_vvms/wcs_clean_dbsync_timer_ast.c
@@ -0,0 +1,57 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "gdskill.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "efn.h" /* for efn_ignore */
+
+GBLREF int4 defer_dbsync[2];
+GBLREF short astq_dyn_avail;
+
+/* wcs_clean_dbsync_ast() is not directly being called when the active queue becomes empty. This is because
+ * we want to avoid syncing the database, in the case where it is actively being updated though frequently
+ * getting emptied (by something other than a wcs_flu). Only in the case where there is prolonged update
+ * inactivity after emptying the active queue do we sync the db. "prolonged" is defined by TIM_DEFER_DBSYNC.
+ */
+void wcs_clean_dbsync_timer_ast(sgmnt_addrs *csa)
+{
+ int status;
+ void wcs_clean_dbsync_ast();
+
+ assert(lib$ast_in_prog()); /* If dclast fails and setast is used, this assert trips, but in that
+ * case, we anyway want to know why we needed setast. */
+ assert(0 < astq_dyn_avail);
+ if (0 >= astq_dyn_avail)
+ csa->dbsync_timer = FALSE;
+ /* Note that csa->dbsync_timer can be FALSE while entering this routine in case we had issued the dsk_write (sys$qio)
+ * of the last dirty cache-record and then went to gds_rundown() which resets the dbsync_timer to FALSE unconditionally.
+ * In this case, we need to return.
+ */
+ if (FALSE == csa->dbsync_timer)
+ {
+ astq_dyn_avail++;
+ return;
+ }
+ status = sys$setimr(efn_ignore, &defer_dbsync[0], wcs_clean_dbsync_ast, csa, 0);
+ if (0 == (status & 1))
+ {
+ assert(FALSE);
+ csa->dbsync_timer = FALSE;
+ astq_dyn_avail++; /* in this case too, we skip syncing the database */
+ }
+ return;
+}
diff --git a/sr_vvms/wcs_flu.c b/sr_vvms/wcs_flu.c
new file mode 100644
index 0000000..0266d9d
--- /dev/null
+++ b/sr_vvms/wcs_flu.c
@@ -0,0 +1,296 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <ssdef.h>
+#include <psldef.h>
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsbgtr.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "ast.h"
+#include "efn.h"
+#include "jnl.h"
+#include "iosp.h"
+#include "sleep_cnt.h"
+#include "send_msg.h"
+#include "wcs_recover.h"
+#include "wcs_sleep.h"
+#include "wcs_flu.h"
+#include "wcs_phase2_commit_wait.h"
+#include "wbox_test_init.h"
+#include "memcoherency.h"
+
+GBLREF gd_region *gv_cur_region;
+GBLREF uint4 process_id;
+GBLREF sgmnt_addrs *cs_addrs;
+GBLREF jnl_gbls_t jgbl;
+GBLREF bool in_backup;
+#ifdef DEBUG
+GBLREF boolean_t in_mu_rndwn_file;
+#endif
+
+error_def(ERR_DBFILERR);
+error_def(ERR_JNLFILOPN);
+error_def(ERR_JNLFLUSH);
+error_def(ERR_TEXT);
+error_def(ERR_WCBLOCKED);
+
+static const unsigned short zero_fid[3];
+
+boolean_t wcs_flu(uint4 options)
+{
+ bool broken, ret, was_crit;
+ boolean_t jnl_enabled, flush_hdr, write_epoch, sync_epoch, in_commit;
+ cache_que_head *crq, *crqwip;
+ cache_rec *cr, *crtop;
+ file_control *fc;
+ sgmnt_addrs *csa;
+ sgmnt_data *csd;
+ short iosb[4];
+ uint4 jnl_status;
+ unsigned int lcnt1, lcnt2, lcnt3, pass, status;
+ jnl_private_control *jpc;
+ jnl_buffer_ptr_t jbp;
+ node_local_ptr_t cnl;
+# ifdef DEBUG
+ cache_que_head lclwip, lclact;
+ cache_rec lclcr;
+# endif
+
+ flush_hdr = options & WCSFLU_FLUSH_HDR;
+ write_epoch = options & WCSFLU_WRITE_EPOCH;
+ sync_epoch = options & WCSFLU_SYNC_EPOCH;
+ /* WCSFLU_IN_COMMIT bit is set if caller is t_end or tp_tend. In that case, we should NOT invoke wcs_recover if we
+ * encounter an error. Instead we should return the error as such so they can trigger appropriate error handling.
+ * This is necessary because t_end and tp_tend could have pinned one or more cache-records (cr->in_cw_set non-zero)
+ * BEFORE invoking wcs_flu. And code AFTER the wcs_flu in them relies on the fact that those cache records stay
+ * pinned. If wcs_flu invokes wcs_recover, it will reset cr->in_cw_set to 0 for ALL cache-records so code AFTER
+ * the wcs_flu in the caller will fail because no buffer is pinned at that point.
+ */
+ in_commit = options & WCSFLU_IN_COMMIT;
+ csa = &(FILE_INFO(gv_cur_region)->s_addrs);
+ csd = csa->hdr;
+ cnl = csa->nl;
+ assert(cnl->glob_sec_init);
+ INCR_GVSTATS_COUNTER(csa, cnl, n_db_flush, 1);
+ if (!(was_crit = csa->now_crit)) /* Caution: assignment */
+ grab_crit(gv_cur_region);
+ if (dba_mm == csa->hdr->acc_meth)
+ {
+ if (SS$_NORMAL == (ret = sys$updsec(csa->db_addrs, NULL, PSL$C_USER, 0, efn_immed_wait, iosb, NULL, 0)))
+ {
+ sys$synch(efn_immed_wait, iosb);
+ ret = iosb[0];
+ } else if (SS$_NOTMODIFIED == ret)
+ ret = SS$_NORMAL;
+ if (!was_crit)
+ rel_crit(gv_cur_region);
+ return (SS$_NORMAL == ret);
+ }
+ cnl->wcsflu_pid = process_id;
+ assert(dba_bg == csa->hdr->acc_meth);
+ /* Worry about journaling only if JNL_ENABLED and if journal has been opened in shared memory */
+ jnl_enabled = (JNL_ENABLED(csa->hdr) && (0 != memcmp(cnl->jnl_file.jnl_file_id.fid, zero_fid, SIZEOF(zero_fid))));
+ if (jnl_enabled)
+ {
+ jpc = csa->jnl;
+ jbp = jpc->jnl_buff;
+ /* 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)
+ SET_GBL_JREC_TIME; /* needed before jnl_ensure_open */
+ /* Before writing to jnlfile, adjust jgbl.gbl_jrec_time (if needed) to maintain time order of jnl
+ * records. This needs to be done BEFORE the jnl_ensure_open as that could write journal records
+ * (if it decides to switch to a new journal file)
+ */
+ ADJUST_GBL_JREC_TIME(jgbl, jbp);
+ assert(csa == cs_addrs); /* for jnl_ensure_open */
+ jnl_status = jnl_ensure_open();
+ if (0 != jnl_status)
+ {
+ assert(ERR_JNLFILOPN == jnl_status);
+ cnl->wcsflu_pid = 0;
+ if (!was_crit)
+ rel_crit(gv_cur_region);
+ send_msg(VARLSTCNT(6) jnl_status, 4, JNL_LEN_STR(csd), DB_LEN_STR(gv_cur_region));
+ return FALSE;
+ }
+ assert(NOJNL != jpc->channel);
+ if (SS_NORMAL != (jnl_status = jnl_flush(gv_cur_region)))
+ {
+ assert(NOJNL == jpc->channel); /* jnl file lost */
+ if (!was_crit)
+ rel_crit(gv_cur_region);
+ send_msg(VARLSTCNT(9) ERR_JNLFLUSH, 2, JNL_LEN_STR(csd),
+ ERR_TEXT, 2, RTS_ERROR_TEXT("Error with journal flush during wcs_flu"),
+ jnl_status);
+ return FALSE;
+ }
+ }
+ /* If not mupip rundown, wait for ALL active phase2 commits to complete first.
+ * In case of mupip rundown, we know no one else is accessing shared memory so no point waiting.
+ */
+ assert(!in_mu_rndwn_file || (0 == cnl->wcs_phase2_commit_pidcnt));
+ if (cnl->wcs_phase2_commit_pidcnt && !wcs_phase2_commit_wait(csa, NULL))
+ {
+ if (!was_crit)
+ rel_crit(gv_cur_region);
+ return FALSE; /* we expect the caller to trigger cache-recovery which will fix this counter */
+ }
+ /* Now that all concurrent commits are complete, wait for these dirty buffers to be flushed to disk. */
+ crq = &csa->acc_meth.bg.cache_state->cacheq_active;
+ crqwip = &csa->acc_meth.bg.cache_state->cacheq_wip;
+ for (pass = 1, ret = FALSE; FALSE == ret; pass++)
+ {
+ for (lcnt1 = DIVIDE_ROUND_UP(csd->n_bts, csd->n_wrt_per_flu); (0 != crq->fl); lcnt1--)
+ { /* attempt to clear the active queue */
+ if (SS$_NORMAL != (status = sys$dclast(wcs_wtstart, gv_cur_region, 0)))
+ {
+ send_msg(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region), status);
+ assert(FALSE);
+ status = sys$setast(DISABLE);
+ wcs_wtstart(gv_cur_region);
+ if (SS$_WASSET == status)
+ ENABLE_AST;
+ }
+ if (!wcs_wtfini(gv_cur_region) || (0 == lcnt1))
+ break;
+ }
+ assert((1 == pass) || (0 == cnl->in_wtstart)); /* in second pass there should be no active writers */
+ /* Wait for all active writers to finish. We wait for 1 minute (similar to code in wcs_recover) */
+ SIGNAL_WRITERS_TO_STOP(cnl); /* to stop all active writers */
+ WAIT_FOR_WRITERS_TO_STOP(cnl, lcnt2, MAXWTSTARTWAIT);
+ SIGNAL_WRITERS_TO_RESUME(cnl);
+ /* Attempt to clear the wip queue and double check that all is well */
+ cr = &csa->acc_meth.bg.cache_state->cache_array;
+ cr += csd->bt_buckets;
+ crtop = cr + csd->n_bts;
+ for (lcnt3 = 0, broken = FALSE; FALSE == ret; )
+ {
+ for ( ; cr < crtop; cr++)
+ { /* check that nothing is dirty */
+ if (cr->dirty)
+ {
+ broken = TRUE;
+ if (0 != crqwip->fl)
+ {
+ broken = ((!wcs_wtfini(gv_cur_region)) ? TRUE : FALSE);
+ assert(FALSE == broken);
+ if ((FALSE == broken) && !cr->dirty)
+ continue;
+ }
+ if (0 != crq->fl)
+ {
+ broken = FALSE;
+ if (SS$_NORMAL != (status = sys$dclast(wcs_wtstart, gv_cur_region, 0)))
+ {
+ send_msg(VARLSTCNT(5) ERR_DBFILERR, 2, DB_LEN_STR(gv_cur_region), status);
+ assert(FALSE);
+ status = sys$setast(DISABLE);
+ wcs_wtstart(gv_cur_region);
+ if (SS$_WASSET == status)
+ ENABLE_AST;
+ }
+ }
+ /* This means we found a dirty cache-record that is neither in the active or wip queue.
+ * This is possible in the following situations.
+ * a) If crash shutdown and mupip rundown is invoked.
+ * b) If a process encountered an error in the midst of committing in phase2
+ * and secshr_db_clnup completed the commit for it. That would not have
+ * inserted the cr into the queues (see comment there as to why). But in
+ * that case, it would have set cnl->wc_blocked to TRUE. Unfortunately, we
+ * reset c>nl->wc_blocked to FALSE as part of the SIGNAL_WRITERS_TO_RESUME
+ * macro call (a few line above). So the only test that we can do is that
+ * a phase2 commit error occurred. This is tested by checking that the
+ * variable gtm_white_box_test_case_enabled is non-zero.
+ */
+ assert((FALSE == broken) || in_mu_rndwn_file || gtm_white_box_test_case_enabled);
+ break;
+ }
+ }
+ if (FALSE == (ret = !broken))
+ break;
+ if (FALSE == (ret = (cr == crtop)))
+ { /* didn't make it to the top without a dirty */
+ if (++lcnt3 > BUF_OWNER_STUCK)
+ {
+ DEBUG_ONLY(
+ lclcr = *cr;
+ lclwip = *crqwip;
+ lclact = *crq;
+ )
+ break;
+ }
+ else if (0 < lcnt3)
+ wcs_sleep(lcnt3);
+ }
+ }
+ if (FALSE == ret)
+ { /* something wrong */
+ /* The only case we know of currently when this is possible is if a process encountered an error
+ * in the midst of committing in phase2 and secshr_db_clnup completed the commit for it and set
+ * wc_blocked to TRUE (even though it was out of crit) causing the wcs_wtstart calls done above
+ * to do nothing. But phase2 commit errors are currently enabled only through white-box testing.
+ * The only exception to this is if this is a crash shutdown and later mupip rundown is being
+ * invoked on this shared memory. Assert accordingly.
+ */
+ assert(gtm_white_box_test_case_enabled || in_mu_rndwn_file);
+ SET_TRACEABLE_VAR(cnl->wc_blocked, TRUE);
+ BG_TRACE_PRO_ANY(csa, wcb_wcs_flu1);
+ send_msg(VARLSTCNT(8) ERR_WCBLOCKED, 6, LEN_AND_LIT("wcb_wcs_flu1"),
+ process_id, &csa->ti->curr_tn, DB_LEN_STR(gv_cur_region));
+ if (in_commit)
+ { /* We should NOT be invoking wcs_recover as otherwise the callers (t_end or tp_tend)
+ * will get confused (see explanation above where variable "in_commit" gets set).
+ */
+ assert(was_crit); /* so dont need to rel_crit */
+ return FALSE;
+ }
+ if (pass > 1)
+ GTMASSERT;
+ wcs_recover(gv_cur_region);
+ }
+ }
+ if (flush_hdr)
+ fileheader_sync(gv_cur_region);
+ if (jnl_enabled && write_epoch && jbp->before_images)
+ { /* Parallel code in Unix does an fsync. Not needed here since VMS writes are hard writes */
+ assert(jgbl.gbl_jrec_time);
+ if (!jgbl.mur_extract)
+ {
+ if (0 == jpc->pini_addr)
+ jnl_put_jrt_pini(csa);
+ jnl_write_epoch_rec(csa);
+ INCR_GVSTATS_COUNTER(csa, cnl, n_jrec_epoch_regular, 1);
+ }
+ }
+ cnl->last_wcsflu_tn = csa->ti->curr_tn; /* record when last successful wcs_flu occurred */
+ cnl->wcsflu_pid = 0;
+ if (!was_crit)
+ rel_crit(gv_cur_region);
+ /* sync the epoch record in the journal if needed. */
+ if (jnl_enabled && jbp->before_images &&
+ write_epoch && sync_epoch && (csa->ti->curr_tn == csa->ti->early_tn))
+ { /* Note that if we are in the midst of committing and came here through a bizarre
+ * stack trace (like wcs_get_space etc.) we want to defer syncing to when we go out of crit.
+ * Note that we are guaranteed to come back to wcs_wtstart since we are currently in commit-phase
+ * and will dirty atleast one block for a timer to be triggered.
+ */
+ jnl_wait(gv_cur_region);
+ }
+ return ret;
+}
diff --git a/sr_vvms/wcs_get_space.c b/sr_vvms/wcs_get_space.c
new file mode 100644
index 0000000..65d9d49
--- /dev/null
+++ b/sr_vvms/wcs_get_space.c
@@ -0,0 +1,162 @@
+/****************************************************************
+ * *
+ * Copyright 2007, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_facility.h"
+#include "gdsroot.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "interlock.h"
+#include "jnl.h"
+#include "sleep_cnt.h"
+#include "gdsbgtr.h"
+
+#include "wcs_get_space.h"
+#include "wbox_test_init.h"
+#include "memcoherency.h"
+
+GBLREF sgmnt_addrs *cs_addrs;
+GBLREF gd_region *gv_cur_region; /* needed for the JNL_ENSURE_OPEN_WCS_WTSTART macro */
+
+/* go after a specific number of buffers or a particular buffer */
+bool wcs_get_space(gd_region *reg, int needed, cache_rec *cr)
+{
+ unsigned int lcnt, ocnt, status;
+ sgmnt_addrs *csa;
+ sgmnt_data_ptr_t csd;
+ node_local_ptr_t cnl;
+ que_ent_ptr_t base, q0;
+ int4 dummy_errno;
+ boolean_t is_mm;
+
+ assert((0 != needed) || (NULL != cr));
+ csa = &(FILE_INFO(reg)->s_addrs);
+ assert(csa == cs_addrs);
+ csd = csa->hdr;
+ is_mm = (dba_mm == csd->acc_meth);
+ assert(is_mm || (dba_bg == csd->acc_meth));
+ cnl = csa->nl;
+ if (FALSE == csa->now_crit)
+ {
+ assert(0 != needed); /* if needed == 0, then we should be in crit */
+ for (lcnt = DIVIDE_ROUND_UP(needed, csd->n_wrt_per_flu); 0 < lcnt; lcnt--)
+ JNL_ENSURE_OPEN_WCS_WTSTART(csa, reg, 0, dummy_errno);
+ /* a macro that ensure jnl is open, dclast's wcs_wtstart and checks for errors etc. */
+ return TRUE;
+ }
+ if (FALSE == wcs_wtfini(reg))
+ return FALSE;
+ /* while calculating flush_trigger, the decrement should be atleast 1 if still not reached the minimum allowed */
+ csd->flush_trigger = MAX(csd->flush_trigger - MAX(csd->flush_trigger/STEP_FACTOR, 1), MIN_FLUSH_TRIGGER(csd->n_bts));
+ if (0 == needed)
+ {
+ if (!is_mm)
+ { /* If another process is concurrently finishing up phase2 of commit, wait for that to complete first. */
+ if (cr->in_tend && !wcs_phase2_commit_wait(csa, cr))
+ return FALSE; /* assumption is that caller will set wc_blocked and trigger cache recovery */
+ }
+ for (lcnt = 1; (MAXGETSPACEWAIT > lcnt) && (0 != cr->dirty); lcnt++)
+ { /* We want to flush a specific cache-record. We speed up the wait by moving the dirty cache-record
+ * to the head of the active queue. But to do this, we need exclusive access to the active queue.
+ * The only other processes outside of crit that can be touching this concurrently are wcs_wtstart
+ * (which can remove entries from the queue) and bg_update_phase2 (which can add entries to the queue).
+ * In the case of writers, we can wait for those to complete (by setting cnl->wc_blocked to TRUE)
+ * and then play with the queue. But in the case of bg_update_phase2, it is not easily possible to
+ * do a similar wait so in this case we choose to do plain wcs_wtstart (which uses interlocked
+ * queue operations and hence can work well with concurrent bg_update_phase2) and wait until the
+ * cache record of interest becomes non-dirty. The consequence is we might wait a little longer than
+ * necessary but that is considered acceptable for now.
+ */
+ /* Check if cache recovery is needed (could be set by another process in
+ * secshr_db_clnup finishing off a phase2 commit). If so, no point invoking
+ * wcs_wtstart as it will return right away. Instead return FALSE so
+ * cache-recovery can be triggered by the caller.
+ */
+ if (cnl->wc_blocked)
+ {
+ assert(gtm_white_box_test_case_enabled);
+ return FALSE;
+ }
+ if (!is_mm && cnl->wcs_phase2_commit_pidcnt)
+ {
+ JNL_ENSURE_OPEN_WCS_WTSTART(csa, reg, 0, dummy_errno);
+ /* a macro that ensure jnl is open, dclast's wcs_wtstart and checks for errors etc. */
+ wcs_sleep(lcnt);
+ } else if (LATCH_CLEAR == WRITE_LATCH_VAL(cr))
+ {
+ SIGNAL_WRITERS_TO_STOP(cnl); /* to stop all active writers */
+ WAIT_FOR_WRITERS_TO_STOP(cnl, ocnt, MAXGETSPACEWAIT);
+ if (MAXGETSPACEWAIT <= ocnt)
+ {
+ assert(FALSE);
+ return FALSE;
+ }
+ if (LATCH_CLEAR == WRITE_LATCH_VAL(cr))
+ { /* Check if cache-record is part of the active queue. If so, then remove it from the
+ * tail of the active queue and move it to the head to try and speed up the flush.
+ * If not and if cr->dirty is non-zero, then the only way this is possible we know
+ * of is if a concurrent process encountered an error in the midst of commit in phase2
+ * of bg_update and finished the update but did not reinsert the cache-record in the
+ * active queue (see comment in secshr_db_clnup about why INSQ*I macros are not used
+ * in VMS). In this case, return FALSE as wcs_get_space cannot flush this cache-record.
+ * The caller will trigger appropriate error handling. We are guaranteed that cr cannot
+ * be part of the wip queue because WRITE_LATCH_VAL(cr) is LATCH_CLEAR (in wip queue it
+ * will be > LATCH_CLEAR).
+ */
+ if (0 != cr->state_que.fl)
+ { /* We are about to play with the queues without using interlocks.
+ * Assert no one else could be concurrently playing with the queue.
+ */
+ assert(!cnl->wcs_phase2_commit_pidcnt && !cnl->in_wtstart);
+ base = &csa->acc_meth.bg.cache_state->cacheq_active;
+ q0 = (que_ent_ptr_t)((sm_uc_ptr_t)&cr->state_que + cr->state_que.fl);
+ shuffqth((que_ent_ptr_t)q0, (que_ent_ptr_t)base);
+ } else if (cr->dirty)
+ {
+ assert(gtm_white_box_test_case_enabled);
+ return FALSE;
+ }
+ }
+ SIGNAL_WRITERS_TO_RESUME(cnl);
+ JNL_ENSURE_OPEN_WCS_WTSTART(csa, reg, 0, dummy_errno);
+ /* a macro that ensure jnl is open, dclast's wcs_wtstart and checks for errors etc. */
+ wcs_sleep(lcnt);
+ } else if ((0 == cr->iosb.cond) || (WRT_STRT_PNDNG == cr->iosb.cond))
+ {
+ JNL_ENSURE_OPEN_WCS_WTSTART(csa, reg, 0, dummy_errno);
+ /* a macro that ensure jnl is open, dclast's wcs_wtstart and checks for errors etc. */
+ wcs_sleep(lcnt);
+ }
+ if (FALSE == wcs_wtfini(reg))
+ return FALSE;
+ }
+ if (0 == cr->dirty)
+ return TRUE;
+ assert(FALSE);
+ return FALSE;
+ }
+ for (lcnt = 1; ((cnl->wc_in_free < needed) && (MAXGETSPACEWAIT > lcnt)); lcnt++)
+ {
+ DCLAST_WCS_WTSTART(reg, 0, dummy_errno); /* a macro that dclast's wcs_wtstart and checks for errors etc. */
+ wcs_sleep(lcnt);
+ if (FALSE == wcs_wtfini(reg))
+ return FALSE;
+ }
+ if (cnl->wc_in_free < needed)
+ {
+ assert(FALSE);
+ return FALSE;
+ }
+ return TRUE;
+}
diff --git a/sr_vvms/wcs_wtfini.c b/sr_vvms/wcs_wtfini.c
new file mode 100644
index 0000000..64efe2e
--- /dev/null
+++ b/sr_vvms/wcs_wtfini.c
@@ -0,0 +1,227 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <ssdef.h>
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "gdskill.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsfhead.h"
+#include "gdsbgtr.h" /* for the BG_TRACE_ANY macros */
+#include "filestruct.h" /* for WRT_STRT_PNDNG and FILE_INFO macros */
+#include "ast.h" /* for ENABLE and DISABLE macros to pass to sys$setast() */
+#include "interlock.h" /* atleast for *_LATCH_* macros */
+#include "relqueopi.h" /* for REMQHI and INSQHI macros */
+#include "send_msg.h"
+#include "is_proc_alive.h"
+#include "shmpool.h"
+
+GBLREF int4 wtfini_in_prog;
+GBLREF uint4 image_count;
+GBLREF uint4 process_id;
+
+error_def(ERR_BLKWRITERR);
+error_def(ERR_DBCCERR);
+error_def(ERR_DBFILERR);
+error_def(ERR_IOWRITERR);
+
+bool wcs_wtfini(gd_region *reg)
+{
+ cache_state_rec_ptr_t csr, start_csr;
+ cache_rec_ptr_t cr_alt;
+ cache_que_head_ptr_t whead;
+ sgmnt_addrs *csa;
+ sgmnt_data_ptr_t csd;
+ shmpool_blk_hdr_ptr_t sblkh_p;
+ sm_off_t sblkh_off;
+ unsigned int ast_status, dummy, lcnt;
+ uint4 wrtfail_epid;
+ int status;
+ cache_rec_ptr_t cr, cr_lo, cr_hi;
+ boolean_t ret_value;
+ unsigned int iosb_cond;
+ node_local_ptr_t cnl;
+
+ csa = &FILE_INFO(reg)->s_addrs;
+ csd = csa->hdr;
+ cnl = csa->nl;
+ BG_TRACE_ANY(csa, wcs_wtfini_invoked);
+ wtfini_in_prog++;
+ assert((TRUE == csa->now_crit) || (TRUE == csd->clustered));
+ whead = &csa->acc_meth.bg.cache_state->cacheq_wip;
+ assert(0 == (((int4)whead) & 7));
+ cr_lo = csa->acc_meth.bg.cache_state->cache_array + csd->bt_buckets;
+ cr_hi = cr_lo + csd->n_bts;
+ ret_value = TRUE;
+ for (lcnt = 0, start_csr = NULL; lcnt <= csd->n_bts; lcnt++)
+ {
+ csr = (cache_state_rec_ptr_t)REMQHI((que_head_ptr_t)whead);
+ if (INTERLOCK_FAIL == (int4)csr)
+ {
+ assert(FALSE);
+ SET_TRACEABLE_VAR(cnl->wc_blocked, TRUE);
+ BG_TRACE_PRO_ANY(csa, wcb_wtfini_lckfail1);
+ ret_value = FALSE;
+ break;
+ }
+ if (NULL == csr)
+ break; /* empty queue */
+ /* wcs_get_space relies on the fact that a cache-record that is out of either active or wip queue has its
+ * fl and bl fields set to 0. Initialize those fields now that this cache-record is out of the active queue.
+ */
+ csr->state_que.fl = csr->state_que.bl = 0;
+ if (csr == start_csr)
+ {
+ status = INSQHI((que_ent_ptr_t)csr, (que_head_ptr_t)whead);
+ if (INTERLOCK_FAIL == status)
+ {
+ assert(FALSE);
+ SET_TRACEABLE_VAR(cnl->wc_blocked, TRUE);
+ BG_TRACE_PRO_ANY(csa, wcb_wtfini_lckfail2);
+ ret_value = FALSE;
+ }
+ break; /* looped the queue */
+ }
+ cr = (cache_rec_ptr_t)((sm_uc_ptr_t)csr - SIZEOF(cr->blkque));
+ if (CR_NOT_ALIGNED(cr, cr_lo) || CR_NOT_IN_RANGE(cr, cr_lo, cr_hi))
+ {
+ assert(FALSE);
+ SET_TRACEABLE_VAR(cnl->wc_blocked, TRUE);
+ BG_TRACE_PRO_ANY(csa, wc_blocked_wcs_wtfini_bad_cr);
+ ret_value = FALSE;
+ break;
+ }
+ assert(0 == csr->r_epid);
+ assert(LATCH_CLEAR < WRITE_LATCH_VAL(csr));
+ iosb_cond = csr->iosb.cond;
+ /* Since cr->iosb.cond can change concurrently (wcs_wtstart.c can issue a dsk_write for the same cache-record
+ * concurrently which can change the iosb) and since it needs to be used in multiple places in the if statement
+ * below, we note down cr->iosb.cond in a local variable and use that instead. Using the shared memory value
+ * might cause us to go into the if block for a block whose IO is not complete and end up reissuing the IO for
+ * the same block causing TWO CONCURRENTLY PENDING IOs for the same block.
+ */
+ if ((((0 != iosb_cond)
+ && ((WRT_STRT_PNDNG != iosb_cond) || (FALSE == is_proc_alive(csr->epid, csr->image_count))))
+ || ((TRUE == csr->wip_stopped) && (FALSE == is_proc_alive(csr->epid, csr->image_count)))))
+ { /* if 0 == csr->epid, is_proc_alive returns FALSE */
+ /* As long as the cache-record is PINNED (in_cw_set is TRUE), wcs_wtfini should NOT remove an older
+ * twin even if it is an older twin whose write is complete. This is because the contents of that
+ * buffer could be relied upon by secshr_db_clnup/wcs_recover to complete the flush of the before-image
+ * to the backup file (in case of an error in the midst of commit) so we should NOT touch csr->blk.
+ */
+ if (1 == (iosb_cond & 1) || (0 == csr->dirty) || (CR_BLKEMPTY == csr->blk)
+ || ((0 == csr->bt_index) && !csr->in_cw_set))
+ { /* it's done properly, or it doesn't matter */
+ if (0 != csr->twin)
+ {
+ cr_alt = (cache_rec_ptr_t)GDS_ANY_REL2ABS(csa, csr->twin);
+ assert(&((cache_rec_ptr_t)GDS_ANY_REL2ABS(csa, cr_alt->twin))->state_que == csr);
+ cr_alt->twin = csr->twin = 0;
+ if (0 == csr->bt_index)
+ {
+ assert(CR_BLKEMPTY != cr_alt->blk);
+ assert(LATCH_CONFLICT == WRITE_LATCH_VAL(csr));
+ csr->cycle++; /* increment cycle whenever blk number changes (tp_hist needs it) */
+ csr->blk = CR_BLKEMPTY;
+ } else
+ {
+ assert(CR_BLKEMPTY != csr->blk);
+ cr_alt->cycle++; /* increment cycle for blk number changes (for tp_hist) */
+ cr_alt->blk = CR_BLKEMPTY;
+ }
+ }
+ assert(FALSE == csr->data_invalid);
+ BG_TRACE_ANY(csa, qio_to_clean);
+ csr->flushed_dirty_tn = csr->dirty;
+ csr->dirty = 0;
+ csr->epid = 0;
+ csr->iosb.cond = 0;
+ csr->wip_stopped = FALSE;
+ INCR_CNT(&cnl->wc_in_free, &dummy);
+ WRITE_LATCH_VAL(csr) = LATCH_CLEAR; /* off the queues and now_crit */
+ SHMPOOL_FREE_CR_RFMT_BLOCK(reg, csa, cr);
+ } else
+ { /* block is still valid, current, dirty and the write was not successful OR in_cw_set is TRUE */
+ status = INSQTI((que_ent_ptr_t)csr, (que_head_ptr_t)whead);
+ if (INTERLOCK_FAIL == status)
+ {
+ assert(FALSE);
+ SET_TRACEABLE_VAR(cnl->wc_blocked, TRUE);
+ BG_TRACE_PRO_ANY(csa, wcb_wtfini_lckfail3);
+ ret_value = FALSE;
+ break;
+ }
+ if ((FALSE == reg->read_only) && !lib$ast_in_prog())
+ { /* Don't want to do setast(DISABLE)s when we are within an AST.
+ * Anyway a future non-AST driven wcs_wtfini will take care of this.
+ */
+ wrtfail_epid = csr->epid;
+ csr->image_count = image_count;
+ csr->epid = process_id;
+ csr->iosb.cond = WRT_STRT_PNDNG;
+ csr->wip_stopped = FALSE;
+ csr->shmpool_blk_off = 0; /* dsk_write() may (if dwngrd) want to redo this anyway */
+ ast_status = sys$setast(DISABLE);
+ /* Notify of IO error. Notify of status if not special retry and the original job died. */
+ send_msg(VARLSTCNT(7) ERR_IOWRITERR, 5, wrtfail_epid, csr->blk, DB_LEN_STR(reg), csr->epid);
+ if (WRT_STRT_PNDNG != iosb_cond)
+ send_msg(VARLSTCNT(1) iosb_cond);
+ CR_BUFFER_CHECK1(reg, csa, csd, cr, cr_lo, cr_hi);
+ status = dsk_write(reg, csr->blk, cr, NULL, 0, &csr->iosb);
+ if (SS$_WASSET == ast_status)
+ sys$setast(ENABLE);
+ if (0 == (status & 1))
+ { /* if it fails, leave it and hope that another process will work (infinite retry) */
+ send_msg(VARLSTCNT(4) ERR_DBFILERR, 2, DB_LEN_STR(reg));
+ send_msg(VARLSTCNT(3) ERR_BLKWRITERR, 1, csr->blk);
+ send_msg(VARLSTCNT(1) status);
+ /* since the state of iosb.cond is indeterminate (but believed to never have
+ * severity of SUCCESS) the following [slightly sleazy] assignment forces a retry */
+ csr->iosb.cond = WRT_STRT_PNDNG;
+ csr->epid = 0;
+ csr->shmpool_blk_off = 0; /* Allow reuse of our reformat buffer (if any) */
+ assert(FALSE);
+ }
+ }
+ if (NULL == start_csr)
+ start_csr = csr;
+ }
+ } else
+ {
+ assert(csr->epid);
+ status = INSQTI((que_ent_ptr_t)csr, (que_head_ptr_t)whead);
+ if (INTERLOCK_FAIL == status)
+ {
+ assert(FALSE);
+ SET_TRACEABLE_VAR(cnl->wc_blocked, TRUE);
+ BG_TRACE_PRO_ANY(csa, wcb_wtfini_lckfail4);
+ ret_value = FALSE;
+ break;
+ }
+ if (NULL == start_csr)
+ start_csr = csr;
+ }
+ }
+ wtfini_in_prog--;
+ assert(0 <= wtfini_in_prog);
+ if (0 > wtfini_in_prog)
+ wtfini_in_prog = 0;
+ if (!ret_value || ((NULL != csr) && (csr != start_csr)))
+ {
+ assert(FALSE);
+ return FALSE;
+ }
+ return TRUE;
+}
diff --git a/sr_vvms/wcs_wtstart.c b/sr_vvms/wcs_wtstart.c
new file mode 100644
index 0000000..c9c7a32
--- /dev/null
+++ b/sr_vvms/wcs_wtstart.c
@@ -0,0 +1,229 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gdsroot.h"
+#include "gtm_facility.h"
+#include "fileinfo.h"
+#include "gdsbt.h"
+#include "gdsblk.h"
+#include "gdsbml.h"
+#include "gdsfhead.h"
+#include "filestruct.h"
+#include "ast.h"
+#include "interlock.h"
+#include "jnl.h"
+#include "relqueopi.h"
+#include "send_msg.h"
+#include "iosp.h"
+#include "gdsbgtr.h" /* for the BG_TRACE_ANY macros */
+#include "memcoherency.h"
+
+GBLREF short astq_dyn_avail;
+GBLREF uint4 process_id;
+GBLREF uint4 image_count;
+
+error_def(ERR_BLKWRITERR);
+error_def(ERR_DBCCERR);
+error_def(ERR_DBFILERR);
+
+/* currently returns 0 always */
+int4 wcs_wtstart(gd_region *reg)
+{
+ boolean_t bmp_status;
+ blk_hdr_ptr_t bp;
+ cache_que_head_ptr_t ahead, whead;
+ cache_state_rec_ptr_t csr, start_csr;
+ jnl_private_control *jpc;
+ node_local_ptr_t cnl;
+ sgmnt_data_ptr_t csd;
+ sgmnt_addrs *csa;
+ unsigned int max_writes, wcnt;
+ int status, dummy, lcnt, n;
+ cache_rec_ptr_t cr, cr_lo, cr_hi;
+ uint4 index;
+
+ assert(lib$ast_in_prog()); /* if a dclast fails and the setast is used, this assert fails - put can't happen in pro */
+ assert(0 != WRT_STRT_PNDNG);
+ assert(0 == (1 & WRT_STRT_PNDNG));
+ assert(FALSE == reg->read_only);
+ csa = &FILE_INFO(reg)->s_addrs;
+ csd = csa->hdr;
+ cnl = csa->nl;
+ if (cnl->wc_blocked)
+ return 0;
+ INCR_INTENT_WTSTART(cnl); /* signal intent to enter wcs_wtstart */
+ /* the above interlocked instruction does the appropriate write memory barrier to publish this change to the world */
+ SHM_READ_MEMORY_BARRIER; /* need to do this to ensure uptodate value of csa->nl->wc_blocked is read */
+ if (cnl->wc_blocked)
+ {
+ DECR_INTENT_WTSTART(cnl);
+ return 0;
+ }
+ csa->in_wtstart = TRUE; /* secshr_db_clnup depends on the order of this and the INCR_CNT done below */
+ INCR_CNT(&cnl->in_wtstart, &dummy); /* if a wc_blocked sneeks in the loop below will prevent queue operations */
+ SAVE_WTSTART_PID(cnl, process_id, index);
+ assert(cnl->in_wtstart > 0 && csa->in_wtstart);
+
+ jpc = csa->jnl;
+ assert(!JNL_ALLOWED(csd) || NULL != jpc);
+ if (JNL_ENABLED(csd) && (NULL != jpc) && (NOJNL != jpc->channel)) /* not jnl_write, which is believed to be ok */
+ jnl_start_ast(jpc);
+ cnl->wcs_staleness = -1;
+ lcnt = csd->n_bts;
+ max_writes = csd->n_wrt_per_flu;
+ whead = &csa->acc_meth.bg.cache_state->cacheq_wip;
+ assert(0 == ((int4)whead & 7));
+ ahead = &csa->acc_meth.bg.cache_state->cacheq_active;
+ assert(0 == ((int4)ahead & 7));
+ cr_lo = csa->acc_meth.bg.cache_state->cache_array + csd->bt_buckets;
+ cr_hi = cr_lo + csd->n_bts;
+ csa->wbuf_dqd++; /* increase the counter. In case ACCVIO or something bad happens
+ * secshr_db_cleanup will check the field and handle appropriarely */
+ for (wcnt = 0, start_csr = NULL; (0 < lcnt) && (wcnt < max_writes) && (FALSE == cnl->wc_blocked); --lcnt)
+ {
+ csr = (cache_state_rec_ptr_t)REMQHI((que_head_ptr_t)ahead);
+ if (INTERLOCK_FAIL == (int4)csr)
+ {
+ assert(FALSE);
+ SET_TRACEABLE_VAR(cnl->wc_blocked, TRUE);
+ BG_TRACE_PRO_ANY(csa, wcb_wtstart_lckfail1);
+ break;
+ }
+ if (NULL == csr)
+ break; /* the queue is empty */
+ /* wcs_get_space relies on the fact that a cache-record that is out of either active or wip queue has its
+ * fl and bl fields set to 0. Initialize those fields now that this cache-record is out of the active queue.
+ */
+ csr->state_que.fl = csr->state_que.bl = 0;
+ if (csr == start_csr)
+ { /* completed a tour of the queue */
+ status = INSQTI((que_ent_ptr_t)csr, (que_head_ptr_t)ahead);
+ if (INTERLOCK_FAIL == status)
+ {
+ assert(FALSE);
+ SET_TRACEABLE_VAR(cnl->wc_blocked, TRUE);
+ BG_TRACE_PRO_ANY(csa, wcb_wtstart_lckfail2);
+ }
+ break;
+ }
+ cr = (cache_rec_ptr_t)((sm_uc_ptr_t)csr - SIZEOF(cr->blkque));
+ assert(!CR_NOT_ALIGNED(cr, cr_lo) && !CR_NOT_IN_RANGE(cr, cr_lo, cr_hi));
+ if (CR_BLKEMPTY == csr->blk)
+ { /* must be left by t_commit_cleanup - remove it from the queue and complete the cleanup */
+ assert(0 == csr->twin);
+ assert(FALSE == csr->data_invalid);
+ assert(csr->dirty);
+ assert(0 == csr->iosb.cond);
+ csr->dirty = 0;
+ INCR_CNT(&cnl->wc_in_free, &dummy);
+ if (!SUB_ENT_FROM_ACTIVE_QUE_CNT(&cnl->wcs_active_lvl, &cnl->wc_var_lock)
+ && !cnl->wcsflu_pid && FALSE == csa->dbsync_timer)
+ {
+ assert(0 < astq_dyn_avail);
+ if (0 < astq_dyn_avail)
+ {
+ csa->dbsync_timer = TRUE;
+ astq_dyn_avail--;
+ /* Since we are already in an ast, we can invoke wcs_clean_dbsync_timer_ast directly. */
+ wcs_clean_dbsync_timer_ast(csa);
+ }
+ }
+ continue;
+ }
+ assert(0 != csr->dirty);
+ assert(0 == csr->iosb.cond);
+ assert(0 == csr->epid);
+ assert(0 == csr->r_epid);
+ if (((0 != csr->twin) && (1 != ((cache_rec_ptr_t)GDS_ANY_REL2ABS(csa, csr->twin))->iosb.cond))
+ || ((0 != csr->jnl_addr) && JNL_ENABLED(csd) && (csr->jnl_addr > jpc->jnl_buff->dskaddr)))
+ { /* twin still in write OR would write ahead of journal */
+ status = INSQTI((que_ent_ptr_t)csr, (que_head_ptr_t)ahead);
+ if ((unsigned int)INTERLOCK_FAIL == status)
+ {
+ assert(FALSE);
+ SET_TRACEABLE_VAR(cnl->wc_blocked, TRUE);
+ BG_TRACE_PRO_ANY(csa, wcb_wtstart_lckfail3);
+ break;
+ }
+ if (NULL == start_csr)
+ start_csr = csr;
+ continue;
+ }
+ csr->image_count = image_count;
+ csr->epid = process_id;
+ csr->iosb.cond = WRT_STRT_PNDNG; /* Illegal value, shows that write has not been issued */
+ LOCK_BUFF_FOR_WRITE(csr, n);
+ assert(WRITE_LATCH_VAL(csr) >= LATCH_CLEAR);
+ assert(WRITE_LATCH_VAL(csr) <= LATCH_CONFLICT);
+ if (n < 1)
+ { /* sole owner; if not, leave it off the queue for t_end_sysops to replace */
+ assert(WRITE_LATCH_VAL(csr) > LATCH_CLEAR);
+ assert(FALSE == csr->data_invalid); /* check that buffer has valid data */
+ assert(0 == n);
+ assert(csr->epid);
+ status = INSQTI((que_ent_ptr_t)csr, (que_head_ptr_t)whead);
+ if (INTERLOCK_FAIL == status)
+ {
+ assert(FALSE);
+ SET_TRACEABLE_VAR(cnl->wc_blocked, TRUE);
+ BG_TRACE_PRO_ANY(csa, wcb_wtstart_lckfail4);
+ break;
+ }
+ INCR_GVSTATS_COUNTER(csa, cnl, n_dsk_write, 1);
+ CR_BUFFER_CHECK1(reg, csa, csd, cr, cr_lo, cr_hi);
+ bp = (blk_hdr_ptr_t)(GDS_ANY_REL2ABS(csa, csr->buffaddr));
+ VALIDATE_BM_BLK(csr->blk, bp, csa, reg, bmp_status); /* bmp_status reflects bitmap buffer's validity */
+ if (SUB_ENT_FROM_ACTIVE_QUE_CNT(&cnl->wcs_active_lvl, &cnl->wc_var_lock) || cnl->wcsflu_pid)
+ status = dsk_write(reg, csr->blk, cr, NULL, 0, &csr->iosb);
+ else
+ {
+ if ((0 < astq_dyn_avail) && (FALSE == csa->dbsync_timer))
+ {
+ astq_dyn_avail--;
+ csa->dbsync_timer = TRUE;
+ status = dsk_write(reg, csr->blk, cr, wcs_clean_dbsync_timer_ast, csa, &csr->iosb);
+ } else
+ {
+ assert(csa->dbsync_timer); /* in PRO, we skip writing an epoch record. */
+ status = dsk_write(reg, csr->blk, cr, NULL, 0, &csr->iosb);
+ }
+ }
+ if (0 == (status & 1))
+ { /* if it fails, leave it and hope that another time, another process will work (infinite retry) */
+ send_msg(VARLSTCNT(4) ERR_DBFILERR, 2, DB_LEN_STR(reg));
+ send_msg(VARLSTCNT(3) ERR_BLKWRITERR, 1, csr->blk);
+ send_msg(VARLSTCNT(1) status);
+ /* since the state of iosb.cond is indeterminate (but believed to never have severity of SUCCESS)
+ * when the qio fails, the following [slightly sleazy] assignment forces a retry */
+ csr->iosb.cond = WRT_STRT_PNDNG;/* this and the next line assume that iosb and epid are aligned */
+ csr->epid = 0; /* so that memory coherency is not disrupted by concurrent access */
+ assert(FALSE);
+ }
+ ++wcnt;
+ }
+ }
+ csa->wbuf_dqd--; /* Everything completed successfully, so clear the field now */
+ assert(cnl->in_wtstart > 0 && csa->in_wtstart);
+ DECR_CNT(&cnl->in_wtstart, &dummy); /* secshr_db_clnup depends on the order of this and the next line */
+ CLEAR_WTSTART_PID(cnl, index);
+ csa->in_wtstart = FALSE;
+ DECR_INTENT_WTSTART(cnl);
+ /* Ideally we should be having an invocation of the DEFERRED_EXIT_HANDLING_CHECK macro here (see unix wcs_wtstart.c).
+ * But since we are in an AST at this point, invoking the exit handler is going to defer it once again (there is
+ * code in generic_exit_handler.c which checks for ast_in_prog) so no point invoking it here. This means if
+ * a MUPIP STOP gets delivered while we are in wcs_wtstart and therefore exit-handling gets deferred, it will not
+ * be triggered at the end of wcs_wtstart but has to wait until the next t_end/tp_tend/rel_crit/rel_lock occurs
+ * (those places have the DEFERRED_EXIT_HANDLING_CHECK checks).
+ */
+ return 0;
+}
diff --git a/sr_vvms/zcall.h b/sr_vvms/zcall.h
new file mode 100644
index 0000000..fd287e3
--- /dev/null
+++ b/sr_vvms/zcall.h
@@ -0,0 +1,66 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/*
+ * ZCALL Table Definitions
+ *
+ * NOTES:
+ * 1. Any changes made here must also be reflected in ZC_CALL.MAR (for VAX)
+ * or in ZC_CALL.M64 (for Alpha);
+ * 2. In order for these definitions to be portable across both VAX and Alpha
+ * platforms, the structure types defined here must be padded, if necessary,
+ * such that their declared sizes (as returned by the SIZEOF operator ) are
+ * a multiple of the alignment boundary of their most stringently aligned
+ * member. (This is only because the respective compilers would otherwise
+ * compute SIZEOF differently .)
+ */
+
+typedef struct zctabrtn_type
+ {
+ unsigned short entry_length;
+ unsigned char n_inputs;
+ unsigned char n_outputs;
+ unsigned char *entrypoint;
+ unsigned char outbnd_reset;
+ char padding; /* make SIZEOF(zctabrtn) == 12 */
+ unsigned char callnamelen;
+ unsigned char callname[1]; /* variable size > 0 */
+ } zctabrtn;
+
+typedef struct zctabret_type
+ {
+ unsigned char class;
+ unsigned char type;
+ } zctabret;
+
+typedef struct zctabinput_type
+ {
+ unsigned char mechanism;
+ unsigned char type;
+ unsigned char position;
+ unsigned char qualifier;
+ char *value;
+ } zctabinput;
+
+typedef struct zctaboutput_type
+ {
+ unsigned char mechanism;
+ unsigned char type;
+ unsigned char position;
+ unsigned char qualifier;
+ int4 value;
+ } zctaboutput;
+
+typedef struct zcpackage_type
+ {
+ zctabrtn *begin, *end;
+ unsigned char *packname;
+ } zcpackage;
diff --git a/sr_vvms/zcch.c b/sr_vvms/zcch.c
new file mode 100644
index 0000000..a05bce1
--- /dev/null
+++ b/sr_vvms/zcch.c
@@ -0,0 +1,46 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "io.h"
+#include "error.h"
+#include "setterm.h"
+
+GBLREF io_pair io_std_device;
+
+CONDITION_HANDLER(zcch)
+{
+ static struct chf$signal_array *newsig = 0;
+ void free();
+ error_def (ERR_ZCUSRRTN);
+
+ if (SIGNAL == SS$_DEBUG)
+ return SS$_RESIGNAL;
+ if (SIGNAL == SS$_UNWIND)
+ {
+ if (newsig)
+ free(newsig);
+ return SS$_NORMAL;
+ }
+
+ if (io_std_device.in->type == tt)
+ { setterm(io_std_device.in);
+ }
+
+ /* add GT.M cover message over users error */
+ newsig = malloc((sig->chf$l_sig_args + 2 + 1) * SIZEOF(int4));
+ memcpy(&newsig->chf$l_sig_name + 2, &sig->chf$l_sig_name, sig->chf$l_sig_args * SIZEOF(int4));
+ newsig->chf$l_sig_args = sig->chf$l_sig_args + 2;
+ newsig->chf$l_sig_name = ERR_ZCUSRRTN;
+ newsig->chf$l_sig_arg1 = 0;
+ sig = newsig;
+ NEXTCH;
+}
diff --git a/sr_vvms/zcdef.h b/sr_vvms/zcdef.h
new file mode 100644
index 0000000..f3fae13
--- /dev/null
+++ b/sr_vvms/zcdef.h
@@ -0,0 +1,51 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2012 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+/* ZCDEF.H -- coincides with module ZCDEF in GTMZCALL.MAX, GTMZCALL.MLB */
+
+#define ZC$RETC_ 0 ; Return classes
+#define ZC$RETC_STATUS 1
+#define ZC$RETC_VALUE 2
+#define ZC$RETC_IGNORED 3
+
+#define ZC$MECH_ 0 ; Argument-passing mechanisms
+#define ZC$MECH_VALUE 1
+#define ZC$MECH_REFERENCE 2
+#define ZC$MECH_DESCRIPTOR 3
+#define ZC$MECH_DESCRIPTOR64 4
+
+#define ZC$DTYPE_ 0 ; Native data types
+#define ZC$DTYPE_STRING DSC$K_DTYPE_T
+#define ZC$DTYPE_BYTE DSC$K_DTYPE_B
+#define ZC$DTYPE_BYTEU DSC$K_DTYPE_BU
+#define ZC$DTYPE_WORD DSC$K_DTYPE_W
+#define ZC$DTYPE_WORDU DSC$K_DTYPE_WU
+#define ZC$DTYPE_LONG DSC$K_DTYPE_L
+#define ZC$DTYPE_LONGU DSC$K_DTYPE_LU
+#define ZC$DTYPE_QUAD DSC$K_DTYPE_Q
+#define ZC$DTYPE_FLOATING DSC$K_DTYPE_F
+#define ZC$DTYPE_DOUBLE DSC$K_DTYPE_G
+#define ZC$DTYPE_G_FLOATING DSC$K_DTYPE_G
+#define ZC$DTYPE_H_FLOATING DSC$K_DTYPE_H
+
+#define ZC$IQUAL_ 0 ; Input argument qualifiers
+#define ZC$IQUAL_CONSTANT 1
+#define ZC$IQUAL_OPTIONAL 2
+#define ZC$IQUAL_OPTIONAL_0 3
+#define ZC$IQUAL_DEFAULT 4
+#define ZC$IQUAL_REQUIRED 5
+#define ZC$IQUAL_BLOCK 6
+
+#define ZC$OQUAL_ 0 ; Output argument qualifiers
+#define ZC$OQUAL_REQUIRED 1
+#define ZC$OQUAL_DUMMY 2
+#define ZC$OQUAL_PREALLOCATE 3
+
diff --git a/sr_vvms/zl_cmd_qlf.c b/sr_vvms/zl_cmd_qlf.c
new file mode 100644
index 0000000..a3ba57b
--- /dev/null
+++ b/sr_vvms/zl_cmd_qlf.c
@@ -0,0 +1,47 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2009 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+
+#include "cmd_qlf.h"
+#include "stringpool.h"
+#include <descrip.h>
+
+unsigned int clich();
+
+#define COMMAND "MUMPS "
+
+GBLREF spdesc stringpool;
+
+void zl_cmd_qlf (mstr *quals, command_qualifier *qualif)
+{
+ unsigned status, mumps_clitab ();
+ struct dsc$descriptor comdsc;
+ error_def (ERR_COMPILEQUALS);
+
+ ENSURE_STP_FREE_SPACE(quals->len + SIZEOF(COMMAND) - 1);
+
+ memcpy (stringpool.free, COMMAND, SIZEOF(COMMAND) - 1);
+ memcpy (stringpool.free + SIZEOF(COMMAND) - 1, quals->addr, quals->len);
+ comdsc.dsc$w_length = SIZEOF(COMMAND) - 1 + quals->len;
+ comdsc.dsc$b_dtype = DSC$K_DTYPE_T;
+ comdsc.dsc$b_class = DSC$K_CLASS_S;
+ comdsc.dsc$a_pointer = stringpool.free;
+ lib$establish (clich);
+ status = cli$dcl_parse (&comdsc, &mumps_clitab, 0, 0);
+ lib$revert ();
+ if (!(status & 1))
+ rts_error(VARLSTCNT(5) ERR_COMPILEQUALS, 2, quals->len, quals->addr, status);
+ qualif->object_file.mvtype = qualif->list_file.mvtype = qualif->ceprep_file.mvtype = 0;
+ get_cmd_qlf (qualif);
+}
diff --git a/sr_vvms/zl_olb.c b/sr_vvms/zl_olb.c
new file mode 100644
index 0000000..ad7561b
--- /dev/null
+++ b/sr_vvms/zl_olb.c
@@ -0,0 +1,53 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "lbrdef.h"
+#include <descrip.h>
+
+globalvalue int4 LBR$_NORMAL;
+globalvalue int4 LBR$_LIBOPN;
+globalvalue int4 LBR$_OLDLIBRARY;
+globalvalue int4 LBR$_KEYNOTFND;
+
+zl_olb(mstr *olblib, mstr *module, int4 *libindex)
+{
+ int4 txtrfa[2];
+ uint4 pos, status;
+ struct dsc$descriptor_s libnamdes, modnamdes;
+ static readonly $DESCRIPTOR(period, ".");
+
+ modnamdes.dsc$b_dtype = DSC$K_DTYPE_T;
+ modnamdes.dsc$b_class = DSC$K_CLASS_S;
+ modnamdes.dsc$a_pointer = module->addr;
+ modnamdes.dsc$w_length = module->len;
+ pos = lib$locc(&period, &modnamdes);
+ if (pos != 0 && pos != module->len)
+ modnamdes.dsc$w_length = pos - 1;
+ else
+ GTMASSERT;
+ libnamdes.dsc$b_dtype = DSC$K_DTYPE_T;
+ libnamdes.dsc$b_class = DSC$K_CLASS_S;
+ libnamdes.dsc$a_pointer = olblib->addr;
+ libnamdes.dsc$w_length = olblib->len;
+ status = lbr$ini_control(libindex, &LBR$C_READ, &LBR$C_TYP_OBJ, 0);
+ if (LBR$_NORMAL == status)
+ {
+ status = lbr$open(libindex, &libnamdes, 0, 0, 0, 0, 0);
+ if ((LBR$_OLDLIBRARY | LBR$_LIBOPN | LBR$_NORMAL) & status)
+ {
+ status = lbr$set_locate(libindex);
+ if (LBR$_NORMAL == status)
+ status = lbr$lookup_key(libindex, &modnamdes, txtrfa);
+ }
+ }
+ return status;
+}
diff --git a/sr_vvms/zl_olb.h b/sr_vvms/zl_olb.h
new file mode 100644
index 0000000..a46111c
--- /dev/null
+++ b/sr_vvms/zl_olb.h
@@ -0,0 +1,17 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef ZL_OLB_INCLUDED
+#define ZL_OLB_INCLUDED
+
+int zl_olb(mstr *olblib, mstr *module, int4 *libindex); /***type int added***/
+
+#endif /* ZL_OLB_INCLUDED */
diff --git a/sr_vvms/zro_gettok.c b/sr_vvms/zro_gettok.c
new file mode 100644
index 0000000..f9ef2d0
--- /dev/null
+++ b/sr_vvms/zro_gettok.c
@@ -0,0 +1,54 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+#include "toktyp.h"
+#include "zroutines.h"
+
+void zro_gettok (unsigned char **lp, unsigned char *top, unsigned *toktyp, mstr *tok)
+{
+ while (*lp < top && **lp == ' ')
+ (*lp)++;
+ if (*lp >= top)
+ *toktyp = TK_EOL;
+ else
+ switch (**lp)
+ {
+ case ',':
+ *toktyp = TK_COMMA;
+ (*lp)++;
+ break;
+ case '=':
+ *toktyp = TK_EQUAL;
+ (*lp)++;
+ break;
+ case '(':
+ *toktyp = TK_LPAREN;
+ (*lp)++;
+ break;
+ case ')':
+ *toktyp = TK_RPAREN;
+ (*lp)++;
+ break;
+ case '/':
+ *toktyp = TK_SLASH;
+ (*lp)++;
+ break;
+ default:
+ tok->addr = *lp;
+ while (*lp < top && **lp != ',' && **lp != '=' && **lp != '(' && **lp != ')' && **lp != '/' && **lp != ' ')
+ (*lp)++;
+ *toktyp = TK_IDENT;
+ tok->len = *lp - (unsigned char *) tok->addr;
+ break;
+ }
+ return;
+}
diff --git a/sr_vvms/zro_load.c b/sr_vvms/zro_load.c
new file mode 100644
index 0000000..eec0882
--- /dev/null
+++ b/sr_vvms/zro_load.c
@@ -0,0 +1,272 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+#include <rms.h>
+
+#include "toktyp.h"
+#include "zroutines.h"
+#include "gtm_caseconv.h"
+#include "longcpy.h"
+#include "error.h"
+
+#define GETTOK zro_gettok (&lp, top, &toktyp, &tok)
+
+static char *zro_str;
+
+error_def (ERR_BADQUAL);
+error_def (ERR_COMMAORRPAREXP);
+error_def (ERR_DIRONLY);
+error_def (ERR_FILEPARSE);
+error_def (ERR_FSEXP);
+error_def (ERR_MAXARGCNT);
+error_def (ERR_QUALEXP);
+error_def (ERR_QUALVAL);
+error_def (ERR_WILDCARD);
+error_def (ERR_ZROSYNTAX);
+error_def (ERR_NOLBRSRC);
+
+CONDITION_HANDLER(zro_load_ch)
+{
+ START_CH;
+ if (zro_str)
+ free(zro_str);
+ zro_str = NULL;
+ NEXTCH;
+}
+
+void zro_load (mstr *str)
+{
+ unsigned toktyp, status;
+ mstr tok;
+ struct FAB fab;
+ struct NAM nam;
+ unsigned char *lp, *top, qual[8];
+ boolean_t file;
+ zro_ent array[ZRO_MAX_ENTS];
+ int oi, si;
+ unsigned char buff[255];
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ /* D9D01-002286 - copy str->addr into the malloc'd area (zro_str) so that zro_root components
+ * always point to the persistent area (rather than to the string pool which may get garbage
+ * collected later). */
+ if (zro_str)
+ free(zro_str);
+ zro_str = (char *)malloc(str->len);
+ memcpy(zro_str, str->addr, str->len);
+
+ ESTABLISH(zro_load_ch); /* Condition handler to release zro_str if $ZRO fails to load */
+ fab = cc$rms_fab;
+ nam = cc$rms_nam;
+ fab.fab$l_nam = &nam;
+ nam.nam$l_esa = buff;
+ nam.nam$b_ess = SIZEOF(buff);
+
+ lp = zro_str;
+ top = lp + str->len;
+ array[0].type = ZRO_TYPE_COUNT;
+ array[0].count = 0;
+
+ GETTOK;
+ if (toktyp == TK_EOL)
+ {
+ status = sys$parse (&fab);
+ array[0].count = 1;
+ array[1].type = ZRO_TYPE_OBJECT;
+ array[1].node_present = FALSE;
+ array[1].str.len = 0;
+ memcpy (array[1].dvi, nam.nam$t_dvi, NAM$C_DVI + 12);
+ array[2].type = ZRO_TYPE_COUNT;
+ array[2].count = 1;
+ array[3] = array[1];
+ array[3].type = ZRO_TYPE_SOURCE;
+ si = 4;
+ } else
+ {
+ for (oi = 1;;)
+ {
+ file = FALSE;
+ if (toktyp != TK_IDENT)
+ rts_error(VARLSTCNT(5) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_FSEXP);
+ if (oi + 1 >= ZRO_MAX_ENTS)
+ rts_error(VARLSTCNT(7) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_MAXARGCNT, 1, ZRO_MAX_ENTS);
+ fab.fab$b_fns = tok.len;
+ fab.fab$l_fna = tok.addr;
+ status = sys$parse (&fab);
+ if (!(status & 1))
+ rts_error(VARLSTCNT(9) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_FILEPARSE, 2, tok.len, tok.addr,
+ status);
+ if (nam.nam$l_fnb & (NAM$M_WILDCARD))
+ rts_error(VARLSTCNT(8) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_WILDCARD, 2, tok.len, tok.addr);
+ if (nam.nam$l_fnb & (NAM$M_EXP_NAME | NAM$M_EXP_TYPE | NAM$M_EXP_VER))
+ {
+ file = TRUE;
+ status = sys$search(&fab);
+ if (!(status & 1))
+ rts_error(VARLSTCNT(9) ERR_ZROSYNTAX, 2, str->len, str->addr,
+ ERR_FILEPARSE, 2, tok.len, tok.addr, status);
+ }
+ array[0].count++;
+ if (file)
+ array[oi].type = ZRO_TYPE_OBJLIB;
+ else
+ array[oi].type = ZRO_TYPE_OBJECT;
+ array[oi].node_present = (nam.nam$l_fnb & (NAM$M_NODE));
+ array[oi].str = tok;
+ memcpy (array[oi].dvi, nam.nam$t_dvi, NAM$C_DVI + 12);
+ array[oi + 1].type = ZRO_TYPE_COUNT;
+ si = oi + 2;
+ GETTOK;
+ if (toktyp == TK_SLASH)
+ {
+ GETTOK;
+ if (toktyp != TK_IDENT)
+ rts_error(VARLSTCNT(5) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_QUALEXP);
+ if (tok.len == 3)
+ {
+ lower_to_upper (qual, tok.addr, 3);
+ if (!memcmp (qual, "SRC", 3))
+ {
+ if (file)
+ rts_error(VARLSTCNT(5) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_NOLBRSRC);
+
+ GETTOK;
+ if (si >= ZRO_MAX_ENTS)
+ rts_error(VARLSTCNT(7) ERR_ZROSYNTAX, 2, str->len, str->addr,
+ ERR_MAXARGCNT, 1, ZRO_MAX_ENTS);
+ if (toktyp == TK_COMMA || toktyp == TK_EOL)
+ {
+ array[oi + 1].count = 1;
+ array[si] = array[oi];
+ array[si].type = ZRO_TYPE_SOURCE;
+ si++;
+ } else if (toktyp == TK_EQUAL)
+ {
+ GETTOK;
+ if (toktyp != TK_LPAREN)
+ {
+ if (toktyp != TK_IDENT)
+ rts_error(VARLSTCNT(5) ERR_ZROSYNTAX, 2, str->len,
+ str->addr, ERR_FSEXP);
+ fab.fab$b_fns = tok.len;
+ fab.fab$l_fna = tok.addr;
+ status = sys$parse (&fab);
+ if (!(status & 1))
+ rts_error(VARLSTCNT(9) ERR_ZROSYNTAX, 2, str->len,
+ str->addr, ERR_FILEPARSE, 2, tok.len, tok.addr,
+ status);
+ if (nam.nam$l_fnb & (NAM$M_EXP_NAME | NAM$M_EXP_TYPE
+ | NAM$M_EXP_VER))
+ rts_error(VARLSTCNT(8) ERR_ZROSYNTAX, 2, str->len,
+ str->addr, ERR_DIRONLY, 2, tok.len,
+ tok.addr);
+ if (nam.nam$l_fnb & (NAM$M_WILDCARD))
+ rts_error(VARLSTCNT(8) ERR_ZROSYNTAX, 2, str->len,
+ str->addr, ERR_WILDCARD, 2, tok.len,
+ tok.addr);
+ array[oi + 1].count = 1;
+ array[si].type = ZRO_TYPE_SOURCE;
+ array[si].node_present = (nam.nam$l_fnb & (NAM$M_NODE));
+ array[si].str = tok;
+ memcpy (array[si].dvi, nam.nam$t_dvi, NAM$C_DVI + 12);
+ si++;
+ GETTOK;
+ } else
+ {
+ array[oi + 1].count = 0;
+ for (;;)
+ {
+ GETTOK;
+ if (toktyp != TK_IDENT)
+ rts_error(VARLSTCNT(5) ERR_ZROSYNTAX, 2, str->len,
+ str->addr, ERR_FSEXP);
+ if (si >= ZRO_MAX_ENTS)
+ rts_error(VARLSTCNT(7) ERR_ZROSYNTAX, 2, str->len,
+ str->addr,ERR_MAXARGCNT, 1, ZRO_MAX_ENTS);
+ fab.fab$b_fns = tok.len;
+ fab.fab$l_fna = tok.addr;
+ status = sys$parse (&fab);
+ if (!(status & 1))
+ rts_error(VARLSTCNT(9) ERR_ZROSYNTAX, 2, str->len,
+ str->addr,ERR_FILEPARSE, 2, tok.len,
+ tok.addr, status);
+ if (nam.nam$l_fnb & (NAM$M_EXP_NAME | NAM$M_EXP_TYPE
+ | NAM$M_EXP_VER))
+ rts_error(VARLSTCNT(8) ERR_ZROSYNTAX, 2, str->len,
+ str->addr, ERR_DIRONLY, 2, tok.len,
+ tok.addr);
+ if (nam.nam$l_fnb & (NAM$M_WILDCARD))
+ rts_error(VARLSTCNT(8) ERR_ZROSYNTAX, 2, str->len,
+ str->addr, ERR_WILDCARD, 2, tok.len,
+ tok.addr);
+ array[oi + 1].count++;
+ array[si].type = ZRO_TYPE_SOURCE;
+ array[si].node_present = (nam.nam$l_fnb & (NAM$M_NODE));
+ array[si].str = tok;
+ memcpy (array[si].dvi, nam.nam$t_dvi, NAM$C_DVI + 12);
+ si++;
+ GETTOK;
+ if (toktyp == TK_RPAREN)
+ break;
+ if (toktyp != TK_COMMA)
+ rts_error(VARLSTCNT(5) ERR_ZROSYNTAX, 2, str->len,
+ str->addr, ERR_COMMAORRPAREXP);
+ }
+ GETTOK;
+ }
+ } else
+ rts_error(VARLSTCNT(5) ERR_ZROSYNTAX, 2, str->len, str->addr, ERR_QUALVAL);
+ } else
+ rts_error(VARLSTCNT(8) ERR_ZROSYNTAX, 2, str->len, str->addr,
+ ERR_BADQUAL, 2, tok.len, tok.addr);
+ } else if (tok.len == 5)
+ {
+ lower_to_upper (qual, tok.addr, 5);
+ if (!memcmp (qual, "NOSRC", 5))
+ {
+ array[oi + 1].count = 0;
+ GETTOK;
+ } else
+ rts_error(VARLSTCNT(8) ERR_ZROSYNTAX, 2, str->len, str->addr,
+ ERR_BADQUAL, 2, tok.len, tok.addr);
+ } else
+ rts_error(VARLSTCNT(8) ERR_ZROSYNTAX, 2, str->len, str->addr,
+ ERR_BADQUAL, 2, tok.len, tok.addr);
+ } else if (toktyp == TK_COMMA || toktyp == TK_EOL)
+ {
+ if (!file)
+ {
+ array[oi + 1].count = 1;
+ array[si] = array[oi];
+ array[si].type = ZRO_TYPE_SOURCE;
+ si++;
+ } else
+ array[oi + 1].count = 0;
+ }
+ if (toktyp == TK_COMMA)
+ GETTOK;
+ else if (toktyp == TK_EOL)
+ break;
+ else
+ rts_error(VARLSTCNT(4) ERR_ZROSYNTAX, 2, str->len, str->addr);
+ oi = si;
+ }
+ }
+ if (TREF(zro_root))
+ free (TREF(zro_root));
+ TREF(zro_root) = malloc(si * SIZEOF(zro_ent));
+ memcpy((uchar_ptr_t)TREF(zro_root), (uchar_ptr_t)array, si * SIZEOF(zro_ent));
+ REVERT;
+}
diff --git a/sr_vvms/zro_search.c b/sr_vvms/zro_search.c
new file mode 100644
index 0000000..3da3069
--- /dev/null
+++ b/sr_vvms/zro_search.c
@@ -0,0 +1,163 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+#include <rms.h>
+
+#include "zroutines.h"
+#include "zl_olb.h"
+
+error_def (ERR_ZFILENMTOOLONG);
+
+/* if NULL == objstr, do not search for object, else pointer to object file text string */
+/* objdir is NULL if objstr is NULL, otherwise, return pointer to associated object directory
+ *objdir is NULL if object directory is not found */
+/* srcstr is like objstr, except for associated source program */
+/* srcdir is like objdir, except for associated source program directory*/
+void zro_search(mstr *objstr, zro_ent **objdir, mstr *srcstr, zro_ent **srcdir)
+{
+ unsigned obj_status, src_status;
+ uint4 librindx, status;
+ zro_ent *op, *sp, *op_result, *sp_result;
+ struct FAB objfab, srcfab;
+ struct NAM objnam, srcnam;
+ unsigned char objfn[255], srcfn[255];
+ unsigned char objes[255], srces[255];
+ int objcnt, srccnt, namidx;
+ mstr obj_string;
+ DCL_THREADGBL_ACCESS;
+
+ SETUP_THREADGBL_ACCESS;
+ if (!TREF(zro_root))
+ zro_init();
+ assert(objstr || srcstr); /* must search for object or source or both */
+ op_result = sp_result = NULL;
+ if (objstr)
+ {
+ assert(objdir); /* if object text, then must have pointer for result */
+ objfab = cc$rms_fab;
+ objnam = cc$rms_nam;
+ objfab.fab$l_nam = &objnam;
+ }
+ if (srcstr)
+ {
+ assert(srcdir); /* if source text, then must have pointer for result */
+ srcfab = cc$rms_fab;
+ srcnam = cc$rms_nam;
+ srcfab.fab$l_nam = &srcnam;
+ }
+ assert((TREF(zro_root))->type == ZRO_TYPE_COUNT);
+ objcnt = (TREF(zro_root))->count;
+ assert(objcnt);
+ for (op = TREF(zro_root) + 1; !op_result && !sp_result && objcnt-- > 0;)
+ {
+ assert(op->type == ZRO_TYPE_OBJECT || op->type == ZRO_TYPE_OBJLIB);
+ if (objstr)
+ {
+ if (op->type == ZRO_TYPE_OBJECT)
+ {
+ if (op->str.len > SIZEOF(objfn))
+ rts_error(VARLSTCNT(4) ERR_ZFILENMTOOLONG, 2, op->str.len, op->str.addr);
+ memcpy(objfn, op->str.addr, op->str.len);
+ namidx = op->str.len;
+ if (':' != objfn[namidx - 1] && ']' != objfn[namidx - 1]
+ && '>' != objfn[namidx - 1])
+ objfn[namidx++] = ':';
+ if (namidx + objstr->len > SIZEOF(objfn))
+ rts_error(VARLSTCNT(4) ERR_ZFILENMTOOLONG, 2, op->str.len, op->str.addr);
+ memcpy(&objfn[namidx], objstr->addr, objstr->len);
+ objfab.fab$l_fna = objfn;
+ objfab.fab$b_fns = namidx + objstr->len;
+ objnam.nam$l_esa = objes;
+ objnam.nam$b_ess = SIZEOF(objes);
+ obj_status = sys$parse(&objfab);
+ if (!(obj_status & 1))
+ rts_error(VARLSTCNT(2) obj_status, objfab.fab$l_stv);
+ objnam.nam$l_wcc = 0;
+ obj_status = sys$search(&objfab);
+ switch (obj_status)
+ {
+ case RMS$_NORMAL:
+ op_result = op;
+ break;
+ case RMS$_FNF:
+ case RMS$_NMF:
+ break;
+ default:
+ rts_error(VARLSTCNT(2) obj_status, objfab.fab$l_stv);
+ }
+ } else
+ {
+ obj_status = zl_olb(&op->str, objstr, &librindx);
+ status = lbr$close(&librindx);
+ if (!(status & 1))
+ rts_error(VARLSTCNT(1) status);
+ if (1 & obj_status)
+ op_result = op;
+ }
+ }
+ if (srcstr)
+ {
+ sp = op + 1;
+ assert(sp->type == ZRO_TYPE_COUNT);
+ srccnt = sp++->count;
+ for (; !sp_result && srccnt-- > 0; sp++)
+ {
+ assert(sp->type == ZRO_TYPE_SOURCE);
+ if (sp->str.len > SIZEOF(srcfn))
+ rts_error(VARLSTCNT(4) ERR_ZFILENMTOOLONG, 2, sp->str.len, sp->str.addr);
+ memcpy(srcfn, sp->str.addr, sp->str.len);
+ namidx = sp->str.len;
+ if (':' != srcfn[namidx - 1] && ']' != srcfn[namidx - 1]
+ && '>' != srcfn[namidx - 1])
+ srcfn[namidx++] = ':';
+ if (namidx + srcstr->len > SIZEOF(srcfn))
+ rts_error(VARLSTCNT(4) ERR_ZFILENMTOOLONG, 2, sp->str.len, sp->str.addr);
+ memcpy(&srcfn[namidx], srcstr->addr, srcstr->len);
+ srcfab.fab$l_fna = srcfn;
+ srcfab.fab$b_fns = namidx + srcstr->len;
+ srcnam.nam$l_esa = srces;
+ srcnam.nam$b_ess = SIZEOF(srces);
+ src_status = sys$parse(&srcfab);
+ if (!(src_status & 1))
+ rts_error(VARLSTCNT(2) src_status, srcfab.fab$l_stv);
+ srcnam.nam$l_wcc = 0;
+ src_status = sys$search(&srcfab);
+ switch (src_status)
+ {
+ case RMS$_NORMAL:
+ sp_result = sp;
+ op_result = op;
+ break;
+ case RMS$_FNF:
+ case RMS$_NMF:
+ break;
+ default:
+ rts_error(VARLSTCNT(2) src_status, srcfab.fab$l_stv);
+ }
+ }
+ op = sp;
+ } else
+ {
+ op++;
+ assert(op->type == ZRO_TYPE_COUNT);
+ op += op->count;
+ op++;
+ }
+ }
+ if (objdir)
+ *objdir = op_result;
+ if (srcdir)
+ *srcdir = sp_result;
+ return;
+}
diff --git a/sr_vvms/zroutinessp.h b/sr_vvms/zroutinessp.h
new file mode 100644
index 0000000..872d9fc
--- /dev/null
+++ b/sr_vvms/zroutinessp.h
@@ -0,0 +1,39 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2011 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#ifndef __ZROUTINESSP_H__
+#define __ZROUTINESSP_H__
+
+#include <nam.h>
+/*
+ * CAUTION ---- It is assumed that dvi, fid and did are contiguous not
+ * only in the zro_ent structures but also in the RMS
+ * NAM structure.
+ */
+
+typedef struct zro_ent_type
+{
+ uint4 type;
+ uint4 count;
+ boolean_t node_present;
+ mstr str;
+ char dvi[NAM$C_DVI];
+ unsigned short fid[3];
+ unsigned short did[3];
+} zro_ent;
+
+#define MAX_FILE_OPEN_TRIES 20
+#define WAIT_FOR_FILE_TIME 100 /* msec */
+
+void zro_gettok(unsigned char **lp, unsigned char *top, unsigned *toktyp, mstr *tok);
+void zro_search (mstr *objstr, zro_ent **objdir, mstr *srcstr, zro_ent **srcdir);
+
+#endif
diff --git a/sr_vvms/zshow_devices.c b/sr_vvms/zshow_devices.c
new file mode 100644
index 0000000..2fc6158
--- /dev/null
+++ b/sr_vvms/zshow_devices.c
@@ -0,0 +1,564 @@
+/****************************************************************
+ * *
+ * Copyright 2001, 2013 Fidelity Information Services, Inc *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include "gtm_string.h"
+#include "gtm_socket.h"
+#include "gtm_inet.h"
+
+#include <iodef.h>
+#include <rms.h>
+#include <trmdef.h>
+#include <ttdef.h>
+#include <tt2def.h>
+
+#include "io.h"
+#include "iottdef.h"
+#include "iombdef.h"
+#include "iomtdef.h"
+#include "iormdef.h"
+#include "iotcpdef.h"
+#include "gt_timer.h"
+#include "iosocketdef.h"
+#include "nametabtyp.h"
+#include "mlkdef.h"
+#include "zshow.h"
+#include "zshow_params.h"
+#include "mvalconv.h"
+
+typedef struct
+{
+ unsigned short mem;
+ unsigned short grp;
+} uic_struct;
+
+LITREF nametabent dev_param_names[];
+LITREF unsigned char dev_param_index[];
+LITREF zshow_index zshow_param_index[];
+
+static readonly char space_text[] = {' '};
+
+#define ZS_ONE_OUT(V, TEXT) ((V)->str.len = 1, (V)->str.addr = (TEXT), zshow_output(output, &(V)->str))
+#define ZS_STR_OUT(V, TEXT) ((V)->str.len = SIZEOF((TEXT)) - 1, (V)->str.addr = (TEXT), zshow_output(output, &(V)->str))
+#define ZS_PARM_SP(V, TEXT) ((V)->str.len = dev_param_names[dev_param_index[zshow_param_index[(TEXT)].letter] + \
+ zshow_param_index[(TEXT)].offset ].len, \
+ (V)->str.addr = dev_param_names[dev_param_index[zshow_param_index[(TEXT)].letter] + \
+ zshow_param_index[(TEXT)].offset ].name, zshow_output(output, &(V)->str), ZS_ONE_OUT((V), space_text))
+#define ZS_PARM_EQU(V, TEXT) ((V)->str.len = dev_param_names[dev_param_index[zshow_param_index[(TEXT)].letter] + \
+ zshow_param_index[(TEXT)].offset ].len, \
+ (V)->str.addr = dev_param_names[dev_param_index[zshow_param_index[(TEXT)].letter] + \
+ zshow_param_index[(TEXT)].offset ].name, zshow_output(output, &(V)->str), ZS_ONE_OUT((V), equal_text))
+
+GBLREF bool ctrlc_on;
+GBLREF io_log_name *io_root_log_name;
+GBLREF io_pair *io_std_device;
+
+void zshow_devices(zshow_out *output)
+{
+ static readonly char filchar_text[] = "CHARACTERS";
+ static readonly char filesc_text[] = "ESCAPES";
+ static readonly char terminal_text[] = "TERMINAL ";
+ static readonly char magtape_text[] = "MAGTAPE ";
+ static readonly char rmsfile_text[] = "RMS ";
+ static readonly char mailbox_text[] = "MAILBOX ";
+ static readonly char dollarc_text[] = "$C(";
+ static readonly char equal_text[] = {'='};
+ static readonly char comma_text[] = {','};
+ static readonly char quote_text[] = {'"'};
+ static readonly char lparen_text[] = {'('};
+ static readonly char rparen_text[] = {')'};
+ static readonly char devop[] = "OPEN ";
+ static readonly char devcl[] = "CLOSED ";
+ static readonly char largerecord[] = "BIGRECORD ";
+ static readonly char rfm_tab[][7] = {"UDF ", "FIXED ", "VAR ", "VFC ", "STM ", "STMLF ", "STMCR "};
+ bool first;
+ int4 i, j, ii, jj;
+ io_log_name *l; /* logical name pointer */
+ mval v;
+ mval m;
+ struct FAB *f;
+ struct RAB *r;
+ d_mb_struct *mb_ptr;
+ d_mt_struct *mt_ptr;
+ d_rm_struct *rm_ptr;
+ d_tt_struct *tt_ptr;
+ d_socket_struct *dsocketptr;
+ socket_struct *socketptr;
+ io_termmask *mask_out;
+ unsigned char delim_buff_sm[MAX_DELIM_LEN];
+ unsigned short delim_len_sm;
+ char delim_mstr_buff[(MAX_DELIM_LEN * MAX_ZWR_EXP_RATIO) + 11];
+ mstr delim;
+ int delim_len;
+ static readonly char space8_text[] = " "; /* starting from here, for gtmsocket only */
+ static readonly char lb_text[] = {'['};
+ static readonly char rb_text[] = {']'};
+ static readonly char at_text[] = {'@'};
+ static readonly char delimiter_text[] = "DELIMITER ";
+ static readonly char nodelimiter_text[] = "NODELIMITER ";
+ static readonly char local_text[] = "LOCAL=";
+ static readonly char remote_text[] = "REMOTE=";
+ static readonly char total_text[] = "TOTAL=";
+ static readonly char current_text[] = "CURRENT=";
+ static readonly char passive_text[] = "PASSIVE ";
+ static readonly char active_text[] = "ACTIVE ";
+ static readonly char socket_text[] = "SOCKET";
+ static readonly char descriptor_text[] = "DESC=";
+ static readonly char trap_text[] = "TRAP ";
+ static readonly char notrap_text[] = "NOTRAP ";
+ static readonly char zdelay_text[] = "ZDELAY ";
+ static readonly char znodelay_text[] = "ZNODELAY ";
+ static readonly char zbfsize_text[] = "ZBFSIZE=";
+ static readonly char zibfsize_text[] = "ZIBFSIZE=";
+ static readonly char port_text[] = "PORT=";
+ static readonly char zsh_socket_state[][10] =
+ { "CONNECTED"
+ ,"LISTENING"
+ ,"BOUND"
+ ,"CREATED"
+ };
+ static readonly char morereadtime_text[] = "MOREREADTIME=";
+
+ v.mvtype = MV_STR;
+ for (l = io_root_log_name; l != 0; l = l->next)
+ {
+ if (l->dollar_io[0] != IO_ESC && l->iod->trans_name == l)
+ {
+ 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)
+ {
+ ZS_STR_OUT(&v, devop);
+ switch(l->iod->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 ((int4)(tt_ptr->item_list[0].addr) & TRM$M_TM_CVTLOW)
+ ZS_PARM_SP(&v, zshow_conv);
+ 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_char) & TT$M_NOECHO)
+ ZS_PARM_SP(&v, zshow_noecho);
+ if ((int4)(tt_ptr->ext_cap) & TT2$M_EDITING)
+ ZS_PARM_SP(&v, zshow_edit);
+ else
+ ZS_PARM_SP(&v, zshow_noedit);
+ if (!((int4)(tt_ptr->term_char) & TT$M_ESCAPE))
+ ZS_PARM_SP(&v, zshow_noesca);
+ if (tt_ptr->in_buf_sz != TTDEF_BUF_SZ)
+ {
+ ZS_PARM_EQU(&v, zshow_field);
+ MV_FORCE_MVAL(&m, tt_ptr->in_buf_sz);
+ mval_write(output, &m, FALSE);
+ ZS_ONE_OUT(&v, space_text);
+ }
+ if (tt_ptr->term_char & TT$M_HOSTSYNC)
+ ZS_PARM_SP(&v, zshow_host);
+ else
+ ZS_PARM_SP(&v, zshow_nohost);
+ if (tt_ptr->ext_cap & TT2$M_INSERT)
+ ZS_PARM_SP(&v, zshow_inse);
+ else
+ ZS_PARM_SP(&v, zshow_noinse);
+ if (tt_ptr->ext_cap & TT2$M_PASTHRU)
+ ZS_PARM_SP(&v, zshow_past);
+ else
+ ZS_PARM_SP(&v, zshow_nopast);
+ if (tt_ptr->term_char & TT$M_READSYNC)
+ ZS_PARM_SP(&v, zshow_reads);
+ else
+ ZS_PARM_SP(&v, zshow_noreads);
+ if (tt_ptr->term_char & TT$M_TTSYNC)
+ ZS_PARM_SP(&v, zshow_ttsy);
+ else
+ ZS_PARM_SP(&v, zshow_nottsy);
+ if (tt_ptr->term_char & TT$M_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->item_list[2].addr;
+ if (mask_out->mask[0] != TERM_MSK)
+ {
+ 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))
+ {
+ 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_PARM_EQU(&v, zshow_width);
+ MV_FORCE_MVAL(&m, l->iod->width);
+ mval_write(output, &m, FALSE);
+ ZS_ONE_OUT(&v, space_text);
+ ZS_PARM_EQU(&v, zshow_leng);
+ MV_FORCE_MVAL(&m, 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_fil);
+ if (l->iod->write_filter & CHAR_FILTER)
+ {
+ 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);
+ }
+ }
+ if (l->iod->write_filter & ESC1)
+ ZS_STR_OUT(&v, filesc_text);
+ if (twoparms)
+ ZS_ONE_OUT(&v, rparen_text);
+ ZS_ONE_OUT(&v, space_text);
+ }
+ break;
+ case mt:
+ ZS_STR_OUT(&v, magtape_text);
+ mt_ptr = (d_tt_struct *)l->iod->dev_sp;
+ if (mt_ptr->block_sz != MTDEF_BUF_SZ)
+ {
+ ZS_PARM_EQU(&v, zshow_bloc);
+ MV_FORCE_MVAL(&m, mt_ptr->block_sz);
+ mval_write(output, &m, FALSE);
+ ZS_ONE_OUT(&v, space_text);
+ }
+ if (mt_ptr->record_sz != MTDEF_REC_SZ)
+ {
+ ZS_PARM_EQU(&v, zshow_rec);
+ MV_FORCE_MVAL(&m, mt_ptr->record_sz);
+ mval_write(output, &m, FALSE);
+ ZS_ONE_OUT(&v, space_text);
+ }
+ if (mt_ptr->read_only)
+ ZS_PARM_SP(&v, zshow_read);
+ if (mt_ptr->ebcdic)
+ ZS_PARM_SP(&v, zshow_ebcd);
+ if (mt_ptr->fixed)
+ ZS_PARM_SP(&v, zshow_fixed);
+ if (mt_ptr->read_mask & IO$M_DATACHECK)
+ ZS_PARM_SP(&v, zshow_rchk);
+ if (mt_ptr->write_mask & IO$M_DATACHECK)
+ ZS_PARM_SP(&v, zshow_wchk);
+ if (!l->iod->wrap)
+ ZS_PARM_SP(&v, zshow_nowrap);
+ break;
+ case rm:
+ ZS_STR_OUT(&v, rmsfile_text);
+ rm_ptr = (d_rm_struct *)l->iod->dev_sp;
+ f = &rm_ptr->f;
+ r = &rm_ptr->r;
+ if (r->rab$l_rop & RAB$M_CVT)
+ ZS_PARM_SP(&v, zshow_conv);
+ if (f->fab$l_alq != 0)
+ {
+ ZS_PARM_EQU(&v, zshow_allo);
+ MV_FORCE_MVAL(&m, f->fab$l_alq);
+ mval_write(output, &m, FALSE);
+ ZS_ONE_OUT(&v, space_text);
+ }
+ if (f->fab$l_fop & FAB$M_DLT)
+ ZS_PARM_SP(&v, zshow_dele);
+ if (f->fab$w_deq != 0)
+ {
+ ZS_PARM_EQU(&v, zshow_exte);
+ MV_FORCE_MVAL(&m, f->fab$w_deq);
+ mval_write(output, &m, FALSE);
+ ZS_ONE_OUT(&v, space_text);
+ }
+ assert(FAB$C_MAXRFM == (SIZEOF(rfm_tab)/SIZEOF(rfm_tab[0]) - 1));
+ if (FAB$C_MAXRFM >= rm_ptr->b_rfm && FAB$C_RFM_DFLT != rm_ptr->b_rfm)
+ ZS_STR_OUT(&v, rfm_tab[rm_ptr->b_rfm]);
+ if (rm_ptr->largerecord)
+ ZS_STR_OUT(&v, largerecord);
+ if (f->fab$b_fac == FAB$M_GET)
+ ZS_PARM_SP(&v, zshow_read);
+ if (rm_ptr->l_mrs != DEF_RM_WIDTH)
+ {
+ ZS_PARM_EQU(&v, zshow_rec);
+ MV_FORCE_MVAL(&m, rm_ptr->l_mrs);
+ mval_write(output, &m, FALSE);
+ ZS_ONE_OUT(&v, space_text);
+ }
+/* smw should we add width aka usz */
+ if (f->fab$b_shr & FAB$M_SHRGET)
+ ZS_PARM_SP(&v, zshow_shar);
+ /*
+ if (f->fab$l_fop & FAB$M_SPL)
+ ZS_PARM_SP(&v, zshow_spo);
+ if (f->fab$l_fop & FAB$M_SCF)
+ ZS_PARM_SP(&v, zshow_sub);
+ */
+ if (!l->iod->wrap)
+ ZS_PARM_SP(&v, zshow_nowrap);
+ if (f->fab$l_xab)
+ {
+/* smw need to handle other XABs and uic as octal */
+ struct XABPRO *xabpro;
+ uic_struct uic;
+
+ ZS_PARM_EQU(&v, zshow_uic);
+ ZS_ONE_OUT(&v, quote_text);
+ xabpro = f->fab$l_xab;
+ memcpy(&uic, &xabpro->xab$l_uic, SIZEOF(int4));
+ MV_FORCE_MVAL(&m, uic.grp);
+ mval_write(output, &m, FALSE);
+ ZS_ONE_OUT(&v, comma_text);
+ MV_FORCE_MVAL(&m, uic.mem);
+ mval_write(output, &m, FALSE);
+ ZS_ONE_OUT(&v, quote_text);
+ ZS_ONE_OUT(&v, space_text);
+ }
+ break;
+ case mb:
+ ZS_STR_OUT(&v, mailbox_text);
+ mb_ptr = (d_mb_struct *)l->iod->dev_sp;
+ if (!(mb_ptr->write_mask & IO$M_NOW))
+ ZS_PARM_SP(&v, zshow_wait);
+ if (mb_ptr->prmflg)
+ ZS_PARM_SP(&v, zshow_prmmbx);
+ if (mb_ptr->maxmsg != DEF_MB_MAXMSG)
+ {
+ ZS_PARM_EQU(&v, zshow_bloc);
+ MV_FORCE_MVAL(&m, mb_ptr->maxmsg);
+ mval_write(output, &m, FALSE);
+ ZS_ONE_OUT(&v, space_text);
+ }
+ if (mb_ptr->promsk & IO_RD_ONLY)
+ ZS_PARM_SP(&v, zshow_read);
+ if (mb_ptr->del_on_close)
+ ZS_PARM_SP(&v, zshow_dele);
+ if (mb_ptr->promsk & IO_SEQ_WRT)
+ ZS_PARM_SP(&v, zshow_write);
+ if (l->iod->width != DEF_MB_MAXMSG)
+ {
+ ZS_PARM_EQU(&v, zshow_width);
+ MV_FORCE_MVAL(&m, l->iod->width);
+ mval_write(output, &m, FALSE);
+ ZS_ONE_OUT(&v, space_text);
+ }
+ if (!l->iod->wrap)
+ ZS_PARM_SP(&v, zshow_nowrap);
+ if (l->iod->length != DEF_MB_LENGTH)
+ {
+ ZS_PARM_EQU(&v, zshow_leng);
+ MV_FORCE_MVAL(&m, l->iod->length);
+ mval_write(output, &m, FALSE);
+ ZS_ONE_OUT(&v, space_text);
+ }
+ break;
+ case gtmsocket:
+ delim.addr = delim_mstr_buff;
+ delim_len = 0;
+ ZS_STR_OUT(&v, socket_text);
+ dsocketptr = (d_socket_struct *)l->iod->dev_sp;
+ ZS_ONE_OUT(&v, space_text);
+ 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);
+ 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);
+ 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 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 (socketptr->passive)
+ {
+ ZS_STR_OUT(&v, port_text);
+ MV_FORCE_MVAL(&m, (int)socketptr->local.port);
+ mval_write(output, &m, FALSE);
+ } else
+ {
+ 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);
+ ZS_ONE_OUT(&v, at_text);
+ MV_FORCE_MVAL(&m, (int)socketptr->remote.port);
+ mval_write(output, &m, FALSE);
+ ZS_ONE_OUT(&v, space_text);
+ /* to be added later ...
+ 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);
+ MV_FORCE_MVAL(&m, (int)socketptr->local.port);
+ mval_write(output, &m, FALSE);
+ */
+ }
+ 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, 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);
+ /* 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, socketptr->moreread_timeout);
+ mval_write(output, &m, FALSE);
+ }
+ output->flush = TRUE;
+ zshow_output(output, 0);
+ }
+ default:
+ v.str.len = 0;
+ break;
+ }
+ if (l->iod->error_handler.len)
+ {
+ ZS_PARM_EQU(&v, zshow_exce);
+ ZS_ONE_OUT(&v, quote_text);
+ v.str = l->iod->error_handler;
+ zshow_output(output, &v.str);
+ output->flush = TRUE;
+ ZS_ONE_OUT(&v, quote_text);
+ } else
+ {
+ output->flush = TRUE;
+ zshow_output(output, 0);
+ }
+ }
+ else
+ {
+ output->flush = TRUE;
+ ZS_STR_OUT(&v, devcl);
+ }
+ }
+ }
+}
diff --git a/sr_vvms/zshow_zcalls.c b/sr_vvms/zshow_zcalls.c
new file mode 100644
index 0000000..edaf775
--- /dev/null
+++ b/sr_vvms/zshow_zcalls.c
@@ -0,0 +1,93 @@
+/****************************************************************
+ * *
+ * Copyright 2001 Sanchez Computer Associates, Inc. *
+ * *
+ * This source code contains the intellectual property *
+ * of its copyright holder(s), and is made available *
+ * under a license. If you do not know the terms of *
+ * the license, please stop and do not read further. *
+ * *
+ ****************************************************************/
+
+#include "mdef.h"
+
+#include <descrip.h>
+
+#include "mlkdef.h"
+#include "zshow.h"
+#include "zcall.h"
+
+GBLREF zctabrtn *zctab, *zctab_end;
+GBLREF zcpackage *zcpack_start, *zcpack_end;
+
+/********************************************************************
+ * the package and routine data structures are as follows:
+ * zcpackage structure points to the
+ * name of each package.
+ * and begin, and endpoints of the routines in the package.
+ *
+ * +-------------|----------|---------------------+
+ * zcpack_start zcpack ... zcpack... zcpack_end
+ *
+ * zctabrtn structure points to the routines
+ *
+ * zctab (...routines...) zctab_end
+ * +---------------------------------------------+
+ *
+ * sample
+ * zctab: --routine-- |There might be routines that do
+ * --routine-- |not belong to a package
+ * zcpack1->begin: --routine--
+ * --routine--
+ * zcpack1->end: --routine-- |Other routines that do not
+ * --routine-- |belong to a package
+ * zcpack2->begin: --routine--
+ * --routine--
+ *zctab_end:zcpack2->end:--routine--
+ *
+ *
+ ********************************************************************/
+static readonly char period[] = ".";
+void zshow_zcalls(zshow_out *output)
+{
+ mval decpt_mv,pack_mv,rtn_mv;
+ zctabrtn *zcrtn;
+ zcpackage *zcpack;
+ error_def(ERR_ZCALLTABLE);
+
+ decpt_mv.mvtype = pack_mv.mvtype = rtn_mv.mvtype = MV_STR;
+ decpt_mv.str.len = 1;
+ decpt_mv.str.addr = .
+ pack_mv.str.len = 0;
+ zcrtn = zctab;
+ zcpack = zcpack_start;
+ while (zcrtn < zctab_end)
+ {
+ if (0 == zcrtn->callnamelen)
+ rts_error(VARLSTCNT(1) ERR_ZCALLTABLE);
+ if (zcpack < zcpack_end)
+ {
+ if (zcpack->end <= zcrtn)
+ {
+ zcpack++;
+ pack_mv.str.len = 0;
+ }
+ if ((0 == pack_mv.str.len) && (zcpack->begin <= zcrtn))
+ {
+ pack_mv.str.addr = zcpack->packname + 1;
+ pack_mv.str.len = *zcpack->packname;
+ }
+ }
+ rtn_mv.str.addr = &zcrtn->callname;
+ rtn_mv.str.len = zcrtn->callnamelen;
+ if (pack_mv.str.len)
+ {
+ zshow_output(output,&pack_mv.str);
+ zshow_output(output,&decpt_mv.str);
+ }
+ output->flush = TRUE;
+ zshow_output(output,&rtn_mv.str);
+ zcrtn = (zctabrtn *)((char *)zcrtn + zcrtn->entry_length);
+ }
+ return;
+}
diff --git a/sr_x86_64/compswap.s b/sr_x86_64/compswap.s
index 9164243..d8d2c62 100644
--- a/sr_x86_64/compswap.s
+++ b/sr_x86_64/compswap.s
@@ -1,6 +1,6 @@
#################################################################
# #
-# Copyright 2007 Fidelity Information Services, Inc #
+# Copyright 2007, 2013 Fidelity Information Services, Inc #
# #
# This source code contains the intellectual property #
# of its copyright holder(s), and is made available #
@@ -34,4 +34,5 @@ ENTRY compswap
fail:
xor REG32_RET0,REG32_RET0 # return FALSE
+ pause
ret
diff --git a/sr_x86_64/merrors_ansi.h b/sr_x86_64/merrors_ansi.h
index faa0fe7..38cc6a1 100644
--- a/sr_x86_64/merrors_ansi.h
+++ b/sr_x86_64/merrors_ansi.h
@@ -193,7 +193,7 @@ const static readonly int error_ansi[] = {
5, /* TEXTARG */
0, /* TMPSTOREMAX */
0, /* VIEWCMD */
- 12, /* TXTNEGLIN */
+ 0, /* JNI */
0, /* TXTSRCFMT */
0, /* UIDMSG */
0, /* UIDSND */
@@ -202,9 +202,9 @@ const static readonly int error_ansi[] = {
39, /* VAREXPECTED */
0, /* VARRECBLKSZ */
0, /* MAXARGCNT */
- 0, /* WCFAIL */
+ 0, /* GTMSECSHRSEMGET */
0, /* VIEWARGCNT */
- 0, /* XKILLCNTEXC */
+ 0, /* GTMSECSHRDMNSTARTED */
0, /* ZATTACHERR */
0, /* ZDATEFMT */
0, /* ZEDFILSPEC */
@@ -271,14 +271,14 @@ const static readonly int error_ansi[] = {
21, /* MULTFORMPARM */
16, /* QUITARGUSE */
0, /* NAMEEXPECTED */
- 11, /* UNUSEDMSG438 */
+ 11, /* FALLINTOFLST */
16, /* NOTEXTRINSIC */
- 11, /* UNUSEDMSG440 */
+ 0, /* GTMSECSHRREMSEMFAIL */
20, /* FMLLSTMISSING */
58, /* ACTLSTTOOLONG */
0, /* ACTOFFSET */
0, /* MAXACTARG */
- 0, /* GTMDUMPFAIL */
+ 0, /* GTMSECSHRREMSEM */
0, /* JNLTMQUAL2 */
0, /* GDINVALID */
0, /* ASSERT */
@@ -422,13 +422,13 @@ const static readonly int error_ansi[] = {
0, /* BEGINST */
0, /* INVMVXSZ */
0, /* JNLWRTNOWWRTR */
- 0, /* MUPGDERR */
+ 0, /* GTMSECSHRSHMCONCPROC */
0, /* JNLINVALLOC */
0, /* JNLINVEXT */
0, /* MUPCLIERR */
0, /* JNLTMQUAL4 */
- 0, /* UNUSEDMSG594 */
- 0, /* UNUSEDMSG595 */
+ 0, /* GTMSECSHRREMSHM */
+ 0, /* GTMSECSHRREMFILE */
0, /* MUNODBNAME */
0, /* FILECREATE */
0, /* FILENOTCREATE */
@@ -450,7 +450,7 @@ const static readonly int error_ansi[] = {
0, /* WCWRNNOTCHG */
0, /* ZCWRONGDESC */
0, /* MUTNWARN */
- 0, /* JNLNAMLEN */
+ 0, /* GTMSECSHRUPDDBHDR */
0, /* LCKSTIMOUT */
0, /* CTLMNEMAXLEN */
0, /* CTLMNEXPECTED */
@@ -586,14 +586,14 @@ const static readonly int error_ansi[] = {
0, /* GTMSECSHR */
0, /* GTMSECSHRSRVFID */
0, /* GTMSECSHRSRVFIL */
- 0, /* SOCKACTNA */
+ 0, /* FREEBLKSLOW */
0, /* PROTNOTSUP */
0, /* DELIMSIZNA */
0, /* INVCTLMNE */
0, /* SOCKLISTEN */
0, /* LQLENGTHNA */
0, /* ADDRTOOLONG */
- 76, /* UNUSEDMSG760 */
+ 0, /* GTMSECSHRGETSEMFAIL */
0, /* CPBEYALLOC */
0, /* DBRDONLY */
0, /* DUPTN */
@@ -614,7 +614,7 @@ const static readonly int error_ansi[] = {
0, /* NOFORKCORE */
0, /* JNLREAD */
0, /* JNLMINALIGN */
- 0, /* JNLDSKALIGN */
+ 0, /* UNUSEDMSG781 */
0, /* JNLPOOLSETUP */
0, /* JNLSTATEOFF */
0, /* RECVPOOLSETUP */
@@ -677,7 +677,7 @@ const static readonly int error_ansi[] = {
0, /* BUFFLUFAILED */
0, /* MUQUALINCOMP */
0, /* DISTPATHMAX */
- 0, /* MAXTRACEHEIGHT */
+ 0, /* UNUSEDMSG844 */
0, /* IMAGENAME */
0, /* GTMSECSHRPERM */
0, /* GTMDISTUNDEF */
@@ -783,7 +783,7 @@ const static readonly int error_ansi[] = {
0, /* DBMBPFRINT */
0, /* DBMAXKEYEXC */
0, /* DBMXRSEXCMIN */
- 0, /* DBMAXRSEXBL */
+ 0, /* UNUSEDMSG950 */
0, /* DBREADBM */
0, /* DBCOMPTOOLRG */
0, /* DBVERPERFWARN2 */
@@ -805,7 +805,7 @@ const static readonly int error_ansi[] = {
0, /* SEMWT2LONG */
0, /* REPLINSTOPEN */
0, /* REPLINSTCLOSE */
- 0, /* JNLNOTFOUND */
+ 0, /* UNUSEDMSG972 */
0, /* DBCRERR8 */
0, /* NUMPROCESSORS */
0, /* DBADDRANGE8 */
@@ -822,16 +822,16 @@ const static readonly int error_ansi[] = {
0, /* RENAMEFAIL */
0, /* FILERENAME */
0, /* JNLBUFINFO */
- 0, /* JNLQIOLOCKED */
- 0, /* JNLEOFPREZERO */
+ 0, /* UNUSEDMSG989 */
+ 0, /* UNUSEDMSG990 */
0, /* TPNOTACID */
0, /* JNLSETDATA2LONG */
0, /* JNLNEWREC */
0, /* REPLFTOKSEM */
- 0, /* GETCWD */
+ 0, /* UNUSEDMSG995 */
0, /* EXTRIOERR */
0, /* EXTRCLOSEERR */
- 0, /* TRUNCATE */
+ 0, /* UNUSEDMSG998 */
0, /* REPLEXITERR */
0, /* MUDESTROYSUC */
0, /* DBRNDWN */
@@ -912,7 +912,7 @@ const static readonly int error_ansi[] = {
0, /* SYSTEMVALUE */
0, /* SIZENOTVALID4 */
0, /* STRNOTVALID */
- 0, /* RECNOCREJNL */
+ 0, /* UNUSEDMSG1079 */
0, /* ERRWETRAP */
0, /* TRACINGON */
0, /* CITABENV */
@@ -940,9 +940,9 @@ const static readonly int error_ansi[] = {
0, /* ZDIROUTOFSYNC */
0, /* GBLNOEXIST */
0, /* MAXBTLEVEL */
- 0, /* JNLSTRESTFL */
+ 0, /* UNUSEDMSG1107 */
0, /* JNLALIGNSZCHG */
- 0, /* MAXTRACELEVEL */
+ 0, /* UNUSEDMSG1109 */
0, /* GVFAILCORE */
0, /* DBCDBNOCERTIFY */
0, /* DBFRZRESETSUC */
@@ -1187,7 +1187,7 @@ const static readonly int error_ansi[] = {
0, /* TRIGTLVLCHNG */
0, /* TRIGNAMEUNIQ */
0, /* ZTRIGINVACT */
- 0, /* UNUSEDMSG1354 */
+ 0, /* INDRCOMPFAIL */
0, /* QUITALSINV */
0, /* PROCTERM */
0, /* SRCLNNTDSP */
@@ -1200,10 +1200,10 @@ const static readonly int error_ansi[] = {
0, /* SSATTACHSHM */
0, /* TRIGDEFNOSYNC */
0, /* TRESTMAX */
- 0, /* TPLOCKRESTMAX */
+ 0, /* UNUSEDMSG1367 */
0, /* GBLEXPECTED */
0, /* GVZTRIGFAIL */
- 0, /* UNUSEDMSG1370 */
+ 0, /* MUUSERLBK */
0, /* SETINSETTRIGONLY */
0, /* DZTRIGINTRIG */
0, /* SECNODZTRIGINTP */
@@ -1215,7 +1215,7 @@ const static readonly int error_ansi[] = {
0, /* REPLXENDIANFAIL */
0, /* ZGOTOINVLVL2 */
0, /* GTMSECSHRCHDIRF */
- 0, /* UNUSEDMSG1382 */
+ 0, /* JNLORDBFLU */
0, /* ZCCLNUPRTNMISNG */
0, /* ZCINVALIDKEYWORD */
0, /* REPLNOMULTILINETRG */
@@ -1247,7 +1247,7 @@ const static readonly int error_ansi[] = {
0, /* NOSUPPLSUPPL */
0, /* REPL2OLD */
0, /* EXTRFILEXISTS */
- 0, /* UNUSEDMSG1414 */
+ 0, /* MUUSERECOV */
0, /* SECNOTSUPPLEMENTARY */
0, /* SUPRCVRNEEDSSUPSRC */
0, /* UNUSEDMSG1417 */
@@ -1270,7 +1270,7 @@ const static readonly int error_ansi[] = {
0, /* ORLBKNOV4BLK */
0, /* DBROLLEDBACK */
0, /* DSEWCREINIT */
- 0, /* UNUSEDMSG1437 */
+ 0, /* MURNDWNOVRD */
0, /* REPLONLNRLBK */
0, /* SRVLCKWT2LNG */
0, /* IGNBMPMRKFREE */
@@ -1340,4 +1340,25 @@ const static readonly int error_ansi[] = {
0, /* TPRESTNESTERR */
0, /* JNLFILRDOPN */
0, /* SEQNUMSEARCHTIMEOUT */
+ 0, /* FTOKKEY */
+ 0, /* SEMID */
+ 0, /* JNLQIOSALVAGE */
+ 0, /* FAKENOSPCLEARED */
+ 0, /* MMFILETOOLARGE */
+ 0, /* BADZPEEKARG */
+ 0, /* BADZPEEKRANGE */
+ 0, /* BADZPEEKFMT */
+ 0, /* DBMBMINCFREFIXED */
+ 0, /* NULLENTRYREF */
+ 0, /* ZPEEKNORPLINFO */
+ 0, /* MMREGNOACCESS */
+ 0, /* MALLOCMAXUNIX */
+ 0, /* MALLOCMAXVMS */
+ 0, /* HOSTCONFLICT */
+ 0, /* GETADDRINFO */
+ 0, /* GETNAMEINFO */
+ 0, /* SOCKBIND */
+ 0, /* INSTFRZDEFER */
+ 0, /* REGOPENRETRY */
+ 0, /* REGOPENFAIL */
};
diff --git a/sr_x86_64/merrors_ctl.c b/sr_x86_64/merrors_ctl.c
index 10346ac..a409df6 100644
--- a/sr_x86_64/merrors_ctl.c
+++ b/sr_x86_64/merrors_ctl.c
@@ -195,7 +195,7 @@ LITDEF err_msg merrors[] = {
"TEXTARG", "Invalid argument to $TEXT function", 0,
"TMPSTOREMAX", "Maximum space for temporary values exceeded", 0,
"VIEWCMD", "View parameter is not valid with VIEW command", 0,
- "TXTNEGLIN", "A line prior to line number zero was referenced in $TEXT", 0,
+ "JNI", "!AD", 2,
"TXTSRCFMT", "$TEXT encountered an invalid source program file format", 0,
"UIDMSG", "Unidentified message received", 0,
"UIDSND", "Unidentified sender PID", 0,
@@ -204,9 +204,9 @@ LITDEF err_msg merrors[] = {
"VAREXPECTED", "Variable expected in this context", 0,
"VARRECBLKSZ", "Blocksize must be at least record size + 4 bytes", 0,
"MAXARGCNT", "Maximum number of arguments !UL exceeded", 1,
- "WCFAIL", "The database cache is corrupt", 0,
+ "GTMSECSHRSEMGET", "semget error errno = !UL", 1,
"VIEWARGCNT", "View parameter !AD has inappropriate number of subparameters", 2,
- "XKILLCNTEXC", "Maximum number of arguments (!UL) to exclusive kill exceeded", 1,
+ "GTMSECSHRDMNSTARTED", "gtmsecshr daemon started (key: 0x!XL) for version !AD from !AD", 5,
"ZATTACHERR", "Error attaching to \"!AD\"", 2,
"ZDATEFMT", "$ZDATE format string contains invalid character", 0,
"ZEDFILSPEC", "Illegal ZEDIT file specification: !AD", 2,
@@ -273,14 +273,14 @@ LITDEF err_msg merrors[] = {
"MULTFORMPARM", "This formal parameter is multiply defined", 0,
"QUITARGUSE", "Quit cannot take an argument in this context", 0,
"NAMEEXPECTED", "A local variable name is expected in this context", 0,
- "UNUSEDMSG438", "ACTLSTEXP: Last used in V5.4-002B", 0,
+ "FALLINTOFLST", "Fall-through to a label with formallist is not allowed", 0,
"NOTEXTRINSIC", "Quit does not return to an extrinsic function: argument not allowed", 0,
- "UNUSEDMSG440", "FMLLSTPRESENT: Last used in V5.4-002B", 0,
+ "GTMSECSHRREMSEMFAIL", "error removing semaphore errno = !UL", 1,
"FMLLSTMISSING", "The formal list is absent from a label called with an actual list: !AD", 2,
"ACTLSTTOOLONG", "More actual parameters than formal parameters: !AD", 2,
"ACTOFFSET", "Actuallist not allowed with offset", 0,
"MAXACTARG", "Maximum number of actual arguments exceeded", 0,
- "GTMDUMPFAIL", "Could not create DUMP FILE", 0,
+ "GTMSECSHRREMSEM", "[client pid !UL] Semaphore (!UL) removed", 2,
"JNLTMQUAL2", "Time qualifier LOOKBACK_TIME=\"!AZ\" is later than SINCE_TIME=\"!AZ\"", 2,
"GDINVALID", "Unrecognized Global Directory file format: !AD, expected label: !AD, found: !AD", 6,
"ASSERT", "Assert failed in !AD line !UL for expression (!AD)", 5,
@@ -424,13 +424,13 @@ LITDEF err_msg merrors[] = {
"BEGINST", "Beginning LOAD at record number: !UL", 1,
"INVMVXSZ", "Invalid block size for GOQ load format", 0,
"JNLWRTNOWWRTR", "Journal writer attempting another write", 0,
- "MUPGDERR", "Command aborted due to global directory errors", 0,
+ "GTMSECSHRSHMCONCPROC", "More than one process attached to Shared memory segment (!UL) not removed (!UL)", 2,
"JNLINVALLOC", "Journal file allocation !UL is not within the valid range of !UL to !UL. Journal file not created.", 3,
"JNLINVEXT", "Journal file extension !UL is greater than the maximum allowed size of !UL. Journal file not created.", 2,
"MUPCLIERR", "Action not taken due to CLI errors", 0,
"JNLTMQUAL4", "Time qualifier BEFORE_TIME=\"!AZ\" is less than AFTER_TIME=\"!AZ\"", 2,
- "UNUSEDMSG594", "JNLBUFFTOOLG Last used in V5.5-000", 0,
- "UNUSEDMSG595", "JNLBUFFTOOSM Last used in V5.5-000", 0,
+ "GTMSECSHRREMSHM", "[client pid !UL] Shared memory segment (!UL) removed, nattch = !UL", 3,
+ "GTMSECSHRREMFILE", "[client pid !UL] File (!AD) removed", 3,
"MUNODBNAME", "A database name or the region qualifier must be specified", 0,
"FILECREATE", "!AD file !AD created", 4,
"FILENOTCREATE", "!AD file !AD not created", 4,
@@ -452,7 +452,7 @@ LITDEF err_msg merrors[] = {
"WCWRNNOTCHG", "Not all specified database files were changed", 0,
"ZCWRONGDESC", "A string longer than 65535 is passed via 32-bit descriptor", 0,
"MUTNWARN", "Database file !AD has 0x!16 at XQ more transactions to go before reaching the transaction number limit (0x!16 at XQ). Renew database with MUPIP INTEG TN_RESET", 4,
- "JNLNAMLEN", "Journal file name !AD: for database file !AD exceeds maximum length of !UL", 5,
+ "GTMSECSHRUPDDBHDR", "[client pid !UL] database fileheader (!AD) updated !AD", 5,
"LCKSTIMOUT", "DAL timed lock request expired", 0,
"CTLMNEMAXLEN", "The maximum length of a control mnemonic has been exceeded", 0,
"CTLMNEXPECTED", "Control mnemonic is expected in this context", 0,
@@ -588,14 +588,14 @@ LITDEF err_msg merrors[] = {
"GTMSECSHR", "!UL : Error during gtmsecshr operation", 1,
"GTMSECSHRSRVFID", "!AD: !UL - Attempt to service request failed.!/ client id: !UL, mesg type: !UL, mesg data: !UL", 6,
"GTMSECSHRSRVFIL", "!AD: !UL - Attempt to service request failed.!/ client id: !UL, mesg type: !UL!/file: !AD", 7,
- "SOCKACTNA", "Action not appropriate for current socket", 0,
+ "FREEBLKSLOW", "Only !UL free blocks left out of !UL total blocks for !AD", 4,
"PROTNOTSUP", "Protocol !AD not supported", 2,
"DELIMSIZNA", "Delimiter size is not appropriate", 0,
"INVCTLMNE", "Invalid control mnemonics", 0,
"SOCKLISTEN", "Error listening on a socket", 0,
"LQLENGTHNA", "Listening queue length !UL not appropriate. Must be between 1 and 5.", 1,
"ADDRTOOLONG", "Socket address !AD of length !UL is longer than the maximum permissible length !UL", 4,
- "UNUSEDMSG760", "LSNCONNOTCMP Last used in V5.4-002A", 0,
+ "GTMSECSHRGETSEMFAIL", "error getting semaphore errno = !UL", 1,
"CPBEYALLOC", "Attempt to copy beyond the allocated buffer", 0,
"DBRDONLY", "Database file !AD read only", 2,
"DUPTN", "Duplicate transaction found [TN = 0x!16 at XQ] at offset 0x!XL in journal file !AD", 4,
@@ -616,7 +616,7 @@ LITDEF err_msg merrors[] = {
"NOFORKCORE", "Unable to fork off process to create core. Core creation postponed.", 0,
"JNLREAD", "Error reading from journal file !AD at offset [0x!XL]", 3,
"JNLMINALIGN", "Journal Record Alignment !UL is less than the minimum value of !UL", 2,
- "JNLDSKALIGN", "Journal Record Alignment !UL is not a multiple of 512", 1,
+ "UNUSEDMSG781", "JNLDSKALIGN : Last used in V4.3-000", 0,
"JNLPOOLSETUP", "Journal Pool setup error", 0,
"JNLSTATEOFF", "ROLLBACK or RECOVER BACKWARD cannot proceed as database file !AD does not have journaling ENABLED and ON", 2,
"RECVPOOLSETUP", "Receive Pool setup error", 0,
@@ -679,7 +679,7 @@ LITDEF err_msg merrors[] = {
"BUFFLUFAILED", "Error flushing buffers from !AD for database file !AD", 4,
"MUQUALINCOMP", "Incompatible qualifiers - FILE and REGION", 0,
"DISTPATHMAX", "$gtm_dist path is greater than maximum (!UL)", 1,
- "MAXTRACEHEIGHT", "The maximum trace tree height (!UL) has been exceeded. The trace information will be incomplete.", 1,
+ "UNUSEDMSG844", "MAXTRACEHEIGHT last used in V5.4-002", 0,
"IMAGENAME", "The executing module name should be !AD instead of !AD", 4,
"GTMSECSHRPERM", "The gtmsecshr module in $gtm_dist does not have the correct permission and uid", 0,
"GTMDISTUNDEF", "Environment variable $gtm_dist is not defined", 0,
@@ -785,7 +785,7 @@ LITDEF err_msg merrors[] = {
"DBMBPFRINT", "!AD Master bit map shows this map has space, agreeing with MUPIP INTEG", 2,
"DBMAXKEYEXC", "!AD Maximum key size for database exceeds design maximum", 2,
"DBMXRSEXCMIN", "!AD Maximum record size for database is less than the design minimum", 2,
- "DBMAXRSEXBL", "!AD Maximum record size for database exceeds what the block size can support", 2,
+ "UNUSEDMSG950", "DBMAXRSEXBL : Last used in V5.5-000", 0,
"DBREADBM", "!AD Read error on bitmap", 2,
"DBCOMPTOOLRG", "!AD Record has too large compression count", 2,
"DBVERPERFWARN2", "Peformance warning: Database !AD is not fully upgraded. Run MUPIP REORG UPGRADE for best overall performance", 2,
@@ -807,7 +807,7 @@ LITDEF err_msg merrors[] = {
"SEMWT2LONG", "Process !UL waited !UL second(s) for the !AD lock for region !AD, lock held by pid !UL", 7,
"REPLINSTOPEN", "Error opening replication instance file !AD", 2,
"REPLINSTCLOSE", "Error closing replication instance file !AD", 2,
- "JNLNOTFOUND", "File !AD does not exist -- possibly moved or deleted", 2,
+ "UNUSEDMSG972", "JNLNOTFOUND : Last used in V4.4-000", 0,
"DBCRERR8", "Database file !AD, cr location 0x!XJ blk = 0x!XL error: !AD was 0x!16 at XQ, expecting 0x!16 at XQ -- called from module !AD at line !UL", 11,
"NUMPROCESSORS", "Could not determine number of processors", 0,
"DBADDRANGE8", "Database file !AD, element location 0x!XJ: blk = 0x!XL: control 0x!16 at XQ was outside !AD range 0x!16 at XQ to 0x!16 at XQ", 9,
@@ -824,16 +824,16 @@ LITDEF err_msg merrors[] = {
"RENAMEFAIL", "Rename of file !AD to !AD failed", 4,
"FILERENAME", "File !AD is renamed to !AD", 4,
"JNLBUFINFO", "Pid 0x!XL!/ dsk 0x!XL free 0x!XL bytcnt 0x!XL io_in_prog 0x!XL fsync_in_prog 0x!XL!/ dskaddr 0x!XL freeaddr 0x!XL qiocnt 0x!XL now_writer 0x!XL fsync_pid 0x!XL!/filesize 0x!XL cycle 0x!XL errcnt 0x!XL wrtsize 0x!XL fsync_dskaddr 0x!XL", 16,
- "JNLQIOLOCKED", "Error obtaining io_in_prog lock on jnl-file !AD", 2,
- "JNLEOFPREZERO", "Error while zeroing jnl-file !AD", 2,
+ "UNUSEDMSG989", "JNLQIOLOCKED : Last used in V4.4-000", 0,
+ "UNUSEDMSG990", "JNLEOFPREZERO : Last used in V4.4-000", 0,
"TPNOTACID", "!AD at !AD in a final TP retry violates ACID properties of a TRANSACTION; indefinite RESTARTs may occur !AD !AD", 8,
"JNLSETDATA2LONG", "SET journal record has data of length !UL. Target system cannot handle data more than !UL bytes.", 2,
"JNLNEWREC", "Target system cannot recognize journal record of type !UL, last recognized type is !UL", 2,
"REPLFTOKSEM", "Error with replication semaphores for instance file !AD", 2,
- "GETCWD", "Error getting current working directory for file !AD", 2,
+ "UNUSEDMSG995", "GETCWD : Last used before V4.0-001E", 0,
"EXTRIOERR", "Error writing extract file !AD", 2,
"EXTRCLOSEERR", "Error closing extract file !AD", 2,
- "TRUNCATE", "Error while truncating jnl-file !AD to length !UL", 3,
+ "UNUSEDMSG998", "TRUNCATE : Last used in V4.3-001F", 0,
"REPLEXITERR", "Replication process encountered an error while exiting", 0,
"MUDESTROYSUC", "Global section (!AD) corresponding to file !AD successfully destroyed", 4,
"DBRNDWN", "Error during global database rundown for region !AD.!/Notify those responsible for proper database operation.", 2,
@@ -846,7 +846,7 @@ LITDEF err_msg merrors[] = {
"TCSETATTR", "Error while setting terminal attributes on file descriptor !UL", 1,
"IOWRITERR", "IO Write by pid 0x!XL to blk 0x!XL of database file !AD failed. Pid 0x!XL retrying the IO.", 5,
"REPLINSTWRITE", "Error writing [0x!XL] bytes at offset [0x!16 at XQ] in replication instance file !AD", 4,
- "DBBADFREEBLKCTR", "Database !AD free blocks counter in file header: 0x!XL is incorrect, should be 0x!XL. Auto-corrected.", 4,
+ "DBBADFREEBLKCTR", "Database !AD free blocks counter in file header: 0x!XL appears incorrect, should be 0x!XL. Auto-corrected.", 4,
"REQ2RESUME", "Request to resume suspended processing received from process !UL owned by userid !UL", 2,
"TIMERHANDLER", "Incorrect SIGALRM handler (0x!XJ) found by !AD", 3,
"FREEMEMORY", "Error occurred freeing memory from 0x!XJ", 1,
@@ -914,7 +914,7 @@ LITDEF err_msg merrors[] = {
"SYSTEMVALUE", "Invalid value for $SYSTEM (!AD)", 2,
"SIZENOTVALID4", "Size (in bytes) must be either 1, 2, or 4", 0,
"STRNOTVALID", "Error: cannot convert !AD value to valid value", 2,
- "RECNOCREJNL", "Recover could not create new journal file !AD", 2,
+ "UNUSEDMSG1079", "RECNOCREJNL : Last used in V4.3-001F", 0,
"ERRWETRAP", "Error while processing $ETRAP", 0,
"TRACINGON", "Tracing already turned on", 0,
"CITABENV", "Environment variable for call-in table !AD not set", 2,
@@ -942,9 +942,9 @@ LITDEF err_msg merrors[] = {
"ZDIROUTOFSYNC", "$ZDIRECTORY !AD is not the same as its cached value !AD", 4,
"GBLNOEXIST", "Global !AD no longer exists", 2,
"MAXBTLEVEL", "Global !AD reached maximum level", 2,
- "JNLSTRESTFL", "Failed to restore journaling state for database !AD", 2,
+ "UNUSEDMSG1107", "JNLSTRESTFL : found no evidence it ever was used in a production release", 0,
"JNLALIGNSZCHG", "Journal ALIGNSIZE is rounded up to !UL blocks (closest next higher power of two)", 1,
- "MAXTRACELEVEL", "The maximum traceable level of !UL has been exceeded. The frame information will not be maintained.", 1,
+ "UNUSEDMSG1109", "MAXTRACELEVEL : last used in V5.4-002B", 0,
"GVFAILCORE", "A core file is being created for later analysis if necessary", 0,
"DBCDBNOCERTIFY", "Database !AD HAS NOT been certified due to the preceding errors - rerun DBCERTIFY SCAN", 2,
"DBFRZRESETSUC", "Freeze released successfully on database file !AD", 2,
@@ -1189,7 +1189,7 @@ LITDEF err_msg merrors[] = {
"TRIGTLVLCHNG", "Detected a net transaction level ($TLEVEL) change during trigger !AD. Transaction level must be the same at exit as when the trigger started", 2,
"TRIGNAMEUNIQ", "Unable to make trigger name !AD unique beyond !UL versions already loaded", 3,
"ZTRIGINVACT", "Missing or invalid parameter in position !UL given to $ZTRIGGER()", 1,
- "UNUSEDMSG1354", "ZTRIGNOTP : Last used in V5.4-001", 0,
+ "INDRCOMPFAIL", "Compilation of indirection failed", 0,
"QUITALSINV", "QUIT * return when the extrinsic was not invoked with SET *", 0,
"PROCTERM", "!AD process termination due to !AD (return code !UL) from !AD", 7,
"SRCLNNTDSP", "Source lines exceeding !UL character width are not displayed", 1,
@@ -1202,10 +1202,10 @@ 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,
- "TPLOCKRESTMAX", "Transaction restarts due to unavailability of locks not allowed in a final TP retry more than !UL times", 1,
+ "UNUSEDMSG1367", "TPLOCKRESTMAX : Last used in V5.5-000", 0,
"GBLEXPECTED", "Global variable reference expected in this context", 0,
"GVZTRIGFAIL", "ZTRIGGER of a global variable failed. Failure code: !AD.", 2,
- "UNUSEDMSG1370", "ONLYLDTRIG: Last used in V5.4-001", 0,
+ "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,
@@ -1217,7 +1217,7 @@ LITDEF err_msg merrors[] = {
"REPLXENDIANFAIL", "!AD side encountered error while doing endian conversion at journal sequence number 0x!16 at XQ", 3,
"ZGOTOINVLVL2", "ZGOTO 0:entryref is not valid on VMS (UNLINK is a UNIX only feature)", 0,
"GTMSECSHRCHDIRF", "gtmsecshr unable to chdir to its temporary directory (!AD)", 2,
- "UNUSEDMSG1382", "FORCTRLINDX: Only used in V5.4-002", 0,
+ "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,
@@ -1249,7 +1249,7 @@ LITDEF err_msg merrors[] = {
"NOSUPPLSUPPL", "Instance !AD is configured to perform local updates so it cannot receive from Supplementary Instance !AD", 4,
"REPL2OLD", "Instance !AD uses a GT.M version that does not support connection with the current version on instance !AD", 4,
"EXTRFILEXISTS", "Error opening output file: !AD -- File exists", 2,
- "UNUSEDMSG1414", "!AD : An error encountered with the shared object : !AZ", 3,
+ "MUUSERECOV", "Abnormal shutdown of journaled database !AD detected", 2,
"SECNOTSUPPLEMENTARY", "!AD is a Supplementary Instance and so cannot act as a source to non-Supplementary Instance !AD ", 4,
"SUPRCVRNEEDSSUPSRC", "Instance !AD is not configured to perform local updates so it cannot act as a receiver for non-Supplementary Instance !AD", 4,
"UNUSEDMSG1417", "SYNCTOSAMETYPE: Never used before so slot free for reuse", 0,
@@ -1272,7 +1272,7 @@ LITDEF err_msg merrors[] = {
"ORLBKNOV4BLK", "Region !AD (!AD) has V4 format blocks. Database upgrade required. ONLINE ROLLBACK cannot continue", 4,
"DBROLLEDBACK", "Concurrent ONLINE ROLLBACK detected on one or more regions. The current operation is no longer valid", 0,
"DSEWCREINIT", "Database cache reinitialized by DSE for region !AD", 2,
- "UNUSEDMSG1437", "A total of !UL process(es) skipped database rundown due to a concurrent ONLINE ROLLBACK", 1,
+ "MURNDWNOVRD", "OVERRIDE qualifier used with MUPIP RUNDOWN on database file !AD", 2,
"REPLONLNRLBK", "ONLINE ROLLBACK detected. Starting afresh", 0,
"SRVLCKWT2LNG", "PID !UL is holding the source server lock. Waited for !UL minute(s). Now exiting", 2,
"IGNBMPMRKFREE", "Ignoring bitmap free-up operation for region !AD (!AD) due to concurrent ONLINE ROLLBACK", 4,
@@ -1342,6 +1342,27 @@ LITDEF err_msg merrors[] = {
"TPRESTNESTERR", "TP restart signaled while handing error - treated as nested error - Use TROLLBACK in error handler to avoid this", 0,
"JNLFILRDOPN", "Error opening journal file !AD for read for database file !AD", 4,
"SEQNUMSEARCHTIMEOUT", "Timed out trying to find sequence number !@ZQ [0x!16 at XQ] in Journal File(s). See above messages for details. Source server exiting", 2,
+ "FTOKKEY", "FTOK key 0x!XL", 1,
+ "SEMID", "Semaphore id !UL", 1,
+ "JNLQIOSALVAGE", "Journal IO lock salvaged", 0,
+ "FAKENOSPCLEARED", "DEBUG: All fake ENOSPC flags were cleared !UL heartbeats ago", 1,
+ "MMFILETOOLARGE", "Size of !AD region (!AD) is larger than maximum size supported for memory mapped I/O on this platform", 4,
+ "BADZPEEKARG", "Missing, invalid or surplus !AD parameter for $ZPEEK()", 2,
+ "BADZPEEKRANGE", "Access exception raised in memory range given to $ZPEEK()", 0,
+ "BADZPEEKFMT", "$ZPEEK() value length inappropriate for selected format", 0,
+ "DBMBMINCFREFIXED", "Master bitmap incorrectly marks local bitmap 0x!XL as free. Auto-corrected", 1,
+ "NULLENTRYREF", "JOB command did not specify entryref", 0,
+ "ZPEEKNORPLINFO", "$ZPEEK() unable to access requested replication structure", 0,
+ "MMREGNOACCESS", "Region !AD (!AD) is no longer accessible. See prior error messages in the operator and application error logs", 4,
+ "MALLOCMAXUNIX", "Exceeded maximum allocation defined by $gtm_max_storalloc", 0,
+ "MALLOCMAXVMS", "Exceeded maximum allocation defined by GTM_MAX_STORALLOC", 0,
+ "HOSTCONFLICT", "Host !AD could not open database file !AD because it is marked as already open on node !AD", 6,
+ "GETADDRINFO", "Error in getting address info", 0,
+ "GETNAMEINFO", "Error in getting name info", 0,
+ "SOCKBIND", "Error in binding TCP socket", 0,
+ "INSTFRZDEFER", "Instance Freeze initiated by !AD error on region !AD deferred due to critical resource conflict", 4,
+ "REGOPENRETRY", "Attempt to open region !AD (!AD) using startup shortcut failed due to conflicting database shutdown. Retrying...", 4,
+ "REGOPENFAIL", "Failed to open region !AD (!AD) due to conflicting database shutdown activity", 4,
};
LITDEF int ERR_ACK = 150372361;
@@ -1526,7 +1547,7 @@ LITDEF int ERR_TERMASTQUOTA = 150373786;
LITDEF int ERR_TEXTARG = 150373794;
LITDEF int ERR_TMPSTOREMAX = 150373802;
LITDEF int ERR_VIEWCMD = 150373810;
-LITDEF int ERR_TXTNEGLIN = 150373818;
+LITDEF int ERR_JNI = 150373818;
LITDEF int ERR_TXTSRCFMT = 150373826;
LITDEF int ERR_UIDMSG = 150373834;
LITDEF int ERR_UIDSND = 150373842;
@@ -1535,9 +1556,9 @@ LITDEF int ERR_UNIMPLOP = 150373858;
LITDEF int ERR_VAREXPECTED = 150373866;
LITDEF int ERR_VARRECBLKSZ = 150373874;
LITDEF int ERR_MAXARGCNT = 150373882;
-LITDEF int ERR_WCFAIL = 150373890;
+LITDEF int ERR_GTMSECSHRSEMGET = 150373890;
LITDEF int ERR_VIEWARGCNT = 150373898;
-LITDEF int ERR_XKILLCNTEXC = 150373906;
+LITDEF int ERR_GTMSECSHRDMNSTARTED = 150373907;
LITDEF int ERR_ZATTACHERR = 150373914;
LITDEF int ERR_ZDATEFMT = 150373922;
LITDEF int ERR_ZEDFILSPEC = 150373930;
@@ -1592,7 +1613,7 @@ LITDEF int ERR_GVRUNDOWN = 150374314;
LITDEF int ERR_LKRUNDOWN = 150374322;
LITDEF int ERR_IORUNDOWN = 150374330;
LITDEF int ERR_FILENOTFND = 150374338;
-LITDEF int ERR_MUFILRNDWNFL = 150374347;
+LITDEF int ERR_MUFILRNDWNFL = 150374346;
LITDEF int ERR_JNLTMQUAL1 = 150374354;
LITDEF int ERR_FORCEDHALT = 150374364;
LITDEF int ERR_LOADEOF = 150374370;
@@ -1604,14 +1625,14 @@ LITDEF int ERR_GVZPREVFAIL = 150374410;
LITDEF int ERR_MULTFORMPARM = 150374418;
LITDEF int ERR_QUITARGUSE = 150374426;
LITDEF int ERR_NAMEEXPECTED = 150374434;
-LITDEF int ERR_UNUSEDMSG438 = 150374442;
+LITDEF int ERR_FALLINTOFLST = 150374442;
LITDEF int ERR_NOTEXTRINSIC = 150374450;
-LITDEF int ERR_UNUSEDMSG440 = 150374458;
+LITDEF int ERR_GTMSECSHRREMSEMFAIL = 150374458;
LITDEF int ERR_FMLLSTMISSING = 150374466;
LITDEF int ERR_ACTLSTTOOLONG = 150374474;
LITDEF int ERR_ACTOFFSET = 150374482;
LITDEF int ERR_MAXACTARG = 150374490;
-LITDEF int ERR_GTMDUMPFAIL = 150374498;
+LITDEF int ERR_GTMSECSHRREMSEM = 150374498;
LITDEF int ERR_JNLTMQUAL2 = 150374506;
LITDEF int ERR_GDINVALID = 150374514;
LITDEF int ERR_ASSERT = 150374524;
@@ -1755,13 +1776,13 @@ LITDEF int ERR_LDGOQFMT = 150375618;
LITDEF int ERR_BEGINST = 150375627;
LITDEF int ERR_INVMVXSZ = 150375636;
LITDEF int ERR_JNLWRTNOWWRTR = 150375642;
-LITDEF int ERR_MUPGDERR = 150375650;
+LITDEF int ERR_GTMSECSHRSHMCONCPROC = 150375650;
LITDEF int ERR_JNLINVALLOC = 150375656;
LITDEF int ERR_JNLINVEXT = 150375664;
LITDEF int ERR_MUPCLIERR = 150375674;
LITDEF int ERR_JNLTMQUAL4 = 150375682;
-LITDEF int ERR_UNUSEDMSG594 = 150375690;
-LITDEF int ERR_UNUSEDMSG595 = 150375698;
+LITDEF int ERR_GTMSECSHRREMSHM = 150375691;
+LITDEF int ERR_GTMSECSHRREMFILE = 150375699;
LITDEF int ERR_MUNODBNAME = 150375706;
LITDEF int ERR_FILECREATE = 150375715;
LITDEF int ERR_FILENOTCREATE = 150375723;
@@ -1783,7 +1804,7 @@ LITDEF int ERR_WCERRNOTCHG = 150375842;
LITDEF int ERR_WCWRNNOTCHG = 150375848;
LITDEF int ERR_ZCWRONGDESC = 150375858;
LITDEF int ERR_MUTNWARN = 150375864;
-LITDEF int ERR_JNLNAMLEN = 150375874;
+LITDEF int ERR_GTMSECSHRUPDDBHDR = 150375875;
LITDEF int ERR_LCKSTIMOUT = 150375880;
LITDEF int ERR_CTLMNEMAXLEN = 150375890;
LITDEF int ERR_CTLMNEXPECTED = 150375898;
@@ -1919,14 +1940,14 @@ LITDEF int ERR_MUTEXFRCDTERM = 150376928;
LITDEF int ERR_GTMSECSHR = 150376938;
LITDEF int ERR_GTMSECSHRSRVFID = 150376944;
LITDEF int ERR_GTMSECSHRSRVFIL = 150376952;
-LITDEF int ERR_SOCKACTNA = 150376962;
+LITDEF int ERR_FREEBLKSLOW = 150376960;
LITDEF int ERR_PROTNOTSUP = 150376970;
LITDEF int ERR_DELIMSIZNA = 150376978;
LITDEF int ERR_INVCTLMNE = 150376986;
LITDEF int ERR_SOCKLISTEN = 150376994;
LITDEF int ERR_LQLENGTHNA = 150377002;
LITDEF int ERR_ADDRTOOLONG = 150377010;
-LITDEF int ERR_UNUSEDMSG760 = 150377018;
+LITDEF int ERR_GTMSECSHRGETSEMFAIL = 150377018;
LITDEF int ERR_CPBEYALLOC = 150377026;
LITDEF int ERR_DBRDONLY = 150377034;
LITDEF int ERR_DUPTN = 150377040;
@@ -1947,7 +1968,7 @@ LITDEF int ERR_BCKUPBUFLUSH = 150377154;
LITDEF int ERR_NOFORKCORE = 150377160;
LITDEF int ERR_JNLREAD = 150377170;
LITDEF int ERR_JNLMINALIGN = 150377176;
-LITDEF int ERR_JNLDSKALIGN = 150377184;
+LITDEF int ERR_UNUSEDMSG781 = 150377186;
LITDEF int ERR_JNLPOOLSETUP = 150377194;
LITDEF int ERR_JNLSTATEOFF = 150377202;
LITDEF int ERR_RECVPOOLSETUP = 150377210;
@@ -2010,7 +2031,7 @@ LITDEF int ERR_RECSIZENOTEVEN = 150377658;
LITDEF int ERR_BUFFLUFAILED = 150377666;
LITDEF int ERR_MUQUALINCOMP = 150377674;
LITDEF int ERR_DISTPATHMAX = 150377682;
-LITDEF int ERR_MAXTRACEHEIGHT = 150377691;
+LITDEF int ERR_UNUSEDMSG844 = 150377690;
LITDEF int ERR_IMAGENAME = 150377698;
LITDEF int ERR_GTMSECSHRPERM = 150377706;
LITDEF int ERR_GTMDISTUNDEF = 150377714;
@@ -2116,7 +2137,7 @@ LITDEF int ERR_DBMBPFRDLBM = 150378504;
LITDEF int ERR_DBMBPFRINT = 150378512;
LITDEF int ERR_DBMAXKEYEXC = 150378522;
LITDEF int ERR_DBMXRSEXCMIN = 150378530;
-LITDEF int ERR_DBMAXRSEXBL = 150378538;
+LITDEF int ERR_UNUSEDMSG950 = 150378538;
LITDEF int ERR_DBREADBM = 150378546;
LITDEF int ERR_DBCOMPTOOLRG = 150378554;
LITDEF int ERR_DBVERPERFWARN2 = 150378560;
@@ -2138,7 +2159,7 @@ LITDEF int ERR_MUTEXRSRCCLNUP = 150378683;
LITDEF int ERR_SEMWT2LONG = 150378690;
LITDEF int ERR_REPLINSTOPEN = 150378698;
LITDEF int ERR_REPLINSTCLOSE = 150378706;
-LITDEF int ERR_JNLNOTFOUND = 150378715;
+LITDEF int ERR_UNUSEDMSG972 = 150378714;
LITDEF int ERR_DBCRERR8 = 150378723;
LITDEF int ERR_NUMPROCESSORS = 150378728;
LITDEF int ERR_DBADDRANGE8 = 150378739;
@@ -2155,16 +2176,16 @@ LITDEF int ERR_REPLJNLCLOSED = 150378818;
LITDEF int ERR_RENAMEFAIL = 150378824;
LITDEF int ERR_FILERENAME = 150378835;
LITDEF int ERR_JNLBUFINFO = 150378843;
-LITDEF int ERR_JNLQIOLOCKED = 150378850;
-LITDEF int ERR_JNLEOFPREZERO = 150378858;
+LITDEF int ERR_UNUSEDMSG989 = 150378850;
+LITDEF int ERR_UNUSEDMSG990 = 150378858;
LITDEF int ERR_TPNOTACID = 150378867;
LITDEF int ERR_JNLSETDATA2LONG = 150378874;
LITDEF int ERR_JNLNEWREC = 150378882;
LITDEF int ERR_REPLFTOKSEM = 150378890;
-LITDEF int ERR_GETCWD = 150378898;
+LITDEF int ERR_UNUSEDMSG995 = 150378898;
LITDEF int ERR_EXTRIOERR = 150378906;
LITDEF int ERR_EXTRCLOSEERR = 150378914;
-LITDEF int ERR_TRUNCATE = 150378922;
+LITDEF int ERR_UNUSEDMSG998 = 150378922;
LITDEF int ERR_REPLEXITERR = 150378930;
LITDEF int ERR_MUDESTROYSUC = 150378939;
LITDEF int ERR_DBRNDWN = 150378946;
@@ -2177,7 +2198,7 @@ LITDEF int ERR_TCGETATTR = 150378994;
LITDEF int ERR_TCSETATTR = 150379002;
LITDEF int ERR_IOWRITERR = 150379010;
LITDEF int ERR_REPLINSTWRITE = 150379018;
-LITDEF int ERR_DBBADFREEBLKCTR = 150379027;
+LITDEF int ERR_DBBADFREEBLKCTR = 150379024;
LITDEF int ERR_REQ2RESUME = 150379035;
LITDEF int ERR_TIMERHANDLER = 150379040;
LITDEF int ERR_FREEMEMORY = 150379050;
@@ -2185,11 +2206,11 @@ LITDEF int ERR_MUREPLSECDEL = 150379059;
LITDEF int ERR_MUREPLSECNOTDEL = 150379067;
LITDEF int ERR_MUJPOOLRNDWNSUC = 150379075;
LITDEF int ERR_MURPOOLRNDWNSUC = 150379083;
-LITDEF int ERR_MUJPOOLRNDWNFL = 150379091;
-LITDEF int ERR_MURPOOLRNDWNFL = 150379099;
+LITDEF int ERR_MUJPOOLRNDWNFL = 150379090;
+LITDEF int ERR_MURPOOLRNDWNFL = 150379098;
LITDEF int ERR_MUREPLPOOL = 150379107;
LITDEF int ERR_REPLACCSEM = 150379114;
-LITDEF int ERR_JNLFLUSHNOPROG = 150379122;
+LITDEF int ERR_JNLFLUSHNOPROG = 150379120;
LITDEF int ERR_REPLINSTCREATE = 150379130;
LITDEF int ERR_SUSPENDING = 150379139;
LITDEF int ERR_SOCKBFNOTEMPTY = 150379146;
@@ -2245,7 +2266,7 @@ LITDEF int ERR_NOSUBSCRIPT = 150379538;
LITDEF int ERR_SYSTEMVALUE = 150379546;
LITDEF int ERR_SIZENOTVALID4 = 150379554;
LITDEF int ERR_STRNOTVALID = 150379562;
-LITDEF int ERR_RECNOCREJNL = 150379571;
+LITDEF int ERR_UNUSEDMSG1079 = 150379570;
LITDEF int ERR_ERRWETRAP = 150379578;
LITDEF int ERR_TRACINGON = 150379587;
LITDEF int ERR_CITABENV = 150379594;
@@ -2273,9 +2294,9 @@ LITDEF int ERR_INVZDIRFORM = 150379762;
LITDEF int ERR_ZDIROUTOFSYNC = 150379768;
LITDEF int ERR_GBLNOEXIST = 150379779;
LITDEF int ERR_MAXBTLEVEL = 150379786;
-LITDEF int ERR_JNLSTRESTFL = 150379794;
+LITDEF int ERR_UNUSEDMSG1107 = 150379794;
LITDEF int ERR_JNLALIGNSZCHG = 150379803;
-LITDEF int ERR_MAXTRACELEVEL = 150379811;
+LITDEF int ERR_UNUSEDMSG1109 = 150379810;
LITDEF int ERR_GVFAILCORE = 150379818;
LITDEF int ERR_DBCDBNOCERTIFY = 150379826;
LITDEF int ERR_DBFRZRESETSUC = 150379835;
@@ -2520,7 +2541,7 @@ LITDEF int ERR_TRIGTCOMMIT = 150381738;
LITDEF int ERR_TRIGTLVLCHNG = 150381746;
LITDEF int ERR_TRIGNAMEUNIQ = 150381754;
LITDEF int ERR_ZTRIGINVACT = 150381762;
-LITDEF int ERR_UNUSEDMSG1354 = 150381770;
+LITDEF int ERR_INDRCOMPFAIL = 150381770;
LITDEF int ERR_QUITALSINV = 150381778;
LITDEF int ERR_PROCTERM = 150381784;
LITDEF int ERR_SRCLNNTDSP = 150381795;
@@ -2533,10 +2554,10 @@ LITDEF int ERR_TCOMMITDISALLOW = 150381842;
LITDEF int ERR_SSATTACHSHM = 150381850;
LITDEF int ERR_TRIGDEFNOSYNC = 150381856;
LITDEF int ERR_TRESTMAX = 150381866;
-LITDEF int ERR_TPLOCKRESTMAX = 150381874;
+LITDEF int ERR_UNUSEDMSG1367 = 150381874;
LITDEF int ERR_GBLEXPECTED = 150381882;
LITDEF int ERR_GVZTRIGFAIL = 150381890;
-LITDEF int ERR_UNUSEDMSG1370 = 150381898;
+LITDEF int ERR_MUUSERLBK = 150381898;
LITDEF int ERR_SETINSETTRIGONLY = 150381906;
LITDEF int ERR_DZTRIGINTRIG = 150381914;
LITDEF int ERR_SECNODZTRIGINTP = 150381922;
@@ -2548,7 +2569,7 @@ LITDEF int ERR_REPLNOXENDIAN = 150381962;
LITDEF int ERR_REPLXENDIANFAIL = 150381970;
LITDEF int ERR_ZGOTOINVLVL2 = 150381978;
LITDEF int ERR_GTMSECSHRCHDIRF = 150381986;
-LITDEF int ERR_UNUSEDMSG1382 = 150381994;
+LITDEF int ERR_JNLORDBFLU = 150381994;
LITDEF int ERR_ZCCLNUPRTNMISNG = 150382002;
LITDEF int ERR_ZCINVALIDKEYWORD = 150382010;
LITDEF int ERR_REPLNOMULTILINETRG = 150382018;
@@ -2580,7 +2601,7 @@ LITDEF int ERR_NORESYNCUPDATERONLY = 150382218;
LITDEF int ERR_NOSUPPLSUPPL = 150382226;
LITDEF int ERR_REPL2OLD = 150382234;
LITDEF int ERR_EXTRFILEXISTS = 150382242;
-LITDEF int ERR_UNUSEDMSG1414 = 150382250;
+LITDEF int ERR_MUUSERECOV = 150382250;
LITDEF int ERR_SECNOTSUPPLEMENTARY = 150382258;
LITDEF int ERR_SUPRCVRNEEDSSUPSRC = 150382266;
LITDEF int ERR_UNUSEDMSG1417 = 150382275;
@@ -2603,7 +2624,7 @@ LITDEF int ERR_ORLBKFRZOVER = 150382403;
LITDEF int ERR_ORLBKNOV4BLK = 150382410;
LITDEF int ERR_DBROLLEDBACK = 150382418;
LITDEF int ERR_DSEWCREINIT = 150382427;
-LITDEF int ERR_UNUSEDMSG1437 = 150382435;
+LITDEF int ERR_MURNDWNOVRD = 150382435;
LITDEF int ERR_REPLONLNRLBK = 150382442;
LITDEF int ERR_SRVLCKWT2LNG = 150382450;
LITDEF int ERR_IGNBMPMRKFREE = 150382459;
@@ -2654,7 +2675,7 @@ LITDEF int ERR_JNLBUFFDBUPD = 150382808;
LITDEF int ERR_LOCKINCR2HIGH = 150382818;
LITDEF int ERR_LOCKIS = 150382827;
LITDEF int ERR_LDSPANGLOINCMP = 150382834;
-LITDEF int ERR_MUFILRNDWNFL2 = 150382843;
+LITDEF int ERR_MUFILRNDWNFL2 = 150382842;
LITDEF int ERR_MUINSTFROZEN = 150382851;
LITDEF int ERR_MUINSTUNFROZEN = 150382859;
LITDEF int ERR_GTMEISDIR = 150382866;
@@ -2673,9 +2694,30 @@ LITDEF int ERR_NOTALLDBRNDWN = 150382962;
LITDEF int ERR_TPRESTNESTERR = 150382970;
LITDEF int ERR_JNLFILRDOPN = 150382978;
LITDEF int ERR_SEQNUMSEARCHTIMEOUT = 150382986;
+LITDEF int ERR_FTOKKEY = 150382995;
+LITDEF int ERR_SEMID = 150383003;
+LITDEF int ERR_JNLQIOSALVAGE = 150383011;
+LITDEF int ERR_FAKENOSPCLEARED = 150383019;
+LITDEF int ERR_MMFILETOOLARGE = 150383026;
+LITDEF int ERR_BADZPEEKARG = 150383034;
+LITDEF int ERR_BADZPEEKRANGE = 150383042;
+LITDEF int ERR_BADZPEEKFMT = 150383050;
+LITDEF int ERR_DBMBMINCFREFIXED = 150383056;
+LITDEF int ERR_NULLENTRYREF = 150383066;
+LITDEF int ERR_ZPEEKNORPLINFO = 150383074;
+LITDEF int ERR_MMREGNOACCESS = 150383082;
+LITDEF int ERR_MALLOCMAXUNIX = 150383090;
+LITDEF int ERR_MALLOCMAXVMS = 150383098;
+LITDEF int ERR_HOSTCONFLICT = 150383106;
+LITDEF int ERR_GETADDRINFO = 150383114;
+LITDEF int ERR_GETNAMEINFO = 150383122;
+LITDEF int ERR_SOCKBIND = 150383130;
+LITDEF int ERR_INSTFRZDEFER = 150383139;
+LITDEF int ERR_REGOPENRETRY = 150383147;
+LITDEF int ERR_REGOPENFAIL = 150383154;
GBLDEF err_ctl merrors_ctl = {
246,
"GTM",
&merrors[0],
- 1329};
+ 1350};
diff --git a/sr_x86_64/op_exfun.s b/sr_x86_64/op_exfun.s
index ce9dece..31950e1 100644
--- a/sr_x86_64/op_exfun.s
+++ b/sr_x86_64/op_exfun.s
@@ -1,6 +1,6 @@
#################################################################
# #
-# Copyright 2007, 2012 Fidelity Information Services, Inc #
+# Copyright 2007, 2013 Fidelity Information Services, Inc #
# #
# This source code contains the intellectual property #
# of its copyright holder(s), and is made available #
@@ -77,7 +77,7 @@ error: movl ERR_GTMCHECK(REG_IP),REG32_ARG1
jmp retlab
long: movq REG64_ACCUM,msf_mpc_off(REG64_ARG2)
- addl REG32_ARG1, msf_mpc_off(REG64_ARG2)
+ addq REG64_ARG1,msf_mpc_off(REG64_ARG2)
cont: call exfun_frame
movl act_cnt(REG_FRAME_POINTER),REG32_ACCUM
diff --git a/sr_x86_64/op_mprofexfun.s b/sr_x86_64/op_mprofexfun.s
index ea257fa..6db6ab1 100644
--- a/sr_x86_64/op_mprofexfun.s
+++ b/sr_x86_64/op_mprofexfun.s
@@ -1,6 +1,6 @@
#################################################################
# #
-# Copyright 2007, 2012 Fidelity Information Services, Inc #
+# Copyright 2007, 2013 Fidelity Information Services, Inc #
# #
# This source code contains the intellectual property #
# of its copyright holder(s), and is made available #
@@ -75,7 +75,7 @@ error: movl ERR_GTMCHECK(REG_IP),REG32_ARG1
jmp retlab
long: movq REG64_ACCUM,msf_mpc_off(REG64_ARG2)
- addl REG32_ARG1, msf_mpc_off(REG64_ARG2)
+ addq REG64_ARG1,msf_mpc_off(REG64_ARG2)
cont: call exfun_frame_sp
movq frame_pointer(REG_IP),REG64_SCRATCH1
diff --git a/sr_x86_64/ttt.c b/sr_x86_64/ttt.c
index 6be6648..e0bfaf8 100644
--- a/sr_x86_64/ttt.c
+++ b/sr_x86_64/ttt.c
@@ -13,689 +13,696 @@
#include "vxi.h"
#include "vxt.h"
#include "xfer_enum.h"
-LITDEF short ttt[4239] = {
+LITDEF short ttt[4291] = {
-/* 0 */ 0,0,0,0,322,3547,3020,564,
-/* 8 */ 2344,3005,3035,2025,418,3497,2146,3121,
-/* 16 */ 2223,2214,3730,3767,2187,2196,2262,2208,
-/* 24 */ 2253,2232,2169,770,785,797,809,851,
-/* 32 */ 869,890,919,949,964,979,997,1156,
-/* 40 */ 1069,1102,1135,1213,1264,1594,1627,1642,
-/* 48 */ 1672,1738,1768,1792,1855,1876,1891,3562,
-/* 56 */ 3584,0,0,0,0,579,0,520,
-/* 64 */ 0,2011,0,3107,0,0,0,0,
-/* 72 */ 0,0,354,430,2322,2328,2753,2780,
-/* 80 */ 2798,2901,2839,2830,2916,3636,3720,3056,
-/* 88 */ 0,3086,3187,3150,3135,3165,3511,3363,
-/* 96 */ 3642,3654,3669,3693,3702,3687,3678,3396,
-/* 104 */ 3763,3776,3798,3835,3847,3868,3892,3958,
-/* 112 */ 0,0,2949,2304,3239,4188,658,4191,
-/* 120 */ 712,2810,3205,534,540,4194,2407,2504,
-/* 128 */ 2394,487,2430,2524,2178,2462,2534,4197,
-/* 136 */ 2289,2280,4201,1282,4202,350,346,3387,
-/* 144 */ 442,4206,4209,4212,3072,4215,4218,4221,
-/* 152 */ 4224,4227,4230,3533,0,2925,2593,2571,
-/* 160 */ 1555,2562,2340,2160,2876,2046,737,2866,
-/* 168 */ 0,0,2359,3711,3739,1486,3663,2442,
-/* 176 */ 2039,549,3859,1840,2271,1198,337,3191,
-/* 184 */ 621,690,602,668,3823,1117,3791,3049,
-/* 192 */ 2298,2940,3063,640,1009,2880,4233,2514,
-/* 200 */ 3910,3928,3943,511,2895,3183,1972,3985,
-/* 208 */ 3970,1300,3525,593,1657,1726,2477,4236,
-/* 216 */ 3596,2550,746,827,3222,3751,3620,3606,
-/* 224 */ 3613,3602,722,904,2417,1051,2381,1039,
-/* 232 */ 2241,1024,1084,2489,1456,1399,1384,1438,
-/* 240 */ 1354,1366,1411,1339,1423,1471,0,3483,
-/* 248 */ 0,928,937,3342,1867,3321,2368,2452,
-/* 256 */ 2975,2981,2993,2961,1237,1249,1171,1183,
-/* 264 */ 1225,3574,1702,1903,0,1312,1498,1576,
-/* 272 */ 3417,1609,1687,1714,1825,1804,3459,1750,
-/* 280 */ 3438,1936,1510,1525,1999,4000,1918,3249,
-/* 288 */ 3261,3273,3285,2789,2804,1543,451,1327,
-/* 296 */ 1954,649,3297,3309,3979,3991,0,0,
-/* 304 */ 0,0,3814,4012,4023,4035,4044,4058,
-/* 312 */ 4071,4081,4098,4107,4116,4128,4140,4152,
-/* 320 */ 4167,4179,VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,
-/* 328 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_add,
-/* 336 */ VXT_END,
-/* 337 */ VXT_IREPL,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_bindparm,
-/* 345 */ VXT_END,
-/* 346 */ VXI_INCL,VXT_VAL,1,VXT_END,
-/* 350 */ VXI_CLRL,VXT_VAL,0,VXT_END,
-/* 354 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_break,VXT_END,
-/* 358 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callb,VXI_BRB,VXT_JMP,
-/* 366 */ 1,VXT_END,
-/* 368 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_calll,VXI_JMP,VXT_JMP,
-/* 376 */ 1,VXT_END,
-/* 378 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callw,VXI_BRW,VXT_JMP,
-/* 386 */ 1,VXT_END,
-/* 388 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callspb,VXI_BRB,VXT_JMP,
-/* 396 */ 1,VXT_END,
-/* 398 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callspl,VXI_JMP,VXT_JMP,
-/* 406 */ 1,VXT_END,
-/* 408 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callspw,VXI_BRW,VXT_JMP,
-/* 416 */ 1,VXT_END,
-/* 418 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL,
-/* 426 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_cat,VXT_END,
-/* 430 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 438 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_close,VXT_END,
-/* 442 */ VXI_BICB2,VXT_LIT,1,VXT_REG,0x5A,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_dt_false,
-/* 450 */ VXT_END,
-/* 451 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_clralsvars,
-/* 459 */ VXT_END,
-/* 460 */ VXI_TSTL,VXT_VAL,1,VXT_END,
-/* 464 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_mval2bool,
-/* 472 */ VXT_END,
-/* 473 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_mval2mint,
-/* 481 */ VXI_MOVL,VXT_REG,0x50,VXT_VAL,0,VXT_END,
-/* 487 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
-/* 495 */ SIZEOF(char *) * (short int)xf_commarg,VXT_END,
-/* 497 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x50,VXI_MOVL,VXT_VAL,1,
-/* 505 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_mint2mval,VXT_END,
-/* 511 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_mval2num,
-/* 519 */ VXT_END,
-/* 520 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2,
-/* 528 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_contain,VXT_END,
-/* 534 */ VXI_MOVL,VXT_REG,0x6C,VXT_ADDR,0,VXT_END,
-/* 540 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_currtn,
-/* 548 */ VXT_END,
-/* 549 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,
-/* 557 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_cvtparm,VXT_END,
-/* 564 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 572 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_div,VXT_END,
-/* 579 */ VXI_MOVAB,VXT_VAL,2,VXT_REG,0x51,VXI_MOVAB,VXT_VAL,1,
-/* 587 */ VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_equ,VXT_END,
-/* 593 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_equnul,
-/* 601 */ VXT_END,
-/* 602 */ VXT_IREPAB,VXT_VAL,5,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
-/* 610 */ 3,VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_LIT,0,VXI_JSB,
-/* 618 */ VXT_XFER,SIZEOF(char *) * (short int)xf_exfun,VXT_END,
-/* 621 */ VXT_IREPAB,VXT_VAL,5,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
-/* 629 */ 3,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_JSB,
-/* 637 */ VXT_XFER,SIZEOF(char *) * (short int)xf_exfun,VXT_END,
-/* 640 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_exfunret,
-/* 648 */ VXT_END,
-/* 649 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_exfunretals,
-/* 657 */ VXT_END,
-/* 658 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
-/* 666 */ SIZEOF(char *) * (short int)xf_extcall,VXT_END,
-/* 668 */ VXT_IREPAB,VXT_VAL,5,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
-/* 676 */ 3,VXI_PUSHL,VXT_LIT,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,
-/* 684 */ VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_extexfun,VXT_END,
-/* 690 */ VXT_IREPAB,VXT_VAL,5,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
-/* 698 */ 3,VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,
-/* 706 */ VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_extexfun,VXT_END,
-/* 712 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
-/* 720 */ SIZEOF(char *) * (short int)xf_extjmp,VXT_END,
-/* 722 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 730 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_exp,VXT_END,
-/* 737 */ VXT_IREPL,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fetch,
-/* 745 */ VXT_END,
-/* 746 */ VXT_IREPAB,VXT_VAL,6,VXI_PUSHL,VXT_VAL,5,VXI_PUSHL,VXT_VAL,
-/* 754 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,
-/* 762 */ VXT_LIT,0,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnfgncal,VXT_END,
-/* 770 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL,
-/* 778 */ 2,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnascii,VXT_END,
-/* 785 */ VXT_IREPL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL,
-/* 793 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnchar,VXT_END,
-/* 797 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 805 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fndata,VXT_END,
-/* 809 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL,
-/* 817 */ 2,VXI_PUSHL,VXT_VAL,3,VXI_CALLS,VXT_LIT,4,VXT_XFER,
-/* 825 */ SIZEOF(char *) * (short int)xf_fnextract,VXT_END,
-/* 827 */ VXT_IREPAB,VXT_VAL,6,VXI_PUSHL,VXT_VAL,5,VXI_PUSHL,VXT_VAL,
-/* 835 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,
-/* 843 */ VXT_VAL,0,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnfgncal,VXT_END,
-/* 851 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
-/* 859 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
-/* 867 */ SIZEOF(char *) * (short int)xf_fnfind,VXT_END,
-/* 869 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
-/* 877 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
-/* 885 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnfnumber,VXT_END,
-/* 890 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_MOVAB,VXT_VAL,0,
-/* 898 */ VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_fnget,VXT_END,
-/* 904 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 912 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnget2,VXT_END,
-/* 919 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fngvget,
-/* 927 */ VXT_END,
-/* 928 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fngvget1,
-/* 936 */ VXT_END,
-/* 937 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 945 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnget1,VXT_END,
-/* 949 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 957 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnincr,VXT_END,
-/* 964 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 972 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnj2,VXT_END,
-/* 979 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
-/* 987 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
-/* 995 */ SIZEOF(char *) * (short int)xf_fnj3,VXT_END,
-/* 997 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 1005 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnlength,VXT_END,
-/* 1009 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 1017 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnlvname,VXT_END,
-/* 1024 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,
-/* 1032 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnlvnameo2,VXT_END,
-/* 1039 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 1047 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnlvprvname,VXT_END,
-/* 1051 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL,
-/* 1059 */ 3,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL,2,VXT_XFER,
-/* 1067 */ SIZEOF(char *) * (short int)xf_fnname,VXT_END,
-/* 1069 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 1077 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnnext,VXT_END,
-/* 1084 */ VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,
-/* 1092 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
-/* 1100 */ SIZEOF(char *) * (short int)xf_fno2,VXT_END,
-/* 1102 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 1110 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnorder,VXT_END,
-/* 1117 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
-/* 1125 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
-/* 1133 */ SIZEOF(char *) * (short int)xf_fnp1,VXT_END,
-/* 1135 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
-/* 1143 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
-/* 1151 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnpiece,VXT_END,
-/* 1156 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 1164 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnpopulation,VXT_END,
-/* 1171 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 1179 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnqlength,VXT_END,
-/* 1183 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 1191 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnqsubscript,VXT_END,
-/* 1198 */ VXT_IREPAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 1206 */ 0,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnquery,VXT_END,
-/* 1213 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 1221 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnrandom,VXT_END,
-/* 1225 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 1233 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnreverse,VXT_END,
-/* 1237 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 1245 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnstack1,VXT_END,
-/* 1249 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,
-/* 1257 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnstack2,VXT_END,
-/* 1264 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
-/* 1272 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
-/* 1280 */ SIZEOF(char *) * (short int)xf_fntext,VXT_END,
-/* 1282 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
-/* 1290 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
-/* 1298 */ SIZEOF(char *) * (short int)xf_fntranslate,VXT_END,
-/* 1300 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL,
-/* 1308 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnview,VXT_END,
-/* 1312 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL,
-/* 1320 */ 2,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzascii,VXT_END,
-/* 1327 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 1335 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzahandle,VXT_END,
-/* 1339 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
-/* 1347 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitand,VXT_END,
-/* 1354 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,
-/* 1362 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitcoun,VXT_END,
-/* 1366 */ VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 1374 */ 1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,4,VXT_XFER,
-/* 1382 */ SIZEOF(char *) * (short int)xf_fnzbitfind,VXT_END,
-/* 1384 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
-/* 1392 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitget,VXT_END,
-/* 1399 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,
-/* 1407 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitlen,VXT_END,
-/* 1411 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,
-/* 1419 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitnot,VXT_END,
-/* 1423 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
-/* 1431 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitor,VXT_END,
-/* 1438 */ VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 1446 */ 1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,4,VXT_XFER,
-/* 1454 */ SIZEOF(char *) * (short int)xf_fnzbitset,VXT_END,
-/* 1456 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
-/* 1464 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitstr,VXT_END,
-/* 1471 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
-/* 1479 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitxor,VXT_END,
-/* 1486 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL,
-/* 1494 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzcall,VXT_END,
-/* 1498 */ VXT_IREPL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL,
-/* 1506 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzchar,VXT_END,
-/* 1510 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 1518 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzconvert2,VXT_END,
-/* 1525 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
-/* 1533 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
-/* 1541 */ SIZEOF(char *) * (short int)xf_fnzconvert3,VXT_END,
-/* 1543 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 1551 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzdata,VXT_END,
-/* 1555 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,
-/* 1563 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
-/* 1571 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzdate,VXT_END,
-/* 1576 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL,
-/* 1584 */ 2,VXI_PUSHL,VXT_VAL,3,VXI_CALLS,VXT_LIT,4,VXT_XFER,
-/* 1592 */ SIZEOF(char *) * (short int)xf_fnzextract,VXT_END,
-/* 1594 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 1602 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzfile,VXT_END,
-/* 1609 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
-/* 1617 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
-/* 1625 */ SIZEOF(char *) * (short int)xf_fnzfind,VXT_END,
-/* 1627 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 1635 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngetdvi,VXT_END,
-/* 1642 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,
-/* 1650 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngetjpi,VXT_END,
-/* 1657 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,
-/* 1665 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngetlki,VXT_END,
-/* 1672 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 1680 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngetsyi,VXT_END,
-/* 1687 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 1695 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzj2,VXT_END,
-/* 1702 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 1710 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzjobexam,VXT_END,
-/* 1714 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 1722 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzlength,VXT_END,
-/* 1726 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 1734 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzlkid,VXT_END,
-/* 1738 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 1746 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzm,VXT_END,
-/* 1750 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
-/* 1758 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
-/* 1766 */ SIZEOF(char *) * (short int)xf_fnzp1,VXT_END,
-/* 1768 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,
-/* 1776 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,
-/* 1784 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,6,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzparse,VXT_END,
-/* 1792 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 1800 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpid,VXT_END,
-/* 1804 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
-/* 1812 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
-/* 1820 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpiece,VXT_END,
-/* 1825 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 1833 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpopulation,VXT_END,
-/* 1840 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 1848 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzprevious,VXT_END,
-/* 1855 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 1863 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpriv,VXT_END,
-/* 1867 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzqgblmod,
-/* 1875 */ VXT_END,
-/* 1876 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 1884 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzsearch,VXT_END,
-/* 1891 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 1899 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzsetprv,VXT_END,
-/* 1903 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,
-/* 1911 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzsigproc,VXT_END,
-/* 1918 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
-/* 1926 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
-/* 1934 */ SIZEOF(char *) * (short int)xf_fnzsubstr,VXT_END,
-/* 1936 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
-/* 1944 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
-/* 1952 */ SIZEOF(char *) * (short int)xf_fnztranslate,VXT_END,
-/* 1954 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
-/* 1962 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
-/* 1970 */ SIZEOF(char *) * (short int)xf_fnztrigger,VXT_END,
-/* 1972 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,6,VXI_PUSHAB,VXT_VAL,
-/* 1980 */ 5,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,
-/* 1988 */ VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,7,
-/* 1996 */ VXT_XFER,SIZEOF(char *) * (short int)xf_fnztrnlnm,VXT_END,
-/* 1999 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 2007 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzwidth,VXT_END,
-/* 2011 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2,
-/* 2019 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_follow,VXT_END,
-/* 2025 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,1,
-/* 2033 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forcenum,VXT_END,
-/* 2039 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forchk1,VXT_END,
-/* 2046 */ VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 2054 */ 1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forinit,VXT_END,
-/* 2059 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forlcldob,VXI_BRB,VXT_JMP,
-/* 2067 */ 1,VXT_END,
-/* 2069 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forlcldol,VXI_JMP,VXT_JMP,
-/* 2077 */ 1,VXT_END,
-/* 2079 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forlcldow,VXI_BRW,VXT_JMP,
-/* 2087 */ 1,VXT_END,
-/* 2089 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_JMP,1,VXI_PUSHAB,VXT_VAL,
-/* 2097 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_JSB,
-/* 2105 */ VXT_XFER,SIZEOF(char *) * (short int)xf_forloop,VXT_END,
-/* 2108 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_JMP,1,VXI_PUSHAB,VXT_VAL,
-/* 2116 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_JSB,
-/* 2124 */ VXT_XFER,SIZEOF(char *) * (short int)xf_forloop,VXT_END,
-/* 2127 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_JMP,1,VXI_PUSHAB,VXT_VAL,
-/* 2135 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_JSB,
-/* 2143 */ VXT_XFER,SIZEOF(char *) * (short int)xf_forloop,VXT_END,
-/* 2146 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_getindx,
-/* 2154 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END,
-/* 2160 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_gettruth,
-/* 2168 */ VXT_END,
-/* 2169 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvdata,
-/* 2177 */ VXT_END,
-/* 2178 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvextnam,
-/* 2186 */ VXT_END,
-/* 2187 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvget,
-/* 2195 */ VXT_END,
-/* 2196 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT,
-/* 2204 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_gvincr,VXT_END,
-/* 2208 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_gvkill,VXT_END,
-/* 2214 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvnaked,
-/* 2222 */ VXT_END,
-/* 2223 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvname,
-/* 2231 */ VXT_END,
-/* 2232 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvnext,
-/* 2240 */ VXT_END,
-/* 2241 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,
-/* 2249 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_gvo2,VXT_END,
-/* 2253 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvorder,
-/* 2261 */ VXT_END,
-/* 2262 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvput,
-/* 2270 */ VXT_END,
-/* 2271 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvquery,
-/* 2279 */ VXT_END,
-/* 2280 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvrectarg,
-/* 2288 */ VXT_END,
-/* 2289 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvsavtarg,
-/* 2297 */ VXT_END,
-/* 2298 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_gvzwithdraw,VXT_END,
-/* 2304 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
-/* 2312 */ 3,VXI_PUSHL,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,
-/* 2320 */ SIZEOF(char *) * (short int)xf_gvzwrite,VXT_END,
-/* 2322 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_halt,VXT_END,
-/* 2328 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 2336 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_hang,VXT_END,
-/* 2340 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_hardret,VXT_END,
-/* 2344 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 2352 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_idiv,VXT_END,
-/* 2359 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_igetsrc,
-/* 2367 */ VXT_END,
-/* 2368 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 2376 */ 1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_inddevparms,VXT_END,
-/* 2381 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
-/* 2389 */ 0,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indfnname,VXT_END,
-/* 2394 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 2402 */ 1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indfun,VXT_END,
-/* 2407 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
-/* 2415 */ SIZEOF(char *) * (short int)xf_indglvn,VXT_END,
-/* 2417 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 2425 */ 0,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indincr,VXT_END,
-/* 2430 */ VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indlvadr,VXI_MOVL,VXT_REG,
-/* 2438 */ 0x50,VXT_ADDR,0,VXT_END,
-/* 2442 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
-/* 2450 */ SIZEOF(char *) * (short int)xf_indlvarg,VXT_END,
-/* 2452 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_JSB,VXT_XFER,
-/* 2460 */ SIZEOF(char *) * (short int)xf_indmerge,VXT_END,
-/* 2462 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
-/* 2470 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_indname,VXT_END,
-/* 2477 */ VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indlvnamadr,VXI_MOVL,VXT_REG,
-/* 2485 */ 0x50,VXT_ADDR,0,VXT_END,
-/* 2489 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
-/* 2497 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_indo2,VXT_END,
-/* 2504 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
-/* 2512 */ SIZEOF(char *) * (short int)xf_indpat,VXT_END,
-/* 2514 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
-/* 2522 */ SIZEOF(char *) * (short int)xf_indrzshow,VXT_END,
-/* 2524 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
-/* 2532 */ SIZEOF(char *) * (short int)xf_indset,VXT_END,
-/* 2534 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
-/* 2542 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indtext,VXT_END,
-/* 2550 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,
-/* 2558 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_iocontrol,VXT_END,
-/* 2562 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_iretmvad,
-/* 2570 */ VXT_END,
-/* 2571 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
-/* 2579 */ SIZEOF(char *) * (short int)xf_iretmval,VXT_END,
-/* 2581 */ VXI_BRB,VXT_JMP,1,VXT_END,
-/* 2585 */ VXI_JMP,VXT_JMP,1,VXT_END,
-/* 2589 */ VXI_BRW,VXT_JMP,1,VXT_END,
-/* 2593 */ VXI_JMP,VXT_VAL,1,VXT_END,
-/* 2597 */ VXI_BEQL,VXT_JMP,1,VXT_END,
-/* 2601 */ VXI_BNEQ,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END,
-/* 2608 */ VXI_BNEQ,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END,
-/* 2615 */ VXI_BGEQ,VXT_JMP,1,VXT_END,
-/* 2619 */ VXI_BLSS,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END,
-/* 2626 */ VXI_BLSS,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END,
-/* 2633 */ VXI_BGTR,VXT_JMP,1,VXT_END,
-/* 2637 */ VXI_BLEQ,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END,
-/* 2644 */ VXI_BLEQ,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END,
-/* 2651 */ VXI_BLEQ,VXT_JMP,1,VXT_END,
-/* 2655 */ VXI_BGTR,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END,
-/* 2662 */ VXI_BGTR,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END,
-/* 2669 */ VXI_BLSS,VXT_JMP,1,VXT_END,
-/* 2673 */ VXI_BGEQ,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END,
-/* 2680 */ VXI_BGEQ,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END,
-/* 2687 */ VXI_BNEQ,VXT_JMP,1,VXT_END,
-/* 2691 */ VXI_BNEQ,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END,
-/* 2698 */ VXI_BEQL,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END,
-/* 2705 */ VXI_BLBC,VXT_REG,0x5A,VXT_JMP,1,VXT_END,
-/* 2711 */ VXI_BLBS,VXT_REG,0x5A,VXT_LIT,6,VXI_JMP,VXT_JMP,1,
-/* 2719 */ VXT_END,
-/* 2720 */ VXI_BLBS,VXT_REG,0x5A,VXT_LIT,3,VXI_BRW,VXT_JMP,1,
-/* 2728 */ VXT_END,
-/* 2729 */ VXI_BLBS,VXT_REG,0x5A,VXT_JMP,1,VXT_END,
-/* 2735 */ VXI_BLBC,VXT_REG,0x5A,VXT_LIT,6,VXI_JMP,VXT_JMP,1,
-/* 2743 */ VXT_END,
-/* 2744 */ VXI_BLBC,VXT_REG,0x5A,VXT_LIT,3,VXI_BRW,VXT_JMP,1,
-/* 2752 */ VXT_END,
-/* 2753 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,7,VXI_PUSHL,VXT_VAL,
-/* 2761 */ 6,VXI_PUSHAB,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL,
-/* 2769 */ VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,
-/* 2777 */ VXT_XFER,SIZEOF(char *) * (short int)xf_job,VXT_END,
-/* 2780 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_kill,
-/* 2788 */ VXT_END,
-/* 2789 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_killalias,
-/* 2797 */ VXT_END,
-/* 2798 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_killall,VXT_END,
-/* 2804 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_killaliasall,VXT_END,
-/* 2810 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
-/* 2818 */ 3,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_labaddr,VXI_MOVL,VXT_REG,
-/* 2826 */ 0x50,VXT_ADDR,0,VXT_END,
-/* 2830 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lckdecr,
-/* 2838 */ VXT_END,
-/* 2839 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lckincr,
-/* 2847 */ VXT_END,
-/* 2848 */ VXI_MOVAB,VXT_JMP,1,VXT_ADDR,0,VXT_END,
-/* 2854 */ VXI_MOVAB,VXT_JMP,1,VXT_ADDR,0,VXT_END,
-/* 2860 */ VXI_MOVAB,VXT_JMP,1,VXT_ADDR,0,VXT_END,
-/* 2866 */ VXT_IREPL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,
-/* 2874 */ SIZEOF(char *) * (short int)xf_linefetch,VXT_END,
-/* 2876 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_linestart,VXT_END,
-/* 2880 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
-/* 2888 */ 2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lkname,VXT_END,
-/* 2895 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_lkinit,VXT_END,
-/* 2901 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
-/* 2909 */ 2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lkname,VXT_END,
-/* 2916 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lock,
-/* 2924 */ VXT_END,
-/* 2925 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
-/* 2933 */ 2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lvpatwrite,VXT_END,
-/* 2940 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lvzwithdraw,
-/* 2948 */ VXT_END,
-/* 2949 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,
-/* 2957 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_lvzwrite,VXT_END,
-/* 2961 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_m_srchindx,
-/* 2969 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END,
-/* 2975 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_merge,VXT_END,
-/* 2981 */ VXI_PUSHL,VXT_LIT,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 2989 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_merge_arg,VXT_END,
-/* 2993 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 3001 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_merge_arg,VXT_END,
-/* 3005 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 3013 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_flt_mod,VXT_END,
-/* 3020 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 3028 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_mul,VXT_END,
-/* 3035 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,1,
-/* 3043 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_neg,VXT_END,
-/* 3049 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_newintrinsic,VXT_END,
-/* 3056 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_newvar,VXT_END,
-/* 3063 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_nullexp,
-/* 3071 */ VXT_END,
-/* 3072 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2,
-/* 3080 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_numcmp,VXT_END,
-/* 3086 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
-/* 3094 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
-/* 3102 */ VXT_LIT,4,VXT_XFER,SIZEOF(char *) * (short int)xf_open,VXT_END,
-/* 3107 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2,
-/* 3115 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_pattern,VXT_END,
-/* 3121 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_putindx,
-/* 3129 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END,
-/* 3135 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
-/* 3143 */ 0,VXI_CALLS,VXT_LIT,2,VXT_XFER,SIZEOF(char *) * (short int)xf_rdone,VXT_END,
-/* 3150 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
-/* 3158 */ 0,VXI_CALLS,VXT_LIT,2,VXT_XFER,SIZEOF(char *) * (short int)xf_read,VXT_END,
-/* 3165 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,
-/* 3173 */ 1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,3,VXT_XFER,
-/* 3181 */ SIZEOF(char *) * (short int)xf_readfl,VXT_END,
-/* 3183 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_END,
-/* 3187 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_ret,VXT_END,
-/* 3191 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVL,VXT_VAL,2,
-/* 3199 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_retarg,VXT_END,
-/* 3205 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 3213 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_rhdaddr,VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,
-/* 3221 */ VXT_END,
-/* 3222 */ VXI_PUSHL,VXT_LIT,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 3230 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_rhdaddr,VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,
-/* 3238 */ VXT_END,
-/* 3239 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,
-/* 3247 */ SIZEOF(char *) * (short int)xf_rterror,VXT_END,
-/* 3249 */ VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT,
-/* 3257 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setals2als,VXT_END,
-/* 3261 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT,
-/* 3269 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setalsin2alsct,VXT_END,
-/* 3273 */ VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT,
-/* 3281 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setalsctin2als,VXT_END,
-/* 3285 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT,
-/* 3293 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setalsct2alsct,VXT_END,
-/* 3297 */ VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT,
-/* 3305 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setfnretin2als,VXT_END,
-/* 3309 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT,
-/* 3317 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setfnretin2alsct,VXT_END,
-/* 3321 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
-/* 3329 */ 2,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
-/* 3337 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setextract,VXT_END,
-/* 3342 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
-/* 3350 */ 4,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
-/* 3358 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setp1,VXT_END,
-/* 3363 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
-/* 3371 */ 3,VXI_PUSHAB,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,
-/* 3379 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,6,VXT_XFER,SIZEOF(char *) * (short int)xf_setpiece,VXT_END,
-/* 3387 */ VXI_BISB2,VXT_LIT,1,VXT_REG,0x5A,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_dt_true,
-/* 3395 */ VXT_END,
-/* 3396 */ VXI_PUSHL,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
-/* 3404 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,3,VXI_CALLS,
-/* 3412 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setzbrk,VXT_END,
-/* 3417 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
-/* 3425 */ 2,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
-/* 3433 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setzextract,VXT_END,
-/* 3438 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
-/* 3446 */ 4,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
-/* 3454 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setzp1,VXT_END,
-/* 3459 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
-/* 3467 */ 3,VXI_PUSHAB,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,
-/* 3475 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,6,VXT_XFER,SIZEOF(char *) * (short int)xf_setzpiece,VXT_END,
-/* 3483 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2,
-/* 3491 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_sorts_after,VXT_END,
-/* 3497 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_srchindx,
-/* 3505 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END,
-/* 3511 */ VXI_MOVAB,VXT_VAL,2,VXT_REG,0x51,VXI_MOVAB,VXT_VAL,1,
-/* 3519 */ VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_sto,VXT_END,
-/* 3525 */ VXI_MOVC3,VXT_LIT,16,VXT_VAL,2,VXT_VAL,1,VXT_END,
-/* 3533 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_MOVAB,VXT_VAL,0,
-/* 3541 */ VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_sto,VXT_END,
-/* 3547 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 3555 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_sub,VXT_END,
-/* 3562 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 3570 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_svget,VXT_END,
-/* 3574 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,
-/* 3582 */ SIZEOF(char *) * (short int)xf_psvput,VXT_END,
-/* 3584 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 3592 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_svput,VXT_END,
-/* 3596 */ VXI_MOVL,VXT_REG,0x50,VXT_REG,0x5A,VXT_END,
-/* 3602 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_tcommit,VXT_END,
-/* 3606 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_trollback,VXT_END,
-/* 3613 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_trestart,VXT_END,
-/* 3620 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
-/* 3628 */ 2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_tstart,VXT_END,
-/* 3636 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_unlock,VXT_END,
-/* 3642 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 3650 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_use,VXT_END,
-/* 3654 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_view,
-/* 3662 */ VXT_END,
-/* 3663 */ VXI_CMPL,VXT_VAL,1,VXT_VAL,2,VXT_END,
-/* 3669 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_write,
-/* 3677 */ VXT_END,
-/* 3678 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_wteol,
-/* 3686 */ VXT_END,
-/* 3687 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_wtff,VXT_END,
-/* 3693 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_wtone,
-/* 3701 */ VXT_END,
-/* 3702 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_wttab,
-/* 3710 */ VXT_END,
-/* 3711 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_xkill,
-/* 3719 */ VXT_END,
-/* 3720 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,
-/* 3728 */ SIZEOF(char *) * (short int)xf_xnew,VXT_END,
-/* 3730 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zallocate,
-/* 3738 */ VXT_END,
-/* 3739 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 3747 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_zattach,VXT_END,
-/* 3751 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 3759 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zcompile,VXT_END,
-/* 3763 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zcont,VXT_END,
-/* 3767 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zdeallocate,
-/* 3775 */ VXT_END,
-/* 3776 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 3784 */ 1,VXI_CALLS,VXT_LIT,2,VXT_XFER,SIZEOF(char *) * (short int)xf_zedit,VXT_END,
-/* 3791 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zg1,VXT_END,
-/* 3798 */ VXI_PUSHL,VXT_VAL,1,VXI_PUSHL,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,
-/* 3806 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zgoto,VXT_END,
-/* 3814 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zhalt,
-/* 3822 */ VXT_END,
-/* 3823 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 3831 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zhelp,VXT_END,
-/* 3835 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 3843 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zlink,VXT_END,
-/* 3847 */ VXT_IREPAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL,2,VXI_CALLS,VXT_VAL,
-/* 3855 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_zmess,VXT_END,
-/* 3859 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zprevious,
-/* 3867 */ VXT_END,
-/* 3868 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,
-/* 3876 */ 4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,
-/* 3884 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_zprint,VXT_END,
-/* 3892 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_LIT,0,VXI_PUSHL,VXT_VAL,
-/* 3900 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,3,VXT_XFER,
-/* 3908 */ SIZEOF(char *) * (short int)xf_zshow,VXT_END,
-/* 3910 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
-/* 3918 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,3,VXT_XFER,
-/* 3926 */ SIZEOF(char *) * (short int)xf_zshow,VXT_END,
-/* 3928 */ VXI_PUSHL,VXT_LIT,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 3936 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zstep,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zcont,VXT_END,
-/* 3943 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 3951 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zstep,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zcont,VXT_END,
-/* 3958 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 3966 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_zsystem,VXT_END,
-/* 3970 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_ztcommit,
-/* 3978 */ VXT_END,
-/* 3979 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_ztrigger,VXT_END,
-/* 3985 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_ztstart,VXT_END,
-/* 3991 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zwritesvn,
-/* 3999 */ VXT_END,
-/* 4000 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 4008 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzwrite,VXT_END,
-/* 4012 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_igetdst,VXI_MOVL,VXT_REG,0x50,
-/* 4020 */ VXT_ADDR,0,VXT_END,
-/* 4023 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 4031 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_indget1,VXT_END,
-/* 4035 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_glvnpop,
-/* 4043 */ VXT_END,
-/* 4044 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_glvnslot,
-/* 4052 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END,
-/* 4058 */ VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
-/* 4066 */ 1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indsavglvn,VXT_END,
-/* 4071 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
-/* 4079 */ SIZEOF(char *) * (short int)xf_indsavlvn,VXT_END,
-/* 4081 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 4089 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_rfrshlvn,VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,
-/* 4097 */ VXT_END,
-/* 4098 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_savgvn,
-/* 4106 */ VXT_END,
-/* 4107 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_savlvn,
-/* 4115 */ VXT_END,
-/* 4116 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 4124 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_shareslot,VXT_END,
-/* 4128 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 4136 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_stoglvn,VXT_END,
-/* 4140 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
-/* 4148 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_rfrshgvn,VXT_END,
-/* 4152 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
-/* 4160 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_indfnname2,VXT_END,
-/* 4167 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,
-/* 4175 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_indget2,VXT_END,
-/* 4179 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_indmerge2,
-/* 4187 */ VXT_END,
-/* 4188 */ 358,378,368,2581,2589,2585,2848,2860,
-/* 4196 */ 2854,0,0,0,497,473,464,0,
-/* 4204 */ 0,460,2089,2127,2108,2729,2744,2735,
-/* 4212 */ 2705,2720,2711,2597,2608,2601,2687,2698,
-/* 4220 */ 2691,2633,2644,2637,2651,2662,2655,2669,
-/* 4228 */ 2680,2673,2615,2626,2619,2059,2079,2069,
-/* 4236 */ 388,408,398};
+/* 0 */ 0,0,0,0,325,3550,3023,567,
+/* 8 */ 2347,3008,3038,2028,421,3500,2149,3124,
+/* 16 */ 2226,2217,3733,3770,2190,2199,2265,2211,
+/* 24 */ 2256,2235,2172,773,788,800,812,854,
+/* 32 */ 872,893,922,952,967,982,1000,1159,
+/* 40 */ 1072,1105,1138,1216,1267,1597,1630,1645,
+/* 48 */ 1675,1741,1771,1795,1858,1879,1894,3565,
+/* 56 */ 3587,0,0,0,0,582,0,523,
+/* 64 */ 0,2014,0,3110,0,0,0,0,
+/* 72 */ 0,0,357,433,2325,2331,2756,2783,
+/* 80 */ 2801,2904,2842,2833,2919,3639,3723,3059,
+/* 88 */ 0,3089,3190,3153,3138,3168,3514,3366,
+/* 96 */ 3645,3657,3672,3696,3705,3690,3681,3399,
+/* 104 */ 3766,3779,3801,3838,3850,3871,3895,3961,
+/* 112 */ 0,0,2952,2307,3242,4240,661,4243,
+/* 120 */ 715,2813,3208,537,543,4246,2410,2507,
+/* 128 */ 2397,490,2433,2527,2181,2465,2537,4249,
+/* 136 */ 2292,2283,4253,1285,4254,353,349,3390,
+/* 144 */ 445,4258,4261,4264,3075,4267,4270,4273,
+/* 152 */ 4276,4279,4282,3536,0,2928,2596,2574,
+/* 160 */ 1558,2565,2343,2163,2879,2049,740,2869,
+/* 168 */ 0,0,2362,3714,3742,1489,3666,2445,
+/* 176 */ 2042,552,3862,1843,2274,1201,340,3194,
+/* 184 */ 624,693,605,671,3826,1120,3794,3052,
+/* 192 */ 2301,2943,3066,643,1012,2883,4285,2517,
+/* 200 */ 3913,3931,3946,514,2898,3186,1975,3988,
+/* 208 */ 3973,1303,3528,596,1660,1729,2480,4288,
+/* 216 */ 3599,2553,749,830,3225,3754,3623,3609,
+/* 224 */ 3616,3605,725,907,2420,1054,2384,1042,
+/* 232 */ 2244,1027,1087,2492,1459,1402,1387,1441,
+/* 240 */ 1357,1369,1414,1342,1426,1474,0,3486,
+/* 248 */ 0,931,940,3345,1870,3324,2371,2455,
+/* 256 */ 2978,2984,2996,2964,1240,1252,1174,1186,
+/* 264 */ 1228,3577,1705,1906,0,1315,1501,1579,
+/* 272 */ 3420,1612,1690,1717,1828,1807,3462,1753,
+/* 280 */ 3441,1939,1513,1528,2002,4003,1921,3252,
+/* 288 */ 3264,3276,3288,2792,2807,1546,454,1330,
+/* 296 */ 1957,652,3300,3312,3982,3994,0,0,
+/* 304 */ 0,0,3817,4015,4026,4038,4047,4061,
+/* 312 */ 4074,4084,4101,4110,4119,4131,4143,4155,
+/* 320 */ 4170,4182,4191,4203,4219,VXI_PUSHAB,VXT_VAL,0,
+/* 328 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 336 */ 3,VXT_XFER,SIZEOF(char *) * (short int)xf_add,VXT_END,
+/* 340 */ VXT_IREPL,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_bindparm,
+/* 348 */ VXT_END,
+/* 349 */ VXI_INCL,VXT_VAL,1,VXT_END,
+/* 353 */ VXI_CLRL,VXT_VAL,0,VXT_END,
+/* 357 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_break,VXT_END,
+/* 361 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callb,VXI_BRB,VXT_JMP,
+/* 369 */ 1,VXT_END,
+/* 371 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_calll,VXI_JMP,VXT_JMP,
+/* 379 */ 1,VXT_END,
+/* 381 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callw,VXI_BRW,VXT_JMP,
+/* 389 */ 1,VXT_END,
+/* 391 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callspb,VXI_BRB,VXT_JMP,
+/* 399 */ 1,VXT_END,
+/* 401 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callspl,VXI_JMP,VXT_JMP,
+/* 409 */ 1,VXT_END,
+/* 411 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_callspw,VXI_BRW,VXT_JMP,
+/* 419 */ 1,VXT_END,
+/* 421 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL,
+/* 429 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_cat,VXT_END,
+/* 433 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 441 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_close,VXT_END,
+/* 445 */ VXI_BICB2,VXT_LIT,1,VXT_REG,0x5A,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_dt_false,
+/* 453 */ VXT_END,
+/* 454 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_clralsvars,
+/* 462 */ VXT_END,
+/* 463 */ VXI_TSTL,VXT_VAL,1,VXT_END,
+/* 467 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_mval2bool,
+/* 475 */ VXT_END,
+/* 476 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_mval2mint,
+/* 484 */ VXI_MOVL,VXT_REG,0x50,VXT_VAL,0,VXT_END,
+/* 490 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
+/* 498 */ SIZEOF(char *) * (short int)xf_commarg,VXT_END,
+/* 500 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x50,VXI_MOVL,VXT_VAL,1,
+/* 508 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_mint2mval,VXT_END,
+/* 514 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_mval2num,
+/* 522 */ VXT_END,
+/* 523 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2,
+/* 531 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_contain,VXT_END,
+/* 537 */ VXI_MOVL,VXT_REG,0x6C,VXT_ADDR,0,VXT_END,
+/* 543 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_currtn,
+/* 551 */ VXT_END,
+/* 552 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,
+/* 560 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_cvtparm,VXT_END,
+/* 567 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 575 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_div,VXT_END,
+/* 582 */ VXI_MOVAB,VXT_VAL,2,VXT_REG,0x51,VXI_MOVAB,VXT_VAL,1,
+/* 590 */ VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_equ,VXT_END,
+/* 596 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_equnul,
+/* 604 */ VXT_END,
+/* 605 */ VXT_IREPAB,VXT_VAL,5,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
+/* 613 */ 3,VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_LIT,0,VXI_JSB,
+/* 621 */ VXT_XFER,SIZEOF(char *) * (short int)xf_exfun,VXT_END,
+/* 624 */ VXT_IREPAB,VXT_VAL,5,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
+/* 632 */ 3,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_JSB,
+/* 640 */ VXT_XFER,SIZEOF(char *) * (short int)xf_exfun,VXT_END,
+/* 643 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_exfunret,
+/* 651 */ VXT_END,
+/* 652 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_exfunretals,
+/* 660 */ VXT_END,
+/* 661 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
+/* 669 */ SIZEOF(char *) * (short int)xf_extcall,VXT_END,
+/* 671 */ VXT_IREPAB,VXT_VAL,5,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
+/* 679 */ 3,VXI_PUSHL,VXT_LIT,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,
+/* 687 */ VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_extexfun,VXT_END,
+/* 693 */ VXT_IREPAB,VXT_VAL,5,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
+/* 701 */ 3,VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,
+/* 709 */ VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_extexfun,VXT_END,
+/* 715 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
+/* 723 */ SIZEOF(char *) * (short int)xf_extjmp,VXT_END,
+/* 725 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 733 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_exp,VXT_END,
+/* 740 */ VXT_IREPL,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fetch,
+/* 748 */ VXT_END,
+/* 749 */ VXT_IREPAB,VXT_VAL,6,VXI_PUSHL,VXT_VAL,5,VXI_PUSHL,VXT_VAL,
+/* 757 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,
+/* 765 */ VXT_LIT,0,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnfgncal,VXT_END,
+/* 773 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL,
+/* 781 */ 2,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnascii,VXT_END,
+/* 788 */ VXT_IREPL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL,
+/* 796 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnchar,VXT_END,
+/* 800 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 808 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fndata,VXT_END,
+/* 812 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL,
+/* 820 */ 2,VXI_PUSHL,VXT_VAL,3,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 828 */ SIZEOF(char *) * (short int)xf_fnextract,VXT_END,
+/* 830 */ VXT_IREPAB,VXT_VAL,6,VXI_PUSHL,VXT_VAL,5,VXI_PUSHL,VXT_VAL,
+/* 838 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,
+/* 846 */ VXT_VAL,0,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnfgncal,VXT_END,
+/* 854 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
+/* 862 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 870 */ SIZEOF(char *) * (short int)xf_fnfind,VXT_END,
+/* 872 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
+/* 880 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
+/* 888 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnfnumber,VXT_END,
+/* 893 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_MOVAB,VXT_VAL,0,
+/* 901 */ VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_fnget,VXT_END,
+/* 907 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 915 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnget2,VXT_END,
+/* 922 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fngvget,
+/* 930 */ VXT_END,
+/* 931 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fngvget1,
+/* 939 */ VXT_END,
+/* 940 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 948 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnget1,VXT_END,
+/* 952 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 960 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnincr,VXT_END,
+/* 967 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 975 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnj2,VXT_END,
+/* 982 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
+/* 990 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 998 */ SIZEOF(char *) * (short int)xf_fnj3,VXT_END,
+/* 1000 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1008 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnlength,VXT_END,
+/* 1012 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1020 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnlvname,VXT_END,
+/* 1027 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,
+/* 1035 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnlvnameo2,VXT_END,
+/* 1042 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1050 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnlvprvname,VXT_END,
+/* 1054 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL,
+/* 1062 */ 3,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL,2,VXT_XFER,
+/* 1070 */ SIZEOF(char *) * (short int)xf_fnname,VXT_END,
+/* 1072 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1080 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnnext,VXT_END,
+/* 1087 */ VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,
+/* 1095 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 1103 */ SIZEOF(char *) * (short int)xf_fno2,VXT_END,
+/* 1105 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1113 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnorder,VXT_END,
+/* 1120 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
+/* 1128 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 1136 */ SIZEOF(char *) * (short int)xf_fnp1,VXT_END,
+/* 1138 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
+/* 1146 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
+/* 1154 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnpiece,VXT_END,
+/* 1159 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1167 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnpopulation,VXT_END,
+/* 1174 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1182 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnqlength,VXT_END,
+/* 1186 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1194 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnqsubscript,VXT_END,
+/* 1201 */ VXT_IREPAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1209 */ 0,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnquery,VXT_END,
+/* 1216 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1224 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnrandom,VXT_END,
+/* 1228 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1236 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnreverse,VXT_END,
+/* 1240 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1248 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnstack1,VXT_END,
+/* 1252 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,
+/* 1260 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnstack2,VXT_END,
+/* 1267 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
+/* 1275 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 1283 */ SIZEOF(char *) * (short int)xf_fntext,VXT_END,
+/* 1285 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
+/* 1293 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 1301 */ SIZEOF(char *) * (short int)xf_fntranslate,VXT_END,
+/* 1303 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL,
+/* 1311 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnview,VXT_END,
+/* 1315 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL,
+/* 1323 */ 2,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzascii,VXT_END,
+/* 1330 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1338 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzahandle,VXT_END,
+/* 1342 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
+/* 1350 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitand,VXT_END,
+/* 1357 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,
+/* 1365 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitcoun,VXT_END,
+/* 1369 */ VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1377 */ 1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 1385 */ SIZEOF(char *) * (short int)xf_fnzbitfind,VXT_END,
+/* 1387 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
+/* 1395 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitget,VXT_END,
+/* 1402 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,
+/* 1410 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitlen,VXT_END,
+/* 1414 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,
+/* 1422 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitnot,VXT_END,
+/* 1426 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
+/* 1434 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitor,VXT_END,
+/* 1441 */ VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1449 */ 1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 1457 */ SIZEOF(char *) * (short int)xf_fnzbitset,VXT_END,
+/* 1459 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
+/* 1467 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitstr,VXT_END,
+/* 1474 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
+/* 1482 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzbitxor,VXT_END,
+/* 1489 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL,
+/* 1497 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzcall,VXT_END,
+/* 1501 */ VXT_IREPL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_VAL,
+/* 1509 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzchar,VXT_END,
+/* 1513 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1521 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzconvert2,VXT_END,
+/* 1528 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
+/* 1536 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 1544 */ SIZEOF(char *) * (short int)xf_fnzconvert3,VXT_END,
+/* 1546 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1554 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzdata,VXT_END,
+/* 1558 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,
+/* 1566 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
+/* 1574 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzdate,VXT_END,
+/* 1579 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHL,VXT_VAL,
+/* 1587 */ 2,VXI_PUSHL,VXT_VAL,3,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 1595 */ SIZEOF(char *) * (short int)xf_fnzextract,VXT_END,
+/* 1597 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1605 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzfile,VXT_END,
+/* 1612 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
+/* 1620 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 1628 */ SIZEOF(char *) * (short int)xf_fnzfind,VXT_END,
+/* 1630 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1638 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngetdvi,VXT_END,
+/* 1645 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,
+/* 1653 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngetjpi,VXT_END,
+/* 1660 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,
+/* 1668 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngetlki,VXT_END,
+/* 1675 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1683 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fngetsyi,VXT_END,
+/* 1690 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1698 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzj2,VXT_END,
+/* 1705 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1713 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzjobexam,VXT_END,
+/* 1717 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1725 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzlength,VXT_END,
+/* 1729 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1737 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzlkid,VXT_END,
+/* 1741 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1749 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzm,VXT_END,
+/* 1753 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
+/* 1761 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 1769 */ SIZEOF(char *) * (short int)xf_fnzp1,VXT_END,
+/* 1771 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,
+/* 1779 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,
+/* 1787 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,6,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzparse,VXT_END,
+/* 1795 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1803 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpid,VXT_END,
+/* 1807 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
+/* 1815 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
+/* 1823 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpiece,VXT_END,
+/* 1828 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1836 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpopulation,VXT_END,
+/* 1843 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1851 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzprevious,VXT_END,
+/* 1858 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1866 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpriv,VXT_END,
+/* 1870 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzqgblmod,
+/* 1878 */ VXT_END,
+/* 1879 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 1887 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzsearch,VXT_END,
+/* 1894 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 1902 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzsetprv,VXT_END,
+/* 1906 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,
+/* 1914 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzsigproc,VXT_END,
+/* 1921 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
+/* 1929 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 1937 */ SIZEOF(char *) * (short int)xf_fnzsubstr,VXT_END,
+/* 1939 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
+/* 1947 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 1955 */ SIZEOF(char *) * (short int)xf_fnztranslate,VXT_END,
+/* 1957 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
+/* 1965 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,4,VXT_XFER,
+/* 1973 */ SIZEOF(char *) * (short int)xf_fnztrigger,VXT_END,
+/* 1975 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,6,VXI_PUSHAB,VXT_VAL,
+/* 1983 */ 5,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,
+/* 1991 */ VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,7,
+/* 1999 */ VXT_XFER,SIZEOF(char *) * (short int)xf_fnztrnlnm,VXT_END,
+/* 2002 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 2010 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzwidth,VXT_END,
+/* 2014 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2,
+/* 2022 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_follow,VXT_END,
+/* 2028 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,1,
+/* 2036 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forcenum,VXT_END,
+/* 2042 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forchk1,VXT_END,
+/* 2049 */ VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 2057 */ 1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forinit,VXT_END,
+/* 2062 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forlcldob,VXI_BRB,VXT_JMP,
+/* 2070 */ 1,VXT_END,
+/* 2072 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forlcldol,VXI_JMP,VXT_JMP,
+/* 2080 */ 1,VXT_END,
+/* 2082 */ VXI_PUSHL,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_forlcldow,VXI_BRW,VXT_JMP,
+/* 2090 */ 1,VXT_END,
+/* 2092 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_JMP,1,VXI_PUSHAB,VXT_VAL,
+/* 2100 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_JSB,
+/* 2108 */ VXT_XFER,SIZEOF(char *) * (short int)xf_forloop,VXT_END,
+/* 2111 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_JMP,1,VXI_PUSHAB,VXT_VAL,
+/* 2119 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_JSB,
+/* 2127 */ VXT_XFER,SIZEOF(char *) * (short int)xf_forloop,VXT_END,
+/* 2130 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_JMP,1,VXI_PUSHAB,VXT_VAL,
+/* 2138 */ 4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_JSB,
+/* 2146 */ VXT_XFER,SIZEOF(char *) * (short int)xf_forloop,VXT_END,
+/* 2149 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_getindx,
+/* 2157 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END,
+/* 2163 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_gettruth,
+/* 2171 */ VXT_END,
+/* 2172 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvdata,
+/* 2180 */ VXT_END,
+/* 2181 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvextnam,
+/* 2189 */ VXT_END,
+/* 2190 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvget,
+/* 2198 */ VXT_END,
+/* 2199 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT,
+/* 2207 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_gvincr,VXT_END,
+/* 2211 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_gvkill,VXT_END,
+/* 2217 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvnaked,
+/* 2225 */ VXT_END,
+/* 2226 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvname,
+/* 2234 */ VXT_END,
+/* 2235 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvnext,
+/* 2243 */ VXT_END,
+/* 2244 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,
+/* 2252 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_gvo2,VXT_END,
+/* 2256 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvorder,
+/* 2264 */ VXT_END,
+/* 2265 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvput,
+/* 2273 */ VXT_END,
+/* 2274 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvquery,
+/* 2282 */ VXT_END,
+/* 2283 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvrectarg,
+/* 2291 */ VXT_END,
+/* 2292 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_gvsavtarg,
+/* 2300 */ VXT_END,
+/* 2301 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_gvzwithdraw,VXT_END,
+/* 2307 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
+/* 2315 */ 3,VXI_PUSHL,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,
+/* 2323 */ SIZEOF(char *) * (short int)xf_gvzwrite,VXT_END,
+/* 2325 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_halt,VXT_END,
+/* 2331 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 2339 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_hang,VXT_END,
+/* 2343 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_hardret,VXT_END,
+/* 2347 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 2355 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_idiv,VXT_END,
+/* 2362 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_igetsrc,
+/* 2370 */ VXT_END,
+/* 2371 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 2379 */ 1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_inddevparms,VXT_END,
+/* 2384 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
+/* 2392 */ 0,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indfnname,VXT_END,
+/* 2397 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 2405 */ 1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indfun,VXT_END,
+/* 2410 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
+/* 2418 */ SIZEOF(char *) * (short int)xf_indglvn,VXT_END,
+/* 2420 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 2428 */ 0,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indincr,VXT_END,
+/* 2433 */ VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indlvadr,VXI_MOVL,VXT_REG,
+/* 2441 */ 0x50,VXT_ADDR,0,VXT_END,
+/* 2445 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
+/* 2453 */ SIZEOF(char *) * (short int)xf_indlvarg,VXT_END,
+/* 2455 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_JSB,VXT_XFER,
+/* 2463 */ SIZEOF(char *) * (short int)xf_indmerge,VXT_END,
+/* 2465 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
+/* 2473 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_indname,VXT_END,
+/* 2480 */ VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indlvnamadr,VXI_MOVL,VXT_REG,
+/* 2488 */ 0x50,VXT_ADDR,0,VXT_END,
+/* 2492 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
+/* 2500 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_indo2,VXT_END,
+/* 2507 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
+/* 2515 */ SIZEOF(char *) * (short int)xf_indpat,VXT_END,
+/* 2517 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
+/* 2525 */ SIZEOF(char *) * (short int)xf_indrzshow,VXT_END,
+/* 2527 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
+/* 2535 */ SIZEOF(char *) * (short int)xf_indset,VXT_END,
+/* 2537 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
+/* 2545 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indtext,VXT_END,
+/* 2553 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,
+/* 2561 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_iocontrol,VXT_END,
+/* 2565 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_iretmvad,
+/* 2573 */ VXT_END,
+/* 2574 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
+/* 2582 */ SIZEOF(char *) * (short int)xf_iretmval,VXT_END,
+/* 2584 */ VXI_BRB,VXT_JMP,1,VXT_END,
+/* 2588 */ VXI_JMP,VXT_JMP,1,VXT_END,
+/* 2592 */ VXI_BRW,VXT_JMP,1,VXT_END,
+/* 2596 */ VXI_JMP,VXT_VAL,1,VXT_END,
+/* 2600 */ VXI_BEQL,VXT_JMP,1,VXT_END,
+/* 2604 */ VXI_BNEQ,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END,
+/* 2611 */ VXI_BNEQ,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END,
+/* 2618 */ VXI_BGEQ,VXT_JMP,1,VXT_END,
+/* 2622 */ VXI_BLSS,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END,
+/* 2629 */ VXI_BLSS,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END,
+/* 2636 */ VXI_BGTR,VXT_JMP,1,VXT_END,
+/* 2640 */ VXI_BLEQ,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END,
+/* 2647 */ VXI_BLEQ,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END,
+/* 2654 */ VXI_BLEQ,VXT_JMP,1,VXT_END,
+/* 2658 */ VXI_BGTR,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END,
+/* 2665 */ VXI_BGTR,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END,
+/* 2672 */ VXI_BLSS,VXT_JMP,1,VXT_END,
+/* 2676 */ VXI_BGEQ,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END,
+/* 2683 */ VXI_BGEQ,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END,
+/* 2690 */ VXI_BNEQ,VXT_JMP,1,VXT_END,
+/* 2694 */ VXI_BNEQ,VXT_LIT,6,VXI_JMP,VXT_JMP,1,VXT_END,
+/* 2701 */ VXI_BEQL,VXT_LIT,3,VXI_BRW,VXT_JMP,1,VXT_END,
+/* 2708 */ VXI_BLBC,VXT_REG,0x5A,VXT_JMP,1,VXT_END,
+/* 2714 */ VXI_BLBS,VXT_REG,0x5A,VXT_LIT,6,VXI_JMP,VXT_JMP,1,
+/* 2722 */ VXT_END,
+/* 2723 */ VXI_BLBS,VXT_REG,0x5A,VXT_LIT,3,VXI_BRW,VXT_JMP,1,
+/* 2731 */ VXT_END,
+/* 2732 */ VXI_BLBS,VXT_REG,0x5A,VXT_JMP,1,VXT_END,
+/* 2738 */ VXI_BLBC,VXT_REG,0x5A,VXT_LIT,6,VXI_JMP,VXT_JMP,1,
+/* 2746 */ VXT_END,
+/* 2747 */ VXI_BLBC,VXT_REG,0x5A,VXT_LIT,3,VXI_BRW,VXT_JMP,1,
+/* 2755 */ VXT_END,
+/* 2756 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,7,VXI_PUSHL,VXT_VAL,
+/* 2764 */ 6,VXI_PUSHAB,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL,
+/* 2772 */ VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,
+/* 2780 */ VXT_XFER,SIZEOF(char *) * (short int)xf_job,VXT_END,
+/* 2783 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_kill,
+/* 2791 */ VXT_END,
+/* 2792 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_killalias,
+/* 2800 */ VXT_END,
+/* 2801 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_killall,VXT_END,
+/* 2807 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_killaliasall,VXT_END,
+/* 2813 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
+/* 2821 */ 3,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_labaddr,VXI_MOVL,VXT_REG,
+/* 2829 */ 0x50,VXT_ADDR,0,VXT_END,
+/* 2833 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lckdecr,
+/* 2841 */ VXT_END,
+/* 2842 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lckincr,
+/* 2850 */ VXT_END,
+/* 2851 */ VXI_MOVAB,VXT_JMP,1,VXT_ADDR,0,VXT_END,
+/* 2857 */ VXI_MOVAB,VXT_JMP,1,VXT_ADDR,0,VXT_END,
+/* 2863 */ VXI_MOVAB,VXT_JMP,1,VXT_ADDR,0,VXT_END,
+/* 2869 */ VXT_IREPL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,
+/* 2877 */ SIZEOF(char *) * (short int)xf_linefetch,VXT_END,
+/* 2879 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_linestart,VXT_END,
+/* 2883 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
+/* 2891 */ 2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lkname,VXT_END,
+/* 2898 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_lkinit,VXT_END,
+/* 2904 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
+/* 2912 */ 2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lkname,VXT_END,
+/* 2919 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lock,
+/* 2927 */ VXT_END,
+/* 2928 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
+/* 2936 */ 2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lvpatwrite,VXT_END,
+/* 2943 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_lvzwithdraw,
+/* 2951 */ VXT_END,
+/* 2952 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,
+/* 2960 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_lvzwrite,VXT_END,
+/* 2964 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_m_srchindx,
+/* 2972 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END,
+/* 2978 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_merge,VXT_END,
+/* 2984 */ VXI_PUSHL,VXT_LIT,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 2992 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_merge_arg,VXT_END,
+/* 2996 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3004 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_merge_arg,VXT_END,
+/* 3008 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 3016 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_flt_mod,VXT_END,
+/* 3023 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 3031 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_mul,VXT_END,
+/* 3038 */ VXI_MOVAB,VXT_VAL,0,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,1,
+/* 3046 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_neg,VXT_END,
+/* 3052 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_newintrinsic,VXT_END,
+/* 3059 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_newvar,VXT_END,
+/* 3066 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_nullexp,
+/* 3074 */ VXT_END,
+/* 3075 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2,
+/* 3083 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_numcmp,VXT_END,
+/* 3089 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
+/* 3097 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
+/* 3105 */ VXT_LIT,4,VXT_XFER,SIZEOF(char *) * (short int)xf_open,VXT_END,
+/* 3110 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2,
+/* 3118 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_pattern,VXT_END,
+/* 3124 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_putindx,
+/* 3132 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END,
+/* 3138 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
+/* 3146 */ 0,VXI_CALLS,VXT_LIT,2,VXT_XFER,SIZEOF(char *) * (short int)xf_rdone,VXT_END,
+/* 3153 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
+/* 3161 */ 0,VXI_CALLS,VXT_LIT,2,VXT_XFER,SIZEOF(char *) * (short int)xf_read,VXT_END,
+/* 3168 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,
+/* 3176 */ 1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,3,VXT_XFER,
+/* 3184 */ SIZEOF(char *) * (short int)xf_readfl,VXT_END,
+/* 3186 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXT_END,
+/* 3190 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_ret,VXT_END,
+/* 3194 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVL,VXT_VAL,2,
+/* 3202 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_retarg,VXT_END,
+/* 3208 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3216 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_rhdaddr,VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,
+/* 3224 */ VXT_END,
+/* 3225 */ VXI_PUSHL,VXT_LIT,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3233 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_rhdaddr,VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,
+/* 3241 */ VXT_END,
+/* 3242 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,
+/* 3250 */ SIZEOF(char *) * (short int)xf_rterror,VXT_END,
+/* 3252 */ VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT,
+/* 3260 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setals2als,VXT_END,
+/* 3264 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT,
+/* 3272 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setalsin2alsct,VXT_END,
+/* 3276 */ VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT,
+/* 3284 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setalsctin2als,VXT_END,
+/* 3288 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT,
+/* 3296 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setalsct2alsct,VXT_END,
+/* 3300 */ VXI_PUSHL,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT,
+/* 3308 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setfnretin2als,VXT_END,
+/* 3312 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,2,VXI_CALLS,VXT_LIT,
+/* 3320 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_setfnretin2alsct,VXT_END,
+/* 3324 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
+/* 3332 */ 2,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
+/* 3340 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setextract,VXT_END,
+/* 3345 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
+/* 3353 */ 4,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
+/* 3361 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setp1,VXT_END,
+/* 3366 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
+/* 3374 */ 3,VXI_PUSHAB,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,
+/* 3382 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,6,VXT_XFER,SIZEOF(char *) * (short int)xf_setpiece,VXT_END,
+/* 3390 */ VXI_BISB2,VXT_LIT,1,VXT_REG,0x5A,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_dt_true,
+/* 3398 */ VXT_END,
+/* 3399 */ VXI_PUSHL,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
+/* 3407 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,3,VXI_CALLS,
+/* 3415 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setzbrk,VXT_END,
+/* 3420 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
+/* 3428 */ 2,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
+/* 3436 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setzextract,VXT_END,
+/* 3441 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
+/* 3449 */ 4,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
+/* 3457 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_setzp1,VXT_END,
+/* 3462 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
+/* 3470 */ 3,VXI_PUSHAB,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,
+/* 3478 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,6,VXT_XFER,SIZEOF(char *) * (short int)xf_setzpiece,VXT_END,
+/* 3486 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x50,VXI_MOVAB,VXT_VAL,2,
+/* 3494 */ VXT_REG,0x51,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_sorts_after,VXT_END,
+/* 3500 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_srchindx,
+/* 3508 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END,
+/* 3514 */ VXI_MOVAB,VXT_VAL,2,VXT_REG,0x51,VXI_MOVAB,VXT_VAL,1,
+/* 3522 */ VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_sto,VXT_END,
+/* 3528 */ VXI_MOVC3,VXT_LIT,16,VXT_VAL,2,VXT_VAL,1,VXT_END,
+/* 3536 */ VXI_MOVAB,VXT_VAL,1,VXT_REG,0x51,VXI_MOVAB,VXT_VAL,0,
+/* 3544 */ VXT_REG,0x50,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_sto,VXT_END,
+/* 3550 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 3558 */ 1,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_sub,VXT_END,
+/* 3565 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3573 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_svget,VXT_END,
+/* 3577 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,
+/* 3585 */ SIZEOF(char *) * (short int)xf_psvput,VXT_END,
+/* 3587 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3595 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_svput,VXT_END,
+/* 3599 */ VXI_MOVL,VXT_REG,0x50,VXT_REG,0x5A,VXT_END,
+/* 3605 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_tcommit,VXT_END,
+/* 3609 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_trollback,VXT_END,
+/* 3616 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_trestart,VXT_END,
+/* 3623 */ VXT_IREPAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,
+/* 3631 */ 2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_tstart,VXT_END,
+/* 3639 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_unlock,VXT_END,
+/* 3645 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3653 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_use,VXT_END,
+/* 3657 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_view,
+/* 3665 */ VXT_END,
+/* 3666 */ VXI_CMPL,VXT_VAL,1,VXT_VAL,2,VXT_END,
+/* 3672 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_write,
+/* 3680 */ VXT_END,
+/* 3681 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_wteol,
+/* 3689 */ VXT_END,
+/* 3690 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_wtff,VXT_END,
+/* 3696 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_wtone,
+/* 3704 */ VXT_END,
+/* 3705 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_wttab,
+/* 3713 */ VXT_END,
+/* 3714 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_xkill,
+/* 3722 */ VXT_END,
+/* 3723 */ VXT_IREPAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,
+/* 3731 */ SIZEOF(char *) * (short int)xf_xnew,VXT_END,
+/* 3733 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zallocate,
+/* 3741 */ VXT_END,
+/* 3742 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3750 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_zattach,VXT_END,
+/* 3754 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3762 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zcompile,VXT_END,
+/* 3766 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zcont,VXT_END,
+/* 3770 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zdeallocate,
+/* 3778 */ VXT_END,
+/* 3779 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 3787 */ 1,VXI_CALLS,VXT_LIT,2,VXT_XFER,SIZEOF(char *) * (short int)xf_zedit,VXT_END,
+/* 3794 */ VXI_PUSHL,VXT_VAL,1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zg1,VXT_END,
+/* 3801 */ VXI_PUSHL,VXT_VAL,1,VXI_PUSHL,VXT_VAL,4,VXI_PUSHAB,VXT_VAL,
+/* 3809 */ 3,VXI_PUSHAB,VXT_VAL,2,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zgoto,VXT_END,
+/* 3817 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zhalt,
+/* 3825 */ VXT_END,
+/* 3826 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3834 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zhelp,VXT_END,
+/* 3838 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3846 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zlink,VXT_END,
+/* 3850 */ VXT_IREPAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL,2,VXI_CALLS,VXT_VAL,
+/* 3858 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_zmess,VXT_END,
+/* 3862 */ VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zprevious,
+/* 3870 */ VXT_END,
+/* 3871 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_VAL,5,VXI_PUSHAB,VXT_VAL,
+/* 3879 */ 4,VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,
+/* 3887 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_zprint,VXT_END,
+/* 3895 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHL,VXT_LIT,0,VXI_PUSHL,VXT_VAL,
+/* 3903 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,3,VXT_XFER,
+/* 3911 */ SIZEOF(char *) * (short int)xf_zshow,VXT_END,
+/* 3913 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,3,VXI_PUSHL,VXT_VAL,
+/* 3921 */ 2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,3,VXT_XFER,
+/* 3929 */ SIZEOF(char *) * (short int)xf_zshow,VXT_END,
+/* 3931 */ VXI_PUSHL,VXT_LIT,0,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3939 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zstep,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zcont,VXT_END,
+/* 3946 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3954 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_zstep,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_zcont,VXT_END,
+/* 3961 */ VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_restartpc,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 3969 */ 1,VXT_XFER,SIZEOF(char *) * (short int)xf_zsystem,VXT_END,
+/* 3973 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_ztcommit,
+/* 3981 */ VXT_END,
+/* 3982 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_ztrigger,VXT_END,
+/* 3988 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_ztstart,VXT_END,
+/* 3994 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_zwritesvn,
+/* 4002 */ VXT_END,
+/* 4003 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 4011 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzwrite,VXT_END,
+/* 4015 */ VXI_CALLS,VXT_LIT,0,VXT_XFER,SIZEOF(char *) * (short int)xf_igetdst,VXI_MOVL,VXT_REG,0x50,
+/* 4023 */ VXT_ADDR,0,VXT_END,
+/* 4026 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 4034 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_indget1,VXT_END,
+/* 4038 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_glvnpop,
+/* 4046 */ VXT_END,
+/* 4047 */ VXI_PUSHL,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_glvnslot,
+/* 4055 */ VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,VXT_END,
+/* 4061 */ VXI_PUSHL,VXT_VAL,3,VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,
+/* 4069 */ 1,VXI_JSB,VXT_XFER,SIZEOF(char *) * (short int)xf_indsavglvn,VXT_END,
+/* 4074 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_JSB,VXT_XFER,
+/* 4082 */ SIZEOF(char *) * (short int)xf_indsavlvn,VXT_END,
+/* 4084 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 4092 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_rfrshlvn,VXI_MOVL,VXT_REG,0x50,VXT_ADDR,0,
+/* 4100 */ VXT_END,
+/* 4101 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_savgvn,
+/* 4109 */ VXT_END,
+/* 4110 */ VXT_IREPAB,VXT_VAL,2,VXI_CALLS,VXT_VAL,1,VXT_XFER,SIZEOF(char *) * (short int)xf_savlvn,
+/* 4118 */ VXT_END,
+/* 4119 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 4127 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_shareslot,VXT_END,
+/* 4131 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 4139 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_stoglvn,VXT_END,
+/* 4143 */ VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,
+/* 4151 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_rfrshgvn,VXT_END,
+/* 4155 */ VXI_PUSHAB,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,
+/* 4163 */ 0,VXI_CALLS,VXT_LIT,3,VXT_XFER,SIZEOF(char *) * (short int)xf_indfnname2,VXT_END,
+/* 4170 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,
+/* 4178 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_indget2,VXT_END,
+/* 4182 */ VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_indmerge2,
+/* 4190 */ VXT_END,
+/* 4191 */ VXI_PUSHAB,VXT_VAL,1,VXI_PUSHAB,VXT_VAL,0,VXI_CALLS,VXT_LIT,
+/* 4199 */ 2,VXT_XFER,SIZEOF(char *) * (short int)xf_litc,VXT_END,
+/* 4203 */ VXI_MOVC3,VXT_LIT,16,VXT_VAL,2,VXT_VAL,1,VXI_PUSHAB,
+/* 4211 */ VXT_VAL,1,VXI_CALLS,VXT_LIT,1,VXT_XFER,SIZEOF(char *) * (short int)xf_stolitc,VXT_END,
+/* 4219 */ VXI_PUSHAB,VXT_VAL,0,VXI_PUSHAB,VXT_VAL,4,VXI_PUSHL,VXT_VAL,
+/* 4227 */ 3,VXI_PUSHL,VXT_VAL,2,VXI_PUSHAB,VXT_VAL,1,VXI_CALLS,
+/* 4235 */ VXT_LIT,5,VXT_XFER,SIZEOF(char *) * (short int)xf_fnzpeek,VXT_END,
+/* 4240 */ 361,381,371,2584,2592,2588,2851,2863,
+/* 4248 */ 2857,0,0,0,500,476,467,0,
+/* 4256 */ 0,463,2092,2130,2111,2732,2747,2738,
+/* 4264 */ 2708,2723,2714,2600,2611,2604,2690,2701,
+/* 4272 */ 2694,2636,2647,2640,2654,2665,2658,2672,
+/* 4280 */ 2683,2676,2618,2629,2622,2062,2082,2072,
+/* 4288 */ 391,411,401};
--
Alioth's /git/debian-med/git-commit-notice on /srv/git.debian.org/git/debian-med/fis-gtm.git
More information about the debian-med-commit
mailing list