Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

wrapping structures

Status
Not open for further replies.

stillflame

Programmer
Jan 12, 2001
416
0
0
hey all,

this is likely well beyond the scope of what any of you have done with ruby, but i figured i'd ask it here, and at least answer it myself when and if i figure it out.

i have a problem writing this ruby extension 'o mine, and i was wondering if anyone could help me figure out why. i've narrowed it down to me not knowing enough about how ruby is wrapping structures, and how i have to treat those objects. for starters, i'm not really a wiz in c - this may be more at the root of my problem than anything else. my current guesses point to somewhere in the memory allocation area or in the Data_(Get|Wrap)_Struct calls, but i don't really know.

anyway, here's a piece of my c coding that should (hopefully) show where i'm having the problem. nothing in it will really be important except the "Data_(Wrap|Get)_Struct" parts and what they deal with, as the rest i have verified as functional with non-ruby-extending test programs that use the same fuctions (but i left it in to help describe the setting):

#################### C code starts here [tt]

VALUE cDictionary;

static void LP_dict_delete(void *p)
{
Dictionary *q;
q = p;
dictionary_delete(*q);
/* int dictionary_delete(Dictionary) */
}

VALUE LP_dict_new(VALUE class, VALUE dict_names)
{
VALUE rb_dict;
VALUE argv[1];
Dictionary *LP_dict;
*LP_dict = dictionary_create(
STR2CSTR(rb_ary_shift(dict_names)),
STR2CSTR(rb_ary_shift(dict_names)),
STR2CSTR(rb_ary_shift(dict_names)),
STR2CSTR(rb_ary_shift(dict_names)));
argv[0] = rb_dict = Data_Wrap_Struct(class, 0, LP_dict_delete, LP_dict);
rb_obj_call_init(rb_dict, 1, argv);
return rb_dict;
}

static VALUE LP_dict_init(VALUE self, VALUE dict_names)
{
rb_iv_set(self, "@dict_names", dict_names);
return self;
}

static VALUE LP_dict_get_max_cost(VALUE self)
{
Dictionary *LP_dict;
int cost;
Data_Get_Struct(self, Dictionary, LP_dict);
cost = dictionary_get_max_cost(*LP_dict);
return INT2NUM(cost);
}
[/tt]
## then later, in the Init subroutine, this is the relevant part: [tt]

cDictionary = rb_define_class_under(mLinkParsing, "Dictionary", rb_cObject);
rb_define_singleton_method(cDictionary, "new", LP_dict_new, 1);
rb_define_method(cDictionary, "initialize", LP_dict_init, 1);
rb_define_method(cDictionary, "get_max_cost", LP_dict_get_max_cost, 0);
[/tt]
#################### C code ends here

in the test script:
----------------------------- [tt]
#'require's and stuff...
dict = Dictionary.new(dict_names)
dict.get_max_cost()
test.rb:20: [BUG] Segmentation fault
ruby 1.7.0 (2001-05-17) [i686-linux]
Aborted
[/tt]
-----------------------------

and also:
----------------------------- [tt]
dict = Dictionary.new(dict_names)
dict = nil
GC.start
test.rb:21: [bug] rb_gc_mark(): unknown data type 0x28(0x4034b690) corrupted object
ruby 1.7.0 (2001-05-17) [i686-linux]
Aborted [/tt]

-----------------------------

