cmod inherit question

View: New views
7 Messages — Rating Filter:   Alert me  

cmod inherit question

by Yvan Vander Sanden :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

hi.

Something i'm confused about (again :-). I've made this class/structure:

PIKECLASS HostApiInfo {
    PIKEVAR int structVersion;
    PIKEVAR int type;
    PIKEVAR string name;
    PIKEVAR int deviceCount;
    PIKEVAR int defaultInputDevice;
    PIKEVAR int defaultOutputDevice;
   
    INIT{

    }
   
    EXIT{
   
    }
}   

And want to use it in the next class:

PIKECLASS Control {
    INHERIT HostApiInfo;
    PIKEVAR HostApiInfo Info;

    PIKEFUN HostApiInfo get_host_api_info(int hostApi) {
        const PaHostApiInfo * info;
        info = Pa_GetHostApiInfo(hostApi);
        THIS->Info->structVersion = info->structVersion;
        [...]
        RETURN(THIS->Info);
    }

etc...

But it doesn't work that way. At least the HostApiInfo class was recognised as a PIKEVAR, but when i use the structVersion function the compiler complains:

    error: ‘struct object’ has no member named ‘structVersion’

I know, the structure is not initialized. But where and how to do that? I tried something like

   THIS->Info = HostApiInfo();

But that didn't help. Probably I could get around it this time by using a mapping instead of my own struct, but i'm gonna need the real thing sooner or later anyway, and using a mapping for this is just not my idea of good programming :-)

If anyone knows more about that, some hints would really help. Thanks!

yvan

--
Copyright only exists in the imagination of those who do not have any.

Re: cmod inherit question

by Bill Welliver :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

I'll take a stab at providing some places to look for answers...

I am a little conused, though... Control inherits HostApiInfo and also  
contains one as a member variable?

You might want to take a look at the source for the Public.Xapian  
module. It uses inheritance, though not really any PIKEVARS, though  
the data is accessed very similarly, due to the next little bit of  
information:

Though CMOD takes care of a lot of the basics for you, you're still  
essentially working on the C-level, so you'll need to write some C  
using the pike C api in order to get certain things done. As an  
example, in order to create an object of a particular type, you'll  
need to use one of the C-level functions that cause objects to be  
created, such as clone_object(). Also note that you'll need to push  
arguments for the clone, if any, onto the stack.

 From a practical standpoint, a PIKEVAR declaration just generates a  
struct member of the appropriate C-level pike datatype that gets added  
to the storage for the class. Then, I'm pretty sure it also causes the  
C-level struct to get mapped to the variable so that it's accessible  
at the Pike-level. I don't think that specifying the classname in the  
pikevar does anything useful for you; it probably just gets converted  
to an svalue placeholder or something similar.

I find it helpful to look at the source generated by the  
precompiler... there are a lot of macros that are useful in working  
with storage, and, for example, you'll be able to see what the struct  
* program is called so that you can clone the HostApiInfo class, and  
you'll see the macro that converts an object's generic storage into  
that of the class you want to access... your line for THIS->info-
 >structVer will probably become OBJ2_HOSTAPIINFO(THIS->info)-
 >structVersion or something similar.

Finally, I've gathered some info on C-level modules at the Pike  
Wiki... it's not completely organized, and there are certainly a lot  
of unanswered questions, but perhaps you'll find something useful.

http://www.gotpike.org/PikeWiki/index.pike/PikeDevel/C%20Modules

Good luck!

Bill

On Nov 3, 2009, at 3:48 PM, Yvan Vander Sanden wrote:

