aboutsummaryrefslogtreecommitdiff
path: root/unix/os/zopdpr.c
blob: 56e97f20c61f624fba056d7548a7ee72a8814c39 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
/* Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
 */

#include <ctype.h>
#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/resource.h>

#define import_spp
#define	import_xwhen
#define	import_kernel
#define	import_knames
#include <iraf.h>

#define	QUANTUM		6
#ifdef SYSV
#define	vfork	fork
#endif

extern void pr_enter (int pid, int inchan, int outchan);
extern int  pr_wait (int pid);
extern void pr_release (int pid);


/* ZOPDPR -- Open a detached process.  In this implementation detached
 * processes begin execution immediately, runing concurrently with the parent.
 * "Jobcode" can be anything we want, provided it is unique.  Since detached
 * processes run concurrently we return the pid of the child as the jobcode.
 */
int
ZOPDPR (
  PKCHAR  *osfn,
  PKCHAR  *bkgfile,
  PKCHAR  *queue,
  XINT	  *jobcode
)
{
	register char	*ip;
	register int	sum;
	int	pid, maxforks = 3;
	int	curpri, priority, delta, neg;


	/* Check that the process file exists and is executable.
	 * Check that the background file exists and is readable.
	 */
	if (access ((char *)osfn, 1) == ERR) {
	    *jobcode = XERR;
	    return (XERR);
	} else if (access ((char *)bkgfile, 4) == ERR) {
	    *jobcode = XERR;
	    return (XERR);
	}

	/* Determine priority at which child process is to run.  A relative
	 * priority of -1 lowers the priority by QUANTUM UNIX units (e.g., nices
	 * the process to 4, 6 or whatever the QUANTUM is).  If an absolute
	 * priority is specified it is used without scaling.
	 */
#ifdef SYSV
	curpri = nice (0);
#else
	curpri = getpriority (PRIO_PROCESS, 0);
#endif

	for (ip=(char *)queue;  isspace (*ip);  ip++)
	    ;
	if (*ip != EOS) {
	    if (*ip == '+' || *ip == '-') {
		delta = 1;
		neg = (*ip++ == '-');
	    } else {
		delta = 0;
		neg = 0;
	    }

	    for (sum=0;  isdigit (*ip);  ip++)
		sum = sum * 10 + *ip - '0';
	    if (neg)
		sum = -sum;

	} else {
	    delta = 1;
	    sum = -1;
	}

	if (delta)
	    priority = curpri - (QUANTUM * sum);
	else
	    priority = sum;

	/* Create child process.  Vfork is used to avoid necessity to copy
	 * the full address space of the parent, since we are going to overlay
	 * a new process immediately with Execl anyhow.  The child inherits
	 * the open stdio files.  The fork can fail if swap space is full or
	 * if we have too many processes.
	 */
	while ((pid = vfork()) == ERR) {
	    if (--maxforks == 0) {
		*jobcode = XERR;
		return (XERR);
	    }
	    sleep (2);
	}

	if (pid == 0) {
	    /* New, child process.
	     * Arrange for the local file descriptors of the parent to be
	     * closed in the child if the exec succeeds.  IRAF subprocesses
	     * do not expect to inherit any file descriptors other than
	     * stdin, stdout, and stderr.
	     */
	    struct rlimit rlim;
	    int maxfd, fd;

	    if (getrlimit (RLIMIT_NOFILE, &rlim))
		maxfd = MAXOFILES;
	    else
		maxfd = rlim.rlim_cur;

	    for (fd=3;  fd < min(MAXOFILES,maxfd);  fd++)
		fcntl (fd, F_SETFD, 1);

#ifdef SYSV
	    /* nice (0, priority * 2); */
	    nice ( priority * 2);
#else
	    setpriority (PRIO_PROCESS, 0, priority);
#endif

	    /* Since we used vfork we share memory with the parent until the
	     * call to execl(), hence we must not close any files or do
	     * anything else which would corrupt the parent's data structures.
	     * Instead, immediately exec the new process (will not return if
	     * successful).  The "-d" flag tells the subprocess that it is a
	     * detached process.  The background file name is passed to the
	     * child, which reads the file to learn what to do, and deletes
	     * the file upon exit.
	     */
	    execl ((char *)osfn, (char *)osfn, "-d", (char *)bkgfile, 
		(char *) 0);

	    /* If we get here the new process could not be executed for some
	     * reason.  Shutdown, calling _exit to avoid flushing parent's
	     * io buffers.  Delete bkgfile to tell parent that child has
	     * terminated.
	     */
	    unlink ((char *)bkgfile);
	    _exit (1);

	} else {
	    /* Existing, parent process.
	     * Save pid in parent's process table.  Entry cleared when
	     * pr_wait is called to wait for process to terminate.
	     */
	    pr_enter (pid, 0, 0);
	}

	*jobcode = pid;

	return (XOK);
}


/* ZCLDPR -- Close a detached process.  If killflag is set interrupt the
 * process before waiting for it to die.  A detached process will shutdown
 * when interrupted, unlike a connected subprocess which merely processes
 * the interrupt and continues execution.  The process itself deletes the
 * bkgfile before exiting.
 */
int
ZCLDPR (
  XINT	*jobcode,
  XINT	*killflag,
  XINT	*exit_status
)
{
	int	pid = *jobcode;


	/* If killing process do not wait for it to die.
	 */
	if (*killflag == XYES) {
	    if (kill (pid, SIGTERM) == ERR) {
		*exit_status = XERR;
		return (XERR);
	    } else {
		pr_release (pid);
		*exit_status = X_INT;
		return (*exit_status);
	    }
	}

	if ((*exit_status = pr_wait (pid)) == ERR)
	    *exit_status = XERR;

	return (*exit_status);
}