ruby-lsapi 1.13 → 2.0

Sign up to get free protection for your applications and to get access to all the features.
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