bytesemaphore.go 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  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. s.mut.Lock()
  48. defer s.mut.Unlock()
  49. if bytes > s.max {
  50. bytes = s.max
  51. }
  52. for bytes > s.available {
  53. s.cond.Wait()
  54. select {
  55. case <-ctx.Done():
  56. return ctx.Err()
  57. default:
  58. }
  59. if bytes > s.max {
  60. bytes = s.max
  61. }
  62. }
  63. s.available -= bytes
  64. return nil
  65. }
  66. func (s *byteSemaphore) give(bytes int) {
  67. s.mut.Lock()
  68. if bytes > s.max {
  69. bytes = s.max
  70. }
  71. if s.available+bytes > s.max {
  72. s.available = s.max
  73. } else {
  74. s.available += bytes
  75. }
  76. s.cond.Broadcast()
  77. s.mut.Unlock()
  78. }
  79. func (s *byteSemaphore) setCapacity(cap int) {
  80. if cap < 0 {
  81. cap = 0
  82. }
  83. s.mut.Lock()
  84. diff := cap - s.max
  85. s.max = cap
  86. s.available += diff
  87. if s.available < 0 {
  88. s.available = 0
  89. } else if s.available > s.max {
  90. s.available = s.max
  91. }
  92. s.cond.Broadcast()
  93. s.mut.Unlock()
  94. }