I am submitting a JCL job to allocate a VB dataset in Mainframe. After submitting the job, the dataset gets created successfully.
Then I am running a java program in omvs region of mainframe, to open the file and write some contents into it. When I try to write the data into the file I am getting the below error.
//DD:SYS00011 : fwrite() failed. EDC5024I An attempt was made to close a file that had been opened by another thread.; errno=24 errno2=0xc0640021 last_op=0 errorCode=0x0.
JCL submitted to allocate the dataset:
//USERNAME JOB ABC,,NOTIFY=&SYSUID,CLASS=F,MSGLEVEL=(1,1),MSGCLASS=X
//STEP1 EXEC PGM=IEFBR14
//STEP DD DSN=ASD00T.SM.ULRL,
// DISP=(NEW,CATLG,DELETE),
// UNIT=SYSDA,SPACE=(1,(10,60),RLSE),AVGREC=M,
// DCB=(RECFM=VB),
// DSORG=PS
code to write the file:
zFileIn = new ZFile("//'ASD00T.INPUT.ULRL'", "rb,type=record,noseek");
if (zFileIn.getDsorg() != ZFile.DSORG_PS) {
throw new IllegalStateException("Input dataset must be DSORG=PS");
}
zFileOut = new ZFile("//'ASD00T.SM.ULRL'", "wb,type=record,noseek, recfm="+ zFileIn.getRecfm()+ ", lrecl="+ zFileIn.getLrecl());
long count = 0;
byte[] recBuf = new byte[zFileIn.getLrecl()];
int nRead;
while((nRead = zFileIn.read(recBuf)) >= 0) {
zFileOut.write(recBuf, 0, nRead);
count++;
}
The heart of your problem is that you need to invoke the ZFile.close() method after you're done writing. Doing so will guarantee that the open, writes and close all happen under the same thread and you should be fine. This is a side-effect of using conventional datasets instead of USS files.
The reason for this is complicated, but it has to do with the fact that in z/OS, "conventional" QSAM/BSAM/VSAM datasets behave slightly differently than do UNIX filesystem files.
If you were writing to a UNIX file (HFS, ZFS, NFS, etc) instead of a conventional dataset, what you're doing would work perfectly fine...this is because USS treats resource ownership differently - file handles are owned at a process level, not a thread. When you open a USS file, that file handle can be used or closed by any thread in the process...this is mandated by the various UNIX standards, so z/OS has no choice but to work this way.
Conventional datasets are a bit different. When you open a conventional dataset, the operating system structures that define the open file are stored in memory anchored to the thread where the file was opened. There's enough information in the file handle that you can do I/O from other threads, but closing the file needs to happen from the thread where the file was opened.
Now, since you don't seem to have a close() in your code, the file stays open until your Java thread ends. When your Java thread ends, the system runtime gets control in order to clean up any resources you might have allocated. It sees the lingering open file and tries to close it, but now it's not running under the thread that opened the file, so you get the failure you're seeing.
Normally, UNIX files and z/OS datasets work almost exactly the same, but this issue is one of the slight differences. IBM gets away with it from a standards compliance perspective since z/OS datasets aren't part of any standard, and generally, the way they can be used interchangeably is a great feature.
By the way, all of this is spelled out in the fine print of the LE (Language Environment) and C Runtime references.