z/OS 上 Java 程序的用户指定 ABEND 代码

Posted

技术标签:

【中文标题】z/OS 上 Java 程序的用户指定 ABEND 代码【英文标题】:User specified ABEND code for Java Program on z/OS 【发布时间】:2020-04-17 02:26:25 【问题描述】:

如果我在 JZOS 启动器中设置环境变量

导出 JZOS_ABEND_EXIT=50

然后在 Java 代码中调用System.exit(51),程序将像这样终止:

IEF450I MYPROG JAVAJVM 创建 - ABEND=S000 U3333 REASON=00000010

是否可以指定异常终止代码,例如将其设为 U999 而不是 U3333。我在How to trigger a user ABEND? 中找到了对 LE abend 例程“CEE3ABD”的神秘引用,但如果有人能指出如何从 Java 调用此例程,我将不胜感激。我是否需要编写 JNI 代码并从 C 语言调用它?还是有更简单的方法?

【问题讨论】:

我已经很久没有在 zos 上做任何事情了,但是您链接上的 response 似乎很相关。另外,你不应该在那里使用50 吗?基本上,我认为的建议是使用 JCL(作业控制语言)来监控退出代码并生成适当的 ABEND 代码。如果有这样的 C 库,应该可以用 JNI 或 JNA 调用它。但我认为链接中的批处理解决方案可能更容易。 当我说很长一段时间时,“zos”当时被称为 OS/390(和迷你版的 OS/400)。 IBM Documentation.... 它总是那么美丽 第 292-293 页是我认为您想要的部分。但是,我不知道第 4、26 和 54 页是否故意留白。所以他们似乎已经滑倒了一些(至少与我记忆中的相比)。答案可能在某处的文档中。至于为什么会这样工作,他们仍然有 50 到 70 年代运行银行、社会保障和失业等的软件。而且这些东西必须从穿孔卡上运行(当时)。 IBM 必须(通常)去发明一些方法来做到这一点。 @ElliottFrisch 51 是正确的 - 任何大于 JZOS_ABEND_EXIT 的值大于 都会触发异常结束。 @ElliottFrisch 您可能会发现 IBM 文档的 Knowledge Center 版本比 PDF 更友好。 【参考方案1】:

我玩了一下,发现对于 31 位 JZOS,您还可以通过 LE-runtime-options 注册一个用户编写的条件处理程序,并使用它来捕获 U3333 异常并将其更改为其他内容。

不幸的是,(从 z/OS 2.3 开始)似乎无法通过 64 位 LE 中的运行时选项注册条件处理程序。

在您的 JCL 中,您可以通过 CEEOPTS DD 语句添加选项:

//CEEOPTS  DD   *              
ENVAR("JZOS_ABEND_EXIT=50")    
USRHDLR(MYHDLR)                
/*                             

在处理程序中,您可以分析消息 CEE3250(用户发起的异常终止)的 LE-condition.token。在这种情况下,您可以调用 CEEGQDT 以获取包含异常结束和原因码的异常结束特定 q_data,以便您识别 U3333。

如果您想发出不同的 ABEND,您可以调用 CEE3ABD。请注意,我只有通过使用CLEANUP = 0 调用 CEE3ABD 来禁用任何进一步的 LE 条件处理才能使其工作。我想否则有些事情会搞砸,因为在当前处理程序尚未退出时引发了另一个条件。

这是我用 PL/I 编写的示例处理程序,但也可以用 COBOL 或 C(如果您愿意,也可以使用汇编程序......)来完成。

MYHDLR: PROC(P1,P2,P3,P4) OPTIONS(BYVALUE FETCHABLE);                  

   DCL(P1,P2,P3,P4) POINTER;                                           
/* DCL CUR_COND     CHAR(12);  */  /*P1->*/                            
   DCL TOKEN        BIN FIXED(31) BASED(P2);                           
   DCL RESULT       BIN FIXED(31) BASED(P3);                           
