static void _devio_destroy_smio (devio_t *self, uint32_t smio_id) { assert (self); /* Stringify ID */ char *key_c = halutils_stringify_key (smio_id); ASSERT_ALLOC (key_c, err_key_alloc); /* Lookup SMIO reference in hash table */ void *pipe = zhash_lookup (self->sm_io_h, key_c); ASSERT_TEST (pipe != NULL, "Could not find SMIO registered with this ID", err_hash_lookup); /* Send message to SMIO informing it to destroy itself */ /* This cannot fail at this point... but it can */ zmsg_t *send_msg = zmsg_new (); ASSERT_ALLOC (send_msg, err_msg_alloc); /* An empty message means to selfdestruct */ zmsg_pushstr (send_msg, ""); int zerr = zmsg_send (&send_msg, pipe); ASSERT_TEST (zerr == 0, "Could not send self-destruct message to SMIO instance", err_send_msg); /* Finally, remove the pipe from hash */ zhash_delete (self->sm_io_h, key_c); err_send_msg: zmsg_destroy (&send_msg); err_msg_alloc: err_hash_lookup: free (key_c); err_key_alloc: return; }
/* Creates a new instance of the SMCH PCA9547 */ smch_pca9547_t * smch_pca9547_new (smio_t *parent, uint64_t base, uint32_t addr, int verbose) { (void) verbose; assert (parent); smch_pca9547_t *self = (smch_pca9547_t *) zmalloc (sizeof *self); ASSERT_ALLOC(self, err_self_alloc); self->i2c = smpr_new (SMCH_PCA9547_NAME, parent, SMPR_I2C, verbose); ASSERT_ALLOC(self->i2c, err_i2c_alloc); /* Initalize the I2C protocol */ int smpr_err = smpr_open (self->i2c, base, NULL /* Default parameters are fine */); ASSERT_TEST(smpr_err == 0, "Could not initialize SMPR protocol", err_smpr_init); self->addr = addr; DBE_DEBUG (DBG_SM_CH | DBG_LVL_INFO, "[sm_ch:pca9547] Created instance of SMCH\n"); return self; err_smpr_init: smpr_destroy (&self->i2c); err_i2c_alloc: free (self); err_self_alloc: return NULL; }
/* Creates a new instance of the SMCH RFFE */ smch_rffe_t * smch_rffe_new (smio_t *parent, int verbose) { (void) verbose; assert (parent); smch_rffe_t *self = (smch_rffe_t *) zmalloc (sizeof *self); ASSERT_ALLOC(self, err_self_alloc); self->bsmp = smpr_new (SMCH_RFFE_NAME, parent, SMPR_BSMP, verbose); ASSERT_ALLOC(self->bsmp, err_bsmp_alloc); /* Initalize the BSMP protocol */ int smpr_err = smpr_open (self->bsmp, 0, NULL /* Default parameters are fine */); ASSERT_TEST(smpr_err == 0, "Could not initialize SMPR protocol", err_smpr_init); DBE_DEBUG (DBG_SM_CH | DBG_LVL_INFO, "[sm_ch:rffe] Created instance of SMCH\n"); return self; err_smpr_init: smpr_destroy (&self->bsmp); err_bsmp_alloc: free (self); err_self_alloc: return NULL; }
smio_err_e fmc130m_4ch_init (smio_t * self) { DBE_DEBUG (DBG_SM_IO | DBG_LVL_TRACE, "[sm_io:fmc130m_4ch_exp] Initializing fmc130m_4ch\n"); smio_err_e err = SMIO_ERR_ALLOC; self->id = FMC130M_4CH_SDB_DEVID; self->name = strdup (FMC130M_4CH_SDB_NAME); ASSERT_ALLOC(self->name, err_name_alloc); /* Set SMIO ops pointers */ self->ops = &fmc130m_4ch_ops; self->thsafe_client_ops = &smio_thsafe_client_zmq_ops; self->exp_ops = fmc130m_exp_ops; /* Initialize specific structure */ self->smio_handler = smio_fmc130m_4ch_new (0); ASSERT_ALLOC(self->smio_handler, err_smio_handler_alloc); err = SMIO_SUCCESS; return err; err_smio_handler_alloc: free (self->name); err_name_alloc: return err; }
static halutils_err_e _disp_table_insert (disp_table_t *self, uint32_t key, disp_table_func_fp func_fp) { if (func_fp == NULL) { return HALUTILS_ERR_NULL_POINTER; } DBE_DEBUG (DBG_HAL_UTILS | DBG_LVL_TRACE, "[halutils:disp_table] Registering function (%p) opcode (%u) into dispatch table\n", func_fp, key); func_fp_wrapper_t *func_fp_wrapper = zmalloc (sizeof *func_fp_wrapper); ASSERT_ALLOC (func_fp_wrapper, err_func_wrapper_alloc); /* Initialize func_p_wrapper struct */ func_fp_wrapper->func_fp = func_fp; char *key_c = halutils_stringify_key (key); ASSERT_ALLOC (key_c, err_key_c_alloc); int zerr = zhash_insert (self->table_h, key_c, func_fp_wrapper); ASSERT_TEST(zerr == 0, "Could not insert item into dispatch table", err_insert_hash); /* Setup free function */ zhash_freefn (self->table_h, key_c, _disp_table_free_item); free (key_c); return HALUTILS_SUCCESS; err_insert_hash: free (key_c); err_key_c_alloc: free (func_fp_wrapper); err_func_wrapper_alloc: return HALUTILS_ERR_ALLOC; }
/* Creates a new instance of the dev_pcie */ static llio_dev_pcie_t * llio_dev_pcie_new (const char *dev_entry) { llio_dev_pcie_t *self = (llio_dev_pcie_t *) zmalloc (sizeof *self); ASSERT_ALLOC (self, err_llio_dev_pcie_alloc); self->dev = (pd_device_t *) zmalloc (sizeof *self->dev); ASSERT_ALLOC (self->dev, err_dev_pcie_alloc); /* FIXME: hardcoded dev number */ /* TODO: should we use llio_endpoint_get to get the endpoint name? */ int err = pd_open (0, self->dev, dev_entry); if (err != 0) { perror ("pd_open"); } ASSERT_TEST(err==0, "Error opening device", err_dev_pcie_open); /* Map all available BARs */ self->bar0 = (uint32_t *) pd_mapBAR (self->dev, BAR0NO); ASSERT_TEST(self->bar0!=NULL, "Could not allocate bar0", err_bar0_alloc); self->bar2 = (uint32_t *) pd_mapBAR (self->dev, BAR2NO); ASSERT_TEST(self->bar2!=NULL, "Could not allocate bar2", err_bar2_alloc); DBE_DEBUG (DBG_LL_IO | DBG_LVL_TRACE, "[ll_io_pcie] BAR2 addr = %p\n", self->bar2); self->bar4 = (uint64_t *) pd_mapBAR (self->dev, BAR4NO); ASSERT_TEST(self->bar4!=NULL, "Could not allocate bar4", err_bar4_alloc); DBE_DEBUG (DBG_LL_IO | DBG_LVL_TRACE, "[ll_io_pcie] BAR4 addr = %p\n", self->bar4); self->bar0_size = pd_getBARsize (self->dev, BAR0NO); ASSERT_TEST(self->bar0_size > 0, "Could not get bar0 size", err_bar0_size); self->bar2_size = pd_getBARsize (self->dev, BAR2NO); ASSERT_TEST(self->bar2_size > 0, "Could not get bar2 size", err_bar2_size); self->bar4_size = pd_getBARsize (self->dev, BAR4NO); ASSERT_TEST(self->bar4_size > 0, "Could not get bar4 size", err_bar4_size); /* Initialize PCIE timeout pattern */ memset (&pcie_timeout_patt, PCIE_TIMEOUT_PATT_INIT, sizeof (pcie_timeout_patt)); DBE_DEBUG (DBG_LL_IO | DBG_LVL_TRACE, "[ll_io_pcie] Created instance of llio_dev_pcie\n"); return self; err_bar4_size: err_bar2_size: err_bar0_size: pd_unmapBAR (self->dev, BAR4NO, self->bar4); err_bar4_alloc: pd_unmapBAR (self->dev, BAR2NO, self->bar2); err_bar2_alloc: pd_unmapBAR (self->dev, BAR0NO, self->bar0); err_bar0_alloc: pd_close (self->dev); err_dev_pcie_open: free (self->dev); err_dev_pcie_alloc: free (self); err_llio_dev_pcie_alloc: return NULL; }
static void _devio_destroy_smio_all (devio_t *self) { #if 0 unsigned i; for (i = 0; i < self->nnodes; ++i) { /* This cannot fail at this point... but it can */ zmsg_t *msg = zmsg_new (); /* An empty message means to selfdestruct */ zmsg_pushstr (msg, ""); zmsg_send (&msg, self->pipes [i]); } #endif /* Get all hash keys */ zlist_t *hash_keys = zhash_keys (self->sm_io_h); ASSERT_ALLOC (hash_keys, err_hash_keys_alloc); char *hash_item = zlist_first (hash_keys); /* Iterate over all keys removing each of one */ for (; hash_item != NULL; hash_item = zlist_next (hash_keys)) { /* FIXME: Usage of stroul fucntion for reconverting the string * into a uint32_t */ _devio_destroy_smio (self, (uint32_t) strtoul (hash_item, (char **) NULL, 16)); } zlist_destroy (&hash_keys); err_hash_keys_alloc: return; }
/* TODO: Avoid exporting the functions before we have initialized * our server with the default values */ smio_err_e trigger_iface_config_defaults (char *broker_endp, char *service, const char *log_file_name) { (void) log_file_name; DBE_DEBUG (DBG_SM_IO | DBG_LVL_INFO, "[sm_io:trigger_iface_defaults] Configuring SMIO " "TRIGGER_IFACE with default values ...\n"); bpm_client_err_e client_err = BPM_CLIENT_SUCCESS; smio_err_e err = SMIO_SUCCESS; bpm_client_t *config_client = bpm_client_new_log_mode (broker_endp, 0, log_file_name, SMIO_TRIGGER_IFACE_LIBBPMCLIENT_LOG_MODE); ASSERT_ALLOC(config_client, err_alloc_client); uint32_t chan; for (chan = 0; chan < SMIO_TRIGGER_IFACE_MAX_CHAN; ++chan) { client_err = bpm_set_trigger_dir (config_client, service, chan, TRIGGER_IFACE_DFLT_DIR); client_err |= bpm_set_trigger_dir_pol (config_client, service, chan, TRIGGER_IFACE_DFLT_DIR_POL); client_err |= bpm_set_trigger_rcv_count_rst (config_client, service, chan, TRIGGER_IFACE_DFLT_RCV_RST); client_err |= bpm_set_trigger_transm_count_rst (config_client, service, chan, TRIGGER_IFACE_DFLT_TRANSM_RST); client_err |= bpm_set_trigger_rcv_len (config_client, service, chan, TRIGGER_IFACE_DFLT_RCV_LEN); client_err |= bpm_set_trigger_transm_len (config_client, service, chan, TRIGGER_IFACE_DFLT_TRANSM_LEN); } ASSERT_TEST(client_err == BPM_CLIENT_SUCCESS, "Could set trigger defaults", err_param_set, SMIO_ERR_CONFIG_DFLT); err_param_set: bpm_client_destroy (&config_client); err_alloc_client: DBE_DEBUG (DBG_SM_IO | DBG_LVL_INFO, "[sm_io:trigger_iface_defaults] Exiting Config thread %s\n", service); return err; }
static inline const char * _bs_main_bundle_bs_path(void) { static bool done = false; static char *path = NULL; /* XXX not thread-safe */ if (!done) { CFBundleRef bundle; done = true; bundle = CFBundleGetMainBundle(); if (bundle != NULL) { CFURLRef url; url = CFBundleCopyResourceURL(bundle, CFSTR("BridgeSupport"), NULL, NULL); if (url != NULL) { CFStringRef str = CFURLCopyPath(url); path = (char *)malloc(sizeof(char) * PATH_MAX); ASSERT_ALLOC(path); CFStringGetFileSystemRepresentation(str, path, PATH_MAX); CFRelease(str); CFRelease(url); } } } return path; }
static inline char * get_framework_name(const char *path) { char *base; char *name; char *p; base = basename((char *)path); if (base == NULL) return NULL; p = strrchr(base, '.'); if (p == NULL) return NULL; if (strcmp(p + 1, "framework") != 0) return NULL; assert(p - base > 0); name = (char *)malloc(p - base + 1); ASSERT_ALLOC(name); strncpy(name, base, p - base); name[p - base] = '\0'; return name; }
disp_table_t *disp_table_new (void) { disp_table_t *self = zmalloc (sizeof *self); ASSERT_ALLOC (self, err_self_alloc); self->table_h = zhash_new (); ASSERT_ALLOC (self->table_h, err_table_h_alloc); /* Only work for strings zhash_autofree (self->table_h);*/ return self; err_table_h_alloc: free (self); err_self_alloc: return NULL; }
static ssize_t _thsafe_zmq_client_read_generic (smio_t *self, loff_t offs, uint8_t *data, uint32_t size) { assert (self); ssize_t ret_size = -1; zmsg_t *send_msg = zmsg_new (); ASSERT_ALLOC(send_msg, err_msg_alloc); uint32_t opcode; DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_client:zmq] Calling _thsafe_read_generic\n"); switch (size) { case THSAFE_READ_16_DSIZE: opcode = THSAFE_READ_16; break; case THSAFE_READ_32_DSIZE: opcode = THSAFE_READ_32; break; case THSAFE_READ_64_DSIZE: opcode = THSAFE_READ_64; break; default: opcode = THSAFE_READ_32; } /* Message is: * frame 0: READ<size> opcode * frame 1: offset */ int zerr = zmsg_addmem (send_msg, &opcode, sizeof (opcode)); ASSERT_TEST(zerr == 0, "Could not add READ opcode in message", err_add_opcode); zerr = zmsg_addmem (send_msg, &offs, sizeof (offs)); ASSERT_TEST(zerr == 0, "Could not add offset in message", err_add_offset); DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_client:zmq] Sending message:\n"); #ifdef LOCAL_MSG_DBG zmsg_print (send_msg); #endif zerr = zmsg_send (&send_msg, self->pipe); ASSERT_TEST(zerr == 0, "Could not send message", err_send_msg); /* Message is: * frame 0: reply code * frame 1: return code * frame 2: data */ ret_size = _thsafe_zmq_client_recv_read (self, data, size); err_send_msg: err_add_offset: err_add_opcode: zmsg_destroy (&send_msg); err_msg_alloc: return ret_size; }
void *disp_table_call (disp_table_t *self, uint32_t key, void *owner, void *args) { char *key_c = halutils_stringify_key (key); ASSERT_ALLOC (key_c, err_key_c_alloc); func_fp_wrapper_t *func_fp_wrapper = zhash_lookup (self->table_h, key_c); ASSERT_ALLOC (func_fp_wrapper, err_func_p_wrapper_null); free (key_c); /* DBE_DEBUG (DBG_HAL_UTILS | DBG_LVL_TRACE, "[halutils:disp_table] Calling function (key = %u, addr = %p) from dispatch table\n", key, func_fp_wrapper->func_fp); */ /* The function pointer is never NULL */ return func_fp_wrapper->func_fp (owner, args); err_func_p_wrapper_null: free (key_c); err_key_c_alloc: return NULL; }
/* Creates a new instance of Device Information */ llio_dev_info_t * llio_dev_info_new () { llio_dev_info_t *self = (llio_dev_info_t *) zmalloc (sizeof *self); ASSERT_ALLOC(self, err_self_alloc); /* Initilialize llio_dev_info */ /* Put some default values as these are going to be filled later by read_dev_info() */ self->sdb_addr = 0x0; self->parsed = false; self->sdb = zlist_new (); /* HASH!? */ ASSERT_ALLOC(self->sdb, err_sdb_alloc); return self; err_sdb_alloc: free (self); err_self_alloc: return NULL; }
bs_parser_t * bs_parser_new(void) { struct _bs_parser *parser; parser = (struct _bs_parser *)malloc(sizeof(struct _bs_parser)); ASSERT_ALLOC(parser); parser->loaded_paths = CFArrayCreateMutable(kCFAllocatorMalloc, 0, &kCFTypeArrayCallBacks); return parser; }
DefineFunction(Array, void, enlarge, size_t min_count) { if (this->m_size >= min_count) return; this->m_size = min_count * 15 / 10; if (this->m_size < min_count) this->m_size = min_count; this->m_elements = realloc(this->m_elements, this->m_size * sizeof(this->m_elements[0])); ASSERT_ALLOC(this->m_elements); }
/* Creates a new instance of Device Information */ smio_trigger_mux_t * smio_trigger_mux_new (smio_t *parent) { (void) parent; smio_trigger_mux_t *self = (smio_trigger_mux_t *) zmalloc (sizeof *self); ASSERT_ALLOC(self, err_self_alloc); return self; err_self_alloc: return NULL; }
halutils_err_e disp_table_remove (disp_table_t *self, uint32_t key) { char *key_c = halutils_stringify_key (key); ASSERT_ALLOC (key_c, err_key_c_alloc); DBE_DEBUG (DBG_HAL_UTILS | DBG_LVL_TRACE, "[halutils:disp_table] Removing function (key = %u) into dispatch table\n", key); /* This will trigger the free fucntion previously registered */ zhash_delete (self->table_h, key_c); free (key_c); return HALUTILS_SUCCESS; err_key_c_alloc: return HALUTILS_ERR_ALLOC; }
/**** Read data block from device function pointer, size in bytes ****/ ssize_t thsafe_zmq_client_read_block (smio_t *self, loff_t offs, size_t size, uint32_t *data) { assert (self); ssize_t ret_size = -1; zmsg_t *send_msg = zmsg_new (); ASSERT_ALLOC(send_msg, err_msg_alloc); uint32_t opcode = THSAFE_READ_BLOCK; DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_client:zmq] Calling thsafe_read_block\n"); /* Message is: * frame 0: READ_BLOCK opcode * frame 1: offset * frame 2: number of bytes to be read */ int zerr = zmsg_addmem (send_msg, &opcode, sizeof (opcode)); ASSERT_TEST(zerr == 0, "Could not add READ opcode in message", err_add_opcode); zerr = zmsg_addmem (send_msg, &offs, sizeof (offs)); ASSERT_TEST(zerr == 0, "Could not add offset in message", err_add_offset); zerr = zmsg_addmem (send_msg, &size, sizeof (size)); ASSERT_TEST(zerr == 0, "Could not add size in message", err_add_size); DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_client:zmq] Sending message:\n"); #ifdef LOCAL_MSG_DBG zmsg_print (send_msg); #endif zerr = zmsg_send (&send_msg, self->pipe); ASSERT_TEST(zerr == 0, "Could not send message", err_send_msg); /* Message is: * frame 0: reply code * frame 1: return code * frame 2: data */ ret_size = _thsafe_zmq_client_recv_read (self, (uint8_t *) data, size); err_send_msg: err_add_size: err_add_offset: err_add_opcode: zmsg_destroy (&send_msg); err_msg_alloc: return ret_size; }
/**** Write data block from device function pointer, size in bytes ****/ ssize_t thsafe_zmq_client_write_block (smio_t *self, loff_t offs, size_t size, const uint32_t *data) { assert (self); ssize_t ret_size = -1; zmsg_t *send_msg = zmsg_new (); ASSERT_ALLOC(send_msg, err_msg_alloc); uint32_t opcode = THSAFE_WRITE_BLOCK; DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_client:zmq] Calling thsafe_write_block\n"); /* Message is: * frame 0: WRITE_BLOCK opcode * frame 1: offset * frame 2: data to be written * */ int zerr = zmsg_addmem (send_msg, &opcode, sizeof (opcode)); ASSERT_TEST(zerr == 0, "Could not add WRITE opcode in message", err_add_opcode); zerr = zmsg_addmem (send_msg, &offs, sizeof (offs)); ASSERT_TEST(zerr == 0, "Could not add offset in message", err_add_offset); zerr = zmsg_addmem (send_msg, data, size); ASSERT_TEST(zerr == 0, "Could not add data in message", err_add_data); DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_client:zmq] Sending message:\n"); #ifdef LOCAL_MSG_DBG zmsg_print (send_msg); #endif zerr = zmsg_send (&send_msg, self->pipe); ASSERT_TEST(zerr == 0, "Could not send message", err_send_msg); /* Message is: * frame 0: reply code * frame 1: return code */ ret_size = _thsafe_zmq_client_recv_write (self); err_send_msg: err_add_data: err_add_offset: err_add_opcode: zmsg_destroy (&send_msg); err_msg_alloc: return ret_size; }
/**************** FMC130M SMIO Functions ****************/ bpm_client_err_e bpm_blink_leds (bpm_client_t *self, char *service, uint32_t leds) { assert (self); assert (service); bpm_client_err_e err = BPM_CLIENT_SUCCESS; FMC130M_4CH_REPLY_TYPE operation = FMC130M_4CH_OPCODE_LEDS; zmsg_t *request = zmsg_new (); err = (request == NULL) ? BPM_CLIENT_ERR_ALLOC : err; ASSERT_ALLOC(request, err_send_msg_alloc); zmsg_addmem (request, &operation, sizeof (operation)); zmsg_addmem (request, &leds, sizeof (leds)); mdp_client_send (self->mdp_client, service, &request); err_send_msg_alloc: return err; }
bpm_client_t *bpm_client_new (char *broker_endp, int verbose) { bpm_client_t *self = zmalloc (sizeof *self); ASSERT_ALLOC(self, err_self_alloc); self->mdp_client = mdp_client_new (broker_endp, verbose); ASSERT_TEST(self->mdp_client!=NULL, "Could not create MDP client", err_mdp_client); /* Initialize acquisition table. Defined in hal/smio/modules/ * acq/ddr3_map.h */ self->acq_buf = __acq_buf; return self; err_mdp_client: free (self); err_self_alloc: return NULL; }
/* Creates a new instance of Device Information */ devio_t * devio_new (char *name, char *endpoint_dev, llio_type_e type, char *endpoint_broker, int verbose) { devio_t *self = (devio_t *) zmalloc (sizeof *self); ASSERT_ALLOC(self, err_self_alloc); /* Initialize the sockets structure to talk to nodes */ self->pipes = zmalloc (sizeof (void *) * NODES_MAX_LEN); ASSERT_ALLOC(self->pipes, err_pipes_alloc); /* 0 nodes for now... */ self->nnodes = 0; /* Nullify poller */ self->poller = zpoller_new (NULL); ASSERT_ALLOC(self->poller, err_poller_alloc); /* Initilize mdp_worrker last, as we need to have everything ready * when we attemp to register in broker. Actually, we still need * to parse the SDB strucutres and register the operations in the * hash tables... * TODO (FIXME?): Find a better initialitazion routine before registering * to the broker the request from clients */ self->name = strdup (name); ASSERT_ALLOC(self->name, err_name_alloc); self->endpoint_broker = strdup (endpoint_broker); ASSERT_ALLOC(self->endpoint_broker, err_endp_broker_alloc); self->verbose = verbose; /* Concatenate recv'ed name with a llio identifier */ char *llio_name = zmalloc (sizeof (char)*(strlen(name)+strlen(LLIO_STR)+1)); ASSERT_ALLOC(llio_name, err_llio_name_alloc); strcat (llio_name, name); strcat (llio_name, LLIO_STR); self->llio = llio_new (llio_name, endpoint_dev, type, verbose); ASSERT_ALLOC(self->llio, err_llio_alloc); /* We try to open the device */ int err = llio_open (self->llio, NULL); ASSERT_TEST(err==0, "Error opening device!", err_llio_open); /* We can free llio_name now, as llio copies the string */ free (llio_name); llio_name = NULL; /* Avoid double free error */ /* Init sm_io_thsafe_server_ops_h. For now, we assume we want zmq * for exchanging messages between smio and devio instances */ self->thsafe_server_ops = &smio_thsafe_zmq_server_ops; /* Init sm_io_h hash */ self->sm_io_h = zhash_new (); ASSERT_ALLOC(self->sm_io_h, err_sm_io_h_alloc); /* Init sm_io_thsafe_ops_h dispatch table */ self->disp_table_thsafe_ops = disp_table_new (); ASSERT_ALLOC(self->disp_table_thsafe_ops, err_disp_table_thsafe_ops_alloc); disp_table_func_fp *thsafe_server_fp = (disp_table_func_fp *) (self->thsafe_server_ops); const uint32_t *thsafe_opcodes_p = thsafe_opcodes; halutils_err_e halutils_err = disp_table_insert_all (self->disp_table_thsafe_ops, thsafe_server_fp, thsafe_opcodes_p, THSAFE_OPCODE_END); ASSERT_TEST(halutils_err==HALUTILS_SUCCESS, "Could not initialize dispatch table", err_disp_table_init); /* Finally, initialize mdp_worker with service being the BPM<board_number> */ /* self->worker = mdp_worker_new (endpoint_broker, name, verbose); ASSERT_ALLOC(self->worker, err_worker_alloc); */ /* Finally, initialize out zeroMQ context */ self->ctx = zctx_new (); ASSERT_ALLOC(self->ctx, err_ctx_alloc); /* Adjust linger time for Majordomo protocol (MDP) */ /* A non-zero linger value is required for DISCONNECT to be sent * when the worker is destroyed. 100 is arbitrary but chosen to be * sufficient for common cases without significant delay in broken ones. */ zctx_set_linger (self->ctx, 100); return self; err_ctx_alloc: err_disp_table_init: disp_table_destroy (&self->disp_table_thsafe_ops); err_disp_table_thsafe_ops_alloc: zhash_destroy (&self->sm_io_h); err_sm_io_h_alloc: llio_release (self->llio, NULL); err_llio_open: llio_destroy (&self->llio); err_llio_alloc: free (llio_name); err_llio_name_alloc: free (self->endpoint_broker); err_endp_broker_alloc: free (self->name); err_name_alloc: zpoller_destroy (&self->poller); err_poller_alloc: free (self->pipes); err_pipes_alloc: free (self); err_self_alloc: return NULL; }
/* Register an specific sm_io modules to this device */ devio_err_e devio_register_sm (devio_t *self, uint32_t smio_id, void *priv) { assert (self); /* Search the sm_io_mod_dsapatch table for the smio_id and, * if found, call the correspondent bootstrap code to initilize * the sm_io module */ th_boot_args_t *th_args = NULL; /* For now, just do a simple linear search. We can afford this, as * we don't expect to insert new sm_io modules often */ unsigned int i; DBE_DEBUG (DBG_DEV_IO | DBG_LVL_TRACE, "[dev_io_core:register_sm] smio_mod_dispatch table size = %ld\n", ARRAY_SIZE(smio_mod_dispatch)); for (i = 0; i < ARRAY_SIZE(smio_mod_dispatch); ++i) { if (smio_mod_dispatch[i].id == smio_id) { /* Found! Call bootstrap code and insert in * hash table */ /* FIXME: Why do I need this? smio always gets initilized * after smio_mod_dispatch[i].bootstrap_ops->smio_boot (self); */ /* smio_t *smio = NULL; */ /* It is expected tha after the boot () call the operations * this sm_io inscate can handle are already registered! */ DBE_DEBUG (DBG_DEV_IO | DBG_LVL_TRACE, "[dev_io_core:register_sm] Allocating thread args\n"); /* Alloacate thread arguments struct and pass it to the * thread. It is the responsability of the calling thread * to clear this structure after using it! */ th_boot_args_t *th_args = zmalloc (sizeof *th_args); ASSERT_ALLOC (th_args, err_th_args_alloc); th_args->parent = self; /* FIXME: weak identifier */ th_args->smio_id = i; th_args->broker = self->endpoint_broker; th_args->service = self->name; th_args->verbose = self->verbose; th_args->priv = priv; DBE_DEBUG (DBG_DEV_IO | DBG_LVL_TRACE, "[dev_io_core:register_sm] Calling boot func\n"); uint32_t pipe_idx = self->nnodes++; self->pipes [pipe_idx] = zthread_fork (self->ctx, smio_startup, th_args); /* self->pipes [pipe_idx] = zthread_fork (self->ctx, smio_mod_dispatch[i].bootstrap_ops->thread_boot, th_args); */ /*smio = smio_mod_dispatch[i].bootstrap_ops->boot (self);*/ /*ASSERT_ALLOC (smio, err_smio_alloc); */ /* Stringify ID */ DBE_DEBUG (DBG_DEV_IO | DBG_LVL_TRACE, "[dev_io_core:register_sm] Stringify hash ID\n"); char *key = halutils_stringify_key (smio_mod_dispatch[i].id); ASSERT_ALLOC (key, err_key_alloc); DBE_DEBUG (DBG_DEV_IO | DBG_LVL_TRACE, "[dev_io_core:register_sm] Inserting hash with key: %s\n", key); zhash_insert (self->sm_io_h, key, self->pipes [pipe_idx]); free (key); /* stop on first match */ break; } } //free (th_args); return DEVIO_SUCCESS; err_key_alloc: free (th_args); err_th_args_alloc: return DEVIO_ERR_ALLOC; }
int _thsafe_zmq_client_open_release (smio_t *self, llio_endpoint_t *endpoint, uint32_t opcode) { assert (self); int ret = -1; zmsg_t *send_msg = zmsg_new (); ASSERT_ALLOC(send_msg, err_msg_alloc); DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_client:zmq] Calling thsafe_release\n"); /* Message is: * frame 0: RELEASE opcode * frame 1: endpopint struct (FIXME?) */ int zerr = zmsg_addmem (send_msg, &opcode, sizeof (opcode)); ASSERT_TEST(zerr == 0, "Could not add OPEN opcode in message", err_add_opcode); zerr = zmsg_addmem (send_msg, endpoint, sizeof (*endpoint)); ASSERT_TEST(zerr == 0, "Could not add endpoint in message", err_add_endpoint); DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_client:zmq] Sending message:\n"); #ifdef LOCAL_MSG_DBG zmsg_print (send_msg); #endif zerr = zmsg_send (&send_msg, self->pipe); ASSERT_TEST(zerr == 0, "Could not send message", err_send_msg); /* Message is: * frame 0: reply code * frame 1: return code */ /* Returns NULL if confirmation was not OK or in case of error. * Returns the original message if the confirmation was OK */ zmsg_t *recv_msg = _thsafe_zmq_client_recv_confirmation (self); ASSERT_TEST(recv_msg != NULL, "Could not receive confirmation code", err_null_raw_data); /* If we are here the message got a OK reply code. * Just return the return code */ zframe_t *reply_frame = zmsg_pop (recv_msg); zframe_destroy (&reply_frame); /* Don't do anything with the reply code */ zframe_t *ret_code_frame = zmsg_pop (recv_msg); if (ret_code_frame == NULL) { DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_client:zmq] Interrupted or malformed message\n"); /* Interrupted or malformed message */ goto err_recv_data; } /* Check if the frame has the number of bytes requested. * For now, we consider a success only when the number of * bytes requested is the same as the actually read*/ if (zframe_size (ret_code_frame) != THSAFE_REPLY_SIZE) { DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_client:zmq] Frame size is wrong\n"); goto err_recv_data_size; } ret = *(THSAFE_REPLY_TYPE *) zframe_data (ret_code_frame); DBE_DEBUG (DBG_MSG | DBG_LVL_TRACE, "[smio_thsafe_client:zmq] Received return code: %08X\n", ret); err_recv_data_size: zframe_destroy (&ret_code_frame); err_recv_data: err_null_raw_data: zmsg_destroy (&recv_msg); err_send_msg: err_add_endpoint: err_add_opcode: zmsg_destroy (&send_msg); err_msg_alloc: return ret; }
bool bs_parser_parse(bs_parser_t *parser, const char *path, const char *framework_path, bs_parse_options_t options, bs_parse_callback_t callback, void *context, char **error) { xmlTextReaderPtr reader; bs_element_function_t *func; bs_element_class_t *klass; bs_element_method_t *method; unsigned int i; #define MAX_ARGS 128 bs_element_arg_t args[MAX_ARGS]; bs_element_arg_t fptr_args[MAX_ARGS]; char *protocol_name = NULL; int func_ptr_arg_depth; bs_element_function_pointer_t *func_ptr; bool success; CFStringRef cf_path; bool nested_func_ptr; unsigned int version_number = 0; if (callback == NULL) return false; /* check if the given framework path has not been loaded already */ cf_path = CFStringCreateWithFileSystemRepresentation(kCFAllocatorMalloc, path); CFMakeCollectable(cf_path); for (unsigned i = 0, count = CFArrayGetCount(parser->loaded_paths); i < count; i++) { CFStringRef s = CFArrayGetValueAtIndex(parser->loaded_paths, i); if (CFStringCompare(cf_path, s, kCFCompareCaseInsensitive) == kCFCompareEqualTo) { /* already loaded */ return true; } } CFArrayAppendValue(parser->loaded_paths, cf_path); //printf("parsing %s\n", path); #define BAIL(fmt, args...) \ do { \ if (error != NULL) { \ char buf[1024]; \ snprintf(buf, sizeof buf, \ "%s:%ld - "fmt, path, \ xmlGetLineNo(xmlTextReaderCurrentNode(reader)), \ ##args); \ *error = strdup(buf); \ } \ success = false; \ goto bails; \ } \ while (0) #if __LP64__ # define CHECK_TYPE_ATTRIBUTE(var) CHECK_ATTRIBUTE(var, "type") #else # define CHECK_TYPE_ATTRIBUTE(var) \ if (var == NULL && get_type64_attribute(reader) != NULL) { \ break; \ } \ CHECK_ATTRIBUTE(var, "type") #endif #define CHECK_ATTRIBUTE_CAN_BE_EMPTY(a, name) \ CHECK_ATTRIBUTE0(a, name, true) #define CHECK_ATTRIBUTE(a, name) \ CHECK_ATTRIBUTE0(a, name, false) #define CHECK_ATTRIBUTE0(a, name, can_be_empty) \ do { \ if (a == NULL) \ BAIL("expected attribute `%s' for element `%s'", \ name, xmlTextReaderConstName(reader)); \ if (!can_be_empty && *a == '\0') { \ free(a); \ BAIL("empty attribute `%s' for element `%s'", \ name, xmlTextReaderConstName(reader)); \ } \ } while (0) \ reader = xmlNewTextReaderFilename(path); if (reader == NULL) BAIL("cannot create XML text reader for file at path `%s'", path); func = NULL; func_ptr = NULL; func_ptr_arg_depth = -1; nested_func_ptr = false; klass = NULL; method = NULL; protocol_name = NULL; while (true) { const char *name; unsigned int namelen; int node_type = -1; bool eof = false; struct bs_xml_atom *atom; void *bs_element; bs_element_type_t bs_element_type = 0; do { int retval = xmlTextReaderRead(reader); if (retval == 0) { eof = true; break; } else if (retval < 0) BAIL("parsing error: %d", retval); node_type = xmlTextReaderNodeType(reader); } while (node_type != XML_READER_TYPE_ELEMENT && node_type != XML_READER_TYPE_END_ELEMENT); if (eof) break; name = (const char *)xmlTextReaderConstName(reader); namelen = strlen(name); bs_element = NULL; atom = bs_xml_element(name, namelen); if (atom == NULL) { // TODO: we should include the "signatures" string into the gperf // function. if (version_number == 0 && strcmp(name, "signatures") == 0) { char *str = get_attribute(reader, "version"); if (str != NULL) { char *p = strchr(str, '.'); if (p != NULL) { *p = '\0'; int major = atoi(str); int minor = atoi(&p[1]); assert(major < 10 && minor < 10); version_number = (major * 10) + minor; parser->version_number = version_number; } free(str); } } continue; } if (nested_func_ptr) { // FIXME: elements nesting function_pointers aren't supported yet by the // parser, so we just ignore them. if (node_type == XML_READER_TYPE_END_ELEMENT && (atom->val == BS_XML_FUNCTION || atom->val == BS_XML_METHOD)) { nested_func_ptr = false; } continue; } if (node_type == XML_READER_TYPE_ELEMENT) { switch (atom->val) { case BS_XML_DEPENDS_ON: { char *depends_on_path; char bs_path[PATH_MAX]; bool bs_path_found; depends_on_path = get_attribute(reader, "path"); CHECK_ATTRIBUTE(depends_on_path, "path"); //printf("depends of %s\n", depends_on_path); bs_path_found = bs_find_path(depends_on_path, bs_path, sizeof bs_path); if (bs_path_found) { if (!bs_parser_parse(parser, bs_path, depends_on_path, options, callback, context, error)) { free(depends_on_path); return false; } } free(depends_on_path); break; } case BS_XML_CONSTANT: { bs_element_constant_t *bs_const; char *const_name; char *const_type; const_name = get_attribute(reader, "name"); CHECK_ATTRIBUTE(const_name, "name"); const_type = get_type_attribute(reader); CHECK_TYPE_ATTRIBUTE(const_type); bs_const = (bs_element_constant_t *) malloc(sizeof(bs_element_constant_t)); ASSERT_ALLOC(bs_const); bs_const->name = const_name; bs_const->type = const_type; bs_const->ignore = false; bs_const->suggestion = NULL; bs_const->magic_cookie = get_boolean_attribute(reader, "magic_cookie", false); bs_element = bs_const; bs_element_type = BS_ELEMENT_CONSTANT; break; } case BS_XML_STRING_CONSTANT: { bs_element_string_constant_t *bs_strconst; char *strconst_name; char *strconst_value; strconst_name = get_attribute(reader, "name"); CHECK_ATTRIBUTE(strconst_name, "name"); strconst_value = get_attribute(reader, "value"); CHECK_ATTRIBUTE_CAN_BE_EMPTY(strconst_value, "value"); bs_strconst = (bs_element_string_constant_t *) malloc(sizeof(bs_element_string_constant_t)); ASSERT_ALLOC(bs_strconst); bs_strconst->name = strconst_name; bs_strconst->value = strconst_value; bs_strconst->nsstring = get_boolean_attribute(reader, "nsstring", false); bs_element = bs_strconst; bs_element_type = BS_ELEMENT_STRING_CONSTANT; break; } case BS_XML_ENUM: { char *enum_name; char *enum_value; enum_name = get_attribute(reader, "name"); CHECK_ATTRIBUTE(enum_name, "name"); #if __LP64__ enum_value = get_attribute(reader, "value64"); if (enum_value == NULL) #endif enum_value = get_attribute(reader, "value"); #if BYTE_ORDER == BIG_ENDIAN # define BYTE_ORDER_VALUE_ATTR_NAME "be_value" #else # define BYTE_ORDER_VALUE_ATTR_NAME "le_value" #endif if (enum_value == NULL) enum_value = get_attribute(reader, BYTE_ORDER_VALUE_ATTR_NAME); if (enum_value != NULL) { bs_element_enum_t *bs_enum; bs_enum = (bs_element_enum_t *)malloc(sizeof(bs_element_enum_t)); ASSERT_ALLOC(bs_enum); bs_enum->name = enum_name; bs_enum->value = enum_value; bs_enum->ignore = get_boolean_attribute(reader, "ignore", false); bs_enum->suggestion = get_attribute(reader, "suggestion"); bs_element = bs_enum; bs_element_type = BS_ELEMENT_ENUM; } break; } case BS_XML_STRUCT: { bs_element_struct_t *bs_struct; char *struct_decorated_type; char *struct_name; char type[MAX_ENCODE_LEN]; bs_element_struct_field_t fields[128]; int field_count; struct_decorated_type = get_type_attribute(reader); CHECK_TYPE_ATTRIBUTE(struct_decorated_type); struct_name = get_attribute(reader, "name"); CHECK_ATTRIBUTE(struct_name, "name"); if (!undecorate_struct_type(struct_decorated_type, type, sizeof type, fields, 128, &field_count)) { BAIL("Can't handle structure '%s' with type '%s'", struct_name, struct_decorated_type); } free(struct_decorated_type); bs_struct = (bs_element_struct_t *)malloc(sizeof(bs_element_struct_t)); ASSERT_ALLOC(bs_struct); bs_struct->name = struct_name; bs_struct->type = strdup(type); bs_struct->fields = (bs_element_struct_field_t *)malloc( sizeof(bs_element_struct_field_t) * field_count); ASSERT_ALLOC(bs_struct->fields); memcpy(bs_struct->fields, fields, sizeof(bs_element_struct_field_t) * field_count); bs_struct->fields_count = field_count; bs_struct->opaque = get_boolean_attribute(reader, "opaque", false); bs_element = bs_struct; bs_element_type = BS_ELEMENT_STRUCT; break; } case BS_XML_OPAQUE: { bs_element_opaque_t *bs_opaque; char *opaque_name; char *opaque_type; opaque_name = get_attribute(reader, "name"); CHECK_ATTRIBUTE(opaque_name, "name"); opaque_type = get_type_attribute(reader); CHECK_TYPE_ATTRIBUTE(opaque_type); bs_opaque = (bs_element_opaque_t *)malloc(sizeof(bs_element_opaque_t)); ASSERT_ALLOC(bs_opaque); bs_opaque->name = opaque_name; bs_opaque->type = opaque_type; bs_element = bs_opaque; bs_element_type = BS_ELEMENT_OPAQUE; break; } case BS_XML_CFTYPE: { bs_element_cftype_t *bs_cftype; char *cftype_name; char *cftype_type; cftype_name = get_attribute(reader, "name"); CHECK_ATTRIBUTE(cftype_name, "name"); cftype_type = get_type_attribute(reader); CHECK_TYPE_ATTRIBUTE(cftype_type); bs_cftype = (bs_element_cftype_t *)malloc(sizeof(bs_element_cftype_t)); ASSERT_ALLOC(bs_cftype); bs_cftype->name = cftype_name; bs_cftype->type = cftype_type; #if 1 /* the type_id field isn't used in MacRuby */ bs_cftype->type_id = 0; #else char *cftype_gettypeid_func_name; cftype_gettypeid_func_name = get_attribute(reader, "gettypeid_func"); if (cftype_gettypeid_func_name != NULL) { void *sym; sym = dlsym(RTLD_DEFAULT, cftype_gettypeid_func_name); if (sym == NULL) { BAIL("cannot locate gettypeid_func function `%s'", cftype_gettypeid_func_name); } else { CFTypeID (*cb)(void) = sym; bs_cftype->type_id = (*cb)(); } } else { bs_cftype->type_id = 0; } #endif bs_cftype->tollfree = get_attribute(reader, "tollfree"); bs_element = bs_cftype; bs_element_type = BS_ELEMENT_CFTYPE; break; } case BS_XML_INFORMAL_PROTOCOL: { if (protocol_name != NULL) free(protocol_name); protocol_name = get_attribute(reader, "name"); CHECK_ATTRIBUTE(protocol_name, "name"); break; } case BS_XML_FUNCTION: { char *func_name; func_name = get_attribute(reader, "name"); CHECK_ATTRIBUTE(func_name, "name"); func = (bs_element_function_t *)malloc(sizeof(bs_element_function_t)); ASSERT_ALLOC(func); func->name = func_name; func->variadic = get_boolean_attribute(reader, "variadic", false); func->args_count = 0; func->args = NULL; func->retval = NULL; if (xmlTextReaderIsEmptyElement(reader)) { bs_element = func; bs_element_type = BS_ELEMENT_FUNCTION; func = NULL; } break; } case BS_XML_FUNCTION_ALIAS: { bs_element_function_alias_t *bs_func_alias; char *alias_name; char *alias_original; alias_name = get_attribute(reader, "name"); CHECK_ATTRIBUTE(alias_name, "name"); alias_original = get_attribute(reader, "original"); CHECK_ATTRIBUTE(alias_original, "original"); bs_func_alias = (bs_element_function_alias_t *)malloc( sizeof(bs_element_function_alias_t)); ASSERT_ALLOC(bs_func_alias); bs_func_alias->name = alias_name; bs_func_alias->original = alias_original; bs_element = bs_func_alias; bs_element_type = BS_ELEMENT_FUNCTION_ALIAS; break; } case BS_XML_CLASS: { char *class_name; class_name = get_attribute(reader, "name"); CHECK_ATTRIBUTE(class_name, "name"); klass = (bs_element_class_t *)malloc(sizeof(bs_element_class_t)); ASSERT_ALLOC(klass); klass->name = class_name; klass->class_methods = klass->instance_methods = NULL; klass->class_methods_count = klass->instance_methods_count = 0; break; } case BS_XML_ARG: { if (func != NULL || method != NULL || func_ptr != NULL) { bs_element_arg_t *bs_arg; unsigned *argc; argc = func_ptr != NULL ? &func_ptr->args_count : func != NULL ? &func->args_count : &method->args_count; if (*argc >= MAX_ARGS) { if (func_ptr != NULL) BAIL("maximum number of arguments (%d) reached " \ "for function pointer", MAX_ARGS); else if (func != NULL) BAIL("maximum number of arguments (%d) reached " \ "for function '%s'", MAX_ARGS, func->name); else BAIL("maximum number of arguments (%d) reached " \ "for method '%s'", MAX_ARGS, (char *)method->name); } bs_element_arg_t *args_from = (func_ptr == NULL ? args : fptr_args); bs_arg = &args_from[(*argc)++]; if (method != NULL && func_ptr == NULL) { char *index = get_attribute(reader, "index"); CHECK_ATTRIBUTE(index, "index"); bs_arg->index = strtol(index, NULL, 10); free(index); } else { bs_arg->index = -1; } get_type_modifier_attribute(reader, &bs_arg->type_modifier); #if __LP64__ bs_arg->sel_of_type = get_attribute(reader, "sel_of_type64"); if (bs_arg->sel_of_type == NULL) #endif bs_arg->sel_of_type = get_attribute(reader, "sel_of_type"); bs_arg->printf_format = get_boolean_attribute(reader, "printf_format", false); bs_arg->null_accepted = get_boolean_attribute(reader, "null_accepted", true); get_c_ary_type_attribute(reader, &bs_arg->carray_type, &bs_arg->carray_type_value); bs_arg->type = get_type_attribute(reader); if (get_boolean_attribute(reader, "function_pointer", false)) { if (func_ptr != NULL) { func_ptr = NULL; nested_func_ptr = true; break; } bs_arg->function_pointer = (bs_element_function_pointer_t *) calloc(1, sizeof(bs_element_function_pointer_t)); ASSERT_ALLOC(bs_arg->function_pointer); func_ptr = bs_arg->function_pointer; func_ptr_arg_depth = xmlTextReaderDepth(reader); } else { bs_arg->function_pointer = NULL; } } else { BAIL("argument defined outside of a " \ "function/method/function_pointer"); } break; } case BS_XML_RETVAL: { if (func != NULL || method != NULL || func_ptr != NULL) { bs_element_retval_t *bs_retval; if (func_ptr != NULL) { if (func_ptr->retval != NULL) BAIL("function pointer return value defined more than once"); } else if (func != NULL) { if (func->retval != NULL) BAIL("function '%s' return value defined more than once", func->name); } else if (method != NULL) { if (method->retval != NULL) BAIL("method '%s' return value defined more than once", (char *)method->name); } bs_retval = (bs_element_retval_t *)malloc(sizeof(bs_element_retval_t)); ASSERT_ALLOC(bs_retval); get_c_ary_type_attribute(reader, &bs_retval->carray_type, &bs_retval->carray_type_value); bs_retval->type = get_type_attribute(reader); if (bs_retval->type != NULL) bs_retval->already_retained = get_boolean_attribute(reader, "already_retained", false); if (func_ptr != NULL) { if (bs_retval->type != NULL) { func_ptr->retval = bs_retval; } else { free(bs_retval); BAIL("function pointer return value defined without type"); } } else if (func != NULL) { if (bs_retval->type != NULL) { func->retval = bs_retval; } else { free(bs_retval); #if !defined(__LP64__) if (get_type64_attribute(reader) != NULL) { // The function has no 32-bit return value type and we // run in 32-bit mode. We just ignore it. func = NULL; break; } #endif BAIL("function '%s' return value defined without type", func->name); } } else { method->retval = bs_retval; } if (get_boolean_attribute(reader, "function_pointer", false)) { if (func_ptr != NULL) { func_ptr = NULL; nested_func_ptr = true; break; } bs_retval->function_pointer = (bs_element_function_pointer_t *) calloc(1, sizeof(bs_element_function_pointer_t)); ASSERT_ALLOC(bs_retval->function_pointer); func_ptr = bs_retval->function_pointer; func_ptr_arg_depth = xmlTextReaderDepth(reader); } else { bs_retval->function_pointer = NULL; } } else { BAIL("return value defined outside a function/method"); } break; } case BS_XML_METHOD: { if (protocol_name != NULL) { bs_element_informal_protocol_method_t *bs_informal_method; char *selector; char *method_type; selector = get_attribute(reader, "selector"); CHECK_ATTRIBUTE(selector, "selector"); method_type = get_type_attribute(reader); CHECK_TYPE_ATTRIBUTE(method_type); bs_informal_method = (bs_element_informal_protocol_method_t *) malloc(sizeof(bs_element_informal_protocol_method_t)); ASSERT_ALLOC(bs_informal_method); bs_informal_method->name = sel_registerName(selector); free(selector); bs_informal_method->class_method = get_boolean_attribute(reader, "class_method", false); bs_informal_method->type = method_type; bs_informal_method->protocol_name = strdup(protocol_name); bs_element = bs_informal_method; bs_element_type = BS_ELEMENT_INFORMAL_PROTOCOL_METHOD; } else if (klass != NULL) { char *selector; selector = get_attribute(reader, "selector"); CHECK_ATTRIBUTE(selector, "selector"); method = (bs_element_method_t *)malloc(sizeof(bs_element_method_t)); ASSERT_ALLOC(method); method->name = sel_registerName(selector); free(selector); method->class_method = get_boolean_attribute(reader, "class_method", false); method->variadic = get_boolean_attribute(reader, "variadic", false); method->ignore = get_boolean_attribute(reader, "ignore", false); method->suggestion = get_attribute(reader, "suggestion"); method->args_count = 0; method->args = NULL; method->retval = NULL; if (xmlTextReaderIsEmptyElement(reader)) { goto index_method; } } else { BAIL("method defined outside a class or informal protocol"); } break; } } } else if (node_type == XML_READER_TYPE_END_ELEMENT) { switch (atom->val) { case BS_XML_INFORMAL_PROTOCOL: { protocol_name = NULL; break; } case BS_XML_RETVAL: case BS_XML_ARG: { if (func_ptr != NULL && func_ptr_arg_depth == xmlTextReaderDepth(reader)) { bs_element_retval_t *retval = NULL; bs_element_arg_t *arg = NULL; unsigned args_count; if (atom->val == BS_XML_RETVAL) { retval = func != NULL ? func->retval : method->retval; } else { args_count = func != NULL ? func->args_count : method->args_count; arg = &args[args_count - 1]; } // Determine if we deal with a block or a function pointer. const char *old_type = (retval ? retval->type : arg->type); const char lambda_type = *old_type == '@' ? _MR_C_LAMBDA_BLOCK : _MR_C_LAMBDA_FUNCPTR; char tmp_type[1025]; // 3 less to fit <, type and > char new_type[1028]; // Function ptr return type strlcpy(tmp_type, func_ptr->retval->type, sizeof(tmp_type)); // Function ptr args for (i = 0; i < func_ptr->args_count; i++) { strlcat(tmp_type, fptr_args[i].type, sizeof(tmp_type)); } // Clear the final type string memset(new_type, 0, sizeof(new_type)); // Append the function pointer type snprintf(new_type, sizeof(new_type), "%c%c%s%c", _MR_C_LAMBDA_B, lambda_type, tmp_type, _MR_C_LAMBDA_E); // Free the old values if (retval) { free(retval->type); retval->type = strdup(new_type); } else { free(arg->type); arg->type = strdup(new_type); } if (func_ptr->args_count > 0) { size_t len; len = sizeof(bs_element_arg_t) * func_ptr->args_count; func_ptr->args = (bs_element_arg_t *)malloc(len); ASSERT_ALLOC(func_ptr->args); memcpy(func_ptr->args, fptr_args, len); } else { func_ptr->args = NULL; } func_ptr = NULL; func_ptr_arg_depth = -1; } break; } case BS_XML_FUNCTION: { if (func == NULL) { break; } for (i = 0; i < func->args_count; i++) { if (args[i].type == NULL) BAIL("function '%s' argument #%d type not provided", func->name, i); } if (func->args_count > 0) { size_t len; len = sizeof(bs_element_arg_t) * func->args_count; func->args = (bs_element_arg_t *)malloc(len); ASSERT_ALLOC(func->args); memcpy(func->args, args, len); } bs_element = func; bs_element_type = BS_ELEMENT_FUNCTION; func = NULL; break; } case BS_XML_METHOD: { bs_element_method_t *methods; unsigned *methods_count; if (method->args_count > 0) { size_t len; len = sizeof(bs_element_arg_t) * method->args_count; method->args = (bs_element_arg_t *)malloc(len); ASSERT_ALLOC(method->args); memcpy(method->args, args, len); } index_method: methods = method->class_method ? klass->class_methods : klass->instance_methods; methods_count = method->class_method ? &klass->class_methods_count : &klass->instance_methods_count; if (methods == NULL) { methods = (bs_element_method_t *)malloc( sizeof(bs_element_method_t) * (*methods_count + 1)); } else { methods = (bs_element_method_t *)realloc(methods, sizeof(bs_element_method_t) * (*methods_count + 1)); } ASSERT_ALLOC(methods); // methods[*methods_count] = method; // FIXME this is inefficient memcpy(&methods[*methods_count], method, sizeof(bs_element_method_t)); (*methods_count)++; if (method->class_method) klass->class_methods = methods; else klass->instance_methods = methods; free(method); method = NULL; break; } case BS_XML_CLASS: { bs_element = klass; bs_element_type = BS_ELEMENT_CLASS; klass = NULL; break; } } } if (bs_element != NULL) (*callback)(parser, path, bs_element_type, bs_element, context); } success = true; bails: if (protocol_name != NULL) free(protocol_name); xmlFreeTextReader(reader); if (!success) { for (unsigned i = 0, count = CFArrayGetCount(parser->loaded_paths); i < count; i++) { CFStringRef s = CFArrayGetValueAtIndex(parser->loaded_paths, i); if (CFStringCompare(cf_path, s, kCFCompareCaseInsensitive) == kCFCompareEqualTo) { CFArrayRemoveValueAtIndex(parser->loaded_paths, i); break; } } } if (success && options == BS_PARSE_OPTIONS_LOAD_DYLIBS && framework_path != NULL) { char buf[PATH_MAX]; if (_bs_find_path(framework_path, buf, sizeof buf, "dylib")) { if (dlopen(buf, RTLD_LAZY) == NULL) { if (error != NULL) { *error = dlerror(); } success = false; } } } return success; }
static bool undecorate_struct_type(const char *src, char *dest, size_t dest_len, bs_element_struct_field_t *fields, size_t fields_count, int *out_fields_count) { const char *p_src; char *p_dst; char *pos; size_t src_len; unsigned field_idx; unsigned i; p_src = src; p_dst = dest; src_len = strlen(src); field_idx = 0; if (out_fields_count != NULL) *out_fields_count = 0; for (;;) { bs_element_struct_field_t *field; size_t len; field = field_idx < fields_count ? &fields[field_idx] : NULL; /* Locate the first field, if any. */ pos = strchr(p_src, '"'); /* Copy what's before the first field, or the rest of the source. */ len = MIN(pos == NULL ? src_len - (p_src - src) + 1 : pos - p_src, dest_len - (p_dst - dest)); strncpy(p_dst, p_src, len); p_dst += len; /* We can break if there wasn't any field. */ if (pos == NULL) break; /* Jump to the end of the field, saving the field name if necessary. */ p_src = pos + 1; pos = strchr(p_src, '"'); if (pos == NULL) { fprintf(stderr, "Can't find the end of field delimiter starting at %d\n", (int)(p_src - src)); goto bails; } if (field != NULL) { field->name = (char *)malloc((sizeof(char) * (pos - p_src)) + 1); ASSERT_ALLOC(field->name); strncpy(field->name, p_src, pos - p_src); field->name[pos - p_src] = '\0'; field_idx++; } p_src = pos + 1; pos = NULL; /* Save the field encoding if necessary. */ if (field != NULL) { char opposite; bool ok; int nested; opposite = *p_src == '{' ? '}' : *p_src == '(' ? ')' : *p_src == '[' ? ']' : 0; for (i = 0, ok = false, nested = 0; i < src_len - (p_src - src) && !ok; i++) { char c = p_src[i]; if (opposite != 0) { /* Encoding is a structure, we need to match the closing '}', * taking into account that other structures can be nested in it. */ if (c == opposite) { if (nested == 0) ok = true; else nested--; } else if (c == *p_src && i > 0) nested++; } else { /* Easy case, just match another field delimiter, or the end * of the encoding. */ if (c == '"' || c == '}') { i--; ok = true; } } } if (ok == false) { fprintf(stderr, "Can't find the field encoding starting at %d\n", (int)(p_src - src)); goto bails; } if (opposite == '}' || opposite == ')') { char buf[MAX_ENCODE_LEN]; char buf2[MAX_ENCODE_LEN]; strncpy(buf, p_src, MIN(sizeof buf, i)); buf[MIN(sizeof buf, i)] = '\0'; if (!undecorate_struct_type(buf, buf2, sizeof buf2, NULL, 0, NULL)) { fprintf(stderr, "Can't un-decode the field encoding '%s'\n", buf); goto bails; } len = strlen(buf2); field->type = (char *)malloc((sizeof(char) * len) + 1); ASSERT_ALLOC(field->type); strncpy(field->type, buf2, len); field->type[len] = '\0'; } else { field->type = (char *)malloc((sizeof(char) * i) + 1); ASSERT_ALLOC(field->type); strncpy(field->type, p_src, i); field->type[i] = '\0'; len = i; } strncpy(p_dst, field->type, len); p_src += i; p_dst += len; } } *p_dst = '\0'; if (out_fields_count != NULL) *out_fields_count = field_idx; return true; bails: /* Free what we allocated! */ for (i = 0; i < field_idx; i++) { free(fields[i].name); free(fields[i].type); } return false; }