// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package signal

import (
	
	
	
)

var handlers struct {
	sync.Mutex
	// Map a channel to the signals that should be sent to it.
	m map[chan<- os.Signal]*handler
	// Map a signal to the number of channels receiving it.
	ref [numSig]int64
	// Map channels to signals while the channel is being stopped.
	// Not a map because entries live here only very briefly.
	// We need a separate container because we need m to correspond to ref
	// at all times, and we also need to keep track of the *handler
	// value for a channel being stopped. See the Stop function.
	stopping []stopping
}

type stopping struct {
	c chan<- os.Signal
	h *handler
}

type handler struct {
	mask [(numSig + 31) / 32]uint32
}

func ( *handler) ( int) bool {
	return (.mask[/32]>>uint(&31))&1 != 0
}

func ( *handler) ( int) {
	.mask[/32] |= 1 << uint(&31)
}

func ( *handler) ( int) {
	.mask[/32] &^= 1 << uint(&31)
}

// Stop relaying the signals, sigs, to any channels previously registered to
// receive them and either reset the signal handlers to their original values
// (action=disableSignal) or ignore the signals (action=ignoreSignal).
func cancel( []os.Signal,  func(int)) {
	handlers.Lock()
	defer handlers.Unlock()

	 := func( int) {
		var  handler

		for ,  := range handlers.m {
			if .want() {
				handlers.ref[]--
				.clear()
				if .mask == .mask {
					delete(handlers.m, )
				}
			}
		}

		()
	}

	if len() == 0 {
		for  := 0;  < numSig; ++ {
			()
		}
	} else {
		for ,  := range  {
			(signum())
		}
	}
}

// Ignore causes the provided signals to be ignored. If they are received by
// the program, nothing will happen. Ignore undoes the effect of any prior
// calls to [Notify] for the provided signals.
// If no signals are provided, all incoming signals will be ignored.
func ( ...os.Signal) {
	cancel(, ignoreSignal)
}

// Ignored reports whether sig is currently ignored.
func ( os.Signal) bool {
	 := signum()
	return  >= 0 && signalIgnored()
}

var (
	// watchSignalLoopOnce guards calling the conditionally
	// initialized watchSignalLoop. If watchSignalLoop is non-nil,
	// it will be run in a goroutine lazily once Notify is invoked.
	// See Issue 21576.
	watchSignalLoopOnce sync.Once
	watchSignalLoop     func()
)

// Notify causes package signal to relay incoming signals to c.
// If no signals are provided, all incoming signals will be relayed to c.
// Otherwise, just the provided signals will.
//
// Package signal will not block sending to c: the caller must ensure
// that c has sufficient buffer space to keep up with the expected
// signal rate. For a channel used for notification of just one signal value,
// a buffer of size 1 is sufficient.
//
// It is allowed to call Notify multiple times with the same channel:
// each call expands the set of signals sent to that channel.
// The only way to remove signals from the set is to call [Stop].
//
// It is allowed to call Notify multiple times with different channels
// and the same signals: each channel receives copies of incoming
// signals independently.
func ( chan<- os.Signal,  ...os.Signal) {
	if  == nil {
		panic("os/signal: Notify using nil channel")
	}

	handlers.Lock()
	defer handlers.Unlock()

	 := handlers.m[]
	if  == nil {
		if handlers.m == nil {
			handlers.m = make(map[chan<- os.Signal]*handler)
		}
		 = new(handler)
		handlers.m[] = 
	}

	 := func( int) {
		if  < 0 {
			return
		}
		if !.want() {
			.set()
			if handlers.ref[] == 0 {
				enableSignal()

				// The runtime requires that we enable a
				// signal before starting the watcher.
				watchSignalLoopOnce.Do(func() {
					if watchSignalLoop != nil {
						go watchSignalLoop()
					}
				})
			}
			handlers.ref[]++
		}
	}

	if len() == 0 {
		for  := 0;  < numSig; ++ {
			()
		}
	} else {
		for ,  := range  {
			(signum())
		}
	}
}

