github.com/goplusjs/gopherjs@v1.2.6-0.20211206034512-f187917453b8/compiler/natives/src/sync/go113_sync.go (about)

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