watchpoint.go 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. // Copyright (c) 2014-2015 The Notify Authors. All rights reserved.
  2. // Use of this source code is governed by the MIT license that can be
  3. // found in the LICENSE file.
  4. package notify
  5. // EventDiff describes a change to an event set - EventDiff[0] is an old state,
  6. // while EventDiff[1] is a new state. If event set has not changed (old == new),
  7. // functions typically return the None value.
  8. type eventDiff [2]Event
  9. func (diff eventDiff) Event() Event {
  10. return diff[1] &^ diff[0]
  11. }
  12. // Watchpoint
  13. //
  14. // The nil key holds total event set - logical sum for all registered events.
  15. // It speeds up computing EventDiff for Add method.
  16. //
  17. // The rec key holds an event set for a watchpoints created by RecursiveWatch
  18. // for a Watcher implementation which is not natively recursive.
  19. type watchpoint map[chan<- EventInfo]Event
  20. // None is an empty event diff, think null object.
  21. var none eventDiff
  22. // rec is just a placeholder
  23. var rec = func() (ch chan<- EventInfo) {
  24. ch = make(chan<- EventInfo)
  25. close(ch)
  26. return
  27. }()
  28. func (wp watchpoint) dryAdd(ch chan<- EventInfo, e Event) eventDiff {
  29. if e &^= internal; wp[ch]&e == e {
  30. return none
  31. }
  32. total := wp[ch] &^ internal
  33. return eventDiff{total, total | e}
  34. }
  35. // Add assumes neither c nor e are nil or zero values.
  36. func (wp watchpoint) Add(c chan<- EventInfo, e Event) (diff eventDiff) {
  37. wp[c] |= e
  38. diff[0] = wp[nil]
  39. diff[1] = diff[0] | e
  40. wp[nil] = diff[1] &^ omit
  41. // Strip diff from internal events.
  42. diff[0] &^= internal
  43. diff[1] &^= internal
  44. if diff[0] == diff[1] {
  45. return none
  46. }
  47. return
  48. }
  49. func (wp watchpoint) Del(c chan<- EventInfo, e Event) (diff eventDiff) {
  50. wp[c] &^= e
  51. if wp[c] == 0 {
  52. delete(wp, c)
  53. }
  54. diff[0] = wp[nil]
  55. delete(wp, nil)
  56. if len(wp) != 0 {
  57. // Recalculate total event set.
  58. for _, e := range wp {
  59. diff[1] |= e
  60. }
  61. wp[nil] = diff[1] &^ omit
  62. }
  63. // Strip diff from internal events.
  64. diff[0] &^= internal
  65. diff[1] &^= internal
  66. if diff[0] == diff[1] {
  67. return none
  68. }
  69. return
  70. }
  71. func (wp watchpoint) Dispatch(ei EventInfo, extra Event) {
  72. e := eventmask(ei, extra)
  73. if !matches(wp[nil], e) {
  74. return
  75. }
  76. for ch, eset := range wp {
  77. if ch != nil && matches(eset, e) {
  78. select {
  79. case ch <- ei:
  80. default: // Drop event if receiver is too slow
  81. dbgprintf("dropped %s on %q: receiver too slow", ei.Event(), ei.Path())
  82. }
  83. }
  84. }
  85. }
  86. func (wp watchpoint) Total() Event {
  87. return wp[nil] &^ internal
  88. }
  89. func (wp watchpoint) IsRecursive() bool {
  90. return wp[nil]&recursive != 0
  91. }