[VOL-5474] fixes for deadlock and exceptions found in WaitForGreenLight()
Signed-off-by: bseeniva <balaji.seenivasan@radisys.com>
Change-Id: I875233ce1c0c1ee3bf444662b5bd455ac2464815
diff --git a/VERSION b/VERSION
index c241e96..33e5103 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-3.6.18
+3.6.19
diff --git a/rw_core/utils/request_queue.go b/rw_core/utils/request_queue.go
index c232b6d..8126f39 100644
--- a/rw_core/utils/request_queue.go
+++ b/rw_core/utils/request_queue.go
@@ -45,6 +45,10 @@
// proceeding. The caller can also provide a context with timeout. The timeout will be triggered if the wait is
// too long (previous requests taking too long)
func (rq *RequestQueue) WaitForGreenLight(ctx context.Context) error {
+ // if ctx is already canceled, no need to create a request
+ if err := ctx.Err(); err != nil {
+ return err
+ }
// add ourselves to the end of the queue
rq.mutex.Lock()
waitingOn := rq.lastCompleteCh
@@ -74,15 +78,28 @@
rq.releaseWithoutLock()
default:
// on abort, skip our position in the queue
- r.prev.notifyOnComplete = r.notifyOnComplete
- // and remove ourselves from the queue
- if r.next != nil { // if we are somewhere in the middle of the queue
+ if r.prev != nil {
+ r.prev.notifyOnComplete = r.notifyOnComplete
+ } else if rq.current != nil {
+ // On abort, if the previous pointer is nil, transfer notifyOnComplete to the current processing request
+ rq.current.notifyOnComplete = r.notifyOnComplete
+ }
+ // Remove ourselves from the queue
+ if r.next != nil && r.prev != nil { // If we are somewhere in the middle of the queue
r.prev.next = r.next
r.next.prev = r.prev
- } else { // if we are at the end of the queue
+ } else if r.prev != nil { // If we are at the end of the queue
rq.last = r.prev
r.prev.next = nil
+ } else if r.next != nil { // If we are at the start of the queue
+ r.next.prev = nil
+ } else { // If we are the only request in the queue
+ rq.last = nil
}
+
+ // Clear references to help garbage collection
+ r.prev = nil
+ r.next = nil
}
return ctx.Err()
@@ -90,10 +107,24 @@
// Previous request has signaled that it is complete.
// This request now can proceed as the active
// request
-
rq.mutex.Lock()
defer rq.mutex.Unlock()
rq.current = r
+
+ // Remove the processed request from the queue
+ if r.prev != nil {
+ r.prev.next = r.next
+ }
+ if r.next != nil {
+ r.next.prev = r.prev
+ }
+ if rq.last == r {
+ rq.last = r.prev
+ }
+
+ // Clear references to help garbage collection
+ r.prev = nil
+ r.next = nil
return nil
}
}
@@ -109,9 +140,15 @@
func (rq *RequestQueue) releaseWithoutLock() {
// Notify the next waiting request. This will panic if the lock is released more than once.
- close(rq.current.notifyOnComplete)
+ if rq.current.notifyOnComplete != nil {
+ close(rq.current.notifyOnComplete)
+ rq.current.notifyOnComplete = nil
+ }
if rq.current.next != nil {
rq.current.next.prev = nil
}
+
+ // Clear the current request reference to help garbage collection
+ rq.current = nil
}