github.com/gopherjs/gopherjs@v1.19.0-beta1.0.20240506212314-27071a8796e4/compiler/natives/src/sync/sync.go (about)

     1  //go:build js
     2  // +build js
     3  
     4  package sync
     5  
     6  import (
     7  	_ "unsafe" // For go:linkname
     8  
     9  	"github.com/gopherjs/gopherjs/js"
    10  )
    11  
    12  var semWaiters = make(map[*uint32][]chan bool)
    13  
    14  // semAwoken tracks the number of waiters awoken by runtime_Semrelease (`ch <- true`)
    15  // that have not yet acquired the semaphore (`<-ch` in runtime_SemacquireMutex).
    16  //
    17  // This prevents a new call to runtime_SemacquireMutex to wrongly acquire the semaphore
    18  // in between (because runtime_Semrelease has already incremented the semaphore while
    19  // all the pending calls to runtime_SemacquireMutex have not yet received from the channel
    20  // and thus decremented the semaphore).
    21  //
    22  // See https://github.com/gopherjs/gopherjs/issues/736.
    23  var semAwoken = make(map[*uint32]uint32)
    24  
    25  func runtime_Semacquire(s *uint32) {
    26  	runtime_SemacquireMutex(s, false, 1)
    27  }
    28  
    29  // SemacquireMutex is like Semacquire, but for profiling contended Mutexes.
    30  // Mutex profiling is not supported, so just use the same implementation as runtime_Semacquire.
    31  // TODO: Investigate this. If it's possible to implement, consider doing so, otherwise remove this comment.
    32  func runtime_SemacquireMutex(s *uint32, lifo bool, skipframes int) {
    33  	if (*s - semAwoken[s]) == 0 {
    34  		ch := make(chan bool)
    35  		if lifo {
    36  			semWaiters[s] = append([]chan bool{ch}, semWaiters[s]...)
    37  		} else {
    38  			semWaiters[s] = append(semWaiters[s], ch)
    39  		}
    40  		<-ch
    41  		semAwoken[s] -= 1
    42  		if semAwoken[s] == 0 {
    43  			delete(semAwoken, s)
    44  		}
    45  	}
    46  	*s--
    47  }
    48  
    49  func runtime_Semrelease(s *uint32, handoff bool, skipframes int) {
    50  	// TODO: Use handoff if needed/possible.
    51  	*s++
    52  
    53  	w := semWaiters[s]
    54  	if len(w) == 0 {
    55  		return
    56  	}
    57  
    58  	ch := w[0]
    59  	w = w[1:]
    60  	semWaiters[s] = w
    61  	if len(w) == 0 {
    62  		delete(semWaiters, s)
    63  	}
    64  
    65  	semAwoken[s] += 1
    66  
    67  	ch <- true
    68  }
    69  
    70  func runtime_notifyListCheck(size uintptr) {}
    71  
    72  func runtime_canSpin(i int) bool {
    73  	return false
    74  }
    75  
    76  //go:linkname runtime_nanotime runtime.nanotime
    77  func runtime_nanotime() int64
    78  
    79  // Implemented in runtime.
    80  func throw(s string) {
    81  	js.Global.Call("$throwRuntimeError", s)
    82  }