@@ -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>
@@ -113,18 +114,26 @@ typedef struct lsapi_MD5Context lsapi_MD5_CTX;
113
114
#define LSAPI_ST_REQ_BODY 2
114
115
#define LSAPI_ST_RESP_HEADER 4
115
116
#define LSAPI_ST_RESP_BODY 8
117
+ #define LSAPI_ST_BACKGROUND 16
116
118
117
119
#define LSAPI_RESP_BUF_SIZE 8192
118
120
#define LSAPI_INIT_RESP_HEADER_LEN 4096
119
121
122
+ enum
123
+ {
124
+ LSAPI_STATE_IDLE ,
125
+ LSAPI_STATE_CONNECTED ,
126
+ LSAPI_STATE_ACCEPTING ,
127
+ };
128
+
120
129
typedef struct _lsapi_child_status
121
130
{
122
131
int m_pid ;
123
132
long m_tmStart ;
124
133
125
134
volatile short m_iKillSent ;
126
135
volatile char m_inProcess ;
127
- volatile char m_connected ;
136
+ volatile char m_state ;
128
137
volatile int m_iReqCounter ;
129
138
130
139
volatile long m_tmWaitBegin ;
@@ -156,6 +165,9 @@ static int s_max_busy_workers = -1;
156
165
static char * s_stderr_log_path = NULL ;
157
166
static int s_stderr_is_pipe = 0 ;
158
167
static int s_ignore_pid = -1 ;
168
+ static size_t s_total_pages = 1 ;
169
+ static size_t s_min_avail_pages = 256 * 1024 ;
170
+ static size_t * s_avail_pages = & s_total_pages ;
159
171
160
172
LSAPI_Request g_req =
161
173
{ .m_fdListen = -1 , .m_fd = -1 };
@@ -415,7 +427,7 @@ static void lsapi_close_connection(LSAPI_Request *pReq)
415
427
if (s_busy_workers )
416
428
__sync_fetch_and_sub (s_busy_workers , 1 );
417
429
if (s_worker_status )
418
- s_worker_status -> m_connected = 0 ;
430
+ __sync_lock_test_and_set ( & s_worker_status -> m_state , LSAPI_STATE_IDLE ) ;
419
431
}
420
432
421
433
@@ -1558,7 +1570,8 @@ int LSAPI_Accept_r( LSAPI_Request * pReq )
1558
1570
else
1559
1571
{
1560
1572
if (s_worker_status )
1561
- s_worker_status -> m_connected = 1 ;
1573
+ __sync_lock_test_and_set (& s_worker_status -> m_state ,
1574
+ LSAPI_STATE_CONNECTED );
1562
1575
if (s_busy_workers )
1563
1576
__sync_fetch_and_add (s_busy_workers , 1 );
1564
1577
lsapi_set_nblock ( pReq -> m_fd , 0 );
@@ -1621,6 +1634,37 @@ int LSAPI_Finish_r( LSAPI_Request * pReq )
1621
1634
}
1622
1635
1623
1636
1637
+ int LSAPI_End_Response_r (LSAPI_Request * pReq )
1638
+ {
1639
+ if (!pReq )
1640
+ return -1 ;
1641
+ if (pReq -> m_reqState )
1642
+ {
1643
+ if ( pReq -> m_fd != -1 )
1644
+ {
1645
+ if ( pReq -> m_reqState & LSAPI_ST_RESP_HEADER )
1646
+ {
1647
+ LSAPI_FinalizeRespHeaders_r ( pReq );
1648
+ }
1649
+ if ( pReq -> m_pRespBufPos != pReq -> m_pRespBuf )
1650
+ {
1651
+ Flush_RespBuf_r ( pReq );
1652
+ }
1653
+
1654
+ pReq -> m_pIovecCur -> iov_base = (void * )& finish ;
1655
+ pReq -> m_pIovecCur -> iov_len = LSAPI_PACKET_HEADER_LEN ;
1656
+ pReq -> m_totalLen += LSAPI_PACKET_HEADER_LEN ;
1657
+ ++ pReq -> m_pIovecCur ;
1658
+ LSAPI_Flush_r ( pReq );
1659
+ }
1660
+ send_conn_close_notification (pReq -> m_fd );
1661
+ lsapi_close_connection (pReq );
1662
+ pReq -> m_reqState |= LSAPI_ST_BACKGROUND ;
1663
+ }
1664
+ return 0 ;
1665
+ }
1666
+
1667
+
1624
1668
void LSAPI_Reset_r ( LSAPI_Request * pReq )
1625
1669
{
1626
1670
pReq -> m_pRespBufPos = pReq -> m_pRespBuf ;
@@ -1806,7 +1850,11 @@ ssize_t LSAPI_Write_r( LSAPI_Request * pReq, const char * pBuf, size_t len )
1806
1850
ssize_t packetLen ;
1807
1851
int skip = 0 ;
1808
1852
1809
- if ( !pReq || !pBuf || (pReq -> m_fd == -1 ) )
1853
+ if (!pReq || !pBuf )
1854
+ return -1 ;
1855
+ if (pReq -> m_reqState & LSAPI_ST_BACKGROUND )
1856
+ return len ;
1857
+ if (pReq -> m_fd == -1 )
1810
1858
return -1 ;
1811
1859
if ( pReq -> m_reqState & LSAPI_ST_RESP_HEADER )
1812
1860
{
@@ -2708,6 +2756,9 @@ int LSAPI_Init_Prefork_Server( int max_children, fn_select_t fp, int avoidFork )
2708
2756
s_ppid = getppid ();
2709
2757
s_pid = getpid ();
2710
2758
setpgid ( s_pid , s_pid );
2759
+ #if defined(linux ) || defined(__linux ) || defined(__linux__ ) || defined(__gnu_linux__ )
2760
+ s_total_pages = sysconf (_SC_PHYS_PAGES );
2761
+ #endif
2711
2762
g_prefork_server -> m_iAvoidFork = avoidFork ;
2712
2763
g_prefork_server -> m_iMaxChildren = max_children ;
2713
2764
@@ -2842,11 +2893,19 @@ static void lsapi_sigchild( int signal )
2842
2893
child_status = find_child_status ( pid );
2843
2894
if ( child_status )
2844
2895
{
2845
- if (child_status -> m_connected )
2896
+ if (__sync_bool_compare_and_swap (& child_status -> m_state ,
2897
+ LSAPI_STATE_CONNECTED ,
2898
+ LSAPI_STATE_IDLE ))
2846
2899
{
2847
2900
if (s_busy_workers )
2848
2901
__sync_fetch_and_sub (s_busy_workers , 1 );
2849
- child_status -> m_connected = 0 ;
2902
+ }
2903
+ else if (__sync_bool_compare_and_swap (& child_status -> m_state ,
2904
+ LSAPI_STATE_ACCEPTING ,
2905
+ LSAPI_STATE_IDLE ))
2906
+ {
2907
+ if (s_accepting_workers )
2908
+ __sync_fetch_and_sub (s_accepting_workers , 1 );
2850
2909
}
2851
2910
child_status -> m_pid = 0 ;
2852
2911
-- g_prefork_server -> m_iCurChildren ;
@@ -2882,6 +2941,7 @@ static int lsapi_init_children_status(void)
2882
2941
s_busy_workers = (int * )g_prefork_server -> m_pChildrenStatusEnd ;
2883
2942
s_accepting_workers = s_busy_workers + 1 ;
2884
2943
s_global_counter = s_accepting_workers + 1 ;
2944
+ s_avail_pages = (size_t * )(s_global_counter + 1 );
2885
2945
return 0 ;
2886
2946
}
2887
2947
@@ -3021,6 +3081,17 @@ void set_skip_write()
3021
3081
{ s_skip_write = 1 ; }
3022
3082
3023
3083
3084
+ int is_enough_free_mem ()
3085
+ {
3086
+ #if defined(linux ) || defined(__linux ) || defined(__linux__ ) || defined(__gnu_linux__ )
3087
+ //minimum 1GB or 10% available free memory
3088
+ return (* s_avail_pages > s_min_avail_pages
3089
+ || (* s_avail_pages * 10 ) / s_total_pages > 0 );
3090
+ #endif
3091
+ return 1 ;
3092
+ }
3093
+
3094
+
3024
3095
static int lsapi_prefork_server_accept ( lsapi_prefork_server * pServer ,
3025
3096
LSAPI_Request * pReq )
3026
3097
{
@@ -3090,18 +3161,28 @@ static int lsapi_prefork_server_accept( lsapi_prefork_server * pServer,
3090
3161
}
3091
3162
}
3092
3163
3164
+ #if defined(linux ) || defined(__linux ) || defined(__linux__ ) || defined(__gnu_linux__ )
3165
+ * s_avail_pages = sysconf (_SC_AVPHYS_PAGES );
3166
+ lsapi_log ("Memory total: %zd, free: %zd, free %%%zd\n" ,
3167
+ s_total_pages , * s_avail_pages , * s_avail_pages * 100 / s_total_pages );
3168
+
3169
+ #endif
3093
3170
FD_ZERO ( & readfds );
3094
3171
FD_SET ( pServer -> m_fd , & readfds );
3095
3172
timeout .tv_sec = 1 ;
3096
3173
timeout .tv_usec = 0 ;
3097
3174
ret = (* g_fnSelect )(pServer -> m_fd + 1 , & readfds , NULL , NULL , & timeout );
3098
3175
if (ret == 1 )
3099
3176
{
3100
- if (pServer -> m_iCurChildren >= pServer -> m_iMaxChildren
3101
- && s_accepting_workers
3102
- && (ret = __sync_add_and_fetch (s_accepting_workers , 0 )) > 0 )
3177
+ int accepting = 0 ;
3178
+ if (s_accepting_workers )
3179
+ accepting = __sync_add_and_fetch (s_accepting_workers , 0 );
3180
+
3181
+ if (pServer -> m_iCurChildren > 0 && accepting > 0 )
3103
3182
{
3104
- usleep ( 200 );
3183
+ usleep (400 );
3184
+ while (accepting -- > 0 )
3185
+ sched_yield ();
3105
3186
continue ;
3106
3187
}
3107
3188
}
@@ -3162,14 +3243,17 @@ static int lsapi_prefork_server_accept( lsapi_prefork_server * pServer,
3162
3243
if (pthread_atfork_func )
3163
3244
(* pthread_atfork_func )(NULL , NULL , set_skip_write );
3164
3245
3165
- s_worker_status -> m_connected = 1 ;
3246
+ __sync_lock_test_and_set (& s_worker_status -> m_state ,
3247
+ LSAPI_STATE_CONNECTED );
3166
3248
if (s_busy_workers )
3167
3249
__sync_add_and_fetch (s_busy_workers , 1 );
3168
3250
lsapi_set_nblock ( pReq -> m_fd , 0 );
3169
3251
//keep it open if busy_count is used.
3170
- if (s_busy_workers && s_uid != 0 )
3252
+ if (s_busy_workers
3253
+ && * s_busy_workers > (pServer -> m_iMaxChildren >> 1 ))
3171
3254
s_keepListener = 1 ;
3172
- else if ( pReq -> m_fdListen != -1 )
3255
+ if ((s_uid == 0 || !s_keepListener || !is_enough_free_mem ())
3256
+ && pReq -> m_fdListen != -1 )
3173
3257
{
3174
3258
close ( pReq -> m_fdListen );
3175
3259
pReq -> m_fdListen = -1 ;
@@ -3295,6 +3379,9 @@ int LSAPI_Prefork_Accept_r( LSAPI_Request * pReq )
3295
3379
timeout .tv_usec = 0 ;
3296
3380
if (fd == pReq -> m_fdListen )
3297
3381
{
3382
+ if (s_worker_status )
3383
+ __sync_lock_test_and_set (& s_worker_status -> m_state ,
3384
+ LSAPI_STATE_ACCEPTING );
3298
3385
if (s_accepting_workers )
3299
3386
__sync_fetch_and_add (s_accepting_workers , 1 );
3300
3387
}
@@ -3303,14 +3390,18 @@ int LSAPI_Prefork_Accept_r( LSAPI_Request * pReq )
3303
3390
{
3304
3391
if (s_accepting_workers )
3305
3392
__sync_fetch_and_sub (s_accepting_workers , 1 );
3393
+ if (s_worker_status )
3394
+ __sync_lock_test_and_set (& s_worker_status -> m_state ,
3395
+ LSAPI_STATE_IDLE );
3306
3396
}
3307
3397
3308
3398
if ( ret == 0 )
3309
3399
{
3310
3400
if ( s_worker_status )
3311
3401
{
3312
3402
s_worker_status -> m_inProcess = 0 ;
3313
- if (fd == pReq -> m_fdListen )
3403
+ if (fd == pReq -> m_fdListen
3404
+ && (s_keepListener != 2 || !is_enough_free_mem ()))
3314
3405
return -1 ;
3315
3406
}
3316
3407
++ wait_secs ;
@@ -3337,15 +3428,16 @@ int LSAPI_Prefork_Accept_r( LSAPI_Request * pReq )
3337
3428
if ( pReq -> m_fd != -1 )
3338
3429
{
3339
3430
if (s_worker_status )
3340
- s_worker_status -> m_connected = 1 ;
3431
+ __sync_lock_test_and_set (& s_worker_status -> m_state ,
3432
+ LSAPI_STATE_CONNECTED );
3341
3433
if (s_busy_workers )
3342
3434
__sync_fetch_and_add (s_busy_workers , 1 );
3343
3435
3344
3436
fd = pReq -> m_fd ;
3345
3437
3346
3438
lsapi_set_nblock ( fd , 0 );
3347
3439
//init_conn_key( pReq->m_fd );
3348
- if ( !s_keepListener )
3440
+ if (!s_keepListener )
3349
3441
{
3350
3442
close ( pReq -> m_fdListen );
3351
3443
pReq -> m_fdListen = -1 ;
@@ -3611,6 +3703,7 @@ static int lsapi_reopen_stderr(const char *p)
3611
3703
int LSAPI_Init_Env_Parameters ( fn_select_t fp )
3612
3704
{
3613
3705
const char * p ;
3706
+ char ch ;
3614
3707
int n ;
3615
3708
int avoidFork = 0 ;
3616
3709
@@ -3632,10 +3725,28 @@ int LSAPI_Init_Env_Parameters( fn_select_t fp )
3632
3725
LSAPI_Set_Max_Reqs ( n );
3633
3726
}
3634
3727
3728
+ p = getenv ( "LSAPI_KEEP_LISTEN" );
3729
+ if ( p )
3730
+ {
3731
+ n = atoi ( p );
3732
+ s_keepListener = n ;
3733
+ }
3734
+
3635
3735
p = getenv ( "LSAPI_AVOID_FORK" );
3636
3736
if ( p )
3637
3737
{
3638
3738
avoidFork = atoi ( p );
3739
+ if (avoidFork )
3740
+ {
3741
+ s_keepListener = 2 ;
3742
+ ch = * (p + strlen (p ) - 1 );
3743
+ if ( ch == 'G' || ch == 'g' )
3744
+ avoidFork *= 1024 * 1024 * 1024 ;
3745
+ else if ( ch == 'M' || ch == 'm' )
3746
+ avoidFork *= 1024 * 1024 ;
3747
+ if (avoidFork >= 1024 * 10240 )
3748
+ s_min_avail_pages = avoidFork / 4096 ;
3749
+ }
3639
3750
}
3640
3751
3641
3752
p = getenv ( "LSAPI_ACCEPT_NOTIFY" );
@@ -3670,14 +3781,6 @@ int LSAPI_Init_Env_Parameters( fn_select_t fp )
3670
3781
LSAPI_Set_Max_Idle ( n );
3671
3782
}
3672
3783
3673
- p = getenv ( "LSAPI_KEEP_LISTEN" );
3674
- if ( p )
3675
- {
3676
- n = atoi ( p );
3677
- s_keepListener = n ;
3678
- }
3679
-
3680
-
3681
3784
if ( LSAPI_Is_Listen () )
3682
3785
{
3683
3786
n = 0 ;
@@ -3688,7 +3791,7 @@ int LSAPI_Init_Env_Parameters( fn_select_t fp )
3688
3791
n = atoi ( p );
3689
3792
if ( n > 1 )
3690
3793
{
3691
- LSAPI_Init_Prefork_Server ( n , fp , avoidFork );
3794
+ LSAPI_Init_Prefork_Server ( n , fp , avoidFork != 0 );
3692
3795
LSAPI_Set_Server_fd ( g_req .m_fdListen );
3693
3796
}
3694
3797
0 commit comments