summary refs log tree commit diff stats
path: root/tinyc/tccasm.c
Commit message (Expand)AuthorAgeFilesLines
* move tinyc to a separate repo and allow installing external dependencency (eg...Timothee Cour2020-04-031-1303/+0
* TinyC upgrade (#6593)Dmitry Atamanov2017-10-281-218/+500
* Fix typosFederico Ceratto2015-02-151-1/+1
* Removes executable bit for text files.Grzegorz Adam Hankiewicz2013-03-161-0/+0
* tiny C support; cosmetic improvements for the docsAraq2010-08-281-0/+1021
span> ^
c80d563af ^




dbf9117c5 ^
c80d563af ^
43bddf62d ^
c80d563af ^
3b69a8d27 ^

3b69a8d27 ^
3b69a8d27 ^




2ca90a20a ^
3b69a8d27 ^
2ca90a20a ^
36fc1d9d7 ^
3b69a8d27 ^




36fc1d9d7 ^
3b69a8d27 ^
6195dbe49 ^


3b69a8d27 ^

36fc1d9d7 ^




3b69a8d27 ^


36fc1d9d7 ^





3b69a8d27 ^









36fc1d9d7 ^
3b69a8d27 ^









c80d563af ^
3b69a8d27 ^







6195dbe49 ^



















3b69a8d27 ^






























da7d6c844 ^
3b69a8d27 ^






c50b5b62e ^
3b69a8d27 ^


7c03c882f ^
3b69a8d27 ^









0ab373115 ^
3b69a8d27 ^



0ab373115 ^
3b69a8d27 ^
































1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194

 
                                  
                                         




                                                   
                            
 
                             
                                                         

                       
 




                                                                          
              
                        
                         
                  




                                  
                                  
 


                                                

                             




                                      


                            





                              









                                       
                                       









                                                   
                                                       







                                         



















                                                     






























                                                                              
                                      






                     
                                                


                                        
                            









                                                                          
                                           



                                                                      
                               
































                                                                                
#
#
#            Nim's Runtime Library
#        (c) Copyright 2015 Andreas Rumpf
#
#    See the file "copying.txt", included in this
#    distribution, for details about the copyright.
#

## Implements Nim's 'spawn'.

when not declared(NimString):
  {.error: "You must not import this module explicitly".}

{.push stackTrace:off.}

# We declare our own condition variables here to get rid of the dummy lock
# on Windows:

type
  CondVar = object
    c: SysCond
    when defined(posix):
      stupidLock: SysLock
      counter: int

proc createCondVar(): CondVar =
  initSysCond(result.c)
  when defined(posix):
    initSysLock(result.stupidLock)
    #acquireSys(result.stupidLock)

proc destroyCondVar(c: var CondVar) {.inline.} =
  deinitSysCond(c.c)

proc await(cv: var CondVar) =
  when defined(posix):
    acquireSys(cv.stupidLock)
    while cv.counter <= 0:
      waitSysCond(cv.c, cv.stupidLock)
    dec cv.counter
    releaseSys(cv.stupidLock)
  else:
    waitSysCondWindows(cv.c)

proc signal(cv: var CondVar) =
  when defined(posix):
    acquireSys(cv.stupidLock)
    inc cv.counter
    releaseSys(cv.stupidLock)
  signalSysCond(cv.c)

type
  FastCondVar = object
    event, slowPath: bool
    slow: CondVar

proc createFastCondVar(): FastCondVar =
  initSysCond(result.slow.c)
  when defined(posix):
    initSysLock(result.slow.stupidLock)
    #acquireSys(result.slow.stupidLock)
  result.event = false
  result.slowPath = false

proc await(cv: var FastCondVar) =
  #for i in 0 .. 50:
  #  if cas(addr cv.event, true, false):
  #    # this is a HIT: Triggers > 95% in my tests.
  #    return
  #  cpuRelax()
  #cv.slowPath = true
  # XXX For some reason this crashes some test programs
  await(cv.slow)
  cv.event = false

proc signal(cv: var FastCondVar) =
  cv.event = true
  #if cas(addr cv.slowPath, true, false):
  signal(cv.slow)

type
  Barrier* {.compilerProc.} = object
    counter: int
    cv: CondVar

proc barrierEnter*(b: ptr Barrier) {.compilerProc.} =
  atomicInc b.counter

proc barrierLeave*(b: ptr Barrier) {.compilerProc.} =
  atomicDec b.counter
  if b.counter <= 0: signal(b.cv)

proc openBarrier*(b: ptr Barrier) {.compilerProc.} =
  b.counter = 0
  b.cv = createCondVar()

proc closeBarrier*(b: ptr Barrier) {.compilerProc.} =
  await(b.cv)
  destroyCondVar(b.cv)

{.pop.}

# ----------------------------------------------------------------------------

type
  WorkerProc = proc (thread, args: pointer) {.nimcall, gcsafe.}
  Worker = object
    taskArrived: CondVar
    taskStarted: FastCondVar #\
    # task data:
    f: WorkerProc
    data: pointer
    ready: bool # put it here for correct alignment!

proc nimArgsPassingDone(p: pointer) {.compilerProc.} =
  let w = cast[ptr Worker](p)
  signal(w.taskStarted)

var gSomeReady = createFastCondVar()

proc slave(w: ptr Worker) {.thread.} =
  while true:
    w.ready = true # If we instead signal "workerReady" we need the scheduler
                   # to notice this. The scheduler could then optimize the
                   # layout of the worker threads (e.g. keep the list sorted)
                   # so that no search for a "ready" thread is necessary.
                   # This might be implemented later, but is more tricky than
                   # it looks because 'spawn' itself can run concurrently.
    signal(gSomeReady)
    await(w.taskArrived)
    assert(not w.ready)
    # shield against spurious wakeups:
    if w.data != nil:
      w.f(w, w.data)
      w.data = nil

const NumThreads = 4

var
  workers: array[NumThreads, Thread[ptr Worker]]
  workersData: array[NumThreads, Worker]

proc setup() =
  for i in 0 ..< NumThreads:
    workersData[i].taskArrived = createCondVar()
    workersData[i].taskStarted = createFastCondVar()
    createThread(workers[i], slave, addr(workersData[i]))

proc preferSpawn*(): bool =
  ## Use this proc to determine quickly if a 'spawn' or a direct call is
  ## preferable. If it returns 'true' a 'spawn' may make sense. In general
  ## it is not necessary to call this directly; use 'spawnX' instead.
  result = gSomeReady.event

proc spawn*(call: typed) {.magic: "Spawn".}
  ## always spawns a new task, so that the 'call' is never executed on
  ## the calling thread. 'call' has to be proc call 'p(...)' where 'p'
  ## is gcsafe and has 'void' as the return type.

template spawnX*(call: typed) =
  ## spawns a new task if a CPU core is ready, otherwise executes the
  ## call in the calling thread. Usually it is advised to
  ## use 'spawn' in order to not block the producer for an unknown
  ## amount of time. 'call' has to be proc call 'p(...)' where 'p'
  ## is gcsafe and has 'void' as the return type.
  if preferSpawn(): spawn call
  else: call

proc nimSpawn(fn: WorkerProc; data: pointer) {.compilerProc.} =
  # implementation of 'spawn' that is used by the code generator.
  while true:
    for i in 0.. high(workers):
      let w = addr(workersData[i])
      if cas(addr w.ready, true, false):
        w.data = data
        w.f = fn
        signal(w.taskArrived)
        await(w.taskStarted)
        return
    await(gSomeReady)

proc sync*() =
  ## a simple barrier to wait for all spawn'ed tasks. If you need more elaborate
  ## waiting, you have to use an explicit barrier.
  while true:
    var allReady = true
    for i in 0 .. high(workers):
      if not allReady: break
      allReady = allReady and workersData[i].ready
    if allReady: break
    await(gSomeReady)

setup()