コード例 #1
0
ファイル: inproc_transport.c プロジェクト: mdsteele/grpc
/*******************************************************************************
 * Main inproc transport functions
 */
static void inproc_transports_create(grpc_exec_ctx *exec_ctx,
                                     grpc_transport **server_transport,
                                     const grpc_channel_args *server_args,
                                     grpc_transport **client_transport,
                                     const grpc_channel_args *client_args) {
  INPROC_LOG(GPR_DEBUG, "inproc_transports_create");
  inproc_transport *st = gpr_zalloc(sizeof(*st));
  inproc_transport *ct = gpr_zalloc(sizeof(*ct));
  // Share one lock between both sides since both sides get affected
  st->mu = ct->mu = gpr_malloc(sizeof(*st->mu));
  gpr_mu_init(&st->mu->mu);
  gpr_ref_init(&st->mu->refs, 2);
  st->base.vtable = &inproc_vtable;
  ct->base.vtable = &inproc_vtable;
  // Start each side of transport with 2 refs since they each have a ref
  // to the other
  gpr_ref_init(&st->refs, 2);
  gpr_ref_init(&ct->refs, 2);
  st->is_client = false;
  ct->is_client = true;
  grpc_connectivity_state_init(&st->connectivity, GRPC_CHANNEL_READY,
                               "inproc_server");
  grpc_connectivity_state_init(&ct->connectivity, GRPC_CHANNEL_READY,
                               "inproc_client");
  st->other_side = ct;
  ct->other_side = st;
  st->stream_list = NULL;
  ct->stream_list = NULL;
  *server_transport = (grpc_transport *)st;
  *client_transport = (grpc_transport *)ct;
}
コード例 #2
0
ファイル: round_robin.c プロジェクト: CoderRookie/grpc
static grpc_lb_policy *create_round_robin(grpc_lb_policy_factory *factory,
                                          grpc_lb_policy_args *args) {
  size_t i;
  round_robin_lb_policy *p = gpr_malloc(sizeof(*p));
  GPR_ASSERT(args->num_subchannels > 0);
  memset(p, 0, sizeof(*p));
  grpc_lb_policy_init(&p->base, &round_robin_lb_policy_vtable);
  p->num_subchannels = args->num_subchannels;
  p->subchannels = gpr_malloc(sizeof(*p->subchannels) * p->num_subchannels);
  memset(p->subchannels, 0, sizeof(*p->subchannels) * p->num_subchannels);
  grpc_connectivity_state_init(&p->state_tracker, GRPC_CHANNEL_IDLE,
                               "round_robin");

  gpr_mu_init(&p->mu);
  for (i = 0; i < args->num_subchannels; i++) {
    subchannel_data *sd = gpr_malloc(sizeof(*sd));
    memset(sd, 0, sizeof(*sd));
    p->subchannels[i] = sd;
    sd->policy = p;
    sd->index = i;
    sd->subchannel = args->subchannels[i];
    grpc_closure_init(&sd->connectivity_changed_closure,
                      rr_connectivity_changed, sd);
  }

  /* The (dummy node) root of the ready list */
  p->ready_list.subchannel = NULL;
  p->ready_list.prev = NULL;
  p->ready_list.next = NULL;
  p->ready_list_last_pick = &p->ready_list;

  return &p->base;
}
コード例 #3
0
static void test_check(void) {
  grpc_connectivity_state_tracker tracker;
  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
  gpr_log(GPR_DEBUG, "test_check");
  grpc_connectivity_state_init(&tracker, GRPC_CHANNEL_IDLE, "xxx");
  GPR_ASSERT(grpc_connectivity_state_check(&tracker) == GRPC_CHANNEL_IDLE);
  grpc_connectivity_state_destroy(&exec_ctx, &tracker);
  grpc_exec_ctx_finish(&exec_ctx);
}
コード例 #4
0
ファイル: round_robin.c プロジェクト: 201528013359030/grpc
static grpc_lb_policy *create_round_robin(grpc_exec_ctx *exec_ctx,
                                          grpc_lb_policy_factory *factory,
                                          grpc_lb_policy_args *args) {
  GPR_ASSERT(args->addresses != NULL);
  GPR_ASSERT(args->client_channel_factory != NULL);

  round_robin_lb_policy *p = gpr_malloc(sizeof(*p));
  memset(p, 0, sizeof(*p));

  p->subchannels =
      gpr_malloc(sizeof(*p->subchannels) * args->addresses->naddrs);
  memset(p->subchannels, 0, sizeof(*p->subchannels) * args->addresses->naddrs);

  grpc_subchannel_args sc_args;
  size_t subchannel_idx = 0;
  for (size_t i = 0; i < args->addresses->naddrs; i++) {
    memset(&sc_args, 0, sizeof(grpc_subchannel_args));
    sc_args.addr = (struct sockaddr *)(args->addresses->addrs[i].addr);
    sc_args.addr_len = (size_t)args->addresses->addrs[i].len;

    grpc_subchannel *subchannel = grpc_client_channel_factory_create_subchannel(
        exec_ctx, args->client_channel_factory, &sc_args);

    if (subchannel != NULL) {
      subchannel_data *sd = gpr_malloc(sizeof(*sd));
      memset(sd, 0, sizeof(*sd));
      p->subchannels[subchannel_idx] = sd;
      sd->policy = p;
      sd->index = subchannel_idx;
      sd->subchannel = subchannel;
      ++subchannel_idx;
      grpc_closure_init(&sd->connectivity_changed_closure,
                        rr_connectivity_changed, sd);
    }
  }
  if (subchannel_idx == 0) {
    gpr_free(p->subchannels);
    gpr_free(p);
    return NULL;
  }
  p->num_subchannels = subchannel_idx;

  /* The (dummy node) root of the ready list */
  p->ready_list.subchannel = NULL;
  p->ready_list.prev = NULL;
  p->ready_list.next = NULL;
  p->ready_list_last_pick = &p->ready_list;

  grpc_lb_policy_init(&p->base, &round_robin_lb_policy_vtable);
  grpc_connectivity_state_init(&p->state_tracker, GRPC_CHANNEL_IDLE,
                               "round_robin");
  gpr_mu_init(&p->mu);
  return &p->base;
}
コード例 #5
0
ファイル: client_uchannel.c プロジェクト: wirlfly/grpc
/* Constructor for channel_data */
static void cuc_init_channel_elem(grpc_exec_ctx *exec_ctx,
                                  grpc_channel_element *elem,
                                  grpc_channel_element_args *args) {
  channel_data *chand = elem->channel_data;
  memset(chand, 0, sizeof(*chand));
  grpc_closure_init(&chand->connectivity_cb, monitor_subchannel, chand);
  GPR_ASSERT(args->is_last);
  GPR_ASSERT(elem->filter == &grpc_client_uchannel_filter);
  chand->owning_stack = args->channel_stack;
  grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE,
                               "client_uchannel");
  gpr_mu_init(&chand->mu_state);
}
コード例 #6
0
ファイル: pick_first.c プロジェクト: JoeWoo/grpc
static grpc_lb_policy *create_pick_first(grpc_lb_policy_factory *factory,
                                         grpc_lb_policy_args *args) {
  pick_first_lb_policy *p = gpr_malloc(sizeof(*p));
  GPR_ASSERT(args->num_subchannels > 0);
  memset(p, 0, sizeof(*p));
  grpc_lb_policy_init(&p->base, &pick_first_lb_policy_vtable);
  p->subchannels = gpr_malloc(sizeof(grpc_subchannel *) * args->num_subchannels);
  p->num_subchannels = args->num_subchannels;
  grpc_connectivity_state_init(&p->state_tracker, GRPC_CHANNEL_IDLE,
                               "pick_first");
  memcpy(p->subchannels, args->subchannels,
         sizeof(grpc_subchannel *) * args->num_subchannels);
  grpc_iomgr_closure_init(&p->connectivity_changed, pf_connectivity_changed, p);
  gpr_mu_init(&p->mu);
  return &p->base;
}
コード例 #7
0
ファイル: client_channel.c プロジェクト: autodesk-forks/grpc
/* Constructor for channel_data */
static void init_channel_elem(grpc_exec_ctx *exec_ctx,
                              grpc_channel_element *elem,
                              grpc_channel_element_args *args) {
  channel_data *chand = elem->channel_data;

  memset(chand, 0, sizeof(*chand));

  GPR_ASSERT(args->is_last);
  GPR_ASSERT(elem->filter == &grpc_client_channel_filter);

  gpr_mu_init(&chand->mu_config);
  grpc_closure_init(&chand->on_config_changed, cc_on_config_changed, chand);
  chand->owning_stack = args->channel_stack;

  grpc_connectivity_state_init(&chand->state_tracker, GRPC_CHANNEL_IDLE,
                               "client_channel");
  chand->interested_parties = grpc_pollset_set_create();
}
コード例 #8
0
static void test_subscribe_with_failure_then_destroy(void) {
  grpc_connectivity_state_tracker tracker;
  grpc_closure *closure = grpc_closure_create(must_fail, THE_ARG);
  grpc_connectivity_state state = GRPC_CHANNEL_FATAL_FAILURE;
  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
  gpr_log(GPR_DEBUG, "test_subscribe_with_failure_then_destroy");
  g_counter = 0;
  grpc_connectivity_state_init(&tracker, GRPC_CHANNEL_FATAL_FAILURE, "xxx");
  GPR_ASSERT(0 == grpc_connectivity_state_notify_on_state_change(
                      &exec_ctx, &tracker, &state, closure));
  grpc_exec_ctx_flush(&exec_ctx);
  GPR_ASSERT(state == GRPC_CHANNEL_FATAL_FAILURE);
  GPR_ASSERT(g_counter == 0);
  grpc_connectivity_state_destroy(&exec_ctx, &tracker);
  grpc_exec_ctx_finish(&exec_ctx);
  GPR_ASSERT(state == GRPC_CHANNEL_FATAL_FAILURE);
  GPR_ASSERT(g_counter == 1);
}
コード例 #9
0
ファイル: round_robin.c プロジェクト: bjori/grpc
static grpc_lb_policy *create_round_robin(grpc_lb_policy_factory *factory,
                                          grpc_lb_policy_args *args) {
  size_t i;
  round_robin_lb_policy *p = gpr_malloc(sizeof(*p));
  GPR_ASSERT(args->num_subchannels > 0);
  memset(p, 0, sizeof(*p));
  grpc_lb_policy_init(&p->base, &round_robin_lb_policy_vtable);
  p->subchannels =
      gpr_malloc(sizeof(grpc_subchannel *) * args->num_subchannels);
  p->num_subchannels = args->num_subchannels;
  grpc_connectivity_state_init(&p->state_tracker, GRPC_CHANNEL_IDLE,
                               "round_robin");
  memcpy(p->subchannels, args->subchannels,
         sizeof(grpc_subchannel *) * args->num_subchannels);

  gpr_mu_init(&p->mu);
  p->connectivity_changed_cbs =
      gpr_malloc(sizeof(grpc_closure) * args->num_subchannels);
  p->subchannel_connectivity =
      gpr_malloc(sizeof(grpc_connectivity_state) * args->num_subchannels);

  p->cb_args =
      gpr_malloc(sizeof(connectivity_changed_cb_arg) * args->num_subchannels);
  for (i = 0; i < args->num_subchannels; i++) {
    p->cb_args[i].subchannel_idx = i;
    p->cb_args[i].p = p;
    grpc_closure_init(&p->connectivity_changed_cbs[i], rr_connectivity_changed,
                      &p->cb_args[i]);
  }

  /* The (dummy node) root of the ready list */
  p->ready_list.subchannel = NULL;
  p->ready_list.prev = NULL;
  p->ready_list.next = NULL;
  p->ready_list_last_pick = &p->ready_list;

  p->subchannel_index_to_readylist_node =
      gpr_malloc(sizeof(grpc_subchannel *) * args->num_subchannels);
  memset(p->subchannel_index_to_readylist_node, 0,
         sizeof(grpc_subchannel *) * args->num_subchannels);
  return &p->base;
}
コード例 #10
0
ファイル: chttp2_transport.c プロジェクト: rootusr/grpc
static void init_transport(grpc_chttp2_transport *t,
                           const grpc_channel_args *channel_args,
                           grpc_endpoint *ep, grpc_mdctx *mdctx,
                           int is_client) {
  size_t i;
  int j;

  GPR_ASSERT(strlen(GRPC_CHTTP2_CLIENT_CONNECT_STRING) ==
             GRPC_CHTTP2_CLIENT_CONNECT_STRLEN);

  memset(t, 0, sizeof(*t));

  t->base.vtable = &vtable;
  t->ep = ep;
  /* one ref is for destroy, the other for when ep becomes NULL */
  gpr_ref_init(&t->refs, 2);
  gpr_mu_init(&t->mu);
  grpc_mdctx_ref(mdctx);
  t->peer_string = grpc_endpoint_get_peer(ep);
  t->metadata_context = mdctx;
  t->endpoint_reading = 1;
  t->global.next_stream_id = is_client ? 1 : 2;
  t->global.is_client = is_client;
  t->global.outgoing_window = DEFAULT_WINDOW;
  t->global.incoming_window = DEFAULT_WINDOW;
  t->global.connection_window_target = DEFAULT_CONNECTION_WINDOW_TARGET;
  t->global.ping_counter = 1;
  t->global.pings.next = t->global.pings.prev = &t->global.pings;
  t->parsing.is_client = is_client;
  t->parsing.str_grpc_timeout =
      grpc_mdstr_from_string(t->metadata_context, "grpc-timeout", 0);
  t->parsing.deframe_state =
      is_client ? GRPC_DTS_FH_0 : GRPC_DTS_CLIENT_PREFIX_0;
  t->writing.is_client = is_client;
  grpc_connectivity_state_init(&t->channel_callback.state_tracker,
                               GRPC_CHANNEL_READY, "transport");

  gpr_slice_buffer_init(&t->global.qbuf);

  gpr_slice_buffer_init(&t->writing.outbuf);
  grpc_chttp2_hpack_compressor_init(&t->writing.hpack_compressor, mdctx);
  grpc_iomgr_closure_init(&t->writing_action, writing_action, t);
  grpc_iomgr_closure_init(&t->reading_action, reading_action, t);

  gpr_slice_buffer_init(&t->parsing.qbuf);
  grpc_chttp2_goaway_parser_init(&t->parsing.goaway_parser);
  grpc_chttp2_hpack_parser_init(&t->parsing.hpack_parser, t->metadata_context);

  if (is_client) {
    gpr_slice_buffer_add(
        &t->global.qbuf,
        gpr_slice_from_copied_string(GRPC_CHTTP2_CLIENT_CONNECT_STRING));
  }
  /* 8 is a random stab in the dark as to a good initial size: it's small enough
     that it shouldn't waste memory for infrequently used connections, yet
     large enough that the exponential growth should happen nicely when it's
     needed.
     TODO(ctiller): tune this */
  grpc_chttp2_stream_map_init(&t->parsing_stream_map, 8);
  grpc_chttp2_stream_map_init(&t->new_stream_map, 8);

  /* copy in initial settings to all setting sets */
  for (i = 0; i < GRPC_CHTTP2_NUM_SETTINGS; i++) {
    t->parsing.settings[i] = grpc_chttp2_settings_parameters[i].default_value;
    for (j = 0; j < GRPC_NUM_SETTING_SETS; j++) {
      t->global.settings[j][i] =
          grpc_chttp2_settings_parameters[i].default_value;
    }
  }
  t->global.dirtied_local_settings = 1;
  /* Hack: it's common for implementations to assume 65536 bytes initial send
     window -- this should by rights be 0 */
  t->global.force_send_settings = 1 << GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
  t->global.sent_local_settings = 0;

  /* configure http2 the way we like it */
  if (is_client) {
    push_setting(t, GRPC_CHTTP2_SETTINGS_ENABLE_PUSH, 0);
    push_setting(t, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 0);
  }
  push_setting(t, GRPC_CHTTP2_SETTINGS_INITIAL_WINDOW_SIZE, DEFAULT_WINDOW);

  if (channel_args) {
    for (i = 0; i < channel_args->num_args; i++) {
      if (0 ==
          strcmp(channel_args->args[i].key, GRPC_ARG_MAX_CONCURRENT_STREAMS)) {
        if (is_client) {
          gpr_log(GPR_ERROR, "%s: is ignored on the client",
                  GRPC_ARG_MAX_CONCURRENT_STREAMS);
        } else if (channel_args->args[i].type != GRPC_ARG_INTEGER) {
          gpr_log(GPR_ERROR, "%s: must be an integer",
                  GRPC_ARG_MAX_CONCURRENT_STREAMS);
        } else {
          push_setting(t, GRPC_CHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS,
                       channel_args->args[i].value.integer);
        }
      } else if (0 == strcmp(channel_args->args[i].key,
                             GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER)) {
        if (channel_args->args[i].type != GRPC_ARG_INTEGER) {
          gpr_log(GPR_ERROR, "%s: must be an integer",
                  GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER);
        } else if ((t->global.next_stream_id & 1) !=
                   (channel_args->args[i].value.integer & 1)) {
          gpr_log(GPR_ERROR, "%s: low bit must be %d on %s",
                  GRPC_ARG_HTTP2_INITIAL_SEQUENCE_NUMBER,
                  t->global.next_stream_id & 1,
                  is_client ? "client" : "server");
        } else {
          t->global.next_stream_id = channel_args->args[i].value.integer;
        }
      }
    }
  }
}
コード例 #11
0
ファイル: round_robin.c プロジェクト: pquerna/grpc
static grpc_lb_policy *round_robin_create(grpc_exec_ctx *exec_ctx,
                                          grpc_lb_policy_factory *factory,
                                          grpc_lb_policy_args *args) {
  GPR_ASSERT(args->client_channel_factory != NULL);

  /* Get server name. */
  const grpc_arg *arg =
      grpc_channel_args_find(args->args, GRPC_ARG_SERVER_NAME);
  const char *server_name =
      arg != NULL && arg->type == GRPC_ARG_STRING ? arg->value.string : NULL;

  /* Find the number of backend addresses. We ignore balancer
   * addresses, since we don't know how to handle them. */
  arg = grpc_channel_args_find(args->args, GRPC_ARG_LB_ADDRESSES);
  GPR_ASSERT(arg != NULL && arg->type == GRPC_ARG_POINTER);
  grpc_lb_addresses *addresses = arg->value.pointer.p;
  size_t num_addrs = 0;
  for (size_t i = 0; i < addresses->num_addresses; i++) {
    if (!addresses->addresses[i].is_balancer) ++num_addrs;
  }
  if (num_addrs == 0) return NULL;

  round_robin_lb_policy *p = gpr_malloc(sizeof(*p));
  memset(p, 0, sizeof(*p));

  p->num_addresses = num_addrs;
  p->subchannels = gpr_malloc(sizeof(*p->subchannels) * num_addrs);
  memset(p->subchannels, 0, sizeof(*p->subchannels) * num_addrs);

  grpc_subchannel_args sc_args;
  size_t subchannel_idx = 0;
  for (size_t i = 0; i < addresses->num_addresses; i++) {
    /* Skip balancer addresses, since we only know how to handle backends. */
    if (addresses->addresses[i].is_balancer) continue;

    memset(&sc_args, 0, sizeof(grpc_subchannel_args));
    /* server_name will be copied as part of the subchannel creation. This makes
     * the copying of server_name (a borrowed pointer) OK. */
    sc_args.server_name = server_name;
    sc_args.addr = &addresses->addresses[i].address;
    sc_args.args = args->args;

    grpc_subchannel *subchannel = grpc_client_channel_factory_create_subchannel(
        exec_ctx, args->client_channel_factory, &sc_args);

    if (subchannel != NULL) {
      subchannel_data *sd = gpr_malloc(sizeof(*sd));
      memset(sd, 0, sizeof(*sd));
      p->subchannels[subchannel_idx] = sd;
      sd->policy = p;
      sd->index = subchannel_idx;
      sd->subchannel = subchannel;
      sd->user_data_vtable = addresses->user_data_vtable;
      if (sd->user_data_vtable != NULL) {
        sd->user_data =
            sd->user_data_vtable->copy(addresses->addresses[i].user_data);
      }
      ++subchannel_idx;
      grpc_closure_init(&sd->connectivity_changed_closure,
                        rr_connectivity_changed, sd);
    }
  }
  if (subchannel_idx == 0) {
    /* couldn't create any subchannel. Bail out */
    gpr_free(p->subchannels);
    gpr_free(p);
    return NULL;
  }
  p->num_subchannels = subchannel_idx;

  /* The (dummy node) root of the ready list */
  p->ready_list.subchannel = NULL;
  p->ready_list.prev = NULL;
  p->ready_list.next = NULL;
  p->ready_list_last_pick = &p->ready_list;

  grpc_lb_policy_init(&p->base, &round_robin_lb_policy_vtable);
  grpc_connectivity_state_init(&p->state_tracker, GRPC_CHANNEL_IDLE,
                               "round_robin");

  if (grpc_lb_round_robin_trace) {
    gpr_log(GPR_DEBUG, "Created RR policy at %p with %lu subchannels",
            (void *)p, (unsigned long)p->num_subchannels);
  }
  gpr_mu_init(&p->mu);
  return &p->base;
}
コード例 #12
0
ファイル: round_robin.c プロジェクト: andrewpollock/grpc
static grpc_lb_policy *round_robin_create(grpc_exec_ctx *exec_ctx,
                                          grpc_lb_policy_factory *factory,
                                          grpc_lb_policy_args *args) {
  GPR_ASSERT(args->addresses != NULL);
  GPR_ASSERT(args->client_channel_factory != NULL);

  /* Find the number of backend addresses. We ignore balancer
   * addresses, since we don't know how to handle them. */
  size_t num_addrs = 0;
  for (size_t i = 0; i < args->addresses->num_addresses; i++) {
    if (!args->addresses->addresses[i].is_balancer) ++num_addrs;
  }
  if (num_addrs == 0) return NULL;

  round_robin_lb_policy *p = gpr_malloc(sizeof(*p));
  memset(p, 0, sizeof(*p));

  p->num_addresses = num_addrs;
  p->subchannels = gpr_malloc(sizeof(*p->subchannels) * num_addrs);
  memset(p->subchannels, 0, sizeof(*p->subchannels) * num_addrs);

  grpc_subchannel_args sc_args;
  size_t subchannel_idx = 0;
  for (size_t i = 0; i < args->addresses->num_addresses; i++) {
    /* Skip balancer addresses, since we only know how to handle backends. */
    if (args->addresses->addresses[i].is_balancer) continue;

    memset(&sc_args, 0, sizeof(grpc_subchannel_args));
    /* server_name will be copied as part of the subchannel creation. This makes
     * the copying of args->server_name (a borrowed pointer) OK. */
    sc_args.server_name = args->server_name;
    sc_args.addr =
        (struct sockaddr *)(&args->addresses->addresses[i].address.addr);
    sc_args.addr_len = args->addresses->addresses[i].address.len;
    sc_args.args = args->additional_args;

    grpc_subchannel *subchannel = grpc_client_channel_factory_create_subchannel(
        exec_ctx, args->client_channel_factory, &sc_args);

    if (subchannel != NULL) {
      subchannel_data *sd = gpr_malloc(sizeof(*sd));
      memset(sd, 0, sizeof(*sd));
      p->subchannels[subchannel_idx] = sd;
      sd->policy = p;
      sd->index = subchannel_idx;
      sd->subchannel = subchannel;
      sd->user_data = args->addresses->addresses[i].user_data;
      ++subchannel_idx;
      grpc_closure_init(&sd->connectivity_changed_closure,
                        rr_connectivity_changed, sd);
    }
  }
  if (subchannel_idx == 0) {
    /* couldn't create any subchannel. Bail out */
    gpr_free(p->subchannels);
    gpr_free(p);
    return NULL;
  }
  p->num_subchannels = subchannel_idx;

  /* The (dummy node) root of the ready list */
  p->ready_list.subchannel = NULL;
  p->ready_list.prev = NULL;
  p->ready_list.next = NULL;
  p->ready_list_last_pick = &p->ready_list;

  grpc_lb_policy_init(&p->base, &round_robin_lb_policy_vtable);
  grpc_connectivity_state_init(&p->state_tracker, GRPC_CHANNEL_IDLE,
                               "round_robin");
  gpr_mu_init(&p->mu);
  return &p->base;
}