i know - ruby version 1.7.0, but i tried it with 1.6.3 to the same effect, so that's not an issue. for the most part, this seems to have the same structure as the example that Dave and /\ndy give in their book (p. 181), but, well i don't know - if i knew how to debug c stuff better, i could probly figure this out on my own, but, as it is, i've hit a dead end as to how i should attack this problem. i've tried pre-ALLOC-ing the Dictionary struct, but dictionary_create does that for itself:
--------------------------------------- [tt]
static Dictionary internal_dictionary_create(char * dict_name, char * pp_name, char * cons_name, char * affix_name, char * path) {
Dictionary dict;
static int rand_table_inited=FALSE;
Dict_node *dict_node;
char * dictionary_path_name;
dict = (Dictionary) xalloc(sizeof(struct Dictionary_s));
/* then fills that structure */
[/tt]
---------------------------------------
(note: in addition to 'xalloc', the program i'm wrapping also defines and uses an 'xfree'. this matters only because ruby.h has a macro that redefines 'xfree' to 'ruby_xfree' - i get errors unless i include the program's files before ruby's.)

there's lots of other things i've tried, in fact i've came up with a few more ideas while writing this letter, but (...time passes) to no avail. all i think i'm asking for is suggestions on where i should look to solve this.

thank you, anyone who takes the time to consider this,

stillflame "If you think you're too small to make a difference, try spending a night in a closed tent with a mosquito."
 
well, with some help from ruby-talk, i'm a little bit further along with this extension, but i cannot figure out what is going on behind the scenes. i changed the code a little, and the passing around of the structure is now alot more natural, however, i'm still getting seg faults. i'll illustrate where.

changing the LP_dict_get_max_cost subroutine to the following, while not producing any useful results, does not cause a seg fault:[tt]
static VALUE LP_dict_get_max_cost(VALUE self)
{
Dictionary LP_dict;
VALUE return_me;
int cost;

Data_Get_Struct(self, struct Dictionary_s, LP_dict);

cost = LP_dict->max_cost;
return_me = INT2NUM(cost);
return INT2NUM(1);
}
[/tt]
but if i make it usable by having it return the actual 'return_me' variable, it seg faults. everything is fine until i try to return it. i cannot figure out why. unwrapping the structure doesn't produce any errors, reading one of the structure's attributes is fine, as well as manipulating that value, but if i even try a roundabout process to return the useful value this subroutine should, it fails (although i am allowed to return 'sizeof' values, so i have determined that things do in fact exist within the structure after it has been unwrapped). i'm not sure if i should look into the INT2NUM processes, or what... maybe the program i'm wrapping should be forced to use the xalloc and xfree that ruby has (the particular struct i'm wrapping is pretty complex in it's initialization, with multiple pointers to structures that get alloced separately (but still during the initialization step) and this complexness may be fooling with the actual wrapping of the structure.) ?
*sigh*
i can't wait till i'm done coding this c stuff and can play in ruby some more... "If you think you're too small to make a difference, try spending a night in a closed tent with a mosquito."
 
well, i've figured out that the problem lies in the complexity which is the Dictionary structure. i can wrap and unwrap simpler structures without the seg fault, however Dictionary, and the other structure which will use Dictionary, are really twisted and full of stuff. i don't know what's tripping up ruby - the linked lists like Dict_node, or just the humungousness of it (which sure does cause my brain to seg fault). i might be able to make a trimmed down version, limiting it to only those parts that will get used, but i won't be able to trim much (the postprocessors can go, and they are pretty big themselves).

here's what it looks like ('+'s mean nested structure. also, i didn't finish the post processor structure, it's way to deep):[tt]
struct Dictionary_s {
- Dict_node * root;
- char * string;
- Word_file * file;
- char file[MAX_PATH_NAME+1];
- int changed;
+ Word_file * next;

- Exp * exp;
+ Dict_node *left, *right;

- char * name;
- int use_unknown_word;
- int unknown_word_defined;
- int capitalized_word_defined;
- int pl_capitalized_word_defined;
- int hyphenated_word_defined;
- int number_word_defined;
- int ing_word_defined;
- int s_word_defined;
- int ed_word_defined;
- int ly_word_defined;
- int left_wall_defined;
- int right_wall_defined;
- Postprocessor * postprocessor;
- pp_knowledge *knowledge;
- PPLexTable *lt;
- char *path;
- pp_linkset *domain_starter_links;
- pp_linkset *urfl_domain_starter_links;
- pp_linkset *urfl_only_domain_starter_links;
- pp_linkset *domain_contains_links;
- pp_linkset *must_form_a_cycle_links;
- pp_linkset *restricted_links;
- pp_linkset *ignore_these_links;
- pp_linkset *left_domain_starter_links;
- pp_rule *connected_rules;
- pp_rule *form_a_cycle_rules;
- pp_rule *contains_one_rules;
- pp_rule *contains_none_rules;
- pp_rule *bounded_rules;
- int n_connected_rules, n_form_a_cycle_rules;
- int n_contains_one_rules, n_contains_none_rules;
- int n_bounded_rules;
- pp_linkset *set_of_links_starting_bounded_domain;
- StartingLinkAndDomain *starting_link_lookup_table;
- int nStartingLinks;
- String_set *string_set;

- int n_global_rules_firing;
- int n_local_rules_firing;
- pp_linkset *set_of_links_of_sentence;
- pp_linkset *set_of_links_in_an_active_rule;
- int *relevant_contains_one_rules;
- int *relevant_contains_none_rules;
- String_set *sentence_link_name_set;
- int visited[MAX_SENTENCE];
- PP_node *pp_node;
- PP_data pp_data;

- Postprocessor * constituent_pp;
+ Dictionary affix_table;
- int andable_defined;
- Connector_set * andable_connector_set;
- Connector ** hash_table;
- int table_size;
- int is_defined;
- Connector_set * unlimited_connector_set;
- int max_cost;
- String_set * string_set;
- int size;
- int count;
- char ** table;

- int num_entries;
- Word_file * word_file_header;
- char file[MAX_PATH_NAME+1];
- int changed;
+ Word_file * next;

- Exp * exp_list;
- char type;
- unsigned char cost;
- char dir;
- char multi;
- union {
- E_list * l;
+ E_list * next;
- Exp * e;
- char * string;
- }u;
+ Exp * next;

- FILE * fp;
- char token[MAX_TOKEN_LENGTH];
- int is_special;
- int already_got_it;
- int line_number;
};
[/tt]

sometimes i think i was never meant to program in c... sorry to use this forum as a place to document this process, but i figure not many people are going to read this anytime, so it shouldn't matter too much.

stillflame. "If you think you're too small to make a difference, try spending a night in a closed tent with a mosquito."
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top