@@ -55,6 +55,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5555#include <fcntl.h>
5656#include <limits.h>
5757#include <sys/stat.h>
58+ #include <sched.h>
5859#include <signal.h>
5960#include <stdlib.h>
6061#include <stdio.h>
@@ -115,18 +116,26 @@ typedef struct lsapi_MD5Context lsapi_MD5_CTX;
115116#define LSAPI_ST_REQ_BODY 2
116117#define LSAPI_ST_RESP_HEADER 4
117118#define LSAPI_ST_RESP_BODY 8
119+ #define LSAPI_ST_BACKGROUND 16
118120
119121#define LSAPI_RESP_BUF_SIZE 8192
120122#define LSAPI_INIT_RESP_HEADER_LEN 4096
121123
124+ enum
125+ {
126+ LSAPI_STATE_IDLE ,
127+ LSAPI_STATE_CONNECTED ,
128+ LSAPI_STATE_ACCEPTING ,
129+ };
130+
122131typedef struct _lsapi_child_status
123132{
124133 int m_pid ;
125134 long m_tmStart ;
126135
127136 volatile short m_iKillSent ;
128137 volatile char m_inProcess ;
129- volatile char m_connected ;
138+ volatile char m_state ;
130139 volatile int m_iReqCounter ;
131140
132141 volatile long m_tmWaitBegin ;
@@ -158,6 +167,9 @@ static int s_max_busy_workers = -1;
158167static char * s_stderr_log_path = NULL ;
159168static int s_stderr_is_pipe = 0 ;
160169static int s_ignore_pid = -1 ;
170+ static size_t s_total_pages = 1 ;
171+ static size_t s_min_avail_pages = 256 * 1024 ;
172+ static size_t * s_avail_pages = & s_total_pages ;
161173
162174LSAPI_Request g_req =
163175{ .m_fdListen = -1 , .m_fd = -1 };
@@ -417,7 +429,7 @@ static void lsapi_close_connection(LSAPI_Request *pReq)
417429 if (s_busy_workers )
418430 __sync_fetch_and_sub (s_busy_workers , 1 );
419431 if (s_worker_status )
420- s_worker_status -> m_connected = 0 ;
432+ __sync_lock_test_and_set ( & s_worker_status -> m_state , LSAPI_STATE_IDLE ) ;
421433}
422434
423435
@@ -1560,7 +1572,8 @@ int LSAPI_Accept_r( LSAPI_Request * pReq )
15601572 else
15611573 {
15621574 if (s_worker_status )
1563- s_worker_status -> m_connected = 1 ;
1575+ __sync_lock_test_and_set (& s_worker_status -> m_state ,
1576+ LSAPI_STATE_CONNECTED );
15641577 if (s_busy_workers )
15651578 __sync_fetch_and_add (s_busy_workers , 1 );
15661579 lsapi_set_nblock ( pReq -> m_fd , 0 );
@@ -1623,6 +1636,37 @@ int LSAPI_Finish_r( LSAPI_Request * pReq )
16231636}
16241637
16251638
1639+ int LSAPI_End_Response_r (LSAPI_Request * pReq )
1640+ {
1641+ if (!pReq )
1642+ return -1 ;
1643+ if (pReq -> m_reqState )
1644+ {
1645+ if ( pReq -> m_fd != -1 )
1646+ {
1647+ if ( pReq -> m_reqState & LSAPI_ST_RESP_HEADER )
1648+ {
1649+ LSAPI_FinalizeRespHeaders_r ( pReq );
1650+ }
1651+ if ( pReq -> m_pRespBufPos != pReq -> m_pRespBuf )
1652+ {
1653+ Flush_RespBuf_r ( pReq );
1654+ }
1655+
1656+ pReq -> m_pIovecCur -> iov_base = (void * )& finish ;
1657+ pReq -> m_pIovecCur -> iov_len = LSAPI_PACKET_HEADER_LEN ;
1658+ pReq -> m_totalLen += LSAPI_PACKET_HEADER_LEN ;
1659+ ++ pReq -> m_pIovecCur ;
1660+ LSAPI_Flush_r ( pReq );
1661+ }
1662+ send_conn_close_notification (pReq -> m_fd );
1663+ lsapi_close_connection (pReq );
1664+ pReq -> m_reqState |= LSAPI_ST_BACKGROUND ;
1665+ }
1666+ return 0 ;
1667+ }
1668+
1669+
16261670void LSAPI_Reset_r ( LSAPI_Request * pReq )
16271671{
16281672 pReq -> m_pRespBufPos = pReq -> m_pRespBuf ;
@@ -1808,7 +1852,11 @@ ssize_t LSAPI_Write_r( LSAPI_Request * pReq, const char * pBuf, size_t len )
18081852 ssize_t packetLen ;
18091853 int skip = 0 ;
18101854
1811- if ( !pReq || !pBuf || (pReq -> m_fd == -1 ) )
1855+ if (!pReq || !pBuf )
1856+ return -1 ;
1857+ if (pReq -> m_reqState & LSAPI_ST_BACKGROUND )
1858+ return len ;
1859+ if (pReq -> m_fd == -1 )
18121860 return -1 ;
18131861 if ( pReq -> m_reqState & LSAPI_ST_RESP_HEADER )
18141862 {
@@ -2710,6 +2758,9 @@ int LSAPI_Init_Prefork_Server( int max_children, fn_select_t fp, int avoidFork )
27102758 s_ppid = getppid ();
27112759 s_pid = getpid ();
27122760 setpgid ( s_pid , s_pid );
2761+ #if defined(linux ) || defined(__linux ) || defined(__linux__ ) || defined(__gnu_linux__ )
2762+ s_total_pages = sysconf (_SC_PHYS_PAGES );
2763+ #endif
27132764 g_prefork_server -> m_iAvoidFork = avoidFork ;
27142765 g_prefork_server -> m_iMaxChildren = max_children ;
27152766
@@ -2844,11 +2895,19 @@ static void lsapi_sigchild( int signal )
28442895 child_status = find_child_status ( pid );
28452896 if ( child_status )
28462897 {
2847- if (child_status -> m_connected )
2898+ if (__sync_bool_compare_and_swap (& child_status -> m_state ,
2899+ LSAPI_STATE_CONNECTED ,
2900+ LSAPI_STATE_IDLE ))
28482901 {
28492902 if (s_busy_workers )
28502903 __sync_fetch_and_sub (s_busy_workers , 1 );
2851- child_status -> m_connected = 0 ;
2904+ }
2905+ else if (__sync_bool_compare_and_swap (& child_status -> m_state ,
2906+ LSAPI_STATE_ACCEPTING ,
2907+ LSAPI_STATE_IDLE ))
2908+ {
2909+ if (s_accepting_workers )
2910+ __sync_fetch_and_sub (s_accepting_workers , 1 );
28522911 }
28532912 child_status -> m_pid = 0 ;
28542913 -- g_prefork_server -> m_iCurChildren ;
@@ -2884,6 +2943,7 @@ static int lsapi_init_children_status(void)
28842943 s_busy_workers = (int * )g_prefork_server -> m_pChildrenStatusEnd ;
28852944 s_accepting_workers = s_busy_workers + 1 ;
28862945 s_global_counter = s_accepting_workers + 1 ;
2946+ s_avail_pages = (size_t * )(s_global_counter + 1 );
28872947 return 0 ;
28882948}
28892949
@@ -3023,6 +3083,17 @@ void set_skip_write()
30233083{ s_skip_write = 1 ; }
30243084
30253085
3086+ int is_enough_free_mem ()
3087+ {
3088+ #if defined(linux ) || defined(__linux ) || defined(__linux__ ) || defined(__gnu_linux__ )
3089+ //minimum 1GB or 10% available free memory
3090+ return (* s_avail_pages > s_min_avail_pages
3091+ || (* s_avail_pages * 10 ) / s_total_pages > 0 );
3092+ #endif
3093+ return 1 ;
3094+ }
3095+
3096+
30263097static int lsapi_prefork_server_accept ( lsapi_prefork_server * pServer ,
30273098 LSAPI_Request * pReq )
30283099{
@@ -3092,18 +3163,28 @@ static int lsapi_prefork_server_accept( lsapi_prefork_server * pServer,
30923163 }
30933164 }
30943165
3166+ #if defined(linux ) || defined(__linux ) || defined(__linux__ ) || defined(__gnu_linux__ )
3167+ * s_avail_pages = sysconf (_SC_AVPHYS_PAGES );
3168+ lsapi_log ("Memory total: %zd, free: %zd, free %%%zd\n" ,
3169+ s_total_pages , * s_avail_pages , * s_avail_pages * 100 / s_total_pages );
3170+
3171+ #endif
30953172 FD_ZERO ( & readfds );
30963173 FD_SET ( pServer -> m_fd , & readfds );
30973174 timeout .tv_sec = 1 ;
30983175 timeout .tv_usec = 0 ;
30993176 ret = (* g_fnSelect )(pServer -> m_fd + 1 , & readfds , NULL , NULL , & timeout );
31003177 if (ret == 1 )
31013178 {
3102- if (pServer -> m_iCurChildren >= pServer -> m_iMaxChildren
3103- && s_accepting_workers
3104- && (ret = __sync_add_and_fetch (s_accepting_workers , 0 )) > 0 )
3179+ int accepting = 0 ;
3180+ if (s_accepting_workers )
3181+ accepting = __sync_add_and_fetch (s_accepting_workers , 0 );
3182+
3183+ if (pServer -> m_iCurChildren > 0 && accepting > 0 )
31053184 {
3106- usleep ( 200 );
3185+ usleep (400 );
3186+ while (accepting -- > 0 )
3187+ sched_yield ();
31073188 continue ;
31083189 }
31093190 }
@@ -3164,14 +3245,17 @@ static int lsapi_prefork_server_accept( lsapi_prefork_server * pServer,
31643245 if (pthread_atfork_func )
31653246 (* pthread_atfork_func )(NULL , NULL , set_skip_write );
31663247
3167- s_worker_status -> m_connected = 1 ;
3248+ __sync_lock_test_and_set (& s_worker_status -> m_state ,
3249+ LSAPI_STATE_CONNECTED );
31683250 if (s_busy_workers )
31693251 __sync_add_and_fetch (s_busy_workers , 1 );
31703252 lsapi_set_nblock ( pReq -> m_fd , 0 );
31713253 //keep it open if busy_count is used.
3172- if (s_busy_workers && s_uid != 0 )
3254+ if (s_busy_workers
3255+ && * s_busy_workers > (pServer -> m_iMaxChildren >> 1 ))
31733256 s_keepListener = 1 ;
3174- else if ( pReq -> m_fdListen != -1 )
3257+ if ((s_uid == 0 || !s_keepListener || !is_enough_free_mem ())
3258+ && pReq -> m_fdListen != -1 )
31753259 {
31763260 close ( pReq -> m_fdListen );
31773261 pReq -> m_fdListen = -1 ;
@@ -3297,6 +3381,9 @@ int LSAPI_Prefork_Accept_r( LSAPI_Request * pReq )
32973381 timeout .tv_usec = 0 ;
32983382 if (fd == pReq -> m_fdListen )
32993383 {
3384+ if (s_worker_status )
3385+ __sync_lock_test_and_set (& s_worker_status -> m_state ,
3386+ LSAPI_STATE_ACCEPTING );
33003387 if (s_accepting_workers )
33013388 __sync_fetch_and_add (s_accepting_workers , 1 );
33023389 }
@@ -3305,14 +3392,18 @@ int LSAPI_Prefork_Accept_r( LSAPI_Request * pReq )
33053392 {
33063393 if (s_accepting_workers )
33073394 __sync_fetch_and_sub (s_accepting_workers , 1 );
3395+ if (s_worker_status )
3396+ __sync_lock_test_and_set (& s_worker_status -> m_state ,
3397+ LSAPI_STATE_IDLE );
33083398 }
33093399
33103400 if ( ret == 0 )
33113401 {
33123402 if ( s_worker_status )
33133403 {
33143404 s_worker_status -> m_inProcess = 0 ;
3315- if (fd == pReq -> m_fdListen )
3405+ if (fd == pReq -> m_fdListen
3406+ && (s_keepListener != 2 || !is_enough_free_mem ()))
33163407 return -1 ;
33173408 }
33183409 ++ wait_secs ;
@@ -3339,15 +3430,16 @@ int LSAPI_Prefork_Accept_r( LSAPI_Request * pReq )
33393430 if ( pReq -> m_fd != -1 )
33403431 {
33413432 if (s_worker_status )
3342- s_worker_status -> m_connected = 1 ;
3433+ __sync_lock_test_and_set (& s_worker_status -> m_state ,
3434+ LSAPI_STATE_CONNECTED );
33433435 if (s_busy_workers )
33443436 __sync_fetch_and_add (s_busy_workers , 1 );
33453437
33463438 fd = pReq -> m_fd ;
33473439
33483440 lsapi_set_nblock ( fd , 0 );
33493441 //init_conn_key( pReq->m_fd );
3350- if ( !s_keepListener )
3442+ if (!s_keepListener )
33513443 {
33523444 close ( pReq -> m_fdListen );
33533445 pReq -> m_fdListen = -1 ;
@@ -3613,6 +3705,7 @@ static int lsapi_reopen_stderr(const char *p)
36133705int LSAPI_Init_Env_Parameters ( fn_select_t fp )
36143706{
36153707 const char * p ;
3708+ char ch ;
36163709 int n ;
36173710 int avoidFork = 0 ;
36183711
@@ -3634,10 +3727,28 @@ int LSAPI_Init_Env_Parameters( fn_select_t fp )
36343727 LSAPI_Set_Max_Reqs ( n );
36353728 }
36363729
3730+ p = getenv ( "LSAPI_KEEP_LISTEN" );
3731+ if ( p )
3732+ {
3733+ n = atoi ( p );
3734+ s_keepListener = n ;
3735+ }
3736+
36373737 p = getenv ( "LSAPI_AVOID_FORK" );
36383738 if ( p )
36393739 {
36403740 avoidFork = atoi ( p );
3741+ if (avoidFork )
3742+ {
3743+ s_keepListener = 2 ;
3744+ ch = * (p + strlen (p ) - 1 );
3745+ if ( ch == 'G' || ch == 'g' )
3746+ avoidFork *= 1024 * 1024 * 1024 ;
3747+ else if ( ch == 'M' || ch == 'm' )
3748+ avoidFork *= 1024 * 1024 ;
3749+ if (avoidFork >= 1024 * 10240 )
3750+ s_min_avail_pages = avoidFork / 4096 ;
3751+ }
36413752 }
36423753
36433754 p = getenv ( "LSAPI_ACCEPT_NOTIFY" );
@@ -3672,14 +3783,6 @@ int LSAPI_Init_Env_Parameters( fn_select_t fp )
36723783 LSAPI_Set_Max_Idle ( n );
36733784 }
36743785
3675- p = getenv ( "LSAPI_KEEP_LISTEN" );
3676- if ( p )
3677- {
3678- n = atoi ( p );
3679- s_keepListener = n ;
3680- }
3681-
3682-
36833786 if ( LSAPI_Is_Listen () )
36843787 {
36853788 n = 0 ;
@@ -3690,7 +3793,7 @@ int LSAPI_Init_Env_Parameters( fn_select_t fp )
36903793 n = atoi ( p );
36913794 if ( n > 1 )
36923795 {
3693- LSAPI_Init_Prefork_Server ( n , fp , avoidFork );
3796+ LSAPI_Init_Prefork_Server ( n , fp , avoidFork != 0 );
36943797 LSAPI_Set_Server_fd ( g_req .m_fdListen );
36953798 }
36963799
0 commit comments