help-smalltalk
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Help-smalltalk] [PATCH] Pass ByteArray as #cObject


From: Paolo Bonzini
Subject: [Help-smalltalk] [PATCH] Pass ByteArray as #cObject
Date: Thu, 15 May 2008 08:22:57 +0200
User-agent: Thunderbird 2.0.0.14 (Macintosh/20080421)

And actually any object with non-pointer indexed instance variables can be passed as #cObject. The catch is that it will break if the function causes a garbage collection, so this must be used with care! (The same shortcoming, actually, applies to garbage-collected CObjects).

In the case of MD5 and TCP, however, it works great and removes a copy operation. In general, this is perfectly safe for functions that do not access the #cObject-passed values after creating new objects or having called back into smalltalk. In case the function does one of these two things, #cObject should be used only for heap-allocated data, or for pointers that were returned by another C function.

Paolo
libgst:
2008-05-15  Paolo Bonzini  <address@hidden>
    
        * libgst/cint.c: Allow passing any object with non-pointer indexed
        instance variables as a #cObject.
    
packages/digest:
2008-05-15  Paolo Bonzini  <address@hidden>
    
        * md5.st: Pass data to C functions as #cObject.
        * sha1.st: Pass data to C functions as #cObject.
    
packages/tcp:
2008-05-15  Paolo Bonzini  <address@hidden>
    
        * AbstractSocketImpl.st: Replace ByteArray buffers with
        garbage-collected CObjects.
        * IPSocketImpl.st: Likewise.
        * cfuncs.st: Change #byteArray and #byteArrayOut arguments
        to #cObject.

diff --git a/doc/gst.texi b/doc/gst.texi
index e091754..c9a0746 100644
--- a/doc/gst.texi
+++ b/doc/gst.texi
@@ -3320,7 +3320,16 @@ passed as @code{double}
 passed as @code{long double}
 
 @item cObject     
-C object value passed as @code{void *}
+C object value passed as @code{void *}.
+
+Any class with non-pointer indexed instance variables can be passed as
+a @code{#cObject}, and GNU Smalltalk will pass the address of the first indexed
+instance variable.  This however should never be done for functions that
+allocate objects, call back into Smalltalk code or otherwise may cause
+a garbage collection: after a GC, pointers passed as @code{#cObject} may be
+invalidated.  In this case, it is safer to pass every object as
address@hidden, or to only pass @code{CObject}s that were returned
+by a C function previously.
 
 @item cObjectPtr
 Pointer to C object value passed as @code{void **}.  The @code{CObject}
@@ -3354,6 +3363,7 @@ Table of parameter conversions:
 @item boolean             @tab Boolean (True, False)@tab int
 @item byteArray           @tab ByteArray            @tab char *
 @item cObject             @tab CObject              @tab void *
address@hidden cObject             @tab ByteArray, etc.      @tab void *
 @item cObjectPtr          @tab CObject              @tab void **
 @item char                @tab Boolean (True, False)@tab int
 @item char                @tab Character            @tab int (C promotion rule)
diff --git a/libgst/cint.c b/libgst/cint.c
index c4ed5d8..a1e91d6 100644
--- a/libgst/cint.c
+++ b/libgst/cint.c
@@ -1138,6 +1138,23 @@ push_smalltalk_obj (OOP oop,
        }
     }
 
+  /* #cObject can pass every object with non-pointer indexed instance
+     variables.  */
+  if (cType == CDATA_COBJECT)
+    {
+      switch (CLASS_INSTANCE_SPEC (class) & ISP_INDEXEDVARS)
+       {
+       case GST_ISP_FIXED:
+       case GST_ISP_POINTER:
+         break;
+
+       default:
+         /* Byte indexed variables, pass the pointer through.  */
+         cp->u.ptrVal = OOP_TO_OBJ (oop)->data + CLASS_FIXED_FIELDS (class);
+         SET_TYPE (&ffi_type_pointer);
+         return;
+       }
+    }
 
   bad_type (class, cType);
 }
