Attached is an early, still very rough patch to add support for 'work
queues' to quagga. Along with second patch to convert rib_process'ing
in zebra_rib.c to use work_queues. These patches are a generic rework
of an earlier proof-of-concept version i had hacked directly into
zebra_rib.c. The proof-of-concept worked, but i havnt tested this
rework, it very likely has bugs :) (be glad to hear results of
testing - but dont try on anything but unimportant machine). I hope
to next look at converting code in bgpd to work_queues - which
hopefully would alleviate the bgp idle timeout problem.
Work queues allow often repeated work to be put onto a queue, to be
dealt with by the threads subsystem, rather than have to potentially
spend a long time on repeated work (and blocking the current thread).
The work queued, by default, is processed in a serial fashion. While
ideally a work_queue should be processable by one (user supplied)
work function, individual queue items can provide their own (useful
for serialising work to some object, where bulk of work is done via
one function, but occassionally an item may need to be worked in some
other way.) When processing work queues, the threads subsystem will
periodically check how much time has elapsed and yield control if
neccessary.
Code that currently spend long amounts of time iterating through a
list or route_table, processing each node and hence taking up lots
of time (and causing response problems in quagga) are ideal
candidates for porting to work queues. (eg zebra's rib processing,
bgpd's rib processing).
the basic units are:
work_queue_t - defines a work queue
work_queue_spec_t - the specification for a work queue, user
defines work function, default error strategy, optional error
handler, etc..
work_queue_item_t - an item of work, may optionally define its own
work_queue_spec_t to override the default work_queue spec.
Process is:
- initialises a new work queue, work_queue_new(). A work queue will
typically be long lived - length of the process - and be specific to
some task. Fill in the spec (esp the caller data deletion callback!)
- as and when needed, submit a work_queue_item_t to the queue:
- prepare some caller specific data structure
- work_queue_item_new()
- work_queue_spec_new() - /if/ item specific spec is required
- fill in spec, attach it to item
- attach caller specific data structure to item
- submit the item to the work_queue, work_queue_item_add
deletion of items and specs is done by the thread subsystem.
thats it.. thread subsystem takes care of rest. user's provided work
function will be called for each item submitted at some later stage
as the queue is processed. User's provided del_item_data callback
will be used when deleting items.
The work function can indicate by its return status what action the
work queue processing subsystem should take:
WQ_ERROR - run error handler, if provided
WQ_RETRY_NOW - retry immediately
WQ_RETRY_LATER - cease processing this work queue,
leave item on the queue.
WQ_REQUEUE - requeue the item for later processing, continue
on with queue
note that a retry counter is incremented for the item in the cases of
RETRY_NOW, RETRY_LATER and REQUEUE. If an item exceeds the
max_retries value in the spec, it is treated as an error, error
handler (if provided) is run and item is removed from queue.
thats about it really.. the thread.c scheduler will need more
tweaking i think (eg process_fd's shouldnt put an unlimited amount of
threads onto the ready list, perhaps max of 10 or 20 or so? also
events have top priority - they can starve the ready thread_list -
perhaps events should be queued onto the ready list).
regards,
--
Paul Jakma paul@clubi.ie paul@jakma.org Key ID: 64A2FF6A
warning: do not ever send email to spam@dishone.st
Fortune:
if (argc > 1 && strcmp(argv[1], "-advice") == 0) {
printf("Don't Panic!\n");
exit(42);
}
(Arnold Robbins in the LJ of February '95, describing RCS)
queues' to quagga. Along with second patch to convert rib_process'ing
in zebra_rib.c to use work_queues. These patches are a generic rework
of an earlier proof-of-concept version i had hacked directly into
zebra_rib.c. The proof-of-concept worked, but i havnt tested this
rework, it very likely has bugs :) (be glad to hear results of
testing - but dont try on anything but unimportant machine). I hope
to next look at converting code in bgpd to work_queues - which
hopefully would alleviate the bgp idle timeout problem.
Work queues allow often repeated work to be put onto a queue, to be
dealt with by the threads subsystem, rather than have to potentially
spend a long time on repeated work (and blocking the current thread).
The work queued, by default, is processed in a serial fashion. While
ideally a work_queue should be processable by one (user supplied)
work function, individual queue items can provide their own (useful
for serialising work to some object, where bulk of work is done via
one function, but occassionally an item may need to be worked in some
other way.) When processing work queues, the threads subsystem will
periodically check how much time has elapsed and yield control if
neccessary.
Code that currently spend long amounts of time iterating through a
list or route_table, processing each node and hence taking up lots
of time (and causing response problems in quagga) are ideal
candidates for porting to work queues. (eg zebra's rib processing,
bgpd's rib processing).
the basic units are:
work_queue_t - defines a work queue
work_queue_spec_t - the specification for a work queue, user
defines work function, default error strategy, optional error
handler, etc..
work_queue_item_t - an item of work, may optionally define its own
work_queue_spec_t to override the default work_queue spec.
Process is:
- initialises a new work queue, work_queue_new(). A work queue will
typically be long lived - length of the process - and be specific to
some task. Fill in the spec (esp the caller data deletion callback!)
- as and when needed, submit a work_queue_item_t to the queue:
- prepare some caller specific data structure
- work_queue_item_new()
- work_queue_spec_new() - /if/ item specific spec is required
- fill in spec, attach it to item
- attach caller specific data structure to item
- submit the item to the work_queue, work_queue_item_add
deletion of items and specs is done by the thread subsystem.
thats it.. thread subsystem takes care of rest. user's provided work
function will be called for each item submitted at some later stage
as the queue is processed. User's provided del_item_data callback
will be used when deleting items.
The work function can indicate by its return status what action the
work queue processing subsystem should take:
WQ_ERROR - run error handler, if provided
WQ_RETRY_NOW - retry immediately
WQ_RETRY_LATER - cease processing this work queue,
leave item on the queue.
WQ_REQUEUE - requeue the item for later processing, continue
on with queue
note that a retry counter is incremented for the item in the cases of
RETRY_NOW, RETRY_LATER and REQUEUE. If an item exceeds the
max_retries value in the spec, it is treated as an error, error
handler (if provided) is run and item is removed from queue.
thats about it really.. the thread.c scheduler will need more
tweaking i think (eg process_fd's shouldnt put an unlimited amount of
threads onto the ready list, perhaps max of 10 or 20 or so? also
events have top priority - they can starve the ready thread_list -
perhaps events should be queued onto the ready list).
regards,
--
Paul Jakma paul@clubi.ie paul@jakma.org Key ID: 64A2FF6A
warning: do not ever send email to spam@dishone.st
Fortune:
if (argc > 1 && strcmp(argv[1], "-advice") == 0) {
printf("Don't Panic!\n");
exit(42);
}
(Arnold Robbins in the LJ of February '95, describing RCS)