> hi.
>
> Something i'm confused about (again :-). I've made this class/
> structure:
>
> PIKECLASS HostApiInfo {
>     PIKEVAR int structVersion;
>     PIKEVAR int type;
>     PIKEVAR string name;
>     PIKEVAR int deviceCount;
>     PIKEVAR int defaultInputDevice;
>     PIKEVAR int defaultOutputDevice;
>
>     INIT{
>
>     }
>
>     EXIT{
>
>     }
> }
>
> And want to use it in the next class:
>
> PIKECLASS Control {
>     INHERIT HostApiInfo;
>     PIKEVAR HostApiInfo Info;
>
>     PIKEFUN HostApiInfo get_host_api_info(int hostApi) {
>         const PaHostApiInfo * info;
>         info = Pa_GetHostApiInfo(hostApi);
>         THIS->Info->structVersion = info->structVersion;
>         [...]
>         RETURN(THIS->Info);
>     }
>
> etc...
>
> But it doesn't work that way. At least the HostApiInfo class was  
> recognised as a PIKEVAR, but when i use the structVersion function  
> the compiler complains:
>
>     error: ‘struct object’ has no member named ‘structVersion’
>
> I know, the structure is not initialized. But where and how to do  
> that? I tried something like
>
>    THIS->Info = HostApiInfo();
>
> But that didn't help. Probably I could get around it this time by  
> using a mapping instead of my own struct, but i'm gonna need the  
> real thing sooner or later anyway, and using a mapping for this is  
> just not my idea of good programming :-)
>
> If anyone knows more about that, some hints would really help. Thanks!
>
> yvan
>
> --
> Copyright only exists in the imagination of those who do not have any.


Re: cmod inherit question

by Yvan Vander Sanden :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message



2009/11/4 H. William Welliver III <hww3@...>
I'll take a stab at providing some places to look for answers...

I am a little conused, though... Control inherits HostApiInfo and also contains one as a member variable?

Ah, yes. It is meant to be a member variable. I know that is not the way you're supposed to use inherit in c, but it works in Pike, and since my class was at least recognised since I added the inherit directive, i thought i was heading in the right direction.

After a night's sleep it looks less good, i must say :-) Thanks for pointing me to the C-level code. I thought using CMOD excluded the C-level functions. I guess I'd better take a look at them too.

Thanks!


--
Copyright only exists in the imagination of those who do not have any.

Re: cmod inherit question

by Johan Bj�rklund :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


A few things. The best way to know what CMOD does is to examine the
generated .c file and find the macros generated there.

The "THIS" macro is defined within each PIKECLASS block to cast the
storage-pointer of the "this" object to the struct defining the member
variables. That is why you can use -> references in c.

However, on the c-level, all object-type PIKEVARs are defined struct
*object.

> And want to use it in the next class:
>
> PIKECLASS Control {
>     INHERIT HostApiInfo;
>     PIKEVAR HostApiInfo Info;
This does work, and will be a struct *object. To access members in this
object from within this class, you must use the OBJ2_HOSTAPIINFO macro,
which casts an object into the struct you want.
>     PIKEFUN HostApiInfo get_host_api_info(int hostApi) {
>         const PaHostApiInfo * info;
>         info = Pa_GetHostApiInfo(hostApi);
>         THIS->Info->structVersion = info->structVersion;
This should be OBJ2_HOSTAPINFO(THIS->Info)->structVersion =
info->structVersion.
>         [...]
>         RETURN(THIS->Info);
>     }

> But it doesn't work that way. At least the HostApiInfo class was
> recognised as a PIKEVAR, but when i use the structVersion function the
> compiler complains:
>
>     error: ‘struct object’ has no member named ‘structVersion’
>
> I know, the structure is not initialized. But where and how to do
> that? I tried something like
>    THIS->Info = HostApiInfo();
This would be:

THIS->Info = low_clone(HostApiInfo_program);
call_c_initalizers(THIS->Info);

But because of INHERIT pike will make a new HostApiInfo object
automatically everytime a new Control object is made. The way to access
it is to use the get_storage(struct object*, struct program*) function.

Try something like this:

#define THISOBJ Pike_fp->current_object;

PIKECLASS HostApiInfo {
  /* ... */
}

#define SUPER_HOSTAPIINFO(o) ( ((struct HostApiInfo_struct *)
get_storage((o), HostApiInfo_program)) )

PIKECLASS Control {
  INHERIT HostApiInfo;

  PIKEFUN int set_version(int version) {
    RETURN (SUPER_HOSTAPIINFO(THISOBJ)->structVersion = version);
  }
}

