@@ -73,6 +73,22 @@ int fpm_scoreboard_init_main(void)
73
73
return 0 ;
74
74
}
75
75
76
+ static inline void fpm_scoreboard_readers_decrement (struct fpm_scoreboard_s * scoreboard )
77
+ {
78
+ fpm_spinlock (& scoreboard -> lock , 1 );
79
+ if (scoreboard -> reader_count > 0 ) {
80
+ scoreboard -> reader_count -= 1 ;
81
+ }
82
+ #ifdef PHP_FPM_ZLOG_TRACE
83
+ unsigned int current_reader_count = scoreboard -> reader_count ;
84
+ #endif
85
+ fpm_unlock (scoreboard -> lock );
86
+ #ifdef PHP_FPM_ZLOG_TRACE
87
+ /* this is useful for debugging but currently needs to be hidden as external logger would always log it */
88
+ zlog (ZLOG_DEBUG , "scoreboard: for proc %d reader decremented to value %u" , getpid (), current_reader_count );
89
+ #endif
90
+ }
91
+
76
92
static struct fpm_scoreboard_s * fpm_scoreboard_get_for_update (struct fpm_scoreboard_s * scoreboard ) /* {{{ */
77
93
{
78
94
if (!scoreboard ) {
@@ -93,7 +109,33 @@ void fpm_scoreboard_update_begin(struct fpm_scoreboard_s *scoreboard) /* {{{ */
93
109
return ;
94
110
}
95
111
96
- fpm_spinlock (& scoreboard -> lock , 0 );
112
+ int retries = 0 ;
113
+ while (1 ) {
114
+ fpm_spinlock (& scoreboard -> lock , 1 );
115
+ if (scoreboard -> reader_count == 0 ) {
116
+ if (!fpm_spinlock_with_max_retries (& scoreboard -> writer_active , FPM_SCOREBOARD_SPINLOCK_MAX_RETRIES )) {
117
+ /* in this case the writer might have crashed so just warn and continue as the lock was acquired */
118
+ zlog (ZLOG_WARNING , "scoreboard: writer %d waited too long for another writer to release lock." , getpid ());
119
+ }
120
+ #ifdef PHP_FPM_ZLOG_TRACE
121
+ else {
122
+ zlog (ZLOG_DEBUG , "scoreboard: writer lock acquired by writer %d" , getpid ());
123
+ }
124
+ #endif
125
+ fpm_unlock (scoreboard -> lock );
126
+ break ;
127
+ }
128
+ fpm_unlock (scoreboard -> lock );
129
+
130
+ if (++ retries > FPM_SCOREBOARD_SPINLOCK_MAX_RETRIES ) {
131
+ /* decrement reader count by 1 (assuming a killed or crashed reader) */
132
+ fpm_scoreboard_readers_decrement (scoreboard );
133
+ zlog (ZLOG_WARNING , "scoreboard: writer detected a potential crashed reader, decrementing reader count." );
134
+ retries = 0 ;
135
+ }
136
+
137
+ sched_yield ();
138
+ }
97
139
}
98
140
/* }}} */
99
141
@@ -173,7 +215,10 @@ void fpm_scoreboard_update_commit(
173
215
scoreboard -> memory_peak = memory_peak ;
174
216
}
175
217
176
- fpm_unlock (scoreboard -> lock );
218
+ fpm_unlock (scoreboard -> writer_active );
219
+ #ifdef PHP_FPM_ZLOG_TRACE
220
+ zlog (ZLOG_DEBUG , "scoreboard: writer lock released by writer %d" , getpid ());
221
+ #endif
177
222
}
178
223
/* }}} */
179
224
@@ -237,16 +282,37 @@ struct fpm_scoreboard_proc_s *fpm_scoreboard_proc_get_from_child(struct fpm_chil
237
282
238
283
struct fpm_scoreboard_s * fpm_scoreboard_acquire (struct fpm_scoreboard_s * scoreboard , int nohang ) /* {{{ */
239
284
{
240
- struct fpm_scoreboard_s * s ;
241
-
242
- s = scoreboard ? scoreboard : fpm_scoreboard ;
285
+ struct fpm_scoreboard_s * s = scoreboard ? scoreboard : fpm_scoreboard ;
243
286
if (!s ) {
244
287
return NULL ;
245
288
}
246
289
247
- if (!fpm_spinlock (& s -> lock , nohang )) {
248
- return NULL ;
290
+ int retries = 0 ;
291
+ while (1 ) {
292
+ /* increment reader if no writer active */
293
+ fpm_spinlock (& s -> lock , 1 );
294
+ if (!s -> writer_active ) {
295
+ s -> reader_count += 1 ;
296
+ #ifdef PHP_FPM_ZLOG_TRACE
297
+ unsigned int current_reader_count = s -> reader_count ;
298
+ #endif
299
+ fpm_unlock (s -> lock );
300
+ #ifdef PHP_FPM_ZLOG_TRACE
301
+ zlog (ZLOG_DEBUG , "scoreboard: for proc %d reader incremented to value %u" , getpid (), current_reader_count );
302
+ #endif
303
+ break ;
304
+ }
305
+ fpm_unlock (s -> lock );
306
+
307
+ sched_yield ();
308
+
309
+ if (++ retries > FPM_SCOREBOARD_SPINLOCK_MAX_RETRIES ) {
310
+ zlog (ZLOG_WARNING , "scoreboard: reader waited too long for writer to release lock." );
311
+ fpm_scoreboard_readers_decrement (s );
312
+ return NULL ;
313
+ }
249
314
}
315
+
250
316
return s ;
251
317
}
252
318
/* }}} */
@@ -256,7 +322,7 @@ void fpm_scoreboard_release(struct fpm_scoreboard_s *scoreboard) {
256
322
return ;
257
323
}
258
324
259
- scoreboard -> lock = 0 ;
325
+ fpm_scoreboard_readers_decrement ( scoreboard ) ;
260
326
}
261
327
262
328
struct fpm_scoreboard_s * fpm_scoreboard_copy (struct fpm_scoreboard_s * scoreboard , int copy_procs )
0 commit comments