github.com/ttpreport/gvisor-ligolo@v0.0.0-20240123134145-a858404967ba/pkg/sentry/kernel/semaphore/semaphore.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package semaphore implements System V semaphores.
    16  package semaphore
    17  
    18  import (
    19  	"fmt"
    20  
    21  	"github.com/ttpreport/gvisor-ligolo/pkg/abi/linux"
    22  	"github.com/ttpreport/gvisor-ligolo/pkg/context"
    23  	"github.com/ttpreport/gvisor-ligolo/pkg/errors/linuxerr"
    24  	"github.com/ttpreport/gvisor-ligolo/pkg/sentry/kernel/auth"
    25  	"github.com/ttpreport/gvisor-ligolo/pkg/sentry/kernel/ipc"
    26  	ktime "github.com/ttpreport/gvisor-ligolo/pkg/sentry/kernel/time"
    27  	"github.com/ttpreport/gvisor-ligolo/pkg/sentry/vfs"
    28  	"github.com/ttpreport/gvisor-ligolo/pkg/sync"
    29  )
    30  
    31  const (
    32  	// Maximum semaphore value.
    33  	valueMax = linux.SEMVMX
    34  
    35  	// Maximum number of semaphore sets.
    36  	setsMax = linux.SEMMNI
    37  
    38  	// Maximum number of semaphores in a semaphore set.
    39  	semsMax = linux.SEMMSL
    40  
    41  	// Maximum number of semaphores in all semaphore sets.
    42  	semsTotalMax = linux.SEMMNS
    43  )
    44  
    45  // Registry maintains a set of semaphores that can be found by key or ID.
    46  //
    47  // +stateify savable
    48  type Registry struct {
    49  	// mu protects all fields below.
    50  	mu sync.Mutex `state:"nosave"`
    51  
    52  	// reg defines basic fields and operations needed for all SysV registries.
    53  	reg *ipc.Registry
    54  
    55  	// indexes maintains a mapping between a set's index in virtual array and
    56  	// its identifier.
    57  	indexes map[int32]ipc.ID
    58  }
    59  
    60  // Set represents a set of semaphores that can be operated atomically.
    61  //
    62  // +stateify savable
    63  type Set struct {
    64  	// registry owning this sem set. Immutable.
    65  	registry *Registry
    66  
    67  	// mu protects all fields below.
    68  	mu sync.Mutex `state:"nosave"`
    69  
    70  	obj *ipc.Object
    71  
    72  	opTime     ktime.Time
    73  	changeTime ktime.Time
    74  
    75  	// sems holds all semaphores in the set. The slice itself is immutable after
    76  	// it's been set, however each 'sem' object in the slice requires 'mu' lock.
    77  	sems []sem
    78  
    79  	// dead is set to true when the set is removed and can't be reached anymore.
    80  	// All waiters must wake up and fail when set is dead.
    81  	dead bool
    82  }
    83  
    84  // sem represents a single semaphore from a set.
    85  //
    86  // +stateify savable
    87  type sem struct {
    88  	value   int16
    89  	waiters waiterList `state:"zerovalue"`
    90  	pid     int32
    91  }
    92  
    93  // waiter represents a caller that is waiting for the semaphore value to
    94  // become positive or zero.
    95  //
    96  // +stateify savable
    97  type waiter struct {
    98  	waiterEntry
    99  
   100  	// value represents how much resource the waiter needs to wake up.
   101  	// The value is either 0 or negative.
   102  	value int16
   103  	ch    chan struct{}
   104  }
   105  
   106  // NewRegistry creates a new semaphore set registry.
   107  func NewRegistry(userNS *auth.UserNamespace) *Registry {
   108  	return &Registry{
   109  		reg:     ipc.NewRegistry(userNS),
   110  		indexes: make(map[int32]ipc.ID),
   111  	}
   112  }
   113  
   114  // FindOrCreate searches for a semaphore set that matches 'key'. If not found,
   115  // it may create a new one if requested. If private is true, key is ignored and
   116  // a new set is always created. If create is false, it fails if a set cannot
   117  // be found. If exclusive is true, it fails if a set with the same key already
   118  // exists.
   119  func (r *Registry) FindOrCreate(ctx context.Context, key ipc.Key, nsems int32, mode linux.FileMode, private, create, exclusive bool) (*Set, error) {
   120  	if nsems < 0 || nsems > semsMax {
   121  		return nil, linuxerr.EINVAL
   122  	}
   123  
   124  	r.mu.Lock()
   125  	defer r.mu.Unlock()
   126  
   127  	if !private {
   128  		set, err := r.reg.Find(ctx, key, mode, create, exclusive)
   129  		if err != nil {
   130  			return nil, err
   131  		}
   132  
   133  		// Validate semaphore-specific parameters.
   134  		if set != nil {
   135  			set := set.(*Set)
   136  			if nsems > int32(set.Size()) {
   137  				return nil, linuxerr.EINVAL
   138  			}
   139  			return set, nil
   140  		}
   141  	}
   142  
   143  	// Zero is only valid if an existing set is found.
   144  	if nsems == 0 {
   145  		return nil, linuxerr.EINVAL
   146  	}
   147  
   148  	// Apply system limits.
   149  	//
   150  	// Map reg.objects and map indexes in a registry are of the same size,
   151  	// check map reg.objects only here for the system limit.
   152  	if r.reg.ObjectCount() >= setsMax {
   153  		return nil, linuxerr.ENOSPC
   154  	}
   155  	if r.totalSems() > int(semsTotalMax-nsems) {
   156  		return nil, linuxerr.ENOSPC
   157  	}
   158  
   159  	// Finally create a new set.
   160  	return r.newSetLocked(ctx, key, auth.CredentialsFromContext(ctx), mode, nsems)
   161  }
   162  
   163  // IPCInfo returns information about system-wide semaphore limits and parameters.
   164  func (r *Registry) IPCInfo() *linux.SemInfo {
   165  	return &linux.SemInfo{
   166  		SemMap: linux.SEMMAP,
   167  		SemMni: linux.SEMMNI,
   168  		SemMns: linux.SEMMNS,
   169  		SemMnu: linux.SEMMNU,
   170  		SemMsl: linux.SEMMSL,
   171  		SemOpm: linux.SEMOPM,
   172  		SemUme: linux.SEMUME,
   173  		SemUsz: linux.SEMUSZ,
   174  		SemVmx: linux.SEMVMX,
   175  		SemAem: linux.SEMAEM,
   176  	}
   177  }
   178  
   179  // SemInfo returns a seminfo structure containing the same information as
   180  // for IPC_INFO, except that SemUsz field returns the number of existing
   181  // semaphore sets, and SemAem field returns the number of existing semaphores.
   182  func (r *Registry) SemInfo() *linux.SemInfo {
   183  	r.mu.Lock()
   184  	defer r.mu.Unlock()
   185  
   186  	info := r.IPCInfo()
   187  	info.SemUsz = uint32(r.reg.ObjectCount())
   188  	info.SemAem = uint32(r.totalSems())
   189  
   190  	return info
   191  }
   192  
   193  // HighestIndex returns the index of the highest used entry in
   194  // the kernel's array.
   195  func (r *Registry) HighestIndex() int32 {
   196  	r.mu.Lock()
   197  	defer r.mu.Unlock()
   198  
   199  	// By default, highest used index is 0 even though
   200  	// there is no semaphore set.
   201  	var highestIndex int32
   202  	for index := range r.indexes {
   203  		if index > highestIndex {
   204  			highestIndex = index
   205  		}
   206  	}
   207  	return highestIndex
   208  }
   209  
   210  // Remove removes set with give 'id' from the registry and marks the set as
   211  // dead. All waiters will be awakened and fail.
   212  func (r *Registry) Remove(id ipc.ID, creds *auth.Credentials) error {
   213  	r.mu.Lock()
   214  	defer r.mu.Unlock()
   215  
   216  	index, found := r.findIndexByID(id)
   217  	if !found {
   218  		return linuxerr.EINVAL
   219  	}
   220  	delete(r.indexes, index)
   221  
   222  	r.reg.Remove(id, creds)
   223  
   224  	return nil
   225  }
   226  
   227  // newSetLocked creates a new Set using given fields. An error is returned if there
   228  // are no more available identifiers.
   229  //
   230  // Precondition: r.mu must be held.
   231  func (r *Registry) newSetLocked(ctx context.Context, key ipc.Key, creator *auth.Credentials, mode linux.FileMode, nsems int32) (*Set, error) {
   232  	set := &Set{
   233  		registry:   r,
   234  		obj:        ipc.NewObject(r.reg.UserNS, ipc.Key(key), creator, creator, mode),
   235  		changeTime: ktime.NowFromContext(ctx),
   236  		sems:       make([]sem, nsems),
   237  	}
   238  
   239  	err := r.reg.Register(set)
   240  	if err != nil {
   241  		return nil, err
   242  	}
   243  
   244  	index, found := r.findFirstAvailableIndex()
   245  	if !found {
   246  		// See linux, ipc/sem.c:newary().
   247  		return nil, linuxerr.ENOSPC
   248  	}
   249  	r.indexes[index] = set.obj.ID
   250  
   251  	return set, nil
   252  }
   253  
   254  // FindByID looks up a set given an ID.
   255  func (r *Registry) FindByID(id ipc.ID) *Set {
   256  	r.mu.Lock()
   257  	defer r.mu.Unlock()
   258  	mech := r.reg.FindByID(id)
   259  	if mech == nil {
   260  		return nil
   261  	}
   262  	return mech.(*Set)
   263  }
   264  
   265  // FindByIndex looks up a set given an index.
   266  func (r *Registry) FindByIndex(index int32) *Set {
   267  	r.mu.Lock()
   268  	defer r.mu.Unlock()
   269  
   270  	id, present := r.indexes[index]
   271  	if !present {
   272  		return nil
   273  	}
   274  	return r.reg.FindByID(id).(*Set)
   275  }
   276  
   277  func (r *Registry) findIndexByID(id ipc.ID) (int32, bool) {
   278  	for k, v := range r.indexes {
   279  		if v == id {
   280  			return k, true
   281  		}
   282  	}
   283  	return 0, false
   284  }
   285  
   286  func (r *Registry) findFirstAvailableIndex() (int32, bool) {
   287  	for index := int32(0); index < setsMax; index++ {
   288  		if _, present := r.indexes[index]; !present {
   289  			return index, true
   290  		}
   291  	}
   292  	return 0, false
   293  }
   294  
   295  func (r *Registry) totalSems() int {
   296  	totalSems := 0
   297  	r.reg.ForAllObjects(
   298  		func(o ipc.Mechanism) {
   299  			totalSems += o.(*Set).Size()
   300  		},
   301  	)
   302  	return totalSems
   303  }
   304  
   305  // ID returns semaphore's ID.
   306  func (s *Set) ID() ipc.ID {
   307  	return s.obj.ID
   308  }
   309  
   310  // Object implements ipc.Mechanism.Object.
   311  func (s *Set) Object() *ipc.Object {
   312  	return s.obj
   313  }
   314  
   315  // Lock implements ipc.Mechanism.Lock.
   316  func (s *Set) Lock() {
   317  	s.mu.Lock()
   318  }
   319  
   320  // Unlock implements ipc.mechanism.Unlock.
   321  //
   322  // +checklocksignore
   323  func (s *Set) Unlock() {
   324  	s.mu.Unlock()
   325  }
   326  
   327  func (s *Set) findSem(num int32) *sem {
   328  	if num < 0 || int(num) >= s.Size() {
   329  		return nil
   330  	}
   331  	return &s.sems[num]
   332  }
   333  
   334  // Size returns the number of semaphores in the set. Size is immutable.
   335  func (s *Set) Size() int {
   336  	return len(s.sems)
   337  }
   338  
   339  // Set modifies attributes for a semaphore set. See semctl(IPC_SET).
   340  func (s *Set) Set(ctx context.Context, ds *linux.SemidDS) error {
   341  	s.mu.Lock()
   342  	defer s.mu.Unlock()
   343  
   344  	if err := s.obj.Set(ctx, &ds.SemPerm); err != nil {
   345  		return err
   346  	}
   347  
   348  	s.changeTime = ktime.NowFromContext(ctx)
   349  	return nil
   350  }
   351  
   352  // GetStat extracts semid_ds information from the set.
   353  func (s *Set) GetStat(creds *auth.Credentials) (*linux.SemidDS, error) {
   354  	// "The calling process must have read permission on the semaphore set."
   355  	return s.semStat(creds, vfs.MayRead)
   356  }
   357  
   358  // GetStatAny extracts semid_ds information from the set without requiring read access.
   359  func (s *Set) GetStatAny(creds *auth.Credentials) (*linux.SemidDS, error) {
   360  	return s.semStat(creds, 0)
   361  }
   362  
   363  func (s *Set) semStat(creds *auth.Credentials, ats vfs.AccessTypes) (*linux.SemidDS, error) {
   364  	s.mu.Lock()
   365  	defer s.mu.Unlock()
   366  
   367  	if !s.obj.CheckPermissions(creds, ats) {
   368  		return nil, linuxerr.EACCES
   369  	}
   370  
   371  	return &linux.SemidDS{
   372  		SemPerm: linux.IPCPerm{
   373  			Key:  uint32(s.obj.Key),
   374  			UID:  uint32(creds.UserNamespace.MapFromKUID(s.obj.OwnerUID)),
   375  			GID:  uint32(creds.UserNamespace.MapFromKGID(s.obj.OwnerGID)),
   376  			CUID: uint32(creds.UserNamespace.MapFromKUID(s.obj.CreatorUID)),
   377  			CGID: uint32(creds.UserNamespace.MapFromKGID(s.obj.CreatorGID)),
   378  			Mode: uint16(s.obj.Mode),
   379  			Seq:  0, // IPC sequence not supported.
   380  		},
   381  		SemOTime: s.opTime.TimeT(),
   382  		SemCTime: s.changeTime.TimeT(),
   383  		SemNSems: uint64(s.Size()),
   384  	}, nil
   385  }
   386  
   387  // SetVal overrides a semaphore value, waking up waiters as needed.
   388  func (s *Set) SetVal(ctx context.Context, num int32, val int16, creds *auth.Credentials, pid int32) error {
   389  	if val < 0 || val > valueMax {
   390  		return linuxerr.ERANGE
   391  	}
   392  
   393  	s.mu.Lock()
   394  	defer s.mu.Unlock()
   395  
   396  	// "The calling process must have alter permission on the semaphore set."
   397  	if !s.obj.CheckPermissions(creds, vfs.MayWrite) {
   398  		return linuxerr.EACCES
   399  	}
   400  
   401  	sem := s.findSem(num)
   402  	if sem == nil {
   403  		return linuxerr.ERANGE
   404  	}
   405  
   406  	// TODO(gvisor.dev/issue/137): Clear undo entries in all processes.
   407  	sem.value = val
   408  	sem.pid = pid
   409  	s.changeTime = ktime.NowFromContext(ctx)
   410  	sem.wakeWaiters()
   411  	return nil
   412  }
   413  
   414  // SetValAll overrides all semaphores values, waking up waiters as needed. It also
   415  // sets semaphore's PID which was fixed in Linux 4.6.
   416  //
   417  // 'len(vals)' must be equal to 's.Size()'.
   418  func (s *Set) SetValAll(ctx context.Context, vals []uint16, creds *auth.Credentials, pid int32) error {
   419  	if len(vals) != s.Size() {
   420  		panic(fmt.Sprintf("vals length (%d) different that Set.Size() (%d)", len(vals), s.Size()))
   421  	}
   422  
   423  	for _, val := range vals {
   424  		if val > valueMax {
   425  			return linuxerr.ERANGE
   426  		}
   427  	}
   428  
   429  	s.mu.Lock()
   430  	defer s.mu.Unlock()
   431  
   432  	// "The calling process must have alter permission on the semaphore set."
   433  	if !s.obj.CheckPermissions(creds, vfs.MayWrite) {
   434  		return linuxerr.EACCES
   435  	}
   436  
   437  	for i, val := range vals {
   438  		sem := &s.sems[i]
   439  
   440  		// TODO(gvisor.dev/issue/137): Clear undo entries in all processes.
   441  		sem.value = int16(val)
   442  		sem.pid = pid
   443  		sem.wakeWaiters()
   444  	}
   445  	s.changeTime = ktime.NowFromContext(ctx)
   446  	return nil
   447  }
   448  
   449  // GetVal returns a semaphore value.
   450  func (s *Set) GetVal(num int32, creds *auth.Credentials) (int16, error) {
   451  	s.mu.Lock()
   452  	defer s.mu.Unlock()
   453  
   454  	// "The calling process must have read permission on the semaphore set."
   455  	if !s.obj.CheckPermissions(creds, vfs.MayRead) {
   456  		return 0, linuxerr.EACCES
   457  	}
   458  
   459  	sem := s.findSem(num)
   460  	if sem == nil {
   461  		return 0, linuxerr.ERANGE
   462  	}
   463  	return sem.value, nil
   464  }
   465  
   466  // GetValAll returns value for all semaphores.
   467  func (s *Set) GetValAll(creds *auth.Credentials) ([]uint16, error) {
   468  	s.mu.Lock()
   469  	defer s.mu.Unlock()
   470  
   471  	// "The calling process must have read permission on the semaphore set."
   472  	if !s.obj.CheckPermissions(creds, vfs.MayRead) {
   473  		return nil, linuxerr.EACCES
   474  	}
   475  
   476  	vals := make([]uint16, s.Size())
   477  	for i, sem := range s.sems {
   478  		vals[i] = uint16(sem.value)
   479  	}
   480  	return vals, nil
   481  }
   482  
   483  // GetPID returns the PID set when performing operations in the semaphore.
   484  func (s *Set) GetPID(num int32, creds *auth.Credentials) (int32, error) {
   485  	s.mu.Lock()
   486  	defer s.mu.Unlock()
   487  
   488  	// "The calling process must have read permission on the semaphore set."
   489  	if !s.obj.CheckPermissions(creds, vfs.MayRead) {
   490  		return 0, linuxerr.EACCES
   491  	}
   492  
   493  	sem := s.findSem(num)
   494  	if sem == nil {
   495  		return 0, linuxerr.ERANGE
   496  	}
   497  	return sem.pid, nil
   498  }
   499  
   500  func (s *Set) countWaiters(num int32, creds *auth.Credentials, pred func(w *waiter) bool) (uint16, error) {
   501  	s.mu.Lock()
   502  	defer s.mu.Unlock()
   503  
   504  	// The calling process must have read permission on the semaphore set.
   505  	if !s.obj.CheckPermissions(creds, vfs.MayRead) {
   506  		return 0, linuxerr.EACCES
   507  	}
   508  
   509  	sem := s.findSem(num)
   510  	if sem == nil {
   511  		return 0, linuxerr.ERANGE
   512  	}
   513  	var cnt uint16
   514  	for w := sem.waiters.Front(); w != nil; w = w.Next() {
   515  		if pred(w) {
   516  			cnt++
   517  		}
   518  	}
   519  	return cnt, nil
   520  }
   521  
   522  // CountZeroWaiters returns number of waiters waiting for the sem's value to increase.
   523  func (s *Set) CountZeroWaiters(num int32, creds *auth.Credentials) (uint16, error) {
   524  	return s.countWaiters(num, creds, func(w *waiter) bool {
   525  		return w.value == 0
   526  	})
   527  }
   528  
   529  // CountNegativeWaiters returns number of waiters waiting for the sem to go to zero.
   530  func (s *Set) CountNegativeWaiters(num int32, creds *auth.Credentials) (uint16, error) {
   531  	return s.countWaiters(num, creds, func(w *waiter) bool {
   532  		return w.value < 0
   533  	})
   534  }
   535  
   536  // ExecuteOps attempts to execute a list of operations to the set. It only
   537  // succeeds when all operations can be applied. No changes are made if it fails.
   538  //
   539  // On failure, it may return an error (retries are hopeless) or it may return
   540  // a channel that can be waited on before attempting again.
   541  func (s *Set) ExecuteOps(ctx context.Context, ops []linux.Sembuf, creds *auth.Credentials, pid int32) (chan struct{}, int32, error) {
   542  	s.mu.Lock()
   543  	defer s.mu.Unlock()
   544  
   545  	// Did it race with a removal operation?
   546  	if s.dead {
   547  		return nil, 0, linuxerr.EIDRM
   548  	}
   549  
   550  	// Validate the operations.
   551  	readOnly := true
   552  	for _, op := range ops {
   553  		if s.findSem(int32(op.SemNum)) == nil {
   554  			return nil, 0, linuxerr.EFBIG
   555  		}
   556  		if op.SemOp != 0 {
   557  			readOnly = false
   558  		}
   559  	}
   560  
   561  	ats := vfs.MayRead
   562  	if !readOnly {
   563  		ats = vfs.MayWrite
   564  	}
   565  	if !s.obj.CheckPermissions(creds, ats) {
   566  		return nil, 0, linuxerr.EACCES
   567  	}
   568  
   569  	ch, num, err := s.executeOps(ctx, ops, pid)
   570  	if err != nil {
   571  		return nil, 0, err
   572  	}
   573  	return ch, num, nil
   574  }
   575  
   576  func (s *Set) executeOps(ctx context.Context, ops []linux.Sembuf, pid int32) (chan struct{}, int32, error) {
   577  	// Changes to semaphores go to this slice temporarily until they all succeed.
   578  	tmpVals := make([]int16, len(s.sems))
   579  	for i := range s.sems {
   580  		tmpVals[i] = s.sems[i].value
   581  	}
   582  
   583  	for _, op := range ops {
   584  		sem := &s.sems[op.SemNum]
   585  		if op.SemOp == 0 {
   586  			// Handle 'wait for zero' operation.
   587  			if tmpVals[op.SemNum] != 0 {
   588  				// Semaphore isn't 0, must wait.
   589  				if op.SemFlg&linux.IPC_NOWAIT != 0 {
   590  					return nil, 0, linuxerr.ErrWouldBlock
   591  				}
   592  
   593  				w := newWaiter(op.SemOp)
   594  				sem.waiters.PushBack(w)
   595  				return w.ch, int32(op.SemNum), nil
   596  			}
   597  		} else {
   598  			if op.SemOp < 0 {
   599  				// Handle 'wait' operation.
   600  				if -op.SemOp > valueMax {
   601  					return nil, 0, linuxerr.ERANGE
   602  				}
   603  				if -op.SemOp > tmpVals[op.SemNum] {
   604  					// Not enough resources, must wait.
   605  					if op.SemFlg&linux.IPC_NOWAIT != 0 {
   606  						return nil, 0, linuxerr.ErrWouldBlock
   607  					}
   608  
   609  					w := newWaiter(op.SemOp)
   610  					sem.waiters.PushBack(w)
   611  					return w.ch, int32(op.SemNum), nil
   612  				}
   613  			} else {
   614  				// op.SemOp > 0: Handle 'signal' operation.
   615  				if tmpVals[op.SemNum] > valueMax-op.SemOp {
   616  					return nil, 0, linuxerr.ERANGE
   617  				}
   618  			}
   619  
   620  			tmpVals[op.SemNum] += op.SemOp
   621  		}
   622  	}
   623  
   624  	// All operations succeeded, apply them.
   625  	// TODO(gvisor.dev/issue/137): handle undo operations.
   626  	for i, v := range tmpVals {
   627  		s.sems[i].value = v
   628  		s.sems[i].wakeWaiters()
   629  		s.sems[i].pid = pid
   630  	}
   631  	s.opTime = ktime.NowFromContext(ctx)
   632  	return nil, 0, nil
   633  }
   634  
   635  // AbortWait notifies that a waiter is giving up and will not wait on the
   636  // channel anymore.
   637  func (s *Set) AbortWait(num int32, ch chan struct{}) {
   638  	s.mu.Lock()
   639  	defer s.mu.Unlock()
   640  
   641  	sem := &s.sems[num]
   642  	for w := sem.waiters.Front(); w != nil; w = w.Next() {
   643  		if w.ch == ch {
   644  			sem.waiters.Remove(w)
   645  			return
   646  		}
   647  	}
   648  	// Waiter may not be found in case it raced with wakeWaiters().
   649  }
   650  
   651  // Destroy implements ipc.Mechanism.Destroy.
   652  //
   653  // Preconditions: Caller must hold 's.mu'.
   654  func (s *Set) Destroy() {
   655  	// Notify all waiters. They will fail on the next attempt to execute
   656  	// operations and return error.
   657  	s.dead = true
   658  	for _, s := range s.sems {
   659  		for w := s.waiters.Front(); w != nil; w = w.Next() {
   660  			w.ch <- struct{}{}
   661  		}
   662  		s.waiters.Reset()
   663  	}
   664  }
   665  
   666  func abs(val int16) int16 {
   667  	if val < 0 {
   668  		return -val
   669  	}
   670  	return val
   671  }
   672  
   673  // wakeWaiters goes over all waiters and checks which of them can be notified.
   674  func (s *sem) wakeWaiters() {
   675  	// Note that this will release all waiters waiting for 0 too.
   676  	for w := s.waiters.Front(); w != nil; {
   677  		if s.value < abs(w.value) {
   678  			// Still blocked, skip it.
   679  			w = w.Next()
   680  			continue
   681  		}
   682  		w.ch <- struct{}{}
   683  		old := w
   684  		w = w.Next()
   685  		s.waiters.Remove(old)
   686  	}
   687  }
   688  
   689  func newWaiter(val int16) *waiter {
   690  	return &waiter{
   691  		value: val,
   692  		ch:    make(chan struct{}, 1),
   693  	}
   694  }