git ssb

0+

wanderer🌟 / js-primea-hypervisor



Tree: c331410c6a6f9cd1457d0321b06291624febe799

Files: c331410c6a6f9cd1457d0321b06291624febe799 / kernel.js

4667 bytesRaw
1const Message = require('primea-message')
2const BN = require('bn.js')
3const PortManager = require('./portManager.js')
4const DeleteMessage = require('./deleteMessage')
5
6module.exports = class Kernel {
7 /**
8 * the Kernel manages the varous message passing functions and provides
9 * an interface for the containers to use
10 * @param {Object} opts
11 * @param {Object} opts.id - the UUID of the Kernel
12 * @param {Object} opts.state - the state of the container
13 * @param {Object} opts.hypervisor
14 * @param {Object} opts.container - the container constuctor and argments
15 */
16 constructor (opts) {
17 this.state = opts.state
18 this.hypervisor = opts.hypervisor
19 this.id = opts.id
20 this.container = new opts.container.Constructor(this, opts.container.args)
21
22 this.ticks = 0
23 this.containerState = 'idle'
24
25 // create the port manager
26 this.ports = new PortManager(Object.assign({
27 kernel: this
28 }, opts))
29 }
30
31 /**
32 * adds a message to this containers message queue
33 * @param {string} portName
34 * @param {object} message
35 */
36 queue (portName, message) {
37 this.ports.queue(portName, message)
38 return this._startMessageLoop()
39 }
40
41 async initialize (message) {
42 await this.run(message, 'initialize')
43 return this._startMessageLoop()
44 }
45
46 // waits for the next message
47 async _startMessageLoop () {
48 // this ensure we only every have one loop running at a time
49 if (this.containerState !== 'running') {
50 this.containerState = 'running'
51
52 while (1) {
53 const message = await this.ports.getNextMessage()
54 if (!message) break
55
56 // dequqe message
57 message.fromPort.messages.shift()
58 // if the message we recived had more ticks then we currently have the
59 // update it
60 if (message._fromTicks > this.ticks) {
61 this.ticks = message._fromTicks
62 this.hypervisor.scheduler.update(this)
63 }
64 // run the next message
65 await this.run(message)
66 }
67 // no more messages; shut down
68 this.hypervisor.scheduler.done(this.id)
69 }
70 }
71
72 /**
73 * run the kernels code with a given enviroment
74 * @param {object} message - the message to run
75 * @param {boolean} init - whether or not to run the intialization routine
76 * @returns {Promise}
77 */
78 async run (message, method = 'run') {
79 let result
80
81 const responsePort = message.responsePort
82 delete message.responsePort
83
84 this.ports.addReceivedPorts(message)
85
86 if (message.constructor === DeleteMessage) {
87 this.ports._delete(message.fromName)
88 } else {
89 try {
90 result = await this.container[method](message) || {}
91 } catch (e) {
92 result = {
93 exception: true,
94 exceptionError: e
95 }
96 }
97 }
98
99 if (responsePort) {
100 this.send(responsePort, new Message({
101 data: result
102 }))
103 }
104
105 this.ports.clearUnboundedPorts()
106 }
107
108 getResponsePort (message) {
109 if (message.responsePort) {
110 return message.responsePort.destPort
111 } else {
112 const [portRef1, portRef2] = this.ports.createChannel()
113 message.responsePort = portRef2
114 this.ports._unboundPorts.delete(portRef2)
115 return portRef1
116 }
117 }
118
119 /**
120 * updates the number of ticks that the container has run
121 * @param {Number} count - the number of ticks to add
122 */
123 incrementTicks (count) {
124 this.ticks += count
125 this.hypervisor.scheduler.update(this)
126 }
127
128 /**
129 * creates a new message
130 * @param {*} data
131 */
132 createMessage (opts) {
133 const message = new Message(opts)
134 this.ports.checkSendingPorts(message)
135 return message
136 }
137
138 /**
139 * creates a new container. Returning a port to it.
140 * @param {String} type
141 * @param {*} data - the data to populate the initail state with
142 * @returns {Object}
143 */
144 createInstance (type, message) {
145 let nonce = this.state.nonce
146
147 const id = {
148 nonce: nonce,
149 parent: this.id
150 }
151
152 // incerment the nonce
153 nonce = new BN(nonce)
154 nonce.iaddn(1)
155 this.state.nonce = nonce.toArray()
156 this.ports.removeSentPorts(message)
157
158 return this.hypervisor.createInstance(type, message, id)
159 }
160
161 /**
162 * sends a message to a given port
163 * @param {Object} portRef - the port
164 * @param {Message} message - the message
165 */
166 send (port, message) {
167 message._hops++
168 // set the port that the message came from
169 message._fromTicks = this.ticks
170 this.ports.removeSentPorts(message)
171
172 // if (this.currentMessage !== message && !message.responsePort) {
173 // this.currentMessage._addSubMessage(message)
174 // }
175 return this.hypervisor.send(port, message)
176 }
177}
178

Built with git-ssb-web