1 |
|
2 | function createPool(n){
|
3 | var T, pool, idleThreads, q, poolObject, e;
|
4 | T = this;
|
5 | n = Math.floor(n);
|
6 | if (!(n > 0)) {
|
7 | throw '.createPool( num ): number of threads must be a Number > 0';
|
8 | }
|
9 | pool = [];
|
10 | idleThreads = [];
|
11 | q = {
|
12 | first: null,
|
13 | last: null,
|
14 | length: 0
|
15 | };
|
16 | poolObject = {
|
17 | on: onEvent,
|
18 | load: poolLoad,
|
19 | destroy: destroy,
|
20 | pendingJobs: getPendingJobs,
|
21 | idleThreads: getIdleThreads,
|
22 | totalThreads: getNumThreads,
|
23 | any: {
|
24 | eval: evalAny,
|
25 | emit: emitAny
|
26 | },
|
27 | all: {
|
28 | eval: evalAll,
|
29 | emit: emitAll
|
30 | }
|
31 | };
|
32 | try {
|
33 | while (n--) {
|
34 | pool[n] = idleThreads[n] = T.create();
|
35 | }
|
36 | } catch (e$) {
|
37 | e = e$;
|
38 | destroy('rudely');
|
39 | throw e;
|
40 | }
|
41 | return poolObject;
|
42 | function poolLoad(path, cb){
|
43 | var i;
|
44 | i = pool.length;
|
45 | while (i--) {
|
46 | pool[i].load(path, cb);
|
47 | }
|
48 | }
|
49 | function nextJob(t){
|
50 | var job;
|
51 | job = qPull();
|
52 | if (job) {
|
53 | if (job.type === 1) {
|
54 | t.eval(job.srcTextOrEventType, function(e, d){
|
55 | var f;
|
56 | nextJob(t);
|
57 | f = job.cbOrData;
|
58 | if (typeof f === 'function') {
|
59 | try {
|
60 | return f.call(t, e, d);
|
61 | } catch (e$) {
|
62 | e = e$;
|
63 | return e;
|
64 | }
|
65 | } else {
|
66 | return t.emit(job.srcTextOrEventType, f);
|
67 | }
|
68 | });
|
69 | } else if (job.type === 2) {
|
70 | t.emit(job.srcTextOrEventType, job.cbOrData);
|
71 | nextJob(t);
|
72 | }
|
73 | } else {
|
74 | idleThreads.push(t);
|
75 | }
|
76 | }
|
77 | function qPush(srcTextOrEventType, cbOrData, type){
|
78 | var job;
|
79 | job = {
|
80 | srcTextOrEventType: srcTextOrEventType,
|
81 | cbOrData: cbOrData,
|
82 | type: type,
|
83 | next: null
|
84 | };
|
85 | if (q.last) {
|
86 | q.last = q.last.next = job;
|
87 | } else {
|
88 | q.first = q.last = job;
|
89 | }
|
90 | q.length++;
|
91 | }
|
92 | function qPull(){
|
93 | var job;
|
94 | job = q.first;
|
95 | if (job) {
|
96 | if (q.last === job) {
|
97 | q.first = q.last = null;
|
98 | } else {
|
99 | q.first = job.next;
|
100 | }
|
101 | q.length--;
|
102 | }
|
103 | return job;
|
104 | }
|
105 | function evalAny(src, cb){
|
106 | qPush(src, cb, 1);
|
107 | if (idleThreads.length) {
|
108 | nextJob(idleThreads.pop());
|
109 | }
|
110 | return poolObject;
|
111 | }
|
112 | function evalAll(src, cb){
|
113 | pool.forEach(function(v, i, o){
|
114 | return v.eval(src, cb);
|
115 | });
|
116 | return poolObject;
|
117 | }
|
118 | function emitAny(event, data){
|
119 | qPush(event, data, 2);
|
120 | if (idleThreads.length) {
|
121 | nextJob(idleThreads.pop());
|
122 | }
|
123 | return poolObject;
|
124 | }
|
125 | function emitAll(event, data){
|
126 | pool.forEach(function(v, i, o){
|
127 | return v.emit(event, data);
|
128 | });
|
129 | return poolObject;
|
130 | }
|
131 | function onEvent(event, cb){
|
132 | pool.forEach(function(v, i, o){
|
133 | return v.on(event, cb);
|
134 | });
|
135 | return this;
|
136 | }
|
137 | function destroy(rudely){
|
138 | var err, beNice, beRude;
|
139 | err = function(){
|
140 | throw 'This thread pool has been destroyed';
|
141 | };
|
142 | beNice = function(){
|
143 | if (q.length) {
|
144 | return setTimeout(beNice, 666);
|
145 | } else {
|
146 | return beRude();
|
147 | }
|
148 | };
|
149 | beRude = function(){
|
150 | q.length = 0;
|
151 | q.first = null;
|
152 | pool.forEach(function(v, i, o){
|
153 | return v.destroy();
|
154 | });
|
155 | return poolObject.eval = poolObject.totalThreads = poolObject.idleThreads = poolObject.pendingJobs = poolObject.destroy = err;
|
156 | };
|
157 | if (rudely) {
|
158 | beRude();
|
159 | } else {
|
160 | beNice();
|
161 | }
|
162 | }
|
163 | function getNumThreads(){
|
164 | return pool.length;
|
165 | }
|
166 | function getIdleThreads(){
|
167 | return idleThreads.length;
|
168 | }
|
169 | function getPendingJobs(){
|
170 | return q.length;
|
171 | }
|
172 | return getPendingJobs;
|
173 | }
|