static BIF_RETTYPE dirty_test(Process *c_p, Eterm type, Eterm arg1, Eterm arg2, UWord *I) { BIF_RETTYPE ret; if (am_scheduler == arg1) { ErtsSchedulerData *esdp; if (arg2 != am_type) goto badarg; esdp = erts_proc_sched_data(c_p); if (!esdp) goto scheduler_type_error; switch (esdp->type) { case ERTS_SCHED_NORMAL: ERTS_BIF_PREP_RET(ret, am_normal); break; case ERTS_SCHED_DIRTY_CPU: ERTS_BIF_PREP_RET(ret, am_dirty_cpu); break; case ERTS_SCHED_DIRTY_IO: ERTS_BIF_PREP_RET(ret, am_dirty_io); break; default: scheduler_type_error: ERTS_BIF_PREP_RET(ret, am_error); break; } } else if (am_error == arg1) { switch (arg2) { case am_notsup: ERTS_BIF_PREP_ERROR(ret, c_p, EXC_NOTSUP); break; case am_undef: ERTS_BIF_PREP_ERROR(ret, c_p, EXC_UNDEF); break; case am_badarith: ERTS_BIF_PREP_ERROR(ret, c_p, EXC_BADARITH); break; case am_noproc: ERTS_BIF_PREP_ERROR(ret, c_p, EXC_NOPROC); break; case am_system_limit: ERTS_BIF_PREP_ERROR(ret, c_p, SYSTEM_LIMIT); break; case am_badarg: default: goto badarg; } } else if (am_copy == arg1) { int i; Eterm res; for (res = NIL, i = 0; i < 1000; i++) { Eterm *hp, sz; Eterm cpy; /* We do not want this to be optimized, but rather the oposite... */ sz = size_object(arg2); hp = HAlloc(c_p, sz); cpy = copy_struct(arg2, sz, &hp, &c_p->off_heap); hp = HAlloc(c_p, 2); res = CONS(hp, cpy, res); } ERTS_BIF_PREP_RET(ret, res); } else if (am_send == arg1) { dirty_send_message(c_p, arg2, am_ok); ERTS_BIF_PREP_RET(ret, am_ok); } else if (ERTS_IS_ATOM_STR("wait", arg1)) { if (!ms_wait(c_p, arg2, type == am_dirty_cpu)) goto badarg; ERTS_BIF_PREP_RET(ret, am_ok); } else if (ERTS_IS_ATOM_STR("reschedule", arg1)) { /* * Reschedule operation after decrement of two until we reach * zero. Switch between dirty scheduler types when 'n' is * evenly divided by 4. If the initial value wasn't evenly * dividable by 2, throw badarg exception. */ Eterm next_type; Sint n; if (!term_to_Sint(arg2, &n) || n < 0) goto badarg; if (n == 0) ERTS_BIF_PREP_RET(ret, am_ok); else { Eterm argv[3]; Eterm eint = erts_make_integer((Uint) (n - 2), c_p); if (n % 4 != 0) next_type = type; else { switch (type) { case am_dirty_cpu: next_type = am_dirty_io; break; case am_dirty_io: next_type = am_normal; break; case am_normal: next_type = am_dirty_cpu; break; default: goto badarg; } } switch (next_type) { case am_dirty_io: argv[0] = arg1; argv[1] = eint; ret = erts_schedule_bif(c_p, argv, I, erts_debug_dirty_io_2, ERTS_SCHED_DIRTY_IO, am_erts_debug, am_dirty_io, 2); break; case am_dirty_cpu: argv[0] = arg1; argv[1] = eint; ret = erts_schedule_bif(c_p, argv, I, erts_debug_dirty_cpu_2, ERTS_SCHED_DIRTY_CPU, am_erts_debug, am_dirty_cpu, 2); break; case am_normal: argv[0] = am_normal; argv[1] = arg1; argv[2] = eint; ret = erts_schedule_bif(c_p, argv, I, erts_debug_dirty_3, ERTS_SCHED_NORMAL, am_erts_debug, am_dirty, 3); break; default: goto badarg; } } } else if (ERTS_IS_ATOM_STR("ready_wait6_done", arg1)) { ERTS_DECL_AM(ready); ERTS_DECL_AM(done); dirty_send_message(c_p, arg2, AM_ready); ms_wait(c_p, make_small(6000), 0); dirty_send_message(c_p, arg2, AM_done); ERTS_BIF_PREP_RET(ret, am_ok); } else if (ERTS_IS_ATOM_STR("alive_waitexiting", arg1)) { Process *real_c_p = erts_proc_shadow2real(c_p); Eterm *hp, *hp2; Uint sz; int i; ErtsSchedulerData *esdp = erts_proc_sched_data(c_p); int dirty_io = esdp->type == ERTS_SCHED_DIRTY_IO; if (ERTS_PROC_IS_EXITING(real_c_p)) goto badarg; dirty_send_message(c_p, arg2, am_alive); /* Wait until dead */ while (!ERTS_PROC_IS_EXITING(real_c_p)) { if (dirty_io) ms_wait(c_p, make_small(100), 0); else erts_thr_yield(); } ms_wait(c_p, make_small(1000), 0); /* Should still be able to allocate memory */ hp = HAlloc(c_p, 3); /* Likely on heap */ sz = 10000; hp2 = HAlloc(c_p, sz); /* Likely in heap fragment */ *hp2 = make_pos_bignum_header(sz); for (i = 1; i < sz; i++) hp2[i] = (Eterm) 4711; ERTS_BIF_PREP_RET(ret, TUPLE2(hp, am_ok, make_big(hp2))); } else { badarg: ERTS_BIF_PREP_ERROR(ret, c_p, BADARG); } return ret; }
/* decode_packet(Type,Bin,Options) Returns: {ok, PacketBodyBin, RestBin} {more, PacketSz | undefined} {error, invalid} */ BIF_RETTYPE decode_packet_3(BIF_ALIST_3) { unsigned max_plen = 0; /* Packet max length, 0=no limit */ unsigned trunc_len = 0; /* Truncate lines if longer, 0=no limit */ int http_state = 0; /* 0=request/response 1=header */ int packet_sz; /*-------Binaries involved: ------------------*/ byte* bin_ptr; /*| orig: original binary */ byte bin_bitsz; /*| bin: BIF_ARG_2, may be sub-binary of orig */ /*| packet: prefix of bin */ char* body_ptr; /*| body: part of packet to return */ int body_sz; /*| rest: bin without packet */ struct packet_callback_args pca; enum PacketParseType type; Eterm* hp; Eterm* hend; ErlSubBin* rest; Eterm res; Eterm options; int code; char delimiter = '\n'; if (!is_binary(BIF_ARG_2) || (!is_list(BIF_ARG_3) && !is_nil(BIF_ARG_3))) { BIF_ERROR(BIF_P, BADARG); } switch (BIF_ARG_1) { case make_small(0): case am_raw: type = TCP_PB_RAW; break; case make_small(1): type = TCP_PB_1; break; case make_small(2): type = TCP_PB_2; break; case make_small(4): type = TCP_PB_4; break; case am_asn1: type = TCP_PB_ASN1; break; case am_sunrm: type = TCP_PB_RM; break; case am_cdr: type = TCP_PB_CDR; break; case am_fcgi: type = TCP_PB_FCGI; break; case am_line: type = TCP_PB_LINE_LF; break; case am_tpkt: type = TCP_PB_TPKT; break; case am_http: type = TCP_PB_HTTP; break; case am_httph: type = TCP_PB_HTTPH; break; case am_http_bin: type = TCP_PB_HTTP_BIN; break; case am_httph_bin: type = TCP_PB_HTTPH_BIN; break; case am_ssl_tls: type = TCP_PB_SSL_TLS; break; default: BIF_ERROR(BIF_P, BADARG); } options = BIF_ARG_3; while (!is_nil(options)) { Eterm* cons = list_val(options); if (is_tuple(CAR(cons))) { Eterm* tpl = tuple_val(CAR(cons)); Uint val; if (tpl[0] == make_arityval(2) && term_to_Uint(tpl[2],&val) && val <= UINT_MAX) { switch (tpl[1]) { case am_packet_size: max_plen = val; goto next_option; case am_line_length: trunc_len = val; goto next_option; case am_line_delimiter: if (type == TCP_PB_LINE_LF && val <= 255) { delimiter = (char)val; goto next_option; } } } } BIF_ERROR(BIF_P, BADARG); next_option: options = CDR(cons); } pca.bin_sz = binary_size(BIF_ARG_2); ERTS_GET_BINARY_BYTES(BIF_ARG_2, bin_ptr, pca.bin_bitoffs, bin_bitsz); if (pca.bin_bitoffs != 0) { pca.aligned_ptr = erts_alloc(ERTS_ALC_T_TMP, pca.bin_sz); erts_copy_bits(bin_ptr, pca.bin_bitoffs, 1, pca.aligned_ptr, 0, 1, pca.bin_sz*8); } else { pca.aligned_ptr = bin_ptr; } packet_sz = packet_get_length(type, (char*)pca.aligned_ptr, pca.bin_sz, max_plen, trunc_len, delimiter, &http_state); if (!(packet_sz > 0 && packet_sz <= pca.bin_sz)) { if (packet_sz < 0) { goto error; } else { /* not enough data */ Eterm plen = (packet_sz==0) ? am_undefined : erts_make_integer(packet_sz, BIF_P); Eterm* hp = HAlloc(BIF_P,3); res = TUPLE2(hp, am_more, plen); goto done; } } /* We got a whole packet */ body_ptr = (char*) pca.aligned_ptr; body_sz = packet_sz; packet_get_body(type, (const char**) &body_ptr, &body_sz); ERTS_GET_REAL_BIN(BIF_ARG_2, pca.orig, pca.bin_offs, pca.bin_bitoffs, bin_bitsz); pca.p = BIF_P; pca.res = THE_NON_VALUE; pca.string_as_bin = (type == TCP_PB_HTTP_BIN || type == TCP_PB_HTTPH_BIN); code = packet_parse(type, (char*)pca.aligned_ptr, packet_sz, &http_state, &packet_callbacks_erl, &pca); if (code == 0) { /* no special packet parsing, make plain binary */ ErlSubBin* body; Uint hsz = 2*ERL_SUB_BIN_SIZE + 4; hp = HAlloc(BIF_P, hsz); hend = hp + hsz; body = (ErlSubBin *) hp; body->thing_word = HEADER_SUB_BIN; body->size = body_sz; body->offs = pca.bin_offs + (body_ptr - (char*)pca.aligned_ptr); body->orig = pca.orig; body->bitoffs = pca.bin_bitoffs; body->bitsize = 0; body->is_writable = 0; hp += ERL_SUB_BIN_SIZE; pca.res = make_binary(body); } else if (code > 0) { Uint hsz = ERL_SUB_BIN_SIZE + 4; ASSERT(pca.res != THE_NON_VALUE); hp = HAlloc(BIF_P, hsz); hend = hp + hsz; } else { error: hp = HAlloc(BIF_P,3); res = TUPLE2(hp, am_error, am_invalid); goto done; } rest = (ErlSubBin *) hp; rest->thing_word = HEADER_SUB_BIN; rest->size = pca.bin_sz - packet_sz; rest->offs = pca.bin_offs + packet_sz; rest->orig = pca.orig; rest->bitoffs = pca.bin_bitoffs; rest->bitsize = bin_bitsz; /* The extra bits go into the rest. */ rest->is_writable = 0; hp += ERL_SUB_BIN_SIZE; res = TUPLE3(hp, am_ok, pca.res, make_binary(rest)); hp += 4; ASSERT(hp==hend); (void)hend; done: if (pca.aligned_ptr != bin_ptr) { erts_free(ERTS_ALC_T_TMP, pca.aligned_ptr); } BIF_RET(res); }