Browse Source

Using global configuration variable instead of function arguments

Yann Weber 4 years ago
parent
commit
dcc8a7a622
9 changed files with 80 additions and 49 deletions
  1. 5
    0
      include/conf.h
  2. 1
    1
      include/logger.h
  3. 3
    2
      include/pyworker.h
  4. 4
    6
      include/responder.h
  5. 25
    2
      src/conf.c
  6. 7
    2
      src/logger.c
  7. 10
    10
      src/main.c
  8. 11
    10
      src/pyworker.c
  9. 14
    16
      src/responder.c

+ 5
- 0
include/conf.h View File

@@ -90,6 +90,8 @@
90 90
 You can escape { and } by using {{ and }} and all field names can by\n\
91 91
 abbreviated to one character.\n"
92 92
 
93
+#define PYENTRY_DEFAULT_FUN "application"
94
+
93 95
 /**@brief Friendly name for @ref struct pyfcgi_conf_s
94 96
  * @see struct pyfcgi_conf_s */
95 97
 typedef struct pyfcgi_conf_s pyfcgi_conf_t;
@@ -143,6 +145,9 @@ void usage();
143 145
 /**@brief Print pyfcgi & python version on given fd */
144 146
 void print_version(int);
145 147
 
148
+/**@brief Init conf with default values */
149
+void default_conf();
150
+
146 151
 /**@brief Parse arguments and store them in conf
147 152
  * @return 0 if no error */
148 153
 int parse_args(int argc, char *argv[]);

+ 1
- 1
include/logger.h View File

@@ -324,7 +324,7 @@ int pyfcgi_logger_stop();
324 324
 /**@brief Enable syslog logging with given ident
325 325
  * @param char* ident if NULL use current ident
326 326
  */
327
-void pyfcgi_logger_enable_syslog(char*);
327
+void pyfcgi_logger_enable_syslog(const char*);
328 328
 
329 329
 /**@brief Stop & free an individual logger */
330 330
 void _pyfcgi_logger_free(pyfcgi_logger_t*);

+ 3
- 2
include/pyworker.h View File

@@ -109,7 +109,7 @@ struct piper_args_s
109 109
  * @param int max request before worker restart
110 110
  * @return 0 if exit avec max requests
111 111
  */
112
-int work(char*, int, int, int);
112
+int work(int, int);
113 113
 
114 114
 /**@brief function for a subprocess designed to read stdin & stdout from
115 115
  * python & forward them to syslog or FCGI
@@ -139,8 +139,9 @@ void worker_piper_sighandler(int);
139 139
 int ctl_get_rep_sz(int, size_t*);
140 140
 
141 141
 /**@brief Import & return the python entrypoint callable
142
+ * from PyFCGI_conf.py_entrymod & PyFCGI_conf.py_entryfun
142 143
  */
143
-PyObject* import_entrypoint(char* py_entrypoint);
144
+PyObject* import_entrypoint();
144 145
 
145 146
 /**@brief Fetch stdout & stderr python flush() function
146 147
  * @param PyObject* pystdout_flush

+ 4
- 6
include/responder.h View File

@@ -67,26 +67,24 @@ void init_context();
67 67
  * The main function of the fcgi app fork child
68 68
  * @param int max_requests : exit normally after this number of requests. If
69 69
  * 0 given never exit.
70
- * @param char* python_entrypoint a path to a python entrypoint
70
+ * @param char* python_entrymodule a python module name
71
+ * @param char* python_entrymodule a python callable name from entry module
71 72
  * @param unsigned int max_requests before exiting worker
72 73
  * @param unsigned int minimum workers count
73 74
  * @param unsigned int maximum wrokers count
74 75
  * @return 0 on success
75 76
  */
76
-int responder_loop(char *py_entrypoint, unsigned int max_reqs,
77
-	unsigned int min_wrk, unsigned int max_wrk);
77
+int responder_loop();
78 78
 
79 79
 
80 80
 /**@brief Spawn a worker given an entrypoint
81 81
  * @ingroup work_master_proc
82 82
  * Spawn a new worker process and prepare ENV & request forwarding
83
- * @param char* python_entrypoint a path to a python entrypoint
84 83
  * @param int worker uid
85 84
  * @param int semid for FCGI access
86
- * @param int max request before worker restart
87 85
  * @return child PID
88 86
  */
89
-pid_t spawn(char*, int, int, int);
87
+pid_t spawn(int, int);
90 88
 
