Skip to content

Commit 7bfd198

Browse files
committed
Merge branch 'PHP-8.4'
2 parents c015242 + 0cc0c7c commit 7bfd198

File tree

3 files changed

+97
-8
lines changed

3 files changed

+97
-8
lines changed

sapi/fpm/fpm/fpm_atomic.h

+19
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,25 @@ static inline int fpm_spinlock(atomic_t *lock, int try_once) /* {{{ */
156156
}
157157
/* }}} */
158158

159+
static inline int fpm_spinlock_with_max_retries(atomic_t *lock, unsigned int max_retries)
160+
{
161+
unsigned int retries = 0;
162+
163+
for (;;) {
164+
if (atomic_cmp_set(lock, 0, 1)) {
165+
return 1;
166+
}
167+
168+
sched_yield();
169+
170+
if (++retries > max_retries) {
171+
return 0;
172+
}
173+
}
174+
175+
return 1;
176+
}
177+
159178
#define fpm_unlock(lock) lock = 0
160179

161180
#endif

sapi/fpm/fpm/fpm_scoreboard.c

+74-8
Original file line numberDiff line numberDiff line change
@@ -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+
7692
static 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

@@ -173,7 +215,10 @@ void fpm_scoreboard_update_commit(
173215
scoreboard->memory_peak = memory_peak;
174216
}
175217

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
177222
}
178223
/* }}} */
179224

@@ -237,16 +282,37 @@ struct fpm_scoreboard_proc_s *fpm_scoreboard_proc_get_from_child(struct fpm_chil
237282

238283
struct fpm_scoreboard_s *fpm_scoreboard_acquire(struct fpm_scoreboard_s *scoreboard, int nohang) /* {{{ */
239284
{
240-
struct fpm_scoreboard_s *s;
241-
242-
s = scoreboard ? scoreboard : fpm_scoreboard;
285+
struct fpm_scoreboard_s *s = scoreboard ? scoreboard : fpm_scoreboard;
243286
if (!s) {
244287
return NULL;
245288
}
246289

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+
}
249314
}
315+
250316
return s;
251317
}
252318
/* }}} */
@@ -256,7 +322,7 @@ void fpm_scoreboard_release(struct fpm_scoreboard_s *scoreboard) {
256322
return;
257323
}
258324

259-
scoreboard->lock = 0;
325+
fpm_scoreboard_readers_decrement(scoreboard);
260326
}
261327

262328
struct fpm_scoreboard_s *fpm_scoreboard_copy(struct fpm_scoreboard_s *scoreboard, int copy_procs)

sapi/fpm/fpm/fpm_scoreboard.h

+4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
#define FPM_SCOREBOARD_LOCK_HANG 0
1919
#define FPM_SCOREBOARD_LOCK_NOHANG 1
2020

21+
#define FPM_SCOREBOARD_SPINLOCK_MAX_RETRIES 50000
22+
2123
struct fpm_scoreboard_proc_s {
2224
union {
2325
atomic_t lock;
@@ -52,6 +54,8 @@ struct fpm_scoreboard_s {
5254
atomic_t lock;
5355
char dummy[16];
5456
};
57+
atomic_t writer_active;
58+
unsigned int reader_count;
5559
char pool[32];
5660
int pm;
5761
time_t start_epoch;

0 commit comments

Comments
 (0)