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 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
- RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
44
- to
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
- It is very expensive to start a fresh Rails application process, and on
48
- the other hand, server hardware resources can be used more efficiently with
49
- dynamic spawning. In order to solve this problem, instead of spawning a
50
- fresh Rails process, LSAPI dispatcher will dynamically fork children processes
51
- off an initialized Rails process.
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
- When you configure dispatch.lsapi as a LSAPI application, you should add
54
- an extra environment variable
60
+ There are a few environment variables that can be tweaked to tune ruby
61
+ LSAPI process.
55
62
 
56
- LSAPI_CHILDREN=n
63
+ * LSAPI_CHILDREN (default: 0)
57
64
 
58
- n should match the "Max Conns" configuration entry of the LSAPI application.
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
- Two new environment variables has been introduced since Ruby LSAPI 1.4:
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
- n is the maximum number of requests that a child process can serve. Default
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
- LSAPI_MAX_IDLE=n
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
- n is the maximum idle time in seconds that a child process will be waiting
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
- Ruby Script Runner
77
- ``````````````````
78
- If you don't want to change your existing Ruby CGI code, you can use our
79
- Ruby script runner under scripts/ folder. You need to configure
80
- lsruby_runner.rb as a LSAPI application, then add a script handler
81
- for "rb" suffix.
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
- //#include <arpa/inet.h>
49
- #include <sys/types.h>
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