summaryrefslogtreecommitdiff
path: root/node_modules/webworker-threads/src/createPool.ls
blob: 36b7c47acd00e4f00dc8ef6b383c7663f60f907c (plain)
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
function create-pool (n)
    T = this
    n = Math.floor n
    throw '.createPool( num ): number of threads must be a Number > 0' unless n > 0

    pool         = []
    idle-threads = []
    q            = { first: null, last: null, length: 0 }
    pool-object  = {
        on: on-event
        load: pool-load
        destroy: destroy
        pending-jobs: get-pending-jobs
        idle-threads: get-idle-threads
        total-threads: get-num-threads
        any: { eval: eval-any, emit: emit-any }
        all: { eval: eval-all, emit: emit-all }
    }

    try
        while n-- => pool[n] = idle-threads[n] = T.create!
    catch e
        destroy \rudely
        throw e

    return pool-object

    ### Helper Functions Start Here ###

    const RUN = 1
    const EMIT = 2

    function pool-load (path, cb)
        i = pool.length
        while i--
            pool[i].load path, cb
        return

    function next-job (t)
        job = q-pull!
        if job
            if job.type is RUN
                t.eval job.src-text-or-event-type, (e, d) ->
                    next-job t
                    f = job.cb-or-data
                    job.cb-or-data.call t, e, d if f
            else
                if job.type is EMIT
                    t.emit job.src-text-or-event-type, job.cb-or-data
                    next-job t
        else
            idle-threads.push t
        return

    function q-push (src-text-or-event-type, cb-or-data, type)
        job = { src-text-or-event-type, cb-or-data, type, next: null }
        if q.last
            q.last = q.last.next = job
        else
            q.first = q.last = job
        q.length++
        return

    function q-pull
        job = q.first
        if job
            if q.last is job then q.first = q.last = null else q.first = job.next
            q.length--
        return job

    function eval-any (src, cb)
        q-push src, cb, RUN
        next-job idle-threads.pop! if idle-threads.length
        return pool-object

    function eval-all (src, cb)
        pool.for-each (v, i, o) -> v.eval src, cb
        return pool-object

    function emit-any (event, data)
        q-push event, data, EMIT
        next-job idle-threads.pop! if idle-threads.length
        return pool-object

    function emit-all (event, data)
        pool.for-each (v, i, o) -> v.emit event, data
        return pool-object

    function on-event (event, cb)
        pool.for-each (v, i, o) -> v.on event, cb
        return this

    function destroy (rudely)
        err = -> throw 'This thread pool has been destroyed'
        be-nice = -> if q.length then setTimeout be-nice, 666 else be-rude!
        be-rude = ->
            q.length = 0
            q.first = null
            pool.for-each (v, i, o) -> v.destroy!
            pool-object.eval = pool-object.total-threads = pool-object.idle-threads =
                pool-object.pendingJobs = pool-object.destroy = err
        if rudely then be-rude! else be-nice!
        return

    function get-num-threads  => pool.length
    function get-idle-threads => idle-threads.length
    function get-pending-jobs => q.length