Skip to content

Commit 34809c2

Browse files
onWritable callback should support setting a new onWritable callback from inside itself
1 parent ef78dfd commit 34809c2

1 file changed

Lines changed: 40 additions & 12 deletions

File tree

src/HttpResponseData.h

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,23 +43,51 @@ struct HttpResponseData : AsyncSocketData<SSL>, HttpParser {
4343
state &= ~HttpResponseData<SSL>::HTTP_RESPONSE_PENDING;
4444
}
4545

46-
/* Caller of onWritable. It is possible onWritable calls markDone so we need to borrow it. */
46+
/* Caller of onWritable. It is possible onWritable calls markDone so we need to borrow it.
47+
* It is also possible user code sets a new onWritable while running user registered onWritable. */
4748
bool callOnWritable(uintmax_t offset) {
48-
/* Borrow real onWritable */
49+
/* 1. Borrow the real callback */
4950
MoveOnlyFunction<bool(uintmax_t)> borrowedOnWritable = std::move(onWritable);
50-
51-
/* Set onWritable to placeholder */
52-
onWritable = [](uintmax_t) {return true;};
53-
54-
/* Run borrowed onWritable */
51+
52+
/* 2. Setup the stack-based detection flag */
53+
bool placeholderReplaced = false;
54+
55+
struct Sentinel {
56+
bool *replacedFlag;
57+
Sentinel(bool *f) : replacedFlag(f) {}
58+
59+
Sentinel(Sentinel &&other) noexcept : replacedFlag(other.replacedFlag) {
60+
other.replacedFlag = nullptr;
61+
}
62+
63+
~Sentinel() {
64+
if (replacedFlag) {
65+
*replacedFlag = true;
66+
}
67+
}
68+
69+
/* Delete copy to ensure move-only semantics */
70+
Sentinel(const Sentinel&) = delete;
71+
Sentinel& operator=(const Sentinel&) = delete;
72+
};
73+
74+
/* 3. Set placeholder with the captured Sentinel */
75+
onWritable = [tracker = Sentinel(&placeholderReplaced)](uintmax_t) {
76+
return true;
77+
};
78+
79+
/* 4. Run the borrowed callback */
5580
bool ret = borrowedOnWritable(offset);
56-
57-
/* If we still have onWritable (the placeholder) then move back the real one */
58-
if (onWritable) {
59-
/* We haven't reset onWritable, so give it back */
81+
82+
/*
83+
5. If placeholderReplaced is STILL false, it means the lambda (and its Sentinel)
84+
is still sitting inside 'onWritable'. If it's true, the lambda was destroyed
85+
to make room for a new one.
86+
*/
87+
if (!placeholderReplaced) {
6088
onWritable = std::move(borrowedOnWritable);
6189
}
62-
90+
6391
return ret;
6492
}
6593
private:

0 commit comments

Comments
 (0)