/* DCL NEW_COND     CHAR(12);  */  /*P4->*/                            


   DCL COND_PTR      POINTER;                                          
   DCL 1 COND_STRU   BASED(COND_PTR),                                  
          2 SEVERITY BIN FIXED(15),                                    
          2 MESSAGE  BIN FIXED(15),                                    
          2 FLAGS    BIT(8),                                           
          2 FACILITY CHAR(3),                                          
          2 ISI      BIN FIXED(31);                                    

   DCL QDATA_PTR   POINTER;                                            

   DCL 1 QDATA        BASED(QDATA_PTR),                                
         2 QCOUNT_PTR POINTER,                                         
         2 ABCODE_PTR POINTER,                                         
         2 REASON_PTR POINTER;                                         

   DCL ABCODE         BIN FIXED(31) BASED(ABCODE_PTR);                 
   DCL REASON         BIN FIXED(31) BASED(REASON_PTR);                 

   DCL MYABCODE       BIN FIXED(31);                                   
   DCL CLEANUP        BIN FIXED(31);                                   

   DCL FEEDBACK     CHAR(12);                                          

   DCL SYSPRINT     FILE;                                              
   DCL (CEEGQDT,CEE3ABD)  ENTRY OPTIONS(ASM);                          

   PUT SKIP LIST('HANDLER CALLED');                                

   /* ANALYZE CONDITION */                                         
   COND_PTR = P1;                                                  
   PUT SKIP EDIT(FACILITY,MESSAGE,SEVERITY)(A,F(4),F(4));          
   IF FACILITY = 'CEE' & MESSAGE = 3250 THEN DO;                   
      PUT SKIP LIST('ABEND ISSUED');                               
      CALL CEEGQDT(COND_STRU,QDATA_PTR,FEEDBACK);                  
      COND_PTR = ADDR(FEEDBACK); /* REUSE TOKEN STRUCTURE */       
      PUT SKIP EDIT(SEVERITY,ABCODE)(F(6),F(6));                   
      IF SEVERITY = 0 &          /* CEEGQDT CALL SUCCESSFUL */     
         ABCODE = 3333           /* ONLY HANDLE USER-ABEND U3333 */
      THEN DO;                                                     
         CLEANUP = 0;            /* NO LE-CLEANUP */               
         MYABCODE = 100;                                           
         IF REASON = 51 THEN MYABCODE = 999;                       
         CALL CEE3ABD(MYABCODE,CLEANUP);                           
      END;                                                         
   END;                                                            
   ELSE DO;                                                        
      PUT SKIP LIST('NO ABEND');                                   
      RESULT = 20; /* PERCOLATE CONDITION */                       
   END;                                                            


END;                                                               

【讨论】:

【参考方案2】:

我通过使用 JNI 调用解决了这个问题。我没有依赖用户编写的退出处理程序,而是直接从 Java 调用 Abend.abend 方法。

public class Abend 
    public static native void abend(int abcode, int reasoncode, int cleanup);

和C的实现:

#include <stdio.h>
#include <ctest.h>
#include "Abend.h"

#define _POSIX_SOURCE
#include <unistd.h>

JNIEXPORT void JNICALL Java_Abend_abend
  (JNIEnv * end, jclass class, jint code, jint reasoncode, jint timing) 
   /* fprintf(stderr, "values %d %d %d\n", code, reasoncode, timing);*/
   __cabend(code, reasoncode, timing);

【讨论】:

以上是关于z/OS 上 Java 程序的用户指定 ABEND 代码的主要内容,如果未能解决你的问题,请参考以下文章

java.lang.UnsatisfiedLinkError - 运行 z/OS 应用程序时

如何使用 Java 确定在 z/OS 上哪个安全管理器处于活动状态?

如何通过 Java Web 应用在 IBM z OS 中提交 JCL?

如何在 z/os Unix 组中显示用户?

尝试执行 Web 服务时,“Abend in target program”作为一般异常

在 z/OS 上启用端口共享时是不是有任何源代码注意事项?