OSDN Git Service

runtime: Fix chan code for big-endian strict-alignment systems
[pf3gnuchains/gcc-fork.git] / libgo / runtime / chan.c
1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 #include "runtime.h"
6 #include "go-type.h"
7
8 #define NOSELGEN        1
9
10 static  int32   debug   = 0;
11
12 typedef struct  WaitQ   WaitQ;
13 typedef struct  SudoG   SudoG;
14 typedef struct  Select  Select;
15 typedef struct  Scase   Scase;
16
17 typedef struct  __go_type_descriptor    Type;
18 typedef struct  __go_channel_type       ChanType;
19
20 struct  SudoG
21 {
22         G*      g;              // g and selgen constitute
23         uint32  selgen;         // a weak pointer to g
24         SudoG*  link;
25         byte*   elem;           // data element
26 };
27
28 struct  WaitQ
29 {
30         SudoG*  first;
31         SudoG*  last;
32 };
33
34 struct  Hchan
35 {
36         uint32  qcount;                 // total data in the q
37         uint32  dataqsiz;               // size of the circular q
38         uint16  elemsize;
39         bool    closed;
40         uint8   elemalign;
41         uint32  sendx;                  // send index
42         uint32  recvx;                  // receive index
43         WaitQ   recvq;                  // list of recv waiters
44         WaitQ   sendq;                  // list of send waiters
45         Lock;
46 };
47
48 // Buffer follows Hchan immediately in memory.
49 // chanbuf(c, i) is pointer to the i'th slot in the buffer.
50 #define chanbuf(c, i) ((byte*)((c)+1)+(uintptr)(c)->elemsize*(i))
51
52 enum
53 {
54         // Scase.kind
55         CaseRecv,
56         CaseSend,
57         CaseDefault,
58 };
59
60 struct  Scase
61 {
62         SudoG   sg;                     // must be first member (cast to Scase)
63         Hchan*  chan;                   // chan
64         uint16  kind;
65         uint16  index;                  // index to return
66         bool*   receivedp;              // pointer to received bool (recv2)
67 };
68
69 struct  Select
70 {
71         uint16  tcase;                  // total count of scase[]
72         uint16  ncase;                  // currently filled scase[]
73         uint16* pollorder;              // case poll order
74         Hchan** lockorder;              // channel lock order
75         Scase   scase[1];               // one per case (in order of appearance)
76 };
77
78 static  void    dequeueg(WaitQ*);
79 static  SudoG*  dequeue(WaitQ*);
80 static  void    enqueue(WaitQ*, SudoG*);
81
82 Hchan*
83 runtime_makechan_c(ChanType *t, int64 hint)
84 {
85         Hchan *c;
86         int32 n;
87         const Type *elem;
88         
89         elem = t->__element_type;
90
91         if(hint < 0 || (int32)hint != hint || (elem->__size > 0 && (uintptr)hint > ((uintptr)-1) / elem->__size))
92                 runtime_panicstring("makechan: size out of range");
93
94         n = sizeof(*c);
95
96         // allocate memory in one call
97         c = (Hchan*)runtime_mal(n + hint*elem->__size);
98         c->elemsize = elem->__size;
99         c->elemalign = elem->__align;
100         c->dataqsiz = hint;
101
102         if(debug)
103                 runtime_printf("makechan: chan=%p; elemsize=%lld; elemalign=%d; dataqsiz=%d\n",
104                         c, (long long)elem->__size, elem->__align, c->dataqsiz);
105
106         return c;
107 }
108
109 // For reflect
110 //      func makechan(typ *ChanType, size uint32) (chan)
111 uintptr reflect_makechan(ChanType *, uint32)
112   asm ("libgo_reflect.reflect.makechan");
113
114 uintptr
115 reflect_makechan(ChanType *t, uint32 size)
116 {
117         void *ret;
118         Hchan *c;
119
120         c = runtime_makechan_c(t, size);
121         ret = runtime_mal(sizeof(void*));
122         __builtin_memcpy(ret, &c, sizeof(void*));
123         return (uintptr)ret;
124 }
125
126 // makechan(t *ChanType, hint int64) (hchan *chan any);
127 Hchan*
128 __go_new_channel(ChanType *t, uintptr hint)
129 {
130         return runtime_makechan_c(t, hint);
131 }
132
133 Hchan*
134 __go_new_channel_big(ChanType *t, uint64 hint)
135 {
136         return runtime_makechan_c(t, hint);
137 }
138
139 /*
140  * generic single channel send/recv
141  * if the bool pointer is nil,
142  * then the full exchange will
143  * occur. if pres is not nil,
144  * then the protocol will not
145  * sleep but return if it could
146  * not complete.
147  *
148  * sleep can wake up with g->param == nil
149  * when a channel involved in the sleep has
150  * been closed.  it is easiest to loop and re-run
151  * the operation; we'll see that it's now closed.
152  */
153 void
154 runtime_chansend(ChanType *t, Hchan *c, byte *ep, bool *pres)
155 {
156         SudoG *sg;
157         SudoG mysg;
158         G* gp;
159         G* g;
160
161         g = runtime_g();
162
163         if(c == nil) {
164                 USED(t);
165                 if(pres != nil) {
166                         *pres = false;
167                         return;
168                 }
169                 g->status = Gwaiting;
170                 g->waitreason = "chan send (nil chan)";
171                 runtime_gosched();
172                 return;  // not reached
173         }
174
175         if(runtime_gcwaiting)
176                 runtime_gosched();
177
178         if(debug) {
179                 runtime_printf("chansend: chan=%p\n", c);
180         }
181
182         runtime_lock(c);
183         if(c->closed)
184                 goto closed;
185
186         if(c->dataqsiz > 0)
187                 goto asynch;
188
189         sg = dequeue(&c->recvq);
190         if(sg != nil) {
191                 runtime_unlock(c);
192                 
193                 gp = sg->g;
194                 gp->param = sg;
195                 if(sg->elem != nil)
196                         runtime_memmove(sg->elem, ep, c->elemsize);
197                 runtime_ready(gp);
198
199                 if(pres != nil)
200                         *pres = true;
201                 return;
202         }
203
204         if(pres != nil) {
205                 runtime_unlock(c);
206                 *pres = false;
207                 return;
208         }
209
210         mysg.elem = ep;
211         mysg.g = g;
212         mysg.selgen = NOSELGEN;
213         g->param = nil;
214         g->status = Gwaiting;
215         g->waitreason = "chan send";
216         enqueue(&c->sendq, &mysg);
217         runtime_unlock(c);
218         runtime_gosched();
219
220         if(g->param == nil) {
221                 runtime_lock(c);
222                 if(!c->closed)
223                         runtime_throw("chansend: spurious wakeup");
224                 goto closed;
225         }
226
227         return;
228
229 asynch:
230         if(c->closed)
231                 goto closed;
232
233         if(c->qcount >= c->dataqsiz) {
234                 if(pres != nil) {
235                         runtime_unlock(c);
236                         *pres = false;
237                         return;
238                 }
239                 mysg.g = g;
240                 mysg.elem = nil;
241                 mysg.selgen = NOSELGEN;
242                 g->status = Gwaiting;
243                 g->waitreason = "chan send";
244                 enqueue(&c->sendq, &mysg);
245                 runtime_unlock(c);
246                 runtime_gosched();
247
248                 runtime_lock(c);
249                 goto asynch;
250         }
251         runtime_memmove(chanbuf(c, c->sendx), ep, c->elemsize);
252         if(++c->sendx == c->dataqsiz)
253                 c->sendx = 0;
254         c->qcount++;
255
256         sg = dequeue(&c->recvq);
257         if(sg != nil) {
258                 gp = sg->g;
259                 runtime_unlock(c);
260                 runtime_ready(gp);
261         } else
262                 runtime_unlock(c);
263         if(pres != nil)
264                 *pres = true;
265         return;
266
267 closed:
268         runtime_unlock(c);
269         runtime_panicstring("send on closed channel");
270 }
271
272
273 void
274 runtime_chanrecv(ChanType *t, Hchan* c, byte *ep, bool *selected, bool *received)
275 {
276         SudoG *sg;
277         SudoG mysg;
278         G *gp;
279         G *g;
280
281         if(runtime_gcwaiting)
282                 runtime_gosched();
283
284         if(debug)
285                 runtime_printf("chanrecv: chan=%p\n", c);
286
287         g = runtime_g();
288
289         if(c == nil) {
290                 USED(t);
291                 if(selected != nil) {
292                         *selected = false;
293                         return;
294                 }
295                 g->status = Gwaiting;
296                 g->waitreason = "chan receive (nil chan)";
297                 runtime_gosched();
298                 return;  // not reached
299         }
300
301         runtime_lock(c);
302         if(c->dataqsiz > 0)
303                 goto asynch;
304
305         if(c->closed)
306                 goto closed;
307
308         sg = dequeue(&c->sendq);
309         if(sg != nil) {
310                 runtime_unlock(c);
311
312                 if(ep != nil)
313                         runtime_memmove(ep, sg->elem, c->elemsize);
314                 gp = sg->g;
315                 gp->param = sg;
316                 runtime_ready(gp);
317
318                 if(selected != nil)
319                         *selected = true;
320                 if(received != nil)
321                         *received = true;
322                 return;
323         }
324
325         if(selected != nil) {
326                 runtime_unlock(c);
327                 *selected = false;
328                 return;
329         }
330
331         mysg.elem = ep;
332         mysg.g = g;
333         mysg.selgen = NOSELGEN;
334         g->param = nil;
335         g->status = Gwaiting;
336         g->waitreason = "chan receive";
337         enqueue(&c->recvq, &mysg);
338         runtime_unlock(c);
339         runtime_gosched();
340
341         if(g->param == nil) {
342                 runtime_lock(c);
343                 if(!c->closed)
344                         runtime_throw("chanrecv: spurious wakeup");
345                 goto closed;
346         }
347
348         if(received != nil)
349                 *received = true;
350         return;
351
352 asynch:
353         if(c->qcount <= 0) {
354                 if(c->closed)
355                         goto closed;
356
357                 if(selected != nil) {
358                         runtime_unlock(c);
359                         *selected = false;
360                         if(received != nil)
361                                 *received = false;
362                         return;
363                 }
364                 mysg.g = g;
365                 mysg.elem = nil;
366                 mysg.selgen = NOSELGEN;
367                 g->status = Gwaiting;
368                 g->waitreason = "chan receive";
369                 enqueue(&c->recvq, &mysg);
370                 runtime_unlock(c);
371                 runtime_gosched();
372
373                 runtime_lock(c);
374                 goto asynch;
375         }
376         if(ep != nil)
377                 runtime_memmove(ep, chanbuf(c, c->recvx), c->elemsize);
378         runtime_memclr(chanbuf(c, c->recvx), c->elemsize);
379         if(++c->recvx == c->dataqsiz)
380                 c->recvx = 0;
381         c->qcount--;
382
383         sg = dequeue(&c->sendq);
384         if(sg != nil) {
385                 gp = sg->g;
386                 runtime_unlock(c);
387                 runtime_ready(gp);
388         } else
389                 runtime_unlock(c);
390
391         if(selected != nil)
392                 *selected = true;
393         if(received != nil)
394                 *received = true;
395         return;
396
397 closed:
398         if(ep != nil)
399                 runtime_memclr(ep, c->elemsize);
400         if(selected != nil)
401                 *selected = true;
402         if(received != nil)
403                 *received = false;
404         runtime_unlock(c);
405 }
406
407 // The compiler generates a call to __go_send_small to send a value 8
408 // bytes or smaller.
409 void
410 __go_send_small(ChanType *t, Hchan* c, uint64 val)
411 {
412         union
413         {
414                 byte b[sizeof(uint64)];
415                 uint64 v;
416         } u;
417         byte *p;
418
419         u.v = val;
420 #ifndef WORDS_BIGENDIAN
421         p = u.b;
422 #else
423         p = u.b + sizeof(uint64) - t->__element_type->__size;
424 #endif
425         runtime_chansend(t, c, p, nil);
426 }
427
428 // The compiler generates a call to __go_send_big to send a value
429 // larger than 8 bytes or smaller.
430 void
431 __go_send_big(ChanType *t, Hchan* c, byte* p)
432 {
433         runtime_chansend(t, c, p, nil);
434 }
435
436 // The compiler generates a call to __go_receive_small to receive a
437 // value 8 bytes or smaller.
438 uint64
439 __go_receive_small(ChanType *t, Hchan* c)
440 {
441         union {
442                 byte b[sizeof(uint64)];
443                 uint64 v;
444         } u;
445         byte *p;
446
447         u.v = 0;
448 #ifndef WORDS_BIGENDIAN
449         p = u.b;
450 #else
451         p = u.b + sizeof(uint64) - t->__element_type->__size;
452 #endif
453         runtime_chanrecv(t, c, p, nil, nil);
454         return u.v;
455 }
456
457 // The compiler generates a call to __go_receive_big to receive a
458 // value larger than 8 bytes.
459 void
460 __go_receive_big(ChanType *t, Hchan* c, byte* p)
461 {
462         runtime_chanrecv(t, c, p, nil, nil);
463 }
464
465 _Bool runtime_chanrecv2(ChanType *t, Hchan* c, byte* p)
466   __asm__("runtime.chanrecv2");
467
468 _Bool
469 runtime_chanrecv2(ChanType *t, Hchan* c, byte* p)
470 {
471         bool received;
472
473         runtime_chanrecv(t, c, p, nil, &received);
474         return received;
475 }
476
477 // func selectnbsend(c chan any, elem any) bool
478 //
479 // compiler implements
480 //
481 //      select {
482 //      case c <- v:
483 //              ... foo
484 //      default:
485 //              ... bar
486 //      }
487 //
488 // as
489 //
490 //      if selectnbsend(c, v) {
491 //              ... foo
492 //      } else {
493 //              ... bar
494 //      }
495 //
496 _Bool
497 runtime_selectnbsend(ChanType *t, Hchan *c, byte *p)
498 {
499         bool res;
500
501         runtime_chansend(t, c, p, &res);
502         return res;
503 }
504
505 // func selectnbrecv(elem *any, c chan any) bool
506 //
507 // compiler implements
508 //
509 //      select {
510 //      case v = <-c:
511 //              ... foo
512 //      default:
513 //              ... bar
514 //      }
515 //
516 // as
517 //
518 //      if selectnbrecv(&v, c) {
519 //              ... foo
520 //      } else {
521 //              ... bar
522 //      }
523 //
524 _Bool
525 runtime_selectnbrecv(ChanType *t, byte *v, Hchan *c)
526 {
527         bool selected;
528
529         runtime_chanrecv(t, c, v, &selected, nil);
530         return selected;
531 }       
532
533 // func selectnbrecv2(elem *any, ok *bool, c chan any) bool
534 //
535 // compiler implements
536 //
537 //      select {
538 //      case v, ok = <-c:
539 //              ... foo
540 //      default:
541 //              ... bar
542 //      }
543 //
544 // as
545 //
546 //      if c != nil && selectnbrecv2(&v, &ok, c) {
547 //              ... foo
548 //      } else {
549 //              ... bar
550 //      }
551 //
552 _Bool
553 runtime_selectnbrecv2(ChanType *t, byte *v, _Bool *received, Hchan *c)
554 {
555         bool selected;
556         bool r;
557
558         r = false;
559         runtime_chanrecv(t, c, v, &selected, received == nil ? nil : &r);
560         if(received != nil)
561                 *received = r;
562         return selected;
563 }       
564
565 // For reflect:
566 //      func chansend(c chan, val iword, nb bool) (selected bool)
567 // where an iword is the same word an interface value would use:
568 // the actual data if it fits, or else a pointer to the data.
569
570 _Bool reflect_chansend(ChanType *, Hchan *, uintptr, _Bool)
571   __asm__("libgo_reflect.reflect.chansend");
572
573 _Bool
574 reflect_chansend(ChanType *t, Hchan *c, uintptr val, _Bool nb)
575 {
576         bool selected;
577         bool *sp;
578         byte *vp;
579         
580         if(nb) {
581                 selected = false;
582                 sp = (bool*)&selected;
583         } else {
584                 selected = true;
585                 sp = nil;
586         }
587         if(__go_is_pointer_type(t->__element_type))
588                 vp = (byte*)&val;
589         else
590                 vp = (byte*)val;
591         runtime_chansend(t, c, vp, sp);
592         return selected;
593 }
594
595 // For reflect:
596 //      func chanrecv(c chan, nb bool) (val iword, selected, received bool)
597 // where an iword is the same word an interface value would use:
598 // the actual data if it fits, or else a pointer to the data.
599
600 struct chanrecv_ret
601 {
602         uintptr val;
603         _Bool selected;
604         _Bool received;
605 };
606
607 struct chanrecv_ret reflect_chanrecv(ChanType *, Hchan *, _Bool)
608   __asm__("libgo_reflect.reflect.chanrecv");
609
610 struct chanrecv_ret
611 reflect_chanrecv(ChanType *t, Hchan *c, _Bool nb)
612 {
613         struct chanrecv_ret ret;
614         byte *vp;
615         bool *sp;
616         bool selected;
617         bool received;
618
619         if(nb) {
620                 selected = false;
621                 sp = &selected;
622         } else {
623                 ret.selected = true;
624                 sp = nil;
625         }
626         received = false;
627         if(__go_is_pointer_type(t->__element_type)) {
628                 vp = (byte*)&ret.val;
629         } else {
630                 vp = runtime_mal(t->__element_type->__size);
631                 ret.val = (uintptr)vp;
632         }
633         runtime_chanrecv(t, c, vp, sp, &received);
634         if(nb)
635                 ret.selected = selected;
636         ret.received = received;
637         return ret;
638 }
639
640 static void newselect(int32, Select**);
641
642 // newselect(size uint32) (sel *byte);
643
644 void* runtime_newselect(int) __asm__("runtime.newselect");
645
646 void*
647 runtime_newselect(int size)
648 {
649         Select *sel;
650
651         newselect(size, &sel);
652         return (void*)sel;
653 }
654
655 static void
656 newselect(int32 size, Select **selp)
657 {
658         int32 n;
659         Select *sel;
660
661         n = 0;
662         if(size > 1)
663                 n = size-1;
664
665         sel = runtime_mal(sizeof(*sel) +
666                 n*sizeof(sel->scase[0]) +
667                 size*sizeof(sel->lockorder[0]) +
668                 size*sizeof(sel->pollorder[0]));
669
670         sel->tcase = size;
671         sel->ncase = 0;
672         sel->lockorder = (void*)(sel->scase + size);
673         sel->pollorder = (void*)(sel->lockorder + size);
674         *selp = sel;
675
676         if(debug)
677                 runtime_printf("newselect s=%p size=%d\n", sel, size);
678 }
679
680 // cut in half to give stack a chance to split
681 static void selectsend(Select *sel, Hchan *c, int index, void *elem);
682
683 // selectsend(sel *byte, hchan *chan any, elem *any) (selected bool);
684
685 void runtime_selectsend(Select *, Hchan *, void *, int)
686   __asm__("runtime.selectsend");
687
688 void
689 runtime_selectsend(Select *sel, Hchan *c, void *elem, int index)
690 {
691         // nil cases do not compete
692         if(c == nil)
693                 return;
694         
695         selectsend(sel, c, index, elem);
696 }
697
698 static void
699 selectsend(Select *sel, Hchan *c, int index, void *elem)
700 {
701         int32 i;
702         Scase *cas;
703         
704         i = sel->ncase;
705         if(i >= sel->tcase)
706                 runtime_throw("selectsend: too many cases");
707         sel->ncase = i+1;
708         cas = &sel->scase[i];
709
710         cas->index = index;
711         cas->chan = c;
712         cas->kind = CaseSend;
713         cas->sg.elem = elem;
714
715         if(debug)
716                 runtime_printf("selectsend s=%p index=%d chan=%p\n",
717                         sel, cas->index, cas->chan);
718 }
719
720 // cut in half to give stack a chance to split
721 static void selectrecv(Select *sel, Hchan *c, int index, void *elem, bool*);
722
723 // selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
724
725 void runtime_selectrecv(Select *, Hchan *, void *, int)
726   __asm__("runtime.selectrecv");
727
728 void
729 runtime_selectrecv(Select *sel, Hchan *c, void *elem, int index)
730 {
731         // nil cases do not compete
732         if(c == nil)
733                 return;
734
735         selectrecv(sel, c, index, elem, nil);
736 }
737
738 // selectrecv2(sel *byte, hchan *chan any, elem *any, received *bool) (selected bool);
739
740 void runtime_selectrecv2(Select *, Hchan *, void *, bool *, int)
741   __asm__("runtime.selectrecv2");
742
743 void
744 runtime_selectrecv2(Select *sel, Hchan *c, void *elem, bool *received, int index)
745 {
746         // nil cases do not compete
747         if(c == nil)
748                 return;
749
750         selectrecv(sel, c, index, elem, received);
751 }
752
753 static void
754 selectrecv(Select *sel, Hchan *c, int index, void *elem, bool *received)
755 {
756         int32 i;
757         Scase *cas;
758
759         i = sel->ncase;
760         if(i >= sel->tcase)
761                 runtime_throw("selectrecv: too many cases");
762         sel->ncase = i+1;
763         cas = &sel->scase[i];
764         cas->index = index;
765         cas->chan = c;
766
767         cas->kind = CaseRecv;
768         cas->sg.elem = elem;
769         cas->receivedp = received;
770
771         if(debug)
772                 runtime_printf("selectrecv s=%p index=%d chan=%p\n",
773                         sel, cas->index, cas->chan);
774 }
775
776 // cut in half to give stack a chance to split
777 static void selectdefault(Select*, int);
778
779 // selectdefault(sel *byte) (selected bool);
780
781 void runtime_selectdefault(Select *, int) __asm__("runtime.selectdefault");
782
783 void
784 runtime_selectdefault(Select *sel, int index)
785 {
786         selectdefault(sel, index);
787 }
788
789 static void
790 selectdefault(Select *sel, int index)
791 {
792         int32 i;
793         Scase *cas;
794
795         i = sel->ncase;
796         if(i >= sel->tcase)
797                 runtime_throw("selectdefault: too many cases");
798         sel->ncase = i+1;
799         cas = &sel->scase[i];
800         cas->index = index;
801         cas->chan = nil;
802
803         cas->kind = CaseDefault;
804
805         if(debug)
806                 runtime_printf("selectdefault s=%p index=%d\n",
807                         sel, cas->index);
808 }
809
810 static void
811 sellock(Select *sel)
812 {
813         uint32 i;
814         Hchan *c, *c0;
815
816         c = nil;
817         for(i=0; i<sel->ncase; i++) {
818                 c0 = sel->lockorder[i];
819                 if(c0 && c0 != c) {
820                         c = sel->lockorder[i];
821                         runtime_lock(c);
822                 }
823         }
824 }
825
826 static void
827 selunlock(Select *sel)
828 {
829         uint32 i;
830         Hchan *c, *c0;
831
832         c = nil;
833         for(i=sel->ncase; i-->0;) {
834                 c0 = sel->lockorder[i];
835                 if(c0 && c0 != c) {
836                         c = c0;
837                         runtime_unlock(c);
838                 }
839         }
840 }
841
842 void
843 runtime_block(void)
844 {
845         G *g;
846
847         g = runtime_g();
848         g->status = Gwaiting;   // forever
849         g->waitreason = "select (no cases)";
850         runtime_gosched();
851 }
852
853 static int selectgo(Select**);
854
855 // selectgo(sel *byte);
856
857 int runtime_selectgo(Select *) __asm__("runtime.selectgo");
858
859 int
860 runtime_selectgo(Select *sel)
861 {
862         return selectgo(&sel);
863 }
864
865 static int
866 selectgo(Select **selp)
867 {
868         Select *sel;
869         uint32 o, i, j;
870         Scase *cas, *dfl;
871         Hchan *c;
872         SudoG *sg;
873         G *gp;
874         int index;
875         G *g;
876
877         sel = *selp;
878         if(runtime_gcwaiting)
879                 runtime_gosched();
880
881         if(debug)
882                 runtime_printf("select: sel=%p\n", sel);
883
884         g = runtime_g();
885
886         // The compiler rewrites selects that statically have
887         // only 0 or 1 cases plus default into simpler constructs.
888         // The only way we can end up with such small sel->ncase
889         // values here is for a larger select in which most channels
890         // have been nilled out.  The general code handles those
891         // cases correctly, and they are rare enough not to bother
892         // optimizing (and needing to test).
893
894         // generate permuted order
895         for(i=0; i<sel->ncase; i++)
896                 sel->pollorder[i] = i;
897         for(i=1; i<sel->ncase; i++) {
898                 o = sel->pollorder[i];
899                 j = runtime_fastrand1()%(i+1);
900                 sel->pollorder[i] = sel->pollorder[j];
901                 sel->pollorder[j] = o;
902         }
903
904         // sort the cases by Hchan address to get the locking order.
905         for(i=0; i<sel->ncase; i++) {
906                 c = sel->scase[i].chan;
907                 for(j=i; j>0 && sel->lockorder[j-1] >= c; j--)
908                         sel->lockorder[j] = sel->lockorder[j-1];
909                 sel->lockorder[j] = c;
910         }
911         sellock(sel);
912
913 loop:
914         // pass 1 - look for something already waiting
915         dfl = nil;
916         for(i=0; i<sel->ncase; i++) {
917                 o = sel->pollorder[i];
918                 cas = &sel->scase[o];
919                 c = cas->chan;
920
921                 switch(cas->kind) {
922                 case CaseRecv:
923                         if(c->dataqsiz > 0) {
924                                 if(c->qcount > 0)
925                                         goto asyncrecv;
926                         } else {
927                                 sg = dequeue(&c->sendq);
928                                 if(sg != nil)
929                                         goto syncrecv;
930                         }
931                         if(c->closed)
932                                 goto rclose;
933                         break;
934
935                 case CaseSend:
936                         if(c->closed)
937                                 goto sclose;
938                         if(c->dataqsiz > 0) {
939                                 if(c->qcount < c->dataqsiz)
940                                         goto asyncsend;
941                         } else {
942                                 sg = dequeue(&c->recvq);
943                                 if(sg != nil)
944                                         goto syncsend;
945                         }
946                         break;
947
948                 case CaseDefault:
949                         dfl = cas;
950                         break;
951                 }
952         }
953
954         if(dfl != nil) {
955                 selunlock(sel);
956                 cas = dfl;
957                 goto retc;
958         }
959
960
961         // pass 2 - enqueue on all chans
962         for(i=0; i<sel->ncase; i++) {
963                 o = sel->pollorder[i];
964                 cas = &sel->scase[o];
965                 c = cas->chan;
966                 sg = &cas->sg;
967                 sg->g = g;
968                 sg->selgen = g->selgen;
969
970                 switch(cas->kind) {
971                 case CaseRecv:
972                         enqueue(&c->recvq, sg);
973                         break;
974                 
975                 case CaseSend:
976                         enqueue(&c->sendq, sg);
977                         break;
978                 }
979         }
980
981         g->param = nil;
982         g->status = Gwaiting;
983         g->waitreason = "select";
984         selunlock(sel);
985         runtime_gosched();
986
987         sellock(sel);
988         sg = g->param;
989
990         // pass 3 - dequeue from unsuccessful chans
991         // otherwise they stack up on quiet channels
992         for(i=0; i<sel->ncase; i++) {
993                 cas = &sel->scase[i];
994                 if(cas != (Scase*)sg) {
995                         c = cas->chan;
996                         if(cas->kind == CaseSend)
997                                 dequeueg(&c->sendq);
998                         else
999                                 dequeueg(&c->recvq);
1000                 }
1001         }
1002
1003         if(sg == nil)
1004                 goto loop;
1005
1006         cas = (Scase*)sg;
1007         c = cas->chan;
1008
1009         if(c->dataqsiz > 0)
1010                 runtime_throw("selectgo: shouldnt happen");
1011
1012         if(debug)
1013                 runtime_printf("wait-return: sel=%p c=%p cas=%p kind=%d\n",
1014                         sel, c, cas, cas->kind);
1015
1016         if(cas->kind == CaseRecv) {
1017                 if(cas->receivedp != nil)
1018                         *cas->receivedp = true;
1019         }
1020
1021         selunlock(sel);
1022         goto retc;
1023
1024 asyncrecv:
1025         // can receive from buffer
1026         if(cas->receivedp != nil)
1027                 *cas->receivedp = true;
1028         if(cas->sg.elem != nil)
1029                 runtime_memmove(cas->sg.elem, chanbuf(c, c->recvx), c->elemsize);
1030         runtime_memclr(chanbuf(c, c->recvx), c->elemsize);
1031         if(++c->recvx == c->dataqsiz)
1032                 c->recvx = 0;
1033         c->qcount--;
1034         sg = dequeue(&c->sendq);
1035         if(sg != nil) {
1036                 gp = sg->g;
1037                 selunlock(sel);
1038                 runtime_ready(gp);
1039         } else {
1040                 selunlock(sel);
1041         }
1042         goto retc;
1043
1044 asyncsend:
1045         // can send to buffer
1046         runtime_memmove(chanbuf(c, c->sendx), cas->sg.elem, c->elemsize);
1047         if(++c->sendx == c->dataqsiz)
1048                 c->sendx = 0;
1049         c->qcount++;
1050         sg = dequeue(&c->recvq);
1051         if(sg != nil) {
1052                 gp = sg->g;
1053                 selunlock(sel);
1054                 runtime_ready(gp);
1055         } else {
1056                 selunlock(sel);
1057         }
1058         goto retc;
1059
1060 syncrecv:
1061         // can receive from sleeping sender (sg)
1062         selunlock(sel);
1063         if(debug)
1064                 runtime_printf("syncrecv: sel=%p c=%p o=%d\n", sel, c, o);
1065         if(cas->receivedp != nil)
1066                 *cas->receivedp = true;
1067         if(cas->sg.elem != nil)
1068                 runtime_memmove(cas->sg.elem, sg->elem, c->elemsize);
1069         gp = sg->g;
1070         gp->param = sg;
1071         runtime_ready(gp);
1072         goto retc;
1073
1074 rclose:
1075         // read at end of closed channel
1076         selunlock(sel);
1077         if(cas->receivedp != nil)
1078                 *cas->receivedp = false;
1079         if(cas->sg.elem != nil)
1080                 runtime_memclr(cas->sg.elem, c->elemsize);
1081         goto retc;
1082
1083 syncsend:
1084         // can send to sleeping receiver (sg)
1085         selunlock(sel);
1086         if(debug)
1087                 runtime_printf("syncsend: sel=%p c=%p o=%d\n", sel, c, o);
1088         if(sg->elem != nil)
1089                 runtime_memmove(sg->elem, cas->sg.elem, c->elemsize);
1090         gp = sg->g;
1091         gp->param = sg;
1092         runtime_ready(gp);
1093
1094 retc:
1095         // return index corresponding to chosen case
1096         index = cas->index;
1097         runtime_free(sel);
1098         return index;
1099
1100 sclose:
1101         // send on closed channel
1102         selunlock(sel);
1103         runtime_panicstring("send on closed channel");
1104         return 0;  // not reached
1105 }
1106
1107 // closechan(sel *byte);
1108 void
1109 runtime_closechan(Hchan *c)
1110 {
1111         SudoG *sg;
1112         G* gp;
1113
1114         if(c == nil)
1115                 runtime_panicstring("close of nil channel");
1116
1117         if(runtime_gcwaiting)
1118                 runtime_gosched();
1119
1120         runtime_lock(c);
1121         if(c->closed) {
1122                 runtime_unlock(c);
1123                 runtime_panicstring("close of closed channel");
1124         }
1125
1126         c->closed = true;
1127
1128         // release all readers
1129         for(;;) {
1130                 sg = dequeue(&c->recvq);
1131                 if(sg == nil)
1132                         break;
1133                 gp = sg->g;
1134                 gp->param = nil;
1135                 runtime_ready(gp);
1136         }
1137
1138         // release all writers
1139         for(;;) {
1140                 sg = dequeue(&c->sendq);
1141                 if(sg == nil)
1142                         break;
1143                 gp = sg->g;
1144                 gp->param = nil;
1145                 runtime_ready(gp);
1146         }
1147
1148         runtime_unlock(c);
1149 }
1150
1151 void
1152 __go_builtin_close(Hchan *c)
1153 {
1154         runtime_closechan(c);
1155 }
1156
1157 // For reflect
1158 //      func chanclose(c chan)
1159
1160 void reflect_chanclose(uintptr) __asm__("libgo_reflect.reflect.chanclose");
1161
1162 void
1163 reflect_chanclose(uintptr c)
1164 {
1165         runtime_closechan((Hchan*)c);
1166 }
1167
1168 // For reflect
1169 //      func chanlen(c chan) (len int32)
1170
1171 int32 reflect_chanlen(uintptr) __asm__("libgo_reflect.reflect.chanlen");
1172
1173 int32
1174 reflect_chanlen(uintptr ca)
1175 {
1176         Hchan *c;
1177         int32 len;
1178
1179         c = (Hchan*)ca;
1180         if(c == nil)
1181                 len = 0;
1182         else
1183                 len = c->qcount;
1184         return len;
1185 }
1186
1187 int
1188 __go_chan_len(Hchan *c)
1189 {
1190         return reflect_chanlen((uintptr)c);
1191 }
1192
1193 // For reflect
1194 //      func chancap(c chan) (cap int32)
1195
1196 int32 reflect_chancap(uintptr) __asm__("libgo_reflect.reflect.chancap");
1197
1198 int32
1199 reflect_chancap(uintptr ca)
1200 {
1201         Hchan *c;
1202         int32 cap;
1203
1204         c = (Hchan*)ca;
1205         if(c == nil)
1206                 cap = 0;
1207         else
1208                 cap = c->dataqsiz;
1209         return cap;
1210 }
1211
1212 int
1213 __go_chan_cap(Hchan *c)
1214 {
1215         return reflect_chancap((uintptr)c);
1216 }
1217
1218 static SudoG*
1219 dequeue(WaitQ *q)
1220 {
1221         SudoG *sgp;
1222
1223 loop:
1224         sgp = q->first;
1225         if(sgp == nil)
1226                 return nil;
1227         q->first = sgp->link;
1228
1229         // if sgp is stale, ignore it
1230         if(sgp->selgen != NOSELGEN &&
1231                 (sgp->selgen != sgp->g->selgen ||
1232                 !runtime_cas(&sgp->g->selgen, sgp->selgen, sgp->selgen + 2))) {
1233                 //prints("INVALID PSEUDOG POINTER\n");
1234                 goto loop;
1235         }
1236
1237         return sgp;
1238 }
1239
1240 static void
1241 dequeueg(WaitQ *q)
1242 {
1243         SudoG **l, *sgp, *prevsgp;
1244         G *g;
1245
1246         g = runtime_g();
1247         prevsgp = nil;
1248         for(l=&q->first; (sgp=*l) != nil; l=&sgp->link, prevsgp=sgp) {
1249                 if(sgp->g == g) {
1250                         *l = sgp->link;
1251                         if(q->last == sgp)
1252                                 q->last = prevsgp;
1253                         break;
1254                 }
1255         }
1256 }
1257
1258 static void
1259 enqueue(WaitQ *q, SudoG *sgp)
1260 {
1261         sgp->link = nil;
1262         if(q->first == nil) {
1263                 q->first = sgp;
1264                 q->last = sgp;
1265                 return;
1266         }
1267         q->last->link = sgp;
1268         q->last = sgp;
1269 }