8. -》\kernel\proc.c
-
PUBLIC int do_ipc(reg_t r1, reg_t r2, reg_t r3)
-
{
-
struct proc *const caller_ptr = get_cpulocal_var(proc_ptr); /* get pointer to caller */
-
int call_nr = (int) r1;
-
-
assert(!RTS_ISSET(caller_ptr, RTS_SLOT_FREE));
-
-
/* bill kernel time to this process. */
-
kbill_ipc = caller_ptr;
-
-
/* If this process is subject to system call tracing, handle that first. */
-
if (caller_ptr->p_misc_flags & (MF_SC_TRACE | MF_SC_DEFER)) {
-
/* Are we tracing this process, and is it the first sys_call entry? */
-
if ((caller_ptr->p_misc_flags & (MF_SC_TRACE | MF_SC_DEFER)) ==
-
MF_SC_TRACE) {
-
/* We must notify the tracer before processing the actual
-
* system call. If we don't, the tracer could not obtain the
-
* input message. Postpone the entire system call.
-
*/
-
caller_ptr->p_misc_flags &= ~MF_SC_TRACE;
-
caller_ptr->p_misc_flags |= MF_SC_DEFER;
-
-
/* Signal the "enter system call" event. Block the process. */
-
cause_sig(proc_nr(caller_ptr), SIGTRAP);
-
-
/* Preserve the return register's value. */
-
return caller_ptr->p_reg.retreg;
-
}
-
-
/* If the MF_SC_DEFER flag is set, the syscall is now being resumed. */
-
caller_ptr->p_misc_flags &= ~MF_SC_DEFER;
-
-
assert (!(caller_ptr->p_misc_flags & MF_SC_ACTIVE));
-
-
/* Set a flag to allow reliable tracing of leaving the system call. */
-
caller_ptr->p_misc_flags |= MF_SC_ACTIVE;
-
}
-
-
if(caller_ptr->p_misc_flags & MF_DELIVERMSG) {
-
panic("sys_call: MF_DELIVERMSG on for %s / %d\n",
-
caller_ptr->p_name, caller_ptr->p_endpoint);
-
}
-
-
/* Now check if the call is known and try to perform the request. The only
-
* system calls that exist in MINIX are sending and receiving messages.
-
* - SENDREC: combines SEND and RECEIVE in a single system call
-
* - SEND: sender blocks until its message has been delivered
-
* - RECEIVE: receiver blocks until an acceptable message has arrived
-
* - NOTIFY: asynchronous call; deliver notification or mark pending
-
* - SENDA: list of asynchronous send requests
-
*/
-
switch(call_nr) {
-
case SENDREC:
-
case SEND:
-
case RECEIVE:
-
case NOTIFY:
-
case SENDNB:
-
{
-
/* Process accounting for scheduling */
-
caller_ptr->p_accounting.ipc_sync++;
-
-
return do_sync_ipc(caller_ptr, call_nr, (endpoint_t) r2,
-
(message *) r3);
-
}
-
case SENDA:
-
{
-
/*
-
* Get and check the size of the argument in bytes as it is a
-
* table
-
*/
-
size_t msg_size = (size_t) r2;
-
-
/* Process accounting for scheduling */
-
caller_ptr->p_accounting.ipc_async++;
-
-
/* Limit size to something reasonable. An arbitrary choice is 16
-
* times the number of process table entries.
-
*/
-
if (msg_size > 16*(NR_TASKS + NR_PROCS))
-
return EDOM;
-
return mini_senda(caller_ptr, (asynmsg_t *) r3, msg_size);
-
}
-
default:
-
return EBADCALL; /* illegal system call */
-
}
-
}
-
PRIVATE int do_sync_ipc(struct proc * caller_ptr, /* who made the call */
-
int call_nr, /* system call number and flags */
-
endpoint_t src_dst_e, /* src or dst of the call */
-
message *m_ptr) /* users pointer to a message */
-
{
-
int result; /* the system call's result */
-
int src_dst_p; /* Process slot number */
-
char *callname;
-
-
/* Check destination. RECEIVE is the only call that accepts ANY (in addition
-
* to a real endpoint). The other calls (SEND, SENDREC, and NOTIFY) require an
-
* endpoint to corresponds to a process. In addition, it is necessary to check
-
* whether a process is allowed to send to a given destination.
-
*/
-
assert(call_nr != SENDA);
-
-
/* Only allow non-negative call_nr values less than 32 */
-
if (call_nr < 0 || call_nr > IPCNO_HIGHEST || call_nr >= 32
-
|| !(callname = ipc_call_names[call_nr])) {
-
#if DEBUG_ENABLE_IPC_WARNINGS
-
printf("sys_call: trap %d not allowed, caller %d, src_dst %d\n",
-
call_nr, proc_nr(caller_ptr), src_dst_p);
-
#endif
-
return(ETRAPDENIED); /* trap denied by mask or kernel */
-
}
-
-
if (src_dst_e == ANY)
-
{
-
if (call_nr != RECEIVE)
-
{
-
#if 0
-
printf("sys_call: %s by %d with bad endpoint %d\n",
-
callname,
-
proc_nr(caller_ptr), src_dst_e);
-
#endif
-
return EINVAL;
-
}
-
src_dst_p = (int) src_dst_e;
-
}
-
else
-
{
-
/* Require a valid source and/or destination process. */
-
if(!isokendpt(src_dst_e, &src_dst_p)) {
-
#if 0
-
printf("sys_call: %s by %d with bad endpoint %d\n",
-
callname,
-
proc_nr(caller_ptr), src_dst_e);
-
#endif
-
return EDEADSRCDST;
-
}
-
-
/* If the call is to send to a process, i.e., for SEND, SENDNB,
-
* SENDREC or NOTIFY, verify that the caller is allowed to send to
-
* the given destination.
-
*/
-
if (call_nr != RECEIVE)
-
{
-
if (!may_send_to(caller_ptr, src_dst_p)) {
-
#if DEBUG_ENABLE_IPC_WARNINGS
-
printf(
-
"sys_call: ipc mask denied %s from %d to %d\n",
-
callname,
-
caller_ptr->p_endpoint, src_dst_e);
-
#endif
-
return(ECALLDENIED); /* call denied by ipc mask */
-
}
-
}
-
}
-
-
/* Check if the process has privileges for the requested call. Calls to the
-
* kernel may only be SENDREC, because tasks always reply and may not block
-
* if the caller doesn't do receive().
-
*/
-
if (!(priv(caller_ptr)->s_trap_mask & (1 << call_nr))) {
-
#if DEBUG_ENABLE_IPC_WARNINGS
-
printf("sys_call: %s not allowed, caller %d, src_dst %d\n",
-
callname, proc_nr(caller_ptr), src_dst_p);
-
#endif
-
return(ETRAPDENIED); /* trap denied by mask or kernel */
-
}
-
-
if (call_nr != SENDREC && call_nr != RECEIVE && iskerneln(src_dst_p)) {
-
#if DEBUG_ENABLE_IPC_WARNINGS
-
printf("sys_call: trap %s not allowed, caller %d, src_dst %d\n",
-
callname, proc_nr(caller_ptr), src_dst_e);
-
#endif
-
return(ETRAPDENIED); /* trap denied by mask or kernel */
-
}
-
-
switch(call_nr) {
-
case SENDREC:
-
/* A flag is set so that notifications cannot interrupt SENDREC. */
-
caller_ptr->p_misc_flags |= MF_REPLY_PEND;
-
/* fall through */
-
case SEND:
-
result = mini_send(caller_ptr, src_dst_e, m_ptr, 0);
-
if (call_nr == SEND || result != OK)
-
break; /* done, or SEND failed */
-
/* fall through for SENDREC */
-
case RECEIVE:
-
if (call_nr == RECEIVE) {
-
caller_ptr->p_misc_flags &= ~MF_REPLY_PEND;
-
IPC_STATUS_CLEAR(caller_ptr); /* clear IPC status code */
-
}
-
result = mini_receive(caller_ptr, src_dst_e, m_ptr, 0);
-
break;
-
case NOTIFY:
-
result = mini_notify(caller_ptr, src_dst_e);
-
break;
-
case SENDNB:
-
result = mini_send(caller_ptr, src_dst_e, m_ptr, NON_BLOCKING);
-
break;
-
default:
-
result = EBADCALL; /* illegal system call */
-
}
-
-
/* Now, return the result of the system call to the caller. */
-
return(result);
-
}
9. 由于call_nr==SENDREC,所以,首先调用mini_send函数(同样在源文件
\kernel\proc.c)
-
/*===========================================================================*
-
* mini_send *
-
*===========================================================================*/
-
PUBLIC int mini_send(
-
register struct proc *caller_ptr, /* who is trying to send a message? */
-
endpoint_t dst_e, /* to whom is message being sent? */
-
message *m_ptr, /* pointer to message buffer */
-
const int flags
-
)
-
{
-
/* Send a message from 'caller_ptr' to 'dst'. If 'dst' is blocked waiting
-
* for this message, copy the message to it and unblock 'dst'. If 'dst' is
-
* not waiting at all, or is waiting for another source, queue 'caller_ptr'.
-
*/
-
register struct proc *dst_ptr;
-
register struct proc **xpp;
-
int dst_p;
-
dst_p = _ENDPOINT_P(dst_e);
-
dst_ptr = proc_addr(dst_p);
-
-
if (RTS_ISSET(dst_ptr, RTS_NO_ENDPOINT))
-
{
-
return EDEADSRCDST;
-
}
-
-
/* Check if 'dst' is blocked waiting for this message. The destination's
-
* RTS_SENDING flag may be set when its SENDREC call blocked while sending.
-
*/
-
if (WILLRECEIVE(dst_ptr, caller_ptr->p_endpoint)) {
-
int call;
-
/* Destination is indeed waiting for this message. */
-
assert(!(dst_ptr->p_misc_flags & MF_DELIVERMSG));
-
-
if (!(flags & FROM_KERNEL)) {
-
if(copy_msg_from_user(caller_ptr, m_ptr, &dst_ptr->p_delivermsg))
-
return EFAULT;
-
} else {
-
dst_ptr->p_delivermsg = *m_ptr;
-
IPC_STATUS_ADD_FLAGS(dst_ptr, IPC_FLG_MSG_FROM_KERNEL);
-
}
-
-
dst_ptr->p_delivermsg.m_source = caller_ptr->p_endpoint;
-
dst_ptr->p_misc_flags |= MF_DELIVERMSG;
-
-
call = (caller_ptr->p_misc_flags & MF_REPLY_PEND ? SENDREC
-
: (flags & NON_BLOCKING ? SENDNB : SEND));
-
IPC_STATUS_ADD_CALL(dst_ptr, call);
-
-
if (dst_ptr->p_misc_flags & MF_REPLY_PEND)
-
dst_ptr->p_misc_flags &= ~MF_REPLY_PEND;
-
-
RTS_UNSET(dst_ptr, RTS_RECEIVING)
阅读(1268) | 评论(0) | 转发(0) |