91 89
 /**@brief Generate a new semaphore from given key
92 90
  * @ingroup work_master_proc

+ 25
- 2
src/conf.c View File

@@ -5,7 +5,7 @@ void usage()
5 5
 	static const struct option opts[] = PYFCGI_LONG_OPT;
6 6
 	static const char *help[][2] = PYFCGI_OPT_HELP;
7 7
 	size_t i;
8
-	dprintf(2, "Usage : %s -e PYMODULE -E PYFUN [OPTIONS]\n", PYFCGI_NAME);
8
+	dprintf(2, "Usage : %s -e PYMODULE [-E PYFUN] [OPTIONS]\n", PYFCGI_NAME);
9 9
 	dprintf(2, "\nOptions list :\n");
10 10
 	i=0;
11 11
 	while(opts[i].name)
@@ -33,12 +33,24 @@ void usage()
33 33
 void print_version(int fd)
34 34
 {
35 35
 	dprintf(fd, "%s\n", PACKAGE_STRING);
36
+	/**@todo TODO : get python version */
37
+}
38
+
39
+void default_conf()
40
+{
41
+	memset(&PyFCGI_conf, 0, sizeof(pyfcgi_conf_t));
42
+	PyFCGI_conf.context.pid = getpid();
43
+	PyFCGI_conf.min_wrk = 1;
44
+	PyFCGI_conf.max_wrk = 5;
45
+	PyFCGI_conf.max_reqs = 1000;
36 46
 }
37 47
 
38 48
 int parse_args(int argc, char *argv[])
39 49
 {
40 50
 	static const struct option long_options[] = PYFCGI_LONG_OPT;
51
+	char ident[] = "pyfcgi[XXXXXXXX]";
41 52
 	int c, opt_i;
53
+
42 54
 	while(1)
43 55
 	{
44 56
 		c = getopt_long(argc, argv, PYFCGI_SHORT_OPT, long_options,
@@ -78,7 +90,8 @@ int parse_args(int argc, char *argv[])
78 90
 				}
79 91
 				break;
80 92
 			case 'S':
81
-				PyFCGI_conf.logs.flags |= PYFCGI_LOG_FSYSLOG;
93
+				snprintf(ident+7, 8, "%4d]", PyFCGI_conf.context.pid);
94
+				pyfcgi_logger_enable_syslog(ident);
82 95
 				break;
83 96
 			case 'P':
84 97
 				PyFCGI_conf.context.pidfile = strdup(optarg);
@@ -100,6 +113,16 @@ int parse_args(int argc, char *argv[])
100 113
 		usage();
101 114
 		exit(1);
102 115
 	}
116
+	if(!PyFCGI_conf.py_entrymod)
117
+	{
118
+		dprintf(2, "No python entry module given... exiting\n");
119
+		usage();
120
+		exit(2);
121
+	}
122
+	if(!PyFCGI_conf.py_entryfun)
123
+	{
124
+		PyFCGI_conf.py_entryfun = PYENTRY_DEFAULT_FUN;
125
+	}
103 126
 	return 0;
104 127
 }
105 128
 

+ 7
- 2
src/logger.c View File

@@ -32,7 +32,7 @@ int pyfcgi_logger_stop()
32 32
 	return 0;
33 33
 }
34 34
 
35
-void pyfcgi_logger_enable_syslog(char* nident)
35
+void pyfcgi_logger_enable_syslog(const char* nident)
36 36
 {
37 37
 	pyfcgi_conf_logger_t *conf;
38 38
 	conf = &PyFCGI_conf.logs;
@@ -45,7 +45,12 @@ void pyfcgi_logger_enable_syslog(char* nident)
45 45
 	{
46 46
 		nident = conf->ident;
47 47
 	}
48
-	openlog(nident, LOG_CONS | LOG_PERROR, LOG_DAEMON | LOG_USER);
48
+	if(conf->syslog_ident)
49
+	{
50
+		free(conf->syslog_ident);
51
+	}
52
+	conf->syslog_ident = strdup(nident);
53
+	openlog(conf->syslog_ident, LOG_CONS | LOG_PERROR, LOG_DAEMON | LOG_USER);
49 54
 }
50 55
 
51 56
 void _pyfcgi_logger_free(pyfcgi_logger_t *logger)

+ 10
- 10
src/main.c View File

@@ -52,13 +52,10 @@ extern pyfcgi_conf_t PyFCGI_conf;
52 52
 