// Reset undoes the effect of any prior calls to [Notify] for the provided
// signals.
// If no signals are provided, all signal handlers will be reset.
func ( ...os.Signal) {
	cancel(, disableSignal)
}

// Stop causes package signal to stop relaying incoming signals to c.
// It undoes the effect of all prior calls to [Notify] using c.
// When Stop returns, it is guaranteed that c will receive no more signals.
func ( chan<- os.Signal) {
	handlers.Lock()

	 := handlers.m[]
	if  == nil {
		handlers.Unlock()
		return
	}
	delete(handlers.m, )

	for  := 0;  < numSig; ++ {
		if .want() {
			handlers.ref[]--
			if handlers.ref[] == 0 {
				disableSignal()
			}
		}
	}

	// Signals will no longer be delivered to the channel.
	// We want to avoid a race for a signal such as SIGINT:
	// it should be either delivered to the channel,
	// or the program should take the default action (that is, exit).
	// To avoid the possibility that the signal is delivered,
	// and the signal handler invoked, and then Stop deregisters
	// the channel before the process function below has a chance
	// to send it on the channel, put the channel on a list of
	// channels being stopped and wait for signal delivery to
	// quiesce before fully removing it.

	handlers.stopping = append(handlers.stopping, stopping{, })

	handlers.Unlock()

	signalWaitUntilIdle()

	handlers.Lock()

	for ,  := range handlers.stopping {
		if .c ==  {
			handlers.stopping = append(handlers.stopping[:], handlers.stopping[+1:]...)
			break
		}
	}

	handlers.Unlock()
}

// Wait until there are no more signals waiting to be delivered.
// Defined by the runtime package.
func signalWaitUntilIdle()

func process( os.Signal) {
	 := signum()
	if  < 0 {
		return
	}

	handlers.Lock()
	defer handlers.Unlock()

	for ,  := range handlers.m {
		if .want() {
			// send but do not block for it
			select {
			case  <- :
			default:
			}
		}
	}

	// Avoid the race mentioned in Stop.
	for ,  := range handlers.stopping {
		if .h.want() {
			select {
			case .c <- :
			default:
			}
		}
	}
}

// NotifyContext returns a copy of the parent context that is marked done
// (its Done channel is closed) when one of the listed signals arrives,
// when the returned stop function is called, or when the parent context's
// Done channel is closed, whichever happens first.
//
// The stop function unregisters the signal behavior, which, like [signal.Reset],
// may restore the default behavior for a given signal. For example, the default
// behavior of a Go program receiving [os.Interrupt] is to exit. Calling
// NotifyContext(parent, os.Interrupt) will change the behavior to cancel
// the returned context. Future interrupts received will not trigger the default
// (exit) behavior until the returned stop function is called.
//
// The stop function releases resources associated with it, so code should
// call stop as soon as the operations running in this Context complete and
// signals no longer need to be diverted to the context.
func ( context.Context,  ...os.Signal) ( context.Context,  context.CancelFunc) {
	,  := context.WithCancel()
	 := &signalCtx{
		Context: ,
		cancel:  ,
		signals: ,
	}
	.ch = make(chan os.Signal, 1)
	Notify(.ch, .signals...)
	if .Err() == nil {
		go func() {
			select {
			case <-.ch:
				.cancel()
			case <-.Done():
			}
		}()
	}
	return , .stop
}

type signalCtx struct {
	context.Context

	cancel  context.CancelFunc
	signals []os.Signal
	ch      chan os.Signal
}

func ( *signalCtx) () {
	.cancel()
	Stop(.ch)
}

type stringer interface {
	String() string
}

func ( *signalCtx) () string {
	var  []byte
	// We know that the type of c.Context is context.cancelCtx, and we know that the
	// String method of cancelCtx returns a string that ends with ".WithCancel".
	 := .Context.(stringer).String()
	 = [:len()-len(".WithCancel")]
	 = append(, "signal.NotifyContext("+...)
	if len(.signals) != 0 {
		 = append(, ", ["...)
		for ,  := range .signals {
			 = append(, .String()...)
			if  != len(.signals)-1 {
				 = append(, ' ')
			}
		}
		 = append(, ']')
	}
	 = append(, ')')
	return string()
}