Home | History | Annotate | Download | only in net
      1 // Copyright 2013 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package net
      6 
      7 import (
      8 	"math/rand"
      9 	"runtime"
     10 	"testing"
     11 	"time"
     12 )
     13 
     14 func TestMutexLock(t *testing.T) {
     15 	var mu fdMutex
     16 
     17 	if !mu.incref() {
     18 		t.Fatal("broken")
     19 	}
     20 	if mu.decref() {
     21 		t.Fatal("broken")
     22 	}
     23 
     24 	if !mu.rwlock(true) {
     25 		t.Fatal("broken")
     26 	}
     27 	if mu.rwunlock(true) {
     28 		t.Fatal("broken")
     29 	}
     30 
     31 	if !mu.rwlock(false) {
     32 		t.Fatal("broken")
     33 	}
     34 	if mu.rwunlock(false) {
     35 		t.Fatal("broken")
     36 	}
     37 }
     38 
     39 func TestMutexClose(t *testing.T) {
     40 	var mu fdMutex
     41 	if !mu.increfAndClose() {
     42 		t.Fatal("broken")
     43 	}
     44 
     45 	if mu.incref() {
     46 		t.Fatal("broken")
     47 	}
     48 	if mu.rwlock(true) {
     49 		t.Fatal("broken")
     50 	}
     51 	if mu.rwlock(false) {
     52 		t.Fatal("broken")
     53 	}
     54 	if mu.increfAndClose() {
     55 		t.Fatal("broken")
     56 	}
     57 }
     58 
     59 func TestMutexCloseUnblock(t *testing.T) {
     60 	c := make(chan bool)
     61 	var mu fdMutex
     62 	mu.rwlock(true)
     63 	for i := 0; i < 4; i++ {
     64 		go func() {
     65 			if mu.rwlock(true) {
     66 				t.Error("broken")
     67 				return
     68 			}
     69 			c <- true
     70 		}()
     71 	}
     72 	// Concurrent goroutines must not be able to read lock the mutex.
     73 	time.Sleep(time.Millisecond)
     74 	select {
     75 	case <-c:
     76 		t.Fatal("broken")
     77 	default:
     78 	}
     79 	mu.increfAndClose() // Must unblock the readers.
     80 	for i := 0; i < 4; i++ {
     81 		select {
     82 		case <-c:
     83 		case <-time.After(10 * time.Second):
     84 			t.Fatal("broken")
     85 		}
     86 	}
     87 	if mu.decref() {
     88 		t.Fatal("broken")
     89 	}
     90 	if !mu.rwunlock(true) {
     91 		t.Fatal("broken")
     92 	}
     93 }
     94 
     95 func TestMutexPanic(t *testing.T) {
     96 	ensurePanics := func(f func()) {
     97 		defer func() {
     98 			if recover() == nil {
     99 				t.Fatal("does not panic")
    100 			}
    101 		}()
    102 		f()
    103 	}
    104 
    105 	var mu fdMutex
    106 	ensurePanics(func() { mu.decref() })
    107 	ensurePanics(func() { mu.rwunlock(true) })
    108 	ensurePanics(func() { mu.rwunlock(false) })
    109 
    110 	ensurePanics(func() { mu.incref(); mu.decref(); mu.decref() })
    111 	ensurePanics(func() { mu.rwlock(true); mu.rwunlock(true); mu.rwunlock(true) })
    112 	ensurePanics(func() { mu.rwlock(false); mu.rwunlock(false); mu.rwunlock(false) })
    113 
    114 	// ensure that it's still not broken
    115 	mu.incref()
    116 	mu.decref()
    117 	mu.rwlock(true)
    118 	mu.rwunlock(true)
    119 	mu.rwlock(false)
    120 	mu.rwunlock(false)
    121 }
    122 
    123 func TestMutexStress(t *testing.T) {
    124 	P := 8
    125 	N := int(1e6)
    126 	if testing.Short() {
    127 		P = 4
    128 		N = 1e4
    129 	}
    130 	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(P))
    131 	done := make(chan bool)
    132 	var mu fdMutex
    133 	var readState [2]uint64
    134 	var writeState [2]uint64
    135 	for p := 0; p < P; p++ {
    136 		go func() {
    137 			r := rand.New(rand.NewSource(rand.Int63()))
    138 			for i := 0; i < N; i++ {
    139 				switch r.Intn(3) {
    140 				case 0:
    141 					if !mu.incref() {
    142 						t.Error("broken")
    143 						return
    144 					}
    145 					if mu.decref() {
    146 						t.Error("broken")
    147 						return
    148 					}
    149 				case 1:
    150 					if !mu.rwlock(true) {
    151 						t.Error("broken")
    152 						return
    153 					}
    154 					// Ensure that it provides mutual exclusion for readers.
    155 					if readState[0] != readState[1] {
    156 						t.Error("broken")
    157 						return
    158 					}
    159 					readState[0]++
    160 					readState[1]++
    161 					if mu.rwunlock(true) {
    162 						t.Error("broken")
    163 						return
    164 					}
    165 				case 2:
    166 					if !mu.rwlock(false) {
    167 						t.Error("broken")
    168 						return
    169 					}
    170 					// Ensure that it provides mutual exclusion for writers.
    171 					if writeState[0] != writeState[1] {
    172 						t.Error("broken")
    173 						return
    174 					}
    175 					writeState[0]++
    176 					writeState[1]++
    177 					if mu.rwunlock(false) {
    178 						t.Error("broken")
    179 						return
    180 					}
    181 				}
    182 			}
    183 			done <- true
    184 		}()
    185 	}
    186 	for p := 0; p < P; p++ {
    187 		<-done
    188 	}
    189 	if !mu.increfAndClose() {
    190 		t.Fatal("broken")
    191 	}
    192 	if !mu.decref() {
    193 		t.Fatal("broken")
    194 	}
    195 }
    196