53 53
 int main(int argc, char **argv)
54 54
 {
55
-	char *ident, *py_entrypoint;
56
-	size_t ident_len;
57 55
 	pid_t child;
58 56
 	int child_ret;
59 57
 	unsigned int emerg_sleep = 3;
60 58
 
61
-	py_entrypoint = getenv("PY_ENTRYPOINT");
62 59
 	/*
63 60
 	if(argc > 1 || !py_entrypoint)
64 61
 	{
@@ -70,17 +67,20 @@ int main(int argc, char **argv)
70 67
 		return 1;
71 68
 	}
72 69
 	*/
70
+	default_conf();
71
+	pyfcgi_logger_init();
72
+	pyfcgi_logger_set_ident("pyfcgi(main)");
73 73
 	if(parse_args(argc, argv))
74 74
 	{
75 75
 		return 1;
76 76
 	}
77 77
 
78
-PyFCGI_conf.context.pid = getpid();
79 78
 
80
-	pyfcgi_logger_init();
81
-	pyfcgi_logger_set_ident("pyfcgi(main)");
82
-	pyfcgi_logger_add("/tmp/pyfcgi.log", 0xFF, 0xFF, NULL);
79
+	//pyfcgi_logger_add("/tmp/pyfcgi.log", 0xFF, 0xFF, NULL);
83 80
 
81
+	/*
82
+	cahr *ident;
83
+	size_t ident_len;
84 84
 	ident_len = snprintf(NULL, 0, IDENT_FMT, getpid());
85 85
 	ident_len++;
86 86
 	ident = malloc(sizeof(char)*ident_len);
@@ -91,7 +91,8 @@ PyFCGI_conf.context.pid = getpid();
91 91
 	}
92 92
 	snprintf(ident, ident_len, IDENT_FMT, getpid());
93 93
 	pyfcgi_logger_enable_syslog(ident);
94
-
94
+	free(ident);
95
+	*/
95 96
 
96 97
 	pyfcgi_log(LOG_INFO, "New server started");
97 98
 
@@ -107,7 +108,7 @@ PyFCGI_conf.context.pid = getpid();
107 108
 		}
108 109
 		else if(!child)
109 110
 		{
110
-			responder_loop(py_entrypoint, MAX_REQS, 1, 10);
111
+			responder_loop();
111 112
 			exit((unsigned char)-1);
112 113
 		}
113 114
 		waitpid(child, &child_ret, 0);
@@ -128,7 +129,6 @@ PyFCGI_conf.context.pid = getpid();
128 129
 	}
129 130
 
130 131
 	closelog();
131
-	free(ident);
132 132
 }
133 133
 
