This handles both syscall_send and syscall_sendreceive
(
context_ptr: *mut Context,
syscall_id: u64,
data1: u64,
data2: u64,
data3: u64)
| 368 | |
| 369 | /// This handles both syscall_send and syscall_sendreceive |
| 370 | fn sys_send( |
| 371 | context_ptr: *mut Context, |
| 372 | syscall_id: u64, |
| 373 | data1: u64, |
| 374 | data2: u64, |
| 375 | data3: u64) { |
| 376 | let handle = syscall_id >> 32; // High 32 bits are the handle |
| 377 | // Extract the current thread |
| 378 | if let Some(mut thread) = process::take_current_thread() { |
| 379 | let current_tid = thread.tid(); |
| 380 | thread.set_context(context_ptr); |
| 381 | |
| 382 | // Get the Rendezvous, create Message and call |
| 383 | if let Some(rdv) = thread.rendezvous(handle) { |
| 384 | // Check how many references this Rendezvous has. |
| 385 | if Arc::strong_count(&rdv) == 2 { |
| 386 | // Only this handle (rdv) and the one stored in the Thread/Process |
| 387 | // All other handles have been dropped -> Return error |
| 388 | thread.return_error(SYSCALL_ERROR_CLOSED); |
| 389 | process::set_current_thread(thread); |
| 390 | return; |
| 391 | } |
| 392 | |
| 393 | match Message::from_values(&mut thread, syscall_id, data1, data2, data3) { |
| 394 | Ok(message) => { |
| 395 | let (thread1, thread2) = match syscall_id & SYSCALL_MASK { |
| 396 | SYSCALL_SEND => rdv.write().send( |
| 397 | Some(thread), |
| 398 | message), |
| 399 | SYSCALL_SENDRECEIVE => rdv.write().send_receive( |
| 400 | thread, |
| 401 | message), |
| 402 | _ => panic!("Internal error") |
| 403 | }; |
| 404 | // thread1 should be started asap |
| 405 | // thread2 should be scheduled |
| 406 | |
| 407 | let mut returning = false; |
| 408 | for maybe_thread in [thread2, thread1] { |
| 409 | if let Some(t) = maybe_thread { |
| 410 | if t.tid() == current_tid { |
| 411 | // Same thread -> return |
| 412 | returning = true; |
| 413 | process::set_current_thread(t); |
| 414 | } else { |
| 415 | process::schedule_thread(t); |
| 416 | } |
| 417 | } |
| 418 | } |
| 419 | |
| 420 | if !returning { |
| 421 | // Original thread is waiting. |
| 422 | // Switch to a different thread |
| 423 | drop(rdv); // Not returning from launch_thread |
| 424 | let new_context_addr = process::schedule_next(context_ptr as usize); |
| 425 | interrupts::launch_thread(new_context_addr); |
| 426 | } |
| 427 | } |
no test coverage detected