@@ -55,6 +55,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
55
55
#include <fcntl.h>
56
56
#include <limits.h>
57
57
#include <sys/stat.h>
58
+ #include <sched.h>
58
59
#include <signal.h>
59
60
#include <stdlib.h>
60
61
#include <stdio.h>
@@ -115,18 +116,26 @@ typedef struct lsapi_MD5Context lsapi_MD5_CTX;
115
116
#define LSAPI_ST_REQ_BODY 2
116
117
#define LSAPI_ST_RESP_HEADER 4
117
118
#define LSAPI_ST_RESP_BODY 8
119
+ #define LSAPI_ST_BACKGROUND 16
118
120
119
121
#define LSAPI_RESP_BUF_SIZE 8192
120
122
#define LSAPI_INIT_RESP_HEADER_LEN 4096
121
123
124
+ enum
125
+ {
126
+ LSAPI_STATE_IDLE ,
127
+ LSAPI_STATE_CONNECTED ,
128
+ LSAPI_STATE_ACCEPTING ,
129
+ };
130
+
122
131
typedef struct _lsapi_child_status
123
132
{
124
133
int m_pid ;
125
134
long m_tmStart ;
126
135
127
136
volatile short m_iKillSent ;
128
137
volatile char m_inProcess ;
129
- volatile char m_connected ;
138
+ volatile char m_state ;
130
139
volatile int m_iReqCounter ;
131
140
132
141
volatile long m_tmWaitBegin ;
@@ -158,6 +167,9 @@ static int s_max_busy_workers = -1;
158
167
static char * s_stderr_log_path = NULL ;
159
168
static int s_stderr_is_pipe = 0 ;
160
169
static 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 ;
161
173
162
174
LSAPI_Request g_req =
163
175
{ .m_fdListen = -1 , .m_fd = -1 };
@@ -417,7 +429,7 @@ static void lsapi_close_connection(LSAPI_Request *pReq)
417
429
if (s_busy_workers )
418
430
__sync_fetch_and_sub (s_busy_workers , 1 );
419
431
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 ) ;
421
433
}
422
434
423
435
@@ -1560,7 +1572,8 @@ int LSAPI_Accept_r( LSAPI_Request * pReq )
1560
1572
else
1561
1573
{
1562
1574
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 );
1564
1577
if (s_busy_workers )
1565
1578
__sync_fetch_and_add (s_busy_workers , 1 );
1566
1579
lsapi_set_nblock ( pReq -> m_fd , 0 );
@@ -1623,6 +1636,37 @@ int LSAPI_Finish_r( LSAPI_Request * pReq )
1623
1636
}
1624
1637
1625
1638
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
+
1626
1670
void LSAPI_Reset_r ( LSAPI_Request * pReq )
1627
1671
{
1628
1672
pReq -> m_pRespBufPos = pReq -> m_pRespBuf ;
@@ -1808,7 +1852,11 @@ ssize_t LSAPI_Write_r( LSAPI_Request * pReq, const char * pBuf, size_t len )
1808
1852
ssize_t packetLen ;
1809
1853
int skip = 0 ;
1810
1854
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 )
1812
1860
return -1 ;
1813
1861
if ( pReq -> m_reqState & LSAPI_ST_RESP_HEADER )
1814
1862
{
@@ -2710,6 +2758,9 @@ int LSAPI_Init_Prefork_Server( int max_children, fn_select_t fp, int avoidFork )
2710
2758
s_ppid = getppid ();
2711
2759
s_pid = getpid ();
2712
2760
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
2713
2764
g_prefork_server -> m_iAvoidFork = avoidFork ;
2714
2765
g_prefork_server -> m_iMaxChildren = max_children ;
2715
2766
@@ -2844,11 +2895,19 @@ static void lsapi_sigchild( int signal )
2844
2895
child_status = find_child_status ( pid );
2845
2896
if ( child_status )
2846
2897
{
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 ))
2848
2901
{
2849
2902
if (s_busy_workers )
2850
2903
__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 );
2852
2911
}
2853
2912
child_status -> m_pid = 0 ;
2854
2913
-- g_prefork_server -> m_iCurChildren ;
@@ -2884,6 +2943,7 @@ static int lsapi_init_children_status(void)
2884
2943
s_busy_workers = (int * )g_prefork_server -> m_pChildrenStatusEnd ;
2885
2944
s_accepting_workers = s_busy_workers + 1 ;
2886
2945
s_global_counter = s_accepting_workers + 1 ;
2946
+ s_avail_pages = (size_t * )(s_global_counter + 1 );
2887
2947
return 0 ;
2888
2948
}
2889
2949
@@ -3023,6 +3083,17 @@ void set_skip_write()
3023
3083
{ s_skip_write = 1 ; }
3024
3084
3025
3085
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
+
3026
3097
static int lsapi_prefork_server_accept ( lsapi_prefork_server * pServer ,
3027
3098
LSAPI_Request * pReq )
3028
3099
{
@@ -3092,18 +3163,28 @@ static int lsapi_prefork_server_accept( lsapi_prefork_server * pServer,
3092
3163
}
3093
3164
}
3094
3165
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
3095
3172
FD_ZERO ( & readfds );
3096
3173
FD_SET ( pServer -> m_fd , & readfds );
3097
3174
timeout .tv_sec = 1 ;
3098
3175
timeout .tv_usec = 0 ;
3099
3176
ret = (* g_fnSelect )(pServer -> m_fd + 1 , & readfds , NULL , NULL , & timeout );
3100
3177
if (ret == 1 )
3101
3178
{
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 )
3105
3184
{
3106
- usleep ( 200 );
3185
+ usleep (400 );
3186
+ while (accepting -- > 0 )
3187
+ sched_yield ();
3107
3188
continue ;
3108
3189
}
3109
3190
}
@@ -3164,14 +3245,17 @@ static int lsapi_prefork_server_accept( lsapi_prefork_server * pServer,
3164
3245
if (pthread_atfork_func )
3165
3246
(* pthread_atfork_func )(NULL , NULL , set_skip_write );
3166
3247
3167
- s_worker_status -> m_connected = 1 ;
3248
+ __sync_lock_test_and_set (& s_worker_status -> m_state ,
3249
+ LSAPI_STATE_CONNECTED );
3168
3250
if (s_busy_workers )
3169
3251
__sync_add_and_fetch (s_busy_workers , 1 );
3170
3252
lsapi_set_nblock ( pReq -> m_fd , 0 );
3171
3253
//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 ))
3173
3256
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 )
3175
3259
{
3176
3260
close ( pReq -> m_fdListen );
3177
3261
pReq -> m_fdListen = -1 ;
@@ -3297,6 +3381,9 @@ int LSAPI_Prefork_Accept_r( LSAPI_Request * pReq )
3297
3381
timeout .tv_usec = 0 ;
3298
3382
if (fd == pReq -> m_fdListen )
3299
3383
{
3384
+ if (s_worker_status )
3385
+ __sync_lock_test_and_set (& s_worker_status -> m_state ,
3386
+ LSAPI_STATE_ACCEPTING );
3300
3387
if (s_accepting_workers )
3301
3388
__sync_fetch_and_add (s_accepting_workers , 1 );
3302
3389
}
@@ -3305,14 +3392,18 @@ int LSAPI_Prefork_Accept_r( LSAPI_Request * pReq )
3305
3392
{
3306
3393
if (s_accepting_workers )
3307
3394
__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 );
3308
3398
}
3309
3399
3310
3400
if ( ret == 0 )
3311
3401
{
3312
3402
if ( s_worker_status )
3313
3403
{
3314
3404
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 ()))
3316
3407
return -1 ;
3317
3408
}
3318
3409
++ wait_secs ;
@@ -3339,15 +3430,16 @@ int LSAPI_Prefork_Accept_r( LSAPI_Request * pReq )
3339
3430
if ( pReq -> m_fd != -1 )
3340
3431
{
3341
3432
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 );
3343
3435
if (s_busy_workers )
3344
3436
__sync_fetch_and_add (s_busy_workers , 1 );
3345
3437
3346
3438
fd = pReq -> m_fd ;
3347
3439
3348
3440
lsapi_set_nblock ( fd , 0 );
3349
3441
//init_conn_key( pReq->m_fd );
3350
- if ( !s_keepListener )
3442
+ if (!s_keepListener )
3351
3443
{
3352
3444
close ( pReq -> m_fdListen );
3353
3445
pReq -> m_fdListen = -1 ;
@@ -3613,6 +3705,7 @@ static int lsapi_reopen_stderr(const char *p)
3613
3705
int LSAPI_Init_Env_Parameters ( fn_select_t fp )
3614
3706
{
3615
3707
const char * p ;
3708
+ char ch ;
3616
3709
int n ;
3617
3710
int avoidFork = 0 ;
3618
3711
@@ -3634,10 +3727,28 @@ int LSAPI_Init_Env_Parameters( fn_select_t fp )
3634
3727
LSAPI_Set_Max_Reqs ( n );
3635
3728
}
3636
3729
3730
+ p = getenv ( "LSAPI_KEEP_LISTEN" );
3731
+ if ( p )
3732
+ {
3733
+ n = atoi ( p );
3734
+ s_keepListener = n ;
3735
+ }
3736
+
3637
3737
p = getenv ( "LSAPI_AVOID_FORK" );
3638
3738
if ( p )
3639
3739
{
3640
3740
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
+ }
3641
3752
}
3642
3753
3643
3754
p = getenv ( "LSAPI_ACCEPT_NOTIFY" );
@@ -3672,14 +3783,6 @@ int LSAPI_Init_Env_Parameters( fn_select_t fp )
3672
3783
LSAPI_Set_Max_Idle ( n );
3673
3784
}
3674
3785
3675
- p = getenv ( "LSAPI_KEEP_LISTEN" );
3676
- if ( p )
3677
- {
3678
- n = atoi ( p );
3679
- s_keepListener = n ;
3680
- }
3681
-
3682
-
3683
3786
if ( LSAPI_Is_Listen () )
3684
3787
{
3685
3788
n = 0 ;
@@ -3690,7 +3793,7 @@ int LSAPI_Init_Env_Parameters( fn_select_t fp )
3690
3793
n = atoi ( p );
3691
3794
if ( n > 1 )
3692
3795
{
3693
- LSAPI_Init_Prefork_Server ( n , fp , avoidFork );
3796
+ LSAPI_Init_Prefork_Server ( n , fp , avoidFork != 0 );
3694
3797
LSAPI_Set_Server_fd ( g_req .m_fdListen );
3695
3798
}
3696
3799
0 commit comments