| From: VBORMC::"[email protected]" "Mats Nilsson" 9-APR-1997 08:19:29.08
To: "[email protected] - UK Software Partner Engineering 830-4121
08-Apr-1997 1519 +0100" <[email protected]>
CC:
Subj: POINT 25037, Nectar -vfork closing tables
Reply to the message of Tuesday April 8, 1997 17:15 +0100
-----------------------------------------------------------------
>>I wonder how vfork works ?
>>Are the open tables from the father also open in the child process ?
>I am not clear from the code extract above what you are doing. For
>example, since a call to vfork() will return zero, if you substitute
>"vfork" for "fork" in the above snippet of code, then "cc" will be
>zero, and you will execute the code that is commented "child process",
>even though you're still in the parent.
>Could you send me a program example which shows what your problem is?
My question is does the subprocess inherit the open files from the father=
?
Because we want to close them for the subprocess.
This is a bit of the same problem that I asked about in 23091.
In the example when we fork, for the subprocess we close all open files
with fildes greater than STDERR.
Regards
Mats
+----------------------------------------------+
! !
! oooooo ooooo Nectar Systems AB !
! ooooooo ooooo Mats Nilsson !
! oooooo ooo Development Manager !
! ooooooo ooo [email protected] !
! ooo oooo ooo Box 124 !
! ooo ooooooo S-281 22 H=E4ssleholm !
! ooooo oooooooo Tel. +46 (0)451 893 00 !
! ooooo ooooooo Fax. +46 (0)451 817 30 !
! !
! -For excellence in 4GL- !
! !
+----------------------- http://www.nectar.se -+
% ====== Internet headers and postmarks (see DECWRL::GATEWAY.DOC) ======
% Received: from mail.vbo.dec.com ([16.36.208.34]) by vbormc.vbo.dec.com
(8.7.3/8.7) with ESMTP id JAA19662 for <[email protected]>; Wed, 9 Apr
1997 09:12:30 +0200
% Received: from server21.digital.fr (server21.digital.fr [193.56.15.21]) by
mail.vbo.dec.com (8.7.3/8.7) with ESMTP id JAA17283 for
<[email protected]>; Wed, 9 Apr 1997 09:18:49 +0200 (MET DST)
% Received: from nectar (nectar.nectar.se [193.14.116.1]) by server21.digital.fr
(8.7.5/8.7) with SMTP id JAA25032 for <[email protected]>; Wed, 9 Apr
1997 09:23:50 +0200 (MET DST)
% Received: (from gmail@localhost) by nectar (8.6.12/8.6.12) id JAA16150 for
[email protected]; Wed, 9 Apr 1997 09:15:51 +0200
% Received: by gmail.nectar.se with Gmail (ginets/4.0.1) id 334b421e; Wed, 9 Apr
97 09:15:51 +010
% Date: Wed, 9 Apr 97 09:12:06 +0100
% Message-Id: <[email protected]>
% In-Reply-To: <[email protected]>
% From: Mats Nilsson <[email protected]>
% To: "[email protected] - UK Software Partner Engineering 830-4121
08-Apr-1997 1519 +0100" <[email protected]>
% Subject: POINT 25037, Nectar -vfork closing tables
% Mime-Version: 1.0
% Content-Type: text/plain; charset=ISO-8859-1
% Content-Transfer-Encoding: quoted-printable
|
| From: DEC:.REO.REOVTX::HUDSON "[email protected] - UK Software
Partner Engineering 830-4121" 9-APR-1997 15:17:59.11
To: nm%VBORMC::"[email protected]"
CC: HUDSON
Subj: RE: No.23091, and 25037, files and child processes
Hello Mats
I have done some investigation and hope I can now answer your questions.
There are a couple of things that are causing problems. Partly this is because
"vfork" doesn't work the same way on VMS as Unix, and partly this is because of
the bug in the C RTL which we've already mentioned.
To start with, following your question on whether a "close" in a child will
close the parent's files, you need to understand that vfork on VMS is different
from Unix. Section 5.2 in the DEC C RTL manual discusses this, but
essentially:
When you call "vfork", this does NOT create a child process. After vfork, you
are expected to call "execl" (or "execv", etc.), and it is the "execl" call
that creates the subprocess. So if you have:
status = vfork();
if (status == 0) {
/* I must be the child */
close(x);
}
if (status != 0) {
/* I must be the parent */
write(x,...)
}
Then the "close" you do is actually happening in the parent. The "status"
returned from the vfork() call should be used only to decide whether you call
execl() or not.
When the execl is called and the child program starts, then all the open file
descriptors from the parent are given to the child, and it should be able to
use them. But because of the C RTL problem, it can't use them in the case
where you are trying to do shared writes.
I have below a parent and child program which show what I mean. Also is an
annotated run from the program which I hope explains what's happening.
As I said, this is discussed in the C RTL manual. If there are things you
don't understand in the book or from what I include here please let me know and
I'll try to explain better.
Regards
Nick
/*
Program: Parent_fork.c
Description:
Program to test "UNIX" like system service routines for subprocesses
on VMS. Program uses VFORK, EXECL & WAIT:
EXECL passes the name of an image to be activated in a child process.
VFORK creates a duplicate process of the current process. It returns
the process ID of the child process to the parent; & returns 0 to
the child process, indicating successful creation of process
context.
*/
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <perror.h>
#include <processes.h>
#include <climsgdef> /* for CLI status values */
main()
{
int status, cstatus;
int logfile,textfile;
textfile = open("textfile.dat",O_RDONLY);
logfile = open("logfile.dat",(O_APPEND | O_RDWR | O_TRUNC | O_CREAT),
"shr=put,get","ctx=rec");
printf("fileno of logfile is %d\n",logfile);
printf("fileno of textfile is %d\n",textfile);
/* create independent child process */
status = vfork();
printf( "parent_fork: status from vfork = %d\n", status );
if (status == 0) {
write(logfile,"status from vfork was zero : child\n",36);
} else {
write(logfile,"status from vfork nonzero : parent\n",36);
}
/* check for failure (-1) */
if (status < 0)
{
printf( "parent_fork: Child process failed: status %d\n", status );
exit( status );
}
if (status > 0)
{
/* this piece of code is executed by parent process only */
printf( "parent_fork: waiting for Child (status = %d [0x%x])\n",
status, status );
/* call WAIT function to suspend parent process until child */
/* process exits: WAIT returns status from child process */
if ((status = wait( &cstatus )) == -1)
perror( "parent_fork: Wait failed" );
else
if (cstatus == CLI$_IMAGEFNF)
printf( "parent_fork: Child does not exist\n" );
else
printf( "parent_fork: Child final status: %d\n", cstatus );
exit(0);
}
/* ..else status from vfork must be 0 */
/* - so this is the new process */
/* we can close the logfile for the child now */
printf( "parent_fork: This is new forked process\n" );
/* call EXECL which passes name of image to be activated by child */
/*( rem: second parameter can be an argument list - set to NULL here */
if ((status = execl( "child_fork", 0 )) == -1)
{
perror( "parent_fork: (New Forked process) Execl failed\n" ), exit(0);
}
}
/* child_fork.c */
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
main()
{
int stat;
int textfile,logfile;
char buff[100] = "******************************************";
printf("Hello, this is child_fork, give me logfile number ?");
scanf("%d",&logfile);
printf("Give me textfile number ?");
scanf("%d",&textfile);
stat = read(textfile,buff,100);
printf("read from textfile returns %d\n",stat);
buff[stat] = 0;
printf("buffer is now -->%s<--\n",buff);
printf("write to logfile returns %d\n",write(logfile,"hello",6));
exit(1);
}
This session shows the programs being run. The steps numbered show:
1. To start with, there is no "logfile.dat" file
2. There is a "textfile.dat", containing three lines of text
When I run "parent_fork":
3. The call to "vfork" returns zero, which indicates that this is running a
child process. In fact though, this is still the parent process running.
So at this stage, all variables, files and so on that I touch will change
in the "parent" thread. For example, if I "close()" a file here, I'm
actually closing the parent's file descriptor.
4. The call to "vfork" returns a child-id. This indicates that the child has
been successfully created, by the call to "execl"
5. This is the actual child process now, running the "child_fork" program.
At this stage, the file descriptors for files that were opened by the
parent will have been set up in the child, so I should be able to access
those same files (as long as I know the file descriptor numbers). You
can see that I am able to read the textfile...
6. But I can't write to the logfile. This is because of the C RTL bug
7. When the child terminates, the parent realises and also finishes
8. Looking in the logfile, you can see output which was written by both
paths from the "vfork". But these are both written by the parent, since
the child doesn't really appear until after the "execl"
$ cc parent_fork/pref=all
$ link parent_fork
$ cc child_fork/pref=all
$ link child_fork
$!done
1. $ ty logfile.dat
%TYPE-W-SEARCHFAIL, error searching for
SYS$SYSDEVICE:[HUDSON.ASAP.VFORK]LOGFILE.DAT;
-RMS-E-FNF, file not found
2. $ ty textfile.dat
this is textfile.dat
line 2
line 3
$ r parent_fork
fileno of logfile is 4
fileno of textfile is 3
3. parent_fork: status from vfork = 0
parent_fork: This is new forked process
4. parent_fork: status from vfork = 692
parent_fork: waiting for Child (status = 692 [0x2b4])
5. Hello, this is child_fork, give me logfile number ? 4
Give me textfile number ? 3
read from textfile returns 21
buffer is now -->this is textfile.dat
<--
6. write to logfile returns -1
7. parent_fork: Child final status: 1
8. $ type logfile.dat
status from vfork was zero : child
status from vfork nonzero : parent
$
|
| From: VBORMC::"[email protected]" "Mats Nilsson" 10-APR-1997 07:19:54.84
To: "[email protected] - UK Software Partner Engineering 830-4121
09-Apr-1997 1517 +0100" <[email protected]>
CC:
Subj: RE: No.23091, and 25037, files and child processes
Reply to the message of Wednesday April 9, 1997 17:13 +0100
-----------------------------------------------------------------
Hello Nick
Thank you for your answer.
I understand how vfork works and the C rtl problem, but I have some more
questions.
1. If I add keyword "ctx=3Drec" to my open statement now afterwards, when
the files are already created, without this keyword, I get and errorcode
from open.
Questions:
-What does "ctx=3Drec" really mean ?
-Shall I use this keyword to open, to solv the the problem to share files
beetween processes, as I described eariler ?
-Will it be another type of file if I use this keyword to open, and is
that why I get an error from open, or why do I get this error from open
when I add this keyword ?
-Do I have to recreate the files with this keyword to avoid the error ?
As I showed in my earier example, when we closing all files in the
childprocess, and we can not do this in VMS, and all open files are
inherited by the childprocess and new files opened by th child.
Question:
What does this this affect the resources of VMS, if each user starts a
chain of up to six seven processes as every new processes in the chain
gets more and more files opened ?
Thanks
Mats
+----------------------------------------------+
! !
! oooooo ooooo Nectar Systems AB !
! ooooooo ooooo Mats Nilsson !
! oooooo ooo Development Manager !
! ooooooo ooo [email protected] !
! ooo oooo ooo Box 124 !
! ooo ooooooo S-281 22 H=E4ssleholm !
! ooooo oooooooo Tel. +46 (0)451 893 00 !
! ooooo ooooooo Fax. +46 (0)451 817 30 !
! !
! -For excellence in 4GL- !
! !
+----------------------- http://www.nectar.se -+
% ====== Internet headers and postmarks (see DECWRL::GATEWAY.DOC) ======
% Received: from mail.vbo.dec.com (mail.vbo.dec.com [16.36.208.34]) by
vbormc.vbo.dec.com (8.7.3/8.7) with ESMTP id HAA12707 for
<[email protected]>; Thu, 10 Apr 1997 07:47:46 +0200
% Received: from server21.digital.fr (server21.digital.fr [193.56.15.21]) by
mail.vbo.dec.com (8.7.3/8.7) with ESMTP id HAA06355 for
<[email protected]>; Thu, 10 Apr 1997 07:54:31 +0200 (MET DST)
% Received: from nectar (nectar.nectar.se [193.14.116.1]) by server21.digital.fr
(8.7.5/8.7) with SMTP id HAA16507 for <[email protected]>; Thu, 10 Apr
1997 07:59:34 +0200 (MET DST)
% Received: (from gmail@localhost) by nectar (8.6.12/8.6.12) id HAA20930 for
[email protected]; Thu, 10 Apr 1997 07:51:39 +0200
% Received: by gmail.nectar.se with Gmail (ginets/4.0.1) id 334c7fdf; Thu, 10
Apr 97 07:51:39 +010
% Date: Thu, 10 Apr 97 07:47:46 +0100
% Message-Id: <[email protected]>
% In-Reply-To: <[email protected]>
% From: Mats Nilsson <[email protected]>
% To: "[email protected] - UK Software Partner Engineering 830-4121
09-Apr-1997 1517 +0100" <[email protected]>
% Subject: RE: No.23091, and 25037, files and child processes
% Mime-Version: 1.0
% Content-Type: text/plain; charset=ISO-8859-1
% Content-Transfer-Encoding: quoted-printable
|
| From: DEC:.REO.REOVTX::HUDSON "[email protected] - UK Software
Partner Engineering 830-4121" 10-APR-1997 11:10:16.21
To: nm%VBORMC::"[email protected]"
CC: HUDSON
Subj: RE: No.23091, and 25037, files and child processes
Hello Mats
Here is some more info. I think the whole thing may just boil down to the fact
that VMS is fundamentally different in several ways to Unix, and so while DEC C
and the C RTL do their best to give you an environment similar to the Unix one,
there are inevitably compromises and situations where you can't get identical
behaviour.
If you really need full control over file-sharing, then the best way is to use
pure RMS calls, but obviously this is VMS specific and will make your code
non-portable to Unix.
>1. If I add keyword "ctx=rec" to my open statement now afterwards, when
>the files are already created, without this keyword, I get and errorcode
>from open.
You don't say what the error is. Maybe "errno" would give you more info.
>Questions:
>
>-What does "ctx=rec" really mean ?
>
This is a big question to answer. Basically, the RMS file system that is used
by VMS is a RECORD management system, which doesn't fit very well to the model
used by Unix, where a file is a stream of bytes, not a series of records.
On VMS, the C RTL tries to give an approximation to Unix I/O by using a form
of RMS file called "Stream files". If you create a file from a C program and
then do a "DIR/FULL" of it, you should see that the file format is some type
of "STREAM" format.
A limitation of stream format files is that certain RMS file sharing options
don't work. RMS allows multiple users to share files by using locks, and
locks are done on a record-by-record basis. Since stream files don't really
have records, then locking can't be done like that by RMS, and so it won't let
you have many people writing to the same file at once - the first person to
open a stream file for writing will get exclusive access.
In order to be able to share files in this case, you therefore need to stop
the C RTL from using "stream" format. This is what "ctx=rec" is for. If you
look in the C RTL manual under the description of "creat()", which talks about
all the RMS options, it says:
Notes
- While these options provide much flexibility and
functionality, many of them can also cause severe
problems if not used correctly.
- You cannot share the default DEC C for
OpenVMS stream file I/O. If you wish to share
files, you must specify "ctx=rec" to force record
access mode. You must also specify the appropriate
"shr" options depending on the type of access you
want.
So "ctx=rec" is a special flag to the C RTL to say "don't use stream, use
record format". If you create a file with this flag and do a DIR/FULL, I'd
expect you won't see "file format:stream", you'll see "variable length, max xx
bytes" or something like that.
Because you have told the C RTL to use record format, then the "shr" options
you use will take effect.
>-Shall I use this keyword to open, to solv the the problem to share files
>beetween processes, as I described eariler ?
>-Will it be another type of file if I use this keyword to open, and is
>that why I get an error from open, or why do I get this error from open
>when I add this keyword ?
>-Do I have to recreate the files with this keyword to avoid the error ?
Don't know the answer to this, it depends what the error is. Basically if you
want to share write access, then you won't be able to do it unless you have
"ctx=rec" and "shr=....". But if you do that then there are still limitations
on what RMS will let you do.
>As I showed in my earier example, when we closing all files in the
>childprocess, and we can not do this in VMS, and all open files are
>inherited by the childprocess and new files opened by th child.
>
>Question:
>
>What does this this affect the resources of VMS, if each user starts a
>chain of up to six seven processes as every new processes in the chain
>gets more and more files opened ?
If your parent has several open files, then does vfork/exec to create a
subprocess which runs a different program, then as we have seen, that
subprocess should have the same filenumbers open that were in the parent.
At this stage, the subprocess could do a "for (i=3;i<NFILE;i++) {close(i)};"
type thing I suppose.
As far as resources go, then every time you have a file open, you use up 1 of
your "FILLM" limit ("Open File Quota" in SHOW PROC/QUOTA), and at least 96 of
your "BYTLM" ("Buffered I/O byte count quota"). This info comes from the
OpenVMS System Manager's manual.
Both "FILLM" and "BYTLM" are "pooled" quotas. That means that the quota
applies to all the processes and subprocesses in a tree. So if you have a
FILLM of 100, and you open 50 files then create a subprocess, the subprocess
won't be able to open more than 50 more files (and if it did, then the parent
wouldn't be able to open any more new ones).
So if you have a parent which has files open, and then creates a child which
creates a child,... then you could quickly use up FILLM I suppose.
FILLM and BYTLM are quotas which you can set as high as you like, like a disk
quota. Having a high quota doesn't take up resources, but it means that a
user has the potential to use up resources.
As well as FILLM and BYTLM, which are quotas set in the AUTHORIZE utility, any
one process can't open more files than is specified by the SYSGEN parameter
CHANNELCNT.
Normally FILLM will be around 100, and CHANNELCNT is 127, so it is very
unusual to hit CHANNELCNT.
Does this help?
Regards
nick
|