@@ -73,6 +73,22 @@ int fpm_scoreboard_init_main(void)
7373 return 0 ;
7474}
7575
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+
7692static struct fpm_scoreboard_s * fpm_scoreboard_get_for_update (struct fpm_scoreboard_s * scoreboard ) /* {{{ */
7793{
7894 if (!scoreboard ) {
@@ -93,7 +109,33 @@ void fpm_scoreboard_update_begin(struct fpm_scoreboard_s *scoreboard) /* {{{ */
93109 return ;
94110 }
95111
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+ }
97139}
98140/* }}} */
99141
@@ -170,7 +212,10 @@ void fpm_scoreboard_update_commit(
170212 scoreboard -> active_max = scoreboard -> active ;
171213 }
172214
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
174219}
175220/* }}} */
176221
@@ -234,16 +279,37 @@ struct fpm_scoreboard_proc_s *fpm_scoreboard_proc_get_from_child(struct fpm_chil
234279
235280struct fpm_scoreboard_s * fpm_scoreboard_acquire (struct fpm_scoreboard_s * scoreboard , int nohang ) /* {{{ */
236281{
237- struct fpm_scoreboard_s * s ;
238-
239- s = scoreboard ? scoreboard : fpm_scoreboard ;
282+ struct fpm_scoreboard_s * s = scoreboard ? scoreboard : fpm_scoreboard ;
240283 if (!s ) {
241284 return NULL ;
242285 }
243286
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+ }
246311 }
312+
247313 return s ;
248314}
249315/* }}} */
@@ -253,7 +319,7 @@ void fpm_scoreboard_release(struct fpm_scoreboard_s *scoreboard) {
253319 return ;
254320 }
255321
256- scoreboard -> lock = 0 ;
322+ fpm_scoreboard_readers_decrement ( scoreboard ) ;
257323}
258324
259325struct fpm_scoreboard_s * fpm_scoreboard_copy (struct fpm_scoreboard_s * scoreboard , int copy_procs )
0 commit comments