OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [runtime/] [chan.c] - Blame information for rev 864

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 747 jeremybenn
// 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
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.