![]() Chapter Contents |
![]() Previous |
![]() Next |
SAS/C Software: Changes and Enhancements, Release 6.50 |
This section describes the new library
functions available to Release 6.50 SAS/C users under OpenEdition.
#include <sys/resource.h> int chpriority(int kind, id_t id, int form, int prio);
chpriority
function changes the OpenEdition priority of a process, or of all processes in a process group or belonging to a user. See the
getpriority
function description in section getpriority for further information on OpenEdition
priorities.
The
kind
argument to
chpriority
should be specified as a symbolic constant indicating the scope of the priority change. The permissible values
are:
PRIO_PROCESS
- Specifies that the
id
argument is the pid of the process whose priority is to be changed.
PRIO_PGRP
- Specifies that the
id
argument is the pid of the process group whose processes should be changed in priority.
PRIO_USER
- Specifies that the
id
argument is the uid of the user whose processes are to be changed in priority.
The
id
argument specifies the process id, process group id, or user id whose priority should be changed. If
id
is 0, the calling process id, process group id, or user id is specified.
The
form
argument specifies whether the
prio
argument is an absolute or relative priority. It should be specified as one of the following symbolic
constants:
CPRIO_ABSOLUTE
- Specifies that
prio
is to be the new priority of the processes specified.
CPRIO_RELATIVE
- Specifies that
prio
is the amount which should be added to the existing priority of each process specified.
The
prio
argument specifies the requested new priority, or the amount by which the priority should be changed, depending of the value of the
form
argument. Priorities are restricted to the range of -20 to 19, where lower numbers indicate higher priority.
Note: OpenEdition sites
must enable the use of the
chpriority
function. If the use of
chpriority
has not been enabled, any use of
chpriority
will fail with errno set to
ENOSYS
.
chpriority
returns
0
if successful, or
-1
if unsuccessful.chpriority
function can only be used with MVS 5.2.2 or a later release.sascc370 -Krent -o
. This program demonstrates the use of the Open Edition process priority functions
chpriority()
,
getpriority()
, and
setpriority()
.
/*---------------------------+ | POSIX/UNIX header files | +----------------------------*/ #include <unistd.h> #include <sys/types.h> #include <errno.h> /*---------------------------+ | ISO/ANSI header files | +----------------------------*/ #include <stdlib.h> #include <stdio.h> #include <errno.h> /*---------------------------+ | Name: main | | Returns: exit(EXIT_SUCCESS)| | or exit(EXIT_FAILURE) | +----------------------------| +---------------------------*/ int main() { /* generic return code */ int rc; /* which kind of process */ /* id to use */ int kind; /* process id */ id_t id; /* is oeprty relative or */ /* absolute */ int form; /* process priority */ /* (version 1) */ int prty1; /* process priority */ /* (version 2) */ int prty2; /* process id from getpid() */ pid_t pid; /* process group id from */ /* getpgid() */ pid_t pgid; /* process user id from */ */ getuid() */ uid_t uid; /* get the user id for this */ /* process */ uid = getuid(); /* get the process id for */ /* this process */ pid = getpid(); /* get the group process id */ /* for this process */ pgid = getpgid(pid); if (pgid == -1) { perror("Call to getpgid failed"); exit(EXIT_FAILURE); } printf(" The process id: %d\n", (int)pid); printf("The process group id: %d\n", (int)pgid); printf(" The process user id: %d\n", (int)uid); /*------------------------------*/ /* Get the process priority */ /* using the process id */ /*------------------------------*/ print ("\nGet the Process Priority using the Process ID\n"); /* the id arg is the pid of a process */ kind = PRIO_PROCESS; /* version 1 */ id = (id_t)pid; /* Set errno to zero for */ /* error handling */ errno = 0; prty1 = getpriority(kind, id); /* ---------------------------------*/ /* Test for Error */ /* Note: */ /* getpriority() may return a '-1' */ /* return code for either a */ /* failure rc, or when the priority */ /* is in-fact '-1'. To distinguish */ /* between the two conditions, */ /* check the errno */ /* value for a non-zero value. */ /*----------------------------------*/ if (prty1 == -1 && errno != 0) { perror("Call to getpriority failed"); exit(EXIT_FAILURE); } else { printf("The process priority (pid:version 1): %d\n", prty1); } /* version 2 */ /* 0 implies current processs id */ id = (id_t)0; /* Reset errno to zero for */ /* error handling */ errno = 0; prty2 = getpriority(kind, id); /* Test for Error */ if (prty2 == -1 && errno != 0) { perror("Call to getpriority failed"); exit(EXIT_FAILURE); } else { printf("The process priority (pid:version 2): %d\n", prty2); } /*-----------------------------*/ /* Get the process priority */ /* using the group process id */ /*-----------------------------*/ printf("\nGet the Process Priority using the Group Process ID\n"); /* the id arg is the group process id */ kind = PRIO_PGRP; /* version 1 */ id = (id_t)pgid; /* Set errno to zero for error handling */ errno = 0; prty1 = getpriority(kind, id); /* Test for Error */ if (prty1 == -1 && errno != 0) { perror("Call to getpriority failed"); exit(EXIT_FAILURE); } else { printf("The process priority (gpid:version 1): %d\n", prty1); } /* version 2 */ /* 0 implies current group processs id */ id = (id_t)0; /* Reset errno to zero for error handling */ errno = 0; prty2 = getpriority(kind, id); /* Test for Error */ if (prty2 == -1 && errno != 0) { perror("Call to getpriority failed"); exit(EXIT_FAILURE); } else { printf("The process priority (gpid:version 2): %d\n", prty2); } /*-------------------------------------------*/ /* Get the process priority using the */ /* process User id */ /*-------------------------------------------*/ print ("\nGet the Process Priority of the User ID\n"); /* the id arg is the user id of the process */ kind = PRIO_USER; /* version 1 */ id = (id_t)uid; /* Set errno to zero for error handling */ errno = 0; prty1 = getpriority(kind, id); /* Test for Error */ if (prty1 == -1 && errno != 0) { perror("Call to getpriority failed"); exit(EXIT_FAILURE); } else { printf("The process priority (uid:version 2): %d\n", prty1); } /* version 2 */ /* Reset errno to zero for error handling */ errno = 0; /* 0 implies current process user id */ id = (id_t)0; prty2 = getpriority(kind, id); /* Test for Error */ if (prty2 == -1 && errno != 0) { perror("Call to getpriority failed"); exit(EXIT_FAILURE); } else { printf("The process priority (uid:version 2): %d\n", prty2); } /*-----------------------------------------------*/ /* Set the process priority using the */ /* process id */ /*----------------------------------------------*/ printf ("\nSet the Process Priority using the Process ID\n"); /* the id arg is the pid of a process */ kind = PRIO_PROCESS; /* an id of 0 implies current processs id */ id = (id_t)0; /* Reset errno to zero for error handling */ errno = 0; /* Set process priority to 5 */ prty1 = 5; rc = setpriority(kind, id, prty1); /*---------------------------------------------*/ /* Test for Error */ /* Note: OpenEdition sites must enable the use */ /* of the setpriority() function. If the */ /* use of setpriority() has not been */ /* enabled, any use of setpriority() */ /* will fail with errno set to ENOSYS. */ /* */ /*---------------------------------------------*/ if (rc == -1) { perror("Call to setpriority failed"); exit(EXIT_FAILURE); } else { prty2 = getpriority(kind, id); /* Test for Error */ if (errno != 0) { perror("Call to getpriority failed"); exit(EXIT_FAILURE); } printf("The process priority is now (pid): %d\n", prty2); } /*--------------------------------------------*/ /* Set the process priority using the group */ /* process id */ /*--------------------------------------------*/ printf ("\nSet the Process Priority using the Group Process ID\n"); /* the id arg is the group id of the process */ kind = PRIO_PGRP; /* 0 implies current group processs id */ id = (id_t)0; /* Reset errno to zero for error handling */ errno = 0; /* Set process priority to 10 */ prty1 = 10; rc = setpriority(kind, id, prty1); /* Test for Error */ if (rc == -1) { perror("Call to setpriority failed"); exit(EXIT_FAILURE); } else { prty2 = getpriority(kind, id); /* Test for Error */ if (errno != 0) { perror("Call to getpriority failed"); exit(EXIT_FAILURE); } printf("The process priority is now (gpid): %d\n", prty2); } /*-------------------------------------------*/ /* Set the process priority using the */ /*process User id */ /*-------------------------------------------*/ printf ("\nSet the Process Priority of the User ID\n"); /* the id arg is the user id of the process */ kind = PRIO_USER; /* an id of 0 implies current user id */ id = (id_t)0; /* Reset errno to zero for error handling */ errno = 0; /* Set process priority to 15 */ prty1 = 15; rc = setpriority(kind, id, prty1); /* Test for Error */ if (rc == -1) { perror("Call to setpriority failed"); exit(EXIT_FAILURE); } else { prty2 = getpriority(kind, id); /* Test for Error */ if (errno != 0) { perror("Call to getpriority failed"); exit(EXIT_FAILURE); } printf ("The process priority is now (uid): %d\n", prty2); } /*-------------------------------------------*/ /* Change the process priority using the */ /* process id */ /*-------------------------------------------*/ printf ("\nChange the Process Priority using the Process ID\n"); /* the id arg is the pid of a process */ kind = PRIO_PROCESS; /* an id of 0 implies current processs id */ id = (id_t)0; /* Reset errno to zero for error handling */ errno = 0; /* change using "absolute" */ /* priority - equivalent to setpriority() */ form = CPRIO_ABSOLUTE; printf("\tChange using CPRIO_ABSOLUTE\n"); /* Change process priority to 3 */ prty1 = 3; rc = chpriority(kind, id, form, prty1); /*------------------------------------------------*/ /* Test for Error */ /* Note: OpenEdition sites must enable the use */ /* of the chpriority() function. */ /* If the use of chpriority() has not been */ /* enabled, any use of chpriority() will */ /* fail with errno set to ENOSYS. */ /* */ /*------------------------------------------------*/ if (rc == -1) { perror("Call to chpriority failed"); exit(EXIT_FAILURE); } else { prty2 = getpriority(kind, id); /* Test for Error */ if (errno != 0) { perror("Call to getpriority failed"); exit(EXIT_FAILURE); } printf ("The process priority is now (pid): %d\n", prty2); } /* change using "relative" priority */ form = CPRIO_RELATIVE; printf("\tChange using CPRIO_RELATIVE\n"); /* Bump process priority up by 2 */ prty1 = 2; rc = chpriority(kind, id, form, prty1); /* Test for Error */ if (rc == -1) { perror("Call to chpriority failed"); exit(EXIT_FAILURE); } else { prty2 = getpriority(kind, id); /* Test for Error */ if (errno != 0) { perror("Call to getpriority failed"); exit(EXIT_FAILURE); } printf("The process priority is now (pid): %d\n", prty2); } /*---------------------------------------------*/ /* Change the process priority using the */ /* group process id */ /*---------------------------------------------*/ printf ("\nChange the Process Priority using the Group Process ID\n"); /* the id arg is the group id of the process */ kind = PRIO_PGRP; /* 0 implies current group processs id */ id = (id_t)0; /* Reset errno to zero for error handling */ errno = 0; /* change using "absolute" */ /* priority - equivalent to setpriority() */ form = CPRIO_ABSOLUTE; printf("\tChange using CPRIO_ABSOLUTE\n"); /* Change process priority to 7 */ prty1 = 7; rc = chpriority(kind, id, form, prty1); /* Test for Error */ if (rc == -1) { perror("Call to chpriority failed"); exit(EXIT_FAILURE); } else { prty2 = getpriority(kind, id); /* Test for Error */ if (errno != 0) { perror("Call to getpriority failed"); exit(EXIT_FAILURE); } printf ("The process priority is now (gpid): %d\n", prty2); } /* change using "relative" priority */ form = CPRIO_RELATIVE; printf("\tChange using CPRIO_RELATIVE\n"); /* Bump process priority up by 3 */ prty1 = 3; rc = chpriority(kind, id, form, prty1); /* Test for Error */ if (rc == -1) { perror("Call to chpriority failed"); exit(EXIT_FAILURE); } else { prty2 = getpriority(kind, id); /* Test for Error */ if (errno != 0) { perror("Call to getpriority failed"); exit(EXIT_FAILURE); } printf("The process priority is now (gpid): %d\n", prty2); } /*--------------------------------------*/ /* Change the process priority using */ /* the process User id */ /*--------------------------------------*/ printf ("\nChange the Process Priority of the User ID\n"); /* the id arg is the user id of the process */ kind = PRIO_USER; /* 0 implies current group processs id */ id = (id_t)0; /* Reset errno to zero for error handling */ errno = 0; /* change using "absolute" */ /* priority - equivalent to setpriority() */ form = CPRIO_ABSOLUTE; printf("\tChange using CPRIO_ABSOLUTE\n"); /* Change process priority to 11 */ prty1 = 11; rc = chpriority(kind, id, form, prty1); /* Test for Error */ if (rc == -1) { perror("Call to chpriority failed"); exit(EXIT_FAILURE); } else { prty2 = getpriority(kind, id); /* Test for Error */ if (errno != 0) { perror("Call to getpriority failed"); exit(EXIT_FAILURE); } printf("The process priority is now (uid): %d\n", prty2); } /* change using "relative" priority */ form = CPRIO_RELATIVE; printf("\tChange using CPRIO_RELATIVE\n"); /* Bump process priority up by 4 */ prty1 = 4; rc = chpriority(kind, id, form, prty1); /* Test for Error */ if (rc == -1) { perror("Call to chpriority failed"); exit(EXIT_FAILURE); } else { prty2 = getpriority(kind, id); /* Test for Error */ if (errno != 0) { perror("Call to getpriority failed"); exit(EXIT_FAILURE); } printf("The process priority is now (uid): %d\n", prty2); } exit(EXIT_SUCCESS); } /* end of main() */
getpriority
,
setpriority
#include <sys/types.h> #include <grp.h> void endgrent(void);
endgrent
function closes the OpenEdition group database once the
getgrent
function is complete. If
getgrent
is called after a call to
endgrent
, the database will be opened once again, and information about the first group returned.endgrent
has no return value.endgrent
function can only be used with MVS 5.2.2 or a later release.
If the
endgrent
function cannot be executed (for instance, because OpenEdition is not installed or running), it issues an MVS user
ABEND 1230
to indicate the error.
getgrent
,
setgrent
#include <sys/types.h> #include <pwd.h> void endpwent(void);
endpwent
function closes the OpenEdition user database once the
getpwent
function is complete. If
getpwent
is called after a call to
endpwent
, the database will be opened once again, and information about the first user returned.endpwent
has no return value.endpwent
function can only be used with MVS 5.2.2 or a later release.
If the
endpwent
function cannot be executed (for instance, because OpenEdition is not installed or running), it issues an MVS user
ABEND 1230
to indicate the error.
getpwent
,
setpwent
#include <unistd.h> int extlink(const char *ename, const char *lname);
extlink
functions creates a link from the OpenEdition hierachical file system to an external (non-HFS) file. The argument
ename
is the name of the external file, and
lname
specifies the name of the link.
lname
must specify the name of an HFS file. For programs not compiled with the
option, style prefixes may be required. The external name,posix
ename
, must not specify a style prefix. See "File Naming Conventions" in the SAS/C Library Reference, Volume 1, for further
information.
Note: External links are not transparent, similar to other OpenEdition symbolic links. That is, opening or unlinking an external link will not open or delete the referenced
external file. External links are used by IBM's NFS implementation and can be used by other applications, but are not handled automatically by either OpenEdition or the SAS/C library. The contents of
an external link can be accessed using the
readextlink
function.
Note: An external link resembles a symbolic link, and that
S_ISLNK(s->st_mode)
will be true when
s
is the value stored by the
lstat
function for an external link. You can distinguish external links from other links using
S_ISEXTL(s->st_mode, s->st_genvalue)
, which will be non-zero only for an external
link.
extlink
returns
0
if successful, or
-1
if unsuccessful.lstat
,
readextlink
Access group database sequentially
#include <sys/types.h> #include <grp.h> struct group *getgrent(void);
getgrent
function is used to read the system database that defines all OpenEdition groups. The first call to
getgrent
returns the first defined group, and each successive call returns information about the next group in the database. After information about
the last group is obtained,
getgrent
returns
0
to indicate the end of file. When
0
is returned, the file position is reset, so that the next call to
getgrent
will retrieve the first database entry.
Note: It is more efficient to use the
getgrgid
or
getgrnam
function to obtain information about a specific group, rather than a loop calling
getgrent
.
getgrent
is provided mainly as an aid to porting existing UNIX programs that use it.
getgrent
returns a pointer to a
struct group
if successful, and the end of the group database has not been reached.
getgrent
returns
0
if the end of the database has been reached, or if an error condition occurred. See the function description for
getgrgid
in the "
posix
Function Reference" section of the SAS/C Library Reference, Volume 2 for more information about the definition of
struct group
.
Note: The pointer returned by
getgrent
may be a static data area that can be rewritten by the next call to
getgrent
,
getgrgid
or
getgrnam
.
getgrent
function can only be used with MVS 5.2.2 or a later release.endgrent
,
getgrgid
,
getgrnam
,
setgrent
#include <sys/time.h> int getitimer(int kind, struct itimerval *val);
getitimer
function returns information about an active interval timer. (See the
setitimer
function in section setitimer for more information about interval
timers.)
The
kind
argument is a symbolic constant that specifies the type of time interval for which information is wanted. The permitted values
are:
ITIMER_REAL
- Specifies a real time interval. Each time the interval expires, a SIGALRM signal is generated.
ITIMER_VIRTUAL
- Specifies a virtual (CPU) time interval. Each time the interval expires, a SIGVTALRM signal is
generated.
ITIMER_PROF
- Specifies a profiling interval, measuring CPU time plus system time used in behalf of this process. Each time the interval expires,
a SIGPROF signal is generated.
The
val
argument is a pointer to an
itimerval
structure in which information about the current interval timer should be stored. See the
setitimer
function description for more information on the contents of a
struct itimerval
.
getitimer
returns
0
if successful, or
-1
if unsuccessful.getitimer
function can only be used with MVS 5.2.2 or a later release. setitimer
Get Process Group Id for a Process
#include <sys/types.h> #include <unistd.h> pid_t getpgid(pid_t pid);
getpgid
function returns the process group id for a specific process id. The argument
pid
should be the id of the process, or
0
to request the process group id for the current process.getpgid
returns the process group id, or
-1
if it fails.getpgid
function can only be used with MVS 5.2.2 or a later release.sascc370 -Krent -o
.
/*------------------------------------+ | POSIX/UNIX header files | +-------------------------------------*/ #include <unistd.h> #include <sys/types.h> /*------------------------------------+ | ISO/ANSI header files | +-------------------------------------*/ #include <stdlib.h> #include <stdio.h> #include <errno.h> /*------------------------------------+ | Name: main | | Returns: exit(EXIT_SUCCESS) or | exit(EXIT_FAILURE) | +-------------------------------------* int main() { /* current process id from getpid() */ pid_t pid; /* process group id from getpgid() */ pid_t pgid; /*------------------------------------------*/ /* Get the group process id of the current */ /* process */ /* Note: Both version 1 and version 2 are */ /* equivalent to calling the */ /*. getpgrp() function */ /*------------------------------------------*/ printf ("\nGet the Group Process ID of the Current Process\n"); /* version 1 */ /* Set errno to zero for error handling */ errno = 0; /* get the process id for this process */ pid = getpid(); /* get the group process id for this process */ pgid = getpgid(pid); /* Test for Error */ if (pgid == -1) { perror("Call to getpgid failed"); exit(EXIT_FAILURE); } else { printf (" The process id: %d\n", (int)pid); printf("The process group id:%d\n", (int)pgid); } /* version 2 */ /* Reset errno to zero for error handling */ errno = 0; /* 0 implies current processs id */ pid = 0; /* get the group process id for this process */ pgid = getpgid(pid); /* Test for Error */ if (pgid == -1) { perror("Call to getpgid failed"); exit(EXIT_FAILURE); } else { printf ("The process group id: %d\n", (int)pgid); } exit(EXIT_SUCCESS); } /* end of main() */
getpgrp
,
setpgid
#include <sys/resource.h> int getpriority(int kind, int id);
getpriority
function obtains the OpenEdition priority of a process, a process group or a user. The priority is an integer between -20 and 19 which is
used in scheduling process execution. Lower priority numbers are considered more urgent. These priority numbers are translated by OpenEdition in a site-specific manner into MVS SRM (system resources
manager) specifications that control the priority of both OpenEdition and non-OpenEdition MVS
processing. See the IBM Publication OpenEdition MVS Planning (SC23-3015) for more information on OpenEdition priorities and their interpretation.
The
kind
argument to
getpriority
should be specified as a symbolic constant indicating what kind of priority information is needed. The permissible values
are:
PRIO_PROCESS
- Specifies that the
id
argument is the pid of the process whose priority is wanted.
PRIO_PGRP
- Specifies that the
id
argument is the pid of the process group whose priority is wanted.
PRIO_USER
- Specifies that the
id
argument is the uid of the user whose priority is wanted.
The
id
argument specifies the process id, process group id, or user id whose priority is needed. If
id
is
0
, the calling process id, process group id, or user is indicated.
If there is more than one process running that matches the arguments, for instance, multiple processes for a specified user, the smallest priority value for any process is returned.
getpriority
returns the requested priority if successful, or
-1
if unsuccessful. Since
-1
can also be returned as a priority value, you should set
errno
to
0
before calling
getpriority
,
and test it for a non-zero value after the call to determine whether an error occurred.getpriority
function can only be used with MVS 5.2.2 or a later release.chpriority
,
getpriority
, and
setpriority
.chpriority
,
setpriority
Access user database sequentially
#include <sys/types.h> #include <pwd.h> struct passwd *getpwent(void);
getpwent
function is used to read the system database defining all OpenEdition users. The first call to
getpwent
returns the first defined user, and each successive call returns information about the next user in the database. After information about the
last user is obtained,
getpwent
returns
0
to indicate the end of file. When
0
is returned, the file position is reset, so that the next call to
getpwent
will retrieve the first database entry.
Note: It is more efficient to use the
getpwuid
or
getpwnam
function to obtain information about a specific user, rather than a loop calling
getpwent
.
getpwent
is provided mainly as an aid to porting existing UNIX programs that use it.
getpwent
returns a pointer to a
struct passwd
if successful, and the end of the user database has not been reached.
getpwent
returns
0
if the end of the database has been reached, or if an error condition occurred. See the function description for
getpwuid
in the "
posix
Function Reference" section of the SAS/C Library Reference, Volume 2 for more information about the definition of
struct passwd
.
Note: The pointer returned by
getpwent
may be a static data area that can be rewritten by the next call to
getpwent
,
getpwuid
or
getpwnam
.
getpwent
function can only be used with MVS 5.2.2 or a later release.endpwent
,
getpwnam
,
getpwuid
,
setpwent
Obtain OpenEdition resource limits
#include <sys/resource.h> int getrlimit(int resource, struct rlimit *info);
getrlimit
function determines the resource limits for the calling process. The limits are expressed as a pair of integers, a soft limit and a hard
limit. The soft limit controls the amount of the resource the program is actually allowed to consume, while the hard limit specifies an upper bound on the soft limit. The soft limit can be raised up
to the hard limit value, but the hard limit can only be raised by a privileged (superuser) caller.
The
info
argument is a pointer to a structure of type
struct rlimit
, into which will be stored the defined limits. The structure contains the following fields:
The
resource
argument defines the resource to which the limit applies. It should be specified as one of the symbolic values defined
below.
RLIMIT_AS
- The maximum size in bytes of the address space for this process.
RLIMIT_CORE
- The maximum size in bytes of an OpenEdition memory dump (core file) for this process.
RLIMIT_CPU
- The maximum CPU time in seconds allowed for this address space.
RLIMIT_DATA
- The maximum amount of memory available for data allocation using
malloc
or
calloc
. This limit is not enforced under OpenEdition MVS, and an attempt to set the limit lower than
RLIM_INFINITY
will be rejected.
RLIMIT_FSIZE
- The maximum file size in bytes allowed for this process. The limit applies only to OpenEdition HFS files, not to standard MVS data
sets.
RLIMIT_NOFILE
- The maximum number of file descriptors the process may have open.
RLIMIT_STACK
- The maximum amount of memory available for stack allocation. This limit is not enforced under OpenEdition MVS, and an attempt to
set the limit lower than
RLIM_INFINITY
will be rejected.
getrlimit
returns
0
if successful, or
-1
if unsuccessful.getrlimit
function can only be used with MVS 5.2.2 or a later release.
Note: Resource limits are inherited from the parent process when
fork
or
exec
is used.
setrlimit
Obtain OpenEdition usage statistics
#include <sys/resource.h> int getrusage(int type, struct rusage *info);
getrusage
function returns resource usage information for the calling process, or for terminated child processes of the calling
process.
The
type
argument is a symbolic constant which specifies the processes for which resource information is wanted. The permissible values
are:
Note: If
RUSAGE_CHILDREN
is specified, information is returned only for child processes for which the parent has waited.
The
info
argument specifies a pointer to an
rusage
structure in which resource usage information is to be stored. The
rusage
structure contains two fields:
ru_utime
- the user time consumed by the process(es)
ru_stime
- the system time consumed by the process(es)
The
ru_utime
and
ru_stime
fields both have type
struct timeval
, which allows a time value to be specified to an accuracy of a microsecond. The structure has two
fields:
getrusage
returns
0
if successful, or
-1
if unsuccessful.getrusage
function can only be used with MVS 5.2.2 or a later
releaseGet session leader id for a process
#include <sys/types.h> #include <unistd.h> pid_t getsid(pid_t pid);
getsid
function returns the process id for the session leader for a specific process. The argument
pid
should be either the id of a specific process or
0
to request the id of the session leader for the current process.getsid
returns the session leader's process id, or
-1
if it fails.getsid
function can only be used with MVS 5.2.2 or a later release.sascc370 -Krent -o
.
/*--------------------------------------+ | POSIX/UNIX header files | +--------------------------------------*/ #include <sys/types.h> #include <unistd.h> /*--------------------------------------+ | ISO/ANSI header files | +--------------------------------------*/ #include <stdlib.h> #include <stdio.h> #include <errno.h> /*--------------------------------------+ | Name: main | | Returns: exit(EXIT_SUCCESS) | | or exit(EXIT_FAILURE) | + -------------------------------------*/ int main() { /* current process id from getpid() */ pid_t pid; /* process group id from getsid() */ pid_t sid; /*---------------------------------------*/ /* Get the Session Leader id for the */ /* Current Process */ /*---------------------------------------*/ printf("\nGet the Session Leader ID of the Current Process\n"); /* version 1 */ /* Set errno to zero for error handling */ errno = 0; /* get the process id for this process */ pid = getpid(); /* get the session leader id for */ /* this process */ sid = getsid(pid); /* Test for Error */ if (sid == -1) { perror("Call to getsid failed"); exit(EXIT_FAILURE); } else { printf (" The process id: %d\n", (int)pid); printf ("The Session Leader id: %d\n", (int)sid); } /* version 2 */ /* Reset errno to zero for error handling */ errno = 0; /* 0 implies current processs id */ pid = 0; /* get the session leader id for */ /* this process */ sid = getsid(pid); /* Test for Error */ if (sid == -1) { perror("Call to getsid failed"); exit(EXIT_FAILURE); } else { printf(" The process id: %d\n", (int)pid); printf("The Session Leader id: %d\n", (int)sid); } exit(EXIT_SUCCESS); } /* end of main() */
setsid
Get working directory path name
#include <unistd.h> char *getwd(char *buffer);
getwd
determines and stores the name of the working OpenEdition directory. The
buffer
argument is an array where the path name is to be stored. It should address an area of at least
PATH_MAX+1
bytes.
Note: The
PATH_MAX
symbol is defined in the header file.
When you call
getwd
in an application which was not compiled with the
posix
option, the returned directory name will begin with an
hfs:
style prefix.
getwd
returns a pointer to the
buffer
in which the directory path name was stored. If it fails, it returns
NULL
.getwd
function can only be used with MVS 5.2.2 or a later release.
Note: Use of the more portable and standard
getcwd
function is recommended in place of
getwd
.
getcwd
#include <unistd.h> int lchown(const char *pathname, uid_t owner, gid_t group);
lchown
changes the owner or owning group of an HFS file or symbolic link. It can be used with either regular files or special files such as
directories, FIFO files or links.
pathname
is the name of the file or link,
owner
is the new owning user id, and
group
is the new group id. If either
owner
or
group
is specified as -1, the owner or group of the file or link is unchanged.
For programs not compiled with the
posix
option, a style prefix may be required as part of the
pathname
specification. See "File Naming Conventions" in the SAS/C Library Reference, Volume 1, for further
information.
Note: For information when OpenEdition permits file ownership to be changed, see the
chown
function in the SAS/C Library Reference, Volume 2.
lchown
returns
0
if successful, or
-1
if unsuccessful.lchown
function can only be used with MVS 5.2.2 or a later release.chown
,
fchown
#include <mman.h> void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
mmap
function is used to request memory mapping of all or part of an HFS file. Memory mapping allocates a block of memory so that fetching from the
memory block will obtain the corresponding bytes of the file. Depending on the
mmap
flags, memory mapping is capable of changing the corresponding bytes of the file when data is stored in the memory block.
The
addr
argument may be either
0
or a memory address. If
addr
is
0,
the system will map the file anywhere in memory it chooses. If
addr
is not
0
, the system will attempt to allocate the memory for
the file mapping near the address specified.
The
len
argument specifies the number of bytes of the file that are to be mapped. The length must not cause the map to extend beyond the end of the file.
If the length does not specify an integral number of pages, the map is extended to the next highest page boundary, and the additional space is set to binary zeroes.
The
prot
argument specifies the protection status of the mapped memory. It should be specified as one of the symbolic
constants:
PROT_EXEC
- the memory is execute mode only (treated as
PROT_READ
by OpenEdition MVS)
PROT_NONE
- no access to the memory is permitted
PROT_READ
- the memory can be read, but not written
PROT_WRITE
- both read and write access to the memory is permitted
You cannot specify
PROT_WRITE
if the file descriptor for the file does not permit writing.
Note: The protection status of the mapped memory can be changed
later by a call to the
mprotect
function.
The
flags
argument specifies one or more option flags, combined using the or operator (|). Each flag should be specified as one of the following symbolic
constants:
MAP_SHARED
- the mapped memory is shared with the file, that is, changes to the memory will ultimately be reflected in the file contents
(mutually exclusive with
MAP_PRIVATE
)
MAP_PRIVATE
- the mapped memory is private, and changes will not be reflected in the file contents (mutually exclusive with
MAP_SHARED
)
MAP_FIXED
- the system is required to allocate the memory in the address specified by the
addr
argument
The
fd
argument specifies an open file descriptor for the file to be mapped, which must be a regular HFS file.
The
offset
argument specifies the first byte of the file to be mapped. The offset must be an exact multiple of the system page size (4096
bytes).
Note: See the IBM OpenEdition Assembler Callable Services manual for additional information about the behavior of
mmap
and the conditions under which it can be used.
mmap
returns the address of the start of the mapped memory if successful, or
0
if unsuccessful.mmap
function can only be used with MVS 5.2.2 or a later release.sascc370 -Krent -o
. The program uses the memory map functions,
mmap()
,
mprotect()
,
msync()
, and
munmap()
, to copy a file similar to the unix
cp
command.
/*--------------------------------------+ | POSIX/UNIX header files | +---------------------------------------*/ #include <unistd.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/mman.h> /*--------------------------------------+ | ISO/ANSI header files | +--------------------------------------*/ #include <stdlib.h> #include <stdio.h> /*--------------------------------------+ | Types | +--------------------------------------*/ /*--------------------------------------+ | Constants | +--------------------------------------*/ #define F_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) /*--------------------------------------+ | Name: main | | Returns: exit(EXIT_SUCCESS) or * | exit(EXIT_FAILURE) | +--------------------------------------*/ int main( int argc, char **argv ) { /* file descripter for the src file */ int fdSrc; /* file descripter for the dest file */ int fdDest; /* memory addr of the mapped src file */ char *src; /* memory addr of the mapped dest file */ char *dest; /* Buffer for fstat() info */ struct stat statBuffer; /*--------------------------------------*/ /* test args to main */ /*--------------------------------------*/ if ( argc != 3 ) { fprintf(stderr, "Usage: mmcp \n"); exit(EXIT_FAILURE); } /*-----------------------------------*/ /* open the source file for read */ /*-----------------------------------*/ if ( (fdSrc = open(argv[1], O_RDONLY)) < 0 ) { fprintf(stderr, "ERROR: Cannot open source file <%s>\n", argv[1]); exit(EXIT_FAILURE); } /*------------------------------------*/ /* open/create new file for output */ /*------------------------------------*/ if ( (fdDest = open(argv[2], O_RDWR | O_CREAT | O_TRUNC, F_MODE)) < 0) { fprintf(stderr, "ERROR: Cannot create dest file <%s>\n", argv[1]); exit(EXIT_FAILURE); } /*--------------------------------------*/ /* retrieve size of source file from */ /* fstat() function */ /*--------------------------------------*/ if ( fstat(fdSrc, &statBuffer) < 0 ) { fprintf(stderr, "ERROR: Cannot fstat source file <%s>\n", argv[1]); exit(EXIT_FAILURE); } /*---------------------------------------------*/ /* set the size of the dest file. */ /* If we don't we'll get an */ /* SIGSEGV when we try to copy to its mmap. */ /*---------------------------------------------*/ if ( ftruncate( fdDest, (off_t)statBuffer.st_size ) < 0 ) { fprintf(stderr, "ERROR: Cannot set size of the dest file <%s>\n", argv[2]); exit(EXIT_FAILURE); } /*----------------------------------------------*/ /* map the source file to memory */ /* (for read only) */ /*----------------------------------------------*/ if ( (src = mmap(0, statBuffer.st_size, PROT_READ, MAP_SHARED, fdSrc, 0)) == (char *)-1) { fprintf(stderr, "ERROR: Cannot memory map source file <%s>\n", argv[1]); exit(EXIT_FAILURE); } else { printf ("NOTE: source file <%s> mapped at address <%p>\n", argv[1], src); } /*----------------------------------------------*/ /* map the dest file to memory */ /* (for read only) */ /*----------------------------------------------*/ if ( (dest = mmap (0, statBuffer.st_size, PROT_READ, MAP_SHARED, fdDest, 0)) == (char *)-1) { fprintf(stderr, "ERROR: Cannot memory map dest file <%s>\n", argv[2]); exit(EXIT_FAILURE); } else { printf("NOTE: dest file <%s> mapped at address <%p>\n", argv[2], dest); } /*-----------------------------------------------*/ /* chg the protection of memory map of */ /* the dest file to write */ /*-----------------------------------------------*/ if ( (mprotect(dest, statBuffer.st_size, PROT_WRITE)) == -1) { fprintf(stderr, "ERROR: Cannot change memory map protect of dest file <%s>\n", argv[2]); exit(EXIT_FAILURE); } /*------------------------------------------*/ /* copy src to dest in memory */ /*------------------------------------------*/ memcpy(dest, src, statBuffer.st_size); /*-------------------------------------------*/ /* synchronize the memory mapped dest file. */ /*-------------------------------------------*/ if ( (msync (dest, statBuffer.st_size, MS_SYNC)) == -1) { fprintf(stderr, "ERROR: Cannot synchronize memory map of dest file <%s>\n", argv[2]); exit(EXIT_FAILURE); } /*--------------------------------------------*/ /* cancel mapping of memory to the src file. */ /*--------------------------------------------*/ if ( (munmap(src, statBuffer.st_size)) == -1) { fprintf(stderr, "ERROR: Cannot terminate memory map of src file <%s>\n", argv[2]); exit(EXIT_FAILURE); } /*--------------------------------------------*/ /* cancel mapping of memory to the dest file. */ /*--------------------------------------------*/ if ( (munmap(dest, statBuffer.st_size)) == -1) { fprintf(stderr, "ERROR: Cannot terminate memory map of dest file <%s>\n", argv[2]); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); } /* end of main() */ /* end of mmcp.c */
mprotect
,
msync
,
munmap
Change protection of memory mapped to a file
#include <mman.h> int mprotect(void *addr, unsigned int len, int prot);
mprotect
function is used to change the protection status of one or more pages of memory mapped to an HFS file by a previous call to the
mmap
function.
The
addr
argument is the address of the first page of mapped memory for which the protection attributes are to be changed. The address must be on a page
boundary, but need not be the first byte of the entire area mapped to a file.
The
len
argument specifies the number of bytes of memory whose protection attributes are to be changed. If the length does not specify an integral number
of pages, it is rounded up to do so. The length need not specify the entire area of mapped memory.
The
prot
argument specifies the new protection status of the mapped memory. It should be specified as one of the symbolic constants described in the
mmap
function write-up.
You cannot specify
PROT_WRITE
if the file descriptor for the file does not permit writing.
Note: See the IBM OpenEdition Assembler Callable
Services manual for additional information about the behavior of
mprotect
and the conditions under which it can be used.
mprotect
returns
0
if successful, or
-1
if unsuccessful.mprotect
function can only be used with MVS 5.2.2 or a later release.mmap
,
msync
,
munmap
#include <sys/msg.h> int msgctl(int id, int cmd, struct msgid_ds *buf);
msgctl
function is used to perform one of several control operations on an OpenEdition message queue.
Note: See the
msgget
function description in section msgget for general information about message
queues.
The
id
argument to
msgctl
specifies a message queue id. This argument is an id, such as the id returned by
msgget
, not a message queue key, which might be passed as an argument to
msgget
.
The
cmd
argument should be specified as a symbolic constant specifying the particular operation to be performed by
msgctl
. The constant values are described below.
Several of the
msgctl
operations allow you to obtain or access the message queue id data structure, which is mapped by the
struct msqid_ds
type defined in
sys/msg.h
. This data structure is defined as follows:
struct msqid_ds { /* permission information */ struct ipc_perm msg_perm; /* messages presently on the queue */ unsigned msg_qnum; /* max bytes of queued info */ unsigned msg_qbytes; /* process id of last sender */ pid_t msg_lspid; /* process id of last receiver */ pid_t msg_lrpid; /* time of last msgsnd call */ time_t msg_stime; /* time of last msg(x)rcv call */ time_t msg_rtime; /* time of last change by msgget/msgctl */ time_t msg_ctime; };
The
ipc_perm
structure, which contains security information about the owner and the creator of the message queue, is defined as follows:
struct ipc_perm { /* owner's effective user ID */ uid_t uid; /* owner's effective group ID */ gid_t gid; /* creator's effective user ID */ uid_t cuid; /* creator's effective group ID */ gid_t cgid; /* read/write permission bits */ mode_t mode; };
For
msgctl
operations which access or modify the message queue data structure, the
buf
argument addresses a
struct msqid_ds
, used as described below. For other operations, the
buf
argument is ignored.
The
cmd
values accepted by
msgctl
and their meanings are as follows:
IPC_RMID
- Removes the message queue and its id from the system. The
buf
argument is not used by this operation.
IPC_SET
- Can be used to change the ownership of a message queue or the access rules. The contents of
buf->msg_perm.uid
,
buf->msg_perm.gid
and
buf->msg_perm.mode
will be copied to the message queue id data structure.
IPC_STAT
- Returns the contents of the message queue id data structure. All elements of the data structure are stored in the object addressed by
buf
.
msgctl
returns
0
if successful, or
-1
if unsuccessful.msgctl
function can only be used with MVS 5.2.2 or a later release.sascc370 -Krent -o
. This program uses the functions
msgget()
,
msgsnd()
,
msgrcv()
, and
msgctl()
to establish an IPC Server using Message Queues.
/*-------------------------+ | POSIX/UNIX header files | +-------------------------*/ #include <sys/types.h> #include <unistd.h> #include <fcntl.h> #include <sys/ipc.h> #include <sys/msg.h> /*-------------------------+ | ISO/ANSI header files | +-------------------------*/ #include <stdlib.h> #include <stdio.h> #include <string.h> #include <errno.h> /*---------------------------+ | Constants | +---------------------------*/ /* maximum message size */ #define MAX_MSGSIZE 256 /* message key, set by server */ #define MSG_KEY (key_t)1097 /* Server's message type */ #define SERVER_MSG_TYPE (long)10 /* Client's message type */ #define CLIENT_MSG_TYPE (long)20 /* give everyone read/write */ /* permission to messages */ #define MSG_PERM (S_IRUSR|S_IWUSR |S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) /*----------------------------------+ | Types | +-----------------------------------*/ /* Declare the message structure. */ typedef struct Message { /* positive message type */ long type; /* message data */ char text[MAX_MSGSIZE]; }Message; /*----------------------------------+ | Name: main | | Returns: exit(EXIT_SUCCESS) or | | exit(EXIT_FAILURE) | +----------------------------------*/ int main() { /* message queue id */ int msgQID; /* message flags */ int msgFlags; /* message type */ long msgType; /* message key */ key_t msgKey; /* message to send */ Message sendMsg; /* message received */ Message recvMsg; /*------------------------------------*/ /* Create message queue. */ /* Give everyone read/write */ /* permissions. */ /*------------------------------------*/ msgKey = MSG_KEY; msgFlags = IPC_CREAT | MSG_PERM; if ( (msgQID = msgget(msgKey, msgFlags)) < 0 ) { perror("SERVER: msgget"); exit(EXIT_FAILURE); } /*---------------------------------------*/ /* Receive a message from client. */ /*---------------------------------------*/ msgType = CLIENT_MSG_TYPE; msgFlags = 0; if (msgrcv(msgQID, &recMsg, MAX_MSGSIZE, msgType, msgFlags) < 0) { perror("SERVER: msgrcv"); msgctl(msgQID, IPC_RMID, NULL); exit(EXIT_FAILURE); } /*-----------------------------------------*/ /* Print message received from client. */ /*-----------------------------------------*/ printf("%s\n", recvMsg.text); /*------------------------------------------*/ /* Send ACK Message to client. */ /*------------------------------------------*/ sendMsg.type = SERVER_MSG_TYPE; sprintf(sendMsg.text, "From SERVER: Message received!"); msgFlags = 0; if (msgsnd(msgQID, &sendMsg, strlen(sendMsg.text)+1, msgFlags) < 0) { perror("SERVER: msgsnd"); msgctl(msgQID, IPC_RMID, NULL); exit(EXIT_FAILURE); } /*--------------------------------------------*/ /* Go to sleep to allow time for the client */ /* to recieve the message */ /* before removing the message queue. */ /*--------------------------------------------*/ sleep(60); /*--------------------------------------------*/ /* Call msgctl to remove message queue. */ /*--------------------------------------------*/ if (msgctl(msgQID, IPC_RMID, NULL) < 0) { perror("SERVER: msgctl"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); } /* end of main() */
sascc370 -Krent -o.
This program usese the functions
msgctl()
,
msgget()
,
msgsnd()
, and
msgxrcv
to establish IPC Client using XMessage Queues. Also, it uses Open Edition's extended Message structure.
Note: You cannot use the Extended
Message structure to send a message, i.e., call
msgsnd()
with this structure. Attempting to do so will cause the program to "hang".
/*--------------------------------------------+ | POSIX/UNIX header files | +--------------------------------------------*/ #include <sys/types.h> #include <unistd.h> #include <fcntl.h> #include <sys/ipc.h> #include <sys/msg.h> /*--------------------------------------------+ | ISO/ANSI header files | +--------------------------------------------*/ #include <stdlib.h> #include <stdio.h> #include <string.h> #include <time.h> #include <errno.h> /*--------------------------------------------+ | Constants | +--------------------------------------------*/ /* maximum message size */ #define MAX_MSGSIZE 256 /* message key, set by server */ #define MSG_KEY (key_t)1097 /* Server's message type */ #define SERVER_MSG_TYPE (long)10 /* Client's message type */ #define CLIENT_MSG_TYPE (long)20 /* give everyone read/write */ /* permission to messages */ #define MSG_PERM (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) /*---------------------------------------------+ | Types | +---------------------------------------------*/ /* Declare the message structure. */ typedef struct Message { /* positive message type */ long type; /* message data */ char text[MAX_MSGSIZE]; }Message; /* Declare the message structure. */ typedef struct XMessage { /* time msg sent */ time_t time; /* effective uid of sender */ uid_t uid; /* effective gid of sender */ gid_t gid; /* process id of sender */ pid_t pid; /* positive message type */ long type; /* message data */ char text[MAX_MSGSIZE]; }XMessage; /*-------------------------------------------+ | Name: main | | Returns: exit(EXIT_SUCCESS) or | | exit(EXIT_FAILURE) | +-------------------------------------------*/ int main() { /* message queue id */ int msgQID; /* message flags */ int msgFlags; /* command to message queue, used w/ msgctl * int msgQcmd; / /* message type */ long msgType; /* message key */ key_t msgKey; /* message to send */ Message sendMsg; /* message received - eXtended */ XMessage recvMsg; /*------------------------------------------*/ /* Create message queue. */ /* Give everyone read/write permissions. */ /*------------------------------------------*/ msgKey = MSG_KEY; msgFlags = IPC_CREAT | MSG_PERM; if ( (msgQID = msgget(msgKey, msgFlags)) < 0 ) { perror("SERVER: msgget"); exit(EXIT_FAILURE); } /*---------------------------------------------*/ /* Receive a message from client. */ /*---------------------------------------------*/ msgType = CLIENT_MSG_TYPE; msgFlags = 0; if (msgxrcv(msgQID, &recMsg, MAX_MSGSIZE, msgType, msgFlags) < 0) { perror("SERVER: msgrcv"); msgctl(msgQID, IPC_RMID, NULL); exit(EXIT_FAILURE); } /*---------------------------------------------*/ /* Print message received from client. */ /*---------------------------------------------*/ printf("Message: %s\n", recvMsg.text); printf(" Time message was sent: %s\n", ctime(&recvMsg.time)); printf(" The user id of sender: %d\n", (int)recvMsg.uid); printf(" The group id of sender: %d\n", (int)recvMsg.gid); printf("The process id of sender: %d\n", (int)recvMsg.pid); /*-------------------------------------------*/ /* Send ACK XMessage to client. */ /*-------------------------------------------*/ sendMsg.type = SERVER_MSG_TYPE; sprintf( sendMsg.text, "From SERVER: XMessage received!"); msgFlags = 0; if (msgsnd(msgQID, &sendMsg, strlen(sendMsg.text)+1, msgFlags) < 0) { perror("SERVER: msgsnd"); msgctl(msgQID, IPC_RMID, NULL); exit(EXIT_FAILURE); } /*----------------------------------------------*/ /* Go to sleep to allow time for the client to */ /* recieve the message */ /* before removing the message queue. */ /*-------------------------------------------*/ sleep(60); /*----------------------------------------------*/ /* Call msgctl to remove message queue. */ /*----------------------------------------------*/ if (msgctl(msgQID, IPC_RMID, NULL) < 0) { perror("SERVER: msgctl"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); } /* end of main() */
msgget
,
msgrcv
,
msgsnd
,
msgxrcv
Create or find a message queue
#include <sys/msg.h> int msgget(key_t key, int flags);
msgget
function is used either to create a new message queue or to locate an existing queue based on a key. Message queues are implemented by
OpenEdition, and allow messages of multiple types to be queued. OpenEdition message queues support multiple senders and multiple receivers and do not require the senders and receivers to be running
simultaneously. Message queues, once created using
msgget
, remain in existence until they are explicitly destroyed with a call to
msgctl
.
The
key
argument is an integral value which identifies the message queue desired. A
key
value of
IPC_PRIVATE
requests a new message queue without an associated
key
, and which can be accessed only by the queue id returned by
msgget
.
The
flags
argument specifies zero or more option flags specifying whether or not the queue already exists, and how access to the queue should be regulated.
The argument should be specified as
0
for no flags, or as one or more of the following symbolic constants, combined using the or operator (|):
IPC_CREAT
- Specifies that if a queue with the requested
key
does not exist, it should be created. This flag is ignored if
IPC_PRIVATE
is specified.
IPC_EXCL
- Specifies that a queue with the requested
key
must not already exist. This flag is ignored if
IPC_PRIVATE
is specified, or if
IPC_CREAT
is not specified.
Additionally, any of the permission bits
S_IRUSR
,
S_IWUSR
,
S_IRGRP
,
S_IWGRP
,
S_IROTH
and
S_IWOTH
may be specified as part of the
flags
argument,
to regulate what users are permitted to access or modify the message queue. See the
umask
function description in the SAS/C Library Reference, Volume 2, for more information about the meaning of these
flags.
msgget
returns the identifier of the message queue if successful, or
-1
if unsuccessful.msgget
function can only be used with MVS 5.2.2 or a later release.
Note: A site can impose limits on the number and size of queued
messages.
sascc370 -Krent -o
. This program uses the functions
msgget()
,
msgsnd()
, and
msgrcv()
to establish IPC Client using Message Queues.
/*------------------------------------------+ | POSIX/UNIX header files | +-------------------------------------------*/ #include <fcntl.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> /*------------------------------------------+ | ISO/ANSI header files | +------------------------------------------*/ #include <stdlib.h> #include <stdio.h> #include <string.h> #include <errno.h> /*------------------------------------------+ | Constants | +------------------------------------------*/ /* maximum message size */ #define MAX_MSGSIZE 256 /* message key, set by server */ #define MSG_KEY (key_t)1097 /* Server's message type */ #define SERVER_MSG_TYPE (long)10 /* Client's message type */ #define CLIENT_MSG_TYPE (long)20 /* give everyone read/write */ /* permission to messages */ #define MSG_PERM (S_IRUSR|S_IWUSR|S_IRGRP |S_IWGRP|S_IROTH|S_IWOTH) /*---------------------------------+ | Types | +---------------------------------*/ /* Declare the message structure. */ typedef struct Message { /* positive message type */ long type; /* message data */ char text[MAX_MSGSIZE]; }Message; /*---------------------------------+ | Name: main | | Returns: exit(EXIT_SUCCESS) or | | exit(EXIT_FAILURE) | +---------------------------------*/ int main() { /* message queue id */ int msgQID; /* message flags */ int msgFlags; /* message type */ long msgType; /* message key */ key_t msgKey; /* message to send */ Message sendMsg; /* message received */ Message recvMsg; /*------------------------------------------*/ /* Get the message queue id for MSG_KEY, */ /* which was set by the */ /* message server. */ /*------------------------------------------*/ msgKey = MSG_KEY; msgFlags = MSG_PERM; if ( (msgQID = msgget(msgKey, msgFlags)) < 0 ) { perror("CLIENT: msgget"); exit(EXIT_FAILURE); } /*-------------------------------------------*/ /* Send the message. */ /*-------------------------------------------*/ sendMsg.type = CLIENT_MSG_TYPE; sprintf (sendMsg.text, "From CLIENT: Are you there?"); msgFlags = 0; if (msgsnd(msgQID, &sendMsg, strlen(sendMsg.text)+1, msgFlags) < 0) { perror("CLIENT: msgsnd"); exit(EXIT_FAILURE); } /*-----------------------------------------*/ /* Receive a message from server. */ /*-----------------------------------------*/ msgType = SERVER_MSG_TYPE; msgFlags = 0; if (msgrcv(msgQID, &recMsg, MAX_MSGSIZE, msgType, msgFlags) < 0) { perror("CLIENT: msgrcv"); exit(EXIT_FAILURE); } /*-------------------------------------------*/ /* Print message received from server. */ /*-------------------------------------------*/ printf("%s\n", recvMsg.text); exit(EXIT_SUCCESS); } /* end of main() */
sascc370 -Krent -o
. This program uses the
msgget()
function to create IPC message queue and then uses the
msgctl()
function to retrieve statistics on the newly created message queue.
/*-------------------------------------------+ | POSIX/UNIX header files | +-------------------------------------------*/ #include <sys/types.h> #include <unistd.h> #include <fcntl.h> #include <sys/ipc.h> #include <sys/msg.h> /*-------------------------------------------+ | ISO/ANSI header files | +-------------------------------------------*/ #include <stdlib.h> #include <stdio.h> #include <string.h> #include <time.h> #include <errno.h> /*-------------------------------------------+ | Types | +-------------------------------------------*/ /* message queue id structure */ typedef struct msqid_ds MsgQueueID; /*--------------------------------------------+ | Constants | +--------------------------------------------*/ /* message key */ #define MSG_KEY (key_t)1097 /* give everyone read/write permission to */ /*messages */ #define MSG_PERM (S_IRUSR|S_IWUSR|S_IRGRP |S_IWGRP|S_IROTH|S_IWOTH) /*---------------------------------------------+ | Name: main | | Returns: exit(EXIT_SUCCESS) or | | exit(EXIT_FAILURE) | +---------------------------------------------*/ int main() { /* message queue id */ int msgQID; /* message flags */ int msgFlags; /* command to message queue. */ int msgQcmd; /* message key */ key_t msgKey; /* message queue id data structure */ MsgQueueID * msgQueue; /*---------------------------------------------*/ /* Create message queue. */ /* Give everyone read/write permissions. */ /*---------------------------------------------*/ msgKey = MSG_KEY; msgFlags = IPC_CREAT | MSG_PERM; if ( (msgQID = msgget(msgKey, msgFlags)) < 0 ) { perror("MSGSTAT: msgget"); exit(EXIT_FAILURE); } /*-----------------------------------------------*/ /* Allocate memory to store information from */ /* message queue */ /*-----------------------------------------------*/ msgQueue = malloc(sizeof(MsgQueueID)); if (msgQueue == NULL) { fprintf(stderr, "ERROR: Cannot allocate memory for message queue stats\n"); exit(EXIT_FAILURE); } /*-----------------------------------------------*/ /* Call msgctl to retrieve information from */ /* message queue */ /*--------------------------------------------*/ msgQcmd = IPC_STAT; if (msgctl(msgQID, msgQcmd, msgQueue) < 0) { perror ("MSGSTAT: msgctl failed to retrieve message queue stats"); free(msgQueue); exit(EXIT_FAILURE); } /*-----------------------------------------------*/ /* Print infomation retrieved from message queue */ /*-----------------------------------------------*/ printf("Message Queue ID statistics:\n\n"); printf("\tQueue owner's effective user ID: %d\n",(int)msgQueue->msg_perm.uid); printf("\tQueue owner's effective group ID: %d\n",(int)msgQueue->msg_perm.gid); printf("\tQueue creator's effective user ID: %d\n",(int)msgQueue->msg_perm.cuid); printf("\tQueue creator's effective group ID: %d\n",(int)msgQueue->msg_perm.cgid); printf("\tQueue permission mode bits: %#.3o\n\n",(int)msgQueue->msg_perm.mode); printf("\tNumber of messages currently on Queue: %d\n",msgQueue->msg_qnum); printf("\tMaximum bytes of queued info: %d\n", msgQueue->msg_qbytes); printf("\tProcess id of last sender: %d\n", (int)msgQueue->msg_lspid); printf("\tProcess id of last receiver: %d\n", (int)msgQueue->msg_lrpid); printf("\tTime of last msgsnd call: %s",ctime(&msgQueue->msg_stime)); printf("\tTime of last msg(x)rcv call: %s",ctime(&msgQueue->msg_rtime)); printf("\tTime of last chg by msgget/msgctl: %s",ctime(&msgQueue->msg_ctime)); /*-------------------------------------------------*/ /* Free memory used to store information from */ /* message queue */ /*-------------------------------------------------*/ free(msgQueue); /*--------------------------------------------------*/ /* Call msgctl to remove message queue. */ /*--------------------------------------------------*/ msgQcmd = IPC_RMID; if (msgctl(msgQID, msgQcmd, NULL) < 0) { perror ("MSGSTAT: msgctl failed to remove message queue"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); } /* end of main() */
sascc370 -Krent -o
.
This program uses the functions
msgget()
,
msgsnd()
, and
msgxrcv()
to establish IPC Client using XMessage Queues. Also, it uses Open Edition's extended Message structure.
Note: You cannot use the
Extended Message structure to send a message, i.e., call
msgsnd()
with this structure. Attempting
to do so will cause the program to "hang".
/*---------------------------------+ | POSIX/UNIX header files | +---------------------------------*/ #include <fcntl.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/msg.h> /*---------------------------------+ | ISO/ANSI header files | +----------------------------------*/ #include <stdlib.h> #include <stdio.h> #include <string.h> #include <time.h> #include <errno.h> /*---------------------------------+ | Constants | +---------------------------------*/ /* maximum message size */ #define MAX_MSGSIZE 256 /* message key, set by server */ #define MSG_KEY (key_t)1097 /* Server's message type */ #define SERVER_MSG_TYPE (long)10 /* Client's message type */ #define CLIENT_MSG_TYPE (long)20 /* give everyone read/write */ /* permission to messages */ #define MSG_PERM (S_IRUSR|S_IWUSR|S_IRGRP |S_IWGRP|S_IROTH|S_IWOTH) /*-----------------------------------+ | Types | +-----------------------------------*/ /* Declare the message structure. */ typedef struct Message { /* positive message type */ long type; /* message data */ char text[MAX_MSGSIZE]; }Message; /* Declare the OE Extended message structure. */ typedef struct XMessage { /* time msg sent */ time_t time; /* effective uid of sender */ uid_t uid; /* effective gid of sender */ gid_t gid; /* process id of sender */ pid_t pid; /* positive message type */ long type; /* message data */ char text[MAX_MSGSIZE]; }XMessage; /*----------------------------------+ | Name: main | | Returns: exit(EXIT_SUCCESS) or | | exit(EXIT_FAILURE) | +----------------------------------*/ int main() { /* message queue id */ int msgQID; /* message flags */ int msgFlags; /* message type */ long msgType; /* message key */ key_t msgKey; /* message to send */ Message sendMsg; /* message received - eXtended */ XMessage recvMsg; /*-------------------------------------------*/ /* Get the message queue id for MSG_KEY, */ /* which was set by the */ /* message server. */ /*-------------------------------------------*/ msgKey = MSG_KEY; msgFlags = MSG_PERM; if ( (msgQID = msgget(msgKey, msgFlags)) < 0 ) { perror("CLIENT: msgget"); exit(EXIT_FAILURE); } /*----------------------------------------------*/ /* Send the message. */ /*----------------------------------------------*/ sendMsg.type = CLIENT_MSG_TYPE; sprintf (sendMsg.text, "From CLIENT: Are you there?"); msgFlags = 0; if (msgsnd(msgQID, &sendMsg, strlen(sendMsg.text)+1, msgFlags) < 0) { perror("CLIENT: msgsnd"); exit(EXIT_FAILURE); } /*------------------------------------------*/ /* Receive a message from server. */ /*------------------------------------------*/ msgType = SERVER_MSG_TYPE; msgFlags = 0; if (msgxrcv(msgQID, &recMsg, MAX_MSGSIZE, msgType, msgFlags) < 0) { perror("CLIENT: msgrcv"); exit(EXIT_FAILURE); } /*------------------------------------------*/ /* Print message received from server. */ /*------------------------------------------*/ printf("Message: %s\n", recvMsg.text); printf(" Time message was sent: %s\n", ctime(&recMsg.time)); printf(" The user id of sender: %d\n", (int)recvMsg.uid); printf(" The group id of sender: %d\n", (int)recvMsg.gid); printf("The process id of sender: %d\n", (int)recvMsg.pid); exit(EXIT_SUCCESS); } /* end of main() */
msgctl
,
msgrcv
,
msgsnd
,
msgxrcv
Receive a message from a message queue
#include <sys/msg.h> int msgrcv(int id, void *msg, size_t size, long msgtype,int flags);
msgrcv
function is used to receive a message from an OpenEdition message queue. The
msgtype
argument allows the caller to select the type of message to be received.
Note: See the
msgget
function description in section msgget for general information about OpenEdition
message queues.
The
id
argument to
msgrcv
specifies the id of the message queue from which messages will be received. This argument is an id, such as the id returned by
msgget
, not a message queue key, which might be passed as an argument to
msgget
.
The
msg
argument should be a pointer to a message buffer into which the received message should be stored. The message buffer should have the following
layout:
struct { long mtype; /* message type */ char mtext[n]; /* message text */ };
where
n
is an integer constant large enough for the message text.
Note: You must declare an appropriate type for the messages you receive
yourself, as no such type is defined by
sys/msg.h
. Also the meaning of
mtype
is not fixed by the message queue protocol, but can be used by the application to establish message types or priorities in any natural
way.
The
size
argument to
msgrcv
should be the maximum number of bytes of message text to be received.
size
should not include the size of the
mtype
field. If the size of the message text to be received is larger than the
size
argument, the result depends
upon the options specified by the
flags
argument.
The
msgtype
argument specifies which message, if any, is received. The argument is interpreted as follows:
msgtype
is
0
, the first message on the queue is received.
msgtype
is greater than
0
, the first message whose
mtype
field is equal to
msgtype
is received.
msgtype
is less than zero, a message whose
mtype
field is less than or equal to
-msgtype
is received. If there is more than one such message, the first one of minimal
mtype
value is received.
The
flags
argument specifies zero or more option flags specifying processing options. The argument should be specified as
0
for no flags, or as one or more of the following symbolic constants, combined using the or operator (|):
IPC_NOWAIT
- Specifies that the caller does not wish to wait if there is no appropriate message on the queue. In this case,
msgrcv
fails, and
errno
is set to
ENOMSG
. If
IPC_NOWAIT
is not set and there is no appropriate message, the caller
will wait until an appropriate message is sent, the message queue is destroyed, or a signal is received.
MSG_NOERROR
- Specifies that receiving a message whose text is larger than the
size
argument is not to be considered an error. In this case, the message text will be truncated and no indication of the truncation is returned. If
MSG_NOERROR
is not specified and the message to be received is larger than the
size
argument, the
msgrcv
call fails, and
errno
is set to
E2BIG
.
msgrcv
returns the number of bytes of message text stored (not including the
mtype
field). If it fails,
msgrcv
returns
-1
.msgrcv
function can only be used with MVS 5.2.2 or a later release.msgctl
,
msgget
,
msgsnd
,
msgxrcv
Send a message to a message queue
#include <sys/msg.h> int msgsnd(int id, const void *msg, size_t size, int flags);
msgsnd
function is used to send a message to an OpenEdition message queue, for later receipt by another process calling
msgrcv
or
msgxrcv
.
Note: See the
msgget
function description in section msgget for general information about message
queues.
The
id
argument to
msgsnd
specifies the id of the message queue to which messages will be sent. This argument is an id, such as the id returned by
msgget
, not a message queue key, which might be passed as an argument to
msgget
.
The
msg
argument should be a pointer to a message buffer that contains the message to be sent. The message buffer should have the following
layout:
wherestruct { long mtype; /* message type */ char mtext[n]; /* message text */ };
n
is an integer constant large enough for the message text.
Note: You must declare an appropriate type for the messages you send yourself,
as no such type is defined by
sys/msg.h
. Also the meaning of
mtype
is not fixed by the message queue protocol (other than that its value must be greater than zero), but it can be used by the application to
establish message types or priorities in any natural way.
The
size
argument to
msgsnd
should be the number of bytes of message text to be sent.
size
should not include the size of the
mtype
field. It is possible to send a message which contains only a type, but no text, in which case a size of
0
should be
passed.
The
flags
argument specifies either
0
or the
IPC_NOWAIT
option. If
IPC_NOWAIT
is set, and the system limits on the amount of queued up data have been reached, the call to
msgsnd
will immediately fail, with
errno
set to
EAGAIN
. If
IPC_NOWAIT
is not set, and the limits have been reached, the calling process will wait until enough messages are removed from the queue to allow this
message to be sent.
msgsnd
returns
0
if successful, or
-1
if unsuccessful.msgsnd
function can only be used with MVS 5.2.2 or a later release.msgctl
,
msgget
,
msgrcv
,
msgxrcv
Receive a message from a message queue with sender information
#include <sys/msg.h> int msgxrcv(int id, void *msg, size_t size, long msgtype, int flags);
msgxrcv
function is used to receive a message from an OpenEdition message queue. The
msgtype
argument allows the caller to select the type of message to be received. Unlike
msgrcv
,
msgxrcv
stores information about the time the message was sent and the process which sent the message.
Note: See the
msgget
function description in section msgget for general information about OpenEdition
message queues.
The
id
argument to
msgxrcv
specifies the id of the message queue from which messages will be received. This argument is an id, such as the id returned by
msgget
, not a message queue key, which might be passed as an argument to
msgget
.
The
msg
argument should be a pointer to a message buffer into which the received message should be stored. The message buffer should have the following
layout:
struct { /* the time the message was sent */ time_t mtime; /* the effective uid of the sender */ uid_t muid; /* the effective gid of the sender */ gid_t mgid; /* the process id of the sender */ pid_t mpid; /* message type */ long mtype; /* message text */ char mtext[n]; };
where n is an integer constant large enough for the message text.
Note: You must declare an appropriate type for the messages you receive yourself, as no
such type is defined by
sys/msg.h
. Also, the meaning of
mtype
is not fixed by the message queue protocol, but can be used by the application to establish message types or priorities in any natural
way.
The
size
argument to
msgxrcv
should be the maximum number of bytes of message text to be received.
size
should not include the size of any of the fields preceding
mtext
in the structure. If the size of the message text to be received is larger than the
size
argument, the result depends upon the options specified by the
flags
argument.
The
msgtype
argument specifies which message, if any, is received. The argument is interpreted as follows:
msgtype
is
0
, the first message on the queue is received.
msgtype
is greater than
0
, the first message whose
mtype
field is equal to
msgtype
is received.
msgtype
is less than zero, a message whose
mtype
field is less than or equal to
-msgtype
is received. If there is more than one such message, the first one of minimal
mtype
is received.
The
flags
argument specifies zero or more option flags specifying processing options. The argument should be specified as
0
for no flags, or as one or more of the following symbolic constants, combined using the or operator (|):
IPC_NOWAIT
- Specifies that the caller does not wish to wait if there is no appropriate message on the queue. In this case,
msgxrcv
fails, and
errno
is set to
ENOMSG
. If
IPC_NOWAIT
is not set and there is no appropriate message, the caller
will wait until an appropriate message is sent, the message queue is destroyed, or a signal is received.
MSG_NOERROR
- Specifies that receiving a message whose text is larger than the
size
argument is not to be considered an error. In this case, the message text will be truncated and no indication of the truncation is returned. If
MSG_NOERROR
is not specified and the message to be received is larger than the
size
argument, the
msgxrcv
call fails, and
errno
is set to
E2BIG
.
msgxrcv
returns the number of bytes of message text stored (not including the header fields). If it fails,
msgxrcv
returns
-1
.msgxrcv
function can only be used with MVS 5.2.2 or a later release.msgxrcv
is an OpenEdition extension to UNIX message queue processing, and is not portable.msgctl
,
msgget
,
msgrcv
,
msgsnd
Synchronize a memory mapped HFS file
#include <mman.h> int msync(void *addr, unsigned int len, int flags);
msync
function is used to synchronize an HFS file with one or more pages of memory mapped to the file. The call may either cause the file to be updated
with data in memory or cause the data in memory to be updated from the file.
The
addr
argument is the address of the first page of mapped memory to be synchronized. The address must be on a page boundary, but need not be the first
byte of the entire area mapped to a file.
The
len
argument specifies the number of bytes of memory to be synchronized. If the length does not specify an integral number of pages, it is rounded up
to do so. The length need not specify the entire area of mapped memory.
The
flags
argument specifies options describing how synchronization should be performed. One or more of the following symbolic constants should be
specified, combined using the or operator (|).
MS_ASYNC
- All modified data in the memory specified is written to the file. The writes are performed asynchronously, which means that they need
not be performed in any particular order. Control is returned as soon as all writes have been scheduled.
MS_SYNC
- All modified data in the memory specified is written to the file. The writes are performed synchronously, that is, control is not
returned from
msync
until all data has been written.
MS_INVALIDATE
- The contents of the memory pages specified are discarded. References to data in the affected pages will cause data to be read
from the appropriate portion of the mapped file.
One of the three flags must be specified, and only one of
MS_ASYNC
and
MS_SYNC
may be specified. If
MS_INVALIDATE
is specified together with another flag, the memory contents specified are discarded only after all write operations have
completed.
See the IBM OpenEdition Assembler Callable Services manual for additional information about the behavior of
msync
and the conditions under which it can be used.
msync
returns
0
if successful, or
-1
if unsuccessful.msync
function can only be used with MVS 5.2.2 or a later release.mmap
,
mprotect
,
munmap
Cancel mapping of a memory area to a file
#include <mman.h> int munmap(void *addr, unsigned int len);
munmap
function is used to terminate mapping of part or all of a memory area previously mapped to a file by the
mmap
function.
The
addr
argument is the address of the first page of mapped memory to be unmapped. The address must be on a page boundary, but need not be the first byte
of the entire area mapped to a file.
The
len
argument specifies the number of bytes of memory to be unmapped. If the length does not specify an integral number of pages, it is rounded up to do
so. The length need not specify the entire area of mapped memory.
If an area of memory is mapped and then partially unmapped, any reference to an unmapped portion will cause a segmentation violation.
If the memory area was created by a call to
mmap
specifying the
MAP_SHARED
symbolic flag, all changed areas of memory are written back to the file before
munmap
completes. If the
mmap
call specified
MAP_PRIVATE
, all changes are discarded.
See the IBM OpenEdition Assembler Callable Services manual for additional information
about the behavior of
munmap
and the conditions under which it can be used.
munmap
returns
0
if successful, or
-1
if unsuccessful.munmap
function can only be used with MVS 5.2.2 or a later release.mmap
,
mprotect
,
msync
Control subtasks with OpenEdition
#include <lclib.h> int oetaskctl(int setting);
oetaskctl
function is used to control the interpretation of MVS subtasks of the current program, such as subtasks created by the system or
oslink
functions, or by the assembler
ATTACH
macro. By default, subtasks of a program which has used OpenEdition facilities are treated as threads. This means that OpenEdition
resources,
such as file descriptors, current directory, and signal handlers, are shared between the subtasks. Because the SAS/C library assumes that these resources are not shared, this mode of operation can
lead to errors.
Alternately,
oetaskctl
can be used to indicate that subtasks of the calling program are to be treated as a separate process from the calling program. This implies
each subtask will have its own set of file descriptors, its own current directory, and its own signal handling. This is generally recommended when both tasks are SAS/C programs.
The
setting
argument to
oetaskctl
specifies whether a new subtask should be treated as a thread or a process. An argument of
0
specifies a thread, and
1
specifies a process.
Note: The thread or process decision is made when the subtask calls the first OpenEdition function, not when
the subtask is
ATTACH
ed.
oetaskctl
returns the previous
oetaskctl
setting if successful. It returns
-1
if it was unable to complete successfully.oetaskctl
is useful only if both the calling task and the subtask use OpenEdition facilities.ATTACH
,
system
#include <unistd.h> int readextlink(const char *name, char *buf, size_t size);
readextlink
reads the contents of an external link. (See the
extlink
function description in section extlink for further information on external links.)
The
name
argument specifies the name of the external link. The
buf
argument
specifies the address of a buffer into which the contents of the link should be read, and
size
specifies the size of the buffer in bytes. If
size
is
0
, no data is stored, and the length required is returned as the function value.
When you call
readextlink
in an application which was not compiled with the
option, the link name is interpreted according to the normal rules for file name interpretation. For this reason, when not compiled withposix
the file name should include a style prefix unless the default style isposix
hfs
.
Note: The name stored in
buf
will not contain any prefix.
readextlink
returns the number of bytes stored in the buffer, or the number of bytes required if
size
was zero, or
-1
if unsuccessful.getrusage
function can only be used with MVS 5.2.2 or a later release.extlink
,
lstat
#include <lclib.h> char *realpath(const char *pathname, char absname[PATH_MAX+1]);
If the feature test macro
_SASC_POSIX_SOURCE
is defined and
_POSIX_SOURCE
is not defined, the prototype is also visible in
<stdlib.h>
.
realpath
function can be used to return a standard form of an OpenEdition path name. The path name returned will be an absolute path name, which does
not involve the "." or ".." notations or symbolic links.
The
pathname
argument to
realpath
is the OpenEdition path name to be resolved. If the program was not compiled with the
compiler option,posix
pathname
should begin with an
hfs:
style prefix.
The
absname
argument should be an array of
PATH_MAX
+1 characters, in which
realpath
will store the canonical form of the path name.
PATH_MAX
is defined in the header file
<limits.h>
. If the program was not compiled with the
compiler option, the value stored will begin with anposix
hfs:
style prefix.realpath
returns the address of the standardized path name if successful, and otherwise returns
0
.realpath
function can only be used with MVS 5.2.2 or a later
release.#include <sys/sem.h> int semctl(int id, int num, int cmd, argument);
semctl
function is used to perform one of several control operations on an OpenEdition semaphore set.
Note: See the
semget
function description in section semget for general information about semaphore
sets.
The
id
argument to
semctl
specifies a semaphore set id. This argument is an id, such as the id returned by
semget
, not a semaphore set key, which might be passed as an argument to
semget
.
The
num
argument to
semctl
specifies the index of the specific semaphore to which the control operation applies. Some operations apply to the entire set. For these
operations, this argument is ignored.
The
cmd
argument specifies the operation which is to be performed. The value and type of the fourth argument (
argument
) to
semctl
, if any, is dependent on the
cmd
specification.
cmd
should be specified as one of the following symbolic values:
IPC_RMID
- Removes the semaphore set and its id from the system.
argument
is not used by this operation, and need not be specified.
IPC_SET
- Can be used to change the ownership of the semaphore set or the access rules.
argument
should be a pointer to a
struct semid_ds
, as described below. The contents of
argument->sem_perm.uid
,
argument->sem_perm.gid
and
argument->sem_perm.mode
will be copied to the system's semaphore set id data structure.
IPC_STAT
- Returns the contents of the semaphore set id data structure (see below). All elements of the data structure are stored in the object
addressed by
argument
, which should be a pointer to a
struct semid_ds
.
GETVAL
- Returns the value in the semaphore specified by the
num
argument.
argument
is not used, and may be omitted.
SETVAL
- Stores a specified value in the semaphore selected by the
num
argument.
argument
specifies the value to be stored, which should be of type
int
.
Note: Successful use of the
SETVAL
operation clears any semaphore adjustment information for this semaphore in any process. (See the
semop
function description in section semop for information on semaphore
adjustment.)
GETALL
- Stores the value of each semaphore in the set.
argument
should be a pointer to an array of unsigned shorts in which the values will be stored. The required array size can be determined by using the
IPC_STAT
command to get the number of semaphores in the set.
SETALL
- Stores values in all semaphores of the set.
argument
should be a pointer to an array of unsigned shorts containing the values to be stored. The required array size can be determined by using the
IPC_STAT
command.
Note: Successful use of the
SETAlL
operation clears any semaphore adjustment information for all semaphores in the set in any process. See the
semop
function description for information on semaphore adjustment.
GETNCNT
- Returns the number of callers waiting for the value of the semaphore selected by the
num
argument to become non-zero.
argument
is not used, and need not be specified.
GETZCNT
- Returns the number of callers waiting for the value of the semaphore selected by the
num
argument to become zero.
argument
is not used, and need not be specified.
GETPID
- Returns the process id of the process which most recently updated the semaphore selected by the
num
argument.
argument
is not used, and need not be specified.
Several of the
semctl
operations allow you to obtain or access the semaphore set id data structure, which is mapped by the
struct semid_ds
type defined in
This data structure is defined as follows:
struct semid_ds { /* permission information */ struct ipc_perm sem_perm; /* number of semaphores in set */ unsigned short sem_nsems; /* time of last semop call */ time_t sem_otime; /* time of last change by semctl */ time_t sem_ctime; };
The
ipc_perm
structure, which contains security information about the owner and the creator of the semaphore set, is defined as follows:
struct ipc_perm { /* owner's effective user ID */ uid_t uid; /* owner's effective group ID */ gid_t gid; /* creator's effective user ID */ uid_t cuid; /* creator's effective group ID */ gid_t cgid; /* read/write permission bits */ mode_t mode; };
GETVAL
,
GETNCNT
,
GETZCNT
and
GETPID
,
semctl
returns the information requested. For all others, it returns
0
if successful. In all cases, it returns
-1
if unsuccessful.semctl
function can only be used with MVS 5.2.2 or a later release.semget
,
semop
Create or find a set of semaphores
#include <sys/sem.h> int semget(key_t key, int num, int flags);
semget
function is used to create a new set of semaphores or to locate an existing set based on a key. Semaphore sets are implemented by OpenEdition,
and allow synchronization of multiple processes which do not share memory. Each semaphore in the set has an integer value, which can be raised, lowered and tested safely by multiple processes.
OpenEdition semaphores allow multiple semaphores to be processed with a single call, and support
both blocking and non-blocking processing. Semaphore sets, once created using
semget
, remain in existence until explicitly destroyed with a call to
semctl
.
The
key
argument is an integral value which identifies the semaphore set desired. A
key
value of
IPC_PRIVATE
requests a new semaphore set without an associated
key
, and which can be accessed only by the queue id returned by
semget
.
The
num
argument specifies the number of semaphores in the set, if the set is created. If the semaphore set already exists,
num
must not be larger than the number of semaphores in the set.
Note: The
num
argument may be specified as zero if the set already exists, but not for a new set.
The
flags
argument specifies zero or more option flags specifying whether or not the semaphore set already exists, and how access to the set should be
regulated. The argument should be specified as
0
for no flags, or as one or more of the following symbolic constants, combined using the or operator (|):
IPC_CREAT
- Specifies that if a semaphore set with the requested key does not exist, it should be created. This flag is ignored if
IPC_PRIVATE
is specified.
IPC_EXCL
- Specifies that a semaphore set with the requested key must not already exist. This flag is ignored if
IPC_PRIVATE
is specified, or if
IPC_CREAT
is not specified.
Additionally, any of the permission bits
S_IRUSR
,
S_IWUSR
,
S_IRGRP
,
S_IWGRP
,
S_IROTH
and
S_IWOTH
may be specified, to define what users are permitted to access or modify the semaphore set. See the
umask
function description in the SAS/C Library Reference, Volume 2, for more information about the meaning of these
flags.
semget
returns the identifier of the semaphore set if successful, or
-1
if unsuccessful.semget
function can only be used with MVS 5.2.2 or a later release.
When
semget
creates a set of semaphores, the semaphores are uninitialized. You should use the
SETALL
command of
semctl
to give the semaphores their initial values.
sascc370 -Krent -o
. This program demonstrates the use of the Open Edition IPC functions
semget()
and
semstat()
.
/*--------------------------------+ | POSIX/UNIX header files | +--------------------------------*/ #include <sys/types.h> #include <unistd.h> #include <fcntl.h> #include <sys/ipc.h> #include <sys/sem.h> /*--------------------------------+ | ISO/ANSI header files | +--------------------------------*/ #include <stdlib.h> #include <stdio.h> #include <string.h> #include <time.h> #include errno.h> /*--------------------------------+ | Types | +--------------------------------*/ /* argument for semctl() */ typedef union semun { /* for SETVAL */ int val; /* for IPC_STAT and IPC_SET */ struct semid_ds * ID; /* for GETALL and SETALL */ unsigned short * array; } SemaphoreSet; /*----------------------------------+ | Constants | +----------------------------------*/ /* semaphore key */ #define SEM_KEY (key_t)1097 /* give everyone read/write */ /* permission to semaphore */ #define SEM_PERM (S_IRUSR|S_IWUSR |S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) /*------------------------------------+ | Name: main | | Returns: exit(EXIT_SUCCESS) or | | exit(EXIT_FAILURE) | +-------------------------------------*/ int main() { /* semaphore set id */ int semID; /* semaphore flags */ int semFlags; /* number of semaphore in a set */ int numSems; /* index into semaphore set (array) */ int semNumber; /* command to semaphore. */ int semCmd; /* union of info on semaphore set */ SemaphoreSet semSet; /*-----------------------------------------*/ /* Create semaphore set with 5 semaphores. */ /* Give everyone read/write permissions. */ /*-----------------------------------------*/ /* create set with 5 semaphores */ numSems = 5; semFlags = IPC_CREAT | SEM_PERM; if ( (semID = semget (SEM_KEY, numSems, semFlags)) < 0 ) { perror("SEMSTAT: semget"); exit(EXIT_FAILURE); } /*-------------------------------------*/ /* Allocate memory to store */ /* information from semaphore set */ /*-------------------------------------*/ semSet.ID = malloc(sizeof(struct semid_ds)); if (semSet.ID == NULL) { fprintf(stderr, "ERROR: Cannot allocate memory for semaphore set stats\n"); semctl(semID, NULL, IPC_RMID, NULL); exit(EXIT_FAILURE); } /*------------------------------------*/ /* Call semctl to retrieve */ /* information from semaphore set */ /*------------------------------------*/ /* command to retrieve stats */ semCmd = IPC_STAT; /* ignored for IPC_STAT command */ semNumber = 0; if (semctl(semID, semNumber, semCmd, semSet) < 0) { perror("SEMSTAT: semctl failed to retrieve semaphore set stats"); semctl(semID, NULL, IPC_RMID, NULL); free(semSet.ID); exit(EXIT_FAILURE); } /*-----------------------------------*/ /* Print infomation retrieved from */ /* semaphore set */ /*-----------------------------------*/ printf("Semaphore Set Statistics:\n\n"); printf("\tOwner's effective user ID: %d\n", (int)semSet.ID->sem_perm.uid); printf("\tOwner's effective group ID: %d\n", (int)semSet.ID->sem_perm.gid); printf("\tCreator's effective user ID: %d\n", (int)semSet.ID->sem_perm.cuid); printf("\tCreator's effective group ID: %d\n", (int)semSet.ID->sem_perm.cgid); printf("\tPermission mode bits: %#.3o\n\n", (int)semSet.ID->sem_perm.mode); printf("\tNumber of semaphores currently in the set: %d\n", semSet.ID->sem_nsems); printf("\tTime of last semop call: %s", ctime(&semSet,ID->sem_otime)); printf("\tTime of last change: %s", ctime(&semSet.ID->sem_ctime)); /*--------------------------------------*/ /* Free memory used to store */ /* information from semaphore set */ *--------------------------------------*/ free(semSet.ID); /*---------------------------------------*/ /* Call semctl to remove semaphore set. */ /*---------------------------------------*/ if (semctl(semID, NULL, IPC_RMID, NULL) < 0) { perror("SEMSTAT: semctl failed to remove semNumber set"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); } /* end of main() */
semctl
,
semop
#include <sys/sem.h> int semop(int id, struct sembuf *ops, size_t num);
semop
function is used to update one or more semaphores from a set atomically. For each update, the caller can request either blocking until the
operation can be performed, or immediate failure of
semop
.
Note: See the
semget
function description in section semget for general information about OpenEdition
semaphores.
The
id
argument to
semop
specifies the id of the semaphore set to be updated. This argument is an id, such as the id returned by
semget
, not a semaphore set key, which might be passed as an argument to
semget
.
The
ops
argument should be a pointer to an array of one or more
sembuf
structures, each of which defines a single semaphore operation to be performed. All the operations are performed simultaneously and atomically;
that is, no changes are made to any semaphore until they can be made to all specified semaphores. The
struct sembuf
mapping is defined by
sys/sem.h
as follows:
struct sembuf { /* semaphore number */ unsigned short sem_num; /* semaphore operation code */ short sem_op; /* option flags */ short sem_flg; };
The
sem_num
field of a
struct sembuf
specifies the specific semaphore to be updated. The
sem_op
field is interpreted in the following manner:
sem_op
is a positive integer, the value of the indicated semaphore is increased by the specified amount.
sem_op
is a negative integer and the semaphore value is greater than or equal to
-sem_op
, the semaphore value is decremented by
-sem_op
.
sem_op
is a negative integer and the semaphore value is less than
-sem_op
,
semop
will either wait for the semaphore value to be raised, or return failure, depending on whether
IPC_NOWAIT
is set in
sem_flg
. If
semop
waits, once the semaphore value is greater than or equal to
-sem_op
, the value is decremented by
-sem_op
.
sem_op
is zero and the semaphore value is zero, no action is taken.
sem_op
is zero and the semaphore value is non-zero,
semop
will either wait for the semaphore value to become zero, or return failure, depending on whether
IPC_NOWAIT
is set in
sem_flg
.
The
sem_flg
field of the
sembuf
structure is used to specify option flags. It may contain
0
if no options are required, or one or more of the following symbolic constants, combined by the or operator (|).
IPC_NOWAIT
- Specifies that if the operation specified by
sem_op
cannot be immediately performed,
semop
should return failure with
errno
set to
EAGAIN
rather than waiting to perform the operation. If
IPC_NOWAIT
is not specified,
semop
will block until the operation can be performed, or until the semaphore set is destroyed or a signal is received.
SEM_UNDO
- Specifies that each successful semaphore operation be reflected in a semaphore adjustment value maintained for the process for each
semaphore changed. When the process is terminated, each semaphore updated by the process using the
SEM_UNDO
flag is adjusted by the semaphore adjustment value. If
SEM_UNDO
is used consistently
by the process, this will have the effect of undoing the semaphore updates performed by the process when it terminates.
The
num
argument to
semop
indicates the number of operations specified by the
ops
argument.
semop
returns
0
if successful, or
-1
if unsuccessful.semop
function can only be used with MVS 5.2.2 or a later release.semop
calls may be handled differently by different systems, especially if some operations specify
IPC_NOWAIT
and some do not. For best results, it is recommended that
IPC_NOWAIT
should be either specified by all elements of the
ops
array, or by none of them. -d
.
#include <sys/sem.h> #include <string.h> #include <stdlib.h> #include <errno.h> int main(int argc, char *argv[]) { /* semaphore set id */ int id; /* inital value for semaphore set */ unsigned short available[1] = { 1 }; /* return code var */ int rc; /* to reserve the semaphore */ struct sembuf reserve[1]; /* to release the semaphore */ struct sembuf release[1]; /* If this application's semaphore does not exist, create it */ /* arg1-arbitrary unique semaphore key */ /* arg2-only 1 semaphore in set */ /* arg3-don't create it */ id = semget(0x5A5C, 1, 0); if (id < 0) /* if failed, but not because semaphore doesn't exist */ if (errno != ENOENT) { badget: perror("semget"); abort(); } /* no semaphore, create it */ else { /* unless its to be deleted */ if (argc>1 && strcmp(argv[1],"-d")==0) exit(0); id=semget(0x5A5C, 1, IPC_CREAT | S_IRUSR | S_IWUSR); /* if that fails, give up */ if (id < 0) goto badget; /* Init semaphore to 1 (available) */ rc=semctl(id, 0, SETALL, available); if (rc < 0) { perror("semctl SETALL"); abort(); } } /* set up to reserve semaphore */ reserve[0].sem_num = 0; /* try to decrement semaphore by 1 */ reserve[0].sem_op = -1; /* if process dies, unreserve it */ reserve[0].sem_flg = SEM_UNDO; /* wait for semaphore to become non-zero, then zero it */ rc = semop(id, reserve, 1); if (rc < 0) { perror("semop reserve"); abort(); } /* We now have exclusive control of the guarded resource. Place code here to update the resource. */ if (argc>1 && strcmp(argv[1],"-d") == 0) { /* Check for a request to delete the semaphore */ rc = semctl(id, 0, IPC_RMID); if (rc < 0) { perror("semctl IPC_RMID"); abort(); } exit(0); } /* Release semaphore for next request */ /* set up to release semaphore */ release[0].sem_num = 0; /* try to increment semaphore by 1 */ release[0].sem_op = 1; /* if process dies, undo it */ release[0].sem_flg = SEM_UNDO; rc = semop(id, release, 1); if (rc < 0) { perror("semop release"); abort(); } exit(0); }
semctl
,
semget
#include <sys/types.h> #include <grp.h> void setgrent(void);
setgrent
function rewinds the group database so that the next call to the
getgrent
function will access the first group in the database.setgrent
has no return value.setgrent
function can only be used with MVS 5.2.2 or a later release.
If the
setgrent
function cannot be executed (for instance, because OpenEdition is not installed or running), it issues an MVS user
ABEND 1230
to indicate the error.
endgrent
,
getgrent
#include <sys/time.h> int setitimer(int kind, const struct itimerval *ival, struct itimerval *oval);
setitimer
function defines an interval timer, that is, a timer which generates a signal each time a specified time interval expires. Three different
forms of time measurement may be specified.
The
kind
argument is a symbolic constant specifying the type of time interval required. The permitted values are:
ITIMER_REAL
- Specifies a real time interval. Each time the interval expires, a
SIGALRM
signal is generated.
Note: A call to the
alarm
function will cancel a real time interval defined by
setitimer
, and similarly, a call to
setitimer
specifying
ITIMER_REAL
will cancel an outstanding
alarm
.
ITIMER_VIRTUAL
- Specifies a virtual (CPU) time interval. Each time the interval expires, a
SIGVTALRM
signal is generated.
ITIMER_PROF
- Specifies a profiling interval, measuring CPU time plus system time used in behalf of this process. Each time the interval expires,
a
SIGPROF
signal is generated.
The
ival
argument specifies the time values controlling the timer. This argument is a pointer to an
itimerval
structure, which contains two fields defined as follows:
it_value
- the time until the next expiration of the timer
it_interval
- the time between successive timer expirations.
In other words, the
it_value
field specifies the amount of time between the
setitimer
call and the first expiration, while the
it_interval
field specifies the time between successive expirations. If
it_value
is specified as zero when
setitimer
is called,
any existing interval is immediately cancelled. If
it_interval
is specified as zero, the timer will expire once, and then be cancelled.
The
it_value
and
it_interval
fields both have type
struct timeval
, which allows a time value to be specified to an accuracy of a microsecond. The structure has two
fields:
tv_sec
- the number of seconds in the interval
tv_usec
- the number of microseconds to be added to the interval.
The
oval
argument to
setitimer
is a pointer to a
struct itimerval
in which the current interval timer values are to be stored.
oval
may be specified as
NULL
, in which case, this information is not stored.
setitimer
returns
0
if successful, or
-1
if unsuccessful.setitimer
function can only be used with MVS 5.2.2 or a later release.
Programs which are not invoked from the shell must call the
oesigsetup
function to enable handling of the timer signals before invoking
setitimer
.
getitimer
#include <sys/resource.h> int setpriority(int kind, int id, int prio);
setpriority
function changes the OpenEdition priority of a process, or the priority of all processes in a process group or belonging to a user. See the
getpriority
function description in section getpriority for further information on OpenEdition
priorities.
The
kind
argument to
setpriority
should be specified as a symbolic constant indicating the scope of the priority change. The permissible values
are:
PRIO_PROCESS
- specifies that the
id
argument is the pid of the process whose priority is to be changed
PRIO_PGRP
- specifies that the
id
argument is the pid of the process group whose processes should be changed in priority
PRIO_USER
- specifies that the
id
argument is the uid of the user whose processes are to be changed in priority.
The
id
argument specifies the process id, process group id, or user id whose priority should be changed. If
id
is
0
, it specifies the calling process, process group or user.
The
prio
argument specifies the requested new priority. It should be a signed integer between -20 to 19. Lower numbers indicate higher
priority.
Note: OpenEdition sites must enable the use of the
setpriority
function. If the use of
setpriority
has not been enabled, any use of
setpriority
will fail with
errno
set to
ENOSYS
.
setpriority
returns
0
if successful, or
-1
if unsuccessful. setpriority
function can only be used with MVS 5.2.2 or a later release.chpriority
,
getpriority
, and
setpriority
. chpriority
,
getpriority
#include <sys/types.h> #include <pwd.h> void setpwent(void);
setpwent
function rewinds the user database so that the next call to the
getpwent
function will access the first user in the database.setpwent
has no return value.setpwent
function can only be used with MVS 5.2.2 or a later release.
If the
setpwent
function cannot be executed (for instance, because OpenEdition is not installed or running), it issues an MVS user
ABEND 1230
to indicate the error.
endpwent
,
getpwent
Set real and/or effective group id
#include <sys/types.h> #include <unistd.h> int setregid(gid_t realgid, gid_t effgid);
setregid
function is used to set the real and/or the effective group ids for the calling process. A superuser or daemon process has the ability to set
any valid group id. Other processes are limited in their use of
setregid
.
Note: See the IBM OpenEdition MVS Assembler Callable Services publication, SC28-2899, for more information on the
use of
setregid
by unprivileged processes.
The
realgid
argument to
setregid
specifies the new real group id. If
realgid
is specified as
-1
, the real group id is unchanged. The
effgid
argument to
setregid
specifies the new effective group id.
If
effgid
is specified as
-1
, the effective group id is unchanged.
setregid
returns
0
if successful, or
-1
if unsuccessful.setregid
function can only be used with MVS 5.2.2 or a later release.sascc370 -Krent -o
. This program demonstrates the use of the OpenEdition functions
setregid()
and
setreuid()
.
/*---------------------------------------+ | POSIX/UNIX header files | +---------------------------------------*/ #include <sys/types.h> #include <unistd.h> /*---------------------------------------+ | ISO/ANSI header files | +---------------------------------------*/ #include <stdlib.h> #include <stdio.h> #include <errno.h> /*---------------------------------------+ | Name: main | | Returns: exit(EXIT_SUCCESS) or | | exit(EXIT_FAILURE) | +---------------------------------------*/ int main() { /* generic return code */ int rc; /* real group ID of calling process */ gid_t rgid; /* effective group ID of calling process */ gid_t egid; /* real user ID of calling process */ uid_t ruid; /* effective user ID of calling process */ uid_t euid; /*----------------------------------------------*/ /* Get the real and effective group and user */ /* ids for this process. */ /*----------------------------------------------*/ printf("\nGet the Real and Effective Group and User IDs\n"); /* get real group ID */ rgid = getgid(); /* get effective group ID */ egid = getegid(); /* get real user ID */ ruid = getuid(); /* get effective user ID */ euid = geteuid(); printf(" The real group id is: %d\n", (int)rgid); printf("The effective group id is: %d\n", (int)egid); printf(" The real user id is: %d\n", (int)ruid); printf(" The effective user id is: %d\n", (int)euid); /*-----------------------------------------------*/ /* Set the real and effective group id for this */ /* process. */ /*-----------------------------------------------*/ printf("\nSetting the Real and Effective Group ID\n"); errno = 0; egid = rgid; /* -1 implies use current real group id (nochg) */ rgid = (gid_t)-1; rc = setregid(rgid, egid); /* Test for Error */ if (rc == -1) { perror("Call to setregid failed"); exit(EXIT_FAILURE); } /*--------------------------------------------*/ /* Set the real and effective user id for */ /* this process. */ /*--------------------------------------------*/ printf("\nSetting the Real and Effective User ID\n"); errno = 0; euid = ruid; /* -1 implies use current real user id (nochg) */ ruid = (gid_t)-1; rc = setreuid(ruid, euid); /* Test for Error */ if (rc == -1) { perror("Call to setreuid failed"); exit(EXIT_FAILURE); } /*-----------------------------------------*/ /* Get the real and effective group and */ /* user ids */ /*-----------------------------------------*/ printf("\nThe Real and Effective Group and User IDs are now!\n"); /* get real group ID */ rgid = getgid(); /* get effective group ID */ egid = getegid(); /* get real user ID */ ruid = getuid(); /* get effective user ID */ euid = geteuid(); printf(" The real group id is: %d\n", (int)rgid); printf("The effective group id is: %d\n", (int)egid); printf(" The real user id is: %d\n", (int)ruid); printf(" The effective user id is: %d\n", (int)euid); exit(EXIT_SUCCESS); } /* end of main() */
getegid
,
getgid
,
setegid
,
setgid
Set real and/or effective user id
#include <sys/types.h> #include <unistd.h> int setreuid(uid_t realuid, uid_t effuid);
setreuid
function is used to set the real and/or the effective user ids for the calling process. A superuser or daemon process has the ability to set
any valid user id. Other processes are limited in their use of
setreuid
.
Note: See the IBM OpenEdition MVS Assembler Callable Services publication, SC28-2899, for more information on the
use of
setreuid
by unprivileged processes.
The
realuid
argument to
setreuid
specifies the new real user id. If
realuid
is specified as
-1
, the real user id is unchanged. The
effuid
argument to
setreuid
specifies the new effective user id.
If
effuid
is specified as
-1
, the effective user id is unchanged.
setreuid
returns
0
if successful, or
-1
if unsuccessful.setreuid
function can only be used with MVS 5.2.2 or a later release.setregid()
and
setreuid()
.geteuid
,
getuid
,
seteuid
,
setuid
Define OpenEdition resource limits
#include <sys/resource.h> int setrlimit(int resource, const struct rlimit *info);
setrlimit
function defines resource limits for the calling process. Limits are expressed as a pair of integers, a soft limit and a hard limit. The soft
limit controls the amount of the resource the program is actually allowed to consume, while the hard limit specifies an upper bound on the soft limit. The soft limit can be raised up to the hard limit
value, but the hard limit can only be raised by a privileged (superuser) caller.
The
resource
argument defines the resource to which the limit applies. It should be specified as one of the symbolic values defined
below.
RLIMIT_AS
- Specifies the maximum size in bytes of the address space for this process. If the limit is exceeded, memory allocation functions such
as
malloc
or
GETMAIN
will be unable to allocate additional memory.
Note: Setting this limit too low could cause the program to be terminated due to the
inability of the library to obtain more
stack space.
RLIMIT_CORE
- Specifies the maximum size in bytes of an OpenEdition memory dump (core file) for this process. A limit of
0
will prevent a dump file from being created.
RLIMIT_CPU
- Specifies the maximum CPU time in seconds allowed for this address space. When the limit is exceeded, a
SIGXCPU
signal is sent to the process, and a small amount of additional time is allocated to allow a signal handler to
execute.
RLIMIT_DATA
- Specifies the maximum amount of memory available for data allocation using
malloc
or
calloc
. This limit is not enforced under OpenEdition MVS, and an attempt to set the limit lower than
RLIM_INFINITY
will be rejected.
RLIMIT_FSIZE
- Specifies the maximum file size in bytes allowed for this process. A limit of
0
will prevent new files from being created. If an attempt is made to extend a file beyond the limit, a
SIGXFSZ
signal is sent to the process. The limit applies only to OpenEdition HFS files, not to standard MVS data sets.
RLIMIT_NOFILE
- The maximum number of file descriptors the process may have open. Any attempt to open a file with a file number above the limit
will fail with
errno
set to
EMFILE
.
RLIMIT_STACK
- The maximum amount of memory available for stack allocation. This limit is not enforced under OpenEdition MVS, and an attempt to
set the limit lower than
RLIM_INFINITY
will be rejected.
info
argument is a pointer to a structure of type
struct rlimit
, which defines the soft and hard limits. The structure contains the following fields:
setrlimit
returns
0
if successful, or
-1
if unsuccessful.setrlimit
function can only be used with MVS 5.2.2 or a later release.
Note: Resource limits defined by
setrlimit
are propagated to child processes created by
fork
or
exec
.
getrlimit
Attach a shared memory segment
#include <sys/shm.h> void *shmat(int id, const void *addr, int flags);
shmat
function is used to attach a shared memory segment to a process, so that the memory contents can be accessed.
Note: See the
shmget
function description in section shmget for general information about shared memory
segments.
The
id
argument to
shmat
specifies a shared memory segment id. This argument is an id, such as the id returned by
shmget
, not a memory segment key, which might be passed as an argument to
shmget
.
The
addr
argument to
shmat
specifies a pointer value indicating the address at which the memory segment is to be attached. If
addr
is
NULL
, the segment will be attached at an address selected by the system. If
addr
is specified,
shmat
will fail if the segment cannot be attached as specified because memory is already allocated near the address specified.
Note: The
flag bit
SHM_RND
influences the interpretation of
addr
, as described below.
The
flags
argument specifies zero or more option flags. The argument should be specified as
0
for no flags, or as one or more of the following symbolic constants, combined using the or operator (|):
SHM_RDONLY
- Specifies that the segment is attached read-only, that is, the process will be able to read the memory contents, but not change
them.
SHM_RND
- Specifies that the address specified by
addr
will be rounded down to a multiple of the page size. The page size is defined by the symbolic constant
SHMLBA
.
shmat
returns the address of the attached segment, or (void *)
-1
if unsuccessful.shmat
function can only be used with MVS 5.2.2 or a later release.
Note: A site can impose limits on the size and number of shared memory
segments that can be attached.
sascc370 -Krent -o
. This program uses the functions
shmat()
,
shmctl()
,
shmdt()
, and
shmget()
to establish an IPC Client using a Shared Memory Segment.
/*-------------------------------------+ | POSIX/UNIX header files | +-------------------------------------*/ #include <fcntl.h> #include <sys/types.h> #include <sys/ipc.h> #include sys/shm.h> /*-------------------------------------+ | ISO/ANSI header files | +-------------------------------------*/ #include <stdlib.h> #include <stdio.h> #include <string.h> #include <errno.h> /*-------------------------------------+ | Constants | +-------------------------------------*/ /* memory segment character value */ #define MEM_CHK_CHAR '*' /* shared memory key */ #define SHM_KEY (key_t)1097 #define SHM_SIZE (size_t)256 /* size of memory segment (bytes) */ /* give everyone read/write */ /* permission to shared memory */ #define SHM_PERM (S_IRUSR|S_IWUSR |S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) /*------------------------------------+ | Name: main | | Returns: exit(EXIT_SUCCESS) or | | exit(EXIT_FAILURE) | +------------------------------------*/ int main() { /* loop counter */ int i; /* shared memory segment id */ int shMemSegID; /* shared memory flags */ int shmFlags; /* ptr to shared memory segment */ char * shMemSeg; /* generic char pointer */ char * cptr; /*-------------------------------------*/ /* Get the shared memory segment for */ /* SHM_KEY, which was set by */ /* the shared memory server. */ /*-------------------------------------*/ shmFlags = SHM_PERM; if ( (shMemSegID = shmget(SHM_KEY, SHM_SIZE, shmFlags)) < 0 ) { perror("CLIENT: shmget"); exit(EXIT_FAILURE); } /*-----------------------------------------*/ /* Attach the segment to the process's */ /* data space at an address */ /* selected by the system. */ /*-----------------------------------------*/ shmFlags = 0; if ( (shMemSeg = shmat(shMemSegID, NULL, shmFlags)) == (void *) -1 ) { perror("SERVER: shmat"); exit(EXIT_FAILURE); } /*-------------------------------------------*/ /* Read the memory segment and verify that */ /* it contains the values */ /* MEM_CHK_CHAR and print them to the screen */ /*-------------------------------------------*/ for (i=0, cptr = shMemSeg; i < SHM_SIZE; i++, cptr++) { if ( *cptr != MEM_CHK_CHAR ) { fprintf(stderr, "CLIENT: Memory Segment corrupted!\n"); exit(EXIT_FAILURE); } putchar( *cptr ); /* print 40 columns across */ if ( ((i+1) % 40) == 0 ) { putchar('\n'); } } putchar('\n'); /*--------------------------------------------*/ /* Clear shared memory segment. */ /*--------------------------------------------*/ memset(shMemSeg, '\0', SHM_SIZE); /*------------------------------------------*/ /* Call shmdt() to detach shared */ /* memory segment. */ /*------------------------------------------*/ if ( shmdt(shMemSeg) < 0 ) { perror("SERVER: shmdt"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); } /* end of main() */
sascc370 -Krent -o
. This program uses the functions
shmat()
,
shmctl()
,
shmdt()
, and
shmget()
to establish an IPC Server using a Shared Memory Segment.
Note: One cannot use the Extended Message structure
to send a message, i.e., call
shmsnd()
with this structure. Attempting to do so will cause the program to "hang".
/*--------------------------------------+ | POSIX/UNIX header files | +--------------------------------------*/ #include <sys/types.h> #include <unistd.h> #include <fcntl.h> #include <sys/ipc.h> #include >sys/shm.h> /*--------------------------------------+ | ISO/ANSI header files | +--------------------------------------*/ #include <stdlib.h> #include <stdio.h> #include <string.h> #include <time.h> #include <errno.h> /*--------------------------------------+ | Constants | +--------------------------------------*/ /* value to fill memory segment */ #define MEM_CHK_CHAR '*' /* shared memory key */ #define SHM_KEY (key_t)1097 /* size of memory segment (bytes) */ #define SHM_SIZE (size_t)256 /* give everyone read/write permission */ /* to shared memory */ #define SHM_PERM (S_IRUSR|S_IWUSR |S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) /*----------------------------------------+ | Name: main | | Returns: exit(EXIT_SUCCESS) or | | exit(EXIT_FAILURE) | +-----------------------------------------*/ int main() { /* shared memory segment id */ int shMemSegID; /* shared memory flags */ int shmFlags; /* ptr to shared memory segment */ char * shMemSeg; /*---------------------------------------*/ /* Create shared memory segment */ /* Give everyone read/write permissions. */ /*---------------------------------------*/ shmFlags = IPC_CREAT | SHM_PERM; if ( (shMemSegID = shmget(SHM_KEY, SHM_SIZE, shmFlags)) < 0 ) { perror("SERVER: shmget"); exit(EXIT_FAILURE); } /*-------------------------------------------*/ /* Attach the segment to the process's data */ /* space at an address */ /* selected by the system. */ /*-------------------------------------------*/ shmFlags = 0; if ( (shMemSeg = shmat(shMemSegID, NULL, shmFlags)) == (void *) -1 ) { perror("SERVER: shmat"); exit(EXIT_FAILURE); } /*-------------------------------------------*/ /* Fill the memory segment with MEM_CHK_CHAR */ /* for other processes to read */ /*-------------------------------------------*/ memset(shMemSeg, MEM_CHK_CHAR, SHM_SIZE); /*-----------------------------------------------*/ /* Go to sleep until some other process changes */ /* first character */ /* in the shared memory segment. */ /*-----------------------------------------------*/ while (*shMemSeg == MEM_CHK_CHAR) { sleep(1); } /*------------------------------------------------*/ /* Call shmdt() to detach shared memory segment. */ /*------------------------------------------------*/ if ( shmdt(shMemSeg) < 0 ) { perror("SERVER: shmdt"); exit(EXIT_FAILURE); } /*--------------------------------------------------*/ /* Call shmctl to remove shared memory segment. */ /*--------------------------------------------------*/ if (shmctl(shMemSegID, IPC_RMID, NULL) < 0) { perror("SERVER: shmctl"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); } /* end of main() */
shmctl
,
shmdt
,
shmget
Control a shared memory segment
#include <sys/shm.h> int shmctl(int id, int cmd, struct shmid_ds *buf);
shmctl
function is used to perform one of several control operations on a shared memory segment.
Note: See the
shmget
function description in section shmget for general information about shared memory
segments.
The
id
argument to
shmctl
specifies a shared memory segment id. This argument is an id, such as the id returned by
shmget
, not a memory segment key, which might be passed as an argument to
shmget
.
The
cmd
argument should be specified as a symbolic constant specifying the specific operation to be performed by
shmctl
. The constant values are described below.
Several of the
shmctl
operations allow you to obtain or access the shared memory id data structure, which is mapped by the
struct shmid_ds
type defined in
sys/shm.h
.
This data structure is defined as follows:
struct shmid_ds { /* permission information */ struct ipc_perm shm_perm; /* segment size */ int shm_segsz; /* process id for last shm operation */ pid_t shm_lpid; /* process id of creator */ pid_t shm_cpid; /* number of times segment attached */ unsigned shm_nattch; /* time of last shmat call */ time_t shm_atime; /* time of last shmdt call */ time_t shm_dtime; /* time of last change by shmget/shmctl */ time_t shm_ctime; };
The
ipc_perm
structure contains security information about the owner and the creator of the memory segment and is defined as follows:
struct ipc_perm { /* owner's effective user ID */ uid_t uid; /* owner's effective group ID */ gid_t gid; /* creator's effective user ID */ uid_t cuid; /* creator's effective group ID */ gid_t cgid; /* read/write permission bits */ mode_t mode; };
For
shmctl
operations which access or modify the shared memory id data structure, the
buf
argument addresses a
struct shmid_ds
, used as described below. For other operations, the
buf
argument is ignored.
The
cmd
values accepted by
shmctl
and their meanings are as follows:
IPC_RMID
- Removes the shared memory segment and its id from the system, after all users have detached it. The
buf
argument is not used by this operation.
IPC_SET
- Can be used to change the ownership of a shared memory segment or the access rules. The contents of
buf->shm_perm.uid
,
buf->shm_perm.gid
and
buf->shm_perm.mode
will
be copied to the shared memory id data structure.
IPC_STAT
- Returns the contents of the shared memory id data structure. All elements of the data structure are stored in the object addressed by
buf
.
shmctl
returns
0
if successful, or
-1
if unsuccessful.shmctl
function can only be used with MVS 5.2.2 or a later release.shmat()
,
shmctl()
,
shmdt()
, and
shmget()
to establish an IPC Client using a Shared Memory Segment.shmat()
,
shmctl()
,
shmdt()
, and
shmget()
to establish an IPC Server using a Shared Memory Segment.shmat
,
shmdt
,
shmget
Detach a shared memory segment
#include <sys/shm.h> int shmdt(const void *addr);
shmdt
function is used to detach a shared memory segment from a process. The segment is not destroyed, even if the calling process is the only process
which has it attached. (See the
shmget
function description in section shmget for general information about shared memory
segments.)
The
addr
argument specifies a pointer value to the location at which the shared segment is attached.
shmdt
returns
0
if successful, or
-1
if unsuccessful.shmdt
function can only be used with MVS 5.2.2 or a later release.shmat()
,
shmctl()
,
shmdt()
, and
shmget()
to establish an IPC Client using a Shared Memory Segment. shmat()
,
shmctl()
,
shmdt()
, and
shmget()
to establish an IPC Server using a Shared Memory Segment.shmat
,
shmctl
,
shmget
Create or find a shared memory segment
#include <sys/shm.h> int shmget(key_t key, size_t size, int flags);
shmget
function is used to create a new shared memory segment or to locate an existing one based on a key. Shared memory segments are memory areas
which can be shared by several processes and which, once created, continue to exist until explicitly deleted using the
shmctl
function.
The
key
argument is an integral value which identifies the shared memory segment desired. A
key
value of
IPC_PRIVATE
requests a new shared memory segment without an associated key, and which can be accessed only by the segment id returned by
shmget
.
The
size
argument specifies the required size of the segment. If the segment already exists,
size
must be no greater than the size specified when the segment was created.
The
flags
argument specifies zero or more option flags specifying whether or not the segment already exists, and how access to the segment should be
regulated. The argument should be specified as
0
for no flags, or as one or more of the following symbolic constants, combined using the or operator (|):
IPC_CREAT
- Specifies that if a segment with the requested key does not exist, it should be created. This flag is ignored if
IPC_PRIVATE
is specified.
IPC_EXCL
- Specifies that a segment with the requested key must not already exist. This flag is ignored if
IPC_PRIVATE
is specified, or if
IPC_CREAT
is not specified.
Additionally, any of the permission bits
S_IRUSR
,
S_IWUSR
,
S_IRGRP
,
S_IWGRP
,
S_IROTH
and
S_IWOTH
may be specified, to define what users are permitted to access or modify the memory segment. See the
umask
function description in the SAS/C Library Reference, Volume 2, for more information about the meaning of these
flags.
shmget
returns the identifier of the shared memory segment if successful, or
-1
if unsuccessful.shmget
function can only be used with MVS 5.2.2 or a later release.
Note: A site can impose limits on the size and number of shared memory
segments created.
shmat()
,
shmctl()
,
shmdt(),
and
shmget()
to establish an IPC Client using a Shared Memory Segment. shmat()
,
shmctl()
,
shmdt()
, and
shmget()
to establish an IPC Server using a Shared Memory Segment. sascc370 -Krent -o
. This program demonstrates the functions
shmget()
and
shmstat()
. It uses the
shmget()
function to create IPC shared memory segment and then uses the
shmctl()
function to retrieve statistics on the newly created memory segment.
/*-------------------------------------+ | POSIX/UNIX header files | +-------------------------------------*/ #include <sys/types.h> #include <unistd.h> #include <fcntl.h> #include <sys/ipc.h> #include <sys/shm.h> /*-------------------------------------+ | ISO/ANSI header files | +-------------------------------------*/ #include <stdlib.h> #include <stdio.h> #include <string.h> #include <time.h> #include <errno.h /*-------------------------------------+ | Types | +-------------------------------------*/ /* shared memory segment structure */ typedef struct shmid_ds ShMemSeg; /*--------------------------------------+ | Constants | +--------------------------------------*/ /* shared memory key */ #define SHM_KEY (key_t)1097 /* size of memory segment (bytes) */ #define SHM_SIZE (size_t)256 /* give everyone read/write */ /* permission to shared memory */ #define SHM_PERM (S_IRUSR|S_IWUSR |S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) /*--------------------------------------+ | Name: main | | Returns: exit(EXIT_SUCCESS) or | | exit(EXIT_FAILURE) | +--------------------------------------*/ int main() { /* shared memory segment id */ int shMemSegID; /* shared memory flags */ int shmFlags; /* command to shared memory */ int shmCmd; /* ptr to shared mem id structure */ ShMemSeg * shMemSeg; /*--------------------------------------*/ /* Create shared memory segment */ /* Give everyone read/write permissions */ /*--------------------------------------*/ shmFlags = IPC_CREAT | SHM_PERM; if ( (shMemSegID = shmget(SHM_KEY, SHM_SIZE, shmFlags)) < 0 ) { perror("SHMSTAT: shmget"); exit(EXIT_FAILURE); } /*-------------------------------------------*/ /* Allocate memory to store information */ /* from shared memory seg */ /*-------------------------------------------*/ shMemSeg = malloc(sizeof(ShMemSeg)); if (shMemSeg == NULL) { fprintf(stderr, "ERROR: Cannot allocate memory for shared mem stats\n"); exit(EXIT_FAILURE); } /*---------------------------------------------*/ /* Call shmctl to retrieve information from */ /* shared memory seg */ /*---------------------------------------------*/ shmCmd = IPC_STAT; if (shmctl(shMemSegID, shmCmd, shMemSeg) < 0) { perror("SHMSTAT: shmctl failed to retrieve shared mem stats"); free(shMemSeg); exit(EXIT_FAILURE); } /*---------------------------------------------*/ /* Print infomation retrieved from shared */ /* memory segment */ /*---------------------------------------------*/ printf("Shared Memory Segment statistics:\n\n"); printf("\tSegment owner's effective user ID: %d\n",(int)shMemSeg->shm_perm.uid); printf("\tSegment owner's effective group ID: %d\n",(int)shMemSeg->shm_perm.gid); printf("\tSegment creator's effective user ID: %d\n",(int)shMemSeg->shm_perm.cuid); printf("\tSegment creator's effective group ID: %d\n",(int)shMemSeg->shm_perm.cgid); printf("\tSegment permission mode bits: %#.3o\n\n",(int)shMemSeg->shm_perm.mode); printf("\tShared Memory Segment size: %d\n",shMemSeg->shm_segsz); printf("\tProcess id of last Segment operation: %d\n",(int)shMemSeg->shm_lpid); printf("\tProcess id of Segment creator: %d\n",(int)shMemSeg->shm_cpid); printf("\tNumber of times Segment attached: %u\n",shMemSeg->shm_nattch); printf("\tTime of last shmat call: %s", ctime(&shMemSeg->shm_atime)); printf("\tTime of last shmdt call: %s", ctime(&shMemSeg->shm_dtime)); printf("\tTime of last change: %s", ctime(&shMemSeg->shm_ctime)); /*-------------------------------------------*/ /* Free memory used to store information */ /* from shared memory seg */ /*-------------------------------------------*/ free(shMemSeg); /*---------------------------------------------*/ /* Call shmctl to remove shared memory segment */ /*---------------------------------------------*/ shmCmd = IPC_RMID; if (shmctl(shMemSegID, shmCmd, NULL) < 0) { perror("SHMSTAT: shmctl failed to remove shared mem"); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); } /* end of main() */
shmat
,
shmctl
,
shmdt
Intercept longjmp without changing signal mask
#include <lcjmp.h> int sigblkjmp(sigjmp_buf env);
sigblkjmp
requests interception of calls to
longjmp
or
siglongjmp
that could terminate the calling function. When you call
sigblkjmp
, it always returns
0
. If a call to
longjmp
or
siglongjmp
is later intercepted, the call to
sigblkjmp
is resumed and upon completion returns the integer argument that was passed to
longjmp
. The
env
variable is modified to indicate the target of the intercepted call so it can be resumed by a call to
siglongjmp
.
Note: When a
siglongjmp
call is intercepted due to the use of
sigblkjmp
, the signal mask has not yet been changed.
After a call to
longjmp
or
siglongjmp
is intercepted,
sigblkjmp
must be re-issued if continued interception is wanted.
Because
exit
is implemented as a
longjmp
to the caller of
main
, you can use
sigblkjmp
to intercept program exit.
sigblkjmp
normally returns
0
; it returns a non-zero value if a call to
longjmp
or
siglongjmp
has been intercepted (in which case
sigblkjmp
returns the value of the second argument passed to
longjmp
or
siglongjmp
).class auto
and
register
whose values are changed between the
sigblkjmp
and
siglongjmp
calls have indeterminate values on return to
sigblkjmp
.sigblkjmp
can be used to enable a function to release resources even if terminated by a call to
longjmp
or
siglongjmp
in a function that
sigblkjmp
calls:
#include <stdio.h> #include <lcjmp.h> #include <stdlib.h> #include <lcsignal.h> sigjmp_buf env; static void get_resource(void), use_resource(void); int main() { int code; if (code = sigsetjmp(env,1)) goto escape; get_resource(); puts("get_resource returned normally."); exit(0); escape: printf("Executing escape routine for ", "error %d\n", code); exit(code); } static void get_resource(void) { int code; sigjmp_buf my_env; sigset_t blockall, oldset; sigfillset(&blockall); /* block all signals while allocating and using resource */ sigprocmask(SIG_SETMASK, &blockall, &oldset); /* Allocate resource here */ if (code = sigblkjmp(my_env)) goto release; puts("Resources allocated."); /* Free resource here */ use_resource(); puts("use_resource returned normally, " "get_resource is freeing resources."); setprocmask(SIG_SETMASK, &oldset, NULL); return; release: printf("use_resource indicated ", "error %d\n", code); puts("Resources now freed, proceeding ", "with longjmp."); siglongjmp(my_env, code); } static void use_resource(void) { puts("Entering use_resource."); /* Attempt to use resource here. */ puts("Error 3 detected, ", "calling siglongjmp."); siglongjmp(env, 3); puts("This statement will not ", "be executed."); }
blkjmp
,
longjmp
,
setjmp
,
siglongjmp
,
sigsetjmp
#include <spawn.h> pid_t spawn(const char *path, int count, const int fd_map[], struct inheritance *inh, const char *argv[], const char *envp[]);
spawn
function creates a new process to run an executable program in the hierarchical file system. If indicated by an environment variable, an attempt
is made to execute the process in the same address space as the caller.
spawn
permits the calling process to remap file descriptors, alter the signal handling, and change the process group of the new
process.
The
path
argument specifies the name of the HFS file to be executed.
The
count
specifies the number of file descriptors to be remapped, and
fd_map
specifies a list of file descriptors that describe the remapping. If
fd_map
is
0
, no remapping is performed, and the child process receives all file descriptors open in the current process. If
fd_map
is not
0
, then for n less than
count
, file descriptor n in the child process is mapped to be the same file as
fd_map[n]
in the parent process. If
fd_map[n]
has the value
SPAWN_FDCLOSED
, file descriptor n
will be closed in the child process. All file descriptors greater than or equal to
count
will be closed in the child process.
The
inh
argument specifies a pointer to an inheritance structure which defines how signals and process groups should be handled in the child process. The
inheritance structure contains the following fields:
flags |
bit flags defining required inheritance options |
pgroup |
an alternate process group for the new process |
sigmask |
a new signal mask for the child process |
sigdefault |
a set of signals to restore to default handling |
ctlttyfd |
a controlling terminal file descriptor for the child process |
The
inheritance
structure can be used to request the following inheritance options.
If the
SPAWN_SETGROUP
flag is set in
inh->flags
, the child's process group will be set as specified by
inh->pgroup
. If
inh->pgroup
is
0
, the child will be created in a new process group. Otherwise, the new process will be assigned to the specified
process group. If
SPAWN_SETGROUP
is not set, the new process is part of the same process group as the parent.
If the
SPAWN_SETSIGDEF
flag is set in
inh->flags
, each signal specified in
inh->sigdefault
(a value of type
sigset_t
) is reset to default handling in the child process. All other signals inherit their handling from the parent process, as with the
exec
functions.
If the
SPAWN_SETSIGDEF
flag is not set, all signals inherit their handling from the parent in the manner of
exec
. If the
SPAWN_SETSIGMASK
flag is set in
inh->flags
, the initial signal mask for the new child process is as specified by
inh->sigmask
(a
value of type
sigset_t
). If the
SPAWN_SETSIGMASK
flag is not set, the child process inherits the signal mask of the parent process.
If the
SPAWN_SETTCPGRP
flag is set in
inh->flags
, the file descriptor specified by
inh->ctlttyfd
becomes the controlling terminal for the child process's foreground process group. If the
SPAWN_SETTCPGRP
flag is not set, the child process inherits the controlling terminal file descriptor from the parent
process.
The
argv
argument to
spawn
specifies a list of arguments to be passed to the new process.
argv
is an array of strings, where
argv[0]
contains the name of the executable file, and the final element of
argv
is a
NULL
pointer value.
The
envp
argument to
spawn
specifies an array of environment variable values. Each element of the array is a string of the form:
The last element of the array must be a
NULL
pointer to indicate the end of the array. If the new process should inherit the environment variables of the calling process, pass the external
environment variable pointer
environ
as
envp
.
Certain environment variables may be defined in the
envp
array to modify the operation of
spawn
. These are as follows:
If the environment variable
_BPX_SHAREAS
is defined and has the value
YES
,
spawn
will attempt to create the new process in the same address space as the parent address space.
Note: The
spawn
may be unable to use the same address space for security or performance reasons, in which case a new address
space will be created for the process.
Note: When several processes run in a single address space, some requirements of the
standards are violated. (For instance, it is not possible for the child process to execute after termination of the parent in this case.)posix
_BPX_SHAREAS
is not defined, or has any value other than
YES
, the child process
will be executed in a new address space.
If the environment variable
_BPX_SPAWN_SCRIPT
is defined and set to
YES
, the spawn service recognizes an attempt to use
spawn
to invoke a shell script, and instead spawns a copy of the shell to run the script. If the environment variable is not defined, or has some value
other than
YES
, the script is
treated as a non-executable file.
spawn
returns the process id of the new process. If unsuccessful,
spawn
returns
-1
.spawn
function can only be used with MVS 5.2.2 or a later release./* This example must be compiled with the posix compiler option */ #include <spawn.h> #include <unistd.h> #include <signal.h> /* posix environment variable ptr */ extern char **environ; pid_t subprocess(const char *file, int input_fd, int output_fd, int local) { /* This function uses the spawn system call to create a subprocess. The file descriptor specified by input_fd is used as the new process' standard input, and the file descriptor specified by output_fd is used as the new process' standard output. If the flag local is non-zero, the new process is created in the same address space. If local is non-zero, the process is created in a new address space, and the signal SIGHUP is set to be ignored in the new process. */ /* file map for new process */ int fd_map[3]; /* inheritance structure */ struct inheritance inh; /* argument vector for new process */ const char *argv[2]; /* old handler for SIGHUP */ void (*hup_hndlr)(int); pid_t newpid; /* use input_fd as new stdin */ fd_map[0] = input_fd; /* use output_fd as new stdout */ fd_map[1] = output_fd; /* use same file for stderr */ fd_map[2] = 2; inh.flags = SPAWN_SETSIGDEF; /* set all signals to default in new process */ sigfillset(inh.sigdefault); /* if spawning non-locally */ if (local == 0) { /* don't default SIGHUP */ sigdelset(inh.sigdefault, SIGHUP); /* temporarily ignore SIGHUP */ hup_hndlr = signal(SIGHUP, SIG_IGN); } setenv("_BPX_SHAREAS", local? "YES": "NO"); /* set up argv for new process, */ argv[0] = file; /* no args */ argv[1] = 0; /* spawn new procdess */ newpid = spawn(file, 3, fd_map, &inh, argv, environ); /* restore SIGHUP handling if necessary */ if (local == 0) signal(SIGHUP, hup_hndlr); /* return id of new process */ return newpid; }
execve
,
fork
,
oeattache
,
spawnp
#include <spawn.h> pid_t spawnp(const char *file, int count, const int fd_map[], struct inheritance *inh, const char *argv[], const char *envp[]);
spawnp
function creates a new process to run an executable program in the hierarchical file system. It performs the same functions as the
spawn
function, except the path portion of the filename is optional.
The
file
argument to
spawnp
is the name of the HFS file to be executed. If the name includes path information, then the file is invoked exactly as specified. If no path
information is specified, a search is made of the directories specified by the
PATH
environment variable (as specified by the
envp
argument) until an executable file of the specified name is located.
All other arguments to
spawnp
are interpreted exactly like the corresponding argument to
spawn
.
spawnp
returns the process id of the new process. If unsuccessful,
spawnp
returns
-1
.spawnp
function can only be used with MVS 5.2.2 or a later release.execve
,
fork
,
oeattache
,
spawn
Get session leader id for a process
#include <sys/types.h> #include <termios.h> pid_t tcgetsid(int fileDescriptor);
tcgetsid
function returns the process group id of the session for which a specific file descriptor is the controlling terminal. The argument
fileDescriptor
specifies the terminal file descriptor for which the information is required.tcsetgid
returns the process group id for the associated session, or
-1
if it fails (for instance, if the file associated with
fileDescriptor
is not a controlling terminal).tcgetsid
function can only be used with MVS 5.2.2 or a later release.sascc370 -Krent -o
. This program demonstrates the use of the Open Edition function
tcgetsid()
.
/*----------------------------------+ | POSIX/UNIX header files | +----------------------------------*/ #include <sys/types.h> #include <termios.h> #include <errno.h> /*----------------------------------+ | ISO/ANSI header files | +----------------------------------*/ #include <stdlib.h> #include <stdio.h> #include <errno.h> /*----------------------------------+ | Name: main | | Returns: exit(EXIT_SUCCESS) or | | exit(EXIT_FAILURE) | +----------------------------------*/ int main() { /* session leader id for stdin */ pid_t stdin_SID; /* session leader id for stdout */ pid_t stdout_SID; /* session leader id for stderr */ pid_t stderr_SID; /*----------------------------------------*/ /* Get the Session Leader ID for STDIN */ /*----------------------------------------*/ printf("\nGet the Session Leader ID for STDIN\n"); stdin_SID = tcgetsid(STDIN_FILENO); /* Test for Error */ if (stdin_SID == -1) { fprintf(stderr,"Could not get SID for stdin\n"); exit(EXIT_FAILURE); } else { printf(" The Session Leader ID for stdin: %d\n", (int)stdin_SID); } /*--------------------------------------------*/ /* Get the Session Leader ID for STDOUT */ *---------------------------------------------*/ printf("\nGet the Session Leader ID for STDOUT\n"); stdout_SID = tcgetsid(STDOUT_FILENO); /* Test for Error */ if (stdout_SID == -1) { fprintf(stderr,"Could not get SID for stdout\n"); exit(EXIT_FAILURE); } else { printf("The Session Leader ID for stdout: %d\n", (int)stdout_SID); } /*---------------------------------------------*/ /* Get the Session Leader ID for STDERR */ /*---------------------------------------------*/ printf ("\nGet the Session Leader ID for STDERR\n"); stderr_SID = tcgetsid(STDERR_FILENO); /* Test for Error */ if (stderr_SID == -1) { fprintf(stderr,"Could not get SID for stderr\n"); exit(EXIT_FAILURE); } else { printf("The Session Leader ID for stderr: %d\n", (int)stderr_SID); } exit(EXIT_SUCCESS); } /* end of main() */
getsid
,
setsid
,
tcgetpgrp
#include <unistd.h> int truncate(const char *pathname, off_t length);
truncate
truncates or extends an OpenEdition file.
pathname
specifies the name of the file.
length
specifies the size of the file. If the length is greater than the current file size, zero bytes are added to the file at the
end.
For programs not compiled with the posix option, a style prefix may be required as part of the
pathname
. See "File Naming Conventions" in the SAS/C Library Reference, Volume 1, for further
information.
truncate
returns
0
if successful, or
-1
if unsuccessful.truncate
function can only be used with MVS 5.2.2 or a later release.ftruncate
![]() Chapter Contents |
![]() Previous |
![]() Next |
![]() Top of Page |
Copyright © Mon Mar 9 09:11:22 EST 1998 by SAS Institute Inc., Cary, NC, USA. All rights reserved.