134 134
 /**@mainpage PyFCGI

+ 11
- 10
src/pyworker.c View File

@@ -21,13 +21,14 @@
21 21
 
22 22
 static int worker_piper_sigrcv = 0;
23 23
 
24
-int work(char* py_entrypoint, int wrk_id, int semid, int max_reqs)
24
+int work(int wrk_id, int semid)
25 25
 {
26 26
 	PyObject *entry_fun, *pystdout_flush, *pystderr_flush,
27 27
 	         *py_osmod;
28 28
 	FCGX_Stream *in_stream, *out_stream, *err_stream;
29 29
 	char **envp;
30 30
 	int count, pipe_out[2], pipe_err[2], pipe_ctl[2], err, piper_status;
31
+	int max_reqs;
31 32
 	struct sembuf sop;
32 33
 	struct sigaction act;
33 34
 	struct timeval start, stop;
@@ -37,7 +38,7 @@ int work(char* py_entrypoint, int wrk_id, int semid, int max_reqs)
37 38
 	piper_args_t piper_args;
38 39
 	char *piper_stack;
39 40
 
40
-
41
+	max_reqs = PyFCGI_conf.max_reqs;
41 42
 	piper_args.wrk_id = wrk_id;
42 43
 	piper_args.act = &act;
43 44
 	sop.sem_num = 0;
@@ -89,11 +90,11 @@ int work(char* py_entrypoint, int wrk_id, int semid, int max_reqs)
89 90
 	}
90 91
 
91 92
 	// loading module
92
-	entry_fun = import_entrypoint(py_entrypoint);
93
+	entry_fun = import_entrypoint();
93 94
 
94 95
 	pyfcgi_log(	LOG_INFO,
95 96
 		"Worker[%d] Waiting request with %s.%s()", wrk_id,
96
-		py_entrypoint, PYENTRY_FUNNAME);
97
+		PyFCGI_conf.py_entrymod, PyFCGI_conf.py_entryfun);
97 98
 
98 99
 
99 100
 	sop.sem_op = 1; //indicate worker as ready & idle
@@ -445,10 +446,10 @@ int ctl_get_rep_sz(int ctl_pipe, size_t* rep_sz)
445 446
 	return 0;
446 447
 }
447 448
 
448
-PyObject* import_entrypoint(char* py_entrypoint)
449
+PyObject* import_entrypoint()
449 450
 {
450 451
 	PyObject *entry_fname, *entry_module, *entry_fun;
451
-	entry_fname = PyUnicode_DecodeFSDefault(py_entrypoint);
452
+	entry_fname = PyUnicode_DecodeFSDefault(PyFCGI_conf.py_entrymod);
452 453
 	entry_module = PyImport_Import(entry_fname);
453 454
 	Py_DECREF(entry_fname);
454 455
 
@@ -457,7 +458,7 @@ PyObject* import_entrypoint(char* py_entrypoint)
457 458
 		//TODO syslog python error / traceback
458 459
 		pyfcgi_log(	LOG_CRIT,
459 460
 			"Unable to import python file '%s'",
460
-			py_entrypoint);
461
+			PyFCGI_conf.py_entrymod);
461 462
 		pyfcgi_log( LOG_INFO,
462 463
 			"%s", getcwd(NULL, 256));
463 464
 		log_expt(LOG_ERR);
@@ -466,7 +467,7 @@ PyObject* import_entrypoint(char* py_entrypoint)
466 467
 	}
467 468
 
468 469
 	// getting entrypoint function
469
-	entry_fun = PyObject_GetAttrString(entry_module, PYENTRY_FUNNAME);
470
+	entry_fun = PyObject_GetAttrString(entry_module, PyFCGI_conf.py_entryfun);
470 471
 	Py_DECREF(entry_module);
471 472
 
472 473
 	if(!entry_fun)
@@ -474,14 +475,14 @@ PyObject* import_entrypoint(char* py_entrypoint)
474 475
 		//TODO syslog python error / traceback
475 476
 		pyfcgi_log(	LOG_CRIT,
476 477
 			"Unable to import object '%s' from '%s'",
477
-			PYENTRY_FUNNAME, py_entrypoint);
478
+			PyFCGI_conf.py_entryfun, PyFCGI_conf.py_entrymod);
478 479
 		Py_Exit(2);
479 480
 	}
480 481
 	if(!PyCallable_Check(entry_fun))
481 482
 	{
482 483
 		pyfcgi_log( LOG_CRIT,
483 484
 			"When imported from '%s', '%s' was not a callable",
484
-			py_entrypoint, PYENTRY_FUNNAME);
485
+			PyFCGI_conf.py_entrymod, PyFCGI_conf.py_entryfun);
485 486
 		Py_Exit(3);
486 487
 	}
487 488
 	return entry_fun;

+ 14
- 16
src/responder.c View File

@@ -25,8 +25,7 @@ void init_context()
25 25
 }
26 26
 
27 27
 
28
-int responder_loop(char *py_entrypoint, unsigned int max_reqs,
29
-	unsigned int min_wrk, unsigned int max_wrk)
28
+int responder_loop()
30 29
 {
31 30
 	unsigned int n_wrk, wanted_n, n;
32 31
 	pid_t *wrk_pids;
@@ -48,7 +47,7 @@ int responder_loop(char *py_entrypoint, unsigned int max_reqs,
48 47
 
49 48
 	init_context();
50 49
 
51
-	wrk_pids = malloc(sizeof(int) * max_wrk);
50
+	wrk_pids = malloc(sizeof(int) * PyFCGI_conf.max_wrk);
52 51
 	if(!wrk_pids)
53 52
 	{
54 53
 		err = errno;
@@ -57,16 +56,16 @@ int responder_loop(char *py_entrypoint, unsigned int max_reqs,
57 56
 			strerror(err));
58 57
 		clean_exit(err);
59 58
 	}
60
-	bzero(wrk_pids, sizeof(int) * max_wrk);
59
+	bzero(wrk_pids, sizeof(int) * PyFCGI_conf.max_wrk);
61 60
 
62 61
 	semid = new_semaphore();
63 62
 	
64
-	wanted_n = min_wrk;
63
+	wanted_n = PyFCGI_conf.min_wrk;
65 64
 	n_wrk = 0;
66 65
 	// prespawning minimum worker count
67 66
 	for(n_wrk=0; n_wrk < wanted_n; n_wrk++)
68 67
 	{
69
-		wrk_pids[n_wrk] = spawn(py_entrypoint, n_wrk, semid, max_reqs);
68
+		wrk_pids[n_wrk] = spawn(n_wrk, semid);
70 69
 	}
71 70
 	//Wait at least for a process to be ready
72 71
 	while(!semtimedop(semid, &sop, 1, &timeout));
@@ -135,8 +134,7 @@ pyfcgi_log( LOG_DEBUG, "GC want %d have %d", wanted_n, n_wrk);
135 134
 			else
136 135
 			{	// respawn on same slot
137 136
 				pyfcgi_log(LOG_INFO, "respawn #%d", n);
138
-				wrk_pids[n] = spawn(py_entrypoint, n,
139
-				                    semid, max_reqs);
137
+				wrk_pids[n] = spawn(n, semid);
140 138
 				continue;
141 139
 			}
142 140
 		}
@@ -153,7 +151,8 @@ pyfcgi_log( LOG_DEBUG, "GC want %d have %d", wanted_n, n_wrk);
153 151
 				{
154 152
 					idle = 1;
155 153
 				}
156
-				else if(wanted_n > min_wrk && n_wrk - wanted_n < 2)
154
+				else if(wanted_n > PyFCGI_conf.min_wrk
155
+					&& n_wrk - wanted_n < 2)
157 156
 				{
158 157
 					wanted_n--;
159 158
 				}
@@ -162,7 +161,7 @@ pyfcgi_log( LOG_DEBUG, "GC want %d have %d", wanted_n, n_wrk);
162 161
 			pyfcgi_log(LOG_ERR, "Unable to read semaphore : %s",
163 162
 			       strerror(err));
164 163
 		}
165
-		if(!ret && n_wrk < max_wrk)
164
+		if(!ret && n_wrk < PyFCGI_conf.max_wrk)
166 165
 		{
167 166
 			idle=0;
168 167
 			pyfcgi_log( LOG_DEBUG,
@@ -170,13 +169,12 @@ pyfcgi_log( LOG_DEBUG, "GC want %d have %d", wanted_n, n_wrk);
170 169
 			n = n_wrk;
171 170
 			n_wrk++;
172 171
 			wanted_n = n_wrk;
173
-			wrk_pids[n] = spawn(py_entrypoint, n,
174
-					    semid, max_reqs);
172
+			wrk_pids[n] = spawn(n, semid);
175 173
 		}
176 174
 	}
177 175
 	
178 176
 	//Debug wait & exit
179
-	for(n_wrk=0; n_wrk != min_wrk; n_wrk++)
177
+	for(n_wrk=0; n_wrk != PyFCGI_conf.min_wrk; n_wrk++)
180 178
 	{
181 179
 		waitpid(wrk_pids[n_wrk], &status, 0);
182 180
 		pyfcgi_log(LOG_DEBUG, "Child %d stopped with status %d",
@@ -187,7 +185,7 @@ pyfcgi_log( LOG_DEBUG, "GC want %d have %d", wanted_n, n_wrk);
187 185
 	exit(0);
188 186
 }
189 187
 
190
-pid_t spawn(char* py_entrypoint, int wrk_id, int semid, int max_reqs)
188
+pid_t spawn(int wrk_id, int semid)
191 189
 {
192 190
 	pid_t res;
193 191
 	struct timespec timeout;
@@ -198,14 +196,14 @@ pid_t spawn(char* py_entrypoint, int wrk_id, int semid, int max_reqs)
198 196
 	res = fork();
199 197
 	if(res == -1)
200 198
 	{
201
-		pyfcgi_log(	LOG_ERR, "Fork fails for worker #%d : %s",
199
+		pyfcgi_log(LOG_ERR, "Fork fails for worker #%d : %s",
202 200
 			wrk_id, strerror(errno));
203 201
 		return -1;
204 202
 	}
205 203
 	else if(!res)
206 204
 	{
207 205
 		// Child process
208
-		exit(work(py_entrypoint, wrk_id, semid, max_reqs));
206
+		exit(work(wrk_id, semid));
209 207
 	}
210 208
 	// Sleep to avoid spawning like hell thinking all workers are
211 209
 	// busy. Let some time to this one to go up...

Loading…
Cancel
Save