Skip to content

Instantly share code, notes, and snippets.

@tsnow
Last active August 29, 2015 14:01
Show Gist options
  • Save tsnow/58324c115a11975b35f6 to your computer and use it in GitHub Desktop.
Save tsnow/58324c115a11975b35f6 to your computer and use it in GitHub Desktop.
History of golang channels

http://golang.org/src/pkg/runtime/chan.c#L868

hg clone https://code.google.com/p/go/;
cd go;
hg log --template "{rev} {date|isodate}\n" -f src/pkg/runtime/chan.goc | tail -r | \
   while read i d _ __; do hg log -r $i -p > $d-$i.diff; done
changeset: 342:59711a1bdc17
user: Ken Thompson <[email protected]>
date: Sun Jul 13 14:29:46 2008 -0700
summary: chan
diff -r a983ade04fab -r 59711a1bdc17 src/cmd/gc/sys.go
--- a/src/cmd/gc/sys.go Sat Jul 12 17:16:22 2008 -0700
+++ b/src/cmd/gc/sys.go Sun Jul 13 14:29:46 2008 -0700
@@ -45,6 +45,9 @@
func mapassign2(hmap *map[any]any, key any, val any, pres bool);
func newchan(elemsize uint32, elemalg uint32, hint uint32) (hchan *chan any);
+func chansend(hchan *chan any, elem any);
+func chanrecv1(hchan *chan any) (elem any);
+func chanrecv2(hchan *chan any) (elem any, pres bool);
func gosched();
func goexit();
@@ -100,6 +103,9 @@
// chan
newchan
+ chansend
+ chanrecv1
+ chanrecv2
// go routines
gosched
diff -r a983ade04fab -r 59711a1bdc17 src/cmd/gc/sysimport.c
--- a/src/cmd/gc/sysimport.c Sat Jul 12 17:16:22 2008 -0700
+++ b/src/cmd/gc/sysimport.c Sun Jul 13 14:29:46 2008 -0700
@@ -3,10 +3,10 @@
"type sys._esys_002 {}\n"
"type sys.any 24\n"
"type sys._esys_003 *sys.any\n"
- "type sys._osys_281 {_esys_279 sys._esys_003}\n"
+ "type sys._osys_298 {_esys_296 sys._esys_003}\n"
"type sys.uint32 6\n"
- "type sys._isys_283 {_esys_280 sys.uint32}\n"
- "type sys._esys_001 (sys._esys_002 sys._osys_281 sys._isys_283)\n"
+ "type sys._isys_300 {_esys_297 sys.uint32}\n"
+ "type sys._esys_001 (sys._esys_002 sys._osys_298 sys._isys_300)\n"
"var !sys.mal sys._esys_001\n"
"type sys._esys_005 {}\n"
"type sys._esys_006 {}\n"
@@ -16,209 +16,230 @@
"type sys._esys_009 {}\n"
"type sys._esys_010 {}\n"
"type sys.int32 5\n"
- "type sys._isys_289 {_esys_288 sys.int32}\n"
- "type sys._esys_008 (sys._esys_009 sys._esys_010 sys._isys_289)\n"
+ "type sys._isys_306 {_esys_305 sys.int32}\n"
+ "type sys._esys_008 (sys._esys_009 sys._esys_010 sys._isys_306)\n"
"var !sys.panicl sys._esys_008\n"
"type sys._esys_012 {}\n"
"type sys._esys_013 {}\n"
"type sys.bool 12\n"
- "type sys._isys_294 {_esys_293 sys.bool}\n"
- "type sys._esys_011 (sys._esys_012 sys._esys_013 sys._isys_294)\n"
+ "type sys._isys_311 {_esys_310 sys.bool}\n"
+ "type sys._esys_011 (sys._esys_012 sys._esys_013 sys._isys_311)\n"
"var !sys.printbool sys._esys_011\n"
"type sys._esys_015 {}\n"
"type sys._esys_016 {}\n"
"type sys.float64 10\n"
- "type sys._isys_299 {_esys_298 sys.float64}\n"
- "type sys._esys_014 (sys._esys_015 sys._esys_016 sys._isys_299)\n"
+ "type sys._isys_316 {_esys_315 sys.float64}\n"
+ "type sys._esys_014 (sys._esys_015 sys._esys_016 sys._isys_316)\n"
"var !sys.printfloat sys._esys_014\n"
"type sys._esys_018 {}\n"
"type sys._esys_019 {}\n"
"type sys.int64 7\n"
- "type sys._isys_304 {_esys_303 sys.int64}\n"
- "type sys._esys_017 (sys._esys_018 sys._esys_019 sys._isys_304)\n"
+ "type sys._isys_321 {_esys_320 sys.int64}\n"
+ "type sys._esys_017 (sys._esys_018 sys._esys_019 sys._isys_321)\n"
"var !sys.printint sys._esys_017\n"
"type sys._esys_021 {}\n"
"type sys._esys_022 {}\n"
"type sys._esys_023 25\n"
"type sys.string *sys._esys_023\n"
- "type sys._isys_309 {_esys_308 sys.string}\n"
- "type sys._esys_020 (sys._esys_021 sys._esys_022 sys._isys_309)\n"
+ "type sys._isys_326 {_esys_325 sys.string}\n"
+ "type sys._esys_020 (sys._esys_021 sys._esys_022 sys._isys_326)\n"
"var !sys.printstring sys._esys_020\n"
"type sys._esys_025 {}\n"
"type sys._esys_026 {}\n"
"type sys.uint8 2\n"
"type sys._esys_027 *sys.uint8\n"
- "type sys._isys_314 {_esys_313 sys._esys_027}\n"
- "type sys._esys_024 (sys._esys_025 sys._esys_026 sys._isys_314)\n"
+ "type sys._isys_331 {_esys_330 sys._esys_027}\n"
+ "type sys._esys_024 (sys._esys_025 sys._esys_026 sys._isys_331)\n"
"var !sys.printpointer sys._esys_024\n"
"type sys._esys_029 {}\n"
- "type sys._osys_321 {_esys_318 sys.string}\n"
- "type sys._isys_323 {_esys_319 sys.string _esys_320 sys.string}\n"
- "type sys._esys_028 (sys._esys_029 sys._osys_321 sys._isys_323)\n"
+ "type sys._osys_338 {_esys_335 sys.string}\n"
+ "type sys._isys_340 {_esys_336 sys.string _esys_337 sys.string}\n"
+ "type sys._esys_028 (sys._esys_029 sys._osys_338 sys._isys_340)\n"
"var !sys.catstring sys._esys_028\n"
"type sys._esys_031 {}\n"
- "type sys._osys_331 {_esys_328 sys.int32}\n"
- "type sys._isys_333 {_esys_329 sys.string _esys_330 sys.string}\n"
- "type sys._esys_030 (sys._esys_031 sys._osys_331 sys._isys_333)\n"
+ "type sys._osys_348 {_esys_345 sys.int32}\n"
+ "type sys._isys_350 {_esys_346 sys.string _esys_347 sys.string}\n"
+ "type sys._esys_030 (sys._esys_031 sys._osys_348 sys._isys_350)\n"
"var !sys.cmpstring sys._esys_030\n"
"type sys._esys_033 {}\n"
- "type sys._osys_342 {_esys_338 sys.string}\n"
- "type sys._isys_344 {_esys_339 sys.string _esys_340 sys.int32 _esys_341 sys.int32}\n"
- "type sys._esys_032 (sys._esys_033 sys._osys_342 sys._isys_344)\n"
+ "type sys._osys_359 {_esys_355 sys.string}\n"
+ "type sys._isys_361 {_esys_356 sys.string _esys_357 sys.int32 _esys_358 sys.int32}\n"
+ "type sys._esys_032 (sys._esys_033 sys._osys_359 sys._isys_361)\n"
"var !sys.slicestring sys._esys_032\n"
"type sys._esys_035 {}\n"
- "type sys._osys_353 {_esys_350 sys.uint8}\n"
- "type sys._isys_355 {_esys_351 sys.string _esys_352 sys.int32}\n"
- "type sys._esys_034 (sys._esys_035 sys._osys_353 sys._isys_355)\n"
+ "type sys._osys_370 {_esys_367 sys.uint8}\n"
+ "type sys._isys_372 {_esys_368 sys.string _esys_369 sys.int32}\n"
+ "type sys._esys_034 (sys._esys_035 sys._osys_370 sys._isys_372)\n"
"var !sys.indexstring sys._esys_034\n"
"type sys._esys_037 {}\n"
- "type sys._osys_362 {_esys_360 sys.string}\n"
- "type sys._isys_364 {_esys_361 sys.int64}\n"
- "type sys._esys_036 (sys._esys_037 sys._osys_362 sys._isys_364)\n"
+ "type sys._osys_379 {_esys_377 sys.string}\n"
+ "type sys._isys_381 {_esys_378 sys.int64}\n"
+ "type sys._esys_036 (sys._esys_037 sys._osys_379 sys._isys_381)\n"
"var !sys.intstring sys._esys_036\n"
"type sys._esys_039 {}\n"
- "type sys._osys_371 {_esys_368 sys.string}\n"
+ "type sys._osys_388 {_esys_385 sys.string}\n"
"type sys._esys_040 *sys.uint8\n"
- "type sys._isys_373 {_esys_369 sys._esys_040 _esys_370 sys.int32}\n"
- "type sys._esys_038 (sys._esys_039 sys._osys_371 sys._isys_373)\n"
+ "type sys._isys_390 {_esys_386 sys._esys_040 _esys_387 sys.int32}\n"
+ "type sys._esys_038 (sys._esys_039 sys._osys_388 sys._isys_390)\n"
"var !sys.byteastring sys._esys_038\n"
"type sys._esys_042 {}\n"
"type sys._esys_043 <>\n"
- "type sys._osys_382 {_esys_378 sys._esys_043}\n"
+ "type sys._osys_399 {_esys_395 sys._esys_043}\n"
"type sys._esys_044 *sys.uint8\n"
"type sys._esys_045 *sys.uint8\n"
- "type sys._ssys_389 {}\n"
- "type sys._esys_046 *sys._ssys_389\n"
- "type sys._isys_384 {_esys_379 sys._esys_044 _esys_380 sys._esys_045 _esys_381 sys._esys_046}\n"
- "type sys._esys_041 (sys._esys_042 sys._osys_382 sys._isys_384)\n"
+ "type sys._ssys_406 {}\n"
+ "type sys._esys_046 *sys._ssys_406\n"
+ "type sys._isys_401 {_esys_396 sys._esys_044 _esys_397 sys._esys_045 _esys_398 sys._esys_046}\n"
+ "type sys._esys_041 (sys._esys_042 sys._osys_399 sys._isys_401)\n"
"var !sys.mkiface sys._esys_041\n"
"type sys._esys_048 {}\n"
- "type sys._osys_393 {_esys_392 sys.int32}\n"
+ "type sys._osys_410 {_esys_409 sys.int32}\n"
"type sys._esys_049 {}\n"
- "type sys._esys_047 (sys._esys_048 sys._osys_393 sys._esys_049)\n"
+ "type sys._esys_047 (sys._esys_048 sys._osys_410 sys._esys_049)\n"
"var !sys.argc sys._esys_047\n"
"type sys._esys_051 {}\n"
- "type sys._osys_397 {_esys_396 sys.int32}\n"
+ "type sys._osys_414 {_esys_413 sys.int32}\n"
"type sys._esys_052 {}\n"
- "type sys._esys_050 (sys._esys_051 sys._osys_397 sys._esys_052)\n"
+ "type sys._esys_050 (sys._esys_051 sys._osys_414 sys._esys_052)\n"
"var !sys.envc sys._esys_050\n"
"type sys._esys_054 {}\n"
- "type sys._osys_402 {_esys_400 sys.string}\n"
- "type sys._isys_404 {_esys_401 sys.int32}\n"
- "type sys._esys_053 (sys._esys_054 sys._osys_402 sys._isys_404)\n"
+ "type sys._osys_419 {_esys_417 sys.string}\n"
+ "type sys._isys_421 {_esys_418 sys.int32}\n"
+ "type sys._esys_053 (sys._esys_054 sys._osys_419 sys._isys_421)\n"
"var !sys.argv sys._esys_053\n"
"type sys._esys_056 {}\n"
- "type sys._osys_410 {_esys_408 sys.string}\n"
- "type sys._isys_412 {_esys_409 sys.int32}\n"
- "type sys._esys_055 (sys._esys_056 sys._osys_410 sys._isys_412)\n"
+ "type sys._osys_427 {_esys_425 sys.string}\n"
+ "type sys._isys_429 {_esys_426 sys.int32}\n"
+ "type sys._esys_055 (sys._esys_056 sys._osys_427 sys._isys_429)\n"
"var !sys.envv sys._esys_055\n"
"type sys._esys_058 {}\n"
- "type sys._osys_419 {_esys_416 sys.float64 _esys_417 sys.int32}\n"
- "type sys._isys_421 {_esys_418 sys.float64}\n"
- "type sys._esys_057 (sys._esys_058 sys._osys_419 sys._isys_421)\n"
+ "type sys._osys_436 {_esys_433 sys.float64 _esys_434 sys.int32}\n"
+ "type sys._isys_438 {_esys_435 sys.float64}\n"
+ "type sys._esys_057 (sys._esys_058 sys._osys_436 sys._isys_438)\n"
"var !sys.frexp sys._esys_057\n"
"type sys._esys_060 {}\n"
- "type sys._osys_428 {_esys_425 sys.float64}\n"
- "type sys._isys_430 {_esys_426 sys.float64 _esys_427 sys.int32}\n"
- "type sys._esys_059 (sys._esys_060 sys._osys_428 sys._isys_430)\n"
+ "type sys._osys_445 {_esys_442 sys.float64}\n"
+ "type sys._isys_447 {_esys_443 sys.float64 _esys_444 sys.int32}\n"
+ "type sys._esys_059 (sys._esys_060 sys._osys_445 sys._isys_447)\n"
"var !sys.ldexp sys._esys_059\n"
"type sys._esys_062 {}\n"
- "type sys._osys_438 {_esys_435 sys.float64 _esys_436 sys.float64}\n"
- "type sys._isys_440 {_esys_437 sys.float64}\n"
- "type sys._esys_061 (sys._esys_062 sys._osys_438 sys._isys_440)\n"
+ "type sys._osys_455 {_esys_452 sys.float64 _esys_453 sys.float64}\n"
+ "type sys._isys_457 {_esys_454 sys.float64}\n"
+ "type sys._esys_061 (sys._esys_062 sys._osys_455 sys._isys_457)\n"
"var !sys.modf sys._esys_061\n"
"type sys._esys_064 {}\n"
- "type sys._osys_447 {_esys_444 sys.bool}\n"
- "type sys._isys_449 {_esys_445 sys.float64 _esys_446 sys.int32}\n"
- "type sys._esys_063 (sys._esys_064 sys._osys_447 sys._isys_449)\n"
+ "type sys._osys_464 {_esys_461 sys.bool}\n"
+ "type sys._isys_466 {_esys_462 sys.float64 _esys_463 sys.int32}\n"
+ "type sys._esys_063 (sys._esys_064 sys._osys_464 sys._isys_466)\n"
"var !sys.isInf sys._esys_063\n"
"type sys._esys_066 {}\n"
- "type sys._osys_456 {_esys_454 sys.bool}\n"
- "type sys._isys_458 {_esys_455 sys.float64}\n"
- "type sys._esys_065 (sys._esys_066 sys._osys_456 sys._isys_458)\n"
+ "type sys._osys_473 {_esys_471 sys.bool}\n"
+ "type sys._isys_475 {_esys_472 sys.float64}\n"
+ "type sys._esys_065 (sys._esys_066 sys._osys_473 sys._isys_475)\n"
"var !sys.isNaN sys._esys_065\n"
"type sys._esys_068 {}\n"
- "type sys._osys_464 {_esys_462 sys.float64}\n"
- "type sys._isys_466 {_esys_463 sys.int32}\n"
- "type sys._esys_067 (sys._esys_068 sys._osys_464 sys._isys_466)\n"
+ "type sys._osys_481 {_esys_479 sys.float64}\n"
+ "type sys._isys_483 {_esys_480 sys.int32}\n"
+ "type sys._esys_067 (sys._esys_068 sys._osys_481 sys._isys_483)\n"
"var !sys.Inf sys._esys_067\n"
"type sys._esys_070 {}\n"
- "type sys._osys_471 {_esys_470 sys.float64}\n"
+ "type sys._osys_488 {_esys_487 sys.float64}\n"
"type sys._esys_071 {}\n"
- "type sys._esys_069 (sys._esys_070 sys._osys_471 sys._esys_071)\n"
+ "type sys._esys_069 (sys._esys_070 sys._osys_488 sys._esys_071)\n"
"var !sys.NaN sys._esys_069\n"
"type sys._esys_073 {}\n"
"type sys._esys_075 [sys.any] sys.any\n"
"type sys._esys_074 *sys._esys_075\n"
- "type sys._osys_474 {hmap sys._esys_074}\n"
- "type sys._isys_476 {keysize sys.uint32 valsize sys.uint32 keyalg sys.uint32 valalg sys.uint32 hint sys.uint32}\n"
- "type sys._esys_072 (sys._esys_073 sys._osys_474 sys._isys_476)\n"
+ "type sys._osys_491 {hmap sys._esys_074}\n"
+ "type sys._isys_493 {keysize sys.uint32 valsize sys.uint32 keyalg sys.uint32 valalg sys.uint32 hint sys.uint32}\n"
+ "type sys._esys_072 (sys._esys_073 sys._osys_491 sys._isys_493)\n"
"var !sys.newmap sys._esys_072\n"
"type sys._esys_077 {}\n"
- "type sys._osys_485 {val sys.any}\n"
+ "type sys._osys_502 {val sys.any}\n"
"type sys._esys_079 [sys.any] sys.any\n"
"type sys._esys_078 *sys._esys_079\n"
- "type sys._isys_487 {hmap sys._esys_078 key sys.any}\n"
- "type sys._esys_076 (sys._esys_077 sys._osys_485 sys._isys_487)\n"
+ "type sys._isys_504 {hmap sys._esys_078 key sys.any}\n"
+ "type sys._esys_076 (sys._esys_077 sys._osys_502 sys._isys_504)\n"
"var !sys.mapaccess1 sys._esys_076\n"
"type sys._esys_081 {}\n"
- "type sys._osys_493 {val sys.any pres sys.bool}\n"
+ "type sys._osys_510 {val sys.any pres sys.bool}\n"
"type sys._esys_083 [sys.any] sys.any\n"
"type sys._esys_082 *sys._esys_083\n"
- "type sys._isys_495 {hmap sys._esys_082 key sys.any}\n"
- "type sys._esys_080 (sys._esys_081 sys._osys_493 sys._isys_495)\n"
+ "type sys._isys_512 {hmap sys._esys_082 key sys.any}\n"
+ "type sys._esys_080 (sys._esys_081 sys._osys_510 sys._isys_512)\n"
"var !sys.mapaccess2 sys._esys_080\n"
"type sys._esys_085 {}\n"
"type sys._esys_086 {}\n"
"type sys._esys_088 [sys.any] sys.any\n"
"type sys._esys_087 *sys._esys_088\n"
- "type sys._isys_502 {hmap sys._esys_087 key sys.any val sys.any}\n"
- "type sys._esys_084 (sys._esys_085 sys._esys_086 sys._isys_502)\n"
+ "type sys._isys_519 {hmap sys._esys_087 key sys.any val sys.any}\n"
+ "type sys._esys_084 (sys._esys_085 sys._esys_086 sys._isys_519)\n"
"var !sys.mapassign1 sys._esys_084\n"
"type sys._esys_090 {}\n"
"type sys._esys_091 {}\n"
"type sys._esys_093 [sys.any] sys.any\n"
"type sys._esys_092 *sys._esys_093\n"
- "type sys._isys_508 {hmap sys._esys_092 key sys.any val sys.any pres sys.bool}\n"
- "type sys._esys_089 (sys._esys_090 sys._esys_091 sys._isys_508)\n"
+ "type sys._isys_525 {hmap sys._esys_092 key sys.any val sys.any pres sys.bool}\n"
+ "type sys._esys_089 (sys._esys_090 sys._esys_091 sys._isys_525)\n"
"var !sys.mapassign2 sys._esys_089\n"
"type sys._esys_095 {}\n"
"type sys._esys_097 1 sys.any\n"
"type sys._esys_096 *sys._esys_097\n"
- "type sys._osys_515 {hchan sys._esys_096}\n"
- "type sys._isys_517 {elemsize sys.uint32 elemalg sys.uint32 hint sys.uint32}\n"
- "type sys._esys_094 (sys._esys_095 sys._osys_515 sys._isys_517)\n"
+ "type sys._osys_532 {hchan sys._esys_096}\n"
+ "type sys._isys_534 {elemsize sys.uint32 elemalg sys.uint32 hint sys.uint32}\n"
+ "type sys._esys_094 (sys._esys_095 sys._osys_532 sys._isys_534)\n"
"var !sys.newchan sys._esys_094\n"
"type sys._esys_099 {}\n"
"type sys._esys_100 {}\n"
- "type sys._esys_101 {}\n"
- "type sys._esys_098 (sys._esys_099 sys._esys_100 sys._esys_101)\n"
- "var !sys.gosched sys._esys_098\n"
- "type sys._esys_103 {}\n"
+ "type sys._esys_102 1 sys.any\n"
+ "type sys._esys_101 *sys._esys_102\n"
+ "type sys._isys_541 {hchan sys._esys_101 elem sys.any}\n"
+ "type sys._esys_098 (sys._esys_099 sys._esys_100 sys._isys_541)\n"
+ "var !sys.chansend sys._esys_098\n"
"type sys._esys_104 {}\n"
- "type sys._esys_105 {}\n"
- "type sys._esys_102 (sys._esys_103 sys._esys_104 sys._esys_105)\n"
- "var !sys.goexit sys._esys_102\n"
- "type sys._esys_107 {}\n"
- "type sys._osys_529 {_esys_526 sys.string _esys_527 sys.bool}\n"
- "type sys._isys_531 {_esys_528 sys.string}\n"
- "type sys._esys_106 (sys._esys_107 sys._osys_529 sys._isys_531)\n"
- "var !sys.readfile sys._esys_106\n"
- "type sys._esys_109 {}\n"
- "type sys._osys_540 {_esys_535 sys.int32 _esys_536 sys.int32}\n"
- "type sys._esys_110 *sys.uint8\n"
- "type sys._isys_542 {_esys_537 sys._esys_110 _esys_538 sys.int32 _esys_539 sys.int32}\n"
- "type sys._esys_108 (sys._esys_109 sys._osys_540 sys._isys_542)\n"
- "var !sys.bytestorune sys._esys_108\n"
+ "type sys._osys_546 {elem sys.any}\n"
+ "type sys._esys_106 1 sys.any\n"
+ "type sys._esys_105 *sys._esys_106\n"
+ "type sys._isys_548 {hchan sys._esys_105}\n"
+ "type sys._esys_103 (sys._esys_104 sys._osys_546 sys._isys_548)\n"
+ "var !sys.chanrecv1 sys._esys_103\n"
+ "type sys._esys_108 {}\n"
+ "type sys._osys_553 {elem sys.any pres sys.bool}\n"
+ "type sys._esys_110 1 sys.any\n"
+ "type sys._esys_109 *sys._esys_110\n"
+ "type sys._isys_555 {hchan sys._esys_109}\n"
+ "type sys._esys_107 (sys._esys_108 sys._osys_553 sys._isys_555)\n"
+ "var !sys.chanrecv2 sys._esys_107\n"
"type sys._esys_112 {}\n"
- "type sys._osys_553 {_esys_548 sys.int32 _esys_549 sys.int32}\n"
- "type sys._isys_555 {_esys_550 sys.string _esys_551 sys.int32 _esys_552 sys.int32}\n"
- "type sys._esys_111 (sys._esys_112 sys._osys_553 sys._isys_555)\n"
- "var !sys.stringtorune sys._esys_111\n"
+ "type sys._esys_113 {}\n"
"type sys._esys_114 {}\n"
- "type sys._esys_115 {}\n"
- "type sys._isys_562 {_esys_561 sys.int32}\n"
- "type sys._esys_113 (sys._esys_114 sys._esys_115 sys._isys_562)\n"
- "var !sys.exit sys._esys_113\n"
+ "type sys._esys_111 (sys._esys_112 sys._esys_113 sys._esys_114)\n"
+ "var !sys.gosched sys._esys_111\n"
+ "type sys._esys_116 {}\n"
+ "type sys._esys_117 {}\n"
+ "type sys._esys_118 {}\n"
+ "type sys._esys_115 (sys._esys_116 sys._esys_117 sys._esys_118)\n"
+ "var !sys.goexit sys._esys_115\n"
+ "type sys._esys_120 {}\n"
+ "type sys._osys_566 {_esys_563 sys.string _esys_564 sys.bool}\n"
+ "type sys._isys_568 {_esys_565 sys.string}\n"
+ "type sys._esys_119 (sys._esys_120 sys._osys_566 sys._isys_568)\n"
+ "var !sys.readfile sys._esys_119\n"
+ "type sys._esys_122 {}\n"
+ "type sys._osys_577 {_esys_572 sys.int32 _esys_573 sys.int32}\n"
+ "type sys._esys_123 *sys.uint8\n"
+ "type sys._isys_579 {_esys_574 sys._esys_123 _esys_575 sys.int32 _esys_576 sys.int32}\n"
+ "type sys._esys_121 (sys._esys_122 sys._osys_577 sys._isys_579)\n"
+ "var !sys.bytestorune sys._esys_121\n"
+ "type sys._esys_125 {}\n"
+ "type sys._osys_590 {_esys_585 sys.int32 _esys_586 sys.int32}\n"
+ "type sys._isys_592 {_esys_587 sys.string _esys_588 sys.int32 _esys_589 sys.int32}\n"
+ "type sys._esys_124 (sys._esys_125 sys._osys_590 sys._isys_592)\n"
+ "var !sys.stringtorune sys._esys_124\n"
+ "type sys._esys_127 {}\n"
+ "type sys._esys_128 {}\n"
+ "type sys._isys_599 {_esys_598 sys.int32}\n"
+ "type sys._esys_126 (sys._esys_127 sys._esys_128 sys._isys_599)\n"
+ "var !sys.exit sys._esys_126\n"
"))\n"
;
diff -r a983ade04fab -r 59711a1bdc17 src/cmd/gc/walk.c
--- a/src/cmd/gc/walk.c Sat Jul 12 17:16:22 2008 -0700
+++ b/src/cmd/gc/walk.c Sun Jul 13 14:29:46 2008 -0700
@@ -246,6 +246,7 @@
}
switch(r->op) {
+
case OCALLMETH:
case OCALLINTER:
case OCALL:
@@ -273,6 +274,19 @@
goto ret;
}
break;
+
+ case ORECV:
+ if(cl == 2 && cr == 1) {
+ // a,b = <chan - chanrecv2
+ if(!isptrto(r->left->type, TCHAN))
+ break;
+ l = chanop(n, top);
+ if(l == N)
+ break;
+ *n = *l;
+ goto ret;
+ }
+ break;
}
switch(l->op) {
@@ -538,7 +552,7 @@
goto badt;
case TMAP:
- // right side must map type
+ // right side must be map type
if(n->right->type == T) {
convlit(n->right, t->down);
if(n->right->type == T)
@@ -570,6 +584,28 @@
}
goto ret;
+ case OSEND:
+ if(top != Elv)
+ goto nottop;
+ walktype(n->left, Erv);
+ t = n->left->type;
+ if(!isptrto(t, TCHAN))
+ goto badt;
+ n->type = t->type->type;
+ goto ret;
+
+ case ORECV:
+ if(top != Erv)
+ goto nottop;
+ walktype(n->left, Erv);
+ t = n->left->type;
+ if(!isptrto(t, TCHAN))
+ goto badt;
+ n->type = t->type->type;
+
+ *n = *chanop(n, top);
+ goto ret;
+
case OSLICE:
if(top == Etop)
goto nottop;
@@ -1251,7 +1287,7 @@
switch(n->op) {
default:
- fatal("stringop: unknown op %E", n->op);
+ fatal("stringop: unknown op %O", n->op);
case OEQ:
case ONE:
@@ -1278,7 +1314,7 @@
// sys_catstring(s1, s2)
switch(n->etype) {
default:
- fatal("stringop: unknown op %E-%E", n->op, n->etype);
+ fatal("stringop: unknown op %O-%O", n->op, n->etype);
case OADD:
// s1 = sys_catstring(s1, s2)
@@ -1436,7 +1472,7 @@
r = n;
switch(n->op) {
default:
- fatal("mapop: unknown op %E", n->op);
+ fatal("mapop: unknown op %O", n->op);
case ONEW:
if(top != Erv)
@@ -1636,7 +1672,7 @@
r = n;
switch(n->op) {
default:
- fatal("mapop: unknown op %E", n->op);
+ fatal("chanop: unknown op %O", n->op);
case ONEW:
// newchan(elemsize uint32, elemalg uint32,
@@ -1662,8 +1698,38 @@
walktype(r, top);
r->type = n->type;
break;
+
+ case OAS:
+ // chansend(hchan *chan any, elem any);
+
+//dump("assign1", n);
+ if(n->left->op != OSEND)
+ goto shape;
+
+ t = fixchan(n->left->left->type);
+ if(t == T)
+ break;
+
+ a = n->right; // val
+ r = a;
+ a = n->left->left; // chan
+ r = nod(OLIST, a, r);
+
+ on = syslook("chansend", 1);
+
+ argtype(on, t->type); // any-1
+ argtype(on, t->type); // any-2
+
+ r = nod(OCALL, on, r);
+ walktype(r, Erv);
+ break;
+
}
return r;
+
+shape:
+ fatal("chanop: %O", n->op);
+ return N;
}
void
@@ -1710,6 +1776,12 @@
return n;
}
+ if(n->left->op == OSEND)
+ if(n->left->type != T) {
+ *n = *chanop(n, Elv);
+ return n;
+ }
+
if(eqtype(lt, rt, 0))
return n;
diff -r a983ade04fab -r 59711a1bdc17 src/runtime/Makefile
--- a/src/runtime/Makefile Sat Jul 12 17:16:22 2008 -0700
+++ b/src/runtime/Makefile Sun Jul 13 14:29:46 2008 -0700
@@ -19,6 +19,7 @@
sys_$(GOARCH)_$(GOOS).$O\
runtime.$O\
map.$O\
+ chan.$O\
print.$O\
rune.$O\
string.$O\
diff -r a983ade04fab -r 59711a1bdc17 src/runtime/chan.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/runtime/chan.c Sun Jul 13 14:29:46 2008 -0700
@@ -0,0 +1,75 @@
+// Copyright 2009 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.
+
+#include "runtime.h"
+
+static int32 debug = 1;
+
+typedef struct Hchan Hchan;
+
+struct Hchan
+{
+ uint32 elemsize;
+ uint32 hint;
+ uint32 eo;
+ Alg* elemalg;
+};
+
+// newchan(elemsize uint32, elemalg uint32, hint uint32) (hchan *chan any);
+void
+sys·newchan(uint32 elemsize, uint32 elemalg, uint32 hint,
+ Hchan* ret)
+{
+ Hchan *c;
+
+ if(elemalg >= nelem(algarray)) {
+ prints("0<=");
+ sys·printint(elemalg);
+ prints("<");
+ sys·printint(nelem(algarray));
+ prints("\n");
+
+ throw("sys·newchan: elem algorithm out of range");
+ }
+
+ c = mal(sizeof(*c));
+
+ c->elemsize = elemsize;
+ c->elemalg = &algarray[elemalg];
+ c->hint = hint;
+
+ // these calculations are compiler dependent
+ c->eo = rnd(sizeof(c), elemsize);
+
+ ret = c;
+ FLUSH(&ret);
+
+ if(debug) {
+ prints("newchan: chan=");
+ sys·printpointer(c);
+ prints("; elemsize=");
+ sys·printint(elemsize);
+ prints("; elemalg=");
+ sys·printint(elemalg);
+ prints("; hint=");
+ sys·printint(hint);
+ prints("\n");
+ }
+}
+
+// chansend(hchan *chan any, elem any);
+void
+sys·chansend(Hchan* c, ...)
+{
+ byte *ae;
+
+ ae = (byte*)&c + c->eo;
+ if(debug) {
+ prints("chansend: chan=");
+ sys·printpointer(c);
+ prints("; elem=");
+ c->elemalg->print(c->elemsize, ae);
+ prints("\n");
+ }
+}
diff -r a983ade04fab -r 59711a1bdc17 src/runtime/map.c
--- a/src/runtime/map.c Sat Jul 12 17:16:22 2008 -0700
+++ b/src/runtime/map.c Sun Jul 13 14:29:46 2008 -0700
@@ -4,17 +4,10 @@
#include "runtime.h"
+static int32 debug = 0;
+
typedef struct Link Link;
typedef struct Hmap Hmap;
-typedef struct Alg Alg;
-
-struct Alg
-{
- uint64 (*hash)(uint32, void*);
- uint32 (*equal)(uint32, void*, void*);
- void (*print)(uint32, void*);
- void (*copy)(uint32, void*, void*);
-};
struct Link
{
@@ -28,154 +21,15 @@
uint32 keysize;
uint32 valsize;
uint32 hint;
- Alg* keyalg;
- Alg* valalg;
uint32 valoffset;
uint32 ko;
uint32 vo;
uint32 po;
+ Alg* keyalg;
+ Alg* valalg;
Link* link;
};
-static uint64
-memhash(uint32 s, void *a)
-{
- prints("memhash\n");
- return 0x12345;
-}
-
-static uint32
-memequal(uint32 s, void *a, void *b)
-{
- byte *ba, *bb;
- uint32 i;
-
- ba = a;
- bb = b;
- for(i=0; i<s; i++)
- if(ba[i] != bb[i])
- return 0;
- return 1;
-}
-
-static void
-memprint(uint32 s, void *a)
-{
- uint64 v;
-
- v = 0xbadb00b;
- switch(s) {
- case 1:
- v = *(uint8*)a;
- break;
- case 2:
- v = *(uint16*)a;
- break;
- case 4:
- v = *(uint32*)a;
- break;
- case 8:
- v = *(uint64*)a;
- break;
- }
- sys·printint(v);
-}
-
-static void
-memcopy(uint32 s, void *a, void *b)
-{
- byte *ba, *bb;
- uint32 i;
-
- ba = a;
- bb = b;
- if(bb == nil) {
- for(i=0; i<s; i++)
- ba[i] = 0;
- return;
- }
- for(i=0; i<s; i++)
- ba[i] = bb[i];
-}
-
-static uint64
-stringhash(uint32 s, string *a)
-{
- prints("stringhash\n");
- return 0x12345;
-}
-
-static uint32
-stringequal(uint32 s, string *a, string *b)
-{
- return cmpstring(*a, *b) == 0;
-}
-
-static void
-stringprint(uint32 s, string *a)
-{
- sys·printstring(*a);
-}
-
-static void
-stringcopy(uint32 s, string *a, string *b)
-{
- if(b == nil) {
- *a = nil;
- return;
- }
- *a = *b;
-}
-
-static uint64
-pointerhash(uint32 s, void **a)
-{
- prints("pointerhash\n");
- return 0x12345;
-}
-
-static uint32
-pointerequal(uint32 s, void **a, void **b)
-{
- prints("pointerequal\n");
- return 0;
-}
-
-static void
-pointerprint(uint32 s, void **a)
-{
- prints("pointerprint\n");
-}
-
-static void
-pointercopy(uint32 s, void **a, void **b)
-{
- if(b == nil) {
- *a = nil;
- return;
- }
- *a = *b;
-}
-
-static uint32
-rnd(uint32 n, uint32 m)
-{
- uint32 r;
-
- r = n % m;
- if(r)
- n += m-r;
- return n;
-}
-
-static Alg
-algarray[] =
-{
- { &memhash, &memequal, &memprint, &memcopy },
- { &stringhash, &stringequal, &stringprint, &stringcopy },
- { &pointerhash, &pointerequal, &pointerprint, &pointercopy },
-};
-
// newmap(keysize uint32, valsize uint32,
// keyalg uint32, valalg uint32,
// hint uint32) (hmap *map[any]any);
diff -r a983ade04fab -r 59711a1bdc17 src/runtime/runtime.c
--- a/src/runtime/runtime.c Sat Jul 12 17:16:22 2008 -0700
+++ b/src/runtime/runtime.c Sun Jul 13 14:29:46 2008 -0700
@@ -64,6 +64,17 @@
}
}
+uint32
+rnd(uint32 n, uint32 m)
+{
+ uint32 r;
+
+ r = n % m;
+ if(r)
+ n += m-r;
+ return n;
+}
+
static byte*
brk(uint32 n)
{
@@ -81,7 +92,7 @@
byte* v;
// round to keep everything 64-bit aligned
- n = (n+7) & ~7;
+ n = rnd(n, 8);
nmal += n;
// do we have enough in contiguous hunk
@@ -469,7 +480,6 @@
static int32 envc;
static uint8** envv;
-
void
args(int32 c, uint8 **v)
{
@@ -797,3 +807,136 @@
*(int32*)234 = 123;
}
+
+/*
+ * map and chan helpers for
+ * dealing with unknown types
+ */
+
+static uint64
+memhash(uint32 s, void *a)
+{
+ prints("memhash\n");
+ return 0x12345;
+}
+
+static uint32
+memequal(uint32 s, void *a, void *b)
+{
+ byte *ba, *bb;
+ uint32 i;
+
+ ba = a;
+ bb = b;
+ for(i=0; i<s; i++)
+ if(ba[i] != bb[i])
+ return 0;
+ return 1;
+}
+
+static void
+memprint(uint32 s, void *a)
+{
+ uint64 v;
+
+ v = 0xbadb00b;
+ switch(s) {
+ case 1:
+ v = *(uint8*)a;
+ break;
+ case 2:
+ v = *(uint16*)a;
+ break;
+ case 4:
+ v = *(uint32*)a;
+ break;
+ case 8:
+ v = *(uint64*)a;
+ break;
+ }
+ sys·printint(v);
+}
+
+static void
+memcopy(uint32 s, void *a, void *b)
+{
+ byte *ba, *bb;
+ uint32 i;
+
+ ba = a;
+ bb = b;
+ if(bb == nil) {
+ for(i=0; i<s; i++)
+ ba[i] = 0;
+ return;
+ }
+ for(i=0; i<s; i++)
+ ba[i] = bb[i];
+}
+
+static uint64
+stringhash(uint32 s, string *a)
+{
+ prints("stringhash\n");
+ return 0x12345;
+}
+
+static uint32
+stringequal(uint32 s, string *a, string *b)
+{
+ return cmpstring(*a, *b) == 0;
+}
+
+static void
+stringprint(uint32 s, string *a)
+{
+ sys·printstring(*a);
+}
+
+static void
+stringcopy(uint32 s, string *a, string *b)
+{
+ if(b == nil) {
+ *a = nil;
+ return;
+ }
+ *a = *b;
+}
+
+static uint64
+pointerhash(uint32 s, void **a)
+{
+ prints("pointerhash\n");
+ return 0x12345;
+}
+
+static uint32
+pointerequal(uint32 s, void **a, void **b)
+{
+ prints("pointerequal\n");
+ return 0;
+}
+
+static void
+pointerprint(uint32 s, void **a)
+{
+ prints("pointerprint\n");
+}
+
+static void
+pointercopy(uint32 s, void **a, void **b)
+{
+ if(b == nil) {
+ *a = nil;
+ return;
+ }
+ *a = *b;
+}
+
+Alg
+algarray[3] =
+{
+ { &memhash, &memequal, &memprint, &memcopy },
+ { &stringhash, &stringequal, &stringprint, &stringcopy },
+ { &pointerhash, &pointerequal, &pointerprint, &pointercopy },
+};
diff -r a983ade04fab -r 59711a1bdc17 src/runtime/runtime.h
--- a/src/runtime/runtime.h Sat Jul 12 17:16:22 2008 -0700
+++ b/src/runtime/runtime.h Sun Jul 13 14:29:46 2008 -0700
@@ -33,24 +33,58 @@
*/
typedef uint8 bool;
typedef uint8 byte;
-typedef struct
+typedef struct String *string;
+typedef struct Sigs Sigs;
+typedef struct Sigi Sigi;
+typedef struct Map Map;
+typedef struct Gobuf Gobuf;
+typedef struct G G;
+typedef struct M M;
+typedef struct Stktop Stktop;
+typedef struct Alg Alg;
+
+/*
+ * per cpu declaration
+ */
+extern register G* g; // R15
+extern register M* m; // R14
+
+/*
+ * defined constants
+ */
+enum
+{
+ // G status
+ Gidle,
+ Grunnable,
+ Gdead,
+};
+enum
+{
+ true = 1,
+ false = 0,
+};
+
+/*
+ * structures
+ */
+struct String
{
int32 len;
byte str[1];
-} *string;
-typedef struct
+};
+struct Sigs
{
byte* name;
uint32 hash;
void (*fun)(void);
-} Sigs;
-typedef struct
+};
+struct Sigi
{
byte* name;
uint32 hash;
uint32 offset;
-} Sigi;
-typedef struct Map Map;
+};
struct Map
{
Sigi* si;
@@ -60,13 +94,11 @@
int32 unused;
void (*fun[])(void);
};
-typedef struct Gobuf Gobuf;
struct Gobuf
{
byte* SP;
byte* PC;
};
-typedef struct G G;
struct G
{
byte* stackguard; // must not move
@@ -77,7 +109,6 @@
int32 pri;
int32 goid;
};
-typedef struct M M;
struct M
{
G* g0; // g0 w interrupt stack - must not move
@@ -90,38 +121,24 @@
int32 siz1;
int32 siz2;
};
-typedef struct Stktop Stktop;
-struct Stktop {
+struct Stktop
+{
uint8* oldbase;
uint8* oldsp;
uint64 magic;
uint8* oldguard;
};
-extern register G* g; // R15
-extern register M* m; // R14
-
-enum
+struct Alg
{
- // G status
- Gidle,
- Grunnable,
- Gdead,
+ uint64 (*hash)(uint32, void*);
+ uint32 (*equal)(uint32, void*, void*);
+ void (*print)(uint32, void*);
+ void (*copy)(uint32, void*, void*);
};
-
-/*
- * global variables
- */
-M* allm;
-G* allg;
-int32 goidgen;
-
-/*
- * defined constants
- */
-enum
+struct SigTab
{
- true = 1,
- false = 0,
+ int32 catch;
+ int8 *name;
};
/*
@@ -133,6 +150,15 @@
#define nil ((void*)0)
/*
+ * external data
+ */
+extern Alg algarray[3];
+extern string emptystring;
+M* allm;
+G* allg;
+int32 goidgen;
+
+/*
* common functions and data
*/
int32 strcmp(byte*, byte*);
@@ -141,9 +167,6 @@
int32 runetochar(byte*, int32);
int32 chartorune(uint32*, byte*);
-extern string emptystring;
-extern int32 debug;
-
/*
* very low level c-called
*/
@@ -155,6 +178,7 @@
void FLUSH(void*);
void* getu(void);
void throw(int8*);
+uint32 rnd(uint32, uint32);
void prints(int8*);
void mcpy(byte*, byte*, uint32);
void* mal(uint32);
@@ -165,11 +189,6 @@
int32 read(int32, void*, int32);
void close(int32);
int32 fstat(int32, void*);
-struct SigTab
-{
- int32 catch;
- int8 *name;
-};
/*
* low level go -called
changeset: 343:eb53a02aa7c2
user: Ken Thompson <[email protected]>
date: Sun Jul 13 16:20:27 2008 -0700
summary: chan
diff -r 59711a1bdc17 -r eb53a02aa7c2 src/cmd/gc/subr.c
--- a/src/cmd/gc/subr.c Sun Jul 13 14:29:46 2008 -0700
+++ b/src/cmd/gc/subr.c Sun Jul 13 16:20:27 2008 -0700
@@ -1364,6 +1364,7 @@
case TPTR32:
case TPTR64:
+ case TCHAN:
nt = shallow(t);
nt->type = deep(t->type);
break;
diff -r 59711a1bdc17 -r eb53a02aa7c2 src/cmd/gc/walk.c
--- a/src/cmd/gc/walk.c Sun Jul 13 14:29:46 2008 -0700
+++ b/src/cmd/gc/walk.c Sun Jul 13 16:20:27 2008 -0700
@@ -1700,12 +1700,16 @@
break;
case OAS:
+ cl = listcount(n->left);
+ cr = listcount(n->right);
+
+ if(cl == 2 && cr == 1 && n->right->op == ORECV)
+ goto recv2;
+ if(cl != 1 || cr != 1 || n->left->op != OSEND)
+ goto shape;
+
// chansend(hchan *chan any, elem any);
-//dump("assign1", n);
- if(n->left->op != OSEND)
- goto shape;
-
t = fixchan(n->left->left->type);
if(t == T)
break;
@@ -1716,14 +1720,54 @@
r = nod(OLIST, a, r);
on = syslook("chansend", 1);
-
+print("type=%lT\n", t);
+print("on=%lT\n", on->type);
argtype(on, t->type); // any-1
+print("on=%lT\n", on->type);
argtype(on, t->type); // any-2
+print("on=%lT\n", on->type);
r = nod(OCALL, on, r);
walktype(r, Erv);
break;
+ case ORECV:
+ // chanrecv1(hchan *chan any) (elem any);
+
+ t = fixchan(n->left->type);
+ if(t == T)
+ break;
+
+ a = n->left; // chan
+ r = a;
+
+ on = syslook("chanrecv1", 1);
+
+ argtype(on, t->type); // any-1
+ argtype(on, t->type); // any-2
+ r = nod(OCALL, on, r);
+ walktype(r, Erv);
+ break;
+
+ recv2:
+ // chanrecv2(hchan *chan any) (elem any, pres bool);
+
+ t = fixchan(n->right->left->type);
+ if(t == T)
+ break;
+
+ a = n->right->left; // chan
+ r = a;
+
+ on = syslook("chanrecv2", 1);
+
+ argtype(on, t->type); // any-1
+ argtype(on, t->type); // any-2
+ r = nod(OCALL, on, r);
+ n->right = r;
+ r = n;
+ walktype(r, Etop);
+ break;
}
return r;
@@ -1950,6 +1994,18 @@
a = old2new(nl->right, types[TBOOL]);
n = nod(OLIST, n, a);
break;
+
+ case ORECV:
+ if(cl != 2)
+ goto badt;
+ walktype(nr->left, Erv);
+ t = nr->left->type;
+ if(!isptrto(t, TCHAN))
+ goto badt;
+ a = old2new(nl->left, t->type->type);
+ n = a;
+ a = old2new(nl->right, types[TBOOL]);
+ n = nod(OLIST, n, a);
}
n = rev(n);
return n;
diff -r 59711a1bdc17 -r eb53a02aa7c2 src/runtime/chan.c
--- a/src/runtime/chan.c Sun Jul 13 14:29:46 2008 -0700
+++ b/src/runtime/chan.c Sun Jul 13 16:20:27 2008 -0700
@@ -73,3 +73,31 @@
prints("\n");
}
}
+
+// chanrecv1(hchan *chan any) (elem any);
+void
+sys·chanrecv1(Hchan* c, ...)
+{
+ byte *ae;
+
+ ae = (byte*)&c + c->eo;
+ if(debug) {
+ prints("chanrecv1: chan=");
+ sys·printpointer(c);
+ prints("\n");
+ }
+}
+
+// chanrecv2(hchan *chan any) (elem any, pres bool);
+void
+sys·chanrecv2(Hchan* c, ...)
+{
+ byte *ae;
+
+ ae = (byte*)&c + c->eo;
+ if(debug) {
+ prints("chanrecv2: chan=");
+ sys·printpointer(c);
+ prints("\n");
+ }
+}
changeset: 345:d6a0312c45ab
user: Ken Thompson <[email protected]>
date: Mon Jul 14 14:33:39 2008 -0700
summary: synch chan
diff -r 2bb5c39a8542 -r d6a0312c45ab src/runtime/Makefile
--- a/src/runtime/Makefile Sun Jul 13 16:22:50 2008 -0700
+++ b/src/runtime/Makefile Mon Jul 14 14:33:39 2008 -0700
@@ -22,6 +22,7 @@
chan.$O\
print.$O\
rune.$O\
+ proc.$O\
string.$O\
sys_file.$O\
diff -r 2bb5c39a8542 -r d6a0312c45ab src/runtime/chan.c
--- a/src/runtime/chan.c Sun Jul 13 16:22:50 2008 -0700
+++ b/src/runtime/chan.c Mon Jul 14 14:33:39 2008 -0700
@@ -4,16 +4,29 @@
#include "runtime.h"
-static int32 debug = 1;
+static int32 debug = 0;
typedef struct Hchan Hchan;
+typedef struct Link Link;
struct Hchan
{
uint32 elemsize;
- uint32 hint;
- uint32 eo;
- Alg* elemalg;
+ uint32 dataqsiz; // size of the circular q
+ uint32 qcount; // total data in the q
+ uint32 eo; // vararg of element
+ uint32 po; // vararg of present bool
+ Alg* elemalg; // interface for element type
+ Link* senddataq; // pointer for sender
+ Link* recvdataq; // pointer for receiver
+ WaitQ recvq; // list of recv waiters
+ WaitQ sendq; // list of send waiters
+};
+
+struct Link
+{
+ Link* link;
+ byte data[8];
};
// newchan(elemsize uint32, elemalg uint32, hint uint32) (hchan *chan any);
@@ -22,6 +35,7 @@
Hchan* ret)
{
Hchan *c;
+ int32 i;
if(elemalg >= nelem(algarray)) {
prints("0<=");
@@ -37,10 +51,30 @@
c->elemsize = elemsize;
c->elemalg = &algarray[elemalg];
- c->hint = hint;
+
+ if(hint > 0) {
+ Link *d, *b, *e;
+
+ // make a circular q
+ b = nil;
+ e = nil;
+ for(i=0; i<hint; i++) {
+ d = mal(sizeof(*d));
+ if(e == nil)
+ e = d;
+ d->link = b;
+ b = d;
+ }
+ e->link = b;
+ c->recvdataq = b;
+ c->senddataq = b;
+ c->qcount = 0;
+ c->dataqsiz = hint;
+ }
// these calculations are compiler dependent
c->eo = rnd(sizeof(c), elemsize);
+ c->po = rnd(c->eo+elemsize, 1);
ret = c;
FLUSH(&ret);
@@ -52,10 +86,11 @@
sys·printint(elemsize);
prints("; elemalg=");
sys·printint(elemalg);
- prints("; hint=");
- sys·printint(hint);
+ prints("; dataqsiz=");
+ sys·printint(c->dataqsiz);
prints("\n");
}
+
}
// chansend(hchan *chan any, elem any);
@@ -63,6 +98,7 @@
sys·chansend(Hchan* c, ...)
{
byte *ae;
+ G *gr;
ae = (byte*)&c + c->eo;
if(debug) {
@@ -72,6 +108,23 @@
c->elemalg->print(c->elemsize, ae);
prints("\n");
}
+ if(c->dataqsiz > 0)
+ goto asynch;
+
+ gr = dequeue(&c->recvq);
+ if(gr != nil) {
+ c->elemalg->copy(c->elemsize, gr->elem, ae);
+ gr->status = Grunnable;
+ return;
+ }
+ c->elemalg->copy(c->elemsize, g->elem, ae);
+ g->status = Gwaiting;
+ enqueue(&c->sendq, g);
+ sys·gosched();
+ return;
+
+asynch:
+ throw("sys·chansend: asynch not yet");
}
// chanrecv1(hchan *chan any) (elem any);
@@ -79,6 +132,7 @@
sys·chanrecv1(Hchan* c, ...)
{
byte *ae;
+ G *gs;
ae = (byte*)&c + c->eo;
if(debug) {
@@ -86,18 +140,42 @@
sys·printpointer(c);
prints("\n");
}
+ if(c->dataqsiz > 0)
+ goto asynch;
+
+ gs = dequeue(&c->sendq);
+ if(gs != nil) {
+ c->elemalg->copy(c->elemsize, ae, gs->elem);
+ gs->status = Grunnable;
+ return;
+ }
+ g->status = Gwaiting;
+ enqueue(&c->recvq, g);
+ sys·gosched();
+ c->elemalg->copy(c->elemsize, ae, g->elem);
+ return;
+
+asynch:
+ throw("sys·chanrecv1: asynch not yet");
}
// chanrecv2(hchan *chan any) (elem any, pres bool);
void
sys·chanrecv2(Hchan* c, ...)
{
- byte *ae;
+ byte *ae, *ap;
ae = (byte*)&c + c->eo;
+ ap = (byte*)&c + c->po;
if(debug) {
prints("chanrecv2: chan=");
sys·printpointer(c);
prints("\n");
}
+ if(c->dataqsiz > 0)
+ goto asynch;
+ throw("sys·chanrecv2: synch not yet");
+
+asynch:
+ throw("sys·chanrecv2: asynch not yet");
}
diff -r 2bb5c39a8542 -r d6a0312c45ab src/runtime/runtime.c
--- a/src/runtime/runtime.c Sun Jul 13 16:22:50 2008 -0700
+++ b/src/runtime/runtime.c Mon Jul 14 14:33:39 2008 -0700
@@ -581,238 +581,10 @@
initsig();
}
-void
-sys·goexit(void)
-{
-//prints("goexit goid=");
-//sys·printint(g->goid);
-//prints("\n");
- g->status = Gdead;
- sys·gosched();
-}
-
-void
-sys·newproc(int32 siz, byte* fn, byte* arg0)
-{
- byte *stk, *sp;
- G *newg;
-
-//prints("newproc siz=");
-//sys·printint(siz);
-//prints(" fn=");
-//sys·printpointer(fn);
-
- siz = (siz+7) & ~7;
- if(siz > 1024) {
- prints("sys·newproc: too many args: ");
- sys·printint(siz);
- prints("\n");
- sys·panicl(123);
- }
-
- newg = mal(sizeof(G));
- stk = mal(4096);
- newg->stackguard = stk+160;
-
- sp = stk + 4096 - 4*8;
- newg->stackbase = sp;
-
- sp -= siz;
- mcpy(sp, (byte*)&arg0, siz);
-
- sp -= 8;
- *(byte**)sp = (byte*)sys·goexit;
-
- sp -= 8; // retpc used by gogo
- newg->sched.SP = sp;
- newg->sched.PC = fn;
-
- goidgen++;
- newg->goid = goidgen;
-
- newg->status = Grunnable;
- newg->link = allg;
- allg = newg;
-
-//prints(" goid=");
-//sys·printint(newg->goid);
-//prints("\n");
-}
-
-G*
-select(void)
-{
- G *gp, *bestg;
-
- bestg = nil;
- for(gp=allg; gp!=nil; gp=gp->link) {
- if(gp->status != Grunnable)
- continue;
- if(bestg == nil || gp->pri < bestg->pri)
- bestg = gp;
- }
- if(bestg != nil)
- bestg->pri++;
- return bestg;
-}
-
-void
-gom0init(void)
-{
- gosave(&m->sched);
- sys·gosched();
-}
-
-void
-sys·gosched(void)
-{
- G* gp;
-
- if(g != m->g0) {
- if(gosave(&g->sched))
- return;
- g = m->g0;
- gogo(&m->sched);
- }
- gp = select();
- if(gp == nil) {
-// prints("sched: no more work\n");
- sys·exit(0);
- }
-
- m->curg = gp;
- g = gp;
- gogo(&gp->sched);
-}
-
-//
-// the calling sequence for a routine that
-// needs N bytes stack, A args.
-//
-// N1 = (N+160 > 4096)? N+160: 0
-// A1 = A
-//
-// if N <= 75
-// CMPQ SP, 0(R15)
-// JHI 4(PC)
-// MOVQ $(N1<<0) | (A1<<32)), AX
-// MOVQ AX, 0(R14)
-// CALL sys·morestack(SB)
-//
-// if N > 75
-// LEAQ (-N-75)(SP), AX
-// CMPQ AX, 0(R15)
-// JHI 4(PC)
-// MOVQ $(N1<<0) | (A1<<32)), AX
-// MOVQ AX, 0(R14)
-// CALL sys·morestack(SB)
-//
-
-void
-oldstack(void)
-{
- Stktop *top;
- uint32 siz2;
- byte *sp;
-if(debug) prints("oldstack m->cret = ");
-if(debug) sys·printpointer((void*)m->cret);
-if(debug) prints("\n");
-
- top = (Stktop*)m->curg->stackbase;
-
- m->curg->stackbase = top->oldbase;
- m->curg->stackguard = top->oldguard;
- siz2 = (top->magic>>32) & 0xffffLL;
-
- sp = (byte*)top;
- if(siz2 > 0) {
- siz2 = (siz2+7) & ~7;
- sp -= siz2;
- mcpy(top->oldsp+16, sp, siz2);
- }
-
- m->morestack.SP = top->oldsp+8;
- m->morestack.PC = (byte*)(*(uint64*)(top->oldsp+8));
-if(debug) prints("oldstack sp=");
-if(debug) sys·printpointer(m->morestack.SP);
-if(debug) prints(" pc=");
-if(debug) sys·printpointer(m->morestack.PC);
-if(debug) prints("\n");
- gogoret(&m->morestack, m->cret);
-}
-
-void
-newstack(void)
-{
- int32 siz1, siz2;
- Stktop *top;
- byte *stk, *sp;
- void (*fn)(void);
-
- siz1 = m->morearg & 0xffffffffLL;
- siz2 = (m->morearg>>32) & 0xffffLL;
-
-if(debug) prints("newstack siz1=");
-if(debug) sys·printint(siz1);
-if(debug) prints(" siz2=");
-if(debug) sys·printint(siz2);
-if(debug) prints(" moresp=");
-if(debug) sys·printpointer(m->moresp);
-if(debug) prints("\n");
-
- if(siz1 < 4096)
- siz1 = 4096;
- stk = mal(siz1 + 1024);
- stk += 512;
-
- top = (Stktop*)(stk+siz1-sizeof(*top));
-
- top->oldbase = m->curg->stackbase;
- top->oldguard = m->curg->stackguard;
- top->oldsp = m->moresp;
- top->magic = m->morearg;
-
- m->curg->stackbase = (byte*)top;
- m->curg->stackguard = stk + 160;
-
- sp = (byte*)top;
-
- if(siz2 > 0) {
- siz2 = (siz2+7) & ~7;
- sp -= siz2;
- mcpy(sp, m->moresp+16, siz2);
- }
-
- g = m->curg;
- fn = (void(*)(void))(*(uint64*)m->moresp);
-if(debug) prints("fn=");
-if(debug) sys·printpointer(fn);
-if(debug) prints("\n");
- setspgoto(sp, fn, retfromnewstack);
-
- *(int32*)345 = 123;
-}
-
-void
-sys·morestack(uint64 u)
-{
- while(g == m->g0) {
- // very bad news
- *(int32*)123 = 123;
- }
-
- g = m->g0;
- m->moresp = (byte*)(&u-1);
- setspgoto(m->sched.SP, newstack, nil);
-
- *(int32*)234 = 123;
-}
-
/*
* map and chan helpers for
* dealing with unknown types
*/
-
static uint64
memhash(uint32 s, void *a)
{
diff -r 2bb5c39a8542 -r d6a0312c45ab src/runtime/runtime.h
--- a/src/runtime/runtime.h Sun Jul 13 16:22:50 2008 -0700
+++ b/src/runtime/runtime.h Mon Jul 14 14:33:39 2008 -0700
@@ -42,6 +42,7 @@
typedef struct M M;
typedef struct Stktop Stktop;
typedef struct Alg Alg;
+typedef struct WaitQ WaitQ;
/*
* per cpu declaration
@@ -57,6 +58,7 @@
// G status
Gidle,
Grunnable,
+ Gwaiting,
Gdead,
};
enum
@@ -104,10 +106,12 @@
byte* stackguard; // must not move
byte* stackbase; // must not move
Gobuf sched;
- G* link;
+ G* alllink; // on allq
+ G* qlink; // on wait q
int32 status;
int32 pri;
int32 goid;
+ byte elem[8]; // transfer element for chan
};
struct M
{
@@ -121,7 +125,12 @@
int32 siz1;
int32 siz2;
};
-struct Stktop
+struct WaitQ
+{
+ G* first;
+ G* last;
+};
+struct Stktop
{
uint8* oldbase;
uint8* oldsp;
@@ -166,6 +175,8 @@
void dump(byte*, int32);
int32 runetochar(byte*, int32);
int32 chartorune(uint32*, byte*);
+G* dequeue(WaitQ*);
+void enqueue(WaitQ*, G*);
/*
* very low level c-called
changeset: 351:405dda82648b
user: Ken Thompson <[email protected]>
date: Mon Jul 14 17:41:38 2008 -0700
summary: chan asynch
diff -r 24658b05d409 -r 405dda82648b src/cmd/gc/go.y
--- a/src/cmd/gc/go.y Mon Jul 14 16:57:42 2008 -0700
+++ b/src/cmd/gc/go.y Mon Jul 14 17:41:38 2008 -0700
@@ -706,6 +706,11 @@
$$ = nod(ONEW, N, N);
$$->type = ptrto($3);
}
+| LNEW '(' type ',' expr_list ')'
+ {
+ $$ = nod(ONEW, $5, N);
+ $$->type = ptrto($3);
+ }
| fnliteral
| '[' expr_list ']'
{
diff -r 24658b05d409 -r 405dda82648b src/runtime/chan.c
--- a/src/runtime/chan.c Mon Jul 14 16:57:42 2008 -0700
+++ b/src/runtime/chan.c Mon Jul 14 17:41:38 2008 -0700
@@ -26,7 +26,7 @@
struct Link
{
Link* link;
- byte data[8];
+ byte elem[8];
};
// newchan(elemsize uint32, elemalg uint32, hint uint32) (hchan *chan any);
@@ -124,7 +124,17 @@
return;
asynch:
- throw("sys·chansend: asynch not yet");
+ while(c->qcount >= c->dataqsiz) {
+ g->status = Gwaiting;
+ enqueue(&c->sendq, g);
+ sys·gosched();
+ }
+ c->elemalg->copy(c->elemsize, c->senddataq->elem, ae);
+ c->senddataq = c->senddataq->link;
+ c->qcount++;
+ gr = dequeue(&c->recvq);
+ if(gr != nil)
+ gr->status = Grunnable;
}
// chanrecv1(hchan *chan any) (elem any);
@@ -156,7 +166,17 @@
return;
asynch:
- throw("sys·chanrecv1: asynch not yet");
+ while(c->qcount <= 0) {
+ g->status = Gwaiting;
+ enqueue(&c->recvq, g);
+ sys·gosched();
+ }
+ c->elemalg->copy(c->elemsize, ae, c->recvdataq->elem);
+ c->recvdataq = c->recvdataq->link;
+ c->qcount--;
+ gs = dequeue(&c->sendq);
+ if(gs != nil)
+ gs->status = Grunnable;
}
// chanrecv2(hchan *chan any) (elem any, pres bool);
@@ -164,6 +184,7 @@
sys·chanrecv2(Hchan* c, ...)
{
byte *ae, *ap;
+ G *gs;
ae = (byte*)&c + c->eo;
ap = (byte*)&c + c->po;
@@ -174,8 +195,27 @@
}
if(c->dataqsiz > 0)
goto asynch;
- throw("sys·chanrecv2: synch not yet");
+
+ gs = dequeue(&c->sendq);
+ if(gs != nil) {
+ c->elemalg->copy(c->elemsize, ae, gs->elem);
+ gs->status = Grunnable;
+ *ap = true;
+ return;
+ }
+ *ap = false;
+ return;
asynch:
- throw("sys·chanrecv2: asynch not yet");
+ if(c->qcount <= 0) {
+ *ap = false;
+ return;
+ }
+ c->elemalg->copy(c->elemsize, ae, c->recvdataq->elem);
+ c->recvdataq = c->recvdataq->link;
+ c->qcount--;
+ gs = dequeue(&c->sendq);
+ if(gs != nil)
+ gs->status = Grunnable;
+ *ap = true;
}
changeset: 368:da3e36ef0a7b
user: Ken Thompson <[email protected]>
date: Tue Jul 15 21:07:59 2008 -0700
summary: new chan syntax
diff -r 219cb744ece7 -r da3e36ef0a7b src/cmd/gc/go.y
--- a/src/cmd/gc/go.y Tue Jul 15 20:52:07 2008 -0700
+++ b/src/cmd/gc/go.y Tue Jul 15 21:07:59 2008 -0700
@@ -22,7 +22,7 @@
%token LFOR LIF LELSE LSWITCH LCASE LDEFAULT
%token LBREAK LCONTINUE LGO LGOTO LRANGE
%token LOROR LANDAND LEQ LNE LLE LLT LGE LGT
-%token LLSH LRSH LINC LDEC
+%token LLSH LRSH LINC LDEC LSEND LRECV
%token LNIL LTRUE LFALSE LIOTA
%token LPANIC LPRINT LIGNORE
@@ -56,6 +56,7 @@
%left LOROR
%left LANDAND
+%left LSEND LRECV
%left LEQ LNE LLE LGE LLT LGT
%left '+' '-' '|' '^'
%left '*' '/' '%' '&' LLSH LRSH
@@ -599,6 +600,14 @@
{
$$ = nod(ORSH, $1, $3);
}
+| expr LSEND expr
+ {
+ $$ = nod(OSEND, $1, $3);
+ }
+| expr LRECV expr
+ {
+ $$ = nod(ORECV, $1, $3);
+ }
uexpr:
pexpr
@@ -631,14 +640,10 @@
{
$$ = nod(OCOM, $2, N);
}
-| LLT uexpr
+| LRECV uexpr
{
$$ = nod(ORECV, $2, N);
}
-| LGT uexpr
- {
- $$ = nod(OSEND, $2, N);
- }
pexpr:
LLITERAL
@@ -907,22 +912,14 @@
{
$$ = Cboth;
}
-| LLT
+| LRECV
{
$$ = Crecv;
}
-| LGT
+| LSEND
{
$$ = Csend;
}
-| LLT LGT
- {
- $$ = Cboth;
- }
-| LGT LLT
- {
- $$ = 0;
- }
keyval:
expr ':' expr
@@ -1027,6 +1024,7 @@
$$ = newname(lookup(namebuf));
addvar($$, $1, PEXTERN);
+dump("lit1", $$);
{
Node *n;
@@ -1037,10 +1035,13 @@
n->nbody = $3;
if(n->nbody == N)
n->nbody = nod(ORETURN, N, N);
+dump("comp1", n);
compile(n);
+dump("comp2", n);
}
$$ = nod(OADDR, $$, N);
+dump("lit2", $$);
}
fnbody:
diff -r 219cb744ece7 -r da3e36ef0a7b src/cmd/gc/lex.c
--- a/src/cmd/gc/lex.c Tue Jul 15 20:52:07 2008 -0700
+++ b/src/cmd/gc/lex.c Tue Jul 15 21:07:59 2008 -0700
@@ -480,6 +480,10 @@
c = LDEC;
goto lx;
}
+ if(c1 == '<') {
+ c = LSEND;
+ goto lx;
+ }
if(c1 == '=') {
c = OSUB;
goto asop;
@@ -519,6 +523,10 @@
c = LLE;
goto lx;
}
+ if(c1 == '-') {
+ c = LRECV;
+ goto lx;
+ }
c = LLT;
break;
diff -r 219cb744ece7 -r da3e36ef0a7b src/cmd/gc/sys.go
--- a/src/cmd/gc/sys.go Tue Jul 15 20:52:07 2008 -0700
+++ b/src/cmd/gc/sys.go Tue Jul 15 21:07:59 2008 -0700
@@ -45,9 +45,11 @@
func mapassign2(hmap *map[any]any, key any, val any, pres bool);
func newchan(elemsize uint32, elemalg uint32, hint uint32) (hchan *chan any);
-func chansend(hchan *chan any, elem any);
func chanrecv1(hchan *chan any) (elem any);
func chanrecv2(hchan *chan any) (elem any, pres bool);
+func chanrecv3(hchan *chan any) (elem any, pres bool);
+func chansend1(hchan *chan any, elem any);
+func chansend2(hchan *chan any, elem any) (pres bool);
func gosched();
func goexit();
@@ -104,9 +106,11 @@
// chan
newchan
- chansend
chanrecv1
chanrecv2
+ chanrecv3
+ chansend1
+ chansend2
// go routines
gosched
diff -r 219cb744ece7 -r da3e36ef0a7b src/cmd/gc/sysimport.c
--- a/src/cmd/gc/sysimport.c Tue Jul 15 20:52:07 2008 -0700
+++ b/src/cmd/gc/sysimport.c Tue Jul 15 21:07:59 2008 -0700
@@ -190,61 +190,75 @@
"type sys._esys_094 (sys._esys_095 sys._osys_548 sys._isys_550)\n"
"var !sys.newchan sys._esys_094\n"
"type sys._esys_099 {}\n"
- "type sys._esys_100 {}\n"
- "type sys._esys_102 1 sys.any\n"
- "type sys._esys_101 *sys._esys_102\n"
- "type sys._isys_557 {hchan sys._esys_101 elem sys.any}\n"
- "type sys._esys_098 (sys._esys_099 sys._esys_100 sys._isys_557)\n"
- "var !sys.chansend sys._esys_098\n"
- "type sys._esys_104 {}\n"
- "type sys._osys_562 {elem sys.any}\n"
- "type sys._esys_106 1 sys.any\n"
- "type sys._esys_105 *sys._esys_106\n"
- "type sys._isys_564 {hchan sys._esys_105}\n"
- "type sys._esys_103 (sys._esys_104 sys._osys_562 sys._isys_564)\n"
- "var !sys.chanrecv1 sys._esys_103\n"
- "type sys._esys_108 {}\n"
- "type sys._osys_569 {elem sys.any pres sys.bool}\n"
- "type sys._esys_110 1 sys.any\n"
- "type sys._esys_109 *sys._esys_110\n"
- "type sys._isys_571 {hchan sys._esys_109}\n"
- "type sys._esys_107 (sys._esys_108 sys._osys_569 sys._isys_571)\n"
- "var !sys.chanrecv2 sys._esys_107\n"
+ "type sys._osys_557 {elem sys.any}\n"
+ "type sys._esys_101 1 sys.any\n"
+ "type sys._esys_100 *sys._esys_101\n"
+ "type sys._isys_559 {hchan sys._esys_100}\n"
+ "type sys._esys_098 (sys._esys_099 sys._osys_557 sys._isys_559)\n"
+ "var !sys.chanrecv1 sys._esys_098\n"
+ "type sys._esys_103 {}\n"
+ "type sys._osys_564 {elem sys.any pres sys.bool}\n"
+ "type sys._esys_105 1 sys.any\n"
+ "type sys._esys_104 *sys._esys_105\n"
+ "type sys._isys_566 {hchan sys._esys_104}\n"
+ "type sys._esys_102 (sys._esys_103 sys._osys_564 sys._isys_566)\n"
+ "var !sys.chanrecv2 sys._esys_102\n"
+ "type sys._esys_107 {}\n"
+ "type sys._osys_572 {elem sys.any pres sys.bool}\n"
+ "type sys._esys_109 1 sys.any\n"
+ "type sys._esys_108 *sys._esys_109\n"
+ "type sys._isys_574 {hchan sys._esys_108}\n"
+ "type sys._esys_106 (sys._esys_107 sys._osys_572 sys._isys_574)\n"
+ "var !sys.chanrecv3 sys._esys_106\n"
+ "type sys._esys_111 {}\n"
"type sys._esys_112 {}\n"
- "type sys._esys_113 {}\n"
- "type sys._esys_114 {}\n"
- "type sys._esys_111 (sys._esys_112 sys._esys_113 sys._esys_114)\n"
- "var !sys.gosched sys._esys_111\n"
+ "type sys._esys_114 1 sys.any\n"
+ "type sys._esys_113 *sys._esys_114\n"
+ "type sys._isys_580 {hchan sys._esys_113 elem sys.any}\n"
+ "type sys._esys_110 (sys._esys_111 sys._esys_112 sys._isys_580)\n"
+ "var !sys.chansend1 sys._esys_110\n"
"type sys._esys_116 {}\n"
- "type sys._esys_117 {}\n"
- "type sys._esys_118 {}\n"
- "type sys._esys_115 (sys._esys_116 sys._esys_117 sys._esys_118)\n"
- "var !sys.goexit sys._esys_115\n"
+ "type sys._osys_585 {pres sys.bool}\n"
+ "type sys._esys_118 1 sys.any\n"
+ "type sys._esys_117 *sys._esys_118\n"
+ "type sys._isys_587 {hchan sys._esys_117 elem sys.any}\n"
+ "type sys._esys_115 (sys._esys_116 sys._osys_585 sys._isys_587)\n"
+ "var !sys.chansend2 sys._esys_115\n"
"type sys._esys_120 {}\n"
- "type sys._osys_582 {_esys_579 sys.string _esys_580 sys.bool}\n"
- "type sys._isys_584 {_esys_581 sys.string}\n"
- "type sys._esys_119 (sys._esys_120 sys._osys_582 sys._isys_584)\n"
- "var !sys.readfile sys._esys_119\n"
+ "type sys._esys_121 {}\n"
"type sys._esys_122 {}\n"
- "type sys._osys_591 {_esys_588 sys.bool}\n"
- "type sys._isys_593 {_esys_589 sys.string _esys_590 sys.string}\n"
- "type sys._esys_121 (sys._esys_122 sys._osys_591 sys._isys_593)\n"
- "var !sys.writefile sys._esys_121\n"
+ "type sys._esys_119 (sys._esys_120 sys._esys_121 sys._esys_122)\n"
+ "var !sys.gosched sys._esys_119\n"
"type sys._esys_124 {}\n"
- "type sys._osys_603 {_esys_598 sys.int32 _esys_599 sys.int32}\n"
- "type sys._esys_125 *sys.uint8\n"
- "type sys._isys_605 {_esys_600 sys._esys_125 _esys_601 sys.int32 _esys_602 sys.int32}\n"
- "type sys._esys_123 (sys._esys_124 sys._osys_603 sys._isys_605)\n"
- "var !sys.bytestorune sys._esys_123\n"
- "type sys._esys_127 {}\n"
- "type sys._osys_616 {_esys_611 sys.int32 _esys_612 sys.int32}\n"
- "type sys._isys_618 {_esys_613 sys.string _esys_614 sys.int32 _esys_615 sys.int32}\n"
- "type sys._esys_126 (sys._esys_127 sys._osys_616 sys._isys_618)\n"
- "var !sys.stringtorune sys._esys_126\n"
- "type sys._esys_129 {}\n"
+ "type sys._esys_125 {}\n"
+ "type sys._esys_126 {}\n"
+ "type sys._esys_123 (sys._esys_124 sys._esys_125 sys._esys_126)\n"
+ "var !sys.goexit sys._esys_123\n"
+ "type sys._esys_128 {}\n"
+ "type sys._osys_598 {_esys_595 sys.string _esys_596 sys.bool}\n"
+ "type sys._isys_600 {_esys_597 sys.string}\n"
+ "type sys._esys_127 (sys._esys_128 sys._osys_598 sys._isys_600)\n"
+ "var !sys.readfile sys._esys_127\n"
"type sys._esys_130 {}\n"
- "type sys._isys_625 {_esys_624 sys.int32}\n"
- "type sys._esys_128 (sys._esys_129 sys._esys_130 sys._isys_625)\n"
- "var !sys.exit sys._esys_128\n"
+ "type sys._osys_607 {_esys_604 sys.bool}\n"
+ "type sys._isys_609 {_esys_605 sys.string _esys_606 sys.string}\n"
+ "type sys._esys_129 (sys._esys_130 sys._osys_607 sys._isys_609)\n"
+ "var !sys.writefile sys._esys_129\n"
+ "type sys._esys_132 {}\n"
+ "type sys._osys_619 {_esys_614 sys.int32 _esys_615 sys.int32}\n"
+ "type sys._esys_133 *sys.uint8\n"
+ "type sys._isys_621 {_esys_616 sys._esys_133 _esys_617 sys.int32 _esys_618 sys.int32}\n"
+ "type sys._esys_131 (sys._esys_132 sys._osys_619 sys._isys_621)\n"
+ "var !sys.bytestorune sys._esys_131\n"
+ "type sys._esys_135 {}\n"
+ "type sys._osys_632 {_esys_627 sys.int32 _esys_628 sys.int32}\n"
+ "type sys._isys_634 {_esys_629 sys.string _esys_630 sys.int32 _esys_631 sys.int32}\n"
+ "type sys._esys_134 (sys._esys_135 sys._osys_632 sys._isys_634)\n"
+ "var !sys.stringtorune sys._esys_134\n"
+ "type sys._esys_137 {}\n"
+ "type sys._esys_138 {}\n"
+ "type sys._isys_641 {_esys_640 sys.int32}\n"
+ "type sys._esys_136 (sys._esys_137 sys._esys_138 sys._isys_641)\n"
+ "var !sys.exit sys._esys_136\n"
"))\n"
;
diff -r 219cb744ece7 -r da3e36ef0a7b src/cmd/gc/walk.c
--- a/src/cmd/gc/walk.c Tue Jul 15 20:52:07 2008 -0700
+++ b/src/cmd/gc/walk.c Tue Jul 15 21:07:59 2008 -0700
@@ -278,6 +278,7 @@
case ORECV:
if(cl == 2 && cr == 1) {
// a,b = <chan - chanrecv2
+ walktype(r->left, Erv);
if(!isptrto(r->left->type, TCHAN))
break;
l = chanop(n, top);
@@ -585,25 +586,24 @@
goto ret;
case OSEND:
- if(top != Elv)
+ if(top == Elv)
goto nottop;
walktype(n->left, Erv);
- t = n->left->type;
- if(!isptrto(t, TCHAN))
- goto badt;
- n->type = t->type->type;
+ walktype(n->right, Erv);
+ *n = *chanop(n, top);
goto ret;
case ORECV:
- if(top != Erv)
+ if(top == Elv)
goto nottop;
- walktype(n->left, Erv);
- t = n->left->type;
- if(!isptrto(t, TCHAN))
- goto badt;
- n->type = t->type->type;
-
- *n = *chanop(n, top);
+ if(n->right == N) {
+ walktype(n->left, Erv); // chan
+ *n = *chanop(n, top); // returns e blocking
+ goto ret;
+ }
+ walktype(n->left, Elv); // e
+ walktype(n->right, Erv); // chan
+ *n = *chanop(n, top); // returns bool non-blocking
goto ret;
case OSLICE:
@@ -1396,7 +1396,7 @@
}
if(t->etype != TMAP) {
- fatal("fixmap: %O not map");
+ fatal("fixmap: %lT not map", tm);
return T;
}
@@ -1423,7 +1423,7 @@
}
if(t->etype != TCHAN) {
- fatal("fixchan: %O not map");
+ fatal("fixchan: %lT not chan", tm);
return T;
}
@@ -1703,31 +1703,32 @@
cl = listcount(n->left);
cr = listcount(n->right);
- if(cl == 2 && cr == 1 && n->right->op == ORECV)
- goto recv2;
- if(cl != 1 || cr != 1 || n->left->op != OSEND)
+ if(cl != 2 || cr != 1 || n->right->op != ORECV)
goto shape;
- // chansend(hchan *chan any, elem any);
+ // chanrecv2(hchan *chan any) (elem any, pres bool);
- t = fixchan(n->left->left->type);
+ t = fixchan(n->right->left->type);
if(t == T)
break;
- a = n->right; // val
+ a = n->right->left; // chan
r = a;
- a = n->left->left; // chan
- r = nod(OLIST, a, r);
- on = syslook("chansend", 1);
+ on = syslook("chanrecv2", 1);
+
argtype(on, t->type); // any-1
argtype(on, t->type); // any-2
-
r = nod(OCALL, on, r);
- walktype(r, Erv);
+ n->right = r;
+ r = n;
+ walktype(r, Etop);
break;
case ORECV:
+ if(n->right != N)
+ goto recv2;
+
// chanrecv1(hchan *chan any) (elem any);
t = fixchan(n->left->type);
@@ -1747,12 +1748,12 @@
recv2:
// chanrecv2(hchan *chan any) (elem any, pres bool);
-
- t = fixchan(n->right->left->type);
+fatal("recv2 not yet");
+ t = fixchan(n->right->type);
if(t == T)
break;
- a = n->right->left; // chan
+ a = n->right; // chan
r = a;
on = syslook("chanrecv2", 1);
@@ -1764,6 +1765,48 @@
r = n;
walktype(r, Etop);
break;
+
+ case OSEND:
+ t = fixchan(n->left->type);
+ if(t == T)
+ break;
+ if(top != Etop)
+ goto send2;
+
+ // chansend1(hchan *chan any, elem any);
+ t = fixchan(n->left->type);
+ if(t == T)
+ break;
+
+ a = n->right; // e
+ r = a;
+ a = n->left; // chan
+ r = nod(OLIST, a, r);
+
+ on = syslook("chansend1", 1);
+ argtype(on, t->type); // any-1
+ argtype(on, t->type); // any-2
+ r = nod(OCALL, on, r);
+ walktype(r, top);
+ break;
+
+ send2:
+ // chansend2(hchan *chan any, val any) (pres bool);
+ t = fixchan(n->left->type);
+ if(t == T)
+ break;
+
+ a = n->right; // e
+ r = a;
+ a = n->left; // chan
+ r = nod(OLIST, a, r);
+
+ on = syslook("chansend2", 1);
+ argtype(on, t->type); // any-1
+ argtype(on, t->type); // any-2
+ r = nod(OCALL, on, r);
+ walktype(r, top);
+ break;
}
return r;
diff -r 219cb744ece7 -r da3e36ef0a7b src/runtime/chan.c
--- a/src/runtime/chan.c Tue Jul 15 20:52:07 2008 -0700
+++ b/src/runtime/chan.c Tue Jul 15 21:07:59 2008 -0700
@@ -93,9 +93,9 @@
}
-// chansend(hchan *chan any, elem any);
+// chansend1(hchan *chan any, elem any);
void
-sys·chansend(Hchan* c, ...)
+sys·chansend1(Hchan* c, ...)
{
byte *ae;
G *gr;
@@ -137,6 +137,49 @@
gr->status = Grunnable;
}
+// chansend2(hchan *chan any, elem any) (pres bool);
+void
+sys·chansend2(Hchan* c, ...)
+{
+ byte *ae, *ap;
+ G *gr;
+
+ ae = (byte*)&c + c->eo;
+ ap = (byte*)&c + c->po;
+ if(debug) {
+ prints("chansend: chan=");
+ sys·printpointer(c);
+ prints("; elem=");
+ c->elemalg->print(c->elemsize, ae);
+ prints("\n");
+ }
+ if(c->dataqsiz > 0)
+ goto asynch;
+
+ gr = dequeue(&c->recvq);
+ if(gr != nil) {
+ c->elemalg->copy(c->elemsize, gr->elem, ae);
+ gr->status = Grunnable;
+ *ap = true;
+ return;
+ }
+ *ap = false;
+ return;
+
+asynch:
+ if(c->qcount >= c->dataqsiz) {
+ *ap = false;
+ return;
+ }
+ c->elemalg->copy(c->elemsize, c->senddataq->elem, ae);
+ c->senddataq = c->senddataq->link;
+ c->qcount++;
+ gr = dequeue(&c->recvq);
+ if(gr != nil)
+ gr->status = Grunnable;
+ *ap = true;
+}
+
// chanrecv1(hchan *chan any) (elem any);
void
sys·chanrecv1(Hchan* c, ...)
diff -r 219cb744ece7 -r da3e36ef0a7b test/chan/sieve.go
--- a/test/chan/sieve.go Tue Jul 15 20:52:07 2008 -0700
+++ b/test/chan/sieve.go Tue Jul 15 21:07:59 2008 -0700
@@ -28,12 +28,12 @@
}
// The prime sieve: Daisy-chain Filter processes together.
-func Sieve() {
+func Sieve(primes *chan-< int) {
ch := new(chan int); // Create a new channel.
go Generate(ch); // Start Generate() as a subprocess.
for {
prime := <-ch;
- print prime, "\n";
+ primes -< prime;
ch1 := new(chan int);
go Filter(ch, ch1, prime);
ch = ch1
changeset: 369:aed09caac042
user: Ken Thompson <[email protected]>
date: Wed Jul 16 11:46:33 2008 -0700
summary: chan bool offset bug
diff -r da3e36ef0a7b -r aed09caac042 src/runtime/chan.c
--- a/src/runtime/chan.c Tue Jul 15 21:07:59 2008 -0700
+++ b/src/runtime/chan.c Wed Jul 16 11:46:33 2008 -0700
@@ -15,7 +15,8 @@
uint32 dataqsiz; // size of the circular q
uint32 qcount; // total data in the q
uint32 eo; // vararg of element
- uint32 po; // vararg of present bool
+ uint32 po1; // vararg of present bool in next structure
+ uint32 po2; // vararg of present bool in same structure
Alg* elemalg; // interface for element type
Link* senddataq; // pointer for sender
Link* recvdataq; // pointer for receiver
@@ -74,7 +75,8 @@
// these calculations are compiler dependent
c->eo = rnd(sizeof(c), elemsize);
- c->po = rnd(c->eo+elemsize, 1);
+ c->po1 = rnd(c->eo+elemsize, 8); // next structure
+ c->po2 = rnd(c->eo+elemsize, 1); // same structure
ret = c;
FLUSH(&ret);
@@ -90,7 +92,6 @@
sys·printint(c->dataqsiz);
prints("\n");
}
-
}
// chansend1(hchan *chan any, elem any);
@@ -145,7 +146,8 @@
G *gr;
ae = (byte*)&c + c->eo;
- ap = (byte*)&c + c->po;
+ ap = (byte*)&c + c->po1;
+
if(debug) {
prints("chansend: chan=");
sys·printpointer(c);
@@ -230,7 +232,8 @@
G *gs;
ae = (byte*)&c + c->eo;
- ap = (byte*)&c + c->po;
+ ap = (byte*)&c + c->po2;
+
if(debug) {
prints("chanrecv2: chan=");
sys·printpointer(c);
changeset: 370:a29a464f26fb
user: Ken Thompson <[email protected]>
date: Wed Jul 16 12:44:21 2008 -0700
summary: back out last chan fix
diff -r aed09caac042 -r a29a464f26fb src/cmd/gc/sys.go
--- a/src/cmd/gc/sys.go Wed Jul 16 11:46:33 2008 -0700
+++ b/src/cmd/gc/sys.go Wed Jul 16 12:44:21 2008 -0700
@@ -13,7 +13,7 @@
func printfloat(double);
func printint(int64);
func printstring(string);
-func printpointer(*byte);
+func printpointer(*any);
func catstring(string, string) string;
func cmpstring(string, string) int32;
diff -r aed09caac042 -r a29a464f26fb src/cmd/gc/sysimport.c
--- a/src/cmd/gc/sysimport.c Wed Jul 16 11:46:33 2008 -0700
+++ b/src/cmd/gc/sysimport.c Wed Jul 16 12:44:21 2008 -0700
@@ -3,10 +3,10 @@
"type sys._esys_002 {}\n"
"type sys.any 24\n"
"type sys._esys_003 *sys.any\n"
- "type sys._osys_314 {_esys_312 sys._esys_003}\n"
+ "type sys._osys_332 {_esys_330 sys._esys_003}\n"
"type sys.uint32 6\n"
- "type sys._isys_316 {_esys_313 sys.uint32}\n"
- "type sys._esys_001 (sys._esys_002 sys._osys_314 sys._isys_316)\n"
+ "type sys._isys_334 {_esys_331 sys.uint32}\n"
+ "type sys._esys_001 (sys._esys_002 sys._osys_332 sys._isys_334)\n"
"var !sys.mal sys._esys_001\n"
"type sys._esys_005 {}\n"
"type sys._esys_006 {}\n"
@@ -16,213 +16,213 @@
"type sys._esys_009 {}\n"
"type sys._esys_010 {}\n"
"type sys.int32 5\n"
- "type sys._isys_322 {_esys_321 sys.int32}\n"
- "type sys._esys_008 (sys._esys_009 sys._esys_010 sys._isys_322)\n"
+ "type sys._isys_340 {_esys_339 sys.int32}\n"
+ "type sys._esys_008 (sys._esys_009 sys._esys_010 sys._isys_340)\n"
"var !sys.panicl sys._esys_008\n"
"type sys._esys_012 {}\n"
"type sys._esys_013 {}\n"
"type sys.bool 12\n"
- "type sys._isys_327 {_esys_326 sys.bool}\n"
- "type sys._esys_011 (sys._esys_012 sys._esys_013 sys._isys_327)\n"
+ "type sys._isys_345 {_esys_344 sys.bool}\n"
+ "type sys._esys_011 (sys._esys_012 sys._esys_013 sys._isys_345)\n"
"var !sys.printbool sys._esys_011\n"
"type sys._esys_015 {}\n"
"type sys._esys_016 {}\n"
"type sys.float64 10\n"
- "type sys._isys_332 {_esys_331 sys.float64}\n"
- "type sys._esys_014 (sys._esys_015 sys._esys_016 sys._isys_332)\n"
+ "type sys._isys_350 {_esys_349 sys.float64}\n"
+ "type sys._esys_014 (sys._esys_015 sys._esys_016 sys._isys_350)\n"
"var !sys.printfloat sys._esys_014\n"
"type sys._esys_018 {}\n"
"type sys._esys_019 {}\n"
"type sys.int64 7\n"
- "type sys._isys_337 {_esys_336 sys.int64}\n"
- "type sys._esys_017 (sys._esys_018 sys._esys_019 sys._isys_337)\n"
+ "type sys._isys_355 {_esys_354 sys.int64}\n"
+ "type sys._esys_017 (sys._esys_018 sys._esys_019 sys._isys_355)\n"
"var !sys.printint sys._esys_017\n"
"type sys._esys_021 {}\n"
"type sys._esys_022 {}\n"
"type sys._esys_023 25\n"
"type sys.string *sys._esys_023\n"
- "type sys._isys_342 {_esys_341 sys.string}\n"
- "type sys._esys_020 (sys._esys_021 sys._esys_022 sys._isys_342)\n"
+ "type sys._isys_360 {_esys_359 sys.string}\n"
+ "type sys._esys_020 (sys._esys_021 sys._esys_022 sys._isys_360)\n"
"var !sys.printstring sys._esys_020\n"
"type sys._esys_025 {}\n"
"type sys._esys_026 {}\n"
- "type sys.uint8 2\n"
- "type sys._esys_027 *sys.uint8\n"
- "type sys._isys_347 {_esys_346 sys._esys_027}\n"
- "type sys._esys_024 (sys._esys_025 sys._esys_026 sys._isys_347)\n"
+ "type sys._esys_027 *sys.any\n"
+ "type sys._isys_365 {_esys_364 sys._esys_027}\n"
+ "type sys._esys_024 (sys._esys_025 sys._esys_026 sys._isys_365)\n"
"var !sys.printpointer sys._esys_024\n"
"type sys._esys_029 {}\n"
- "type sys._osys_354 {_esys_351 sys.string}\n"
- "type sys._isys_356 {_esys_352 sys.string _esys_353 sys.string}\n"
- "type sys._esys_028 (sys._esys_029 sys._osys_354 sys._isys_356)\n"
+ "type sys._osys_372 {_esys_369 sys.string}\n"
+ "type sys._isys_374 {_esys_370 sys.string _esys_371 sys.string}\n"
+ "type sys._esys_028 (sys._esys_029 sys._osys_372 sys._isys_374)\n"
"var !sys.catstring sys._esys_028\n"
"type sys._esys_031 {}\n"
- "type sys._osys_364 {_esys_361 sys.int32}\n"
- "type sys._isys_366 {_esys_362 sys.string _esys_363 sys.string}\n"
- "type sys._esys_030 (sys._esys_031 sys._osys_364 sys._isys_366)\n"
+ "type sys._osys_382 {_esys_379 sys.int32}\n"
+ "type sys._isys_384 {_esys_380 sys.string _esys_381 sys.string}\n"
+ "type sys._esys_030 (sys._esys_031 sys._osys_382 sys._isys_384)\n"
"var !sys.cmpstring sys._esys_030\n"
"type sys._esys_033 {}\n"
- "type sys._osys_375 {_esys_371 sys.string}\n"
- "type sys._isys_377 {_esys_372 sys.string _esys_373 sys.int32 _esys_374 sys.int32}\n"
- "type sys._esys_032 (sys._esys_033 sys._osys_375 sys._isys_377)\n"
+ "type sys._osys_393 {_esys_389 sys.string}\n"
+ "type sys._isys_395 {_esys_390 sys.string _esys_391 sys.int32 _esys_392 sys.int32}\n"
+ "type sys._esys_032 (sys._esys_033 sys._osys_393 sys._isys_395)\n"
"var !sys.slicestring sys._esys_032\n"
"type sys._esys_035 {}\n"
- "type sys._osys_386 {_esys_383 sys.uint8}\n"
- "type sys._isys_388 {_esys_384 sys.string _esys_385 sys.int32}\n"
- "type sys._esys_034 (sys._esys_035 sys._osys_386 sys._isys_388)\n"
+ "type sys.uint8 2\n"
+ "type sys._osys_404 {_esys_401 sys.uint8}\n"
+ "type sys._isys_406 {_esys_402 sys.string _esys_403 sys.int32}\n"
+ "type sys._esys_034 (sys._esys_035 sys._osys_404 sys._isys_406)\n"
"var !sys.indexstring sys._esys_034\n"
"type sys._esys_037 {}\n"
- "type sys._osys_395 {_esys_393 sys.string}\n"
- "type sys._isys_397 {_esys_394 sys.int64}\n"
- "type sys._esys_036 (sys._esys_037 sys._osys_395 sys._isys_397)\n"
+ "type sys._osys_413 {_esys_411 sys.string}\n"
+ "type sys._isys_415 {_esys_412 sys.int64}\n"
+ "type sys._esys_036 (sys._esys_037 sys._osys_413 sys._isys_415)\n"
"var !sys.intstring sys._esys_036\n"
"type sys._esys_039 {}\n"
- "type sys._osys_404 {_esys_401 sys.string}\n"
+ "type sys._osys_422 {_esys_419 sys.string}\n"
"type sys._esys_040 *sys.uint8\n"
- "type sys._isys_406 {_esys_402 sys._esys_040 _esys_403 sys.int32}\n"
- "type sys._esys_038 (sys._esys_039 sys._osys_404 sys._isys_406)\n"
+ "type sys._isys_424 {_esys_420 sys._esys_040 _esys_421 sys.int32}\n"
+ "type sys._esys_038 (sys._esys_039 sys._osys_422 sys._isys_424)\n"
"var !sys.byteastring sys._esys_038\n"
"type sys._esys_042 {}\n"
"type sys._esys_043 <>\n"
- "type sys._osys_415 {_esys_411 sys._esys_043}\n"
+ "type sys._osys_433 {_esys_429 sys._esys_043}\n"
"type sys._esys_044 *sys.uint8\n"
"type sys._esys_045 *sys.uint8\n"
- "type sys._ssys_422 {}\n"
- "type sys._esys_046 *sys._ssys_422\n"
- "type sys._isys_417 {_esys_412 sys._esys_044 _esys_413 sys._esys_045 _esys_414 sys._esys_046}\n"
- "type sys._esys_041 (sys._esys_042 sys._osys_415 sys._isys_417)\n"
+ "type sys._ssys_440 {}\n"
+ "type sys._esys_046 *sys._ssys_440\n"
+ "type sys._isys_435 {_esys_430 sys._esys_044 _esys_431 sys._esys_045 _esys_432 sys._esys_046}\n"
+ "type sys._esys_041 (sys._esys_042 sys._osys_433 sys._isys_435)\n"
"var !sys.mkiface sys._esys_041\n"
"type sys._esys_048 {}\n"
- "type sys._osys_426 {_esys_425 sys.int32}\n"
+ "type sys._osys_444 {_esys_443 sys.int32}\n"
"type sys._esys_049 {}\n"
- "type sys._esys_047 (sys._esys_048 sys._osys_426 sys._esys_049)\n"
+ "type sys._esys_047 (sys._esys_048 sys._osys_444 sys._esys_049)\n"
"var !sys.argc sys._esys_047\n"
"type sys._esys_051 {}\n"
- "type sys._osys_430 {_esys_429 sys.int32}\n"
+ "type sys._osys_448 {_esys_447 sys.int32}\n"
"type sys._esys_052 {}\n"
- "type sys._esys_050 (sys._esys_051 sys._osys_430 sys._esys_052)\n"
+ "type sys._esys_050 (sys._esys_051 sys._osys_448 sys._esys_052)\n"
"var !sys.envc sys._esys_050\n"
"type sys._esys_054 {}\n"
- "type sys._osys_435 {_esys_433 sys.string}\n"
- "type sys._isys_437 {_esys_434 sys.int32}\n"
- "type sys._esys_053 (sys._esys_054 sys._osys_435 sys._isys_437)\n"
+ "type sys._osys_453 {_esys_451 sys.string}\n"
+ "type sys._isys_455 {_esys_452 sys.int32}\n"
+ "type sys._esys_053 (sys._esys_054 sys._osys_453 sys._isys_455)\n"
"var !sys.argv sys._esys_053\n"
"type sys._esys_056 {}\n"
- "type sys._osys_443 {_esys_441 sys.string}\n"
- "type sys._isys_445 {_esys_442 sys.int32}\n"
- "type sys._esys_055 (sys._esys_056 sys._osys_443 sys._isys_445)\n"
+ "type sys._osys_461 {_esys_459 sys.string}\n"
+ "type sys._isys_463 {_esys_460 sys.int32}\n"
+ "type sys._esys_055 (sys._esys_056 sys._osys_461 sys._isys_463)\n"
"var !sys.envv sys._esys_055\n"
"type sys._esys_058 {}\n"
- "type sys._osys_452 {_esys_449 sys.float64 _esys_450 sys.int32}\n"
- "type sys._isys_454 {_esys_451 sys.float64}\n"
- "type sys._esys_057 (sys._esys_058 sys._osys_452 sys._isys_454)\n"
+ "type sys._osys_470 {_esys_467 sys.float64 _esys_468 sys.int32}\n"
+ "type sys._isys_472 {_esys_469 sys.float64}\n"
+ "type sys._esys_057 (sys._esys_058 sys._osys_470 sys._isys_472)\n"
"var !sys.frexp sys._esys_057\n"
"type sys._esys_060 {}\n"
- "type sys._osys_461 {_esys_458 sys.float64}\n"
- "type sys._isys_463 {_esys_459 sys.float64 _esys_460 sys.int32}\n"
- "type sys._esys_059 (sys._esys_060 sys._osys_461 sys._isys_463)\n"
+ "type sys._osys_479 {_esys_476 sys.float64}\n"
+ "type sys._isys_481 {_esys_477 sys.float64 _esys_478 sys.int32}\n"
+ "type sys._esys_059 (sys._esys_060 sys._osys_479 sys._isys_481)\n"
"var !sys.ldexp sys._esys_059\n"
"type sys._esys_062 {}\n"
- "type sys._osys_471 {_esys_468 sys.float64 _esys_469 sys.float64}\n"
- "type sys._isys_473 {_esys_470 sys.float64}\n"
- "type sys._esys_061 (sys._esys_062 sys._osys_471 sys._isys_473)\n"
+ "type sys._osys_489 {_esys_486 sys.float64 _esys_487 sys.float64}\n"
+ "type sys._isys_491 {_esys_488 sys.float64}\n"
+ "type sys._esys_061 (sys._esys_062 sys._osys_489 sys._isys_491)\n"
"var !sys.modf sys._esys_061\n"
"type sys._esys_064 {}\n"
- "type sys._osys_480 {_esys_477 sys.bool}\n"
- "type sys._isys_482 {_esys_478 sys.float64 _esys_479 sys.int32}\n"
- "type sys._esys_063 (sys._esys_064 sys._osys_480 sys._isys_482)\n"
+ "type sys._osys_498 {_esys_495 sys.bool}\n"
+ "type sys._isys_500 {_esys_496 sys.float64 _esys_497 sys.int32}\n"
+ "type sys._esys_063 (sys._esys_064 sys._osys_498 sys._isys_500)\n"
"var !sys.isInf sys._esys_063\n"
"type sys._esys_066 {}\n"
- "type sys._osys_489 {_esys_487 sys.bool}\n"
- "type sys._isys_491 {_esys_488 sys.float64}\n"
- "type sys._esys_065 (sys._esys_066 sys._osys_489 sys._isys_491)\n"
+ "type sys._osys_507 {_esys_505 sys.bool}\n"
+ "type sys._isys_509 {_esys_506 sys.float64}\n"
+ "type sys._esys_065 (sys._esys_066 sys._osys_507 sys._isys_509)\n"
"var !sys.isNaN sys._esys_065\n"
"type sys._esys_068 {}\n"
- "type sys._osys_497 {_esys_495 sys.float64}\n"
- "type sys._isys_499 {_esys_496 sys.int32}\n"
- "type sys._esys_067 (sys._esys_068 sys._osys_497 sys._isys_499)\n"
+ "type sys._osys_515 {_esys_513 sys.float64}\n"
+ "type sys._isys_517 {_esys_514 sys.int32}\n"
+ "type sys._esys_067 (sys._esys_068 sys._osys_515 sys._isys_517)\n"
"var !sys.Inf sys._esys_067\n"
"type sys._esys_070 {}\n"
- "type sys._osys_504 {_esys_503 sys.float64}\n"
+ "type sys._osys_522 {_esys_521 sys.float64}\n"
"type sys._esys_071 {}\n"
- "type sys._esys_069 (sys._esys_070 sys._osys_504 sys._esys_071)\n"
+ "type sys._esys_069 (sys._esys_070 sys._osys_522 sys._esys_071)\n"
"var !sys.NaN sys._esys_069\n"
"type sys._esys_073 {}\n"
"type sys._esys_075 [sys.any] sys.any\n"
"type sys._esys_074 *sys._esys_075\n"
- "type sys._osys_507 {hmap sys._esys_074}\n"
- "type sys._isys_509 {keysize sys.uint32 valsize sys.uint32 keyalg sys.uint32 valalg sys.uint32 hint sys.uint32}\n"
- "type sys._esys_072 (sys._esys_073 sys._osys_507 sys._isys_509)\n"
+ "type sys._osys_525 {hmap sys._esys_074}\n"
+ "type sys._isys_527 {keysize sys.uint32 valsize sys.uint32 keyalg sys.uint32 valalg sys.uint32 hint sys.uint32}\n"
+ "type sys._esys_072 (sys._esys_073 sys._osys_525 sys._isys_527)\n"
"var !sys.newmap sys._esys_072\n"
"type sys._esys_077 {}\n"
- "type sys._osys_518 {val sys.any}\n"
+ "type sys._osys_536 {val sys.any}\n"
"type sys._esys_079 [sys.any] sys.any\n"
"type sys._esys_078 *sys._esys_079\n"
- "type sys._isys_520 {hmap sys._esys_078 key sys.any}\n"
- "type sys._esys_076 (sys._esys_077 sys._osys_518 sys._isys_520)\n"
+ "type sys._isys_538 {hmap sys._esys_078 key sys.any}\n"
+ "type sys._esys_076 (sys._esys_077 sys._osys_536 sys._isys_538)\n"
"var !sys.mapaccess1 sys._esys_076\n"
"type sys._esys_081 {}\n"
- "type sys._osys_526 {val sys.any pres sys.bool}\n"
+ "type sys._osys_544 {val sys.any pres sys.bool}\n"
"type sys._esys_083 [sys.any] sys.any\n"
"type sys._esys_082 *sys._esys_083\n"
- "type sys._isys_528 {hmap sys._esys_082 key sys.any}\n"
- "type sys._esys_080 (sys._esys_081 sys._osys_526 sys._isys_528)\n"
+ "type sys._isys_546 {hmap sys._esys_082 key sys.any}\n"
+ "type sys._esys_080 (sys._esys_081 sys._osys_544 sys._isys_546)\n"
"var !sys.mapaccess2 sys._esys_080\n"
"type sys._esys_085 {}\n"
"type sys._esys_086 {}\n"
"type sys._esys_088 [sys.any] sys.any\n"
"type sys._esys_087 *sys._esys_088\n"
- "type sys._isys_535 {hmap sys._esys_087 key sys.any val sys.any}\n"
- "type sys._esys_084 (sys._esys_085 sys._esys_086 sys._isys_535)\n"
+ "type sys._isys_553 {hmap sys._esys_087 key sys.any val sys.any}\n"
+ "type sys._esys_084 (sys._esys_085 sys._esys_086 sys._isys_553)\n"
"var !sys.mapassign1 sys._esys_084\n"
"type sys._esys_090 {}\n"
"type sys._esys_091 {}\n"
"type sys._esys_093 [sys.any] sys.any\n"
"type sys._esys_092 *sys._esys_093\n"
- "type sys._isys_541 {hmap sys._esys_092 key sys.any val sys.any pres sys.bool}\n"
- "type sys._esys_089 (sys._esys_090 sys._esys_091 sys._isys_541)\n"
+ "type sys._isys_559 {hmap sys._esys_092 key sys.any val sys.any pres sys.bool}\n"
+ "type sys._esys_089 (sys._esys_090 sys._esys_091 sys._isys_559)\n"
"var !sys.mapassign2 sys._esys_089\n"
"type sys._esys_095 {}\n"
"type sys._esys_097 1 sys.any\n"
"type sys._esys_096 *sys._esys_097\n"
- "type sys._osys_548 {hchan sys._esys_096}\n"
- "type sys._isys_550 {elemsize sys.uint32 elemalg sys.uint32 hint sys.uint32}\n"
- "type sys._esys_094 (sys._esys_095 sys._osys_548 sys._isys_550)\n"
+ "type sys._osys_566 {hchan sys._esys_096}\n"
+ "type sys._isys_568 {elemsize sys.uint32 elemalg sys.uint32 hint sys.uint32}\n"
+ "type sys._esys_094 (sys._esys_095 sys._osys_566 sys._isys_568)\n"
"var !sys.newchan sys._esys_094\n"
"type sys._esys_099 {}\n"
- "type sys._osys_557 {elem sys.any}\n"
+ "type sys._osys_575 {elem sys.any}\n"
"type sys._esys_101 1 sys.any\n"
"type sys._esys_100 *sys._esys_101\n"
- "type sys._isys_559 {hchan sys._esys_100}\n"
- "type sys._esys_098 (sys._esys_099 sys._osys_557 sys._isys_559)\n"
+ "type sys._isys_577 {hchan sys._esys_100}\n"
+ "type sys._esys_098 (sys._esys_099 sys._osys_575 sys._isys_577)\n"
"var !sys.chanrecv1 sys._esys_098\n"
"type sys._esys_103 {}\n"
- "type sys._osys_564 {elem sys.any pres sys.bool}\n"
+ "type sys._osys_582 {elem sys.any pres sys.bool}\n"
"type sys._esys_105 1 sys.any\n"
"type sys._esys_104 *sys._esys_105\n"
- "type sys._isys_566 {hchan sys._esys_104}\n"
- "type sys._esys_102 (sys._esys_103 sys._osys_564 sys._isys_566)\n"
+ "type sys._isys_584 {hchan sys._esys_104}\n"
+ "type sys._esys_102 (sys._esys_103 sys._osys_582 sys._isys_584)\n"
"var !sys.chanrecv2 sys._esys_102\n"
"type sys._esys_107 {}\n"
- "type sys._osys_572 {elem sys.any pres sys.bool}\n"
+ "type sys._osys_590 {elem sys.any pres sys.bool}\n"
"type sys._esys_109 1 sys.any\n"
"type sys._esys_108 *sys._esys_109\n"
- "type sys._isys_574 {hchan sys._esys_108}\n"
- "type sys._esys_106 (sys._esys_107 sys._osys_572 sys._isys_574)\n"
+ "type sys._isys_592 {hchan sys._esys_108}\n"
+ "type sys._esys_106 (sys._esys_107 sys._osys_590 sys._isys_592)\n"
"var !sys.chanrecv3 sys._esys_106\n"
"type sys._esys_111 {}\n"
"type sys._esys_112 {}\n"
"type sys._esys_114 1 sys.any\n"
"type sys._esys_113 *sys._esys_114\n"
- "type sys._isys_580 {hchan sys._esys_113 elem sys.any}\n"
- "type sys._esys_110 (sys._esys_111 sys._esys_112 sys._isys_580)\n"
+ "type sys._isys_598 {hchan sys._esys_113 elem sys.any}\n"
+ "type sys._esys_110 (sys._esys_111 sys._esys_112 sys._isys_598)\n"
"var !sys.chansend1 sys._esys_110\n"
"type sys._esys_116 {}\n"
- "type sys._osys_585 {pres sys.bool}\n"
+ "type sys._osys_603 {pres sys.bool}\n"
"type sys._esys_118 1 sys.any\n"
"type sys._esys_117 *sys._esys_118\n"
- "type sys._isys_587 {hchan sys._esys_117 elem sys.any}\n"
- "type sys._esys_115 (sys._esys_116 sys._osys_585 sys._isys_587)\n"
+ "type sys._isys_605 {hchan sys._esys_117 elem sys.any}\n"
+ "type sys._esys_115 (sys._esys_116 sys._osys_603 sys._isys_605)\n"
"var !sys.chansend2 sys._esys_115\n"
"type sys._esys_120 {}\n"
"type sys._esys_121 {}\n"
@@ -235,30 +235,30 @@
"type sys._esys_123 (sys._esys_124 sys._esys_125 sys._esys_126)\n"
"var !sys.goexit sys._esys_123\n"
"type sys._esys_128 {}\n"
- "type sys._osys_598 {_esys_595 sys.string _esys_596 sys.bool}\n"
- "type sys._isys_600 {_esys_597 sys.string}\n"
- "type sys._esys_127 (sys._esys_128 sys._osys_598 sys._isys_600)\n"
+ "type sys._osys_616 {_esys_613 sys.string _esys_614 sys.bool}\n"
+ "type sys._isys_618 {_esys_615 sys.string}\n"
+ "type sys._esys_127 (sys._esys_128 sys._osys_616 sys._isys_618)\n"
"var !sys.readfile sys._esys_127\n"
"type sys._esys_130 {}\n"
- "type sys._osys_607 {_esys_604 sys.bool}\n"
- "type sys._isys_609 {_esys_605 sys.string _esys_606 sys.string}\n"
- "type sys._esys_129 (sys._esys_130 sys._osys_607 sys._isys_609)\n"
+ "type sys._osys_625 {_esys_622 sys.bool}\n"
+ "type sys._isys_627 {_esys_623 sys.string _esys_624 sys.string}\n"
+ "type sys._esys_129 (sys._esys_130 sys._osys_625 sys._isys_627)\n"
"var !sys.writefile sys._esys_129\n"
"type sys._esys_132 {}\n"
- "type sys._osys_619 {_esys_614 sys.int32 _esys_615 sys.int32}\n"
+ "type sys._osys_637 {_esys_632 sys.int32 _esys_633 sys.int32}\n"
"type sys._esys_133 *sys.uint8\n"
- "type sys._isys_621 {_esys_616 sys._esys_133 _esys_617 sys.int32 _esys_618 sys.int32}\n"
- "type sys._esys_131 (sys._esys_132 sys._osys_619 sys._isys_621)\n"
+ "type sys._isys_639 {_esys_634 sys._esys_133 _esys_635 sys.int32 _esys_636 sys.int32}\n"
+ "type sys._esys_131 (sys._esys_132 sys._osys_637 sys._isys_639)\n"
"var !sys.bytestorune sys._esys_131\n"
"type sys._esys_135 {}\n"
- "type sys._osys_632 {_esys_627 sys.int32 _esys_628 sys.int32}\n"
- "type sys._isys_634 {_esys_629 sys.string _esys_630 sys.int32 _esys_631 sys.int32}\n"
- "type sys._esys_134 (sys._esys_135 sys._osys_632 sys._isys_634)\n"
+ "type sys._osys_650 {_esys_645 sys.int32 _esys_646 sys.int32}\n"
+ "type sys._isys_652 {_esys_647 sys.string _esys_648 sys.int32 _esys_649 sys.int32}\n"
+ "type sys._esys_134 (sys._esys_135 sys._osys_650 sys._isys_652)\n"
"var !sys.stringtorune sys._esys_134\n"
"type sys._esys_137 {}\n"
"type sys._esys_138 {}\n"
- "type sys._isys_641 {_esys_640 sys.int32}\n"
- "type sys._esys_136 (sys._esys_137 sys._esys_138 sys._isys_641)\n"
+ "type sys._isys_659 {_esys_658 sys.int32}\n"
+ "type sys._esys_136 (sys._esys_137 sys._esys_138 sys._isys_659)\n"
"var !sys.exit sys._esys_136\n"
"))\n"
;
diff -r aed09caac042 -r a29a464f26fb src/cmd/gc/walk.c
--- a/src/cmd/gc/walk.c Wed Jul 16 11:46:33 2008 -0700
+++ b/src/cmd/gc/walk.c Wed Jul 16 12:44:21 2008 -0700
@@ -1179,6 +1179,8 @@
loop:
if(l == N) {
+ if(r == N)
+ return nod(OBAD, N, N);
walktype(r, Etop);
return r;
}
@@ -1186,28 +1188,33 @@
w = whatis(l);
switch(w) {
default:
- badtype(n->op, l->type, T);
- l = listnext(&save);
- goto loop;
+ if(!isptr[l->type->etype]) {
+ badtype(n->op, l->type, T);
+ l = listnext(&save);
+ goto loop;
+ }
+ on = syslook("printpointer", 1);
+ argtype(on, l->type->type); // any-1
+ break;
+
case Wlitint:
case Wtint:
- name = "printint";
+ on = syslook("printint", 0);
break;
case Wlitfloat:
case Wtfloat:
- name = "printfloat";
+ on = syslook("printfloat", 0);
break;
case Wlitbool:
case Wtbool:
- name = "printbool";
+ on = syslook("printbool", 0);
break;
case Wlitstr:
case Wtstr:
- name = "printstring";
+ on = syslook("printstring", 0);
break;
}
- on = syslook(name, 0);
t = *getinarg(on->type);
if(t != nil)
t = t->type;
diff -r aed09caac042 -r a29a464f26fb src/runtime/chan.c
--- a/src/runtime/chan.c Wed Jul 16 11:46:33 2008 -0700
+++ b/src/runtime/chan.c Wed Jul 16 12:44:21 2008 -0700
@@ -15,8 +15,7 @@
uint32 dataqsiz; // size of the circular q
uint32 qcount; // total data in the q
uint32 eo; // vararg of element
- uint32 po1; // vararg of present bool in next structure
- uint32 po2; // vararg of present bool in same structure
+ uint32 po; // vararg of present bool
Alg* elemalg; // interface for element type
Link* senddataq; // pointer for sender
Link* recvdataq; // pointer for receiver
@@ -75,8 +74,7 @@
// these calculations are compiler dependent
c->eo = rnd(sizeof(c), elemsize);
- c->po1 = rnd(c->eo+elemsize, 8); // next structure
- c->po2 = rnd(c->eo+elemsize, 1); // same structure
+ c->po = rnd(c->eo+elemsize, 1);
ret = c;
FLUSH(&ret);
@@ -146,7 +144,7 @@
G *gr;
ae = (byte*)&c + c->eo;
- ap = (byte*)&c + c->po1;
+ ap = (byte*)&c + c->po;
if(debug) {
prints("chansend: chan=");
@@ -232,7 +230,7 @@
G *gs;
ae = (byte*)&c + c->eo;
- ap = (byte*)&c + c->po2;
+ ap = (byte*)&c + c->po;
if(debug) {
prints("chanrecv2: chan=");
changeset: 400:3a6d388a8d27
user: Ken Thompson <[email protected]>
date: Sun Jul 20 20:13:07 2008 -0700
summary: start of select
diff -r 060e01f01f04 -r 3a6d388a8d27 src/cmd/6g/gen.c
--- a/src/cmd/6g/gen.c Sun Jul 20 13:33:45 2008 -0700
+++ b/src/cmd/6g/gen.c Sun Jul 20 20:13:07 2008 -0700
@@ -902,6 +902,11 @@
case TPTR32:
case TPTR64:
+ if(isptrto(tl, TSTRING)) {
+ nr->val.sval = mal(8);
+ nr->val.ctype = CTSTR;
+ break;
+ }
nr->val.ctype = CTNIL;
nr->val.vval = 0;
break;
diff -r 060e01f01f04 -r 3a6d388a8d27 src/cmd/gc/const.c
--- a/src/cmd/gc/const.c Sun Jul 20 13:33:45 2008 -0700
+++ b/src/cmd/gc/const.c Sun Jul 20 20:13:07 2008 -0700
@@ -20,9 +20,13 @@
goto bad1;
case Wlitnil:
- if(isptr[et] || et == TINTER)
- break;
- goto bad1;
+ if(!isptr[et] && et != TINTER)
+ goto bad1;
+ if(isptrto(t, TSTRING)) {
+ n->val.sval = mal(8);
+ n->val.ctype = CTSTR;
+ }
+ break;
case Wlitstr:
if(isptrto(t, TSTRING))
diff -r 060e01f01f04 -r 3a6d388a8d27 src/cmd/gc/go.h
--- a/src/cmd/gc/go.h Sun Jul 20 13:33:45 2008 -0700
+++ b/src/cmd/gc/go.h Sun Jul 20 20:13:07 2008 -0700
@@ -219,7 +219,7 @@
OLIST, OCMP,
OPTR, OARRAY,
ORETURN, OFOR, OIF, OSWITCH, OI2S, OS2I, OI2I,
- OAS, OASOP, OCASE, OXCASE, OFALL, OXFALL,
+ OAS, OASOP, OCASE, OXCASE, OFALL, OXFALL, OSELECT,
OGOTO, OPROC, ONEW, OPANIC, OPRINT, OEMPTY,
OOROR,
diff -r 060e01f01f04 -r 3a6d388a8d27 src/cmd/gc/go.y
--- a/src/cmd/gc/go.y Sun Jul 20 13:33:45 2008 -0700
+++ b/src/cmd/gc/go.y Sun Jul 20 20:13:07 2008 -0700
@@ -18,7 +18,7 @@
%token LMAP LCHAN LINTERFACE LFUNC LSTRUCT
%token LCOLAS LFALL LRETURN
%token LNEW LLEN
-%token LVAR LTYPE LCONST LCONVERT
+%token LVAR LTYPE LCONST LCONVERT LSELECT
%token LFOR LIF LELSE LSWITCH LCASE LDEFAULT
%token LBREAK LCONTINUE LGO LGOTO LRANGE
%token LOROR LANDAND LEQ LNE LLE LLT LGE LGT
@@ -37,7 +37,7 @@
%type <node> Astmt Bstmt Cstmt Dstmt
%type <node> for_stmt for_body for_header
%type <node> if_stmt if_body if_header
-%type <node> range_header range_body range_stmt
+%type <node> range_header range_body range_stmt select_stmt
%type <node> simple_stmt osimple_stmt semi_stmt
%type <node> expr uexpr pexpr expr_list oexpr oexpr_list expr_list_r
%type <node> name name_name new_name new_name_list_r conexpr
@@ -360,6 +360,11 @@
//if($$->ninit != N && $$->ntest == N)
// yyerror("if conditional should not be missing");
}
+| LSELECT select_stmt
+ {
+ popdcl();
+ $$ = $2;
+ }
| LRANGE range_stmt
{
popdcl();
@@ -529,6 +534,15 @@
$$ = $2;
}
+select_stmt:
+ {
+ markdcl();
+ }
+ compound_stmt
+ {
+ $$ = nod(OSELECT, $2, N);
+ }
+
/*
* expressions
*/
diff -r 060e01f01f04 -r 3a6d388a8d27 src/cmd/gc/lex.c
--- a/src/cmd/gc/lex.c Sun Jul 20 13:33:45 2008 -0700
+++ b/src/cmd/gc/lex.c Sun Jul 20 20:13:07 2008 -0700
@@ -962,20 +962,20 @@
"string", LBASETYPE, TSTRING,
"any", LBASETYPE, TANY,
+ "sys", LPACK, Txxx,
/* keywords */
-// "any", LANY, Txxx,
"break", LBREAK, Txxx,
"case", LCASE, Txxx,
"chan", LCHAN, Txxx,
"const", LCONST, Txxx,
"continue", LCONTINUE, Txxx,
- "convert", LCONVERT, Txxx,
+ "convert", LCONVERT, Txxx, // should be a var
"default", LDEFAULT, Txxx,
"else", LELSE, Txxx,
"export", LEXPORT, Txxx,
"fallthrough", LFALL, Txxx,
- "false", LFALSE, Txxx,
+ "false", LFALSE, Txxx, // should be a var
"for", LFOR, Txxx,
"func", LFUNC, Txxx,
"go", LGO, Txxx,
@@ -985,20 +985,20 @@
"interface", LINTERFACE, Txxx,
"iota", LIOTA, Txxx,
"map", LMAP, Txxx,
- "new", LNEW, Txxx,
- "len", LLEN, Txxx,
- "nil", LNIL, Txxx,
+ "new", LNEW, Txxx, // should be a var
+ "len", LLEN, Txxx, // should be a var
+ "nil", LNIL, Txxx, // should be a var
"package", LPACKAGE, Txxx,
- "panic", LPANIC, Txxx,
- "print", LPRINT, Txxx,
+ "panic", LPANIC, Txxx, // temp
+ "print", LPRINT, Txxx, // temp
"range", LRANGE, Txxx,
"return", LRETURN, Txxx,
+ "select", LSELECT, Txxx,
"struct", LSTRUCT, Txxx,
"switch", LSWITCH, Txxx,
- "true", LTRUE, Txxx,
+ "true", LTRUE, Txxx, // should be a var
"type", LTYPE, Txxx,
"var", LVAR, Txxx,
- "sys", LPACK, Txxx,
"notwithstanding", LIGNORE, Txxx,
"thetruthofthematter", LIGNORE, Txxx,
diff -r 060e01f01f04 -r 3a6d388a8d27 src/cmd/gc/subr.c
--- a/src/cmd/gc/subr.c Sun Jul 20 13:33:45 2008 -0700
+++ b/src/cmd/gc/subr.c Sun Jul 20 20:13:07 2008 -0700
@@ -659,6 +659,7 @@
[OI2I] = "I2I",
[OSLICE] = "SLICE",
[OSUB] = "SUB",
+ [OSELECT] = "SELECT",
[OSWITCH] = "SWITCH",
[OTYPE] = "TYPE",
[OVAR] = "VAR",
diff -r 060e01f01f04 -r 3a6d388a8d27 src/runtime/chan.c
--- a/src/runtime/chan.c Sun Jul 20 13:33:45 2008 -0700
+++ b/src/runtime/chan.c Sun Jul 20 20:13:07 2008 -0700
@@ -8,6 +8,21 @@
typedef struct Hchan Hchan;
typedef struct Link Link;
+typedef struct WaitQ WaitQ;
+typedef struct SudoG SudoG;
+
+struct SudoG
+{
+ G* g; // g and selgen constitute
+ int64 selgen; // a weak pointer to g
+ SudoG* link;
+};
+
+struct WaitQ
+{
+ SudoG* first;
+ SudoG* last;
+};
struct Hchan
{
@@ -21,6 +36,7 @@
Link* recvdataq; // pointer for receiver
WaitQ recvq; // list of recv waiters
WaitQ sendq; // list of send waiters
+ SudoG* free; // freelist
};
struct Link
@@ -29,6 +45,11 @@
byte elem[8];
};
+static SudoG* dequeue(WaitQ*, Hchan*);
+static void enqueue(WaitQ*, SudoG*);
+static SudoG* allocsg(Hchan*);
+static void freesg(Hchan*, SudoG*);
+
// newchan(elemsize uint32, elemalg uint32, hint uint32) (hchan *chan any);
void
sys·newchan(uint32 elemsize, uint32 elemalg, uint32 hint,
@@ -97,7 +118,8 @@
sys·chansend1(Hchan* c, ...)
{
byte *ae;
- G *gr;
+ SudoG *sgr;
+ G* gr;
ae = (byte*)&c + c->eo;
if(debug) {
@@ -110,30 +132,39 @@
if(c->dataqsiz > 0)
goto asynch;
- gr = dequeue(&c->recvq);
- if(gr != nil) {
+ sgr = dequeue(&c->recvq, c);
+ if(sgr != nil) {
+ gr = sgr->g;
+ freesg(c, sgr);
+
c->elemalg->copy(c->elemsize, gr->elem, ae);
gr->status = Grunnable;
return;
}
+
c->elemalg->copy(c->elemsize, g->elem, ae);
+ sgr = allocsg(c);
g->status = Gwaiting;
- enqueue(&c->sendq, g);
+ enqueue(&c->sendq, sgr);
sys·gosched();
return;
asynch:
while(c->qcount >= c->dataqsiz) {
+ sgr = allocsg(c);
g->status = Gwaiting;
- enqueue(&c->sendq, g);
+ enqueue(&c->sendq, sgr);
sys·gosched();
}
c->elemalg->copy(c->elemsize, c->senddataq->elem, ae);
c->senddataq = c->senddataq->link;
c->qcount++;
- gr = dequeue(&c->recvq);
- if(gr != nil)
+ sgr = dequeue(&c->recvq, c);
+ if(sgr != nil) {
+ gr = sgr->g;
+ freesg(c, sgr);
gr->status = Grunnable;
+ }
}
// chansend2(hchan *chan any, elem any) (pres bool);
@@ -141,6 +172,7 @@
sys·chansend2(Hchan* c, ...)
{
byte *ae, *ap;
+ SudoG *sgr;
G *gr;
ae = (byte*)&c + c->eo;
@@ -156,8 +188,11 @@
if(c->dataqsiz > 0)
goto asynch;
- gr = dequeue(&c->recvq);
- if(gr != nil) {
+ sgr = dequeue(&c->recvq, c);
+ if(sgr != nil) {
+ gr = sgr->g;
+ freesg(c, sgr);
+
c->elemalg->copy(c->elemsize, gr->elem, ae);
gr->status = Grunnable;
*ap = true;
@@ -174,9 +209,12 @@
c->elemalg->copy(c->elemsize, c->senddataq->elem, ae);
c->senddataq = c->senddataq->link;
c->qcount++;
- gr = dequeue(&c->recvq);
- if(gr != nil)
+ sgr = dequeue(&c->recvq, c);
+ if(gr != nil) {
+ gr = sgr->g;
+ freesg(c, sgr);
gr->status = Grunnable;
+ }
*ap = true;
}
@@ -185,6 +223,7 @@
sys·chanrecv1(Hchan* c, ...)
{
byte *ae;
+ SudoG *sgs;
G *gs;
ae = (byte*)&c + c->eo;
@@ -196,30 +235,39 @@
if(c->dataqsiz > 0)
goto asynch;
- gs = dequeue(&c->sendq);
- if(gs != nil) {
+ sgs = dequeue(&c->sendq, c);
+ if(sgs != nil) {
+ gs = sgs->g;
+ freesg(c, sgs);
+
c->elemalg->copy(c->elemsize, ae, gs->elem);
gs->status = Grunnable;
return;
}
+ sgs = allocsg(c);
g->status = Gwaiting;
- enqueue(&c->recvq, g);
+ enqueue(&c->recvq, sgs);
sys·gosched();
c->elemalg->copy(c->elemsize, ae, g->elem);
return;
asynch:
while(c->qcount <= 0) {
+ sgs = allocsg(c);
g->status = Gwaiting;
- enqueue(&c->recvq, g);
+ enqueue(&c->recvq, sgs);
sys·gosched();
}
c->elemalg->copy(c->elemsize, ae, c->recvdataq->elem);
c->recvdataq = c->recvdataq->link;
c->qcount--;
- gs = dequeue(&c->sendq);
- if(gs != nil)
+ sgs = dequeue(&c->sendq, c);
+ if(gs != nil) {
+ gs = sgs->g;
+ freesg(c, sgs);
+
gs->status = Grunnable;
+ }
}
// chanrecv2(hchan *chan any) (elem any, pres bool);
@@ -227,6 +275,7 @@
sys·chanrecv2(Hchan* c, ...)
{
byte *ae, *ap;
+ SudoG *sgs;
G *gs;
ae = (byte*)&c + c->eo;
@@ -240,8 +289,11 @@
if(c->dataqsiz > 0)
goto asynch;
- gs = dequeue(&c->sendq);
- if(gs != nil) {
+ sgs = dequeue(&c->sendq, c);
+ if(sgs != nil) {
+ gs = sgs->g;
+ freesg(c, sgs);
+
c->elemalg->copy(c->elemsize, ae, gs->elem);
gs->status = Grunnable;
*ap = true;
@@ -258,8 +310,70 @@
c->elemalg->copy(c->elemsize, ae, c->recvdataq->elem);
c->recvdataq = c->recvdataq->link;
c->qcount--;
- gs = dequeue(&c->sendq);
- if(gs != nil)
+ sgs = dequeue(&c->sendq, c);
+ if(sgs != nil) {
+ gs = sgs->g;
+ freesg(c, sgs);
+
gs->status = Grunnable;
+ }
*ap = true;
}
+
+static SudoG*
+dequeue(WaitQ *q, Hchan *c)
+{
+ SudoG *sgp;
+
+loop:
+ sgp = q->first;
+ if(sgp == nil)
+ return nil;
+ q->first = sgp->link;
+
+ // if sgp is stale, ignore it
+ if(sgp->selgen != sgp->g->selgen) {
+prints("INVALID PSEUDOG POINTER\n");
+ freesg(c, sgp);
+ goto loop;
+ }
+
+ // invalidate any others
+ sgp->g->selgen++;
+ return sgp;
+}
+
+static void
+enqueue(WaitQ *q, SudoG *sgp)
+{
+ sgp->link = nil;
+ if(q->first == nil) {
+ q->first = sgp;
+ q->last = sgp;
+ return;
+ }
+ q->last->link = sgp;
+ q->last = sgp;
+}
+
+static SudoG*
+allocsg(Hchan *c)
+{
+ SudoG* sg;
+
+ sg = c->free;
+ if(sg != nil) {
+ c->free = sg->link;
+ } else
+ sg = mal(sizeof(*sg));
+ sg->selgen = g->selgen;
+ sg->g = g;
+ return sg;
+}
+
+static void
+freesg(Hchan *c, SudoG *sg)
+{
+ sg->link = c->free;
+ c->free = sg;
+}
diff -r 060e01f01f04 -r 3a6d388a8d27 src/runtime/proc.c
--- a/src/runtime/proc.c Sun Jul 20 13:33:45 2008 -0700
+++ b/src/runtime/proc.c Sun Jul 20 20:13:07 2008 -0700
@@ -254,28 +254,3 @@
*(int32*)234 = 123; // never return
}
-
-G*
-dequeue(WaitQ *q)
-{
- G *gp;
-
- gp = q->first;
- if(gp == nil)
- return nil;
- q->first = gp->qlink;
- return gp;
-}
-
-void
-enqueue(WaitQ *q, G *gp)
-{
- gp->qlink = nil;
- if(q->first == nil) {
- q->first = gp;
- q->last = gp;
- return;
- }
- q->last->qlink = gp;
- q->last = gp;
-}
diff -r 060e01f01f04 -r 3a6d388a8d27 src/runtime/runtime.h
--- a/src/runtime/runtime.h Sun Jul 20 13:33:45 2008 -0700
+++ b/src/runtime/runtime.h Sun Jul 20 20:13:07 2008 -0700
@@ -42,7 +42,6 @@
typedef struct M M;
typedef struct Stktop Stktop;
typedef struct Alg Alg;
-typedef struct WaitQ WaitQ;
/*
* per cpu declaration
@@ -108,9 +107,9 @@
byte* stack0; // first stack segment
Gobuf sched;
G* alllink; // on allq
- G* qlink; // on wait q
int32 status;
int32 goid;
+ int64 selgen; // valid sudog pointer
byte elem[8]; // transfer element for chan
};
struct M
@@ -126,11 +125,6 @@
int32 siz1;
int32 siz2;
};
-struct WaitQ
-{
- G* first;
- G* last;
-};
struct Stktop
{
uint8* oldbase;
@@ -176,8 +170,6 @@
void dump(byte*, int32);
int32 runetochar(byte*, int32);
int32 chartorune(uint32*, byte*);
-G* dequeue(WaitQ*);
-void enqueue(WaitQ*, G*);
/*
* very low level c-called
diff -r 060e01f01f04 -r 3a6d388a8d27 test/chan/powser1.go
--- a/test/chan/powser1.go Sun Jul 20 13:33:45 2008 -0700
+++ b/test/chan/powser1.go Sun Jul 20 20:13:07 2008 -0700
@@ -233,24 +233,6 @@
var Ones PS
var Twos PS
-// print eval in floating point of PS at x=c to n terms
-func
-Evaln(c *rat, U PS, n int)
-{
- xn := float64(1);
- x := float64(c.num)/float64(c.den);
- val := float64(0);
- for i:=0; i<n; i++ {
- u := get(U);
- if end(u) != 0 {
- break;
- }
- val = val + x * float64(u.num)/float64(u.den);
- xn = xn*x;
- }
- print val, "\n";
-}
-
func mkPS() *dch {
return mkdch()
}
@@ -335,8 +317,25 @@
return i2tor(u.den, u.num);
}
+// print eval in floating point of PS at x=c to n terms
+func
+Evaln(c *rat, U PS, n int)
+{
+ xn := float64(1);
+ x := float64(c.num)/float64(c.den);
+ val := float64(0);
+ for i:=0; i<n; i++ {
+ u := get(U);
+ if end(u) != 0 {
+ break;
+ }
+ val = val + x * float64(u.num)/float64(u.den);
+ xn = xn*x;
+ }
+ print val, "\n";
+}
+
// Print n terms of a power series
-
func Printn(U PS, n int){
done := false;
for ; !done && n>0; n-- {
@@ -352,7 +351,6 @@
}
// Evaluate n terms of power series U at x=c
-
func eval(c *rat, U PS, n int) *rat{
if n==0 { return zero }
y := get(U);
changeset: 417:50e7bca25907
user: Ken Thompson <[email protected]>
date: Thu Jul 24 15:57:30 2008 -0700
summary: select
diff -r 4bd3dc3df3e4 -r 50e7bca25907 src/cmd/6g/gen.c
--- a/src/cmd/6g/gen.c Thu Jul 24 13:36:18 2008 -0700
+++ b/src/cmd/6g/gen.c Thu Jul 24 15:57:30 2008 -0700
@@ -255,6 +255,17 @@
breakpc = sbreak;
break;
+ case OSELECT:
+ gen(n->ninit);
+ sbreak = breakpc;
+ p1 = gbranch(AJMP, T); // goto test
+ breakpc = gbranch(AJMP, T); // break: goto done
+ patch(p1, pc); // test:
+ gen(n->nbody); // select() body
+ patch(breakpc, pc); // done:
+ breakpc = sbreak;
+ break;
+
case OASOP:
cgen_asop(n);
break;
diff -r 4bd3dc3df3e4 -r 50e7bca25907 src/cmd/6g/gg.h
--- a/src/cmd/6g/gg.h Thu Jul 24 13:36:18 2008 -0700
+++ b/src/cmd/6g/gg.h Thu Jul 24 15:57:30 2008 -0700
@@ -107,6 +107,7 @@
void proglist(void);
void gen(Node*);
void swgen(Node*);
+void selgen(Node*);
Node* lookdot(Node*, Node*, int);
void inarggen(void);
void agen_inter(Node*, Node*);
diff -r 4bd3dc3df3e4 -r 50e7bca25907 src/cmd/gc/go.h
--- a/src/cmd/gc/go.h Thu Jul 24 13:36:18 2008 -0700
+++ b/src/cmd/gc/go.h Thu Jul 24 15:57:30 2008 -0700
@@ -219,8 +219,8 @@
OLIST, OCMP,
OPTR, OARRAY,
ORETURN, OFOR, OIF, OSWITCH, OI2S, OS2I, OI2I,
- OAS, OASOP, OCASE, OXCASE, OFALL, OXFALL, OSELECT,
- OGOTO, OPROC, ONEW, OPANIC, OPRINT, OEMPTY,
+ OAS, OASOP, OCASE, OXCASE, OSCASE, OFALL, OXFALL,
+ OGOTO, OPROC, ONEW, OPANIC, OPRINT, OEMPTY, OSELECT,
OOROR,
OANDAND,
@@ -575,6 +575,7 @@
void walkbool(Node*);
Type* walkswitch(Node*, Type*(*)(Node*, Type*));
int casebody(Node*);
+void walkselect(Node*);
int whatis(Node*);
void walkdot(Node*, int);
Node* ascompatee(int, Node**, Node**);
@@ -585,7 +586,9 @@
Node* nodpanic(long);
Node* newcompat(Node*);
Node* stringop(Node*, int);
+Type* fixmap(Type*);
Node* mapop(Node*, int);
+Type* fixchan(Type*);
Node* chanop(Node*, int);
Node* convas(Node*);
void arrayconv(Type*, Node*);
diff -r 4bd3dc3df3e4 -r 50e7bca25907 src/cmd/gc/go.y
--- a/src/cmd/gc/go.y Thu Jul 24 13:36:18 2008 -0700
+++ b/src/cmd/gc/go.y Thu Jul 24 15:57:30 2008 -0700
@@ -338,8 +338,6 @@
| LSWITCH if_stmt
{
popdcl();
- if(!casebody($2->nbody))
- yyerror("switch statement must have case labels");
$$ = $2;
$$->op = OSWITCH;
//if($$->ninit != N && $$->ntest == N)
diff -r 4bd3dc3df3e4 -r 50e7bca25907 src/cmd/gc/mksys.bash
--- a/src/cmd/gc/mksys.bash Thu Jul 24 13:36:18 2008 -0700
+++ b/src/cmd/gc/mksys.bash Thu Jul 24 15:57:30 2008 -0700
@@ -7,6 +7,7 @@
6g sys.go
echo '1,/((/d
/))/+1,$d
+g/init_.*_function/d
1,$s/foop/sys/g
1,$s/^[ ]*/ "/g
1,$s/$/\\n"/g
diff -r 4bd3dc3df3e4 -r 50e7bca25907 src/cmd/gc/subr.c
--- a/src/cmd/gc/subr.c Thu Jul 24 13:36:18 2008 -0700
+++ b/src/cmd/gc/subr.c Thu Jul 24 15:57:30 2008 -0700
@@ -603,6 +603,7 @@
[OCALLINTER] = "CALLINTER",
[OCASE] = "CASE",
[OXCASE] = "XCASE",
+ [OSCASE] = "SCASE",
[OCMP] = "CMP",
[OFALL] = "FALL",
[OCONV] = "CONV",
diff -r 4bd3dc3df3e4 -r 50e7bca25907 src/cmd/gc/sys.go
--- a/src/cmd/gc/sys.go Thu Jul 24 13:36:18 2008 -0700
+++ b/src/cmd/gc/sys.go Thu Jul 24 15:57:30 2008 -0700
@@ -51,6 +51,11 @@
func chansend1(hchan *chan any, elem any);
func chansend2(hchan *chan any, elem any) (pres bool);
+func newselect(size uint32) (sel *byte);
+func selectsend(sel *byte, hchan *chan any, elem any) (selected bool);
+func selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
+func selectgo(sel *byte);
+
func gosched();
func goexit();
@@ -112,6 +117,12 @@
chansend1
chansend2
+ // select
+ newselect
+ selectsend
+ selectrecv
+ selectgo
+
// go routines
gosched
goexit
diff -r 4bd3dc3df3e4 -r 50e7bca25907 src/cmd/gc/sysimport.c
--- a/src/cmd/gc/sysimport.c Thu Jul 24 13:36:18 2008 -0700
+++ b/src/cmd/gc/sysimport.c Thu Jul 24 15:57:30 2008 -0700
@@ -3,10 +3,10 @@
"type sys._esys_002 {}\n"
"type sys.any 24\n"
"type sys._esys_003 *sys.any\n"
- "type sys._osys_332 {_esys_330 sys._esys_003}\n"
+ "type sys._osys_361 {_esys_359 sys._esys_003}\n"
"type sys.uint32 6\n"
- "type sys._isys_334 {_esys_331 sys.uint32}\n"
- "type sys._esys_001 (sys._esys_002 sys._osys_332 sys._isys_334)\n"
+ "type sys._isys_363 {_esys_360 sys.uint32}\n"
+ "type sys._esys_001 (sys._esys_002 sys._osys_361 sys._isys_363)\n"
"var !sys.mal sys._esys_001\n"
"type sys._esys_005 {}\n"
"type sys._esys_006 {}\n"
@@ -16,249 +16,282 @@
"type sys._esys_009 {}\n"
"type sys._esys_010 {}\n"
"type sys.int32 5\n"
- "type sys._isys_340 {_esys_339 sys.int32}\n"
- "type sys._esys_008 (sys._esys_009 sys._esys_010 sys._isys_340)\n"
+ "type sys._isys_369 {_esys_368 sys.int32}\n"
+ "type sys._esys_008 (sys._esys_009 sys._esys_010 sys._isys_369)\n"
"var !sys.panicl sys._esys_008\n"
"type sys._esys_012 {}\n"
"type sys._esys_013 {}\n"
"type sys.bool 12\n"
- "type sys._isys_345 {_esys_344 sys.bool}\n"
- "type sys._esys_011 (sys._esys_012 sys._esys_013 sys._isys_345)\n"
+ "type sys._isys_374 {_esys_373 sys.bool}\n"
+ "type sys._esys_011 (sys._esys_012 sys._esys_013 sys._isys_374)\n"
"var !sys.printbool sys._esys_011\n"
"type sys._esys_015 {}\n"
"type sys._esys_016 {}\n"
"type sys.float64 10\n"
- "type sys._isys_350 {_esys_349 sys.float64}\n"
- "type sys._esys_014 (sys._esys_015 sys._esys_016 sys._isys_350)\n"
+ "type sys._isys_379 {_esys_378 sys.float64}\n"
+ "type sys._esys_014 (sys._esys_015 sys._esys_016 sys._isys_379)\n"
"var !sys.printfloat sys._esys_014\n"
"type sys._esys_018 {}\n"
"type sys._esys_019 {}\n"
"type sys.int64 7\n"
- "type sys._isys_355 {_esys_354 sys.int64}\n"
- "type sys._esys_017 (sys._esys_018 sys._esys_019 sys._isys_355)\n"
+ "type sys._isys_384 {_esys_383 sys.int64}\n"
+ "type sys._esys_017 (sys._esys_018 sys._esys_019 sys._isys_384)\n"
"var !sys.printint sys._esys_017\n"
"type sys._esys_021 {}\n"
"type sys._esys_022 {}\n"
"type sys._esys_023 25\n"
"type sys.string *sys._esys_023\n"
- "type sys._isys_360 {_esys_359 sys.string}\n"
- "type sys._esys_020 (sys._esys_021 sys._esys_022 sys._isys_360)\n"
+ "type sys._isys_389 {_esys_388 sys.string}\n"
+ "type sys._esys_020 (sys._esys_021 sys._esys_022 sys._isys_389)\n"
"var !sys.printstring sys._esys_020\n"
"type sys._esys_025 {}\n"
"type sys._esys_026 {}\n"
"type sys._esys_027 *sys.any\n"
- "type sys._isys_365 {_esys_364 sys._esys_027}\n"
- "type sys._esys_024 (sys._esys_025 sys._esys_026 sys._isys_365)\n"
+ "type sys._isys_394 {_esys_393 sys._esys_027}\n"
+ "type sys._esys_024 (sys._esys_025 sys._esys_026 sys._isys_394)\n"
"var !sys.printpointer sys._esys_024\n"
"type sys._esys_029 {}\n"
- "type sys._osys_372 {_esys_369 sys.string}\n"
- "type sys._isys_374 {_esys_370 sys.string _esys_371 sys.string}\n"
- "type sys._esys_028 (sys._esys_029 sys._osys_372 sys._isys_374)\n"
+ "type sys._osys_401 {_esys_398 sys.string}\n"
+ "type sys._isys_403 {_esys_399 sys.string _esys_400 sys.string}\n"
+ "type sys._esys_028 (sys._esys_029 sys._osys_401 sys._isys_403)\n"
"var !sys.catstring sys._esys_028\n"
"type sys._esys_031 {}\n"
- "type sys._osys_382 {_esys_379 sys.int32}\n"
- "type sys._isys_384 {_esys_380 sys.string _esys_381 sys.string}\n"
- "type sys._esys_030 (sys._esys_031 sys._osys_382 sys._isys_384)\n"
+ "type sys._osys_411 {_esys_408 sys.int32}\n"
+ "type sys._isys_413 {_esys_409 sys.string _esys_410 sys.string}\n"
+ "type sys._esys_030 (sys._esys_031 sys._osys_411 sys._isys_413)\n"
"var !sys.cmpstring sys._esys_030\n"
"type sys._esys_033 {}\n"
- "type sys._osys_393 {_esys_389 sys.string}\n"
- "type sys._isys_395 {_esys_390 sys.string _esys_391 sys.int32 _esys_392 sys.int32}\n"
- "type sys._esys_032 (sys._esys_033 sys._osys_393 sys._isys_395)\n"
+ "type sys._osys_422 {_esys_418 sys.string}\n"
+ "type sys._isys_424 {_esys_419 sys.string _esys_420 sys.int32 _esys_421 sys.int32}\n"
+ "type sys._esys_032 (sys._esys_033 sys._osys_422 sys._isys_424)\n"
"var !sys.slicestring sys._esys_032\n"
"type sys._esys_035 {}\n"
"type sys.uint8 2\n"
- "type sys._osys_404 {_esys_401 sys.uint8}\n"
- "type sys._isys_406 {_esys_402 sys.string _esys_403 sys.int32}\n"
- "type sys._esys_034 (sys._esys_035 sys._osys_404 sys._isys_406)\n"
+ "type sys._osys_433 {_esys_430 sys.uint8}\n"
+ "type sys._isys_435 {_esys_431 sys.string _esys_432 sys.int32}\n"
+ "type sys._esys_034 (sys._esys_035 sys._osys_433 sys._isys_435)\n"
"var !sys.indexstring sys._esys_034\n"
"type sys._esys_037 {}\n"
- "type sys._osys_413 {_esys_411 sys.string}\n"
- "type sys._isys_415 {_esys_412 sys.int64}\n"
- "type sys._esys_036 (sys._esys_037 sys._osys_413 sys._isys_415)\n"
+ "type sys._osys_442 {_esys_440 sys.string}\n"
+ "type sys._isys_444 {_esys_441 sys.int64}\n"
+ "type sys._esys_036 (sys._esys_037 sys._osys_442 sys._isys_444)\n"
"var !sys.intstring sys._esys_036\n"
"type sys._esys_039 {}\n"
- "type sys._osys_422 {_esys_419 sys.string}\n"
+ "type sys._osys_451 {_esys_448 sys.string}\n"
"type sys._esys_040 *sys.uint8\n"
- "type sys._isys_424 {_esys_420 sys._esys_040 _esys_421 sys.int32}\n"
- "type sys._esys_038 (sys._esys_039 sys._osys_422 sys._isys_424)\n"
+ "type sys._isys_453 {_esys_449 sys._esys_040 _esys_450 sys.int32}\n"
+ "type sys._esys_038 (sys._esys_039 sys._osys_451 sys._isys_453)\n"
"var !sys.byteastring sys._esys_038\n"
"type sys._esys_042 {}\n"
"type sys._esys_043 <>\n"
- "type sys._osys_433 {_esys_429 sys._esys_043}\n"
+ "type sys._osys_462 {_esys_458 sys._esys_043}\n"
"type sys._esys_044 *sys.uint8\n"
"type sys._esys_045 *sys.uint8\n"
- "type sys._ssys_440 {}\n"
- "type sys._esys_046 *sys._ssys_440\n"
- "type sys._isys_435 {_esys_430 sys._esys_044 _esys_431 sys._esys_045 _esys_432 sys._esys_046}\n"
- "type sys._esys_041 (sys._esys_042 sys._osys_433 sys._isys_435)\n"
+ "type sys._ssys_469 {}\n"
+ "type sys._esys_046 *sys._ssys_469\n"
+ "type sys._isys_464 {_esys_459 sys._esys_044 _esys_460 sys._esys_045 _esys_461 sys._esys_046}\n"
+ "type sys._esys_041 (sys._esys_042 sys._osys_462 sys._isys_464)\n"
"var !sys.mkiface sys._esys_041\n"
"type sys._esys_048 {}\n"
- "type sys._osys_444 {_esys_443 sys.int32}\n"
+ "type sys._osys_473 {_esys_472 sys.int32}\n"
"type sys._esys_049 {}\n"
- "type sys._esys_047 (sys._esys_048 sys._osys_444 sys._esys_049)\n"
+ "type sys._esys_047 (sys._esys_048 sys._osys_473 sys._esys_049)\n"
"var !sys.argc sys._esys_047\n"
"type sys._esys_051 {}\n"
- "type sys._osys_448 {_esys_447 sys.int32}\n"
+ "type sys._osys_477 {_esys_476 sys.int32}\n"
"type sys._esys_052 {}\n"
- "type sys._esys_050 (sys._esys_051 sys._osys_448 sys._esys_052)\n"
+ "type sys._esys_050 (sys._esys_051 sys._osys_477 sys._esys_052)\n"
"var !sys.envc sys._esys_050\n"
"type sys._esys_054 {}\n"
- "type sys._osys_453 {_esys_451 sys.string}\n"
- "type sys._isys_455 {_esys_452 sys.int32}\n"
- "type sys._esys_053 (sys._esys_054 sys._osys_453 sys._isys_455)\n"
+ "type sys._osys_482 {_esys_480 sys.string}\n"
+ "type sys._isys_484 {_esys_481 sys.int32}\n"
+ "type sys._esys_053 (sys._esys_054 sys._osys_482 sys._isys_484)\n"
"var !sys.argv sys._esys_053\n"
"type sys._esys_056 {}\n"
- "type sys._osys_461 {_esys_459 sys.string}\n"
- "type sys._isys_463 {_esys_460 sys.int32}\n"
- "type sys._esys_055 (sys._esys_056 sys._osys_461 sys._isys_463)\n"
+ "type sys._osys_490 {_esys_488 sys.string}\n"
+ "type sys._isys_492 {_esys_489 sys.int32}\n"
+ "type sys._esys_055 (sys._esys_056 sys._osys_490 sys._isys_492)\n"
"var !sys.envv sys._esys_055\n"
"type sys._esys_058 {}\n"
- "type sys._osys_470 {_esys_467 sys.float64 _esys_468 sys.int32}\n"
- "type sys._isys_472 {_esys_469 sys.float64}\n"
- "type sys._esys_057 (sys._esys_058 sys._osys_470 sys._isys_472)\n"
+ "type sys._osys_499 {_esys_496 sys.float64 _esys_497 sys.int32}\n"
+ "type sys._isys_501 {_esys_498 sys.float64}\n"
+ "type sys._esys_057 (sys._esys_058 sys._osys_499 sys._isys_501)\n"
"var !sys.frexp sys._esys_057\n"
"type sys._esys_060 {}\n"
- "type sys._osys_479 {_esys_476 sys.float64}\n"
- "type sys._isys_481 {_esys_477 sys.float64 _esys_478 sys.int32}\n"
- "type sys._esys_059 (sys._esys_060 sys._osys_479 sys._isys_481)\n"
+ "type sys._osys_508 {_esys_505 sys.float64}\n"
+ "type sys._isys_510 {_esys_506 sys.float64 _esys_507 sys.int32}\n"
+ "type sys._esys_059 (sys._esys_060 sys._osys_508 sys._isys_510)\n"
"var !sys.ldexp sys._esys_059\n"
"type sys._esys_062 {}\n"
- "type sys._osys_489 {_esys_486 sys.float64 _esys_487 sys.float64}\n"
- "type sys._isys_491 {_esys_488 sys.float64}\n"
- "type sys._esys_061 (sys._esys_062 sys._osys_489 sys._isys_491)\n"
+ "type sys._osys_518 {_esys_515 sys.float64 _esys_516 sys.float64}\n"
+ "type sys._isys_520 {_esys_517 sys.float64}\n"
+ "type sys._esys_061 (sys._esys_062 sys._osys_518 sys._isys_520)\n"
"var !sys.modf sys._esys_061\n"
"type sys._esys_064 {}\n"
- "type sys._osys_498 {_esys_495 sys.bool}\n"
- "type sys._isys_500 {_esys_496 sys.float64 _esys_497 sys.int32}\n"
- "type sys._esys_063 (sys._esys_064 sys._osys_498 sys._isys_500)\n"
+ "type sys._osys_527 {_esys_524 sys.bool}\n"
+ "type sys._isys_529 {_esys_525 sys.float64 _esys_526 sys.int32}\n"
+ "type sys._esys_063 (sys._esys_064 sys._osys_527 sys._isys_529)\n"
"var !sys.isInf sys._esys_063\n"
"type sys._esys_066 {}\n"
- "type sys._osys_507 {_esys_505 sys.bool}\n"
- "type sys._isys_509 {_esys_506 sys.float64}\n"
- "type sys._esys_065 (sys._esys_066 sys._osys_507 sys._isys_509)\n"
+ "type sys._osys_536 {_esys_534 sys.bool}\n"
+ "type sys._isys_538 {_esys_535 sys.float64}\n"
+ "type sys._esys_065 (sys._esys_066 sys._osys_536 sys._isys_538)\n"
"var !sys.isNaN sys._esys_065\n"
"type sys._esys_068 {}\n"
- "type sys._osys_515 {_esys_513 sys.float64}\n"
- "type sys._isys_517 {_esys_514 sys.int32}\n"
- "type sys._esys_067 (sys._esys_068 sys._osys_515 sys._isys_517)\n"
+ "type sys._osys_544 {_esys_542 sys.float64}\n"
+ "type sys._isys_546 {_esys_543 sys.int32}\n"
+ "type sys._esys_067 (sys._esys_068 sys._osys_544 sys._isys_546)\n"
"var !sys.Inf sys._esys_067\n"
"type sys._esys_070 {}\n"
- "type sys._osys_522 {_esys_521 sys.float64}\n"
+ "type sys._osys_551 {_esys_550 sys.float64}\n"
"type sys._esys_071 {}\n"
- "type sys._esys_069 (sys._esys_070 sys._osys_522 sys._esys_071)\n"
+ "type sys._esys_069 (sys._esys_070 sys._osys_551 sys._esys_071)\n"
"var !sys.NaN sys._esys_069\n"
"type sys._esys_073 {}\n"
"type sys._esys_075 [sys.any] sys.any\n"
"type sys._esys_074 *sys._esys_075\n"
- "type sys._osys_525 {hmap sys._esys_074}\n"
- "type sys._isys_527 {keysize sys.uint32 valsize sys.uint32 keyalg sys.uint32 valalg sys.uint32 hint sys.uint32}\n"
- "type sys._esys_072 (sys._esys_073 sys._osys_525 sys._isys_527)\n"
+ "type sys._osys_554 {hmap sys._esys_074}\n"
+ "type sys._isys_556 {keysize sys.uint32 valsize sys.uint32 keyalg sys.uint32 valalg sys.uint32 hint sys.uint32}\n"
+ "type sys._esys_072 (sys._esys_073 sys._osys_554 sys._isys_556)\n"
"var !sys.newmap sys._esys_072\n"
"type sys._esys_077 {}\n"
- "type sys._osys_536 {val sys.any}\n"
+ "type sys._osys_565 {val sys.any}\n"
"type sys._esys_079 [sys.any] sys.any\n"
"type sys._esys_078 *sys._esys_079\n"
- "type sys._isys_538 {hmap sys._esys_078 key sys.any}\n"
- "type sys._esys_076 (sys._esys_077 sys._osys_536 sys._isys_538)\n"
+ "type sys._isys_567 {hmap sys._esys_078 key sys.any}\n"
+ "type sys._esys_076 (sys._esys_077 sys._osys_565 sys._isys_567)\n"
"var !sys.mapaccess1 sys._esys_076\n"
"type sys._esys_081 {}\n"
- "type sys._osys_544 {val sys.any pres sys.bool}\n"
+ "type sys._osys_573 {val sys.any pres sys.bool}\n"
"type sys._esys_083 [sys.any] sys.any\n"
"type sys._esys_082 *sys._esys_083\n"
- "type sys._isys_546 {hmap sys._esys_082 key sys.any}\n"
- "type sys._esys_080 (sys._esys_081 sys._osys_544 sys._isys_546)\n"
+ "type sys._isys_575 {hmap sys._esys_082 key sys.any}\n"
+ "type sys._esys_080 (sys._esys_081 sys._osys_573 sys._isys_575)\n"
"var !sys.mapaccess2 sys._esys_080\n"
"type sys._esys_085 {}\n"
"type sys._esys_086 {}\n"
"type sys._esys_088 [sys.any] sys.any\n"
"type sys._esys_087 *sys._esys_088\n"
- "type sys._isys_553 {hmap sys._esys_087 key sys.any val sys.any}\n"
- "type sys._esys_084 (sys._esys_085 sys._esys_086 sys._isys_553)\n"
+ "type sys._isys_582 {hmap sys._esys_087 key sys.any val sys.any}\n"
+ "type sys._esys_084 (sys._esys_085 sys._esys_086 sys._isys_582)\n"
"var !sys.mapassign1 sys._esys_084\n"
"type sys._esys_090 {}\n"
"type sys._esys_091 {}\n"
"type sys._esys_093 [sys.any] sys.any\n"
"type sys._esys_092 *sys._esys_093\n"
- "type sys._isys_559 {hmap sys._esys_092 key sys.any val sys.any pres sys.bool}\n"
- "type sys._esys_089 (sys._esys_090 sys._esys_091 sys._isys_559)\n"
+ "type sys._isys_588 {hmap sys._esys_092 key sys.any val sys.any pres sys.bool}\n"
+ "type sys._esys_089 (sys._esys_090 sys._esys_091 sys._isys_588)\n"
"var !sys.mapassign2 sys._esys_089\n"
"type sys._esys_095 {}\n"
"type sys._esys_097 1 sys.any\n"
"type sys._esys_096 *sys._esys_097\n"
- "type sys._osys_566 {hchan sys._esys_096}\n"
- "type sys._isys_568 {elemsize sys.uint32 elemalg sys.uint32 hint sys.uint32}\n"
- "type sys._esys_094 (sys._esys_095 sys._osys_566 sys._isys_568)\n"
+ "type sys._osys_595 {hchan sys._esys_096}\n"
+ "type sys._isys_597 {elemsize sys.uint32 elemalg sys.uint32 hint sys.uint32}\n"
+ "type sys._esys_094 (sys._esys_095 sys._osys_595 sys._isys_597)\n"
"var !sys.newchan sys._esys_094\n"
"type sys._esys_099 {}\n"
- "type sys._osys_575 {elem sys.any}\n"
+ "type sys._osys_604 {elem sys.any}\n"
"type sys._esys_101 1 sys.any\n"
"type sys._esys_100 *sys._esys_101\n"
- "type sys._isys_577 {hchan sys._esys_100}\n"
- "type sys._esys_098 (sys._esys_099 sys._osys_575 sys._isys_577)\n"
+ "type sys._isys_606 {hchan sys._esys_100}\n"
+ "type sys._esys_098 (sys._esys_099 sys._osys_604 sys._isys_606)\n"
"var !sys.chanrecv1 sys._esys_098\n"
"type sys._esys_103 {}\n"
- "type sys._osys_582 {elem sys.any pres sys.bool}\n"
+ "type sys._osys_611 {elem sys.any pres sys.bool}\n"
"type sys._esys_105 1 sys.any\n"
"type sys._esys_104 *sys._esys_105\n"
- "type sys._isys_584 {hchan sys._esys_104}\n"
- "type sys._esys_102 (sys._esys_103 sys._osys_582 sys._isys_584)\n"
+ "type sys._isys_613 {hchan sys._esys_104}\n"
+ "type sys._esys_102 (sys._esys_103 sys._osys_611 sys._isys_613)\n"
"var !sys.chanrecv2 sys._esys_102\n"
"type sys._esys_107 {}\n"
- "type sys._osys_590 {elem sys.any pres sys.bool}\n"
+ "type sys._osys_619 {elem sys.any pres sys.bool}\n"
"type sys._esys_109 1 sys.any\n"
"type sys._esys_108 *sys._esys_109\n"
- "type sys._isys_592 {hchan sys._esys_108}\n"
- "type sys._esys_106 (sys._esys_107 sys._osys_590 sys._isys_592)\n"
+ "type sys._isys_621 {hchan sys._esys_108}\n"
+ "type sys._esys_106 (sys._esys_107 sys._osys_619 sys._isys_621)\n"
"var !sys.chanrecv3 sys._esys_106\n"
"type sys._esys_111 {}\n"
"type sys._esys_112 {}\n"
"type sys._esys_114 1 sys.any\n"
"type sys._esys_113 *sys._esys_114\n"
- "type sys._isys_598 {hchan sys._esys_113 elem sys.any}\n"
- "type sys._esys_110 (sys._esys_111 sys._esys_112 sys._isys_598)\n"
+ "type sys._isys_627 {hchan sys._esys_113 elem sys.any}\n"
+ "type sys._esys_110 (sys._esys_111 sys._esys_112 sys._isys_627)\n"
"var !sys.chansend1 sys._esys_110\n"
"type sys._esys_116 {}\n"
- "type sys._osys_603 {pres sys.bool}\n"
+ "type sys._osys_632 {pres sys.bool}\n"
"type sys._esys_118 1 sys.any\n"
"type sys._esys_117 *sys._esys_118\n"
- "type sys._isys_605 {hchan sys._esys_117 elem sys.any}\n"
- "type sys._esys_115 (sys._esys_116 sys._osys_603 sys._isys_605)\n"
+ "type sys._isys_634 {hchan sys._esys_117 elem sys.any}\n"
+ "type sys._esys_115 (sys._esys_116 sys._osys_632 sys._isys_634)\n"
"var !sys.chansend2 sys._esys_115\n"
"type sys._esys_120 {}\n"
- "type sys._esys_121 {}\n"
- "type sys._esys_122 {}\n"
- "type sys._esys_119 (sys._esys_120 sys._esys_121 sys._esys_122)\n"
- "var !sys.gosched sys._esys_119\n"
- "type sys._esys_124 {}\n"
- "type sys._esys_125 {}\n"
- "type sys._esys_126 {}\n"
- "type sys._esys_123 (sys._esys_124 sys._esys_125 sys._esys_126)\n"
- "var !sys.goexit sys._esys_123\n"
+ "type sys._esys_121 *sys.uint8\n"
+ "type sys._osys_640 {sel sys._esys_121}\n"
+ "type sys._isys_642 {size sys.uint32}\n"
+ "type sys._esys_119 (sys._esys_120 sys._osys_640 sys._isys_642)\n"
+ "var !sys.newselect sys._esys_119\n"
+ "type sys._esys_123 {}\n"
+ "type sys._osys_647 {selected sys.bool}\n"
+ "type sys._esys_124 *sys.uint8\n"
+ "type sys._esys_126 1 sys.any\n"
+ "type sys._esys_125 *sys._esys_126\n"
+ "type sys._isys_649 {sel sys._esys_124 hchan sys._esys_125 elem sys.any}\n"
+ "type sys._esys_122 (sys._esys_123 sys._osys_647 sys._isys_649)\n"
+ "var !sys.selectsend sys._esys_122\n"
"type sys._esys_128 {}\n"
- "type sys._osys_616 {_esys_613 sys.string _esys_614 sys.bool}\n"
- "type sys._isys_618 {_esys_615 sys.string}\n"
- "type sys._esys_127 (sys._esys_128 sys._osys_616 sys._isys_618)\n"
- "var !sys.readfile sys._esys_127\n"
- "type sys._esys_130 {}\n"
- "type sys._osys_625 {_esys_622 sys.bool}\n"
- "type sys._isys_627 {_esys_623 sys.string _esys_624 sys.string}\n"
- "type sys._esys_129 (sys._esys_130 sys._osys_625 sys._isys_627)\n"
- "var !sys.writefile sys._esys_129\n"
- "type sys._esys_132 {}\n"
- "type sys._osys_637 {_esys_632 sys.int32 _esys_633 sys.int32}\n"
- "type sys._esys_133 *sys.uint8\n"
- "type sys._isys_639 {_esys_634 sys._esys_133 _esys_635 sys.int32 _esys_636 sys.int32}\n"
- "type sys._esys_131 (sys._esys_132 sys._osys_637 sys._isys_639)\n"
- "var !sys.bytestorune sys._esys_131\n"
+ "type sys._osys_656 {selected sys.bool}\n"
+ "type sys._esys_129 *sys.uint8\n"
+ "type sys._esys_131 1 sys.any\n"
+ "type sys._esys_130 *sys._esys_131\n"
+ "type sys._esys_132 *sys.any\n"
+ "type sys._isys_658 {sel sys._esys_129 hchan sys._esys_130 elem sys._esys_132}\n"
+ "type sys._esys_127 (sys._esys_128 sys._osys_656 sys._isys_658)\n"
+ "var !sys.selectrecv sys._esys_127\n"
+ "type sys._esys_134 {}\n"
"type sys._esys_135 {}\n"
- "type sys._osys_650 {_esys_645 sys.int32 _esys_646 sys.int32}\n"
- "type sys._isys_652 {_esys_647 sys.string _esys_648 sys.int32 _esys_649 sys.int32}\n"
- "type sys._esys_134 (sys._esys_135 sys._osys_650 sys._isys_652)\n"
- "var !sys.stringtorune sys._esys_134\n"
- "type sys._esys_137 {}\n"
+ "type sys._esys_136 *sys.uint8\n"
+ "type sys._isys_665 {sel sys._esys_136}\n"
+ "type sys._esys_133 (sys._esys_134 sys._esys_135 sys._isys_665)\n"
+ "var !sys.selectgo sys._esys_133\n"
"type sys._esys_138 {}\n"
- "type sys._isys_659 {_esys_658 sys.int32}\n"
- "type sys._esys_136 (sys._esys_137 sys._esys_138 sys._isys_659)\n"
- "var !sys.exit sys._esys_136\n"
+ "type sys._esys_139 {}\n"
+ "type sys._esys_140 {}\n"
+ "type sys._esys_137 (sys._esys_138 sys._esys_139 sys._esys_140)\n"
+ "var !sys.gosched sys._esys_137\n"
+ "type sys._esys_142 {}\n"
+ "type sys._esys_143 {}\n"
+ "type sys._esys_144 {}\n"
+ "type sys._esys_141 (sys._esys_142 sys._esys_143 sys._esys_144)\n"
+ "var !sys.goexit sys._esys_141\n"
+ "type sys._esys_146 {}\n"
+ "type sys._osys_674 {_esys_671 sys.string _esys_672 sys.bool}\n"
+ "type sys._isys_676 {_esys_673 sys.string}\n"
+ "type sys._esys_145 (sys._esys_146 sys._osys_674 sys._isys_676)\n"
+ "var !sys.readfile sys._esys_145\n"
+ "type sys._esys_148 {}\n"
+ "type sys._osys_683 {_esys_680 sys.bool}\n"
+ "type sys._isys_685 {_esys_681 sys.string _esys_682 sys.string}\n"
+ "type sys._esys_147 (sys._esys_148 sys._osys_683 sys._isys_685)\n"
+ "var !sys.writefile sys._esys_147\n"
+ "type sys._esys_150 {}\n"
+ "type sys._osys_695 {_esys_690 sys.int32 _esys_691 sys.int32}\n"
+ "type sys._esys_151 *sys.uint8\n"
+ "type sys._isys_697 {_esys_692 sys._esys_151 _esys_693 sys.int32 _esys_694 sys.int32}\n"
+ "type sys._esys_149 (sys._esys_150 sys._osys_695 sys._isys_697)\n"
+ "var !sys.bytestorune sys._esys_149\n"
+ "type sys._esys_153 {}\n"
+ "type sys._osys_708 {_esys_703 sys.int32 _esys_704 sys.int32}\n"
+ "type sys._isys_710 {_esys_705 sys.string _esys_706 sys.int32 _esys_707 sys.int32}\n"
+ "type sys._esys_152 (sys._esys_153 sys._osys_708 sys._isys_710)\n"
+ "var !sys.stringtorune sys._esys_152\n"
+ "type sys._esys_155 {}\n"
+ "type sys._esys_156 {}\n"
+ "type sys._isys_717 {_esys_716 sys.int32}\n"
+ "type sys._esys_154 (sys._esys_155 sys._esys_156 sys._isys_717)\n"
+ "var !sys.exit sys._esys_154\n"
+ "type sys._esys_158 {}\n"
+ "type sys._esys_159 {}\n"
+ "type sys._esys_160 {}\n"
+ "type sys._esys_157 (sys._esys_158 sys._esys_159 sys._esys_160)\n"
"))\n"
;
diff -r 4bd3dc3df3e4 -r 50e7bca25907 src/cmd/gc/walk.c
--- a/src/cmd/gc/walk.c Thu Jul 24 13:36:18 2008 -0700
+++ b/src/cmd/gc/walk.c Thu Jul 24 15:57:30 2008 -0700
@@ -70,7 +70,7 @@
if(top != Etop)
goto nottop;
walktype(n->left, Erv);
- *n = *nod(OLIST, prcompat(n->left), nodpanic(n->lineno));
+ *n = *list(prcompat(n->left), nodpanic(n->lineno));
goto ret;
case OLITERAL:
@@ -121,6 +121,9 @@
if(top != Etop)
goto nottop;
+ if(!casebody(n->nbody))
+ yyerror("switch statement must have case labels");
+
if(n->ntest == N)
n->ntest = booltrue;
walktype(n->ninit, Etop);
@@ -142,6 +145,20 @@
walktype(n->nincr, Erv);
goto ret;
+ case OSELECT:
+ if(top != Etop)
+ goto nottop;
+
+ walkselect(n);
+ goto ret;
+
+ case OSCASE:
+ if(top != Etop)
+ goto nottop;
+// walktype(n->left, Erv); SPECIAL
+ n = n->right;
+ goto loop;
+
case OEMPTY:
if(top != Etop)
goto nottop;
@@ -216,7 +233,7 @@
l = ascompatte(n->op, getinarg(t), &n->right, 0);
r = ascompatte(n->op, getthis(t), &n->left->left, 0);
if(l != N)
- r = nod(OLIST, r, l);
+ r = list(r, l);
n->left->left = N;
ullmancalc(n->left);
n->right = reorder1(r);
@@ -255,7 +272,7 @@
walktype(r, Erv);
l = ascompatet(n->op, &n->left, &r->type, 0);
if(l != N) {
- *n = *nod(OLIST, r, reorder2(l));
+ *n = *list(r, reorder2(l));
}
goto ret;
}
@@ -591,8 +608,8 @@
case OSEND:
if(top == Elv)
goto nottop;
- walktype(n->left, Erv);
- walktype(n->right, Erv);
+ walktype(n->left, Erv); // chan
+ walktype(n->right, Erv); // e
*n = *chanop(n, top);
goto ret;
@@ -805,7 +822,7 @@
}
/*
- * check that selected type
+ * check that switch type
* is compat with all the cases
*/
Type*
@@ -897,6 +914,125 @@
goto loop;
}
+Node*
+selcase(Node *c, Node *var)
+{
+ Node *a, *r, *on;
+ Type *t;
+
+ walktype(c->left, Erv); // chan
+ walktype(c->right, Erv); // elem
+ t = fixchan(c->left->type);
+ if(t == T)
+ return;
+
+ convlit(c->right, t->type);
+ if(!ascompat(t->type, c->right->type)) {
+ badtype(c->op, t->type, c->right->type);
+ return;
+ }
+
+ // selectsend(sel *byte, hchan *chan any, elem any) (selected bool);
+ on = syslook("selectsend", 1);
+ argtype(on, t->type);
+ argtype(on, t->type);
+
+ a = c->right; // elem
+ r = a;
+ a = c->left; // chan
+ r = list(a, r);
+ a = var; // sel-var
+ r = list(a, r);
+
+ a = nod(OCALL, on, r);
+ r = nod(OIF, N, N);
+ r->ntest = a;
+
+ return r;
+
+}
+
+void
+walkselect(Node *sel)
+{
+ Iter iter;
+ Node *n, *oc, *on, *r;
+ Node *var, *bod, *res;
+ int count;
+ long lno;
+
+ lno = setlineno(sel);
+
+ // generate sel-struct
+ var = nod(OXXX, N, N);
+ tempname(var, ptrto(types[TUINT8]));
+
+ n = listfirst(&iter, &sel->left);
+ if(n == N || n->op != OXCASE)
+ yyerror("first select statement must be a case");
+
+ count = 0; // number of cases
+ res = N; // entire select body
+ bod = N; // body of each case
+ oc = N; // last case
+
+ for(count=0; n!=N; n=listnext(&iter)) {
+ setlineno(n);
+
+ switch(n->op) {
+ default:
+ bod = list(bod, n);
+ break;
+
+ case OXCASE:
+ switch(n->left->op) {
+ default:
+ yyerror("select cases must be send or recv");
+ break;
+
+ case OSEND:
+ if(oc != N) {
+ bod = list(bod, nod(OBREAK, N, N));
+ oc->nbody = rev(bod);
+ }
+ oc = selcase(n->left, var);
+ res = list(res, oc);
+ break;
+ }
+ bod = N;
+ count++;
+ break;
+ }
+ }
+ if(oc != N) {
+ bod = list(bod, nod(OBREAK, N, N));
+ oc->nbody = rev(bod);
+ }
+ setlineno(sel);
+
+ // selectgo(sel *byte);
+ on = syslook("selectgo", 0);
+ r = nod(OCALL, on, var); // sel-var
+ res = list(res, r);
+
+ // newselect(size uint32) (sel *byte);
+ on = syslook("newselect", 0);
+
+ r = nod(OXXX, N, N);
+ nodconst(r, types[TINT32], count); // count
+ r = nod(OCALL, on, r);
+ r = nod(OAS, var, r);
+
+ sel->ninit = r;
+ sel->nbody = rev(res);
+ sel->left = N;
+
+ walktype(sel->ninit, Etop);
+ walktype(sel->nbody, Etop);
+
+ lineno = lno;
+}
+
/*
* allowable type combinations for
* normal binary operations.
@@ -1053,7 +1189,7 @@
if(nn == N)
nn = a;
else
- nn = nod(OLIST, a, nn);
+ nn = list(a, nn);
l = listnext(&savel);
r = listnext(&saver);
@@ -1093,7 +1229,7 @@
if(nn == N)
nn = a;
else
- nn = nod(OLIST, a, nn);
+ nn = list(a, nn);
l = listnext(&savel);
r = structnext(&saver);
@@ -1134,7 +1270,7 @@
if(nn == N)
nn = a;
else
- nn = nod(OLIST, a, nn);
+ nn = list(a, nn);
l = structnext(&savel);
r = listnext(&saver);
@@ -1230,7 +1366,7 @@
if(r == N)
r = nod(OCALL, on, l);
else
- r = nod(OLIST, r, nod(OCALL, on, l));
+ r = list(r, nod(OCALL, on, l));
l = listnext(&save);
goto loop;
@@ -1305,7 +1441,7 @@
case OLT:
// sys_cmpstring(s1, s2) :: 0
on = syslook("cmpstring", 0);
- r = nod(OLIST, n->left, n->right);
+ r = list(n->left, n->right);
r = nod(OCALL, on, r);
c = nodintconst(0);
r = nod(n->op, r, c);
@@ -1314,7 +1450,7 @@
case OADD:
// sys_catstring(s1, s2)
on = syslook("catstring", 0);
- r = nod(OLIST, n->left, n->right);
+ r = list(n->left, n->right);
r = nod(OCALL, on, r);
break;
@@ -1328,7 +1464,7 @@
// s1 = sys_catstring(s1, s2)
if(n->etype != OADD)
fatal("stringop: not cat");
- r = nod(OLIST, n->left, n->right);
+ r = list(n->left, n->right);
on = syslook("catstring", 0);
r = nod(OCALL, on, r);
r = nod(OAS, n->left, r);
@@ -1344,8 +1480,8 @@
c = nod(OCONV, n->right->right, N);
c->type = types[TINT32];
- r = nod(OLIST, r, c);
- r = nod(OLIST, n->left, r);
+ r = list(r, c);
+ r = list(n->left, r);
on = syslook("slicestring", 0);
r = nod(OCALL, on, r);
break;
@@ -1360,7 +1496,7 @@
}
r = nod(OCONV, n->right, N);
r->type = types[TINT32];
- r = nod(OLIST, c, r);
+ r = list(c, r);
on = syslook("indexstring", 0);
r = nod(OCALL, on, r);
break;
@@ -1382,7 +1518,7 @@
l = isbytearray(n->left->type);
c = nodintconst(l-1);
- r = nod(OLIST, r, c);
+ r = list(r, c);
on = syslook("byteastring", 0);
r = nod(OCALL, on, r);
break;
@@ -1499,13 +1635,13 @@
a = nodintconst(0);
r = a;
a = nodintconst(algtype(t->type)); // val algorithm
- r = nod(OLIST, a, r);
+ r = list(a, r);
a = nodintconst(algtype(t->down)); // key algorithm
- r = nod(OLIST, a, r);
+ r = list(a, r);
a = nodintconst(t->type->width); // val width
- r = nod(OLIST, a, r);
+ r = list(a, r);
a = nodintconst(t->down->width); // key width
- r = nod(OLIST, a, r);
+ r = list(a, r);
on = syslook("newmap", 1);
@@ -1541,7 +1677,7 @@
r = a;
a = n->left; // map
- r = nod(OLIST, a, r);
+ r = list(a, r);
on = syslook("mapaccess1", 1);
@@ -1579,9 +1715,9 @@
a = n->right; // val
r = a;
a = n->left->right; // key
- r = nod(OLIST, a, r);
+ r = list(a, r);
a = n->left->left; // map
- r = nod(OLIST, a, r);
+ r = list(a, r);
on = syslook("mapassign1", 1);
@@ -1608,11 +1744,11 @@
a = n->right->right; // pres
r = a;
a = n->right->left; // val
- r =nod(OLIST, a, r);
+ r =list(a, r);
a = n->left->right; // key
- r = nod(OLIST, a, r);
+ r = list(a, r);
a = n->left->left; // map
- r = nod(OLIST, a, r);
+ r = list(a, r);
on = syslook("mapassign2", 1);
@@ -1639,7 +1775,7 @@
a = n->right->right; // key
r = a;
a = n->right->left; // map
- r = nod(OLIST, a, r);
+ r = list(a, r);
on = syslook("mapaccess2", 1);
@@ -1695,9 +1831,9 @@
a = nodintconst(0);
r = a;
a = nodintconst(algtype(t->type)); // elem algorithm
- r = nod(OLIST, a, r);
+ r = list(a, r);
a = nodintconst(t->type->width); // elem width
- r = nod(OLIST, a, r);
+ r = list(a, r);
on = syslook("newchan", 1);
argtype(on, t->type); // any-1
@@ -1789,7 +1925,7 @@
a = n->right; // e
r = a;
a = n->left; // chan
- r = nod(OLIST, a, r);
+ r = list(a, r);
on = syslook("chansend1", 1);
argtype(on, t->type); // any-1
@@ -1807,7 +1943,7 @@
a = n->right; // e
r = a;
a = n->left; // chan
- r = nod(OLIST, a, r);
+ r = list(a, r);
on = syslook("chansend2", 1);
argtype(on, t->type); // any-1
@@ -1981,7 +2117,7 @@
if(n == N)
n = a;
else
- n = nod(OLIST, n, a);
+ n = list(n, a);
l = listnext(&savel);
r = listnext(&saver);
@@ -2017,7 +2153,7 @@
if(n == N)
n = a;
else
- n = nod(OLIST, n, a);
+ n = list(n, a);
l = listnext(&savel);
t = structnext(&saver);
}
@@ -2039,7 +2175,7 @@
a = old2new(nl->left, t->type);
n = a;
a = old2new(nl->right, types[TBOOL]);
- n = nod(OLIST, n, a);
+ n = list(n, a);
break;
case ORECV:
@@ -2052,7 +2188,7 @@
a = old2new(nl->left, t->type->type);
n = a;
a = old2new(nl->right, types[TBOOL]);
- n = nod(OLIST, n, a);
+ n = list(n, a);
}
n = rev(n);
return n;
@@ -2107,15 +2243,15 @@
r = rev(r);
g = rev(g);
if(g != N)
- f = nod(OLIST, g, f);
- r = nod(OLIST, f, r);
+ f = list(g, f);
+ r = list(f, r);
return r;
}
if(l->ullman < UINF) {
if(r == N)
r = l;
else
- r = nod(OLIST, l, r);
+ r = list(l, r);
goto more;
}
if(f == N) {
@@ -2131,7 +2267,7 @@
if(g == N)
g = a;
else
- g = nod(OLIST, a, g);
+ g = list(a, g);
// put normal arg assignment on list
// with fncall replaced by tempname
@@ -2139,7 +2275,7 @@
if(r == N)
r = l;
else
- r = nod(OLIST, l, r);
+ r = list(l, r);
more:
l = listnext(&save);
@@ -2256,7 +2392,7 @@
if(r == N)
r = q;
else
- r = nod(OLIST, r, q);
+ r = list(r, q);
break;
}
}
@@ -2275,7 +2411,7 @@
if(q == N)
q = l1;
else
- q = nod(OLIST, q, l1);
+ q = list(q, l1);
l1 = listnext(&save1);
}
@@ -2285,7 +2421,7 @@
if(q == N)
q = l1;
else
- q = nod(OLIST, q, l1);
+ q = list(q, l1);
l1 = listnext(&save1);
}
diff -r 4bd3dc3df3e4 -r 50e7bca25907 src/runtime/chan.c
--- a/src/runtime/chan.c Thu Jul 24 13:36:18 2008 -0700
+++ b/src/runtime/chan.c Thu Jul 24 15:57:30 2008 -0700
@@ -10,10 +10,13 @@
typedef struct Link Link;
typedef struct WaitQ WaitQ;
typedef struct SudoG SudoG;
+typedef struct Select Select;
+typedef struct Scase Scase;
struct SudoG
{
G* g; // g and selgen constitute
+ byte elem[8]; // synch data element
int64 selgen; // a weak pointer to g
SudoG* link;
};
@@ -29,8 +32,8 @@
uint32 elemsize;
uint32 dataqsiz; // size of the circular q
uint32 qcount; // total data in the q
- uint32 eo; // vararg of element
- uint32 po; // vararg of present bool
+ uint16 eo; // vararg of element
+ uint16 po; // vararg of present bool
Alg* elemalg; // interface for element type
Link* senddataq; // pointer for sender
Link* recvdataq; // pointer for receiver
@@ -41,14 +44,33 @@
struct Link
{
- Link* link;
- byte elem[8];
+ Link* link; // asynch queue circular linked list
+ byte elem[8]; // asynch queue data element
};
-static SudoG* dequeue(WaitQ*, Hchan*);
-static void enqueue(WaitQ*, SudoG*);
-static SudoG* allocsg(Hchan*);
-static void freesg(Hchan*, SudoG*);
+struct Scase
+{
+ Hchan* chan; // chan
+ byte* pc; // return pc
+ uint16 send; // 0-recv 1-send
+ uint16 so; // vararg of selected bool
+ byte elem[8]; // element
+};
+
+struct Select
+{
+ uint16 tcase; // total count of scase[]
+ uint16 ncase; // currently filled scase[]
+ Scase scase[1]; // one per case
+};
+
+static SudoG* dequeue(WaitQ*, Hchan*);
+static void enqueue(WaitQ*, SudoG*);
+static SudoG* allocsg(Hchan*);
+static void freesg(Hchan*, SudoG*);
+static uint32 gcd(uint32, uint32);
+static uint32 fastrand1(void);
+static uint32 fastrand2(void);
// newchan(elemsize uint32, elemalg uint32, hint uint32) (hchan *chan any);
void
@@ -134,16 +156,15 @@
sgr = dequeue(&c->recvq, c);
if(sgr != nil) {
+ c->elemalg->copy(c->elemsize, sgr->elem, ae);
+
gr = sgr->g;
- freesg(c, sgr);
-
- c->elemalg->copy(c->elemsize, gr->elem, ae);
gr->status = Grunnable;
return;
}
- c->elemalg->copy(c->elemsize, g->elem, ae);
sgr = allocsg(c);
+ c->elemalg->copy(c->elemsize, sgr->elem, ae);
g->status = Gwaiting;
enqueue(&c->sendq, sgr);
sys·gosched();
@@ -191,9 +212,8 @@
sgr = dequeue(&c->recvq, c);
if(sgr != nil) {
gr = sgr->g;
- freesg(c, sgr);
+ c->elemalg->copy(c->elemsize, sgr->elem, ae);
- c->elemalg->copy(c->elemsize, gr->elem, ae);
gr->status = Grunnable;
*ap = true;
return;
@@ -237,18 +257,20 @@
sgs = dequeue(&c->sendq, c);
if(sgs != nil) {
+ c->elemalg->copy(c->elemsize, ae, sgs->elem);
+
gs = sgs->g;
+ gs->status = Grunnable;
+
freesg(c, sgs);
-
- c->elemalg->copy(c->elemsize, ae, gs->elem);
- gs->status = Grunnable;
return;
}
sgs = allocsg(c);
g->status = Gwaiting;
enqueue(&c->recvq, sgs);
sys·gosched();
- c->elemalg->copy(c->elemsize, ae, g->elem);
+ c->elemalg->copy(c->elemsize, ae, sgs->elem);
+ freesg(c, sgs);
return;
asynch:
@@ -291,11 +313,12 @@
sgs = dequeue(&c->sendq, c);
if(sgs != nil) {
+ c->elemalg->copy(c->elemsize, ae, sgs->elem);
+
gs = sgs->g;
+ gs->status = Grunnable;
+
freesg(c, sgs);
-
- c->elemalg->copy(c->elemsize, ae, gs->elem);
- gs->status = Grunnable;
*ap = true;
return;
}
@@ -320,6 +343,150 @@
*ap = true;
}
+// newselect(size uint32) (sel *byte);
+void
+sys·newselect(int32 size, Select *sel)
+{
+ int32 n;
+
+ n = 0;
+ if(size > 1)
+ n = size-1;
+ sel = mal(sizeof(*sel) + n*sizeof(sel->scase[0]));
+ sel->tcase = size;
+ sel->ncase = 0;
+ FLUSH(&sel);
+ if(debug) {
+ prints("newselect s=");
+ sys·printpointer(sel);
+ prints("\n");
+ }
+}
+
+// selectsend(sel *byte, hchan *chan any, elem any) (selected bool);
+void
+sys·selectsend(Select *sel, Hchan *c, ...)
+{
+ int32 i, eo;
+ Scase *cas;
+ byte *as, *ae;
+
+ // return val, selected, is preset to false
+ if(c == nil)
+ return;
+
+ i = sel->ncase;
+ if(i >= sel->tcase)
+ throw("selectsend: too many cases");
+ sel->ncase = i+1;
+ cas = &sel->scase[i];
+
+ cas->pc = sys·getcallerpc(&sel);
+ cas->chan = c;
+
+ eo = rnd(sizeof(sel), sizeof(c));
+ eo = rnd(eo+sizeof(c), c->elemsize);
+ cas->so = rnd(eo+c->elemsize, 1);
+ cas->send = 1;
+
+ ae = (byte*)&sel + eo;
+ c->elemalg->copy(c->elemsize, cas->elem, ae);
+
+ as = (byte*)&sel + cas->so;
+ *as = false;
+
+ if(debug) {
+ prints("newselect s=");
+ sys·printpointer(sel);
+ prints(" pc=");
+ sys·printpointer(cas->pc);
+ prints(" chan=");
+ sys·printpointer(cas->chan);
+ prints(" po=");
+ sys·printint(cas->so);
+ prints(" send=");
+ sys·printint(cas->send);
+ prints("\n");
+ }
+}
+
+// selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
+void
+sys·selectrecv(Select *sel, Hchan *c, ...)
+{
+ throw("selectrecv");
+}
+
+// selectgo(sel *byte);
+void
+sys·selectgo(Select *sel)
+{
+ uint32 p, o, i;
+ Scase *cas;
+ Hchan *c;
+
+ byte *ae, *as;
+ SudoG *sgr;
+ G *gr;
+
+ if(sel->ncase < 1) {
+ throw("selectgo: no cases");
+ }
+
+ // select a (relative) prime
+ for(i=0;; i++) {
+ p = fastrand1();
+ if(gcd(p, sel->ncase) == 1)
+ break;
+ if(i > 1000) {
+ throw("selectgo: failed to select prime");
+ }
+ }
+ o = fastrand2();
+
+ p %= sel->ncase;
+ o %= sel->ncase;
+
+ // pass 1 - look for something that can go
+ for(i=0; i<sel->ncase; i++) {
+ cas = &sel->scase[o];
+ c = cas->chan;
+ if(cas->send) {
+ if(c->dataqsiz > 0) {
+ throw("selectgo: asynch");
+ }
+ sgr = dequeue(&c->recvq, c);
+ if(sgr == nil)
+ continue;
+
+ c->elemalg->copy(c->elemsize, sgr->elem, cas->elem);
+ gr = sgr->g;
+ gr->status = Grunnable;
+
+ goto retc;
+ }
+
+ o += p;
+ if(o >= sel->ncase)
+ o -= sel->ncase;
+ }
+
+ if(debug) {
+ prints("selectgo s=");
+ sys·printpointer(sel);
+ prints(" p=");
+ sys·printpointer((void*)p);
+ prints("\n");
+ }
+
+ throw("selectgo");
+
+retc:
+ sys·setcallerpc(&sel, cas->pc);
+ as = (byte*)&sel + cas->so;
+ *as = true;
+}
+
static SudoG*
dequeue(WaitQ *q, Hchan *c)
{
@@ -377,3 +544,41 @@
sg->link = c->free;
c->free = sg;
}
+
+static uint32
+gcd(uint32 u, uint32 v)
+{
+ for(;;) {
+ if(u > v) {
+ if(v == 0)
+ return u;
+ u = u%v;
+ continue;
+ }
+ if(u == 0)
+ return v;
+ v = v%u;
+ }
+}
+
+static uint32
+fastrand1(void)
+{
+ static uint32 x = 0x49f6428aUL;
+
+ x += x;
+ if(x & 0x80000000L)
+ x ^= 0x88888eefUL;
+ return x;
+}
+
+static uint32
+fastrand2(void)
+{
+ static uint32 x = 0x49f6428aUL;
+
+ x += x;
+ if(x & 0x80000000L)
+ x ^= 0xfafd871bUL;
+ return x;
+}
diff -r 4bd3dc3df3e4 -r 50e7bca25907 src/runtime/runtime.h
--- a/src/runtime/runtime.h Thu Jul 24 13:36:18 2008 -0700
+++ b/src/runtime/runtime.h Thu Jul 24 15:57:30 2008 -0700
@@ -110,7 +110,6 @@
int32 status;
int32 goid;
int64 selgen; // valid sudog pointer
- byte elem[8]; // transfer element for chan
};
struct M
{
@@ -205,6 +204,7 @@
void sys·breakpoint(void);
uint8* sys·mmap(byte*, uint32, int32, int32, int32, uint32);
void sys·memclr(byte*, uint32);
+void sys·setcallerpc(void*, void*);
void* sys·getcallerpc(void*);
void sys·sigaction(int64, void*, void*);
void sys·rt_sigaction(int64, void*, void*, uint64);
diff -r 4bd3dc3df3e4 -r 50e7bca25907 src/runtime/sys_amd64_darwin.s
--- a/src/runtime/sys_amd64_darwin.s Thu Jul 24 13:36:18 2008 -0700
+++ b/src/runtime/sys_amd64_darwin.s Thu Jul 24 15:57:30 2008 -0700
@@ -110,6 +110,12 @@
RET
TEXT sys·getcallerpc+0(SB),1,$0
- MOVQ x+0(FP),AX
- MOVQ -8(AX),AX
+ MOVQ x+0(FP),AX // addr of first arg
+ MOVQ -8(AX),AX // get calling pc
RET
+
+TEXT sys·setcallerpc+0(SB),1,$0
+ MOVQ x+0(FP),AX // addr of first arg
+ MOVQ x+8(FP), BX
+ MOVQ BX, -8(AX) // set calling pc
+ RET
diff -r 4bd3dc3df3e4 -r 50e7bca25907 src/runtime/sys_amd64_linux.s
--- a/src/runtime/sys_amd64_linux.s Thu Jul 24 13:36:18 2008 -0700
+++ b/src/runtime/sys_amd64_linux.s Thu Jul 24 15:57:30 2008 -0700
@@ -114,6 +114,12 @@
RET
TEXT sys·getcallerpc+0(SB),1,$0
- MOVQ x+0(FP),AX
- MOVQ -8(AX),AX
+ MOVQ x+0(FP),AX // addr of first arg
+ MOVQ -8(AX),AX // get calling pc
RET
+
+TEXT sys·setcallerpc+0(SB),1,$0
+ MOVQ x+0(FP),AX // addr of first arg
+ MOVQ x+8(FP), BX
+ MOVQ BX, -8(AX) // set calling pc
+ RET
changeset: 422:71cd9bfc8dbb
user: Ken Thompson <[email protected]>
date: Fri Jul 25 11:58:26 2008 -0700
summary: read select
diff -r aded86599731 -r 71cd9bfc8dbb src/cmd/gc/subr.c
--- a/src/cmd/gc/subr.c Fri Jul 25 11:27:13 2008 -0700
+++ b/src/cmd/gc/subr.c Fri Jul 25 11:58:26 2008 -0700
@@ -446,6 +446,7 @@
case OIF:
case OSWITCH:
case OFOR:
+ case OSELECT:
dodump(n->ninit, dep);
break;
}
@@ -480,6 +481,11 @@
}
return;
+ case OSELECT:
+ print("%O%J\n", n->op, n);
+ dodump(n->nbody, dep+1);
+ return;
+
case OSWITCH:
case OFOR:
print("%O%J\n", n->op, n);
diff -r aded86599731 -r 71cd9bfc8dbb src/cmd/gc/walk.c
--- a/src/cmd/gc/walk.c Fri Jul 25 11:27:13 2008 -0700
+++ b/src/cmd/gc/walk.c Fri Jul 25 11:58:26 2008 -0700
@@ -915,13 +915,18 @@
}
Node*
-selcase(Node *c, Node *var)
+selcase(Node *n, Node *var)
{
- Node *a, *r, *on;
+ Node *a, *r, *on, *c;
Type *t;
+ c = n->left;
+ if(c->op == ORECV)
+ goto recv;
+
walktype(c->left, Erv); // chan
walktype(c->right, Erv); // elem
+
t = fixchan(c->left->type);
if(t == T)
return;
@@ -937,11 +942,44 @@
argtype(on, t->type);
argtype(on, t->type);
- a = c->right; // elem
+ a = c->right; // elem
r = a;
- a = c->left; // chan
+ a = c->left; // chan
r = list(a, r);
- a = var; // sel-var
+ a = var; // sel-var
+ r = list(a, r);
+
+ a = nod(OCALL, on, r);
+ r = nod(OIF, N, N);
+ r->ntest = a;
+
+ return r;
+
+recv:
+ walktype(c->left, Elv); // elem
+ walktype(c->right, Erv); // chan
+
+ t = fixchan(c->right->type);
+ if(t == T)
+ return;
+
+ convlit(c->left, t->type);
+ if(!ascompat(t->type, c->left->type)) {
+ badtype(c->op, t->type, c->left->type);
+ return;
+ }
+
+ // selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
+ on = syslook("selectrecv", 1);
+ argtype(on, t->type);
+ argtype(on, t->type);
+
+ a = c->left; // elem
+ a = nod(OADDR, a, N);
+ r = a;
+ a = c->right; // chan
+ r = list(a, r);
+ a = var; // sel-var
r = list(a, r);
a = nod(OCALL, on, r);
@@ -991,11 +1029,12 @@
break;
case OSEND:
+ case ORECV:
if(oc != N) {
bod = list(bod, nod(OBREAK, N, N));
oc->nbody = rev(bod);
}
- oc = selcase(n->left, var);
+ oc = selcase(n, var);
res = list(res, oc);
break;
}
@@ -1030,6 +1069,8 @@
walktype(sel->ninit, Etop);
walktype(sel->nbody, Etop);
+dump("sel", sel);
+
lineno = lno;
}
diff -r aded86599731 -r 71cd9bfc8dbb src/runtime/chan.c
--- a/src/runtime/chan.c Fri Jul 25 11:27:13 2008 -0700
+++ b/src/runtime/chan.c Fri Jul 25 11:58:26 2008 -0700
@@ -54,7 +54,10 @@
byte* pc; // return pc
uint16 send; // 0-recv 1-send
uint16 so; // vararg of selected bool
- byte elem[8]; // element
+ union {
+ byte elem[8]; // element (send)
+ byte* elemp; // pointer to element (recv)
+ } u;
};
struct Select
@@ -390,7 +393,7 @@
cas->send = 1;
ae = (byte*)&sel + eo;
- c->elemalg->copy(c->elemsize, cas->elem, ae);
+ c->elemalg->copy(c->elemsize, cas->u.elem, ae);
as = (byte*)&sel + cas->so;
*as = false;
@@ -414,7 +417,45 @@
void
sys·selectrecv(Select *sel, Hchan *c, ...)
{
- throw("selectrecv");
+ int32 i, epo;
+ Scase *cas;
+ byte *as;
+
+ // return val, selected, is preset to false
+ if(c == nil)
+ return;
+
+ i = sel->ncase;
+ if(i >= sel->tcase)
+ throw("selectsend: too many cases");
+ sel->ncase = i+1;
+ cas = &sel->scase[i];
+
+ cas->pc = sys·getcallerpc(&sel);
+ cas->chan = c;
+
+ epo = rnd(sizeof(sel), sizeof(c));
+ epo = rnd(epo+sizeof(c), sizeof(byte*));
+ cas->so = rnd(epo+sizeof(byte*), 1);
+ cas->send = 0;
+ cas->u.elemp = *(byte**)((byte*)&sel + epo);
+
+ as = (byte*)&sel + cas->so;
+ *as = false;
+
+ if(debug) {
+ prints("newselect s=");
+ sys·printpointer(sel);
+ prints(" pc=");
+ sys·printpointer(cas->pc);
+ prints(" chan=");
+ sys·printpointer(cas->chan);
+ prints(" so=");
+ sys·printint(cas->so);
+ prints(" send=");
+ sys·printint(cas->send);
+ prints("\n");
+ }
}
// selectgo(sel *byte);
@@ -429,6 +470,9 @@
SudoG *sgr;
G *gr;
+ SudoG *sgs;
+ G *gs;
+
if(sel->ncase < 1) {
throw("selectgo: no cases");
}
@@ -453,17 +497,34 @@
c = cas->chan;
if(cas->send) {
if(c->dataqsiz > 0) {
- throw("selectgo: asynch");
+ throw("selectgo: send asynch");
}
sgr = dequeue(&c->recvq, c);
if(sgr == nil)
continue;
- c->elemalg->copy(c->elemsize, sgr->elem, cas->elem);
+ c->elemalg->copy(c->elemsize, sgr->elem, cas->u.elem);
gr = sgr->g;
gr->status = Grunnable;
goto retc;
+ } else {
+ if(c->dataqsiz > 0) {
+ throw("selectgo: recv asynch");
+ }
+ sgs = dequeue(&c->sendq, c);
+ if(sgs == nil)
+ continue;
+
+ if(cas->u.elemp != nil)
+ c->elemalg->copy(c->elemsize, cas->u.elemp, sgs->elem);
+
+ gs = sgs->g;
+ gs->status = Grunnable;
+
+ freesg(c, sgs);
+
+ goto retc;
}
o += p;
changeset: 425:a1505259dd93
user: Ken Thompson <[email protected]>
date: Fri Jul 25 15:55:12 2008 -0700
summary: select
diff -r 4cad076072fc -r a1505259dd93 src/cmd/gc/walk.c
--- a/src/cmd/gc/walk.c Fri Jul 25 12:49:36 2008 -0700
+++ b/src/cmd/gc/walk.c Fri Jul 25 15:55:12 2008 -0700
@@ -1069,7 +1069,7 @@
walktype(sel->ninit, Etop);
walktype(sel->nbody, Etop);
-dump("sel", sel);
+//dump("sel", sel);
lineno = lno;
}
diff -r 4cad076072fc -r a1505259dd93 src/runtime/chan.c
--- a/src/runtime/chan.c Fri Jul 25 12:49:36 2008 -0700
+++ b/src/runtime/chan.c Fri Jul 25 15:55:12 2008 -0700
@@ -17,7 +17,8 @@
{
G* g; // g and selgen constitute
byte elem[8]; // synch data element
- int64 selgen; // a weak pointer to g
+ int16 offset; // offset of case number
+ int32 selgen; // a weak pointer to g
SudoG* link;
};
@@ -162,6 +163,7 @@
c->elemalg->copy(c->elemsize, sgr->elem, ae);
gr = sgr->g;
+ gr->param = sgr;
gr->status = Grunnable;
return;
}
@@ -217,6 +219,7 @@
gr = sgr->g;
c->elemalg->copy(c->elemsize, sgr->elem, ae);
+ gr->param = sgr;
gr->status = Grunnable;
*ap = true;
return;
@@ -263,6 +266,7 @@
c->elemalg->copy(c->elemsize, ae, sgs->elem);
gs = sgs->g;
+ gs->param = sgs;
gs->status = Grunnable;
freesg(c, sgs);
@@ -319,6 +323,7 @@
c->elemalg->copy(c->elemsize, ae, sgs->elem);
gs = sgs->g;
+ gs->param = sgs;
gs->status = Grunnable;
freesg(c, sgs);
@@ -374,7 +379,7 @@
Scase *cas;
byte *as, *ae;
- // return val, selected, is preset to false
+ // nil cases do not compete
if(c == nil)
return;
@@ -421,7 +426,7 @@
Scase *cas;
byte *as;
- // return val, selected, is preset to false
+ // nil cases do not compete
if(c == nil)
return;
@@ -465,16 +470,21 @@
uint32 p, o, i;
Scase *cas;
Hchan *c;
+ SudoG *sg;
+ G *gp;
byte *ae, *as;
- SudoG *sgr;
- G *gr;
- SudoG *sgs;
- G *gs;
+ if(0) {
+ prints("selectgo: sel=");
+ sys·printpointer(sel);
+ prints("\n");
+ }
- if(sel->ncase < 1) {
- throw("selectgo: no cases");
+ if(sel->ncase < 2) {
+ if(sel->ncase < 1)
+ throw("selectgo: no cases");
+ // make special case of one.
}
// select a (relative) prime
@@ -486,45 +496,33 @@
throw("selectgo: failed to select prime");
}
}
+
+ // select an initial offset
o = fastrand2();
p %= sel->ncase;
o %= sel->ncase;
- // pass 1 - look for something that can go
+ // pass 1 - look for something already waiting
for(i=0; i<sel->ncase; i++) {
cas = &sel->scase[o];
c = cas->chan;
+
+ if(c->dataqsiz > 0) {
+ if(cas->send)
+ throw("selectgo: send asynch");
+ else
+ throw("selectgo: recv asynch");
+ }
+
if(cas->send) {
- if(c->dataqsiz > 0) {
- throw("selectgo: send asynch");
- }
- sgr = dequeue(&c->recvq, c);
- if(sgr == nil)
- continue;
-
- c->elemalg->copy(c->elemsize, sgr->elem, cas->u.elem);
- gr = sgr->g;
- gr->status = Grunnable;
-
- goto retc;
+ sg = dequeue(&c->recvq, c);
+ if(sg != nil)
+ goto gotr;
} else {
- if(c->dataqsiz > 0) {
- throw("selectgo: recv asynch");
- }
- sgs = dequeue(&c->sendq, c);
- if(sgs == nil)
- continue;
-
- if(cas->u.elemp != nil)
- c->elemalg->copy(c->elemsize, cas->u.elemp, sgs->elem);
-
- gs = sgs->g;
- gs->status = Grunnable;
-
- freesg(c, sgs);
-
- goto retc;
+ sg = dequeue(&c->sendq, c);
+ if(sg != nil)
+ goto gots;
}
o += p;
@@ -532,15 +530,96 @@
o -= sel->ncase;
}
- if(debug) {
- prints("selectgo s=");
+ // pass 2 - enqueue on all chans
+ for(i=0; i<sel->ncase; i++) {
+ cas = &sel->scase[o];
+ c = cas->chan;
+ if(cas->send) {
+ sg = dequeue(&c->recvq, c);
+ if(sg != nil)
+ goto gotr; // probably an error
+ sg = allocsg(c);
+ sg->offset = o;
+ c->elemalg->copy(c->elemsize, sg->elem, cas->u.elem);
+ enqueue(&c->sendq, sg);
+ } else {
+ sg = dequeue(&c->sendq, c);
+ if(sg != nil)
+ goto gots; // probably an error
+
+ sg = allocsg(c);
+ sg->offset = o;
+ enqueue(&c->recvq, sg);
+ }
+
+ o += p;
+ if(o >= sel->ncase)
+ o -= sel->ncase;
+ }
+
+ if(0) {
+ prints("wait: sel=");
sys·printpointer(sel);
- prints(" p=");
- sys·printpointer((void*)p);
+ prints("\n");
+ }
+ g->status = Gwaiting;
+ sys·gosched();
+
+ if(0) {
+ prints("wait-return: sel=");
+ sys·printpointer(sel);
prints("\n");
}
- throw("selectgo");
+ sg = g->param;
+ o = sg->offset;
+ cas = &sel->scase[o];
+ c = cas->chan;
+
+ if(0) {
+ prints("wake: sel=");
+ sys·printpointer(sel);
+ prints(" c=");
+ sys·printpointer(c);
+ prints(" o=");
+ sys·printint(o);
+ prints("\n");
+ }
+ if(cas->send)
+ goto gots;
+
+gotr:
+ if(0) {
+ prints("gotr: sel=");
+ sys·printpointer(sel);
+ prints(" c=");
+ sys·printpointer(c);
+ prints(" o=");
+ sys·printint(o);
+ prints("\n");
+ }
+ c->elemalg->copy(c->elemsize, sg->elem, cas->u.elem);
+ gp = sg->g;
+ gp->param = sg;
+ gp->status = Grunnable;
+ goto retc;
+
+gots:
+ if(0) {
+ prints("gots: sel=");
+ sys·printpointer(sel);
+ prints(" c=");
+ sys·printpointer(c);
+ prints(" o=");
+ sys·printint(o);
+ prints("\n");
+ }
+ if(cas->u.elemp != nil)
+ c->elemalg->copy(c->elemsize, cas->u.elemp, sg->elem);
+ gp = sg->g;
+ gp->param = sg;
+ gp->status = Grunnable;
+ freesg(c, sg);
retc:
sys·setcallerpc(&sel, cas->pc);
@@ -561,7 +640,7 @@
// if sgp is stale, ignore it
if(sgp->selgen != sgp->g->selgen) {
-prints("INVALID PSEUDOG POINTER\n");
+ //prints("INVALID PSEUDOG POINTER\n");
freesg(c, sgp);
goto loop;
}
diff -r 4cad076072fc -r a1505259dd93 src/runtime/runtime.h
--- a/src/runtime/runtime.h Fri Jul 25 12:49:36 2008 -0700
+++ b/src/runtime/runtime.h Fri Jul 25 15:55:12 2008 -0700
@@ -107,9 +107,10 @@
byte* stack0; // first stack segment
Gobuf sched;
G* alllink; // on allq
- int32 status;
+ void* param; // passed parameter on wakeup
+ int16 status;
int32 goid;
- int64 selgen; // valid sudog pointer
+ int32 selgen; // valid sudog pointer
};
struct M
{
changeset: 426:a0789f16988a
user: Ken Thompson <[email protected]>
date: Fri Jul 25 17:03:27 2008 -0700
summary: select
diff -r a1505259dd93 -r a0789f16988a src/cmd/gc/walk.c
--- a/src/cmd/gc/walk.c Fri Jul 25 15:55:12 2008 -0700
+++ b/src/cmd/gc/walk.c Fri Jul 25 17:03:27 2008 -0700
@@ -20,6 +20,23 @@
dump("fn", fn->nbody);
}
+int
+isselect(Node *n)
+{
+ Sym *s;
+
+ if(n == N)
+ return 0;
+ n = n->left;
+ s = pkglookup("selectsend", "sys");
+ if(s == n->sym)
+ return 1;
+ s = pkglookup("selectrecv", "sys");
+ if(s == n->sym)
+ return 1;
+ return 0;
+}
+
void
walktype(Node *n, int top)
{
@@ -227,16 +244,20 @@
case OCALL:
l = ascompatte(n->op, getinarg(t), &n->right, 0);
n->right = reorder1(l);
+ if(isselect(n)) {
+ // clear output bool - special prob with selectsend
+ r = ascompatte(n->op, getoutarg(t), &boolfalse, 0);
+ n->right = list(n->right, r);
+ }
break;
case OCALLMETH:
l = ascompatte(n->op, getinarg(t), &n->right, 0);
r = ascompatte(n->op, getthis(t), &n->left->left, 0);
- if(l != N)
- r = list(r, l);
+ l = list(r, l);
n->left->left = N;
ullmancalc(n->left);
- n->right = reorder1(r);
+ n->right = reorder1(l);
break;
}
goto ret;
@@ -919,6 +940,7 @@
{
Node *a, *r, *on, *c;
Type *t;
+ Iter iter;
c = n->left;
if(c->op == ORECV)
@@ -949,11 +971,7 @@
a = var; // sel-var
r = list(a, r);
- a = nod(OCALL, on, r);
- r = nod(OIF, N, N);
- r->ntest = a;
-
- return r;
+ goto out;
recv:
walktype(c->left, Elv); // elem
@@ -982,12 +1000,12 @@
a = var; // sel-var
r = list(a, r);
+out:
a = nod(OCALL, on, r);
r = nod(OIF, N, N);
r->ntest = a;
return r;
-
}
void
diff -r a1505259dd93 -r a0789f16988a src/runtime/chan.c
--- a/src/runtime/chan.c Fri Jul 25 15:55:12 2008 -0700
+++ b/src/runtime/chan.c Fri Jul 25 17:03:27 2008 -0700
@@ -377,7 +377,7 @@
{
int32 i, eo;
Scase *cas;
- byte *as, *ae;
+ byte *ae;
// nil cases do not compete
if(c == nil)
@@ -400,9 +400,6 @@
ae = (byte*)&sel + eo;
c->elemalg->copy(c->elemsize, cas->u.elem, ae);
- as = (byte*)&sel + cas->so;
- *as = false;
-
if(debug) {
prints("newselect s=");
sys·printpointer(sel);
@@ -424,7 +421,6 @@
{
int32 i, epo;
Scase *cas;
- byte *as;
// nil cases do not compete
if(c == nil)
@@ -445,9 +441,6 @@
cas->send = 0;
cas->u.elemp = *(byte**)((byte*)&sel + epo);
- as = (byte*)&sel + cas->so;
- *as = false;
-
if(debug) {
prints("newselect s=");
sys·printpointer(sel);
changeset: 427:a941613b3268
user: Ken Thompson <[email protected]>
date: Sat Jul 26 14:21:21 2008 -0700
summary: select/chan
diff -r a0789f16988a -r a941613b3268 src/cmd/gc/sys.go
--- a/src/cmd/gc/sys.go Fri Jul 25 17:03:27 2008 -0700
+++ b/src/cmd/gc/sys.go Sat Jul 26 14:21:21 2008 -0700
@@ -47,7 +47,7 @@
func newchan(elemsize uint32, elemalg uint32, hint uint32) (hchan *chan any);
func chanrecv1(hchan *chan any) (elem any);
func chanrecv2(hchan *chan any) (elem any, pres bool);
-func chanrecv3(hchan *chan any) (elem any, pres bool);
+func chanrecv3(hchan *chan any, elem *any) (pres bool);
func chansend1(hchan *chan any, elem any);
func chansend2(hchan *chan any, elem any) (pres bool);
diff -r a0789f16988a -r a941613b3268 src/cmd/gc/sysimport.c
--- a/src/cmd/gc/sysimport.c Fri Jul 25 17:03:27 2008 -0700
+++ b/src/cmd/gc/sysimport.c Sat Jul 26 14:21:21 2008 -0700
@@ -3,10 +3,10 @@
"type sys._esys_002 {}\n"
"type sys.any 24\n"
"type sys._esys_003 *sys.any\n"
- "type sys._osys_361 {_esys_359 sys._esys_003}\n"
+ "type sys._osys_372 {_esys_370 sys._esys_003}\n"
"type sys.uint32 6\n"
- "type sys._isys_363 {_esys_360 sys.uint32}\n"
- "type sys._esys_001 (sys._esys_002 sys._osys_361 sys._isys_363)\n"
+ "type sys._isys_374 {_esys_371 sys.uint32}\n"
+ "type sys._esys_001 (sys._esys_002 sys._osys_372 sys._isys_374)\n"
"var !sys.mal sys._esys_001\n"
"type sys._esys_005 {}\n"
"type sys._esys_006 {}\n"
@@ -16,282 +16,283 @@
"type sys._esys_009 {}\n"
"type sys._esys_010 {}\n"
"type sys.int32 5\n"
- "type sys._isys_369 {_esys_368 sys.int32}\n"
- "type sys._esys_008 (sys._esys_009 sys._esys_010 sys._isys_369)\n"
+ "type sys._isys_380 {_esys_379 sys.int32}\n"
+ "type sys._esys_008 (sys._esys_009 sys._esys_010 sys._isys_380)\n"
"var !sys.panicl sys._esys_008\n"
"type sys._esys_012 {}\n"
"type sys._esys_013 {}\n"
"type sys.bool 12\n"
- "type sys._isys_374 {_esys_373 sys.bool}\n"
- "type sys._esys_011 (sys._esys_012 sys._esys_013 sys._isys_374)\n"
+ "type sys._isys_385 {_esys_384 sys.bool}\n"
+ "type sys._esys_011 (sys._esys_012 sys._esys_013 sys._isys_385)\n"
"var !sys.printbool sys._esys_011\n"
"type sys._esys_015 {}\n"
"type sys._esys_016 {}\n"
"type sys.float64 10\n"
- "type sys._isys_379 {_esys_378 sys.float64}\n"
- "type sys._esys_014 (sys._esys_015 sys._esys_016 sys._isys_379)\n"
+ "type sys._isys_390 {_esys_389 sys.float64}\n"
+ "type sys._esys_014 (sys._esys_015 sys._esys_016 sys._isys_390)\n"
"var !sys.printfloat sys._esys_014\n"
"type sys._esys_018 {}\n"
"type sys._esys_019 {}\n"
"type sys.int64 7\n"
- "type sys._isys_384 {_esys_383 sys.int64}\n"
- "type sys._esys_017 (sys._esys_018 sys._esys_019 sys._isys_384)\n"
+ "type sys._isys_395 {_esys_394 sys.int64}\n"
+ "type sys._esys_017 (sys._esys_018 sys._esys_019 sys._isys_395)\n"
"var !sys.printint sys._esys_017\n"
"type sys._esys_021 {}\n"
"type sys._esys_022 {}\n"
"type sys._esys_023 25\n"
"type sys.string *sys._esys_023\n"
- "type sys._isys_389 {_esys_388 sys.string}\n"
- "type sys._esys_020 (sys._esys_021 sys._esys_022 sys._isys_389)\n"
+ "type sys._isys_400 {_esys_399 sys.string}\n"
+ "type sys._esys_020 (sys._esys_021 sys._esys_022 sys._isys_400)\n"
"var !sys.printstring sys._esys_020\n"
"type sys._esys_025 {}\n"
"type sys._esys_026 {}\n"
"type sys._esys_027 *sys.any\n"
- "type sys._isys_394 {_esys_393 sys._esys_027}\n"
- "type sys._esys_024 (sys._esys_025 sys._esys_026 sys._isys_394)\n"
+ "type sys._isys_405 {_esys_404 sys._esys_027}\n"
+ "type sys._esys_024 (sys._esys_025 sys._esys_026 sys._isys_405)\n"
"var !sys.printpointer sys._esys_024\n"
"type sys._esys_029 {}\n"
- "type sys._osys_401 {_esys_398 sys.string}\n"
- "type sys._isys_403 {_esys_399 sys.string _esys_400 sys.string}\n"
- "type sys._esys_028 (sys._esys_029 sys._osys_401 sys._isys_403)\n"
+ "type sys._osys_412 {_esys_409 sys.string}\n"
+ "type sys._isys_414 {_esys_410 sys.string _esys_411 sys.string}\n"
+ "type sys._esys_028 (sys._esys_029 sys._osys_412 sys._isys_414)\n"
"var !sys.catstring sys._esys_028\n"
"type sys._esys_031 {}\n"
- "type sys._osys_411 {_esys_408 sys.int32}\n"
- "type sys._isys_413 {_esys_409 sys.string _esys_410 sys.string}\n"
- "type sys._esys_030 (sys._esys_031 sys._osys_411 sys._isys_413)\n"
+ "type sys._osys_422 {_esys_419 sys.int32}\n"
+ "type sys._isys_424 {_esys_420 sys.string _esys_421 sys.string}\n"
+ "type sys._esys_030 (sys._esys_031 sys._osys_422 sys._isys_424)\n"
"var !sys.cmpstring sys._esys_030\n"
"type sys._esys_033 {}\n"
- "type sys._osys_422 {_esys_418 sys.string}\n"
- "type sys._isys_424 {_esys_419 sys.string _esys_420 sys.int32 _esys_421 sys.int32}\n"
- "type sys._esys_032 (sys._esys_033 sys._osys_422 sys._isys_424)\n"
+ "type sys._osys_433 {_esys_429 sys.string}\n"
+ "type sys._isys_435 {_esys_430 sys.string _esys_431 sys.int32 _esys_432 sys.int32}\n"
+ "type sys._esys_032 (sys._esys_033 sys._osys_433 sys._isys_435)\n"
"var !sys.slicestring sys._esys_032\n"
"type sys._esys_035 {}\n"
"type sys.uint8 2\n"
- "type sys._osys_433 {_esys_430 sys.uint8}\n"
- "type sys._isys_435 {_esys_431 sys.string _esys_432 sys.int32}\n"
- "type sys._esys_034 (sys._esys_035 sys._osys_433 sys._isys_435)\n"
+ "type sys._osys_444 {_esys_441 sys.uint8}\n"
+ "type sys._isys_446 {_esys_442 sys.string _esys_443 sys.int32}\n"
+ "type sys._esys_034 (sys._esys_035 sys._osys_444 sys._isys_446)\n"
"var !sys.indexstring sys._esys_034\n"
"type sys._esys_037 {}\n"
- "type sys._osys_442 {_esys_440 sys.string}\n"
- "type sys._isys_444 {_esys_441 sys.int64}\n"
- "type sys._esys_036 (sys._esys_037 sys._osys_442 sys._isys_444)\n"
+ "type sys._osys_453 {_esys_451 sys.string}\n"
+ "type sys._isys_455 {_esys_452 sys.int64}\n"
+ "type sys._esys_036 (sys._esys_037 sys._osys_453 sys._isys_455)\n"
"var !sys.intstring sys._esys_036\n"
"type sys._esys_039 {}\n"
- "type sys._osys_451 {_esys_448 sys.string}\n"
+ "type sys._osys_462 {_esys_459 sys.string}\n"
"type sys._esys_040 *sys.uint8\n"
- "type sys._isys_453 {_esys_449 sys._esys_040 _esys_450 sys.int32}\n"
- "type sys._esys_038 (sys._esys_039 sys._osys_451 sys._isys_453)\n"
+ "type sys._isys_464 {_esys_460 sys._esys_040 _esys_461 sys.int32}\n"
+ "type sys._esys_038 (sys._esys_039 sys._osys_462 sys._isys_464)\n"
"var !sys.byteastring sys._esys_038\n"
"type sys._esys_042 {}\n"
"type sys._esys_043 <>\n"
- "type sys._osys_462 {_esys_458 sys._esys_043}\n"
+ "type sys._osys_473 {_esys_469 sys._esys_043}\n"
"type sys._esys_044 *sys.uint8\n"
"type sys._esys_045 *sys.uint8\n"
- "type sys._ssys_469 {}\n"
- "type sys._esys_046 *sys._ssys_469\n"
- "type sys._isys_464 {_esys_459 sys._esys_044 _esys_460 sys._esys_045 _esys_461 sys._esys_046}\n"
- "type sys._esys_041 (sys._esys_042 sys._osys_462 sys._isys_464)\n"
+ "type sys._ssys_480 {}\n"
+ "type sys._esys_046 *sys._ssys_480\n"
+ "type sys._isys_475 {_esys_470 sys._esys_044 _esys_471 sys._esys_045 _esys_472 sys._esys_046}\n"
+ "type sys._esys_041 (sys._esys_042 sys._osys_473 sys._isys_475)\n"
"var !sys.mkiface sys._esys_041\n"
"type sys._esys_048 {}\n"
- "type sys._osys_473 {_esys_472 sys.int32}\n"
+ "type sys._osys_484 {_esys_483 sys.int32}\n"
"type sys._esys_049 {}\n"
- "type sys._esys_047 (sys._esys_048 sys._osys_473 sys._esys_049)\n"
+ "type sys._esys_047 (sys._esys_048 sys._osys_484 sys._esys_049)\n"
"var !sys.argc sys._esys_047\n"
"type sys._esys_051 {}\n"
- "type sys._osys_477 {_esys_476 sys.int32}\n"
+ "type sys._osys_488 {_esys_487 sys.int32}\n"
"type sys._esys_052 {}\n"
- "type sys._esys_050 (sys._esys_051 sys._osys_477 sys._esys_052)\n"
+ "type sys._esys_050 (sys._esys_051 sys._osys_488 sys._esys_052)\n"
"var !sys.envc sys._esys_050\n"
"type sys._esys_054 {}\n"
- "type sys._osys_482 {_esys_480 sys.string}\n"
- "type sys._isys_484 {_esys_481 sys.int32}\n"
- "type sys._esys_053 (sys._esys_054 sys._osys_482 sys._isys_484)\n"
+ "type sys._osys_493 {_esys_491 sys.string}\n"
+ "type sys._isys_495 {_esys_492 sys.int32}\n"
+ "type sys._esys_053 (sys._esys_054 sys._osys_493 sys._isys_495)\n"
"var !sys.argv sys._esys_053\n"
"type sys._esys_056 {}\n"
- "type sys._osys_490 {_esys_488 sys.string}\n"
- "type sys._isys_492 {_esys_489 sys.int32}\n"
- "type sys._esys_055 (sys._esys_056 sys._osys_490 sys._isys_492)\n"
+ "type sys._osys_501 {_esys_499 sys.string}\n"
+ "type sys._isys_503 {_esys_500 sys.int32}\n"
+ "type sys._esys_055 (sys._esys_056 sys._osys_501 sys._isys_503)\n"
"var !sys.envv sys._esys_055\n"
"type sys._esys_058 {}\n"
- "type sys._osys_499 {_esys_496 sys.float64 _esys_497 sys.int32}\n"
- "type sys._isys_501 {_esys_498 sys.float64}\n"
- "type sys._esys_057 (sys._esys_058 sys._osys_499 sys._isys_501)\n"
+ "type sys._osys_510 {_esys_507 sys.float64 _esys_508 sys.int32}\n"
+ "type sys._isys_512 {_esys_509 sys.float64}\n"
+ "type sys._esys_057 (sys._esys_058 sys._osys_510 sys._isys_512)\n"
"var !sys.frexp sys._esys_057\n"
"type sys._esys_060 {}\n"
- "type sys._osys_508 {_esys_505 sys.float64}\n"
- "type sys._isys_510 {_esys_506 sys.float64 _esys_507 sys.int32}\n"
- "type sys._esys_059 (sys._esys_060 sys._osys_508 sys._isys_510)\n"
+ "type sys._osys_519 {_esys_516 sys.float64}\n"
+ "type sys._isys_521 {_esys_517 sys.float64 _esys_518 sys.int32}\n"
+ "type sys._esys_059 (sys._esys_060 sys._osys_519 sys._isys_521)\n"
"var !sys.ldexp sys._esys_059\n"
"type sys._esys_062 {}\n"
- "type sys._osys_518 {_esys_515 sys.float64 _esys_516 sys.float64}\n"
- "type sys._isys_520 {_esys_517 sys.float64}\n"
- "type sys._esys_061 (sys._esys_062 sys._osys_518 sys._isys_520)\n"
+ "type sys._osys_529 {_esys_526 sys.float64 _esys_527 sys.float64}\n"
+ "type sys._isys_531 {_esys_528 sys.float64}\n"
+ "type sys._esys_061 (sys._esys_062 sys._osys_529 sys._isys_531)\n"
"var !sys.modf sys._esys_061\n"
"type sys._esys_064 {}\n"
- "type sys._osys_527 {_esys_524 sys.bool}\n"
- "type sys._isys_529 {_esys_525 sys.float64 _esys_526 sys.int32}\n"
- "type sys._esys_063 (sys._esys_064 sys._osys_527 sys._isys_529)\n"
+ "type sys._osys_538 {_esys_535 sys.bool}\n"
+ "type sys._isys_540 {_esys_536 sys.float64 _esys_537 sys.int32}\n"
+ "type sys._esys_063 (sys._esys_064 sys._osys_538 sys._isys_540)\n"
"var !sys.isInf sys._esys_063\n"
"type sys._esys_066 {}\n"
- "type sys._osys_536 {_esys_534 sys.bool}\n"
- "type sys._isys_538 {_esys_535 sys.float64}\n"
- "type sys._esys_065 (sys._esys_066 sys._osys_536 sys._isys_538)\n"
+ "type sys._osys_547 {_esys_545 sys.bool}\n"
+ "type sys._isys_549 {_esys_546 sys.float64}\n"
+ "type sys._esys_065 (sys._esys_066 sys._osys_547 sys._isys_549)\n"
"var !sys.isNaN sys._esys_065\n"
"type sys._esys_068 {}\n"
- "type sys._osys_544 {_esys_542 sys.float64}\n"
- "type sys._isys_546 {_esys_543 sys.int32}\n"
- "type sys._esys_067 (sys._esys_068 sys._osys_544 sys._isys_546)\n"
+ "type sys._osys_555 {_esys_553 sys.float64}\n"
+ "type sys._isys_557 {_esys_554 sys.int32}\n"
+ "type sys._esys_067 (sys._esys_068 sys._osys_555 sys._isys_557)\n"
"var !sys.Inf sys._esys_067\n"
"type sys._esys_070 {}\n"
- "type sys._osys_551 {_esys_550 sys.float64}\n"
+ "type sys._osys_562 {_esys_561 sys.float64}\n"
"type sys._esys_071 {}\n"
- "type sys._esys_069 (sys._esys_070 sys._osys_551 sys._esys_071)\n"
+ "type sys._esys_069 (sys._esys_070 sys._osys_562 sys._esys_071)\n"
"var !sys.NaN sys._esys_069\n"
"type sys._esys_073 {}\n"
"type sys._esys_075 [sys.any] sys.any\n"
"type sys._esys_074 *sys._esys_075\n"
- "type sys._osys_554 {hmap sys._esys_074}\n"
- "type sys._isys_556 {keysize sys.uint32 valsize sys.uint32 keyalg sys.uint32 valalg sys.uint32 hint sys.uint32}\n"
- "type sys._esys_072 (sys._esys_073 sys._osys_554 sys._isys_556)\n"
+ "type sys._osys_565 {hmap sys._esys_074}\n"
+ "type sys._isys_567 {keysize sys.uint32 valsize sys.uint32 keyalg sys.uint32 valalg sys.uint32 hint sys.uint32}\n"
+ "type sys._esys_072 (sys._esys_073 sys._osys_565 sys._isys_567)\n"
"var !sys.newmap sys._esys_072\n"
"type sys._esys_077 {}\n"
- "type sys._osys_565 {val sys.any}\n"
+ "type sys._osys_576 {val sys.any}\n"
"type sys._esys_079 [sys.any] sys.any\n"
"type sys._esys_078 *sys._esys_079\n"
- "type sys._isys_567 {hmap sys._esys_078 key sys.any}\n"
- "type sys._esys_076 (sys._esys_077 sys._osys_565 sys._isys_567)\n"
+ "type sys._isys_578 {hmap sys._esys_078 key sys.any}\n"
+ "type sys._esys_076 (sys._esys_077 sys._osys_576 sys._isys_578)\n"
"var !sys.mapaccess1 sys._esys_076\n"
"type sys._esys_081 {}\n"
- "type sys._osys_573 {val sys.any pres sys.bool}\n"
+ "type sys._osys_584 {val sys.any pres sys.bool}\n"
"type sys._esys_083 [sys.any] sys.any\n"
"type sys._esys_082 *sys._esys_083\n"
- "type sys._isys_575 {hmap sys._esys_082 key sys.any}\n"
- "type sys._esys_080 (sys._esys_081 sys._osys_573 sys._isys_575)\n"
+ "type sys._isys_586 {hmap sys._esys_082 key sys.any}\n"
+ "type sys._esys_080 (sys._esys_081 sys._osys_584 sys._isys_586)\n"
"var !sys.mapaccess2 sys._esys_080\n"
"type sys._esys_085 {}\n"
"type sys._esys_086 {}\n"
"type sys._esys_088 [sys.any] sys.any\n"
"type sys._esys_087 *sys._esys_088\n"
- "type sys._isys_582 {hmap sys._esys_087 key sys.any val sys.any}\n"
- "type sys._esys_084 (sys._esys_085 sys._esys_086 sys._isys_582)\n"
+ "type sys._isys_593 {hmap sys._esys_087 key sys.any val sys.any}\n"
+ "type sys._esys_084 (sys._esys_085 sys._esys_086 sys._isys_593)\n"
"var !sys.mapassign1 sys._esys_084\n"
"type sys._esys_090 {}\n"
"type sys._esys_091 {}\n"
"type sys._esys_093 [sys.any] sys.any\n"
"type sys._esys_092 *sys._esys_093\n"
- "type sys._isys_588 {hmap sys._esys_092 key sys.any val sys.any pres sys.bool}\n"
- "type sys._esys_089 (sys._esys_090 sys._esys_091 sys._isys_588)\n"
+ "type sys._isys_599 {hmap sys._esys_092 key sys.any val sys.any pres sys.bool}\n"
+ "type sys._esys_089 (sys._esys_090 sys._esys_091 sys._isys_599)\n"
"var !sys.mapassign2 sys._esys_089\n"
"type sys._esys_095 {}\n"
"type sys._esys_097 1 sys.any\n"
"type sys._esys_096 *sys._esys_097\n"
- "type sys._osys_595 {hchan sys._esys_096}\n"
- "type sys._isys_597 {elemsize sys.uint32 elemalg sys.uint32 hint sys.uint32}\n"
- "type sys._esys_094 (sys._esys_095 sys._osys_595 sys._isys_597)\n"
+ "type sys._osys_606 {hchan sys._esys_096}\n"
+ "type sys._isys_608 {elemsize sys.uint32 elemalg sys.uint32 hint sys.uint32}\n"
+ "type sys._esys_094 (sys._esys_095 sys._osys_606 sys._isys_608)\n"
"var !sys.newchan sys._esys_094\n"
"type sys._esys_099 {}\n"
- "type sys._osys_604 {elem sys.any}\n"
+ "type sys._osys_615 {elem sys.any}\n"
"type sys._esys_101 1 sys.any\n"
"type sys._esys_100 *sys._esys_101\n"
- "type sys._isys_606 {hchan sys._esys_100}\n"
- "type sys._esys_098 (sys._esys_099 sys._osys_604 sys._isys_606)\n"
+ "type sys._isys_617 {hchan sys._esys_100}\n"
+ "type sys._esys_098 (sys._esys_099 sys._osys_615 sys._isys_617)\n"
"var !sys.chanrecv1 sys._esys_098\n"
"type sys._esys_103 {}\n"
- "type sys._osys_611 {elem sys.any pres sys.bool}\n"
+ "type sys._osys_622 {elem sys.any pres sys.bool}\n"
"type sys._esys_105 1 sys.any\n"
"type sys._esys_104 *sys._esys_105\n"
- "type sys._isys_613 {hchan sys._esys_104}\n"
- "type sys._esys_102 (sys._esys_103 sys._osys_611 sys._isys_613)\n"
+ "type sys._isys_624 {hchan sys._esys_104}\n"
+ "type sys._esys_102 (sys._esys_103 sys._osys_622 sys._isys_624)\n"
"var !sys.chanrecv2 sys._esys_102\n"
"type sys._esys_107 {}\n"
- "type sys._osys_619 {elem sys.any pres sys.bool}\n"
+ "type sys._osys_630 {pres sys.bool}\n"
"type sys._esys_109 1 sys.any\n"
"type sys._esys_108 *sys._esys_109\n"
- "type sys._isys_621 {hchan sys._esys_108}\n"
- "type sys._esys_106 (sys._esys_107 sys._osys_619 sys._isys_621)\n"
+ "type sys._esys_110 *sys.any\n"
+ "type sys._isys_632 {hchan sys._esys_108 elem sys._esys_110}\n"
+ "type sys._esys_106 (sys._esys_107 sys._osys_630 sys._isys_632)\n"
"var !sys.chanrecv3 sys._esys_106\n"
- "type sys._esys_111 {}\n"
"type sys._esys_112 {}\n"
- "type sys._esys_114 1 sys.any\n"
- "type sys._esys_113 *sys._esys_114\n"
- "type sys._isys_627 {hchan sys._esys_113 elem sys.any}\n"
- "type sys._esys_110 (sys._esys_111 sys._esys_112 sys._isys_627)\n"
- "var !sys.chansend1 sys._esys_110\n"
- "type sys._esys_116 {}\n"
- "type sys._osys_632 {pres sys.bool}\n"
- "type sys._esys_118 1 sys.any\n"
- "type sys._esys_117 *sys._esys_118\n"
- "type sys._isys_634 {hchan sys._esys_117 elem sys.any}\n"
- "type sys._esys_115 (sys._esys_116 sys._osys_632 sys._isys_634)\n"
- "var !sys.chansend2 sys._esys_115\n"
- "type sys._esys_120 {}\n"
- "type sys._esys_121 *sys.uint8\n"
- "type sys._osys_640 {sel sys._esys_121}\n"
- "type sys._isys_642 {size sys.uint32}\n"
- "type sys._esys_119 (sys._esys_120 sys._osys_640 sys._isys_642)\n"
- "var !sys.newselect sys._esys_119\n"
- "type sys._esys_123 {}\n"
- "type sys._osys_647 {selected sys.bool}\n"
- "type sys._esys_124 *sys.uint8\n"
- "type sys._esys_126 1 sys.any\n"
- "type sys._esys_125 *sys._esys_126\n"
- "type sys._isys_649 {sel sys._esys_124 hchan sys._esys_125 elem sys.any}\n"
- "type sys._esys_122 (sys._esys_123 sys._osys_647 sys._isys_649)\n"
- "var !sys.selectsend sys._esys_122\n"
- "type sys._esys_128 {}\n"
- "type sys._osys_656 {selected sys.bool}\n"
- "type sys._esys_129 *sys.uint8\n"
- "type sys._esys_131 1 sys.any\n"
- "type sys._esys_130 *sys._esys_131\n"
- "type sys._esys_132 *sys.any\n"
- "type sys._isys_658 {sel sys._esys_129 hchan sys._esys_130 elem sys._esys_132}\n"
- "type sys._esys_127 (sys._esys_128 sys._osys_656 sys._isys_658)\n"
- "var !sys.selectrecv sys._esys_127\n"
- "type sys._esys_134 {}\n"
+ "type sys._esys_113 {}\n"
+ "type sys._esys_115 1 sys.any\n"
+ "type sys._esys_114 *sys._esys_115\n"
+ "type sys._isys_638 {hchan sys._esys_114 elem sys.any}\n"
+ "type sys._esys_111 (sys._esys_112 sys._esys_113 sys._isys_638)\n"
+ "var !sys.chansend1 sys._esys_111\n"
+ "type sys._esys_117 {}\n"
+ "type sys._osys_643 {pres sys.bool}\n"
+ "type sys._esys_119 1 sys.any\n"
+ "type sys._esys_118 *sys._esys_119\n"
+ "type sys._isys_645 {hchan sys._esys_118 elem sys.any}\n"
+ "type sys._esys_116 (sys._esys_117 sys._osys_643 sys._isys_645)\n"
+ "var !sys.chansend2 sys._esys_116\n"
+ "type sys._esys_121 {}\n"
+ "type sys._esys_122 *sys.uint8\n"
+ "type sys._osys_651 {sel sys._esys_122}\n"
+ "type sys._isys_653 {size sys.uint32}\n"
+ "type sys._esys_120 (sys._esys_121 sys._osys_651 sys._isys_653)\n"
+ "var !sys.newselect sys._esys_120\n"
+ "type sys._esys_124 {}\n"
+ "type sys._osys_658 {selected sys.bool}\n"
+ "type sys._esys_125 *sys.uint8\n"
+ "type sys._esys_127 1 sys.any\n"
+ "type sys._esys_126 *sys._esys_127\n"
+ "type sys._isys_660 {sel sys._esys_125 hchan sys._esys_126 elem sys.any}\n"
+ "type sys._esys_123 (sys._esys_124 sys._osys_658 sys._isys_660)\n"
+ "var !sys.selectsend sys._esys_123\n"
+ "type sys._esys_129 {}\n"
+ "type sys._osys_667 {selected sys.bool}\n"
+ "type sys._esys_130 *sys.uint8\n"
+ "type sys._esys_132 1 sys.any\n"
+ "type sys._esys_131 *sys._esys_132\n"
+ "type sys._esys_133 *sys.any\n"
+ "type sys._isys_669 {sel sys._esys_130 hchan sys._esys_131 elem sys._esys_133}\n"
+ "type sys._esys_128 (sys._esys_129 sys._osys_667 sys._isys_669)\n"
+ "var !sys.selectrecv sys._esys_128\n"
"type sys._esys_135 {}\n"
- "type sys._esys_136 *sys.uint8\n"
- "type sys._isys_665 {sel sys._esys_136}\n"
- "type sys._esys_133 (sys._esys_134 sys._esys_135 sys._isys_665)\n"
- "var !sys.selectgo sys._esys_133\n"
- "type sys._esys_138 {}\n"
+ "type sys._esys_136 {}\n"
+ "type sys._esys_137 *sys.uint8\n"
+ "type sys._isys_676 {sel sys._esys_137}\n"
+ "type sys._esys_134 (sys._esys_135 sys._esys_136 sys._isys_676)\n"
+ "var !sys.selectgo sys._esys_134\n"
"type sys._esys_139 {}\n"
"type sys._esys_140 {}\n"
- "type sys._esys_137 (sys._esys_138 sys._esys_139 sys._esys_140)\n"
- "var !sys.gosched sys._esys_137\n"
- "type sys._esys_142 {}\n"
+ "type sys._esys_141 {}\n"
+ "type sys._esys_138 (sys._esys_139 sys._esys_140 sys._esys_141)\n"
+ "var !sys.gosched sys._esys_138\n"
"type sys._esys_143 {}\n"
"type sys._esys_144 {}\n"
- "type sys._esys_141 (sys._esys_142 sys._esys_143 sys._esys_144)\n"
- "var !sys.goexit sys._esys_141\n"
- "type sys._esys_146 {}\n"
- "type sys._osys_674 {_esys_671 sys.string _esys_672 sys.bool}\n"
- "type sys._isys_676 {_esys_673 sys.string}\n"
- "type sys._esys_145 (sys._esys_146 sys._osys_674 sys._isys_676)\n"
- "var !sys.readfile sys._esys_145\n"
- "type sys._esys_148 {}\n"
- "type sys._osys_683 {_esys_680 sys.bool}\n"
- "type sys._isys_685 {_esys_681 sys.string _esys_682 sys.string}\n"
- "type sys._esys_147 (sys._esys_148 sys._osys_683 sys._isys_685)\n"
- "var !sys.writefile sys._esys_147\n"
- "type sys._esys_150 {}\n"
- "type sys._osys_695 {_esys_690 sys.int32 _esys_691 sys.int32}\n"
- "type sys._esys_151 *sys.uint8\n"
- "type sys._isys_697 {_esys_692 sys._esys_151 _esys_693 sys.int32 _esys_694 sys.int32}\n"
- "type sys._esys_149 (sys._esys_150 sys._osys_695 sys._isys_697)\n"
- "var !sys.bytestorune sys._esys_149\n"
- "type sys._esys_153 {}\n"
- "type sys._osys_708 {_esys_703 sys.int32 _esys_704 sys.int32}\n"
- "type sys._isys_710 {_esys_705 sys.string _esys_706 sys.int32 _esys_707 sys.int32}\n"
- "type sys._esys_152 (sys._esys_153 sys._osys_708 sys._isys_710)\n"
- "var !sys.stringtorune sys._esys_152\n"
- "type sys._esys_155 {}\n"
+ "type sys._esys_145 {}\n"
+ "type sys._esys_142 (sys._esys_143 sys._esys_144 sys._esys_145)\n"
+ "var !sys.goexit sys._esys_142\n"
+ "type sys._esys_147 {}\n"
+ "type sys._osys_685 {_esys_682 sys.string _esys_683 sys.bool}\n"
+ "type sys._isys_687 {_esys_684 sys.string}\n"
+ "type sys._esys_146 (sys._esys_147 sys._osys_685 sys._isys_687)\n"
+ "var !sys.readfile sys._esys_146\n"
+ "type sys._esys_149 {}\n"
+ "type sys._osys_694 {_esys_691 sys.bool}\n"
+ "type sys._isys_696 {_esys_692 sys.string _esys_693 sys.string}\n"
+ "type sys._esys_148 (sys._esys_149 sys._osys_694 sys._isys_696)\n"
+ "var !sys.writefile sys._esys_148\n"
+ "type sys._esys_151 {}\n"
+ "type sys._osys_706 {_esys_701 sys.int32 _esys_702 sys.int32}\n"
+ "type sys._esys_152 *sys.uint8\n"
+ "type sys._isys_708 {_esys_703 sys._esys_152 _esys_704 sys.int32 _esys_705 sys.int32}\n"
+ "type sys._esys_150 (sys._esys_151 sys._osys_706 sys._isys_708)\n"
+ "var !sys.bytestorune sys._esys_150\n"
+ "type sys._esys_154 {}\n"
+ "type sys._osys_719 {_esys_714 sys.int32 _esys_715 sys.int32}\n"
+ "type sys._isys_721 {_esys_716 sys.string _esys_717 sys.int32 _esys_718 sys.int32}\n"
+ "type sys._esys_153 (sys._esys_154 sys._osys_719 sys._isys_721)\n"
+ "var !sys.stringtorune sys._esys_153\n"
"type sys._esys_156 {}\n"
- "type sys._isys_717 {_esys_716 sys.int32}\n"
- "type sys._esys_154 (sys._esys_155 sys._esys_156 sys._isys_717)\n"
- "var !sys.exit sys._esys_154\n"
- "type sys._esys_158 {}\n"
+ "type sys._esys_157 {}\n"
+ "type sys._isys_728 {_esys_727 sys.int32}\n"
+ "type sys._esys_155 (sys._esys_156 sys._esys_157 sys._isys_728)\n"
+ "var !sys.exit sys._esys_155\n"
"type sys._esys_159 {}\n"
"type sys._esys_160 {}\n"
- "type sys._esys_157 (sys._esys_158 sys._esys_159 sys._esys_160)\n"
+ "type sys._esys_161 {}\n"
+ "type sys._esys_158 (sys._esys_159 sys._esys_160 sys._esys_161)\n"
"))\n"
;
diff -r a0789f16988a -r a941613b3268 src/cmd/gc/walk.c
--- a/src/cmd/gc/walk.c Fri Jul 25 17:03:27 2008 -0700
+++ b/src/cmd/gc/walk.c Sat Jul 26 14:21:21 2008 -0700
@@ -1910,7 +1910,6 @@
goto shape;
// chanrecv2(hchan *chan any) (elem any, pres bool);
-
t = fixchan(n->right->left->type);
if(t == T)
break;
@@ -1950,19 +1949,27 @@
break;
recv2:
- // chanrecv2(hchan *chan any) (elem any, pres bool);
-fatal("recv2 not yet");
+ // chanrecv3(hchan *chan any, *elem any) (pres bool);
t = fixchan(n->right->type);
if(t == T)
break;
a = n->right; // chan
r = a;
+ a = n->left; // elem
+ if(a == N) {
+ a = nil;
+ a = nod(OLITERAL, N, N);
+ a->val.ctype = CTNIL;
+ a->val.vval = 0;
+ } else
+ a = nod(OADDR, a, N);
- on = syslook("chanrecv2", 1);
+ on = syslook("chanrecv3", 1);
argtype(on, t->type); // any-1
argtype(on, t->type); // any-2
+
r = nod(OCALL, on, r);
n->right = r;
r = n;
diff -r a0789f16988a -r a941613b3268 src/runtime/chan.c
--- a/src/runtime/chan.c Fri Jul 25 17:03:27 2008 -0700
+++ b/src/runtime/chan.c Sat Jul 26 14:21:21 2008 -0700
@@ -33,8 +33,6 @@
uint32 elemsize;
uint32 dataqsiz; // size of the circular q
uint32 qcount; // total data in the q
- uint16 eo; // vararg of element
- uint16 po; // vararg of present bool
Alg* elemalg; // interface for element type
Link* senddataq; // pointer for sender
Link* recvdataq; // pointer for receiver
@@ -65,9 +63,12 @@
{
uint16 tcase; // total count of scase[]
uint16 ncase; // currently filled scase[]
+ Select* link; // for freelist
Scase scase[1]; // one per case
};
+static Select* selfree[20];
+
static SudoG* dequeue(WaitQ*, Hchan*);
static void enqueue(WaitQ*, SudoG*);
static SudoG* allocsg(Hchan*);
@@ -119,10 +120,6 @@
c->dataqsiz = hint;
}
- // these calculations are compiler dependent
- c->eo = rnd(sizeof(c), elemsize);
- c->po = rnd(c->eo+elemsize, 1);
-
ret = c;
FLUSH(&ret);
@@ -139,216 +136,205 @@
}
}
+/*
+ * generic single channel send/recv
+ * if the bool pointer is nil,
+ * then the full exchange will
+ * occur. if pres is not nil,
+ * then the protocol will not
+ * sleep but return if it could
+ * not complete
+ */
+void
+sendchan(Hchan *c, byte *ep, bool *pres)
+{
+ SudoG *sg;
+ G* gp;
+
+ if(debug) {
+ prints("chansend: chan=");
+ sys·printpointer(c);
+ prints("; elem=");
+ c->elemalg->print(c->elemsize, ep);
+ prints("\n");
+ }
+
+ if(c->dataqsiz > 0)
+ goto asynch;
+
+ sg = dequeue(&c->recvq, c);
+ if(sg != nil) {
+ if(ep != nil)
+ c->elemalg->copy(c->elemsize, sg->elem, ep);
+
+ gp = sg->g;
+ gp->param = sg;
+ gp->status = Grunnable;
+
+ if(pres != nil)
+ *pres = true;
+ return;
+ }
+
+ if(pres != nil) {
+ *pres = false;
+ return;
+ }
+
+ sg = allocsg(c);
+ if(ep != nil)
+ c->elemalg->copy(c->elemsize, sg->elem, ep);
+ g->param = nil;
+ g->status = Gwaiting;
+ enqueue(&c->sendq, sg);
+ sys·gosched();
+
+ sg = g->param;
+ freesg(c, sg);
+ return;
+
+asynch:
+ while(c->qcount >= c->dataqsiz) {
+ sg = allocsg(c);
+ g->status = Gwaiting;
+ enqueue(&c->sendq, sg);
+ sys·gosched();
+ }
+ if(ep != nil)
+ c->elemalg->copy(c->elemsize, c->senddataq->elem, ep);
+ c->senddataq = c->senddataq->link;
+ c->qcount++;
+
+ sg = dequeue(&c->recvq, c);
+ if(sg != nil) {
+ gp = sg->g;
+ freesg(c, sg);
+ gp->status = Grunnable;
+ }
+}
+
+static void
+chanrecv(Hchan* c, byte *ep, bool* pres)
+{
+ SudoG *sg;
+ G *gp;
+
+ if(debug) {
+ prints("chanrecv: chan=");
+ sys·printpointer(c);
+ prints("\n");
+ }
+
+ if(c->dataqsiz > 0)
+ goto asynch;
+
+ sg = dequeue(&c->sendq, c);
+ if(sg != nil) {
+ c->elemalg->copy(c->elemsize, ep, sg->elem);
+
+ gp = sg->g;
+ gp->param = sg;
+ gp->status = Grunnable;
+
+ if(pres != nil)
+ *pres = true;
+ return;
+ }
+
+ if(pres != nil) {
+ *pres = false;
+ return;
+ }
+
+ sg = allocsg(c);
+ g->param = nil;
+ g->status = Gwaiting;
+ enqueue(&c->recvq, sg);
+ sys·gosched();
+
+ sg = g->param;
+ c->elemalg->copy(c->elemsize, ep, sg->elem);
+ freesg(c, sg);
+ return;
+
+asynch:
+ while(c->qcount <= 0) {
+ sg = allocsg(c);
+ g->status = Gwaiting;
+ enqueue(&c->recvq, sg);
+ sys·gosched();
+ }
+ c->elemalg->copy(c->elemsize, ep, c->recvdataq->elem);
+ c->recvdataq = c->recvdataq->link;
+ c->qcount--;
+ sg = dequeue(&c->sendq, c);
+ if(sg != nil) {
+ gp = sg->g;
+ freesg(c, sg);
+ gp->status = Grunnable;
+ }
+}
+
// chansend1(hchan *chan any, elem any);
void
sys·chansend1(Hchan* c, ...)
{
+ int32 o;
byte *ae;
- SudoG *sgr;
- G* gr;
- ae = (byte*)&c + c->eo;
- if(debug) {
- prints("chansend: chan=");
- sys·printpointer(c);
- prints("; elem=");
- c->elemalg->print(c->elemsize, ae);
- prints("\n");
- }
- if(c->dataqsiz > 0)
- goto asynch;
-
- sgr = dequeue(&c->recvq, c);
- if(sgr != nil) {
- c->elemalg->copy(c->elemsize, sgr->elem, ae);
-
- gr = sgr->g;
- gr->param = sgr;
- gr->status = Grunnable;
- return;
- }
-
- sgr = allocsg(c);
- c->elemalg->copy(c->elemsize, sgr->elem, ae);
- g->status = Gwaiting;
- enqueue(&c->sendq, sgr);
- sys·gosched();
- return;
-
-asynch:
- while(c->qcount >= c->dataqsiz) {
- sgr = allocsg(c);
- g->status = Gwaiting;
- enqueue(&c->sendq, sgr);
- sys·gosched();
- }
- c->elemalg->copy(c->elemsize, c->senddataq->elem, ae);
- c->senddataq = c->senddataq->link;
- c->qcount++;
- sgr = dequeue(&c->recvq, c);
- if(sgr != nil) {
- gr = sgr->g;
- freesg(c, sgr);
- gr->status = Grunnable;
- }
+ o = rnd(sizeof(c), c->elemsize);
+ ae = (byte*)&c + o;
+ sendchan(c, ae, nil);
}
// chansend2(hchan *chan any, elem any) (pres bool);
void
sys·chansend2(Hchan* c, ...)
{
+ int32 o;
byte *ae, *ap;
- SudoG *sgr;
- G *gr;
- ae = (byte*)&c + c->eo;
- ap = (byte*)&c + c->po;
+ o = rnd(sizeof(c), c->elemsize);
+ ae = (byte*)&c + o;
+ o = rnd(o+c->elemsize, 1);
+ ap = (byte*)&c + o;
- if(debug) {
- prints("chansend: chan=");
- sys·printpointer(c);
- prints("; elem=");
- c->elemalg->print(c->elemsize, ae);
- prints("\n");
- }
- if(c->dataqsiz > 0)
- goto asynch;
-
- sgr = dequeue(&c->recvq, c);
- if(sgr != nil) {
- gr = sgr->g;
- c->elemalg->copy(c->elemsize, sgr->elem, ae);
-
- gr->param = sgr;
- gr->status = Grunnable;
- *ap = true;
- return;
- }
- *ap = false;
- return;
-
-asynch:
- if(c->qcount >= c->dataqsiz) {
- *ap = false;
- return;
- }
- c->elemalg->copy(c->elemsize, c->senddataq->elem, ae);
- c->senddataq = c->senddataq->link;
- c->qcount++;
- sgr = dequeue(&c->recvq, c);
- if(gr != nil) {
- gr = sgr->g;
- freesg(c, sgr);
- gr->status = Grunnable;
- }
- *ap = true;
+ sendchan(c, ae, ap);
}
// chanrecv1(hchan *chan any) (elem any);
void
sys·chanrecv1(Hchan* c, ...)
{
+ int32 o;
byte *ae;
- SudoG *sgs;
- G *gs;
- ae = (byte*)&c + c->eo;
- if(debug) {
- prints("chanrecv1: chan=");
- sys·printpointer(c);
- prints("\n");
- }
- if(c->dataqsiz > 0)
- goto asynch;
+ o = rnd(sizeof(c), c->elemsize);
+ ae = (byte*)&c + o;
- sgs = dequeue(&c->sendq, c);
- if(sgs != nil) {
- c->elemalg->copy(c->elemsize, ae, sgs->elem);
-
- gs = sgs->g;
- gs->param = sgs;
- gs->status = Grunnable;
-
- freesg(c, sgs);
- return;
- }
- sgs = allocsg(c);
- g->status = Gwaiting;
- enqueue(&c->recvq, sgs);
- sys·gosched();
- c->elemalg->copy(c->elemsize, ae, sgs->elem);
- freesg(c, sgs);
- return;
-
-asynch:
- while(c->qcount <= 0) {
- sgs = allocsg(c);
- g->status = Gwaiting;
- enqueue(&c->recvq, sgs);
- sys·gosched();
- }
- c->elemalg->copy(c->elemsize, ae, c->recvdataq->elem);
- c->recvdataq = c->recvdataq->link;
- c->qcount--;
- sgs = dequeue(&c->sendq, c);
- if(gs != nil) {
- gs = sgs->g;
- freesg(c, sgs);
-
- gs->status = Grunnable;
- }
+ chanrecv(c, ae, nil);
}
// chanrecv2(hchan *chan any) (elem any, pres bool);
void
sys·chanrecv2(Hchan* c, ...)
{
+ int32 o;
byte *ae, *ap;
- SudoG *sgs;
- G *gs;
- ae = (byte*)&c + c->eo;
- ap = (byte*)&c + c->po;
+ o = rnd(sizeof(c), c->elemsize);
+ ae = (byte*)&c + o;
+ o = rnd(o+c->elemsize, 1);
+ ap = (byte*)&c + o;
- if(debug) {
- prints("chanrecv2: chan=");
- sys·printpointer(c);
- prints("\n");
- }
- if(c->dataqsiz > 0)
- goto asynch;
+ chanrecv(c, ae, ap);
+}
- sgs = dequeue(&c->sendq, c);
- if(sgs != nil) {
- c->elemalg->copy(c->elemsize, ae, sgs->elem);
-
- gs = sgs->g;
- gs->param = sgs;
- gs->status = Grunnable;
-
- freesg(c, sgs);
- *ap = true;
- return;
- }
- *ap = false;
- return;
-
-asynch:
- if(c->qcount <= 0) {
- *ap = false;
- return;
- }
- c->elemalg->copy(c->elemsize, ae, c->recvdataq->elem);
- c->recvdataq = c->recvdataq->link;
- c->qcount--;
- sgs = dequeue(&c->sendq, c);
- if(sgs != nil) {
- gs = sgs->g;
- freesg(c, sgs);
-
- gs->status = Grunnable;
- }
- *ap = true;
+// chanrecv3(hchan *chan any, elem *any) (pres bool);
+void
+sys·chanrecv3(Hchan* c, byte* ep, byte pres)
+{
+ chanrecv(c, ep, &pres);
}
// newselect(size uint32) (sel *byte);
@@ -360,7 +346,16 @@
n = 0;
if(size > 1)
n = size-1;
- sel = mal(sizeof(*sel) + n*sizeof(sel->scase[0]));
+
+ sel = nil;
+ if(size >= 1 && size < nelem(selfree)) {
+ sel = selfree[size];
+ if(sel != nil)
+ selfree[size] = sel->link;
+ }
+ if(sel == nil)
+ sel = mal(sizeof(*sel) + n*sizeof(sel->scase[0]));
+
sel->tcase = size;
sel->ncase = 0;
FLUSH(&sel);
@@ -419,7 +414,7 @@
void
sys·selectrecv(Select *sel, Hchan *c, ...)
{
- int32 i, epo;
+ int32 i, eo;
Scase *cas;
// nil cases do not compete
@@ -435,11 +430,11 @@
cas->pc = sys·getcallerpc(&sel);
cas->chan = c;
- epo = rnd(sizeof(sel), sizeof(c));
- epo = rnd(epo+sizeof(c), sizeof(byte*));
- cas->so = rnd(epo+sizeof(byte*), 1);
+ eo = rnd(sizeof(sel), sizeof(c));
+ eo = rnd(eo+sizeof(c), sizeof(byte*));
+ cas->so = rnd(eo+sizeof(byte*), 1);
cas->send = 0;
- cas->u.elemp = *(byte**)((byte*)&sel + epo);
+ cas->u.elemp = *(byte**)((byte*)&sel + eo);
if(debug) {
prints("newselect s=");
@@ -456,6 +451,8 @@
}
}
+uint32 xxx = 0;
+
// selectgo(sel *byte);
void
sys·selectgo(Select *sel)
@@ -468,7 +465,7 @@
byte *ae, *as;
- if(0) {
+ if(xxx) {
prints("selectgo: sel=");
sys·printpointer(sel);
prints("\n");
@@ -502,20 +499,23 @@
c = cas->chan;
if(c->dataqsiz > 0) {
- if(cas->send)
- throw("selectgo: send asynch");
- else
- throw("selectgo: recv asynch");
+ if(cas->send) {
+ if(c->qcount < c->dataqsiz)
+ goto asyns;
+ } else {
+ if(c->qcount > 0)
+ goto asynr;
+ }
}
if(cas->send) {
sg = dequeue(&c->recvq, c);
if(sg != nil)
- goto gotr;
+ goto gots;
} else {
sg = dequeue(&c->sendq, c);
if(sg != nil)
- goto gots;
+ goto gotr;
}
o += p;
@@ -527,19 +527,39 @@
for(i=0; i<sel->ncase; i++) {
cas = &sel->scase[o];
c = cas->chan;
+
+ if(c->dataqsiz > 0) {
+ if(cas->send) {
+ if(c->qcount < c->dataqsiz) {
+ prints("second pass asyn send\n");
+ goto asyns;
+ }
+ } else {
+ if(c->qcount > 0) {
+ prints("second pass asyn recv\n");
+ goto asynr;
+ }
+ }
+ }
+
if(cas->send) {
sg = dequeue(&c->recvq, c);
- if(sg != nil)
- goto gotr; // probably an error
+ if(sg != nil) {
+ prints("second pass syn send\n");
+ g->selgen++;
+ goto gots; // probably an error
+ }
sg = allocsg(c);
sg->offset = o;
c->elemalg->copy(c->elemsize, sg->elem, cas->u.elem);
enqueue(&c->sendq, sg);
} else {
sg = dequeue(&c->sendq, c);
- if(sg != nil)
- goto gots; // probably an error
-
+ if(sg != nil) {
+ prints("second pass syn recv\n");
+ g->selgen++;
+ goto gotr; // probably an error
+ }
sg = allocsg(c);
sg->offset = o;
enqueue(&c->recvq, sg);
@@ -550,56 +570,44 @@
o -= sel->ncase;
}
- if(0) {
- prints("wait: sel=");
- sys·printpointer(sel);
- prints("\n");
- }
+ // send and recv paths to sleep for a rendezvous
g->status = Gwaiting;
sys·gosched();
- if(0) {
- prints("wait-return: sel=");
- sys·printpointer(sel);
- prints("\n");
- }
-
sg = g->param;
o = sg->offset;
cas = &sel->scase[o];
c = cas->chan;
- if(0) {
- prints("wake: sel=");
+ if(xxx) {
+ prints("wait-return: sel=");
sys·printpointer(sel);
prints(" c=");
sys·printpointer(c);
+ prints(" cas=");
+ sys·printpointer(cas);
+ prints(" send=");
+ sys·printint(cas->send);
prints(" o=");
sys·printint(o);
prints("\n");
}
- if(cas->send)
- goto gots;
-gotr:
- if(0) {
- prints("gotr: sel=");
- sys·printpointer(sel);
- prints(" c=");
- sys·printpointer(c);
- prints(" o=");
- sys·printint(o);
- prints("\n");
+ if(!cas->send) {
+ if(cas->u.elemp != nil)
+ c->elemalg->copy(c->elemsize, cas->u.elemp, sg->elem);
}
- c->elemalg->copy(c->elemsize, sg->elem, cas->u.elem);
- gp = sg->g;
- gp->param = sg;
- gp->status = Grunnable;
+
+ freesg(c, sg);
goto retc;
-gots:
- if(0) {
- prints("gots: sel=");
+asynr:
+asyns:
+ throw("asyn");
+gotr:
+ // recv path to wakeup the sender (sg)
+ if(xxx) {
+ prints("gotr: sel=");
sys·printpointer(sel);
prints(" c=");
sys·printpointer(c);
@@ -612,9 +620,30 @@
gp = sg->g;
gp->param = sg;
gp->status = Grunnable;
- freesg(c, sg);
+ goto retc;
+
+gots:
+ // send path to wakeup the receiver (sg)
+ if(xxx) {
+ prints("gots: sel=");
+ sys·printpointer(sel);
+ prints(" c=");
+ sys·printpointer(c);
+ prints(" o=");
+ sys·printint(o);
+ prints("\n");
+ }
+ c->elemalg->copy(c->elemsize, sg->elem, cas->u.elem);
+ gp = sg->g;
+ gp->param = sg;
+ gp->status = Grunnable;
retc:
+ if(sel->ncase >= 1 && sel->ncase < nelem(selfree)) {
+ sel->link = selfree[sel->ncase];
+ selfree[sel->ncase] = sel;
+ }
+
sys·setcallerpc(&sel, cas->pc);
as = (byte*)&sel + cas->so;
*as = true;
@@ -668,6 +697,8 @@
sg = mal(sizeof(*sg));
sg->selgen = g->selgen;
sg->g = g;
+ sg->offset = 0;
+
return sg;
}
changeset: 480:8e3ec1bb32ec
user: Russ Cox <[email protected]>
date: Mon Aug 04 16:43:49 2008 -0700
summary: first cut at multithreading. works on Linux.
diff -r a6809e7103e9 -r 8e3ec1bb32ec src/cmd/gc/sys.go
--- a/src/cmd/gc/sys.go Mon Aug 04 16:29:22 2008 -0700
+++ b/src/cmd/gc/sys.go Mon Aug 04 16:43:49 2008 -0700
@@ -64,6 +64,7 @@
func bytestorune(*byte, int32, int32) (int32, int32); // convert bytes to runes
func stringtorune(string, int32, int32) (int32, int32); // convert bytes to runes
+func sleep(ms int64);
func exit(int32);
export
@@ -136,5 +137,6 @@
stringtorune
// system calls
+ sleep
exit
;
diff -r a6809e7103e9 -r 8e3ec1bb32ec src/cmd/gc/sysimport.c
--- a/src/cmd/gc/sysimport.c Mon Aug 04 16:29:22 2008 -0700
+++ b/src/cmd/gc/sysimport.c Mon Aug 04 16:43:49 2008 -0700
@@ -3,10 +3,10 @@
"type sys._esys_002 {}\n"
"type sys.any 24\n"
"type sys._esys_003 *sys.any\n"
- "type sys._osys_372 {_esys_370 sys._esys_003}\n"
+ "type sys._osys_373 {_esys_371 sys._esys_003}\n"
"type sys.uint32 6\n"
- "type sys._isys_374 {_esys_371 sys.uint32}\n"
- "type sys._esys_001 (sys._esys_002 sys._osys_372 sys._isys_374)\n"
+ "type sys._isys_375 {_esys_372 sys.uint32}\n"
+ "type sys._esys_001 (sys._esys_002 sys._osys_373 sys._isys_375)\n"
"var !sys.mal sys._esys_001\n"
"type sys._esys_005 {}\n"
"type sys._esys_006 {}\n"
@@ -16,243 +16,243 @@
"type sys._esys_009 {}\n"
"type sys._esys_010 {}\n"
"type sys.int32 5\n"
- "type sys._isys_380 {_esys_379 sys.int32}\n"
- "type sys._esys_008 (sys._esys_009 sys._esys_010 sys._isys_380)\n"
+ "type sys._isys_381 {_esys_380 sys.int32}\n"
+ "type sys._esys_008 (sys._esys_009 sys._esys_010 sys._isys_381)\n"
"var !sys.panicl sys._esys_008\n"
"type sys._esys_012 {}\n"
"type sys._esys_013 {}\n"
"type sys.bool 12\n"
- "type sys._isys_385 {_esys_384 sys.bool}\n"
- "type sys._esys_011 (sys._esys_012 sys._esys_013 sys._isys_385)\n"
+ "type sys._isys_386 {_esys_385 sys.bool}\n"
+ "type sys._esys_011 (sys._esys_012 sys._esys_013 sys._isys_386)\n"
"var !sys.printbool sys._esys_011\n"
"type sys._esys_015 {}\n"
"type sys._esys_016 {}\n"
"type sys.float64 10\n"
- "type sys._isys_390 {_esys_389 sys.float64}\n"
- "type sys._esys_014 (sys._esys_015 sys._esys_016 sys._isys_390)\n"
+ "type sys._isys_391 {_esys_390 sys.float64}\n"
+ "type sys._esys_014 (sys._esys_015 sys._esys_016 sys._isys_391)\n"
"var !sys.printfloat sys._esys_014\n"
"type sys._esys_018 {}\n"
"type sys._esys_019 {}\n"
"type sys.int64 7\n"
- "type sys._isys_395 {_esys_394 sys.int64}\n"
- "type sys._esys_017 (sys._esys_018 sys._esys_019 sys._isys_395)\n"
+ "type sys._isys_396 {_esys_395 sys.int64}\n"
+ "type sys._esys_017 (sys._esys_018 sys._esys_019 sys._isys_396)\n"
"var !sys.printint sys._esys_017\n"
"type sys._esys_021 {}\n"
"type sys._esys_022 {}\n"
"type sys._esys_023 25\n"
"type sys.string *sys._esys_023\n"
- "type sys._isys_400 {_esys_399 sys.string}\n"
- "type sys._esys_020 (sys._esys_021 sys._esys_022 sys._isys_400)\n"
+ "type sys._isys_401 {_esys_400 sys.string}\n"
+ "type sys._esys_020 (sys._esys_021 sys._esys_022 sys._isys_401)\n"
"var !sys.printstring sys._esys_020\n"
"type sys._esys_025 {}\n"
"type sys._esys_026 {}\n"
"type sys._esys_027 *sys.any\n"
- "type sys._isys_405 {_esys_404 sys._esys_027}\n"
- "type sys._esys_024 (sys._esys_025 sys._esys_026 sys._isys_405)\n"
+ "type sys._isys_406 {_esys_405 sys._esys_027}\n"
+ "type sys._esys_024 (sys._esys_025 sys._esys_026 sys._isys_406)\n"
"var !sys.printpointer sys._esys_024\n"
"type sys._esys_029 {}\n"
- "type sys._osys_412 {_esys_409 sys.string}\n"
- "type sys._isys_414 {_esys_410 sys.string _esys_411 sys.string}\n"
- "type sys._esys_028 (sys._esys_029 sys._osys_412 sys._isys_414)\n"
+ "type sys._osys_413 {_esys_410 sys.string}\n"
+ "type sys._isys_415 {_esys_411 sys.string _esys_412 sys.string}\n"
+ "type sys._esys_028 (sys._esys_029 sys._osys_413 sys._isys_415)\n"
"var !sys.catstring sys._esys_028\n"
"type sys._esys_031 {}\n"
- "type sys._osys_422 {_esys_419 sys.int32}\n"
- "type sys._isys_424 {_esys_420 sys.string _esys_421 sys.string}\n"
- "type sys._esys_030 (sys._esys_031 sys._osys_422 sys._isys_424)\n"
+ "type sys._osys_423 {_esys_420 sys.int32}\n"
+ "type sys._isys_425 {_esys_421 sys.string _esys_422 sys.string}\n"
+ "type sys._esys_030 (sys._esys_031 sys._osys_423 sys._isys_425)\n"
"var !sys.cmpstring sys._esys_030\n"
"type sys._esys_033 {}\n"
- "type sys._osys_433 {_esys_429 sys.string}\n"
- "type sys._isys_435 {_esys_430 sys.string _esys_431 sys.int32 _esys_432 sys.int32}\n"
- "type sys._esys_032 (sys._esys_033 sys._osys_433 sys._isys_435)\n"
+ "type sys._osys_434 {_esys_430 sys.string}\n"
+ "type sys._isys_436 {_esys_431 sys.string _esys_432 sys.int32 _esys_433 sys.int32}\n"
+ "type sys._esys_032 (sys._esys_033 sys._osys_434 sys._isys_436)\n"
"var !sys.slicestring sys._esys_032\n"
"type sys._esys_035 {}\n"
"type sys.uint8 2\n"
- "type sys._osys_444 {_esys_441 sys.uint8}\n"
- "type sys._isys_446 {_esys_442 sys.string _esys_443 sys.int32}\n"
- "type sys._esys_034 (sys._esys_035 sys._osys_444 sys._isys_446)\n"
+ "type sys._osys_445 {_esys_442 sys.uint8}\n"
+ "type sys._isys_447 {_esys_443 sys.string _esys_444 sys.int32}\n"
+ "type sys._esys_034 (sys._esys_035 sys._osys_445 sys._isys_447)\n"
"var !sys.indexstring sys._esys_034\n"
"type sys._esys_037 {}\n"
- "type sys._osys_453 {_esys_451 sys.string}\n"
- "type sys._isys_455 {_esys_452 sys.int64}\n"
- "type sys._esys_036 (sys._esys_037 sys._osys_453 sys._isys_455)\n"
+ "type sys._osys_454 {_esys_452 sys.string}\n"
+ "type sys._isys_456 {_esys_453 sys.int64}\n"
+ "type sys._esys_036 (sys._esys_037 sys._osys_454 sys._isys_456)\n"
"var !sys.intstring sys._esys_036\n"
"type sys._esys_039 {}\n"
- "type sys._osys_462 {_esys_459 sys.string}\n"
+ "type sys._osys_463 {_esys_460 sys.string}\n"
"type sys._esys_040 *sys.uint8\n"
- "type sys._isys_464 {_esys_460 sys._esys_040 _esys_461 sys.int32}\n"
- "type sys._esys_038 (sys._esys_039 sys._osys_462 sys._isys_464)\n"
+ "type sys._isys_465 {_esys_461 sys._esys_040 _esys_462 sys.int32}\n"
+ "type sys._esys_038 (sys._esys_039 sys._osys_463 sys._isys_465)\n"
"var !sys.byteastring sys._esys_038\n"
"type sys._esys_042 {}\n"
"type sys._esys_043 <>\n"
- "type sys._osys_473 {_esys_469 sys._esys_043}\n"
+ "type sys._osys_474 {_esys_470 sys._esys_043}\n"
"type sys._esys_044 *sys.uint8\n"
"type sys._esys_045 *sys.uint8\n"
- "type sys._ssys_480 {}\n"
- "type sys._esys_046 *sys._ssys_480\n"
- "type sys._isys_475 {_esys_470 sys._esys_044 _esys_471 sys._esys_045 _esys_472 sys._esys_046}\n"
- "type sys._esys_041 (sys._esys_042 sys._osys_473 sys._isys_475)\n"
+ "type sys._ssys_481 {}\n"
+ "type sys._esys_046 *sys._ssys_481\n"
+ "type sys._isys_476 {_esys_471 sys._esys_044 _esys_472 sys._esys_045 _esys_473 sys._esys_046}\n"
+ "type sys._esys_041 (sys._esys_042 sys._osys_474 sys._isys_476)\n"
"var !sys.mkiface sys._esys_041\n"
"type sys._esys_048 {}\n"
- "type sys._osys_484 {_esys_483 sys.int32}\n"
+ "type sys._osys_485 {_esys_484 sys.int32}\n"
"type sys._esys_049 {}\n"
- "type sys._esys_047 (sys._esys_048 sys._osys_484 sys._esys_049)\n"
+ "type sys._esys_047 (sys._esys_048 sys._osys_485 sys._esys_049)\n"
"var !sys.argc sys._esys_047\n"
"type sys._esys_051 {}\n"
- "type sys._osys_488 {_esys_487 sys.int32}\n"
+ "type sys._osys_489 {_esys_488 sys.int32}\n"
"type sys._esys_052 {}\n"
- "type sys._esys_050 (sys._esys_051 sys._osys_488 sys._esys_052)\n"
+ "type sys._esys_050 (sys._esys_051 sys._osys_489 sys._esys_052)\n"
"var !sys.envc sys._esys_050\n"
"type sys._esys_054 {}\n"
- "type sys._osys_493 {_esys_491 sys.string}\n"
- "type sys._isys_495 {_esys_492 sys.int32}\n"
- "type sys._esys_053 (sys._esys_054 sys._osys_493 sys._isys_495)\n"
+ "type sys._osys_494 {_esys_492 sys.string}\n"
+ "type sys._isys_496 {_esys_493 sys.int32}\n"
+ "type sys._esys_053 (sys._esys_054 sys._osys_494 sys._isys_496)\n"
"var !sys.argv sys._esys_053\n"
"type sys._esys_056 {}\n"
- "type sys._osys_501 {_esys_499 sys.string}\n"
- "type sys._isys_503 {_esys_500 sys.int32}\n"
- "type sys._esys_055 (sys._esys_056 sys._osys_501 sys._isys_503)\n"
+ "type sys._osys_502 {_esys_500 sys.string}\n"
+ "type sys._isys_504 {_esys_501 sys.int32}\n"
+ "type sys._esys_055 (sys._esys_056 sys._osys_502 sys._isys_504)\n"
"var !sys.envv sys._esys_055\n"
"type sys._esys_058 {}\n"
- "type sys._osys_510 {_esys_507 sys.float64 _esys_508 sys.int32}\n"
- "type sys._isys_512 {_esys_509 sys.float64}\n"
- "type sys._esys_057 (sys._esys_058 sys._osys_510 sys._isys_512)\n"
+ "type sys._osys_511 {_esys_508 sys.float64 _esys_509 sys.int32}\n"
+ "type sys._isys_513 {_esys_510 sys.float64}\n"
+ "type sys._esys_057 (sys._esys_058 sys._osys_511 sys._isys_513)\n"
"var !sys.frexp sys._esys_057\n"
"type sys._esys_060 {}\n"
- "type sys._osys_519 {_esys_516 sys.float64}\n"
- "type sys._isys_521 {_esys_517 sys.float64 _esys_518 sys.int32}\n"
- "type sys._esys_059 (sys._esys_060 sys._osys_519 sys._isys_521)\n"
+ "type sys._osys_520 {_esys_517 sys.float64}\n"
+ "type sys._isys_522 {_esys_518 sys.float64 _esys_519 sys.int32}\n"
+ "type sys._esys_059 (sys._esys_060 sys._osys_520 sys._isys_522)\n"
"var !sys.ldexp sys._esys_059\n"
"type sys._esys_062 {}\n"
- "type sys._osys_529 {_esys_526 sys.float64 _esys_527 sys.float64}\n"
- "type sys._isys_531 {_esys_528 sys.float64}\n"
- "type sys._esys_061 (sys._esys_062 sys._osys_529 sys._isys_531)\n"
+ "type sys._osys_530 {_esys_527 sys.float64 _esys_528 sys.float64}\n"
+ "type sys._isys_532 {_esys_529 sys.float64}\n"
+ "type sys._esys_061 (sys._esys_062 sys._osys_530 sys._isys_532)\n"
"var !sys.modf sys._esys_061\n"
"type sys._esys_064 {}\n"
- "type sys._osys_538 {_esys_535 sys.bool}\n"
- "type sys._isys_540 {_esys_536 sys.float64 _esys_537 sys.int32}\n"
- "type sys._esys_063 (sys._esys_064 sys._osys_538 sys._isys_540)\n"
+ "type sys._osys_539 {_esys_536 sys.bool}\n"
+ "type sys._isys_541 {_esys_537 sys.float64 _esys_538 sys.int32}\n"
+ "type sys._esys_063 (sys._esys_064 sys._osys_539 sys._isys_541)\n"
"var !sys.isInf sys._esys_063\n"
"type sys._esys_066 {}\n"
- "type sys._osys_547 {_esys_545 sys.bool}\n"
- "type sys._isys_549 {_esys_546 sys.float64}\n"
- "type sys._esys_065 (sys._esys_066 sys._osys_547 sys._isys_549)\n"
+ "type sys._osys_548 {_esys_546 sys.bool}\n"
+ "type sys._isys_550 {_esys_547 sys.float64}\n"
+ "type sys._esys_065 (sys._esys_066 sys._osys_548 sys._isys_550)\n"
"var !sys.isNaN sys._esys_065\n"
"type sys._esys_068 {}\n"
- "type sys._osys_555 {_esys_553 sys.float64}\n"
- "type sys._isys_557 {_esys_554 sys.int32}\n"
- "type sys._esys_067 (sys._esys_068 sys._osys_555 sys._isys_557)\n"
+ "type sys._osys_556 {_esys_554 sys.float64}\n"
+ "type sys._isys_558 {_esys_555 sys.int32}\n"
+ "type sys._esys_067 (sys._esys_068 sys._osys_556 sys._isys_558)\n"
"var !sys.Inf sys._esys_067\n"
"type sys._esys_070 {}\n"
- "type sys._osys_562 {_esys_561 sys.float64}\n"
+ "type sys._osys_563 {_esys_562 sys.float64}\n"
"type sys._esys_071 {}\n"
- "type sys._esys_069 (sys._esys_070 sys._osys_562 sys._esys_071)\n"
+ "type sys._esys_069 (sys._esys_070 sys._osys_563 sys._esys_071)\n"
"var !sys.NaN sys._esys_069\n"
"type sys._esys_073 {}\n"
"type sys._esys_075 [sys.any] sys.any\n"
"type sys._esys_074 *sys._esys_075\n"
- "type sys._osys_565 {hmap sys._esys_074}\n"
- "type sys._isys_567 {keysize sys.uint32 valsize sys.uint32 keyalg sys.uint32 valalg sys.uint32 hint sys.uint32}\n"
- "type sys._esys_072 (sys._esys_073 sys._osys_565 sys._isys_567)\n"
+ "type sys._osys_566 {hmap sys._esys_074}\n"
+ "type sys._isys_568 {keysize sys.uint32 valsize sys.uint32 keyalg sys.uint32 valalg sys.uint32 hint sys.uint32}\n"
+ "type sys._esys_072 (sys._esys_073 sys._osys_566 sys._isys_568)\n"
"var !sys.newmap sys._esys_072\n"
"type sys._esys_077 {}\n"
- "type sys._osys_576 {val sys.any}\n"
+ "type sys._osys_577 {val sys.any}\n"
"type sys._esys_079 [sys.any] sys.any\n"
"type sys._esys_078 *sys._esys_079\n"
- "type sys._isys_578 {hmap sys._esys_078 key sys.any}\n"
- "type sys._esys_076 (sys._esys_077 sys._osys_576 sys._isys_578)\n"
+ "type sys._isys_579 {hmap sys._esys_078 key sys.any}\n"
+ "type sys._esys_076 (sys._esys_077 sys._osys_577 sys._isys_579)\n"
"var !sys.mapaccess1 sys._esys_076\n"
"type sys._esys_081 {}\n"
- "type sys._osys_584 {val sys.any pres sys.bool}\n"
+ "type sys._osys_585 {val sys.any pres sys.bool}\n"
"type sys._esys_083 [sys.any] sys.any\n"
"type sys._esys_082 *sys._esys_083\n"
- "type sys._isys_586 {hmap sys._esys_082 key sys.any}\n"
- "type sys._esys_080 (sys._esys_081 sys._osys_584 sys._isys_586)\n"
+ "type sys._isys_587 {hmap sys._esys_082 key sys.any}\n"
+ "type sys._esys_080 (sys._esys_081 sys._osys_585 sys._isys_587)\n"
"var !sys.mapaccess2 sys._esys_080\n"
"type sys._esys_085 {}\n"
"type sys._esys_086 {}\n"
"type sys._esys_088 [sys.any] sys.any\n"
"type sys._esys_087 *sys._esys_088\n"
- "type sys._isys_593 {hmap sys._esys_087 key sys.any val sys.any}\n"
- "type sys._esys_084 (sys._esys_085 sys._esys_086 sys._isys_593)\n"
+ "type sys._isys_594 {hmap sys._esys_087 key sys.any val sys.any}\n"
+ "type sys._esys_084 (sys._esys_085 sys._esys_086 sys._isys_594)\n"
"var !sys.mapassign1 sys._esys_084\n"
"type sys._esys_090 {}\n"
"type sys._esys_091 {}\n"
"type sys._esys_093 [sys.any] sys.any\n"
"type sys._esys_092 *sys._esys_093\n"
- "type sys._isys_599 {hmap sys._esys_092 key sys.any val sys.any pres sys.bool}\n"
- "type sys._esys_089 (sys._esys_090 sys._esys_091 sys._isys_599)\n"
+ "type sys._isys_600 {hmap sys._esys_092 key sys.any val sys.any pres sys.bool}\n"
+ "type sys._esys_089 (sys._esys_090 sys._esys_091 sys._isys_600)\n"
"var !sys.mapassign2 sys._esys_089\n"
"type sys._esys_095 {}\n"
"type sys._esys_097 1 sys.any\n"
"type sys._esys_096 *sys._esys_097\n"
- "type sys._osys_606 {hchan sys._esys_096}\n"
- "type sys._isys_608 {elemsize sys.uint32 elemalg sys.uint32 hint sys.uint32}\n"
- "type sys._esys_094 (sys._esys_095 sys._osys_606 sys._isys_608)\n"
+ "type sys._osys_607 {hchan sys._esys_096}\n"
+ "type sys._isys_609 {elemsize sys.uint32 elemalg sys.uint32 hint sys.uint32}\n"
+ "type sys._esys_094 (sys._esys_095 sys._osys_607 sys._isys_609)\n"
"var !sys.newchan sys._esys_094\n"
"type sys._esys_099 {}\n"
- "type sys._osys_615 {elem sys.any}\n"
+ "type sys._osys_616 {elem sys.any}\n"
"type sys._esys_101 1 sys.any\n"
"type sys._esys_100 *sys._esys_101\n"
- "type sys._isys_617 {hchan sys._esys_100}\n"
- "type sys._esys_098 (sys._esys_099 sys._osys_615 sys._isys_617)\n"
+ "type sys._isys_618 {hchan sys._esys_100}\n"
+ "type sys._esys_098 (sys._esys_099 sys._osys_616 sys._isys_618)\n"
"var !sys.chanrecv1 sys._esys_098\n"
"type sys._esys_103 {}\n"
- "type sys._osys_622 {elem sys.any pres sys.bool}\n"
+ "type sys._osys_623 {elem sys.any pres sys.bool}\n"
"type sys._esys_105 1 sys.any\n"
"type sys._esys_104 *sys._esys_105\n"
- "type sys._isys_624 {hchan sys._esys_104}\n"
- "type sys._esys_102 (sys._esys_103 sys._osys_622 sys._isys_624)\n"
+ "type sys._isys_625 {hchan sys._esys_104}\n"
+ "type sys._esys_102 (sys._esys_103 sys._osys_623 sys._isys_625)\n"
"var !sys.chanrecv2 sys._esys_102\n"
"type sys._esys_107 {}\n"
- "type sys._osys_630 {pres sys.bool}\n"
+ "type sys._osys_631 {pres sys.bool}\n"
"type sys._esys_109 1 sys.any\n"
"type sys._esys_108 *sys._esys_109\n"
"type sys._esys_110 *sys.any\n"
- "type sys._isys_632 {hchan sys._esys_108 elem sys._esys_110}\n"
- "type sys._esys_106 (sys._esys_107 sys._osys_630 sys._isys_632)\n"
+ "type sys._isys_633 {hchan sys._esys_108 elem sys._esys_110}\n"
+ "type sys._esys_106 (sys._esys_107 sys._osys_631 sys._isys_633)\n"
"var !sys.chanrecv3 sys._esys_106\n"
"type sys._esys_112 {}\n"
"type sys._esys_113 {}\n"
"type sys._esys_115 1 sys.any\n"
"type sys._esys_114 *sys._esys_115\n"
- "type sys._isys_638 {hchan sys._esys_114 elem sys.any}\n"
- "type sys._esys_111 (sys._esys_112 sys._esys_113 sys._isys_638)\n"
+ "type sys._isys_639 {hchan sys._esys_114 elem sys.any}\n"
+ "type sys._esys_111 (sys._esys_112 sys._esys_113 sys._isys_639)\n"
"var !sys.chansend1 sys._esys_111\n"
"type sys._esys_117 {}\n"
- "type sys._osys_643 {pres sys.bool}\n"
+ "type sys._osys_644 {pres sys.bool}\n"
"type sys._esys_119 1 sys.any\n"
"type sys._esys_118 *sys._esys_119\n"
- "type sys._isys_645 {hchan sys._esys_118 elem sys.any}\n"
- "type sys._esys_116 (sys._esys_117 sys._osys_643 sys._isys_645)\n"
+ "type sys._isys_646 {hchan sys._esys_118 elem sys.any}\n"
+ "type sys._esys_116 (sys._esys_117 sys._osys_644 sys._isys_646)\n"
"var !sys.chansend2 sys._esys_116\n"
"type sys._esys_121 {}\n"
"type sys._esys_122 *sys.uint8\n"
- "type sys._osys_651 {sel sys._esys_122}\n"
- "type sys._isys_653 {size sys.uint32}\n"
- "type sys._esys_120 (sys._esys_121 sys._osys_651 sys._isys_653)\n"
+ "type sys._osys_652 {sel sys._esys_122}\n"
+ "type sys._isys_654 {size sys.uint32}\n"
+ "type sys._esys_120 (sys._esys_121 sys._osys_652 sys._isys_654)\n"
"var !sys.newselect sys._esys_120\n"
"type sys._esys_124 {}\n"
- "type sys._osys_658 {selected sys.bool}\n"
+ "type sys._osys_659 {selected sys.bool}\n"
"type sys._esys_125 *sys.uint8\n"
"type sys._esys_127 1 sys.any\n"
"type sys._esys_126 *sys._esys_127\n"
- "type sys._isys_660 {sel sys._esys_125 hchan sys._esys_126 elem sys.any}\n"
- "type sys._esys_123 (sys._esys_124 sys._osys_658 sys._isys_660)\n"
+ "type sys._isys_661 {sel sys._esys_125 hchan sys._esys_126 elem sys.any}\n"
+ "type sys._esys_123 (sys._esys_124 sys._osys_659 sys._isys_661)\n"
"var !sys.selectsend sys._esys_123\n"
"type sys._esys_129 {}\n"
- "type sys._osys_667 {selected sys.bool}\n"
+ "type sys._osys_668 {selected sys.bool}\n"
"type sys._esys_130 *sys.uint8\n"
"type sys._esys_132 1 sys.any\n"
"type sys._esys_131 *sys._esys_132\n"
"type sys._esys_133 *sys.any\n"
- "type sys._isys_669 {sel sys._esys_130 hchan sys._esys_131 elem sys._esys_133}\n"
- "type sys._esys_128 (sys._esys_129 sys._osys_667 sys._isys_669)\n"
+ "type sys._isys_670 {sel sys._esys_130 hchan sys._esys_131 elem sys._esys_133}\n"
+ "type sys._esys_128 (sys._esys_129 sys._osys_668 sys._isys_670)\n"
"var !sys.selectrecv sys._esys_128\n"
"type sys._esys_135 {}\n"
"type sys._esys_136 {}\n"
"type sys._esys_137 *sys.uint8\n"
- "type sys._isys_676 {sel sys._esys_137}\n"
- "type sys._esys_134 (sys._esys_135 sys._esys_136 sys._isys_676)\n"
+ "type sys._isys_677 {sel sys._esys_137}\n"
+ "type sys._esys_134 (sys._esys_135 sys._esys_136 sys._isys_677)\n"
"var !sys.selectgo sys._esys_134\n"
"type sys._esys_139 {}\n"
"type sys._esys_140 {}\n"
@@ -265,34 +265,39 @@
"type sys._esys_142 (sys._esys_143 sys._esys_144 sys._esys_145)\n"
"var !sys.goexit sys._esys_142\n"
"type sys._esys_147 {}\n"
- "type sys._osys_685 {_esys_682 sys.string _esys_683 sys.bool}\n"
- "type sys._isys_687 {_esys_684 sys.string}\n"
- "type sys._esys_146 (sys._esys_147 sys._osys_685 sys._isys_687)\n"
+ "type sys._osys_686 {_esys_683 sys.string _esys_684 sys.bool}\n"
+ "type sys._isys_688 {_esys_685 sys.string}\n"
+ "type sys._esys_146 (sys._esys_147 sys._osys_686 sys._isys_688)\n"
"var !sys.readfile sys._esys_146\n"
"type sys._esys_149 {}\n"
- "type sys._osys_694 {_esys_691 sys.bool}\n"
- "type sys._isys_696 {_esys_692 sys.string _esys_693 sys.string}\n"
- "type sys._esys_148 (sys._esys_149 sys._osys_694 sys._isys_696)\n"
+ "type sys._osys_695 {_esys_692 sys.bool}\n"
+ "type sys._isys_697 {_esys_693 sys.string _esys_694 sys.string}\n"
+ "type sys._esys_148 (sys._esys_149 sys._osys_695 sys._isys_697)\n"
"var !sys.writefile sys._esys_148\n"
"type sys._esys_151 {}\n"
- "type sys._osys_706 {_esys_701 sys.int32 _esys_702 sys.int32}\n"
+ "type sys._osys_707 {_esys_702 sys.int32 _esys_703 sys.int32}\n"
"type sys._esys_152 *sys.uint8\n"
- "type sys._isys_708 {_esys_703 sys._esys_152 _esys_704 sys.int32 _esys_705 sys.int32}\n"
- "type sys._esys_150 (sys._esys_151 sys._osys_706 sys._isys_708)\n"
+ "type sys._isys_709 {_esys_704 sys._esys_152 _esys_705 sys.int32 _esys_706 sys.int32}\n"
+ "type sys._esys_150 (sys._esys_151 sys._osys_707 sys._isys_709)\n"
"var !sys.bytestorune sys._esys_150\n"
"type sys._esys_154 {}\n"
- "type sys._osys_719 {_esys_714 sys.int32 _esys_715 sys.int32}\n"
- "type sys._isys_721 {_esys_716 sys.string _esys_717 sys.int32 _esys_718 sys.int32}\n"
- "type sys._esys_153 (sys._esys_154 sys._osys_719 sys._isys_721)\n"
+ "type sys._osys_720 {_esys_715 sys.int32 _esys_716 sys.int32}\n"
+ "type sys._isys_722 {_esys_717 sys.string _esys_718 sys.int32 _esys_719 sys.int32}\n"
+ "type sys._esys_153 (sys._esys_154 sys._osys_720 sys._isys_722)\n"
"var !sys.stringtorune sys._esys_153\n"
"type sys._esys_156 {}\n"
"type sys._esys_157 {}\n"
- "type sys._isys_728 {_esys_727 sys.int32}\n"
+ "type sys._isys_728 {ms sys.int64}\n"
"type sys._esys_155 (sys._esys_156 sys._esys_157 sys._isys_728)\n"
- "var !sys.exit sys._esys_155\n"
+ "var !sys.sleep sys._esys_155\n"
"type sys._esys_159 {}\n"
"type sys._esys_160 {}\n"
- "type sys._esys_161 {}\n"
- "type sys._esys_158 (sys._esys_159 sys._esys_160 sys._esys_161)\n"
+ "type sys._isys_733 {_esys_732 sys.int32}\n"
+ "type sys._esys_158 (sys._esys_159 sys._esys_160 sys._isys_733)\n"
+ "var !sys.exit sys._esys_158\n"
+ "type sys._esys_162 {}\n"
+ "type sys._esys_163 {}\n"
+ "type sys._esys_164 {}\n"
+ "type sys._esys_161 (sys._esys_162 sys._esys_163 sys._esys_164)\n"
"))\n"
;
diff -r a6809e7103e9 -r 8e3ec1bb32ec src/runtime/amd64_linux.h
--- a/src/runtime/amd64_linux.h Mon Aug 04 16:29:22 2008 -0700
+++ b/src/runtime/amd64_linux.h Mon Aug 04 16:43:49 2008 -0700
@@ -3,7 +3,7 @@
// license that can be found in the LICENSE file.
/*
- * System structs for Darwin, amd64
+ * System structs for Linux, amd64
*/
typedef uint64 dev_t;
@@ -22,6 +22,11 @@
int64 tv_nsec;
};
+struct timeval {
+ time_t tv_sec;
+ int64 tv_usec;
+};
+
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* inode number */
@@ -40,3 +45,9 @@
};
#define O_CREAT 0100
+
+// Linux-specific system calls
+int64 futex(uint32*, int32, uint32, struct timespec*, uint32*, uint32);
+int64 clone(int32, void*, M*, G*, void(*)(void*), void*);
+int64 select(int32, void*, void*, void*, void*);
+
diff -r a6809e7103e9 -r 8e3ec1bb32ec src/runtime/chan.c
--- a/src/runtime/chan.c Mon Aug 04 16:29:22 2008 -0700
+++ b/src/runtime/chan.c Mon Aug 04 16:43:49 2008 -0700
@@ -4,6 +4,8 @@
#include "runtime.h"
+// TODO locking of select
+
static int32 debug = 0;
typedef struct Hchan Hchan;
@@ -30,6 +32,7 @@
struct Hchan
{
+ Lock;
uint32 elemsize;
uint32 dataqsiz; // size of the circular q
uint32 qcount; // total data in the q
@@ -159,6 +162,7 @@
prints("\n");
}
+ lock(c);
if(c->dataqsiz > 0)
goto asynch;
@@ -169,7 +173,8 @@
gp = sg->g;
gp->param = sg;
- gp->status = Grunnable;
+ unlock(c);
+ ready(gp);
if(pres != nil)
*pres = true;
@@ -177,6 +182,7 @@
}
if(pres != nil) {
+ unlock(c);
*pres = false;
return;
}
@@ -187,18 +193,24 @@
g->param = nil;
g->status = Gwaiting;
enqueue(&c->sendq, sg);
+ unlock(c);
sys·gosched();
+ lock(c);
sg = g->param;
freesg(c, sg);
+ unlock(c);
return;
asynch:
while(c->qcount >= c->dataqsiz) {
+ // (rsc) should check for pres != nil
sg = allocsg(c);
g->status = Gwaiting;
enqueue(&c->sendq, sg);
+ unlock(c);
sys·gosched();
+ lock(c);
}
if(ep != nil)
c->elemalg->copy(c->elemsize, c->senddataq->elem, ep);
@@ -209,8 +221,10 @@
if(sg != nil) {
gp = sg->g;
freesg(c, sg);
- gp->status = Grunnable;
- }
+ unlock(c);
+ ready(gp);
+ }else
+ unlock(c);
}
static void
@@ -225,6 +239,7 @@
prints("\n");
}
+ lock(c);
if(c->dataqsiz > 0)
goto asynch;
@@ -234,7 +249,8 @@
gp = sg->g;
gp->param = sg;
- gp->status = Grunnable;
+ unlock(c);
+ ready(gp);
if(pres != nil)
*pres = true;
@@ -242,6 +258,7 @@
}
if(pres != nil) {
+ unlock(c);
*pres = false;
return;
}
@@ -250,11 +267,14 @@
g->param = nil;
g->status = Gwaiting;
enqueue(&c->recvq, sg);
+ unlock(c);
sys·gosched();
+ lock(c);
sg = g->param;
c->elemalg->copy(c->elemsize, ep, sg->elem);
freesg(c, sg);
+ unlock(c);
return;
asynch:
@@ -262,7 +282,9 @@
sg = allocsg(c);
g->status = Gwaiting;
enqueue(&c->recvq, sg);
+ unlock(c);
sys·gosched();
+ lock(c);
}
c->elemalg->copy(c->elemsize, ep, c->recvdataq->elem);
c->recvdataq = c->recvdataq->link;
@@ -271,8 +293,10 @@
if(sg != nil) {
gp = sg->g;
freesg(c, sg);
- gp->status = Grunnable;
- }
+ unlock(c);
+ ready(gp);
+ }else
+ unlock(c);
}
// chansend1(hchan *chan any, elem any);
@@ -571,6 +595,8 @@
}
// send and recv paths to sleep for a rendezvous
+ // (rsc) not correct to set Gwaiting after queueing;
+ // might already have been readied.
g->status = Gwaiting;
sys·gosched();
@@ -619,7 +645,7 @@
c->elemalg->copy(c->elemsize, cas->u.elemp, sg->elem);
gp = sg->g;
gp->param = sg;
- gp->status = Grunnable;
+ ready(gp);
goto retc;
gots:
@@ -636,7 +662,7 @@
c->elemalg->copy(c->elemsize, sg->elem, cas->u.elem);
gp = sg->g;
gp->param = sg;
- gp->status = Grunnable;
+ ready(gp);
retc:
if(sel->ncase >= 1 && sel->ncase < nelem(selfree)) {
diff -r a6809e7103e9 -r 8e3ec1bb32ec src/runtime/proc.c
--- a/src/runtime/proc.c Mon Aug 04 16:29:22 2008 -0700
+++ b/src/runtime/proc.c Mon Aug 04 16:43:49 2008 -0700
@@ -4,19 +4,59 @@
#include "runtime.h"
+typedef struct Sched Sched;
+
+M m0;
+G g0; // idle goroutine for m0
+
+// Maximum number of os procs (M's) to kick off.
+// Can override with $gomaxprocs environment variable.
+// For now set to 1 (single-threaded), because not
+// everything is properly locked (e.g., chans) and because
+// Darwin's multithreading code isn't implemented.
+int32 gomaxprocs = 1;
+
static int32 debug = 0;
+struct Sched {
+ G *runhead;
+ G *runtail;
+ int32 nwait;
+ int32 nready;
+ int32 ng;
+ int32 nm;
+ M *wait;
+ Lock;
+};
+
+Sched sched;
+
void
sys·goexit(void)
{
-//prints("goexit goid=");
-//sys·printint(g->goid);
-//prints("\n");
+ if(debug){
+ prints("goexit goid=");
+ sys·printint(g->goid);
+ prints("\n");
+ }
g->status = Gdead;
sys·gosched();
}
void
+schedinit(void)
+{
+ byte *p;
+ extern int32 getenvc(void);
+
+ p = getenv("gomaxprocs");
+ if(p && '0' <= *p && *p <= '9')
+ gomaxprocs = atoi(p);
+ sched.nm = 1;
+ sched.nwait = 1;
+}
+
+void
sys·newproc(int32 siz, byte* fn, byte* arg0)
{
byte *stk, *sp;
@@ -64,10 +104,13 @@
newg->sched.SP = sp;
newg->sched.PC = fn;
+ lock(&sched);
+ sched.ng++;
goidgen++;
newg->goid = goidgen;
+ unlock(&sched);
- newg->status = Grunnable;
+ ready(newg);
//prints(" goid=");
//sys·printint(newg->goid);
@@ -80,7 +123,7 @@
G *g;
for(g = allg; g != nil; g = g->alllink) {
- if(g == me)
+ if(g == me || g->status == Gdead)
continue;
prints("\ngoroutine ");
sys·printint(g->goid);
@@ -89,47 +132,176 @@
}
}
+void newmach(void);
+
+static void
+readylocked(G *g)
+{
+ g->status = Grunnable;
+ if(sched.runhead == nil)
+ sched.runhead = g;
+ else
+ sched.runtail->runlink = g;
+ sched.runtail = g;
+ g->runlink = nil;
+ sched.nready++;
+ // Don't wake up another scheduler.
+ // This only gets called when we're
+ // about to reschedule anyway.
+}
+
+static Lock print;
+
+void
+ready(G *g)
+{
+ M *mm;
+
+ // gp might be running on another scheduler.
+ // (E.g., it queued and then we decided to wake it up
+ // before it had a chance to sys·gosched().)
+ // Grabbing the runlock ensures that it is not running elsewhere.
+ // You can delete the if check, but don't delete the
+ // lock/unlock sequence (being able to grab the lock
+ // means the proc has gone to sleep).
+ lock(&g->runlock);
+ if(g->status == Grunnable || g->status == Grunning)
+ *(int32*)0x1023 = 0x1023;
+ lock(&sched);
+ g->status = Grunnable;
+ if(sched.runhead == nil)
+ sched.runhead = g;
+ else
+ sched.runtail->runlink = g;
+ sched.runtail = g;
+ g->runlink = nil;
+ unlock(&g->runlock);
+ sched.nready++;
+ if(sched.nready > sched.nwait)
+ if(gomaxprocs == 0 || sched.nm < gomaxprocs){
+ if(debug){
+ prints("new scheduler: ");
+ sys·printint(sched.nready);
+ prints(" > ");
+ sys·printint(sched.nwait);
+ prints("\n");
+ }
+ sched.nwait++;
+ newmach();
+ }
+ if(sched.wait){
+ mm = sched.wait;
+ sched.wait = mm->waitlink;
+ rwakeupandunlock(&mm->waitr);
+ }else
+ unlock(&sched);
+}
+
+extern void p0(void), p1(void);
+
G*
nextgoroutine(void)
{
G *gp;
- gp = m->lastg;
- if(gp == nil)
- gp = allg;
-
- for(gp=gp->alllink; gp!=nil; gp=gp->alllink) {
- if(gp->status == Grunnable) {
- m->lastg = gp;
- return gp;
+ while((gp = sched.runhead) == nil){
+ if(debug){
+ prints("nextgoroutine runhead=nil ng=");
+ sys·printint(sched.ng);
+ prints("\n");
}
+ if(sched.ng == 0)
+ return nil;
+ m->waitlink = sched.wait;
+ m->waitr.l = &sched.Lock;
+ sched.wait = m;
+ sched.nwait++;
+ if(sched.nm == sched.nwait)
+ prints("all goroutines are asleep - deadlock!\n");
+ rsleep(&m->waitr);
+ sched.nwait--;
}
- for(gp=allg; gp!=nil; gp=gp->alllink) {
- if(gp->status == Grunnable) {
- m->lastg = gp;
- return gp;
- }
- }
- return nil;
+ sched.nready--;
+ sched.runhead = gp->runlink;
+ return gp;
}
void
scheduler(void)
{
G* gp;
-
+
+ m->pid = getprocid();
+
gosave(&m->sched);
+ lock(&sched);
+
+ if(m->curg == nil){
+ // Brand new scheduler; nwait counts us.
+ // Not anymore.
+ sched.nwait--;
+ }else{
+ gp = m->curg;
+ gp->m = nil;
+ switch(gp->status){
+ case Gdead:
+ sched.ng--;
+ if(debug){
+ prints("sched: dead: ");
+ sys·printint(sched.ng);
+ prints("\n");
+ }
+ break;
+ case Grunning:
+ readylocked(gp);
+ break;
+ case Grunnable:
+ // don't want to see this
+ *(int32*)0x456 = 0x234;
+ break;
+ }
+ unlock(&gp->runlock);
+ }
+
gp = nextgoroutine();
if(gp == nil) {
// prints("sched: no more work\n");
sys·exit(0);
}
+ unlock(&sched);
+
+ lock(&gp->runlock);
+ gp->status = Grunning;
m->curg = gp;
+ gp->m = m;
g = gp;
gogo(&gp->sched);
}
void
+newmach(void)
+{
+ M *mm;
+ byte *stk, *stktop;
+ int64 ret;
+
+ sched.nm++;
+ if(!(sched.nm&(sched.nm-1))){
+ sys·printint(sched.nm);
+ prints(" threads\n");
+ }
+ mm = mal(sizeof(M)+sizeof(G)+1024+104);
+ sys·memclr((byte*)mm, sizeof(M));
+ mm->g0 = (G*)(mm+1);
+ sys·memclr((byte*)mm->g0, sizeof(G));
+ stk = (byte*)mm->g0 + 104;
+ stktop = stk + 1024;
+ mm->g0->stackguard = stk;
+ mm->g0->stackbase = stktop;
+ newosproc(mm, mm->g0, stktop, (void(*)(void*))scheduler, nil);
+}
+
+void
gom0init(void)
{
scheduler();
@@ -138,10 +310,11 @@
void
sys·gosched(void)
{
- if(gosave(&g->sched))
- return;
- g = m->g0;
- gogo(&m->sched);
+ if(gosave(&g->sched) == 0){
+ // (rsc) signal race here?
+ g = m->g0;
+ gogo(&m->sched);
+ }
}
//
diff -r a6809e7103e9 -r 8e3ec1bb32ec src/runtime/rt0_amd64.s
--- a/src/runtime/rt0_amd64.s Mon Aug 04 16:29:22 2008 -0700
+++ b/src/runtime/rt0_amd64.s Mon Aug 04 16:43:49 2008 -0700
@@ -14,9 +14,9 @@
MOVQ AX, 16(SP)
MOVQ BX, 24(SP)
- // allocate the per-user and per-mach blocks
+ // set the per-goroutine and per-mach registers
- LEAQ m0<>(SB), R14 // dedicated m. register
+ LEAQ m0(SB), R14 // dedicated m. register
LEAQ g0(SB), R15 // dedicated g. register
MOVQ R15, 0(R14) // m has pointer to its g0
@@ -33,8 +33,9 @@
MOVQ 24(SP), AX // copy argv
MOVQ AX, 8(SP)
CALL args(SB)
+ CALL schedinit(SB)
CALL main·init_function(SB) // initialization
-
+
// create a new goroutine to start program
PUSHQ $main·main(SB) // entry
@@ -102,4 +103,22 @@
POPQ AX
RET
-GLOBL m0<>(SB),$64
+// bool cas(int32 *val, int32 old, int32 new)
+// Atomically:
+// if(*val == old){
+// *val = new;
+// return 1;
+// }else
+// return 0;
+TEXT cas(SB), 7, $0
+ MOVQ 8(SP), BX
+ MOVL 16(SP), AX
+ MOVL 20(SP), CX
+ LOCK
+ CMPXCHGL CX, 0(BX)
+ JZ 3(PC)
+ MOVL $0, AX
+ RET
+ MOVL $1, AX
+ RET
+
diff -r a6809e7103e9 -r 8e3ec1bb32ec src/runtime/rt1_amd64_darwin.c
--- a/src/runtime/rt1_amd64_darwin.c Mon Aug 04 16:29:22 2008 -0700
+++ b/src/runtime/rt1_amd64_darwin.c Mon Aug 04 16:43:49 2008 -0700
@@ -5,7 +5,6 @@
#include "runtime.h"
#include "signals.h"
-
typedef uint64 __uint64_t;
/* From /usr/include/mach/i386/_structs.h */
@@ -174,3 +173,75 @@
sys·sigaction(i, &a, (void*)0);
}
}
+
+static void
+unimplemented(int8 *name)
+{
+ prints(name);
+ prints(" not implemented\n");
+ *(int32*)1231 = 1231;
+}
+
+void
+sys·sleep(int64 ms)
+{
+ unimplemented("sleep");
+}
+
+void
+lock(Lock *l)
+{
+ if(xadd(&l->key, 1) == 1)
+ return;
+ unimplemented("lock wait");
+}
+
+void
+unlock(Lock *l)
+{
+ if(xadd(&l->key, -1) == 0)
+ return;
+ unimplemented("unlock wakeup");
+}
+
+void
+rsleep(Rendez *r)
+{
+ unimplemented("rsleep");
+
+ // dumb implementation:
+ r->sleeping = 1;
+ unlock(r->l);
+ while(r->sleeping)
+ ;
+ lock(r->l);
+}
+
+void
+rwakeup(Rendez *r)
+{
+ unimplemented("rwakeup");
+
+ // dumb implementation:
+ r->sleeping = 0;
+}
+
+void
+rwakeupandunlock(Rendez *r)
+{
+ // dumb implementation:
+ rwakeup(r);
+ unlock(r->l);
+}
+
+void
+newosproc(M *mm, G *gg, void *stk, void (*fn)(void*), void *arg)
+{
+ unimplemented("newosproc");
+}
+
+int32
+getprocid(void)
+{
+ return 0;
+}
diff -r a6809e7103e9 -r 8e3ec1bb32ec src/runtime/rt1_amd64_linux.c
--- a/src/runtime/rt1_amd64_linux.c Mon Aug 04 16:29:22 2008 -0700
+++ b/src/runtime/rt1_amd64_linux.c Mon Aug 04 16:43:49 2008 -0700
@@ -3,6 +3,7 @@
// license that can be found in the LICENSE file.
#include "runtime.h"
+#include "amd64_linux.h"
#include "signals.h"
/* From /usr/include/asm-x86_64/sigcontext.h */
@@ -161,7 +162,7 @@
}
-sigaction a;
+static sigaction a;
void
initsig(void)
@@ -177,3 +178,235 @@
sys·rt_sigaction(i, &a, (void*)0, 8);
}
}
+
+// Linux futex. The simple cases really are simple:
+//
+// futex(addr, FUTEX_WAIT, val, duration, _, _)
+// Inside the kernel, atomically check that *addr == val
+// and go to sleep for at most duration.
+//
+// futex(addr, FUTEX_WAKE, val, _, _, _)
+// Wake up at least val procs sleeping on addr.
+//
+// (Of course, they have added more complicated things since then.)
+
+enum
+{
+ FUTEX_WAIT = 0,
+ FUTEX_WAKE = 1,
+
+ EINTR = 4,
+ EAGAIN = 11,
+};
+
+// TODO(rsc) I tried using 1<<40 here but it woke up (-ETIMEDOUT).
+// I wonder if the timespec that gets to the kernel
+// actually has two 32-bit numbers in it, so that
+// a 64-bit 1<<40 ends up being 0 seconds,
+// 1<<8 nanoseconds.
+static struct timespec longtime =
+{
+ 1<<30, // 34 years
+ 0
+};
+
+static void
+efutex(uint32 *addr, int32 op, int32 val, struct timespec *ts)
+{
+ int64 ret;
+
+again:
+ ret = futex(addr, op, val, ts, nil, 0);
+
+ // These happen when you use a debugger, among other times.
+ if(ret == -EAGAIN || ret == -EINTR){
+ // If we were sleeping, it's okay to wake up early.
+ if(op == FUTEX_WAIT)
+ return;
+
+ // If we were waking someone up, we don't know
+ // whether that succeeded, so wake someone else up too.
+ if(op == FUTEX_WAKE){
+prints("futexwake ");
+sys·printint(ret);
+prints("\n");
+ goto again;
+ }
+ }
+
+ if(ret < 0){
+ prints("futex error addr=");
+ sys·printpointer(addr);
+ prints(" op=");
+ sys·printint(op);
+ prints(" val=");
+ sys·printint(val);
+ prints(" ts=");
+ sys·printpointer(ts);
+ prints(" returned ");
+ sys·printint(-ret);
+ prints("\n");
+ *(int32*)101 = 202;
+ }
+}
+
+// Lock and unlock.
+// A zeroed Lock is unlocked (no need to initialize each lock).
+// The l->key is either 0 (unlocked), 1 (locked), or >=2 (contended).
+
+void
+lock(Lock *l)
+{
+ uint32 v;
+
+ if(l->key != 0) *(int32*)0x1001 = 0x1001;
+ l->key = 1;
+ return;
+
+ for(;;){
+ // Try for lock. If we incremented it from 0 to 1, we win.
+ if((v=xadd(&l->key, 1)) == 1)
+ return;
+
+ // We lose. It was already >=1 and is now >=2.
+ // Use futex to atomically check that the value is still
+ // what we think it is and go to sleep.
+ efutex(&l->key, FUTEX_WAIT, v, &longtime);
+ }
+}
+
+void
+unlock(Lock *l)
+{
+ uint32 v;
+
+ if(l->key != 1) *(int32*)0x1002 = 0x1002;
+ l->key = 0;
+ return;
+
+ // Unlock the lock. If we decremented from 1 to 0, wasn't contended.
+ if((v=xadd(&l->key, -1)) == 0)
+ return;
+
+ // The lock was contended. Mark it as unlocked and wake a waiter.
+ l->key = 0;
+ efutex(&l->key, FUTEX_WAKE, 1, nil);
+}
+
+// Sleep and wakeup (see description in runtime.h)
+
+void
+rsleep(Rendez *r)
+{
+ // Record that we're about to go to sleep and drop the lock.
+ r->sleeping = 1;
+ unlock(r->l);
+
+ // Go to sleep if r->sleeping is still 1.
+ efutex(&r->sleeping, FUTEX_WAIT, 1, &longtime);
+
+ // Reacquire the lock.
+ lock(r->l);
+}
+
+void
+rwakeup(Rendez *r)
+{
+ if(!r->sleeping)
+ return;
+
+ // Clear the sleeping flag in case sleeper
+ // is between unlock and futex.
+ r->sleeping = 0;
+
+ // Wake up if actually made it to sleep.
+ efutex(&r->sleeping, FUTEX_WAKE, 1, nil);
+}
+
+// Like rwakeup(r), unlock(r->l), but drops the lock before
+// waking the other proc. This reduces bouncing back and forth
+// in the scheduler: the first thing the other proc wants to do
+// is acquire r->l, so it helps to unlock it before we wake him.
+void
+rwakeupandunlock(Rendez *r)
+{
+ int32 wassleeping;
+
+ if(!r->sleeping){
+ unlock(r->l);
+ return;
+ }
+
+ r->sleeping = 0;
+ unlock(r->l);
+ efutex(&r->sleeping, FUTEX_WAKE, 1, nil);
+}
+
+enum
+{
+ CLONE_VM = 0x100,
+ CLONE_FS = 0x200,
+ CLONE_FILES = 0x400,
+ CLONE_SIGHAND = 0x800,
+ CLONE_PTRACE = 0x2000,
+ CLONE_VFORK = 0x4000,
+ CLONE_PARENT = 0x8000,
+ CLONE_THREAD = 0x10000,
+ CLONE_NEWNS = 0x20000,
+ CLONE_SYSVSEM = 0x40000,
+ CLONE_SETTLS = 0x80000,
+ CLONE_PARENT_SETTID = 0x100000,
+ CLONE_CHILD_CLEARTID = 0x200000,
+ CLONE_UNTRACED = 0x800000,
+ CLONE_CHILD_SETTID = 0x1000000,
+ CLONE_STOPPED = 0x2000000,
+ CLONE_NEWUTS = 0x4000000,
+ CLONE_NEWIPC = 0x8000000,
+};
+
+void
+newosproc(M *mm, G *gg, void *stk, void (*fn)(void*), void *arg)
+{
+ int64 ret;
+ int32 flags;
+
+ flags = CLONE_PARENT /* getppid doesn't change in child */
+ | CLONE_VM /* share memory */
+ | CLONE_FS /* share cwd, etc */
+ | CLONE_FILES /* share fd table */
+ | CLONE_SIGHAND /* share sig handler table */
+ | CLONE_PTRACE /* revisit - okay for now */
+ | CLONE_THREAD /* revisit - okay for now */
+ ;
+
+ if(0){
+ prints("newosproc stk=");
+ sys·printpointer(stk);
+ prints(" mm=");
+ sys·printpointer(mm);
+ prints(" gg=");
+ sys·printpointer(gg);
+ prints(" fn=");
+ sys·printpointer(fn);
+ prints(" arg=");
+ sys·printpointer(arg);
+ prints(" clone=");
+ sys·printpointer(clone);
+ prints("\n");
+ }
+
+ ret = clone(flags, stk, mm, gg, fn, arg);
+ if(ret < 0)
+ *(int32*)123 = 123;
+}
+
+void
+sys·sleep(int64 ms)
+{
+ struct timeval tv;
+
+ tv.tv_sec = ms/1000;
+ tv.tv_usec = ms%1000 * 1000;
+ select(0, nil, nil, nil, &tv);
+}
+
diff -r a6809e7103e9 -r 8e3ec1bb32ec src/runtime/runtime.c
--- a/src/runtime/runtime.c Mon Aug 04 16:29:22 2008 -0700
+++ b/src/runtime/runtime.c Mon Aug 04 16:43:49 2008 -0700
@@ -4,7 +4,6 @@
#include "runtime.h"
-G g0; // idle goroutine
int32 debug = 0;
void
@@ -24,10 +23,6 @@
sys·exit(2);
}
-static uint8* hunk;
-static uint32 nhunk;
-static uint64 nmmap;
-static uint64 nmal;
enum
{
NHUNK = 20<<20,
@@ -76,42 +71,51 @@
return n;
}
-static byte*
+static void*
brk(uint32 n)
{
- byte* v;
+ byte *v;
v = sys·mmap(nil, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, 0, 0);
- sys·memclr(v, n);
- nmmap += n;
+ m->mem.nmmap += n;
return v;
}
+
void*
mal(uint32 n)
{
byte* v;
+ Mem *mem;
// round to keep everything 64-bit aligned
n = rnd(n, 8);
- nmal += n;
- // do we have enough in contiguous hunk
- if(n > nhunk) {
-
- // if it is big allocate it separately
- if(n > NHUNK)
- return brk(n);
-
- // allocate a new contiguous hunk
- hunk = brk(NHUNK);
- nhunk = NHUNK;
+ // be careful. calling any function might invoke
+ // mal to allocate more stack.
+ if(n > NHUNK) {
+ // this call is okay - calling mal recursively
+ // won't change anything we depend on.
+ v = brk(n);
+ } else {
+ // allocate a new hunk if this one is too small
+ if(n > m->mem.nhunk) {
+ // better not to call brk here - it might grow the stack,
+ // causing a call to mal and the allocation of a
+ // new hunk behind our backs. then we'd toss away
+ // almost all of that new hunk and replace it.
+ // that'd just be a memory leak - the code would still run.
+ m->mem.hunk =
+ sys·mmap(nil, NHUNK, PROT_READ|PROT_WRITE,
+ MAP_ANON|MAP_PRIVATE, 0, 0);
+ m->mem.nhunk = NHUNK;
+ m->mem.nmmap += NHUNK;
+ }
+ v = m->mem.hunk;
+ m->mem.hunk += n;
+ m->mem.nhunk -= n;
}
-
- // allocate from the contiguous hunk
- v = hunk;
- hunk += n;
- nhunk -= n;
+ m->mem.nmal += n;
return v;
}
@@ -491,6 +495,44 @@
;
}
+int32
+getenvc(void)
+{
+ return envc;
+}
+
+byte*
+getenv(int8 *s)
+{
+ int32 i, j, len;
+ byte *v, *bs;
+
+ bs = (byte*)s;
+ len = findnull(s);
+ for(i=0; i<envc; i++){
+ v = envv[i];
+ for(j=0; j<len; j++)
+ if(bs[j] != v[j])
+ goto nomatch;
+ if(v[len] != '=')
+ goto nomatch;
+ return v+len+1;
+ nomatch:;
+ }
+ return nil;
+}
+
+int32
+atoi(byte *p)
+{
+ int32 n;
+
+ n = 0;
+ while('0' <= *p && *p <= '9')
+ n = n*10 + *p++ - '0';
+ return n;
+}
+
//func argc() int32; // return number of arguments
void
sys·argc(int32 v)
@@ -579,9 +621,35 @@
if(sizeof(k) != 8) throw("bad k");
if(sizeof(l) != 8) throw("bad l");
// prints(1"check ok\n");
+
+ uint32 z;
+ z = 1;
+ if(!cas(&z, 1, 2))
+ throw("cas1");
+ if(z != 2)
+ throw("cas2");
+
+ z = 4;
+ if(cas(&z, 5, 6))
+ throw("cas3");
+ if(z != 4)
+ throw("cas4");
+
initsig();
}
+uint32
+xadd(uint32 *val, uint32 delta)
+{
+ uint32 v;
+
+ for(;;){
+ v = *val;
+ if(cas(val, v, v+delta))
+ return v+delta;
+ }
+}
+
/*
* map and chan helpers for
* dealing with unknown types
diff -r a6809e7103e9 -r 8e3ec1bb32ec src/runtime/runtime.h
--- a/src/runtime/runtime.h Mon Aug 04 16:29:22 2008 -0700
+++ b/src/runtime/runtime.h Mon Aug 04 16:43:49 2008 -0700
@@ -40,8 +40,11 @@
typedef struct Gobuf Gobuf;
typedef struct G G;
typedef struct M M;
-typedef struct Stktop Stktop;
+typedef struct Stktop Stktop;
typedef struct Alg Alg;
+typedef struct Lock Lock;
+typedef struct Rendez Rendez;
+typedef struct Mem Mem;
/*
* per cpu declaration
@@ -57,6 +60,7 @@
// G status
Gidle,
Grunnable,
+ Grunning,
Gwaiting,
Gdead,
};
@@ -69,6 +73,15 @@
/*
* structures
*/
+struct Lock
+{
+ uint32 key;
+};
+struct Rendez
+{
+ Lock* l;
+ uint32 sleeping; // someone is sleeping (Linux)
+};
struct String
{
int32 len;
@@ -111,6 +124,16 @@
int16 status;
int32 goid;
int32 selgen; // valid sudog pointer
+ G* runlink;
+ Lock runlock;
+ M* m; // for debuggers
+};
+struct Mem
+{
+ uint8* hunk;
+ uint32 nhunk;
+ uint64 nmmap;
+ uint64 nmal;
};
struct M
{
@@ -124,6 +147,10 @@
byte* moresp;
int32 siz1;
int32 siz2;
+ Rendez waitr;
+ M* waitlink;
+ int32 pid; // for debuggers
+ Mem mem;
};
struct Stktop
{
@@ -161,6 +188,7 @@
M* allm;
G* allg;
int32 goidgen;
+extern int32 gomaxprocs;
/*
* common functions and data
@@ -195,6 +223,37 @@
int32 write(int32, void*, int32);
void close(int32);
int32 fstat(int32, void*);
+bool cas(uint32*, uint32, uint32);
+uint32 xadd(uint32*, uint32);
+void exit1(int32);
+void ready(G*);
+byte* getenv(int8*);
+int32 atoi(byte*);
+void newosproc(M *mm, G *gg, void *stk, void (*fn)(void*), void *arg);
+int32 getprocid(void);
+
+/*
+ * mutual exclusion locks. in the uncontended case,
+ * as fast as spin locks (just a few user-level instructions),
+ * but on the contention path they sleep in the kernel.
+ */
+void lock(Lock*);
+void unlock(Lock*);
+void lockinit(Lock*);
+
+/*
+ * sleep and wakeup.
+ * a Rendez is somewhere to sleep. it is protected by the lock r->l.
+ * the caller must acquire r->l, check the condition, and if the
+ * condition is false, call rsleep. rsleep will atomically drop the lock
+ * and go to sleep. a subsequent rwakeup (caller must hold r->l)
+ * will wake up the guy who is rsleeping. the lock keeps rsleep and
+ * rwakeup from missing each other.
+ * n.b. only one proc can rsleep on a given rendez at a time.
+ */
+void rsleep(Rendez*);
+void rwakeup(Rendez*);
+void rwakeupandunlock(Rendez*);
/*
* low level go -called
diff -r a6809e7103e9 -r 8e3ec1bb32ec src/runtime/sys_amd64_darwin.s
--- a/src/runtime/sys_amd64_darwin.s Mon Aug 04 16:29:22 2008 -0700
+++ b/src/runtime/sys_amd64_darwin.s Mon Aug 04 16:43:49 2008 -0700
@@ -6,6 +6,7 @@
// System calls and other sys.stuff for AMD64, Darwin
//
+// TODO(rsc): Either sys·exit or exit1 is wrong!
TEXT sys·exit(SB),1,$-8
MOVL 8(SP), DI // arg 1 exit status
MOVL $(0x2000000+1), AX // syscall entry
@@ -13,6 +14,13 @@
CALL notok(SB)
RET
+TEXT exit1(SB),1,$-8
+ MOVL 8(SP), DI // arg 1 exit status
+ MOVL $(0x2000000+1), AX // syscall entry
+ SYSCALL
+ CALL notok(SB)
+ RET
+
TEXT sys·write(SB),1,$-8
MOVL 8(SP), DI // arg 1 fid
MOVQ 16(SP), SI // arg 2 buf
@@ -80,7 +88,7 @@
CALL sighandler(SB)
RET
-TEXT sys·mmap(SB),1,$-8
+TEXT sys·mmap(SB),7,$-8
MOVQ 8(SP), DI // arg 1 addr
MOVL 16(SP), SI // arg 2 len
MOVL 20(SP), DX // arg 3 prot
@@ -98,7 +106,7 @@
MOVQ BP, (BP)
RET
-TEXT sys·memclr(SB),1,$-8
+TEXT sys·memclr(SB),7,$-8
MOVQ 8(SP), DI // arg 1 addr
MOVL 16(SP), CX // arg 2 count
ADDL $7, CX
diff -r a6809e7103e9 -r 8e3ec1bb32ec src/runtime/sys_amd64_linux.s
--- a/src/runtime/sys_amd64_linux.s Mon Aug 04 16:29:22 2008 -0700
+++ b/src/runtime/sys_amd64_linux.s Mon Aug 04 16:43:49 2008 -0700
@@ -8,7 +8,13 @@
TEXT sys·exit(SB),1,$0-8
MOVL 8(SP), DI
- MOVL $60, AX
+ MOVL $231, AX // force all os threads to exit
+ SYSCALL
+ RET
+
+TEXT exit1(SB),1,$0-8
+ MOVL 8(SP), DI
+ MOVL $60, AX // exit the current os thread
SYSCALL
RET
@@ -61,8 +67,7 @@
MOVL 8(SP), DI
MOVQ 16(SP), SI
MOVQ 24(SP), DX
- MOVQ 32(SP), CX
- MOVL CX, R10
+ MOVQ 32(SP), R10
MOVL $13, AX // syscall entry
SYSCALL
RET
@@ -74,11 +79,11 @@
CALL sighandler(SB)
RET
-TEXT sys·mmap(SB),1,$0-32
+TEXT sys·mmap(SB),7,$0-32
MOVQ 8(SP), DI
MOVL 16(SP), SI
MOVL 20(SP), DX
- MOVL 24(SP), CX
+ MOVL 24(SP), R10
MOVL 28(SP), R8
MOVL 32(SP), R9
@@ -102,7 +107,7 @@
MOVQ BP, (BP)
RET
-TEXT sys·memclr(SB),1,$0-16
+TEXT sys·memclr(SB),7,$0-16
MOVQ 8(SP), DI // arg 1 addr
MOVL 16(SP), CX // arg 2 count (cannot be zero)
ADDL $7, CX
@@ -123,3 +128,74 @@
MOVQ x+8(FP), BX
MOVQ BX, -8(AX) // set calling pc
RET
+
+// int64 futex(int32 *uaddr, int32 op, int32 val,
+// struct timespec *timeout, int32 *uaddr2, int32 val2);
+TEXT futex(SB),1,$0
+ MOVQ 8(SP), DI
+ MOVL 16(SP), SI
+ MOVL 20(SP), DX
+ MOVQ 24(SP), R10
+ MOVQ 32(SP), R8
+ MOVL 40(SP), R9
+ MOVL $202, AX
+ SYSCALL
+ RET
+
+// int64 clone(int32 flags, void *stack, M *m, G *g, void (*fn)(void*), void *arg);
+TEXT clone(SB),7,$0
+ MOVL 8(SP), DI
+ MOVQ 16(SP), SI
+
+ // Copy m, g, fn, arg off parent stack for use by child.
+ // Careful: Linux system call clobbers CX and R11.
+ MOVQ 24(SP), R8
+ MOVQ 32(SP), R9
+ MOVQ 40(SP), R12
+ MOVQ 48(SP), R13
+
+ MOVL $56, AX
+ SYSCALL
+
+ // In parent, return.
+ CMPQ AX, $0
+ JEQ 2(PC)
+ RET
+
+ // In child, call fn(arg) on new stack
+ MOVQ SI, SP
+ MOVQ R8, R14 // m
+ MOVQ R9, R15 // g
+ PUSHQ R13
+ CALL R12
+
+ // It shouldn't return. If it does, exit
+ MOVL $111, DI
+ MOVL $60, AX
+ SYSCALL
+ JMP -3(PC) // keep exiting
+
+// int64 select(int32, void*, void*, void*, void*)
+TEXT select(SB),1,$0
+ MOVL 8(SP), DI
+ MOVQ 16(SP), SI
+ MOVQ 24(SP), DX
+ MOVQ 32(SP), R10
+ MOVQ 40(SP), R8
+ MOVL $23, AX
+ SYSCALL
+ RET
+
+// Linux allocates each thread its own pid, like Plan 9.
+// But the getpid() system call returns the pid of the
+// original thread (the one that exec started with),
+// no matter which thread asks. This system call,
+// which Linux calls gettid, returns the actual pid of
+// the calling thread, not the fake one.
+//
+// int32 getprocid(void)
+TEXT getprocid(SB),1,$0
+ MOVL $186, AX
+ SYSCALL
+ RET
+
diff -r a6809e7103e9 -r 8e3ec1bb32ec src/syscall/syscall_amd64_linux.s
--- a/src/syscall/syscall_amd64_linux.s Mon Aug 04 16:29:22 2008 -0700
+++ b/src/syscall/syscall_amd64_linux.s Mon Aug 04 16:43:49 2008 -0700
@@ -7,7 +7,9 @@
//
// func Syscall(trap int64, a1, a2, a3 int64) (r1, r2, err int64);
-// Trap # in AX, args in DI SI DX, return in AX DX
+// Trap # in AX, args in DI SI DX R10 R8 R9, return in AX DX
+// Note that this differs from "standard" ABI convention, which
+// would pass 4th arg in CX, not R10.
TEXT syscall·Syscall(SB),7,$-8
MOVQ 16(SP), DI
changeset: 486:5b619aac0233
user: Russ Cox <[email protected]>
date: Tue Aug 05 14:18:47 2008 -0700
summary: * comment, clean up scheduler
diff -r 942605b8b20f -r 5b619aac0233 src/runtime/Makefile
--- a/src/runtime/Makefile Tue Aug 05 11:14:35 2008 -0700
+++ b/src/runtime/Makefile Tue Aug 05 14:18:47 2008 -0700
@@ -49,10 +49,10 @@
rm -f *.$(O) *.a runtime.acid
%.$O: %.c
- $(CC) $<
+ $(CC) -w $<
sys_file.$O: sys_file.c sys_types.h $(OS_H)
- $(CC) -D$(GOARCH)_$(GOOS) $<
+ $(CC) -w -D$(GOARCH)_$(GOOS) $<
%.$O: %.s
$(AS) $<
diff -r 942605b8b20f -r 5b619aac0233 src/runtime/amd64_linux.h
--- a/src/runtime/amd64_linux.h Tue Aug 05 11:14:35 2008 -0700
+++ b/src/runtime/amd64_linux.h Tue Aug 05 14:18:47 2008 -0700
@@ -48,6 +48,6 @@
// Linux-specific system calls
int64 futex(uint32*, int32, uint32, struct timespec*, uint32*, uint32);
-int64 clone(int32, void*, M*, G*, void(*)(void*), void*);
+int64 clone(int32, void*, M*, G*, void(*)(void));
int64 select(int32, void*, void*, void*, void*);
diff -r 942605b8b20f -r 5b619aac0233 src/runtime/chan.c
--- a/src/runtime/chan.c Tue Aug 05 11:14:35 2008 -0700
+++ b/src/runtime/chan.c Tue Aug 05 14:18:47 2008 -0700
@@ -487,7 +487,7 @@
SudoG *sg;
G *gp;
- byte *ae, *as;
+ byte *as;
if(xxx) {
prints("selectgo: sel=");
@@ -630,6 +630,8 @@
asynr:
asyns:
throw("asyn");
+ return; // compiler doesn't know throw doesn't return
+
gotr:
// recv path to wakeup the sender (sg)
if(xxx) {
diff -r 942605b8b20f -r 5b619aac0233 src/runtime/map.c
--- a/src/runtime/map.c Tue Aug 05 11:14:35 2008 -0700
+++ b/src/runtime/map.c Tue Aug 05 14:18:47 2008 -0700
@@ -199,7 +199,6 @@
void
sys·mapassign1(Hmap *m, ...)
{
- Link **ll;
byte *ak, *av;
ak = (byte*)&m + m->ko;
diff -r 942605b8b20f -r 5b619aac0233 src/runtime/print.c
--- a/src/runtime/print.c Tue Aug 05 11:14:35 2008 -0700
+++ b/src/runtime/print.c Tue Aug 05 14:18:47 2008 -0700
@@ -8,7 +8,6 @@
void
dump(byte *p, int32 n)
{
- uint32 v;
int32 i;
for(i=0; i<n; i++) {
diff -r 942605b8b20f -r 5b619aac0233 src/runtime/proc.c
--- a/src/runtime/proc.c Tue Aug 05 11:14:35 2008 -0700
+++ b/src/runtime/proc.c Tue Aug 05 14:18:47 2008 -0700
@@ -9,28 +9,101 @@
M m0;
G g0; // idle goroutine for m0
-// Maximum number of os procs (M's) to kick off.
-// Can override with $gomaxprocs environment variable.
-// For now set to 1 (single-threaded), because not
-// everything is properly locked (e.g., chans) and because
-// Darwin's multithreading code isn't implemented.
-int32 gomaxprocs = 1;
-
static int32 debug = 0;
+// Go scheduler
+//
+// The go scheduler's job is to match ready-to-run goroutines (`g's)
+// with waiting-for-work schedulers (`m's). If there are ready gs
+// and no waiting ms, ready() will start a new m running in a new
+// OS thread, so that all ready gs can run simultaneously, up to a limit.
+// For now, ms never go away.
+//
+// The default maximum number of ms is one: go runs single-threaded.
+// This is because some locking details have to be worked ou
+// (select in particular is not locked properly) and because the low-level
+// code hasn't been written yet for OS X. Setting the environmen
+// variable $gomaxprocs changes sched.mmax for now.
+//
+// Even a program that can run without deadlock in a single process
+// might use more ms if given the chance. For example, the prime
+// sieve will use as many ms as there are primes (up to sched.mmax),
+// allowing different stages of the pipeline to execute in parallel.
+// We could revisit this choice, only kicking off new ms for blocking
+// system calls, but that would limit the amount of parallel computation
+// that go would try to do.
+//
+// In general, one could imagine all sorts of refinements to the
+// scheduler, but the goal now is just to get something working on
+// Linux and OS X.
+
struct Sched {
- G *runhead;
- G *runtail;
- int32 nwait;
- int32 nready;
- int32 ng;
- int32 nm;
- M *wait;
Lock;
+
+ G *gfree; // available gs (status == Gdead)
+
+ G *ghead; // gs waiting to run
+ G *gtail;
+ int32 gwait; // number of gs waiting to run
+ int32 gcount; // number of gs that are alive
+
+ M *mhead; // ms waiting for work
+ int32 mwait; // number of ms waiting for work
+ int32 mcount; // number of ms that are alive
+ int32 mmax; // max number of ms allowed
+
+ int32 predawn; // running initialization, don't run new gs.
};
Sched sched;
+// Scheduling helpers. Sched must be locked.
+static void gput(G*); // put/get on ghead/gtail
+static G* gget(void);
+static void mput(M*); // put/get on mhead
+static M* mget(void);
+static void gfput(G*); // put/get on gfree
+static G* gfget(void);
+static void mnew(void); // kick off new m
+static void readylocked(G*); // ready, but sched is locked
+
+// Scheduler loop.
+static void scheduler(void);
+
+// Called before main·init_function.
+void
+schedinit(void)
+{
+ int32 n;
+ byte *p;
+
+ sched.mmax = 1;
+ p = getenv("gomaxprocs");
+ if(p != nil && (n = atoi(p)) != 0)
+ sched.mmax = n;
+ sched.mcount = 1;
+ sched.predawn = 1;
+}
+
+// Called after main·init_function; main·main is on ready queue.
+void
+m0init(void)
+{
+ int32 i;
+
+ // Let's go.
+ sched.predawn = 0;
+
+ // There's already one m (us).
+ // If main·init_function started other goroutines,
+ // kick off new ms to handle them, like ready
+ // would have, had it not been pre-dawn.
+ for(i=1; i<sched.gcount && i<sched.mmax; i++)
+ mnew();
+
+ scheduler();
+}
+
void
sys·goexit(void)
{
@@ -39,24 +112,11 @@
sys·printint(g->goid);
prints("\n");
}
- g->status = Gdead;
+ g->status = Gmoribund;
sys·gosched();
}
void
-schedinit(void)
-{
- byte *p;
- extern int32 getenvc(void);
-
- p = getenv("gomaxprocs");
- if(p && '0' <= *p && *p <= '9')
- gomaxprocs = atoi(p);
- sched.nm = 1;
- sched.nwait = 1;
-}
-
-void
sys·newproc(int32 siz, byte* fn, byte* arg0)
{
byte *stk, *sp;
@@ -71,22 +131,18 @@
if(siz > 1024)
throw("sys·newproc: too many args");
- // try to rip off an old goroutine
- for(newg=allg; newg!=nil; newg=newg->alllink)
- if(newg->status == Gdead)
- break;
+ lock(&sched);
- if(newg == nil) {
+ if((newg = gfget()) != nil){
+ newg->status = Gwaiting;
+ stk = newg->stack0;
+ }else{
newg = mal(sizeof(G));
stk = mal(4096);
newg->stack0 = stk;
-
newg->status = Gwaiting;
newg->alllink = allg;
allg = newg;
- } else {
- stk = newg->stack0;
- newg->status = Gwaiting;
}
newg->stackguard = stk+160;
@@ -104,14 +160,13 @@
newg->sched.SP = sp;
newg->sched.PC = fn;
- lock(&sched);
- sched.ng++;
+ sched.gcount++;
goidgen++;
newg->goid = goidgen;
+
+ readylocked(newg);
unlock(&sched);
- ready(newg);
-
//prints(" goid=");
//sys·printint(newg->goid);
//prints("\n");
@@ -132,193 +187,248 @@
}
}
-void newmach(void);
+// Put on `g' queue. Sched must be locked.
+static void
+gput(G *g)
+{
+ g->schedlink = nil;
+ if(sched.ghead == nil)
+ sched.ghead = g;
+ else
+ sched.gtail->schedlink = g;
+ sched.gtail = g;
+ sched.gwait++;
+}
+// Get from `g' queue. Sched must be locked.
+static G*
+gget(void)
+{
+ G *g;
+
+ g = sched.ghead;
+ if(g){
+ sched.ghead = g->schedlink;
+ if(sched.ghead == nil)
+ sched.gtail = nil;
+ sched.gwait--;
+ }
+ return g;
+}
+
+// Put on `m' list. Sched must be locked.
+static void
+mput(M *m)
+{
+ m->schedlink = sched.mhead;
+ sched.mhead = m;
+ sched.mwait++;
+}
+
+// Get from `m' list. Sched must be locked.
+static M*
+mget(void)
+{
+ M *m;
+
+ m = sched.mhead;
+ if(m){
+ sched.mhead = m->schedlink;
+ sched.mwait--;
+ }
+ return m;
+}
+
+// Put on gfree list. Sched must be locked.
+static void
+gfput(G *g)
+{
+ g->schedlink = sched.gfree;
+ sched.gfree = g;
+}
+
+// Get from gfree list. Sched must be locked.
+static G*
+gfget(void)
+{
+ G *g;
+
+ g = sched.gfree;
+ if(g)
+ sched.gfree = g->schedlink;
+ return g;
+}
+
+// Mark g ready to run.
+void
+ready(G *g)
+{
+ // Wait for g to stop running (for example, it migh
+ // have queued itself on a channel but not yet gotten
+ // a chance to call sys·gosched and actually go to sleep).
+ notesleep(&g->stopped);
+
+ lock(&sched);
+ readylocked(g);
+ unlock(&sched);
+}
+
+// Mark g ready to run. Sched is already locked,
+// and g is known not to be running right now
+// (i.e., ready has slept on g->stopped or the g was
+// just allocated in sys·newproc).
static void
readylocked(G *g)
{
+ M *m;
+
+ // Mark runnable.
+ if(g->status == Grunnable || g->status == Grunning)
+ throw("bad g->status in ready");
g->status = Grunnable;
- if(sched.runhead == nil)
- sched.runhead = g;
- else
- sched.runtail->runlink = g;
- sched.runtail = g;
- g->runlink = nil;
- sched.nready++;
- // Don't wake up another scheduler.
- // This only gets called when we're
- // about to reschedule anyway.
+
+ // Before we've gotten to main·main,
+ // only queue new gs, don't run them
+ // or try to allocate new ms for them.
+ // That includes main·main itself.
+ if(sched.predawn){
+ gput(g);
+ }
+
+ // Else if there's an m waiting, give it g.
+ else if((m = mget()) != nil){
+ m->nextg = g;
+ notewakeup(&m->havenextg);
+ }
+
+ // Else put g on queue, kicking off new m if needed.
+ else{
+ gput(g);
+ if(sched.mcount < sched.mmax)
+ mnew();
+ }
}
-static Lock print;
-
-void
-ready(G *g)
-{
- M *mm;
-
- // gp might be running on another scheduler.
- // (E.g., it queued and then we decided to wake it up
- // before it had a chance to sys·gosched().)
- // Grabbing the runlock ensures that it is not running elsewhere.
- // You can delete the if check, but don't delete the
- // lock/unlock sequence (being able to grab the lock
- // means the proc has gone to sleep).
- lock(&g->runlock);
- if(g->status == Grunnable || g->status == Grunning)
- *(int32*)0x1023 = 0x1023;
- lock(&sched);
- g->status = Grunnable;
- if(sched.runhead == nil)
- sched.runhead = g;
- else
- sched.runtail->runlink = g;
- sched.runtail = g;
- g->runlink = nil;
- unlock(&g->runlock);
- sched.nready++;
- if(sched.nready > sched.nwait)
- if(gomaxprocs == 0 || sched.nm < gomaxprocs){
- if(debug){
- prints("new scheduler: ");
- sys·printint(sched.nready);
- prints(" > ");
- sys·printint(sched.nwait);
- prints("\n");
- }
- sched.nwait++;
- newmach();
- }
- if(sched.wait){
- mm = sched.wait;
- sched.wait = mm->waitlink;
- rwakeupandunlock(&mm->waitr);
- }else
- unlock(&sched);
-}
-
-extern void p0(void), p1(void);
-
-G*
-nextgoroutine(void)
+// Get the next goroutine that m should run.
+// Sched must be locked on entry, is unlocked on exit.
+static G*
+nextgandunlock(void)
{
G *gp;
- while((gp = sched.runhead) == nil){
- if(debug){
- prints("nextgoroutine runhead=nil ng=");
- sys·printint(sched.ng);
- prints("\n");
- }
- if(sched.ng == 0)
- return nil;
- m->waitlink = sched.wait;
- m->waitr.l = &sched.Lock;
- sched.wait = m;
- sched.nwait++;
- if(sched.nm == sched.nwait)
- prints("all goroutines are asleep - deadlock!\n");
- rsleep(&m->waitr);
- sched.nwait--;
+ if((gp = gget()) != nil){
+ unlock(&sched);
+ return gp;
}
- sched.nready--;
- sched.runhead = gp->runlink;
+
+ mput(m);
+ if(sched.mcount == sched.mwait)
+ prints("warning: all goroutines are asleep - deadlock!\n");
+ m->nextg = nil;
+ noteclear(&m->havenextg);
+ unlock(&sched);
+
+ notesleep(&m->havenextg);
+ if((gp = m->nextg) == nil)
+ throw("bad m->nextg in nextgoroutine");
+ m->nextg = nil;
return gp;
}
-void
+// Scheduler loop: find g to run, run it, repeat.
+static void
scheduler(void)
{
G* gp;
- m->pid = getprocid();
-
- gosave(&m->sched);
+ // Initialization.
+ m->procid = getprocid();
lock(&sched);
- if(m->curg == nil){
- // Brand new scheduler; nwait counts us.
- // Not anymore.
- sched.nwait--;
- }else{
+ if(gosave(&m->sched)){
+ // Jumped here via gosave/gogo, so didn'
+ // execute lock(&sched) above.
+ lock(&sched);
+
+ // Just finished running m->curg.
gp = m->curg;
- gp->m = nil;
+ gp->m = nil; // for debugger
switch(gp->status){
+ case Grunnable:
case Gdead:
- sched.ng--;
- if(debug){
- prints("sched: dead: ");
- sys·printint(sched.ng);
- prints("\n");
- }
+ // Shouldn't have been running!
+ throw("bad gp->status in sched");
+ case Grunning:
+ gp->status = Grunnable;
+ gput(gp);
break;
- case Grunning:
- readylocked(gp);
- break;
- case Grunnable:
- // don't want to see this
- *(int32*)0x456 = 0x234;
+ case Gmoribund:
+ gp->status = Gdead;
+ if(--sched.gcount == 0)
+ sys·exit(0);
break;
}
- unlock(&gp->runlock);
+ notewakeup(&gp->stopped);
}
- gp = nextgoroutine();
- if(gp == nil) {
-// prints("sched: no more work\n");
- sys·exit(0);
- }
- unlock(&sched);
+ // Find (or wait for) g to run. Unlocks sched.
+ gp = nextgandunlock();
- lock(&gp->runlock);
+ noteclear(&gp->stopped);
gp->status = Grunning;
m->curg = gp;
- gp->m = m;
+ gp->m = m; // for debugger
g = gp;
gogo(&gp->sched);
}
-void
-newmach(void)
-{
- M *mm;
- byte *stk, *stktop;
- int64 ret;
-
- sched.nm++;
- if(!(sched.nm&(sched.nm-1))){
- sys·printint(sched.nm);
- prints(" threads\n");
- }
- mm = mal(sizeof(M)+sizeof(G)+1024+104);
- sys·memclr((byte*)mm, sizeof(M));
- mm->g0 = (G*)(mm+1);
- sys·memclr((byte*)mm->g0, sizeof(G));
- stk = (byte*)mm->g0 + 104;
- stktop = stk + 1024;
- mm->g0->stackguard = stk;
- mm->g0->stackbase = stktop;
- newosproc(mm, mm->g0, stktop, (void(*)(void*))scheduler, nil);
-}
-
-void
-gom0init(void)
-{
- scheduler();
-}
-
+// Enter scheduler. If g->status is Grunning,
+// re-queues g and runs everyone else who is waiting
+// before running g again. If g->status is Gmoribund,
+// kills off g.
void
sys·gosched(void)
{
if(gosave(&g->sched) == 0){
- // (rsc) signal race here?
+ // TODO(rsc) signal race here?
+ // If a signal comes in between
+ // changing g and changing SP,
+ // growing the stack will fail.
g = m->g0;
gogo(&m->sched);
}
}
+// Fork off a new m. Sched must be locked.
+static void
+mnew(void)
+{
+ M *m;
+ G *g;
+ byte *stk, *stktop;
+
+ sched.mcount++;
+ if(debug){
+ sys·printint(sched.mcount);
+ prints(" threads\n");
+ }
+
+ // Allocate m, g, stack in one chunk.
+ // 1024 and 104 are the magic constants
+ // use in rt0_amd64.s when setting up g0.
+ m = mal(sizeof(M)+sizeof(G)+104+1024);
+ g = (G*)(m+1);
+ stk = (byte*)g + 104;
+ stktop = stk + 1024;
+
+ m->g0 = g;
+ g->stackguard = stk;
+ g->stackbase = stktop;
+ newosproc(m, g, stktop, scheduler);
+}
+
//
-// the calling sequence for a routine that
+// the calling sequence for a routine tha
// needs N bytes stack, A args.
//
// N1 = (N+160 > 4096)? N+160: 0
diff -r 942605b8b20f -r 5b619aac0233 src/runtime/rt0_amd64.s
--- a/src/runtime/rt0_amd64.s Tue Aug 05 11:14:35 2008 -0700
+++ b/src/runtime/rt0_amd64.s Tue Aug 05 14:18:47 2008 -0700
@@ -41,7 +41,7 @@
PUSHQ $main·main(SB) // entry
PUSHQ $16 // arg size
CALL sys·newproc(SB)
- CALL gom0init(SB)
+ CALL m0init(SB)
POPQ AX
POPQ AX
diff -r 942605b8b20f -r 5b619aac0233 src/runtime/rt1_amd64_darwin.c
--- a/src/runtime/rt1_amd64_darwin.c Tue Aug 05 11:14:35 2008 -0700
+++ b/src/runtime/rt1_amd64_darwin.c Tue Aug 05 14:18:47 2008 -0700
@@ -191,7 +191,7 @@
void
lock(Lock *l)
{
- if(xadd(&l->key, 1) == 1)
+ if(cas(&l->key, 0, 1))
return;
unimplemented("lock wait");
}
@@ -199,43 +199,33 @@
void
unlock(Lock *l)
{
- if(xadd(&l->key, -1) == 0)
+ if(cas(&l->key, 1, 0))
return;
unimplemented("unlock wakeup");
}
void
-rsleep(Rendez *r)
+noteclear(Note *n)
{
- unimplemented("rsleep");
-
- // dumb implementation:
- r->sleeping = 1;
- unlock(r->l);
- while(r->sleeping)
- ;
- lock(r->l);
+ n->lock.key = 0;
+ lock(&n->lock);
}
void
-rwakeup(Rendez *r)
+notesleep(Note *n)
{
- unimplemented("rwakeup");
-
- // dumb implementation:
- r->sleeping = 0;
+ lock(&n->lock);
+ unlock(&n->lock);
}
void
-rwakeupandunlock(Rendez *r)
+notewakeup(Note *n)
{
- // dumb implementation:
- rwakeup(r);
- unlock(r->l);
+ unlock(&n->lock);
}
void
-newosproc(M *mm, G *gg, void *stk, void (*fn)(void*), void *arg)
+newosproc(M *mm, G *gg, void *stk, void (*fn)(void))
{
unimplemented("newosproc");
}
diff -r 942605b8b20f -r 5b619aac0233 src/runtime/rt1_amd64_linux.c
--- a/src/runtime/rt1_amd64_linux.c Tue Aug 05 11:14:35 2008 -0700
+++ b/src/runtime/rt1_amd64_linux.c Tue Aug 05 14:18:47 2008 -0700
@@ -138,21 +138,19 @@
void
sighandler(int32 sig, siginfo* info, void** context)
{
- int32 i;
-
if(sig < 0 || sig >= NSIG){
prints("Signal ");
sys·printint(sig);
}else{
prints(sigtab[sig].name);
}
-
+
struct sigcontext *sc = &(((struct ucontext *)context)->uc_mcontext);
-
+
prints("\nFaulting address: 0x"); sys·printpointer(info->si_addr);
prints("\npc: 0x"); sys·printpointer((void *)sc->rip);
prints("\n\n");
-
+
traceback((void *)sc->rip, (void *)sc->rsp, (void *)sc->r15);
tracebackothers((void*)sc->r15);
print_sigcontext(sc);
@@ -179,16 +177,14 @@
}
}
-// Linux futex. The simple cases really are simple:
+// Linux futex.
//
-// futex(addr, FUTEX_WAIT, val, duration, _, _)
-// Inside the kernel, atomically check that *addr == val
-// and go to sleep for at most duration.
+// futexsleep(uint32 *addr, uint32 val)
+// futexwakeup(uint32 *addr)
//
-// futex(addr, FUTEX_WAKE, val, _, _, _)
-// Wake up at least val procs sleeping on addr.
-//
-// (Of course, they have added more complicated things since then.)
+// Futexsleep atomically checks if *addr == val and if so, sleeps on addr.
+// Futexwakeup wakes up one thread sleeping on addr.
+// Futexsleep is allowed to wake up spuriously.
enum
{
@@ -199,10 +195,10 @@
EAGAIN = 11,
};
-// TODO(rsc) I tried using 1<<40 here but it woke up (-ETIMEDOUT).
+// TODO(rsc) I tried using 1<<40 here but futex woke up (-ETIMEDOUT).
// I wonder if the timespec that gets to the kernel
-// actually has two 32-bit numbers in it, so that
-// a 64-bit 1<<40 ends up being 0 seconds,
+// actually has two 32-bit numbers in it, so tha
+// a 64-bit 1<<40 ends up being 0 seconds,
// 1<<8 nanoseconds.
static struct timespec longtime =
{
@@ -210,69 +206,106 @@
0
};
+// Atomically,
+// if(*addr == val) sleep
+// Might be woken up spuriously; that's allowed.
static void
-efutex(uint32 *addr, int32 op, int32 val, struct timespec *ts)
+futexsleep(uint32 *addr, uint32 val)
{
int64 ret;
+
+ ret = futex(addr, FUTEX_WAIT, val, &longtime, nil, 0);
+ if(ret >= 0 || ret == -EAGAIN || ret == -EINTR)
+ return;
-again:
- ret = futex(addr, op, val, ts, nil, 0);
-
- // These happen when you use a debugger, among other times.
- if(ret == -EAGAIN || ret == -EINTR){
- // If we were sleeping, it's okay to wake up early.
- if(op == FUTEX_WAIT)
- return;
-
- // If we were waking someone up, we don't know
- // whether that succeeded, so wake someone else up too.
- if(op == FUTEX_WAKE){
-prints("futexwake ");
-sys·printint(ret);
-prints("\n");
- goto again;
- }
- }
-
- if(ret < 0){
- prints("futex error addr=");
- sys·printpointer(addr);
- prints(" op=");
- sys·printint(op);
- prints(" val=");
- sys·printint(val);
- prints(" ts=");
- sys·printpointer(ts);
- prints(" returned ");
- sys·printint(-ret);
- prints("\n");
- *(int32*)101 = 202;
- }
+ prints("futexsleep addr=");
+ sys·printpointer(addr);
+ prints(" val=");
+ sys·printint(val);
+ prints(" returned ");
+ sys·printint(ret);
+ prints("\n");
+ *(int32*)0x1005 = 0x1005;
}
-// Lock and unlock.
-// A zeroed Lock is unlocked (no need to initialize each lock).
-// The l->key is either 0 (unlocked), 1 (locked), or >=2 (contended).
+// If any procs are sleeping on addr, wake up at least one.
+static void
+futexwakeup(uint32 *addr)
+{
+ int64 ret;
+
+ ret = futex(addr, FUTEX_WAKE, 1, nil, nil, 0);
+
+ if(ret >= 0)
+ return;
+
+ // I don't know that futex wakeup can return
+ // EAGAIN or EINTR, but if it does, it would be
+ // safe to loop and call futex again.
+
+ prints("futexwakeup addr=");
+ sys·printpointer(addr);
+ prints(" returned ");
+ sys·printint(ret);
+ prints("\n");
+ *(int32*)0x1006 = 0x1006;
+}
+
+
+// Lock and unlock.
+//
+// The lock state is a single 32-bit word that holds
+// a 31-bit count of threads waiting for the lock
+// and a single bit (the low bit) saying whether the lock is held.
+// The uncontended case runs entirely in user space.
+// When contention is detected, we defer to the kernel (futex).
+//
+// A reminder: compare-and-swap cas(addr, old, new) does
+// if(*addr == old) { *addr = new; return 1; }
+// else return 0;
+// but atomically.
void
lock(Lock *l)
{
uint32 v;
+
+again:
+ v = l->key;
+ if((v&1) == 0){
+ if(cas(&l->key, v, v|1)){
+ // Lock wasn't held; we grabbed it.
+ return;
+ }
+ goto again;
+ }
- if(l->key != 0) *(int32*)0x1001 = 0x1001;
- l->key = 1;
- return;
-
+ // Lock was held; try to add ourselves to the waiter count.
+ if(!cas(&l->key, v, v+2))
+ goto again;
+
+ // We're accounted for, now sleep in the kernel.
+ //
+ // We avoid the obvious lock/unlock race because
+ // the kernel won't put us to sleep if l->key has
+ // changed underfoot and is no longer v+2.
+ //
+ // We only really care that (v&1) == 1 (the lock is held),
+ // and in fact there is a futex variant that could
+ // accomodate that check, but let's not get carried away.)
+ futexsleep(&l->key, v+2);
+
+ // We're awake: remove ourselves from the count.
for(;;){
- // Try for lock. If we incremented it from 0 to 1, we win.
- if((v=xadd(&l->key, 1)) == 1)
- return;
-
- // We lose. It was already >=1 and is now >=2.
- // Use futex to atomically check that the value is still
- // what we think it is and go to sleep.
- efutex(&l->key, FUTEX_WAIT, v, &longtime);
+ v = l->key;
+ if(v < 2)
+ throw("bad lock key");
+ if(cas(&l->key, v, v-2))
+ break;
}
+
+ // Try for the lock again.
+ goto again;
}
void
@@ -280,68 +313,54 @@
{
uint32 v;
- if(l->key != 1) *(int32*)0x1002 = 0x1002;
- l->key = 0;
- return;
+ // Atomically get value and clear lock bit.
+again:
+ v = l->key;
+ if((v&1) == 0)
+ throw("unlock of unlocked lock");
+ if(!cas(&l->key, v, v&~1))
+ goto again;
- // Unlock the lock. If we decremented from 1 to 0, wasn't contended.
- if((v=xadd(&l->key, -1)) == 0)
- return;
-
- // The lock was contended. Mark it as unlocked and wake a waiter.
- l->key = 0;
- efutex(&l->key, FUTEX_WAKE, 1, nil);
+ // If there were waiters, wake one.
+ if(v & ~1)
+ futexwakeup(&l->key);
}
-// Sleep and wakeup (see description in runtime.h)
+
+// One-time notifications.
+//
+// Since the lock/unlock implementation already
+// takes care of sleeping in the kernel, we just reuse it.
+// (But it's a weird use, so it gets its own interface.)
+//
+// We use a lock to represent the event:
+// unlocked == event has happened.
+// Thus the lock starts out locked, and to wait for the
+// event you try to lock the lock. To signal the event,
+// you unlock the lock.
void
-rsleep(Rendez *r)
+noteclear(Note *n)
{
- // Record that we're about to go to sleep and drop the lock.
- r->sleeping = 1;
- unlock(r->l);
-
- // Go to sleep if r->sleeping is still 1.
- efutex(&r->sleeping, FUTEX_WAIT, 1, &longtime);
-
- // Reacquire the lock.
- lock(r->l);
+ n->lock.key = 0; // memset(n, 0, sizeof *n)
+ lock(&n->lock);
}
void
-rwakeup(Rendez *r)
+notewakeup(Note *n)
{
- if(!r->sleeping)
- return;
-
- // Clear the sleeping flag in case sleeper
- // is between unlock and futex.
- r->sleeping = 0;
-
- // Wake up if actually made it to sleep.
- efutex(&r->sleeping, FUTEX_WAKE, 1, nil);
+ unlock(&n->lock);
}
-// Like rwakeup(r), unlock(r->l), but drops the lock before
-// waking the other proc. This reduces bouncing back and forth
-// in the scheduler: the first thing the other proc wants to do
-// is acquire r->l, so it helps to unlock it before we wake him.
void
-rwakeupandunlock(Rendez *r)
+notesleep(Note *n)
{
- int32 wassleeping;
-
- if(!r->sleeping){
- unlock(r->l);
- return;
- }
-
- r->sleeping = 0;
- unlock(r->l);
- efutex(&r->sleeping, FUTEX_WAKE, 1, nil);
+ lock(&n->lock);
+ unlock(&n->lock); // Let other sleepers find out too.
}
+
+// Clone, the Linux rfork.
enum
{
CLONE_VM = 0x100,
@@ -365,7 +384,7 @@
};
void
-newosproc(M *mm, G *gg, void *stk, void (*fn)(void*), void *arg)
+newosproc(M *m, G *g, void *stk, void (*fn)(void))
{
int64 ret;
int32 flags;
@@ -382,20 +401,18 @@
if(0){
prints("newosproc stk=");
sys·printpointer(stk);
- prints(" mm=");
- sys·printpointer(mm);
- prints(" gg=");
- sys·printpointer(gg);
+ prints(" m=");
+ sys·printpointer(m);
+ prints(" g=");
+ sys·printpointer(g);
prints(" fn=");
sys·printpointer(fn);
- prints(" arg=");
- sys·printpointer(arg);
prints(" clone=");
sys·printpointer(clone);
prints("\n");
}
- ret = clone(flags, stk, mm, gg, fn, arg);
+ ret = clone(flags, stk, m, g, fn);
if(ret < 0)
*(int32*)123 = 123;
}
diff -r 942605b8b20f -r 5b619aac0233 src/runtime/runtime.c
--- a/src/runtime/runtime.c Tue Aug 05 11:14:35 2008 -0700
+++ b/src/runtime/runtime.c Tue Aug 05 14:18:47 2008 -0700
@@ -71,6 +71,7 @@
return n;
}
+// Convenient wrapper around mmap.
static void*
brk(uint32 n)
{
@@ -81,12 +82,15 @@
return v;
}
-
+// Allocate n bytes of memory. Note that this gets used
+// to allocate new stack segments, so at each call to a function
+// you have to ask yourself "would it be okay to call mal recursively
+// right here?" The answer is yes unless we're in the middle of
+// editing the malloc state in m->mem.
void*
mal(uint32 n)
{
byte* v;
- Mem *mem;
// round to keep everything 64-bit aligned
n = rnd(n, 8);
@@ -94,17 +98,19 @@
// be careful. calling any function might invoke
// mal to allocate more stack.
if(n > NHUNK) {
- // this call is okay - calling mal recursively
- // won't change anything we depend on.
v = brk(n);
} else {
// allocate a new hunk if this one is too small
if(n > m->mem.nhunk) {
- // better not to call brk here - it might grow the stack,
- // causing a call to mal and the allocation of a
- // new hunk behind our backs. then we'd toss away
- // almost all of that new hunk and replace it.
- // that'd just be a memory leak - the code would still run.
+ // here we're in the middle of editing m->mem
+ // (we're about to overwrite m->mem.hunk),
+ // so we can't call brk - it might call mal to grow the
+ // stack, and the recursive call would allocate a new
+ // hunk, and then once brk returned we'd immediately
+ // overwrite that hunk with our own.
+ // (the net result would be a memory leak, not a crash.)
+ // so we have to call sys·mmap directly - it is written
+ // in assembly and tagged not to grow the stack.
m->mem.hunk =
sys·mmap(nil, NHUNK, PROT_READ|PROT_WRITE,
MAP_ANON|MAP_PRIVATE, 0, 0);
@@ -136,7 +142,7 @@
byte *sname, *iname;
Map *m;
- h = ((uint32)si + (uint32)ss) % nelem(hash);
+ h = ((uint32)(uint64)si + (uint32)(uint64)ss) % nelem(hash);
for(m=hash[h]; m!=nil; m=m->link) {
if(m->si == si && m->ss == ss) {
if(m->bad) {
@@ -301,9 +307,9 @@
NANSIGN = 1<<31,
};
-static uint64 uvnan = 0x7FF0000000000001;
-static uint64 uvinf = 0x7FF0000000000000;
-static uint64 uvneginf = 0xFFF0000000000000;
+static uint64 uvnan = 0x7FF0000000000001ULL;
+static uint64 uvinf = 0x7FF0000000000000ULL;
+static uint64 uvneginf = 0xFFF0000000000000ULL;
static int32
isInf(float64 d, int32 sign)
@@ -338,7 +344,7 @@
uint64 x;
x = *(uint64*)&d;
- return ((uint32)x>>32)==0x7FF00000 && !isInf(d, 0);
+ return (uint32)(x>>32)==0x7FF00000 && !isInf(d, 0);
}
static float64
@@ -424,7 +430,7 @@
return d - dd;
}
-// func frexp(float64) (float64, int32); // break fp into exp,fract
+// func frexp(float64) (float64, int32); // break fp into exp,frac
void
sys·frexp(float64 din, float64 dou, int32 iou)
{
@@ -432,7 +438,7 @@
FLUSH(&dou);
}
-//func ldexp(int32, float64) float64; // make fp from exp,fract
+//func ldexp(int32, float64) float64; // make fp from exp,frac
void
sys·ldexp(float64 din, int32 ein, float64 dou)
{
@@ -441,7 +447,7 @@
}
//func modf(float64) (float64, float64); // break fp into double+double
-float64
+void
sys·modf(float64 din, float64 integer, float64 fraction)
{
fraction = modf(din, &integer);
@@ -593,6 +599,7 @@
FLUSH(&s);
}
+void
check(void)
{
int8 a;
@@ -638,18 +645,6 @@
initsig();
}
-uint32
-xadd(uint32 *val, uint32 delta)
-{
- uint32 v;
-
- for(;;){
- v = *val;
- if(cas(val, v, v+delta))
- return v+delta;
- }
-}
-
/*
* map and chan helpers for
* dealing with unknown types
@@ -657,6 +652,7 @@
static uint64
memhash(uint32 s, void *a)
{
+ USED(s, a);
prints("memhash\n");
return 0x12345;
}
@@ -718,6 +714,7 @@
static uint64
stringhash(uint32 s, string *a)
{
+ USED(s, a);
prints("stringhash\n");
return 0x12345;
}
@@ -725,18 +722,21 @@
static uint32
stringequal(uint32 s, string *a, string *b)
{
+ USED(s);
return cmpstring(*a, *b) == 0;
}
static void
stringprint(uint32 s, string *a)
{
+ USED(s);
sys·printstring(*a);
}
static void
stringcopy(uint32 s, string *a, string *b)
{
+ USED(s);
if(b == nil) {
*a = nil;
return;
@@ -747,6 +747,7 @@
static uint64
pointerhash(uint32 s, void **a)
{
+ USED(s, a);
prints("pointerhash\n");
return 0x12345;
}
@@ -754,6 +755,7 @@
static uint32
pointerequal(uint32 s, void **a, void **b)
{
+ USED(s, a, b);
prints("pointerequal\n");
return 0;
}
@@ -761,12 +763,14 @@
static void
pointerprint(uint32 s, void **a)
{
+ USED(s, a);
prints("pointerprint\n");
}
static void
pointercopy(uint32 s, void **a, void **b)
{
+ USED(s);
if(b == nil) {
*a = nil;
return;
@@ -777,8 +781,8 @@
Alg
algarray[3] =
{
- { &memhash, &memequal, &memprint, &memcopy }, // 0
- { &stringhash, &stringequal, &stringprint, &stringcopy }, // 1
-// { &pointerhash, &pointerequal, &pointerprint, &pointercopy }, // 2
- { &memhash, &memequal, &memprint, &memcopy }, // 2 - treat pointers as ints
+ { memhash, memequal, memprint, memcopy }, // 0
+ { stringhash, stringequal, stringprint, stringcopy }, // 1
+// { pointerhash, pointerequal, pointerprint, pointercopy }, // 2
+ { memhash, memequal, memprint, memcopy }, // 2 - treat pointers as ints
};
diff -r 942605b8b20f -r 5b619aac0233 src/runtime/runtime.h
--- a/src/runtime/runtime.h Tue Aug 05 11:14:35 2008 -0700
+++ b/src/runtime/runtime.h Tue Aug 05 14:18:47 2008 -0700
@@ -43,7 +43,7 @@
typedef struct Stktop Stktop;
typedef struct Alg Alg;
typedef struct Lock Lock;
-typedef struct Rendez Rendez;
+typedef struct Note Note;
typedef struct Mem Mem;
/*
@@ -62,6 +62,7 @@
Grunnable,
Grunning,
Gwaiting,
+ Gmoribund,
Gdead,
};
enum
@@ -77,10 +78,9 @@
{
uint32 key;
};
-struct Rendez
+struct Note
{
- Lock* l;
- uint32 sleeping; // someone is sleeping (Linux)
+ Lock lock;
};
struct String
{
@@ -124,8 +124,8 @@
int16 status;
int32 goid;
int32 selgen; // valid sudog pointer
- G* runlink;
- Lock runlock;
+ G* schedlink;
+ Note stopped;
M* m; // for debuggers
};
struct Mem
@@ -147,9 +147,10 @@
byte* moresp;
int32 siz1;
int32 siz2;
- Rendez waitr;
- M* waitlink;
- int32 pid; // for debuggers
+ Note havenextg;
+ G* nextg;
+ M* schedlink;
+ int32 procid; // for debuggers
Mem mem;
};
struct Stktop
@@ -224,36 +225,34 @@
void close(int32);
int32 fstat(int32, void*);
bool cas(uint32*, uint32, uint32);
-uint32 xadd(uint32*, uint32);
void exit1(int32);
void ready(G*);
byte* getenv(int8*);
int32 atoi(byte*);
-void newosproc(M *mm, G *gg, void *stk, void (*fn)(void*), void *arg);
+void newosproc(M *m, G *g, void *stk, void (*fn)(void));
int32 getprocid(void);
/*
* mutual exclusion locks. in the uncontended case,
* as fast as spin locks (just a few user-level instructions),
* but on the contention path they sleep in the kernel.
+ * a zeroed Lock is unlocked (no need to initialize each lock).
*/
void lock(Lock*);
void unlock(Lock*);
-void lockinit(Lock*);
/*
- * sleep and wakeup.
- * a Rendez is somewhere to sleep. it is protected by the lock r->l.
- * the caller must acquire r->l, check the condition, and if the
- * condition is false, call rsleep. rsleep will atomically drop the lock
- * and go to sleep. a subsequent rwakeup (caller must hold r->l)
- * will wake up the guy who is rsleeping. the lock keeps rsleep and
- * rwakeup from missing each other.
- * n.b. only one proc can rsleep on a given rendez at a time.
+ * sleep and wakeup on one-time events.
+ * before any calls to notesleep or notewakeup,
+ * must call noteclear to initialize the Note.
+ * then, any number of threads can call notesleep
+ * and exactly one thread can call notewakeup (once).
+ * once notewakeup has been called, all the notesleeps
+ * will return. future notesleeps will return immediately.
*/
-void rsleep(Rendez*);
-void rwakeup(Rendez*);
-void rwakeupandunlock(Rendez*);
+void noteclear(Note*);
+void notesleep(Note*);
+void notewakeup(Note*);
/*
* low level go -called
diff -r 942605b8b20f -r 5b619aac0233 src/runtime/string.c
--- a/src/runtime/string.c Tue Aug 05 11:14:35 2008 -0700
+++ b/src/runtime/string.c Tue Aug 05 14:18:47 2008 -0700
@@ -45,8 +45,6 @@
static void
prbounds(int8* s, int32 a, int32 b, int32 c)
{
- int32 i;
-
prints(s);
prints(" ");
sys·printint(a);
@@ -115,7 +113,6 @@
void
sys·slicestring(string si, int32 lindex, int32 hindex, string so)
{
- string s, str;
int32 l;
if(si == nil)
@@ -154,8 +151,6 @@
void
sys·intstring(int64 v, string s)
{
- int32 l;
-
s = mal(sizeof(s->len)+8);
s->len = runetochar(s->str, v);
FLUSH(&s);
diff -r 942605b8b20f -r 5b619aac0233 src/runtime/sys_amd64_darwin.s
--- a/src/runtime/sys_amd64_darwin.s Tue Aug 05 11:14:35 2008 -0700
+++ b/src/runtime/sys_amd64_darwin.s Tue Aug 05 14:18:47 2008 -0700
@@ -7,21 +7,24 @@
//
// TODO(rsc): Either sys·exit or exit1 is wrong!
-TEXT sys·exit(SB),1,$-8
+// It looks like sys·exit is correct (exits the entire program)
+// and exit1 should be mimicking the OS X library routine
+// __bsdthread_terminate.
+TEXT sys·exit(SB),7,$-8
MOVL 8(SP), DI // arg 1 exit status
MOVL $(0x2000000+1), AX // syscall entry
SYSCALL
CALL notok(SB)
RET
-TEXT exit1(SB),1,$-8
+TEXT exit1(SB),7,$-8
MOVL 8(SP), DI // arg 1 exit status
MOVL $(0x2000000+1), AX // syscall entry
SYSCALL
CALL notok(SB)
RET
-TEXT sys·write(SB),1,$-8
+TEXT sys·write(SB),7,$-8
MOVL 8(SP), DI // arg 1 fid
MOVQ 16(SP), SI // arg 2 buf
MOVL 24(SP), DX // arg 3 count
@@ -31,7 +34,7 @@
CALL notok(SB)
RET
-TEXT open(SB),1,$-8
+TEXT open(SB),7,$-8
MOVQ 8(SP), DI
MOVL 16(SP), SI
MOVL 20(SP), DX
@@ -40,20 +43,20 @@
SYSCALL
RET
-TEXT close(SB),1,$-8
+TEXT close(SB),7,$-8
MOVL 8(SP), DI
MOVL $(0x2000000+6), AX // syscall entry
SYSCALL
RET
-TEXT fstat(SB),1,$-8
+TEXT fstat(SB),7,$-8
MOVL 8(SP), DI
MOVQ 16(SP), SI
MOVL $(0x2000000+339), AX // syscall entry; really fstat64
SYSCALL
RET
-TEXT read(SB),1,$-8
+TEXT read(SB),7,$-8
MOVL 8(SP), DI
MOVQ 16(SP), SI
MOVL 24(SP), DX
@@ -61,7 +64,7 @@
SYSCALL
RET
-TEXT write(SB),1,$-8
+TEXT write(SB),7,$-8
MOVL 8(SP), DI
MOVQ 16(SP), SI
MOVL 24(SP), DX
@@ -69,7 +72,7 @@
SYSCALL
RET
-TEXT sys·sigaction(SB),1,$-8
+TEXT sys·sigaction(SB),7,$-8
MOVL 8(SP), DI // arg 1 sig
MOVQ 16(SP), SI // arg 2 act
MOVQ 24(SP), DX // arg 3 oact
@@ -81,7 +84,7 @@
CALL notok(SB)
RET
-TEXT sigtramp(SB),1,$24
+TEXT sigtramp(SB),7,$24
MOVL DX,0(SP)
MOVQ CX,8(SP)
MOVQ R8,16(SP)
@@ -101,7 +104,7 @@
CALL notok(SB)
RET
-TEXT notok(SB),1,$-8
+TEXT notok(SB),7,$-8
MOVL $0xf1, BP
MOVQ BP, (BP)
RET
@@ -117,12 +120,12 @@
STOSQ
RET
-TEXT sys·getcallerpc+0(SB),1,$0
+TEXT sys·getcallerpc+0(SB),7,$0
MOVQ x+0(FP),AX // addr of first arg
MOVQ -8(AX),AX // get calling pc
RET
-TEXT sys·setcallerpc+0(SB),1,$0
+TEXT sys·setcallerpc+0(SB),7,$0
MOVQ x+0(FP),AX // addr of first arg
MOVQ x+8(FP), BX
MOVQ BX, -8(AX) // set calling pc
diff -r 942605b8b20f -r 5b619aac0233 src/runtime/sys_amd64_linux.s
--- a/src/runtime/sys_amd64_linux.s Tue Aug 05 11:14:35 2008 -0700
+++ b/src/runtime/sys_amd64_linux.s Tue Aug 05 14:18:47 2008 -0700
@@ -6,19 +6,19 @@
// System calls and other sys.stuff for AMD64, Linux
//
-TEXT sys·exit(SB),1,$0-8
+TEXT sys·exit(SB),7,$0-8
MOVL 8(SP), DI
- MOVL $231, AX // force all os threads to exit
+ MOVL $231, AX // exitgroup - force all os threads to exi
SYSCALL
RET
-TEXT exit1(SB),1,$0-8
+TEXT exit1(SB),7,$0-8
MOVL 8(SP), DI
- MOVL $60, AX // exit the current os thread
+ MOVL $60, AX // exit - exit the current os thread
SYSCALL
RET
-TEXT open(SB),1,$0-16
+TEXT open(SB),7,$0-16
MOVQ 8(SP), DI
MOVL 16(SP), SI
MOVL 20(SP), DX
@@ -26,20 +26,20 @@
SYSCALL
RET
-TEXT close(SB),1,$0-8
+TEXT close(SB),7,$0-8
MOVL 8(SP), DI
MOVL $3, AX // syscall entry
SYSCALL
RET
-TEXT fstat(SB),1,$0-16
+TEXT fstat(SB),7,$0-16
MOVL 8(SP), DI
MOVQ 16(SP), SI
MOVL $5, AX // syscall entry
SYSCALL
RET
-TEXT read(SB),1,$0-24
+TEXT read(SB),7,$0-24
MOVL 8(SP), DI
MOVQ 16(SP), SI
MOVL 24(SP), DX
@@ -47,7 +47,7 @@
SYSCALL
RET
-TEXT write(SB),1,$0-24
+TEXT write(SB),7,$0-24
MOVL 8(SP), DI
MOVQ 16(SP), SI
MOVL 24(SP), DX
@@ -55,7 +55,7 @@
SYSCALL
RET
-TEXT sys·write(SB),1,$0-24
+TEXT sys·write(SB),7,$0-24
MOVL 8(SP), DI
MOVQ 16(SP), SI
MOVL 24(SP), DX
@@ -63,7 +63,7 @@
SYSCALL
RET
-TEXT sys·rt_sigaction(SB),1,$0-32
+TEXT sys·rt_sigaction(SB),7,$0-32
MOVL 8(SP), DI
MOVQ 16(SP), SI
MOVQ 24(SP), DX
@@ -72,7 +72,7 @@
SYSCALL
RET
-TEXT sigtramp(SB),1,$24-16
+TEXT sigtramp(SB),7,$24-16
MOVQ DI,0(SP)
MOVQ SI,8(SP)
MOVQ DX,16(SP)
@@ -118,20 +118,20 @@
STOSQ
RET
-TEXT sys·getcallerpc+0(SB),1,$0
+TEXT sys·getcallerpc+0(SB),7,$0
MOVQ x+0(FP),AX // addr of first arg
MOVQ -8(AX),AX // get calling pc
RET
-TEXT sys·setcallerpc+0(SB),1,$0
+TEXT sys·setcallerpc+0(SB),7,$0
MOVQ x+0(FP),AX // addr of first arg
MOVQ x+8(FP), BX
MOVQ BX, -8(AX) // set calling pc
RET
-// int64 futex(int32 *uaddr, int32 op, int32 val,
+// int64 futex(int32 *uaddr, int32 op, int32 val,
// struct timespec *timeout, int32 *uaddr2, int32 val2);
-TEXT futex(SB),1,$0
+TEXT futex(SB),7,$0
MOVQ 8(SP), DI
MOVL 16(SP), SI
MOVL 20(SP), DX
@@ -142,17 +142,16 @@
SYSCALL
RET
-// int64 clone(int32 flags, void *stack, M *m, G *g, void (*fn)(void*), void *arg);
+// int64 clone(int32 flags, void *stack, M *m, G *g, void (*fn)(void));
TEXT clone(SB),7,$0
- MOVL 8(SP), DI
- MOVQ 16(SP), SI
+ MOVL flags+8(SP), DI
+ MOVQ stack+16(SP), SI
- // Copy m, g, fn, arg off parent stack for use by child.
+ // Copy m, g, fn off parent stack for use by child.
// Careful: Linux system call clobbers CX and R11.
- MOVQ 24(SP), R8
- MOVQ 32(SP), R9
- MOVQ 40(SP), R12
- MOVQ 48(SP), R13
+ MOVQ m+24(SP), R8
+ MOVQ g+32(SP), R9
+ MOVQ fn+40(SP), R12
MOVL $56, AX
SYSCALL
@@ -162,21 +161,20 @@
JEQ 2(PC)
RET
- // In child, call fn(arg) on new stack
+ // In child, call fn on new stack
MOVQ SI, SP
MOVQ R8, R14 // m
MOVQ R9, R15 // g
- PUSHQ R13
CALL R12
- // It shouldn't return. If it does, exit
+ // It shouldn't return. If it does, exi
MOVL $111, DI
MOVL $60, AX
SYSCALL
JMP -3(PC) // keep exiting
// int64 select(int32, void*, void*, void*, void*)
-TEXT select(SB),1,$0
+TEXT select(SB),7,$0
MOVL 8(SP), DI
MOVQ 16(SP), SI
MOVQ 24(SP), DX
@@ -187,14 +185,14 @@
RET
// Linux allocates each thread its own pid, like Plan 9.
-// But the getpid() system call returns the pid of the
+// But the getpid() system call returns the pid of the
// original thread (the one that exec started with),
// no matter which thread asks. This system call,
// which Linux calls gettid, returns the actual pid of
// the calling thread, not the fake one.
//
// int32 getprocid(void)
-TEXT getprocid(SB),1,$0
+TEXT getprocid(SB),7,$0
MOVL $186, AX
SYSCALL
RET
changeset: 487:8aeb6d032bf6
user: Russ Cox <[email protected]>
date: Tue Aug 05 14:21:42 2008 -0700
summary: kill trailing white space.
diff -r 5b619aac0233 -r 8aeb6d032bf6 src/runtime/chan.c
--- a/src/runtime/chan.c Tue Aug 05 14:18:47 2008 -0700
+++ b/src/runtime/chan.c Tue Aug 05 14:21:42 2008 -0700
@@ -262,7 +262,7 @@
*pres = false;
return;
}
-
+
sg = allocsg(c);
g->param = nil;
g->status = Gwaiting;
diff -r 5b619aac0233 -r 8aeb6d032bf6 src/runtime/proc.c
--- a/src/runtime/proc.c Tue Aug 05 14:18:47 2008 -0700
+++ b/src/runtime/proc.c Tue Aug 05 14:21:42 2008 -0700
@@ -41,17 +41,17 @@
Lock;
G *gfree; // available gs (status == Gdead)
-
+
G *ghead; // gs waiting to run
G *gtail;
int32 gwait; // number of gs waiting to run
int32 gcount; // number of gs that are alive
-
+
M *mhead; // ms waiting for work
int32 mwait; // number of ms waiting for work
int32 mcount; // number of ms that are alive
int32 mmax; // max number of ms allowed
-
+
int32 predawn; // running initialization, don't run new gs.
};
@@ -76,7 +76,7 @@
{
int32 n;
byte *p;
-
+
sched.mmax = 1;
p = getenv("gomaxprocs");
if(p != nil && (n = atoi(p)) != 0)
@@ -90,7 +90,7 @@
m0init(void)
{
int32 i;
-
+
// Let's go.
sched.predawn = 0;
@@ -163,7 +163,7 @@
sched.gcount++;
goidgen++;
newg->goid = goidgen;
-
+
readylocked(newg);
unlock(&sched);
@@ -205,7 +205,7 @@
gget(void)
{
G *g;
-
+
g = sched.ghead;
if(g){
sched.ghead = g->schedlink;
@@ -230,7 +230,7 @@
mget(void)
{
M *m;
-
+
m = sched.mhead;
if(m){
sched.mhead = m->schedlink;
@@ -252,7 +252,7 @@
gfget(void)
{
G *g;
-
+
g = sched.gfree;
if(g)
sched.gfree = g->schedlink;
@@ -267,7 +267,7 @@
// have queued itself on a channel but not yet gotten
// a chance to call sys·gosched and actually go to sleep).
notesleep(&g->stopped);
-
+
lock(&sched);
readylocked(g);
unlock(&sched);
@@ -300,7 +300,7 @@
m->nextg = g;
notewakeup(&m->havenextg);
}
-
+
// Else put g on queue, kicking off new m if needed.
else{
gput(g);
@@ -327,7 +327,7 @@
m->nextg = nil;
noteclear(&m->havenextg);
unlock(&sched);
-
+
notesleep(&m->havenextg);
if((gp = m->nextg) == nil)
throw("bad m->nextg in nextgoroutine");
@@ -373,7 +373,7 @@
// Find (or wait for) g to run. Unlocks sched.
gp = nextgandunlock();
-
+
noteclear(&gp->stopped);
gp->status = Grunning;
m->curg = gp;
@@ -406,13 +406,13 @@
M *m;
G *g;
byte *stk, *stktop;
-
+
sched.mcount++;
if(debug){
sys·printint(sched.mcount);
prints(" threads\n");
}
-
+
// Allocate m, g, stack in one chunk.
// 1024 and 104 are the magic constants
// use in rt0_amd64.s when setting up g0.
@@ -420,7 +420,7 @@
g = (G*)(m+1);
stk = (byte*)g + 104;
stktop = stk + 1024;
-
+
m->g0 = g;
g->stackguard = stk;
g->stackbase = stktop;
@@ -521,7 +521,7 @@
m->curg->stackguard = stk + 160;
sp = (byte*)top;
-
+
if(siz2 > 0) {
siz2 = (siz2+7) & ~7;
sp -= siz2;
diff -r 5b619aac0233 -r 8aeb6d032bf6 src/runtime/rt0_amd64.s
--- a/src/runtime/rt0_amd64.s Tue Aug 05 14:18:47 2008 -0700
+++ b/src/runtime/rt0_amd64.s Tue Aug 05 14:21:42 2008 -0700
@@ -35,7 +35,7 @@
CALL args(SB)
CALL schedinit(SB)
CALL main·init_function(SB) // initialization
-
+
// create a new goroutine to start program
PUSHQ $main·main(SB) // entry
diff -r 5b619aac0233 -r 8aeb6d032bf6 src/runtime/rt1_amd64_darwin.c
--- a/src/runtime/rt1_amd64_darwin.c Tue Aug 05 14:18:47 2008 -0700
+++ b/src/runtime/rt1_amd64_darwin.c Tue Aug 05 14:21:42 2008 -0700
@@ -146,11 +146,11 @@
prints("\nFaulting address: 0x"); sys·printpointer(info->si_addr);
prints("\npc: 0x"); sys·printpointer((void *)ss->__rip);
prints("\n\n");
-
+
traceback((void *)ss->__rip, (void *)ss->__rsp, (void*)ss->__r15);
tracebackothers((void*)ss->__r15);
print_thread_state(ss);
-
+
sys·exit(2);
}
diff -r 5b619aac0233 -r 8aeb6d032bf6 src/runtime/rt1_amd64_linux.c
--- a/src/runtime/rt1_amd64_linux.c Tue Aug 05 14:18:47 2008 -0700
+++ b/src/runtime/rt1_amd64_linux.c Tue Aug 05 14:21:42 2008 -0700
@@ -187,10 +187,10 @@
// Futexsleep is allowed to wake up spuriously.
enum
-{
+{
FUTEX_WAIT = 0,
FUTEX_WAKE = 1,
-
+
EINTR = 4,
EAGAIN = 11,
};
@@ -213,7 +213,7 @@
futexsleep(uint32 *addr, uint32 val)
{
int64 ret;
-
+
ret = futex(addr, FUTEX_WAIT, val, &longtime, nil, 0);
if(ret >= 0 || ret == -EAGAIN || ret == -EINTR)
return;
@@ -233,14 +233,14 @@
futexwakeup(uint32 *addr)
{
int64 ret;
-
+
ret = futex(addr, FUTEX_WAKE, 1, nil, nil, 0);
if(ret >= 0)
return;
// I don't know that futex wakeup can return
- // EAGAIN or EINTR, but if it does, it would be
+ // EAGAIN or EINTR, but if it does, it would be
// safe to loop and call futex again.
prints("futexwakeup addr=");
@@ -279,11 +279,11 @@
}
goto again;
}
-
+
// Lock was held; try to add ourselves to the waiter count.
if(!cas(&l->key, v, v+2))
goto again;
-
+
// We're accounted for, now sleep in the kernel.
//
// We avoid the obvious lock/unlock race because
@@ -294,7 +294,7 @@
// and in fact there is a futex variant that could
// accomodate that check, but let's not get carried away.)
futexsleep(&l->key, v+2);
-
+
// We're awake: remove ourselves from the count.
for(;;){
v = l->key;
@@ -303,7 +303,7 @@
if(cas(&l->key, v, v-2))
break;
}
-
+
// Try for the lock again.
goto again;
}
@@ -388,7 +388,7 @@
{
int64 ret;
int32 flags;
-
+
flags = CLONE_PARENT /* getppid doesn't change in child */
| CLONE_VM /* share memory */
| CLONE_FS /* share cwd, etc */
diff -r 5b619aac0233 -r 8aeb6d032bf6 src/runtime/rune.c
--- a/src/runtime/rune.c Tue Aug 05 14:18:47 2008 -0700
+++ b/src/runtime/rune.c Tue Aug 05 14:21:42 2008 -0700
@@ -26,7 +26,7 @@
Bit2 = 5,
Bit3 = 4,
Bit4 = 3,
- Bit5 = 2,
+ Bit5 = 2,
T1 = ((1<<(Bit1+1))-1) ^ 0xFF, /* 0000 0000 */
Tx = ((1<<(Bitx+1))-1) ^ 0xFF, /* 1000 0000 */
@@ -48,15 +48,15 @@
Runeself = 0x80,
Bad = Runeerror,
-
+
Runemax = 0x10FFFF, /* maximum rune value */
};
/*
* Modified by Wei-Hwa Huang, Google Inc., on 2004-09-24
- * This is a slower but "safe" version of the old chartorune
+ * This is a slower but "safe" version of the old chartorune
* that works on strings that are not necessarily null-terminated.
- *
+ *
* If you know for sure that your string is null-terminated,
* chartorune will be a bit faster.
*
diff -r 5b619aac0233 -r 8aeb6d032bf6 src/runtime/runtime.c
--- a/src/runtime/runtime.c Tue Aug 05 14:18:47 2008 -0700
+++ b/src/runtime/runtime.c Tue Aug 05 14:21:42 2008 -0700
@@ -512,7 +512,7 @@
{
int32 i, j, len;
byte *v, *bs;
-
+
bs = (byte*)s;
len = findnull(s);
for(i=0; i<envc; i++){
@@ -532,7 +532,7 @@
atoi(byte *p)
{
int32 n;
-
+
n = 0;
while('0' <= *p && *p <= '9')
n = n*10 + *p++ - '0';
@@ -635,7 +635,7 @@
throw("cas1");
if(z != 2)
throw("cas2");
-
+
z = 4;
if(cas(&z, 5, 6))
throw("cas3");
diff -r 5b619aac0233 -r 8aeb6d032bf6 src/runtime/runtime.h
--- a/src/runtime/runtime.h Tue Aug 05 14:18:47 2008 -0700
+++ b/src/runtime/runtime.h Tue Aug 05 14:21:42 2008 -0700
@@ -243,7 +243,7 @@
/*
* sleep and wakeup on one-time events.
- * before any calls to notesleep or notewakeup,
+ * before any calls to notesleep or notewakeup,
* must call noteclear to initialize the Note.
* then, any number of threads can call notesleep
* and exactly one thread can call notewakeup (once).
diff -r 5b619aac0233 -r 8aeb6d032bf6 src/runtime/sys_amd64_linux.s
--- a/src/runtime/sys_amd64_linux.s Tue Aug 05 14:18:47 2008 -0700
+++ b/src/runtime/sys_amd64_linux.s Tue Aug 05 14:21:42 2008 -0700
@@ -146,7 +146,7 @@
TEXT clone(SB),7,$0
MOVL flags+8(SP), DI
MOVQ stack+16(SP), SI
-
+
// Copy m, g, fn off parent stack for use by child.
// Careful: Linux system call clobbers CX and R11.
MOVQ m+24(SP), R8
@@ -160,13 +160,13 @@
CMPQ AX, $0
JEQ 2(PC)
RET
-
+
// In child, call fn on new stack
MOVQ SI, SP
MOVQ R8, R14 // m
MOVQ R9, R15 // g
CALL R12
-
+
// It shouldn't return. If it does, exi
MOVL $111, DI
MOVL $60, AX
changeset: 594:7627e93b0342
user: Russ Cox <[email protected]>
date: Tue Sep 09 11:50:14 2008 -0700
summary: go threads for OS X
diff -r f1f205d50880 -r 7627e93b0342 src/runtime/amd64_darwin.h
--- a/src/runtime/amd64_darwin.h Tue Sep 09 10:48:14 2008 -0700
+++ b/src/runtime/amd64_darwin.h Tue Sep 09 11:50:14 2008 -0700
@@ -22,6 +22,11 @@
int64 tv_nsec;
};
+struct timeval {
+ time_t tv_sec;
+ int64 tv_usec;
+};
+
struct stat { // really a stat64
dev_t st_dev;
mode_t st_mode;
@@ -43,3 +48,19 @@
};
#define O_CREAT 0x0200
+
+void bsdthread_create(void*, M*, G*, void(*)(void));
+void bsdthread_register(void);
+int64 select(int32, void*, void*, void*, struct timeval*);
+
+
+// Mach calls
+
+typedef int32 kern_return_t;
+typedef uint32 mach_port_t;
+
+mach_port_t semcreate(void);
+void semacquire(mach_port_t);
+void semrelease(mach_port_t);
+void semreset(mach_port_t);
+void semdestroy(mach_port_t);
diff -r f1f205d50880 -r 7627e93b0342 src/runtime/amd64_linux.h
--- a/src/runtime/amd64_linux.h Tue Sep 09 10:48:14 2008 -0700
+++ b/src/runtime/amd64_linux.h Tue Sep 09 11:50:14 2008 -0700
@@ -49,5 +49,5 @@
// Linux-specific system calls
int64 futex(uint32*, int32, uint32, struct timespec*, uint32*, uint32);
int64 clone(int32, void*, M*, G*, void(*)(void));
-int64 select(int32, void*, void*, void*, void*);
+int64 select(int32, void*, void*, void*, struct timeval*);
diff -r f1f205d50880 -r 7627e93b0342 src/runtime/chan.c
--- a/src/runtime/chan.c Tue Sep 09 10:48:14 2008 -0700
+++ b/src/runtime/chan.c Tue Sep 09 11:50:14 2008 -0700
@@ -4,9 +4,8 @@
#include "runtime.h"
-// TODO locking of select
-
static int32 debug = 0;
+static Lock chanlock;
typedef struct Hchan Hchan;
typedef struct Link Link;
@@ -32,7 +31,6 @@
struct Hchan
{
- Lock;
uint32 elemsize;
uint32 dataqsiz; // size of the circular q
uint32 qcount; // total data in the q
@@ -162,7 +160,7 @@
prints("\n");
}
- lock(c);
+ lock(&chanlock);
if(c->dataqsiz > 0)
goto asynch;
@@ -173,7 +171,7 @@
gp = sg->g;
gp->param = sg;
- unlock(c);
+ unlock(&chanlock);
ready(gp);
if(pres != nil)
@@ -182,7 +180,7 @@
}
if(pres != nil) {
- unlock(c);
+ unlock(&chanlock);
*pres = false;
return;
}
@@ -193,13 +191,13 @@
g->param = nil;
g->status = Gwaiting;
enqueue(&c->sendq, sg);
- unlock(c);
+ unlock(&chanlock);
sys·gosched();
- lock(c);
+ lock(&chanlock);
sg = g->param;
freesg(c, sg);
- unlock(c);
+ unlock(&chanlock);
return;
asynch:
@@ -208,9 +206,9 @@
sg = allocsg(c);
g->status = Gwaiting;
enqueue(&c->sendq, sg);
- unlock(c);
+ unlock(&chanlock);
sys·gosched();
- lock(c);
+ lock(&chanlock);
}
if(ep != nil)
c->elemalg->copy(c->elemsize, c->senddataq->elem, ep);
@@ -221,10 +219,10 @@
if(sg != nil) {
gp = sg->g;
freesg(c, sg);
- unlock(c);
+ unlock(&chanlock);
ready(gp);
}else
- unlock(c);
+ unlock(&chanlock);
}
static void
@@ -239,7 +237,7 @@
prints("\n");
}
- lock(c);
+ lock(&chanlock);
if(c->dataqsiz > 0)
goto asynch;
@@ -249,7 +247,7 @@
gp = sg->g;
gp->param = sg;
- unlock(c);
+ unlock(&chanlock);
ready(gp);
if(pres != nil)
@@ -258,7 +256,7 @@
}
if(pres != nil) {
- unlock(c);
+ unlock(&chanlock);
*pres = false;
return;
}
@@ -267,14 +265,14 @@
g->param = nil;
g->status = Gwaiting;
enqueue(&c->recvq, sg);
- unlock(c);
+ unlock(&chanlock);
sys·gosched();
- lock(c);
+ lock(&chanlock);
sg = g->param;
c->elemalg->copy(c->elemsize, ep, sg->elem);
freesg(c, sg);
- unlock(c);
+ unlock(&chanlock);
return;
asynch:
@@ -282,9 +280,9 @@
sg = allocsg(c);
g->status = Gwaiting;
enqueue(&c->recvq, sg);
- unlock(c);
+ unlock(&chanlock);
sys·gosched();
- lock(c);
+ lock(&chanlock);
}
c->elemalg->copy(c->elemsize, ep, c->recvdataq->elem);
c->recvdataq = c->recvdataq->link;
@@ -293,10 +291,10 @@
if(sg != nil) {
gp = sg->g;
freesg(c, sg);
- unlock(c);
+ unlock(&chanlock);
ready(gp);
}else
- unlock(c);
+ unlock(&chanlock);
}
// chansend1(hchan *chan any, elem any);
@@ -371,12 +369,14 @@
if(size > 1)
n = size-1;
+ lock(&chanlock);
sel = nil;
if(size >= 1 && size < nelem(selfree)) {
sel = selfree[size];
if(sel != nil)
selfree[size] = sel->link;
}
+ unlock(&chanlock);
if(sel == nil)
sel = mal(sizeof(*sel) + n*sizeof(sel->scase[0]));
@@ -517,6 +517,8 @@
p %= sel->ncase;
o %= sel->ncase;
+ lock(&chanlock);
+
// pass 1 - look for something already waiting
for(i=0; i<sel->ncase; i++) {
cas = &sel->scase[o];
@@ -598,8 +600,10 @@
// (rsc) not correct to set Gwaiting after queueing;
// might already have been readied.
g->status = Gwaiting;
+ unlock(&chanlock);
sys·gosched();
+ lock(&chanlock);
sg = g->param;
o = sg->offset;
cas = &sel->scase[o];
@@ -629,6 +633,7 @@
asynr:
asyns:
+ unlock(&chanlock);
throw("asyn");
return; // compiler doesn't know throw doesn't return
@@ -671,6 +676,7 @@
sel->link = selfree[sel->ncase];
selfree[sel->ncase] = sel;
}
+ unlock(&chanlock);
sys·setcallerpc(&sel, cas->pc);
as = (byte*)&sel + cas->so;
diff -r f1f205d50880 -r 7627e93b0342 src/runtime/proc.c
--- a/src/runtime/proc.c Tue Sep 09 10:48:14 2008 -0700
+++ b/src/runtime/proc.c Tue Sep 09 11:50:14 2008 -0700
@@ -341,8 +341,6 @@
{
G* gp;
- // Initialization.
- m->procid = getprocid();
lock(&sched);
if(gosave(&m->sched)){
@@ -472,7 +470,7 @@
mcpy(top->oldsp+16, sp, siz2);
}
- // call no more functions after this point - limit register disagrees with R15
+ // call no more functions after this point - stackguard disagrees with SP
m->curg->stackbase = top->oldbase;
m->curg->stackguard = top->oldguard;
m->morestack.SP = top->oldsp+8;
diff -r f1f205d50880 -r 7627e93b0342 src/runtime/rt0_amd64.s
--- a/src/runtime/rt0_amd64.s Tue Sep 09 10:48:14 2008 -0700
+++ b/src/runtime/rt0_amd64.s Tue Sep 09 11:50:14 2008 -0700
@@ -33,6 +33,7 @@
MOVQ 24(SP), AX // copy argv
MOVQ AX, 8(SP)
CALL args(SB)
+ CALL osinit(SB)
CALL schedinit(SB)
CALL main·init_function(SB) // initialization
diff -r f1f205d50880 -r 7627e93b0342 src/runtime/rt1_amd64_darwin.c
--- a/src/runtime/rt1_amd64_darwin.c Tue Sep 09 10:48:14 2008 -0700
+++ b/src/runtime/rt1_amd64_darwin.c Tue Sep 09 11:50:14 2008 -0700
@@ -3,6 +3,7 @@
// license that can be found in the LICENSE file.
#include "runtime.h"
+#include "amd64_darwin.h"
#include "signals.h"
typedef uint64 __uint64_t;
@@ -185,53 +186,494 @@
void
sys·sleep(int64 ms)
{
- unimplemented("sleep");
+ struct timeval tv;
+
+ tv.tv_sec = ms/1000;
+ tv.tv_usec = ms%1000 * 1000;
+ select(0, nil, nil, nil, &tv);
}
+// Thread-safe allocation of a semaphore.
+// Psema points at a kernel semaphore key.
+// It starts out zero, meaning no semaphore.
+// Fill it in, being careful of others calling initsema
+// simultaneously.
+static void
+initsema(uint32 *psema)
+{
+ uint32 sema;
+
+ if(*psema != 0) // already have one
+ return;
+
+ sema = semcreate();
+ if(!cas(psema, 0, sema)){
+ // Someone else filled it in. Use theirs.
+ semdestroy(sema);
+ return;
+ }
+}
+
+
+// Atomic add and return new value.
+static uint32
+xadd(uint32 volatile *val, int32 delta)
+{
+ uint32 oval, nval;
+
+ for(;;){
+ oval = *val;
+ nval = oval + delta;
+ if(cas(val, oval, nval))
+ return nval;
+ }
+}
+
+
+// Blocking locks.
+
+// Implement Locks, using semaphores.
+// l->key is the number of threads who want the lock.
+// In a race, one thread increments l->key from 0 to 1
+// and the others increment it from >0 to >1. The thread
+// who does the 0->1 increment gets the lock, and the
+// others wait on the semaphore. When the 0->1 thread
+// releases the lock by decrementing l->key, l->key will
+// be >0, so it will increment the semaphore to wake up
+// one of the others. This is the same algorithm used
+// in Plan 9's user-space locks.
+//
+// Note that semaphores are never destroyed (the kernel
+// will clean up when the process exits). We assume for now
+// that Locks are only used for long-lived structures like M and G.
+
void
lock(Lock *l)
{
- if(cas(&l->key, 0, 1))
- return;
- unimplemented("lock wait");
+ // Allocate semaphore if needed.
+ if(l->sema == 0)
+ initsema(&l->sema);
+
+ if(xadd(&l->key, 1) > 1) // someone else has it; wait
+ semacquire(l->sema);
}
void
unlock(Lock *l)
{
- if(cas(&l->key, 1, 0))
- return;
- unimplemented("unlock wakeup");
+ if(xadd(&l->key, -1) > 0) // someone else is waiting
+ semrelease(l->sema);
}
+
+// Event notifications.
void
noteclear(Note *n)
{
- n->lock.key = 0;
- lock(&n->lock);
+ n->wakeup = 0;
}
void
notesleep(Note *n)
{
- lock(&n->lock);
- unlock(&n->lock);
+ if(n->sema == 0)
+ initsema(&n->sema);
+ while(!n->wakeup)
+ semacquire(n->sema);
}
void
notewakeup(Note *n)
{
- unlock(&n->lock);
+ if(n->sema == 0)
+ initsema(&n->sema);
+ n->wakeup = 1;
+ semrelease(n->sema);
+}
+
+
+// BSD interface for threading.
+void
+osinit(void)
+{
+ // Register our thread-creation callback (see sys_amd64_darwin.s).
+ bsdthread_register();
}
void
-newosproc(M *mm, G *gg, void *stk, void (*fn)(void))
+newosproc(M *m, G *g, void *stk, void (*fn)(void))
{
- unimplemented("newosproc");
+ bsdthread_create(stk, m, g, fn);
}
-int32
-getprocid(void)
+
+// Mach IPC, to get at semaphores
+// Definitions are in /usr/include/mach on a Mac.
+
+static void
+macherror(kern_return_t r, int8 *fn)
{
+ prints("mach error ");
+ prints(fn);
+ prints(": ");
+ sys·printint(r);
+ prints("\n");
+ throw("mach error");
+}
+
+enum
+{
+ DebugMach = 0
+};
+
+typedef int32 mach_msg_option_t;
+typedef uint32 mach_msg_bits_t;
+typedef uint32 mach_msg_id_t;
+typedef uint32 mach_msg_size_t;
+typedef uint32 mach_msg_timeout_t;
+typedef uint32 mach_port_name_t;
+typedef uint64 mach_vm_address_t;
+
+typedef struct mach_msg_header_t mach_msg_header_t;
+typedef struct mach_msg_body_t mach_msg_body_t;
+typedef struct mach_msg_port_descriptor_t mach_msg_port_descriptor_t;
+typedef struct NDR_record_t NDR_record_t;
+
+enum
+{
+ MACH_MSG_TYPE_MOVE_RECEIVE = 16,
+ MACH_MSG_TYPE_MOVE_SEND = 17,
+ MACH_MSG_TYPE_MOVE_SEND_ONCE = 18,
+ MACH_MSG_TYPE_COPY_SEND = 19,
+ MACH_MSG_TYPE_MAKE_SEND = 20,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE = 21,
+ MACH_MSG_TYPE_COPY_RECEIVE = 22,
+
+ MACH_MSG_PORT_DESCRIPTOR = 0,
+ MACH_MSG_OOL_DESCRIPTOR = 1,
+ MACH_MSG_OOL_PORTS_DESCRIPTOR = 2,
+ MACH_MSG_OOL_VOLATILE_DESCRIPTOR = 3,
+
+ MACH_MSGH_BITS_COMPLEX = 0x80000000,
+
+ MACH_SEND_MSG = 1,
+ MACH_RCV_MSG = 2,
+ MACH_RCV_LARGE = 4,
+
+ MACH_SEND_TIMEOUT = 0x10,
+ MACH_SEND_INTERRUPT = 0x40,
+ MACH_SEND_CANCEL = 0x80,
+ MACH_SEND_ALWAYS = 0x10000,
+ MACH_SEND_TRAILER = 0x20000,
+ MACH_RCV_TIMEOUT = 0x100,
+ MACH_RCV_NOTIFY = 0x200,
+ MACH_RCV_INTERRUPT = 0x400,
+ MACH_RCV_OVERWRITE = 0x1000,
+};
+
+mach_port_t mach_task_self(void);
+mach_port_t mach_thread_self(void);
+
+#pragma pack on
+struct mach_msg_header_t
+{
+ mach_msg_bits_t bits;
+ mach_msg_size_t size;
+ mach_port_t remote_port;
+ mach_port_t local_port;
+ mach_msg_size_t reserved;
+ mach_msg_id_t id;
+};
+
+struct mach_msg_body_t
+{
+ uint32 descriptor_count;
+};
+
+struct mach_msg_port_descriptor_t
+{
+ mach_port_t name;
+ uint32 pad1;
+ uint16 pad2;
+ uint8 disposition;
+ uint8 type;
+};
+
+enum
+{
+ NDR_PROTOCOL_2_0 = 0,
+ NDR_INT_BIG_ENDIAN = 0,
+ NDR_INT_LITTLE_ENDIAN = 1,
+ NDR_FLOAT_IEEE = 0,
+ NDR_CHAR_ASCII = 0
+};
+
+struct NDR_record_t
+{
+ uint8 mig_vers;
+ uint8 if_vers;
+ uint8 reserved1;
+ uint8 mig_encoding;
+ uint8 int_rep;
+ uint8 char_rep;
+ uint8 float_rep;
+ uint8 reserved2;
+};
+#pragma pack off
+
+static NDR_record_t zerondr;
+
+#define MACH_MSGH_BITS(a, b) ((a) | ((b)<<8))
+
+// Mach system calls (in sys_amd64_darwin.s)
+kern_return_t mach_msg_trap(mach_msg_header_t*,
+ mach_msg_option_t, mach_msg_size_t, mach_msg_size_t,
+ mach_port_name_t, mach_msg_timeout_t, mach_port_name_t);
+mach_port_t mach_reply_port(void);
+mach_port_t mach_task_self(void);
+mach_port_t mach_thread_self(void);
+
+static kern_return_t
+mach_msg(mach_msg_header_t *h,
+ mach_msg_option_t op,
+ mach_msg_size_t send_size,
+ mach_msg_size_t rcv_size,
+ mach_port_name_t rcv_name,
+ mach_msg_timeout_t timeout,
+ mach_port_name_t notify)
+{
+ // TODO: Loop on interrupt.
+ return mach_msg_trap(h, op, send_size, rcv_size, rcv_name, timeout, notify);
+}
+
+
+// Mach RPC (MIG)
+// I'm not using the Mach names anymore. They're too long.
+
+enum
+{
+ MinMachMsg = 48,
+ Reply = 100,
+};
+
+#pragma pack on
+typedef struct CodeMsg CodeMsg;
+struct CodeMsg
+{
+ mach_msg_header_t h;
+ NDR_record_t NDR;
+ kern_return_t code;
+};
+#pragma pack off
+
+static kern_return_t
+machcall(mach_msg_header_t *h, int32 maxsize, int32 rxsize)
+{
+ uint32 *p;
+ int32 i, ret, id;
+ mach_port_t port;
+ CodeMsg *c;
+
+ if((port = m->machport) == 0){
+ port = mach_reply_port();
+ m->machport = port;
+ }
+
+ h->bits |= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE);
+ h->local_port = port;
+ h->reserved = 0;
+ id = h->id;
+
+ if(DebugMach){
+ p = (uint32*)h;
+ prints("send:\t");
+ for(i=0; i<h->size/sizeof(p[0]); i++){
+ prints(" ");
+ sys·printpointer((void*)p[i]);
+ if(i%8 == 7)
+ prints("\n\t");
+ }
+ if(i%8)
+ prints("\n");
+ }
+
+ ret = mach_msg(h, MACH_SEND_MSG|MACH_RCV_MSG,
+ h->size, maxsize, port, 0, 0);
+ if(ret != 0){
+ if(DebugMach){
+ prints("mach_msg error ");
+ sys·printint(ret);
+ prints("\n");
+ }
+ return ret;
+ }
+
+ if(DebugMach){
+ p = (uint32*)h;
+ prints("recv:\t");
+ for(i=0; i<h->size/sizeof(p[0]); i++){
+ prints(" ");
+ sys·printpointer((void*)p[i]);
+ if(i%8 == 7)
+ prints("\n\t");
+ }
+ if(i%8)
+ prints("\n");
+ }
+
+ if(h->id != id+Reply){
+ if(DebugMach){
+ prints("mach_msg reply id mismatch ");
+ sys·printint(h->id);
+ prints(" != ");
+ sys·printint(id+Reply);
+ prints("\n");
+ }
+ return -303; // MIG_REPLY_MISMATCH
+ }
+
+ // Look for a response giving the return value.
+ // Any call can send this back with an error,
+ // and some calls only have return values so they
+ // send it back on success too. I don't quite see how
+ // you know it's one of these and not the full response
+ // format, so just look if the message is right.
+ c = (CodeMsg*)h;
+ if(h->size == sizeof(CodeMsg)
+ && !(h->bits & MACH_MSGH_BITS_COMPLEX)){
+ if(DebugMach){
+ prints("mig result ");
+ sys·printint(c->code);
+ prints("\n");
+ }
+ return c->code;
+ }
+
+ if(h->size != rxsize){
+ if(DebugMach){
+ prints("mach_msg reply size mismatch ");
+ sys·printint(h->size);
+ prints(" != ");
+ sys·printint(rxsize);
+ prints("\n");
+ }
+ return -307; // MIG_ARRAY_TOO_LARGE
+ }
+
return 0;
}
+
+
+// Semaphores!
+
+enum
+{
+ Tsemcreate = 3418,
+ Rsemcreate = Tsemcreate + Reply,
+
+ Tsemdestroy = 3419,
+ Rsemdestroy = Tsemdestroy + Reply,
+};
+
+typedef struct TsemcreateMsg TsemcreateMsg;
+typedef struct RsemcreateMsg RsemcreateMsg;
+typedef struct TsemdestroyMsg TsemdestroyMsg;
+// RsemdestroyMsg = CodeMsg
+
+#pragma pack on
+struct TsemcreateMsg
+{
+ mach_msg_header_t h;
+ NDR_record_t ndr;
+ int32 policy;
+ int32 value;
+};
+
+struct RsemcreateMsg
+{
+ mach_msg_header_t h;
+ mach_msg_body_t body;
+ mach_msg_port_descriptor_t semaphore;
+};
+
+struct TsemdestroyMsg
+{
+ mach_msg_header_t h;
+ mach_msg_body_t body;
+ mach_msg_port_descriptor_t semaphore;
+};
+#pragma pack off
+
+mach_port_t
+semcreate(void)
+{
+ union {
+ TsemcreateMsg tx;
+ RsemcreateMsg rx;
+ uint8 pad[MinMachMsg];
+ } m;
+ kern_return_t r;
+
+ m.tx.h.bits = 0;
+ m.tx.h.size = sizeof(m.tx);
+ m.tx.h.remote_port = mach_task_self();
+ m.tx.h.id = Tsemcreate;
+ m.tx.ndr = zerondr;
+
+ m.tx.policy = 0; // 0 = SYNC_POLICY_FIFO
+ m.tx.value = 0;
+
+ if((r = machcall(&m.tx.h, sizeof m, sizeof(m.rx))) != 0)
+ macherror(r, "semaphore_create");
+ if(m.rx.body.descriptor_count != 1)
+ unimplemented("semcreate desc count");
+ return m.rx.semaphore.name;
+}
+
+void
+semdestroy(mach_port_t sem)
+{
+ union {
+ TsemdestroyMsg tx;
+ uint8 pad[MinMachMsg];
+ } m;
+ kern_return_t r;
+
+ m.tx.h.bits = MACH_MSGH_BITS_COMPLEX;
+ m.tx.h.size = sizeof(m.tx);
+ m.tx.h.remote_port = mach_task_self();
+ m.tx.h.id = Tsemdestroy;
+ m.tx.body.descriptor_count = 1;
+ m.tx.semaphore.name = sem;
+ m.tx.semaphore.disposition = MACH_MSG_TYPE_MOVE_SEND;
+ m.tx.semaphore.type = 0;
+
+ if((r = machcall(&m.tx.h, sizeof m, 0)) != 0)
+ macherror(r, "semaphore_destroy");
+}
+
+// The other calls have simple system call traps
+// in sys_amd64_darwin.s
+kern_return_t mach_semaphore_wait(uint32 sema);
+kern_return_t mach_semaphore_timedwait(uint32 sema, uint32 sec, uint32 nsec);
+kern_return_t mach_semaphore_signal(uint32 sema);
+kern_return_t mach_semaphore_signal_all(uint32 sema);
+
+void
+semacquire(mach_port_t sem)
+{
+ kern_return_t r;
+
+ if((r = mach_semaphore_wait(sem)) != 0)
+ macherror(r, "semaphore_wait");
+}
+
+void
+semrelease(mach_port_t sem)
+{
+ kern_return_t r;
+
+ if((r = mach_semaphore_signal(sem)) != 0)
+ macherror(r, "semaphore_signal");
+}
+
diff -r f1f205d50880 -r 7627e93b0342 src/runtime/rt1_amd64_linux.c
--- a/src/runtime/rt1_amd64_linux.c Tue Sep 09 10:48:14 2008 -0700
+++ b/src/runtime/rt1_amd64_linux.c Tue Sep 09 11:50:14 2008 -0700
@@ -427,3 +427,7 @@
select(0, nil, nil, nil, &tv);
}
+void
+osinit(void)
+{
+}
diff -r f1f205d50880 -r 7627e93b0342 src/runtime/runtime.h
--- a/src/runtime/runtime.h Tue Sep 09 10:48:14 2008 -0700
+++ b/src/runtime/runtime.h Tue Sep 09 11:50:14 2008 -0700
@@ -44,7 +44,7 @@
typedef struct Stktop Stktop;
typedef struct Alg Alg;
typedef struct Lock Lock;
-typedef struct Note Note;
+typedef union Note Note;
typedef struct Mem Mem;
/*
@@ -78,10 +78,17 @@
struct Lock
{
uint32 key;
+ uint32 sema; // for OS X
};
-struct Note
+union Note
{
- Lock lock;
+ struct { // Linux
+ Lock lock;
+ };
+ struct { // OS X
+ int32 wakeup;
+ uint32 sema;
+ };
};
struct String
{
@@ -149,6 +156,7 @@
G* g0; // g0 w interrupt stack - must not move
uint64 morearg; // arg to morestack - must not move
uint64 cret; // return value from C - must not move
+ uint64 procid; // for debuggers - must not move
G* curg; // current running goroutine
G* lastg; // last running goroutine - to emulate fifo
Gobuf sched;
@@ -159,8 +167,8 @@
Note havenextg;
G* nextg;
M* schedlink;
- int32 procid; // for debuggers
Mem mem;
+ uint32 machport; // Return address for Mach IPC (OS X)
};
struct Stktop
{
@@ -239,7 +247,6 @@
byte* getenv(int8*);
int32 atoi(byte*);
void newosproc(M *m, G *g, void *stk, void (*fn)(void));
-int32 getprocid(void);
/*
* mutual exclusion locks. in the uncontended case,
diff -r f1f205d50880 -r 7627e93b0342 src/runtime/sys_amd64_darwin.s
--- a/src/runtime/sys_amd64_darwin.s Tue Sep 09 10:48:14 2008 -0700
+++ b/src/runtime/sys_amd64_darwin.s Tue Sep 09 11:50:14 2008 -0700
@@ -4,12 +4,11 @@
//
// System calls and other sys.stuff for AMD64, Darwin
+// See http://fxr.watson.org/fxr/source/bsd/kern/syscalls.c?v=xnu-1228
+// or /usr/include/sys/syscall.h (on a Mac) for system call numbers.
//
-// TODO(rsc): Either sys·exit or exit1 is wrong!
-// It looks like sys·exit is correct (exits the entire program)
-// and exit1 should be mimicking the OS X library routine
-// __bsdthread_terminate.
+// Exit the entire program (like C exit)
TEXT sys·exit(SB),7,$-8
MOVL 8(SP), DI // arg 1 exit status
MOVL $(0x2000000+1), AX // syscall entry
@@ -17,9 +16,11 @@
CALL notok(SB)
RET
+// Exit this OS thread (like pthread_exit, which eventually
+// calls __bsdthread_terminate).
TEXT exit1(SB),7,$-8
MOVL 8(SP), DI // arg 1 exit status
- MOVL $(0x2000000+1), AX // syscall entry
+ MOVL $(0x2000000+361), AX // syscall entry
SYSCALL
CALL notok(SB)
RET
@@ -130,3 +131,127 @@
MOVQ x+8(FP), BX
MOVQ BX, -8(AX) // set calling pc
RET
+
+// void bsdthread_create(void *stk, M *m, G *g, void (*fn)(void))
+TEXT bsdthread_create(SB),7,$-8
+ // Set up arguments to bsdthread_create system call.
+ // The ones in quotes pass through to the thread callback
+ // uninterpreted, so we can put whatever we want there.
+ MOVQ fn+32(SP), DI // "func"
+ MOVQ m+16(SP), SI // "arg"
+ MOVQ stk+8(SP), DX // stack
+ MOVQ g+24(SP), R10 // "pthread"
+ MOVQ $0, R10 // flags
+ MOVQ $(0x2000000+360), AX // bsdthread_create
+ SYSCALL
+ JCC 2(PC)
+ CALL notok(SB)
+ RET
+
+// The thread that bsdthread_create creates starts executing here,
+// because we registered this function using bsdthread_register
+// at startup.
+// DI = "pthread" (= g)
+// SI = mach thread port
+// DX = "func" (= fn)
+// CX = "arg" (= m)
+// R8 = stack
+// R9 = flags (= 0)
+// SP = stack - C_64_REDZONE_LEN (= stack - 128)
+TEXT bsdthread_start(SB),7,$-8
+ MOVQ CX, R14 // m
+ MOVQ DI, R15 // g
+ MOVQ SI, 24(R14) // thread port is m->procid
+ CALL DX // fn
+ CALL exit1(SB)
+ RET
+
+// void bsdthread_register(void)
+// registers callbacks for threadstart (see bsdthread_create above
+// and wqthread and pthsize (not used). returns 0 on success.
+TEXT bsdthread_register(SB),7,$-8
+ MOVQ $bsdthread_start(SB), DI // threadstart
+ MOVQ $0, SI // wqthread, not used by us
+ MOVQ $0, DX // pthsize, not used by us
+ MOVQ $(0x2000000+366), AX // bsdthread_register
+ SYSCALL
+ JCC 2(PC)
+ CALL notok(SB)
+ RET
+
+// int64 select(int32, void*, void*, void*, void*)
+TEXT select(SB),7,$0
+ MOVL 8(SP), DI
+ MOVQ 16(SP), SI
+ MOVQ 24(SP), DX
+ MOVQ 32(SP), R10
+ MOVQ 40(SP), R8
+ MOVL $(0x2000000+407), AX // select_nocancel
+ SYSCALL
+ RET
+
+// Mach system calls use 0x1000000 instead of the BSD's 0x2000000.
+
+// uint32 mach_msg_trap(void*, uint32, uint32, uint32, uint32, uint32, uint32)
+TEXT mach_msg_trap(SB),7,$0
+ MOVQ 8(SP), DI
+ MOVL 16(SP), SI
+ MOVL 20(SP), DX
+ MOVL 24(SP), R10
+ MOVL 28(SP), R8
+ MOVL 32(SP), R9
+ MOVL 36(SP), R11
+ PUSHQ R11 // seventh arg, on stack
+ MOVL $(0x1000000+31), AX // mach_msg_trap
+ SYSCALL
+ POPQ R11
+ RET
+
+TEXT mach_task_self(SB),7,$0
+ MOVL $(0x1000000+28), AX // task_self_trap
+ SYSCALL
+ RET
+
+TEXT mach_thread_self(SB),7,$0
+ MOVL $(0x1000000+27), AX // thread_self_trap
+ SYSCALL
+ RET
+
+TEXT mach_reply_port(SB),7,$0
+ MOVL $(0x1000000+26), AX // mach_reply_port
+ SYSCALL
+ RET
+
+// Mach provides trap versions of the semaphore ops,
+// instead of requiring the use of RPC.
+
+// uint32 mach_semaphore_wait(uint32)
+TEXT mach_semaphore_wait(SB),7,$0
+ MOVL 8(SP), DI
+ MOVL $(0x1000000+36), AX // semaphore_wait_trap
+ SYSCALL
+ RET
+
+// uint32 mach_semaphore_timedwait(uint32, uint32, uint32)
+TEXT mach_semaphore_timedwait(SB),7,$0
+ MOVL 8(SP), DI
+ MOVL 12(SP), SI
+ MOVL 16(SP), DX
+ MOVL $(0x1000000+38), AX // semaphore_timedwait_trap
+ SYSCALL
+ RET
+
+// uint32 mach_semaphore_signal(uint32)
+TEXT mach_semaphore_signal(SB),7,$0
+ MOVL 8(SP), DI
+ MOVL $(0x1000000+33), AX // semaphore_signal_trap
+ SYSCALL
+ RET
+
+// uint32 mach_semaphore_signal_all(uint32)
+TEXT mach_semaphore_signal_all(SB),7,$0
+ MOVL 8(SP), DI
+ MOVL $(0x1000000+34), AX // semaphore_signal_all_trap
+ SYSCALL
+ RET
+
diff -r f1f205d50880 -r 7627e93b0342 src/runtime/sys_amd64_linux.s
--- a/src/runtime/sys_amd64_linux.s Tue Sep 09 10:48:14 2008 -0700
+++ b/src/runtime/sys_amd64_linux.s Tue Sep 09 11:50:14 2008 -0700
@@ -162,10 +162,17 @@
JEQ 2(PC)
RET
- // In child, call fn on new stack
+ // In child, set up new stack
MOVQ SI, SP
MOVQ R8, R14 // m
MOVQ R9, R15 // g
+
+ // Initialize m->procid to Linux tid
+ MOVL $186, AX // gettid
+ SYSCALL
+ MOVQ AX, 24(R14)
+
+ // Call fn
CALL R12
// It shouldn't return. If it does, exi
@@ -174,7 +181,7 @@
SYSCALL
JMP -3(PC) // keep exiting
-// int64 select(int32, void*, void*, void*, void*)
+// int64 select(int32, void*, void*, void*, struct timeval*)
TEXT select(SB),7,$0
MOVL 8(SP), DI
MOVQ 16(SP), SI
@@ -185,16 +192,3 @@
SYSCALL
RET
-// Linux allocates each thread its own pid, like Plan 9.
-// But the getpid() system call returns the pid of the
-// original thread (the one that exec started with),
-// no matter which thread asks. This system call,
-// which Linux calls gettid, returns the actual pid of
-// the calling thread, not the fake one.
-//
-// int32 getprocid(void)
-TEXT getprocid(SB),7,$0
- MOVL $186, AX
- SYSCALL
- RET
-
changeset: 689:86cd498ec3ec
user: Ken Thompson <[email protected]>
date: Fri Sep 19 20:43:30 2008 -0700
summary: fix bugs in asynch select
diff -r 1916211023d6 -r 86cd498ec3ec src/runtime/chan.c
--- a/src/runtime/chan.c Fri Sep 19 18:06:53 2008 -0700
+++ b/src/runtime/chan.c Fri Sep 19 20:43:30 2008 -0700
@@ -201,6 +201,7 @@
return;
asynch:
+//prints("\nasend\n");
while(c->qcount >= c->dataqsiz) {
// (rsc) should check for pres != nil
sg = allocsg(c);
@@ -208,6 +209,7 @@
enqueue(&c->sendq, sg);
unlock(&chanlock);
sys·gosched();
+
lock(&chanlock);
}
if(ep != nil)
@@ -218,10 +220,12 @@
sg = dequeue(&c->recvq, c);
if(sg != nil) {
gp = sg->g;
+ gp->param = sg;
freesg(c, sg);
unlock(&chanlock);
+//prints("wakeup\n");
ready(gp);
- }else
+ } else
unlock(&chanlock);
}
@@ -290,10 +294,11 @@
sg = dequeue(&c->sendq, c);
if(sg != nil) {
gp = sg->g;
+ gp->param = sg;
freesg(c, sg);
unlock(&chanlock);
ready(gp);
- }else
+ } else
unlock(&chanlock);
}
@@ -523,7 +528,6 @@
for(i=0; i<sel->ncase; i++) {
cas = &sel->scase[o];
c = cas->chan;
-
if(c->dataqsiz > 0) {
if(cas->send) {
if(c->qcount < c->dataqsiz)
@@ -532,7 +536,7 @@
if(c->qcount > 0)
goto asynr;
}
- }
+ } else
if(cas->send) {
sg = dequeue(&c->recvq, c);
@@ -557,23 +561,29 @@
if(c->dataqsiz > 0) {
if(cas->send) {
if(c->qcount < c->dataqsiz) {
- prints("second pass asyn send\n");
+ prints("selectgo: pass 2 async send\n");
goto asyns;
}
+ sg = allocsg(c);
+ sg->offset = o;
+ enqueue(&c->sendq, sg);
} else {
if(c->qcount > 0) {
- prints("second pass asyn recv\n");
+ prints("selectgo: pass 2 async recv\n");
goto asynr;
}
+ sg = allocsg(c);
+ sg->offset = o;
+ enqueue(&c->recvq, sg);
}
- }
+ } else
if(cas->send) {
sg = dequeue(&c->recvq, c);
if(sg != nil) {
- prints("second pass syn send\n");
+ prints("selectgo: pass 2 sync send\n");
g->selgen++;
- goto gots; // probably an error
+ goto gots;
}
sg = allocsg(c);
sg->offset = o;
@@ -582,9 +592,9 @@
} else {
sg = dequeue(&c->sendq, c);
if(sg != nil) {
- prints("second pass syn recv\n");
+ prints("selectgo: pass 2 sync recv\n");
g->selgen++;
- goto gotr; // probably an error
+ goto gotr;
}
sg = allocsg(c);
sg->offset = o;
@@ -596,9 +606,6 @@
o -= sel->ncase;
}
- // send and recv paths to sleep for a rendezvous
- // (rsc) not correct to set Gwaiting after queueing;
- // might already have been readied.
g->status = Gwaiting;
unlock(&chanlock);
sys·gosched();
@@ -623,6 +630,12 @@
prints("\n");
}
+ if(c->dataqsiz > 0) {
+ if(cas->send)
+ goto asyns;
+ goto asynr;
+ }
+
if(!cas->send) {
if(cas->u.elemp != nil)
c->elemalg->copy(c->elemsize, cas->u.elemp, sg->elem);
@@ -632,10 +645,31 @@
goto retc;
asynr:
+ if(cas->u.elemp != nil)
+ c->elemalg->copy(c->elemsize, cas->u.elemp, c->recvdataq->elem);
+ c->recvdataq = c->recvdataq->link;
+ c->qcount--;
+ sg = dequeue(&c->sendq, c);
+ if(sg != nil) {
+ gp = sg->g;
+ freesg(c, sg);
+ ready(gp);
+ }
+ goto retc;
+
asyns:
- unlock(&chanlock);
- throw("asyn");
- return; // compiler doesn't know throw doesn't return
+ if(cas->u.elem != nil)
+ c->elemalg->copy(c->elemsize, c->senddataq->elem, cas->u.elem);
+ c->senddataq = c->senddataq->link;
+ c->qcount++;
+ sg = dequeue(&c->recvq, c);
+ if(sg != nil) {
+ gp = sg->g;
+ gp->param = sg;
+ freesg(c, sg);
+ ready(gp);
+ }
+ goto retc;
gotr:
// recv path to wakeup the sender (sg)
changeset: 693:d4ccaa48fb8f
user: Ken Thompson <[email protected]>
date: Sat Sep 20 19:56:40 2008 -0700
summary: another async select bug
diff -r c74c13f5ffbd -r d4ccaa48fb8f src/cmd/gc/walk.c
--- a/src/cmd/gc/walk.c Sat Sep 20 15:16:48 2008 -0700
+++ b/src/cmd/gc/walk.c Sat Sep 20 19:56:40 2008 -0700
@@ -563,7 +563,7 @@
goto ret;
}
- // structure literal
+ // array literal
if(t->etype == TARRAY) {
r = arraylit(n);
indir(n, r);
@@ -2149,9 +2149,13 @@
if(t == T)
break;
- a = n->left; // hint
- if(n->left == N)
+ if(n->left != N) {
+ // async buf size
+ a = nod(OCONV, n->left, N);
+ a->type = types[TUINT32];
+ } else
a = nodintconst(0);
+
r = a;
a = nodintconst(algtype(t->type)); // elem algorithm
r = list(a, r);
@@ -2991,10 +2995,10 @@
if(t->bound < 0) {
// make it a closed array
- // should there be a type copy here?
r = listfirst(&saver, &n->left);
for(idx=0; r!=N; idx++)
r = listnext(&saver);
+ t = deep(t);
t->bound = idx;
}
diff -r c74c13f5ffbd -r d4ccaa48fb8f src/runtime/chan.c
--- a/src/runtime/chan.c Sat Sep 20 15:16:48 2008 -0700
+++ b/src/runtime/chan.c Sat Sep 20 19:56:40 2008 -0700
@@ -652,6 +652,7 @@
sg = dequeue(&c->sendq, c);
if(sg != nil) {
gp = sg->g;
+ gp->param = sg;
freesg(c, sg);
ready(gp);
}
diff -r c74c13f5ffbd -r d4ccaa48fb8f test/ken/chan.go
--- a/test/ken/chan.go Sat Sep 20 15:16:48 2008 -0700
+++ b/test/ken/chan.go Sat Sep 20 19:56:40 2008 -0700
@@ -8,32 +8,42 @@
import rand "rand"
+type Chan
+struct
+{
+ sc,rc *chan int; // send and recv chan
+ sv,rv int; // send and recv seq
+}
+
var
(
- c0 *chan int;
- c1 *chan int;
- c2 *chan int;
- c3 *chan int;
- n int;
- End int = 1000;
- totr int;
- tots int;
+ nproc int;
+ cval int;
+ End int = 10000;
+ totr,tots int;
+ nc *Chan;
)
func
-mkchan(c uint)
+init()
{
- n = 0;
+ nc = new(Chan);
+}
- c0 = new(chan int, c);
- c1 = new(chan int, c);
- c2 = new(chan int, c);
- c3 = new(chan int, c);
-
-// print("c0=", c0, "\n");
-// print("c1=", c1, "\n");
-// print("c2=", c2, "\n");
-// print("c3=", c3, "\n");
+func
+mkchan(c,n int) *[]*Chan
+{
+ ca := new([]*Chan, n);
+ for i:=0; i<n; i++ {
+ cval = cval+100;
+ ch := new(Chan);
+ ch.sc = new(chan int, c);
+ ch.rc = ch.sc;
+ ch.sv = cval;
+ ch.rv = cval;
+ ca[i] = ch;
+ }
+ return ca;
}
func
@@ -48,42 +58,82 @@
panic("got ", v, " expected ", v0+1, "\n");
}
+func (c *Chan)
+send() bool
+{
+// print("send ", c.sv, "\n");
+ tots++;
+ c.sv = expect(c.sv, c.sv);
+ if c.sv == End {
+ c.sc = nil
+ return true;
+ }
+ return false;
+}
+
func
-send(c *chan int, v0 int)
+send(c *Chan)
{
- n++;
+ nproc++; // total goroutines running
for {
for r:=rand.nrand(10); r>=0; r-- {
sys.gosched();
}
- c <- v0;
- tots++;
- v0 = expect(v0, v0);
- if v0 == End {
+ c.sc <- c.sv;
+ if c.send() {
break;
}
}
- n--;
+ nproc--;
+}
+
+func (c *Chan)
+recv(v int) bool
+{
+// print("recv ", v, "\n");
+ totr++;
+ c.rv = expect(c.rv, v);
+ if c.rv == End {
+ c.rc = nil;
+ return true;
+ }
+ return false;
}
func
-selsend()
+recv(c *Chan)
{
var v int;
- a := 4; // local chans running
- n += a; // total chans running
- v0 := 100;
- v1 := 200;
- v2 := 300;
- v3 := 400;
+ nproc++; // total goroutines running
+ for {
+ for r:=rand.nrand(10); r>=0; r-- {
+ sys.gosched();
+ }
+ v = <-c.rc;
+ if c.recv(v) {
+ break;
+ }
+ }
+ nproc--;
+}
- // local copies of the chans
- // so we can nil them out
- l0 := c0;
- l1 := c1;
- l2 := c2;
- l3 := c3;
+func
+sel(r0,r1,r2,r3, s0,s1,s2,s3 *Chan)
+{
+ var v int;
+
+ nproc++; // total goroutines running
+ a := 0; // local chans running
+
+ if r0.rc != nil { a++ }
+ if r1.rc != nil { a++ }
+ if r2.rc != nil { a++ }
+ if r3.rc != nil { a++ }
+ if s0.sc != nil { a++ }
+ if s1.sc != nil { a++ }
+ if s2.sc != nil { a++ }
+ if s3.sc != nil { a++ }
for {
for r:=rand.nrand(5); r>=0; r-- {
@@ -91,136 +141,118 @@
}
select {
- case l0 <- v0:
- v0 = expect(v0, v0);
- if v0 == End {
- l0 = nil;
+ case v = <-r0.rc:
+ if r0.recv(v) {
a--;
}
- case l1 <- v1:
- v1 = expect(v1, v1);
- if v1 == End {
- l1 = nil;
+ case v = <-r1.rc:
+ if r1.recv(v) {
a--;
}
- case l2 <- v2:
- v2 = expect(v2, v2);
- if v2 == End {
- l2 = nil;
+ case v = <-r2.rc:
+ if r2.recv(v) {
a--;
}
- case l3 <- v3:
- v3 = expect(v3, v3);
- if v3 == End {
- l3 = nil;
+ case v = <-r3.rc:
+ if r3.recv(v) {
+ a--;
+ }
+ case s0.sc <- s0.sv:
+ if s0.send() {
+ a--;
+ }
+ case s1.sc <- s1.sv:
+ if s1.send() {
+ a--;
+ }
+ case s2.sc <- s2.sv:
+ if s2.send() {
+ a--;
+ }
+ case s3.sc <- s3.sv:
+ if s3.send() {
a--;
}
}
-
- tots++;
if a == 0 {
break;
}
}
- n -= 4;
-}
-
-func
-recv(c *chan int, v0 int)
-{
- var v int;
-
- n++;
- for i:=0; i<100; i++ {
- for r:=rand.nrand(10); r>=0; r-- {
- sys.gosched();
- }
- v = <- c;
- totr++;
- v0 = expect(v0, v);
- if v0 == End {
- break;
- }
- }
- n--;
-}
-
-func
-selrecv()
-{
- var v int;
-
- a := 4; // local chans running
- n += a; // total chans running
- v0 := 100;
- v1 := 200;
- v2 := 300;
- v3 := 400;
-
- for {
- for r:=rand.nrand(5); r>=0; r-- {
- sys.gosched();
- }
-
- select {
- case v = <- c0:
- v0 = expect(v0, v);
- if v0 == End {
- a--;
- }
- case v = <- c1:
- v1 = expect(v1, v);
- if v1 == End {
- a--;
- }
- case v = <- c2:
- v2 = expect(v2, v);
- if v2 == End {
- a--;
- }
- case v = <- c3:
- v3 = expect(v3, v);
- if v3 == End {
- a--;
- }
- }
-
- totr++;
- if a == 0 {
- break;
- }
- }
- n -= 4;
+ nproc--;
}
// direct send to direct recv
func
-test1(c *chan int, v0 int)
+test1(c *Chan)
{
- go send(c, v0);
- go recv(c, v0);
+ go send(c);
+ go recv(c);
}
// direct send to select recv
func
-test2()
+test2(c int)
{
- go send(c0, 100);
- go send(c1, 200);
- go send(c2, 300);
- go send(c3, 400);
- go selrecv();
+ ca := mkchan(c,4);
+
+ go send(ca[0]);
+ go send(ca[1]);
+ go send(ca[2]);
+ go send(ca[3]);
+
+ go sel(ca[0],ca[1],ca[2],ca[3], nc,nc,nc,nc);
}
// select send to direct recv
func
-test3()
+test3(c int)
{
- go recv(c0, 100);
- go recv(c1, 200);
- go recv(c2, 300);
- go recv(c3, 400);
- go selsend();
+ ca := mkchan(c,4);
+
+ go recv(ca[0]);
+ go recv(ca[1]);
+ go recv(ca[2]);
+ go recv(ca[3]);
+
+ go sel(nc,nc,nc,nc, ca[0],ca[1],ca[2],ca[3]);
+}
+
+// select send to select recv
+func
+test4(c int)
+{
+ ca := mkchan(c,4);
+
+ go sel(nc,nc,nc,nc, ca[0],ca[1],ca[2],ca[3]);
+ go sel(ca[0],ca[1],ca[2],ca[3], nc,nc,nc,nc);
+}
+
+func
+test5(c int)
+{
+ ca := mkchan(c,8);
+
+ go sel(ca[4],ca[5],ca[6],ca[7], ca[0],ca[1],ca[2],ca[3]);
+ go sel(ca[0],ca[1],ca[2],ca[3], ca[4],ca[5],ca[6],ca[7]);
+}
+
+func
+test6(c int)
+{
+ ca := mkchan(c,12);
+
+ go send(ca[4]);
+ go send(ca[5]);
+ go send(ca[6]);
+ go send(ca[7]);
+
+ go recv(ca[8]);
+ go recv(ca[9]);
+ go recv(ca[10]);
+ go recv(ca[11]);
+
+ go sel(ca[4],ca[5],ca[6],ca[7], ca[0],ca[1],ca[2],ca[3]);
+ go sel(ca[0],ca[1],ca[2],ca[3], ca[8],ca[9],ca[10],ca[11]);
}
// wait for outstanding tests to finish
@@ -228,28 +260,35 @@
wait()
{
sys.gosched();
- for n != 0 {
+ for nproc != 0 {
sys.gosched();
}
}
// run all tests with specified buffer size
func
-tests(c uint)
+tests(c int)
{
- mkchan(c);
- test1(c0, 100);
- test1(c1, 200);
- test1(c2, 300);
- test1(c3, 400);
+ ca := mkchan(c,4);
+ test1(ca[0]);
+ test1(ca[1]);
+ test1(ca[2]);
+ test1(ca[3]);
wait();
- mkchan(c);
- test2();
+ test2(c);
wait();
- mkchan(c);
- test3();
+ test3(c);
+ wait();
+
+ test4(c);
+ wait();
+
+ test5(c);
+ wait();
+
+ test6(c);
wait();
}
@@ -257,13 +296,20 @@
func
main()
{
+
tests(0);
tests(1);
tests(10);
tests(100);
- if tots != totr || tots != 3648 {
- print("tots=", tots, " totr=", totr, "\n");
+ t := 4 // buffer sizes
+ * ( 4*4 // tests 1,2,3,4 channels
+ + 8 // test 5 channels
+ + 12 // test 6 channels
+ ) * 76; // sends/recvs on a channel
+
+ if tots != t || totr != t {
+ print("tots=", tots, " totr=", totr, " sb=", t, "\n");
sys.exit(1);
}
sys.exit(0);
changeset: 741:fa74ddeacaa7
user: Russ Cox <[email protected]>
date: Fri Sep 26 11:47:04 2008 -0700
summary: test and fix non-blocking chan ops on buffered chans
diff -r 00d9ac9effd4 -r fa74ddeacaa7 src/runtime/chan.c
--- a/src/runtime/chan.c Fri Sep 26 11:44:20 2008 -0700
+++ b/src/runtime/chan.c Fri Sep 26 11:47:04 2008 -0700
@@ -198,12 +198,18 @@
sg = g->param;
freesg(c, sg);
unlock(&chanlock);
+ if(pres != nil)
+ *pres = true;
return;
asynch:
//prints("\nasend\n");
while(c->qcount >= c->dataqsiz) {
- // (rsc) should check for pres != nil
+ if(pres != nil) {
+ unlock(&chanlock);
+ *pres = false;
+ return;
+ }
sg = allocsg(c);
g->status = Gwaiting;
enqueue(&c->sendq, sg);
@@ -227,6 +233,8 @@
ready(gp);
} else
unlock(&chanlock);
+ if(pres != nil)
+ *pres = true;
}
static void
@@ -277,10 +285,17 @@
c->elemalg->copy(c->elemsize, ep, sg->elem);
freesg(c, sg);
unlock(&chanlock);
+ if(pres != nil)
+ *pres = true;
return;
asynch:
while(c->qcount <= 0) {
+ if(pres != nil) {
+ unlock(&chanlock);
+ *pres = false;
+ return;
+ }
sg = allocsg(c);
g->status = Gwaiting;
enqueue(&c->recvq, sg);
@@ -300,6 +315,8 @@
ready(gp);
} else
unlock(&chanlock);
+ if(pres != nil)
+ *pres = true;
}
// chansend1(hchan *chan any, elem any);
diff -r 00d9ac9effd4 -r fa74ddeacaa7 test/chan/nonblock.go
--- a/test/chan/nonblock.go Fri Sep 26 11:44:20 2008 -0700
+++ b/test/chan/nonblock.go Fri Sep 26 11:47:04 2008 -0700
@@ -52,61 +52,63 @@
var s string;
var ok bool;
- c32 := new(chan int32);
- c64 := new(chan int64);
- cb := new(chan bool);
- cs := new(chan string);
-
- i32, ok = <-c32;
- if ok { panic("blocked i32sender") }
-
- i64, ok = <-c64;
- if ok { panic("blocked i64sender") }
-
- b, ok = <-cb;
- if ok { panic("blocked bsender") }
-
- s, ok = <-cs;
- if ok { panic("blocked ssender") }
-
- go i32receiver(c32);
- pause();
- ok = c32 <- 123;
- if !ok { panic("i32receiver") }
- go i32sender(c32);
- pause();
- i32, ok = <-c32;
- if !ok { panic("i32sender") }
- if i32 != 234 { panic("i32sender value") }
-
- go i64receiver(c64);
- pause();
- ok = c64 <- 123456;
- if !ok { panic("i64receiver") }
- go i64sender(c64);
- pause();
- i64, ok = <-c64;
- if !ok { panic("i64sender") }
- if i64 != 234567 { panic("i64sender value") }
-
- go breceiver(cb);
- pause();
- ok = cb <- true;
- if !ok { panic("breceiver") }
- go bsender(cb);
- pause();
- b, ok = <-cb;
- if !ok { panic("bsender") }
- if !b{ panic("bsender value") }
-
- go sreceiver(cs);
- pause();
- ok = cs <- "hello";
- if !ok { panic("sreceiver") }
- go ssender(cs);
- pause();
- s, ok = <-cs;
- if !ok { panic("ssender") }
- if s != "hello again" { panic("ssender value") }
+ for buffer := 0; buffer < 2; buffer++ {
+ c32 := new(chan int32, buffer);
+ c64 := new(chan int64, buffer);
+ cb := new(chan bool, buffer);
+ cs := new(chan string, buffer);
+
+ i32, ok = <-c32;
+ if ok { panic("blocked i32sender") }
+
+ i64, ok = <-c64;
+ if ok { panic("blocked i64sender") }
+
+ b, ok = <-cb;
+ if ok { panic("blocked bsender") }
+
+ s, ok = <-cs;
+ if ok { panic("blocked ssender") }
+
+ go i32receiver(c32);
+ pause();
+ ok = c32 <- 123;
+ if !ok { panic("i32receiver") }
+ go i32sender(c32);
+ pause();
+ i32, ok = <-c32;
+ if !ok { panic("i32sender") }
+ if i32 != 234 { panic("i32sender value") }
+
+ go i64receiver(c64);
+ pause();
+ ok = c64 <- 123456;
+ if !ok { panic("i64receiver") }
+ go i64sender(c64);
+ pause();
+ i64, ok = <-c64;
+ if !ok { panic("i64sender") }
+ if i64 != 234567 { panic("i64sender value") }
+
+ go breceiver(cb);
+ pause();
+ ok = cb <- true;
+ if !ok { panic("breceiver") }
+ go bsender(cb);
+ pause();
+ b, ok = <-cb;
+ if !ok { panic("bsender") }
+ if !b{ panic("bsender value") }
+
+ go sreceiver(cs);
+ pause();
+ ok = cs <- "hello";
+ if !ok { panic("sreceiver") }
+ go ssender(cs);
+ pause();
+ s, ok = <-cs;
+ if !ok { panic("ssender") }
+ if s != "hello again" { panic("ssender value") }
+ }
print("PASS\n")
}
changeset: 1068:64cf79b61d8d
user: Russ Cox <[email protected]>
date: Wed Nov 05 17:57:18 2008 -0800
summary: runtime support for default in select.
diff -r ba82900ec25b -r 64cf79b61d8d src/runtime/chan.c
--- a/src/runtime/chan.c Wed Nov 05 16:09:12 2008 -0800
+++ b/src/runtime/chan.c Wed Nov 05 17:57:18 2008 -0800
@@ -52,7 +52,7 @@
{
Hchan* chan; // chan
byte* pc; // return pc
- uint16 send; // 0-recv 1-send
+ uint16 send; // 0-recv 1-send 2-default
uint16 so; // vararg of selected bool
union {
byte elem[8]; // element (send)
@@ -504,7 +504,7 @@
sys·selectgo(Select *sel)
{
uint32 p, o, i;
- Scase *cas;
+ Scase *cas, *dfl;
Hchan *c;
SudoG *sg;
G *gp;
@@ -542,8 +542,13 @@
lock(&chanlock);
// pass 1 - look for something already waiting
+ dfl = nil;
for(i=0; i<sel->ncase; i++) {
cas = &sel->scase[o];
+ if(cas->send == 2) { // default
+ dfl = cas;
+ continue;
+ }
c = cas->chan;
if(c->dataqsiz > 0) {
if(cas->send) {
@@ -569,6 +574,12 @@
if(o >= sel->ncase)
o -= sel->ncase;
}
+
+ if(dfl != nil) {
+ cas = dfl;
+ goto retc;
+ }
+
// pass 2 - enqueue on all chans
for(i=0; i<sel->ncase; i++) {
changeset: 1069:bc30e0e39397
user: Russ Cox <[email protected]>
date: Wed Nov 05 18:04:24 2008 -0800
summary: more runtime support for chan select default
diff -r 64cf79b61d8d -r bc30e0e39397 src/runtime/chan.c
--- a/src/runtime/chan.c Wed Nov 05 17:57:18 2008 -0800
+++ b/src/runtime/chan.c Wed Nov 05 18:04:24 2008 -0800
@@ -469,7 +469,7 @@
i = sel->ncase;
if(i >= sel->tcase)
- throw("selectsend: too many cases");
+ throw("selectrecv: too many cases");
sel->ncase = i+1;
cas = &sel->scase[i];
@@ -497,6 +497,44 @@
}
}
+void
+sys·selectdefault(Select *sel)
+{
+ int32 i, eo;
+ Scase *cas;
+ Hchan *c;
+
+ c = nil;
+ i = sel->ncase;
+ if(i >= sel->tcase)
+ throw("selectdefault: too many cases");
+ sel->ncase = i+1;
+ cas = &sel->scase[i];
+
+ cas->pc = sys·getcallerpc(&sel);
+ cas->chan = c;
+
+ eo = rnd(sizeof(sel), sizeof(c));
+ eo = rnd(eo+sizeof(c), sizeof(byte*));
+ cas->so = rnd(eo+sizeof(byte*), 1);
+ cas->send = 2;
+ cas->u.elemp = *(byte**)((byte*)&sel + eo);
+
+ if(debug) {
+ prints("newselect s=");
+ sys·printpointer(sel);
+ prints(" pc=");
+ sys·printpointer(cas->pc);
+ prints(" chan=");
+ sys·printpointer(cas->chan);
+ prints(" so=");
+ sys·printint(cas->so);
+ prints(" send=");
+ sys·printint(cas->send);
+ prints("\n");
+ }
+}
+
uint32 xxx = 0;
// selectgo(sel *byte);
changeset: 1070:b1489fa12c44
user: Ken Thompson <[email protected]>
date: Wed Nov 05 21:50:28 2008 -0800
summary: select default
diff -r bc30e0e39397 -r b1489fa12c44 src/cmd/gc/subr.c
--- a/src/cmd/gc/subr.c Wed Nov 05 18:04:24 2008 -0800
+++ b/src/cmd/gc/subr.c Wed Nov 05 21:50:28 2008 -0800
@@ -1447,6 +1447,9 @@
s = pkglookup("selectrecv", "sys");
if(s == n->sym)
return 1;
+ s = pkglookup("selectdefault", "sys");
+ if(s == n->sym)
+ return 1;
return 0;
}
diff -r bc30e0e39397 -r b1489fa12c44 src/cmd/gc/sys.go
--- a/src/cmd/gc/sys.go Wed Nov 05 18:04:24 2008 -0800
+++ b/src/cmd/gc/sys.go Wed Nov 05 21:50:28 2008 -0800
@@ -68,6 +68,7 @@
export func newselect(size int) (sel *byte);
export func selectsend(sel *byte, hchan *chan any, elem any) (selected bool);
export func selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
+export func selectdefault(sel *byte) (selected bool);
export func selectgo(sel *byte);
export func newarray(nel int, cap int, width int) (ary *[]any);
diff -r bc30e0e39397 -r b1489fa12c44 src/cmd/gc/sysimport.c
--- a/src/cmd/gc/sysimport.c Wed Nov 05 18:04:24 2008 -0800
+++ b/src/cmd/gc/sysimport.c Wed Nov 05 21:50:28 2008 -0800
@@ -53,6 +53,7 @@
"export func sys.newselect (size int) (sel *uint8)\n"
"export func sys.selectsend (sel *uint8, hchan *chan any, elem any) (selected bool)\n"
"export func sys.selectrecv (sel *uint8, hchan *chan any, elem *any) (selected bool)\n"
+ "export func sys.selectdefault (sel *uint8) (selected bool)\n"
"export func sys.selectgo (sel *uint8)\n"
"export func sys.newarray (nel int, cap int, width int) (ary *[]any)\n"
"export func sys.arraysliced (old *[]any, lb int, hb int, width int) (ary *[]any)\n"
diff -r bc30e0e39397 -r b1489fa12c44 src/cmd/gc/walk.c
--- a/src/cmd/gc/walk.c Wed Nov 05 18:04:24 2008 -0800
+++ b/src/cmd/gc/walk.c Wed Nov 05 21:50:28 2008 -0800
@@ -1246,6 +1246,8 @@
Node *a, *r, *on, *c;
Type *t;
+ if(n->left == N)
+ goto dflt;
c = n->left;
if(c->op == ORECV)
goto recv;
@@ -1329,6 +1331,14 @@
r = list(a, r);
a = var; // sel-var
r = list(a, r);
+ goto out;
+
+dflt:
+ // selectdefault(sel *byte);
+ on = syslook("selectdefault", 0);
+ a = var;
+ r = a; // sel-var
+ goto out;
out:
a = nod(OCALL, on, r);
@@ -1367,8 +1377,8 @@
{
Iter iter;
Node *n, *oc, *on, *r;
- Node *var, *bod, *res;
- int count;
+ Node *var, *bod, *res, *def;
+ int count, op;
int32 lno;
lno = setlineno(sel);
@@ -1385,6 +1395,7 @@
res = N; // entire select body
bod = N; // body of each case
oc = N; // last case
+ def = N; // default case
for(count=0; n!=N; n=listnext(&iter)) {
setlineno(n);
@@ -1395,15 +1406,22 @@
break;
case OXCASE:
- switch(n->left->op) {
+ if(n->left == N) {
+ op = ORECV; // actual value not used
+ if(def != N)
+ yyerror("only one default select allowed");
+ def = n;
+ } else
+ op = n->left->op;
+ switch(op) {
default:
- yyerror("select cases must be send or recv");
+ yyerror("select cases must be send, recv or default");
break;
case OAS:
// convert new syntax (a=recv(chan)) to (recv(a,chan))
if(n->left->right == N || n->left->right->op != ORECV) {
- yyerror("select cases must be send or recv");
+ yyerror("select cases must be send, recv or default");
break;
}
n->left->right->right = n->left->right->left;
@@ -1419,6 +1437,8 @@
oc = selcase(n, var);
res = list(res, oc);
break;
+
+
}
bod = N;
count++;
diff -r bc30e0e39397 -r b1489fa12c44 src/runtime/chan.c
--- a/src/runtime/chan.c Wed Nov 05 18:04:24 2008 -0800
+++ b/src/runtime/chan.c Wed Nov 05 21:50:28 2008 -0800
@@ -497,14 +497,14 @@
}
}
+
+// selectrecv(sel *byte) (selected bool);
void
-sys·selectdefault(Select *sel)
+sys·selectdefault(Select *sel, ...)
{
- int32 i, eo;
+ int32 i;
Scase *cas;
- Hchan *c;
- c = nil;
i = sel->ncase;
if(i >= sel->tcase)
throw("selectdefault: too many cases");
@@ -512,13 +512,11 @@
cas = &sel->scase[i];
cas->pc = sys·getcallerpc(&sel);
- cas->chan = c;
+ cas->chan = nil;
- eo = rnd(sizeof(sel), sizeof(c));
- eo = rnd(eo+sizeof(c), sizeof(byte*));
- cas->so = rnd(eo+sizeof(byte*), 1);
+ cas->so = rnd(sizeof(sel), 1);
cas->send = 2;
- cas->u.elemp = *(byte**)((byte*)&sel + eo);
+ cas->u.elemp = nil;
if(debug) {
prints("newselect s=");
diff -r bc30e0e39397 -r b1489fa12c44 src/runtime/runtime.c
--- a/src/runtime/runtime.c Wed Nov 05 18:04:24 2008 -0800
+++ b/src/runtime/runtime.c Wed Nov 05 21:50:28 2008 -0800
@@ -4,7 +4,8 @@
#include "runtime.h"
-int32 panicking = 0;
+int32 panicking = 0;
+int32 maxround = 8;
int32
gotraceback(void)
@@ -91,6 +92,8 @@
{
uint32 r;
+ if(m > maxround)
+ m = maxround;
r = n % m;
if(r)
n += m-r;
diff -r bc30e0e39397 -r b1489fa12c44 src/runtime/runtime.h
--- a/src/runtime/runtime.h Wed Nov 05 18:04:24 2008 -0800
+++ b/src/runtime/runtime.h Wed Nov 05 21:50:28 2008 -0800
@@ -190,6 +190,7 @@
int32 goidgen;
extern int32 gomaxprocs;
extern int32 panicking;
+extern int32 maxround;
/*
* common functions and data
changeset: 1084:c6f9c890a2cd
user: Ken Thompson <[email protected]>
date: Thu Nov 06 17:50:28 2008 -0800
summary: bug in select default
diff -r f8f3741ed8e5 -r c6f9c890a2cd src/runtime/chan.c
--- a/src/runtime/chan.c Thu Nov 06 17:39:48 2008 -0800
+++ b/src/runtime/chan.c Thu Nov 06 17:50:28 2008 -0800
@@ -408,6 +408,8 @@
if(debug) {
prints("newselect s=");
sys·printpointer(sel);
+ prints("newselect size=");
+ sys·printint(size);
prints("\n");
}
}
@@ -523,8 +525,6 @@
sys·printpointer(sel);
prints(" pc=");
sys·printpointer(cas->pc);
- prints(" chan=");
- sys·printpointer(cas->chan);
prints(" so=");
sys·printint(cas->so);
prints(" send=");
@@ -544,7 +544,6 @@
Hchan *c;
SudoG *sg;
G *gp;
-
byte *as;
if(xxx) {
@@ -581,31 +580,35 @@
dfl = nil;
for(i=0; i<sel->ncase; i++) {
cas = &sel->scase[o];
+
if(cas->send == 2) { // default
dfl = cas;
- continue;
+ goto next1;
}
+
c = cas->chan;
if(c->dataqsiz > 0) {
if(cas->send) {
if(c->qcount < c->dataqsiz)
goto asyns;
- } else {
- if(c->qcount > 0)
- goto asynr;
+ goto next1;
}
- } else
+ if(c->qcount > 0)
+ goto asynr;
+ goto next1;
+ }
if(cas->send) {
sg = dequeue(&c->recvq, c);
if(sg != nil)
goto gots;
- } else {
- sg = dequeue(&c->sendq, c);
- if(sg != nil)
- goto gotr;
+ goto next1;
}
+ sg = dequeue(&c->sendq, c);
+ if(sg != nil)
+ goto gotr;
+ next1:
o += p;
if(o >= sel->ncase)
o -= sel->ncase;
@@ -631,16 +634,17 @@
sg = allocsg(c);
sg->offset = o;
enqueue(&c->sendq, sg);
- } else {
- if(c->qcount > 0) {
- prints("selectgo: pass 2 async recv\n");
- goto asynr;
- }
- sg = allocsg(c);
- sg->offset = o;
- enqueue(&c->recvq, sg);
+ goto next2;
}
- } else
+ if(c->qcount > 0) {
+ prints("selectgo: pass 2 async recv\n");
+ goto asynr;
+ }
+ sg = allocsg(c);
+ sg->offset = o;
+ enqueue(&c->recvq, sg);
+ goto next2;
+ }
if(cas->send) {
sg = dequeue(&c->recvq, c);
@@ -653,18 +657,19 @@
sg->offset = o;
c->elemalg->copy(c->elemsize, sg->elem, cas->u.elem);
enqueue(&c->sendq, sg);
- } else {
- sg = dequeue(&c->sendq, c);
- if(sg != nil) {
- prints("selectgo: pass 2 sync recv\n");
- g->selgen++;
- goto gotr;
- }
- sg = allocsg(c);
- sg->offset = o;
- enqueue(&c->recvq, sg);
+ goto next2;
}
+ sg = dequeue(&c->sendq, c);
+ if(sg != nil) {
+ prints("selectgo: pass 2 sync recv\n");
+ g->selgen++;
+ goto gotr;
+ }
+ sg = allocsg(c);
+ sg->offset = o;
+ enqueue(&c->recvq, sg);
+ next2:
o += p;
if(o >= sel->ncase)
o -= sel->ncase;
changeset: 1306:b482984bfd47
user: Russ Cox <[email protected]>
date: Tue Dec 09 16:16:07 2008 -0800
summary: chans and maps of interfaces
diff -r ce4a3dca9a17 -r b482984bfd47 src/runtime/chan.c
--- a/src/runtime/chan.c Tue Dec 09 15:41:21 2008 -0800
+++ b/src/runtime/chan.c Tue Dec 09 16:16:07 2008 -0800
@@ -17,10 +17,10 @@
struct SudoG
{
G* g; // g and selgen constitute
- byte elem[8]; // synch data element
int16 offset; // offset of case number
int32 selgen; // a weak pointer to g
SudoG* link;
+ byte elem[8]; // synch data element (+ more)
};
struct WaitQ
@@ -45,7 +45,7 @@
struct Link
{
Link* link; // asynch queue circular linked list
- byte elem[8]; // asynch queue data element
+ byte elem[8]; // asynch queue data element (+ more)
};
struct Scase
@@ -65,7 +65,7 @@
uint16 tcase; // total count of scase[]
uint16 ncase; // currently filled scase[]
Select* link; // for freelist
- Scase scase[1]; // one per case
+ Scase* scase[1]; // one per case
};
static Select* selfree[20];
@@ -108,7 +108,7 @@
b = nil;
e = nil;
for(i=0; i<hint; i++) {
- d = mal(sizeof(*d));
+ d = mal(sizeof(*d) + c->elemsize - sizeof(d->elem));
if(e == nil)
e = d;
d->link = b;
@@ -430,7 +430,11 @@
if(i >= sel->tcase)
throw("selectsend: too many cases");
sel->ncase = i+1;
- cas = &sel->scase[i];
+ cas = sel->scase[i];
+ if(cas == nil) {
+ cas = mal(sizeof *cas + c->elemsize - sizeof(cas->u.elem));
+ sel->scase[i] = cas;
+ }
cas->pc = sys·getcallerpc(&sel);
cas->chan = c;
@@ -473,8 +477,11 @@
if(i >= sel->tcase)
throw("selectrecv: too many cases");
sel->ncase = i+1;
- cas = &sel->scase[i];
-
+ cas = sel->scase[i];
+ if(cas == nil) {
+ cas = mal(sizeof *cas);
+ sel->scase[i] = cas;
+ }
cas->pc = sys·getcallerpc(&sel);
cas->chan = c;
@@ -506,13 +513,16 @@
{
int32 i;
Scase *cas;
-
+
i = sel->ncase;
if(i >= sel->tcase)
throw("selectdefault: too many cases");
sel->ncase = i+1;
- cas = &sel->scase[i];
-
+ cas = sel->scase[i];
+ if(cas == nil) {
+ cas = mal(sizeof *cas);
+ sel->scase[i] = cas;
+ }
cas->pc = sys·getcallerpc(&sel);
cas->chan = nil;
@@ -579,7 +589,7 @@
// pass 1 - look for something already waiting
dfl = nil;
for(i=0; i<sel->ncase; i++) {
- cas = &sel->scase[o];
+ cas = sel->scase[o];
if(cas->send == 2) { // default
dfl = cas;
@@ -613,16 +623,16 @@
if(o >= sel->ncase)
o -= sel->ncase;
}
-
+
if(dfl != nil) {
cas = dfl;
goto retc;
}
-
+
// pass 2 - enqueue on all chans
for(i=0; i<sel->ncase; i++) {
- cas = &sel->scase[o];
+ cas = sel->scase[o];
c = cas->chan;
if(c->dataqsiz > 0) {
@@ -682,7 +692,7 @@
lock(&chanlock);
sg = g->param;
o = sg->offset;
- cas = &sel->scase[o];
+ cas = sel->scase[o];
c = cas->chan;
if(xxx) {
@@ -832,7 +842,7 @@
if(sg != nil) {
c->free = sg->link;
} else
- sg = mal(sizeof(*sg));
+ sg = mal(sizeof(*sg) + c->elemsize - sizeof(sg->elem));
sg->selgen = g->selgen;
sg->g = g;
sg->offset = 0;
diff -r ce4a3dca9a17 -r b482984bfd47 src/runtime/hashmap.c
--- a/src/runtime/hashmap.c Tue Dec 09 15:41:21 2008 -0800
+++ b/src/runtime/hashmap.c Tue Dec 09 16:16:07 2008 -0800
@@ -8,6 +8,7 @@
/* Return a pointer to the struct/union of type "type"
whose "field" field is addressed by pointer "p". */
+
struct hash { /* a hash table; initialize with hash_init() */
uint32 count; /* elements in table - must be first */
@@ -291,7 +292,7 @@
int32 shift = HASH_BITS - (st->power + used);
int32 index_mask = (1 << st->power) - 1;
int32 i = (hash >> shift) & index_mask; /* i is the natural position of hash */
-
+
e = HASH_OFFSET (st->entry, i * elemsize); /* e points to element i */
e_hash = e->hash;
if ((e_hash & HASH_MASK) != HASH_SUBHASH) { /* a subtable */
@@ -332,7 +333,7 @@
int32 shift = HASH_BITS - (st->power + used);
int32 index_mask = (1 << st->power) - 1;
int32 i = (hash >> shift) & index_mask; /* i is the natural position of hash */
-
+
e = HASH_OFFSET (st->entry, i * elemsize); /* e points to element i */
e_hash = e->hash;
if ((e_hash & HASH_MASK) != HASH_SUBHASH) { /* a subtable */
@@ -378,7 +379,7 @@
struct hash_entry *e = start_e; /* e is going to range over [start_e, end_e) */
struct hash_entry *end_e;
hash_hash_t e_hash = e->hash;
-
+
if ((e_hash & HASH_MASK) == HASH_SUBHASH) { /* a subtable */
pst = (struct hash_subtable **) e->data;
flags += HASH_MAKE_USED (st->power);
@@ -662,8 +663,8 @@
{
Hmap *h;
- if(keyalg >= 3 ||
- valalg >= 3) {
+ if(keyalg >= 4 ||
+ valalg >= 4) {
prints("0<=");
sys·printint(keyalg);
prints("<");
diff -r ce4a3dca9a17 -r b482984bfd47 src/runtime/runtime.c
--- a/src/runtime/runtime.c Tue Dec 09 15:41:21 2008 -0800
+++ b/src/runtime/runtime.c Tue Dec 09 16:16:07 2008 -0800
@@ -644,11 +644,12 @@
}
Alg
-algarray[3] =
+algarray[4] =
{
{ memhash, memequal, memprint, memcopy }, // 0
{ stringhash, stringequal, stringprint, stringcopy }, // 1
// { pointerhash, pointerequal, pointerprint, pointercopy }, // 2
{ memhash, memequal, memprint, memcopy }, // 2 - treat pointers as ints
+ { memhash, memequal, memprint, memcopy }, // 3 - treat interfaces as memory
};
diff -r ce4a3dca9a17 -r b482984bfd47 src/runtime/runtime.h
--- a/src/runtime/runtime.h Tue Dec 09 15:41:21 2008 -0800
+++ b/src/runtime/runtime.h Tue Dec 09 16:16:07 2008 -0800
@@ -220,7 +220,7 @@
/*
* external data
*/
-extern Alg algarray[3];
+extern Alg algarray[4];
extern string emptystring;
G* allg;
int32 goidgen;
diff -r ce4a3dca9a17 -r b482984bfd47 test/chan/powser2.go
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/chan/powser2.go Tue Dec 09 16:16:07 2008 -0800
@@ -0,0 +1,720 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 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.
+
+// Power series package
+// A power series is a channel, along which flow rational
+// coefficients. A denominator of zero signifies the end.
+// Original code in Newsqueak by Doug McIlroy.
+// See Squinting at Power Series by Doug McIlroy,
+// http://www.cs.bell-labs.com/who/rsc/thread/squint.pdf
+// Like powser1.go but uses channels of interfaces.
+
+package main
+
+type rat struct {
+ num, den int64; // numerator, denominator
+}
+
+type item interface {
+ pr();
+ eq(c item) bool;
+}
+
+func (u *rat) pr(){
+ if u.den==1 { print(u.num) }
+ else { print(u.num, "/", u.den) }
+ print(" ")
+}
+
+func (u *rat) eq(c item) bool {
+ c1 := c.(*rat);
+ return u.num == c1.num && u.den == c1.den
+}
+
+type dch struct {
+ req *chan int;
+ dat *chan item;
+ nam int;
+}
+
+type dch2 [2] *dch
+
+var chnames string
+var chnameserial int
+var seqno int
+
+func Init();
+
+func mkdch() *dch {
+ c := chnameserial % len(chnames);
+ chnameserial++;
+ d := new(dch);
+ d.req = new(chan int);
+ d.dat = new(chan item);
+ d.nam = c;
+ return d;
+}
+
+func mkdch2() *dch2 {
+ d2 := new(dch2);
+ d2[0] = mkdch();
+ d2[1] = mkdch();
+ return d2;
+}
+
+// split reads a single demand channel and replicates its
+// output onto two, which may be read at different rates.
+// A process is created at first demand for an item and dies
+// after the item has been sent to both outputs.
+
+// When multiple generations of split exist, the newest
+// will service requests on one channel, which is
+// always renamed to be out[0]; the oldest will service
+// requests on the other channel, out[1]. All generations but the
+// newest hold queued data that has already been sent to
+// out[0]. When data has finally been sent to out[1],
+// a signal on the release-wait channel tells the next newer
+// generation to begin servicing out[1].
+
+func dosplit(in *dch, out *dch2, wait *chan int ){
+ var t *dch;
+ both := false; // do not service both channels
+
+ select {
+ case <-out[0].req:
+ ;
+ case <-wait:
+ both = true;
+ select {
+ case <-out[0].req:
+ ;
+ case <-out[1].req:
+ t=out[0]; out[0]=out[1]; out[1]=t;
+ }
+ }
+
+ seqno++;
+ in.req <- seqno;
+ release := new(chan int);
+ go dosplit(in, out, release);
+ dat := <-in.dat;
+ out[0].dat <- dat;
+ if !both {
+ <-wait
+ }
+ <-out[1].req;
+ out[1].dat <- dat;
+ release <- 0;
+}
+
+func split(in *dch, out *dch2){
+ release := new(chan int);
+ go dosplit(in, out, release);
+ release <- 0;
+}
+
+func put(dat item, out *dch){
+ <-out.req;
+ out.dat <- dat;
+}
+
+func get(in *dch) *rat {
+ seqno++;
+ in.req <- seqno;
+ return <-in.dat;
+}
+
+// Get one item from each of n demand channels
+
+func getn(in *[]*dch, n int) *[]item {
+ // BUG n:=len(in);
+ if n != 2 { panic("bad n in getn") };
+ req := new([2] *chan int);
+ dat := new([2] *chan item);
+ out := new([2] item);
+ var i int;
+ var it item;
+ for i=0; i<n; i++ {
+ req[i] = in[i].req;
+ dat[i] = nil;
+ }
+ for n=2*n; n>0; n-- {
+ seqno++;
+
+ select{
+ case req[0] <- seqno:
+ dat[0] = in[0].dat;
+ req[0] = nil;
+ case req[1] <- seqno:
+ dat[1] = in[1].dat;
+ req[1] = nil;
+ case it = <-dat[0]:
+ out[0] = it;
+ dat[0] = nil;
+ case it = <-dat[1]:
+ out[1] = it;
+ dat[1] = nil;
+ }
+ }
+ return out;
+}
+
+// Get one item from each of 2 demand channels
+
+func get2(in0 *dch, in1 *dch) *[]item {
+ x := new([2] *dch);
+ x[0] = in0;
+ x[1] = in1;
+ return getn(x, 2);
+}
+
+func copy(in *dch, out *dch){
+ for {
+ <-out.req;
+ out.dat <- get(in);
+ }
+}
+
+func repeat(dat item, out *dch){
+ for {
+ put(dat, out)
+ }
+}
+
+type PS *dch; // power series
+type PS2 *[2] PS; // pair of power series
+
+var Ones PS
+var Twos PS
+
+func mkPS() *dch {
+ return mkdch()
+}
+
+func mkPS2() *dch2 {
+ return mkdch2()
+}
+
+// Conventions
+// Upper-case for power series.
+// Lower-case for rationals.
+// Input variables: U,V,...
+// Output variables: ...,Y,Z
+
+// Integer gcd; needed for rational arithmetic
+
+func gcd (u, v int64) int64{
+ if u < 0 { return gcd(-u, v) }
+ if u == 0 { return v }
+ return gcd(v%u, u)
+}
+
+// Make a rational from two ints and from one int
+
+func i2tor(u, v int64) *rat{
+ g := gcd(u,v);
+ r := new(rat);
+ if v > 0 {
+ r.num = u/g;
+ r.den = v/g;
+ } else {
+ r.num = -u/g;
+ r.den = -v/g;
+ }
+ return r;
+}
+
+func itor(u int64) *rat{
+ return i2tor(u, 1);
+}
+
+var zero *rat;
+var one *rat;
+
+
+// End mark and end test
+
+var finis *rat;
+
+func end(u *rat) int64 {
+ if u.den==0 { return 1 }
+ return 0
+}
+
+// Operations on rationals
+
+func add(u, v *rat) *rat {
+ g := gcd(u.den,v.den);
+ return i2tor(u.num*(v.den/g)+v.num*(u.den/g),u.den*(v.den/g));
+}
+
+func mul(u, v *rat) *rat{
+ g1 := gcd(u.num,v.den);
+ g2 := gcd(u.den,v.num);
+ r := new(rat);
+ r.num =(u.num/g1)*(v.num/g2);
+ r.den = (u.den/g2)*(v.den/g1);
+ return r;
+}
+
+func neg(u *rat) *rat{
+ return i2tor(-u.num, u.den);
+}
+
+func sub(u, v *rat) *rat{
+ return add(u, neg(v));
+}
+
+func inv(u *rat) *rat{ // invert a rat
+ if u.num == 0 { panic("zero divide in inv") }
+ return i2tor(u.den, u.num);
+}
+
+// print eval in floating point of PS at x=c to n terms
+func
+Evaln(c *rat, U PS, n int)
+{
+ xn := float64(1);
+ x := float64(c.num)/float64(c.den);
+ val := float64(0);
+ for i:=0; i<n; i++ {
+ u := get(U);
+ if end(u) != 0 {
+ break;
+ }
+ val = val + x * float64(u.num)/float64(u.den);
+ xn = xn*x;
+ }
+ print(val, "\n");
+}
+
+// Print n terms of a power series
+func Printn(U PS, n int){
+ done := false;
+ for ; !done && n>0; n-- {
+ u := get(U);
+ if end(u) != 0 { done = true }
+ else { u.pr() }
+ }
+ print(("\n"));
+}
+
+func Print(U PS){
+ Printn(U,1000000000);
+}
+
+// Evaluate n terms of power series U at x=c
+func eval(c *rat, U PS, n int) *rat{
+ if n==0 { return zero }
+ y := get(U);
+ if end(y) != 0 { return zero }
+ return add(y,mul(c,eval(c,U,n-1)));
+}
+
+// Power-series constructors return channels on which power
+// series flow. They start an encapsulated generator that
+// puts the terms of the series on the channel.
+
+// Make a pair of power series identical to a given power series
+
+func Split(U PS) *dch2{
+ UU := mkdch2();
+ go split(U,UU);
+ return UU;
+}
+
+// Add two power series
+func Add(U, V PS) PS{
+ Z := mkPS();
+ go func(U, V, Z PS){
+ var uv *[] item;
+ for {
+ <-Z.req;
+ uv = get2(U,V);
+ switch end(uv[0])+2*end(uv[1]) {
+ case 0:
+ Z.dat <- add(uv[0], uv[1]);
+ case 1:
+ Z.dat <- uv[1];
+ copy(V,Z);
+ case 2:
+ Z.dat <- uv[0];
+ copy(U,Z);
+ case 3:
+ Z.dat <- finis;
+ }
+ }
+ }(U, V, Z);
+ return Z;
+}
+
+// Multiply a power series by a constant
+func Cmul(c *rat,U PS) PS{
+ Z := mkPS();
+ go func(c *rat, U, Z PS){
+ done := false;
+ for !done {
+ <-Z.req;
+ u := get(U);
+ if end(u) != 0 { done = true }
+ else { Z.dat <- mul(c,u) }
+ }
+ Z.dat <- finis;
+ }(c, U, Z);
+ return Z;
+}
+
+// Subtract
+
+func Sub(U, V PS) PS{
+ return Add(U, Cmul(neg(one), V));
+}
+
+// Multiply a power series by the monomial x^n
+
+func Monmul(U PS, n int) PS{
+ Z := mkPS();
+ go func(n int, U PS, Z PS){
+ for ; n>0; n-- { put(zero,Z) }
+ copy(U,Z);
+ }(n, U, Z);
+ return Z;
+}
+
+// Multiply by x
+
+func Xmul(U PS) PS{
+ return Monmul(U,1);
+}
+
+func Rep(c *rat) PS{
+ Z := mkPS();
+ go repeat(c,Z);
+ return Z;
+}
+
+// Monomial c*x^n
+
+func Mon(c *rat, n int) PS{
+ Z:=mkPS();
+ go func(c *rat, n int, Z PS){
+ if(c.num!=0) {
+ for ; n>0; n=n-1 { put(zero,Z) }
+ put(c,Z);
+ }
+ put(finis,Z);
+ }(c, n, Z);
+ return Z;
+}
+
+func Shift(c *rat, U PS) PS{
+ Z := mkPS();
+ go func(c *rat, U, Z PS){
+ put(c,Z);
+ copy(U,Z);
+ }(c, U, Z);
+ return Z;
+}
+
+// simple pole at 1: 1/(1-x) = 1 1 1 1 1 ...
+
+// Convert array of coefficients, constant term first
+// to a (finite) power series
+
+/* BUG: NEED LEN OF ARRAY
+func Poly(a [] *rat) PS{
+ Z:=mkPS();
+ begin func(a [] *rat, Z PS){
+ j:=0;
+ done:=0;
+ for j=len(a); !done&&j>0; j=j-1)
+ if(a[j-1].num!=0) done=1;
+ i:=0;
+ for(; i<j; i=i+1) put(a[i],Z);
+ put(finis,Z);
+ }();
+ return Z;
+}
+*/
+
+// Multiply. The algorithm is
+// let U = u + x*UU
+// let V = v + x*VV
+// then UV = u*v + x*(u*VV+v*UU) + x*x*UU*VV
+
+func Mul(U, V PS) PS{
+ Z:=mkPS();
+ go func(U, V, Z PS){
+ <-Z.req;
+ uv := get2(U,V);
+ if end(uv[0])!=0 || end(uv[1]) != 0 {
+ Z.dat <- finis;
+ } else {
+ Z.dat <- mul(uv[0],uv[1]);
+ UU := Split(U);
+ VV := Split(V);
+ W := Add(Cmul(uv[0],VV[0]),Cmul(uv[1],UU[0]));
+ <-Z.req;
+ Z.dat <- get(W);
+ copy(Add(W,Mul(UU[1],VV[1])),Z);
+ }
+ }(U, V, Z);
+ return Z;
+}
+
+// Differentiate
+
+func Diff(U PS) PS{
+ Z:=mkPS();
+ go func(U, Z PS){
+ <-Z.req;
+ u := get(U);
+ if end(u) == 0 {
+ done:=false;
+ for i:=1; !done; i++ {
+ u = get(U);
+ if end(u) != 0 { done=true }
+ else {
+ Z.dat <- mul(itor(int64(i)),u);
+ <-Z.req;
+ }
+ }
+ }
+ Z.dat <- finis;
+ }(U, Z);
+ return Z;
+}
+
+// Integrate, with const of integration
+func Integ(c *rat,U PS) PS{
+ Z:=mkPS();
+ go func(c *rat, U, Z PS){
+ put(c,Z);
+ done:=false;
+ for i:=1; !done; i++ {
+ <-Z.req;
+ u := get(U);
+ if end(u) != 0 { done= true }
+ Z.dat <- mul(i2tor(1,int64(i)),u);
+ }
+ Z.dat <- finis;
+ }(c, U, Z);
+ return Z;
+}
+
+// Binomial theorem (1+x)^c
+
+func Binom(c *rat) PS{
+ Z:=mkPS();
+ go func(c *rat, Z PS){
+ n := 1;
+ t := itor(1);
+ for c.num!=0 {
+ put(t,Z);
+ t = mul(mul(t,c),i2tor(1,int64(n)));
+ c = sub(c,one);
+ n++;
+ }
+ put(finis,Z);
+ }(c, Z);
+ return Z;
+}
+
+// Reciprocal of a power series
+// let U = u + x*UU
+// let Z = z + x*ZZ
+// (u+x*UU)*(z+x*ZZ) = 1
+// z = 1/u
+// u*ZZ + z*UU +x*UU*ZZ = 0
+// ZZ = -UU*(z+x*ZZ)/u;
+
+func Recip(U PS) PS{
+ Z:=mkPS();
+ go func(U, Z PS){
+ ZZ:=mkPS2();
+ <-Z.req;
+ z := inv(get(U));
+ Z.dat <- z;
+ split(Mul(Cmul(neg(z),U),Shift(z,ZZ[0])),ZZ);
+ copy(ZZ[1],Z);
+ }(U, Z);
+ return Z;
+}
+
+// Exponential of a power series with constant term 0
+// (nonzero constant term would make nonrational coefficients)
+// bug: the constant term is simply ignored
+// Z = exp(U)
+// DZ = Z*DU
+// integrate to get Z
+
+func Exp(U PS) PS{
+ ZZ := mkPS2();
+ split(Integ(one,Mul(ZZ[0],Diff(U))),ZZ);
+ return ZZ[1];
+}
+
+// Substitute V for x in U, where the leading term of V is zero
+// let U = u + x*UU
+// let V = v + x*VV
+// then S(U,V) = u + VV*S(V,UU)
+// bug: a nonzero constant term is ignored
+
+func Subst(U, V PS) PS {
+ Z:= mkPS();
+ go func(U, V, Z PS) {
+ VV := Split(V);
+ <-Z.req;
+ u := get(U);
+ Z.dat <- u;
+ if end(u) == 0 {
+ if end(get(VV[0])) != 0 { put(finis,Z); }
+ else { copy(Mul(VV[0],Subst(U,VV[1])),Z); }
+ }
+ }(U, V, Z);
+ return Z;
+}
+
+// Monomial Substition: U(c x^n)
+// Each Ui is multiplied by c^i and followed by n-1 zeros
+
+func MonSubst(U PS, c0 *rat, n int) PS {
+ Z:= mkPS();
+ go func(U, Z PS, c0 *rat, n int) {
+ c := one;
+ for {
+ <-Z.req;
+ u := get(U);
+ Z.dat <- mul(u, c);
+ c = mul(c, c0);
+ if end(u) != 0 {
+ Z.dat <- finis;
+ break;
+ }
+ for i := 1; i < n; i++ {
+ <-Z.req;
+ Z.dat <- zero;
+ }
+ }
+ }(U, Z, c0, n);
+ return Z;
+}
+
+
+func Init() {
+ chnameserial = -1;
+ seqno = 0;
+ chnames = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+ zero = itor(0);
+ one = itor(1);
+ finis = i2tor(1,0);
+ Ones = Rep(one);
+ Twos = Rep(itor(2));
+}
+
+func check(U PS, c *rat, count int, str string) {
+ for i := 0; i < count; i++ {
+ r := get(U);
+ if !r.eq(c) {
+ print("got: ");
+ r.pr();
+ print("should get ");
+ c.pr();
+ print("\n");
+ panic(str)
+ }
+ }
+}
+
+const N=10
+func checka(U PS, a *[]*rat, str string) {
+ for i := 0; i < N; i++ {
+ check(U, a[i], 1, str);
+ }
+}
+
+func main() {
+ Init();
+ if sys.argc() > 1 { // print
+ print("Ones: "); Printn(Ones, 10);
+ print("Twos: "); Printn(Twos, 10);
+ print("Add: "); Printn(Add(Ones, Twos), 10);
+ print("Diff: "); Printn(Diff(Ones), 10);
+ print("Integ: "); Printn(Integ(zero, Ones), 10);
+ print("CMul: "); Printn(Cmul(neg(one), Ones), 10);
+ print("Sub: "); Printn(Sub(Ones, Twos), 10);
+ print("Mul: "); Printn(Mul(Ones, Ones), 10);
+ print("Exp: "); Printn(Exp(Ones), 15);
+ print("MonSubst: "); Printn(MonSubst(Ones, neg(one), 2), 10);
+ print("ATan: "); Printn(Integ(zero, MonSubst(Ones, neg(one), 2)), 10);
+ } else { // test
+ check(Ones, one, 5, "Ones");
+ check(Add(Ones, Ones), itor(2), 0, "Add Ones Ones"); // 1 1 1 1 1
+ check(Add(Ones, Twos), itor(3), 0, "Add Ones Twos"); // 3 3 3 3 3
+ a := new([N] *rat);
+ d := Diff(Ones);
+ // BUG: want array initializer
+ for i:=0; i < N; i++ {
+ a[i] = itor(int64(i+1))
+ }
+ checka(d, a, "Diff"); // 1 2 3 4 5
+ in := Integ(zero, Ones);
+ // BUG: want array initializer
+ a[0] = zero; // integration constant
+ for i:=1; i < N; i++ {
+ a[i] = i2tor(1, int64(i))
+ }
+ checka(in, a, "Integ"); // 0 1 1/2 1/3 1/4 1/5
+ check(Cmul(neg(one), Twos), itor(-2), 10, "CMul"); // -1 -1 -1 -1 -1
+ check(Sub(Ones, Twos), itor(-1), 0, "Sub Ones Twos"); // -1 -1 -1 -1 -1
+ m := Mul(Ones, Ones);
+ // BUG: want array initializer
+ for i:=0; i < N; i++ {
+ a[i] = itor(int64(i+1))
+ }
+ checka(m, a, "Mul"); // 1 2 3 4 5
+ e := Exp(Ones);
+ // BUG: want array initializer
+ a[0] = itor(1);
+ a[1] = itor(1);
+ a[2] = i2tor(3,2);
+ a[3] = i2tor(13,6);
+ a[4] = i2tor(73,24);
+ a[5] = i2tor(167,40);
+ a[6] = i2tor(4051,720);
+ a[7] = i2tor(37633,5040);
+ a[8] = i2tor(43817,4480);
+ a[9] = i2tor(4596553,362880);
+ checka(e, a, "Exp"); // 1 1 3/2 13/6 73/24
+ at := Integ(zero, MonSubst(Ones, neg(one), 2));
+ // BUG: want array initializer
+ for c, i := 1, 0; i < N; i++ {
+ if i%2 == 0 {
+ a[i] = zero
+ } else {
+ a[i] = i2tor(int64(c), int64(i));
+ c *= -1
+ }
+ }
+ checka(at, a, "ATan"); // 0 -1 0 -1/3 0 -1/5
+/*
+ t := Revert(Integ(zero, MonSubst(Ones, neg(one), 2)));
+ // BUG: want array initializer
+ a[0] = zero;
+ a[1] = itor(1);
+ a[2] = zero;
+ a[3] = i2tor(1,3);
+ a[4] = zero;
+ a[5] = i2tor(2,15);
+ a[6] = zero;
+ a[7] = i2tor(17,315);
+ a[8] = zero;
+ a[9] = i2tor(62,2835);
+ checka(t, a, "Tan"); // 0 1 0 1/3 0 2/15
+*/
+ }
+ sys.exit(0); // BUG: force waiting goroutines to exit
+}
changeset: 1380:8b65ea265a95
user: Russ Cox <[email protected]>
date: Fri Dec 19 12:05:22 2008 -0800
summary: chan and map of [] and struct
diff -r adfbb1eb062d -r 8b65ea265a95 src/cmd/gc/go.h
--- a/src/cmd/gc/go.h Fri Dec 19 09:03:44 2008 -0800
+++ b/src/cmd/gc/go.h Fri Dec 19 12:05:22 2008 -0800
@@ -41,6 +41,8 @@
ASTRING,
APTR,
AINTER,
+ AARRAY,
+ ASTRUCT,
BADWIDTH = -1000000000
};
diff -r adfbb1eb062d -r 8b65ea265a95 src/cmd/gc/subr.c
--- a/src/cmd/gc/subr.c Fri Dec 19 09:03:44 2008 -0800
+++ b/src/cmd/gc/subr.c Fri Dec 19 12:05:22 2008 -0800
@@ -301,6 +301,12 @@
if(isptr[t->etype])
a = APTR; // pointer
else
+ if(t->etype == TARRAY)
+ a = AARRAY;
+ else
+ if(t->etype == TSTRUCT)
+ a = ASTRUCT;
+ else
if(isinter(t))
a = AINTER; // interface
// else
diff -r adfbb1eb062d -r 8b65ea265a95 src/runtime/chan.c
--- a/src/runtime/chan.c Fri Dec 19 09:03:44 2008 -0800
+++ b/src/runtime/chan.c Fri Dec 19 12:05:22 2008 -0800
@@ -86,14 +86,17 @@
Hchan *c;
int32 i;
- if(elemalg >= nelem(algarray)) {
- prints("0<=");
- sys·printint(elemalg);
- prints("<");
- sys·printint(nelem(algarray));
- prints("\n");
-
- throw("sys·newchan: elem algorithm out of range");
+ switch(elemalg){
+ case ASIMP:
+ case ASTRING:
+ case APTR:
+ case AINTER:
+ case AARRAY:
+ case ASTRUCT:
+ break;
+ default:
+ printf("chan(alg=%d)\n", elemalg);
+ throw("sys·newchan: unsupported channel element type");
}
c = mal(sizeof(*c));
diff -r adfbb1eb062d -r 8b65ea265a95 src/runtime/hashmap.c
--- a/src/runtime/hashmap.c Fri Dec 19 09:03:44 2008 -0800
+++ b/src/runtime/hashmap.c Fri Dec 19 12:05:22 2008 -0800
@@ -663,19 +663,30 @@
{
Hmap *h;
- if(keyalg >= 4 ||
- valalg >= 4) {
- prints("0<=");
- sys·printint(keyalg);
- prints("<");
- sys·printint(nelem(algarray));
- prints("\n0<=");
- sys·printint(valalg);
- prints("<");
- sys·printint(nelem(algarray));
- prints("\n");
+ switch(keyalg) {
+ case ASIMP:
+ case ASTRING:
+ case APTR:
+ case AINTER:
+ case AARRAY:
+ case ASTRUCT:
+ break;
+ default:
+ printf("map(keyalg=%d)\n", keyalg);
+ throw("sys·newmap: unsupported map key type");
+ }
- throw("sys·newmap: key/val algorithm out of range");
+ switch(valalg) {
+ case ASIMP:
+ case ASTRING:
+ case APTR:
+ case AINTER:
+ case AARRAY:
+ case ASTRUCT:
+ break;
+ default:
+ printf("map(valalg=%d)\n", valalg);
+ throw("sys·newmap: unsupported map value type");
}
h = mal(sizeof(*h));
diff -r adfbb1eb062d -r 8b65ea265a95 src/runtime/iface.c
--- a/src/runtime/iface.c Fri Dec 19 09:03:44 2008 -0800
+++ b/src/runtime/iface.c Fri Dec 19 12:05:22 2008 -0800
@@ -6,18 +6,13 @@
static int32 debug = 0;
-enum
-{
- ASIMP = 0,
- ASTRING,
- APTR,
- AINTER,
-};
-
typedef struct Sigt Sigt;
typedef struct Sigi Sigi;
typedef struct Map Map;
+/*
+ * the layout of Sigt and Sigi are known to the compiler
+ */
struct Sigt
{
byte* name;
diff -r adfbb1eb062d -r 8b65ea265a95 src/runtime/runtime.c
--- a/src/runtime/runtime.c Fri Dec 19 09:03:44 2008 -0800
+++ b/src/runtime/runtime.c Fri Dec 19 12:05:22 2008 -0800
@@ -580,7 +580,7 @@
}
static uint64
-stringhash(uint32 s, string *a)
+strhash(uint32 s, string *a)
{
USED(s);
if(*a == nil)
@@ -589,21 +589,21 @@
}
static uint32
-stringequal(uint32 s, string *a, string *b)
+strequal(uint32 s, string *a, string *b)
{
USED(s);
return cmpstring(*a, *b) == 0;
}
static void
-stringprint(uint32 s, string *a)
+strprint(uint32 s, string *a)
{
USED(s);
sys·printstring(*a);
}
static void
-stringcopy(uint32 s, string *a, string *b)
+strcopy(uint32 s, string *a, string *b)
{
USED(s);
if(b == nil) {
@@ -614,28 +614,28 @@
}
static uint64
-pointerhash(uint32 s, void **a)
+ptrhash(uint32 s, void **a)
{
return memhash(s, *a);
}
static uint32
-pointerequal(uint32 s, void **a, void **b)
+ptrequal(uint32 s, void **a, void **b)
{
USED(s, a, b);
- prints("pointerequal\n");
+ prints("ptrequal\n");
return 0;
}
static void
-pointerprint(uint32 s, void **a)
+ptrprint(uint32 s, void **a)
{
USED(s, a);
- prints("pointerprint\n");
+ prints("ptrprint\n");
}
static void
-pointercopy(uint32 s, void **a, void **b)
+ptrcopy(uint32 s, void **a, void **b)
{
USED(s);
if(b == nil) {
@@ -646,12 +646,13 @@
}
Alg
-algarray[4] =
+algarray[] =
{
- { memhash, memequal, memprint, memcopy }, // 0
- { stringhash, stringequal, stringprint, stringcopy }, // 1
-// { pointerhash, pointerequal, pointerprint, pointercopy }, // 2
- { memhash, memequal, memprint, memcopy }, // 2 - treat pointers as ints
- { memhash, memequal, memprint, memcopy }, // 3 - treat interfaces as memory
+[ASIMP] { memhash, memequal, memprint, memcopy },
+[ASTRING] { strhash, strequal, strprint, strcopy },
+[APTR] { memhash, memequal, memprint, memcopy }, // TODO: ptr routines
+[AINTER] { memhash, memequal, memprint, memcopy }, // TODO: interface routines
+[ASTRUCT] { memhash, memequal, memprint, memcopy }, // TODO: what goes here?
+[AARRAY] { memhash, memequal, memprint, memcopy }, // TODO: what goes here?
};
diff -r adfbb1eb062d -r 8b65ea265a95 src/runtime/runtime.h
--- a/src/runtime/runtime.h Fri Dec 19 09:03:44 2008 -0800
+++ b/src/runtime/runtime.h Fri Dec 19 12:05:22 2008 -0800
@@ -215,9 +215,22 @@
#define nil ((void*)0)
/*
+ * known to compiler
+ */
+enum
+{
+ ASIMP = 0,
+ ASTRING,
+ APTR,
+ AINTER,
+ AARRAY,
+ ASTRUCT,
+};
+
+/*
* external data
*/
-extern Alg algarray[4];
+extern Alg algarray[];
extern string emptystring;
G* allg;
int32 goidgen;
diff -r adfbb1eb062d -r 8b65ea265a95 test/bigalg.go
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/bigalg.go Fri Dec 19 12:05:22 2008 -0800
@@ -0,0 +1,110 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 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 main
+
+import (
+ "os";
+ "fmt";
+)
+
+type T struct {
+ a float64;
+ b int64;
+ c string;
+ d byte;
+}
+
+var a = []int{ 1, 2, 3 }
+var NIL []int;
+
+func arraycmptest() {
+ a1 := a;
+ if NIL != nil {
+ println("fail1:", NIL, "!= nil");
+ }
+ if nil != NIL {
+ println("fail2: nil !=", NIL);
+ }
+ if a == nil || nil == a {
+ println("fail3:", a, "== nil");
+ }
+ if a == NIL || NIL == a {
+ println("fail4:", a, "==", NIL);
+ }
+ if a != a {
+ println("fail5:", a, "!=", a);
+ }
+ if a1 != a {
+ println("fail6:", a1, "!=", a);
+ }
+}
+
+var t = T{1.5, 123, "hello", 255}
+var mt = new(map[int]T)
+var ma = new(map[int][]int)
+
+func maptest() {
+ mt[0] = t;
+ t1 := mt[0];
+ if t1.a != t.a || t1.b != t.b || t1.c != t.c || t1.d != t.d {
+ println("fail: map val struct", t1.a, t1.b, t1.c, t1.d);
+ }
+
+ ma[1] = a;
+ a1 := ma[1];
+ if a1 != a {
+ println("fail: map val array", a, a1);
+ }
+}
+
+var mt1 = new(map[T]int)
+var ma1 = new(map[[]int] int)
+
+func maptest2() {
+ mt1[t] = 123;
+ t1 := t;
+ val, ok := mt1[t1];
+ if val != 123 || !ok {
+ println("fail: map key struct", val, ok);
+ }
+
+ ma1[a] = 345;
+ a1 := a;
+ val, ok = ma1[a1];
+ if val != 345 || !ok {
+ panic("map key array", val, ok);
+ }
+}
+
+var ct = new(chan T)
+var ca = new(chan []int)
+
+func send() {
+ ct <- t;
+ ca <- a;
+}
+
+func chantest() {
+ go send();
+
+ t1 := <-ct;
+ if t1.a != t.a || t1.b != t.b || t1.c != t.c || t1.d != t.d {
+ println("fail: chan struct", t1.a, t1.b, t1.c, t1.d);
+ }
+
+ a1 := <-ca;
+ if a1 != a {
+ println("fail: chan array", a, a1);
+ }
+}
+
+func main() {
+ arraycmptest();
+ maptest();
+ maptest2();
+ chantest();
+}
changeset: 1512:5df06070216e
user: Russ Cox <[email protected]>
date: Fri Jan 16 14:58:14 2009 -0800
summary: casify, cleanup sys
diff -r 14731a6251fa -r 5df06070216e doc/progs/cat.go
--- a/doc/progs/cat.go Fri Jan 16 14:16:31 2009 -0800
+++ b/doc/progs/cat.go Fri Jan 16 14:58:14 2009 -0800
@@ -16,7 +16,7 @@
switch nr, er := file.Read(buf); true {
case nr < 0:
print("error reading from ", file.String(), ": ", er.String(), "\n");
- sys.exit(1);
+ sys.Exit(1);
case nr == 0: // EOF
return;
case nr > 0:
@@ -36,7 +36,7 @@
file, err := fd.Open(flag.Arg(i), 0, 0);
if file == nil {
print("can't open ", flag.Arg(i), ": error ", err, "\n");
- sys.exit(1);
+ sys.Exit(1);
}
cat(file);
file.Close();
diff -r 14731a6251fa -r 5df06070216e doc/progs/cat_rot13.go
--- a/doc/progs/cat_rot13.go Fri Jan 16 14:16:31 2009 -0800
+++ b/doc/progs/cat_rot13.go Fri Jan 16 14:58:14 2009 -0800
@@ -59,7 +59,7 @@
switch nr, er := r.Read(buf); {
case nr < 0:
print("error reading from ", r.String(), ": ", er.String(), "\n");
- sys.exit(1);
+ sys.Exit(1);
case nr == 0: // EOF
return;
case nr > 0:
@@ -80,7 +80,7 @@
file, err := fd.Open(flag.Arg(i), 0, 0);
if file == nil {
print("can't open ", flag.Arg(i), ": error ", err, "\n");
- sys.exit(1);
+ sys.Exit(1);
}
cat(file);
file.Close();
diff -r 14731a6251fa -r 5df06070216e doc/progs/helloworld3.go
--- a/doc/progs/helloworld3.go Fri Jan 16 14:16:31 2009 -0800
+++ b/doc/progs/helloworld3.go Fri Jan 16 14:58:14 2009 -0800
@@ -12,6 +12,6 @@
file, err := fd.Open("/does/not/exist", 0, 0);
if file == nil {
print("can't open file; err=", err.String(), "\n");
- sys.exit(1);
+ sys.Exit(1);
}
}
diff -r 14731a6251fa -r 5df06070216e src/cmd/gc/export.c
--- a/src/cmd/gc/export.c Fri Jan 16 14:16:31 2009 -0800
+++ b/src/cmd/gc/export.c Fri Jan 16 14:58:14 2009 -0800
@@ -355,7 +355,10 @@
static int
mypackage(Node *ss)
{
- return strcmp(ss->psym->name, package) == 0;
+ // we import all definitions for sys.
+ // lowercase ones can only be used by the compiler.
+ return strcmp(ss->psym->name, package) == 0
+ || strcmp(ss->psym->name, "sys") == 0;
}
void
diff -r 14731a6251fa -r 5df06070216e src/cmd/gc/sys.go
--- a/src/cmd/gc/sys.go Fri Jan 16 14:16:31 2009 -0800
+++ b/src/cmd/gc/sys.go Fri Jan 16 14:58:14 2009 -0800
@@ -7,102 +7,97 @@
// emitted by compiler, not referred to by go programs
-export func mal(int32) *any;
-export func throwindex();
-export func throwreturn();
-export func panicl(int32);
+func mal(int32) *any;
+func throwindex();
+func throwreturn();
+func panicl(int32);
-export func printbool(bool);
-export func printfloat(float64);
-export func printint(int64);
-export func printstring(string);
-export func printpointer(*any);
-export func printinter(any);
-export func printarray(any);
-export func printnl();
-export func printsp();
+func printbool(bool);
+func printfloat(float64);
+func printint(int64);
+func printstring(string);
+func printpointer(*any);
+func printinter(any);
+func printarray(any);
+func printnl();
+func printsp();
-export func catstring(string, string) string;
-export func cmpstring(string, string) int;
-export func slicestring(string, int, int) string;
-export func indexstring(string, int) byte;
-export func intstring(int64) string;
-export func byteastring(*byte, int) string;
-export func arraystring([]byte) string;
+func catstring(string, string) string;
+func cmpstring(string, string) int;
+func slicestring(string, int, int) string;
+func indexstring(string, int) byte;
+func intstring(int64) string;
+func byteastring(*byte, int) string;
+func arraystring([]byte) string;
-export func ifaceT2I(sigi *byte, sigt *byte, elem any) (ret any);
-export func ifaceI2T(sigt *byte, iface any) (ret any);
-export func ifaceI2T2(sigt *byte, iface any) (ret any, ok bool);
-export func ifaceI2I(sigi *byte, iface any) (ret any);
-export func ifaceI2I2(sigi *byte, iface any) (ret any, ok bool);
-export func ifaceeq(i1 any, i2 any) (ret bool);
+func ifaceT2I(sigi *byte, sigt *byte, elem any) (ret any);
+func ifaceI2T(sigt *byte, iface any) (ret any);
+func ifaceI2T2(sigt *byte, iface any) (ret any, ok bool);
+func ifaceI2I(sigi *byte, iface any) (ret any);
+func ifaceI2I2(sigi *byte, iface any) (ret any, ok bool);
+func ifaceeq(i1 any, i2 any) (ret bool);
-export func newmap(keysize int, valsize int,
+func newmap(keysize int, valsize int,
keyalg int, valalg int,
hint int) (hmap map[any]any);
-export func mapaccess1(hmap map[any]any, key any) (val any);
-export func mapaccess2(hmap map[any]any, key any) (val any, pres bool);
-export func mapassign1(hmap map[any]any, key any, val any);
-export func mapassign2(hmap map[any]any, key any, val any, pres bool);
-export func mapiterinit(hmap map[any]any, hiter *any);
-export func mapiternext(hiter *any);
-export func mapiter1(hiter *any) (key any);
-export func mapiter2(hiter *any) (key any, val any);
+func mapaccess1(hmap map[any]any, key any) (val any);
+func mapaccess2(hmap map[any]any, key any) (val any, pres bool);
+func mapassign1(hmap map[any]any, key any, val any);
+func mapassign2(hmap map[any]any, key any, val any, pres bool);
+func mapiterinit(hmap map[any]any, hiter *any);
+func mapiternext(hiter *any);
+func mapiter1(hiter *any) (key any);
+func mapiter2(hiter *any) (key any, val any);
-export func newchan(elemsize int, elemalg int, hint int) (hchan chan any);
-export func chanrecv1(hchan chan any) (elem any);
-export func chanrecv2(hchan chan any) (elem any, pres bool);
-export func chanrecv3(hchan chan any, elem *any) (pres bool);
-export func chansend1(hchan chan any, elem any);
-export func chansend2(hchan chan any, elem any) (pres bool);
+func newchan(elemsize int, elemalg int, hint int) (hchan chan any);
+func chanrecv1(hchan chan any) (elem any);
+func chanrecv2(hchan chan any) (elem any, pres bool);
+func chanrecv3(hchan chan any, elem *any) (pres bool);
+func chansend1(hchan chan any, elem any);
+func chansend2(hchan chan any, elem any) (pres bool);
-export func newselect(size int) (sel *byte);
-export func selectsend(sel *byte, hchan chan any, elem any) (selected bool);
-export func selectrecv(sel *byte, hchan chan any, elem *any) (selected bool);
-export func selectdefault(sel *byte) (selected bool);
-export func selectgo(sel *byte);
+func newselect(size int) (sel *byte);
+func selectsend(sel *byte, hchan chan any, elem any) (selected bool);
+func selectrecv(sel *byte, hchan chan any, elem *any) (selected bool);
+func selectdefault(sel *byte) (selected bool);
+func selectgo(sel *byte);
-export func newarray(nel int, cap int, width int) (ary []any);
-export func arraysliced(old []any, lb int, hb int, width int) (ary []any);
-export func arrayslices(old *any, nel int, lb int, hb int, width int) (ary []any);
-export func arrays2d(old *any, nel int) (ary []any);
+func newarray(nel int, cap int, width int) (ary []any);
+func arraysliced(old []any, lb int, hb int, width int) (ary []any);
+func arrayslices(old *any, nel int, lb int, hb int, width int) (ary []any);
+func arrays2d(old *any, nel int) (ary []any);
// used by go programs
-export func breakpoint();
+export func Breakpoint();
-export func reflect(i interface { }) (uint64, string, bool);
-export func unreflect(uint64, string, bool) (ret interface { });
+export func Reflect(i interface { }) (uint64, string, bool);
+export func Unreflect(uint64, string, bool) (ret interface { });
-export func argc() int;
-export func envc() int;
-export func argv(int) string;
-export func envv(int) string;
+export var Args []string;
+export var Envs []string;
-export func frexp(float64) (float64, int); // break fp into exp,fract
-export func ldexp(float64, int) float64; // make fp from exp,fract
-export func modf(float64) (float64, float64); // break fp into double.double
-export func isInf(float64, int) bool; // test for infinity
-export func isNaN(float64) bool; // test for not-a-number
+export func Frexp(float64) (float64, int); // break fp into exp,fract
+export func Ldexp(float64, int) float64; // make fp from exp,fract
+export func Modf(float64) (float64, float64); // break fp into double.double
+export func IsInf(float64, int) bool; // test for infinity
+export func IsNaN(float64) bool; // test for not-a-number
export func Inf(int) float64; // return signed Inf
export func NaN() float64; // return a NaN
-export func float32bits(float32) uint32; // raw bits
-export func float64bits(float64) uint64; // raw bits
-export func float32frombits(uint32) float32; // raw bits
-export func float64frombits(uint64) float64; // raw bits
+export func Float32bits(float32) uint32; // raw bits
+export func Float64bits(float64) uint64; // raw bits
+export func Float32frombits(uint32) float32; // raw bits
+export func Float64frombits(uint64) float64; // raw bits
-export func gosched();
-export func goexit();
+export func Gosched();
+export func Goexit();
-export func readfile(string) (string, bool); // read file into string; boolean status
-export func writefile(string, string) (bool); // write string into file; boolean status
-export func bytestorune(*byte, int, int) (int, int); // convert bytes to runes
-export func stringtorune(string, int) (int, int); // convert bytes to runes
+export func BytesToRune(*byte, int, int) (int, int); // convert bytes to runes
+export func StringToRune(string, int) (int, int); // convert bytes to runes
-export func exit(int);
+export func Exit(int);
-export func symdat() (symtab []byte, pclntab []byte);
-export func caller(n int) (pc uint64, file string, line int, ok bool);
+export func Caller(n int) (pc uint64, file string, line int, ok bool);
-export func semacquire(sema *int32);
-export func semrelease(sema *int32);
+export func SemAcquire(sema *int32);
+export func SemRelease(sema *int32);
diff -r 14731a6251fa -r 5df06070216e src/cmd/gc/sysimport.c
--- a/src/cmd/gc/sysimport.c Fri Jan 16 14:16:31 2009 -0800
+++ b/src/cmd/gc/sysimport.c Fri Jan 16 14:58:14 2009 -0800
@@ -1,84 +1,79 @@
char *sysimport =
"package sys\n"
- "export func sys.mal (? int32) (? *any)\n"
- "export func sys.throwindex ()\n"
- "export func sys.throwreturn ()\n"
- "export func sys.panicl (? int32)\n"
- "export func sys.printbool (? bool)\n"
- "export func sys.printfloat (? float64)\n"
- "export func sys.printint (? int64)\n"
- "export func sys.printstring (? string)\n"
- "export func sys.printpointer (? *any)\n"
- "export func sys.printinter (? any)\n"
- "export func sys.printarray (? any)\n"
- "export func sys.printnl ()\n"
- "export func sys.printsp ()\n"
- "export func sys.catstring (? string, ? string) (? string)\n"
- "export func sys.cmpstring (? string, ? string) (? int)\n"
- "export func sys.slicestring (? string, ? int, ? int) (? string)\n"
- "export func sys.indexstring (? string, ? int) (? uint8)\n"
- "export func sys.intstring (? int64) (? string)\n"
- "export func sys.byteastring (? *uint8, ? int) (? string)\n"
- "export func sys.arraystring (? []uint8) (? string)\n"
- "export func sys.ifaceT2I (sigi *uint8, sigt *uint8, elem any) (ret any)\n"
- "export func sys.ifaceI2T (sigt *uint8, iface any) (ret any)\n"
- "export func sys.ifaceI2T2 (sigt *uint8, iface any) (ret any, ok bool)\n"
- "export func sys.ifaceI2I (sigi *uint8, iface any) (ret any)\n"
- "export func sys.ifaceI2I2 (sigi *uint8, iface any) (ret any, ok bool)\n"
- "export func sys.ifaceeq (i1 any, i2 any) (ret bool)\n"
- "export func sys.newmap (keysize int, valsize int, keyalg int, valalg int, hint int) (hmap map[any] any)\n"
- "export func sys.mapaccess1 (hmap map[any] any, key any) (val any)\n"
- "export func sys.mapaccess2 (hmap map[any] any, key any) (val any, pres bool)\n"
- "export func sys.mapassign1 (hmap map[any] any, key any, val any)\n"
- "export func sys.mapassign2 (hmap map[any] any, key any, val any, pres bool)\n"
- "export func sys.mapiterinit (hmap map[any] any, hiter *any)\n"
- "export func sys.mapiternext (hiter *any)\n"
- "export func sys.mapiter1 (hiter *any) (key any)\n"
- "export func sys.mapiter2 (hiter *any) (key any, val any)\n"
- "export func sys.newchan (elemsize int, elemalg int, hint int) (hchan chan any)\n"
- "export func sys.chanrecv1 (hchan chan any) (elem any)\n"
- "export func sys.chanrecv2 (hchan chan any) (elem any, pres bool)\n"
- "export func sys.chanrecv3 (hchan chan any, elem *any) (pres bool)\n"
- "export func sys.chansend1 (hchan chan any, elem any)\n"
- "export func sys.chansend2 (hchan chan any, elem any) (pres bool)\n"
- "export func sys.newselect (size int) (sel *uint8)\n"
- "export func sys.selectsend (sel *uint8, hchan chan any, elem any) (selected bool)\n"
- "export func sys.selectrecv (sel *uint8, hchan chan any, elem *any) (selected bool)\n"
- "export func sys.selectdefault (sel *uint8) (selected bool)\n"
- "export func sys.selectgo (sel *uint8)\n"
- "export func sys.newarray (nel int, cap int, width int) (ary []any)\n"
- "export func sys.arraysliced (old []any, lb int, hb int, width int) (ary []any)\n"
- "export func sys.arrayslices (old *any, nel int, lb int, hb int, width int) (ary []any)\n"
- "export func sys.arrays2d (old *any, nel int) (ary []any)\n"
- "export func sys.breakpoint ()\n"
- "export func sys.reflect (i interface { }) (? uint64, ? string, ? bool)\n"
- "export func sys.unreflect (? uint64, ? string, ? bool) (ret interface { })\n"
- "export func sys.argc () (? int)\n"
- "export func sys.envc () (? int)\n"
- "export func sys.argv (? int) (? string)\n"
- "export func sys.envv (? int) (? string)\n"
- "export func sys.frexp (? float64) (? float64, ? int)\n"
- "export func sys.ldexp (? float64, ? int) (? float64)\n"
- "export func sys.modf (? float64) (? float64, ? float64)\n"
- "export func sys.isInf (? float64, ? int) (? bool)\n"
- "export func sys.isNaN (? float64) (? bool)\n"
+ "package func sys.mal (? int32) (? *any)\n"
+ "package func sys.throwindex ()\n"
+ "package func sys.throwreturn ()\n"
+ "package func sys.panicl (? int32)\n"
+ "package func sys.printbool (? bool)\n"
+ "package func sys.printfloat (? float64)\n"
+ "package func sys.printint (? int64)\n"
+ "package func sys.printstring (? string)\n"
+ "package func sys.printpointer (? *any)\n"
+ "package func sys.printinter (? any)\n"
+ "package func sys.printarray (? any)\n"
+ "package func sys.printnl ()\n"
+ "package func sys.printsp ()\n"
+ "package func sys.catstring (? string, ? string) (? string)\n"
+ "package func sys.cmpstring (? string, ? string) (? int)\n"
+ "package func sys.slicestring (? string, ? int, ? int) (? string)\n"
+ "package func sys.indexstring (? string, ? int) (? uint8)\n"
+ "package func sys.intstring (? int64) (? string)\n"
+ "package func sys.byteastring (? *uint8, ? int) (? string)\n"
+ "package func sys.arraystring (? []uint8) (? string)\n"
+ "package func sys.ifaceT2I (sigi *uint8, sigt *uint8, elem any) (ret any)\n"
+ "package func sys.ifaceI2T (sigt *uint8, iface any) (ret any)\n"
+ "package func sys.ifaceI2T2 (sigt *uint8, iface any) (ret any, ok bool)\n"
+ "package func sys.ifaceI2I (sigi *uint8, iface any) (ret any)\n"
+ "package func sys.ifaceI2I2 (sigi *uint8, iface any) (ret any, ok bool)\n"
+ "package func sys.ifaceeq (i1 any, i2 any) (ret bool)\n"
+ "package func sys.newmap (keysize int, valsize int, keyalg int, valalg int, hint int) (hmap map[any] any)\n"
+ "package func sys.mapaccess1 (hmap map[any] any, key any) (val any)\n"
+ "package func sys.mapaccess2 (hmap map[any] any, key any) (val any, pres bool)\n"
+ "package func sys.mapassign1 (hmap map[any] any, key any, val any)\n"
+ "package func sys.mapassign2 (hmap map[any] any, key any, val any, pres bool)\n"
+ "package func sys.mapiterinit (hmap map[any] any, hiter *any)\n"
+ "package func sys.mapiternext (hiter *any)\n"
+ "package func sys.mapiter1 (hiter *any) (key any)\n"
+ "package func sys.mapiter2 (hiter *any) (key any, val any)\n"
+ "package func sys.newchan (elemsize int, elemalg int, hint int) (hchan chan any)\n"
+ "package func sys.chanrecv1 (hchan chan any) (elem any)\n"
+ "package func sys.chanrecv2 (hchan chan any) (elem any, pres bool)\n"
+ "package func sys.chanrecv3 (hchan chan any, elem *any) (pres bool)\n"
+ "package func sys.chansend1 (hchan chan any, elem any)\n"
+ "package func sys.chansend2 (hchan chan any, elem any) (pres bool)\n"
+ "package func sys.newselect (size int) (sel *uint8)\n"
+ "package func sys.selectsend (sel *uint8, hchan chan any, elem any) (selected bool)\n"
+ "package func sys.selectrecv (sel *uint8, hchan chan any, elem *any) (selected bool)\n"
+ "package func sys.selectdefault (sel *uint8) (selected bool)\n"
+ "package func sys.selectgo (sel *uint8)\n"
+ "package func sys.newarray (nel int, cap int, width int) (ary []any)\n"
+ "package func sys.arraysliced (old []any, lb int, hb int, width int) (ary []any)\n"
+ "package func sys.arrayslices (old *any, nel int, lb int, hb int, width int) (ary []any)\n"
+ "package func sys.arrays2d (old *any, nel int) (ary []any)\n"
+ "export func sys.Breakpoint ()\n"
+ "export func sys.Reflect (i interface { }) (? uint64, ? string, ? bool)\n"
+ "export func sys.Unreflect (? uint64, ? string, ? bool) (ret interface { })\n"
+ "export var sys.Args []string\n"
+ "export var sys.Envs []string\n"
+ "export func sys.Frexp (? float64) (? float64, ? int)\n"
+ "export func sys.Ldexp (? float64, ? int) (? float64)\n"
+ "export func sys.Modf (? float64) (? float64, ? float64)\n"
+ "export func sys.IsInf (? float64, ? int) (? bool)\n"
+ "export func sys.IsNaN (? float64) (? bool)\n"
"export func sys.Inf (? int) (? float64)\n"
"export func sys.NaN () (? float64)\n"
- "export func sys.float32bits (? float32) (? uint32)\n"
- "export func sys.float64bits (? float64) (? uint64)\n"
- "export func sys.float32frombits (? uint32) (? float32)\n"
- "export func sys.float64frombits (? uint64) (? float64)\n"
- "export func sys.gosched ()\n"
- "export func sys.goexit ()\n"
- "export func sys.readfile (? string) (? string, ? bool)\n"
- "export func sys.writefile (? string, ? string) (? bool)\n"
- "export func sys.bytestorune (? *uint8, ? int, ? int) (? int, ? int)\n"
- "export func sys.stringtorune (? string, ? int) (? int, ? int)\n"
- "export func sys.exit (? int)\n"
- "export func sys.symdat () (symtab []uint8, pclntab []uint8)\n"
- "export func sys.caller (n int) (pc uint64, file string, line int, ok bool)\n"
- "export func sys.semacquire (sema *int32)\n"
- "export func sys.semrelease (sema *int32)\n"
+ "export func sys.Float32bits (? float32) (? uint32)\n"
+ "export func sys.Float64bits (? float64) (? uint64)\n"
+ "export func sys.Float32frombits (? uint32) (? float32)\n"
+ "export func sys.Float64frombits (? uint64) (? float64)\n"
+ "export func sys.Gosched ()\n"
+ "export func sys.Goexit ()\n"
+ "export func sys.BytesToRune (? *uint8, ? int, ? int) (? int, ? int)\n"
+ "export func sys.StringToRune (? string, ? int) (? int, ? int)\n"
+ "export func sys.Exit (? int)\n"
+ "export func sys.Caller (n int) (pc uint64, file string, line int, ok bool)\n"
+ "export func sys.SemAcquire (sema *int32)\n"
+ "export func sys.SemRelease (sema *int32)\n"
"\n"
"$$\n";
char *unsafeimport =
diff -r 14731a6251fa -r 5df06070216e src/lib/flag.go
--- a/src/lib/flag.go Fri Jan 16 14:16:31 2009 -0800
+++ b/src/lib/flag.go Fri Jan 16 14:58:14 2009 -0800
@@ -239,13 +239,13 @@
}
export func Usage() {
- if sys.argc() > 0 {
- print("Usage of ", sys.argv(0), ": \n");
+ if len(sys.Args) > 0 {
+ print("Usage of ", sys.Args[0], ": \n");
} else {
print("Usage: \n");
}
PrintDefaults();
- sys.exit(1);
+ sys.Exit(1);
}
export func NFlag() int {
@@ -254,14 +254,14 @@
export func Arg(i int) string {
i += flags.first_arg;
- if i < 0 || i >= sys.argc() {
+ if i < 0 || i >= len(sys.Args) {
return "";
}
- return sys.argv(i)
+ return sys.Args[i]
}
export func NArg() int {
- return sys.argc() - flags.first_arg
+ return len(sys.Args) - flags.first_arg
}
func add(name string, value _Value, usage string) {
@@ -339,7 +339,7 @@
func (f *allFlags) ParseOne(index int) (ok bool, next int)
{
- s := sys.argv(index);
+ s := sys.Args[index];
f.first_arg = index; // until proven otherwise
if len(s) == 0 {
return false, -1
@@ -398,11 +398,11 @@
}
} else {
// It must have a value, which might be the next argument.
- if !has_value && index < sys.argc()-1 {
+ if !has_value && index < len(sys.Args)-1 {
// value is the next arg
has_value = true;
index++;
- value = sys.argv(index);
+ value = sys.Args[index];
}
if !has_value {
print("flag needs an argument: -", name, "\n");
@@ -433,7 +433,7 @@
}
export func Parse() {
- for i := 1; i < sys.argc(); {
+ for i := 1; i < len(sys.Args); {
ok, next := flags.ParseOne(i);
if next > 0 {
flags.first_arg = next;
diff -r 14731a6251fa -r 5df06070216e src/lib/fmt/print.go
--- a/src/lib/fmt/print.go Fri Jan 16 14:16:31 2009 -0800
+++ b/src/lib/fmt/print.go Fri Jan 16 14:58:14 2009 -0800
@@ -14,6 +14,7 @@
"io";
"reflect";
"os";
+ "utf8";
)
// Representation of printer state passed to custom formatters.
@@ -438,7 +439,7 @@
end := len(format) - 1;
fieldnum := 0; // we process one field per non-trivial format
for i := 0; i <= end; {
- c, w := sys.stringtorune(format, i);
+ c, w := utf8.DecodeRuneInString(format, i);
if c != '%' || i == end {
p.add(c);
i += w;
@@ -469,7 +470,7 @@
if i < end && format[i] == '.' {
p.fmt.prec, p.fmt.prec_present, i = parsenum(format, i+1, end);
}
- c, w = sys.stringtorune(format, i);
+ c, w = utf8.DecodeRuneInString(format, i);
i += w;
// percent is special - absorbs no operand
if c == '%' {
diff -r 14731a6251fa -r 5df06070216e src/lib/math/exp.go
--- a/src/lib/math/exp.go Fri Jan 16 14:16:31 2009 -0800
+++ b/src/lib/math/exp.go Fri Jan 16 14:58:14 2009 -0800
@@ -101,9 +101,9 @@
// special cases
switch {
- case sys.isNaN(x) || sys.isInf(x, 1):
+ case sys.IsNaN(x) || sys.IsInf(x, 1):
return x;
- case sys.isInf(x, -1):
+ case sys.IsInf(x, -1):
return 0;
case x > Overflow:
return sys.Inf(1);
@@ -129,6 +129,6 @@
t := r * r;
c := r - t*(P1+t*(P2+t*(P3+t*(P4+t*P5))));
y := 1 - ((lo - (r*c)/(2-c)) - hi);
- // TODO(rsc): make sure sys.ldexp can handle boundary k
- return sys.ldexp(y, k);
+ // TODO(rsc): make sure sys.Ldexp can handle boundary k
+ return sys.Ldexp(y, k);
}
diff -r 14731a6251fa -r 5df06070216e src/lib/math/floor.go
--- a/src/lib/math/floor.go Fri Jan 16 14:16:31 2009 -0800
+++ b/src/lib/math/floor.go Fri Jan 16 14:58:14 2009 -0800
@@ -11,13 +11,13 @@
export func Floor(arg float64) float64 {
if arg < 0 {
- d, fract := sys.modf(-arg);
+ d, fract := sys.Modf(-arg);
if fract != 0.0 {
d = d+1;
}
return -d;
}
- d, fract := sys.modf(arg);
+ d, fract := sys.Modf(arg);
return d;
}
diff -r 14731a6251fa -r 5df06070216e src/lib/math/fmod.go
--- a/src/lib/math/fmod.go Fri Jan 16 14:16:31 2009 -0800
+++ b/src/lib/math/fmod.go Fri Jan 16 14:58:14 2009 -0800
@@ -16,7 +16,7 @@
y = -y;
}
- yfr, yexp := sys.frexp(y);
+ yfr, yexp := sys.Frexp(y);
sign := false;
r := x;
if x < 0 {
@@ -25,11 +25,11 @@
}
for r >= y {
- rfr, rexp := sys.frexp(r);
+ rfr, rexp := sys.Frexp(r);
if rfr < yfr {
rexp = rexp - 1;
}
- r = r - sys.ldexp(y, rexp-yexp);
+ r = r - sys.Ldexp(y, rexp-yexp);
}
if sign {
r = -r;
diff -r 14731a6251fa -r 5df06070216e src/lib/math/log.go
--- a/src/lib/math/log.go Fri Jan 16 14:16:31 2009 -0800
+++ b/src/lib/math/log.go Fri Jan 16 14:58:14 2009 -0800
@@ -85,7 +85,7 @@
// special cases
switch {
- case sys.isNaN(x) || sys.isInf(x, 1):
+ case sys.IsNaN(x) || sys.IsInf(x, 1):
return x;
case x < 0:
return sys.NaN();
@@ -94,7 +94,7 @@
}
// reduce
- f1, ki := sys.frexp(x);
+ f1, ki := sys.Frexp(x);
if f1 < Sqrt2/2 {
f1 *= 2;
ki--;
diff -r 14731a6251fa -r 5df06070216e src/lib/math/pow.go
--- a/src/lib/math/pow.go Fri Jan 16 14:16:31 2009 -0800
+++ b/src/lib/math/pow.go Fri Jan 16 14:58:14 2009 -0800
@@ -30,7 +30,7 @@
absy = -absy;
flip = true;
}
- yi, yf := sys.modf(absy);
+ yi, yf := sys.Modf(absy);
if yf != 0 && x < 0 {
return sys.NaN();
}
@@ -55,7 +55,7 @@
// by multiplying in successive squarings
// of x according to bits of yi.
// accumulate powers of two into exp.
- x1, xe := sys.frexp(x);
+ x1, xe := sys.Frexp(x);
for i := int64(yi); i != 0; i >>= 1 {
if i&1 == 1 {
a1 *= x1;
@@ -76,5 +76,5 @@
a1 = 1 / a1;
ae = -ae;
}
- return sys.ldexp(a1, ae);
+ return sys.Ldexp(a1, ae);
}
diff -r 14731a6251fa -r 5df06070216e src/lib/math/sin.go
--- a/src/lib/math/sin.go Fri Jan 16 14:16:31 2009 -0800
+++ b/src/lib/math/sin.go Fri Jan 16 14:58:14 2009 -0800
@@ -29,9 +29,9 @@
var y float64;
if x > 32764 {
var e float64;
- e, y = sys.modf(x);
+ e, y = sys.Modf(x);
e = e + float64(quad);
- temp1, f := sys.modf(0.25*e);
+ temp1, f := sys.Modf(0.25*e);
quad = int(e - 4*f);
} else {
k := int32(x);
diff -r 14731a6251fa -r 5df06070216e src/lib/math/sqrt.go
--- a/src/lib/math/sqrt.go Fri Jan 16 14:16:31 2009 -0800
+++ b/src/lib/math/sqrt.go Fri Jan 16 14:58:14 2009 -0800
@@ -12,7 +12,7 @@
*/
export func Sqrt(arg float64) float64 {
- if sys.isInf(arg, 1) {
+ if sys.IsInf(arg, 1) {
return arg;
}
@@ -23,7 +23,7 @@
return 0;
}
- x,exp := sys.frexp(arg);
+ x,exp := sys.Frexp(arg);
for x < 0.5 {
x = x*2;
exp = exp-1;
diff -r 14731a6251fa -r 5df06070216e src/lib/math/tan.go
--- a/src/lib/math/tan.go Fri Jan 16 14:16:31 2009 -0800
+++ b/src/lib/math/tan.go Fri Jan 16 14:58:14 2009 -0800
@@ -33,7 +33,7 @@
}
x = x * (4/Pi); /* overflow? */
var e float64;
- e, x = sys.modf(x);
+ e, x = sys.Modf(x);
i := int32(e);
switch i & 3 {
diff -r 14731a6251fa -r 5df06070216e src/lib/os/os_env.go
--- a/src/lib/os/os_env.go Fri Jan 16 14:16:31 2009 -0800
+++ b/src/lib/os/os_env.go Fri Jan 16 14:58:14 2009 -0800
@@ -18,10 +18,9 @@
if n == 0 {
return "", EINVAL
}
- for i := 0; i < sys.envc(); i++ {
- e := sys.envv(i);
- if len(e) > n && e[n] == '=' && e[0 : n] == s {
- return e[n+1 : len(e)], nil
+ for i, e := range sys.Envs {
+ if len(e) > n && e[n] == '=' && e[0:n] == s {
+ return e[n+1:len(e)], nil
}
}
return "", ENOENV
diff -r 14731a6251fa -r 5df06070216e src/lib/reflect/type.go
--- a/src/lib/reflect/type.go Fri Jan 16 14:16:31 2009 -0800
+++ b/src/lib/reflect/type.go Fri Jan 16 14:58:14 2009 -0800
@@ -7,13 +7,16 @@
package reflect
-import "sync"
+import (
+ "utf8";
+ "sync";
+)
export type Type interface
export func ExpandType(name string) Type
-export func typestrings() string // implemented in C; declared here
+func typestrings() string // implemented in C; declared here
export const (
MissingKind = iota;
@@ -577,7 +580,7 @@
return;
}
start := p.index;
- c, w := sys.stringtorune(p.str, p.index);
+ c, w := utf8.DecodeRuneInString(p.str, p.index);
p.index += w;
switch {
case c == '<':
diff -r 14731a6251fa -r 5df06070216e src/lib/reflect/value.go
--- a/src/lib/reflect/value.go Fri Jan 16 14:16:31 2009 -0800
+++ b/src/lib/reflect/value.go Fri Jan 16 14:58:14 2009 -0800
@@ -48,12 +48,12 @@
func (c *commonValue) Interface() interface {} {
var i interface {};
if c.typ.Size() > 8 { // TODO(rsc): how do we know it is 8?
- i = sys.unreflect(c.addr.(uintptr).(uint64), c.typ.String(), true);
+ i = sys.Unreflect(c.addr.(uintptr).(uint64), c.typ.String(), true);
} else {
if uintptr(c.addr) == 0 {
panicln("reflect: address 0 for", c.typ.String());
}
- i = sys.unreflect(uint64(uintptr(*c.addr.(*Addr))), c.typ.String(), false);
+ i = sys.Unreflect(uint64(uintptr(*c.addr.(*Addr))), c.typ.String(), false);
}
return i;
}
@@ -876,7 +876,7 @@
export func NewValue(e interface {}) Value {
- value, typestring, indir := sys.reflect(e);
+ value, typestring, indir := sys.Reflect(e);
typ, ok := typecache[typestring];
if !ok {
typ = ParseTypeString("", typestring);
diff -r 14731a6251fa -r 5df06070216e src/lib/regexp/regexp.go
--- a/src/lib/regexp/regexp.go Fri Jan 16 14:16:31 2009 -0800
+++ b/src/lib/regexp/regexp.go Fri Jan 16 14:58:14 2009 -0800
@@ -7,8 +7,9 @@
package regexp
import (
+ "array";
"os";
- "array";
+ "utf8";
)
var debug = false;
@@ -215,7 +216,7 @@
func (re *_RE) Error(err *os.Error) {
re.error = err;
re.ch <- re;
- sys.goexit();
+ sys.Goexit();
}
func (re *_RE) Add(i instr) instr {
@@ -241,7 +242,7 @@
if p.pos >= len(p.re.expr) {
p.ch = endOfFile
} else {
- c, w := sys.stringtorune(p.re.expr, p.pos);
+ c, w := utf8.DecodeRuneInString(p.re.expr, p.pos);
p.ch = c;
p.pos += w;
}
@@ -653,7 +654,7 @@
charwidth := 1;
c := endOfFile;
if pos < len(str) {
- c, charwidth = sys.stringtorune(str, pos);
+ c, charwidth = utf8.DecodeRuneInString(str, pos);
}
for i := 0; i < len(s[in]); i++ {
st := s[in][i];
diff -r 14731a6251fa -r 5df06070216e src/lib/strconv/atof.go
--- a/src/lib/strconv/atof.go Fri Jan 16 14:16:31 2009 -0800
+++ b/src/lib/strconv/atof.go Fri Jan 16 14:58:14 2009 -0800
@@ -329,7 +329,7 @@
}
}
b, ovf := decimalToFloatBits(neg, d, trunc, &float64info);
- f = sys.float64frombits(b);
+ f = sys.Float64frombits(b);
if ovf {
err = os.ERANGE;
}
@@ -347,7 +347,7 @@
}
}
b, ovf := decimalToFloatBits(neg, d, trunc, &float32info);
- f = sys.float32frombits(uint32(b));
+ f = sys.Float32frombits(uint32(b));
if ovf {
err = os.ERANGE;
}
diff -r 14731a6251fa -r 5df06070216e src/lib/strconv/ftoa.go
--- a/src/lib/strconv/ftoa.go Fri Jan 16 14:16:31 2009 -0800
+++ b/src/lib/strconv/ftoa.go Fri Jan 16 14:58:14 2009 -0800
@@ -41,11 +41,11 @@
export var FloatSize = floatsize()
export func Ftoa32(f float32, fmt byte, prec int) string {
- return genericFtoa(uint64(sys.float32bits(f)), fmt, prec, &float32info);
+ return genericFtoa(uint64(sys.Float32bits(f)), fmt, prec, &float32info);
}
export func Ftoa64(f float64, fmt byte, prec int) string {
- return genericFtoa(sys.float64bits(f), fmt, prec, &float64info);
+ return genericFtoa(sys.Float64bits(f), fmt, prec, &float64info);
}
export func Ftoa(f float, fmt byte, prec int) string {
diff -r 14731a6251fa -r 5df06070216e src/lib/sync/mutex.go
--- a/src/lib/sync/mutex.go Fri Jan 16 14:16:31 2009 -0800
+++ b/src/lib/sync/mutex.go Fri Jan 16 14:58:14 2009 -0800
@@ -4,7 +4,9 @@
package sync
-package func cas(val *int32, old, new int32) bool
+func cas(val *int32, old, new int32) bool
+func semacquire(*int32)
+func semrelease(*int32)
export type Mutex struct {
key int32;
@@ -26,7 +28,7 @@
// changed from 0 to 1; we hold lock
return;
}
- sys.semacquire(&m.sema);
+ semacquire(&m.sema);
}
func (m *Mutex) Unlock() {
@@ -34,6 +36,6 @@
// changed from 1 to 0; no contention
return;
}
- sys.semrelease(&m.sema);
+ semrelease(&m.sema);
}
diff -r 14731a6251fa -r 5df06070216e src/lib/sync/mutex_test.go
--- a/src/lib/sync/mutex_test.go Fri Jan 16 14:16:31 2009 -0800
+++ b/src/lib/sync/mutex_test.go Fri Jan 16 14:58:14 2009 -0800
@@ -11,10 +11,10 @@
"testing"
)
-func hammerSemaphore(s *int32, cdone chan bool) {
+export func HammerSemaphore(s *int32, cdone chan bool) {
for i := 0; i < 1000; i++ {
- sys.semacquire(s);
- sys.semrelease(s);
+ semacquire(s);
+ semrelease(s);
}
cdone <- true;
}
@@ -24,7 +24,7 @@
*s = 1;
c := make(chan bool);
for i := 0; i < 10; i++ {
- go hammerSemaphore(s, c);
+ go HammerSemaphore(s, c);
}
for i := 0; i < 10; i++ {
<-c;
@@ -32,7 +32,7 @@
}
-func hammerMutex(m *Mutex, cdone chan bool) {
+export func HammerMutex(m *Mutex, cdone chan bool) {
for i := 0; i < 1000; i++ {
m.Lock();
m.Unlock();
@@ -44,7 +44,7 @@
m := new(Mutex);
c := make(chan bool);
for i := 0; i < 10; i++ {
- go hammerMutex(m, c);
+ go HammerMutex(m, c);
}
for i := 0; i < 10; i++ {
<-c;
diff -r 14731a6251fa -r 5df06070216e src/lib/testing.go
--- a/src/lib/testing.go Fri Jan 16 14:16:31 2009 -0800
+++ b/src/lib/testing.go Fri Jan 16 14:58:14 2009 -0800
@@ -34,7 +34,7 @@
func (t *T) FailNow() {
t.Fail();
t.ch <- t;
- sys.goexit();
+ sys.Goexit();
}
func (t *T) Log(args ...) {
@@ -104,7 +104,7 @@
}
if !ok {
println("FAIL");
- sys.exit(1);
+ sys.Exit(1);
}
println("PASS");
}
diff -r 14731a6251fa -r 5df06070216e src/libmach_amd64/darwin.c
--- a/src/libmach_amd64/darwin.c Fri Jan 16 14:16:31 2009 -0800
+++ b/src/libmach_amd64/darwin.c Fri Jan 16 14:58:14 2009 -0800
@@ -635,6 +635,14 @@
goto havet;
}
}
+ if(nthr > 0)
+ addpid(thr[0].pid, 1);
+ for(i=0; i<nthr; i++){
+ if(thr[i].thread == thread){
+ t = &thr[i];
+ goto havet;
+ }
+ }
fprint(2, "did not find thread in catch_exception_raise\n");
return KERN_SUCCESS; // let thread continue
diff -r 14731a6251fa -r 5df06070216e src/runtime/Makefile
--- a/src/runtime/Makefile Fri Jan 16 14:16:31 2009 -0800
+++ b/src/runtime/Makefile Fri Jan 16 14:58:14 2009 -0800
@@ -36,7 +36,6 @@
sema.$O\
string.$O\
symtab.$O\
- sys_file.$O\
OFILES=$(RT0OFILES) $(LIBOFILES)
OS_H=$(GOARCH)_$(GOOS).h
diff -r 14731a6251fa -r 5df06070216e src/runtime/chan.c
--- a/src/runtime/chan.c Fri Jan 16 14:16:31 2009 -0800
+++ b/src/runtime/chan.c Fri Jan 16 14:58:14 2009 -0800
@@ -195,7 +195,7 @@
g->status = Gwaiting;
enqueue(&c->sendq, sg);
unlock(&chanlock);
- sys·gosched();
+ sys·Gosched();
lock(&chanlock);
sg = g->param;
@@ -217,7 +217,7 @@
g->status = Gwaiting;
enqueue(&c->sendq, sg);
unlock(&chanlock);
- sys·gosched();
+ sys·Gosched();
lock(&chanlock);
}
@@ -281,7 +281,7 @@
g->status = Gwaiting;
enqueue(&c->recvq, sg);
unlock(&chanlock);
- sys·gosched();
+ sys·Gosched();
lock(&chanlock);
sg = g->param;
@@ -303,7 +303,7 @@
g->status = Gwaiting;
enqueue(&c->recvq, sg);
unlock(&chanlock);
- sys·gosched();
+ sys·Gosched();
lock(&chanlock);
}
c->elemalg->copy(c->elemsize, ep, c->recvdataq->elem);
@@ -690,7 +690,7 @@
g->status = Gwaiting;
unlock(&chanlock);
- sys·gosched();
+ sys·Gosched();
lock(&chanlock);
sg = g->param;
diff -r 14731a6251fa -r 5df06070216e src/runtime/iface.c
--- a/src/runtime/iface.c Fri Jan 16 14:16:31 2009 -0800
+++ b/src/runtime/iface.c Fri Jan 16 14:58:14 2009 -0800
@@ -457,7 +457,7 @@
}
void
-sys·reflect(Iface i, uint64 retit, string rettype, bool retindir)
+sys·Reflect(Iface i, uint64 retit, string rettype, bool retindir)
{
int32 wid;
@@ -492,14 +492,14 @@
// print("first field is string");
// }
//
-// vv.Interface() returns the result of sys.unreflect with
+// vv.Interface() returns the result of sys.Unreflect with
// a typestring of "[]int". If []int is not used with interfaces
// in the rest of the program, there will be no signature in gotypesigs
// for "[]int", so we have to invent one. The only requirements
// on the fake signature are:
//
// (1) any interface conversion using the signature will fail
-// (2) calling sys.reflect() returns the args to unreflect
+// (2) calling sys.Reflect() returns the args to unreflect
//
// (1) is ensured by the fact that we allocate a new Sigt,
// so it will necessarily be != any Sigt in gotypesigs.
@@ -561,7 +561,7 @@
void
-sys·unreflect(uint64 it, string type, bool indir, Iface ret)
+sys·Unreflect(uint64 it, string type, bool indir, Iface ret)
{
Sigt *sigt;
diff -r 14731a6251fa -r 5df06070216e src/runtime/proc.c
--- a/src/runtime/proc.c Fri Jan 16 14:16:31 2009 -0800
+++ b/src/runtime/proc.c Fri Jan 16 14:58:14 2009 -0800
@@ -97,7 +97,8 @@
byte *p;
mallocinit();
-
+ goargs();
+
// Allocate internal symbol table representation now,
// so that we don't need to call malloc when we crash.
findfunc(0);
@@ -127,7 +128,7 @@
}
void
-sys·goexit(void)
+sys·Goexit(void)
{
if(debug > 1){
lock(&debuglock);
@@ -135,7 +136,7 @@
unlock(&debuglock);
}
g->status = Gmoribund;
- sys·gosched();
+ sys·Gosched();
}
G*
@@ -186,7 +187,7 @@
mcpy(sp, (byte*)&arg0, siz);
sp -= 8;
- *(byte**)sp = (byte*)sys·goexit;
+ *(byte**)sp = (byte*)sys·Goexit;
sp -= 8; // retpc used by gogo
newg->sched.SP = sp;
@@ -493,7 +494,7 @@
case Gmoribund:
gp->status = Gdead;
if(--sched.gcount == 0)
- sys·exit(0);
+ sys_Exit(0);
break;
}
if(gp->readyonstop){
@@ -522,7 +523,7 @@
// before running g again. If g->status is Gmoribund,
// kills off g.
void
-sys·gosched(void)
+sys·Gosched(void)
{
if(gosave(&g->sched) == 0){
g = m->g0;
@@ -585,7 +586,7 @@
// The scheduler will ready g and put this m to sleep.
// When the scheduler takes g awa from m,
// it will undo the sched.mcpu++ above.
- sys·gosched();
+ sys·Gosched();
}
diff -r 14731a6251fa -r 5df06070216e src/runtime/rt0_amd64.s
--- a/src/runtime/rt0_amd64.s Fri Jan 16 14:16:31 2009 -0800
+++ b/src/runtime/rt0_amd64.s Fri Jan 16 14:58:14 2009 -0800
@@ -55,12 +55,12 @@
CALL initdone(SB)
CALL main·main(SB)
PUSHQ $0
- CALL sys·exit(SB)
+ CALL sys·Exit(SB)
POPQ AX
CALL notok(SB)
RET
-TEXT sys·breakpoint(SB),7,$0
+TEXT sys·Breakpoint(SB),7,$0
BYTE $0xcc
RET
diff -r 14731a6251fa -r 5df06070216e src/runtime/rt1_amd64_darwin.c
--- a/src/runtime/rt1_amd64_darwin.c Fri Jan 16 14:16:31 2009 -0800
+++ b/src/runtime/rt1_amd64_darwin.c Fri Jan 16 14:58:14 2009 -0800
@@ -129,7 +129,7 @@
sighandler(int32 sig, struct siginfo *info, void *context)
{
if(panicking) // traceback already printed
- sys·exit(2);
+ sys_Exit(2);
_STRUCT_MCONTEXT64 *uc_mcontext = get_uc_mcontext(context);
_STRUCT_X86_THREAD_STATE64 *ss = get___ss(uc_mcontext);
@@ -151,7 +151,7 @@
print_thread_state(ss);
}
- sys·exit(2);
+ sys_Exit(2);
}
void
diff -r 14731a6251fa -r 5df06070216e src/runtime/rt1_amd64_linux.c
--- a/src/runtime/rt1_amd64_linux.c Fri Jan 16 14:16:31 2009 -0800
+++ b/src/runtime/rt1_amd64_linux.c Fri Jan 16 14:58:14 2009 -0800
@@ -135,7 +135,7 @@
sighandler(int32 sig, struct siginfo* info, void** context)
{
if(panicking) // traceback already printed
- sys·exit(2);
+ sys_Exit(2);
struct sigcontext *sc = &(((struct ucontext *)context)->uc_mcontext);
@@ -156,8 +156,8 @@
print_sigcontext(sc);
}
- sys·breakpoint();
- sys·exit(2);
+ sys·Breakpoint();
+ sys_Exit(2);
}
struct stack_t {
diff -r 14731a6251fa -r 5df06070216e src/runtime/rt2_amd64.c
--- a/src/runtime/rt2_amd64.c Fri Jan 16 14:16:31 2009 -0800
+++ b/src/runtime/rt2_amd64.c Fri Jan 16 14:58:14 2009 -0800
@@ -72,7 +72,7 @@
// func caller(n int) (pc uint64, file string, line int, ok bool)
void
-sys·caller(int32 n, uint64 retpc, string retfile, int32 retline, bool retbool)
+sys·Caller(int32 n, uint64 retpc, string retfile, int32 retline, bool retbool)
{
uint64 pc;
byte *sp;
diff -r 14731a6251fa -r 5df06070216e src/runtime/rune.c
--- a/src/runtime/rune.c Fri Jan 16 14:16:31 2009 -0800
+++ b/src/runtime/rune.c Fri Jan 16 14:58:14 2009 -0800
@@ -52,120 +52,6 @@
Runemax = 0x10FFFF, /* maximum rune value */
};
-/*
- * Modified by Wei-Hwa Huang, Google Inc., on 2004-09-24
- * This is a slower but "safe" version of the old chartorune
- * that works on strings that are not necessarily null-terminated.
- *
- * If you know for sure that your string is null-terminated,
- * chartorune will be a bit faster.
- *
- * It is guaranteed not to attempt to access "length"
- * past the incoming pointer. This is to avoid
- * possible access violations. If the string appears to be
- * well-formed but incomplete (i.e., to get the whole Rune
- * we'd need to read past str+length) then we'll set the Rune
- * to Bad and return 0.
- *
- * Note that if we have decoding problems for other
- * reasons, we return 1 instead of 0.
- */
-int32
-charntorune(int32 *rune, byte *str, int32 length)
-{
- int32 c, c1, c2, c3;
- int32 l;
-
- /* When we're not allowed to read anything */
- if(length <= 0) {
- goto badlen;
- }
-
- /*
- * one character sequence (7-bit value)
- * 00000-0007F => T1
- */
- c = *(byte*)str; /* cast not necessary, but kept for safety */
- if(c < Tx) {
- *rune = c;
- return 1;
- }
-
- // If we can't read more than one character we must stop
- if(length <= 1) {
- goto badlen;
- }
-
- /*
- * two character sequence (11-bit value)
- * 0080-07FF => T2 Tx
- */
- c1 = *(byte*)(str+1) ^ Tx;
- if(c1 & Testx)
- goto bad;
- if(c < T3) {
- if(c < T2)
- goto bad;
- l = ((c << Bitx) | c1) & Rune2;
- if(l <= Rune1)
- goto bad;
- *rune = l;
- return 2;
- }
-
- // If we can't read more than two characters we must stop
- if(length <= 2) {
- goto badlen;
- }
-
- /*
- * three character sequence (16-bit value)
- * 0800-FFFF => T3 Tx Tx
- */
- c2 = *(byte*)(str+2) ^ Tx;
- if(c2 & Testx)
- goto bad;
- if(c < T4) {
- l = ((((c << Bitx) | c1) << Bitx) | c2) & Rune3;
- if(l <= Rune2)
- goto bad;
- *rune = l;
- return 3;
- }
-
- if (length <= 3)
- goto badlen;
-
- /*
- * four character sequence (21-bit value)
- * 10000-1FFFFF => T4 Tx Tx Tx
- */
- c3 = *(byte*)(str+3) ^ Tx;
- if (c3 & Testx)
- goto bad;
- if (c < T5) {
- l = ((((((c << Bitx) | c1) << Bitx) | c2) << Bitx) | c3) & Rune4;
- if (l <= Rune3)
- goto bad;
- *rune = l;
- return 4;
- }
-
- // Support for 5-byte or longer UTF-8 would go here, but
- // since we don't have that, we'll just fall through to bad.
-
- /*
- * bad decoding
- */
-bad:
- *rune = Bad;
- return 1;
-badlen:
- *rune = Bad;
- return 0;
-
-}
-
int32
runetochar(byte *str, int32 rune) /* note: in original, arg2 was pointer */
{
@@ -222,22 +108,3 @@
str[3] = Tx | (c & Maskx);
return 4;
}
-
-/*
- * Wrappers for calling from go
- */
-void
-sys·bytestorune(byte *str, int32 off, int32 length, int32 outrune, int32 outcount)
-{
- outcount = charntorune(&outrune, str + off, length);
- FLUSH(&outrune);
- FLUSH(&outcount);
-}
-
-void
-sys·stringtorune(string str, int32 off, int32 outrune, int32 outcount)
-{
- outcount = charntorune(&outrune, str->str + off, str->len - off);
- FLUSH(&outrune);
- FLUSH(&outcount);
-}
diff -r 14731a6251fa -r 5df06070216e src/runtime/runtime.c
--- a/src/runtime/runtime.c Fri Jan 16 14:16:31 2009 -0800
+++ b/src/runtime/runtime.c Fri Jan 16 14:58:14 2009 -0800
@@ -32,8 +32,8 @@
tracebackothers(g);
}
panicking = 1;
- sys·breakpoint(); // so we can grab it in a debugger
- sys·exit(2);
+ sys·Breakpoint(); // so we can grab it in a debugger
+ sys_Exit(2);
}
void
@@ -55,7 +55,7 @@
prints(s);
prints("\n");
*(int32*)0 = 0;
- sys·exit(1);
+ sys_Exit(1);
}
void
@@ -280,9 +280,9 @@
return d - dd;
}
-// func frexp(float64) (float64, int32); // break fp into exp,frac
+// func Frexp(float64) (float64, int32); // break fp into exp,frac
void
-sys·frexp(float64 din, float64 dou, int32 iou)
+sys·Frexp(float64 din, float64 dou, int32 iou)
{
dou = frexp(din, &iou);
FLUSH(&dou);
@@ -290,7 +290,7 @@
//func ldexp(int32, float64) float64; // make fp from exp,frac
void
-sys·ldexp(float64 din, int32 ein, float64 dou)
+sys·Ldexp(float64 din, int32 ein, float64 dou)
{
dou = ldexp(din, ein);
FLUSH(&dou);
@@ -298,7 +298,7 @@
//func modf(float64) (float64, float64); // break fp into double+double
void
-sys·modf(float64 din, float64 integer, float64 fraction)
+sys·Modf(float64 din, float64 integer, float64 fraction)
{
fraction = modf(din, &integer);
FLUSH(&fraction);
@@ -306,7 +306,7 @@
//func isinf(float64, int32 sign) bool; // test for infinity
void
-sys·isInf(float64 din, int32 signin, bool out)
+sys·IsInf(float64 din, int32 signin, bool out)
{
out = isInf(din, signin);
FLUSH(&out);
@@ -314,7 +314,7 @@
//func isnan(float64) bool; // test for NaN
void
-sys·isNaN(float64 din, bool out)
+sys·IsNaN(float64 din, bool out)
{
out = isNaN(din);
FLUSH(&out);
@@ -338,7 +338,7 @@
// func float32bits(float32) uint32; // raw bits of float32
void
-sys·float32bits(float32 din, uint32 iou)
+sys·Float32bits(float32 din, uint32 iou)
{
iou = float32tobits(din);
FLUSH(&iou);
@@ -346,7 +346,7 @@
// func float64bits(float64) uint64; // raw bits of float64
void
-sys·float64bits(float64 din, uint64 iou)
+sys·Float64bits(float64 din, uint64 iou)
{
iou = float64tobits(din);
FLUSH(&iou);
@@ -354,7 +354,7 @@
// func float32frombits(uint32) float32; // raw bits to float32
void
-sys·float32frombits(uint32 uin, float32 dou)
+sys·Float32frombits(uint32 uin, float32 dou)
{
dou = float32frombits(uin);
FLUSH(&dou);
@@ -362,7 +362,7 @@
// func float64frombits(uint64) float64; // raw bits to float64
void
-sys·float64frombits(uint64 uin, float64 dou)
+sys·Float64frombits(uint64 uin, float64 dou)
{
dou = float64frombits(uin);
FLUSH(&dou);
@@ -370,23 +370,37 @@
static int32 argc;
static uint8** argv;
-static int32 envc;
-static uint8** envv;
+
+Array sys·Args;
+Array sys·Envs;
void
args(int32 c, uint8 **v)
{
argc = c;
argv = v;
- envv = v + argc + 1; // skip 0 at end of argv
- for (envc = 0; envv[envc] != 0; envc++)
- ;
}
-int32
-getenvc(void)
+void
+goargs(void)
{
- return envc;
+ string* goargv;
+ string* envv;
+ int32 i, envc;
+
+ goargv = (string*)argv;
+ for (i=0; i<argc; i++)
+ goargv[i] = gostring(argv[i]);
+ sys·Args.array = (byte*)argv;
+ sys·Args.nel = argc;
+ sys·Args.cap = argc;
+
+ envv = goargv + argc + 1; // skip 0 at end of argv
+ for (envc = 0; envv[envc] != 0; envc++)
+ envv[envc] = gostring((uint8*)envv[envc]);
+ sys·Envs.array = (byte*)envv;
+ sys·Envs.nel = envc;
+ sys·Envs.cap = envc;
}
byte*
@@ -394,11 +408,15 @@
{
int32 i, j, len;
byte *v, *bs;
+ string* envv;
+ int32 envc;
bs = (byte*)s;
len = findnull(bs);
+ envv = (string*)sys·Envs.array;
+ envc = sys·Envs.nel;
for(i=0; i<envc; i++){
- v = envv[i];
+ v = envv[i]->str;
for(j=0; j<len; j++)
if(bs[j] != v[j])
goto nomatch;
@@ -410,6 +428,7 @@
return nil;
}
+
int32
atoi(byte *p)
{
@@ -421,44 +440,6 @@
return n;
}
-//func argc() int32; // return number of arguments
-void
-sys·argc(int32 v)
-{
- v = argc;
- FLUSH(&v);
-}
-
-//func envc() int32; // return number of environment variables
-void
-sys·envc(int32 v)
-{
- v = envc;
- FLUSH(&v);
-}
-
-//func argv(i) string; // return argument i
-void
-sys·argv(int32 i, string s)
-{
- if(i >= 0 && i < argc)
- s = gostring(argv[i]);
- else
- s = emptystring;
- FLUSH(&s);
-}
-
-//func envv(i) string; // return environment variable i
-void
-sys·envv(int32 i, string s)
-{
- if(i >= 0 && i < envc)
- s = gostring(envv[i]);
- else
- s = emptystring;
- FLUSH(&s);
-}
-
void
check(void)
{
diff -r 14731a6251fa -r 5df06070216e src/runtime/runtime.h
--- a/src/runtime/runtime.h Fri Jan 16 14:16:31 2009 -0800
+++ b/src/runtime/runtime.h Fri Jan 16 14:58:14 2009 -0800
@@ -252,7 +252,6 @@
int32 findnull(byte*);
void dump(byte*, int32);
int32 runetochar(byte*, int32);
-int32 chartorune(uint32*, byte*);
/*
* very low level c-called
@@ -261,6 +260,7 @@
int32 gosave(Gobuf*);
int32 gogoret(Gobuf*, uint64);
void retfromnewstack(void);
+void goargs(void);
void setspgoto(byte*, void(*)(void), void(*)(void));
void FLUSH(void*);
void* getu(void);
@@ -348,16 +348,15 @@
* UTF-8 characters in identifiers.
*/
#ifndef __GNUC__
-#define sys_exit sys·exit
-#define sys_gosched sys·gosched
+#define sys_Exit sys·Exit
+#define sys_Gosched sys·Gosched
#define sys_memclr sys·memclr
#define sys_write sys·write
-#define sys_breakpoint sys·breakpoint
-#define sys_bytestorune sys·bytestorune
+#define sys_Breakpoint sys·Breakpoint
#define sys_catstring sys·catstring
#define sys_cmpstring sys·cmpstring
#define sys_getcallerpc sys·getcallerpc
-#define sys_goexit sys·goexit
+#define sys_Goexit sys·Goexit
#define sys_indexstring sys·indexstring
#define sys_intstring sys·intstring
#define sys_mal sys·mal
@@ -376,17 +375,16 @@
#define sys_semrelease sys·semrelease
#define sys_setcallerpc sys·setcallerpc
#define sys_slicestring sys·slicestring
-#define sys_stringtorune sys·stringtorune
#endif
/*
* low level go -called
*/
-void sys_goexit(void);
-void sys_gosched(void);
-void sys_exit(int32);
+void sys_Goexit(void);
+void sys_Gosched(void);
+void sys_Exit(int32);
void sys_write(int32, void*, int32);
-void sys_breakpoint(void);
+void sys_Breakpoint(void);
uint8* sys_mmap(byte*, uint32, int32, int32, int32, uint32);
void sys_memclr(byte*, uint32);
void sys_setcallerpc(void*, void*);
@@ -416,7 +414,5 @@
* User go-called
*/
void sys_readfile(string, string, bool);
-void sys_bytestorune(byte*, int32, int32, int32, int32);
-void sys_stringtorune(string, int32, int32, int32);
void sys_semacquire(uint32*);
void sys_semrelease(uint32*);
diff -r 14731a6251fa -r 5df06070216e src/runtime/sema.c
--- a/src/runtime/sema.c Fri Jan 16 14:16:31 2009 -0800
+++ b/src/runtime/sema.c Fri Jan 16 14:58:14 2009 -0800
@@ -119,7 +119,7 @@
{
USED(s);
g->status = Gwaiting;
- sys·gosched();
+ sys·Gosched();
}
static int32
@@ -133,11 +133,11 @@
return 0;
}
-// func sys.semacquire(addr *uint32)
+// func sync.semacquire(addr *uint32)
// For now has no return value.
// Might return an ok (not interrupted) bool in the future?
void
-sys·semacquire(uint32 *addr)
+sync·semacquire(uint32 *addr)
{
Sema s;
@@ -163,9 +163,9 @@
semwakeup(addr);
}
-// func sys.semrelease(addr *uint32)
+// func sync.semrelease(addr *uint32)
void
-sys·semrelease(uint32 *addr)
+sync·semrelease(uint32 *addr)
{
uint32 v;
diff -r 14731a6251fa -r 5df06070216e src/runtime/sys_amd64_darwin.s
--- a/src/runtime/sys_amd64_darwin.s Fri Jan 16 14:16:31 2009 -0800
+++ b/src/runtime/sys_amd64_darwin.s Fri Jan 16 14:58:14 2009 -0800
@@ -9,7 +9,7 @@
//
// Exit the entire program (like C exit)
-TEXT sys·exit(SB),7,$-8
+TEXT sys·Exit(SB),7,$-8
MOVL 8(SP), DI // arg 1 exit status
MOVL $(0x2000000+1), AX // syscall entry
SYSCALL
diff -r 14731a6251fa -r 5df06070216e src/runtime/sys_amd64_linux.s
--- a/src/runtime/sys_amd64_linux.s Fri Jan 16 14:16:31 2009 -0800
+++ b/src/runtime/sys_amd64_linux.s Fri Jan 16 14:58:14 2009 -0800
@@ -6,7 +6,7 @@
// System calls and other sys.stuff for AMD64, Linux
//
-TEXT sys·exit(SB),7,$0-8
+TEXT sys·Exit(SB),7,$0-8
MOVL 8(SP), DI
MOVL $231, AX // exitgroup - force all os threads to exi
SYSCALL
@@ -175,12 +175,12 @@
MOVQ SI, SP
MOVQ R8, R14 // m
MOVQ R9, R15 // g
-
+
// Initialize m->procid to Linux tid
MOVL $186, AX // gettid
SYSCALL
MOVQ AX, 24(R14)
-
+
// Call fn
CALL R12
diff -r 14731a6251fa -r 5df06070216e src/runtime/sys_file.c
--- a/src/runtime/sys_file.c Fri Jan 16 14:16:31 2009 -0800
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,75 +0,0 @@
-// Copyright 2009 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.
-
-#include "runtime.h"
-#include "sys_types.h"
-
-void
-sys·readfile(string filein, string fileout, bool okout)
-{
- int32 fd;
- byte namebuf[256];
- struct stat statbuf;
-
- fileout = nil;
- okout = false;
-
- if(filein == nil || filein->len >= sizeof(namebuf))
- goto out;
-
- mcpy(namebuf, filein->str, filein->len);
- namebuf[filein->len] = '\0';
- fd = open(namebuf, 0);
- if(fd < 0)
- goto out;
-
- if (fstat(fd, &statbuf) < 0)
- goto close_out;
-
- if (statbuf.st_size <= 0)
- goto close_out;
-
- fileout = mal(sizeof(fileout->len)+statbuf.st_size + 1);
- fileout->len = statbuf.st_size;
-
- if (read(fd, fileout->str, statbuf.st_size) != statbuf.st_size) {
- fileout = nil;
- goto close_out;
- }
- okout = true;
-
-close_out:
- close(fd);
-out:
- FLUSH(&fileout);
- FLUSH(&okout);
-}
-
-void
-sys·writefile(string filein, string textin, bool okout)
-{
- int32 fd;
- byte namebuf[256];
-
- okout = false;
-
- if(filein == nil || filein->len >= sizeof(namebuf))
- goto out;
-
- mcpy(namebuf, filein->str, filein->len);
- namebuf[filein->len] = '\0';
- fd = open(namebuf, 1|O_CREAT, 0644); // open for write, create if non-existant (sic)
- if(fd < 0)
- goto out;
-
- if (write(fd, textin->str, textin->len) != textin->len) {
- goto close_out;
- }
- okout = true;
-
-close_out:
- close(fd);
-out:
- FLUSH(&okout);
-}
diff -r 14731a6251fa -r 5df06070216e test/235.go
--- a/test/235.go Fri Jan 16 14:16:31 2009 -0800
+++ b/test/235.go Fri Jan 16 14:58:14 2009 -0800
@@ -65,5 +65,5 @@
x = min(xs);
if x != OUT[i] { panic("bad: ", x, " should be ", OUT[i]); }
}
- sys.exit(0);
+ sys.Exit(0);
}
diff -r 14731a6251fa -r 5df06070216e test/args.go
--- a/test/args.go Fri Jan 16 14:16:31 2009 -0800
+++ b/test/args.go Fri Jan 16 14:58:14 2009 -0800
@@ -7,13 +7,13 @@
package main
func main() {
- if sys.argc() != 3 {
+ if len(sys.Args) != 3 {
panic("argc")
}
- if sys.argv(1) != "arg1" {
+ if sys.Args[1] != "arg1" {
panic("arg1")
}
- if sys.argv(2) != "arg2" {
+ if sys.Args[2] != "arg2" {
panic("arg2")
}
}
diff -r 14731a6251fa -r 5df06070216e test/bugs/bug130.go
--- a/test/bugs/bug130.go Fri Jan 16 14:16:31 2009 -0800
+++ b/test/bugs/bug130.go Fri Jan 16 14:58:14 2009 -0800
@@ -16,5 +16,5 @@
var i I = &s;
c := make(chan int);
go i.send(c);
- sys.exit(<-c);
+ sys.Exit(<-c);
}
diff -r 14731a6251fa -r 5df06070216e test/chan/fifo.go
--- a/test/chan/fifo.go Fri Jan 16 14:16:31 2009 -0800
+++ b/test/chan/fifo.go Fri Jan 16 14:58:14 2009 -0800
@@ -18,7 +18,7 @@
for i := 0; i < N; i++ {
if <-ch != i {
print("bad receive\n");
- sys.exit(1);
+ sys.Exit(1);
}
}
}
diff -r 14731a6251fa -r 5df06070216e test/chan/goroutines.go
--- a/test/chan/goroutines.go Fri Jan 16 14:16:31 2009 -0800
+++ b/test/chan/goroutines.go Fri Jan 16 14:58:14 2009 -0800
@@ -20,12 +20,12 @@
func main() {
var n = 10000;
- if sys.argc() > 1 {
+ if len(sys.Args) > 1 {
var err *os.Error;
- n, err = strconv.Atoi(sys.argv(1));
+ n, err = strconv.Atoi(sys.Args[1]);
if err != nil {
print("bad arg\n");
- sys.exit(1);
+ sys.Exit(1);
}
}
leftmost := make(chan int);
diff -r 14731a6251fa -r 5df06070216e test/chan/nonblock.go
--- a/test/chan/nonblock.go Fri Jan 16 14:16:31 2009 -0800
+++ b/test/chan/nonblock.go Fri Jan 16 14:58:14 2009 -0800
@@ -10,7 +10,7 @@
package main
func pause() {
- for i:=0; i<100; i++ { sys.gosched() }
+ for i:=0; i<100; i++ { sys.Gosched() }
}
func i32receiver(c chan int32) {
diff -r 14731a6251fa -r 5df06070216e test/chan/powser1.go
--- a/test/chan/powser1.go Fri Jan 16 14:16:31 2009 -0800
+++ b/test/chan/powser1.go Fri Jan 16 14:58:14 2009 -0800
@@ -630,7 +630,7 @@
func main() {
Init();
- if sys.argc() > 1 { // print
+ if len(sys.Args) > 1 { // print
print("Ones: "); Printn(Ones, 10);
print("Twos: "); Printn(Twos, 10);
print("Add: "); Printn(Add(Ones, Twos), 10);
@@ -708,5 +708,5 @@
checka(t, a, "Tan"); // 0 1 0 1/3 0 2/15
*/
}
- sys.exit(0); // BUG: force waiting goroutines to exit
+ sys.Exit(0); // BUG: force waiting goroutines to exit
}
diff -r 14731a6251fa -r 5df06070216e test/chan/powser2.go
--- a/test/chan/powser2.go Fri Jan 16 14:16:31 2009 -0800
+++ b/test/chan/powser2.go Fri Jan 16 14:58:14 2009 -0800
@@ -635,7 +635,7 @@
func main() {
Init();
- if sys.argc() > 1 { // print
+ if len(sys.Args) > 1 { // print
print("Ones: "); Printn(Ones, 10);
print("Twos: "); Printn(Twos, 10);
print("Add: "); Printn(Add(Ones, Twos), 10);
@@ -713,5 +713,5 @@
checka(t, a, "Tan"); // 0 1 0 1/3 0 2/15
*/
}
- sys.exit(0); // BUG: force waiting goroutines to exit
+ sys.Exit(0); // BUG: force waiting goroutines to exit
}
diff -r 14731a6251fa -r 5df06070216e test/chan/sieve.go
--- a/test/chan/sieve.go Fri Jan 16 14:16:31 2009 -0800
+++ b/test/chan/sieve.go Fri Jan 16 14:58:14 2009 -0800
@@ -47,5 +47,5 @@
for i := 0; i < len(a); i++ {
if <-primes != a[i] { panic(a[i])}
}
- sys.exit(0);
+ sys.Exit(0);
}
diff -r 14731a6251fa -r 5df06070216e test/char_lit.go
--- a/test/char_lit.go Fri Jan 16 14:16:31 2009 -0800
+++ b/test/char_lit.go Fri Jan 16 14:58:14 2009 -0800
@@ -33,10 +33,10 @@
;
if '\Ucafebabe' != 0xcafebabe {
print("cafebabe wrong\n");
- sys.exit(1)
+ sys.Exit(1)
}
if i != 0xcc238de1 {
print("number is ", i, " should be ", 0xcc238de1, "\n");
- sys.exit(1)
+ sys.Exit(1)
}
}
diff -r 14731a6251fa -r 5df06070216e test/env.go
--- a/test/env.go Fri Jan 16 14:16:31 2009 -0800
+++ b/test/env.go Fri Jan 16 14:58:14 2009 -0800
@@ -12,15 +12,15 @@
ga, e0 := os.Getenv("GOARCH");
if e0 != nil {
print("$GOARCH: ", e0.String(), "\n");
- sys.exit(1);
+ sys.Exit(1);
}
if ga != "amd64" {
print("$GOARCH=", ga, "\n");
- sys.exit(1);
+ sys.Exit(1);
}
xxx, e1 := os.Getenv("DOES_NOT_EXIST");
if e1 != os.ENOENV {
print("$DOES_NOT_EXIST=", xxx, "; err = ", e1.String(), "\n");
- sys.exit(1);
+ sys.Exit(1);
}
}
diff -r 14731a6251fa -r 5df06070216e test/fixedbugs/bug006.go
--- a/test/fixedbugs/bug006.go Fri Jan 16 14:16:31 2009 -0800
+++ b/test/fixedbugs/bug006.go Fri Jan 16 14:58:14 2009 -0800
@@ -13,5 +13,5 @@
func main() {
if g == 0.0 { print("zero\n");}
- if g != 4.5 { print(" fail\n"); sys.exit(1); }
+ if g != 4.5 { print(" fail\n"); sys.Exit(1); }
}
diff -r 14731a6251fa -r 5df06070216e test/fixedbugs/bug059.go
--- a/test/fixedbugs/bug059.go Fri Jan 16 14:16:31 2009 -0800
+++ b/test/fixedbugs/bug059.go Fri Jan 16 14:58:14 2009 -0800
@@ -29,6 +29,6 @@
a[0] = "x";
m["0"][0] = "deleted";
if m["0"][0] != "deleted" {
- sys.exit(1);
+ sys.Exit(1);
}
}
diff -r 14731a6251fa -r 5df06070216e test/fixedbugs/bug060.go
--- a/test/fixedbugs/bug060.go Fri Jan 16 14:16:31 2009 -0800
+++ b/test/fixedbugs/bug060.go Fri Jan 16 14:58:14 2009 -0800
@@ -12,6 +12,6 @@
m[0]++;
if m[0] != 1 {
print("map does not increment\n");
- sys.exit(1)
+ sys.Exit(1)
}
}
diff -r 14731a6251fa -r 5df06070216e test/fixedbugs/bug097.go
--- a/test/fixedbugs/bug097.go Fri Jan 16 14:16:31 2009 -0800
+++ b/test/fixedbugs/bug097.go Fri Jan 16 14:58:14 2009 -0800
@@ -30,8 +30,8 @@
pc: 0x4558
0x4558?zi
- sys·breakpoint(40960, 0, 45128, ...)
- sys·breakpoint(0xa000, 0xb048, 0xa000, ...)
+ sys·Breakpoint(40960, 0, 45128, ...)
+ sys·Breakpoint(0xa000, 0xb048, 0xa000, ...)
0x156a?zi
sys·panicl(342, 0, 0, ...)
sys·panicl(0x156, 0x300000000, 0xb024, ...)
diff -r 14731a6251fa -r 5df06070216e test/fixedbugs/bug120.go
--- a/test/fixedbugs/bug120.go Fri Jan 16 14:16:31 2009 -0800
+++ b/test/fixedbugs/bug120.go Fri Jan 16 14:58:14 2009 -0800
@@ -53,6 +53,6 @@
}
}
if !ok {
- sys.exit(1);
+ sys.Exit(1);
}
}
diff -r 14731a6251fa -r 5df06070216e test/if1.go
--- a/test/if1.go Fri Jan 16 14:16:31 2009 -0800
+++ b/test/if1.go Fri Jan 16 14:58:14 2009 -0800
@@ -9,10 +9,10 @@
func main() {
count := 7;
if one := 1; {
- count = count + one
+ count = count + one
}
if count != 8 {
print(count, " should be 8\n");
- sys.exit(1)
+ sys.Exit(1)
}
}
diff -r 14731a6251fa -r 5df06070216e test/int_lit.go
--- a/test/int_lit.go Fri Jan 16 14:16:31 2009 -0800
+++ b/test/int_lit.go Fri Jan 16 14:58:14 2009 -0800
@@ -7,7 +7,7 @@
package main
func main() {
- s :=
+ s :=
0 +
123 +
0123 +
@@ -18,6 +18,6 @@
0X123;
if s != 788 {
print("s is ", s, "; should be 788\n");
- sys.exit(1);
+ sys.Exit(1);
}
}
diff -r 14731a6251fa -r 5df06070216e test/interface4.go
--- a/test/interface4.go Fri Jan 16 14:16:31 2009 -0800
+++ b/test/interface4.go Fri Jan 16 14:58:14 2009 -0800
@@ -70,6 +70,6 @@
nonptrs();
if bad {
- sys.exit(1)
+ sys.Exit(1)
}
}
diff -r 14731a6251fa -r 5df06070216e test/interface6.go
--- a/test/interface6.go Fri Jan 16 14:16:31 2009 -0800
+++ b/test/interface6.go Fri Jan 16 14:58:14 2009 -0800
@@ -145,6 +145,6 @@
f11();
f12();
if fail > 0 {
- sys.exit(1)
+ sys.Exit(1)
}
}
diff -r 14731a6251fa -r 5df06070216e test/ken/chan.go
--- a/test/ken/chan.go Fri Jan 16 14:16:31 2009 -0800
+++ b/test/ken/chan.go Fri Jan 16 14:58:14 2009 -0800
@@ -88,7 +88,7 @@
nproc++; // total goroutines running
for {
for r:=nrand(10); r>=0; r-- {
- sys.gosched();
+ sys.Gosched();
}
c.sc <- c.sv;
if c.send() {
@@ -119,7 +119,7 @@
nproc++; // total goroutines running
for {
for r:=nrand(10); r>=0; r-- {
- sys.gosched();
+ sys.Gosched();
}
v = <-c.rc;
if c.recv(v) {
@@ -148,7 +148,7 @@
for {
for r:=nrand(5); r>=0; r-- {
- sys.gosched();
+ sys.Gosched();
}
select {
@@ -270,9 +270,9 @@
func
wait()
{
- sys.gosched();
+ sys.Gosched();
for nproc != 0 {
- sys.gosched();
+ sys.Gosched();
}
}
@@ -321,7 +321,7 @@
if tots != t || totr != t {
print("tots=", tots, " totr=", totr, " sb=", t, "\n");
- sys.exit(1);
+ sys.Exit(1);
}
- sys.exit(0);
+ sys.Exit(0);
}
diff -r 14731a6251fa -r 5df06070216e test/readfile.go
--- a/test/readfile.go Fri Jan 16 14:16:31 2009 -0800
+++ b/test/readfile.go Fri Jan 16 14:58:14 2009 -0800
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// $G $F.go && $L $F.$A && ./$A.out readfile.go
+// # $G $F.go && $L $F.$A && ./$A.out readfile.go
// # This is some data we can recognize
package main
@@ -14,7 +14,7 @@
s, ok = sys.readfile("readfile.go");
if !ok {
print("couldn't readfile\n");
- sys.exit(1)
+ sys.Exit(1)
}
start_of_file :=
"// $G $F.go && $L $F.$A && ./$A.out readfile.go\n" +
@@ -23,6 +23,6 @@
"package main\n";
if s[0:102] != start_of_file {
print("wrong data\n");
- sys.exit(1)
+ sys.Exit(1)
}
}
diff -r 14731a6251fa -r 5df06070216e test/string_lit.go
--- a/test/string_lit.go Fri Jan 16 14:16:31 2009 -0800
+++ b/test/string_lit.go Fri Jan 16 14:58:14 2009 -0800
@@ -43,7 +43,7 @@
"本"
"\a\b\f\n\r\t\v\\\""
"\000\123\x00\xca\xFE\u0123\ubabe\U0000babe"
-
+
``
` `
`'"`
@@ -84,5 +84,5 @@
r = 0x10ffff + 1;
s = string(r);
assert(s, "\xef\xbf\xbd", "too-large rune");
- sys.exit(ecode);
+ sys.Exit(ecode);
}
diff -r 14731a6251fa -r 5df06070216e test/switch1.go
--- a/test/switch1.go Fri Jan 16 14:16:31 2009 -0800
+++ b/test/switch1.go Fri Jan 16 14:58:14 2009 -0800
@@ -10,9 +10,9 @@
i := 0;
switch x := 5; {
case i < x:
- sys.exit(0);
+ sys.Exit(0);
case i == x:
case i > x:
- sys.exit(1);
+ sys.Exit(1);
}
}
diff -r 14731a6251fa -r 5df06070216e test/utf.go
--- a/test/utf.go Fri Jan 16 14:16:31 2009 -0800
+++ b/test/utf.go Fri Jan 16 14:58:14 2009 -0800
@@ -6,6 +6,8 @@
package main
+import "utf8"
+
func main() {
var chars [6] int;
chars[0] = 'a';
@@ -21,7 +23,7 @@
var l = len(s);
for w, i, j := 0,0,0; i < l; i += w {
var r int;
- r, w = sys.stringtorune(s, i);
+ r, w = utf8.DecodeRuneInString(s, i);
if w == 0 { panic("zero width in string") }
if r != chars[j] { panic("wrong value from string") }
j++;
@@ -29,7 +31,7 @@
// encoded as bytes: 'a' 'b' 'c' e6 97 a5 e6 9c ac e8 aa 9e
const L = 12;
if L != l { panic("wrong length constructing array") }
- a := new([L]byte);
+ a := make([]byte, L);
a[0] = 'a';
a[1] = 'b';
a[2] = 'c';
@@ -44,7 +46,7 @@
a[11] = 0x9e;
for w, i, j := 0,0,0; i < L; i += w {
var r int;
- r, w = sys.bytestorune(&a[0], i, L);
+ r, w = utf8.DecodeRune(a[i:L]);
if w == 0 { panic("zero width in bytes") }
if r != chars[j] { panic("wrong value from bytes") }
j++;
diff -r 14731a6251fa -r 5df06070216e usr/gri/gosrc/compilation.go
--- a/usr/gri/gosrc/compilation.go Fri Jan 16 14:16:31 2009 -0800
+++ b/usr/gri/gosrc/compilation.go Fri Jan 16 14:58:14 2009 -0800
@@ -23,7 +23,7 @@
func LineCol(src string, pos int) (line, col int) {
line = 1;
lpos := 0;
-
+
if pos > len(src) {
pos = len(src);
}
@@ -34,7 +34,7 @@
lpos = i;
}
}
-
+
return line, pos - lpos;
}
@@ -60,9 +60,9 @@
comp.nerrors++;
comp.errpos = pos;
}
-
+
if comp.nerrors >= 10 {
- sys.exit(1);
+ sys.Exit(1);
}
}
@@ -135,7 +135,7 @@
// calling this function recursively w/o setting up a new comp - this
// is broken and leads to an assertion error (more then one package
// upon parsing of the package header).
-
+
src, ok := Platform.ReadSourceFile(src_file);
if !ok {
print("cannot open ", src_file, "\n");
@@ -144,7 +144,7 @@
comp.src_file = src_file;
comp.src = src;
-
+
if comp.flags.verbosity > 0 {
print(src_file, "\n");
}
diff -r 14731a6251fa -r 5df06070216e usr/gri/gosrc/go.go
--- a/usr/gri/gosrc/go.go Fri Jan 16 14:16:31 2009 -0800
+++ b/usr/gri/gosrc/go.go Fri Jan 16 14:58:14 2009 -0800
@@ -28,8 +28,8 @@
var argno int = 1;
func Next() string {
arg := "";
- if argno < sys.argc() {
- arg = sys.argv(argno);
+ if argno < len(sys.Args) {
+ arg = sys.Args[argno];
argno++;
}
return arg;
diff -r 14731a6251fa -r 5df06070216e usr/gri/gosrc/scanner.go
--- a/usr/gri/gosrc/scanner.go Fri Jan 16 14:16:31 2009 -0800
+++ b/usr/gri/gosrc/scanner.go Fri Jan 16 14:58:14 2009 -0800
@@ -401,7 +401,7 @@
}
if S.nerrors >= 10 {
- sys.exit(1);
+ sys.Exit(1);
}
}
@@ -601,7 +601,7 @@
}
S.Error(pos, "illegal char escape");
}
-
+
return ""; // TODO fix this
}
diff -r 14731a6251fa -r 5df06070216e usr/gri/gosrc/test_scanner.go
--- a/usr/gri/gosrc/test_scanner.go Fri Jan 16 14:16:31 2009 -0800
+++ b/usr/gri/gosrc/test_scanner.go Fri Jan 16 14:58:14 2009 -0800
@@ -46,18 +46,18 @@
func main() {
- for i := 1; i < sys.argc(); i++ {
+ for i := 1; i < len(sys.Args); i++ {
var src string;
var ok bool;
- src, ok = sys.readfile(sys.argv(i));
+ src, ok = sys.readfile(sys.Args[i]);
if ok {
- print("scanning (standard) " + sys.argv(i) + "\n");
- Scan1(sys.argv(i), src);
+ print("scanning (standard) " + sys.Args[i] + "\n");
+ Scan1(sys.Args[i], src);
print("\n");
- print("scanning (channels) " + sys.argv(i) + "\n");
- Scan2(sys.argv(i), src);
+ print("scanning (channels) " + sys.Args[i] + "\n");
+ Scan2(sys.Args[i], src);
} else {
- print("error: cannot read " + sys.argv(i) + "\n");
+ print("error: cannot read " + sys.Args[i] + "\n");
}
print("\n");
}
diff -r 14731a6251fa -r 5df06070216e usr/gri/pretty/compilation.go
--- a/usr/gri/pretty/compilation.go Fri Jan 16 14:16:31 2009 -0800
+++ b/usr/gri/pretty/compilation.go Fri Jan 16 14:58:14 2009 -0800
@@ -92,7 +92,7 @@
if h.nerrors >= 10 {
// TODO enable when done with name convention
- //sys.exit(1);
+ //sys.Exit(1);
}
}
diff -r 14731a6251fa -r 5df06070216e usr/gri/pretty/platform.go
--- a/usr/gri/pretty/platform.go Fri Jan 16 14:16:31 2009 -0800
+++ b/usr/gri/pretty/platform.go Fri Jan 16 14:58:14 2009 -0800
@@ -4,6 +4,8 @@
package Platform
+import IO "io"
+import OS "os"
import Utils "utils"
@@ -16,24 +18,13 @@
GOROOT,
USER string;
+func init() {
+ var e *OS.Error;
-func getEnv(key string) string {
- n := len(key);
- for i := 0; i < sys.envc(); i++ {
- v := sys.envv(i);
- if n < len(v) && v[0 : n] == key && v[n] == '=' {
- return v[n + 1 : len(v)]; // +1: trim "="
- }
- }
- return "";
-}
-
-
-func init() {
- GOARCH = getEnv("GOARCH");
- GOOS = getEnv("GOOS");
- GOROOT = getEnv("GOROOT");
- USER = getEnv("USER");
+ GOARCH, e = OS.Getenv("GOARCH");
+ GOOS, e = OS.Getenv("GOOS");
+ GOROOT, e = OS.Getenv("GOROOT");
+ USER, e = OS.Getenv("USER");
}
@@ -46,25 +37,48 @@
Obj_file_ext = ".7";
)
+func readfile(filename string) (string, *OS.Error) {
+ fd, err := OS.Open(filename, OS.O_RDONLY, 0);
+ if err != nil {
+ return "", err;
+ }
+ var buf [1<<20]byte;
+ n, err1 := IO.Readn(fd, buf);
+ fd.Close();
+ if err1 == IO.ErrEOF {
+ err1 = nil;
+ }
+ return string(buf[0:n]), err1;
+}
-export func ReadObjectFile(filename string) (data string, ok bool) {
- data, ok = sys.readfile(filename + Obj_file_ext);
+func writefile(name, data string) *OS.Error {
+ fd, err := OS.Open(name, OS.O_WRONLY, 0);
+ if err != nil {
+ return err;
+ }
+ n, err1 := IO.WriteString(fd, data);
+ fd.Close();
+ return err1;
+}
+
+export func ReadObjectFile(filename string) (string, bool) {
+ data, err := readfile(filename + Obj_file_ext);
magic := MAGIC_obj_file; // TODO remove once len(constant) works
- if ok && len(data) >= len(magic) && data[0 : len(magic)] == magic {
- return data, ok;
+ if err == nil && len(data) >= len(magic) && data[0 : len(magic)] == magic {
+ return data, true;
}
return "", false;
}
-export func ReadSourceFile(name string) (data string, ok bool) {
+export func ReadSourceFile(name string) (string, bool) {
name = Utils.TrimExt(name, Src_file_ext) + Src_file_ext;
- data, ok = sys.readfile(name);
- return data, ok;
+ data, err := readfile(name);
+ return data, err == nil;
}
export func WriteObjectFile(name string, data string) bool {
name = Utils.TrimExt(Utils.BaseName(name), Src_file_ext) + Obj_file_ext;
- return sys.writefile(name, data);
+ return writefile(name, data) != nil;
}
diff -r 14731a6251fa -r 5df06070216e usr/gri/pretty/pretty.go
--- a/usr/gri/pretty/pretty.go Fri Jan 16 14:16:31 2009 -0800
+++ b/usr/gri/pretty/pretty.go Fri Jan 16 14:58:14 2009 -0800
@@ -32,13 +32,13 @@
func usage() {
print("usage: pretty { flags } { files }\n");
Flag.PrintDefaults();
- sys.exit(0);
+ sys.Exit(0);
}
func main() {
Flag.Parse();
-
+
if Flag.NFlag() == 0 && Flag.NArg() == 0 {
usage();
}
@@ -49,7 +49,7 @@
if false /* DISABLED flags.deps */ {
Compilation.ComputeDeps(src_file, &flags);
-
+
} else {
prog, nerrors := Compilation.Compile(src_file, &flags);
if nerrors > 0 {
diff -r 14731a6251fa -r 5df06070216e usr/gri/pretty/untab.go
--- a/usr/gri/pretty/untab.go Fri Jan 16 14:16:31 2009 -0800
+++ b/usr/gri/pretty/untab.go Fri Jan 16 14:58:14 2009 -0800
@@ -21,7 +21,7 @@
func error(format string, params ...) {
fmt.Printf(format, params);
- sys.exit(1);
+ sys.Exit(1);
}
changeset: 1549:de63148af56a
user: Ken Thompson <[email protected]>
date: Sat Jan 24 15:58:44 2009 -0800
summary: bug in async select read
diff -r dd923c91b506 -r de63148af56a src/runtime/chan.c
--- a/src/runtime/chan.c Fri Jan 23 17:04:56 2009 -0800
+++ b/src/runtime/chan.c Sat Jan 24 15:58:44 2009 -0800
@@ -5,6 +5,7 @@
#include "runtime.h"
static int32 debug = 0;
+static int32 xxx = 0;
static Lock chanlock;
typedef struct Hchan Hchan;
@@ -17,8 +18,9 @@
struct SudoG
{
G* g; // g and selgen constitute
+ int32 selgen; // a weak pointer to g
int16 offset; // offset of case number
- int32 selgen; // a weak pointer to g
+ int8 isfree; // offset of case number
SudoG* link;
byte elem[8]; // synch data element (+ more)
};
@@ -206,7 +208,6 @@
return;
asynch:
-//prints("\nasend\n");
while(c->qcount >= c->dataqsiz) {
if(pres != nil) {
unlock(&chanlock);
@@ -229,10 +230,8 @@
sg = dequeue(&c->recvq, c);
if(sg != nil) {
gp = sg->g;
- gp->param = sg;
freesg(c, sg);
unlock(&chanlock);
-//prints("wakeup\n");
ready(gp);
} else
unlock(&chanlock);
@@ -312,7 +311,6 @@
sg = dequeue(&c->sendq, c);
if(sg != nil) {
gp = sg->g;
- gp->param = sg;
freesg(c, sg);
unlock(&chanlock);
ready(gp);
@@ -411,7 +409,7 @@
if(debug) {
prints("newselect s=");
sys·printpointer(sel);
- prints("newselect size=");
+ prints(" size=");
sys·printint(size);
prints("\n");
}
@@ -451,7 +449,7 @@
c->elemalg->copy(c->elemsize, cas->u.elem, ae);
if(debug) {
- prints("newselect s=");
+ prints("selectsend s=");
sys·printpointer(sel);
prints(" pc=");
sys·printpointer(cas->pc);
@@ -495,7 +493,7 @@
cas->u.elemp = *(byte**)((byte*)&sel + eo);
if(debug) {
- prints("newselect s=");
+ prints("selectrecv s=");
sys·printpointer(sel);
prints(" pc=");
sys·printpointer(cas->pc);
@@ -510,7 +508,7 @@
}
-// selectrecv(sel *byte) (selected bool);
+// selectdefaul(sel *byte) (selected bool);
void
sys·selectdefault(Select *sel, ...)
{
@@ -534,7 +532,7 @@
cas->u.elemp = nil;
if(debug) {
- prints("newselect s=");
+ prints("selectdefault s=");
sys·printpointer(sel);
prints(" pc=");
sys·printpointer(cas->pc);
@@ -546,7 +544,6 @@
}
}
-uint32 xxx = 0;
// selectgo(sel *byte);
void
@@ -589,6 +586,7 @@
lock(&chanlock);
+loop:
// pass 1 - look for something already waiting
dfl = nil;
for(i=0; i<sel->ncase; i++) {
@@ -688,16 +686,25 @@
o -= sel->ncase;
}
+ g->param = nil;
g->status = Gwaiting;
unlock(&chanlock);
sys·Gosched();
lock(&chanlock);
sg = g->param;
+ if(sg == nil)
+ goto loop;
+
o = sg->offset;
cas = sel->scase[o];
c = cas->chan;
+ if(c->dataqsiz > 0) {
+// prints("shouldnt happen\n");
+ goto loop;
+ }
+
if(xxx) {
prints("wait-return: sel=");
sys·printpointer(sel);
@@ -712,12 +719,6 @@
prints("\n");
}
- if(c->dataqsiz > 0) {
- if(cas->send)
- goto asyns;
- goto asynr;
- }
-
if(!cas->send) {
if(cas->u.elemp != nil)
c->elemalg->copy(c->elemsize, cas->u.elemp, sg->elem);
@@ -734,7 +735,6 @@
sg = dequeue(&c->sendq, c);
if(sg != nil) {
gp = sg->g;
- gp->param = sg;
freesg(c, sg);
ready(gp);
}
@@ -748,7 +748,6 @@
sg = dequeue(&c->recvq, c);
if(sg != nil) {
gp = sg->g;
- gp->param = sg;
freesg(c, sg);
ready(gp);
}
@@ -849,6 +848,7 @@
sg->selgen = g->selgen;
sg->g = g;
sg->offset = 0;
+ sg->isfree = 0;
return sg;
}
@@ -856,6 +856,9 @@
static void
freesg(Hchan *c, SudoG *sg)
{
+ if(sg->isfree)
+ throw("chan.freesg: already free");
+ sg->isfree = 1;
sg->link = c->free;
c->free = sg;
}
changeset: 1552:82a994c54141
user: Russ Cox <[email protected]>
date: Mon Jan 26 09:56:42 2009 -0800
summary: implement new restrictions on what
diff -r 346466330152 -r 82a994c54141 src/cmd/gc/go.h
--- a/src/cmd/gc/go.h Mon Jan 26 09:34:19 2009 -0800
+++ b/src/cmd/gc/go.h Mon Jan 26 09:56:42 2009 -0800
@@ -37,13 +37,12 @@
PRIME10 = 10093,
AUNK = 100,
+
// these values are known by runtime
- ASIMP = 0,
+ AMEM = 0,
+ ANOEQ,
ASTRING,
- APTR,
AINTER,
- ASLICE,
- ASTRUCT,
BADWIDTH = -1000000000
};
diff -r 346466330152 -r 82a994c54141 src/cmd/gc/subr.c
--- a/src/cmd/gc/subr.c Mon Jan 26 09:34:19 2009 -0800
+++ b/src/cmd/gc/subr.c Mon Jan 26 09:56:42 2009 -0800
@@ -291,26 +291,16 @@
{
int a;
- a = AUNK;
- if(issimple[t->etype])
- a = ASIMP; // simple mem
+ if(issimple[t->etype] || isptr[t->etype] || t->etype == TCHAN)
+ a = AMEM; // just bytes (int, ptr, etc)
else
if(t->etype == TSTRING)
a = ASTRING; // string
else
- if(isptr[simtype[t->etype]])
- a = APTR; // pointer
+ if(t->etype == TINTER)
+ a = AINTER; // interface
else
- if(isslice(t))
- a = ASLICE;
- else
- if(t->etype == TSTRUCT)
- a = ASTRUCT;
- else
- if(isinter(t))
- a = AINTER; // interface
-// else
-// fatal("algtype: cant find type %T", t);
+ a = ANOEQ; // just bytes, but no hash/eq
return a;
}
diff -r 346466330152 -r 82a994c54141 src/runtime/chan.c
--- a/src/runtime/chan.c Mon Jan 26 09:34:19 2009 -0800
+++ b/src/runtime/chan.c Mon Jan 26 09:56:42 2009 -0800
@@ -88,17 +88,9 @@
Hchan *c;
int32 i;
- switch(elemalg){
- case ASIMP:
- case ASTRING:
- case APTR:
- case AINTER:
- case AARRAY:
- case ASTRUCT:
- break;
- default:
+ if(elemalg >= nelem(algarray)) {
printf("chan(alg=%d)\n", elemalg);
- throw("sys·newchan: unsupported channel element type");
+ throw("sys·newchan: unsupported elem type");
}
c = mal(sizeof(*c));
diff -r 346466330152 -r 82a994c54141 src/runtime/hashmap.c
--- a/src/runtime/hashmap.c Mon Jan 26 09:34:19 2009 -0800
+++ b/src/runtime/hashmap.c Mon Jan 26 09:56:42 2009 -0800
@@ -663,28 +663,12 @@
{
Hmap *h;
- switch(keyalg) {
- case ASIMP:
- case ASTRING:
- case APTR:
- case AINTER:
- case AARRAY:
- case ASTRUCT:
- break;
- default:
+ if(keyalg >= nelem(algarray) || algarray[keyalg].hash == nohash) {
printf("map(keyalg=%d)\n", keyalg);
throw("sys·newmap: unsupported map key type");
}
- switch(valalg) {
- case ASIMP:
- case ASTRING:
- case APTR:
- case AINTER:
- case AARRAY:
- case ASTRUCT:
- break;
- default:
+ if(valalg >= nelem(algarray)) {
printf("map(valalg=%d)\n", valalg);
throw("sys·newmap: unsupported map value type");
}
diff -r 346466330152 -r 82a994c54141 src/runtime/iface.c
--- a/src/runtime/iface.c Mon Jan 26 09:34:19 2009 -0800
+++ b/src/runtime/iface.c Mon Jan 26 09:56:42 2009 -0800
@@ -404,11 +404,32 @@
FLUSH(&ok);
}
-// ifaceeq(i1 any, i2 any) (ret bool);
-void
-sys·ifaceeq(Iface i1, Iface i2, bool ret)
+uint64
+ifacehash(Iface a)
{
int32 alg, wid;
+
+ if(a.type == nil)
+ return 0;
+ alg = a.type->sigt->hash;
+ wid = a.type->sigt->offset;
+ if(algarray[alg].hash == nohash) {
+ // calling nohash will throw too,
+ // but we can print a better error.
+ printf("hash of unhashable type %s\n", a.type->sigt->name);
+ throw("interface hash");
+ }
+ if(wid <= sizeof a.data)
+ return algarray[alg].hash(wid, &a.data);
+ else
+ return algarray[alg].hash(wid, a.data);
+}
+
+bool
+ifaceeq(Iface i1, Iface i2)
+{
+ int32 alg, wid;
+ bool ret;
if(iface_debug) {
prints("Ieq i1=");
@@ -438,6 +459,13 @@
if(wid != i2.type->sigt->offset)
goto no;
+ if(algarray[alg].equal == noequal) {
+ // calling noequal will throw too,
+ // but we can print a better error.
+ printf("comparing uncomparable type %s\n", i1.type->sigt->name);
+ throw("interface compare");
+ }
+
if(wid <= sizeof i1.data) {
if(!algarray[alg].equal(wid, &i1.data, &i2.data))
goto no;
@@ -454,6 +482,14 @@
sys·printbool(ret);
prints("\n");
}
+ return ret;
+}
+
+// ifaceeq(i1 any, i2 any) (ret bool);
+void
+sys·ifaceeq(Iface i1, Iface i2, bool ret)
+{
+ ret = ifaceeq(i1, i2);
FLUSH(&ret);
}
@@ -526,7 +562,7 @@
sigt = mal(2*sizeof sigt[0]);
sigt[0].name = mal(type->len + 1);
mcpy(sigt[0].name, type->str, type->len);
- sigt[0].hash = ASIMP; // alg
+ sigt[0].hash = AMEM; // alg
if(indir)
sigt[0].offset = 2*sizeof(niliface.data); // big width
else
diff -r 346466330152 -r 82a994c54141 src/runtime/runtime.c
--- a/src/runtime/runtime.c Mon Jan 26 09:34:19 2009 -0800
+++ b/src/runtime/runtime.c Mon Jan 26 09:56:42 2009 -0800
@@ -328,57 +328,52 @@
sys·printstring(*a);
}
-static void
-strcopy(uint32 s, string *a, string *b)
+static uint64
+interhash(uint32 s, Iface *a)
{
USED(s);
- if(b == nil) {
- *a = nil;
- return;
- }
- *a = *b;
+ return ifacehash(*a);
}
-static uint64
-ptrhash(uint32 s, void **a)
+static void
+interprint(uint32 s, Iface *a)
{
- return memhash(s, *a);
+ USED(s);
+ sys·printinter(*a);
}
static uint32
-ptrequal(uint32 s, void **a, void **b)
+interequal(uint32 s, Iface *a, Iface *b)
{
- USED(s, a, b);
- prints("ptrequal\n");
+ USED(s);
+ return ifaceeq(*a, *b);
+}
+
+uint64
+nohash(uint32 s, void *a)
+{
+ USED(s);
+ USED(a);
+ throw("hash of unhashable type");
return 0;
}
-static void
-ptrprint(uint32 s, void **a)
-{
- USED(s, a);
- prints("ptrprint\n");
-}
-
-static void
-ptrcopy(uint32 s, void **a, void **b)
+uint32
+noequal(uint32 s, void *a, void *b)
{
USED(s);
- if(b == nil) {
- *a = nil;
- return;
- }
- *a = *b;
+ USED(a);
+ USED(b);
+ throw("comparing uncomparable types");
+ return 0;
}
Alg
algarray[] =
{
-[ASIMP] { memhash, memequal, memprint, memcopy },
-[ASTRING] { strhash, strequal, strprint, strcopy },
-[APTR] { memhash, memequal, memprint, memcopy }, // TODO: ptr routines
-[AINTER] { memhash, memequal, memprint, memcopy }, // TODO: interface routines
-[ASTRUCT] { memhash, memequal, memprint, memcopy }, // TODO: what goes here?
-[AARRAY] { memhash, memequal, memprint, memcopy }, // TODO: what goes here?
+[AMEM] { memhash, memequal, memprint, memcopy },
+[ANOEQ] { nohash, noequal, memprint, memcopy },
+[ASTRING] { strhash, strequal, strprint, memcopy },
+[AINTER] { interhash, interequal, interprint, memcopy },
};
diff -r 346466330152 -r 82a994c54141 src/runtime/runtime.h
--- a/src/runtime/runtime.h Mon Jan 26 09:34:19 2009 -0800
+++ b/src/runtime/runtime.h Mon Jan 26 09:56:42 2009 -0800
@@ -226,18 +226,17 @@
*/
enum
{
- ASIMP = 0,
+ AMEM,
+ ANOEQ,
ASTRING,
- APTR,
AINTER,
- AARRAY,
- ASTRUCT,
+ Amax
};
/*
* external data
*/
-extern Alg algarray[];
+extern Alg algarray[Amax];
extern string emptystring;
G* allg;
int32 goidgen;
@@ -299,6 +298,10 @@
void stackfree(void*);
MCache* allocmcache(void);
void mallocinit(void);
+bool ifaceeq(Iface, Iface);
+uint64 ifacehash(Iface);
+uint64 nohash(uint32, void*);
+uint32 noequal(uint32, void*, void*);
#pragma varargck argpos printf 1
@@ -366,6 +369,7 @@
#define sys_printfloat sys·printfloat
#define sys_printhex sys·printhex
#define sys_printint sys·printint
+#define sys_printinter sys·printinter
#define sys_printpc sys·printpc
#define sys_printpointer sys·printpointer
#define sys_printstring sys·printstring
@@ -393,6 +397,7 @@
void sys_printbool(bool);
void sys_printfloat(float64);
void sys_printint(int64);
+void sys_printinter(Iface);
void sys_printstring(string);
void sys_printpc(void*);
void sys_printpointer(void*);
diff -r 346466330152 -r 82a994c54141 test/bigalg.go
--- a/test/bigalg.go Mon Jan 26 09:34:19 2009 -0800
+++ b/test/bigalg.go Mon Jan 26 09:56:42 2009 -0800
@@ -62,25 +62,6 @@
}
}
-var mt1 = make(map[T]int)
-var ma1 = make(map[[]int] int)
-
-func maptest2() {
- mt1[t] = 123;
- t1 := t;
- val, ok := mt1[t1];
- if val != 123 || !ok {
- println("fail: map key struct", val, ok);
- }
-
- ma1[a] = 345;
- a1 := a;
- val, ok = ma1[a1];
- if val != 345 || !ok {
- panic("map key array", val, ok);
- }
-}
-
var ct = make(chan T)
var ca = make(chan []int)
@@ -136,7 +117,6 @@
func main() {
arraycmptest();
maptest();
- maptest2();
chantest();
interfacetest();
}
diff -r 346466330152 -r 82a994c54141 test/cmp1.go
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/cmp1.go Mon Jan 26 09:56:42 2009 -0800
@@ -0,0 +1,66 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 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 main
+
+import "unsafe"
+
+func use(bool) { }
+
+func stringptr(s string) uintptr {
+ return *(&s).(unsafe.Pointer).(*uintptr);
+}
+
+func isfalse(b bool) {
+ if b { panicln("wanted false, got true") } // stack will explain where
+}
+
+func istrue(b bool) {
+ if !b { panicln("wanted true, got false") } // stack will explain where
+}
+
+func main()
+{
+ var a []int;
+ var b map[string]int;
+
+ var c string = "hello";
+ var d string = "hel"; // try to get different pointer
+ d = d + "lo";
+ if stringptr(c) == stringptr(d) {
+ panic("compiler too smart -- got same string")
+ }
+
+ var e = make(chan int);
+
+ var ia interface{} = a;
+ var ib interface{} = b;
+ var ic interface{} = c;
+ var id interface{} = d;
+ var ie interface{} = e;
+
+ // these comparisons are okay because
+ // string compare is okay and the others
+ // are comparisons where the types differ.
+ isfalse(ia == ib);
+ isfalse(ia == ic);
+ isfalse(ia == id);
+ isfalse(ib == ic);
+ isfalse(ib == id);
+ istrue(ic == id);
+ istrue(ie == ie);
+
+ // map of interface should use == on interface values,
+ // not memory.
+ // TODO: should m[c], m[d] be valid here?
+ var m = make(map[interface{}] int);
+ m[ic] = 1;
+ m[id] = 2;
+ if m[ic] != 2 {
+ panic("m[ic] = ", m[ic]);
+ }
+}
+
diff -r 346466330152 -r 82a994c54141 test/cmp2.go
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/cmp2.go Mon Jan 26 09:56:42 2009 -0800
@@ -0,0 +1,16 @@
+// $G $D/$F.go && $L $F.$A && ! ./$A.out
+
+// Copyright 2009 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 main
+
+func use(bool) { }
+
+func main()
+{
+ var a []int;
+ var ia interface{} = a;
+ use(ia == ia);
+}
diff -r 346466330152 -r 82a994c54141 test/cmp3.go
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/cmp3.go Mon Jan 26 09:56:42 2009 -0800
@@ -0,0 +1,16 @@
+// $G $D/$F.go && $L $F.$A && ! ./$A.out
+
+// Copyright 2009 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 main
+
+func use(bool) { }
+
+func main()
+{
+ var b map[string]int;
+ var ib interface{} = b;
+ use(ib == ib);
+}
diff -r 346466330152 -r 82a994c54141 test/cmp4.go
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/cmp4.go Mon Jan 26 09:56:42 2009 -0800
@@ -0,0 +1,15 @@
+// $G $D/$F.go && $L $F.$A && ! ./$A.out
+
+// Copyright 2009 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 main
+
+func main()
+{
+ var a []int;
+ var ia interface{} = a;
+ var m = make(map[interface{}] int);
+ m[ia] = 1;
+}
diff -r 346466330152 -r 82a994c54141 test/cmp5.go
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/cmp5.go Mon Jan 26 09:56:42 2009 -0800
@@ -0,0 +1,15 @@
+// $G $D/$F.go && $L $F.$A && ! ./$A.out
+
+// Copyright 2009 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 main
+
+func main()
+{
+ var b map[string]int;
+ var ib interface{} = b;
+ var m = make(map[interface{}] int);
+ m[ib] = 1;
+}
diff -r 346466330152 -r 82a994c54141 test/golden.out
--- a/test/golden.out Mon Jan 26 09:34:19 2009 -0800
+++ b/test/golden.out Mon Jan 26 09:56:42 2009 -0800
@@ -1,3 +1,35 @@
+
+=========== ./cmp2.go
+comparing uncomparable type []int
+throw: interface compare
+SIGSEGV: segmentation violation
+Faulting address: 0x0
+pc: xxx
+
+
+=========== ./cmp3.go
+comparing uncomparable type map[string] int
+throw: interface compare
+SIGSEGV: segmentation violation
+Faulting address: 0x0
+pc: xxx
+
+
+=========== ./cmp4.go
+hash of unhashable type []int
+throw: interface hash
+SIGSEGV: segmentation violation
+Faulting address: 0x0
+pc: xxx
+
+
+=========== ./cmp5.go
+hash of unhashable type map[string] int
+throw: interface hash
+SIGSEGV: segmentation violation
+Faulting address: 0x0
+pc: xxx
+
=========== ./convlit.go
BUG: errchk: ./convlit.go: missing expected error message on line 16: 'conver|incompatible'
diff -r 346466330152 -r 82a994c54141 test/map.go
--- a/test/map.go Mon Jan 26 09:34:19 2009 -0800
+++ b/test/map.go Mon Jan 26 09:56:42 2009 -0800
@@ -52,7 +52,7 @@
mipT := make(map[int] *T);
mpTi := make(map[*T] int);
mit := make(map[int] T);
- mti := make(map[T] int);
+// mti := make(map[T] int);
type M map[int] int;
mipM := make(map[int] M);
@@ -88,7 +88,7 @@
mpTi[apT[i]] = i;
mipM[i] = m;
mit[i] = t;
- mti[t] = i;
+ // mti[t] = i;
}
// test len
@@ -122,15 +122,15 @@
if len(mpTi) != count {
fmt.Printf("len(mpTi) = %d\n", len(mpTi));
}
- if len(mti) != count {
- fmt.Printf("len(mti) = %d\n", len(mti));
- }
+// if len(mti) != count {
+// fmt.Printf("len(mti) = %d\n", len(mti));
+// }
if len(mipM) != count {
fmt.Printf("len(mipM) = %d\n", len(mipM));
}
- if len(mti) != count {
- fmt.Printf("len(mti) = %d\n", len(mti));
- }
+// if len(mti) != count {
+// fmt.Printf("len(mti) = %d\n", len(mti));
+// }
if len(mit) != count {
fmt.Printf("len(mit) = %d\n", len(mit));
}
@@ -174,15 +174,15 @@
if(mpTi[apT[i]] != i) {
fmt.Printf("mpTi[apT[%d]] = %d\n", i, mpTi[apT[i]]);
}
- if(mti[t] != i) {
- fmt.Printf("mti[%s] = %s\n", s, mti[t]);
- }
+ // if(mti[t] != i) {
+ // fmt.Printf("mti[%s] = %s\n", s, mti[t]);
+ // }
if (mipM[i][i] != i + 1) {
fmt.Printf("mipM[%d][%d] = %d\n", i, i, mipM[i][i]);
}
- if(mti[t] != i) {
- fmt.Printf("mti[%v] = %d\n", t, mti[t]);
- }
+ // if(mti[t] != i) {
+ // fmt.Printf("mti[%v] = %d\n", t, mti[t]);
+ // }
if(mit[i].i != int64(i) || mit[i].f != f) {
fmt.Printf("mit[%d] = {%d %g}\n", i, mit[i].i, mit[i].f);
}
@@ -314,16 +314,16 @@
fmt.Printf("tuple existence assign: mit[%d]\n", i);
}
}
- {
- a, b := mti[t];
- if !b {
- fmt.Printf("tuple existence decl: mti[%d]\n", i);
- }
- a, b = mti[t];
- if !b {
- fmt.Printf("tuple existence assign: mti[%d]\n", i);
- }
- }
+// {
+// a, b := mti[t];
+// if !b {
+// fmt.Printf("tuple existence decl: mti[%d]\n", i);
+// }
+// a, b = mti[t];
+// if !b {
+// fmt.Printf("tuple existence assign: mti[%d]\n", i);
+// }
+// }
}
// test nonexistence with tuple check
@@ -442,16 +442,16 @@
fmt.Printf("tuple nonexistence assign: mipM[%d]", i);
}
}
- {
- a, b := mti[t];
- if b {
- fmt.Printf("tuple nonexistence decl: mti[%d]", i);
- }
- a, b = mti[t];
- if b {
- fmt.Printf("tuple nonexistence assign: mti[%d]", i);
- }
- }
+// {
+// a, b := mti[t];
+// if b {
+// fmt.Printf("tuple nonexistence decl: mti[%d]", i);
+// }
+// a, b = mti[t];
+// if b {
+// fmt.Printf("tuple nonexistence assign: mti[%d]", i);
+// }
+// }
{
a, b := mit[i];
if b {
changeset: 1569:0fe08f7ad686
user: Ken Thompson <[email protected]>
date: Tue Jan 27 13:23:28 2009 -0800
summary: spelling
diff -r bbcb79c21314 -r 0fe08f7ad686 src/runtime/chan.c
--- a/src/runtime/chan.c Tue Jan 27 12:03:53 2009 -0800
+++ b/src/runtime/chan.c Tue Jan 27 13:23:28 2009 -0800
@@ -5,7 +5,6 @@
#include "runtime.h"
static int32 debug = 0;
-static int32 xxx = 0;
static Lock chanlock;
typedef struct Hchan Hchan;
@@ -548,7 +547,7 @@
G *gp;
byte *as;
- if(xxx) {
+ if(debug) {
prints("selectgo: sel=");
sys·printpointer(sel);
prints("\n");
@@ -697,7 +696,7 @@
goto loop;
}
- if(xxx) {
+ if(debug) {
prints("wait-return: sel=");
sys·printpointer(sel);
prints(" c=");
@@ -747,7 +746,7 @@
gotr:
// recv path to wakeup the sender (sg)
- if(xxx) {
+ if(debug) {
prints("gotr: sel=");
sys·printpointer(sel);
prints(" c=");
@@ -765,7 +764,7 @@
gots:
// send path to wakeup the receiver (sg)
- if(xxx) {
+ if(debug) {
prints("gots: sel=");
sys·printpointer(sel);
prints(" c=");
diff -r bbcb79c21314 -r 0fe08f7ad686 src/runtime/runtime.h
--- a/src/runtime/runtime.h Tue Jan 27 12:03:53 2009 -0800
+++ b/src/runtime/runtime.h Tue Jan 27 13:23:28 2009 -0800
@@ -238,7 +238,7 @@
};
/*
- * defered subroutine calls
+ * deferred subroutine calls
*/
struct Defer
{
changeset: 1819:1c6a4ed8e67b
user: Ken Thompson <[email protected]>
date: Thu Mar 12 17:55:11 2009 -0700
summary: chan flags close/closed installed
diff -r fef2441bd362 -r 1c6a4ed8e67b src/cmd/gc/Makefile
--- a/src/cmd/gc/Makefile Thu Mar 12 17:24:03 2009 -0700
+++ b/src/cmd/gc/Makefile Thu Mar 12 17:55:11 2009 -0700
@@ -41,7 +41,7 @@
test -f y.tab.c && touch y.tab.c
builtin.c: sys.go unsafe.go mkbuiltin1.c mkbuiltin
- mkbuiltin >builtin.c || \
+ ./mkbuiltin >builtin.c || \
(echo 'mkbuiltin failed; using bootstrap copy of builtin.c'; cp builtin.c.boot builtin.c)
clean:
diff -r fef2441bd362 -r 1c6a4ed8e67b src/cmd/gc/builtin.c.boot
--- a/src/cmd/gc/builtin.c.boot Thu Mar 12 17:24:03 2009 -0700
+++ b/src/cmd/gc/builtin.c.boot Thu Mar 12 17:55:11 2009 -0700
@@ -41,6 +41,8 @@
"func sys.chanrecv3 (hchan chan any, elem *any) (pres bool)\n"
"func sys.chansend1 (hchan chan any, elem any)\n"
"func sys.chansend2 (hchan chan any, elem any) (pres bool)\n"
+ "func sys.closechan (hchan chan any)\n"
+ "func sys.closedchan (hchan chan any) (? bool)\n"
"func sys.newselect (size int) (sel *uint8)\n"
"func sys.selectsend (sel *uint8, hchan chan any, elem any) (selected bool)\n"
"func sys.selectrecv (sel *uint8, hchan chan any, elem *any) (selected bool)\n"
diff -r fef2441bd362 -r 1c6a4ed8e67b src/cmd/gc/go.h
--- a/src/cmd/gc/go.h Thu Mar 12 17:24:03 2009 -0700
+++ b/src/cmd/gc/go.h Thu Mar 12 17:55:11 2009 -0700
@@ -309,6 +309,7 @@
OAS, OASOP, OCASE, OXCASE, OFALL, OXFALL,
OGOTO, OPROC, OMAKE, ONEW, OEMPTY, OSELECT,
OLEN, OCAP, OPANIC, OPANICN, OPRINT, OPRINTN, OTYPEOF,
+ OCLOSE, OCLOSED,
OOROR,
OANDAND,
diff -r fef2441bd362 -r 1c6a4ed8e67b src/cmd/gc/go.y
--- a/src/cmd/gc/go.y Thu Mar 12 17:24:03 2009 -0700
+++ b/src/cmd/gc/go.y Thu Mar 12 17:55:11 2009 -0700
@@ -15,7 +15,7 @@
%token <val> LLITERAL
%token <lint> LASOP
%token <sym> LNAME LBASETYPE LATYPE LPACK LACONST
-%token <sym> LPACKAGE LIMPORT LDEFER
+%token <sym> LPACKAGE LIMPORT LDEFER LCLOSE LCLOSED
%token <sym> LMAP LCHAN LINTERFACE LFUNC LSTRUCT
%token <sym> LCOLAS LFALL LRETURN LDDD
%token <sym> LLEN LCAP LPANIC LPANICN LPRINT LPRINTN
@@ -888,6 +888,14 @@
{
$$ = nod(OLEN, $3, N);
}
+| LCLOSE '(' expr ')'
+ {
+ $$ = nod(OCLOSE, $3, N);
+ }
+| LCLOSED '(' expr ')'
+ {
+ $$ = nod(OCLOSED, $3, N);
+ }
| LCAP '(' expr ')'
{
$$ = nod(OCAP, $3, N);
@@ -1023,6 +1031,8 @@
sym3:
LLEN
| LCAP
+| LCLOSE
+| LCLOSED
| LPANIC
| LPANICN
| LPRINT
diff -r fef2441bd362 -r 1c6a4ed8e67b src/cmd/gc/lex.c
--- a/src/cmd/gc/lex.c Thu Mar 12 17:24:03 2009 -0700
+++ b/src/cmd/gc/lex.c Thu Mar 12 17:55:11 2009 -0700
@@ -1112,7 +1112,6 @@
"any", LBASETYPE, TANY,
"sys", LPACK, Txxx,
-/* keywords */
"break", LBREAK, Txxx,
"case", LCASE, Txxx,
"chan", LCHAN, Txxx,
@@ -1151,6 +1150,9 @@
"type", LTYPE, Txxx,
"var", LVAR, Txxx,
+ "close", LCLOSE, Txxx,
+ "closed", LCLOSED, Txxx,
+
"notwithstanding", LIGNORE, Txxx,
"thetruthofthematter", LIGNORE, Txxx,
"despiteallobjections", LIGNORE, Txxx,
diff -r fef2441bd362 -r 1c6a4ed8e67b src/cmd/gc/mkbuiltin
--- a/src/cmd/gc/mkbuiltin Thu Mar 12 17:24:03 2009 -0700
+++ b/src/cmd/gc/mkbuiltin Thu Mar 12 17:55:11 2009 -0700
@@ -21,7 +21,8 @@
ken | r | rsc)
if ! cmp _builtin.c builtin.c.boot
then
- p4 open builtin.c.boot
+ PATH=$PATH:/usr/local/bin
+ p4 open builtin.c.boot >/dev/null
cp _builtin.c builtin.c.boot
fi
esac
diff -r fef2441bd362 -r 1c6a4ed8e67b src/cmd/gc/subr.c
--- a/src/cmd/gc/subr.c Thu Mar 12 17:24:03 2009 -0700
+++ b/src/cmd/gc/subr.c Thu Mar 12 17:55:11 2009 -0700
@@ -688,6 +688,8 @@
[OLABEL] = "LABEL",
[OLE] = "LE",
[OLEN] = "LEN",
+ [OCLOSE] = "CLOSE",
+ [OCLOSED] = "CLOSED",
[OCAP] = "CAP",
[OLIST] = "LIST",
[OLITERAL] = "LITERAL",
diff -r fef2441bd362 -r 1c6a4ed8e67b src/cmd/gc/sys.go
--- a/src/cmd/gc/sys.go Thu Mar 12 17:24:03 2009 -0700
+++ b/src/cmd/gc/sys.go Thu Mar 12 17:55:11 2009 -0700
@@ -55,6 +55,8 @@
func chanrecv3(hchan chan any, elem *any) (pres bool);
func chansend1(hchan chan any, elem any);
func chansend2(hchan chan any, elem any) (pres bool);
+func closechan(hchan chan any);
+func closedchan(hchan chan any) bool;
func newselect(size int) (sel *byte);
func selectsend(sel *byte, hchan chan any, elem any) (selected bool);
diff -r fef2441bd362 -r 1c6a4ed8e67b src/cmd/gc/walk.c
--- a/src/cmd/gc/walk.c Thu Mar 12 17:24:03 2009 -0700
+++ b/src/cmd/gc/walk.c Thu Mar 12 17:55:11 2009 -0700
@@ -126,6 +126,8 @@
case OASOP:
case OAS:
+ case OCLOSE:
+ case OCLOSED:
case OCALLMETH:
case OCALLINTER:
case OCALL:
@@ -852,6 +854,20 @@
}
goto ret;
+ case OCLOSE:
+ if(top != Etop)
+ goto nottop;
+ walktype(n->left, Erv); // chan
+ indir(n, chanop(n, top));
+ goto ret;
+
+ case OCLOSED:
+ if(top == Elv)
+ goto nottop;
+ walktype(n->left, Erv); // chan
+ indir(n, chanop(n, top));
+ goto ret;
+
case OSEND:
if(top == Elv)
goto nottop;
@@ -2447,6 +2463,40 @@
default:
fatal("chanop: unknown op %O", n->op);
+ case OCLOSE:
+ // closechan(hchan *chan any);
+ t = fixchan(n->left->type);
+ if(t == T)
+ break;
+
+ a = n->left; // chan
+ r = a;
+
+ on = syslook("closechan", 1);
+ argtype(on, t->type); // any-1
+
+ r = nod(OCALL, on, r);
+ walktype(r, top);
+ r->type = n->type;
+ break;
+
+ case OCLOSED:
+ // closedchan(hchan *chan any) bool;
+ t = fixchan(n->left->type);
+ if(t == T)
+ break;
+
+ a = n->left; // chan
+ r = a;
+
+ on = syslook("closedchan", 1);
+ argtype(on, t->type); // any-1
+
+ r = nod(OCALL, on, r);
+ walktype(r, top);
+ n->type = r->type;
+ break;
+
case OMAKE:
cl = listcount(n->left);
if(cl > 1)
diff -r fef2441bd362 -r 1c6a4ed8e67b src/runtime/chan.c
--- a/src/runtime/chan.c Thu Mar 12 17:24:03 2009 -0700
+++ b/src/runtime/chan.c Thu Mar 12 17:55:11 2009 -0700
@@ -7,6 +7,14 @@
static int32 debug = 0;
static Lock chanlock;
+enum
+{
+ Wclosed = 0x0001,
+ Rclosed = 0xfffe,
+ Rincr = 0x0002,
+ Rmax = 0x8000,
+};
+
typedef struct Hchan Hchan;
typedef struct Link Link;
typedef struct WaitQ WaitQ;
@@ -32,7 +40,9 @@
struct Hchan
{
- uint32 elemsize;
+ uint16 elemsize;
+ uint16 closed; // Wclosed closed() hash been called
+ // Rclosed read-count after closed()
uint32 dataqsiz; // size of the circular q
uint32 qcount; // total data in the q
Alg* elemalg; // interface for element type
@@ -535,7 +545,6 @@
}
}
-
// selectgo(sel *byte);
void
sys·selectgo(Select *sel)
@@ -790,6 +799,42 @@
*as = true;
}
+// closechan(sel *byte);
+void
+sys·closechan(Hchan *c)
+{
+ if(c == nil)
+ throw("closechan: channel not allocated");
+
+ // if wclosed already set
+ // work has been done - just return
+ if(c->closed & Wclosed)
+ return;
+
+ // set wclosed
+ c->closed |= Wclosed;
+}
+
+// closedchan(sel *byte) bool;
+void
+sys·closedchan(Hchan *c, bool closed)
+{
+ if(c == nil)
+ throw("closedchan: channel not allocated");
+
+ closed = 0;
+
+ // test rclosed
+ if(c->closed & Rclosed) {
+ // see if rclosed has been set a lot
+ if(c->closed & Rmax)
+ throw("closedchan: ignored");
+ c->closed += Rincr;
+ closed = 1;
+ }
+ FLUSH(&closed);
+}
+
static SudoG*
dequeue(WaitQ *q, Hchan *c)
{
changeset: 1827:ceeee951ab0e
user: Ken Thompson <[email protected]>
date: Fri Mar 13 16:47:54 2009 -0700
summary: close/closed on chans
diff -r cf5a31f5e045 -r ceeee951ab0e src/runtime/chan.c
--- a/src/runtime/chan.c Fri Mar 13 15:03:07 2009 -0700
+++ b/src/runtime/chan.c Fri Mar 13 16:47:54 2009 -0700
@@ -9,10 +9,10 @@
enum
{
- Wclosed = 0x0001,
- Rclosed = 0xfffe,
- Rincr = 0x0002,
- Rmax = 0x8000,
+ Wclosed = 0x0001, // writer has closed
+ Rclosed = 0x0002, // reader has seen close
+ Eincr = 0x0004, // increment errors
+ Emax = 0x0800, // error limit before throw
};
typedef struct Hchan Hchan;
@@ -41,8 +41,7 @@
struct Hchan
{
uint16 elemsize;
- uint16 closed; // Wclosed closed() hash been called
- // Rclosed read-count after closed()
+ uint16 closed; // Wclosed Rclosed errorcount
uint32 dataqsiz; // size of the circular q
uint32 qcount; // total data in the q
Alg* elemalg; // interface for element type
@@ -143,6 +142,16 @@
}
}
+static void
+incerr(Hchan* c)
+{
+ c->closed += Eincr;
+ if(c->closed & Emax) {
+ unlock(&chanlock);
+ throw("too many operations on a closed channel");
+ }
+}
+
/*
* generic single channel send/recv
* if the bool pointer is nil,
@@ -167,9 +176,13 @@
}
lock(&chanlock);
+
if(c->dataqsiz > 0)
goto asynch;
+ if(c->closed & Wclosed)
+ goto closed;
+
sg = dequeue(&c->recvq, c);
if(sg != nil) {
if(ep != nil)
@@ -209,7 +222,10 @@
return;
asynch:
- while(c->qcount >= c->dataqsiz) {
+ if(c->closed & Wclosed)
+ goto closed;
+
+ if(c->qcount >= c->dataqsiz) {
if(pres != nil) {
unlock(&chanlock);
*pres = false;
@@ -222,6 +238,7 @@
sys·Gosched();
lock(&chanlock);
+ goto asynch;
}
if(ep != nil)
c->elemalg->copy(c->elemsize, c->senddataq->elem, ep);
@@ -238,6 +255,13 @@
unlock(&chanlock);
if(pres != nil)
*pres = true;
+ return;
+
+closed:
+ incerr(c);
+ if(pres != nil)
+ *pres = false;
+ unlock(&chanlock);
}
static void
@@ -256,6 +280,9 @@
if(c->dataqsiz > 0)
goto asynch;
+ if(c->closed & Wclosed)
+ goto closed;
+
sg = dequeue(&c->sendq, c);
if(sg != nil) {
c->elemalg->copy(c->elemsize, ep, sg->elem);
@@ -285,6 +312,12 @@
lock(&chanlock);
sg = g->param;
+
+ if(c->closed & Wclosed) {
+ freesg(c, sg);
+ goto closed;
+ }
+
c->elemalg->copy(c->elemsize, ep, sg->elem);
freesg(c, sg);
unlock(&chanlock);
@@ -293,7 +326,10 @@
return;
asynch:
- while(c->qcount <= 0) {
+ if(c->qcount <= 0) {
+ if(c->closed & Wclosed)
+ goto closed;
+
if(pres != nil) {
unlock(&chanlock);
*pres = false;
@@ -304,7 +340,9 @@
enqueue(&c->recvq, sg);
unlock(&chanlock);
sys·Gosched();
+
lock(&chanlock);
+ goto asynch;
}
c->elemalg->copy(c->elemsize, ep, c->recvdataq->elem);
c->recvdataq = c->recvdataq->link;
@@ -315,10 +353,23 @@
freesg(c, sg);
unlock(&chanlock);
ready(gp);
- } else
- unlock(&chanlock);
+ if(pres != nil)
+ *pres = true;
+ return;
+ }
+
+ unlock(&chanlock);
if(pres != nil)
*pres = true;
+ return;
+
+closed:
+ c->elemalg->copy(c->elemsize, ep, nil);
+ c->closed |= Rclosed;
+ incerr(c);
+ if(pres != nil)
+ *pres = false;
+ unlock(&chanlock);
}
// chansend1(hchan *chan any, elem any);
@@ -602,10 +653,14 @@
if(cas->send) {
if(c->qcount < c->dataqsiz)
goto asyns;
+ if(c->closed & Wclosed)
+ goto gots;
goto next1;
}
if(c->qcount > 0)
goto asynr;
+ if(c->closed & Wclosed)
+ goto gotr;
goto next1;
}
@@ -613,11 +668,15 @@
sg = dequeue(&c->recvq, c);
if(sg != nil)
goto gots;
+ if(c->closed & Wclosed)
+ goto gots;
goto next1;
}
sg = dequeue(&c->sendq, c);
if(sg != nil)
goto gotr;
+ if(c->closed & Wclosed)
+ goto gotr;
next1:
o += p;
@@ -764,6 +823,13 @@
sys·printint(o);
prints("\n");
}
+ if(c->closed & Wclosed) {
+ if(cas->u.elemp != nil)
+ c->elemalg->copy(c->elemsize, cas->u.elemp, nil);
+ c->closed |= Rclosed;
+ incerr(c);
+ goto retc;
+ }
if(cas->u.elemp != nil)
c->elemalg->copy(c->elemsize, cas->u.elemp, sg->elem);
gp = sg->g;
@@ -782,6 +848,10 @@
sys·printint(o);
prints("\n");
}
+ if(c->closed & Wclosed) {
+ incerr(c);
+ goto retc;
+ }
c->elemalg->copy(c->elemsize, sg->elem, cas->u.elem);
gp = sg->g;
gp->param = sg;
@@ -803,35 +873,47 @@
void
sys·closechan(Hchan *c)
{
- if(c == nil)
- throw("closechan: channel not allocated");
+ SudoG *sg;
+ G* gp;
- // if wclosed already set
- // work has been done - just return
- if(c->closed & Wclosed)
- return;
+ lock(&chanlock);
+ incerr(c);
+ c->closed |= Wclosed;
- // set wclosed
- c->closed |= Wclosed;
+ // release all readers
+ for(;;) {
+ sg = dequeue(&c->recvq, c);
+ if(sg == nil)
+ break;
+ gp = sg->g;
+ gp->param = nil;
+ freesg(c, sg);
+ ready(gp);
+ }
+
+ // release all writers
+ for(;;) {
+ sg = dequeue(&c->sendq, c);
+ if(sg == nil)
+ break;
+ gp = sg->g;
+ gp->param = nil;
+ freesg(c, sg);
+ ready(gp);
+ }
+
+ unlock(&chanlock);
}
// closedchan(sel *byte) bool;
void
sys·closedchan(Hchan *c, bool closed)
{
- if(c == nil)
- throw("closedchan: channel not allocated");
+ // test Rclosed
closed = 0;
-
- // test rclosed
- if(c->closed & Rclosed) {
- // see if rclosed has been set a lot
- if(c->closed & Rmax)
- throw("closedchan: ignored");
- c->closed += Rincr;
+ if(c->closed & Rclosed)
closed = 1;
- }
FLUSH(&closed);
}
@@ -892,11 +974,13 @@
static void
freesg(Hchan *c, SudoG *sg)
{
- if(sg->isfree)
- throw("chan.freesg: already free");
- sg->isfree = 1;
- sg->link = c->free;
- c->free = sg;
+ if(sg != nil) {
+ if(sg->isfree)
+ throw("chan.freesg: already free");
+ sg->isfree = 1;
+ sg->link = c->free;
+ c->free = sg;
+ }
}
static uint32
changeset: 1868:99a2b734df38
user: Russ Cox <[email protected]>
date: Mon Mar 23 18:50:35 2009 -0700
summary: add test for close/closed, fix a few implementation bugs.
diff -r 29c9666007fe -r 99a2b734df38 src/runtime/chan.c
--- a/src/runtime/chan.c Mon Mar 23 18:32:37 2009 -0700
+++ b/src/runtime/chan.c Mon Mar 23 18:50:35 2009 -0700
@@ -176,13 +176,13 @@
}
lock(&chanlock);
+loop:
+ if(c->closed & Wclosed)
+ goto closed;
if(c->dataqsiz > 0)
goto asynch;
- if(c->closed & Wclosed)
- goto closed;
-
sg = dequeue(&c->recvq, c);
if(sg != nil) {
if(ep != nil)
@@ -215,6 +215,8 @@
lock(&chanlock);
sg = g->param;
+ if(sg == nil)
+ goto loop;
freesg(c, sg);
unlock(&chanlock);
if(pres != nil)
@@ -260,7 +262,7 @@
closed:
incerr(c);
if(pres != nil)
- *pres = false;
+ *pres = true;
unlock(&chanlock);
}
@@ -277,6 +279,7 @@
}
lock(&chanlock);
+loop:
if(c->dataqsiz > 0)
goto asynch;
@@ -312,11 +315,8 @@
lock(&chanlock);
sg = g->param;
-
- if(c->closed & Wclosed) {
- freesg(c, sg);
- goto closed;
- }
+ if(sg == nil)
+ goto loop;
c->elemalg->copy(c->elemsize, ep, sg->elem);
freesg(c, sg);
@@ -368,7 +368,7 @@
c->closed |= Rclosed;
incerr(c);
if(pres != nil)
- *pres = false;
+ *pres = true;
unlock(&chanlock);
}
@@ -651,32 +651,32 @@
c = cas->chan;
if(c->dataqsiz > 0) {
if(cas->send) {
+ if(c->closed & Wclosed)
+ goto sclose;
if(c->qcount < c->dataqsiz)
goto asyns;
- if(c->closed & Wclosed)
- goto gots;
goto next1;
}
if(c->qcount > 0)
goto asynr;
if(c->closed & Wclosed)
- goto gotr;
+ goto rclose;
goto next1;
}
if(cas->send) {
+ if(c->closed & Wclosed)
+ goto sclose;
sg = dequeue(&c->recvq, c);
if(sg != nil)
goto gots;
- if(c->closed & Wclosed)
- goto gots;
goto next1;
}
sg = dequeue(&c->sendq, c);
if(sg != nil)
goto gotr;
if(c->closed & Wclosed)
- goto gotr;
+ goto rclose;
next1:
o += p;
@@ -823,13 +823,6 @@
sys·printint(o);
prints("\n");
}
- if(c->closed & Wclosed) {
- if(cas->u.elemp != nil)
- c->elemalg->copy(c->elemsize, cas->u.elemp, nil);
- c->closed |= Rclosed;
- incerr(c);
- goto retc;
- }
if(cas->u.elemp != nil)
c->elemalg->copy(c->elemsize, cas->u.elemp, sg->elem);
gp = sg->g;
@@ -837,6 +830,13 @@
ready(gp);
goto retc;
+rclose:
+ if(cas->u.elemp != nil)
+ c->elemalg->copy(c->elemsize, cas->u.elemp, nil);
+ c->closed |= Rclosed;
+ incerr(c);
+ goto retc;
+
gots:
// send path to wakeup the receiver (sg)
if(debug) {
@@ -848,14 +848,17 @@
sys·printint(o);
prints("\n");
}
- if(c->closed & Wclosed) {
- incerr(c);
- goto retc;
- }
+ if(c->closed & Wclosed)
+ goto sclose;
c->elemalg->copy(c->elemsize, sg->elem, cas->u.elem);
gp = sg->g;
gp->param = sg;
ready(gp);
+ goto retc;
+
+sclose:
+ incerr(c);
+ goto retc;
retc:
if(sel->ncase >= 1 && sel->ncase < nelem(selfree)) {
@@ -909,7 +912,6 @@
void
sys·closedchan(Hchan *c, bool closed)
{
-
// test Rclosed
closed = 0;
if(c->closed & Rclosed)
diff -r 29c9666007fe -r 99a2b734df38 test/closedchan.go
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/closedchan.go Mon Mar 23 18:50:35 2009 -0700
@@ -0,0 +1,197 @@
+// $G $D/$F.go && $L $F.$A && ./$A.out
+
+// Copyright 2009 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.
+
+// Test close(c), closed(c).
+//
+// TODO(rsc): Doesn't check behavior of close(c) when there
+// are blocked senders/receivers.
+
+package main
+
+type Chan interface {
+ Send(int);
+ Nbsend(int) bool;
+ Recv() int;
+ Nbrecv() (int, bool);
+ Close();
+ Closed() bool;
+ Impl() string;
+}
+
+// direct channel operations
+type XChan chan int
+func (c XChan) Send(x int) {
+ c <- x
+}
+
+func (c XChan) Nbsend(x int) bool {
+ return c <- x;
+}
+
+func (c XChan) Recv() int {
+ return <-c
+}
+
+func (c XChan) Nbrecv() (int, bool) {
+ x, ok := <-c;
+ return x, ok;
+}
+
+func (c XChan) Close() {
+ close(c)
+}
+
+func (c XChan) Closed() bool {
+ return closed(c)
+}
+
+func (c XChan) Impl() string {
+ return "(<- operator)"
+}
+
+// indirect operations via select
+type SChan chan int
+func (c SChan) Send(x int) {
+ select {
+ case c <- x:
+ }
+}
+
+func (c SChan) Nbsend(x int) bool {
+ select {
+ case c <- x:
+ return true;
+ default:
+ return false;
+ }
+ panic("nbsend");
+}
+
+func (c SChan) Recv() int {
+ select {
+ case x := <-c:
+ return x;
+ }
+ panic("recv");
+}
+
+func (c SChan) Nbrecv() (int, bool) {
+ select {
+ case x := <-c:
+ return x, true;
+ default:
+ return 0, false;
+ }
+ panic("nbrecv");
+}
+
+func (c SChan) Close() {
+ close(c)
+}
+
+func (c SChan) Closed() bool {
+ return closed(c)
+}
+
+func (c SChan) Impl() string {
+ return "(select)";
+}
+
+func test1(c Chan) {
+ // not closed until the close signal (a zero value) has been received.
+ if c.Closed() {
+ println("test1: Closed before Recv zero:", c.Impl());
+ }
+
+ for i := 0; i < 3; i++ {
+ // recv a close signal (a zero value)
+ if x := c.Recv(); x != 0 {
+ println("test1: recv on closed got non-zero:", x, c.Impl());
+ }
+
+ // should now be closed.
+ if !c.Closed() {
+ println("test1: not closed after recv zero", c.Impl());
+ }
+
+ // should work with ,ok: received a value without blocking, so ok == true.
+ x, ok := c.Nbrecv();
+ if !ok {
+ println("test1: recv on closed got not ok", c.Impl());
+ }
+ if x != 0 {
+ println("test1: recv ,ok on closed got non-zero:", x, c.Impl());
+ }
+ }
+
+ // send should work with ,ok too: sent a value without blocking, so ok == true.
+ ok := c.Nbsend(1);
+ if !ok {
+ println("test1: send on closed got not ok", c.Impl());
+ }
+
+ // but the value should have been discarded.
+ if x := c.Recv(); x != 0 {
+ println("test1: recv on closed got non-zero after send on closed:", x, c.Impl());
+ }
+
+ // similarly Send.
+ c.Send(2);
+ if x := c.Recv(); x != 0 {
+ println("test1: recv on closed got non-zero after send on closed:", x, c.Impl());
+ }
+}
+
+func testasync1(c Chan) {
+ // not closed until the close signal (a zero value) has been received.
+ if c.Closed() {
+ println("testasync1: Closed before Recv zero:", c.Impl());
+ }
+
+ // should be able to get the last value via Recv
+ if x := c.Recv(); x != 1 {
+ println("testasync1: Recv did not get 1:", x, c.Impl());
+ }
+
+ test1(c);
+}
+
+func testasync2(c Chan) {
+ // not closed until the close signal (a zero value) has been received.
+ if c.Closed() {
+ println("testasync2: Closed before Recv zero:", c.Impl());
+ }
+
+ // should be able to get the last value via Nbrecv
+ if x, ok := c.Nbrecv(); !ok || x != 1 {
+ println("testasync2: Nbrecv did not get 1, true:", x, ok, c.Impl());
+ }
+
+ test1(c);
+}
+
+func closedsync() chan int {
+ c := make(chan int);
+ close(c);
+ return c;
+}
+
+func closedasync() chan int {
+ c := make(chan int, 2);
+ c <- 1;
+ close(c);
+ return c;
+}
+
+func main() {
+ test1(XChan(closedsync()));
+ test1(SChan(closedsync()));
+
+ testasync1(XChan(closedasync()));
+ testasync1(SChan(closedasync()));
+ testasync2(XChan(closedasync()));
+ testasync2(SChan(closedasync()));
+}
changeset: 2175:620f3b46ef19
user: Russ Cox <[email protected]>
date: Fri May 08 15:21:41 2009 -0700
summary: move things out of sys into os and runtime
diff -r 597b72316015 -r 620f3b46ef19 doc/progs/cat.go
--- a/doc/progs/cat.go Fri May 08 14:57:56 2009 -0700
+++ b/doc/progs/cat.go Fri May 08 15:21:41 2009 -0700
@@ -18,7 +18,7 @@
switch nr, er := f.Read(&buf); true {
case nr < 0:
fmt.Fprintf(os.Stderr, "error reading from %s: %s\n", f.String(), er.String());
- sys.Exit(1);
+ os.Exit(1);
case nr == 0: // EOF
return;
case nr > 0:
@@ -38,7 +38,7 @@
f, err := file.Open(flag.Arg(i), 0, 0);
if f == nil {
fmt.Fprintf(os.Stderr, "can't open %s: error %s\n", flag.Arg(i), err);
- sys.Exit(1);
+ os.Exit(1);
}
cat(f);
f.Close();
diff -r 597b72316015 -r 620f3b46ef19 doc/progs/cat_rot13.go
--- a/doc/progs/cat_rot13.go Fri May 08 14:57:56 2009 -0700
+++ b/doc/progs/cat_rot13.go Fri May 08 15:21:41 2009 -0700
@@ -60,7 +60,7 @@
switch nr, er := r.Read(&buf); {
case nr < 0:
fmt.Fprintf(os.Stderr, "error reading from %s: %s\n", r.String(), er.String());
- sys.Exit(1);
+ os.Exit(1);
case nr == 0: // EOF
return;
case nr > 0:
@@ -81,7 +81,7 @@
f, err := file.Open(flag.Arg(i), 0, 0);
if f == nil {
fmt.Fprintf(os.Stderr, "can't open %s: error %s\n", flag.Arg(i), err);
- sys.Exit(1);
+ os.Exit(1);
}
cat(f);
f.Close();
diff -r 597b72316015 -r 620f3b46ef19 doc/progs/helloworld3.go
--- a/doc/progs/helloworld3.go Fri May 08 14:57:56 2009 -0700
+++ b/doc/progs/helloworld3.go Fri May 08 15:21:41 2009 -0700
@@ -7,6 +7,7 @@
import (
"file";
"fmt";
+ "os";
)
func main() {
@@ -15,6 +16,6 @@
file, err := file.Open("/does/not/exist", 0, 0);
if file == nil {
fmt.Printf("can't open file; err=%s\n", err.String());
- sys.Exit(1);
+ os.Exit(1);
}
}
diff -r 597b72316015 -r 620f3b46ef19 doc/progs/strings.go
--- a/doc/progs/strings.go Fri May 08 14:57:56 2009 -0700
+++ b/doc/progs/strings.go Fri May 08 15:21:41 2009 -0700
@@ -5,10 +5,11 @@
package main
import "fmt"
+import "os"
func main() {
s := "hello";
- if s[1] != 'e' { sys.Exit(1) }
+ if s[1] != 'e' { os.Exit(1) }
s = "good bye";
var p *string = &s;
*p = "ciao";
diff -r 597b72316015 -r 620f3b46ef19 src/cmd/gc/Makefile
--- a/src/cmd/gc/Makefile Fri May 08 14:57:56 2009 -0700
+++ b/src/cmd/gc/Makefile Fri May 08 15:21:41 2009 -0700
@@ -44,7 +44,7 @@
y.tab.c: y.tab.h
test -f y.tab.c && touch y.tab.c
-builtin.c: sys.go unsafe.go mkbuiltin1.c mkbuiltin
+builtin.c: sys.go unsafe.go runtime.go mkbuiltin1.c mkbuiltin
./mkbuiltin >builtin.c || \
(echo 'mkbuiltin failed; using bootstrap copy of builtin.c'; cp builtin.c.boot builtin.c)
diff -r 597b72316015 -r 620f3b46ef19 src/cmd/gc/builtin.c.boot
--- a/src/cmd/gc/builtin.c.boot Fri May 08 14:57:56 2009 -0700
+++ b/src/cmd/gc/builtin.c.boot Fri May 08 15:21:41 2009 -0700
@@ -55,13 +55,6 @@
"func sys.arrayslices (old *any, nel int, lb int, hb int, width int) (ary []any)\n"
"func sys.arrays2d (old *any, nel int) (ary []any)\n"
"func sys.closure ()\n"
- "func sys.Breakpoint ()\n"
- "var sys.Args []string\n"
- "var sys.Envs []string\n"
- "func sys.Gosched ()\n"
- "func sys.Goexit ()\n"
- "func sys.Exit (? int)\n"
- "func sys.Caller (n int) (pc uint64, file string, line int, ok bool)\n"
"\n"
"$$\n";
char *unsafeimport =
@@ -74,3 +67,11 @@
"func unsafe.Unreflect (? uint64, ? string, ? bool) (ret interface { })\n"
"\n"
"$$\n";
+char *runtimeimport =
+ "package runtime\n"
+ "func runtime.Breakpoint ()\n"
+ "func runtime.Gosched ()\n"
+ "func runtime.Goexit ()\n"
+ "func runtime.Caller (n int) (pc uint64, file string, line int, ok bool)\n"
+ "\n"
+ "$$\n";
diff -r 597b72316015 -r 620f3b46ef19 src/cmd/gc/go.h
--- a/src/cmd/gc/go.h Fri May 08 14:57:56 2009 -0700
+++ b/src/cmd/gc/go.h Fri May 08 15:21:41 2009 -0700
@@ -541,6 +541,7 @@
EXTERN int tptr; // either TPTR32 or TPTR64
extern char* sysimport;
extern char* unsafeimport;
+extern char* runtimeimport;
EXTERN char* filename; // name to uniqify names
EXTERN Idir* idirs;
diff -r 597b72316015 -r 620f3b46ef19 src/cmd/gc/lex.c
--- a/src/cmd/gc/lex.c Fri May 08 14:57:56 2009 -0700
+++ b/src/cmd/gc/lex.c Fri May 08 15:21:41 2009 -0700
@@ -265,6 +265,10 @@
cannedimports("unsafe.6", unsafeimport);
return;
}
+ if(strcmp(f->u.sval->s, "runtime") == 0) {
+ cannedimports("runtime.6", runtimeimport);
+ return;
+ }
if(!findpkg(f->u.sval))
fatal("can't find import: %Z", f->u.sval);
diff -r 597b72316015 -r 620f3b46ef19 src/cmd/gc/mkbuiltin
--- a/src/cmd/gc/mkbuiltin Fri May 08 14:57:56 2009 -0700
+++ b/src/cmd/gc/mkbuiltin Fri May 08 15:21:41 2009 -0700
@@ -5,11 +5,12 @@
set -e
gcc -o mkbuiltin1 mkbuiltin1.c
-6g sys.go
-6g unsafe.go
rm -f _builtin.c
-./mkbuiltin1 sys >_builtin.c
-./mkbuiltin1 unsafe >>_builtin.c
+for i in sys unsafe runtime
+do
+ 6g $i.go
+ ./mkbuiltin1 $i >>_builtin.c
+done
# If _builtin.c has changed vs builtin.c.boot,
# check in the new change if being run by
diff -r 597b72316015 -r 620f3b46ef19 src/cmd/gc/runtime.go
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cmd/gc/runtime.go Fri May 08 15:21:41 2009 -0700
@@ -0,0 +1,9 @@
+// Copyright 2009 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 PACKAGE
+func Breakpoint();
+func Gosched();
+func Goexit();
+func Caller(n int) (pc uint64, file string, line int, ok bool);
diff -r 597b72316015 -r 620f3b46ef19 src/cmd/gc/sys.go
--- a/src/cmd/gc/sys.go Fri May 08 14:57:56 2009 -0700
+++ b/src/cmd/gc/sys.go Fri May 08 15:21:41 2009 -0700
@@ -72,17 +72,3 @@
func arrays2d(old *any, nel int) (ary []any);
func closure(); // has args, but compiler fills in
-
-// used by go programs
-
-func Breakpoint();
-
-var Args []string;
-var Envs []string;
-
-func Gosched();
-func Goexit();
-
-func Exit(int);
-
-func Caller(n int) (pc uint64, file string, line int, ok bool);
diff -r 597b72316015 -r 620f3b46ef19 src/cmd/gobuild/gobuild.go
--- a/src/cmd/gobuild/gobuild.go Fri May 08 14:57:56 2009 -0700
+++ b/src/cmd/gobuild/gobuild.go Fri May 08 15:21:41 2009 -0700
@@ -131,7 +131,7 @@
// TODO(rsc): Build a binary from package main?
z := new(Info);
- z.Args = sys.Args;
+ z.Args = os.Args;
z.Dir = PkgDir();
z.Char = theChar; // for template
z.ObjDir = ObjDir; // for template
diff -r 597b72316015 -r 620f3b46ef19 src/cmd/gobuild/util.go
--- a/src/cmd/gobuild/util.go Fri May 08 14:57:56 2009 -0700
+++ b/src/cmd/gobuild/util.go Fri May 08 15:21:41 2009 -0700
@@ -34,7 +34,7 @@
func fatal(args ...) {
fmt.Fprintf(os.Stderr, "gobuild: %s\n", fmt.Sprint(args));
- sys.Exit(1);
+ os.Exit(1);
}
func init() {
diff -r 597b72316015 -r 620f3b46ef19 src/lib/flag/flag.go
--- a/src/lib/flag/flag.go Fri May 08 14:57:56 2009 -0700
+++ b/src/lib/flag/flag.go Fri May 08 15:21:41 2009 -0700
@@ -261,15 +261,15 @@
}
// Usage prints to standard error a default usage message documenting all defined flags and
-// then calls sys.Exit(1).
+// then calls os.Exit(1).
func Usage() {
- if len(sys.Args) > 0 {
- fmt.Fprintln(os.Stderr, "Usage of", sys.Args[0] + ":");
+ if len(os.Args) > 0 {
+ fmt.Fprintln(os.Stderr, "Usage of", os.Args[0] + ":");
} else {
fmt.Fprintln(os.Stderr, "Usage:");
}
PrintDefaults();
- sys.Exit(1);
+ os.Exit(1);
}
func NFlag() int {
@@ -280,20 +280,20 @@
// after flags have been processed.
func Arg(i int) string {
i += flags.first_arg;
- if i < 0 || i >= len(sys.Args) {
+ if i < 0 || i >= len(os.Args) {
return "";
}
- return sys.Args[i]
+ return os.Args[i]
}
// NArg is the number of arguments remaining after flags have been processed.
func NArg() int {
- return len(sys.Args) - flags.first_arg
+ return len(os.Args) - flags.first_arg
}
// Args returns the non-flag command-line arguments.
func Args() []string {
- return sys.Args[flags.first_arg:len(sys.Args)];
+ return os.Args[flags.first_arg:len(os.Args)];
}
func add(name string, value FlagValue, usage string) {
@@ -393,7 +393,7 @@
func (f *allFlags) parseOne(index int) (ok bool, next int)
{
- s := sys.Args[index];
+ s := os.Args[index];
f.first_arg = index; // until proven otherwise
if len(s) == 0 {
return false, -1
@@ -450,11 +450,11 @@
}
} else {
// It must have a value, which might be the next argument.
- if !has_value && index < len(sys.Args)-1 {
+ if !has_value && index < len(os.Args)-1 {
// value is the next arg
has_value = true;
index++;
- value = sys.Args[index];
+ value = os.Args[index];
}
if !has_value {
print("flag needs an argument: -", name, "\n");
@@ -473,7 +473,7 @@
// Parse parses the command-line flags. Must be called after all flags are defined
// and before any are accessed by the program.
func Parse() {
- for i := 1; i < len(sys.Args); {
+ for i := 1; i < len(os.Args); {
ok, next := flags.parseOne(i);
if next > 0 {
flags.first_arg = next;
diff -r 597b72316015 -r 620f3b46ef19 src/lib/http/triv.go
--- a/src/lib/http/triv.go Fri May 08 14:57:56 2009 -0700
+++ b/src/lib/http/triv.go Fri May 08 15:21:41 2009 -0700
@@ -74,7 +74,7 @@
// simple argument server
func ArgServer(c *http.Conn, req *http.Request) {
- for i, s := range sys.Args {
+ for i, s := range os.Args {
fmt.Fprint(c, s, " ");
}
}
diff -r 597b72316015 -r 620f3b46ef19 src/lib/log/log.go
--- a/src/lib/log/log.go Fri May 08 14:57:56 2009 -0700
+++ b/src/lib/log/log.go Fri May 08 15:21:41 2009 -0700
@@ -14,6 +14,7 @@
import (
"fmt";
"io";
+ "runtime";
"os";
"time";
)
@@ -96,7 +97,7 @@
}
}
if l.flag & (Lshortfile | Llongfile) != 0 {
- pc, file, line, ok := sys.Caller(calldepth);
+ pc, file, line, ok := runtime.Caller(calldepth);
if ok {
if l.flag & Lshortfile != 0 {
short, ok := shortnames[file];
@@ -139,7 +140,7 @@
case Lcrash:
panic("log: fatal error");
case Lexit:
- sys.Exit(1);
+ os.Exit(1);
}
}
@@ -173,12 +174,12 @@
stderr.Output(2, fmt.Sprintf(format, v))
}
-// Exit is equivalent to Stderr() followed by a call to sys.Exit(1).
+// Exit is equivalent to Stderr() followed by a call to os.Exit(1).
func Exit(v ...) {
exit.Output(2, fmt.Sprintln(v))
}
-// Exitf is equivalent to Stderrf() followed by a call to sys.Exit(1).
+// Exitf is equivalent to Stderrf() followed by a call to os.Exit(1).
func Exitf(format string, v ...) {
exit.Output(2, fmt.Sprintf(format, v))
}
diff -r 597b72316015 -r 620f3b46ef19 src/lib/os/Makefile
--- a/src/lib/os/Makefile Fri May 08 14:57:56 2009 -0700
+++ b/src/lib/os/Makefile Fri May 08 15:21:41 2009 -0700
@@ -3,7 +3,7 @@
# license that can be found in the LICENSE file.
# DO NOT EDIT. Automatically generated by gobuild.
-# gobuild -m dir_${GOARCH}_${GOOS}.go env.go error.go file.go stat_${GOARCH}_${GOOS}.go time.go types.go exec.go >Makefile
+# gobuild -m dir_${GOARCH}_${GOOS}.go env.go error.go file.go proc.go stat_${GOARCH}_${GOOS}.go time.go types.go exec.go >Makefile
D=
@@ -41,6 +41,7 @@
O1=\
error.$O\
+ proc.$O\
types.$O\
O2=\
@@ -60,7 +61,7 @@
_obj$D/os.a: phases
a1: $(O1)
- $(AR) grc _obj$D/os.a error.$O types.$O
+ $(AR) grc _obj$D/os.a error.$O proc.$O types.$O
rm -f $(O1)
a2: $(O2)
diff -r 597b72316015 -r 620f3b46ef19 src/lib/os/env.go
--- a/src/lib/os/env.go Fri May 08 14:57:56 2009 -0700
+++ b/src/lib/os/env.go Fri May 08 15:21:41 2009 -0700
@@ -19,7 +19,7 @@
func copyenv() {
env = make(map[string] string);
- for i, s := range sys.Envs {
+ for i, s := range os.Envs {
for j := 0; j < len(s); j++ {
if s[j] == '=' {
env[s[0:j]] = s[j+1:len(s)];
diff -r 597b72316015 -r 620f3b46ef19 src/lib/os/file.go
--- a/src/lib/os/file.go Fri May 08 14:57:56 2009 -0700
+++ b/src/lib/os/file.go Fri May 08 15:21:41 2009 -0700
@@ -132,7 +132,7 @@
if e == syscall.EPIPE {
file.nepipe++;
if file.nepipe >= 10 {
- sys.Exit(syscall.EPIPE);
+ os.Exit(syscall.EPIPE);
}
} else {
file.nepipe = 0;
diff -r 597b72316015 -r 620f3b46ef19 src/lib/regexp/regexp.go
--- a/src/lib/regexp/regexp.go Fri May 08 14:57:56 2009 -0700
+++ b/src/lib/regexp/regexp.go Fri May 08 15:21:41 2009 -0700
@@ -25,6 +25,7 @@
import (
"container/vector";
"os";
+ "runtime";
"utf8";
)
@@ -236,7 +237,7 @@
func (re *Regexp) setError(err os.Error) {
re.error = err;
re.ch <- re;
- sys.Goexit();
+ runtime.Goexit();
}
func (re *Regexp) add(i instr) instr {
diff -r 597b72316015 -r 620f3b46ef19 src/lib/template/template.go
--- a/src/lib/template/template.go Fri May 08 14:57:56 2009 -0700
+++ b/src/lib/template/template.go Fri May 08 15:21:41 2009 -0700
@@ -44,7 +44,7 @@
first looked for in the cursor, as in .section and .repeated.
If it is not found, the search continues in outer sections
until the top level is reached.
-
+
If a formatter is specified, it must be named in the formatter
map passed to the template set up routines or in the default
set ("html","str","") and is used to process the data for
@@ -61,6 +61,7 @@
"io";
"os";
"reflect";
+ "runtime";
"strings";
"template";
"container/vector";
@@ -181,7 +182,7 @@
// Generic error handler, called only from execError or parseError.
func error(errors chan os.Error, line int, err string, args ...) {
errors <- ParseError{fmt.Sprintf("line %d: %s", line, fmt.Sprintf(err, args))};
- sys.Goexit();
+ runtime.Goexit();
}
// Report error and stop executing. The line number must be provided explicitly.
diff -r 597b72316015 -r 620f3b46ef19 src/lib/testing/testing.go
--- a/src/lib/testing/testing.go Fri May 08 14:57:56 2009 -0700
+++ b/src/lib/testing/testing.go Fri May 08 15:21:41 2009 -0700
@@ -14,6 +14,8 @@
import (
"flag";
"fmt";
+ "os";
+ "runtime";
)
// Report as tests are run; default is silent for success.
@@ -47,7 +49,7 @@
func (t *T) FailNow() {
t.Fail();
t.ch <- t;
- sys.Goexit();
+ runtime.Goexit();
}
// Log formats its arguments using default formatting, analogous to Print(),
@@ -129,7 +131,7 @@
}
if !ok {
println("FAIL");
- sys.Exit(1);
+ os.Exit(1);
}
println("PASS");
}
diff -r 597b72316015 -r 620f3b46ef19 src/runtime/386/asm.s
--- a/src/runtime/386/asm.s Fri May 08 14:57:56 2009 -0700
+++ b/src/runtime/386/asm.s Fri May 08 15:21:41 2009 -0700
@@ -84,12 +84,12 @@
CALL initdone(SB)
CALL main·main(SB)
PUSHL $0
- CALL sys·Exit(SB)
+ CALL exit(SB)
POPL AX
INT $3
RET
-TEXT sys·Breakpoint(SB),7,$0
+TEXT breakpoint(SB),7,$0
BYTE $0xcc
RET
diff -r 597b72316015 -r 620f3b46ef19 src/runtime/386/traceback.c
--- a/src/runtime/386/traceback.c Fri May 08 14:57:56 2009 -0700
+++ b/src/runtime/386/traceback.c Fri May 08 15:21:41 2009 -0700
@@ -82,7 +82,7 @@
// func caller(n int) (pc uint64, file string, line int, ok bool)
void
-sys·Caller(int32 n, uint64 retpc, string retfile, int32 retline, bool retbool)
+runtime·Caller(int32 n, uint64 retpc, string retfile, int32 retline, bool retbool)
{
uint64 pc;
byte *sp;
diff -r 597b72316015 -r 620f3b46ef19 src/runtime/amd64/asm.s
--- a/src/runtime/amd64/asm.s Fri May 08 14:57:56 2009 -0700
+++ b/src/runtime/amd64/asm.s Fri May 08 15:21:41 2009 -0700
@@ -55,12 +55,12 @@
CALL initdone(SB)
CALL main·main(SB)
PUSHQ $0
- CALL sys·Exit(SB)
+ CALL exit(SB)
POPQ AX
CALL notok(SB)
RET
-TEXT sys·Breakpoint(SB),7,$0
+TEXT breakpoint(SB),7,$0
BYTE $0xcc
RET
diff -r 597b72316015 -r 620f3b46ef19 src/runtime/amd64/traceback.c
--- a/src/runtime/amd64/traceback.c Fri May 08 14:57:56 2009 -0700
+++ b/src/runtime/amd64/traceback.c Fri May 08 15:21:41 2009 -0700
@@ -79,7 +79,7 @@
// func caller(n int) (pc uint64, file string, line int, ok bool)
void
-sys·Caller(int32 n, uint64 retpc, String retfile, int32 retline, bool retbool)
+runtime·Caller(int32 n, uint64 retpc, String retfile, int32 retline, bool retbool)
{
uint64 pc;
byte *sp;
diff -r 597b72316015 -r 620f3b46ef19 src/runtime/chan.c
--- a/src/runtime/chan.c Fri May 08 14:57:56 2009 -0700
+++ b/src/runtime/chan.c Fri May 08 15:21:41 2009 -0700
@@ -211,7 +211,7 @@
g->status = Gwaiting;
enqueue(&c->sendq, sg);
unlock(&chanlock);
- sys·Gosched();
+ gosched();
lock(&chanlock);
sg = g->param;
@@ -237,7 +237,7 @@
g->status = Gwaiting;
enqueue(&c->sendq, sg);
unlock(&chanlock);
- sys·Gosched();
+ gosched();
lock(&chanlock);
goto asynch;
@@ -311,7 +311,7 @@
g->status = Gwaiting;
enqueue(&c->recvq, sg);
unlock(&chanlock);
- sys·Gosched();
+ gosched();
lock(&chanlock);
sg = g->param;
@@ -339,7 +339,7 @@
g->status = Gwaiting;
enqueue(&c->recvq, sg);
unlock(&chanlock);
- sys·Gosched();
+ gosched();
lock(&chanlock);
goto asynch;
@@ -748,7 +748,7 @@
g->param = nil;
g->status = Gwaiting;
unlock(&chanlock);
- sys·Gosched();
+ gosched();
lock(&chanlock);
sg = g->param;
diff -r 597b72316015 -r 620f3b46ef19 src/runtime/darwin/386/signal.c
--- a/src/runtime/darwin/386/signal.c Fri May 08 14:57:56 2009 -0700
+++ b/src/runtime/darwin/386/signal.c Fri May 08 15:21:41 2009 -0700
@@ -33,7 +33,7 @@
Regs *r;
if(panicking) // traceback already printed
- sys_Exit(2);
+ exit(2);
panicking = 1;
if(sig < 0 || sig >= NSIG){
@@ -56,8 +56,8 @@
dumpregs(r);
}
- sys·Breakpoint();
- sys_Exit(2);
+ breakpoint();
+ exit(2);
}
void
diff -r 597b72316015 -r 620f3b46ef19 src/runtime/darwin/386/sys.s
--- a/src/runtime/darwin/386/sys.s Fri May 08 14:57:56 2009 -0700
+++ b/src/runtime/darwin/386/sys.s Fri May 08 15:21:41 2009 -0700
@@ -11,7 +11,7 @@
RET
// Exit the entire program (like C exit)
-TEXT sys·Exit(SB),7,$0
+TEXT exit(SB),7,$0
MOVL $1, AX
INT $0x80
CALL notok(SB)
diff -r 597b72316015 -r 620f3b46ef19 src/runtime/darwin/amd64/signal.c
--- a/src/runtime/darwin/amd64/signal.c Fri May 08 14:57:56 2009 -0700
+++ b/src/runtime/darwin/amd64/signal.c Fri May 08 15:21:41 2009 -0700
@@ -41,7 +41,7 @@
Regs *r;
if(panicking) // traceback already printed
- sys_Exit(2);
+ exit(2);
panicking = 1;
if(sig < 0 || sig >= NSIG){
@@ -64,8 +64,8 @@
dumpregs(r);
}
- sys·Breakpoint();
- sys_Exit(2);
+ breakpoint();
+ exit(2);
}
void
diff -r 597b72316015 -r 620f3b46ef19 src/runtime/darwin/amd64/sys.s
--- a/src/runtime/darwin/amd64/sys.s Fri May 08 14:57:56 2009 -0700
+++ b/src/runtime/darwin/amd64/sys.s Fri May 08 15:21:41 2009 -0700
@@ -9,7 +9,7 @@
//
// Exit the entire program (like C exit)
-TEXT sys·Exit(SB),7,$-8
+TEXT exit(SB),7,$-8
MOVL 8(SP), DI // arg 1 exit status
MOVL $(0x2000000+1), AX // syscall entry
SYSCALL
diff -r 597b72316015 -r 620f3b46ef19 src/runtime/linux/386/signal.c
--- a/src/runtime/linux/386/signal.c Fri May 08 14:57:56 2009 -0700
+++ b/src/runtime/linux/386/signal.c Fri May 08 15:21:41 2009 -0700
@@ -40,7 +40,7 @@
Sigcontext *sc;
if(panicking) // traceback already printed
- sys_Exit(2);
+ exit(2);
panicking = 1;
uc = context;
@@ -61,8 +61,8 @@
dumpregs(sc);
}
- sys·Breakpoint();
- sys_Exit(2);
+ breakpoint();
+ exit(2);
}
void
diff -r 597b72316015 -r 620f3b46ef19 src/runtime/linux/386/sys.s
--- a/src/runtime/linux/386/sys.s Fri May 08 14:57:56 2009 -0700
+++ b/src/runtime/linux/386/sys.s Fri May 08 15:21:41 2009 -0700
@@ -20,7 +20,7 @@
INT $3 // not reached
RET
-TEXT sys·Exit(SB),7,$0
+TEXT exit(SB),7,$0
MOVL $252, AX // syscall number
MOVL 4(SP), BX
INT $0x80
diff -r 597b72316015 -r 620f3b46ef19 src/runtime/linux/amd64/signal.c
--- a/src/runtime/linux/amd64/signal.c Fri May 08 14:57:56 2009 -0700
+++ b/src/runtime/linux/amd64/signal.c Fri May 08 15:21:41 2009 -0700
@@ -49,7 +49,7 @@
Sigcontext *sc;
if(panicking) // traceback already printed
- sys_Exit(2);
+ exit(2);
panicking = 1;
uc = context;
@@ -71,8 +71,8 @@
dumpregs(sc);
}
- sys·Breakpoint();
- sys_Exit(2);
+ breakpoint();
+ exit(2);
}
void
diff -r 597b72316015 -r 620f3b46ef19 src/runtime/linux/amd64/sys.s
--- a/src/runtime/linux/amd64/sys.s Fri May 08 14:57:56 2009 -0700
+++ b/src/runtime/linux/amd64/sys.s Fri May 08 15:21:41 2009 -0700
@@ -6,7 +6,7 @@
// System calls and other sys.stuff for AMD64, Linux
//
-TEXT sys·Exit(SB),7,$0-8
+TEXT exit(SB),7,$0-8
MOVL 8(SP), DI
MOVL $231, AX // exitgroup - force all os threads to exi
SYSCALL
diff -r 597b72316015 -r 620f3b46ef19 src/runtime/proc.c
--- a/src/runtime/proc.c Fri May 08 14:57:56 2009 -0700
+++ b/src/runtime/proc.c Fri May 08 15:21:41 2009 -0700
@@ -129,7 +129,7 @@
}
void
-sys·Goexit(void)
+goexit(void)
{
if(debug > 1){
lock(&debuglock);
@@ -137,7 +137,7 @@
unlock(&debuglock);
}
g->status = Gmoribund;
- sys·Gosched();
+ gosched();
}
void
@@ -431,7 +431,7 @@
case Gmoribund:
gp->status = Gdead;
if(--sched.gcount == 0)
- sys_Exit(0);
+ exit(0);
break;
}
if(gp->readyonstop){
@@ -461,7 +461,7 @@
// before running g again. If g->status is Gmoribund,
// kills off g.
void
-sys·Gosched(void)
+gosched(void)
{
if(g == m->g0)
throw("gosched of g0");
@@ -529,7 +529,7 @@
// The scheduler will ready g and put this m to sleep.
// When the scheduler takes g awa from m,
// it will undo the sched.mcpu++ above.
- sys·Gosched();
+ gosched();
}
/*
@@ -784,7 +784,7 @@
mcpy(sp, (byte*)&arg0, siz);
sp -= sizeof(uintptr);
- *(byte**)sp = (byte*)sys·Goexit;
+ *(byte**)sp = (byte*)goexit;
sp -= sizeof(uintptr); // retpc used by gogo
newg->sched.SP = sp;
@@ -839,3 +839,21 @@
jmpdefer(sp);
}
+void
+runtime·Breakpoint(void)
+{
+ breakpoint();
+}
+
+void
+runtime·Goexit(void)
+{
+ goexit();
+}
+
+void
+runtime·Gosched(void)
+{
+ gosched();
+}
+
diff -r 597b72316015 -r 620f3b46ef19 src/runtime/runtime.c
--- a/src/runtime/runtime.c Fri May 08 14:57:56 2009 -0700
+++ b/src/runtime/runtime.c Fri May 08 15:21:41 2009 -0700
@@ -25,7 +25,7 @@
if(panicking) {
printf("double panic\n");
- sys_Exit(3);
+ exit(3);
}
panicking++;
@@ -35,8 +35,8 @@
traceback(sys·getcallerpc(&lno), sp, g);
tracebackothers(g);
}
- sys·Breakpoint(); // so we can grab it in a debugger
- sys_Exit(2);
+ breakpoint(); // so we can grab it in a debugger
+ exit(2);
}
void
@@ -57,7 +57,7 @@
printf("throw: %s\n", s);
sys·panicl(-1);
*(int32*)0 = 0; // not reached
- sys_Exit(1); // even more not reached
+ exit(1); // even more not reached
}
void
@@ -136,8 +136,8 @@
static int32 argc;
static uint8** argv;
-Array sys·Args;
-Array sys·Envs;
+Array os·Args;
+Array os·Envs;
void
args(int32 c, uint8 **v)
@@ -161,15 +161,15 @@
for(i=0; i<argc; i++)
gargv[i] = gostring(argv[i]);
- sys·Args.array = (byte*)gargv;
- sys·Args.nel = argc;
- sys·Args.cap = argc;
+ os·Args.array = (byte*)gargv;
+ os·Args.nel = argc;
+ os·Args.cap = argc;
for(i=0; i<envc; i++)
genvv[i] = gostring(argv[argc+1+i]);
- sys·Envs.array = (byte*)genvv;
- sys·Envs.nel = envc;
- sys·Envs.cap = envc;
+ os·Envs.array = (byte*)genvv;
+ os·Envs.nel = envc;
+ os·Envs.cap = envc;
}
byte*
@@ -182,8 +182,8 @@
bs = (byte*)s;
len = findnull(bs);
- envv = (String*)sys·Envs.array;
- envc = sys·Envs.nel;
+ envv = (String*)os·Envs.array;
+ envc = os·Envs.nel;
for(i=0; i<envc; i++){
if(envv[i].len <= len)
continue;
diff -r 597b72316015 -r 620f3b46ef19 src/runtime/runtime.h
--- a/src/runtime/runtime.h Fri May 08 14:57:56 2009 -0700
+++ b/src/runtime/runtime.h Fri May 08 15:21:41 2009 -0700
@@ -329,6 +329,10 @@
void* malloc(uintptr size);
void* mallocgc(uintptr size);
void free(void *v);
+void exit(int32);
+void breakpoint(void);
+void gosched(void);
+void goexit(void);
#pragma varargck argpos printf 1
@@ -378,15 +382,11 @@
* UTF-8 characters in identifiers.
*/
#ifndef __GNUC__
-#define sys_Exit sys·Exit
-#define sys_Gosched sys·Gosched
#define sys_memclr sys·memclr
#define sys_write sys·write
-#define sys_Breakpoint sys·Breakpoint
#define sys_catstring sys·catstring
#define sys_cmpstring sys·cmpstring
#define sys_getcallerpc sys·getcallerpc
-#define sys_Goexit sys·Goexit
#define sys_indexstring sys·indexstring
#define sys_intstring sys·intstring
#define sys_mal sys·mal
@@ -408,11 +408,7 @@
/*
* low level go-called
*/
-void sys_Goexit(void);
-void sys_Gosched(void);
-void sys_Exit(int32);
void sys_write(int32, void*, int32);
-void sys_Breakpoint(void);
uint8* sys_mmap(byte*, uint32, int32, int32, int32, uint32);
void sys_memclr(byte*, uint32);
void sys_setcallerpc(void*, void*);
diff -r 597b72316015 -r 620f3b46ef19 src/runtime/sema.c
--- a/src/runtime/sema.c Fri May 08 14:57:56 2009 -0700
+++ b/src/runtime/sema.c Fri May 08 15:21:41 2009 -0700
@@ -119,7 +119,7 @@
{
USED(s);
g->status = Gwaiting;
- sys·Gosched();
+ gosched();
}
static int32
diff -r 597b72316015 -r 620f3b46ef19 src/runtime/string.c
--- a/src/runtime/string.c Fri May 08 14:57:56 2009 -0700
+++ b/src/runtime/string.c Fri May 08 15:21:41 2009 -0700
@@ -215,8 +215,6 @@
void
sys·stringiter2(String s, int32 k, int32 retk, int32 retv)
{
- int32 l;
-
if(k >= s.len) {
// retk=0 is end of iteration
retk = 0;
diff -r 597b72316015 -r 620f3b46ef19 test/235.go
--- a/test/235.go Fri May 08 14:57:56 2009 -0700
+++ b/test/235.go Fri May 08 15:21:41 2009 -0700
@@ -6,6 +6,8 @@
package main
+import "os"
+
type T chan uint64;
func M(f uint64) (in, out T) {
@@ -65,5 +67,5 @@
x = min(xs);
if x != OUT[i] { panic("bad: ", x, " should be ", OUT[i]); }
}
- sys.Exit(0);
+ os.Exit(0);
}
diff -r 597b72316015 -r 620f3b46ef19 test/args.go
--- a/test/args.go Fri May 08 14:57:56 2009 -0700
+++ b/test/args.go Fri May 08 15:21:41 2009 -0700
@@ -6,14 +6,16 @@
package main
+import "os"
+
func main() {
- if len(sys.Args) != 3 {
+ if len(os.Args) != 3 {
panic("argc")
}
- if sys.Args[1] != "arg1" {
+ if os.Args[1] != "arg1" {
panic("arg1")
}
- if sys.Args[2] != "arg2" {
+ if os.Args[2] != "arg2" {
panic("arg2")
}
}
diff -r 597b72316015 -r 620f3b46ef19 test/chan/fifo.go
--- a/test/chan/fifo.go Fri May 08 14:57:56 2009 -0700
+++ b/test/chan/fifo.go Fri May 08 15:21:41 2009 -0700
@@ -8,6 +8,8 @@
package main
+import "os"
+
const N = 10
func AsynchFifo() {
@@ -18,7 +20,7 @@
for i := 0; i < N; i++ {
if <-ch != i {
print("bad receive\n");
- sys.Exit(1);
+ os.Exit(1);
}
}
}
diff -r 597b72316015 -r 620f3b46ef19 test/chan/goroutines.go
--- a/test/chan/goroutines.go Fri May 08 14:57:56 2009 -0700
+++ b/test/chan/goroutines.go Fri May 08 15:21:41 2009 -0700
@@ -20,12 +20,12 @@
func main() {
var n = 10000;
- if len(sys.Args) > 1 {
+ if len(os.Args) > 1 {
var err os.Error;
- n, err = strconv.Atoi(sys.Args[1]);
+ n, err = strconv.Atoi(os.Args[1]);
if err != nil {
print("bad arg\n");
- sys.Exit(1);
+ os.Exit(1);
}
}
leftmost := make(chan int);
diff -r 597b72316015 -r 620f3b46ef19 test/chan/nonblock.go
--- a/test/chan/nonblock.go Fri May 08 14:57:56 2009 -0700
+++ b/test/chan/nonblock.go Fri May 08 15:21:41 2009 -0700
@@ -9,6 +9,7 @@
package main
+import "runtime"
import "time"
func i32receiver(c chan int32, strobe chan bool) {
@@ -55,9 +56,9 @@
func sleep() {
<-ticker;
<-ticker;
- sys.Gosched();
- sys.Gosched();
- sys.Gosched();
+ runtime.Gosched();
+ runtime.Gosched();
+ runtime.Gosched();
}
func main() {
diff -r 597b72316015 -r 620f3b46ef19 test/chan/powser1.go
--- a/test/chan/powser1.go Fri May 08 14:57:56 2009 -0700
+++ b/test/chan/powser1.go Fri May 08 15:21:41 2009 -0700
@@ -13,6 +13,8 @@
package main
+import "os"
+
type rat struct {
num, den int64; // numerator, denominator
}
@@ -623,7 +625,7 @@
func main() {
Init();
- if len(sys.Args) > 1 { // print
+ if len(os.Args) > 1 { // print
print("Ones: "); printn(Ones, 10);
print("Twos: "); printn(Twos, 10);
print("Add: "); printn(Add(Ones, Twos), 10);
diff -r 597b72316015 -r 620f3b46ef19 test/chan/powser2.go
--- a/test/chan/powser2.go Fri May 08 14:57:56 2009 -0700
+++ b/test/chan/powser2.go Fri May 08 15:21:41 2009 -0700
@@ -16,6 +16,8 @@
package main
+import "os"
+
type rat struct {
num, den int64; // numerator, denominator
}
@@ -636,7 +638,7 @@
func main() {
Init();
- if len(sys.Args) > 1 { // print
+ if len(os.Args) > 1 { // print
print("Ones: "); Printn(Ones, 10);
print("Twos: "); Printn(Twos, 10);
print("Add: "); Printn(Add(Ones, Twos), 10);
diff -r 597b72316015 -r 620f3b46ef19 test/chan/sieve.go
--- a/test/chan/sieve.go Fri May 08 14:57:56 2009 -0700
+++ b/test/chan/sieve.go Fri May 08 15:21:41 2009 -0700
@@ -9,6 +9,8 @@
package main
+import "os"
+
// Send the sequence 2, 3, 4, ... to channel 'ch'.
func Generate(ch chan<- int) {
for i := 2; ; i++ {
@@ -47,5 +49,5 @@
for i := 0; i < len(a); i++ {
if x := <-primes; x != a[i] { panic(x, " != ", a[i]) }
}
- sys.Exit(0);
+ os.Exit(0);
}
diff -r 597b72316015 -r 620f3b46ef19 test/char_lit.go
--- a/test/char_lit.go Fri May 08 14:57:56 2009 -0700
+++ b/test/char_lit.go Fri May 08 15:21:41 2009 -0700
@@ -6,6 +6,8 @@
package main
+import "os"
+
func main() {
var i uint64 =
' ' +
@@ -33,10 +35,10 @@
;
if '\Ucafebabe' != 0xcafebabe {
print("cafebabe wrong\n");
- sys.Exit(1)
+ os.Exit(1)
}
if i != 0xcc238de1 {
print("number is ", i, " should be ", 0xcc238de1, "\n");
- sys.Exit(1)
+ os.Exit(1)
}
}
diff -r 597b72316015 -r 620f3b46ef19 test/env.go
--- a/test/env.go Fri May 08 14:57:56 2009 -0700
+++ b/test/env.go Fri May 08 15:21:41 2009 -0700
@@ -12,15 +12,15 @@
ga, e0 := os.Getenv("GOARCH");
if e0 != nil {
print("$GOARCH: ", e0.String(), "\n");
- sys.Exit(1);
+ os.Exit(1);
}
if ga != "amd64" {
print("$GOARCH=", ga, "\n");
- sys.Exit(1);
+ os.Exit(1);
}
xxx, e1 := os.Getenv("DOES_NOT_EXIST");
if e1 != os.ENOENV {
print("$DOES_NOT_EXIST=", xxx, "; err = ", e1.String(), "\n");
- sys.Exit(1);
+ os.Exit(1);
}
}
diff -r 597b72316015 -r 620f3b46ef19 test/fixedbugs/bug006.go
--- a/test/fixedbugs/bug006.go Fri May 08 14:57:56 2009 -0700
+++ b/test/fixedbugs/bug006.go Fri May 08 15:21:41 2009 -0700
@@ -6,6 +6,8 @@
package main
+import "os"
+
const (
x float = iota;
g float = 4.5 * iota;
@@ -13,5 +15,5 @@
func main() {
if g == 0.0 { print("zero\n");}
- if g != 4.5 { print(" fail\n"); sys.Exit(1); }
+ if g != 4.5 { print(" fail\n"); os.Exit(1); }
}
diff -r 597b72316015 -r 620f3b46ef19 test/fixedbugs/bug059.go
--- a/test/fixedbugs/bug059.go Fri May 08 14:57:56 2009 -0700
+++ b/test/fixedbugs/bug059.go Fri May 08 15:21:41 2009 -0700
@@ -6,6 +6,8 @@
package main
+import "os"
+
func P(a []string) string {
s := "{";
for i := 0; i < 2; i++ {
@@ -29,6 +31,6 @@
a[0] = "x";
m["0"][0] = "deleted";
if m["0"][0] != "deleted" {
- sys.Exit(1);
+ os.Exit(1);
}
}
diff -r 597b72316015 -r 620f3b46ef19 test/fixedbugs/bug060.go
--- a/test/fixedbugs/bug060.go Fri May 08 14:57:56 2009 -0700
+++ b/test/fixedbugs/bug060.go Fri May 08 15:21:41 2009 -0700
@@ -6,12 +6,14 @@
package main
+import "os"
+
func main() {
m := make(map[int]int);
m[0] = 0;
m[0]++;
if m[0] != 1 {
print("map does not increment\n");
- sys.Exit(1)
+ os.Exit(1)
}
}
diff -r 597b72316015 -r 620f3b46ef19 test/fixedbugs/bug120.go
--- a/test/fixedbugs/bug120.go Fri May 08 14:57:56 2009 -0700
+++ b/test/fixedbugs/bug120.go Fri May 08 15:21:41 2009 -0700
@@ -6,6 +6,7 @@
package main
+import "os"
import "strconv";
type Test struct {
@@ -53,6 +54,6 @@
}
}
if !ok {
- sys.Exit(1);
+ os.Exit(1);
}
}
diff -r 597b72316015 -r 620f3b46ef19 test/fixedbugs/bug130.go
--- a/test/fixedbugs/bug130.go Fri May 08 14:57:56 2009 -0700
+++ b/test/fixedbugs/bug130.go Fri May 08 15:21:41 2009 -0700
@@ -6,6 +6,8 @@
package main
+import "os"
+
type I interface { send(chan <- int) }
type S struct { v int }
@@ -16,5 +18,5 @@
var i I = &s;
c := make(chan int);
go i.send(c);
- sys.Exit(<-c);
+ os.Exit(<-c);
}
diff -r 597b72316015 -r 620f3b46ef19 test/fixedbugs/bug141.go
--- a/test/fixedbugs/bug141.go Fri May 08 14:57:56 2009 -0700
+++ b/test/fixedbugs/bug141.go Fri May 08 15:21:41 2009 -0700
@@ -6,6 +6,8 @@
package main
+import "os"
+
type S struct { i int }
func (p *S) Get() int { return p.i }
@@ -18,7 +20,7 @@
func f1(p Empty) {
switch x := p.(type) {
- default: println("failed to match interface"); sys.Exit(1);
+ default: println("failed to match interface"); os.Exit(1);
case Getter: break;
}
diff -r 597b72316015 -r 620f3b46ef19 test/if1.go
--- a/test/if1.go Fri May 08 14:57:56 2009 -0700
+++ b/test/if1.go Fri May 08 15:21:41 2009 -0700
@@ -6,6 +6,8 @@
package main
+import "os"
+
func main() {
count := 7;
if one := 1; {
@@ -13,6 +15,6 @@
}
if count != 8 {
print(count, " should be 8\n");
- sys.Exit(1)
+ os.Exit(1)
}
}
diff -r 597b72316015 -r 620f3b46ef19 test/int_lit.go
--- a/test/int_lit.go Fri May 08 14:57:56 2009 -0700
+++ b/test/int_lit.go Fri May 08 15:21:41 2009 -0700
@@ -6,6 +6,8 @@
package main
+import "os"
+
func main() {
s :=
0 +
@@ -18,6 +20,6 @@
0X123;
if s != 788 {
print("s is ", s, "; should be 788\n");
- sys.Exit(1);
+ os.Exit(1);
}
}
diff -r 597b72316015 -r 620f3b46ef19 test/interface10.go
--- a/test/interface10.go Fri May 08 14:57:56 2009 -0700
+++ b/test/interface10.go Fri May 08 15:21:41 2009 -0700
@@ -6,6 +6,8 @@
package main
+import "os"
+
const Value = 1e12
type Inter interface { M() int64 }
@@ -73,6 +75,6 @@
if !ok {
println("BUG: interface10");
- sys.Exit(1)
+ os.Exit(1)
}
}
diff -r 597b72316015 -r 620f3b46ef19 test/interface4.go
--- a/test/interface4.go Fri May 08 14:57:56 2009 -0700
+++ b/test/interface4.go Fri May 08 15:21:41 2009 -0700
@@ -9,6 +9,8 @@
package main
+import "os"
+
type I interface { M() int64 }
type BigPtr struct { a, b, c, d int64 }
@@ -70,6 +72,6 @@
nonptrs();
if bad {
- sys.Exit(1)
+ os.Exit(1)
}
}
diff -r 597b72316015 -r 620f3b46ef19 test/interface6.go
--- a/test/interface6.go Fri May 08 14:57:56 2009 -0700
+++ b/test/interface6.go Fri May 08 15:21:41 2009 -0700
@@ -6,6 +6,8 @@
package main
+import "os"
+
var fail int
func check(b bool, msg string) {
@@ -145,6 +147,6 @@
f11();
f12();
if fail > 0 {
- sys.Exit(1)
+ os.Exit(1)
}
}
diff -r 597b72316015 -r 620f3b46ef19 test/ken/chan.go
--- a/test/ken/chan.go Fri May 08 14:57:56 2009 -0700
+++ b/test/ken/chan.go Fri May 08 15:21:41 2009 -0700
@@ -6,6 +6,8 @@
package main
+import "os"
+import "runtime"
var randx int;
@@ -88,7 +90,7 @@
nproc++; // total goroutines running
for {
for r:=nrand(10); r>=0; r-- {
- sys.Gosched();
+ runtime.Gosched();
}
c.sc <- c.sv;
if c.send() {
@@ -119,7 +121,7 @@
nproc++; // total goroutines running
for {
for r:=nrand(10); r>=0; r-- {
- sys.Gosched();
+ runtime.Gosched();
}
v = <-c.rc;
if c.recv(v) {
@@ -148,7 +150,7 @@
for {
for r:=nrand(5); r>=0; r-- {
- sys.Gosched();
+ runtime.Gosched();
}
select {
@@ -270,9 +272,9 @@
func
wait()
{
- sys.Gosched();
+ runtime.Gosched();
for nproc != 0 {
- sys.Gosched();
+ runtime.Gosched();
}
}
@@ -321,7 +323,7 @@
if tots != t || totr != t {
print("tots=", tots, " totr=", totr, " sb=", t, "\n");
- sys.Exit(1);
+ os.Exit(1);
}
- sys.Exit(0);
+ os.Exit(0);
}
diff -r 597b72316015 -r 620f3b46ef19 test/ken/chan1.go
--- a/test/ken/chan1.go Fri May 08 14:57:56 2009 -0700
+++ b/test/ken/chan1.go Fri May 08 15:21:41 2009 -0700
@@ -6,6 +6,8 @@
package main
+import "runtime"
+
const N = 1000; // sent messages
const M = 10; // receiving goroutines
const W = 2; // channel buffering
@@ -48,9 +50,9 @@
c := make(chan int, W);
for m:=0; m<M; m++ {
go r(c, m);
- sys.Gosched();
+ runtime.Gosched();
}
- sys.Gosched();
- sys.Gosched();
+ runtime.Gosched();
+ runtime.Gosched();
s(c);
}
diff -r 597b72316015 -r 620f3b46ef19 test/string_lit.go
--- a/test/string_lit.go Fri May 08 14:57:56 2009 -0700
+++ b/test/string_lit.go Fri May 08 15:21:41 2009 -0700
@@ -6,6 +6,8 @@
package main
+import "os"
+
var ecode int;
func assert(a, b, c string) {
@@ -84,5 +86,5 @@
r = 0x10ffff + 1;
s = string(r);
assert(s, "\xef\xbf\xbd", "too-large rune");
- sys.Exit(ecode);
+ os.Exit(ecode);
}
diff -r 597b72316015 -r 620f3b46ef19 test/stringrange.go
--- a/test/stringrange.go Fri May 08 14:57:56 2009 -0700
+++ b/test/stringrange.go Fri May 08 15:21:41 2009 -0700
@@ -8,6 +8,7 @@
import(
"fmt";
+ "os";
"utf8";
)
@@ -56,6 +57,6 @@
if !ok {
fmt.Println("BUG: stringrange");
- sys.Exit(1)
+ os.Exit(1)
}
}
diff -r 597b72316015 -r 620f3b46ef19 test/switch1.go
--- a/test/switch1.go Fri May 08 14:57:56 2009 -0700
+++ b/test/switch1.go Fri May 08 15:21:41 2009 -0700
@@ -6,13 +6,15 @@
package main
+import "os"
+
func main() {
i := 0;
switch x := 5; {
case i < x:
- sys.Exit(0);
+ os.Exit(0);
case i == x:
case i > x:
- sys.Exit(1);
+ os.Exit(1);
}
}
diff -r 597b72316015 -r 620f3b46ef19 test/typeswitch.go
--- a/test/typeswitch.go Fri May 08 14:57:56 2009 -0700
+++ b/test/typeswitch.go Fri May 08 15:21:41 2009 -0700
@@ -6,6 +6,8 @@
package main
+import "os"
+
const (
Bool = iota;
Int;
@@ -31,7 +33,7 @@
func assert(b bool, s string) {
if !b {
println(s);
- sys.Exit(1);
+ os.Exit(1);
}
}
diff -r 597b72316015 -r 620f3b46ef19 usr/gri/pretty/godoc.go
--- a/usr/gri/pretty/godoc.go Fri May 08 14:57:56 2009 -0700
+++ b/usr/gri/pretty/godoc.go Fri May 08 15:21:41 2009 -0700
@@ -641,7 +641,7 @@
return info;
}
}
-
+
info.Packages = paks;
if cname == "." {
info.Path = "";
@@ -704,7 +704,7 @@
" godoc -http=:6060\n"
);
flag.PrintDefaults();
- sys.Exit(1);
+ os.Exit(1);
}
@@ -761,7 +761,7 @@
if err != nil {
log.Stderrf("packagelistText.Execute: %s", err);
}
- sys.Exit(1);
+ os.Exit(1);
}
doc, errors := info.Package.Doc();
@@ -770,7 +770,7 @@
if err != nil {
log.Stderrf("parseerrorText.Execute: %s", err);
}
- sys.Exit(1);
+ os.Exit(1);
}
if flag.NArg() > 1 {
diff -r 597b72316015 -r 620f3b46ef19 usr/gri/pretty/pretty.go
--- a/usr/gri/pretty/pretty.go Fri May 08 14:57:56 2009 -0700
+++ b/usr/gri/pretty/pretty.go Fri May 08 15:21:41 2009 -0700
@@ -41,7 +41,7 @@
func usage() {
fmt.Fprintf(os.Stderr, "usage: pretty { flags } { files }\n");
flag.PrintDefaults();
- sys.Exit(1);
+ os.Exit(1);
}
@@ -127,12 +127,12 @@
src, err := readFile(ast_txt);
if err != nil {
fmt.Fprintf(os.Stderr, "%s: %v\n", ast_txt, err);
- sys.Exit(1);
+ os.Exit(1);
}
ast_format, err := format.Parse(src, format.FormatterMap{"isValidPos": isValidPos, "isSend": isSend, "isRecv": isRecv});
if err != nil {
fmt.Fprintf(os.Stderr, "%s: format errors:\n%s", ast_txt, err);
- sys.Exit(1);
+ os.Exit(1);
}
// process files
@@ -150,7 +150,7 @@
prog, ok := parser.Parse(src, &ErrorHandler{filename, 0}, mode);
if !ok {
exitcode = 1;
- continue; // proceed with next file
+ continue; // proceed with next file
}
if !*silent {
@@ -165,6 +165,6 @@
tw.Flush();
}
}
-
- sys.Exit(exitcode);
+
+ os.Exit(exitcode);
}
diff -r 597b72316015 -r 620f3b46ef19 usr/gri/pretty/untab.go
--- a/usr/gri/pretty/untab.go Fri May 08 14:57:56 2009 -0700
+++ b/usr/gri/pretty/untab.go Fri May 08 15:21:41 2009 -0700
@@ -21,7 +21,7 @@
func error(format string, params ...) {
fmt.Printf(format, params);
- sys.Exit(1);
+ os.Exit(1);
}
This file has been truncated, but you can view the full file.
changeset: 2420:31d3a7baefdd
user: Russ Cox <[email protected]>
date: Sat Jun 06 22:04:39 2009 -0700
summary: move src/runtime -> src/lib/runtime;
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/386/asm.s
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/386/asm.s Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,217 @@
+// Copyright 2009 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.
+
+TEXT _rt0_386(SB),7,$0
+ // copy arguments forward on an even stack
+ MOVL 0(SP), AX // argc
+ LEAL 4(SP), BX // argv
+ SUBL $128, SP // plenty of scratch
+ ANDL $~7, SP
+ MOVL AX, 120(SP) // save argc, argv away
+ MOVL BX, 124(SP)
+
+/*
+ // write "go386\n"
+ PUSHL $6
+ PUSHL $hello(SB)
+ PUSHL $1
+ CALL sys·write(SB)
+ POPL AX
+ POPL AX
+ POPL AX
+*/
+
+ CALL ldt0setup(SB)
+
+ // set up %fs to refer to that ldt entry
+ MOVL $(7*8+7), AX
+ MOVW AX, FS
+
+ // store through it, to make sure it works
+ MOVL $0x123, 0(FS)
+ MOVL tls0(SB), AX
+ CMPL AX, $0x123
+ JEQ ok
+ MOVL AX, 0
+ok:
+
+ // set up m and g "registers"
+ // g is 0(FS), m is 4(FS)
+ LEAL g0(SB), CX
+ MOVL CX, 0(FS)
+ LEAL m0(SB), AX
+ MOVL AX, 4(FS)
+
+ // save m->g0 = g0
+ MOVL CX, 0(AX)
+
+ // create istack out of the OS stack
+ LEAL (-8192+104)(SP), AX // TODO: 104?
+ MOVL AX, 0(CX) // 8(g) is stack limit (w 104b guard)
+ MOVL SP, 4(CX) // 12(g) is base
+ CALL emptyfunc(SB) // fault if stack check is wrong
+
+ // convention is D is always cleared
+ CLD
+
+ CALL check(SB)
+
+ // saved argc, argv
+ MOVL 120(SP), AX
+ MOVL AX, 0(SP)
+ MOVL 124(SP), AX
+ MOVL AX, 4(SP)
+ CALL args(SB)
+ CALL osinit(SB)
+ CALL schedinit(SB)
+
+ // create a new goroutine to start program
+ PUSHL $mainstart(SB) // entry
+ PUSHL $8 // arg size
+ CALL sys·newproc(SB)
+ POPL AX
+ POPL AX
+
+ // start this M
+ CALL mstart(SB)
+
+ INT $3
+ RET
+
+TEXT mainstart(SB),7,$0
+ CALL main·init(SB)
+ CALL initdone(SB)
+ CALL main·main(SB)
+ PUSHL $0
+ CALL exit(SB)
+ POPL AX
+ INT $3
+ RET
+
+TEXT breakpoint(SB),7,$0
+ BYTE $0xcc
+ RET
+
+// go-routine
+TEXT gogo(SB), 7, $0
+ MOVL 4(SP), AX // gobuf
+ MOVL 0(AX), SP // restore SP
+ MOVL 4(AX), AX
+ MOVL AX, 0(SP) // put PC on the stack
+ MOVL $1, AX
+ RET
+
+TEXT gosave(SB), 7, $0
+ MOVL 4(SP), AX // gobuf
+ MOVL SP, 0(AX) // save SP
+ MOVL 0(SP), BX
+ MOVL BX, 4(AX) // save PC
+ MOVL $0, AX // return 0
+ RET
+
+// support for morestack
+
+// return point when leaving new stack.
+// save AX, jmp to lesstack to switch back
+TEXT retfromnewstack(SB),7,$0
+ MOVL 4(FS), BX // m
+ MOVL AX, 12(BX) // save AX in m->cret
+ JMP lessstack(SB)
+
+// gogo, returning 2nd arg instead of 1
+TEXT gogoret(SB), 7, $0
+ MOVL 8(SP), AX // return 2nd arg
+ MOVL 4(SP), BX // gobuf
+ MOVL 0(BX), SP // restore SP
+ MOVL 4(BX), BX
+ MOVL BX, 0(SP) // put PC on the stack
+ RET
+
+TEXT setspgoto(SB), 7, $0
+ MOVL 4(SP), AX // SP
+ MOVL 8(SP), BX // fn to call
+ MOVL 12(SP), CX // fn to return
+ MOVL AX, SP
+ PUSHL CX
+ JMP BX
+ POPL AX // not reached
+ RET
+
+// bool cas(int32 *val, int32 old, int32 new)
+// Atomically:
+// if(*val == old){
+// *val = new;
+// return 1;
+// }else
+// return 0;
+TEXT cas(SB), 7, $0
+ MOVL 4(SP), BX
+ MOVL 8(SP), AX
+ MOVL 12(SP), CX
+ LOCK
+ CMPXCHGL CX, 0(BX)
+ JZ 3(PC)
+ MOVL $0, AX
+ RET
+ MOVL $1, AX
+ RET
+
+// void jmpdefer(fn, sp);
+// called from deferreturn.
+// 1. pop the caller
+// 2. sub 5 bytes from the callers return
+// 3. jmp to the argument
+TEXT jmpdefer(SB), 7, $0
+ MOVL 4(SP), AX // fn
+ MOVL 8(SP), BX // caller sp
+ LEAL -4(BX), SP // caller sp after CALL
+ SUBL $5, (SP) // return to CALL again
+ JMP AX // but first run the deferred function
+
+TEXT sys·memclr(SB),7,$0
+ MOVL 4(SP), DI // arg 1 addr
+ MOVL 8(SP), CX // arg 2 count
+ ADDL $3, CX
+ SHRL $2, CX
+ MOVL $0, AX
+ CLD
+ REP
+ STOSL
+ RET
+
+TEXT sys·getcallerpc+0(SB),7,$0
+ MOVL x+0(FP),AX // addr of first arg
+ MOVL -4(AX),AX // get calling pc
+ RET
+
+TEXT sys·setcallerpc+0(SB),7,$0
+ MOVL x+0(FP),AX // addr of first arg
+ MOVL x+4(FP), BX
+ MOVL BX, -4(AX) // set calling pc
+ RET
+
+TEXT ldt0setup(SB),7,$16
+ // set up ldt 7 to point at tls0
+ // ldt 1 would be fine on Linux, but on OS X, 7 is as low as we can go.
+ MOVL $7, 0(SP)
+ LEAL tls0(SB), AX
+ MOVL AX, 4(SP)
+ MOVL $32, 8(SP) // sizeof(tls array)
+ CALL setldt(SB)
+ RET
+
+GLOBL m0+0(SB), $1024
+GLOBL g0+0(SB), $1024
+
+GLOBL tls0+0(SB), $32
+
+TEXT emptyfunc(SB),0,$0
+ RET
+
+TEXT abort(SB),7,$0
+ INT $0x3
+
+DATA hello+0(SB)/8, $"go386\n\z\z"
+GLOBL hello+0(SB), $8
+
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/386/closure.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/386/closure.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,104 @@
+// Copyright 2009 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.
+
+#include "runtime.h"
+
+#pragma textflag 7
+// func closure(siz int32,
+// fn func(arg0, arg1, arg2 *ptr, callerpc uintptr, xxx) yyy,
+// arg0, arg1, arg2 *ptr) (func(xxx) yyy)
+void
+sys·closure(int32 siz, byte *fn, byte *arg0)
+{
+ byte *p, *q, **ret;
+ int32 i, n;
+ int32 pcrel;
+
+ if(siz < 0 || siz%4 != 0)
+ throw("bad closure size");
+
+ ret = (byte**)((byte*)&arg0 + siz);
+
+ if(siz > 100) {
+ // TODO(rsc): implement stack growth preamble?
+ throw("closure too big");
+ }
+
+ // compute size of new fn.
+ // must match code laid out below.
+ n = 6+5+2+1; // SUBL MOVL MOVL CLD
+ if(siz <= 4*4)
+ n += 1*siz/4; // MOVSL MOVSL...
+ else
+ n += 6+2; // MOVL REP MOVSL
+ n += 5; // CALL
+ n += 6+1; // ADDL RET
+
+ // store args aligned after code, so gc can find them.
+ n += siz;
+ if(n%4)
+ n += 4 - n%4;
+
+ p = mal(n);
+ *ret = p;
+ q = p + n - siz;
+ mcpy(q, (byte*)&arg0, siz);
+
+ // SUBL $siz, SP
+ *p++ = 0x81;
+ *p++ = 0xec;
+ *(uint32*)p = siz;
+ p += 4;
+
+ // MOVL $q, SI
+ *p++ = 0xbe;
+ *(byte**)p = q;
+ p += 4;
+
+ // MOVL SP, DI
+ *p++ = 0x89;
+ *p++ = 0xe7;
+
+ // CLD
+ *p++ = 0xfc;
+
+ if(siz <= 4*4) {
+ for(i=0; i<siz; i+=4) {
+ // MOVSL
+ *p++ = 0xa5;
+ }
+ } else {
+ // MOVL $(siz/4), CX [32-bit immediate siz/4]
+ *p++ = 0xc7;
+ *p++ = 0xc1;
+ *(uint32*)p = siz/4;
+ p += 4;
+
+ // REP; MOVSL
+ *p++ = 0xf3;
+ *p++ = 0xa5;
+ }
+
+ // call fn
+ pcrel = fn - (p+5);
+ // direct call with pc-relative offset
+ // CALL fn
+ *p++ = 0xe8;
+ *(int32*)p = pcrel;
+ p += 4;
+
+ // ADDL $siz, SP
+ *p++ = 0x81;
+ *p++ = 0xc4;
+ *(uint32*)p = siz;
+ p += 4;
+
+ // RET
+ *p++ = 0xc3;
+
+ if(p > q)
+ throw("bad math in sys.closure");
+}
+
+
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/386/traceback.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/386/traceback.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,148 @@
+// Copyright 2009 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.
+
+#include "runtime.h"
+
+// TODO(rsc): Move this into portable code, with calls to a
+// machine-dependent isclosure() function.
+
+void
+traceback(byte *pc0, byte *sp, G *g)
+{
+ Stktop *stk;
+ uintptr pc;
+ int32 i, n;
+ Func *f;
+ byte *p;
+
+ pc = (uintptr)pc0;
+
+ // If the PC is zero, it's likely a nil function call.
+ // Start in the caller's frame.
+ if(pc == 0) {
+ pc = *(uintptr*)sp;
+ sp += sizeof(uintptr);
+ }
+
+ stk = (Stktop*)g->stackbase;
+ for(n=0; n<100; n++) {
+ while(pc == (uintptr)retfromnewstack) {
+ // pop to earlier stack block
+ sp = stk->oldsp;
+ stk = (Stktop*)stk->oldbase;
+ pc = *(uintptr*)(sp+sizeof(uintptr));
+ sp += 2*sizeof(uintptr); // two irrelevant calls on stack: morestack plus its call
+ }
+ f = findfunc(pc);
+ if(f == nil) {
+ // dangerous, but poke around to see if it is a closure
+ p = (byte*)pc;
+ // ADDL $xxx, SP; RET
+ if(p[0] == 0x81 && p[1] == 0xc4 && p[6] == 0xc3) {
+ sp += *(uint32*)(p+2) + 8;
+ pc = *(uintptr*)(sp - 8);
+ if(pc <= 0x1000)
+ return;
+ continue;
+ }
+ printf("%p unknown pc\n", pc);
+ return;
+ }
+ if(f->frame < sizeof(uintptr)) // assembly funcs say 0 but lie
+ sp += sizeof(uintptr);
+ else
+ sp += f->frame;
+
+ // print this frame
+ // main+0xf /home/rsc/go/src/runtime/x.go:23
+ // main(0x1, 0x2, 0x3)
+ printf("%S", f->name);
+ if(pc > f->entry)
+ printf("+%p", (uintptr)(pc - f->entry));
+ printf(" %S:%d\n", f->src, funcline(f, pc-1)); // -1 to get to CALL instr.
+ printf("\t%S(", f->name);
+ for(i = 0; i < f->args; i++) {
+ if(i != 0)
+ prints(", ");
+ sys·printhex(((uint32*)sp)[i]);
+ if(i >= 4) {
+ prints(", ...");
+ break;
+ }
+ }
+ prints(")\n");
+
+ pc = *(uintptr*)(sp-sizeof(uintptr));
+ if(pc <= 0x1000)
+ return;
+ }
+ prints("...\n");
+}
+
+// func caller(n int) (pc uintptr, file string, line int, ok bool)
+void
+runtime·Caller(int32 n, uintptr retpc, String retfile, int32 retline, bool retbool)
+{
+ uintptr pc;
+ byte *sp;
+ byte *p;
+ Stktop *stk;
+ Func *f;
+
+ // our caller's pc, sp.
+ sp = (byte*)&n;
+ pc = *((uintptr*)sp - 1);
+ if((f = findfunc(pc)) == nil) {
+ error:
+ retpc = 0;
+ retline = 0;
+ retfile = emptystring;
+ retbool = false;
+ FLUSH(&retpc);
+ FLUSH(&retfile);
+ FLUSH(&retline);
+ FLUSH(&retbool);
+ return;
+ }
+
+ // now unwind n levels
+ stk = (Stktop*)g->stackbase;
+ while(n-- > 0) {
+ while(pc == (uintptr)retfromnewstack) {
+ sp = stk->oldsp;
+ stk = (Stktop*)stk->oldbase;
+ pc = *((uintptr*)sp + 1);
+ sp += 2*sizeof(uintptr);
+ }
+
+ if(f->frame < sizeof(uintptr)) // assembly functions lie
+ sp += sizeof(uintptr);
+ else
+ sp += f->frame;
+
+ loop:
+ pc = *((uintptr*)sp - 1);
+ if(pc <= 0x1000 || (f = findfunc(pc)) == nil) {
+ // dangerous, but let's try this.
+ // see if it is a closure.
+ p = (byte*)pc;
+ // ADDL $xxx, SP; RET
+ if(p[0] == 0x81 && p[1] == 0xc4 && p[6] == 0xc3) {
+ sp += *(uint32*)(p+2) + sizeof(uintptr);
+ goto loop;
+ }
+ goto error;
+ }
+ }
+
+ retpc = pc;
+ retfile = f->src;
+ retline = funcline(f, pc-1);
+ retbool = true;
+ FLUSH(&retpc);
+ FLUSH(&retfile);
+ FLUSH(&retline);
+ FLUSH(&retbool);
+}
+
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/386/vlop.s
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/386/vlop.s Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,48 @@
+// Inferno's libkern/vlop-386.s
+// http://code.google.com/p/inferno-os/source/browse/libkern/vlop-386.s
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+// Portions Copyright 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+/*
+ * C runtime for 64-bit divide.
+ */
+
+TEXT _mul64by32(SB), 7, $0
+ MOVL r+0(FP), CX
+ MOVL a+4(FP), AX
+ MULL b+12(FP)
+ MOVL AX, 0(CX)
+ MOVL DX, BX
+ MOVL a+8(FP), AX
+ MULL b+12(FP)
+ ADDL AX, BX
+ MOVL BX, 4(CX)
+ RET
+
+TEXT _div64by32(SB), 7, $0
+ MOVL r+12(FP), CX
+ MOVL a+0(FP), AX
+ MOVL a+4(FP), DX
+ DIVL b+8(FP)
+ MOVL DX, 0(CX)
+ RET
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/386/vlrt.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/386/vlrt.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,815 @@
+// Inferno's libkern/vlrt-386.c
+// http://code.google.com/p/inferno-os/source/browse/libkern/vlrt-386.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
+// Portions Copyright 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+/*
+ * C runtime for 64-bit divide, others.
+ *
+ * TODO(rsc): The simple functions are dregs--8c knows how
+ * to generate the code directly now. Find and remove.
+ */
+
+typedef unsigned long ulong;
+typedef unsigned int uint;
+typedef unsigned short ushort;
+typedef unsigned char uchar;
+typedef signed char schar;
+
+#define SIGN(n) (1UL<<(n-1))
+
+typedef struct Vlong Vlong;
+struct Vlong
+{
+ union
+ {
+ long long v;
+ struct
+ {
+ ulong lo;
+ ulong hi;
+ };
+ struct
+ {
+ ushort lols;
+ ushort loms;
+ ushort hils;
+ ushort hims;
+ };
+ };
+};
+
+void abort(void);
+
+void
+_d2v(Vlong *y, double d)
+{
+ union { double d; struct Vlong; } x;
+ ulong xhi, xlo, ylo, yhi;
+ int sh;
+
+ x.d = d;
+
+ xhi = (x.hi & 0xfffff) | 0x100000;
+ xlo = x.lo;
+ sh = 1075 - ((x.hi >> 20) & 0x7ff);
+
+ ylo = 0;
+ yhi = 0;
+ if(sh >= 0) {
+ /* v = (hi||lo) >> sh */
+ if(sh < 32) {
+ if(sh == 0) {
+ ylo = xlo;
+ yhi = xhi;
+ } else {
+ ylo = (xlo >> sh) | (xhi << (32-sh));
+ yhi = xhi >> sh;
+ }
+ } else {
+ if(sh == 32) {
+ ylo = xhi;
+ } else
+ if(sh < 64) {
+ ylo = xhi >> (sh-32);
+ }
+ }
+ } else {
+ /* v = (hi||lo) << -sh */
+ sh = -sh;
+ if(sh <= 10) {
+ ylo = xlo << sh;
+ yhi = (xhi << sh) | (xlo >> (32-sh));
+ } else {
+ /* overflow */
+ yhi = d; /* causes something awful */
+ }
+ }
+ if(x.hi & SIGN(32)) {
+ if(ylo != 0) {
+ ylo = -ylo;
+ yhi = ~yhi;
+ } else
+ yhi = -yhi;
+ }
+
+ y->hi = yhi;
+ y->lo = ylo;
+}
+
+void
+_f2v(Vlong *y, float f)
+{
+
+ _d2v(y, f);
+}
+
+double
+_v2d(Vlong x)
+{
+ if(x.hi & SIGN(32)) {
+ if(x.lo) {
+ x.lo = -x.lo;
+ x.hi = ~x.hi;
+ } else
+ x.hi = -x.hi;
+ return -((long)x.hi*4294967296. + x.lo);
+ }
+ return (long)x.hi*4294967296. + x.lo;
+}
+
+float
+_v2f(Vlong x)
+{
+ return _v2d(x);
+}
+
+ulong _div64by32(Vlong, ulong, ulong*);
+void _mul64by32(Vlong*, Vlong, ulong);
+
+static void
+slowdodiv(Vlong num, Vlong den, Vlong *q, Vlong *r)
+{
+ ulong numlo, numhi, denhi, denlo, quohi, quolo, t;
+ int i;
+
+ numhi = num.hi;
+ numlo = num.lo;
+ denhi = den.hi;
+ denlo = den.lo;
+
+ /*
+ * get a divide by zero
+ */
+ if(denlo==0 && denhi==0) {
+ numlo = numlo / denlo;
+ }
+
+ /*
+ * set up the divisor and find the number of iterations needed
+ */
+ if(numhi >= SIGN(32)) {
+ quohi = SIGN(32);
+ quolo = 0;
+ } else {
+ quohi = numhi;
+ quolo = numlo;
+ }
+ i = 0;
+ while(denhi < quohi || (denhi == quohi && denlo < quolo)) {
+ denhi = (denhi<<1) | (denlo>>31);
+ denlo <<= 1;
+ i++;
+ }
+
+ quohi = 0;
+ quolo = 0;
+ for(; i >= 0; i--) {
+ quohi = (quohi<<1) | (quolo>>31);
+ quolo <<= 1;
+ if(numhi > denhi || (numhi == denhi && numlo >= denlo)) {
+ t = numlo;
+ numlo -= denlo;
+ if(numlo > t)
+ numhi--;
+ numhi -= denhi;
+ quolo |= 1;
+ }
+ denlo = (denlo>>1) | (denhi<<31);
+ denhi >>= 1;
+ }
+
+ if(q) {
+ q->lo = quolo;
+ q->hi = quohi;
+ }
+ if(r) {
+ r->lo = numlo;
+ r->hi = numhi;
+ }
+}
+
+static void
+dodiv(Vlong num, Vlong den, Vlong *qp, Vlong *rp)
+{
+ ulong n;
+ Vlong x, q, r;
+
+ if(den.hi > num.hi || (den.hi == num.hi && den.lo > num.lo)){
+ if(qp) {
+ qp->hi = 0;
+ qp->lo = 0;
+ }
+ if(rp) {
+ rp->hi = num.hi;
+ rp->lo = num.lo;
+ }
+ return;
+ }
+
+ if(den.hi != 0){
+ q.hi = 0;
+ n = num.hi/den.hi;
+ _mul64by32(&x, den, n);
+ if(x.hi > num.hi || (x.hi == num.hi && x.lo > num.lo))
+ slowdodiv(num, den, &q, &r);
+ else {
+ q.lo = n;
+ r.v = num.v - x.v;
+ }
+ } else {
+ if(num.hi >= den.lo){
+ q.hi = n = num.hi/den.lo;
+ num.hi -= den.lo*n;
+ } else {
+ q.hi = 0;
+ }
+ q.lo = _div64by32(num, den.lo, &r.lo);
+ r.hi = 0;
+ }
+ if(qp) {
+ qp->lo = q.lo;
+ qp->hi = q.hi;
+ }
+ if(rp) {
+ rp->lo = r.lo;
+ rp->hi = r.hi;
+ }
+}
+
+void
+_divvu(Vlong *q, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ q->hi = 0;
+ q->lo = n.lo / d.lo;
+ return;
+ }
+ dodiv(n, d, q, 0);
+}
+
+void
+sys·uint64div(Vlong n, Vlong d, Vlong q)
+{
+ _divvu(&q, n, d);
+}
+
+void
+_modvu(Vlong *r, Vlong n, Vlong d)
+{
+
+ if(n.hi == 0 && d.hi == 0) {
+ r->hi = 0;
+ r->lo = n.lo % d.lo;
+ return;
+ }
+ dodiv(n, d, 0, r);
+}
+
+void
+sys·uint64mod(Vlong n, Vlong d, Vlong q)
+{
+ _modvu(&q, n, d);
+}
+
+static void
+vneg(Vlong *v)
+{
+
+ if(v->lo == 0) {
+ v->hi = -v->hi;
+ return;
+ }
+ v->lo = -v->lo;
+ v->hi = ~v->hi;
+}
+
+void
+_divv(Vlong *q, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ if((long)n.lo == -0x80000000 && (long)d.lo == -1) {
+ // special case: 32-bit -0x80000000 / -1 causes divide error,
+ // but it's okay in this 64-bit context.
+ q->lo = 0x80000000;
+ q->hi = 0;
+ return;
+ }
+ q->lo = (long)n.lo / (long)d.lo;
+ q->hi = ((long)q->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, q, 0);
+ if(nneg != dneg)
+ vneg(q);
+}
+
+void
+sys·int64div(Vlong n, Vlong d, Vlong q)
+{
+ _divv(&q, n, d);
+}
+
+void
+_modv(Vlong *r, Vlong n, Vlong d)
+{
+ long nneg, dneg;
+
+ if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
+ if((long)n.lo == -0x80000000 && (long)d.lo == -1) {
+ // special case: 32-bit -0x80000000 % -1 causes divide error,
+ // but it's okay in this 64-bit context.
+ r->lo = 0;
+ r->hi = 0;
+ return;
+ }
+ r->lo = (long)n.lo % (long)d.lo;
+ r->hi = ((long)r->lo) >> 31;
+ return;
+ }
+ nneg = n.hi >> 31;
+ if(nneg)
+ vneg(&n);
+ dneg = d.hi >> 31;
+ if(dneg)
+ vneg(&d);
+ dodiv(n, d, 0, r);
+ if(nneg)
+ vneg(r);
+}
+
+void
+sys·int64mod(Vlong n, Vlong d, Vlong q)
+{
+ _modv(&q, n, d);
+}
+
+void
+_rshav(Vlong *r, Vlong a, int b)
+{
+ long t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = t>>31;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = t>>31;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_rshlv(Vlong *r, Vlong a, int b)
+{
+ ulong t;
+
+ t = a.hi;
+ if(b >= 32) {
+ r->hi = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->lo = 0;
+ return;
+ }
+ r->lo = t >> (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->hi = t;
+ r->lo = a.lo;
+ return;
+ }
+ r->hi = t >> b;
+ r->lo = (t << (32-b)) | (a.lo >> b);
+}
+
+void
+_lshv(Vlong *r, Vlong a, int b)
+{
+ ulong t;
+
+ t = a.lo;
+ if(b >= 32) {
+ r->lo = 0;
+ if(b >= 64) {
+ /* this is illegal re C standard */
+ r->hi = 0;
+ return;
+ }
+ r->hi = t << (b-32);
+ return;
+ }
+ if(b <= 0) {
+ r->lo = t;
+ r->hi = a.hi;
+ return;
+ }
+ r->lo = t << b;
+ r->hi = (t >> (32-b)) | (a.hi << b);
+}
+
+void
+_andv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi & b.hi;
+ r->lo = a.lo & b.lo;
+}
+
+void
+_orv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi | b.hi;
+ r->lo = a.lo | b.lo;
+}
+
+void
+_xorv(Vlong *r, Vlong a, Vlong b)
+{
+ r->hi = a.hi ^ b.hi;
+ r->lo = a.lo ^ b.lo;
+}
+
+void
+_vpp(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+}
+
+void
+_vmm(Vlong *l, Vlong *r)
+{
+
+ l->hi = r->hi;
+ l->lo = r->lo;
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+}
+
+void
+_ppv(Vlong *l, Vlong *r)
+{
+
+ r->lo++;
+ if(r->lo == 0)
+ r->hi++;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_mmv(Vlong *l, Vlong *r)
+{
+
+ if(r->lo == 0)
+ r->hi--;
+ r->lo--;
+ l->hi = r->hi;
+ l->lo = r->lo;
+}
+
+void
+_vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv)
+{
+ Vlong t, u;
+
+ u.lo = 0;
+ u.hi = 0;
+ switch(type) {
+ default:
+ abort();
+ break;
+
+ case 1: /* schar */
+ t.lo = *(schar*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(schar*)lv = u.lo;
+ break;
+
+ case 2: /* uchar */
+ t.lo = *(uchar*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uchar*)lv = u.lo;
+ break;
+
+ case 3: /* short */
+ t.lo = *(short*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(short*)lv = u.lo;
+ break;
+
+ case 4: /* ushort */
+ t.lo = *(ushort*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ushort*)lv = u.lo;
+ break;
+
+ case 9: /* int */
+ t.lo = *(int*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(int*)lv = u.lo;
+ break;
+
+ case 10: /* uint */
+ t.lo = *(uint*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(uint*)lv = u.lo;
+ break;
+
+ case 5: /* long */
+ t.lo = *(long*)lv;
+ t.hi = t.lo >> 31;
+ fn(&u, t, rv);
+ *(long*)lv = u.lo;
+ break;
+
+ case 6: /* ulong */
+ t.lo = *(ulong*)lv;
+ t.hi = 0;
+ fn(&u, t, rv);
+ *(ulong*)lv = u.lo;
+ break;
+
+ case 7: /* vlong */
+ case 8: /* uvlong */
+ fn(&u, *(Vlong*)lv, rv);
+ *(Vlong*)lv = u;
+ break;
+ }
+ *ret = u;
+}
+
+void
+_p2v(Vlong *ret, void *p)
+{
+ long t;
+
+ t = (ulong)p;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sl2v(Vlong *ret, long sl)
+{
+ long t;
+
+ t = sl;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ul2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_si2v(Vlong *ret, int si)
+{
+ long t;
+
+ t = si;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_ui2v(Vlong *ret, uint ui)
+{
+ long t;
+
+ t = ui;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sh2v(Vlong *ret, long sh)
+{
+ long t;
+
+ t = (sh << 16) >> 16;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uh2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xffff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+void
+_sc2v(Vlong *ret, long uc)
+{
+ long t;
+
+ t = (uc << 24) >> 24;
+ ret->lo = t;
+ ret->hi = t >> 31;
+}
+
+void
+_uc2v(Vlong *ret, ulong ul)
+{
+ long t;
+
+ t = ul & 0xff;
+ ret->lo = t;
+ ret->hi = 0;
+}
+
+long
+_v2sc(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xff;
+ return (t << 24) >> 24;
+}
+
+long
+_v2uc(Vlong rv)
+{
+
+ return rv.lo & 0xff;
+}
+
+long
+_v2sh(Vlong rv)
+{
+ long t;
+
+ t = rv.lo & 0xffff;
+ return (t << 16) >> 16;
+}
+
+long
+_v2uh(Vlong rv)
+{
+
+ return rv.lo & 0xffff;
+}
+
+long
+_v2sl(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ul(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2si(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+long
+_v2ui(Vlong rv)
+{
+
+ return rv.lo;
+}
+
+int
+_testv(Vlong rv)
+{
+ return rv.lo || rv.hi;
+}
+
+int
+_eqv(Vlong lv, Vlong rv)
+{
+ return lv.lo == rv.lo && lv.hi == rv.hi;
+}
+
+int
+_nev(Vlong lv, Vlong rv)
+{
+ return lv.lo != rv.lo || lv.hi != rv.hi;
+}
+
+int
+_ltv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi < (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_gtv(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_gev(Vlong lv, Vlong rv)
+{
+ return (long)lv.hi > (long)rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
+
+int
+_lov(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo < rv.lo);
+}
+
+int
+_lsv(Vlong lv, Vlong rv)
+{
+ return lv.hi < rv.hi ||
+ (lv.hi == rv.hi && lv.lo <= rv.lo);
+}
+
+int
+_hiv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo > rv.lo);
+}
+
+int
+_hsv(Vlong lv, Vlong rv)
+{
+ return lv.hi > rv.hi ||
+ (lv.hi == rv.hi && lv.lo >= rv.lo);
+}
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/amd64/asm.s
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/amd64/asm.s Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,207 @@
+// Copyright 2009 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.
+
+
+TEXT _rt0_amd64(SB),7,$-8
+
+ // copy arguments forward on an even stack
+
+ MOVQ 0(SP), AX // argc
+ LEAQ 8(SP), BX // argv
+ SUBQ $(4*8+7), SP // 2args 2auto
+ ANDQ $~7, SP
+ MOVQ AX, 16(SP)
+ MOVQ BX, 24(SP)
+
+ // set the per-goroutine and per-mach registers
+
+ LEAQ m0(SB), R14 // dedicated m. register
+ LEAQ g0(SB), R15 // dedicated g. register
+ MOVQ R15, 0(R14) // m has pointer to its g0
+
+ // create istack out of the given (operating system) stack
+
+ LEAQ (-8192+104)(SP), AX
+ MOVQ AX, 0(R15) // 0(R15) is stack limit (w 104b guard)
+ MOVQ SP, 8(R15) // 8(R15) is base
+
+ CLD // convention is D is always left cleared
+ CALL check(SB)
+
+ MOVL 16(SP), AX // copy argc
+ MOVL AX, 0(SP)
+ MOVQ 24(SP), AX // copy argv
+ MOVQ AX, 8(SP)
+ CALL args(SB)
+ CALL osinit(SB)
+ CALL schedinit(SB)
+
+ // create a new goroutine to start program
+ PUSHQ $mainstart(SB) // entry
+ PUSHQ $16 // arg size
+ CALL sys·newproc(SB)
+ POPQ AX
+ POPQ AX
+
+ // start this M
+ CALL mstart(SB)
+
+ CALL notok(SB) // never returns
+ RET
+
+TEXT mainstart(SB),7,$0
+ CALL main·init(SB)
+ CALL initdone(SB)
+ CALL main·main(SB)
+ PUSHQ $0
+ CALL exit(SB)
+ POPQ AX
+ CALL notok(SB)
+ RET
+
+TEXT breakpoint(SB),7,$0
+ BYTE $0xcc
+ RET
+
+/*
+ * go-routine
+ */
+TEXT gogo(SB), 7, $0
+ MOVQ 8(SP), AX // gobuf
+ MOVQ 0(AX), SP // restore SP
+ MOVQ 8(AX), AX
+ MOVQ AX, 0(SP) // put PC on the stack
+ MOVL $1, AX // return 1
+ RET
+
+TEXT gosave(SB), 7, $0
+ MOVQ 8(SP), AX // gobuf
+ MOVQ SP, 0(AX) // save SP
+ MOVQ 0(SP), BX
+ MOVQ BX, 8(AX) // save PC
+ MOVL $0, AX // return 0
+ RET
+
+/*
+ * support for morestack
+ */
+
+// morestack trampolines
+TEXT sys·morestack00+0(SB),7,$0
+ MOVQ $0, AX
+ MOVQ AX, 8(R14)
+ MOVQ $sys·morestack+0(SB), AX
+ JMP AX
+
+TEXT sys·morestack01+0(SB),7,$0
+ SHLQ $32, AX
+ MOVQ AX, 8(R14)
+ MOVQ $sys·morestack+0(SB), AX
+ JMP AX
+
+TEXT sys·morestack10+0(SB),7,$0
+ MOVLQZX AX, AX
+ MOVQ AX, 8(R14)
+ MOVQ $sys·morestack+0(SB), AX
+ JMP AX
+
+TEXT sys·morestack11+0(SB),7,$0
+ MOVQ AX, 8(R14)
+ MOVQ $sys·morestack+0(SB), AX
+ JMP AX
+
+TEXT sys·morestackx(SB),7,$0
+ POPQ AX
+ SHLQ $35, AX
+ MOVQ AX, 8(R14)
+ MOVQ $sys·morestack(SB), AX
+ JMP AX
+
+// subcases of morestack01
+// with const of 8,16,...48
+TEXT sys·morestack8(SB),7,$0
+ PUSHQ $1
+ MOVQ $sys·morestackx(SB), AX
+ JMP AX
+
+TEXT sys·morestack16(SB),7,$0
+ PUSHQ $2
+ MOVQ $sys·morestackx(SB), AX
+ JMP AX
+
+TEXT sys·morestack24(SB),7,$0
+ PUSHQ $3
+ MOVQ $sys·morestackx(SB), AX
+ JMP AX
+
+TEXT sys·morestack32(SB),7,$0
+ PUSHQ $4
+ MOVQ $sys·morestackx(SB), AX
+ JMP AX
+
+TEXT sys·morestack40(SB),7,$0
+ PUSHQ $5
+ MOVQ $sys·morestackx(SB), AX
+ JMP AX
+
+TEXT sys·morestack48(SB),7,$0
+ PUSHQ $6
+ MOVQ $sys·morestackx(SB), AX
+ JMP AX
+
+// return point when leaving new stack. save AX, jmp to lessstack to switch back
+TEXT retfromnewstack(SB), 7, $0
+ MOVQ AX, 16(R14) // save AX in m->cret
+ MOVQ $lessstack(SB), AX
+ JMP AX
+
+// gogo, returning 2nd arg instead of 1
+TEXT gogoret(SB), 7, $0
+ MOVQ 16(SP), AX // return 2nd arg
+ MOVQ 8(SP), BX // gobuf
+ MOVQ 0(BX), SP // restore SP
+ MOVQ 8(BX), BX
+ MOVQ BX, 0(SP) // put PC on the stack
+ RET
+
+TEXT setspgoto(SB), 7, $0
+ MOVQ 8(SP), AX // SP
+ MOVQ 16(SP), BX // fn to call
+ MOVQ 24(SP), CX // fn to return
+ MOVQ AX, SP
+ PUSHQ CX
+ JMP BX
+ POPQ AX // not reached
+ RET
+
+// bool cas(int32 *val, int32 old, int32 new)
+// Atomically:
+// if(*val == old){
+// *val = new;
+// return 1;
+// } else
+// return 0;
+TEXT cas(SB), 7, $0
+ MOVQ 8(SP), BX
+ MOVL 16(SP), AX
+ MOVL 20(SP), CX
+ LOCK
+ CMPXCHGL CX, 0(BX)
+ JZ 3(PC)
+ MOVL $0, AX
+ RET
+ MOVL $1, AX
+ RET
+
+// void jmpdefer(fn, sp);
+// called from deferreturn.
+// 1. pop the caller
+// 2. sub 5 bytes from the callers return
+// 3. jmp to the argument
+TEXT jmpdefer(SB), 7, $0
+ MOVQ 8(SP), AX // fn
+ MOVQ 16(SP), BX // caller sp
+ LEAQ -8(BX), SP // caller sp after CALL
+ SUBQ $5, (SP) // return to CALL again
+ JMP AX // but first run the deferred function
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/amd64/closure.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/amd64/closure.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,121 @@
+// Copyright 2009 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.
+
+#include "runtime.h"
+
+#pragma textflag 7
+// func closure(siz int32,
+// fn func(arg0, arg1, arg2 *ptr, callerpc uintptr, xxx) yyy,
+// arg0, arg1, arg2 *ptr) (func(xxx) yyy)
+void
+sys·closure(int32 siz, byte *fn, byte *arg0)
+{
+ byte *p, *q, **ret;
+ int32 i, n;
+ int64 pcrel;
+
+ if(siz < 0 || siz%8 != 0)
+ throw("bad closure size");
+
+ ret = (byte**)((byte*)&arg0 + siz);
+
+ if(siz > 100) {
+ // TODO(rsc): implement stack growth preamble?
+ throw("closure too big");
+ }
+
+ // compute size of new fn.
+ // must match code laid out below.
+ n = 7+10+3; // SUBQ MOVQ MOVQ
+ if(siz <= 4*8)
+ n += 2*siz/8; // MOVSQ MOVSQ...
+ else
+ n += 7+3; // MOVQ REP MOVSQ
+ n += 12; // CALL worst case; sometimes only 5
+ n += 7+1; // ADDQ RET
+
+ // store args aligned after code, so gc can find them.
+ n += siz;
+ if(n%8)
+ n += 8 - n%8;
+
+ p = mal(n);
+ *ret = p;
+ q = p + n - siz;
+ mcpy(q, (byte*)&arg0, siz);
+
+ // SUBQ $siz, SP
+ *p++ = 0x48;
+ *p++ = 0x81;
+ *p++ = 0xec;
+ *(uint32*)p = siz;
+ p += 4;
+
+ // MOVQ $q, SI
+ *p++ = 0x48;
+ *p++ = 0xbe;
+ *(byte**)p = q;
+ p += 8;
+
+ // MOVQ SP, DI
+ *p++ = 0x48;
+ *p++ = 0x89;
+ *p++ = 0xe7;
+
+ if(siz <= 4*8) {
+ for(i=0; i<siz; i+=8) {
+ // MOVSQ
+ *p++ = 0x48;
+ *p++ = 0xa5;
+ }
+ } else {
+ // MOVQ $(siz/8), CX [32-bit immediate siz/8]
+ *p++ = 0x48;
+ *p++ = 0xc7;
+ *p++ = 0xc1;
+ *(uint32*)p = siz/8;
+ p += 4;
+
+ // REP; MOVSQ
+ *p++ = 0xf3;
+ *p++ = 0x48;
+ *p++ = 0xa5;
+ }
+
+
+ // call fn
+ pcrel = fn - (p+5);
+ if((int32)pcrel == pcrel) {
+ // can use direct call with pc-relative offset
+ // CALL fn
+ *p++ = 0xe8;
+ *(int32*)p = pcrel;
+ p += 4;
+ } else {
+ // MOVQ $fn, CX [64-bit immediate fn]
+ *p++ = 0x48;
+ *p++ = 0xb9;
+ *(byte**)p = fn;
+ p += 8;
+
+ // CALL *CX
+ *p++ = 0xff;
+ *p++ = 0xd1;
+ }
+
+ // ADDQ $siz, SP
+ *p++ = 0x48;
+ *p++ = 0x81;
+ *p++ = 0xc4;
+ *(uint32*)p = siz;
+ p += 4;
+
+ // RET
+ *p++ = 0xc3;
+
+ if(p > q)
+ throw("bad math in sys.closure");
+}
+
+
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/amd64/traceback.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/amd64/traceback.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,146 @@
+// Copyright 2009 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.
+
+#include "runtime.h"
+
+void
+traceback(byte *pc0, byte *sp, G *g)
+{
+ Stktop *stk;
+ uint64 pc;
+ int32 i, n;
+ Func *f;
+ byte *p;
+
+ pc = (uint64)pc0;
+
+ // If the PC is zero, it's likely a nil function call.
+ // Start in the caller's frame.
+ if(pc == 0) {
+ pc = *(uint64*)sp;
+ sp += 8;
+ }
+
+ stk = (Stktop*)g->stackbase;
+ for(n=0; n<100; n++) {
+ while(pc == (uint64)retfromnewstack) {
+ // pop to earlier stack block
+ sp = stk->oldsp;
+ stk = (Stktop*)stk->oldbase;
+ pc = *(uint64*)(sp+8);
+ sp += 16; // two irrelevant calls on stack: morestack plus its call
+ }
+ f = findfunc(pc);
+ if(f == nil) {
+ // dangerous, but poke around to see if it is a closure
+ p = (byte*)pc;
+ // ADDQ $xxx, SP; RET
+ if(p[0] == 0x48 && p[1] == 0x81 && p[2] == 0xc4 && p[7] == 0xc3) {
+ sp += *(uint32*)(p+3) + 8;
+ pc = *(uint64*)(sp - 8);
+ if(pc <= 0x1000)
+ return;
+ continue;
+ }
+ printf("%p unknown pc\n", pc);
+ return;
+ }
+ if(f->frame < 8) // assembly funcs say 0 but lie
+ sp += 8;
+ else
+ sp += f->frame;
+
+ // print this frame
+ // main+0xf /home/rsc/go/src/runtime/x.go:23
+ // main(0x1, 0x2, 0x3)
+ printf("%S", f->name);
+ if(pc > f->entry)
+ printf("+%X", pc - f->entry);
+ printf(" %S:%d\n", f->src, funcline(f, pc-1)); // -1 to get to CALL instr.
+ printf("\t%S(", f->name);
+ for(i = 0; i < f->args; i++) {
+ if(i != 0)
+ prints(", ");
+ sys·printhex(((uint32*)sp)[i]);
+ if(i >= 4) {
+ prints(", ...");
+ break;
+ }
+ }
+ prints(")\n");
+
+ pc = *(uint64*)(sp-8);
+ if(pc <= 0x1000)
+ return;
+ }
+ prints("...\n");
+}
+
+// func caller(n int) (pc uint64, file string, line int, ok bool)
+void
+runtime·Caller(int32 n, uint64 retpc, String retfile, int32 retline, bool retbool)
+{
+ uint64 pc;
+ byte *sp;
+ byte *p;
+ Stktop *stk;
+ Func *f;
+
+ // our caller's pc, sp.
+ sp = (byte*)&n;
+ pc = *(uint64*)(sp-8);
+ if((f = findfunc(pc)) == nil) {
+ error:
+ retpc = 0;
+ retline = 0;
+ retfile = emptystring;
+ retbool = false;
+ FLUSH(&retpc);
+ FLUSH(&retfile);
+ FLUSH(&retline);
+ FLUSH(&retbool);
+ return;
+ }
+
+ // now unwind n levels
+ stk = (Stktop*)g->stackbase;
+ while(n-- > 0) {
+ while(pc == (uint64)retfromnewstack) {
+ sp = stk->oldsp;
+ stk = (Stktop*)stk->oldbase;
+ pc = *(uint64*)(sp+8);
+ sp += 16;
+ }
+
+ if(f->frame < 8) // assembly functions lie
+ sp += 8;
+ else
+ sp += f->frame;
+
+ loop:
+ pc = *(uint64*)(sp-8);
+ if(pc <= 0x1000 || (f = findfunc(pc)) == nil) {
+ // dangerous, but let's try this.
+ // see if it is a closure.
+ p = (byte*)pc;
+ // ADDQ $xxx, SP; RET
+ if(p[0] == 0x48 && p[1] == 0x81 && p[2] == 0xc4 && p[7] == 0xc3) {
+ sp += *(uint32*)(p+3) + 8;
+ goto loop;
+ }
+ goto error;
+ }
+ }
+
+ retpc = pc;
+ retfile = f->src;
+ retline = funcline(f, pc-1);
+ retbool = true;
+ FLUSH(&retpc);
+ FLUSH(&retfile);
+ FLUSH(&retline);
+ FLUSH(&retbool);
+}
+
+
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/arm/asm.s
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/arm/asm.s Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,83 @@
+// Copyright 2009 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.
+
+TEXT _rt0_arm(SB),7,$0
+ // copy arguments forward on an even stack
+ // MOVW $0(SP), R0
+ // MOVL 0(SP), R1 // argc
+// LEAL 4(SP), R1 // argv
+// SUBL $128, SP // plenty of scratch
+// ANDL $~7, SP
+// MOVL AX, 120(SP) // save argc, argv away
+// MOVL BX, 124(SP)
+
+
+// // write "go386\n"
+// PUSHL $6
+// PUSHL $hello(SB)
+// PUSHL $1
+// CALL sys·write(SB)
+// POPL AX
+// POPL AX
+// POPL AX
+
+
+// CALL ldt0setup(SB)
+
+ // set up %fs to refer to that ldt entry
+// MOVL $(7*8+7), AX
+// MOVW AX, FS
+
+// // store through it, to make sure it works
+// MOVL $0x123, 0(FS)
+// MOVL tls0(SB), AX
+// CMPL AX, $0x123
+// JEQ ok
+// MOVL AX, 0
+// ok:
+
+// // set up m and g "registers"
+// // g is 0(FS), m is 4(FS)
+// LEAL g0(SB), CX
+// MOVL CX, 0(FS)
+// LEAL m0(SB), AX
+// MOVL AX, 4(FS)
+
+// // save m->g0 = g0
+// MOVL CX, 0(AX)
+
+// // create istack out of the OS stack
+// LEAL (-8192+104)(SP), AX // TODO: 104?
+// MOVL AX, 0(CX) // 8(g) is stack limit (w 104b guard)
+// MOVL SP, 4(CX) // 12(g) is base
+// CALL emptyfunc(SB) // fault if stack check is wrong
+
+// // convention is D is always cleared
+// CLD
+
+// CALL check(SB)
+
+// // saved argc, argv
+// MOVL 120(SP), AX
+// MOVL AX, 0(SP)
+// MOVL 124(SP), AX
+// MOVL AX, 4(SP)
+// CALL args(SB)
+// CALL osinit(SB)
+// CALL schedinit(SB)
+
+// // create a new goroutine to start program
+// PUSHL $mainstart(SB) // entry
+// PUSHL $8 // arg size
+// CALL sys·newproc(SB)
+// POPL AX
+// POPL AX
+
+// // start this M
+// CALL mstart(SB)
+
+ BL main�main(SB)
+ MOVW $99, R0
+ SWI $0x00900001
+
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/arm/closure.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/arm/closure.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,4 @@
+// Copyright 2009 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.
+
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/array.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/array.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,175 @@
+// Copyright 2009 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.
+
+#include "runtime.h"
+
+static int32 debug = 0;
+
+// newarray(nel int, cap int, width int) (ary []any);
+void
+sys·newarray(uint32 nel, uint32 cap, uint32 width, Array ret)
+{
+ uint64 size;
+
+ if(cap < nel)
+ cap = nel;
+ size = cap*width;
+
+ ret.nel = nel;
+ ret.cap = cap;
+ ret.array = mal(size);
+
+ FLUSH(&ret);
+
+ if(debug) {
+ prints("newarray: nel=");
+ sys·printint(nel);
+ prints("; cap=");
+ sys·printint(cap);
+ prints("; width=");
+ sys·printint(width);
+ prints("; ret=");
+ sys·printarray(ret);
+ prints("\n");
+ }
+}
+
+static void
+throwslice(uint32 lb, uint32 hb, uint32 n)
+{
+ prints("slice[");
+ sys·printint(lb);
+ prints(":");
+ sys·printint(hb);
+ prints("] of [");
+ sys·printint(n);
+ prints("] array\n");
+ throw("array slice");
+}
+
+// arraysliced(old []any, lb int, hb int, width int) (ary []any);
+void
+sys·arraysliced(Array old, uint32 lb, uint32 hb, uint32 width, Array ret)
+{
+
+ if(hb > old.cap || lb > hb) {
+ if(debug) {
+ prints("sys·arraysliced: old=");
+ sys·printarray(old);
+ prints("; lb=");
+ sys·printint(lb);
+ prints("; hb=");
+ sys·printint(hb);
+ prints("; width=");
+ sys·printint(width);
+ prints("\n");
+
+ prints("oldarray: nel=");
+ sys·printint(old.nel);
+ prints("; cap=");
+ sys·printint(old.cap);
+ prints("\n");
+ }
+ throwslice(lb, hb, old.cap);
+ }
+
+ // new array is inside old array
+ ret.nel = hb-lb;
+ ret.cap = old.cap - lb;
+ ret.array = old.array + lb*width;
+
+ FLUSH(&ret);
+
+ if(debug) {
+ prints("sys·arraysliced: old=");
+ sys·printarray(old);
+ prints("; lb=");
+ sys·printint(lb);
+ prints("; hb=");
+ sys·printint(hb);
+ prints("; width=");
+ sys·printint(width);
+ prints("; ret=");
+ sys·printarray(ret);
+ prints("\n");
+ }
+}
+
+// arrayslices(old *any, nel int, lb int, hb int, width int) (ary []any);
+void
+sys·arrayslices(byte* old, uint32 nel, uint32 lb, uint32 hb, uint32 width, Array ret)
+{
+
+ if(hb > nel || lb > hb) {
+ if(debug) {
+ prints("sys·arrayslices: old=");
+ sys·printpointer(old);
+ prints("; nel=");
+ sys·printint(nel);
+ prints("; lb=");
+ sys·printint(lb);
+ prints("; hb=");
+ sys·printint(hb);
+ prints("; width=");
+ sys·printint(width);
+ prints("\n");
+ }
+ throwslice(lb, hb, nel);
+ }
+
+ // new array is inside old array
+ ret.nel = hb-lb;
+ ret.cap = nel-lb;
+ ret.array = old + lb*width;
+
+ FLUSH(&ret);
+
+ if(debug) {
+ prints("sys·arrayslices: old=");
+ sys·printpointer(old);
+ prints("; nel=");
+ sys·printint(nel);
+ prints("; lb=");
+ sys·printint(lb);
+ prints("; hb=");
+ sys·printint(hb);
+ prints("; width=");
+ sys·printint(width);
+ prints("; ret=");
+ sys·printarray(ret);
+ prints("\n");
+ }
+}
+
+// arrays2d(old *any, nel int) (ary []any)
+void
+sys·arrays2d(byte* old, uint32 nel, Array ret)
+{
+
+ // new dope to old array
+ ret.nel = nel;
+ ret.cap = nel;
+ ret.array = old;
+
+ FLUSH(&ret);
+
+ if(debug) {
+ prints("sys·arrays2d: old=");
+ sys·printpointer(old);
+ prints("; ret=");
+ sys·printarray(ret);
+ prints("\n");
+ }
+}
+
+void
+sys·printarray(Array a)
+{
+ prints("[");
+ sys·printint(a.nel);
+ prints("/");
+ sys·printint(a.cap);
+ prints("]");
+ sys·printpointer(a.array);
+}
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/cgo2c.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/cgo2c.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,602 @@
+// Copyright 2009 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.
+
+/* Translate a .cgo file into a .c file. A .cgo file is a combination
+ of a limited form of Go with C. */
+
+/*
+ package PACKAGENAME
+ {# line}
+ func NAME([NAME TYPE { , NAME TYPE }]) [(NAME TYPE { , NAME TYPE })] \{
+ C code with proper brace nesting
+ \}
+*/
+
+/* We generate C code which implements the function such that it can
+ be called from Go and executes the C code. */
+
+#include <assert.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+/* Whether we're emitting for gcc */
+static int gcc;
+
+/* File and line number */
+static const char *file;
+static unsigned int lineno;
+
+/* List of names and types. */
+struct params {
+ struct params *next;
+ char *name;
+ char *type;
+};
+
+/* Unexpected EOF. */
+static void
+bad_eof(void)
+{
+ fprintf(stderr, "%s:%u: unexpected EOF\n", file, lineno);
+ exit(1);
+}
+
+/* Out of memory. */
+static void
+bad_mem(void)
+{
+ fprintf(stderr, "%s:%u: out of memory\n", file, lineno);
+ exit(1);
+}
+
+/* Allocate memory without fail. */
+static void *
+xmalloc(unsigned int size)
+{
+ void *ret = malloc(size);
+ if (ret == NULL)
+ bad_mem();
+ return ret;
+}
+
+/* Reallocate memory without fail. */
+static void*
+xrealloc(void *buf, unsigned int size)
+{
+ void *ret = realloc(buf, size);
+ if (ret == NULL)
+ bad_mem();
+ return ret;
+}
+
+/* Free a list of parameters. */
+static void
+free_params(struct params *p)
+{
+ while (p != NULL) {
+ struct params *next;
+
+ next = p->next;
+ free(p->name);
+ free(p->type);
+ free(p);
+ p = next;
+ }
+}
+
+/* Read a character, tracking lineno. */
+static int
+getchar_update_lineno(void)
+{
+ int c;
+
+ c = getchar();
+ if (c == '\n')
+ ++lineno;
+ return c;
+}
+
+/* Read a character, giving an error on EOF, tracking lineno. */
+static int
+getchar_no_eof(void)
+{
+ int c;
+
+ c = getchar_update_lineno();
+ if (c == EOF)
+ bad_eof();
+ return c;
+}
+
+/* Read a character, skipping comments. */
+static int
+getchar_skipping_comments(void)
+{
+ int c;
+
+ while (1) {
+ c = getchar_update_lineno();
+ if (c != '/')
+ return c;
+
+ c = getchar();
+ if (c == '/') {
+ do {
+ c = getchar_update_lineno();
+ } while (c != EOF && c != '\n');
+ return c;
+ } else if (c == '*') {
+ while (1) {
+ c = getchar_update_lineno();
+ if (c == EOF)
+ return EOF;
+ if (c == '*') {
+ do {
+ c = getchar_update_lineno();
+ } while (c == '*');
+ if (c == '/')
+ break;
+ }
+ }
+ } else {
+ ungetc(c, stdin);
+ return '/';
+ }
+ }
+}
+
+/* Read and return a token. Tokens are delimited by whitespace or by
+ [(),{}]. The latter are all returned as single characters. */
+static char *
+read_token(void)
+{
+ int c;
+ char *buf;
+ unsigned int alc, off;
+ const char* delims = "(),{}";
+
+ while (1) {
+ c = getchar_skipping_comments();
+ if (c == EOF)
+ return NULL;
+ if (!isspace(c))
+ break;
+ }
+ alc = 16;
+ buf = xmalloc(alc + 1);
+ off = 0;
+ if (strchr(delims, c) != NULL) {
+ buf[off] = c;
+ ++off;
+ } else {
+ while (1) {
+ if (off >= alc) {
+ alc *= 2;
+ buf = xrealloc(buf, alc + 1);
+ }
+ buf[off] = c;
+ ++off;
+ c = getchar_skipping_comments();
+ if (c == EOF)
+ break;
+ if (isspace(c) || strchr(delims, c) != NULL) {
+ ungetc(c, stdin);
+ break;
+ }
+ }
+ }
+ buf[off] = '\0';
+ return buf;
+}
+
+/* Read a token, giving an error on EOF. */
+static char *
+read_token_no_eof(void)
+{
+ char *token = read_token();
+ if (token == NULL)
+ bad_eof();
+ return token;
+}
+
+/* Read the package clause, and return the package name. */
+static char *
+read_package(void)
+{
+ char *token;
+
+ token = read_token_no_eof();
+ if (strcmp(token, "package") != 0) {
+ fprintf(stderr,
+ "%s:%u: expected \"package\", got \"%s\"\n",
+ file, lineno, token);
+ exit(1);
+ }
+ return read_token_no_eof();
+}
+
+/* Read and copy preprocessor lines. */
+static void
+read_preprocessor_lines(void)
+{
+ while (1) {
+ int c;
+
+ do {
+ c = getchar_skipping_comments();
+ } while (isspace(c));
+ if (c != '#') {
+ ungetc(c, stdin);
+ return;
+ }
+ putchar(c);
+ do {
+ c = getchar_update_lineno();
+ putchar(c);
+ } while (c != '\n');
+ }
+}
+
+/* Read a type in Go syntax and return a type in C syntax. We only
+ permit basic types and pointers. */
+static char *
+read_type(void)
+{
+ char *p, *op, *q;
+ int pointer_count;
+ unsigned int len;
+
+ p = read_token_no_eof();
+ if (*p != '*')
+ return p;
+ op = p;
+ pointer_count = 0;
+ while (*p == '*') {
+ ++pointer_count;
+ ++p;
+ }
+ len = strlen(p);
+ q = xmalloc(len + pointer_count + 1);
+ memcpy(q, p, len);
+ while (pointer_count > 0) {
+ q[len] = '*';
+ ++len;
+ --pointer_count;
+ }
+ q[len] = '\0';
+ free(op);
+ return q;
+}
+
+/* Read a list of parameters. Each parameter is a name and a type.
+ The list ends with a ')'. We have already read the '('. */
+static struct params *
+read_params(void)
+{
+ char *token;
+ struct params *ret, **pp;
+
+ ret = NULL;
+ pp = &ret;
+ token = read_token_no_eof();
+ if (strcmp(token, ")") != 0) {
+ while (1) {
+ *pp = xmalloc(sizeof(struct params));
+ (*pp)->name = token;
+ (*pp)->type = read_type();
+ pp = &(*pp)->next;
+ *pp = NULL;
+
+ token = read_token_no_eof();
+ if (strcmp(token, ",") != 0)
+ break;
+ token = read_token_no_eof();
+ }
+ }
+ if (strcmp(token, ")") != 0) {
+ fprintf(stderr, "%s:%u: expected '('\n",
+ file, lineno);
+ exit(1);
+ }
+ return ret;
+}
+
+/* Read a function header. This reads up to and including the initial
+ '{' character. Returns 1 if it read a header, 0 at EOF. */
+static int
+read_func_header(char **name, struct params **params, struct params **rets)
+{
+ char *token;
+
+ token = read_token();
+ if (token == NULL)
+ return 0;
+ if (strcmp(token, "func") != 0) {
+ fprintf(stderr, "%s:%u: expected \"func\"\n",
+ file, lineno);
+ exit(1);
+ }
+ *name = read_token_no_eof();
+
+ token = read_token();
+ if (token == NULL || strcmp(token, "(") != 0) {
+ fprintf(stderr, "%s:%u: expected \"(\"\n",
+ file, lineno);
+ exit(1);
+ }
+ *params = read_params();
+
+ token = read_token();
+ if (token == NULL || strcmp(token, "(") != 0)
+ *rets = NULL;
+ else {
+ *rets = read_params();
+ token = read_token();
+ }
+ if (token == NULL || strcmp(token, "{") != 0) {
+ fprintf(stderr, "%s:%u: expected \"{\"\n",
+ file, lineno);
+ exit(1);
+ }
+ return 1;
+}
+
+/* Write out parameters. */
+static void
+write_params(struct params *params, int *first)
+{
+ struct params *p;
+
+ for (p = params; p != NULL; p = p->next) {
+ if (*first)
+ *first = 0;
+ else
+ printf(", ");
+ printf("%s %s", p->type, p->name);
+ }
+}
+
+/* Write a 6g function header. */
+static void
+write_6g_func_header(char *package, char *name, struct params *params,
+ struct params *rets)
+{
+ int first;
+
+ printf("void\n%s·%s(", package, name);
+ first = 1;
+ write_params(params, &first);
+ write_params(rets, &first);
+ printf(")\n{\n");
+}
+
+/* Write a 6g function trailer. */
+static void
+write_6g_func_trailer(struct params *rets)
+{
+ struct params *p;
+
+ for (p = rets; p != NULL; p = p->next)
+ printf("\tFLUSH(&%s);\n", p->name);
+ printf("}\n");
+}
+
+/* Define the gcc function return type if necessary. */
+static void
+define_gcc_return_type(char *package, char *name, struct params *rets)
+{
+ struct params *p;
+
+ if (rets == NULL || rets->next == NULL)
+ return;
+ printf("struct %s_%s_ret {\n", package, name);
+ for (p = rets; p != NULL; p = p->next)
+ printf(" %s %s;\n", p->type, p->name);
+ printf("};\n");
+}
+
+/* Write out the gcc function return type. */
+static void
+write_gcc_return_type(char *package, char *name, struct params *rets)
+{
+ if (rets == NULL)
+ printf("void");
+ else if (rets->next == NULL)
+ printf("%s", rets->type);
+ else
+ printf("struct %s_%s_ret", package, name);
+}
+
+/* Write out a gcc function header. */
+static void
+write_gcc_func_header(char *package, char *name, struct params *params,
+ struct params *rets)
+{
+ int first;
+ struct params *p;
+
+ define_gcc_return_type(package, name, rets);
+ write_gcc_return_type(package, name, rets);
+ printf(" %s_%s(", package, name);
+ first = 1;
+ write_params(params, &first);
+ printf(") asm (\"%s.%s\");\n", package, name);
+ write_gcc_return_type(package, name, rets);
+ printf(" %s_%s(", package, name);
+ first = 1;
+ write_params(params, &first);
+ printf(")\n{\n");
+ for (p = rets; p != NULL; p = p->next)
+ printf(" %s %s;\n", p->type, p->name);
+}
+
+/* Write out a gcc function trailer. */
+static void
+write_gcc_func_trailer(char *package, char *name, struct params *rets)
+{
+ if (rets == NULL)
+ ;
+ else if (rets->next == NULL)
+ printf("return %s;\n", rets->name);
+ else {
+ struct params *p;
+
+ printf(" {\n struct %s_%s_ret __ret;\n", package, name);
+ for (p = rets; p != NULL; p = p->next)
+ printf(" __ret.%s = %s;\n", p->name, p->name);
+ printf(" return __ret;\n }\n");
+ }
+ printf("}\n");
+}
+
+/* Write out a function header. */
+static void
+write_func_header(char *package, char *name,
+ struct params *params, struct params *rets)
+{
+ if (gcc)
+ write_gcc_func_header(package, name, params, rets);
+ else
+ write_6g_func_header(package, name, params, rets);
+ printf("#line %d \"%s\"\n", lineno, file);
+}
+
+/* Write out a function trailer. */
+static void
+write_func_trailer(char *package, char *name,
+ struct params *rets)
+{
+ if (gcc)
+ write_gcc_func_trailer(package, name, rets);
+ else
+ write_6g_func_trailer(rets);
+}
+
+/* Read and write the body of the function, ending in an unnested }
+ (which is read but not written). */
+static void
+copy_body(void)
+{
+ int nesting = 0;
+ while (1) {
+ int c;
+
+ c = getchar_no_eof();
+ if (c == '}' && nesting == 0)
+ return;
+ putchar(c);
+ switch (c) {
+ default:
+ break;
+ case '{':
+ ++nesting;
+ break;
+ case '}':
+ --nesting;
+ break;
+ case '/':
+ c = getchar_update_lineno();
+ putchar(c);
+ if (c == '/') {
+ do {
+ c = getchar_no_eof();
+ putchar(c);
+ } while (c != '\n');
+ } else if (c == '*') {
+ while (1) {
+ c = getchar_no_eof();
+ putchar(c);
+ if (c == '*') {
+ do {
+ c = getchar_no_eof();
+ putchar(c);
+ } while (c == '*');
+ if (c == '/')
+ break;
+ }
+ }
+ }
+ break;
+ case '"':
+ case '\'':
+ {
+ int delim = c;
+ do {
+ c = getchar_no_eof();
+ putchar(c);
+ if (c == '\\') {
+ c = getchar_no_eof();
+ putchar(c);
+ c = '\0';
+ }
+ } while (c != delim);
+ }
+ break;
+ }
+ }
+}
+
+/* Process the entire file. */
+static void
+process_file(void)
+{
+ char *package, *name;
+ struct params *params, *rets;
+
+ package = read_package();
+ read_preprocessor_lines();
+ while (read_func_header(&name, &params, &rets)) {
+ write_func_header(package, name, params, rets);
+ copy_body();
+ write_func_trailer(package, name, rets);
+ free(name);
+ free_params(params);
+ free_params(rets);
+ }
+ free(package);
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "Usage: cgo2c [--6g | --gc] [file]\n");
+ exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+ while(argc > 1 && argv[1][0] == '-') {
+ if(strcmp(argv[1], "-") == 0)
+ break;
+ if(strcmp(argv[1], "--6g") == 0)
+ gcc = 0;
+ else if(strcmp(argv[1], "--gcc") == 0)
+ gcc = 1;
+ else
+ usage();
+ argc--;
+ argv++;
+ }
+
+ if(argc <= 1 || strcmp(argv[1], "-") == 0) {
+ file = "<stdin>";
+ process_file();
+ return 0;
+ }
+
+ if(argc > 2)
+ usage();
+
+ file = argv[1];
+ if(freopen(file, "r", stdin) == 0) {
+ fprintf(stderr, "open %s: %s\n", file, strerror(errno));
+ exit(1);
+ }
+ process_file();
+ return 0;
+}
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/chan.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/chan.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,1024 @@
+// Copyright 2009 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.
+
+#include "runtime.h"
+
+static int32 debug = 0;
+static Lock chanlock;
+
+enum
+{
+ Wclosed = 0x0001, // writer has closed
+ Rclosed = 0x0002, // reader has seen close
+ Eincr = 0x0004, // increment errors
+ Emax = 0x0800, // error limit before throw
+};
+
+typedef struct Hchan Hchan;
+typedef struct Link Link;
+typedef struct WaitQ WaitQ;
+typedef struct SudoG SudoG;
+typedef struct Select Select;
+typedef struct Scase Scase;
+
+struct SudoG
+{
+ G* g; // g and selgen constitute
+ int32 selgen; // a weak pointer to g
+ int16 offset; // offset of case number
+ int8 isfree; // offset of case number
+ SudoG* link;
+ byte elem[8]; // synch data element (+ more)
+};
+
+struct WaitQ
+{
+ SudoG* first;
+ SudoG* last;
+};
+
+struct Hchan
+{
+ uint16 elemsize;
+ uint16 closed; // Wclosed Rclosed errorcount
+ uint32 dataqsiz; // size of the circular q
+ uint32 qcount; // total data in the q
+ Alg* elemalg; // interface for element type
+ Link* senddataq; // pointer for sender
+ Link* recvdataq; // pointer for receiver
+ WaitQ recvq; // list of recv waiters
+ WaitQ sendq; // list of send waiters
+ SudoG* free; // freelist
+};
+
+struct Link
+{
+ Link* link; // asynch queue circular linked list
+ byte elem[8]; // asynch queue data element (+ more)
+};
+
+struct Scase
+{
+ Hchan* chan; // chan
+ byte* pc; // return pc
+ uint16 send; // 0-recv 1-send 2-default
+ uint16 so; // vararg of selected bool
+ union {
+ byte elem[8]; // element (send)
+ byte* elemp; // pointer to element (recv)
+ } u;
+};
+
+struct Select
+{
+ uint16 tcase; // total count of scase[]
+ uint16 ncase; // currently filled scase[]
+ Select* link; // for freelist
+ Scase* scase[1]; // one per case
+};
+
+static Select* selfree[20];
+
+static SudoG* dequeue(WaitQ*, Hchan*);
+static void enqueue(WaitQ*, SudoG*);
+static SudoG* allocsg(Hchan*);
+static void freesg(Hchan*, SudoG*);
+static uint32 gcd(uint32, uint32);
+static uint32 fastrand1(void);
+static uint32 fastrand2(void);
+
+// newchan(elemsize uint32, elemalg uint32, hint uint32) (hchan *chan any);
+void
+sys·newchan(uint32 elemsize, uint32 elemalg, uint32 hint,
+ Hchan* ret)
+{
+ Hchan *c;
+ int32 i;
+
+ if(elemalg >= nelem(algarray)) {
+ printf("chan(alg=%d)\n", elemalg);
+ throw("sys·newchan: unsupported elem type");
+ }
+
+ c = mal(sizeof(*c));
+
+ c->elemsize = elemsize;
+ c->elemalg = &algarray[elemalg];
+
+ if(hint > 0) {
+ Link *d, *b, *e;
+
+ // make a circular q
+ b = nil;
+ e = nil;
+ for(i=0; i<hint; i++) {
+ d = mal(sizeof(*d) + c->elemsize - sizeof(d->elem));
+ if(e == nil)
+ e = d;
+ d->link = b;
+ b = d;
+ }
+ e->link = b;
+ c->recvdataq = b;
+ c->senddataq = b;
+ c->qcount = 0;
+ c->dataqsiz = hint;
+ }
+
+ ret = c;
+ FLUSH(&ret);
+
+ if(debug) {
+ prints("newchan: chan=");
+ sys·printpointer(c);
+ prints("; elemsize=");
+ sys·printint(elemsize);
+ prints("; elemalg=");
+ sys·printint(elemalg);
+ prints("; dataqsiz=");
+ sys·printint(c->dataqsiz);
+ prints("\n");
+ }
+}
+
+static void
+incerr(Hchan* c)
+{
+ c->closed += Eincr;
+ if(c->closed & Emax) {
+ unlock(&chanlock);
+ throw("too many operations on a closed channel");
+ }
+}
+
+/*
+ * generic single channel send/recv
+ * if the bool pointer is nil,
+ * then the full exchange will
+ * occur. if pres is not nil,
+ * then the protocol will not
+ * sleep but return if it could
+ * not complete
+ */
+void
+sendchan(Hchan *c, byte *ep, bool *pres)
+{
+ SudoG *sg;
+ G* gp;
+
+ if(debug) {
+ prints("chansend: chan=");
+ sys·printpointer(c);
+ prints("; elem=");
+ c->elemalg->print(c->elemsize, ep);
+ prints("\n");
+ }
+
+ lock(&chanlock);
+loop:
+ if(c->closed & Wclosed)
+ goto closed;
+
+ if(c->dataqsiz > 0)
+ goto asynch;
+
+ sg = dequeue(&c->recvq, c);
+ if(sg != nil) {
+ if(ep != nil)
+ c->elemalg->copy(c->elemsize, sg->elem, ep);
+
+ gp = sg->g;
+ gp->param = sg;
+ unlock(&chanlock);
+ ready(gp);
+
+ if(pres != nil)
+ *pres = true;
+ return;
+ }
+
+ if(pres != nil) {
+ unlock(&chanlock);
+ *pres = false;
+ return;
+ }
+
+ sg = allocsg(c);
+ if(ep != nil)
+ c->elemalg->copy(c->elemsize, sg->elem, ep);
+ g->param = nil;
+ g->status = Gwaiting;
+ enqueue(&c->sendq, sg);
+ unlock(&chanlock);
+ gosched();
+
+ lock(&chanlock);
+ sg = g->param;
+ if(sg == nil)
+ goto loop;
+ freesg(c, sg);
+ unlock(&chanlock);
+ if(pres != nil)
+ *pres = true;
+ return;
+
+asynch:
+ if(c->closed & Wclosed)
+ goto closed;
+
+ if(c->qcount >= c->dataqsiz) {
+ if(pres != nil) {
+ unlock(&chanlock);
+ *pres = false;
+ return;
+ }
+ sg = allocsg(c);
+ g->status = Gwaiting;
+ enqueue(&c->sendq, sg);
+ unlock(&chanlock);
+ gosched();
+
+ lock(&chanlock);
+ goto asynch;
+ }
+ if(ep != nil)
+ c->elemalg->copy(c->elemsize, c->senddataq->elem, ep);
+ c->senddataq = c->senddataq->link;
+ c->qcount++;
+
+ sg = dequeue(&c->recvq, c);
+ if(sg != nil) {
+ gp = sg->g;
+ freesg(c, sg);
+ unlock(&chanlock);
+ ready(gp);
+ } else
+ unlock(&chanlock);
+ if(pres != nil)
+ *pres = true;
+ return;
+
+closed:
+ incerr(c);
+ if(pres != nil)
+ *pres = true;
+ unlock(&chanlock);
+}
+
+static void
+chanrecv(Hchan* c, byte *ep, bool* pres)
+{
+ SudoG *sg;
+ G *gp;
+
+ if(debug) {
+ prints("chanrecv: chan=");
+ sys·printpointer(c);
+ prints("\n");
+ }
+
+ lock(&chanlock);
+loop:
+ if(c->dataqsiz > 0)
+ goto asynch;
+
+ if(c->closed & Wclosed)
+ goto closed;
+
+ sg = dequeue(&c->sendq, c);
+ if(sg != nil) {
+ c->elemalg->copy(c->elemsize, ep, sg->elem);
+
+ gp = sg->g;
+ gp->param = sg;
+ unlock(&chanlock);
+ ready(gp);
+
+ if(pres != nil)
+ *pres = true;
+ return;
+ }
+
+ if(pres != nil) {
+ unlock(&chanlock);
+ *pres = false;
+ return;
+ }
+
+ sg = allocsg(c);
+ g->param = nil;
+ g->status = Gwaiting;
+ enqueue(&c->recvq, sg);
+ unlock(&chanlock);
+ gosched();
+
+ lock(&chanlock);
+ sg = g->param;
+ if(sg == nil)
+ goto loop;
+
+ c->elemalg->copy(c->elemsize, ep, sg->elem);
+ freesg(c, sg);
+ unlock(&chanlock);
+ if(pres != nil)
+ *pres = true;
+ return;
+
+asynch:
+ if(c->qcount <= 0) {
+ if(c->closed & Wclosed)
+ goto closed;
+
+ if(pres != nil) {
+ unlock(&chanlock);
+ *pres = false;
+ return;
+ }
+ sg = allocsg(c);
+ g->status = Gwaiting;
+ enqueue(&c->recvq, sg);
+ unlock(&chanlock);
+ gosched();
+
+ lock(&chanlock);
+ goto asynch;
+ }
+ c->elemalg->copy(c->elemsize, ep, c->recvdataq->elem);
+ c->recvdataq = c->recvdataq->link;
+ c->qcount--;
+ sg = dequeue(&c->sendq, c);
+ if(sg != nil) {
+ gp = sg->g;
+ freesg(c, sg);
+ unlock(&chanlock);
+ ready(gp);
+ if(pres != nil)
+ *pres = true;
+ return;
+ }
+
+ unlock(&chanlock);
+ if(pres != nil)
+ *pres = true;
+ return;
+
+closed:
+ c->elemalg->copy(c->elemsize, ep, nil);
+ c->closed |= Rclosed;
+ incerr(c);
+ if(pres != nil)
+ *pres = true;
+ unlock(&chanlock);
+}
+
+// chansend1(hchan *chan any, elem any);
+void
+sys·chansend1(Hchan* c, ...)
+{
+ int32 o;
+ byte *ae;
+
+ o = rnd(sizeof(c), c->elemsize);
+ ae = (byte*)&c + o;
+ sendchan(c, ae, nil);
+}
+
+// chansend2(hchan *chan any, elem any) (pres bool);
+void
+sys·chansend2(Hchan* c, ...)
+{
+ int32 o;
+ byte *ae, *ap;
+
+ o = rnd(sizeof(c), c->elemsize);
+ ae = (byte*)&c + o;
+ o = rnd(o+c->elemsize, 1);
+ ap = (byte*)&c + o;
+
+ sendchan(c, ae, ap);
+}
+
+// chanrecv1(hchan *chan any) (elem any);
+void
+sys·chanrecv1(Hchan* c, ...)
+{
+ int32 o;
+ byte *ae;
+
+ o = rnd(sizeof(c), c->elemsize);
+ ae = (byte*)&c + o;
+
+ chanrecv(c, ae, nil);
+}
+
+// chanrecv2(hchan *chan any) (elem any, pres bool);
+void
+sys·chanrecv2(Hchan* c, ...)
+{
+ int32 o;
+ byte *ae, *ap;
+
+ o = rnd(sizeof(c), c->elemsize);
+ ae = (byte*)&c + o;
+ o = rnd(o+c->elemsize, 1);
+ ap = (byte*)&c + o;
+
+ chanrecv(c, ae, ap);
+}
+
+// chanrecv3(hchan *chan any, elem *any) (pres bool);
+void
+sys·chanrecv3(Hchan* c, byte* ep, byte pres)
+{
+ chanrecv(c, ep, &pres);
+}
+
+// newselect(size uint32) (sel *byte);
+void
+sys·newselect(int32 size, Select *sel)
+{
+ int32 n;
+
+ n = 0;
+ if(size > 1)
+ n = size-1;
+
+ lock(&chanlock);
+ sel = nil;
+ if(size >= 1 && size < nelem(selfree)) {
+ sel = selfree[size];
+ if(sel != nil)
+ selfree[size] = sel->link;
+ }
+ unlock(&chanlock);
+ if(sel == nil)
+ sel = mal(sizeof(*sel) + n*sizeof(sel->scase[0]));
+
+ sel->tcase = size;
+ sel->ncase = 0;
+ FLUSH(&sel);
+ if(debug) {
+ prints("newselect s=");
+ sys·printpointer(sel);
+ prints(" size=");
+ sys·printint(size);
+ prints("\n");
+ }
+}
+
+// selectsend(sel *byte, hchan *chan any, elem any) (selected bool);
+void
+sys·selectsend(Select *sel, Hchan *c, ...)
+{
+ int32 i, eo;
+ Scase *cas;
+ byte *ae;
+
+ // nil cases do not compete
+ if(c == nil)
+ return;
+
+ i = sel->ncase;
+ if(i >= sel->tcase)
+ throw("selectsend: too many cases");
+ sel->ncase = i+1;
+ cas = sel->scase[i];
+ if(cas == nil) {
+ cas = mal(sizeof *cas + c->elemsize - sizeof(cas->u.elem));
+ sel->scase[i] = cas;
+ }
+
+ cas->pc = sys·getcallerpc(&sel);
+ cas->chan = c;
+
+ eo = rnd(sizeof(sel), sizeof(c));
+ eo = rnd(eo+sizeof(c), c->elemsize);
+ cas->so = rnd(eo+c->elemsize, 1);
+ cas->send = 1;
+
+ ae = (byte*)&sel + eo;
+ c->elemalg->copy(c->elemsize, cas->u.elem, ae);
+
+ if(debug) {
+ prints("selectsend s=");
+ sys·printpointer(sel);
+ prints(" pc=");
+ sys·printpointer(cas->pc);
+ prints(" chan=");
+ sys·printpointer(cas->chan);
+ prints(" po=");
+ sys·printint(cas->so);
+ prints(" send=");
+ sys·printint(cas->send);
+ prints("\n");
+ }
+}
+
+// selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
+void
+sys·selectrecv(Select *sel, Hchan *c, ...)
+{
+ int32 i, eo;
+ Scase *cas;
+
+ // nil cases do not compete
+ if(c == nil)
+ return;
+
+ i = sel->ncase;
+ if(i >= sel->tcase)
+ throw("selectrecv: too many cases");
+ sel->ncase = i+1;
+ cas = sel->scase[i];
+ if(cas == nil) {
+ cas = mal(sizeof *cas);
+ sel->scase[i] = cas;
+ }
+ cas->pc = sys·getcallerpc(&sel);
+ cas->chan = c;
+
+ eo = rnd(sizeof(sel), sizeof(c));
+ eo = rnd(eo+sizeof(c), sizeof(byte*));
+ cas->so = rnd(eo+sizeof(byte*), 1);
+ cas->send = 0;
+ cas->u.elemp = *(byte**)((byte*)&sel + eo);
+
+ if(debug) {
+ prints("selectrecv s=");
+ sys·printpointer(sel);
+ prints(" pc=");
+ sys·printpointer(cas->pc);
+ prints(" chan=");
+ sys·printpointer(cas->chan);
+ prints(" so=");
+ sys·printint(cas->so);
+ prints(" send=");
+ sys·printint(cas->send);
+ prints("\n");
+ }
+}
+
+
+// selectdefaul(sel *byte) (selected bool);
+void
+sys·selectdefault(Select *sel, ...)
+{
+ int32 i;
+ Scase *cas;
+
+ i = sel->ncase;
+ if(i >= sel->tcase)
+ throw("selectdefault: too many cases");
+ sel->ncase = i+1;
+ cas = sel->scase[i];
+ if(cas == nil) {
+ cas = mal(sizeof *cas);
+ sel->scase[i] = cas;
+ }
+ cas->pc = sys·getcallerpc(&sel);
+ cas->chan = nil;
+
+ cas->so = rnd(sizeof(sel), 1);
+ cas->send = 2;
+ cas->u.elemp = nil;
+
+ if(debug) {
+ prints("selectdefault s=");
+ sys·printpointer(sel);
+ prints(" pc=");
+ sys·printpointer(cas->pc);
+ prints(" so=");
+ sys·printint(cas->so);
+ prints(" send=");
+ sys·printint(cas->send);
+ prints("\n");
+ }
+}
+
+// selectgo(sel *byte);
+void
+sys·selectgo(Select *sel)
+{
+ uint32 p, o, i;
+ Scase *cas, *dfl;
+ Hchan *c;
+ SudoG *sg;
+ G *gp;
+ byte *as;
+
+ if(debug) {
+ prints("selectgo: sel=");
+ sys·printpointer(sel);
+ prints("\n");
+ }
+
+ if(sel->ncase < 2) {
+ if(sel->ncase < 1)
+ throw("selectgo: no cases");
+ // make special case of one.
+ }
+
+ // select a (relative) prime
+ for(i=0;; i++) {
+ p = fastrand1();
+ if(gcd(p, sel->ncase) == 1)
+ break;
+ if(i > 1000) {
+ throw("selectgo: failed to select prime");
+ }
+ }
+
+ // select an initial offset
+ o = fastrand2();
+
+ p %= sel->ncase;
+ o %= sel->ncase;
+
+ lock(&chanlock);
+
+loop:
+ // pass 1 - look for something already waiting
+ dfl = nil;
+ for(i=0; i<sel->ncase; i++) {
+ cas = sel->scase[o];
+
+ if(cas->send == 2) { // default
+ dfl = cas;
+ goto next1;
+ }
+
+ c = cas->chan;
+ if(c->dataqsiz > 0) {
+ if(cas->send) {
+ if(c->closed & Wclosed)
+ goto sclose;
+ if(c->qcount < c->dataqsiz)
+ goto asyns;
+ goto next1;
+ }
+ if(c->qcount > 0)
+ goto asynr;
+ if(c->closed & Wclosed)
+ goto rclose;
+ goto next1;
+ }
+
+ if(cas->send) {
+ if(c->closed & Wclosed)
+ goto sclose;
+ sg = dequeue(&c->recvq, c);
+ if(sg != nil)
+ goto gots;
+ goto next1;
+ }
+ sg = dequeue(&c->sendq, c);
+ if(sg != nil)
+ goto gotr;
+ if(c->closed & Wclosed)
+ goto rclose;
+
+ next1:
+ o += p;
+ if(o >= sel->ncase)
+ o -= sel->ncase;
+ }
+
+ if(dfl != nil) {
+ cas = dfl;
+ goto retc;
+ }
+
+
+ // pass 2 - enqueue on all chans
+ for(i=0; i<sel->ncase; i++) {
+ cas = sel->scase[o];
+ c = cas->chan;
+
+ if(c->dataqsiz > 0) {
+ if(cas->send) {
+ if(c->qcount < c->dataqsiz) {
+ prints("selectgo: pass 2 async send\n");
+ goto asyns;
+ }
+ sg = allocsg(c);
+ sg->offset = o;
+ enqueue(&c->sendq, sg);
+ goto next2;
+ }
+ if(c->qcount > 0) {
+ prints("selectgo: pass 2 async recv\n");
+ goto asynr;
+ }
+ sg = allocsg(c);
+ sg->offset = o;
+ enqueue(&c->recvq, sg);
+ goto next2;
+ }
+
+ if(cas->send) {
+ sg = dequeue(&c->recvq, c);
+ if(sg != nil) {
+ prints("selectgo: pass 2 sync send\n");
+ g->selgen++;
+ goto gots;
+ }
+ sg = allocsg(c);
+ sg->offset = o;
+ c->elemalg->copy(c->elemsize, sg->elem, cas->u.elem);
+ enqueue(&c->sendq, sg);
+ goto next2;
+ }
+ sg = dequeue(&c->sendq, c);
+ if(sg != nil) {
+ prints("selectgo: pass 2 sync recv\n");
+ g->selgen++;
+ goto gotr;
+ }
+ sg = allocsg(c);
+ sg->offset = o;
+ enqueue(&c->recvq, sg);
+
+ next2:
+ o += p;
+ if(o >= sel->ncase)
+ o -= sel->ncase;
+ }
+
+ g->param = nil;
+ g->status = Gwaiting;
+ unlock(&chanlock);
+ gosched();
+
+ lock(&chanlock);
+ sg = g->param;
+ if(sg == nil)
+ goto loop;
+
+ o = sg->offset;
+ cas = sel->scase[o];
+ c = cas->chan;
+
+ if(c->dataqsiz > 0) {
+// prints("shouldnt happen\n");
+ goto loop;
+ }
+
+ if(debug) {
+ prints("wait-return: sel=");
+ sys·printpointer(sel);
+ prints(" c=");
+ sys·printpointer(c);
+ prints(" cas=");
+ sys·printpointer(cas);
+ prints(" send=");
+ sys·printint(cas->send);
+ prints(" o=");
+ sys·printint(o);
+ prints("\n");
+ }
+
+ if(!cas->send) {
+ if(cas->u.elemp != nil)
+ c->elemalg->copy(c->elemsize, cas->u.elemp, sg->elem);
+ }
+
+ freesg(c, sg);
+ goto retc;
+
+asynr:
+ if(cas->u.elemp != nil)
+ c->elemalg->copy(c->elemsize, cas->u.elemp, c->recvdataq->elem);
+ c->recvdataq = c->recvdataq->link;
+ c->qcount--;
+ sg = dequeue(&c->sendq, c);
+ if(sg != nil) {
+ gp = sg->g;
+ freesg(c, sg);
+ ready(gp);
+ }
+ goto retc;
+
+asyns:
+ if(cas->u.elem != nil)
+ c->elemalg->copy(c->elemsize, c->senddataq->elem, cas->u.elem);
+ c->senddataq = c->senddataq->link;
+ c->qcount++;
+ sg = dequeue(&c->recvq, c);
+ if(sg != nil) {
+ gp = sg->g;
+ freesg(c, sg);
+ ready(gp);
+ }
+ goto retc;
+
+gotr:
+ // recv path to wakeup the sender (sg)
+ if(debug) {
+ prints("gotr: sel=");
+ sys·printpointer(sel);
+ prints(" c=");
+ sys·printpointer(c);
+ prints(" o=");
+ sys·printint(o);
+ prints("\n");
+ }
+ if(cas->u.elemp != nil)
+ c->elemalg->copy(c->elemsize, cas->u.elemp, sg->elem);
+ gp = sg->g;
+ gp->param = sg;
+ ready(gp);
+ goto retc;
+
+rclose:
+ if(cas->u.elemp != nil)
+ c->elemalg->copy(c->elemsize, cas->u.elemp, nil);
+ c->closed |= Rclosed;
+ incerr(c);
+ goto retc;
+
+gots:
+ // send path to wakeup the receiver (sg)
+ if(debug) {
+ prints("gots: sel=");
+ sys·printpointer(sel);
+ prints(" c=");
+ sys·printpointer(c);
+ prints(" o=");
+ sys·printint(o);
+ prints("\n");
+ }
+ if(c->closed & Wclosed)
+ goto sclose;
+ c->elemalg->copy(c->elemsize, sg->elem, cas->u.elem);
+ gp = sg->g;
+ gp->param = sg;
+ ready(gp);
+ goto retc;
+
+sclose:
+ incerr(c);
+ goto retc;
+
+retc:
+ if(sel->ncase >= 1 && sel->ncase < nelem(selfree)) {
+ sel->link = selfree[sel->ncase];
+ selfree[sel->ncase] = sel;
+ }
+ unlock(&chanlock);
+
+ sys·setcallerpc(&sel, cas->pc);
+ as = (byte*)&sel + cas->so;
+ *as = true;
+}
+
+// closechan(sel *byte);
+void
+sys·closechan(Hchan *c)
+{
+ SudoG *sg;
+ G* gp;
+
+ lock(&chanlock);
+ incerr(c);
+ c->closed |= Wclosed;
+
+ // release all readers
+ for(;;) {
+ sg = dequeue(&c->recvq, c);
+ if(sg == nil)
+ break;
+ gp = sg->g;
+ gp->param = nil;
+ freesg(c, sg);
+ ready(gp);
+ }
+
+ // release all writers
+ for(;;) {
+ sg = dequeue(&c->sendq, c);
+ if(sg == nil)
+ break;
+ gp = sg->g;
+ gp->param = nil;
+ freesg(c, sg);
+ ready(gp);
+ }
+
+ unlock(&chanlock);
+}
+
+// closedchan(sel *byte) bool;
+void
+sys·closedchan(Hchan *c, bool closed)
+{
+ // test Rclosed
+ closed = 0;
+ if(c->closed & Rclosed)
+ closed = 1;
+ FLUSH(&closed);
+}
+
+static SudoG*
+dequeue(WaitQ *q, Hchan *c)
+{
+ SudoG *sgp;
+
+loop:
+ sgp = q->first;
+ if(sgp == nil)
+ return nil;
+ q->first = sgp->link;
+
+ // if sgp is stale, ignore it
+ if(sgp->selgen != sgp->g->selgen) {
+ //prints("INVALID PSEUDOG POINTER\n");
+ freesg(c, sgp);
+ goto loop;
+ }
+
+ // invalidate any others
+ sgp->g->selgen++;
+ return sgp;
+}
+
+static void
+enqueue(WaitQ *q, SudoG *sgp)
+{
+ sgp->link = nil;
+ if(q->first == nil) {
+ q->first = sgp;
+ q->last = sgp;
+ return;
+ }
+ q->last->link = sgp;
+ q->last = sgp;
+}
+
+static SudoG*
+allocsg(Hchan *c)
+{
+ SudoG* sg;
+
+ sg = c->free;
+ if(sg != nil) {
+ c->free = sg->link;
+ } else
+ sg = mal(sizeof(*sg) + c->elemsize - sizeof(sg->elem));
+ sg->selgen = g->selgen;
+ sg->g = g;
+ sg->offset = 0;
+ sg->isfree = 0;
+
+ return sg;
+}
+
+static void
+freesg(Hchan *c, SudoG *sg)
+{
+ if(sg != nil) {
+ if(sg->isfree)
+ throw("chan.freesg: already free");
+ sg->isfree = 1;
+ sg->link = c->free;
+ c->free = sg;
+ }
+}
+
+static uint32
+gcd(uint32 u, uint32 v)
+{
+ for(;;) {
+ if(u > v) {
+ if(v == 0)
+ return u;
+ u = u%v;
+ continue;
+ }
+ if(u == 0)
+ return v;
+ v = v%u;
+ }
+}
+
+static uint32
+fastrand1(void)
+{
+ static uint32 x = 0x49f6428aUL;
+
+ x += x;
+ if(x & 0x80000000L)
+ x ^= 0x88888eefUL;
+ return x;
+}
+
+static uint32
+fastrand2(void)
+{
+ static uint32 x = 0x49f6428aUL;
+
+ x += x;
+ if(x & 0x80000000L)
+ x ^= 0xfafd871bUL;
+ return x;
+}
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/darwin/386/defs.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/darwin/386/defs.h Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,229 @@
+// godefs -f -m32 defs.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+// Constants
+enum {
+ PROT_NONE = 0,
+ PROT_READ = 0x1,
+ PROT_WRITE = 0x2,
+ PROT_EXEC = 0x4,
+ MAP_ANON = 0x1000,
+ MAP_PRIVATE = 0x2,
+ MACH_MSG_TYPE_MOVE_RECEIVE = 0x10,
+ MACH_MSG_TYPE_MOVE_SEND = 0x11,
+ MACH_MSG_TYPE_MOVE_SEND_ONCE = 0x12,
+ MACH_MSG_TYPE_COPY_SEND = 0x13,
+ MACH_MSG_TYPE_MAKE_SEND = 0x14,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE = 0x15,
+ MACH_MSG_TYPE_COPY_RECEIVE = 0x16,
+ MACH_MSG_PORT_DESCRIPTOR = 0,
+ MACH_MSG_OOL_DESCRIPTOR = 0x1,
+ MACH_MSG_OOL_PORTS_DESCRIPTOR = 0x2,
+ MACH_MSG_OOL_VOLATILE_DESCRIPTOR = 0x3,
+ MACH_MSGH_BITS_COMPLEX = 0x80000000,
+ MACH_SEND_MSG = 0x1,
+ MACH_RCV_MSG = 0x2,
+ MACH_RCV_LARGE = 0x4,
+ MACH_SEND_TIMEOUT = 0x10,
+ MACH_SEND_INTERRUPT = 0x40,
+ MACH_SEND_CANCEL = 0x80,
+ MACH_SEND_ALWAYS = 0x10000,
+ MACH_SEND_TRAILER = 0x20000,
+ MACH_RCV_TIMEOUT = 0x100,
+ MACH_RCV_NOTIFY = 0x200,
+ MACH_RCV_INTERRUPT = 0x400,
+ MACH_RCV_OVERWRITE = 0x1000,
+ NDR_PROTOCOL_2_0 = 0,
+ NDR_INT_BIG_ENDIAN = 0,
+ NDR_INT_LITTLE_ENDIAN = 0x1,
+ NDR_FLOAT_IEEE = 0,
+ NDR_CHAR_ASCII = 0,
+ SA_SIGINFO = 0x40,
+ SA_RESTART = 0x2,
+ SA_ONSTACK = 0x1,
+ SA_USERTRAMP = 0x100,
+ SA_64REGSET = 0x200,
+};
+
+// Types
+#pragma pack on
+
+typedef struct MachBody MachBody;
+struct MachBody {
+ uint32 msgh_descriptor_count;
+};
+
+typedef struct MachHeader MachHeader;
+struct MachHeader {
+ uint32 msgh_bits;
+ uint32 msgh_size;
+ uint32 msgh_remote_port;
+ uint32 msgh_local_port;
+ uint32 msgh_reserved;
+ int32 msgh_id;
+};
+
+typedef struct MachNDR MachNDR;
+struct MachNDR {
+ uint8 mig_vers;
+ uint8 if_vers;
+ uint8 reserved1;
+ uint8 mig_encoding;
+ uint8 int_rep;
+ uint8 char_rep;
+ uint8 float_rep;
+ uint8 reserved2;
+};
+
+typedef struct MachPort MachPort;
+struct MachPort {
+ uint32 name;
+ uint32 pad1;
+ uint16 pad2;
+ uint8 disposition;
+ uint8 type;
+};
+
+typedef struct StackT StackT;
+struct StackT {
+ void *ss_sp;
+ uint32 ss_size;
+ int32 ss_flags;
+};
+
+typedef union Sighandler Sighandler;
+union Sighandler {
+ void *__sa_handler;
+ void *__sa_sigaction;
+};
+
+typedef struct Sigaction Sigaction;
+struct Sigaction {
+ Sighandler __sigaction_u;
+ void *sa_tramp;
+ uint32 sa_mask;
+ int32 sa_flags;
+};
+
+typedef union Sigval Sigval;
+union Sigval {
+ int32 sival_int;
+ void *sival_ptr;
+};
+
+typedef struct Siginfo Siginfo;
+struct Siginfo {
+ int32 si_signo;
+ int32 si_errno;
+ int32 si_code;
+ int32 si_pid;
+ uint32 si_uid;
+ int32 si_status;
+ void *si_addr;
+ Sigval si_value;
+ int32 si_band;
+ uint32 __pad[7];
+};
+
+typedef struct FPControl FPControl;
+struct FPControl {
+ byte pad0[2];
+};
+
+typedef struct FPStatus FPStatus;
+struct FPStatus {
+ byte pad0[2];
+};
+
+typedef struct RegMMST RegMMST;
+struct RegMMST {
+ int8 mmst_reg[10];
+ int8 mmst_rsrv[6];
+};
+
+typedef struct RegXMM RegXMM;
+struct RegXMM {
+ int8 xmm_reg[16];
+};
+
+typedef struct Regs Regs;
+struct Regs {
+ uint32 eax;
+ uint32 ebx;
+ uint32 ecx;
+ uint32 edx;
+ uint32 edi;
+ uint32 esi;
+ uint32 ebp;
+ uint32 esp;
+ uint32 ss;
+ uint32 eflags;
+ uint32 eip;
+ uint32 cs;
+ uint32 ds;
+ uint32 es;
+ uint32 fs;
+ uint32 gs;
+};
+
+typedef struct FloatState FloatState;
+struct FloatState {
+ int32 fpu_reserved[2];
+ FPControl fpu_fcw;
+ FPStatus fpu_fsw;
+ uint8 fpu_ftw;
+ uint8 fpu_rsrv1;
+ uint16 fpu_fop;
+ uint32 fpu_ip;
+ uint16 fpu_cs;
+ uint16 fpu_rsrv2;
+ uint32 fpu_dp;
+ uint16 fpu_ds;
+ uint16 fpu_rsrv3;
+ uint32 fpu_mxcsr;
+ uint32 fpu_mxcsrmask;
+ RegMMST fpu_stmm0;
+ RegMMST fpu_stmm1;
+ RegMMST fpu_stmm2;
+ RegMMST fpu_stmm3;
+ RegMMST fpu_stmm4;
+ RegMMST fpu_stmm5;
+ RegMMST fpu_stmm6;
+ RegMMST fpu_stmm7;
+ RegXMM fpu_xmm0;
+ RegXMM fpu_xmm1;
+ RegXMM fpu_xmm2;
+ RegXMM fpu_xmm3;
+ RegXMM fpu_xmm4;
+ RegXMM fpu_xmm5;
+ RegXMM fpu_xmm6;
+ RegXMM fpu_xmm7;
+ int8 fpu_rsrv4[224];
+ int32 fpu_reserved1;
+};
+
+typedef struct ExceptionState ExceptionState;
+struct ExceptionState {
+ uint32 trapno;
+ uint32 err;
+ uint32 faultvaddr;
+};
+
+typedef struct Mcontext Mcontext;
+struct Mcontext {
+ ExceptionState es;
+ Regs ss;
+ FloatState fs;
+};
+
+typedef struct Ucontext Ucontext;
+struct Ucontext {
+ int32 uc_onstack;
+ uint32 uc_sigmask;
+ StackT uc_stack;
+ Ucontext *uc_link;
+ uint32 uc_mcsize;
+ Mcontext *uc_mcontext;
+};
+#pragma pack off
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/darwin/386/rt0.s
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/darwin/386/rt0.s Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,8 @@
+// Copyright 2009 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.
+
+// Darwin and Linux use the same linkage to main
+
+TEXT _rt0_386_darwin(SB),7,$0
+ JMP _rt0_386(SB)
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/darwin/386/signal.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/darwin/386/signal.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,103 @@
+// Copyright 2009 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.
+
+#include "runtime.h"
+#include "defs.h"
+#include "os.h"
+#include "signals.h"
+
+void
+dumpregs(Regs *r)
+{
+ printf("eax %x\n", r->eax);
+ printf("ebx %x\n", r->ebx);
+ printf("ecx %x\n", r->ecx);
+ printf("edx %x\n", r->edx);
+ printf("edi %x\n", r->edi);
+ printf("esi %x\n", r->esi);
+ printf("ebp %x\n", r->ebp);
+ printf("esp %x\n", r->esp);
+ printf("eip %x\n", r->eip);
+ printf("eflags %x\n", r->eflags);
+ printf("cs %x\n", r->cs);
+ printf("fs %x\n", r->fs);
+ printf("gs %x\n", r->gs);
+}
+
+void
+sighandler(int32 sig, Siginfo *info, void *context)
+{
+ Ucontext *uc;
+ Mcontext *mc;
+ Regs *r;
+
+ if(panicking) // traceback already printed
+ exit(2);
+ panicking = 1;
+
+ if(sig < 0 || sig >= NSIG){
+ printf("Signal %d\n", sig);
+ }else{
+ printf("%s\n", sigtab[sig].name);
+ }
+
+ uc = context;
+ mc = uc->uc_mcontext;
+ r = &mc->ss;
+
+ printf("Faulting address: %p\n", info->si_addr);
+ printf("pc: %x\n", r->eip);
+ printf("\n");
+
+ if(gotraceback()){
+ traceback((void*)r->eip, (void*)r->esp, m->curg);
+ tracebackothers(m->curg);
+ dumpregs(r);
+ }
+
+ breakpoint();
+ exit(2);
+}
+
+void
+sigignore(int32, Siginfo*, void*)
+{
+}
+
+void
+signalstack(byte *p, int32 n)
+{
+ StackT st;
+
+ st.ss_sp = p;
+ st.ss_size = n;
+ st.ss_flags = 0;
+ sigaltstack(&st, nil);
+}
+
+void
+initsig(void)
+{
+ int32 i;
+ static Sigaction sa;
+
+ sa.sa_flags |= SA_SIGINFO|SA_ONSTACK;
+ sa.sa_mask = 0; // 0xFFFFFFFFU;
+ sa.sa_tramp = sigtramp; // sigtramp's job is to call into real handler
+ for(i = 0; i<NSIG; i++) {
+ if(sigtab[i].flags) {
+ if(sigtab[i].flags & SigCatch) {
+ sa.__sigaction_u.__sa_sigaction = sighandler;
+ } else {
+ sa.__sigaction_u.__sa_sigaction = sigignore;
+ }
+ if(sigtab[i].flags & SigRestart)
+ sa.sa_flags |= SA_RESTART;
+ else
+ sa.sa_flags &= ~SA_RESTART;
+ sigaction(i, &sa, nil);
+ }
+ }
+}
+
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/darwin/386/sys.s
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/darwin/386/sys.s Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,278 @@
+// Copyright 2009 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.
+
+// System calls and other sys.stuff for 386, Darwin
+// See http://fxr.watson.org/fxr/source/bsd/kern/syscalls.c?v=xnu-1228
+// or /usr/include/sys/syscall.h (on a Mac) for system call numbers.
+
+TEXT notok(SB),7,$0
+ MOVL $0xf1, 0xf1
+ RET
+
+// Exit the entire program (like C exit)
+TEXT exit(SB),7,$0
+ MOVL $1, AX
+ INT $0x80
+ CALL notok(SB)
+ RET
+
+// Exit this OS thread (like pthread_exit, which eventually
+// calls __bsdthread_terminate).
+TEXT exit1(SB),7,$0
+ MOVL $361, AX
+ INT $0x80
+ JAE 2(PC)
+ CALL notok(SB)
+ RET
+
+TEXT sys·write(SB),7,$0
+ MOVL $4, AX
+ INT $0x80
+ JAE 2(PC)
+ CALL notok(SB)
+ RET
+
+TEXT sys·mmap(SB),7,$0
+ MOVL $197, AX
+ INT $0x80
+ JAE 2(PC)
+ CALL notok(SB)
+ RET
+
+TEXT sigaction(SB),7,$0
+ MOVL $46, AX
+ INT $0x80
+ JAE 2(PC)
+ CALL notok(SB)
+ RET
+
+// Sigtramp's job is to call the actual signal handler.
+// It is called with the following arguments on the stack:
+// 0(FP) "return address" - ignored
+// 4(FP) actual handler
+// 8(FP) siginfo style - ignored
+// 12(FP) signal number
+// 16(FP) siginfo
+// 20(FP) context
+TEXT sigtramp(SB),7,$40
+ MOVL 4(FS), BP // m
+ MOVL 28(BP), BP // m->gsignal
+ MOVL BP, 0(FS) // g = m->gsignal
+
+ MOVL handler+4(FP), DI
+ MOVL signo+12(FP), AX
+ MOVL siginfo+16(FP), BX
+ MOVL context+20(FP), CX
+
+ MOVL AX, 0(SP)
+ MOVL BX, 4(SP)
+ MOVL CX, 8(SP)
+ CALL DI
+
+ MOVL context+20(FP), CX
+ MOVL style+8(FP), BX
+
+ MOVL $0, 0(SP) // "caller PC" - ignored
+ MOVL CX, 4(SP)
+ MOVL BX, 8(SP)
+ MOVL $184, AX // sigreturn(ucontext, infostyle)
+ INT $0x80
+ CALL notok(SB)
+ RET
+
+TEXT sigaltstack(SB),7,$0
+ MOVL $53, AX
+ INT $0x80
+ JAE 2(PC)
+ CALL notok(SB)
+ RET
+
+// void bsdthread_create(void *stk, M *m, G *g, void (*fn)(void))
+// System call args are: func arg stack pthread flags.
+TEXT bsdthread_create(SB),7,$32
+ MOVL $360, AX
+ // 0(SP) is where the caller PC would be; kernel skips it
+ MOVL func+12(FP), BX
+ MOVL BX, 4(SP) // func
+ MOVL m+4(FP), BX
+ MOVL BX, 8(SP) // arg
+ MOVL stk+0(FP), BX
+ MOVL BX, 12(SP) // stack
+ MOVL g+8(FP), BX
+ MOVL BX, 16(SP) // pthread
+ MOVL $0x1000000, 20(SP) // flags = PTHREAD_START_CUSTOM
+ INT $0x80
+ JAE 2(PC)
+ CALL notok(SB)
+ RET
+
+// The thread that bsdthread_create creates starts executing here,
+// because we registered this function using bsdthread_register
+// at startup.
+// AX = "pthread" (= g)
+// BX = mach thread port
+// CX = "func" (= fn)
+// DX = "arg" (= m)
+// DI = stack top
+// SI = flags (= 0x1000000)
+// SP = stack - C_32_STK_ALIGN
+TEXT bsdthread_start(SB),7,$0
+ // set up ldt 7+id to point at m->tls.
+ // m->tls is at m+40. newosproc left
+ // the m->id in tls[0].
+ LEAL 40(DX), BP
+ MOVL 0(BP), DI
+ ADDL $7, DI // m0 is LDT#7. count up.
+ // setldt(tls#, &tls, sizeof tls)
+ PUSHAL // save registers
+ PUSHL $32 // sizeof tls
+ PUSHL BP // &tls
+ PUSHL DI // tls #
+ CALL setldt(SB)
+ POPL AX
+ POPL AX
+ POPL AX
+ POPAL
+ SHLL $3, DI // segment# is ldt*8 + 7.
+ ADDL $7, DI
+ MOVW DI, FS
+
+ // Now segment is established. Initialize m, g.
+ MOVL AX, 0(FS) // g
+ MOVL DX, 4(FS) // m
+ MOVL BX, 20(DX) // m->procid = thread port (for debuggers)
+ CALL CX // fn()
+ CALL exit1(SB)
+ RET
+
+// void bsdthread_register(void)
+// registers callbacks for threadstart (see bsdthread_create above
+// and wqthread and pthsize (not used). returns 0 on success.
+TEXT bsdthread_register(SB),7,$40
+ MOVL $366, AX
+ // 0(SP) is where kernel expects caller PC; ignored
+ MOVL $bsdthread_start(SB), 4(SP) // threadstart
+ MOVL $0, 8(SP) // wqthread, not used by us
+ MOVL $0, 12(SP) // pthsize, not used by us
+ MOVL $0, 16(SP) // paranoia
+ MOVL $0, 20(SP)
+ MOVL $0, 24(SP)
+ INT $0x80
+ JAE 2(PC)
+ CALL notok(SB)
+ RET
+
+// Invoke Mach system call.
+// Assumes system call number in AX,
+// caller PC on stack, caller's caller PC next,
+// and then the system call arguments.
+//
+// Can be used for BSD too, but we don't,
+// because if you use this interface the BSD
+// system call numbers need an extra field
+// in the high 16 bits that seems to be the
+// argument count in bytes but is not always.
+// INT $0x80 works fine for those.
+TEXT sysenter(SB),7,$0
+ POPL DX
+ MOVL SP, CX
+ BYTE $0x0F; BYTE $0x34; // SYSENTER
+ // returns to DX with SP set to CX
+
+TEXT mach_msg_trap(SB),7,$0
+ MOVL $-31, AX
+ CALL sysenter(SB)
+ RET
+
+TEXT mach_reply_port(SB),7,$0
+ MOVL $-26, AX
+ CALL sysenter(SB)
+ RET
+
+TEXT mach_task_self(SB),7,$0
+ MOVL $-28, AX
+ CALL sysenter(SB)
+ RET
+
+// Mach provides trap versions of the semaphore ops,
+// instead of requiring the use of RPC.
+
+// uint32 mach_semaphore_wait(uint32)
+TEXT mach_semaphore_wait(SB),7,$0
+ MOVL $-36, AX
+ CALL sysenter(SB)
+ RET
+
+// uint32 mach_semaphore_timedwait(uint32, uint32, uint32)
+TEXT mach_semaphore_timedwait(SB),7,$0
+ MOVL $-38, AX
+ CALL sysenter(SB)
+ RET
+
+// uint32 mach_semaphore_signal(uint32)
+TEXT mach_semaphore_signal(SB),7,$0
+ MOVL $-33, AX
+ CALL sysenter(SB)
+ RET
+
+// uint32 mach_semaphore_signal_all(uint32)
+TEXT mach_semaphore_signal_all(SB),7,$0
+ MOVL $-34, AX
+ CALL sysenter(SB)
+ RET
+
+/*
+descriptor entry format for system call
+is the native machine format, ugly as it is:
+
+ 2-byte limit
+ 3-byte base
+ 1-byte: 0x80=present, 0x60=dpl<<5, 0x1F=type
+ 1-byte: 0x80=limit is *4k, 0x40=32-bit operand size,
+ 0x0F=4 more bits of limit
+ 1 byte: 8 more bits of base
+
+int i386_get_ldt(int, union ldt_entry *, int);
+int i386_set_ldt(int, const union ldt_entry *, int);
+
+*/
+
+// setldt(int entry, int address, int limit)
+TEXT setldt(SB),7,$32
+ // set up data_desc
+ LEAL 16(SP), AX // struct data_desc
+ MOVL $0, 0(AX)
+ MOVL $0, 4(AX)
+
+ MOVL address+4(FP), BX // aka base
+ MOVW BX, 2(AX)
+ SHRL $16, BX
+ MOVB BX, 4(AX)
+ SHRL $8, BX
+ MOVB BX, 7(AX)
+
+ MOVL limit+8(FP), BX
+ MOVW BX, 0(AX)
+ SHRL $16, BX
+ ANDL $0x0F, BX
+ ORL $0x40, BX // 32-bit operand size
+ MOVB BX, 6(AX)
+
+ MOVL $0xF2, 5(AX) // r/w data descriptor, dpl=3, present
+
+ // call i386_set_ldt(entry, desc, 1)
+ MOVL entry+0(FP), BX
+ MOVL BX, 0(SP)
+ MOVL AX, 4(SP)
+ MOVL $1, 8(SP)
+ CALL i386_set_ldt(SB)
+ RET
+
+TEXT i386_set_ldt(SB),7,$0
+ MOVL $5, AX
+ INT $0x82 // sic
+ JAE 2(PC)
+ CALL notok(SB)
+ RET
+
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/darwin/amd64/defs.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/darwin/amd64/defs.h Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,244 @@
+// godefs -f -m64 defs.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+// Constants
+enum {
+ PROT_NONE = 0,
+ PROT_READ = 0x1,
+ PROT_WRITE = 0x2,
+ PROT_EXEC = 0x4,
+ MAP_ANON = 0x1000,
+ MAP_PRIVATE = 0x2,
+ MACH_MSG_TYPE_MOVE_RECEIVE = 0x10,
+ MACH_MSG_TYPE_MOVE_SEND = 0x11,
+ MACH_MSG_TYPE_MOVE_SEND_ONCE = 0x12,
+ MACH_MSG_TYPE_COPY_SEND = 0x13,
+ MACH_MSG_TYPE_MAKE_SEND = 0x14,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE = 0x15,
+ MACH_MSG_TYPE_COPY_RECEIVE = 0x16,
+ MACH_MSG_PORT_DESCRIPTOR = 0,
+ MACH_MSG_OOL_DESCRIPTOR = 0x1,
+ MACH_MSG_OOL_PORTS_DESCRIPTOR = 0x2,
+ MACH_MSG_OOL_VOLATILE_DESCRIPTOR = 0x3,
+ MACH_MSGH_BITS_COMPLEX = 0x80000000,
+ MACH_SEND_MSG = 0x1,
+ MACH_RCV_MSG = 0x2,
+ MACH_RCV_LARGE = 0x4,
+ MACH_SEND_TIMEOUT = 0x10,
+ MACH_SEND_INTERRUPT = 0x40,
+ MACH_SEND_CANCEL = 0x80,
+ MACH_SEND_ALWAYS = 0x10000,
+ MACH_SEND_TRAILER = 0x20000,
+ MACH_RCV_TIMEOUT = 0x100,
+ MACH_RCV_NOTIFY = 0x200,
+ MACH_RCV_INTERRUPT = 0x400,
+ MACH_RCV_OVERWRITE = 0x1000,
+ NDR_PROTOCOL_2_0 = 0,
+ NDR_INT_BIG_ENDIAN = 0,
+ NDR_INT_LITTLE_ENDIAN = 0x1,
+ NDR_FLOAT_IEEE = 0,
+ NDR_CHAR_ASCII = 0,
+ SA_SIGINFO = 0x40,
+ SA_RESTART = 0x2,
+ SA_ONSTACK = 0x1,
+ SA_USERTRAMP = 0x100,
+ SA_64REGSET = 0x200,
+};
+
+// Types
+#pragma pack on
+
+typedef struct MachBody MachBody;
+struct MachBody {
+ uint32 msgh_descriptor_count;
+};
+
+typedef struct MachHeader MachHeader;
+struct MachHeader {
+ uint32 msgh_bits;
+ uint32 msgh_size;
+ uint32 msgh_remote_port;
+ uint32 msgh_local_port;
+ uint32 msgh_reserved;
+ int32 msgh_id;
+};
+
+typedef struct MachNDR MachNDR;
+struct MachNDR {
+ uint8 mig_vers;
+ uint8 if_vers;
+ uint8 reserved1;
+ uint8 mig_encoding;
+ uint8 int_rep;
+ uint8 char_rep;
+ uint8 float_rep;
+ uint8 reserved2;
+};
+
+typedef struct MachPort MachPort;
+struct MachPort {
+ uint32 name;
+ uint32 pad1;
+ uint16 pad2;
+ uint8 disposition;
+ uint8 type;
+};
+
+typedef struct StackT StackT;
+struct StackT {
+ void *ss_sp;
+ uint64 ss_size;
+ int32 ss_flags;
+ byte pad0[4];
+};
+
+typedef union Sighandler Sighandler;
+union Sighandler {
+ void *__sa_handler;
+ void *__sa_sigaction;
+};
+
+typedef struct Sigaction Sigaction;
+struct Sigaction {
+ Sighandler __sigaction_u;
+ void *sa_tramp;
+ uint32 sa_mask;
+ int32 sa_flags;
+};
+
+typedef union Sigval Sigval;
+union Sigval {
+ int32 sival_int;
+ void *sival_ptr;
+};
+
+typedef struct Siginfo Siginfo;
+struct Siginfo {
+ int32 si_signo;
+ int32 si_errno;
+ int32 si_code;
+ int32 si_pid;
+ uint32 si_uid;
+ int32 si_status;
+ void *si_addr;
+ Sigval si_value;
+ int64 si_band;
+ uint64 __pad[7];
+};
+
+typedef struct FPControl FPControl;
+struct FPControl {
+ byte pad0[2];
+};
+
+typedef struct FPStatus FPStatus;
+struct FPStatus {
+ byte pad0[2];
+};
+
+typedef struct RegMMST RegMMST;
+struct RegMMST {
+ int8 mmst_reg[10];
+ int8 mmst_rsrv[6];
+};
+
+typedef struct RegXMM RegXMM;
+struct RegXMM {
+ int8 xmm_reg[16];
+};
+
+typedef struct Regs Regs;
+struct Regs {
+ uint64 rax;
+ uint64 rbx;
+ uint64 rcx;
+ uint64 rdx;
+ uint64 rdi;
+ uint64 rsi;
+ uint64 rbp;
+ uint64 rsp;
+ uint64 r8;
+ uint64 r9;
+ uint64 r10;
+ uint64 r11;
+ uint64 r12;
+ uint64 r13;
+ uint64 r14;
+ uint64 r15;
+ uint64 rip;
+ uint64 rflags;
+ uint64 cs;
+ uint64 fs;
+ uint64 gs;
+};
+
+typedef struct FloatState FloatState;
+struct FloatState {
+ int32 fpu_reserved[2];
+ FPControl fpu_fcw;
+ FPStatus fpu_fsw;
+ uint8 fpu_ftw;
+ uint8 fpu_rsrv1;
+ uint16 fpu_fop;
+ uint32 fpu_ip;
+ uint16 fpu_cs;
+ uint16 fpu_rsrv2;
+ uint32 fpu_dp;
+ uint16 fpu_ds;
+ uint16 fpu_rsrv3;
+ uint32 fpu_mxcsr;
+ uint32 fpu_mxcsrmask;
+ RegMMST fpu_stmm0;
+ RegMMST fpu_stmm1;
+ RegMMST fpu_stmm2;
+ RegMMST fpu_stmm3;
+ RegMMST fpu_stmm4;
+ RegMMST fpu_stmm5;
+ RegMMST fpu_stmm6;
+ RegMMST fpu_stmm7;
+ RegXMM fpu_xmm0;
+ RegXMM fpu_xmm1;
+ RegXMM fpu_xmm2;
+ RegXMM fpu_xmm3;
+ RegXMM fpu_xmm4;
+ RegXMM fpu_xmm5;
+ RegXMM fpu_xmm6;
+ RegXMM fpu_xmm7;
+ RegXMM fpu_xmm8;
+ RegXMM fpu_xmm9;
+ RegXMM fpu_xmm10;
+ RegXMM fpu_xmm11;
+ RegXMM fpu_xmm12;
+ RegXMM fpu_xmm13;
+ RegXMM fpu_xmm14;
+ RegXMM fpu_xmm15;
+ int8 fpu_rsrv4[96];
+ int32 fpu_reserved1;
+};
+
+typedef struct ExceptionState ExceptionState;
+struct ExceptionState {
+ uint32 trapno;
+ uint32 err;
+ uint64 faultvaddr;
+};
+
+typedef struct Mcontext Mcontext;
+struct Mcontext {
+ ExceptionState es;
+ Regs ss;
+ FloatState fs;
+ byte pad0[4];
+};
+
+typedef struct Ucontext Ucontext;
+struct Ucontext {
+ int32 uc_onstack;
+ uint32 uc_sigmask;
+ StackT uc_stack;
+ Ucontext *uc_link;
+ uint64 uc_mcsize;
+ Mcontext *uc_mcontext;
+};
+#pragma pack off
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/darwin/amd64/rt0.s
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/darwin/amd64/rt0.s Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,9 @@
+// Copyright 2009 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.
+
+// Darwin and Linux use the same linkage to main
+
+TEXT _rt0_amd64_darwin(SB),7,$-8
+ MOVQ $_rt0_amd64(SB), AX
+ JMP AX
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/darwin/amd64/signal.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/darwin/amd64/signal.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,111 @@
+// Copyright 2009 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.
+
+#include "runtime.h"
+#include "defs.h"
+#include "os.h"
+#include "signals.h"
+
+void
+dumpregs(Regs *r)
+{
+ printf("rax %X\n", r->rax);
+ printf("rbx %X\n", r->rbx);
+ printf("rcx %X\n", r->rcx);
+ printf("rdx %X\n", r->rdx);
+ printf("rdi %X\n", r->rdi);
+ printf("rsi %X\n", r->rsi);
+ printf("rbp %X\n", r->rbp);
+ printf("rsp %X\n", r->rsp);
+ printf("r8 %X\n", r->r8 );
+ printf("r9 %X\n", r->r9 );
+ printf("r10 %X\n", r->r10);
+ printf("r11 %X\n", r->r11);
+ printf("r12 %X\n", r->r12);
+ printf("r13 %X\n", r->r13);
+ printf("r14 %X\n", r->r14);
+ printf("r15 %X\n", r->r15);
+ printf("rip %X\n", r->rip);
+ printf("rflags %X\n", r->rflags);
+ printf("cs %X\n", r->cs);
+ printf("fs %X\n", r->fs);
+ printf("gs %X\n", r->gs);
+}
+
+void
+sighandler(int32 sig, Siginfo *info, void *context)
+{
+ Ucontext *uc;
+ Mcontext *mc;
+ Regs *r;
+
+ if(panicking) // traceback already printed
+ exit(2);
+ panicking = 1;
+
+ if(sig < 0 || sig >= NSIG){
+ printf("Signal %d\n", sig);
+ }else{
+ printf("%s\n", sigtab[sig].name);
+ }
+
+ uc = context;
+ mc = uc->uc_mcontext;
+ r = &mc->ss;
+
+ printf("Faulting address: %p\n", info->si_addr);
+ printf("pc: %X\n", r->rip);
+ printf("\n");
+
+ if(gotraceback()){
+ traceback((void*)r->rip, (void*)r->rsp, (void*)r->r15);
+ tracebackothers((void*)r->r15);
+ dumpregs(r);
+ }
+
+ breakpoint();
+ exit(2);
+}
+
+void
+sigignore(int32, Siginfo*, void*)
+{
+}
+
+void
+signalstack(byte *p, int32 n)
+{
+ StackT st;
+
+ st.ss_sp = p;
+ st.ss_size = n;
+ st.ss_flags = 0;
+ sigaltstack(&st, nil);
+}
+
+void
+initsig(void)
+{
+ int32 i;
+ static Sigaction sa;
+
+ sa.sa_flags |= SA_SIGINFO|SA_ONSTACK;
+ sa.sa_mask = 0; // 0xFFFFFFFFU;
+ sa.sa_tramp = sigtramp; // sigtramp's job is to call into real handler
+ for(i = 0; i<NSIG; i++) {
+ if(sigtab[i].flags) {
+ if(sigtab[i].flags & SigCatch) {
+ sa.__sigaction_u.__sa_sigaction = sighandler;
+ } else {
+ sa.__sigaction_u.__sa_sigaction = sigignore;
+ }
+ if(sigtab[i].flags & SigRestart)
+ sa.sa_flags |= SA_RESTART;
+ else
+ sa.sa_flags &= ~SA_RESTART;
+ sigaction(i, &sa, nil);
+ }
+ }
+}
+
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/darwin/amd64/sys.s
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/darwin/amd64/sys.s Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,263 @@
+// Copyright 2009 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.
+
+//
+// System calls and other sys.stuff for AMD64, Darwin
+// See http://fxr.watson.org/fxr/source/bsd/kern/syscalls.c?v=xnu-1228
+// or /usr/include/sys/syscall.h (on a Mac) for system call numbers.
+//
+
+// Exit the entire program (like C exit)
+TEXT exit(SB),7,$-8
+ MOVL 8(SP), DI // arg 1 exit status
+ MOVL $(0x2000000+1), AX // syscall entry
+ SYSCALL
+ CALL notok(SB)
+ RET
+
+// Exit this OS thread (like pthread_exit, which eventually
+// calls __bsdthread_terminate).
+TEXT exit1(SB),7,$-8
+ MOVL 8(SP), DI // arg 1 exit status
+ MOVL $(0x2000000+361), AX // syscall entry
+ SYSCALL
+ CALL notok(SB)
+ RET
+
+TEXT sys·write(SB),7,$-8
+ MOVL 8(SP), DI // arg 1 fid
+ MOVQ 16(SP), SI // arg 2 buf
+ MOVL 24(SP), DX // arg 3 count
+ MOVL $(0x2000000+4), AX // syscall entry
+ SYSCALL
+ JCC 2(PC)
+ CALL notok(SB)
+ RET
+
+TEXT open(SB),7,$-8
+ MOVQ 8(SP), DI
+ MOVL 16(SP), SI
+ MOVL 20(SP), DX
+ MOVQ $0, R10
+ MOVL $(0x2000000+5), AX // syscall entry
+ SYSCALL
+ RET
+
+TEXT close(SB),7,$-8
+ MOVL 8(SP), DI
+ MOVL $(0x2000000+6), AX // syscall entry
+ SYSCALL
+ RET
+
+TEXT fstat(SB),7,$-8
+ MOVL 8(SP), DI
+ MOVQ 16(SP), SI
+ MOVL $(0x2000000+339), AX // syscall entry; really fstat64
+ SYSCALL
+ RET
+
+TEXT read(SB),7,$-8
+ MOVL 8(SP), DI
+ MOVQ 16(SP), SI
+ MOVL 24(SP), DX
+ MOVL $(0x2000000+3), AX // syscall entry
+ SYSCALL
+ RET
+
+TEXT write(SB),7,$-8
+ MOVL 8(SP), DI
+ MOVQ 16(SP), SI
+ MOVL 24(SP), DX
+ MOVL $(0x2000000+4), AX // syscall entry
+ SYSCALL
+ RET
+
+TEXT sigaction(SB),7,$-8
+ MOVL 8(SP), DI // arg 1 sig
+ MOVQ 16(SP), SI // arg 2 act
+ MOVQ 24(SP), DX // arg 3 oact
+ MOVQ 24(SP), CX // arg 3 oact
+ MOVQ 24(SP), R10 // arg 3 oact
+ MOVL $(0x2000000+46), AX // syscall entry
+ SYSCALL
+ JCC 2(PC)
+ CALL notok(SB)
+ RET
+
+TEXT sigtramp(SB),7,$40
+ MOVQ 32(R14), R15 // g = m->gsignal
+ MOVL DX,0(SP)
+ MOVQ CX,8(SP)
+ MOVQ R8,16(SP)
+ MOVQ R8, 24(SP) // save ucontext
+ MOVQ SI, 32(SP) // save infostyle
+ CALL DI
+ MOVL $(0x2000000+184), AX // sigreturn(ucontext, infostyle)
+ MOVQ 24(SP), DI // saved ucontext
+ MOVQ 32(SP), SI // saved infostyle
+ SYSCALL
+ INT $3 // not reached
+
+TEXT sys·mmap(SB),7,$-8
+ MOVQ 8(SP), DI // arg 1 addr
+ MOVL 16(SP), SI // arg 2 len
+ MOVL 20(SP), DX // arg 3 prot
+ MOVL 24(SP), R10 // arg 4 flags
+ MOVL 28(SP), R8 // arg 5 fid
+ MOVL 32(SP), R9 // arg 6 offset
+ MOVL $(0x2000000+197), AX // syscall entry
+ SYSCALL
+ JCC 2(PC)
+ CALL notok(SB)
+ RET
+
+TEXT notok(SB),7,$-8
+ MOVL $0xf1, BP
+ MOVQ BP, (BP)
+ RET
+
+TEXT sys·memclr(SB),7,$-8
+ MOVQ 8(SP), DI // arg 1 addr
+ MOVL 16(SP), CX // arg 2 count
+ ADDL $7, CX
+ SHRL $3, CX
+ MOVQ $0, AX
+ CLD
+ REP
+ STOSQ
+ RET
+
+TEXT sys·getcallerpc+0(SB),7,$0
+ MOVQ x+0(FP),AX // addr of first arg
+ MOVQ -8(AX),AX // get calling pc
+ RET
+
+TEXT sys·setcallerpc+0(SB),7,$0
+ MOVQ x+0(FP),AX // addr of first arg
+ MOVQ x+8(FP), BX
+ MOVQ BX, -8(AX) // set calling pc
+ RET
+
+TEXT sigaltstack(SB),7,$-8
+ MOVQ new+8(SP), DI
+ MOVQ old+16(SP), SI
+ MOVQ $(0x2000000+53), AX
+ SYSCALL
+ JCC 2(PC)
+ CALL notok(SB)
+ RET
+
+// void bsdthread_create(void *stk, M *m, G *g, void (*fn)(void))
+TEXT bsdthread_create(SB),7,$-8
+ // Set up arguments to bsdthread_create system call.
+ // The ones in quotes pass through to the thread callback
+ // uninterpreted, so we can put whatever we want there.
+ MOVQ fn+32(SP), DI // "func"
+ MOVQ m+16(SP), SI // "arg"
+ MOVQ stk+8(SP), DX // stack
+ MOVQ g+24(SP), R10 // "pthread"
+// TODO(rsc): why do we get away with 0 flags here but not on 386?
+ MOVQ $0, R8 // flags
+ MOVQ $(0x2000000+360), AX // bsdthread_create
+ SYSCALL
+ JCC 2(PC)
+ CALL notok(SB)
+ RET
+
+// The thread that bsdthread_create creates starts executing here,
+// because we registered this function using bsdthread_register
+// at startup.
+// DI = "pthread" (= g)
+// SI = mach thread port
+// DX = "func" (= fn)
+// CX = "arg" (= m)
+// R8 = stack
+// R9 = flags (= 0)
+// SP = stack - C_64_REDZONE_LEN (= stack - 128)
+TEXT bsdthread_start(SB),7,$-8
+ MOVQ CX, R14 // m
+ MOVQ DI, R15 // g
+ MOVQ SI, 24(R14) // thread port is m->procid
+ CALL DX // fn
+ CALL exit1(SB)
+ RET
+
+// void bsdthread_register(void)
+// registers callbacks for threadstart (see bsdthread_create above
+// and wqthread and pthsize (not used). returns 0 on success.
+TEXT bsdthread_register(SB),7,$-8
+ MOVQ $bsdthread_start(SB), DI // threadstart
+ MOVQ $0, SI // wqthread, not used by us
+ MOVQ $0, DX // pthsize, not used by us
+ MOVQ $(0x2000000+366), AX // bsdthread_register
+ SYSCALL
+ JCC 2(PC)
+ CALL notok(SB)
+ RET
+
+// Mach system calls use 0x1000000 instead of the BSD's 0x2000000.
+
+// uint32 mach_msg_trap(void*, uint32, uint32, uint32, uint32, uint32, uint32)
+TEXT mach_msg_trap(SB),7,$0
+ MOVQ 8(SP), DI
+ MOVL 16(SP), SI
+ MOVL 20(SP), DX
+ MOVL 24(SP), R10
+ MOVL 28(SP), R8
+ MOVL 32(SP), R9
+ MOVL 36(SP), R11
+ PUSHQ R11 // seventh arg, on stack
+ MOVL $(0x1000000+31), AX // mach_msg_trap
+ SYSCALL
+ POPQ R11
+ RET
+
+TEXT mach_task_self(SB),7,$0
+ MOVL $(0x1000000+28), AX // task_self_trap
+ SYSCALL
+ RET
+
+TEXT mach_thread_self(SB),7,$0
+ MOVL $(0x1000000+27), AX // thread_self_trap
+ SYSCALL
+ RET
+
+TEXT mach_reply_port(SB),7,$0
+ MOVL $(0x1000000+26), AX // mach_reply_port
+ SYSCALL
+ RET
+
+// Mach provides trap versions of the semaphore ops,
+// instead of requiring the use of RPC.
+
+// uint32 mach_semaphore_wait(uint32)
+TEXT mach_semaphore_wait(SB),7,$0
+ MOVL 8(SP), DI
+ MOVL $(0x1000000+36), AX // semaphore_wait_trap
+ SYSCALL
+ RET
+
+// uint32 mach_semaphore_timedwait(uint32, uint32, uint32)
+TEXT mach_semaphore_timedwait(SB),7,$0
+ MOVL 8(SP), DI
+ MOVL 12(SP), SI
+ MOVL 16(SP), DX
+ MOVL $(0x1000000+38), AX // semaphore_timedwait_trap
+ SYSCALL
+ RET
+
+// uint32 mach_semaphore_signal(uint32)
+TEXT mach_semaphore_signal(SB),7,$0
+ MOVL 8(SP), DI
+ MOVL $(0x1000000+33), AX // semaphore_signal_trap
+ SYSCALL
+ RET
+
+// uint32 mach_semaphore_signal_all(uint32)
+TEXT mach_semaphore_signal_all(SB),7,$0
+ MOVL 8(SP), DI
+ MOVL $(0x1000000+34), AX // semaphore_signal_all_trap
+ SYSCALL
+ RET
+
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/darwin/defs.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/darwin/defs.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,104 @@
+// Copyright 2009 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.
+
+/*
+ * Input to godefs.
+ *
+ godefs -f -m64 defs.c >amd64/defs.h
+ godefs defs.c >386/defs.h
+ */
+
+#define __DARWIN_UNIX03 0
+
+#include <mach/mach.h>
+#include <mach/message.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <sys/mman.h>
+
+enum {
+ $PROT_NONE = PROT_NONE,
+ $PROT_READ = PROT_READ,
+ $PROT_WRITE = PROT_WRITE,
+ $PROT_EXEC = PROT_EXEC,
+
+ $MAP_ANON = MAP_ANON,
+ $MAP_PRIVATE = MAP_PRIVATE,
+
+ $MACH_MSG_TYPE_MOVE_RECEIVE = MACH_MSG_TYPE_MOVE_RECEIVE,
+ $MACH_MSG_TYPE_MOVE_SEND = MACH_MSG_TYPE_MOVE_SEND,
+ $MACH_MSG_TYPE_MOVE_SEND_ONCE = MACH_MSG_TYPE_MOVE_SEND_ONCE,
+ $MACH_MSG_TYPE_COPY_SEND = MACH_MSG_TYPE_COPY_SEND,
+ $MACH_MSG_TYPE_MAKE_SEND = MACH_MSG_TYPE_MAKE_SEND,
+ $MACH_MSG_TYPE_MAKE_SEND_ONCE = MACH_MSG_TYPE_MAKE_SEND_ONCE,
+ $MACH_MSG_TYPE_COPY_RECEIVE = MACH_MSG_TYPE_COPY_RECEIVE,
+
+ $MACH_MSG_PORT_DESCRIPTOR = MACH_MSG_PORT_DESCRIPTOR,
+ $MACH_MSG_OOL_DESCRIPTOR = MACH_MSG_OOL_DESCRIPTOR,
+ $MACH_MSG_OOL_PORTS_DESCRIPTOR = MACH_MSG_OOL_PORTS_DESCRIPTOR,
+ $MACH_MSG_OOL_VOLATILE_DESCRIPTOR = MACH_MSG_OOL_VOLATILE_DESCRIPTOR,
+
+ $MACH_MSGH_BITS_COMPLEX = MACH_MSGH_BITS_COMPLEX,
+
+ $MACH_SEND_MSG = MACH_SEND_MSG,
+ $MACH_RCV_MSG = MACH_RCV_MSG,
+ $MACH_RCV_LARGE = MACH_RCV_LARGE,
+
+ $MACH_SEND_TIMEOUT = MACH_SEND_TIMEOUT,
+ $MACH_SEND_INTERRUPT = MACH_SEND_INTERRUPT,
+ $MACH_SEND_CANCEL = MACH_SEND_CANCEL,
+ $MACH_SEND_ALWAYS = MACH_SEND_ALWAYS,
+ $MACH_SEND_TRAILER = MACH_SEND_TRAILER,
+ $MACH_RCV_TIMEOUT = MACH_RCV_TIMEOUT,
+ $MACH_RCV_NOTIFY = MACH_RCV_NOTIFY,
+ $MACH_RCV_INTERRUPT = MACH_RCV_INTERRUPT,
+ $MACH_RCV_OVERWRITE = MACH_RCV_OVERWRITE,
+
+ $NDR_PROTOCOL_2_0 = NDR_PROTOCOL_2_0,
+ $NDR_INT_BIG_ENDIAN = NDR_INT_BIG_ENDIAN,
+ $NDR_INT_LITTLE_ENDIAN = NDR_INT_LITTLE_ENDIAN,
+ $NDR_FLOAT_IEEE = NDR_FLOAT_IEEE,
+ $NDR_CHAR_ASCII = NDR_CHAR_ASCII,
+
+ $SA_SIGINFO = SA_SIGINFO,
+ $SA_RESTART = SA_RESTART,
+ $SA_ONSTACK = SA_ONSTACK,
+ $SA_USERTRAMP = SA_USERTRAMP,
+ $SA_64REGSET = SA_64REGSET,
+};
+
+typedef mach_msg_body_t $MachBody;
+typedef mach_msg_header_t $MachHeader;
+typedef NDR_record_t $MachNDR;
+typedef mach_msg_port_descriptor_t $MachPort;
+
+typedef stack_t $StackT;
+typedef union __sigaction_u $Sighandler;
+
+typedef struct __sigaction $Sigaction; // used in syscalls
+// typedef struct sigaction $Sigaction; // used by the C library
+typedef union sigval $Sigval;
+typedef siginfo_t $Siginfo;
+
+typedef struct fp_control $FPControl;
+typedef struct fp_status $FPStatus;
+typedef struct mmst_reg $RegMMST;
+typedef struct xmm_reg $RegXMM;
+
+#ifdef __LP64__
+// amd64
+typedef x86_thread_state64_t $Regs;
+typedef x86_float_state64_t $FloatState;
+typedef x86_exception_state64_t $ExceptionState;
+typedef struct mcontext64 $Mcontext;
+#else
+// 386
+typedef x86_thread_state32_t $Regs;
+typedef x86_float_state32_t $FloatState;
+typedef x86_exception_state32_t $ExceptionState;
+typedef struct mcontext32 $Mcontext;
+#endif
+
+typedef ucontext_t $Ucontext;
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/darwin/os.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/darwin/os.h Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,24 @@
+// Copyright 2009 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.
+
+void bsdthread_create(void*, M*, G*, void(*)(void));
+void bsdthread_register(void);
+int32 mach_msg_trap(MachHeader*, int32, uint32, uint32, uint32, uint32, uint32);
+uint32 mach_reply_port(void);
+void mach_semacquire(uint32);
+uint32 mach_semcreate(void);
+void mach_semdestroy(uint32);
+void mach_semrelease(uint32);
+void mach_semreset(uint32);
+uint32 mach_task_self(void);
+uint32 mach_task_self(void);
+uint32 mach_thread_self(void);
+uint32 mach_thread_self(void);
+
+struct Sigaction;
+void sigaction(int64, struct Sigaction*, struct Sigaction*);
+
+struct StackT;
+void sigaltstack(struct StackT*, struct StackT*);
+void sigtramp(void);
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/darwin/signals.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/darwin/signals.h Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,48 @@
+// Copyright 2009 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.
+
+
+#define C SigCatch
+#define I SigIgnore
+#define R SigRestart
+
+static SigTab sigtab[] = {
+ /* 0 */ 0, "SIGNONE: no trap",
+ /* 1 */ 0, "SIGHUP: terminal line hangup",
+ /* 2 */ 0, "SIGINT: interrupt",
+ /* 3 */ C, "SIGQUIT: quit",
+ /* 4 */ C, "SIGILL: illegal instruction",
+ /* 5 */ C, "SIGTRAP: trace trap", /* used by panic and array out of bounds, etc. */
+ /* 6 */ C, "SIGABRT: abort",
+ /* 7 */ C, "SIGEMT: emulate instruction executed",
+ /* 8 */ C, "SIGFPE: floating-point exception",
+ /* 9 */ 0, "SIGKILL: kill",
+ /* 10 */ C, "SIGBUS: bus error",
+ /* 11 */ C, "SIGSEGV: segmentation violation",
+ /* 12 */ C, "SIGSYS: bad system call",
+ /* 13 */ I, "SIGPIPE: write to broken pipe",
+ /* 14 */ 0, "SIGALRM: alarm clock",
+ /* 15 */ 0, "SIGTERM: termination",
+ /* 16 */ 0, "SIGURG: urgent condition on socket",
+ /* 17 */ 0, "SIGSTOP: stop",
+ /* 18 */ 0, "SIGTSTP: keyboard stop",
+ /* 19 */ 0, "SIGCONT: continue after stop",
+ /* 20 */ I+R, "SIGCHLD: child status has changed",
+ /* 21 */ 0, "SIGTTIN: background read from tty",
+ /* 22 */ 0, "SIGTTOU: background write to tty",
+ /* 23 */ 0, "SIGIO: i/o now possible",
+ /* 24 */ 0, "SIGXCPU: cpu limit exceeded",
+ /* 25 */ 0, "SIGXFSZ: file size limit exceeded",
+ /* 26 */ 0, "SIGVTALRM: virtual alarm clock",
+ /* 27 */ 0, "SIGPROF: profiling alarm clock",
+ /* 28 */ I+R, "SIGWINCH: window size change",
+ /* 29 */ 0, "SIGINFO: status request from keyboard",
+ /* 30 */ 0, "SIGUSR1: user-defined signal 1",
+ /* 31 */ 0, "SIGUSR2: user-defined signal 2",
+};
+#undef C
+#undef I
+#undef R
+
+#define NSIG 32
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/darwin/thread.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/darwin/thread.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,427 @@
+// Copyright 2009 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.
+
+#include "runtime.h"
+#include "defs.h"
+#include "os.h"
+
+static void
+unimplemented(int8 *name)
+{
+ prints(name);
+ prints(" not implemented\n");
+ *(int32*)1231 = 1231;
+}
+
+// Thread-safe allocation of a semaphore.
+// Psema points at a kernel semaphore key.
+// It starts out zero, meaning no semaphore.
+// Fill it in, being careful of others calling initsema
+// simultaneously.
+static void
+initsema(uint32 *psema)
+{
+ uint32 sema;
+
+ if(*psema != 0) // already have one
+ return;
+
+ sema = mach_semcreate();
+ if(!cas(psema, 0, sema)){
+ // Someone else filled it in. Use theirs.
+ mach_semdestroy(sema);
+ return;
+ }
+}
+
+
+// Atomic add and return new value.
+static uint32
+xadd(uint32 volatile *val, int32 delta)
+{
+ uint32 oval, nval;
+
+ for(;;){
+ oval = *val;
+ nval = oval + delta;
+ if(cas(val, oval, nval))
+ return nval;
+ }
+}
+
+
+// Blocking locks.
+
+// Implement Locks, using semaphores.
+// l->key is the number of threads who want the lock.
+// In a race, one thread increments l->key from 0 to 1
+// and the others increment it from >0 to >1. The thread
+// who does the 0->1 increment gets the lock, and the
+// others wait on the semaphore. When the 0->1 thread
+// releases the lock by decrementing l->key, l->key will
+// be >0, so it will increment the semaphore to wake up
+// one of the others. This is the same algorithm used
+// in Plan 9's user-level locks.
+//
+// Note that semaphores are never destroyed (the kernel
+// will clean up when the process exits). We assume for now
+// that Locks are only used for long-lived structures like M and G.
+
+void
+lock(Lock *l)
+{
+ if(m->locks < 0)
+ throw("lock count");
+ m->locks++;
+
+ // Allocate semaphore if needed.
+ if(l->sema == 0)
+ initsema(&l->sema);
+
+ if(xadd(&l->key, 1) > 1) // someone else has it; wait
+ mach_semacquire(l->sema);
+}
+
+void
+unlock(Lock *l)
+{
+ m->locks--;
+ if(m->locks < 0)
+ throw("lock count");
+
+ if(xadd(&l->key, -1) > 0) // someone else is waiting
+ mach_semrelease(l->sema);
+}
+
+
+// User-level semaphore implementation:
+// try to do the operations in user space on u,
+// but when it's time to block, fall back on the kernel semaphore k.
+// This is the same algorithm used in Plan 9.
+void
+usemacquire(Usema *s)
+{
+ if((int32)xadd(&s->u, -1) < 0)
+ mach_semacquire(s->k);
+}
+
+void
+usemrelease(Usema *s)
+{
+ if((int32)xadd(&s->u, 1) <= 0)
+ mach_semrelease(s->k);
+}
+
+
+// Event notifications.
+void
+noteclear(Note *n)
+{
+ n->wakeup = 0;
+}
+
+void
+notesleep(Note *n)
+{
+ if(n->sema.k == 0)
+ initsema(&n->sema.k);
+ while(!n->wakeup)
+ usemacquire(&n->sema);
+}
+
+void
+notewakeup(Note *n)
+{
+ if(n->sema.k == 0)
+ initsema(&n->sema.k);
+ n->wakeup = 1;
+ usemrelease(&n->sema);
+}
+
+
+// BSD interface for threading.
+void
+osinit(void)
+{
+ // Register our thread-creation callback (see {amd64,386}/sys.s).
+ bsdthread_register();
+}
+
+void
+newosproc(M *m, G *g, void *stk, void (*fn)(void))
+{
+ // printf("newosproc m=%p g=%p stk=%p fn=%p\n", m, g, stk, fn);
+ m->tls[0] = m->id; // so 386 asm can find it
+ bsdthread_create(stk, m, g, fn);
+}
+
+// Called to initialize a new m (including the bootstrap m).
+void
+minit(void)
+{
+ // Initialize signal handling.
+ m->gsignal = malg(32*1024); // OS X wants >=8K, Linux >=2K
+ signalstack(m->gsignal->stackguard, 32*1024);
+}
+
+// Mach IPC, to get at semaphores
+// Definitions are in /usr/include/mach on a Mac.
+
+static void
+macherror(int32 r, int8 *fn)
+{
+ printf("mach error %s: %d\n", fn, r);
+ throw("mach error");
+}
+
+enum
+{
+ DebugMach = 0
+};
+
+static MachNDR zerondr;
+
+#define MACH_MSGH_BITS(a, b) ((a) | ((b)<<8))
+
+static int32
+mach_msg(MachHeader *h,
+ int32 op,
+ uint32 send_size,
+ uint32 rcv_size,
+ uint32 rcv_name,
+ uint32 timeout,
+ uint32 notify)
+{
+ // TODO: Loop on interrupt.
+ return mach_msg_trap(h, op, send_size, rcv_size, rcv_name, timeout, notify);
+}
+
+// Mach RPC (MIG)
+
+enum
+{
+ MinMachMsg = 48,
+ Reply = 100,
+};
+
+#pragma pack on
+typedef struct CodeMsg CodeMsg;
+struct CodeMsg
+{
+ MachHeader h;
+ MachNDR NDR;
+ int32 code;
+};
+#pragma pack off
+
+static int32
+machcall(MachHeader *h, int32 maxsize, int32 rxsize)
+{
+ uint32 *p;
+ int32 i, ret, id;
+ uint32 port;
+ CodeMsg *c;
+
+ if((port = m->machport) == 0){
+ port = mach_reply_port();
+ m->machport = port;
+ }
+
+ h->msgh_bits |= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE);
+ h->msgh_local_port = port;
+ h->msgh_reserved = 0;
+ id = h->msgh_id;
+
+ if(DebugMach){
+ p = (uint32*)h;
+ prints("send:\t");
+ for(i=0; i<h->msgh_size/sizeof(p[0]); i++){
+ prints(" ");
+ sys·printpointer((void*)p[i]);
+ if(i%8 == 7)
+ prints("\n\t");
+ }
+ if(i%8)
+ prints("\n");
+ }
+
+ ret = mach_msg(h, MACH_SEND_MSG|MACH_RCV_MSG,
+ h->msgh_size, maxsize, port, 0, 0);
+ if(ret != 0){
+ if(DebugMach){
+ prints("mach_msg error ");
+ sys·printint(ret);
+ prints("\n");
+ }
+ return ret;
+ }
+
+ if(DebugMach){
+ p = (uint32*)h;
+ prints("recv:\t");
+ for(i=0; i<h->msgh_size/sizeof(p[0]); i++){
+ prints(" ");
+ sys·printpointer((void*)p[i]);
+ if(i%8 == 7)
+ prints("\n\t");
+ }
+ if(i%8)
+ prints("\n");
+ }
+
+ if(h->msgh_id != id+Reply){
+ if(DebugMach){
+ prints("mach_msg reply id mismatch ");
+ sys·printint(h->msgh_id);
+ prints(" != ");
+ sys·printint(id+Reply);
+ prints("\n");
+ }
+ return -303; // MIG_REPLY_MISMATCH
+ }
+
+ // Look for a response giving the return value.
+ // Any call can send this back with an error,
+ // and some calls only have return values so they
+ // send it back on success too. I don't quite see how
+ // you know it's one of these and not the full response
+ // format, so just look if the message is right.
+ c = (CodeMsg*)h;
+ if(h->msgh_size == sizeof(CodeMsg)
+ && !(h->msgh_bits & MACH_MSGH_BITS_COMPLEX)){
+ if(DebugMach){
+ prints("mig result ");
+ sys·printint(c->code);
+ prints("\n");
+ }
+ return c->code;
+ }
+
+ if(h->msgh_size != rxsize){
+ if(DebugMach){
+ prints("mach_msg reply size mismatch ");
+ sys·printint(h->msgh_size);
+ prints(" != ");
+ sys·printint(rxsize);
+ prints("\n");
+ }
+ return -307; // MIG_ARRAY_TOO_LARGE
+ }
+
+ return 0;
+}
+
+
+// Semaphores!
+
+enum
+{
+ Tmach_semcreate = 3418,
+ Rmach_semcreate = Tmach_semcreate + Reply,
+
+ Tmach_semdestroy = 3419,
+ Rmach_semdestroy = Tmach_semdestroy + Reply,
+};
+
+typedef struct Tmach_semcreateMsg Tmach_semcreateMsg;
+typedef struct Rmach_semcreateMsg Rmach_semcreateMsg;
+typedef struct Tmach_semdestroyMsg Tmach_semdestroyMsg;
+// Rmach_semdestroyMsg = CodeMsg
+
+#pragma pack on
+struct Tmach_semcreateMsg
+{
+ MachHeader h;
+ MachNDR ndr;
+ int32 policy;
+ int32 value;
+};
+
+struct Rmach_semcreateMsg
+{
+ MachHeader h;
+ MachBody body;
+ MachPort semaphore;
+};
+
+struct Tmach_semdestroyMsg
+{
+ MachHeader h;
+ MachBody body;
+ MachPort semaphore;
+};
+#pragma pack off
+
+uint32
+mach_semcreate(void)
+{
+ union {
+ Tmach_semcreateMsg tx;
+ Rmach_semcreateMsg rx;
+ uint8 pad[MinMachMsg];
+ } m;
+ int32 r;
+
+ m.tx.h.msgh_bits = 0;
+ m.tx.h.msgh_size = sizeof(m.tx);
+ m.tx.h.msgh_remote_port = mach_task_self();
+ m.tx.h.msgh_id = Tmach_semcreate;
+ m.tx.ndr = zerondr;
+
+ m.tx.policy = 0; // 0 = SYNC_POLICY_FIFO
+ m.tx.value = 0;
+
+ if((r = machcall(&m.tx.h, sizeof m, sizeof(m.rx))) != 0)
+ macherror(r, "semaphore_create");
+ if(m.rx.body.msgh_descriptor_count != 1)
+ unimplemented("mach_semcreate desc count");
+ return m.rx.semaphore.name;
+}
+
+void
+mach_semdestroy(uint32 sem)
+{
+ union {
+ Tmach_semdestroyMsg tx;
+ uint8 pad[MinMachMsg];
+ } m;
+ int32 r;
+
+ m.tx.h.msgh_bits = MACH_MSGH_BITS_COMPLEX;
+ m.tx.h.msgh_size = sizeof(m.tx);
+ m.tx.h.msgh_remote_port = mach_task_self();
+ m.tx.h.msgh_id = Tmach_semdestroy;
+ m.tx.body.msgh_descriptor_count = 1;
+ m.tx.semaphore.name = sem;
+ m.tx.semaphore.disposition = MACH_MSG_TYPE_MOVE_SEND;
+ m.tx.semaphore.type = 0;
+
+ if((r = machcall(&m.tx.h, sizeof m, 0)) != 0)
+ macherror(r, "semaphore_destroy");
+}
+
+// The other calls have simple system call traps in sys.s
+int32 mach_semaphore_wait(uint32 sema);
+int32 mach_semaphore_timedwait(uint32 sema, uint32 sec, uint32 nsec);
+int32 mach_semaphore_signal(uint32 sema);
+int32 mach_semaphore_signal_all(uint32 sema);
+
+void
+mach_semacquire(uint32 sem)
+{
+ int32 r;
+
+ if((r = mach_semaphore_wait(sem)) != 0)
+ macherror(r, "semaphore_wait");
+}
+
+void
+mach_semrelease(uint32 sem)
+{
+ int32 r;
+
+ if((r = mach_semaphore_signal(sem)) != 0)
+ macherror(r, "semaphore_signal");
+}
+
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/extern.go
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/extern.go Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,28 @@
+// Copyright 2009 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.
+
+/*
+ The runtime package contains operations that interact with Go's runtime system,
+ such as functions to control goroutines.
+ */
+package runtime
+
+// These functions are implemented in the base runtime library, ../../runtime/.
+
+// Gosched yields the processor, allowing other goroutines to run. It does not
+// suspend the current goroutine, so execution resumes automatically.
+func Gosched()
+
+// Goexit terminates the goroutine that calls it. No other goroutine is affected.
+func Goexit()
+
+// Breakpoint() executes a breakpoint trap.
+func Breakpoint()
+
+// Caller reports file and line number information about function invocations on
+// the calling goroutine's stack. The argument is the number of stack frames to
+// ascend, with 1 identifying the the caller of Caller. The return values report the
+// program counter, file name, and line number within the file of the corresponding
+// call. The boolean ok is false if it was not possible to recover the information.
+func Caller(n int) (pc uintptr, file string, line int, ok bool)
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/float.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/float.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,173 @@
+// Copyright 2009 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.
+
+#include "runtime.h"
+
+static uint64 uvnan = 0x7FF0000000000001ULL;
+static uint64 uvinf = 0x7FF0000000000000ULL;
+static uint64 uvneginf = 0xFFF0000000000000ULL;
+
+uint32
+float32tobits(float32 f)
+{
+ // The obvious cast-and-pointer code is technically
+ // not valid, and gcc miscompiles it. Use a union instead.
+ union {
+ float32 f;
+ uint32 i;
+ } u;
+ u.f = f;
+ return u.i;
+}
+
+uint64
+float64tobits(float64 f)
+{
+ // The obvious cast-and-pointer code is technically
+ // not valid, and gcc miscompiles it. Use a union instead.
+ union {
+ float64 f;
+ uint64 i;
+ } u;
+ u.f = f;
+ return u.i;
+}
+
+float64
+float64frombits(uint64 i)
+{
+ // The obvious cast-and-pointer code is technically
+ // not valid, and gcc miscompiles it. Use a union instead.
+ union {
+ float64 f;
+ uint64 i;
+ } u;
+ u.i = i;
+ return u.f;
+}
+
+float32
+float32frombits(uint32 i)
+{
+ // The obvious cast-and-pointer code is technically
+ // not valid, and gcc miscompiles it. Use a union instead.
+ union {
+ float32 f;
+ uint32 i;
+ } u;
+ u.i = i;
+ return u.f;
+}
+
+bool
+isInf(float64 f, int32 sign)
+{
+ uint64 x;
+
+ x = float64tobits(f);
+ if(sign == 0)
+ return x == uvinf || x == uvneginf;
+ if(sign > 0)
+ return x == uvinf;
+ return x == uvneginf;
+}
+
+float64
+NaN(void)
+{
+ return float64frombits(uvnan);
+}
+
+bool
+isNaN(float64 f)
+{
+ uint64 x;
+
+ x = float64tobits(f);
+ return ((uint32)(x>>52) & 0x7FF) == 0x7FF && !isInf(f, 0);
+}
+
+float64
+Inf(int32 sign)
+{
+ if(sign >= 0)
+ return float64frombits(uvinf);
+ else
+ return float64frombits(uvneginf);
+}
+
+enum
+{
+ MASK = 0x7ffL,
+ SHIFT = 64-11-1,
+ BIAS = 1022L,
+};
+
+float64
+frexp(float64 d, int32 *ep)
+{
+ uint64 x;
+
+ if(d == 0) {
+ *ep = 0;
+ return 0;
+ }
+ x = float64tobits(d);
+ *ep = (int32)((x >> SHIFT) & MASK) - BIAS;
+ x &= ~((uint64)MASK << SHIFT);
+ x |= (uint64)BIAS << SHIFT;
+ return float64frombits(x);
+}
+
+float64
+ldexp(float64 d, int32 e)
+{
+ uint64 x;
+
+ if(d == 0)
+ return 0;
+ x = float64tobits(d);
+ e += (int32)(x >> SHIFT) & MASK;
+ if(e <= 0)
+ return 0; /* underflow */
+ if(e >= MASK){ /* overflow */
+ if(d < 0)
+ return Inf(-1);
+ return Inf(1);
+ }
+ x &= ~((uint64)MASK << SHIFT);
+ x |= (uint64)e << SHIFT;
+ return float64frombits(x);
+}
+
+float64
+modf(float64 d, float64 *ip)
+{
+ float64 dd;
+ uint64 x;
+ int32 e;
+
+ if(d < 1) {
+ if(d < 0) {
+ d = modf(-d, ip);
+ *ip = -*ip;
+ return -d;
+ }
+ *ip = 0;
+ return d;
+ }
+
+ x = float64tobits(d);
+ e = (int32)((x >> SHIFT) & MASK) - BIAS;
+
+ /*
+ * Keep the top 11+e bits; clear the rest.
+ */
+ if(e <= 64-11)
+ x &= ~(((uint64)1 << (64LL-11LL-e))-1);
+ dd = float64frombits(x);
+ *ip = dd;
+ return d - dd;
+}
+
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/float_go.cgo
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/float_go.cgo Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,52 @@
+// Copyright 2009 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 math
+
+#include "runtime.h"
+
+func Frexp(f float64) (frac float64, exp int32) {
+ frac = frexp(f, &exp);
+}
+
+func Ldexp(frac float64, exp int32) (f float64) {
+ f = ldexp(frac, exp);
+}
+
+func Modf(f float64) (integer float64, frac float64) {
+ frac = modf(f, &integer);
+}
+
+func IsInf(f float64, sign int32) (is bool) {
+ is = isInf(f, sign);
+}
+
+func IsNaN(f float64) (is bool) {
+ is = isNaN(f);
+}
+
+func Inf(sign int32) (f float64) {
+ f = Inf(sign);
+}
+
+func NaN() (f float64) {
+ f = NaN();
+}
+
+func Float32bits(f float32) (b uint32) {
+ b = float32tobits(f);
+}
+
+func Float64bits(f float64) (b uint64) {
+ b = float64tobits(f);
+}
+
+func Float32frombits(b uint32) (f float32) {
+ f = float32frombits(b);
+}
+
+func Float64frombits(b uint64) (f float64) {
+ f = float64frombits(b);
+}
+
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/hashmap.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/hashmap.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,954 @@
+// Copyright 2009 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.
+
+#include "runtime.h"
+#include "hashmap.h"
+
+/* Return a pointer to the struct/union of type "type"
+ whose "field" field is addressed by pointer "p". */
+
+
+struct hash { /* a hash table; initialize with hash_init() */
+ uint32 count; /* elements in table - must be first */
+
+ uint8 datasize; /* amount of data to store in entry */
+ uint8 max_power; /* max power of 2 to create sub-tables */
+ uint8 max_probes; /* max entries to probe before rehashing */
+ int32 changes; /* inc'ed whenever a subtable is created/grown */
+ hash_hash_t (*data_hash) (uint32, void *a); /* return hash of *a */
+ uint32 (*data_eq) (uint32, void *a, void *b); /* return whether *a == *b */
+ void (*data_del) (uint32, void *arg, void *data); /* invoked on deletion */
+ struct hash_subtable *st; /* first-level table */
+
+ uint32 keysize;
+ uint32 valsize;
+ uint32 datavo;
+ uint32 ko;
+ uint32 vo;
+ uint32 po;
+ Alg* keyalg;
+ Alg* valalg;
+};
+
+struct hash_entry {
+ hash_hash_t hash; /* hash value of data */
+ byte data[1]; /* user data has "datasize" bytes */
+};
+
+struct hash_subtable {
+ uint8 power; /* bits used to index this table */
+ uint8 used; /* bits in hash used before reaching this table */
+ uint8 datasize; /* bytes of client data in an entry */
+ uint8 max_probes; /* max number of probes when searching */
+ int16 limit_bytes; /* max_probes * (datasize+sizeof (hash_hash_t)) */
+ struct hash_entry *end; /* points just past end of entry[] */
+ struct hash_entry entry[1]; /* 2**power+max_probes-1 elements of elemsize bytes */
+};
+
+#define HASH_DATA_EQ(h,x,y) ((*h->data_eq) (h->keysize, (x), (y)))
+
+#define HASH_REHASH 0x2 /* an internal flag */
+/* the number of bits used is stored in the flags word too */
+#define HASH_USED(x) ((x) >> 2)
+#define HASH_MAKE_USED(x) ((x) << 2)
+
+#define HASH_LOW 6
+#define HASH_ONE (((hash_hash_t)1) << HASH_LOW)
+#define HASH_MASK (HASH_ONE - 1)
+#define HASH_ADJUST(x) (((x) < HASH_ONE) << HASH_LOW)
+
+#define HASH_BITS (sizeof (hash_hash_t) * 8)
+
+#define HASH_SUBHASH HASH_MASK
+#define HASH_NIL 0
+#define HASH_NIL_MEMSET 0
+
+#define HASH_OFFSET(base, byte_offset) \
+ ((struct hash_entry *) (((byte *) (base)) + (byte_offset)))
+
+
+/* return a hash layer with 2**power empty entries */
+static struct hash_subtable *
+hash_subtable_new (struct hash *h, int32 power, int32 used)
+{
+ int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
+ int32 bytes = elemsize << power;
+ struct hash_subtable *st;
+ int32 limit_bytes = h->max_probes * elemsize;
+ int32 max_probes = h->max_probes;
+
+ if (bytes < limit_bytes) {
+ limit_bytes = bytes;
+ max_probes = 1 << power;
+ }
+ bytes += limit_bytes - elemsize;
+ st = malloc (offsetof (struct hash_subtable, entry[0]) + bytes);
+ st->power = power;
+ st->used = used;
+ st->datasize = h->datasize;
+ st->max_probes = max_probes;
+ st->limit_bytes = limit_bytes;
+ st->end = HASH_OFFSET (st->entry, bytes);
+ memset (st->entry, HASH_NIL_MEMSET, bytes);
+ return (st);
+}
+
+static void
+init_sizes (int64 hint, int32 *init_power, int32 *max_power)
+{
+ int32 log = 0;
+ int32 i;
+
+ for (i = 32; i != 0; i >>= 1) {
+ if ((hint >> (log + i)) != 0) {
+ log += i;
+ }
+ }
+ log += 1 + (((hint << 3) >> log) >= 11); /* round up for utilization */
+ if (log <= 14) {
+ *init_power = log;
+ } else {
+ *init_power = 12;
+ }
+ *max_power = 12;
+}
+
+static void
+hash_init (struct hash *h,
+ int32 datasize,
+ hash_hash_t (*data_hash) (uint32, void *),
+ uint32 (*data_eq) (uint32, void *, void *),
+ void (*data_del) (uint32, void *, void *),
+ int64 hint)
+{
+ int32 init_power;
+ int32 max_power;
+
+ if(datasize < sizeof (void *))
+ datasize = sizeof (void *);
+ datasize = rnd(datasize, sizeof (void *));
+ init_sizes (hint, &init_power, &max_power);
+ h->datasize = datasize;
+ h->max_power = max_power;
+ h->max_probes = 15;
+ assert (h->datasize == datasize);
+ assert (h->max_power == max_power);
+ assert (sizeof (void *) <= h->datasize || h->max_power == 255);
+ h->count = 0;
+ h->changes = 0;
+ h->data_hash = data_hash;
+ h->data_eq = data_eq;
+ h->data_del = data_del;
+ h->st = hash_subtable_new (h, init_power, 0);
+}
+
+static void
+hash_remove_n (struct hash_subtable *st, struct hash_entry *dst_e, int32 n)
+{
+ int32 elemsize = st->datasize + offsetof (struct hash_entry, data[0]);
+ struct hash_entry *src_e = HASH_OFFSET (dst_e, n * elemsize);
+ struct hash_entry *end_e = st->end;
+ int32 shift = HASH_BITS - (st->power + st->used);
+ int32 index_mask = (((hash_hash_t)1) << st->power) - 1;
+ int32 dst_i = (((byte *) dst_e) - ((byte *) st->entry)) / elemsize;
+ int32 src_i = dst_i + n;
+ hash_hash_t hash;
+ int32 skip;
+ int32 bytes;
+
+ while (dst_e != src_e) {
+ if (src_e != end_e) {
+ struct hash_entry *cp_e = src_e;
+ int32 save_dst_i = dst_i;
+ while (cp_e != end_e && (hash = cp_e->hash) != HASH_NIL &&
+ ((hash >> shift) & index_mask) <= dst_i) {
+ cp_e = HASH_OFFSET (cp_e, elemsize);
+ dst_i++;
+ }
+ bytes = ((byte *) cp_e) - (byte *) src_e;
+ memmove (dst_e, src_e, bytes);
+ dst_e = HASH_OFFSET (dst_e, bytes);
+ src_e = cp_e;
+ src_i += dst_i - save_dst_i;
+ if (src_e != end_e && (hash = src_e->hash) != HASH_NIL) {
+ skip = ((hash >> shift) & index_mask) - dst_i;
+ } else {
+ skip = src_i - dst_i;
+ }
+ } else {
+ skip = src_i - dst_i;
+ }
+ bytes = skip * elemsize;
+ memset (dst_e, HASH_NIL_MEMSET, bytes);
+ dst_e = HASH_OFFSET (dst_e, bytes);
+ dst_i += skip;
+ }
+}
+
+static int32
+hash_insert_internal (struct hash_subtable **pst, int32 flags, hash_hash_t hash,
+ struct hash *h, void *data, void **pres);
+
+static void
+hash_conv (struct hash *h,
+ struct hash_subtable *st, int32 flags,
+ hash_hash_t hash,
+ struct hash_entry *e)
+{
+ int32 new_flags = (flags + HASH_MAKE_USED (st->power)) | HASH_REHASH;
+ int32 shift = HASH_BITS - HASH_USED (new_flags);
+ hash_hash_t prefix_mask = (-(hash_hash_t)1) << shift;
+ int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
+ void *dummy_result;
+ struct hash_entry *de;
+ int32 index_mask = (1 << st->power) - 1;
+ hash_hash_t e_hash;
+ struct hash_entry *pe = HASH_OFFSET (e, -elemsize);
+
+ while (e != st->entry && (e_hash = pe->hash) != HASH_NIL && (e_hash & HASH_MASK) != HASH_SUBHASH) {
+ e = pe;
+ pe = HASH_OFFSET (pe, -elemsize);
+ }
+
+ de = e;
+ while (e != st->end &&
+ (e_hash = e->hash) != HASH_NIL &&
+ (e_hash & HASH_MASK) != HASH_SUBHASH) {
+ struct hash_entry *target_e = HASH_OFFSET (st->entry, ((e_hash >> shift) & index_mask) * elemsize);
+ struct hash_entry *ne = HASH_OFFSET (e, elemsize);
+ hash_hash_t current = e_hash & prefix_mask;
+ if (de < target_e) {
+ memset (de, HASH_NIL_MEMSET, ((byte *) target_e) - (byte *) de);
+ de = target_e;
+ }
+ if ((hash & prefix_mask) == current ||
+ (ne != st->end && (e_hash = ne->hash) != HASH_NIL &&
+ (e_hash & prefix_mask) == current)) {
+ struct hash_subtable *new_st = hash_subtable_new (h, 1, HASH_USED (new_flags));
+ int32 rc = hash_insert_internal (&new_st, new_flags, e->hash, h, e->data, &dummy_result);
+ assert (rc == 0);
+ memcpy(dummy_result, e->data, h->datasize);
+ e = ne;
+ while (e != st->end && (e_hash = e->hash) != HASH_NIL && (e_hash & prefix_mask) == current) {
+ assert ((e_hash & HASH_MASK) != HASH_SUBHASH);
+ rc = hash_insert_internal (&new_st, new_flags, e_hash, h, e->data, &dummy_result);
+ assert (rc == 0);
+ memcpy(dummy_result, e->data, h->datasize);
+ e = HASH_OFFSET (e, elemsize);
+ }
+ memset (de->data, HASH_NIL_MEMSET, h->datasize);
+ *(struct hash_subtable **)de->data = new_st;
+ de->hash = current | HASH_SUBHASH;
+ } else {
+ if (e != de) {
+ memcpy (de, e, elemsize);
+ }
+ e = HASH_OFFSET (e, elemsize);
+ }
+ de = HASH_OFFSET (de, elemsize);
+ }
+ if (e != de) {
+ hash_remove_n (st, de, (((byte *) e) - (byte *) de) / elemsize);
+ }
+}
+
+static void
+hash_grow (struct hash *h, struct hash_subtable **pst, int32 flags)
+{
+ struct hash_subtable *old_st = *pst;
+ int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
+ *pst = hash_subtable_new (h, old_st->power + 1, HASH_USED (flags));
+ struct hash_entry *end_e = old_st->end;
+ struct hash_entry *e;
+ void *dummy_result;
+ int32 used = 0;
+
+ flags |= HASH_REHASH;
+ for (e = old_st->entry; e != end_e; e = HASH_OFFSET (e, elemsize)) {
+ hash_hash_t hash = e->hash;
+ if (hash != HASH_NIL) {
+ int32 rc = hash_insert_internal (pst, flags, e->hash, h, e->data, &dummy_result);
+ assert (rc == 0);
+ memcpy(dummy_result, e->data, h->datasize);
+ used++;
+ }
+ }
+ free (old_st);
+}
+
+int32
+hash_lookup (struct hash *h, void *data, void **pres)
+{
+ int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
+ hash_hash_t hash = (*h->data_hash) (h->keysize, data) & ~HASH_MASK;
+ struct hash_subtable *st = h->st;
+ int32 used = 0;
+ hash_hash_t e_hash;
+ struct hash_entry *e;
+ struct hash_entry *end_e;
+
+ hash += HASH_ADJUST (hash);
+ for (;;) {
+ int32 shift = HASH_BITS - (st->power + used);
+ int32 index_mask = (1 << st->power) - 1;
+ int32 i = (hash >> shift) & index_mask; /* i is the natural position of hash */
+
+ e = HASH_OFFSET (st->entry, i * elemsize); /* e points to element i */
+ e_hash = e->hash;
+ if ((e_hash & HASH_MASK) != HASH_SUBHASH) { /* a subtable */
+ break;
+ }
+ used += st->power;
+ st = *(struct hash_subtable **)e->data;
+ }
+ end_e = HASH_OFFSET (e, st->limit_bytes);
+ while (e != end_e && (e_hash = e->hash) != HASH_NIL && e_hash < hash) {
+ e = HASH_OFFSET (e, elemsize);
+ }
+ while (e != end_e && ((e_hash = e->hash) ^ hash) < HASH_SUBHASH) {
+ if (HASH_DATA_EQ (h, data, e->data)) { /* a match */
+ *pres = e->data;
+ return (1);
+ }
+ e = HASH_OFFSET (e, elemsize);
+ }
+ USED(e_hash);
+ *pres = 0;
+ return (0);
+}
+
+int32
+hash_remove (struct hash *h, void *data, void *arg)
+{
+ int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
+ hash_hash_t hash = (*h->data_hash) (h->keysize, data) & ~HASH_MASK;
+ struct hash_subtable *st = h->st;
+ int32 used = 0;
+ hash_hash_t e_hash;
+ struct hash_entry *e;
+ struct hash_entry *end_e;
+
+ hash += HASH_ADJUST (hash);
+ for (;;) {
+ int32 shift = HASH_BITS - (st->power + used);
+ int32 index_mask = (1 << st->power) - 1;
+ int32 i = (hash >> shift) & index_mask; /* i is the natural position of hash */
+
+ e = HASH_OFFSET (st->entry, i * elemsize); /* e points to element i */
+ e_hash = e->hash;
+ if ((e_hash & HASH_MASK) != HASH_SUBHASH) { /* a subtable */
+ break;
+ }
+ used += st->power;
+ st = *(struct hash_subtable **)e->data;
+ }
+ end_e = HASH_OFFSET (e, st->limit_bytes);
+ while (e != end_e && (e_hash = e->hash) != HASH_NIL && e_hash < hash) {
+ e = HASH_OFFSET (e, elemsize);
+ }
+ while (e != end_e && ((e_hash = e->hash) ^ hash) < HASH_SUBHASH) {
+ if (HASH_DATA_EQ (h, data, e->data)) { /* a match */
+ (*h->data_del) (h->keysize, arg, e->data);
+ hash_remove_n (st, e, 1);
+ h->count--;
+ return (1);
+ }
+ e = HASH_OFFSET (e, elemsize);
+ }
+ USED(e_hash);
+ return (0);
+}
+
+static int32
+hash_insert_internal (struct hash_subtable **pst, int32 flags, hash_hash_t hash,
+ struct hash *h, void *data, void **pres)
+{
+ int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
+
+ if ((flags & HASH_REHASH) == 0) {
+ hash += HASH_ADJUST (hash);
+ hash &= ~HASH_MASK;
+ }
+ for (;;) {
+ struct hash_subtable *st = *pst;
+ int32 shift = HASH_BITS - (st->power + HASH_USED (flags));
+ int32 index_mask = (1 << st->power) - 1;
+ int32 i = (hash >> shift) & index_mask; /* i is the natural position of hash */
+ struct hash_entry *start_e =
+ HASH_OFFSET (st->entry, i * elemsize); /* start_e is the pointer to element i */
+ struct hash_entry *e = start_e; /* e is going to range over [start_e, end_e) */
+ struct hash_entry *end_e;
+ hash_hash_t e_hash = e->hash;
+
+ if ((e_hash & HASH_MASK) == HASH_SUBHASH) { /* a subtable */
+ pst = (struct hash_subtable **) e->data;
+ flags += HASH_MAKE_USED (st->power);
+ continue;
+ }
+ end_e = HASH_OFFSET (start_e, st->limit_bytes);
+ while (e != end_e && (e_hash = e->hash) != HASH_NIL && e_hash < hash) {
+ e = HASH_OFFSET (e, elemsize);
+ i++;
+ }
+ if (e != end_e && e_hash != HASH_NIL) {
+ /* ins_e ranges over the elements that may match */
+ struct hash_entry *ins_e = e;
+ int32 ins_i = i;
+ hash_hash_t ins_e_hash;
+ while (ins_e != end_e && ((e_hash = ins_e->hash) ^ hash) < HASH_SUBHASH) {
+ if (HASH_DATA_EQ (h, data, ins_e->data)) { /* a match */
+ *pres = ins_e->data;
+ return (1);
+ }
+ assert (e_hash != hash || (flags & HASH_REHASH) == 0);
+ hash += (e_hash == hash); /* adjust hash if it collides */
+ ins_e = HASH_OFFSET (ins_e, elemsize);
+ ins_i++;
+ if (e_hash <= hash) { /* set e to insertion point */
+ e = ins_e;
+ i = ins_i;
+ }
+ }
+ /* set ins_e to the insertion point for the new element */
+ ins_e = e;
+ ins_i = i;
+ ins_e_hash = 0;
+ /* move ins_e to point at the end of the contiguous block, but
+ stop if any element can't be moved by one up */
+ while (ins_e != st->end && (ins_e_hash = ins_e->hash) != HASH_NIL &&
+ ins_i + 1 - ((ins_e_hash >> shift) & index_mask) < st->max_probes &&
+ (ins_e_hash & HASH_MASK) != HASH_SUBHASH) {
+ ins_e = HASH_OFFSET (ins_e, elemsize);
+ ins_i++;
+ }
+ if (e == end_e || ins_e == st->end || ins_e_hash != HASH_NIL) {
+ e = end_e; /* can't insert; must grow or convert to subtable */
+ } else { /* make space for element */
+ memmove (HASH_OFFSET (e, elemsize), e, ((byte *) ins_e) - (byte *) e);
+ }
+ }
+ if (e != end_e) {
+ e->hash = hash;
+ *pres = e->data;
+ return (0);
+ }
+ h->changes++;
+ if (st->power < h->max_power) {
+ hash_grow (h, pst, flags);
+ } else {
+ hash_conv (h, st, flags, hash, start_e);
+ }
+ }
+}
+
+int32
+hash_insert (struct hash *h, void *data, void **pres)
+{
+ int32 rc = hash_insert_internal (&h->st, 0, (*h->data_hash) (h->keysize, data), h, data, pres);
+
+ h->count += (rc == 0); /* increment count if element didn't previously exist */
+ return (rc);
+}
+
+uint32
+hash_count (struct hash *h)
+{
+ return (h->count);
+}
+
+static void
+iter_restart (struct hash_iter *it, struct hash_subtable *st, int32 used)
+{
+ int32 elemsize = it->elemsize;
+ hash_hash_t last_hash = it->last_hash;
+ struct hash_entry *e;
+ hash_hash_t e_hash;
+ struct hash_iter_sub *sub = &it->subtable_state[it->i];
+ struct hash_entry *end;
+
+ for (;;) {
+ int32 shift = HASH_BITS - (st->power + used);
+ int32 index_mask = (1 << st->power) - 1;
+ int32 i = (last_hash >> shift) & index_mask;
+
+ end = st->end;
+ e = HASH_OFFSET (st->entry, i * elemsize);
+ sub->start = st->entry;
+ sub->end = end;
+
+ if ((e->hash & HASH_MASK) != HASH_SUBHASH) {
+ break;
+ }
+ sub->e = HASH_OFFSET (e, elemsize);
+ sub = &it->subtable_state[++(it->i)];
+ used += st->power;
+ st = *(struct hash_subtable **)e->data;
+ }
+ while (e != end && ((e_hash = e->hash) == HASH_NIL || e_hash <= last_hash)) {
+ e = HASH_OFFSET (e, elemsize);
+ }
+ sub->e = e;
+}
+
+void *
+hash_next (struct hash_iter *it)
+{
+ int32 elemsize = it->elemsize;
+ struct hash_iter_sub *sub = &it->subtable_state[it->i];
+ struct hash_entry *e = sub->e;
+ struct hash_entry *end = sub->end;
+ hash_hash_t e_hash = 0;
+
+ if (it->changes != it->h->changes) { /* hash table's structure changed; recompute */
+ it->changes = it->h->changes;
+ it->i = 0;
+ iter_restart (it, it->h->st, 0);
+ sub = &it->subtable_state[it->i];
+ e = sub->e;
+ end = sub->end;
+ }
+ if (e != sub->start && it->last_hash != HASH_OFFSET (e, -elemsize)->hash) {
+ struct hash_entry *start = HASH_OFFSET (e, -(elemsize * it->h->max_probes));
+ struct hash_entry *pe = HASH_OFFSET (e, -elemsize);
+ hash_hash_t last_hash = it->last_hash;
+ if (start < sub->start) {
+ start = sub->start;
+ }
+ while (e != start && ((e_hash = pe->hash) == HASH_NIL || last_hash < e_hash)) {
+ e = pe;
+ pe = HASH_OFFSET (pe, -elemsize);
+ }
+ while (e != end && ((e_hash = e->hash) == HASH_NIL || e_hash <= last_hash)) {
+ e = HASH_OFFSET (e, elemsize);
+ }
+ }
+
+ for (;;) {
+ while (e != end && (e_hash = e->hash) == HASH_NIL) {
+ e = HASH_OFFSET (e, elemsize);
+ }
+ if (e == end) {
+ if (it->i == 0) {
+ it->last_hash = HASH_OFFSET (e, -elemsize)->hash;
+ sub->e = e;
+ return (0);
+ } else {
+ it->i--;
+ sub = &it->subtable_state[it->i];
+ e = sub->e;
+ end = sub->end;
+ }
+ } else if ((e_hash & HASH_MASK) != HASH_SUBHASH) {
+ it->last_hash = e->hash;
+ sub->e = HASH_OFFSET (e, elemsize);
+ return (e->data);
+ } else {
+ struct hash_subtable *st =
+ *(struct hash_subtable **)e->data;
+ sub->e = HASH_OFFSET (e, elemsize);
+ it->i++;
+ assert (it->i < sizeof (it->subtable_state) /
+ sizeof (it->subtable_state[0]));
+ sub = &it->subtable_state[it->i];
+ sub->e = e = st->entry;
+ sub->start = st->entry;
+ sub->end = end = st->end;
+ }
+ }
+}
+
+void
+hash_iter_init (struct hash *h, struct hash_iter *it)
+{
+ it->elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
+ it->changes = h->changes;
+ it->i = 0;
+ it->h = h;
+ it->last_hash = 0;
+ it->subtable_state[0].e = h->st->entry;
+ it->subtable_state[0].start = h->st->entry;
+ it->subtable_state[0].end = h->st->end;
+}
+
+static void
+clean_st (struct hash_subtable *st, int32 *slots, int32 *used)
+{
+ int32 elemsize = st->datasize + offsetof (struct hash_entry, data[0]);
+ struct hash_entry *e = st->entry;
+ struct hash_entry *end = st->end;
+ int32 lslots = (((byte *) end) - (byte *) e) / elemsize;
+ int32 lused = 0;
+
+ while (e != end) {
+ hash_hash_t hash = e->hash;
+ if ((hash & HASH_MASK) == HASH_SUBHASH) {
+ clean_st (*(struct hash_subtable **)e->data, slots, used);
+ } else {
+ lused += (hash != HASH_NIL);
+ }
+ e = HASH_OFFSET (e, elemsize);
+ }
+ free (st);
+ *slots += lslots;
+ *used += lused;
+}
+
+void
+hash_destroy (struct hash *h)
+{
+ int32 slots = 0;
+ int32 used = 0;
+
+ clean_st (h->st, &slots, &used);
+ free (h);
+}
+
+static void
+hash_visit_internal (struct hash_subtable *st,
+ int32 used, int32 level,
+ void (*data_visit) (void *arg, int32 level, void *data),
+ void *arg)
+{
+ int32 elemsize = st->datasize + offsetof (struct hash_entry, data[0]);
+ struct hash_entry *e = st->entry;
+ int32 shift = HASH_BITS - (used + st->power);
+ int32 i = 0;
+
+ while (e != st->end) {
+ int32 index = ((e->hash >> (shift - 1)) >> 1) & ((1 << st->power) - 1);
+ if ((e->hash & HASH_MASK) == HASH_SUBHASH) {
+ (*data_visit) (arg, level, e->data);
+ hash_visit_internal (*(struct hash_subtable **)e->data,
+ used + st->power, level + 1, data_visit, arg);
+ } else {
+ (*data_visit) (arg, level, e->data);
+ }
+ if (e->hash != HASH_NIL) {
+ assert (i < index + st->max_probes);
+ assert (index <= i);
+ }
+ e = HASH_OFFSET (e, elemsize);
+ i++;
+ }
+}
+
+void
+hash_visit (struct hash *h, void (*data_visit) (void *arg, int32 level, void *data), void *arg)
+{
+ hash_visit_internal (h->st, 0, 0, data_visit, arg);
+}
+
+//
+/// interfaces to go runtime
+//
+
+static void
+donothing(uint32 s, void *a, void *b)
+{
+ USED(s);
+ USED(a);
+ USED(b);
+}
+
+typedef struct hash Hmap;
+static int32 debug = 0;
+
+// newmap(keysize uint32, valsize uint32,
+// keyalg uint32, valalg uint32,
+// hint uint32) (hmap *map[any]any);
+void
+sys·newmap(uint32 keysize, uint32 valsize,
+ uint32 keyalg, uint32 valalg, uint32 hint,
+ Hmap* ret)
+{
+ Hmap *h;
+
+ if(keyalg >= nelem(algarray) || algarray[keyalg].hash == nohash) {
+ printf("map(keyalg=%d)\n", keyalg);
+ throw("sys·newmap: unsupported map key type");
+ }
+
+ if(valalg >= nelem(algarray)) {
+ printf("map(valalg=%d)\n", valalg);
+ throw("sys·newmap: unsupported map value type");
+ }
+
+ h = mal(sizeof(*h));
+
+ // align value inside data so that mark-sweep gc can find it.
+ // might remove in the future and just assume datavo == keysize.
+ h->datavo = keysize;
+ if(valsize >= sizeof(void*))
+ h->datavo = rnd(keysize, sizeof(void*));
+
+ hash_init(h, h->datavo+valsize,
+ algarray[keyalg].hash,
+ algarray[keyalg].equal,
+ donothing,
+ hint);
+
+ h->keysize = keysize;
+ h->valsize = valsize;
+ h->keyalg = &algarray[keyalg];
+ h->valalg = &algarray[valalg];
+
+ // these calculations are compiler dependent.
+ // figure out offsets of map call arguments.
+ h->ko = rnd(sizeof(h), keysize);
+ h->vo = rnd(h->ko+keysize, valsize);
+ h->po = rnd(h->vo+valsize, 1);
+
+ ret = h;
+ FLUSH(&ret);
+
+ if(debug) {
+ prints("newmap: map=");
+ sys·printpointer(h);
+ prints("; keysize=");
+ sys·printint(keysize);
+ prints("; valsize=");
+ sys·printint(valsize);
+ prints("; keyalg=");
+ sys·printint(keyalg);
+ prints("; valalg=");
+ sys·printint(valalg);
+ prints("; ko=");
+ sys·printint(h->ko);
+ prints("; vo=");
+ sys·printint(h->vo);
+ prints("; po=");
+ sys·printint(h->po);
+ prints("\n");
+ }
+}
+
+// mapaccess1(hmap *map[any]any, key any) (val any);
+void
+sys·mapaccess1(Hmap *h, ...)
+{
+ byte *ak, *av;
+ byte *res;
+ int32 hit;
+
+ ak = (byte*)&h + h->ko;
+ av = (byte*)&h + h->vo;
+
+ res = nil;
+ hit = hash_lookup(h, ak, (void**)&res);
+ if(!hit)
+ throw("sys·mapaccess1: key not in map");
+ h->valalg->copy(h->valsize, av, res+h->datavo);
+
+ if(debug) {
+ prints("sys·mapaccess1: map=");
+ sys·printpointer(h);
+ prints("; key=");
+ h->keyalg->print(h->keysize, ak);
+ prints("; val=");
+ h->valalg->print(h->valsize, av);
+ prints("; hit=");
+ sys·printint(hit);
+ prints("; res=");
+ sys·printpointer(res);
+ prints("\n");
+ }
+}
+
+// mapaccess2(hmap *map[any]any, key any) (val any, pres bool);
+void
+sys·mapaccess2(Hmap *h, ...)
+{
+ byte *ak, *av, *ap;
+ byte *res;
+ int32 hit;
+
+ ak = (byte*)&h + h->ko;
+ av = (byte*)&h + h->vo;
+ ap = (byte*)&h + h->po;
+
+ res = nil;
+ hit = hash_lookup(h, ak, (void**)&res);
+ if(!hit) {
+ *ap = false;
+ h->valalg->copy(h->valsize, av, nil);
+ } else {
+ *ap = true;
+ h->valalg->copy(h->valsize, av, res+h->datavo);
+ }
+
+ if(debug) {
+ prints("sys·mapaccess2: map=");
+ sys·printpointer(h);
+ prints("; key=");
+ h->keyalg->print(h->keysize, ak);
+ prints("; val=");
+ h->valalg->print(h->valsize, av);
+ prints("; hit=");
+ sys·printint(hit);
+ prints("; res=");
+ sys·printpointer(res);
+ prints("; pres=");
+ sys·printbool(*ap);
+ prints("\n");
+ }
+}
+
+static void
+mapassign(Hmap *h, byte *ak, byte *av)
+{
+ byte *res;
+ int32 hit;
+
+ res = nil;
+ hit = hash_insert(h, ak, (void**)&res);
+ h->keyalg->copy(h->keysize, res, ak);
+ h->valalg->copy(h->valsize, res+h->datavo, av);
+
+ if(debug) {
+ prints("mapassign: map=");
+ sys·printpointer(h);
+ prints("; key=");
+ h->keyalg->print(h->keysize, ak);
+ prints("; val=");
+ h->valalg->print(h->valsize, av);
+ prints("; hit=");
+ sys·printint(hit);
+ prints("; res=");
+ sys·printpointer(res);
+ prints("\n");
+ }
+}
+
+// mapassign1(hmap *map[any]any, key any, val any);
+void
+sys·mapassign1(Hmap *h, ...)
+{
+ byte *ak, *av;
+
+ ak = (byte*)&h + h->ko;
+ av = (byte*)&h + h->vo;
+
+ mapassign(h, ak, av);
+}
+
+// mapassign2(hmap *map[any]any, key any, val any, pres bool);
+void
+sys·mapassign2(Hmap *h, ...)
+{
+ byte *ak, *av, *ap;
+ byte *res;
+ int32 hit;
+
+ ak = (byte*)&h + h->ko;
+ av = (byte*)&h + h->vo;
+ ap = (byte*)&h + h->po;
+
+ if(*ap == true) {
+ // assign
+ mapassign(h, ak, av);
+ return;
+ }
+
+ // delete
+ hit = hash_remove(h, ak, (void**)&res);
+
+ if(debug) {
+ prints("mapassign2: map=");
+ sys·printpointer(h);
+ prints("; key=");
+ h->keyalg->print(h->keysize, ak);
+ prints("; hit=");
+ sys·printint(hit);
+ prints("; res=");
+ sys·printpointer(res);
+ prints("\n");
+ }
+}
+
+// mapiterinit(hmap *map[any]any, hiter *any);
+void
+sys·mapiterinit(Hmap *h, struct hash_iter *it)
+{
+ if(h == nil) {
+ it->data = nil;
+ return;
+ }
+ hash_iter_init(h, it);
+ it->data = hash_next(it);
+ if(debug) {
+ prints("sys·mapiterinit: map=");
+ sys·printpointer(h);
+ prints("; iter=");
+ sys·printpointer(it);
+ prints("; data=");
+ sys·printpointer(it->data);
+ prints("\n");
+ }
+}
+
+// mapiternext(hiter *any);
+void
+sys·mapiternext(struct hash_iter *it)
+{
+ it->data = hash_next(it);
+ if(debug) {
+ prints("sys·mapiternext: iter=");
+ sys·printpointer(it);
+ prints("; data=");
+ sys·printpointer(it->data);
+ prints("\n");
+ }
+}
+
+// mapiter1(hiter *any) (key any);
+void
+sys·mapiter1(struct hash_iter *it, ...)
+{
+ Hmap *h;
+ byte *ak, *res;
+
+ h = it->h;
+ ak = (byte*)&it + h->ko;
+
+ res = it->data;
+ if(res == nil)
+ throw("sys·mapiter2: key:val nil pointer");
+
+ h->keyalg->copy(h->keysize, ak, res);
+
+ if(debug) {
+ prints("mapiter2: iter=");
+ sys·printpointer(it);
+ prints("; map=");
+ sys·printpointer(h);
+ prints("\n");
+ }
+}
+
+// mapiter2(hiter *any) (key any, val any);
+void
+sys·mapiter2(struct hash_iter *it, ...)
+{
+ Hmap *h;
+ byte *ak, *av, *res;
+
+ h = it->h;
+ ak = (byte*)&it + h->ko;
+ av = (byte*)&it + h->vo;
+
+ res = it->data;
+ if(res == nil)
+ throw("sys·mapiter2: key:val nil pointer");
+
+ h->keyalg->copy(h->keysize, ak, res);
+ h->valalg->copy(h->valsize, av, res+h->datavo);
+
+ if(debug) {
+ prints("mapiter2: iter=");
+ sys·printpointer(it);
+ prints("; map=");
+ sys·printpointer(h);
+ prints("\n");
+ }
+}
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/hashmap.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/hashmap.h Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,161 @@
+// Copyright 2009 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.
+
+
+/* A hash table.
+ Example, hashing nul-terminated char*s:
+ hash_hash_t str_hash (void *v) {
+ char *s;
+ hash_hash_t hash = 0;
+ for (s = *(char **)v; *s != 0; s++) {
+ hash = (hash ^ *s) * 2654435769U;
+ }
+ return (hash);
+ }
+ int str_eq (void *a, void *b) {
+ return (strcmp (*(char **)a, *(char **)b) == 0);
+ }
+ void str_del (void *arg, void *data) {
+ *(char **)arg = *(char **)data;
+ }
+
+ struct hash *h = hash_new (sizeof (char *), &str_hash, &str_eq, &str_del, 3, 12, 15);
+ ... 3=> 2**3 entries initial size
+ ... 12=> 2**12 entries before sprouting sub-tables
+ ... 15=> number of adjacent probes to attempt before growing
+
+ Example lookup:
+ char *key = "foobar";
+ char **result_ptr;
+ if (hash_lookup (h, &key, (void **) &result_ptr)) {
+ printf ("found in table: %s\n", *result_ptr);
+ } else {
+ printf ("not found in table\n");
+ }
+
+ Example insertion:
+ char *key = strdup ("foobar");
+ char **result_ptr;
+ if (hash_lookup (h, &key, (void **) &result_ptr)) {
+ printf ("found in table: %s\n", *result_ptr);
+ printf ("to overwrite, do *result_ptr = key\n");
+ } else {
+ printf ("not found in table; inserted as %s\n", *result_ptr);
+ assert (*result_ptr == key);
+ }
+
+ Example deletion:
+ char *key = "foobar";
+ char *result;
+ if (hash_remove (h, &key, &result)) {
+ printf ("key found and deleted from table\n");
+ printf ("called str_del (&result, data) to copy data to result: %s\n", result);
+ } else {
+ printf ("not found in table\n");
+ }
+
+ Example iteration over the elements of *h:
+ char **data;
+ struct hash_iter it;
+ hash_iter_init (h, &it);
+ for (data = hash_next (&it); data != 0; data = hash_next (&it)) {
+ printf ("%s\n", *data);
+ }
+ */
+
+#define malloc mal
+#define free(a) USED(a)
+#define offsetof(s,m) (uint32)(&(((s*)0)->m))
+#define memset(a,b,c) sys·memclr((byte*)(a), (uint32)(c))
+#define memmove(a,b,c) mmov((byte*)(a),(byte*)(b),(uint32)(c))
+#define memcpy(a,b,c) mcpy((byte*)(a),(byte*)(b),(uint32)(c))
+#define assert(a) if(!(a)) throw("assert")
+
+struct hash; /* opaque */
+struct hash_subtable; /* opaque */
+struct hash_entry; /* opaque */
+
+typedef uintptr uintptr_t;
+typedef uintptr_t hash_hash_t;
+
+struct hash_iter {
+ uint8* data; /* returned from next */
+ int32 elemsize; /* size of elements in table */
+ int32 changes; /* number of changes observed last time */
+ int32 i; /* stack pointer in subtable_state */
+ hash_hash_t last_hash; /* last hash value returned */
+ struct hash *h; /* the hash table */
+ struct hash_iter_sub {
+ struct hash_entry *e; /* pointer into subtable */
+ struct hash_entry *start; /* start of subtable */
+ struct hash_entry *end; /* end of subtable */
+ } subtable_state[4]; /* Should be large enough unless the hashing is
+ so bad that many distinct data values hash
+ to the same hash value. */
+};
+
+/* Return a hashtable h 2**init_power empty entries, each with
+ "datasize" data bytes.
+ (*data_hash)(a) should return the hash value of data element *a.
+ (*data_eq)(a,b) should return whether the data at "a" and the data at "b"
+ are equal.
+ (*data_del)(arg, a) will be invoked when data element *a is about to be removed
+ from the table. "arg" is the argument passed to "hash_remove()".
+
+ Growing is accomplished by resizing if the current tables size is less than
+ a threshold, and by adding subtables otherwise. hint should be set
+ the expected maximum size of the table.
+ "datasize" should be in [sizeof (void*), ..., 255]. If you need a
+ bigger "datasize", store a pointer to another piece of memory. */
+
+//struct hash *hash_new (int32 datasize,
+// hash_hash_t (*data_hash) (void *),
+// int32 (*data_eq) (void *, void *),
+// void (*data_del) (void *, void *),
+// int64 hint);
+
+/* Lookup *data in *h. If the data is found, return 1 and place a pointer to
+ the found element in *pres. Otherwise return 0 and place 0 in *pres. */
+int32 hash_lookup (struct hash *h, void *data, void **pres);
+
+/* Lookup *data in *h. If the data is found, execute (*data_del) (arg, p)
+ where p points to the data in the table, then remove it from *h and return
+ 1. Otherwise return 0. */
+int32 hash_remove (struct hash *h, void *data, void *arg);
+
+/* Lookup *data in *h. If the data is found, return 1, and place a pointer
+ to the found element in *pres. Otherwise, return 0, allocate a region
+ for the data to be inserted, and place a pointer to the inserted element
+ in *pres; it is the caller's responsibility to copy the data to be
+ inserted to the pointer returned in *pres in this case.
+
+ If using garbage collection, it is the caller's responsibility to
+ add references for **pres if HASH_ADDED is returned. */
+int32 hash_insert (struct hash *h, void *data, void **pres);
+
+/* Return the number of elements in the table. */
+uint32 hash_count (struct hash *h);
+
+/* The following call is useful only if not using garbage collection on the
+ table.
+ Remove all sub-tables associated with *h.
+ This undoes the effects of hash_init().
+ If other memory pointed to by user data must be freed, the caller is
+ responsible for doiing do by iterating over *h first; see
+ hash_iter_init()/hash_next(). */
+void hash_destroy (struct hash *h);
+
+/*----- iteration -----*/
+
+/* Initialize *it from *h. */
+void hash_iter_init (struct hash *h, struct hash_iter *it);
+
+/* Return the next used entry in the table which which *it was initialized. */
+void *hash_next (struct hash_iter *it);
+
+/*---- test interface ----*/
+/* Call (*data_visit) (arg, level, data) for every data entry in the table,
+ whether used or not. "level" is the subtable level, 0 means first level. */
+/* TESTING ONLY: DO NOT USE THIS ROUTINE IN NORMAL CODE */
+void hash_visit (struct hash *h, void (*data_visit) (void *arg, int32 level, void *data), void *arg);
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/iface.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/iface.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,906 @@
+// Copyright 2009 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.
+
+#include "runtime.h"
+
+int32 iface_debug = 0;
+
+typedef struct Sigt Sigt;
+typedef struct Sigi Sigi;
+typedef struct Itype Itype;
+
+/*
+ * the layout of Iface, Sigt and Sigi are known to the compiler
+ */
+struct Sigt
+{
+ byte* name; // name of basic type
+ Sigt* link; // for linking into hash tables
+ uint32 thash; // hash of type
+ uint32 mhash; // hash of methods
+ uint16 width; // width of base type in bytes
+ uint16 alg; // algorithm
+ // note: on amd64 there is a 32-bit pad here.
+ struct {
+ byte* fname;
+ uint32 fhash; // hash of type
+ uint32 offset; // offset of substruct
+ void (*fun)(void);
+ } meth[1]; // one or more - last name is nil
+};
+
+struct Sigi
+{
+ byte* name;
+ uint32 hash;
+ uint32 size; // number of methods
+ struct {
+ byte* fname;
+ uint32 fhash;
+ uint32 perm; // location of fun in Sigt
+ } meth[1]; // [size+1] - last name is nil
+};
+
+struct Itype
+{
+ Sigi* sigi;
+ Sigt* sigt;
+ Itype* link;
+ int32 bad;
+ int32 unused;
+ void (*fun[])(void);
+};
+
+static Iface niliface;
+static Eface nileface;
+
+static Itype* hash[1009];
+static Lock ifacelock;
+
+Sigi sigi·empty[2] = { (byte*)"interface { }" };
+
+static void
+printsigi(Sigi *si)
+{
+ int32 i;
+ byte *name;
+
+ sys·printpointer(si);
+ prints("{");
+ prints((int8*)si->name);
+ prints(":");
+ for(i=0;; i++) {
+ name = si->meth[i].fname;
+ if(name == nil)
+ break;
+ prints("[");
+ sys·printint(i);
+ prints("]\"");
+ prints((int8*)name);
+ prints("\"");
+ sys·printint(si->meth[i].fhash%999);
+ prints("/");
+ sys·printint(si->meth[i].perm);
+ }
+ prints("}");
+}
+
+static void
+printsigt(Sigt *st)
+{
+ int32 i;
+ byte *name;
+
+ sys·printpointer(st);
+ prints("{");
+ prints((int8*)st->name);
+ prints(":");
+ sys·printint(st->thash%999); // type hash
+ prints(",");
+ sys·printint(st->mhash%999); // method hash
+ prints(",");
+ sys·printint(st->width); // width
+ prints(",");
+ sys·printint(st->alg); // algorithm
+ for(i=0;; i++) {
+ name = st->meth[i].fname;
+ if(name == nil)
+ break;
+ prints("[");
+ sys·printint(i);
+ prints("]\"");
+ prints((int8*)name);
+ prints("\"");
+ sys·printint(st->meth[i].fhash%999);
+ prints("/");
+ sys·printint(st->meth[i].offset);
+ prints("/");
+ sys·printpointer(st->meth[i].fun);
+ }
+ prints("}");
+}
+
+static void
+printiface(Iface i)
+{
+ prints("(");
+ sys·printpointer(i.type);
+ prints(",");
+ sys·printpointer(i.data);
+ prints(")");
+}
+
+static void
+printeface(Eface e)
+{
+ prints("(");
+ sys·printpointer(e.type);
+ prints(",");
+ sys·printpointer(e.data);
+ prints(")");
+}
+
+static Itype*
+itype(Sigi *si, Sigt *st, int32 canfail)
+{
+ int32 locked;
+ int32 nt, ni;
+ uint32 ihash, h;
+ byte *sname, *iname;
+ Itype *m;
+
+ if(si->size == 0)
+ throw("internal error - misuse of itype");
+
+ // easy case
+ if(st->meth[0].fname == nil) {
+ if(canfail)
+ return nil;
+ iname = si->meth[0].fname;
+ goto throw1;
+ }
+
+ // compiler has provided some good hash codes for us.
+ h = 0;
+ if(si)
+ h += si->hash;
+ if(st) {
+ h += st->thash;
+ h += st->mhash;
+ }
+
+ h %= nelem(hash);
+
+ // look twice - once without lock, once with.
+ // common case will be no lock contention.
+ for(locked=0; locked<2; locked++) {
+ if(locked)
+ lock(&ifacelock);
+ for(m=hash[h]; m!=nil; m=m->link) {
+ if(m->sigi == si && m->sigt == st) {
+ if(m->bad) {
+ m = nil;
+ if(!canfail) {
+ // this can only happen if the conversion
+ // was already done once using the , ok form
+ // and we have a cached negative result.
+ // the cached result doesn't record which
+ // interface function was missing, so jump
+ // down to the interface check, which will
+ // give a better error.
+ goto throw;
+ }
+ }
+ if(locked)
+ unlock(&ifacelock);
+ return m;
+ }
+ }
+ }
+
+ ni = si->size;
+ m = malloc(sizeof(*m) + ni*sizeof(m->fun[0]));
+ m->sigi = si;
+ m->sigt = st;
+
+throw:
+ nt = 0;
+ for(ni=0;; ni++) {
+ iname = si->meth[ni].fname;
+ if(iname == nil)
+ break;
+
+ // pick up next name from
+ // interface signature
+ ihash = si->meth[ni].fhash;
+
+ for(;; nt++) {
+ // pick up and compare next name
+ // from structure signature
+ sname = st->meth[nt].fname;
+ if(sname == nil) {
+ if(!canfail) {
+ throw1:
+ printf("cannot convert type %s to interface %s: missing method %s\n",
+ st->name, si->name, iname);
+ if(iface_debug) {
+ prints("interface");
+ printsigi(si);
+ prints("\ntype");
+ printsigt(st);
+ prints("\n");
+ }
+ throw("interface conversion");
+ return nil; // not reached
+ }
+ m->bad = 1;
+ m->link = hash[h];
+ hash[h] = m;
+ if(locked)
+ unlock(&ifacelock);
+ return nil;
+ }
+ if(ihash == st->meth[nt].fhash && strcmp(sname, iname) == 0)
+ break;
+ }
+ m->fun[si->meth[ni].perm] = st->meth[nt].fun;
+ }
+ m->link = hash[h];
+ hash[h] = m;
+ if(locked)
+ unlock(&ifacelock);
+
+ return m;
+}
+
+static void
+copyin(Sigt *st, void *src, void **dst)
+{
+ int32 wid, alg;
+ void *p;
+
+ wid = st->width;
+ alg = st->alg;
+
+ if(wid <= sizeof(*dst))
+ algarray[alg].copy(wid, dst, src);
+ else {
+ p = mal(wid);
+ algarray[alg].copy(wid, p, src);
+ *dst = p;
+ }
+}
+
+static void
+copyout(Sigt *st, void **src, void *dst)
+{
+ int32 wid, alg;
+
+ wid = st->width;
+ alg = st->alg;
+
+ if(wid <= sizeof(*src))
+ algarray[alg].copy(wid, dst, src);
+ else
+ algarray[alg].copy(wid, dst, *src);
+}
+
+// ifaceT2I(sigi *byte, sigt *byte, elem any) (ret any);
+#pragma textflag 7
+void
+sys·ifaceT2I(Sigi *si, Sigt *st, ...)
+{
+ byte *elem;
+ Iface *ret;
+ int32 wid;
+
+ elem = (byte*)(&st+1);
+ wid = st->width;
+ ret = (Iface*)(elem + rnd(wid, sizeof(uintptr)));
+
+ ret->type = itype(si, st, 0);
+ copyin(st, elem, &ret->data);
+}
+
+// ifaceT2E(sigt *byte, elem any) (ret any);
+#pragma textflag 7
+void
+sys·ifaceT2E(Sigt *st, ...)
+{
+ byte *elem;
+ Eface *ret;
+ int32 wid;
+
+ elem = (byte*)(&st+1);
+ wid = st->width;
+ ret = (Eface*)(elem + rnd(wid, sizeof(uintptr)));
+
+ ret->type = st;
+ copyin(st, elem, &ret->data);
+}
+
+// ifaceI2T(sigt *byte, iface any) (ret any);
+#pragma textflag 7
+void
+sys·ifaceI2T(Sigt *st, Iface i, ...)
+{
+ Itype *im;
+ byte *ret;
+
+ ret = (byte*)(&i+1);
+
+ im = i.type;
+ if(im == nil) {
+ printf("interface is nil, not %s\n", st->name);
+ throw("interface conversion");
+ }
+ if(im->sigt != st) {
+ printf("%s is %s, not %s\n", im->sigi->name, im->sigt->name, st->name);
+ throw("interface conversion");
+ }
+ copyout(st, &i.data, ret);
+}
+
+// ifaceI2T2(sigt *byte, iface any) (ret any, ok bool);
+#pragma textflag 7
+void
+sys·ifaceI2T2(Sigt *st, Iface i, ...)
+{
+ byte *ret;
+ bool *ok;
+ Itype *im;
+ int32 wid;
+
+ ret = (byte*)(&i+1);
+ wid = st->width;
+ ok = (bool*)(ret+rnd(wid, 1));
+
+ im = i.type;
+ if(im == nil || im->sigt != st) {
+ *ok = false;
+ sys·memclr(ret, wid);
+ return;
+ }
+
+ *ok = true;
+ copyout(st, &i.data, ret);
+}
+
+// ifaceE2T(sigt *byte, iface any) (ret any);
+#pragma textflag 7
+void
+sys·ifaceE2T(Sigt *st, Eface e, ...)
+{
+ Sigt *t;
+ byte *ret;
+
+ ret = (byte*)(&e+1);
+
+ t = e.type;
+ if(t == nil) {
+ printf("interface is nil, not %s\n", st->name);
+ throw("interface conversion");
+ }
+ if(t != st) {
+ printf("interface is %s, not %s\n", t->name, st->name);
+ throw("interface conversion");
+ }
+ copyout(st, &e.data, ret);
+}
+
+// ifaceE2T2(sigt *byte, iface any) (ret any, ok bool);
+#pragma textflag 7
+void
+sys·ifaceE2T2(Sigt *st, Eface e, ...)
+{
+ byte *ret;
+ bool *ok;
+ Sigt *t;
+ int32 wid;
+
+ ret = (byte*)(&e+1);
+ wid = st->width;
+ ok = (bool*)(ret+rnd(wid, 1));
+
+ t = e.type;
+ if(t != st) {
+ *ok = false;
+ sys·memclr(ret, wid);
+ return;
+ }
+
+ *ok = true;
+ copyout(st, &e.data, ret);
+}
+
+// ifaceI2E(sigi *byte, iface any) (ret any);
+// TODO(rsc): Move to back end, throw away function.
+void
+sys·ifaceI2E(Iface i, Eface ret)
+{
+ Itype *im;
+
+ ret.data = i.data;
+ im = i.type;
+ if(im == nil)
+ ret.type = nil;
+ else
+ ret.type = im->sigt;
+ FLUSH(&ret);
+}
+
+// ifaceI2I(sigi *byte, iface any) (ret any);
+// called only for implicit (no type assertion) conversions
+void
+sys·ifaceI2I(Sigi *si, Iface i, Iface ret)
+{
+ Itype *im;
+
+ im = i.type;
+ if(im == nil) {
+ // If incoming interface is uninitialized (zeroed)
+ // make the outgoing interface zeroed as well.
+ ret = niliface;
+ } else {
+ ret = i;
+ if(im->sigi != si)
+ ret.type = itype(si, im->sigt, 0);
+ }
+
+ FLUSH(&ret);
+}
+
+// ifaceI2Ix(sigi *byte, iface any) (ret any);
+// called only for explicit conversions (with type assertion).
+void
+sys·ifaceI2Ix(Sigi *si, Iface i, Iface ret)
+{
+ Itype *im;
+
+ im = i.type;
+ if(im == nil) {
+ // explicit conversions require non-nil interface value.
+ printf("interface is nil, not %s\n", si->name);
+ throw("interface conversion");
+ } else {
+ ret = i;
+ if(im->sigi != si)
+ ret.type = itype(si, im->sigt, 0);
+ }
+
+ FLUSH(&ret);
+}
+
+// ifaceI2I2(sigi *byte, iface any) (ret any, ok bool);
+void
+sys·ifaceI2I2(Sigi *si, Iface i, Iface ret, bool ok)
+{
+ Itype *im;
+
+ im = i.type;
+ if(im == nil) {
+ // If incoming interface is nil, the conversion fails.
+ ret = niliface;
+ ok = false;
+ } else {
+ ret = i;
+ ok = true;
+ if(im->sigi != si) {
+ ret.type = itype(si, im->sigt, 1);
+ if(ret.type == nil) {
+ ret = niliface;
+ ok = false;
+ }
+ }
+ }
+
+ FLUSH(&ret);
+ FLUSH(&ok);
+}
+
+// ifaceE2I(sigi *byte, iface any) (ret any);
+// Called only for explicit conversions (with type assertion).
+void
+sys·ifaceE2I(Sigi *si, Eface e, Iface ret)
+{
+ Sigt *t;
+
+ t = e.type;
+ if(t == nil) {
+ // explicit conversions require non-nil interface value.
+ printf("interface is nil, not %s\n", si->name);
+ throw("interface conversion");
+ } else {
+ ret.data = e.data;
+ ret.type = itype(si, t, 0);
+ }
+ FLUSH(&ret);
+}
+
+// ifaceE2I2(sigi *byte, iface any) (ret any, ok bool);
+void
+sys·ifaceE2I2(Sigi *si, Eface e, Iface ret, bool ok)
+{
+ Sigt *t;
+
+ t = e.type;
+ ok = true;
+ if(t == nil) {
+ // If incoming interface is nil, the conversion fails.
+ ret = niliface;
+ ok = false;
+ } else {
+ ret.data = e.data;
+ ret.type = itype(si, t, 1);
+ if(ret.type == nil) {
+ ret = niliface;
+ ok = false;
+ }
+ }
+ FLUSH(&ret);
+ FLUSH(&ok);
+}
+
+static uintptr
+ifacehash1(void *data, Sigt *sigt)
+{
+ int32 alg, wid;
+
+ if(sigt == nil)
+ return 0;
+
+ alg = sigt->alg;
+ wid = sigt->width;
+ if(algarray[alg].hash == nohash) {
+ // calling nohash will throw too,
+ // but we can print a better error.
+ printf("hash of unhashable type %s\n", sigt->name);
+ if(alg == AFAKE)
+ throw("fake interface hash");
+ throw("interface hash");
+ }
+ if(wid <= sizeof(data))
+ return algarray[alg].hash(wid, &data);
+ return algarray[alg].hash(wid, data);
+}
+
+uintptr
+ifacehash(Iface a)
+{
+ if(a.type == nil)
+ return 0;
+ return ifacehash1(a.data, a.type->sigt);
+}
+
+uintptr
+efacehash(Eface a)
+{
+ return ifacehash1(a.data, a.type);
+}
+
+static bool
+ifaceeq1(void *data1, void *data2, Sigt *sigt)
+{
+ int32 alg, wid;
+
+ alg = sigt->alg;
+ wid = sigt->width;
+
+ if(algarray[alg].equal == noequal) {
+ // calling noequal will throw too,
+ // but we can print a better error.
+ printf("comparing uncomparable type %s\n", sigt->name);
+ if(alg == AFAKE)
+ throw("fake interface compare");
+ throw("interface compare");
+ }
+
+ if(wid <= sizeof(data1))
+ return algarray[alg].equal(wid, &data1, &data2);
+ return algarray[alg].equal(wid, data1, data2);
+}
+
+bool
+ifaceeq(Iface i1, Iface i2)
+{
+ if(i1.type != i2.type)
+ return false;
+ if(i1.type == nil)
+ return true;
+ return ifaceeq1(i1.data, i2.data, i1.type->sigt);
+}
+
+bool
+efaceeq(Eface e1, Eface e2)
+{
+ if(e1.type != e2.type)
+ return false;
+ if(e1.type == nil)
+ return true;
+ return ifaceeq1(e1.data, e2.data, e1.type);
+}
+
+// ifaceeq(i1 any, i2 any) (ret bool);
+void
+sys·ifaceeq(Iface i1, Iface i2, bool ret)
+{
+ ret = ifaceeq(i1, i2);
+ FLUSH(&ret);
+}
+
+// efaceeq(i1 any, i2 any) (ret bool)
+void
+sys·efaceeq(Eface e1, Eface e2, bool ret)
+{
+ ret = efaceeq(e1, e2);
+ FLUSH(&ret);
+}
+
+// ifacethash(i1 any) (ret uint32);
+void
+sys·ifacethash(Iface i1, uint32 ret)
+{
+ Itype *im;
+ Sigt *st;
+
+ ret = 0;
+ im = i1.type;
+ if(im != nil) {
+ st = im->sigt;
+ if(st != nil)
+ ret = st->thash;
+ }
+ FLUSH(&ret);
+}
+
+// efacethash(e1 any) (ret uint32)
+void
+sys·efacethash(Eface e1, uint32 ret)
+{
+ Sigt *st;
+
+ ret = 0;
+ st = e1.type;
+ if(st != nil)
+ ret = st->thash;
+ FLUSH(&ret);
+}
+
+void
+sys·printiface(Iface i)
+{
+ printiface(i);
+}
+
+void
+sys·printeface(Eface e)
+{
+ printeface(e);
+}
+
+void
+unsafe·Reflect(Eface i, uint64 retit, String rettype, bool retindir)
+{
+ int32 wid;
+
+ if(i.type == nil) {
+ retit = 0;
+ rettype = emptystring;
+ retindir = false;
+ } else {
+ retit = (uint64)i.data;
+ rettype = gostring(i.type->name);
+ wid = i.type->width;
+ retindir = wid > sizeof(i.data);
+ }
+ FLUSH(&retit);
+ FLUSH(&rettype);
+ FLUSH(&retindir);
+}
+
+extern Sigt *gotypesigs[];
+extern int32 ngotypesigs;
+
+
+// The reflection library can ask to unreflect on a type
+// that has never been used, so we don't have a signature for it.
+// For concreteness, suppose a program does
+//
+// type T struct{ x []int }
+// var t T;
+// v := reflect.NewValue(v);
+// vv := v.Field(0);
+// if s, ok := vv.Interface().(string) {
+// print("first field is string");
+// }
+//
+// vv.Interface() returns the result of sys.Unreflect with
+// a typestring of "[]int". If []int is not used with interfaces
+// in the rest of the program, there will be no signature in gotypesigs
+// for "[]int", so we have to invent one. The requirements
+// on the fake signature are:
+//
+// (1) any interface conversion using the signature will fail
+// (2) calling unsafe.Reflect() returns the args to unreflect
+// (3) the right algorithm type is used, for == and map insertion
+//
+// (1) is ensured by the fact that we allocate a new Sigt,
+// so it will necessarily be != any Sigt in gotypesigs.
+// (2) is ensured by storing the type string in the signature
+// and setting the width to force the correct value of the bool indir.
+// (3) is ensured by sniffing the type string.
+//
+// Note that (1) is correct behavior: if the program had tested
+// for .([]int) instead of .(string) above, then there would be a
+// signature with type string "[]int" in gotypesigs, and unreflect
+// wouldn't call fakesigt.
+
+static Sigt* fake[1009];
+static int32 nfake;
+
+enum
+{
+ SizeofInt = 4,
+ SizeofFloat = 4,
+};
+
+// Table of prefixes of names of comparable types.
+static struct {
+ int8 *s;
+ int8 n;
+ int8 alg;
+ int8 w;
+} cmp[] =
+{
+ // basic types
+ "int", 3+1, AMEM, SizeofInt, // +1 is NUL
+ "uint", 4+1, AMEM, SizeofInt,
+ "int8", 4+1, AMEM, 1,
+ "uint8", 5+1, AMEM, 1,
+ "int16", 5+1, AMEM, 2,
+ "uint16", 6+1, AMEM, 2,
+ "int32", 5+1, AMEM, 4,
+ "uint32", 6+1, AMEM, 4,
+ "int64", 5+1, AMEM, 8,
+ "uint64", 6+1, AMEM, 8,
+ "uintptr", 7+1, AMEM, sizeof(uintptr),
+ "float", 5+1, AMEM, SizeofFloat,
+ "float32", 7+1, AMEM, 4,
+ "float64", 7+1, AMEM, 8,
+ "bool", 4+1, AMEM, sizeof(bool),
+
+ // string compare is special
+ "string", 6+1, ASTRING, sizeof(String),
+
+ // generic types, identified by prefix
+ "*", 1, AMEM, sizeof(uintptr),
+ "chan ", 5, AMEM, sizeof(uintptr),
+ "func(", 5, AMEM, sizeof(uintptr),
+ "map[", 4, AMEM, sizeof(uintptr),
+};
+
+static Sigt*
+fakesigt(String type, bool indir)
+{
+ Sigt *sigt;
+ uint32 h;
+ int32 i, locked;
+
+ h = 0;
+ for(i=0; i<type.len; i++)
+ h = h*37 + type.str[i];
+ h += indir;
+ h %= nelem(fake);
+
+ for(locked=0; locked<2; locked++) {
+ if(locked)
+ lock(&ifacelock);
+ for(sigt = fake[h]; sigt != nil; sigt = sigt->link) {
+ // don't need to compare indir.
+ // same type string but different indir will have
+ // different hashes.
+ if(mcmp(sigt->name, type.str, type.len) == 0)
+ if(sigt->name[type.len] == '\0') {
+ if(locked)
+ unlock(&ifacelock);
+ return sigt;
+ }
+ }
+ }
+
+ sigt = malloc(sizeof(*sigt));
+ sigt->name = malloc(type.len + 1);
+ mcpy(sigt->name, type.str, type.len);
+
+ sigt->alg = AFAKE;
+ sigt->width = 1; // small width
+ if(indir)
+ sigt->width = 2*sizeof(niliface.data); // big width
+
+ // AFAKE is like ANOEQ; check whether the type
+ // should have a more capable algorithm.
+ for(i=0; i<nelem(cmp); i++) {
+ if(mcmp((byte*)sigt->name, (byte*)cmp[i].s, cmp[i].n) == 0) {
+ sigt->alg = cmp[i].alg;
+ sigt->width = cmp[i].w;
+ break;
+ }
+ }
+
+ sigt->link = fake[h];
+ fake[h] = sigt;
+
+ unlock(&ifacelock);
+ return sigt;
+}
+
+static int32
+cmpstringchars(String a, uint8 *b)
+{
+ int32 i;
+ byte c1, c2;
+
+ for(i=0;; i++) {
+ c1 = 0;
+ if(i < a.len)
+ c1 = a.str[i];
+ c2 = b[i];
+ if(c1 < c2)
+ return -1;
+ if(c1 > c2)
+ return +1;
+ if(c1 == 0)
+ return 0;
+ }
+}
+
+static Sigt*
+findtype(String type, bool indir)
+{
+ int32 i, lo, hi, m;
+
+ lo = 0;
+ hi = ngotypesigs;
+ while(lo < hi) {
+ m = lo + (hi - lo)/2;
+ i = cmpstringchars(type, gotypesigs[m]->name);
+ if(i == 0)
+ return gotypesigs[m];
+ if(i < 0)
+ hi = m;
+ else
+ lo = m+1;
+ }
+ return fakesigt(type, indir);
+}
+
+
+void
+unsafe·Unreflect(uint64 it, String type, bool indir, Eface ret)
+{
+ Sigt *sigt;
+
+ ret = nileface;
+
+ if(cmpstring(type, emptystring) == 0)
+ goto out;
+
+ if(type.len > 10 && mcmp(type.str, (byte*)"interface ", 10) == 0) {
+ printf("unsafe.Unreflect: cannot put %S in interface\n", type);
+ throw("unsafe.Unreflect");
+ }
+
+ // if we think the type should be indirect
+ // and caller does not, play it safe, return nil.
+ sigt = findtype(type, indir);
+ if(indir != (sigt->width > sizeof(ret.data)))
+ goto out;
+
+ ret.type = sigt;
+ ret.data = (void*)it;
+
+out:
+ FLUSH(&ret);
+}
+
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/linux/386/defs.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/linux/386/defs.h Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,136 @@
+// godefs -f -m32 -f -I/home/rsc/pub/linux-2.6/arch/x86/include -f -I/home/rsc/pub/linux-2.6/include defs2.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+// Constants
+enum {
+ PROT_NONE = 0,
+ PROT_READ = 0x1,
+ PROT_WRITE = 0x2,
+ PROT_EXEC = 0x4,
+ MAP_ANON = 0x20,
+ MAP_PRIVATE = 0x2,
+ SA_RESTART = 0x10000000,
+ SA_ONSTACK = 0x8000000,
+ SA_RESTORER = 0x4000000,
+ SA_SIGINFO = 0x4,
+};
+
+// Types
+#pragma pack on
+
+typedef struct Fpreg Fpreg;
+struct Fpreg {
+ uint16 significand[4];
+ uint16 exponent;
+};
+
+typedef struct Fpxreg Fpxreg;
+struct Fpxreg {
+ uint16 significand[4];
+ uint16 exponent;
+ uint16 padding[3];
+};
+
+typedef struct Xmmreg Xmmreg;
+struct Xmmreg {
+ uint32 element[4];
+};
+
+typedef struct Fpstate Fpstate;
+struct Fpstate {
+ uint32 cw;
+ uint32 sw;
+ uint32 tag;
+ uint32 ipoff;
+ uint32 cssel;
+ uint32 dataoff;
+ uint32 datasel;
+ Fpreg _st[8];
+ uint16 status;
+ uint16 magic;
+ uint32 _fxsr_env[6];
+ uint32 mxcsr;
+ uint32 reserved;
+ Fpxreg _fxsr_st[8];
+ Xmmreg _xmm[8];
+ uint32 padding1[44];
+ byte _anon_[48];
+};
+
+typedef struct Timespec Timespec;
+struct Timespec {
+ int32 tv_sec;
+ int32 tv_nsec;
+};
+
+typedef struct Timeval Timeval;
+struct Timeval {
+ int32 tv_sec;
+ int32 tv_usec;
+};
+
+typedef struct Sigaction Sigaction;
+struct Sigaction {
+ byte _u[4];
+ uint32 sa_mask;
+ uint32 sa_flags;
+ void *sa_restorer;
+};
+
+typedef struct Siginfo Siginfo;
+struct Siginfo {
+ int32 si_signo;
+ int32 si_errno;
+ int32 si_code;
+ byte _sifields[116];
+};
+
+typedef struct Sigaltstack Sigaltstack;
+struct Sigaltstack {
+ void *ss_sp;
+ int32 ss_flags;
+ uint32 ss_size;
+};
+
+typedef struct Sigcontext Sigcontext;
+struct Sigcontext {
+ uint16 gs;
+ uint16 __gsh;
+ uint16 fs;
+ uint16 __fsh;
+ uint16 es;
+ uint16 __esh;
+ uint16 ds;
+ uint16 __dsh;
+ uint32 edi;
+ uint32 esi;
+ uint32 ebp;
+ uint32 esp;
+ uint32 ebx;
+ uint32 edx;
+ uint32 ecx;
+ uint32 eax;
+ uint32 trapno;
+ uint32 err;
+ uint32 eip;
+ uint16 cs;
+ uint16 __csh;
+ uint32 eflags;
+ uint32 esp_at_signal;
+ uint16 ss;
+ uint16 __ssh;
+ Fpstate *fpstate;
+ uint32 oldmask;
+ uint32 cr2;
+};
+
+typedef struct Ucontext Ucontext;
+struct Ucontext {
+ uint32 uc_flags;
+ Ucontext *uc_link;
+ Sigaltstack uc_stack;
+ Sigcontext uc_mcontext;
+ uint32 uc_sigmask;
+};
+#pragma pack off
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/linux/386/rt0.s
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/linux/386/rt0.s Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,8 @@
+// Copyright 2009 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.
+
+// Darwin and Linux use the same linkage to main
+
+TEXT _rt0_386_linux(SB),7,$0
+ JMP _rt0_386(SB)
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/linux/386/signal.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/linux/386/signal.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,102 @@
+// Copyright 2009 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.
+
+#include "runtime.h"
+#include "defs.h"
+#include "signals.h"
+#include "os.h"
+
+void
+dumpregs(Sigcontext *r)
+{
+ printf("eax %X\n", r->eax);
+ printf("ebx %X\n", r->ebx);
+ printf("ecx %X\n", r->ecx);
+ printf("edx %X\n", r->edx);
+ printf("edi %X\n", r->edi);
+ printf("esi %X\n", r->esi);
+ printf("ebp %X\n", r->ebp);
+ printf("esp %X\n", r->esp);
+ printf("eip %X\n", r->eip);
+ printf("eflags %X\n", r->eflags);
+ printf("cs %X\n", r->cs);
+ printf("fs %X\n", r->fs);
+ printf("gs %X\n", r->gs);
+}
+
+/*
+ * This assembler routine takes the args from registers, puts them on the stack,
+ * and calls sighandler().
+ */
+extern void sigtramp(void);
+extern void sigignore(void); // just returns
+extern void sigreturn(void); // calls sigreturn
+
+void
+sighandler(int32 sig, Siginfo* info, void* context)
+{
+ Ucontext *uc;
+ Sigcontext *sc;
+
+ if(panicking) // traceback already printed
+ exit(2);
+ panicking = 1;
+
+ uc = context;
+ sc = &uc->uc_mcontext;
+
+ if(sig < 0 || sig >= NSIG)
+ printf("Signal %d\n", sig);
+ else
+ printf("%s\n", sigtab[sig].name);
+
+ printf("Faulting address: %p\n", *(void**)info->_sifields);
+ printf("pc=%X\n", sc->eip);
+ printf("\n");
+
+ if(gotraceback()){
+ traceback((void*)sc->eip, (void*)sc->esp, m->curg);
+ tracebackothers(m->curg);
+ dumpregs(sc);
+ }
+
+ breakpoint();
+ exit(2);
+}
+
+void
+signalstack(byte *p, int32 n)
+{
+ Sigaltstack st;
+
+ st.ss_sp = p;
+ st.ss_size = n;
+ st.ss_flags = 0;
+ sigaltstack(&st, nil);
+}
+
+void
+initsig(void)
+{
+ static Sigaction sa;
+
+ int32 i;
+ sa.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESTORER;
+ sa.sa_mask = 0xFFFFFFFFFFFFFFFFULL;
+ sa.sa_restorer = (void*)sigreturn;
+ for(i = 0; i<NSIG; i++) {
+ if(sigtab[i].flags) {
+ if(sigtab[i].flags & SigCatch)
+ *(void**)sa._u = (void*)sigtramp; // handler
+ else
+ *(void**)sa._u = (void*)sigignore; // handler
+ if(sigtab[i].flags & SigRestart)
+ sa.sa_flags |= SA_RESTART;
+ else
+ sa.sa_flags &= ~SA_RESTART;
+ rt_sigaction(i, &sa, nil, 8);
+ }
+ }
+}
+
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/linux/386/sys.s
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/linux/386/sys.s Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,222 @@
+// Copyright 2009 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.
+
+//
+// System calls and other sys.stuff for 386, Linux
+//
+
+TEXT syscall(SB),7,$0
+ MOVL 4(SP), AX // syscall number
+ MOVL 8(SP), BX // arg1
+ MOVL 12(SP), CX // arg2
+ MOVL 16(SP), DX // arg3
+ MOVL 20(SP), SI // arg4
+ MOVL 24(SP), DI // arg5
+ MOVL 28(SP), BP // arg6
+ INT $0x80
+ CMPL AX, $0xfffff001
+ JLS 2(PC)
+ INT $3 // not reached
+ RET
+
+TEXT exit(SB),7,$0
+ MOVL $252, AX // syscall number
+ MOVL 4(SP), BX
+ INT $0x80
+ INT $3 // not reached
+ RET
+
+TEXT exit1(SB),7,$0
+ MOVL $1, AX // exit - exit the current os thread
+ MOVL 4(SP), BX
+ INT $0x80
+ INT $3 // not reached
+ RET
+
+TEXT write(SB),7,$0
+ MOVL $4, AX // syscall - write
+ MOVL 4(SP), BX
+ MOVL 8(SP), CX
+ MOVL 12(SP), DX
+ INT $0x80
+ RET
+
+TEXT getpid(SB),7,$0
+ MOVL $20, AX
+ INT $0x80
+ RET
+
+TEXT kill(SB),7,$0
+ MOVL $37, AX
+ MOVL 4(SP), BX
+ MOVL 8(SP), CX
+ INT $0x80
+ RET
+
+TEXT sys·write(SB),7,$0
+ MOVL $4, AX // syscall - write
+ MOVL 4(SP), BX
+ MOVL 8(SP), CX
+ MOVL 12(SP), DX
+ INT $0x80
+ RET
+
+TEXT rt_sigaction(SB),7,$0
+ MOVL $174, AX // syscall - rt_sigaction
+ MOVL 4(SP), BX
+ MOVL 8(SP), CX
+ MOVL 12(SP), DX
+ MOVL 16(SP), SI
+ INT $0x80
+ RET
+
+TEXT sigtramp(SB),7,$0
+ MOVL 4(FS), BP // m
+ MOVL 20(BP), AX // m->gsignal
+ MOVL AX, 0(FS) // g = m->gsignal
+ JMP sighandler(SB)
+
+TEXT sigignore(SB),7,$0
+ RET
+
+TEXT sigreturn(SB),7,$0
+ MOVL 4(FS), BP // m
+ MOVL 32(BP), BP // m->curg
+ MOVL BP, 0(FS) // g = m->curg
+ MOVL $173, AX // rt_sigreturn
+ INT $0x80
+ INT $3 // not reached
+ RET
+
+TEXT sys·mmap(SB),7,$0
+ MOVL $192, AX // mmap2
+ MOVL 4(SP), BX
+ MOVL 8(SP), CX
+ MOVL 12(SP), DX
+ MOVL 16(SP), SI
+ MOVL 20(SP), DI
+ MOVL 24(SP), BP
+ SHRL $12, BP
+ INT $0x80
+ CMPL AX, $0xfffff001
+ JLS 2(PC)
+ INT $3
+ RET
+
+// int64 futex(int32 *uaddr, int32 op, int32 val,
+// struct timespec *timeout, int32 *uaddr2, int32 val2);
+TEXT futex(SB),7,$0
+ MOVL $240, AX // futex
+ MOVL 4(SP), BX
+ MOVL 8(SP), CX
+ MOVL 12(SP), DX
+ MOVL 16(SP), SI
+ MOVL 20(SP), DI
+ MOVL 24(SP), BP
+ INT $0x80
+ RET
+
+// int64 clone(int32 flags, void *stack, M *m, G *g, void (*fn)(void));
+TEXT clone(SB),7,$0
+ MOVL $120, AX // clone
+ MOVL flags+4(SP), BX
+ MOVL stack+8(SP), CX
+
+ // Copy m, g, fn off parent stack for use by child.
+ SUBL $12, CX
+ MOVL m+12(SP), DX
+ MOVL DX, 0(CX)
+ MOVL g+16(SP), DX
+ MOVL DX, 4(CX)
+ MOVL fn+20(SP), DX
+ MOVL DX, 8(CX)
+
+ MOVL $120, AX
+ INT $0x80
+
+ // In parent, return.
+ CMPL AX, $0
+ JEQ 2(PC)
+ RET
+
+ // In child, set up new stack, etc.
+ MOVL 0(CX), BX // m
+ MOVL 12(AX), AX // fs (= m->cret)
+ MOVW AX, FS
+ MOVL 8(CX), DX // fn
+ ADDL $12, CX
+ MOVL CX, SP
+
+ // fn is now on top of stack.
+
+ // initialize m->procid to Linux tid
+ MOVL $224, AX
+ INT $0x80
+ MOVL AX, 20(BX)
+
+ // call fn
+ CALL DX
+
+ // It shouldn't return; if it does, exit.
+ MOVL $111, DI
+ MOVL $1, AX
+ INT $0x80
+ JMP -3(PC) // keep exiting
+
+TEXT sigaltstack(SB),7,$-8
+ MOVL $186, AX // sigaltstack
+ MOVL new+4(SP), BX
+ MOVL old+8(SP), CX
+ INT $0x80
+ CMPL AX, $0xfffff001
+ JLS 2(PC)
+ INT $3
+ RET
+
+// // fake the per-goroutine and per-mach registers
+// LEAL m0(SB),
+
+// TODO(rsc): move to linux.s
+// <asm-i386/ldt.h>
+// struct user_desc {
+// unsigned int entry_number;
+// unsigned long base_addr;
+// unsigned int limit;
+// unsigned int seg_32bit:1;
+// unsigned int contents:2;
+// unsigned int read_exec_only:1;
+// unsigned int limit_in_pages:1;
+// unsigned int seg_not_present:1;
+// unsigned int useable:1;
+// };
+#define SEG_32BIT 0x01
+// contents are the 2 bits 0x02 and 0x04.
+#define CONTENTS_DATA 0x00
+#define CONTENTS_STACK 0x02
+#define CONTENTS_CODE 0x04
+#define READ_EXEC_ONLY 0x08
+#define LIMIT_IN_PAGES 0x10
+#define SEG_NOT_PRESENT 0x20
+#define USEABLE 0x40
+
+// setldt(int entry, int address, int limit)
+TEXT setldt(SB),7,$32
+ // set up user_desc
+ LEAL 16(SP), AX // struct user_desc
+ MOVL entry+0(FP), BX // entry
+ MOVL BX, 0(AX)
+ MOVL address+4(FP), BX // base address
+ MOVL BX, 4(AX)
+ MOVL limit+8(FP), BX // limit
+ MOVL BX, 8(AX)
+ MOVL $(SEG_32BIT|USEABLE|CONTENTS_DATA), 12(AX) // flag bits
+
+ // call modify_ldt
+ MOVL $123, 0(SP) // syscall - modify_ldt
+ MOVL $1, 4(SP) // func = 1 (write)
+ MOVL AX, 8(SP) // user_desc
+ MOVL $16, 12(SP) // sizeof(user_desc)
+ CALL syscall(SB)
+ RET
+
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/linux/amd64/defs.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/linux/amd64/defs.h Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,175 @@
+// godefs -f -m64 defs.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+// Constants
+enum {
+ PROT_NONE = 0,
+ PROT_READ = 0x1,
+ PROT_WRITE = 0x2,
+ PROT_EXEC = 0x4,
+ MAP_ANON = 0x20,
+ MAP_PRIVATE = 0x2,
+ SA_RESTART = 0x10000000,
+ SA_ONSTACK = 0x8000000,
+ SA_RESTORER = 0x4000000,
+ SA_SIGINFO = 0x4,
+};
+
+// Types
+#pragma pack on
+
+typedef struct Timespec Timespec;
+struct Timespec {
+ int64 tv_sec;
+ int64 tv_nsec;
+};
+
+typedef struct Timeval Timeval;
+struct Timeval {
+ int64 tv_sec;
+ int64 tv_usec;
+};
+
+typedef struct Sigaction Sigaction;
+struct Sigaction {
+ void *sa_handler;
+ uint64 sa_flags;
+ void *sa_restorer;
+ uint64 sa_mask;
+};
+
+typedef struct Siginfo Siginfo;
+struct Siginfo {
+ int32 si_signo;
+ int32 si_errno;
+ int32 si_code;
+ byte pad0[4];
+ byte _sifields[112];
+};
+#pragma pack off
+// godefs -f -m64 defs1.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+// Constants
+
+// Types
+#pragma pack on
+
+typedef struct Usigset Usigset;
+struct Usigset {
+ uint64 __val[16];
+};
+
+typedef struct Fpxreg Fpxreg;
+struct Fpxreg {
+ uint16 significand[4];
+ uint16 exponent;
+ uint16 padding[3];
+};
+
+typedef struct Xmmreg Xmmreg;
+struct Xmmreg {
+ uint32 element[4];
+};
+
+typedef struct Fpstate Fpstate;
+struct Fpstate {
+ uint16 cwd;
+ uint16 swd;
+ uint16 ftw;
+ uint16 fop;
+ uint64 rip;
+ uint64 rdp;
+ uint32 mxcsr;
+ uint32 mxcr_mask;
+ Fpxreg _st[8];
+ Xmmreg _xmm[16];
+ uint32 padding[24];
+};
+
+typedef struct Fpxreg1 Fpxreg1;
+struct Fpxreg1 {
+ uint16 significand[4];
+ uint16 exponent;
+ uint16 padding[3];
+};
+
+typedef struct Xmmreg1 Xmmreg1;
+struct Xmmreg1 {
+ uint32 element[4];
+};
+
+typedef struct Fpstate1 Fpstate1;
+struct Fpstate1 {
+ uint16 cwd;
+ uint16 swd;
+ uint16 ftw;
+ uint16 fop;
+ uint64 rip;
+ uint64 rdp;
+ uint32 mxcsr;
+ uint32 mxcr_mask;
+ Fpxreg1 _st[8];
+ Xmmreg1 _xmm[16];
+ uint32 padding[24];
+};
+
+typedef struct Sigaltstack Sigaltstack;
+struct Sigaltstack {
+ void *ss_sp;
+ int32 ss_flags;
+ byte pad0[4];
+ uint64 ss_size;
+};
+
+typedef struct Mcontext Mcontext;
+struct Mcontext {
+ int64 gregs[23];
+ Fpstate *fpregs;
+ uint64 __reserved1[8];
+};
+
+typedef struct Ucontext Ucontext;
+struct Ucontext {
+ uint64 uc_flags;
+ Ucontext *uc_link;
+ Sigaltstack uc_stack;
+ Mcontext uc_mcontext;
+ Usigset uc_sigmask;
+ Fpstate __fpregs_mem;
+};
+
+typedef struct Sigcontext Sigcontext;
+struct Sigcontext {
+ uint64 r8;
+ uint64 r9;
+ uint64 r10;
+ uint64 r11;
+ uint64 r12;
+ uint64 r13;
+ uint64 r14;
+ uint64 r15;
+ uint64 rdi;
+ uint64 rsi;
+ uint64 rbp;
+ uint64 rbx;
+ uint64 rdx;
+ uint64 rax;
+ uint64 rcx;
+ uint64 rsp;
+ uint64 rip;
+ uint64 eflags;
+ uint16 cs;
+ uint16 gs;
+ uint16 fs;
+ uint16 __pad0;
+ uint64 err;
+ uint64 trapno;
+ uint64 oldmask;
+ uint64 cr2;
+ Fpstate1 *fpstate;
+ uint64 __reserved1[8];
+};
+#pragma pack off
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/linux/amd64/rt0.s
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/linux/amd64/rt0.s Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,9 @@
+// Copyright 2009 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.
+
+// Darwin and Linux use the same linkage to main
+
+TEXT _rt0_amd64_linux(SB),7,$-8
+ MOVQ $_rt0_amd64(SB), AX
+ JMP AX
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/linux/amd64/signal.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/linux/amd64/signal.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,112 @@
+// Copyright 2009 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.
+
+#include "runtime.h"
+#include "defs.h"
+#include "signals.h"
+#include "os.h"
+
+void
+dumpregs(Sigcontext *r)
+{
+ printf("rax %X\n", r->rax);
+ printf("rbx %X\n", r->rbx);
+ printf("rcx %X\n", r->rcx);
+ printf("rdx %X\n", r->rdx);
+ printf("rdi %X\n", r->rdi);
+ printf("rsi %X\n", r->rsi);
+ printf("rbp %X\n", r->rbp);
+ printf("rsp %X\n", r->rsp);
+ printf("r8 %X\n", r->r8 );
+ printf("r9 %X\n", r->r9 );
+ printf("r10 %X\n", r->r10);
+ printf("r11 %X\n", r->r11);
+ printf("r12 %X\n", r->r12);
+ printf("r13 %X\n", r->r13);
+ printf("r14 %X\n", r->r14);
+ printf("r15 %X\n", r->r15);
+ printf("rip %X\n", r->rip);
+ printf("rflags %X\n", r->eflags);
+ printf("cs %X\n", (uint64)r->cs);
+ printf("fs %X\n", (uint64)r->fs);
+ printf("gs %X\n", (uint64)r->gs);
+}
+
+/*
+ * This assembler routine takes the args from registers, puts them on the stack,
+ * and calls sighandler().
+ */
+extern void sigtramp(void);
+extern void sigignore(void); // just returns
+extern void sigreturn(void); // calls sigreturn
+
+void
+sighandler(int32 sig, Siginfo* info, void* context)
+{
+ Ucontext *uc;
+ Mcontext *mc;
+ Sigcontext *sc;
+
+ if(panicking) // traceback already printed
+ exit(2);
+ panicking = 1;
+
+ uc = context;
+ mc = &uc->uc_mcontext;
+ sc = (Sigcontext*)mc; // same layout, more conveient names
+
+ if(sig < 0 || sig >= NSIG)
+ printf("Signal %d\n", sig);
+ else
+ printf("%s\n", sigtab[sig].name);
+
+ printf("Faulting address: %p\n", *(void**)info->_sifields);
+ printf("PC=%X\n", sc->rip);
+ printf("\n");
+
+ if(gotraceback()){
+ traceback((void*)sc->rip, (void*)sc->rsp, (void*)sc->r15);
+ tracebackothers((void*)sc->r15);
+ dumpregs(sc);
+ }
+
+ breakpoint();
+ exit(2);
+}
+
+void
+signalstack(byte *p, int32 n)
+{
+ Sigaltstack st;
+
+ st.ss_sp = p;
+ st.ss_size = n;
+ st.ss_flags = 0;
+ sigaltstack(&st, nil);
+}
+
+void
+initsig(void)
+{
+ static Sigaction sa;
+
+ int32 i;
+ sa.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESTORER;
+ sa.sa_mask = 0xFFFFFFFFFFFFFFFFULL;
+ sa.sa_restorer = (void*)sigreturn;
+ for(i = 0; i<NSIG; i++) {
+ if(sigtab[i].flags) {
+ if(sigtab[i].flags & SigCatch)
+ sa.sa_handler = (void*)sigtramp;
+ else
+ sa.sa_handler = (void*)sigignore;
+ if(sigtab[i].flags & SigRestart)
+ sa.sa_flags |= SA_RESTART;
+ else
+ sa.sa_flags &= ~SA_RESTART;
+ rt_sigaction(i, &sa, nil, 8);
+ }
+ }
+}
+
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/linux/amd64/sys.s
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/linux/amd64/sys.s Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,193 @@
+// Copyright 2009 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.
+
+//
+// System calls and other sys.stuff for AMD64, Linux
+//
+
+TEXT exit(SB),7,$0-8
+ MOVL 8(SP), DI
+ MOVL $231, AX // exitgroup - force all os threads to exi
+ SYSCALL
+ RET
+
+TEXT exit1(SB),7,$0-8
+ MOVL 8(SP), DI
+ MOVL $60, AX // exit - exit the current os thread
+ SYSCALL
+ RET
+
+TEXT open(SB),7,$0-16
+ MOVQ 8(SP), DI
+ MOVL 16(SP), SI
+ MOVL 20(SP), DX
+ MOVL $2, AX // syscall entry
+ SYSCALL
+ RET
+
+TEXT close(SB),7,$0-8
+ MOVL 8(SP), DI
+ MOVL $3, AX // syscall entry
+ SYSCALL
+ RET
+
+TEXT fstat(SB),7,$0-16
+ MOVL 8(SP), DI
+ MOVQ 16(SP), SI
+ MOVL $5, AX // syscall entry
+ SYSCALL
+ RET
+
+TEXT read(SB),7,$0-24
+ MOVL 8(SP), DI
+ MOVQ 16(SP), SI
+ MOVL 24(SP), DX
+ MOVL $0, AX // syscall entry
+ SYSCALL
+ RET
+
+TEXT write(SB),7,$0-24
+ MOVL 8(SP), DI
+ MOVQ 16(SP), SI
+ MOVL 24(SP), DX
+ MOVL $1, AX // syscall entry
+ SYSCALL
+ RET
+
+TEXT sys·write(SB),7,$0-24
+ MOVL 8(SP), DI
+ MOVQ 16(SP), SI
+ MOVL 24(SP), DX
+ MOVL $1, AX // syscall entry
+ SYSCALL
+ RET
+
+TEXT rt_sigaction(SB),7,$0-32
+ MOVL 8(SP), DI
+ MOVQ 16(SP), SI
+ MOVQ 24(SP), DX
+ MOVQ 32(SP), R10
+ MOVL $13, AX // syscall entry
+ SYSCALL
+ RET
+
+TEXT sigtramp(SB),7,$24-16
+ MOVQ 32(R14), R15 // g = m->gsignal
+ MOVQ DI,0(SP)
+ MOVQ SI,8(SP)
+ MOVQ DX,16(SP)
+ CALL sighandler(SB)
+ RET
+
+TEXT sigignore(SB),7,$0
+ RET
+
+TEXT sigreturn(SB),7,$0
+ MOVL $15, AX // rt_sigreturn
+ SYSCALL
+ INT $3 // not reached
+
+TEXT sys·mmap(SB),7,$0-32
+ MOVQ 8(SP), DI
+ MOVQ $0, SI
+ MOVL 16(SP), SI
+ MOVL 20(SP), DX
+ MOVL 24(SP), R10
+ MOVL 28(SP), R8
+ MOVL 32(SP), R9
+
+ MOVL $9, AX // syscall entry
+ SYSCALL
+ CMPQ AX, $0xfffffffffffff001
+ JLS 2(PC)
+ CALL notok(SB)
+ RET
+
+TEXT notok(SB),7,$0
+ MOVQ $0xf1, BP
+ MOVQ BP, (BP)
+ RET
+
+TEXT sys·memclr(SB),7,$0-16
+ MOVQ 8(SP), DI // arg 1 addr
+ MOVL 16(SP), CX // arg 2 count (cannot be zero)
+ ADDL $7, CX
+ SHRL $3, CX
+ MOVQ $0, AX
+ CLD
+ REP
+ STOSQ
+ RET
+
+TEXT sys·getcallerpc+0(SB),7,$0
+ MOVQ x+0(FP),AX // addr of first arg
+ MOVQ -8(AX),AX // get calling pc
+ RET
+
+TEXT sys·setcallerpc+0(SB),7,$0
+ MOVQ x+0(FP),AX // addr of first arg
+ MOVQ x+8(FP), BX
+ MOVQ BX, -8(AX) // set calling pc
+ RET
+
+// int64 futex(int32 *uaddr, int32 op, int32 val,
+// struct timespec *timeout, int32 *uaddr2, int32 val2);
+TEXT futex(SB),7,$0
+ MOVQ 8(SP), DI
+ MOVL 16(SP), SI
+ MOVL 20(SP), DX
+ MOVQ 24(SP), R10
+ MOVQ 32(SP), R8
+ MOVL 40(SP), R9
+ MOVL $202, AX
+ SYSCALL
+ RET
+
+// int64 clone(int32 flags, void *stack, M *m, G *g, void (*fn)(void));
+TEXT clone(SB),7,$0
+ MOVL flags+8(SP), DI
+ MOVQ stack+16(SP), SI
+
+ // Copy m, g, fn off parent stack for use by child.
+ // Careful: Linux system call clobbers CX and R11.
+ MOVQ m+24(SP), R8
+ MOVQ g+32(SP), R9
+ MOVQ fn+40(SP), R12
+
+ MOVL $56, AX
+ SYSCALL
+
+ // In parent, return.
+ CMPQ AX, $0
+ JEQ 2(PC)
+ RET
+
+ // In child, set up new stack
+ MOVQ SI, SP
+ MOVQ R8, R14 // m
+ MOVQ R9, R15 // g
+
+ // Initialize m->procid to Linux tid
+ MOVL $186, AX // gettid
+ SYSCALL
+ MOVQ AX, 24(R14)
+
+ // Call fn
+ CALL R12
+
+ // It shouldn't return. If it does, exi
+ MOVL $111, DI
+ MOVL $60, AX
+ SYSCALL
+ JMP -3(PC) // keep exiting
+
+TEXT sigaltstack(SB),7,$-8
+ MOVQ new+8(SP), DI
+ MOVQ old+16(SP), SI
+ MOVQ $131, AX
+ SYSCALL
+ CMPQ AX, $0xfffffffffffff001
+ JLS 2(PC)
+ CALL notok(SB)
+ RET
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/linux/arm/defs.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/linux/arm/defs.h Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,27 @@
+// godefs -carm-gcc -f -I/usr/local/google/src/linux-2.6.28/arch/arm/include -f -I/usr/local/google/src/linux-2.6.28/include defs_arm.c
+
+// MACHINE GENERATED - DO NOT EDIT.
+
+// Constants
+enum {
+ PROT_NONE = 0,
+ PROT_READ = 0x1,
+ PROT_WRITE = 0x2,
+ PROT_EXEC = 0x4,
+ MAP_ANON = 0x20,
+ MAP_PRIVATE = 0x2,
+ SA_RESTART = 0x10000000,
+ SA_ONSTACK = 0x8000000,
+ SA_RESTORER = 0x4000000,
+ SA_SIGINFO = 0x4,
+};
+
+// Types
+#pragma pack on
+
+typedef struct Timespec Timespec;
+struct Timespec {
+ int32 tv_sec;
+ int32 tv_nsec;
+};
+#pragma pack off
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/linux/arm/rt0.s
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/linux/arm/rt0.s Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,6 @@
+// Copyright 2009 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.
+
+TEXT _rt0_arm_linux(SB),7,$0
+ B _rt0_arm(SB)
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/linux/arm/signal.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/linux/arm/signal.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,4 @@
+// Copyright 2009 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.
+
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/linux/arm/sys.s
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/linux/arm/sys.s Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,15 @@
+// Copyright 2009 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.
+
+//
+// System calls and other sys.stuff for arm, Linux
+//
+
+TEXT write(SB),7,$0
+ MOVW 4(SP), R0
+ MOVW 8(SP), R1
+ MOVW 12(SP), R2
+ SWI $0x00900004 // syscall write
+ RET
+
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/linux/defs.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/linux/defs.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,40 @@
+// Copyright 2009 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.
+
+/*
+ * Input to godefs
+ godefs -f -m64 defs.c >amd64/defs.h
+ godefs -f -m64 defs1.c >>amd64/defs.h
+ */
+
+// Linux glibc and Linux kernel define different and conflicting
+// definitions for struct sigaction, struct timespec, etc.
+// We want the kernel ones, which are in the asm/* headers.
+// But then we'd get conflicts when we include the system
+// headers for things like ucontext_t, so that happens in
+// a separate file, defs1.c.
+
+#include <asm/signal.h>
+#include <asm/siginfo.h>
+#include <asm/mman.h>
+
+enum {
+ $PROT_NONE = PROT_NONE,
+ $PROT_READ = PROT_READ,
+ $PROT_WRITE = PROT_WRITE,
+ $PROT_EXEC = PROT_EXEC,
+
+ $MAP_ANON = MAP_ANONYMOUS,
+ $MAP_PRIVATE = MAP_PRIVATE,
+
+ $SA_RESTART = SA_RESTART,
+ $SA_ONSTACK = SA_ONSTACK,
+ $SA_RESTORER = SA_RESTORER,
+ $SA_SIGINFO = SA_SIGINFO,
+};
+
+typedef struct timespec $Timespec;
+typedef struct timeval $Timeval;
+typedef struct sigaction $Sigaction;
+typedef siginfo_t $Siginfo;
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/linux/defs1.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/linux/defs1.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,25 @@
+// Copyright 2009 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.
+
+/*
+ * Input to godefs
+ godefs -f -m64 defs.c >amd64/defs.h
+ godefs -f -m64 defs1.c >>amd64/defs.h
+ */
+
+#include <ucontext.h>
+
+typedef __sigset_t $Usigset;
+typedef struct _libc_fpxreg $Fpxreg;
+typedef struct _libc_xmmreg $Xmmreg;
+typedef struct _libc_fpstate $Fpstate;
+typedef struct _libc_fpreg $Fpreg;
+typedef struct _fpxreg $Fpxreg1;
+typedef struct _xmmreg $Xmmreg1;
+typedef struct _fpstate $Fpstate1;
+typedef struct _fpreg $Fpreg1;
+typedef struct sigaltstack $Sigaltstack;
+typedef mcontext_t $Mcontext;
+typedef ucontext_t $Ucontext;
+typedef struct sigcontext $Sigcontext;
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/linux/defs2.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/linux/defs2.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,51 @@
+// Copyright 2009 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.
+
+/*
+ * Input to godefs
+ godefs -f -m32 -f -I/home/rsc/pub/linux-2.6/arch/x86/include -f -I/home/rsc/pub/linux-2.6/include defs2.c >386/defs.h
+
+ * The asm header tricks we have to use for Linux on amd64
+ * (see defs.c and defs1.c) don't work here, so this is yet another
+ * file. Sigh.
+ */
+
+#include <asm/signal.h>
+#include <asm/mman.h>
+#include <asm/sigframe.h>
+#include <asm/ucontext.h>
+
+/*
+#include <sys/signal.h>
+#include <sys/mman.h>
+#include <ucontext.h>
+*/
+
+enum {
+ $PROT_NONE = PROT_NONE,
+ $PROT_READ = PROT_READ,
+ $PROT_WRITE = PROT_WRITE,
+ $PROT_EXEC = PROT_EXEC,
+
+ $MAP_ANON = MAP_ANONYMOUS,
+ $MAP_PRIVATE = MAP_PRIVATE,
+
+ $SA_RESTART = SA_RESTART,
+ $SA_ONSTACK = SA_ONSTACK,
+ $SA_RESTORER = SA_RESTORER,
+ $SA_SIGINFO = SA_SIGINFO,
+};
+
+typedef struct _fpreg $Fpreg;
+typedef struct _fpxreg $Fpxreg;
+typedef struct _xmmreg $Xmmreg;
+typedef struct _fpstate $Fpstate;
+typedef struct timespec $Timespec;
+typedef struct timeval $Timeval;
+typedef struct sigaction $Sigaction;
+typedef siginfo_t $Siginfo;
+typedef struct sigaltstack $Sigaltstack;
+typedef struct sigcontext $Sigcontext;
+typedef struct ucontext $Ucontext;
+
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/linux/defs_arm.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/linux/defs_arm.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,54 @@
+// Copyright 2009 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.
+
+/*
+ * Input to godefs
+ godefs -carm-gcc -f -I/usr/local/google/src/linux-2.6.28/arch/arm/include -f
+ -I/usr/local/google/src/linux-2.6.28/include defs_arm.c >arm/defs.h
+
+ * Another input file for ARM defs.h
+ */
+
+#include <asm/signal.h>
+#include <asm/mman.h>
+#include <asm/sigcontext.h>
+#include <asm/ucontext.h>
+
+/*
+#include <sys/signal.h>
+#include <sys/mman.h>
+#include <ucontext.h>
+*/
+
+#include <time.h>
+
+enum {
+ $PROT_NONE = PROT_NONE,
+ $PROT_READ = PROT_READ,
+ $PROT_WRITE = PROT_WRITE,
+ $PROT_EXEC = PROT_EXEC,
+
+ $MAP_ANON = MAP_ANONYMOUS,
+ $MAP_PRIVATE = MAP_PRIVATE,
+
+ $SA_RESTART = SA_RESTART,
+ $SA_ONSTACK = SA_ONSTACK,
+ $SA_RESTORER = SA_RESTORER,
+ $SA_SIGINFO = SA_SIGINFO
+};
+
+
+
+
+//typedef struct _fpreg $Fpreg;
+//typedef struct _fpxreg $Fpxreg;
+//typedef struct _xmmreg $Xmmreg;
+//typedef struct _fpstate $Fpstate;
+typedef struct timespec $Timespec;
+//typedef struct timeval $Timeval;
+// typedef struct sigaction $Sigaction;
+// typedef siginfo_t $Siginfo;
+// typedef struct sigaltstack $Sigaltstack;
+// typedef struct sigcontext $Sigcontext;
+// typedef struct ucontext $Ucontext;
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/linux/os.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/linux/os.h Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,10 @@
+// Copyright 2009 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.
+
+// Linux-specific system calls
+int64 futex(uint32*, int32, uint32, Timespec*, uint32*, uint32);
+int64 clone(int32, void*, M*, G*, void(*)(void));
+
+struct Sigaction;
+void rt_sigaction(int64, struct Sigaction*, void*, uint64);
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/linux/signals.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/linux/signals.h Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,48 @@
+// Copyright 2009 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.
+
+
+#define C SigCatch
+#define I SigIgnore
+#define R SigRestart
+
+static SigTab sigtab[] = {
+ /* 0 */ 0, "SIGNONE: no trap",
+ /* 1 */ 0, "SIGHUP: terminal line hangup",
+ /* 2 */ 0, "SIGINT: interrupt",
+ /* 3 */ C, "SIGQUIT: quit",
+ /* 4 */ C, "SIGILL: illegal instruction",
+ /* 5 */ C, "SIGTRAP: trace trap",
+ /* 6 */ C, "SIGABRT: abort",
+ /* 7 */ C, "SIGBUS: bus error",
+ /* 8 */ C, "SIGFPE: floating-point exception",
+ /* 9 */ 0, "SIGKILL: kill",
+ /* 10 */ 0, "SIGUSR1: user-defined signal 1",
+ /* 11 */ C, "SIGSEGV: segmentation violation",
+ /* 12 */ 0, "SIGUSR2: user-defined signal 2",
+ /* 13 */ I, "SIGPIPE: write to broken pipe",
+ /* 14 */ 0, "SIGALRM: alarm clock",
+ /* 15 */ 0, "SIGTERM: termination",
+ /* 16 */ 0, "SIGSTKFLT: stack fault",
+ /* 17 */ I+R, "SIGCHLD: child status has changed",
+ /* 18 */ 0, "SIGCONT: continue",
+ /* 19 */ 0, "SIGSTOP: stop, unblockable",
+ /* 20 */ 0, "SIGTSTP: keyboard stop",
+ /* 21 */ 0, "SIGTTIN: background read from tty",
+ /* 22 */ 0, "SIGTTOU: background write to tty",
+ /* 23 */ 0, "SIGURG: urgent condition on socket",
+ /* 24 */ 0, "SIGXCPU: cpu limit exceeded",
+ /* 25 */ 0, "SIGXFSZ: file size limit exceeded",
+ /* 26 */ 0, "SIGVTALRM: virtual alarm clock",
+ /* 27 */ 0, "SIGPROF: profiling alarm clock",
+ /* 28 */ I+R, "SIGWINCH: window size change",
+ /* 29 */ 0, "SIGIO: i/o now possible",
+ /* 30 */ 0, "SIGPWR: power failure restart",
+ /* 31 */ C, "SIGSYS: bad system call",
+};
+#undef C
+#undef I
+#undef R
+
+#define NSIG 32
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/linux/thread.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/linux/thread.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,282 @@
+// Copyright 2009 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.
+
+#include "runtime.h"
+#include "defs.h"
+#include "signals.h"
+#include "os.h"
+
+// Linux futex.
+//
+// futexsleep(uint32 *addr, uint32 val)
+// futexwakeup(uint32 *addr)
+//
+// Futexsleep atomically checks if *addr == val and if so, sleeps on addr.
+// Futexwakeup wakes up one thread sleeping on addr.
+// Futexsleep is allowed to wake up spuriously.
+
+enum
+{
+ FUTEX_WAIT = 0,
+ FUTEX_WAKE = 1,
+
+ EINTR = 4,
+ EAGAIN = 11,
+};
+
+// TODO(rsc): I tried using 1<<40 here but futex woke up (-ETIMEDOUT).
+// I wonder if the timespec that gets to the kernel
+// actually has two 32-bit numbers in it, so that
+// a 64-bit 1<<40 ends up being 0 seconds,
+// 1<<8 nanoseconds.
+static Timespec longtime =
+{
+ 1<<30, // 34 years
+ 0
+};
+
+// Atomically,
+// if(*addr == val) sleep
+// Might be woken up spuriously; that's allowed.
+static void
+futexsleep(uint32 *addr, uint32 val)
+{
+ int64 ret;
+
+ ret = futex(addr, FUTEX_WAIT, val, &longtime, nil, 0);
+ if(ret >= 0 || ret == -EAGAIN || ret == -EINTR)
+ return;
+
+ prints("futexsleep addr=");
+ sys·printpointer(addr);
+ prints(" val=");
+ sys·printint(val);
+ prints(" returned ");
+ sys·printint(ret);
+ prints("\n");
+ *(int32*)0x1005 = 0x1005;
+}
+
+// If any procs are sleeping on addr, wake up at least one.
+static void
+futexwakeup(uint32 *addr)
+{
+ int64 ret;
+
+ ret = futex(addr, FUTEX_WAKE, 1, nil, nil, 0);
+
+ if(ret >= 0)
+ return;
+
+ // I don't know that futex wakeup can return
+ // EAGAIN or EINTR, but if it does, it would be
+ // safe to loop and call futex again.
+
+ prints("futexwakeup addr=");
+ sys·printpointer(addr);
+ prints(" returned ");
+ sys·printint(ret);
+ prints("\n");
+ *(int32*)0x1006 = 0x1006;
+}
+
+
+// Lock and unlock.
+//
+// The lock state is a single 32-bit word that holds
+// a 31-bit count of threads waiting for the lock
+// and a single bit (the low bit) saying whether the lock is held.
+// The uncontended case runs entirely in user space.
+// When contention is detected, we defer to the kernel (futex).
+//
+// A reminder: compare-and-swap cas(addr, old, new) does
+// if(*addr == old) { *addr = new; return 1; }
+// else return 0;
+// but atomically.
+
+static void
+futexlock(Lock *l)
+{
+ uint32 v;
+
+again:
+ v = l->key;
+ if((v&1) == 0){
+ if(cas(&l->key, v, v|1)){
+ // Lock wasn't held; we grabbed it.
+ return;
+ }
+ goto again;
+ }
+
+ // Lock was held; try to add ourselves to the waiter count.
+ if(!cas(&l->key, v, v+2))
+ goto again;
+
+ // We're accounted for, now sleep in the kernel.
+ //
+ // We avoid the obvious lock/unlock race because
+ // the kernel won't put us to sleep if l->key has
+ // changed underfoot and is no longer v+2.
+ //
+ // We only really care that (v&1) == 1 (the lock is held),
+ // and in fact there is a futex variant that could
+ // accomodate that check, but let's not get carried away.)
+ futexsleep(&l->key, v+2);
+
+ // We're awake: remove ourselves from the count.
+ for(;;){
+ v = l->key;
+ if(v < 2)
+ throw("bad lock key");
+ if(cas(&l->key, v, v-2))
+ break;
+ }
+
+ // Try for the lock again.
+ goto again;
+}
+
+static void
+futexunlock(Lock *l)
+{
+ uint32 v;
+
+ // Atomically get value and clear lock bit.
+again:
+ v = l->key;
+ if((v&1) == 0)
+ throw("unlock of unlocked lock");
+ if(!cas(&l->key, v, v&~1))
+ goto again;
+
+ // If there were waiters, wake one.
+ if(v & ~1)
+ futexwakeup(&l->key);
+}
+
+void
+lock(Lock *l)
+{
+ if(m->locks < 0)
+ throw("lock count");
+ m->locks++;
+ futexlock(l);
+}
+
+void
+unlock(Lock *l)
+{
+ m->locks--;
+ if(m->locks < 0)
+ throw("lock count");
+ futexunlock(l);
+}
+
+
+// One-time notifications.
+//
+// Since the lock/unlock implementation already
+// takes care of sleeping in the kernel, we just reuse it.
+// (But it's a weird use, so it gets its own interface.)
+//
+// We use a lock to represent the event:
+// unlocked == event has happened.
+// Thus the lock starts out locked, and to wait for the
+// event you try to lock the lock. To signal the event,
+// you unlock the lock.
+
+void
+noteclear(Note *n)
+{
+ n->lock.key = 0; // memset(n, 0, sizeof *n)
+ futexlock(&n->lock);
+}
+
+void
+notewakeup(Note *n)
+{
+ futexunlock(&n->lock);
+}
+
+void
+notesleep(Note *n)
+{
+ futexlock(&n->lock);
+ futexunlock(&n->lock); // Let other sleepers find out too.
+}
+
+
+// Clone, the Linux rfork.
+enum
+{
+ CLONE_VM = 0x100,
+ CLONE_FS = 0x200,
+ CLONE_FILES = 0x400,
+ CLONE_SIGHAND = 0x800,
+ CLONE_PTRACE = 0x2000,
+ CLONE_VFORK = 0x4000,
+ CLONE_PARENT = 0x8000,
+ CLONE_THREAD = 0x10000,
+ CLONE_NEWNS = 0x20000,
+ CLONE_SYSVSEM = 0x40000,
+ CLONE_SETTLS = 0x80000,
+ CLONE_PARENT_SETTID = 0x100000,
+ CLONE_CHILD_CLEARTID = 0x200000,
+ CLONE_UNTRACED = 0x800000,
+ CLONE_CHILD_SETTID = 0x1000000,
+ CLONE_STOPPED = 0x2000000,
+ CLONE_NEWUTS = 0x4000000,
+ CLONE_NEWIPC = 0x8000000,
+};
+
+void
+newosproc(M *m, G *g, void *stk, void (*fn)(void))
+{
+ int64 ret;
+ int32 flags;
+
+ /*
+ * note: strace gets confused if we use CLONE_PTRACE here.
+ */
+ flags = CLONE_PARENT /* getppid doesn't change in child */
+ | CLONE_VM /* share memory */
+ | CLONE_FS /* share cwd, etc */
+ | CLONE_FILES /* share fd table */
+ | CLONE_SIGHAND /* share sig handler table */
+ | CLONE_THREAD /* revisit - okay for now */
+ ;
+
+ if(0){
+ prints("newosproc stk=");
+ sys·printpointer(stk);
+ prints(" m=");
+ sys·printpointer(m);
+ prints(" g=");
+ sys·printpointer(g);
+ prints(" fn=");
+ sys·printpointer(fn);
+ prints(" clone=");
+ sys·printpointer(clone);
+ prints("\n");
+ }
+
+ ret = clone(flags, stk, m, g, fn);
+ if(ret < 0)
+ *(int32*)123 = 123;
+}
+
+void
+osinit(void)
+{
+}
+
+// Called to initialize a new m (including the bootstrap m).
+void
+minit(void)
+{
+ // Initialize signal handling.
+ m->gsignal = malg(32*1024); // OS X wants >=8K, Linux >=2K
+ signalstack(m->gsignal->stackguard, 32*1024);
+}
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/malloc.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/malloc.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,308 @@
+// Copyright 2009 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.
+
+// See malloc.h for overview.
+//
+// TODO(rsc): double-check stats.
+// TODO(rsc): solve "stack overflow during malloc" problem.
+
+#include "runtime.h"
+#include "malloc.h"
+#include "defs.h"
+
+MHeap mheap;
+MStats mstats;
+
+// Allocate an object of at least size bytes.
+// Small objects are allocated from the per-thread cache's free lists.
+// Large objects (> 32 kB) are allocated straight from the heap.
+void*
+malloc(uintptr size)
+{
+ int32 sizeclass;
+ MCache *c;
+ uintptr npages;
+ MSpan *s;
+ void *v;
+ uint32 *ref;
+
+ if(m->mallocing)
+ throw("malloc/free - deadlock");
+ m->mallocing = 1;
+
+ if(size == 0)
+ size = 1;
+
+ if(size <= MaxSmallSize) {
+ // Allocate from mcache free lists.
+ sizeclass = SizeToClass(size);
+ size = class_to_size[sizeclass];
+ c = m->mcache;
+ v = MCache_Alloc(c, sizeclass, size);
+ if(v == nil)
+ throw("out of memory");
+ mstats.alloc += size;
+ } else {
+ // TODO(rsc): Report tracebacks for very large allocations.
+
+ // Allocate directly from heap.
+ npages = size >> PageShift;
+ if((size & PageMask) != 0)
+ npages++;
+ s = MHeap_Alloc(&mheap, npages, 0);
+ if(s == nil)
+ throw("out of memory");
+ mstats.alloc += npages<<PageShift;
+ v = (void*)(s->start << PageShift);
+ }
+
+ // setup for mark sweep
+ if(!mlookup(v, nil, nil, &ref)) {
+ printf("malloc %D; mlookup failed\n", (uint64)size);
+ throw("malloc mlookup");
+ }
+ *ref = RefNone;
+
+ m->mallocing = 0;
+ return v;
+}
+
+void*
+mallocgc(uintptr size)
+{
+ void *v;
+
+ v = malloc(size);
+ if(mstats.inuse_pages > mstats.next_gc)
+ gc(0);
+ return v;
+}
+
+// Free the object whose base pointer is v.
+void
+free(void *v)
+{
+ int32 sizeclass, size;
+ uintptr page, tmp;
+ MSpan *s;
+ MCache *c;
+ uint32 *ref;
+
+ if(v == nil)
+ return;
+
+ if(m->mallocing)
+ throw("malloc/free - deadlock");
+ m->mallocing = 1;
+
+ if(!mlookup(v, nil, nil, &ref))
+ throw("free mlookup");
+ *ref = RefFree;
+
+ // Find size class for v.
+ page = (uintptr)v >> PageShift;
+ sizeclass = MHeapMapCache_GET(&mheap.mapcache, page, tmp);
+ if(sizeclass == 0) {
+ // Missed in cache.
+ s = MHeap_Lookup(&mheap, page);
+ if(s == nil)
+ throw("free - invalid pointer");
+ sizeclass = s->sizeclass;
+ if(sizeclass == 0) {
+ // Large object.
+ mstats.alloc -= s->npages<<PageShift;
+ sys_memclr(v, s->npages<<PageShift);
+ MHeap_Free(&mheap, s);
+ goto out;
+ }
+ MHeapMapCache_SET(&mheap.mapcache, page, sizeclass);
+ }
+
+ // Small object.
+ c = m->mcache;
+ size = class_to_size[sizeclass];
+ sys_memclr(v, size);
+ mstats.alloc -= size;
+ MCache_Free(c, v, sizeclass, size);
+
+out:
+ m->mallocing = 0;
+}
+
+int32
+mlookup(void *v, byte **base, uintptr *size, uint32 **ref)
+{
+ uintptr n, nobj, i;
+ byte *p;
+ MSpan *s;
+
+ s = MHeap_LookupMaybe(&mheap, (uintptr)v>>PageShift);
+ if(s == nil) {
+ if(base)
+ *base = nil;
+ if(size)
+ *size = 0;
+ if(ref)
+ *ref = 0;
+ return 0;
+ }
+
+ p = (byte*)((uintptr)s->start<<PageShift);
+ if(s->sizeclass == 0) {
+ // Large object.
+ if(base)
+ *base = p;
+ if(size)
+ *size = s->npages<<PageShift;
+ if(ref)
+ *ref = &s->gcref0;
+ return 1;
+ }
+
+ if((byte*)v >= (byte*)s->gcref) {
+ // pointers into the gc ref counts
+ // do not count as pointers.
+ return 0;
+ }
+
+ n = class_to_size[s->sizeclass];
+ i = ((byte*)v - p)/n;
+ if(base)
+ *base = p + i*n;
+ if(size)
+ *size = n;
+ nobj = (s->npages << PageShift) / (n + RefcountOverhead);
+ if((byte*)s->gcref < p || (byte*)(s->gcref+nobj) > p+(s->npages<<PageShift)) {
+ printf("odd span state=%d span=%p base=%p sizeclass=%d n=%D size=%D npages=%D\n",
+ s->state, s, p, s->sizeclass, (uint64)nobj, (uint64)n, (uint64)s->npages);
+ printf("s->base sizeclass %d v=%p base=%p gcref=%p blocksize=%D nobj=%D size=%D end=%p end=%p\n",
+ s->sizeclass, v, p, s->gcref, (uint64)s->npages<<PageShift,
+ (uint64)nobj, (uint64)n, s->gcref + nobj, p+(s->npages<<PageShift));
+ throw("bad gcref");
+ }
+ if(ref)
+ *ref = &s->gcref[i];
+
+ return 1;
+}
+
+MCache*
+allocmcache(void)
+{
+ return FixAlloc_Alloc(&mheap.cachealloc);
+}
+
+void
+mallocinit(void)
+{
+ InitSizes();
+ MHeap_Init(&mheap, SysAlloc);
+ m->mcache = allocmcache();
+
+ // See if it works.
+ free(malloc(1));
+}
+
+void*
+SysAlloc(uintptr n)
+{
+ mstats.sys += n;
+ return sys_mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, -1, 0);
+}
+
+void
+SysUnused(void *v, uintptr n)
+{
+ USED(v);
+ USED(n);
+ // TODO(rsc): call madvise MADV_DONTNEED
+}
+
+void
+SysFree(void *v, uintptr n)
+{
+ USED(v);
+ USED(n);
+ // TODO(rsc): call munmap
+}
+
+// Runtime stubs.
+
+extern void *oldmal(uint32);
+
+void*
+mal(uint32 n)
+{
+//return oldmal(n);
+ void *v;
+
+ v = mallocgc(n);
+
+ if(0) {
+ byte *p;
+ uint32 i;
+ p = v;
+ for(i=0; i<n; i++) {
+ if(p[i] != 0) {
+ printf("mal %d => %p: byte %d is non-zero\n", n, v, i);
+ throw("mal");
+ }
+ }
+ }
+
+//printf("mal %d %p\n", n, v); // |checkmal to check for overlapping returns.
+ return v;
+}
+
+// Stack allocator uses malloc/free most of the time,
+// but if we're in the middle of malloc and need stack,
+// we have to do something else to avoid deadlock.
+// In that case, we fall back on a fixed-size free-list
+// allocator, assuming that inside malloc all the stack
+// frames are small, so that all the stack allocations
+// will be a single size, the minimum (right now, 5k).
+struct {
+ Lock;
+ FixAlloc;
+} stacks;
+
+void*
+stackalloc(uint32 n)
+{
+ void *v;
+ uint32 *ref;
+
+//return oldmal(n);
+ if(m->mallocing) {
+ lock(&stacks);
+ if(stacks.size == 0)
+ FixAlloc_Init(&stacks, n, SysAlloc, nil, nil);
+ if(stacks.size != n) {
+ printf("stackalloc: in malloc, size=%D want %d", (uint64)stacks.size, n);
+ throw("stackalloc");
+ }
+ v = FixAlloc_Alloc(&stacks);
+ unlock(&stacks);
+ return v;
+ }
+ v = malloc(n);
+ if(!mlookup(v, nil, nil, &ref))
+ throw("stackalloc mlookup");
+ *ref = RefStack;
+ return v;
+}
+
+void
+stackfree(void *v)
+{
+//return;
+
+ if(m->mallocing) {
+ lock(&stacks);
+ FixAlloc_Free(&stacks, v);
+ unlock(&stacks);
+ return;
+ }
+ free(v);
+}
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/malloc.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/malloc.h Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,308 @@
+// Copyright 2009 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.
+
+// Memory allocator, based on tcmalloc.
+// http://goog-perftools.sourceforge.net/doc/tcmalloc.html
+
+// The main allocator works in runs of pages.
+// Small allocation sizes (up to and including 32 kB) are
+// rounded to one of about 100 size classes, each of which
+// has its own free list of objects of exactly that size.
+// Any free page of memory can be split into a set of objects
+// of one size class, which are then managed using free list
+// allocators.
+//
+// The allocator's data structures are:
+//
+// FixAlloc: a free-list allocator for fixed-size objects,
+// used to manage storage used by the allocator.
+// MHeap: the malloc heap, managed at page (4096-byte) granularity.
+// MSpan: a run of pages managed by the MHeap.
+// MHeapMap: a mapping from page IDs to MSpans.
+// MHeapMapCache: a small cache of MHeapMap mapping page IDs
+// to size classes for pages used for small objects.
+// MCentral: a shared free list for a given size class.
+// MCache: a per-thread (in Go, per-M) cache for small objects.
+// MStats: allocation statistics.
+//
+// Allocating a small object proceeds up a hierarchy of caches:
+//
+// 1. Round the size up to one of the small size classes
+// and look in the corresponding MCache free list.
+// If the list is not empty, allocate an object from it.
+// This can all be done without acquiring a lock.
+//
+// 2. If the MCache free list is empty, replenish it by
+// taking a bunch of objects from the MCentral free list.
+// Moving a bunch amortizes the cost of acquiring the MCentral lock.
+//
+// 3. If the MCentral free list is empty, replenish it by
+// allocating a run of pages from the MHeap and then
+// chopping that memory into a objects of the given size.
+// Allocating many objects amortizes the cost of locking
+// the heap.
+//
+// 4. If the MHeap is empty or has no page runs large enough,
+// allocate a new group of pages (at least 1MB) from the
+// operating system. Allocating a large run of pages
+// amortizes the cost of talking to the operating system.
+//
+// Freeing a small object proceeds up the same hierarchy:
+//
+// 1. Look up the size class for the object and add it to
+// the MCache free list.
+//
+// 2. If the MCache free list is too long or the MCache has
+// too much memory, return some to the MCentral free lists.
+//
+// 3. If all the objects in a given span have returned to
+// the MCentral list, return that span to the page heap.
+//
+// 4. If the heap has too much memory, return some to the
+// operating system.
+//
+// TODO(rsc): Step 4 is not implemented.
+//
+// Allocating and freeing a large object uses the page heap
+// directly, bypassing the MCache and MCentral free lists.
+//
+// This C code was written with an eye toward translating to Go
+// in the future. Methods have the form Type_Method(Type *t, ...).
+
+
+typedef struct FixAlloc FixAlloc;
+typedef struct MCentral MCentral;
+typedef struct MHeap MHeap;
+typedef struct MHeapMap MHeapMap;
+typedef struct MHeapMapCache MHeapMapCache;
+typedef struct MSpan MSpan;
+typedef struct MStats MStats;
+typedef struct MLink MLink;
+
+enum
+{
+ PageShift = 12,
+ PageSize = 1<<PageShift,
+ PageMask = PageSize - 1,
+};
+typedef uintptr PageID; // address >> PageShift
+
+enum
+{
+ // Tunable constants.
+ NumSizeClasses = 67, // Number of size classes (must match msize.c)
+ MaxSmallSize = 32<<10,
+
+ FixAllocChunk = 128<<10, // Chunk size for FixAlloc
+ MaxMCacheListLen = 256, // Maximum objects on MCacheList
+ MaxMCacheSize = 2<<20, // Maximum bytes in one MCache
+ MaxMHeapList = 1<<(20 - PageShift), // Maximum page length for fixed-size list in MHeap.
+ HeapAllocChunk = 1<<20, // Chunk size for heap growth
+};
+
+#ifdef _64BIT
+#include "mheapmap64.h"
+#else
+#include "mheapmap32.h"
+#endif
+
+// A generic linked list of blocks. (Typically the block is bigger than sizeof(MLink).)
+struct MLink
+{
+ MLink *next;
+};
+
+// SysAlloc obtains a large chunk of memory from the operating system,
+// typically on the order of a hundred kilobytes or a megabyte.
+//
+// SysUnused notifies the operating system that the contents
+// of the memory region are no longer needed and can be reused
+// for other purposes. The program reserves the right to start
+// accessing those pages in the future.
+//
+// SysFree returns it unconditionally; this is only used if
+// an out-of-memory error has been detected midway through
+// an allocation. It is okay if SysFree is a no-op.
+
+void* SysAlloc(uintptr nbytes);
+void SysFree(void *v, uintptr nbytes);
+void SysUnused(void *v, uintptr nbytes);
+
+
+// FixAlloc is a simple free-list allocator for fixed size objects.
+// Malloc uses a FixAlloc wrapped around SysAlloc to manages its
+// MCache and MSpan objects.
+//
+// Memory returned by FixAlloc_Alloc is not zeroed.
+// The caller is responsible for locking around FixAlloc calls.
+// Callers can keep state in the object but the first word is
+// smashed by freeing and reallocating.
+struct FixAlloc
+{
+ uintptr size;
+ void *(*alloc)(uintptr);
+ void (*first)(void *arg, byte *p); // called first time p is returned
+ void *arg;
+ MLink *list;
+ byte *chunk;
+ uint32 nchunk;
+};
+
+void FixAlloc_Init(FixAlloc *f, uintptr size, void *(*alloc)(uintptr), void (*first)(void*, byte*), void *arg);
+void* FixAlloc_Alloc(FixAlloc *f);
+void FixAlloc_Free(FixAlloc *f, void *p);
+
+
+// Statistics.
+// Shared with Go: if you edit this structure, also edit ../lib/malloc.go.
+struct MStats
+{
+ uint64 alloc;
+ uint64 sys;
+ uint64 stacks;
+ uint64 inuse_pages; // protected by mheap.Lock
+ uint64 next_gc; // protected by mheap.Lock
+ bool enablegc;
+};
+extern MStats mstats;
+
+
+// Size classes. Computed and initialized by InitSizes.
+//
+// SizeToClass(0 <= n <= MaxSmallSize) returns the size class,
+// 1 <= sizeclass < NumSizeClasses, for n.
+// Size class 0 is reserved to mean "not small".
+//
+// class_to_size[i] = largest size in class i
+// class_to_allocnpages[i] = number of pages to allocate when
+// making new objects in class i
+// class_to_transfercount[i] = number of objects to move when
+// taking a bunch of objects out of the central lists
+// and putting them in the thread free list.
+
+int32 SizeToClass(int32);
+extern int32 class_to_size[NumSizeClasses];
+extern int32 class_to_allocnpages[NumSizeClasses];
+extern int32 class_to_transfercount[NumSizeClasses];
+extern void InitSizes(void);
+
+
+// Per-thread (in Go, per-M) cache for small objects.
+// No locking needed because it is per-thread (per-M).
+typedef struct MCacheList MCacheList;
+struct MCacheList
+{
+ MLink *list;
+ uint32 nlist;
+ uint32 nlistmin;
+};
+
+struct MCache
+{
+ MCacheList list[NumSizeClasses];
+ uint64 size;
+};
+
+void* MCache_Alloc(MCache *c, int32 sizeclass, uintptr size);
+void MCache_Free(MCache *c, void *p, int32 sizeclass, uintptr size);
+
+
+// An MSpan is a run of pages.
+enum
+{
+ MSpanInUse = 0,
+ MSpanFree,
+ MSpanListHead,
+ MSpanDead,
+};
+struct MSpan
+{
+ MSpan *next; // in a span linked list
+ MSpan *prev; // in a span linked list
+ MSpan *allnext; // in the list of all spans
+ PageID start; // starting page number
+ uintptr npages; // number of pages in span
+ MLink *freelist; // list of free objects
+ uint32 ref; // number of allocated objects in this span
+ uint32 sizeclass; // size class
+ uint32 state; // MSpanInUse etc
+ union {
+ uint32 *gcref; // sizeclass > 0
+ uint32 gcref0; // sizeclass == 0
+ };
+};
+
+void MSpan_Init(MSpan *span, PageID start, uintptr npages);
+
+// Every MSpan is in one doubly-linked list,
+// either one of the MHeap's free lists or one of the
+// MCentral's span lists. We use empty MSpan structures as list heads.
+void MSpanList_Init(MSpan *list);
+bool MSpanList_IsEmpty(MSpan *list);
+void MSpanList_Insert(MSpan *list, MSpan *span);
+void MSpanList_Remove(MSpan *span); // from whatever list it is in
+
+
+// Central list of free objects of a given size.
+struct MCentral
+{
+ Lock;
+ int32 sizeclass;
+ MSpan nonempty;
+ MSpan empty;
+ int32 nfree;
+};
+
+void MCentral_Init(MCentral *c, int32 sizeclass);
+int32 MCentral_AllocList(MCentral *c, int32 n, MLink **first);
+void MCentral_FreeList(MCentral *c, int32 n, MLink *first);
+
+// Main malloc heap.
+// The heap itself is the "free[]" and "large" arrays,
+// but all the other global data is here too.
+struct MHeap
+{
+ Lock;
+ MSpan free[MaxMHeapList]; // free lists of given length
+ MSpan large; // free lists length >= MaxMHeapList
+ MSpan *allspans;
+
+ // span lookup
+ MHeapMap map;
+ MHeapMapCache mapcache;
+
+ // central free lists for small size classes.
+ // the union makes sure that the MCentrals are
+ // spaced 64 bytes apart, so that each MCentral.Lock
+ // gets its own cache line.
+ union {
+ MCentral;
+ byte pad[64];
+ } central[NumSizeClasses];
+
+ FixAlloc spanalloc; // allocator for Span*
+ FixAlloc cachealloc; // allocator for MCache*
+};
+extern MHeap mheap;
+
+void MHeap_Init(MHeap *h, void *(*allocator)(uintptr));
+MSpan* MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass);
+void MHeap_Free(MHeap *h, MSpan *s);
+MSpan* MHeap_Lookup(MHeap *h, PageID p);
+MSpan* MHeap_LookupMaybe(MHeap *h, PageID p);
+
+int32 mlookup(void *v, byte **base, uintptr *size, uint32 **ref);
+void gc(int32 force);
+
+enum
+{
+ RefcountOverhead = 4, // one uint32 per object
+
+ RefFree = 0, // must be zero
+ RefManual, // manual allocation - don't free
+ RefStack, // stack segment - don't free and don't scan for pointers
+ RefNone, // no references
+ RefSome, // some references
+};
+
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/malloc_go.cgo
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/malloc_go.cgo Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,28 @@
+// Copyright 2009 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 malloc
+#include "runtime.h"
+#include "malloc.h"
+
+func Alloc(n uintptr) (p *byte) {
+ p = malloc(n);
+}
+
+func Free(p *byte) {
+ free(p);
+}
+
+func Lookup(p *byte) (base *byte, size uintptr) {
+ mlookup(p, &base, &size, nil);
+}
+
+func GetStats() (s *MStats) {
+ s = &mstats;
+}
+
+func GC() {
+ gc(1);
+}
+
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/mcache.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/mcache.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,105 @@
+// Copyright 2009 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.
+
+// Per-thread (in Go, per-M) malloc cache for small objects.
+//
+// See malloc.h for an overview.
+
+#include "runtime.h"
+#include "malloc.h"
+
+void*
+MCache_Alloc(MCache *c, int32 sizeclass, uintptr size)
+{
+ MCacheList *l;
+ MLink *first, *v;
+ int32 n;
+
+ // Allocate from list.
+ l = &c->list[sizeclass];
+ if(l->list == nil) {
+ // Replenish using central lists.
+ n = MCentral_AllocList(&mheap.central[sizeclass],
+ class_to_transfercount[sizeclass], &first);
+ l->list = first;
+ l->nlist = n;
+ c->size += n*size;
+ }
+ v = l->list;
+ l->list = v->next;
+ l->nlist--;
+ if(l->nlist < l->nlistmin)
+ l->nlistmin = l->nlist;
+ c->size -= size;
+
+ // v is zeroed except for the link pointer
+ // that we used above; zero that.
+ v->next = nil;
+ return v;
+}
+
+// Take n elements off l and return them to the central free list.
+static void
+ReleaseN(MCache *c, MCacheList *l, int32 n, int32 sizeclass)
+{
+ MLink *first, **lp;
+ int32 i;
+
+ // Cut off first n elements.
+ first = l->list;
+ lp = &l->list;
+ for(i=0; i<n; i++)
+ lp = &(*lp)->next;
+ l->list = *lp;
+ *lp = nil;
+ l->nlist -= n;
+ if(l->nlist < l->nlistmin)
+ l->nlistmin = l->nlist;
+ c->size -= n*class_to_size[sizeclass];
+
+ // Return them to central free list.
+ MCentral_FreeList(&mheap.central[sizeclass], n, first);
+}
+
+void
+MCache_Free(MCache *c, void *v, int32 sizeclass, uintptr size)
+{
+ int32 i, n;
+ MCacheList *l;
+ MLink *p;
+
+ // Put back on list.
+ l = &c->list[sizeclass];
+ p = v;
+ p->next = l->list;
+ l->list = p;
+ l->nlist++;
+ c->size += size;
+
+ if(l->nlist >= MaxMCacheListLen) {
+ // Release a chunk back.
+ ReleaseN(c, l, class_to_transfercount[sizeclass], sizeclass);
+ }
+
+ if(c->size >= MaxMCacheSize) {
+ // Scavenge.
+ for(i=0; i<NumSizeClasses; i++) {
+ l = &c->list[i];
+ n = l->nlistmin;
+
+ // n is the minimum number of elements we've seen on
+ // the list since the last scavenge. If n > 0, it means that
+ // we could have gotten by with n fewer elements
+ // without needing to consult the central free list.
+ // Move toward that situation by releasing n/2 of them.
+ if(n > 0) {
+ if(n > 1)
+ n /= 2;
+ ReleaseN(c, l, n, i);
+ }
+ l->nlistmin = l->nlist;
+ }
+ }
+}
+
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/mcentral.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/mcentral.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,192 @@
+// Copyright 2009 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.
+
+// Central free lists.
+//
+// See malloc.h for an overview.
+//
+// The MCentral doesn't actually contain the list of free objects; the MSpan does.
+// Each MCentral is two lists of MSpans: those with free objects (c->nonempty)
+// and those that are completely allocated (c->empty).
+//
+// TODO(rsc): tcmalloc uses a "transfer cache" to split the list
+// into sections of class_to_transfercount[sizeclass] objects
+// so that it is faster to move those lists between MCaches and MCentrals.
+
+#include "runtime.h"
+#include "malloc.h"
+
+static bool MCentral_Grow(MCentral *c);
+static void* MCentral_Alloc(MCentral *c);
+static void MCentral_Free(MCentral *c, void *v);
+
+// Initialize a single central free list.
+void
+MCentral_Init(MCentral *c, int32 sizeclass)
+{
+ c->sizeclass = sizeclass;
+ MSpanList_Init(&c->nonempty);
+ MSpanList_Init(&c->empty);
+}
+
+// Allocate up to n objects from the central free list.
+// Return the number of objects allocated.
+// The objects are linked together by their first words.
+// On return, *pstart points at the first object and *pend at the last.
+int32
+MCentral_AllocList(MCentral *c, int32 n, MLink **pfirst)
+{
+ MLink *first, *last, *v;
+ int32 i;
+
+
+ lock(c);
+ // Replenish central list if empty.
+ if(MSpanList_IsEmpty(&c->nonempty)) {
+ if(!MCentral_Grow(c)) {
+ unlock(c);
+ *pfirst = nil;
+ return 0;
+ }
+ }
+
+ // Copy from list, up to n.
+ // First one is guaranteed to work, because we just grew the list.
+ first = MCentral_Alloc(c);
+ last = first;
+ for(i=1; i<n && (v = MCentral_Alloc(c)) != nil; i++) {
+ last->next = v;
+ last = v;
+ }
+ last->next = nil;
+ c->nfree -= i;
+
+ unlock(c);
+ *pfirst = first;
+ return i;
+}
+
+// Helper: allocate one object from the central free list.
+static void*
+MCentral_Alloc(MCentral *c)
+{
+ MSpan *s;
+ MLink *v;
+
+ if(MSpanList_IsEmpty(&c->nonempty))
+ return nil;
+ s = c->nonempty.next;
+ s->ref++;
+ v = s->freelist;
+ s->freelist = v->next;
+ if(s->freelist == nil) {
+ MSpanList_Remove(s);
+ MSpanList_Insert(&c->empty, s);
+ }
+ return v;
+}
+
+// Free n objects back into the central free list.
+// Return the number of objects allocated.
+// The objects are linked together by their first words.
+// On return, *pstart points at the first object and *pend at the last.
+void
+MCentral_FreeList(MCentral *c, int32 n, MLink *start)
+{
+ MLink *v, *next;
+
+ // Assume next == nil marks end of list.
+ // n and end would be useful if we implemented
+ // the transfer cache optimization in the TODO above.
+ USED(n);
+
+ lock(c);
+ for(v=start; v; v=next) {
+ next = v->next;
+ MCentral_Free(c, v);
+ }
+ unlock(c);
+}
+
+// Helper: free one object back into the central free list.
+static void
+MCentral_Free(MCentral *c, void *v)
+{
+ MSpan *s;
+ PageID page;
+ MLink *p, *next;
+
+ // Find span for v.
+ page = (uintptr)v >> PageShift;
+ s = MHeap_Lookup(&mheap, page);
+ if(s == nil || s->ref == 0)
+ throw("invalid free");
+
+ // Move to nonempty if necessary.
+ if(s->freelist == nil) {
+ MSpanList_Remove(s);
+ MSpanList_Insert(&c->nonempty, s);
+ }
+
+ // Add v back to s's free list.
+ p = v;
+ p->next = s->freelist;
+ s->freelist = p;
+ c->nfree++;
+
+ // If s is completely freed, return it to the heap.
+ if(--s->ref == 0) {
+ MSpanList_Remove(s);
+ // Freed blocks are zeroed except for the link pointer.
+ // Zero the link pointers so that the page is all zero.
+ for(p=s->freelist; p; p=next) {
+ next = p->next;
+ p->next = nil;
+ }
+ s->freelist = nil;
+ c->nfree -= (s->npages << PageShift) / class_to_size[c->sizeclass];
+ unlock(c);
+ MHeap_Free(&mheap, s);
+ lock(c);
+ }
+}
+
+// Fetch a new span from the heap and
+// carve into objects for the free list.
+static bool
+MCentral_Grow(MCentral *c)
+{
+ int32 i, n, npages, size;
+ MLink **tailp, *v;
+ byte *p;
+ MSpan *s;
+
+ unlock(c);
+ npages = class_to_allocnpages[c->sizeclass];
+ s = MHeap_Alloc(&mheap, npages, c->sizeclass);
+ if(s == nil) {
+ // TODO(rsc): Log out of memory
+ lock(c);
+ return false;
+ }
+
+ // Carve span into sequence of blocks.
+ tailp = &s->freelist;
+ p = (byte*)(s->start << PageShift);
+ size = class_to_size[c->sizeclass];
+ n = (npages << PageShift) / (size + RefcountOverhead);
+ s->gcref = (uint32*)(p + size*n);
+ for(i=0; i<n; i++) {
+ v = (MLink*)p;
+ *tailp = v;
+ tailp = &v->next;
+ p += size;
+ }
+ *tailp = nil;
+
+ lock(c);
+ c->nfree += n;
+ MSpanList_Insert(&c->nonempty, s);
+ return true;
+}
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/mem.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/mem.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,75 @@
+// Copyright 2009 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.
+
+#include "runtime.h"
+#include "defs.h"
+
+// Stubs for memory management.
+// In a separate file so they can be overridden during testing of gc.
+
+enum
+{
+ NHUNK = 20<<20,
+};
+
+// Convenient wrapper around mmap.
+static void*
+brk(uint32 n)
+{
+ byte *v;
+
+ v = sys_mmap(nil, n, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, 0, 0);
+ m->mem.nmmap += n;
+ return v;
+}
+
+// Allocate n bytes of memory. Note that this gets used
+// to allocate new stack segments, so at each call to a function
+// you have to ask yourself "would it be okay to call mal recursively
+// right here?" The answer is yes unless we're in the middle of
+// editing the malloc state in m->mem.
+void*
+oldmal(uint32 n)
+{
+ byte* v;
+
+ // round to keep everything 64-bit aligned
+ n = rnd(n, 8);
+
+ // be careful. calling any function might invoke
+ // mal to allocate more stack.
+ if(n > NHUNK) {
+ v = brk(n);
+ } else {
+ // allocate a new hunk if this one is too small
+ if(n > m->mem.nhunk) {
+ // here we're in the middle of editing m->mem
+ // (we're about to overwrite m->mem.hunk),
+ // so we can't call brk - it might call mal to grow the
+ // stack, and the recursive call would allocate a new
+ // hunk, and then once brk returned we'd immediately
+ // overwrite that hunk with our own.
+ // (the net result would be a memory leak, not a crash.)
+ // so we have to call sys_mmap directly - it is written
+ // in assembly and tagged not to grow the stack.
+ m->mem.hunk =
+ sys_mmap(nil, NHUNK, PROT_READ|PROT_WRITE|PROT_EXEC,
+ MAP_ANON|MAP_PRIVATE, 0, 0);
+ m->mem.nhunk = NHUNK;
+ m->mem.nmmap += NHUNK;
+ }
+ v = m->mem.hunk;
+ m->mem.hunk += n;
+ m->mem.nhunk -= n;
+ }
+ m->mem.nmal += n;
+ return v;
+}
+
+void
+sys_mal(uint32 n, uint8 *ret)
+{
+ ret = mal(n);
+ FLUSH(&ret);
+}
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/mfixalloc.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/mfixalloc.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,56 @@
+// Copyright 2009 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.
+
+// Fixed-size object allocator. Returned memory is not zeroed.
+//
+// See malloc.h for overview.
+
+#include "runtime.h"
+#include "malloc.h"
+
+// Initialize f to allocate objects of the given size,
+// using the allocator to obtain chunks of memory.
+void
+FixAlloc_Init(FixAlloc *f, uintptr size, void *(*alloc)(uintptr), void (*first)(void*, byte*), void *arg)
+{
+ f->size = size;
+ f->alloc = alloc;
+ f->first = first;
+ f->arg = arg;
+ f->list = nil;
+ f->chunk = nil;
+ f->nchunk = 0;
+}
+
+void*
+FixAlloc_Alloc(FixAlloc *f)
+{
+ void *v;
+
+ if(f->list) {
+ v = f->list;
+ f->list = *(void**)f->list;
+ return v;
+ }
+ if(f->nchunk < f->size) {
+ f->chunk = f->alloc(FixAllocChunk);
+ if(f->chunk == nil)
+ throw("out of memory (FixAlloc)");
+ f->nchunk = FixAllocChunk;
+ }
+ v = f->chunk;
+ if(f->first)
+ f->first(f->arg, v);
+ f->chunk += f->size;
+ f->nchunk -= f->size;
+ return v;
+}
+
+void
+FixAlloc_Free(FixAlloc *f, void *p)
+{
+ *(void**)p = f->list;
+ f->list = p;
+}
+
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/mgc0.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/mgc0.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,231 @@
+// Copyright 2009 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.
+
+// Garbage collector -- step 0.
+//
+// Stop the world, mark and sweep garbage collector.
+// NOT INTENDED FOR PRODUCTION USE.
+//
+// A mark and sweep collector provides a way to exercise
+// and test the memory allocator and the stack walking machinery
+// without also needing to get reference counting
+// exactly right.
+
+#include "runtime.h"
+#include "malloc.h"
+
+enum {
+ Debug = 0
+};
+
+extern byte etext[];
+extern byte end[];
+
+enum {
+ PtrSize = sizeof(void*)
+};
+
+static void
+scanblock(int32 depth, byte *b, int64 n)
+{
+ int32 off;
+ void *obj;
+ uintptr size;
+ uint32 *ref;
+ void **vp;
+ int64 i;
+
+ if(Debug)
+ printf("%d scanblock %p %D\n", depth, b, n);
+ off = (uint32)(uintptr)b & (PtrSize-1);
+ if(off) {
+ b += PtrSize - off;
+ n -= PtrSize - off;
+ }
+
+ vp = (void**)b;
+ n /= PtrSize;
+ for(i=0; i<n; i++) {
+ if(mlookup(vp[i], &obj, &size, &ref)) {
+ if(*ref == RefFree || *ref == RefStack)
+ continue;
+ if(*ref == RefNone) {
+ if(Debug)
+ printf("%d found at %p: ", depth, &vp[i]);
+ *ref = RefSome;
+ scanblock(depth+1, obj, size);
+ }
+ }
+ }
+}
+
+static void
+scanstack(G *g)
+{
+ Stktop *stk;
+ byte *sp;
+
+ sp = g->sched.SP;
+ stk = (Stktop*)g->stackbase;
+ while(stk) {
+ scanblock(0, sp, (byte*)stk - sp);
+ sp = stk->oldsp;
+ stk = (Stktop*)stk->oldbase;
+ }
+}
+
+static void
+mark(void)
+{
+ G *gp;
+
+ // mark data+bss
+ scanblock(0, etext, end - etext);
+
+ // mark stacks
+ for(gp=allg; gp!=nil; gp=gp->alllink) {
+ switch(gp->status){
+ default:
+ printf("unexpected G.status %d\n", gp->status);
+ throw("mark - bad status");
+ case Gdead:
+ break;
+ case Grunning:
+ if(gp != g)
+ throw("mark - world not stopped");
+ scanstack(gp);
+ break;
+ case Grunnable:
+ case Gsyscall:
+ case Gwaiting:
+ scanstack(gp);
+ break;
+ }
+ }
+}
+
+static void
+sweepspan(MSpan *s)
+{
+ int32 i, n, npages, size;
+ byte *p;
+
+ if(s->state != MSpanInUse)
+ return;
+
+ p = (byte*)(s->start << PageShift);
+ if(s->sizeclass == 0) {
+ // Large block.
+ switch(s->gcref0) {
+ default:
+ throw("bad 'ref count'");
+ case RefFree:
+ case RefManual:
+ case RefStack:
+ break;
+ case RefNone:
+ if(Debug)
+ printf("free %D at %p\n", (uint64)s->npages<<PageShift, p);
+ free(p);
+ break;
+ case RefSome:
+ s->gcref0 = RefNone; // set up for next mark phase
+ break;
+ }
+ return;
+ }
+
+ // Chunk full of small blocks.
+ // Must match computation in MCentral_Grow.
+ size = class_to_size[s->sizeclass];
+ npages = class_to_allocnpages[s->sizeclass];
+ n = (npages << PageShift) / (size + RefcountOverhead);
+ for(i=0; i<n; i++) {
+ switch(s->gcref[i]) {
+ default:
+ throw("bad 'ref count'");
+ case RefFree:
+ case RefManual:
+ case RefStack:
+ break;
+ case RefNone:
+ if(Debug)
+ printf("free %d at %p\n", size, p+i*size);
+ free(p + i*size);
+ break;
+ case RefSome:
+ s->gcref[i] = RefNone; // set up for next mark phase
+ break;
+ }
+ }
+}
+
+static void
+sweep(void)
+{
+ MSpan *s;
+
+ // Sweep all the spans.
+ for(s = mheap.allspans; s != nil; s = s->allnext)
+ sweepspan(s);
+}
+
+// Semaphore, not Lock, so that the goroutine
+// reschedules when there is contention rather
+// than spinning.
+static uint32 gcsema = 1;
+
+// Initialized from $GOGC. GOGC=off means no gc.
+//
+// Next gc is after we've allocated an extra amount of
+// memory proportional to the amount already in use.
+// If gcpercent=100 and we're using 4M, we'll gc again
+// when we get to 8M. This keeps the gc cost in linear
+// proportion to the allocation cost. Adjusting gcpercent
+// just changes the linear constant (and also the amount of
+// extra memory used).
+static int32 gcpercent = -2;
+
+void
+gc(int32 force)
+{
+ byte *p;
+
+ // The gc is turned off (via enablegc) until
+ // the bootstrap has completed.
+ // Also, malloc gets called in the guts
+ // of a number of libraries that might be
+ // holding locks. To avoid priority inversion
+ // problems, don't bother trying to run gc
+ // while holding a lock. The next mallocgc
+ // without a lock will do the gc instead.
+ if(!mstats.enablegc || m->locks > 0 || panicking)
+ return;
+
+ if(gcpercent == -2) { // first time through
+ p = getenv("GOGC");
+ if(p == nil || p[0] == '\0')
+ gcpercent = 100;
+ else if(strcmp(p, (byte*)"off") == 0)
+ gcpercent = -1;
+ else
+ gcpercent = atoi(p);
+ }
+ if(gcpercent < 0)
+ return;
+
+ semacquire(&gcsema);
+ gosave(&g->sched); // update g's stack pointer for scanstack
+ stoptheworld();
+ if(mheap.Lock.key != 0)
+ throw("mheap locked during gc");
+ if(force || mstats.inuse_pages >= mstats.next_gc) {
+ mark();
+ sweep();
+ mstats.next_gc = mstats.inuse_pages+mstats.inuse_pages*gcpercent/100;
+ }
+ starttheworld();
+ gosave(&g->sched); // update g's stack pointer for debugging
+ semrelease(&gcsema);
+}
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/mheap.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/mheap.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,333 @@
+// Copyright 2009 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.
+
+// Page heap.
+//
+// See malloc.h for overview.
+//
+// When a MSpan is in the heap free list, state == MSpanFree
+// and heapmap(s->start) == span, heapmap(s->start+s->npages-1) == span.
+//
+// When a MSpan is allocated, state == MSpanInUse
+// and heapmap(i) == span for all s->start <= i < s->start+s->npages.
+
+#include "runtime.h"
+#include "malloc.h"
+
+static MSpan *MHeap_AllocLocked(MHeap*, uintptr, int32);
+static bool MHeap_Grow(MHeap*, uintptr);
+static void MHeap_FreeLocked(MHeap*, MSpan*);
+static MSpan *MHeap_AllocLarge(MHeap*, uintptr);
+static MSpan *BestFit(MSpan*, uintptr, MSpan*);
+
+static void
+RecordSpan(void *vh, byte *p)
+{
+ MHeap *h;
+ MSpan *s;
+
+ h = vh;
+ s = (MSpan*)p;
+ s->allnext = h->allspans;
+ h->allspans = s;
+}
+
+// Initialize the heap; fetch memory using alloc.
+void
+MHeap_Init(MHeap *h, void *(*alloc)(uintptr))
+{
+ uint32 i;
+
+ FixAlloc_Init(&h->spanalloc, sizeof(MSpan), alloc, RecordSpan, h);
+ FixAlloc_Init(&h->cachealloc, sizeof(MCache), alloc, nil, nil);
+ MHeapMap_Init(&h->map, alloc);
+ // h->mapcache needs no init
+ for(i=0; i<nelem(h->free); i++)
+ MSpanList_Init(&h->free[i]);
+ MSpanList_Init(&h->large);
+ for(i=0; i<nelem(h->central); i++)
+ MCentral_Init(&h->central[i], i);
+}
+
+// Allocate a new span of npage pages from the heap
+// and record its size class in the HeapMap and HeapMapCache.
+MSpan*
+MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass)
+{
+ MSpan *s;
+
+ lock(h);
+ s = MHeap_AllocLocked(h, npage, sizeclass);
+ if(s != nil)
+ mstats.inuse_pages += npage;
+ unlock(h);
+ return s;
+}
+
+static MSpan*
+MHeap_AllocLocked(MHeap *h, uintptr npage, int32 sizeclass)
+{
+ uintptr n;
+ MSpan *s, *t;
+
+ // Try in fixed-size lists up to max.
+ for(n=npage; n < nelem(h->free); n++) {
+ if(!MSpanList_IsEmpty(&h->free[n])) {
+ s = h->free[n].next;
+ goto HaveSpan;
+ }
+ }
+
+ // Best fit in list of large spans.
+ if((s = MHeap_AllocLarge(h, npage)) == nil) {
+ if(!MHeap_Grow(h, npage))
+ return nil;
+ if((s = MHeap_AllocLarge(h, npage)) == nil)
+ return nil;
+ }
+
+HaveSpan:
+ // Mark span in use.
+ if(s->state != MSpanFree)
+ throw("MHeap_AllocLocked - MSpan not free");
+ if(s->npages < npage)
+ throw("MHeap_AllocLocked - bad npages");
+ MSpanList_Remove(s);
+ s->state = MSpanInUse;
+
+ if(s->npages > npage) {
+ // Trim extra and put it back in the heap.
+ t = FixAlloc_Alloc(&h->spanalloc);
+ MSpan_Init(t, s->start + npage, s->npages - npage);
+ s->npages = npage;
+ MHeapMap_Set(&h->map, t->start - 1, s);
+ MHeapMap_Set(&h->map, t->start, t);
+ MHeapMap_Set(&h->map, t->start + t->npages - 1, t);
+ t->state = MSpanInUse;
+ MHeap_FreeLocked(h, t);
+ }
+
+ // If span is being used for small objects, cache size class.
+ // No matter what, cache span info, because gc needs to be
+ // able to map interior pointer to containing span.
+ s->sizeclass = sizeclass;
+ for(n=0; n<npage; n++)
+ MHeapMap_Set(&h->map, s->start+n, s);
+ if(sizeclass == 0) {
+ uintptr tmp;
+
+ // If there are entries for this span, invalidate them,
+ // but don't blow out cache entries about other spans.
+ for(n=0; n<npage; n++)
+ if(MHeapMapCache_GET(&h->mapcache, s->start+n, tmp) != 0)
+ MHeapMapCache_SET(&h->mapcache, s->start+n, 0);
+ } else {
+ // Save cache entries for this span.
+ // If there's a size class, there aren't that many pages.
+ for(n=0; n<npage; n++)
+ MHeapMapCache_SET(&h->mapcache, s->start+n, sizeclass);
+ }
+
+ return s;
+}
+
+// Allocate a span of exactly npage pages from the list of large spans.
+static MSpan*
+MHeap_AllocLarge(MHeap *h, uintptr npage)
+{
+ return BestFit(&h->large, npage, nil);
+}
+
+// Search list for smallest span with >= npage pages.
+// If there are multiple smallest spans, take the one
+// with the earliest starting address.
+static MSpan*
+BestFit(MSpan *list, uintptr npage, MSpan *best)
+{
+ MSpan *s;
+
+ for(s=list->next; s != list; s=s->next) {
+ if(s->npages < npage)
+ continue;
+ if(best == nil
+ || s->npages < best->npages
+ || (s->npages == best->npages && s->start < best->start))
+ best = s;
+ }
+ return best;
+}
+
+// Try to add at least npage pages of memory to the heap,
+// returning whether it worked.
+static bool
+MHeap_Grow(MHeap *h, uintptr npage)
+{
+ uintptr ask;
+ void *v;
+ MSpan *s;
+
+ // Ask for a big chunk, to reduce the number of mappings
+ // the operating system needs to track; also amortizes
+ // the overhead of an operating system mapping.
+ ask = npage<<PageShift;
+ if(ask < HeapAllocChunk)
+ ask = HeapAllocChunk;
+
+ v = SysAlloc(ask);
+ if(v == nil) {
+ if(ask > (npage<<PageShift)) {
+ ask = npage<<PageShift;
+ v = SysAlloc(ask);
+ }
+ if(v == nil)
+ return false;
+ }
+
+ // NOTE(rsc): In tcmalloc, if we've accumulated enough
+ // system allocations, the heap map gets entirely allocated
+ // in 32-bit mode. (In 64-bit mode that's not practical.)
+
+ if(!MHeapMap_Preallocate(&h->map, ((uintptr)v>>PageShift) - 1, (ask>>PageShift) + 2)) {
+ SysFree(v, ask);
+ return false;
+ }
+
+ // Create a fake "in use" span and free it, so that the
+ // right coalescing happens.
+ s = FixAlloc_Alloc(&h->spanalloc);
+ MSpan_Init(s, (uintptr)v>>PageShift, ask>>PageShift);
+ MHeapMap_Set(&h->map, s->start, s);
+ MHeapMap_Set(&h->map, s->start + s->npages - 1, s);
+ s->state = MSpanInUse;
+ MHeap_FreeLocked(h, s);
+ return true;
+}
+
+// Look up the span at the given page number.
+// Page number is guaranteed to be in map
+// and is guaranteed to be start or end of span.
+MSpan*
+MHeap_Lookup(MHeap *h, PageID p)
+{
+ return MHeapMap_Get(&h->map, p);
+}
+
+// Look up the span at the given page number.
+// Page number is *not* guaranteed to be in map
+// and may be anywhere in the span.
+// Map entries for the middle of a span are only
+// valid for allocated spans. Free spans may have
+// other garbage in their middles, so we have to
+// check for that.
+MSpan*
+MHeap_LookupMaybe(MHeap *h, PageID p)
+{
+ MSpan *s;
+
+ s = MHeapMap_GetMaybe(&h->map, p);
+ if(s == nil || p < s->start || p - s->start >= s->npages)
+ return nil;
+ if(s->state != MSpanInUse)
+ return nil;
+ return s;
+}
+
+// Free the span back into the heap.
+void
+MHeap_Free(MHeap *h, MSpan *s)
+{
+ lock(h);
+ mstats.inuse_pages -= s->npages;
+ MHeap_FreeLocked(h, s);
+ unlock(h);
+}
+
+static void
+MHeap_FreeLocked(MHeap *h, MSpan *s)
+{
+ MSpan *t;
+
+ if(s->state != MSpanInUse || s->ref != 0) {
+ printf("MHeap_FreeLocked - span %p ptr %p state %d ref %d\n", s, s->start<<PageShift, s->state, s->ref);
+ throw("MHeap_FreeLocked - invalid free");
+ }
+ s->state = MSpanFree;
+ MSpanList_Remove(s);
+
+ // Coalesce with earlier, later spans.
+ if((t = MHeapMap_Get(&h->map, s->start - 1)) != nil && t->state != MSpanInUse) {
+ s->start = t->start;
+ s->npages += t->npages;
+ MHeapMap_Set(&h->map, s->start, s);
+ MSpanList_Remove(t);
+ t->state = MSpanDead;
+ FixAlloc_Free(&h->spanalloc, t);
+ }
+ if((t = MHeapMap_Get(&h->map, s->start + s->npages)) != nil && t->state != MSpanInUse) {
+ s->npages += t->npages;
+ MHeapMap_Set(&h->map, s->start + s->npages - 1, s);
+ MSpanList_Remove(t);
+ t->state = MSpanDead;
+ FixAlloc_Free(&h->spanalloc, t);
+ }
+
+ // Insert s into appropriate list.
+ if(s->npages < nelem(h->free))
+ MSpanList_Insert(&h->free[s->npages], s);
+ else
+ MSpanList_Insert(&h->large, s);
+
+ // TODO(rsc): IncrementalScavenge() to return memory to OS.
+}
+
+// Initialize a new span with the given start and npages.
+void
+MSpan_Init(MSpan *span, PageID start, uintptr npages)
+{
+ span->next = nil;
+ span->prev = nil;
+ span->start = start;
+ span->npages = npages;
+ span->freelist = nil;
+ span->ref = 0;
+ span->sizeclass = 0;
+ span->state = 0;
+}
+
+// Initialize an empty doubly-linked list.
+void
+MSpanList_Init(MSpan *list)
+{
+ list->state = MSpanListHead;
+ list->next = list;
+ list->prev = list;
+}
+
+void
+MSpanList_Remove(MSpan *span)
+{
+ if(span->prev == nil && span->next == nil)
+ return;
+ span->prev->next = span->next;
+ span->next->prev = span->prev;
+ span->prev = nil;
+ span->next = nil;
+}
+
+bool
+MSpanList_IsEmpty(MSpan *list)
+{
+ return list->next == list;
+}
+
+void
+MSpanList_Insert(MSpan *list, MSpan *span)
+{
+ if(span->next != nil || span->prev != nil)
+ throw("MSpanList_Insert");
+ span->next = list->next;
+ span->prev = list;
+ span->next->prev = span;
+ span->prev->next = span;
+}
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/mheapmap32.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/mheapmap32.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,96 @@
+// Copyright 2009 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.
+
+// Heap map, 32-bit version
+// See malloc.h and mheap.c for overview.
+
+#include "runtime.h"
+#include "malloc.h"
+
+// 3-level radix tree mapping page ids to Span*.
+void
+MHeapMap_Init(MHeapMap *m, void *(*allocator)(size_t))
+{
+ m->allocator = allocator;
+}
+
+MSpan*
+MHeapMap_Get(MHeapMap *m, PageID k)
+{
+ int32 i1, i2;
+
+ i2 = k & MHeapMap_Level2Mask;
+ k >>= MHeapMap_Level2Bits;
+ i1 = k & MHeapMap_Level1Mask;
+ k >>= MHeapMap_Level1Bits;
+ if(k != 0)
+ throw("MHeapMap_Get");
+
+ return m->p[i1]->s[i2];
+}
+
+MSpan*
+MHeapMap_GetMaybe(MHeapMap *m, PageID k)
+{
+ int32 i1, i2;
+ MHeapMapNode2 *p2;
+
+ i2 = k & MHeapMap_Level2Mask;
+ k >>= MHeapMap_Level2Bits;
+ i1 = k & MHeapMap_Level1Mask;
+ k >>= MHeapMap_Level1Bits;
+ if(k != 0)
+ throw("MHeapMap_Get");
+
+ p2 = m->p[i1];
+ if(p2 == nil)
+ return nil;
+ return p2->s[i2];
+}
+
+void
+MHeapMap_Set(MHeapMap *m, PageID k, MSpan *s)
+{
+ int32 i1, i2;
+
+ i2 = k & MHeapMap_Level2Mask;
+ k >>= MHeapMap_Level2Bits;
+ i1 = k & MHeapMap_Level1Mask;
+ k >>= MHeapMap_Level1Bits;
+ if(k != 0)
+ throw("MHeapMap_Set");
+
+ m->p[i1]->s[i2] = s;
+}
+
+// Allocate the storage required for entries [k, k+1, ..., k+len-1]
+// so that Get and Set calls need not check for nil pointers.
+bool
+MHeapMap_Preallocate(MHeapMap *m, PageID k, uintptr len)
+{
+ uintptr end;
+ int32 i1;
+ MHeapMapNode2 *p2;
+
+ end = k+len;
+ while(k < end) {
+ if((k >> MHeapMap_TotalBits) != 0)
+ return false;
+ i1 = (k >> MHeapMap_Level2Bits) & MHeapMap_Level1Mask;
+
+ // first-level pointer
+ if(m->p[i1] == nil) {
+ p2 = m->allocator(sizeof *p2);
+ if(p2 == nil)
+ return false;
+ sys_memclr((byte*)p2, sizeof *p2);
+ m->p[i1] = p2;
+ }
+
+ // advance key past this leaf node
+ k = ((k >> MHeapMap_Level2Bits) + 1) << MHeapMap_Level2Bits;
+ }
+ return true;
+}
+
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/mheapmap32.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/mheapmap32.h Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,76 @@
+// Copyright 2009 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.
+
+// Free(v) must be able to determine the MSpan containing v.
+// The MHeapMap is a 2-level radix tree mapping page numbers to MSpans.
+
+typedef struct MHeapMapNode2 MHeapMapNode2;
+
+enum
+{
+ // 32 bit address - 12 bit page size = 20 bits to map
+ MHeapMap_Level1Bits = 10,
+ MHeapMap_Level2Bits = 10,
+
+ MHeapMap_TotalBits =
+ MHeapMap_Level1Bits +
+ MHeapMap_Level2Bits,
+
+ MHeapMap_Level1Mask = (1<<MHeapMap_Level1Bits) - 1,
+ MHeapMap_Level2Mask = (1<<MHeapMap_Level2Bits) - 1,
+};
+
+struct MHeapMap
+{
+ void *(*allocator)(uintptr);
+ MHeapMapNode2 *p[1<<MHeapMap_Level1Bits];
+};
+
+struct MHeapMapNode2
+{
+ MSpan *s[1<<MHeapMap_Level2Bits];
+};
+
+void MHeapMap_Init(MHeapMap *m, void *(*allocator)(uintptr));
+bool MHeapMap_Preallocate(MHeapMap *m, PageID k, uintptr npages);
+MSpan* MHeapMap_Get(MHeapMap *m, PageID k);
+MSpan* MHeapMap_GetMaybe(MHeapMap *m, PageID k);
+void MHeapMap_Set(MHeapMap *m, PageID k, MSpan *v);
+
+
+// Much of the time, free(v) needs to know only the size class for v,
+// not which span it came from. The MHeapMap finds the size class
+// by looking up the span.
+//
+// An MHeapMapCache is a simple direct-mapped cache translating
+// page numbers to size classes. It avoids the expensive MHeapMap
+// lookup for hot pages.
+//
+// The cache entries are 32 bits, with the page number in the low part
+// and the value at the top.
+//
+// NOTE(rsc): On a machine with 32-bit addresses (= 20-bit page numbers),
+// we can use a 16-bit cache entry by not storing the redundant 12 bits
+// of the key that are used as the entry index. For now, keep it simple.
+enum
+{
+ MHeapMapCache_HashBits = 12
+};
+
+struct MHeapMapCache
+{
+ uint32 array[1<<MHeapMapCache_HashBits];
+};
+
+// All macros for speed (sorry).
+#define HMASK ((1<<MHeapMapCache_HashBits)-1)
+#define KBITS MHeapMap_TotalBits
+#define KMASK ((1LL<<KBITS)-1)
+
+#define MHeapMapCache_SET(cache, key, value) \
+ ((cache)->array[(key) & HMASK] = (key) | ((uintptr)(value) << KBITS))
+
+#define MHeapMapCache_GET(cache, key, tmp) \
+ (tmp = (cache)->array[(key) & HMASK], \
+ (tmp & KMASK) == (key) ? (tmp >> KBITS) : 0)
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/mheapmap64.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/mheapmap64.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,117 @@
+// Copyright 2009 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.
+
+// Heap map, 64-bit version
+// See malloc.h and mheap.c for overview.
+
+#include "runtime.h"
+#include "malloc.h"
+
+// 3-level radix tree mapping page ids to Span*.
+void
+MHeapMap_Init(MHeapMap *m, void *(*allocator)(size_t))
+{
+ m->allocator = allocator;
+}
+
+MSpan*
+MHeapMap_Get(MHeapMap *m, PageID k)
+{
+ int32 i1, i2, i3;
+
+ i3 = k & MHeapMap_Level3Mask;
+ k >>= MHeapMap_Level3Bits;
+ i2 = k & MHeapMap_Level2Mask;
+ k >>= MHeapMap_Level2Bits;
+ i1 = k & MHeapMap_Level1Mask;
+ k >>= MHeapMap_Level1Bits;
+ if(k != 0)
+ throw("MHeapMap_Get");
+
+ return m->p[i1]->p[i2]->s[i3];
+}
+
+MSpan*
+MHeapMap_GetMaybe(MHeapMap *m, PageID k)
+{
+ int32 i1, i2, i3;
+ MHeapMapNode2 *p2;
+ MHeapMapNode3 *p3;
+
+ i3 = k & MHeapMap_Level3Mask;
+ k >>= MHeapMap_Level3Bits;
+ i2 = k & MHeapMap_Level2Mask;
+ k >>= MHeapMap_Level2Bits;
+ i1 = k & MHeapMap_Level1Mask;
+ k >>= MHeapMap_Level1Bits;
+ if(k != 0)
+ throw("MHeapMap_Get");
+
+ p2 = m->p[i1];
+ if(p2 == nil)
+ return nil;
+ p3 = p2->p[i2];
+ if(p3 == nil)
+ return nil;
+ return p3->s[i3];
+}
+
+void
+MHeapMap_Set(MHeapMap *m, PageID k, MSpan *s)
+{
+ int32 i1, i2, i3;
+
+ i3 = k & MHeapMap_Level3Mask;
+ k >>= MHeapMap_Level3Bits;
+ i2 = k & MHeapMap_Level2Mask;
+ k >>= MHeapMap_Level2Bits;
+ i1 = k & MHeapMap_Level1Mask;
+ k >>= MHeapMap_Level1Bits;
+ if(k != 0)
+ throw("MHeapMap_Set");
+
+ m->p[i1]->p[i2]->s[i3] = s;
+}
+
+// Allocate the storage required for entries [k, k+1, ..., k+len-1]
+// so that Get and Set calls need not check for nil pointers.
+bool
+MHeapMap_Preallocate(MHeapMap *m, PageID k, uintptr len)
+{
+ uintptr end;
+ int32 i1, i2;
+ MHeapMapNode2 *p2;
+ MHeapMapNode3 *p3;
+
+ end = k+len;
+ while(k < end) {
+ if((k >> MHeapMap_TotalBits) != 0)
+ return false;
+ i2 = (k >> MHeapMap_Level3Bits) & MHeapMap_Level2Mask;
+ i1 = (k >> (MHeapMap_Level3Bits + MHeapMap_Level2Bits)) & MHeapMap_Level1Mask;
+
+ // first-level pointer
+ if((p2 = m->p[i1]) == nil) {
+ p2 = m->allocator(sizeof *p2);
+ if(p2 == nil)
+ return false;
+ sys_memclr((byte*)p2, sizeof *p2);
+ m->p[i1] = p2;
+ }
+
+ // second-level pointer
+ if(p2->p[i2] == nil) {
+ p3 = m->allocator(sizeof *p3);
+ if(p3 == nil)
+ return false;
+ sys_memclr((byte*)p3, sizeof *p3);
+ p2->p[i2] = p3;
+ }
+
+ // advance key past this leaf node
+ k = ((k >> MHeapMap_Level3Bits) + 1) << MHeapMap_Level3Bits;
+ }
+ return true;
+}
+
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/mheapmap64.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/mheapmap64.h Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,96 @@
+// Copyright 2009 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.
+
+// Free(v) must be able to determine the MSpan containing v.
+// The MHeapMap is a 3-level radix tree mapping page numbers to MSpans.
+//
+// NOTE(rsc): On a 32-bit platform (= 20-bit page numbers),
+// we can swap in a 2-level radix tree.
+//
+// NOTE(rsc): We use a 3-level tree because tcmalloc does, but
+// having only three levels requires approximately 1 MB per node
+// in the tree, making the minimum map footprint 3 MB.
+// Using a 4-level tree would cut the minimum footprint to 256 kB.
+// On the other hand, it's just virtual address space: most of
+// the memory is never going to be touched, thus never paged in.
+
+typedef struct MHeapMapNode2 MHeapMapNode2;
+typedef struct MHeapMapNode3 MHeapMapNode3;
+
+enum
+{
+ // 64 bit address - 12 bit page size = 52 bits to map
+ MHeapMap_Level1Bits = 18,
+ MHeapMap_Level2Bits = 18,
+ MHeapMap_Level3Bits = 16,
+
+ MHeapMap_TotalBits =
+ MHeapMap_Level1Bits +
+ MHeapMap_Level2Bits +
+ MHeapMap_Level3Bits,
+
+ MHeapMap_Level1Mask = (1<<MHeapMap_Level1Bits) - 1,
+ MHeapMap_Level2Mask = (1<<MHeapMap_Level2Bits) - 1,
+ MHeapMap_Level3Mask = (1<<MHeapMap_Level3Bits) - 1,
+};
+
+struct MHeapMap
+{
+ void *(*allocator)(uintptr);
+ MHeapMapNode2 *p[1<<MHeapMap_Level1Bits];
+};
+
+struct MHeapMapNode2
+{
+ MHeapMapNode3 *p[1<<MHeapMap_Level2Bits];
+};
+
+struct MHeapMapNode3
+{
+ MSpan *s[1<<MHeapMap_Level3Bits];
+};
+
+void MHeapMap_Init(MHeapMap *m, void *(*allocator)(uintptr));
+bool MHeapMap_Preallocate(MHeapMap *m, PageID k, uintptr npages);
+MSpan* MHeapMap_Get(MHeapMap *m, PageID k);
+MSpan* MHeapMap_GetMaybe(MHeapMap *m, PageID k);
+void MHeapMap_Set(MHeapMap *m, PageID k, MSpan *v);
+
+
+// Much of the time, free(v) needs to know only the size class for v,
+// not which span it came from. The MHeapMap finds the size class
+// by looking up the span.
+//
+// An MHeapMapCache is a simple direct-mapped cache translating
+// page numbers to size classes. It avoids the expensive MHeapMap
+// lookup for hot pages.
+//
+// The cache entries are 64 bits, with the page number in the low part
+// and the value at the top.
+//
+// NOTE(rsc): On a machine with 32-bit addresses (= 20-bit page numbers),
+// we can use a 16-bit cache entry by not storing the redundant 12 bits
+// of the key that are used as the entry index. Here in 64-bit land,
+// that trick won't work unless the hash table has 2^28 entries.
+enum
+{
+ MHeapMapCache_HashBits = 12
+};
+
+struct MHeapMapCache
+{
+ uintptr array[1<<MHeapMapCache_HashBits];
+};
+
+// All macros for speed (sorry).
+#define HMASK ((1<<MHeapMapCache_HashBits)-1)
+#define KBITS MHeapMap_TotalBits
+#define KMASK ((1LL<<KBITS)-1)
+
+#define MHeapMapCache_SET(cache, key, value) \
+ ((cache)->array[(key) & HMASK] = (key) | ((uintptr)(value) << KBITS))
+
+#define MHeapMapCache_GET(cache, key, tmp) \
+ (tmp = (cache)->array[(key) & HMASK], \
+ (tmp & KMASK) == (key) ? (tmp >> KBITS) : 0)
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/msize.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/msize.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,165 @@
+// Copyright 2009 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.
+
+// Malloc small size classes.
+//
+// See malloc.h for overview.
+//
+// The size classes are chosen so that rounding an allocation
+// request up to the next size class wastes at most 12.5% (1.125x).
+//
+// Each size class has its own page count that gets allocated
+// and chopped up when new objects of the size class are needed.
+// That page count is chosen so that chopping up the run of
+// pages into objects of the given size wastes at most 12.5% (1.125x)
+// of the memory. It is not necessary that the cutoff here be
+// the same as above.
+//
+// The two sources of waste multiply, so the worst possible case
+// for the above constraints would be that allocations of some
+// size might have a 26.6% (1.266x) overhead.
+// In practice, only one of the wastes comes into play for a
+// given size (sizes < 512 waste mainly on the round-up,
+// sizes > 512 waste mainly on the page chopping).
+//
+// TODO(rsc): Compute max waste for any given size.
+
+#include "runtime.h"
+#include "malloc.h"
+
+int32 class_to_size[NumSizeClasses];
+int32 class_to_allocnpages[NumSizeClasses];
+int32 class_to_transfercount[NumSizeClasses];
+
+// The SizeToClass lookup is implemented using two arrays,
+// one mapping sizes <= 1024 to their class and one mapping
+// sizes >= 1024 and <= MaxSmallSize to their class.
+// All objects are 8-aligned, so the first array is indexed by
+// the size divided by 8 (rounded up). Objects >= 1024 bytes
+// are 128-aligned, so the second array is indexed by the
+// size divided by 128 (rounded up). The arrays are filled in
+// by InitSizes.
+
+static int32 size_to_class8[1024/8 + 1];
+static int32 size_to_class128[(MaxSmallSize-1024)/128 + 1];
+
+int32
+SizeToClass(int32 size)
+{
+ if(size > MaxSmallSize)
+ throw("SizeToClass - invalid size");
+ if(size > 1024-8)
+ return size_to_class128[(size-1024+127) >> 7];
+ return size_to_class8[(size+7)>>3];
+}
+
+void
+InitSizes(void)
+{
+ int32 align, sizeclass, size, osize, nextsize, n;
+ uint32 i;
+ uintptr allocsize, npages;
+
+ // Initialize the class_to_size table (and choose class sizes in the process).
+ class_to_size[0] = 0;
+ sizeclass = 1; // 0 means no class
+ align = 8;
+ for(size = align; size <= MaxSmallSize; size += align) {
+ if((size&(size-1)) == 0) { // bump alignment once in a while
+ if(size >= 2048)
+ align = 256;
+ else if(size >= 128)
+ align = size / 8;
+ else if(size >= 16)
+ align = 16; // required for x86 SSE instructions, if we want to use them
+ }
+ if((align&(align-1)) != 0)
+ throw("InitSizes - bug");
+
+ // Make the allocnpages big enough that
+ // the leftover is less than 1/8 of the total,
+ // so wasted space is at most 12.5%.
+ allocsize = PageSize;
+ osize = size + RefcountOverhead;
+ while(allocsize%osize > (allocsize/8))
+ allocsize += PageSize;
+ npages = allocsize >> PageShift;
+
+ // If the previous sizeclass chose the same
+ // allocation size and fit the same number of
+ // objects into the page, we might as well
+ // use just this size instead of having two
+ // different sizes.
+ if(sizeclass > 1
+ && npages == class_to_allocnpages[sizeclass-1]
+ && allocsize/osize == allocsize/(class_to_size[sizeclass-1]+RefcountOverhead)) {
+ class_to_size[sizeclass-1] = size;
+ continue;
+ }
+
+ class_to_allocnpages[sizeclass] = npages;
+ class_to_size[sizeclass] = size;
+ sizeclass++;
+ }
+ if(sizeclass != NumSizeClasses) {
+ printf("sizeclass=%d NumSizeClasses=%d\n", sizeclass, NumSizeClasses);
+ throw("InitSizes - bad NumSizeClasses");
+ }
+
+ // Initialize the size_to_class tables.
+ nextsize = 0;
+ for (sizeclass = 1; sizeclass < NumSizeClasses; sizeclass++) {
+ for(; nextsize < 1024 && nextsize <= class_to_size[sizeclass]; nextsize+=8)
+ size_to_class8[nextsize/8] = sizeclass;
+ if(nextsize >= 1024)
+ for(; nextsize <= class_to_size[sizeclass]; nextsize += 128)
+ size_to_class128[(nextsize-1024)/128] = sizeclass;
+ }
+
+ // Double-check SizeToClass.
+ if(0) {
+ for(n=0; n < MaxSmallSize; n++) {
+ sizeclass = SizeToClass(n);
+ if(sizeclass < 1 || sizeclass >= NumSizeClasses || class_to_size[sizeclass] < n) {
+ printf("size=%d sizeclass=%d class_to_size=%d\n", n, sizeclass, class_to_size[sizeclass]);
+ printf("incorrect SizeToClass");
+ goto dump;
+ }
+ if(sizeclass > 1 && class_to_size[sizeclass-1] >= n) {
+ printf("size=%d sizeclass=%d class_to_size=%d\n", n, sizeclass, class_to_size[sizeclass]);
+ printf("SizeToClass too big");
+ goto dump;
+ }
+ }
+ }
+
+ // Initialize the class_to_transfercount table.
+ for(sizeclass = 1; sizeclass < NumSizeClasses; sizeclass++) {
+ n = 64*1024 / class_to_size[sizeclass];
+ if(n < 2)
+ n = 2;
+ if(n > 32)
+ n = 32;
+ class_to_transfercount[sizeclass] = n;
+ }
+ return;
+
+dump:
+ if(1){
+ printf("NumSizeClasses=%d\n", NumSizeClasses);
+ printf("class_to_size:");
+ for(sizeclass=0; sizeclass<NumSizeClasses; sizeclass++)
+ printf(" %d", class_to_size[sizeclass]);
+ printf("\n\n");
+ printf("size_to_class8:");
+ for(i=0; i<nelem(size_to_class8); i++)
+ printf(" %d=>%d(%d)\n", i*8, size_to_class8[i], class_to_size[size_to_class8[i]]);
+ printf("\n");
+ printf("size_to_class128:");
+ for(i=0; i<nelem(size_to_class128); i++)
+ printf(" %d=>%d(%d)\n", i*128, size_to_class128[i], class_to_size[size_to_class128[i]]);
+ printf("\n");
+ }
+ throw("InitSizes failed");
+}
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/print.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/print.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,268 @@
+// Copyright 2009 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.
+
+#include "runtime.h"
+
+
+void
+dump(byte *p, int32 n)
+{
+ int32 i;
+
+ for(i=0; i<n; i++) {
+ sys·printpointer((byte*)(p[i]>>4));
+ sys·printpointer((byte*)(p[i]&0xf));
+ if((i&15) == 15)
+ prints("\n");
+ else
+ prints(" ");
+ }
+ if(n & 15)
+ prints("\n");
+}
+
+void
+prints(int8 *s)
+{
+ sys·write(1, s, findnull((byte*)s));
+}
+
+// Very simple printf. Only for debugging prints.
+// Do not add to this without checking with Rob.
+void
+printf(int8 *s, ...)
+{
+ int8 *p, *lp;
+ byte *arg, *narg;
+
+ lp = p = s;
+ arg = (byte*)(&s+1);
+ for(; *p; p++) {
+ if(*p != '%')
+ continue;
+ if(p > lp)
+ sys·write(1, lp, p-lp);
+ p++;
+ narg = nil;
+ switch(*p) {
+ case 'd': // 32-bit
+ case 'x':
+ narg = arg + 4;
+ break;
+ case 'D': // 64-bit
+ case 'X':
+ if(sizeof(uintptr) == 8 && ((uint32)(uint64)arg)&4)
+ arg += 4;
+ narg = arg + 8;
+ break;
+ case 'p': // pointer-sized
+ case 's':
+ if(sizeof(uintptr) == 8 && ((uint32)(uint64)arg)&4)
+ arg += 4;
+ narg = arg + sizeof(uintptr);
+ break;
+ case 'S': // pointer-aligned but bigger
+ if(sizeof(uintptr) == 8 && ((uint32)(uint64)arg)&4)
+ arg += 4;
+ narg = arg + sizeof(String);
+ break;
+ }
+ switch(*p) {
+ case 'd':
+ sys·printint(*(int32*)arg);
+ break;
+ case 'D':
+ sys·printint(*(int64*)arg);
+ break;
+ case 'x':
+ sys·printhex(*(int32*)arg);
+ break;
+ case 'X':
+ sys·printhex(*(int64*)arg);
+ break;
+ case 'p':
+ sys·printpointer(*(void**)arg);
+ break;
+ case 's':
+ prints(*(int8**)arg);
+ break;
+ case 'S':
+ sys·printstring(*(String*)arg);
+ break;
+ }
+ arg = narg;
+ lp = p+1;
+ }
+ if(p > lp)
+ sys·write(1, lp, p-lp);
+}
+
+
+void
+sys·printpc(void *p)
+{
+ prints("PC=");
+ sys·printhex((uint64)sys·getcallerpc(p));
+}
+
+void
+sys·printbool(bool v)
+{
+ if(v) {
+ sys·write(1, (byte*)"true", 4);
+ return;
+ }
+ sys·write(1, (byte*)"false", 5);
+}
+
+void
+sys·printfloat(float64 v)
+{
+ byte buf[20];
+ int32 e, s, i, n;
+ float64 h;
+
+ if(isNaN(v)) {
+ sys·write(1, "NaN", 3);
+ return;
+ }
+ if(isInf(v, 0)) {
+ sys·write(1, "+Inf", 4);
+ return;
+ }
+ if(isInf(v, -1)) {
+ sys·write(1, "+Inf", 4);
+ return;
+ }
+
+
+ n = 7; // digits printed
+ e = 0; // exp
+ s = 0; // sign
+ if(v != 0) {
+ // sign
+ if(v < 0) {
+ v = -v;
+ s = 1;
+ }
+
+ // normalize
+ while(v >= 10) {
+ e++;
+ v /= 10;
+ }
+ while(v < 1) {
+ e--;
+ v *= 10;
+ }
+
+ // round
+ h = 5;
+ for(i=0; i<n; i++)
+ h /= 10;
+ v += h;
+ if(v >= 10) {
+ e++;
+ v /= 10;
+ }
+ }
+
+ // format +d.dddd+edd
+ buf[0] = '+';
+ if(s)
+ buf[0] = '-';
+ for(i=0; i<n; i++) {
+ s = v;
+ buf[i+2] = s+'0';
+ v -= s;
+ v *= 10.;
+ }
+ buf[1] = buf[2];
+ buf[2] = '.';
+
+ buf[n+2] = 'e';
+ buf[n+3] = '+';
+ if(e < 0) {
+ e = -e;
+ buf[n+3] = '-';
+ }
+
+ buf[n+4] = (e/100) + '0';
+ buf[n+5] = (e/10)%10 + '0';
+ buf[n+6] = (e%10) + '0';
+ sys·write(1, buf, n+7);
+}
+
+void
+sys·printuint(uint64 v)
+{
+ byte buf[100];
+ int32 i;
+
+ for(i=nelem(buf)-1; i>0; i--) {
+ buf[i] = v%10 + '0';
+ if(v < 10)
+ break;
+ v = v/10;
+ }
+ sys·write(1, buf+i, nelem(buf)-i);
+}
+
+void
+sys·printint(int64 v)
+{
+ if(v < 0) {
+ sys·write(1, "-", 1);
+ v = -v;
+ }
+ sys·printuint(v);
+}
+
+void
+sys·printhex(uint64 v)
+{
+ static int8 *dig = "0123456789abcdef";
+ byte buf[100];
+ int32 i;
+
+ i=nelem(buf);
+ for(; v>0; v/=16)
+ buf[--i] = dig[v%16];
+ if(i == nelem(buf))
+ buf[--i] = '0';
+ buf[--i] = 'x';
+ buf[--i] = '0';
+ sys·write(1, buf+i, nelem(buf)-i);
+}
+
+void
+sys·printpointer(void *p)
+{
+ sys·printhex((uint64)p);
+}
+
+void
+sys·printstring(String v)
+{
+ extern int32 maxstring;
+
+ if(v.len > maxstring) {
+ sys·write(1, "[invalid string]", 16);
+ return;
+ }
+ if(v.len > 0)
+ sys·write(1, v.str, v.len);
+}
+
+void
+sys·printsp(void)
+{
+ sys·write(1, " ", 1);
+}
+
+void
+sys·printnl(void)
+{
+ sys·write(1, "\n", 1);
+}
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/proc.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/proc.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,858 @@
+// Copyright 2009 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.
+
+#include "runtime.h"
+#include "malloc.h"
+
+typedef struct Sched Sched;
+
+M m0;
+G g0; // idle goroutine for m0
+
+static int32 debug = 0;
+static Lock debuglock;
+
+// Go scheduler
+//
+// The go scheduler's job is to match ready-to-run goroutines (`g's)
+// with waiting-for-work schedulers (`m's). If there are ready gs
+// and no waiting ms, ready() will start a new m running in a new
+// OS thread, so that all ready gs can run simultaneously, up to a limit.
+// For now, ms never go away.
+//
+// The default maximum number of ms is one: go runs single-threaded.
+// This is because some locking details have to be worked ou
+// (select in particular is not locked properly) and because the low-level
+// code hasn't been written yet for OS X. Setting the environmen
+// variable $gomaxprocs changes sched.mmax for now.
+//
+// Even a program that can run without deadlock in a single process
+// might use more ms if given the chance. For example, the prime
+// sieve will use as many ms as there are primes (up to sched.mmax),
+// allowing different stages of the pipeline to execute in parallel.
+// We could revisit this choice, only kicking off new ms for blocking
+// system calls, but that would limit the amount of parallel computation
+// that go would try to do.
+//
+// In general, one could imagine all sorts of refinements to the
+// scheduler, but the goal now is just to get something working on
+// Linux and OS X.
+
+struct Sched {
+ Lock;
+
+ G *gfree; // available gs (status == Gdead)
+
+ G *ghead; // gs waiting to run
+ G *gtail;
+ int32 gwait; // number of gs waiting to run
+ int32 gcount; // number of gs that are alive
+
+ M *mhead; // ms waiting for work
+ int32 mwait; // number of ms waiting for work
+ int32 mcount; // number of ms that have been created
+ int32 mcpu; // number of ms executing on cpu
+ int32 mcpumax; // max number of ms allowed on cpu
+ int32 gomaxprocs;
+ int32 msyscall; // number of ms in system calls
+
+ int32 predawn; // running initialization, don't run new gs.
+
+ Note stopped; // one g can wait here for ms to stop
+ int32 waitstop; // after setting this flag
+};
+
+Sched sched;
+
+// Scheduling helpers. Sched must be locked.
+static void gput(G*); // put/get on ghead/gtail
+static G* gget(void);
+static void mput(M*); // put/get on mhead
+static M* mget(void);
+static void gfput(G*); // put/get on gfree
+static G* gfget(void);
+static void matchmg(void); // match ms to gs
+static void readylocked(G*); // ready, but sched is locked
+
+// Scheduler loop.
+static void scheduler(void);
+
+// The bootstrap sequence is:
+//
+// call osinit
+// call schedinit
+// make & queue new G
+// call mstart
+//
+// The new G does:
+//
+// call main·init_function
+// call initdone
+// call main·main
+void
+schedinit(void)
+{
+ int32 n;
+ byte *p;
+
+ mallocinit();
+ goargs();
+
+ // Allocate internal symbol table representation now,
+ // so that we don't need to call malloc when we crash.
+ findfunc(0);
+
+ sched.gomaxprocs = 1;
+ p = getenv("GOMAXPROCS");
+ if(p != nil && (n = atoi(p)) != 0)
+ sched.gomaxprocs = n;
+ sched.mcpumax = sched.gomaxprocs;
+ sched.mcount = 1;
+ sched.predawn = 1;
+}
+
+// Called after main·init_function; main·main will be called on return.
+void
+initdone(void)
+{
+ // Let's go.
+ sched.predawn = 0;
+ mstats.enablegc = 1;
+
+ // If main·init_function started other goroutines,
+ // kick off new ms to handle them, like ready
+ // would have, had it not been pre-dawn.
+ lock(&sched);
+ matchmg();
+ unlock(&sched);
+}
+
+void
+goexit(void)
+{
+ if(debug > 1){
+ lock(&debuglock);
+ printf("goexit goid=%d\n", g->goid);
+ unlock(&debuglock);
+ }
+ g->status = Gmoribund;
+ gosched();
+}
+
+void
+tracebackothers(G *me)
+{
+ G *g;
+
+ for(g = allg; g != nil; g = g->alllink) {
+ if(g == me || g->status == Gdead)
+ continue;
+ printf("\ngoroutine %d:\n", g->goid);
+ traceback(g->sched.PC, g->sched.SP+sizeof(uintptr), g); // gogo adjusts SP by one word
+ }
+}
+
+// Put on `g' queue. Sched must be locked.
+static void
+gput(G *g)
+{
+ g->schedlink = nil;
+ if(sched.ghead == nil)
+ sched.ghead = g;
+ else
+ sched.gtail->schedlink = g;
+ sched.gtail = g;
+ sched.gwait++;
+}
+
+// Get from `g' queue. Sched must be locked.
+static G*
+gget(void)
+{
+ G *g;
+
+ g = sched.ghead;
+ if(g){
+ sched.ghead = g->schedlink;
+ if(sched.ghead == nil)
+ sched.gtail = nil;
+ sched.gwait--;
+ }
+ return g;
+}
+
+// Put on `m' list. Sched must be locked.
+static void
+mput(M *m)
+{
+ m->schedlink = sched.mhead;
+ sched.mhead = m;
+ sched.mwait++;
+}
+
+// Get from `m' list. Sched must be locked.
+static M*
+mget(void)
+{
+ M *m;
+
+ m = sched.mhead;
+ if(m){
+ sched.mhead = m->schedlink;
+ sched.mwait--;
+ }
+ return m;
+}
+
+// Put on gfree list. Sched must be locked.
+static void
+gfput(G *g)
+{
+ g->schedlink = sched.gfree;
+ sched.gfree = g;
+}
+
+// Get from gfree list. Sched must be locked.
+static G*
+gfget(void)
+{
+ G *g;
+
+ g = sched.gfree;
+ if(g)
+ sched.gfree = g->schedlink;
+ return g;
+}
+
+// Mark g ready to run.
+void
+ready(G *g)
+{
+ lock(&sched);
+ readylocked(g);
+ unlock(&sched);
+}
+
+// Mark g ready to run. Sched is already locked.
+// G might be running already and about to stop.
+// The sched lock protects g->status from changing underfoot.
+static void
+readylocked(G *g)
+{
+ if(g->m){
+ // Running on another machine.
+ // Ready it when it stops.
+ g->readyonstop = 1;
+ return;
+ }
+
+ // Mark runnable.
+ if(g->status == Grunnable || g->status == Grunning)
+ throw("bad g->status in ready");
+ g->status = Grunnable;
+
+ gput(g);
+ if(!sched.predawn)
+ matchmg();
+}
+
+// Get the next goroutine that m should run.
+// Sched must be locked on entry, is unlocked on exit.
+// Makes sure that at most $GOMAXPROCS gs are
+// running on cpus (not in system calls) at any given time.
+static G*
+nextgandunlock(void)
+{
+ G *gp;
+
+ // On startup, each m is assigned a nextg and
+ // has already been accounted for in mcpu.
+ if(m->nextg != nil) {
+ gp = m->nextg;
+ m->nextg = nil;
+ unlock(&sched);
+ if(debug > 1) {
+ lock(&debuglock);
+ printf("m%d nextg found g%d\n", m->id, gp->goid);
+ unlock(&debuglock);
+ }
+ return gp;
+ }
+
+ // Otherwise, look for work.
+ if(sched.mcpu < sched.mcpumax && (gp=gget()) != nil) {
+ sched.mcpu++;
+ unlock(&sched);
+ if(debug > 1) {
+ lock(&debuglock);
+ printf("m%d nextg got g%d\n", m->id, gp->goid);
+ unlock(&debuglock);
+ }
+ return gp;
+ }
+
+ // Otherwise, sleep.
+ mput(m);
+ if(sched.mcpu == 0 && sched.msyscall == 0)
+ throw("all goroutines are asleep - deadlock!");
+ m->nextg = nil;
+ noteclear(&m->havenextg);
+ if(sched.waitstop && sched.mcpu <= sched.mcpumax) {
+ sched.waitstop = 0;
+ notewakeup(&sched.stopped);
+ }
+ unlock(&sched);
+
+ notesleep(&m->havenextg);
+ if((gp = m->nextg) == nil)
+ throw("bad m->nextg in nextgoroutine");
+ m->nextg = nil;
+ if(debug > 1) {
+ lock(&debuglock);
+ printf("m%d nextg woke g%d\n", m->id, gp->goid);
+ unlock(&debuglock);
+ }
+ return gp;
+}
+
+// TODO(rsc): Remove. This is only temporary,
+// for the mark and sweep collector.
+void
+stoptheworld(void)
+{
+ lock(&sched);
+ sched.mcpumax = 1;
+ while(sched.mcpu > 1) {
+ noteclear(&sched.stopped);
+ sched.waitstop = 1;
+ unlock(&sched);
+ notesleep(&sched.stopped);
+ lock(&sched);
+ }
+ unlock(&sched);
+}
+
+// TODO(rsc): Remove. This is only temporary,
+// for the mark and sweep collector.
+void
+starttheworld(void)
+{
+ lock(&sched);
+ sched.mcpumax = sched.gomaxprocs;
+ matchmg();
+ unlock(&sched);
+}
+
+// Called to start an M.
+void
+mstart(void)
+{
+ if(m->mcache == nil)
+ m->mcache = allocmcache();
+ minit();
+ scheduler();
+}
+
+// Kick of new ms as needed (up to mcpumax).
+// There are already `other' other cpus that will
+// start looking for goroutines shortly.
+// Sched is locked.
+static void
+matchmg(void)
+{
+ M *m;
+ G *g;
+
+ if(debug > 1 && sched.ghead != nil) {
+ lock(&debuglock);
+ printf("matchmg mcpu=%d mcpumax=%d gwait=%d\n", sched.mcpu, sched.mcpumax, sched.gwait);
+ unlock(&debuglock);
+ }
+
+ while(sched.mcpu < sched.mcpumax && (g = gget()) != nil){
+ sched.mcpu++;
+ if((m = mget()) != nil){
+ if(debug > 1) {
+ lock(&debuglock);
+ printf("wakeup m%d g%d\n", m->id, g->goid);
+ unlock(&debuglock);
+ }
+ m->nextg = g;
+ notewakeup(&m->havenextg);
+ }else{
+ m = malloc(sizeof(M));
+ m->g0 = malg(8192);
+ m->nextg = g;
+ m->id = sched.mcount++;
+ if(debug) {
+ lock(&debuglock);
+ printf("alloc m%d g%d\n", m->id, g->goid);
+ unlock(&debuglock);
+ }
+ newosproc(m, m->g0, m->g0->stackbase, mstart);
+ }
+ }
+}
+
+// Scheduler loop: find g to run, run it, repeat.
+static void
+scheduler(void)
+{
+ G* gp;
+
+ lock(&sched);
+ if(gosave(&m->sched)){
+ // Jumped here via gosave/gogo, so didn't
+ // execute lock(&sched) above.
+ lock(&sched);
+
+ if(sched.predawn)
+ throw("init sleeping");
+
+ // Just finished running m->curg.
+ gp = m->curg;
+ gp->m = nil;
+ sched.mcpu--;
+ if(debug > 1) {
+ lock(&debuglock);
+ printf("m%d sched g%d status %d\n", m->id, gp->goid, gp->status);
+ unlock(&debuglock);
+ }
+ switch(gp->status){
+ case Grunnable:
+ case Gdead:
+ // Shouldn't have been running!
+ throw("bad gp->status in sched");
+ case Grunning:
+ gp->status = Grunnable;
+ gput(gp);
+ break;
+ case Gmoribund:
+ gp->status = Gdead;
+ if(--sched.gcount == 0)
+ exit(0);
+ break;
+ }
+ if(gp->readyonstop){
+ gp->readyonstop = 0;
+ readylocked(gp);
+ }
+ }
+
+ // Find (or wait for) g to run. Unlocks sched.
+ gp = nextgandunlock();
+ gp->readyonstop = 0;
+ gp->status = Grunning;
+ if(debug > 1) {
+ lock(&debuglock);
+ printf("m%d run g%d at %p\n", m->id, gp->goid, gp->sched.PC);
+ traceback(gp->sched.PC, gp->sched.SP+8, gp);
+ unlock(&debuglock);
+ }
+ m->curg = gp;
+ gp->m = m;
+ g = gp;
+ gogo(&gp->sched);
+}
+
+// Enter scheduler. If g->status is Grunning,
+// re-queues g and runs everyone else who is waiting
+// before running g again. If g->status is Gmoribund,
+// kills off g.
+void
+gosched(void)
+{
+ if(g == m->g0)
+ throw("gosched of g0");
+ if(gosave(&g->sched) == 0){
+ g = m->g0;
+ gogo(&m->sched);
+ }
+}
+
+// The goroutine g is about to enter a system call.
+// Record that it's not using the cpu anymore.
+// This is called only from the go syscall library, not
+// from the low-level system calls used by the runtime.
+// The "arguments" are syscall.Syscall's stack frame
+void
+sys·entersyscall(uint64 callerpc, int64 trap)
+{
+ USED(callerpc);
+
+ if(debug > 1) {
+ lock(&debuglock);
+ printf("m%d g%d enter syscall %D\n", m->id, g->goid, trap);
+ unlock(&debuglock);
+ }
+ lock(&sched);
+ g->status = Gsyscall;
+ sched.mcpu--;
+ sched.msyscall++;
+ if(sched.gwait != 0)
+ matchmg();
+ if(sched.waitstop && sched.mcpu <= sched.mcpumax) {
+ sched.waitstop = 0;
+ notewakeup(&sched.stopped);
+ }
+ unlock(&sched);
+ // leave SP around for gc and traceback
+ gosave(&g->sched);
+}
+
+// The goroutine g exited its system call.
+// Arrange for it to run on a cpu again.
+// This is called only from the go syscall library, not
+// from the low-level system calls used by the runtime.
+void
+sys·exitsyscall(void)
+{
+ if(debug > 1) {
+ lock(&debuglock);
+ printf("m%d g%d exit syscall mcpu=%d mcpumax=%d\n", m->id, g->goid, sched.mcpu, sched.mcpumax);
+ unlock(&debuglock);
+ }
+
+ lock(&sched);
+ g->status = Grunning;
+ sched.msyscall--;
+ sched.mcpu++;
+ // Fast path - if there's room for this m, we're done.
+ if(sched.mcpu <= sched.mcpumax) {
+ unlock(&sched);
+ return;
+ }
+ unlock(&sched);
+
+ // Slow path - all the cpus are taken.
+ // The scheduler will ready g and put this m to sleep.
+ // When the scheduler takes g awa from m,
+ // it will undo the sched.mcpu++ above.
+ gosched();
+}
+
+/*
+ * stack layout parameters.
+ * known to linkers.
+ *
+ * g->stackguard is set to point StackGuard bytes
+ * above the bottom of the stack. each function
+ * compares its stack pointer against g->stackguard
+ * to check for overflow. to cut one instruction from
+ * the check sequence for functions with tiny frames,
+ * the stack is allowed to protrude StackSmall bytes
+ * below the stack guard. functions with large frames
+ * don't bother with the check and always call morestack.
+ * the sequences are:
+ *
+ * guard = g->stackguard
+ * frame = function's stack frame size
+ * argsize = size of function arguments (call + return)
+ *
+ * stack frame size <= StackSmall:
+ * CMPQ guard, SP
+ * JHI 3(PC)
+ * MOVQ m->morearg, $(argsize << 32)
+ * CALL sys.morestack(SB)
+ *
+ * stack frame size > StackSmall but < StackBig
+ * LEAQ (frame-StackSmall)(SP), R0
+ * CMPQ guard, R0
+ * JHI 3(PC)
+ * MOVQ m->morearg, $(argsize << 32)
+ * CALL sys.morestack(SB)
+ *
+ * stack frame size >= StackBig:
+ * MOVQ m->morearg, $((argsize << 32) | frame)
+ * CALL sys.morestack(SB)
+ *
+ * the bottom StackGuard - StackSmall bytes are important:
+ * there has to be enough room to execute functions that
+ * refuse to check for stack overflow, either because they
+ * need to be adjacent to the actual caller's frame (sys.deferproc)
+ * or because they handle the imminent stack overflow (sys.morestack).
+ *
+ * for example, sys.deferproc might call malloc,
+ * which does one of the above checks (without allocating a full frame),
+ * which might trigger a call to sys.morestack.
+ * this sequence needs to fit in the bottom section of the stack.
+ * on amd64, sys.morestack's frame is 40 bytes, and
+ * sys.deferproc's frame is 56 bytes. that fits well within
+ * the StackGuard - StackSmall = 128 bytes at the bottom.
+ * there may be other sequences lurking or yet to be written
+ * that require more stack. sys.morestack checks to make sure
+ * the stack has not completely overflowed and should
+ * catch such sequences.
+ */
+enum
+{
+ // byte offset of stack guard (g->stackguard) above bottom of stack.
+ StackGuard = 256,
+
+ // checked frames are allowed to protrude below the guard by
+ // this many bytes. this saves an instruction in the checking
+ // sequence when the stack frame is tiny.
+ StackSmall = 128,
+
+ // extra space in the frame (beyond the function for which
+ // the frame is allocated) is assumed not to be much bigger
+ // than this amount. it may not be used efficiently if it is.
+ StackBig = 4096,
+};
+
+void
+oldstack(void)
+{
+ Stktop *top;
+ uint32 args;
+ byte *sp;
+ uintptr oldsp, oldpc, oldbase, oldguard;
+
+// printf("oldstack m->cret=%p\n", m->cret);
+
+ top = (Stktop*)m->curg->stackbase;
+
+ args = (top->magic>>32) & 0xffffLL;
+
+ sp = (byte*)top;
+ if(args > 0) {
+ args = (args+7) & ~7;
+ sp -= args;
+ mcpy(top->oldsp+2*sizeof(uintptr), sp, args);
+ }
+
+ oldsp = (uintptr)top->oldsp + sizeof(uintptr);
+ oldpc = *(uintptr*)oldsp;
+ oldbase = (uintptr)top->oldbase;
+ oldguard = (uintptr)top->oldguard;
+
+ stackfree((byte*)m->curg->stackguard - StackGuard);
+
+ m->curg->stackbase = (byte*)oldbase;
+ m->curg->stackguard = (byte*)oldguard;
+ m->morestack.SP = (byte*)oldsp;
+ m->morestack.PC = (byte*)oldpc;
+
+ // These two lines must happen in sequence;
+ // once g has been changed, must switch to g's stack
+ // before calling any non-assembly functions.
+ // TODO(rsc): Perhaps make the new g a parameter
+ // to gogoret and setspgoto, so that g is never
+ // explicitly assigned to without also setting
+ // the stack pointer.
+ g = m->curg;
+ gogoret(&m->morestack, m->cret);
+}
+
+#pragma textflag 7
+void
+lessstack(void)
+{
+ g = m->g0;
+ setspgoto(m->sched.SP, oldstack, nil);
+}
+
+void
+newstack(void)
+{
+ int32 frame, args;
+ Stktop *top;
+ byte *stk, *sp;
+ void (*fn)(void);
+
+ frame = m->morearg & 0xffffffffLL;
+ args = (m->morearg>>32) & 0xffffLL;
+
+// printf("newstack frame=%d args=%d moresp=%p morepc=%p\n", frame, args, m->moresp, *(uintptr*)m->moresp);
+
+ if(frame < StackBig)
+ frame = StackBig;
+ frame += 1024; // for more functions, Stktop.
+ stk = stackalloc(frame);
+
+ top = (Stktop*)(stk+frame-sizeof(*top));
+
+ top->oldbase = m->curg->stackbase;
+ top->oldguard = m->curg->stackguard;
+ top->oldsp = m->moresp;
+ top->magic = m->morearg;
+
+ m->curg->stackbase = (byte*)top;
+ m->curg->stackguard = stk + StackGuard;
+
+ sp = (byte*)top;
+
+ if(args > 0) {
+ // Copy args. There have been two function calls
+ // since they got pushed, so skip over those return
+ // addresses.
+ args = (args+7) & ~7;
+ sp -= args;
+ mcpy(sp, m->moresp+2*sizeof(uintptr), args);
+ }
+
+ g = m->curg;
+
+ // sys.morestack's return address
+ fn = (void(*)(void))(*(uintptr*)m->moresp);
+
+// printf("fn=%p\n", fn);
+
+ setspgoto(sp, fn, retfromnewstack);
+
+ *(int32*)345 = 123; // never return
+}
+
+#pragma textflag 7
+void
+sys·morestack(uintptr u)
+{
+ while(g == m->g0) {
+ // very bad news
+ *(int32*)0x1001 = 123;
+ }
+
+ // Morestack's frame is about 0x30 bytes on amd64.
+ // If that the frame ends below the stack bottom, we've already
+ // overflowed. Stop right now.
+ while((byte*)&u - 0x30 < m->curg->stackguard - StackGuard) {
+ // very bad news
+ *(int32*)0x1002 = 123;
+ }
+
+ g = m->g0;
+ m->moresp = (byte*)(&u-1);
+ setspgoto(m->sched.SP, newstack, nil);
+
+ *(int32*)0x1003 = 123; // never return
+}
+
+G*
+malg(int32 stacksize)
+{
+ G *g;
+ byte *stk;
+
+ g = malloc(sizeof(G));
+ stk = stackalloc(stacksize + StackGuard);
+ g->stack0 = stk;
+ g->stackguard = stk + StackGuard;
+ g->stackbase = stk + StackGuard + stacksize;
+ return g;
+}
+
+/*
+ * Newproc and deferproc need to be textflag 7
+ * (no possible stack split when nearing overflow)
+ * because they assume that the arguments to fn
+ * are available sequentially beginning at &arg0.
+ * If a stack split happened, only the one word
+ * arg0 would be copied. It's okay if any functions
+ * they call split the stack below the newproc frame.
+ */
+#pragma textflag 7
+void
+sys·newproc(int32 siz, byte* fn, byte* arg0)
+{
+ byte *stk, *sp;
+ G *newg;
+
+//printf("newproc siz=%d fn=%p", siz, fn);
+
+ siz = (siz+7) & ~7;
+ if(siz > 1024)
+ throw("sys·newproc: too many args");
+
+ lock(&sched);
+
+ if((newg = gfget()) != nil){
+ newg->status = Gwaiting;
+ } else {
+ newg = malg(4096);
+ newg->status = Gwaiting;
+ newg->alllink = allg;
+ allg = newg;
+ }
+ stk = newg->stack0;
+
+ newg->stackguard = stk+StackGuard;
+
+ sp = stk + 4096 - 4*8;
+ newg->stackbase = sp;
+
+ sp -= siz;
+ mcpy(sp, (byte*)&arg0, siz);
+
+ sp -= sizeof(uintptr);
+ *(byte**)sp = (byte*)goexit;
+
+ sp -= sizeof(uintptr); // retpc used by gogo
+ newg->sched.SP = sp;
+ newg->sched.PC = fn;
+
+ sched.gcount++;
+ goidgen++;
+ newg->goid = goidgen;
+
+ readylocked(newg);
+ unlock(&sched);
+
+//printf(" goid=%d\n", newg->goid);
+}
+
+#pragma textflag 7
+void
+sys·deferproc(int32 siz, byte* fn, byte* arg0)
+{
+ Defer *d;
+
+ d = malloc(sizeof(*d) + siz - sizeof(d->args));
+ d->fn = fn;
+ d->sp = (byte*)&arg0;
+ d->siz = siz;
+ mcpy(d->args, d->sp, d->siz);
+
+ d->link = g->defer;
+ g->defer = d;
+}
+
+#pragma textflag 7
+void
+sys·deferreturn(uintptr arg0)
+{
+ Defer *d;
+ byte *sp, *fn;
+ uintptr *caller;
+
+ d = g->defer;
+ if(d == nil)
+ return;
+ sp = (byte*)&arg0;
+ if(d->sp != sp)
+ return;
+ mcpy(d->sp, d->args, d->siz);
+ g->defer = d->link;
+ fn = d->fn;
+ free(d);
+ jmpdefer(fn, sp);
+ }
+
+void
+runtime·Breakpoint(void)
+{
+ breakpoint();
+}
+
+void
+runtime·Goexit(void)
+{
+ goexit();
+}
+
+void
+runtime·Gosched(void)
+{
+ gosched();
+}
+
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/rune.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/rune.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,238 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 2002 by Lucent Technologies.
+ * Portions Copyright 2009 The Go Authors. All rights reserved.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
+
+/*
+ * This code is copied, with slight editing due to type differences,
+ * from a subset of ../lib9/utf/rune.c
+ */
+
+#include "runtime.h"
+
+enum
+{
+ Bit1 = 7,
+ Bitx = 6,
+ Bit2 = 5,
+ Bit3 = 4,
+ Bit4 = 3,
+ Bit5 = 2,
+
+ T1 = ((1<<(Bit1+1))-1) ^ 0xFF, /* 0000 0000 */
+ Tx = ((1<<(Bitx+1))-1) ^ 0xFF, /* 1000 0000 */
+ T2 = ((1<<(Bit2+1))-1) ^ 0xFF, /* 1100 0000 */
+ T3 = ((1<<(Bit3+1))-1) ^ 0xFF, /* 1110 0000 */
+ T4 = ((1<<(Bit4+1))-1) ^ 0xFF, /* 1111 0000 */
+ T5 = ((1<<(Bit5+1))-1) ^ 0xFF, /* 1111 1000 */
+
+ Rune1 = (1<<(Bit1+0*Bitx))-1, /* 0000 0000 0111 1111 */
+ Rune2 = (1<<(Bit2+1*Bitx))-1, /* 0000 0111 1111 1111 */
+ Rune3 = (1<<(Bit3+2*Bitx))-1, /* 1111 1111 1111 1111 */
+ Rune4 = (1<<(Bit4+3*Bitx))-1,
+ /* 0001 1111 1111 1111 1111 1111 */
+
+ Maskx = (1<<Bitx)-1, /* 0011 1111 */
+ Testx = Maskx ^ 0xFF, /* 1100 0000 */
+
+ Runeerror = 0xFFFD,
+ Runeself = 0x80,
+
+ Bad = Runeerror,
+
+ Runemax = 0x10FFFF, /* maximum rune value */
+};
+
+/*
+ * Modified by Wei-Hwa Huang, Google Inc., on 2004-09-24
+ * This is a slower but "safe" version of the old chartorune
+ * that works on strings that are not necessarily null-terminated.
+ *
+ * If you know for sure that your string is null-terminated,
+ * chartorune will be a bit faster.
+ *
+ * It is guaranteed not to attempt to access "length"
+ * past the incoming pointer. This is to avoid
+ * possible access violations. If the string appears to be
+ * well-formed but incomplete (i.e., to get the whole Rune
+ * we'd need to read past str+length) then we'll set the Rune
+ * to Bad and return 0.
+ *
+ * Note that if we have decoding problems for other
+ * reasons, we return 1 instead of 0.
+ */
+int32
+charntorune(int32 *rune, uint8 *str, int32 length)
+{
+ int32 c, c1, c2, c3, l;
+
+ /* When we're not allowed to read anything */
+ if(length <= 0) {
+ goto badlen;
+ }
+
+ /*
+ * one character sequence (7-bit value)
+ * 00000-0007F => T1
+ */
+ c = *(uint8*)str;
+ if(c < Tx) {
+ *rune = c;
+ return 1;
+ }
+
+ // If we can't read more than one character we must stop
+ if(length <= 1) {
+ goto badlen;
+ }
+
+ /*
+ * two character sequence (11-bit value)
+ * 0080-07FF => T2 Tx
+ */
+ c1 = *(uint8*)(str+1) ^ Tx;
+ if(c1 & Testx)
+ goto bad;
+ if(c < T3) {
+ if(c < T2)
+ goto bad;
+ l = ((c << Bitx) | c1) & Rune2;
+ if(l <= Rune1)
+ goto bad;
+ *rune = l;
+ return 2;
+ }
+
+ // If we can't read more than two characters we must stop
+ if(length <= 2) {
+ goto badlen;
+ }
+
+ /*
+ * three character sequence (16-bit value)
+ * 0800-FFFF => T3 Tx Tx
+ */
+ c2 = *(uint8*)(str+2) ^ Tx;
+ if(c2 & Testx)
+ goto bad;
+ if(c < T4) {
+ l = ((((c << Bitx) | c1) << Bitx) | c2) & Rune3;
+ if(l <= Rune2)
+ goto bad;
+ *rune = l;
+ return 3;
+ }
+
+ if (length <= 3)
+ goto badlen;
+
+ /*
+ * four character sequence (21-bit value)
+ * 10000-1FFFFF => T4 Tx Tx Tx
+ */
+ c3 = *(uint8*)(str+3) ^ Tx;
+ if (c3 & Testx)
+ goto bad;
+ if (c < T5) {
+ l = ((((((c << Bitx) | c1) << Bitx) | c2) << Bitx) | c3) & Rune4;
+ if (l <= Rune3 || l > Runemax)
+ goto bad;
+ *rune = l;
+ return 4;
+ }
+
+ // Support for 5-byte or longer UTF-8 would go here, but
+ // since we don't have that, we'll just fall through to bad.
+
+ /*
+ * bad decoding
+ */
+bad:
+ *rune = Bad;
+ return 1;
+badlen:
+ *rune = Bad;
+ return 0;
+
+}
+
+int32
+runetochar(byte *str, int32 rune) /* note: in original, arg2 was pointer */
+{
+ /* Runes are signed, so convert to unsigned for range check. */
+ uint32 c;
+
+ /*
+ * one character sequence
+ * 00000-0007F => 00-7F
+ */
+ c = rune;
+ if(c <= Rune1) {
+ str[0] = c;
+ return 1;
+ }
+
+ /*
+ * two character sequence
+ * 0080-07FF => T2 Tx
+ */
+ if(c <= Rune2) {
+ str[0] = T2 | (c >> 1*Bitx);
+ str[1] = Tx | (c & Maskx);
+ return 2;
+ }
+
+ /*
+ * If the Rune is out of range, convert it to the error rune.
+ * Do this test here because the error rune encodes to three bytes.
+ * Doing it earlier would duplicate work, since an out of range
+ * Rune wouldn't have fit in one or two bytes.
+ */
+ if (c > Runemax)
+ c = Runeerror;
+
+ /*
+ * three character sequence
+ * 0800-FFFF => T3 Tx Tx
+ */
+ if (c <= Rune3) {
+ str[0] = T3 | (c >> 2*Bitx);
+ str[1] = Tx | ((c >> 1*Bitx) & Maskx);
+ str[2] = Tx | (c & Maskx);
+ return 3;
+ }
+
+ /*
+ * four character sequence (21-bit value)
+ * 10000-1FFFFF => T4 Tx Tx Tx
+ */
+ str[0] = T4 | (c >> 3*Bitx);
+ str[1] = Tx | ((c >> 2*Bitx) & Maskx);
+ str[2] = Tx | ((c >> 1*Bitx) & Maskx);
+ str[3] = Tx | (c & Maskx);
+ return 4;
+}
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/runtime.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/runtime.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,462 @@
+// Copyright 2009 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.
+
+#include "runtime.h"
+
+int32 panicking = 0;
+int32 maxround = sizeof(uintptr);
+
+int32
+gotraceback(void)
+{
+ byte *p;
+
+ p = getenv("GOTRACEBACK");
+ if(p == nil || p[0] == '\0')
+ return 1; // default is on
+ return atoi(p);
+}
+
+void
+sys·panicl(int32 lno)
+{
+ uint8 *sp;
+
+ if(panicking) {
+ printf("double panic\n");
+ exit(3);
+ }
+ panicking++;
+
+ printf("\npanic PC=%X\n", (uint64)(uintptr)&lno);
+ sp = (uint8*)&lno;
+ if(gotraceback()){
+ traceback(sys·getcallerpc(&lno), sp, g);
+ tracebackothers(g);
+ }
+ breakpoint(); // so we can grab it in a debugger
+ exit(2);
+}
+
+void
+sys·throwindex(void)
+{
+ throw("index out of range");
+}
+
+void
+sys·throwreturn(void)
+{
+ throw("no return at end of a typed function");
+}
+
+void
+sys·throwinit(void)
+{
+ throw("recursive call during initialization");
+}
+
+void
+throw(int8 *s)
+{
+ printf("throw: %s\n", s);
+ sys·panicl(-1);
+ *(int32*)0 = 0; // not reached
+ exit(1); // even more not reached
+}
+
+void
+mcpy(byte *t, byte *f, uint32 n)
+{
+ while(n > 0) {
+ *t = *f;
+ t++;
+ f++;
+ n--;
+ }
+}
+
+int32
+mcmp(byte *s1, byte *s2, uint32 n)
+{
+ uint32 i;
+ byte c1, c2;
+
+ for(i=0; i<n; i++) {
+ c1 = s1[i];
+ c2 = s2[i];
+ if(c1 < c2)
+ return -1;
+ if(c1 > c2)
+ return +1;
+ }
+ return 0;
+}
+
+
+void
+mmov(byte *t, byte *f, uint32 n)
+{
+ if(t < f) {
+ while(n > 0) {
+ *t = *f;
+ t++;
+ f++;
+ n--;
+ }
+ } else {
+ t += n;
+ f += n;
+ while(n > 0) {
+ t--;
+ f--;
+ *t = *f;
+ n--;
+ }
+ }
+}
+
+byte*
+mchr(byte *p, byte c, byte *ep)
+{
+ for(; p < ep; p++)
+ if(*p == c)
+ return p;
+ return nil;
+}
+
+uint32
+rnd(uint32 n, uint32 m)
+{
+ uint32 r;
+
+ if(m > maxround)
+ m = maxround;
+ r = n % m;
+ if(r)
+ n += m-r;
+ return n;
+}
+
+static int32 argc;
+static uint8** argv;
+
+Array os·Args;
+Array os·Envs;
+
+void
+args(int32 c, uint8 **v)
+{
+ argc = c;
+ argv = v;
+}
+
+void
+goargs(void)
+{
+ String *gargv;
+ String *genvv;
+ int32 i, envc;
+
+ for(envc=0; argv[argc+1+envc] != 0; envc++)
+ ;
+
+ gargv = malloc(argc*sizeof gargv[0]);
+ genvv = malloc(envc*sizeof genvv[0]);
+
+ for(i=0; i<argc; i++)
+ gargv[i] = gostring(argv[i]);
+ os·Args.array = (byte*)gargv;
+ os·Args.nel = argc;
+ os·Args.cap = argc;
+
+ for(i=0; i<envc; i++)
+ genvv[i] = gostring(argv[argc+1+i]);
+ os·Envs.array = (byte*)genvv;
+ os·Envs.nel = envc;
+ os·Envs.cap = envc;
+}
+
+byte*
+getenv(int8 *s)
+{
+ int32 i, j, len;
+ byte *v, *bs;
+ String* envv;
+ int32 envc;
+
+ bs = (byte*)s;
+ len = findnull(bs);
+ envv = (String*)os·Envs.array;
+ envc = os·Envs.nel;
+ for(i=0; i<envc; i++){
+ if(envv[i].len <= len)
+ continue;
+ v = envv[i].str;
+ for(j=0; j<len; j++)
+ if(bs[j] != v[j])
+ goto nomatch;
+ if(v[len] != '=')
+ goto nomatch;
+ return v+len+1;
+ nomatch:;
+ }
+ return nil;
+}
+
+
+int32
+atoi(byte *p)
+{
+ int32 n;
+
+ n = 0;
+ while('0' <= *p && *p <= '9')
+ n = n*10 + *p++ - '0';
+ return n;
+}
+
+void
+check(void)
+{
+ int8 a;
+ uint8 b;
+ int16 c;
+ uint16 d;
+ int32 e;
+ uint32 f;
+ int64 g;
+ uint64 h;
+ float32 i;
+ float64 j;
+ void* k;
+ uint16* l;
+
+ if(sizeof(a) != 1) throw("bad a");
+ if(sizeof(b) != 1) throw("bad b");
+ if(sizeof(c) != 2) throw("bad c");
+ if(sizeof(d) != 2) throw("bad d");
+ if(sizeof(e) != 4) throw("bad e");
+ if(sizeof(f) != 4) throw("bad f");
+ if(sizeof(g) != 8) throw("bad g");
+ if(sizeof(h) != 8) throw("bad h");
+ if(sizeof(i) != 4) throw("bad i");
+ if(sizeof(j) != 8) throw("bad j");
+ if(sizeof(k) != sizeof(uintptr)) throw("bad k");
+ if(sizeof(l) != sizeof(uintptr)) throw("bad l");
+// prints(1"check ok\n");
+
+ uint32 z;
+ z = 1;
+ if(!cas(&z, 1, 2))
+ throw("cas1");
+ if(z != 2)
+ throw("cas2");
+
+ z = 4;
+ if(cas(&z, 5, 6))
+ throw("cas3");
+ if(z != 4)
+ throw("cas4");
+
+ initsig();
+}
+
+/*
+ * map and chan helpers for
+ * dealing with unknown types
+ */
+static uintptr
+memhash(uint32 s, void *a)
+{
+ byte *b;
+ uintptr hash;
+
+ b = a;
+ if(sizeof(hash) == 4)
+ hash = 2860486313U;
+ else
+ hash = 33054211828000289ULL;
+ while(s > 0) {
+ if(sizeof(hash) == 4)
+ hash = (hash ^ *b) * 3267000013UL;
+ else
+ hash = (hash ^ *b) * 23344194077549503ULL;
+ b++;
+ s--;
+ }
+ return hash;
+}
+
+static uint32
+memequal(uint32 s, void *a, void *b)
+{
+ byte *ba, *bb;
+ uint32 i;
+
+ ba = a;
+ bb = b;
+ for(i=0; i<s; i++)
+ if(ba[i] != bb[i])
+ return 0;
+ return 1;
+}
+
+static void
+memprint(uint32 s, void *a)
+{
+ uint64 v;
+
+ v = 0xbadb00b;
+ switch(s) {
+ case 1:
+ v = *(uint8*)a;
+ break;
+ case 2:
+ v = *(uint16*)a;
+ break;
+ case 4:
+ v = *(uint32*)a;
+ break;
+ case 8:
+ v = *(uint64*)a;
+ break;
+ }
+ sys·printint(v);
+}
+
+static void
+memcopy(uint32 s, void *a, void *b)
+{
+ byte *ba, *bb;
+ uint32 i;
+
+ ba = a;
+ bb = b;
+ if(bb == nil) {
+ for(i=0; i<s; i++)
+ ba[i] = 0;
+ return;
+ }
+ for(i=0; i<s; i++)
+ ba[i] = bb[i];
+}
+
+static uintptr
+strhash(uint32 s, String *a)
+{
+ USED(s);
+ return memhash((*a).len, (*a).str);
+}
+
+static uint32
+strequal(uint32 s, String *a, String *b)
+{
+ USED(s);
+ return cmpstring(*a, *b) == 0;
+}
+
+static void
+strprint(uint32 s, String *a)
+{
+ USED(s);
+ sys·printstring(*a);
+}
+
+static uintptr
+interhash(uint32 s, Iface *a)
+{
+ USED(s);
+ return ifacehash(*a);
+}
+
+static void
+interprint(uint32 s, Iface *a)
+{
+ USED(s);
+ sys·printiface(*a);
+}
+
+static uint32
+interequal(uint32 s, Iface *a, Iface *b)
+{
+ USED(s);
+ return ifaceeq(*a, *b);
+}
+
+static uintptr
+nilinterhash(uint32 s, Eface *a)
+{
+ USED(s);
+ return efacehash(*a);
+}
+
+static void
+nilinterprint(uint32 s, Eface *a)
+{
+ USED(s);
+ sys·printeface(*a);
+}
+
+static uint32
+nilinterequal(uint32 s, Eface *a, Eface *b)
+{
+ USED(s);
+ return efaceeq(*a, *b);
+}
+
+uintptr
+nohash(uint32 s, void *a)
+{
+ USED(s);
+ USED(a);
+ throw("hash of unhashable type");
+ return 0;
+}
+
+uint32
+noequal(uint32 s, void *a, void *b)
+{
+ USED(s);
+ USED(a);
+ USED(b);
+ throw("comparing uncomparable types");
+ return 0;
+}
+
+static void
+noprint(uint32 s, void *a)
+{
+ USED(s);
+ USED(a);
+ throw("print of unprintable type");
+}
+
+static void
+nocopy(uint32 s, void *a, void *b)
+{
+ USED(s);
+ USED(a);
+ USED(b);
+ throw("copy of uncopyable type");
+}
+
+Alg
+algarray[] =
+{
+[AMEM] { memhash, memequal, memprint, memcopy },
+[ANOEQ] { nohash, noequal, memprint, memcopy },
+[ASTRING] { strhash, strequal, strprint, memcopy },
+[AINTER] { interhash, interequal, interprint, memcopy },
+[ANILINTER] { nilinterhash, nilinterequal, nilinterprint, memcopy },
+[AFAKE] { nohash, noequal, noprint, nocopy },
+};
+
+#pragma textflag 7
+void
+FLUSH(void *v)
+{
+ USED(v);
+}
+
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/runtime.go
--- a/src/lib/runtime/runtime.go Sat Jun 06 21:56:04 2009 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,28 +0,0 @@
-// Copyright 2009 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.
-
-/*
- The runtime package contains operations that interact with Go's runtime system,
- such as functions to control goroutines.
- */
-package runtime
-
-// These functions are implemented in the base runtime library, ../../runtime/.
-
-// Gosched yields the processor, allowing other goroutines to run. It does not
-// suspend the current goroutine, so execution resumes automatically.
-func Gosched()
-
-// Goexit terminates the goroutine that calls it. No other goroutine is affected.
-func Goexit()
-
-// Breakpoint() executes a breakpoint trap.
-func Breakpoint()
-
-// Caller reports file and line number information about function invocations on
-// the calling goroutine's stack. The argument is the number of stack frames to
-// ascend, with 1 identifying the the caller of Caller. The return values report the
-// program counter, file name, and line number within the file of the corresponding
-// call. The boolean ok is false if it was not possible to recover the information.
-func Caller(n int) (pc uintptr, file string, line int, ok bool)
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/runtime.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/runtime.h Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,464 @@
+// Copyright 2009 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.
+
+/*
+ * basic types
+ */
+typedef signed char int8;
+typedef unsigned char uint8;
+typedef signed short int16;
+typedef unsigned short uint16;
+typedef signed int int32;
+typedef unsigned int uint32;
+typedef signed long long int int64;
+typedef unsigned long long int uint64;
+typedef float float32;
+typedef double float64;
+
+#ifdef _64BIT
+typedef uint64 uintptr;
+#else
+typedef uint32 uintptr;
+#endif
+
+/*
+ * get rid of C types
+ * the / / / forces a syntax error immediately,
+ * which will show "last name: XXunsigned".
+ */
+#define unsigned XXunsigned / / /
+#define signed XXsigned / / /
+#define char XXchar / / /
+#define short XXshort / / /
+#define int XXint / / /
+#define long XXlong / / /
+#define float XXfloat / / /
+#define double XXdouble / / /
+
+/*
+ * defined types
+ */
+typedef uint8 bool;
+typedef uint8 byte;
+typedef struct Alg Alg;
+typedef struct Array Array;
+typedef struct Func Func;
+typedef struct G G;
+typedef struct Gobuf Gobuf;
+typedef struct Lock Lock;
+typedef struct M M;
+typedef struct Mem Mem;
+typedef union Note Note;
+typedef struct Stktop Stktop;
+typedef struct String String;
+typedef struct Usema Usema;
+typedef struct SigTab SigTab;
+typedef struct MCache MCache;
+typedef struct Iface Iface;
+typedef struct Itype Itype;
+typedef struct Eface Eface;
+typedef struct Sigt Sigt;
+typedef struct Defer Defer;
+
+/*
+ * per cpu declaration
+ */
+extern register G* g; // R15
+extern register M* m; // R14
+
+/*
+ * defined constants
+ */
+enum
+{
+ // G status
+ Gidle,
+ Grunnable,
+ Grunning,
+ Gsyscall,
+ Gwaiting,
+ Gmoribund,
+ Gdead,
+};
+enum
+{
+ true = 1,
+ false = 0,
+};
+
+/*
+ * structures
+ */
+struct Lock
+{
+ uint32 key;
+ uint32 sema; // for OS X
+};
+struct Usema
+{
+ uint32 u;
+ uint32 k;
+};
+union Note
+{
+ struct { // Linux
+ Lock lock;
+ };
+ struct { // OS X
+ int32 wakeup;
+ Usema sema;
+ };
+};
+struct String
+{
+ byte* str;
+ int32 len;
+};
+struct Iface
+{
+ Itype* type;
+ void* data;
+};
+struct Eface
+{
+ Sigt* type;
+ void* data;
+};
+
+struct Array
+{ // must not move anything
+ byte* array; // actual data
+ uint32 nel; // number of elements
+ uint32 cap; // allocated number of elements
+};
+struct Gobuf
+{
+ byte* SP;
+ byte* PC;
+};
+struct G
+{
+ byte* stackguard; // must not move
+ byte* stackbase; // must not move
+ Defer* defer; // must not move
+ byte* stack0; // first stack segment
+ Gobuf sched;
+ G* alllink; // on allg
+ void* param; // passed parameter on wakeup
+ int16 status;
+ int32 goid;
+ int32 selgen; // valid sudog pointer
+ G* schedlink;
+ bool readyonstop;
+ M* m; // for debuggers
+};
+struct Mem
+{
+ uint8* hunk;
+ uint32 nhunk;
+ uint64 nmmap;
+ uint64 nmal;
+};
+struct M
+{
+ G* g0; // g0 w interrupt stack - must not move
+ uint64 morearg; // arg to morestack - must not move
+ uint64 cret; // return value from C - must not move
+ uint64 procid; // for debuggers - must not move
+ G* gsignal; // signal-handling G - must not move
+ G* curg; // current running goroutine - must not move
+ G* lastg; // last running goroutine - to emulate fifo - must not move
+ uint32 tls[8]; // thread-local storage (for 386 extern register) - must not move
+ Gobuf sched;
+ Gobuf morestack;
+ byte* moresp;
+ int32 siz1;
+ int32 siz2;
+ int32 id;
+ int32 mallocing;
+ int32 locks;
+ Note havenextg;
+ G* nextg;
+ M* schedlink;
+ Mem mem;
+ uint32 machport; // Return address for Mach IPC (OS X)
+ MCache *mcache;
+};
+struct Stktop
+{
+ uint8* oldbase;
+ uint8* oldsp;
+ uint64 magic;
+ uint8* oldguard;
+};
+struct Alg
+{
+ uintptr (*hash)(uint32, void*);
+ uint32 (*equal)(uint32, void*, void*);
+ void (*print)(uint32, void*);
+ void (*copy)(uint32, void*, void*);
+};
+struct SigTab
+{
+ int32 flags;
+ int8 *name;
+};
+enum
+{
+ SigCatch = 1<<0,
+ SigIgnore = 1<<1,
+ SigRestart = 1<<2,
+};
+
+// (will be) shared with go; edit ../cmd/6g/sys.go too.
+// should move out of sys.go eventually.
+// also eventually, the loaded symbol table should
+// be closer to this form.
+struct Func
+{
+ String name;
+ String type; // go type string
+ String src; // src file name
+ uint64 entry; // entry pc
+ int64 frame; // stack frame size
+ Array pcln; // pc/ln tab for this func
+ int64 pc0; // starting pc, ln for table
+ int32 ln0;
+ int32 args; // number of 32-bit in/out args
+ int32 locals; // number of 32-bit locals
+};
+
+/*
+ * defined macros
+ * you need super-goru privilege
+ * to add this list.
+ */
+#define nelem(x) (sizeof(x)/sizeof((x)[0]))
+#define nil ((void*)0)
+
+/*
+ * known to compiler
+ */
+enum
+{
+ AMEM,
+ ANOEQ,
+ ASTRING,
+ AINTER,
+ ANILINTER,
+ AFAKE,
+ Amax
+};
+
+/*
+ * deferred subroutine calls
+ */
+struct Defer
+{
+ int32 siz;
+ byte* sp;
+ byte* fn;
+ Defer* link;
+ byte args[8]; // padded to actual size
+};
+
+/*
+ * external data
+ */
+extern Alg algarray[Amax];
+extern String emptystring;
+G* allg;
+int32 goidgen;
+extern int32 gomaxprocs;
+extern int32 panicking;
+extern int32 maxround;
+
+/*
+ * common functions and data
+ */
+int32 strcmp(byte*, byte*);
+int32 findnull(byte*);
+void dump(byte*, int32);
+int32 runetochar(byte*, int32);
+int32 charntorune(int32*, uint8*, int32);
+
+/*
+ * very low level c-called
+ */
+int32 gogo(Gobuf*);
+int32 gosave(Gobuf*);
+int32 gogoret(Gobuf*, uint64);
+void retfromnewstack(void);
+void goargs(void);
+void setspgoto(byte*, void(*)(void), void(*)(void));
+void FLUSH(void*);
+void* getu(void);
+void throw(int8*);
+uint32 rnd(uint32, uint32);
+void prints(int8*);
+void printf(int8*, ...);
+byte* mchr(byte*, byte, byte*);
+void mcpy(byte*, byte*, uint32);
+int32 mcmp(byte*, byte*, uint32);
+void mmov(byte*, byte*, uint32);
+void* mal(uint32);
+uint32 cmpstring(String, String);
+String gostring(byte*);
+void initsig(void);
+int32 gotraceback(void);
+void traceback(uint8 *pc, uint8 *sp, G* gp);
+void tracebackothers(G*);
+int32 open(byte*, int32, ...);
+int32 read(int32, void*, int32);
+int32 write(int32, void*, int32);
+void close(int32);
+int32 fstat(int32, void*);
+bool cas(uint32*, uint32, uint32);
+void jmpdefer(byte*, void*);
+void exit1(int32);
+void ready(G*);
+byte* getenv(int8*);
+int32 atoi(byte*);
+void newosproc(M *m, G *g, void *stk, void (*fn)(void));
+void sigaltstack(void*, void*);
+void signalstack(byte*, int32);
+G* malg(int32);
+void minit(void);
+Func* findfunc(uintptr);
+int32 funcline(Func*, uint64);
+void* stackalloc(uint32);
+void stackfree(void*);
+MCache* allocmcache(void);
+void mallocinit(void);
+bool ifaceeq(Iface, Iface);
+bool efaceeq(Eface, Eface);
+uintptr ifacehash(Iface);
+uintptr efacehash(Eface);
+uintptr nohash(uint32, void*);
+uint32 noequal(uint32, void*, void*);
+void* malloc(uintptr size);
+void* mallocgc(uintptr size);
+void free(void *v);
+void exit(int32);
+void breakpoint(void);
+void gosched(void);
+void goexit(void);
+
+#pragma varargck argpos printf 1
+
+#pragma varargck type "d" int32
+#pragma varargck type "d" uint32
+#pragma varargck type "D" int64
+#pragma varargck type "D" uint64
+#pragma varargck type "x" int32
+#pragma varargck type "x" uint32
+#pragma varargck type "X" int64
+#pragma varargck type "X" uint64
+#pragma varargck type "p" void*
+#pragma varargck type "p" uintptr
+#pragma varargck type "s" int8*
+#pragma varargck type "s" uint8*
+#pragma varargck type "S" String
+
+// TODO(rsc): Remove. These are only temporary,
+// for the mark and sweep collector.
+void stoptheworld(void);
+void starttheworld(void);
+
+/*
+ * mutual exclusion locks. in the uncontended case,
+ * as fast as spin locks (just a few user-level instructions),
+ * but on the contention path they sleep in the kernel.
+ * a zeroed Lock is unlocked (no need to initialize each lock).
+ */
+void lock(Lock*);
+void unlock(Lock*);
+
+/*
+ * sleep and wakeup on one-time events.
+ * before any calls to notesleep or notewakeup,
+ * must call noteclear to initialize the Note.
+ * then, any number of threads can call notesleep
+ * and exactly one thread can call notewakeup (once).
+ * once notewakeup has been called, all the notesleeps
+ * will return. future notesleeps will return immediately.
+ */
+void noteclear(Note*);
+void notesleep(Note*);
+void notewakeup(Note*);
+
+/*
+ * Redefine methods for the benefit of gcc, which does not support
+ * UTF-8 characters in identifiers.
+ */
+#ifndef __GNUC__
+#define sys_memclr sys·memclr
+#define sys_write sys·write
+#define sys_catstring sys·catstring
+#define sys_cmpstring sys·cmpstring
+#define sys_getcallerpc sys·getcallerpc
+#define sys_indexstring sys·indexstring
+#define sys_intstring sys·intstring
+#define sys_mal sys·mal
+#define sys_mmap sys·mmap
+#define sys_printarray sys·printarray
+#define sys_printbool sys·printbool
+#define sys_printfloat sys·printfloat
+#define sys_printhex sys·printhex
+#define sys_printint sys·printint
+#define sys_printiface sys·printiface
+#define sys_printeface sys·printeface
+#define sys_printpc sys·printpc
+#define sys_printpointer sys·printpointer
+#define sys_printstring sys·printstring
+#define sys_printuint sys·printuint
+#define sys_setcallerpc sys·setcallerpc
+#define sys_slicestring sys·slicestring
+#endif
+
+/*
+ * low level go-called
+ */
+void sys_write(int32, void*, int32);
+uint8* sys_mmap(byte*, uint32, int32, int32, int32, uint32);
+void sys_memclr(byte*, uint32);
+void sys_setcallerpc(void*, void*);
+void* sys_getcallerpc(void*);
+
+/*
+ * runtime go-called
+ */
+void sys_printbool(bool);
+void sys_printfloat(float64);
+void sys_printint(int64);
+void sys_printiface(Iface);
+void sys_printeface(Eface);
+void sys_printstring(String);
+void sys_printpc(void*);
+void sys_printpointer(void*);
+void sys_printuint(uint64);
+void sys_printhex(uint64);
+void sys_printarray(Array);
+void sys_catstring(String, String, String);
+void sys_cmpstring(String, String, int32);
+void sys_slicestring(String, int32, int32, String);
+void sys_indexstring(String, int32, byte);
+void sys_intstring(int64, String);
+
+/*
+ * wrapped for go users
+ */
+float64 Inf(int32 sign);
+float64 NaN(void);
+float32 float32frombits(uint32 i);
+uint32 float32tobits(float32 f);
+float64 float64frombits(uint64 i);
+uint64 float64tobits(float64 f);
+float64 frexp(float64 d, int32 *ep);
+bool isInf(float64 f, int32 sign);
+bool isNaN(float64 f);
+float64 ldexp(float64 d, int32 e);
+float64 modf(float64 d, float64 *ip);
+void semacquire(uint32*);
+void semrelease(uint32*);
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/sema.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/sema.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,176 @@
+// Copyright 2009 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.
+
+// Semaphore implementation exposed to Go.
+// Intended use is provide a sleep and wakeup
+// primitive that can be used in the contended case
+// of other synchronization primitives.
+// Thus it targets the same goal as Linux's futex,
+// but it has much simpler semantics.
+//
+// That is, don't think of these as semaphores.
+// Think of them as a way to implement sleep and wakeup
+// such that every sleep is paired with a single wakeup,
+// even if, due to races, the wakeup happens before the sleep.
+//
+// See Mullender and Cox, ``Semaphores in Plan 9,''
+// http://swtch.com/semaphore.pdf
+
+#include "runtime.h"
+
+typedef struct Sema Sema;
+struct Sema
+{
+ uint32 *addr;
+ G *g;
+ Sema *prev;
+ Sema *next;
+};
+
+// TODO: For now, a linked list; maybe a hash table of linked lists later.
+static Sema *semfirst, *semlast;
+static Lock semlock;
+
+static void
+semqueue(uint32 *addr, Sema *s)
+{
+ s->addr = addr;
+ s->g = nil;
+
+ lock(&semlock);
+ s->prev = semlast;
+ s->next = nil;
+ if(semlast)
+ semlast->next = s;
+ else
+ semfirst = s;
+ semlast = s;
+ unlock(&semlock);
+}
+
+static void
+semdequeue(Sema *s)
+{
+ lock(&semlock);
+ if(s->next)
+ s->next->prev = s->prev;
+ else
+ semlast = s->prev;
+ if(s->prev)
+ s->prev->next = s->next;
+ else
+ semfirst = s->next;
+ s->prev = nil;
+ s->next = nil;
+ unlock(&semlock);
+}
+
+static void
+semwakeup(uint32 *addr)
+{
+ Sema *s;
+
+ lock(&semlock);
+ for(s=semfirst; s; s=s->next) {
+ if(s->addr == addr && s->g) {
+ ready(s->g);
+ s->g = nil;
+ break;
+ }
+ }
+ unlock(&semlock);
+}
+
+// Step 1 of sleep: make ourselves available for wakeup.
+// TODO(rsc): Maybe we can write a version without
+// locks by using cas on s->g. Maybe not: I need to
+// think more about whether it would be correct.
+static void
+semsleep1(Sema *s)
+{
+ lock(&semlock);
+ s->g = g;
+ unlock(&semlock);
+}
+
+// Decided not to go through with it: undo step 1.
+static void
+semsleepundo1(Sema *s)
+{
+ lock(&semlock);
+ if(s->g != nil) {
+ s->g = nil; // back ourselves out
+ } else {
+ // If s->g == nil already, semwakeup
+ // already readied us. Since we never stopped
+ // running, readying us just set g->readyonstop.
+ // Clear it.
+ if(g->readyonstop == 0)
+ *(int32*)0x555 = 555;
+ g->readyonstop = 0;
+ }
+ unlock(&semlock);
+}
+
+// Step 2: wait for the wakeup.
+static void
+semsleep2(Sema *s)
+{
+ USED(s);
+ g->status = Gwaiting;
+ gosched();
+}
+
+static int32
+cansemacquire(uint32 *addr)
+{
+ uint32 v;
+
+ while((v = *addr) > 0)
+ if(cas(addr, v, v-1))
+ return 1;
+ return 0;
+}
+
+// For now has no return value.
+// Might return an ok (not interrupted) bool in the future?
+void
+semacquire(uint32 *addr)
+{
+ Sema s;
+
+ // Easy case.
+ if(cansemacquire(addr))
+ return;
+
+ // Harder case:
+ // queue
+ // try semacquire one more time, sleep if failed
+ // dequeue
+ // wake up one more guy to avoid races (TODO(rsc): maybe unnecessary?)
+ semqueue(addr, &s);
+ for(;;) {
+ semsleep1(&s);
+ if(cansemacquire(addr)) {
+ semsleepundo1(&s);
+ break;
+ }
+ semsleep2(&s);
+ }
+ semdequeue(&s);
+ semwakeup(addr);
+}
+
+void
+semrelease(uint32 *addr)
+{
+ uint32 v;
+
+ for(;;) {
+ v = *addr;
+ if(cas(addr, v, v+1))
+ break;
+ }
+ semwakeup(addr);
+}
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/sema_go.cgo
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/sema_go.cgo Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,15 @@
+// Copyright 2009 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 sync
+#include "runtime.h"
+
+func semacquire(addr *uint32) {
+ semacquire(addr);
+}
+
+func semrelease(addr *uint32) {
+ semrelease(addr);
+}
+
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/string.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/string.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,263 @@
+// Copyright 2009 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.
+
+#include "runtime.h"
+
+String emptystring;
+
+int32
+findnull(byte *s)
+{
+ int32 l;
+
+ if(s == nil)
+ return 0;
+ for(l=0; s[l]!=0; l++)
+ ;
+ return l;
+}
+
+int32 maxstring;
+
+String
+gostringsize(int32 l)
+{
+ String s;
+
+ if(l == 0)
+ return emptystring;
+ s.str = mal(l+1); // leave room for NUL for C runtime (e.g., callers of getenv)
+ s.len = l;
+ if(l > maxstring)
+ maxstring = l;
+ return s;
+}
+
+String
+gostring(byte *str)
+{
+ int32 l;
+ String s;
+
+ l = findnull(str);
+ s = gostringsize(l);
+ mcpy(s.str, str, l);
+ return s;
+}
+
+void
+sys·catstring(String s1, String s2, String s3)
+{
+ if(s1.len == 0) {
+ s3 = s2;
+ goto out;
+ }
+ if(s2.len == 0) {
+ s3 = s1;
+ goto out;
+ }
+
+ s3 = gostringsize(s1.len + s2.len);
+ mcpy(s3.str, s1.str, s1.len);
+ mcpy(s3.str+s1.len, s2.str, s2.len);
+
+out:
+ FLUSH(&s3);
+}
+
+static void
+prbounds(int8* s, int32 a, int32 b, int32 c)
+{
+ prints(s);
+ prints(" ");
+ sys·printint(a);
+ prints("<");
+ sys·printint(b);
+ prints(">");
+ sys·printint(c);
+ prints("\n");
+ throw("string bounds");
+}
+
+uint32
+cmpstring(String s1, String s2)
+{
+ uint32 i, l;
+ byte c1, c2;
+
+ l = s1.len;
+ if(s2.len < l)
+ l = s2.len;
+ for(i=0; i<l; i++) {
+ c1 = s1.str[i];
+ c2 = s2.str[i];
+ if(c1 < c2)
+ return -1;
+ if(c1 > c2)
+ return +1;
+ }
+ if(s1.len < s2.len)
+ return -1;
+ if(s1.len > s2.len)
+ return +1;
+ return 0;
+}
+
+void
+sys·cmpstring(String s1, String s2, int32 v)
+{
+ v = cmpstring(s1, s2);
+ FLUSH(&v);
+}
+
+int32
+strcmp(byte *s1, byte *s2)
+{
+ uint32 i;
+ byte c1, c2;
+
+ for(i=0;; i++) {
+ c1 = s1[i];
+ c2 = s2[i];
+ if(c1 < c2)
+ return -1;
+ if(c1 > c2)
+ return +1;
+ if(c1 == 0)
+ return 0;
+ }
+}
+
+void
+sys·slicestring(String si, int32 lindex, int32 hindex, String so)
+{
+ int32 l;
+
+ if(lindex < 0 || lindex > si.len ||
+ hindex < lindex || hindex > si.len) {
+ sys·printpc(&si);
+ prints(" ");
+ prbounds("slice", lindex, si.len, hindex);
+ }
+
+ l = hindex-lindex;
+ so.str = si.str + lindex;
+ so.len = l;
+
+// alternate to create a new string
+// so = gostringsize(l);
+// mcpy(so.str, si.str+lindex, l);
+
+ FLUSH(&so);
+}
+
+void
+sys·indexstring(String s, int32 i, byte b)
+{
+ if(i < 0 || i >= s.len) {
+ sys·printpc(&s);
+ prints(" ");
+ prbounds("index", 0, i, s.len);
+ }
+
+ b = s.str[i];
+ FLUSH(&b);
+}
+
+void
+sys·intstring(int64 v, String s)
+{
+ s = gostringsize(8);
+ s.len = runetochar(s.str, v);
+ FLUSH(&s);
+}
+
+void
+sys·arraystring(Array b, String s)
+{
+ s = gostringsize(b.nel);
+ mcpy(s.str, b.array, s.len);
+ FLUSH(&s);
+}
+
+void
+sys·arraystringi(Array b, String s)
+{
+ int32 siz1, siz2, i;
+ int32 *a;
+ byte dum[8];
+
+ a = (int32*)b.array;
+ siz1 = 0;
+ for(i=0; i<b.nel; i++) {
+ siz1 += runetochar(dum, a[i]);
+ }
+
+ s = gostringsize(siz1+4);
+ siz2 = 0;
+ for(i=0; i<b.nel; i++) {
+ // check for race
+ if(siz2 >= siz1)
+ break;
+ siz2 += runetochar(s.str+siz2, a[i]);
+ }
+ s.len = siz2;
+
+ FLUSH(&s);
+}
+
+enum
+{
+ Runeself = 0x80,
+};
+
+// func stringiter(string, int) (retk int);
+void
+sys·stringiter(String s, int32 k, int32 retk)
+{
+ int32 l;
+
+ if(k >= s.len) {
+ // retk=0 is end of iteration
+ retk = 0;
+ goto out;
+ }
+
+ l = s.str[k];
+ if(l < Runeself) {
+ retk = k+1;
+ goto out;
+ }
+
+ // multi-char rune
+ retk = k + charntorune(&l, s.str+k, s.len-k);
+
+out:
+ FLUSH(&retk);
+}
+
+// func stringiter2(string, int) (retk int, retv any);
+void
+sys·stringiter2(String s, int32 k, int32 retk, int32 retv)
+{
+ if(k >= s.len) {
+ // retk=0 is end of iteration
+ retk = 0;
+ retv = 0;
+ goto out;
+ }
+
+ retv = s.str[k];
+ if(retv < Runeself) {
+ retk = k+1;
+ goto out;
+ }
+
+ // multi-char rune
+ retk = k + charntorune(&retv, s.str+k, s.len-k);
+
+out:
+ FLUSH(&retk);
+ FLUSH(&retv);
+}
diff -r 6aabab677469 -r 31d3a7baefdd src/lib/runtime/symtab.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/runtime/symtab.c Sat Jun 06 22:04:39 2009 -0700
@@ -0,0 +1,377 @@
+// Copyright 2009 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.
+
+// Runtime symbol table access. Work in progress.
+// The Plan 9 symbol table is not in a particularly convenient form.
+// The routines here massage it into a more usable form; eventually
+// we'll change 6l to do this for us, but it is easier to experiment
+// here than to change 6l and all the other tools.
+//
+// The symbol table also needs to be better integrated with the type
+// strings table in the future. This is just a quick way to get started
+// and figure out exactly what we want.
+
+#include "runtime.h"
+
+// TODO(rsc): Move this *under* the text segment.
+// Then define names for these addresses instead of hard-coding magic ones.
+#ifdef _64BIT
+#define SYMCOUNTS ((int32*)(0x99LL<<32)) // known to 6l
+#define SYMDATA ((byte*)(0x99LL<<32) + 8)
+#else
+#define SYMCOUNTS ((int32*)(0x99LL<<24)) // known to 8l
+#define SYMDATA ((byte*)(0x99LL<<24) + 8)
+#endif
+
+
+// Return a pointer to a byte array containing the symbol table segment.
+void
+sys·symdat(Array *symtab, Array *pclntab)
+{
+ Array *a;
+ int32 *v;
+
+ v = SYMCOUNTS;
+
+ a = mal(sizeof *a);
+ a->nel = v[0];
+ a->cap = a->nel;
+ a->array = SYMDATA;
+ symtab = a;
+ FLUSH(&symtab);
+
+ a = mal(sizeof *a);
+ a->nel = v[1];
+ a->cap = a->nel;
+ a->array = SYMDATA + v[0];
+ pclntab = a;
+ FLUSH(&pclntab);
+}
+
+typedef struct Sym Sym;
+struct Sym
+{
+ uintptr value;
+ byte symtype;
+ byte *name;
+ byte *gotype;
+};
+
+// Walk over symtab, calling fn(&s) for each symbol.
+static void
+walksymtab(void (*fn)(Sym*))
+{
+ int32 *v;
+ byte *p, *ep, *q;
+ Sym s;
+
+ v = SYMCOUNTS;
+ p = SYMDATA;
+ ep = p + v[0];
+ while(p < ep) {
+ if(p + 7 > ep)
+ break;
+ s.value = ((uint32)p[0]<<24) | ((uint32)p[1]<<16) | ((uint32)p[2]<<8) | ((uint32)p[3]);
+ if(!(p[4]&0x80))
+ break;
+ s.symtype = p[4] & ~0x80;
+ p += 5;
+ s.name = p;
+ if(s.symtype == 'z' || s.symtype == 'Z') {
+ // path reference string - skip first byte,
+ // then 2-byte pairs ending at two zeros.
+ q = p+1;
+ for(;;) {
+ if(q+2 > ep)
+ return;
+ if(q[0] == '\0' && q[1] == '\0')
+ break;
+ q += 2;
+ }
+ p = q+2;
+ }else{
+ q = mchr(p, '\0', ep);
+ if(q == nil)
+ break;
+ p = q+1;
+ }
+ q = mchr(p, '\0', ep);
+ if(q == nil)
+ break;
+ s.gotype = p;
+ p = q+1;
+ fn(&s);
+ }
+}
+
+// Symtab walker; accumulates info about functions.
+
+static Func *func;
+static int32 nfunc;
+
+static byte **fname;
+static int32 nfname;
+
+static void
+dofunc(Sym *sym)
+{
+ Func *f;
+
+ switch(sym->symtype) {
+ case 't':
+ case 'T':
+ if(strcmp(sym->name, (byte*)"etext") == 0)
+ break;
+ if(func == nil) {
+ nfunc++;
+ break;
+ }
+ f = &func[nfunc++];
+ f->name = gostring(sym->name);
+ f->entry = sym->value;
+ break;
+ case 'm':
+ if(nfunc > 0 && func != nil)
+ func[nfunc-1].frame = sym->value;
+ break;
+ case 'p':
+ if(nfunc > 0 && func != nil) {
+ f = &func[nfunc-1];
+ // args counts 32-bit words.
+ // sym->value is the arg's offset.
+ // don't know width of this arg, so assume it is 64 bits.
+ if(f->args < sym->value/4 + 2)
+ f->args = sym->value/4 + 2;
+ }
+ break;
+ case 'f':
+ if(fname == nil) {
+ if(sym->value >= nfname)
+ nfname = sym->value+1;
+ break;
+ }
+ fname[sym->value] = sym->name;
+ break;
+ }
+}
+
+// put together the path name for a z entry.
+// the f entries have been accumulated into fname already.
+static void
+makepath(byte *buf, int32 nbuf, byte *path)
+{
+ int32 n, len;
+ byte *p, *ep, *q;
+
+ if(nbuf <= 0)
+ return;
+
+ p = buf;
+ ep = buf + nbuf;
+ *p = '\0';
+ for(;;) {
+ if(path[0] == 0 && path[1] == 0)
+ break;
+ n = (path[0]<<8) | path[1];
+ path += 2;
+ if(n >= nfname)
+ break;
+ q = fname[n];
+ len = findnull(q);
+ if(p+1+len >= ep)
+ break;
+ if(p > buf && p[-1] != '/')
+ *p++ = '/';
+ mcpy(p, q, len+1);
+ p += len;
+ }
+}
+
+// walk symtab accumulating path names for use by pc/ln table.
+// don't need the full generality of the z entry history stack because
+// there are no includes in go (and only sensible includes in our c).
+static void
+dosrcline(Sym *sym)
+{
+ static byte srcbuf[1000];
+ static String srcstring;
+ static int32 lno, incstart;
+ static int32 nf, nhist;
+ Func *f;
+
+ switch(sym->symtype) {
+ case 't':
+ case 'T':
+ if(strcmp(sym->name, (byte*)"etext") == 0)
+ break;
+ f = &func[nf++];
+ f->src = srcstring;
+ f->ln0 += lno;
+ break;
+ case 'z':
+ if(sym->value == 1) {
+ // entry for main source file for a new object.
+ makepath(srcbuf, sizeof srcbuf, sym->name+1);
+ srcstring = gostring(srcbuf);
+ lno = 0;
+ nhist = 0;
+ } else {
+ // push or pop of included file.
+ makepath(srcbuf, sizeof srcbuf, sym->name+1);
+ if(srcbuf[0] != '\0') {
+ if(nhist++ == 0)
+ incstart = sym->value;
+ }else{
+ if(--nhist == 0)
+ lno -= sym->value - incstart;
+ }
+ }
+ }
+}
+
+enum { PcQuant = 1 };
+
+// Interpret pc/ln table, saving the subpiece for each func.
+static void
+splitpcln(void)
+{
+ int32 line;
+ uintptr pc;
+ byte *p, *ep;
+ Func *f, *ef;
+ int32 *v;
+
+ // pc/ln table bounds
+ v = SYMCOUNTS;
+ p = SYMDATA;
+ p += v[0];
+ ep = p+v[1];
+
+ f = func;
+ ef = func + nfunc;
+ pc = func[0].entry; // text base
+ f->pcln.array = p;
+ f->pc0 = pc - PcQuant;
+ line = 0;
+ for(; p < ep; p++) {
+ if(f < ef && pc >= (f+1)->entry) {
+ f->pcln.nel = p - f->pcln.array;
+ f->pcln.cap = f->pcln.nel;
+ f++;
+ f->pcln.array = p;
+ f->pc0 = pc;
+ f->ln0 = line;
+ }
+ if(*p == 0) {
+ // 4 byte add to line
+ line += (p[1]<<24) | (p[2]<<16) | (p[3]<<8) | p[4];
+ p += 4;
+ } else if(*p <= 64) {
+ line += *p;
+ } else if(*p <= 128) {
+ line -= *p - 64;
+ } else {
+ pc += PcQuant*(*p - 129);
+ }
+ pc += PcQuant;
+ }
+ if(f < ef) {
+ f->pcln.nel = p - f->pcln.array;
+ f->pcln.cap = f->pcln.nel;
+ }
+}
+
+
+// Return actual file line number for targetpc in func f.
+// (Source file is f->src.)
+int32
+funcline(Func *f, uint64 targetpc)
+{
+ byte *p, *ep;
+ uintptr pc;
+ int32 line;
+
+ p = f->pcln.array;
+ ep = p + f->pcln.nel;
+ pc = f->pc0;
+ line = f->ln0;
+ for(; p < ep; p++) {
+ if(pc >= targetpc)
+ return line;
+ if(*p == 0) {
+ line += (p[1]<<24) | (p[2]<<16) | (p[3]<<8) | p[4];
+ p += 4;
+ } else if(*p <= 64) {
+ line += *p;
+ } else if(*p <= 128) {
+ line -= *p - 64;
+ } else {
+ pc += PcQuant*(*p - 129);
+ }
+ pc += PcQuant;
+ }
+ return line;
+}
+
+static void
+buildfuncs(void)
+{
+ extern byte etext[];
+
+ if(func != nil)
+ return;
+ // count funcs, fnames
+ nfunc = 0;
+ nfname = 0;
+ walksymtab(dofunc);
+
+ // initialize tables
+ func = mal((nfunc+1)*sizeof func[0]);
+ func[nfunc].entry = (uint64)etext;
+ fname = mal(nfname*sizeof fname[0]);
+ nfunc = 0;
+ walksymtab(dofunc);
+
+ // split pc/ln table by func
+ splitpcln();
+
+ // record src file and line info for each func
+ walksymtab(dosrcline);
+}
+
+Func*
+findfunc(uintptr addr)
+{
+ Func *f;
+ int32 nf, n;
+
+ if(func == nil)
+ buildfuncs();
+ if(nfunc == 0)
+ return nil;
+ if(addr < func[0].entry || addr >= func[nfunc].entry)
+ return nil;
+
+ // binary search to find func with entry <= addr.
+ f = func;
+ nf = nfunc;
+ while(nf > 0) {
+ n = nf/2;
+ if(f[n].entry <= addr && addr < f[n+1].entry)
+ return &f[n];
+ else if(addr < f[n].entry)
+ nf = n;
+ else {
+ f += n+1;
+ nf -= n+1;
+ }
+ }
+
+ // can't get here -- we already checked above
+ // that the address was in the table bounds.
+ // this can only happen if the table isn't sorted
+ // by address or if the binary search above is buggy.
+ prints("findfunc unreachable\n");
+ return nil;
+}
diff -r 6aabab677469 -r 31d3a7baefdd src/runtime/386/asm.s
--- a/src/runtime/386/asm.s Sat Jun 06 21:56:04 2009 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,217 +0,0 @@
-// Copyright 2009 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.
-
-TEXT _rt0_386(SB),7,$0
- // copy arguments forward on an even stack
- MOVL 0(SP), AX // argc
- LEAL 4(SP), BX // argv
- SUBL $128, SP // plenty of scratch
- ANDL $~7, SP
- MOVL AX, 120(SP) // save argc, argv away
- MOVL BX, 124(SP)
-
-/*
- // write "go386\n"
- PUSHL $6
- PUSHL $hello(SB)
- PUSHL $1
- CALL sys·write(SB)
- POPL AX
- POPL AX
- POPL AX
-*/
-
- CALL ldt0setup(SB)
-
- // set up %fs to refer to that ldt entry
- MOVL $(7*8+7), AX
- MOVW AX, FS
-
- // store through it, to make sure it works
- MOVL $0x123, 0(FS)
- MOVL tls0(SB), AX
- CMPL AX, $0x123
- JEQ ok
- MOVL AX, 0
-ok:
-
- // set up m and g "registers"
- // g is 0(FS), m is 4(FS)
- LEAL g0(SB), CX
- MOVL CX, 0(FS)
- LEAL m0(SB), AX
- MOVL AX, 4(FS)
-
- // save m->g0 = g0
- MOVL CX, 0(AX)
-
- // create istack out of the OS stack
- LEAL (-8192+104)(SP), AX // TODO: 104?
- MOVL AX, 0(CX) // 8(g) is stack limit (w 104b guard)
- MOVL SP, 4(CX) // 12(g) is base
- CALL emptyfunc(SB) // fault if stack check is wrong
-
- // convention is D is always cleared
- CLD
-
- CALL check(SB)
-
- // saved argc, argv
- MOVL 120(SP), AX
- MOVL AX, 0(SP)
- MOVL 124(SP), AX
- MOVL AX, 4(SP)
- CALL args(SB)
- CALL osinit(SB)
- CALL schedinit(SB)
-
- // create a new goroutine to start program
- PUSHL $mainstart(SB) // entry
- PUSHL $8 // arg size
- CALL sys·newproc(SB)
- POPL AX
- POPL AX
-
- // start this M
- CALL mstart(SB)
-
- INT $3
- RET
-
-TEXT mainstart(SB),7,$0
- CALL main·init(SB)
- CALL initdone(SB)
- CALL main·main(SB)
- PUSHL $0
- CALL exit(SB)
- POPL AX
- INT $3
- RET
-
-TEXT breakpoint(SB),7,$0
- BYTE $0xcc
- RET
-
-// go-routine
-TEXT gogo(SB), 7, $0
- MOVL 4(SP), AX // gobuf
- MOVL 0(AX), SP // restore SP
- MOVL 4(AX), AX
- MOVL AX, 0(SP) // put PC on the stack
- MOVL $1, AX
- RET
-
-TEXT gosave(SB), 7, $0
- MOVL 4(SP), AX // gobuf
- MOVL SP, 0(AX) // save SP
- MOVL 0(SP), BX
- MOVL BX, 4(AX) // save PC
- MOVL $0, AX // return 0
- RET
-
-// support for morestack
-
-// return point when leaving new stack.
-// save AX, jmp to lesstack to switch back
-TEXT retfromnewstack(SB),7,$0
- MOVL 4(FS), BX // m
- MOVL AX, 12(BX) // save AX in m->cret
- JMP lessstack(SB)
-
-// gogo, returning 2nd arg instead of 1
-TEXT gogoret(SB), 7, $0
- MOVL 8(SP), AX // return 2nd arg
- MOVL 4(SP), BX // gobuf
- MOVL 0(BX), SP // restore SP
- MOVL 4(BX), BX
- MOVL BX, 0(SP) // put PC on the stack
- RET
-
-TEXT setspgoto(SB), 7, $0
- MOVL 4(SP), AX // SP
- MOVL 8(SP), BX // fn to call
- MOVL 12(SP), CX // fn to return
- MOVL AX, SP
- PUSHL CX
- JMP BX
- POPL AX // not reached
- RET
-
-// bool cas(int32 *val, int32 old, int32 new)
-// Atomically:
-// if(*val == old){
-// *val = new;
-// return 1;
-// }else
-// return 0;
-TEXT cas(SB), 7, $0
- MOVL 4(SP), BX
- MOVL 8(SP), AX
- MOVL 12(SP), CX
- LOCK
- CMPXCHGL CX, 0(BX)
- JZ 3(PC)
- MOVL $0, AX
- RET
- MOVL $1, AX
- RET
-
-// void jmpdefer(fn, sp);
-// called from deferreturn.
-// 1. pop the caller
-// 2. sub 5 bytes from the callers return
-// 3. jmp to the argument
-TEXT jmpdefer(SB), 7, $0
- MOVL 4(SP), AX // fn
- MOVL 8(SP), BX // caller sp
- LEAL -4(BX), SP // caller sp after CALL
- SUBL $5, (SP) // return to CALL again
- JMP AX // but first run the deferred function
-
-TEXT sys·memclr(SB),7,$0
- MOVL 4(SP), DI // arg 1 addr
- MOVL 8(SP), CX // arg 2 count
- ADDL $3, CX
- SHRL $2, CX
- MOVL $0, AX
- CLD
- REP
- STOSL
- RET
-
-TEXT sys·getcallerpc+0(SB),7,$0
- MOVL x+0(FP),AX // addr of first arg
- MOVL -4(AX),AX // get calling pc
- RET
-
-TEXT sys·setcallerpc+0(SB),7,$0
- MOVL x+0(FP),AX // addr of first arg
- MOVL x+4(FP), BX
- MOVL BX, -4(AX) // set calling pc
- RET
-
-TEXT ldt0setup(SB),7,$16
- // set up ldt 7 to point at tls0
- // ldt 1 would be fine on Linux, but on OS X, 7 is as low as we can go.
- MOVL $7, 0(SP)
- LEAL tls0(SB), AX
- MOVL AX, 4(SP)
- MOVL $32, 8(SP) // sizeof(tls array)
- CALL setldt(SB)
- RET
-
-GLOBL m0+0(SB), $1024
-GLOBL g0+0(SB), $1024
-
-GLOBL tls0+0(SB), $32
-
-TEXT emptyfunc(SB),0,$0
- RET
-
-TEXT abort(SB),7,$0
- INT $0x3
-
-DATA hello+0(SB)/8, $"go386\n\z\z"
-GLOBL hello+0(SB), $8
-
diff -r 6aabab677469 -r 31d3a7baefdd src/runtime/386/closure.c
--- a/src/runtime/386/closure.c Sat Jun 06 21:56:04 2009 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,104 +0,0 @@
-// Copyright 2009 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.
-
-#include "runtime.h"
-
-#pragma textflag 7
-// func closure(siz int32,
-// fn func(arg0, arg1, arg2 *ptr, callerpc uintptr, xxx) yyy,
-// arg0, arg1, arg2 *ptr) (func(xxx) yyy)
-void
-sys·closure(int32 siz, byte *fn, byte *arg0)
-{
- byte *p, *q, **ret;
- int32 i, n;
- int32 pcrel;
-
- if(siz < 0 || siz%4 != 0)
- throw("bad closure size");
-
- ret = (byte**)((byte*)&arg0 + siz);
-
- if(siz > 100) {
- // TODO(rsc): implement stack growth preamble?
- throw("closure too big");
- }
-
- // compute size of new fn.
- // must match code laid out below.
- n = 6+5+2+1; // SUBL MOVL MOVL CLD
- if(siz <= 4*4)
- n += 1*siz/4; // MOVSL MOVSL...
- else
- n += 6+2; // MOVL REP MOVSL
- n += 5; // CALL
- n += 6+1; // ADDL RET
-
- // store args aligned after code, so gc can find them.
- n += siz;
- if(n%4)
- n += 4 - n%4;
-
- p = mal(n);
- *ret = p;
- q = p + n - siz;
- mcpy(q, (byte*)&arg0, siz);
-
- // SUBL $siz, SP
- *p++ = 0x81;
- *p++ = 0xec;
- *(uint32*)p = siz;
- p += 4;
-
- // MOVL $q, SI
- *p++ = 0xbe;
- *(byte**)p = q;
- p += 4;
-
- // MOVL SP, DI
- *p++ = 0x89;
- *p++ = 0xe7;
-
- // CLD
- *p++ = 0xfc;
-
- if(siz <= 4*4) {
- for(i=0; i<siz; i+=4) {
- // MOVSL
- *p++ = 0xa5;
- }
- } else {
- // MOVL $(siz/4), CX [32-bit immediate siz/4]
- *p++ = 0xc7;
- *p++ = 0xc1;
- *(uint32*)p = siz/4;
- p += 4;
-
- // REP; MOVSL
- *p++ = 0xf3;
- *p++ = 0xa5;
- }
-
- // call fn
- pcrel = fn - (p+5);
- // direct call with pc-relative offset
- // CALL fn
- *p++ = 0xe8;
- *(int32*)p = pcrel;
- p += 4;
-
- // ADDL $siz, SP
- *p++ = 0x81;
- *p++ = 0xc4;
- *(uint32*)p = siz;
- p += 4;
-
- // RET
- *p++ = 0xc3;
-
- if(p > q)
- throw("bad math in sys.closure");
-}
-
-
diff -r 6aabab677469 -r 31d3a7baefdd src/runtime/386/traceback.c
--- a/src/runtime/386/traceback.c Sat Jun 06 21:56:04 2009 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,148 +0,0 @@
-// Copyright 2009 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.
-
-#include "runtime.h"
-
-// TODO(rsc): Move this into portable code, with calls to a
-// machine-dependent isclosure() function.
-
-void
-traceback(byte *pc0, byte *sp, G *g)
-{
- Stktop *stk;
- uintptr pc;
- int32 i, n;
- Func *f;
- byte *p;
-
- pc = (uintptr)pc0;
-
- // If the PC is zero, it's likely a nil function call.
- // Start in the caller's frame.
- if(pc == 0) {
- pc = *(uintptr*)sp;
- sp += sizeof(uintptr);
- }
-
- stk = (Stktop*)g->stackbase;
- for(n=0; n<100; n++) {
- while(pc == (uintptr)retfromnewstack) {
- // pop to earlier stack block
- sp = stk->oldsp;
- stk = (Stktop*)stk->oldbase;
- pc = *(uintptr*)(sp+sizeof(uintptr));
- sp += 2*sizeof(uintptr); // two irrelevant calls on stack: morestack plus its call
- }
- f = findfunc(pc);
- if(f == nil) {
- // dangerous, but poke around to see if it is a closure
- p = (byte*)pc;
- // ADDL $xxx, SP; RET
- if(p[0] == 0x81 && p[1] == 0xc4 && p[6] == 0xc3) {
- sp += *(uint32*)(p+2) + 8;
- pc = *(uintptr*)(sp - 8);
- if(pc <= 0x1000)
- return;
- continue;
- }
- printf("%p unknown pc\n", pc);
- return;
- }
- if(f->frame < sizeof(uintptr)) // assembly funcs say 0 but lie
- sp += sizeof(uintptr);
- else
- sp += f->frame;
-
- // print this frame
- // main+0xf /home/rsc/go/src/runtime/x.go:23
- // main(0x1, 0x2, 0x3)
- printf("%S", f->name);
- if(pc > f->entry)
- printf("+%p", (uintptr)(pc - f->entry));
- printf(" %S:%d\n", f->src, funcline(f, pc-1)); // -1 to get to CALL instr.
- printf("\t%S(", f->name);
- for(i = 0; i < f->args; i++) {
- if(i != 0)
- prints(", ");
- sys·printhex(((uint32*)sp)[i]);
- if(i >= 4) {
- prints(", ...");
- break;
- }
- }
- prints(")\n");
-
- pc = *(uintptr*)(sp-sizeof(uintptr));
- if(pc <= 0x1000)
- return;
- }
- prints("...\n");
-}
-
-// func caller(n int) (pc uintptr, file string, line int, ok bool)
-void
-runtime·Caller(int32 n, uintptr retpc, String retfile, int32 retline, bool retbool)
-{
- uintptr pc;
- byte *sp;
- byte *p;
- Stktop *stk;
- Func *f;
-
- // our caller's pc, sp.
- sp = (byte*)&n;
- pc = *((uintptr*)sp - 1);
- if((f = findfunc(pc)) == nil) {
- error:
- retpc = 0;
- retline = 0;
- retfile = emptystring;
- retbool = false;
- FLUSH(&retpc);
- FLUSH(&retfile);
- FLUSH(&retline);
- FLUSH(&retbool);
- return;
- }
-
- // now unwind n levels
- stk = (Stktop*)g->stackbase;
- while(n-- > 0) {
- while(pc == (uintptr)retfromnewstack) {
- sp = stk->oldsp;
- stk = (Stktop*)stk->oldbase;
- pc = *((uintptr*)sp + 1);
- sp += 2*sizeof(uintptr);
- }
-
- if(f->frame < sizeof(uintptr)) // assembly functions lie
- sp += sizeof(uintptr);
- else
- sp += f->frame;
-
- loop:
- pc = *((uintptr*)sp - 1);
- if(pc <= 0x1000 || (f = findfunc(pc)) == nil) {
- // dangerous, but let's try this.
- // see if it is a closure.
- p = (byte*)pc;
- // ADDL $xxx, SP; RET
- if(p[0] == 0x81 && p[1] == 0xc4 && p[6] == 0xc3) {
- sp += *(uint32*)(p+2) + sizeof(uintptr);
- goto loop;
- }
- goto error;
- }
- }
-
- retpc = pc;
- retfile = f->src;
- retline = funcline(f, pc-1);
- retbool = true;
- FLUSH(&retpc);
- FLUSH(&retfile);
- FLUSH(&retline);
- FLUSH(&retbool);
-}
-
diff -r 6aabab677469 -r 31d3a7baefdd src/runtime/386/vlop.s
--- a/src/runtime/386/vlop.s Sat Jun 06 21:56:04 2009 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-// Inferno's libkern/vlop-386.s
-// http://code.google.com/p/inferno-os/source/browse/libkern/vlop-386.s
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
-// Portions Copyright 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-/*
- * C runtime for 64-bit divide.
- */
-
-TEXT _mul64by32(SB), 7, $0
- MOVL r+0(FP), CX
- MOVL a+4(FP), AX
- MULL b+12(FP)
- MOVL AX, 0(CX)
- MOVL DX, BX
- MOVL a+8(FP), AX
- MULL b+12(FP)
- ADDL AX, BX
- MOVL BX, 4(CX)
- RET
-
-TEXT _div64by32(SB), 7, $0
- MOVL r+12(FP), CX
- MOVL a+0(FP), AX
- MOVL a+4(FP), DX
- DIVL b+8(FP)
- MOVL DX, 0(CX)
- RET
diff -r 6aabab677469 -r 31d3a7baefdd src/runtime/386/vlrt.c
--- a/src/runtime/386/vlrt.c Sat Jun 06 21:56:04 2009 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,815 +0,0 @@
-// Inferno's libkern/vlrt-386.c
-// http://code.google.com/p/inferno-os/source/browse/libkern/vlrt-386.c
-//
-// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-// Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
-// Portions Copyright 2009 The Go Authors. All rights reserved.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-
-/*
- * C runtime for 64-bit divide, others.
- *
- * TODO(rsc): The simple functions are dregs--8c knows how
- * to generate the code directly now. Find and remove.
- */
-
-typedef unsigned long ulong;
-typedef unsigned int uint;
-typedef unsigned short ushort;
-typedef unsigned char uchar;
-typedef signed char schar;
-
-#define SIGN(n) (1UL<<(n-1))
-
-typedef struct Vlong Vlong;
-struct Vlong
-{
- union
- {
- long long v;
- struct
- {
- ulong lo;
- ulong hi;
- };
- struct
- {
- ushort lols;
- ushort loms;
- ushort hils;
- ushort hims;
- };
- };
-};
-
-void abort(void);
-
-void
-_d2v(Vlong *y, double d)
-{
- union { double d; struct Vlong; } x;
- ulong xhi, xlo, ylo, yhi;
- int sh;
-
- x.d = d;
-
- xhi = (x.hi & 0xfffff) | 0x100000;
- xlo = x.lo;
- sh = 1075 - ((x.hi >> 20) & 0x7ff);
-
- ylo = 0;
- yhi = 0;
- if(sh >= 0) {
- /* v = (hi||lo) >> sh */
- if(sh < 32) {
- if(sh == 0) {
- ylo = xlo;
- yhi = xhi;
- } else {
- ylo = (xlo >> sh) | (xhi << (32-sh));
- yhi = xhi >> sh;
- }
- } else {
- if(sh == 32) {
- ylo = xhi;
- } else
- if(sh < 64) {
- ylo = xhi >> (sh-32);
- }
- }
- } else {
- /* v = (hi||lo) << -sh */
- sh = -sh;
- if(sh <= 10) {
- ylo = xlo << sh;
- yhi = (xhi << sh) | (xlo >> (32-sh));
- } else {
- /* overflow */
- yhi = d; /* causes something awful */
- }
- }
- if(x.hi & SIGN(32)) {
- if(ylo != 0) {
- ylo = -ylo;
- yhi = ~yhi;
- } else
- yhi = -yhi;
- }
-
- y->hi = yhi;
- y->lo = ylo;
-}
-
-void
-_f2v(Vlong *y, float f)
-{
-
- _d2v(y, f);
-}
-
-double
-_v2d(Vlong x)
-{
- if(x.hi & SIGN(32)) {
- if(x.lo) {
- x.lo = -x.lo;
- x.hi = ~x.hi;
- } else
- x.hi = -x.hi;
- return -((long)x.hi*4294967296. + x.lo);
- }
- return (long)x.hi*4294967296. + x.lo;
-}
-
-float
-_v2f(Vlong x)
-{
- return _v2d(x);
-}
-
-ulong _div64by32(Vlong, ulong, ulong*);
-void _mul64by32(Vlong*, Vlong, ulong);
-
-static void
-slowdodiv(Vlong num, Vlong den, Vlong *q, Vlong *r)
-{
- ulong numlo, numhi, denhi, denlo, quohi, quolo, t;
- int i;
-
- numhi = num.hi;
- numlo = num.lo;
- denhi = den.hi;
- denlo = den.lo;
-
- /*
- * get a divide by zero
- */
- if(denlo==0 && denhi==0) {
- numlo = numlo / denlo;
- }
-
- /*
- * set up the divisor and find the number of iterations needed
- */
- if(numhi >= SIGN(32)) {
- quohi = SIGN(32);
- quolo = 0;
- } else {
- quohi = numhi;
- quolo = numlo;
- }
- i = 0;
- while(denhi < quohi || (denhi == quohi && denlo < quolo)) {
- denhi = (denhi<<1) | (denlo>>31);
- denlo <<= 1;
- i++;
- }
-
- quohi = 0;
- quolo = 0;
- for(; i >= 0; i--) {
- quohi = (quohi<<1) | (quolo>>31);
- quolo <<= 1;
- if(numhi > denhi || (numhi == denhi && numlo >= denlo)) {
- t = numlo;
- numlo -= denlo;
- if(numlo > t)
- numhi--;
- numhi -= denhi;
- quolo |= 1;
- }
- denlo = (denlo>>1) | (denhi<<31);
- denhi >>= 1;
- }
-
- if(q) {
- q->lo = quolo;
- q->hi = quohi;
- }
- if(r) {
- r->lo = numlo;
- r->hi = numhi;
- }
-}
-
-static void
-dodiv(Vlong num, Vlong den, Vlong *qp, Vlong *rp)
-{
- ulong n;
- Vlong x, q, r;
-
- if(den.hi > num.hi || (den.hi == num.hi && den.lo > num.lo)){
- if(qp) {
- qp->hi = 0;
- qp->lo = 0;
- }
- if(rp) {
- rp->hi = num.hi;
- rp->lo = num.lo;
- }
- return;
- }
-
- if(den.hi != 0){
- q.hi = 0;
- n = num.hi/den.hi;
- _mul64by32(&x, den, n);
- if(x.hi > num.hi || (x.hi == num.hi && x.lo > num.lo))
- slowdodiv(num, den, &q, &r);
- else {
- q.lo = n;
- r.v = num.v - x.v;
- }
- } else {
- if(num.hi >= den.lo){
- q.hi = n = num.hi/den.lo;
- num.hi -= den.lo*n;
- } else {
- q.hi = 0;
- }
- q.lo = _div64by32(num, den.lo, &r.lo);
- r.hi = 0;
- }
- if(qp) {
- qp->lo = q.lo;
- qp->hi = q.hi;
- }
- if(rp) {
- rp->lo = r.lo;
- rp->hi = r.hi;
- }
-}
-
-void
-_divvu(Vlong *q, Vlong n, Vlong d)
-{
-
- if(n.hi == 0 && d.hi == 0) {
- q->hi = 0;
- q->lo = n.lo / d.lo;
- return;
- }
- dodiv(n, d, q, 0);
-}
-
-void
-sys·uint64div(Vlong n, Vlong d, Vlong q)
-{
- _divvu(&q, n, d);
-}
-
-void
-_modvu(Vlong *r, Vlong n, Vlong d)
-{
-
- if(n.hi == 0 && d.hi == 0) {
- r->hi = 0;
- r->lo = n.lo % d.lo;
- return;
- }
- dodiv(n, d, 0, r);
-}
-
-void
-sys·uint64mod(Vlong n, Vlong d, Vlong q)
-{
- _modvu(&q, n, d);
-}
-
-static void
-vneg(Vlong *v)
-{
-
- if(v->lo == 0) {
- v->hi = -v->hi;
- return;
- }
- v->lo = -v->lo;
- v->hi = ~v->hi;
-}
-
-void
-_divv(Vlong *q, Vlong n, Vlong d)
-{
- long nneg, dneg;
-
- if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
- if((long)n.lo == -0x80000000 && (long)d.lo == -1) {
- // special case: 32-bit -0x80000000 / -1 causes divide error,
- // but it's okay in this 64-bit context.
- q->lo = 0x80000000;
- q->hi = 0;
- return;
- }
- q->lo = (long)n.lo / (long)d.lo;
- q->hi = ((long)q->lo) >> 31;
- return;
- }
- nneg = n.hi >> 31;
- if(nneg)
- vneg(&n);
- dneg = d.hi >> 31;
- if(dneg)
- vneg(&d);
- dodiv(n, d, q, 0);
- if(nneg != dneg)
- vneg(q);
-}
-
-void
-sys·int64div(Vlong n, Vlong d, Vlong q)
-{
- _divv(&q, n, d);
-}
-
-void
-_modv(Vlong *r, Vlong n, Vlong d)
-{
- long nneg, dneg;
-
- if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
- if((long)n.lo == -0x80000000 && (long)d.lo == -1) {
- // special case: 32-bit -0x80000000 % -1 causes divide error,
- // but it's okay in this 64-bit context.
- r->lo = 0;
- r->hi = 0;
- return;
- }
- r->lo = (long)n.lo % (long)d.lo;
- r->hi = ((long)r->lo) >> 31;
- return;
- }
- nneg = n.hi >> 31;
- if(nneg)
- vneg(&n);
- dneg = d.hi >> 31;
- if(dneg)
- vneg(&d);
- dodiv(n, d, 0, r);
- if(nneg)
- vneg(r);
-}
-
-void
-sys·int64mod(Vlong n, Vlong d, Vlong q)
-{
- _modv(&q, n, d);
-}
-
-void
-_rshav(Vlong *r, Vlong a, int b)
-{
- long t;
-
- t = a.hi;
- if(b >= 32) {
- r->hi = t>>31;
- if(b >= 64) {
- /* this is illegal re C standard */
- r->lo = t>>31;
- return;
- }
- r->lo = t >> (b-32);
- return;
- }
- if(b <= 0) {
- r->hi = t;
- r->lo = a.lo;
- return;
- }
- r->hi = t >> b;
- r->lo = (t << (32-b)) | (a.lo >> b);
-}
-
-void
-_rshlv(Vlong *r, Vlong a, int b)
-{
- ulong t;
-
- t = a.hi;
- if(b >= 32) {
- r->hi = 0;
- if(b >= 64) {
- /* this is illegal re C standard */
- r->lo = 0;
- return;
- }
- r->lo = t >> (b-32);
- return;
- }
- if(b <= 0) {
- r->hi = t;
- r->lo = a.lo;
- return;
- }
- r->hi = t >> b;
- r->lo = (t << (32-b)) | (a.lo >> b);
-}
-
-void
-_lshv(Vlong *r, Vlong a, int b)
-{
- ulong t;
-
- t = a.lo;
- if(b >= 32) {
- r->lo = 0;
- if(b >= 64) {
- /* this is illegal re C standard */
- r->hi = 0;
- return;
- }
- r->hi = t << (b-32);
- return;
- }
- if(b <= 0) {
- r->lo = t;
- r->hi = a.hi;
- return;
- }
- r->lo = t << b;
- r->hi = (t >> (32-b)) | (a.hi << b);
-}
-
-void
-_andv(Vlong *r, Vlong a, Vlong b)
-{
- r->hi = a.hi & b.hi;
- r->lo = a.lo & b.lo;
-}
-
-void
-_orv(Vlong *r, Vlong a, Vlong b)
-{
- r->hi = a.hi | b.hi;
- r->lo = a.lo | b.lo;
-}
-
-void
-_xorv(Vlong *r, Vlong a, Vlong b)
-{
- r->hi = a.hi ^ b.hi;
- r->lo = a.lo ^ b.lo;
-}
-
-void
-_vpp(Vlong *l, Vlong *r)
-{
-
- l->hi = r->hi;
- l->lo = r->lo;
- r->lo++;
- if(r->lo == 0)
- r->hi++;
-}
-
-void
-_vmm(Vlong *l, Vlong *r)
-{
-
- l->hi = r->hi;
- l->lo = r->lo;
- if(r->lo == 0)
- r->hi--;
- r->lo--;
-}
-
-void
-_ppv(Vlong *l, Vlong *r)
-{
-
- r->lo++;
- if(r->lo == 0)
- r->hi++;
- l->hi = r->hi;
- l->lo = r->lo;
-}
-
-void
-_mmv(Vlong *l, Vlong *r)
-{
-
- if(r->lo == 0)
- r->hi--;
- r->lo--;
- l->hi = r->hi;
- l->lo = r->lo;
-}
-
-void
-_vasop(Vlong *ret, void *lv, void fn(Vlong*, Vlong, Vlong), int type, Vlong rv)
-{
- Vlong t, u;
-
- u.lo = 0;
- u.hi = 0;
- switch(type) {
- default:
- abort();
- break;
-
- case 1: /* schar */
- t.lo = *(schar*)lv;
- t.hi = t.lo >> 31;
- fn(&u, t, rv);
- *(schar*)lv = u.lo;
- break;
-
- case 2: /* uchar */
- t.lo = *(uchar*)lv;
- t.hi = 0;
- fn(&u, t, rv);
- *(uchar*)lv = u.lo;
- break;
-
- case 3: /* short */
- t.lo = *(short*)lv;
- t.hi = t.lo >> 31;
- fn(&u, t, rv);
- *(short*)lv = u.lo;
- break;
-
- case 4: /* ushort */
- t.lo = *(ushort*)lv;
- t.hi = 0;
- fn(&u, t, rv);
- *(ushort*)lv = u.lo;
- break;
-
- case 9: /* int */
- t.lo = *(int*)lv;
- t.hi = t.lo >> 31;
- fn(&u, t, rv);
- *(int*)lv = u.lo;
- break;
-
- case 10: /* uint */
- t.lo = *(uint*)lv;
- t.hi = 0;
- fn(&u, t, rv);
- *(uint*)lv = u.lo;
- break;
-
- case 5: /* long */
- t.lo = *(long*)lv;
- t.hi = t.lo >> 31;
- fn(&u, t, rv);
- *(long*)lv = u.lo;
- break;
-
- case 6: /* ulong */
- t.lo = *(ulong*)lv;
- t.hi = 0;
- fn(&u, t, rv);
- *(ulong*)lv = u.lo;
- break;
-
- case 7: /* vlong */
- case 8: /* uvlong */
- fn(&u, *(Vlong*)lv, rv);
- *(Vlong*)lv = u;
- break;
- }
- *ret = u;
-}
-
-void
-_p2v(Vlong *ret, void *p)
-{
- long t;
-
- t = (ulong)p;
- ret->lo = t;
- ret->hi = 0;
-}
-
-void
-_sl2v(Vlong *ret, long sl)
-{
- long t;
-
- t = sl;
- ret->lo = t;
- ret->hi = t >> 31;
-}
-
-void
-_ul2v(Vlong *ret, ulong ul)
-{
- long t;
-
- t = ul;
- ret->lo = t;
- ret->hi = 0;
-}
-
-void
-_si2v(Vlong *ret, int si)
-{
- long t;
-
- t = si;
- ret->lo = t;
- ret->hi = t >> 31;
-}
-
-void
-_ui2v(Vlong *ret, uint ui)
-{
- long t;
-
- t = ui;
- ret->lo = t;
- ret->hi = 0;
-}
-
-void
-_sh2v(Vlong *ret, long sh)
-{
- long t;
-
- t = (sh << 16) >> 16;
- ret->lo = t;
- ret->hi = t >> 31;
-}
-
-void
-_uh2v(Vlong *ret, ulong ul)
-{
- long t;
-
- t = ul & 0xffff;
- ret->lo = t;
- ret->hi = 0;
-}
-
-void
-_sc2v(Vlong *ret, long uc)
-{
- long t;
-
- t = (uc << 24) >> 24;
- ret->lo = t;
- ret->hi = t >> 31;
-}
-
-void
-_uc2v(Vlong *ret, ulong ul)
-{
- long t;
-
- t = ul & 0xff;
- ret->lo = t;
- ret->hi = 0;
-}
-
-long
-_v2sc(Vlong rv)
-{
- long t;
-
- t = rv.lo & 0xff;
- return (t << 24) >> 24;
-}
-
-long
-_v2uc(Vlong rv)
-{
-
- return rv.lo & 0xff;
-}
-
-long
-_v2sh(Vlong rv)
-{
- long t;
-
- t = rv.lo & 0xffff;
- return (t << 16) >> 16;
-}
-
-long
-_v2uh(Vlong rv)
-{
-
- return rv.lo & 0xffff;
-}
-
-long
-_v2sl(Vlong rv)
-{
-
- return rv.lo;
-}
-
-long
-_v2ul(Vlong rv)
-{
-
- return rv.lo;
-}
-
-long
-_v2si(Vlong rv)
-{
-
- return rv.lo;
-}
-
-long
-_v2ui(Vlong rv)
-{
-
- return rv.lo;
-}
-
-int
-_testv(Vlong rv)
-{
- return rv.lo || rv.hi;
-}
-
-int
-_eqv(Vlong lv, Vlong rv)
-{
- return lv.lo == rv.lo && lv.hi == rv.hi;
-}
-
-int
-_nev(Vlong lv, Vlong rv)
-{
- return lv.lo != rv.lo || lv.hi != rv.hi;
-}
-
-int
-_ltv(Vlong lv, Vlong rv)
-{
- return (long)lv.hi < (long)rv.hi ||
- (lv.hi == rv.hi && lv.lo < rv.lo);
-}
-
-int
-_lev(Vlong lv, Vlong rv)
-{
- return (long)lv.hi < (long)rv.hi ||
- (lv.hi == rv.hi && lv.lo <= rv.lo);
-}
-
-int
-_gtv(Vlong lv, Vlong rv)
-{
- return (long)lv.hi > (long)rv.hi ||
- (lv.hi == rv.hi && lv.lo > rv.lo);
-}
-
-int
-_gev(Vlong lv, Vlong rv)
-{
- return (long)lv.hi > (long)rv.hi ||
- (lv.hi == rv.hi && lv.lo >= rv.lo);
-}
-
-int
-_lov(Vlong lv, Vlong rv)
-{
- return lv.hi < rv.hi ||
- (lv.hi == rv.hi && lv.lo < rv.lo);
-}
-
-int
-_lsv(Vlong lv, Vlong rv)
-{
- return lv.hi < rv.hi ||
- (lv.hi == rv.hi && lv.lo <= rv.lo);
-}
-
-int
-_hiv(Vlong lv, Vlong rv)
-{
- return lv.hi > rv.hi ||
- (lv.hi == rv.hi && lv.lo > rv.lo);
-}
-
-int
-_hsv(Vlong lv, Vlong rv)
-{
- return lv.hi > rv.hi ||
- (lv.hi == rv.hi && lv.lo >= rv.lo);
-}
diff -r 6aabab677469 -r 31d3a7baefdd src/runtime/Makefile
--- a/src/runtime/Makefile Sat Jun 06 21:56:04 2009 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,119 +0,0 @@
-# Copyright 2009 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.
-
-# Set SIZE to 32 or 64.
-SIZE_386=32
-SIZE_amd64=64
-SIZE_arm=32
-SIZE=$(SIZE_$(GOARCH))
-
-# Setup CFLAGS. Add -D_64BIT on 64-bit platforms (sorry).
-CFLAGS_64=-D_64BIT
-CFLAGS=-I$(GOOS) -I$(GOOS)/$(GOARCH) -wF $(CFLAGS_$(SIZE))
-
-# Set O to right letter.
-O_386=8
-O_amd64=6
-O_arm=5
-O=$(O_$(GOARCH))
-
-# Tools
-CC=$(O)c
-AS=$(O)a
-AR=6ar # sic
-
-LIB=lib.a
-
-# 386-specific object files
-OFILES_386=\
- vlop.$O\
- vlrt.$O\
-
-OFILES=\
- array.$O\
- asm.$O\
- chan.$O\
- closure.$O\
- float.$O\
- float_go.$O\
- hashmap.$O\
- iface.$O\
- malloc.$O\
- malloc_go.$O\
- mcache.$O\
- mcentral.$O\
- mem.$O\
- mfixalloc.$O\
- mgc0.$O\
- mheap.$O\
- mheapmap$(SIZE).$O\
- msize.$O\
- print.$O\
- proc.$O\
- rune.$O\
- runtime.$O\
- rt0.$O\
- sema.$O\
- sema_go.$O\
- signal.$O\
- string.$O\
- symtab.$O\
- sys.$O\
- thread.$O\
- traceback.$O\
- $(OFILES_$(GOARCH))\
-
-HFILES=\
- runtime.h\
- hashmap.h\
- malloc.h\
- $(GOOS)/os.h\
- $(GOOS)/$(GOARCH)/defs.h\
-
-install: $(LIB) runtime.acid
- cp $(LIB) $(GOROOT)/lib/lib_$(GOARCH)_$(GOOS).a
- cp runtime.acid $(GOROOT)/acid/runtime.acid
-
-$(LIB): $(OFILES)
- $(AR) rc $(LIB) $(OFILES)
-
-$(OFILES): $(HFILES)
-
-nuke:
- rm -f *.[568] *.a $(GOROOT)/lib/$(LIB)
-
-clean:
- rm -f *.[568] *.a runtime.acid cgo2c
-
-%.$O: %.c
- $(CC) $(CFLAGS) $<
-
-%.$O: $(GOARCH)/%.c
- $(CC) $(CFLAGS) $<
-
-%.$O: $(GOOS)/%.c
- $(CC) $(CFLAGS) $<
-
-%.$O: $(GOOS)/$(GOARCH)/%.c
- $(CC) $(CFLAGS) $<
-
-%.$O: $(GOARCH)/%.s
- $(AS) $<
-
-%.$O: $(GOOS)/$(GOARCH)/%.s
- $(AS) $<
-
-cgo2c: cgo2c.c
- quietgcc -o $@ $<
-
-%.c: %.cgo cgo2c
- ./cgo2c $< > [email protected]
- mv -f [email protected] $@
-
-runtime.acid: runtime.h proc.c
- $(CC) -a proc.c >runtime.acid
-
-chan.acid: runtime.h chan.c
- $(CC) -a chan.c >chan.acid
-
diff -r 6aabab677469 -r 31d3a7baefdd src/runtime/amd64/asm.s
--- a/src/runtime/amd64/asm.s Sat Jun 06 21:56:04 2009 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,207 +0,0 @@
-// Copyright 2009 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.
-
-
-TEXT _rt0_amd64(SB),7,$-8
-
- // copy arguments forward on an even stack
-
- MOVQ 0(SP), AX // argc
- LEAQ 8(SP), BX // argv
- SUBQ $(4*8+7), SP // 2args 2auto
- ANDQ $~7, SP
- MOVQ AX, 16(SP)
- MOVQ BX, 24(SP)
-
- // set the per-goroutine and per-mach registers
-
- LEAQ m0(SB), R14 // dedicated m. register
- LEAQ g0(SB), R15 // dedicated g. register
- MOVQ R15, 0(R14) // m has pointer to its g0
-
- // create istack out of the given (operating system) stack
-
- LEAQ (-8192+104)(SP), AX
- MOVQ AX, 0(R15) // 0(R15) is stack limit (w 104b guard)
- MOVQ SP, 8(R15) // 8(R15) is base
-
- CLD // convention is D is always left cleared
- CALL check(SB)
-
- MOVL 16(SP), AX // copy argc
- MOVL AX, 0(SP)
- MOVQ 24(SP), AX // copy argv
- MOVQ AX, 8(SP)
- CALL args(SB)
- CALL osinit(SB)
- CALL schedinit(SB)
-
- // create a new goroutine to start program
- PUSHQ $mainstart(SB) // entry
- PUSHQ $16 // arg size
- CALL sys·newproc(SB)
- POPQ AX
- POPQ AX
-
- // start this M
- CALL mstart(SB)
-
- CALL notok(SB) // never returns
- RET
-
-TEXT mainstart(SB),7,$0
- CALL main·init(SB)
- CALL initdone(SB)
- CALL main·main(SB)
- PUSHQ $0
- CALL exit(SB)
- POPQ AX
- CALL notok(SB)
- RET
-
-TEXT breakpoint(SB),7,$0
- BYTE $0xcc
- RET
-
-/*
- * go-routine
- */
-TEXT gogo(SB), 7, $0
- MOVQ 8(SP), AX // gobuf
- MOVQ 0(AX), SP // restore SP
- MOVQ 8(AX), AX
- MOVQ AX, 0(SP) // put PC on the stack
- MOVL $1, AX // return 1
- RET
-
-TEXT gosave(SB), 7, $0
- MOVQ 8(SP), AX // gobuf
- MOVQ SP, 0(AX) // save SP
- MOVQ 0(SP), BX
- MOVQ BX, 8(AX) // save PC
- MOVL $0, AX // return 0
- RET
-
-/*
- * support for morestack
- */
-
-// morestack trampolines
-TEXT sys·morestack00+0(SB),7,$0
- MOVQ $0, AX
- MOVQ AX, 8(R14)
- MOVQ $sys·morestack+0(SB), AX
- JMP AX
-
-TEXT sys·morestack01+0(SB),7,$0
- SHLQ $32, AX
- MOVQ AX, 8(R14)
- MOVQ $sys·morestack+0(SB), AX
- JMP AX
-
-TEXT sys·morestack10+0(SB),7,$0
- MOVLQZX AX, AX
- MOVQ AX, 8(R14)
- MOVQ $sys·morestack+0(SB), AX
- JMP AX
-
-TEXT sys·morestack11+0(SB),7,$0
- MOVQ AX, 8(R14)
- MOVQ $sys·morestack+0(SB), AX
- JMP AX
-
-TEXT sys·morestackx(SB),7,$0
- POPQ AX
- SHLQ $35, AX
- MOVQ AX, 8(R14)
- MOVQ $sys·morestack(SB), AX
- JMP AX
-
-// subcases of morestack01
-// with const of 8,16,...48
-TEXT sys·morestack8(SB),7,$0
- PUSHQ $1
- MOVQ $sys·morestackx(SB), AX
- JMP AX
-
-TEXT sys·morestack16(SB),7,$0
- PUSHQ $2
- MOVQ $sys·morestackx(SB), AX
- JMP AX
-
-TEXT sys·morestack24(SB),7,$0
- PUSHQ $3
- MOVQ $sys·morestackx(SB), AX
- JMP AX
-
-TEXT sys·morestack32(SB),7,$0
- PUSHQ $4
- MOVQ $sys·morestackx(SB), AX
- JMP AX
-
-TEXT sys·morestack40(SB),7,$0
- PUSHQ $5
- MOVQ $sys·morestackx(SB), AX
- JMP AX
-
-TEXT sys·morestack48(SB),7,$0
- PUSHQ $6
- MOVQ $sys·morestackx(SB), AX
- JMP AX
-
-// return point when leaving new stack. save AX, jmp to lessstack to switch back
-TEXT retfromnewstack(SB), 7, $0
- MOVQ AX, 16(R14) // save AX in m->cret
- MOVQ $lessstack(SB), AX
- JMP AX
-
-// gogo, returning 2nd arg instead of 1
-TEXT gogoret(SB), 7, $0
- MOVQ 16(SP), AX // return 2nd arg
- MOVQ 8(SP), BX // gobuf
- MOVQ 0(BX), SP // restore SP
- MOVQ 8(BX), BX
- MOVQ BX, 0(SP) // put PC on the stack
- RET
-
-TEXT setspgoto(SB), 7, $0
- MOVQ 8(SP), AX // SP
- MOVQ 16(SP), BX // fn to call
- MOVQ 24(SP), CX // fn to return
- MOVQ AX, SP
- PUSHQ CX
- JMP BX
- POPQ AX // not reached
- RET
-
-// bool cas(int32 *val, int32 old, int32 new)
-// Atomically:
-// if(*val == old){
-// *val = new;
-// return 1;
-// } else
-// return 0;
-TEXT cas(SB), 7, $0
- MOVQ 8(SP), BX
- MOVL 16(SP), AX
- MOVL 20(SP), CX
- LOCK
- CMPXCHGL CX, 0(BX)
- JZ 3(PC)
- MOVL $0, AX
- RET
- MOVL $1, AX
- RET
-
-// void jmpdefer(fn, sp);
-// called from deferreturn.
-// 1. pop the caller
-// 2. sub 5 bytes from the callers return
-// 3. jmp to the argument
-TEXT jmpdefer(SB), 7, $0
- MOVQ 8(SP), AX // fn
- MOVQ 16(SP), BX // caller sp
- LEAQ -8(BX), SP // caller sp after CALL
- SUBQ $5, (SP) // return to CALL again
- JMP AX // but first run the deferred function
diff -r 6aabab677469 -r 31d3a7baefdd src/runtime/amd64/closure.c
--- a/src/runtime/amd64/closure.c Sat Jun 06 21:56:04 2009 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,121 +0,0 @@
-// Copyright 2009 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.
-
-#include "runtime.h"
-
-#pragma textflag 7
-// func closure(siz int32,
-// fn func(arg0, arg1, arg2 *ptr, callerpc uintptr, xxx) yyy,
-// arg0, arg1, arg2 *ptr) (func(xxx) yyy)
-void
-sys·closure(int32 siz, byte *fn, byte *arg0)
-{
- byte *p, *q, **ret;
- int32 i, n;
- int64 pcrel;
-
- if(siz < 0 || siz%8 != 0)
- throw("bad closure size");
-
- ret = (byte**)((byte*)&arg0 + siz);
-
- if(siz > 100) {
- // TODO(rsc): implement stack growth preamble?
- throw("closure too big");
- }
-
- // compute size of new fn.
- // must match code laid out below.
- n = 7+10+3; // SUBQ MOVQ MOVQ
- if(siz <= 4*8)
- n += 2*siz/8; // MOVSQ MOVSQ...
- else
- n += 7+3; // MOVQ REP MOVSQ
- n += 12; // CALL worst case; sometimes only 5
- n += 7+1; // ADDQ RET
-
- // store args aligned after code, so gc can find them.
- n += siz;
- if(n%8)
- n += 8 - n%8;
-
- p = mal(n);
- *ret = p;
- q = p + n - siz;
- mcpy(q, (byte*)&arg0, siz);
-
- // SUBQ $siz, SP
- *p++ = 0x48;
- *p++ = 0x81;
- *p++ = 0xec;
- *(uint32*)p = siz;
- p += 4;
-
- // MOVQ $q, SI
- *p++ = 0x48;
- *p++ = 0xbe;
- *(byte**)p = q;
- p += 8;
-
- // MOVQ SP, DI
- *p++ = 0x48;
- *p++ = 0x89;
- *p++ = 0xe7;
-
- if(siz <= 4*8) {
- for(i=0; i<siz; i+=8) {
- // MOVSQ
- *p++ = 0x48;
- *p++ = 0xa5;
- }
- } else {
- // MOVQ $(siz/8), CX [32-bit immediate siz/8]
- *p++ = 0x48;
- *p++ = 0xc7;
- *p++ = 0xc1;
- *(uint32*)p = siz/8;
- p += 4;
-
- // REP; MOVSQ
- *p++ = 0xf3;
- *p++ = 0x48;
- *p++ = 0xa5;
- }
-
-
- // call fn
- pcrel = fn - (p+5);
- if((int32)pcrel == pcrel) {
- // can use direct call with pc-relative offset
- // CALL fn
- *p++ = 0xe8;
- *(int32*)p = pcrel;
- p += 4;
- } else {
- // MOVQ $fn, CX [64-bit immediate fn]
- *p++ = 0x48;
- *p++ = 0xb9;
- *(byte**)p = fn;
- p += 8;
-
- // CALL *CX
- *p++ = 0xff;
- *p++ = 0xd1;
- }
-
- // ADDQ $siz, SP
- *p++ = 0x48;
- *p++ = 0x81;
- *p++ = 0xc4;
- *(uint32*)p = siz;
- p += 4;
-
- // RET
- *p++ = 0xc3;
-
- if(p > q)
- throw("bad math in sys.closure");
-}
-
-
diff -r 6aabab677469 -r 31d3a7baefdd src/runtime/amd64/traceback.c
--- a/src/runtime/amd64/traceback.c Sat Jun 06 21:56:04 2009 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,146 +0,0 @@
-// Copyright 2009 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.
-
-#include "runtime.h"
-
-void
-traceback(byte *pc0, byte *sp, G *g)
-{
- Stktop *stk;
- uint64 pc;
- int32 i, n;
- Func *f;
- byte *p;
-
- pc = (uint64)pc0;
-
- // If the PC is zero, it's likely a nil function call.
- // Start in the caller's frame.
- if(pc == 0) {
- pc = *(uint64*)sp;
- sp += 8;
- }
-
- stk = (Stktop*)g->stackbase;
- for(n=0; n<100; n++) {
- while(pc == (uint64)retfromnewstack) {
- // pop to earlier stack block
- sp = stk->oldsp;
- stk = (Stktop*)stk->oldbase;
- pc = *(uint64*)(sp+8);
- sp += 16; // two irrelevant calls on stack: morestack plus its call
- }
- f = findfunc(pc);
- if(f == nil) {
- // dangerous, but poke around to see if it is a closure
- p = (byte*)pc;
- // ADDQ $xxx, SP; RET
- if(p[0] == 0x48 && p[1] == 0x81 && p[2] == 0xc4 && p[7] == 0xc3) {
- sp += *(uint32*)(p+3) + 8;
- pc = *(uint64*)(sp - 8);
- if(pc <= 0x1000)
- return;
- continue;
- }
- printf("%p unknown pc\n", pc);
- return;
- }
- if(f->frame < 8) // assembly funcs say 0 but lie
- sp += 8;
- else
- sp += f->frame;
-
- // print this frame
- // main+0xf /home/rsc/go/src/runtime/x.go:23
- // main(0x1, 0x2, 0x3)
- printf("%S", f->name);
- if(pc > f->entry)
- printf("+%X", pc - f->entry);
- printf(" %S:%d\n", f->src, funcline(f, pc-1)); // -1 to get to CALL instr.
- printf("\t%S(", f->name);
- for(i = 0; i < f->args; i++) {
- if(i != 0)
- prints(", ");
- sys·printhex(((uint32*)sp)[i]);
- if(i >= 4) {
- prints(", ...");
- break;
- }
- }
- prints(")\n");
-
- pc = *(uint64*)(sp-8);
- if(pc <= 0x1000)
- return;
- }
- prints("...\n");
-}
-
-// func caller(n int) (pc uint64, file string, line int, ok bool)
-void
-runtime·Caller(int32 n, uint64 retpc, String retfile, int32 retline, bool retbool)
-{
- uint64 pc;
- byte *sp;
- byte *p;
- Stktop *stk;
- Func *f;
-
- // our caller's pc, sp.
- sp = (byte*)&n;
- pc = *(uint64*)(sp-8);
- if((f = findfunc(pc)) == nil) {
- error:
- retpc = 0;
- retline = 0;
- retfile = emptystring;
- retbool = false;
- FLUSH(&retpc);
- FLUSH(&retfile);
- FLUSH(&retline);
- FLUSH(&retbool);
- return;
- }
-
- // now unwind n levels
- stk = (Stktop*)g->stackbase;
- while(n-- > 0) {
- while(pc == (uint64)retfromnewstack) {
- sp = stk->oldsp;
- stk = (Stktop*)stk->oldbase;
- pc = *(uint64*)(sp+8);
- sp += 16;
- }
-
- if(f->frame < 8) // assembly functions lie
- sp += 8;
- else
- sp += f->frame;
-
- loop:
- pc = *(uint64*)(sp-8);
- if(pc <= 0x1000 || (f = findfunc(pc)) == nil) {
- // dangerous, but let's try this.
- // see if it is a closure.
- p = (byte*)pc;
- // ADDQ $xxx, SP; RET
- if(p[0] == 0x48 && p[1] == 0x81 && p[2] == 0xc4 && p[7] == 0xc3) {
- sp += *(uint32*)(p+3) + 8;
- goto loop;
- }
- goto error;
- }
- }
-
- retpc = pc;
- retfile = f->src;
- retline = funcline(f, pc-1);
- retbool = true;
- FLUSH(&retpc);
- FLUSH(&retfile);
- FLUSH(&retline);
- FLUSH(&retbool);
-}
-
-
diff -r 6aabab677469 -r 31d3a7baefdd src/runtime/arm/asm.s
--- a/src/runtime/arm/asm.s Sat Jun 06 21:56:04 2009 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,83 +0,0 @@
-// Copyright 2009 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.
-
-TEXT _rt0_arm(SB),7,$0
- // copy arguments forward on an even stack
- // MOVW $0(SP), R0
- // MOVL 0(SP), R1 // argc
-// LEAL 4(SP), R1 // argv
-// SUBL $128, SP // plenty of scratch
-// ANDL $~7, SP
-// MOVL AX, 120(SP) // save argc, argv away
-// MOVL BX, 124(SP)
-
-
-// // write "go386\n"
-// PUSHL $6
-// PUSHL $hello(SB)
-// PUSHL $1
-// CALL sys·write(SB)
-// POPL AX
-// POPL AX
-// POPL AX
-
-
-// CALL ldt0setup(SB)
-
- // set up %fs to refer to that ldt entry
-// MOVL $(7*8+7), AX
-// MOVW AX, FS
-
-// // store through it, to make sure it works
-// MOVL $0x123, 0(FS)
-// MOVL tls0(SB), AX
-// CMPL AX, $0x123
-// JEQ ok
-// MOVL AX, 0
-// ok:
-
-// // set up m and g "registers"
-// // g is 0(FS), m is 4(FS)
-// LEAL g0(SB), CX
-// MOVL CX, 0(FS)
-// LEAL m0(SB), AX
-// MOVL AX, 4(FS)
-
-// // save m->g0 = g0
-// MOVL CX, 0(AX)
-
-// // create istack out of the OS stack
-// LEAL (-8192+104)(SP), AX // TODO: 104?
-// MOVL AX, 0(CX) // 8(g) is stack limit (w 104b guard)
-// MOVL SP, 4(CX) // 12(g) is base
-// CALL emptyfunc(SB) // fault if stack check is wrong
-
-// // convention is D is always cleared
-// CLD
-
-// CALL check(SB)
-
-// // saved argc, argv
-// MOVL 120(SP), AX
-// MOVL AX, 0(SP)
-// MOVL 124(SP), AX
-// MOVL AX, 4(SP)
-// CALL args(SB)
-// CALL osinit(SB)
-// CALL schedinit(SB)
-
-// // create a new goroutine to start program
-// PUSHL $mainstart(SB) // entry
-// PUSHL $8 // arg size
-// CALL sys·newproc(SB)
-// POPL AX
-// POPL AX
-
-// // start this M
-// CALL mstart(SB)
-
- BL main�main(SB)
- MOVW $99, R0
- SWI $0x00900001
-
diff -r 6aabab677469 -r 31d3a7baefdd src/runtime/arm/closure.c
--- a/src/runtime/arm/closure.c Sat Jun 06 21:56:04 2009 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-// Copyright 2009 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.
-
diff -r 6aabab677469 -r 31d3a7baefdd src/runtime/array.c
--- a/src/runtime/array.c Sat Jun 06 21:56:04 2009 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,175 +0,0 @@
-// Copyright 2009 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.
-
-#include "runtime.h"
-
-static int32 debug = 0;
-
-// newarray(nel int, cap int, width int) (ary []any);
-void
-sys·newarray(uint32 nel, uint32 cap, uint32 width, Array ret)
-{
- uint64 size;
-
- if(cap < nel)
- cap = nel;
- size = cap*width;
-
- ret.nel = nel;
- ret.cap = cap;
- ret.array = mal(size);
-
- FLUSH(&ret);
-
- if(debug) {
- prints("newarray: nel=");
- sys·printint(nel);
- prints("; cap=");
- sys·printint(cap);
- prints("; width=");
- sys·printint(width);
- prints("; ret=");
- sys·printarray(ret);
- prints("\n");
- }
-}
-
-static void
-throwslice(uint32 lb, uint32 hb, uint32 n)
-{
- prints("slice[");
- sys·printint(lb);
- prints(":");
- sys·printint(hb);
- prints("] of [");
- sys·printint(n);
- prints("] array\n");
- throw("array slice");
-}
-
-// arraysliced(old []any, lb int, hb int, width int) (ary []any);
-void
-sys·arraysliced(Array old, uint32 lb, uint32 hb, uint32 width, Array ret)
-{
-
- if(hb > old.cap || lb > hb) {
- if(debug) {
- prints("sys·arraysliced: old=");
- sys·printarray(old);
- prints("; lb=");
- sys·printint(lb);
- prints("; hb=");
- sys·printint(hb);
- prints("; width=");
- sys·printint(width);
- prints("\n");
-
- prints("oldarray: nel=");
- sys·printint(old.nel);
- prints("; cap=");
- sys·printint(old.cap);
- prints("\n");
- }
- throwslice(lb, hb, old.cap);
- }
-
- // new array is inside old array
- ret.nel = hb-lb;
- ret.cap = old.cap - lb;
- ret.array = old.array + lb*width;
-
- FLUSH(&ret);
-
- if(debug) {
- prints("sys·arraysliced: old=");
- sys·printarray(old);
- prints("; lb=");
- sys·printint(lb);
- prints("; hb=");
- sys·printint(hb);
- prints("; width=");
- sys·printint(width);
- prints("; ret=");
- sys·printarray(ret);
- prints("\n");
- }
-}
-
-// arrayslices(old *any, nel int, lb int, hb int, width int) (ary []any);
-void
-sys·arrayslices(byte* old, uint32 nel, uint32 lb, uint32 hb, uint32 width, Array ret)
-{
-
- if(hb > nel || lb > hb) {
- if(debug) {
- prints("sys·arrayslices: old=");
- sys·printpointer(old);
- prints("; nel=");
- sys·printint(nel);
- prints("; lb=");
- sys·printint(lb);
- prints("; hb=");
- sys·printint(hb);
- prints("; width=");
- sys·printint(width);
- prints("\n");
- }
- throwslice(lb, hb, nel);
- }
-
- // new array is inside old array
- ret.nel = hb-lb;
- ret.cap = nel-lb;
- ret.array = old + lb*width;
-
- FLUSH(&ret);
-
- if(debug) {
- prints("sys·arrayslices: old=");
- sys·printpointer(old);
- prints("; nel=");
- sys·printint(nel);
- prints("; lb=");
- sys·printint(lb);
- prints("; hb=");
- sys·printint(hb);
- prints("; width=");
- sys·printint(width);
- prints("; ret=");
- sys·printarray(ret);
- prints("\n");
- }
-}
-
-// arrays2d(old *any, nel int) (ary []any)
-void
-sys·arrays2d(byte* old, uint32 nel, Array ret)
-{
-
- // new dope to old array
- ret.nel = nel;
- ret.cap = nel;
- ret.array = old;
-
- FLUSH(&ret);
-
- if(debug) {
- prints("sys·arrays2d: old=");
- sys·printpointer(old);
- prints("; ret=");
- sys·printarray(ret);
- prints("\n");
- }
-}
-
-void
-sys·printarray(Array a)
-{
- prints("[");
- sys·printint(a.nel);
- prints("/");
- sys·printint(a.cap);
- prints("]");
- sys·printpointer(a.array);
-}
diff -r 6aabab677469 -r 31d3a7baefdd src/runtime/cgo2c.c
--- a/src/runtime/cgo2c.c Sat Jun 06 21:56:04 2009 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,602 +0,0 @@
-// Copyright 2009 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.
-
-/* Translate a .cgo file into a .c file. A .cgo file is a combination
- of a limited form of Go with C. */
-
-/*
- package PACKAGENAME
- {# line}
- func NAME([NAME TYPE { , NAME TYPE }]) [(NAME TYPE { , NAME TYPE })] \{
- C code with proper brace nesting
- \}
-*/
-
-/* We generate C code which implements the function such that it can
- be called from Go and executes the C code. */
-
-#include <assert.h>
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-/* Whether we're emitting for gcc */
-static int gcc;
-
-/* File and line number */
-static const char *file;
-static unsigned int lineno;
-
-/* List of names and types. */
-struct params {
- struct params *next;
- char *name;
- char *type;
-};
-
-/* Unexpected EOF. */
-static void
-bad_eof(void)
-{
- fprintf(stderr, "%s:%u: unexpected EOF\n", file, lineno);
- exit(1);
-}
-
-/* Out of memory. */
-static void
-bad_mem(void)
-{
- fprintf(stderr, "%s:%u: out of memory\n", file, lineno);
- exit(1);
-}
-
-/* Allocate memory without fail. */
-static void *
-xmalloc(unsigned int size)
-{
- void *ret = malloc(size);
- if (ret == NULL)
- bad_mem();
- return ret;
-}
-
-/* Reallocate memory without fail. */
-static void*
-xrealloc(void *buf, unsigned int size)
-{
- void *ret = realloc(buf, size);
- if (ret == NULL)
- bad_mem();
- return ret;
-}
-
-/* Free a list of parameters. */
-static void
-free_params(struct params *p)
-{
- while (p != NULL) {
- struct params *next;
-
- next = p->next;
- free(p->name);
- free(p->type);
- free(p);
- p = next;
- }
-}
-
-/* Read a character, tracking lineno. */
-static int
-getchar_update_lineno(void)
-{
- int c;
-
- c = getchar();
- if (c == '\n')
- ++lineno;
- return c;
-}
-
-/* Read a character, giving an error on EOF, tracking lineno. */
-static int
-getchar_no_eof(void)
-{
- int c;
-
- c = getchar_update_lineno();
- if (c == EOF)
- bad_eof();
- return c;
-}
-
-/* Read a character, skipping comments. */
-static int
-getchar_skipping_comments(void)
-{
- int c;
-
- while (1) {
- c = getchar_update_lineno();
- if (c != '/')
- return c;
-
- c = getchar();
- if (c == '/') {
- do {
- c = getchar_update_lineno();
- } while (c != EOF && c != '\n');
- return c;
- } else if (c == '*') {
- while (1) {
- c = getchar_update_lineno();
- if (c == EOF)
- return EOF;
- if (c == '*') {
- do {
- c = getchar_update_lineno();
- } while (c == '*');
- if (c == '/')
- break;
- }
- }
- } else {
- ungetc(c, stdin);
- return '/';
- }
- }
-}
-
-/* Read and return a token. Tokens are delimited by whitespace or by
- [(),{}]. The latter are all returned as single characters. */
-static char *
-read_token(void)
-{
- int c;
- char *buf;
- unsigned int alc, off;
- const char* delims = "(),{}";
-
- while (1) {
- c = getchar_skipping_comments();
- if (c == EOF)
- return NULL;
- if (!isspace(c))
- break;
- }
- alc = 16;
- buf = xmalloc(alc + 1);
- off = 0;
- if (strchr(delims, c) != NULL) {
- buf[off] = c;
- ++off;
- } else {
- while (1) {
- if (off >= alc) {
- alc *= 2;
- buf = xrealloc(buf, alc + 1);
- }
- buf[off] = c;
- ++off;
- c = getchar_skipping_comments();
- if (c == EOF)
- break;
- if (isspace(c) || strchr(delims, c) != NULL) {
- ungetc(c, stdin);
- break;
- }
- }
- }
- buf[off] = '\0';
- return buf;
-}
-
-/* Read a token, giving an error on EOF. */
-static char *
-read_token_no_eof(void)
-{
- char *token = read_token();
- if (token == NULL)
- bad_eof();
- return token;
-}
-
-/* Read the package clause, and return the package name. */
-static char *
-read_package(void)
-{
- char *token;
-
- token = read_token_no_eof();
- if (strcmp(token, "package") != 0) {
- fprintf(stderr,
- "%s:%u: expected \"package\", got \"%s\"\n",
- file, lineno, token);
- exit(1);
- }
- return read_token_no_eof();
-}
-
-/* Read and copy preprocessor lines. */
-static void
-read_preprocessor_lines(void)
-{
- while (1) {
- int c;
-
- do {
- c = getchar_skipping_comments();
- } while (isspace(c));
- if (c != '#') {
- ungetc(c, stdin);
- return;
- }
- putchar(c);
- do {
- c = getchar_update_lineno();
- putchar(c);
- } while (c != '\n');
- }
-}
-
-/* Read a type in Go syntax and return a type in C syntax. We only
- permit basic types and pointers. */
-static char *
-read_type(void)
-{
- char *p, *op, *q;
- int pointer_count;
- unsigned int len;
-
- p = read_token_no_eof();
- if (*p != '*')
- return p;
- op = p;
- pointer_count = 0;
- while (*p == '*') {
- ++pointer_count;
- ++p;
- }
- len = strlen(p);
- q = xmalloc(len + pointer_count + 1);
- memcpy(q, p, len);
- while (pointer_count > 0) {
- q[len] = '*';
- ++len;
- --pointer_count;
- }
- q[len] = '\0';
- free(op);
- return q;
-}
-
-/* Read a list of parameters. Each parameter is a name and a type.
- The list ends with a ')'. We have already read the '('. */
-static struct params *
-read_params(void)
-{
- char *token;
- struct params *ret, **pp;
-
- ret = NULL;
- pp = &ret;
- token = read_token_no_eof();
- if (strcmp(token, ")") != 0) {
- while (1) {
- *pp = xmalloc(sizeof(struct params));
- (*pp)->name = token;
- (*pp)->type = read_type();
- pp = &(*pp)->next;
- *pp = NULL;
-
- token = read_token_no_eof();
- if (strcmp(token, ",") != 0)
- break;
- token = read_token_no_eof();
- }
- }
- if (strcmp(token, ")") != 0) {
- fprintf(stderr, "%s:%u: expected '('\n",
- file, lineno);
- exit(1);
- }
- return ret;
-}
-
-/* Read a function header. This reads up to and including the initial
- '{' character. Returns 1 if it read a header, 0 at EOF. */
-static int
-read_func_header(char **name, struct params **params, struct params **rets)
-{
- char *token;
-
- token = read_token();
- if (token == NULL)
- return 0;
- if (strcmp(token, "func") != 0) {
- fprintf(stderr, "%s:%u: expected \"func\"\n",
- file, lineno);
- exit(1);
- }
- *name = read_token_no_eof();
-
- token = read_token();
- if (token == NULL || strcmp(token, "(") != 0) {
- fprintf(stderr, "%s:%u: expected \"(\"\n",
- file, lineno);
- exit(1);
- }
- *params = read_params();
-
- token = read_token();
- if (token == NULL || strcmp(token, "(") != 0)
- *rets = NULL;
- else {
- *rets = read_params();
- token = read_token();
- }
- if (token == NULL || strcmp(token, "{") != 0) {
- fprintf(stderr, "%s:%u: expected \"{\"\n",
- file, lineno);
- exit(1);
- }
- return 1;
-}
-
-/* Write out parameters. */
-static void
-write_params(struct params *params, int *first)
-{
- struct params *p;
-
- for (p = params; p != NULL; p = p->next) {
- if (*first)
- *first = 0;
- else
- printf(", ");
- printf("%s %s", p->type, p->name);
- }
-}
-
-/* Write a 6g function header. */
-static void
-write_6g_func_header(char *package, char *name, struct params *params,
- struct params *rets)
-{
- int first;
-
- printf("void\n%s·%s(", package, name);
- first = 1;
- write_params(params, &first);
- write_params(rets, &first);
- printf(")\n{\n");
-}
-
-/* Write a 6g function trailer. */
-static void
-write_6g_func_trailer(struct params *rets)
-{
- struct params *p;
-
- for (p = rets; p != NULL; p = p->next)
- printf("\tFLUSH(&%s);\n", p->name);
- printf("}\n");
-}
-
-/* Define the gcc function return type if necessary. */
-static void
-define_gcc_return_type(char *package, char *name, struct params *rets)
-{
- struct params *p;
-
- if (rets == NULL || rets->next == NULL)
- return;
- printf("struct %s_%s_ret {\n", package, name);
- for (p = rets; p != NULL; p = p->next)
- printf(" %s %s;\n", p->type, p->name);
- printf("};\n");
-}
-
-/* Write out the gcc function return type. */
-static void
-write_gcc_return_type(char *package, char *name, struct params *rets)
-{
- if (rets == NULL)
- printf("void");
- else if (rets->next == NULL)
- printf("%s", rets->type);
- else
- printf("struct %s_%s_ret", package, name);
-}
-
-/* Write out a gcc function header. */
-static void
-write_gcc_func_header(char *package, char *name, struct params *params,
- struct params *rets)
-{
- int first;
- struct params *p;
-
- define_gcc_return_type(package, name, rets);
- write_gcc_return_type(package, name, rets);
- printf(" %s_%s(", package, name);
- first = 1;
- write_params(params, &first);
- printf(") asm (\"%s.%s\");\n", package, name);
- write_gcc_return_type(package, name, rets);
- printf(" %s_%s(", package, name);
- first = 1;
- write_params(params, &first);
- printf(")\n{\n");
- for (p = rets; p != NULL; p = p->next)
- printf(" %s %s;\n", p->type, p->name);
-}
-
-/* Write out a gcc function trailer. */
-static void
-write_gcc_func_trailer(char *package, char *name, struct params *rets)
-{
- if (rets == NULL)
- ;
- else if (rets->next == NULL)
- printf("return %s;\n", rets->name);
- else {
- struct params *p;
-
- printf(" {\n struct %s_%s_ret __ret;\n", package, name);
- for (p = rets; p != NULL; p = p->next)
- printf(" __ret.%s = %s;\n", p->name, p->name);
- printf(" return __ret;\n }\n");
- }
- printf("}\n");
-}
-
-/* Write out a function header. */
-static void
-write_func_header(char *package, char *name,
- struct params *params, struct params *rets)
-{
- if (gcc)
- write_gcc_func_header(package, name, params, rets);
- else
- write_6g_func_header(package, name, params, rets);
- printf("#line %d \"%s\"\n", lineno, file);
-}
-
-/* Write out a function trailer. */
-static void
-write_func_trailer(char *package, char *name,
- struct params *rets)
-{
- if (gcc)
- write_gcc_func_trailer(package, name, rets);
- else
- write_6g_func_trailer(rets);
-}
-
-/* Read and write the body of the function, ending in an unnested }
- (which is read but not written). */
-static void
-copy_body(void)
-{
- int nesting = 0;
- while (1) {
- int c;
-
- c = getchar_no_eof();
- if (c == '}' && nesting == 0)
- return;
- putchar(c);
- switch (c) {
- default:
- break;
- case '{':
- ++nesting;
- break;
- case '}':
- --nesting;
- break;
- case '/':
- c = getchar_update_lineno();
- putchar(c);
- if (c == '/') {
- do {
- c = getchar_no_eof();
- putchar(c);
- } while (c != '\n');
- } else if (c == '*') {
- while (1) {
- c = getchar_no_eof();
- putchar(c);
- if (c == '*') {
- do {
- c = getchar_no_eof();
- putchar(c);
- } while (c == '*');
- if (c == '/')
- break;
- }
- }
- }
- break;
- case '"':
- case '\'':
- {
- int delim = c;
- do {
- c = getchar_no_eof();
- putchar(c);
- if (c == '\\') {
- c = getchar_no_eof();
- putchar(c);
- c = '\0';
- }
- } while (c != delim);
- }
- break;
- }
- }
-}
-
-/* Process the entire file. */
-static void
-process_file(void)
-{
- char *package, *name;
- struct params *params, *rets;
-
- package = read_package();
- read_preprocessor_lines();
- while (read_func_header(&name, &params, &rets)) {
- write_func_header(package, name, params, rets);
- copy_body();
- write_func_trailer(package, name, rets);
- free(name);
- free_params(params);
- free_params(rets);
- }
- free(package);
-}
-
-static void
-usage(void)
-{
- fprintf(stderr, "Usage: cgo2c [--6g | --gc] [file]\n");
- exit(1);
-}
-
-int
-main(int argc, char **argv)
-{
- while(argc > 1 && argv[1][0] == '-') {
- if(strcmp(argv[1], "-") == 0)
- break;
- if(strcmp(argv[1], "--6g") == 0)
- gcc = 0;
- else if(strcmp(argv[1], "--gcc") == 0)
- gcc = 1;
- else
- usage();
- argc--;
- argv++;
- }
-
- if(argc <= 1 || strcmp(argv[1], "-") == 0) {
- file = "<stdin>";
- process_file();
- return 0;
- }
-
- if(argc > 2)
- usage();
-
- file = argv[1];
- if(freopen(file, "r", stdin) == 0) {
- fprintf(stderr, "open %s: %s\n", file, strerror(errno));
- exit(1);
- }
- process_file();
- return 0;
-}
diff -r 6aabab677469 -r 31d3a7baefdd src/runtime/chan.c
--- a/src/runtime/chan.c Sat Jun 06 21:56:04 2009 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1024 +0,0 @@
-// Copyright 2009 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.
-
-#include "runtime.h"
-
-static int32 debug = 0;
-static Lock chanlock;
-
-enum
-{
- Wclosed = 0x0001, // writer has closed
- Rclosed = 0x0002, // reader has seen close
- Eincr = 0x0004, // increment errors
- Emax = 0x0800, // error limit before throw
-};
-
-typedef struct Hchan Hchan;
-typedef struct Link Link;
-typedef struct WaitQ WaitQ;
-typedef struct SudoG SudoG;
-typedef struct Select Select;
-typedef struct Scase Scase;
-
-struct SudoG
-{
- G* g; // g and selgen constitute
- int32 selgen; // a weak pointer to g
- int16 offset; // offset of case number
- int8 isfree; // offset of case number
- SudoG* link;
- byte elem[8]; // synch data element (+ more)
-};
-
-struct WaitQ
-{
- SudoG* first;
- SudoG* last;
-};
-
-struct Hchan
-{
- uint16 elemsize;
- uint16 closed; // Wclosed Rclosed errorcount
- uint32 dataqsiz; // size of the circular q
- uint32 qcount; // total data in the q
- Alg* elemalg; // interface for element type
- Link* senddataq; // pointer for sender
- Link* recvdataq; // pointer for receiver
- WaitQ recvq; // list of recv waiters
- WaitQ sendq; // list of send waiters
- SudoG* free; // freelist
-};
-
-struct Link
-{
- Link* link; // asynch queue circular linked list
- byte elem[8]; // asynch queue data element (+ more)
-};
-
-struct Scase
-{
- Hchan* chan; // chan
- byte* pc; // return pc
- uint16 send; // 0-recv 1-send 2-default
- uint16 so; // vararg of selected bool
- union {
- byte elem[8]; // element (send)
- byte* elemp; // pointer to element (recv)
- } u;
-};
-
-struct Select
-{
- uint16 tcase; // total count of scase[]
- uint16 ncase; // currently filled scase[]
- Select* link; // for freelist
- Scase* scase[1]; // one per case
-};
-
-static Select* selfree[20];
-
-static SudoG* dequeue(WaitQ*, Hchan*);
-static void enqueue(WaitQ*, SudoG*);
-static SudoG* allocsg(Hchan*);
-static void freesg(Hchan*, SudoG*);
-static uint32 gcd(uint32, uint32);
-static uint32 fastrand1(void);
-static uint32 fastrand2(void);
-
-// newchan(elemsize uint32, elemalg uint32, hint uint32) (hchan *chan any);
-void
-sys·newchan(uint32 elemsize, uint32 elemalg, uint32 hint,
- Hchan* ret)
-{
- Hchan *c;
- int32 i;
-
- if(elemalg >= nelem(algarray)) {
- printf("chan(alg=%d)\n", elemalg);
- throw("sys·newchan: unsupported elem type");
- }
-
- c = mal(sizeof(*c));
-
- c->elemsize = elemsize;
- c->elemalg = &algarray[elemalg];
-
- if(hint > 0) {
- Link *d, *b, *e;
-
- // make a circular q
- b = nil;
- e = nil;
- for(i=0; i<hint; i++) {
- d = mal(sizeof(*d) + c->elemsize - sizeof(d->elem));
- if(e == nil)
- e = d;
- d->link = b;
- b = d;
- }
- e->link = b;
- c->recvdataq = b;
- c->senddataq = b;
- c->qcount = 0;
- c->dataqsiz = hint;
- }
-
- ret = c;
- FLUSH(&ret);
-
- if(debug) {
- prints("newchan: chan=");
- sys·printpointer(c);
- prints("; elemsize=");
- sys·printint(elemsize);
- prints("; elemalg=");
- sys·printint(elemalg);
- prints("; dataqsiz=");
- sys·printint(c->dataqsiz);
- prints("\n");
- }
-}
-
-static void
-incerr(Hchan* c)
-{
- c->closed += Eincr;
- if(c->closed & Emax) {
- unlock(&chanlock);
- throw("too many operations on a closed channel");
- }
-}
-
-/*
- * generic single channel send/recv
- * if the bool pointer is nil,
- * then the full exchange will
- * occur. if pres is not nil,
- * then the protocol will not
- * sleep but return if it could
- * not complete
- */
-void
-sendchan(Hchan *c, byte *ep, bool *pres)
-{
- SudoG *sg;
- G* gp;
-
- if(debug) {
- prints("chansend: chan=");
- sys·printpointer(c);
- prints("; elem=");
- c->elemalg->print(c->elemsize, ep);
- prints("\n");
- }
-
- lock(&chanlock);
-loop:
- if(c->closed & Wclosed)
- goto closed;
-
- if(c->dataqsiz > 0)
- goto asynch;
-
- sg = dequeue(&c->recvq, c);
- if(sg != nil) {
- if(ep != nil)
- c->elemalg->copy(c->elemsize, sg->elem, ep);
-
- gp = sg->g;
- gp->param = sg;
- unlock(&chanlock);
- ready(gp);
-
- if(pres != nil)
- *pres = true;
- return;
- }
-
- if(pres != nil) {
- unlock(&chanlock);
- *pres = false;
- return;
- }
-
- sg = allocsg(c);
- if(ep != nil)
- c->elemalg->copy(c->elemsize, sg->elem, ep);
- g->param = nil;
- g->status = Gwaiting;
- enqueue(&c->sendq, sg);
- unlock(&chanlock);
- gosched();
-
- lock(&chanlock);
- sg = g->param;
- if(sg == nil)
- goto loop;
- freesg(c, sg);
- unlock(&chanlock);
- if(pres != nil)
- *pres = true;
- return;
-
-asynch:
- if(c->closed & Wclosed)
- goto closed;
-
- if(c->qcount >= c->dataqsiz) {
- if(pres != nil) {
- unlock(&chanlock);
- *pres = false;
- return;
- }
- sg = allocsg(c);
- g->status = Gwaiting;
- enqueue(&c->sendq, sg);
- unlock(&chanlock);
- gosched();
-
- lock(&chanlock);
- goto asynch;
- }
- if(ep != nil)
- c->elemalg->copy(c->elemsize, c->senddataq->elem, ep);
- c->senddataq = c->senddataq->link;
- c->qcount++;
-
- sg = dequeue(&c->recvq, c);
- if(sg != nil) {
- gp = sg->g;
- freesg(c, sg);
- unlock(&chanlock);
- ready(gp);
- } else
- unlock(&chanlock);
- if(pres != nil)
- *pres = true;
- return;
-
-closed:
- incerr(c);
- if(pres != nil)
- *pres = true;
- unlock(&chanlock);
-}
-
-static void
-chanrecv(Hchan* c, byte *ep, bool* pres)
-{
- SudoG *sg;
- G *gp;
-
- if(debug) {
- prints("chanrecv: chan=");
- sys·printpointer(c);
- prints("\n");
- }
-
- lock(&chanlock);
-loop:
- if(c->dataqsiz > 0)
- goto asynch;
-
- if(c->closed & Wclosed)
- goto closed;
-
- sg = dequeue(&c->sendq, c);
- if(sg != nil) {
- c->elemalg->copy(c->elemsize, ep, sg->elem);
-
- gp = sg->g;
- gp->param = sg;
- unlock(&chanlock);
- ready(gp);
-
- if(pres != nil)
- *pres = true;
- return;
- }
-
- if(pres != nil) {
- unlock(&chanlock);
- *pres = false;
- return;
- }
-
- sg = allocsg(c);
- g->param = nil;
- g->status = Gwaiting;
- enqueue(&c->recvq, sg);
- unlock(&chanlock);
- gosched();
-
- lock(&chanlock);
- sg = g->param;
- if(sg == nil)
- goto loop;
-
- c->elemalg->copy(c->elemsize, ep, sg->elem);
- freesg(c, sg);
- unlock(&chanlock);
- if(pres != nil)
- *pres = true;
- return;
-
-asynch:
- if(c->qcount <= 0) {
- if(c->closed & Wclosed)
- goto closed;
-
- if(pres != nil) {
- unlock(&chanlock);
- *pres = false;
- return;
- }
- sg = allocsg(c);
- g->status = Gwaiting;
- enqueue(&c->recvq, sg);
- unlock(&chanlock);
- gosched();
-
- lock(&chanlock);
- goto asynch;
- }
- c->elemalg->copy(c->elemsize, ep, c->recvdataq->elem);
- c->recvdataq = c->recvdataq->link;
- c->qcount--;
- sg = dequeue(&c->sendq, c);
- if(sg != nil) {
- gp = sg->g;
- freesg(c, sg);
- unlock(&chanlock);
- ready(gp);
- if(pres != nil)
- *pres = true;
- return;
- }
-
- unlock(&chanlock);
- if(pres != nil)
- *pres = true;
- return;
-
-closed:
- c->elemalg->copy(c->elemsize, ep, nil);
- c->closed |= Rclosed;
- incerr(c);
- if(pres != nil)
- *pres = true;
- unlock(&chanlock);
-}
-
-// chansend1(hchan *chan any, elem any);
-void
-sys·chansend1(Hchan* c, ...)
-{
- int32 o;
- byte *ae;
-
- o = rnd(sizeof(c), c->elemsize);
- ae = (byte*)&c + o;
- sendchan(c, ae, nil);
-}
-
-// chansend2(hchan *chan any, elem any) (pres bool);
-void
-sys·chansend2(Hchan* c, ...)
-{
- int32 o;
- byte *ae, *ap;
-
- o = rnd(sizeof(c), c->elemsize);
- ae = (byte*)&c + o;
- o = rnd(o+c->elemsize, 1);
- ap = (byte*)&c + o;
-
- sendchan(c, ae, ap);
-}
-
-// chanrecv1(hchan *chan any) (elem any);
-void
-sys·chanrecv1(Hchan* c, ...)
-{
- int32 o;
- byte *ae;
-
- o = rnd(sizeof(c), c->elemsize);
- ae = (byte*)&c + o;
-
- chanrecv(c, ae, nil);
-}
-
-// chanrecv2(hchan *chan any) (elem any, pres bool);
-void
-sys·chanrecv2(Hchan* c, ...)
-{
- int32 o;
- byte *ae, *ap;
-
- o = rnd(sizeof(c), c->elemsize);
- ae = (byte*)&c + o;
- o = rnd(o+c->elemsize, 1);
- ap = (byte*)&c + o;
-
- chanrecv(c, ae, ap);
-}
-
-// chanrecv3(hchan *chan any, elem *any) (pres bool);
-void
-sys·chanrecv3(Hchan* c, byte* ep, byte pres)
-{
- chanrecv(c, ep, &pres);
-}
-
-// newselect(size uint32) (sel *byte);
-void
-sys·newselect(int32 size, Select *sel)
-{
- int32 n;
-
- n = 0;
- if(size > 1)
- n = size-1;
-
- lock(&chanlock);
- sel = nil;
- if(size >= 1 && size < nelem(selfree)) {
- sel = selfree[size];
- if(sel != nil)
- selfree[size] = sel->link;
- }
- unlock(&chanlock);
- if(sel == nil)
- sel = mal(sizeof(*sel) + n*sizeof(sel->scase[0]));
-
- sel->tcase = size;
- sel->ncase = 0;
- FLUSH(&sel);
- if(debug) {
- prints("newselect s=");
- sys·printpointer(sel);
- prints(" size=");
- sys·printint(size);
- prints("\n");
- }
-}
-
-// selectsend(sel *byte, hchan *chan any, elem any) (selected bool);
-void
-sys·selectsend(Select *sel, Hchan *c, ...)
-{
- int32 i, eo;
- Scase *cas;
- byte *ae;
-
- // nil cases do not compete
- if(c == nil)
- return;
-
- i = sel->ncase;
- if(i >= sel->tcase)
- throw("selectsend: too many cases");
- sel->ncase = i+1;
- cas = sel->scase[i];
- if(cas == nil) {
- cas = mal(sizeof *cas + c->elemsize - sizeof(cas->u.elem));
- sel->scase[i] = cas;
- }
-
- cas->pc = sys·getcallerpc(&sel);
- cas->chan = c;
-
- eo = rnd(sizeof(sel), sizeof(c));
- eo = rnd(eo+sizeof(c), c->elemsize);
- cas->so = rnd(eo+c->elemsize, 1);
- cas->send = 1;
-
- ae = (byte*)&sel + eo;
- c->elemalg->copy(c->elemsize, cas->u.elem, ae);
-
- if(debug) {
- prints("selectsend s=");
- sys·printpointer(sel);
- prints(" pc=");
- sys·printpointer(cas->pc);
- prints(" chan=");
- sys·printpointer(cas->chan);
- prints(" po=");
- sys·printint(cas->so);
- prints(" send=");
- sys·printint(cas->send);
- prints("\n");
- }
-}
-
-// selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
-void
-sys·selectrecv(Select *sel, Hchan *c, ...)
-{
- int32 i, eo;
- Scase *cas;
-
- // nil cases do not compete
- if(c == nil)
- return;
-
- i = sel->ncase;
- if(i >= sel->tcase)
- throw("selectrecv: too many cases");
- sel->ncase = i+1;
- cas = sel->scase[i];
- if(cas == nil) {
- cas = mal(sizeof *cas);
- sel->scase[i] = cas;
- }
- cas->pc = sys·getcallerpc(&sel);
- cas->chan = c;
-
- eo = rnd(sizeof(sel), sizeof(c));
- eo = rnd(eo+sizeof(c), sizeof(byte*));
- cas->so = rnd(eo+sizeof(byte*), 1);
- cas->send = 0;
- cas->u.elemp = *(byte**)((byte*)&sel + eo);
-
- if(debug) {
- prints("selectrecv s=");
- sys·printpointer(sel);
- prints(" pc=");
- sys·printpointer(cas->pc);
- prints(" chan=");
- sys·printpointer(cas->chan);
- prints(" so=");
- sys·printint(cas->so);
- prints(" send=");
- sys·printint(cas->send);
- prints("\n");
- }
-}
-
-
-// selectdefaul(sel *byte) (selected bool);
-void
-sys·selectdefault(Select *sel, ...)
-{
- int32 i;
- Scase *cas;
-
- i = sel->ncase;
- if(i >= sel->tcase)
- throw("selectdefault: too many cases");
- sel->ncase = i+1;
- cas = sel->scase[i];
- if(cas == nil) {
- cas = mal(sizeof *cas);
- sel->scase[i] = cas;
- }
- cas->pc = sys·getcallerpc(&sel);
- cas->chan = nil;
-
- cas->so = rnd(sizeof(sel), 1);
- cas->send = 2;
- cas->u.elemp = nil;
-
- if(debug) {
- prints("selectdefault s=");
- sys·printpointer(sel);
- prints(" pc=");
- sys·printpointer(cas->pc);
- prints(" so=");
- sys·printint(cas->so);
- prints(" send=");
- sys·printint(cas->send);
- prints("\n");
- }
-}
-
-// selectgo(sel *byte);
-void
-sys·selectgo(Select *sel)
-{
- uint32 p, o, i;
- Scase *cas, *dfl;
- Hchan *c;
- SudoG *sg;
- G *gp;
- byte *as;
-
- if(debug) {
- prints("selectgo: sel=");
- sys·printpointer(sel);
- prints("\n");
- }
-
- if(sel->ncase < 2) {
- if(sel->ncase < 1)
- throw("selectgo: no cases");
- // make special case of one.
- }
-
- // select a (relative) prime
- for(i=0;; i++) {
- p = fastrand1();
- if(gcd(p, sel->ncase) == 1)
- break;
- if(i > 1000) {
- throw("selectgo: failed to select prime");
- }
- }
-
- // select an initial offset
- o = fastrand2();
-
- p %= sel->ncase;
- o %= sel->ncase;
-
- lock(&chanlock);
-
-loop:
- // pass 1 - look for something already waiting
- dfl = nil;
- for(i=0; i<sel->ncase; i++) {
- cas = sel->scase[o];
-
- if(cas->send == 2) { // default
- dfl = cas;
- goto next1;
- }
-
- c = cas->chan;
- if(c->dataqsiz > 0) {
- if(cas->send) {
- if(c->closed & Wclosed)
- goto sclose;
- if(c->qcount < c->dataqsiz)
- goto asyns;
- goto next1;
- }
- if(c->qcount > 0)
- goto asynr;
- if(c->closed & Wclosed)
- goto rclose;
- goto next1;
- }
-
- if(cas->send) {
- if(c->closed & Wclosed)
- goto sclose;
- sg = dequeue(&c->recvq, c);
- if(sg != nil)
- goto gots;
- goto next1;
- }
- sg = dequeue(&c->sendq, c);
- if(sg != nil)
- goto gotr;
- if(c->closed & Wclosed)
- goto rclose;
-
- next1:
- o += p;
- if(o >= sel->ncase)
- o -= sel->ncase;
- }
-
- if(dfl != nil) {
- cas = dfl;
- goto retc;
- }
-
-
- // pass 2 - enqueue on all chans
- for(i=0; i<sel->ncase; i++) {
- cas = sel->scase[o];
- c = cas->chan;
-
- if(c->dataqsiz > 0) {
- if(cas->send) {
- if(c->qcount < c->dataqsiz) {
- prints("selectgo: pass 2 async send\n");
- goto asyns;
- }
- sg = allocsg(c);
- sg->offset = o;
- enqueue(&c->sendq, sg);
- goto next2;
- }
- if(c->qcount > 0) {
- prints("selectgo: pass 2 async recv\n");
- goto asynr;
- }
- sg = allocsg(c);
- sg->offset = o;
- enqueue(&c->recvq, sg);
- goto next2;
- }
-
- if(cas->send) {
- sg = dequeue(&c->recvq, c);
- if(sg != nil) {
- prints("selectgo: pass 2 sync send\n");
- g->selgen++;
- goto gots;
- }
- sg = allocsg(c);
- sg->offset = o;
- c->elemalg->copy(c->elemsize, sg->elem, cas->u.elem);
- enqueue(&c->sendq, sg);
- goto next2;
- }
- sg = dequeue(&c->sendq, c);
- if(sg != nil) {
- prints("selectgo: pass 2 sync recv\n");
- g->selgen++;
- goto gotr;
- }
- sg = allocsg(c);
- sg->offset = o;
- enqueue(&c->recvq, sg);
-
- next2:
- o += p;
- if(o >= sel->ncase)
- o -= sel->ncase;
- }
-
- g->param = nil;
- g->status = Gwaiting;
- unlock(&chanlock);
- gosched();
-
- lock(&chanlock);
- sg = g->param;
- if(sg == nil)
- goto loop;
-
- o = sg->offset;
- cas = sel->scase[o];
- c = cas->chan;
-
- if(c->dataqsiz > 0) {
-// prints("shouldnt happen\n");
- goto loop;
- }
-
- if(debug) {
- prints("wait-return: sel=");
- sys·printpointer(sel);
- prints(" c=");
- sys·printpointer(c);
- prints(" cas=");
- sys·printpointer(cas);
- prints(" send=");
- sys·printint(cas->send);
- prints(" o=");
- sys·printint(o);
- prints("\n");
- }
-
- if(!cas->send) {
- if(cas->u.elemp != nil)
- c->elemalg->copy(c->elemsize, cas->u.elemp, sg->elem);
- }
-
- freesg(c, sg);
- goto retc;
-
-asynr:
- if(cas->u.elemp != nil)
- c->elemalg->copy(c->elemsize, cas->u.elemp, c->recvdataq->elem);
- c->recvdataq = c->recvdataq->link;
- c->qcount--;
- sg = dequeue(&c->sendq, c);
- if(sg != nil) {
- gp = sg->g;
- freesg(c, sg);
- ready(gp);
- }
- goto retc;
-
-asyns:
- if(cas->u.elem != nil)
- c->elemalg->copy(c->elemsize, c->senddataq->elem, cas->u.elem);
- c->senddataq = c->senddataq->link;
- c->qcount++;
- sg = dequeue(&c->recvq, c);
- if(sg != nil) {
- gp = sg->g;
- freesg(c, sg);
- ready(gp);
- }
- goto retc;
-
-gotr:
- // recv path to wakeup the sender (sg)
- if(debug) {
- prints("gotr: sel=");
- sys·printpointer(sel);
- prints(" c=");
- sys·printpointer(c);
- prints(" o=");
- sys·printint(o);
- prints("\n");
- }
- if(cas->u.elemp != nil)
- c->elemalg->copy(c->elemsize, cas->u.elemp, sg->elem);
- gp = sg->g;
- gp->param = sg;
- ready(gp);
- goto retc;
-
-rclose:
- if(cas->u.elemp != nil)
- c->elemalg->copy(c->elemsize, cas->u.elemp, nil);
- c->closed |= Rclosed;
- incerr(c);
- goto retc;
-
-gots:
- // send path to wakeup the receiver (sg)
- if(debug) {
- prints("gots: sel=");
- sys·printpointer(sel);
- prints(" c=");
- sys·printpointer(c);
- prints(" o=");
- sys·printint(o);
- prints("\n");
- }
- if(c->closed & Wclosed)
- goto sclose;
- c->elemalg->copy(c->elemsize, sg->elem, cas->u.elem);
- gp = sg->g;
- gp->param = sg;
- ready(gp);
- goto retc;
-
-sclose:
- incerr(c);
- goto retc;
-
-retc:
- if(sel->ncase >= 1 && sel->ncase < nelem(selfree)) {
- sel->link = selfree[sel->ncase];
- selfree[sel->ncase] = sel;
- }
- unlock(&chanlock);
-
- sys·setcallerpc(&sel, cas->pc);
- as = (byte*)&sel + cas->so;
- *as = true;
-}
-
-// closechan(sel *byte);
-void
-sys·closechan(Hchan *c)
-{
- SudoG *sg;
- G* gp;
-
- lock(&chanlock);
- incerr(c);
- c->closed |= Wclosed;
-
- // release all readers
- for(;;) {
- sg = dequeue(&c->recvq, c);
- if(sg == nil)
- break;
- gp = sg->g;
- gp->param = nil;
- freesg(c, sg);
- ready(gp);
- }
-
- // release all writers
- for(;;) {
- sg = dequeue(&c->sendq, c);
- if(sg == nil)
- break;
- gp = sg->g;
- gp->param = nil;
- freesg(c, sg);
- ready(gp);
- }
-
- unlock(&chanlock);
-}
-
-// closedchan(sel *byte) bool;
-void
-sys·closedchan(Hchan *c, bool closed)
-{
- // test Rclosed
- closed = 0;
- if(c->closed & Rclosed)
- closed = 1;
- FLUSH(&closed);
-}
-
-static SudoG*
-dequeue(WaitQ *q, Hchan *c)
-{
- SudoG *sgp;
-
-loop:
- sgp = q->first;
- if(sgp == nil)
- return nil;
- q->first = sgp->link;
-
- // if sgp is stale, ignore it
- if(sgp->selgen != sgp->g->selgen) {
- //prints("INVALID PSEUDOG POINTER\n");
- freesg(c, sgp);
- goto loop;
- }
-
- // invalidate any others
- sgp->g->selgen++;
- return sgp;
-}
-
-static void
-enqueue(WaitQ *q, SudoG *sgp)
-{
- sgp->link = nil;
- if(q->
View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

@tsnow
Copy link
Author

tsnow commented May 15, 2014

[12:16 AM] Josh Svee: haha I wrote a channel for C++ http://pastebin.com/TFgem03N
I'm sure I'm not the first, I didn't really look
but it's works like:



Channel<int> ch;
     
ch <= 5;

      
int out;

ch >= out;

        

// and then out == 5

@tsnow
Copy link
Author

tsnow commented May 15, 2014

Alan Harris
9:28 AM (2 hours ago)

to me
Yep. It's easy to write to a queue with a coarse lock. Lot harder to implement channel semantics.

Alan Harris
9:34 AM (2 hours ago)

to me
Yep, select is the hard thing to write,
ex. You can't write to a closed channel but you can read from it and it never blocks.

Etc.

It's all about observers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment