[PATCH] Pass ByteArray as #cObject

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

[PATCH] Pass ByteArray as #cObject

Paolo Bonzini-2
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  <[hidden email]>
   
        * libgst/cint.c: Allow passing any object with non-pointer indexed
        instance variables as a #cObject.
   
packages/digest:
2008-05-15  Paolo Bonzini  <[hidden email]>
   
        * 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  <[hidden email]>
   
        * 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
+@code{#smalltalk}, 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 *
+@item 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 )>
 
     ]
 

_______________________________________________
help-smalltalk mailing list
[hidden email]
http://lists.gnu.org/mailman/listinfo/help-smalltalk