CEE3INF 的优势在于可以记录并移植到任何 LE 环境,以及提供在 z/OS 结构中不容易找到的有关 PIPI 的信息。
作为 CEE3INF 的替代方案,如果您只需要区分 Batch、TSO、CICS 以及您是否被称为 USS 流程,那么系统数据区域中有大量信息。替代方法很简单,而且它在 LE 环境之外特别有用……尽管它在 C 中甚至很容易通过加载一些指针来完成,您可以使用 XLC DSECT 到 C 结构转换实用程序获得这些指针。
TSO 地址空间是 ASCBTSB 非零 (PSAAOLD->ASCBTSB) 的地址空间。批处理作业是填充 ASCBJBNI (PSAAOLD->ASCBJBNI) 的作业。CICS 地址空间的 TCBCAUF 设置为非零 (PSATOLD->TCBCAUF)。
在上述任何一个中,您还可以通过检查 TCB->STCB->STCBOTCB 来检查您的任务是否已被称为 UNIX 进程。如果不为零,则您已被配音并且可以使用 UNIX 服务。OTCBPRLI 字段具有进程信息,如 PID,而 THLI 字段具有线程级信息。
请注意,给定的任务可能有资格使用 USS 功能,但目前还没有。“querydub()”函数可以帮助您区分已配音的任务与可以配音但尚未配音的任务。
如果您使用 CEE3INF,有一些评论说它在 main() 函数之外无法正常工作,但我认为问题是 IBM 在其文档中提供的示例中的一个小错误。此示例在我的 z/OS 2.3 和 2.4 系统上运行良好:
#include <leawi.h>
#include <string.h>
#include <ceeedcct.h>
int do_call(void)
{
_INT4 sys_subsys,env_info,member_id,gpid;
_FEEDBACK fc;
CEE3INF(&sys_subsys,&env_info,&member_id,&gpid,&fc);
if ( _FBCHECK(fc,CEE000) != 0 )
{
printf("CEE3INF failed with message number %d\n", fc.tok_msgno);
}
printf("System/Subsystem in hex %08x \n",sys_subsys);
printf("Enviornment info in hex %08x \n",env_info);
printf("Member languages in hex %08x \n",member_id);
printf("GPID information in hex %08x \n",gpid);
printf("\n");
}
int main(void)
{
do_call();
}
Run Code Online (Sandbox Code Playgroud)
这是 IBM 手册中的示例代码,除了在调用 CEE3INF 时注意,IBM 文档有一个错误(“...fc”而不是“...&fc”)。有关于 CEE3INF 在 main() 之外调用时不起作用的评论,但我认为问题只是上面示例中的错误。
为了测试,我使用以下命令在 UNIX 服务 shell 下编译上面的代码:
xlc -o testinf testinf.c
Run Code Online (Sandbox Code Playgroud)
然后我从 z/OS shell 会话运行可执行文件:
> ./testinf
System/Subsystem in hex 02000002
Enviornment info in hex 00540000
Member languages in hex 10000000
GPID information in hex 04020300
Run Code Online (Sandbox Code Playgroud)
这是 z/OS 2.3 系统 - 我在 2.4 上得到相同的结果。
更新:“在 z/OS UNIX 服务环境中运行”是什么意思?
很容易理解批处理作业、TSO 会话和启动的任务,但“在 z/OS UNIX 服务环境中运行”是什么意思?在像 CICS、IMS 或 WebSphere 这样的子系统中,“在 xxx 下运行”很容易定义,因为事务在特殊类型的服务地址空间内运行……但不幸的是,UNIX 服务并非如此。
实际上,几乎所有在 z/OS 上运行的任务都可以使用 z/OS UNIX 服务,因此确实没有您可以以传统方式定义的“z/OS UNIX 服务环境”。并行将是 VSAM...是一个打开 VSAM 文件“在 VSAM 中运行?”的程序。我们可能会关心运行 IDCAMS 的程序、打开 VSAM 文件的程序、使用 CICS/VSAM 的程序——但是如果没有进一步的限定,“在 VSAM 中运行”并不是特别有意义。此外,“在 VSAM 中运行”并不仅限于以批处理、STC 或 TSO 用户身份运行——这与 z/OS UNIX 服务相同——您可以是批处理作业、启动任务或 TSO 用户,并且您还可以是否“在 z/OS UNIX 服务中运行”。
以下是“在 z/OS UNIX 服务中运行”的三个截然不同的定义:
为什么会有这些问题?好吧,一些软件——尤其是其他应用程序调用的运行时库函数之类的东西——根据调用者是否是 UNIX 进程而表现不同。
想象一下编写一个“OPEN”函数,该函数将文件名作为参数传递。如果您的调用方是 UNIX 进程,您可能会将文件名解释为实际文件名...OPEN(XYZ) 被解释为“检查当前工作目录中是否存在名为 'XYZ' 的文件”。但是如果调用者不被称为 UNIX 进程,那么 OPEN(XYZ) 可能意味着打开 'XYZ' DD 语句。您可以使用我上面概述的方法来做出这个决定,因为它告诉您您的任务实际上被称为 UNIX 进程。
好的,但是这个和上面的#2(在shell下运行)有什么不同?
这是一个例子。假设您有一个可调用的例程,想要将消息写入输出文件。大多数非大型机 UNIX 应用程序只会写入 STDOUT 或 STDERR,但这在 z/OS 上并不总是有效,因为许多应用程序是 UNIX 进程,但它们不在 shell 下运行 - 没有 shell、STDOUT 和 STDERR可能不存在。
这是场景...
您运行一个与 UNIX 服务无关的传统程序,但它做了一些事情,将自己称为 UNIX 进程。举个例子,也许有人把“DD PATH=/some/unix/file”放在一个古老的 COBOL 程序的 JCL 中……奇迹的是,当这个 COBOL 批处理作业运行时,它是一个 UNIX 进程,因为它利用了UNIX 服务文件系统。有很多事情可以让你的任务被称为 UNIX 进程......DD PATH 就是其中之一,但即使调用一个打开 TCP/IP 套接字的函数或类似的良性东西也可以做到这一点。也许您正在编写一个供应商产品,它只是一个批处理汇编程序,但它打开了一个 TCP/IP 套接字……这是另一个在没有外壳的情况下运行的 UNIX 进程的常见示例。
那么为什么这是一个问题呢?好吧,想想如果该可调用函数决定将其消息写入 STDERR 会发生什么。也许它会测试它是否作为 UNIX 服务进程运行,如果是,它会写入 STDERR,否则它会动态分配并写入 SYSOUT 文件。听起来很简单,但它不适用于我的具有 DD PATH 的应用程序示例。
STDERR 来自哪里?通常,UNIX shell 程序会设置它 - 当您在 shell 下运行程序时,shell 通常会为您的程序传递三个预打开的 STDIN、STDOUT 和 STDERR 文件句柄。由于我的示例场景中没有 shell,这些文件句柄没有传递给应用程序,因此写入 STDERR 将失败。实际上,除了 STDIN/STDOUT/STDERR 之外,shell 传递给子进程的还有很多东西,例如环境变量、信号处理等。(当然,用户可以在他的 JCL 中手动分配 STDIN/STDOUT/STDERR ......我不是在这里谈论这个)。
如果您想要拥有既可以在 shell 下运行又可以不在 shell 下运行的软件,那么您要做的不仅仅是查看您的应用程序是否被称为 UNIX 进程:
至于我的第三个例子——使用 POSIX(ON) 运行的 LE 程序——这对于使用基于 LE 运行时的高级语言编写的开发人员来说主要是一个问题,因为某些运行时函数的行为与 POSIX(ON) 或 POSIX 不同(离开)。
一个例子是 C 程序员编写的函数可以被 POSIX(ON) 和 POSIX(OFF) 调用者调用。假设函数想要在单独的线程下进行一些后台处理……在 POSIX(ON) 应用程序中,开发人员可能会使用 pthread_create(),但这在 POSIX(OFF) 中不起作用。IBM 的 LE 运行时中实际上有很多东西会根据 POSIX 设置而表现不同:线程、信号处理等。如果您希望编写“通用”代码并且需要这些功能,您肯定需要查询POSIX 设置在执行时并根据它的设置方式采用不同的路径。
所以希望这能揭示隐藏在这个问题背后的复杂性......“在 z/OS UNIX 环境中运行”的三个不同定义,以及三个不同的用例,说明为什么每个用例都很重要。