(I might have missed a bracket or two and it be slightly wrong but the
that's the basics)

When you use reference types such as objects and strings in CMOD, you
must initalize them, otherwise they will blow up in pike:

PIKECLASS HostApiInfo {
    PIKEVAR string name;
 
    INIT{
      THIS->name = NULL;
    }
   
    EXIT{
      if (THIS->name != NULL) free_string(THIS->name);
    }
}

You should use a pike compiled with the "--with-checker" option.
Otherwise you won't see your memory problems.


Re: cmod inherit question

by Henrik Grubbström-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Tue, 10 Nov 2009, Johan Björklund wrote:

> A few things. The best way to know what CMOD does is to examine the generated
> .c file and find the macros generated there.
>
> The "THIS" macro is defined within each PIKECLASS block to cast the
> storage-pointer of the "this" object to the struct defining the member
> variables. That is why you can use -> references in c.
>
> However, on the c-level, all object-type PIKEVARs are defined struct *object.
[...]
>> I know, the structure is not initialized. But where and how to do that? I
>> tried something like
>>    THIS->Info = HostApiInfo();
> This would be:
>
> THIS->Info = low_clone(HostApiInfo_program);
> call_c_initalizers(THIS->Info);

A more common case would be to use clone_object() (which calls
call_c_initializers() (and call_pike_initializers()) for you)
instead of low_clone().

> When you use reference types such as objects and strings in CMOD, you must
> initalize them, otherwise they will blow up in pike:
>
> PIKECLASS HostApiInfo {
>   PIKEVAR string name;
>    INIT{
>     THIS->name = NULL;
>   }
>     EXIT{
>     if (THIS->name != NULL) free_string(THIS->name);
>   }
> }
Actually, PIKEVARs are automatically initialized (to 0, NULL or 0.0
depending on type) and freed on exit, so both INIT and EXIT in the above
example are redundant. CVARs on the other hand are NOT initialized
or freed automatically (unless they've been mapped by hand), and will need
INIT and EXIT code.

> You should use a pike compiled with the "--with-checker" option. Otherwise
> you won't see your memory problems.

Not quite; --with-checker adds some code to simplify analysis by C-level
code checkers (eg valgrind, purify, coverity etc). Most consistency checks
are added by --with-rtldebug (runtime-level debug).

--
Henrik Grubbström grubba@...
Roxen Internet Software AB

Re: cmod inherit question

by Johan Bj�rklund :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Henrik Grubbström wrote:
>
> Not quite; --with-checker adds some code to simplify analysis by
> C-level code checkers (eg valgrind, purify, coverity etc). Most
> consistency checks are added by --with-rtldebug (runtime-level debug).
>

I think "--with-cleanup-on-exit" is the one I was really thinking of. It
gives a list of the leaked objects with line numbers?

  --with-cleanup-on-exit            Do full cleanup at exit to detect
leaks better.
  --with-dmalloc                    Enable memory leak checks.
  --with-dmalloc-malloc             Enable overloading of malloc(3)
  --with-dmalloc-malloc-leaks       Report memory allocated by malloc(3)
as leaks.
  --with-dmalloc-trace              enable tracepoints
  --with-dmalloc-c-stack-trace      record C stack traces for block
allocations
  --with-dmalloc-track-free         track freed memory too
  --with-debug                      same as --with-cdebug --with-rtldebug
  --without-debug                   same as --without-cdebug
--without-rtldebug
  --with-rtldebug                   enable run time self tests


It might it be worth it to try all of these when writing a cmod.



Re: cmod inherit question

by Martin Stjernholm :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Johan Björklund <johbjo09@...> skrev:

> I think "--with-cleanup-on-exit" is the one I was really thinking of.
> It gives a list of the leaked objects with line numbers?

You get line numbers where the block has been only if you combine it
with --with-dmalloc, but note that it also makes pike a lot slower and
memory consuming. If you also add --with-dmalloc-c-stack-trace, you'll
get backtraces of the C stack where the leaked blocks were allocated,
provided you're using GNU libc.