sc_iterator3* sc_iterator3_new(const sc_memory_context *ctx, sc_iterator3_type type, sc_iterator_param p1, sc_iterator_param p2, sc_iterator_param p3) { sc_access_levels levels; // check types if (type > sc_iterator3_f_a_f) return (sc_iterator3*)0; // check params with template switch (type) { case sc_iterator3_f_a_a: if (p1.is_type || !p2.is_type || !p3.is_type || sc_storage_get_access_levels(ctx, p1.addr, &levels) != SC_RESULT_OK || !sc_access_lvl_check_read(ctx->access_levels, levels) || _sc_iterator_ref_element(ctx, p1.addr) != SC_TRUE ) { return (sc_iterator3*)0; } break; case sc_iterator3_a_a_f: if (!p1.is_type || !p2.is_type || p3.is_type || sc_storage_get_access_levels(ctx, p3.addr, &levels) != SC_RESULT_OK || !sc_access_lvl_check_read(ctx->access_levels, levels) || _sc_iterator_ref_element(ctx, p3.addr) != SC_TRUE ) { return (sc_iterator3*)0; } break; case sc_iterator3_f_a_f: if (p1.is_type || !p2.is_type || p3.is_type || sc_storage_get_access_levels(ctx, p1.addr, &levels) != SC_RESULT_OK || !sc_access_lvl_check_read(ctx->access_levels, levels) || sc_storage_get_access_levels(ctx, p3.addr, &levels) != SC_RESULT_OK || !sc_access_lvl_check_read(ctx->access_levels, levels) || _sc_iterator_ref_element(ctx, p1.addr) != SC_TRUE || _sc_iterator_ref_element(ctx, p3.addr) != SC_TRUE ) { return (sc_iterator3*)0; } break; }; sc_iterator3 *it = g_new0(sc_iterator3, 1); it->params[0] = p1; it->params[1] = p2; it->params[2] = p3; it->type = type; it->ctx = ctx; it->finished = SC_FALSE; return it; }
sc_iterator3* sc_iterator3_f_a_f_new(const sc_memory_context *ctx, sc_addr el_beg, sc_type arc_type, sc_addr el_end) { sc_access_levels levels; if (sc_storage_get_access_levels(ctx, el_beg, &levels) != SC_RESULT_OK || !sc_access_lvl_check_read(ctx->access_levels, levels) || sc_storage_get_access_levels(ctx, el_end, &levels) != SC_RESULT_OK || !sc_access_lvl_check_read(ctx->access_levels, levels)) { return 0; } sc_iterator_param p1, p2, p3; p1.is_type = SC_FALSE; p1.addr = el_beg; p2.is_type = SC_TRUE; p2.type = arc_type; p3.is_type = SC_FALSE; p3.addr = el_end; return sc_iterator3_new(ctx, sc_iterator3_f_a_f, p1, p2, p3); }
sc_iterator3* sc_iterator3_f_a_a_new(const sc_memory_context *ctx, sc_addr el, sc_type arc_type, sc_type end_type) { sc_access_levels levels; sc_iterator_param p1, p2, p3; if (sc_storage_get_access_levels(ctx, el, &levels) != SC_RESULT_OK || !sc_access_lvl_check_read(ctx->access_levels, levels)) return 0; p1.is_type = SC_FALSE; p1.addr = el; p2.is_type = SC_TRUE; p2.type = arc_type; p3.is_type = SC_TRUE; p3.type = end_type; return sc_iterator3_new(ctx, sc_iterator3_f_a_a, p1, p2, p3); }
sc_bool _sc_iterator3_a_a_f_next(sc_iterator3 *it) { sc_addr arc_addr; SC_ADDR_MAKE_EMPTY(arc_addr) it->results[2] = it->params[2].addr; // try to find first input arc if (SC_ADDR_IS_EMPTY(it->results[1])) { sc_element *el = 0; STORAGE_CHECK_CALL(sc_storage_element_lock(it->ctx, it->params[2].addr, &el)); g_assert(el != null_ptr); arc_addr = el->first_in_arc; STORAGE_CHECK_CALL(sc_storage_element_unlock(it->ctx, it->params[2].addr)); }else { sc_element *el = 0; STORAGE_CHECK_CALL(sc_storage_element_lock(it->ctx, it->results[1], &el)); g_assert(el != null_ptr); arc_addr = el->arc.next_in_arc; _sc_iterator_unref_element(it->ctx, el, it->results[1]); STORAGE_CHECK_CALL(sc_storage_element_unlock(it->ctx, it->results[1])); } // trying to find input arc, that created before iterator, and wasn't deleted while (SC_ADDR_IS_NOT_EMPTY(arc_addr)) { sc_element *el = 0; while (el == null_ptr) STORAGE_CHECK_CALL(sc_storage_element_lock_try(it->ctx, arc_addr, s_max_iterator_lock_attempts, &el)); if (!sc_element_itref_add(sc_storage_get_element_meta(it->ctx, arc_addr))) { STORAGE_CHECK_CALL(sc_storage_element_unlock(it->ctx, arc_addr)); continue; } sc_addr next_in_arc = el->arc.next_in_arc; if (sc_element_is_request_deletion(el) == SC_FALSE) { sc_type arc_type = el->flags.type; sc_addr arc_begin = el->arc.begin; sc_access_levels arc_access = el->flags.access_levels; sc_access_levels begin_access; if (sc_storage_get_access_levels(it->ctx, arc_begin, &begin_access) != SC_RESULT_OK) begin_access = sc_access_lvl_make_max; STORAGE_CHECK_CALL(sc_storage_element_unlock(it->ctx, arc_addr)); sc_type el_type = 0; sc_storage_get_element_type(it->ctx, arc_begin, &el_type); if (sc_iterator_compare_type(arc_type, it->params[1].type) && sc_iterator_compare_type(el_type, it->params[0].type) && sc_access_lvl_check_read(it->ctx->access_levels, arc_access) && sc_access_lvl_check_read(it->ctx->access_levels, begin_access) ) { // store found result it->results[1] = arc_addr; it->results[0] = arc_begin; return SC_TRUE; } } else { _sc_iterator_unref_element(it->ctx, el, arc_addr); STORAGE_CHECK_CALL(sc_storage_element_unlock(it->ctx, arc_addr)); } // go to next arc arc_addr = next_in_arc; } it->finished = SC_TRUE; return SC_FALSE; }
sc_bool _sc_iterator3_f_a_a_next(sc_iterator3 *it) { sc_addr arc_addr; SC_ADDR_MAKE_EMPTY(arc_addr); if (it->finished == SC_TRUE) return SC_FALSE; it->results[0] = it->params[0].addr; // try to find first output arc if (SC_ADDR_IS_EMPTY(it->results[1])) { sc_element *el = 0; STORAGE_CHECK_CALL(sc_storage_element_lock(it->ctx, it->params[0].addr, &el)); g_assert(el != null_ptr); arc_addr = el->first_out_arc; STORAGE_CHECK_CALL(sc_storage_element_unlock(it->ctx, it->params[0].addr)); }else { sc_element *el = 0; STORAGE_CHECK_CALL(sc_storage_element_lock(it->ctx, it->results[1], &el)); g_assert(el != null_ptr); arc_addr = el->arc.next_out_arc; _sc_iterator_unref_element(it->ctx, el, it->results[1]); STORAGE_CHECK_CALL(sc_storage_element_unlock(it->ctx, it->results[1])); } // iterate throught output arcs while (SC_ADDR_IS_NOT_EMPTY(arc_addr)) { sc_element *el = 0; // lock required elements to prevent deadlock with deletion while (el == null_ptr) STORAGE_CHECK_CALL(sc_storage_element_lock_try(it->ctx, arc_addr, s_max_iterator_lock_attempts, &el)); if (!sc_element_itref_add(sc_storage_get_element_meta(it->ctx, arc_addr))) { STORAGE_CHECK_CALL(sc_storage_element_unlock(it->ctx, arc_addr)); continue; } sc_addr next_out_arc = el->arc.next_out_arc; if (sc_element_is_request_deletion(el) == SC_FALSE) { sc_addr arc_end = el->arc.end; sc_type arc_type = el->flags.type; sc_access_levels arc_access = el->flags.access_levels; sc_access_levels end_access; if (sc_storage_get_access_levels(it->ctx, arc_end, &end_access) != SC_RESULT_OK) end_access = sc_access_lvl_make_max; STORAGE_CHECK_CALL(sc_storage_element_unlock(it->ctx, arc_addr)); sc_type el_type; sc_storage_get_element_type(it->ctx, arc_end, &el_type); if (sc_iterator_compare_type(arc_type, it->params[1].type) && sc_iterator_compare_type(el_type, it->params[2].type) && sc_access_lvl_check_read(it->ctx->access_levels, arc_access) && sc_access_lvl_check_read(it->ctx->access_levels, end_access) ) { // store found result it->results[1] = arc_addr; it->results[2] = arc_end; return SC_TRUE; } } else { _sc_iterator_unref_element(it->ctx, el, arc_addr); STORAGE_CHECK_CALL(sc_storage_element_unlock(it->ctx, arc_addr)); } // go to next arc arc_addr = next_out_arc; } it->finished = SC_TRUE; return SC_FALSE; }
sc_result sc_memory_get_element_access_levels(sc_memory_context const * ctx, sc_addr addr, sc_access_levels * result) { return sc_storage_get_access_levels(ctx, addr, result); }