Guest User

Untitled

a guest
Apr 30th, 2018
71
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 1.29 KB | None | 0 0
  1. package transmit
  2.  
  3. import (
  4. "time"
  5.  
  6. "golang.org/x/sys/unix"
  7. )
  8.  
  9. type Bucket struct {
  10. available chan int64
  11. done chan struct{}
  12. }
  13.  
  14. func NewBucket(n int64, e time.Duration) *Bucket {
  15. b := &Bucket{
  16. available: make(chan int64),
  17. done: make(chan struct{}),
  18. }
  19. go b.refill(n, e)
  20. return b
  21. }
  22.  
  23. func (b *Bucket) Take(n int64) {
  24. b.available <- n
  25. <-b.done
  26. }
  27.  
  28. func (b *Bucket) refill(limit int64, every time.Duration) {
  29. queue := make(chan int64)
  30. go func() {
  31. for {
  32. ns := sleepAtLeast(every.Nanoseconds())
  33. queue <- (limit * int64(ns/time.Millisecond)) / 1000
  34. }
  35. }()
  36. available, empty := limit, struct{}{}
  37. for {
  38. select {
  39. case n := <-queue:
  40. if d := available + n; d > limit {
  41. available = limit
  42. } else {
  43. available = d
  44. }
  45. case n := <- b.available:
  46. d := available - n
  47. if d >= 0 {
  48. available = d
  49. } else {
  50. c := <-queue
  51. if d := available - n + c; d > limit {
  52. available = limit
  53. } else {
  54. available = d
  55. }
  56. }
  57. b.done <- empty
  58. }
  59. }
  60. }
  61.  
  62. func now() *unix.Timespec {
  63. var t unix.Timespec
  64. if err := unix.ClockGettime(unix.CLOCK_REALTIME, &t); err != nil {
  65. return nil
  66. }
  67. return &t
  68. }
  69.  
  70. func sleepAtLeast(ns int64) time.Duration {
  71. b := now()
  72. i := unix.NsecToTimespec(ns)
  73. unix.Nanosleep(&i, nil)
  74. a := now()
  75.  
  76. return time.Duration(a.Nano() - b.Nano())
  77. }
Add Comment
Please, Sign In to add comment