diff --git a/packages/digest/md5.st b/packages/digest/md5.st
index 58c33a0..1d1594e 100644
--- a/packages/digest/md5.st
+++ b/packages/digest/md5.st
@@ -49,13 +49,13 @@ MessageDigest subclass: MD5 [
 
     combine: input size: len into: context [
        <category: 'C call-outs'>
-       <cCall: 'MD5Update' returning: #void args: #(#byteArray #int 
#byteArrayOut)>
+       <cCall: 'MD5Update' returning: #void args: #(#cObject #int #cObject)>
        
     ]
 
     finalize: state in: digest [
        <category: 'C call-outs'>
-       <cCall: 'MD5Final' returning: #void args: #(#byteArray #byteArrayOut)>
+       <cCall: 'MD5Final' returning: #void args: #(#cObject #cObject)>
        
     ]
 
diff --git a/packages/digest/sha1.st b/packages/digest/sha1.st
index feadac3..b76ad7d 100644
--- a/packages/digest/sha1.st
+++ b/packages/digest/sha1.st
@@ -49,13 +49,13 @@ MessageDigest subclass: SHA1 [
 
     combine: input size: len into: context [
        <category: 'C call-outs'>
-       <cCall: 'SHA1Update' returning: #void args: #(#byteArray #int 
#byteArrayOut)>
+       <cCall: 'SHA1Update' returning: #void args: #(#cObject #int #cObject)>
        
     ]
 
     finalize: state in: digest [
        <category: 'C call-outs'>
-       <cCall: 'SHA1Final' returning: #void args: #(#byteArray #byteArrayOut)>
+       <cCall: 'SHA1Final' returning: #void args: #(#cObject #cObject)>
        
     ]
 
diff --git a/packages/tcp/AbstractSocketImpl.st 
b/packages/tcp/AbstractSocketImpl.st
index 79d6f74..32d03d0 100644
--- a/packages/tcp/AbstractSocketImpl.st
+++ b/packages/tcp/AbstractSocketImpl.st
@@ -78,15 +78,14 @@ FileDescriptor subclass: AbstractSocketImpl [
         active server socket."
 
        <category: 'socket operations'>
-       | peer sizePtr newFD fd |
+       | peer addrLen newFD fd |
        peer := ByteArray new: CSockAddrStruct sizeof.
-       sizePtr := ByteArray new: CInt sizeof.
-       sizePtr intAt: 1 put: CSockAddrStruct sizeof.
+       addrLen := CInt gcValue: CSockAddrStruct sizeof.
        (fd := self fd) isNil ifTrue: [ ^SystemExceptions.EndOfStream signal ].
        newFD := self 
                    accept: fd
                    peer: peer
-                   addrLen: sizePtr.
+                   addrLen: addrLen.
        ^(implementationClass on: newFD)
            hasBeenBound;
            hasBeenConnectedTo: peer;
@@ -192,15 +191,14 @@ FileDescriptor subclass: AbstractSocketImpl [
         local endpoint of the socket."
 
        <category: 'socket operations'>
-       | sock sizePtr fd |
+       | sock addrLen fd |
        sock := ByteArray new: CSockAddrStruct sizeof.
-       sizePtr := ByteArray new: CInt sizeof.
-       sizePtr intAt: 1 put: CSockAddrStruct sizeof.
+       addrLen := CInt gcValue: CSockAddrStruct sizeof.
        (fd := self fd) isNil ifTrue: [ ^nil ].
        self 
            getSockName: fd
            addr: sock
-           addrLen: sizePtr.
+           addrLen: addrLen.
        ^sock
     ]
 
@@ -273,17 +271,16 @@ FileDescriptor subclass: AbstractSocketImpl [
         so this will be rarely used."
 
        <category: 'socket options'>
-       | result sizeArray fd |
+       | result len fd |
        result := ByteArray new: size.
-       sizeArray := ByteArray new: CInt sizeof.
-       sizeArray intAt: 1 put: size.
+       len := CInt gcValue: size.
        (fd := self fd) isNil ifTrue: [ ^nil ].
        self 
            option: fd
            level: level
            at: opt
            get: result
-           size: sizeArray.
+           size: len.
        ^result
     ]
 
@@ -538,15 +535,14 @@ AbstractSocketImpl subclass: SocketImpl [
         remote endpoint of the socket."
 
        <category: 'socket operations'>
-       | peer sizePtr fd |
+       | peer addrLen fd |
        peer := ByteArray new: CSockAddrStruct sizeof.
-       sizePtr := ByteArray new: CInt sizeof.
-       sizePtr intAt: 1 put: CSockAddrStruct sizeof.
+       addrLen := CInt gcValue: CSockAddrStruct sizeof.
        (fd := self fd) isNil ifTrue: [ ^nil ].
        self 
            getPeerName: self fd
            addr: peer
-           addrLen: sizePtr.
+           addrLen: addrLen.
        ^peer
     ]
 
@@ -638,10 +634,9 @@ AbstractSocketImpl subclass: DatagramSocketImpl [
 
        <category: 'socket operations'>
        | address port data from addrLen fd |
-       addrLen := ByteArray new: CInt sizeof.
        data := ByteArray new: self bufferSize.
        from := ByteArray new: CSockAddrStruct sizeof.
-       addrLen intAt: 1 put: from size.
+       addrLen := CInt gcValue: from size.
        (fd := self fd) isNil ifTrue: [ ^SystemExceptions.EndOfStream signal ].
        self 
            receive: fd
@@ -664,7 +659,7 @@ AbstractSocketImpl subclass: DatagramSocketImpl [
        <category: 'socket operations'>
        | size receiver fd |
        theReceiver isNil 
-           ifTrue: [receiver := size := 0]
+           ifTrue: [receiver := nil. size := 0]
            ifFalse: 
                [receiver := theReceiver port: port.
                size := receiver size].
diff --git a/packages/tcp/IPSocketImpl.st b/packages/tcp/IPSocketImpl.st
index bffa5b2..65f0d45 100644
--- a/packages/tcp/IPSocketImpl.st
+++ b/packages/tcp/IPSocketImpl.st
@@ -340,22 +340,20 @@ SocketAddress subclass: IPAddress [
        <category: 'private'>
        port < 0 | (port > 65535) ifTrue: [self error: 'port out of range'].
        ^(ByteArray new: CSockAddrStruct sizeof)
+           "Write sin_addr"
            replaceFrom: CSockAddrStruct sizeof - 11
                to: CSockAddrStruct sizeof - 8
                with: address
                startingAt: 1;
+
+           "Write sin_family = AF_INET in host order"
            shortAt: 1 put: self class addressFamily;
+
+           "Write sin_port in network order (big endian)"
            at: CSockAddrStruct sizeof - 13 put: port // 256;
            at: CSockAddrStruct sizeof - 12 put: (port bitAnd: 255);
            yourself
 
-       "Write sin_addr"
-
-       "Write sin_family = AF_INET in host order"
-
-       "Write sin_port in network order (big endian)"
-
-       "ouf..."
     ]
 ]
 
@@ -548,6 +546,10 @@ RawSocketImpl subclass: ICMPSocketImpl [
 
 Eval [
     CStruct newStruct: #CSockAddrStruct
-       declaration: #(#(#sinFamily #short) #(#sinPort #(#array #byte 2)) 
#(#sinAddr #(#array #byte 4)) #(#sinZero #(#array #byte 8)))
+       declaration: #(
+               #(#sinFamily #short)
+               #(#sinPort #(#array #byte 2))
+               #(#sinAddr #(#array #byte 4))
+               #(#sinZero #(#array #byte 8)))
 ]
 
diff --git a/packages/tcp/cfuncs.st b/packages/tcp/cfuncs.st
index f0d4010..0cf2c1f 100644
--- a/packages/tcp/cfuncs.st
+++ b/packages/tcp/cfuncs.st
@@ -184,7 +184,7 @@ SocketAddress class extend [
     primName: address len: len type: addressFamily [
        <category: 'C call-outs'>
        <cCall: 'TCPgetHostByAddr' returning: #stringOut
-       args: #(#byteArray #int #int)>
+       args: #(#cObject #int #int)>
        
     ]
 
@@ -204,7 +204,7 @@ IPAddress class extend [
     primAnyLocalAddress: hostName in: byteArray [
        <category: 'C call-outs'>
        <cCall: 'TCPgetAnyLocalAddress' returning: #void
-       args: #(#string #byteArrayOut)>
+       args: #(#string #cObject)>
        
     ]
 
@@ -217,21 +217,21 @@ AbstractSocketImpl extend [
     accept: socket peer: peer addrLen: len [
        <category: 'C call-outs'>
        <cCall: 'TCPaccept' returning: #int
-       args: #(#int #byteArrayOut #byteArray )>
+       args: #(#int #cObject #cObject )>
        
     ]
 
     bind: socket to: addr addrLen: len [
        <category: 'C call-outs'>
        <cCall: 'TCPbind' returning: #int
-       args: #(#int #byteArray #int )>
+       args: #(#int #cObject #int )>
        
     ]
 
     connect: socket to: addr addrLen: len [
        <category: 'C call-outs'>
        <cCall: 'TCPconnect' returning: #int
-       args: #(#int #byteArray #int )>
+       args: #(#int #cObject #int )>
        
     ]
 
@@ -245,42 +245,42 @@ AbstractSocketImpl extend [
     getPeerName: socket addr: addr addrLen: len [
        <category: 'C call-outs'>
        <cCall: 'TCPgetpeername' returning: #int
-       args: #(#int #byteArrayOut #byteArray )>
+       args: #(#int #cObject #cObject )>
        
     ]
 
     getSockName: socket addr: addr addrLen: len [
        <category: 'C call-outs'>
        <cCall: 'TCPgetsockname' returning: #int
-       args: #(#int #byteArrayOut #byteArray )>
+       args: #(#int #cObject #cObject )>
        
     ]
 
     receive: socket buffer: buf size: len flags: flags from: addr size: 
addrLen [
        <category: 'C call-outs'>
        <cCall: 'TCPrecvfrom' returning: #int
-       args: #(#int #byteArrayOut #int #int #byteArray #byteArrayOut )>
+       args: #(#int #cObject #int #int #cObject #cObject )>
        
     ]
 
     send: socket buffer: buf size: len flags: flags to: addr size: addrLen [
        <category: 'C call-outs'>
        <cCall: 'TCPsendto' returning: #int
-       args: #(#int #byteArray #int #int #unknown #int )>
+       args: #(#int #cObject #int #int #cObject #int )>
        
     ]
 
     option: socket level: level at: name put: value size: len [
        <category: 'C call-outs'>
        <cCall: 'TCPsetsockopt' returning: #int
-       args: #(#int #int #int #byteArray #int )>
+       args: #(#int #int #int #cObject #int )>
        
     ]
 
     option: socket level: level at: name get: value size: len [
        <category: 'C call-outs'>
        <cCall: 'TCPgetsockopt' returning: #int
-       args: #(#int #int #int #byteArrayOut #byteArrayOut )>
+       args: #(#int #int #int #cObject #cObject )>
        
     ]
 
@@ -300,21 +300,21 @@ AbstractSocketImpl class extend [
     accept: socket peer: peer addrLen: len [
        <category: 'C call-outs'>
        <cCall: 'TCPaccept' returning: #int
-       args: #(#int #byteArrayOut #byteArray )>
+       args: #(#int #cObject #cObject )>
        
     ]
 
     bind: socket to: addr addrLen: len [
        <category: 'C call-outs'>
        <cCall: 'TCPbind' returning: #int
-       args: #(#int #byteArray #int )>
+       args: #(#int #cObject #int )>
        
     ]
 
     connect: socket to: addr addrLen: len [
        <category: 'C call-outs'>
        <cCall: 'TCPconnect' returning: #int
-       args: #(#int #byteArray #int )>
+       args: #(#int #cObject #int )>
        
     ]
 
@@ -328,42 +328,42 @@ AbstractSocketImpl class extend [
     getPeerName: socket addr: addr addrLen: len [
        <category: 'C call-outs'>
        <cCall: 'TCPgetpeername' returning: #int
-       args: #(#int #byteArrayOut #byteArray )>
+       args: #(#int #cObject #cObject )>
        
     ]
 
     getSockName: socket addr: addr addrLen: len [
        <category: 'C call-outs'>
        <cCall: 'TCPgetsockname' returning: #int
-       args: #(#int #byteArrayOut #byteArray )>
+       args: #(#int #cObject #cObject )>
        
     ]
 
     receive: socket buffer: buf size: len flags: flags from: addr size: 
addrLen [
        <category: 'C call-outs'>
        <cCall: 'TCPrecvfrom' returning: #int
-       args: #(#int #byteArrayOut #int #int #byteArray #byteArrayOut )>
+       args: #(#int #cObject #int #int #cObject #cObject )>
        
     ]
 
     send: socket buffer: buf size: len flags: flags to: addr size: addrLen [
        <category: 'C call-outs'>
        <cCall: 'TCPsendto' returning: #int
-       args: #(#int #byteArray #int #int #unknown #int )>
+       args: #(#int #cObject #int #int #cObject #int )>
        
     ]
 
     option: socket level: level at: name put: value size: len [
        <category: 'C call-outs'>
        <cCall: 'TCPsetsockopt' returning: #int
-       args: #(#int #int #int #byteArray #int )>
+       args: #(#int #int #int #cObject #int )>
        
     ]
 
     option: socket level: level at: name get: value size: len [
        <category: 'C call-outs'>
        <cCall: 'TCPgetsockopt' returning: #int
-       args: #(#int #int #int #byteArrayOut #byteArrayOut )>
+       args: #(#int #int #int #cObject #cObject )>
        
     ]
 

reply via email to

[Prev in Thread] Current Thread [Next in Thread]