[Vm-dev] Slang newbie question
Ronald Spengler
ron.spengler at gmail.com
Tue Sep 15 02:58:32 UTC 2009
Okay, reread the code, realized that the comments actually answer
every question I have except "how do I guarantee that the garbage
collector doesn't run"
On Mon, Sep 14, 2009 at 7:36 PM, Ronald Spengler <ron.spengler at gmail.com> wrote:
> Thanks Dave! That helps a lot. This snippet scares me a little bit though:
> "in a section of code in which the garbage collector is guaranteed not to run"
>
> I realize now that:
> - I don't know how to guarantee that the gc won't run
> - My C library will take it's sweet time running, and it's runtime is
> a function of it's input, could be forever in the extreme case.
>
> So, to be safe, on the C side of things, should I copy the string
> ASAP? Or does C code escape the garbage collector? Is it safe to
> malloc()?
>
> Thanks again for your help, and please forgive my ignorance.
>
>
> On Sun, Sep 13, 2009 at 6:56 PM, David T. Lewis <lewis at mail.msen.com> wrote:
>>
>> On Sun, Sep 13, 2009 at 01:23:32PM -0700, Ronald Spengler wrote:
>> >
>> > Hello everyone.
>> > I have a named primitive, and I need to send a ByteString to it, to be
>> > processed and returned by an external library. To get a string into Slang,
>> > should I send it #asByteArray, and would that let me treat the bytes as
>> > integers on the stack? I'm basically trying to get a char* on the other
>> > side.
>>
>> You can use the ByteString as a parameter to the primitive, no problem.
>> The only tricky bit is that C expects null terminated strings, so you need
>> to copy the contents of the ByteString into a null terminated array before
>> you can let it be used by the C library as a char *.
>>
>> I'm sure there are lots of examples, but you can look at
>> OSProcessPlugin>>cStringFromString: and OSProcess>>transientCStringFromString:
>> for examples of how to copy the string buffer into a null terminated buffer
>> for use in C. Look at senders of these two methods for examples of primitives
>> that pass strings as parameters. (OSProcessPlugin is on SqueakSource if you
>> do not have it).
>>
>> Following are a couple of examples taken from OSPP. In both cases, a buffer
>> is allocated with size one greater than the string length, and the contents
>> of the Smalltalk string are copied into the buffer space with a trailing
>> null terminator. The #primitiveChdir example allocates a new Smalltalk
>> string to use for the buffer, and #primitivePutEnv uses malloc to allocate
>> the new buffer (because in this case the buffer must be "permanently" valid
>> after the primitive exits).
>>
>> primitiveChdir
>> "Call chdir(2) to change current working directory to the specified path string. Answer
>> nil for success, or errno on failure."
>>
>> | path errno |
>> self export: true.
>> self var: 'path' type: 'char *'.
>> self var: 'errno' type: 'extern int'.
>> path := self transientCStringFromString: (interpreterProxy stackObjectValue: 0).
>> (self chdir: path)
>> ifTrue: [interpreterProxy pop: 2; push: interpreterProxy nilObject]
>> ifFalse: [interpreterProxy pop: 2; pushInteger: errno].
>>
>> transientCStringFromString: aString
>> "Answer a new null-terminated C string copied from aString.
>> The string is allocated in object memory, and will be moved
>> without warning by the garbage collector. Any C pointer
>> reference the the result is valid only until the garbage
>> collector next runs. Therefore, this method should only be used
>> within a single primitive in a section of code in which the
>> garbage collector is guaranteed not to run. Note also that
>> this method may itself invoke the garbage collector prior
>> to allocating the new C string.
>>
>> Warning: The result of this method will be invalidated by the
>> next garbage collection, including a GC triggered by creation
>> of a new object within a primitive. Do not call this method
>> twice to obtain two string pointers."
>>
>> | len stringPtr newString cString |
>> self returnTypeC: 'char *'.
>> self var: 'stringPtr' declareC: 'char *stringPtr'.
>> self var: 'cString' declareC: 'char *cString'.
>> len := interpreterProxy sizeOfSTArrayFromCPrimitive: (interpreterProxy arrayValueOf: aString).
>> "Allocate space for a null terminated C string."
>> interpreterProxy pushRemappableOop: aString.
>> newString := interpreterProxy
>> instantiateClass: interpreterProxy classString
>> indexableSize: len + 1.
>> stringPtr := interpreterProxy arrayValueOf: interpreterProxy popRemappableOop.
>> cString := interpreterProxy arrayValueOf: newString. "Point to the actual C string."
>> self cCode: '(char *)strncpy(cString, stringPtr, len)'. "Make a copy of the string."
>> cString at: (len) put: 0. "Null terminate the C string."
>> ^ cString
>>
>> primitivePutEnv
>> "Set an environment variable using a string of the form 'KEY=value'. This
>> implementation allocates a C string using malloc to allocate from the C heap
>> (using cStringFromString rather than transientCStringFromString). This
>> is necessary because the C runtime library does not make a copy of the
>> string into separately allocated environment memory."
>>
>> | cStringPtr keyValueString |
>> self export: true.
>> self var: 'cStringPtr' declareC: 'char *cStringPtr'.
>> keyValueString := interpreterProxy stackObjectValue: 0.
>> cStringPtr := self cStringFromString: keyValueString.
>> ((self putenv: cStringPtr) == 0) "Set environment variable."
>> ifTrue: [interpreterProxy pop: 2; push: keyValueString]
>> ifFalse: [^ interpreterProxy primitiveFail]
>>
>> cStringFromString: aString
>> "Answer a new null-terminated C string copied from aString. The C string
>> is allocated from the C runtime heap. See transientCStringFromString for
>> a version which allocates from object memory.
>> Caution: This may invoke the garbage collector."
>>
>> | len sPtr cString |
>> self returnTypeC: 'char *'.
>> self var: 'sPtr' declareC: 'char *sPtr'.
>> self var: 'cString' declareC: 'char *cString'.
>> sPtr := interpreterProxy arrayValueOf: aString.
>> len := interpreterProxy sizeOfSTArrayFromCPrimitive: sPtr.
>> cString := self callocWrapper: len + 1 size: 1. "Space for a null terminated C string."
>> self cCode: '(char *) strncpy (cString, sPtr, len)'. "Copy the string."
>> ^ cString
>>
>> callocWrapper: count size: objectSize
>> "Using malloc() and calloc() is something I would like to avoid, since it is
>> likely to cause problems some time in the future if somebody redesigns
>> object memory allocation. This wrapper just makes it easy to find senders
>> of calloc() in my code. -dtl"
>>
>> self returnTypeC: 'void *'.
>> ^ self cCode: 'calloc(count, objectSize)'
>>
>> Dave
>>
>
>
>
> --
> Ron
>
--
Ron
More information about the Vm-dev
mailing list