bytesemaphore.go 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. // Copyright (C) 2018 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at https://mozilla.org/MPL/2.0/.
  6. package model
  7. import (
  8. "context"
  9. "sync"
  10. )
  11. type byteSemaphore struct {
  12. max int
  13. available int
  14. mut sync.Mutex
  15. cond *sync.Cond
  16. }
  17. func newByteSemaphore(max int) *byteSemaphore {
  18. if max < 0 {
  19. max = 0
  20. }
  21. s := byteSemaphore{
  22. max: max,
  23. available: max,
  24. }
  25. s.cond = sync.NewCond(&s.mut)
  26. return &s
  27. }
  28. func (s *byteSemaphore) takeWithContext(ctx context.Context, bytes int) error {
  29. done := make(chan struct{})
  30. var err error
  31. go func() {
  32. err = s.takeInner(ctx, bytes)
  33. close(done)
  34. }()
  35. select {
  36. case <-done:
  37. case <-ctx.Done():
  38. s.cond.Broadcast()
  39. <-done
  40. }
  41. return err
  42. }
  43. func (s *byteSemaphore) take(bytes int) {
  44. _ = s.takeInner(context.Background(), bytes)
  45. }
  46. func (s *byteSemaphore) takeInner(ctx context.Context, bytes int) error {
  47. // Checking context for bytes <= s.available is required for testing and doesn't do any harm.
  48. select {
  49. case <-ctx.Done():
  50. return ctx.Err()
  51. default:
  52. }
  53. s.mut.Lock()
  54. defer s.mut.Unlock()
  55. if bytes > s.max {
  56. bytes = s.max
  57. }
  58. for bytes > s.available {
  59. s.cond.Wait()
  60. select {
  61. case <-ctx.Done():
  62. return ctx.Err()
  63. default:
  64. }
  65. if bytes > s.max {
  66. bytes = s.max
  67. }
  68. }
  69. s.available -= bytes
  70. return nil
  71. }
  72. func (s *byteSemaphore) give(bytes int) {
  73. s.mut.Lock()
  74. if bytes > s.max {
  75. bytes = s.max
  76. }
  77. if s.available+bytes > s.max {
  78. s.available = s.max
  79. } else {
  80. s.available += bytes
  81. }
  82. s.cond.Broadcast()
  83. s.mut.Unlock()
  84. }
  85. func (s *byteSemaphore) setCapacity(cap int) {
  86. if cap < 0 {
  87. cap = 0
  88. }
  89. s.mut.Lock()
  90. diff := cap - s.max
  91. s.max = cap
  92. s.available += diff
  93. if s.available < 0 {
  94. s.available = 0
  95. } else if s.available > s.max {
  96. s.available = s.max
  97. }
  98. s.cond.Broadcast()
  99. s.mut.Unlock()
  100. }