Skip to content

Fix pollsession turn queue starving session addition and removal - #637

Open
Roytak wants to merge 1 commit into
develfrom
pspoll-prio-queue
Open

Fix pollsession turn queue starving session addition and removal#637
Roytak wants to merge 1 commit into
develfrom
pspoll-prio-queue

Conversation

@Roytak

@Roytak Roytak commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

The turn queue was strictly FIFO, so nc_ps_add_session() and the other
bounded operations queued up behind every poll thread, each holding its turn
for the whole timeout it was given so a new session went unpolled for up to
thread_count * poll_timeout msec.

Threads now queue up with a priority: everything except nc_ps_poll() only
walks the session array, so it is queued in front of the poll threads, and the
polling thread hands the turn over once it is no longer first. Queue entries
are pthread_t, so there are no generated IDs. The queue also grows on demand
instead of failing once PSPOLL_THREAD_COUNT threads share a pollsession,
which silently dropped the session being added.

Also fixes the session idle timeout being compared against the poll deadline
instead of the current time. New test_ps_poll covers the above.

Fixes #561

Comment thread CMakeLists.txt Outdated
set(READ_INACTIVE_TIMEOUT 20 CACHE STRING "Maximum number of seconds waiting for new data once some data have arrived")
set(READ_ACTIVE_TIMEOUT 300 CACHE STRING "Maximum number of seconds for receiving a full message")
set(MAX_PSPOLL_THREAD_COUNT 6 CACHE STRING "Maximum number of threads that could simultaneously access a ps_poll structure")
set(PSPOLL_THREAD_COUNT 6 CACHE STRING "Expected number of threads that simultaneously access a ps_poll structure, its queue grows past this value if needed")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be completely removed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed from both CMakeLists.txt, README.md and libnetconf2.pc.in. Will need to update netopeer2's cmake accordingly.

Comment thread CMakeLists.txt Outdated
Comment thread src/session_server.c Outdated
if (!ps->queue_size) {
/* start with the configured size */
new_size = (NC_PS_QUEUE_SIZE > 1) ? NC_PS_QUEUE_SIZE : 2;
} else if (ps->queue_size > UINT8_MAX / 2) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why only half of UINT8_MAX?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added an extra branch to cap at UINT8_MAX.

Comment thread src/session_server.c Outdated
Comment thread src/session_p.h Outdated
Comment thread src/session_server.c Outdated
Comment thread src/session_server.c Outdated
Comment thread src/session_server.c Outdated
nc_ps_queue_add(ps, 0);

/* broadcast to all other threads that the queue moved */
pthread_cond_broadcast(&ps->cond);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely more efficient to pthread_cond_signal() in this case.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to pthread_cond_signal at the cost of each thread needing it's own cond.

Comment thread src/session_server.c Outdated
The pollsession turn queue was strictly FIFO, so nc_ps_add_session() and
the other bounded operations queued up behind every poll thread and each
of them kept its turn for the whole timeout it was given. A newly
established session was therefore not polled for up to
thread_count * poll_timeout msec.

Threads now queue up with a priority. Every operation except nc_ps_poll()
only walks the session array, so it is queued up in front of all the poll
threads, and the polling thread notices it is no longer at the head of the
queue and hands the turn over. The turn holder is tracked separately from
the queue head, as the head is now the thread that gets the turn next.

The queue is also allocated and grows on demand instead of failing once
MAX_PSPOLL_THREAD_COUNT threads use the same pollsession, which silently
dropped the session being added.

Waiting longer than NC_PS_QUEUE_TIMEOUT is only an error for the high
priority threads now, a poll thread may legitimately wait behind several
other poll threads for longer than that.

Also fixes the session idle timeout being compared against the poll
deadline instead of the current time, which terminated active sessions
when the poll timeout was longer than the remaining idle time, and read
an uninitialized timespec with an infinite timeout.

Fixes #561
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants