Ejemplo n.º 1
0
BIF_RETTYPE erts_internal_port_command_3(BIF_ALIST_3)
{
    BIF_RETTYPE res;
    Port *prt;
    int flags = 0;
    Eterm ref;

    if (is_not_nil(BIF_ARG_3)) {
	Eterm l = BIF_ARG_3;
	while (is_list(l)) {
	    Eterm* cons = list_val(l);
	    Eterm car = CAR(cons);
	    if (car == am_force)
		flags |= ERTS_PORT_SIG_FLG_FORCE;
	    else if (car == am_nosuspend)
		flags |= ERTS_PORT_SIG_FLG_NOSUSPEND;
	    else
		BIF_RET(am_badarg);
	    l = CDR(cons);
	}
	if (!is_nil(l))
	    BIF_RET(am_badarg);
    }

    prt = sig_lookup_port(BIF_P, BIF_ARG_1);
    if (!prt)
	BIF_RET(am_badarg);

    if (flags & ERTS_PORT_SIG_FLG_FORCE) {
	if (!(prt->drv_ptr->flags & ERL_DRV_FLAG_SOFT_BUSY))
	    BIF_RET(am_notsup);
    }

#ifdef DEBUG
    ref = NIL;
#endif

    switch (erts_port_output(BIF_P, flags, prt, prt->common.id, BIF_ARG_2, &ref)) {
    case ERTS_PORT_OP_CALLER_EXIT:
    case ERTS_PORT_OP_BADARG:
    case ERTS_PORT_OP_DROPPED:
 	ERTS_BIF_PREP_RET(res, am_badarg);
	break;
    case ERTS_PORT_OP_BUSY:
	ASSERT(!(flags & ERTS_PORT_SIG_FLG_FORCE));
	if (flags & ERTS_PORT_SIG_FLG_NOSUSPEND)
	    ERTS_BIF_PREP_RET(res, am_false);
	else {
	    erts_suspend(BIF_P, ERTS_PROC_LOCK_MAIN, prt);
	    ERTS_BIF_PREP_YIELD3(res, bif_export[BIF_erts_internal_port_command_3],
				 BIF_P, BIF_ARG_1, BIF_ARG_2, BIF_ARG_3);
	}
	break;
    case ERTS_PORT_OP_BUSY_SCHEDULED:
	ASSERT(!(flags & ERTS_PORT_SIG_FLG_FORCE));
	/* Fall through... */
    case ERTS_PORT_OP_SCHEDULED:
	ASSERT(is_internal_ordinary_ref(ref));
	ERTS_BIF_PREP_RET(res, ref);
	break;
    case ERTS_PORT_OP_DONE:
	ERTS_BIF_PREP_RET(res, am_true);
	break;
    default:
	ERTS_INTERNAL_ERROR("Unexpected erts_port_output() result");
	break;
    }

    if (ERTS_PROC_IS_EXITING(BIF_P)) {
	KILL_CATCHES(BIF_P);	/* Must exit */
	ERTS_BIF_PREP_ERROR(res, BIF_P, EXC_ERROR);
    }

    return res;
}
Ejemplo n.º 2
0
static BIF_RETTYPE
do_port_command(Process *BIF_P, Eterm arg1, Eterm arg2, Eterm arg3,
		Uint32 flags)
{
    BIF_RETTYPE res;
    Port *p;

    /* Trace sched out before lock check wait */    
    if (IS_TRACED_FL(BIF_P, F_TRACE_SCHED_PROCS)) {
	trace_virtual_sched(BIF_P, am_out);
    }
    
    if (erts_system_profile_flags.runnable_procs && erts_system_profile_flags.exclusive) {
    	profile_runnable_proc(BIF_P, am_inactive);
    }

    p = id_or_name2port(BIF_P, arg1);
    if (!p) {
    	if (IS_TRACED_FL(BIF_P, F_TRACE_SCHED_PROCS)) {
	    trace_virtual_sched(BIF_P, am_in);
	}
    	if (erts_system_profile_flags.runnable_procs && erts_system_profile_flags.exclusive) {
    	    profile_runnable_proc(BIF_P, am_active);
    	}
	BIF_ERROR(BIF_P, BADARG);
    }
    
    /* Trace port in, id_or_name2port causes wait */

    if (IS_TRACED_FL(p, F_TRACE_SCHED_PORTS)) {
	trace_sched_ports_where(p, am_in, am_command);
    }
    if (erts_system_profile_flags.runnable_ports && !erts_port_is_scheduled(p)) {
    	profile_runnable_port(p, am_active);
    }

    ERTS_BIF_PREP_RET(res, am_true);

    if ((flags & ERTS_PORT_COMMAND_FLAG_FORCE)
	&& !(p->drv_ptr->flags & ERL_DRV_FLAG_SOFT_BUSY)) {
	ERTS_BIF_PREP_ERROR(res, BIF_P, EXC_NOTSUP);
    }
    else if (!(flags & ERTS_PORT_COMMAND_FLAG_FORCE)
	     && p->status & ERTS_PORT_SFLG_PORT_BUSY) {
	if (flags & ERTS_PORT_COMMAND_FLAG_NOSUSPEND) {
	    ERTS_BIF_PREP_RET(res, am_false);
	}
	else {
	    erts_suspend(BIF_P, ERTS_PROC_LOCK_MAIN, p);
	    if (erts_system_monitor_flags.busy_port) {
		monitor_generic(BIF_P, am_busy_port, p->id);
	    }
	    ERTS_BIF_PREP_YIELD3(res, bif_export[BIF_port_command_3], BIF_P,
				 arg1, arg2, arg3);
	}
    } else {
	int wres;
	erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN);
	ERTS_SMP_CHK_NO_PROC_LOCKS;
	wres = erts_write_to_port(BIF_P->id, p, arg2);
	erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);
	if (wres != 0) {
	    ERTS_BIF_PREP_ERROR(res, BIF_P, BADARG);
	}
    }
    
    if (IS_TRACED_FL(p, F_TRACE_SCHED_PORTS)) {
	trace_sched_ports_where(p, am_out, am_command);
    }
    if (erts_system_profile_flags.runnable_ports && !erts_port_is_scheduled(p)) {
    	profile_runnable_port(p, am_inactive);
    }

    erts_port_release(p);
    /* Trace sched in after port release */
    if (IS_TRACED_FL(BIF_P, F_TRACE_SCHED_PROCS)) {
	trace_virtual_sched(BIF_P, am_in);
    }
    if (erts_system_profile_flags.runnable_procs && erts_system_profile_flags.exclusive) {
    	profile_runnable_proc(BIF_P, am_active);
    }
    
    if (ERTS_PROC_IS_EXITING(BIF_P)) {
	KILL_CATCHES(BIF_P);	/* Must exit */
	ERTS_BIF_PREP_ERROR(res, BIF_P, EXC_ERROR);
    }
    return res;
}