| 835 | } |
| 836 | |
| 837 | func (c *Manager) EventChan() (<-chan Event, <-chan error) { |
| 838 | ec := make(chan Event, 1) |
| 839 | errCh := make(chan error, 1) |
| 840 | |
| 841 | fd, err := c.memoryEventNonBlockFD() |
| 842 | if err != nil { |
| 843 | errCh <- err |
| 844 | return ec, errCh |
| 845 | } |
| 846 | |
| 847 | go func() { |
| 848 | defer close(errCh) |
| 849 | defer fd.Close() |
| 850 | |
| 851 | for { |
| 852 | buffer := make([]byte, unix.SizeofInotifyEvent*10) |
| 853 | bytesRead, err := fd.Read(buffer) |
| 854 | if err != nil { |
| 855 | errCh <- err |
| 856 | return |
| 857 | } |
| 858 | |
| 859 | if bytesRead < unix.SizeofInotifyEvent { |
| 860 | continue |
| 861 | } |
| 862 | |
| 863 | // Check cgroup.events first |
| 864 | shouldExit := false |
| 865 | if c.isCgroupEmpty() { |
| 866 | shouldExit = true |
| 867 | } |
| 868 | |
| 869 | out := make(map[string]uint64) |
| 870 | if err := readKVStatsFile(c.path, "memory.events", out); err != nil { |
| 871 | // When cgroup is deleted read may return -ENODEV instead of -ENOENT from open. |
| 872 | if _, statErr := os.Lstat(filepath.Join(c.path, "memory.events")); !os.IsNotExist(statErr) { |
| 873 | errCh <- err |
| 874 | } |
| 875 | return |
| 876 | } |
| 877 | |
| 878 | ec <- Event{ |
| 879 | Low: out["low"], |
| 880 | High: out["high"], |
| 881 | Max: out["max"], |
| 882 | OOM: out["oom"], |
| 883 | OOMKill: out["oom_kill"], |
| 884 | OOMGroupKill: out["oom_group_kill"], |
| 885 | } |
| 886 | |
| 887 | if shouldExit { |
| 888 | return |
| 889 | } |
| 890 | } |
| 891 | }() |
| 892 | return ec, errCh |
| 893 | } |
| 894 | |