ruby-lsapi 1.13 → 2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +71 -35
- data/ext/lsapi/lsapilib.c +729 -4
- data/ext/lsapi/lsapilib.h +31 -1
- data/ext/lsapi/lsruby.c +67 -245
- metadata +4 -3
data/README
CHANGED
@@ -2,8 +2,6 @@
|
|
2
2
|
lsapi - LSAPI extension for Ruby
|
3
3
|
================================
|
4
4
|
|
5
|
-
Version 1.4
|
6
|
-
|
7
5
|
INSTALL
|
8
6
|
-------
|
9
7
|
|
@@ -15,7 +13,7 @@ USAGE
|
|
15
13
|
-----
|
16
14
|
|
17
15
|
General CGI scripts
|
18
|
-
|
16
|
+
^^^^^^^^^^^^^^^^^^^
|
19
17
|
The most efficient way to use LSAPI interface is to modify your CGI scripts.
|
20
18
|
You need to add the following code to your CGI scripts:
|
21
19
|
|
@@ -34,51 +32,89 @@ are being accessed in your scripts.
|
|
34
32
|
You can find some examples under examples/ folder.
|
35
33
|
|
36
34
|
|
35
|
+
Ruby Script Runner
|
36
|
+
^^^^^^^^^^^^^^^^^^
|
37
|
+
If you don't want to change your existing Ruby CGI code, you can use our
|
38
|
+
Ruby script runner under scripts/ folder. You need to configure
|
39
|
+
lsruby_runner.rb as a LSAPI application, then add a script handler
|
40
|
+
for "rb" suffix.
|
41
|
+
|
42
|
+
|
43
|
+
|
37
44
|
Rails dispatcher
|
38
|
-
|
39
|
-
A LSAPI dispatcher is available under rails/ folder, just copy it over to
|
40
|
-
the public/ folder of your Rails application, then change the rewrite rule
|
41
|
-
in public/.htaccess from
|
45
|
+
^^^^^^^^^^^^^^^^
|
42
46
|
|
43
|
-
|
44
|
-
|
45
|
-
RewriteRule ^(.*)$ dispatch.lsapi [QSA,L]
|
47
|
+
With Ruby LSAPI, we proudly provide a optimum platform for Rails application
|
48
|
+
deployment. Ruby LSAPI has the following advantages over other solutions.
|
46
49
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
50
|
+
* Easy configuration, deploy a Rails application only take a few clicks
|
51
|
+
with our Rails easy configuration
|
52
|
+
* Fast startup, the expensive Rails framework initialization only takes
|
53
|
+
place once when multiple processes need to be started
|
54
|
+
* Resource efficience, ruby processes can be started on demand, idle
|
55
|
+
process will be stop.
|
56
|
+
|
57
|
+
To use LSAPI with Ruby on Rails, please check out our toturial
|
58
|
+
http://www.litespeedtech.com/support/wiki/doku.php
|
52
59
|
|
53
|
-
|
54
|
-
|
60
|
+
There are a few environment variables that can be tweaked to tune ruby
|
61
|
+
LSAPI process.
|
55
62
|
|
56
|
-
|
63
|
+
* LSAPI_CHILDREN (default: 0)
|
57
64
|
|
58
|
-
|
65
|
+
LSAPI_CHILDREN controls the maximum number of children processes can be
|
66
|
+
started by the first ruby process started by web server. When set to <=1,
|
67
|
+
the first ruby process will handle request by itself, without starting any
|
68
|
+
child process. When LSAPI_CHILDREN is >1, the LSAPI application is stared in
|
69
|
+
"Self Managed Mode", which will start children processes based on demand.
|
70
|
+
With Rails easy configuration, LSAPI_CHILDREN is set to the value of
|
71
|
+
"Max Connections" by web server, no need to set it explicitly.
|
59
72
|
|
60
|
-
|
73
|
+
Usually, there is no need to set value of LSAPI_CHILDREN over 100 in most
|
74
|
+
server environment.
|
61
75
|
|
62
|
-
LSAPI_MAX_REQS=n
|
63
76
|
|
64
|
-
|
65
|
-
value is 1,000,000. Once that number is reached, the child process will exit
|
66
|
-
automatically. This will help in case of any memory leaks in Rails.
|
77
|
+
* LSAPI_MAX_REQUESTS (default value: 10000)
|
67
78
|
|
68
|
-
|
79
|
+
LSAPI_MAX_REQUESTS specifies the maximum number of requests each child
|
80
|
+
process will handle before it exits automatically. This parameter can
|
81
|
+
help reducing memory usage when there are memory leaks in the application.
|
69
82
|
|
70
|
-
|
71
|
-
for a new request. Once it is reached, the child process will quit.
|
72
|
-
Default value is 60. When n <= 0, the child process will wait indefinitely.
|
73
|
-
This option helps getting rid of idle children processes.
|
83
|
+
* LSAPI_MAX_IDLE (default value: 300 seconds)
|
74
84
|
|
85
|
+
In Self Managed Mode, LSAPI_MAX_IDLE controls how long a idle child
|
86
|
+
process will wait for a new request before exit. This option help
|
87
|
+
releasing system resources taken by idle processes.
|
75
88
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
89
|
+
* LSAPI_MAX_IDLE_CHILDREN (default value: 1/3 of LSAPI_CHILDREN)
|
90
|
+
|
91
|
+
In Self Managed Mode, LSAI_MAX_IDLE_CHILDREN controls how many idle
|
92
|
+
children processes are allowed. Excessive idle children processes
|
93
|
+
will be killed by the parent process.
|
94
|
+
|
95
|
+
* LSAPI_MAX_PROCESS_TIME (default value: 300 seconds)
|
96
|
+
|
97
|
+
In Self Managed Mode, LSAPI_MAX_PROCESS_TIME controls the maximum
|
98
|
+
processing time allowed when processing a request. If a child process
|
99
|
+
can not finish processing of a request in the given time period, it
|
100
|
+
will be killed by the parent process. This option can help getting rid
|
101
|
+
of dead or runaway child process.
|
102
|
+
|
103
|
+
* LSAPI_PGRP_MAX_IDLE (default value: FOREVER )
|
104
|
+
|
105
|
+
In Self Managed Mode, LSAPI_PGRP_MAX_IDLE controls how long the parent
|
106
|
+
process will wait before exiting when there is no child process.
|
107
|
+
This option help releasing system resources taken by an idle parent
|
108
|
+
process.
|
109
|
+
|
110
|
+
* LSAPI_PPID_NO_CHECK
|
111
|
+
|
112
|
+
By default a LSAPI application check the existence of its parent process
|
113
|
+
and exits automatically if the parent process died. This is to reduce
|
114
|
+
orphan process when web server is restarted. However, it is desireable
|
115
|
+
to disable this feature, such as when a LSAPI process was started
|
116
|
+
manually from command line. LSAPI_PPID_NO_CHECK should be set when
|
117
|
+
you want to disable the checking of existence of parent process.
|
82
118
|
|
83
119
|
|
84
120
|
License
|
data/ext/lsapi/lsapilib.c
CHANGED
@@ -45,16 +45,20 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
45
45
|
#include <errno.h>
|
46
46
|
#include <fcntl.h>
|
47
47
|
|
48
|
-
|
49
|
-
#include <
|
48
|
+
#include <arpa/inet.h>
|
49
|
+
#include <netdb.h>
|
50
50
|
#include <netinet/in.h>
|
51
51
|
#include <netinet/tcp.h>
|
52
|
+
#include <sys/un.h>
|
52
53
|
#include <signal.h>
|
53
54
|
#include <stdlib.h>
|
54
55
|
#include <stdio.h>
|
55
56
|
#include <string.h>
|
57
|
+
#include <sys/mman.h>
|
56
58
|
#include <sys/socket.h>
|
57
59
|
#include <sys/uio.h>
|
60
|
+
#include <sys/wait.h>
|
61
|
+
#include <time.h>
|
58
62
|
#include <unistd.h>
|
59
63
|
|
60
64
|
#define LSAPI_ST_REQ_HEADER 1
|
@@ -68,6 +72,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
68
72
|
|
69
73
|
static int g_inited = 0;
|
70
74
|
static int g_running = 1;
|
75
|
+
static int s_ppid;
|
71
76
|
LSAPI_Request g_req;
|
72
77
|
|
73
78
|
void Flush_RespBuf_r( LSAPI_Request * pReq );
|
@@ -545,6 +550,7 @@ int LSAPI_Init(void)
|
|
545
550
|
if ( LSAPI_InitRequest( &g_req, LSAPI_SOCK_FILENO ) == -1 )
|
546
551
|
return -1;
|
547
552
|
g_inited = 1;
|
553
|
+
s_ppid = getppid();
|
548
554
|
}
|
549
555
|
return 0;
|
550
556
|
}
|
@@ -859,7 +865,7 @@ int LSAPI_Write_r( LSAPI_Request * pReq, const char * pBuf, int len )
|
|
859
865
|
int toWrite;
|
860
866
|
int packetLen;
|
861
867
|
|
862
|
-
if ( !pReq || !pBuf )
|
868
|
+
if ( !pReq || !pBuf || (pReq->m_fd == -1) )
|
863
869
|
return -1;
|
864
870
|
if ( len < pReq->m_pRespBufEnd - pReq->m_pRespBufPos )
|
865
871
|
{
|
@@ -958,6 +964,13 @@ int LSAPI_Flush_r( LSAPI_Request * pReq )
|
|
958
964
|
n = pReq->m_pIovecCur - pReq->m_pIovecToWrite;
|
959
965
|
if (( 0 == n )&&( pReq->m_pRespBufPos == pReq->m_pRespBuf ))
|
960
966
|
return 0;
|
967
|
+
if ( pReq->m_fd == -1 )
|
968
|
+
{
|
969
|
+
pReq->m_pRespBufPos = pReq->m_pRespBuf;
|
970
|
+
pReq->m_totalLen = 0;
|
971
|
+
pReq->m_pIovecCur = pReq->m_pIovecToWrite = pReq->m_pIovec;
|
972
|
+
return -1;
|
973
|
+
}
|
961
974
|
if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER )
|
962
975
|
{
|
963
976
|
LSAPI_FinalizeRespHeaders_r( pReq );
|
@@ -997,6 +1010,8 @@ int LSAPI_Write_Stderr_r( LSAPI_Request * pReq, const char * pBuf, int len )
|
|
997
1010
|
struct iovec iov[2];
|
998
1011
|
struct iovec *pIov;
|
999
1012
|
|
1013
|
+
if (( !pReq )||( pReq->m_fd == -1 ))
|
1014
|
+
return -1;
|
1000
1015
|
if ( pReq->m_pRespBufPos != pReq->m_pRespBuf )
|
1001
1016
|
{
|
1002
1017
|
LSAPI_Flush_r( pReq );
|
@@ -1050,7 +1065,7 @@ static char * GetHeaderVar( LSAPI_Request * pReq, const char * name )
|
|
1050
1065
|
{
|
1051
1066
|
const char *p;
|
1052
1067
|
char *pKey;
|
1053
|
-
char *pKeyEnd
|
1068
|
+
char *pKeyEnd;
|
1054
1069
|
int keyLen;
|
1055
1070
|
struct lsapi_header_offset * pCur, *pEnd;
|
1056
1071
|
pCur = pReq->m_pUnknownHeader;
|
@@ -1272,7 +1287,717 @@ int LSAPI_AppendRespHeader_r( LSAPI_Request * pReq, char * pBuf, int len )
|
|
1272
1287
|
}
|
1273
1288
|
|
1274
1289
|
|
1290
|
+
int LSAPI_CreateListenSock2( const struct sockaddr * pServerAddr, int backlog )
|
1291
|
+
{
|
1292
|
+
int ret;
|
1293
|
+
int fd;
|
1294
|
+
int flag = 1;
|
1295
|
+
int addr_len;
|
1296
|
+
|
1297
|
+
switch( pServerAddr->sa_family )
|
1298
|
+
{
|
1299
|
+
case AF_INET:
|
1300
|
+
addr_len = 16;
|
1301
|
+
break;
|
1302
|
+
case AF_INET6:
|
1303
|
+
addr_len = sizeof( struct sockaddr_in6 );
|
1304
|
+
break;
|
1305
|
+
case AF_UNIX:
|
1306
|
+
addr_len = sizeof( struct sockaddr_un );
|
1307
|
+
unlink( ((struct sockaddr_un *)pServerAddr)->sun_path );
|
1308
|
+
break;
|
1309
|
+
default:
|
1310
|
+
return -1;
|
1311
|
+
}
|
1312
|
+
|
1313
|
+
fd = socket( pServerAddr->sa_family, SOCK_STREAM, 0 );
|
1314
|
+
if ( fd == -1 )
|
1315
|
+
return -1;
|
1316
|
+
|
1317
|
+
fcntl( fd, F_SETFD, FD_CLOEXEC );
|
1318
|
+
|
1319
|
+
if(setsockopt( fd, SOL_SOCKET, SO_REUSEADDR,
|
1320
|
+
(char *)( &flag ), sizeof(flag)) == 0)
|
1321
|
+
{
|
1322
|
+
ret = bind( fd, pServerAddr, addr_len );
|
1323
|
+
if ( !ret )
|
1324
|
+
{
|
1325
|
+
ret = listen( fd, backlog );
|
1326
|
+
if ( !ret )
|
1327
|
+
return fd;
|
1328
|
+
}
|
1329
|
+
}
|
1330
|
+
|
1331
|
+
ret = errno;
|
1332
|
+
close(fd);
|
1333
|
+
errno = ret;
|
1334
|
+
return -1;
|
1335
|
+
|
1336
|
+
}
|
1337
|
+
|
1338
|
+
int LSAPI_ParseSockAddr( const char * pBind, struct sockaddr * pAddr )
|
1339
|
+
{
|
1340
|
+
char achAddr[256];
|
1341
|
+
char * p = achAddr;
|
1342
|
+
char * pEnd;
|
1343
|
+
struct addrinfo *res, hints;
|
1344
|
+
int doAddrInfo = 0;
|
1345
|
+
int port;
|
1346
|
+
|
1347
|
+
if ( !pBind )
|
1348
|
+
return -1;
|
1349
|
+
|
1350
|
+
while( isspace( *p ) )
|
1351
|
+
++pBind;
|
1352
|
+
|
1353
|
+
strncpy( achAddr, pBind, 256 );
|
1354
|
+
|
1355
|
+
switch( *p )
|
1356
|
+
{
|
1357
|
+
case '/':
|
1358
|
+
pAddr->sa_family = AF_UNIX;
|
1359
|
+
strncpy( ((struct sockaddr_un *)pAddr)->sun_path, p,
|
1360
|
+
sizeof(((struct sockaddr_un *)pAddr)->sun_path) );
|
1361
|
+
return 0;
|
1362
|
+
|
1363
|
+
case '[':
|
1364
|
+
pAddr->sa_family = AF_INET6;
|
1365
|
+
++p;
|
1366
|
+
pEnd = strchr( p, ']' );
|
1367
|
+
if ( !pEnd )
|
1368
|
+
return -1;
|
1369
|
+
*pEnd++ = 0;
|
1370
|
+
|
1371
|
+
if ( *p == '*' )
|
1372
|
+
{
|
1373
|
+
strcpy( achAddr, "::" );
|
1374
|
+
p = achAddr;
|
1375
|
+
}
|
1376
|
+
doAddrInfo = 1;
|
1377
|
+
break;
|
1378
|
+
|
1379
|
+
default:
|
1380
|
+
pAddr->sa_family = AF_INET;
|
1381
|
+
pEnd = strchr( p, ':' );
|
1382
|
+
if ( !pEnd )
|
1383
|
+
return -1;
|
1384
|
+
*pEnd++ = 0;
|
1385
|
+
|
1386
|
+
doAddrInfo = 0;
|
1387
|
+
if ( *p == '*' )
|
1388
|
+
{
|
1389
|
+
((struct sockaddr_in *)pAddr)->sin_addr.s_addr = htonl(INADDR_ANY);
|
1390
|
+
}
|
1391
|
+
else if (!strcasecmp( p, "localhost" ) )
|
1392
|
+
((struct sockaddr_in *)pAddr)->sin_addr.s_addr = htonl( INADDR_LOOPBACK );
|
1393
|
+
else
|
1394
|
+
{
|
1395
|
+
((struct sockaddr_in *)pAddr)->sin_addr.s_addr = inet_addr( p );
|
1396
|
+
if ( ((struct sockaddr_in *)pAddr)->sin_addr.s_addr == INADDR_BROADCAST)
|
1397
|
+
{
|
1398
|
+
doAddrInfo = 1;
|
1399
|
+
}
|
1400
|
+
}
|
1401
|
+
break;
|
1402
|
+
}
|
1403
|
+
if ( *pEnd == ':' )
|
1404
|
+
++pEnd;
|
1405
|
+
|
1406
|
+
port = atoi( pEnd );
|
1407
|
+
if (( port <= 0 )||( port > 655535 ))
|
1408
|
+
return -1;
|
1409
|
+
if ( doAddrInfo )
|
1410
|
+
{
|
1411
|
+
|
1412
|
+
memset(&hints, 0, sizeof(hints));
|
1413
|
+
|
1414
|
+
hints.ai_family = pAddr->sa_family;
|
1415
|
+
hints.ai_socktype = SOCK_STREAM;
|
1416
|
+
hints.ai_protocol = IPPROTO_TCP;
|
1417
|
+
|
1418
|
+
if ( getaddrinfo(p, NULL, &hints, &res) )
|
1419
|
+
{
|
1420
|
+
return -1;
|
1421
|
+
}
|
1422
|
+
|
1423
|
+
memcpy(pAddr, res->ai_addr, res->ai_addrlen);
|
1424
|
+
freeaddrinfo(res);
|
1425
|
+
}
|
1426
|
+
|
1427
|
+
if ( pAddr->sa_family == AF_INET )
|
1428
|
+
((struct sockaddr_in *)pAddr)->sin_port = htons( port );
|
1429
|
+
else
|
1430
|
+
((struct sockaddr_in6 *)pAddr)->sin6_port = htons( port );
|
1431
|
+
return 0;
|
1432
|
+
|
1433
|
+
}
|
1434
|
+
|
1435
|
+
int LSAPI_CreateListenSock( const char * pBind, int backlog )
|
1436
|
+
{
|
1437
|
+
char serverAddr[128];
|
1438
|
+
int ret;
|
1439
|
+
int fd = -1;
|
1440
|
+
ret = LSAPI_ParseSockAddr( pBind, (struct sockaddr *)serverAddr );
|
1441
|
+
if ( !ret )
|
1442
|
+
{
|
1443
|
+
fd = LSAPI_CreateListenSock2( (struct sockaddr *)serverAddr, backlog );
|
1444
|
+
}
|
1445
|
+
return fd;
|
1446
|
+
}
|
1447
|
+
|
1448
|
+
static fn_select_t g_fnSelect = select;
|
1449
|
+
|
1450
|
+
typedef struct _lsapi_child_status
|
1451
|
+
{
|
1452
|
+
int m_pid;
|
1453
|
+
short m_iKillSent;
|
1454
|
+
volatile short m_inProcess;
|
1455
|
+
|
1456
|
+
volatile long m_tmWaitBegin;
|
1457
|
+
volatile long m_tmReqBegin;
|
1458
|
+
volatile long m_tmLastCheckPoint;
|
1459
|
+
}
|
1460
|
+
lsapi_child_status;
|
1461
|
+
|
1462
|
+
static lsapi_child_status * s_pChildStatus = NULL;
|
1463
|
+
|
1464
|
+
typedef struct _lsapi_prefork_server
|
1465
|
+
{
|
1466
|
+
int m_fd;
|
1467
|
+
int m_iMaxChildren;
|
1468
|
+
int m_iCurChildren;
|
1469
|
+
int m_iMaxIdleChildren;
|
1470
|
+
int m_iServerMaxIdle;
|
1471
|
+
int m_iChildrenMaxIdleTime;
|
1472
|
+
int m_iMaxReqProcessTime;
|
1473
|
+
|
1474
|
+
lsapi_child_status * m_pChildrenStatus;
|
1475
|
+
|
1476
|
+
}lsapi_prefork_server;
|
1477
|
+
|
1478
|
+
static lsapi_prefork_server * g_prefork_server = NULL;
|
1479
|
+
|
1480
|
+
int LSAPI_Init_Prefork_Server( int max_children, fn_select_t fp )
|
1481
|
+
{
|
1482
|
+
if ( g_prefork_server )
|
1483
|
+
return 0;
|
1484
|
+
if ( max_children <= 1 )
|
1485
|
+
return -1;
|
1486
|
+
if ( max_children >= 10000)
|
1487
|
+
max_children = 10000;
|
1488
|
+
|
1489
|
+
g_prefork_server = (lsapi_prefork_server *)malloc( sizeof( lsapi_prefork_server ) );
|
1490
|
+
if ( !g_prefork_server )
|
1491
|
+
return -1;
|
1492
|
+
memset( g_prefork_server, 0, sizeof( lsapi_prefork_server ) );
|
1493
|
+
|
1494
|
+
if ( fp != NULL )
|
1495
|
+
g_fnSelect = fp;
|
1496
|
+
|
1497
|
+
s_ppid = getppid();
|
1498
|
+
g_prefork_server->m_iMaxChildren = max_children;
|
1499
|
+
g_prefork_server->m_iMaxIdleChildren = max_children / 3;
|
1500
|
+
g_prefork_server->m_iChildrenMaxIdleTime = 30;
|
1501
|
+
g_prefork_server->m_iMaxReqProcessTime = 300;
|
1502
|
+
return 0;
|
1503
|
+
}
|
1504
|
+
|
1505
|
+
void LSAPI_Set_Server_fd( int fd )
|
1506
|
+
{
|
1507
|
+
if( g_prefork_server )
|
1508
|
+
g_prefork_server->m_fd = fd;
|
1509
|
+
}
|
1510
|
+
|
1511
|
+
|
1512
|
+
static int lsapi_accept( int fdListen )
|
1513
|
+
{
|
1514
|
+
int fd;
|
1515
|
+
int nodelay = 1;
|
1516
|
+
socklen_t len;
|
1517
|
+
char achPeer[128];
|
1518
|
+
|
1519
|
+
len = sizeof( achPeer );
|
1520
|
+
fd = accept( fdListen, (struct sockaddr *)&achPeer, &len );
|
1521
|
+
if ( fd != -1 )
|
1522
|
+
{
|
1523
|
+
if (((struct sockaddr *)&achPeer)->sa_family == AF_INET )
|
1524
|
+
{
|
1525
|
+
setsockopt( fd, IPPROTO_TCP, TCP_NODELAY,
|
1526
|
+
(char *)&nodelay, sizeof(nodelay));
|
1527
|
+
}
|
1528
|
+
}
|
1529
|
+
return fd;
|
1530
|
+
|
1531
|
+
}
|
1532
|
+
|
1533
|
+
|
1534
|
+
|
1535
|
+
|
1536
|
+
static int s_req_processed = 0;
|
1537
|
+
static int s_max_reqs = 10000;
|
1538
|
+
static int s_max_idle_secs = 300;
|
1539
|
+
|
1540
|
+
static int s_stop;
|
1541
|
+
|
1542
|
+
static void lsapi_cleanup(int signal)
|
1543
|
+
{
|
1544
|
+
s_stop = signal;
|
1545
|
+
}
|
1546
|
+
|
1547
|
+
static lsapi_child_status * find_child_status( int pid )
|
1548
|
+
{
|
1549
|
+
lsapi_child_status * pStatus = g_prefork_server->m_pChildrenStatus;
|
1550
|
+
lsapi_child_status * pEnd = g_prefork_server->m_pChildrenStatus + g_prefork_server->m_iMaxChildren * 2;
|
1551
|
+
while( pStatus < pEnd )
|
1552
|
+
{
|
1553
|
+
if ( pStatus->m_pid == pid )
|
1554
|
+
return pStatus;
|
1555
|
+
++pStatus;
|
1556
|
+
}
|
1557
|
+
return NULL;
|
1558
|
+
}
|
1559
|
+
|
1560
|
+
|
1561
|
+
|
1562
|
+
static void lsapi_sigchild( int signal )
|
1563
|
+
{
|
1564
|
+
int status, pid;
|
1565
|
+
lsapi_child_status * child_status;
|
1566
|
+
while( 1 )
|
1567
|
+
{
|
1568
|
+
pid = waitpid( -1, &status, WNOHANG|WUNTRACED );
|
1569
|
+
if ( pid <= 0 )
|
1570
|
+
{
|
1571
|
+
break;
|
1572
|
+
}
|
1573
|
+
child_status = find_child_status( pid );
|
1574
|
+
if ( child_status )
|
1575
|
+
child_status->m_pid = 0;
|
1576
|
+
--g_prefork_server->m_iCurChildren;
|
1577
|
+
}
|
1578
|
+
|
1579
|
+
}
|
1580
|
+
|
1581
|
+
static int lsapi_init_children_status()
|
1582
|
+
{
|
1583
|
+
int size = 4096;
|
1584
|
+
|
1585
|
+
char * pBuf;
|
1586
|
+
size = g_prefork_server->m_iMaxChildren * sizeof( lsapi_child_status ) * 2;
|
1587
|
+
size = (size + 4095 ) / 4096 * 4096;
|
1588
|
+
pBuf =( char*) mmap( NULL, size, PROT_READ | PROT_WRITE,
|
1589
|
+
MAP_ANON | MAP_SHARED, -1, 0 );
|
1590
|
+
if ( pBuf == MAP_FAILED )
|
1591
|
+
{
|
1592
|
+
perror( "Anonymous mmap() failed" );
|
1593
|
+
return -1;
|
1594
|
+
}
|
1595
|
+
memset( pBuf, 0, size );
|
1596
|
+
g_prefork_server->m_pChildrenStatus = (lsapi_child_status *)pBuf;
|
1597
|
+
return 0;
|
1598
|
+
}
|
1599
|
+
|
1600
|
+
static void lsapi_check_child_status()
|
1601
|
+
{
|
1602
|
+
int idle = 0;
|
1603
|
+
int tobekilled;
|
1604
|
+
long tmCur = time( NULL );
|
1605
|
+
lsapi_child_status * pStatus = g_prefork_server->m_pChildrenStatus;
|
1606
|
+
lsapi_child_status * pEnd = g_prefork_server->m_pChildrenStatus + g_prefork_server->m_iMaxChildren * 2;
|
1607
|
+
while( pStatus < pEnd )
|
1608
|
+
{
|
1609
|
+
tobekilled = pStatus->m_iKillSent;
|
1610
|
+
if ( pStatus->m_pid != 0 )
|
1611
|
+
{
|
1612
|
+
if ( !tobekilled )
|
1613
|
+
{
|
1614
|
+
if ( !pStatus->m_inProcess )
|
1615
|
+
{
|
1616
|
+
if ( idle > g_prefork_server->m_iMaxIdleChildren )
|
1617
|
+
{
|
1618
|
+
tobekilled = 1;
|
1619
|
+
}
|
1620
|
+
else
|
1621
|
+
{
|
1622
|
+
if (( s_max_idle_secs> 0)&&(tmCur - pStatus->m_tmWaitBegin > s_max_idle_secs + 5 ))
|
1623
|
+
tobekilled = 1;
|
1624
|
+
}
|
1625
|
+
++idle;
|
1626
|
+
}
|
1627
|
+
else
|
1628
|
+
{
|
1629
|
+
if ( tmCur - pStatus->m_tmReqBegin >
|
1630
|
+
g_prefork_server->m_iMaxReqProcessTime )
|
1631
|
+
tobekilled = 1;
|
1632
|
+
}
|
1633
|
+
}
|
1634
|
+
if ( tobekilled )
|
1635
|
+
{
|
1636
|
+
tobekilled = 0;
|
1637
|
+
if ( pStatus->m_iKillSent > 5 )
|
1638
|
+
tobekilled = SIGKILL;
|
1639
|
+
else if ( pStatus->m_iKillSent == 2 )
|
1640
|
+
tobekilled = SIGTERM;
|
1641
|
+
else if ( pStatus->m_iKillSent == 0 )
|
1642
|
+
tobekilled = SIGUSR1;
|
1643
|
+
if ( tobekilled )
|
1644
|
+
kill( pStatus->m_pid, tobekilled );
|
1645
|
+
++pStatus->m_iKillSent;
|
1646
|
+
}
|
1647
|
+
|
1648
|
+
}
|
1649
|
+
++pStatus;
|
1650
|
+
}
|
1651
|
+
}
|
1652
|
+
|
1653
|
+
|
1654
|
+
|
1655
|
+
static int lsapi_prefork_server_accept( lsapi_prefork_server * pServer, LSAPI_Request * pReq )
|
1656
|
+
{
|
1657
|
+
struct sigaction act, old_term, old_quit, old_int,
|
1658
|
+
old_usr1, old_child;
|
1659
|
+
lsapi_child_status * child_status;
|
1660
|
+
int wait_secs = 0;
|
1661
|
+
int ret;
|
1662
|
+
int pid;
|
1663
|
+
fd_set readfds;
|
1664
|
+
struct timeval timeout;
|
1665
|
+
|
1666
|
+
lsapi_init_children_status();
|
1667
|
+
|
1668
|
+
setsid();
|
1669
|
+
|
1670
|
+
act.sa_flags = 0;
|
1671
|
+
act.sa_handler = lsapi_sigchild;
|
1672
|
+
if( sigaction( SIGCHLD, &act, &old_child ) )
|
1673
|
+
{
|
1674
|
+
perror( "Can't set signal handler for SIGCHILD" );
|
1675
|
+
return -1;
|
1676
|
+
}
|
1677
|
+
|
1678
|
+
/* Set up handler to kill children upon exit */
|
1679
|
+
act.sa_flags = 0;
|
1680
|
+
act.sa_handler = lsapi_cleanup;
|
1681
|
+
if( sigaction( SIGTERM, &act, &old_term ) ||
|
1682
|
+
sigaction( SIGINT, &act, &old_int ) ||
|
1683
|
+
sigaction( SIGUSR1, &act, &old_usr1 ) ||
|
1684
|
+
sigaction( SIGQUIT, &act, &old_quit ))
|
1685
|
+
{
|
1686
|
+
perror( "Can't set signals" );
|
1687
|
+
return -1;
|
1688
|
+
}
|
1689
|
+
s_stop = 0;
|
1690
|
+
while( !s_stop )
|
1691
|
+
{
|
1692
|
+
if ( pServer->m_iCurChildren >= (pServer->m_iMaxChildren << 1 ) )
|
1693
|
+
{
|
1694
|
+
usleep( 10000 );
|
1695
|
+
continue;
|
1696
|
+
}
|
1697
|
+
|
1698
|
+
FD_ZERO( &readfds );
|
1699
|
+
FD_SET( pServer->m_fd, &readfds );
|
1700
|
+
timeout.tv_sec = 1; timeout.tv_usec = 0;
|
1701
|
+
if ((ret = (*g_fnSelect)(pServer->m_fd+1, &readfds, NULL, NULL, &timeout)) == 1 )
|
1702
|
+
{
|
1703
|
+
if ( pServer->m_iCurChildren >= 0 )
|
1704
|
+
{
|
1705
|
+
usleep( 10 );
|
1706
|
+
FD_ZERO( &readfds );
|
1707
|
+
FD_SET( pServer->m_fd, &readfds );
|
1708
|
+
timeout.tv_sec = 0; timeout.tv_usec = 0;
|
1709
|
+
if ( (*g_fnSelect)(pServer->m_fd+1, &readfds, NULL, NULL, &timeout) == 0 )
|
1710
|
+
continue;
|
1711
|
+
}
|
1712
|
+
}
|
1713
|
+
else if ( ret == -1 )
|
1714
|
+
{
|
1715
|
+
if ( errno == EINTR )
|
1716
|
+
continue;
|
1717
|
+
//perror( "select()" );
|
1718
|
+
break;
|
1719
|
+
}
|
1720
|
+
else
|
1721
|
+
{
|
1722
|
+
if (s_ppid &&
|
1723
|
+
(kill(s_ppid, 0) == -1)&&(errno == ESRCH))
|
1724
|
+
break;
|
1725
|
+
lsapi_check_child_status();
|
1726
|
+
if (pServer->m_iServerMaxIdle)
|
1727
|
+
{
|
1728
|
+
if ( pServer->m_iCurChildren <= 0 )
|
1729
|
+
{
|
1730
|
+
++wait_secs;
|
1731
|
+
if ( wait_secs > pServer->m_iServerMaxIdle )
|
1732
|
+
return -1;
|
1733
|
+
}
|
1734
|
+
else
|
1735
|
+
wait_secs = 0;
|
1736
|
+
}
|
1737
|
+
continue;
|
1738
|
+
}
|
1739
|
+
|
1740
|
+
pReq->m_fd = lsapi_accept( pServer->m_fd );
|
1741
|
+
if ( pReq->m_fd != -1 )
|
1742
|
+
{
|
1743
|
+
child_status = find_child_status( 0 );
|
1744
|
+
pid = fork();
|
1745
|
+
if ( !pid )
|
1746
|
+
{
|
1747
|
+
g_prefork_server = NULL;
|
1748
|
+
s_ppid = getppid();
|
1749
|
+
s_req_processed = 0;
|
1750
|
+
s_pChildStatus = child_status;
|
1751
|
+
|
1752
|
+
/* don't catch our signals */
|
1753
|
+
sigaction( SIGCHLD, &old_child, 0 );
|
1754
|
+
sigaction( SIGTERM, &old_term, 0 );
|
1755
|
+
sigaction( SIGQUIT, &old_quit, 0 );
|
1756
|
+
sigaction( SIGINT, &old_int, 0 );
|
1757
|
+
sigaction( SIGUSR1, &old_usr1, 0 );
|
1758
|
+
return 0;
|
1759
|
+
}
|
1760
|
+
else if ( pid == -1 )
|
1761
|
+
{
|
1762
|
+
perror( "fork() failed, please increase process limit" );
|
1763
|
+
}
|
1764
|
+
else
|
1765
|
+
{
|
1766
|
+
++pServer->m_iCurChildren;
|
1767
|
+
if ( child_status )
|
1768
|
+
{
|
1769
|
+
child_status->m_pid = pid;
|
1770
|
+
child_status->m_iKillSent = 0;
|
1771
|
+
child_status->m_tmWaitBegin = time(NULL);
|
1772
|
+
}
|
1773
|
+
}
|
1774
|
+
close( pReq->m_fd );
|
1775
|
+
pReq->m_fd = -1;
|
1776
|
+
|
1777
|
+
}
|
1778
|
+
else
|
1779
|
+
{
|
1780
|
+
if (( errno == EINTR )||( errno == EAGAIN))
|
1781
|
+
continue;
|
1782
|
+
perror( "accept() failed" );
|
1783
|
+
return -1;
|
1784
|
+
}
|
1785
|
+
}
|
1786
|
+
sigaction( SIGUSR1, &old_usr1, 0 );
|
1787
|
+
kill( -getpgrp(), SIGUSR1 );
|
1788
|
+
return -1;
|
1789
|
+
|
1790
|
+
}
|
1791
|
+
|
1792
|
+
int LSAPI_Prefork_Accept_r( LSAPI_Request * pReq )
|
1793
|
+
{
|
1794
|
+
int fd;
|
1795
|
+
int ret;
|
1796
|
+
int wait_secs;
|
1797
|
+
fd_set readfds;
|
1798
|
+
struct timeval timeout;
|
1799
|
+
|
1800
|
+
LSAPI_Finish_r( pReq );
|
1801
|
+
|
1275
1802
|
|
1803
|
+
if ( g_prefork_server )
|
1804
|
+
{
|
1805
|
+
if ( g_prefork_server->m_fd != -1 )
|
1806
|
+
if ( lsapi_prefork_server_accept( g_prefork_server, pReq ) == -1 )
|
1807
|
+
return -1;
|
1808
|
+
}
|
1809
|
+
if ( s_req_processed >= s_max_reqs )
|
1810
|
+
return -1;
|
1276
1811
|
|
1812
|
+
if ( s_pChildStatus )
|
1813
|
+
{
|
1814
|
+
s_pChildStatus->m_tmWaitBegin = time( NULL );
|
1815
|
+
}
|
1816
|
+
|
1817
|
+
while( g_running )
|
1818
|
+
{
|
1819
|
+
if ( pReq->m_fd != -1 )
|
1820
|
+
{
|
1821
|
+
fd = pReq->m_fd;
|
1822
|
+
}
|
1823
|
+
else if ( pReq->m_fdListen != -1 )
|
1824
|
+
fd = pReq->m_fdListen;
|
1825
|
+
else
|
1826
|
+
return -1;
|
1827
|
+
wait_secs = 0;
|
1828
|
+
while( 1 )
|
1829
|
+
{
|
1830
|
+
if ( !g_running )
|
1831
|
+
return -1;
|
1832
|
+
FD_ZERO( &readfds );
|
1833
|
+
FD_SET( fd, &readfds );
|
1834
|
+
timeout.tv_sec = 1;
|
1835
|
+
timeout.tv_usec = 0;
|
1836
|
+
ret = (*g_fnSelect)(fd+1, &readfds, NULL, NULL, &timeout);
|
1837
|
+
if ( ret == 0 )
|
1838
|
+
{
|
1839
|
+
if ( s_pChildStatus )
|
1840
|
+
{
|
1841
|
+
s_pChildStatus->m_inProcess = 0;
|
1842
|
+
}
|
1843
|
+
++wait_secs;
|
1844
|
+
if (( s_max_idle_secs > 0 )&&(wait_secs >= s_max_idle_secs ))
|
1845
|
+
return -1;
|
1846
|
+
if ( s_ppid &&(kill(s_ppid, 0) == -1)&&(errno == ESRCH))
|
1847
|
+
return -1;
|
1848
|
+
}
|
1849
|
+
else if ( ret == -1 )
|
1850
|
+
{
|
1851
|
+
if ( errno == EINTR )
|
1852
|
+
continue;
|
1853
|
+
else
|
1854
|
+
return -1;
|
1855
|
+
}
|
1856
|
+
else if ( ret >= 1 )
|
1857
|
+
{
|
1858
|
+
if ( fd == pReq->m_fdListen )
|
1859
|
+
{
|
1860
|
+
pReq->m_fd = lsapi_accept( pReq->m_fdListen );
|
1861
|
+
if ( pReq->m_fd != -1 )
|
1862
|
+
{
|
1863
|
+
fd = pReq->m_fd;
|
1864
|
+
}
|
1865
|
+
else
|
1866
|
+
return -1;
|
1867
|
+
}
|
1868
|
+
else
|
1869
|
+
break;
|
1870
|
+
}
|
1871
|
+
}
|
1872
|
+
|
1873
|
+
if ( !readReq( pReq ) )
|
1874
|
+
{
|
1875
|
+
if ( s_pChildStatus )
|
1876
|
+
{
|
1877
|
+
s_pChildStatus->m_inProcess = 1;
|
1878
|
+
s_pChildStatus->m_tmReqBegin = s_pChildStatus->m_tmLastCheckPoint = time(NULL);
|
1879
|
+
}
|
1880
|
+
++s_req_processed;
|
1881
|
+
return 0;
|
1882
|
+
}
|
1883
|
+
lsapi_close( pReq->m_fd );
|
1884
|
+
pReq->m_fd = -1;
|
1885
|
+
LSAPI_Reset_r( pReq );
|
1886
|
+
}
|
1887
|
+
return -1;
|
1888
|
+
|
1889
|
+
}
|
1890
|
+
|
1891
|
+
void LSAPI_Set_Max_Reqs( int reqs )
|
1892
|
+
{ s_max_reqs = reqs; }
|
1893
|
+
|
1894
|
+
void LSAPI_Set_Max_Idle( int secs )
|
1895
|
+
{ s_max_idle_secs = secs; }
|
1896
|
+
|
1897
|
+
void LSAPI_Set_Max_Children( int maxChildren )
|
1898
|
+
{
|
1899
|
+
if ( g_prefork_server )
|
1900
|
+
g_prefork_server->m_iMaxChildren = maxChildren;
|
1901
|
+
}
|
1902
|
+
|
1903
|
+
void LSAPI_Set_Max_Process_Time( int secs )
|
1904
|
+
{
|
1905
|
+
if (( g_prefork_server )&&( secs > 0 ))
|
1906
|
+
g_prefork_server->m_iMaxReqProcessTime = secs;
|
1907
|
+
}
|
1908
|
+
|
1909
|
+
|
1910
|
+
void LSAPI_Set_Max_Idle_Children( int maxIdleChld )
|
1911
|
+
{
|
1912
|
+
if (( g_prefork_server )&&( maxIdleChld > 0 ))
|
1913
|
+
g_prefork_server->m_iMaxIdleChildren = maxIdleChld;
|
1914
|
+
}
|
1915
|
+
|
1916
|
+
void LSAPI_Set_Server_Max_Idle_Secs( int serverMaxIdle )
|
1917
|
+
{
|
1918
|
+
if ( g_prefork_server )
|
1919
|
+
g_prefork_server->m_iServerMaxIdle = serverMaxIdle;
|
1920
|
+
}
|
1921
|
+
|
1922
|
+
|
1923
|
+
void LSAPI_No_Check_ppid()
|
1924
|
+
{
|
1925
|
+
s_ppid = 0;
|
1926
|
+
}
|
1927
|
+
|
1928
|
+
extern char ** environ;
|
1929
|
+
static void unset_lsapi_envs()
|
1930
|
+
{
|
1931
|
+
char **env = environ;
|
1932
|
+
while( env != NULL && *env != NULL )
|
1933
|
+
{
|
1934
|
+
if (!strncmp(*env, "LSAPI_", 6) || !strncmp( *env, "PHP_LSAPI_", 10 ) )
|
1935
|
+
{
|
1936
|
+
char ** del = env;
|
1937
|
+
do
|
1938
|
+
*del = del[1];
|
1939
|
+
while( *del++ );
|
1940
|
+
}
|
1941
|
+
else
|
1942
|
+
++env;
|
1943
|
+
}
|
1944
|
+
}
|
1945
|
+
|
1946
|
+
void LSAPI_Init_Env_Parameters( fn_select_t fp )
|
1947
|
+
{
|
1948
|
+
const char *p;
|
1949
|
+
int n;
|
1950
|
+
p = getenv( "PHP_LSAPI_MAX_REQUESTS" );
|
1951
|
+
if ( !p )
|
1952
|
+
p = getenv( "LSAPI_MAX_REQS" );
|
1953
|
+
if ( p )
|
1954
|
+
{
|
1955
|
+
n = atoi( p );
|
1956
|
+
if ( n > 0 )
|
1957
|
+
LSAPI_Set_Max_Reqs( n );
|
1958
|
+
}
|
1959
|
+
|
1960
|
+
p = getenv( "LSAPI_MAX_IDLE" );
|
1961
|
+
if ( p )
|
1962
|
+
{
|
1963
|
+
n = atoi( p );
|
1964
|
+
LSAPI_Set_Max_Idle( n );
|
1965
|
+
}
|
1966
|
+
|
1967
|
+
if ( LSAPI_Is_Listen() )
|
1968
|
+
{
|
1969
|
+
n = 0;
|
1970
|
+
p = getenv( "PHP_LSAPI_CHILDREN" );
|
1971
|
+
if ( !p )
|
1972
|
+
p = getenv( "LSAPI_CHILDREN" );
|
1973
|
+
if ( p )
|
1974
|
+
n = atoi( p );
|
1975
|
+
if ( n > 1 )
|
1976
|
+
{
|
1977
|
+
LSAPI_Init_Prefork_Server( n, fp );
|
1978
|
+
LSAPI_Set_Server_fd( g_req.m_fdListen );
|
1979
|
+
}
|
1980
|
+
|
1981
|
+
p = getenv( "LSAPI_MAX_IDLE_CHILDREN" );
|
1982
|
+
if ( p )
|
1983
|
+
LSAPI_Set_Max_Idle_Children( atoi( p ) );
|
1984
|
+
|
1985
|
+
p = getenv( "LSAPI_PGRP_MAX_IDLE" );
|
1986
|
+
if ( p )
|
1987
|
+
{
|
1988
|
+
LSAPI_Set_Server_Max_Idle_Secs( atoi( p ) );
|
1989
|
+
}
|
1990
|
+
|
1991
|
+
p = getenv( "LSAPI_MAX_PROCESS_TIME" );
|
1992
|
+
if ( p )
|
1993
|
+
LSAPI_Set_Max_Process_Time( atoi( p ) );
|
1994
|
+
|
1995
|
+
if ( getenv( "LSAPI_PPID_NO_CHECK" ) )
|
1996
|
+
{
|
1997
|
+
LSAPI_No_Check_ppid();
|
1998
|
+
}
|
1999
|
+
}
|
2000
|
+
unset_lsapi_envs();
|
2001
|
+
}
|
1277
2002
|
|
1278
2003
|
|