@@ -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
@@ -170,7 +212,10 @@ void fpm_scoreboard_update_commit(
170
212
scoreboard -> active_max = scoreboard -> active ;
171
213
}
172
214
173
- fpm_unlock (scoreboard -> lock );
215
+ fpm_unlock (scoreboard -> writer_active );
216
+ #ifdef PHP_FPM_ZLOG_TRACE
217
+ zlog (ZLOG_DEBUG , "scoreboard: writer lock released by writer %d" , getpid ());
218
+ #endif
174
219
}
175
220
/* }}} */
176
221
@@ -234,16 +279,37 @@ struct fpm_scoreboard_proc_s *fpm_scoreboard_proc_get_from_child(struct fpm_chil
234
279
235
280
struct fpm_scoreboard_s * fpm_scoreboard_acquire (struct fpm_scoreboard_s * scoreboard , int nohang ) /* {{{ */
236
281
{
237
- struct fpm_scoreboard_s * s ;
238
-
239
- s = scoreboard ? scoreboard : fpm_scoreboard ;
282
+ struct fpm_scoreboard_s * s = scoreboard ? scoreboard : fpm_scoreboard ;
240
283
if (!s ) {
241
284
return NULL ;
242
285
}
243
286
244
- if (!fpm_spinlock (& s -> lock , nohang )) {
245
- return NULL ;
287
+ int retries = 0 ;
288
+ while (1 ) {
289
+ /* increment reader if no writer active */
290
+ fpm_spinlock (& s -> lock , 1 );
291
+ if (!s -> writer_active ) {
292
+ s -> reader_count += 1 ;
293
+ #ifdef PHP_FPM_ZLOG_TRACE
294
+ unsigned int current_reader_count = s -> reader_count ;
295
+ #endif
296
+ fpm_unlock (s -> lock );
297
+ #ifdef PHP_FPM_ZLOG_TRACE
298
+ zlog (ZLOG_DEBUG , "scoreboard: for proc %d reader incremented to value %u" , getpid (), current_reader_count );
299
+ #endif
300
+ break ;
301
+ }
302
+ fpm_unlock (s -> lock );
303
+
304
+ sched_yield ();
305
+
306
+ if (++ retries > FPM_SCOREBOARD_SPINLOCK_MAX_RETRIES ) {
307
+ zlog (ZLOG_WARNING , "scoreboard: reader waited too long for writer to release lock." );
308
+ fpm_scoreboard_readers_decrement (s );
309
+ return NULL ;
310
+ }
246
311
}
312
+
247
313
return s ;
248
314
}
249
315
/* }}} */
@@ -253,7 +319,7 @@ void fpm_scoreboard_release(struct fpm_scoreboard_s *scoreboard) {
253
319
return ;
254
320
}
255
321
256
- scoreboard -> lock = 0 ;
322
+ fpm_scoreboard_readers_decrement ( scoreboard ) ;
257
323
}
258
324
259
325
struct fpm_scoreboard_s * fpm_scoreboard_copy (struct fpm_scoreboard_s * scoreboard , int copy_procs )
0 commit comments