@@ -181,12 +181,8 @@ __static_yoink("blink_xnu_aarch64"); // is apple silicon
181
181
#define HeaderLength (H ) (cpm.msg.headers[H].b - cpm.msg.headers[H].a)
182
182
#define HeaderEqualCase (H , S ) \
183
183
SlicesEqualCase(S, strlen(S), HeaderData(H), HeaderLength(H))
184
- #define LockInc (P ) \
185
- atomic_fetch_add_explicit((_Atomic(typeof(*(P))) *)(P), +1, \
186
- memory_order_relaxed)
187
- #define LockDec (P ) \
188
- atomic_fetch_add_explicit((_Atomic(typeof(*(P))) *)(P), -1, \
189
- memory_order_relaxed)
184
+ #define LockInc (P ) atomic_fetch_add_explicit(P, +1, memory_order_relaxed)
185
+ #define LockDec (P ) atomic_fetch_add_explicit(P, -1, memory_order_relaxed)
190
186
191
187
#define TRACE_BEGIN \
192
188
do { \
@@ -377,19 +373,21 @@ struct Blackhole {
377
373
} blackhole ;
378
374
379
375
static struct Shared {
380
- int workers ;
381
- struct timespec nowish ;
382
- struct timespec lastreindex ;
376
+ _Atomic (int ) workers ;
383
377
struct timespec lastmeltdown ;
378
+ struct timespec nowish ;
384
379
char currentdate [32 ];
385
380
struct rusage server ;
386
381
struct rusage children ;
387
382
struct Counters {
388
- #define C (x ) long x;
383
+ #define C (x ) _Atomic( long) x;
389
384
#include "tool/net/counters.inc"
390
385
#undef C
391
386
} c ;
392
- pthread_spinlock_t montermlock ;
387
+ pthread_mutex_t datetime_mu ;
388
+ pthread_mutex_t server_mu ;
389
+ pthread_mutex_t children_mu ;
390
+ pthread_mutex_t lastmeltdown_mu ;
393
391
} * shared ;
394
392
395
393
static const char kCounterNames [] =
@@ -1350,8 +1348,8 @@ static void CallSimpleHookIfDefined(const char *s) {
1350
1348
}
1351
1349
1352
1350
static void ReportWorkerExit (int pid , int ws ) {
1353
- int workers ;
1354
- workers = atomic_fetch_sub ((_Atomic ( int ) * ) & shared -> workers , 1 ) - 1 ;
1351
+ int workers =
1352
+ atomic_fetch_sub_explicit ( & shared -> workers , 1 , memory_order_release ) ;
1355
1353
if (WIFEXITED (ws )) {
1356
1354
if (WEXITSTATUS (ws )) {
1357
1355
LockInc (& shared -> c .failedchildren );
@@ -1383,7 +1381,9 @@ static void ReportWorkerResources(int pid, struct rusage *ru) {
1383
1381
1384
1382
static void HandleWorkerExit (int pid , int ws , struct rusage * ru ) {
1385
1383
LockInc (& shared -> c .connectionshandled );
1384
+ unassert (!pthread_mutex_lock (& shared -> children_mu ));
1386
1385
rusage_add (& shared -> children , ru );
1386
+ unassert (!pthread_mutex_unlock (& shared -> children_mu ));
1387
1387
ReportWorkerExit (pid , ws );
1388
1388
ReportWorkerResources (pid , ru );
1389
1389
if (hasonprocessdestroy ) {
@@ -2129,9 +2129,11 @@ static void UpdateCurrentDate(struct timespec now) {
2129
2129
int64_t t ;
2130
2130
struct tm tm ;
2131
2131
t = now .tv_sec ;
2132
- shared -> nowish = now ;
2133
2132
gmtime_r (& t , & tm );
2133
+ unassert (!pthread_mutex_lock (& shared -> datetime_mu ));
2134
+ shared -> nowish = now ;
2134
2135
FormatHttpDateTime (shared -> currentdate , & tm );
2136
+ unassert (!pthread_mutex_unlock (& shared -> datetime_mu ));
2135
2137
}
2136
2138
2137
2139
static int64_t GetGmtOffset (int64_t t ) {
@@ -2364,7 +2366,10 @@ static char *AppendCache(char *p, int64_t seconds, char *directive) {
2364
2366
p = stpcpy (p , directive );
2365
2367
}
2366
2368
p = AppendCrlf (p );
2367
- return AppendExpires (p , shared -> nowish .tv_sec + seconds );
2369
+ unassert (!pthread_mutex_lock (& shared -> datetime_mu ));
2370
+ long nowish_sec = shared -> nowish .tv_sec ;
2371
+ unassert (!pthread_mutex_unlock (& shared -> datetime_mu ));
2372
+ return AppendExpires (p , nowish_sec + seconds );
2368
2373
}
2369
2374
2370
2375
static inline char * AppendContentLength (char * p , size_t n ) {
@@ -3103,9 +3108,12 @@ td { padding-right: 3em; }\r\n\
3103
3108
<td valign=\"top\">\r\n\
3104
3109
<a href=\"/statusz\">/statusz</a>\r\n\
3105
3110
" );
3106
- if (shared -> c .connectionshandled ) {
3111
+ if (atomic_load_explicit (& shared -> c .connectionshandled ,
3112
+ memory_order_acquire )) {
3107
3113
appends (& cpm .outbuf , "says your redbean<br>\r\n" );
3114
+ unassert (!pthread_mutex_lock (& shared -> children_mu ));
3108
3115
AppendResourceReport (& cpm .outbuf , & shared -> children , "<br>\r\n" );
3116
+ unassert (!pthread_mutex_unlock (& shared -> children_mu ));
3109
3117
}
3110
3118
appends (& cpm .outbuf , "<td valign=\"top\">\r\n" );
3111
3119
and = "" ;
@@ -3127,12 +3135,12 @@ td { padding-right: 3em; }\r\n\
3127
3135
}
3128
3136
appendf (& cpm .outbuf , "%s%,ld second%s of operation<br>\r\n" , and , y .rem ,
3129
3137
y .rem == 1 ? "" : "s" );
3130
- x = shared -> c .messageshandled ;
3138
+ x = atomic_load_explicit ( & shared -> c .messageshandled , memory_order_relaxed ) ;
3131
3139
appendf (& cpm .outbuf , "%,ld message%s handled<br>\r\n" , x , x == 1 ? "" : "s" );
3132
- x = shared -> c .connectionshandled ;
3140
+ x = atomic_load_explicit ( & shared -> c .connectionshandled , memory_order_relaxed ) ;
3133
3141
appendf (& cpm .outbuf , "%,ld connection%s handled<br>\r\n" , x ,
3134
3142
x == 1 ? "" : "s" );
3135
- x = shared -> workers ;
3143
+ x = atomic_load_explicit ( & shared -> workers , memory_order_relaxed ) ;
3136
3144
appendf (& cpm .outbuf , "%,ld connection%s active<br>\r\n" , x ,
3137
3145
x == 1 ? "" : "s" );
3138
3146
appends (& cpm .outbuf , "</table>\r\n" );
@@ -3184,11 +3192,11 @@ static void AppendRusage(const char *a, struct rusage *ru) {
3184
3192
}
3185
3193
3186
3194
static void ServeCounters (void ) {
3187
- const long * c ;
3195
+ const _Atomic ( long ) * c ;
3188
3196
const char * s ;
3189
- for (c = (const long * )& shared -> c , s = kCounterNames ; * s ;
3197
+ for (c = (const _Atomic ( long ) * )& shared -> c , s = kCounterNames ; * s ;
3190
3198
++ c , s += strlen (s ) + 1 ) {
3191
- AppendLong1 (s , * c );
3199
+ AppendLong1 (s , atomic_load_explicit ( c , memory_order_relaxed ) );
3192
3200
}
3193
3201
}
3194
3202
@@ -3201,21 +3209,30 @@ static char *ServeStatusz(void) {
3201
3209
AppendLong1 ("pid" , getpid ());
3202
3210
AppendLong1 ("ppid" , getppid ());
3203
3211
AppendLong1 ("now" , timespec_real ().tv_sec );
3212
+ unassert (!pthread_mutex_lock (& shared -> datetime_mu ));
3204
3213
AppendLong1 ("nowish" , shared -> nowish .tv_sec );
3214
+ unassert (!pthread_mutex_unlock (& shared -> datetime_mu ));
3205
3215
AppendLong1 ("gmtoff" , gmtoff );
3206
3216
AppendLong1 ("CLK_TCK" , CLK_TCK );
3207
3217
AppendLong1 ("startserver" , startserver .tv_sec );
3218
+ unassert (!pthread_mutex_lock (& shared -> lastmeltdown_mu ));
3208
3219
AppendLong1 ("lastmeltdown" , shared -> lastmeltdown .tv_sec );
3209
- AppendLong1 ("workers" , shared -> workers );
3220
+ unassert (!pthread_mutex_unlock (& shared -> lastmeltdown_mu ));
3221
+ AppendLong1 ("workers" ,
3222
+ atomic_load_explicit (& shared -> workers , memory_order_relaxed ));
3210
3223
AppendLong1 ("assets.n" , assets .n );
3211
3224
#ifndef STATIC
3212
3225
lua_State * L = GL ;
3213
3226
AppendLong1 ("lua.memory" ,
3214
3227
lua_gc (L , LUA_GCCOUNT ) * 1024 + lua_gc (L , LUA_GCCOUNTB ));
3215
3228
#endif
3216
3229
ServeCounters ();
3230
+ unassert (!pthread_mutex_lock (& shared -> server_mu ));
3217
3231
AppendRusage ("server" , & shared -> server );
3232
+ unassert (!pthread_mutex_unlock (& shared -> server_mu ));
3233
+ unassert (!pthread_mutex_lock (& shared -> children_mu ));
3218
3234
AppendRusage ("children" , & shared -> children );
3235
+ unassert (!pthread_mutex_unlock (& shared -> children_mu ));
3219
3236
p = SetStatus (200 , "OK" );
3220
3237
p = AppendContentType (p , "text/plain" );
3221
3238
if (cpm .msg .version >= 11 ) {
@@ -3980,7 +3997,9 @@ static int LuaNilTlsError(lua_State *L, const char *s, int r) {
3980
3997
#include "tool/net/fetch.inc"
3981
3998
3982
3999
static int LuaGetDate (lua_State * L ) {
4000
+ unassert (!pthread_mutex_lock (& shared -> datetime_mu ));
3983
4001
lua_pushinteger (L , shared -> nowish .tv_sec );
4002
+ unassert (!pthread_mutex_unlock (& shared -> datetime_mu ));
3984
4003
return 1 ;
3985
4004
}
3986
4005
@@ -5034,7 +5053,7 @@ static int LuaProgramTokenBucket(lua_State *L) {
5034
5053
npassert (pid != -1 );
5035
5054
if (!pid )
5036
5055
Replenisher ();
5037
- ++ shared -> workers ;
5056
+ atomic_fetch_add_explicit ( & shared -> workers , 1 , memory_order_acquire ) ;
5038
5057
return 0 ;
5039
5058
}
5040
5059
@@ -5679,7 +5698,8 @@ static void LogClose(const char *reason) {
5679
5698
if (amtread || meltdown || killed ) {
5680
5699
LockInc (& shared -> c .fumbles );
5681
5700
INFOF ("(stat) %s %s with %,ld unprocessed and %,d handled (%,d workers)" ,
5682
- DescribeClient (), reason , amtread , messageshandled , shared -> workers );
5701
+ DescribeClient (), reason , amtread , messageshandled ,
5702
+ atomic_load_explicit (& shared -> workers , memory_order_relaxed ));
5683
5703
} else {
5684
5704
DEBUGF ("(stat) %s %s with %,d messages handled" , DescribeClient (), reason ,
5685
5705
messageshandled );
@@ -5737,14 +5757,18 @@ Content-Length: 22\r\n\
5737
5757
}
5738
5758
5739
5759
static void EnterMeltdownMode (void ) {
5760
+ unassert (!pthread_mutex_lock (& shared -> lastmeltdown_mu ));
5740
5761
if (timespec_cmp (timespec_sub (timespec_real (), shared -> lastmeltdown ),
5741
5762
(struct timespec ){1 }) < 0 ) {
5763
+ unassert (!pthread_mutex_unlock (& shared -> lastmeltdown_mu ));
5742
5764
return ;
5743
5765
}
5744
- WARNF ("(srvr) server is melting down (%,d workers)" , shared -> workers );
5745
- LOGIFNEG1 (kill (0 , SIGUSR2 ));
5746
5766
shared -> lastmeltdown = timespec_real ();
5747
- ++ shared -> c .meltdowns ;
5767
+ pthread_mutex_unlock (& shared -> lastmeltdown_mu );
5768
+ WARNF ("(srvr) server is melting down (%,d workers)" ,
5769
+ atomic_load_explicit (& shared -> workers , memory_order_relaxed ));
5770
+ LOGIFNEG1 (kill (0 , SIGUSR2 ));
5771
+ LockInc (& shared -> c .meltdowns );
5748
5772
}
5749
5773
5750
5774
static char * HandlePayloadDisconnect (void ) {
@@ -5861,7 +5885,9 @@ static void HandleHeartbeat(void) {
5861
5885
size_t i ;
5862
5886
UpdateCurrentDate (timespec_real ());
5863
5887
Reindex ();
5888
+ unassert (!pthread_mutex_lock (& shared -> server_mu ));
5864
5889
getrusage (RUSAGE_SELF , & shared -> server );
5890
+ unassert (!pthread_mutex_unlock (& shared -> server_mu ));
5865
5891
#ifndef STATIC
5866
5892
CallSimpleHookIfDefined ("OnServerHeartbeat" );
5867
5893
CollectGarbage ();
@@ -6481,7 +6507,9 @@ static bool HandleMessageActual(void) {
6481
6507
DEBUGF ("(clnt) could not synchronize message stream" );
6482
6508
}
6483
6509
if (cpm .msg .version >= 10 ) {
6510
+ unassert (!pthread_mutex_lock (& shared -> datetime_mu ));
6484
6511
p = AppendCrlf (stpcpy (stpcpy (p , "Date: " ), shared -> currentdate ));
6512
+ unassert (!pthread_mutex_unlock (& shared -> datetime_mu ));
6485
6513
if (!cpm .branded )
6486
6514
p = stpcpy (p , serverheader );
6487
6515
if (extrahdrs )
@@ -6751,7 +6779,9 @@ static int HandleConnection(size_t i) {
6751
6779
DEBUGF ("(token) can't acquire accept() token for client" );
6752
6780
}
6753
6781
startconnection = timespec_real ();
6754
- if (UNLIKELY (maxworkers ) && shared -> workers >= maxworkers ) {
6782
+ if (UNLIKELY (maxworkers ) &&
6783
+ atomic_load_explicit (& shared -> workers , memory_order_relaxed ) >=
6784
+ maxworkers ) {
6755
6785
EnterMeltdownMode ();
6756
6786
SendServiceUnavailable ();
6757
6787
close (client );
@@ -7346,6 +7376,14 @@ void RedBean(int argc, char *argv[]) {
7346
7376
(shared = mmap (NULL , ROUNDUP (sizeof (struct Shared ), getgransize ()),
7347
7377
PROT_READ | PROT_WRITE , MAP_SHARED | MAP_ANONYMOUS ,
7348
7378
-1 , 0 )));
7379
+ pthread_mutexattr_t attr ;
7380
+ unassert (!pthread_mutexattr_init (& attr ));
7381
+ unassert (!pthread_mutexattr_setpshared (& attr , PTHREAD_PROCESS_SHARED ));
7382
+ unassert (!pthread_mutex_init (& shared -> datetime_mu , & attr ));
7383
+ unassert (!pthread_mutex_init (& shared -> server_mu , & attr ));
7384
+ unassert (!pthread_mutex_init (& shared -> children_mu , & attr ));
7385
+ unassert (!pthread_mutex_init (& shared -> lastmeltdown_mu , & attr ));
7386
+ unassert (!pthread_mutexattr_destroy (& attr ));
7349
7387
if (daemonize ) {
7350
7388
for (int i = 0 ; i < 256 ; ++ i ) {
7351
7389
close (i );
0 commit comments