|
1 | 1 | // Some temporary libuv hacks for servo
|
2 | 2 |
|
| 3 | +// UV2 |
| 4 | +enum uv_operation { |
| 5 | + op_hw() |
| 6 | +} |
| 7 | + |
| 8 | +enum uv_msg { |
| 9 | + // requests from library users |
| 10 | + msg_run(comm::chan<bool>), |
| 11 | + msg_run_in_bg(), |
| 12 | + msg_loop_delete(), |
| 13 | + msg_async_init([u8], fn~()), |
| 14 | + msg_async_send([u8]), |
| 15 | + msg_hw(), |
| 16 | + |
| 17 | + // dispatches from libuv |
| 18 | + uv_hw() |
| 19 | +} |
| 20 | + |
| 21 | +type uv_loop_data = { |
| 22 | + operation_port: comm::port<uv_operation>, |
| 23 | + rust_loop_chan: comm::chan<uv_msg> |
| 24 | +}; |
| 25 | + |
| 26 | +type uv_loop = comm::chan<uv_msg>; |
| 27 | + |
| 28 | +enum uv_handle { |
| 29 | + handle([u8], *ctypes::void) |
| 30 | +} |
| 31 | + |
3 | 32 | #[nolink]
|
4 | 33 | native mod rustrt {
|
5 | 34 | fn rust_uvtmp_create_thread() -> thread;
|
@@ -29,8 +58,177 @@ native mod rustrt {
|
29 | 58 | chan: comm::chan<iomsg>);
|
30 | 59 | fn rust_uvtmp_delete_buf(buf: *u8);
|
31 | 60 | fn rust_uvtmp_get_req_id(cd: connect_data) -> u32;
|
| 61 | + |
| 62 | + fn rust_uvtmp_uv_loop_new() -> *ctypes::void; |
| 63 | + fn rust_uvtmp_uv_loop_set_data( |
| 64 | + loop: *ctypes::void, |
| 65 | + data: *uv_loop_data); |
| 66 | + fn rust_uvtmp_uv_bind_op_cb(loop: *ctypes::void, cb: *u8) -> *ctypes::void; |
| 67 | + fn rust_uvtmp_uv_run(loop_handle: *ctypes::void); |
| 68 | + fn rust_uvtmp_uv_async_send(handle: *ctypes::void); |
32 | 69 | }
|
33 | 70 |
|
| 71 | +mod uv { |
| 72 | + export loop_new, run, run_in_bg, hw; |
| 73 | + |
| 74 | + // public functions |
| 75 | + fn loop_new() -> uv_loop unsafe { |
| 76 | + let ret_recv_port: comm::port<uv_loop> = |
| 77 | + comm::port(); |
| 78 | + let ret_recv_chan: comm::chan<uv_loop> = |
| 79 | + comm::chan(ret_recv_port); |
| 80 | + |
| 81 | + task::spawn_sched(3u) {|| |
| 82 | + // our beloved uv_loop_t ptr |
| 83 | + let loop_handle = rustrt:: |
| 84 | + rust_uvtmp_uv_loop_new(); |
| 85 | + |
| 86 | + // this port/chan pair are used to send messages to |
| 87 | + // libuv. libuv processes any pending messages on the |
| 88 | + // port (via crust) after receiving an async "wakeup" |
| 89 | + // on a special uv_async_t handle created below |
| 90 | + let operation_port = comm::port::<uv_operation>(); |
| 91 | + let operation_chan = comm::chan::<uv_operation>( |
| 92 | + operation_port); |
| 93 | + |
| 94 | + // this port/chan pair as used in the while() loop |
| 95 | + // below. It takes dispatches, originating from libuv |
| 96 | + // callbacks, to invoke handles registered by the |
| 97 | + // user |
| 98 | + let rust_loop_port = comm::port::<uv_msg>(); |
| 99 | + let rust_loop_chan = |
| 100 | + comm::chan::<uv_msg>(rust_loop_port); |
| 101 | + // let the task-spawner return |
| 102 | + comm::send(ret_recv_chan, copy(rust_loop_chan)); |
| 103 | + |
| 104 | + // create our "special" async handle that will |
| 105 | + // allow all operations against libuv to be |
| 106 | + // "buffered" in the operation_port, for processing |
| 107 | + // from the thread that libuv runs on |
| 108 | + let loop_data: uv_loop_data = { |
| 109 | + operation_port: operation_port, |
| 110 | + rust_loop_chan: rust_loop_chan |
| 111 | + }; |
| 112 | + rustrt::rust_uvtmp_uv_loop_set_data( |
| 113 | + loop_handle, |
| 114 | + ptr::addr_of(loop_data)); // pass an opaque C-ptr |
| 115 | + // to libuv, this will be |
| 116 | + // in the process_operation |
| 117 | + // crust fn |
| 118 | + let async_handle = rustrt::rust_uvtmp_uv_bind_op_cb( |
| 119 | + loop_handle, |
| 120 | + process_operation); |
| 121 | + |
| 122 | + // all state goes here |
| 123 | + let handles: map::map<[u8], uv_handle> = |
| 124 | + map::new_bytes_hash(); |
| 125 | + |
| 126 | + // the main loop that this task blocks on. |
| 127 | + // should have the same lifetime as the C libuv |
| 128 | + // event loop. |
| 129 | + let keep_going = true; |
| 130 | + while (keep_going) { |
| 131 | + alt comm::recv(rust_loop_port) { |
| 132 | + msg_run(end_chan) { |
| 133 | + // start the libuv event loop |
| 134 | + // we'll also do a uv_async_send with |
| 135 | + // the operation handle to have the |
| 136 | + // loop process any pending operations |
| 137 | + // once its up and running |
| 138 | + task::spawn_sched(1u) {|| |
| 139 | + // this call blocks |
| 140 | + rustrt::rust_uvtmp_uv_run(loop_handle); |
| 141 | + // when we're done, msg the |
| 142 | + // end chan |
| 143 | + comm::send(end_chan, true); |
| 144 | + }; |
| 145 | + } |
| 146 | + msg_run_in_bg { |
| 147 | + task::spawn_sched(1u) {|| |
| 148 | + // this call blocks |
| 149 | + rustrt::rust_uvtmp_uv_run(loop_handle); |
| 150 | + }; |
| 151 | + } |
| 152 | + msg_hw() { |
| 153 | + comm::send(operation_chan, op_hw); |
| 154 | + io::println("CALLING ASYNC_SEND FOR HW"); |
| 155 | + rustrt::rust_uvtmp_uv_async_send(async_handle); |
| 156 | + } |
| 157 | + uv_hw() { |
| 158 | + io::println("HELLO WORLD!!!"); |
| 159 | + } |
| 160 | + |
| 161 | + ////// STUBS /////// |
| 162 | + msg_loop_delete { |
| 163 | + // delete the event loop's c ptr |
| 164 | + // this will of course stop any |
| 165 | + // further processing |
| 166 | + } |
| 167 | + msg_async_init(id, callback) { |
| 168 | + // create a new async handle |
| 169 | + // with the id as the handle's |
| 170 | + // data and save the callback for |
| 171 | + // invocation on msg_async_send |
| 172 | + } |
| 173 | + msg_async_send(id) { |
| 174 | + // get the callback matching the |
| 175 | + // supplied id and invoke it |
| 176 | + } |
| 177 | + |
| 178 | + _ { fail "unknown form of uv_msg received"; } |
| 179 | + } |
| 180 | + } |
| 181 | + }; |
| 182 | + ret comm::recv(ret_recv_port); |
| 183 | + } |
| 184 | + |
| 185 | + fn run(loop: uv_loop) { |
| 186 | + let end_port = comm::port::<bool>(); |
| 187 | + let end_chan = comm::chan::<bool>(end_port); |
| 188 | + comm::send(loop, msg_run(end_chan)); |
| 189 | + comm::recv(end_port); |
| 190 | + } |
| 191 | + |
| 192 | + fn run_in_bg(loop: uv_loop) { |
| 193 | + comm::send(loop, msg_run_in_bg); |
| 194 | + } |
| 195 | + |
| 196 | + fn hw(loop: uv_loop) { |
| 197 | + comm::send(loop, msg_hw); |
| 198 | + } |
| 199 | + |
| 200 | + // internal functions |
| 201 | + |
| 202 | + // crust |
| 203 | + crust fn process_operation(data: *uv_loop_data) unsafe { |
| 204 | + io::println("IN PROCESS_OPERATION"); |
| 205 | + let op_port = (*data).operation_port; |
| 206 | + let loop_chan = (*data).rust_loop_chan; |
| 207 | + let op_pending = comm::peek(op_port); |
| 208 | + while(op_pending) { |
| 209 | + io::println("OPERATION PENDING!"); |
| 210 | + alt comm::recv(op_port) { |
| 211 | + op_hw() { |
| 212 | + io::println("GOT OP_HW IN CRUST"); |
| 213 | + comm::send(loop_chan, uv_hw); |
| 214 | + } |
| 215 | + _ { fail "unknown form of uv_operation received"; } |
| 216 | + } |
| 217 | + op_pending = comm::peek(op_port); |
| 218 | + } |
| 219 | + io::println("NO MORE OPERATIONS PENDING!"); |
| 220 | + } |
| 221 | +} |
| 222 | + |
| 223 | +#[test] |
| 224 | +fn uvtmp_uv_test_hello_world() { |
| 225 | + let test_loop = uv::loop_new(); |
| 226 | + uv::hw(test_loop); |
| 227 | + uv::run(test_loop); |
| 228 | +} |
| 229 | + |
| 230 | +// END OF UV2 |
| 231 | + |
34 | 232 | type thread = *ctypes::void;
|
35 | 233 |
|
36 | 234 | type connect_data = *ctypes::void;
|
|
0 commit comments